CustomGames.ru - Dota 2 пользовательские игры

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

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн Илья

  • Супермодератор
  • 1904
  • Мощь: 16
Оригинал здесь.  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

« Последнее редактирование: 19-10-2015, 00:21:57 от Илья »

Оффлайн M@G

  • Продвинутый
  • 63
  • Мощь: 0
Пытаюсь использовать 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.

Если не использовать такой прекеш, то абилки добавляются нормально, но нет самой модели.
« Последнее редактирование: 09-10-2015, 16:32:18 от M@G »

Оффлайн Илья

  • Супермодератор
  • 1904
  • Мощь: 16

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



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

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

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

И поконкретнее, в чем идея?  А то я не очень понял, что в итоге должно получиться.
« Последнее редактирование: 09-10-2015, 17:01:44 от Илья »

Оффлайн M@G

  • Продвинутый
  • 63
  • Мощь: 0
А на какую именно строчку жалуется?
В том то и дело, что ни на какую.

Оффлайн Илья

  • Супермодератор
  • 1904
  • Мощь: 16
И т.к. пишет это:
Код
Cannot create an entity because entity class is NULL -1

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

Оффлайн Илья

  • Супермодератор
  • 1904
  • Мощь: 16
Что пока имеем:

Цитировать
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, что береться отсюда :

Цитировать
(2)Precache(context)

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

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

Цитировать
handle CreateHeroForPlayer(string unitName, handle player)

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

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

Оффлайн Илья

  • Супермодератор
  • 1904
  • Мощь: 16
Смотрим дальше:

Цитировать
void AddAbility(string pszAbilityName)

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

Цитировать
hero = CreateHeroForPlayer(heroName, player)

Собственно, то, с чего все и начиналось.

Оффлайн Илья

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

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

Стадия "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)


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

Заметь, там подгрузка идет в момент спавна, а не в момент выбора.
« Последнее редактирование: 09-10-2015, 18:11:08 от Илья »

Оффлайн M@G

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

И да, ты был прав, когда говорил про код петров. Я смотрел и туда, но это же не единственный источник.
« Последнее редактирование: 10-10-2015, 13:33:21 от M@G »

Оффлайн Илья

  • Супермодератор
  • 1904
  • Мощь: 16
Ну, хорошо, что все хорошо кончилось и у тебя все удалось.

Хотя я так и не понял, что именно у тебя за идея  ;D

Оффлайн M@G

  • Продвинутый
  • 63
  • Мощь: 0
Теперь у курьера моделька ERROR. Ее надо отдельно прекешировать? Пробовал что-то вроде:
Код
PrecacheUnitByNameAsync( "npc_dota_courier", function()
    end, pID )
но не помогает.

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

Оффлайн M@G

  • Продвинутый
  • 63
  • Мощь: 0
Теперь у курьера моделька ERROR.
Все оказалось проще.

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

Ссылка