[Crash] GUI. Custom Script prevents map from loading the map or stops the map.

Level 9
Joined
Feb 11, 2016
Messages
249
Custom Script - for if it is in the map Initialization with out Wait - prevents map from loading and for other cases - the map stops with music keep playing. A few days ago I probably have read multiple cases of it. Now it is my problem too and I found this noting of it. I did not find things I have read a few days ago.

This is in Map Initialization. The last Custom Script is a problem. Matters not the way PRegion[2] is set.
1739500287472.png
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
You could just delete the RemoveRect calls, it shouldn't make a noticeable difference with or without them. Otherwise, maybe check if they're nil before trying to Remove them:
  • Custom script: if udg_PRegion[1] ~= nil then
  • Custom script: RemoveRect(udg_PRegion[1])
  • Custom script: end

But you really shouldn't be using a While Loop like that, there's no guarantee that it'll break since there's no guarantee that PRegion[2] will NOT contain the next Point. You should always have a failsafe that ensures it will stop and avoid executing too many times. Solution:

1) Create a new "SAFE" Region that is guaranteed to be outside of PRegion[2].
2) Use a For Loop and try to get a Random Point with a set number of attempts.
3) If the For Loop somehow fails, which is likely a < 0.01% chance to happen, you can fallback to your SAFE Region:
  • Custom script: for i=1,500 do
  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
    • If - Conditions
      • (PRegion[2] contains PMesto[1]) Equal to True
    • Then - Actions
      • Custom script: RemoveLocation(udg_PMesto[1])
      • Custom script: if i < 500 then
      • Set Variable PMesto[1] = (Random point in PRegion[1])
      • Custom script: else
      • Set Variable PMesto[1] = (Center of PRegionSafe <gen>)
      • Custom script: break
      • Custom script: end
    • Else - Actions
      • Custom script: break
  • Custom script: end
To further randomize it, in the extremely rare case that it fails, you can create multiple SAFE Regions and pick one at random.

Edit: Also, you could optimize this by checking the value of i AFTER the Loop has finished. That way it doesn't need to compare it's value up to 500 times.
 
Last edited:

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
Is the GUI call really for nil, instead of null? Or does it depend on the map script language settings?
It's because he's using Lua, GUI uses whichever scripting language you've enabled.

At the end of the day GUI is just coding with an interface layered over it. You're essentially writing Jass/Lua code whenever you create a GUI trigger.
 
Last edited:

Chaosy

Tutorial Reviewer
Level 41
Joined
Jun 9, 2011
Messages
13,239
You can also do the loop without custom scripts. 'break' would just be setting the loop number to above the max. It's not very pretty but if you're worried about custom scripts doing silly things that might be preferable. You can also avoid using rects entirely and use coordinates, avoids leaks naturally.

Probably not 'ideal' solutions but hey they work if nothing else will.
 
Level 9
Joined
Feb 11, 2016
Messages
249
@Uncle I seek perfection. Removing every leak. The solution of checking if it is nil workes, please somebody to check my Trigger, the only change is adding recommended two Custom Scripts. Weird WarCraft, weird GUI. I want not safe condition, even for random in programming, and more so in WarCraft, is problematic.
@Chaosy That is too advanced for me, I fail to understand. I want to understand.

This is the things I am afraid of in WarCraft, him not working properly, must I check every time to compensate for possible mistake of WarCraft, what if checking also be mistaken, not working, it can go forever, thankfully, this was rare to me yet, yet, I could not know which parts of the map will break for the mistake of WarCraft III?

Custom Script 1: "if udg_PRegion[1] ~= nil then";
Custom Script 2: "end".
 

Attachments

  • 1739543575128.png
    1739543575128.png
    26.8 KB · Views: 9
Last edited:

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
You're checking if [1] is nil then removing [2]. You're NOT checking this when you remove [1].

Here's how your trigger should look. I am replacing the While Loop with a For Loop:
  • Actions
    • Set Variable PRegion[1] = ...
    • Set Variable PRegion[2] = ...
    • Set Variable PMesto[1] = ...
    • // NEW //
    • Custom script: for i=1,500 do
    • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      • If - Conditions
        • (PRegion[2] contains PMesto[1]) Equal to True
      • Then - Actions
        • Custom script: RemoveLocation(udg_PMesto[1])
        • Custom script: if i < 500 then
        • Set Variable PMesto[1] = (Random point in PRegion[1])
        • Custom script: else
        • Set Variable PMesto[1] = (Center of PRegionSafe <gen>)
        • Custom script: break
        • Custom script: end
      • Else - Actions
        • Custom script: break
    • Custom script: end
    • Custom script: if udg_PRegion[1] ~= nil then
    • Custom script: RemoveRect(udg_PRegion[1])
    • Custom script: end
    • Custom script: if udg_PRegion[2] ~= nil then
    • Custom script: RemoveRect(udg_PRegion[2])
    • Custom script: end
PRegionSafe is a new Region you need to create and put OUTSIDE of PRegion[2]:
1739544183001.png

This is where PMesto[1] will be set to in extremely rare situations.


Also, please post your triggers instead of using pictures:
 
Level 9
Joined
Feb 11, 2016
Messages
249
@Uncle Yes. Fixing it leads to the base problem. Last days I have tried learning Variables being set to the Values from Hashtables, how are they connected, Memory Leaks of Hashtables for when a Variable that has Value from Hashtable is Removed or changed, does it Remove or change a Value in the Hashtable. It was too confusing and I failed learning that. It may be that the Value in Hashtable is Removed or changed for if a Variable that has a Value from that Hashtable is Removed or changed and that makes problems for me. Yet, I did read recently, weeks or months ago, also multiple cases, that Cust Scripts worked not. And Variable might be connected to a Hashtable only for the complex Values, that means Values that Leak Memory.

Post Scriptum: They are connected in this case, I tested, this was my fear, will I ever understand Hashtable Leaks, Gyrocopter is created at the Center of that Region, Gryphon Rider is Created at Null Position, Center of the Map.
 

Attachments

  • 1739548913340.png
    1739548913340.png
    12.1 KB · Views: 9
  • 1739549031873.png
    1739549031873.png
    2.4 MB · Views: 9
Last edited:

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
@Uncle Yes. Fixing it leads to the base problem. Last days I have tried learning Variables being set to the Values from Hashtables, how are they connected, Memory Leaks of Hashtables for when a Variable that has Value from Hashtable is Removed or changed, does it Remove or change a Value in the Hashtable. It was too confusing and I failed learning that. It may be that the Value in Hashtable is Removed or changed for if a Variable that has a Value from that Hashtable is Removed or changed and that makes problems for me. Yet, I did read recently, weeks or months ago, also multiple cases, that Cust Scripts worked not. And Variable might be connected to a Hashtable only for the complex Values, that means Values that Leak Memory.

Post Scriptum: They are connected in this case, I tested, this was my fear, will I ever udnerstand Hashtable Leaks, Gyrocopter is created at the Center of that Region, Gryphon Rider is Created at Null Position, Center of the Map.
I think you're trying to avoid the memory leak related to this function -> (Center of Region).

You do NOT want to Destroy or Remove the Region (Rect). Instead, you should Set a Point at the Center of that Region, use that Point when Creating your Units or whatever, and then Destroy that Point once you're done with it.

Here's an example:
  • Set Variable Region = (Load 4 of 1 in Hashtable[3])
  • Set Variable Point = (Center of Region)
  • Unit - Create 1 Gryphon Rider at Point facing (Random angle) degrees
  • Custom script: call RemoveLocation(udg_Point)
There is no memory leak here.

You do NOT want to Remove the Region (rect) if you plan on using it again. Only remove/destroy things that you don't want to use anymore. In other words, you destroy/remove TEMPORARY objects not PERMANENT objects. It's okay to have a bunch of Regions stored throughout the game, our computer's have so much memory these days it's not worth worrying about.

Note that you would probably be better off storing Points in your Hashtable instead of Regions:
  • Set Variable Point = (Load 4 of 1 in Hashtable[3])
  • Unit - Create 1 Gryphon Rider at Point facing (Random angle) degrees
There is no memory leak here. We loaded a Point from our Hashtable instead of a Region. That Point can remain active throughout the game if you plan on reusing it.
 
Last edited:
Level 9
Joined
Feb 11, 2016
Messages
249
@Uncle That is irrelevant, it is just for testing. My real problem is different. I have Regions saved in Hashtables, then, for if I am using the same Region multiple Actions - it is more difficult using Hashtable every time than saving it in the Temporary Variable, then using that Variable multiple Actions and Remove the Value of that Variable to prevent Memory Leak.
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
@Uncle That is irrelevant, it is just for testing. My real problem is different. I have Regions saved in Hashtables, then, for if I am using the same Region multiple Actions - it is more difficult using Hashtable every time than saving it in the Temporary Variable, then using that Variable multiple Actions and Remove the Value of that Variable to prevent Memory Leak.
I don't really understand what you're saying to be honest. :peasant-sad:

Saving Regions in a Hashtable isn't that useful. You're likely better off saving Points that exist at the Center of those Regions. Or you can save coordinates like Chaosy suggested, although, that's not so useful when working in GUI since everything is based on Points rather than X/Y/Z coordinates. Working with coordinates is great if you use code since you can use the more efficient non-Point related functions.

Point = (X, Y, Z)
Region = (Min X, Min Y, Max X, Max Y)

When you do something at the (Center of a Region) the game creates a Point there, using that Region's coordinates to figure out where to put it. You don't have to worry about memory leaks for these objects if you plan on reusing them.
 
Last edited:
Level 45
Joined
Feb 27, 2007
Messages
5,578
does it Remove or change a Value in the Hashtable
Object (unit, point, region, item, group, force...) exists. Hashtable stores a reference to that object, but not the object itself, so the hashtable can point you back to that same object when you want to find it again. If object is removed, hashtable reference now points to a nonexistant object (it doesn't contain the object that was removed still). If, instead, the hashtable is cleared then the object still exists (it doesn't contain the object, just a reference to that object) but there is nothing in the hashtable that would allow you to 'find' it.

Primitives (integer, real, string, boolean) are not objects and are not stored in hashtables as references. Instead, the actual value at the time of storage is stored there. If the variable holding the primitive is changed to a different value elsewhere the hashtable does not update. If the hashtable is cleared the variable holding the primitive will not change.
 
Level 9
Joined
Feb 11, 2016
Messages
249
@Pyrogasm Therefore - it is possible having a Temporary Variable for Object in a Hashtable? How can that Variable be Removed for removing Memory Leaks if Removing it the this way with Custom Script Removes it from a Hashtable, and in this, how can that Variable be Created (Set) at all, for, if Removing it Removes from a Hashtable, changing it - shall change it in the Hashtable, and Creating (Setting) it, somehow would set it in a Hashtable, the last one is not true, but the logic goes, it is weird.
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
@Pyrogasm Therefore - it is possible having a Temporary Variable for Object in a Hashtable? How can that Variable be Removed for removing Memory Leaks if Removing it the this way with Custom Script Removes it from a Hashtable, and in this, how can that Variable be Created (Set) at all, for, if Removing it Removes from a Hashtable, changing it - shall change it in the Hashtable, and Creating (Setting) it, somehow would set it in a Hashtable, the last one is not true, but the logic goes, it is weird.
Yes, you can store temporary variables in a Hashtable.

Simply removing a reference from a Hashtable (RemoveSavedHandle) does not automatically prevent memory leaks.

If the object in question is a handle (like a unit, effect, or timer), you need to explicitly destroy it first before removing it from the Hashtable.

Examples:

Destroying a Special Effect and Removing it from the Hashtable:
vJASS:
call DestroyEffect(LoadEffectHandle(myHashtable, key1, key2))
call RemoveSavedHandle(myHashtable, key1, key2)

Destroying a Point and Removing it from the Hashtable:
  • Actions
    • Set Variable TempPoint = (Load 1 of 1 from MyHashtable)
    • Custom script: call RemoveLocation( udg_TempPoint )
    • Custom script: call RemoveSavedHandle( udg_MyHashtable, 1, 1 )
I think the GUI actions for removing data from a Hashtable are a little weird/limited.

Here's a random thread I picked out of the dozens that talk about this:
 
Level 45
Joined
Feb 27, 2007
Messages
5,578
Man we really need an easy thread to link people about this. I can't explain it any better than I did in my above post or than DSG in the linked thread, so I'll just quote them here:
Dr Super Good said:
Once again. . .
Hashtables store integers, strings, reals, booleans or pointers.

When you store a location handle in a hashtable, you are storing its 32 bit pointer and not the actual location object itself. Thus when you clear the hashtable, all you do is flush away a pointer to the location (and free up some space in the hashtable to make it more efficent). The location still remains in memory, and infact will be the forever unless you have another pointer to it or can get a pointer to it which you then pass through the location destruction native.

Remember that clearing hashtables of usless data is important. It keeps them working efficently and also allows the recycling of handleIDs (pointers). While a handle is still stored in a struct, it's index can not be recycled even if the object it points to has long since stopped existing.
If you would like to ask a direct question for clarification/to grow your understanding/to learn the definition of a word/chip away at what you don't get, please do so. But frankly it's tiring to give a whole long-winded explanation at a wall that just says "I don't get it".
 
Top