• 🏆 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!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[Hashtable] Handle - Using for (...) - Possible ?

Status
Not open for further replies.

Ardenian

A

Ardenian

Hello,

I am facing a problem with my system I re-work using hashtable.

I have one unit which will be linked to another ( theoretically and practically, with a lightning). My problem is, how do I save the relation, so I can load it if needed, considering one unit can be linked to multiple at once ?
Without the hashtable I would have to use dynamic indexing.

My approach was:
  • Unit - Add TempUnit to UnitGroup[Key(CastingUnit)]
But it seemed not to work.

So, my next idea, in theory, would be the following:

  • Hashtable - Save Handle of TempUnit as Key(CastingUnit) of Key(CastingUnit) in Hashtable
Does this work ? It would solve the problem I have with linking two units.

Another question, off-topic, but related:
I thought handles of the same type overwrite themselves ?
I use
  • Hashtable - Save Handle Of TempLightning as 2 of (Key (Target unit of ability being cast)) in Hashtable
and judging from the in-game behaviour it seems as if it does not overwrite itself, instead, allowing multiple instances of lightning.

It should not work, after all I know, and it makes me mad why it does work.
Does anyone can help me with this ? My triggers aren't necessary, the action above is the only one to save multiple lightning and they seem not to overwrite themselves.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,467
So you are doing a unit-> unit lightning attachment, correct? The best way to do it is with dynamic indexing (link in my sig). Every 0.03 seconds (or whatever you choose), iterate over the list of indices. Each index contains a lightning and both units the lightning is to follow. Hashtables are for attaching data to units, but what you need is to work with that abstract dynamic list.
 

Ardenian

A

Ardenian

So I would Index + 1 or every new relation ? I hoped to avoid this and only using hashtable, since units are dynamic, can die and so on.
 

Ardenian

A

Ardenian

Thanks, I see that I somehow have to link and differ between the different groups of linked units ( one group = two different units and one lightning), but it feels odd to create indexing.

I think I will add an index like:

  • Hashtable - Save Handle of TempUnit as 0 of GroupIndex
  • Hashtable - Load 0 of LoopInteger
Something like this.

About leaks, I heard one has to nullify removed entries, does clearing the child tables do this ?
 
You basicly have to apply logic here:

A hashtable has a parent and a childkey, basicly working like a 2-dimensional array.

You store your relations under GetHandleId(unit) as parentkey. This will make sure that the system is MUI.

Your childkey can be constructed in two different ways:

Version 1: Unordered Stack

0 --> Integer: counts the number of units currently linked
1 --> unit: holds the first linked unit
2 --> lightning: holds the first lightning
3 --> unit: holds the second linked unit
4 --> lightning: holds the second lightning
... etc.

So if you want to add a new link to a unit, you increase the counter (childkey 0) by 1, then add the unit to counter*2-1 and the lightning to counter*2.
This will always make sure you never overwrite a previously stored link.

If you want to remove a link again, things get a bit more complicated:
You can basicly loop through all stored links in the table (integer A from 1 to counter) and get the units as Integer A*2-1 and the lightnings as Integer A*2 until you find the "right" unit and remove it.
In this case you have to swap the position of the unit that is to be removed with the last unit in the list (set the unit at A*2-1 = the unit at counter*2-1 and set the lightning at A*2 = lightning at counter*2), to make sure the list does not have a "hole" in it after you remove this unit and lightning.


Version 2: Binary Map

This one is extremely clever and makes use of the fact that you only have two sets of data per unit: a unit reference and a lightning.

Basicly, your childkeys will look like this:
0 --> Group: Holds all units hooked up with the parent unit.
GetHandleId(hooked unit) --> Lightning: holds the Lightning.

So, to add a linked unit, all you have to do is add it into the group stored at childkey 0, then create the lightning under the childkey "GetHandleId()" of the unit you just added.
To remove this linked unit again, all you have to do is check if the unit is in the group and remove it, then remove the lightning stored under this unit's handle id.

This approach also allows storing a second variable under GetHandleId(hooked unit)*(-1), which is useful if you want to add a countdown timer or a damage variable aswell. However, with this approach you can't save more than 2 variables per hooked unit.
 

Ardenian

A

Ardenian

Thanks Bribe, yes, I am learning to use them in an efficient way, up to now the hashtable indexing was fine, but now I need Handle Id for efficiency.

Wow, thanks Zwiebelchen!
1. is the method I would NOT like to use, it feels odd to. Then I feel as if I could use array variables instead.

About 2., I think that is what I am searching for, but I am not sure whether it does what I would like to achieve, let me visualize, please:

So we have one group with all targets B for example and every Handle Id of units A is saved in the hashtable as:
  • hashtable - Save Handle of UnitA as 0 of Key(TriggeringUnitA) in Hashtable
The group is saved as
  • Hashtable - Save Handle of Group as 0 of Key(TriggeringUnitA) in Hashtable
Then a unit B with Lightning C is saved as:
  • Hashtable - Save Handle of Lightning as Key(TriggeringUnitB) of Key(TriggeringUnitA) in Hashtable
Okay okay, so basically, a unit is saved with a lightning.

Hm, to be honest, I am not sure whether it fulfils everything I need, I will have to think about it, thank you!
 

Ardenian

A

Ardenian

Oh, I recall now what is troublesome.

Each link, relation is, should be unique, but as every Unit of type A and every Unit of type B can be used in multiple relations, its unique status is lost.

Example:

Unit A can be linked to multiple Units B
All these Units B can be linked to other Units A

Do you know a way to add an unique relation ?


The only one that comes to my mind is having a dummy unit for each relation to have its unique HandleId, but I guess it is wasted object data.

Hm, it seems Dynamic Indexing is indeed the most favourable option here..
 
Oh, I recall now what is troublesome.

Each link, relation is, should be unique, but as every Unit of type A and every Unit of type B can be used in multiple relations, its unique status is lost.

Example:

Unit A can be linked to multiple Units B
All these Units B can be linked to other Units A

Do you know a way to add an unique relation ?


The only one that comes to my mind is having a dummy unit for each relation to have its unique HandleId, but I guess it is wasted object data.

Hm, it seems Dynamic Indexing is indeed the most favourable option here..
This approach:
--> Save Group as 0 of Key(UnitA) in Hashtable.
--> Save Lightning as Key(UnitB) of Key(UnitA) in Hashtable.
already works bi-directional, as each UnitB can also be a UnitA at the same time.

Just to go sure; here is how to link UnitA (source) to UnitB (target):
- Load Group as 0 of Key(UnitA) in Hashtable
- Add UnitB to Group
- Create Lightning and store it as Key(UnitB) of Key(UnitA)

This is how to unlink UnitA (source) from UnitB (target):
- Load Group as 0 of Key(UnitA) in Hashtable
- Remove UnitB from Group
- Destroy Lightning at Key(UnitB) of Key(UnitA)
- Remove Handle at Key(UnitB) of Key(UnitA) --> this is important to clean the reference leak in the hashtable!

Remember that in this implementation the direction (from caster to target) matters!
So only caster knows target, but target does not know caster by default.
If you want bi-directional links (so the caster knows the target and the target also knows the caster; so any of the two sides can "break" the connection at will), you must run the add and remove processes twice with swapped UnitA and UnitB:


Add a Link:
Connect A to B
Connect B to A

Remove a Link:
Remove A from B
Remove B from A
 

Ardenian

A

Ardenian

Alright, I think now I got it. Thanks a bunch for the detailed explanation!
 
Status
Not open for further replies.
Top