• 🏆 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!

Unit Group Saving to Hashtable not working

Status
Not open for further replies.
Level 4
Joined
Jan 27, 2016
Messages
89
I have 2 spells here, one summons a ward unit which summons skeletons, the other orders all skeletons summoned by the summoner of the ward and caster of the spell to attack-move to a certain point, it seems to properly convert unit Ids but for some reason it doesn't save the unit groups properly, they're always empty, anyone know what might be causing this?
 
Level 12
Joined
Jan 2, 2016
Messages
973
I got a bit confused while looking at these triggers. From what I saw, I can tell that you aren't doing things right in more than 1 way(s). So I guess I'll just tell you how your triggers should look like:
Event: a unit spawns a summoned unit:
set temp_int = (load integer 0 of summoning unit from the table) + 1
save unit (summoned unit as temp_int of summoning unit into the table)
save integer (temp_int as 0 of summoning unit into the table)
......................
Event: a unit begins channeling an ability
...
Actions:
set temp_int = LoadInteger( 0 of triggering unit from the table)
loop ~int~ from 1 to temp_int
Order Load Unit ( ~int~ of triggering unit form the table) to attack-move to ....

This way you basically keep the '0' of the table to count how many skeletons has this unit summoned. the '1' field contains the 1-st skeleton, '2' contains the 2-nd, and so on..
The loop is from 1 to 'the amount of skeletons' - it picks each skeleton and orders it to attack-move.

Ofc you will also need to save the summoner into the skeleton's table too, and when a skeleton dies - you run a loop to reduce and re-set the skeletons in the caster's table, but I think you should be able to manage that :p

ALTERNATIVELY (this may be kind a easier)
you can save a unit GROUP handle into the caster's table, and when it summons a skeleton:
load the unit group, and add the skeleton to it.
when you start casting the spell - load the group again, and use it as a normal unit group.
you also need to save the unit group handle into the skeletons' tables as well, and when they die - load the unit group, remove the skeleton from it, and clear the skeleton's child hashtable.
 
Level 12
Joined
May 22, 2015
Messages
1,051
You shouldn't destroy the groups.

Here's what's happening, basically:
Since groups are not a normal type of data, you store a "handle" to them.
The group is actually stored somewhere else, and the handle just points to them.
If you use the handle for other things, the group, which is stored somewhere else, is lost forever (memory leak).
If you call the custom script to DestroyGroup(yourGroup), you are telling the code to delete the actual group, which is stored somewhere else. You just give it the handle.

In your case, you are storing the handle of the group inside the hashtable (you can't store the actual group). Then you are destroying the group. This means that the handle inside the hashtable is pointing at nothing. When you go to use it for something else, it doesn't do anything.

EDIT:
Further problem - you are not actually even creating a group (unless I missed it). Instead of storing the unit handle. It looks like you are doing a lot more than you need to to keep track of data. You don't need to store any units in the hashtable - only the group.
WereElf basically already described this.

You should create a new, empty group in Skeletos Spawn. Save it under key 0 of Temp_Integer like you have already done.
In Skeletos Spawn2, you should only load the group and add the unit to it. You don't need to clear the table and store the group again. You don't even need to save the group again (because of what I described above).
You destroy the group in Skeletos dies. You also clear the hashtable at this point.

I feel like the final trigger doesn't quite make sense. Maybe it is supposed to be a separate spell by the main caster? As in, not from the dummy unit. I think the problem is you need to store the "summoning unit" in the first trigger and use it in this trigger. That would actually explain a lot lol.

Can you describe more what your spells are doing?
 
Level 12
Joined
May 22, 2015
Messages
1,051
Okay cool. I think I get it now.

Anyway, you need to not destroy the groups where you are destroying them. Only destroy them when the necromancer dies. Create them when the necromancer is created. Then I think it will work. Try that and let me know how it goes.

As noted, you don't need to ever clear the table or save the group back in. You should only clear the table when you destroy the group - which all should only happen when the necromancer dies.
 
Level 4
Joined
Jan 27, 2016
Messages
89
Thing is, Temp_Group is a group I reuse a lot, and a lot of Necromancers will be using this ability, so how do I use the group? It's a unit spell, and there will be a lot of said units. So if I destroy the group, won't it screw up everything for all Necromancers?
 
Level 12
Joined
May 22, 2015
Messages
1,051
Thing is, Temp_Group is a group I reuse a lot, and a lot of Necromancers will be using this ability, so how do I use the group? It's a unit spell, and there will be a lot of said units.

Use it how you are now. You don't need to worry about what Temp_Group is because you will assign it to a new value each time. You load the handle in Skeletos Spawn2 and use that for Temp_Group. When you go to use Temp_Group elsewhere, you assign it before using it to something else. It doesn't leak because you are not passing groups around or creating new ones. You are just swapping the handles it is using each time.

EDIT:
http://www.hiveworkshop.com/forums/miscellaneous-tutorials-456/how-easily-post-triggers-163285/
^ This link will help you post your triggers. They will be text, so others can edit them manually to show you what to change. It's just way easier for everyone :D
 
Level 12
Joined
Jan 2, 2016
Messages
973
try using more custom scripts:
  • Custom script: local group g = LoadGroupHandle(udg_RaiseDead, GetHandleId(GetSummoningUnit()),0)
  • Custom script: if g == null then
  • Custom script: set g = CreateGroup()
  • Custom script: endif
  • Custom script: call GroupAddUnit(g, GetSummonedUnit())
  • Custom script: call SaveGroupHandle(udg_RaiseDead, GetHandleId(GetSummoningUnit()), 0, g)
  • Custom script: set g = null
You can't really create groups in GUI, so you need to use custom scripts xP
 
Level 12
Joined
Jan 2, 2016
Messages
973
Okay, I kind a noticed something disturbing:
Hashtable - Save Handle Of(Summoning unit) as 0 of Temp_Integer in RaiseDead
(so 0 of the 1-st summoned unit is taken by a UNIT)
Set Temp_Unit = (Load 0 of Temp_Integer in RaiseDead)
(you take the value of that unit, still good)
Set Temp_Group = (Load 0 of Temp_Integer in RaiseDead)
(This is where you lose me.... You have a UNIT saved in the 0, but you are trying to load a group :vw_wtf:)
 
Level 12
Joined
Jan 2, 2016
Messages
973
Ah, right, didn't notice you switch the value of Temp_Integer.
Anyways, as SAUS said, you should stop Destroying Temp_Group. That's what's causing problems (or at least it's 1 of the problems).
You are saving a REFERENCE to the unit group in the hashtable, so when you save the unit group there, and then you destroy it, when you try to load it - it will be a destroyed group.
I also don't see where you Create the group...
 
Level 12
Joined
May 22, 2015
Messages
1,051
It looks good. It is just confusing to read because "Summoning unit" doesn't look much different from "Summoned unit", and those are what you are using.

Have you tried just commenting out / deleting the lines where you delete the groups? Also, do you have somewhere where you create them? You should create them when you create one of the Skeletos Serveants.

EDIT:
It doesn't matter if other triggers destroy Temp_Group - they should be working with a different group by that time.

When do you create the groups that get stored in the hashtable? There needs to be a 5th trigger for when you create a Skeletos Serveant that creates an empty group for them and saves it in the hashtable.
 
Level 12
Joined
May 22, 2015
Messages
1,051
Close! I made a few modifications:
  • Skeletos Spawn2
    • Events
      • Unit - A unit Spawns a summoned unit
    • Conditions
      • (Unit-type of (Summoning unit)) Equal to RaiseDead Dummy
    • Actions
      • Custom script: local group g
      • Set Temp_Unit = (Summoning unit)
      • Custom script: set udg_Temp_Integer = GetHandleId(udg_Temp_Unit)
      • Game - Display to (All players) for 30.00 seconds the text: (String(Temp_Integer))
      • Set Temp_Unit = (Load 0 of Temp_Integer in RaiseDead)
      • Custom script: set udg_Temp_Integer = GetHandleId(udg_Temp_Unit)
      • Game - Display to (All players) for 30.00 seconds the text: (String(Temp_Integer))
      • Custom script: set g = LoadGroupHandle(udg_RaiseDead, udg_Temp_Integer,0)
      • Custom script: if g == null then
      • Custom script: set g = CreateGroup()
      • Custom script: call SaveGroupHandle(udg_RaiseDead, GetHandleId(GetSummoningUnit()), 0, g)
      • Custom script: endif
      • Custom script: call GroupAddUnit(g, GetSummonedUnit())
      • Custom script: set g = null
      • Custom script: call UnitAddAbilityBJ( 'Aloc', GetSummonedUnit() )
      • Custom script: call UnitRemoveAbilityBJ( 'Aloc', GetSummonedUnit() )
      • Unit - Add CUpgradeRaisdeDead (Grom) to (Summoned unit)
What does adding locust ('Aloc') and removing it do?
 
Level 12
Joined
Jan 2, 2016
Messages
973
Well, I can see why it's working only once. You are destroying the unit group in the trigger at the top, so the 2-nd time you try to cast the ability - there isn't a unit group for it to pick.
I didn't check the rest of the triggers. Fix that and tell me if it starts to work normally.
 
Level 12
Joined
Jan 2, 2016
Messages
973
Meh, I'll tomorrow I'll try to make the triggers for you. I'm kind a too tired now.
Can you post me a comeplete describtion of everything that happens/should happen?
I see that RaiseDead are summoned units, that summon other units.
In the end, who should be controlling who?
If the necromancer is "1", RaiseDead are "2" and the units, summoned by "2" are "3", then who controls who?
 
Level 12
Joined
Jan 2, 2016
Messages
973
Okay, I made you triggers that work:
  • Summon Primal
    • Events
      • Unit - A unit Spawns a summoned unit
    • Conditions
      • (Unit-type of (Summoned unit)) Equal to Necromancer Lesser
    • Actions
      • Hashtable - Save Handle Of(Summoning unit) as 0 of (Key (Summoned unit)) in RaiseDead
  • Summon Secondary
    • Events
      • Unit - A unit Spawns a summoned unit
    • Conditions
      • (Unit-type of (Summoning unit)) Equal to Necromancer Lesser
    • Actions
      • Set Temp_Unit = (Load 0 of (Key (Summoning unit)) in RaiseDead)
      • Custom script: set udg_Temp_Group = LoadGroupHandle(udg_RaiseDead, GetHandleId(udg_Temp_Unit), 0)
      • Custom script: if udg_Temp_Group == null then
      • Custom script: set udg_Temp_Group = CreateGroup()
      • Custom script: endif
      • Unit Group - Add (Summoned unit) to Temp_Group
      • Hashtable - Save Handle OfTemp_Group as 0 of (Key (Summoned unit)) in RaiseDead
      • Custom script: call SaveGroupHandle(udg_RaiseDead, GetHandleId(udg_Temp_Unit), 0, udg_Temp_Group)
      • Custom script: set udg_Temp_Group = null
      • Custom script: call UnitAddAbility(GetSummonedUnit(), 'Aloc')
      • Custom script: call UnitRemoveAbility(GetSummonedUnit(), 'Aloc')
  • Order Units
    • Events
      • Unit - A unit Begins channeling an ability
    • Conditions
      • (Ability being cast) Equal to Channel Modified
    • Actions
      • Custom script: set udg_X = GetSpellTargetX()
      • Custom script: set udg_Y = GetSpellTargetY()
      • Set Temp_Group = (Load 0 of (Key (Triggering unit)) in RaiseDead)
      • Unit Group - Pick every unit in Temp_Group and do (Actions)
        • Loop - Actions
          • Custom script: call IssuePointOrder( GetEnumUnit(), "attack", udg_X, udg_Y )
      • Custom script: set udg_Temp_Group = null
  • UnitDeath
    • Events
      • Unit - A unit Dies
    • Conditions
      • ((Unit-type of (Triggering unit)) Equal to Necromancer Greater) or ((Unit-type of (Triggering unit)) Equal to Skeleton Warrior)
    • Actions
      • Set Temp_Group = (Load 0 of (Key (Triggering unit)) in RaiseDead)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Unit-type of (Triggering unit)) Equal to Necromancer Greater
        • Then - Actions
          • Unit Group - Pick every unit in Temp_Group and do (Actions)
            • Loop - Actions
              • Unit - Add a 0.01 second Generic expiration timer to (Picked unit)
          • Unit Group - Remove all units from Temp_Group
          • Custom script: call DestroyGroup(udg_Temp_Group)
        • Else - Actions
          • Unit Group - Remove (Triggering unit) from Temp_Group
      • Hashtable - Clear all child hashtables of child (Key (Triggering unit)) in RaiseDead
      • Custom script: set udg_Temp_Group = null
Uploaded a sample map too.
 

Attachments

  • Necromancers.w3x
    19.2 KB · Views: 59
Level 4
Joined
Jan 27, 2016
Messages
89
Thanks, works perfectly with pretty much any potential issue I could see arise from it, plus its so much smoother without having to set Temp_Integers all the time.
 
Level 12
Joined
Jan 2, 2016
Messages
973
Why even use GUI when you are using so much custom script already...


You never set Temp_Unit, I am guessing that line should not be there?

I did it in GUI for him, idk if Somefaggot knows JASS.
However, check the 1-st line of the trigger, and say again "You never set Temp_Unit".

The only thing that I could improve in the 2-nd trigger tho is instead of
  • Actions
  • Set Temp_Unit = (Load 0 of (Key (Summoning unit)) in RaiseDead)
  • Custom script: set udg_Temp_Group = LoadGroupHandle(udg_RaiseDead, GetHandleId(udg_Temp_Unit), 0)
  • Custom script: if udg_Temp_Group == null then
  • Custom script: set udg_Temp_Group = CreateGroup()
  • Custom script: endif
  • Unit Group - Add (Summoned unit) to Temp_Group
  • Hashtable - Save Handle OfTemp_Group as 0 of (Key (Summoned unit)) in RaiseDead
  • Custom script: call SaveGroupHandle(udg_RaiseDead, GetHandleId(udg_Temp_Unit), 0, udg_Temp_Group)
  • Custom script: set udg_Temp_Group = null
  • Custom script: call UnitAddAbility(GetSummonedUnit(), 'Aloc')
  • Custom script: call UnitRemoveAbility(GetSummonedUnit(), 'Aloc')
I could do:
  • Actions
  • Set Temp_Unit = (Load 0 of (Key (Summoning unit)) in RaiseDead)
  • Custom script: set udg_Temp_Group = LoadGroupHandle(udg_RaiseDead, GetHandleId(udg_Temp_Unit), 0)
  • Custom script: if udg_Temp_Group == null then
  • Custom script: set udg_Temp_Group = CreateGroup()
  • Custom script: call SaveGroupHandle(udg_RaiseDead, GetHandleId(udg_Temp_Unit), 0, udg_Temp_Group)
  • Custom script: endif
  • Unit Group - Add (Summoned unit) to Temp_Group
  • Hashtable - Save Handle OfTemp_Group as 0 of (Key (Summoned unit)) in RaiseDead
  • Custom script: set udg_Temp_Group = null
  • Custom script: call UnitAddAbility(GetSummonedUnit(), 'Aloc')
  • Custom script: call UnitRemoveAbility(GetSummonedUnit(), 'Aloc')
So once the Necromancer has a unit group saved - it wouldn't keep saving the same group into his hashtable :p
But that's too minor to be bothered with. Tho Somefaggot can still fix it if he wants.
 
Last edited:

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,198
I did it in GUI for him, idk if Somefaggot knows JASS.
However, check the 1-st line of the trigger, and say again "You never set Temp_Unit".
And where do you flush the mapping from the hashtable in case the "Necromancer Lesser" is removed or dies?

idk if Somefaggot knows JASS.
Well he clearly must in order to use so much custom script. It is as good as a pure JASS trigger except uglier.

Why use GUI with so much custom script. It is easier to just JASS the thing. Even makes it more readable as you can have proper indentation.
 
Level 12
Joined
Jan 2, 2016
Messages
973
Ah, yes, I forgot to clear the Lesser one's hashtable.

And well, a bit over a month ago, I was using custom scripts, which I've seen on the forum. Didn't really know what exactly they were doing, just knew what should happen when I use them.

If someone is using custom scripts, that doesn't mean he knows JASS.

To Somefaggot:
Add 1 more condition to the OnDeath trigger: "Unit-Type of Triggering Unit is equal to ~the ward unit (Necromancer Lesser in my map)~"
in an "or" block
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,198
If someone is using custom scripts, that doesn't mean he knows JASS.
But it does when over 90% of what he is using is custom script.

Custom script: call SaveGroupHandle(udg_RaiseDead, GetHandleId(udg_Temp_Unit), 0, udg_Temp_Group)
Custom script: set udg_Temp_Group = LoadGroupHandle(udg_RaiseDead, GetHandleId(udg_Temp_Unit), 0)
Does not need to be custom script? Unless JNGP is used where the handle type is broken due to lack of maintenance.
 
Status
Not open for further replies.
Top