InjectFix Documentation

repository·master·Indexed 24 days ago

https://github.com/tencent/injectfix

A hotfix framework for Unity developers to fix C# logic bugs without requiring full app updates. It supports all Unity versions and platforms, providing a non-intrusive integration that allows logic updates via a two-stage workflow: 'Inject' for one-time code preprocessing and 'Fix' for generating .patch.bytes files. Key features include direct C# updates, secure private patch formats, and support for namespace-wide configuration using Reflection.

Tokens
7K
Snippets
19
Records
36
Agent score
82%

What's inside InjectFix

  1. Overview of InjectFix for Unity

    master

    InjectFix is a hotfix solution for Unity business logic. It supports the full series of Unity versions and all platforms. Key features include:

    • Direct C# Updates: You can update logic by directly modifying C# code within the Unity project.
    • Non-intrusive Integration: Existing projects can use InjectFix without needing to modify original source code.
    • Secure Patch Format: Each game uses its own private patch format, ensuring better security.
  2. Overview of InjectFix

    master
    InjectFix is a hotfix solution for Unity code logic. It allows developers to fix bugs in Unity projects by modifying C# code directly without needing to modify the original project source code. It provides a private patch format for each game to enhance security.
  3. The InjectFix workflow: Inject vs Fix

    master

    The InjectFix process consists of two distinct phases:

    1. Inject: A preprocessing step performed on the source code. This must be done once (typically during the build/packaging process). Only code that has been preprocessed via Inject can successfully load patches at runtime.
    2. Fix: The process of generating a patch. This compares the current compiled DLL (containing the fixed logic) against the version that was previously Injected to create a .patch.bytes file.

    Important Constraint: Do not run Inject between modifying code and running Fix. If you run Inject after modifying code, InjectFix will treat the new code as the 'online version' and refuse to generate a patch.

    Recommended Editor Workflow:

    1. Modify code to the correct logic.
    2. Apply the [Patch] attribute to the target function.
    3. Run Fix to generate the patch.
    4. Revert the code to the 'broken' state.
    5. Run Inject to simulate the online environment.
  4. Understand the IFix workflow: Inject vs Fix

    master

    IFix operates using two distinct stages:

    1. Inject: A one-time preprocessing step. This must be done when sending the package to users. It prepares the code so that it is capable of switching to patch logic at runtime.
    2. Fix: The process of generating a patch. This is done after you have modified your code and want to create a .patch.bytes file to fix the logic in the field.

    Recommended Editor Workflow: To avoid the limitation where IFix refuses to generate a patch if it thinks you are already on the 'online' version:

    1. Modify code to the correct logic.
    2. Run InjectFix/Fix to generate the patch.
    3. Revert the code to the incorrect logic.
    4. Run InjectFix/Inject to simulate the problematic online version.
  5. Configure classes for preprocessing

    master

    iFix relies on static code insertion. You must configure which classes are preprocessed so they can be patched. You can use static or dynamic lists.

    Rules for Configuration:

    1. Apply the [Configure] attribute to the configuration class.
    2. Apply the [IFix] attribute to a static property/field within that class that returns an IEnumerable<Type>.

    Dynamic Configuration Example: Using a dynamic list (e.g., via LINQ) is recommended as it automatically includes new classes added to a namespace without requiring manual updates to the configuration.

    [Configure]
    public class InterpertConfig {
        [IFix]
        static IEnumerable<Type> ToProcess
        {
            get
            {
                return (from type in Assembly.Load("Assembly-CSharp").GetTypes()
                        where type.Namespace == "XLua" && !type.Name.Contains("<")
                        select type);
            }
        }
    }
  6. Inject code for runtime patching

    master

    The Inject process is a one-time operation (typically performed when building the package) that pre-processes the code. Only code that has been pre-processed via Inject can load patches at runtime.

    Steps:

    1. Revert your code to the 'problematic' (original) logic.
    2. In the Unity Editor, execute the menu command: InjectFix/Inject.
    3. To apply a patch at runtime, copy your generated patch file (e.g., Assembly-CSharp.patch.bytes) to Assets/IFix/Resources.
  7. Configure IFix code preprocessing

    master

    To enable hotfixing, you must first configure which classes should be preprocessed. This allows the preprocessed code to switch to the patch code at runtime.

    Requirements:

    1. The configuration class must be placed in an Editor directory.
    2. The configuration class must be decorated with the [Configure] attribute.
    3. The property decorated with [IFix] must be static and return an IEnumerable<Type>.

    You can manually list types or use Reflection/LINQ to include entire namespaces.

    [Configure]
    public class HelloworldCfg
    {
        [IFix]
        static IEnumerable<Type> hotfix
        {
            get
            {
                return new List<Type>()
                {
                    typeof(IFix.Test.Calculator)
                };
            }
        }
    }
  8. Generate a patch using the Fix menu

    master

    To generate a patch for a specific function:

    1. Open the source file (e.g., Calc.cs).
    2. Apply the [Patch] attribute to the function you wish to fix.
    3. In the Unity Editor, execute the menu command: InjectFix/Fix.
    4. Upon success (process success), a file named Assembly-CSharp.patch.bytes will be created in your project root directory.
  9. Create a patch for a function

    master

    To make a function eligible for hotfixing, decorate it with the [Patch] attribute.

    1. Add [Patch] to the target function:
    [Patch]
    public int Add(int a, int b)
    {
        return a + b;
    }
    1. In the Unity Editor, execute the menu command: "InjectFix/Fix".
    2. The generated patch file will be saved in your project directory with the naming convention {Dll Name}.patch.bytes (e.g., Assembly-CSharp.patch.bytes).
    3. Upload this file to the target device and load it using PatchManager.Load.
  10. Configure code for hotfixing

    master

    To enable hotfixing for specific classes, you must define a configuration class. This configuration tells the InjectFix preprocessor which types are eligible to be switched to patch code at runtime.

    Requirements:

    1. The configuration class must be placed in an Editor directory.
    2. The class must be decorated with the [Configure] attribute.
    3. The configuration property must be decorated with the [IFix] attribute and must be declared as static.
    4. The property must return an IEnumerable<Type>.

    You can manually list types or use LINQ and Reflection to include entire namespaces automatically.

    [Configure]
    public class HelloworldCfg
    {
        [IFix]
        static IEnumerable<Type> hotfix
        {
            get
            {
                return new List<Type>()
                {
                    typeof(IFix.Test.Calculator)
                };
            }
        }
    }
  11. Create a hot patch

    master

    To make a function eligible for hot patching, decorate it with the [Patch] attribute.

    [Patch]
    public int Add(int a, int b)
    {
        return a + b;
    }

    Generating the patch file

    For functions without conditional compilation macros:

    1. Apply the [Patch] attribute to the target function.
    2. In the Unity Editor, execute the menu command: InjectFix/Fix.
    3. The patch file will be generated in your project directory with the naming convention {Dll Name}.patch.bytes (e.g., Assembly-CSharp.patch.bytes).

    For functions with conditional compilation macros: If the function contains #if macros (e.g., #if UNITY_EDITOR), generating the patch directly in the Editor may result in a patch that does not match the runtime environment on a mobile device. This can lead to logic errors or missing function calls. Refer to the FAQ for handling conditional compilation macros correctly.

  12. Configure classes for hot patching

    master

    iFix requires pre-processing of specific classes to enable hot patching. You must define which types should be processed using a configuration class.

    Requirements:

    1. The configuration class must be decorated with the [Configure] attribute.
    2. The property containing the list of types must be decorated with the [IFix] attribute.
    3. The property must be static.

    You can use a static list or a dynamic list (using IEnumerable<Type>) to specify types. Dynamic lists are recommended as they automatically include new types added to a namespace without requiring configuration updates.

    Example of dynamic configuration for all types in the XLua namespace (excluding anonymous types):

    [Configure]
    public class InterpertConfig {
        [IFix]
        static IEnumerable<Type> ToProcess
        {
            get
            {
                return (from type in Assembly.Load("Assembly-CSharp").GetTypes()
                        where type.Namespace == "XLua" && !type.Name.Contains("<")
                        select type);
            }
        }
    }