Add LAN party modpack, server automation, and client install scripts
Covers the Create + Farmer's Delight modpack list, food roadmap pool, cross-platform client bootstrap (offline account + modpack + auto-join), and the venue-box server setup (lazymc idle sleep/wake, Chunky pregen, file distribution).
This commit is contained in:
@@ -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
|
||||
+94
@@ -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 (`"<server name> <ip>:<port>"` 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://<venue-box-lan-ip>:8000`
|
||||
- `SERVER_ADDR` / `$ServerAddr` → `<venue-box-lan-ip>: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 <password from server.properties> "<command>"`):
|
||||
|
||||
```
|
||||
/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://<your-lan-ip>:8000/install.ps1 | iex`
|
||||
- **Linux / macOS:** `curl -fsSL http://<your-lan-ip>: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.
|
||||
@@ -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.
|
||||
+80
@@ -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://<host-ip>: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
|
||||
Executable
+101
@@ -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://<host-ip>: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 <<EOF
|
||||
{
|
||||
"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": "$CLIENT_TOKEN", "userName": "$NICK" }, "iat": $(date +%s) }
|
||||
}
|
||||
],
|
||||
"formatVersion": 3
|
||||
}
|
||||
EOF
|
||||
echo "==> 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"
|
||||
+47
@@ -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.
|
||||
Executable
+145
@@ -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" <<EOF
|
||||
[server]
|
||||
directory = "$SERVER_DIR"
|
||||
command = "bash run.sh nogui -Xms${MIN_RAM} -Xmx${MAX_RAM}"
|
||||
address = "127.0.0.1:${MC_INTERNAL_PORT}"
|
||||
freeze_process = false
|
||||
wake_whitelist = false
|
||||
|
||||
[public]
|
||||
address = "0.0.0.0:${MC_PUBLIC_PORT}"
|
||||
|
||||
[time]
|
||||
sleep_after = "${SLEEP_AFTER}"
|
||||
minimum_online_time = "1m"
|
||||
|
||||
[motd]
|
||||
sleeping = "☀ Server is asleep, join to wake it up"
|
||||
starting = "⏳ Server is starting, hang tight..."
|
||||
|
||||
[rcon]
|
||||
enabled = true
|
||||
port = 25575
|
||||
EOF
|
||||
echo "==> 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 <<EOF
|
||||
[Unit]
|
||||
Description=LAN party Minecraft server (via lazymc)
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=${BASE_DIR}
|
||||
ExecStart=${BASE_DIR}/lazymc
|
||||
Restart=on-failure
|
||||
User=${USER}
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
sudo tee /etc/systemd/system/mc-fileserver.service >/dev/null <<EOF
|
||||
[Unit]
|
||||
Description=LAN party modpack/install-script file server
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=${DIST_DIR}
|
||||
ExecStart=/usr/bin/python3 -m http.server ${FILESERVER_PORT}
|
||||
Restart=on-failure
|
||||
User=${USER}
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now mc-lazymc.service mc-fileserver.service
|
||||
|
||||
echo "==> Done."
|
||||
echo " - Minecraft server: public port ${MC_PUBLIC_PORT}, sleeps after ${SLEEP_AFTER} idle, wakes on connect."
|
||||
echo " - File server: http://<this-box-lan-ip>:${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
|
||||
Reference in New Issue
Block a user