diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a1b391d --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +# generated locally by server/setup-server.sh — don't commit the actual server/binaries +server/mcserver/ +server/lazymc +server/lazymc.toml + +# generated locally when building the client modpack — too large / personal for git +server/dist/*.zip +*.zip diff --git a/HOSTING.md b/HOSTING.md new file mode 100644 index 0000000..421a86a --- /dev/null +++ b/HOSTING.md @@ -0,0 +1,94 @@ +# How to run this at the LAN party + +## 1. Prep the modpack instance once, yourself, beforehand + +1. Install [Fjord Launcher Unlocked](https://github.com/hero-persson/FjordLauncherUnlocked) normally on your own machine. +2. Create a new instance: Minecraft **1.20.1**, **Forge**. Name it exactly `LANParty` (or change `INSTANCE_NAME`/`$InstanceName` in both scripts to match). +3. Add the mods from `modpack.md` (use the launcher's built-in Modrinth/CurseForge browser, or drop jars straight into the instance's `mods/` folder). +4. **Set up the server and pregenerate first** — do the "Set up the dedicated venue box" and "Pre-generate chunks before the party starts (Chunky)" steps below *before* continuing here. Distant Horizons can only cache real terrain that already exists; it can't backfill detail after the fact. +5. Launch the client, go to **Multiplayer → Add Server**, enter the venue box's LAN IP, and join for real. Set your preferred video settings (these land in `options.txt`). Then fly/walk around the pregenerated build area with a decent render distance and Distant Horizons enabled — this is what actually populates `Distant_Horizons_server_data/` in the instance with real LOD data for that area. Quit when you've covered the zone you pregenerated. +6. Quit the launcher, then export the instance via **right-click the instance → Export Instance** (don't blindly zip the raw folder — the exporter lets you pick what's included). Check: `mods/`, `config/`, `options.txt`, `servers.dat`, `Distant_Horizons_server_data/`. Uncheck: `logs/`, `crash-reports/`, `screenshots/`, and any asset/library caches — those regenerate automatically on first launch and just bloat the zip. Name the result `modpack.zip`, with the instance's folder (`LANParty/...`) as the zip's top-level entry. + +**Caveats for this to actually pay off for participants:** +- Don't rename the server list entry or change Distant Horizons' "Server Folder Name Mode" setting afterward — both are part of the cache key (`" :"` by default). Change either and participants' clients won't find the cache you built. +- Don't regenerate/reset the server world after this point. If the actual party world differs from the one you explored, the cached LOD will show stale terrain that doesn't match reality. +- This cache is for *scenery beyond render distance* only — it doesn't substitute for the server having `online-mode=false` or for Chunky's pregen; all three pieces (pregen, DH cache, offline accounts) are independent and all need to land in the final zip/setup. + +## 2. Set up the dedicated venue box (one machine, does both jobs) + +Run `server/setup-server.sh` on the Linux box you're bringing to the party. It: + +- Installs the Forge 1.20.1 server and wraps it in **lazymc**, which sleeps the real server after 5 idle minutes and transparently wakes it the instant someone connects — no manual start/stop for the whole 3 days. +- Serves `server/dist/` over HTTP via a systemd unit (survives logout, auto-restarts if it dies). +- Opens the relevant ports in `ufw` if it's active. + +```bash +cd server +./setup-server.sh +# then copy your client modpack's mod jars into mcserver/mods/, and: +sudo systemctl restart mc-lazymc +``` + +Put `install.sh`, `install.ps1`, and `modpack.zip` into `server/dist/` (that's what gets served on port 8000). + +Find the box's LAN IP (`ip a`) and edit the top of **both** `install.sh` and `install.ps1`: + +- `HOST_URL` / `$HostUrl` → `http://:8000` +- `SERVER_ADDR` / `$ServerAddr` → `:25565` (lazymc's public port) + +Useful commands during the party: +- `sudo systemctl status mc-lazymc` — check if the MC server is asleep/awake +- `sudo journalctl -u mc-lazymc -f` — watch it wake/sleep live +- `sudo systemctl restart mc-lazymc` — pick up new mods or a config change + +### Resource sizing for the venue box (5–15 players) + +Create is the dominant cost here — it's heavier on the server **tick thread (CPU)** than on RAM, because kinetic networks and contraptions get simulated every tick regardless of how many players are nearby. Farmer's Delight/its addons are cheap by comparison. Numbers below assume this modpack (~10 mods) and are *total host box* numbers, not just the JVM heap: + +| Concurrent players | JVM heap (`-Xmx`, set in `setup-server.sh`) | Host RAM (total, incl. OS + file server) | CPU | Free disk | Network | +|---|---|---|---|---|---| +| 5–8 | 6G | 10–12 GB | 4 cores, 3.5 GHz+ single-core perf matters more than core count | ~10 GB (world + mods + Forge libs + logs) | Gigabit LAN recommended, Wi-Fi workable | +| 9–12 | 8G | 12–16 GB | 4–6 cores, 3.5 GHz+ | ~15 GB | Gigabit LAN recommended | +| 13–15 | 10–12G | 16 GB+ | 6+ cores, 3.5 GHz+ | ~20 GB | Gigabit LAN, wire the host box if possible | + +Practical knobs to turn if the box is lighter than the table: +- Lower `server.properties` **`view-distance`** to 6–8 — this is the single biggest CPU/RAM lever on a modded server, and the Distant Horizons client mod (see `modpack.md`) makes a short server view-distance look fine anyway. +- Set `simulation-distance` a notch below `view-distance` if things chug — it controls how far Create's kinetic networks/entities get ticked, independent of render range. +- `MIN_RAM`/`MAX_RAM` in `setup-server.sh` default to `2G`/`4G` — bump `MAX_RAM` to match the table above for your headcount before running the script (or edit `lazymc.toml`'s `command` line afterward and `sudo systemctl restart mc-lazymc`). +- An SSD matters more than raw disk size here — Create's block-entity-heavy contraptions do a lot of small, frequent chunk saves; a spinning HDD will show up as tick-time spikes. + +### Pre-generate chunks before the party starts (Chunky) + +Chunky (server-side mod, already listed in `modpack.md`) fills in a radius of real terrain ahead of time so nobody hits on-the-fly generation lag while exploring. Do this once, before participants arrive: + +1. Make sure `mcserver/mods/` has the Chunky jar, then `sudo systemctl restart mc-lazymc` and let the server boot (connect once from a client, or `sudo journalctl -u mc-lazymc -f` and wait for "Done"). +2. Run the commands below either from the server console (attach via `sudo systemctl stop mc-lazymc && cd mcserver && bash run.sh nogui`, temporarily bypassing lazymc so you get an interactive console) or via RCON (`mcrcon -H 127.0.0.1 -P 25575 -p ""`): + + ``` + /chunky center 0 0 # or your build area's coordinates + /chunky radius 800 # 800 blocks ≈ 50 chunks (1 chunk = 16 blocks) + /chunky start + /chunky confirm # if it warns about area size + ``` +3. Watch progress with `/chunky status`. For ~50 chunks radius this finishes in seconds to a couple minutes depending on the box. +4. If you stopped lazymc to get console access in step 2, restart it afterward: `sudo systemctl start mc-lazymc`. + +Repeat with `/chunky world the_nether` / `/chunky world the_end` first if you want the Nether/End build areas pregenerated too (useful since the roadmap sends people there for Nether's/End's Delight dishes). + +## 3. Give participants the one-liner + +- **Windows:** `irm http://:8000/install.ps1 | iex` +- **Linux / macOS:** `curl -fsSL http://:8000/install.sh | bash` + +Each script asks for a nickname, derives a stable offline-mode UUID from it (so the same name = same player data across the whole 3-day party, even if they re-run the script), seeds that into a fresh `accounts.json`, downloads Fjord Launcher Unlocked + the modpack, and launches straight into the instance already connected to your server. + +Make sure your Minecraft server itself is running with `online-mode=false` in `server.properties` — offline accounts only work against offline-mode servers. + +## Notes / things that can break + +- The scripts pull Fjord Launcher Unlocked's **latest GitHub release** dynamically, so they stay correct even after version bumps — but if `hero-persson/FjordLauncherUnlocked` ever disappears, swap the repo slug at the top of the scripts for a current fork. +- `install.sh` needs `curl`, `unzip`/`find` (standard on any Linux/macOS box) and relies on FUSE for running the AppImage directly; if a participant's distro lacks FUSE, the AppImage will fail to launch — tell them to run `./FjordLauncher.AppImage --appimage-extract` once and point `LAUNCHER_BIN` at the extracted `AppRun`. +- Re-running either script is safe/idempotent: it skips re-downloading the modpack if the instance folder already exists, and just overwrites `accounts.json` with the (same, deterministic) account if the nickname is unchanged. +- lazymc's first wake after a sleep takes as long as the Forge server normally does to boot (expect 20–60s depending on the box) — the client will show a "starting" MOTD/kick message during that window; just reconnect after a few seconds. +- `setup-server.sh` pins a Forge build (`47.4.28` for `1.20.1`) — check [files.minecraftforge.net](https://files.minecraftforge.net/net/minecraftforge/forge/index_1.20.1.html) if it's gone stale by the time you run this. +- Double-check the server's mod list is byte-for-byte the same mods as the client instance (same versions) — Forge is strict about mod-list mismatches between client and server and will refuse to connect otherwise. diff --git a/food.md b/food.md new file mode 100644 index 0000000..2e1020e --- /dev/null +++ b/food.md @@ -0,0 +1,184 @@ +# Food Pool — pick your IRL roadmap meals from here + +Checklist of every food item I could confirm, grouped by mod/station. Tick the ones you want to put on the in-game quest line (and cook IRL). Items marked `⚠` are ones I could not fully verify from public sources — double-check with JEI in a test world before committing to cooking them. + +## Farmer's Delight (base) + +### Raw ingredients / crops +- [ ] Tomato +- [ ] Onion +- [ ] Cabbage +- [ ] Rice + +### Cutting board +- [ ] Cabbage Leaf +- [ ] Pumpkin Slice +- [ ] Melon Slice +- [ ] Minced Beef +- [ ] Raw Bacon +- [ ] Raw Chicken Cuts +- [ ] Raw Mutton Chops +- [ ] Raw Cod Slice +- [ ] Raw Salmon Slice +- [ ] Raw Porkchop (cut) +- [ ] Raw Pasta +- [ ] Straw + +### Furnace / Smoker / Campfire +- [ ] Cooked Bacon +- [ ] Cooked Chicken Cuts +- [ ] Cooked Mutton Chops +- [ ] Cooked Cod Slice +- [ ] Cooked Salmon Slice +- [ ] Beef Patty +- [ ] Fried Egg +- [ ] Bread (vanilla, FD-compatible) +- [ ] Smoked Ham + +### Cooking Pot — soups & stews +- [ ] Beef Stew +- [ ] Chicken Soup +- [ ] Vegetable Soup +- [ ] Fish Stew +- [ ] Pumpkin Soup +- [ ] Baked Cod Stew +- [ ] Noodle Soup +- [ ] Onion Soup +- [ ] Bone Broth +- [ ] Mushroom Stew (vanilla, buffed) +- [ ] Beetroot Soup (vanilla, buffed) +- [ ] Rabbit Stew (vanilla, buffed) + +### Cooking Pot — rice, pasta & mains +- [ ] Cooked Rice +- [ ] Fried Rice +- [ ] Mushroom Rice +- [ ] Pasta with Meatballs +- [ ] Pasta with Mutton Chop +- [ ] Squid Ink Pasta +- [ ] Vegetable Noodles +- [ ] Ratatouille +- [ ] Cabbage Rolls +- [ ] Dumplings + +### Cooking Pot — other +- [ ] Tomato Sauce +- [ ] Hot Cocoa +- [ ] Apple Cider +- [ ] Glow Berry Custard +- [ ] Dog Food (wolf feed, not for humans!) +- [ ] Stuffed Pumpkin (raw, placeable) + +### Crafting Table — sandwiches & rolls +- [ ] Egg Sandwich +- [ ] Chicken Sandwich +- [ ] Hamburger +- [ ] Bacon Sandwich +- [ ] Mutton Wrap +- [ ] Barbecue on a Stick +- [ ] Kelp Roll +- [ ] Salmon Roll +- [ ] Cod Roll + +### Crafting Table — plates & salads +- [ ] Stuffed Potato +- [ ] Steak and Potatoes +- [ ] Roasted Mutton Chops +- [ ] Grilled Salmon +- [ ] Bacon and Eggs +- [ ] Mixed Salad +- [ ] Fruit Salad +- [ ] Nether Salad + +### Crafting Table — pies & sweets +- [ ] Pie Crust (component) +- [ ] Apple Pie +- [ ] Chocolate Pie +- [ ] Sweet Berry Cheesecake +- [ ] Pumpkin Pie (FD-enabled slicing) +- [ ] Melon Popsicle +- [ ] Honey Cookie +- [ ] Sweet Berry Cookie + +### Crafting Table — drinks & basics +- [ ] Melon Juice +- [ ] Milk Bottle +- [ ] Wheat Dough (component) + +### Feasts (placed, multi-serving centerpieces — great "final dish" quest targets) +- [ ] Roast Chicken (Plate of Roast Chicken) +- [ ] Stuffed Pumpkin (Bowl of Stuffed Pumpkin) +- [ ] Honey Glazed Ham (Plate of Honey Glazed Ham) +- [ ] Shepherd's Pie (Plate of Shepherd's Pie) +- [ ] Gleaming Salad (Bowl of Gleaming Salad) +- [ ] Rice Roll Medley + +--- + +## Nether's Delight + +- [ ] Hoglin Loin (raw/cooked) +- [ ] Hoglin Ham +- [ ] Hoglin Hide (crafting component) +- [ ] Nether Skewers +- [ ] Nether Salad (Warped Fungus + Crimson Fungus + bowl) +- [ ] Magma Gelatin ⚠ +- [ ] Raw Stuffed Hoglin +- [ ] Stuffed Hoglin (feast, placeable) +- [ ] Plate of Roasted Hoglin +- [ ] Hoglin sausages ⚠ +- [ ] Hoglin burgers ⚠ +- [ ] Hoglin breakfast plate ⚠ + +## End's Delight ⚠ (item names unconfirmed — pull the full list from JEI in a test world) + +- [ ] End-dimension dishes — Shulker/Chorus-themed, exact names not published. Treat this mod as a "bonus dimension" quest stage and name the actual dish after checking in-game. + +## Delightful + +- [ ] Marshmallow on a Stick (raw + roasted) +- [ ] S'more +- [ ] Cheeseburger +- [ ] Deluxe Cheeseburger +- [ ] Jelly Bottle +- [ ] Glow Jelly Bottle +- [ ] Nut Butter Bottle +- [ ] Nut Butter and Jelly Sandwich +- [ ] Ender Nectar (utility item, single-use Ender Chest access — not really "food" to serve IRL) +- [ ] Cactus Flesh +- [ ] Cactus Steak +- [ ] Field Salad +- [ ] Acorn +- [ ] Raw Goat / Cooked Goat +- [ ] Raw Venison Chops / Cooked Venison Chops +- [ ] Cantaloupe Slice +- [ ] Salmonberries +- [ ] Salmonberry Pie +- [ ] Salmonberry Ice Cream +- [ ] Matcha Latte +- [ ] Berry Matcha Latte +- [ ] Matcha Ice Cream +- [ ] Green Tea Leaves (ingredient) +- [ ] Overhauled Pumpkin Pie (sliceable) + +(Delightful also adds cross-mod recipes like Crab Rangoon / Honey Glazed Walnut if Biomes O'Plenty/Ecologics are present — skip those, we're not installing those mods.) + +## Create × Farmer's Delight bridge mods (Delightful Creators / FarmersCreate / Create: Food) + +These mostly add **automation recipes** for dishes you already picked above (e.g. Create's Mixer can brew the same stews, the Deployer can run the cutting board) rather than brand-new meals. Worth noting for the roadmap's "build the automated kitchen" quest stage, but not a separate food source: +- [ ] Bottled/Barreled Soups & Stews (fluid form, for automation) +- [ ] Cut Pumpkin Pie (Create-automatable) +- [ ] Honey Cookie / Sweet Berry Cookie (Create-automatable) +- [ ] Chocolate Pie (Create-automatable) + +--- + +## Suggested picks for a 3-day / 10–12h roadmap + +A good spread that's realistic to actually cook IRL for a group: + +1. **Day 1 (Overworld basics):** Vegetable Soup → Bacon and Eggs → Mixed Salad +2. **Day 2 (mid-game / Nether run):** Pasta with Meatballs or Beef Stew → Hoglin Ham / Stuffed Hoglin +3. **Day 3 (feast finale):** Shepherd's Pie or Honey Glazed Ham feast, served as the literal centerpiece dish + +Strike anything above that's impractical to cook for 10–12 people (e.g. skip Dog Food, skip Ender Nectar — not food) and finalize your checklist. diff --git a/install.ps1 b/install.ps1 new file mode 100644 index 0000000..b19f677 --- /dev/null +++ b/install.ps1 @@ -0,0 +1,80 @@ +# LAN party bootstrap for Windows: installs Fjord Launcher Unlocked (DRM-free +# Prism fork), seeds a persistent offline account, drops in the pre-built +# modpack instance, and launches straight into it on the LAN server. +# +# Host this file via: python3 -m http.server 8000 (alongside modpack.zip) +# Participants run: irm http://:8000/install.ps1 | iex + +# ---- EDIT ME before hosting ---- +$HostUrl = "http://192.168.1.50:8000" +$ModpackUrl = "$HostUrl/modpack.zip" +$InstanceName = "LANParty" +$ServerAddr = "192.168.1.50:25565" +# --------------------------------- + +$InstallDir = Join-Path $env:USERPROFILE "mc-lan-party" +New-Item -ItemType Directory -Force -Path $InstallDir | Out-Null +Set-Location $InstallDir + +Write-Host "==> Setting up in $InstallDir" + +$release = Invoke-RestMethod -Uri "https://api.github.com/repos/hero-persson/FjordLauncherUnlocked/releases/latest" +$asset = $release.assets | Where-Object { $_.name -match "Windows-MSVC-Portable-.*\.zip$" } | Select-Object -First 1 +if (-not $asset) { + $asset = $release.assets | Where-Object { $_.name -match "Windows-MinGW-w64-Portable-.*\.zip$" } | Select-Object -First 1 +} +if (-not $asset) { throw "Could not find a Windows portable build in the latest Fjord Launcher Unlocked release." } + +Write-Host "==> Downloading $($asset.name)" +Invoke-WebRequest -Uri $asset.browser_download_url -OutFile "FjordLauncher.zip" +Expand-Archive -Path "FjordLauncher.zip" -DestinationPath "app" -Force +$LauncherBin = Get-ChildItem -Path "app" -Filter "fjordlauncher.exe" -Recurse | Select-Object -First 1 -ExpandProperty FullName +if (-not $LauncherBin) { throw "fjordlauncher.exe not found after extracting the portable build." } + +# ---- offline account: compute Mojang-style offline UUID so playerdata persists across launches ---- +$Nick = Read-Host "Minecraft nickname [$env:USERNAME]" +if ([string]::IsNullOrWhiteSpace($Nick)) { $Nick = $env:USERNAME } + +function Get-OfflineUuid([string]$name) { + $md5 = [System.Security.Cryptography.MD5]::Create() + $bytes = $md5.ComputeHash([System.Text.Encoding]::UTF8.GetBytes("OfflinePlayer:$name")) + $bytes[6] = ($bytes[6] -band 0x0f) -bor 0x30 + $bytes[8] = ($bytes[8] -band 0x3f) -bor 0x80 + $hex = -join ($bytes | ForEach-Object { $_.ToString("x2") }) + return "{0}-{1}-{2}-{3}-{4}" -f $hex.Substring(0,8), $hex.Substring(8,4), $hex.Substring(12,4), $hex.Substring(16,4), $hex.Substring(20,12) +} + +$Uuid = Get-OfflineUuid $Nick +$md5 = [System.Security.Cryptography.MD5]::Create() +$clientTokenBytes = $md5.ComputeHash([System.Text.Encoding]::UTF8.GetBytes("ClientToken:$Nick")) +$ClientToken = -join ($clientTokenBytes | ForEach-Object { $_.ToString("x2") }) +$Iat = [int][double]::Parse((Get-Date -UFormat %s)) + +$accounts = @{ + accounts = @( + @{ + active = $true + type = "Offline" + profile = @{ id = $Uuid; name = $Nick; capes = @(); skin = @{ id = ""; url = ""; variant = "" } } + entitlement = @{ canPlayMinecraft = $true; ownsMinecraft = $true } + ygg = @{ token = "0"; extra = @{ clientToken = $ClientToken; userName = $Nick }; iat = $Iat } + } + ) + formatVersion = 3 +} +$accounts | ConvertTo-Json -Depth 6 | Set-Content -Path "accounts.json" -Encoding UTF8 +Write-Host "==> Offline account '$Nick' ready (UUID $Uuid)" + +# ---- modpack instance ---- +New-Item -ItemType Directory -Force -Path "instances" | Out-Null +if (-not (Test-Path (Join-Path "instances" $InstanceName))) { + Write-Host "==> Downloading modpack from $ModpackUrl" + Invoke-WebRequest -Uri $ModpackUrl -OutFile "modpack.zip" + Expand-Archive -Path "modpack.zip" -DestinationPath "instances" -Force + Write-Host "==> Modpack installed to instances\$InstanceName" +} else { + Write-Host "==> Instance already present, skipping download" +} + +Write-Host "==> Launching into $InstanceName as $Nick, joining $ServerAddr" +& $LauncherBin --dir $InstallDir --launch $InstanceName --profile $Nick --server $ServerAddr diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..20e4038 --- /dev/null +++ b/install.sh @@ -0,0 +1,101 @@ +#!/usr/bin/env bash +# LAN party bootstrap: installs Fjord Launcher Unlocked (DRM-free Prism fork), +# seeds a persistent offline account, drops in the pre-built modpack instance, +# and launches straight into it on the LAN server. +# +# Host this file via: python3 -m http.server 8000 +# Participants run: curl -fsSL http://:8000/install.sh | bash +set -euo pipefail + +# ---- EDIT ME before hosting ---- +HOST_URL="http://192.168.1.50:8000" # where THIS script + modpack.zip are served from +MODPACK_URL="$HOST_URL/modpack.zip" # exported Prism instance folder, zipped (see HOSTING.md) +INSTANCE_NAME="LANParty" # must match the top-level folder name inside modpack.zip +SERVER_ADDR="192.168.1.50:25565" # your Minecraft server IP:port +GH_REPO="unmojang/FjordLauncherUnlocked" # fallback if hero-persson's fork disappears; see note below +# --------------------------------- + +INSTALL_DIR="$HOME/mc-lan-party" +mkdir -p "$INSTALL_DIR" +cd "$INSTALL_DIR" + +echo "==> Setting up in $INSTALL_DIR" + +os="$(uname -s)" +arch="$(uname -m)" + +api_url="https://api.github.com/repos/hero-persson/FjordLauncherUnlocked/releases/latest" +release_json="$(curl -fsSL "$api_url")" + +pick_asset() { + # $1 = grep pattern for the asset name + echo "$release_json" | grep -oE '"browser_download_url": *"[^"]+"' \ + | cut -d'"' -f4 | grep -E "$1" | head -n1 +} + +LAUNCHER_BIN="" + +if [[ "$os" == "Linux" ]]; then + if [[ "$arch" == "aarch64" ]]; then + url="$(pick_asset 'Linux-aarch64\.AppImage$')" + else + url="$(pick_asset 'Linux-x86_64\.AppImage$')" + fi + [[ -n "$url" ]] || { echo "Could not find a Linux AppImage in the latest release." >&2; exit 1; } + echo "==> Downloading $url" + curl -fsSL -o FjordLauncher.AppImage "$url" + chmod +x FjordLauncher.AppImage + LAUNCHER_BIN="$INSTALL_DIR/FjordLauncher.AppImage" +elif [[ "$os" == "Darwin" ]]; then + url="$(pick_asset 'macOS-.*\.zip$')" + [[ -n "$url" ]] || { echo "Could not find a macOS build in the latest release." >&2; exit 1; } + echo "==> Downloading $url" + curl -fsSL -o FjordLauncher.zip "$url" + unzip -oq FjordLauncher.zip -d app + app_path="$(find app -maxdepth 2 -name '*.app' | head -n1)" + LAUNCHER_BIN="$app_path/Contents/MacOS/$(ls "$app_path/Contents/MacOS" | head -n1)" +else + echo "Unsupported OS for install.sh: $os. Use install.ps1 on Windows." >&2 + exit 1 +fi + +# ---- offline account: compute Mojang-style offline UUID so playerdata persists across launches ---- +read -rp "Minecraft nickname [${USER:-Player}]: " NICK +NICK="${NICK:-${USER:-Player}}" + +md5hex="$(printf '%s' "OfflinePlayer:$NICK" | md5sum | cut -d' ' -f1)" +variant_nibble=$(( (16#${md5hex:16:1} & 3) | 8 )) +variant_hex="$(printf '%x' "$variant_nibble")" +patched="${md5hex:0:12}3${md5hex:13:3}${variant_hex}${md5hex:17:15}" +UUID="${patched:0:8}-${patched:8:4}-${patched:12:4}-${patched:16:4}-${patched:20:12}" +CLIENT_TOKEN="$(printf '%s' "ClientToken:$NICK" | md5sum | cut -d' ' -f1)" + +cat > accounts.json < Offline account '$NICK' ready (UUID $UUID)" + +# ---- modpack instance ---- +mkdir -p instances +if [[ ! -d "instances/$INSTANCE_NAME" ]]; then + echo "==> Downloading modpack from $MODPACK_URL" + curl -fsSL -o modpack.zip "$MODPACK_URL" + unzip -oq modpack.zip -d instances + echo "==> Modpack installed to instances/$INSTANCE_NAME" +else + echo "==> Instance already present, skipping download" +fi + +echo "==> Launching into $INSTANCE_NAME as $NICK, joining $SERVER_ADDR" +"$LAUNCHER_BIN" --dir "$INSTALL_DIR" --launch "$INSTANCE_NAME" --profile "$NICK" --server "$SERVER_ADDR" diff --git a/modpack.md b/modpack.md new file mode 100644 index 0000000..795a1cb --- /dev/null +++ b/modpack.md @@ -0,0 +1,47 @@ +# LAN Party Modpack — "Create & Delight" (MC 1.20.1, Forge) + +Target: **Minecraft 1.20.1, Forge**. This version/loader combo has the widest, most stable support across every mod below — don't mix in NeoForge/Fabric builds. + +## Core + +| Mod | Why it's in | +|---|---| +| [Create](https://www.curseforge.com/minecraft/mc-mods/create) | The automation/contraptions backbone. Gives the roadmap something to *build* toward (farms, kitchens, conveyor lines) before the food payoff. | +| [Flywheel](https://modrinth.com/mod/flywheel) | Required rendering engine dependency for Create (Forge build). | +| [Just Enough Items (JEI)](https://modrinth.com/mod/jei) | Not food itself, but mandatory — with this many food-adding mods stacked, nobody will find recipes without it. | + +## Cooking base + +| Mod | Adds | +|---|---| +| [Farmer's Delight](https://modrinth.com/mod/farmers-delight) | The core cooking/farming mod everything else builds on: cutting board, cooking pot, skillet, stews, pies, feasts. | + +## Farmer's Delight addons (the "roadmap fuel") + +| Mod | Adds | +|---|---| +| [Nether's Delight](https://modrinth.com/mod/nethers-delight) | Nether-themed cooking: Hoglin loin/ham/hide, nether salad, stuffed Hoglin, nether skewers. | +| [End's Delight](https://modrinth.com/mod/ends-delight) | End-dimension culinary content (shulker/chorus-themed dishes). Item list is thin on public docs — verify in-game with JEI before committing recipes to the IRL roadmap. | +| [Delightful](https://modrinth.com/mod/delightful) | Big grab-bag of immersive new foods independent of any dimension: marshmallows/s'mores, cheeseburgers, nut butter & jelly sandwiches, goat/venison, berry pies, matcha. | +| [Delightful Creators](https://modrinth.com/mod/delightful-creators) | Bridges Create ↔ Farmer's Delight: soups/stews as Create fluids, sequenced-assembly "incomplete foods," cookie/pie recipes usable in Create contraptions. | +| [FarmersCreate](https://modrinth.com/mod/farmerscreate) | Lets Create's Mixer/Deployer automate Farmer's Delight cooking-pot and cutting-board recipes (auto-cook the feast, don't stand there clicking). | + +## Performance utility + +| Mod | Side | Why it's in | +|---|---|---| +| [Distant Horizons](https://modrinth.com/mod/distanthorizons) | Client only | Renders a simplified level-of-detail view of terrain beyond the server's `view-distance`, so players see far-off scenery without the server having to actually load/send those chunks. Does the same job you were picturing from "Bobby" — Bobby itself is **Fabric-only** (no Forge build exists), so Distant Horizons is the Forge equivalent. Caches the LOD data locally per-world, same idea as Bobby's chunk cache. | +| [Chunky](https://www.curseforge.com/minecraft/mc-mods/chunky-pregenerator-forge) | Server only | Pre-generates a fixed radius of chunks around a chosen center (e.g. spawn/build area) **once, before the party**, via console/RCON commands (`/chunky radius`, `/chunky start`) — eliminates on-the-fly world-gen lag while people explore. **Not** a per-player dynamic follower on Forge — that variant ("Chunky Pregenerator") is Fabric-only, same restriction as Bobby. See `HOSTING.md` for the exact commands. | + +**Important:** install Distant Horizons in the client instance's `mods/` folder only — do **not** put it in the server's `mods/` folder. It tags itself as client-side in its mod metadata, so Forge won't reject the mismatched mod list between client and server. Keep the server's `server.properties` `view-distance` modest (6–8, see `HOSTING.md` sizing section) and let Distant Horizons fill in the rest visually on each client. Chunky, conversely, only needs to go in the **server's** `mods/` folder — it has no client-side purpose here. + +## Optional / stretch (only if the group wants more scope) + +| Mod | Adds | Caveat | +|---|---|---| +| [Aether's Delight](https://modrinth.com/mod/the-aethers-delight) | Aether-themed dishes (Holystone/Zanite knives, berry bowls, buffed meals) | Requires installing **The Aether** too — a full extra dimension mod. Only add if someone really wants to make the trip. | + +## Why this shape + +- Create gives you *progression* (you have to build the farm/kitchen contraption before you "unlock" a dish) — good quest-line material. +- Farmer's Delight + addons give you the actual *food variety* across three dimensions (Overworld/Nether/End) plus a flavor-pack (Delightful) that isn't dimension-gated, so you can pace the 3-day roadmap: early-game Overworld dishes → mid-game Nether run → late-game End dish as the "final boss" meal. diff --git a/server/setup-server.sh b/server/setup-server.sh new file mode 100755 index 0000000..08e628a --- /dev/null +++ b/server/setup-server.sh @@ -0,0 +1,145 @@ +#!/usr/bin/env bash +# One-time setup for the LAN party's dedicated box: installs a Forge 1.20.1 +# Minecraft server, wraps it in lazymc (auto-sleep when empty / auto-wake on +# connect), and serves the client install scripts + modpack.zip over HTTP — +# all as systemd services so the box can run unattended for the 3 days. +# +# Target: a Linux machine (Debian/Ubuntu/etc with systemd) at the venue. +# Run as a normal user with sudo rights: ./setup-server.sh +set -euo pipefail + +# ---- EDIT ME ---- +FORGE_MC_VERSION="1.20.1" +FORGE_BUILD="47.4.28" # current recommended build for 1.20.1 — check files.minecraftforge.net if this is stale +MC_PUBLIC_PORT=25565 # what players connect to (lazymc listens here) +MC_INTERNAL_PORT=25566 # real server listens here, lazymc proxies to it +FILESERVER_PORT=8000 # install.sh / install.ps1 / modpack.zip served from here +SLEEP_AFTER="5m" # idle time before lazymc stops the real server +MIN_RAM="2G" +MAX_RAM="6G" # 5-8 players; see ../HOSTING.md sizing table — bump to 8G (9-12p) or 10-12G (13-15p) +# ------------------ + +BASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SERVER_DIR="$BASE_DIR/mcserver" +DIST_DIR="$BASE_DIR/dist" +FORGE_VERSION="${FORGE_MC_VERSION}-${FORGE_BUILD}" + +command -v java >/dev/null || { echo "Java not found. Install a Java 17+ JDK (e.g. 'sudo apt install -y openjdk-17-jre-headless') then re-run."; exit 1; } +command -v python3 >/dev/null || { echo "python3 not found. Install it (e.g. 'sudo apt install -y python3') then re-run."; exit 1; } + +mkdir -p "$SERVER_DIR" "$DIST_DIR" + +# ---- 1. Install the Forge server ---- +if [[ ! -f "$SERVER_DIR/run.sh" ]]; then + echo "==> Downloading Forge $FORGE_VERSION installer" + installer_url="https://maven.minecraftforge.net/net/minecraftforge/forge/${FORGE_VERSION}/forge-${FORGE_VERSION}-installer.jar" + curl -fsSL -o "$SERVER_DIR/forge-installer.jar" "$installer_url" + + read -rp "Do you accept the Minecraft EULA (https://aka.ms/MinecraftEULA)? [y/N] " eula_ans + [[ "$eula_ans" =~ ^[Yy]$ ]] || { echo "EULA not accepted, aborting."; exit 1; } + + echo "==> Running Forge server installer" + (cd "$SERVER_DIR" && java -jar forge-installer.jar --installServer) + echo "eula=true" > "$SERVER_DIR/eula.txt" +else + echo "==> Forge server already installed, skipping" +fi + +# server.properties: lazymc will rewrite host/port/rcon itself, we just set gameplay-relevant bits +touch "$SERVER_DIR/server.properties" +for kv in "online-mode=false" "motd=LAN Party - Create & Delight" "difficulty=normal" "max-players=20"; do + key="${kv%%=*}" + if grep -q "^${key}=" "$SERVER_DIR/server.properties" 2>/dev/null; then + sed -i "s/^${key}=.*/${kv}/" "$SERVER_DIR/server.properties" + else + echo "$kv" >> "$SERVER_DIR/server.properties" + fi +done + +mkdir -p "$SERVER_DIR/mods" +echo "==> NOTE: copy the same mod jars from your client modpack's mods/ folder into $SERVER_DIR/mods/ (Create, Flywheel, Farmer's Delight + addons, JEI, etc.) before first boot." + +# ---- 2. Install lazymc ---- +if [[ ! -x "$BASE_DIR/lazymc" ]]; then + echo "==> Downloading latest lazymc" + api_url="https://api.github.com/repos/timvisee/lazymc/releases/latest" + release_json="$(curl -fsSL "$api_url")" + asset_url="$(echo "$release_json" | grep -oE '"browser_download_url": *"[^"]+linux-x64"' | cut -d'"' -f4 | head -n1)" + [[ -n "$asset_url" ]] || { echo "Could not find linux-x64 lazymc asset" >&2; exit 1; } + curl -fsSL -o "$BASE_DIR/lazymc" "$asset_url" + chmod +x "$BASE_DIR/lazymc" +else + echo "==> lazymc already present, skipping" +fi + +cat > "$BASE_DIR/lazymc.toml" < Wrote lazymc.toml (sleeps after ${SLEEP_AFTER} empty, public port ${MC_PUBLIC_PORT} -> internal ${MC_INTERNAL_PORT})" + +# ---- 3. systemd services ---- +sudo tee /etc/systemd/system/mc-lazymc.service >/dev/null </dev/null < Done." +echo " - Minecraft server: public port ${MC_PUBLIC_PORT}, sleeps after ${SLEEP_AFTER} idle, wakes on connect." +echo " - File server: http://:${FILESERVER_PORT}/ serving ${DIST_DIR}/" +echo " - Put install.sh, install.ps1 and modpack.zip into ${DIST_DIR}/ (see ../HOSTING.md)." +echo " - Copy your client mod jars into ${SERVER_DIR}/mods/ if you haven't yet, then: sudo systemctl restart mc-lazymc" +if command -v ufw >/dev/null && sudo ufw status | grep -q "Status: active"; then + echo "==> ufw is active — opening ${MC_PUBLIC_PORT}/tcp and ${FILESERVER_PORT}/tcp" + sudo ufw allow "${MC_PUBLIC_PORT}/tcp" + sudo ufw allow "${FILESERVER_PORT}/tcp" +fi