我希望能够动态地更改游戏代码。例如,假设我的游戏以这种方式构建:
class GameState {
public int SomeData;
public Entity[] EntityPool;
}
interface IServices {
IRenderer Renderer { get; }
}
interface IGameCode {
void RenderAndUpdate(GameState currentState, IServices serviceProvider);
}
我现在希望能够编写这样的代码:
void MainLoop() {
IGameCode gameCode = new DefaultGameCode();
while(true) {
// Handle Plattform things
if(shouldUseNewGameCode) {
UnloadCode(gameCode);
gameCode = LoadCode("new.dll");
// or
gameCode = LoadCode("new.cs");
}
// Call GameTick
gameCode.RenderAndUpdate(gameState, services);
}
}
我已经使用过AppDomains和一个Proxyclass,但是每个帧序列化太慢了。我试图只传递一个指针,但由于AppDomains使用自己的虚拟地址空间,我无法访问GameState对象。我的另一个想法是使用Reflection通过GetMethodBody()从编译的方法中获取IL并将其传递给DynamicMethod,但这会限制我编写RenderAndUpdate方法的方式,因为我不能在IGameCode实现中使用Submethods或Variables
那么我怎样才能实现我想做的事呢?
答案 0 :(得分:0)
正如您所见,您真的不希望在每个帧上越过AppDomain
边界,特别是如果该代码必须回调到主代码,例如IServices
多次。即使使用MarshalByRefObject
,这可以改善一些事情,但它会变得太慢。因此,您需要一个不涉及AppDomain
的解决方案。
你的装配有多大?您希望多久改变一次?
注意到.NET程序集通常具有相当大的空间效率,并且在您的场景中,用户似乎不太可能在会话中多次切换程序集,我只会将您的DLL作为{{1}读入内存然后使用Assembly.Load(byte[]);
加载它。
或者,如果您真的无法容忍进程内存空间中的死组件,我认为最好使用辅助进程,即“launcher”:当您想要切换实现时,启动辅助进程(或者只是让它一直运行,如果你想要的话),然后等待当前的游戏进程退出,然后用新的设置启动一个新的。
切换速度较慢,但当然每个开关只需一次性费用,然后程序可以在实际游戏过程中全速运行。