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

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

思路很简单:
建立一个工程包含两个代码库:UnityEngine(以下称为FakeUnityEngine)和UnityEngineImp,在UnityEngineImp里引用游戏里用到的第三方库和unity编译好的游戏代码库以及FakeUnityEngine代码库。这样游戏里用到的UnityEngine的接口都会call到FakeUnityEngine里,只要在FakeUnityEngine里实现所有用到的UnityEngine的接口(无绘制层),游戏代码库就能在.net环境上运行起来。
UnityEngineImp
UnityEngine
首先要实现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连接、重定向、发送登录游戏请求,收到各种模块信息及登陆游戏请求回复:
效果

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值