|
|
#1 |
|
master of fugue
Join Date: Jun 2007
Posts: 2,558
![]() ![]() ![]() ![]()
|
PUI://============================================================================== // PUI -- Perfect Unit Indexing by Cohadar -- v6.1 //============================================================================== // // PURPOUSE: // * Extending UnitUserData() // * This is basically perfect hashing algorithm for units // // HOW TO USE: // * You have two functions at your disposal: // GetUnitIndex(unit) -> index // GetIndexUnit(index) -> unit // // * Put you custom unit properties in struct that extends arrays. // Use unit index as id of that struct. // There is an example of this in demo map. // // PROS: // * Unit indexes are assigned only to units that actually need them. // * Unit index will be automatically recycled when unit is removed from the game. // * Automatically detects null unit handles and removed unit handles (in debug mode) // // CONS: // * This system needs exclusive access to UnitUserData // // DETAILS: // * Uses internal vJass struct index allocation/deallocation algorithm. // * Periodically checks and recycles unit indexes // // HOW TO IMPORT: // * Just create a trigger named PUI // * convert it to text and replace the whole trigger text with this one // //============================================================================== library PUI initializer Init //============================================================================== globals // maximum number of indexed units on your map at a single moment of time private constant integer MAX_INDEXES = 1024 // up to 8192 // period of recycling, 32 indexes per second private constant real PERIOD = 0.03125 // current check index private integer C = 0 endglobals //============================================================================== // Using internal struct algorithm for index allocation/dealocation // This way I don't have to write messy code of my own //============================================================================== private struct UnitIndex unit u //---------------------------------------------------------- static method create takes unit whichUnit returns UnitIndex local UnitIndex index // check for null unit handle debug if whichUnit == null then debug call BJDebugMsg("|c00FF0000ERROR: PUI - Index requested for null unit") debug return 0 debug endif set index = UnitIndex.allocate() set index.u = whichUnit call SetUnitUserData(whichUnit, index) // check for removed unit handle debug if GetUnitUserData(whichUnit) == 0 then debug call BJDebugMsg("|c00FFCC00WARNING: PUI - Bad unit handle") debug return 0 debug endif return index endmethod //---------------------------------------------------------- static method Recycler takes nothing returns boolean local UnitIndex index = C set C = C + 1 if C == MAX_INDEXES then set C = 0 endif if index.u != null then if (GetUnitUserData(index.u) == 0) then set index.u = null call index.destroy() endif endif return false endmethod endstruct //============================================================================== // Returns index of some unit, if unit has no index it gets a new one. //============================================================================== function GetUnitIndex takes unit whichUnit returns integer local UnitIndex index = GetUnitUserData(whichUnit) if index == 0 then set index = UnitIndex.create(whichUnit) endif return index endfunction //============================================================================== // Return unit that has specified index, or null in no such unit exists. //============================================================================== function GetIndexUnit takes integer index returns unit local UnitIndex i = index if i.u != null then if GetUnitUserData(i.u) == index then return i.u endif endif return null endfunction //============================================================================== private function Init takes nothing returns nothing local trigger trig = CreateTrigger() call TriggerRegisterTimerEvent(trig, PERIOD, true) call TriggerAddCondition(trig, Condition(function UnitIndex.Recycler)) endfunction endlibrary example://=========================================================================== // We define 2 integer properties for any unit, // number of deaths and number of kills. //=========================================================================== scope Example initializer Init //=========================================================================== private struct Data extends array unit whichUnit integer deaths integer kills // reset instead of create because array structs are never created method reset takes unit whichUnit returns nothing set .whichUnit = whichUnit set .deaths = 0 set .kills = 0 endmethod // In case unit handle gets recycled we need to reset the data static method Get takes unit whichUnit returns Data local Data data = GetUnitIndex(whichUnit) if data.whichUnit != whichUnit then call data.reset(whichUnit) endif return data endmethod endstruct //=========================================================================== private function Actions takes nothing returns nothing local unit victim = GetDyingUnit() local unit killer = GetKillingUnit() local Data data = Data.Get(victim) set data.deaths = data.deaths + 1 if killer != null then set data = Data.Get(killer) set data.kills = data.kills + 1 call TextTag_Unit(killer,I2S(data.kills), "|c00FFFFFF") endif set victim = null set killer = null endfunction //=========================================================================== private function Conditions takes nothing returns boolean return true endfunction //=========================================================================== private function Init takes nothing returns nothing local trigger trig = CreateTrigger() call TriggerRegisterAnyUnitEventBJ( trig, EVENT_PLAYER_UNIT_DEATH ) call TriggerAddCondition( trig, Condition( function Conditions ) ) call TriggerAddAction( trig, function Actions ) endfunction endscope Last edited by cohadar : 12-16-2011 at 05:13 AM. |
|
|
|
| Sponsored Links - Login to hide this ad! |
|
|
|
|
#2 |
|
User
|
This should have optional support for hashtable.
The "create" method leaks indices in some cases in DEBUG_MODE. To fix this you can revise it (and shorten it) to: JASS:
static method create takes unit whichUnit returns UnitIndex
local UnitIndex index
// check for invalid unit handle
debug if GetUnitTypeId(whichUnit) == 0 then
debug call BJDebugMsg("|c00FF0000ERROR: PUI - Index requested for invalid unit")
debug return 0
debug endif
set index = UnitIndex.allocate()
set index.u = whichUnit
call SetUnitUserData(whichUnit, index)
return index
endmethod
Why using a trigger for the timer, instead of just a normal timer? PUI_PROPERTY is nice... if you are using just ONE piece of data. I don't even think it has a purpose otherwise. |
|
|
|
|
|
#3 | ||||
|
master of fugue
Join Date: Jun 2007
Posts: 2,558
![]() ![]() ![]() ![]()
|
Quote:
Quote:
I don't want to shorten anything, I want both null and removed errors to be detected, it is debug mode anyways. Quote:
Quote:
![]() EDIT: I just realized this version of PUI does not require exclusive access to UnitUserData. If you assign custom values to some UnitUser data that unit will be ignored by PUI automatically. This way you can have special uses for UserData on dummy casters for example, same goes for heroes, and what is best you need no custom filters for this. Sometimes I am better coder than myself. Last edited by cohadar : 12-06-2011 at 08:31 AM. |
||||
|
|
|
|
|
#4 |
|
User
Join Date: May 2011
Posts: 85
![]()
|
I don't see why anyone would use this over AutoIndex or any other decent indexer.
|
|
|
|
|
|
#5 | |
|
master of fugue
Join Date: Jun 2007
Posts: 2,558
![]() ![]() ![]() ![]()
|
Quote:
1. not indexing every unit > not inline-friendly 2. No functionality to detect when a unit enters or leaves the map. There exists a standard unit-enters-map event no? And unit-leaves-map is not really a unit event but an index event. 3 No modules for structs. version 5.3 had support for structs but than I realized I never used it so I removed it. 4. Periodic recycling How is this worse than adding a defend ability to every unit, and processing all unit-enters-map events and catching all undefend orders? 5. Zinc? What is that? Oh wait, another thing Vexorian made that is used by 0.000001% of mapmakers. PUI was the first indexing system ever created, the concept did not exist before it. It is simple,it does the job and has been used in maps. (Still used in EleTD as far as I know) I don't care if anyone uses it, I want it approved on general principle. |
|
|
|
|
|
|
#6 | |||||||
|
User
Join Date: May 2011
Posts: 85
![]()
|
Quote:
Quote:
Quote:
Quote:
Quote:
Quote:
Quote:
If I'm not mistaken, Anitarf (or it could have been somebody else) has stated that there is no "space" for different indexers in a single community -- and I can't help but agree with him. |
|||||||
|
|
|
|
|
#7 | |
|
master of fugue
Join Date: Jun 2007
Posts: 2,558
![]() ![]() ![]() ![]()
|
Quote:
Oh I knew chances of approval were in low percents when I posted this. It is just a matter of principle for me to try. I have long ago realized that all systems I make are always better than alternatives. This has something to do with objective nature of human beings, but still I would feel bad if I did not try to share my code with other people and assure them in the error of their ways. ![]() EDIT: I was reading this: http://www.wc3c.net/vexorian/jasshel...html#arrstruct and realized that not only that unit indexing does not need support for structs (those idiotic module stuff), it also does not need any textmacros (like PUI_PROPERTY) In the end, the only thing you need is an integer and a struct that extends array. You don't need any events for this at all. Last edited by cohadar : 12-08-2011 at 10:58 AM. |
|
|
|
|
|
|
#8 |
|
Procrastination Incarnate
Development Director
|
I don't see how this would be better than simply using a HandleTable. The argument of speed is not really convincing when your GetUnitIndex function is not inline friendly.
__________________Evein with inlining, I don't paticularly care for the speed benefits. For me, the index/deindex events are the main selling point of indexing systems, since they allow you to easily do automatic creation and recycling. Without even that, I don't know what this script is supposed to do. |
|
|
|
|
|
#9 | ||
|
master of fugue
Join Date: Jun 2007
Posts: 2,558
![]() ![]() ![]() ![]()
|
Quote:
Autoindex function can be inline friendly because it uses enter-map event and creates indexes there, PUI creates indexes when you ask for them. It is the same amount of work just done in two different places. Quote:
Last edited by cohadar : 12-15-2011 at 07:00 AM. |
||
|
|
|
|
|
#10 |
|
User
|
@ Cohadar, here's a spell I wrote from last year which uses AutoIndex + AutoEvents so that it gets reincarnation events, on-birth events, etc:
http://www.hiveworkshop.com/forums/s...mproved-166353 I'll give it that most spells can use just your GetUnitIndex function, but the more advanced stuff is going to need more advanced indexing. Efficiency aside. Last edited by Bribe : 12-15-2011 at 07:14 AM. |
|
|
|
|
|
#11 | ||
|
Procrastination Incarnate
Development Director
|
Quote:
Quote:
|
||
|
|
|
|
|
#12 | ||
|
master of fugue
Join Date: Jun 2007
Posts: 2,558
![]() ![]() ![]() ![]()
|
Quote:
I have no intention of browsing through 10 different triggers and 5000 lines of code just to prove a point. I am sure there are simpler examples that use both AutoIndex + AutoEvents. Quote:
(And I have very strong doubts when comparing code sizes of Autoindex and PUI) It is AutoEvents that has more functionality, not AutoIndex, you are mixing stuff here. And I still claim that functionality is just a fluff. Last edited by cohadar : 12-15-2011 at 04:11 PM. |
||
|
|
|
|
|
#13 | |||
|
Procrastination Incarnate
Development Director
|
Quote:
Quote:
Quote:
|
|||
|
|
|
|
|
#14 | |
|
master of fugue
Join Date: Jun 2007
Posts: 2,558
![]() ![]() ![]() ![]()
|
I'll just ignore the speed nonsense, because you just keep arguing without any proof.
__________________Quote:
This events is what I have been claiming to be not needed the whole time. Since you failed to provide an example of their use, let's try it in reverse. JASS://=========================================================================== // We define 2 integer properties for any unit, // number of deaths and number of kills. //=========================================================================== scope Example initializer Init //=========================================================================== private struct Data extends array unit whichUnit integer deaths integer kills method reset takes unit whichUnit returns nothing set .whichUnit = whichUnit set .deaths = 0 set .kills = 0 endmethod static method Get takes unit whichUnit returns Data local Data data = GetUnitIndex(whichUnit) if data.whichUnit != whichUnit then call data.reset(whichUnit) endif return data endmethod endstruct //=========================================================================== private function Actions takes nothing returns nothing local unit victim = GetDyingUnit() local unit killer = GetKillingUnit() local Data data = Data.Get(victim) set data.deaths = data.deaths + 1 if killer != null then set data = Data.Get(killer) set data.kills = data.kills + 1 call TextTag_Unit(killer,I2S(data.kills), "|c00FFFFFF") endif endfunction //=========================================================================== private function Conditions takes nothing returns boolean return true endfunction //=========================================================================== private function Init takes nothing returns nothing local trigger trig = CreateTrigger() call TriggerRegisterAnyUnitEventBJ( trig, EVENT_PLAYER_UNIT_DEATH ) call TriggerAddCondition( trig, Condition( function Conditions ) ) call TriggerAddAction( trig, function Actions ) endfunction endscope Oh look, I created an unit indexed struct without the need for onIndexed and onDeindexed. Can you please recode this to use those events so we can all be awed by how much better Autoindex version is? |
|
|
|
|
|
|
#15 | ||
|
Procrastination Incarnate
Development Director
|
Quote:
Quote:
JASS: |
||
|
|
|
![]() |
| Thread Tools | Search this Thread |
|
|
|
Donate |