Compare commits

..

5 Commits

Author SHA1 Message Date
minjaesong
d460447331 for alpha 2 release 2024-11-16 11:12:47 +09:00
minjaesong
63fe28eee2 wrap-up commits for "not a true Alpha 2.0 release I was hoping for" 2024-11-15 23:41:25 +09:00
minjaesong
2d7ef6e9ff fix: edge detection of electric fixture not working 2024-10-31 23:40:49 +09:00
minjaesong
fa3a129991 worldportal ui fix 2024-10-31 10:53:11 +09:00
minjaesong
4cc74a85d1 fix: prev commit was made haphazardly 2024-10-30 18:10:30 +09:00
48 changed files with 903 additions and 1524 deletions

View File

@@ -132,8 +132,8 @@ id;classname;tags
320;net.torvald.terrarum.modulebasegame.gameitems.ItemWorldPortal;FIXTURE,STATION
# industrial
2048;net.torvald.terrarum.modulebasegame.gameitems.ItemInductionMotor;FIXTURE,POWER,KINETIC
2049;net.torvald.terrarum.modulebasegame.gameitems.ItemGearbox;FIXTURE,POWER,KINETIC
#2048;net.torvald.terrarum.modulebasegame.gameitems.ItemInductionMotor;FIXTURE,POWER,KINETIC
#2049;net.torvald.terrarum.modulebasegame.gameitems.ItemGearbox;FIXTURE,POWER,KINETIC
# data storage (discs; 256)
# 32768 is a reserved number for a blank disc
@@ -179,5 +179,5 @@ id;classname;tags
1048835;net.torvald.terrarum.modulebasegame.gameitems.ItemBucketIron03;FLUIDSTORAGE,OPENSTORAGE
# reserved for debug items
16777216;net.torvald.terrarum.modulebasegame.gameitems.ItemBottomlessWaterBucket;DEBUG,TOOL
16777217;net.torvald.terrarum.modulebasegame.gameitems.ItemBottomlessLavaBucket;DEBUG,TOOL
#16777216;net.torvald.terrarum.modulebasegame.gameitems.ItemBottomlessWaterBucket;DEBUG,TOOL
#16777217;net.torvald.terrarum.modulebasegame.gameitems.ItemBottomlessLavaBucket;DEBUG,TOOL
1 id classname tags
132 32774 net.torvald.terrarum.modulebasegame.gameitems.MusicDisc06 MUSIC,PHONO
133 32775 net.torvald.terrarum.modulebasegame.gameitems.MusicDisc07 MUSIC,PHONO
134 32776 net.torvald.terrarum.modulebasegame.gameitems.MusicDisc08 MUSIC,PHONO
135 32777 net.torvald.terrarum.modulebasegame.gameitems.MusicDisc09 MUSIC,PHONO
136 # data storage (tapestries 256)
137 #33024 net.torvald.terrarum.modulebasegame.gameitems.ItemTapestry FIXTURE,BASEOBJECT
138 # data storage (text signs 256)
139 33280 net.torvald.terrarum.modulebasegame.gameitems.ItemTextSignCopper FIXTURE,BASEOBJECT
179
180
181
182
183

View File

@@ -1,5 +1,6 @@
{
"ITEM_ALLOYING_FURNACE": "Alloying Furnace",
"ITEM_AXLE": "Axle",
"ITEM_BRICK_SINGULAR": "Brick", /* always singular */
"ITEM_BUCKET_IRON": "Iron Bucket %1$s",
"ITEM_BUCKET_WOODEN": "Wooden Bucket %1$s",
@@ -17,6 +18,7 @@
"ITEM_ELECTRIC_WORKBENCH": "Electric Workbench",
"ITEM_ENGRAVING_WORKBENCH": "Engraving Workbench",
"ITEM_FURNACE_AND_ANVIL": "Furnace and Anvil",
"ITEM_GEARBOX": "Gearbox",
"ITEM_GEM_RUBY": "Raw Ruby",
"ITEM_GEM_EMERALD": "Raw Emerald",
"ITEM_GEM_SAPPHIRE": "Raw Sapphire",
@@ -30,6 +32,7 @@
"ITEM_HATCHET_STEEL": "Steel Axe",
"ITEM_HATCHET_STONE": "Stone Axe",
"ITEM_HATCHET_WOODEN": "Wooden Axe",
"ITEM_INDUCTION_MOTOR": "Induction Motor",
"ITEM_INGOT_BRASS": "Brass Ingot",
"ITEM_INGOT_BRONZE": "Bronze Ingot",
"ITEM_INGOT_COPPER": "Copper Ingot",

View File

@@ -9,7 +9,7 @@ id;drop;name;renderclass;accept;inputcount;inputtype;outputtype;javaclass;invent
2;2;WIRE_POWER_HIGH;power;power_high;3;N/A;N/A;net.torvald.terrarum.modulebasegame.gameitems.WirePieceSignalWire;basegame.items,6,4;1;"POWERWIRE_HIGH"
16;16;WIRE_ETHERNET;network;10base2;3;N/A;N/A;net.torvald.terrarum.modulebasegame.gameitems.WirePieceSignalWire;basegame.items,7,4;1;"ETHERNETWIRE"
256;256;AXLE;axle;axle;1;N/A;N/A;net.torvald.terrarum.modulebasegame.gameitems.WirePieceAxle;basegame.items,1,5;0;"AXLE"
#256;256;AXLE;axle;axle;1;N/A;N/A;net.torvald.terrarum.modulebasegame.gameitems.WirePieceAxle;basegame.items,1,5;0;"AXLE"
# accept: which wiretype (defined elsewhere) the wires acceps. Use comma to separate multiple. N/A for electronic components (aka not wires)
# inputcount: how many sides are input (outputcount is deduced from the inputcount). N/A for wires
1 id drop name renderclass accept inputcount inputtype outputtype javaclass inventoryimg branching tags
9 16 16 WIRE_ETHERNET network 10base2 3 N/A N/A net.torvald.terrarum.modulebasegame.gameitems.WirePieceSignalWire basegame.items,7,4 1 ETHERNETWIRE
10 256 #256 256 AXLE axle axle 1 N/A N/A net.torvald.terrarum.modulebasegame.gameitems.WirePieceAxle basegame.items,1,5 0 AXLE
11 # accept: which wiretype (defined elsewhere) the wires acceps. Use comma to separate multiple. N/A for electronic components (aka not wires)
12 # inputcount: how many sides are input (outputcount is deduced from the inputcount). N/A for wires
13 # inputtype: which wiretype it accepts. N/A for wires
14 # outputtype: which wiretype it emits. N/A for wires
15 # branching: if this wire can have branches. Something like a thicknet can't have branches

View File

@@ -31,7 +31,6 @@ import net.torvald.terrarum.gamecontroller.KeyToggler;
import net.torvald.terrarum.gamecontroller.TerrarumKeyboardEvent;
import net.torvald.terrarum.gameitems.GameItem;
import net.torvald.terrarum.gameworld.GameWorld;
import net.torvald.terrarum.gameworld.TheGameWorld;
import net.torvald.terrarum.imagefont.BigAlphNum;
import net.torvald.terrarum.imagefont.TinyAlphNum;
import net.torvald.terrarum.langpack.Lang;
@@ -1017,7 +1016,7 @@ public class App implements ApplicationListener {
ModMgr.INSTANCE.disposeMods();
TheGameWorld.Companion.makeNullWorld().dispose();
GameWorld.Companion.makeNullWorld().dispose();
Terrarum.INSTANCE.dispose();

View File

@@ -33,7 +33,7 @@ object CheckUpdate {
private val checkUpdateURL = setOf(
"https://github.com/curioustorvald/Terrarum/releases/tag/v$versionNumOnly",
"https://github.com/curioustorvald/Terrarum/releases/tag/v$versionNumFull",
).toList()
).map { it.replace(' ', '_') }
private fun wget(url: String): String? {
printdbg(this, "wget $url")

View File

@@ -12,8 +12,6 @@ import net.torvald.terrarum.gamecontroller.KeyToggler
import net.torvald.terrarum.gamecontroller.TerrarumKeyboardEvent
import net.torvald.terrarum.gameitems.ItemID
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.TheGameWorld
import net.torvald.terrarum.gameworld.TitlescreenGameWorld
import net.torvald.terrarum.modulebasegame.IngameRenderer
import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
@@ -107,7 +105,7 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo
printStackTrace(this)
}
open var world: GameWorld = TheGameWorld.makeNullWorld()
open var world: GameWorld = GameWorld.makeNullWorld()
set(value) {
val oldWorld = field
newWorldLoadedLatch = true

View File

@@ -69,7 +69,7 @@ basegame
* e.g. 0x02010034 will be translated as 2.1.52
*
*/
const val VERSION_RAW: Long = 0x0000_000004_000004
const val VERSION_RAW: Long = 0x0000_000005_000000
// Commit counts up to the Release 0.3.0: 2259
// Commit counts up to the Release 0.3.1: 2278
// Commit counts up to the Release 0.3.2: 2732
@@ -77,6 +77,7 @@ basegame
// Commit counts up to the Release 0.4.0: 3631
// Commit counts up to the Release 0.4.1: 3678
// Commit counts up to the Release 0.4.2: 3762
// Commit counts up to the Release 0.5.0: 4090
val DEV_CYCLE: Map<String, Long> = mapOf(
"Alpha" to 0x0000_000004_000000,

View File

@@ -2,17 +2,26 @@ package net.torvald.terrarum.blockstats
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.Pixmap
import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.graphics.glutils.FrameBuffer
import com.badlogic.gdx.utils.Disposable
import com.badlogic.gdx.utils.GdxRuntimeException
import com.badlogic.gdx.utils.Queue
import net.torvald.terrarum.App
import net.torvald.terrarum.App.printdbg
import net.torvald.terrarum.abs
import net.torvald.terrarum.concurrent.ThreadExecutor
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.TheGameWorld
import net.torvald.terrarum.modulebasegame.ui.UIInventoryMinimap.Companion.MINIMAP_HEIGHT
import net.torvald.terrarum.modulebasegame.ui.UIInventoryMinimap.Companion.MINIMAP_WIDTH
import net.torvald.terrarum.sqr
import net.torvald.terrarum.toInt
import net.torvald.terrarum.worlddrawer.CreateTileAtlas.Companion.WALL_OVERLAY_COLOUR
import java.util.concurrent.Callable
import java.util.concurrent.atomic.AtomicInteger
import kotlin.math.absoluteValue
import kotlin.math.max
import kotlin.math.roundToInt
object MinimapComposer : Disposable {
@@ -23,7 +32,7 @@ object MinimapComposer : Disposable {
val MINIMAP_TILE_WIDTH = (MINIMAP_WIDTH.toInt() * 3) / SQUARE_SIZE + 4
val MINIMAP_TILE_HEIGHT = (MINIMAP_HEIGHT.toInt() * 3) / SQUARE_SIZE + 4
private var world: GameWorld = TheGameWorld.makeNullWorld()
private var world: GameWorld = GameWorld.makeNullWorld()
fun setWorld(world: GameWorld) {
try {

View File

@@ -1,7 +1,6 @@
package net.torvald.terrarum.console
import net.torvald.terrarum.*
import net.torvald.terrarum.gameworld.TheGameWorld
import net.torvald.terrarum.modulebasegame.console.GetAV.isNum
/**
@@ -9,7 +8,7 @@ import net.torvald.terrarum.modulebasegame.console.GetAV.isNum
*/
internal object GetGR : ConsoleCommand {
override fun execute(args: Array<String>) {
val gameRules = (INGAME.world as TheGameWorld).gameRules
val gameRules = INGAME.world.gameRules
// check if args[1] is number or not
if (args.size > 1 && !args[1].isNum()) { // args[1] is Gamerule name

View File

@@ -18,7 +18,6 @@ import net.torvald.terrarum.gameitems.ItemID
import net.torvald.terrarum.gameparticles.createRandomBlockParticle
import net.torvald.terrarum.gameworld.BlockAddress
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.TheGameWorld
import net.torvald.terrarum.itemproperties.Calculate
import net.torvald.terrarum.modulebasegame.TerrarumIngame
import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid

View File

@@ -5,48 +5,17 @@ import com.badlogic.gdx.utils.Disposable
/**
* Created by minjaesong on 2023-10-10.
*/
open class BlockLayer() : Disposable {
// abstract val chunkPool: ChunkPool
open val width: Int = 0
open val height: Int = 0
open val bytesPerBlock: Long = 0
open fun unsafeToBytes(x: Int, y: Int): ByteArray = byteArrayOf(0,0,0,0)
open fun unsafeSetTile(x: Int, y: Int, bytes: ByteArray) { }
// for I16; other layer must throw UnsupportedOperationException
open fun unsafeSetTile(x: Int, y: Int, tile: Int) { }
// for I16F16; other layer must throw UnsupportedOperationException
open fun unsafeSetTile(x: Int, y: Int, tile: Int, fill: Float) { }
// for I16I8; other layer must throw UnsupportedOperationException
open fun unsafeSetTile(x: Int, y: Int, tile: Int, placement: Int) { }
interface BlockLayer : Disposable {
open fun unsafeGetTile(x: Int, y: Int): Int = 0
open fun getOffset(x: Int, y: Int): Long {
return this.bytesPerBlock * (y * this.width + x)
}
open val disposed: Boolean = false
override fun dispose() {
}
open fun unsafeGetTileI16F16(x: Int, y: Int): Pair<Int, Float> = 0 to 0f
open fun unsafeGetTileI16I8(x: Int, y: Int): Pair<Int, Int> = 0 to 0
open fun unsafeSetTileKeepOrePlacement(x: Int, y: Int, tile: Int) { }
val width: Int
val height: Int
val bytesPerBlock: Long
fun unsafeToBytes(x: Int, y: Int): ByteArray
fun unsafeSetTile(x: Int, y: Int, bytes: ByteArray)
fun unsafeGetTile(x: Int, y: Int): Int
}
abstract class BlockLayerWithChunkPool : BlockLayer() {
abstract val chunkPool: ChunkPool
/**
* Unsupported for BlockLayerWithChunkPool
*/
override fun getOffset(x: Int, y: Int): Long {
throw UnsupportedOperationException()
}
}
/*inline fun BlockLayer.getOffset(x: Int, y: Int): Long {
inline fun BlockLayer.getOffset(x: Int, y: Int): Long {
return this.bytesPerBlock * (y * this.width + x)
}*/
}

View File

@@ -1,8 +1,9 @@
package net.torvald.terrarum.gameworld
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.archivers.ClusteredFormatDOM
import net.torvald.terrarum.savegame.DiskSkimmer
import net.torvald.terrarum.App
import net.torvald.terrarum.serialise.toUint
import net.torvald.unsafe.UnsafeHelper
import net.torvald.unsafe.UnsafePtr
import net.torvald.util.Float16
const val FLUID_MIN_MASS = 1f / 1024f //Ignore cells that are almost dry (smaller than epsilon of float16)
@@ -14,81 +15,97 @@ const val FLUID_MIN_MASS = 1f / 1024f //Ignore cells that are almost dry (smalle
* * ```
* * where a_n is a fluid number, f_n is a fluid fill
*
* Unsafe version Created by minjaesong on 2023-10-10.
* Chunkpool version Created by minjaesong on 2024-10-22.
* Created by minjaesong on 2023-10-10.
*/
class BlockLayerFluidI16F16 : BlockLayerWithChunkPool {
override val width: Int
override val height: Int
override val chunkPool: ChunkPool
constructor(
width: Int,
height: Int,
disk: ClusteredFormatDOM,
layerNum: Int,
world: TheGameWorld
) {
this.width = width
this.height = height
chunkPool = ChunkPool(disk, layerNum, BYTES_PER_BLOCK, world, -1, ChunkPool.getRenameFunFluids(world))
}
constructor(
width: Int,
height: Int,
disk: DiskSkimmer,
layerNum: Int,
world: TheGameWorld
) {
this.width = width
this.height = height
chunkPool = ChunkPool(disk, layerNum, BYTES_PER_BLOCK, world, -1, ChunkPool.getRenameFunFluids(world))
}
class BlockLayerFluidI16F16(override val width: Int, override val height: Int) : BlockLayer {
override val bytesPerBlock = BYTES_PER_BLOCK
override fun unsafeGetTile(x: Int, y: Int): Int {
return unsafeGetTileI16F16(x, y).first
// 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 * bytesPerBlock)
val ptrDestroyed: Boolean
get() = ptr.destroyed
init {
ptr.fillWith(-1)
}
override fun unsafeGetTileI16F16(x: Int, y: Int): Pair<Int, Float> {
val (chunk, ox, oy) = chunkPool.worldXYChunkNumAndOffset(x, y)
return chunkPool.getTileI16F16(chunk, ox, oy)
/**
* @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 * bytesPerBlock
}
override fun next(): Byte {
iteratorCount += 1
return ptr[iteratorCount - 1]
}
}
}
override fun unsafeGetTile(x: Int, y: Int): Int {
val offset = getOffset(x, y)
val lsb = ptr[offset]
val msb = ptr[offset + 1]
return lsb.toUint() or msb.toUint().shl(8)
}
internal fun unsafeGetTile1(x: Int, y: Int): Pair<Int, Float> {
val offset = getOffset(x, y)
val lsb = ptr[offset]
val msb = ptr[offset + 1]
val hbits = (ptr[offset + 2].toUint() or ptr[offset + 3].toUint().shl(8)).toShort()
val fill = Float16.toFloat(hbits)
return lsb.toUint() or msb.toUint().shl(8) to fill
}
override fun unsafeToBytes(x: Int, y: Int): ByteArray {
val (tile, fill0) = unsafeGetTileI16F16(x, y)
val fill = Float16.fromFloat(fill0).toUint()
return byteArrayOf(
((tile ushr 8) and 255).toByte(),
(tile and 255).toByte(),
((fill ushr 8) and 255).toByte(),
(fill and 255).toByte(), )
val offset = getOffset(x, y)
return byteArrayOf(ptr[offset + 1], ptr[offset + 0], ptr[offset + 3], ptr[offset + 2])
}
override fun unsafeSetTile(x: Int, y: Int, tile: Int) {
throw UnsupportedOperationException()
}
internal fun unsafeSetTile(x: Int, y: Int, tile0: Int, fill: Float) {
val offset = getOffset(x, y)
val hbits = Float16.fromFloat(fill).toInt().and(0xFFFF)
override fun unsafeSetTile(x: Int, y: Int, tile: Int, placement: Int) {
throw UnsupportedOperationException()
}
val tile = if (fill < FLUID_MIN_MASS) 0 else tile0
val lsb = tile.and(0xff).toByte()
val msb = tile.ushr(8).and(0xff).toByte()
val hlsb = hbits.and(0xff).toByte()
val hmsb = hbits.ushr(8).and(0xff).toByte()
ptr[offset] = lsb
ptr[offset + 1] = msb
ptr[offset + 2] = hlsb
ptr[offset + 3] = hmsb
override fun unsafeSetTile(x: Int, y: Int, tile0: Int, fill: Float) {
val (chunk, ox, oy) = chunkPool.worldXYChunkNumAndOffset(x, y)
val fill = Float16.fromFloat(fill).toUint()
chunkPool.setTileRaw(chunk, ox, oy, tile0.and(65535) or fill.shl(16))
}
override fun unsafeSetTile(x: Int, y: Int, bytes: ByteArray) {
val tile = bytes[1].toUint().shl(8) or bytes[0].toUint()
val fill = Float16.toFloat((bytes[3].toUint().shl(8) or bytes[2].toUint()).toShort())
unsafeSetTile(x, y, tile, fill)
val offset = getOffset(x, y)
ptr[offset] = bytes[1]
ptr[offset + 1] = bytes[0]
ptr[offset + 2] = bytes[3]
ptr[offset + 3] = bytes[2]
}
/**
@@ -106,18 +123,14 @@ class BlockLayerFluidI16F16 : BlockLayerWithChunkPool {
fun isInBound(x: Int, y: Int) = (x >= 0 && y >= 0 && x < width && y < height)
override var disposed: Boolean = false
override fun dispose() {
chunkPool.dispose()
disposed = true
ptr.destroy()
App.printdbg(this, "BlockLayerI16F16 with ptr ($ptr) successfully freed")
}
override fun toString(): String = "BlockLayerI16F16 (${width}x$height)"
override fun toString(): String = ptr.toString("BlockLayerI16F16")
companion object {
@Transient val BYTES_PER_BLOCK = 4L
private fun Short.toUint() = this.toInt().and(65535)
}
}

View File

@@ -1,10 +1,13 @@
package net.torvald.terrarum.gameworld
import com.badlogic.gdx.utils.Disposable
import net.torvald.terrarum.App.printdbg
import net.torvald.terrarum.gameworld.GameWorld.Companion.TERRAIN
import net.torvald.terrarum.gameworld.GameWorld.Companion.WALL
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.archivers.ClusteredFormatDOM
import net.torvald.terrarum.savegame.DiskSkimmer
import net.torvald.terrarum.serialise.toUint
import net.torvald.unsafe.UnsafeHelper
import net.torvald.unsafe.UnsafePtr
/**
* Memory layout:
@@ -15,89 +18,80 @@ import net.torvald.terrarum.serialise.toUint
*
* Original version Created by minjaesong on 2016-01-17.
* Unsafe version Created by minjaesong on 2019-06-08.
* Chunkpool version Created by minjaesong on 2024-10-22.
*
* Note to self: refrain from using shorts--just do away with two bytes: different system have different endianness
*/
class BlockLayerGenericI16: BlockLayerWithChunkPool {
override val width: Int
override val height: Int
override val chunkPool: ChunkPool
private var _hashcode = 0
constructor(
width: Int,
height: Int,
disk: ClusteredFormatDOM,
layerNum: Int,
world: TheGameWorld
) {
this.width = width
this.height = height
chunkPool = ChunkPool(disk, layerNum, BYTES_PER_BLOCK, world, -1, when (layerNum) {
TERRAIN -> ChunkPool.getRenameFunTerrain(world)
WALL -> ChunkPool.getRenameFunTerrain(world)
else -> throw IllegalArgumentException("Unknown layer number for I16: $layerNum")
})
_hashcode = disk.uuid.hashCode()
}
constructor(
width: Int,
height: Int,
disk: DiskSkimmer,
layerNum: Int,
world: TheGameWorld
) {
this.width = width
this.height = height
chunkPool = ChunkPool(disk, layerNum, BYTES_PER_BLOCK, world, -1, when (layerNum) {
TERRAIN -> ChunkPool.getRenameFunTerrain(world)
WALL -> ChunkPool.getRenameFunTerrain(world)
else -> throw IllegalArgumentException("Unknown layer number for I16: $layerNum")
})
_hashcode = disk.diskFile.hashCode()
}
override fun hashCode() = _hashcode
class BlockLayerGenericI16(
override val width: Int,
override 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 * bytesPerBlock)
val ptrDestroyed: Boolean
get() = ptr.destroyed
init {
ptr.fillWith(-1)
}
/**
* 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 * bytesPerBlock
}
override fun next(): Byte {
iteratorCount += 1
return ptr[iteratorCount - 1]
}
}
}
override fun unsafeGetTile(x: Int, y: Int): Int {
val (chunk, ox, oy) = chunkPool.worldXYChunkNumAndOffset(x, y)
return chunkPool.getTileI16(chunk, ox, oy)
val offset = getOffset(x, y)
val lsb = ptr[offset]
val msb = ptr[offset + 1]
return lsb.toUint() or msb.toUint().shl(8)
}
override fun unsafeToBytes(x: Int, y: Int): ByteArray {
val bytes = unsafeGetTile(x, y)
return byteArrayOf(
((bytes ushr 8) and 255).toByte(),
(bytes and 255).toByte()
)
val offset = getOffset(x, y)
return byteArrayOf(ptr[offset + 1], ptr[offset + 0])
}
override fun unsafeSetTile(x: Int, y: Int, tile: Int) {
val (chunk, ox, oy) = chunkPool.worldXYChunkNumAndOffset(x, y)
chunkPool.setTileRaw(chunk, ox, oy, tile)
}
internal fun unsafeSetTile(x: Int, y: Int, tile: Int) {
val offset = getOffset(x, y)
override fun unsafeSetTile(x: Int, y: Int, tile: Int, fill: Float) {
throw UnsupportedOperationException()
}
val lsb = tile.and(0xff).toByte()
val msb = tile.ushr(8).and(0xff).toByte()
override fun unsafeSetTile(x: Int, y: Int, tile: Int, placement: Int) {
throw UnsupportedOperationException()
// 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 tile = (0..1).fold(0) { acc, i -> acc or (bytes[i].toUint()).shl(8*i) }
unsafeSetTile(x, y, tile)
val offset = getOffset(x, y)
ptr[offset] = bytes[1]
ptr[offset + 1] = bytes[0]
}
/**
@@ -115,14 +109,12 @@ class BlockLayerGenericI16: BlockLayerWithChunkPool {
fun isInBound(x: Int, y: Int) = (x >= 0 && y >= 0 && x < width && y < height)
override var disposed: Boolean = false
override fun dispose() {
chunkPool.dispose()
disposed = true
ptr.destroy()
printdbg(this, "BlockLayerI16 with ptr ($ptr) successfully freed")
}
override fun toString(): String = "BlockLayerI16 (${width}x$height)"
override fun toString(): String = ptr.toString("BlockLayerI16")
companion object {
@Transient val BYTES_PER_BLOCK = 2L

View File

@@ -1,133 +0,0 @@
package net.torvald.terrarum.gameworld
import com.badlogic.gdx.utils.Disposable
import net.torvald.terrarum.App.printdbg
import net.torvald.terrarum.gameworld.GameWorld.Companion.TERRAIN
import net.torvald.terrarum.gameworld.GameWorld.Companion.WALL
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.archivers.ClusteredFormatDOM
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
*/
class BlockLayerInMemoryI16(
override val width: Int,
override val height: Int,
): BlockLayer() {
private constructor() : this(0, 0)
override val bytesPerBlock = BYTES_PER_BLOCK
// using unsafe pointer gets you 100 fps, whereas using directbytebuffer gets you 90
internal val ptr: UnsafePtr = UnsafeHelper.allocate(width * height * bytesPerBlock)
val ptrDestroyed: Boolean
get() = ptr.destroyed
init {
ptr.fillWith(-1)
}
/**
* 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 * bytesPerBlock
}
override fun next(): Byte {
iteratorCount += 1
return ptr[iteratorCount - 1]
}
}
}
override fun unsafeGetTile(x: Int, y: Int): Int {
val offset = getOffset(x, y)
val lsb = ptr[offset]
val msb = ptr[offset + 1]
return lsb.toUint() or msb.toUint().shl(8)
}
override fun unsafeToBytes(x: Int, y: Int): ByteArray {
val offset = getOffset(x, y)
return byteArrayOf(ptr[offset + 1], ptr[offset + 0])
}
override fun unsafeSetTile(x: Int, y: Int, tile: Int, fill: Float) {
throw UnsupportedOperationException()
}
override fun unsafeSetTile(x: Int, y: Int, tile: Int, placement: Int) {
throw UnsupportedOperationException()
}
override fun unsafeSetTile(x: Int, y: Int, tile: Int) {
val offset = getOffset(x, y)
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 = getOffset(x, y)
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 val disposed: Boolean
get() = ptr.destroyed
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
}
}

View File

@@ -1,145 +0,0 @@
package net.torvald.terrarum.gameworld
import net.torvald.terrarum.App
import net.torvald.terrarum.serialise.toUint
import net.torvald.unsafe.UnsafeHelper
import net.torvald.unsafe.UnsafePtr
import net.torvald.util.Float16
/**
* * Memory layout:
* * ```
* * a7 a6 a5 a4 a3 a2 a1 a0 | aF aE aD aC aB aA a9 a8 | f7 f6 f5 f4 f3 f2 f1 f0 | fF fE fD fC fB fA f9 f8 ||
* * ```
* * where a_n is a fluid number, f_n is a fluid fill
*
* Created by minjaesong on 2023-10-10.
*/
class BlockLayerInMemoryI16F16(override val width: Int, override 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 * bytesPerBlock)
val ptrDestroyed: Boolean
get() = ptr.destroyed
init {
ptr.fillWith(-1)
}
/**
* @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 * bytesPerBlock
}
override fun next(): Byte {
iteratorCount += 1
return ptr[iteratorCount - 1]
}
}
}
override fun unsafeGetTile(x: Int, y: Int): Int {
val offset = getOffset(x, y)
val lsb = ptr[offset]
val msb = ptr[offset + 1]
return lsb.toUint() or msb.toUint().shl(8)
}
internal fun unsafeGetTile1(x: Int, y: Int): Pair<Int, Float> {
val offset = getOffset(x, y)
val lsb = ptr[offset]
val msb = ptr[offset + 1]
val hbits = (ptr[offset + 2].toUint() or ptr[offset + 3].toUint().shl(8)).toShort()
val fill = Float16.toFloat(hbits)
return lsb.toUint() or msb.toUint().shl(8) to fill
}
override fun unsafeToBytes(x: Int, y: Int): ByteArray {
val offset = getOffset(x, y)
return byteArrayOf(ptr[offset + 1], ptr[offset + 0], ptr[offset + 3], ptr[offset + 2])
}
override fun unsafeSetTile(x: Int, y: Int, tile: Int) {
throw UnsupportedOperationException()
}
override fun unsafeSetTile(x: Int, y: Int, tile: Int, placement: Int) {
throw UnsupportedOperationException()
}
override fun unsafeSetTile(x: Int, y: Int, tile0: Int, fill: Float) {
val offset = getOffset(x, y)
val hbits = Float16.fromFloat(fill).toInt().and(0xFFFF)
val tile = if (fill < FLUID_MIN_MASS) 0 else tile0
val lsb = tile.and(0xff).toByte()
val msb = tile.ushr(8).and(0xff).toByte()
val hlsb = hbits.and(0xff).toByte()
val hmsb = hbits.ushr(8).and(0xff).toByte()
ptr[offset] = lsb
ptr[offset + 1] = msb
ptr[offset + 2] = hlsb
ptr[offset + 3] = hmsb
}
override fun unsafeSetTile(x: Int, y: Int, bytes: ByteArray) {
val offset = getOffset(x, y)
ptr[offset] = bytes[1]
ptr[offset + 1] = bytes[0]
ptr[offset + 2] = bytes[3]
ptr[offset + 3] = 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 val disposed: Boolean
get() = ptr.destroyed
override fun dispose() {
ptr.destroy()
App.printdbg(this, "BlockLayerI16F16 with ptr ($ptr) successfully freed")
}
override fun toString(): String = ptr.toString("BlockLayerI16F16")
companion object {
@Transient val BYTES_PER_BLOCK = 4L
}
}

View File

@@ -1,151 +0,0 @@
package net.torvald.terrarum.gameworld
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 BlockLayerInMemoryI16I8 (override val width: Int, override 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 * bytesPerBlock)
val ptrDestroyed: Boolean
get() = ptr.destroyed
init {
ptr.fillWith(0) // there is no NOT-GENERATED for ores, keep it as 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 * bytesPerBlock
}
override fun next(): Byte {
iteratorCount += 1
return ptr[iteratorCount - 1]
}
}
}
override fun unsafeGetTile(x: Int, y: Int): Int {
val offset = getOffset(x, y)
val lsb = ptr[offset]
val msb = ptr[offset + 1]
val placement = ptr[offset + 2]
return lsb.toUint() + msb.toUint().shl(8)
}
internal fun unsafeGetTile1(x: Int, y: Int): Pair<Int, Int> {
val offset = getOffset(x, y)
val lsb = ptr[offset]
val msb = ptr[offset + 1]
val placement = ptr[offset + 2]
return lsb.toUint() or msb.toUint().shl(8) to placement.toUint()
}
override fun unsafeToBytes(x: Int, y: Int): ByteArray {
val offset = getOffset(x, y)
return byteArrayOf(ptr[offset + 1], ptr[offset + 0], ptr[offset + 2])
}
override fun unsafeSetTile(x: Int, y: Int, tile: Int) {
throw UnsupportedOperationException()
}
override fun unsafeSetTile(x: Int, y: Int, tile: Int, fill: Float) {
throw UnsupportedOperationException()
}
override fun unsafeSetTile(x: Int, y: Int, tile: Int, placement: Int) {
val offset = getOffset(x, y)
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 = getOffset(x, y)
ptr[offset] = bytes[1]
ptr[offset + 1] = bytes[0]
ptr[offset + 2] = bytes[2]
}
override fun unsafeSetTileKeepOrePlacement(x: Int, y: Int, tile: Int) {
val offset = getOffset(x, y)
val lsb = tile.and(0xff).toByte()
val msb = tile.ushr(8).and(0xff).toByte()
ptr[offset] = lsb
ptr[offset + 1] = msb
}
/**
* @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 val disposed: Boolean
get() = ptr.destroyed
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
}
}

View File

@@ -1,8 +1,9 @@
package net.torvald.terrarum.gameworld
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.archivers.ClusteredFormatDOM
import net.torvald.terrarum.savegame.DiskSkimmer
import net.torvald.terrarum.App
import net.torvald.terrarum.serialise.toUint
import net.torvald.unsafe.UnsafeHelper
import net.torvald.unsafe.UnsafePtr
/**
* Memory layout:
@@ -10,85 +11,105 @@ import net.torvald.terrarum.serialise.toUint
* 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
*
* Unsafe version Created by minjaesong on 2023-10-10.
* Chunkpool version Created by minjaesong on 2024-10-22.
* Created by minjaesong on 2023-10-10.
*/
class BlockLayerOresI16I8 : BlockLayerWithChunkPool {
override val width: Int
override val height: Int
override val chunkPool: ChunkPool
constructor(
width: Int,
height: Int,
disk: ClusteredFormatDOM,
layerNum: Int,
world: TheGameWorld
) {
this.width = width
this.height = height
chunkPool = ChunkPool(disk, layerNum, BYTES_PER_BLOCK, world, 0, ChunkPool.getRenameFunOres(world))
}
constructor(
width: Int,
height: Int,
disk: DiskSkimmer,
layerNum: Int,
world: TheGameWorld
) {
this.width = width
this.height = height
chunkPool = ChunkPool(disk, layerNum, BYTES_PER_BLOCK, world, 0, ChunkPool.getRenameFunOres(world))
}
class BlockLayerOresI16I8 (override val width: Int, override val height: Int) : BlockLayer {
override val bytesPerBlock = BYTES_PER_BLOCK
override fun unsafeGetTile(x: Int, y: Int): Int {
return unsafeGetTileI16I8(x, y).first
// 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 * bytesPerBlock)
val ptrDestroyed: Boolean
get() = ptr.destroyed
init {
ptr.fillWith(0) // there is no NOT-GENERATED for ores, keep it as 0
}
override fun unsafeGetTileI16I8(x: Int, y: Int): Pair<Int, Int> {
val (chunk, ox, oy) = chunkPool.worldXYChunkNumAndOffset(x, y)
return chunkPool.getTileI16I8(chunk, ox, oy)
/**
* @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 * bytesPerBlock
}
override fun next(): Byte {
iteratorCount += 1
return ptr[iteratorCount - 1]
}
}
}
override fun unsafeGetTile(x: Int, y: Int): Int {
val offset = getOffset(x, y)
val lsb = ptr[offset]
val msb = ptr[offset + 1]
val placement = ptr[offset + 2]
return lsb.toUint() + msb.toUint().shl(8)
}
internal fun unsafeGetTile1(x: Int, y: Int): Pair<Int, Int> {
val offset = getOffset(x, y)
val lsb = ptr[offset]
val msb = ptr[offset + 1]
val placement = ptr[offset + 2]
return lsb.toUint() or msb.toUint().shl(8) to placement.toUint()
}
override fun unsafeToBytes(x: Int, y: Int): ByteArray {
val (tile, fill) = unsafeGetTileI16I8(x, y)
return byteArrayOf(
((tile ushr 8) and 255).toByte(),
(tile and 255).toByte(),
(fill and 255).toByte()
)
val offset = getOffset(x, y)
return byteArrayOf(ptr[offset + 1], ptr[offset + 0], ptr[offset + 2])
}
override fun unsafeSetTile(x: Int, y: Int, tile: Int) {
throw UnsupportedOperationException()
}
internal fun unsafeSetTile(x: Int, y: Int, tile: Int, placement: Int) {
val offset = getOffset(x, y)
override fun unsafeSetTile(x: Int, y: Int, tile: Int, fill: Float) {
throw UnsupportedOperationException()
}
val lsb = tile.and(0xff).toByte()
val msb = tile.ushr(8).and(0xff).toByte()
override fun unsafeSetTile(x: Int, y: Int, tile: Int, placement: Int) {
val (chunk, ox, oy) = chunkPool.worldXYChunkNumAndOffset(x, y)
chunkPool.setTileRaw(chunk, ox, oy, tile or placement.shl(16))
// 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 tile = bytes[1].toUint().shl(8) or bytes[0].toUint()
val placement = bytes[2].toUint()
unsafeSetTile(x, y, tile, placement)
val offset = getOffset(x, y)
ptr[offset] = bytes[1]
ptr[offset + 1] = bytes[0]
ptr[offset + 2] = bytes[2]
}
override fun unsafeSetTileKeepOrePlacement(x: Int, y: Int, tile: Int) {
val oldPlacement = unsafeGetTileI16I8(x, y).second
unsafeSetTile(x, y, tile, oldPlacement)
internal fun unsafeSetTileKeepPlacement(x: Int, y: Int, tile: Int) {
val offset = getOffset(x, y)
val lsb = tile.and(0xff).toByte()
val msb = tile.ushr(8).and(0xff).toByte()
ptr[offset] = lsb
ptr[offset + 1] = msb
}
/**
@@ -106,14 +127,12 @@ class BlockLayerOresI16I8 : BlockLayerWithChunkPool {
fun isInBound(x: Int, y: Int) = (x >= 0 && y >= 0 && x < width && y < height)
override var disposed: Boolean = false
override fun dispose() {
chunkPool.dispose()
disposed = true
ptr.destroy()
App.printdbg(this, "BlockLayerI16I8 with ptr ($ptr) successfully freed")
}
override fun toString(): String = "BlockLayerI16I8 (${width}x$height)"
override fun toString(): String = ptr.toString("BlockLayerI16I8")
companion object {
@Transient val BYTES_PER_BLOCK = 3L

View File

@@ -1,7 +1,6 @@
package net.torvald.terrarum.gameworld
import net.torvald.terrarum.App
import net.torvald.terrarum.App.printdbg
import net.torvald.terrarum.INGAME
import net.torvald.terrarum.Point2i
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.archivers.ClusteredFormatDOM
@@ -9,7 +8,6 @@ import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.archivers.Clustf
import net.torvald.terrarum.realestate.LandUtil
import net.torvald.terrarum.realestate.LandUtil.CHUNK_H
import net.torvald.terrarum.realestate.LandUtil.CHUNK_W
import net.torvald.terrarum.savegame.ByteArray64
import net.torvald.terrarum.savegame.DiskEntry
import net.torvald.terrarum.savegame.DiskSkimmer
import net.torvald.terrarum.savegame.EntryFile
@@ -37,74 +35,25 @@ enum class ChunkAllocClass {
}
/**
* WHAT IF instead of reading chunks directly from the savegame, I treat ChunkPool as a mere disk-cache?
*
* FIXME: loading a chunk from disk will attempt to create a chunk because the chunk-to-be-loaded
* is not on the pointers map, and this operation will want to create a new chunk file but the file already exists
*
* Single layer gets single Chunk Pool.
*
* Created by minjaesong on 2024-09-07.
*/
open class ChunkPool {
private enum class ChunkLoadingStatus {
LOADING_REQUESTED, RAW, LOADED_FROM_DISK, NEWLY_GENERATED
}
open class ChunkPool(
// `DiskSkimmer` or `ClusteredFormatDOM`
private val disk: Any
private val layerIndex: Int
private val wordSizeInBytes: Long
private val world: TheGameWorld
private val initialValue: Int // bytes to fill the new chunk
private val renumberFun: (Int) -> Int
private val chunkStatus = HashMap<Long, ChunkLoadingStatus>()
val disk: Any,
val layerIndex: Int,
val wordSizeInBytes: Long,
val world: GameWorld,
val renumberFun: (Int) -> Int,
) {
private val pointers = TreeMap<Long, Long>()
private var allocCap = 32
private var allocMap = Array<ChunkAllocation?>(allocCap) { null }
private var allocCounter = 0
private val chunkSize: Long
private val pool: UnsafePtr
constructor(
disk: DiskSkimmer,
layerIndex: Int,
wordSizeInBytes: Long,
world: TheGameWorld,
initialValue: Int,
renumberFun: (Int) -> Int,
) {
this.disk = disk
this.layerIndex = layerIndex
this.wordSizeInBytes = wordSizeInBytes
this.world = world
this.initialValue = initialValue
this.renumberFun = renumberFun
chunkSize = wordSizeInBytes * CHUNK_W * CHUNK_H
pool = UnsafeHelper.allocate(chunkSize * allocCap)
}
constructor(
disk: ClusteredFormatDOM,
layerIndex: Int,
wordSizeInBytes: Long,
world: TheGameWorld,
initialValue: Int,
renumberFun: (Int) -> Int,
) {
this.disk = disk
this.layerIndex = layerIndex
this.wordSizeInBytes = wordSizeInBytes
this.world = world
this.initialValue = initialValue
this.renumberFun = renumberFun
chunkSize = wordSizeInBytes * CHUNK_W * CHUNK_H
pool = UnsafeHelper.allocate(chunkSize * allocCap)
}
private val chunkSize = (wordSizeInBytes * CHUNK_W * CHUNK_H)
private val pool = UnsafeHelper.allocate(chunkSize * allocCap)
init {
allocMap.fill(null)
@@ -115,9 +64,6 @@ open class ChunkPool {
return UnsafePtr(baseAddr, chunkSize)
}
/**
* Returns a pointer and the offset from the pointer. The offset is given in bytes, but always word-aligned (if block offset is `(2, 0)`, the returning offset will be `8`, assuming word size of 4)
*/
private fun createPointerViewOfChunk(chunkNumber: Long, offsetX: Int, offsetY: Int): Pair<UnsafePtr, Long> {
val baseAddr = pointers[chunkNumber]!!
return UnsafePtr(baseAddr, chunkSize) to wordSizeInBytes * (offsetY * CHUNK_W + offsetX)
@@ -222,17 +168,12 @@ open class ChunkPool {
}
}
/**
* @return `unit` if IO operation was successful, `null` if failed (e.g. file not exists)
*/
private fun fetchFromDisk(chunkNumber: Long): Unit? {
private fun fetchFromDisk(chunkNumber: Long) {
val fileName = chunkNumToFileNum(layerIndex, chunkNumber)
// read data from the disk
return if (disk is ClusteredFormatDOM) {
val fileName = chunkNumToFileNumType17(layerIndex, chunkNumber)
if (disk is ClusteredFormatDOM) {
Clustfile(disk, fileName).let {
if (!it.exists()) return@let null
val bytes = Common.unzip(it.readBytes())
val ptr = allocate(chunkNumber)
UnsafeHelper.memcpyFromArrToPtr(bytes, 0, ptr.ptr, bytes.size)
@@ -240,42 +181,21 @@ open class ChunkPool {
}
}
else if (disk is DiskSkimmer) {
val fileID = chunkNumToFileEntryID(layerIndex, chunkNumber)
disk.getFile(fileID).let {
printdbg(this, "Reading chunk data: Layer $layerIndex Chunk $chunkNumber (fileID: $fileID), file: $it")
if (it == null) return@let null
val fileID = fileName.toLong()
disk.getFile(fileID)!!.let {
val bytes = Common.unzip(it.bytes)
val ptr = allocate(chunkNumber)
memcpyFromByteArray64ToPtr(bytes, 0L, ptr, 0L, bytes.size)
UnsafeHelper.memcpyFromArrToPtr(bytes, 0, ptr.ptr, bytes.size)
renumber(ptr)
}
}
else {
throw IllegalStateException()
}
}
private fun memcpyFromByteArray64ToPtr(ba: ByteArray64, srcIndex: Long, destPtr: UnsafePtr, destOffset: Long, copyLen: Long) {
// TODO temporary
val obj = ba.toByteArray()
UnsafeHelper.memcpyFromArrToPtr(obj, srcIndex.toInt(), destPtr.ptr + destOffset, copyLen)
}
/**
* @return `unit` if IO operation was successful, `null` if failed (e.g. file not exists)
*/
private fun createNewChunkFile(chunkNumber: Long): Unit? {
TODO()
}
private fun storeToDisk(chunkNumber: Long) {
val fileName = chunkNumToFileNum(layerIndex, chunkNumber)
// write to the disk (the disk must be an autosaving copy of the original)
if (disk is ClusteredFormatDOM) {
val fileName = chunkNumToFileNumType17(layerIndex, chunkNumber)
Clustfile(disk, fileName).let {
val bytes = Common.zip(serialise(chunkNumber).iterator())
it.overwrite(bytes.toByteArray())
@@ -283,7 +203,7 @@ open class ChunkPool {
}
// append the new entry
else if (disk is DiskSkimmer) {
val fileID = chunkNumToFileEntryID(layerIndex, chunkNumber)
val fileID = fileName.toLong()
val bytes = Common.zip(serialise(chunkNumber).iterator())
val oldEntry = disk.getEntry(fileID)
@@ -294,7 +214,7 @@ open class ChunkPool {
private fun checkForChunk(chunkNumber: Long) {
if (!pointers.containsKey(chunkNumber)) {
fetchFromDisk(chunkNumber) ?: createNewChunkFile(chunkNumber) ?: TODO("handle IO error")
fetchFromDisk(chunkNumber)
}
}
@@ -305,19 +225,6 @@ open class ChunkPool {
return out
}
fun worldXYChunkNumAndOffset(worldx: Int, worldy: Int): Triple<Long, Int, Int> {
val chunkX = worldx / CHUNK_W
val chunkY = worldy / CHUNK_H
val chunkOx = worldx % CHUNK_W
val chunkOy = worldy % CHUNK_H
val chunkNum = LandUtil.chunkXYtoChunkNum(world, chunkX, chunkY)
return Triple(chunkNum, chunkOx, chunkOy)
}
private fun updateAccessTime(chunkNumber: Long) {
allocMap.find { it?.chunkNumber == chunkNumber }!!.let { it.lastAccessTime = System.nanoTime() }
}
/**
* Given the word-aligned byte sequence of `[B0, B1, B2, B3, ...]`,
@@ -328,7 +235,7 @@ open class ChunkPool {
*/
fun getTileRaw(chunkNumber: Long, offX: Int, offY: Int): Int {
checkForChunk(chunkNumber)
updateAccessTime(chunkNumber)
allocMap.find { it?.chunkNumber == chunkNumber }!!.let { it.lastAccessTime = System.nanoTime() }
val (ptr, ptrOff) = createPointerViewOfChunk(chunkNumber, offX, offY)
val numIn = (0 until wordSizeInBytes.toInt()).fold(0) { acc, off ->
acc or (ptr[ptrOff].toUint().shl(8 * off))
@@ -336,23 +243,6 @@ open class ChunkPool {
return numIn
}
/**
* Given the bytes of Int `B3_B2_B1_B0`
* Saved as:
* - word size is 4: `[B0, B1, B2, B3]`
* - word size is 3: `[B0, B1, B2]` (B3 is ignored)
* - word size is 2: `[B0, B1]` (B2 and B3 are ignored)
*/
fun setTileRaw(chunkNumber: Long, offX: Int, offY: Int, bytes: Int) {
checkForChunk(chunkNumber)
updateAccessTime(chunkNumber)
val (ptr, ptrOff) = createPointerViewOfChunk(chunkNumber, offX, offY)
for (i in 0 until wordSizeInBytes.toInt()) {
val b = bytes.ushr(8*i).and(255)
ptr[ptrOff + i] = b.toByte()
}
}
/**
* Given the word-aligned byte sequence of `[B0, B1, B2, B3, ...]`,
* Return format:
@@ -390,18 +280,11 @@ open class ChunkPool {
return ibits to jbits
}
fun dispose() {
}
companion object {
fun chunkNumToFileNumType17(layerNum: Int, chunkNum: Long): String {
fun chunkNumToFileNum(layerNum: Int, chunkNum: Long): String {
val entryID = Common.layerAndChunkNumToEntryID(layerNum, chunkNum)
return Common.type254EntryIDtoType17Filename(entryID)
}
fun chunkNumToFileEntryID(layerNum: Int, chunkNum: Long): Long {
return Common.layerAndChunkNumToEntryID(layerNum, chunkNum)
}
private fun Int.get1SS() = this and 65535
private fun Int.get2SS() = (this ushr 16) and 65535
@@ -417,7 +300,7 @@ open class ChunkPool {
private fun Int.get2LSB() = this.get3MSB()
private fun Int.getLSB() = this.get4MSB()
fun getRenameFunTerrain(world: TheGameWorld): (Int) -> Int {
fun getRenameFunTerrain(world: GameWorld): (Int) -> Int {
// word size: 2
return { oldTileNum ->
val oldOreName = world.oldTileNumberToNameMap[oldTileNum.toLong()]
@@ -426,7 +309,7 @@ open class ChunkPool {
}
}
fun getRenameFunOres(world: TheGameWorld): (Int) -> Int {
fun getRenameFunOres(world: GameWorld): (Int) -> Int {
// word size: 3
return { oldTileNumRaw ->
val oldOreNum = oldTileNumRaw and 0x0000FFFF
@@ -437,7 +320,7 @@ open class ChunkPool {
}
}
fun getRenameFunFluids(world: TheGameWorld): (Int) -> Int {
fun getRenameFunFluids(world: GameWorld): (Int) -> Int {
// word size: 4
return { oldTileNumRaw ->
val oldFluidNum = oldTileNumRaw and 0x0000FFFF
@@ -448,8 +331,7 @@ open class ChunkPool {
}
}
// this list does NOT contain `Point2i(0,0)`
val chunkOffsetsNearPlayer = listOf(
private val chunkOffsetsNearPlayer = listOf(
Point2i(-1,-2), Point2i(0,-2),Point2i(1,-2),
Point2i(-2,-1),Point2i(-1,-1),Point2i(0,-1),Point2i(1,-1),Point2i(2,-1),
Point2i(-2,0),Point2i(-1,0),Point2i(1,0),Point2i(2,0),

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,6 @@ package net.torvald.terrarum.modulebasegame
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.Input.Keys
import com.badlogic.gdx.InputAdapter
import com.badlogic.gdx.files.FileHandle
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.badlogic.gdx.graphics.g2d.TextureRegion
@@ -15,14 +14,14 @@ import net.torvald.terrarum.gameactors.*
import net.torvald.terrarum.gamecontroller.TerrarumKeyboardEvent
import net.torvald.terrarum.gameitems.ItemID
import net.torvald.terrarum.gameparticles.ParticleBase
import net.torvald.terrarum.gameworld.*
import net.torvald.terrarum.gameworld.BlockLayerGenericI16
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid
import net.torvald.terrarum.gameworld.WorldTime
import net.torvald.terrarum.modulebasegame.ui.UIBuildingMakerBlockChooser
import net.torvald.terrarum.modulebasegame.ui.UIBuildingMakerPenMenu
import net.torvald.terrarum.modulebasegame.ui.UIPaletteSelector
import net.torvald.terrarum.modulebasegame.ui.UIScreenZoom
import net.torvald.terrarum.savegame.DiskSkimmer
import net.torvald.terrarum.savegame.VDUtil
import net.torvald.terrarum.serialise.Common
import net.torvald.terrarum.serialise.PointOfInterest
import net.torvald.terrarum.serialise.POILayer
@@ -62,7 +61,7 @@ class BuildingMaker(batch: FlippingSpriteBatch) : IngameInstance(batch) {
- Set…
""".trimIndent())
lateinit var gameWorld: TheGameWorld
lateinit var gameWorld: GameWorld
override val musicStreamer = TerrarumMusicAndAmbientStreamer()
@@ -420,7 +419,7 @@ class BuildingMaker(batch: FlippingSpriteBatch) : IngameInstance(batch) {
for (x in for_x_start..for_x_end) {
if (wiringCounter >= maxRenderableWires) break
val (wires, nodes) = gameWorld.getAllWiresFrom(x, y)
val (wires, nodes) = world.getAllWiresFrom(x, y)
wires?.forEach {
val wireActor = wireActorsContainer[wiringCounter]
@@ -554,7 +553,7 @@ class BuildingMaker(batch: FlippingSpriteBatch) : IngameInstance(batch) {
)
}
private fun getNearbyOres8(x: Int, y: Int): List<OrePlacement> {
return getNearbyTilesPos8(x, y).map { gameWorld.getTileFromOre(it.x, it.y) }
return getNearbyTilesPos8(x, y).map { world.getTileFromOre(it.x, it.y) }
}
private fun makePenWork(x: Int, y: Int) {
@@ -878,8 +877,8 @@ class YamlCommandToolExportTest : YamlInvokable {
ui.world.tileNameToNumberMap
)
val layer = POILayer(name)
val terr = BlockLayerInMemoryI16(poi.w, poi.h)
val wall = BlockLayerInMemoryI16(poi.w, poi.h)
val terr = BlockLayerGenericI16(poi.w, poi.h)
val wall = BlockLayerGenericI16(poi.w, poi.h)
layer.blockLayer = arrayListOf(terr, wall)
poi.layers.add(layer)
@@ -935,13 +934,8 @@ class YamlCommandNewFlatTerrain : YamlInvokable {
println("[BuildingMaker] Generating builder world...")
val tempFile = FileHandle.tempFile("terrarumbuildingmaker").file()
val tempDisk = VDUtil.createNewDisk(1L shl 30, "buildingmaker", Common.CHARSET)
VDUtil.dumpToRealMachine(tempDisk, tempFile)
val tempDiskSkimmer = DiskSkimmer(tempFile)
val timeNow = System.currentTimeMillis() / 1000
ui.gameWorld = TheGameWorld(90*12, 90*4, tempDiskSkimmer, timeNow, timeNow)
ui.gameWorld = GameWorld(90*12, 90*4, timeNow, timeNow)
// remove null tiles
for (y in 0 until ui.gameWorld.height) {

View File

@@ -4,8 +4,9 @@ import net.torvald.terrarum.BlockCodex
import net.torvald.terrarum.ItemCodex
import net.torvald.terrarum.OreCodex
import net.torvald.terrarum.ceilToInt
import net.torvald.terrarum.gameworld.BlockLayerInMemoryI16
import net.torvald.terrarum.gameworld.BlockLayerGenericI16
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.getOffset
import net.torvald.terrarum.modulebasegame.gameitems.PickaxeCore
import net.torvald.unsafe.UnsafeHelper
import java.util.concurrent.*
@@ -33,7 +34,7 @@ object ExplosionManager {
val lineMax = world.height - ty + CALC_RADIUS
// create a copy of the tilemap
val tilemap = BlockLayerInMemoryI16(CALC_WIDTH, CALC_WIDTH)
val tilemap = BlockLayerGenericI16(CALC_WIDTH, CALC_WIDTH)
val breakmap = UnsafeFloatArray(CALC_WIDTH, CALC_WIDTH)
// fill in the tilemap copy
@@ -68,9 +69,9 @@ object ExplosionManager {
}.start()
}
private fun memcpyFromWorldTiles(CALC_RADIUS: Int, CALC_WIDTH: Int, world: GameWorld, xStart: Int, yStart: Int, yOff: Int, out: BlockLayerInMemoryI16) {
private fun memcpyFromWorldTiles(CALC_RADIUS: Int, CALC_WIDTH: Int, world: GameWorld, xStart: Int, yStart: Int, yOff: Int, out: BlockLayerGenericI16) {
// if the bounding box must wrap around
/*if (xStart > world.width - CALC_RADIUS) {
if (xStart > world.width - CALC_RADIUS) {
val lenLeft = world.width - xStart
val lenRight = CALC_WIDTH - lenLeft
@@ -97,18 +98,12 @@ object ExplosionManager {
out.getOffset(0, yOff),
world.layerTerrain.bytesPerBlock * CALC_WIDTH
)
}*/
// temporary: copy one by one
for (ox in xStart until xStart + CALC_WIDTH) {
val (x, y) = world.coerceXY(ox, yStart + yOff)
val tileInWorld = world.layerTerrain.unsafeGetTile(x, y)
out.unsafeSetTile(x, y, tileInWorld)
}
}
private fun memcpyToWorldTiles(CALC_RADIUS: Int, CALC_WIDTH: Int, world: GameWorld, xStart: Int, yStart: Int, yOff: Int, out: BlockLayerInMemoryI16) {
private fun memcpyToWorldTiles(CALC_RADIUS: Int, CALC_WIDTH: Int, world: GameWorld, xStart: Int, yStart: Int, yOff: Int, out: BlockLayerGenericI16) {
// if the bounding box must wrap around
/*if (xStart > world.width - CALC_RADIUS) {
if (xStart > world.width - CALC_RADIUS) {
val lenLeft = world.width - xStart
val lenRight = CALC_WIDTH - lenLeft
@@ -135,12 +130,6 @@ object ExplosionManager {
world.layerTerrain.getOffset(xStart, yStart + yOff),
world.layerTerrain.bytesPerBlock * CALC_WIDTH
)
}*/
// temporary: copy one by one
for (ox in xStart until xStart + CALC_WIDTH) {
val (x, y) = world.coerceXY(ox, yStart + yOff)
val tileInWorld = out.unsafeGetTile(x, y)
world.layerTerrain.unsafeSetTile(x, y, tileInWorld)
}
}
@@ -166,7 +155,7 @@ object ExplosionManager {
CALC_RADIUS: Int, CALC_WIDTH: Int,
world: GameWorld,
breakmap: UnsafeFloatArray,
tilemap: BlockLayerInMemoryI16,
tilemap: BlockLayerGenericI16,
tx: Int, ty: Int,
power: Float,
dropProbNonOre: Float,

View File

@@ -17,6 +17,7 @@ import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZED
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZEF
import net.torvald.terrarum.blockproperties.Block
import net.torvald.terrarum.blockproperties.FluidCodex
import net.torvald.terrarum.gameactors.ActorWithBody
import net.torvald.terrarum.gameactors.ActorWithBody.Companion.METER
import net.torvald.terrarum.gameactors.ActorWithBody.Companion.PHYS_EPSILON_DIST
@@ -27,7 +28,6 @@ import net.torvald.terrarum.gameitems.GameItem
import net.torvald.terrarum.gameitems.mouseInInteractableRange
import net.torvald.terrarum.gameparticles.ParticleBase
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.TheGameWorld
import net.torvald.terrarum.gameworld.fmod
import net.torvald.terrarum.modulebasegame.gameactors.Pocketed
import net.torvald.terrarum.modulebasegame.gameitems.ItemThrowable
@@ -44,6 +44,8 @@ import kotlin.math.min
import kotlin.system.exitProcess
/**
* This will be rendered to a postprocessor FBO.
*
@@ -129,7 +131,7 @@ object IngameRenderer : Disposable {
//var renderingParticleCount = 0
// private set
var world: GameWorld = TheGameWorld.makeNullWorld()
var world: GameWorld = GameWorld.makeNullWorld()
private set // the grammar "IngameRenderer.world = gameWorld" seemes mundane and this function needs special care!
private var newWorldLoadedLatch = false
@@ -391,16 +393,11 @@ object IngameRenderer : Disposable {
blendNormalStraightAlpha(batch)
val (vo, vg) = if (world is TheGameWorld) {
(world as TheGameWorld).weatherbox.let {
if (it.currentWeather.identifier == "titlescreen")
1f to 1f
else
it.currentVibrancy.x to it.currentVibrancy.y
}
}
else {
1f to 1f
val (vo, vg) = world.weatherbox.let {
if (it.currentWeather.identifier == "titlescreen")
1f to 1f
else
it.currentVibrancy.x to it.currentVibrancy.y
}
mixedOutTex.texture.bind(0)

View File

@@ -28,7 +28,6 @@ import net.torvald.terrarum.gameitems.GameItem
import net.torvald.terrarum.gameitems.mouseInInteractableRange
import net.torvald.terrarum.gameparticles.ParticleBase
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.TheGameWorld
import net.torvald.terrarum.gameworld.fmod
import net.torvald.terrarum.langpack.Lang
import net.torvald.terrarum.modulebasegame.gameactors.*
@@ -47,7 +46,6 @@ import net.torvald.terrarum.modulebasegame.worldgenerator.WorldgenParams
import net.torvald.terrarum.realestate.LandUtil
import net.torvald.terrarum.realestate.LandUtil.CHUNK_H
import net.torvald.terrarum.realestate.LandUtil.CHUNK_W
import net.torvald.terrarum.savegame.DiskSkimmer
import net.torvald.terrarum.savegame.VDUtil
import net.torvald.terrarum.savegame.VirtualDisk
import net.torvald.terrarum.serialise.Common
@@ -350,7 +348,7 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
data class Codices(
val disk: VirtualDisk, // WORLD disk
val world: TheGameWorld,
val world: GameWorld,
// val meta: WriteMeta.WorldMeta,
// val block: BlockCodex,
// val item: ItemCodex,
@@ -385,8 +383,7 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
// feed info to the worldgen
if (world is TheGameWorld)
Worldgen.attachMap(world as TheGameWorld, WorldgenParams.getParamsByVersion(codices.worldGenver, world.generatorSeed))
Worldgen.attachMap(world, WorldgenParams.getParamsByVersion(codices.worldGenver, world.generatorSeed))
}
loadCallback = codices.callbackAfterLoad
@@ -446,6 +443,7 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
}
}
// try to unstuck the repositioned player
codices.player.tryUnstuck()
@@ -522,18 +520,13 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
}
else {
App.getLoadScreen().addMessage("${App.GAME_NAME} ${App.getVERSION_STRING()}")
App.getLoadScreen().addMessage("Creating new world")
val worldFile = getWorldSaveFiledesc(worldSavefileName)
VDUtil.dumpToRealMachine(worldDisk, worldFile)
val skimmer = DiskSkimmer(worldFile)
// init map as chosen size
val timeNow = App.getTIME_T()
world = TheGameWorld(worldParams.width, worldParams.height, skimmer, timeNow, timeNow) // new game, so the creation time is right now
world = GameWorld(worldParams.width, worldParams.height, timeNow, timeNow) // new game, so the creation time is right now
world.generatorSeed = worldParams.worldGenSeed
//gameworldIndices.add(world.worldIndex)
world.extraFields["basegame.economy"] = GameEconomy()

View File

@@ -24,15 +24,18 @@ import net.torvald.terrarum.gameactors.ai.ActorAI
import net.torvald.terrarum.gamecontroller.KeyToggler
import net.torvald.terrarum.gamecontroller.TerrarumKeyboardEvent
import net.torvald.terrarum.gameparticles.ParticleBase
import net.torvald.terrarum.gameworld.*
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.WorldTime
import net.torvald.terrarum.gameworld.fmod
import net.torvald.terrarum.langpack.Lang
import net.torvald.terrarum.modulebasegame.ui.UILoadGovernor
import net.torvald.terrarum.modulebasegame.ui.UIRemoCon
import net.torvald.terrarum.modulebasegame.ui.UITitleRemoConYaml
import net.torvald.terrarum.realestate.LandUtil
import net.torvald.terrarum.serialise.ReadTitlescreenGameWorld
import net.torvald.terrarum.serialise.ReadSimpleWorld
import net.torvald.terrarum.ui.Toolkit
import net.torvald.terrarum.ui.UICanvas
import net.torvald.terrarum.ui.UIItemTextButton
import net.torvald.terrarum.utils.OpenURL
import net.torvald.terrarum.weather.WeatherMixer
import net.torvald.terrarum.worlddrawer.WorldCamera
@@ -66,7 +69,7 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
//private var loadDone = false // not required; draw-while-loading is implemented in the AppLoader
private lateinit var demoWorld: TitlescreenGameWorld
private lateinit var demoWorld: GameWorld
private lateinit var cameraNodes: FloatArray // camera Y-pos
private val cameraNodeWidth = 15
private val lookaheadDist = cameraNodeWidth * TILE_SIZED
@@ -162,19 +165,19 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
val file = ModMgr.getFile("basegame", "demoworld")
val reader = java.io.FileReader(file)
//ReadWorld.readWorldAndSetNewWorld(Terrarum.ingame!! as TerrarumIngame, reader)
val world = ReadTitlescreenGameWorld(reader, file)
val world = ReadSimpleWorld(reader, file)
demoWorld = world
demoWorld.worldTime.timeDelta = 30
printdbg(this, "Demo world loaded")
}
catch (e: IOException) {
demoWorld = TitlescreenGameWorld(LandUtil.CHUNK_W, LandUtil.CHUNK_H)
demoWorld = GameWorld(LandUtil.CHUNK_W, LandUtil.CHUNK_H, 0L, 0L)
demoWorld.worldTime.timeDelta = 30
printdbg(this, "Demo world not found, using empty world")
}
this.world = demoWorld
demoWorld.renumberTilesAfterLoad()
this.world = demoWorld
// set initial time to summer
demoWorld.worldTime.addTime(WorldTime.DAY_LENGTH * 32)
@@ -362,7 +365,7 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
gdxClearAndEnableBlend(.64f, .754f, .84f, 1f)
if (!demoWorld.disposed) { // FIXME q&d hack to circumvent the dangling pointer issue #26
if (!demoWorld.layerTerrain.ptr.destroyed) { // FIXME q&d hack to circumvent the dangling pointer issue #26
WorldCamera.update(demoWorld, cameraPlayer)
IngameRenderer.invoke(

View File

@@ -12,7 +12,6 @@ import net.torvald.terrarum.gameactors.Controllable
import net.torvald.terrarum.gameitems.ItemID
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.GameWorld.Companion.FLUID
import net.torvald.terrarum.gameworld.TheGameWorld
import net.torvald.terrarum.modulebasegame.TerrarumIngame.Companion.inUpdateRange
import net.torvald.terrarum.modulebasegame.gameactors.*
import net.torvald.terrarum.modulebasegame.gameitems.AxeCore

View File

@@ -5,7 +5,6 @@ import com.badlogic.gdx.graphics.Pixmap
import com.badlogic.gdx.graphics.Texture
import net.torvald.terrarum.*
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.TheGameWorld
import net.torvald.terrarum.ui.Toolkit
import kotlin.math.roundToInt
@@ -97,7 +96,7 @@ class WorldgenLoadScreen(screenToBeLoaded: IngameInstance, private val worldwidt
try {
// q&d solution for the dangling pointer; i'm doing this only because it's this fucking load screen that's fucking the dead pointer
if (!world.layerTerrain.disposed) {
if (!world.layerTerrain.ptrDestroyed) {
val outCol = if (BlockCodex[world.getTileFromTerrain(wx, wy)].isSolid) COL_TERR
else if (BlockCodex[world.getTileFromWall(wx, wy)].isSolid) COL_WALLED
else COL_AIR

View File

@@ -4,9 +4,9 @@ import net.torvald.terrarum.App
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.console.ConsoleCommand
import net.torvald.terrarum.console.Echo
import net.torvald.terrarum.gameworld.TitlescreenGameWorld
import net.torvald.terrarum.gameworld.SimpleGameWorld
import net.torvald.terrarum.modulebasegame.TerrarumIngame
import net.torvald.terrarum.serialise.WriteTitlescreenGameWorld
import net.torvald.terrarum.serialise.WriteSimpleWorld
import java.io.File
import java.io.IOException
@@ -21,12 +21,12 @@ object ExportWorld : ConsoleCommand {
try {
val ingame = Terrarum.ingame!! as TerrarumIngame
val file = File(App.defaultDir + "/Exports/${args[1]}.json")
val simpleworld = TitlescreenGameWorld(ingame.world.width, ingame.world.height).also {
val simpleworld = SimpleGameWorld(ingame.world.width, ingame.world.height).also {
it.layerTerrain = ingame.world.layerTerrain
it.layerWall = ingame.world.layerWall
it.tileNumberToNameMap.putAll(ingame.world.tileNumberToNameMap)
}
file.writeText(WriteTitlescreenGameWorld(ingame, simpleworld, listOf()))
file.writeText(WriteSimpleWorld(ingame, simpleworld, listOf()))
Echo("Exportworld: exported the world as ${args[1]}.json")
}
catch (e: IOException) {

View File

@@ -5,7 +5,7 @@ import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.console.ConsoleCommand
import net.torvald.terrarum.console.Echo
import net.torvald.terrarum.modulebasegame.TerrarumIngame
import net.torvald.terrarum.serialise.ReadTitlescreenGameWorld
import net.torvald.terrarum.serialise.ReadSimpleWorld
import java.io.File
import java.io.IOException
@@ -20,7 +20,7 @@ object ImportWorld : ConsoleCommand {
try {
val file = File(App.defaultDir + "/Exports/${args[1]}.json")
val reader = java.io.FileReader(file)
ReadTitlescreenGameWorld.readWorldAndSetNewWorld(Terrarum.ingame!! as TerrarumIngame, reader, file)
ReadSimpleWorld.readWorldAndSetNewWorld(Terrarum.ingame!! as TerrarumIngame, reader, file)
Echo("Importworld: imported a world from ${args[1]}.json")
}
catch (e: IOException) {

View File

@@ -1,6 +1,7 @@
package net.torvald.terrarum.modulebasegame.gameactors
import net.torvald.terrarum.*
import net.torvald.terrarum.App.printdbg
import net.torvald.terrarum.gameactors.ActorID
import net.torvald.terrarum.gameactors.PhysProperties
import net.torvald.terrarum.ui.UICanvas
@@ -16,7 +17,7 @@ open class Electric : FixtureBase {
protected constructor() : super() {
oldSinkStatus = Array(blockBox.width * blockBox.height) { Vector2() }
newSinkStatus = Array(blockBox.width * blockBox.height) { Vector2() }
// newSinkStatus = Array(blockBox.width * blockBox.height) { Vector2() }
}
/**
@@ -45,7 +46,7 @@ open class Electric : FixtureBase {
App.disposables.add(mainUI)
oldSinkStatus = Array(blockBox.width * blockBox.height) { Vector2() }
newSinkStatus = Array(blockBox.width * blockBox.height) { Vector2() }
// newSinkStatus = Array(blockBox.width * blockBox.height) { Vector2() }
}
companion object {
@@ -137,7 +138,7 @@ open class Electric : FixtureBase {
getWireEmissionAt(offsetX, offsetY).x <= ELECTRIC_THRESHOLD_LOW
protected var oldSinkStatus: Array<Vector2>
protected var newSinkStatus: Array<Vector2>
// protected var newSinkStatus: Array<Vector2>
open fun updateOnWireGraphTraversal(offsetX: Int, offsetY: Int, sinkType: WireEmissionType) {
val index = pointToBlockBoxIndex(offsetX, offsetY)
@@ -149,9 +150,6 @@ open class Electric : FixtureBase {
Vector2(acc.x + (it?.x ?: 0.0), acc.y + (it?.y ?: 0.0))
}
}
oldSinkStatus[index].set(new2)
}
/**
@@ -167,35 +165,35 @@ open class Electric : FixtureBase {
for (x in 0 until blockBox.width) {
// get indices of "rising edges"
// get indices of "falling edges"
val wx = x + worldBlockPos!!.x
val wy = y + worldBlockPos!!.y
val new = WireCodex.getAllWiresThatAccepts(getWireSinkAt(x, y) ?: "").fold(Vector2()) { acc, (id, _) ->
INGAME.world.getWireEmitStateOf(wx, wy, id).let {
Vector2(acc.x + (it?.x ?: 0.0), acc.y + (it?.y ?: 0.0))
}
}
val index = pointToBlockBoxIndex(x, y)
val type = getWireSinkAt(index) ?: ""
if (new.x - oldSinkStatus[index].x >= ELECTRIC_THRESHOLD_EDGE_DELTA && new.x >= ELECTRIC_THRESHOLD_HIGH)
risingEdgeIndices.add(index)
else if (oldSinkStatus[index].x - new.x >= ELECTRIC_THRESHOLD_EDGE_DELTA && new.x <= ELECTRIC_THRESHOLD_LOW)
fallingEdgeIndices.add(index)
if (type.isNotBlank()) {
val old = oldSinkStatus[index]
val new = getWireStateAt(x, y, type)
val wx = x + worldBlockPos!!.x
val wy = y + worldBlockPos!!.y
// println("Wxy($wx,$wy) getWireState($type)=$new, oldState($type)=$old")
if (new.x - old.x >= ELECTRIC_THRESHOLD_EDGE_DELTA && new.x >= ELECTRIC_THRESHOLD_HIGH)
risingEdgeIndices.add(index)
else if (old.x - new.x >= ELECTRIC_THRESHOLD_EDGE_DELTA && new.x <= ELECTRIC_THRESHOLD_LOW)
fallingEdgeIndices.add(index)
oldSinkStatus[index].set(new)
oldSinkStatus[index].set(new)
}
}
}
// if (risingEdgeIndices.isNotEmpty()) {
// println("risingEdgeIndices=$risingEdgeIndices")
// }
risingEdgeIndices.forEach { onRisingEdge(it) }
fallingEdgeIndices.forEach { onFallingEdge(it) }
updateSignal()
/*oldSinkStatus.indices.forEach { index ->
oldSinkStatus[index].set(new)
}*/
}
}

View File

@@ -80,7 +80,7 @@ class FixtureTextSignCopper : Electric {
blockBox = BlockBox(BlockBox.NO_COLLISION, panelCount, 2)
setHitboxDimension(TILE_SIZE * blockBox.width, TILE_SIZE * blockBox.height, 0, 2)
oldSinkStatus = Array(blockBox.width * blockBox.height) { Vector2() }
newSinkStatus = Array(blockBox.width * blockBox.height) { Vector2() }
// newSinkStatus = Array(blockBox.width * blockBox.height) { Vector2() }
}
// must be re-spawned on reload to make it visible after load

View File

@@ -62,10 +62,12 @@ class FixtureWorldPortal : Electric {
}
override fun onRisingEdge(readFrom: BlockBoxIndex) {
// printdbg(this, "readFrom=$readFrom; getWireSinkAt(readFrom)=${getWireSinkAt(readFrom)}")
if (getWireSinkAt(readFrom) != "digital_bit") return
printdbg(this, "teleport! $teleportRequest")
// printdbg(this, "teleport! $teleportRequest")
teleportRequest?.let {
if (it.worldDiskToLoad != null && it.worldLoadParam != null) {
throw InternalError("Contradiction -- worldDiskToLoad and worldLoadParam are both not null: $teleportRequest")

View File

@@ -9,7 +9,6 @@ import net.torvald.terrarum.gameitems.ItemID
import net.torvald.terrarum.gameitems.isWall
import net.torvald.terrarum.gameitems.mouseInInteractableRange
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.TheGameWorld
import net.torvald.terrarum.modulebasegame.TerrarumIngame
import net.torvald.terrarum.modulebasegame.gameactors.FixtureBase

View File

@@ -1,14 +1,11 @@
package net.torvald.terrarum.modulebasegame.serialise
import net.torvald.terrarum.*
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZED
import net.torvald.terrarum.console.Echo
import net.torvald.terrarum.gameworld.*
import net.torvald.terrarum.gameworld.ChunkPool.Companion.chunkOffsetsNearPlayer
import net.torvald.terrarum.gameworld.GameWorld.Companion.FLUID
import net.torvald.terrarum.gameworld.GameWorld.Companion.ORES
import net.torvald.terrarum.gameworld.GameWorld.Companion.TERRAIN
import net.torvald.terrarum.gameworld.GameWorld.Companion.WALL
import net.torvald.terrarum.gameworld.BlockLayerGenericI16
import net.torvald.terrarum.gameworld.BlockLayerFluidI16F16
import net.torvald.terrarum.gameworld.BlockLayerOresI16I8
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.langpack.Lang
import net.torvald.terrarum.modulebasegame.FancyWorldReadLoadScreen
import net.torvald.terrarum.modulebasegame.TerrarumIngame
@@ -16,7 +13,6 @@ import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
import net.torvald.terrarum.realestate.LandUtil
import net.torvald.terrarum.savegame.*
import net.torvald.terrarum.serialise.Common
import org.dyn4j.geometry.Vector2
import java.io.Reader
import java.util.logging.Level
import kotlin.experimental.or
@@ -64,10 +60,11 @@ object LoadSavegame {
val worldDiskSavegameInfo = ByteArray64Reader(worldDisk.getFile(VDFileID.SAVEGAMEINFO)!!.bytes, Common.CHARSET)
val world = ReadWorld(worldDiskSavegameInfo, worldDisk.diskFile)
world.layerTerrain = BlockLayerGenericI16(world.width, world.height, worldDisk, TERRAIN, world)
world.layerWall = BlockLayerGenericI16(world.width, world.height, worldDisk, WALL, world)
world.layerOres = BlockLayerOresI16I8(world.width, world.height, worldDisk, ORES, world)
world.layerFluids = BlockLayerFluidI16F16(world.width, world.height, worldDisk, FLUID, world)
world.layerTerrain = BlockLayerGenericI16(world.width, world.height)
world.layerWall = BlockLayerGenericI16(world.width, world.height)
world.layerOres = BlockLayerOresI16I8(world.width, world.height)
world.layerFluids = BlockLayerFluidI16F16(world.width, world.height)
world.chunkFlags = Array(world.height / LandUtil.CHUNK_H) { ByteArray(world.width / LandUtil.CHUNK_W) }
newIngame.world = world // must be set before the loadscreen, otherwise the loadscreen will try to read from the NullWorld which is already destroyed
@@ -122,24 +119,12 @@ object LoadSavegame {
val (cx, cy) = LandUtil.chunkNumToChunkXY(world, chunk)
ReadWorld.decodeChunkToLayer(chunkFile.getContent(), worldLayer[layer]!!, cx, cy)
world.chunkFlags[cy][cx] = world.chunkFlags[cy][cx] or TheGameWorld.CHUNK_LOADED
world.chunkFlags[cy][cx] = world.chunkFlags[cy][cx] or GameWorld.CHUNK_LOADED
}
}
loadscreen.progress.getAndAdd(1)
}
val playerChunk = player.hitbox.canonVec.let {
(it.x / (cw * TILE_SIZED)).toInt() to (it.y / (ch * TILE_SIZED)).toInt()
}.let { Point2i(it.first, it.second) }
val chunksToLoad = chunkOffsetsNearPlayer.map {
playerChunk + it
} + playerChunk
/*for (layer in worldLayer) {
(layer as? BlockLayerWithChunkPool)?.chunkPool?.
}*/
loadscreen.addMessage(Lang["MENU_IO_LOAD_UPDATING_BLOCK_MAPPINGS"])
world.renumberTilesAfterLoad()

View File

@@ -4,7 +4,6 @@ import net.torvald.gdx.graphics.PixmapIO2
import net.torvald.terrarum.App.printdbg
import net.torvald.terrarum.TerrarumAppConfiguration
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.TheGameWorld
import net.torvald.terrarum.modulebasegame.IngameRenderer
import net.torvald.terrarum.modulebasegame.TerrarumIngame
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
@@ -119,7 +118,7 @@ class QuickSingleplayerWorldSavingThread(
// println("Chunk xy from number $chunkNumber -> (${chunkXY.x}, ${chunkXY.y})")
if (chunkFlag and 0x7F == TheGameWorld.CHUNK_LOADED) {
if (chunkFlag and 0x7F == GameWorld.CHUNK_LOADED) {
val chunkBytes = WriteWorld.encodeChunk(layer, cx, cy)
val entryID = 0x1_0000_0000L or layerNum.toLong().shl(24) or chunkNumber.toLong()

View File

@@ -2,11 +2,11 @@ package net.torvald.terrarum.modulebasegame.serialise
import net.torvald.gdx.graphics.PixmapIO2
import net.torvald.terrarum.*
import net.torvald.terrarum.gameworld.GameWorld.Companion.CHUNK_LOADED
import net.torvald.terrarum.gameworld.GameWorld.Companion.FLUID
import net.torvald.terrarum.gameworld.GameWorld.Companion.ORES
import net.torvald.terrarum.gameworld.GameWorld.Companion.TERRAIN
import net.torvald.terrarum.gameworld.GameWorld.Companion.WALL
import net.torvald.terrarum.gameworld.TheGameWorld.Companion.CHUNK_LOADED
import net.torvald.terrarum.modulebasegame.IngameRenderer
import net.torvald.terrarum.modulebasegame.TerrarumIngame
import net.torvald.terrarum.modulebasegame.gameactors.FixtureBase

View File

@@ -5,7 +5,6 @@ import net.torvald.terrarum.gameactors.Actor
import net.torvald.terrarum.gameactors.NoSerialise
import net.torvald.terrarum.gameworld.BlockLayer
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.TheGameWorld
import net.torvald.terrarum.modulebasegame.TerrarumIngame
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
import net.torvald.terrarum.modulebasegame.worldgenerator.RoguelikeRandomiser
@@ -96,12 +95,12 @@ object WriteWorld {
*/
object ReadWorld {
operator fun invoke(worldDataStream: Reader, origin: File?): TheGameWorld =
Common.jsoner.fromJson(TheGameWorld::class.java, worldDataStream).also {
operator fun invoke(worldDataStream: Reader, origin: File?): GameWorld =
Common.jsoner.fromJson(GameWorld::class.java, worldDataStream).also {
fillInDetails(origin, it)
}
private fun fillInDetails(origin: File?, world: TheGameWorld) {
private fun fillInDetails(origin: File?, world: GameWorld) {
world.tileNumberToNameMap.forEach { l, s ->
world.tileNameToNumberMap[s] = l.toInt()
}

View File

@@ -136,6 +136,7 @@ class UIWorldPortalSearch(val full: UIWorldPortal) : UICanvas() {
override fun show() {
clearTooltip()
uiItems.forEach { it.show() }
seedInput.clearText()
seedInput.refreshPlaceholder()

View File

@@ -15,6 +15,7 @@ import net.torvald.terrarum.serialise.toBig64
import net.torvald.terrarum.toInt
import net.torvald.terrarum.utils.OrePlacement
import net.torvald.terrarum.worlddrawer.BlocksDrawer
import kotlin.math.max
/**
* Created by minjaesong on 2023-10-26.

View File

@@ -10,7 +10,6 @@ import net.torvald.terrarum.blockproperties.Block
import net.torvald.terrarum.gameitems.ItemID
import net.torvald.terrarum.gameworld.BlockAddress
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.TheGameWorld
import net.torvald.terrarum.gameworld.fmod
import net.torvald.terrarum.langpack.Lang
import net.torvald.terrarum.modulebasegame.TerrarumIngame
@@ -164,14 +163,14 @@ object Worldgen {
val jobs = getJobs()
printdbg(this, "Generating chunk on ($cx, $cy)")
Thread {
world.chunkFlags[cy][cx] = TheGameWorld.CHUNK_GENERATING
world.chunkFlags[cy][cx] = GameWorld.CHUNK_GENERATING
for (i in jobs.indices) {
val it = jobs[i]
it.theWork.getChunkDone(cx, cy)
}
world.chunkFlags[cy][cx] = TheGameWorld.CHUNK_LOADED
world.chunkFlags[cy][cx] = GameWorld.CHUNK_LOADED
callback(cx, cy)
}.let {
it.priority = 2
@@ -567,7 +566,7 @@ abstract class Gen(val world: GameWorld, val isFinal: Boolean, val seed: Long, v
draw(chunkX * LandUtil.CHUNK_W, chunkY * CHUNK_H, localJoise, sampleOffset)
loadscreen?.progress?.addAndGet(1L)
world.chunkFlags[chunkY][chunkX] = if (isFinal) TheGameWorld.CHUNK_LOADED else TheGameWorld.CHUNK_GENERATING
world.chunkFlags[chunkY][chunkX] = if (isFinal) GameWorld.CHUNK_LOADED else GameWorld.CHUNK_GENERATING
}
}
}

View File

@@ -10,9 +10,8 @@ import io.airlift.compress.zstd.ZstdOutputStream
import net.torvald.random.HQRNG
import net.torvald.terrarum.*
import net.torvald.terrarum.console.EchoError
import net.torvald.terrarum.gameworld.BlockLayerInMemoryI16
import net.torvald.terrarum.gameworld.BlockLayerGenericI16
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.TheGameWorld
import net.torvald.terrarum.gameworld.WorldTime
import net.torvald.terrarum.savegame.ByteArray64
import net.torvald.terrarum.savegame.ByteArray64GrowableOutputStream
@@ -42,7 +41,7 @@ object Common {
val CHARSET = Charsets.UTF_8
/** dispose of the `offendingObject` after rejection! */
class BlockLayerHashMismatchError(val oldHash: String, val newHash: String, val offendingObject: BlockLayerInMemoryI16) : Error("Old Hash $oldHash != New Hash $newHash")
class BlockLayerHashMismatchError(val oldHash: String, val newHash: String, val offendingObject: BlockLayerGenericI16) : 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()
@@ -75,8 +74,8 @@ object Common {
}
})
// BlockLayer
it.setSerializer(BlockLayerInMemoryI16::class.java, object : Json.Serializer<BlockLayerInMemoryI16> {
override fun write(json: Json, obj: BlockLayerInMemoryI16, knownType: Class<*>?) {
it.setSerializer(BlockLayerGenericI16::class.java, object : Json.Serializer<BlockLayerGenericI16> {
override fun write(json: Json, obj: BlockLayerGenericI16, knownType: Class<*>?) {
digester.reset()
obj.bytesIterator().forEachRemaining { digester.update(it) }
val hash = StringBuilder().let { sb -> digester.digest().forEach { sb.append(it.tostr()) }; sb.toString() }
@@ -86,7 +85,7 @@ object Common {
json.writeValue(layer)
}
override fun read(json: Json, jsonData: JsonValue, type: Class<*>): BlockLayerInMemoryI16 {
override fun read(json: Json, jsonData: JsonValue, type: Class<*>): BlockLayerGenericI16 {
// full manual
try {
return strToBlockLayer(LayerInfo(
@@ -436,12 +435,12 @@ object Common {
* @param b a BlockLayer
* @return Bytes in [b] which are GZip'd then Ascii85-encoded
*/
private fun blockLayerToStr(b: BlockLayerInMemoryI16): String {
private fun blockLayerToStr(b: BlockLayerGenericI16): String {
return bytesToZipdStr(b.bytesIterator())
}
private fun strToBlockLayer(layerInfo: LayerInfo): BlockLayerInMemoryI16 {
val layer = BlockLayerInMemoryI16(layerInfo.x, layerInfo.y)
private fun strToBlockLayer(layerInfo: LayerInfo): BlockLayerGenericI16 {
val layer = BlockLayerGenericI16(layerInfo.x, layerInfo.y)
val unzipdBytes = strToBytes(StringReader(layerInfo.b))
// write to blocklayer and the digester

View File

@@ -6,7 +6,6 @@ import net.torvald.terrarum.TerrarumAppConfiguration
import net.torvald.terrarum.blockproperties.Block
import net.torvald.terrarum.gameitems.ItemID
import net.torvald.terrarum.gameworld.BlockLayerGenericI16
import net.torvald.terrarum.gameworld.BlockLayerInMemoryI16
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.GameWorld.Companion.TERRAIN
import net.torvald.terrarum.gameworld.GameWorld.Companion.WALL
@@ -129,7 +128,7 @@ class POILayer(
constructor() : this("undefined")
@Transient var name = name
@Transient internal lateinit var blockLayer: ArrayList<BlockLayerInMemoryI16>
@Transient internal lateinit var blockLayer: ArrayList<BlockLayerGenericI16>
@Transient internal lateinit var dat: Array<ByteArray>
@Deprecated("Used for debug print", ReplaceWith("name")) @Transient internal var id = ""
@@ -180,10 +179,10 @@ class POILayer(
if (::blockLayer.isInitialized) {
blockLayer.forEach { it.dispose() }
}
blockLayer = ArrayList()
blockLayer = ArrayList<BlockLayerGenericI16>()
dat.forEachIndexed { layerIndex, layer ->
val currentBlockLayer = BlockLayerInMemoryI16(width, height).also {
val currentBlockLayer = BlockLayerGenericI16(width, height).also {
blockLayer.add(it)
}
for (w in 0 until layer.size / byteLength) {

View File

@@ -4,53 +4,56 @@ import net.torvald.terrarum.App
import net.torvald.terrarum.IngameInstance
import net.torvald.terrarum.ItemCodex
import net.torvald.terrarum.gameactors.Actor
import net.torvald.terrarum.gameworld.*
import net.torvald.terrarum.modulebasegame.IngameRenderer
import net.torvald.terrarum.gameworld.BlockLayerFluidI16F16
import net.torvald.terrarum.gameworld.BlockLayerOresI16I8
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.SimpleGameWorld
import java.io.File
import java.io.Reader
/**
* Created by minjaesong on 2022-09-03.
*/
object ReadTitlescreenGameWorld {
object ReadSimpleWorld {
operator fun invoke(worldDataStream: Reader, origin: File?): TitlescreenGameWorld =
Common.jsoner.fromJson(TitlescreenGameWorld::class.java, worldDataStream).also {
operator fun invoke(worldDataStream: Reader, origin: File?): GameWorld =
Common.jsoner.fromJson(SimpleGameWorld::class.java, worldDataStream).also {
fillInDetails(origin, it)
}
private fun fillInDetails(origin: File?, world: TitlescreenGameWorld) {
private fun fillInDetails(origin: File?, world: GameWorld) {
world.tileNumberToNameMap.forEach { l, s ->
world.tileNameToNumberMap[s] = l.toInt()
}
world.layerOres = BlockLayerInMemoryI16I8(world.width, world.height)
world.layerFluids = BlockLayerInMemoryI16F16(world.width, world.height)
world.layerOres = BlockLayerOresI16I8(world.width, world.height)
world.layerFluids = BlockLayerFluidI16F16(world.width, world.height)
ItemCodex.loadFromSave(origin, world.dynamicToStaticTable, world.dynamicItemInventory)
}
fun readWorldAndSetNewWorld(ingame: IngameInstance, worldDataStream: Reader, origin: File?): TitlescreenGameWorld {
fun readWorldAndSetNewWorld(ingame: IngameInstance, worldDataStream: Reader, origin: File?): GameWorld {
val world = invoke(worldDataStream, origin)
ingame.world = world
return world
}
}
object WriteTitlescreenGameWorld {
object WriteSimpleWorld {
private fun preWrite(ingame: IngameInstance, time_t: Long, world: TitlescreenGameWorld, actorsList: List<Actor>) {
private fun preWrite(ingame: IngameInstance, time_t: Long, world: SimpleGameWorld, actorsList: List<Actor>) {
val currentPlayTime_t = time_t - ingame.loadedTime_t
world.comp = Common.getCompIndex()
world.lastPlayTime = time_t
world.totalPlayTime += currentPlayTime_t
// world.actors.clear()
// world.actors.addAll(actorsList.map { it.referenceID }.sorted().distinct())
world.actors.clear()
world.actors.addAll(actorsList.map { it.referenceID }.sorted().distinct())
}
operator fun invoke(ingame: IngameInstance, world: TitlescreenGameWorld, actorsList: List<Actor>): String {
operator fun invoke(ingame: IngameInstance, world: SimpleGameWorld, actorsList: List<Actor>): String {
val time_t = App.getTIME_T()
preWrite(ingame, time_t, world, actorsList)
val s = Common.jsoner.toJson(world)

View File

@@ -18,7 +18,6 @@ import net.torvald.terrarum.audio.AudioMixer.Companion.DS_FLTIDX_PAN
import net.torvald.terrarum.audio.dsp.*
import net.torvald.terrarum.controller.TerrarumController
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.TheGameWorld
import net.torvald.terrarum.gameworld.fmod
import net.torvald.terrarum.imagefont.TinyAlphNum
import net.torvald.terrarum.modulebasegame.IngameRenderer
@@ -316,7 +315,7 @@ class BasicDebugInfoWindow : UICanvas() {
val wallNum = it.getTileFromWall(mouseTileX, mouseTileY)
val tileNum = it.getTileFromTerrain(mouseTileX, mouseTileY)
val (oreNum, orePlacement) = it.getTileFromOre(mouseTileX, mouseTileY)
val wires = if (it is TheGameWorld) it.getAllWiresFrom(mouseTileX, mouseTileY) else null to null
val wires = it.getAllWiresFrom(mouseTileX, mouseTileY)
val fluid = it.getFluid(mouseTileX, mouseTileY)
val wireCount = wires.first?.size?.toString() ?: "no"
val tdmg = it.getTerrainDamage(mouseTileX, mouseTileY).toIntAndFrac(2,2)

View File

@@ -136,6 +136,7 @@ abstract class UICanvas(
/** A function that is run ONCE when the UI is requested to be opened; will work identical to [endOpening] if [openCloseTime] is zero */
open fun show() {
clearTooltip()
openingClickLatched = true
uiItems.forEach { it.show() }
handler.subUIs.forEach { it.show() }

View File

@@ -1,6 +1,8 @@
package net.torvald.terrarum.utils
import com.badlogic.gdx.utils.Json
import com.badlogic.gdx.utils.JsonValue
import net.torvald.terrarum.gameactors.ActorValue
import net.torvald.terrarum.gameitems.ItemID
import net.torvald.terrarum.gameworld.BlockAddress

View File

@@ -17,7 +17,9 @@ import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZEF
import net.torvald.terrarum.blockproperties.Block
import net.torvald.terrarum.gamecontroller.KeyToggler
import net.torvald.terrarum.gameitems.ItemID
import net.torvald.terrarum.gameworld.*
import net.torvald.terrarum.gameworld.FLUID_MIN_MASS
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.fmod
import net.torvald.terrarum.modulebasegame.worldgenerator.shake
import net.torvald.terrarum.realestate.LandUtil
import net.torvald.terrarum.serialise.toBig64
@@ -41,7 +43,7 @@ import kotlin.math.roundToInt
internal object BlocksDrawer {
/** World change is managed by IngameRenderer.setWorld() */
internal var world: GameWorld = TheGameWorld.makeNullWorld()
internal var world: GameWorld = GameWorld.makeNullWorld()
/**
@@ -446,10 +448,6 @@ internal object BlocksDrawer {
*/
private fun fillInTileBuffer(mode: Int) {
// don't render fluid and ores for TitlescreenGameWorld (for now)
if (world.layerFluids !is BlockLayerFluidI16F16) return
if (world.layerOres !is BlockLayerOresI16I8) return
// TODO the real fluid rendering must use separate function, but its code should be similar to this.
// shader's tileAtlas will be fluid.tga, pixels written to the buffer is in accordance with the new
// atlas. IngameRenderer must be modified so that fluid-draw call is separated from drawing tiles.
@@ -469,7 +467,7 @@ internal object BlocksDrawer {
WALL -> world.layerWall.unsafeGetTile(wx, wy)
TERRAIN -> world.layerTerrain.unsafeGetTile(wx, wy)
ORES -> world.layerOres.unsafeGetTile(wx, wy)//.also { println(it) }
FLUID -> world.layerFluids.unsafeGetTileI16F16(wx, wy).let { (number, fill) ->
FLUID -> world.layerFluids.unsafeGetTile1(wx, wy).let { (number, fill) ->
if (number == 65535 || fill < 1f/30f) 0
else number
}
@@ -499,7 +497,7 @@ internal object BlocksDrawer {
val nearbyFluidType = fluids.asSequence().filter { it.amount >= 0.5f / 16f }.map { it.type }.filter { it.startsWith("fluid@") }.sorted().firstOrNull()
val fillThis =
world.layerFluids.unsafeGetTileI16F16(wx, wy).second.let { if (it.isNaN()) 0f else it.coerceAtMost(1f) }
world.layerFluids.unsafeGetTile1(wx, wy).second.let { if (it.isNaN()) 0f else it.coerceAtMost(1f) }
val tile = world.getTileFromTerrain(wx, wy)
@@ -673,7 +671,7 @@ internal object BlocksDrawer {
rawTileNum + nearbyTilesInfo
// special case: ores
else if (mode == ORES)
rawTileNum + world.layerOres.unsafeGetTileI16I8(wx, wy).second
rawTileNum + world.layerOres.unsafeGetTile1(wx, wy).second
// rest of the cases: terrain and walls
else rawTileNum + when (renderTag.maskType) {
CreateTileAtlas.RenderTag.MASK_NA -> 0
@@ -1190,7 +1188,7 @@ internal object BlocksDrawer {
get() {
val rate = (((Gdx.graphics.framesPerSecond / 50f) * TILE_SIZEF) / maxOf(WorldCamera.deltaX.abs(), WorldCamera.deltaY.abs()).coerceAtLeast(1)).roundToInt().coerceIn(1, 4)
App.debugTimers.put("Renderer.tilemapUpdateDivider", rate.toLong())
return (!world.layerTerrain.disposed && App.GLOBAL_RENDER_TIMER % rate == 0L)
return (!world.layerTerrain.ptrDestroyed && App.GLOBAL_RENDER_TIMER % rate == 0L)
}
private var camTransX = 0

View File

@@ -1,11 +1,13 @@
package net.torvald.terrarum.worlddrawer
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.jme3.math.FastMath
import net.torvald.colourutil.ColourTemp
import net.torvald.terrarum.*
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZEF
import net.torvald.terrarum.blockproperties.Block
import net.torvald.terrarum.blockstats.TileSurvey
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.TheGameWorld
import net.torvald.terrarum.ui.Toolkit
import kotlin.math.roundToInt
@@ -15,7 +17,7 @@ import kotlin.math.roundToInt
object FeaturesDrawer {
/** World change is managed by IngameRenderer.setWorld() */
internal var world: GameWorld = TheGameWorld.makeNullWorld()
internal var world: GameWorld = GameWorld.makeNullWorld()
//const val TILE_SIZE = TILE_SIZE

View File

@@ -19,7 +19,6 @@ import net.torvald.terrarum.gameitems.GameItem
import net.torvald.terrarum.gameitems.isBlock
import net.torvald.terrarum.gameworld.BlockAddress
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.TheGameWorld
import net.torvald.terrarum.modulebasegame.IngameRenderer
import net.torvald.terrarum.modulebasegame.gameactors.Pocketed
import net.torvald.terrarum.modulebasegame.ui.abs
@@ -44,7 +43,7 @@ import kotlin.math.*
object LightmapRenderer {
/** World change is managed by IngameRenderer.setWorld() */
private var world: GameWorld = TheGameWorld.makeNullWorld()
private var world: GameWorld = GameWorld.makeNullWorld()
//private lateinit var lightCalcShader: ShaderProgram
//private val SHADER_LIGHTING = AppLoader.getConfigBoolean("gpulightcalc")
@@ -142,7 +141,7 @@ object LightmapRenderer {
}
fun recalculate(actorContainer: List<ActorWithBody>) {
if (!world.layerTerrain.disposed) _recalculate(actorContainer, lightmap)
if (!world.layerTerrain.ptrDestroyed) _recalculate(actorContainer, lightmap)
}
private fun _recalculate(actorContainer: List<ActorWithBody>, lightmap: UnsafeCvecArray) {
@@ -154,7 +153,7 @@ object LightmapRenderer {
}
catch (e: NullPointerException) {
System.err.println("[LightmapRendererNew.recalculate] Attempted to refer destroyed unsafe array " +
"(${world.layerTerrain})")
"(${world.layerTerrain.ptr})")
e.printStackTrace()
return // something's wrong but we'll ignore it like a trustful AK
}
@@ -657,7 +656,7 @@ object LightmapRenderer {
internal fun draw(): Texture {
if (!world.layerTerrain.disposed) {
if (!world.layerTerrain.ptrDestroyed) {
// when shader is not used: 0.5 ms on 6700K
App.measureDebugTime("Renderer.LightToScreen") {