mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-07 20:31:51 +09:00
fixed a bug where a dynamic item would not get saved/loaded at all
This commit is contained in:
@@ -28,4 +28,5 @@ SpawnPhysTestBall
|
||||
StreamerMode
|
||||
Teleport
|
||||
ToggleNoClip
|
||||
Zoom
|
||||
Zoom
|
||||
DynToStatic
|
||||
|
@@ -66,6 +66,7 @@ object Terrarum : Disposable {
|
||||
|
||||
|
||||
var blockCodex = BlockCodex(); internal set
|
||||
/** The actual contents of the ItemCodex is sum of Player's Codex and the World's Codex */
|
||||
var itemCodex = ItemCodex(); internal set
|
||||
var wireCodex = WireCodex(); internal set
|
||||
var materialCodex = MaterialCodex(); internal set
|
||||
|
||||
@@ -5,7 +5,6 @@ import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||
import net.torvald.terrarum.gameitems.GameItem
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.INVEN_DEBUG_MODE
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIItemInventoryCellBase
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIItemInventoryCellCommonRes
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIItemInventoryCellCommonRes.toItemCountText
|
||||
@@ -97,23 +96,13 @@ class UIItemInventoryElemWide(
|
||||
)
|
||||
|
||||
// draw name of the item
|
||||
if (INVEN_DEBUG_MODE) {
|
||||
App.fontGame.draw(batch,
|
||||
// print static id, dynamic id, and count
|
||||
"${item!!.originalID}/${item!!.dynamicID}" + (if (amount > 0 && item!!.stackable) "$fwsp($amountString)" else if (amount != 1L) "$fwsp!!$amountString!!" else ""),
|
||||
posX + textOffsetX,
|
||||
posY + textOffsetY
|
||||
)
|
||||
}
|
||||
else {
|
||||
App.fontGame.draw(batch,
|
||||
// print name and amount in parens
|
||||
item!!.name + (if (amount > 0 && item!!.stackable) "$fwsp($amountString)" else if (amount != 1L) "$fwsp!!$amountString!!" else ""),
|
||||
App.fontGame.draw(batch,
|
||||
// print name and amount in parens
|
||||
item!!.name + (if (amount > 0 && item!!.stackable) "$fwsp($amountString)" else if (amount != 1L) "$fwsp!!$amountString!!" else ""),
|
||||
|
||||
posX + textOffsetX,
|
||||
posY + textOffsetY
|
||||
)
|
||||
}
|
||||
posX + textOffsetX,
|
||||
posY + textOffsetY
|
||||
)
|
||||
|
||||
|
||||
// durability metre
|
||||
|
||||
@@ -24,6 +24,8 @@ typealias ItemID = String
|
||||
*/
|
||||
abstract class GameItem(val originalID: ItemID) : Comparable<GameItem>, Cloneable {
|
||||
|
||||
constructor() : this("-uninitialised-")
|
||||
|
||||
open var dynamicID: ItemID = originalID
|
||||
/**
|
||||
* if the ID is a Actor range, it's an actor contained in a pocket.
|
||||
|
||||
@@ -10,6 +10,8 @@ import net.torvald.terrarum.blockproperties.Fluid
|
||||
import net.torvald.terrarum.gameactors.ActorID
|
||||
import net.torvald.terrarum.gameactors.WireActor
|
||||
import net.torvald.terrarum.gameitems.ItemID
|
||||
import net.torvald.terrarum.itemproperties.ItemRemapTable
|
||||
import net.torvald.terrarum.itemproperties.ItemTable
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
|
||||
import net.torvald.terrarum.realestate.LandUtil
|
||||
import net.torvald.terrarum.utils.*
|
||||
@@ -128,6 +130,9 @@ open class GameWorld() : Disposable {
|
||||
internal var genver = -1 // only gets used when the game saves and loads
|
||||
internal var comp = -1 // only gets used when the game saves and loads
|
||||
|
||||
internal val dynamicItemInventory = ItemTable()
|
||||
internal val dynamicToStaticTable = ItemRemapTable()
|
||||
|
||||
@Deprecated("This value is only used for savegames; DO NOT USE THIS", ReplaceWith("INGAME.actorContainerActive", "net.torvald.terrarum.INGAME"))
|
||||
internal val actors = ArrayList<ActorID>() // only filled up on save and load; DO NOT USE THIS
|
||||
|
||||
|
||||
@@ -13,7 +13,13 @@ import net.torvald.terrarum.gameitems.ItemID
|
||||
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.CanBeAnItem
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.FixtureBase
|
||||
import net.torvald.terrarum.serialise.SaveLoadError
|
||||
import net.torvald.terrarum.worlddrawer.BlocksDrawer
|
||||
import java.io.File
|
||||
import java.io.InvalidObjectException
|
||||
|
||||
typealias ItemRemapTable = java.util.HashMap<ItemID, ItemID>
|
||||
typealias ItemTable = java.util.HashMap<ItemID, GameItem>
|
||||
|
||||
/**
|
||||
* ItemCodex holds information of every item in the game, including blocks despite the 'item' naming
|
||||
@@ -26,9 +32,9 @@ class ItemCodex {
|
||||
* <ItemID or RefID for Actor, TheItem>
|
||||
* Will return corresponding Actor if ID >= ACTORID_MIN
|
||||
*/
|
||||
@Transient val itemCodex = HashMap<ItemID, GameItem>()
|
||||
@Transient var dynamicItemDescription = HashMap<ItemID, GameItem>(); private set
|
||||
var dynamicToStaticTable = HashMap<ItemID, ItemID>(); private set
|
||||
@Transient val itemCodex = ItemTable()
|
||||
val dynamicItemInventory = ItemTable()
|
||||
val dynamicToStaticTable = ItemRemapTable()
|
||||
|
||||
@Transient val ACTORID_MIN = ReferencingRanges.ACTORS.first
|
||||
|
||||
@@ -41,18 +47,33 @@ class ItemCodex {
|
||||
|
||||
fun clear() {
|
||||
itemCodex.clear()
|
||||
dynamicItemDescription.clear()
|
||||
dynamicItemInventory.clear()
|
||||
dynamicToStaticTable.clear()
|
||||
}
|
||||
|
||||
/**
|
||||
* This method does not alter already-been-loaded itemCodex; only filles up dynamicitem-related fields
|
||||
*
|
||||
* Normally, the player's dynamicToStaticTable is what gets loaded first.
|
||||
*/
|
||||
fun loadFromSave(other: ItemCodex) {
|
||||
this.dynamicToStaticTable = other.dynamicToStaticTable
|
||||
dynamicToStaticTable.forEach { dynid, itemid ->
|
||||
fun loadFromSave(savefile: File?, otherDynamicToStaticTable: ItemRemapTable, otherDynamicItemInventory: ItemTable) {
|
||||
otherDynamicToStaticTable.forEach { dynid, itemid ->
|
||||
printdbg(this, "Loadfromsave dynid $dynid ->> $itemid")
|
||||
dynamicItemDescription[dynid] = itemCodex[itemid]!!
|
||||
dynamicToStaticTable[dynid]?.let {
|
||||
if (it != itemid) {
|
||||
throw SaveLoadError(savefile, InvalidObjectException("Discrepancy detected -- currently loaded $dynid is mapped to $it, but ${savefile?.name} indicates it should map to $itemid"))
|
||||
}
|
||||
}
|
||||
dynamicToStaticTable[dynid] = itemid
|
||||
}
|
||||
otherDynamicItemInventory.forEach { dynid, item ->
|
||||
printdbg(this, "Loadfromsave dynitem $dynid ->> $item")
|
||||
dynamicItemInventory[dynid]?.let {
|
||||
if (it != item) {
|
||||
throw SaveLoadError(savefile, InvalidObjectException("Discrepancy detected -- currently loaded $dynid is mapped to $it, but ${savefile?.name} indicates it should map to $item"))
|
||||
}
|
||||
}
|
||||
dynamicItemInventory[dynid] = item
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +85,7 @@ class ItemCodex {
|
||||
*/
|
||||
fun registerNewDynamicItem(dynamicID: ItemID, item: GameItem) {
|
||||
printdbg(this, "Registering new dynamic item $dynamicID (from ${item.originalID})")
|
||||
dynamicItemDescription[dynamicID] = item
|
||||
dynamicItemInventory[dynamicID] = item
|
||||
dynamicToStaticTable[dynamicID] = item.originalID
|
||||
}
|
||||
|
||||
@@ -76,7 +97,7 @@ class ItemCodex {
|
||||
if (code == null) return null
|
||||
|
||||
if (code.startsWith("$PREFIX_DYNAMICITEM:"))
|
||||
return dynamicItemDescription[code] ?: throw NullPointerException("No ItemProp with id $code")
|
||||
return dynamicItemInventory[code] ?: throw NullPointerException("No ItemProp with id $code")
|
||||
else if (code.startsWith("$PREFIX_ACTORITEM:")) {
|
||||
val a = (Terrarum.ingame!! as TerrarumIngame).getActorByID(code.substring(6).toInt()) // actor item
|
||||
if (a is CanBeAnItem) return a.itemData
|
||||
@@ -142,5 +163,5 @@ class ItemCodex {
|
||||
|
||||
}
|
||||
|
||||
fun hasItem(itemID: ItemID): Boolean = dynamicItemDescription.containsKey(itemID)
|
||||
fun hasItem(itemID: ItemID): Boolean = dynamicItemInventory.containsKey(itemID)
|
||||
}
|
||||
@@ -133,9 +133,10 @@ class TitleScreen(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
|
||||
|
||||
try {
|
||||
val reader = java.io.FileReader(ModMgr.getFile("basegame", "demoworld"))
|
||||
val file = ModMgr.getFile("basegame", "demoworld")
|
||||
val reader = java.io.FileReader(file)
|
||||
//ReadWorld.readWorldAndSetNewWorld(Terrarum.ingame!! as TerrarumIngame, reader)
|
||||
val world = ReadWorld.readLayerFormat(reader)
|
||||
val world = ReadWorld.readLayerFormat(reader, file)
|
||||
demoWorld = world
|
||||
printdbg(this, "Demo world loaded")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
import net.torvald.terrarum.serialise.Common
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2022-02-22.
|
||||
*/
|
||||
object DynToStatic : ConsoleCommand {
|
||||
override fun execute(args: Array<String>) {
|
||||
ItemCodex.dynamicToStaticTable.forEach { (d,s) ->
|
||||
Echo("$ccG$d$ccW → $ccY$s")
|
||||
}
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import net.torvald.terrarum.console.Echo
|
||||
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||
import net.torvald.terrarum.serialise.ReadActor
|
||||
import net.torvald.terrarum.serialise.ReadWorld
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
|
||||
/**
|
||||
@@ -16,8 +17,9 @@ object ImportWorld : ConsoleCommand {
|
||||
override fun execute(args: Array<String>) {
|
||||
if (args.size == 2) {
|
||||
try {
|
||||
val reader = java.io.FileReader(App.defaultDir + "/Exports/${args[1]}.json")
|
||||
ReadWorld.readWorldAndSetNewWorld(Terrarum.ingame!! as TerrarumIngame, reader)
|
||||
val file = File(App.defaultDir + "/Exports/${args[1]}.json")
|
||||
val reader = java.io.FileReader(file)
|
||||
ReadWorld.readWorldAndSetNewWorld(Terrarum.ingame!! as TerrarumIngame, reader, file)
|
||||
Echo("Importworld: imported a world from ${args[1]}.json")
|
||||
}
|
||||
catch (e: IOException) {
|
||||
|
||||
@@ -28,6 +28,8 @@ class ActorInventory() : FixtureInventory() {
|
||||
/**
|
||||
* List of all equipped items (tools, armours, rings, necklaces, etc.)
|
||||
*
|
||||
* It's your responsibility to make sure currently equipped item also exists in the `super.itemList`
|
||||
*
|
||||
* The ItemID must be `dynamicID`
|
||||
*/
|
||||
val itemEquipped = Array<ItemID?>(GameItem.EquipPosition.INDEX_MAX) { null }
|
||||
@@ -62,7 +64,7 @@ class ActorInventory() : FixtureInventory() {
|
||||
}
|
||||
}
|
||||
|
||||
fun getQuickslotItem(slot: Int): InventoryPair? = invSearchByDynamicID(quickSlot[slot])
|
||||
fun getQuickslotItem(slot: Int): InventoryPair? = searchByID(quickSlot[slot])
|
||||
|
||||
fun consumeItem(item: GameItem) {
|
||||
val actor = this.actor as Actor
|
||||
|
||||
@@ -4,10 +4,9 @@ import net.torvald.terrarum.ItemCodex
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.gameitems.GameItem
|
||||
import net.torvald.terrarum.gameitems.ItemID
|
||||
import net.torvald.terrarum.lock
|
||||
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||
import net.torvald.util.SortedArrayList
|
||||
import java.math.BigInteger
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2021-03-16.
|
||||
@@ -32,7 +31,7 @@ open class FixtureInventory() {
|
||||
/**
|
||||
* Sorted by referenceID.
|
||||
*/
|
||||
val itemList = ArrayList<InventoryPair>()
|
||||
val itemList = SortedArrayList<InventoryPair>()
|
||||
var wallet = BigInteger("0") // unified currency for whole civs; Dwarf Fortress approach seems too complicated
|
||||
|
||||
fun isEmpty() = getTotalCount() == 0L
|
||||
@@ -66,7 +65,7 @@ open class FixtureInventory() {
|
||||
|
||||
// If we already have the item, increment the amount
|
||||
// If not, add item with specified amount
|
||||
val existingItem = invSearchByDynamicID(item.dynamicID)
|
||||
val existingItem = searchByID(item.dynamicID)
|
||||
|
||||
// if the item already exists
|
||||
if (existingItem != null) {
|
||||
@@ -80,7 +79,7 @@ open class FixtureInventory() {
|
||||
else {
|
||||
itemList.add(InventoryPair(item.dynamicID, count))
|
||||
}
|
||||
insertionSortLastElem(itemList)
|
||||
// insertionSortLastElem(itemList)
|
||||
}
|
||||
|
||||
open fun remove(itemID: ItemID, count: Long) = remove(ItemCodex[itemID]!!, count) {}
|
||||
@@ -102,7 +101,7 @@ open class FixtureInventory() {
|
||||
|
||||
|
||||
|
||||
val existingItem = invSearchByDynamicID(item.dynamicID)
|
||||
val existingItem = searchByID(item.dynamicID)
|
||||
if (existingItem != null) { // if the item already exists
|
||||
val newCount = existingItem.qty - count
|
||||
|
||||
@@ -171,28 +170,14 @@ open class FixtureInventory() {
|
||||
if (itemList.size == 0)
|
||||
false
|
||||
else
|
||||
itemList.binarySearch(id, DYNAMIC_ID) >= 0
|
||||
fun invSearchByDynamicID(id: ItemID?): InventoryPair? {
|
||||
itemList.contains(InventoryPair(id, 1))
|
||||
fun searchByID(id: ItemID?): InventoryPair? {
|
||||
if (itemList.size == 0 || id == null)
|
||||
return null
|
||||
|
||||
val index = itemList.binarySearch(id, DYNAMIC_ID)
|
||||
if (index < 0)
|
||||
return null
|
||||
else
|
||||
return itemList[index]
|
||||
return itemList.searchFor(id) { it.itm }
|
||||
}
|
||||
protected fun invSearchByStaticID(id: ItemID?): InventoryPair? {
|
||||
if (itemList.size == 0 || id == null)
|
||||
return null
|
||||
|
||||
val index = itemList.binarySearch(id, STATIC_ID)
|
||||
if (index < 0)
|
||||
return null
|
||||
else
|
||||
return itemList[index]
|
||||
}
|
||||
protected fun insertionSortLastElem(arr: ArrayList<InventoryPair>) {
|
||||
/*protected fun insertionSortLastElem(arr: ArrayList<InventoryPair>) {
|
||||
ReentrantLock().lock {
|
||||
var j = arr.lastIndex - 1
|
||||
val x = arr.last()
|
||||
@@ -202,7 +187,7 @@ open class FixtureInventory() {
|
||||
}
|
||||
arr[j + 1] = x
|
||||
}
|
||||
}
|
||||
}*/
|
||||
@Transient private val STATIC_ID = 41324534
|
||||
@Transient private val DYNAMIC_ID = 181643953
|
||||
protected fun ArrayList<InventoryPair>.binarySearch(ID: ItemID, searchMode: Int): Int {
|
||||
@@ -229,7 +214,7 @@ open class FixtureInventory() {
|
||||
}
|
||||
}
|
||||
|
||||
class InventoryPair {
|
||||
class InventoryPair : Comparable<InventoryPair> {
|
||||
|
||||
var itm: ItemID = ""; private set
|
||||
var qty: Long = 0
|
||||
@@ -244,4 +229,5 @@ class InventoryPair {
|
||||
operator fun component1() = itm
|
||||
operator fun component2() = qty
|
||||
|
||||
override fun compareTo(other: InventoryPair) = this.itm.compareTo(other.itm)
|
||||
}
|
||||
@@ -11,6 +11,9 @@ import net.torvald.terrarum.App
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.gameactors.AVKey
|
||||
import net.torvald.terrarum.gameitems.GameItem
|
||||
import net.torvald.terrarum.gameitems.ItemID
|
||||
import net.torvald.terrarum.itemproperties.ItemRemapTable
|
||||
import net.torvald.terrarum.itemproperties.ItemTable
|
||||
import net.torvald.terrarum.savegame.DiskSkimmer
|
||||
import net.torvald.terrarum.savegame.SimpleFileSystem
|
||||
import net.torvald.terrarum.utils.PlayerLastStatus
|
||||
@@ -33,6 +36,9 @@ class IngamePlayer : ActorHumanoid, HasAssembledSprite {
|
||||
val uuid = UUID.randomUUID()
|
||||
var worldCurrentlyPlaying: UUID = UUID(0L,0L) // only filled up on save and load; DO NOT USE THIS
|
||||
|
||||
internal val dynamicItemInventory = ItemTable()
|
||||
internal val dynamicToStaticTable = ItemRemapTable()
|
||||
|
||||
@Transient override var spriteHeadTexture: TextureRegion? = null
|
||||
|
||||
|
||||
|
||||
@@ -111,6 +111,7 @@ object PickaxeCore {
|
||||
* Created by minjaesong on 2017-07-17.
|
||||
*/
|
||||
class PickaxeCopper(originalID: ItemID) : GameItem(originalID) {
|
||||
internal constructor() : this("-uninitialised-")
|
||||
|
||||
override val originalName = "PACKAGED_PICK"
|
||||
override var baseToolSize: Double? = BASE_MASS_AND_SIZE
|
||||
@@ -138,6 +139,7 @@ class PickaxeCopper(originalID: ItemID) : GameItem(originalID) {
|
||||
* Created by minjaesong on 2019-03-10.
|
||||
*/
|
||||
class PickaxeIron(originalID: ItemID) : GameItem(originalID) {
|
||||
internal constructor() : this("-uninitialised-")
|
||||
|
||||
override val originalName = "PACKAGED_PICK"
|
||||
override var baseToolSize: Double? = BASE_MASS_AND_SIZE
|
||||
@@ -165,6 +167,7 @@ class PickaxeIron(originalID: ItemID) : GameItem(originalID) {
|
||||
* Created by minjaesong on 2019-03-10.
|
||||
*/
|
||||
class PickaxeSteel(originalID: ItemID) : GameItem(originalID) {
|
||||
internal constructor() : this("-uninitialised-")
|
||||
|
||||
override val originalName = "PACKAGED_PICK"
|
||||
override var baseToolSize: Double? = BASE_MASS_AND_SIZE
|
||||
|
||||
@@ -26,5 +26,8 @@ object WeaponMeleeCore {
|
||||
}
|
||||
|
||||
abstract class WeaponMeleeBase(originalID: ItemID) : GameItem(originalID) {
|
||||
|
||||
internal constructor() : this("-uninitialised-")
|
||||
|
||||
abstract val velocityMod: Double
|
||||
}
|
||||
@@ -19,7 +19,7 @@ object AmmoMeterProxy {
|
||||
else {
|
||||
meter.vitalGetterVal = {
|
||||
if (currentItem.stackable && currentItem.maxDurability == GameItem.DURABILITY_NA) {
|
||||
actor.inventory.invSearchByDynamicID(currentItem.dynamicID)!!.qty.toFloat()
|
||||
actor.inventory.searchByID(currentItem.dynamicID)!!.qty.toFloat()
|
||||
}
|
||||
else
|
||||
currentItem.durability
|
||||
|
||||
@@ -10,9 +10,7 @@ import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.CELLS_HO
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.CELLS_VRT
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.INVENTORY_CELLS_OFFSET_X
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.INVENTORY_CELLS_OFFSET_Y
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.INVEN_DEBUG_MODE
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.controlHelpHeight
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.internalHeight
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.internalWidth
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIItemInventoryItemGrid.Companion.createInvCellGenericKeyDownFun
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIItemInventoryItemGrid.Companion.createInvCellGenericTouchDownFun
|
||||
@@ -136,7 +134,7 @@ internal class UIInventoryCells(
|
||||
)
|
||||
// debug text
|
||||
batch.color = Color.LIGHT_GRAY
|
||||
if (INVEN_DEBUG_MODE) {
|
||||
if (App.IS_DEVELOPMENT_BUILD) {
|
||||
App.fontSmallNumbers.draw(batch,
|
||||
"${full.actor.inventory.capacity}/${full.actor.inventory.maxCapacity}",
|
||||
encumbBarTextXPos,
|
||||
|
||||
@@ -38,8 +38,6 @@ class UIInventoryFull(
|
||||
|
||||
val CELL_COL = Toolkit.Theme.COL_CELL_FILL
|
||||
|
||||
const val INVEN_DEBUG_MODE = false
|
||||
|
||||
const val REQUIRED_MARGIN: Int = 138 // hard-coded value. Don't know the details. Range: [91-146]. I chose MAX-8 because cell gap is 8
|
||||
const val CELLS_HOR = 10
|
||||
val CELLS_VRT: Int; get() = (App.scr.height - REQUIRED_MARGIN - 134 + UIItemInventoryItemGrid.listGap) / // 134 is another magic number
|
||||
|
||||
@@ -125,7 +125,7 @@ class UIItemInventoryEquippedView(
|
||||
itemGrid[k].equippedSlot = null
|
||||
}
|
||||
else {
|
||||
val itemRecord = it.invSearchByDynamicID(item)!!
|
||||
val itemRecord = it.searchByID(item)!!
|
||||
|
||||
itemGrid[k].item = ItemCodex[item]
|
||||
itemGrid[k].amount = itemRecord.qty
|
||||
|
||||
@@ -13,7 +13,6 @@ import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.ActorInventory
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.FixtureInventory
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.InventoryPair
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.INVEN_DEBUG_MODE
|
||||
import net.torvald.terrarum.ui.Toolkit
|
||||
import net.torvald.terrarum.ui.UICanvas
|
||||
import net.torvald.terrarum.ui.UIItem
|
||||
@@ -162,6 +161,9 @@ class UIItemInventoryItemGrid(
|
||||
listRebuildFun()
|
||||
}
|
||||
}
|
||||
|
||||
// COMMON variables because more than one instance of this can be up on the screen
|
||||
private val tooltipShowing = HashMap<UIItemInventoryItemGrid, Boolean>()
|
||||
}
|
||||
|
||||
private val itemGrid = Array<UIItemInventoryCellBase>(horizontalCells * verticalCells) {
|
||||
@@ -347,8 +349,8 @@ class UIItemInventoryItemGrid(
|
||||
override fun update(delta: Float) {
|
||||
super.update(delta)
|
||||
|
||||
var tooltipSet = false
|
||||
|
||||
tooltipShowing[this] = false
|
||||
|
||||
|
||||
items.forEach {
|
||||
@@ -356,20 +358,21 @@ class UIItemInventoryItemGrid(
|
||||
|
||||
|
||||
// set tooltip accordingly
|
||||
if (isCompactMode && it.item != null && it.mouseUp && !tooltipSet) {
|
||||
if ((App.IS_DEVELOPMENT_BUILD || isCompactMode) && it.item != null && it.mouseUp && tooltipShowing[this] != true) {
|
||||
INGAME.setTooltipMessage(
|
||||
if (INVEN_DEBUG_MODE) {
|
||||
it.item?.name + " (${it.item?.originalID}${if (it.item?.originalID == it.item?.dynamicID) "" else "/${it.item?.dynamicID}"})"
|
||||
if (App.IS_DEVELOPMENT_BUILD) {
|
||||
it.item?.name + "\n(${it.item?.originalID}${if (it.item?.originalID == it.item?.dynamicID) "" else "/${it.item?.dynamicID}"})"
|
||||
}
|
||||
else {
|
||||
it.item?.name
|
||||
}
|
||||
)
|
||||
tooltipSet = true
|
||||
|
||||
tooltipShowing[this] = true
|
||||
}
|
||||
}
|
||||
|
||||
if (!tooltipSet) {
|
||||
if (tooltipShowing.values.all { !it }) {
|
||||
INGAME.setTooltipMessage(null)
|
||||
}
|
||||
|
||||
@@ -461,7 +464,11 @@ class UIItemInventoryItemGrid(
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
tooltipShowing.remove(this)
|
||||
}
|
||||
|
||||
override fun hide() {
|
||||
tooltipShowing.remove(this)
|
||||
}
|
||||
|
||||
override fun touchDown(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
||||
|
||||
@@ -23,6 +23,8 @@ class DiskSkimmer(
|
||||
noInit: Boolean = false
|
||||
): SimpleFileSystem {
|
||||
|
||||
override fun getBackingFile() = diskFile
|
||||
|
||||
/*
|
||||
|
||||
init:
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.torvald.terrarum.savegame
|
||||
|
||||
import java.io.File
|
||||
import java.nio.charset.Charset
|
||||
|
||||
/**
|
||||
@@ -9,4 +10,5 @@ interface SimpleFileSystem {
|
||||
fun getEntry(id: EntryID): DiskEntry?
|
||||
fun getFile(id: EntryID): EntryFile?
|
||||
fun getDiskName(charset: Charset): String
|
||||
fun getBackingFile(): File?
|
||||
}
|
||||
@@ -63,7 +63,7 @@ object VDUtil {
|
||||
if (diskSpecVersion != specversion)
|
||||
throw RuntimeException("Unsupported disk format version: current internal version is $specversion; the file's version is $diskSpecVersion")
|
||||
|
||||
val vdisk = VirtualDisk(diskSize, diskName)
|
||||
val vdisk = VirtualDisk(diskSize, diskName, infile)
|
||||
|
||||
vdisk.__internalSetFooter__(footers)
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package net.torvald.terrarum.savegame
|
||||
|
||||
import net.torvald.terrarum.App.printdbg
|
||||
import net.torvald.terrarum.serialise.Common
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.nio.charset.Charset
|
||||
import java.util.*
|
||||
@@ -125,8 +126,12 @@ val specversion = 254.toByte()
|
||||
class VirtualDisk(
|
||||
/** capacity of 0 makes the disk read-only */
|
||||
var capacity: Long,
|
||||
var diskName: ByteArray = ByteArray(NAME_LENGTH)
|
||||
var diskName: ByteArray = ByteArray(NAME_LENGTH),
|
||||
var origin: File? = null
|
||||
): SimpleFileSystem {
|
||||
|
||||
override fun getBackingFile() = origin
|
||||
|
||||
var extraInfoBytes = ByteArray(16)
|
||||
val entries = HashMap<EntryID, DiskEntry>()
|
||||
var isReadOnly: Boolean
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.torvald.terrarum.savegame.finder
|
||||
|
||||
import net.torvald.terrarum.savegame.*
|
||||
import net.torvald.terrarum.serialise.Common
|
||||
import java.awt.BorderLayout
|
||||
import java.awt.Dimension
|
||||
import java.awt.event.KeyEvent
|
||||
@@ -676,5 +677,5 @@ ${String(file.contents.bytes.sliceArray64(0L..minOf(PREVIEW_MAX_BYTES, file.cont
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
VirtualDiskCracker(Charset.forName("CP437"))
|
||||
VirtualDiskCracker(Common.CHARSET)
|
||||
}
|
||||
@@ -329,4 +329,4 @@ object Common {
|
||||
|
||||
}
|
||||
|
||||
class SaveLoadError(file: File, cause: Throwable) : RuntimeException("An error occured while loading save file '${file.absolutePath}'", cause)
|
||||
class SaveLoadError(file: File?, cause: Throwable) : RuntimeException("An error occured while loading save file '${file?.absolutePath}'", cause)
|
||||
@@ -2,13 +2,20 @@ package net.torvald.terrarum.serialise
|
||||
|
||||
import net.torvald.gdx.graphics.PixmapIO2
|
||||
import net.torvald.terrarum.App.printdbg
|
||||
import net.torvald.terrarum.ItemCodex
|
||||
import net.torvald.terrarum.ReferencingRanges.PREFIX_DYNAMICITEM
|
||||
import net.torvald.terrarum.gameitems.ItemID
|
||||
import net.torvald.terrarum.itemproperties.ItemRemapTable
|
||||
import net.torvald.terrarum.modulebasegame.IngameRenderer
|
||||
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.FixtureBase
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.Pocketed
|
||||
import net.torvald.terrarum.realestate.LandUtil
|
||||
import net.torvald.terrarum.toInt
|
||||
import net.torvald.terrarum.savegame.*
|
||||
import java.io.File
|
||||
import java.util.HashMap
|
||||
import java.util.zip.GZIPOutputStream
|
||||
|
||||
/**
|
||||
@@ -61,14 +68,14 @@ class WorldSavingThread(
|
||||
|
||||
val allTheActors = ingame.actorContainerActive.cloneToList() + ingame.actorContainerInactive.cloneToList()
|
||||
|
||||
val playersList: List<IngamePlayer> = allTheActors.filter{ it is IngamePlayer } as List<IngamePlayer>
|
||||
val playersList: List<IngamePlayer> = allTheActors.filterIsInstance<IngamePlayer>()
|
||||
val actorsList = allTheActors.filter { WriteWorld.actorAcceptable(it) }
|
||||
val layers = intArrayOf(0,1).map { ingame.world.getLayer(it) }
|
||||
val cw = ingame.world.width / LandUtil.CHUNK_W
|
||||
val ch = ingame.world.height / LandUtil.CHUNK_H
|
||||
|
||||
WriteSavegame.saveProgress = 0f
|
||||
WriteSavegame.saveProgressMax = 2f + (cw * ch * layers.size) + actorsList.size
|
||||
WriteSavegame.saveProgressMax = 3f + (cw * ch * layers.size) + actorsList.size
|
||||
|
||||
|
||||
val tgaout = ByteArray64GrowableOutputStream()
|
||||
@@ -79,6 +86,39 @@ class WorldSavingThread(
|
||||
val creation_t = ingame.world.creationTime
|
||||
|
||||
|
||||
// Write subset of Ingame.ItemCodex
|
||||
// The existing ItemCodex must be rewritten to clear out obsolete records
|
||||
|
||||
// We're assuming the dynamic item generated by players does exist in the world, and it's recorded
|
||||
// into the world's dynamicToStaticTable, therefore every item recorded into the world's dynamicToStaticTable
|
||||
// can be found in this world without need to look up the players
|
||||
ingame.world.dynamicToStaticTable.clear()
|
||||
ingame.world.dynamicItemInventory.clear()
|
||||
actorsList.filterIsInstance<Pocketed>().forEach { actor ->
|
||||
actor.inventory.forEach { (itemid, _) ->
|
||||
|
||||
printdbg(this, "World side dynamicitem: $itemid contained in $actor")
|
||||
|
||||
if (itemid.startsWith("$PREFIX_DYNAMICITEM:")) {
|
||||
ingame.world.dynamicToStaticTable[itemid] = ItemCodex.dynamicToStaticID(itemid)
|
||||
ingame.world.dynamicItemInventory[itemid] = ItemCodex[itemid]!!
|
||||
}
|
||||
}
|
||||
}
|
||||
actorsList.filterIsInstance<FixtureBase>().forEach { fixture ->
|
||||
fixture.inventory?.forEach { (itemid, _) ->
|
||||
|
||||
printdbg(this, "World side dynamicitem: $itemid contained in $fixture")
|
||||
|
||||
if (itemid.startsWith("$PREFIX_DYNAMICITEM:")) {
|
||||
ingame.world.dynamicToStaticTable[itemid] = ItemCodex.dynamicToStaticID(itemid)
|
||||
ingame.world.dynamicItemInventory[itemid] = ItemCodex[itemid]!!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (hasThumbnail) {
|
||||
PixmapIO2._writeTGA(gzout, IngameRenderer.fboRGBexport, true, true)
|
||||
IngameRenderer.fboRGBexport.dispose()
|
||||
|
||||
@@ -4,9 +4,12 @@ import net.torvald.spriteanimation.HasAssembledSprite
|
||||
import net.torvald.spriteanimation.SpriteAnimation
|
||||
import net.torvald.terrarum.spriteassembler.ADProperties
|
||||
import net.torvald.terrarum.ItemCodex
|
||||
import net.torvald.terrarum.ReferencingRanges.PREFIX_DYNAMICITEM
|
||||
import net.torvald.terrarum.gameactors.Actor
|
||||
import net.torvald.terrarum.gameactors.ActorWithBody
|
||||
import net.torvald.terrarum.gameitems.GameItem
|
||||
import net.torvald.terrarum.gameitems.ItemID
|
||||
import net.torvald.terrarum.itemproperties.ItemRemapTable
|
||||
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
|
||||
import net.torvald.terrarum.savegame.*
|
||||
@@ -74,6 +77,17 @@ object WritePlayer {
|
||||
|
||||
player.worldCurrentlyPlaying = ingame?.world?.worldIndex ?: UUID(0L,0L)
|
||||
|
||||
// Write subset of Ingame.ItemCodex
|
||||
// The existing ItemCodex must be rewritten to clear out obsolete records
|
||||
player.dynamicToStaticTable.clear()
|
||||
player.dynamicItemInventory.clear()
|
||||
player.inventory.forEach { (itemid, _) ->
|
||||
if (itemid.startsWith("$PREFIX_DYNAMICITEM:")) {
|
||||
player.dynamicToStaticTable[itemid] = ItemCodex.dynamicToStaticID(itemid)
|
||||
player.dynamicItemInventory[itemid] = ItemCodex[itemid]!!
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val actorJson = WriteActor.encodeToByteArray64(player)
|
||||
val adl = player.animDesc!!.getRawADL()
|
||||
@@ -142,6 +156,8 @@ object ReadActor {
|
||||
actor.animDescGlow = ADProperties(ByteArray64Reader(animFileGlow.bytes, Common.CHARSET))
|
||||
}
|
||||
|
||||
ItemCodex.loadFromSave(disk.getBackingFile(), actor.dynamicToStaticTable, actor.dynamicItemInventory)
|
||||
|
||||
val heldItem = ItemCodex[actor.inventory.itemEquipped[GameItem.EquipPosition.HAND_GRIP]]
|
||||
|
||||
if (bodypartsFile != null)
|
||||
|
||||
@@ -125,7 +125,7 @@ object LoadSavegame {
|
||||
|
||||
val currentWorldId = player.worldCurrentlyPlaying
|
||||
val worldDisk = worldDisk0 ?: App.savegameWorlds[currentWorldId]!!
|
||||
val world = ReadWorld(ByteArray64Reader(worldDisk.getFile(-1L)!!.bytes, Common.CHARSET))
|
||||
val world = ReadWorld(ByteArray64Reader(worldDisk.getFile(-1L)!!.bytes, Common.CHARSET), worldDisk.diskFile)
|
||||
|
||||
world.layerTerrain = BlockLayer(world.width, world.height)
|
||||
world.layerWall = BlockLayer(world.width, world.height)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.torvald.terrarum.serialise
|
||||
|
||||
import net.torvald.terrarum.CommonResourcePool
|
||||
import net.torvald.terrarum.ItemCodex
|
||||
import net.torvald.terrarum.ReferencingRanges
|
||||
import net.torvald.terrarum.gameactors.Actor
|
||||
import net.torvald.terrarum.gameactors.BlockMarkerActor
|
||||
@@ -15,6 +16,7 @@ import net.torvald.terrarum.savegame.ByteArray64
|
||||
import net.torvald.terrarum.savegame.ByteArray64Writer
|
||||
import net.torvald.terrarum.utils.PlayerLastStatus
|
||||
import net.torvald.terrarum.weather.WeatherMixer
|
||||
import java.io.File
|
||||
import java.io.Reader
|
||||
|
||||
/**
|
||||
@@ -90,22 +92,24 @@ object WriteWorld {
|
||||
*/
|
||||
object ReadWorld {
|
||||
|
||||
fun readLayerFormat(worldDataStream: Reader): GameWorld =
|
||||
fillInDetails(Common.jsoner.fromJson(GameWorldTitleScreen::class.java, worldDataStream))
|
||||
fun readLayerFormat(worldDataStream: Reader, origin: File?): GameWorld =
|
||||
fillInDetails(Common.jsoner.fromJson(GameWorldTitleScreen::class.java, worldDataStream), origin)
|
||||
|
||||
operator fun invoke(worldDataStream: Reader): GameWorld =
|
||||
fillInDetails(Common.jsoner.fromJson(GameWorld::class.java, worldDataStream))
|
||||
operator fun invoke(worldDataStream: Reader, origin: File?): GameWorld =
|
||||
fillInDetails(Common.jsoner.fromJson(GameWorld::class.java, worldDataStream), origin)
|
||||
|
||||
private fun fillInDetails(world: GameWorld): GameWorld {
|
||||
private fun fillInDetails(world: GameWorld, origin: File?): GameWorld {
|
||||
world.tileNumberToNameMap.forEach { l, s ->
|
||||
world.tileNameToNumberMap[s] = l.toInt()
|
||||
}
|
||||
|
||||
ItemCodex.loadFromSave(origin, world.dynamicToStaticTable, world.dynamicItemInventory)
|
||||
|
||||
return world
|
||||
}
|
||||
|
||||
fun readWorldAndSetNewWorld(ingame: TerrarumIngame, worldDataStream: Reader): GameWorld {
|
||||
val world = readLayerFormat(worldDataStream)
|
||||
fun readWorldAndSetNewWorld(ingame: TerrarumIngame, worldDataStream: Reader, origin: File?): GameWorld {
|
||||
val world = readLayerFormat(worldDataStream, origin)
|
||||
ingame.world = world
|
||||
return world
|
||||
}
|
||||
|
||||
@@ -142,11 +142,13 @@ class SortedArrayList<T: Comparable<T>>(initialSize: Int = 10) : MutableCollecti
|
||||
val second = Math.min(low, this.size - 1)
|
||||
return Pair(first, second)
|
||||
}
|
||||
/** Searches the element using given predicate instead of the element itself. Returns the element desired, null when there is no such element.
|
||||
/** Searches the element using given predicate instead of the element itself
|
||||
* (e.g. search the Actor by its ID rather than the actor instance)
|
||||
*
|
||||
* @param searchQuery what exactly are we looking for?
|
||||
* @param searchHow and where or how can it be found?
|
||||
*
|
||||
* @return The element you're searching; null when there is no such element.
|
||||
*/
|
||||
fun <R: Comparable<R>> searchFor(searchQuery: R, searchHow: (T) -> R = { it as R }): T? = getOrNull(searchForIndex(searchQuery, searchHow))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user