public static void Init()
        {
            Type origType = _HBSAssembly.GetType(TARGET_TYPE_NAME);

            try
            {
                _ownTaskField =
                    HarmonyUtils.CreateInstanceFieldRef <bool>(origType,
                                                               I_SortMoveCandidatesByInfMapNode.OwnTaskTypeName);
                _thinkTaskField = HarmonyUtils.CreateStaticFieldRef <Task <bool> >(origType,
                                                                                   I_SortMoveCandidatesByInfMapNode.ThinkTaskTypeName);

                _comparer = origType.GetNestedType("AccumulatorComparer", AccessTools.all);

                _drawDebugLines = origType.GetMethod("drawDebugLines", AccessTools.all);

                _targetMethod = origType.GetMethod("Tick", AccessTools.all);
                MethodInfo prefix =
                    typeof(H_SortMoveCandidatesByInfMapNode_Tick)
                    .GetMethod(nameof(Prefix), AccessTools.all);

                HarmonyUtils.Harmony.Patch(_targetMethod, new HarmonyMethod(prefix));
            }
            catch (Exception e)
            {
                Utils.Logger.LogError($"{Utils.LOG_HEADER} Failed to patch {TARGET_TYPE_NAME}", e);
            }
        }
Esempio n. 2
0
        /// <summary>
        ///     Our detour should execute ONLY if the caller is explicitly allowed.
        ///     This prevents unexpected behaviors, but could require some changes in this method to allow compatibility with other
        ///     mods.
        ///     HACK - [ISSUE-10] [ISSUE-18]
        /// </summary>
        /// <param name="st"></param>
        /// <returns></returns>
        private bool IsAllowedCaller(StackTrace st)
        {
            // Extract both type and method
            var callerType   = st.GetFrame(2)?.GetMethod()?.DeclaringType;
            var callerMethod = st.GetFrame(1)?.GetMethod();

            // They should never be null because stack traces are usually longer than 3 lines, but let's add this check because you'll never know
            if (callerType == null || callerMethod == null)
            {
                Log._Debug($"[{nameof(NetManagerDetour)}.{nameof(IsAllowedCaller)}] {nameof(callerType)} or {nameof(callerMethod)} is null.");
                Log._Debug($"[{nameof(NetManagerDetour)}.{nameof(IsAllowedCaller)}] Stacktrace is\n{st}");

                return(false);
            }

            Log._Debug($"[{nameof(NetManagerDetour)}.{nameof(IsAllowedCaller)}] Caller is {callerType.Name}.{callerMethod.Name}");

            // ReSharper disable once ConvertIfStatementToReturnStatement
            if (callerType == typeof(NetTool))
            {
                // We must allow only CreateNode (and eventually patched Harmony methods)
                // This is the compatibility patch for Network Skins 2
                return(HarmonyUtils.IsNameMatching(callerMethod.Name, "CreateNode"));
            }

            return(false);
        }
Esempio n. 3
0
        private static IEnumerable <CodeInstruction> PatchRequirementAmountIndicator(
            IEnumerable <CodeInstruction> instructions)
        {
            HarmonyUtils.LogDebugBuildOnly("Transpiler patch: SetupRequirement");

            var searchTemplate = new List <Tuple <int, CodeInstruction> >
            {
                new Tuple <int, CodeInstruction>(0, new CodeInstruction(OpCodes.Call,
                                                                        AccessTools.Method(typeof(InventoryGui), "HideRequirement",
                                                                                           new[] { typeof(Transform) }))),
                new Tuple <int, CodeInstruction>(3, new CodeInstruction(OpCodes.Ldloc_2)),
                new Tuple <int, CodeInstruction>(5, new CodeInstruction(OpCodes.Call,
                                                                        AccessTools.Method(typeof(int), "ToString"))),
                new Tuple <int, CodeInstruction>(6, new CodeInstruction(OpCodes.Callvirt,
                                                                        AccessTools.PropertySetter(typeof(Text), "text")))
            };

            var patchCount       = 0;
            var instructionsList = instructions.ToList();

            for (var i = 0; i < instructionsList.Count; i++)
            {
                if (!instructionsList.DoInstructionsMatchTemplate(i, searchTemplate))
                {
                    continue;
                }
                HarmonyUtils.LogDebugBuildOnly("Template matched!");
                // ok, we sure we are kinda sure we are patching the right thing
                var numOperandReference    = instructionsList[i + 7].operand;
                var amountOperandReference = instructionsList[i + 8].operand;
                instructionsList.RemoveRange(i + 4, 2);
                instructionsList.InsertRange(i + 4, new List <CodeInstruction>
                {
                    new CodeInstruction(OpCodes.Ldstr, "{0}/{1}"),
                    new CodeInstruction(OpCodes.Ldloc_S, numOperandReference),
                    new CodeInstruction(OpCodes.Box, typeof(int)),
                    new CodeInstruction(OpCodes.Ldloc_S, amountOperandReference),
                    new CodeInstruction(OpCodes.Box, typeof(int)),
                    new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(string), "Format",
                                                                         new[] { typeof(string), typeof(object), typeof(object) }))
                });
                HarmonyUtils.LogDebugBuildOnly("Patch OK");
                patchCount = 1;
            }

            HarmonyUtils.LogDebugBuildOnly($"Patch count {patchCount}");
            if (patchCount == 0)
            {
                Plugin.Log.LogError(
                    "Crafting amount indicator won't work properly");
            }
            return(instructionsList);
        }
Esempio n. 4
0
        private static IEnumerable <CodeInstruction> CountItemsHaveItemsReferencesPatch(MethodBase method,
                                                                                        IEnumerable <CodeInstruction> instructions)
        {
            HarmonyUtils.LogDebugBuildOnly($"Transpiler patching {method.DeclaringType.Name}::{method}");
            var instructionsList = instructions.ToList();
            var patchCount       = 0;

            for (var i = instructionsList.Count - 1; i >= 0; i--)
            {
                var ins = instructionsList[i];
                if (ins.opcode != OpCodes.Callvirt)
                {
                    continue;
                }
                var patchPair = methodPatchMap
                                .SingleOrDefault(pair => ins.Is(pair.Item1));
                if (patchPair == null)
                {
                    continue;
                }
                HarmonyUtils.LogDebugBuildOnly("Patching:");
                instructionsList[i] = patchPair.Item2;
                HarmonyUtils.LogDebugBuildOnly("Post patch instruction is:");
                HarmonyUtils.LogDebugBuildOnly($"{i} - {instructionsList[i]}");
                patchCount += 1;
            }

            HarmonyUtils.LogDebugBuildOnly($"Patch count {patchCount}");
            if (patchCount == 0)
            {
                Plugin.Log.LogError(
                    "Counting/deducting patching was not successful. CratingWithContainers will not work properly if at all.\n" +
                    $"Dumping initial instruction list:\n{string.Join("\n", instructionsList.Select((instruction, i) => $" {i} - {instruction}"))}");
            }

            return(instructionsList);
        }