• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

New Unit Indexer Released

Status
Not open for further replies.
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.

JASS:
library UnitIndexer /* v5.3.0.0
************************************************************************************
*
*	*/ 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 Trigger Event.ON_DEINDEX
*				-	this is a local event that runs whenever a specific unit is deindexed
*
*				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
*
*				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 GlobalUnitIndex
*
*		This has absolutely no module support
*
*		Fields
*		-------------------------
*
*			static constant boolean GLOBAL_UNIT_INDEX = true
*				-	this is used to ensure that only one unit index module is implemented.
*
*			readonly unit unit
*				-	converts a unit index into a unit
*
*			readonly boolean isUnitIndexed
*				-	is the unit index indexed
*
*			readonly UnitIndexer unitIndexer
*				-	the indexer in charge of handling the unit
*					useful for deindex event, which is unit specific
*
*		Methods
*		-------------------------
*
*			static method exists takes unit whichUnit returns boolean
*				-	determines whether the unit is indexed
*
*			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 nothing
*			interface private method onUnitDeindex takes nothing returns nothing
*
*		Operators
*		-------------------------
*
*			static method operator [] takes unit whichUnit returns thistype
*				-	converts a unit into thistype
*
************************************************************************************
*
*	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 ensure that only one unit index module is 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 UnitIndexEx module, implement
*		UnitIndexEx 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 GlobalUnitIndex
		static if thistype.UNIT_INDEX then
		elseif thistype.UNIT_INDEX_EX then
		else
			static constant boolean GLOBAL_UNIT_INDEX = true
			
			static method operator [] takes unit whichUnit returns thistype
				return p_UnitIndex[whichUnit]
			endmethod
			method operator unit takes nothing returns unit
				return p_UnitIndex(this).unit
			endmethod
			method operator unitIndexer takes nothing returns UnitIndexer
				return p_UnitIndex(this).indexer
			endmethod
			method operator isUnitIndexed takes nothing returns boolean
				return p_UnitIndex(this).isAllocated
			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
			
			static if thistype.GLOBAL_UNIT_INDEX then
				static if thistype.onUnitIndex.exists then
					private static method onIndexEvent takes nothing returns boolean
						call thistype(UnitIndexer.eventIndex).onUnitIndex()
					
						return false
					endmethod
				endif
				static if thistype.onUnitDeindex.exists then
					private static method onDeindexEvent takes nothing returns boolean
						call thistype(UnitIndexer.eventIndex).onUnitDeindex()
						
						return false
					endmethod
				endif
				
				static if thistype.onUnitIndex.exists then
					private static method onInit takes nothing returns nothing
				elseif thistype.onUnitDeindex.exists then
					private static method onInit takes nothing returns nothing
				endif
				
				static if thistype.onUnitIndex.exists then
					call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onIndexEvent))
				endif
				
				static if thistype.onUnitDeindex.exists then
					call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onDeindexEvent))
				endif
				
				static if thistype.onUnitIndex.exists then
					endmethod
				elseif thistype.onUnitDeindex.exists then
					endmethod
				endif
			endif
		endif
	endmodule
	
	module UnitIndex
		static if thistype.GLOBAL_UNIT_INDEX then
			private static method error takes nothing returns nothing
				A module requires UnitIndex to operate correctly.
				This struct is currently implementing GlobalUnitIndex.
			endmethod
		elseif thistype.UNIT_INDEX_EX then
		else
			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.GLOBAL_UNIT_INDEX then
			private static method error takes nothing returns nothing
				A module requires UnitIndexEx to operate correctly.
				This struct is currently implementing GlobalUnitIndex.
			endmethod
		elseif 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(true)
						call thistype(UnitIndexer.eventIndex).ON_DEINDEX.register(onDeindexExpression)

						call UnitIndexer(UnitIndexer.eventIndex).Event.ON_DEINDEX.reference(thistype(UnitIndexer.eventIndex).ON_DEINDEX)
						
						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(false)
				
				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(true)
					static if thistype.onUnitDeindex.exists then
						call ON_DEINDEX.register(Condition(function thistype.onDeindexEvent))
					endif
					
					call UnitIndexer.GlobalEvent.ON_DEINDEX.reference(ON_DEINDEX)
					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
		elseif thistype.GLOBAL_UNIT_INDEX then
			private static method error takes nothing returns nothing
				A module requires either UnitIndex or UnitIndexEx to operate correctly.
				This struct is currently implementing GlobalUnitIndex.
			endmethod
		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

/*
*	requires
*
*		Alloc
*		ErrorMessage
*
*		private struct p_UnitIndex extends array
*
*		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

/*
*	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(false)
		set ON_DEINDEX = Trigger.create(true)
	endmethod
	
	implement Init
endstruct

private keyword ON_DEINDEX_MAIN
private struct UnitIndexerTrigger extends array
	readonly Trigger ON_DEINDEX
	
	method createDeindex takes nothing returns nothing
		set ON_DEINDEX = Trigger.create(true)
		
		call ON_DEINDEX.reference(UnitIndexerTriggerGlobal.ON_DEINDEX)
	endmethod
	
	method destroyDeindex takes nothing returns nothing
		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, 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

/*
*	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
 

Attachments

  • Unit Indexer.w3x
    137.9 KB · Views: 144
Last edited:

Kazeon

Hosted Project: EC
Level 34
Joined
Oct 12, 2011
Messages
3,449
It's just seems stupid to write "Left" as your title but actually you still need thw a lot, Idk what's your mission by moving all of your resource there and delete everything here.. Actually, I suggest you just to come back here (why not?). Because, yeah, honestly I need you.. I got a lot of questions for you (idk that this will be a good reason for you to come back :hohum:)..
 
Let's be perfectly honest here: there NEVER was an issue with the efficiency of unit indexers and how index and deindex events got handled. The overhead of pseudo-event trigger evaluations is a wet fart compared to the actual steaming dump mountain that is the overhead of creating a unit.

I'm all in for more readable code and better API though.
 
I added tutorials and labs to the map. They will teach you all about how to use the new unit indexer.

I was going to add GUI support, but really, Trigger kills GUI support, so I can't really do it. I can, but it wouldn't be fully functional, which I like. I'll have to remove GUI support for DDS during the update too.

edit
Don't use Unit Indexer yet. I changed Trigger behavior because it running references before code was bad, lol. I need to update tutorials and the UnitIndexer modules. UnitIndexer can now go back to a single module and work correctly. GlobalEvent.ON_DEINDEX will still always run after Event.ON_DEINDEX.


If you all want to start coding insane resources, use Trigger. It is one of the best things I have ever written ;o. I can't live without it now :D.
 
Last edited:
JASS:
private static method init takes nothing returns nothing
        local thistype this = 8191
    
        loop
            set unitIndex = this
			set unitIndexer = this
            
            exitwhen this == 0
            set this = this - 1
        endloop
    endmethod

Uh

That's for the delegates. It was a way to minimize trigger generation and code generation. The methods are not static, so I had to set the arrays. Blame vJASS for not providing a better way to do this.
 
That is correct.

Unit Indexer is by no means done yet. I think I've settled on a final version, but I'm not going to put it up until I finish the tutorial on the new module.


Feel free to comment on the new approach of global vs local events ^)^. I take this even farther with the new module.

Keep in mind that trigger references and so on are faster than TriggerEvaluate. Empty trigger references add no overhead.
 
Ok, I just spent a very long time working on Unit Indexer.

First, I finished up the tutorials and labs. There are 22 triggers of labs/tutorials. These go from the very basic to the most advanced things you can do with Unit Indexer.

Next, I wrote test cases. I tested the hell out of this thing. The reason was because the modules are now very, very complex. The macro is even more complex >.<.

Next, there are 3 thingies

UnitIndex module
UnitIndexEx module
CREATE_LOCAL_UNIT_INDEX textmacro

Go through the tutorials/labs to learn how to use them.


This new update primarily focuses on supporting local events. No other Unit Indexer does local events! Not only this, but it does proper initialization with local events o_O. If you look at Test 5, you'll see what I'm talking about. Ofc, I doubt you'll understand it unless you go through the tutorials first : ).

The modules are now incredibly complex. They are simple, but... they really morph depending on what code you have implemented. There are 30 different main cases for this code morphing between UnitIndex, UnitIndex, and CREATE_LOCAL_UNIT_INDEX. You can look at LocalUnitIndex Test Cases to see all 30. I tested all 30 of them for proper code execution.

There is just so much : ). Really, I don't think Unit Indexer can be compared to any other unit indexing system anymore. This huge update would not have been possible without Trigger. Trigger is really amazing for local events.


Anyways, I hope you all enjoy it. I certainly spent countless hours doing this update.

The tutorials are located in the map. Be sure to go through them. Just trying to work off of the API isn't going to help you much. The final tutorial is pretty damn cool ^_^. jesus4lyf created 2 guards for each indexed unit in his demo map. He destroyed these guards on deindex. I did something similar, but with local events. You'll see >: o.
 

Kazeon

Hosted Project: EC
Level 34
Joined
Oct 12, 2011
Messages
3,449
well, bribe's GUI auto indexer is good enough for any map I guess. you should not give your life just to make a perfect indexer? at least, it's my suggestion.. Idk that it will be faster or what, but when I was trying to import one of your library, at last I need to import more than 15 other required libraries, that was just crazy..
 
well, bribe's GUI auto indexer is good enough for any map I guess. you should not give your life just to make a perfect indexer? at least, it's my suggestion.. Idk that it will be faster or what, but when I was trying to import one of your library, at last I need to import more than 15 other required libraries, that was just crazy..

copy the required's folder in the map to your map and delete what you already have

I suggest you delete the old required resources since every required resource had formatting updates and what not
 

Kazeon

Hosted Project: EC
Level 34
Joined
Oct 12, 2011
Messages
3,449
it's okay if all possible required library is contained in one folder.. look at this image..
133548d1395246125-snippet-gradienttext-.jpg

I only need the TextTag and that's the result of linking-requirements
and you should know that I haven't finished importing all the required bcs I was something like rage surrender :p

and since you moved everything to github I need to search all the requirements one by one... :hohum:
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
Hm, I tried with both Vexorians and Cohadars Jasshelper but still it doesn't compile. It always throws a error on

static method operator enabled=takes boolean enable returns nothing

If I fix it (seems there is a space missing) it throws subsequent errors. All I did was placing this struct in the testmap:

JASS:
struct MyStruct extends array
    implement UnitIndex
endstruct
 

Kazeon

Hosted Project: EC
Level 34
Joined
Oct 12, 2011
Messages
3,449
it's not about your tuts..

I just want to report that your codeless save/load w nw is not working, I can't load anything, no matter what I do.. so please, explain to me everything I need to do, to implement it and make it work, I have read all your instruction there at demo map but still not working.. Even those debug messages (like "Currently load feature is disabled") is not displayed..

okay, I'm enough with off topic ._.
 
Level 13
Joined
Jul 16, 2012
Messages
679
It's just seems stupid to write "Left" as your title but actually you still need thw a lot, Idk what's your mission by moving all of your resource there and delete everything here.. Actually, I suggest you just to come back here (why not?). Because, yeah, honestly I need you.. I got a lot of questions for you (idk that this will be a good reason for you to come back :hohum:)..

ahaha
 
I checked out the local indexing. It seems like a pretty cool feature. But it seems pretty easy to implement by itself, no? Just a struct, -> register enter map (or index event), -> create struct with unit. Map unit to struct using Table.

But maybe I have the wrong idea. I didn't get the complete gist of what its uses were from the demo, but
maybe you can elaborate a bit? :)
 
so on deindex, how would you run your deindex event for that unit?

on index, how would modules you implement into your struct run index events when your struct does?

on index, how do other structs run index events when your struct does?

how would you disable events for your struct?


If you answered if-statements, those aren't local events. Those are global events with conditions in them.

edit
suppose some struct has data in it

you have another struct that relies on the data of that first struct

how do you accomplish this? If you use global events, the first struct deindexes before the second one does, so the second one loses the data and errors out.
 
Nestharus, I don't have time to read the code but I'm curious what it is.

Is this just an updated UnitIndexer or have you done something unique with this new post?

Edit: And you should really enable visitor messages, I wanted to suggest a nice book to you but I'm not going to make a github issue over it -_-
 
I've done something unique. This is Unit Indexer with local events.

Feel free to open the map and look at the last demo to see what I'm talking about.

Normally, you would do this by chaining up TriggerEvaluate.

In the past, this was done with if-statements.

Both of the above give incorrect behavior. Both of the above also add different types of overhead.


This has no extra overhead and has correct behavior ; ).
 
no, in the tuts/labs folder, the very last one

not the test cases >.>

you can run it and see what happens, although you won't get much ^)^. It's around 150 lines of lightweight code.

I don't really find that interesting. I guess I'll just keep not using unit indexers. Good luck :)
 
Well, I updated this to use the new BooleanExpression and Trigger libraries that allow you to run stuff in reverse order. This fixed the behavior problem the UnitIndex struct had with deindex events running in the incorrect order.

I changed the static ifs around to be a bit smarter (I discovered some super buggy jasshelper behavior /cry). I also added a GlobalUnitIndex module, which is much like the module from the original UnitIndexer.

So system runs a tad bit faster, code's a tad bit better, and the behavior is a tad bit smerter.

For BooleanExpression, I created a simple scripting language to test it. I also ran various tests on it for leaks and so forth to make sure that it had 0 leaks.

For Trigger, I just did a few simple tests since I only changed 2 lines, lmao. Was just making sure that I didn't have to change anything else ;D. The cool thing is that you can mix reversed and regular boolean expressions and triggers with each other O_O.

I updated the tutorial to show new correct behavior, fixed some typos, and made the last lab a little bit better. I also added a tutorial/lab 0 for GlobalUnitIndex.

I revamped the test case trigger to make it easier to run the test cases. The string is now dynamically generated and all you have to do is move x's around on some macros.


People may be asking why the drastic changes came about. Read http://www.hiveworkshop.com/forums/lab-715/events-revisited-252961/ ^)^. This is probably the only system that correctly handles events atm : ). I'll be doing DDS next. I'm really not sure what to do with UnitEvent because it is buggy as hell. Multiple undefend abilities will kill it. I'm also trying to detect hex on it, and the only way to detect it is to count the number of undefends.
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
so I have a question. How can you excuse the amount of code this has? Because remember we are in jass, and we dont need robustestestest code there is, we just need most of the time something that is functional. I dont know of anyone but you that ever gave a shit about local and global events. As long as the unit gets Indexed, I am fine, and so are 99.97% of users in Hive(made up statistics for the win!).

Because currently this has so much code in it that I really think its easier to just hook some natives
 
Level 10
Joined
Sep 19, 2011
Messages
527
so I have a question. How can you excuse the amount of code this has? Because remember we are in jass, and we dont need robustestestest code there is, we just need most of the time something that is functional. I dont know of anyone but you that ever gave a shit about local and global events. As long as the unit gets Indexed, I am fine, and so are 99.97% of users in Hive(made up statistics for the win!).

Because currently this has so much code in it that I really think its easier to just hook some natives

depends on what your needs are. pick what you need.
 
As Ruke pointed out, keep in mind that most of the code is in macro form and is in static ifs. This means that you only generate as much code as you need. If you need something crazy, then you can have it. If you don't, then you don't need it. This generates even less code than the original Unit Indexer does when using the GlobalUnitIndex struct (entire library + modules).
 
Status
Not open for further replies.
Top