diff --git a/scrolls/minecraft/forge/26.3/data/run.sh b/scrolls/minecraft/forge/26.3/data/run.sh new file mode 100644 index 00000000..dbce7d86 --- /dev/null +++ b/scrolls/minecraft/forge/26.3/data/run.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +MAX=${DRUID_MAX_MEMORY%?} +if [ -z "${MAX}" ]; +then + MAX=1024M +fi + +if [ ! -f server.properties ] && [ -f server.properties.default ]; then + if [ -f .druid-rcon-password ]; then + RCON_PASSWORD=$(cat .druid-rcon-password) + else + umask 077 + RCON_PASSWORD=$(LC_ALL=C tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 50 || true) + if [ "${#RCON_PASSWORD}" -ne 50 ]; then + echo "Failed to generate RCON password" >&2 + exit 1 + fi + printf '%s\n' "$RCON_PASSWORD" > .druid-rcon-password + fi + sed \ + -e "s|__DRUID_RCON_PASSWORD__|$RCON_PASSWORD|g" \ + -e "s|__DRUID_PORT_MAIN__|${DRUID_PORT_MAIN_1:-25565}|g" \ + -e "s|__DRUID_PORT_RCON__|${DRUID_PORT_RCON_1:-25575}|g" \ + server.properties.default > server.properties +fi + +java -Xmx$MAX -Xms1024M -jar forge-*-shim.jar nogui diff --git a/scrolls/minecraft/forge/26.3/data/server.properties.default b/scrolls/minecraft/forge/26.3/data/server.properties.default new file mode 100644 index 00000000..e9385571 --- /dev/null +++ b/scrolls/minecraft/forge/26.3/data/server.properties.default @@ -0,0 +1,56 @@ +allow-flight=false +allow-nether=true +broadcast-console-to-ops=true +broadcast-rcon-to-ops=true +difficulty=easy +enable-command-block=false +enable-jmx-monitoring=false +enable-query=false +enable-rcon=true +enable-status=true +enforce-secure-profile=true +enforce-whitelist=false +entity-broadcast-range-percentage=100 +force-gamemode=false +function-permission-level=2 +gamemode=survival +generate-structures=true +generator-settings={} +hardcore=false +hide-online-players=false +initial-disabled-packs= +initial-enabled-packs=vanilla +level-name=world +level-seed= +level-type=minecraft\:normal +max-chained-neighbor-updates=1000000 +max-players=20 +max-tick-time=60000 +max-world-size=29999984 +motd=A Minecraft Server +network-compression-threshold=256 +online-mode=true +op-permission-level=4 +player-idle-timeout=0 +prevent-proxy-connections=false +pvp=true +query.port=__DRUID_PORT_MAIN__ +rate-limit=0 +rcon.password=__DRUID_RCON_PASSWORD__ +rcon.port=__DRUID_PORT_RCON__ +require-resource-pack=false +resource-pack= +resource-pack-prompt= +resource-pack-sha1= +server-ip= +server-port=__DRUID_PORT_MAIN__ +simulation-distance=10 +spawn-animals=true +spawn-monsters=true +spawn-npcs=true +spawn-protection=16 +sync-chunk-writes=true +text-filtering-config= +use-native-transport=true +view-distance=10 +white-list=false diff --git a/scrolls/minecraft/forge/26.3/data/update.sh b/scrolls/minecraft/forge/26.3/data/update.sh new file mode 100755 index 00000000..966812fe --- /dev/null +++ b/scrolls/minecraft/forge/26.3/data/update.sh @@ -0,0 +1,34 @@ +#default update script + +SCRIPTPATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" + +if [ ! -f "$SCRIPTPATH/scroll-lock.json" ]; then + echo "Scroll lock not found. Skipping update" + exit 0 +fi + +if [ -z "$(ls $SCRIPTPATH/update)" ]; then + echo "Update directory is empty. Skipping update" +else + versionsDirs=$(find $SCRIPTPATH/update/* -maxdepth 0 -type d | sort --version-sort) + current=$(cat $SCRIPTPATH/scroll-lock.json | jq -r .scroll_version) + + for versionsDir in $versionsDirs + do + version=$(basename $versionsDir) + if [ ! "$(printf '%s\n' "$version" "$current" | sort -V | head -n1)" = "$version" ] ; + then + echo "$versionsDir/update.sh" + if [ -f "$versionsDir/update.sh" ]; then + sh $versionsDir/update.sh + else + echo "Warning: update $version has no update.sh... skipping" + fi + fi + done +fi + + + +LATEST_VERSION=$(cat $SCRIPTPATH/scroll.yaml | yq -r .version) +jq --arg LV "$LATEST_VERSION" -r '.scroll_version = $LV' $SCRIPTPATH/scroll-lock.json | sponge $SCRIPTPATH/scroll-lock.json \ No newline at end of file diff --git a/scrolls/minecraft/forge/26.3/data/update_user_args.sh b/scrolls/minecraft/forge/26.3/data/update_user_args.sh new file mode 100755 index 00000000..0f6686bf --- /dev/null +++ b/scrolls/minecraft/forge/26.3/data/update_user_args.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env sh + +MAX=${DRUID_MAX_MEMORY%?} +if [ -z "${MAX}" ]; +then + MAX=1024M +fi + + +echo -Xmx$MAX > user_jvm_args.txt \ No newline at end of file diff --git a/scrolls/minecraft/forge/26.3/packet_handler/json.lua b/scrolls/minecraft/forge/26.3/packet_handler/json.lua new file mode 100644 index 00000000..54d44484 --- /dev/null +++ b/scrolls/minecraft/forge/26.3/packet_handler/json.lua @@ -0,0 +1,388 @@ +-- +-- json.lua +-- +-- Copyright (c) 2020 rxi +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy of +-- this software and associated documentation files (the "Software"), to deal in +-- the Software without restriction, including without limitation the rights to +-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +-- of the Software, and to permit persons to whom the Software is furnished to do +-- so, subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in all +-- copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +-- SOFTWARE. +-- + +local json = { _version = "0.1.2" } + +------------------------------------------------------------------------------- +-- Encode +------------------------------------------------------------------------------- + +local encode + +local escape_char_map = { + [ "\\" ] = "\\", + [ "\"" ] = "\"", + [ "\b" ] = "b", + [ "\f" ] = "f", + [ "\n" ] = "n", + [ "\r" ] = "r", + [ "\t" ] = "t", +} + +local escape_char_map_inv = { [ "/" ] = "/" } +for k, v in pairs(escape_char_map) do + escape_char_map_inv[v] = k +end + + +local function escape_char(c) + return "\\" .. (escape_char_map[c] or string.format("u%04x", c:byte())) +end + + +local function encode_nil(val) + return "null" +end + + +local function encode_table(val, stack) + local res = {} + stack = stack or {} + + -- Circular reference? + if stack[val] then error("circular reference") end + + stack[val] = true + + if rawget(val, 1) ~= nil or next(val) == nil then + -- Treat as array -- check keys are valid and it is not sparse + local n = 0 + for k in pairs(val) do + if type(k) ~= "number" then + error("invalid table: mixed or invalid key types") + end + n = n + 1 + end + if n ~= #val then + error("invalid table: sparse array") + end + -- Encode + for i, v in ipairs(val) do + table.insert(res, encode(v, stack)) + end + stack[val] = nil + return "[" .. table.concat(res, ",") .. "]" + + else + -- Treat as an object + for k, v in pairs(val) do + if type(k) ~= "string" then + error("invalid table: mixed or invalid key types") + end + table.insert(res, encode(k, stack) .. ":" .. encode(v, stack)) + end + stack[val] = nil + return "{" .. table.concat(res, ",") .. "}" + end +end + + +local function encode_string(val) + return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"' +end + + +local function encode_number(val) + -- Check for NaN, -inf and inf + if val ~= val or val <= -math.huge or val >= math.huge then + error("unexpected number value '" .. tostring(val) .. "'") + end + return string.format("%.14g", val) +end + + +local type_func_map = { + [ "nil" ] = encode_nil, + [ "table" ] = encode_table, + [ "string" ] = encode_string, + [ "number" ] = encode_number, + [ "boolean" ] = tostring, +} + + +encode = function(val, stack) + local t = type(val) + local f = type_func_map[t] + if f then + return f(val, stack) + end + error("unexpected type '" .. t .. "'") +end + + +function json.encode(val) + return ( encode(val) ) +end + + +------------------------------------------------------------------------------- +-- Decode +------------------------------------------------------------------------------- + +local parse + +local function create_set(...) + local res = {} + for i = 1, select("#", ...) do + res[ select(i, ...) ] = true + end + return res +end + +local space_chars = create_set(" ", "\t", "\r", "\n") +local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",") +local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u") +local literals = create_set("true", "false", "null") + +local literal_map = { + [ "true" ] = true, + [ "false" ] = false, + [ "null" ] = nil, +} + + +local function next_char(str, idx, set, negate) + for i = idx, #str do + if set[str:sub(i, i)] ~= negate then + return i + end + end + return #str + 1 +end + + +local function decode_error(str, idx, msg) + local line_count = 1 + local col_count = 1 + for i = 1, idx - 1 do + col_count = col_count + 1 + if str:sub(i, i) == "\n" then + line_count = line_count + 1 + col_count = 1 + end + end + error( string.format("%s at line %d col %d", msg, line_count, col_count) ) +end + + +local function codepoint_to_utf8(n) + -- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa + local f = math.floor + if n <= 0x7f then + return string.char(n) + elseif n <= 0x7ff then + return string.char(f(n / 64) + 192, n % 64 + 128) + elseif n <= 0xffff then + return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128) + elseif n <= 0x10ffff then + return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128, + f(n % 4096 / 64) + 128, n % 64 + 128) + end + error( string.format("invalid unicode codepoint '%x'", n) ) +end + + +local function parse_unicode_escape(s) + local n1 = tonumber( s:sub(1, 4), 16 ) + local n2 = tonumber( s:sub(7, 10), 16 ) + -- Surrogate pair? + if n2 then + return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000) + else + return codepoint_to_utf8(n1) + end +end + + +local function parse_string(str, i) + local res = "" + local j = i + 1 + local k = j + + while j <= #str do + local x = str:byte(j) + + if x < 32 then + decode_error(str, j, "control character in string") + + elseif x == 92 then -- `\`: Escape + res = res .. str:sub(k, j - 1) + j = j + 1 + local c = str:sub(j, j) + if c == "u" then + local hex = str:match("^[dD][89aAbB]%x%x\\u%x%x%x%x", j + 1) + or str:match("^%x%x%x%x", j + 1) + or decode_error(str, j - 1, "invalid unicode escape in string") + res = res .. parse_unicode_escape(hex) + j = j + #hex + else + if not escape_chars[c] then + decode_error(str, j - 1, "invalid escape char '" .. c .. "' in string") + end + res = res .. escape_char_map_inv[c] + end + k = j + 1 + + elseif x == 34 then -- `"`: End of string + res = res .. str:sub(k, j - 1) + return res, j + 1 + end + + j = j + 1 + end + + decode_error(str, i, "expected closing quote for string") +end + + +local function parse_number(str, i) + local x = next_char(str, i, delim_chars) + local s = str:sub(i, x - 1) + local n = tonumber(s) + if not n then + decode_error(str, i, "invalid number '" .. s .. "'") + end + return n, x +end + + +local function parse_literal(str, i) + local x = next_char(str, i, delim_chars) + local word = str:sub(i, x - 1) + if not literals[word] then + decode_error(str, i, "invalid literal '" .. word .. "'") + end + return literal_map[word], x +end + + +local function parse_array(str, i) + local res = {} + local n = 1 + i = i + 1 + while 1 do + local x + i = next_char(str, i, space_chars, true) + -- Empty / end of array? + if str:sub(i, i) == "]" then + i = i + 1 + break + end + -- Read token + x, i = parse(str, i) + res[n] = x + n = n + 1 + -- Next token + i = next_char(str, i, space_chars, true) + local chr = str:sub(i, i) + i = i + 1 + if chr == "]" then break end + if chr ~= "," then decode_error(str, i, "expected ']' or ','") end + end + return res, i +end + + +local function parse_object(str, i) + local res = {} + i = i + 1 + while 1 do + local key, val + i = next_char(str, i, space_chars, true) + -- Empty / end of object? + if str:sub(i, i) == "}" then + i = i + 1 + break + end + -- Read key + if str:sub(i, i) ~= '"' then + decode_error(str, i, "expected string for key") + end + key, i = parse(str, i) + -- Read ':' delimiter + i = next_char(str, i, space_chars, true) + if str:sub(i, i) ~= ":" then + decode_error(str, i, "expected ':' after key") + end + i = next_char(str, i + 1, space_chars, true) + -- Read value + val, i = parse(str, i) + -- Set + res[key] = val + -- Next token + i = next_char(str, i, space_chars, true) + local chr = str:sub(i, i) + i = i + 1 + if chr == "}" then break end + if chr ~= "," then decode_error(str, i, "expected '}' or ','") end + end + return res, i +end + + +local char_func_map = { + [ '"' ] = parse_string, + [ "0" ] = parse_number, + [ "1" ] = parse_number, + [ "2" ] = parse_number, + [ "3" ] = parse_number, + [ "4" ] = parse_number, + [ "5" ] = parse_number, + [ "6" ] = parse_number, + [ "7" ] = parse_number, + [ "8" ] = parse_number, + [ "9" ] = parse_number, + [ "-" ] = parse_number, + [ "t" ] = parse_literal, + [ "f" ] = parse_literal, + [ "n" ] = parse_literal, + [ "[" ] = parse_array, + [ "{" ] = parse_object, +} + + +parse = function(str, idx) + local chr = str:sub(idx, idx) + local f = char_func_map[chr] + if f then + return f(str, idx) + end + decode_error(str, idx, "unexpected character '" .. chr .. "'") +end + + +function json.decode(str) + if type(str) ~= "string" then + error("expected argument of type string, got " .. type(str)) + end + local res, idx = parse(str, next_char(str, 1, space_chars, true)) + idx = next_char(str, idx, space_chars, true) + if idx <= #str then + decode_error(str, idx, "trailing garbage") + end + return res +end + + +return json \ No newline at end of file diff --git a/scrolls/minecraft/forge/26.3/packet_handler/minecraft.lua b/scrolls/minecraft/forge/26.3/packet_handler/minecraft.lua new file mode 100644 index 00000000..cb36f45f --- /dev/null +++ b/scrolls/minecraft/forge/26.3/packet_handler/minecraft.lua @@ -0,0 +1,262 @@ +json = require("packet_handler/json") + +function string.fromhex(str) + return (str:gsub('..', function(cc) + return string.char(tonumber(cc, 16)) + end)) +end + +function string.tohex(str) + return (str:gsub('.', function(c) + return string.format('%02X', string.byte(c)) + end)) +end + +-- Bitwise AND +local function band(a, b) + local result = 0 + local bitval = 1 + while a > 0 and b > 0 do + local abit = a % 2 + local bbit = b % 2 + if abit == 1 and bbit == 1 then + result = result + bitval + end + a = math.floor(a / 2) + b = math.floor(b / 2) + bitval = bitval * 2 + end + return result +end + +-- Bitwise OR +local function bor(a, b) + local result = 0 + local bitval = 1 + while a > 0 or b > 0 do + local abit = a % 2 + local bbit = b % 2 + if abit == 1 or bbit == 1 then + result = result + bitval + end + a = math.floor(a / 2) + b = math.floor(b / 2) + bitval = bitval * 2 + end + return result +end + +-- Right Shift +local function rshift(value, shift) + return math.floor(value / (2 ^ shift)) +end + +-- Left Shift +local function lshift(value, shift) + return value * (2 ^ shift) +end + +function encodeLEB128(value) + local bytes = {} + repeat + local byte = band(value, 0x7F) + value = rshift(value, 7) + if value ~= 0 then + byte = bor(byte, 0x80) + end + table.insert(bytes, byte) + until value == 0 + return bytes +end + +function decodeLEB128(bytes) + local result = 0 + local shift = 0 + local bytesConsumed = 0 -- Track the number of bytes consumed + + for i, byte in ipairs(bytes) do + local value = band(byte, 0x7F) -- Get lower 7 bits + result = bor(result, lshift(value, shift)) -- Add it to result with the correct shift + bytesConsumed = bytesConsumed + 1 -- Increment the byte counter + if band(byte, 0x80) == 0 then -- If the highest bit is not set, we are done + break + end + shift = shift + 7 -- Move to the next group of 7 bits + end + + return result, bytesConsumed -- Return both the result and the number of bytes consumed +end + +function handle(ctx, data) + hex = string.tohex(data) + + debug_print("Received Packet: " .. hex) + + -- check if hex starts with 0x01 0x00 + if hex:sub(1, 4) == "FE01" then + debug_print("Received Legacy Ping Packet") + sendData(string.fromhex( + "ff002300a7003100000034003700000031002e0034002e0032000000410020004d0069006e006500630072006100660074002000530065007200760065007200000030000000320030")) + end + + local packetNo = 0 + + local maxLoops = 2 + + restBytes = data + + while hex ~= "" do + + queue = get_queue() + + hex = string.tohex(restBytes) + + debug_print("Remaining Bytes: " .. hex) + packetNo = packetNo + 1 + debug_print("Packet No: " .. packetNo) + + packetLength, bytesConsumed = decodeLEB128({string.byte(restBytes, 1, 1)}) + debug_print("Packet Length: " .. packetLength) + + -- cut of consumedBytes and read untul packetLength + packetWithLength = string.sub(restBytes, bytesConsumed + 1, packetLength + bytesConsumed) + + -- next varint is the packetid + packetId, bytesConsumed = decodeLEB128({string.byte(packetWithLength, 1, 1)}) + + debug_print("Packet ID: " .. packetId) + + packetWithLengthHex = string.tohex(packetWithLength) + + debug_print("Trimmed Packet: " .. packetWithLengthHex) + + -- make hex to the rest of the data + restBytes = string.sub(restBytes, packetLength + bytesConsumed + 1) + + debug_print("Rest Bytes: " .. string.tohex(restBytes)) + + if packetLength == 1 and packetId == 0 then + debug_print("Received Status Packet " .. packetWithLengthHex) + sendData(pingResponse()) + + -- check if second byte is 0x01 + elseif packetId == 1 then + debug_print("Received Ping Packet " .. packetWithLengthHex) + -- send same packet back + close(data) + -- login packet 0x20 0x00 + elseif packetId == 0 and packetWithLengthHex:sub(-2) == "02" then -- check for enum at the end + debug_print("Received Login Packet " .. packetWithLengthHex) + -- return + -- debug_print("Received Login Packet") + + sendData(disconnectResponse()) + -- sleep for a sec before closing + finish() + -- return + else + debug_print("Received unknown packet " .. packetWithLengthHex) + -- close("") + end + end +end + +function formatResponse(jsonObj) + local response = json.encode(jsonObj) + local responseBuffer = {string.byte(response, 1, -1)} + local additional = {0x00} + local responseBufferLength = encodeLEB128(#responseBuffer) + local packetLenthBuffer = encodeLEB128(#responseBuffer + #responseBufferLength + 1) + + local concatedBytes = {} + + for i = 1, #packetLenthBuffer do + table.insert(concatedBytes, packetLenthBuffer[i]) + end + + for i = 1, #additional do + table.insert(concatedBytes, additional[i]) + end + + for i = 1, #responseBufferLength do + table.insert(concatedBytes, responseBufferLength[i]) + end + + for i = 1, #responseBuffer do + table.insert(concatedBytes, responseBuffer[i]) + end + + -- convert back to string + local finalString = string.char(unpack(concatedBytes)) + + return finalString +end + +function pingResponse() + + local description = { + color = "red", + extra = {"\n", { + color = "gray", + extra = {{ + bold = true, + text = "HINT" + }, ":", " ", { + color = "white", + text = "Get free servers at:" + }, " ", { + color = "green", + text = "druid.gg" + }}, + text = "" + }}, + text = "This server is in standby." + } + + local obj = { + version = { + name = "§9🕐 Waiting...", + protocol = -1 + }, + description = description, + players = { + max = 0, + online = 1 + }, + favicon = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAAAXNSR0IArs4c6QAAAMlQTFRFR3BM6ndq5Wxb3WBQ6HFi0EUvvVxI8IBzzTwm0EUv11RC3GBQ7X1w00w50EUv42pa1lRB3mNT4WZV0Ugz2VlH0ks22lpJ0ks332RU1VI/6XZo8oV4421e63Zn32JR0046ytvZ2FZEieHa5nBgb+fZFerZ1NrZDOrZDurZ1tjYQunZztrZO+jZruDZFOrZDOrZDOrZ6HVoDOrZ09rZ0cvJn+LZbebZi+PZkOPZC+rZ942B7Xpr9op98oR29Id67n1uz9vZH+rZjeTZHadAYQAAADl0Uk5TAOr9sP4WBv4CDXqV8kcf3m277CmGPaAzx1Pg8tD90lw3YxDx/mzTQ+aq/nYk/bT50NSS71SwxIbiWYkesQAABERJREFUeNqll2tfozgUxkshIeF+vxWoiNfRUaszuztDC7rf/0PtISAlpR1dfPLzTZLzz3POIUgXp0XD2PJUkGetfbT4fyJI9+xNsuqVbGx1beDPh7uKnazq7e+96lWSqj79XLihpKv691SrRPU/4YLGtsbCp9quNp5BPjreE1j4KYT9ZxPYDbQt7GObW9XwxxHqTUz/EB/a8hbC2+iVJpiRbUdpokE92RwbdVJQcjp+x3Ztay0N1iFClFLk6oqYMEa3thUKeqp74q7zLYjQdUzIgjBhGiqRBohOdaLjo/FIldm6FhWIEH4NG8pGHgiReywJagnd8eqwzCF0cTAhq/TIDt+stzAE79Rz76pAYKMW4ukZKJDr9nzldJcMIHSd3dloYiAWapCm8iu83ECrO00tIHEH87JojCfP78/O7u/x/pQw3bEcYCM9MKALANht9HH42d3Pn389PF9enw/bLNjWapf4vAUcyDCreaMGn91dfb/49gv09HxNegAS5ZohNIUHuGlrIHVH8bcv/0I40+MDEDoVYGEHkkXMZbAWYBIMjOJfIX7Qw3W/0YjkHSBqOTW4DFQNAElIhvxvX76z+MHDfU+AnUyJPwZQG7jjyv64er34NdbNZb/CvMJmYT0GGCkANAXvDbyCAU7vFkJTZgRNGQP8RAamTsYVeOPiH5/6KqD2LNiteWNALMCUaewBXAZcDjTtHajjJhSCLMvRtARTAAEAEwdYWABoRPwhgJWrkYcUeEAAgNMpPF0P5WLii7g+AJxzReS6AGcxCRZXxKQZAwi5ezlo4+Mz7i9NxeKbRB8DQrPhasD1kcsgTJsOwD/KKAcAdGGv9iq+jUvYG1AE2Amj4l8IWKyaxkRkNANJ7Ak3z+e9gahqmAT+OhMAN6VPRjOYvQ7euqfwso9HQdZ0Mn0eoJtVkymYmzu7vfrn4tvNDbxP+gWqJL0BlgF/HbPJJI5/3N39fXk5vBSRBcd0KteEBxClrCoz5Gf1IEYLMvBc7z2+ykQ0eWPnVVUqmLcV5J6PujnqFmJZNf0wdXIIwB5YyN3FQWWWqWrFuh4Xnlhm1btKDx/51xxl/QJPlcrSNM1SyqpBknjsQwdbZZWZOk81RKmaSLLDaTzrsVSVosFT/UiqMhhVto8/9ZlEQpYE5Qk6EDpl3XACLp7vu5llpoUPPKgOIDIIbSHLyOLy50ULJ5PMNTmoQ6zmzlICLR3bCunitAi1gJDH+MAZaj+7PU8pdJd+9I2ttIQ1nmRHEUIUk8WHQpYjSXlBF3NFaGFKkqkgMhtB41ySnMDFswlYt5fSMorpbBPEDRww4bl4LgKakbcm1gh/IY3WhKjPRhDDa004wXwE1kWzQxhzEciynRYhFuHcx8JQGGKZe7FLZ3a0RbB7qIRzERbUorURWWhuQ9Zq5CyXS0dBs++HbwU5EKwv3FJDh2rk/uILoqFlT38O/QdGyOZnTVzZRwAAAABJRU5ErkJggg==" + } + + local snapshotMode = get_snapshot_mode() + local snapshotPercentage = get_snapshot_percentage() + + if snapshotMode ~= "idle" then + if snapshotMode == "restore" then + if snapshotPercentage == nil or snapshotPercentage == 100 then + obj.version.name = "§2▶ Downloading snapshot... " .. string.format("%.2f", snapshotPercentage) .. "%" + else + obj.version.name = "§2▶ Extracting snapshot..." + end + obj.description = "Restoring Minecraft Server, this might take a moment" + else + if snapshotPercentage == nil or snapshotPercentage == 100 then + obj.version.name = "§2▶ Backing up... " .. string.format("%.2f", snapshotPercentage) .. "%" + else + obj.version.name = "§2▶ Backing up..." + end + obj.description = "Backing up Minecraft Server, this might take a moment" + end + elseif queue ~= nil and queue["install"] == "running" then + obj.version.name = "§2▶ Installing..." + obj.description = "Installing Minecraft Server, this might take a moment" + elseif get_finish_sec() ~= nil then + obj.version.name = "§2▶ Starting..." + obj.description = "Starting " .. math.ceil(get_finish_sec()) .. "s" + end + + return formatResponse(obj) +end + +function disconnectResponse() + local obj = "Our super cool system will start now... please wait" + return formatResponse(obj) +end diff --git a/scrolls/minecraft/forge/26.3/scroll.yaml b/scrolls/minecraft/forge/26.3/scroll.yaml new file mode 100644 index 00000000..7898a947 --- /dev/null +++ b/scrolls/minecraft/forge/26.3/scroll.yaml @@ -0,0 +1,114 @@ +name: artifacts.druid.gg/druid-team/scroll-minecraft-forge +desc: Minecraft Forge +version: 0.0.1 +app_version: "26.3" +ports: +- name: main + protocol: tcp + port: 25565 +- name: rcon + protocol: tcp + port: 25575 +commands: + start: + needs: + - install + run: restart + procedures: + - id: coldstart + image: artifacts.druid.gg/druid-team/druid:v0.1.256 + expectedPorts: + - name: main + keepAliveTraffic: 1mb/5m + - name: rcon + mounts: + - path: "/runtime" + sub_path: "." + working_dir: "/runtime" + env: + DRUID_ROOT: "/runtime" + DRUID_PORT_MAIN_COLDSTARTER: "packet_handler/minecraft.lua" + DRUID_PORT_RCON_COLDSTARTER: "generic" + command: + - druid-coldstarter + - image: alpine:3.20 + mounts: + - path: "/server" + working_dir: "/server" + command: + - sh + - "./update_user_args.sh" + - id: start + image: eclipse-temurin:25-jre + expectedPorts: + - name: main + keepAliveTraffic: 1mb/5m + - name: rcon + mounts: + - path: "/server" + working_dir: "/server" + command: + - sh + - "./run.sh" + stop: + run: always + procedures: + - type: signal + target: start + signal: SIGTERM + install: + run: once + procedures: + - image: alpine:3.20 + mounts: + - path: "/server" + working_dir: "/server" + command: + - wget + - "-q" + - "-O" + - forge-installer.jar + - http://192.168.100.200:9000/snapshot-cache/minecraft/forge/forge-26.3.jar + - image: eclipse-temurin:25-jre + mounts: + - path: "/server" + working_dir: "/server" + command: + - java + - "-jar" + - forge-installer.jar + - "--installServer" + - image: alpine:3.20 + mounts: + - path: "/server" + working_dir: "/server" + command: + - rm + - forge-installer.jar + - image: alpine:3.20 + mounts: + - path: "/server" + working_dir: "/server" + command: + - sh + - "-c" + - echo eula=true > eula.txt + update: + procedures: + - image: alpine:3.20 + mounts: + - path: "/server" + working_dir: "/server" + command: + - sh + - "-c" + - apk add --no-cache jq yq moreutils && ./update.sh + - image: alpine:3.20 + mounts: + - path: "/server" + working_dir: "/server" + command: + - sh + - "-c" + - echo eula=true > eula.txt +serve: start diff --git a/scrolls/minecraft/forge/26.3/update/.gitkeep b/scrolls/minecraft/forge/26.3/update/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/scrolls/minecraft/minecraft-vanilla/26.3/scroll.yaml b/scrolls/minecraft/minecraft-vanilla/26.3/scroll.yaml index 566d512a..3fe09be8 100644 --- a/scrolls/minecraft/minecraft-vanilla/26.3/scroll.yaml +++ b/scrolls/minecraft/minecraft-vanilla/26.3/scroll.yaml @@ -61,7 +61,7 @@ commands: - "-c" - >- apk add --no-cache ca-certificates wget - && wget -q -O server.jar https://piston-data.mojang.com/v1/objects/823e2250d24b3ddac457a60c92a6a941943fcd6a/server.jar + && wget -q -O server.jar https://piston-data.mojang.com/v1/objects/33680f5f2ac32864d6d7cf5e56a705fdb3e05f4c/server.jar && echo eula=true > eula.txt update: procedures: diff --git a/scrolls/minecraft/papermc/26.3/scroll.yaml b/scrolls/minecraft/papermc/26.3/scroll.yaml index c0cd205c..39bedf85 100644 --- a/scrolls/minecraft/papermc/26.3/scroll.yaml +++ b/scrolls/minecraft/papermc/26.3/scroll.yaml @@ -60,7 +60,7 @@ commands: - "-q" - "-O" - paper.jar - - http://192.168.100.200:9000/snapshot-cache/minecraft/papermc/paper-26.2.jar + - http://192.168.100.200:9000/snapshot-cache/minecraft/papermc/paper-26.3.jar - image: alpine:3.20 mounts: - path: "/server"