Ejemplo n.º 1
0
        static IEnumerable <CodeInstruction> RefreshPreviews(IEnumerable <CodeInstruction> instructions, ILGenerator generator)
        {
            float MirrorBuildingRotation(float yaw, BlueprintBuilding building)
            {
                if (buildingsAxis.ContainsKey(building.modelIndex) && buildingsAxis[building.modelIndex] == MajorAxis.XAXIS)
                {
                    return(MirrorRotation(yaw + 90f) - 90f);
                }

                return(MirrorRotation(yaw));
            }

            CodeMatcher matcher = new CodeMatcher(instructions, generator)
                                  .MatchForward(true,
                                                new CodeMatch(OpCodes.Ldelem, typeof(Vector4)),
                                                new CodeMatch(OpCodes.Stloc_S),
                                                new CodeMatch(OpCodes.Ldloca_S));

            matcher.Advance(1);

            object longAxisVar = matcher.Operand;

            while (matcher.Opcode != OpCodes.Stfld)
            {
                matcher.RemoveInstruction();
            }

            matcher.RemoveInstructions(2);

            object latAxisVar = matcher.Operand;

            while (matcher.Opcode != OpCodes.Stfld)
            {
                matcher.RemoveInstruction();
            }

            matcher.RemoveInstruction()
            .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, longAxisVar))
            .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, latAxisVar))
            .InsertAndAdvance(Transpilers.EmitDelegate <RefAction>(MirrorArea));

            matcher.MatchForward(false,
                                 new CodeMatch(OpCodes.Call, AccessTools.Method(typeof(BlueprintUtils), nameof(BlueprintUtils.TransitionWidthAndHeight))))
            .Advance(-3)
            .RemoveInstruction().RemoveInstruction().RemoveInstruction()
            .SetInstruction(Transpilers.EmitDelegate <Func <float, BlueprintBuilding, Vector2> >((yaw, building) =>
            {
                float x = building.localOffset_x;
                float y = building.localOffset_y;


                if ((mirrorLat && !mirrorLong || !mirrorLat && mirrorLong) && buildingsOffsets.ContainsKey(building.modelIndex))
                {
                    Vector2 offset   = buildingsOffsets[building.modelIndex];
                    float rotatedYaw = MirrorBuildingRotation(building.yaw, building);

                    offset = offset.Rotate(rotatedYaw + (mirrorLong ? 180 : 0));

                    x += offset.x;
                    y += offset.y;
                }

                return(BlueprintUtils.TransitionWidthAndHeight(yaw, x, y));
            }));

            matcher.MatchForward(false,
                                 new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(BlueprintBuilding), nameof(BlueprintBuilding.yaw)))
                                 ).Advance(1)
            .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, 30))
            .InsertAndAdvance(Transpilers.EmitDelegate <Func <float, BlueprintBuilding, float> >(MirrorBuildingRotation)).Advance(2);

            matcher.MatchForward(false,
                                 new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(BlueprintBuilding), nameof(BlueprintBuilding.yaw2)))
                                 ).Advance(1)
            .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, 30))
            .InsertAndAdvance(Transpilers.EmitDelegate <Func <float, BlueprintBuilding, float> >(MirrorBuildingRotation));

            matcher.MatchForward(true,
                                 new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(BuildPreview), nameof(BuildPreview.desc))),
                                 new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(PrefabDesc), nameof(PrefabDesc.isInserter))))
            .Advance(2);

            object previewVar2 = matcher.Operand;

            matcher.Advance(1)
            .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, previewVar2))
            .InsertAndAdvance(Transpilers.EmitDelegate <Action <BuildPreview> >(preview =>
            {
                if (preview.input != null && preview.input.desc.slotPoses.Length > preview.inputFromSlot &&
                    !preview.input.desc.isBelt)
                {
                    Quaternion invRot       = Quaternion.Inverse(preview.input.lrot);
                    Vector3 slotPosition    = preview.lpos - preview.input.lpos;
                    slotPosition            = invRot * slotPosition;
                    Quaternion slotRotation = invRot * preview.lrot;


                    for (int i = 0; i < preview.input.desc.slotPoses.Length; i++)
                    {
                        Pose slotPose = preview.input.desc.slotPoses[i];
                        if (!((slotPose.position - slotPosition).sqrMagnitude < 0.1f))
                        {
                            continue;
                        }
                        if (!slotPose.rotation.Approximately(slotRotation))
                        {
                            continue;
                        }
                        if (preview.inputFromSlot == i)
                        {
                            break;
                        }

                        preview.inputFromSlot = i;
                        break;
                    }
                }

                if (preview.output != null && preview.output.desc.slotPoses.Length > preview.outputToSlot &&
                    !preview.output.desc.isBelt)
                {
                    Quaternion invRot       = Quaternion.Inverse(preview.output.lrot);
                    Vector3 slotPosition    = preview.lpos2 - preview.output.lpos;
                    slotPosition            = invRot * slotPosition;
                    Quaternion slotRotation = invRot * (preview.lrot2 * Quaternion.Euler(0f, -180f, 0f));

                    for (int i = 0; i < preview.output.desc.slotPoses.Length; i++)
                    {
                        Pose slotPose = preview.output.desc.slotPoses[i];
                        if (!((slotPose.position - slotPosition).sqrMagnitude < 0.1f))
                        {
                            continue;
                        }
                        if (!slotPose.rotation.Approximately(slotRotation))
                        {
                            continue;
                        }
                        if (preview.outputToSlot == i)
                        {
                            break;
                        }

                        preview.outputToSlot = i;
                        break;
                    }
                }
            }));


            return(matcher.InstructionEnumeration());
        }
Ejemplo n.º 2
0
        static void PatchClearFromConstructionObstacles(CodeMatcher codeCursor, ILGenerator generator)
        {
            codeCursor.Start();
            codeCursor.MatchForward(false,
                                    new CodeMatch(OpCodes.Ldloc_1),
                                    new CodeMatch(OpCodes.Ldloc_3),
                                    new CodeMatch(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(List <GameObject>), nameof(List <GameObject> .Count))),
                                    new CodeMatch(OpCodes.Ldc_I4_0),
                                    new CodeMatch(OpCodes.Ceq),
                                    new CodeMatch(OpCodes.And),
                                    new CodeMatch(OpCodes.Stloc_1)
                                    );

            if (codeCursor.IsValid)
            {
                // Remove boolean result assignent as we are "moving" it to after obstacle highlighting block
                var labels = codeCursor.Instruction.ExtractLabels();
                codeCursor.RemoveInstructions(7);
                codeCursor.AddLabels(labels);

                codeCursor.MatchForward(true,
                                        new CodeMatch(OpCodes.Ldloc_3),
                                        new CodeMatch(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(List <GameObject>), nameof(List <GameObject> .Count))),
                                        new CodeMatch(OpCodes.Ldc_I4_0),
                                        new CodeMatch(OpCodes.Ble)
                                        );

                if (codeCursor.IsValid)
                {
                    var countCondBranchOperand = (Label)codeCursor.Operand;
                    codeCursor.MatchForward(false, new CodeMatch(instruction => instruction.labels.Contains(countCondBranchOperand)));

                    if (codeCursor.IsValid)
                    {
                        labels = codeCursor.Instruction.ExtractLabels();

                        // Make it to allow construction by clearing contruction obstacles for boolean result assignment if destroying obstacles is enabled
                        var disabledDestroyObstaclesLabel = generator.DefineLabel();
                        codeCursor.InsertAndAdvance(
                            new CodeInstruction(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(Config), nameof(Config.Instance))).WithLabels(labels),
                            new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(Config), nameof(Config.destroyLargerObstaclesOnConstruction))),
                            new CodeInstruction(OpCodes.Brfalse_S, disabledDestroyObstaclesLabel)
                            );

                        codeCursor.InsertAndAdvance(
                            new CodeInstruction(OpCodes.Ldloc_3),
                            new CodeInstruction(OpCodes.Call, AccessTools.Method($"{typeof(UpdateAllowedPatch)}:{nameof(ClearConstructionObstacles)}", new Type[] { typeof(List <GameObject>) }))
                            );

                        // Assign boolean result here (was before highlighting block)
                        codeCursor.InsertAndAdvance(
                            new CodeInstruction(OpCodes.Ldloc_1).WithLabels(disabledDestroyObstaclesLabel),
                            new CodeInstruction(OpCodes.Ldloc_3),
                            new CodeInstruction(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(List <GameObject>), nameof(List <GameObject> .Count))),
                            new CodeInstruction(OpCodes.Ldc_I4_0),
                            new CodeInstruction(OpCodes.Ceq),
                            new CodeInstruction(OpCodes.And),
                            new CodeInstruction(OpCodes.Stloc_1)
                            );
                    }
                }
            }
        }