
# Modding and behavior changes

This document briefly documents what have been added (or removed) regarding modding capabilities or engine behavior(s)

This document is non-exhaustive, engine contains way more behavior change bits than documented here,
but listing all of them will be a hassle, and will pollute actually useful changes.

---------------

## Prototypes

 * `treasurechests` now can specify `treasurePool` as array
 * `damageTable` can be defined directly, without referencing other JSON file (experimental feature)

#### Biomes
 * Tree biome placeables now have `variantsRange` (defaults to `[1, 1]`) and `subVariantsRange` (defaults to `[2, 2]`)
   * `variantsRange` is responsible for "stem-foliage" combinations
   * `subVariantsRange` is responsible for "stem-foliage" hue shift combinations
     * Rolled per each "stem-foliage" combination
     * Also two more properties were added: `sameStemHueShift` (defaults to `true`) and `sameFoliageHueShift` (defaults to `false`), which fixate hue shifts within same "stem-foliage" combination
   * Original engine always generates two tree types when processing placeable items, new engine however, allows to generate any number of trees.

#### Dungeons
 * `front` and `back` brushes now can properly accept detailed data as json object on second position (e.g. `["front", { "material": ... }]`), with following structure (previously, due to oversight in code, it was impossible to specify this structure through any means, because brush definition itself can't be an object):
```kotlin
val material: Registry.Ref<TileDefinition> = BuiltinMetaMaterials.EMPTY.ref
val modifier: Registry.Ref<TileModifierDefinition> = BuiltinMetaMaterials.EMPTY_MOD.ref
val hueShift: Float = 0f
val modHueShift: Float = 0f
val color: TileColor = TileColor.DEFAULT
```
 * `item` brush now can accept proper item descriptors (in json object tag),
   * Previous behavior remains unchanged (if specified as string, creates _randomized_ item, if as object, creates _exactly_ what have been specified)
   * To stop randomizing as Tiled tileset brush, specify `"dont_randomize"` as anything (e.g. as `""`)
 * `liquid` brush now can accept 'level' as second argument
   * Previous behavior is unchanged, `["liquid", "water", true]` will result into infinite water as before, but `["liquid", "water", 0.5, false]` will spawn half-filled water
   * In tiled, you already can do this using `"quantity"` property
 * `dungeonid` brush has been hooked up to legacy dungeons and now can be directly specified inside `"brush"` (previously they were only accessible when using Tiled' tilesets).
   * By default, they mark entire _part_ of dungeon with their ID. To mark specific tile inside dungeon with its own Dungeon ID, supply `true` as third value to brush (e.g `["dungeonid", 40000, true"]`)
   * Tiled map behavior is unchanged, and marks their position only.

#### .terrain
 * All composing terrain selectors (such as `min`, `displacement`, `rotate`, etc) now can reference other terrain selectors by name (the `.terrain` files) instead of embedding entire config inside them
   * They can be referenced by either specifying corresponding field as string, or as object like so: `{"name": "namedselector"}`
   * `min`, `max` and `minmax` terrain selectors now also accept next format: `{"name": "namedselector", "seedBias": 4}`
 * `mix` terrain selector got `mixSeedBias`, `aSeedBias` and `bSeedBias` fields, whose deviate respective selectors seeds (default to `0`)
 * `displacement` terrain selector has `seedBias` added, which deviate seed of `source` selector (default to `0`)
 * `displacement` terrain selector has `xClamp` added, works like `yClamp`
 * `rotate` terrain selector has `rotationWidth` (defaults to `0.5`) and `rotationHeight` (defaults to `0.0`) added, which are multiplied by world's size and world's height respectively to determine rotation point center
 * `min` terrain selector added, opposite of existing `max` (json format is the same as `max`)
 * `cache` terrain selector removed due it not being documented, and having little practical value
 * `perlin` terrain selector now accepts `type`, `frequency` and `amplitude` values (naming inconsistency fix)
 * `ridgeblocks` terrain selector now accepts `amplitude` and `frequency` values (naming inconsistency fix);
 * `ridgeblocks` has `octaves` added (defaults to `2`), `perlinOctaves` (defaults to `1`)

### player.config
 * Inventory bags are no longer limited to 255 slots
   * However, when joining original servers with mod which increase bag size past 255 slots will result in undefined behavior (joining servers with inventory size bag mods will already result in nearly instant desync though, so you may not ever live to see the side effects; and if original server installs said mod, original clients and original server will experience severe desyncs/undefined behavior too)

#### .item
 * `inventoryIcon` additions if specified as array:
   * `scale`, either as float or as vector (for x and y scales); both in prototype file and in `parameters`.
   * `color` (defaults to white `[255, 255, 255, 255]`)
   * `rotation` (in degrees, defaults to `0`)
   * `mirrored` (defaults to `false`, this is different from setting scale to `-1f` since it obeys center point)
   * `centered` (defaults to `true`)
   * `fullbright` (defaults to `false`)

#### .liquid
 * `liquidId` is no longer essential and can be skipped; engine **will not** assign it to anything, but liquid will still be fully functional from engine's point of view
   * However, this has serious implications:
     * Liquid will become "invisible" to legacy clients (this is not guaranteed, and if it ever "bleeds" into structures sent to legacy clients due to missed workarounds in code, legacy client will blow up.)
     * Lua scripts written solely for original engine won't see this liquid too (this includes base game assets!), unless they use new improved functions
 * `liquidId` can be specified as any number in 1 -> 2^31 - 1 range (0 is reserved for "empty" meta-liquid)
   * This will make liquid "invisible" to original clients only, Lua code should continue to function normally
     * This is not guaranteed, and if it ever "bleeds" into structures sent to legacy clients due to missed workarounds in code, legacy client will blow up.

#### .matierial
 * Meta-materials are no longer treated uniquely, and are defined as "real" materials, just like every other material, but still preserve unique interactions.
 * `materialId` is no longer essential and can be skipped, with same notes as described in `liquidId`.
 * `materialId` can be specified as any number in 1 -> 2^31 - 1 (softly excluding reserved "meta materials" ID range, since this range is not actually reserved, but is expected to be used solely by meta materials), with legacy client implications only.
 * Implemented `isConnectable`, which was planned by original developers, but scrapped in process (defaults to `true`, by default only next meta-materials have it set to false: `empty`, `null` and `boundary`)
   * Used by object and plant anchoring code to determine valid placement
   * Used by world tile rendering code (render piece rule `Connects`)
   * And finally, used by `canPlaceMaterial` to determine whenever player can place blocks next to it (at least one such tile should be present for player to be able to place blocks next to it)

#### .object
 * `breakDropOptions` and `smashDropOptions` items created now obey world's threat level
 * `smashDropPool`, `breakDropPool`, `breakDropOptions` and `smashDropOptions` are now deterministic (see [worldgen section](#Deterministic_world_generation))

#### .matmod
 * `modId` is no longer essential and can be skipped, or specified as any number in 1 -> 2^31 range, with notes of `materialId` and `liquidId` apply.

---------------

## Scripting

#### Random
 * Added `random:randn(deviation: double, mean: double): double`, returns normally distributed double, where `deviation` stands for [Standard deviation](https://en.wikipedia.org/wiki/Standard_deviation), and `mean` specifies middle point
 * Removed `random:addEntropy`

#### animator

 * Added `animator.targetRotationAngle(rotationGroup: string): double`
 * Added `animator.hasRotationGroup(rotationGroup: string): boolean`
 * Added `animator.rotationGroups(): List<string>` (returns valid names for `rotateGroup`, `currentRotationAngle` and `targetRotationAngle`)
 * Added `animator.transformationGroups(): List<string>`
 * Added `animator.particleEmitters(): List<string>`
 * Added `animator.hasParticleEmitter(emitter: string): boolean`
 * Added `animator.lights(): List<string>`
 * Added `animator.hasLight(light: string): boolean`
 * Added `animator.sounds(): List<string>`
 * Added `animator.effects(): List<string>`
 * Added `animator.hasEffect(effect: string): boolean`
 * Added `animator.parts(): List<string>`

#### world

 * Added `world.liquidNamesAlongLine(start: Vector2d, end: Vector2d): List<LiquidState>`, will return Liquid' name instead of its ID
 * Added `world.liquidNameAt(at: Vector2i): LiquidState?`, will return Liquid' name instead of its ID
 * Added `world.biomeBlockNamesAt(at: Vector2i): List<String>?`, will return Block names instead of their IDs
 * Added `world.destroyNamedLiquid(at: Vector2i): LiquidState?`, will return Liquid' name instead of its ID
 * Added `world.gravityVector(at: Vector2d): Vector2d`. **Attention:** directional gravity is WIP.
 * Added `world.itemDropLineQuery(p0: Vector2d, p1: Vector2d, options: Table?): List<EntityID>`
 * Added `world.playerLineQuery(p0: Vector2d, p1: Vector2d, options: Table?): List<EntityID>`
 * Added `world.objectLineQuery(p0: Vector2d, p1: Vector2d, options: Table?): List<EntityID>`
 * Added `world.loungeableLineQuery(p0: Vector2d, p1: Vector2d, options: Table?): List<EntityID>`
 * `world.entityCanDamage(source: EntityID, target: EntityID): Boolean` now properly accounts for case when `source == target`

---------------

## Deterministic world generation

In new engine, entirety of world generation is made deterministic. What this means that given one world seed, engine will
generate _exactly the same_ world each time it is requested to generate one (given prototype definitions which influence
world generation are the same between generations).

To put it simply, when you visit a planet on your friend's server, it is _guaranteed_ that in your singleplayer
or on other server, given same set of mods installed (and both players are using new engine server or new engine client),
you will get exactly the same planet as you saw before.

This includes, but not limited to:
 * Containers (such as chests)
 * Smashable objects (e.g. capsules, rocks)
 * `random` dungeon brush
 * Tree types / placement
 * Grass / bush variants and placement
 * Dungeon placement
 * Initial player spawn position in world
 * Microdungeon placement

However, this also means that instance worlds will generate 1:1 each time they are requested if
there is `seed` specified for such world `/instance_worlds.config`. And since vanilla dungeons have it specified
(and mod makers don't question "why" it is there), all mission dungeons will be generated 1:1 each time.

If you are mod creator, **PLEASE** update your mod(s), and remove `seed` from your dungeon worlds!
Both new and old engines will provide random seed for you if you don't specify one inside `/instance_worlds.config`.

---------------

## Behavior

### universe_server.config
 * Added `useNewWireProcessing`, which defaults to `true`
   * New wire updating system is insanely fast (because wiring is updated along entity ticking, and doesn't involve intense entity map lookups)
   * However, it is not a complete replacement for legacy system, because some mods might rely on fact that in legacy system when wired entities update, they load all other endpoints into memory (basically, chunkload all connected entities). In new system if wired entity references unloaded entities it simply does not update its state.
   * If specified as `false`, original behavior will be restored, but beware of performance degradation! If you are a modder, **PLEASE** consider other ways around instead of enabling the old behavior, because performance cost of using old system is almost always gonna outweight "benefits" of chunkloaded wiring systems.

#### Plant drop entities (vines or steps dropping on ground)
 * Collision is now determined using hull instead of rectangle
