Unity Editor v4.3.1f1 源码编译笔记

2018-05-21 18:00:00

0x00 前言

Unity 是“手游时代”的最热门的游戏开发引擎,很多团队使用 Unity 进行开发,市面上使用 Unity 开发的热门游戏更是数不胜数,甚至暴雪的《炉石传说》也使用 Unity 开发,可见 Unity 是一款很强大的引擎。然而对于一些求知欲旺盛的开发者,Unity 有一个缺点,就是它的核心部分是不开放源码的,现在国内一些大公司也陆续购买了 Unity 的源码进行二次开发,可惜我供职的公司还仅仅在计划购买,等到真的拿到代码还不知道要多久时间。一次偶然的机会在论坛上看到有人分享了一份 Unity 代码,虽然只是几年前的 4.x 版本,但也多少能窥出一点端倪,于是有了这篇笔记所记录的 Unity Editor v4.3.1f1 的编译过程。

0x01 源码获取

unity-source-4.3.1f1-e1ff3bcdcd18-pcmac_android_ios.zip 【略】

0x02 准备工作

庆幸的是源码压缩包中还带有文档,通过简单的阅读得知,这个版本的源码建议使用 Windows 7 SP1 + Visual Studio 2010 SP1。我的电脑里已经装了 vs2015vs2017 了。不想把全家桶都装上,于是干脆 hyper-v 创建了一个虚拟机,干干净净,也免去了很多麻烦。步骤简单记录如下:

  • Hyper-V 全新安装 Windows (en_windows_10_consumer_editions_version_1803_updated_march_2018_x64_dvd_12063379.iso)
  • 安装 Visual Studio 2010 (en_visual_studio_2010_ultimate_x86_dvd_509116.iso)
  • 安装 Visual Studio 2010 SP1 (VS10SP1-KB983509.exe)
  • 安装 Active Perl (ActivePerl-5.22.4.2205-MSWin32-x86-64int-403863.exe)
  • 解压源码包

有几个地方需要注意:

  • 最好安装英文系统,如果你使用的中文系统又不打算安装虚拟机,那么在编译之前修改 Projects\Jam\Editor.jam 文件,在 360 行插入 /wd4819 (当然你也可以用其他的方法解决4819错误,比如把报错的源文件另存为指定的 unicode 格式)
  • 一定要安装 Visual Studio 2010 SP1,否则编译 CPUInfo.cpp 时会报错,找不到 _xgetbv 方法
  • 最好安装 x86 版本的 Perl
  • 解压的时候注意最终路径名不要过长,否则下一步解压依赖库的时候会报错,如果是 X:\unity 最好

0x03 解压依赖库&生成vs工程文件

在解压出来的 Unity 源码路径下运行:

perl build.pl --prepare

此时会在 Projects\JamGenerated\_workspace.vs2010_ 目录下生成 solution 文件,如果你仅仅只想更方便的阅读源码,那么到这一步就可以了 (Projects\Sublime 下面有 Sublime 的工程,习惯使用 Sublime 的可以直接打开)

0x04 处理许可管理相关代码

这一步其实理论上可以略过,因为 Unity 4.x 也还是可以运行的,证明激活服务器还在运行,但是我尝试过不修改任何管理 License 的代码,总是会弹出一个 ssl peer certificate or ssh remote key was not okwarning

最干净的办法是修改 Editor\Src\LicenseInfo.cpp,把所有用到 LicenseManger 的地方全部替换掉,代码如下:

// some include...

LicenseInfo* gSingleton = NULL;

LicenseInfo::LicenseInfo()
{
    InitializeProtection();
}

void LicenseInfo::InitializeProtection() 
{
    gSingleton = this;
    m_Tokens = 1; // make token 1 cause some places check if token is zero
}

void LicenseInfo::SetRXValue(const char* value) {}

void LicenseInfo::SignalUserClosedWindow() {}

void LicenseInfo::GenericErrorDialog(const char* title) {}

void LicenseInfo::UnknownErrorDialog(const char* title) {}

void LicenseInfo::DisplayErrorDialog(const char* title, const char* url) {}

void LicenseInfo::ReloadEditorUI () {}

void LicenseInfo::Tick() {}

void LicenseInfo::ShowUpdateFeedbackDialog(bool success) {}

bool LicenseInfo::GetLargeFlag(LicenseInfoFlag f) { return false; }

string LicenseInfo::GetLicenseString () { return "Cracked for study"; }

bool LicenseInfo::OngoingServerCommunication() { return true; }

string LicenseInfo::GetMachineID() { return ""; }

string LicenseInfo::GetAuthToken () { return ""; }

UInt64 LicenseInfo::GetRawFlags ()
{
    return m_Tokens;
}

void LicenseInfo::Reauthorize() {}

LicenseInfo::~LicenseInfo()
{
    if (gSingleton == this)
        gSingleton = NULL;
}

LicenseInfo* LicenseInfo::Get ()
{
    if(gSingleton == NULL)
        gSingleton = new LicenseInfo();
    return gSingleton;
}

void LicenseInfo::Cleanup ()
{
    delete gSingleton;
    gSingleton = NULL;
}

string LicenseInfo::GetDisplaySerialNumber () { return ""; }

int LicenseInfo::SaveLicenseFile ( string licenseData ) { return 0; }

void LicenseInfo::ReturnLicense () {}

bool LicenseInfo::IsLicenseUpdated () { return true; }

void LicenseInfo::CallActivationServer () {}

void LicenseInfo::CallActivationServer (string TX_RX_IDS) {}

void LicenseInfo::QueryLicenseUpdate (bool forceCheck) {}

void LicenseInfo::SignalServerError() {}

void LicenseInfo::NewActivation () {}

void LicenseInfo::ManualActivation () {}

const std::string LicenseInfo::GetLicenseURL() { return ""; }

bool LicenseInfo::UnknownStatus() { return false; }

void LicenseLog (const char* format, ...) {}

然后修改 Editor\Src\LicenseInfo.h,把 LicenseInfo::Flag 这个方法的实现修改如下:

static bool Flag (LicenseInfoFlag f)
{
    return true;
}

这样就会默认所有功能都是开启的,也不会检查本地是否有 license 文件了。

如同解题的方法永远不止一个,我们也有很多其他的方法来解决这个问题。比如在 WinMain 函数里把 LicenseInfo 的相关调用注释掉,但是因为还有很多其他地方使用 LicenseInfo,所以不如把 LicenseInfo 的实现改掉更快。也可以通过离线激活的方式,从 Unity 官网通过上传 Unity_v4.3.1f1.alf 再下载一个 Unity_v4.x.ulf 导入编辑器来激活。但是我在使用这个方式的时候遇到从 ulf 文件中读取 StopDate 时崩溃,需要修改 Editor\Src\LicenseManager.cpp1709 行为 std::string stopString = "2112-01-27T08:00:00";//GetDate("StopDate", doc); 来绕过。

0x05 编译

做了这么久的准备,总算可以编译代码了。其实这一步最简单!

Unity 源码路径下运行:

perl build.pl build --target=WindowsEditor

当然你也可以在 target 中加入 WindowsStandalonePlayer 等其他的平台,记得用逗号隔开就好。

等待大约10分钟。

等待时间插播一个其他话题。Unity 的代码量其实并不大,Runtime 部分30w行代码,Editor 代码14w行。相对于 Unreal 4 的150+80w代码已经相形见绌。Lumberyard 的代码因为分布较散,不好统计,但印象中比 Unreal 更多,毕竟塞进来了整个 CryENGINE,而且 AzCore AzFramework LmbrCentral 也不小,更何况还有繁杂的各类 Gems

Unity:

λ cloc Runtime\
    1842 text files.
    1841 unique files.
     219 files ignored.

https://github.com/AlDanial/cloc v 1.66  T=6.72 s (258.9 files/s, 68280.3 lines/s)
-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
C++                            708          46572          16649         230438
C/C++ Header                   904          21755          10788         110499
C#                             105           2117           1365          12547
Assembly                        10            545            646           1918
CSS                              2             99             13            756
C                                2            174            253            713
MSBuild script                   4              0             21            375
HLSL                             2             42             18            231
DOS Batch                        1             26              0             56
Perl                             1              6              0             42
-------------------------------------------------------------------------------
SUM:                          1739          71336          29753         357575
-------------------------------------------------------------------------------

λ cloc Editor\Src\
     602 text files.
     601 unique files.
      33 files ignored.

https://github.com/AlDanial/cloc v 1.66  T=1.88 s (318.0 files/s, 103003.2 lines/s)
-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
C++                            304          24339          17044         128097
C/C++ Header                   295           5252           2827          16445
-------------------------------------------------------------------------------
SUM:                           599          29591          19871         144542
-------------------------------------------------------------------------------

Unreal 4

λ cloc Engine\Source\Runtime\
    7644 text files.
    7640 unique files.
    1108 files ignored.

https://github.com/AlDanial/cloc v 1.66  T=51.05 s (148.4 files/s, 43955.9 lines/s)
-----------------------------------------------------------------------------------
Language                         files          blank        comment           code
-----------------------------------------------------------------------------------
C++                               3044         216871         110840        1103798
C/C++ Header                      4366         144631         208261         452020
C#                                 160            850            316           5195
XML                                  2             58             10            331
JavaScript                           1             58             64            261
Windows Resource File                2             37             46            129
-----------------------------------------------------------------------------------
SUM:                              7575         362505         319537        1561734
-----------------------------------------------------------------------------------

λ cloc Engine\Source\Editor\
    4650 text files.
    4648 unique files.
     480 files ignored.

https://github.com/AlDanial/cloc v 1.66  T=31.38 s (148.0 files/s, 39353.6 lines/s)
-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
C++                           2038         143587          65619         752908
C/C++ Header                  2498          57829          69772         136169
C#                             105            951            812           7208
MSBuild script                   2              0             14            109
-------------------------------------------------------------------------------
SUM:                          4643         202367         136217         896394
-------------------------------------------------------------------------------

0x06 最后

编译之后的可执行文件在 build\WindowsEditor\Unity.exe 编译完就可以开心的断点看代码了。其实我在不能断点的情况下靠着强大的 Resharper C++ 也阅读了一些代码,在这里也安利一下,如果还在用 Visual Assist 的可以考虑换这个工具,静态分析更加强大。

以后有时间再把看到的 Unity 中的一些代码总结到这里,给自己挖个坑,想填了再来填。(P.S. Lumberyard 的坑还没填的)