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 320;net.torvald.terrarum.modulebasegame.gameitems.ItemWorldPortal;FIXTURE,STATION
# industrial # industrial
2048;net.torvald.terrarum.modulebasegame.gameitems.ItemInductionMotor;FIXTURE,POWER,KINETIC #2048;net.torvald.terrarum.modulebasegame.gameitems.ItemInductionMotor;FIXTURE,POWER,KINETIC
2049;net.torvald.terrarum.modulebasegame.gameitems.ItemGearbox;FIXTURE,POWER,KINETIC #2049;net.torvald.terrarum.modulebasegame.gameitems.ItemGearbox;FIXTURE,POWER,KINETIC
# data storage (discs; 256) # data storage (discs; 256)
# 32768 is a reserved number for a blank disc # 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 1048835;net.torvald.terrarum.modulebasegame.gameitems.ItemBucketIron03;FLUIDSTORAGE,OPENSTORAGE
# reserved for debug items # reserved for debug items
16777216;net.torvald.terrarum.modulebasegame.gameitems.ItemBottomlessWaterBucket;DEBUG,TOOL #16777216;net.torvald.terrarum.modulebasegame.gameitems.ItemBottomlessWaterBucket;DEBUG,TOOL
16777217;net.torvald.terrarum.modulebasegame.gameitems.ItemBottomlessLavaBucket;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_ALLOYING_FURNACE": "Alloying Furnace",
"ITEM_AXLE": "Axle",
"ITEM_BRICK_SINGULAR": "Brick", /* always singular */ "ITEM_BRICK_SINGULAR": "Brick", /* always singular */
"ITEM_BUCKET_IRON": "Iron Bucket %1$s", "ITEM_BUCKET_IRON": "Iron Bucket %1$s",
"ITEM_BUCKET_WOODEN": "Wooden Bucket %1$s", "ITEM_BUCKET_WOODEN": "Wooden Bucket %1$s",
@@ -17,6 +18,7 @@
"ITEM_ELECTRIC_WORKBENCH": "Electric Workbench", "ITEM_ELECTRIC_WORKBENCH": "Electric Workbench",
"ITEM_ENGRAVING_WORKBENCH": "Engraving Workbench", "ITEM_ENGRAVING_WORKBENCH": "Engraving Workbench",
"ITEM_FURNACE_AND_ANVIL": "Furnace and Anvil", "ITEM_FURNACE_AND_ANVIL": "Furnace and Anvil",
"ITEM_GEARBOX": "Gearbox",
"ITEM_GEM_RUBY": "Raw Ruby", "ITEM_GEM_RUBY": "Raw Ruby",
"ITEM_GEM_EMERALD": "Raw Emerald", "ITEM_GEM_EMERALD": "Raw Emerald",
"ITEM_GEM_SAPPHIRE": "Raw Sapphire", "ITEM_GEM_SAPPHIRE": "Raw Sapphire",
@@ -30,6 +32,7 @@
"ITEM_HATCHET_STEEL": "Steel Axe", "ITEM_HATCHET_STEEL": "Steel Axe",
"ITEM_HATCHET_STONE": "Stone Axe", "ITEM_HATCHET_STONE": "Stone Axe",
"ITEM_HATCHET_WOODEN": "Wooden Axe", "ITEM_HATCHET_WOODEN": "Wooden Axe",
"ITEM_INDUCTION_MOTOR": "Induction Motor",
"ITEM_INGOT_BRASS": "Brass Ingot", "ITEM_INGOT_BRASS": "Brass Ingot",
"ITEM_INGOT_BRONZE": "Bronze Ingot", "ITEM_INGOT_BRONZE": "Bronze Ingot",
"ITEM_INGOT_COPPER": "Copper 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" 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" 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) # 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 # 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.gamecontroller.TerrarumKeyboardEvent;
import net.torvald.terrarum.gameitems.GameItem; import net.torvald.terrarum.gameitems.GameItem;
import net.torvald.terrarum.gameworld.GameWorld; import net.torvald.terrarum.gameworld.GameWorld;
import net.torvald.terrarum.gameworld.TheGameWorld;
import net.torvald.terrarum.imagefont.BigAlphNum; import net.torvald.terrarum.imagefont.BigAlphNum;
import net.torvald.terrarum.imagefont.TinyAlphNum; import net.torvald.terrarum.imagefont.TinyAlphNum;
import net.torvald.terrarum.langpack.Lang; import net.torvald.terrarum.langpack.Lang;
@@ -1017,7 +1016,7 @@ public class App implements ApplicationListener {
ModMgr.INSTANCE.disposeMods(); ModMgr.INSTANCE.disposeMods();
TheGameWorld.Companion.makeNullWorld().dispose(); GameWorld.Companion.makeNullWorld().dispose();
Terrarum.INSTANCE.dispose(); Terrarum.INSTANCE.dispose();

View File

@@ -33,7 +33,7 @@ object CheckUpdate {
private val checkUpdateURL = setOf( private val checkUpdateURL = setOf(
"https://github.com/curioustorvald/Terrarum/releases/tag/v$versionNumOnly", "https://github.com/curioustorvald/Terrarum/releases/tag/v$versionNumOnly",
"https://github.com/curioustorvald/Terrarum/releases/tag/v$versionNumFull", "https://github.com/curioustorvald/Terrarum/releases/tag/v$versionNumFull",
).toList() ).map { it.replace(' ', '_') }
private fun wget(url: String): String? { private fun wget(url: String): String? {
printdbg(this, "wget $url") 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.gamecontroller.TerrarumKeyboardEvent
import net.torvald.terrarum.gameitems.ItemID import net.torvald.terrarum.gameitems.ItemID
import net.torvald.terrarum.gameworld.GameWorld 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.IngameRenderer
import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
@@ -107,7 +105,7 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo
printStackTrace(this) printStackTrace(this)
} }
open var world: GameWorld = TheGameWorld.makeNullWorld() open var world: GameWorld = GameWorld.makeNullWorld()
set(value) { set(value) {
val oldWorld = field val oldWorld = field
newWorldLoadedLatch = true newWorldLoadedLatch = true

View File

@@ -69,7 +69,7 @@ basegame
* e.g. 0x02010034 will be translated as 2.1.52 * 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.0: 2259
// Commit counts up to the Release 0.3.1: 2278 // Commit counts up to the Release 0.3.1: 2278
// Commit counts up to the Release 0.3.2: 2732 // 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.0: 3631
// Commit counts up to the Release 0.4.1: 3678 // 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.4.2: 3762
// Commit counts up to the Release 0.5.0: 4090
val DEV_CYCLE: Map<String, Long> = mapOf( val DEV_CYCLE: Map<String, Long> = mapOf(
"Alpha" to 0x0000_000004_000000, "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.Color
import com.badlogic.gdx.graphics.Pixmap 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.Disposable
import com.badlogic.gdx.utils.GdxRuntimeException
import com.badlogic.gdx.utils.Queue
import net.torvald.terrarum.App 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.concurrent.ThreadExecutor
import net.torvald.terrarum.gameworld.GameWorld 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_HEIGHT
import net.torvald.terrarum.modulebasegame.ui.UIInventoryMinimap.Companion.MINIMAP_WIDTH import net.torvald.terrarum.modulebasegame.ui.UIInventoryMinimap.Companion.MINIMAP_WIDTH
import net.torvald.terrarum.sqr
import net.torvald.terrarum.toInt import net.torvald.terrarum.toInt
import net.torvald.terrarum.worlddrawer.CreateTileAtlas.Companion.WALL_OVERLAY_COLOUR import net.torvald.terrarum.worlddrawer.CreateTileAtlas.Companion.WALL_OVERLAY_COLOUR
import java.util.concurrent.Callable import java.util.concurrent.Callable
import java.util.concurrent.atomic.AtomicInteger
import kotlin.math.absoluteValue
import kotlin.math.max import kotlin.math.max
import kotlin.math.roundToInt
object MinimapComposer : Disposable { object MinimapComposer : Disposable {
@@ -23,7 +32,7 @@ object MinimapComposer : Disposable {
val MINIMAP_TILE_WIDTH = (MINIMAP_WIDTH.toInt() * 3) / SQUARE_SIZE + 4 val MINIMAP_TILE_WIDTH = (MINIMAP_WIDTH.toInt() * 3) / SQUARE_SIZE + 4
val MINIMAP_TILE_HEIGHT = (MINIMAP_HEIGHT.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) { fun setWorld(world: GameWorld) {
try { try {

View File

@@ -1,7 +1,6 @@
package net.torvald.terrarum.console package net.torvald.terrarum.console
import net.torvald.terrarum.* import net.torvald.terrarum.*
import net.torvald.terrarum.gameworld.TheGameWorld
import net.torvald.terrarum.modulebasegame.console.GetAV.isNum import net.torvald.terrarum.modulebasegame.console.GetAV.isNum
/** /**
@@ -9,7 +8,7 @@ import net.torvald.terrarum.modulebasegame.console.GetAV.isNum
*/ */
internal object GetGR : ConsoleCommand { internal object GetGR : ConsoleCommand {
override fun execute(args: Array<String>) { 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 // check if args[1] is number or not
if (args.size > 1 && !args[1].isNum()) { // args[1] is Gamerule name 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.gameparticles.createRandomBlockParticle
import net.torvald.terrarum.gameworld.BlockAddress import net.torvald.terrarum.gameworld.BlockAddress
import net.torvald.terrarum.gameworld.GameWorld import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.TheGameWorld
import net.torvald.terrarum.itemproperties.Calculate import net.torvald.terrarum.itemproperties.Calculate
import net.torvald.terrarum.modulebasegame.TerrarumIngame import net.torvald.terrarum.modulebasegame.TerrarumIngame
import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid 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. * Created by minjaesong on 2023-10-10.
*/ */
open class BlockLayer() : Disposable { interface 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) { }
open fun unsafeGetTile(x: Int, y: Int): Int = 0 val width: Int
val height: Int
open fun getOffset(x: Int, y: Int): Long { val bytesPerBlock: Long
return this.bytesPerBlock * (y * this.width + x) fun unsafeToBytes(x: Int, y: Int): ByteArray
} fun unsafeSetTile(x: Int, y: Int, bytes: ByteArray)
fun unsafeGetTile(x: Int, y: Int): Int
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) { }
} }
abstract class BlockLayerWithChunkPool : BlockLayer() { inline fun BlockLayer.getOffset(x: Int, y: Int): Long {
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 {
return this.bytesPerBlock * (y * this.width + x) return this.bytesPerBlock * (y * this.width + x)
}*/ }

View File

@@ -1,8 +1,9 @@
package net.torvald.terrarum.gameworld package net.torvald.terrarum.gameworld
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.archivers.ClusteredFormatDOM import net.torvald.terrarum.App
import net.torvald.terrarum.savegame.DiskSkimmer
import net.torvald.terrarum.serialise.toUint import net.torvald.terrarum.serialise.toUint
import net.torvald.unsafe.UnsafeHelper
import net.torvald.unsafe.UnsafePtr
import net.torvald.util.Float16 import net.torvald.util.Float16
const val FLUID_MIN_MASS = 1f / 1024f //Ignore cells that are almost dry (smaller than epsilon of 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 * * where a_n is a fluid number, f_n is a fluid fill
* *
* Unsafe version Created by minjaesong on 2023-10-10. * Created by minjaesong on 2023-10-10.
* Chunkpool version Created by minjaesong on 2024-10-22.
*/ */
class BlockLayerFluidI16F16 : BlockLayerWithChunkPool { class BlockLayerFluidI16F16(override val width: Int, override val height: Int) : BlockLayer {
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))
}
override val bytesPerBlock = BYTES_PER_BLOCK override val bytesPerBlock = BYTES_PER_BLOCK
override fun unsafeGetTile(x: Int, y: Int): Int { // for some reason, all the efforts of saving the memory space were futile.
return unsafeGetTileI16F16(x, y).first
// 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) * @param data Byte array representation of the layer
return chunkPool.getTileI16F16(chunk, ox, oy) */
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 { override fun unsafeToBytes(x: Int, y: Int): ByteArray {
val (tile, fill0) = unsafeGetTileI16F16(x, y) val offset = getOffset(x, y)
val fill = Float16.fromFloat(fill0).toUint() return byteArrayOf(ptr[offset + 1], ptr[offset + 0], ptr[offset + 3], ptr[offset + 2])
return byteArrayOf(
((tile ushr 8) and 255).toByte(),
(tile and 255).toByte(),
((fill ushr 8) and 255).toByte(),
(fill and 255).toByte(), )
} }
override fun unsafeSetTile(x: Int, y: Int, tile: Int) { internal fun unsafeSetTile(x: Int, y: Int, tile0: Int, fill: Float) {
throw UnsupportedOperationException() val offset = getOffset(x, y)
} val hbits = Float16.fromFloat(fill).toInt().and(0xFFFF)
override fun unsafeSetTile(x: Int, y: Int, tile: Int, placement: Int) { val tile = if (fill < FLUID_MIN_MASS) 0 else tile0
throw UnsupportedOperationException()
} 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) { override fun unsafeSetTile(x: Int, y: Int, bytes: ByteArray) {
val tile = bytes[1].toUint().shl(8) or bytes[0].toUint() val offset = getOffset(x, y)
val fill = Float16.toFloat((bytes[3].toUint().shl(8) or bytes[2].toUint()).toShort()) ptr[offset] = bytes[1]
unsafeSetTile(x, y, tile, fill) 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) fun isInBound(x: Int, y: Int) = (x >= 0 && y >= 0 && x < width && y < height)
override var disposed: Boolean = false
override fun dispose() { override fun dispose() {
chunkPool.dispose() ptr.destroy()
disposed = true 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 { companion object {
@Transient val BYTES_PER_BLOCK = 4L @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 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.TERRAIN
import net.torvald.terrarum.gameworld.GameWorld.Companion.WALL import net.torvald.terrarum.gameworld.GameWorld.Companion.WALL
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.archivers.ClusteredFormatDOM import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.archivers.ClusteredFormatDOM
import net.torvald.terrarum.savegame.DiskSkimmer
import net.torvald.terrarum.serialise.toUint import net.torvald.terrarum.serialise.toUint
import net.torvald.unsafe.UnsafeHelper
import net.torvald.unsafe.UnsafePtr
/** /**
* Memory layout: * Memory layout:
@@ -15,89 +18,80 @@ import net.torvald.terrarum.serialise.toUint
* *
* Original version Created by minjaesong on 2016-01-17. * Original version Created by minjaesong on 2016-01-17.
* Unsafe version Created by minjaesong on 2019-06-08. * 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 * Note to self: refrain from using shorts--just do away with two bytes: different system have different endianness
*/ */
class BlockLayerGenericI16: BlockLayerWithChunkPool { class BlockLayerGenericI16(
override val width: Int,
override val width: Int override val height: Int,
override val height: Int ): BlockLayer {
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
override val bytesPerBlock = BYTES_PER_BLOCK 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 { override fun unsafeGetTile(x: Int, y: Int): Int {
val (chunk, ox, oy) = chunkPool.worldXYChunkNumAndOffset(x, y) val offset = getOffset(x, y)
return chunkPool.getTileI16(chunk, ox, oy) 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 { override fun unsafeToBytes(x: Int, y: Int): ByteArray {
val bytes = unsafeGetTile(x, y) val offset = getOffset(x, y)
return byteArrayOf( return byteArrayOf(ptr[offset + 1], ptr[offset + 0])
((bytes ushr 8) and 255).toByte(),
(bytes and 255).toByte()
)
} }
override fun unsafeSetTile(x: Int, y: Int, tile: Int) { internal fun unsafeSetTile(x: Int, y: Int, tile: Int) {
val (chunk, ox, oy) = chunkPool.worldXYChunkNumAndOffset(x, y) val offset = getOffset(x, y)
chunkPool.setTileRaw(chunk, ox, oy, tile)
}
override fun unsafeSetTile(x: Int, y: Int, tile: Int, fill: Float) { val lsb = tile.and(0xff).toByte()
throw UnsupportedOperationException() 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) { 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) } val offset = getOffset(x, y)
unsafeSetTile(x, y, tile) 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) fun isInBound(x: Int, y: Int) = (x >= 0 && y >= 0 && x < width && y < height)
override var disposed: Boolean = false
override fun dispose() { override fun dispose() {
chunkPool.dispose() ptr.destroy()
disposed = true 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 { companion object {
@Transient val BYTES_PER_BLOCK = 2L @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 package net.torvald.terrarum.gameworld
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.archivers.ClusteredFormatDOM import net.torvald.terrarum.App
import net.torvald.terrarum.savegame.DiskSkimmer
import net.torvald.terrarum.serialise.toUint import net.torvald.terrarum.serialise.toUint
import net.torvald.unsafe.UnsafeHelper
import net.torvald.unsafe.UnsafePtr
/** /**
* Memory layout: * 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 || * 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 * where a_n is a tile number, p_n is a placement index
* * Created by minjaesong on 2023-10-10.
* Unsafe version Created by minjaesong on 2023-10-10.
* Chunkpool version Created by minjaesong on 2024-10-22.
*/ */
class BlockLayerOresI16I8 : BlockLayerWithChunkPool { class BlockLayerOresI16I8 (override val width: Int, override val height: Int) : BlockLayer {
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))
}
override val bytesPerBlock = BYTES_PER_BLOCK override val bytesPerBlock = BYTES_PER_BLOCK
override fun unsafeGetTile(x: Int, y: Int): Int { // for some reason, all the efforts of saving the memory space were futile.
return unsafeGetTileI16I8(x, y).first
// 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) * @param data Byte array representation of the layer
return chunkPool.getTileI16I8(chunk, ox, oy) */
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 { override fun unsafeToBytes(x: Int, y: Int): ByteArray {
val (tile, fill) = unsafeGetTileI16I8(x, y) val offset = getOffset(x, y)
return byteArrayOf( return byteArrayOf(ptr[offset + 1], ptr[offset + 0], ptr[offset + 2])
((tile ushr 8) and 255).toByte(),
(tile and 255).toByte(),
(fill and 255).toByte()
)
} }
override fun unsafeSetTile(x: Int, y: Int, tile: Int) { internal fun unsafeSetTile(x: Int, y: Int, tile: Int, placement: Int) {
throw UnsupportedOperationException() val offset = getOffset(x, y)
}
override fun unsafeSetTile(x: Int, y: Int, tile: Int, fill: Float) { val lsb = tile.and(0xff).toByte()
throw UnsupportedOperationException() 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) // try {
chunkPool.setTileRaw(chunk, ox, oy, tile or placement.shl(16)) 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) { override fun unsafeSetTile(x: Int, y: Int, bytes: ByteArray) {
val tile = bytes[1].toUint().shl(8) or bytes[0].toUint() val offset = getOffset(x, y)
val placement = bytes[2].toUint() ptr[offset] = bytes[1]
unsafeSetTile(x, y, tile, placement) ptr[offset + 1] = bytes[0]
ptr[offset + 2] = bytes[2]
} }
override fun unsafeSetTileKeepOrePlacement(x: Int, y: Int, tile: Int) { internal fun unsafeSetTileKeepPlacement(x: Int, y: Int, tile: Int) {
val oldPlacement = unsafeGetTileI16I8(x, y).second val offset = getOffset(x, y)
unsafeSetTile(x, y, tile, oldPlacement)
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) fun isInBound(x: Int, y: Int) = (x >= 0 && y >= 0 && x < width && y < height)
override var disposed: Boolean = false
override fun dispose() { override fun dispose() {
chunkPool.dispose() ptr.destroy()
disposed = true 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 { companion object {
@Transient val BYTES_PER_BLOCK = 3L @Transient val BYTES_PER_BLOCK = 3L

View File

@@ -1,7 +1,6 @@
package net.torvald.terrarum.gameworld package net.torvald.terrarum.gameworld
import net.torvald.terrarum.App import net.torvald.terrarum.App
import net.torvald.terrarum.App.printdbg
import net.torvald.terrarum.INGAME import net.torvald.terrarum.INGAME
import net.torvald.terrarum.Point2i import net.torvald.terrarum.Point2i
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.archivers.ClusteredFormatDOM 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
import net.torvald.terrarum.realestate.LandUtil.CHUNK_H import net.torvald.terrarum.realestate.LandUtil.CHUNK_H
import net.torvald.terrarum.realestate.LandUtil.CHUNK_W 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.DiskEntry
import net.torvald.terrarum.savegame.DiskSkimmer import net.torvald.terrarum.savegame.DiskSkimmer
import net.torvald.terrarum.savegame.EntryFile 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. * Single layer gets single Chunk Pool.
* *
* Created by minjaesong on 2024-09-07. * Created by minjaesong on 2024-09-07.
*/ */
open class ChunkPool { open class ChunkPool(
private enum class ChunkLoadingStatus {
LOADING_REQUESTED, RAW, LOADED_FROM_DISK, NEWLY_GENERATED
}
// `DiskSkimmer` or `ClusteredFormatDOM` // `DiskSkimmer` or `ClusteredFormatDOM`
private val disk: Any val disk: Any,
private val layerIndex: Int val layerIndex: Int,
private val wordSizeInBytes: Long val wordSizeInBytes: Long,
private val world: TheGameWorld val world: GameWorld,
private val initialValue: Int // bytes to fill the new chunk val renumberFun: (Int) -> Int,
private val renumberFun: (Int) -> Int ) {
private val chunkStatus = HashMap<Long, ChunkLoadingStatus>()
private val pointers = TreeMap<Long, Long>() private val pointers = TreeMap<Long, Long>()
private var allocCap = 32 private var allocCap = 32
private var allocMap = Array<ChunkAllocation?>(allocCap) { null } private var allocMap = Array<ChunkAllocation?>(allocCap) { null }
private var allocCounter = 0 private var allocCounter = 0
private val chunkSize: Long
private val pool: UnsafePtr
constructor( private val chunkSize = (wordSizeInBytes * CHUNK_W * CHUNK_H)
disk: DiskSkimmer, private val pool = UnsafeHelper.allocate(chunkSize * allocCap)
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)
}
init { init {
allocMap.fill(null) allocMap.fill(null)
@@ -115,9 +64,6 @@ open class ChunkPool {
return UnsafePtr(baseAddr, chunkSize) 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> { private fun createPointerViewOfChunk(chunkNumber: Long, offsetX: Int, offsetY: Int): Pair<UnsafePtr, Long> {
val baseAddr = pointers[chunkNumber]!! val baseAddr = pointers[chunkNumber]!!
return UnsafePtr(baseAddr, chunkSize) to wordSizeInBytes * (offsetY * CHUNK_W + offsetX) return UnsafePtr(baseAddr, chunkSize) to wordSizeInBytes * (offsetY * CHUNK_W + offsetX)
@@ -222,17 +168,12 @@ open class ChunkPool {
} }
} }
/** private fun fetchFromDisk(chunkNumber: Long) {
* @return `unit` if IO operation was successful, `null` if failed (e.g. file not exists) val fileName = chunkNumToFileNum(layerIndex, chunkNumber)
*/
private fun fetchFromDisk(chunkNumber: Long): Unit? {
// read data from the disk // read data from the disk
return if (disk is ClusteredFormatDOM) { if (disk is ClusteredFormatDOM) {
val fileName = chunkNumToFileNumType17(layerIndex, chunkNumber)
Clustfile(disk, fileName).let { Clustfile(disk, fileName).let {
if (!it.exists()) return@let null
val bytes = Common.unzip(it.readBytes()) val bytes = Common.unzip(it.readBytes())
val ptr = allocate(chunkNumber) val ptr = allocate(chunkNumber)
UnsafeHelper.memcpyFromArrToPtr(bytes, 0, ptr.ptr, bytes.size) UnsafeHelper.memcpyFromArrToPtr(bytes, 0, ptr.ptr, bytes.size)
@@ -240,42 +181,21 @@ open class ChunkPool {
} }
} }
else if (disk is DiskSkimmer) { else if (disk is DiskSkimmer) {
val fileID = chunkNumToFileEntryID(layerIndex, chunkNumber) val fileID = fileName.toLong()
disk.getFile(fileID)!!.let {
disk.getFile(fileID).let {
printdbg(this, "Reading chunk data: Layer $layerIndex Chunk $chunkNumber (fileID: $fileID), file: $it")
if (it == null) return@let null
val bytes = Common.unzip(it.bytes) val bytes = Common.unzip(it.bytes)
val ptr = allocate(chunkNumber) val ptr = allocate(chunkNumber)
memcpyFromByteArray64ToPtr(bytes, 0L, ptr, 0L, bytes.size) UnsafeHelper.memcpyFromArrToPtr(bytes, 0, ptr.ptr, bytes.size)
renumber(ptr) 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) { private fun storeToDisk(chunkNumber: Long) {
val fileName = chunkNumToFileNum(layerIndex, chunkNumber)
// write to the disk (the disk must be an autosaving copy of the original) // write to the disk (the disk must be an autosaving copy of the original)
if (disk is ClusteredFormatDOM) { if (disk is ClusteredFormatDOM) {
val fileName = chunkNumToFileNumType17(layerIndex, chunkNumber)
Clustfile(disk, fileName).let { Clustfile(disk, fileName).let {
val bytes = Common.zip(serialise(chunkNumber).iterator()) val bytes = Common.zip(serialise(chunkNumber).iterator())
it.overwrite(bytes.toByteArray()) it.overwrite(bytes.toByteArray())
@@ -283,7 +203,7 @@ open class ChunkPool {
} }
// append the new entry // append the new entry
else if (disk is DiskSkimmer) { else if (disk is DiskSkimmer) {
val fileID = chunkNumToFileEntryID(layerIndex, chunkNumber) val fileID = fileName.toLong()
val bytes = Common.zip(serialise(chunkNumber).iterator()) val bytes = Common.zip(serialise(chunkNumber).iterator())
val oldEntry = disk.getEntry(fileID) val oldEntry = disk.getEntry(fileID)
@@ -294,7 +214,7 @@ open class ChunkPool {
private fun checkForChunk(chunkNumber: Long) { private fun checkForChunk(chunkNumber: Long) {
if (!pointers.containsKey(chunkNumber)) { if (!pointers.containsKey(chunkNumber)) {
fetchFromDisk(chunkNumber) ?: createNewChunkFile(chunkNumber) ?: TODO("handle IO error") fetchFromDisk(chunkNumber)
} }
} }
@@ -305,19 +225,6 @@ open class ChunkPool {
return out 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, ...]`, * 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 { fun getTileRaw(chunkNumber: Long, offX: Int, offY: Int): Int {
checkForChunk(chunkNumber) checkForChunk(chunkNumber)
updateAccessTime(chunkNumber) allocMap.find { it?.chunkNumber == chunkNumber }!!.let { it.lastAccessTime = System.nanoTime() }
val (ptr, ptrOff) = createPointerViewOfChunk(chunkNumber, offX, offY) val (ptr, ptrOff) = createPointerViewOfChunk(chunkNumber, offX, offY)
val numIn = (0 until wordSizeInBytes.toInt()).fold(0) { acc, off -> val numIn = (0 until wordSizeInBytes.toInt()).fold(0) { acc, off ->
acc or (ptr[ptrOff].toUint().shl(8 * off)) acc or (ptr[ptrOff].toUint().shl(8 * off))
@@ -336,23 +243,6 @@ open class ChunkPool {
return numIn 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, ...]`, * Given the word-aligned byte sequence of `[B0, B1, B2, B3, ...]`,
* Return format: * Return format:
@@ -390,18 +280,11 @@ open class ChunkPool {
return ibits to jbits return ibits to jbits
} }
fun dispose() {
}
companion object { companion object {
fun chunkNumToFileNumType17(layerNum: Int, chunkNum: Long): String { fun chunkNumToFileNum(layerNum: Int, chunkNum: Long): String {
val entryID = Common.layerAndChunkNumToEntryID(layerNum, chunkNum) val entryID = Common.layerAndChunkNumToEntryID(layerNum, chunkNum)
return Common.type254EntryIDtoType17Filename(entryID) 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.get1SS() = this and 65535
private fun Int.get2SS() = (this ushr 16) 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.get2LSB() = this.get3MSB()
private fun Int.getLSB() = this.get4MSB() private fun Int.getLSB() = this.get4MSB()
fun getRenameFunTerrain(world: TheGameWorld): (Int) -> Int { fun getRenameFunTerrain(world: GameWorld): (Int) -> Int {
// word size: 2 // word size: 2
return { oldTileNum -> return { oldTileNum ->
val oldOreName = world.oldTileNumberToNameMap[oldTileNum.toLong()] 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 // word size: 3
return { oldTileNumRaw -> return { oldTileNumRaw ->
val oldOreNum = oldTileNumRaw and 0x0000FFFF 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 // word size: 4
return { oldTileNumRaw -> return { oldTileNumRaw ->
val oldFluidNum = oldTileNumRaw and 0x0000FFFF val oldFluidNum = oldTileNumRaw and 0x0000FFFF
@@ -448,8 +331,7 @@ open class ChunkPool {
} }
} }
// this list does NOT contain `Point2i(0,0)` private val chunkOffsetsNearPlayer = listOf(
val chunkOffsetsNearPlayer = listOf(
Point2i(-1,-2), Point2i(0,-2),Point2i(1,-2), 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,-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), 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.Gdx
import com.badlogic.gdx.Input.Keys import com.badlogic.gdx.Input.Keys
import com.badlogic.gdx.InputAdapter import com.badlogic.gdx.InputAdapter
import com.badlogic.gdx.files.FileHandle
import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.g2d.SpriteBatch import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.badlogic.gdx.graphics.g2d.TextureRegion 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.gamecontroller.TerrarumKeyboardEvent
import net.torvald.terrarum.gameitems.ItemID import net.torvald.terrarum.gameitems.ItemID
import net.torvald.terrarum.gameparticles.ParticleBase 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.modulebasegame.gameactors.ActorHumanoid
import net.torvald.terrarum.gameworld.WorldTime
import net.torvald.terrarum.modulebasegame.ui.UIBuildingMakerBlockChooser import net.torvald.terrarum.modulebasegame.ui.UIBuildingMakerBlockChooser
import net.torvald.terrarum.modulebasegame.ui.UIBuildingMakerPenMenu import net.torvald.terrarum.modulebasegame.ui.UIBuildingMakerPenMenu
import net.torvald.terrarum.modulebasegame.ui.UIPaletteSelector import net.torvald.terrarum.modulebasegame.ui.UIPaletteSelector
import net.torvald.terrarum.modulebasegame.ui.UIScreenZoom 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.Common
import net.torvald.terrarum.serialise.PointOfInterest import net.torvald.terrarum.serialise.PointOfInterest
import net.torvald.terrarum.serialise.POILayer import net.torvald.terrarum.serialise.POILayer
@@ -62,7 +61,7 @@ class BuildingMaker(batch: FlippingSpriteBatch) : IngameInstance(batch) {
- Set… - Set…
""".trimIndent()) """.trimIndent())
lateinit var gameWorld: TheGameWorld lateinit var gameWorld: GameWorld
override val musicStreamer = TerrarumMusicAndAmbientStreamer() override val musicStreamer = TerrarumMusicAndAmbientStreamer()
@@ -420,7 +419,7 @@ class BuildingMaker(batch: FlippingSpriteBatch) : IngameInstance(batch) {
for (x in for_x_start..for_x_end) { for (x in for_x_start..for_x_end) {
if (wiringCounter >= maxRenderableWires) break if (wiringCounter >= maxRenderableWires) break
val (wires, nodes) = gameWorld.getAllWiresFrom(x, y) val (wires, nodes) = world.getAllWiresFrom(x, y)
wires?.forEach { wires?.forEach {
val wireActor = wireActorsContainer[wiringCounter] val wireActor = wireActorsContainer[wiringCounter]
@@ -554,7 +553,7 @@ class BuildingMaker(batch: FlippingSpriteBatch) : IngameInstance(batch) {
) )
} }
private fun getNearbyOres8(x: Int, y: Int): List<OrePlacement> { 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) { private fun makePenWork(x: Int, y: Int) {
@@ -878,8 +877,8 @@ class YamlCommandToolExportTest : YamlInvokable {
ui.world.tileNameToNumberMap ui.world.tileNameToNumberMap
) )
val layer = POILayer(name) val layer = POILayer(name)
val terr = BlockLayerInMemoryI16(poi.w, poi.h) val terr = BlockLayerGenericI16(poi.w, poi.h)
val wall = BlockLayerInMemoryI16(poi.w, poi.h) val wall = BlockLayerGenericI16(poi.w, poi.h)
layer.blockLayer = arrayListOf(terr, wall) layer.blockLayer = arrayListOf(terr, wall)
poi.layers.add(layer) poi.layers.add(layer)
@@ -935,13 +934,8 @@ class YamlCommandNewFlatTerrain : YamlInvokable {
println("[BuildingMaker] Generating builder world...") 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 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 // remove null tiles
for (y in 0 until ui.gameWorld.height) { 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.ItemCodex
import net.torvald.terrarum.OreCodex import net.torvald.terrarum.OreCodex
import net.torvald.terrarum.ceilToInt 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.GameWorld
import net.torvald.terrarum.gameworld.getOffset
import net.torvald.terrarum.modulebasegame.gameitems.PickaxeCore import net.torvald.terrarum.modulebasegame.gameitems.PickaxeCore
import net.torvald.unsafe.UnsafeHelper import net.torvald.unsafe.UnsafeHelper
import java.util.concurrent.* import java.util.concurrent.*
@@ -33,7 +34,7 @@ object ExplosionManager {
val lineMax = world.height - ty + CALC_RADIUS val lineMax = world.height - ty + CALC_RADIUS
// create a copy of the tilemap // 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) val breakmap = UnsafeFloatArray(CALC_WIDTH, CALC_WIDTH)
// fill in the tilemap copy // fill in the tilemap copy
@@ -68,9 +69,9 @@ object ExplosionManager {
}.start() }.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 the bounding box must wrap around
/*if (xStart > world.width - CALC_RADIUS) { if (xStart > world.width - CALC_RADIUS) {
val lenLeft = world.width - xStart val lenLeft = world.width - xStart
val lenRight = CALC_WIDTH - lenLeft val lenRight = CALC_WIDTH - lenLeft
@@ -97,18 +98,12 @@ object ExplosionManager {
out.getOffset(0, yOff), out.getOffset(0, yOff),
world.layerTerrain.bytesPerBlock * CALC_WIDTH 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 the bounding box must wrap around
/*if (xStart > world.width - CALC_RADIUS) { if (xStart > world.width - CALC_RADIUS) {
val lenLeft = world.width - xStart val lenLeft = world.width - xStart
val lenRight = CALC_WIDTH - lenLeft val lenRight = CALC_WIDTH - lenLeft
@@ -135,12 +130,6 @@ object ExplosionManager {
world.layerTerrain.getOffset(xStart, yStart + yOff), world.layerTerrain.getOffset(xStart, yStart + yOff),
world.layerTerrain.bytesPerBlock * CALC_WIDTH 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, CALC_RADIUS: Int, CALC_WIDTH: Int,
world: GameWorld, world: GameWorld,
breakmap: UnsafeFloatArray, breakmap: UnsafeFloatArray,
tilemap: BlockLayerInMemoryI16, tilemap: BlockLayerGenericI16,
tx: Int, ty: Int, tx: Int, ty: Int,
power: Float, power: Float,
dropProbNonOre: 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_SIZED
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZEF import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZEF
import net.torvald.terrarum.blockproperties.Block import net.torvald.terrarum.blockproperties.Block
import net.torvald.terrarum.blockproperties.FluidCodex
import net.torvald.terrarum.gameactors.ActorWithBody import net.torvald.terrarum.gameactors.ActorWithBody
import net.torvald.terrarum.gameactors.ActorWithBody.Companion.METER import net.torvald.terrarum.gameactors.ActorWithBody.Companion.METER
import net.torvald.terrarum.gameactors.ActorWithBody.Companion.PHYS_EPSILON_DIST 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.gameitems.mouseInInteractableRange
import net.torvald.terrarum.gameparticles.ParticleBase import net.torvald.terrarum.gameparticles.ParticleBase
import net.torvald.terrarum.gameworld.GameWorld import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.TheGameWorld
import net.torvald.terrarum.gameworld.fmod import net.torvald.terrarum.gameworld.fmod
import net.torvald.terrarum.modulebasegame.gameactors.Pocketed import net.torvald.terrarum.modulebasegame.gameactors.Pocketed
import net.torvald.terrarum.modulebasegame.gameitems.ItemThrowable import net.torvald.terrarum.modulebasegame.gameitems.ItemThrowable
@@ -44,6 +44,8 @@ import kotlin.math.min
import kotlin.system.exitProcess import kotlin.system.exitProcess
/** /**
* This will be rendered to a postprocessor FBO. * This will be rendered to a postprocessor FBO.
* *
@@ -129,7 +131,7 @@ object IngameRenderer : Disposable {
//var renderingParticleCount = 0 //var renderingParticleCount = 0
// private set // 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 set // the grammar "IngameRenderer.world = gameWorld" seemes mundane and this function needs special care!
private var newWorldLoadedLatch = false private var newWorldLoadedLatch = false
@@ -391,16 +393,11 @@ object IngameRenderer : Disposable {
blendNormalStraightAlpha(batch) blendNormalStraightAlpha(batch)
val (vo, vg) = if (world is TheGameWorld) { val (vo, vg) = world.weatherbox.let {
(world as TheGameWorld).weatherbox.let { if (it.currentWeather.identifier == "titlescreen")
if (it.currentWeather.identifier == "titlescreen") 1f to 1f
1f to 1f else
else it.currentVibrancy.x to it.currentVibrancy.y
it.currentVibrancy.x to it.currentVibrancy.y
}
}
else {
1f to 1f
} }
mixedOutTex.texture.bind(0) 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.gameitems.mouseInInteractableRange
import net.torvald.terrarum.gameparticles.ParticleBase import net.torvald.terrarum.gameparticles.ParticleBase
import net.torvald.terrarum.gameworld.GameWorld import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.TheGameWorld
import net.torvald.terrarum.gameworld.fmod import net.torvald.terrarum.gameworld.fmod
import net.torvald.terrarum.langpack.Lang import net.torvald.terrarum.langpack.Lang
import net.torvald.terrarum.modulebasegame.gameactors.* 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
import net.torvald.terrarum.realestate.LandUtil.CHUNK_H import net.torvald.terrarum.realestate.LandUtil.CHUNK_H
import net.torvald.terrarum.realestate.LandUtil.CHUNK_W 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.VDUtil
import net.torvald.terrarum.savegame.VirtualDisk import net.torvald.terrarum.savegame.VirtualDisk
import net.torvald.terrarum.serialise.Common import net.torvald.terrarum.serialise.Common
@@ -350,7 +348,7 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
data class Codices( data class Codices(
val disk: VirtualDisk, // WORLD disk val disk: VirtualDisk, // WORLD disk
val world: TheGameWorld, val world: GameWorld,
// val meta: WriteMeta.WorldMeta, // val meta: WriteMeta.WorldMeta,
// val block: BlockCodex, // val block: BlockCodex,
// val item: ItemCodex, // val item: ItemCodex,
@@ -385,8 +383,7 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
// feed info to the worldgen // feed info to the worldgen
if (world is TheGameWorld) Worldgen.attachMap(world, WorldgenParams.getParamsByVersion(codices.worldGenver, world.generatorSeed))
Worldgen.attachMap(world as TheGameWorld, WorldgenParams.getParamsByVersion(codices.worldGenver, world.generatorSeed))
} }
loadCallback = codices.callbackAfterLoad loadCallback = codices.callbackAfterLoad
@@ -446,6 +443,7 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
} }
} }
// try to unstuck the repositioned player // try to unstuck the repositioned player
codices.player.tryUnstuck() codices.player.tryUnstuck()
@@ -522,18 +520,13 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
} }
else { else {
App.getLoadScreen().addMessage("${App.GAME_NAME} ${App.getVERSION_STRING()}") App.getLoadScreen().addMessage("${App.GAME_NAME} ${App.getVERSION_STRING()}")
App.getLoadScreen().addMessage("Creating new world") App.getLoadScreen().addMessage("Creating new world")
val worldFile = getWorldSaveFiledesc(worldSavefileName)
VDUtil.dumpToRealMachine(worldDisk, worldFile)
val skimmer = DiskSkimmer(worldFile)
// init map as chosen size // init map as chosen size
val timeNow = App.getTIME_T() val timeNow = App.getTIME_T()
world = GameWorld(worldParams.width, worldParams.height, timeNow, timeNow) // new game, so the creation time is right now
world = TheGameWorld(worldParams.width, worldParams.height, skimmer, timeNow, timeNow) // new game, so the creation time is right now
world.generatorSeed = worldParams.worldGenSeed world.generatorSeed = worldParams.worldGenSeed
//gameworldIndices.add(world.worldIndex) //gameworldIndices.add(world.worldIndex)
world.extraFields["basegame.economy"] = GameEconomy() 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.KeyToggler
import net.torvald.terrarum.gamecontroller.TerrarumKeyboardEvent import net.torvald.terrarum.gamecontroller.TerrarumKeyboardEvent
import net.torvald.terrarum.gameparticles.ParticleBase 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.langpack.Lang
import net.torvald.terrarum.modulebasegame.ui.UILoadGovernor import net.torvald.terrarum.modulebasegame.ui.UILoadGovernor
import net.torvald.terrarum.modulebasegame.ui.UIRemoCon import net.torvald.terrarum.modulebasegame.ui.UIRemoCon
import net.torvald.terrarum.modulebasegame.ui.UITitleRemoConYaml import net.torvald.terrarum.modulebasegame.ui.UITitleRemoConYaml
import net.torvald.terrarum.realestate.LandUtil 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.Toolkit
import net.torvald.terrarum.ui.UICanvas import net.torvald.terrarum.ui.UICanvas
import net.torvald.terrarum.ui.UIItemTextButton
import net.torvald.terrarum.utils.OpenURL import net.torvald.terrarum.utils.OpenURL
import net.torvald.terrarum.weather.WeatherMixer import net.torvald.terrarum.weather.WeatherMixer
import net.torvald.terrarum.worlddrawer.WorldCamera 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 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 lateinit var cameraNodes: FloatArray // camera Y-pos
private val cameraNodeWidth = 15 private val cameraNodeWidth = 15
private val lookaheadDist = cameraNodeWidth * TILE_SIZED private val lookaheadDist = cameraNodeWidth * TILE_SIZED
@@ -162,19 +165,19 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
val file = ModMgr.getFile("basegame", "demoworld") val file = ModMgr.getFile("basegame", "demoworld")
val reader = java.io.FileReader(file) val reader = java.io.FileReader(file)
//ReadWorld.readWorldAndSetNewWorld(Terrarum.ingame!! as TerrarumIngame, reader) //ReadWorld.readWorldAndSetNewWorld(Terrarum.ingame!! as TerrarumIngame, reader)
val world = ReadTitlescreenGameWorld(reader, file) val world = ReadSimpleWorld(reader, file)
demoWorld = world demoWorld = world
demoWorld.worldTime.timeDelta = 30 demoWorld.worldTime.timeDelta = 30
printdbg(this, "Demo world loaded") printdbg(this, "Demo world loaded")
} }
catch (e: IOException) { 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 demoWorld.worldTime.timeDelta = 30
printdbg(this, "Demo world not found, using empty world") printdbg(this, "Demo world not found, using empty world")
} }
this.world = demoWorld
demoWorld.renumberTilesAfterLoad() demoWorld.renumberTilesAfterLoad()
this.world = demoWorld
// set initial time to summer // set initial time to summer
demoWorld.worldTime.addTime(WorldTime.DAY_LENGTH * 32) demoWorld.worldTime.addTime(WorldTime.DAY_LENGTH * 32)
@@ -362,7 +365,7 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
gdxClearAndEnableBlend(.64f, .754f, .84f, 1f) 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) WorldCamera.update(demoWorld, cameraPlayer)
IngameRenderer.invoke( IngameRenderer.invoke(

View File

@@ -12,7 +12,6 @@ import net.torvald.terrarum.gameactors.Controllable
import net.torvald.terrarum.gameitems.ItemID import net.torvald.terrarum.gameitems.ItemID
import net.torvald.terrarum.gameworld.GameWorld import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.GameWorld.Companion.FLUID 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.TerrarumIngame.Companion.inUpdateRange
import net.torvald.terrarum.modulebasegame.gameactors.* import net.torvald.terrarum.modulebasegame.gameactors.*
import net.torvald.terrarum.modulebasegame.gameitems.AxeCore 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 com.badlogic.gdx.graphics.Texture
import net.torvald.terrarum.* import net.torvald.terrarum.*
import net.torvald.terrarum.gameworld.GameWorld import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.TheGameWorld
import net.torvald.terrarum.ui.Toolkit import net.torvald.terrarum.ui.Toolkit
import kotlin.math.roundToInt import kotlin.math.roundToInt
@@ -97,7 +96,7 @@ class WorldgenLoadScreen(screenToBeLoaded: IngameInstance, private val worldwidt
try { 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 // 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 val outCol = if (BlockCodex[world.getTileFromTerrain(wx, wy)].isSolid) COL_TERR
else if (BlockCodex[world.getTileFromWall(wx, wy)].isSolid) COL_WALLED else if (BlockCodex[world.getTileFromWall(wx, wy)].isSolid) COL_WALLED
else COL_AIR else COL_AIR

View File

@@ -4,9 +4,9 @@ import net.torvald.terrarum.App
import net.torvald.terrarum.Terrarum import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.console.ConsoleCommand import net.torvald.terrarum.console.ConsoleCommand
import net.torvald.terrarum.console.Echo 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.modulebasegame.TerrarumIngame
import net.torvald.terrarum.serialise.WriteTitlescreenGameWorld import net.torvald.terrarum.serialise.WriteSimpleWorld
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
@@ -21,12 +21,12 @@ object ExportWorld : ConsoleCommand {
try { try {
val ingame = Terrarum.ingame!! as TerrarumIngame val ingame = Terrarum.ingame!! as TerrarumIngame
val file = File(App.defaultDir + "/Exports/${args[1]}.json") 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.layerTerrain = ingame.world.layerTerrain
it.layerWall = ingame.world.layerWall it.layerWall = ingame.world.layerWall
it.tileNumberToNameMap.putAll(ingame.world.tileNumberToNameMap) 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") Echo("Exportworld: exported the world as ${args[1]}.json")
} }
catch (e: IOException) { 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.ConsoleCommand
import net.torvald.terrarum.console.Echo import net.torvald.terrarum.console.Echo
import net.torvald.terrarum.modulebasegame.TerrarumIngame 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.File
import java.io.IOException import java.io.IOException
@@ -20,7 +20,7 @@ object ImportWorld : ConsoleCommand {
try { try {
val file = File(App.defaultDir + "/Exports/${args[1]}.json") val file = File(App.defaultDir + "/Exports/${args[1]}.json")
val reader = java.io.FileReader(file) 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") Echo("Importworld: imported a world from ${args[1]}.json")
} }
catch (e: IOException) { catch (e: IOException) {

View File

@@ -1,6 +1,7 @@
package net.torvald.terrarum.modulebasegame.gameactors package net.torvald.terrarum.modulebasegame.gameactors
import net.torvald.terrarum.* import net.torvald.terrarum.*
import net.torvald.terrarum.App.printdbg
import net.torvald.terrarum.gameactors.ActorID import net.torvald.terrarum.gameactors.ActorID
import net.torvald.terrarum.gameactors.PhysProperties import net.torvald.terrarum.gameactors.PhysProperties
import net.torvald.terrarum.ui.UICanvas import net.torvald.terrarum.ui.UICanvas
@@ -16,7 +17,7 @@ open class Electric : FixtureBase {
protected constructor() : super() { protected constructor() : super() {
oldSinkStatus = Array(blockBox.width * blockBox.height) { Vector2() } 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) App.disposables.add(mainUI)
oldSinkStatus = Array(blockBox.width * blockBox.height) { Vector2() } oldSinkStatus = Array(blockBox.width * blockBox.height) { Vector2() }
newSinkStatus = Array(blockBox.width * blockBox.height) { Vector2() } // newSinkStatus = Array(blockBox.width * blockBox.height) { Vector2() }
} }
companion object { companion object {
@@ -137,7 +138,7 @@ open class Electric : FixtureBase {
getWireEmissionAt(offsetX, offsetY).x <= ELECTRIC_THRESHOLD_LOW getWireEmissionAt(offsetX, offsetY).x <= ELECTRIC_THRESHOLD_LOW
protected var oldSinkStatus: Array<Vector2> protected var oldSinkStatus: Array<Vector2>
protected var newSinkStatus: Array<Vector2> // protected var newSinkStatus: Array<Vector2>
open fun updateOnWireGraphTraversal(offsetX: Int, offsetY: Int, sinkType: WireEmissionType) { open fun updateOnWireGraphTraversal(offsetX: Int, offsetY: Int, sinkType: WireEmissionType) {
val index = pointToBlockBoxIndex(offsetX, offsetY) 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)) 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) { for (x in 0 until blockBox.width) {
// get indices of "rising edges" // get indices of "rising edges"
// get indices of "falling 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 index = pointToBlockBoxIndex(x, y)
val type = getWireSinkAt(index) ?: ""
if (new.x - oldSinkStatus[index].x >= ELECTRIC_THRESHOLD_EDGE_DELTA && new.x >= ELECTRIC_THRESHOLD_HIGH) if (type.isNotBlank()) {
risingEdgeIndices.add(index) val old = oldSinkStatus[index]
else if (oldSinkStatus[index].x - new.x >= ELECTRIC_THRESHOLD_EDGE_DELTA && new.x <= ELECTRIC_THRESHOLD_LOW) val new = getWireStateAt(x, y, type)
fallingEdgeIndices.add(index)
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) } risingEdgeIndices.forEach { onRisingEdge(it) }
fallingEdgeIndices.forEach { onFallingEdge(it) } fallingEdgeIndices.forEach { onFallingEdge(it) }
updateSignal() 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) blockBox = BlockBox(BlockBox.NO_COLLISION, panelCount, 2)
setHitboxDimension(TILE_SIZE * blockBox.width, TILE_SIZE * blockBox.height, 0, 2) setHitboxDimension(TILE_SIZE * blockBox.width, TILE_SIZE * blockBox.height, 0, 2)
oldSinkStatus = Array(blockBox.width * blockBox.height) { Vector2() } 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 // 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) { override fun onRisingEdge(readFrom: BlockBoxIndex) {
// printdbg(this, "readFrom=$readFrom; getWireSinkAt(readFrom)=${getWireSinkAt(readFrom)}")
if (getWireSinkAt(readFrom) != "digital_bit") return if (getWireSinkAt(readFrom) != "digital_bit") return
printdbg(this, "teleport! $teleportRequest") // printdbg(this, "teleport! $teleportRequest")
teleportRequest?.let { teleportRequest?.let {
if (it.worldDiskToLoad != null && it.worldLoadParam != null) { if (it.worldDiskToLoad != null && it.worldLoadParam != null) {
throw InternalError("Contradiction -- worldDiskToLoad and worldLoadParam are both not null: $teleportRequest") 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.isWall
import net.torvald.terrarum.gameitems.mouseInInteractableRange import net.torvald.terrarum.gameitems.mouseInInteractableRange
import net.torvald.terrarum.gameworld.GameWorld import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.TheGameWorld
import net.torvald.terrarum.modulebasegame.TerrarumIngame import net.torvald.terrarum.modulebasegame.TerrarumIngame
import net.torvald.terrarum.modulebasegame.gameactors.FixtureBase import net.torvald.terrarum.modulebasegame.gameactors.FixtureBase

View File

@@ -1,14 +1,11 @@
package net.torvald.terrarum.modulebasegame.serialise package net.torvald.terrarum.modulebasegame.serialise
import net.torvald.terrarum.* import net.torvald.terrarum.*
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZED
import net.torvald.terrarum.console.Echo import net.torvald.terrarum.console.Echo
import net.torvald.terrarum.gameworld.* import net.torvald.terrarum.gameworld.BlockLayerGenericI16
import net.torvald.terrarum.gameworld.ChunkPool.Companion.chunkOffsetsNearPlayer import net.torvald.terrarum.gameworld.BlockLayerFluidI16F16
import net.torvald.terrarum.gameworld.GameWorld.Companion.FLUID import net.torvald.terrarum.gameworld.BlockLayerOresI16I8
import net.torvald.terrarum.gameworld.GameWorld.Companion.ORES import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.GameWorld.Companion.TERRAIN
import net.torvald.terrarum.gameworld.GameWorld.Companion.WALL
import net.torvald.terrarum.langpack.Lang import net.torvald.terrarum.langpack.Lang
import net.torvald.terrarum.modulebasegame.FancyWorldReadLoadScreen import net.torvald.terrarum.modulebasegame.FancyWorldReadLoadScreen
import net.torvald.terrarum.modulebasegame.TerrarumIngame 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.realestate.LandUtil
import net.torvald.terrarum.savegame.* import net.torvald.terrarum.savegame.*
import net.torvald.terrarum.serialise.Common import net.torvald.terrarum.serialise.Common
import org.dyn4j.geometry.Vector2
import java.io.Reader import java.io.Reader
import java.util.logging.Level import java.util.logging.Level
import kotlin.experimental.or import kotlin.experimental.or
@@ -64,10 +60,11 @@ object LoadSavegame {
val worldDiskSavegameInfo = ByteArray64Reader(worldDisk.getFile(VDFileID.SAVEGAMEINFO)!!.bytes, Common.CHARSET) val worldDiskSavegameInfo = ByteArray64Reader(worldDisk.getFile(VDFileID.SAVEGAMEINFO)!!.bytes, Common.CHARSET)
val world = ReadWorld(worldDiskSavegameInfo, worldDisk.diskFile) 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.layerTerrain = BlockLayerGenericI16(world.width, world.height)
world.layerOres = BlockLayerOresI16I8(world.width, world.height, worldDisk, ORES, world) world.layerWall = BlockLayerGenericI16(world.width, world.height)
world.layerFluids = BlockLayerFluidI16F16(world.width, world.height, worldDisk, FLUID, world) 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) } 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 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) val (cx, cy) = LandUtil.chunkNumToChunkXY(world, chunk)
ReadWorld.decodeChunkToLayer(chunkFile.getContent(), worldLayer[layer]!!, cx, cy) 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) 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"]) loadscreen.addMessage(Lang["MENU_IO_LOAD_UPDATING_BLOCK_MAPPINGS"])
world.renumberTilesAfterLoad() world.renumberTilesAfterLoad()

View File

@@ -4,7 +4,6 @@ import net.torvald.gdx.graphics.PixmapIO2
import net.torvald.terrarum.App.printdbg import net.torvald.terrarum.App.printdbg
import net.torvald.terrarum.TerrarumAppConfiguration import net.torvald.terrarum.TerrarumAppConfiguration
import net.torvald.terrarum.gameworld.GameWorld import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.TheGameWorld
import net.torvald.terrarum.modulebasegame.IngameRenderer import net.torvald.terrarum.modulebasegame.IngameRenderer
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
@@ -119,7 +118,7 @@ class QuickSingleplayerWorldSavingThread(
// println("Chunk xy from number $chunkNumber -> (${chunkXY.x}, ${chunkXY.y})") // 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 chunkBytes = WriteWorld.encodeChunk(layer, cx, cy)
val entryID = 0x1_0000_0000L or layerNum.toLong().shl(24) or chunkNumber.toLong() 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.gdx.graphics.PixmapIO2
import net.torvald.terrarum.* 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.FLUID
import net.torvald.terrarum.gameworld.GameWorld.Companion.ORES import net.torvald.terrarum.gameworld.GameWorld.Companion.ORES
import net.torvald.terrarum.gameworld.GameWorld.Companion.TERRAIN import net.torvald.terrarum.gameworld.GameWorld.Companion.TERRAIN
import net.torvald.terrarum.gameworld.GameWorld.Companion.WALL 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.IngameRenderer
import net.torvald.terrarum.modulebasegame.TerrarumIngame import net.torvald.terrarum.modulebasegame.TerrarumIngame
import net.torvald.terrarum.modulebasegame.gameactors.FixtureBase 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.gameactors.NoSerialise
import net.torvald.terrarum.gameworld.BlockLayer import net.torvald.terrarum.gameworld.BlockLayer
import net.torvald.terrarum.gameworld.GameWorld import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.TheGameWorld
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.modulebasegame.worldgenerator.RoguelikeRandomiser import net.torvald.terrarum.modulebasegame.worldgenerator.RoguelikeRandomiser
@@ -96,12 +95,12 @@ object WriteWorld {
*/ */
object ReadWorld { object ReadWorld {
operator fun invoke(worldDataStream: Reader, origin: File?): TheGameWorld = operator fun invoke(worldDataStream: Reader, origin: File?): GameWorld =
Common.jsoner.fromJson(TheGameWorld::class.java, worldDataStream).also { Common.jsoner.fromJson(GameWorld::class.java, worldDataStream).also {
fillInDetails(origin, it) fillInDetails(origin, it)
} }
private fun fillInDetails(origin: File?, world: TheGameWorld) { private fun fillInDetails(origin: File?, world: GameWorld) {
world.tileNumberToNameMap.forEach { l, s -> world.tileNumberToNameMap.forEach { l, s ->
world.tileNameToNumberMap[s] = l.toInt() world.tileNameToNumberMap[s] = l.toInt()
} }

View File

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

View File

@@ -15,6 +15,7 @@ import net.torvald.terrarum.serialise.toBig64
import net.torvald.terrarum.toInt import net.torvald.terrarum.toInt
import net.torvald.terrarum.utils.OrePlacement import net.torvald.terrarum.utils.OrePlacement
import net.torvald.terrarum.worlddrawer.BlocksDrawer import net.torvald.terrarum.worlddrawer.BlocksDrawer
import kotlin.math.max
/** /**
* Created by minjaesong on 2023-10-26. * 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.gameitems.ItemID
import net.torvald.terrarum.gameworld.BlockAddress import net.torvald.terrarum.gameworld.BlockAddress
import net.torvald.terrarum.gameworld.GameWorld import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.TheGameWorld
import net.torvald.terrarum.gameworld.fmod import net.torvald.terrarum.gameworld.fmod
import net.torvald.terrarum.langpack.Lang import net.torvald.terrarum.langpack.Lang
import net.torvald.terrarum.modulebasegame.TerrarumIngame import net.torvald.terrarum.modulebasegame.TerrarumIngame
@@ -164,14 +163,14 @@ object Worldgen {
val jobs = getJobs() val jobs = getJobs()
printdbg(this, "Generating chunk on ($cx, $cy)") printdbg(this, "Generating chunk on ($cx, $cy)")
Thread { Thread {
world.chunkFlags[cy][cx] = TheGameWorld.CHUNK_GENERATING world.chunkFlags[cy][cx] = GameWorld.CHUNK_GENERATING
for (i in jobs.indices) { for (i in jobs.indices) {
val it = jobs[i] val it = jobs[i]
it.theWork.getChunkDone(cx, cy) it.theWork.getChunkDone(cx, cy)
} }
world.chunkFlags[cy][cx] = TheGameWorld.CHUNK_LOADED world.chunkFlags[cy][cx] = GameWorld.CHUNK_LOADED
callback(cx, cy) callback(cx, cy)
}.let { }.let {
it.priority = 2 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) draw(chunkX * LandUtil.CHUNK_W, chunkY * CHUNK_H, localJoise, sampleOffset)
loadscreen?.progress?.addAndGet(1L) 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.random.HQRNG
import net.torvald.terrarum.* import net.torvald.terrarum.*
import net.torvald.terrarum.console.EchoError 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.GameWorld
import net.torvald.terrarum.gameworld.TheGameWorld
import net.torvald.terrarum.gameworld.WorldTime import net.torvald.terrarum.gameworld.WorldTime
import net.torvald.terrarum.savegame.ByteArray64 import net.torvald.terrarum.savegame.ByteArray64
import net.torvald.terrarum.savegame.ByteArray64GrowableOutputStream import net.torvald.terrarum.savegame.ByteArray64GrowableOutputStream
@@ -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: 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 fun Byte.tostr() = this.toInt().and(255).toString(16).padStart(2,'0')
private val digester = DigestUtils.getSha256Digest() private val digester = DigestUtils.getSha256Digest()
@@ -75,8 +74,8 @@ object Common {
} }
}) })
// BlockLayer // BlockLayer
it.setSerializer(BlockLayerInMemoryI16::class.java, object : Json.Serializer<BlockLayerInMemoryI16> { it.setSerializer(BlockLayerGenericI16::class.java, object : Json.Serializer<BlockLayerGenericI16> {
override fun write(json: Json, obj: BlockLayerInMemoryI16, knownType: Class<*>?) { override fun write(json: Json, obj: BlockLayerGenericI16, 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() }
@@ -86,7 +85,7 @@ object Common {
json.writeValue(layer) 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 // full manual
try { try {
return strToBlockLayer(LayerInfo( return strToBlockLayer(LayerInfo(
@@ -436,12 +435,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: BlockLayerInMemoryI16): String { private fun blockLayerToStr(b: BlockLayerGenericI16): String {
return bytesToZipdStr(b.bytesIterator()) return bytesToZipdStr(b.bytesIterator())
} }
private fun strToBlockLayer(layerInfo: LayerInfo): BlockLayerInMemoryI16 { private fun strToBlockLayer(layerInfo: LayerInfo): BlockLayerGenericI16 {
val layer = BlockLayerInMemoryI16(layerInfo.x, layerInfo.y) val layer = BlockLayerGenericI16(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

View File

@@ -6,7 +6,6 @@ import net.torvald.terrarum.TerrarumAppConfiguration
import net.torvald.terrarum.blockproperties.Block import net.torvald.terrarum.blockproperties.Block
import net.torvald.terrarum.gameitems.ItemID import net.torvald.terrarum.gameitems.ItemID
import net.torvald.terrarum.gameworld.BlockLayerGenericI16 import net.torvald.terrarum.gameworld.BlockLayerGenericI16
import net.torvald.terrarum.gameworld.BlockLayerInMemoryI16
import net.torvald.terrarum.gameworld.GameWorld import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.GameWorld.Companion.TERRAIN import net.torvald.terrarum.gameworld.GameWorld.Companion.TERRAIN
import net.torvald.terrarum.gameworld.GameWorld.Companion.WALL import net.torvald.terrarum.gameworld.GameWorld.Companion.WALL
@@ -129,7 +128,7 @@ class POILayer(
constructor() : this("undefined") constructor() : this("undefined")
@Transient var name = name @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> @Transient internal lateinit var dat: Array<ByteArray>
@Deprecated("Used for debug print", ReplaceWith("name")) @Transient internal var id = "" @Deprecated("Used for debug print", ReplaceWith("name")) @Transient internal var id = ""
@@ -180,10 +179,10 @@ class POILayer(
if (::blockLayer.isInitialized) { if (::blockLayer.isInitialized) {
blockLayer.forEach { it.dispose() } blockLayer.forEach { it.dispose() }
} }
blockLayer = ArrayList() blockLayer = ArrayList<BlockLayerGenericI16>()
dat.forEachIndexed { layerIndex, layer -> dat.forEachIndexed { layerIndex, layer ->
val currentBlockLayer = BlockLayerInMemoryI16(width, height).also { val currentBlockLayer = BlockLayerGenericI16(width, height).also {
blockLayer.add(it) blockLayer.add(it)
} }
for (w in 0 until layer.size / byteLength) { 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.IngameInstance
import net.torvald.terrarum.ItemCodex import net.torvald.terrarum.ItemCodex
import net.torvald.terrarum.gameactors.Actor import net.torvald.terrarum.gameactors.Actor
import net.torvald.terrarum.gameworld.* import net.torvald.terrarum.gameworld.BlockLayerFluidI16F16
import net.torvald.terrarum.modulebasegame.IngameRenderer 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.File
import java.io.Reader import java.io.Reader
/** /**
* Created by minjaesong on 2022-09-03. * Created by minjaesong on 2022-09-03.
*/ */
object ReadTitlescreenGameWorld { object ReadSimpleWorld {
operator fun invoke(worldDataStream: Reader, origin: File?): TitlescreenGameWorld = operator fun invoke(worldDataStream: Reader, origin: File?): GameWorld =
Common.jsoner.fromJson(TitlescreenGameWorld::class.java, worldDataStream).also { Common.jsoner.fromJson(SimpleGameWorld::class.java, worldDataStream).also {
fillInDetails(origin, it) fillInDetails(origin, it)
} }
private fun fillInDetails(origin: File?, world: TitlescreenGameWorld) { private fun fillInDetails(origin: File?, world: GameWorld) {
world.tileNumberToNameMap.forEach { l, s -> world.tileNumberToNameMap.forEach { l, s ->
world.tileNameToNumberMap[s] = l.toInt() world.tileNameToNumberMap[s] = l.toInt()
} }
world.layerOres = BlockLayerInMemoryI16I8(world.width, world.height) world.layerOres = BlockLayerOresI16I8(world.width, world.height)
world.layerFluids = BlockLayerInMemoryI16F16(world.width, world.height) world.layerFluids = BlockLayerFluidI16F16(world.width, world.height)
ItemCodex.loadFromSave(origin, world.dynamicToStaticTable, world.dynamicItemInventory) 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) val world = invoke(worldDataStream, origin)
ingame.world = world ingame.world = world
return 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 val currentPlayTime_t = time_t - ingame.loadedTime_t
world.comp = Common.getCompIndex() world.comp = Common.getCompIndex()
world.lastPlayTime = time_t
world.totalPlayTime += currentPlayTime_t
// world.actors.clear() world.actors.clear()
// world.actors.addAll(actorsList.map { it.referenceID }.sorted().distinct()) 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() val time_t = App.getTIME_T()
preWrite(ingame, time_t, world, actorsList) preWrite(ingame, time_t, world, actorsList)
val s = Common.jsoner.toJson(world) 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.audio.dsp.*
import net.torvald.terrarum.controller.TerrarumController import net.torvald.terrarum.controller.TerrarumController
import net.torvald.terrarum.gameworld.GameWorld import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.TheGameWorld
import net.torvald.terrarum.gameworld.fmod import net.torvald.terrarum.gameworld.fmod
import net.torvald.terrarum.imagefont.TinyAlphNum import net.torvald.terrarum.imagefont.TinyAlphNum
import net.torvald.terrarum.modulebasegame.IngameRenderer import net.torvald.terrarum.modulebasegame.IngameRenderer
@@ -316,7 +315,7 @@ class BasicDebugInfoWindow : UICanvas() {
val wallNum = it.getTileFromWall(mouseTileX, mouseTileY) val wallNum = it.getTileFromWall(mouseTileX, mouseTileY)
val tileNum = it.getTileFromTerrain(mouseTileX, mouseTileY) val tileNum = it.getTileFromTerrain(mouseTileX, mouseTileY)
val (oreNum, orePlacement) = it.getTileFromOre(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 fluid = it.getFluid(mouseTileX, mouseTileY)
val wireCount = wires.first?.size?.toString() ?: "no" val wireCount = wires.first?.size?.toString() ?: "no"
val tdmg = it.getTerrainDamage(mouseTileX, mouseTileY).toIntAndFrac(2,2) 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 */ /** 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() { open fun show() {
clearTooltip()
openingClickLatched = true openingClickLatched = true
uiItems.forEach { it.show() } uiItems.forEach { it.show() }
handler.subUIs.forEach { it.show() } handler.subUIs.forEach { it.show() }

View File

@@ -1,6 +1,8 @@
package net.torvald.terrarum.utils 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.gameactors.ActorValue
import net.torvald.terrarum.gameitems.ItemID import net.torvald.terrarum.gameitems.ItemID
import net.torvald.terrarum.gameworld.BlockAddress 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.blockproperties.Block
import net.torvald.terrarum.gamecontroller.KeyToggler import net.torvald.terrarum.gamecontroller.KeyToggler
import net.torvald.terrarum.gameitems.ItemID 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.modulebasegame.worldgenerator.shake
import net.torvald.terrarum.realestate.LandUtil import net.torvald.terrarum.realestate.LandUtil
import net.torvald.terrarum.serialise.toBig64 import net.torvald.terrarum.serialise.toBig64
@@ -41,7 +43,7 @@ import kotlin.math.roundToInt
internal object BlocksDrawer { internal object BlocksDrawer {
/** World change is managed by IngameRenderer.setWorld() */ /** 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) { 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. // 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 // 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. // 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) WALL -> world.layerWall.unsafeGetTile(wx, wy)
TERRAIN -> world.layerTerrain.unsafeGetTile(wx, wy) TERRAIN -> world.layerTerrain.unsafeGetTile(wx, wy)
ORES -> world.layerOres.unsafeGetTile(wx, wy)//.also { println(it) } 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 if (number == 65535 || fill < 1f/30f) 0
else number 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 nearbyFluidType = fluids.asSequence().filter { it.amount >= 0.5f / 16f }.map { it.type }.filter { it.startsWith("fluid@") }.sorted().firstOrNull()
val fillThis = 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) val tile = world.getTileFromTerrain(wx, wy)
@@ -673,7 +671,7 @@ internal object BlocksDrawer {
rawTileNum + nearbyTilesInfo rawTileNum + nearbyTilesInfo
// special case: ores // special case: ores
else if (mode == 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 // rest of the cases: terrain and walls
else rawTileNum + when (renderTag.maskType) { else rawTileNum + when (renderTag.maskType) {
CreateTileAtlas.RenderTag.MASK_NA -> 0 CreateTileAtlas.RenderTag.MASK_NA -> 0
@@ -1190,7 +1188,7 @@ internal object BlocksDrawer {
get() { get() {
val rate = (((Gdx.graphics.framesPerSecond / 50f) * TILE_SIZEF) / maxOf(WorldCamera.deltaX.abs(), WorldCamera.deltaY.abs()).coerceAtLeast(1)).roundToInt().coerceIn(1, 4) 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()) 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 private var camTransX = 0

View File

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