diff --git a/.docker/bungee/Dockerfile b/.docker/bungee/Dockerfile new file mode 100644 index 0000000..12e9234 --- /dev/null +++ b/.docker/bungee/Dockerfile @@ -0,0 +1,7 @@ +FROM eclipse-temurin:17-jre-focal + +COPY .docker/bungee/start.sh ./ + +WORKDIR /mcserver + +ENTRYPOINT ["bash", "/start.sh"] diff --git a/.docker/bungee/start.sh b/.docker/bungee/start.sh new file mode 100644 index 0000000..b77a699 --- /dev/null +++ b/.docker/bungee/start.sh @@ -0,0 +1,8 @@ +trap "echo Received stop signal; pkill java" INT TERM EXIT +ls -la +file=$(ls waterfall*.jar | tail -1) +echo Starting $file +mkdir -p proxy +cd proxy +java -jar ../$file +echo Stopped! diff --git a/.docker/docker-compose.server.yml b/.docker/docker-compose.server.yml index cd0e026..e000087 100644 --- a/.docker/docker-compose.server.yml +++ b/.docker/docker-compose.server.yml @@ -27,6 +27,20 @@ services: aliases: - server2 container_name: mc-server2 + bungee: + build: + context: .. + dockerfile: .docker/bungee/Dockerfile + image: bungee + container_name: dockermc-bungee + networks: + dockermc: + aliases: + - bungee + volumes: + - dockermc:/mcserver + ports: + - 25565:25577 volumes: dockermc: name: dockermc diff --git a/.docker/mcserver/configs/server.properties b/.docker/mcserver/configs/server.properties new file mode 100644 index 0000000..5b14bc8 --- /dev/null +++ b/.docker/mcserver/configs/server.properties @@ -0,0 +1,58 @@ +#Minecraft server properties +#Mon Jul 04 21:41:28 UTC 2022 +enable-jmx-monitoring=false +rcon.port=25575 +level-seed= +gamemode=survival +enable-command-block=false +enable-query=false +generator-settings={} +enforce-secure-profile=false +level-name=world +motd=A Minecraft Server +query.port=25565 +pvp=true +generate-structures=true +max-chained-neighbor-updates=1000000 +difficulty=easy +network-compression-threshold=256 +max-tick-time=60000 +require-resource-pack=false +use-native-transport=true +max-players=20 +online-mode=false +enable-status=true +allow-flight=false +broadcast-rcon-to-ops=true +view-distance=10 +server-ip= +resource-pack-prompt= +allow-nether=true +server-port=25565 +enable-rcon=false +sync-chunk-writes=true +op-permission-level=4 +prevent-proxy-connections=false +hide-online-players=false +resource-pack= +entity-broadcast-range-percentage=100 +simulation-distance=10 +rcon.password= +player-idle-timeout=0 +debug=false +force-gamemode=false +rate-limit=0 +hardcore=false +white-list=false +broadcast-console-to-ops=true +spawn-npcs=true +previews-chat=false +spawn-animals=true +function-permission-level=2 +level-type=minecraft\:normal +text-filtering-config= +spawn-monsters=true +enforce-whitelist=false +spawn-protection=16 +resource-pack-sha1= +max-world-size=29999984 diff --git a/.docker/mcserver/configs/spigot.yml b/.docker/mcserver/configs/spigot.yml new file mode 100644 index 0000000..baf42b5 --- /dev/null +++ b/.docker/mcserver/configs/spigot.yml @@ -0,0 +1,170 @@ +# This is the main configuration file for Spigot. +# As you can see, there's tons to configure. Some options may impact gameplay, so use +# with caution, and make sure you know what each option does before configuring. +# For a reference for any variable inside this file, check out the Spigot wiki at +# http://www.spigotmc.org/wiki/spigot-configuration/ +# +# If you need help with the configuration or have any questions related to Spigot, +# join us at the Discord or drop by our forums and leave a post. +# +# Discord: https://www.spigotmc.org/go/discord +# Forums: http://www.spigotmc.org/ + +settings: + debug: false + timeout-time: 60 + restart-on-crash: true + restart-script: ./start.sh + bungeecord: true + sample-count: 12 + player-shuffle: 0 + user-cache-size: 1000 + save-user-cache-on-stop-only: false + moved-wrongly-threshold: 0.0625 + moved-too-quickly-multiplier: 10.0 + netty-threads: 4 + attribute: + maxHealth: + max: 2048.0 + movementSpeed: + max: 2048.0 + attackDamage: + max: 2048.0 + log-villager-deaths: true + log-named-deaths: true +messages: + whitelist: You are not whitelisted on this server! + unknown-command: Unknown command. Type "/help" for help. + server-full: The server is full! + outdated-client: Outdated client! Please use {0} + outdated-server: Outdated server! I'm still on {0} + restart: Server is restarting +advancements: + disable-saving: false + disabled: + - minecraft:story/disabled +commands: + spam-exclusions: + - /skill + silent-commandblock-console: false + replace-commands: + - setblock + - summon + - testforblock + - tellraw + log: true + tab-complete: 0 + send-namespaced: true +players: + disable-saving: false +world-settings: + default: + below-zero-generation-in-existing-chunks: true + merge-radius: + item: 2.5 + exp: 3.0 + item-despawn-rate: 6000 + view-distance: default + simulation-distance: default + thunder-chance: 100000 + enable-zombie-pigmen-portal-spawns: true + wither-spawn-sound-radius: 0 + hanging-tick-frequency: 100 + arrow-despawn-rate: 1200 + trident-despawn-rate: 1200 + zombie-aggressive-towards-villager: true + nerf-spawner-mobs: false + mob-spawn-range: 8 + end-portal-sound-radius: 0 + growth: + cactus-modifier: 100 + cane-modifier: 100 + melon-modifier: 100 + mushroom-modifier: 100 + pumpkin-modifier: 100 + sapling-modifier: 100 + beetroot-modifier: 100 + carrot-modifier: 100 + potato-modifier: 100 + wheat-modifier: 100 + netherwart-modifier: 100 + vine-modifier: 100 + cocoa-modifier: 100 + bamboo-modifier: 100 + sweetberry-modifier: 100 + kelp-modifier: 100 + twistingvines-modifier: 100 + weepingvines-modifier: 100 + cavevines-modifier: 100 + glowberry-modifier: 100 + entity-activation-range: + animals: 32 + monsters: 32 + raiders: 48 + misc: 16 + water: 16 + villagers: 32 + flying-monsters: 32 + wake-up-inactive: + animals-max-per-tick: 4 + animals-every: 1200 + animals-for: 100 + monsters-max-per-tick: 8 + monsters-every: 400 + monsters-for: 100 + villagers-max-per-tick: 4 + villagers-every: 600 + villagers-for: 100 + flying-monsters-max-per-tick: 8 + flying-monsters-every: 200 + flying-monsters-for: 100 + villagers-work-immunity-after: 100 + villagers-work-immunity-for: 20 + villagers-active-for-panic: true + tick-inactive-villagers: true + ignore-spectators: false + entity-tracking-range: + players: 48 + animals: 48 + monsters: 48 + misc: 32 + other: 64 + ticks-per: + hopper-transfer: 8 + hopper-check: 1 + hopper-amount: 1 + hopper-can-load-chunks: false + dragon-death-sound-radius: 0 + seed-village: 10387312 + seed-desert: 14357617 + seed-igloo: 14357618 + seed-jungle: 14357619 + seed-swamp: 14357620 + seed-monument: 10387313 + seed-shipwreck: 165745295 + seed-ocean: 14357621 + seed-outpost: 165745296 + seed-endcity: 10387313 + seed-slime: 987234911 + seed-nether: 30084232 + seed-mansion: 10387319 + seed-fossil: 14357921 + seed-portal: 34222645 + seed-stronghold: default + hunger: + jump-walk-exhaustion: 0.05 + jump-sprint-exhaustion: 0.2 + combat-exhaustion: 0.1 + regen-exhaustion: 6.0 + swim-multiplier: 0.01 + sprint-multiplier: 0.1 + other-multiplier: 0.0 + max-tnt-per-tick: 100 + max-tick-time: + tile: 50 + entity: 50 + verbose: false +config-version: 12 +stats: + disable-saving: false + forced-stats: {} diff --git a/.docker/mcserver/proxy/config.yml b/.docker/mcserver/proxy/config.yml new file mode 100644 index 0000000..6de7ecc --- /dev/null +++ b/.docker/mcserver/proxy/config.yml @@ -0,0 +1,57 @@ +enforce_secure_profile: false +listeners: +- query_port: 25577 + motd: '&bDockerMC proxy' + tab_list: GLOBAL_PING + query_enabled: false + proxy_protocol: false + forced_hosts: + pvp.md-5.net: pvp + ping_passthrough: false + priorities: + - server1 + - server2 + bind_local_address: true + host: 0.0.0.0:25577 + max_players: 1 + tab_size: 60 + force_default_server: false +remote_ping_cache: -1 +network_compression_threshold: 256 +permissions: + default: + - bungeecord.command.server + - bungeecord.command.list + admin: + - bungeecord.command.alert + - bungeecord.command.end + - bungeecord.command.ip + - bungeecord.command.reload + - bungeecord.command.kick +log_pings: true +connection_throttle_limit: 3 +server_connect_timeout: 20000 +timeout: 30000 +stats: 117e0ead-f30b-4062-9fcc-647f38dfabca +player_limit: -1 +ip_forward: true +groups: + md_5: + - admin +remote_ping_timeout: 5000 +connection_throttle: 4000 +log_commands: false +prevent_proxy_connections: false +online_mode: true +forge_support: true +disabled_commands: +- disabledcommandhere +servers: + server1: + motd: '&bDockerMC server 1' + address: server1:25565 + restricted: false + server2: + motd: '&aDockerMC server 2' + address: server2:25565 + restricted: false diff --git a/.docker/server/start.sh b/.docker/server/start.sh index 213248d..b84ce87 100644 --- a/.docker/server/start.sh +++ b/.docker/server/start.sh @@ -3,7 +3,7 @@ #done trap "echo Received stop signal; pkill java" INT TERM EXIT ls -la -file=$(ls *.jar | tail -1) +file=$(ls paper*.jar | tail -1) echo Starting $file mkdir -p $MC_SERVER cd $MC_SERVER diff --git a/.gitignore b/.gitignore index 829709b..9403ed8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,7 @@ /src/dist/ .idea node_modules -.docker/mcserver +.docker/mcserver/proxy +.docker/mcserver/server* +.docker/mcserver/*.jar +.docker/mcserver/plugins diff --git a/src/index.ts b/src/index.ts index d69cb22..9ca4dbd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -18,14 +18,27 @@ const running: { async function main() { console.log("Checking for server updates...", "MC", process.env.MC_VERSION); - const res: { builds: Build[] } = await (await fetch(`https://api.papermc.io/v2/projects/paper/versions/${process.env.MC_VERSION}/builds`)).json() as any; + await updateServer('paper'); + await updateServer('waterfall'); + console.log('Starting server proxy...'); + exec('docker compose -f /docker-compose.server.yml up -d bungee', loggingCallback); + const listener = async (changedPath) => { + console.log(`Plugin change detected at ${changedPath}, switching to ${running.prevServerName()}...`); + await startNextServer(); + }; + running.watch = chokidar.watch(`/mcserver/plugins/*.jar`).on('change', debounce(listener, 500)); + await startNextServer(); +} + +async function updateServer(project: 'paper' | 'waterfall') { + const res: { builds: Build[] } = await (await fetch(`https://api.papermc.io/v2/projects/${project}/versions/${process.env.MC_VERSION}/builds`)).json() as any; const lastBuild = res.builds[res.builds.length - 1]; - console.log("Latest build is", lastBuild.build, "at", new Date(Date.parse(lastBuild.time)).toLocaleString()) + console.log(`Latest ${project} build is ${lastBuild.build} at ${new Date(Date.parse(lastBuild.time)).toLocaleString()}`); try { await promises.access('/mcserver/' + lastBuild.downloads.application.name) } catch { console.log("Build not found locally, downloading..."); - const newVerRes = await fetch(`https://api.papermc.io/v2/projects/paper/versions/${process.env.MC_VERSION}/builds/${lastBuild.build}/downloads/${lastBuild.downloads.application.name}`); + const newVerRes = await fetch(`https://api.papermc.io/v2/projects/${project}/versions/${process.env.MC_VERSION}/builds/${lastBuild.build}/downloads/${lastBuild.downloads.application.name}`); if (newVerRes.status > 299) { console.log("Error while downloading", await newVerRes.json()); throw new Error("Error while downloading"); @@ -34,32 +47,28 @@ async function main() { console.log("Build downloaded", lastBuild.downloads.application.name); } } - const listener = async (changedPath) => { - console.log(`Plugin change detected at ${changedPath}, switching to ${running.prevServerName()}`); - await startNextServer(); - }; - running.watch = chokidar.watch(`/mcserver/plugins/*.jar`).on('change', debounce(listener, 500)); - await startNextServer(); } async function startNextServer() { running.server1 = !running.server1; - console.log("Copying plugin files to", running.serverName()); + console.log(`Copying plugin files to ${running.serverName()}...`); await promises.cp('/mcserver/plugins', `/mcserver/${running.serverName()}/plugins`, {recursive: true}); // TODO: Don't run servers as root // TODO: Copy config files back to main plugins dir - console.log("Starting server", running.server1 ? 'one' : 'two'); + console.log('Copying config files...'); + await promises.cp('/mcserver/configs', `/mcserver/${running.serverName()}`, {recursive: true}); + console.log("Starting server", running.server1 ? 'one...' : 'two...'); exec('docker compose -f /docker-compose.server.yml up -d ' + running.serverName(), loggingCallback); await waitForStartup(); await stopPrevServer(); } async function stopPrevServer() { - console.log("Stopping previous server"); + console.log("Stopping previous server..."); exec('docker compose -f /docker-compose.server.yml stop ' + running.prevServerName(), loggingCallback); } function waitForStartup() { - console.log("Waiting for startup"); + console.log("Waiting for startup..."); return new Promise(function (resolve, reject) { exec(`wait-for-it ${running.serverName()}:25565 -t 60`, loggingCallback).on('exit', function (code) { if (code === 0) {