Unclaimed Package Is this your package? Claim it to unlock full analytics and manage your listing.
Claim This Package

Install via UPM

Add to Unity Package Manager using this URL

https://www.pkglnk.dev/injection.git

README Markdown

Copy this to your project's README.md

Style
Preview
pkglnk installs badge
## Installation

Add **Unity Injection** to your Unity project via Package Manager:

1. Open **Window > Package Manager**
2. Click **+** > **Add package from git URL**
3. Enter:
```
https://www.pkglnk.dev/injection.git
```

[![pkglnk](https://www.pkglnk.dev/badge/injection.svg?style=pkglnk)](https://www.pkglnk.dev/pkg/injection)

Dependencies (2)

README

UnityInjection

Unity注入模块,可以运行时改变被注入函数实现。

mono support il2cpp support GitHub last commit GitHub package.json version

Verified Verisons:

Unity 2021.3.x Unity 2022.3.x
:heavy_check_mark: :heavy_check_mark:

Purpose

开发此模块的最初动机是修改UnityEngine的源码。对这样一个具体问题一般化分析和设计后,最终实现顺便支持了用户自定义的装饰器和AOP。

是个轮子?

Unity的注入模块已经有一些其他大神的实现了,为什么还要造一个轮子呢?原因如下:

  1. 基于UnityEditor。一些注入模块,需要依赖外部工具;而此实现在完全在UnityEditor下注入。
  2. 支持IL2CPP。一些注入模块只支持Editor和Mono;而此实现支持所有平台和选项。
  3. 支持修改引擎源码。一些注入模块只能修改用户代码,无法注入引擎代码;而此实现可以注入引擎和用户代码。

直接修改DLL文件?

直接修改DLL文件是可行的,但是存在以下问题:

  1. 无法记录所做的修改
  2. 不方便团队共享和版本控制
  3. 不能改变Unity版本
  4. 修改步骤繁琐,容易误操作

Quick Start

Installation

install via git url

step 1. 安装依赖库:DirectRetrieveAttribute

step 2. 通过git url安装

install via openupm (recommend)

execute command line:

openupm add com.bbbirder.injection

Basic Usage

一个修改Debug.Log的例子

using com.bbbirder.injection;
using UnityEngine;

// this illustration shows how to hook `Debug.Log`
public class FirstPatch
{
    // the field to be overwrited to original method
    static Action<object> RawLog;

    static void Log(object msg){
        return RawLog.Invoke("[msg] "+msg); 
    }

    internal class MethodReplacer : IInjection
    {
        // implement method: ProvideInjections
        public IEnumerable<InjectionInfo> ProvideInjections()
        {
            yield return InjectionInfo.Create<Action<object>>(
                Debug.Log,      // replace Debug.Log
                FirstPatch.Log, // with FirstPatch.Log
                f => FirstPatch.RawLog = f // save origin method to FirstPatch.RawLog
            );
        }
    }
}

自定类继承自IInjection,并实现接口

ProvideInjections中返回一个或多个InjectionInfo

初始化的时候调用:

FixHelper.InstallAll();// 查找所有注入标记,并使生效

测试成果:

Debug.Log("hello"); //output: [msg] hello

更多用法

装饰器

数据代理

依赖注入

更多使用方法参考附带的Sample工程

Possible Problems

Problem Reason Solution
文档示例中的异步方法无法打印完整 WebGL平台不支持多线程 文档中使用的是Task,改成UniTask或其他方式即可
注入时未搜索到标记的方法 Managed Stripping Level过高,Attribute被移除 降低Stripping Level或 保留代码
注入时报UnauthorizedAccessExceptioncannot access file 文件访问权限不够 管理员运行 或 修改目标文件夹的安全设置(属性-安全-编辑,添加当前用户的完全控制)
打包时报the same key has already been added. Key: mscorlib 不支持的Unity版本,程序集依赖树包含多个不同版本的mscorlib 暂不提供解决方案,可自行修改类型引入部分逻辑,如果这个问题影响的人多则解决之

How it works

UnityInjection在编译时织入,不用担心运行时兼容性

织入时机:

  • 运行时:在打包的Link阶段修改DLL,如此使Runtime生效
  • 编辑器时:Domain Reload

Todo List

  1. 更多Unity版本测试,有问题提ISSUE附Unity版本,或者PR。
  2. Editor加速注入

当前的方法在Editor下也会执行织入,这将导致domain reload一定程度变慢,这对于超大代码库来说是难以忍受的。 事实上Editor下的织入不是必要的。作者忙完本职工作后,会来完善此处。

  1. 支持泛型

泛型的支持有一些特殊性,这种特殊性需要额外的工作:

Inject Phase Fix Phase
AOT approach 与非泛型方法相同 -
RT approach 不同的GenericInstance有时共享同一个方法体,有时又独享之。如:Full Generic Sharing方法存在一个共享的方法体;普通Generic Sharing则按照泛型类型内存大小共享方法体 泛型实例是运行时创建的。UnityInjection需要实现一种GenericInstantiation(classInst&methodInst)遍历的技术。这种技术对于IL2CPP backend来说,可以轻易实现;但是对于Mono backend,则需要对cctor的额外注入。

Comments

No comments yet. Be the first!