InjectFix icon indicating copy to clipboard operation
InjectFix copied to clipboard

CustomBridge没有起到作用

Open LyneXiao opened this issue 5 years ago • 3 comments

在测试使用示例时,我发现CustomBridge并不能达到预期的效果。下面是NewClassTest的修改:

//#define TEST
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using IFix.Core;
using System.IO;

//1、执行菜单“InjectFix/Fix”生成补丁;
//2、注释“NewBehaviourScript”,“SubSystem2”两个类,以及NewClassTest的Init函数里头new SubSystem2的那行语句;
//3、执行菜单“InjectFix/Inject”,模拟线上没有“NewBehaviourScript”,“SubSystem2”的版本;
//4、NewClassTest.cs拖到场景,运行看下效果,此时只加载SubSystem1;
//5、把生成的补丁拷贝到Resources下,再次运行看下效果;

public interface IMonoBehaviour
{
    void Start();//简单demo,只定义了Start方法,实际Awake,Update,OnDestroy。。。都类似

    void Update();
}

public interface ISubSystem
{
    bool running { get; }

    void Destroy();

    void Start();

    void Stop();
}

public class SubSystem1 : ISubSystem
{
    public bool running { get { return true; } }

    public void Start()
    {
        Debug.Log("SubSystem1.Start");
    }

    public void Stop()
    {
        Debug.Log("SubSystem1.Stop");
    }

    public void Destroy()
    {
        Debug.Log("SubSystem1.Destroy");
    }
}

#if TEST
[IFix.Interpret]
public class NewBehaviourScript : IMonoBehaviour
{
    private int tick = 0;

    public void Start()
    {
        Debug.Log("NewBehaviourScript.Start");
    }

    public void Update()
    {
        if (tick++ % 60 == 0)
        {
            Debug.Log("NewBehaviourScript.Update");
        }
    }
}

[IFix.Interpret]
public class SubSystem2 : ISubSystem
{
    public bool running { get { return true; } }

    public void Start()
    {
        Debug.Log("SubSystem2.Start, create GameObject and attach a NewBehaviourScript");
        var go = new GameObject("hehe");
        var behaviour = go.AddComponent(typeof(VMBehaviourScript)) as VMBehaviourScript;
        behaviour.VMMonoBehaviour = new NewBehaviourScript();
    }

    public void Stop()
    {
        Debug.Log("SubSystem2.Stop");
    }

    public void Destroy()
    {
        Debug.Log("SubSystem2.Destroy");
    }
}
#endif

public class NewClassTest : MonoBehaviour
{
    List<ISubSystem> subsystems = new List<ISubSystem>();

    void Awake()
    {
        var patch = Resources.Load<TextAsset>("Assembly-CSharp.patch");
        if (patch != null)
        {
            Debug.Log("loading Assembly-CSharp.patch ...");
            var sw = System.Diagnostics.Stopwatch.StartNew();
            PatchManager.Load(new MemoryStream(patch.bytes));
            Debug.Log("patch Assembly-CSharp.patch, using " + sw.ElapsedMilliseconds + " ms");
        }
        Init();
    }

    [IFix.Patch]
    private void Init()
    {
        subsystems.Add(new SubSystem1());
#if TEST
        subsystems.Add(new SubSystem2());
        StartCoroutine(UpdateTest());
#endif
    }

#if TEST
    [IFix.Interpret]
    private IEnumerator UpdateTest()
    {
        while (true)
        {
            yield return new WaitForSeconds(1);
            Debug.Log("11111111111111111111");
        }
    }
#endif


    void Start()
    {
        foreach (var subSystem in subsystems)
        {
            subSystem.Start();
        }
    }

    void OnDestroy()
    {
        foreach (var subSystem in subsystems)
        {
            subSystem.Destroy();
        }
    }
}


[IFix.CustomBridge]
public static class AdditionalBridge
{
    static List<Type> bridge = new List<Type>()
    {
        typeof(ISubSystem),
        typeof(IMonoBehaviour),
        typeof(IEnumerator)
    };
}

修改后的示例中,我增加了一个协程方法,同时在Bridge中增加了IEnumerator,但是运行加载热更文件时会报错:

KeyNotFoundException: The given key was not present in the dictionary.
System.Collections.Generic.Dictionary`2[TKey,TValue].get_Item (TKey key) (at <e1319b7195c343e79b385cd3aa43f5dc>:0)
IFix.Core.PatchManager.readSlotInfo (System.IO.BinaryReader reader, System.Collections.Generic.Dictionary`2[TKey,TValue] itfMethodToId, System.Type[] externTypes, System.Int32 maxId) (at <ba81e2664e14464ea91a7e42530565c9>:0)
IFix.Core.PatchManager.Load (System.IO.Stream stream) (at <ba81e2664e14464ea91a7e42530565c9>:0)
NewClassTest.Awake () (at <544c37ead6fa48b194169c8b57481067>:0)

新加的协程无法正常运行。

但奇怪的是如果我在原代码(Inject时的代码)中多加入另一个协程方法,就算不在CustomBridge中声明IEnumerator,patch也能正常加载并运行。

是我哪里使用的方式不正确吗?待求证并指明解决方案

LyneXiao avatar Aug 24 '20 06:08 LyneXiao

如果之前有过返回 IEnumerator 类型的函数,那[IFix.Interpret]就没问题; 如果之前没有过,就得手动加个接口,把 IEnumerator<System.Object> 放到[IFix.CustomBridge]里。

annayxguo avatar Sep 06 '20 12:09 annayxguo

如果之前有过返回 IEnumerator 类型的函数,那[IFix.Interpret]就没问题; 如果之前没有过,就得手动加个接口,把 IEnumerator<System.Object> 放到[IFix.CustomBridge]里。

我尝试过,并不能解决问题。 协程方法返回的是System.Collections.IEnumerator,而不是System.Collections.Generic.IEnumerator<out T>,并不是一个派生接口,按说在IFix.CustomBridge中加IEnumerator应该可以生效,而不用加 IEnumerator<System.Object> 。

LyneXiao avatar Sep 16 '20 09:09 LyneXiao

更新下InjectFix,还是添加 IEnumerator<System.Object>

反编译看下,因为UpdateTest(),编译器生成一个类,该类实现了 IEnumerator<System.Object>,IEnumerator ,IDisposable image

而IEnumerator<System.Object> 实现 IDisposable, IEnumerator ,所以即使只加该接口,另两个也会自动加入 image

但IEnumerator 没有实现任何接口,只添加该接口,会少东西 image

annayxguo avatar Sep 16 '20 11:09 annayxguo