Compare commits
18
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
387ee1ef9b | ||
|
|
e371e51856 | ||
|
|
b6ebdb850d | ||
|
|
455e398018 | ||
|
|
86b6620fba | ||
|
|
07ec53727e | ||
|
|
1108ed2abb | ||
|
|
cb90f36e98 | ||
|
|
2fcb8b492e | ||
|
|
769af6fa2d | ||
|
|
1d02bf1cf6 | ||
|
|
7e998fa39f | ||
|
|
b7a7d5add3 | ||
|
|
c6eb2e3cd5 | ||
|
|
eeaca31162 | ||
|
|
b7fde64573 | ||
|
|
25b3f78cdc | ||
|
|
be07001d79 |
No files matched your search
@@ -0,0 +1,2 @@
|
||||
# C2ME runtime worldgen class cache (regenerated at runtime; see .packwizignore)
|
||||
cache/
|
||||
+25
-4
@@ -11,13 +11,20 @@ run.sh
|
||||
*.jar
|
||||
*.jar.log
|
||||
run.bat
|
||||
# Server/runtime config is never tracked; only explicit modpack-default configs
|
||||
# (e.g. the FTB Chunks client config) are shipped.
|
||||
# Server/runtime config is opt-in. Everything under these directories is
|
||||
# ignored; deliberately authored defaults are re-included at the bottom of
|
||||
# this file. This repo doubles as a server directory, so a blanket un-ignore
|
||||
# here would pull every runtime-generated config into the index.
|
||||
config/*
|
||||
!config/ftbchunks-client.snbt
|
||||
defaultconfigs/*
|
||||
kubejs/
|
||||
defaultconfigs/
|
||||
local/
|
||||
|
||||
# Authoring/review material - belongs in the repo, never in the pack
|
||||
FINDINGS.md
|
||||
MODLIST-*.md
|
||||
analysis/
|
||||
phase0/
|
||||
ftbbackups3/
|
||||
patchouli_books/
|
||||
.sable/
|
||||
@@ -28,3 +35,17 @@ patchouli_books/
|
||||
resourcepacks/*.zip
|
||||
start.sh
|
||||
tools/
|
||||
|
||||
# C2ME runtime worldgen cache (regenerated at runtime)
|
||||
cache/
|
||||
|
||||
# Scratch artifacts from the map-migration tooling - never ship these
|
||||
sp-world/
|
||||
*.tar.gz
|
||||
*.tgz
|
||||
|
||||
# --- Shipped config defaults ----------------------------------------------
|
||||
# These must come AFTER every ignore above (last matching pattern wins),
|
||||
# including the blanket "*.json" in the authoring section. Re-include only
|
||||
# files we deliberately author and want enforced on install.
|
||||
!config/petprotect.json
|
||||
@@ -0,0 +1,179 @@
|
||||
# FTB Chunks -> Open Parties and Claims + Xaero's maps
|
||||
|
||||
**Status:** shipped - 2026-09-30 (`1d02bf1`, pushed). FTB Quests/Teams/XMod Compat removed after the
|
||||
swap; see section 8.
|
||||
**Decision:** replace FTB Chunks with **Open Parties and Claims (OPAC)** for claims/forceloading and
|
||||
**Xaero's World Map + Minimap** for mapping, and drop the rest of the FTB suite that depended on it.
|
||||
Remaining FTB mods: **FTB Backups 3** and **FTB Library** only.
|
||||
**Accepted cost:** every player re-claims their land and re-creates their waypoints, and any FTB Quests
|
||||
content and per-team progress is discarded.
|
||||
|
||||
Confidence tags follow `FINDINGS.md`: **VERIFIED** / **DOCUMENTED** / **COMMUNITY** / **INFERENCE**.
|
||||
|
||||
---
|
||||
|
||||
## 1. Why this works at all
|
||||
|
||||
The pack's earlier review (`MODLIST-REVIEW.md` §8) recommended keeping FTB Chunks on the grounds that
|
||||
"wholesale replacement breaks FTB Quests/Teams". That is only true of a *wholesale* FTB removal.
|
||||
**VERIFIED:** FTB Quests' build declares `ftb-library` + `ftb-teams` as required and `ftb-xmod-compat`
|
||||
as optional - **not** FTB Chunks. FTB Quests also ships **no** claim-chunk task type. So FTB Chunks is
|
||||
the one mod in the FTB suite that can leave without touching quests, provided Teams stays.
|
||||
|
||||
**VERIFIED:** nothing else in the pack declares FTB Chunks as a required dependency. The only
|
||||
cross-mod hooks are inside FTB XMod Compat (KubeJS/GameStages progression, rank-based claim limits),
|
||||
which degrade to inert modules.
|
||||
|
||||
## 2. What changed
|
||||
|
||||
| Action | Path |
|
||||
| --- | --- |
|
||||
| Removed | `mods/ftb-chunks-forge.pw.toml` (was `ftb-chunks-neoforge-2101.1.22`, CF 314906) |
|
||||
| Removed | `config/ftbchunks-client.snbt` (the `minimap.enabled=true` modpack default) |
|
||||
| Edited | `.packwizignore` - dropped `config/*` + `!config/ftbchunks-client.snbt`, back to `config/` |
|
||||
| Added | `mods/open-parties-and-claims.pw.toml` - `neoforge-1.21.1-0.31.6` (`side = "both"`) |
|
||||
| Added | `mods/xaeros-world-map.pw.toml` - `neoforge-1.21.1-1.46.0` (`side = "both"`) |
|
||||
| Added | `mods/xaeros-minimap.pw.toml` - `neoforge-1.21.1-26.5.0` (`side = "both"`) |
|
||||
| Added | `mods/xaeros-minimap-world-map-waystones-compatibility-forge.pw.toml` - `2.1.0` |
|
||||
| Regenerated | `index.toml` (147 entries) and the `[index]` hash in `pack.toml` |
|
||||
|
||||
Net: **146 mods** (138 Modrinth/other + 8 CurseForge), down from 9 CurseForge-exclusive mods. All four
|
||||
new mods are Modrinth-hosted, so they are checkable by `packwiz update`.
|
||||
|
||||
The three Xaero's entries are byte-identical to the ones deleted in `b0542f9` (2026-09-28) - same
|
||||
versions, same sha512s - so this is a revert of the map half of that commit, not a new integration.
|
||||
|
||||
## 3. Where the pack traded one thing for another
|
||||
|
||||
| FTB Chunks capability | Replacement | Notes |
|
||||
| --- | --- | --- |
|
||||
| Chunk claims + protection | OPAC | Server config now lives in the world save, not the pack. |
|
||||
| Forceload + offline ticking | OPAC `claims.forceload.offlineForceload` | Farms-vs-TPS trade is unchanged; reliability is less proven (see §5). |
|
||||
| Minimap + fullscreen map | Xaero's Minimap + World Map | Now two client mods instead of one. |
|
||||
| Waypoints + teleport | Xaero's Minimap | **No migration path** - see §4. |
|
||||
| Party/team claims | OPAC's built-in party system | FTB Teams was removed, so this is the only party system now. `/oparties`, `/opm` for party chat. |
|
||||
| Waystones on the map | `xaeros_waystones_compatibility` | Restored; it had been removed with the maps. |
|
||||
| FTB Ranks permission overrides | `xaero.pac_max_claims` / `xaero.pac_max_forceloads` | Moot in practice: FTB Ranks was never installed. |
|
||||
|
||||
## 4. Migration runbook (server operator)
|
||||
|
||||
**Before the update**
|
||||
1. Take a world backup. FTB Chunks' claim data stays in the save after the mod is removed, so this
|
||||
backup is the rollback path.
|
||||
2. Have each player screenshot or export their FTB Chunks waypoints. They live client-side under
|
||||
`local/ftbchunks/`; **there is no FTB Chunks -> Xaero's converter** (only JourneyMap -> Xaero tools
|
||||
exist). Re-entry is manual.
|
||||
3. Capture who owned which claims/forceloads, so players have a checklist and an admin can pre-claim
|
||||
using OPAC server-claim mode if desired.
|
||||
|
||||
**Cutover (one update, low-activity window)**
|
||||
4. Do **not** run FTB Chunks and OPAC side by side - two claim systems means split protection logic.
|
||||
Hard cutover.
|
||||
5. Start the server once with OPAC installed so it generates
|
||||
`world/serverconfig/openpartiesandclaims-server.toml`, then **stop the server**.
|
||||
6. Edit the generated file (it carries `# Default:` comments for every key) and set at minimum:
|
||||
- `maxPlayerClaims = 500` (matches the old FTB Chunks cap)
|
||||
- `maxPlayerClaimForceloads = 25` (**decided 2026-09-30**; the stock default is lower, so leaving it
|
||||
alone silently removes forceloading)
|
||||
- `primaryPartySystem` -> leave at the built-in default (FTB Teams is gone; do **not** point it at
|
||||
`ftbteams`)
|
||||
- a decision on `claims.forceload.offlineForceload` (farms while offline vs TPS)
|
||||
- add `claims.forceload.offlineForceload` to `playerConfigurablePlayerConfigOptions` /
|
||||
`opConfigurablePlayerConfigOptions` if players should be able to toggle their own
|
||||
7. Re-claim: each player re-claims their base and re-forceloads, via the OPAC UI (`'`) or the Xaero's
|
||||
world map (right-click / drag-select).
|
||||
|
||||
**After**
|
||||
8. Verify per-player forceloading actually keeps chunks ticking with the owner offline. This is the
|
||||
known weak point (§5).
|
||||
9. Verify protection across the modded stack - especially Create contraptions, Sable ships, and
|
||||
fake-player automation.
|
||||
10. Re-tier any rank/permission limits you were relying on.
|
||||
|
||||
## 5. Risks and open items
|
||||
|
||||
- **OPAC force-loading reliability is the one thing that can invalidate the swap.** Open upstream
|
||||
issues report chunks marked forceloadable but never actually loaded (#855, #927, plus #237/#528).
|
||||
**COMMUNITY.** Test before trusting; re-test on every OPAC bump. If it fails, this swap should be
|
||||
rolled back - forceloading is the one feature the pack cannot work around.
|
||||
- **OPAC is self-described beta** and releases frequently (0.31.6, 2026-09-10). **DOCUMENTED.**
|
||||
- **OPAC and Xaero's are version-coupled** - OPAC's README tells users to keep the Xaero's mods on
|
||||
their latest versions. Bump them together.
|
||||
- **Claim protection parity is unverified.** OPAC protects vanilla plus a supported-mod list (Create is
|
||||
built in on Forge), and needs manual exception entries for anything else. Open reports exist for
|
||||
creeper explosions (#731) and modded projectiles (#758) inside claims. **COMMUNITY.** The pack's
|
||||
Apotheosis/Sophisticated/Ars Nouveau/Alex's Mobs surface needs a pass.
|
||||
- **Sable / Create Aeronautics.** A crash with Sable contraptions was reported (#873) and is **closed**,
|
||||
but was not re-verified against 0.31.6. **COMMUNITY.** Ships are not covered by plain chunk claims
|
||||
under either system; the pack has no ship-claim mod. Options if that matters:
|
||||
`aeroclaims` ("Create Aeronautics: Claims", NeoForge 1.21.1, works with **OPAC or FTB**), or
|
||||
`sable-protect`. Note that dropping FTB Chunks does close the door on `ftbchunksaerospace` and
|
||||
`Create-Aeronautics-FTB-Chunks`.
|
||||
- **Licensing.** OPAC is **LGPL-3.0** - no pack conditions. Xaero's World Map and Minimap are
|
||||
**All Rights Reserved**: because this pack is distributed from `git.ljones.me` and not from
|
||||
CurseForge/Modrinth, the terms require an **easily accessible credit link to an official Xaero page**
|
||||
in the pack. Add one. **VERIFIED** (from the mods' own "Modpacks and Other" sections).
|
||||
- **`side = "both"` for Xaero's** puts them on the server too. That buys reliable multi-world map
|
||||
identity and server-side map profiles, and matches the pre-`b0542f9` configuration, but the server
|
||||
then registers status effects that stop *vanilla* clients joining unless disabled in
|
||||
`config/xaero/*`. All players get mods via packwiz, so this is not expected to matter.
|
||||
- **Vanilla-client / optional-client is actually improved** for claims: OPAC's client side is optional,
|
||||
so a player without it is still protected and can use `/oclaims` chat commands.
|
||||
|
||||
## 6. Rollback
|
||||
|
||||
Re-add `mods/ftb-chunks-forge.pw.toml` (and the client config if the minimap default is wanted) and
|
||||
`packwiz refresh`. FTB Chunks' claim/forceload data is untouched in the world save, so existing claims
|
||||
resume. Then remove OPAC and the Xaero's mods. Keep the pre-swap world backup regardless.
|
||||
|
||||
Note: rolling back the FTB Quests/Teams removal is a separate, larger job - re-adding them restores the
|
||||
mods but **not** any quest content or team progress that was discarded, unless `<world>/ftbquests/` was
|
||||
archived first.
|
||||
|
||||
## 7. Follow-up: removing the rest of the FTB suite
|
||||
|
||||
Follow-on decision (2026-09-30): drop **FTB Quests, FTB Teams and FTB XMod Compat** as well, leaving
|
||||
only FTB Backups 3 and FTB Library.
|
||||
|
||||
**Why FTB Teams could not go on its own** - FTB Quests has a hard runtime dependency on it, not just a
|
||||
launcher one:
|
||||
|
||||
| Evidence | Result |
|
||||
| --- | --- |
|
||||
| `FTB-Quests@1.21.1/main` build.gradle | `requires('ftb-library-forge')`, `requires('ftb-teams-forge')` |
|
||||
| FTB Quests bytecode | references `dev/ftb/mods/ftbteams/` in **14 classes**, incl. `FTBQuestsEventHandler` |
|
||||
| FTB Quests internals | `TeamData` class - quest progress is keyed per team |
|
||||
|
||||
The `mandatory = false` in FTB's `neoforge.mods.toml` files is launcher metadata; the bytecode
|
||||
references are what actually break. FTB Quests also ships no claim-chunk task type, so nothing about
|
||||
claims depended on it.
|
||||
|
||||
**Why XMod Compat went with it:** its integrations were Quests/Chunks/Ranks plus JEI/KubeJS/LuckPerms
|
||||
bridges. With Quests and Chunks gone there is nothing left for it to bridge.
|
||||
|
||||
**Why Library stayed:** FTB Backups 3 uses FTB Library's config/UI classes (`Panel`, `Theme`, `Widget`,
|
||||
`ConfigGroup`, `ConfigValue`, `SNBTCompoundTag`) - 13 classes, and it does **not** bundle them, despite
|
||||
declaring only `neoforge` in its own metadata. Library in turn references `dev/architectury` in 47
|
||||
classes, so Architectury API stays too.
|
||||
|
||||
**Verified before removing:** FTB Library and FTB Backups 3 reference `ftbteams`, `ftbquests` and
|
||||
`ftbxmodcompat` in **0 classes** each, and nothing else in the pack references XMod Compat.
|
||||
|
||||
**Consequences accepted:** any authored FTB Quests content and per-team quest progress is discarded.
|
||||
There is no longer any party system to point OPAC at, so `primaryPartySystem` stays at OPAC's built-in
|
||||
default. The pack dropped from 9 to **5 CurseForge-sourced mods** and from 149 to 146 mods.
|
||||
|
||||
## 8. Docs that need follow-up
|
||||
|
||||
- **Map/waypoint rescue from the old FTB data** - see `analysis/FTB-XAERO-MAP-MIGRATION.md` and the
|
||||
`tools/ftbchunks-reveal.py` + `tools/prune-world-to-reveal.py` scripts. Mask extraction is validated;
|
||||
the world-save pruning step is written and unit-tested but not yet run.
|
||||
|
||||
- `FINDINGS.md` - §3.3, §7.1, §8 rows 2-3, appendix A and appendix B updated in this change; §1's
|
||||
mod-count statistics were left at their earlier snapshot (a note was added).
|
||||
- `MODLIST-REVIEW.md` §7.4 and §8 still say Open Parties and Claims is a SKIP/duplication and "Keep
|
||||
FTB". **Stale** - the swap is now the intended design.
|
||||
- `MODLIST-GROUPS.md` / `analysis/master-table.md` / `analysis/groups-table.md` carry the same stale
|
||||
OPAC verdict.
|
||||
- Not done: re-adding `xaero-train-map` (was `Ov2r3aVY`, 1.0.0). It is unblocked again by this change and
|
||||
the pack has Create trains; one-line addition if wanted.
|
||||
@@ -0,0 +1,214 @@
|
||||
# FTB Chunks reveal -> Xaero's World Map: what transfers and how
|
||||
|
||||
**Status:** mask extraction implemented and validated against real data; world-save pruning implemented
|
||||
and unit-tested; final step blocked on a copy of the server world save.
|
||||
**Goal:** give each player a native Xaero's map covering, as closely as possible, exactly the terrain
|
||||
they had revealed in FTB Chunks.
|
||||
Confidence tags as in `FINDINGS.md`.
|
||||
|
||||
---
|
||||
|
||||
## 1. Why we do not convert the pixels
|
||||
|
||||
FTB Chunks does **not** store a rendered map image. Verified by decompiling the pack's exact build,
|
||||
`ftb-chunks-neoforge-2101.1.22.jar` (class strings in `MapManager`, `MapRegionData`, `MapDimension`,
|
||||
`MapChunk`):
|
||||
|
||||
```
|
||||
<game>/local/ftbchunks/data/<serverUUID>/
|
||||
├── dimensions.txt, block_map.txt, biome_map.txt
|
||||
└── <dimension>/
|
||||
└── <XXXXX-XXXXX>.zip # region = 512x512 blocks; name = region coord + 60000, %05X-%05X
|
||||
├── chunks.dat # the chunks this player has actually seen
|
||||
├── data.png # NOT viewable: (height << 16) | (water|light|biome) per pixel
|
||||
├── foliage.png # biome-tinted foliage RGB
|
||||
├── grass.png # biome-tinted grass RGB
|
||||
├── water.png # biome-tinted water RGB
|
||||
└── blocks.png # FTB's internal 24-bit block colour index
|
||||
```
|
||||
|
||||
The colour a player actually saw is computed at runtime by combining `blocks.png`'s index with FTB's own
|
||||
`BlockColor` model via `block_map.txt`. Reproducing it means reimplementing FTB Chunks' renderer, and the
|
||||
result would look like FTB's map - i.e. worse than native Xaero's. So we take the **reveal footprint**
|
||||
from FTB Chunks and the **pixels** from Xaero's.
|
||||
|
||||
## 2. Why we also do not write Xaero region files
|
||||
|
||||
The current Xaero's region format is not the format the community tools understand. Comparing a real
|
||||
`region.xaero` from Xaero's World Map 1.46.0 (extracted from the client instance) with the format
|
||||
`JMtoXaero/RegionToXaero` writes:
|
||||
|
||||
| | old format (RegionToXaero) | real 1.46.0 |
|
||||
| --- | --- | --- |
|
||||
| header | `FF` then int 4 | `FF 00 06 00 08` + varying byte (format 6) |
|
||||
| pixel payload | 4-byte parameters (+ optional state / colour / biome) | embeds NBT compounds |
|
||||
| size for region `0,0` | ~25 KB | **355 KB** |
|
||||
|
||||
The 1.46.0 payload contains literal NBT - e.g. `0A 00 00 08 00 04 "Name" 00 10 "minecraft:gravel"` - so
|
||||
each pixel now carries a block descriptor. This matches `JMtoXaero`'s own admission that its region
|
||||
**merger** broke once Xaero changed the format. Writing this format is a live reverse-engineering project
|
||||
against a closed, obfuscated, moving target. Not worth it.
|
||||
|
||||
**Therefore: drive Xaero's own generator, and control what it can see.**
|
||||
|
||||
## 3. The mechanism
|
||||
|
||||
Both mods use the same geometry - a region is 512x512 blocks = 32x32 chunks - so an FTB region maps 1:1
|
||||
onto one Anvil region file, and an FTB within-region chunk `(x,z)` maps 1:1 onto Anvil slot
|
||||
`x + z*32`. That makes the transplant exact rather than approximate:
|
||||
|
||||
1. Extract each player's reveal set from their `chunks.dat` files.
|
||||
2. Prune a copy of the world save to exactly those chunks (Anvil header/sector surgery; chunk payloads
|
||||
copied byte-for-byte, no NBT re-encoding).
|
||||
3. The player opens the pruned save in **singleplayer** with the pack; Xaero's maps it directly from the
|
||||
save, so absent chunks simply never appear on the map.
|
||||
4. Copy the generated instance
|
||||
(`xaero/world-map/World/null/<map>/`) into the server's folder
|
||||
(`xaero/world-map/Multiplayer_advilplug.top/<DIM>/`).
|
||||
|
||||
Result: **per-chunk-exact reveal extent**, rendered natively by Xaero's. Residual differences are only
|
||||
the colour palette/shading (Xaero's, not FTB's) - which is the whole point.
|
||||
|
||||
## 4. What the real data says
|
||||
|
||||
Measured on the supplied archive - **Stirwick**, `minecraft:overworld`:
|
||||
|
||||
| Metric | Value |
|
||||
| --- | --- |
|
||||
| Region files | 167 |
|
||||
| Revealed chunks | **98,170** (of 171,008 in the bounding box) |
|
||||
| Region extent | x `-9..9`, z `-14..7` |
|
||||
| Block extent | x `-4608..5120`, z `-7168..4096` |
|
||||
| Fully revealed regions (`1024/1024`) | 10 |
|
||||
| Median region fill | 560 / 1024 (~55%) |
|
||||
| Sparse regions (`<64` chunks) | 10 |
|
||||
| `chunks.dat` vs `data.png` disagreements | **0** |
|
||||
|
||||
Two consequences:
|
||||
|
||||
- **`chunks.dat` alone is a trustworthy mask.** It was cross-checked against the `data.png` height
|
||||
sentinel (`HeightUtils.UNKNOWN = Short.MIN_VALUE + 1 = -32767`) for all 167 regions. Zero
|
||||
disagreements. Suspicion that claimed-but-never-visited chunks would inflate the set did not
|
||||
materialise.
|
||||
- **Region-granularity pruning is not good enough.** The median region is only ~55% explored, and 10
|
||||
regions are under 6%. Copying whole `.mca` files a player touched would reveal roughly twice the
|
||||
terrain they had seen. Chunk-level pruning is worth the extra ~40 lines.
|
||||
|
||||
`data.png` decoding detail, for anyone revisiting this: FTB writes `(height << 16) | wlb` into a
|
||||
`TYPE_INT_ARGB` image, so after PNG round-trip the 16-bit height is `(A << 8) | R` and the
|
||||
water/light/biome word is `(G << 8) | B`. Unrevealed pixels are exactly `A=0x80, R=0x01`.
|
||||
|
||||
## 5. Tooling
|
||||
|
||||
Both scripts are stdlib-only and live in `tools/` (which `.packwizignore` excludes, so they never ship).
|
||||
|
||||
`tools/migrate-player.sh` - the driver, does steps 1-2 and prints the manual remainder:
|
||||
|
||||
```
|
||||
tools/migrate-player.sh Stirwick <ftb-data-or-archive> <world-dir> \
|
||||
--dimension minecraft:overworld --work /var/tmp/xaero-migration
|
||||
```
|
||||
|
||||
`tools/ftbchunks-reveal.py` - **validated against Stirwick's real 167-region archive.**
|
||||
Emits a JSON mask of global chunk coordinates per dimension. Pass `--dimension` when the input is a
|
||||
bare directory/zip of region files, which cannot name its own dimension.
|
||||
|
||||
```
|
||||
tools/ftbchunks-reveal.py <ftb-data-or-archive> --out mask.json --dimension minecraft:overworld --verify
|
||||
```
|
||||
|
||||
`tools/filter-xaero-regions.py` - post-harvest cleanup. Compares the Xaero's map folder against the
|
||||
mask and removes regions the player never revealed (i.e. terrain Minecraft regenerated around the
|
||||
login position). File-name-only, so no Xaero format knowledge needed; reports before deleting.
|
||||
|
||||
```
|
||||
tools/filter-xaero-regions.py <game>/xaero/world-map/Multiplayer_advilplug.top/null/ mask.json
|
||||
```
|
||||
|
||||
`tools/prune-world-to-reveal.py` - **validated end-to-end against a real region file from the server**
|
||||
(`world/region/r.1.-2.mca`, 15.7 MB):
|
||||
|
||||
| Check | Result |
|
||||
| --- | --- |
|
||||
| Anvil parse (1024 slots, all zlib, 2.5-21.8 KB payloads) | OK |
|
||||
| Slot -> chunk mapping (`slot = x + z*32`), confirmed by reading `xPos`/`zPos` NBT | **1024 / 1024 exact** |
|
||||
| Prune against that player's FTB mask (52 of 1024 chunks revealed) | 52 kept / 972 dropped |
|
||||
| Output sector-aligned | yes |
|
||||
| Kept slot set == mask | yes |
|
||||
| Kept payloads + timestamps byte-identical | yes |
|
||||
| Kept chunks re-parse with correct coordinates | 52 / 52 |
|
||||
| Size | 15,745,024 -> 471,040 bytes (3.0%) |
|
||||
|
||||
Earlier synthetic tests also cover nested per-dimension `region`/`entities`/`poi` trees not being
|
||||
duplicated.
|
||||
|
||||
```
|
||||
tools/prune-world-to-reveal.py <world-copy> mask.json <out-dir> --dimension minecraft:overworld
|
||||
```
|
||||
|
||||
`--minimal` writes only `level.dat` plus the pruned `region/` tree - the smallest thing Xaero's can
|
||||
open and map, and the best fit when the full save is too large to copy around. `--dry-run` reports
|
||||
kept/dropped counts per region without writing anything. Runtime is ~0.15 s per 15 MB region.
|
||||
|
||||
## 6. Running it where the save lives
|
||||
|
||||
The tools are stdlib-only Python, so nothing has to be transferred: run them on the machine that holds
|
||||
the world. The live world is **not** on the VPS (the VPS is only a proxy in front of the real server),
|
||||
so this has to run where the save actually lives. The per-player footprint is only the pruned `region/`
|
||||
tree for the regions that player revealed, not the whole save.
|
||||
|
||||
```bash
|
||||
tools/migrate-player.sh Stirwick <stirwick-ftbchunks-data> <world-dir> \
|
||||
--dimension minecraft:overworld --work /var/tmp/xaero-migration
|
||||
```
|
||||
|
||||
That extracts the mask (with the `chunks.dat` vs `data.png` cross-check) and prunes the world,
|
||||
dry-run first. Then, by hand:
|
||||
|
||||
3. Copy the pruned world (`<work>/<player>/sp-world`) to a machine that can run the pack and open it in
|
||||
**singleplayer** once. Let Xaero's map it, then quit.
|
||||
4. Move the generated instance, `xaero/world-map/World/null/<map>/`, into the server's map folder,
|
||||
`xaero/world-map/Multiplayer_advilplug.top/<DIM>/`.
|
||||
5. Run `tools/filter-xaero-regions.py` on that folder to drop regions the player never revealed.
|
||||
6. Delete the scratch directory - usually a few hundred MB.
|
||||
|
||||
### Two things that will bite
|
||||
|
||||
- **The server does not need stopping, but freeze saves while it runs.** The pruner only reads the world
|
||||
and writes to a separate output directory. However a running server rewrites region files on autosave
|
||||
and rewrites `level.dat` in place, so a read can tear - and half a `level.dat` is an unopenable
|
||||
singleplayer world. From the console: `save-off` -> dry run -> real run -> `save-all` -> `save-on`.
|
||||
The pass takes a couple of minutes. Never forget `save-on`, and never point `--out` at the live world.
|
||||
A region that does fail to read is reported, skipped, and left unwritten; re-run to retry it.
|
||||
|
||||
- **Opening the world regenerates chunks near the login position.** Minecraft loads and generates the
|
||||
chunks around wherever the player spawns, so terrain the player never revealed can reappear on the
|
||||
map if it happens to sit near world spawn. It is bounded by render distance (well under one
|
||||
512x512 region at typical settings), and it is easy to undo: step 4's cleanup compares the harvested
|
||||
region file names against the mask and deletes any region the player never revealed. Keeping
|
||||
`level.dat`'s spawn inside the revealed area, or not walking around in step 3, avoids the rest.
|
||||
- **Do not copy the world with hardlinks.** `cp -al` would make the singleplayer client's own writes to
|
||||
`level.dat` land in the live server save. A real copy, or `--minimal` into a fresh directory, is safe.
|
||||
|
||||
## 7. Open items
|
||||
|
||||
- **Needs: the full world save, read in place on the server.** One real region file (`r.1.-2.mca`) has
|
||||
now validated the reader, the slot mapping and the writer, so the remaining unknowns are operational
|
||||
rather than format-related: total runtime over 167 regions (extrapolating ~0.15 s per 15 MB region,
|
||||
a couple of minutes) and the size of the pruned output. A full 1024-chunk region on this server is
|
||||
~15 MB; the player revealed 57.4% of the bounding box overall, so expect the pruned per-player world
|
||||
to land in the low hundreds of MB. It is scratch data and can be deleted once the Xaero's map has
|
||||
been harvested.
|
||||
- **Per-player, per-dimension.** Only `minecraft:overworld` was supplied and only one player's data.
|
||||
Modded dimensions will each need an FTB-data -> Xaero-dimension mapping. Xaero names its dimension
|
||||
folders `null`/`DIM-1`/`DIM1` for vanilla and uses the `minecraft$overworld` form (`$`, not `:`) in
|
||||
`dimension_config.txt`; a `dimensions.txt` with more than one entry will confirm the rest.
|
||||
- **Step 3 costs one client launch per player.** It cannot be done server-side; Xaero's maps from a save
|
||||
on the client. ~10 launches for this pack.
|
||||
- **Waypoints are a separate, easier win.** FTB stores them in `waypoints.json` next to the region data
|
||||
(empty, 16 bytes, for the sampled player). Xaero waypoints are plain files under `xaero/minimap/`,
|
||||
so a converter is straightforward - worth doing at the same time if anyone has waypoints to keep.
|
||||
- **Fallbacks if the save never materialises:** region-granularity pruning (coarse, ~2x over-reveal), or
|
||||
shipping the full "Convert All Regions" map to everyone (over-reveals everything, zero code).
|
||||
- Nothing here is time-sensitive: removing the mod from the pack does not touch `local/ftbchunks/`, so
|
||||
every client's reveal data is still on disk and this remains doable later.
|
||||
@@ -1,16 +0,0 @@
|
||||
# Onion MC modpack default.
|
||||
#
|
||||
# FTB Chunks computes "minimap.enabled" once as !hasOtherMinimapMod() and then
|
||||
# persists the result. While Xaero's Minimap was in this pack that resolved to
|
||||
# false and was written into players' configs, where it sticks -- removing the
|
||||
# other minimap mod later does not re-enable it. Setting it explicitly here
|
||||
# turns the FTB Chunks minimap on for everyone, including players whose config
|
||||
# was already written with false.
|
||||
#
|
||||
# Players who want a different value can copy this to
|
||||
# <instance>/local/ftbchunks-client.snbt, which is not overwritten on pack update.
|
||||
{
|
||||
minimap: {
|
||||
enabled: true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"prevent_pet_damage": false,
|
||||
"only_prevent_players": false,
|
||||
"prevent_pet_death": false,
|
||||
"apply_totem_effects": false,
|
||||
"prevent_pet_attack": true,
|
||||
"allow_owner_damage": false,
|
||||
"ignore_creative": true
|
||||
}
|
||||
+345
-25
@@ -1,8 +1,8 @@
|
||||
hash-format = "sha256"
|
||||
|
||||
[[files]]
|
||||
file = "config/ftbchunks-client.snbt"
|
||||
hash = "6cbe2d3e5419a9ab0ded6f8d70f9be4a2cfb25f7a1d75c6a93fb4c1ed9e2329b"
|
||||
file = "config/petprotect.json"
|
||||
hash = "de9aefb0a05ee60c880c4c3d51e06d00f1a63b50b686ea740a70979323854637"
|
||||
|
||||
[[files]]
|
||||
file = "mods/3dskinlayers.pw.toml"
|
||||
@@ -15,8 +15,13 @@ hash = "fd9698b3a981f1be9e64c2ef952a390f53cdd763199d567c6ec51e2b189772ad"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/aeronautics-iris-fix.pw.toml"
|
||||
hash = "de4c3b7f4b07956213513de4b7723191bac8b397a9bb8e8a93dee39ce7ce0f28"
|
||||
file = "mods/advancement-plaques.pw.toml"
|
||||
hash = "2b02594380f31aa857c89d296afb53bec67621b491956be09a54ab6845552e2a"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/akashic-tome.pw.toml"
|
||||
hash = "18a5b572a9afdb84b24f5c58c4a53022158f8db746dde95531b780d4713f3fc8"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
@@ -129,11 +134,21 @@ file = "mods/balm.pw.toml"
|
||||
hash = "603cdc47142b5aa5729cbbf265a473574c9e2b55561de4318e9842d3d4b3b995"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/barbeques-delight-forge.pw.toml"
|
||||
hash = "1b8eb6843f324324f30e7d135e25ab89939e93ddd91421282fb6f0f358ec50c1"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/better-combat.pw.toml"
|
||||
hash = "438170e7e704a1b8ed67bf0521dc5d77cdeeaabf6f729dba9f8dfdad75330acf"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/blueprint.pw.toml"
|
||||
hash = "932b1f0df544525e277b4f75fc47dc9c01d0481d773f026082f1cae5c4afdb69"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/bookshelf-lib.pw.toml"
|
||||
hash = "68d6016fa3707c434b3aca5db041c7518c70feb53d0183faa2502cc6efd4c827"
|
||||
@@ -144,6 +159,21 @@ file = "mods/c2me-neoforge.pw.toml"
|
||||
hash = "bf29c048059a9d0b6ff0c4fd3bf6995ffc9637239fa428571a09cbe30cb2237a"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/cat_jam.pw.toml"
|
||||
hash = "c5adc29c7b5aa88587ab54f39d654216bb087e767727a182a4bf44f98228ba5c"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/chalk-mod.pw.toml"
|
||||
hash = "c6b9662ee5f41840989a380ec14b648ec0c1cc138d1d035cef42a9f65d6b886f"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/charta.pw.toml"
|
||||
hash = "41699becee4b195dfbf1cb86dfa806a21eb51501df1dbfd6aeadb489202e17c7"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/chipped.pw.toml"
|
||||
hash = "24c6c3fe917ffbcef04e788dec3e003d0ed03433bc00f9cf4f23fe9b85636aa7"
|
||||
@@ -169,16 +199,31 @@ file = "mods/cloth-config.pw.toml"
|
||||
hash = "75181b55e0407d1fca1e2f346c6501f919f5109545990ddfb66db9cd1b771f8a"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/clumps.pw.toml"
|
||||
hash = "2acaff560bbda5741538528a2967355ec86a8f7564adba0b2316989c66892374"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/collapsible-groups.pw.toml"
|
||||
hash = "3150778e64e987681e33ee7e7d74b017996e86936ba3ca569737354ebab6715e"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/comforts.pw.toml"
|
||||
hash = "36f2f6e74b7dbeccb504572d47006582207544fa234a095093b97adfc7ecd5ac"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/controlify.pw.toml"
|
||||
hash = "67a185a3e5530e49d5b2caa5bee526e6a89add656d6313c687db98350d46c23b"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/coroutil.pw.toml"
|
||||
hash = "d901f874a1e09747b8d0d072c38c426eceead1f29c8ba36680f8f0082996b152"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/create-aeronautics-compatability.pw.toml"
|
||||
hash = "d66f3ca71587c7ab8076f4a0154b0d3aa2f043c29c6373f2b8b2e5d6c3c3e91f"
|
||||
@@ -224,9 +269,19 @@ file = "mods/curios.pw.toml"
|
||||
hash = "36debf7653e95a855b4fedacc19027cf2e01960fc0b6d55ef2ffbffbcb455690"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/delight-lib.pw.toml"
|
||||
hash = "c4fb5bf78ad912a20ff50767f4e5cb64fd84f04d58db0c79bc728b643acc4038"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/distanthorizons.pw.toml"
|
||||
hash = "afed8a03fd6b410c6af339b55a026dc8e77b5b79c6ab0b8c270157fb0d8a2729"
|
||||
hash = "6d3e312dbf8db12dd1b6fb3bd1d29f210ab48024a0b2ebdf02fd32c265955c5d"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/dungeons_delight.pw.toml"
|
||||
hash = "e408acb673d46cd11cfc66db1daa12c4e6154e5529f634d1a596982df7f2b617"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
@@ -234,6 +289,11 @@ file = "mods/dynamic-fps.pw.toml"
|
||||
hash = "ae6fd52d8bdcbeca5bbe6db840f22f92c1928fe0fda22017b19612b9b00a245a"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/emojiful.pw.toml"
|
||||
hash = "6fb320d3ab2a4b3ea9458c60a1fb1d0ceadebe4cceb17291db83699ec4bc7f3d"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/emotecraft.pw.toml"
|
||||
hash = "ee66efb9eae03c2f060086e26c9d9e4a9fbece4cd1f8fc92dfbf2771f3bad296"
|
||||
@@ -264,6 +324,11 @@ file = "mods/entitytexturefeatures.pw.toml"
|
||||
hash = "42731772f3bde6bc35c48ff39a0b16c24edfa245c42d2ca8c8abd11f57edf4e7"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/etched.pw.toml"
|
||||
hash = "e542594c75eddafc1b72baebc82aa65ce2d8d791bc0ace17c731760bf30360b4"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/explorers-compass.pw.toml"
|
||||
hash = "0670ca65c7208aa8211883fae30c935f53cad38196aac46723b10e7bbc695113"
|
||||
@@ -279,6 +344,16 @@ file = "mods/exposure.pw.toml"
|
||||
hash = "28c29922378fa19f4edf1d16fffb48287a87be159a3378647073bbdebd2a2196"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/extradelight.pw.toml"
|
||||
hash = "d3cb20ad2dc8cdbf989751ad22ca4192782f68487e5e8c05e0a3f5a88d52780c"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/extreme_sound_muffler.pw.toml"
|
||||
hash = "7a60a9640f09e527a7d2bef362ee0e950dc5047a549a2afcb802f266818b7cd4"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/farmers-cutting-twilight-forest.pw.toml"
|
||||
hash = "9f042434fe2b7fb10addc596849c71f05307d173a1937b3886519095b10bf354"
|
||||
@@ -294,46 +369,66 @@ file = "mods/ferrite-core.pw.toml"
|
||||
hash = "73360e397134d238ee8fd21d33fd7f9275e9441f74f8f1b6ed92278877c0b9f1"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/findme.pw.toml"
|
||||
hash = "ef9b249b2052ef6cc08214e63debd2a9a71d60b7fe1353bbff41634c3d6408ca"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/fishermans-haven.pw.toml"
|
||||
hash = "d72a60c2053f10a447bdd05577674eeb8d0253a3ca02cb40776e063db556dda2"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/fowlplay.pw.toml"
|
||||
hash = "549e72a053da13a50404bd0901b75ce25c6045e778d5a89afcf58e9b5e1945f5"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/fragmentum.pw.toml"
|
||||
hash = "a36ff0728cf99bb5adfe114d32fce1a42483291aee9312aabb5cf5642b97264e"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/friends-and-foes-flowery-mooblooms-forge.pw.toml"
|
||||
hash = "359fa7c50935dd5eb8e629c47ef5c86ee7cd183dd40cf3650ac9efe9ff7ce854"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/friends-and-foes-forge.pw.toml"
|
||||
hash = "78a50ddf9108d1dda82e7de46a991dcd61a046e4ea2279aa551071ba8f178f86"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/frights-delight.pw.toml"
|
||||
hash = "496e804b2b894db615dafda5c654a33d49f71314ff119ea3562424e0be1b91aa"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/fruits-delight.pw.toml"
|
||||
hash = "bd54b25ed6127a176979f89d56ebee73856ff5023c575232ee707571fcdb2c1c"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/ftb-backups-3.pw.toml"
|
||||
hash = "893f9b4dbe36a0bcae29d87cd68ab84fed83c984c3f5649c155c0522c509a77d"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/ftb-chunks-forge.pw.toml"
|
||||
hash = "670df7985eec05c6a339d90ebbcfda0e5f1f5c63846ac65a441412f123471e14"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/ftb-library-forge.pw.toml"
|
||||
hash = "2e72d40c6d7b128981b19b71c19d45eb6813f1af87ae1abe1cf92adfa5e8223f"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/ftb-quests-forge.pw.toml"
|
||||
hash = "93330f6ec85532067df176c6baee0e0f6d685c78088b1a2217726f6421899148"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/ftb-teams-forge.pw.toml"
|
||||
hash = "c21c2308684a75cda7dd9d557d129c9f89f49be527da3d5aa675fff444c11f5e"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/ftb-xmod-compat.pw.toml"
|
||||
hash = "6ad22c468d67dcbb65784e161d4af9e671d3437cb5bfb1e86a42ae25207cf25b"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/fusion-connected-textures.pw.toml"
|
||||
hash = "7411c38665af0ee0b17613ac80daaa040a5f59b046d418421297acf2c6fa8c9c"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/fwa.pw.toml"
|
||||
hash = "3d8367a300c9058a2d97aaea91b42d91ffae892cbffcd774417c4b4c306ca311"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/fzzy-config.pw.toml"
|
||||
hash = "932c65fb598293dba5dc60a76fc64c2579db427018b10dd4757dd421d9abcaf0"
|
||||
@@ -344,6 +439,11 @@ file = "mods/geckolib.pw.toml"
|
||||
hash = "35779b39ddc06059ec483b33de2ecfdc3adb95c0a49e69b6701fb0024827e2f5"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/grassier-grass.pw.toml"
|
||||
hash = "43b824f4aa5834bbec2488986bbe3b637e20affc8e4d2c4ae52c516130aa44ee"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/gravestone-and-sable-compatibility-patch.pw.toml"
|
||||
hash = "6baec0ac505606e2066b5a00a5873cc6895f0ca639a0bfabd74bf408dcf25749"
|
||||
@@ -364,6 +464,11 @@ file = "mods/handcrafted.pw.toml"
|
||||
hash = "0004feab868f7b873c12db05aae0d0dac6c87b497490b48bb66480e7c8d0f340"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/held-item-tooltips.pw.toml"
|
||||
hash = "d01e1e18bc56a20fd1b37a5716e3fa9cf78704176389865dcbac7c13d3b34770"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/iceberg.pw.toml"
|
||||
hash = "a2fbecad69fcbff54919864ea8b95e54d140a1a2c637d73307fb366e76066fe6"
|
||||
@@ -374,11 +479,21 @@ file = "mods/immediatelyfast.pw.toml"
|
||||
hash = "2863a3b187723e1f69ed2ad2b2c3d834e8442468a1347c80df5b310e243c8753"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/immersive-paintings.pw.toml"
|
||||
hash = "f4f4f93fd59e6a43e7484b44c667875cc8a5d8e5621d98b61e8944c9e0838d61"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/incendium.pw.toml"
|
||||
hash = "391f5b0b0fcae3ce77be6ab211435228faec79cb92c50d69471c52ba36b139d6"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/inventory-particles.pw.toml"
|
||||
hash = "7ff791a8a6074a5f580a0a1899de69cff45ccf6db0a99d83494d57ff1a4cee43"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/iris-veil-compat.pw.toml"
|
||||
hash = "69f9051c61c05546a2bf008654149a101814842bc2bf384df5c0ee0d64301ccd"
|
||||
@@ -389,6 +504,11 @@ file = "mods/iris.pw.toml"
|
||||
hash = "db1c1e6382878b78e994dba1b9026935f8d1c5ca685c89d2437858e0a0dcab58"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/items-displayed-forge.pw.toml"
|
||||
hash = "dd18a83618d87de69fa341e775e58f3e7df6452eb657ae9f95125461c1eb0a3c"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/jade-sable-compat.pw.toml"
|
||||
hash = "673bc79f4d42c7de3343a8e2933a3fbd355ba34e8a7ca06ffdae659bd57a8231"
|
||||
@@ -404,6 +524,11 @@ file = "mods/jei.pw.toml"
|
||||
hash = "4727f9eca761440a318177abe0916e5d1cbff3bdaa0ad5904be3a2b00bc44049"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/keybind-atlas.pw.toml"
|
||||
hash = "84914fc3e4a0dc029068bc402fcd23c9c2059108b57de31b0bc7bbe7b2b10fa8"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/kotlin-for-forge.pw.toml"
|
||||
hash = "712a69b3569a8055979de6eea262068535fe182dffb3833e53e5833e9cbf9766"
|
||||
@@ -429,6 +554,16 @@ file = "mods/lithostitched.pw.toml"
|
||||
hash = "0294264654da6777cfbbbd24ffa6dd1d082768fa7ae28b36b76f78261f53fce9"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/lodestonelib.pw.toml"
|
||||
hash = "f5d0701055478e980b50849f199f266e6ab1940277a17ad2e5060df0d978be83"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/loot-journal.pw.toml"
|
||||
hash = "f8ee8585f6ef37c12d3f5ea749394d3b86c9c97b0f2b98a0056d66a83a91d150"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/lootr.pw.toml"
|
||||
hash = "86390b0fac4ae3a1f24f0723cab5dcd3b798cb0c9be579575ba93b0cc6a90212"
|
||||
@@ -459,16 +594,51 @@ file = "mods/macaws-windows.pw.toml"
|
||||
hash = "450ed5663bf1d12ffddc78eda5aa56cb7808cbdac6db8102d18461361aaa555f"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/mazes.pw.toml"
|
||||
hash = "171cd9e5ff7d88b83575262701803688ed951b159df23e8e5bc53f26fb41ec05"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/mermod.pw.toml"
|
||||
hash = "62b2e4a4dfcf32e46484938534b7ef72af75054ec2b566984230710f822b8b07"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/mezzconfig.pw.toml"
|
||||
hash = "efad386063cb79013d7522fcc5b5879c5c3cd556e83bd41a56980632827b45b2"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/miners-delight.pw.toml"
|
||||
hash = "13481133d139f134bd3407983e29f86df835ff66bacb013d9d43e14f155241f4"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/minopp.pw.toml"
|
||||
hash = "ad45deee7f144ba4ca0b5cca09d8d0d649eee55ae3cd0afd2e21581e23019a20"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/modernfix.pw.toml"
|
||||
hash = "c84140c66f233909b392bd7253ca33c59903ffda51beff558d9a2a4a8c6bc269"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/moonlight.pw.toml"
|
||||
hash = "8a69517eb999eacd8842d42fb2f9cdfda43fe11e70d72eabc54969b4d9e38f5a"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/more-delight.pw.toml"
|
||||
hash = "7b00b0ef46a798a4a46fe541314c63cfd62017190cd554e855cc21ef44e32635"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/mossylib.pw.toml"
|
||||
hash = "ef8e9f48c234fbdadc2bb011ea670248688dda9730f30f13ff5a52fb8a04fb76"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/mouse-tweaks.pw.toml"
|
||||
hash = "6bc414cc0f2d4c078fe83f384d786343f701f371d657c5279b5b0df1595804bd"
|
||||
@@ -479,6 +649,21 @@ file = "mods/mowzies-mobs.pw.toml"
|
||||
hash = "02aa4dcb8fa24cffcd2182c66683c2a476a95abf53002373f953a49737a587e3"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/mru.pw.toml"
|
||||
hash = "f12ee0c88176e66a61de272f1be98077a86560c199903514de7657564130c34f"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/music-disc-maker.pw.toml"
|
||||
hash = "b12186eb8ba1ccff37bc0dba408a3f7964f65c15bba9e28cf9f3c8437df2cdff"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/mystical-oak-tree.pw.toml"
|
||||
hash = "5ee268552c9337e720141a9d3fa03d260d1cc575b0359adbb1a0da566cc605e9"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/natures-compass.pw.toml"
|
||||
hash = "35acdf433fe8f8599f59975e848efdb717663c2c471d3a5dc18743799795a736"
|
||||
@@ -489,6 +674,11 @@ file = "mods/noisium.pw.toml"
|
||||
hash = "d424a9260ef51bc102e56f0423d91dfabb739ccca8a86eb1c450ea631b739280"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/now-playing.pw.toml"
|
||||
hash = "700d7eec503d4cca8287a26354699301c0087b387598695d240bece175a3637b"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/nullscape.pw.toml"
|
||||
hash = "dcfbfa39abeaba554c2c5323f9b9a3ec58dfc386aca2d237f73948abdbdc7125"
|
||||
@@ -499,11 +689,36 @@ file = "mods/oceans-delight.pw.toml"
|
||||
hash = "7bf7c8369bd28212a1e294c60310ccb72f1eb773630970e6ab106ae666766cd3"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/open-parties-and-claims.pw.toml"
|
||||
hash = "97660396e7f075f4c9ca8447878ec3da58ebea9ed464cdb494d4db1d62989936"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/overweight-farming.pw.toml"
|
||||
hash = "836ffb879311a16e620c05796513395a3b9009c7d27d84c5938f03add120bec6"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/patchouli.pw.toml"
|
||||
hash = "d7f360ebb9f009d6dc0b368cd8fa399bdff70c0f6ef931687b2a35137f72715d"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/perception.pw.toml"
|
||||
hash = "378f188dd4dd616783418b9169e6016d5eff359a13c6debeb64c82093637e8e9"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/pet-cemetery.pw.toml"
|
||||
hash = "f54003416e887882952b9a07e339829362c2c597ccd2d651c0a03d2120fb8a3a"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/petprotect.pw.toml"
|
||||
hash = "97363bf59db02a5975f62231de661903ae9d8f0f9a1562825c38ad195d07ed80"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/ping-wheel.pw.toml"
|
||||
hash = "650330109d21831664d2ff597c7a90200eda69a1efaca4e9b0b6b6297ac3c364"
|
||||
@@ -519,6 +734,16 @@ file = "mods/playeranimator.pw.toml"
|
||||
hash = "93284ca7f2f23f0bb76d42b797cabf2aea1914ee9825bec82bf6ffe4c60dda0d"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/playerrevive.pw.toml"
|
||||
hash = "2fce8261a3f3f1c97232926429dfc4aa7ba871a04ce4fde8d87f21404a6ac857"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/portfolio.pw.toml"
|
||||
hash = "a76b0f00e2a4616ab74ba56a5e6d3fd77e29ce4912b1d682c094e5b547da1845"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/prickle.pw.toml"
|
||||
hash = "c99c5bac469e8d6ece5aae80f08635e3bbb8367f0c586b6288573c725faefe69"
|
||||
@@ -529,6 +754,16 @@ file = "mods/prism-lib.pw.toml"
|
||||
hash = "d9b38ba42434eb436d036b1c8add839bee003240dc85cc54ec626aac58c59070"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/puzzles-lib.pw.toml"
|
||||
hash = "6b1ee632cee2d75301016eaac99a3446ad605f11fbfda631effac0eb7da59f6c"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/quick-skin.pw.toml"
|
||||
hash = "90fac93a6b8b10db896bea59f28fb6653f76329dac23b9bddda9c04231faaf45"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/rechiseled-chipped.pw.toml"
|
||||
hash = "e960df6664514910fa5190229c448bffbcddb29d822bb7c07566bf31fd65772f"
|
||||
@@ -544,6 +779,21 @@ file = "mods/resourceful-lib.pw.toml"
|
||||
hash = "c0b066684294c33972d562e0cb08ea17b2d31bcf86cd1d6c63b8e968f0eac7a2"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/room-for-two.pw.toml"
|
||||
hash = "737d534ec922e9f76bf405dc033e3e675aebb035e6f90a58c7fca81327d13c03"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/runiclib.pw.toml"
|
||||
hash = "ea53e1f266236ded756baa6ae49292583fa5f21c5c3134dfef821b11a7f169fb"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/rustic-delight.pw.toml"
|
||||
hash = "ac9db8b319aa7a53d06c5209998dcf8a2d9a6bd17fbd14c3f6dd859727d434a7"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/sable.pw.toml"
|
||||
hash = "a1fa121ed5d0207e4cdd3f545d043f68f9a4bb38dcb21278b968fad5e4cefe4a"
|
||||
@@ -554,16 +804,31 @@ file = "mods/sablecompat.pw.toml"
|
||||
hash = "b9ceb0fa4707ced2e0467f334ce8b6cb2fd60c729b47aee065e2bb0d5b905189"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/shatterbyte-lib.pw.toml"
|
||||
hash = "3f552bbdc42f07fd7d5695ced1d27d774af63cff5460be45817939e5f8e4f9de"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/slice-and-dice.pw.toml"
|
||||
hash = "3c24accda8011a6a5e04c49c40e39617bb04ab3a549d8f2e8180d3246fddac39"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/smartbrainlib.pw.toml"
|
||||
hash = "6e7ce9c2aee5bb72d2698eb89035c9b2458d20daa0782e1a03cfba7a6647621e"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/sodium.pw.toml"
|
||||
hash = "2a001cdb3d5ac4970d422914083c27380eba8ebd40dfd435754fe6566ba78beb"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/sooty-chimneys.pw.toml"
|
||||
hash = "924b292f54a9a8c7196773b03e1f503a0eb70af4c0aa06a02bfb6c8f4617c660"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/sophisticated-backpacks-create-integration.pw.toml"
|
||||
hash = "05073e7d5e3cea5a877954557f3efe77ac8a691ab8dd093a3bdd3458873e3ea8"
|
||||
@@ -594,6 +859,11 @@ file = "mods/sound-physics-remastered.pw.toml"
|
||||
hash = "258a77de0a6db4c9ab045cbb240bcf4eac0dbbca3f6bc981fb461e55c247f23f"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/sound.pw.toml"
|
||||
hash = "4063a3c0f2f9a6544a870f0b90679441d7333652875dafbe3db255fc67f72c82"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/spark.pw.toml"
|
||||
hash = "593fa7b30ab016aa45be07bd6bef3a9f160ed0f24689850d60bf84995d69b843"
|
||||
@@ -624,6 +894,11 @@ file = "mods/supermartijn642s-core-lib.pw.toml"
|
||||
hash = "68ef590d29c127c6b38d81662edfa45a2e1339d38f60aee345e31164c7c10017"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/tarotcards-remastered.pw.toml"
|
||||
hash = "301902ffbfddf70a3ab4fe2d952411d2b057ce7bd61af0a11962493d0d780685"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/tectonic.pw.toml"
|
||||
hash = "dd46fad79cf33a00123be0a74c73581da72cd98503ef23822a624a08f4b10ff2"
|
||||
@@ -644,26 +919,51 @@ file = "mods/tiny-dragons.pw.toml"
|
||||
hash = "78e6f8fc2adf79cb9bf3c49655a9f8cbdae901cc1ad59bdb58d6fb0e0497bc58"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/too-many-bows.pw.toml"
|
||||
hash = "689afe3b2bcff1014c1b842d4004ea7cee6f646c2125b649a739569c699b2566"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/towns-and-towers.pw.toml"
|
||||
hash = "a9afe82b3d1b4975dd9f8b3272898450aeb29365678b3779059977301f88c101"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/travelers-titles.pw.toml"
|
||||
hash = "01cab903b1a7f77aa4f28c7fab24e7fa09b376b18c77b487b7ba34e0afc57813"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/twilight-delight.pw.toml"
|
||||
hash = "3391c4b8e739a2cacd72a40241889007eb81d4ed2027b5cb80313f4f6fc06620"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/veggies-delight.pw.toml"
|
||||
hash = "03787f92417875e7e43a959a9eb07c2c20edbddaa7cbda50205f2c388f8b8c81"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/waystones-sable.pw.toml"
|
||||
hash = "c452c85bb210ec721793610924e61bd11d7c67b46815ac49106fd851dc1e877c"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/waystones-teleport-pets.pw.toml"
|
||||
hash = "2966bd8471246286be3d42515c7e89ca07ba7afd606f00ef6ffdc9a6ce150a1c"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/waystones.pw.toml"
|
||||
hash = "2dad5577c5ec5e73bb3d5cec8da606e3b72e384207c9291a25e1ae96fd20bb70"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/what-are-they-up-to.pw.toml"
|
||||
hash = "9ce52d07c0c3d146a2a44f8bc187138ce7a5558a4e3ab540c86234702b6de274"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/when-dungeons-arise.pw.toml"
|
||||
hash = "485906ff55a5d6ad06070abb80663d6adadc3e4b32f8b52240d8596e7aaef9fa"
|
||||
@@ -674,6 +974,21 @@ file = "mods/wings-of-fire.pw.toml"
|
||||
hash = "07b44e8f4c3e5dd41c13269005638e27d1fcf43e8fc96b2f08299ca3676313e3"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/xaeros-minimap-world-map-waystones-compatibility-forge.pw.toml"
|
||||
hash = "637bc567eb5260d55ce89e6471c31e4369d454607f3d6f40139f7f7bdef90af9"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/xaeros-minimap.pw.toml"
|
||||
hash = "64670072fa3b4db4a721769dd3d66a2865daac01c9a2480b9561675b1e9e9737"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/xaeros-world-map.pw.toml"
|
||||
hash = "f8cc300d53ae8bf71d77124e6c46a5e85fe31654b39c5d73a1652a4d9c404af4"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/yacl.pw.toml"
|
||||
hash = "539f362e9e192cf3b2813e0dfdfc51a5e6814129c6e82a9733842529beea6242"
|
||||
@@ -729,6 +1044,11 @@ file = "mods/yungs-better-witch-huts.pw.toml"
|
||||
hash = "9854b699d5a067c46ac99b1dedeeb529bff3fc18dd079e29b438c4cbf9725f68"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/zume.pw.toml"
|
||||
hash = "165466fe8e528309d95875396f2a5e13c0bab7bcb0c1134d1fd5f3a935d488f5"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "resourcepacks/better-leaves.pw.toml"
|
||||
hash = "c26f8da8b6f013fb7e917e29fc6ae783eb379c539da12d9d61196bc762fd26e1"
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Advancement Plaques"
|
||||
filename = "AdvancementPlaques-1.21.1-neoforge-1.6.8.jar"
|
||||
side = "client"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/9NM0dXub/versions/OWylG33I/AdvancementPlaques-1.21.1-neoforge-1.6.8.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "94724dd77d005f0a189c4843efcc2800cf3d3e01d1f1ac184c6f6ad7c921aec508e93fa0bfac0e641a74c1629d4e5e4d06b8c1a3e0d8e63f97db89b2f879c106"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "9NM0dXub"
|
||||
version = "OWylG33I"
|
||||
@@ -1,13 +0,0 @@
|
||||
name = "Aeronautics Iris Fix"
|
||||
filename = "aero-shadow-fix-2.1.0.jar"
|
||||
side = "client"
|
||||
|
||||
[download]
|
||||
hash-format = "sha1"
|
||||
hash = "47f48363d9805b9b60fb9a3cf1bb447bb80ad538"
|
||||
mode = "metadata:curseforge"
|
||||
|
||||
[update]
|
||||
[update.curseforge]
|
||||
file-id = 8589529
|
||||
project-id = 1641969
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Akashic Tome"
|
||||
filename = "AkashicTome-1.8-30.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/JBthPdnp/versions/MRro5nPG/AkashicTome-1.8-30.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "c0061c263e1d701e71a75355c3db11c9a975dd1e47da0fe6592973bf12d4f5b44aa476f5daaeec42a3146a8d94fe96f1d57f1a4e37dcd18357e4d752b1a194bb"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "JBthPdnp"
|
||||
version = "MRro5nPG"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Barbeque's Delight [Forge/NeoForge]"
|
||||
filename = "barbequesdelight-1.3.0.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/rtu7uERF/versions/rvUhMw6d/barbequesdelight-1.3.0.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "27d8338f862934a2eb7efb62cffcbba6675c00e4dcd1b66a482ad3a07d68aafe9f9e320525da50314cdbdc59d7b0b71d3f72b830b1f32d9f2c14293a62d54815"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "rtu7uERF"
|
||||
version = "rvUhMw6d"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Blueprint"
|
||||
filename = "blueprint-1.21.1-8.2.0.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/VsM5EDoI/versions/FHOjk8Ez/blueprint-1.21.1-8.2.0.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "0b523c2d53a56676286ddd13adbe65b1a24f5af6040dbec6af9a38cc535b7ba2531a1879afb7a496c407683eacbfbed22701053861a5fd12271b08ac93239db4"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "VsM5EDoI"
|
||||
version = "FHOjk8Ez"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "cat_jam"
|
||||
filename = "cat_jam-neoforge-mc1.21-1.3.1.jar"
|
||||
side = "client"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/x3s69afN/versions/1gEvfaqg/cat_jam-neoforge-mc1.21-1.3.1.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "aeae13607de32330b1afe9199c30619a8b54769c15a42475de5408c5b7539e89b19e47125552862a2d5dfda42f46f9bd85bc232a5de3d1beea0d7993436d3ab7"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "x3s69afN"
|
||||
version = "1gEvfaqg"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Chalk"
|
||||
filename = "chalk-neoforge-1.21.1-2.0.2.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/YWGP4Y1d/versions/c9La5ZxO/chalk-neoforge-1.21.1-2.0.2.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "dac534f0af3ee587e7b9f010284f387ebe871e0c7c7dc8ce5b3d235e5fa00e245eaeb9533bb6109f02f7eb90d4de9510d34fabe014ad0dd6c873ea94c6786e74"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "YWGP4Y1d"
|
||||
version = "c9La5ZxO"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Charta"
|
||||
filename = "charta-neoforge-1.21.1-1.2.5.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/sFamPxlk/versions/cuOxTn8V/charta-neoforge-1.21.1-1.2.5.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "bc63123e72dd25101c0442ded05f7bf6fb0769603201df33f0e100a113c29df97b334b0ce3087fc9170c0fe33520b76ee69f2ea6e63b1b581cf5dfa6e8774216"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "sFamPxlk"
|
||||
version = "cuOxTn8V"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Clumps"
|
||||
filename = "Clumps-neoforge-1.21.1-19.0.0.1.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/Wnxd13zP/versions/jo7lDoK4/Clumps-neoforge-1.21.1-19.0.0.1.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "314d8d8e640d73041f27e0f3f2cad7aad8b4c77dbd7fb31700ef7760362261f77085eed5289555c725d99c3f47a114e7290cd608f39c9f0f12ef74958463bdcc"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "Wnxd13zP"
|
||||
version = "jo7lDoK4"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Comforts"
|
||||
filename = "comforts-neoforge-9.0.5+1.21.1.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/SaCpeal4/versions/3kpPjcTc/comforts-neoforge-9.0.5%2B1.21.1.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "e9de2952545e9e773a6e78fc501e8cd231ea19750c30404355b71df9928eb5bd0921a4429aeca9d0fa10e67717f77fcf7a2aae117ac953b8f7de246b0ad685e4"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "SaCpeal4"
|
||||
version = "3kpPjcTc"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "CoroUtil"
|
||||
filename = "coroutil-neoforge-1.21.0-1.3.8.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/rLLJ1OZM/versions/H2YXCYUY/coroutil-neoforge-1.21.0-1.3.8.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "daae9e37acddedccad05e3f8e565f8b4c237f25b2462e043428f88b32fc27e4bc3a00955ed7426a7d7f93f068b4e96b37e2e42d121d40fdf94a31b6c2b7440e0"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "rLLJ1OZM"
|
||||
version = "H2YXCYUY"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Delight Lib"
|
||||
filename = "delightlib-26.05.18-1.21-neoforge.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/rmDY6fYt/versions/wCR4QGbG/delightlib-26.05.18-1.21-neoforge.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "9a383ecf80a0b221d33ce4eb13cec2f8527c9d2e8680cb2147a8d9255a6384c4cb0a8b2987accd2213cd6f1528b9292909d0b0224b9c0d3aaa067fb3320c1a84"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "rmDY6fYt"
|
||||
version = "wCR4QGbG"
|
||||
@@ -2,11 +2,6 @@ name = "Distant Horizons"
|
||||
filename = "DistantHorizons-3.3.2-1.21.1-fabric-neoforge.jar"
|
||||
side = "both"
|
||||
|
||||
[option]
|
||||
optional = true
|
||||
default = true
|
||||
description = "Extended render distance via level-of-detail terrain (heavy on GPU/VRAM)"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/uCdwusMi/versions/Ez3cx7Yd/DistantHorizons-3.3.2-1.21.1-fabric-neoforge.jar"
|
||||
hash-format = "sha512"
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Dungeon's Delight"
|
||||
filename = "neoforge-dungeonsdelight-1.21.1-1.5.1.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/qPfNr476/versions/mAuzCOhP/neoforge-dungeonsdelight-1.21.1-1.5.1.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "5170e57d21a1e247c24a53e67b391cfe6278e841df43dabf58d6a3bd2c02ab18ff84ca44f05260dd5d4e4985c457719469d16cbfb016068f7603e584b30ba726"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "qPfNr476"
|
||||
version = "mAuzCOhP"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Emojiful"
|
||||
filename = "Emojiful-Neoforge-1.21-5.2.4-all.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/72GXx2MO/versions/rY17Eh56/Emojiful-Neoforge-1.21-5.2.4-all.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "eae8c72cab42e423299c12ddcb2eca9c4a523779627af91e45361c54111bc68fd32c5043e182d2a67ce74342b196ebbb3c34d190c5c98270b23d67704be3437c"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "72GXx2MO"
|
||||
version = "rY17Eh56"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Etched"
|
||||
filename = "etched-5.1.0.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/zi3Fnfmc/versions/h6eJfwiW/etched-5.1.0.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "cfbab71feeec3ea14686916349850a640d6ce51e763ac4f2486ed2cacd8c8042c9e457a51b0822fc7c05268370edbf59a322950cd37fbd1cb55c3b2575c3e4b9"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "zi3Fnfmc"
|
||||
version = "h6eJfwiW"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "ExtraDelight"
|
||||
filename = "extradelight-2.6.6.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/yRrY3XII/versions/1SSgrmDa/extradelight-2.6.6.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "39ac6beee0111d45abab3129f275d7f342edb993528d7045538fa42369d995cb4a1b292d271e21ccfe25f822420ebd9e4896beb6028c65b98f891303951219b8"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "yRrY3XII"
|
||||
version = "1SSgrmDa"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Extreme sound muffler"
|
||||
filename = "ExtremeSoundMuffler-3.57_NeoForge-1.21.jar"
|
||||
side = "client"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/5IIKsxiL/versions/nUCCmquN/ExtremeSoundMuffler-3.57_NeoForge-1.21.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "b4fea77c1218b248b20a1a75a5e626f963e48bafc56f3c2f5e833ab2592f8ee745844f9e67a75c786f27b632601e9b543583d65c8dd43696401fd2164fc438d3"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "5IIKsxiL"
|
||||
version = "nUCCmquN"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "FindMe"
|
||||
filename = "findme-3.3.3-neoforge.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/rEuzehyH/versions/XqFomM19/findme-3.3.3-neoforge.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "5884a0ae58a5ec4dad7751697242125a2c96b88fa12edc0714ea60042fa74fa14493ebb735d5d06f74d7237e297d45cc1e17d3abc37d153d6c2304dbdb60ca99"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "rEuzehyH"
|
||||
version = "XqFomM19"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "[HUGE UPDATE] Fisherman's Haven"
|
||||
filename = "fishermans_haven-3.0507-neoforge-1.21.1.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/cNrIBpSY/versions/CEMjH2Hs/fishermans_haven-3.0507-neoforge-1.21.1.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "61e74b56d8342b7f4f741389896ec229386ad713ecea66a90385d0c858e0b670458901eff4577e753e6809b1206b7184e2935c44a06f6f301a4fe2ed0acbf704"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "cNrIBpSY"
|
||||
version = "CEMjH2Hs"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Fowl Play"
|
||||
filename = "fowlplay-1.2.3+1.21.1-neoforge.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/WpXfePbg/versions/kZyPjCmU/fowlplay-1.2.3%2B1.21.1-neoforge.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "69d78df0c54cf77cc8dde61a51ccd6e3b9eebda5f07fd8ed7d4d8fe72f9d7f2d51c025a1c5a7b3f7eeeddc75515ea6ba5c15cf878c111016fbde00581c30dd84"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "WpXfePbg"
|
||||
version = "kZyPjCmU"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Fragmentum"
|
||||
filename = "fragmentum-5.2.0+1.21.1-neoforge.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/49C5QgTK/versions/Kh6I6ckR/fragmentum-5.2.0%2B1.21.1-neoforge.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "f8db7ba5e83a3bd9957ae17de4a11f3abb934a164f474e272dcf151b2424b81d575145135f0763276c5c3e134f72bfa0e73bd41bbece0dcb19366e631903594f"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "49C5QgTK"
|
||||
version = "Kh6I6ckR"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Friends&Foes - Flowery Mooblooms (Forge/NeoForge)"
|
||||
filename = "flowerymooblooms-neoforge-3.0.3+mc1.21.1.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/wYtDgIUZ/versions/Kz3PjwHn/flowerymooblooms-neoforge-3.0.3%2Bmc1.21.1.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "1d70e10b6383022b62b11a2e253ed457b807045ba5ebb41edd6ce95c32ba8c8e1d5b376bc618792562cf5d10b7b039e22d73a99fd0480a1d22c7fe7b2ebe7bc0"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "wYtDgIUZ"
|
||||
version = "Kz3PjwHn"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Fright's Delight"
|
||||
filename = "frightsdelight-neoforge-1.21.1-1.4.8.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/awWvXlb2/versions/4BABsmeb/frightsdelight-neoforge-1.21.1-1.4.8.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "7d6840ff1dd6ef4b5625de44c321d9e3fe4c596a2b5e1c4c04d090d05111891b45b9fb8b48be2a7e8deb42c96368fa7b3673befb072a359289a18ccef5c094e3"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "awWvXlb2"
|
||||
version = "4BABsmeb"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Fruits Delight"
|
||||
filename = "fruitsdelight-1.2.14.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/g6sbyCTu/versions/TWbuEFZt/fruitsdelight-1.2.14.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "473fd3b7cd94fd7daba34554143d70751816b6cd5bbf8b238e9a6d3ee7d80b2c2b9833840dea4c66c6ef4db35ebf0f2c03c3bad80e09b426938ea977a48dc3f5"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "g6sbyCTu"
|
||||
version = "TWbuEFZt"
|
||||
@@ -1,13 +0,0 @@
|
||||
name = "FTB Chunks (NeoForge)"
|
||||
filename = "ftb-chunks-neoforge-2101.1.22.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
hash-format = "sha1"
|
||||
hash = "a53f1bb7965c6954a348d4f321f03d3971ad503f"
|
||||
mode = "metadata:curseforge"
|
||||
|
||||
[update]
|
||||
[update.curseforge]
|
||||
file-id = 8791113
|
||||
project-id = 314906
|
||||
@@ -1,13 +0,0 @@
|
||||
name = "FTB Quests (NeoForge)"
|
||||
filename = "ftb-quests-neoforge-2101.1.36.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
hash-format = "sha1"
|
||||
hash = "b2ede29b98a3022c22065fbe9b1761e385a28683"
|
||||
mode = "metadata:curseforge"
|
||||
|
||||
[update]
|
||||
[update.curseforge]
|
||||
file-id = 8885017
|
||||
project-id = 289412
|
||||
@@ -1,13 +0,0 @@
|
||||
name = "FTB Teams (NeoForge)"
|
||||
filename = "ftb-teams-neoforge-2101.1.11.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
hash-format = "sha1"
|
||||
hash = "62b65f752d0326edd13244e58d5f2aec035da4e9"
|
||||
mode = "metadata:curseforge"
|
||||
|
||||
[update]
|
||||
[update.curseforge]
|
||||
file-id = 8724782
|
||||
project-id = 404468
|
||||
@@ -1,13 +0,0 @@
|
||||
name = "FTB XMod Compat"
|
||||
filename = "ftb-xmod-compat-neoforge-21.1.12.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
hash-format = "sha1"
|
||||
hash = "1f68bf714cf7ea3e07b23c6b8c1ebe516b325047"
|
||||
mode = "metadata:curseforge"
|
||||
|
||||
[update]
|
||||
[update.curseforge]
|
||||
file-id = 8909889
|
||||
project-id = 889915
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Fancy World Animations [FWA]"
|
||||
filename = "fwa+1.21.1-neoforge-1.2.31.jar"
|
||||
side = "client"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/IAzUFvS6/versions/79A6vRlK/fwa%2B1.21.1-neoforge-1.2.31.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "dd44ef2dad3df2b52610b2f289f02590265b467409737630ae12ac5d540613f84191a1b5488bac8098ebbeb78f1922b3b6d86c2c09bbe026f46c88f91b25f74a"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "IAzUFvS6"
|
||||
version = "79A6vRlK"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Grassier Grass"
|
||||
filename = "grassiergrass-neoforge-1.4.5+mc1.21.1.jar"
|
||||
side = "client"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/3jCB9cn2/versions/hWKkBn3u/grassiergrass-neoforge-1.4.5%2Bmc1.21.1.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "5e1085f8039b9e42ce9a11ce3bdfc668e14f86b7b8240940cc4c922640af1dcf0c294a2a5853194fd6625b2f6f3fe8029f6cf405abb9ab496e274971bb36b0fd"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "3jCB9cn2"
|
||||
version = "hWKkBn3u"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Held Item Tooltips"
|
||||
filename = "HeldItemTooltips-v21.1.0-1.21.1-NeoForge.jar"
|
||||
side = "client"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/3wWtgZGB/versions/GLzG8UbN/HeldItemTooltips-v21.1.0-1.21.1-NeoForge.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "e861bf33f854d97d69cc979b16b3a2c2ff8b7b6942add6883f94b4c0112ee325df5f3a7f78e98eebd5dc801131b0d660b4f103c6f156cd72896727e35d145dde"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "3wWtgZGB"
|
||||
version = "GLzG8UbN"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Immersive Paintings"
|
||||
filename = "immersive_paintings-neoforge-1.21.1-0.7.9.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/6txNkua3/versions/ItQ1UJGH/immersive_paintings-neoforge-1.21.1-0.7.9.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "de3e06f3c9f8ce6f041daff5c2b835ec0f386ccdab7ea7fe2cfec57f808ed25675fe056ff062d5f435f5248aa7f0eb3816ae7d4748da8e53beae2419008cb031"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "6txNkua3"
|
||||
version = "ItQ1UJGH"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Inventory Particles"
|
||||
filename = "InventoryParticles-3.2.0+1.21.1+neoforge.jar"
|
||||
side = "client"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/XYnKrsxH/versions/tIeIGFCs/InventoryParticles-3.2.0%2B1.21.1%2Bneoforge.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "0fcec536b01339f1d3bdd875c924cd083328362fdcde9487e67f2a425426faa2b7783a86c1fb7af885e25edfa802cb2cce81db7a643291f2d0677ad6cbcf9c02"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "XYnKrsxH"
|
||||
version = "tIeIGFCs"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Items Displayed [NeoForge]"
|
||||
filename = "ItemsDisplayed-NeoForge-2.0.10.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/PuR4vDBo/versions/8ZZWElcA/ItemsDisplayed-NeoForge-2.0.10.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "9a5e08585281841b67c7a45aa20e9a12a4c3d49f0b7329773db2cf5e6b2a4c80d2895850ccd6ad77e8333840c2d0602780963c52f145711d2856c0915bc07d97"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "PuR4vDBo"
|
||||
version = "8ZZWElcA"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Keybind Atlas"
|
||||
filename = "KeybindAtlas-v1.4.0-mc1.21.1-neoforge.jar"
|
||||
side = "client"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/fokFjwwh/versions/UbE4gXrR/KeybindAtlas-v1.4.0-mc1.21.1-neoforge.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "7ff490f071c6f9befe6a6a79f198e89056ffe76cfac56db5b6f17fcfb76b10aa80ee89225ff54df35c24d85ea5aacec462b458f3258525ff6af972ddce03ef13"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "fokFjwwh"
|
||||
version = "UbE4gXrR"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Lodestone"
|
||||
filename = "lodestone-1.21.1-1.8.2.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/bN3xUWdo/versions/CohX6yP1/lodestone-1.21.1-1.8.2.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "6917080339b982d96cb4a7c98205ade5d89730191bc9113f4f8cd36bb1a760a91ad2421c8869c7063f8dea22a200d7d1896e0bb5e0e64119bb7590e32a998a23"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "bN3xUWdo"
|
||||
version = "CohX6yP1"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Loot Journal: Pickup Notifier"
|
||||
filename = "loot_journal-neoforge-1.21.1-6.2.2.jar"
|
||||
side = "client"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/OJ6ZYz5L/versions/zyIMDDzM/loot_journal-neoforge-1.21.1-6.2.2.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "da6be07bebe1f2f38242568a49e13020c4cbead8e563d02d5106110ce3bc34525c2388ce47d36b477db8dcc7661afc38fa9eb243cc42c53737c531e0b5189c77"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "OJ6ZYz5L"
|
||||
version = "zyIMDDzM"
|
||||
@@ -0,0 +1,8 @@
|
||||
name = "Mazes"
|
||||
filename = "mazes-0.1.0.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://git.ljones.me/yonlu/mazes/releases/download/v0.1.0/mazes-0.1.0.jar"
|
||||
hash-format = "sha256"
|
||||
hash = "405d9e4178856d15bf446abb7644b0617d22ac4503d0743bcb1c589abecaaf3d"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Mermod"
|
||||
filename = "mermod-neoforge-3.3.2+1.21.1.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/ORiydwz3/versions/MyXSxEZm/mermod-neoforge-3.3.2%2B1.21.1.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "b8bd1894f6010718a05f7473f3e8b051cdf27dd237644d327f9b720f985bedd73c5af736d6bc1486ebd704420ddcbaba1f29c6c2c5961063b729c614557ed7ab"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "ORiydwz3"
|
||||
version = "MyXSxEZm"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Miner's Delight"
|
||||
filename = "minersdelight-1.21.1-1.4.5.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/qMxbM4BQ/versions/YUHbwbgQ/minersdelight-1.21.1-1.4.5.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "98db53ab135281ab11e9abacbce846bfb42fdee6e0a85ae38802a5809fddc24af2e3fb5ba6ed53aa2244ce45f3a5ff93970dd1bc1b55d599560f99019a7fcac1"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "qMxbM4BQ"
|
||||
version = "YUHbwbgQ"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Mino++"
|
||||
filename = "minopp-1.4.0+1.21.1+neoforge.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/4QitwNm0/versions/oNb733MS/minopp-1.4.0%2B1.21.1%2Bneoforge.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "ee2bc51647bea76306e44beac96cb33d64438f5d0af4cf14b617548a4e1fee80a8c98f722373bf6a5a1c24641d8394331a520b675950e6998f227d4928dcd33c"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "4QitwNm0"
|
||||
version = "oNb733MS"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Moonlight Lib"
|
||||
filename = "moonlight-1.21.1-3.7.1-neoforge.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/twkfQtEc/versions/YfHkk7hg/moonlight-1.21.1-3.7.1-neoforge.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "871c0d176465f3d0e17a8de0992c8c5cb8c589501b8c480b38e7372f3a79fea3f23c2998f9b1ddeec1281e05927787a511638a11bcde25271ac73bed92852432"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "twkfQtEc"
|
||||
version = "YfHkk7hg"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "More Delight (for Farmer's Delight)"
|
||||
filename = "moredelight-26.05.20a-1.21-neoforge.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/znHQQtuU/versions/DpW4EgJo/moredelight-26.05.20a-1.21-neoforge.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "0c0a8eb68b071b6705e042fb87d5007d33b60899e2721032c6d31eb76f5a27b3482872964995f0add76d339bc92d7ce41ead91ea3014317d1776f1e5f7b36a1c"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "znHQQtuU"
|
||||
version = "DpW4EgJo"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "MossyLib"
|
||||
filename = "MossyLib-1.6.0+1.21.1+neoforge.jar"
|
||||
side = "client"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/ffLDUGbm/versions/r1b2ODLf/MossyLib-1.6.0%2B1.21.1%2Bneoforge.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "5cb30ec2cedc30bb96d5cfb238359e843a6ccdc203cf93dea4a87f3878b82735374552f331870e58fe86b04a64cbb778d8691b3e8ff05b216680bc6b597b74ed"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "ffLDUGbm"
|
||||
version = "r1b2ODLf"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "MRU"
|
||||
filename = "mru-1.0.41+1.21.1-neoforge.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/SNVQ2c0g/versions/Kpai1paZ/mru-1.0.41%2B1.21.1-neoforge.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "463127834c3c0e6f4a849849640be66e5ba666bd9e00121dbd390dc368b55efc9bfd2155ba58817cc88ce0138687970e3ef2ab84273566890b15b4b4a70c6199"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "SNVQ2c0g"
|
||||
version = "Kpai1paZ"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Music Disc Maker"
|
||||
filename = "music_disc_maker-3.0.5+neoforge-1.21.1.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/mqnazM0E/versions/qwym2WOo/music_disc_maker-3.0.5%2Bneoforge-1.21.1.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "4f9c66a57b2acc5d1fb84869e036e376fddd793ce5decf8d85c9e2b947b13e674775585db4d99215a307e438b5f5e24f98aecd96279478ab28eadf5cdfd0c386"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "mqnazM0E"
|
||||
version = "qwym2WOo"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Mystical Oak Tree"
|
||||
filename = "mysticaloaktree-1.21-1.14-neoforge.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/eUma2vmY/versions/DnclMSEE/mysticaloaktree-1.21-1.14-neoforge.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "e38417a51fff91155c3d1f8005bf2ffdd162894a39ae4ee2ae53015af7ce1dc5b2a827832ca2d604332f35f2e975eaa6d5a952d715c90ca691c7ec9ec9a84b2c"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "eUma2vmY"
|
||||
version = "DnclMSEE"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Now Playing"
|
||||
filename = "now-playing-neoforge-1.5.16+1.21.jar"
|
||||
side = "client"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/eNF4Bfla/versions/zocCsL7s/now-playing-neoforge-1.5.16%2B1.21.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "e2f6ee514f9c319d8198e8c0c461d2171402bd875adac2a79f548888bc5d62bf071a7b2da92a693717303f5d3dcc26aca696c3dda90666a133f326384f17bb31"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "eNF4Bfla"
|
||||
version = "zocCsL7s"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Open Parties and Claims"
|
||||
filename = "open-parties-and-claims-neoforge-1.21.1-0.31.6.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/gF3BGWvG/versions/3i48dTzz/open-parties-and-claims-neoforge-1.21.1-0.31.6.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "6f8f2d570b6f674a9180576524b3ba507a3ad046ff319353cee50738644bf46c03ca460fb7c6880eed76f07eb2a26a983166d2510951202af86b3e120b743181"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "gF3BGWvG"
|
||||
version = "3i48dTzz"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Overweight Farming"
|
||||
filename = "OverweightFarming-1.21.1-2.2.0-NeoForge.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/bCxmmxKN/versions/9w8TG5JN/OverweightFarming-1.21.1-2.2.0-NeoForge.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "32aaa8a506019ceefc9e6dfda2617b217911b92e25d11451d5afb7f022c0ad7274045e31230667421f1837193c04bd87dda0a80bf7ab0774c3fa96870f84a97a"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "bCxmmxKN"
|
||||
version = "9w8TG5JN"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Perception"
|
||||
filename = "Perception-NEOFORGE-0.2.1+1.21.1.jar"
|
||||
side = "client"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/P8STLvzB/versions/W5IQteYO/Perception-NEOFORGE-0.2.1%2B1.21.1.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "540180f6b90776096268249baa4e9380dff750989d8a6213289946b788ba07b647a6ff318ec1abbcaee5372ba9bd5b9244980869db43d1af0787a5ba57d6c93b"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "P8STLvzB"
|
||||
version = "W5IQteYO"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Pet Cemetery"
|
||||
filename = "pet_cemetery-1.21.1-3.0.1.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/M6tSWZ4N/versions/t9fzt3Pl/pet_cemetery-1.21.1-3.0.1.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "9494f693e70756258f0a6652ac2442adcf984d5835b645f7a0fc2abf83db5063843759c301a82443e6a80d579eb8fda917368989a0e1ec573ad85077485de398"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "M6tSWZ4N"
|
||||
version = "t9fzt3Pl"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "PetProtect"
|
||||
filename = "petprotect-neoforge-1.21.1-2.0.0.jar"
|
||||
side = "server"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/LeqaEyxB/versions/EjWilMbx/petprotect-neoforge-1.21.1-2.0.0.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "7874f9f2076dfe55f2f236baecb5fa0fd9e6871e8ca7109ee56029adb87cc7e1b59f84a3fcb3d3ce181256249d57c9a0253ad9e54f2aefc6b46b38449f779ae1"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "LeqaEyxB"
|
||||
version = "EjWilMbx"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "PlayerRevive"
|
||||
filename = "PlayerRevive_NEOFORGE_v2.1.2_mc1.21.1.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/ABIMzABM/versions/LS7UoW1b/PlayerRevive_NEOFORGE_v2.1.2_mc1.21.1.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "9f33feecb73d92a7771b389f684ec5ac762df956dfbe748e8b6c3d839eaa9d60b2476fbe95878ff657d8e4b46e1335c4db16094516e17436dca11c8f073aaf40"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "ABIMzABM"
|
||||
version = "LS7UoW1b"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Portfolio"
|
||||
filename = "portfolio-1.21.1-1.6.0-neoforge.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/2k6aLirX/versions/UAqcjhgj/portfolio-1.21.1-1.6.0-neoforge.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "e8a09b24e8251ba505023b2228b9b033a45d6f6bbd18ef03bc63875f71c2ffea58bf579799d231450db6acc7c7087a6880d73c339d7bd4127079f2c049109779"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "2k6aLirX"
|
||||
version = "UAqcjhgj"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Puzzles Lib"
|
||||
filename = "puzzleslib-v21.1.62-mc1.21.1+neoforge.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/QAGBst4M/versions/1TmfTuyw/puzzleslib-v21.1.62-mc1.21.1%2Bneoforge.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "241ff7229990305fe5f85521b9c11cd8e2e8d01cb94bbca987aae4d3d9ecbd9115a4b66f618a62d73ef1b569ff8c72434bc1354bbfaf2f69c0e997db034c4883"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "QAGBst4M"
|
||||
version = "1TmfTuyw"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Quick Skin"
|
||||
filename = "Quick Skin - NeoForge - 1.21.1-3.0.1.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/zAIE84Ch/versions/2SDgblIq/Quick%20Skin%20-%20NeoForge%20-%201.21.1-3.0.1.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "2860483c0e98c5d2a53612100e5f8d41533ed9cb10829099e7bc60a1114b97b713519b71b20bb96dbe80d8423688299b998ec96aeff062c05c09ba352410f3cf"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "zAIE84Ch"
|
||||
version = "2SDgblIq"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Room For Two"
|
||||
filename = "roomfortwo-neoforge-1.21.1-0.3.0.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/YZlvzIFq/versions/nVyx08tS/roomfortwo-neoforge-1.21.1-0.3.0.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "81cb8fa7a099af75339f05c562fea677479329d8cc3c449a231d564c90931d7bf10727af118966512bf2c114995be19a9cb41d0db008f0535eadb7892ad6fb89"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "YZlvzIFq"
|
||||
version = "nVyx08tS"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "RunicLib"
|
||||
filename = "neoforge-runiclib-1.21.1-5.0.7.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/mk0Htq87/versions/tk5EQpUG/neoforge-runiclib-1.21.1-5.0.7.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "c46d25abc6e034cd5d2b5fe53c7cc9fe23f17d5abc91fee7232872476ec9bd500da7504cfc69cab313ff2e7f4fa4c5f2a8b4b932112ebb2851b8e5cb0cd7e365"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "mk0Htq87"
|
||||
version = "tk5EQpUG"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Rustic Delight"
|
||||
filename = "rusticdelight-neoforge-1.21-1.7.1.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/foa4fGIH/versions/sAaG4pSA/rusticdelight-neoforge-1.21-1.7.1.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "1aa22e862f0775699782ee20aa5cf75ce528404711cf8587cb7a732c710aa76f4d14035d2cdd0ed92980eb5f9388765b7f17a5aa31bdeadb85382aad488a6d2a"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "foa4fGIH"
|
||||
version = "sAaG4pSA"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "ShatterLib | OctoLib"
|
||||
filename = "OctoLib-NEOFORGE-0.6.2+1.21.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/RH2KUdKJ/versions/yVCCi6TK/OctoLib-NEOFORGE-0.6.2%2B1.21.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "c33faa056c9d5403f06b7aa883290c86c33dcea3502f99720df98eccbd819cd3050fb2ffecf048f2dbee1b69a14e9dc6c23245f35ba3a78e46b056859666a60a"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "RH2KUdKJ"
|
||||
version = "yVCCi6TK"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "SmartBrainLib"
|
||||
filename = "SmartBrainLib-neoforge-1.21.1-1.16.11.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/PuyPazRT/versions/O5EpeqI3/SmartBrainLib-neoforge-1.21.1-1.16.11.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "bfc76f6fd8c388d01b80601ad1b826f6b3f5ec5ea915e5725af129561e6bc4a10890975e6f6d2a0348d842c13042dcf1a9d0a1574fba76bce60119bee76e2dc2"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "PuyPazRT"
|
||||
version = "O5EpeqI3"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Sooty Chimneys"
|
||||
filename = "sootychimneys-neoforge-1.3.5.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/b3w1XM9H/versions/prx2oU0O/sootychimneys-neoforge-1.3.5.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "137d5342af92bb00dc5ec6c8b15cfa48dfb5c09cab52dc7a8d932c40e90afc7fbd72850de04992c789642169809a20a9d163fbd06b3c41fc067f704d175e5b82"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "b3w1XM9H"
|
||||
version = "prx2oU0O"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Sounds"
|
||||
filename = "sounds-2.4.22+lts+1.21.1-neoforge.jar"
|
||||
side = "client"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/ZouiUX7t/versions/kti7i9SG/sounds-2.4.22%2Blts%2B1.21.1-neoforge.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "0dbfe1cd74be45241c5e95354e6466af10cb50ce780d87672337bd4de03fa708dc56eb013040bb2a02a941cf19b2b282385c6a5305695a4de3534627c645f053"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "ZouiUX7t"
|
||||
version = "kti7i9SG"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "TarotCards: Remastered"
|
||||
filename = "tarotcards-2.3.5-neoforge-1.21.1.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/haEej4hJ/versions/wOCHlHK0/tarotcards-2.3.5-neoforge-1.21.1.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "8c0e4643dc597ed9da82249209253f68d0de463a8571e0df75a0885c6e27aad50a68365dbfef257416f420d5046b0f5f5868139204284b68e45b60a6c748e259"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "haEej4hJ"
|
||||
version = "wOCHlHK0"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Too Many Bows"
|
||||
filename = "too_many_bows-neoforge-1.21.1-3.0.0.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/FOiJ92uI/versions/jkgwiMjB/too_many_bows-neoforge-1.21.1-3.0.0.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "0067d72206c655c0a68bd58eb08095819e75a3b3dac2f37faac045c19475c65eef3d5ed773c382dc0db2c8b2b9b6a391132ec1a7330e382f2f26ec115c899e12"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "FOiJ92uI"
|
||||
version = "jkgwiMjB"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Traveler's Titles"
|
||||
filename = "TravelersTitles-1.21.1-NeoForge-5.1.3.jar"
|
||||
side = "client"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/JtifUr64/versions/2y01mBUy/TravelersTitles-1.21.1-NeoForge-5.1.3.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "eed7ed02277e32f374da0999bbb24410c04543ca39e6e349ca9e441c468e218cf0cad59173f8b98c3f45140b24552efa3672ff48feb311ec01b19ab2f02b2e64"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "JtifUr64"
|
||||
version = "2y01mBUy"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Veggies Delight (A Farmer's Delight Add-on)"
|
||||
filename = "VeggiesDelight-1.21.1-1.9.3.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/emQ94xri/versions/9LiRnALb/VeggiesDelight-1.21.1-1.9.3.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "bd108223b38236c7cae2a02601e52c98d4f655a45f4f3a8c2f5d298aaa0ed0debbb2639bb08e11c5f33a0ae27242a3d4ff0aab9820915e3dadb1ce06a2763960"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "emQ94xri"
|
||||
version = "9LiRnALb"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Waystones Teleport Pets"
|
||||
filename = "WaystonesTeleportPets-1.2-neoforge-1.21.1.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/VaCl9OtG/versions/xWlyBWBZ/WaystonesTeleportPets-1.2-neoforge-1.21.1.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "47a184ee443116799fb2490d8d6b462b21e23f31db04c31b25196f7e1389efbf53e7a0f89ba2c09929c05fd9d0b9619de7b1b90f87cc1221a2d548c2b4bcd6a8"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "VaCl9OtG"
|
||||
version = "xWlyBWBZ"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "What Are They Up To (Watut)"
|
||||
filename = "watut-neoforge-1.21.0-1.2.7.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/AtB5mHky/versions/uWr2aTW9/watut-neoforge-1.21.0-1.2.7.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "b96bd6146344a86e4ad45fd4c274a15f0e146bcc13747940f8b9f0ea21c8ea8bca4d005444f2bf8082f29ec7ad1ce03507764ddfbdda64ac9284d8ac400b44c5"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "AtB5mHky"
|
||||
version = "uWr2aTW9"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Xaero's Minimap & World Map - Waystones Compatibility"
|
||||
filename = "xaeros_waystones_compatibility-NeoForge-1.21.1-2.1.0.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/7mLhyqIY/versions/k8wIAiWT/xaeros_waystones_compatibility-NeoForge-1.21.1-2.1.0.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "440da659b1c406ff410841248a28adba60b73f3d91f513ba335b9e5d44b3e48ab63d5ecc86484ff1e3d1a4f7830ad7566fc1efec2a03eba3c958b414b61feea0"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "7mLhyqIY"
|
||||
version = "k8wIAiWT"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Xaero's Minimap"
|
||||
filename = "xaerominimap-neoforge-1.21.1-26.5.0.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/1bokaNcj/versions/Q1tuMQBB/xaerominimap-neoforge-1.21.1-26.5.0.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "0fde1066dd922ac0796d166ba1bf1b843873b8d8563da3a08777df54bb377ff6466096650c730ad1b96e0aecf2d8974cd87c32165edf6a30f6653840c3f99abf"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "1bokaNcj"
|
||||
version = "Q1tuMQBB"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Xaero's World Map"
|
||||
filename = "xaeroworldmap-neoforge-1.21.1-1.46.0.jar"
|
||||
side = "both"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/NcUtCpym/versions/9Ckiihkz/xaeroworldmap-neoforge-1.21.1-1.46.0.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "fb14d11d66e0a6441981b18454c86534d8f534cd159ca19fa612950521788d858f37f18fe2093bb9b43ca0a88ae9af578eced5d140ff645a7681d7e452e8a268"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "NcUtCpym"
|
||||
version = "9Ckiihkz"
|
||||
@@ -0,0 +1,13 @@
|
||||
name = "Zume"
|
||||
filename = "zume-1.2.2.jar"
|
||||
side = "client"
|
||||
|
||||
[download]
|
||||
url = "https://cdn.modrinth.com/data/o6qsdrrQ/versions/Rh2ImJ86/zume-1.2.2.jar"
|
||||
hash-format = "sha512"
|
||||
hash = "9803fcf070327ed40316f8323ad7de83977a4ff8dc928c892836c8f49a9be3da6e9282aa85bf8bcf3467c4339f3d16dad5ec92d1a2e9bc9fc10bddba1ffc1190"
|
||||
|
||||
[update]
|
||||
[update.modrinth]
|
||||
mod-id = "o6qsdrrQ"
|
||||
version = "Rh2ImJ86"
|
||||
@@ -6,7 +6,7 @@ pack-format = "packwiz:1.1.0"
|
||||
[index]
|
||||
file = "index.toml"
|
||||
hash-format = "sha256"
|
||||
hash = "00c05d449179c84f406b8b3489ca69e8965c730036e76958d711d5ff42b17dcb"
|
||||
hash = "29cee97f1dd3e093e11e3e565cbf11dd1ddc6203a82e7e81b93016e601fa9989"
|
||||
|
||||
[versions]
|
||||
minecraft = "1.21.1"
|
||||
|
||||
Executable
+88
@@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Drop Xaero's map regions that a player never actually revealed.
|
||||
|
||||
After a player opens their pruned singleplayer world, Xaero's maps it - but Minecraft
|
||||
also *regenerates* the chunks around wherever that player logged in, so a little
|
||||
terrain they had never seen can sneak onto the map. This compares the harvested map
|
||||
against the reveal mask and removes the strays.
|
||||
|
||||
It works on file names only (`<rx>_<rz>.zip` is one 512x512-block region, exactly the
|
||||
same geometry as an FTB Chunks region file), so it needs no knowledge of Xaero's
|
||||
region format.
|
||||
|
||||
Usage:
|
||||
filter-xaero-regions.py <xaero-map-dir> <mask.json> [--dimension <id>] [--delete]
|
||||
|
||||
Without --delete it only reports. Run it on one dimension folder at a time, e.g.
|
||||
~/.minecraft/xaero/world-map/Multiplayer_advilplug.top/null/
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
REGION_RE = re.compile(r"^(-?\d+)_(-?\d+)\.zip$")
|
||||
|
||||
|
||||
def main() -> int:
|
||||
ap = argparse.ArgumentParser(description=__doc__.split("\n")[0])
|
||||
ap.add_argument("map_dir", help="Xaero's map instance directory holding <rx>_<rz>.zip")
|
||||
ap.add_argument("mask", help="mask JSON from ftbchunks-reveal.py")
|
||||
ap.add_argument("--dimension", default=None,
|
||||
help="dimension to check (default: the mask's only dimension)")
|
||||
ap.add_argument("--delete", action="store_true", help="actually remove the strays")
|
||||
args = ap.parse_args()
|
||||
|
||||
with open(args.mask) as fh:
|
||||
mask = json.load(fh)
|
||||
dims = mask["dimensions"]
|
||||
dim = args.dimension
|
||||
if dim is None:
|
||||
if len(dims) != 1:
|
||||
print(f"mask has {len(dims)} dimensions; pass --dimension", file=sys.stderr)
|
||||
return 2
|
||||
dim = next(iter(dims))
|
||||
if dim not in dims:
|
||||
print(f"no dimension '{dim}' in mask; have {list(dims)}", file=sys.stderr)
|
||||
return 2
|
||||
|
||||
revealed = {tuple(int(v) for v in key.split(",")) for key in dims[dim]["regions"]}
|
||||
|
||||
if not os.path.isdir(args.map_dir):
|
||||
print(f"not a directory: {args.map_dir}", file=sys.stderr)
|
||||
return 2
|
||||
|
||||
present, strays = [], []
|
||||
for name in sorted(os.listdir(args.map_dir)):
|
||||
m = REGION_RE.match(name)
|
||||
if not m:
|
||||
continue
|
||||
coords = (int(m.group(1)), int(m.group(2)))
|
||||
(present if coords in revealed else strays).append((name, coords))
|
||||
|
||||
print(f"dimension {dim}")
|
||||
print(f" map regions present : {len(present)} (of {len(revealed)} revealed)")
|
||||
print(f" not in the mask : {len(strays)}")
|
||||
for name, _ in strays:
|
||||
print(f" {name}")
|
||||
|
||||
missing = sorted(revealed - {c for _, c in present})
|
||||
if missing:
|
||||
print(f" revealed but absent from the map: {len(missing)} "
|
||||
f"(e.g. {missing[:4]}) - regenerate these, do not delete anything")
|
||||
|
||||
if args.delete and strays:
|
||||
for name, _ in strays:
|
||||
os.remove(os.path.join(args.map_dir, name))
|
||||
print(f"\nremoved {len(strays)} stray region file(s)")
|
||||
elif strays:
|
||||
print("\nre-run with --delete to remove them")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Executable
+284
@@ -0,0 +1,284 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Extract a per-chunk reveal mask from FTB Chunks client map data.
|
||||
|
||||
FTB Chunks stores its explored-terrain map client-side, one zip per 512x512-block
|
||||
region:
|
||||
|
||||
<game>/local/ftbchunks/data/<serverUUID>/<dimension>/<XXXXX-XXXXX>.zip
|
||||
|
||||
Each zip holds `chunks.dat` (the chunks the player has actually seen) plus five
|
||||
PNG data images. Region file names are the region coordinate + 60000, formatted
|
||||
`%05X-%05X`, which is why overworld spawn shows up as `0EA60-0EA60.zip`.
|
||||
|
||||
`chunks.dat` layout (verified against ftb-chunks-neoforge-2101.1.22 bytecode):
|
||||
|
||||
u8 leading byte (0)
|
||||
u8 version (3 on this build)
|
||||
i16 big-endian chunk count
|
||||
per chunk:
|
||||
u8 chunk version (present when version >= 2)
|
||||
u8 x within region (0..31)
|
||||
u8 z within region (0..31)
|
||||
i64 big-endian last-modified millis
|
||||
|
||||
`chunks.dat` was checked against the `data.png` height sentinel (HeightUtils.UNKNOWN
|
||||
= -32767, packed as (height << 16) | (water|light|biome)) across all 167 regions of a
|
||||
real 98,170-chunk dataset: zero disagreements. So chunks.dat alone is a trustworthy
|
||||
reveal mask; --verify re-runs that cross-check anyway.
|
||||
|
||||
Output is a JSON mask consumed by prune-world-to-reveal.py.
|
||||
|
||||
Usage:
|
||||
ftbchunks-reveal.py <input> [--out mask.json] [--dimension <id>] [--verify] [--quiet]
|
||||
|
||||
<input> is either
|
||||
* a client data directory, e.g. .../local/ftbchunks/data/<uuid>/, which is scanned
|
||||
across all dimensions listed in its dimensions.txt, or
|
||||
* a directory or zip containing region zips directly (a single dimension, as when
|
||||
someone has archived just the overworld). Such an input cannot name its own
|
||||
dimension, so pass --dimension to label it.
|
||||
|
||||
Output coordinates are global chunk coordinates, so they are independent of which
|
||||
region file a chunk happened to live in.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import struct
|
||||
import sys
|
||||
import zipfile
|
||||
import zlib
|
||||
|
||||
REGION_RE = re.compile(r"^([0-9A-Fa-f]{4,6})-([0-9A-Fa-f]{4,6})\.zip$")
|
||||
REGION_OFFSET = 60000
|
||||
|
||||
# HeightUtils.UNKNOWN = Short.MIN_VALUE + 1, stored masked to 16 bits.
|
||||
UNKNOWN_RAW = (-32767) & 0xFFFF
|
||||
|
||||
|
||||
def parse_region_name(name: str) -> tuple[int, int] | None:
|
||||
"""`0EA60-0EA5F.zip` -> region coordinate (0, -1)."""
|
||||
m = REGION_RE.match(os.path.basename(name))
|
||||
if not m:
|
||||
return None
|
||||
return int(m.group(1), 16) - REGION_OFFSET, int(m.group(2), 16) - REGION_OFFSET
|
||||
|
||||
|
||||
def parse_chunks_dat(data: bytes) -> set[tuple[int, int]]:
|
||||
"""Return the within-region (x, z) chunk coordinates present in chunks.dat."""
|
||||
if len(data) < 4:
|
||||
return set()
|
||||
buf = io.BytesIO(data)
|
||||
buf.read(1)
|
||||
version = buf.read(1)[0]
|
||||
count = struct.unpack(">h", buf.read(2))[0]
|
||||
chunks: set[tuple[int, int]] = set()
|
||||
for _ in range(count):
|
||||
if version >= 2:
|
||||
buf.read(1)
|
||||
x = buf.read(1)[0]
|
||||
z = buf.read(1)[0]
|
||||
buf.read(8)
|
||||
chunks.add((x, z))
|
||||
return chunks
|
||||
|
||||
|
||||
# --- optional cross-check: decode data.png and find the UNKNOWN sentinel --------
|
||||
|
||||
def _png_decode(data: bytes) -> tuple[int, int, int, bytes]:
|
||||
"""Minimal PNG decoder (8-bit, non-interlaced) -> (w, h, channels, rgba bytes)."""
|
||||
if data[:8] != b"\x89PNG\r\n\x1a\n":
|
||||
raise ValueError("not a PNG")
|
||||
pos, idat = 8, b""
|
||||
width = height = depth = colour = None
|
||||
while pos < len(data):
|
||||
(length,) = struct.unpack(">I", data[pos : pos + 4])
|
||||
kind = data[pos + 4 : pos + 8]
|
||||
body = data[pos + 8 : pos + 8 + length]
|
||||
pos += 12 + length
|
||||
if kind == b"IHDR":
|
||||
width, height, depth, colour, comp, filt, interlace = struct.unpack(
|
||||
">IIBBBBB", body
|
||||
)
|
||||
if depth != 8 or interlace != 0:
|
||||
raise ValueError(f"unsupported PNG depth/interlace {depth}/{interlace}")
|
||||
elif kind == b"IDAT":
|
||||
idat += body
|
||||
elif kind == b"IEND":
|
||||
break
|
||||
channels = {0: 1, 2: 3, 3: 1, 4: 2, 6: 4}[colour]
|
||||
stride = width * channels
|
||||
raw = zlib.decompress(idat)
|
||||
out = bytearray()
|
||||
prev = bytearray(stride)
|
||||
p = 0
|
||||
for _ in range(height):
|
||||
ftype = raw[p]
|
||||
p += 1
|
||||
line = bytearray(raw[p : p + stride])
|
||||
p += stride
|
||||
if ftype == 1:
|
||||
for i in range(channels, stride):
|
||||
line[i] = (line[i] + line[i - channels]) & 0xFF
|
||||
elif ftype == 2:
|
||||
for i in range(stride):
|
||||
line[i] = (line[i] + prev[i]) & 0xFF
|
||||
elif ftype == 3:
|
||||
for i in range(stride):
|
||||
a = line[i - channels] if i >= channels else 0
|
||||
line[i] = (line[i] + ((a + prev[i]) >> 1)) & 0xFF
|
||||
elif ftype == 4:
|
||||
for i in range(stride):
|
||||
a = line[i - channels] if i >= channels else 0
|
||||
b = prev[i]
|
||||
c = prev[i - channels] if i >= channels else 0
|
||||
pp = a + b - c
|
||||
pa, pb, pc = abs(pp - a), abs(pp - b), abs(pp - c)
|
||||
pred = a if (pa <= pb and pa <= pc) else (b if pb <= pc else c)
|
||||
line[i] = (line[i] + pred) & 0xFF
|
||||
out += line
|
||||
prev = line
|
||||
return width, height, channels, bytes(out)
|
||||
|
||||
|
||||
def chunks_seen_in_png(png_bytes: bytes) -> set[tuple[int, int]]:
|
||||
"""Chunks (0..31)^2 having at least one non-UNKNOWN pixel."""
|
||||
width, height, channels, px = _png_decode(png_bytes)
|
||||
unknown_r = UNKNOWN_RAW & 0xFF
|
||||
unknown_a = (UNKNOWN_RAW >> 8) & 0xFF
|
||||
seen: set[tuple[int, int]] = set()
|
||||
for cz in range(32):
|
||||
for cx in range(32):
|
||||
hit = False
|
||||
for yy in range(16):
|
||||
base = ((cz * 16 + yy) * width + cx * 16) * channels
|
||||
for xx in range(16):
|
||||
i = base + xx * channels
|
||||
if not (px[i] == unknown_r and px[i + 3] == unknown_a):
|
||||
hit = True
|
||||
break
|
||||
if hit:
|
||||
break
|
||||
if hit:
|
||||
seen.add((cx, cz))
|
||||
return seen
|
||||
|
||||
|
||||
# --- input discovery -----------------------------------------------------------
|
||||
|
||||
def iter_region_zips(path: str):
|
||||
"""Yield (dimension_name, region_filename, bytes) from a dir or an archive."""
|
||||
if zipfile.is_zipfile(path):
|
||||
with zipfile.ZipFile(path) as outer:
|
||||
for info in outer.infolist():
|
||||
if parse_region_name(info.filename) is None:
|
||||
continue
|
||||
yield "(unspecified)", os.path.basename(info.filename), outer.read(info)
|
||||
return
|
||||
if os.path.isdir(path) and any(
|
||||
parse_region_name(n) for n in os.listdir(path)
|
||||
):
|
||||
for name in sorted(os.listdir(path)):
|
||||
if parse_region_name(name):
|
||||
with open(os.path.join(path, name), "rb") as fh:
|
||||
yield "(unspecified)", name, fh.read()
|
||||
return
|
||||
# treat as a client data directory keyed by dimension
|
||||
dims_file = os.path.join(path, "dimensions.txt")
|
||||
dims = []
|
||||
if os.path.exists(dims_file):
|
||||
with open(dims_file) as fh:
|
||||
dims = [ln.strip() for ln in fh if ln.strip()]
|
||||
else:
|
||||
dims = [
|
||||
d
|
||||
for d in sorted(os.listdir(path))
|
||||
if os.path.isdir(os.path.join(path, d))
|
||||
]
|
||||
for dim in dims:
|
||||
dim_dir = os.path.join(path, dim)
|
||||
if not os.path.isdir(dim_dir):
|
||||
continue
|
||||
for name in sorted(os.listdir(dim_dir)):
|
||||
if parse_region_name(name):
|
||||
with open(os.path.join(dim_dir, name), "rb") as fh:
|
||||
yield dim, name, fh.read()
|
||||
|
||||
|
||||
def extract(path: str, verify: bool, quiet: bool, dimension_label: str | None = None) -> dict:
|
||||
dims: dict[str, dict] = {}
|
||||
total = 0
|
||||
mismatches = 0
|
||||
for dim, name, blob in iter_region_zips(path):
|
||||
if dim == "(unspecified)" and dimension_label:
|
||||
dim = dimension_label
|
||||
coords = parse_region_name(name)
|
||||
if coords is None:
|
||||
continue
|
||||
rx, rz = coords
|
||||
with zipfile.ZipFile(io.BytesIO(blob)) as region:
|
||||
listed = parse_chunks_dat(region.read("chunks.dat"))
|
||||
if verify:
|
||||
seen = chunks_seen_in_png(region.read("data.png"))
|
||||
if seen != listed:
|
||||
mismatches += 1
|
||||
print(
|
||||
f" ! {dim}/{name}: chunks.dat={len(listed)} png={len(seen)}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
entry = dims.setdefault(dim, {"regions": {}, "chunks": []})
|
||||
entry["regions"][f"{rx},{rz}"] = len(listed)
|
||||
for cx, cz in sorted(listed):
|
||||
entry["chunks"].append([rx * 32 + cx, rz * 32 + cz])
|
||||
total += len(listed)
|
||||
if not quiet:
|
||||
print(f" {dim:34} {name:>16} {len(listed):>4} chunks", file=sys.stderr)
|
||||
|
||||
for entry in dims.values():
|
||||
entry["chunks"].sort()
|
||||
entry["region_count"] = len(entry["regions"])
|
||||
entry["chunk_count"] = len(entry["chunks"])
|
||||
return {
|
||||
"source": os.path.abspath(path),
|
||||
"verified": verify,
|
||||
"mismatches": mismatches,
|
||||
"total_chunks": total,
|
||||
"dimensions": dims,
|
||||
}
|
||||
|
||||
|
||||
def main() -> int:
|
||||
ap = argparse.ArgumentParser(description=__doc__.split("\n")[0])
|
||||
ap.add_argument("input", help="FTB Chunks data dir, or a dir/zip of region zips")
|
||||
ap.add_argument("--out", default="ftb-reveal-mask.json")
|
||||
ap.add_argument("--dimension", default=None,
|
||||
help="dimension id used to label a bare directory/zip of region files, which "
|
||||
"cannot say which dimension it is (e.g. minecraft:overworld)")
|
||||
ap.add_argument("--verify", action="store_true", help="cross-check chunks.dat vs data.png")
|
||||
ap.add_argument("--quiet", action="store_true")
|
||||
args = ap.parse_args()
|
||||
|
||||
mask = extract(args.input, args.verify, args.quiet, args.dimension)
|
||||
with open(args.out, "w") as fh:
|
||||
json.dump(mask, fh)
|
||||
|
||||
if args.verify:
|
||||
status = "OK" if mask["mismatches"] == 0 else f"{mask['mismatches']} MISMATCHES"
|
||||
print(f"cross-check chunks.dat vs data.png: {status}", file=sys.stderr)
|
||||
print(
|
||||
f"{mask['total_chunks']:,} revealed chunks in "
|
||||
f"{sum(d['region_count'] for d in mask['dimensions'].values())} regions "
|
||||
f"across {len(mask['dimensions'])} dimension(s) -> {args.out}"
|
||||
)
|
||||
for dim, d in mask["dimensions"].items():
|
||||
print(f" {dim}: {d['chunk_count']:,} chunks / {d['region_count']} regions")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Executable
+131
@@ -0,0 +1,131 @@
|
||||
#!/usr/bin/env bash
|
||||
# End-to-end driver for the FTB Chunks -> Xaero's World Map reveal transplant.
|
||||
#
|
||||
# See analysis/FTB-XAERO-MAP-MIGRATION.md for the reasoning. This script does the
|
||||
# parts that can be automated; the singleplayer pass in step 3 has to be done by hand
|
||||
# on a machine that can run the pack.
|
||||
#
|
||||
# Usage:
|
||||
# migrate-player.sh <player> <ftbchunks-data> <world-dir> [--dimension <id>] [--work <dir>]
|
||||
#
|
||||
# <player> label used for output paths, e.g. Stirwick
|
||||
# <ftbchunks-data> that player's local/ftbchunks/data/<uuid>/, or a bare zip/dir
|
||||
# of region files, or an already-extracted mask .json
|
||||
# <world-dir> the world save containing region/
|
||||
#
|
||||
# Example:
|
||||
# tools/migrate-player.sh Stirwick ~/Stirwick-ftbchunks ~/server/world \
|
||||
# --dimension minecraft:overworld --work /var/tmp/xaero-migration
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
if [ $# -lt 3 ]; then
|
||||
sed -n '2,20p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'
|
||||
exit 2
|
||||
fi
|
||||
|
||||
player="$1"; ftb="$2"; world="$3"; shift 3
|
||||
dimension="minecraft:overworld"
|
||||
work="$(pwd)/xaero-migration"
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--dimension) dimension="$2"; shift 2 ;;
|
||||
--work) work="$2"; shift 2 ;;
|
||||
*) echo "unknown option: $1" >&2; exit 2 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
out="$work/$player"
|
||||
mask="$out/mask.json"
|
||||
sp="$out/sp-world"
|
||||
|
||||
echo "player : $player"
|
||||
echo "ftb data : $ftb"
|
||||
echo "world : $world"
|
||||
echo "dimension : $dimension"
|
||||
echo "output : $out"
|
||||
echo
|
||||
|
||||
if [ ! -d "$world/region" ]; then
|
||||
echo "error: $world/region not found" >&2
|
||||
exit 1
|
||||
fi
|
||||
mkdir -p "$out"
|
||||
|
||||
echo "== 1/2 extracting reveal mask =="
|
||||
if [ "${ftb##*.}" = "json" ]; then
|
||||
cp -f "$ftb" "$mask"
|
||||
echo " using prebuilt mask: $ftb"
|
||||
python3 - "$mask" <<'PY'
|
||||
import json, sys
|
||||
m = json.load(open(sys.argv[1]))
|
||||
dims = m["dimensions"]
|
||||
print(f" {m['total_chunks']:,} chunks / "
|
||||
f"{sum(d['region_count'] for d in dims.values())} regions / "
|
||||
f"dimension(s) {list(dims)}")
|
||||
PY
|
||||
else
|
||||
python3 "$here/ftbchunks-reveal.py" "$ftb" --out "$mask" --dimension "$dimension" --verify
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "== 2/2 pruning the world to those chunks (dry run first) =="
|
||||
python3 "$here/prune-world-to-reveal.py" "$world" "$mask" "$sp" \
|
||||
--dimension "$dimension" --minimal --dry-run
|
||||
echo
|
||||
python3 "$here/prune-world-to-reveal.py" "$world" "$mask" "$sp" \
|
||||
--dimension "$dimension" --minimal
|
||||
|
||||
cat <<EOF
|
||||
|
||||
Done. Pruned world: $sp
|
||||
|
||||
Now, by hand.
|
||||
|
||||
3. Copy $sp to a machine that can run the pack and open it in SINGLEPLAYER once,
|
||||
as a world folder (the directory holding level.dat and region/):
|
||||
|
||||
<game dir>/saves/Stirwick-reveal/
|
||||
|
||||
Open it, open the map (M), let it fill, then quit. Xaero's maps what is in the
|
||||
save, and this save holds only the revealed chunks. Do not walk around --
|
||||
Minecraft regenerates chunks near the login position and they will show up.
|
||||
|
||||
Where the result lands: look under <game dir>/xaero/world-map/ for a folder that
|
||||
is not Multiplayer_*, e.g. World/null/<map>/. Sort by modification time if
|
||||
unsure -- those files were just written.
|
||||
|
||||
SANITY CHECK: you should end up with one zip per region in the mask
|
||||
($(python3 -c "import json;print(sum(d['region_count'] for d in json.load(open('$mask'))['dimensions'].values()))") for $player). A handful means it only mapped the spawn area and
|
||||
you should use 'Convert All Regions' in the world map settings, or report back.
|
||||
|
||||
4. Clean the HARVEST before anything else -- this is the step that removes terrain
|
||||
Minecraft regenerated around the login point. Run it on the harvested folder,
|
||||
NOT on the player's own map folder:
|
||||
|
||||
python3 $here/filter-xaero-regions.py \\
|
||||
"<game dir>/xaero/world-map/World/null/<map>/" \\
|
||||
$mask --dimension $dimension
|
||||
|
||||
Check the list, then re-run with --delete.
|
||||
|
||||
5. Merge the surviving <rx>_<rz>.zip files into the player's existing map folder,
|
||||
WITHOUT overwriting anything already there (-n), so any terrain they have
|
||||
explored since the swap is kept:
|
||||
|
||||
cp -n <harvested>/*.zip \\
|
||||
"<their game dir>/xaero/world-map/Multiplayer_advilplug.top/null/<their map instance>/"
|
||||
|
||||
The right instance is the mw\$... folder there. If the player has not joined the
|
||||
server since the swap, have them join once first so Xaero's creates it.
|
||||
|
||||
6. Delete $out -- scratch, usually a few hundred MB.
|
||||
|
||||
Per-dimension: repeat with --dimension <id> and the matching map folder
|
||||
(null = overworld, DIM-1 = nether, DIM1 = end).
|
||||
Other players: each needs their own local/ftbchunks/data/<uuid>/; there is no
|
||||
server-side copy of this data.
|
||||
EOF
|
||||
Executable
+210
@@ -0,0 +1,210 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Prune a Minecraft Anvil world save down to a set of revealed chunks.
|
||||
|
||||
This is how we transplant FTB Chunks' reveal footprint onto Xaero's World Map
|
||||
without reverse-engineering Xaero's region format: strip the world save down to
|
||||
exactly the chunks a player had explored, then let Xaero's own generator map that
|
||||
save in singleplayer. Xaero's renders it natively (correct palette, shading,
|
||||
light, biome) and the absent chunks simply never appear on the map.
|
||||
|
||||
Chunk payloads are copied through byte-for-byte -- no NBT re-encoding -- so the
|
||||
output is safe for modded 1.21.1 chunk data. Only the 8 KiB header, the sector
|
||||
offsets and the zero padding are rewritten.
|
||||
|
||||
Usage:
|
||||
prune-world-to-reveal.py <world-save-dir> <mask.json> <out-dir>
|
||||
[--dimension minecraft:overworld] [--dry-run]
|
||||
|
||||
Reads `<world-save-dir>/region/r.<x>.<z>.mca` and writes pruned copies to
|
||||
`<out-dir>/region/`, along with whatever else the world needs. Nested per-dimension
|
||||
`region`/`entities`/`poi` trees are never copied, so the Nether and End are not
|
||||
duplicated at full size; `--minimal` goes further and copies only `level.dat`, which
|
||||
is all Xaero's needs to map the overworld.
|
||||
|
||||
If a full save copy is wanted (level.dat, data/, playerdata/ ...), copy the world
|
||||
first and then run this in place with <out-dir> == <world-save-dir>.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import struct
|
||||
import sys
|
||||
|
||||
SECTOR = 4096
|
||||
HEADER = 2 * SECTOR
|
||||
COMPRESSION_NAMES = {1: "gzip", 2: "zlib", 3: "none", 4: "lz4", 127: "external"}
|
||||
|
||||
|
||||
def read_slot(data: bytes, size: int, slot: int) -> tuple[bytes, int, int] | None:
|
||||
"""Return (payload, timestamp, compression) for an Anvil slot, or None if empty."""
|
||||
off = struct.unpack(">I", b"\x00" + data[slot * 4 : slot * 4 + 3])[0]
|
||||
if off == 0:
|
||||
return None
|
||||
timestamp = struct.unpack(">I", data[SECTOR + slot * 4 : SECTOR + slot * 4 + 4])[0]
|
||||
start = off * SECTOR
|
||||
if start + 5 > len(data):
|
||||
raise ValueError(f"slot {slot}: offset {off} past end of file")
|
||||
(length,) = struct.unpack(">I", data[start : start + 4])
|
||||
compression = data[start + 4]
|
||||
if length < 1 or start + 4 + length > len(data):
|
||||
raise ValueError(f"slot {slot}: bad chunk length {length}")
|
||||
return data[start + 5 : start + 4 + length], timestamp, compression
|
||||
|
||||
|
||||
def prune_region(path: str, keep_slots: set[int], out_path: str, dry: bool) -> dict:
|
||||
with open(path, "rb") as fh:
|
||||
data = fh.read()
|
||||
|
||||
kept: list[tuple[int, bytes, int, int]] = []
|
||||
dropped = 0
|
||||
external = 0
|
||||
for slot in range(1024):
|
||||
entry = read_slot(data, SECTOR, slot)
|
||||
if entry is None:
|
||||
continue
|
||||
payload, timestamp, compression = entry
|
||||
if compression == 127:
|
||||
external += 1
|
||||
if slot in keep_slots:
|
||||
kept.append((slot, payload, timestamp, compression))
|
||||
else:
|
||||
dropped += 1
|
||||
|
||||
stats = {
|
||||
"file": os.path.basename(path),
|
||||
"kept": len(kept),
|
||||
"dropped": dropped,
|
||||
"external_payloads": external,
|
||||
}
|
||||
if dry:
|
||||
return stats
|
||||
|
||||
out = bytearray(HEADER)
|
||||
sector = 2
|
||||
for slot, payload, timestamp, compression in kept:
|
||||
blob = struct.pack(">I", len(payload) + 1) + bytes([compression]) + payload
|
||||
sectors = (len(blob) + SECTOR - 1) // SECTOR
|
||||
if sector + sectors > 0xFFFFFF:
|
||||
raise ValueError(f"{path}: region would exceed the Anvil 24-bit offset limit")
|
||||
out[slot * 4 : slot * 4 + 3] = sector.to_bytes(3, "big")
|
||||
out[slot * 4 + 3] = sectors
|
||||
out[SECTOR + slot * 4 : SECTOR + slot * 4 + 4] = struct.pack(">I", timestamp)
|
||||
out += blob
|
||||
out += b"\x00" * (sectors * SECTOR - len(blob))
|
||||
sector += sectors
|
||||
|
||||
os.makedirs(os.path.dirname(out_path) or ".", exist_ok=True)
|
||||
with open(out_path, "wb") as fh:
|
||||
fh.write(out)
|
||||
return stats
|
||||
|
||||
|
||||
def main() -> int:
|
||||
ap = argparse.ArgumentParser(description=__doc__.split("\n")[0])
|
||||
ap.add_argument("world", help="world save directory containing region/")
|
||||
ap.add_argument("mask", help="mask JSON from ftbchunks-reveal.py")
|
||||
ap.add_argument("out", help="output world directory (use the same path for in-place)")
|
||||
ap.add_argument("--dimension", default="minecraft:overworld",
|
||||
help="which dimension in the mask to apply (default overworld)")
|
||||
ap.add_argument("--minimal", action="store_true",
|
||||
help="output only level.dat + the pruned region/ tree (smallest usable world)")
|
||||
ap.add_argument("--dry-run", action="store_true")
|
||||
args = ap.parse_args()
|
||||
|
||||
with open(args.mask) as fh:
|
||||
mask = json.load(fh)
|
||||
dims = mask["dimensions"]
|
||||
if args.dimension not in dims:
|
||||
print(f"mask has no dimension '{args.dimension}'; available: {list(dims)}", file=sys.stderr)
|
||||
return 2
|
||||
|
||||
chunks = {(cx, cz) for cx, cz in dims[args.dimension]["chunks"]}
|
||||
by_region: dict[tuple[int, int], set[int]] = {}
|
||||
for cx, cz in chunks:
|
||||
rx, rz = cx >> 5, cz >> 5
|
||||
by_region.setdefault((rx, rz), set()).add((cx & 31) + (cz & 31) * 32)
|
||||
|
||||
in_region = os.path.join(args.world, "region")
|
||||
if not os.path.isdir(in_region):
|
||||
print(f"no region/ directory under {args.world}", file=sys.stderr)
|
||||
return 2
|
||||
out_region = os.path.join(args.out, "region")
|
||||
os.makedirs(out_region, exist_ok=True)
|
||||
|
||||
# Copy the rest of the world so the pruned save is openable, unless in-place.
|
||||
# Nested `region`/`entities`/`poi` trees (i.e. per-dimension ones like DIM-1/) are never
|
||||
# copied - copying them wholesale would duplicate the Nether and End at full size.
|
||||
if os.path.abspath(args.out) != os.path.abspath(args.world) and not args.dry_run:
|
||||
ignore = shutil.ignore_patterns("region", "entities", "poi")
|
||||
for name in sorted(os.listdir(args.world)):
|
||||
if name in ("region", "entities", "poi"):
|
||||
continue
|
||||
if args.minimal and name not in ("level.dat", "level.dat_old"):
|
||||
continue
|
||||
src, dst = os.path.join(args.world, name), os.path.join(args.out, name)
|
||||
if os.path.exists(dst):
|
||||
continue
|
||||
if os.path.isdir(src):
|
||||
shutil.copytree(src, dst, ignore=ignore)
|
||||
else:
|
||||
shutil.copy2(src, dst)
|
||||
|
||||
total_kept = total_dropped = 0
|
||||
seen_regions = set()
|
||||
failures: list[tuple[str, str]] = []
|
||||
failed_regions: set[tuple[int, int]] = set()
|
||||
for name in sorted(os.listdir(in_region)):
|
||||
if not (name.startswith("r.") and name.endswith(".mca")):
|
||||
continue
|
||||
_, rx, rz, _ = name.split(".")
|
||||
coords = (int(rx), int(rz))
|
||||
keep = by_region.get(coords)
|
||||
if keep is None:
|
||||
continue # region untouched by the reveal set
|
||||
try:
|
||||
stats = prune_region(
|
||||
os.path.join(in_region, name),
|
||||
keep,
|
||||
os.path.join(out_region, name),
|
||||
args.dry_run,
|
||||
)
|
||||
except Exception as exc:
|
||||
# A live server can rewrite a region file mid-read. A torn read is not a reason to
|
||||
# abandon the whole pass - no output is written for a region that fails, so it can
|
||||
# simply be retried.
|
||||
failures.append((name, str(exc)))
|
||||
failed_regions.add(coords)
|
||||
print(f" ! {name}: {exc}", file=sys.stderr)
|
||||
continue
|
||||
seen_regions.add(coords)
|
||||
total_kept += stats["kept"]
|
||||
total_dropped += stats["dropped"]
|
||||
if stats["external_payloads"]:
|
||||
print(f" ! {name}: {stats['external_payloads']} external (.mcc) payload(s) "
|
||||
f"referenced but not copied", file=sys.stderr)
|
||||
print(f" {name}: kept {stats['kept']:>4} / dropped {stats['dropped']:>4}")
|
||||
|
||||
# Any region the player revealed but that has no .mca file.
|
||||
missing = sorted(set(by_region) - seen_regions - failed_regions)
|
||||
if missing:
|
||||
print(f" ! {len(missing)} revealed region(s) have no .mca in the save "
|
||||
f"(e.g. {missing[:3]})", file=sys.stderr)
|
||||
|
||||
verb = "would keep" if args.dry_run else "kept"
|
||||
print(f"\n{verb} {total_kept:,} chunks, dropped {total_dropped:,}, "
|
||||
f"across {len(seen_regions)} region file(s) -> {out_region}")
|
||||
if failures:
|
||||
print(f"\n{len(failures)} region(s) could not be read (not written):", file=sys.stderr)
|
||||
for name, why in failures:
|
||||
print(f" {name}: {why}", file=sys.stderr)
|
||||
print("Re-run to retry them - usually a transient write by a running server.", file=sys.stderr)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in new issue
Block a user