From bbd78786305c1a21675d23c9f0b95d4c20ec6c26 Mon Sep 17 00:00:00 2001 From: minjaesong Date: Tue, 7 Sep 2021 17:15:35 +0900 Subject: [PATCH] tooltip and notifier moved to the base ingame --- src/net/torvald/terrarum/IngameInstance.kt | 121 +++++++++++++++++- .../terrarum/gameworld/WorldSimulator.kt | 66 ---------- .../terrarum/modulebasegame/BuildingMaker.kt | 1 - .../terrarum/modulebasegame/TerrarumIngame.kt | 94 +++++--------- src/net/torvald/terrarum/ui/ConsoleWindow.kt | 19 ++- 5 files changed, 161 insertions(+), 140 deletions(-) diff --git a/src/net/torvald/terrarum/IngameInstance.kt b/src/net/torvald/terrarum/IngameInstance.kt index 68f78edf4..62567618b 100644 --- a/src/net/torvald/terrarum/IngameInstance.kt +++ b/src/net/torvald/terrarum/IngameInstance.kt @@ -7,17 +7,27 @@ import net.torvald.terrarum.blockproperties.BlockCodex import net.torvald.terrarum.blockproperties.WireCodex import net.torvald.terrarum.gameactors.Actor import net.torvald.terrarum.gameactors.ActorID +import net.torvald.terrarum.gameactors.ActorWithBody import net.torvald.terrarum.gameactors.BlockMarkerActor import net.torvald.terrarum.gameactors.faction.FactionCodex import net.torvald.terrarum.gameitem.ItemID import net.torvald.terrarum.gameworld.GameWorld +import net.torvald.terrarum.gameworld.WorldSimulator import net.torvald.terrarum.itemproperties.ItemCodex import net.torvald.terrarum.itemproperties.MaterialCodex import net.torvald.terrarum.modulebasegame.IngameRenderer import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid +import net.torvald.terrarum.modulebasegame.ui.Notification +import net.torvald.terrarum.modulebasegame.ui.UITooltip import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.VirtualDisk import net.torvald.terrarum.ui.ConsoleWindow +import net.torvald.terrarum.ui.UICanvas import net.torvald.util.SortedArrayList +import org.khelekore.prtree.DistanceCalculator +import org.khelekore.prtree.DistanceResult +import org.khelekore.prtree.MBRConverter +import org.khelekore.prtree.PRTree +import org.khelekore.prtree.PointND import java.util.concurrent.locks.Lock /** @@ -26,6 +36,23 @@ import java.util.concurrent.locks.Lock */ open class IngameInstance(val batch: SpriteBatch) : Screen { + open protected val actorMBRConverter = object : MBRConverter { + override fun getDimensions(): Int = 2 + override fun getMin(axis: Int, t: ActorWithBody): Double = + when (axis) { + 0 -> t.hitbox.startX + 1 -> t.hitbox.startY + else -> throw IllegalArgumentException("nonexistent axis $axis for ${dimensions}-dimensional object") + } + + override fun getMax(axis: Int, t: ActorWithBody): Double = + when (axis) { + 0 -> t.hitbox.endX + 1 -> t.hitbox.endY + else -> throw IllegalArgumentException("nonexistent axis $axis for ${dimensions}-dimensional object") + } + } + lateinit var savegameArchive: VirtualDisk internal set @@ -41,8 +68,17 @@ open class IngameInstance(val batch: SpriteBatch) : Screen { var newWorldLoadedLatch = false + /** For in-world text overlays? e.g. cursor on the ore block and tooltip will say "Malachite" or something */ + open var uiTooltip: UITooltip = UITooltip() + open var notifier: Notification = Notification() + + init { consoleHandler.setPosition(0, 0) + notifier.setPosition( + (AppLoader.screenSize.screenW - notifier.width) / 2, + AppLoader.screenSize.screenH - notifier.height - AppLoader.screenSize.tvSafeGraphicsHeight + ) printdbg(this, "New ingame instance ${this.hashCode()}, called from") printStackTrace(this) @@ -85,7 +121,9 @@ open class IngameInstance(val batch: SpriteBatch) : Screen { val actorContainerActive = SortedArrayList(ACTORCONTAINER_INITIAL_SIZE) val actorContainerInactive = SortedArrayList(ACTORCONTAINER_INITIAL_SIZE) - // FIXME queues will not work; input processing (blocks will queue) and queue consuming cannot be synchronised + var actorsRTree: PRTree = PRTree(actorMBRConverter, 24) // no lateinit! + protected set + val terrainChangeQueue = ArrayList() val wallChangeQueue = ArrayList() val wireChangeQueue = ArrayList() // if 'old' is set and 'new' is blank, it's a wire cutter @@ -288,13 +326,84 @@ open class IngameInstance(val batch: SpriteBatch) : Screen { - - data class BlockChangeQueueItem(val old: ItemID, val new: ItemID, val posX: Int, val posY: Int) - open fun sendNotification(messages: Array) {} - open fun sendNotification(messages: List) {} - open fun sendNotification(singleMessage: String) {} + open fun sendNotification(messages: Array) { + notifier.sendNotification(messages.toList()) + } + + open fun sendNotification(messages: List) { + notifier.sendNotification(messages) + } + + open fun sendNotification(singleMessage: String) = sendNotification(listOf(singleMessage)) + + + open fun setTooltipMessage(message: String?) { + if (message == null) { + uiTooltip.setAsClose() + } + else { + if (uiTooltip.isClosed || uiTooltip.isClosing) { + uiTooltip.setAsOpen() + } + uiTooltip.message = message + } + } + + + // simple euclidean norm, squared + private val actorDistanceCalculator = DistanceCalculator { t: ActorWithBody, p: PointND -> + val dist1 = (p.getOrd(0) - t.hitbox.centeredX).sqr() + (p.getOrd(1) - t.hitbox.centeredY).sqr() + // ROUNDWORLD implementation + val dist2 = (p.getOrd(0) - (t.hitbox.centeredX - world.width * TerrarumAppConfiguration.TILE_SIZE)).sqr() + (p.getOrd(1) - t.hitbox.centeredY).sqr() + val dist3 = (p.getOrd(0) - (t.hitbox.centeredX + world.width * TerrarumAppConfiguration.TILE_SIZE)).sqr() + (p.getOrd(1) - t.hitbox.centeredY).sqr() + + minOf(dist1, minOf(dist2, dist3)) + } + + /** + * @return list of actors under the bounding box given, list may be empty if no actor is under the point. + */ + fun getActorsAt(startPoint: Point2d, endPoint: Point2d): List { + val outList = ArrayList() + try { + actorsRTree.find(startPoint.x, startPoint.y, endPoint.x, endPoint.y, outList) + } + catch (e: NullPointerException) {} + return outList + } + + fun getActorsAt(worldX: Double, worldY: Double): List { + val outList = ArrayList() + try { + actorsRTree.find(worldX, worldY, worldX + 1.0, worldY + 1.0, outList) + } + catch (e: NullPointerException) {} + return outList + } + + /** Will use centre point of the actors + * @return List of DistanceResult, list may be empty */ + fun findKNearestActors(from: ActorWithBody, maxHits: Int): List> { + return actorsRTree.nearestNeighbour(actorDistanceCalculator, null, maxHits, object : PointND { + override fun getDimensions(): Int = 2 + override fun getOrd(axis: Int): Double = when(axis) { + 0 -> from.hitbox.centeredX + 1 -> from.hitbox.centeredY + else -> throw IllegalArgumentException("nonexistent axis $axis for ${dimensions}-dimensional object") + } + }) + } + /** Will use centre point of the actors + * @return Pair of: the actor, distance from the actor; null if none found */ + fun findNearestActors(from: ActorWithBody): DistanceResult? { + val t = findKNearestActors(from, 1) + return if (t.isNotEmpty()) + t[0] + else + null + } } inline fun Lock.lock(body: () -> Unit) { diff --git a/src/net/torvald/terrarum/gameworld/WorldSimulator.kt b/src/net/torvald/terrarum/gameworld/WorldSimulator.kt index 3d0433e40..d0e539ccb 100644 --- a/src/net/torvald/terrarum/gameworld/WorldSimulator.kt +++ b/src/net/torvald/terrarum/gameworld/WorldSimulator.kt @@ -74,18 +74,12 @@ object WorldSimulator { get() = ingame.world - private lateinit var actorsRTree: PRTree - fun resetForThisFrame() { } /** Must be called BEFORE the actors update -- actors depend on the R-Tree for various things */ operator fun invoke(player: ActorHumanoid?, delta: Float) { - // build the r-tree that will be used during a single frame of updating - actorsRTree = PRTree(actorMBRConverter, 24) - actorsRTree.load(ingame.actorContainerActive.filterIsInstance()) - //printdbg(this, "============================") @@ -112,42 +106,7 @@ object WorldSimulator { //printdbg(this, "============================") } - /** - * @return list of actors under the bounding box given, list may be empty if no actor is under the point. - */ - fun getActorsAt(startPoint: Point2d, endPoint: Point2d): List { - val outList = ArrayList() - actorsRTree.find(startPoint.x, startPoint.y, endPoint.x, endPoint.y, outList) - return outList - } - fun getActorsAt(worldX: Double, worldY: Double): List { - val outList = ArrayList() - actorsRTree.find(worldX, worldY, worldX + 1.0, worldY + 1.0, outList) - return outList - } - - /** Will use centre point of the actors - * @return List of DistanceResult, list may be empty */ - fun findKNearestActors(from: ActorWithBody, maxHits: Int): List> { - return actorsRTree.nearestNeighbour(actorDistanceCalculator, null, maxHits, object : PointND { - override fun getDimensions(): Int = 2 - override fun getOrd(axis: Int): Double = when(axis) { - 0 -> from.hitbox.centeredX - 1 -> from.hitbox.centeredY - else -> throw IllegalArgumentException("nonexistent axis $axis for ${dimensions}-dimensional object") - } - }) - } - /** Will use centre point of the actors - * @return Pair of: the actor, distance from the actor; null if none found */ - fun findNearestActors(from: ActorWithBody): DistanceResult? { - val t = findKNearestActors(from, 1) - return if (t.isNotEmpty()) - t[0] - else - null - } fun degrass() { if (ingame.terrainChangeQueue.isNotEmpty()) { AppLoader.measureDebugTime("WorldSimulator.degrass") { @@ -482,32 +441,7 @@ object WorldSimulator { fun ItemID.isFallable() = BlockCodex[this].maxSupport - private val actorMBRConverter = object : MBRConverter { - override fun getDimensions(): Int = 2 - override fun getMin(axis: Int, t: ActorWithBody): Double = - when (axis) { - 0 -> t.hitbox.startX - 1 -> t.hitbox.startY - else -> throw IllegalArgumentException("nonexistent axis $axis for ${dimensions}-dimensional object") - } - override fun getMax(axis: Int, t: ActorWithBody): Double = - when (axis) { - 0 -> t.hitbox.endX - 1 -> t.hitbox.endY - else -> throw IllegalArgumentException("nonexistent axis $axis for ${dimensions}-dimensional object") - } - } - - // simple euclidean norm, squared - private val actorDistanceCalculator = DistanceCalculator { t: ActorWithBody, p: PointND -> - val dist1 = (p.getOrd(0) - t.hitbox.centeredX).sqr() + (p.getOrd(1) - t.hitbox.centeredY).sqr() - // ROUNDWORLD implementation - val dist2 = (p.getOrd(0) - (t.hitbox.centeredX - world.width * TILE_SIZE)).sqr() + (p.getOrd(1) - t.hitbox.centeredY).sqr() - val dist3 = (p.getOrd(0) - (t.hitbox.centeredX + world.width * TILE_SIZE)).sqr() + (p.getOrd(1) - t.hitbox.centeredY).sqr() - - minOf(dist1, minOf(dist2, dist3)) - } private val wiresimOverscan = 60 diff --git a/src/net/torvald/terrarum/modulebasegame/BuildingMaker.kt b/src/net/torvald/terrarum/modulebasegame/BuildingMaker.kt index ba9f3efb5..800f91b5b 100644 --- a/src/net/torvald/terrarum/modulebasegame/BuildingMaker.kt +++ b/src/net/torvald/terrarum/modulebasegame/BuildingMaker.kt @@ -100,7 +100,6 @@ class BuildingMaker(batch: SpriteBatch) : IngameInstance(batch) { override var actorNowPlaying: ActorHumanoid? = MovableWorldCamera(this) val uiToolbox = UINSMenu("Menu", 100, menuYaml) - val notifier = Notification() val uiPaletteSelector = UIPaletteSelector(this) val uiPalette = UIBuildingMakerBlockChooser(this) val uiPenMenu = UIBuildingMakerPenMenu(this) diff --git a/src/net/torvald/terrarum/modulebasegame/TerrarumIngame.kt b/src/net/torvald/terrarum/modulebasegame/TerrarumIngame.kt index 65d10ebe5..a542a3c9d 100644 --- a/src/net/torvald/terrarum/modulebasegame/TerrarumIngame.kt +++ b/src/net/torvald/terrarum/modulebasegame/TerrarumIngame.kt @@ -47,6 +47,8 @@ import net.torvald.terrarum.worlddrawer.BlocksDrawer import net.torvald.terrarum.worlddrawer.FeaturesDrawer import net.torvald.terrarum.worlddrawer.WorldCamera import net.torvald.util.CircularArray +import org.khelekore.prtree.MBRConverter +import org.khelekore.prtree.PRTree import java.util.concurrent.locks.ReentrantLock import kotlin.math.roundToInt @@ -143,9 +145,6 @@ open class TerrarumIngame(batch: SpriteBatch) : IngameInstance(batch) { } - - lateinit var notifier: UICanvas - lateinit var uiPieMenu: UICanvas lateinit var uiQuickBar: UICanvas lateinit var uiInventoryPlayer: UICanvas @@ -182,9 +181,6 @@ open class TerrarumIngame(batch: SpriteBatch) : IngameInstance(batch) { private lateinit var uiBasicInfo: UICanvas private lateinit var uiWatchTierOne: UICanvas - /** For in-world text overlays? e.g. cursor on the ore block and tooltip will say "Malachite" or something */ - private lateinit var uiTooltip: UITooltip - lateinit var uiCheatMotherfuckerNootNoot: UICheatDetected @@ -349,14 +345,6 @@ open class TerrarumIngame(batch: SpriteBatch) : IngameInstance(batch) { //consoleHandler.setPosition(0, 0) - // init notifier - notifier = Notification() - notifier.setPosition( - (AppLoader.screenSize.screenW - notifier.width) / 2, - AppLoader.screenSize.screenH - notifier.height - AppLoader.screenSize.tvSafeGraphicsHeight - ) - - // >- queue up game UIs that should pause the world -< @@ -396,8 +384,6 @@ open class TerrarumIngame(batch: SpriteBatch) : IngameInstance(batch) { uiBasicInfo.setPosition((uiQuickBar.posX - uiBasicInfo.width - AppLoader.screenSize.tvSafeActionWidth) / 2 + AppLoader.screenSize.tvSafeActionWidth, uiWatchTierOne.posY) - uiTooltip = UITooltip() - uiCheatMotherfuckerNootNoot = UICheatDetected() @@ -447,7 +433,7 @@ open class TerrarumIngame(batch: SpriteBatch) : IngameInstance(batch) { var uiOpened = false // TODO actorsUnderMouse: support ROUNDWORLD - val actorsUnderMouse: List = WorldSimulator.getActorsAt(Terrarum.mouseX, Terrarum.mouseY).filterIsInstance() + val actorsUnderMouse: List = getActorsAt(Terrarum.mouseX, Terrarum.mouseY).filterIsInstance() if (actorsUnderMouse.size > 1) { AppLoader.printdbgerr(this, "Multiple fixtures at world coord ${Terrarum.mouseX}, ${Terrarum.mouseY}") } @@ -580,29 +566,6 @@ open class TerrarumIngame(batch: SpriteBatch) : IngameInstance(batch) { WorldSimulator.resetForThisFrame() - /////////////////////////// - // world-related updates // - /////////////////////////// - BlockPropUtil.dynamicLumFuncTickClock() - world.updateWorldTime(delta) - measureDebugTime("WorldSimulator.update") { - WorldSimulator.invoke(actorNowPlaying, delta) - } - measureDebugTime("WeatherMixer.update") { - WeatherMixer.update(delta, actorNowPlaying, world) - } - measureDebugTime("BlockStats.update") { - BlockStats.update() - } - // fill up visibleActorsRenderFront for wires, if: - // 1. something is cued on the wire change queue - // 2. wire renderclass changed - if (newWorldLoadedLatch || wireChangeQueue.isNotEmpty() || selectedWireRenderClass != oldSelectedWireRenderClass) { - measureDebugTime("Ingame.FillUpWiresBuffer") { - fillUpWiresBuffer() - } - } - //////////////////////////// // camera-related updates // @@ -624,7 +587,32 @@ open class TerrarumIngame(batch: SpriteBatch) : IngameInstance(batch) { // TODO thread pool(?) CollisionSolver.process() - //WorldCamera.update(gameworld, actorNowPlaying) + + /////////////////////////// + // world-related updates // + /////////////////////////// + actorsRTree = PRTree(actorMBRConverter, 24) + actorsRTree.load(actorContainerActive.filterIsInstance()) + + BlockPropUtil.dynamicLumFuncTickClock() + world.updateWorldTime(delta) + measureDebugTime("WorldSimulator.update") { + WorldSimulator.invoke(actorNowPlaying, delta) + } + measureDebugTime("WeatherMixer.update") { + WeatherMixer.update(delta, actorNowPlaying, world) + } + measureDebugTime("BlockStats.update") { + BlockStats.update() + } + // fill up visibleActorsRenderFront for wires, if: + // 1. something is cued on the wire change queue + // 2. wire renderclass changed + if (newWorldLoadedLatch || wireChangeQueue.isNotEmpty() || selectedWireRenderClass != oldSelectedWireRenderClass) { + measureDebugTime("Ingame.FillUpWiresBuffer") { + fillUpWiresBuffer() + } + } } @@ -779,17 +767,6 @@ open class TerrarumIngame(batch: SpriteBatch) : IngameInstance(batch) { changePossession(getActorByID(refid) as ActorHumanoid) } - /** Send message to notifier UI and toggle the UI as opened. */ - override fun sendNotification(messages: Array) { - (notifier as Notification).sendNotification(messages.toList()) - } - - override fun sendNotification(messages: List) { - (notifier as Notification).sendNotification(messages) - } - - override fun sendNotification(singleMessage: String) = sendNotification(listOf(singleMessage)) - fun wakeDormantActors() { var actorContainerSize = actorContainerInactive.size var i = 0 @@ -1034,18 +1011,6 @@ open class TerrarumIngame(batch: SpriteBatch) : IngameInstance(batch) { } } - fun setTooltipMessage(message: String?) { - if (message == null) { - uiTooltip.setAsClose() - } - else { - if (uiTooltip.isClosed || uiTooltip.isClosing) { - uiTooltip.setAsOpen() - } - uiTooltip.message = message - } - } - override fun pause() { // TODO no pause when off-focus on desktop } @@ -1057,7 +1022,6 @@ open class TerrarumIngame(batch: SpriteBatch) : IngameInstance(batch) { uiContainer.forEach { it?.handler?.dispose() } } - /** * @param width same as AppLoader.terrarumAppConfig.screenW * @param height same as AppLoader.terrarumAppConfig.screenH diff --git a/src/net/torvald/terrarum/ui/ConsoleWindow.kt b/src/net/torvald/terrarum/ui/ConsoleWindow.kt index 8116479fc..0c6bb283e 100644 --- a/src/net/torvald/terrarum/ui/ConsoleWindow.kt +++ b/src/net/torvald/terrarum/ui/ConsoleWindow.kt @@ -8,7 +8,9 @@ import net.torvald.EMDASH import net.torvald.terrarum.* import net.torvald.terrarum.console.Authenticator import net.torvald.terrarum.console.CommandInterpreter +import net.torvald.terrarum.gameactors.AVKey import net.torvald.terrarum.langpack.Lang +import net.torvald.terrarum.modulebasegame.TerrarumIngame import net.torvald.terrarumsansbitmap.gdx.GameFontBase import net.torvald.util.CircularArray @@ -25,7 +27,7 @@ class ConsoleWindow : UICanvas() { private var inputCursorPos: Int = 0 private val MESSAGES_MAX = 5000 private val COMMAND_HISTORY_MAX = 100 - private var messages = Array(MESSAGES_MAX, {""}) + private var messages = Array(MESSAGES_MAX) { "" } private var messageDisplayPos: Int = 0 private var messagesCount: Int = 0 @@ -50,7 +52,19 @@ class ConsoleWindow : UICanvas() { reset() } + private val lb = ArrayList() + override fun updateUI(delta: Float) { + Terrarum.ingame?.let { + lb.clear() + + val actorsUnderCursor = it.getActorsAt(Terrarum.mouseX, Terrarum.mouseY) + actorsUnderCursor.forEach { + lb.add("${it.referenceID} (${it.actorValue[AVKey.NAME] ?: "\u03AF-${it.javaClass.simpleName}"})") + } + + it.setTooltipMessage(if (lb.size > 0) lb.joinToString("\n") else null) + } } override fun renderUI(batch: SpriteBatch, camera: Camera) { @@ -175,7 +189,7 @@ class ConsoleWindow : UICanvas() { } fun reset() { - messages = Array(MESSAGES_MAX, {""}) + messages = Array(MESSAGES_MAX) { "" } messageDisplayPos = 0 messagesCount = 0 inputCursorPos = 0 @@ -212,6 +226,7 @@ class ConsoleWindow : UICanvas() { } override fun endClosing(delta: Float) { + (Terrarum.ingame as? TerrarumIngame)?.setTooltipMessage(null) Terrarum.ingame?.paused = false drawOffY = -height.toFloat() openingTimeCounter = 0f