mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-14 07:36:06 +09:00
tile damage and wire layers are now save/loaded
This commit is contained in:
@@ -2,7 +2,6 @@ package net.torvald.terrarum
|
|||||||
|
|
||||||
import com.badlogic.gdx.Screen
|
import com.badlogic.gdx.Screen
|
||||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||||
import com.badlogic.gdx.utils.Queue
|
|
||||||
import net.torvald.terrarum.AppLoader.printdbg
|
import net.torvald.terrarum.AppLoader.printdbg
|
||||||
import net.torvald.terrarum.gameactors.Actor
|
import net.torvald.terrarum.gameactors.Actor
|
||||||
import net.torvald.terrarum.gameactors.BlockMarkerActor
|
import net.torvald.terrarum.gameactors.BlockMarkerActor
|
||||||
@@ -10,7 +9,6 @@ import net.torvald.terrarum.gameitem.ItemID
|
|||||||
import net.torvald.terrarum.gameworld.GameWorld
|
import net.torvald.terrarum.gameworld.GameWorld
|
||||||
import net.torvald.terrarum.modulebasegame.IngameRenderer
|
import net.torvald.terrarum.modulebasegame.IngameRenderer
|
||||||
import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid
|
import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid
|
||||||
import net.torvald.terrarum.realestate.LandUtil
|
|
||||||
import net.torvald.terrarum.ui.ConsoleWindow
|
import net.torvald.terrarum.ui.ConsoleWindow
|
||||||
import net.torvald.util.SortedArrayList
|
import net.torvald.util.SortedArrayList
|
||||||
import java.util.concurrent.locks.Lock
|
import java.util.concurrent.locks.Lock
|
||||||
@@ -31,6 +29,8 @@ open class IngameInstance(val batch: SpriteBatch) : Screen {
|
|||||||
val consoleOpened: Boolean
|
val consoleOpened: Boolean
|
||||||
get() = consoleHandler.isOpened || consoleHandler.isOpening
|
get() = consoleHandler.isOpened || consoleHandler.isOpening
|
||||||
|
|
||||||
|
var newWorldLoadedLatch = false
|
||||||
|
|
||||||
init {
|
init {
|
||||||
consoleHandler.setPosition(0, 0)
|
consoleHandler.setPosition(0, 0)
|
||||||
|
|
||||||
@@ -40,6 +40,7 @@ open class IngameInstance(val batch: SpriteBatch) : Screen {
|
|||||||
|
|
||||||
open var world: GameWorld = GameWorld.makeNullWorld()
|
open var world: GameWorld = GameWorld.makeNullWorld()
|
||||||
set(value) {
|
set(value) {
|
||||||
|
newWorldLoadedLatch = true
|
||||||
printdbg(this, "Ingame instance ${this.hashCode()}, accepting new world ${value.layerTerrain}; called from")
|
printdbg(this, "Ingame instance ${this.hashCode()}, accepting new world ${value.layerTerrain}; called from")
|
||||||
printStackTrace(this)
|
printStackTrace(this)
|
||||||
field = value
|
field = value
|
||||||
|
|||||||
@@ -483,17 +483,17 @@ fun MutableList<Any>.shuffle() {
|
|||||||
|
|
||||||
|
|
||||||
val ccW = GameFontBase.toColorCode(0xFFFF)
|
val ccW = GameFontBase.toColorCode(0xFFFF)
|
||||||
val ccY = GameFontBase.toColorCode(0xFE8F)
|
val ccY = GameFontBase.toColorCode(0xFFE8)
|
||||||
val ccO = GameFontBase.toColorCode(0xFB2F)
|
val ccO = GameFontBase.toColorCode(0xFFB2)
|
||||||
val ccR = GameFontBase.toColorCode(0xF88F)
|
val ccR = GameFontBase.toColorCode(0xFF88)
|
||||||
val ccF = GameFontBase.toColorCode(0xFAEF)
|
val ccF = GameFontBase.toColorCode(0xFFAE)
|
||||||
val ccM = GameFontBase.toColorCode(0xEAFF)
|
val ccM = GameFontBase.toColorCode(0xFEAF)
|
||||||
val ccB = GameFontBase.toColorCode(0x88FF)
|
val ccB = GameFontBase.toColorCode(0xF88F)
|
||||||
val ccC = GameFontBase.toColorCode(0x8FFF)
|
val ccC = GameFontBase.toColorCode(0xF8FF)
|
||||||
val ccG = GameFontBase.toColorCode(0x8F8F)
|
val ccG = GameFontBase.toColorCode(0xF8F8)
|
||||||
val ccV = GameFontBase.toColorCode(0x080F)
|
val ccV = GameFontBase.toColorCode(0xF080)
|
||||||
val ccX = GameFontBase.toColorCode(0x853F)
|
val ccX = GameFontBase.toColorCode(0xF853)
|
||||||
val ccK = GameFontBase.toColorCode(0x888F)
|
val ccK = GameFontBase.toColorCode(0xF888)
|
||||||
|
|
||||||
|
|
||||||
typealias Second = Float
|
typealias Second = Float
|
||||||
|
|||||||
@@ -63,7 +63,8 @@ object CommandDict {
|
|||||||
/* !! */"exportworld" to ExportWorld,
|
/* !! */"exportworld" to ExportWorld,
|
||||||
/* !! */"exportactor" to ExportActor,
|
/* !! */"exportactor" to ExportActor,
|
||||||
/* !! */"importworld" to ImportWorld,
|
/* !! */"importworld" to ImportWorld,
|
||||||
/* !! */"exportfborgb" to ExportRendererFboRGB
|
/* !! */"exportfborgb" to ExportRendererFboRGB,
|
||||||
|
/* !! */"printworld" to PrintWorld
|
||||||
)
|
)
|
||||||
|
|
||||||
operator fun get(commandName: String): ConsoleCommand {
|
operator fun get(commandName: String): ConsoleCommand {
|
||||||
|
|||||||
@@ -92,12 +92,6 @@ class IngameController(val terrarumIngame: TerrarumIngame) : InputAdapter() {
|
|||||||
tKeyUp(key)
|
tKeyUp(key)
|
||||||
|
|
||||||
keyStatus[key] = keyDown
|
keyStatus[key] = keyDown
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (key == Input.Keys.ENTER && keyDown) {
|
|
||||||
printdbg(this, "ENTER down")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// control mouse/touch events
|
// control mouse/touch events
|
||||||
val newmx = Gdx.input.x
|
val newmx = Gdx.input.x
|
||||||
|
|||||||
@@ -3,10 +3,8 @@ package net.torvald.terrarum.gameworld
|
|||||||
|
|
||||||
import com.badlogic.gdx.utils.Disposable
|
import com.badlogic.gdx.utils.Disposable
|
||||||
import com.badlogic.gdx.utils.Json
|
import com.badlogic.gdx.utils.Json
|
||||||
import com.badlogic.gdx.utils.JsonValue
|
|
||||||
import com.badlogic.gdx.utils.JsonWriter
|
import com.badlogic.gdx.utils.JsonWriter
|
||||||
import com.badlogic.gdx.utils.compression.Lzma
|
import com.badlogic.gdx.utils.compression.Lzma
|
||||||
import net.torvald.UnsafePtr
|
|
||||||
import net.torvald.UnsafePtrInputStream
|
import net.torvald.UnsafePtrInputStream
|
||||||
import net.torvald.gdx.graphics.Cvec
|
import net.torvald.gdx.graphics.Cvec
|
||||||
import net.torvald.terrarum.*
|
import net.torvald.terrarum.*
|
||||||
@@ -19,16 +17,13 @@ import net.torvald.terrarum.gameitem.ItemID
|
|||||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.ByteArray64GrowableOutputStream
|
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.ByteArray64GrowableOutputStream
|
||||||
import net.torvald.terrarum.realestate.LandUtil
|
import net.torvald.terrarum.realestate.LandUtil
|
||||||
import net.torvald.terrarum.serialise.Ascii85
|
import net.torvald.terrarum.serialise.Ascii85
|
||||||
import net.torvald.terrarum.serialise.bytesToLzmadStr
|
|
||||||
import net.torvald.terrarum.serialise.bytesToZipdStr
|
import net.torvald.terrarum.serialise.bytesToZipdStr
|
||||||
|
import net.torvald.terrarum.utils.*
|
||||||
import net.torvald.util.SortedArrayList
|
import net.torvald.util.SortedArrayList
|
||||||
import org.apache.commons.codec.digest.DigestUtils
|
import org.apache.commons.codec.digest.DigestUtils
|
||||||
import org.dyn4j.geometry.Vector2
|
import org.dyn4j.geometry.Vector2
|
||||||
import java.util.zip.GZIPOutputStream
|
import java.util.zip.GZIPOutputStream
|
||||||
import kotlin.experimental.and
|
|
||||||
import kotlin.experimental.or
|
|
||||||
import kotlin.math.absoluteValue
|
import kotlin.math.absoluteValue
|
||||||
import kotlin.math.sign
|
|
||||||
|
|
||||||
typealias BlockAddress = Long
|
typealias BlockAddress = Long
|
||||||
|
|
||||||
@@ -71,24 +66,24 @@ class GameWorld : Disposable {
|
|||||||
/** Tilewise spawn point */
|
/** Tilewise spawn point */
|
||||||
var spawnY: Int
|
var spawnY: Int
|
||||||
|
|
||||||
val wallDamages = HashMap<BlockAddress, Float>()
|
val wallDamages = HashArray<Float>()
|
||||||
val terrainDamages = HashMap<BlockAddress, Float>()
|
val terrainDamages = HashArray<Float>()
|
||||||
val fluidTypes = HashMap<BlockAddress, FluidType>()
|
val fluidTypes = HashedFluidType()
|
||||||
val fluidFills = HashMap<BlockAddress, Float>()
|
val fluidFills = HashArray<Float>()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Single block can have multiple conduits, different types of conduits are stored separately.
|
* Single block can have multiple conduits, different types of conduits are stored separately.
|
||||||
*/
|
*/
|
||||||
private val wirings = HashMap<BlockAddress, WiringNode>()
|
public val wirings = HashedWirings()
|
||||||
|
|
||||||
private val wiringGraph = HashMap<BlockAddress, HashMap<ItemID, WiringSimCell>>()
|
private val wiringGraph = HashedWiringGraph()
|
||||||
@Transient private val WIRE_POS_MAP = intArrayOf(1,2,4,8)
|
@Transient private val WIRE_POS_MAP = intArrayOf(1,2,4,8)
|
||||||
@Transient private val WIRE_ANTIPOS_MAP = intArrayOf(4,8,1,2)
|
@Transient private val WIRE_ANTIPOS_MAP = intArrayOf(4,8,1,2)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used by the renderer. When wirings are updated, `wirings` and this properties must be synchronised.
|
* Used by the renderer. When wirings are updated, `wirings` and this properties must be synchronised.
|
||||||
*/
|
*/
|
||||||
//private val wiringBlocks: HashMap<BlockAddress, ItemID>
|
//private val wiringBlocks: HashArray<ItemID>
|
||||||
|
|
||||||
//public World physWorld = new World( new Vec2(0, -Terrarum.game.gravitationalAccel) );
|
//public World physWorld = new World( new Vec2(0, -Terrarum.game.gravitationalAccel) );
|
||||||
//physics
|
//physics
|
||||||
@@ -111,7 +106,7 @@ class GameWorld : Disposable {
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
val tileNumberToNameMap = HashMap<Int, ItemID>()
|
val tileNumberToNameMap = HashArray<ItemID>()
|
||||||
// does not go to the savefile
|
// does not go to the savefile
|
||||||
@Transient val tileNameToNumberMap = HashMap<ItemID, Int>()
|
@Transient val tileNameToNumberMap = HashMap<ItemID, Int>()
|
||||||
|
|
||||||
@@ -163,7 +158,7 @@ class GameWorld : Disposable {
|
|||||||
AppLoader.tileMaker.tags.forEach {
|
AppLoader.tileMaker.tags.forEach {
|
||||||
printdbg(this, "tileNumber ${it.value.tileNumber} <-> tileName ${it.key}")
|
printdbg(this, "tileNumber ${it.value.tileNumber} <-> tileName ${it.key}")
|
||||||
|
|
||||||
tileNumberToNameMap[it.value.tileNumber] = it.key
|
tileNumberToNameMap[it.value.tileNumber.toLong()] = it.key
|
||||||
tileNameToNumberMap[it.key] = it.value.tileNumber
|
tileNameToNumberMap[it.key] = it.value.tileNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,7 +214,7 @@ class GameWorld : Disposable {
|
|||||||
val (x, y) = coerceXY(rawX, rawY)
|
val (x, y) = coerceXY(rawX, rawY)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return tileNumberToNameMap[layerWall.unsafeGetTile(x, y)]!!
|
return tileNumberToNameMap[layerWall.unsafeGetTile(x, y).toLong()]!!
|
||||||
}
|
}
|
||||||
catch (e: NullPointerException) {
|
catch (e: NullPointerException) {
|
||||||
val msg = "No tile name mapping for wall ${layerWall.unsafeGetTile(x, y)} in ($x, $y)"
|
val msg = "No tile name mapping for wall ${layerWall.unsafeGetTile(x, y)} in ($x, $y)"
|
||||||
@@ -234,7 +229,7 @@ class GameWorld : Disposable {
|
|||||||
val (x, y) = coerceXY(rawX, rawY)
|
val (x, y) = coerceXY(rawX, rawY)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return tileNumberToNameMap[layerTerrain.unsafeGetTile(x, y)]!!
|
return tileNumberToNameMap[layerTerrain.unsafeGetTile(x, y).toLong()]!!
|
||||||
}
|
}
|
||||||
catch (e: NullPointerException) {
|
catch (e: NullPointerException) {
|
||||||
val msg = "No tile name mapping for terrain ${layerTerrain.unsafeGetTile(x, y)} in ($x, $y)"
|
val msg = "No tile name mapping for terrain ${layerTerrain.unsafeGetTile(x, y)} in ($x, $y)"
|
||||||
@@ -317,10 +312,10 @@ class GameWorld : Disposable {
|
|||||||
val wireNode = wirings[blockAddr]
|
val wireNode = wirings[blockAddr]
|
||||||
|
|
||||||
if (wireNode == null) {
|
if (wireNode == null) {
|
||||||
wirings[blockAddr] = WiringNode(blockAddr, SortedArrayList())
|
wirings[blockAddr] = WiringNode(SortedArrayList())
|
||||||
}
|
}
|
||||||
|
|
||||||
wirings[blockAddr]!!.wires.add(tile)
|
wirings[blockAddr]!!.ws.add(tile)
|
||||||
|
|
||||||
if (!bypassEvent)
|
if (!bypassEvent)
|
||||||
Terrarum.ingame?.queueWireChangedEvent(tile, false, x, y)
|
Terrarum.ingame?.queueWireChangedEvent(tile, false, x, y)
|
||||||
@@ -349,7 +344,7 @@ class GameWorld : Disposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getWireGraphUnsafe(blockAddr: BlockAddress, itemID: ItemID): Int? {
|
fun getWireGraphUnsafe(blockAddr: BlockAddress, itemID: ItemID): Int? {
|
||||||
return wiringGraph[blockAddr]?.get(itemID)?.connections
|
return wiringGraph[blockAddr]?.get(itemID)?.cnx
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getWireEmitStateOf(x: Int, y: Int, itemID: ItemID): Vector2? {
|
fun getWireEmitStateOf(x: Int, y: Int, itemID: ItemID): Vector2? {
|
||||||
@@ -359,7 +354,7 @@ class GameWorld : Disposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getWireEmitStateUnsafe(blockAddr: BlockAddress, itemID: ItemID): Vector2? {
|
fun getWireEmitStateUnsafe(blockAddr: BlockAddress, itemID: ItemID): Vector2? {
|
||||||
return wiringGraph[blockAddr]?.get(itemID)?.emitState
|
return wiringGraph[blockAddr]?.get(itemID)?.emt
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getWireRecvStateOf(x: Int, y: Int, itemID: ItemID): ArrayList<WireRecvState>? {
|
fun getWireRecvStateOf(x: Int, y: Int, itemID: ItemID): ArrayList<WireRecvState>? {
|
||||||
@@ -369,7 +364,7 @@ class GameWorld : Disposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getWireRecvStateUnsafe(blockAddr: BlockAddress, itemID: ItemID): ArrayList<WireRecvState>? {
|
fun getWireRecvStateUnsafe(blockAddr: BlockAddress, itemID: ItemID): ArrayList<WireRecvState>? {
|
||||||
return wiringGraph[blockAddr]?.get(itemID)?.recvStates
|
return wiringGraph[blockAddr]?.get(itemID)?.rcv
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setWireGraphOf(x: Int, y: Int, itemID: ItemID, cnx: Int) {
|
fun setWireGraphOf(x: Int, y: Int, itemID: ItemID, cnx: Int) {
|
||||||
@@ -380,11 +375,11 @@ class GameWorld : Disposable {
|
|||||||
|
|
||||||
fun setWireGraphOfUnsafe(blockAddr: BlockAddress, itemID: ItemID, cnx: Int) {
|
fun setWireGraphOfUnsafe(blockAddr: BlockAddress, itemID: ItemID, cnx: Int) {
|
||||||
if (wiringGraph[blockAddr] == null)
|
if (wiringGraph[blockAddr] == null)
|
||||||
wiringGraph[blockAddr] = HashMap()
|
wiringGraph[blockAddr] = WiringGraphMap()
|
||||||
if (wiringGraph[blockAddr]!![itemID] == null)
|
if (wiringGraph[blockAddr]!![itemID] == null)
|
||||||
wiringGraph[blockAddr]!![itemID] = WiringSimCell(cnx)
|
wiringGraph[blockAddr]!![itemID] = WiringSimCell(cnx)
|
||||||
|
|
||||||
wiringGraph[blockAddr]!![itemID]!!.connections = cnx
|
wiringGraph[blockAddr]!![itemID]!!.cnx = cnx
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setWireEmitStateOf(x: Int, y: Int, itemID: ItemID, vector: Vector2) {
|
fun setWireEmitStateOf(x: Int, y: Int, itemID: ItemID, vector: Vector2) {
|
||||||
@@ -395,11 +390,11 @@ class GameWorld : Disposable {
|
|||||||
|
|
||||||
fun setWireEmitStateOfUnsafe(blockAddr: BlockAddress, itemID: ItemID, vector: Vector2) {
|
fun setWireEmitStateOfUnsafe(blockAddr: BlockAddress, itemID: ItemID, vector: Vector2) {
|
||||||
if (wiringGraph[blockAddr] == null)
|
if (wiringGraph[blockAddr] == null)
|
||||||
wiringGraph[blockAddr] = HashMap()
|
wiringGraph[blockAddr] = WiringGraphMap()
|
||||||
if (wiringGraph[blockAddr]!![itemID] == null)
|
if (wiringGraph[blockAddr]!![itemID] == null)
|
||||||
wiringGraph[blockAddr]!![itemID] = WiringSimCell(0, vector)
|
wiringGraph[blockAddr]!![itemID] = WiringSimCell(0, vector)
|
||||||
|
|
||||||
wiringGraph[blockAddr]!![itemID]!!.emitState = vector
|
wiringGraph[blockAddr]!![itemID]!!.emt = vector
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addWireRecvStateOf(x: Int, y: Int, itemID: ItemID, state: WireRecvState) {
|
fun addWireRecvStateOf(x: Int, y: Int, itemID: ItemID, state: WireRecvState) {
|
||||||
@@ -416,11 +411,11 @@ class GameWorld : Disposable {
|
|||||||
|
|
||||||
fun addWireRecvStateOfUnsafe(blockAddr: BlockAddress, itemID: ItemID, state: WireRecvState) {
|
fun addWireRecvStateOfUnsafe(blockAddr: BlockAddress, itemID: ItemID, state: WireRecvState) {
|
||||||
if (wiringGraph[blockAddr] == null)
|
if (wiringGraph[blockAddr] == null)
|
||||||
wiringGraph[blockAddr] = HashMap()
|
wiringGraph[blockAddr] = WiringGraphMap()
|
||||||
if (wiringGraph[blockAddr]!![itemID] == null)
|
if (wiringGraph[blockAddr]!![itemID] == null)
|
||||||
wiringGraph[blockAddr]!![itemID] = WiringSimCell(0)
|
wiringGraph[blockAddr]!![itemID] = WiringSimCell(0)
|
||||||
|
|
||||||
wiringGraph[blockAddr]!![itemID]!!.recvStates.add(state)
|
wiringGraph[blockAddr]!![itemID]!!.rcv.add(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getAllWiringGraph(x: Int, y: Int): HashMap<ItemID, WiringSimCell>? {
|
fun getAllWiringGraph(x: Int, y: Int): HashMap<ItemID, WiringSimCell>? {
|
||||||
@@ -435,7 +430,7 @@ class GameWorld : Disposable {
|
|||||||
|
|
||||||
fun clearAllWireRecvStateUnsafe(blockAddr: BlockAddress) {
|
fun clearAllWireRecvStateUnsafe(blockAddr: BlockAddress) {
|
||||||
wiringGraph[blockAddr]?.forEach {
|
wiringGraph[blockAddr]?.forEach {
|
||||||
it.value.recvStates.clear()
|
it.value.rcv.clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -446,7 +441,7 @@ class GameWorld : Disposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getAllWiresFrom(blockAddr: BlockAddress): SortedArrayList<ItemID>? {
|
fun getAllWiresFrom(blockAddr: BlockAddress): SortedArrayList<ItemID>? {
|
||||||
return wirings[blockAddr]?.wires
|
return wirings[blockAddr]?.ws
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getTileFrom(mode: Int, x: Int, y: Int): ItemID {
|
fun getTileFrom(mode: Int, x: Int, y: Int): ItemID {
|
||||||
@@ -624,13 +619,8 @@ class GameWorld : Disposable {
|
|||||||
* If the wire does not allow them (e.g. wire bridge, thicknet), connect top-bottom and left-right nodes.
|
* If the wire does not allow them (e.g. wire bridge, thicknet), connect top-bottom and left-right nodes.
|
||||||
*/
|
*/
|
||||||
data class WiringNode(
|
data class WiringNode(
|
||||||
val position: BlockAddress = -1, // may seem redundant and it kinda is, but don't remove!
|
val ws: SortedArrayList<ItemID> = SortedArrayList<ItemID>() // what could possibly go wrong bloating up the RAM footprint when it's practically infinite these days?
|
||||||
val wires: SortedArrayList<ItemID> = SortedArrayList<ItemID>() // what could possibly go wrong bloating up the RAM footprint when it's practically infinite these days?
|
)
|
||||||
) : Comparable<WiringNode> {
|
|
||||||
override fun compareTo(other: WiringNode): Int {
|
|
||||||
return (this.position - other.position).sign
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data class WireRecvState(
|
data class WireRecvState(
|
||||||
var dist: Int = -1, // how many tiles it took to traverse
|
var dist: Int = -1, // how many tiles it took to traverse
|
||||||
@@ -642,9 +632,9 @@ class GameWorld : Disposable {
|
|||||||
* These values must be updated by none other than [WorldSimulator]()
|
* These values must be updated by none other than [WorldSimulator]()
|
||||||
*/
|
*/
|
||||||
data class WiringSimCell(
|
data class WiringSimCell(
|
||||||
var connections: Int = 0, // connections
|
var cnx: Int = 0, // connections
|
||||||
var emitState: Vector2 = Vector2(0.0, 0.0), // i'm emitting this much power
|
var emt: Vector2 = Vector2(0.0, 0.0), // i'm emitting this much power
|
||||||
var recvStates: ArrayList<WireRecvState> = ArrayList() // how far away are the power sources
|
var rcv: ArrayList<WireRecvState> = ArrayList() // how far away are the power sources
|
||||||
)
|
)
|
||||||
|
|
||||||
fun getTemperature(worldTileX: Int, worldTileY: Int): Float? {
|
fun getTemperature(worldTileX: Int, worldTileY: Int): Float? {
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ object IngameRenderer : Disposable {
|
|||||||
var world: GameWorld = GameWorld.makeNullWorld()
|
var world: GameWorld = GameWorld.makeNullWorld()
|
||||||
private set // the grammar "IngameRenderer.world = gameWorld" seemes mundane and this function needs special care!
|
private set // the grammar "IngameRenderer.world = gameWorld" seemes mundane and this function needs special care!
|
||||||
|
|
||||||
|
private var newWorldLoadedLatch = false
|
||||||
|
|
||||||
// these codes will run regardless of the invocation of the "initialise()" function
|
// these codes will run regardless of the invocation of the "initialise()" function
|
||||||
// the "initialise()" function will also be called
|
// the "initialise()" function will also be called
|
||||||
@@ -162,6 +163,8 @@ object IngameRenderer : Disposable {
|
|||||||
LightmapRenderer.internalSetWorld(world)
|
LightmapRenderer.internalSetWorld(world)
|
||||||
BlocksDrawer.world = world
|
BlocksDrawer.world = world
|
||||||
FeaturesDrawer.world = world
|
FeaturesDrawer.world = world
|
||||||
|
|
||||||
|
newWorldLoadedLatch = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (e: UninitializedPropertyAccessException) {
|
catch (e: UninitializedPropertyAccessException) {
|
||||||
@@ -201,10 +204,10 @@ object IngameRenderer : Disposable {
|
|||||||
this.player = player
|
this.player = player
|
||||||
|
|
||||||
|
|
||||||
if (!gamePaused) {
|
if (!gamePaused || newWorldLoadedLatch) {
|
||||||
measureDebugTime("Renderer.ApparentLightRun") {
|
measureDebugTime("Renderer.ApparentLightRun") {
|
||||||
// recalculate for even frames, or if the sign of the cam-x changed
|
// recalculate for even frames, or if the sign of the cam-x changed
|
||||||
if (AppLoader.GLOBAL_RENDER_TIMER % 3 == 0 || WorldCamera.x * oldCamX < 0)
|
if (AppLoader.GLOBAL_RENDER_TIMER % 3 == 0 || WorldCamera.x * oldCamX < 0 || newWorldLoadedLatch)
|
||||||
LightmapRenderer.fireRecalculateEvent(actorsRenderBehind, actorsRenderFront, actorsRenderMidTop, actorsRenderMiddle, actorsRenderOverlay)
|
LightmapRenderer.fireRecalculateEvent(actorsRenderBehind, actorsRenderFront, actorsRenderMidTop, actorsRenderMiddle, actorsRenderOverlay)
|
||||||
|
|
||||||
oldCamX = WorldCamera.x
|
oldCamX = WorldCamera.x
|
||||||
@@ -345,6 +348,9 @@ object IngameRenderer : Disposable {
|
|||||||
// works but some UI elements have wrong transparency -> should be fixed with Terrarum.gdxCleanAndSetBlend -- Torvald 2019-01-12
|
// works but some UI elements have wrong transparency -> should be fixed with Terrarum.gdxCleanAndSetBlend -- Torvald 2019-01-12
|
||||||
blendNormal(batch)
|
blendNormal(batch)
|
||||||
batch.color = Color.WHITE
|
batch.color = Color.WHITE
|
||||||
|
|
||||||
|
|
||||||
|
if (newWorldLoadedLatch) newWorldLoadedLatch = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -560,7 +560,7 @@ open class TerrarumIngame(batch: SpriteBatch) : IngameInstance(batch) {
|
|||||||
// will also queue up the block/wall/wire placed events
|
// will also queue up the block/wall/wire placed events
|
||||||
ingameController.update()
|
ingameController.update()
|
||||||
|
|
||||||
if (!paused) {
|
if (!paused || newWorldLoadedLatch) {
|
||||||
|
|
||||||
//hypothetical_input_capturing_function_if_you_finally_decided_to_forgo_gdx_input_processor_and_implement_your_own_to_synchronise_everything()
|
//hypothetical_input_capturing_function_if_you_finally_decided_to_forgo_gdx_input_processor_and_implement_your_own_to_synchronise_everything()
|
||||||
|
|
||||||
@@ -583,7 +583,7 @@ open class TerrarumIngame(batch: SpriteBatch) : IngameInstance(batch) {
|
|||||||
// fill up visibleActorsRenderFront for wires, if:
|
// fill up visibleActorsRenderFront for wires, if:
|
||||||
// 1. something is cued on the wire change queue
|
// 1. something is cued on the wire change queue
|
||||||
// 2. wire renderclass changed
|
// 2. wire renderclass changed
|
||||||
if (wireChangeQueue.isNotEmpty() || selectedWireRenderClass != oldSelectedWireRenderClass) {
|
if (newWorldLoadedLatch || wireChangeQueue.isNotEmpty() || selectedWireRenderClass != oldSelectedWireRenderClass) {
|
||||||
measureDebugTime("Ingame.FillUpWiresBuffer") {
|
measureDebugTime("Ingame.FillUpWiresBuffer") {
|
||||||
fillUpWiresBuffer()
|
fillUpWiresBuffer()
|
||||||
}
|
}
|
||||||
@@ -614,7 +614,7 @@ open class TerrarumIngame(batch: SpriteBatch) : IngameInstance(batch) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!paused) {
|
if (!paused || newWorldLoadedLatch) {
|
||||||
// completely consume block change queues because why not
|
// completely consume block change queues because why not
|
||||||
terrainChangeQueue.clear()
|
terrainChangeQueue.clear()
|
||||||
wallChangeQueue.clear()
|
wallChangeQueue.clear()
|
||||||
@@ -638,6 +638,8 @@ open class TerrarumIngame(batch: SpriteBatch) : IngameInstance(batch) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//println("paused = $paused")
|
//println("paused = $paused")
|
||||||
|
|
||||||
|
if (!paused && newWorldLoadedLatch) newWorldLoadedLatch = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package net.torvald.terrarum.modulebasegame.console
|
||||||
|
|
||||||
|
import net.torvald.terrarum.Terrarum
|
||||||
|
import net.torvald.terrarum.console.ConsoleCommand
|
||||||
|
import net.torvald.terrarum.console.Echo
|
||||||
|
import net.torvald.terrarum.gameworld.BlockAddress
|
||||||
|
import kotlin.reflect.full.memberProperties
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by minjaesong on 2021-08-26.
|
||||||
|
*/
|
||||||
|
object PrintWorld : ConsoleCommand {
|
||||||
|
override fun execute(args: Array<String>) {
|
||||||
|
if (args.size == 2) {
|
||||||
|
val w = Terrarum.ingame!!.world
|
||||||
|
|
||||||
|
val field = w::class.java.getDeclaredField(args[1])
|
||||||
|
val fieldAccessibility = field.isAccessible
|
||||||
|
|
||||||
|
field.isAccessible = true
|
||||||
|
Echo(field.get(w).toString())
|
||||||
|
Echo(field.get(w).javaClass.simpleName)
|
||||||
|
w.wirings.forEach { i, node ->
|
||||||
|
Echo(i.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
field.isAccessible = fieldAccessibility
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printUsage()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun printUsage() {
|
||||||
|
Echo("Usage: Exportworld <field>")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -48,11 +48,11 @@ class WireGraphDebugger(originalID: ItemID) : GameItem(originalID) {
|
|||||||
Terrarum.ingame!!.world.getAllWiringGraph(mx, my)?.forEach { (itemID, simCell) ->
|
Terrarum.ingame!!.world.getAllWiringGraph(mx, my)?.forEach { (itemID, simCell) ->
|
||||||
if (sb.isNotEmpty()) sb.append('\n')
|
if (sb.isNotEmpty()) sb.append('\n')
|
||||||
|
|
||||||
val connexionIcon = (simCell.connections + 0xE0A0).toChar()
|
val connexionIcon = (simCell.cnx + 0xE0A0).toChar()
|
||||||
val wireName = WireCodex[itemID].nameKey
|
val wireName = WireCodex[itemID].nameKey
|
||||||
|
|
||||||
val emit = simCell.emitState
|
val emit = simCell.emt
|
||||||
val recv = simCell.recvStates
|
val recv = simCell.rcv
|
||||||
|
|
||||||
sb.append("$connexionIcon $wireName")
|
sb.append("$connexionIcon $wireName")
|
||||||
sb.append("\nE: $emit")
|
sb.append("\nE: $emit")
|
||||||
|
|||||||
267
src/net/torvald/terrarum/serialise/Common.kt
Normal file
267
src/net/torvald/terrarum/serialise/Common.kt
Normal file
@@ -0,0 +1,267 @@
|
|||||||
|
package net.torvald.terrarum.serialise
|
||||||
|
|
||||||
|
import com.badlogic.gdx.utils.Json
|
||||||
|
import com.badlogic.gdx.utils.JsonValue
|
||||||
|
import com.badlogic.gdx.utils.JsonWriter
|
||||||
|
import net.torvald.terrarum.AppLoader
|
||||||
|
import net.torvald.terrarum.AppLoader.printdbg
|
||||||
|
import net.torvald.terrarum.console.EchoError
|
||||||
|
import net.torvald.terrarum.gameworld.BlockLayer
|
||||||
|
import net.torvald.terrarum.gameworld.GameWorld
|
||||||
|
import net.torvald.terrarum.gameworld.WorldTime
|
||||||
|
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.ByteArray64
|
||||||
|
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.ByteArray64GrowableOutputStream
|
||||||
|
import net.torvald.terrarum.utils.*
|
||||||
|
import org.apache.commons.codec.digest.DigestUtils
|
||||||
|
import java.math.BigInteger
|
||||||
|
import java.util.zip.GZIPOutputStream
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by minjaesong on 2021-08-26.
|
||||||
|
*/
|
||||||
|
object Common {
|
||||||
|
/** dispose of the `offendingObject` after rejection! */
|
||||||
|
class BlockLayerHashMismatchError(val oldHash: String, val newHash: String, val offendingObject: BlockLayer) : Error("Old Hash $oldHash != New Hash $newHash")
|
||||||
|
|
||||||
|
private fun Byte.tostr() = this.toInt().and(255).toString(16).padStart(2,'0')
|
||||||
|
private val digester = DigestUtils.getSha256Digest()
|
||||||
|
|
||||||
|
val jsoner = Json(JsonWriter.OutputType.json)
|
||||||
|
|
||||||
|
// install custom (de)serialiser
|
||||||
|
init {
|
||||||
|
// BigInteger
|
||||||
|
jsoner.setSerializer(BigInteger::class.java, object : Json.Serializer<BigInteger> {
|
||||||
|
|
||||||
|
override fun write(json: Json, obj: BigInteger?, knownType: Class<*>?) {
|
||||||
|
json.writeValue(obj?.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun read(json: Json, jsonData: JsonValue, type: Class<*>?): BigInteger {
|
||||||
|
return BigInteger(jsonData.asString())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// BlockLayer
|
||||||
|
jsoner.setSerializer(BlockLayer::class.java, object : Json.Serializer<BlockLayer> {
|
||||||
|
|
||||||
|
override fun write(json: Json, obj: BlockLayer, knownType: Class<*>?) {
|
||||||
|
digester.reset()
|
||||||
|
obj.bytesIterator().forEachRemaining { digester.update(it) }
|
||||||
|
val hash = StringBuilder().let { sb -> digester.digest().forEach { sb.append(it.tostr()) }; sb.toString() }
|
||||||
|
|
||||||
|
val layer = LayerInfo(hash, blockLayerToStr(obj), obj.width, obj.height)
|
||||||
|
|
||||||
|
AppLoader.printdbg(this, "pre: ${(0L..1023L).map { obj.ptr[it].tostr() }.joinToString(" ")}")
|
||||||
|
|
||||||
|
|
||||||
|
json.writeValue(layer)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun read(json: Json, jsonData: JsonValue, type: Class<*>): BlockLayer {
|
||||||
|
// full auto
|
||||||
|
//return strToBlockLayer(json.fromJson(type, jsonData.toJson(JsonWriter.OutputType.minimal)) as LayerInfo)
|
||||||
|
|
||||||
|
// full manual
|
||||||
|
try {
|
||||||
|
return strToBlockLayer(LayerInfo(
|
||||||
|
jsonData.getString("h"),
|
||||||
|
jsonData.getString("b"),
|
||||||
|
jsonData.getInt("x"),
|
||||||
|
jsonData.getInt("y")
|
||||||
|
))
|
||||||
|
}
|
||||||
|
catch (e: BlockLayerHashMismatchError) {
|
||||||
|
EchoError(e.message ?: "")
|
||||||
|
return e.offendingObject
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// WorldTime
|
||||||
|
jsoner.setSerializer(WorldTime::class.java, object : Json.Serializer<WorldTime> {
|
||||||
|
override fun write(json: Json, obj: WorldTime, knownType: Class<*>?) {
|
||||||
|
json.writeValue(obj.TIME_T)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun read(json: Json, jsonData: JsonValue, type: Class<*>?): WorldTime {
|
||||||
|
return WorldTime(jsonData.asLong())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// HashArray
|
||||||
|
jsoner.setSerializer(HashArray::class.java, object : Json.Serializer<HashArray<*>> {
|
||||||
|
override fun write(json: Json, obj: HashArray<*>, knownType: Class<*>?) {
|
||||||
|
json.writeObjectStart()
|
||||||
|
obj.forEach { (k, v) ->
|
||||||
|
json.writeValue(k.toString(), v)
|
||||||
|
}
|
||||||
|
json.writeObjectEnd()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun read(json: Json, jsonData: JsonValue, type: Class<*>?): HashArray<*> {
|
||||||
|
val hashMap = HashArray<Any>()
|
||||||
|
printdbg(type?.canonicalName, "deserialising '$jsonData'")
|
||||||
|
JsonFetcher.forEach(jsonData) { key, obj ->
|
||||||
|
hashMap[key.toLong()] = json.readValue(null, obj)
|
||||||
|
printdbg(this, "key: $key, value: ${hashMap[key.toLong()]}")
|
||||||
|
}
|
||||||
|
return hashMap
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// HashedWirings
|
||||||
|
jsoner.setSerializer(HashedWirings::class.java, object : Json.Serializer<HashedWirings> {
|
||||||
|
override fun write(json: Json, obj: HashedWirings, knownType: Class<*>?) {
|
||||||
|
json.writeObjectStart()
|
||||||
|
obj.forEach { (k, v) ->
|
||||||
|
json.writeValue(k.toString(), v)
|
||||||
|
}
|
||||||
|
json.writeObjectEnd()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun read(json: Json, jsonData: JsonValue, type: Class<*>?): HashedWirings {
|
||||||
|
val hashMap = HashedWirings()
|
||||||
|
printdbg(type?.canonicalName, "deserialising '$jsonData'")
|
||||||
|
JsonFetcher.forEach(jsonData) { key, obj ->
|
||||||
|
hashMap[key.toLong()] = json.readValue(GameWorld.WiringNode::class.java, obj)
|
||||||
|
printdbg(this, "key: $key, value: ${hashMap[key.toLong()]}")
|
||||||
|
}
|
||||||
|
return hashMap
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// HashedWiringGraph
|
||||||
|
jsoner.setSerializer(HashedWiringGraph::class.java, object : Json.Serializer<HashedWiringGraph> {
|
||||||
|
override fun write(json: Json, obj: HashedWiringGraph, knownType: Class<*>?) {
|
||||||
|
json.writeObjectStart()
|
||||||
|
obj.forEach { (k, v) ->
|
||||||
|
json.writeValue(k.toString(), v, WiringGraphMap::class.java)
|
||||||
|
}
|
||||||
|
json.writeObjectEnd()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun read(json: Json, jsonData: JsonValue, type: Class<*>?): HashedWiringGraph {
|
||||||
|
val hashMap = HashedWiringGraph()
|
||||||
|
printdbg(type?.canonicalName, "deserialising '$jsonData'")
|
||||||
|
JsonFetcher.forEach(jsonData) { key, obj ->
|
||||||
|
hashMap[key.toLong()] = json.readValue(WiringGraphMap::class.java, obj)
|
||||||
|
printdbg(this, "key: $key, value: ${hashMap[key.toLong()]}")
|
||||||
|
}
|
||||||
|
return hashMap
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// WiringGraphMap; this serialiser is here just to reduce the JSON filesize
|
||||||
|
jsoner.setSerializer(WiringGraphMap::class.java, object : Json.Serializer<WiringGraphMap> {
|
||||||
|
override fun write(json: Json, obj: WiringGraphMap, knownType: Class<*>?) {
|
||||||
|
json.writeObjectStart()
|
||||||
|
obj.forEach { (k, v) ->
|
||||||
|
json.writeValue(k, v, GameWorld.WiringSimCell::class.java)
|
||||||
|
}
|
||||||
|
json.writeObjectEnd()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun read(json: Json, jsonData: JsonValue, type: Class<*>?): WiringGraphMap {
|
||||||
|
val hashMap = WiringGraphMap()
|
||||||
|
printdbg(type?.canonicalName, "deserialising '$jsonData'")
|
||||||
|
JsonFetcher.forEach(jsonData) { key, obj ->
|
||||||
|
hashMap[key] = json.readValue(GameWorld.WiringSimCell::class.java, obj)
|
||||||
|
printdbg(this, "key: $key, value: ${hashMap[key]}")
|
||||||
|
}
|
||||||
|
return hashMap
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private data class LayerInfo(val h: String, val b: String, val x: Int, val y: Int)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param b a BlockLayer
|
||||||
|
* @return Bytes in [b] which are GZip'd then Ascii85-encoded
|
||||||
|
*/
|
||||||
|
private fun blockLayerToStr(b: BlockLayer): String {
|
||||||
|
val sb = StringBuilder()
|
||||||
|
val bo = ByteArray64GrowableOutputStream()
|
||||||
|
val zo = GZIPOutputStream(bo)
|
||||||
|
|
||||||
|
// zip
|
||||||
|
/*b.bytesIterator().forEachRemaining {
|
||||||
|
zo.write(it.toInt())
|
||||||
|
}
|
||||||
|
zo.flush(); zo.close()*/
|
||||||
|
|
||||||
|
// enascii
|
||||||
|
val ba = bo.toByteArray64()
|
||||||
|
var bai = 0
|
||||||
|
val buf = IntArray(4) { Ascii85.PAD_BYTE }
|
||||||
|
// ba.forEach {
|
||||||
|
b.bytesIterator().forEachRemaining {
|
||||||
|
if (bai > 0 && bai % 4 == 0) {
|
||||||
|
sb.append(Ascii85.encode(buf[0], buf[1], buf[2], buf[3]))
|
||||||
|
buf.fill(Ascii85.PAD_BYTE)
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[bai % 4] = it.toInt() and 255
|
||||||
|
|
||||||
|
bai += 1
|
||||||
|
}; sb.append(Ascii85.encode(buf[0], buf[1], buf[2], buf[3]))
|
||||||
|
|
||||||
|
return sb.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun strToBlockLayer(layerInfo: LayerInfo): BlockLayer {
|
||||||
|
val layer = BlockLayer(layerInfo.x, layerInfo.y)
|
||||||
|
val unasciidBytes = ByteArray64()
|
||||||
|
val unzipdBytes = ByteArray64()
|
||||||
|
|
||||||
|
// unascii
|
||||||
|
var bai = 0
|
||||||
|
val buf = CharArray(5) { Ascii85.PAD_CHAR }
|
||||||
|
layerInfo.b.forEach {
|
||||||
|
if (bai > 0 && bai % 5 == 0) {
|
||||||
|
Ascii85.decode(buf[0], buf[1], buf[2], buf[3], buf[4]).forEach { unasciidBytes.add(it) }
|
||||||
|
buf.fill(Ascii85.PAD_CHAR)
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[bai % 5] = it
|
||||||
|
|
||||||
|
bai += 1
|
||||||
|
}; Ascii85.decode(buf[0], buf[1], buf[2], buf[3], buf[4]).forEach { unasciidBytes.add(it) }
|
||||||
|
|
||||||
|
// unzip
|
||||||
|
/*val zi = GZIPInputStream(ByteArray64InputStream(unasciidBytes))
|
||||||
|
while (true) {
|
||||||
|
val byte = zi.read()
|
||||||
|
if (byte == -1) break
|
||||||
|
unzipdBytes.add(byte.toByte())
|
||||||
|
}
|
||||||
|
zi.close()*/
|
||||||
|
|
||||||
|
// write to blocklayer and the digester
|
||||||
|
digester.reset()
|
||||||
|
var writeCursor = 0L
|
||||||
|
val sb = StringBuilder()
|
||||||
|
// unzipdBytes.forEach {
|
||||||
|
unasciidBytes.forEach {
|
||||||
|
if (writeCursor < layer.ptr.size) {
|
||||||
|
|
||||||
|
if (writeCursor < 1024) {
|
||||||
|
sb.append("${it.tostr()} ")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
layer.ptr[writeCursor] = it
|
||||||
|
digester.update(it)
|
||||||
|
writeCursor += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AppLoader.printdbg(this, "post: $sb")
|
||||||
|
|
||||||
|
|
||||||
|
// check hash
|
||||||
|
val hash = StringBuilder().let { sb -> digester.digest().forEach { sb.append(it.tostr()) }; sb.toString() }
|
||||||
|
|
||||||
|
if (hash != layerInfo.h) {
|
||||||
|
throw BlockLayerHashMismatchError(layerInfo.h, hash, layer)
|
||||||
|
}
|
||||||
|
|
||||||
|
return layer
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,11 +13,11 @@ import java.io.Reader
|
|||||||
open class ReadWorld(val ingame: TerrarumIngame) {
|
open class ReadWorld(val ingame: TerrarumIngame) {
|
||||||
|
|
||||||
open fun invoke(worldDataStream: InputStream) {
|
open fun invoke(worldDataStream: InputStream) {
|
||||||
postRead(WriteWorld.jsoner.fromJson(GameWorld::class.java, worldDataStream))
|
postRead(Common.jsoner.fromJson(GameWorld::class.java, worldDataStream))
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun invoke(worldDataStream: Reader) {
|
open fun invoke(worldDataStream: Reader) {
|
||||||
postRead(WriteWorld.jsoner.fromJson(GameWorld::class.java, worldDataStream))
|
postRead(Common.jsoner.fromJson(GameWorld::class.java, worldDataStream))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun postRead(world: GameWorld) {
|
private fun postRead(world: GameWorld) {
|
||||||
|
|||||||
@@ -12,23 +12,8 @@ import java.math.BigInteger
|
|||||||
*/
|
*/
|
||||||
object WriteActor {
|
object WriteActor {
|
||||||
|
|
||||||
private val jsoner = Json(JsonWriter.OutputType.json)
|
|
||||||
|
|
||||||
// install custom (de)serialiser
|
|
||||||
init {
|
|
||||||
jsoner.setSerializer(BigInteger::class.java, object : Json.Serializer<BigInteger> {
|
|
||||||
override fun write(json: Json, obj: BigInteger?, knownType: Class<*>?) {
|
|
||||||
json.writeValue(obj?.toString())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun read(json: Json, jsonData: JsonValue, type: Class<*>?): BigInteger {
|
|
||||||
return BigInteger(jsonData.asString())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
operator fun invoke(actor: Actor): String {
|
operator fun invoke(actor: Actor): String {
|
||||||
return jsoner.toJson(actor)
|
return Common.jsoner.toJson(actor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun encodeToByteArray64(actor: Actor): ByteArray64 {
|
fun encodeToByteArray64(actor: Actor): ByteArray64 {
|
||||||
|
|||||||
@@ -1,22 +1,7 @@
|
|||||||
package net.torvald.terrarum.serialise
|
package net.torvald.terrarum.serialise
|
||||||
|
|
||||||
import com.badlogic.gdx.utils.Json
|
|
||||||
import com.badlogic.gdx.utils.JsonReader
|
|
||||||
import com.badlogic.gdx.utils.JsonValue
|
|
||||||
import com.badlogic.gdx.utils.JsonWriter
|
|
||||||
import net.torvald.terrarum.AppLoader.printdbg
|
|
||||||
import net.torvald.terrarum.console.EchoError
|
|
||||||
import net.torvald.terrarum.gameworld.BlockLayer
|
|
||||||
import net.torvald.terrarum.gameworld.WorldTime
|
|
||||||
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.ByteArray64
|
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.ByteArray64
|
||||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.ByteArray64GrowableOutputStream
|
|
||||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.ByteArray64InputStream
|
|
||||||
import net.torvald.terrarum.serialise.WriteWorld.Companion.tostr
|
|
||||||
import org.apache.commons.codec.digest.DigestUtils
|
|
||||||
import java.math.BigInteger
|
|
||||||
import java.util.zip.GZIPInputStream
|
|
||||||
import java.util.zip.GZIPOutputStream
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by minjaesong on 2021-08-23.
|
* Created by minjaesong on 2021-08-23.
|
||||||
@@ -26,7 +11,7 @@ open class WriteWorld(val ingame: TerrarumIngame) {
|
|||||||
open fun invoke(): String {
|
open fun invoke(): String {
|
||||||
val world = ingame.world
|
val world = ingame.world
|
||||||
//return "{${world.getJsonFields().joinToString(",\n")}}"
|
//return "{${world.getJsonFields().joinToString(",\n")}}"
|
||||||
return jsoner.toJson(world)
|
return Common.jsoner.toJson(world)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun encodeToByteArray64(): ByteArray64 {
|
fun encodeToByteArray64(): ByteArray64 {
|
||||||
@@ -44,170 +29,4 @@ open class WriteWorld(val ingame: TerrarumIngame) {
|
|||||||
return ba
|
return ba
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
/** dispose of the `offendingObject` after rejection! */
|
|
||||||
class BlockLayerHashMismatchError(val oldHash: String, val newHash: String, val offendingObject: BlockLayer) : Error("Old Hash $oldHash != New Hash $newHash")
|
|
||||||
|
|
||||||
private fun Byte.tostr() = this.toInt().and(255).toString(16).padStart(2,'0')
|
|
||||||
private val digester = DigestUtils.getSha256Digest()
|
|
||||||
|
|
||||||
val jsoner = Json(JsonWriter.OutputType.json)
|
|
||||||
|
|
||||||
// install custom (de)serialiser
|
|
||||||
init {
|
|
||||||
// BigInteger
|
|
||||||
jsoner.setSerializer(BigInteger::class.java, object : Json.Serializer<BigInteger> {
|
|
||||||
|
|
||||||
override fun write(json: Json, obj: BigInteger?, knownType: Class<*>?) {
|
|
||||||
json.writeValue(obj?.toString())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun read(json: Json, jsonData: JsonValue, type: Class<*>?): BigInteger {
|
|
||||||
return BigInteger(jsonData.asString())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
// BlockLayer
|
|
||||||
jsoner.setSerializer(BlockLayer::class.java, object : Json.Serializer<BlockLayer> {
|
|
||||||
|
|
||||||
override fun write(json: Json, obj: BlockLayer, knownType: Class<*>?) {
|
|
||||||
digester.reset()
|
|
||||||
obj.bytesIterator().forEachRemaining { digester.update(it) }
|
|
||||||
val hash = StringBuilder().let { sb -> digester.digest().forEach { sb.append(it.tostr()) }; sb.toString() }
|
|
||||||
|
|
||||||
val layer = LayerInfo(hash, blockLayerToStr(obj), obj.width, obj.height)
|
|
||||||
|
|
||||||
printdbg(this, "pre: ${(0L..1023L).map { obj.ptr[it].tostr() }.joinToString(" ")}")
|
|
||||||
|
|
||||||
|
|
||||||
json.writeValue(layer)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun read(json: Json, jsonData: JsonValue, type: Class<*>): BlockLayer {
|
|
||||||
// full auto
|
|
||||||
//return strToBlockLayer(json.fromJson(type, jsonData.toJson(JsonWriter.OutputType.minimal)) as LayerInfo)
|
|
||||||
|
|
||||||
// full manual
|
|
||||||
try {
|
|
||||||
return strToBlockLayer(LayerInfo(
|
|
||||||
jsonData.getString("h"),
|
|
||||||
jsonData.getString("b"),
|
|
||||||
jsonData.getInt("x"),
|
|
||||||
jsonData.getInt("y")
|
|
||||||
))
|
|
||||||
}
|
|
||||||
catch (e: BlockLayerHashMismatchError) {
|
|
||||||
EchoError(e.message ?: "")
|
|
||||||
return e.offendingObject
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
// WorldTime
|
|
||||||
jsoner.setSerializer(WorldTime::class.java, object : Json.Serializer<WorldTime> {
|
|
||||||
override fun write(json: Json, obj: WorldTime, knownType: Class<*>?) {
|
|
||||||
json.writeValue(obj.TIME_T)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun read(json: Json, jsonData: JsonValue, type: Class<*>?): WorldTime {
|
|
||||||
return WorldTime(jsonData.asLong())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private data class LayerInfo(val h: String, val b: String, val x: Int, val y: Int)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param b a BlockLayer
|
|
||||||
* @return Bytes in [b] which are GZip'd then Ascii85-encoded
|
|
||||||
*/
|
|
||||||
private fun blockLayerToStr(b: BlockLayer): String {
|
|
||||||
val sb = StringBuilder()
|
|
||||||
val bo = ByteArray64GrowableOutputStream()
|
|
||||||
val zo = GZIPOutputStream(bo)
|
|
||||||
|
|
||||||
// zip
|
|
||||||
/*b.bytesIterator().forEachRemaining {
|
|
||||||
zo.write(it.toInt())
|
|
||||||
}
|
|
||||||
zo.flush(); zo.close()*/
|
|
||||||
|
|
||||||
// enascii
|
|
||||||
val ba = bo.toByteArray64()
|
|
||||||
var bai = 0
|
|
||||||
val buf = IntArray(4) { Ascii85.PAD_BYTE }
|
|
||||||
// ba.forEach {
|
|
||||||
b.bytesIterator().forEachRemaining {
|
|
||||||
if (bai > 0 && bai % 4 == 0) {
|
|
||||||
sb.append(Ascii85.encode(buf[0], buf[1], buf[2], buf[3]))
|
|
||||||
buf.fill(Ascii85.PAD_BYTE)
|
|
||||||
}
|
|
||||||
|
|
||||||
buf[bai % 4] = it.toInt() and 255
|
|
||||||
|
|
||||||
bai += 1
|
|
||||||
}; sb.append(Ascii85.encode(buf[0], buf[1], buf[2], buf[3]))
|
|
||||||
|
|
||||||
return sb.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun strToBlockLayer(layerInfo: LayerInfo): BlockLayer {
|
|
||||||
val layer = BlockLayer(layerInfo.x, layerInfo.y)
|
|
||||||
val unasciidBytes = ByteArray64()
|
|
||||||
val unzipdBytes = ByteArray64()
|
|
||||||
|
|
||||||
// unascii
|
|
||||||
var bai = 0
|
|
||||||
val buf = CharArray(5) { Ascii85.PAD_CHAR }
|
|
||||||
layerInfo.b.forEach {
|
|
||||||
if (bai > 0 && bai % 5 == 0) {
|
|
||||||
Ascii85.decode(buf[0], buf[1], buf[2], buf[3], buf[4]).forEach { unasciidBytes.add(it) }
|
|
||||||
buf.fill(Ascii85.PAD_CHAR)
|
|
||||||
}
|
|
||||||
|
|
||||||
buf[bai % 5] = it
|
|
||||||
|
|
||||||
bai += 1
|
|
||||||
}; Ascii85.decode(buf[0], buf[1], buf[2], buf[3], buf[4]).forEach { unasciidBytes.add(it) }
|
|
||||||
|
|
||||||
// unzip
|
|
||||||
/*val zi = GZIPInputStream(ByteArray64InputStream(unasciidBytes))
|
|
||||||
while (true) {
|
|
||||||
val byte = zi.read()
|
|
||||||
if (byte == -1) break
|
|
||||||
unzipdBytes.add(byte.toByte())
|
|
||||||
}
|
|
||||||
zi.close()*/
|
|
||||||
|
|
||||||
// write to blocklayer and the digester
|
|
||||||
digester.reset()
|
|
||||||
var writeCursor = 0L
|
|
||||||
val sb = StringBuilder()
|
|
||||||
// unzipdBytes.forEach {
|
|
||||||
unasciidBytes.forEach {
|
|
||||||
if (writeCursor < layer.ptr.size) {
|
|
||||||
|
|
||||||
if (writeCursor < 1024) {
|
|
||||||
sb.append("${it.tostr()} ")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
layer.ptr[writeCursor] = it
|
|
||||||
digester.update(it)
|
|
||||||
writeCursor += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
printdbg(this, "post: $sb")
|
|
||||||
|
|
||||||
|
|
||||||
// check hash
|
|
||||||
val hash = StringBuilder().let { sb -> digester.digest().forEach { sb.append(it.tostr()) }; sb.toString() }
|
|
||||||
|
|
||||||
if (hash != layerInfo.h) {
|
|
||||||
throw BlockLayerHashMismatchError(layerInfo.h, hash, layer)
|
|
||||||
}
|
|
||||||
|
|
||||||
return layer
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
18
src/net/torvald/terrarum/utils/HashArray.kt
Normal file
18
src/net/torvald/terrarum/utils/HashArray.kt
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package net.torvald.terrarum.utils
|
||||||
|
|
||||||
|
|
||||||
|
import net.torvald.terrarum.gameitem.ItemID
|
||||||
|
import net.torvald.terrarum.gameworld.BlockAddress
|
||||||
|
import net.torvald.terrarum.gameworld.FluidType
|
||||||
|
import net.torvald.terrarum.gameworld.GameWorld
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by minjaesong on 2021-08-26.
|
||||||
|
*/
|
||||||
|
class HashArray<R>: HashMap<Long, R>() // primitives are working just fine tho
|
||||||
|
|
||||||
|
// Oh for the fucks sake fuck you everyone; json shit won't work with generics
|
||||||
|
class WiringGraphMap: HashMap<ItemID, GameWorld.WiringSimCell>()
|
||||||
|
class HashedFluidType: HashMap<BlockAddress, FluidType>()
|
||||||
|
class HashedWirings: HashMap<BlockAddress, GameWorld.WiringNode>()
|
||||||
|
class HashedWiringGraph: HashMap<BlockAddress, WiringGraphMap>()
|
||||||
@@ -413,9 +413,9 @@ object LightmapRenderer {
|
|||||||
|
|
||||||
|
|
||||||
_thisTerrain = world.getTileFromTerrainRaw(worldX, worldY)
|
_thisTerrain = world.getTileFromTerrainRaw(worldX, worldY)
|
||||||
_thisTerrainProp = BlockCodex[world.tileNumberToNameMap[_thisTerrain]]
|
_thisTerrainProp = BlockCodex[world.tileNumberToNameMap[_thisTerrain.toLong()]]
|
||||||
_thisWall = world.getTileFromWallRaw(worldX, worldY)
|
_thisWall = world.getTileFromWallRaw(worldX, worldY)
|
||||||
_thisWallProp = BlockCodex[world.tileNumberToNameMap[_thisWall]]
|
_thisWallProp = BlockCodex[world.tileNumberToNameMap[_thisWall.toLong()]]
|
||||||
_thisFluid = world.getFluid(worldX, worldY)
|
_thisFluid = world.getFluid(worldX, worldY)
|
||||||
_thisFluidProp = BlockCodex[_thisFluid.type]
|
_thisFluidProp = BlockCodex[_thisFluid.type]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user