Snippet Transport (Enter/Leave Detection)

Jesus4Lyf

Good Idea™
Reaction score
397
Transport​
Version 1.02​

Requirements:
- Jass NewGen
- AIDS
- Event

Code:
JASS:
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//  ~~    Transport     ~~    By Jesus4Lyf    ~~    Version 1.02    ~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//  What is Transport?
//         - Transport provides Events for transport in Warcraft III.
//         - It also tracks what transportation unit a unit is in, and
//           can iterate over all units a transport unit is carrying.
//
//  Functions:
//         - Transport_RegisterLoadEvent(trigger)
//           Registers when a unit enters a transport. Within this:
//            - Use GetTriggerUnit() to refer to the passenger.
//            - Use GetTransportUnit() to refer to the transport.
//
//         - Transport_RegisterUnloadEvent(trigger)
//           Registers when a unit leaves a transport. Within this:
//            - Use GetUnloadedUnit() to refer to the passenger.
//            - Use GetUnloadingTransport() to refer to the transport.
//
//         - Transport_GetCarrier(passenger unit)
//           Returns the transport the unit has currently boarded.
//
//         - Transport_ForPassengers(transport unit, callback function)
//           Calls a ForGroup using the units on board as the group. Within this:
//            - Use GetEnumUnit() to refer to each unit on board.
//
//         - Transport_CountPassengers(transport unit)
//           Returns the number of units on board a transport unit.
//
//  Details:
//         - Unloading is detected by setting a unit's position to outside
//           the map when it is loaded into transport, and then registering when
//           it enters the map again, meaning it was unloaded.
//
//         - The purpose of the Load event is that it fires when the unit's x/y
//           coordinates are correct, but the state of Transport has been updated
//           (so Transport_GetCarrier and Transport_ForPassengers will work correctly).
//
//  How to import:
//         - Create a trigger named Transport.
//         - Convert it to custom text and replace the whole trigger text with this.
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
library Transport uses AIDS, Event, optional Recycle, optional GroupUtils
    globals
        private Event LoadEvent
        private Event UnloadEvent
        private real MAX_X
        private real MAX_Y
    endglobals
    public function RegisterLoadEvent takes trigger t returns EventReg
        return LoadEvent.register(t)
    endfunction
    public function RegisterUnloadEvent takes trigger t returns EventReg
        return UnloadEvent.register(t)
    endfunction
    
    // Group recycling stuff, if available.
    //! textmacro Transport__GetGroup takes VAR
        static if LIBRARY_Recycle then
            call Group.release($VAR$)
        elseif LIBRARY_GroupUtils then
            call ReleaseGroup($VAR$)
        else
            call DestroyGroup($VAR$) // never had enums called.
            set $VAR$=null
        endif
    //! endtextmacro
    //! textmacro Transport__ReleaseGroup takes VAR
        static if LIBRARY_Recycle then
            set $VAR$=Group.get()
        elseif LIBRARY_GroupUtils then
            set $VAR$=NewGroup()
        else
            set $VAR$=CreateGroup()
        endif
    //! endtextmacro
    
    // Data for system
    private struct Data extends array
        // Transport
        group carrying
        integer passengerCount
        // Passenger
        thistype carriedBy
        private static method unloadEnum takes nothing returns nothing
            set thistype[GetEnumUnit()].carriedBy=thistype(0)
        endmethod
        private method AIDS_onDestroy takes nothing returns nothing
            // Transport
            if this.carrying!=null then
                call ForGroup(this.carrying,function thistype.unloadEnum)
                //! runtextmacro Transport__ReleaseGroup("this.carrying")
            endif
            set this.passengerCount=0
            
            // Passenger
            set this.carriedBy=thistype(0)
        endmethod
        //! runtextmacro AIDS()
    endstruct
    public function GetCarrier takes unit passenger returns unit
        return Data[passenger].carriedBy.unit
    endfunction
    public function ForPassengers takes unit transport, code callback returns nothing
        call ForGroup(Data[transport].carrying,callback)
    endfunction
    public function CountPassengers takes unit transport returns integer
        return Data[transport].passengerCount
    endfunction
    
    // Stack for event responses, with recursion safety.
    private module Stack
        static thistype top=0 // thistype(0) throws a syntax error, does not compile
        static method increment takes nothing returns nothing
            set thistype.top=thistype(thistype.top+1)
        endmethod
        static method decrement takes nothing returns nothing
            set thistype.top=thistype(thistype.top-1)
        endmethod
    endmodule
    
    // Event responses for UnloadEvent.
    private struct UnloadStack extends array
        implement Stack
        unit transport
        unit passenger
    endstruct
    function GetUnloadingTransport takes nothing returns unit
        return UnloadStack.top.transport
    endfunction
    function GetUnloadedUnit takes nothing returns unit
        return UnloadStack.top.passenger
    endfunction
    
    // When a unit enters world boundaries...
    globals//locals
        private unit EnteringUnit
        private Data EnteringData
        private Data EnteringTransportData
    endglobals
    private function OnEnterWorld takes nothing returns boolean
        set EnteringUnit=GetFilterUnit()
        set EnteringData=Data[EnteringUnit]
        if EnteringData.carriedBy!=null then // Unit was unloaded.
            
            call UnloadStack.increment()
            set EnteringTransportData=EnteringData.carriedBy
            set UnloadStack.top.transport=EnteringTransportData.unit
            set UnloadStack.top.passenger=EnteringUnit
            
            call GroupRemoveUnit(EnteringTransportData.carrying,EnteringUnit)
            set EnteringTransportData.passengerCount=EnteringTransportData.passengerCount-1
            set EnteringData.carriedBy=Data(0)
            
            // Global locals unsafe from this point on
            call UnloadEvent.fire()
            call UnloadStack.decrement()
            
        endif
        return false
    endfunction
    
    // When a unit enters a transport...
    globals//locals
        private unit LoadedUnit
        private Data LoadingData
    endglobals
    private function OnLoad takes nothing returns boolean
        set LoadedUnit=GetTriggerUnit()
        set LoadingData=Data[GetTransportUnit()]
        if LoadingData.carrying==null then
            //! runtextmacro Transport__GetGroup("LoadingData.carrying")
        endif
        call GroupAddUnit(LoadingData.carrying,LoadedUnit)
        set LoadingData.passengerCount=LoadingData.passengerCount+1
        set Data[LoadedUnit].carriedBy=LoadingData
        call LoadEvent.fire()
        call SetUnitX(LoadedUnit,MAX_X)
        call SetUnitY(LoadedUnit,MAX_Y)
        return false
    endfunction
    
    // Init.
    private struct Initializer extends array
        private static method onInit takes nothing returns nothing
            local trigger t
            local rect r=GetWorldBounds()
            local region g=CreateRegion()
            call RegionAddRect(g,r)
            set MAX_X=GetRectMaxX(r)
            set MAX_Y=GetRectMaxY(r)
            call RemoveRect(r)
            set r=null
            
            set LoadEvent=Event.create()
            set UnloadEvent=Event.create()
            
            // On transport load.
            set t=CreateTrigger()
            call TriggerAddCondition(t,Filter(function OnLoad))
            call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_LOADED)
            
            // On enter world.
            // Reuse previous trigger:
            call TriggerRegisterEnterRegion(t,g,Filter(function OnEnterWorld))
            
            set t=null
            set g=null
        endmethod
    endstruct
endlibrary
This snippet detects when a unit leaves a transport, and fires an Event. It also contains functions for iterating over all units in a transport unit, and for getting what transport unit a unit has currently boarded.

Example:
JASS:
scope TransportDemo initializer OnInit
    private function OnLoad takes nothing returns boolean
        call BJDebugMsg(GetUnitName(GetTransportUnit())+" loaded "+GetUnitName(GetTriggerUnit()))
        call BJDebugMsg("at ("+R2S(GetUnitX(GetTriggerUnit()))+", "+R2S(GetUnitY(GetTriggerUnit()))+").")
        return false
    endfunction
    
    private function OnUnload takes nothing returns boolean
        call BJDebugMsg(GetUnitName(GetUnloadingTransport())+" unloaded "+GetUnitName(GetUnloadedUnit()))
        call BJDebugMsg("at ("+R2S(GetUnitX(GetUnloadedUnit()))+", "+R2S(GetUnitY(GetUnloadedUnit()))+").")
        return false
    endfunction
    
    private function OnInit takes nothing returns nothing
        local trigger t=CreateTrigger()
        call Transport_RegisterLoadEvent(t)
        call TriggerAddCondition(t,Filter(function OnLoad))
        
        set t=CreateTrigger()
        call Transport_RegisterUnloadEvent(t)
        call TriggerAddCondition(t,Filter(function OnUnload))
    endfunction
endscope

Updates:
- Version 1.02: Fixed Recycle usage (it didn't implement Recycle even if it was available).
- Version 1.01: Fixed the event response stack not decrementing, and added Transport_CountPassengers(transport unit) function.
- Version 1.00: Release.
 

Attachments

  • Transport.w3x
    40.3 KB · Views: 419

Jesus4Lyf

Good Idea™
Reaction score
397
>Does this really work?
Yes. :D

>Is there any kind of delay?
No. :D

It does not use a periodic timer or anything, it's all O(1) complexity and quick and nice to use.

I have tested it for KillUnit while a unit is in transport, it detects it and fires the unload event, same for RemoveUnit.
Also, unlike StatusEvent at this time, pausing a unit that is on a transport and then unloading it will actually fire the Unload event. :p
 

Kenny

Back for now.
Reaction score
202
Awesomes stuff. Efficient as always.

One thing though. Last I heard from Vex, the use of elseif within static ifs still isn't supported.

Found the post. (There have been no updates to static ifs since that post that I am aware of)

Oh and:

I have tested it for KillUnit while a unit is in transport, it detects it and fires the unload event, same for RemoveUnit.
Also, unlike StatusEvent at this time, pausing a unit that is on a transport and then unloading it will actually fire the Unload event.

Impressive. :D
 

Jesus4Lyf

Good Idea™
Reaction score
397
>Awesomes stuff. Efficient as always.
Thanks. :D
One thing though. Last I heard from Vex, the use of elseif within static ifs still isn't supported.
Um. Seems to compile fine. Tried using it with Recycle and GroupUtils, putting syntax errors in the appropriate lines to see if they errored. They did...
 

Kenny

Back for now.
Reaction score
202
Oh awesome. Well then... I have nothing more to say, this seems pretty damn good. Quite handy for RPG type maps that use zeplins and stuff to get around.

+rep if I can.

Grrr, still can't +rep. You will get some soon though.
 

Lyerae

I keep popping up on this site from time to time.
Reaction score
105
Awesome. I'll be using this. +rep

> it's all O(1)
Huh? :nuts:
 

Nestharus

o-o
Reaction score
84
Great resource!


Adding new functionality to getting states of regular warcraft 3 operations is always a major plus ; D (stuff that shoulda been included in JASS but wasn't ;o)
 

Jesus4Lyf

Good Idea™
Reaction score
397
I totally agree, but his is broken. It relies on undefend, and units can be issued undefend orders while in transport, triggering his unload event, and units can be unloaded without having the undefend order issued by being paused, which does not trigger his unload event. Therefore, this method is nicer, imho (I should mention that setting x/y with this for a unit in transport (??) would probably fire the unload event, though).

It's not so much a war as an inconvenient ban. When I find bugs in wc3c systems I have to then make my own, as I can't report them. So whatever.
 
Reaction score
341
It's not so much a war as an inconvenient ban. When I find bugs in wc3c systems I have to then make my own, as I can't report them. So whatever.

Unless it requires a total rewrite of the system, wouldn't it be easier to just ask someone to report the bugs for you?
 

Jesus4Lyf

Good Idea™
Reaction score
397
Unless it requires a total rewrite of the system, wouldn't it be easier to just ask someone to report the bugs for you?
No. Well firstly, this did require a rewrite of the system. Secondly, if I used StatusEvent, I'd need to use AutoIndex, which means no AIDS structs (I could probably make this optionally require AutoIndex instead, btw). Thirdly, it is absolutely faster to write it myself. :)

Edit: Here's an example. There is a JassHelper bug. Has anyone reported that on wc3c for me yet? Lol. I have expressed before that I'd like to contribute on wc3c, but apparently an old personal issue is worth dividing the mapping community.
 
General chit-chat
Help Users
  • No one is chatting at the moment.
  • The Helper The Helper:
    The bots will show up as users online in the forum software but they do not show up in my stats tracking. I am sure there are bots in the stats but the way alot of the bots treat the site do not show up on the stats
  • Varine Varine:
    I want to build a filtration system for my 3d printer, and that shit is so much more complicated than I thought it would be
  • Varine Varine:
    Apparently ABS emits styrene particulates which can be like .2 micrometers, which idk if the VOC detectors I have can even catch that
  • Varine Varine:
    Anyway I need to get some of those sensors and two air pressure sensors installed before an after the filters, which I need to figure out how to calculate the necessary pressure for and I have yet to find anything that tells me how to actually do that, just the cfm ratings
  • Varine Varine:
    And then I have to set up an arduino board to read those sensors, which I also don't know very much about but I have a whole bunch of crash course things for that
  • Varine Varine:
    These sensors are also a lot more than I thought they would be. Like 5 to 10 each, idk why but I assumed they would be like 2 dollars
  • Varine Varine:
    Another issue I'm learning is that a lot of the air quality sensors don't work at very high ambient temperatures. I'm planning on heating this enclosure to like 60C or so, and that's the upper limit of their functionality
  • Varine Varine:
    Although I don't know if I need to actually actively heat it or just let the plate and hotend bring the ambient temp to whatever it will, but even then I need to figure out an exfiltration for hot air. I think I kind of know what to do but it's still fucking confusing
  • The Helper The Helper:
    Maybe you could find some of that information from AC tech - like how they detect freon and such
  • Varine Varine:
    That's mostly what I've been looking at
  • Varine Varine:
    I don't think I'm dealing with quite the same pressures though, at the very least its a significantly smaller system. For the time being I'm just going to put together a quick scrubby box though and hope it works good enough to not make my house toxic
  • Varine Varine:
    I mean I don't use this enough to pose any significant danger I don't think, but I would still rather not be throwing styrene all over the air
  • The Helper The Helper:
    New dessert added to recipes Southern Pecan Praline Cake https://www.thehelper.net/threads/recipe-southern-pecan-praline-cake.193555/
  • The Helper The Helper:
    Another bot invasion 493 members online most of them bots that do not show up on stats
  • Varine Varine:
    I'm looking at a solid 378 guests, but 3 members. Of which two are me and VSNES. The third is unlisted, which makes me think its a ghost.
    +1
  • The Helper The Helper:
    Some members choose invisibility mode
    +1
  • The Helper The Helper:
    I bitch about Xenforo sometimes but it really is full featured you just have to really know what you are doing to get the most out of it.
  • The Helper The Helper:
    It is just not easy to fix styles and customize but it definitely can be done
  • The Helper The Helper:
    I do know this - xenforo dropped the ball by not keeping the vbulletin reputation comments as a feature. The loss of the Reputation comments data when we switched to Xenforo really was the death knell for the site when it came to all the users that left. I know I missed it so much and I got way less interested in the site when that feature was gone and I run the site.
  • Blackveiled Blackveiled:
    People love rep, lol
    +1
  • The Helper The Helper:
    The recipe today is Sloppy Joe Casserole - one of my faves LOL https://www.thehelper.net/threads/sloppy-joe-casserole-with-manwich.193585/
  • The Helper The Helper:
    Decided to put up a healthier type recipe to mix it up - Honey Garlic Shrimp Stir-Fry https://www.thehelper.net/threads/recipe-honey-garlic-shrimp-stir-fry.193595/
  • The Helper The Helper:
    Here is another comfort food favorite - Million Dollar Casserole - https://www.thehelper.net/threads/recipe-million-dollar-casserole.193614/

      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