mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-10 10:34:06 +09:00
Generalised BlockLayer
This commit is contained in:
@@ -423,3 +423,4 @@ fun ItemID.isVirtual() = this.startsWith("$PREFIX_VIRTUALTILE@")
|
|||||||
fun ItemID.isBlock() = !this.contains('@') && !this.isDynamic()
|
fun ItemID.isBlock() = !this.contains('@') && !this.isDynamic()
|
||||||
fun ItemID.isWall() = this.startsWith("wall@")
|
fun ItemID.isWall() = this.startsWith("wall@")
|
||||||
fun ItemID.isFluid() = this.startsWith("fluid@")
|
fun ItemID.isFluid() = this.startsWith("fluid@")
|
||||||
|
fun ItemID.isOre() = this.startsWith("ores@")
|
||||||
|
|||||||
@@ -1,110 +1,14 @@
|
|||||||
package net.torvald.terrarum.gameworld
|
package net.torvald.terrarum.gameworld
|
||||||
|
|
||||||
import com.badlogic.gdx.utils.Disposable
|
import com.badlogic.gdx.utils.Disposable
|
||||||
import net.torvald.terrarum.App.printdbg
|
|
||||||
import net.torvald.terrarum.serialise.toUint
|
|
||||||
import net.torvald.unsafe.UnsafeHelper
|
|
||||||
import net.torvald.unsafe.UnsafePtr
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Memory layout:
|
* Created by minjaesong on 2023-10-10.
|
||||||
* ```
|
|
||||||
* a7 a6 a5 a4 a3 a2 a1 a0 | aF aE aD aC aB aA a9 a8 ||
|
|
||||||
* ```
|
|
||||||
* where a_n is a tile number
|
|
||||||
*
|
|
||||||
* Original version Created by minjaesong on 2016-01-17.
|
|
||||||
* Unsafe version Created by minjaesong on 2019-06-08.
|
|
||||||
*
|
|
||||||
* Note to self: refrain from using shorts--just do away with two bytes: different system have different endianness
|
|
||||||
*/
|
*/
|
||||||
open class BlockLayer(val width: Int, val height: Int) : Disposable {
|
interface BlockLayer : Disposable {
|
||||||
// for some reason, all the efforts of saving the memory space were futile.
|
|
||||||
|
|
||||||
// using unsafe pointer gets you 100 fps, whereas using directbytebuffer gets you 90
|
val bytesPerBlock: Long
|
||||||
internal val ptr: UnsafePtr = UnsafeHelper.allocate(width * height * BYTES_PER_BLOCK)
|
fun unsafeToBytes(x: Int, y: Int): ByteArray
|
||||||
|
fun unsafeSetTile(x: Int, y: Int, bytes: ByteArray)
|
||||||
|
|
||||||
val ptrDestroyed: Boolean
|
}
|
||||||
get() = ptr.destroyed
|
|
||||||
|
|
||||||
init {
|
|
||||||
ptr.fillWith(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param data Byte array representation of the layer
|
|
||||||
*/
|
|
||||||
constructor(width: Int, height: Int, data: ByteArray) : this(width, height) {
|
|
||||||
TODO()
|
|
||||||
data.forEachIndexed { index, byte -> UnsafeHelper.unsafe.putByte(ptr.ptr + index, byte) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an iterator over stored bytes.
|
|
||||||
*
|
|
||||||
* @return an Iterator.
|
|
||||||
*/
|
|
||||||
fun bytesIterator(): Iterator<Byte> {
|
|
||||||
return object : Iterator<Byte> {
|
|
||||||
private var iteratorCount = 0L
|
|
||||||
override fun hasNext(): Boolean {
|
|
||||||
return iteratorCount < width * height * BYTES_PER_BLOCK
|
|
||||||
}
|
|
||||||
override fun next(): Byte {
|
|
||||||
iteratorCount += 1
|
|
||||||
return ptr[iteratorCount - 1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun unsafeGetTile(x: Int, y: Int): Int {
|
|
||||||
val offset = BYTES_PER_BLOCK * (y * width + x)
|
|
||||||
val lsb = ptr[offset]
|
|
||||||
val msb = ptr[offset + 1]
|
|
||||||
|
|
||||||
return lsb.toUint() + msb.toUint().shl(8)
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun unsafeSetTile(x: Int, y: Int, tile: Int) {
|
|
||||||
val offset = BYTES_PER_BLOCK * (y * width + x)
|
|
||||||
|
|
||||||
val lsb = tile.and(0xff).toByte()
|
|
||||||
val msb = tile.ushr(8).and(0xff).toByte()
|
|
||||||
|
|
||||||
|
|
||||||
// try {
|
|
||||||
ptr[offset] = lsb
|
|
||||||
ptr[offset + 1] = msb
|
|
||||||
// }
|
|
||||||
// catch (e: IndexOutOfBoundsException) {
|
|
||||||
// printdbgerr(this, "IndexOutOfBoundsException: x = $x, y = $y; offset = $offset")
|
|
||||||
// throw e
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param blockOffset Offset in blocks. BlockOffset of 0x100 is equal to ```layerPtr + 0x200```
|
|
||||||
*/
|
|
||||||
/*internal fun unsafeSetTile(blockOffset: Long, tile: Int) {
|
|
||||||
val offset = BYTES_PER_BLOCK * blockOffset
|
|
||||||
|
|
||||||
val lsb = tile.and(0xff).toByte()
|
|
||||||
val msb = tile.ushr(8).and(0xff).toByte()
|
|
||||||
|
|
||||||
unsafe.putByte(layerPtr + offset, lsb)
|
|
||||||
unsafe.putByte(layerPtr + offset + 1, msb)
|
|
||||||
}*/
|
|
||||||
|
|
||||||
fun isInBound(x: Int, y: Int) = (x >= 0 && y >= 0 && x < width && y < height)
|
|
||||||
|
|
||||||
override fun dispose() {
|
|
||||||
ptr.destroy()
|
|
||||||
printdbg(this, "BlockLayer with ptr ($ptr) successfully freed")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toString(): String = ptr.toString()
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
@Transient val BYTES_PER_BLOCK = 2L
|
|
||||||
}
|
|
||||||
}
|
|
||||||
126
src/net/torvald/terrarum/gameworld/BlockLayerI16.kt
Normal file
126
src/net/torvald/terrarum/gameworld/BlockLayerI16.kt
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
package net.torvald.terrarum.gameworld
|
||||||
|
|
||||||
|
import com.badlogic.gdx.utils.Disposable
|
||||||
|
import net.torvald.terrarum.App.printdbg
|
||||||
|
import net.torvald.terrarum.serialise.toUint
|
||||||
|
import net.torvald.unsafe.UnsafeHelper
|
||||||
|
import net.torvald.unsafe.UnsafePtr
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Memory layout:
|
||||||
|
* ```
|
||||||
|
* a7 a6 a5 a4 a3 a2 a1 a0 | aF aE aD aC aB aA a9 a8 ||
|
||||||
|
* ```
|
||||||
|
* where a_n is a tile number
|
||||||
|
*
|
||||||
|
* Original version Created by minjaesong on 2016-01-17.
|
||||||
|
* Unsafe version Created by minjaesong on 2019-06-08.
|
||||||
|
*
|
||||||
|
* Note to self: refrain from using shorts--just do away with two bytes: different system have different endianness
|
||||||
|
*/
|
||||||
|
open class BlockLayerI16(val width: Int, val height: Int) : BlockLayer {
|
||||||
|
override val bytesPerBlock = BYTES_PER_BLOCK
|
||||||
|
|
||||||
|
// for some reason, all the efforts of saving the memory space were futile.
|
||||||
|
|
||||||
|
// using unsafe pointer gets you 100 fps, whereas using directbytebuffer gets you 90
|
||||||
|
internal val ptr: UnsafePtr = UnsafeHelper.allocate(width * height * BYTES_PER_BLOCK)
|
||||||
|
|
||||||
|
val ptrDestroyed: Boolean
|
||||||
|
get() = ptr.destroyed
|
||||||
|
|
||||||
|
init {
|
||||||
|
ptr.fillWith(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param data Byte array representation of the layer
|
||||||
|
*/
|
||||||
|
constructor(width: Int, height: Int, data: ByteArray) : this(width, height) {
|
||||||
|
TODO()
|
||||||
|
data.forEachIndexed { index, byte -> UnsafeHelper.unsafe.putByte(ptr.ptr + index, byte) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an iterator over stored bytes.
|
||||||
|
*
|
||||||
|
* @return an Iterator.
|
||||||
|
*/
|
||||||
|
fun bytesIterator(): Iterator<Byte> {
|
||||||
|
return object : Iterator<Byte> {
|
||||||
|
private var iteratorCount = 0L
|
||||||
|
override fun hasNext(): Boolean {
|
||||||
|
return iteratorCount < width * height * BYTES_PER_BLOCK
|
||||||
|
}
|
||||||
|
override fun next(): Byte {
|
||||||
|
iteratorCount += 1
|
||||||
|
return ptr[iteratorCount - 1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun unsafeGetTile(x: Int, y: Int): Int {
|
||||||
|
val offset = BYTES_PER_BLOCK * (y * width + x)
|
||||||
|
val lsb = ptr[offset]
|
||||||
|
val msb = ptr[offset + 1]
|
||||||
|
|
||||||
|
return lsb.toUint() + msb.toUint().shl(8)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun unsafeToBytes(x: Int, y: Int): ByteArray {
|
||||||
|
val offset = BYTES_PER_BLOCK * (y * width + x)
|
||||||
|
val lsb = ptr[offset]
|
||||||
|
val msb = ptr[offset + 1]
|
||||||
|
|
||||||
|
return byteArrayOf(msb, lsb)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun unsafeSetTile(x: Int, y: Int, tile: Int) {
|
||||||
|
val offset = BYTES_PER_BLOCK * (y * width + x)
|
||||||
|
|
||||||
|
val lsb = tile.and(0xff).toByte()
|
||||||
|
val msb = tile.ushr(8).and(0xff).toByte()
|
||||||
|
|
||||||
|
|
||||||
|
// try {
|
||||||
|
ptr[offset] = lsb
|
||||||
|
ptr[offset + 1] = msb
|
||||||
|
// }
|
||||||
|
// catch (e: IndexOutOfBoundsException) {
|
||||||
|
// printdbgerr(this, "IndexOutOfBoundsException: x = $x, y = $y; offset = $offset")
|
||||||
|
// throw e
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun unsafeSetTile(x: Int, y: Int, bytes: ByteArray) {
|
||||||
|
val offset = BYTES_PER_BLOCK * (y * width + x)
|
||||||
|
ptr[offset] = bytes[1]
|
||||||
|
ptr[offset + 1] = bytes[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param blockOffset Offset in blocks. BlockOffset of 0x100 is equal to ```layerPtr + 0x200```
|
||||||
|
*/
|
||||||
|
/*internal fun unsafeSetTile(blockOffset: Long, tile: Int) {
|
||||||
|
val offset = BYTES_PER_BLOCK * blockOffset
|
||||||
|
|
||||||
|
val lsb = tile.and(0xff).toByte()
|
||||||
|
val msb = tile.ushr(8).and(0xff).toByte()
|
||||||
|
|
||||||
|
unsafe.putByte(layerPtr + offset, lsb)
|
||||||
|
unsafe.putByte(layerPtr + offset + 1, msb)
|
||||||
|
}*/
|
||||||
|
|
||||||
|
fun isInBound(x: Int, y: Int) = (x >= 0 && y >= 0 && x < width && y < height)
|
||||||
|
|
||||||
|
override fun dispose() {
|
||||||
|
ptr.destroy()
|
||||||
|
printdbg(this, "BlockLayerI16 with ptr ($ptr) successfully freed")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String = ptr.toString("BlockLayerI16")
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@Transient val BYTES_PER_BLOCK = 2L
|
||||||
|
}
|
||||||
|
}
|
||||||
126
src/net/torvald/terrarum/gameworld/BlockLayerI16I8.kt
Normal file
126
src/net/torvald/terrarum/gameworld/BlockLayerI16I8.kt
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
package net.torvald.terrarum.gameworld
|
||||||
|
|
||||||
|
import com.badlogic.gdx.utils.Disposable
|
||||||
|
import net.torvald.terrarum.App
|
||||||
|
import net.torvald.terrarum.serialise.toUint
|
||||||
|
import net.torvald.unsafe.UnsafeHelper
|
||||||
|
import net.torvald.unsafe.UnsafePtr
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Memory layout:
|
||||||
|
* ```
|
||||||
|
* a7 a6 a5 a4 a3 a2 a1 a0 | aF aE aD aC aB aA a9 a8 | p7 p6 p5 p4 p3 p2 p1 p0 ||
|
||||||
|
* ```
|
||||||
|
* where a_n is a tile number, p_n is a placement index
|
||||||
|
* Created by minjaesong on 2023-10-10.
|
||||||
|
*/
|
||||||
|
class BlockLayerI16I8 (val width: Int, val height: Int) : BlockLayer {
|
||||||
|
override val bytesPerBlock = BYTES_PER_BLOCK
|
||||||
|
|
||||||
|
// for some reason, all the efforts of saving the memory space were futile.
|
||||||
|
|
||||||
|
// using unsafe pointer gets you 100 fps, whereas using directbytebuffer gets you 90
|
||||||
|
internal val ptr: UnsafePtr = UnsafeHelper.allocate(width * height * BYTES_PER_BLOCK)
|
||||||
|
|
||||||
|
val ptrDestroyed: Boolean
|
||||||
|
get() = ptr.destroyed
|
||||||
|
|
||||||
|
init {
|
||||||
|
ptr.fillWith(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param data Byte array representation of the layer
|
||||||
|
*/
|
||||||
|
constructor(width: Int, height: Int, data: ByteArray) : this(width, height) {
|
||||||
|
TODO()
|
||||||
|
data.forEachIndexed { index, byte -> UnsafeHelper.unsafe.putByte(ptr.ptr + index, byte) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an iterator over stored bytes.
|
||||||
|
*
|
||||||
|
* @return an Iterator.
|
||||||
|
*/
|
||||||
|
fun bytesIterator(): Iterator<Byte> {
|
||||||
|
return object : Iterator<Byte> {
|
||||||
|
private var iteratorCount = 0L
|
||||||
|
override fun hasNext(): Boolean {
|
||||||
|
return iteratorCount < width * height * BYTES_PER_BLOCK
|
||||||
|
}
|
||||||
|
override fun next(): Byte {
|
||||||
|
iteratorCount += 1
|
||||||
|
return ptr[iteratorCount - 1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun unsafeGetTile(x: Int, y: Int): Pair<Int, Int> {
|
||||||
|
val offset = BYTES_PER_BLOCK * (y * width + x)
|
||||||
|
val lsb = ptr[offset]
|
||||||
|
val msb = ptr[offset + 1]
|
||||||
|
val placement = ptr[offset + 2]
|
||||||
|
|
||||||
|
return lsb.toUint() + msb.toUint().shl(8) to placement.toUint()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun unsafeToBytes(x: Int, y: Int): ByteArray {
|
||||||
|
val offset = BYTES_PER_BLOCK * (y * width + x)
|
||||||
|
val lsb = ptr[offset]
|
||||||
|
val msb = ptr[offset + 1]
|
||||||
|
val placement = ptr[offset + 2]
|
||||||
|
|
||||||
|
return byteArrayOf(msb, lsb, placement)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun unsafeSetTile(x: Int, y: Int, tile: Int, placement: Int) {
|
||||||
|
val offset = BYTES_PER_BLOCK * (y * width + x)
|
||||||
|
|
||||||
|
val lsb = tile.and(0xff).toByte()
|
||||||
|
val msb = tile.ushr(8).and(0xff).toByte()
|
||||||
|
|
||||||
|
|
||||||
|
// try {
|
||||||
|
ptr[offset] = lsb
|
||||||
|
ptr[offset + 1] = msb
|
||||||
|
ptr[offset + 2] = placement.toByte()
|
||||||
|
// }
|
||||||
|
// catch (e: IndexOutOfBoundsException) {
|
||||||
|
// printdbgerr(this, "IndexOutOfBoundsException: x = $x, y = $y; offset = $offset")
|
||||||
|
// throw e
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun unsafeSetTile(x: Int, y: Int, bytes: ByteArray) {
|
||||||
|
val offset = BYTES_PER_BLOCK * (y * width + x)
|
||||||
|
ptr[offset] = bytes[1]
|
||||||
|
ptr[offset + 1] = bytes[0]
|
||||||
|
ptr[offset + 2] = bytes[2]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param blockOffset Offset in blocks. BlockOffset of 0x100 is equal to ```layerPtr + 0x200```
|
||||||
|
*/
|
||||||
|
/*internal fun unsafeSetTile(blockOffset: Long, tile: Int) {
|
||||||
|
val offset = BYTES_PER_BLOCK * blockOffset
|
||||||
|
|
||||||
|
val lsb = tile.and(0xff).toByte()
|
||||||
|
val msb = tile.ushr(8).and(0xff).toByte()
|
||||||
|
|
||||||
|
unsafe.putByte(layerPtr + offset, lsb)
|
||||||
|
unsafe.putByte(layerPtr + offset + 1, msb)
|
||||||
|
}*/
|
||||||
|
|
||||||
|
fun isInBound(x: Int, y: Int) = (x >= 0 && y >= 0 && x < width && y < height)
|
||||||
|
|
||||||
|
override fun dispose() {
|
||||||
|
ptr.destroy()
|
||||||
|
App.printdbg(this, "BlockLayerI16I8 with ptr ($ptr) successfully freed")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String = ptr.toString("BlockLayerI16I8")
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@Transient val BYTES_PER_BLOCK = 3L
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,22 +7,20 @@ import net.torvald.terrarum.*
|
|||||||
import net.torvald.terrarum.App.printdbg
|
import net.torvald.terrarum.App.printdbg
|
||||||
import net.torvald.terrarum.blockproperties.Block
|
import net.torvald.terrarum.blockproperties.Block
|
||||||
import net.torvald.terrarum.blockproperties.Fluid
|
import net.torvald.terrarum.blockproperties.Fluid
|
||||||
import net.torvald.terrarum.concurrent.ThreadExecutor
|
|
||||||
import net.torvald.terrarum.gameactors.ActorID
|
import net.torvald.terrarum.gameactors.ActorID
|
||||||
import net.torvald.terrarum.gameitems.ItemID
|
import net.torvald.terrarum.gameitems.ItemID
|
||||||
import net.torvald.terrarum.gameitems.isFluid
|
import net.torvald.terrarum.gameitems.isFluid
|
||||||
|
import net.torvald.terrarum.gameitems.isOre
|
||||||
import net.torvald.terrarum.itemproperties.ItemRemapTable
|
import net.torvald.terrarum.itemproperties.ItemRemapTable
|
||||||
import net.torvald.terrarum.itemproperties.ItemTable
|
import net.torvald.terrarum.itemproperties.ItemTable
|
||||||
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
|
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
|
||||||
import net.torvald.terrarum.realestate.LandUtil
|
import net.torvald.terrarum.realestate.LandUtil
|
||||||
import net.torvald.terrarum.utils.*
|
import net.torvald.terrarum.utils.*
|
||||||
import net.torvald.terrarum.weather.WeatherMixer
|
import net.torvald.terrarum.weather.WeatherMixer
|
||||||
import net.torvald.terrarum.weather.WeatherSchedule
|
|
||||||
import net.torvald.terrarum.weather.Weatherbox
|
import net.torvald.terrarum.weather.Weatherbox
|
||||||
import net.torvald.util.SortedArrayList
|
import net.torvald.util.SortedArrayList
|
||||||
import org.dyn4j.geometry.Vector2
|
import org.dyn4j.geometry.Vector2
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.math.absoluteValue
|
|
||||||
|
|
||||||
typealias BlockAddress = Long
|
typealias BlockAddress = Long
|
||||||
|
|
||||||
@@ -40,8 +38,8 @@ class PhysicalStatus() {
|
|||||||
* Special version of GameWorld where everything, including layer data, are saved in a single JSON file (i.e. not chunked)
|
* Special version of GameWorld where everything, including layer data, are saved in a single JSON file (i.e. not chunked)
|
||||||
*/
|
*/
|
||||||
class SimpleGameWorld(width: Int, height: Int) : GameWorld(width, height) {
|
class SimpleGameWorld(width: Int, height: Int) : GameWorld(width, height) {
|
||||||
override lateinit var layerWall: BlockLayer
|
override lateinit var layerWall: BlockLayerI16
|
||||||
override lateinit var layerTerrain: BlockLayer
|
override lateinit var layerTerrain: BlockLayerI16
|
||||||
constructor() : this(0, 0)
|
constructor() : this(0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,12 +81,12 @@ open class GameWorld(
|
|||||||
}
|
}
|
||||||
|
|
||||||
//layers
|
//layers
|
||||||
@Transient lateinit open var layerWall: BlockLayer
|
@Transient lateinit open var layerWall: BlockLayerI16
|
||||||
@Transient lateinit open var layerTerrain: BlockLayer
|
@Transient lateinit open var layerTerrain: BlockLayerI16
|
||||||
val layerOres = HashedOres() // damage to the block follows `terrainDamages`
|
@Transient lateinit open var layerOres: BlockLayerI16I8 // damage to the block follows `terrainDamages`
|
||||||
val wallDamages = HashArray<Float>()
|
val wallDamages = HashArray<Float>()
|
||||||
val terrainDamages = HashArray<Float>()
|
val terrainDamages = HashArray<Float>()
|
||||||
val layerFluids = HashedFluidTypeAndFills()
|
val layerFluids = HashedFluidTypeAndFills() // TODO: chunk them using BlockLayerI32
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -201,8 +199,8 @@ open class GameWorld(
|
|||||||
this.spawnX = width / 2
|
this.spawnX = width / 2
|
||||||
this.spawnY = 150
|
this.spawnY = 150
|
||||||
|
|
||||||
layerTerrain = BlockLayer(width, height)
|
layerTerrain = BlockLayerI16(width, height)
|
||||||
layerWall = BlockLayer(width, height)
|
layerWall = BlockLayerI16(width, height)
|
||||||
|
|
||||||
// temperature layer: 2x2 is one cell
|
// temperature layer: 2x2 is one cell
|
||||||
//layerThermal = MapLayerHalfFloat(width, height, averageTemperature)
|
//layerThermal = MapLayerHalfFloat(width, height, averageTemperature)
|
||||||
@@ -277,6 +275,7 @@ open class GameWorld(
|
|||||||
fun getLayer(index: Int) = when(index) {
|
fun getLayer(index: Int) = when(index) {
|
||||||
0 -> layerTerrain
|
0 -> layerTerrain
|
||||||
1 -> layerWall
|
1 -> layerWall
|
||||||
|
2 -> layerOres
|
||||||
else -> null//throw IllegalArgumentException("Unknown layer index: $index")
|
else -> null//throw IllegalArgumentException("Unknown layer index: $index")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -549,6 +548,21 @@ open class GameWorld(
|
|||||||
throw IllegalArgumentException("illegal mode input: " + mode.toString())
|
throw IllegalArgumentException("illegal mode input: " + mode.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getTileFromOre(rawX: Int, rawY: Int): OrePlacement? {
|
||||||
|
val (x, y) = coerceXY(rawX, rawY)
|
||||||
|
val (tileNum, placement) = layerOres.unsafeGetTile(x, y)
|
||||||
|
val tileName = tileNumberToNameMap[tileNum.toLong()]
|
||||||
|
if (tileName == Block.AIR)
|
||||||
|
return null
|
||||||
|
else
|
||||||
|
return OrePlacement(tileName ?: Block.UPDATE, placement)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setTileOre(rawX: Int, rawY: Int, ore: ItemID, placement: Int) {
|
||||||
|
val (x, y) = coerceXY(rawX, rawY)
|
||||||
|
layerOres.unsafeSetTile(x, y, tileNameToNumberMap[ore]!!, placement)
|
||||||
|
}
|
||||||
|
|
||||||
fun terrainIterator(): Iterator<ItemID> {
|
fun terrainIterator(): Iterator<ItemID> {
|
||||||
return object : Iterator<ItemID> {
|
return object : Iterator<ItemID> {
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package net.torvald.terrarum.modulebasegame.gameactors
|
|||||||
import net.torvald.terrarum.App
|
import net.torvald.terrarum.App
|
||||||
import net.torvald.terrarum.BlockCodex
|
import net.torvald.terrarum.BlockCodex
|
||||||
import net.torvald.terrarum.WireCodex
|
import net.torvald.terrarum.WireCodex
|
||||||
|
import net.torvald.terrarum.gameitems.isBlock
|
||||||
|
import net.torvald.terrarum.gameitems.isWall
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by minjaesong on 2016-02-03.
|
* Created by minjaesong on 2016-02-03.
|
||||||
@@ -74,19 +76,22 @@ object PlayerBuilderSigrid {
|
|||||||
fun fillTestInventory(inventory: ActorInventory) {
|
fun fillTestInventory(inventory: ActorInventory) {
|
||||||
|
|
||||||
App.tileMaker.tags.forEach { (t, _) ->
|
App.tileMaker.tags.forEach { (t, _) ->
|
||||||
val prop = BlockCodex[t]
|
if (t.isBlock() || t.isWall()) {
|
||||||
if (!prop.isActorBlock && !prop.hasTag("AIR") && !prop.hasTag("INTERNAL")) {
|
val prop = BlockCodex[t]
|
||||||
|
if (!prop.isActorBlock && !prop.hasTag("AIR") && !prop.hasTag("INTERNAL")) {
|
||||||
|
|
||||||
inventory.add(t, 9995)
|
inventory.add(t, 9995)
|
||||||
try {
|
try {
|
||||||
inventory.add(
|
inventory.add(
|
||||||
"wall@$t",
|
"wall@$t",
|
||||||
9995
|
9995
|
||||||
) // this code will try to add nonexisting wall items, do not get surprised with NPEs
|
) // this code will try to add nonexisting wall items, do not get surprised with NPEs
|
||||||
}
|
}
|
||||||
catch (e: NullPointerException) { /* tHiS iS fInE */ }
|
catch (e: NullPointerException) { /* tHiS iS fInE */
|
||||||
catch (e: Throwable) {
|
}
|
||||||
System.err.println("[PlayerBuilder] $e")
|
catch (e: Throwable) {
|
||||||
|
System.err.println("[PlayerBuilder] $e")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,19 +4,17 @@ import com.badlogic.gdx.graphics.Pixmap
|
|||||||
import net.torvald.terrarum.*
|
import net.torvald.terrarum.*
|
||||||
import net.torvald.terrarum.App.printdbg
|
import net.torvald.terrarum.App.printdbg
|
||||||
import net.torvald.terrarum.console.Echo
|
import net.torvald.terrarum.console.Echo
|
||||||
import net.torvald.terrarum.gameworld.BlockLayer
|
import net.torvald.terrarum.gameworld.BlockLayerI16
|
||||||
import net.torvald.terrarum.gameworld.GameWorld
|
import net.torvald.terrarum.gameworld.GameWorld
|
||||||
import net.torvald.terrarum.langpack.Lang
|
import net.torvald.terrarum.langpack.Lang
|
||||||
import net.torvald.terrarum.modulebasegame.ChunkLoadingLoadScreen
|
import net.torvald.terrarum.modulebasegame.ChunkLoadingLoadScreen
|
||||||
import net.torvald.terrarum.modulebasegame.IngameRenderer
|
import net.torvald.terrarum.modulebasegame.IngameRenderer
|
||||||
import net.torvald.terrarum.modulebasegame.SavegameMigrator
|
|
||||||
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||||
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
|
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
|
||||||
import net.torvald.terrarum.realestate.LandUtil
|
import net.torvald.terrarum.realestate.LandUtil
|
||||||
import net.torvald.terrarum.savegame.*
|
import net.torvald.terrarum.savegame.*
|
||||||
import net.torvald.terrarum.savegame.VDFileID.SAVEGAMEINFO
|
import net.torvald.terrarum.savegame.VDFileID.SAVEGAMEINFO
|
||||||
import net.torvald.terrarum.serialise.Common
|
import net.torvald.terrarum.serialise.Common
|
||||||
import net.torvald.terrarum.utils.JsonFetcher
|
|
||||||
import net.torvald.terrarum.worlddrawer.WorldCamera
|
import net.torvald.terrarum.worlddrawer.WorldCamera
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.Reader
|
import java.io.Reader
|
||||||
@@ -145,8 +143,8 @@ object LoadSavegame {
|
|||||||
val worldDiskSavegameInfo = ByteArray64Reader(worldDisk.getFile(SAVEGAMEINFO)!!.bytes, Common.CHARSET)
|
val worldDiskSavegameInfo = ByteArray64Reader(worldDisk.getFile(SAVEGAMEINFO)!!.bytes, Common.CHARSET)
|
||||||
val world = ReadWorld(worldDiskSavegameInfo, worldDisk.diskFile)
|
val world = ReadWorld(worldDiskSavegameInfo, worldDisk.diskFile)
|
||||||
|
|
||||||
world.layerTerrain = BlockLayer(world.width, world.height)
|
world.layerTerrain = BlockLayerI16(world.width, world.height)
|
||||||
world.layerWall = BlockLayer(world.width, world.height)
|
world.layerWall = BlockLayerI16(world.width, world.height)
|
||||||
|
|
||||||
newIngame.world = world // must be set before the loadscreen, otherwise the loadscreen will try to read from the NullWorld which is already destroyed
|
newIngame.world = world // must be set before the loadscreen, otherwise the loadscreen will try to read from the NullWorld which is already destroyed
|
||||||
newIngame.worldDisk = VDUtil.readDiskArchive(worldDisk.diskFile, Level.INFO)
|
newIngame.worldDisk = VDUtil.readDiskArchive(worldDisk.diskFile, Level.INFO)
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import net.torvald.terrarum.ItemCodex
|
|||||||
import net.torvald.terrarum.gameactors.Actor
|
import net.torvald.terrarum.gameactors.Actor
|
||||||
import net.torvald.terrarum.gameactors.NoSerialise
|
import net.torvald.terrarum.gameactors.NoSerialise
|
||||||
import net.torvald.terrarum.gameworld.BlockLayer
|
import net.torvald.terrarum.gameworld.BlockLayer
|
||||||
|
import net.torvald.terrarum.gameworld.BlockLayerI16
|
||||||
|
import net.torvald.terrarum.gameworld.BlockLayerI16I8
|
||||||
import net.torvald.terrarum.gameworld.GameWorld
|
import net.torvald.terrarum.gameworld.GameWorld
|
||||||
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||||
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
|
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
|
||||||
@@ -82,9 +84,7 @@ object WriteWorld {
|
|||||||
val ba = ByteArray64()
|
val ba = ByteArray64()
|
||||||
for (y in cy * LandUtil.CHUNK_H until (cy + 1) * LandUtil.CHUNK_H) {
|
for (y in cy * LandUtil.CHUNK_H until (cy + 1) * LandUtil.CHUNK_H) {
|
||||||
for (x in cx * LandUtil.CHUNK_W until (cx + 1) * LandUtil.CHUNK_W) {
|
for (x in cx * LandUtil.CHUNK_W until (cx + 1) * LandUtil.CHUNK_W) {
|
||||||
val tilenum = layer.unsafeGetTile(x, y)
|
ba.appendBytes(layer.unsafeToBytes(x, y))
|
||||||
ba.appendByte(tilenum.ushr(8).and(255).toByte())
|
|
||||||
ba.appendByte(tilenum.and(255).toByte())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,17 +116,19 @@ object ReadWorld {
|
|||||||
|
|
||||||
fun decodeChunkToLayer(chunk: ByteArray64, targetLayer: BlockLayer, cx: Int, cy: Int) {
|
fun decodeChunkToLayer(chunk: ByteArray64, targetLayer: BlockLayer, cx: Int, cy: Int) {
|
||||||
val bytes = Common.unzip(chunk)
|
val bytes = Common.unzip(chunk)
|
||||||
if (bytes.size != cw * ch * 2L)
|
if (bytes.size != cw * ch * targetLayer.bytesPerBlock)
|
||||||
throw UnsupportedOperationException("Chunk size mismatch: decoded chunk size is ${bytes.size} bytes " +
|
throw UnsupportedOperationException("Chunk size mismatch: decoded chunk size is ${bytes.size} bytes " +
|
||||||
"where ${LandUtil.CHUNK_W * LandUtil.CHUNK_H * 2L} bytes (Int16 of ${LandUtil.CHUNK_W}x${LandUtil.CHUNK_H}) were expected")
|
"where ${LandUtil.CHUNK_W * LandUtil.CHUNK_H * targetLayer.bytesPerBlock} bytes (Int${8 * targetLayer.bytesPerBlock} of ${LandUtil.CHUNK_W}x${LandUtil.CHUNK_H}) were expected")
|
||||||
|
|
||||||
for (k in 0 until cw * ch) {
|
for (k in 0 until cw * ch) {
|
||||||
val tilenum = bytes[2L*k].toUint().shl(8) or bytes[2L*k + 1].toUint()
|
|
||||||
val offx = k % cw
|
val offx = k % cw
|
||||||
val offy = k / cw
|
val offy = k / cw
|
||||||
|
val ba = ByteArray(targetLayer.bytesPerBlock.toInt()) {
|
||||||
|
bytes[targetLayer.bytesPerBlock * k + it]
|
||||||
|
}
|
||||||
|
|
||||||
// try {
|
// try {
|
||||||
targetLayer.unsafeSetTile(cx * cw + offx, cy * ch + offy, tilenum)
|
targetLayer.unsafeSetTile(cx * cw + offx, cy * ch + offy, ba)
|
||||||
// }
|
// }
|
||||||
// catch (e: IndexOutOfBoundsException) {
|
// catch (e: IndexOutOfBoundsException) {
|
||||||
// printdbgerr(this, "IndexOutOfBoundsException, cx = $cx, cy = $cy, k = $k, offx = $offx, offy = $offy")
|
// printdbgerr(this, "IndexOutOfBoundsException, cx = $cx, cy = $cy, k = $k, offx = $offx, offy = $offy")
|
||||||
|
|||||||
@@ -111,6 +111,12 @@ class Terragen(world: GameWorld, seed: Long, params: Any) : Gen(world, seed, par
|
|||||||
world.setTileTerrain(x, y, newTile, true)
|
world.setTileTerrain(x, y, newTile, true)
|
||||||
|
|
||||||
world.setTileWall(x, y, newTile, true)
|
world.setTileWall(x, y, newTile, true)
|
||||||
|
|
||||||
|
|
||||||
|
// TODO TEST CODE
|
||||||
|
if (newTile == Block.DIRT) {
|
||||||
|
world.setTileOre(x, y, "ores@basegame:1", 0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -4,10 +4,9 @@ import com.badlogic.gdx.utils.Json
|
|||||||
import com.badlogic.gdx.utils.JsonValue
|
import com.badlogic.gdx.utils.JsonValue
|
||||||
import com.badlogic.gdx.utils.JsonWriter
|
import com.badlogic.gdx.utils.JsonWriter
|
||||||
import net.torvald.random.HQRNG
|
import net.torvald.random.HQRNG
|
||||||
import net.torvald.terrarum.App.printdbg
|
|
||||||
import net.torvald.terrarum.TerrarumAppConfiguration
|
import net.torvald.terrarum.TerrarumAppConfiguration
|
||||||
import net.torvald.terrarum.console.EchoError
|
import net.torvald.terrarum.console.EchoError
|
||||||
import net.torvald.terrarum.gameworld.BlockLayer
|
import net.torvald.terrarum.gameworld.BlockLayerI16
|
||||||
import net.torvald.terrarum.gameworld.GameWorld
|
import net.torvald.terrarum.gameworld.GameWorld
|
||||||
import net.torvald.terrarum.gameworld.WorldTime
|
import net.torvald.terrarum.gameworld.WorldTime
|
||||||
import net.torvald.terrarum.savegame.ByteArray64
|
import net.torvald.terrarum.savegame.ByteArray64
|
||||||
@@ -42,7 +41,7 @@ object Common {
|
|||||||
val CHARSET = Charsets.UTF_8
|
val CHARSET = Charsets.UTF_8
|
||||||
|
|
||||||
/** dispose of the `offendingObject` after rejection! */
|
/** dispose of the `offendingObject` after rejection! */
|
||||||
class BlockLayerHashMismatchError(val oldHash: String, val newHash: String, val offendingObject: BlockLayer) : Error("Old Hash $oldHash != New Hash $newHash")
|
class BlockLayerHashMismatchError(val oldHash: String, val newHash: String, val offendingObject: BlockLayerI16) : Error("Old Hash $oldHash != New Hash $newHash")
|
||||||
|
|
||||||
private fun Byte.tostr() = this.toInt().and(255).toString(16).padStart(2,'0')
|
private fun Byte.tostr() = this.toInt().and(255).toString(16).padStart(2,'0')
|
||||||
private val digester = DigestUtils.getSha256Digest()
|
private val digester = DigestUtils.getSha256Digest()
|
||||||
@@ -76,8 +75,8 @@ object Common {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
// BlockLayer
|
// BlockLayer
|
||||||
jsoner.setSerializer(BlockLayer::class.java, object : Json.Serializer<BlockLayer> {
|
jsoner.setSerializer(BlockLayerI16::class.java, object : Json.Serializer<BlockLayerI16> {
|
||||||
override fun write(json: Json, obj: BlockLayer, knownType: Class<*>?) {
|
override fun write(json: Json, obj: BlockLayerI16, knownType: Class<*>?) {
|
||||||
digester.reset()
|
digester.reset()
|
||||||
obj.bytesIterator().forEachRemaining { digester.update(it) }
|
obj.bytesIterator().forEachRemaining { digester.update(it) }
|
||||||
val hash = StringBuilder().let { sb -> digester.digest().forEach { sb.append(it.tostr()) }; sb.toString() }
|
val hash = StringBuilder().let { sb -> digester.digest().forEach { sb.append(it.tostr()) }; sb.toString() }
|
||||||
@@ -87,7 +86,7 @@ object Common {
|
|||||||
json.writeValue(layer)
|
json.writeValue(layer)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun read(json: Json, jsonData: JsonValue, type: Class<*>): BlockLayer {
|
override fun read(json: Json, jsonData: JsonValue, type: Class<*>): BlockLayerI16 {
|
||||||
// full manual
|
// full manual
|
||||||
try {
|
try {
|
||||||
return strToBlockLayer(LayerInfo(
|
return strToBlockLayer(LayerInfo(
|
||||||
@@ -437,12 +436,12 @@ object Common {
|
|||||||
* @param b a BlockLayer
|
* @param b a BlockLayer
|
||||||
* @return Bytes in [b] which are GZip'd then Ascii85-encoded
|
* @return Bytes in [b] which are GZip'd then Ascii85-encoded
|
||||||
*/
|
*/
|
||||||
private fun blockLayerToStr(b: BlockLayer): String {
|
private fun blockLayerToStr(b: BlockLayerI16): String {
|
||||||
return bytesToZipdStr(b.bytesIterator())
|
return bytesToZipdStr(b.bytesIterator())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun strToBlockLayer(layerInfo: LayerInfo): BlockLayer {
|
private fun strToBlockLayer(layerInfo: LayerInfo): BlockLayerI16 {
|
||||||
val layer = BlockLayer(layerInfo.x, layerInfo.y)
|
val layer = BlockLayerI16(layerInfo.x, layerInfo.y)
|
||||||
val unzipdBytes = strToBytes(StringReader(layerInfo.b))
|
val unzipdBytes = strToBytes(StringReader(layerInfo.b))
|
||||||
|
|
||||||
// write to blocklayer and the digester
|
// write to blocklayer and the digester
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ class CreateTileAtlas {
|
|||||||
if (dirName == "blocks") {
|
if (dirName == "blocks") {
|
||||||
// filter files that do not exist on the blockcodex
|
// filter files that do not exist on the blockcodex
|
||||||
dir.list()
|
dir.list()
|
||||||
.filter { tgaFile -> !tgaFile.isDirectory && (BlockCodex.getOrNull("$modname:${tgaFile.nameWithoutExtension()}") != null) }
|
.filter { tgaFile -> tgaFile.extension() == "tga" && !tgaFile.isDirectory && (BlockCodex.getOrNull("$modname:${tgaFile.nameWithoutExtension()}") != null) }
|
||||||
.sortedBy { it.nameWithoutExtension().toInt() }
|
.sortedBy { it.nameWithoutExtension().toInt() }
|
||||||
.forEach { tgaFile: FileHandle -> // toInt() to sort by the number, not lexicographically
|
.forEach { tgaFile: FileHandle -> // toInt() to sort by the number, not lexicographically
|
||||||
// tgaFile be like: ./assets/mods/basegame/blocks/32.tga (which is not always .tga)
|
// tgaFile be like: ./assets/mods/basegame/blocks/32.tga (which is not always .tga)
|
||||||
@@ -173,7 +173,7 @@ class CreateTileAtlas {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// TODO test
|
// TODO test
|
||||||
dir.list().filter { tgaFile -> !tgaFile.isDirectory }.sortedBy { it.nameWithoutExtension().toInt() }.forEach { tgaFile: FileHandle ->
|
dir.list().filter { tgaFile -> tgaFile.extension() == "tga" && !tgaFile.isDirectory }.sortedBy { it.nameWithoutExtension().toInt() }.forEach { tgaFile: FileHandle ->
|
||||||
val newFile = ModMgr.GameRetextureLoader.altFilePaths.getOrDefault(tgaFile.path(), tgaFile)
|
val newFile = ModMgr.GameRetextureLoader.altFilePaths.getOrDefault(tgaFile.path(), tgaFile)
|
||||||
tgaList[dirName]!!.add(modname to newFile)
|
tgaList[dirName]!!.add(modname to newFile)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -198,6 +198,7 @@ internal class UnsafePtr(pointer: Long, allocSize: Long) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun toString() = "0x${ptr.toString(16)} with size $size"
|
override fun toString() = "0x${ptr.toString(16)} with size $size"
|
||||||
|
fun toString(prefix: String) = "$prefix 0x${ptr.toString(16)} with size $size"
|
||||||
override fun equals(other: Any?) = this.ptr == (other as UnsafePtr).ptr && this.size == other.size
|
override fun equals(other: Any?) = this.ptr == (other as UnsafePtr).ptr && this.size == other.size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user