• 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.

[Solved] Leaked points on triggers that fire only once/Custom function to prevent leak

Status
Not open for further replies.
Level 28
Joined
Nov 25, 2021
Messages
507
Firstly, I want to know if leaked points in triggers that only fire once every playthrough (like single-player cinematics) will severely affect the performance.

I also want to know the general consensus on this matter, because in my opinion, it makes the GUI code much longer and harder to read.

Better yet, how can I write a function that's like: call MyFunc(udg_MyUnit, udg_MyRegion) to order MyUnit to move to the center of MyRegion, with no leaked point at all?
 
Level 45
Joined
Feb 27, 2007
Messages
5,578
Firstly, I want to know if leaked points in triggers that only fire once every playthrough (like single-player cinematics) will severely affect the performance.
No, they are a minor amount of memory each (on the order of some bytes, as I recall) and will not negatively impact performance in small numbers (100s to 1000s). The concern is realistically for triggers that run frequently or have a high number of leaks each. If you want to be lazy there is not a real concern in a cinematic, but it's more the principle of ignoring the issues and that often people are not aware of the total number of times triggers with leaks will run.
in my opinion, it makes the GUI code much longer and harder to read.
You will get used to it. These resources can also fundamentally change how GUI works to make these sort of solutions neater/more reasonable looking/more automatic:

Better yet, how can I write a function that's like: call MyFunc(udg_MyUnit, udg_MyRegion) to order MyUnit to move to the center of MyRegion, with no leaked point at all?
I think the Global Variable Remapper by Bribe I linked above is a great way to do this, but here's a function you can use:
JASS:
function MoveUnitToRegion takes unit whichUnit, rect whichRegion, boolean exact returns nothing
  //that says rect because what the WE and GUI call regions are (most of the time) actually JASS rects, hence their names starting with gg_rct_
  local real x = GetRectCenterX(whichRegion)
  local real y = GetRectCenterY(whichRegion)
  local location l

  //Using SetUnitX/Y here is a choice because that can place the unit inside a building or in unpathable terrain
  if exact then //call with true to move to the middle regardless of what's there
    call SetUnitX(whichUnit, x)
    call SetUnitY(whichUnit, y)
  else //call with false to allow the unit to be moved out of unpathable terrain automatically
    set l = Location(x,y)
    call SetUnitPositionLoc(whichUnit, l)
    call RemoveLocation(l)
    set l = null
  endif
endfunction
 
Last edited:
Level 28
Joined
Nov 25, 2021
Messages
507
Thanks a lot for your help and for answering my questions, along with giving me some materials for LUA code in case I need it in the future.

As for your function, I edited it a bit using my limited JASS knowledge to suit my simple purpose:

JASS:
function OrderMoveToRegion takes unit whichUnit, rect whichRegion returns nothing
  local real x = GetRectCenterX(whichRegion)
  local real y = GetRectCenterY(whichRegion)
  local location l

  set l = Location(x,y)
  call IssuePointOrderLoc(whichUnit, "move", l)
  call RemoveLocation(l)
  set l = null
 
endfunction

I also used it as a basis to make this, which shortens the process of making a Dummy that casts a spell on a target of ability being cast:
JASS:
function DummyCastTarget takes integer SpellID, string SpellOrder, integer SpellLevel returns nothing
  
  local unit Caster = GetSpellAbilityUnit()
  local unit Target = GetSpellTargetUnit()
  local location l = GetUnitLoc(Caster)
  local unit Dummy = CreateUnitAtLoc( GetOwningPlayer(Caster), 'dum1', l, GetUnitFacing(Caster) )
  
  call UnitApplyTimedLife(Dummy, 'BHwe', 3)
  call UnitAddAbility(Dummy, SpellID)
  call SetUnitAbilityLevel(Dummy, SpellID, SpellLevel)
  call IssueTargetOrder(Dummy, SpellOrder, Target)
  call RemoveLocation(l)
  set l = null

endfunction
 
I also used it as a basis to make this, which shortens the process of making a Dummy that casts a spell on a target of ability being cast:
There are several good reasons to do something like this.
Say that you in the future want to add a dummy-recycler, you only have to do it in this place and it will be added in most places.
(dummy recyclers can increase performance. Spawning tons of units (dummies) can cause some amount of lag).

I also have small function like this for things like healing and dealing damage (AoE), etc. to be able to add floating texts, filter friendly-fire on/off, adding "bonus healing" and "onHealEvents" etc.

My point is: it is generally a good idea to "centralize" things that you do many times that requires a few lines of GUI or code to do. It makes it easier to expand upon in the future too.
 
Level 45
Joined
Feb 27, 2007
Messages
5,578
Your functions look good and you're well on your way to writing and understanding your own JASS directly instead of relying on GUI! There is a certain irony here that you may appreciate: you initially wanted these functions to avoid cleaning leaks in GUI every time, but JASS actually has much easier and more direct access to coordinates than GUI does. Ultimately, your JASS functions will be most efficient when they use XY coordinates instead of locations at all.
JASS:
function DummyCastTarget takes integer SpellID, string SpellOrder, integer SpellLevel returns nothing
 
  local unit Caster = GetSpellAbilityUnit()
  local unit Target = GetSpellTargetUnit()
  local real x = GetUnitX(Caster)
  local real y = GetUnitY(Caster)
  local unit Dummy = CreateUnit( GetOwningPlayer(Caster), 'dum1', x, y, GetUnitFacing(Caster) )
 
  call UnitApplyTimedLife(Dummy, 'BHwe', 3)
  call UnitAddAbility(Dummy, SpellID)
  call SetUnitAbilityLevel(Dummy, SpellID, SpellLevel)
  call IssueTargetOrder(Dummy, SpellOrder, Target)

endfunction
 
Status
Not open for further replies.
Top