• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

MUI spells

Status
Not open for further replies.
Level 28
Joined
Jan 26, 2007
Messages
4,789
A quite simple method is by using hashtables.
(Really, it's simple. I just use a lot of words :D).

While regular arrayed variables can store 1 variable type in 8192 slots of a single array (from var[0] to var[8191]), a hashtable can store many variable types in a limitless amount of slots in 2 arrays.
If you look at them as a double arrayed variable that can exceed the 8191-limit and can contain different variable types, then you should be okay :).
For example, when doing this:
  • Hashtable - Save 100 as 0 of 0 in someHashtable
You can basically read it as:
  • Set someHashtable[0][0] = 100
The next thing you need to know is that each handle in the game has a unique ID that will be different from all other objects.
In your case, you will probably be using the ID of a unit (most of the time the caster or the projectile, but it can be a dummy as well).

Now before anything can be done, you must initialize the hashtable.
  • Actions
    • Hashtable - Create a hashtable
    • Set someHashtable = (Last created hashtable)
Add these actions to any trigger with the event "Map Initialization" and you're good to go.


Here is the basic idea of how to make things MUI:
  • Hashtable - Save 100 as 0 of 0 in someHashtable
Which, again, can be read as:
  • Actions
    • Set handleId = (Key (Triggering unit))
    • Hashtable - Save spellDamage as 0 of handleId in someHashtable
Here, "handleId" is just a regular integer variable. You set it to the handle ID of the unit (remember that this is a unique ID).
When you save anything for that ID, it cannot be overwritten and will therefore be MUI.
Again, this can just be read as "Set someHashtable[handleId][0] = spellDamage".
(Note that the "handleId" and "0" have seemingly switched places, this is because Blizzard just likes doing those kind of things).

Now you still need to read the information that was saved.
This can be done by adding the unit whose handle ID was used to a unit group.
  • Actions
    • Set handleId = (Key (Triggering unit))
    • Hashtable - Save 0.00 as handleId of 0 in (Last created hashtable)
    • Unit Group - Add (Triggering unit) to spellGroup
And in another trigger, you can do this:
  • Actions
    • Unit Group - Pick every unit in (Units in (Playable map area)) and do (Actions)
      • Loop - Actions
        • Set handleId = (Key (Picked unit))
        • Set spellDamage = (Load handleId of 0 from someHashtable)
This will receive the data you have stored and it is now free to use at any point in time.

But it doesn't end here, as all data needs to be cleaned when the spell is over.
So when you're sure you do not need to retrieve that data anymore (spell is over, clear all data), then you use this action:
  • Hashtable - Clear all child hashtables of child handleId in someHashtable
Remove the key unit from the unit group and done!

  • Init
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Hashtable - Create a hashtable
      • Set spellHashtable = (Last created hashtable)
  • Init Spell
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
    • Actions
      • -------- === Setup Spell Data === --------
      • Set tempUnitType = Footman
      • Set tempReal = 10.00
      • -------- === End Setup === --------
      • Set tempLoc = (Position of (Triggering unit))
      • -------- Create the summoned unit --------
      • Unit - Create 1 tempUnitType for Player 1 (Red) at tempLoc facing Default building facing degrees
      • -------- Save data --------
      • Set handleId = (Key (Last created unit))
      • Hashtable - Save tempReal as 0 of handleId in spellHashtable
      • -------- Add unit to group --------
      • Unit Group - Add (Last created unit) to spellSummonGroup
      • -------- This is an integer I use to track the amount of instances running --------
      • -------- Because the loop-trigger does not need to be running when there is no instance --------
      • Set spellSummonCount = (spellSummonCount + 1)
      • -------- Start Loop --------
      • Trigger - Turn on Loop Spell <gen>
  • Loop Spell
    • Events
      • Time - Every 0.10 seconds of game time
    • Conditions
    • Actions
      • -------- === Trigger initially off === --------
      • Unit Group - Pick every unit in spellSummonGroup and do (Actions)
        • Loop - Actions
          • -------- Retrieve data --------
          • Set handleId = (Key (Picked unit))
          • Set tempReal = ((Load 0 of handleId from spellHashtable) - 0.10)
          • -------- Check if time is over --------
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • tempReal Less than or equal to 0.00
            • Then - Actions
              • -------- Time is over, clear everything --------
              • Hashtable - Clear all child hashtables of child handleId in (Last created hashtable)
              • Unit Group - Remove (Picked unit) from spellSummonGroup
              • Unit - Remove (Picked unit) from the game
              • Set spellSummonCount = (spellSummonCount - 1)
            • Else - Actions
              • -------- There is still some time left, save the new time --------
              • Hashtable - Save tempReal as 0 of handleId in spellHashtable
      • -------- Check if there are any instances left --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • spellSummonCount Equal to 0
        • Then - Actions
          • -------- No instances left, turn off this trigger --------
          • Trigger - Turn off (This trigger)
        • Else - Actions

Notes:
There's a disadvantage to using the handle ID of the triggering unit: the saved data can still be overwritten if the exact same unit casts the same spell before the next one is done.
To avoid this, you can save all data in the projectile that is created, or, if none is created, you can create a dummy whose ID you use to store all data in and you remove the dummy after the spell is done.

You only need 1 hashtable for all systems!
It's easy to get lost when you're just using "handleId" and an integer, but there's something else you can use: StringHash. In GUI, this is "Hashtable - Get String ID".
It will look something like this:
  • Actions
    • Hashtable - Save realDamage as (Key FireballDmg) of handleId in spellHashtable
    • Hashtable - Save realDistance as (Key FireballDistance) of handleId in spellHashtable
And it's awesome.
You can easily keep track of all your data and you're only using 1 hashtable for all your spells. There's a maximum of 255 hashtables in a game by the way.



Edit: uploaded the simple hashtable spell you can mess around with it.
Save some more things (like do X damage over time to the summoned unit), or... you know, just mess around. Do some crazy things and see if it works.
Once you grasp the essence of hashtables, they're easy to use and can come in handy in various situations (like when you need double arrays).
 

Attachments

  • Simple Hashtable Spell.w3x
    18.1 KB · Views: 105
Level 26
Joined
Aug 18, 2009
Messages
4,097
Huh? MUI stands for multi unit instanceability, so every unit needs to carry its own data in order to not affect the other ones, so reserve memory space for each unit and assign it to it.

MUIness is no topic if you store the data sencefully where it belongs to from the beginning.
 
Level 33
Joined
Mar 27, 2008
Messages
8,035
You should worry about MUI when that trigger is not instant and that spell can exist in more than 1 unit at a time in that game.

So;
If your spell has instant effect - Don't care about MUI
If your spell only exist in 1 (ONE) unit at a time in that game - Don't care about MUI

Take the first condition as priority, if your spell is instant, you can give that spell to multiple of units at a time in that game.
 
Level 3
Joined
Apr 21, 2012
Messages
33
I think not if you don't have some events that can cause more than one unit to have the same spell, such as ability to stole other's spell like that.
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
Huh? MUI stands for multi unit instanceability, so every unit needs to carry its own data in order to not affect the other ones, so reserve memory space for each unit and assign it to it.

MUIness is no topic if you store the data sencefully where it belongs to from the beginning.

you are becoming DSG slowly ... your defining of this is very cryptic
Do you think new people will understand that? I certainly dont
 
Level 28
Joined
Jan 26, 2007
Messages
4,789
dont use hashtables they cause fatal errors one some computers instead use jnpg and make your own globals to store everytihng
Ohh, this again? Really?

Post.
Thread.

You've got to come with pretty hard evidence to make me believe what you claim, as I (as said the thread above) have never encountered anything wrong with hashtables.
Besides, every time you talk bad about hashtables, it's very vague. What do you have against hashtables that you try your best to convince people who aren't familiar with them to not use those?
 
Level 33
Joined
Mar 27, 2008
Messages
8,035
Ohh, this again? Really?

Post.
Thread.

You've got to come with pretty hard evidence to make me believe what you claim, as I (as said the thread above) have never encountered anything wrong with hashtables.
Besides, every time you talk bad about hashtables, it's very vague. What do you have against hashtables that you try your best to convince people who aren't familiar with them to not use those?
Face it, they forced me to use a system called "Unit Indexer" to make my systems approvable, if I use Hashtable, it is "bad approach" because apparently Indexing > Hashtable in terms of speed.

I just said, Well, it is fast to my eyes, does it do the same to you ? every time.
 
Level 17
Joined
Jul 17, 2011
Messages
1,863
no no it has nothing to do with speed my current theory is that a hashtable sometimes tries to overwrite memory addresses used by the game which contain leaked handles thus you get the notorious "memory could not be read/written" fatal error that is just a theory of course but one thing is certain for me: i have had many maps crash because of hashtable systems, right after i delete the system triggers the crash stops occurring
 
no no it has nothing to do with speed my current theory is that a hashtable sometimes tries to overwrite memory addresses used by the game which contain leaked handles thus you get the notorious "memory could not be read/written" fatal error that is just a theory of course but one thing is certain for me: i have had many maps crash because of hashtable systems, right after i delete the system triggers the crash stops occurring

not sometimes but it will always overwrite if you use the same handleID again but not destroying the old pointer (like locations)...

if you have more than 255 HT, it will not work, in vJass, Tables are there for us to use nearly unlimited # of instances, I call it virtual hashtable, wihout any conflict...

Depends on how you use it, a spell without saving should use UnitIndexer or DynamicIndexing, but I recommend UnitIndexer, else use Hashtables...
 
Level 28
Joined
Jan 26, 2007
Messages
4,789
Face it, they forced me to use a system called "Unit Indexer" to make my systems approvable, if I use Hashtable, it is "bad approach" because apparently Indexing > Hashtable in terms of speed.

I just said, Well, it is fast to my eyes, does it do the same to you ? every time.
Really? That sucks.
In general, a hashtable isn't noticeably slower than indexing + indexing look really ugly.
And if you do it right, hashtables can make any system or spell SUMI, so that shouldn't be a problem either.

no no it has nothing to do with speed my current theory is that a hashtable sometimes tries to overwrite memory addresses used by the game which contain leaked handles thus you get the notorious "memory could not be read/written" fatal error that is just a theory of course but one thing is certain for me: i have had many maps crash because of hashtable systems, right after i delete the system triggers the crash stops occurring
Defskull already gave a proper answer to this.
Many people use hashtables, including me, and you never hear those people complain.
If I've been able to store quite a few systems and spells into 1 hashtables without ever getting an error, then everyone can do that.

Imagine if everyone who started with JASS would stop using that language because it would make their map stop working (which, if you just started using JASS, is quite common).
That's not the way to go.

not sometimes but it will always overwrite if you use the same handleID again but not destroying the old pointer (like locations)...

if you have more than 255 HT, it will not work, in vJass, Tables are there for us to use nearly unlimited # of instances, I call it virtual hashtable, wihout any conflict...

Depends on how you use it, a spell without saving should use UnitIndexer or DynamicIndexing, but I recommend UnitIndexer, else use Hashtables...
We're talking GUI here.
Besides, I always encourage people to use only 1 hashtable for all systems.
And yes, it overwrites if you use the same handleId again, the simple solution is to not use that handleId anymore. There are plenty of them you can use.



Now we could make another thread about this where we could discuss this in great detail, or agree to disagree and move on.
Whatever the case, this thread has been solved (he PM'd be, the spell he wanted to fix was an instant-spell so it was already MUI).

And gorillabull, I just don't want you to talk nonsense to people who don't quite understand how things work.
If you hate hashtables, don't use them. Don't force your hatred on other people.
 
Level 33
Joined
Mar 27, 2008
Messages
8,035
And if you do it right, hashtables can make any system or spell SUMI, so that shouldn't be a problem either.
I made a trigger to support SUMI by making each dummy unit to hold data ;p
But compared to Indexing (not Unit Indexer - but classic indexing), it does not require any additional handle (in this case - Unit) to hold data to support stacking effect.

Which in this case (SUMI), I have to agree Indexing > Hashtable

But in the matter of "Unit Indexer > Hashtable", ugh... no...
 
Besides, I always encourage people to use only 1 hashtable for all systems.
possible to 1 user, not possible if he's importing spells or systems with hashtable usage from different users coz for sure they will initialize HT on their own...

idk, but maybe there's a way of creating a Table in GUI format, I'll look into that...
 
Level 17
Joined
Jul 17, 2011
Messages
1,863
ok ok ill stop talking about hashtables maybe i need to reinstall wc3 to fix the crash problem or something
^ that is a good reason not to use them tho what if you copy 256 hashtable spells... use them but dont make spells or systems with them otherwise its fine to have 1 or 2 in your map
 
Level 28
Joined
Jan 26, 2007
Messages
4,789
possible to 1 user, not possible if he's importing spells or systems with hashtable usage from different users coz for sure they will initialize HT on their own...
That is true.

However, it may be possible to require a 'global hashtable' for every spell/system uploaded on the hive (each with a unique StringHash, of course).
This will just require a globals block with, for example, "hashtable systemHashtable = InitHashtable()" and all systems and spells could run on that.
That way only 1 hashtable will be used, even when importing tons and tons of spells (as long as they're from the hive :p).

It's really easy to change the hashtable required for any JASS/vJass-script, so the main problem would be the GUI-spells. I do admit that the amount of time needed to change those is quite significant.

Besides, you need like 51 heroes with 5 spells each which all require a hashtable before you encounter the limit.
Which sane person would import that many spells? :)
 
Yeah, hive should add rules of having one global hashtable variable so that when we download a spell, the name is uniform,
although it's slow, Stringhash is the best option for this, but then again, I made something like this before, it's called
http://www.hiveworkshop.com/forums/triggers-scripts-269/one-hash-212277/ and I believe it was you who told me when I was still learning on lastcreated unit's unique ID...
 
Status
Not open for further replies.
Top