Кодим функции: PrecacheForHero или как убрать модель error

  • Автор темы Автор темы Илья
  • Дата начала Дата начала

Илья

Друзья CG
25 Сен 2015
2,348
41
Оригинал здесь. CryDeS, спасибо, что ты есть :D
И конечно же спасибо Noya.

Здесь я лишь хочу разместить весь код в виде функции, чтобы в будущем к ней возвращаться, да и другим может пригодится. Почему именно отдельной функции? Да потому, чтобы не копировать один и тот же участок кода кучу раз.


Код:
--можно и не здесь, главное - это получить переменную "context"
function Precache( context ) 

-- грузим файл с модельками он уже лежит в исходниках доты, не парьтесь на его счет
local pathToIG = LoadKeyValues("scripts/items/items_game.txt") 

- самодельная функция, о которой идет речь. В качестве примера берем Undyinga
PrecacheForHero("npc_dota_hero_undying",pathToIG,context) 

end


function PrecacheForHero(name,path,context)


	print("----------------------------------------Precache Hero Start----------------------------------------") --для консоли

	local wearablesList = {} --"переменная для надеваемых шмоток(для всех героев)"
	local precacheWearables = {} --"переменная только для шмоток нужного героя"
	local precacheParticle = {}
	for k, v in pairs(path) do --лезем в файл, достаем шмоточки
		if k == 'items' then
			wearablesList = v
		end
	end
	local counter = 0 -- всякие счетчики
	local counter_particle = 0
	local value
	for k, v in pairs(wearablesList) do -- "выбираем из списка предметов только предметы на нужных героев"
		if IsForHero(name, wearablesList[k]) then
			if wearablesList[k]["model_player"] then
				value = wearablesList[k]["model_player"] 
				precacheWearables[value] = true
			end
			if wearablesList[k]["particle_file"] then -- "прекешируем еще и частицы, куда ж без них!"
				value = wearablesList[k]["particle_file"] 
				precacheParticle[value] = true
			end
		end
	end

--"собственно само прекеширование всех занесенных в список шмоток"
	for wearable,_ in pairs( precacheWearables ) do 
		print("Precache model: " .. wearable)
		PrecacheResource( "model", wearable, context )
		counter = counter + 1
	end

--"и прекеширование частиц"
	for wearable,_ in pairs( precacheParticle) do 
		print("Precache particle: " .. wearable)
		PrecacheResource( "particle", wearable, context )
		counter_particle = counter_particle + 1

	end

 -- "прекешируем саму модель героя! иначе будут бегать шмотки без тела"
	PrecacheUnitByNameSync(name, context)
		
  print('[Precache]' .. counter .. " models loaded and " .. counter_particle .." particles loaded")
  print('[Precache] End')

end

-- "привет от вашего друга, индийского быдлокодера работающего за еду"
function IsForHero(str, tbl)
	if type(tbl["used_by_heroes"]) ~= type(1) and tbl["used_by_heroes"] then 
		if tbl["used_by_heroes"][str] then
			return true
		end
	end
	return false
end
 
Последнее редактирование модератором:
Пытаюсь использовать PrecacheUnitByNameAsync, чтобы не добавлять этот код, т.к. я не знаю, каких именно героев мне надо прекешировать. Загвоздка в том, что мне надо после инициализации перса свапнуть абилки(SwapAbilities). Есть идеи как заставить работать одно с другим?

Код:
PrecacheUnitByNameAsync(heroName, function()
  hero = CreateHeroForPlayer(heroName, player)
  for k=0,3 do
    abilityOld = hero:GetAbilityByIndex(k):GetName() //беру название старой абилки
    abilityNew = GetFromCustomNetTables("players", pID, (k + 1)) //забираю название новой абилки из таблицы, которую предварительно создал
    DebugPrint(abilityNew) //выводит пустоту
    hero:AddAbility(abilityNew) //добавляю герою новую абилку не удаляя старую
    hero:SwapAbilities(abilityOld, abilityNew, false, true) //делаю свап
  end
end, pID)

Консоль выдает вот это:
Код:
[ W Entity System    ]: Cannot create an entity because entity class is NULL -1
[  Developer      ]: AddAbility - Failed to create ability .

Данное действие выполняется на стадии выбора героя, т.е. HERO_SELECTION.

Если не использовать такой прекеш, то абилки добавляются нормально, но нет самой модели.
 
Последнее редактирование модератором:
[quote author=M@G link=topic=314.msg1685#msg1685 date=1444408209]

Консоль выдает вот это:
Код:
[ W Entity System    ]: Cannot create an entity because entity class is NULL -1
[  Developer      ]: AddAbility - Failed to create ability .

[/quote]


А на какую именно строчку жалуется? Я так понимаю,что на эту:

Код:
 hero:AddAbility(abilityNew) //добавляю герою новую абилку не удаляя старую

Если можешь, то скинь лог побольше.

И поконкретнее, в чем идея? А то я не очень понял, что в итоге должно получиться.
 
И т.к. пишет это:
Код:
Cannot create an entity because entity class is NULL -1

То скорее всего еще и в этом проблема:
Код:
hero = CreateHeroForPlayer(heroName, player)
 
Что пока имеем:

void PrecacheUnitByNameAsync(string string_1, handle handle_2, int int_3)

void PrecacheUnitByNameSync(string string_1, handle handle_2, int int_3)

Одинаковые функции, что различаются лишь способом загрузки фалов. Значит, можно тот же Sync заменить на Async в функции, что в первом посту данной темы.
Однако, стоит заметить, что почему-то (я на это не обратил внимание еще тогда) Noya использует такую функцию:

(1)PrecacheUnitByNameSync(name, context)

В ней всего два аргумента - имя нпс и переменная context, что береться отсюда :


Ни про (1), ни про (2) ничего нет тут. Поэтому, факт их работы и отсутствие знаний оставляет лишь нам принять это, как есть: т.е. соблюдать подобную модель манипуляций с ними.

Далее, heroName - имя нпс, персонажа из доты. Мгм. Ну, в нем проблем быть не должно, поэтому первый параметр в этой функции удовлетворяется точно:

handle CreateHeroForPlayer(string unitName, handle player)

Значит, раз тебе пишет о
Код:
Cannot create an entity because entity class is NULL -1

А у тебя только CreateHeroForPlayer создает entity, то проблема во втором параметре: player.
 
Смотрим дальше:

void AddAbility(string pszAbilityName)

Ну понятно, тут проблем не должно возникнуть, ибо функция требует только строковую переменную, т.е. вряд ли ты ошибся в имени абилки. Значит, дело в том, у какого объекта ты вызываешь эту функцию. А это наш

hero = CreateHeroForPlayer(heroName, player)

Собственно, то, с чего все и начиналось.
 
Надеюсь я тебе помог своими рассуждениями. Хотя бы знаем, где должна быть ошибка.

Но меня все не покидает вопрос твоей идеи:

Стадия "DOTA_GAMERULES_STATE_HERO_SELECTION", так?

То есть, у нас есть только сам player, без каких либо unit.
Далее у меня в наличии только лишь одна функция, кусок кода, по которому я догадываюсь, что ты создаешь игроку персонажа, основываясь на выборе игрока. Меняешь ему абилки и делаешь подгрузку. Все в одном месте.

Кроме того, по комменту:
//забираю название новой абилки из таблицы, которую предварительно создал

Я догадываюсь, что ты либо знаешь, что это за абилки: тогда, пфф, подгрузи героев, которые в доте используют эти абилки).
Либо ты знаешь что-то вроде их id-ников, т.е. в теории можешь выйти через них на тех самых героев.


Если исходить из позиции красоты:
Вся подгрузка, насколько я знаю, обычно делается именно в addon_game_mode.lua в "function Precache( context )".
Если судить о том, что когда мы жестко задаем игроку конкретного персонажа на стадии "...HERO_SELECTION", то на выходе получаем модельку "error", то, где-то после этой стадии, или на ней осуществляется подгрузка моделей.

Однако, устанавливая примитивный print() для консоли в функции "function Precache( context )", мы осознаем, что все это делается в момент, перед стадией выбора игроками команды. Не в игре, а до игры, после прогрузки хоста.


Но т.к. ты подгружешь именно в момент создания героя, то я предполагаю, что ты смотришь этот код. А именно, функцию :
function GameMode:OnHeroInGame(hero)


Если нет, то глянь ее. может, поможет. Если да, то опять же, надо в ней копаться)

Заметь, там подгрузка идет в момент спавна, а не в момент выбора.
 
Последнее редактирование модератором:
Спасибо. Вроде получилось обойтись без масс-прекеша. Смотрел здесь.
Вкратце: надо делать асинхронный прекеш юнита на стадии пре-гейма, а абилки менять при спавне. Единственное, пришлось вместо свапа использовать обычное удаление/добавление, причем в разных циклах.

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

Хотя я так и не понял, что именно у тебя за идея ;D
 
Теперь у курьера моделька ERROR. Ее надо отдельно прекешировать? Пробовал что-то вроде:
Код:
PrecacheUnitByNameAsync( "npc_dota_courier", function()
  end, pID )
но не помогает.

Хотя мне казалось, что если кешируешь героя с айдишником, то и все остальные слоты на него также должны кешироваться.
 
Последнее редактирование модератором:
Теперь у курьера моделька ERROR.
Все оказалось проще.

Код:
PrecacheResource("model_folder", "models/courier/", context)
Кеширует всех курьеров, на время загрузки мода не влияет, т.к. их там не так уж много.

Ссылка
 
Последнее редактирование модератором:
Реклама: