diff --git a/src/net/torvald/spriteassembler/SpriteAssemblerApp.kt b/src/net/torvald/spriteassembler/SpriteAssemblerApp.kt index 2bf91a04c..4456b1055 100644 --- a/src/net/torvald/spriteassembler/SpriteAssemblerApp.kt +++ b/src/net/torvald/spriteassembler/SpriteAssemblerApp.kt @@ -95,6 +95,7 @@ class SpriteAssemblerApp(val gdxWindow: SpriteAssemblerPreview) : JFrame() { } panelCode.font = Font(Font.MONOSPACED, Font.PLAIN, 12) + panelCode.text = "Enter your descriptor code here…" panelAnimationsList.model = DefaultListModel() panelBodypartsList.model = DefaultListModel() @@ -278,7 +279,7 @@ class SpriteAssemblerPreview: Game() { } - gdxClearAndSetBlend(.62f,.79f,1f,1f) + gdxClearAndSetBlend(bgCol) batch.inUse { diff --git a/src/net/torvald/terrarum/AppLoader.java b/src/net/torvald/terrarum/AppLoader.java index e47587f47..9af051cf5 100644 --- a/src/net/torvald/terrarum/AppLoader.java +++ b/src/net/torvald/terrarum/AppLoader.java @@ -181,7 +181,7 @@ public class AppLoader implements ApplicationListener { /** A gamepad. Multiple gamepads may controll this single virtualised gamepad. */ public static TerrarumController gamepad = null; - public static float gamepadDeadzone = 0.2f; + public static float gamepadDeadzone = 0.3f; /** @@ -688,6 +688,7 @@ public class AppLoader implements ApplicationListener { System.out.println(String.format("os.name = %s (with identifier %s)", OSName, operationSystem)); System.out.println(String.format("os.version = %s", OSVersion)); System.out.println(String.format("default directory: %s", defaultDir)); + System.out.println(String.format("java version = %s", System.getProperty("java.version"))); } private static void createDirs() { diff --git a/src/net/torvald/terrarum/IngameInstance.kt b/src/net/torvald/terrarum/IngameInstance.kt index 84161cb03..8b6fd1faf 100644 --- a/src/net/torvald/terrarum/IngameInstance.kt +++ b/src/net/torvald/terrarum/IngameInstance.kt @@ -9,7 +9,6 @@ import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid import net.torvald.terrarum.realestate.LandUtil import net.torvald.terrarum.ui.ConsoleWindow import net.torvald.util.SortedArrayList -import java.util.* import java.util.concurrent.locks.Lock /** @@ -143,11 +142,11 @@ open class IngameInstance(val batch: SpriteBatch) : Screen { if (actorContainerActive.size == 0 && actorContainerInactive.size == 0) throw IllegalArgumentException("Actor with ID $ID does not exist.") - var index = actorContainerActive.binarySearch(ID) - if (index < 0) { - index = actorContainerInactive.binarySearch(ID) + var actor = actorContainerActive.searchFor(ID) { it.referenceID!! } + if (actor == null) { + actor = actorContainerInactive.searchFor(ID) { it.referenceID!! } - if (index < 0) { + if (actor == null) { /*JOptionPane.showMessageDialog( null, "Actor with ID $ID does not exist.", @@ -156,36 +155,14 @@ open class IngameInstance(val batch: SpriteBatch) : Screen { throw IllegalArgumentException("Actor with ID $ID does not exist.") } else - return actorContainerInactive[index] + return actor } else - return actorContainerActive[index] + return actor } - fun ArrayList<*>.binarySearch(actor: Actor) = this.binarySearch(actor.referenceID!!) - - fun ArrayList<*>.binarySearch(ID: Int): Int { - // code from collections/Collections.kt - var low = 0 - var high = this.size - 1 - - while (low <= high) { - val mid = (low + high).ushr(1) // safe from overflows - - val midVal = get(mid)!! - - if (ID > midVal.hashCode()) - low = mid + 1 - else if (ID < midVal.hashCode()) - high = mid - 1 - else - return mid // key found - } - return -(low + 1) // key not found - } - - fun SortedArrayList<*>.binarySearch(actor: Actor) = this.toArrayList().binarySearch(actor.referenceID!!) - fun SortedArrayList<*>.binarySearch(ID: Int) = this.toArrayList().binarySearch(ID) + //fun SortedArrayList<*>.binarySearch(actor: Actor) = this.toArrayList().binarySearch(actor.referenceID!!) + //fun SortedArrayList<*>.binarySearch(ID: Int) = this.toArrayList().binarySearch(ID) open fun removeActor(ID: Int) = removeActor(getActorByID(ID)) /** @@ -199,9 +176,9 @@ open class IngameInstance(val batch: SpriteBatch) : Screen { open fun removeActor(actor: Actor?) { if (actor == null) return - val indexToDelete = actorContainerActive.binarySearch(actor.referenceID!!) - if (indexToDelete >= 0) { - actorContainerActive.removeAt(indexToDelete) + val indexToDelete = actorContainerActive.searchFor(actor.referenceID!!) { it.referenceID!! } + if (indexToDelete != null) { + actorContainerActive.remove(indexToDelete) } } @@ -223,13 +200,13 @@ open class IngameInstance(val batch: SpriteBatch) : Screen { if (actorContainerActive.size == 0) false else - actorContainerActive.binarySearch(ID) >= 0 + actorContainerActive.searchFor(ID) { it.referenceID!! } != null fun isInactive(ID: Int): Boolean = if (actorContainerInactive.size == 0) false else - actorContainerInactive.binarySearch(ID) >= 0 + actorContainerInactive.searchFor(ID) { it.referenceID!! } != null /** * actorContainerActive extensions diff --git a/src/net/torvald/terrarum/Terrarum.kt b/src/net/torvald/terrarum/Terrarum.kt index 6e90b42c7..3faf2e78a 100644 --- a/src/net/torvald/terrarum/Terrarum.kt +++ b/src/net/torvald/terrarum/Terrarum.kt @@ -12,7 +12,6 @@ import com.badlogic.gdx.graphics.glutils.ShaderProgram import com.badlogic.gdx.graphics.glutils.ShapeRenderer import com.badlogic.gdx.utils.GdxRuntimeException import com.jme3.math.FastMath -import net.torvald.util.CircularArray import net.torvald.random.HQRNG import net.torvald.terrarum.AppLoader.* import net.torvald.terrarum.gameactors.Actor @@ -23,6 +22,7 @@ import net.torvald.terrarum.worlddrawer.CreateTileAtlas import net.torvald.terrarum.worlddrawer.WorldCamera import net.torvald.terrarumsansbitmap.gdx.GameFontBase import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack +import net.torvald.util.CircularArray import org.lwjgl.BufferUtils import java.io.File import kotlin.math.absoluteValue @@ -196,7 +196,6 @@ object Terrarum : Screen { init { println("$NAME version ${AppLoader.getVERSION_STRING()}") - println("Java Runtime version ${System.getProperty("java.version")}") println("LibGDX version ${com.badlogic.gdx.Version.VERSION}") @@ -613,6 +612,10 @@ fun blendNormal(batch: SpriteBatch) { // - https://www.andersriggelsen.dk/glblendfunc.php } +fun gdxClearAndSetBlend(color: Color) { + gdxClearAndSetBlend(color.r, color.g, color.b, color.a) +} + fun gdxClearAndSetBlend(r: Float, g: Float, b: Float, a: Float) { Gdx.gl.glClearColor(r,g,b,a) Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT) diff --git a/src/net/torvald/terrarum/blockproperties/Wire.kt b/src/net/torvald/terrarum/blockproperties/Wire.kt index c9aac971a..68618ad86 100644 --- a/src/net/torvald/terrarum/blockproperties/Wire.kt +++ b/src/net/torvald/terrarum/blockproperties/Wire.kt @@ -11,9 +11,11 @@ object Wire { const val BIT_UTILITY_PROTOTYPE = 2 const val BIT_POWER_LOW = 4 const val BIT_POWER_HIGHT = 8 - const val BIT_ETHERNET = 16 + const val BIT_PARALLEL_8B = 16 // uses bit-to-mantissa encoding + const val BIT_PARALLEL_16B = 32 // uses bit-to-mantissa encoding + const val BIT_ETHERNET = 64 // the actual datagramme should be represented by another means than the ConduitFills - /* A mapping for World's conduitFills[] index */ + /* A mapping for World's WiringNode.fills[] index */ const val FILL_ID_SIGNAL_RED = 0 const val FILL_ID_UTILITY_PROTOTYPE = 1 @@ -23,4 +25,22 @@ object Wire { else -> null } + + /** + * Encodes a byte to Float's mantissa. Normal value range is 1.0..1.99609375. When decoding, the sign and exponent bits + * must be ignored. (e.g. the encoded float might have non-one-point-something value after "bitwise" add/subtraction. + * + * MSB of the byte is also the highest bit in the mantissa. Therefore ```0x80``` will be encoded as ```1.5``` + */ + fun Byte.toFloatMantissa(): Float = Float.fromBits(0x3F800000 or (this.toInt().and(0xFF) shl 15)) + fun Short.toFloatMantissa(): Float = Float.fromBits(0x3F800000 or (this.toInt().and(0xFFFF) shl 7)) + + /** + * This function does the reversal calculation. + * + * @see net.torvald.terrarum.blockproperties.Wire.toFloatMantissa + */ + fun Float.fromMantissaToByte(): Byte = this.toRawBits().ushr(15).and(0xFF).toByte() + fun Float.fromMantissaToShort(): Short = this.toRawBits().ushr(7).and(0xFFFF).toShort() + } \ No newline at end of file diff --git a/src/net/torvald/terrarum/console/CommandDict.kt b/src/net/torvald/terrarum/console/CommandDict.kt index d17cedc61..9595d06ea 100644 --- a/src/net/torvald/terrarum/console/CommandDict.kt +++ b/src/net/torvald/terrarum/console/CommandDict.kt @@ -44,7 +44,7 @@ object CommandDict { "kill" to KillActor, "money" to MoneyDisp, "screenshot" to TakeScreenshot, - //"resize" to ResizeScreen, + "resize" to ResizeScreen, // Test codes "bulletintest" to SetBulletin, diff --git a/src/net/torvald/terrarum/console/ResizeScreen.kt b/src/net/torvald/terrarum/console/ResizeScreen.kt index 7e5d0944c..ce3f07e35 100644 --- a/src/net/torvald/terrarum/console/ResizeScreen.kt +++ b/src/net/torvald/terrarum/console/ResizeScreen.kt @@ -1,12 +1,11 @@ package net.torvald.terrarum.console import net.torvald.terrarum.AppLoader -import net.torvald.terrarum.Terrarum object ResizeScreen: ConsoleCommand { override fun execute(args: Array) { if (args.size == 3) { - Terrarum.resize(args[1].toInt(), args[2].toInt()) + AppLoader.resizeScreen(args[1].toInt(), args[2].toInt()) } else if (args.size == 2) { when (args[1]) { diff --git a/src/net/torvald/terrarum/gameactors/Actor.kt b/src/net/torvald/terrarum/gameactors/Actor.kt index 42fd2ff2f..b48160c45 100644 --- a/src/net/torvald/terrarum/gameactors/Actor.kt +++ b/src/net/torvald/terrarum/gameactors/Actor.kt @@ -1,5 +1,6 @@ package net.torvald.terrarum.gameactors +import net.torvald.terrarum.Terrarum import net.torvald.terrarum.itemproperties.ItemCodex.ACTORID_MIN @@ -34,7 +35,7 @@ abstract class Actor(val renderOrder: RenderOrder) : Comparable, Runnable * Valid RefID is equal to or greater than 16777216. * @return Reference ID. (16777216-0x7FFF_FFFF) */ - open var referenceID: ActorID? = null + open var referenceID: ActorID = Terrarum.generateUniqueReferenceID(renderOrder) // once this was nullable without initialiser. If you're going to revert to that, add the reason why this should be nullable. var actorValue = ActorValue(this) // FIXME cyclic reference on GSON @Volatile var flagDespawn = false diff --git a/src/net/torvald/terrarum/gameworld/GameWorld.kt b/src/net/torvald/terrarum/gameworld/GameWorld.kt index 621ce9532..87aa42f4b 100644 --- a/src/net/torvald/terrarum/gameworld/GameWorld.kt +++ b/src/net/torvald/terrarum/gameworld/GameWorld.kt @@ -2,7 +2,6 @@ package net.torvald.terrarum.gameworld import com.badlogic.gdx.graphics.Color -import net.torvald.util.SortedArrayList import net.torvald.terrarum.AppLoader.printdbg import net.torvald.terrarum.Terrarum import net.torvald.terrarum.blockproperties.Block @@ -12,6 +11,7 @@ import net.torvald.terrarum.modulebasegame.gameworld.WorldSimulator import net.torvald.terrarum.realestate.LandUtil import net.torvald.terrarum.serialise.ReadLayerDataZip import net.torvald.terrarum.toInt +import net.torvald.util.SortedArrayList import org.dyn4j.geometry.Vector2 import kotlin.math.absoluteValue import kotlin.math.sign @@ -74,6 +74,9 @@ open class GameWorld { val fluidTypes: HashMap @TEMzPayload("FlFL", TEMzPayload.INT48_FLOAT_PAIR) val fluidFills: HashMap + + // Actually stores the wiring data; used by renderers // + @TEMzPayload("CtYP", TEMzPayload.INT48_INT_PAIR) val conduitTypes: HashMap // 1 bit = 1 conduit (pipe/wire) type @TEMzPayload("CfL", TEMzPayload.INT48_FLOAT_PAIR) @@ -83,6 +86,8 @@ open class GameWorld { val conduitFills1: HashMap // size of gas packet on the block get() = conduitFills[1] + // Built from the above data; used by hypothetical updater // + private val wiringNodes = SortedArrayList() //public World physWorld = new World( new Vec2(0, -Terrarum.game.gravitationalAccel) ); diff --git a/src/net/torvald/terrarum/modulebasegame/BuildingMaker.kt b/src/net/torvald/terrarum/modulebasegame/BuildingMaker.kt index 4aba4d4a8..5471a794c 100644 --- a/src/net/torvald/terrarum/modulebasegame/BuildingMaker.kt +++ b/src/net/torvald/terrarum/modulebasegame/BuildingMaker.kt @@ -137,7 +137,7 @@ class BuildingMaker(batch: SpriteBatch) : IngameInstance(batch) { internal var showSelection = true val blockPointingCursor = object : ActorWithBody(Actor.RenderOrder.OVERLAY) { - override var referenceID: ActorID? = 1048575 // custom refID + override var referenceID: ActorID = 1048575 // custom refID override val hitbox = Hitbox(0.0, 0.0, 16.0, 16.0) @@ -177,7 +177,7 @@ class BuildingMaker(batch: SpriteBatch) : IngameInstance(batch) { private var _testMarkerDrawCalls = 0L private fun generateNewBlockMarkerVisible(x: Int, y: Int) = object : ActorWithBody(Actor.RenderOrder.OVERLAY) { - override var referenceID: ActorID? = blockPosToRefID(x, y) // custom refID + override var referenceID: ActorID = blockPosToRefID(x, y) // custom refID override val hitbox = Hitbox(x * 16.0, y * 16.0, 16.0, 16.0) override fun drawBody(batch: SpriteBatch) { diff --git a/src/net/torvald/terrarum/modulebasegame/Ingame.kt b/src/net/torvald/terrarum/modulebasegame/Ingame.kt index 4cbdf7da3..827b2ead3 100644 --- a/src/net/torvald/terrarum/modulebasegame/Ingame.kt +++ b/src/net/torvald/terrarum/modulebasegame/Ingame.kt @@ -747,8 +747,8 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) { if (actor.referenceID == theRealGamer.referenceID || actor.referenceID == 0x51621D) // do not delete this magic throw RuntimeException("Attempted to remove player.") - val indexToDelete = actorContainerActive.binarySearch(actor.referenceID!!) - if (indexToDelete >= 0) { + val indexToDelete = actorContainerActive.searchForIndex(actor.referenceID!!) { it.referenceID!! } + if (indexToDelete != null) { printdbg(this, "Removing actor $actor") printStackTrace() @@ -783,6 +783,28 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) { } } + private fun ArrayList<*>.binarySearch(actor: Actor) = this.binarySearch(actor.referenceID!!) + + private fun ArrayList<*>.binarySearch(ID: Int): Int { + // code from collections/Collections.kt + var low = 0 + var high = this.size - 1 + + while (low <= high) { + val mid = (low + high).ushr(1) // safe from overflows + + val midVal = get(mid)!! + + if (ID > midVal.hashCode()) + low = mid + 1 + else if (ID < midVal.hashCode()) + high = mid - 1 + else + return mid // key found + } + return -(low + 1) // key not found + } + /** * Check for duplicates, append actor and sort the list */ diff --git a/src/net/torvald/util/SortedArrayList.kt b/src/net/torvald/util/SortedArrayList.kt index 91e0537cc..f583c2b60 100644 --- a/src/net/torvald/util/SortedArrayList.kt +++ b/src/net/torvald/util/SortedArrayList.kt @@ -39,9 +39,58 @@ class SortedArrayList>(initialSize: Int = 10) { fun removeAt(index: Int) = arrayList.removeAt(index) fun remove(element: T) = arrayList.remove(element) - fun removeLast() = arrayList.removeAt(arrayList.size) + fun removeLast() = arrayList.removeAt(arrayList.size - 1) operator fun get(index: Int) = arrayList[index] + fun getOrNull(index: Int?) = if (index == null) null else get(index) + /** + * Searches for the element. Null if the element was not found + */ + fun contains(element: T): Boolean { + // code from collections/Collections.kt + var low = 0 + var high = this.size - 1 + + while (low <= high) { + val mid = (low + high).ushr(1) // safe from overflows + + val midVal = get(mid) + + if (element > midVal) + low = mid + 1 + else if (element < midVal) + high = mid - 1 + else + return true // key found + } + return false // key not found + } + + /** Searches the element using given predicate instead of the element itself. Returns index in the array where desired + * element is stored. + * (e.g. search the Actor by its ID rather than the actor instance) */ + fun > searchForIndex(key: R, predicate: (T) -> R): Int? { + var low = 0 + var high = this.size - 1 + + while (low <= high) { + val mid = (low + high).ushr(1) // safe from overflows + + val midVal = predicate(get(mid)) + + if (key > midVal) + low = mid + 1 + else if (key < midVal) + high = mid - 1 + else + return mid // key found + } + return null // key not found + } + + /** Searches the element using given predicate instead of the element itself. Returns the element desired. + * (e.g. search the Actor by its ID rather than the actor instance) */ + fun > searchFor(key: R, predicate: (T) -> R): T? = getOrNull(searchForIndex(key, predicate)) fun iterator() = arrayList.iterator() fun forEach(action: (T) -> Unit) = arrayList.forEach(action)