Импортирование моделей в карту Dota 2 без косметических предметов

Многие имеют представление о том, что можно импортировать модели в кастомные карты, но не знают и не понимают с чего начать. Как правильно сделать анимацию и импортировать её для моделей, как импортировать текстуру для модели, как создать своего героя, без всяких там косметических предметов. И как же проделать всё это с .mdx форматом, который родом из Warcraft 3,  ведь многие хотят сделать порт карты из WarCraft 3 в Source 2.


Этот гайд будет в основном сосредоточен на импорте .mdx модели в движок Source 2 для использования на герое. Но некоторые пункты из урока можно будет использовать с другими моделями, юнитами и прочими ассетами, если имеется базовая модель и готова анимация. 

Авторство:

  • Dun1007, за импортирование .mdx в Source 2;
  • Tailer007, за модели в этом уроке (не уверен, кто именно оригинальный моделлер);
  • BMD, за скрипт таймера;
  • CustomGames.ru, за перевод урока.

Требуемые материалы:

  • Dota 2
  • Dota 2 Workshop Tools
  • 3ds Max
  • timers.lua, можно найти здесь
  • Модель. В примерах я буду использовать модель Asuna из SAO.
  • impexpmdx_v2.0.4.ms, потребуется только для .mdx формата.
  • Warcraft 3 Model editor, он потребуется только для .mdx формата, можно взять здесь
  • GCFScape, для вскрытия vpk архива.

Содержимое

Шаг 1: Подготовка Модели к MDX формату
Шаг 2: Импортирование и Экспортирование в 3ds Max
Шаг 3: Выбор Текстур
Шаг 4: Настройка Source 2 Model Editor
Шаг 5: Настройка Материалов
Шаг 6: Настройка Базовой Модели
Шаг 7: Импортирование Анимации
Шаг 8: Точки Крепления (Attachment Points)
Шаг 9: Удаляем косметические предметы с героя с помощью скрипта
Шаг 10-1: Оптимизация. Часть 1: Подготовка KV (ключ-значение) Файлов
Шаг 10-2: Оптимизация. Часть 2: Lua Скриптинг

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



 

Если модель уже в формате .FBX с анимацией - эту часть можно пропустить.

Шаг 1: Подготовка к формату MDX

После того, как все необходимые материалы готовы, поместите скрипт impexmdx_v2.0.4.ms в C:\...\Autodesk\3ds Max\scripts\Startup. Это позволит вам импортировать в 3Ds Max модель формата MDX. 



 

Шаг 2: Импортирование и Экспортирование в 3Ds Max

Для других форматов моделей, вы можете просто импортировать их с помощью кнопки импорта в главном меню и перейти к 5 шагу. Формат MDX вы можете импортировать следующими действиями: 

1. Запускаем 3ds Max. 
2. Нажимаем на кнопку молота в правом углу. 
3. Нажимаем на MAXScript. 
4. Кликаем в раскрывшемся меню "Utilities" и выбериаем "MDX Importer/Exporter"

Шаги показаны на изображении ниже:


 

Используйте следующие настройки перед импортом. Очень важно, чтобы галочка не стояла на "Import as M3”. В противном случае, вы не увидите скелет в редакторе моделей Source 2.

 

5. Нажмите на кнопку "Import MDX..." и выберите файл MDX.
6. Выделите все меши, кости, и освещение в сцене или нажмите Ctrl + A.
7. Перейдите к меню и выберите команду Export.
8. Экспортируйте файл в формате FBX. Не забудьте снять галочку с "Animation". То, что мы экспортировали - это базовая модель для вашего героя.
9. Экспортируйте файл еще раз, но на этот раз с пунктом "Animation”. Этот файл уже будет для анимации вашего героя. Для другой модели вам, возможно, придется сделать свою собственную анимацию в 3ds Max или импортировать её из других форматов, а затем экспортировать.



 

Шаг 3: Получение текстур

Теперь у вас есть своя модель, но она без текстуры. Возможно, что рядом с вашей моделью .mdx уже лежат текстуры .tga, .bmp или т.п. Если вы сделаете свой собственный материал в 3ds Max, то вы должны экспортировать UV в .tga формате.

Для .mdx, необходимо проделать следующие шаги:

1. Запустите Warcraft 3 Model Editor. 
2. Нажмите File > Open
3. Выберите .mdx файл, в моём случае - AsunaV1.mdx. 
4. Нажмите на Windows > Texture Manager
5. Выберите текстуру, которая вам нужна. В большинстве случаев это один файл. Хотя в моем случае их две. Количество требуемых текстур можно найти в .blp формате, который обычно поставляется с файлом .mdx. 
6. В Texture Manager, щелкните правой кнопкой мыши на текстуре и выберите экспорт. 
7. Не забудьте сохранить расширение как .tga путем переименования texture.blp в texture.tga.

Теперь у вас есть готовая текстура для модели. Проверим это в Source 2 Model Editor.



 

Шаг 4: Настройки для Source 2 Model Editor

Source 2 Model Editor будет вести себя неправильно, если у вас есть пути к файлу за пределами вашего аддона. Таким образом, вам нужно иметь рабочий аддон, и файлы с правильным путем. Для этого вам нужно сделать следующее: (Если у вас уже есть свой аддон, перейдите к шагу 3)

1. Запускаем Dota 2 Workshop Tool Alpha. 
2. Нажмите на кнопку "Create Empty Addon", чтобы собственно создать аддон. 
3. Выберите созданный аддон и нажмите кнопку "Launch Custom Game Tools" 
4. Теперь, когда ваш аддон готов работать, скопируйте два .fbx файла , которые мы сделали в предыдущем шаге в следующий путь:

C:\...\Steam\steamapps\common\dota 2 beta\dota_ugc\content\dota_addons\название_вашего_аддона\models\ваша_модель\

Последняя папка особо не нужна, но мне нравится держать всё в чистоте. 
5. Скопируйте файлы .TGA в следующую директорию:

C:\...\Steam\steamapps\common\dota 2 beta\dota_ugc\content\dota_addons\название_вашего_аддона\materials\ваша_модель\

Теперь ваши ресурсы готовы к редактированию. Давайте перейдем к следующему шагу.



 

Шаг 5: Настройка материала

Так как Source 2 использует свое собственное расширение материала, мы должны преобразовать в него наши текстуры. Для этого необходимо выполнить следующие действия:

1. После того, как вы запустили Workshop Tool, нажмите на кнопку Material Editor, как показано ниже.


2. Нажмите File > New. Это создаст пустой материал. Как только он создан, сразу же сохраните его. 
3. Нажмите на кнопку "Открыть содержащую папку" (значок рядом с директорией).


4. Откроется окно, в котором нужно изменить расширение файла на "All Images". 
5. Перейдите к вашим .tga файлам
6. Выберите файл и нажмите кнопку ОК. 
7. Сохраните файл. 
8. Если у вас есть карта нормалей (normal map) или карта отражений (specular map), вы можете просто поставить галочку на панели слева и выбрать нужную карту.
9. Для каждого файла .tga, вы должны создать каждый материал отдельно. Просто повторите действия от 2 шага до 8 шага.

Теперь ваш материал готов к использованию внутри движка Source 2. Давайте перейдем к модели.



 

Шаг 6: Настройка базовой модели

Теперь, когда у нас есть все текстуры, мы можем приступить к самой модели.

1. В Asset Browser, запустите Model Editor, как показано ниже.

2. Нажмите на “New VMDL from Mesh File” в нижней части окна.
3. Откройте вашу модель и нажмите ОК. 
4. Теперь вы должны увидеть вашу модель в красном каркасе со скелетом, как показано ниже. Может случиться так, что желтый скелет не будет виден. Попробуйте вернуться к 3ds Max, чтобы импортировать модель снова или попробовать с более старой версией плагина - impexpmdx_v2.0.3.ms, иногда это помогает.

5. Теперь, чтобы избавиться от красного вайр фрейма, нужно сделать ремаппинг (наложить текстуры). 
6. Нажмите на Model > Add Material Remap
7. Обратите внимание, что "Material Remap List" будет отображаться в разделе Outliner слева. Нажмите на него. 
8. С правой стороны, вы увидите "Material Remap List (1 items)". Нажмите на знак "+" слева, чтобы развернуть его. 
9. Теперь вы увидите [0] (CVMaterialRemap) ниже, нажмите знак "+" слева , чтобы снова развернуть. 
10. Отобразится 2 поля.

Поле Описание
Search Material Это поле покажет куски модели (меши), которые вам надо затекстурировать (ремапить). Вам потребуется заменить каждую запись, которую вы увидите в выпавшем меню.
Replace Material Это поле поможет движку понять, какой текстурой вы хотите заменить этот участок модели.

 

11. В Search Material выберите один из участков модели в списке. 
12. В Replace Material, нажмите на иконку лупы, чтобы вызвать окно с выбором материала. 
13. Выберите текстуру , которой вы хотите заменить данный участок. Один материал (текстура) может заменить несколько участков. Если у вас только 1 .tga для .mdx формата, вы можете заменить этим файлом все участки модели.
14. Повторите шаги 9 - 13 для всех участков модели. Чтобы добавить еще один пункт ремапинга, просто нажмите синий символ "+" справа от Material Remap List.

Для модели, которая используется в примере, это будет выглядеть так:

15. После того, как у вас есть что-то похожее, как на картинке выше, нажмите сохранить. 
16. Теперь вы должны увидеть все текстуры, примерно как на изображении ниже:

17. Теперь нам надо прикрепить хит бокс к модели. Это достаточно легко сделать, нажав Model > Hitboxes > Autopopulate Hitboxes. Это обязательный пункт. Если вы не сделаете хит бокс для вашей модели, вы не сможете выделить модель в игре. Если вы хотите узнать подробнее о хит боксах пройдите по этой ссылке.

Уже выглядит намного лучше, не так ли? Но мы не совсем завершили нашу работу. Если мы засунем текущую модель в игру – она конечно будет отображаться, но вот анимации у неё не будет. Давайте перейдем к анимации.



 

Шаг 7: Импорт анимации

Для любой модели, чтобы ею можно было во всю пользоваться - вам нужна анимация. Для того чтобы сделать её у вас должен быть .FBX с анимацией из второго шага. Если вы пропустили этот шаг, прокрутите обратно вверх, и выполните его. Обратите внимание, если у вас есть какие-то ошибки, краши и т.п. на этом этапе - это нормально, не паникуйте.

Теперь, чтобы импортировать анимацию вы должны сделать следующее:

1. В Model Editor нажмите на Animation > Add Animation. После этого появится окно проводника. 
2. Выберите .FBX анимацию и нажмите Открыть.
3. На некоторых компьютерах это действие может занять несколько минут. Движок считывает анимацию с большим количеством ключевых кадров (кей фреймов). Именно поэтому, открытие анимации может занять много времени.
4. После того, как анимация загрузилась в движок, у вас должно получится что-то похожее на это


5. С этого этапа, мы будем работать с кей фреймами (ключевыми кадрами). Это достаточно долго, если вы никогда до этого не работали с ними. Если вы уже знаете о них, вы можете перейти к шагу 8. Тем не менее, я предлагаю сделать это вручную, так как ключевые кадры из .mdl или 3ds Max, как правило, не совпадают с ними же в Source 2. 
6. Если вы не знаете, какие виды анимаций имеет ваша модель, вы должны проверить это в любом редакторе - 3ds Max или в Warcraft 3 Model Editor
7. Для Warcraft 3 Model Editor, нажмите Window > Animation Controller. Там, вы можете увидеть все анимации этой модели. В моём примере должно быть 11 анимаций исключая одну не анимированную. 
8. Теперь, когда вы знаете общее количество анимаций, нажмите символ "+" рядом с "Animations" в правой панели, чтобы увеличить количество анимаций, на то, сколько их у вас есть. 
9. Нажмите на символ "+" слева под Animations, чтобы развернуть каждый пункт анимации. 
10. Здесь, вы увидите два поля , которые нужно обязательно заполнить.

Поле Описание
Animation name Называйте как угодно. Это только для вашего удобства, или для ссылок.
File Path Нажмите на иконку лупы справа, откроется окно выбора. Просто выберите анимацию FBX и закройте проводник.

 

11. По крайней мере, вы должны иметь хотя бы одну idle анимацию (когда модель просто стоит на земле), по одной для атаки, одну для движения, и одну для смерти. Для моей модели я буду использовать достаточно много вариантов анимаций.

 

Если вы уже знаете о ключевых кадрах, вам не нужно читать шаг 12 и 13. 
12. Вернитесь к первой анимации в списке, Start Frame должен стоять на 0 и End Frame в самом конце. Сохраните модель, чтобы иметь возможность смотреть на анимацию в режиме реального времени. Обратите внимание, что иногда анимация не отображается в Model Editor’e. Вам придется повторно экспортировать анимацию из 3ds Max и снова добавлять её. 
13. После того, как анимация воспроизводится, вы должны найти ключевые кадры. Например, я хочу сделать asuna_attack1 - я должен пролистывать список кадров, чтобы найти нужный фрагмент для атаки. В этом случае это будет выглядеть так:

Поле Значение
Animation name asuna_attack1
Start Frame 500
End Frame 542

 

14. Под этими двумя полями вы найдете раздел “Activities”. Нажмите на синий "+" справа. 
15. Разверните поле, которое отобразилось, а затем в "Name" выберите тип поля ACT_DOTA_ATTACK. Это поле является очень важным. Оно сообщит движку, какая анимация будет отображаться в игре. Перечень полных действий можно найти здесь.

Когда ваша модель ничего не делает, а просто стоит на земле, она войдет в состояние ACT_DOTA_IDLE с редким шансом срабатывания ACT_DOTA_IDLE_RARE. Когда ваша модель атакует, будет происходить случайное действие между ACT_DOTA_ATTACK и ACT_DOTA_ATTACK2. Во время использования или направления любой способности движок будет использовать ACT_DOTA_CAST_ABILITY_1 или ACT_DOTA_CHANNEL_ABILITY_1 и так далее. ACT_DOTA_DIE срабатывает, когда юнит умирает и ACT_DOTA_SPAWN срабатывает, когда юнит возрождается, спавнится и т.д. Есть много «актов» такого плана, но большинство из них не будут использоваться в доте или некоторые из них специально захардкожены для героя, поэтому они не используются.

16. Вам нужно повторить от 12 до 15 шага для каждой анимации, которая есть. Потребуется время, чтобы найти подходящий фрагмент. Для любой анимации, которая требует цикла, например, IDLE или channeling (ченнелинг), вы должны поставить галочку на "Loop". Например, если у вас есть IDLE анимация, которая не зациклена. После того, как анимация завершит один круг - ваша модель заморозится на месте. Поэтому не забудьте поставить галочку на "Loop".

Полный список анимаций в данном примере ниже. Каждый юнит может иметь полностью разные анимации (секвенции). В ходе этого процесса, желательно сохраняться как можно чаще (или записывать значения куда-то еще), так как это может привести к сбою программы и вы потратите время зря.

Поле

Значение

Animation Name

asuna_attack2

Start Frame

573

End Frame

626

Loop

False

Activities Name

ACT_DOTA_ATTACK2

Animation Name

asuna_spell1

Start Frame

438

End Frame

478

Loop

True

Activities Name

ACT_DOTA_CAST_ABILITY_1

Animation Name

asuna_spell2

Start Frame

656

End Frame

724

Loop

False

Activities Name

ACT_DOTA_CAST_ABILITY_4

Animation Name

asuna_spell3

Start Frame

750

End Frame

787

Loop

False

Activities Name

ACT_DOTA_CAST_ABILITY_2

Animation Name

asuna_channel

Start Frame

385

End Frame

407

Loop

True

Activities Name

ACT_DOTA_CHANNEL_ABILITY_1

Animation Name

asuna_stand

Start Frame

11

End Frame

73

Loop

True

Activities Name

ACT_DOTA_IDLE

Animation Name

asuna_die

Start Frame

895

End Frame

1020

Loop

False

Activities Name

ACT_DOTA_DIE

Animation Name

asuna_walk

Start Frame

292

End Frame

323

Loop

True

Activities Name

ACT_DOTA_RUN

Мы должны охватывать все основные виды анимации. Я не буду вдаваться в глубину о тонкой настройке. Переходы в анимациях и так будут достаточно сглаженными. Поиграйте с ползунком в анимации.



 

Шаг 8: Точки крепления

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

Точка крепления позволит вам прикрепить частицы (particles) к вашей модели. Без этого, частицы всегда будут отображаться на ноге модели, а в некоторых случаях, это крашит аддон и игру.

Чтобы добавить точку крепления, выполните следующие действия:

1. Выберите Model > Attachments > Add Attachment
2. Введите любое имя, которое вы хотите. Тем не менее, я предлагаю называть attach_название.
3. Выберите сустав, который вы хотите прикрепить. 
4. Сохраните файл.

Вы должны увидеть что-то похожее.

Теперь вы знаете, как прикрепить точку. Вот список точек, которые обязательно должны быть у любой модели:

  • attach_origin
  • attach_hitloc
  • attach_attack1
  • attach_attack2

Вы можете добавить что-то, что вздумается, я, например, добавлю attach_sword к своему мечу. Так я смогу прикрепить какой-то партикл (частицу) к оружию модели. Я прикреплю следующие кости:

Теперь мы переходим к следующей части.



 

Шаг 9: Удаляем косметические предметы с героя.

Чтобы удалить все косметические предметы с героя используйте скрипт, когда герой спавнится

local children = hero:GetChildren()
for k,child in pairs(children) do
   if child:GetClassname() == "dota_item_wearable" then
       child:RemoveSelf()
   end
end


 

Шаг 10.1. Часть 1: Подготовка KV файлов.

Такой подход хорош для тех, кто не разбирается в моделировании, но имеет некоторые знания в области программирования. В первой части мы подготовим наши KV файлы.

Вам нужно открыть следующую папку:

\Steam\steamapps\common\dota 2 beta\dota_ugc\game\dota_addons\ваш_аддон\scripts\npc

Когда вы перейдете по этому пути, вы увидите файлы, которые автоматически сгенерированы движком. Я рекомендую открывать их в Notepad ++, если он у вас есть. Обычного блокнота тоже хватит, для наших целей.

 
  herolist.txt
  npc_heroes_custom.txt
 

Теперь вы должны решить, какого героя вы хотите заменить (именно заменить, а не скопировать). Текущая версия движка не позволяет создавать полностью нового кастомного героя. Единственный способ сделать своего персонажа – заменить уже существующего из доты. В этом примере я буду использовать Spectre.

Измените herolist.txt примерно так:

  "CustomHeroList"
  {
    "npc_dota_hero_spectre" "1" 
  }

Ключ всегда будет похож, на тот что у меня, а значение будет либо -1 (можно пикать много раз), 0 (нельзя пикать) и 1 (можно пикать)

npc_dota_hero_heroname

Есть несколько исключений, где используется старый формат названий, но в большинстве случаев это должно работать с примерно такими значениями:

npc_dota_hero_sven 
npc_dota_hero_meepo
npc_dota_hero_warlock
npc_dota_hero_slark
npc_dota_hero_dragon_knight
npc_dota_hero_drow_ranger
npc_dota_hero_phantom_assassin
npc_dota_hero_juggernaut

Полный список можно найти по этой ссылке. Это позволит вашему замененному герою, отражаться на стадии пика (стадии выбора героя). Если установлено значение 0, то его конечно же не будет.

Теперь перейдем к npc_heroes_custom.txt. Вы должны иметь минимальную структуру вашего файла, примерно такую:

"DOTAHeroes"
{
  "npc_dota_hero_asuna_datadriven"
  { 
    "override_hero"  "npc_dota_hero_spectre"
    "Model"          "models/development/invisiblebox.vmdl"
  }

В поле, где я написал "npc_dota_hero_asuna_datadriven" можно использовать что угодно, как вам нравится. Тем не менее, остальные поля должны строго придерживаться этим форматом (ниже в таблице). Я не буду вдаваться в подробности всех доступных полей, поскольку данный урок не рассказывает о создании статуса героя.

Поле

Значение

override_hero

Будет иметь такое же значение, которое вы указали в herolist.txt ранее

Model

Относительный путь к файлу модели

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

"DOTAHeroes"
{
  "npc_dota_hero_random_dude_datadriven"
  { 
    "override_hero" "npc_dota_hero_sven"
    "Model"         "models/development/invisiblebox.vmdl"
  }
 
  "npc_dota_hero_god_datadriven"
  { 
    "override_hero" "npc_dota_hero_juggernaut"
    "Model"         "models/development/invisiblebox.vmdl"
  }
}

Однако, во время снаряжения героя моделька будет выглядеть баговано. Вы можете принудительно пропустить этап снаряжения разными способами. Один из способов сделать это – вставить следующее ключ-значение для героя.

"npc_dota_hero_god_datadriven"
{ 
  "override_hero" "npc_dota_hero_juggernaut"
  "Model" "models/development/invisiblebox.vmdl"
  "ItemSlots"
  { }
}

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



 

Шаг 10.2. Часть 2: Lua скрипты

Эта часть немного устарела, и будет исправлена в ближайшем времени.

Мы очень близки к тому моменту, когда сможем использовать модель на карте. Перед выполнением этой части, вы должны уже иметь загруженный timers.lua, если нет, то вернитесь к самому началу, чтобы скачать его.

Вы должны перейти в следующий каталог.

\Steam\steamapps\common\dota 2 beta\dota_ugc\game\dota_addons\spell_lib_test\scripts\vscripts

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

1. Скопируйте и вставьте timers.lua в эту папку. 
2. Откройте addon_game_mode.lua в Notepad ++ или в блокноте. 
3. В самом верху поместите следующую строку, чтобы подключить таймер.

require("timers")

4. Теперь вам нужно сделать пре кэширование модели для того, чтобы она отображалась в игре правильно. Давайте изменим следующую функцию, чтобы она выглядела подобно той, что ниже. Таблица model_lookup будет служить в качестве глобальной переменной, поэтому вам не нужно редактировать её в нескольких местах. Её ключ будет именем героя, которого вы заменили, а значение будет названием модели, на которую вы хотите поменять.

model_lookup = {}
model_lookup["npc_dota_hero_spectre"] = "models/asuna/asuna.vmdl"
 
function Precache( context )
  -- Precache models
  for k, v in pairs( model_lookup ) do
    PrecacheResource( "model", v, context )
  end
end

5. Измените функцию InitGameMode(). Убедитесь, что вы добавили слушателя к функции.

function CAddonTemplateGameMode:InitGameMode()
  GameRules:GetGameModeEntity():SetThink( "OnThink", self, "GlobalThink", 2 )
 
  -- Listener 
  ListenToGameEvent( "npc_spawned", Dynamic_Wrap( CAddonTemplateGameMode, "OnNPCSpawned" ), self )
end

6. Ваш аддон теперь будет вызывать функцию OnNPCSpawned каждый раз, когда юнит спавнится. Но мы еще не имеем функцию, поэтому создадим её. 
7. Скопируйте следующую функцию в самый конец файла. Под этим кодом я объясню каждую строку. Ну а если вы сильны в Lua, можете не читать этих комментариев.

function CAddonTemplateGameMode:OnNPCSpawned( keys )
  Timers:CreateTimer( 0.05, function()
      -- Setup variables
      local hero = EntIndexToHScript( keys.entindex )
      local model_name = ""
 
      -- Check if npc is hero
      if not hero:IsHero() then return end
 
      -- Getting model name
      if model_lookup[ hero:GetName() ] ~= nil and hero:GetModelName() ~= model_lookup[ hero:GetName() ] then
        model_name = model_lookup[ hero:GetName() ]
      else
        return nil
      end
 
      -- Check if it's correct format
      if hero:GetModelName() ~= "models/development/invisiblebox.vmdl" then return nil end
 
      -- Never got changed before
      local toRemove = {}
      local wearable = hero:FirstMoveChild()
      while wearable ~= nil do
        if wearable:GetClassname() == "dota_item_wearable" then
          table.insert( toRemove, wearable )
        end
        wearable = wearable:NextMovePeer()
      end
 
      -- Remove wearables
      for k, v in pairs( toRemove ) do
        v:SetModel( "models/development/invisiblebox.vmdl" )
        v:RemoveSelf()
      end
 
      -- Set model
      hero:SetModel( model_name )
      hero:SetOriginalModel( model_name )
      hero:MoveToPosition( hero:GetAbsOrigin() )
 
      return nil
    end
  )
end

Ниже объяснения:

Timers:CreateTimer( 0.05, function()

Это не полностью оптимизированый метод. Когда юнит заспавнился в игру – вызывается событие npc_spawned, но модель не отобразится в игре. Поэтому, вам нужна небольшая задержка, прежде чем всё сработает.

local hero = EntIndexToHScript( keys.entindex )
local model_name = ""

EntIndexToHScript превратит entindex полученную из события npc_spawned события в ручке скрипт, который в этом случае будет ваш герой, так что вы можете бездельничать с моделью.

В переменную model_name нужно указать название модели, на которую вы хотите изменить. Эта переменная инициализируется как пустая строка.

-- Check if npc is hero

if not hero:IsHero() then return end

Эта строка не обязательна, но я люблю проверять всё, чтобы не возникало ошибок. В принципе, ваша функция не должна выходить за пределы этой строки, если это не герой.

-- Getting model name

if model_lookup[ hero:GetName() ] ~= nil and hero:GetModelName() ~= model_lookup[ hero:GetName() ] then
  model_name = model_lookup[ hero:GetName() ]
else
  return nil
end

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

-- Check if it's correct format

if hero:GetModelName() ~= "models/development/invisiblebox.vmdl" then return nil end

Это опять-таки не является обязательным требованием. Если модель не выставлена, как “invisiblebox”, то функция остановится.

-- Never got changed before

local toRemove = {}
local wearable = hero:FirstMoveChild()
while wearable ~= nil do
  if wearable:GetClassname() == "dota_item_wearable" then
    table.insert( toRemove, wearable )
  end

  wearable = wearable:NextMovePeer()
end

Это цикл по всем элементам, который записывает в таблицу прикрепленные к модели косметические предметы, начиная с FirstMoveChild (). Так как мы проверяем, если это "dota_item_wearable", то это будет только регистрировать детей, что является только косметическим. Мы в конечном итоге удалить все эти косметические средства из модели.

-- Remove wearables

for k, v in pairs( toRemove ) do
  v:SetModel( "models/development/invisiblebox.vmdl" )
  v:RemoveSelf()
end

Теперь, когда мы добавили записи в таблицу toRemove, мы можем удалить косметические предметы. Вы можете задаться вопросом, почему я должен установить в качестве модели invisiblebox.vmdl. Это изначально связано с костями, ошибками скелета модели, когда имеется косметический предмет.

Что делает Source 2 движок, когда он спавнит героя? В первую очередь он присоединит все косметические предметы автоматически к вашему герою. Эти косметические шмотки будут иметь такое же имя костей, как и у оригинального героя.

 

Поздравляем, теперь ваш герой готов к использованию в вашем аддоне!