Barotrauma

Barotrauma

48 beoordelingen
Как сделать мод на c#
Door Nupaska
Я конечно не эксперт, но я чутка разобрался
Документации и гайдов по этой теме 0 без палочки
Так что я решил поделиться опытом
2
   
Prijs
Toevoegen aan favorieten
Toegevoegd aan favorieten
Verwijderen uit favorieten
Шо нужно знать
Прочитайте официальный гайд по созданию обычных модов для баротравмы[regalis11.github.io]
Прочитайте руководство по с#[metanit.com], особенно главу про рефлексию
Как примерно это работает
Возможность менять код игры добавляет мод "lua for barotrauma"
Делает он это с помощью библиотеки harmony[harmony.pardeike.net]
В папке мода "lua for barotrauma" лежит полная скомпилированная копия игры скрещенная с harmony
harmony позволяет выполнять свой код перед и после вызова любого метода игры, менять аргументы и предотвращать исполнение оригинального кода полностью заменяя метод
В harmony это называется patch
Поверх всего этого еще прикручен интерпретатор луа, собственно "lua for barotrauma" позволяет писать lua скрипты и использовать harmony
Еще там где-то лежит компилятор c#, c# for barotrauma просто разрешает его использовать теперь c# из главного меню включается

Если у вас на клиенте установлена lua for barotrauma и есть с# for barutrauma, то при заходе на сервер, запуске сиглплеера, заходе в редактор подлодок или cl_reloadlua в главном меню игра прочекает все моды и если в папке мода есть папка CSharp то она скомпилирует все что там есть, загрузит все dll из папки bin и запустит мод
Есть 2 типа c# модов
Скомпилированные и на сурс коде
Моды с кодом компилируются прямо в игре каждый раз
Моды с dll скомпилированы заранее на рефах луатравмы

Плюсы dll модов:
  • Они чуть быстрее грузятся тк уже скомпилены
  • В них можно использовать сторонние библиотеки, например json (в баре его нет)
Минусы:
  • Игроки не знают что внутри dll, а вдруг там вирус
  • Их по идее надо перекомпилировать при каждом апдейте баротравмы
  • В них могут приползти баги из системы плагинов которых нет в сурс версии, например если ты запустил игру, сразу зашел в редактор лодок, вышел и зашел в кампанию, одна рандомная переменная станет равна null несмотря на то что она уже 10 раз инициализирована
  • Опять же из-за бага в системе плагинов dll не выгружаются из игры и чтобы пересобрать мод надо перезапускать игру

Я сначала расскажу про моды с кодом. В dll модах все то же самое только там структура файлов чуть-чуть другая
Ну так вот
Почитайте раздел In-memory CSharp Mod[evilfactory.github.io] в официальном гайде по c#

c# код должен лежать в папке CSharp

Код может запускаться параллельно и на клиенте и на сервере
все что в папке CSharp/Client/* запускается только на клиенте
все что в папке CSharp/Server/* запускается только на сервере
все что в папке CSharp/Shared/* запускается и там и там, разделить код можно директивами препроцессора
#if SERVER InitServer(); #elif CLIENT InitClient(); #endif

помимо этого в папке CSharp должен лежать файл RunConfig.xml в котором написано когда запускать код
<?xml version="1.0" encoding="utf-8"?> <RunConfig> <Server>Standard</Server> <Client>Standard</Client> </RunConfig>
Standard - только если мод включен, как обычные моды
Forced - запускать всегда
None - никогда

Мод - это класс реализующий интерфейс IAssemblyPlugin[github.com]

Когда игра находит такой класс она создает объект этого класса, добавляет в свой список c# модов и вызывает Initialize()
при выгрузке мода вызывается Dispose(), тоже не забудьте реализовать

В Initialize вы можете исполнять любой код
Чтобы поменять поведение методов игры:
  • создайте свой экземпляр Harmony
  • создайте отдельный класс с патчами (для удобства)
  • получите инфу о методах игры через рефлексию
  • пропатчите их через ваш harmony
Простейший пример
мод который выводит надпись "Lol, you opened settings" в консоль когда вы открываете меню настроек

ссылка на мод в мастерской для полного счастья
using System; using System.Reflection; using Barotrauma; using HarmonyLib; using Microsoft.Xna.Framework; // just for color namespace exampleNamespace { class exampleMod : IAssemblyPlugin { public Harmony harmony; public void Initialize() { harmony = new Harmony("example.mod"); // patching this method https://github.com/evilfactory/LuaCsForBarotrauma/blob/master/Barotrauma/BarotraumaClient/ClientSource/Settings/SettingsMenu.cs#L50 harmony.Patch( original: typeof(SettingsMenu).GetMethod("Create"), postfix: new HarmonyMethod(typeof(SettingsMenuPatch).GetMethod("Create")) ); } public void OnLoadCompleted() { } public void PreInitPatching() { } public void Dispose() { // for some reason this doesn't work :( harmony.UnpatchAll(); harmony = null; } } class SettingsMenuPatch { public static void Create(RectTransform mainParent) { DebugConsole.NewMessage("Lol, you opened settings", new Color(0, 255, 0)); } } }
И что теперь?
А теперь иди читать документацию сурс код баротравмы[github.com] и догадывайся как что работает
А как тестить?
cl_reloadlua - перекомпилирует код
reloadlua - перекомпилирует код на сервере в мультиплеере
На ошибки компиляции - просто открой редактор подлодок
В игре - через quickstart[barotraumagame.com]
Как я могу?
Получить доступ к приватным свойствам?
- Через инъекцию свойств Harmony[harmony.pardeike.net], или на крайняк через рефлексию

По идее не обязательно делать инъекцию их всех, достаточно обращаться к ним через __instance.

Вывести сообщение в консоль?
DebugConsole.NewMessage(string msg, Color cl);
Это метод игры, он по умолчанию пишет белым

LuaCsLogger.LogMessage(string msg, Color serverColor, Color clientColor)
Это метод луатравмы, на сервере он не просто выводит сообщение в консоль но еще и посылает его все клиентам
Он пишет по умолчанию фиолетовым

Вот тут[github.com] есть еще более специализированные методы

Добавить консольную команду?
https://github.com/evilfactory/LuaCsForBarotrauma/blob/master/Barotrauma/BarotraumaShared/SharedSource/DebugConsole.cs

DebugConsole.Commands.Add(new DebugConsole.Command(string name, string help, (string[] args) => { string what = args.ElementAtOrDefault(0); DebugConsole.NewMessage(what); }, () =>new string[][] { new string[] {"hint1","hint2"}}));

Учтите что можно случайно добавить несколько одинаковых команд, выполнятся будет только первая подходящая по имени

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

Еще нюанс что команда то есть, но вот разрешения ее использовать в мультиплеере нет, потому что список разрешенных команд жестко закожен

возможное решение - сделать постфикс к LuaGame.IsCustomCommandPermitted
public static void permitCommands(Identifier command, ref bool __result) { if (command.Value == "debugmissions") __result = true; if (command.Value == "sm") __result = true; if (command.Value == "sm_save") __result = true; if (command.Value == "sm_load") __result = true; if (command.Value == "sm_log") __result = true; }

Удалить консольную команду?
DebugConsole.Commands.RemoveAll(c => c.Names.Contains("some_name"));
консольные команды сохраняют ссылку на ваш мод и пока команда не удалена ваш мод продолжит висеть в памяти

Узнать сколько секунд уже прошло?
- Timing.TotalTime

Полностью заменить метод?
- сделайте префикс который возвращает false

скопируйте оригинальный метод, сделайте его public static bool, добавьте __instance. к обращениям к приватным переменным ... profit

Использовать сторонние библиотеки например JSON?
хз
Узнать версию и путь к папке мода?
foreach (ContentPackage p in ContentPackageManager.EnabledPackages.All) { if (p.Name.Contains(ModName)) { ModVersion = p.ModVersion; ModDir = Path.GetFullPath(p.Dir); break; } }

Послать сообщение с клиента на сервер и обратно?
Проще пареной репы:
на клиенте
IWriteMessage message = GameMain.LuaCs.Networking.Start("hifromclient"); message.WriteString("hi!"); GameMain.LuaCs.Networking.Send(message);
на сервере
GameMain.LuaCs.Networking.Receive("hifromclient", (object[] args) => { IReadMessage message = args[0] as IReadMessage; Client client = args[1] as Client; LuaCsLogger.LogMessage(message.ReadString() , Color.Yellow, Color.Yellow); });

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

Узнать что клиент - хост и есть ли у него разрешения?
Поидее вот так на клиенте:
if (GameMain.IsMultiplayer && (GameMain.Client.IsServerOwner || GameMain.Client.HasPermission(ClientPermissions.All)))
и вот так на сервере:
if (client.Connection != GameMain.Server.OwnerConnection && !client.HasPermission(ClientPermissions.All))
Как скомпилировать мод?
Гайд[github.com]
там еще надо добавить ко всем проектам ссылку на соответствующий BarotraumaCore.dll из Refs и удалить readme из assets которого нет

в сурсы надо добавить
using System.Runtime.CompilerServices; [assembly: IgnoresAccessChecksTo("Barotrauma")] [assembly: IgnoresAccessChecksTo("DedicatedServer")] [assembly: IgnoresAccessChecksTo("BarotraumaCore")]

Дальше можно удалить plugin.cs в положить сурсы из CSharp в соответствующие папки вместо plugin.cs

скомпилируйте и положите папку bin в ваш мод
Нюансы
Luatrauma теперь использует HarmonyX [github.com]


Luatrauma больше не снимает все патчи автоматически, вызывайте harmony.UnpatchSelf() в Dispose, а то они там останутся


в главном меню моды сами по себе не запускаются


если вы делаете инъекцию переменной и меняете ее, то обязательно берите ее через ref, иначе вы измените только копию и эффекта не будет
Меняйте все через __instance и проблем не будет


Если метод который вы хотите пропатчить приватный или статичный то вы не сможете его получить просто через GetMethod, вам нужны BindingFlags[metanit.com]
Про конструкторы я вообще молчу

кстати можно использовать AccessTools.all из harmony [harmony.pardeike.net], он ко всему подходит


Префиксы в harmony возвращают bool (выполнять оригинальный метод или нет)
Если вы хотите изменить результат оригинала то запишите его в __result


XmlSerializer - забагован
он создается n^(кол-во c# модов) времени, если у клиента 10 с# модов и кто-то из них использует XmlSerializer то загружаться они будут вечность
Причем ошибок никаких не будет и автору об этом никто не скажет


Если в вашем моде вообще нет xml контента то игра считает его пустым
Он не отображается в списке модов сервера и игра не предлагает клиентам его скачать
Если вы хотите чтобы мод был виден добавьте в него dummyitem.xml


раньше моды делались путем наследования класса ACsMod, но недавно MapleWheels уболтал evilfactory добавить систему плагинов из "Modding Toolkit" в "lua for barotrauma"

так что теперь надо использовать IAssemblyPlugin
гайд как им пользоваться лежит у MapleWheels на гитхабе[github.com]


читайте сурс код баротравмы с гитхаба evilfactory[github.com] а не FakeFishGames, потому что именно эту версию вы патчите, там есть небольшие отличия


В версии evilfactory есть папка LuaCs[evilfactory.github.io] со всякими классами
по идее они для луа, но вы их тоже можете использовать


Баги системы плагинов
Пофикшены в HarmonyX


А в чем мне это все редактировать?
Я прост в VS Code пишу, мне пофиг
В VS Code так же можно компилировать dll версию, хотя там приходится включать выключать c# dev kit, что не очень удобно
MapleWheels предлагает писать моды в Visual Studio поверх дебаговой версии баротравмы[github.com]


Остались вопросы? - донимайте evilfactory в его дискорде[discord.com]
4 opmerkingen
Cain 25 sep 2024 om 9:04 
Одобрено
Sergeev_Racist228[FREEDUROV] 24 sep 2024 om 3:04 
Шаг 1: выучить C#
guns 6 mei 2024 om 9:04 
Смог убрать светящееся гало у персонажей на мод, спасибо за руководство!
Saint_Alexey 5 dec 2023 om 9:03 
странно, что такой полезный гайд с 0 классов. Люди, ставте классы:steamthumbsup: