Вступление
Всем привет. Традиционно кастомки в Доте пишутся на Lua через VScripts. Но если вы, как и я, привыкли к строгой типизации и возможностям C#, то есть способ не мучиться( или заняться дибилизмом ). Благодаря проекту CSharp.lua можно писать всю логику на Шарпе, компилить её в Луа и спокойно запускать в дотовской песочнице.
Я разобрался с тем, как это всё завести, пропатчить под ограничения API Доты и выстроить нормальный воркфлоу. Делюсь опытом.
---
1. Что нам понадобится (Инструментарий)
Для начала нужно понимать, как это работает «под капотом».
Важный нюанс: Чтобы всё работало в Доте, при компиляции обязательно используем флаги
---
2. Структура проекта
Я организовал проект так, чтобы исходники лежали отдельно, а готовый скрипт сам улетал в папку аддона.
Примерная структура:
В самой папке аддона (
---
3. Патчим CoreSystem (ОЧЕНЬ ВАЖНО)
Поскольку Valve сильно ограничили Lua в игре, стандартная библиотека CoreSystem будет выдавать ошибки, пытаясь обратиться к
Правка DateTime.lua:
Нужно обернуть вызовы
Если
Правка Core.lua:
В Доте есть команда
---
4. Связка C# и API Доты
Самое интересное — как вызывать функции Доты из Шарпа. Мы используем атрибут
Пример базового модификатора на C#:
Теперь в наследнике вы просто пишете чистую логику на C#, а компилятор сам подставит нужные вызовы API Доты.
---
5. Точка входа и регистрация
В
А внутри C# создаем класс
---
6. Процесс разработки (Воркфлоу)
1. Пишем код в Visual Studio / Rider (с поддержкой C# 10+).
2. Запускаем
3. В игре открываем консоль и пишем
4. Всё! Изменения подхватились без перезапуска инструментария.
Итог:
Да, настройка требует времени, но на выходе мы получаем мощь Шарпа, типизацию и нормальную структуру кода, чего на чистом Lua в больших проектах добиться сложно.
Репозиторий с реализацией
Всем привет. Традиционно кастомки в Доте пишутся на Lua через VScripts. Но если вы, как и я, привыкли к строгой типизации и возможностям C#, то есть способ не мучиться( или заняться дибилизмом ). Благодаря проекту CSharp.lua можно писать всю логику на Шарпе, компилить её в Луа и спокойно запускать в дотовской песочнице.
Я разобрался с тем, как это всё завести, пропатчить под ограничения API Доты и выстроить нормальный воркфлоу. Делюсь опытом.
---
1. Что нам понадобится (Инструментарий)
Для начала нужно понимать, как это работает «под капотом».
- CSharp.lua — это не просто транспайлер, это мощный компилятор на базе Roslyn. Он превращает ваш C# код в читаемый Lua.
- CoreSystem.lua — это мини-фреймворк, который идет в комплекте. Он эмулирует привычные типы .NET (LINQ, коллекции, делегаты) внутри Lua.
- VScript — это наша среда исполнения. В Доте используется урезанная Lua 5.1. Там нет доступа к файловой системе (
io), ограничена библиотекаosи полностью вырезанаdebug.
Важный нюанс: Чтобы всё работало в Доте, при компиляции обязательно используем флаги
-c (совместимость с Lua 5.1) и -p (отключение вызовов debug.setmetatable).---
2. Структура проекта
Я организовал проект так, чтобы исходники лежали отдельно, а готовый скрипт сам улетал в папку аддона.
Примерная структура:
my-addon/src/ — тут весь ваш C#.my-addon/output/ — сюда падает готовый out.lua.compile.bat — скрипт для сборки одной кнопкой.В самой папке аддона (
game/dota_addons/имя/scripts/vscripts/) нам по сути нужен только один файл — out.lua (ваш код + CoreSystem) и стартовый addon_game_mode.lua.---
3. Патчим CoreSystem (ОЧЕНЬ ВАЖНО)
Поскольку Valve сильно ограничили Lua в игре, стандартная библиотека CoreSystem будет выдавать ошибки, пытаясь обратиться к
os.time или debug. Нужно внести пару правок ручками.Правка DateTime.lua:
Нужно обернуть вызовы
os в проверки, чтобы аддон не падал при инициализации:local ostime = os and os.timeЕсли
os недоступен, ставим заглушку (fallback) на UTC+0.Правка Core.lua:
В Доте есть команда
script_reload. По умолчанию CoreSystem кидает ассерт, если класс пытается определиться дважды. Чтобы перезагрузка скриптов работала, закомментируйте проверку:-- assert(rawget(scope, name) == nil, className)rawset(scope, name, cls)---
4. Связка C# и API Доты
Самое интересное — как вызывать функции Доты из Шарпа. Мы используем атрибут
@CSharpLua.Template.Пример базового модификатора на C#:
C#:
namespace MyAddon.Base {
public abstract class BaseModifier {
// Обертка над методом из Lua
/// @CSharpLua.Template = "{this}:GetParent()"
protected extern object GetParent();
/// @CSharpLua.Template = "IsServer()"
protected static extern bool IsServer();
public virtual bool IsHidden() => false;
}
}
Теперь в наследнике вы просто пишете чистую логику на C#, а компилятор сам подставит нужные вызовы API Доты.
---
5. Точка входа и регистрация
В
addon_game_mode.lua мы просто пишем require("out").А внутри C# создаем класс
EntryPoint, который прокинет ссылки на функции Activate и Precache.
C#:
public static class EntryPoint {
/// @CSharpLua.Template = "Activate = {0}"
private static extern void SetActivate(Action fn);
public static void Setup() {
SetActivate(GameMode.OnActivate);
// Регистрация кастомных абилок в глобальной области Lua
RegisterModifier(typeof(MyModifier));
}
}
---
6. Процесс разработки (Воркфлоу)
1. Пишем код в Visual Studio / Rider (с поддержкой C# 10+).
2. Запускаем
compile.bat. Он прогоняет компилятор и копирует out.lua в папку с Дотой.3. В игре открываем консоль и пишем
script_reload. 4. Всё! Изменения подхватились без перезапуска инструментария.
Итог:
Да, настройка требует времени, но на выходе мы получаем мощь Шарпа, типизацию и нормальную структуру кода, чего на чистом Lua в больших проектах добиться сложно.
Репозиторий с реализацией