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。我的电脑里已经装了 vs2015 和 vs2017 了。不想把全家桶都装上,于是干脆 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 ok 的 warning。

最干净的办法是修改 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.cpp 的 1709 行为 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 的坑还没填的)