Compare commits

..

5 Commits

Author SHA1 Message Date
minjaesong
cc3c1c1b14 apparently the problem was on the other places 2024-11-15 23:07:07 +09:00
minjaesong
0eccc4dbea huge wippie 2024-11-10 22:30:01 +09:00
minjaesong
4c9db1ef60 more chunkpool stuffs 2024-10-25 11:30:50 +09:00
minjaesong
83906e7930 setTile on ChunkPool 2024-10-22 22:49:47 +09:00
minjaesong
39cfc3a4d9 chunkpoolnig wip 2024-10-22 11:47:21 +09:00
65 changed files with 1720 additions and 1411 deletions

View File

@@ -3,7 +3,6 @@ CheatWarnTest
CodexEdictis
ExportAtlas
ExportCodices
ExportFBO
ExportMap
ExportMap2
ExportWorld
1 CatStdout
3 CodexEdictis
4 ExportAtlas
5 ExportCodices
ExportFBO
6 ExportMap
7 ExportMap2
8 ExportWorld

View File

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

View File

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

View File

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

View File

@@ -31,6 +31,7 @@ import net.torvald.terrarum.gamecontroller.KeyToggler;
import net.torvald.terrarum.gamecontroller.TerrarumKeyboardEvent;
import net.torvald.terrarum.gameitems.GameItem;
import net.torvald.terrarum.gameworld.GameWorld;
import net.torvald.terrarum.gameworld.TheGameWorld;
import net.torvald.terrarum.imagefont.BigAlphNum;
import net.torvald.terrarum.imagefont.TinyAlphNum;
import net.torvald.terrarum.langpack.Lang;
@@ -38,7 +39,6 @@ import net.torvald.terrarum.modulebasegame.IngameRenderer;
import net.torvald.terrarum.modulebasegame.TerrarumIngame;
import net.torvald.terrarum.modulebasegame.ui.ItemSlotImageFactory;
import net.torvald.terrarum.serialise.WriteConfig;
import net.torvald.terrarum.ui.BlurMgr;
import net.torvald.terrarum.ui.Toolkit;
import net.torvald.terrarum.utils.JsonFetcher;
import net.torvald.terrarum.worlddrawer.CreateTileAtlas;
@@ -53,14 +53,12 @@ import org.apache.commons.csv.CSVParser;
import org.lwjgl.PointerBuffer;
import org.lwjgl.glfw.GLFW;
import javax.tools.Tool;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Stream;
import java.util.zip.Deflater;
import static java.lang.Thread.MAX_PRIORITY;
import static net.torvald.terrarum.TerrarumKt.*;
@@ -767,7 +765,7 @@ public class App implements ApplicationListener {
FrameBufferManager.begin(fb);
try {
Pixmap p = Pixmap.createFromFrameBuffer(0, 0, fb.getWidth(), fb.getHeight());
PixmapIO.writePNG(Gdx.files.absolute(defaultDir+"/Screenshot-"+String.valueOf(System.currentTimeMillis())+".png"), p, Deflater.DEFAULT_COMPRESSION, true);
PixmapIO.writePNG(Gdx.files.absolute(defaultDir+"/Screenshot-"+String.valueOf(System.currentTimeMillis())+".png"), p, 9, true);
p.dispose();
}
catch (Throwable e) {
@@ -1019,7 +1017,7 @@ public class App implements ApplicationListener {
ModMgr.INSTANCE.disposeMods();
GameWorld.Companion.makeNullWorld().dispose();
TheGameWorld.Companion.makeNullWorld().dispose();
Terrarum.INSTANCE.dispose();
@@ -1029,9 +1027,6 @@ public class App implements ApplicationListener {
deleteTempfiles();
Toolkit.INSTANCE.dispose();
BlurMgr.INSTANCE.dispose();
disposables.forEach((it) -> {
try {
it.dispose();

View File

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

View File

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

View File

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

View File

@@ -95,7 +95,7 @@ class UIFakeBlurOverlay(val blurRadius: Float, val nodarken: Boolean) : UICanvas
batchDrawCol.a = openness
batch.color = batchDrawCol
if (App.getConfigBoolean("fx_backgroundblur")) {
Toolkit.blurEntireScreen(batch, blurRadius * openness, 0, 0, width, height)
Toolkit.blurEntireScreen(batch, camera as OrthographicCamera, blurRadius * openness, 0, 0, width, height)
}
if (!nodarken) {

View File

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

View File

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

View File

@@ -67,7 +67,7 @@ class SavegameCracker(
private val cmds: HashMap<String, KFunction<*>> = HashMap()
init {
SavegameCracker::class.declaredFunctions
.filter { it.findAnnotation<SavegameCrackerCommand>() != null }
.filter { it.findAnnotation<Command>() != null }
// .forEach { it.isAccessible = true; cmds[it.name] = it }
.forEach { cmds[it.name] = it }
}
@@ -100,7 +100,7 @@ class SavegameCracker(
printerrln("${args[0]}: command not found")
else {
try {
val annot = it.findAnnotation<SavegameCrackerCommand>()!!
val annot = it.findAnnotation<Command>()!!
// check arguments
val synopsis = annot.synopsis.split(' ').filter { it.isNotBlank() }
// print out synopsis
@@ -185,14 +185,14 @@ class SavegameCracker(
return this + sb.toString()
}
@SavegameCrackerCommand("Loads a disk archive", "path-to-file")
@Command("Loads a disk archive", "path-to-file")
fun load(args: List<String>) {
file = File(args[1])
disk = VDUtil.readDiskArchive(file!!, Level.INFO) { printerrln("# Warning: $it") }
file!!.copyTo(File(file!!.absolutePath + ".bak"), true)
}
@SavegameCrackerCommand("Lists contents of the disk")
@Command("Lists contents of the disk")
fun ls(args: List<String>) {
letdisk {
it.entries.toSortedMap().forEach { (i, entry) ->
@@ -207,19 +207,19 @@ class SavegameCracker(
}
}
@SavegameCrackerCommand("Prints out available commands and their usage")
@Command("Prints out available commands and their usage")
fun help(args: List<String>) {
cmds.forEach { name, it ->
println("$ccNoun${name.padStart(8)}$cc0 - ${it.findAnnotation<SavegameCrackerCommand>()!!.help}")
println("$ccNoun${name.padStart(8)}$cc0 - ${it.findAnnotation<Command>()!!.help}")
}
}
@SavegameCrackerCommand("Exits the program")
@Command("Exits the program")
fun exit(args: List<String>) { this.exit = true }
@SavegameCrackerCommand("Exits the program")
@Command("Exits the program")
fun quit(args: List<String>) = exit(args)
@SavegameCrackerCommand("Exports contents of the entry into a real file", "entry-id output-file")
@Command("Exports contents of the entry into a real file", "entry-id output-file")
fun export(args: List<String>) {
letdisk {
val entryID = args[1].toLong(10)
@@ -228,7 +228,7 @@ class SavegameCracker(
}
}
@SavegameCrackerCommand("Changes one entry-ID into another", "change-from change-to")
@Command("Changes one entry-ID into another", "change-from change-to")
fun renum(args: List<String>) {
letdisk {
val id0 = args[1].toLong(10)
@@ -244,7 +244,7 @@ class SavegameCracker(
}
}
@SavegameCrackerCommand("Imports a real file onto the savefile", "input-file entry-id")
@Command("Imports a real file onto the savefile", "input-file entry-id")
fun import(args: List<String>) {
letdisk {
val file = File(args[1])
@@ -257,7 +257,7 @@ class SavegameCracker(
}
}
@SavegameCrackerCommand("Removes a file within the savefile", "entry-id")
@Command("Removes a file within the savefile", "entry-id")
fun rm(args: List<String>) {
letdisk {
val id = args[1].toLong(10)
@@ -266,14 +266,14 @@ class SavegameCracker(
}
}
@SavegameCrackerCommand("Saves changes onto the savefile")
@Command("Saves changes onto the savefile")
fun save(args: List<String>) {
letdisk {
VDUtil.dumpToRealMachine(it, file!!)
}
}
@SavegameCrackerCommand("Retrieves all UUIDs found (player UUID, current world UUID, etc.")
@Command("Retrieves all UUIDs found (player UUID, current world UUID, etc.")
fun uuid(args: List<String>) {
letdisk {
val jsonFile = it.getFile(-1) ?: throw FileNotFoundException("savegameinfo.json (entry ID -1) not found")
@@ -294,7 +294,7 @@ class SavegameCracker(
}
}
@SavegameCrackerCommand("Removes the specified chunk(s) completely", "IDs")
@Command("Removes the specified chunk(s) completely", "IDs")
fun discardchunk(args: List<String>) {
letdisk { disk ->
val ids = args[1]
@@ -320,7 +320,7 @@ class SavegameCracker(
}
}
internal annotation class SavegameCrackerCommand(val help: String = "", val synopsis: String = "")
internal annotation class Command(val help: String = "", val synopsis: String = "")
fun main(args: Array<String>) {
SavegameCracker(args).invoke()

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,133 @@
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

@@ -0,0 +1,145 @@
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

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@@ -27,11 +27,11 @@ import net.torvald.terrarum.gameitems.GameItem
import net.torvald.terrarum.gameitems.mouseInInteractableRange
import net.torvald.terrarum.gameparticles.ParticleBase
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.TheGameWorld
import net.torvald.terrarum.gameworld.fmod
import net.torvald.terrarum.modulebasegame.gameactors.Pocketed
import net.torvald.terrarum.modulebasegame.gameitems.ItemThrowable
import net.torvald.terrarum.modulebasegame.gameitems.getThrowPosAndVector
import net.torvald.terrarum.ui.BlurMgr
import net.torvald.terrarum.ui.Toolkit
import net.torvald.terrarum.weather.WeatherMixer
import net.torvald.terrarum.worlddrawer.BlocksDrawer
@@ -44,8 +44,6 @@ import kotlin.math.min
import kotlin.system.exitProcess
/**
* This will be rendered to a postprocessor FBO.
*
@@ -75,17 +73,6 @@ object IngameRenderer : Disposable {
private lateinit var fboA_lightMixed: Float16FrameBuffer
private lateinit var fboEmissive: Float16FrameBuffer
private lateinit var fboMixedOut: Float16FrameBuffer
private lateinit var fboRGBactorsBehind: Float16FrameBuffer // for small shadow eff; A channel is for glow effects so they don't get shadow effects
private lateinit var fboRGBactorsMiddle: Float16FrameBuffer // for large shadow eff; A channel is for glow effects so they don't get shadow effects
private lateinit var fboRGBterrain: Float16FrameBuffer // for large shadow eff; A channel is for glow effects so they don't get shadow effects
private lateinit var fboRGBactorsBehindShadow: Float16FrameBuffer // for small shadow eff; A channel is for glow effects so they don't get shadow effects
private lateinit var fboRGBactorsMiddleShadow: Float16FrameBuffer // for large shadow eff; A channel is for glow effects so they don't get shadow effects
private lateinit var fboRGBterrainShadow: Float16FrameBuffer // for large shadow eff; A channel is for glow effects so they don't get shadow effects
private lateinit var fboRGBwall: Float16FrameBuffer // for masking away the shadows
private lateinit var rgbTex: TextureRegion
private lateinit var aTex: TextureRegion
private lateinit var mixedOutTex: TextureRegion
@@ -115,8 +102,6 @@ object IngameRenderer : Disposable {
val shaderBlendGlow: ShaderProgram
val shaderBlendGlowTex1Flip: ShaderProgram
val shaderForActors: ShaderProgram
val shaderShadowShallow: ShaderProgram
val shaderShadowDeep: ShaderProgram
val shaderDemultiply: ShaderProgram
val shaderBayerAlpha: ShaderProgram
@@ -144,7 +129,7 @@ object IngameRenderer : Disposable {
//var renderingParticleCount = 0
// private set
var world: GameWorld = GameWorld.makeNullWorld()
var world: GameWorld = TheGameWorld.makeNullWorld()
private set // the grammar "IngameRenderer.world = gameWorld" seemes mundane and this function needs special care!
private var newWorldLoadedLatch = false
@@ -159,8 +144,6 @@ object IngameRenderer : Disposable {
shaderForActors = App.loadShaderFromClasspath("shaders/default.vert", "shaders/actors.frag")
shaderShadowShallow = App.loadShaderFromClasspath("shaders/default.vert", "shaders/shadowshallow.frag")
shaderShadowDeep = App.loadShaderFromClasspath("shaders/default.vert", "shaders/shadowdeep.frag")
shaderBlendGlow = App.loadShaderFromClasspath("shaders/blendGlow.vert", "shaders/blendGlow.frag")
shaderBlendGlowTex1Flip = App.loadShaderFromClasspath("shaders/blendGlow.vert", "shaders/blendGlowTex1Flip.frag")
shaderDemultiply = App.loadShaderFromClasspath("shaders/blendGlow.vert", "shaders/demultiply.frag")
@@ -408,11 +391,16 @@ object IngameRenderer : Disposable {
blendNormalStraightAlpha(batch)
val (vo, vg) = world.weatherbox.let {
if (it.currentWeather.identifier == "titlescreen")
1f to 1f
else
it.currentVibrancy.x to it.currentVibrancy.y
val (vo, vg) = if (world is TheGameWorld) {
(world as TheGameWorld).weatherbox.let {
if (it.currentWeather.identifier == "titlescreen")
1f to 1f
else
it.currentVibrancy.x to it.currentVibrancy.y
}
}
else {
1f to 1f
}
mixedOutTex.texture.bind(0)
@@ -512,9 +500,10 @@ object IngameRenderer : Disposable {
fboRGB_lightMixed0.inAction(null, null) { clearBuffer() }
fboRGB_lightMixed.inAction(null, null) { clearBuffer() }
fboRGBactorsBehind.inAction(camera, batch) {
clearBuffer()
fboRGB.inAction(camera, batch) {
setCameraPosition(0f, 0f)
BlocksDrawer.drawWall(batch.projectionMatrix, false)
batch.inUse {
batch.shader = shaderForActors
@@ -522,103 +511,21 @@ object IngameRenderer : Disposable {
moveCameraToWorldCoord()
actorsRenderFarBehind?.forEach { it.drawBody(frameDelta, batch) }
actorsRenderBehind?.forEach { it.drawBody(frameDelta, batch) }
}
}
BlurMgr.makeBlur(fboRGBactorsBehind, fboRGBactorsBehindShadow, 0.25f)
fboRGBactorsMiddle.inAction(camera, batch) {
clearBuffer()
setCameraPosition(0f, 0f)
batch.inUse {
batch.shader = shaderForActors
batch.color = Color.WHITE
moveCameraToWorldCoord()
actorsRenderMiddle?.forEach { it.drawBody(frameDelta, batch) }
}
}
BlurMgr.makeBlur(fboRGBactorsMiddle, fboRGBactorsMiddleShadow, 2.5f)
fboRGBwall.inAction(camera, batch) {
clearBuffer()
setCameraPosition(0f, 0f)
BlocksDrawer.drawWall(batch.projectionMatrix, false)
}
fboRGBterrain.inAction(camera, batch) {
clearBuffer()
setCameraPosition(0f, 0f)
BlocksDrawer.drawTerrain(batch.projectionMatrix, false)
}
BlurMgr.makeBlur(fboRGBterrain, fboRGBterrainShadow, 2.5f)
/////////////////////////////////////////////////////////////////////////////////////////////////////
fboRGB.inAction(camera, batch) {
setCameraPosition(0f, 0f)
batch.inUse {
batch.shader = null
batch.color = Color.WHITE
batch.drawFlipped(fboRGBwall.colorBufferTexture, 0f, 0f)
}
// draw actor shadow BEFORE the terrain draw
fboRGBwall.colorBufferTexture.bind(1)
Gdx.gl.glActiveTexture(GL20.GL_TEXTURE0) // so that batch that comes next will bind any tex to it
batch.inUse {
batch.shader = shaderShadowShallow
shaderShadowShallow.setUniformi("u_wall", 1)
setCameraPosition(0f, 0f)
batch.drawFlipped(fboRGBactorsBehindShadow.colorBufferTexture, 0f, 0f)
}
fboRGBwall.colorBufferTexture.bind(1)
Gdx.gl.glActiveTexture(GL20.GL_TEXTURE0) // so that batch that comes next will bind any tex to it
batch.inUse {
batch.shader = shaderShadowDeep
shaderShadowDeep.setUniformi("u_wall", 1)
setCameraPosition(0f, 0f)
batch.drawFlipped(fboRGBterrainShadow.colorBufferTexture, 0f, 0f)
batch.drawFlipped(fboRGBactorsMiddleShadow.colorBufferTexture, 0f, 0f)
}
// Gdx.gl20.glActiveTexture(0)
// draw behind actors and particles
batch.inUse {
batch.shader = shaderForActors
batch.color = Color.WHITE
setCameraPosition(0f, 0f)
batch.color = Color.WHITE
batch.drawFlipped(fboRGBactorsBehind.colorBufferTexture, 0f, 0f)
moveCameraToWorldCoord()
particlesContainer?.forEach { it.drawBody(frameDelta, batch) }
}
// draw just the terrain
batch.inUse {
batch.shader = null
setCameraPosition(0f, 0f)
batch.color = Color.WHITE
batch.drawFlipped(fboRGBterrain.colorBufferTexture, 0f, 0f)
}
setCameraPosition(0f, 0f)
BlocksDrawer.drawTerrain(batch.projectionMatrix, false)
batch.shader = shaderForActors
batch.inUse {
batch.shader = shaderForActors
batch.color = Color.WHITE
/////////////////
// draw actors //
/////////////////
setCameraPosition(0f, 0f)
batch.color = Color.WHITE
batch.drawFlipped(fboRGBactorsMiddle.colorBufferTexture, 0f, 0f)
moveCameraToWorldCoord()
actorsRenderMiddle?.forEach { it.drawBody(frameDelta, batch) }
actorsRenderMidTop?.forEach { it.drawBody(frameDelta, batch) }
player?.drawBody(frameDelta, batch)
actorsRenderFront?.forEach { it.drawBody(frameDelta, batch) }
@@ -1305,13 +1212,6 @@ object IngameRenderer : Disposable {
fboA_lightMixed = Float16FrameBuffer(width, height, false)
fboEmissive = Float16FrameBuffer(width, height, false)
fboMixedOut = Float16FrameBuffer(width, height, false)
fboRGBactorsBehind = Float16FrameBuffer(width, height, false)
fboRGBactorsMiddle = Float16FrameBuffer(width, height, false)
fboRGBterrain = Float16FrameBuffer(width, height, false)
fboRGBactorsBehindShadow = Float16FrameBuffer(width, height, false)
fboRGBactorsMiddleShadow = Float16FrameBuffer(width, height, false)
fboRGBterrainShadow = Float16FrameBuffer(width, height, false)
fboRGBwall = Float16FrameBuffer(width, height, false)
lightmapFbo = Float16FrameBuffer(
LightmapRenderer.lightBuffer.width * LightmapRenderer.DRAW_TILE_SIZE.toInt(),
LightmapRenderer.lightBuffer.height * LightmapRenderer.DRAW_TILE_SIZE.toInt(),
@@ -1374,13 +1274,6 @@ object IngameRenderer : Disposable {
if (::fboEmissive.isInitialized) fboEmissive.tryDispose()
if (::fboMixedOut.isInitialized) fboMixedOut.tryDispose()
if (::lightmapFbo.isInitialized) lightmapFbo.tryDispose()
if (::fboRGBactorsBehind.isInitialized) fboRGBactorsBehind.tryDispose()
if (::fboRGBactorsMiddle.isInitialized) fboRGBactorsMiddle.tryDispose()
if (::fboRGBterrain.isInitialized) fboRGBterrain.tryDispose()
if (::fboRGBactorsBehindShadow.isInitialized) fboRGBactorsBehindShadow.tryDispose()
if (::fboRGBactorsMiddleShadow.isInitialized) fboRGBactorsMiddleShadow.tryDispose()
if (::fboRGBterrainShadow.isInitialized) fboRGBterrainShadow.tryDispose()
if (::fboRGBwall.isInitialized) fboRGBwall.tryDispose()
blurtex0.tryDispose()
@@ -1404,8 +1297,6 @@ object IngameRenderer : Disposable {
shaderBlendGlow.dispose()
shaderBlendGlowTex1Flip.dispose()
shaderForActors.dispose()
shaderShadowShallow.dispose()
shaderShadowDeep.dispose()
shaderDemultiply.dispose()
shaderBayerAlpha.dispose()

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,142 +0,0 @@
package net.torvald.terrarum.modulebasegame.console
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.GL20
import com.badlogic.gdx.graphics.GL30
import com.badlogic.gdx.graphics.Pixmap
import com.badlogic.gdx.graphics.PixmapIO
import com.badlogic.gdx.graphics.glutils.Float16FrameBuffer
import com.badlogic.gdx.graphics.glutils.FrameBuffer
import com.badlogic.gdx.utils.BufferUtils
import net.torvald.reflection.extortField
import net.torvald.terrarum.App
import net.torvald.terrarum.ccG
import net.torvald.terrarum.ccO
import net.torvald.terrarum.ccW
import net.torvald.terrarum.console.ConsoleCommand
import net.torvald.terrarum.console.Echo
import net.torvald.terrarum.console.EchoError
import net.torvald.terrarum.modulebasegame.IngameRenderer
import net.torvald.unicode.BULLET
import net.torvald.unicode.EMDASH
import java.nio.ByteBuffer
import java.util.zip.Deflater
import kotlin.reflect.KFunction
import kotlin.reflect.full.declaredFunctions
import kotlin.reflect.full.findAnnotation
import kotlin.reflect.full.hasAnnotation
/**
* Created by minjaesong on 2024-11-24.
*/
internal object ExportFBO : ConsoleCommand {
private val cmds: HashMap<String, KFunction<*>> = HashMap()
private val helpMessages: List<Pair<String, String>>
init {
val helpMsgs: HashMap<String, String> = HashMap()
ExportFBO::class.declaredFunctions.filter { it.hasAnnotation<ExportFBOCmd>() }.forEach {
cmds[it.name.lowercase()] = it
helpMsgs[it.name.lowercase()] = it.findAnnotation<ExportFBOCmd>()!!.description
}
helpMessages = helpMsgs.keys.toList().sorted().map {
it to helpMsgs[it]!!
}
}
override fun execute(args: Array<String>) {
if (args.size != 3) { printUsage(); return }
val fn = cmds[args[1].lowercase()]
if (fn == null) { printUsage(); return }
try {
val filename = "${args[2]}-${args[1]}.png"
val fileHandle = Gdx.files.absolute("${App.defaultDir}/Exports/$filename")
val fbo = fn.call(this) as FrameBuffer
// cannot use createFromFrameBuffer because the specific FBO must be bound in a way we can control
val pixels: ByteBuffer = BufferUtils.newByteBuffer(fbo.width * fbo.height * 4)
Gdx.gl.glBindFramebuffer(GL20.GL_FRAMEBUFFER, fbo.framebufferHandle)
Gdx.gl.glReadPixels(0, 0, fbo.width, fbo.height, GL30.GL_RGBA, GL30.GL_UNSIGNED_BYTE, pixels)
Gdx.gl.glBindFramebuffer(GL20.GL_FRAMEBUFFER, 0)
val pixmap: Pixmap = Pixmap(fbo.width, fbo.height, Pixmap.Format.RGBA8888)
BufferUtils.copy(pixels, pixmap.pixels, pixels.capacity())
PixmapIO.writePNG(fileHandle, pixmap, Deflater.DEFAULT_COMPRESSION, true)
Echo("Framebuffer exported to$ccG Exports/$filename")
}
catch (e: Throwable) {
EchoError("Could not retrieve the framebuffer: ${e.message}")
System.err.println(e)
return
}
}
override fun printUsage() {
Echo("Usage: exportfbo <identifier> <filename without extension>")
Echo("Available identifiers are:")
helpMessages.forEach { (name, desc) ->
Echo(" $BULLET $ccG$name $ccW$EMDASH $ccO$desc")
}
}
@ExportFBOCmd("Main RGB channel of the IngameRenderer without lighting")
fun fborgb(): FrameBuffer {
return IngameRenderer.extortField<Float16FrameBuffer>("fboRGB")!!
}
@ExportFBOCmd("Main A channel of the IngameRenderer without lighting")
fun fboa(): FrameBuffer {
return IngameRenderer.extortField<Float16FrameBuffer>("fboA")!!
}
@ExportFBOCmd("Main Emissive channel of the IngameRenderer without lighting")
fun fboemissive(): FrameBuffer {
return IngameRenderer.extortField<Float16FrameBuffer>("fboEmissive")!!
}
@ExportFBOCmd("Framebuffer for render-behind actors used for creating shallow shadow effects")
fun fborgbactorsbehind(): FrameBuffer {
return IngameRenderer.extortField<Float16FrameBuffer>("fboRGBactorsBehind")!!
}
@ExportFBOCmd("Framebuffer for render-middle actors used for creating large shadow effects")
fun fborgbactorsmiddle(): FrameBuffer {
return IngameRenderer.extortField<Float16FrameBuffer>("fboRGBactorsMiddle")!!
}
@ExportFBOCmd("Framebuffer for terrain blocks used for creating large shadow effects")
fun fborgbterrain(): FrameBuffer {
return IngameRenderer.extortField<Float16FrameBuffer>("fboRGBterrain")!!
}
@ExportFBOCmd("Framebuffer for render-behind actors used for creating shallow shadow effects")
fun fborgbactorsbehindshadow(): FrameBuffer {
return IngameRenderer.extortField<Float16FrameBuffer>("fboRGBactorsBehindShadow")!!
}
@ExportFBOCmd("Framebuffer for render-middle actors used for creating large shadow effects")
fun fborgbactorsmiddleshadow(): FrameBuffer {
return IngameRenderer.extortField<Float16FrameBuffer>("fboRGBactorsMiddleShadow")!!
}
@ExportFBOCmd("Framebuffer for terrain blocks used for creating large shadow effects")
fun fborgbterrainshadow(): FrameBuffer {
return IngameRenderer.extortField<Float16FrameBuffer>("fboRGBterrainShadow")!!
}
@ExportFBOCmd("Framebuffer for wall blocks")
fun fborgbwall(): FrameBuffer {
return IngameRenderer.extortField<Float16FrameBuffer>("fboRGBwall")!!
}
}
internal annotation class ExportFBOCmd(val description: String)

View File

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

View File

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

View File

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

View File

@@ -14,12 +14,11 @@ import org.dyn4j.geometry.Vector2
*/
class FixtureLogicSignalAdder : Electric, Reorientable {
@Transient override val spawnNeedsFloor = false
@Transient override val spawnNeedsFloor = true
@Transient override val spawnNeedsWall = true
constructor() : super(
BlockBox(BlockBox.NO_COLLISION, 2, 2),
renderOrder = RenderOrder.BEHIND,
nameFun = { Lang["ITEM_LOGIC_SIGNAL_ADDER"] }
)

View File

@@ -34,12 +34,11 @@ interface Reorientable {
*/
class FixtureLogicSignalBlocker : Electric, Reorientable {
@Transient override val spawnNeedsFloor = false
@Transient override val spawnNeedsFloor = true
@Transient override val spawnNeedsWall = true
constructor() : super(
BlockBox(BlockBox.NO_COLLISION, 2, 2),
renderOrder = RenderOrder.BEHIND,
nameFun = { Lang["ITEM_LOGIC_SIGNAL_BLOCKER"] }
)

View File

@@ -18,7 +18,6 @@ class FixtureLogicSignalBulb : Electric {
constructor() : super(
BlockBox(BlockBox.NO_COLLISION, 1, 1),
renderOrder = RenderOrder.BEHIND,
nameFun = { Lang["ITEM_COPPER_BULB"] }
)

View File

@@ -16,12 +16,11 @@ import org.dyn4j.geometry.Vector2
*/
class FixtureLogicSignalLatch : Electric, Reorientable {
@Transient override val spawnNeedsFloor = false
@Transient override val spawnNeedsFloor = true
@Transient override val spawnNeedsWall = true
constructor() : super(
BlockBox(BlockBox.NO_COLLISION, 2, 3),
renderOrder = RenderOrder.BEHIND,
nameFun = { Lang["ITEM_LOGIC_SIGNAL_LATCH"] }
)

View File

@@ -16,12 +16,11 @@ import org.dyn4j.geometry.Vector2
class FixtureLogicSignalRepeaterHorz : Electric, Reorientable {
@Transient override val spawnNeedsFloor = false
@Transient override val spawnNeedsFloor = true
@Transient override val spawnNeedsWall = true
constructor() : super(
BlockBox(BlockBox.NO_COLLISION, 2, 1),
renderOrder = RenderOrder.BEHIND,
nameFun = { Lang["ITEM_LOGIC_SIGNAL_REPEATER"] }
)

View File

@@ -16,12 +16,11 @@ import org.dyn4j.geometry.Vector2
*/
class FixtureLogicSignalSwitchManual : Electric {
@Transient override val spawnNeedsFloor = false
@Transient override val spawnNeedsFloor = true
@Transient override val spawnNeedsWall = true
constructor() : super(
BlockBox(BlockBox.NO_COLLISION, 1, 1),
renderOrder = RenderOrder.BEHIND,
nameFun = { Lang["ITEM_LOGIC_SIGNAL_SWITCH"] }
)
@@ -75,12 +74,11 @@ class FixtureLogicSignalSwitchManual : Electric {
*/
class FixtureLogicSignalPushbutton : Electric {
@Transient override val spawnNeedsFloor = false
@Transient override val spawnNeedsFloor = true
@Transient override val spawnNeedsWall = true
constructor() : super(
BlockBox(BlockBox.NO_COLLISION, 1, 1),
renderOrder = RenderOrder.BEHIND,
nameFun = { Lang["ITEM_LOGIC_SIGNAL_PUSHBUTTON"] }
)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -35,7 +35,7 @@ class UICheatDetected : UICanvas() {
Terrarum.ingame?.consoleHandler?.setAsClose()
Terrarum.ingame?.consoleHandler?.isVisible = false
Toolkit.blurEntireScreen(batch, 2f, 0, 0, width, height)
Toolkit.blurEntireScreen(batch, camera as OrthographicCamera, 2f, 0, 0, width, height)
batch.color = backgroundCol
Toolkit.fillArea(batch, 0f, 0f, width.toFloat(), height.toFloat())
@@ -80,7 +80,7 @@ class UIPauseTheGame : UICanvas() {
Terrarum.ingame?.consoleHandler?.setAsClose()
Terrarum.ingame?.consoleHandler?.isVisible = false
Toolkit.blurEntireScreen(batch, 2f, 0, 0, width, height)
Toolkit.blurEntireScreen(batch, camera as OrthographicCamera, 2f, 0, 0, width, height)
batch.color = backgroundCol
Toolkit.fillArea(batch, 0f, 0f, width.toFloat(), height.toFloat())

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,159 +0,0 @@
package net.torvald.terrarum.ui
import com.badlogic.gdx.graphics.*
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.badlogic.gdx.graphics.glutils.Float16FrameBuffer
import com.badlogic.gdx.graphics.glutils.FrameBuffer
import com.jme3.math.FastMath
import net.torvald.terrarum.App
import net.torvald.terrarum.ceilToInt
import net.torvald.terrarum.gdxClearAndEnableBlend
import net.torvald.terrarum.inAction
/**
* Created by minjaesong on 2024-11-23.
*/
object BlurMgr {
private class FrameBufferSet(val width: Int, val height: Int) {
private val internalWidth = (width.toFloat() / 4f).ceilToInt() * 4
private val internalHeight = (height.toFloat() / 4f).ceilToInt() * 4
val full = Float16FrameBuffer(width, height, false)
val half = Float16FrameBuffer(internalWidth / 2, internalHeight / 2, false)
val quarter = Float16FrameBuffer(internalWidth / 4, internalHeight / 4, false)
val camera = OrthographicCamera(width.toFloat(), height.toFloat())
val quadFull = Mesh(
true, 4, 4,
VertexAttribute.Position(),
VertexAttribute.ColorUnpacked(),
VertexAttribute.TexCoords(0)
)
val quadHalf = Mesh(
true, 4, 4,
VertexAttribute.Position(),
VertexAttribute.ColorUnpacked(),
VertexAttribute.TexCoords(0)
)
val quadQuarter = Mesh(
true, 4, 4,
VertexAttribute.Position(),
VertexAttribute.ColorUnpacked(),
VertexAttribute.TexCoords(0)
)
init {
camera.setToOrtho(true)
quadFull.setVertices(floatArrayOf(
0f,0f,0f, 1f,1f,1f,1f, 0f,1f,
width.toFloat(),0f,0f, 1f,1f,1f,1f, 1f,1f,
width.toFloat(), height.toFloat(),0f, 1f,1f,1f,1f, 1f,0f,
0f, height.toFloat(),0f, 1f,1f,1f,1f, 0f,0f))
quadFull.setIndices(shortArrayOf(0, 1, 2, 3))
quadHalf.setVertices(floatArrayOf(
0f,0f,0f, 1f,1f,1f,1f, 0f,1f,
width.div(2).toFloat(),0f,0f, 1f,1f,1f,1f, 1f,1f,
width.div(2).toFloat(), height.div(2).toFloat(),0f, 1f,1f,1f,1f, 1f,0f,
0f, height.div(2).toFloat(),0f, 1f,1f,1f,1f, 0f,0f))
quadHalf.setIndices(shortArrayOf(0, 1, 2, 3))
quadQuarter.setVertices(floatArrayOf(
0f,0f,0f, 1f,1f,1f,1f, 0f,1f,
width.div(4).toFloat(),0f,0f, 1f,1f,1f,1f, 1f,1f,
width.div(4).toFloat(), height.div(4).toFloat(),0f, 1f,1f,1f,1f, 1f,0f,
0f, height.div(4).toFloat(),0f, 1f,1f,1f,1f, 0f,0f))
quadQuarter.setIndices(shortArrayOf(0, 1, 2, 3))
}
fun dispose() {
full.dispose()
half.dispose()
quarter.dispose()
}
}
private val fboDict = HashMap<Long, FrameBufferSet>()
private lateinit var blurtex0: Texture
private lateinit var blurtex1: Texture
private lateinit var blurtex2: Texture
private lateinit var blurtex3: Texture
private val shaderKawaseDown = App.loadShaderFromClasspath("shaders/default.vert", "shaders/kawasedown.frag")
private val shaderKawaseUp = App.loadShaderFromClasspath("shaders/default.vert", "shaders/kawaseup.frag")
fun makeBlur(`in`: FrameBuffer, out: FrameBuffer, strength: Float) {
assert(`in`.width == out.width && `in`.height == out.height) {
"Input and Output dimension mismatch: In(${`in`.width}x${`in`.height}), Out(${out.width}x${out.height})"
}
val fbos = fboDict.getOrPut(`in`.width.toLong().shl(32) or `in`.height.toLong()) {
FrameBufferSet(`in`.width, `in`.height)
}
val batch: SpriteBatch? = null // placeholder
val radius3 = FastMath.pow(strength / 2, 0.5f)//(blurRadius - 3f) / 8f
fbos.half.inAction(fbos.camera, batch) {
gdxClearAndEnableBlend(0f,0f,0f,0f)
blurtex0 = `in`.colorBufferTexture
blurtex0.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear)
blurtex0.bind(0)
shaderKawaseDown.bind()
shaderKawaseDown.setUniformMatrix("u_projTrans", fbos.camera.combined)
shaderKawaseDown.setUniformi("u_texture", 0)
shaderKawaseDown.setUniformf("halfpixel", radius3 / fbos.half.width, radius3 / fbos.half.height)
fbos.quadHalf.render(shaderKawaseDown, GL20.GL_TRIANGLE_FAN)
}
fbos.quarter.inAction(fbos.camera, batch) {
gdxClearAndEnableBlend(0f,0f,0f,0f)
blurtex1 = fbos.half.colorBufferTexture
blurtex1.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear)
blurtex1.bind(0)
shaderKawaseDown.bind()
shaderKawaseDown.setUniformMatrix("u_projTrans", fbos.camera.combined)
shaderKawaseDown.setUniformi("u_texture", 0)
shaderKawaseDown.setUniformf("halfpixel", radius3 / fbos.quarter.width, radius3 / fbos.quarter.height)
fbos.quadQuarter.render(shaderKawaseDown, GL20.GL_TRIANGLE_FAN)
}
fbos.half.inAction(fbos.camera, batch) {
gdxClearAndEnableBlend(0f,0f,0f,0f)
blurtex2 = fbos.quarter.colorBufferTexture
blurtex2.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear)
blurtex2.bind(0)
shaderKawaseUp.bind()
shaderKawaseUp.setUniformMatrix("u_projTrans", fbos.camera.combined)
shaderKawaseUp.setUniformi("u_texture", 0)
shaderKawaseUp.setUniformf("halfpixel", radius3 / fbos.quarter.width, radius3 / fbos.quarter.height)
fbos.quadHalf.render(shaderKawaseUp, GL20.GL_TRIANGLE_FAN)
}
out.inAction(fbos.camera, batch) {
gdxClearAndEnableBlend(0f,0f,0f,0f)
blurtex3 = fbos.half.colorBufferTexture
blurtex3.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear)
blurtex3.bind(0)
shaderKawaseUp.bind()
shaderKawaseUp.setUniformMatrix("u_projTrans", fbos.camera.combined)
shaderKawaseUp.setUniformi("u_texture", 0)
shaderKawaseUp.setUniformf("halfpixel", radius3 / fbos.half.width, radius3 / fbos.half.height)
fbos.quadFull.render(shaderKawaseUp, GL20.GL_TRIANGLE_FAN)
}
}
fun dispose() {
fboDict.values.forEach { it.dispose() }
shaderKawaseUp.dispose()
shaderKawaseDown.dispose()
}
}

View File

@@ -40,12 +40,12 @@ class ConsoleWindow : UICanvas() {
private var commandHistory = CircularArray<String>(COMMAND_HISTORY_MAX, true)
private val LINE_HEIGHT = 20
private val MESSAGES_DISPLAY_COUNT = 12
private val MESSAGES_DISPLAY_COUNT = 11
private val inputToMsgboxGap = 3
override var width: Int = App.scr.width
override var height: Int = LINE_HEIGHT * (MESSAGES_DISPLAY_COUNT + 1) + inputToMsgboxGap + 4
override var height: Int = LINE_HEIGHT * (MESSAGES_DISPLAY_COUNT + 1) + inputToMsgboxGap
override var openCloseTime = 0f

View File

@@ -44,7 +44,19 @@ object Toolkit : Disposable {
*/
}
private val shaderKawaseDown = App.loadShaderFromClasspath("shaders/default.vert", "shaders/kawasedown.frag")
private val shaderKawaseUp = App.loadShaderFromClasspath("shaders/default.vert", "shaders/kawaseup.frag")
private val shaderBoxDown = App.loadShaderFromClasspath("shaders/default.vert", "shaders/boxdown.frag")
private val shaderBoxUp = App.loadShaderFromClasspath("shaders/default.vert", "shaders/boxup.frag")
private lateinit var fboBlur: Float16FrameBuffer
private lateinit var fboBlurHalf: Float16FrameBuffer
private lateinit var fboBlurQuarter: Float16FrameBuffer
private lateinit var blurWriteQuad: Mesh
private lateinit var blurWriteQuad2: Mesh
private lateinit var blurWriteQuad4: Mesh
// val baloonTile = TextureRegionPack("assets/graphics/gui/message_black_tileable.tga", 36, 36)
val shadowTile = TextureRegionPack("assets/graphics/gui/blur_shadow.tga", 32, 32)
@@ -70,6 +82,19 @@ object Toolkit : Disposable {
// baloonTile.dispose()
textureWhiteSquare.dispose()
textureWhiteCircle.dispose()
fboBlur.dispose()
fboBlurHalf.dispose()
fboBlurQuarter.dispose()
blurWriteQuad.dispose()
blurWriteQuad2.dispose()
blurWriteQuad4.dispose()
shaderKawaseUp.dispose()
shaderKawaseDown.dispose()
shaderBoxDown.dispose()
shaderBoxUp.dispose()
}
val drawWidth: Int
@@ -176,11 +201,87 @@ object Toolkit : Disposable {
pixmap.fillRectangle(x + w, y, 1, h)
}
fun blurEntireScreen(batch: SpriteBatch, blurRadius0: Float, x: Int, y: Int, w: Int, h: Int) {
private lateinit var blurtex0: Texture
private lateinit var blurtex1: Texture
private lateinit var blurtex2: Texture
private lateinit var blurtex3: Texture
fun blurEntireScreen(batch: SpriteBatch, camera: OrthographicCamera, blurRadius0: Float, x: Int, y: Int, w: Int, h: Int) {
batch.end()
// val blurRadius = FastMath.pow(blurRadius0, 0.5f)
val renderTarget = FrameBufferManager.peek()
BlurMgr.makeBlur(renderTarget, fboBlur, blurRadius0)
//if (blurRadius > 3f) {
val radius3 = FastMath.pow(blurRadius0 / 2, 0.5f)//(blurRadius - 3f) / 8f
fboBlurHalf.inAction(camera, batch) {
blurtex0 = renderTarget.colorBufferTexture
blurtex0.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear)
blurtex0.bind(0)
shaderKawaseDown.bind()
shaderKawaseDown.setUniformMatrix("u_projTrans", camera.combined)
shaderKawaseDown.setUniformi("u_texture", 0)
shaderKawaseDown.setUniformf("halfpixel", radius3 / fboBlurHalf.width, radius3 / fboBlurHalf.height)
blurWriteQuad2.render(shaderKawaseDown, GL20.GL_TRIANGLE_FAN)
}
fboBlurQuarter.inAction(camera, batch) {
blurtex1 = fboBlurHalf.colorBufferTexture
blurtex1.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear)
blurtex1.bind(0)
shaderKawaseDown.bind()
shaderKawaseDown.setUniformMatrix("u_projTrans", camera.combined)
shaderKawaseDown.setUniformi("u_texture", 0)
shaderKawaseDown.setUniformf("halfpixel", radius3 / fboBlurQuarter.width, radius3 / fboBlurQuarter.height)
blurWriteQuad4.render(shaderKawaseDown, GL20.GL_TRIANGLE_FAN)
}
fboBlurHalf.inAction(camera, batch) {
blurtex2 = fboBlurQuarter.colorBufferTexture
blurtex2.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear)
blurtex2.bind(0)
shaderKawaseUp.bind()
shaderKawaseUp.setUniformMatrix("u_projTrans", camera.combined)
shaderKawaseUp.setUniformi("u_texture", 0)
shaderKawaseUp.setUniformf("halfpixel", radius3 / fboBlurQuarter.width, radius3 / fboBlurQuarter.height)
blurWriteQuad2.render(shaderKawaseUp, GL20.GL_TRIANGLE_FAN)
}
fboBlur.inAction(camera, batch) {
blurtex3 = fboBlurHalf.colorBufferTexture
blurtex3.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear)
blurtex3.bind(0)
shaderKawaseUp.bind()
shaderKawaseUp.setUniformMatrix("u_projTrans", camera.combined)
shaderKawaseUp.setUniformi("u_texture", 0)
shaderKawaseUp.setUniformf("halfpixel", radius3 / fboBlurHalf.width, radius3 / fboBlurHalf.height)
blurWriteQuad.render(shaderKawaseUp, GL20.GL_TRIANGLE_FAN)
}
//}
/*fboBlurHalf.inAction(camera, batch) {
blurtex2 = renderTarget.colorBufferTexture
blurtex2.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear)
blurtex2.bind(0)
shaderKawaseDown.bind()
shaderKawaseDown.setUniformMatrix("u_projTrans", camera.combined)
shaderKawaseDown.setUniformi("u_texture", 0)
shaderKawaseDown.setUniformf("halfpixel", blurRadius / fboBlurHalf.width, blurRadius / fboBlurHalf.height)
blurWriteQuad2.render(shaderKawaseDown, GL20.GL_TRIANGLE_FAN)
}
fboBlur.inAction(camera, batch) {
blurtex3 = fboBlurHalf.colorBufferTexture
blurtex3.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear)
blurtex3.bind(0)
shaderKawaseUp.bind()
shaderKawaseUp.setUniformMatrix("u_projTrans", camera.combined)
shaderKawaseUp.setUniformi("u_texture", 0)
shaderKawaseUp.setUniformf("halfpixel", blurRadius / fboBlurHalf.width, blurRadius / fboBlurHalf.height)
blurWriteQuad.render(shaderKawaseUp, GL20.GL_TRIANGLE_FAN)
}*/
Gdx.gl.glActiveTexture(GL20.GL_TEXTURE0) // so that batch that comes next will bind any tex to it
@@ -243,9 +344,33 @@ object Toolkit : Disposable {
init = true
}
else {
blurWriteQuad.dispose()
blurWriteQuad2.dispose()
blurWriteQuad4.dispose()
fboBlur.dispose()
fboBlurHalf.dispose()
fboBlurQuarter.dispose()
}
blurWriteQuad = Mesh(
true, 4, 4,
VertexAttribute.Position(),
VertexAttribute.ColorUnpacked(),
VertexAttribute.TexCoords(0)
)
blurWriteQuad2 = Mesh(
true, 4, 4,
VertexAttribute.Position(),
VertexAttribute.ColorUnpacked(),
VertexAttribute.TexCoords(0)
)
blurWriteQuad4 = Mesh(
true, 4, 4,
VertexAttribute.Position(),
VertexAttribute.ColorUnpacked(),
VertexAttribute.TexCoords(0)
)
val fw = App.scr.width//MathUtils.nextPowerOfTwo(App.scr.width)
val fh = App.scr.height//MathUtils.nextPowerOfTwo(App.scr.height)
@@ -254,5 +379,36 @@ object Toolkit : Disposable {
fh,
false
)
fboBlurHalf = Float16FrameBuffer(
fw / 2,
fh / 2,
false
)
fboBlurQuarter = Float16FrameBuffer(
fw / 4,
fh / 4,
false
)
blurWriteQuad.setVertices(floatArrayOf(
0f,0f,0f, 1f,1f,1f,1f, 0f,1f,
fw.toFloat(),0f,0f, 1f,1f,1f,1f, 1f,1f,
fw.toFloat(), fh.toFloat(),0f, 1f,1f,1f,1f, 1f,0f,
0f, fh.toFloat(),0f, 1f,1f,1f,1f, 0f,0f))
blurWriteQuad.setIndices(shortArrayOf(0, 1, 2, 3))
blurWriteQuad2.setVertices(floatArrayOf(
0f,0f,0f, 1f,1f,1f,1f, 0f,1f,
fw.div(2).toFloat(),0f,0f, 1f,1f,1f,1f, 1f,1f,
fw.div(2).toFloat(), fh.div(2).toFloat(),0f, 1f,1f,1f,1f, 1f,0f,
0f, fh.div(2).toFloat(),0f, 1f,1f,1f,1f, 0f,0f))
blurWriteQuad2.setIndices(shortArrayOf(0, 1, 2, 3))
blurWriteQuad4.setVertices(floatArrayOf(
0f,0f,0f, 1f,1f,1f,1f, 0f,1f,
fw.div(4).toFloat(),0f,0f, 1f,1f,1f,1f, 1f,1f,
fw.div(4).toFloat(), fh.div(4).toFloat(),0f, 1f,1f,1f,1f, 1f,0f,
0f, fh.div(4).toFloat(),0f, 1f,1f,1f,1f, 0f,0f))
blurWriteQuad4.setIndices(shortArrayOf(0, 1, 2, 3))
}
}

View File

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

View File

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

View File

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

View File

@@ -260,7 +260,7 @@ class CreateTileAtlas {
}
// test print
// PixmapIO2.writeTGA(Gdx.files.absolute("${App.defaultDir}/atlas.tga"), atlas, false)
PixmapIO2.writeTGA(Gdx.files.absolute("${App.defaultDir}/atlas.tga"), atlas, false)
// PixmapIO2.writeTGA(Gdx.files.absolute("${AppLoader.defaultDir}/atlasGlow.tga"), atlasGlow, false)
// PixmapIO2.writeTGA(Gdx.files.absolute("${App.defaultDir}/atlas_0.tga"), atlasPrevernal, false)

View File

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

View File

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

View File

@@ -1,20 +0,0 @@
#ifdef GL_ES
precision mediump float;
#endif
in vec4 v_color;
in vec4 v_generic;
in vec2 v_texCoords;
uniform sampler2D u_texture;
uniform sampler2D u_wall;
out vec4 fragColor;
vec4 mult = vec4(0.0, 0.0, 0.0, 1.0);
void main() {
vec4 backcol = texture(u_wall, v_texCoords);
vec4 incol = texture(u_texture, v_texCoords);
vec4 outcol = vec4(incol.rgb, backcol.a * pow(incol.a, 1.4142));
fragColor = mult * outcol;
}

View File

@@ -1,20 +0,0 @@
#ifdef GL_ES
precision mediump float;
#endif
in vec4 v_color;
in vec4 v_generic;
in vec2 v_texCoords;
uniform sampler2D u_texture;
uniform sampler2D u_wall;
out vec4 fragColor;
vec4 mult = vec4(0.0, 0.0, 0.0, 1.4142);
void main() {
vec4 backcol = texture(u_wall, v_texCoords);
vec4 incol = texture(u_texture, v_texCoords);
vec4 outcol = vec4(incol.rgb, backcol.a * pow(incol.a, 2.0));
fragColor = mult * outcol;
}