System Unit Enters Range

Darthfett

Aerospace/Cybersecurity Software Engineer
Reaction score
615
Unit Enters Range
Created by Darthfett
Requires: CSData,PUI,BoolexprUtils
Created in vJASS
MUI
MPI


If you've ever used the Unit comes within range of another unit type events, you've probably realized one of the flaws of the event:
There is no "Get the unit which the entering unit came in range of" type function.

Well, that's what I created this system to solve. Basically, it creates a struct, attaches it to a trigger, and adds the UnitInRange event to the trigger. Then you can add your conditions and actions to the trigger.

About the System:
One Trigger Per Unit - Since the system does not use gamecache (to create unique string keys for each unit), it cannot attach multiple units to the same trigger. Therefore it has to create a unique trigger for each unit.

How To: Use the System -

1. Get something that supports vJASS (Newgen {Recommended}, JASSHelper
2. Create a Trigger named "EnterRange"
3. Copy-paste "System Code" into the "EnterRange" Trigger
4. Read the rest of the "How To"s to learn how to use the system.

JASS:
private function Init takes nothing returns nothing
    local trigger t = TriggerRegisterUnitEnterRangeEvent(UNIT,RANGE,SOME_BOOLEXPR)
endfunction


This will create a trigger, and register the event for the unit, in one line.

How To: Get the Unit -

JASS:
private function Actions takes nothing returns nothing
    local unit u = GetEnteringUnit()
    local unit v = GetCenterUnit()
endfunction


u now contains the entering unit. v now contains the "unit which the entering unit came in range of."

How To: Destroy the Trigger-Event -

If you have a unit, and you want to get rid of the UnitInRange trigger-event for the unit, simply call RemoveUnitEnterRangeEvent with the unit.

If you somehow have the trigger, and want to destroy it, use RemoveTriggerEnterRangeEvent, rather than DestroyTrigger. However, if you are using this with GetTriggeringTrigger() (or the trigger that started the thread), use the RemoveTriggerEnterRangeEventAlt function. This will destroy the trigger in a separate thread, so that you don't cause any problems.

System Code:
JASS:
library EnterRange uses CSData,PUI,BoolexprUtils

//===============
//
//       Enter Range v1.02
//      Created by Darthfett
//
// Requires:
//     CSData
//     PUI
//
// Place in a trigger called "EnterRange"
//
//  Provides the unit which the entering unit 
//      came in range of: "GetCenterUnit()"
//
//===============

private struct Data
    //! runtextmacro PUI()
    
    unit whichUnit
    trigger t
    
    static method create takes unit whichUnit returns Data
        local Data d = Data[whichUnit]
        if d != 0 then
            call d.release()
        endif
        set d = Data.allocate()
        set d.t = CreateTrigger()
        set d.whichUnit = whichUnit
        call SetCSData(d.t,d)
        set Data[whichUnit] = d
        return d
    endmethod
        
    method onDestroy takes nothing returns nothing
        call SetCSData(.t,0)
        call DestroyTrigger(.t)
    endmethod
endstruct

//Use the function below to create a trigger with the event
function TriggerRegisterUnitEnterRangeEvent takes unit whichUnit, real range, boolexpr filter returns trigger
    local Data d = Data.create(whichUnit)
    if filter == null then
        call TriggerRegisterUnitInRange(d.t,whichUnit,range,BOOLEXPR_TRUE)
    else
        call TriggerRegisterUnitInRange(d.t,whichUnit,range,filter)
    endif
    return d.t
endfunction

//Use the function below to get the unit which the entering unit came in range of
function GetCenterUnit takes nothing returns unit
    return Data(GetCSData(GetTriggeringTrigger())).whichUnit
endfunction

//Use the function below to dispose of the trigger and event for the unit.
function RemoveUnitEnterRangeEvent takes unit whichUnit returns boolean
    local Data d = Data[whichUnit]
    if d == 0 then
        return false
    endif
    call d.release()
    return true
endfunction

//This will destroy the trigger and clean the struct, but it is NOT to be used with GetTriggeringTrigger()
function RemoveTriggerEnterRangeEvent takes trigger t returns boolean
    local Data d = GetCSData(t)
    if d == 0 then
        return false
    endif
    call d.release()
    return true
endfunction

private function Destroy takes nothing returns nothing
    call Data(GetCSData(GetExpiredTimer())).release()
    call DestroyTimer(GetExpiredTimer())
endfunction

//If you want to use GetTriggeringTrigger(), use this function instead of RemoveTriggerEnterRangeEvent
function RemoveTriggerEnterRangeEventAlt takes trigger trig returns nothing
    local Data d = GetCSData(trig)
    local timer t = CreateTimer()
    call SetCSData(t,d)
    call TimerStart(t,0,false,function Destroy)
    set t = null
endfunction

endlibrary


Fireshock (Attached) is a spell that uses the system to strike entering units with lightning.
 

Attachments

  • FireShock.w3x
    39.2 KB · Views: 311

Renendaru

(Evol)ution is nothing without love.
Reaction score
309
Don't BoolExpr's leak? Not sure on that though...
 

Darthfett

Aerospace/Cybersecurity Software Engineer
Reaction score
615
Don't BoolExpr's leak? Not sure on that though...

I've heard of the fact that using null boolexpr's leaks, but even if regular boolexprs do, it doesn't matter in this case. I'm using a global boolexpr, to get rid of the null boolexpr. It's going to be reused, so destroying and re-creating it would waste processing speed, as opposed to memory.
 

Renendaru

(Evol)ution is nothing without love.
Reaction score
309
Ah, nice work on the system then.
 

Flare

Stops copies me!
Reaction score
662
Hmmmm... what's so useful about this over just using TriggerRegisterUnitInRange (or whatever the native is called)? There's nothing in particular I can see about this that can't be done with the native and pretty much any struct attachment system. If you could do it without requiring dynamic triggers and guarantee the correct GetCenterUnit, then it'd be awesome, but otherwise I think it's just a bulky version of TriggerRegisterUnitInRange.

Also:
JASS:
//! textmacro EVENT_CreateData
    local Data d = Data.create()
    local trigger t = CreateTrigger()
    call SetCSData(t,d)
    set d.whichUnit = whichUnit
//! endtextmacro

function TriggerRegisterUnitEnterRangeEventEx takes unit whichUnit, real range, boolexpr filter returns trigger
    //! runtextmacro EVENT_CreateData()
    call TriggerRegisterUnitInRange(t,whichUnit,range,filter)
    return t
endfunction

function TriggerRegisterUnitEnterRangeEvent takes unit whichUnit, real range returns trigger
    //! runtextmacro EVENT_CreateData()
    call TriggerRegisterUnitInRange(t,whichUnit,range,BOOLEXPR_TRUE)
    return t
endfunction

can become
JASS:
function TriggerRegisterUnitInRangeEventEx takes unit whichUnit, real range, boolexpr filter returns trigger
    local Data d = Data.create()
    local trigger t = CreateTrigger()
    call SetCSData(t,d)
    set d.whichUnit = whichUnit
    call TriggerRegisterUnitInRange (t, whichUnit, filter)
    return t
endfunction

function TriggerRegisterUnitEnterRangeEvent takes unit whichUnit, real range returns trigger
  return TriggerRegisterUnitInRangeEventEx (whichUnit, range, BOOLEXPR_TRUE)
endfunction


Also, why is Data public? It doesn't need to be, and you're practically begging someone to break stuff :p
 

Dr.Jack

That's Cap'n to you!
Reaction score
109
This a cool system! However may I ask what is the difference between this system and simply attaching the unit to the trigger?
 

Trollvottel

never aging title
Reaction score
262
this actually attaches the unit to the trigger. but it makes it easier for the user. So if you are not so expierienced in triggering, it makes everything simpler. however, there should be a possibility to clear the trigger if you dont want to use it any longer, for example

ReleaseTrigger, ClearTrigger, CleanTrigger. So you can do clearing and destroying in one step.
 

Darthfett

Aerospace/Cybersecurity Software Engineer
Reaction score
615
Hmmmm... what's so useful about this over just using TriggerRegisterUnitInRange (or whatever the native is called)? There's nothing in particular I can see about this that can't be done with the native and pretty much any struct attachment system. If you could do it without requiring dynamic triggers and guarantee the correct GetCenterUnit, then it'd be awesome, but otherwise I think it's just a bulky version of TriggerRegisterUnitInRange.

This is the native with a struct attachment system. The native itself only gives you two Event Response functions: GetTriggerUnit() and GetEnteringUnit() [Same unit], and GetTriggeringTrigger(). I have to attach to one of these two, and it can't work with GetEnteringUnit().

The trigger is the only other way to do it, and since I'm not using gamecache (string keys would allow attaching multiple units to a single trigger), I have to attach the struct to the trigger.

I've needed an Event Response function like "GetCenterUnit()" before, since it allows you to use it in conditions. (Sometimes you don't want any triggers to fire when the center unit is dead).

Also:
JASS:
//! textmacro EVENT_CreateData
    local Data d = Data.create()
    local trigger t = CreateTrigger()
    call SetCSData(t,d)
    set d.whichUnit = whichUnit
//! endtextmacro

function TriggerRegisterUnitEnterRangeEventEx takes unit whichUnit, real range, boolexpr filter returns trigger
    //! runtextmacro EVENT_CreateData()
    call TriggerRegisterUnitInRange(t,whichUnit,range,filter)
    return t
endfunction

function TriggerRegisterUnitEnterRangeEvent takes unit whichUnit, real range returns trigger
    //! runtextmacro EVENT_CreateData()
    call TriggerRegisterUnitInRange(t,whichUnit,range,BOOLEXPR_TRUE)
    return t
endfunction

can become
JASS:
function TriggerRegisterUnitInRangeEventEx takes unit whichUnit, real range, boolexpr filter returns trigger
    local Data d = Data.create()
    local trigger t = CreateTrigger()
    call SetCSData(t,d)
    set d.whichUnit = whichUnit
    call TriggerRegisterUnitInRange (t, whichUnit, filter)
    return t
endfunction

function TriggerRegisterUnitEnterRangeEvent takes unit whichUnit, real range returns trigger
  return TriggerRegisterUnitInRangeEventEx (whichUnit, range, BOOLEXPR_TRUE)
endfunction

I made the textmacro to reduce the size of the code, and to avoid creating a BJ. There's only a few things in the code that you actually need, but I added the extra function and boolexpr so it could work the same as TriggerRegisterUnitInRangeSimple.

Also, why is Data public? It doesn't need to be, and you're practically begging someone to break stuff :p

That's very true. :p I'll fix it in a min.

there should be a possibility to clear the trigger if you dont want to use it any longer, for example

ReleaseTrigger, ClearTrigger, CleanTrigger. So you can do clearing and destroying in one step.

I thought about it, but I've heard a lot of bad things about using DestroyTrigger. I didn't want to add in anything that could potentially lead to problems. I will add it in so that you can remove the trigger off the unit.
 

Flare

Stops copies me!
Reaction score
662
This is the native with a struct attachment system
Well, if someone uses another system (such as ABC, HAIL, HSAS, or a self-made system), it just becomes a pain to have to import CSData for the sake of something you could've done yourself.

I've needed an Event Response function like "GetCenterUnit()" before, since it allows you to use it in conditions.
Well, you don't need a whole system for that when you could just pass a unit using a struct as you would normally do, which is still usable in conditions.

I made the textmacro to reduce the size of the code, and to avoid creating a BJ
Just have one function and allow people to specify a null argument for the filter. If null is specified, set the filter to Condition (function FILTER_True), then you have one function, no BJ-esque function, no null boolexpr leak (since you would be replacing the null with a valid filter), no need for a macro that's not exactly a gigantic help anyway.
 

Darthfett

Aerospace/Cybersecurity Software Engineer
Reaction score
615
Well, if someone uses another system (such as ABC, HAIL, HSAS, or a self-made system), it just becomes a pain to have to import CSData for the sake of something you could've done yourself.

CSData is very lightweight, even if is a bit unsafe with some types. This is a system for a person who does not understand JASS all that well. I'll admit it would be a pain to have to import CSData (and now PUI), just for this, but don't you think it's better to have a premade system like this, than have to start from scratch?

Well, you don't need a whole system for that when you could just pass a unit using a struct as you would normally do, which is still usable in conditions.

Then you would have to create another system which passed the unit as a struct -- something which I'm doing here. With this system, you can simply run the function which creates the trigger&event, and add your Conditions/Actions.

The system is created for someone new to (v)JASS, not someone who already knows all about attaching and structs.

Just have one function and allow people to specify a null argument for the filter. If null is specified, set the filter to Condition (function FILTER_True), then you have one function, no BJ-esque function, no null boolexpr leak (since you would be replacing the null with a valid filter), no need for a macro that's not exactly a gigantic help anyway.

Good idea. :D I'll add it in.

Another point of the macro was to make it so I could modify one function, and change the other as well.
 

Prometheus

Everything is mutable; nothing is sacred
Reaction score
590
Good job making such an uber thing.
Wish it made cookies that come out of my usb ports though, only con with it.
 

Darthfett

Aerospace/Cybersecurity Software Engineer
Reaction score
615
Still awaiting approval, or more comments. Thanks!

EDIT:

I also optimized the GetCenterUnit function so it will get inlined, and made the filterfunc a constant function.

EDIT2:

Also removed the filter "Return true" type functions, and replaced them with the boolexprs in the BoolexprUtils system.
 

Ryuu

I am back with Chocolate (:
Reaction score
64
First it only requires CSData and PUI, but now it requires an additional BoolexprUtils.
But in your documentation you only wrote 'Requires CSData and PUI'.
 

Renendaru

(Evol)ution is nothing without love.
Reaction score
309
Don't know if it's required, but could you post a demo map?
 

UndeadDragon

Super Moderator
Reaction score
447
This is a very useful system. I have come across this problem many times before and I just had to change my idea. Now, I will have to try and remember some of those ideas :)
 

Renendaru

(Evol)ution is nothing without love.
Reaction score
309
I was thinking he should post a demo map, so some people won't have to go dl CS and have to go through the trouble of removing CSData and the functions that accompany it. (This took me half an hour to fix)
 

Troll-Brain

You can change this now in User CP.
Reaction score
85
The requirement of PUI and Cs_Data is annoying imho.
Also i would allow the user to add more than one event for the same trigger.
 
General chit-chat
Help Users
  • No one is chatting at the moment.
  • Monovertex Monovertex:
    How are you all? :D
    +1
  • Ghan Ghan:
    Howdy
  • Ghan Ghan:
    Still lurking
    +3
  • The Helper The Helper:
    I am great and it is fantastic to see you my friend!
    +1
  • The Helper The Helper:
    If you are new to the site please check out the Recipe and Food Forum https://www.thehelper.net/forums/recipes-and-food.220/
  • Monovertex Monovertex:
    How come you're so into recipes lately? Never saw this much interest in this topic in the old days of TH.net
  • Monovertex Monovertex:
    Hmm, how do I change my signature?
  • tom_mai78101 tom_mai78101:
    Signatures can be edit in your account profile. As for the old stuffs, I'm thinking it's because Blizzard is now under Microsoft, and because of Microsoft Xbox going the way it is, it's dreadful.
  • The Helper The Helper:
    I am not big on the recipes I am just promoting them - I use the site as a practice place promoting stuff
    +2
  • Monovertex Monovertex:
    @tom_mai78101 I must be blind. If I go on my profile I don't see any area to edit the signature; If I go to account details (settings) I don't see any signature area either.
  • The Helper The Helper:
    You can get there if you click the bell icon (alerts) and choose preferences from the bottom, signature will be in the menu on the left there https://www.thehelper.net/account/preferences
  • The Helper The Helper:
    I think I need to split the Sci/Tech news forum into 2 one for Science and one for Tech but I am hating all the moving of posts I would have to do
  • The Helper The Helper:
    What is up Old Mountain Shadow?
  • The Helper The Helper:
    Happy Thursday!
  • Varine Varine:
    Crazy how much 3d printing has come in the last few years. Sad that it's not as easily modifiable though
  • Varine Varine:
    I bought an Ender 3 during the pandemic and tinkered with it all the time. Just bought a Sovol, not as easy. I'm trying to make it use a different nozzle because I have a fuck ton of Volcanos, and they use what is basically a modified volcano that is just a smidge longer, and almost every part on this thing needs to be redone to make it work
  • Varine Varine:
    Luckily I have a 3d printer for that, I guess. But it's ridiculous. The regular volcanos are 21mm, these Sovol versions are about 23.5mm
  • Varine Varine:
    So, 2.5mm longer. But the thing that measures the bed is about 1.5mm above the nozzle, so if I swap it with a volcano then I'm 1mm behind it. So cool, new bracket to swap that, but THEN the fan shroud to direct air at the part is ALSO going to be .5mm to low, and so I need to redo that, but by doing that it is a little bit off where it should be blowing and it's throwing it at the heating block instead of the part, and fuck man
  • Varine Varine:
    I didn't realize they designed this entire thing to NOT be modded. I would have just got a fucking Bambu if I knew that, the whole point was I could fuck with this. And no one else makes shit for Sovol so I have to go through them, and they have... interesting pricing models. So I have a new extruder altogether that I'm taking apart and going to just design a whole new one to use my nozzles. Dumb design.
  • Varine Varine:
    Can't just buy a new heatblock, you need to get a whole hotend - so block, heater cartridge, thermistor, heatbreak, and nozzle. And they put this fucking paste in there so I can't take the thermistor or cartridge out with any ease, that's 30 dollars. Or you can get the whole extrudor with the direct driver AND that heatblock for like 50, but you still can't get any of it to come apart
  • Varine Varine:
    Partsbuilt has individual parts I found but they're expensive. I think I can get bits swapped around and make this work with generic shit though

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top