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

[Lua]Obliterate all GUI leaks with 1 trigger!

Status
Not open for further replies.

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,202
Be aware of the age of this post. Much has changed since its creation so it may no longer be relevant or useful for the current version of Warcraft III. It is no longer possible to call the Lua garbage collector explicitly. I am also no longer sure how effective this approach is, or if it remains in sync with the current native garbage collector.

Imagine a world where GUI triggers do not need a mess of temporary variables to hold locations. Or a world where the annoying custom script lines like "RemoveLocation" do not exist. A world where we could leak as much as we want without any performance consequences.

Well imagine no more GUI users. Thanks to the power of patch 1.31 with Lua that world is real!

Behold a single Lua trigger solution which will fix all force, group and location leaks. No custom script calls required, it works fully automatically as if by witchcraft!
Code:
GC = {}
GC.Table = {}
setmetatable(GC.Table, {__mode = "k"})
GC.Native = {}
GC.Type = {}
GC.Type.__index = GC.Type
GC.Debug = true

function GC.Type:new(name, remove, constructors)
    local type = {}
    setmetatable(type, self)

    type.name = name
    type.remove = remove
    type.constructors = constructors
    type:register()
    return type
end

function GC.Type:printstats()
    if self.stats then
        print("Statistics for " .. self.name .. ":")
        print("Automatically freed: " .. self.stats.autofree)
        print("Explicitly freed: " .. self.stats.explicitfree)
        print("Currently alive: " .. self.stats.alive)
        print("Bad free calls: " .. self.stats.badfree)
        print("Bad constructor calls: " .. self.stats.badconstruct)
        print("Free calls on untracked: " .. self.stats.unknownfree)
    else
        print("Can only print statistics when GC is running in debug mode.")
    end
end

function GC.Type:register()
    local debug = GC.Debug

    if not GC.Native[self.remove] then
        GC.Native[self.remove] = _ENV[self.remove]
    end

    local removefunc = GC.Native[self.remove]

    if debug then
        if not GC.FreedTable then
            GC.FreedTable = {}
            setmetatable(GC.FreedTable, {__mode = "k"})
        end

        self.stats = {
            autofree = 0,
            explicitfree = 0,
            alive = 0,
            badfree = 0,
            badconstruct = 0,
            unknownfree = 0
        }
    end

    local collectfunc
    if not debug then
        collectfunc = function(obj)
            removefunc(obj[1])
        end
    else
        collectfunc = function(obj)
            removefunc(obj[1])
            self.stats.autofree = self.stats.autofree + 1
            self.stats.alive = self.stats.alive - 1
        end
    end

    local collectmetatable = {
        __gc = collectfunc
    }

    if not debug then
        _ENV[self.remove] = function(obj)
            local table = GC.Table[obj]
            if table then
                removefunc(obj)
                setmetatable(table, nil)
                GC.Table[obj] = nil
            end
        end
    else
        _ENV[self.remove] = function(obj)
            local table = GC.Table[obj]
            if table then
                removefunc(obj)
                setmetatable(table, nil)
                GC.Table[obj] = nil
                GC.FreedTable[obj] = true
                self.stats.explicitfree = self.stats.explicitfree + 1
                self.stats.alive = self.stats.alive - 1
            else
                if not obj or GC.FreedTable[obj] then
                    if obj then
                        print("Tried to free an already freed object: " .. obj)
                    else
                        print("Tried to free nil of type: " .. self.name)
                    end
                   
                    self.stats.badfree = self.stats.badfree + 1
                else
                    self.stats.unknownfree = self.stats.unknownfree + 1
                end

            end
        end
    end

    local registerfunc
    if not debug then
        registerfunc = function(obj)
            local table = {obj}
            setmetatable(table, collectmetatable)
            GC.Table[obj] = table
        end
    else
        registerfunc = function(obj)
            local table = {obj}
            setmetatable(table, collectmetatable)
            GC.Table[obj] = table
            self.stats.alive = self.stats.alive + 1
        end
    end

    for i, v in ipairs(self.constructors) do
        if not GC.Native[v] then
            GC.Native[v] = _ENV[v]
        end

        local constructorfunc = GC.Native[v]

        if not debug then
            _ENV[v] = function(...)
                local result = constructorfunc(...)
                if result then
                   registerfunc(result)
                end
                return result
            end
        else
            _ENV[v] = function(...)
                local result = constructorfunc(...)
                if result then
                   registerfunc(result)
                else
                    print("Constructor call returned nil: " .. v)
                    self.stats.badconstruct = self.stats.badconstruct + 1
                end
                return result
            end
        end
    end
end

GC.Location = GC.Type:new("location", "RemoveLocation",
    {"BlzGetTriggerPlayerMousePosition",
        "CameraSetupGetDestPositionLoc",
        "GetCameraEyePositionLoc",
        "GetCameraTargetPositionLoc",
        "GetOrderPointLoc",
        "GetSpellTargetLoc",
        "GetStartLocationLoc",
        "GetUnitLoc",
        "GetUnitRallyPoint",
        "Location"
    })

GC.Group = GC.Type:new("group", "DestroyGroup",
    {"CreateGroup"
    })

GC.Force = GC.Type:new("force", "DestroyForce",
    {"CreateForce"
    })
Attached is a demo map to show its usage, and allow one to experiment with it. Press Esc to get technical information such as how many leaks were caught.

Proof that it works is easy. Duplicate the actions of the Leaky Demo Trigger 20 or 40 times and test the map. Thanks to the Lua based garbage collector the Warcraft III application memory usage will not really increase. Now if one disables the Garbage Collector trigger and tests then the Warcraft III application memory usage will increase at the rate of 10s of megabytes per second.

From a technical point of view it works by replacing all references to constructor and destructor functions for force, group and location within the Lua virtual machine to proxies. These proxies register or deregister an object for automatic garbage collection. Automatic garbage collection is implemented using the properties of a weak keyed map to map an object to a table holding the object which uses the garbage collected metamethod to destroy the object it wraps. When all references to a location are lost, the properties of the weak keyed map allow the wrapping table to be garbage collected which then runs the clean up function.

It is worth noting that this approach only works if the Lua garbage collector ever runs. Since the object memory itself is not factored in as part of the Lua heap size it is possible that the default Lua garbage collector settings do not run the collector frequently enough to prevent leak related performance issues. To prevent this one might have to fine tune the Lua garbage collector settings to encourage it to run more frequently. This is done in the demo map in the Lua Test trigger. In theory this could be tuned on a per map basis as required.

WARNING: Garbage collection is run locally for each client. Local object destruction will cause clients to go out of sync. The snippet below can be used to synchronize garbage collection at the cost of disabling incremental collection and potentially causing stutter with complex maps
Code:
collectgarbage("stop")

nsgc = {
trigger = CreateTrigger(),
func = collectgarbage}

nsgc.event = TriggerRegisterTimerEvent(nsgc.trigger, 10, true)
nsgc.action = TriggerAddAction(nsgc.trigger, nsgc.func)

One can turn off statistic logging and warning messages by changing commenting or removing the line containing GC.Debug = true. This mode should offer a minor performance improvement and intended for non-development versions of maps. This mode cannot be toggled dynamically, it is effectively a compile time flag.
 

Attachments

  • GC Demo Network Safe 1.2.w3x
    15.2 KB · Views: 279
Last edited:
Level 13
Joined
Mar 24, 2013
Messages
1,105
I don't understand lua or what is happening in the code.

BUT..the concept sounds nice, and hopefully with the likely new crop of GUI coders coming soon with reforged this will be a nice tool.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,202
Is the TypeId2Integer function necessary? Can you not access UnitIds with single quotes in Lua like you do in JASS?
No Lua does not support that. Read every Lua tutorial every written and you will see that such syntax does not exist in Lua. JASS only supports it because it was specifically made for Warcraft III rather than Lua which is a general programming/scripting language.

Also that is part of the test script so not required for the system to work.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,202
Interesting. So to access any object by it's Id value with Lua, we would need to create a function like the one you wrote?
It is only needed for object types to go from human readable raw code to integer. All object types returned by functions are already integers so can be passed around directly just like with JASS.

There is also a way to decode directly using built in Lua functions (not shown in the map). Additionally I think with 1.31.1 there are now natives to perform the conversion from string as well.
Is there any easier way to do it without using shifts and other bit operations?
Yes you can use the Lua standard library encode and decode mechanisim. This may or may not be faster. There might also be natives to do such a conversion.
GUI Lua code uses FourCC("hfoo") to convert unitIds.
This was added after the PTR, hence why the code above did not use it as it was test code left in from the PTR in the map I developed this system.
 
Level 11
Joined
Jul 19, 2011
Messages
604
Hey, thanks a lot for your work, but I'm having a problem, when I try to save it gives me a syntax error with a message saying "missing endblock", any idea how to fix this?
Untitled.jpg
 
Last edited:

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,202
Try disabling JASSHelper. Apparently there are compatibility issues with it and maps running in Lua mode. For some reason...

If importing into your own map. Make sure the map is operating in Lua mode. This is an Lua only fix for using the Lua virtual machine. The JASS2 virtual machine does not allow one to perform such a fix.

One can still use GUI and JASS (JASS2) with Lua thanks to a transpiler on save. Just for some reason it does not work well with vJASS.
 
Last edited:
Level 11
Joined
Jul 19, 2011
Messages
604
Well now I got a whole bunch of other errors about the lua code after I disabled vJass.
Untitled.jpg

With vJass it works on other maps without missing endblock error.
 
Last edited:
Level 7
Joined
Jul 1, 2008
Messages
1,025
Hi Dr Super good,

If it works in multiplayer this looks like a great tool! Me and Yousef are working on a popular Bnet map: Lordaeron the Foremath (LTF), however since latest Blizzard patches the game becomes very unstable after 1 hour game play. As this is an epic RTS game sometimes the battles can rage on for up to 2 hours so stability is paramount to the map's enjoyment, we think this Lua trash collector could really help us.

However, we already use a lot of Jass custom scripts in the game, this is usually for stuff like cleaning up location variables and other simple functions. If I understand correctly we cna remove these if we are using your clean script as they will become redundant?

Unfortunately we do also use jass custom scripts for other functions, such as making sounds only play to single player, or setting filters for a specific player. Examples below, can you advise on how we can replace these jass scripts with Lua versions? Neither me nor Yousef are trigger experts.

We should then be able to convert the map script to Lua and try out your script. Annoyingly there are quite a lot of triggers on this map, its huge so it will be no easy task for us!

Custom Jass script:
if GetLocalPlayer() == Player(4) then
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,202
However, we already use a lot of Jass custom scripts in the game, this is usually for stuff like cleaning up location variables and other simple functions. If I understand correctly we cna remove these if we are using your clean script as they will become redundant?
You could. However there is also no harm keeping them in as the system will work around them to stop leaks that might otherwise have been missed.

That said in order for the system to work efficiently one might have to tune how often the garbage collector is run, as I did in the demo map. When the Lua garbage collector runs it will remove all leaks, but the rate at which that happens might not be optimal with the default garbage collector settings. In the demo map I changed the settings, but one could also explicitly run the garbage collector, eg every 15 or 60 seconds.
Unfortunately we do also use jass custom scripts for other functions, such as making sounds only play to single player, or setting filters for a specific player. Examples below, can you advise on how we can replace these jass scripts with Lua versions? Neither me nor Yousef are trigger experts.
The built in JASS2toLua transpiler should handle all that. GUI still compiles to JASS on map save but when the map is in Lua mode it will convert the resulting JASS script to Lua using the built in transpiler.
 
Level 7
Joined
Jul 1, 2008
Messages
1,025
That said in order for the system to work efficiently one might have to tune how often the garbage collector is run, as I did in the demo map. When the Lua garbage collector runs it will remove all leaks, but the rate at which that happens might not be optimal with the default garbage collector settings. In the demo map I changed the settings, but one could also explicitly run the garbage collector, eg every 15 or 60 seconds.

I think once very 60 seconds would be perfect, the map is huge so it really depends how much extra stress the cleanup script causes on the game when it runs.

The built in JASS2toLua transpiler should handle all that. GUI still compiles to JASS on map save but when the map is in Lua mode it will convert the resulting JASS script to Lua using the built in transpiler.

If the build in transpiler can do all the converting that would make it so much easier, there's ALOT of triggers. However, the problem I'm finding is that I don't even get the option to convert the script. Its greyed out:

Lua Disabled.jpg
 
if your map contains one line of hand written code you are not allowed to swap language mode. From offical patch-notes.
  • Maps save in the selected language
  • Maps that are written only in standard libraries can switch to Lua
  • Maps that use custom script will have to disable all custom triggers before conversion
Disable all triggers with custom script then you should be able to swap to Lua.
 
Level 11
Joined
Jul 19, 2011
Messages
604
Ok so after doing as mentioned above and changing scripting language, then adding the Garbage Collector trigger and saving I got this syntax error.
Untitled.jpg


EDIT: It doesn't seem to have anything to do with the Garbage Collector because I still got the syntax error after removing the garbage collector and saving.
 
Last edited:

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,202
Edit: @Dr Super Good is this also including all the Blizzard.j functions that create these things?
Yes it does. Whenever Lua tries to call those functions it uses the proxies which register the object.

If someone could confirm it is network safe then it is the ultimate solution for GUI coders. The infrequency of the garbage collector being run can be solved by a trigger that explicitly executes the garbage collector every 10 or 60 seconds.
 
The demo map disconnects for me. I tested it with 2 applications on the same machine playing over lan. After something like 8k where catched (currently alive), it start to free some. When the free count reached 2 the not host got a dc. 2 was the number shown for the not host when he dc. I spammed pressing esc with the host.

I added another ESC event for player(1) and changed blue to a user player.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,202
The demo map disconnects for me. I tested it with 2 applications on the same machine playing over lan. After something like 8k where catched (currently alive), it start to free some. When the free count reached 2 the not host got a dc. 2 was the number shown for the not host when he dc. I spammed pressing esc with the host.

I added another ESC event for player(1) and changed blue to a user player.
This would mean that the garbage collector running is not synchronized. For some reason Warcraft III must be check summing the existence of locations to determine if clients go out of sync.

All hope might not be lost yet. Here is another test which disables the standard garbage collection mechanics and instead explicitly executes the garbage collector every 10 game seconds. This execution of garbage collection should be network safe and due to the usage of all objects being the same between clients the objects collected should also be the same between all clients.

However the order the objects are collected might not be the same. I would hope this does not make a difference since the same object set should exist between all clients however only testing could tell.

Also I am aware of the negative aspects of this solution. Specifically it will perform a full garbage collection sweep instantly every 10 seconds. With very complex or busy maps this could potentially result in stutter every time the garbage collector runs. This normally does not happen because Lua uses an incremental garbage collector which will run over a number of frames.

EDIT: It appears that this approach might work for multiplayer.
 

Attachments

  • GC Demo Network Safe Test.w3x
    14.7 KB · Views: 107
Last edited:

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,202
Dr SG would you be interested in please sharing the Lua code you're using in that map?
Same code as before except with this garbage collector added...
Code:
collectgarbage("stop")

nsgc = {
trigger = CreateTrigger(),
func = collectgarbage}

nsgc.event = TriggerRegisterTimerEvent(nsgc.trigger, 10, true)
nsgc.action = TriggerAddAction(nsgc.trigger, nsgc.func)
Basically it forces the garbage collector to run in lock step. The issue with this is that it disables incremental garbage collection so each collection cycle may freeze LUA for many frames with very complex maps.

The reason I assign the event and action to variables is due to a bug in Warcraft III. If one does not do this the event and action are automatically garbage collected and so the system breaks and no further garbage collection occurs. This only applies to actions and events created in the Lua initialization thread, standard JASS style creation of events and actions work fine in Lua and do not need to be assigned to a variable.
 
What I'm wondering in terms of reliability is to manually check when the variable loses its assignment. I read the garbage collector is able to track references to a variable, and that users have access to some kind of debug script to find the same, but I'm unsure what that script is.

Another possibility is to just assume all locations, groups and forces should be removed and maybe require the user to set an inverse of "wantDestroy" like "wantKeepPosition = true" and just remove everything else after a 0.00 second timer. Obviously still be hooking (replacing) the problem triggers.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,202
What I'm wondering in terms of reliability is to manually check when the variable loses its assignment. I read the garbage collector is able to track references to a variable, and that users have access to some kind of debug script to find the same, but I'm unsure what that script is.
As far as I am aware Lua does not use a reference count based system for garbage collection. Instead it uses the traditional approach of a mark and sweep garbage collector with support for an incremental operating mode. Fundamentally this works by iterating all nodes in the state graph that are reachable from root and marking them. After the entire state graph has been iterated any objects not marked are garbage (not referenced) and so are eligible for garbage collection. The advantage of this approach is minimal overhead with assignments and strong robustness against cyclic references.

As such it is not possible to know when an object in Lua is no longer referenced other than applying a __gc metamethod to it and run a full garbage collection cycle.
Another possibility is to just assume all locations, groups and forces should be removed and maybe require the user to set an inverse of "wantDestroy" like "wantKeepPosition = true" and just remove everything else after a 0.00 second timer. Obviously still be hooking (replacing) the problem triggers.
This kind of defeats the purpose of automatic garbage collection. If a programmer is doing that, they might as well just explicitly destroy the objects they create.

The point of this garbage collector is to provide 2 services.
  • Easily fix up a very leaky map with literally 1 imported trigger. Very newbie friendly and might turn a map that quickly became unplayable due to leaks to being a good experience. The user does not even need to know anything about leaks for this to work as it is all automatic.
  • Provide instrumentation to detect leaks. Many people think their map is leak free but is it actually so? This is a very common question one sees on the forum or in chat rooms. When running in debug mode the garbage collector will count all leaks and incorrect destruction calls. If those numbers are very small then yes their map is leak free and any performance issues they have are caused by trigger complexity. If not then their map was not leak free and likely the leaks were causing the performance issues.
 
Level 3
Joined
Apr 29, 2019
Messages
32
I tried this on my map, with the "Network Safe" script alongside it, and it stopped my orc waves from spawning. Technically, I suppose I had no unit leaks =)

Uploaded the map in case you wanted to look at it. The scripts are there but disabled.
 

Attachments

  • Balin_s Tomb Reforged 2.8.w3x
    1.6 MB · Views: 79

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,202
and it stopped my orc waves from spawning. Technically, I suppose I had no unit leaks =)
The issue is caused by trigger nonsense. For example this trigger...
  • first wave
    • Events
      • Time - Elapsed game time is 45.00 seconds
    • Conditions
    • Actions
      • Unit - Create 10 Goblin for Player 12 (Brown) at (Center of Region 000 <gen>) facing (Position of (Triggering unit))
      • Unit Group - Pick every unit in (Units in Region 000 <gen> owned by Player 12 (Brown)) and do (Unit - Order (Picked unit) to Attack-Move To (Center of Region 001 <gen>))
There is no Triggering unit in that context. Hence you are attempting to get the position of nil.

Warcraft III normally handles this gracefully however a bug in my garbage collection script causes a Lua thread crash instead. Hence the units never are created as code never advances enough to create them. The thread crash was because I tried to wrap nil for garbage collection which makes no sense.

I have attached a fixed version to the main post, GC Demo Network Safe 1.2.w3x. This version will correctly propagate nil returns from constructors and log them as bad constructor calls for debugging purposes. Such errors will now print a message in debug mode rather than crash the thread.
 
Last edited:
Level 3
Joined
Apr 29, 2019
Messages
32
The issue is caused by trigger nonsense. For example this trigger...
  • first wave
    • Events
      • Time - Elapsed game time is 45.00 seconds
    • Conditions
    • Actions
      • Unit - Create 10 Goblin for Player 12 (Brown) at (Center of Region 000 <gen>) facing (Position of (Triggering unit))
      • Unit Group - Pick every unit in (Units in Region 000 <gen> owned by Player 12 (Brown)) and do (Unit - Order (Picked unit) to Attack-Move To (Center of Region 001 <gen>))
There is no Triggering unit in that context. Hence you are attempting to get the position of nil.

Warcraft III normally handles this gracefully however a bug in my garbage collection script causes a Lua thread crash instead. Hence the units never are created as code never advances enough to create them. The thread crash was because I tried to wrap nil for garbage collection which makes no sense.

I have attached a fixed version to the main post, GC Demo Network Safe 1.2.w3x. This version will correctly propagate nil returns from constructors and log them as bad constructor calls for debugging purposes. Such errors will now print a message in debug mode rather than crash the thread.

Oh. Thanks! I didn't even realize I made that one a nonsense facing. Do you think, for any reason, it would be better to make it face "default building degrees" or whatever instead? Then have that leak cleaned instead.

Since I'm going to be using this map as a published version - and I don't know code - I could guess you just remove the "print("Constructor call returned nil: " .. v)" line to prevent it from giving the error message, but I don't want to mess things up further. Is that accurate?
 
Last edited:

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,202
Oh. Thanks! I didn't even realize I made that one a nonsense facing. Do you think, for any reason, it would be better to make it face "default building degrees" or whatever instead? Then have that leak cleaned instead.
It should be made default facing degrees as currently the trigger does not make any sense and is relying on fall back/default behaviour.

As mentioned above the new version of the system, available on the first post, has fixed the thread crash issue. When operating in debug mode it will instead print a warning telling you that some nonsense has happened. These warnings are not produced in non-debug mode.
Since I'm going to be using this map as a published version - and I don't know code - I could guess you just remove the "print("Constructor call returned nil: " .. v)" line to prevent it from giving the error message, but I don't want to mess things up further. Is that accurate?
You can disable debug mode to turn the warning messages off. The reason warning messages are produced is to notify map developers that they are doing something silly/nonsensical by mistake. For example they tried to create a location with invalid parameters resulting in nil being returned or that they tried to call RemoveLocation twice on the same location or on a nil location. These are technically harmless, but do not really make sense to allow to happen as it basically results in wasted cycles.

In your case you would want the units to face some other location, or a default facing angle.
 
Level 2
Joined
Feb 10, 2016
Messages
6
There are other stuff that leak as well, for example Floating Text (called TextTag in Blizzard functions). As far as I understand how this works, simply adding:

Code:
GC.TextTags = GC.Type:new("textTag", "DestroyTextTag",
    {"CreateTextTag"
    })

should clean those as well. I'm not sure what else is leaking as well but few things that comes to mind is Destructible object groups, special effects and ground deformations.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,202
There are other stuff that leak as well, for example Floating Text (called TextTag in Blizzard functions). As far as I understand how this works, simply adding:
There is a limit to at most 100 of them, after which the last allocated one is recycled. Additionally they come with GUI accessible self destruct mechanics and they are easy to notice when leaking as they have a visual appearance. The self destruct mechanics are not compatible with this implementation.

Floating text leaks have not and will never be a problem. At worst displaying them will break, which developers can easily notice and fix. They will not cause performance issues like group, force and location leaks do.
 
Level 2
Joined
Feb 10, 2016
Messages
6
There is a limit to at most 100 of them, after which the last allocated one is recycled.
That explains some weird behavior I had while testing a lot of texts :D For destructable groups, it seems that they are never created in the way as unit groups are, since all destructable functions that do something for multiple destructables return nothing.
Special Effects and other stuff have GUI destructors, so thats why you don't need them in this system, got it :)
 
That explains some weird behavior I had while testing a lot of texts :D For destructable groups, it seems that they are never created in the way as unit groups are, since all destructable functions that do something for multiple destructables return nothing.
Special Effects and other stuff have GUI destructors, so thats why you don't need them in this system, got it :)
There are no destructable groups, item groups, widget groups. There are item pools, unit groups and player forces.

Other things which can be grouped are boolexprs and anything added to a single trigger.
 
Level 1
Joined
Jan 12, 2020
Messages
5
Hello and thanks for writing this. I am unable to test your map (or mine with your triggers). The game just sits there forever on the door knocker screen (with a small blue square on the bottom left).

Can you confirm this still works with current patch?
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,202
Can you confirm this still works with current patch?
Yes it works with 1.31.

It may not work with 1.32 which is currently in beta. Blizzard may have implemented something similar natively so it is no longer required. I cannot test 1.32 beta (do not have Reforged) but the synchronized garbage collector certainly does not work from what other people have said.
 
Level 1
Joined
Jan 12, 2020
Messages
5
I am in fact using 1.32. I don't see anything in the patch notes. However, I did find a few people complaining about lua in recent patch notes feedback.
Anyway, it sounded so lovely to me. Maybe closer to release, it will work again. Thanks.
 
Sorry to say this but for me this is a nice gimmick, nothing more.

Yes it works, yes it helps but in my opinion this should never replace correct cleanup handling. This will cause additional stress on the game which can be prevented by doing cleanups correctly in the first place.

I like the idea/concept, but I fear this will lead to even worse coding in maps.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,202
This will cause additional stress on the game which can be prevented by doing cleanups correctly in the first place.
Additional stress?
I like the idea/concept, but I fear this will lead to even worse coding in maps.
Locations, groups and forces should never have leaked to begin with. In StarCraft II there are no such problems.
 
Status
Not open for further replies.
Top