您的位置:首页 > 移动开发 > Unity3D

Fake UnityEngine:如何让unity编译的代码库直接在.net环境上运行起来(无绘制层)

2016-11-15 10:56 507 查看
项目组用unity开发的slg游戏项目到了收尾阶段,最近要求实现一个带服系统,就是一个程序能挂机很多游戏账号。
UnityEngine的C#层是在mono虚拟机上运行的,一个mono虚拟机至少要占用40M左右的内存。
如果unity编译好的游戏代码库能直接在.net的环境上运行起来,那么挂机程序就能挂更多的账号,
带服专员就能“忽悠”更多的玩家,老板就能挣更多的钱,万恶的资本家QAQ。


思路很简单:

建立一个工程包含两个代码库:UnityEngine(以下称为FakeUnityEngine)和UnityEngineImp,在UnityEngineImp里引用游戏里用到的第三方库和unity编译好的游戏代码库以及FakeUnityEngine代码库。这样游戏里用到的UnityEngine的接口都会call到FakeUnityEngine里,只要在FakeUnityEngine里实现所有用到的UnityEngine的接口(无绘制层),游戏代码库就能在.net环境上运行起来。





首先要实现MonoBehaviourManager类,模拟mono脚本的调用过程,利用反射依次调用mono脚本的Awake、Start及Update函数。

下面贴出该类的代码,代码里有完整的注释:

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Reflection;
using System.Threading;
using System.Collections;

namespace UnityEngine
{
public static class MonoBehaviourManager
{
private static List<object> MonoBehaviourPool = new List<object>();

private static List<object> MonoBehaviourUpdatePool = new List<object>();

private static Thread callMonoBehaviourThread;

private static Thread callMonoBehaviourUpdateThread;

public static void AddInstance(object instance)//加载一个mono脚本对象,把它加到MonoBehaviourPool,并调用它的Awake方法
{
MonoBehaviourPool.Add(instance);
CallMethod(instance, "Awake", null);
}

public static void CallMethod(this object instance, string name, params object[] param)
{
BindingFlags flag = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;
Type type = instance.GetType();
MethodInfo method = type.GetMethod(name, flag);
if (method != null)
{
if (method.ReturnType == typeof(IEnumerator))
{
IEnumerator etr = (IEnumerator)method.Invoke(instance, param);
while (etr.MoveNext())
{
//Debug.Log();
}
}
else
{
method.Invoke(instance, param);
}
}
}

public static void CallMonoBehaviourStartFunc(this object instance)
{
CallMethod(instance, "Start", null);
}

public static void CallMonoBehaviourUpdateFunc(this object instance)
{
CallMethod(instance, "Update", null);
}

public static void Initialize()//初始化,起两个线程分别用来调mono脚本对象的Start方法和Update方法
{
callMonoBehaviourThread = new Thread(new ThreadStart(CallMonoBehaviourThreadFunc));
callMonoBehaviourThread.Start();

callMonoBehaviourUpdateThread = new Thread(new ThreadStart(CallMonoBehaviourUpdateThreadFunc));
callMonoBehaviourUpdateThread.Start();
}

public static void CallMonoBehaviourThreadFunc()
{
while (true)
{
if (MonoBehaviourPool.Count > 0)
{
object currentMonoBehaviour = MonoBehaviourPool[0];
CallMonoBehaviourStartFunc(currentMonoBehaviour);//调用MonoBehaviourPool里的mono脚本对象的Start方法
MonoBehaviourUpdatePool.Add(currentMonoBehaviour);//把MonoBehaviourPool里的mono脚本对象加到MonoBehaviourUpdatePool
MonoBehaviourPool.Remove(currentMonoBehaviour);//移除MonoBehaviourPool里的mono脚本对象
}
Thread.Sleep(20);
}
}

public static void CallMonoBehaviourUpdateThreadFunc()
{
while (true)
{
for (int i = 0; i < MonoBehaviourUpdatePool.Count; i++)
{
object currentMonoBehaviour = MonoBehaviourUpdatePool[i];
CallMonoBehaviourUpdateFunc(currentMonoBehaviour);//调用MonoBehaviourUpdatePool里的mono脚本对象的Update方法,20ms调一次
Thread.Sleep(20);
}
}
}
}
}


另外在FakeUnityEngine里实现的UnityEngine的接口,由于不需要实现绘制层,所有大部分的接口留空就行了。以GameObject为例:

public sealed class GameObject : Object
{
// Methods
public GameObject()
{

}

public GameObject(string name)
{

}

public GameObject(string name, params Type[] components)
{

}

public T AddComponent<T>()
{
T instance = Activator.CreateInstance<T>();
MonoBehaviourManager.AddInstance(instance);
return instance;
}

public T GetComponent<T>()
{
T instance = Activator.CreateInstance<T>();
return instance;
}

public T[] GetComponentsInChildren<T>(bool includeInactive)
{
//T instance = Activator.CreateInstance<T>();
return new T[] { };
}

public T[] GetComponentsInChildren<T>()
{
//T instance = Activator.CreateInstance<T>();
return new T[] { };
}

public static void Destroy(GameObject obj)
{

}

public Transform transform
{
get
{
return new Transform();
}
}
}


然后是整个UnityEngineImp工程的主函数:

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
using Framework;
using UnityEngine;

//Fake UnityEngine  by:yjx

namespace UnityEngineImp
{
class Program
{
static void Main(string[] args)
{
MonoBehaviourManager.Initialize();//mono脚本管理类初始化

//接下来都是Unity的游戏代码库的调用
SDKMsg paySdk = new SDKMsg();
MonoBehaviourManager.AddInstance(paySdk);//SDKMsg加入mono脚本管理类

ANetManager.Init();//ANetManager初始化

OnlineSDKManager onlineSDKManager = new OnlineSDKManager();
MonoBehaviourManager.AddInstance(onlineSDKManager);

AAssetBundleManager aAssetBundleManager = new AAssetBundleManager();
MonoBehaviourManager.AddInstance(aAssetBundleManager);

ViewServerLogic viewServerLogic = new ViewServerLogic();
MonoBehaviourManager.AddInstance(viewServerLogic);

ViewGeneralTipsLogic viewGeneralTipsLogic = new ViewGeneralTipsLogic();
MonoBehaviourManager.AddInstance(viewGeneralTipsLogic);

LoginManager loginManager = new LoginManager();
MonoBehaviourManager.AddInstance(loginManager);
LoginManager.StartGame();//进入游戏:建立socket连接,发送进入游戏请求
}
}
}


最后是实际运行效果,建立socket连接、重定向、发送登录游戏请求,收到各种模块信息及登陆游戏请求回复:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: