System Unit Indexer

Nestharus

o-o
Reaction score
84
Map Includes
  • Required Resources
  • Installation Script + Instructions
  • Installation Objects + Instructions
  • Resource
  • Test Cases
  • Tutorials/Labs
Required resources can also be found on github

Best thing to do is to just go through the tutorials/labs.

This can't be compared to any previous Unit Indexer. This was made possible by Trigger.

Unit Indexer Main
JASS:
library UnitIndexer /* v5.1.0.1
************************************************************************************
*
* */ uses /*
*
* */ WorldBounds /*
* */ Init /*
* */ AllocQ /*
* */ ErrorMessage /*
* */ StaticUniqueList /*
* */ UnitIndexerSettings /*
* */ Trigger /*
*
********************************************************************************
*
* struct UnitIndexer extends array
*
* Fields
* -------------------------
*
* static boolean enabled
* - is UnitIndexer onUnitIndex enabled?
*
* readonly static Trigger GlobalEvent.ON_INDEX
* - this is a global event that runs whenever any unit is indexed
*
* Examples: UnitIndexer.GlobalEvent.ON_INDEX.reference(yourTrigger)
* UnitIndexer.GlobalEvent.ON_INDEX.register(yourCode)
*
* Examples: unitIndex.indexer.Event.ON_DEINDEX.reference(yourTrigger)
* unitIndex.indexer.Event.ON_DEINDEX.register(yourCode)
*
* readonly static Trigger GlobalEvent.ON_DEINDEX
* - this is ON_DEINDEX, but global
* - this runs after unit specific deindex events
*
* Examples: UnitIndexer.GlobalEvent.ON_DEINDEX.reference(yourTrigger)
* UnitIndexer.GlobalEvent.ON_DEINDEX.register(yourCode)
*
* readonly static UnitIndex eventIndex
* - when a unit is indexed or deindexed, this value stores
* the index of that unit
*
* readonly static unit eventUnit
* - when a unit is indexed or deindexed, this value stores
* the unit
*
************************************************************************************
*
* struct UnitIndex extends array
*
* Fields
* -------------------------
*
* readonly unit unit
* - converts a unit index into a unit
*
* readonly UnitIndexer indexer
* - the indexer in charge of handling the unit
* useful for deindex event, which is unit specific
*
* Operators
* -------------------------
*
* static method operator [] takes unit whichUnit returns UnitIndex
* - converts a unit into a UnitIndex
*
* Methods
* -------------------------
*
* static method exists takes unit whichUnit returns boolean
* - determines whether the unit is indexed or not
*
* static method isDeindexing takes unit whichUnit returns boolean
* - determines whether the unit is in the process of being deindexed or not
*
************************************************************************************
*
* module UnitIndex
*
* If you would like to create modules that work off of the UnitIndex module, implement
* UnitIndex at the top of your module
*
* Fields
* -------------------------
*
* static constant boolean UNIT_INDEX = true
* - this is used to make sure that only either UnitIndex or UnitIndexEx
* implemented.
*
* static boolean enabled
* - is this UnitIndex struct enabled?
* - this can only be disabed if onUnitIndex exists
*
* readonly unit unit
* - converts a unit index into a unit
*
* readonly boolean isUnitIndexed
* - is the unit index indexed for the struct?
*
* readonly UnitIndexer unitIndexer
* - the indexer in charge of handling the unit
* useful for deindex event, which is unit specific
*
* Operators
* -------------------------
*
* static method operator [] takes unit whichUnit returns thistype
* - converts a unit into thistype
*
* Methods
* -------------------------
*
* static method exists takes unit whichUnit returns boolean
* - determines whether the unit is indexed or not for the struct
*
* static method isDeindexing takes unit whichUnit returns boolean
* - determines whether the unit is in the process of being deindexed or not
*
* Interface
* -------------------------
*
* interface private method onUnitIndex takes nothing returns boolean
* - if return true, index the unit for this struct
*
* interface private method onUnitDeindex takes nothing returns nothing
* - only runs for units indexed for this struct
* - if not onUnitIndex method is declared, it will run for all units
*
************************************************************************************
*
* module UnitIndexEx
*
* If you would like to create modules that work off of the UnitIndex module, implement
* UnitIndex at the top of your module
*
* Fields
* -------------------------
*
* static constant boolean UNIT_INDEX_EX = true
* - this is used for modules that rely on local events
* it allows these modules to differentiate between UnitIndex
* and UnitIndexEx
*
* static boolean enabled
* - is this UnitIndex struct enabled?
* - this can only be disabed if onUnitIndex exists
*
* readonly unit unit
* - converts a unit index into a unit
*
* readonly boolean isUnitIndexed
* - is the unit index indexed for the struct?
*
* readonly UnitIndexer unitIndexer
* - the indexer in charge of handling the unit
* useful for deindex event, which is unit specific
*
* readonly static Trigger ON_INDEX
* - this is a local event that runs whenever any unit is indexed for the struct
* - this is primarily used for other resources that work off of your struct
*
* Examples: Struct.ON_INDEX.reference(yourTrigger)
* Struct.ON_INDEX.register(yourCode)
*
* readonly Trigger Event.ON_DEINDEX
* readonly static Trigger Event.ON_DEINDEX
* - this is a unit specific event that runs when your local unit is deindexed
* - this is static if onUnitIndex does not exist
*
* Examples: struct.ON_DEINDEX.reference(yourTrigger)
* struct.ON_DEINDEX.register(yourCode)
*
* Operators
* -------------------------
*
* static method operator [] takes unit whichUnit returns thistype
* - converts a unit into thistype
*
* Methods
* -------------------------
*
* static method exists takes unit whichUnit returns boolean
* - determines whether the unit is indexed or not for the struct
*
* static method isDeindexing takes unit whichUnit returns boolean
* - determines whether the unit is in the process of being deindexed or not
*
* Interface
* -------------------------
*
* interface private method onUnitIndex takes nothing returns boolean
* - if return true, index the unit for this struct
*
* interface private method onUnitDeindex takes nothing returns nothing
* - only runs for units indexed for this struct
* - if not onUnitIndex method is declared, it will run for all units
*
************************************************************************************
*
* //! textmacro CREATE_LOCAL_UNIT_INDEX
*
* A macro was chosen because multiple modules utilizing this code may be
* implemented into one struct. If this was a module, then all but one
* of those modules would break.
*
* Interface
* -------------------------
*
* interface private method onLocalUnitIndex takes nothing returns nothing
* - runs whenever a unit is indexed for this struct
*
* interface private method onLocalUnitDeindex takes nothing returns nothing
* - runs whenever a unit is deindexed for this struct
*
* interface private static method localInit takes nothing returns nothing
* - the macro requires the usage of onInit. Declare this method if you
* would like onInit.
*
************************************************************************************/
globals
private UnitIndex p_eventIndex = 0
endglobals
 
//! runtextmacro UNIT_INDEXER_UNIT_INDEX()
//! runtextmacro UNIT_INDEXER_PREGAME_EVENT()
//! runtextmacro UNIT_INDEXER_UNIT_INDEXER()
 
module UnitIndex
static if not thistype.UNIT_INDEX_EX then
static constant boolean UNIT_INDEX = true
 
/*
* [] is included because the struct automatically overrides it
*
* eventIndex is included to return thistype instead of UnitIndex
*/
static method operator [] takes unit whichUnit returns thistype
return UnitIndex[whichUnit]
endmethod
method operator unitIndexer takes nothing returns UnitIndexer
return this
endmethod
method operator unit takes nothing returns unit
return UnitIndex(this).unit
endmethod
 
static method isDeindexing takes unit whichUnit returns boolean
return UnitIndex.isDeindexing(whichUnit)
endmethod
 
/*
* the method is done in the second case because when there is no
* onUnitIndex method, indexed depends on whether the actual
* instance is allocated or not
*/
static if thistype.onUnitIndex.exists then
readonly boolean isUnitIndexed
else
method operator isUnitIndexed takes nothing returns boolean
return p_UnitIndex(this).isAllocated
endmethod
endif
 
static if thistype.onUnitIndex.exists then
static method exists takes unit whichUnit returns boolean
return UnitIndex.exists(whichUnit) and thistype(GetUnitUserData(whichUnit)).isUnitIndexed
endmethod
else
static method exists takes unit whichUnit returns boolean
return UnitIndex.exists(whichUnit)
endmethod
endif
 
/*
* this is used to run local events
*/
static if thistype.onUnitIndex.exists then
/*
* this is where UnitIndex is located
*/
private static TriggerCondition entryPoint
 
/*
* this stores private onUnitIndex method
*/
private static boolexpr onIndexExpression
 
/*
* enable works with code inside of entryPoint here
*/
private static boolean p_enabled = true
static method operator enabled takes nothing returns boolean
return p_enabled
endmethod
static method operator enabled= takes boolean enable returns nothing
set p_enabled = enable
 
if (enable) then
call entryPoint.replace(onIndexExpression)
else
call entryPoint.replace(null)
endif
endmethod
else
/*
* if onUnitIndex does not exist, the struct can't be disabled
*/
static method operator enabled takes nothing returns boolean
return true
endmethod
static method operator enabled= takes boolean enable returns nothing
set enable = true
endmethod
endif
 
/*
* onUnitDeindex
*
* This must be implemented if onUnitIndex exists to clear isUnitIndexed
*/
static if thistype.onUnitDeindex.exists then
static if thistype.onUnitIndex.exists then
private static boolexpr onDeindexExpression
endif
 
private static method onDeindexEvent takes nothing returns boolean
call thistype(UnitIndexer.eventIndex).onUnitDeindex()
 
static if thistype.onUnitIndex.exists then
set thistype(UnitIndexer.eventIndex).isUnitIndexed = false
endif
 
return false
endmethod
elseif thistype.onUnitIndex.exists then
static if thistype.onUnitIndex.exists then
private static boolexpr onDeindexExpression
endif
 
private static method onDeindexEvent takes nothing returns boolean
set thistype(UnitIndexer.eventIndex).isUnitIndexed = false
 
return false
endmethod
endif
 
/*
* onUnitIndex
*/
static if thistype.onUnitIndex.exists then
private static method onIndexEvent takes nothing returns boolean
if (thistype(UnitIndexer.eventIndex).onUnitIndex()) then
set thistype(UnitIndexer.eventIndex).isUnitIndexed = true
 
/*
* this is always registered to clear isUnitIndexed
*/
call UnitIndexer(UnitIndexer.eventIndex).Event.ON_DEINDEX.register(onDeindexExpression)
endif
 
return false
endmethod
endif
 
static if thistype.onUnitIndex.exists then
private static method onInit takes nothing returns nothing
set onIndexExpression = Condition(function thistype.onIndexEvent)
set onDeindexExpression = Condition(function thistype.onDeindexEvent)
 
set entryPoint = UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onIndexEvent))
endmethod
elseif thistype.onUnitDeindex.exists then
private static method onInit takes nothing returns nothing
call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onDeindexEvent))
endmethod
endif
endif
endmodule
 
private struct UnitIndexList extends array
//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "unitIndex2Node", "thistype")
//! runtextmacro CREATE_TABLE_FIELD("public", "integer", "node2UnitIndex", "thistype")
 
method add takes thistype index returns nothing
local thistype node = enqueue()
 
set node.node2UnitIndex = index
set index.unitIndex2Node = node
endmethod
 
method delete takes nothing returns nothing
call unitIndex2Node.remove()
endmethod
 
private static method init takes nothing returns nothing
//! runtextmacro INITIALIZE_TABLE_FIELD("unitIndex2Node")
//! runtextmacro INITIALIZE_TABLE_FIELD("node2UnitIndex")
endmethod
 
implement NxListT
implement Init
endstruct
private struct UnitIndexModuleTrigger extends array
method reference takes Trigger whichTrigger returns TriggerReference
local TriggerReference triggerReference = Trigger(this).reference(whichTrigger)
 
local UnitIndexList node = UnitIndexList(this).first
local integer prevIndexedUnitId = p_eventIndex
 
loop
exitwhen node == UnitIndexList.sentinel or not whichTrigger.enabled
 
set p_eventIndex = node.node2UnitIndex
call whichTrigger.fire()
 
set node = node.next
endloop
 
set p_eventIndex = prevIndexedUnitId
 
return triggerReference
endmethod
 
method register takes boolexpr whichExpression returns TriggerCondition
local TriggerCondition triggerCondition = Trigger(this).register(whichExpression)
 
local trigger triggerContainer = CreateTrigger()
 
local UnitIndexList node = UnitIndexList(this).first
local integer prevIndexedUnitId = p_eventIndex
 
call TriggerAddCondition(triggerContainer, whichExpression)
 
loop
exitwhen node == UnitIndexList.sentinel
 
set p_eventIndex = node.node2UnitIndex
call TriggerEvaluate(triggerContainer)
 
set node = node.next
endloop
 
call TriggerClearConditions(triggerContainer)
call DestroyTrigger(triggerContainer)
set triggerContainer = null
 
set p_eventIndex = prevIndexedUnitId
 
return triggerCondition
endmethod
endstruct
module UnitIndexEx
static if thistype.UNIT_INDEX then
private static method error takes nothing returns nothing
A module requires UnitIndexEx to operate correctly.
This struct is currently implementing UnitIndex.
endmethod
else
static constant boolean UNIT_INDEX_EX = true
 
private static UnitIndex delegate unitIndex = 0
 
/*
* [] is included because the struct automatically overrides it
*
* eventIndex is included to return thistype instead of UnitIndex
*/
static method operator [] takes unit whichUnit returns thistype
return UnitIndex[whichUnit]
endmethod
method operator unit takes nothing returns unit
return UnitIndex(this).unit
endmethod
method operator unitIndexer takes nothing returns UnitIndexer
return this
endmethod
 
static method isDeindexing takes unit whichUnit returns boolean
return UnitIndex.isDeindexing(whichUnit)
endmethod
 
/*
* the method is done in the second case because when there is no
* onUnitIndex method, indexed depends on whether the actual
* instance is allocated or not
*/
static if thistype.onUnitIndex.exists then
readonly boolean isUnitIndexed
else
method operator isUnitIndexed takes nothing returns boolean
return p_UnitIndex(this).isAllocated
endmethod
endif
 
static if thistype.onUnitIndex.exists then
static method exists takes unit whichUnit returns boolean
return UnitIndex.exists(whichUnit) and thistype(GetUnitUserData(whichUnit)).isUnitIndexed
endmethod
else
static method exists takes unit whichUnit returns boolean
return UnitIndex.exists(whichUnit)
endmethod
endif
 
/*
* this is used to run local events
*/
static if thistype.onUnitIndex.exists then
readonly static UnitIndexModuleTrigger ON_INDEX
else
readonly static WrappedTrigger ON_INDEX
endif
 
static if thistype.onUnitIndex.exists then
/*
* this is where UnitIndex is located
*/
private static TriggerCondition entryPoint
 
/*
* this stores private onUnitIndex method
*/
private static boolexpr onIndexExpression
 
/*
* enable works with code inside of entryPoint here
*/
private static boolean p_enabled = true
static method operator enabled takes nothing returns boolean
return p_enabled
endmethod
static method operator enabled= takes boolean enable returns nothing
set p_enabled = enable
 
if (enable) then
call entryPoint.replace(onIndexExpression)
else
call entryPoint.replace(null)
endif
endmethod
else
/*
* if onUnitIndex does not exist, the struct can't be disabled
*/
static method operator enabled takes nothing returns boolean
return true
endmethod
static method operator enabled= takes boolean enable returns nothing
set enable = true
endmethod
endif
 
/*
* this is here so that the module runs after code that relies on the module
*/
static if thistype.onUnitIndex.exists then
readonly Trigger ON_DEINDEX
else
readonly static Trigger ON_DEINDEX
endif
 
/*
* onUnitDeindex
*/
static if thistype.onUnitDeindex.exists then
static if thistype.onUnitIndex.exists then
private static boolexpr onDeindexExpression
endif
 
private static method onDeindexEvent takes nothing returns boolean
call thistype(UnitIndexer.eventIndex).onUnitDeindex()
 
static if thistype.onUnitIndex.exists then
set thistype(UnitIndexer.eventIndex).isUnitIndexed = false
 
call thistype(UnitIndexer.eventIndex).ON_DEINDEX.destroy()
 
if (not PreGameEvent.isGameLoaded) then
call UnitIndexList(UnitIndexer.eventIndex).delete()
endif
endif
 
return false
endmethod
elseif thistype.onUnitIndex.exists then
private static boolexpr onDeindexExpression
 
private static method onDeindexEvent takes nothing returns boolean
set thistype(UnitIndexer.eventIndex).isUnitIndexed = false
 
call thistype(UnitIndexer.eventIndex).ON_DEINDEX.destroy()
 
if (not PreGameEvent.isGameLoaded) then
call UnitIndexList(UnitIndexer.eventIndex).delete()
endif
 
return false
endmethod
endif
 
/*
* onUnitIndex
*/
static if thistype.onUnitIndex.exists then
private static method onIndexEvent takes nothing returns boolean
if (thistype(UnitIndexer.eventIndex).onUnitIndex()) then
set thistype(UnitIndexer.eventIndex).isUnitIndexed = true
 
set thistype(UnitIndexer.eventIndex).ON_DEINDEX = Trigger.create()
call UnitIndexer(UnitIndexer.eventIndex).Event.ON_DEINDEX.reference(thistype(UnitIndexer.eventIndex).ON_DEINDEX)
 
call UnitIndexer(UnitIndexer.eventIndex).Event.ON_DEINDEX.register(onDeindexExpression)
 
if (not PreGameEvent.isGameLoaded) then
call UnitIndexList(ON_INDEX).add(UnitIndexer.eventIndex)
endif
 
call Trigger(thistype.ON_INDEX).fire()
endif
 
return false
endmethod
endif
 
private static method destroyPregameUnitList takes nothing returns nothing
call DestroyTimer(GetExpiredTimer())
 
call UnitIndexList(ON_INDEX).destroy()
endmethod
 
private static method onInit takes nothing returns nothing
set ON_INDEX = Trigger.create()
 
static if thistype.onUnitIndex.exists then
set onIndexExpression = Condition(function thistype.onIndexEvent)
set onDeindexExpression = Condition(function thistype.onDeindexEvent)
 
call UnitIndexList(ON_INDEX).clear()
 
call TimerStart(CreateTimer(), 0, false, function thistype.destroyPregameUnitList)
 
set entryPoint = UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onIndexEvent))
else
set ON_DEINDEX = Trigger.create()
call UnitIndexer.GlobalEvent.ON_DEINDEX.reference(ON_DEINDEX)
 
static if thistype.onUnitDeindex.exists then
call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onDeindexEvent))
endif
 
call UnitIndexer.GlobalEvent.ON_INDEX.reference(ON_INDEX)
endif
endmethod
endif
endmodule
 
//! textmacro CREATE_LOCAL_UNIT_INDEX
/*
* There are three cases
*
* Case 1: UnitIndex is implemented
* Case 2: UnitIndexEx is implemented
* Case 3: Nothing is implemented, go to Case 2
*/
static if thistype.UNIT_INDEX then
/*
* Here, UnitIndex is implemented
*/
 
/*
* There are two cases
*
* onUnitEvent exists, which means that events are conditionally local
* onUnitEven does not exist, meaning all events are global
*/
static if thistype.onUnitIndex.exists then
/*
* Here, events are conditionally local
*/
 
static if thistype.onLocalUnitDeindex.exists then
private static boolexpr onLocalUnitDeindexEventExpr
endif
 
static if thistype.onLocalUnitIndex.exists then
/*
* The user has a local unit index event
*/
private static method onLocalUnitIndexEvent takes nothing returns boolean
/*
* Here, the event is only run if the unit happened to be indexed
*/
if (thistype(UnitIndexer.eventIndex).isUnitIndexed) then
static if thistype.onLocalUnitDeindex.exists then
call UnitIndexer.eventIndex.indexer.Event.ON_DEINDEX.register(onLocalUnitDeindexEventExpr)
endif
 
call thistype(UnitIndexer.eventIndex).onLocalUnitIndex()
endif
 
return false
endmethod
elseif thistype.onLocalUnitDeindex.exists then
/*
* The user did not declare a local unit index event
*
* onLocalUnitIndexEvent is still required because the deindex events are local
*/
private static method onLocalUnitIndexEvent takes nothing returns boolean
if (thistype(UnitIndexer.eventIndex).isUnitIndexed) then
call UnitIndexer.eventIndex.indexer.Event.ON_DEINDEX.register(onLocalUnitDeindexEventExpr)
endif
 
return false
endmethod
endif
 
static if thistype.onLocalUnitDeindex.exists then
private static method onLocalUnitDeindexEvent takes nothing returns boolean
call thistype(UnitIndexer.eventIndex).onLocalUnitDeindex()
return false
endmethod
endif
 
/*
* onLocalUnitDeindexEvent is not registered globally here because these are local
* events. It must be created inside of onLocalUnitIndexEvent whether or not
* onLocalUnitIndex exists.
*/
static if thistype.onLocalUnitIndex.exists then
private static method onInit takes nothing returns nothing
static if thistype.onLocalUnitDeindex.exists then
set onLocalUnitDeindexEventExpr = Condition(function thistype.onLocalUnitDeindexEvent)
endif
 
call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onLocalUnitIndexEvent))
 
static if thistype.localInit.exists then
call localInit()
endif
endmethod
elseif thistype.onLocalUnitDeindex.exists then
private static method onInit takes nothing returns nothing
set onLocalUnitDeindexEventExpr = Condition(function thistype.onLocalUnitDeindexEvent)
 
call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onLocalUnitIndexEvent))
 
static if thistype.localInit.exists then
call localInit()
endif
endmethod
endif
else
/*
* Here, all events are global
*/
static if thistype.onLocalUnitIndex.exists then
private static method onLocalUnitIndexEvent takes nothing returns boolean
call thistype(UnitIndexer.eventIndex).onLocalUnitIndex()
return false
endmethod
endif
 
static if thistype.onLocalUnitDeindex.exists then
private static method onLocalUnitDeindexEvent takes nothing returns boolean
call thistype(UnitIndexer.eventIndex).onLocalUnitDeindex()
return false
endmethod
endif
 
static if thistype.onLocalUnitIndex.exists then
private static method onInit takes nothing returns nothing
static if thistype.onLocalUnitDeindex.exists then
call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onLocalUnitDeindexEvent))
endif
 
call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onLocalUnitIndexEvent))
 
static if thistype.localInit.exists then
call localInit()
endif
endmethod
elseif thistype.onLocalUnitDeindex.exists then
private static method onInit takes nothing returns nothing
call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onLocalUnitDeindexEvent))
 
static if thistype.localInit.exists then
call localInit()
endif
endmethod
endif
endif
else
/*
* Here, UnitIndexEx is either implemented or nothing is implemented
*
* Implement UnitIndexEx and work with its local events
*/
implement UnitIndexEx
 
static if thistype.onUnitIndex.exists then
/*
* local events
*/
static if thistype.onLocalUnitDeindex.exists then
private static boolexpr onLocalUnitDeindexEventExpr
endif
 
/*
* if onUnitIndex exists, then onLocalUnitDeindex is local
*
* this means that if onLocalUnitDeindex exists, the onLocalUnitIndexEvent must be
* made so that it can register onLocalUnitDeindex locally
*/
static if thistype.onLocalUnitIndex.exists then
private static method onLocalUnitIndexEvent takes nothing returns boolean
static if thistype.onLocalUnitDeindex.exists then
call thistype(UnitIndexer.eventIndex).ON_DEINDEX.register(onLocalUnitDeindexEventExpr)
endif
 
call thistype(UnitIndexer.eventIndex).onLocalUnitIndex()
 
return false
endmethod
elseif thistype.onLocalUnitDeindex.exists then
private static method onLocalUnitIndexEvent takes nothing returns boolean
call thistype(UnitIndexer.eventIndex).ON_DEINDEX.register(onLocalUnitDeindexEventExpr)
 
return false
endmethod
endif
elseif thistype.onLocalUnitIndex.exists then
/*
* global events
*
* onLocalUnitDeindex is run globally, so it doesn't need onLocalUnitIndexEvent
* anymore
*/
private static method onLocalUnitIndexEvent takes nothing returns boolean
call thistype(UnitIndexer.eventIndex).onLocalUnitIndex()
 
return false
endmethod
endif
 
static if thistype.onLocalUnitDeindex.exists then
private static method onLocalUnitDeindexEvent takes nothing returns boolean
call thistype(UnitIndexer.eventIndex).onLocalUnitDeindex()
 
return false
endmethod
endif
 
/*
* The reason why ON_INDEX is used is so that the module can be enabled/disabled
* correctly
*/
private static method onInit takes nothing returns nothing
static if thistype.onUnitIndex.exists then
/*
* local events
*/
static if thistype.onLocalUnitDeindex.exists then
set onLocalUnitDeindexEventExpr = Condition(function thistype.onLocalUnitDeindexEvent)
endif
 
/*
* onLocalUnitIndexEvent is registered for onLocalUnitdeindex because onLocalUnitDeindex
* must be registered to each unit. This means that it must register as units are indexed.
*/
static if thistype.onLocalUnitIndex.exists then
call thistype.ON_INDEX.register(Condition(function thistype.onLocalUnitIndexEvent))
elseif thistype.onLocalUnitDeindex.exists then
call thistype.ON_INDEX.register(Condition(function thistype.onLocalUnitIndexEvent))
endif
else
/*
* global events
*
* ON_DEINDEX is used here instead of UnitIndexer.GlobalEvent.ON_DEINDEX for proper
* execution order
*/
 
static if thistype.onLocalUnitDeindex.exists then
call thistype.ON_DEINDEX.register(Condition(function thistype.onLocalUnitDeindexEvent))
endif
 
static if thistype.onLocalUnitIndex.exists then
call thistype.ON_INDEX.register(Condition(function thistype.onLocalUnitIndexEvent))
endif
endif
 
static if thistype.localInit.exists then
call localInit()
endif
endmethod
endif
//! endtextmacro
endlibrary
 

Attachments

  • Unit Indexer.w3x
    129.4 KB · Views: 660

Nestharus

o-o
Reaction score
84
Unit Index
JASS:
/*
*   requires
*
*       Alloc
*       ErrorMessage
*
*       private struct p_UnitIndex extends array
*
*       debug method operator isAllocated takes nothing returns boolean
*       debug static method calculateMemoryUsage takes nothing returns integer
*       debug static method getAllocatedMemoryAsString takes nothing returns string
*
*       method operator indexer takes nothing returns UnitIndexer
*       method operator unit takes nothing returns unit
*       static method operator [] takes unit whichUnit returns thistype
*       static method exists takes unit whichUnit returns boolean
*
*   struct UnitIndex extends array
*
*       readonly unit unit
*       readonly UnitIndexer indexer
*
*       static method operator [] takes unit whichUnit returns UnitIndex
*
*       static method exists takes unit whichUnit returns boolean
*       static method isDeindexing takes unit whichUnit returns boolean
*/
 
//! textmacro UNIT_INDEXER_UNIT_INDEX
private struct p_UnitIndex extends array
    implement AllocQ
 
    private unit p_unit
    
    static method create takes unit whichUnit returns thistype
        local thistype this = allocate()
        
        set p_unit = whichUnit
        call SetUnitUserData(whichUnit, this)
 
        call UnitAddAbility(whichUnit, ABILITIES_UNIT_INDEXER)
        call UnitMakeAbilityPermanent(whichUnit, true, ABILITIES_UNIT_INDEXER)
        
        return this
    endmethod
    
    method destroy takes nothing returns nothing
        set p_unit = null
    
        call deallocate()
    endmethod
    
    method operator indexer takes nothing returns UnitIndexer
        debug call ThrowWarning(not isAllocated,                                            "UnitIndexer", "indexer", "thistype", this, "Getting indexer from a deallocated unit index.")
        
        return this
    endmethod
    
    method operator unit takes nothing returns unit
        debug call ThrowWarning(not isAllocated,                                            "UnitIndexer", "unit", "thistype", this, "Getting unit from a deallocated unit index.")
    
        return p_unit
    endmethod
    static method operator [] takes unit whichUnit returns thistype
        debug call ThrowWarning(GetUnitTypeId(whichUnit) == 0,                              "UnitIndexer", "[]", "thistype", 0, "Getting unit index of a null unit.")
        debug call ThrowWarning(thistype(GetUnitUserData(whichUnit)).p_unit != whichUnit,   "UnitIndexer", "[]", "thistype", 0, "Getting unit index of a unit that isn't indexed.")
        
        return GetUnitUserData(whichUnit)
    endmethod
    
    static method exists takes unit whichUnit returns boolean
        debug call ThrowWarning(GetUnitTypeId(whichUnit) == 0, "UnitIndexer", "exists",     "thistype", 0, "Checking for the existence of a null unit.")
    
        return thistype(GetUnitUserData(whichUnit)).p_unit == whichUnit
    endmethod
    
    static method isDeindexing takes unit whichUnit returns boolean
        return GetUnitTypeId(whichUnit) != 0 and GetUnitAbilityLevel(whichUnit, ABILITIES_UNIT_INDEXER) == 0 and thistype(GetUnitUserData(whichUnit)).p_unit == whichUnit
    endmethod
endstruct
 
struct UnitIndex extends array
    method operator unit takes nothing returns unit
        return p_UnitIndex(this).unit
    endmethod
    
    static method operator [] takes unit whichUnit returns thistype
        return p_UnitIndex[whichUnit]
    endmethod
    
    static method exists takes unit whichUnit returns boolean
        return p_UnitIndex.exists(whichUnit)
    endmethod
    
    static method isDeindexing takes unit whichUnit returns boolean
        return p_UnitIndex.isDeindexing(whichUnit)
    endmethod
    
    method operator indexer takes nothing returns UnitIndexer
        return p_UnitIndex(this).indexer
    endmethod
endstruct
//! endtextmacro


Unit Indexer
JASS:
/*
*   requires
*
*       Event
*       WorldBounds
*
*   struct UnitIndexer extends array
*
*       static boolean enabled = true
*
*       readonly static Trigger GlobalEvent.ON_INDEX
*       readonly static Trigger GlobalEvent.ON_DEINDEX
*       readonly Trigger Event.ON_DEINDEX
*
*       readonly UnitIndex eventIndex = 0
*       readonly unit eventUnit = null
*
*   private struct WrappedTrigger extends array
*
*       method reference takes Trigger whichTrigger returns nothing
*       method register takes boolexpr whichExpression returns nothing
*
*/
 
//! textmacro UNIT_INDEXER_UNIT_INDEXER
private struct WrappedTrigger extends array
    method reference takes Trigger whichTrigger returns TriggerReference
        local TriggerReference triggerReference = Trigger(this).reference(whichTrigger)
        
        call PreGameEvent.fireTrigger(whichTrigger)
        
        return triggerReference
    endmethod
    
    method register takes boolexpr whichExpression returns TriggerCondition
        local TriggerCondition triggerCondition = Trigger(this).register(whichExpression)
        
        call PreGameEvent.fireExpression(whichExpression)
        
        return triggerCondition
    endmethod
endstruct
 
private struct UnitIndexerTriggerGlobal extends array
    readonly static WrappedTrigger  ON_INDEX
    readonly static Trigger         ON_DEINDEX
    
    private static method init takes nothing returns nothing
        set ON_INDEX = Trigger.create()
        set ON_DEINDEX = Trigger.create()
    endmethod
    
    implement Init
endstruct
 
private keyword ON_DEINDEX_MAIN
private struct UnitIndexerTrigger extends array
    readonly Trigger ON_DEINDEX
    readonly Trigger ON_DEINDEX_MAIN
    
    method createDeindex takes nothing returns nothing
        set ON_DEINDEX = Trigger.create()
        set ON_DEINDEX_MAIN = Trigger.create()
        
        call ON_DEINDEX_MAIN.reference(ON_DEINDEX)
        call ON_DEINDEX_MAIN.reference(UnitIndexerTriggerGlobal.ON_DEINDEX)
    endmethod
    
    method destroyDeindex takes nothing returns nothing
        call ON_DEINDEX_MAIN.destroy()
        call ON_DEINDEX.destroy()
    endmethod
endstruct
 
struct UnitIndexer extends array
    private trigger deindexTrigger
    private static boolexpr onDeindexCondition
 
    static method operator eventIndex takes nothing returns UnitIndex
        return p_eventIndex
    endmethod
    static method operator eventUnit takes nothing returns unit
        return eventIndex.unit
    endmethod
    
    static method operator GlobalEvent takes nothing returns UnitIndexerTriggerGlobal
        return 0
    endmethod
    method operator Event takes nothing returns UnitIndexerTrigger
        return this
    endmethod
 
    static boolean enabled = true
    
    private static method fire takes Trigger whichTrigger, integer whichIndex returns nothing
        local integer prevIndexedUnit = p_eventIndex
        set p_eventIndex = whichIndex
        call whichTrigger.fire()
        set p_eventIndex = prevIndexedUnit
    endmethod
    
    private static method onIndex takes nothing returns boolean
        local unit indexedUnit = GetFilterUnit()
        local p_UnitIndex index
        
        if (enabled and not p_UnitIndex.exists(indexedUnit)) then
            set index = p_UnitIndex.create(indexedUnit)
            
            set thistype(index).deindexTrigger = CreateTrigger()
            call TriggerRegisterUnitEvent(thistype(index).deindexTrigger, indexedUnit, EVENT_UNIT_ISSUED_ORDER)
            call TriggerAddCondition(thistype(index).deindexTrigger, onDeindexCondition)
            
            call PreGameEvent.addUnitIndex(index)
            
            call thistype(index).Event.createDeindex()
            
            call fire(GlobalEvent.ON_INDEX, index)
        endif
        
        set indexedUnit = null
        
        return false
    endmethod
    
    private static method onDeindex takes nothing returns boolean
        local p_UnitIndex index = GetUnitUserData(GetTriggerUnit())
        
        if (GetUnitAbilityLevel(GetTriggerUnit(), ABILITIES_UNIT_INDEXER) == 0) then
            call PreGameEvent.removeUnitIndex(index)
            
            call fire(thistype(index).Event.ON_DEINDEX_MAIN, index)
            
            call thistype(index).Event.destroyDeindex()
            
            call DestroyTrigger(thistype(index).deindexTrigger)
            set thistype(index).deindexTrigger = null
            
            call index.destroy()
        endif
        
        return false
    endmethod
    
    private static method init takes nothing returns nothing
        local trigger indexTrigger = CreateTrigger()
        
        local boolexpr onIndexCondition  = Condition(function thistype.onIndex)
        
        local group enumGroup = CreateGroup()
        
        local integer currentPlayerId = 15
        local player currentPlayer
        
        set onDeindexCondition= Condition(function thistype.onDeindex)
        
        call TriggerRegisterEnterRegion(indexTrigger, WorldBounds.worldRegion, onIndexCondition)
        
        loop
            set currentPlayer = Player(currentPlayerId)
            
            call SetPlayerAbilityAvailable(currentPlayer, ABILITIES_UNIT_INDEXER, false)
            call GroupEnumUnitsOfPlayer(enumGroup, currentPlayer, onIndexCondition)
            
            exitwhen currentPlayerId == 0
            set currentPlayerId = currentPlayerId - 1
        endloop
        
        call DestroyGroup(enumGroup)
        
        set onIndexCondition = null
        
        set enumGroup = null
        set currentPlayer = null
        
        set indexTrigger = null
    endmethod
    
    implement Init
endstruct
//! endtextmacro


PreGame Event
JASS:
/*
*   requires
*
*       StaticUniqueList
*
*   private struct PreGameEvent extends array
*
*       Evaluates all triggers and functions registered to
*       Unit Indexer before game start for all indexed units.
*
*
*       static method fireTrigger takes trigger whichTrigger returns nothing
*       static method fireExpression takes boolexpr whichExpression returns nothing
*
*       static method addUnitIndex takes integer whichUnitIndex returns nothing
*       static method removeUnitIndex takes integer whichUnitIndex returns nothing
*/
 
//! textmacro UNIT_INDEXER_PREGAME_EVENT
private struct PreGameEvent extends array
    readonly static boolean isGameLoaded = false
 
    implement StaticUniqueList
    
    private static method p_fireTrigger takes Trigger whichTrigger returns nothing
        local thistype this = first
        local integer prevIndexedUnitId = p_eventIndex
        
        loop
            exitwhen this == sentinel or not whichTrigger.enabled
            
            set p_eventIndex = this
            call whichTrigger.fire()
            
            set this = next
        endloop
        
        set p_eventIndex = prevIndexedUnitId
    endmethod
    static method fireTrigger takes Trigger whichTrigger returns nothing
        if (first != 0) then
            call p_fireTrigger(whichTrigger)
        endif
    endmethod
    
    private static method p_fireExpression takes boolexpr whichExpression returns nothing
        local trigger triggerContainer = CreateTrigger()
        local thistype this = first
        local integer prevIndexedUnitId = p_eventIndex
        
        call TriggerAddCondition(triggerContainer, whichExpression)
        
        loop
            exitwhen this == sentinel
            
            set p_eventIndex = this
            call TriggerEvaluate(triggerContainer)
            
            set this = next
        endloop
        
        call TriggerClearConditions(triggerContainer)
        call DestroyTrigger(triggerContainer)
        set triggerContainer = null
        
        set p_eventIndex = prevIndexedUnitId
    endmethod
    static method fireExpression takes boolexpr whichExpression returns nothing
        if (first != 0) then
            call p_fireExpression(whichExpression)
        endif
    endmethod
    
    static method addUnitIndex takes integer whichUnitIndex returns nothing
        if (isGameLoaded) then
            return
        endif
        
        call enqueue(whichUnitIndex)
    endmethod
    
    static method removeUnitIndex takes integer whichUnitIndex returns nothing
        if (isGameLoaded) then
            return
        endif
        
        call thistype(whichUnitIndex).remove()
    endmethod
    
    private static method run takes nothing returns nothing
        call DestroyTimer(GetExpiredTimer())
        
        set isGameLoaded = true
        
        call clear()
    endmethod
    private static method init takes nothing returns nothing
        call TimerStart(CreateTimer(), 0, false, function thistype.run)
    endmethod
    
    implement Init
endstruct
//! endtextmacro


Installation Script
JASS:
/*
*   This is for World Editor
*
*   You will need to
*
*       1.  Enable This Trigger
*       2.  Save Your Map
*       3.  Close Your Map
*       4.  Open Your Map
*       5.  Disable This Trigger
*       6.  Save Your Map
*/
//! externalblock extension=lua ObjectMerger $FILENAME$
    //! i do
        //! i dofile("GetVarObject")
        
        //! i local id = getvarobject("Adef", "abilities", "ABILITIES_UNIT_INDEXER", true)
        
        //! i createobject("Adef", id)
        //! i makechange(current, "aart", "")
        //! i makechange(current, "arac", "0")
        //! i makechange(current, "anam", "Unit Indexer")
        //! i makechange(current, "ansf", "Unit Indexer")
 
        //! i updateobjects()
    //! i end
//! endexternalblock
 
/*
*   This is for a .lua file
*
*   Can run this through command line using grimex exe
*
dofile("GetVarObject")
 
local id = getvarobject("Adef", "abilities", "ABILITIES_UNIT_INDEXER", true)
 
createobject("Adef", id)
makechange(current, "aart", "")
makechange(current, "arac", "0")
makechange(current, "anam", "Unit Indexer")
makechange(current, "ansf", "Unit Indexer")
 
updateobjects()
*/
 

Nestharus

o-o
Reaction score
84
Sorry all. When I fixed the formatting, a few spaces got dropped. These were causing syntax errors. I put them back in just now.
 

tom_mai78101

The Helper Connoisseur / Ex-MineCraft Host
Staff member
Reaction score
1,663
Quick question, is this for TFT? If so, can I cross post this to Reddit?

The subreddit community I have in mind is this. Perhaps you'll get some testers there.
 

tom_mai78101

The Helper Connoisseur / Ex-MineCraft Host
Staff member
Reaction score
1,663
Good news, after posting it to Reddit, at least one of them appreciated your efforts, impressed that after all these years, there are still people like you working on this.

Feedback is positive.

EDIT: Is "Trigger" a person, or the "trigger" the editor use for JASS?
 

Nestharus

o-o
Reaction score
84
Made it so that Alloc, AllocT, and AllocQ isAllocated field was not debug only. This was causing a syntax error when the UnitIndexer modules were saved outside of debug mode. They depend on isAllocated : |.

These 3 things are separate resources from Unit Indexer. I updated the map to include the latest versions to fix the syntax error ; ).
 

tom_mai78101

The Helper Connoisseur / Ex-MineCraft Host
Staff member
Reaction score
1,663
Updating Reddit post to reflect on this.

But unfortunately, it's going to heavily affect your views count, as I cannot post the same thing (or updates) there.
 
General chit-chat
Help Users
  • Varine Varine:
    I ordered like five blocks for 15 dollars. They're just little aluminum blocks with holes drilled into them
  • Varine Varine:
    They are pretty much disposable. I have shitty nozzles though, and I don't think these were designed for how hot I've run them
  • Varine Varine:
    I tried to extract it but the thing is pretty stuck. Idk what else I can use this for
  • Varine Varine:
    I'll throw it into my scrap stuff box, I'm sure can be used for something
  • Varine Varine:
    I have spare parts for like, everything BUT that block lol. Oh well, I'll print this shit next week I guess. Hopefully it fits
  • Varine Varine:
    I see that, despite your insistence to the contrary, we are becoming a recipe website
  • Varine Varine:
    Which is unique I guess.
  • The Helper The Helper:
    Actually I was just playing with having some kind of mention of the food forum and recipes on the main page to test and see if it would engage some of those people to post something. It is just weird to get so much traffic and no engagement
  • The Helper The Helper:
    So what it really is me trying to implement some kind of better site navigation not change the whole theme of the site
  • Varine Varine:
    How can you tell the difference between real traffic and indexing or AI generation bots?
  • 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 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