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