• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!

Various global tables are all the same table

Level 17
Joined
Apr 13, 2008
Messages
1,597
Hi,

I'm using Bribe's table.
Before I rewrite 2500 lines of code, I gotta ask. Is this expected behaviour?


JASS:
globals
        Table DInventoryDB
        Table DInventoryMetaData
        Table DInventoryBuffer
    endglobals


1 sec after init:
JASS:
    set DInventoryDB = DInventoryDB.create()
    set DInventoryMetaData = DInventoryMetaData.create()
    set DInventoryBuffer = DInventoryBuffer.create()


2 sec after init:
JASS:
local unit u = CreateUnit(Player(0), 'Nfir', -1064, 841, 0)
local item it = CreateItem('bgst', -1064, 841)

set DInventoryBuffer[GetHandleId(u)].item[GetHandleId(it)] = it

call BJDebugMsg("item name of table it = "+GetItemName(DInventoryBuffer[GetHandleId(u)].item[GetHandleId(it)]))
call BJDebugMsg("item name of table it = "+GetItemName(DInventoryDB[GetHandleId(u)].item[GetHandleId(it)]))

Both DInventoryDB and DInventoryBuffer give back the same item, even though only DInventoryBuffer was ever set.
Is there a way to create multiple separate tables?
 
From the looks of it, the Table objects are definitely distinct this time. However, you may be accidentally using a non-existent table, which I'll explain below:

Edit:
For clarification, the term "non-existent table" is somewhat misleading. You can still perform some operations with the "non-existent table", since the table object is essentially a parent key (in vJASS anyway) to the internal hashtable in Bribe's NewTable, but such usage of that specific table is HIGHLY discouraged because the table is reserved exclusively for Table object generation.

JASS:
DInventoryDB = Table object
DInventoryDB[integer index] -> Table object
// ...

DInventoryDB[GetHandleId(u)] -> Probably non-existent Table object -> Table(0)

DInventoryDB[GetHandleId(u)].item[GetHandleId(it)] = it ->
// The table instance mapped under DInventoryDB[GetHandleId(u)] likely does not exist, hence pointing to Table(0). ->
Table(0).item[GetHandleId(it)] = it
 
Last edited:
Level 17
Joined
Apr 13, 2008
Messages
1,597
I think I might have misunderstood the premise of Table altogether.
I thought that it is basically a multidimensional variable that can hold any type of data.

Here is an example data structure I wanted to create:


1696072817551.png



I want to create a complex inventory and equipment system with all the bells and whistles, and uhm, there are 10 different DBs, some of them more complex than this. However, seems like I completely misunderstood Bribe's Table.
 

Attachments

  • 1696072771706.png
    1696072771706.png
    24.6 KB · Views: 3
I think I might have misunderstood the premise of Table altogether.
I thought that it is basically a multidimensional variable that can hold any type of data.

Here is an example data structure I wanted to create:


View attachment 449373


I want to create a complex inventory and equipment system with all the bells and whistles, and uhm, there are 10 different DBs, some of them more complex than this. However, seems like I completely misunderstood Bribe's Table.
Please don't do janky stuff like putting multiple different types on one hashtable parent/key combo. Also don't mix 2d and 3d syntax on the same table. The HashTable type is the one you want here, as it automatically generates new tables for you as you move along. Just make sure to typecast so the API calls HashTable's key-creating methods and not Table's standard ones.
 
Level 17
Joined
Apr 13, 2008
Messages
1,597
Alright. I figured out what the issue is.

JASS:
globals
        HashTable DInventoryDB
        HashTable DInventoryMetaData
endglobals


JASS:
 set DInventoryDB = HashTable.create()
 set DInventoryMetaData = HashTable.create()

If I use HashTable as a 2D array, it works great (as far as my testing goes). The two variables are two different tables.

JASS:
set DInventoryBuffer[GetHandleId(u)].item[GetHandleId(it3)] = it3
call BJDebugMsg("item name of DInventoryBuffer table it3 = "+GetItemName(DInventoryBuffer[GetHandleId(u)].item[GetHandleId(it3)]))
call BJDebugMsg("item name of DInventoryDB table it3 = "+GetItemName(DInventoryDB[GetHandleId(u)].item[GetHandleId(it3)]))

But if I add another dimension, and make it a 3D or higher D array, it will always refer to the same Table.

JASS:
set DInventoryBuffer[GetHandleId(u)][0].item[GetHandleId(it3)] = it3
call BJDebugMsg("item name of DInventoryBuffer table it3 = "+GetItemName(DInventoryBuffer[GetHandleId(u)][0].item[GetHandleId(it3)]))
call BJDebugMsg("item name of DInventoryDB table it3 = "+GetItemName(DInventoryDB[GetHandleId(u)][0].item[GetHandleId(it3)]))

Am I stuck with a maximum of 2 Dimensions or can I somehow get more?
 
To save/load properly, you'd need to typecast.

ht[1][2][3] doesn't work because [2] is Table and not HashTable. You'd do:
HashTable(ht[1])[2][3]

To do a depth of 4, you'd do:
HashTable(HashTable(ht[1])[2])[3][4]

Of course, I could build wrapper API that would define Table2D/3D/4D, which handles the typecasting automatically at those depths. The name HashTable was just to mock the WarCraft 3 name.

Just be careful with the HashTable type in case you ever need to deallocate data from it. You have to track the indices manually as it doesn't offer a "flush" mechanism. Or you can use HashTableEx, which does track everything manually, but it is much slower when saving/loading into keys.

Table[1][2][3][4] works syntactically because Table casts its integer return values into Table rather than just a boring integer. Unless of course you load table.integer[1]. I did it like this to make life easier on people who might carefully build their own 2D tables one day, but it eventually got properly deprecated by HashTable.

There is also this:
[vJASS] - [Snippet] Multidimensional Array - but I have never worked with it. I am not sure why it needs so many lines of code to mimic that behavior.

I think you have inspired me to write some extra API that can be added onto the Table library. Table3D, Table4D, Table5D; each one just the same 22 (mostly-inlinable) lines of code as HashTable. I would not want to do garbage collection on that kind of thing myself, like I did with HashTableEx.
 
Last edited:
vJass Table version 5.1, just released, will solve this problem. It sounds like what you want is just a Table4D, though like I said, I recommend being explicit with your keys and not save integer/boolean into the same key set.

If you want to be able to automate cleanup, such as when a player leaves, you may want to consider using a Table4DT. Even if you don't want destruction, using a Table4DT - at least in TEST mode, will help you to ensure your keys are lined up. The limitation is that it doesn't register the keys inside of the vanilla tables (because I'd have to build out the tracking API onto all of the integer/boolean/string/handle/etc. syntaxes).

Lua doesn't suffer the limitations of needing its indices manually tracked, as it has automatic garbage collection to handle such scenarios. But I may end up building an API for it to handle unlimited depth, similar to what I just did with the vJass version.
 
Top