Путем отладки мне удалось найти функцию из-за которой мои герои внезапно удаляются. Ниже приведен код функции в которой это происходит - DummyDealExtraDamage и на всякий случай сверху вставлю функцию отложенного удаления юнита.
Отладка показывает что именно эта функция пытается удалить героя на месте вызова DelayedUnitRemove, хотя туда отчетливо подается dummy и только, причем дамми который был создан пару строчек назад. Как туда мог попасть герой - не понятно.
Баг проявляется отнюдь не всегда, в 1 из 15 случаев примерно. И не у всех персонажей, использующих DummyDealExtraDamage.
Есть какие-то предположения?
	void DelayedUnitRemove(unit u, float time, string fname, string moduleName)
	{
		if (time == 0.00)
		{
			RemoveUnit_s(u, fname, moduleName);
			u = null;
			return;
		}
		timer t = CreateTimer();
		SaveUnitHandle(g_Hashtable, GetHandleId(t), T_UNIT, u);
		SaveStr(g_Hashtable, GetHandleId(t), T_UNIT+1, fname);
		SaveStr(g_Hashtable, GetHandleId(t), T_UNIT+2, moduleName);
		TimerStart(t, time, false, lambda void ()
		{
			timer t = GetExpiredTimer();
			unit u = LoadUnitHandle(g_Hashtable, GetHandleId(t), T_UNIT);
			string fname = LoadStr(g_Hashtable, GetHandleId(t), T_UNIT+1);
			string moduleName = LoadStr(g_Hashtable, GetHandleId(t), T_UNIT+2);
			RemoveUnit_s(u, fname, moduleName);
			DestroyTimer(t);
			u = null;
			t = null;
		});
		t = null;
		u = null;
	}
	
	
	void DummyDealExtraDamage(unit src, unit target, float dmg, int school, bool canBeReturned)
	{
		if (IsUnitDummy(src))
		{
			src = GetDummyOwningUnit(src);
			DummyDealExtraDamage(src, target, dmg, school, canBeReturned);
			src = null;
			target = null;
			return;
		}
		location loc = GetUnitLoc(src);
		unit dummy = CreateDummy(GetOwningPlayer(src), src, loc);
		SetDummyExtraDamage(dummy);
		if (!canBeReturned)
		{
			SetDummyReturnDamage(dummy);
		}
		DummyDealDamage(dummy, target, dmg, school);
		DelayedUnitRemove(dummy, 0.2, "DummyDealExtraDamage", "Dummy");
		RemoveLocation(loc);
		loc = null;
		dummy = null;
		src = null;
		target = null;
	}

Точно больше 100500 утечек нет? Эт хз как же надо было забить хт чтобы такое приключилось?
`
ОЖИДАНИЕ РЕКЛАМЫ...
23
Похожие вопросы:

ответ
Группы юнитов + хэш или структуры. При касте спелла берешь кастера, берешь его ID, проверяешь не записана ли группа в какой-либо из ячеек. Если нет - создаешь группу и записываешь её в ячейку. При смерти юнита делаешь проверку не записана ли по его ID группа юнитов - если записана - удаляешь его и проверяешь количество юнитов в группе и если оно равно 0 - удаляешь группу. Естественно хэш тоже чистишь всюду где нужно.

Это звучит как "Сделайте мне пожалуйста систему формаций". Чтобы научить тебя как это сделать придётся потратить несколько десятков часов. И тут 2 варианта: либо ты будешь читать статьи и выучишь всё сам, либо обращайся к отдельным пользователям и проси о приватных, платных, уроках в частном порядке.
Вопрос вообще ни о чём. То, о чём ты спрашиваешь делается за 20-30 минут + несколько часов на всякие плюшки и дебаг (в худшем случае).
Конкретно тебе стоит почитать о Локальных переменных, Хэше или Структурах.
ответ
Юзай XT + структуры.
Лично я ХТ использую только для связи инстанции структуры и таймера.

28
IsUnitDummy(src)
GetDummyOwningUnit(src)
CreateDummy(GetOwningPlayer(src), src, loc)
Что внутри этих функций?

Тут используются дефайны?
15
PT153:
IsUnitDummy(src)
GetDummyOwningUnit(src)
CreateDummy(GetOwningPlayer(src), src, loc)
Что внутри этих функций?
bool IsUnitDummy(unit u)
	{
		if (u == null || IsUnitType(u, UNIT_TYPE_HERO))
		{
			if (IsUnitType(u, UNIT_TYPE_HERO))
			{
				GroupRemoveUnit(g_Dummies, u);
			}
			return false;
		}
		return IsUnitInGroup(u, g_Dummies);
	}
	
	unit GetDummyOwningUnit(unit dummy)
	{
		if (dummy == null)
		{
			return null;
		}
		return LoadUnitHandle(g_Hashtable, GetHandleId(dummy), DUMMY_OWNER);
	}

unit CreateDummy(player owner, unit uOwner, location loc)
	{
		unit dummy = CreateUnitAtLoc(owner, 'n001', loc, GetUnitFacing(uOwner));
		SaveUnitHandle(g_Hashtable, GetHandleId(dummy), DUMMY_OWNER, uOwner);
		SaveBoolean(g_Hashtable, GetHandleId(dummy), DUMMY_RETURN_DMG, false);
		SaveBoolean(g_Hashtable, GetHandleId(dummy), DUMMY_EXTRA_DMG, false);
		SaveBoolean(g_Hashtable, GetHandleId(dummy), DUMMY_DO_PERIODIC, false);
		SaveReal(g_Hashtable, GetHandleId(dummy), DUMMY_DMG_PERIOD, 0);
		SetDummySpellId(dummy, 0);
		SetDummySchool(dummy, SCHOOL_NONE);
		SetUnitPathing(dummy, false);
		GroupAddUnit(g_Dummies, dummy);
		owner = null;
		uOwner = null;
		loc = null;
		return dummy;
	}

PT153:
Тут используются дефайны?
Все что сплошным капсом - это дефайны.
28
У DUMMY_OWNER и T_UNIT разные значения?

Я тут пока смотрел, заметил, что ты вообще не чистишь хеш. Ни для таймера уделения, ни для самого даммика. Стоит исправить это.
Аргументы функций обнулять не нужно.

Я не вижу ни одной причины, почему тут может удалятся герой. Думал на отсутствие очистки хеша, но ведь после создания таймера ячейка перезаписывается, то есть там хранится уже даммик. Может ты скопипастил, а потому в действительно ошибочной функции стоит название этой функции?
15
PT153:
У DUMMY_OWNER и T_UNIT разные значения?

Я тут пока смотрел, заметил, что ты вообще не чистишь хеш. Ни для таймера уделения, ни для самого даммика. Стоит пока исправить это.
Аргументы функций обнулять не нужно.

Я не вижу ни одной причины, почему тут может удалятся герой. Думал на отсутствие очистки хеша, но ведь после создания таймера ячейка перезаписывается, то есть там хранится уже даммик. Может ты скопипастил и где-то ввёл неверное название функции?
DUMMY_OWNER = 150
T_UNIT = 159
Упс, а хеш-таблицы надо чистить? Не ну это уже совсем дичь. Код захламится на треть очисткой хеш-таблицы. У меня сотни мест где я её использую и не чищу вообще. Ну потому что это уже через чур, и переменные обнулять, и ладно ресурсы удалять, но хеш чистить эт перебор, ненене, работает так и норм. Пусть он в памяти будет толстенный, как-нибудь переживу. Размер на логичность поведения влиять не должен, не 4 гб же там в памяти. Все равно пишет в одни и те же ячейки, перезаписывая.
Я проверил, нигде нет этого названия. Я не копипастил лишнее, баг именно в этой функции.
28
Упс, а хеш-таблицы надо чистить?
Надо. Благо есть такая функция.
native FlushChildHashtable takes hashtable table, integer parentKey returns nothing
Скармливаешь хендл таймера или даммика, и все записанные поля обнуляются.
15
PT153:
Упс, а хеш-таблицы надо чистить?
Надо. Благо есть такая функция.
native FlushChildHashtable takes hashtable table, integer parentKey returns nothing
Скармливаешь хендл таймера или даммика, и все записанные поля обнуляются.
Тогда это всё упрощает, очистку хештейбла запихну в функцию безопасного удаления юнита, и сделаю такую же функцию для таймеров, и можно считать что таблица очищена от лишнего.
28
Было бы неплохо глянуть на тру JASS (то есть уже после обработки cJass) функций, что в шапке.
15
PT153:
Было бы неплохо глянуть на тру JASS (то есть уже после обработки cJass) функций, что в шапке.
Странно, но когда я добавил очистку очистку хеш-таблицы к удалению таймеров и юнитов этот баг перестал появляться)
32
Точно больше 100500 утечек нет? Эт хз как же надо было забить хт чтобы такое приключилось?
Принятый ответ
Чтобы оставить комментарий, пожалуйста, войдите на сайт.