Deterministic dungeon containers
This commit is contained in:
parent
7857b8821e
commit
fc6938fc35
18
ADDITIONS.md
18
ADDITIONS.md
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
# Modding changes
|
# Modding and behavior changes
|
||||||
|
|
||||||
This document briefly documents what have been added (or removed) regarding modding capabilities
|
This document briefly documents what have been added (or removed) regarding modding capabilities or engine behavior(s)
|
||||||
|
|
||||||
## JSON additions
|
## JSON additions
|
||||||
|
|
||||||
@ -35,7 +35,6 @@ This document briefly documents what have been added (or removed) regarding modd
|
|||||||
* Original engine always generates two tree types when processing placeable items, new engine however, allows to generate any number of trees.
|
* Original engine always generates two tree types when processing placeable items, new engine however, allows to generate any number of trees.
|
||||||
|
|
||||||
#### Dungeons
|
#### Dungeons
|
||||||
* All brushes are now deterministic, and will produce _exact_ results given same seed (this fixes dungeons being generated differently on each machine despite players visiting exactly same coordinates in universe)
|
|
||||||
* `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):
|
* `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
|
```kotlin
|
||||||
val material: Registry.Ref<TileDefinition> = BuiltinMetaMaterials.EMPTY.ref
|
val material: Registry.Ref<TileDefinition> = BuiltinMetaMaterials.EMPTY.ref
|
||||||
@ -101,4 +100,15 @@ val color: TileColor = TileColor.DEFAULT
|
|||||||
* Added `animator.sounds(): List<string>`
|
* Added `animator.sounds(): List<string>`
|
||||||
* Added `animator.effects(): List<string>`
|
* Added `animator.effects(): List<string>`
|
||||||
* Added `animator.hasEffect(effect: string): boolean`
|
* Added `animator.hasEffect(effect: string): boolean`
|
||||||
* Added `animator.parts(): List<string>`
|
* Added `animator.parts(): List<string>`
|
||||||
|
|
||||||
|
## Behavior
|
||||||
|
|
||||||
|
---------------
|
||||||
|
|
||||||
|
### Worldgen
|
||||||
|
* Major dungeon placement on planets is now deterministic
|
||||||
|
* Container item population in dungeons is now deterministic and is based on dungeon seed
|
||||||
|
|
||||||
|
#### Dungeons
|
||||||
|
* All brushes are now deterministic
|
||||||
|
@ -484,7 +484,7 @@ class DungeonWorld(val parent: ServerWorld, val random: RandomGenerator, val mar
|
|||||||
|
|
||||||
val placedObjects = placedObjects.entries
|
val placedObjects = placedObjects.entries
|
||||||
.map { (pos, data) ->
|
.map { (pos, data) ->
|
||||||
WorldObject.create(data.prototype, pos, data.parameters) to data.direction
|
WorldObject.create(data.prototype, pos, data.parameters).also { it?.randomize(random) } to data.direction
|
||||||
}
|
}
|
||||||
.filter { it.first != null }
|
.filter { it.first != null }
|
||||||
|
|
||||||
|
@ -35,6 +35,7 @@ import ru.dbotthepony.kstarbound.world.World
|
|||||||
import ru.dbotthepony.kstarbound.world.entities.ItemDropEntity
|
import ru.dbotthepony.kstarbound.world.entities.ItemDropEntity
|
||||||
import java.io.DataInputStream
|
import java.io.DataInputStream
|
||||||
import java.io.DataOutputStream
|
import java.io.DataOutputStream
|
||||||
|
import java.util.random.RandomGenerator
|
||||||
|
|
||||||
class ContainerObject(config: Registry.Entry<ObjectDefinition>) : WorldObject(config) {
|
class ContainerObject(config: Registry.Entry<ObjectDefinition>) : WorldObject(config) {
|
||||||
var opened by networkedSignedInt().also { networkGroup.upstream.add(it) }
|
var opened by networkedSignedInt().also { networkGroup.upstream.add(it) }
|
||||||
@ -109,6 +110,45 @@ class ContainerObject(config: Registry.Entry<ObjectDefinition>) : WorldObject(co
|
|||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun randomizeContents(random: RandomGenerator) {
|
||||||
|
var level = world.template.threatLevel
|
||||||
|
level = lookupProperty("level") { JsonPrimitive(level) }.asDouble
|
||||||
|
level += lookupProperty("levelAdjustment") { JsonPrimitive(0.0) }.asDouble
|
||||||
|
|
||||||
|
val initialItems = lookupProperty("initialItems")
|
||||||
|
|
||||||
|
if (!initialItems.isJsonNull) {
|
||||||
|
for (item in initialItems.asJsonArray) {
|
||||||
|
items.add(ItemDescriptor(item).build(level, random.nextLong(), random))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val treasurePools = lookupProperty("treasurePools")
|
||||||
|
|
||||||
|
if (!treasurePools.isJsonNull) {
|
||||||
|
val get = treasurePools.asJsonArray.random(random).asString
|
||||||
|
val treasurePool = Registries.treasurePools[get]
|
||||||
|
|
||||||
|
if (treasurePool == null) {
|
||||||
|
LOGGER.error("Unknown treasure pool $get! Can't generate container contents at $tilePosition.")
|
||||||
|
} else {
|
||||||
|
for (item in treasurePool.value.evaluate(random, level)) {
|
||||||
|
val leftover = items.add(item)
|
||||||
|
|
||||||
|
if (leftover.isNotEmpty) {
|
||||||
|
LOGGER.warn("Tried to overfill container at $tilePosition")
|
||||||
|
lostItems.add(leftover)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun randomize(random: RandomGenerator) {
|
||||||
|
super.randomize(random)
|
||||||
|
randomizeContents(random)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onJoinWorld(world: World<*, *>) {
|
override fun onJoinWorld(world: World<*, *>) {
|
||||||
if (!isRemote)
|
if (!isRemote)
|
||||||
isInteractive = true
|
isInteractive = true
|
||||||
@ -119,38 +159,12 @@ class ContainerObject(config: Registry.Entry<ObjectDefinition>) : WorldObject(co
|
|||||||
if (isInitialized) return
|
if (isInitialized) return
|
||||||
isInitialized = true
|
isInitialized = true
|
||||||
|
|
||||||
var level = world.template.threatLevel
|
val seed = lookupProperty("treasureSeed")
|
||||||
val seed = lookupProperty("treasureSeed") { JsonPrimitive(world.random.nextLong()) }.asLong
|
|
||||||
level = lookupProperty("level") { JsonPrimitive(level) }.asDouble
|
|
||||||
level += lookupProperty("levelAdjustment") { JsonPrimitive(0.0) }.asDouble
|
|
||||||
|
|
||||||
val initialItems = lookupProperty("initialItems")
|
if (seed.isJsonNull) {
|
||||||
|
randomizeContents(world.random)
|
||||||
if (!initialItems.isJsonNull) {
|
} else {
|
||||||
for (item in initialItems.asJsonArray) {
|
randomizeContents(random(seed.asLong))
|
||||||
items.add(ItemDescriptor(item).build(level, seed))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val treasurePools = lookupProperty("treasurePools")
|
|
||||||
|
|
||||||
if (!treasurePools.isJsonNull) {
|
|
||||||
val random = random(seed)
|
|
||||||
val get = treasurePools.asJsonArray.random(random).asString
|
|
||||||
val treasurePool = Registries.treasurePools[get]
|
|
||||||
|
|
||||||
if (treasurePool == null) {
|
|
||||||
LOGGER.error("Unknown treasure pool $get! Can't generate container contents at $tilePosition.")
|
|
||||||
} else {
|
|
||||||
for (item in treasurePool.value.evaluate(random, level)) {
|
|
||||||
val leftover = items.add(item)
|
|
||||||
|
|
||||||
if (leftover.isNotEmpty) {
|
|
||||||
LOGGER.warn("Tried to overfill container at $tilePosition")
|
|
||||||
lostItems.add(leftover)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,6 +86,7 @@ import ru.dbotthepony.kstarbound.world.entities.Animator
|
|||||||
import ru.dbotthepony.kstarbound.world.entities.wire.WireConnection
|
import ru.dbotthepony.kstarbound.world.entities.wire.WireConnection
|
||||||
import java.io.DataOutputStream
|
import java.io.DataOutputStream
|
||||||
import java.util.HashMap
|
import java.util.HashMap
|
||||||
|
import java.util.random.RandomGenerator
|
||||||
|
|
||||||
open class WorldObject(val config: Registry.Entry<ObjectDefinition>) : TileEntity() {
|
open class WorldObject(val config: Registry.Entry<ObjectDefinition>) : TileEntity() {
|
||||||
open fun deserialize(data: JsonObject) {
|
open fun deserialize(data: JsonObject) {
|
||||||
@ -134,6 +135,13 @@ open class WorldObject(val config: Registry.Entry<ObjectDefinition>) : TileEntit
|
|||||||
return into
|
return into
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* called by DungeonWorld to deterministically randomize parameters
|
||||||
|
*/
|
||||||
|
open fun randomize(random: RandomGenerator) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
protected val orientationLazies = ArrayList<ManualLazy<*>>()
|
protected val orientationLazies = ArrayList<ManualLazy<*>>()
|
||||||
protected val parametersLazies = ArrayList<ManualLazy<*>>()
|
protected val parametersLazies = ArrayList<ManualLazy<*>>()
|
||||||
protected val spacesLazies = ArrayList<ManualLazy<*>>()
|
protected val spacesLazies = ArrayList<ManualLazy<*>>()
|
||||||
|
Loading…
Reference in New Issue
Block a user