- Joined
- Mar 19, 2008
- Messages
- 3,141
An alternative version to AII. Credits to Vexiorian for original ItemDex idea. Since I'm unsure which item indexer most of you have been using if any, I've decided to uniform module API with powerfull UnitIndexer by Nestharus - it's basicaly the same. Thanks to you Nes.
Table is in use because of lacking GetTriggerItem() native. Some simple hash method could be used instead but for now it's Table.
(Old) I'm off for week or two, will fix my stuff as soon as possible. Thanks for your opinions.
Demo:
Table is in use because of lacking GetTriggerItem() native. Some simple hash method could be used instead but for now it's Table.
(Old) I'm off for week or two, will fix my stuff as soon as possible. Thanks for your opinions.
JASS:
/*****************************************************************************
*
* ItemIndexer v2.0.0.0
* by Bannar aka Spinnaker
*
* Attaches unique indexes to items.
*
******************************************************************************
*
* Important:
* Due to lack of perfect index method, ItemIndexer uses GetItemIndex function to attach index
* if needed to given item before actually returning the value.
* Use NewItem function instead of CreateItem in order to create and index item at once.
*
******************************************************************************
*
* Optionaly uses:
* Event by Nestharus
* hiveworkshop.com/forums/jass-resources-412/snippet-event-186555/
* RegisterPlayerUnitEvent by Magtheridon96
* hiveworkshop.com/forums/jass-functions-413/snippet-registerplayerunitevent-203338/
* Table by Bribe
* hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/
* WorldBounds by Nestharus
* hiveworkshop.com/forums/jass-functions-413/snippet-worldbounds-180494/
* RestoreTrigger by Bannar (Spinnaker)
* hiveworkshop.com/forums/submissions-414/snippet-restoretrigger-233655/
*
******************************************************************************
*
* globals
*
* lastCreatedItem - reference to last created item, similar to bj_lastCreatedItem
*
*
* functions:
*
* function NewItem takes integer itemid, real x, real y returns item
* function LastCreatedItem takes nothing returns item
*
* function GetIndexedItemId takes nothing returns integer
* function GetIndexedItem takes nothing returns item
*
* function GetItemById takes integer v returns item
* function GetItemId takes item it returns integer
* function IsItemIndexed takes item it returns boolean
*
* function RegisterItemIndexEvent takes code c, integer ev returns nothing
* function TriggerRegisterItemIndexEvent takes trigger t, integer ev returns nothing
*
*
* module ItemIndexModule:
*
* static method operator [] takes item it returns thistype
* method operator item takes nothing returns item
* readonly boolean allocated
*
* private method onIndex takes nothing returns nothing
* private method onDeindex takes nothing returns nothing
* private static method filterItem takes item it returns boolean
*
*
* struct ItemIndex - represents and manages item index
*
* method incRef takes nothing returns nothing
* method decRef takes nothing returns nothing
*
*
* struct ItemIndexEvent - child struct to Event, contains and handles item index events
*
* readonly static integer INDEX
* readonly static integer DEINDEX
* static method register takes code c, integer ev returns nothing
* - only if parent struct Event does not exist
*
*
* struct ItemIndex - "almost" private struct handling all index and deindex operations
*
* static boolean enabled
* static method indexItem takes item it returns boolean
*
*
*****************************************************************************/
library ItemIndexer uses /*
*/ optional Event /*
*/ optional RegisterPlayerUnitEvent /*
*/ optional Table /*
*/ optional WorldBounds /*
*/ optional RestoreTrigger
globals
private integer eventIndex = 0
private item lastCreatedItem = null
private item array itemArray
private constant integer TRIG_RESTORE_THRESHOLD = 50
private integer emptyEvents = 0
endglobals
static if not LIBRARY_Event then
globals
private real evCaller = -1
private trigger array evTrigs
endglobals
endif
private module ItemIndexEventInit
private static method onInit takes nothing returns nothing
static if LIBRARY_Event then
set INDEX = CreateEvent()
set DEINDEX = CreateEvent()
else
set evTrigs[INDEX] = CreateTrigger()
set evTrigs[DEINDEX] = CreateTrigger()
endif
call TimerStart(CreateTimer(), 0, false, function thistype.refireIndexEvent)
endmethod
endmodule
// ItemIndexEvent struct realted to INDEX and DEINDEX events
struct ItemIndexEvent extends array
static if LIBRARY_Event then
readonly static Event INDEX
readonly static Event DEINDEX
else
readonly static integer INDEX = 0
readonly static integer DEINDEX = 1
static method register takes code c, integer ev returns nothing
call TriggerAddCondition(evTrigs[ev], Filter(c))
endmethod
endif
static method fireEvent takes integer index, integer ev returns nothing
local integer saveIndex = eventIndex
set eventIndex = index
static if LIBRARY_Event then
call FireEvent(ev)
else
set evCaller = ev
call TriggerEvaluate(evTrigs[ev])
set evCaller = -1
endif
set eventIndex = saveIndex
endmethod
private static method refireIndexEvent takes nothing returns nothing
local ItemIndex this = ItemIndex(0).next
loop
exitwhen 0==this
call ItemIndexEvent.fireEvent(this, ItemIndexEvent.INDEX)
set this = this.next
endloop
call DestroyTimer(GetExpiredTimer())
endmethod
implement ItemIndexEventInit
endstruct
// ItemIndex struct which instance represents given item's index
struct ItemIndex extends array
private static integer idCount = 0
private static thistype recycle = 0
readonly thistype next
private thistype prev
private integer refCount
static method allocate takes nothing returns thistype
local thistype this
if ( 0 == recycle ) then
set idCount = idCount+1
set this = idCount
else
set this = recycle
set recycle = recycle.next
endif
set this.prev = thistype(0).prev
set thistype(0).prev.next = this
set this.next = 0
set thistype(0).prev = this
return this
endmethod
method deallocate takes nothing returns nothing
set this.prev.next = this.next
set this.next.prev = this.prev
if ( this.refCount == 0 ) then
set this.next = recycle
set recycle = this
endif
endmethod
method incRef takes nothing returns nothing
if (itemArray[this] != null) then
set this.refCount = this.refCount+1
endif
endmethod
method decRef takes nothing returns nothing
if ( this.refCount > 0 ) then
set this.refCount = this.refCount - 1
if ( this.refCount == 0 and null == itemArray[this] ) then
set this.next = recycle
set recycle = this
endif
endif
endmethod
endstruct
// ItemIndexer initializer
private module ItemIndexerInit
private static method onInit takes nothing returns nothing
local group g = CreateGroup()
local rect world
local region worldRegion
local trigger t
static if LIBRARY_Table then
set itemTable = Table.create()
endif
set funcLeaving = Condition(function thistype.deindexLeaving)
static if LIBRARY_RestoreTrigger then
set trig = Trigger.create()
call trig.addCondition(function thistype.deindexLeaving)
else
set trig = CreateTrigger()
call TriggerAddCondition(trig, function thistype.deindexLeaving)
endif
static if (LIBRARY_WorldBounds) then
call EnumItemsInRect(WorldBounds.world, Condition(function thistype.indexPreplaced), null)
call GroupEnumUnitsInRect(g, WorldBounds.world, Condition(function thistype.indexInventory))
else
set world = GetWorldBounds()
set worldRegion = CreateRegion()
call RegionAddRect(worldRegion, world)
call EnumItemsInRect(world, Condition(function thistype.indexPreplaced), null)
call GroupEnumUnitsInRect(g, world, Condition(function thistype.indexInventory))
call RemoveRect(world)
call RemoveRegion(worldRegion)
set world = null
set worldRegion = null
endif
static if LIBRARY_RegisterPlayerUnitEvent then
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_PICKUP_ITEM, function thistype.indexManipulated)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SELL_ITEM, function thistype.indexManipulated)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_PAWN_ITEM, function thistype.deindexSold)
else
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_PICKUP_ITEM)
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SELL_ITEM)
call TriggerAddCondition(t, Condition(function thistype.indexManipulated))
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_PICKUP_ITEM)
call TriggerAddCondition(t, Condition(function thistype.deindexSold))
set t = null
endif
call DestroyGroup(g)
set g = null
endmethod
endmodule
// "almost" private struct ItemIndex; enable and indexItem are the only public members
struct ItemIndexer extends array
static boolean enabled = true
// prevents cb for deindexLeaving method from being generated
private static boolexpr funcLeaving = null
static if LIBRARY_RestoreTrigger then
private static Trigger trig
else
private static trigger trig
endif
static if LIBRARY_Table then
private static Table itemTable
else
private static hashtable itemTable = InitHashtable()
endif
// wrappers for storing & removing handle id, exist to make code cleaner
private static method storeHandleId takes item it returns nothing
static if LIBRARY_Table then
set itemTable.item[GetHandleId(it)] = it
else
call SaveItemHandle(itemTable, 0, GetHandleId(it), it)
endif
endmethod
private static method removeHandleId takes item it returns nothing
static if LIBRARY_Table then
call itemTable.remove(GetHandleId(it))
else
call RemoveSavedHandle(itemTable, 0, GetHandleId(it))
endif
endmethod
// wrappers for refreshing and registering trigger data, exist to make code cleaner
private static method registerDeathEvent takes item it returns nothing
static if LIBRARY_RestoreTrigger then
call TriggerRegisterDeathEvent(trig.trigger, it)
else
call TriggerRegisterDeathEvent(trig, it)
endif
endmethod
private static method refreshMainTrigger takes nothing returns nothing
local ItemIndex this = ItemIndex(0).next
static if LIBRARY_RestoreTrigger then
call trig.restore()
else
call DestroyTrigger(trig)
set trig = CreateTrigger()
call TriggerAddCondition(trig, funcLeaving)
endif
loop
exitwhen 0 == this
call registerDeathEvent(itemArray[this])
set this = this.next
endloop
endmethod
static method indexItem takes item it returns boolean
local ItemIndex this
if ( enabled and it != itemArray[GetItemUserData(it)] ) then
set this = ItemIndex.allocate()
call SetItemUserData(it, this)
set itemArray[this] = it
call storeHandleId(it)
call registerDeathEvent(it)
call ItemIndexEvent.fireEvent(this, ItemIndexEvent.INDEX)
endif
return false
endmethod
// index helper methods
private static method indexPreplaced takes nothing returns boolean
return indexItem(GetFilterItem())
endmethod
private static method indexManipulated takes nothing returns boolean
return indexItem(GetManipulatedItem())
endmethod
private static method indexInventory takes nothing returns boolean
local unit u = GetFilterUnit()
local integer slot = 0
local integer last = UnitInventorySize(u)
loop
exitwhen slot == last
if ( UnitItemInSlot(u, slot) != null ) then
call indexItem(UnitItemInSlot(u, slot))
endif
set slot = slot+1
endloop
set u = null
return false
endmethod
private static method deindexItem takes item it returns boolean
local ItemIndex this = GetItemUserData(it)
if ( it == itemArray[this] ) then
call ItemIndexEvent.fireEvent(this, ItemIndexEvent.DEINDEX)
call this.deallocate()
set itemArray[this] = null
call removeHandleId(it)
set emptyEvents = emptyEvents + 1
if ( emptyEvents >= TRIG_RESTORE_THRESHOLD ) then
call refreshMainTrigger()
set emptyEvents = 0
endif
endif
return false
endmethod
// deindex helper methods
private static method deindexLeaving takes nothing returns boolean
static if LIBRARY_Table then
return deindexItem(itemTable.item[GetHandleId(GetTriggerWidget())])
else
return deindexItem(LoadItemHandle(itemTable, 0, GetHandleId(GetTriggerWidget())))
endif
endmethod
private static method deindexSold takes nothing returns boolean
return deindexItem(GetSoldItem())
endmethod
implement ItemIndexerInit
endstruct
// function API
function NewItem takes integer itemid, real x, real y returns item
set lastCreatedItem = CreateItem(itemid, x, y)
call ItemIndexer.indexItem(lastCreatedItem)
return lastCreatedItem
endfunction
function LastCreatedItem takes nothing returns item
return lastCreatedItem
endfunction
function GetIndexedItemId takes nothing returns integer
return eventIndex
endfunction
function GetIndexedItem takes nothing returns item
return itemArray[eventIndex]
endfunction
function IsItemIndexed takes item it returns boolean
return ( it == itemArray[GetItemUserData(it)] )
endfunction
function GetItemIndex takes item it returns integer
if not ( IsItemIndexed(it) ) then
call ItemIndexer.indexItem(it)
endif
return GetItemUserData(it)
endfunction
function GetItemByIndex takes integer index returns item
return itemArray[index]
endfunction
function RegisterItemIndexEvent takes code c, integer ev returns nothing
static if LIBRARY_Event then
call RegisterEvent(Filter(c), ev)
else
call ItemIndexEvent.register(c, ev)
endif
return
endfunction
function TriggerRegisterItemIndexEvent takes trigger t, integer ev returns nothing
static if LIBRARY_Event then
call TriggerRegisterEvent(t, ev)
else
call TriggerRegisterVariableEvent(t, SCOPE_PRIVATE + "evCaller", EQUAL, ev)
endif
return
endfunction
// module API
module ItemIndexModule
static method operator [] takes item it returns thistype
return GetItemUserData(it)
endmethod
method operator item takes nothing returns item
return itemArray[this]
endmethod
static if thistype.filterItem.exists then
static if thistype.onIndex.exists then
static if thistype.onDeindex.exists then
readonly boolean allocated
else
method operator allocated takes nothing returns boolean
return filterItem(item)
endmethod
endif
else
method operator allocated takes nothing returns boolean
return filterItem(item)
endmethod
endif
elseif ( thistype.onIndex.exists ) then
static if thistype.onDeindex.exists then
readonly boolean allocated
else
method operator allocated takes nothing returns boolean
return ( this == GetItemUserData(item) )
endmethod
endif
else
method operator allocated takes nothing returns boolean
return ( this == GetItemUserData(item) )
endmethod
endif
static if thistype.onIndex.exists then
private static method onIndexEvent takes nothing returns boolean
static if thistype.filterItem.exists then
if ( filterItem( itemArray[eventIndex] ) ) then
static if thistype.onDeindex.exists then
set thistype(eventIndex).allocated=true
endif
call thistype(eventIndex).onIndex()
endif
else
static if thistype.onDeindex.exists then
set thistype(eventIndex).allocated=true
endif
call thistype(eventIndex).onIndex()
endif
return false
endmethod
endif
static if thistype.onDeindex.exists then
private static method onDeindexEvent takes nothing returns boolean
static if thistype.filterItem.exists then
static if thistype.onIndex.exists then
if ( thistype(eventIndex).allocated ) then
set thistype(eventIndex).allocated=false
call thistype(eventIndex).onDeindex()
endif
else
if ( filterItem( itemArray[eventIndex] ) ) then
call thistype(eventIndex).onDeindex()
endif
endif
else
static if thistype.onIndex.exists then
set thistype(eventIndex).allocated=false
endif
call thistype(eventIndex).onDeindex()
endif
return false
endmethod
endif
static if thistype.onIndex.exists then
static if thistype.onDeindex.exists then
private static method onInit takes nothing returns nothing
call RegisterItemIndexEvent(function thistype.onIndexEvent, ItemIndexEvent.INDEX)
call RegisterItemIndexEvent(function thistype.onDeindexEvent, ItemIndexEvent.DEINDEX)
endmethod
else
private static method onInit takes nothing returns nothing
call RegisterItemIndexEvent(function thistype.onIndexEvent, ItemIndexEvent.INDEX)
endmethod
endif
elseif thistype.onDeindex.exists then
private static method onInit takes nothing returns nothing
call RegisterItemIndexEvent(function thistype.onDeindexEvent, ItemIndexEvent.DEINDEX)
endmethod
endif
endmodule
endlibrary
JASS:
struct ItemIndexDemo extends array
private method onIndex takes nothing returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, GetItemName(item) + " was indexed (" + I2S(this) + ")")
endmethod
private method onDeindex takes nothing returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, GetItemName(item) + " was deindexed (" + I2S(this) + ")")
endmethod
private static method filterItem takes item it returns boolean
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, GetItemName(it) + " was filtered")
return true
endmethod
private static method runTest takes nothing returns nothing
local item it = NewItem('rin1', 50, 50)
call RemoveItem(it)
endmethod
private static method onInit takes nothing returns nothing
call TimerStart(CreateTimer(), 2, false, function thistype.runTest)
endmethod
implement ItemIndexModule
endstruct
Last edited: