Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# Changelog

## 0.5.5.121012 beta

I wanted magic mods to be able to share a nexus even when they use completely different kinds of magic. A technomancer can now carry aether and a mage can carry mana. Each mod decides who gets a pool and how big it is, and both can draw from the same nexus.

- Transfers and conversions can happen instantly or over time. Mods can also let players refill from a nearby nexus at a rate they choose.
- Player energy drops on death by default. Pack makers can change that behavior, tune capacities and rates, and restrict transfers between players.
- KubeJS can read and change pools, start and cancel jobs, and react when a pool runs empty.
- Structure mods can ask for all the nexuses in a chunk from a generation worker. Ore placement can reuse the column sampler.
- Operators can stage named nexuses and their connections for the next world start. A retired pin keeps its converted balances available for recovery at another nexus.
- Nexus pools now default to 1% of their original size. A 7,000-raw nexus holds 70 raw, enough for 700 units at a rate of 10 units per raw. Change **Nexus Capacity Multiplier** in Server Settings and reopen the world to adjust it. Existing converted energy stays available.
- The ledger backs itself up before changing the pool multiplier or first adding player-pool or pin data. Multiplier changes use save schema 6. Use the same build on the client and server.

This beta is for Minecraft 1.21.1 on NeoForge 21.1.247 or later in the 21.1 line, with Java 21.

## 0.5.4.121012 beta

This beta brings together the work since the 0.4.1 alpha. I’ve added a few ways to see what’s going on in your world and given pack makers more control over how the magic works.
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ Craft a pair of dowsing rods with two copper ingots and two sticks. Hold the pai

If you’re an operator, run `/skysleylines locate nexus` and click the coordinates to copy them. Switch on Ley Vision with `/skysleylines vision on`. River is the default, with Crackle, Sparkles and Glow for a quieter view. Pick up a Ley Meter from **Operator Utilities** and right-click a block to see the local field and any nexus account you can reach from there.

Open **Mods → Sky’s Ley Lines → Config** to set up new-world defaults. In a local single-player world you can also choose the default vision style and adjust how long a nexus takes to refill. The [operator guide](docs/SERVER_GUIDE.md) covers commands and dedicated servers.
Open **Mods → Sky’s Ley Lines → Config** to set up new-world defaults. In a local single-player world you can also choose the default vision style and adjust how much a nexus can hold and how long it takes to refill. Operators can place a named nexus with `/skysleylines nexus pin add`. It takes effect the next time the world opens. The [operator guide](docs/SERVER_GUIDE.md) covers commands and dedicated servers.

## Build on it

A nexus has one shared reserve. Mods can register their own currencies, convert raw magic into them, and spend those balances on their own effects. Pack makers can do the same with optional KubeJS scripts. Start with the [Java quick start](docs/INTEGRATION.md) or the [pack maker guide](docs/MODPACKS.md).
A nexus has one shared reserve. Mods can register their own currencies, convert raw magic into them, and spend those balances on their own effects. They can also give players personal pools and let them draw from a nexus over time. Pack makers can do the same with optional KubeJS scripts. Start with the [Java quick start](docs/INTEGRATION.md) or the [pack maker guide](docs/MODPACKS.md).

The [documentation index](docs/README.md) is also in the mod JAR at `META-INF/skysleylines/docs/README.md`.

Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ tasks.named('processResources', ProcessResources) {
tasks.named('jar', Jar) {
manifest.attributes('Specification-Title': "Sky's Ley Lines", 'Specification-Version': '2',
'Implementation-Version': project.version, 'SkysLeyLines-API-Version': '2',
'SkysLeyLines-Layout-Version': '1', 'SkysLeyLines-Save-Schema': '3',
'SkysLeyLines-Layout-Version': '1', 'SkysLeyLines-Save-Schema': '5',
'SkysLeyLines-Documentation': documentationIndex)
}
tasks.named('javadoc', Javadoc) {
Expand Down
10 changes: 8 additions & 2 deletions docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,13 @@ var returned = power.returnToRawAt(x, y, z, AETHER, 1000, plant);

Every paradigm, player, and machine shares one account per nexus. Consumers may use currencies they understand from any paradigm. Raw magic is a conversion reserve, not a directly spendable currency. There are no per-player wallets or per-currency capacities.

`raw + sum(currency units / unitsPerRaw)` is the total charge. It cannot exceed the strength-dependent nexus capacity. Conversion and return preserve this total; spending reduces it. Recovery adds raw into the remaining space at `capacity / rechargeTicks` per Overworld game tick. It works while chunks are unloaded, without wall-clock/offline recovery or a per-node tick loop. Elapsed recovery is settled before a transaction, preventing retroactive recovery into space that spending just freed.
`raw + sum(currency units / unitsPerRaw)` is the total charge. Conversion and return preserve this total; spending reduces it. A capacity reduction can leave retained energy above the new limit. Such accounts can still convert, spend, and return energy. They cannot recharge or accept deposits until there is room. Recovery adds raw into the remaining space at `capacity / rechargeTicks` per Overworld game tick. It works while chunks are unloaded, without wall-clock/offline recovery or a per-node tick loop. Elapsed recovery is settled before a transaction, preventing retroactive recovery into space that spending just freed.

`MagicAmount` is an exact nonnegative rational with `of(long)` and `fraction(long,long)` helpers. Rates must be positive. Currency balances are whole nonnegative signed-long units. Currency IDs and each reduced rate or saved raw component must fit in a 65,535-byte NBT string. Conversion must produce whole currency units. A fractional output returns `NON_INTEGRAL_OUTPUT`, and a result that exceeds a storage limit returns `OVERFLOW`. Both leave balances intact. Returning a currency unit may restore a fractional raw amount exactly.

`quoteAt` returns an immutable nexus/account snapshot or empty outside a usable nexus field. `account.raw()`, `account.total()`, and `account.currency(id)` expose exact raw, total raw-equivalent, and currency balances. Missing currency entries mean zero. `rates()` gives the saved effective world rates, including retained inactive currencies. Quotes are projections, not reservations: they create no account, emit no event, and never dirty data.

`LeyLinesApi.currencyInfo(level)` returns an immutable map of saved rates and active flags on the server thread. `NexusSnapshot.rechargeTicks()` reports the effective refill interval, including a server override. `Context.profile().rechargeTicks()` is the base interval saved when the world first initialized.
`LeyLinesApi.currencyInfo(level)` returns an immutable map of saved rates and active flags on the server thread. `NexusSnapshot.rechargeTicks()` reports the effective refill interval, including a server override. `NexusSnapshot.capacity()` and `AccountSnapshot.capacity()` report the effective limit with the server's capacity multiplier. `Context.profile()` contains the original world settings, and `Nexus.capacity(profile)` calculates the base capacity from them.

Transactions select the nearest eligible nexus, with canonical identity breaking exact-distance ties. They never split a request or fall through to another nexus when funds are insufficient. Lines alone cannot supply power; horizontal and vertical boundaries apply. Untouched nodes start fully raw.

Expand Down Expand Up @@ -104,6 +104,8 @@ Reuse a column outside candidate-height loops. `naturalStrengthAt` is allocation

For optional integration, check `ModList.get().isLoaded("skysleylines")` before loading a dedicated integration class with API references. Compile production integrations against a matching released artifact and declare a compatible optional dependency. Acquire the sampler during `LevelEvent.Load`; `ServerStartingEvent` runs after spawn preparation on this target. If the optional mod is absent, use the consumer’s ordinary generation rule. The disposable worldgen probe exercises this pattern independently of OreSpawn.

Use `nexusesInChunk(chunkX, chunkZ)` for every centre owned by a chunk, or `LeyLinesApi.worldgenSampler(randomState)` from an actual structure context. See [Worldgen and nexus pins](WORLDGEN_AND_PINS.md) for optional loading, structure placement, and authored anchors.

## Ley vision grants

Since Sky's Ley Lines 0.4, spells, potions, or equipment can grant a player the same local view as the operator command. Call on the server thread with the connected player's `ServerPlayer`.
Expand Down Expand Up @@ -136,3 +138,7 @@ Use a distinct namespaced source for each effect that should expire independentl
The server sends nearby clipped segments and crossings only to the viewer. The client uses terrain already loaded there to place the effect. The display follows the planar field, while exact vertical strength and nexus eligibility come from `LeyFieldSampler`. The visual width, water surface height, and plumes are presentation choices.

[Java integration quick start](INTEGRATION.md) · [Operator commands](SERVER_GUIDE.md) · [KubeJS bindings](MODPACKS.md)

## Player power

From 0.5.5, use `LeyLinesApi.playerPower(server)` for converted player pools and timed operations. See [Player energy pools](PLAYER_ENERGY.md) for the service, timing, transaction events, and policy overrides.
20 changes: 16 additions & 4 deletions docs/CONFIGURATION.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Configuration and world continuity

Open **Mods → Sky’s Ley Lines → Config**. **New World Defaults** edits the settings that a world copies when its ley profile is first initialized. **Server Settings** is available in a local single-player world. It lets you pick the default Ley Vision style and set a recharge override. Reopen the world to apply a new recharge interval. The screen edits the server TOML that NeoForge loaded. Worlds using the instance server config share those settings. To make edits specific to one world, place a copy of the TOML in that world’s `serverconfig` folder before opening it. For a dedicated server or a LAN host, edit the server TOML with the world closed.
Open **Mods → Sky’s Ley Lines → Config**. **New World Defaults** edits the settings that a world copies when its ley profile is first initialized. **Server Settings** is available in a local single-player world. It lets you pick the default Ley Vision style and tune nexus capacity and recharge. Reopen the world to apply capacity and recharge changes. The screen edits the server TOML that NeoForge loaded. Worlds using the instance server config share those settings. To make edits specific to one world, place a copy of the TOML in that world’s `serverconfig` folder before opening it. For a dedicated server or a LAN host, edit the server TOML with the world closed.

`config/skysleylines-common.toml` contains defaults for NEW worlds. On first server start with the mod, the complete effective profile and version identifiers are saved in `<world>/data/skysleylines.dat`. Existing worlds retain those values even when installation defaults change. `/skysleylines profile` shows the saved values.

Expand All @@ -21,12 +21,14 @@ The server config supplies these settings for new and existing worlds.
| --- | --- | --- | --- |
| `defaultVisionStyle` | `"river"` | `"river"`, `"crackle"`, `"sparkles"`, `"glow"` | Operator vision and unstyled effects use the server default. |
| `rechargeTicksOverride` | `0` | `0` or an integer from 1 through 1,728,000 | Read when the world opens. Zero uses the saved base interval. |
| `nexusCapacityMultiplier` | `0.01` | `0.0001` through `100` with up to four decimal places | Read when the world opens. `1.0` uses the original capacity. |

For example, use the following server TOML for Crackle vision and a three Minecraft day refill.

```toml
defaultVisionStyle = "crackle"
rechargeTicksOverride = 72000
nexusCapacityMultiplier = 0.01
```

## Version-one landscape
Expand All @@ -45,17 +47,27 @@ Equipped dowsing rods turn towards the closest ley line within 256 blocks while

Set `defaultVisionStyle` in `config/skysleylines-server.toml` to `"river"` (default), `"crackle"`, `"sparkles"`, or `"glow"`. For a single world, put the same file in `<world>/serverconfig/` to override the instance default. Edit the config while the world is closed. The setting applies to operator vision and unstyled grants in existing and new worlds. Styled grants can override it for the viewer while they are active. All four styles are visual overlays.

## Nexus pins

Admin pins use a restart-applied overlay. See [Worldgen and nexus pins](WORLDGEN_AND_PINS.md) for commands and retirement rules.

## Player energy policy

Player pools and timed operations have their own JSON policy layers. See [Player energy pools](PLAYER_ENERGY.md) for data pack and server files, death behavior, and the schema 4 upgrade.

## Shared accounts and recharge

Each node has one total capacity shared by raw and all currencies. The saved world profile and intrinsic nexus strength determine capacity. Converted balances occupy capacity. Spending frees space for raw recharge, and dowsing rods report total charge, including converted currencies.
Each node has one capacity shared by raw and all currencies. The saved world profile and intrinsic nexus strength determine its base capacity. `nexusCapacityMultiplier` scales that number for natural and authored nexuses. The result rounds to the nearest whole raw unit, with a minimum of 1 and a maximum of 1,000,000. At `0.01`, a nexus with a base capacity of 7,000 holds 70 raw. A child currency at 10 units per raw gets 700 units from that full pool. The default full recharge is one Minecraft day of elapsed Overworld ticks.

Converted balances occupy capacity. Spending frees space for raw recharge, and dowsing rods report total charge, including converted currencies. When the multiplier drops, the mod trims raw above the new limit after accounting for saved currencies. It preserves every converted unit, even if the account ends up above the new capacity. You can still use that energy. Recharge, deposits and retired-pin recovery into that account wait for room. Raising the multiplier preserves the current balance in stored accounts and lets recharge fill the extra space.

Set `rechargeTicksOverride` in `skysleylines-server.toml` to `0` to use the base world profile or to an integer from `1` through `1728000` for a custom full refill interval. Restart the world to apply it. Elapsed ticks settle at the previous rate. The mod backs up the prior ledger before a change. `/skysleylines profile` shows the base and effective values. For example, `72000` gives a three Minecraft day refill. Use `<world>/serverconfig/` for a world-specific override and `config/` for the instance default.

Exact raw fractions, whole currency balances, timestamps, the global account revision, and frozen world ratios are stored in `data/skysleylines.dat`. Untouched accounts are implicitly fully raw. Only full accounts with no converted funds can be pruned; fully converted accounts must remain saved. No per-node ticking or chunk loading is used.

Schema-1 worlds upgrade automatically. The loader validates first and copies the original data file to a unique `skysleylines-schema1-*.dat.bak` before any upgrade is saved. Raw balances and recharge remainders retain their exact value. Layout version 1 and the saved profile remain unchanged. Unknown versions, malformed fields, duplicate IDs, invalid ratios, and over-capacity accounts fail before Minecraft can substitute defaults.
Schema-1 worlds upgrade automatically. The loader validates first and copies the original data file to a unique `skysleylines-schema1-*.dat.bak` before any upgrade is saved. Unknown versions, malformed fields, duplicate IDs, invalid ratios, and balances above the storage limit fail before Minecraft can substitute defaults.

Worlds without a change to the effective recharge rate continue to save as schema 2. The first effective change switches to schema 3, which records the new interval and remains in use even after a reset to the base rate. Older builds refuse schema 3. A recharge change creates a `skysleylines-before-recharge-*.dat.bak` copy if the world already has a ledger.
A multiplier change uses schema 6 and keeps it after a reset to `1.0`. The first restart with `0.01` applies the reduction to existing worlds as well as new ones. To keep the original pool sizes in an existing world, set `1.0` before opening it. A multiplier change creates `skysleylines-before-capacity-*.dat.bak` when a ledger already exists. A recharge-only change creates `skysleylines-before-recharge-*.dat.bak`. Both changes settle elapsed recharge under the previous settings before saving. `/skysleylines profile` shows the effective multiplier and refill interval. The Ley Meter and `/skysleylines account` show the effective capacity at the nexus.

Child mods register currencies and rate suppliers. A world remembers each currency's effective units-per-raw ratio. Removing a child preserves its balances and occupied capacity. Inactive currencies cannot receive new conversions or ordinary spending, but their value can explicitly return to raw through the API. Reinstalling the child restores access at the saved rate.

Expand Down
8 changes: 8 additions & 0 deletions docs/DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ Run one Gradle process at a time against the shared cache. Import the inner `Sky

Validation covers deterministic boundaries/order, concurrent samplers, bounded caches/searches, saved profiles, shared currency competition, exact conversions/returns, cancelled/reentrant events, frozen rates, value-preserving migrations, unloaded recovery, fractional recharge, NBT round trips/rejection, resources, exact packaged runtimes, and visual rods feedback. Runtime receipts are separate from user gameplay acceptance. Keep failed receipts and rerun only after fixing their cause or stating the changed validation conditions.

## Structure worldgen probe

`worldgenProbeJar` builds the separate optional consumer. It registers a placement, a structure start and a saved marker piece. Use disposable worlds to check startup and exploration with Ley Lines present and absent.

For a matched benchmark, launch once with `-Dley.structure.mode=export` for each profile or pin fixture and preserve the resulting `sites.tsv`. Start fresh copies with `-Dley.structure.bench=true` and point `-Dley.structure.oracle` at that file. Use `-Dley.structure.mode=control` for the precomputed placements and `-Dley.structure.mode=both` for live queries. Use `-Dley.structure.baseline=true` with the old JAR and control mode for historical column measurements. Compare the generated `structure-starts.tsv` before comparing the timings, allocated bytes and sampled monitor counts. Keep the packaged runtime, seed, fixture, exploration chunk set and Java settings fixed.

Use `-Dley.structure.endToEndOnly=true` in both arms to time placement and generation without the synthetic column exercise and per-call counters inside the placement callback. Keep those diagnostic results alongside the full benchmark.

## Packaged documentation

Edit the public Markdown guides in `docs/` and link new pages from [the documentation index](README.md). Use relative links between bundled pages so readers can extract the directory and browse it offline. The ordinary JAR packages the guides under `META-INF/skysleylines/docs/` and advertises the index in its manifest. `verifyArtifacts` checks the packaged paths and bytes against the source guides.
Expand Down
Loading
Loading