Nestharus
o-o
- Reaction score
- 84
Unit Indexer
v2.2.1.1
By Nestharus
By Nestharus
Introduction
Unit Indexer is a system for indexing units.
- It has a very efficient deindexing function (only this lib has it) and an efficient indexing function.
- It has locks.
- Global filter for indexing.
- Includes functions for enabling/disabling the unit indexer.
- Unit validation (sees if a unit is indexed).
- Will eventually have an API for PUI.
- Grants access to units before they go out of scope.
- Has by far the best indexing struct module of every indexing system.
System Code
JASS:
library UnitIndexer initializer init
//Primary index filter
private function IndexFilter takes unit u returns boolean
return true
endfunction
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~ Unit Indexer ~~ By Nestharus ~~ Version 2.2.1.1 ~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Description:
// Unit Indexer is a system for indexing units with Unit User Data. It is made
// to have minimal features while retaining safety.
//
// Basic features include an indexing filter, indexer enable/disable, and global indexer events
//
// To apply more filters and minimize evaluation calls (like unit type index event filter),
// just create your own filter and run through that.
//
// ex-
// local Trigger unitTypeEvent = CreateTrigger()
// if (GetUnitTypeId(GetIndexedUnit()) == 'hpea') then
// call TriggerEvaluate(unitTypeEvent)
//
//Installation:
// When running for the first time, hit save and restart WE, then comment out the line below.
//! external ObjectMerger w3a Adef OUIN anam "Unit Indexing" ansf "(Unit Indexing)" aart "" arac 0
//
//API:
//////////////////////////////////////////////////////////////
// -function EnableUnitIndexing takes boolean val returns nothing
// Disables/Enables the unit indexer
//
// -function IsUnitIndexingEnabled takes nothing returns boolean
// Returns a boolean that determines if the unit
// indexer is enabled
//
// -function IndexUnit takes unit u returns integer
// Indexes unit u if the unit is not already indexed and
// returns its index.
//
// -function GetUnitById takes integer index returns unit
// Returns a unit given an index
//
// -function GetUnitId takes unit u returns integer
// Gets a unit's index
//
// -function IsUnitIndexed takes unit u returns boolean
// Returns a boolean that determines if the unit
// is indexed
//
// -function LockUnitIndex takes integer index returns nothing
// Applies a lock on the unit index (can be layered)
// Locks make it so that the given index is not recycled.
//
// -function UnlockUnitIndex takes integer index returns nothing
// Unlocks a unit index. To get the index to recycle, each
// lock must be unlocked.
//
//Events:
//////////////////////////////////////////////////////////////
// Each event is a struct that extends array.
//
// -API
// -static method add takes boolexpr c returns nothing
// Adds code to be run at event.
//
// -Structs
// -UnitIndexEvent
// Fires when a unit is indexed
//
// -function GetIndexedUnit takes nothing returns unit
// Returns the indexed unit.
//
// -function GetIndexedUnitId takes nothing returns integer
// Returns the index.
//
// -UnitDeindexEvent
// Fires when a unit is deindexed
//
// -function GetIndexedUnit takes nothing returns unit
// Returns the deindexed unit.
//
// -function GetIndexedUnitId takes nothing returns integer
// Returns the index.
//
//Unit Index Struct Module:
//////////////////////////////////////////////////////////////
// A module that will automatically call indexing/deindexing methods for you as well
// as automatically check against your own filter. It runs completely off of static ifs,
// so there are minimal calls and there is minimal code.
//
// module UnitIndexStruct
// readonly unit unit
// The indexed unit of the struct
//
// indexAllocated
// Use this to determine whether an index is allocated or not. Useful
// if you only want to run event code for a struct if that struct is
// allocated.
//
// ex- if (indexedAllocated) then
// //run code
// endif
//
//
// Interface:
// private method unitIndex takes nothing returns nothing
// This method is called when a unit is indexed. Not having
// this method in your struct will just remove the indexing event
// code within the module.
//
// If there is a filter, this will only run if the filter returns true.
//
// private method unitDeindex takes nothing returns nothing
// This method is called when a unit is deindexed. Not having
// this method in your struct will just remove the deindexing event
// code within the module.
//
// If there is a filter and a unitIndex, this will only run if the struct is allocated.
// If there is no unitIndex method, this will run if the filter returns true.
//
// private static method unitIndexFilter takes unit u returns boolean
// This method is called when attempting to index a unit. Not having
// this method in your struct will just remove the filter check.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
globals
private boolean indexerEnabled = true
private trigger enter = CreateTrigger()
private trigger undefend = CreateTrigger()
private trigger onIndex = CreateTrigger()
private trigger onDeindex = CreateTrigger()
private unit array indexedUnit
private integer array lock
private integer instanceCount = 0
private integer array recycle
private integer recycleCount = 0
private integer array indexedArray
private integer indexed = 0
private unit replacedUnit = null
endglobals
function EnableUnitIndexing takes boolean val returns nothing
set indexerEnabled = val
endfunction
function IsUnitIndexingEnabled takes nothing returns boolean
return indexerEnabled
endfunction
function GetUnitById takes integer index returns unit
return indexedUnit[index]
endfunction
function GetUnitId takes unit u returns integer
return GetUnitUserData(u)
endfunction
function IsUnitIndexed takes unit u returns boolean
return (indexedUnit[GetUnitUserData(u)] == u)
endfunction
function LockUnitIndex takes integer index returns nothing
set lock[index] = lock[index] + 1
endfunction
function GetReplacedUnit takes nothing returns unit
return replacedUnit
endfunction
struct UnitIndexEvent extends array
public static method add takes boolexpr c returns nothing
call TriggerAddCondition(onIndex, c)
endmethod
endstruct
struct UnitDeindexEvent extends array
public static method add takes boolexpr c returns nothing
call TriggerAddCondition(onDeindex, c)
endmethod
endstruct
function IndexUnit takes unit u returns integer
set indexed = indexed + 1
set indexedArray[indexed] = GetUnitUserData(u)
if (indexedUnit[indexed] != u) then
if (recycleCount != 0) then
set recycleCount = recycleCount - 1
set indexedArray[indexed] = recycle[recycleCount]
else
set instanceCount = instanceCount + 1
set indexedArray[indexed] = instanceCount
endif
//set fields, add ability, set index data
set indexedUnit[indexedArray[indexed]] = u
call UnitAddAbility(u, 039;OUIN039;)
call SetUnitUserData(u, indexedArray[indexed])
call TriggerEvaluate(onIndex)
endif
set indexed = indexed - 1
return indexedArray[indexed+1]
endfunction
function UnlockUnitIndex takes integer index returns nothing
if (lock[index] > 0) then
set lock[index] = lock[index] - 1
if (lock[index] == 0 and indexedUnit[index] == null) then
set recycle[recycleCount] = index
set recycleCount = recycleCount + 1
endif
endif
endfunction
function GetIndexedUnit takes nothing returns unit
return indexedUnit[indexedArray[indexed]]
endfunction
function GetIndexedUnitId takes nothing returns integer
return indexedArray[indexed]
endfunction
private function onEnter takes nothing returns boolean
//retrieve unit and unit type id
local unit filterUnit
if (indexerEnabled) then
set filterUnit = GetFilterUnit()
//make sure not allocated and enabled
if (indexedUnit[GetUnitUserData(filterUnit)] != filterUnit and IndexFilter(filterUnit)) then
//allocate
set indexed = indexed + 1
if (recycleCount != 0) then
set recycleCount = recycleCount - 1
set indexedArray[indexed] = recycle[recycleCount]
else
set instanceCount = instanceCount + 1
set indexedArray[indexed] = instanceCount
endif
//set fields, add ability, set index data
set indexedUnit[indexedArray[indexed]] = filterUnit
call UnitAddAbility(filterUnit, 039;OUIN039;)
call SetUnitUserData(filterUnit, indexedArray[indexed])
call TriggerEvaluate(onIndex)
set indexed = indexed - 1
endif
set filterUnit = null
endif
return false
endfunction
private function onUndefend takes nothing returns boolean
local unit u = GetFilterUnit()
if (GetUnitAbilityLevel(u, 039;OUIN039;) == 0) then
set indexed = indexed + 1
set indexedArray[indexed] = GetUnitUserData(u)
if (indexedUnit[indexedArray[indexed]] == u) then
call TriggerEvaluate(onDeindex)
if (lock[indexedArray[indexed]] == 0) then
set recycle[recycleCount] = indexedArray[indexed]
set recycleCount = recycleCount + 1
endif
set indexedUnit[indexedArray[indexed]] = null
endif
set indexed = indexed - 1
endif
return false
endfunction
private struct UnitIndexing extends array
private static method onInit takes nothing returns nothing
local region world = CreateRegion()
local integer i = 15
local boolexpr bc = Condition(function onUndefend)
local rect r = GetWorldBounds()
call RegionAddRect(world, r)
call TriggerRegisterEnterRegion(enter, world, Condition(function onEnter))
loop
call TriggerRegisterPlayerUnitEvent(undefend, Player(i), EVENT_PLAYER_UNIT_ISSUED_ORDER, bc)
call SetPlayerAbilityAvailable(Player(i), 039;OUIN039;, false)
exitwhen i == 0
set i = i - 1
endloop
call RemoveRect(r)
set r = null
set world = null
set bc = null
endmethod
endstruct
private function init takes nothing returns nothing
local integer i = 15
local group g = CreateGroup()
local boolexpr bc = Condition(function onEnter)
loop
call GroupEnumUnitsOfPlayer(g, Player(i), bc)
exitwhen i == 0
set i = i - 1
endloop
call DestroyGroup(g)
set g = null
endfunction
module UnitIndexStruct
static if thistype.unitIndexFilter.exists then
static if thistype.unitIndex.exists then
private static boolean array allocated
public method operator indexAllocated takes nothing returns boolean
return allocated[this]
endmethod
else
public method operator indexAllocated takes nothing returns boolean
return unitIndexFilter(GetUnitById(this))
endmethod
endif
else
public static constant method operator indexAllocated takes nothing returns boolean
return true
endmethod
endif
static if thistype.unitIndex.exists then
private static method onIndexEvent takes nothing returns boolean
static if thistype.unitIndexFilter.exists then
if (unitIndexFilter(GetIndexedUnit())) then
set allocated[GetIndexedUnitId()] = true
call thistype(GetIndexedUnitId()).unitIndex()
endif
else
call thistype(GetIndexedUnitId()).unitIndex()
endif
return false
endmethod
static if thistype.unitDeindex.exists then
public method operator unit takes nothing returns unit
return GetUnitById(this)
endmethod
else
public method operator unit takes nothing returns unit
return GetUnitById(this)
endmethod
endif
endif
static if thistype.unitDeindex.exists then
private static method onDeindexEvent takes nothing returns boolean
static if thistype.unitIndexFilter.exists then
static if thistype.unitDeindex.exists then
if (allocated[GetIndexedUnitId()]) then
set allocated[GetIndexedUnitId()] = false
call thistype(GetIndexedUnitId()).unitDeindex()
endif
else
if (unitIndexFilter(GetIndexedUnit())) then
call thistype(GetIndexedUnitId()).unitDeindex()
endif
endif
else
call thistype(GetIndexedUnitId()).unitDeindex()
endif
return false
endmethod
endif
static if thistype.unitIndex.exists then
static if thistype.unitDeindex.exists then
private static method onInit takes nothing returns nothing
call UnitIndexEvent.add(Condition(function thistype.onIndexEvent))
call UnitDeindexEvent.add(Condition(function thistype.onDeindexEvent))
endmethod
else
private static method onInit takes nothing returns nothing
call UnitIndexEvent.add(Condition(function thistype.onIndexEvent))
endmethod
endif
elseif thistype.unitDeindex.exists then
private static method onInit takes nothing returns nothing
call UnitDeindexEvent.add(Condition(function thistype.onDeindexEvent))
endmethod
endif
endmodule
endlibrary
Demo
JASS:
struct UnitIndexerDemo extends array
private method unitIndex takes nothing returns nothing
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, GetUnitName(unit) + " was indexed")
endmethod
private method unitDeindex takes nothing returns nothing
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, GetUnitName(unit) + " was deindexed")
endmethod
private static method unitIndexFilter takes unit u returns boolean
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, GetUnitName(u) + " was filtered")
if (GetUnitTypeId(u) == 039;hkni039;) then
return false
endif
return true
endmethod
implement UnitIndexStruct
endstruct