Допустим, у меня есть два приложения на C # - game.exe
(XNA, требуется поддержка Xbox 360) и editor.exe
(XNA, размещенный в WinForms) - они оба используют сборку engine.dll
, которая выполняет подавляющее большинство работа.
Теперь допустим, что я хочу добавить какой-нибудь сценарий на основе C # (это не совсем "сценарий", но я назову это так). Каждый уровень получает свой собственный класс, унаследованный от базового класса (назовем его LevelController
).
Вот важные ограничения для этих скриптов:
Они должны быть реальными, скомпилированный код C #
Они должны требовать минимальной ручной «клеевой» работы, если таковые имеются
Они должны работать в том же домене приложений, что и все остальное
Для игры - это довольно просто: все классы сценариев могут быть скомпилированы в сборку (скажем, levels.dll
), а отдельные классы могут быть созданы с использованием отражения по мере необходимости.
Редактор намного сложнее. Редактор имеет возможность «играть в игру» в окне редактора, а затем сбрасывать все обратно туда, где он был запущен (именно поэтому редактор должен знать об этих сценариях в первую очередь).
То, чего я пытаюсь добиться, это в основном кнопка «перезагрузить скрипт» в редакторе, которая перекомпилирует и загрузит класс скрипта, связанный с редактируемым уровнем, и, когда пользователь нажмет кнопку «играть», создаст экземпляр последний скомпилированный скрипт.
Результатом будет быстрый рабочий процесс редактирования-тестирования в редакторе (вместо альтернативы - сохранения уровня, закрытия редактора, перекомпиляции решения, запуска редактора, загрузки уровня, тестирования).
Теперь я думаю Я разработал потенциальный способ достижения этого - что само по себе приводит к ряду вопросов (приведенных ниже):
Скомпилируйте коллекцию файлов .cs
, необходимых для данного уровня (или, если необходимо, всего проекта levels.dll
), во временную сборку с уникальным именем. Эта сборка должна ссылаться на engine.dll
. Как вызвать компилятор таким образом во время выполнения? Как заставить его выводить такую сборку (и можно ли это сделать в памяти)?
Загрузите новую сборку. Будет ли иметь значение, что я загружаю классы с одинаковыми именами в один и тот же процесс? (У меня сложилось впечатление, что имена уточняются по имени сборки?)
Теперь, как я уже говорил, я не могу использовать домены приложений. Но, с другой стороны, я не возражаю против утечки старых версий классов скриптов, поэтому возможность выгрузки не важна. Если это не так? Я предполагаю, что возможно загрузка нескольких сотен сборок.
При воспроизведении уровня, экземпляр класса, который унаследован от LevelController от конкретной сборки, которая была только что загружена. Как это сделать?
И наконец:
Это разумный подход? Можно ли сделать это лучше?
ОБНОВЛЕНИЕ: В настоящее время я использую гораздо более простой подход для решения основной проблемы.