记录使用 .Net Reflector 和 Reflexil 修改 Sky Force Reloaded(傲气雄鹰)星章倍率

814 阅读4分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

写在前面

  • 修改游戏的做法可能不合适,仅供个人娱乐、学习、测试代码安全之用
  • 仅讨论修改方法,不提供修改成品文件

背景

关于游戏内容

Sky Force Reloaded on Steam

  • 飞行射击游戏。没玩过的话建议先玩前作 Sky Force Anniversary
  • 玩法上,需要大量重复刷星章,来升级武器、购买 Power-ups 等
  • 本人为了缩短刷星时间,尝试修改

关于游戏的相关调研

  • 由较早版本的 Unity 制作
  • Backend 使用 Mono,未使用 IL2CPP,Assembly-CSharp.dll 未混淆
  • 使用含 Mono 插件的 Cheat Engine 7.2 修改失败,估计是内部使用了类似 Anti-Cheat Toolkit 的扩展
  • 已经有前人(peizhaochen)制作了7项修改器,但似乎不能直接修改星章,市面上又几乎没有其他可用的修改器

关于环境

  • Windows 10 专业版 20H2
  • .Net Reflector 10.1 Standard
  • 安装 Reflexil v2.4
  • 从 Steam 购买的正版 Sky Force Reloaded

修改方法

直接上结论,具体过程经历了多次实践和失败,见后文。

  • 用 .Net Reflector 打开游戏的 Assembly-CSharp.dll。
  • 打开空命名空间(-)下的 Player.EvCollectedStar(BonusStar) : Void 方法,得到代码,并作如下修改:
protected virtual void EvCollectedStar(BonusStar coStar)
{
    int nCollectedStars = 0;
    if (coStar.Type == eBonusType.Star)
    {
        this.m_fCollectedStars += TSingleton<CardsManager>.singleton.IsStarDoublerActive ? 2f : 1f;
        nCollectedStars = Mathf.FloorToInt(this.m_fCollectedStars);
        this.m_fCollectedStars -= nCollectedStars;
        //SaveGame.CurrentNumCollectedStarsNotSafe += nCollectedStars; // 原句,注释掉
        SaveGame.CurrentNumCollectedStarsNotSafe += nCollectedStars * 1000; // 修改为,令存档中的数值为实际收获的 1000 倍
    }
    else if (coStar.Type == eBonusType.Star2x)
    {
        this.m_fCollectedStars += TSingleton<CardsManager>.singleton.IsStarDoublerActive ? 10f : 5f;
        nCollectedStars = Mathf.FloorToInt(this.m_fCollectedStars);
        this.m_fCollectedStars -= nCollectedStars;
        //SaveGame.CurrentNumCollectedStarsNotSafe += nCollectedStars; // 原句,注释掉
        SaveGame.CurrentNumCollectedStarsNotSafe += nCollectedStars * 1000; // 同上
    }
    this.LaunchStarCollectedEvent(coStar, nCollectedStars, SaveGame.CurrentNumCollectedStars);
}
  • 使用 Reflexil 重写此方法,然后替换原 dll 即可。注意:
  1. 关于 Reflexil 的基本使用方法,见此处
  2. 点击 Compile 后可能报错“不存在或未定义相关方法”等,这时双击错误,编译窗口会跳转到出错的方法或定义,将其注释掉即可(这是作者在编译窗口留下的原话),或删掉也可以,没出错的不要动;
  3. 点击 Compile 后报错CS1073,是因为 Assembly-CSharp.dll 引用的 mscorlib.dll(与 Assembly-CSharp.dll 位于同一目录)的版本与 UnityEngine 命名空间内引用的 mscorlib.dll(版本 2.0.0.0)的不一致。这是很少见的情况。解决方法是,在点击 Compile 前,将 mscorlib.dll(与 Assembly-CSharp.dll 位于同一目录)重命名(如“mscorlib.dll0”)再点击 Compile,通过后撤销重命名就可以了。这是作者提供的方法,详见此处
  • 修改效果:打开游戏任意一关任意难度,至少收集到 1 个星章(否则不会触发 Player.EvCollectedStar(BonusStar) : Void 方法),然后想办法自杀或退出当前关卡,当然,正常通关也是可以的。战绩界面之前的星章界面,提示的是真正收集到的星章数;但当返回到选关界面,就会发现实际在存档中保存的是 1000 倍的星章数。
  • 反复刷取,或将倍率改得更大,可以得到较为满意的星章,用它就可以快速升级武器装备。

在这里插入图片描述

  • 若希望游戏结束后的星章界面也显示修改后的数值,而不要显示真实值,则找到 Stage.EvCollectedStar(BonusStar) : Void 方法,作如下修改:
private void EvCollectedStar(BonusStar coStar, int nEarnedStars, int nTotalStars)
{
    if (coStar.Type == eBonusType.Star)
    {
        this._Stats_StarsCollected++;
    }
    else if (coStar.Type == eBonusType.Star2x)
    {
        this._Stats_StarsCollected += 5;
    }
    //this._Stats_StarsEarned += nEarnedStars; // 原句,注释掉
    this._Stats_StarsEarned += nEarnedStars * 1000; // 修改为,令显示的数值为实际收获的 1000 倍,但不会保存到存档
    if (!TSingleton<CardsManager>.singleton.IsMoreStarsFromEnemiesActive)
    {
        this.AddPoints(coStar.Points);
    }
    else
    {
        this.AddPoints(coStar.Points / 2);
    }
}

如何找到修改处

具体查找过程,经历了多次失败。太具体的这里也暂时不写出来了,只总结一下大致方法和流程。

  • 首先检查代码的混淆情况和结构,发现未混淆,代码结构清晰,命名良好,这就很方便阅读和修改了;
  • 以星章为切入点,通过阅读代码结构确定其名称,是 Star,而不是 Point/Bonus 之类的近义词;
  • 搜索 Star,在搜索结果中,首先阅读方法名和定义名,找到感觉比较接近的,再详细阅读其方法的实现。感觉可能是目标的,就标记 Bookmark,或进一步 Analyze,查看它调用了谁以及谁调用了它;
  • 慢慢挖掘,直到找到一个方法,你发现它能够基本解释 Star 变化的原因,同时,这个方法和调用它的方法在逻辑上能够自洽,并且便于修改。那么,这个方法就可以作为修改目标了;
  • 修改它,放到程序里试运行,看是否达到目标。当然,这个方法可能并不能带来预期的效果,这时候就要考虑是否该方法的触发条件满足了,或者 Star 这个切入点根本就是错误的?这就需要反复尝试,直到成功,对其他的修改对象也是如此。