Добавлен , опубликован
Алгоритмы, Наработки и Способности
Способ реализации:
Jass
Тип:
Алгоритм
Версия Warcraft:
1.21+

Вступление

Для чего эта наработка?

Фактически, данная наработка - это давняя моя фантазия, а точнее возможность иметь полноценный API групп не только для объектов типа unit, а по нужде расширять и для других объектов тоже. В итоге вышла вот такая вот короткая, но полезная наработка. Которую конечно же можно расширять и улучшать по мере нужды и без нужды в МемХаке, что и делает её столь прелестной.

Какие минусы у наработки?

Фактически единственный минус - это псевдо-реализация путём Хешатаблицы, заместо прямого использования группы. Так как единственная причина, по которой CreateGroup вообще используется - это чтобы получить уникальный хендл и не более. Остальные минусы - это подводные камни, которые ещё могут всплыть, ну и возможно несколько "ужатые" возможности, ибо нет возможность использовать GroupEnum эффективно или же ForGroup (вообще).

Для наработки необходим МемХак?

Нет! В этом и вся прелесть.

API

Базовые функции
globals
	hashtable PseudoGroupTable = InitHashtable( )
endglobals

function InitPseudoGroupVariables takes nothing returns nothing
	// supported handle types

	call SaveInteger( PseudoGroupTable, 'type', 'hndl', 0 )
	call SaveInteger( PseudoGroupTable, 'type', 'item', 1 )

	// variable types
	// 'size' = group size
	// 'iter' = group iterator
endfunction

function CreatePseudoGroup takes integer gtype returns group
	local group g = CreateGroup( )
	local integer hid = GetHandleId( g )

	call SaveGroupHandle( PseudoGroupTable, hid, gtype, g )
	set g = null
	return LoadGroupHandle( PseudoGroupTable, hid, gtype )
endfunction

function ClearPseudoGroup takes group g, integer gtype returns boolean
	local integer hid = GetHandleId( g )

	if g != null and g == LoadGroupHandle( PseudoGroupTable, hid, gtype ) then
		call FlushChildHashtable( PseudoGroupTable, hid )
		call GroupClear( g )
		return true
	endif

	return false
endfunction

function DestroyPseudoGroup takes group g, integer gtype returns nothing
	if ClearPseudoGroup( g, gtype ) then
		call DestroyGroup( g )
	endif
endfunction
Unit Group API
function CreateUnitGroup takes nothing returns group
	return CreatePseudoGroup( 'unit' )
endfunction

function ClearUnitGroup takes group g returns nothing
	call ClearPseudoGroup( g, 'unit' )
endfunction

function DestroyUnitGroup takes group g returns nothing
	call DestroyPseudoGroup( g, 'unit' )
endfunction

function GroupHasUnitEx takes group g, unit u returns boolean
	local integer i = 0
	local integer hid = GetHandleId( g )
	local unit u_temp = null
	local integer size = LoadInteger( PseudoGroupTable, hid, 'size' )
	local boolean result = false

	if g != null and u != null and g == LoadGroupHandle( PseudoGroupTable, hid, 'unit' ) then
		loop
			set u_temp = LoadUnitHandle( PseudoGroupTable, hid, i )
			exitwhen u_temp == u or i > size
			set i = i + 1
		endloop

		set result = u_temp == u
	endif

	return result
endfunction

function GroupAddItemEx takes group g, unit u returns nothing
	local integer i = 0
	local integer hid = GetHandleId( g )
	local integer size = LoadInteger( PseudoGroupTable, hid, 'size' )
	local unit u_temp = null

	if g != null and u != null and g == LoadGroupHandle( PseudoGroupTable, hid, 'unit' ) then
		if not GroupHasUnitEx( g, u ) then
			loop
				set u_temp = LoadUnitHandle( PseudoGroupTable, hid, i )
				exitwhen u_temp == null
				set i = i + 1
			endloop
		endif

		call SaveInteger( PseudoGroupTable, hid, 'size', size + 1 )
		call SaveUnitHandle( PseudoGroupTable, hid, i, u )
	endif

	set u_temp = null
	set g = null
endfunction

function GroupRemoveUnitEx takes group g, unit u returns nothing
	local integer i = 0
	local integer hid = GetHandleId( g )
	local integer size = LoadInteger( PseudoGroupTable, hid, 'size' )
	local unit u_temp = null

	if g != null and u != null and g == LoadGroupHandle( PseudoGroupTable, hid, 'unit' ) then
		loop
			set u_temp = LoadUnitHandle( PseudoGroupTable, hid, i )
			exitwhen u_temp == u or i > size
			set i = i + 1
		endloop

		if u_temp == u then
			loop
				exitwhen i == size
				call RemoveSavedHandle( PseudoGroupTable, hid, i )
				call SaveUnitHandle( PseudoGroupTable, hid, i, LoadUnitHandle( PseudoGroupTable, hid, i + 1 ) )
				set i = i + 1
			endloop

			call SaveInteger( PseudoGroupTable, hid, 'size', size - 1 )
		endif
	endif

	set u_temp = null
	set g = null
endfunction

function GetUnitFromGroupByIndexEx takes group g, integer index returns unit
	local integer hid = GetHandleId( g )
	local integer size = LoadInteger( PseudoGroupTable, hid, 'size' )

	if g != null and g == LoadGroupHandle( PseudoGroupTable, hid, 'unit' ) and index < size then
		return LoadUnitHandle( PseudoGroupTable, GetHandleId( g ), index )
	endif

	return null
endfunction

function ForEachUnitEx takes group g returns unit
	local integer hid = GetHandleId( g )
	local integer iterator = LoadInteger( PseudoGroupTable, hid, 'iter' )
	local integer size = LoadInteger( PseudoGroupTable, hid, 'size' )

	if g != null and g == LoadGroupHandle( PseudoGroupTable, hid, 'unit' ) then
		if iterator < size then
			call SaveInteger( PseudoGroupTable, hid, 'iter', iterator + 1 )
			return LoadUnitHandle( PseudoGroupTable, hid, iterator )
		else
			call SaveInteger( PseudoGroupTable, hid, 'iter', 0 )
		endif
	endif

	return null
endfunction
Item Group API
function CreateItemGroup takes nothing returns group
	return CreatePseudoGroup( 'item' )
endfunction

function ClearItemGroup takes group g returns nothing
	call ClearPseudoGroup( g, 'item' )
endfunction

function DestroyItemGroup takes group g returns nothing
	call DestroyPseudoGroup( g, 'item' )
endfunction

function GroupHasItem takes group g, item it returns boolean
	local integer i = 0
	local integer hid = GetHandleId( g )
	local item it_temp = null
	local integer size = LoadInteger( PseudoGroupTable, hid, 'size' )
	local boolean result = false

	if g != null and it != null and g == LoadGroupHandle( PseudoGroupTable, hid, 'item' ) then
		loop
			set it_temp = LoadItemHandle( PseudoGroupTable, hid, i )
			exitwhen it_temp == it or i > size
			set i = i + 1
		endloop

		set result = it_temp == it
	endif

	set it_temp = null
	return false
endfunction

function GroupAddItem takes group g, item it returns nothing
	local integer i = 0
	local integer hid = GetHandleId( g )
	local integer size = LoadInteger( PseudoGroupTable, hid, 'size' )
	local item it_temp = null

	if g != null and it != null and g == LoadGroupHandle( PseudoGroupTable, hid, 'item' ) then
		if not GroupHasItem( g, it ) then
			loop
				set it_temp = LoadItemHandle( PseudoGroupTable, hid, i )
				exitwhen it_temp == null
				set i = i + 1
			endloop
		endif

		call SaveInteger( PseudoGroupTable, hid, 'size', size + 1 )
		call SaveItemHandle( PseudoGroupTable, hid, i, it )
	endif

	set it_temp = null
	set g = null
endfunction

function GroupRemoveItem takes group g, item it returns nothing
	local integer i = 0
	local integer hid = GetHandleId( g )
	local integer size = LoadInteger( PseudoGroupTable, hid, 'size' )
	local item it_temp = null

	if g != null and it != null and g == LoadGroupHandle( PseudoGroupTable, hid, 'item' ) then
		loop
			set it_temp = LoadItemHandle( PseudoGroupTable, hid, i )
			exitwhen it_temp == it or i > size
			set i = i + 1
		endloop

		if it_temp == it then
			loop
				exitwhen i == size
				call RemoveSavedHandle( PseudoGroupTable, hid, i )
				call SaveItemHandle( PseudoGroupTable, hid, i, LoadItemHandle( PseudoGroupTable, hid, i + 1 ) )
				set i = i + 1
			endloop

			call SaveInteger( PseudoGroupTable, hid, 'size', size - 1 )
		endif
	endif

	set it_temp = null
	set g = null
endfunction

function GetItemFromGroupByIndex takes group g, integer index returns item
	local integer hid = GetHandleId( g )
	local integer size = LoadInteger( PseudoGroupTable, hid, 'size' )

	if g != null and g == LoadGroupHandle( PseudoGroupTable, hid, 'item' ) and index < size then
		return LoadItemHandle( PseudoGroupTable, GetHandleId( g ), index )
	endif

	return null
endfunction

function ForEachItem takes group g returns item
	local integer hid = GetHandleId( g )
	local integer iterator = LoadInteger( PseudoGroupTable, hid, 'iter' )
	local integer size = LoadInteger( PseudoGroupTable, hid, 'size' )

	if g != null and g == LoadGroupHandle( PseudoGroupTable, hid, 'item' ) then
		if iterator < size then
			call SaveInteger( PseudoGroupTable, hid, 'iter', iterator + 1 )
			return LoadItemHandle( PseudoGroupTable, hid, iterator )
		else
			call SaveInteger( PseudoGroupTable, hid, 'iter', 0 )
		endif
	endif

	return null
endfunction
Effect Group API
function CreateEffectGroup takes nothing returns group
	return CreatePseudoGroup( 'efct' )
endfunction

function ClearEffectGroup takes group g returns nothing
	call ClearPseudoGroup( g, 'efct' )
endfunction

function DestroyEffectGroup takes group g returns nothing
	call DestroyPseudoGroup( g, 'efct' )
endfunction

function GroupHasEffect takes group g, effect ef returns boolean
	local integer i = 0
	local integer hid = GetHandleId( g )
	local effect ef_temp = null
	local integer size = LoadInteger( PseudoGroupTable, hid, 'size' )
	local boolean result = false

	if g != null and ef != null and g == LoadGroupHandle( PseudoGroupTable, hid, 'efct' ) then
		loop
			set ef_temp = LoadEffectHandle( PseudoGroupTable, hid, i )
			exitwhen ef_temp == ef or i > size
			set i = i + 1
		endloop

		set result = ef_temp == ef
	endif

	set ef_temp = null
	return false
endfunction

function GroupAddEffect takes group g, effect ef returns nothing
	local integer i = 0
	local integer hid = GetHandleId( g )
	local integer size = LoadInteger( PseudoGroupTable, hid, 'size' )
	local effect ef_temp = null

	if g != null and ef != null and g == LoadGroupHandle( PseudoGroupTable, hid, 'efct' ) then
		if not GroupHasEffect( g, ef ) then
			loop
				exitwhen not HaveSavedHandle( PseudoGroupTable, hid, i )
				set i = i + 1
			endloop

			call SaveInteger( PseudoGroupTable, hid, 'size', size + 1 )
			call SaveEffectHandle( PseudoGroupTable, hid, i, ef )
		endif
	endif

	set ef_temp = null
	set g = null
endfunction

function GroupRemoveEffect takes group g, effect ef returns nothing
	local integer i = 0
	local integer hid = GetHandleId( g )
	local integer size = LoadInteger( PseudoGroupTable, hid, 'size' )
	local effect ef_temp = null

	if g != null and ef != null and g == LoadGroupHandle( PseudoGroupTable, hid, 'efct' ) then
		loop
			set ef_temp = LoadEffectHandle( PseudoGroupTable, hid, i )
			exitwhen ef_temp == ef or i > size
			set i = i + 1
		endloop

		if ef_temp == ef then
			loop
				exitwhen i == size
				call RemoveSavedHandle( PseudoGroupTable, hid, i )
				call SaveEffectHandle( PseudoGroupTable, hid, i, LoadEffectHandle( PseudoGroupTable, hid, i + 1 ) )
				set i = i + 1
			endloop

			call SaveInteger( PseudoGroupTable, hid, 'size', size - 1 )
		endif
	endif

	set ef_temp = null
	set g = null
endfunction

function GetEffectFromGroupByIndex takes group g, integer index returns effect
	local integer hid = GetHandleId( g )
	local integer size = LoadInteger( PseudoGroupTable, hid, 'size' )

	if g != null and g == LoadGroupHandle( PseudoGroupTable, hid, 'efct' ) and index < size then
		return LoadEffectHandle( PseudoGroupTable, GetHandleId( g ), index )
	endif

	return null
endfunction

function ForEachEffect takes group g returns effect
	local integer hid = GetHandleId( g )
	local integer iterator = LoadInteger( PseudoGroupTable, hid, 'iter' )
	local integer size = LoadInteger( PseudoGroupTable, hid, 'size' )

	if g != null and g == LoadGroupHandle( PseudoGroupTable, hid, 'efct' ) then
		if iterator < size then
			call SaveInteger( PseudoGroupTable, hid, 'iter', iterator + 1 )
			return LoadEffectHandle( PseudoGroupTable, hid, iterator )
		else
			call SaveInteger( PseudoGroupTable, hid, 'iter', 0 )
		endif
	endif

	return null
endfunction

Код

`
ОЖИДАНИЕ РЕКЛАМЫ...
2
27
2 года назад
2
а u_temp не будет утекать в функции GroupHasUnitEx?

в остальных функциях оно обнуляется даже при условии что перед присвоением null оно и так будет null
2
20
2 года назад
Отредактирован Unryze
2
а u_temp не будет утекать в функции GroupHasUnitEx?
Как я и писал в Jass Myth Busters, утекает не банальное присвоение, а только создание объекта и выдача его референса в локалку.

в остальных функциях оно обнуляется даже при условии что перед присвоением null оно и так будет null
Ну, 10 нс +- это затрагивает, если очень брезгует u_temp можно заменить на bj_lastCreatedUnit при желании или на свою глобалку. Но утечек там быть не должно и не может быть.
Но не суть, сейчас внесу правку.
Поправка: код поправлен.
2
15
2 года назад
2
Равкоды много где повторяются, было бы правильно вынести их в константу.
3
20
2 года назад
3
Равкоды много где повторяются, было бы правильно вынести их в константу.
Я не фанат лишних переменных, да и эти равкоды для строго внутреннего использования, потому смысла не имеет.
2
15
2 года назад
2
Unryze, разве константы в vJass ведут себя как обычные переменные, а не подставляются препроцессором?
0
27
2 года назад
0
JackFastGame, дефайны сджасса подставляются
0
37
2 года назад
0
vJass optimizer тоже инлайнит и мелкие функции в том числе
0
12
2 года назад
0
Похоже никто не оценил и не понял в чем суть и полезность системы.
0
27
2 года назад
0
Daro, наверное потому что большинство, кому пригодилось бы такое, уже написали на циклах/хэштаблицах
0
28
2 года назад
0
ScorpioT1000, константы не инлайнит. Их инлайнит map optimizer.
0
32
2 года назад
0
Похоже никто не оценил и не понял в чем суть и полезность системы.
Поддержка патча 1.21
2
20
2 года назад
2
Похоже никто не оценил и не понял в чем суть и полезность системы.
Поддержка патча 1.21
хе-хе, хи-хи (спутал немного цифры), система в общем для версий с которых появилась хештаблица. Не знаю почему подумал про 1.21.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.