Пример #1
0
        public override void UpdatePreviewModels(BuildModel model)
        {
            for (int i = 1; i < bpCursor; i++)
            {
                BuildPreview buildPreview = bpPool[i];
                if (buildPreview != null && buildPreview.bpgpuiModelId > 0 && buildPreview.isConnNode)
                {
                    if (buildPreview.objId > 0)
                    {
                        factory.cargoTraffic.SetBeltSelected(factory.entityPool[buildPreview.objId].beltId);
                    }
                    else
                    {
                        uint color = (uint)buildPreview.desc.beltSpeed;
                        if (buildPreview.outputObjId == 0 || buildPreview.inputObjId == 0 || buildPreview.coverbp != null)
                        {
                            model.connRenderer.AddBlueprintBeltMajorPoint(buildPreview.lpos, buildPreview.lrot, color);
                        }
                        else
                        {
                            model.connRenderer.AddBlueprintBeltPoint(buildPreview.lpos, buildPreview.lrot, color);
                        }
                    }

                    model.connRenderer.AddXSign(buildPreview.lpos, buildPreview.lrot);
                }
            }
        }
Пример #2
0
        public static void ConcurrentConnectBuildings(int threadIndex, PastedEntity pastedEntity)
        {
            if (pastedEntity.sourceBuilding.altitude == 0)
            {
                return;
            }

            BuildPreview buildPreview = pastedEntity.buildPreview;

            buildPreview.input         = null;
            buildPreview.inputFromSlot = 0;
            buildPreview.inputToSlot   = 0;

            var pastedConnectedBuildingId = PASTE_INDEX_MULTIPLIER * pastedEntity.pasteIndex + pastedEntity.sourceBuilding.connectedBuildingId;

            if (pastedConnectedBuildingId != 0 &&
                BlueprintManager.pastedEntities.TryGetValue(pastedConnectedBuildingId, out PastedEntity otherPastedEntity) &&
                otherPastedEntity.type == EPastedType.BUILDING &&
                otherPastedEntity.status != EPastedStatus.REMOVE)
            {
                buildPreview.input         = otherPastedEntity.buildPreview;
                buildPreview.inputFromSlot = 15;
                buildPreview.inputToSlot   = 14;
            }
        }
Пример #3
0
        private static void MatchInserterEntityOnly(BuildTool_BlueprintPaste tool, BuildPreview bp)
        {
            IEnumerable <CodeInstruction> Transpiler(IEnumerable <CodeInstruction> instructions)
            {
                CodeMatcher matcher = new CodeMatcher(instructions)
                                      .MatchForward(true,
                                                    new CodeMatch(OpCodes.Ldloca_S),
                                                    new CodeMatch(OpCodes.Call, AccessTools.PropertyGetter(typeof(ColliderData), nameof(ColliderData.objType)))
                                                    )
                                      .MatchForward(false,
                                                    new CodeMatch(OpCodes.Ldloca_S),
                                                    new CodeMatch(OpCodes.Call, AccessTools.PropertyGetter(typeof(ColliderData), nameof(ColliderData.objType)))
                                                    );

                matcher.Opcode  = OpCodes.Nop;
                matcher.Operand = null;
                matcher.Advance(1)
                .SetInstructionAndAdvance(new CodeInstruction(OpCodes.Nop))
                .SetInstructionAndAdvance(new CodeInstruction(OpCodes.Nop))
                .SetOpcodeAndAdvance(OpCodes.Br);

                return(matcher.InstructionEnumeration());
            }

            // make compiler happy
            _ = Transpiler(null);
        }
Пример #4
0
 private static void CheckInserter(BuildTool_BlueprintPaste tool, BuildPreview preview)
 {
     if (preview.input != null && preview.input.desc.isBelt)
     {
         if (preview.input.IsCollide())
         {
             preview.input = null;
             MatchInserterEntityOnly(tool, preview);
         }
         else if (preview.input.coverObjId != 0)
         {
             preview.inputObjId = preview.input.coverObjId;
             preview.input      = null;
         }
     }
     if (preview.output != null && preview.output.desc.isBelt)
     {
         if (preview.output.IsCollide())
         {
             preview.output = null;
             MatchInserterEntityOnly(tool, preview);
         }
         else if (preview.output.coverObjId != 0)
         {
             preview.inputObjId = preview.output.coverObjId;
             preview.output     = null;
         }
     }
 }
Пример #5
0
        public static void OnPaste(BuildTool_BlueprintPaste __instance)
        {
            if (UndoManager.IgnoreAllEvents.Value)
            {
                return;
            }
            if (NebulaModAPI.IsMultiplayerActive)
            {
                if (NebulaModAPI.MultiplayerSession.LocalPlayer.IsClient)
                {
                    return;
                }
            }

            List <int> objectIds = new List <int>(__instance.bpCursor);

            for (int l = 0; l < __instance.bpCursor; l++)
            {
                BuildPreview preview = __instance.bpPool[l];
                objectIds.Add(preview.objId);
            }

            Vector3[] dots = new Vector3[__instance.dotsCursor];
            Array.Copy(__instance.dotsSnapped, dots, __instance.dotsCursor);

            PlayerUndo    data = UndoManager.GetCurrentPlayerData();
            UndoBlueprint undo = new UndoBlueprint(data, objectIds, __instance.blueprint, dots, __instance.yaw);

            data.AddUndoItem(undo);
        }
Пример #6
0
        public static void ConcurrentEnoughItemCheck(BuildPreview buildPreview)
        {
            if (buildPreview.condition != EBuildCondition.Ok)
            {
                return;
            }

            PlayerAction_Build actionBuild = GameMain.data.mainPlayer.controller.actionBuild;

            lock (actionBuild)
            {
                // only check that we have enough items
                if (buildPreview.coverObjId == 0 || buildPreview.willCover)
                {
                    int id  = buildPreview.item.ID;
                    int num = 1;
                    if (actionBuild.tmpInhandId == id && actionBuild.tmpInhandCount > 0)
                    {
                        num = 1;
                        actionBuild.tmpInhandCount--;
                    }
                    else
                    {
                        actionBuild.tmpPackage.TakeTailItems(ref id, ref num, false);
                    }


                    if (num == 0)
                    {
                        buildPreview.condition = EBuildCondition.NotEnoughItem;
                    }
                }
            }
        }
Пример #7
0
            public static void PlayerAction_BuildDetermineBuildPreviewsPostfix(PlayerAction_Build __instance)
            {
                // Do we have cached inserters?
                var ci = PatchCopyInserters.cachedInserters;

                if (CopyInserters.copyEnabled && ci.Count > 0)
                {
                    var bpCount = __instance.buildPreviews.Count;
                    for (int i = 0; i < bpCount; i++)
                    {
                        BuildPreview buildingPreview = __instance.buildPreviews[i];

                        if (!buildingPreview.item.prefabDesc.isInserter)
                        {
                            foreach (var inserter in ci)
                            {
                                var bp = BuildPreview.CreateSingle(LDB.items.Select(inserter.protoId), LDB.items.Select(inserter.protoId).prefabDesc, true);
                                bp.ResetInfos();

                                bp.lpos           = buildingPreview.lpos + buildingPreview.lrot * inserter.posDelta;
                                bp.lrot           = buildingPreview.lrot * inserter.rot;
                                bp.lpos2          = buildingPreview.lpos + buildingPreview.lrot * inserter.pos2Delta;
                                bp.lrot2          = buildingPreview.lrot * inserter.rot2;
                                bp.ignoreCollider = true;
                                __instance.AddBuildPreview(bp);
                            }
                        }
                    }
                }
            }
        public static void UpdatePreviews_Postfix(PlayerAction_Build __instance, List <Renderer> ___previewRenderers)
        {
            if (CopyInserters.IsCopyAvailable() && CopyInserters.copyEnabled)
            {
                var bpCount = __instance.buildPreviews.Count;
                for (int i = 0; i < bpCount; i++)
                {
                    BuildPreview buildPreview = __instance.buildPreviews[i];

                    if (buildPreview.item.prefabDesc.isInserter &&
                        buildPreview.condition == EBuildCondition.Ok &&
                        buildPreview.outputObjId == 0 && buildPreview.inputObjId == 0)
                    {
                        var originalMaterial = ___previewRenderers[buildPreview.previewIndex].sharedMaterial;

                        // this makes the inserter preview white-ish if not connected
                        var newMaterial = UnityEngine.Object.Instantiate <Material>(Configs.builtin.previewGizmoMat_Inserter);
                        newMaterial.SetVector("_Position1", originalMaterial.GetVector("_Position1"));
                        newMaterial.SetVector("_Position2", originalMaterial.GetVector("_Position2"));
                        newMaterial.SetVector("_Rotation1", originalMaterial.GetVector("_Rotation1"));
                        newMaterial.SetVector("_Rotation2", originalMaterial.GetVector("_Rotation2"));
                        ___previewRenderers[buildPreview.previewIndex].sharedMaterial = newMaterial;
                    }
                }
            }
        }
Пример #9
0
        public void AddBPGPUIModel(BuildPreview preview)
        {
            if (preview == null || preview.bpgpuiModelId <= 0)
            {
                return;
            }

            if (!preview.needModel)
            {
                return;
            }

            ModelProto modelProto = LDB.models.Select(preview.desc.modelIndex);
            Color32    color      = Configs.builtin.copyErrorColor;

            if (modelProto.RendererType == 2)
            {
                GetInserterT1T2(preview.objId, out bool flag, out bool flag2);

                if (preview.objId > 0)
                {
                    animPool[preview.bpgpuiModelId] = factory.entityAnimPool[preview.objId];
                }

                animPool[preview.bpgpuiModelId].state = (uint)((color.r << 24) + (color.g << 16) + (color.b << 8) + color.a);
                planet.factoryModel.bpgpuiManager.AddBuildPreviewModel(preview.desc.modelIndex, out preview.bpgpuiModelInstIndex, preview.bpgpuiModelId,
                                                                       preview.lpos, preview.lrot, preview.lpos2, preview.lrot2, flag ? 1 : 0, flag2 ? 1 : 0, false);
                return;
            }

            if (modelProto.RendererType == 3)
            {
                factory.ReadObjectConn(preview.objId, 14, out bool _, out int num, out int _);

                if (preview.objId > 0)
                {
                    animPool[preview.bpgpuiModelId] = factory.entityAnimPool[preview.objId];
                }

                animPool[preview.bpgpuiModelId].state = (uint)((color.r << 24) + (color.g << 16) + (color.b << 8) + color.a);
                planet.factoryModel.bpgpuiManager.AddBuildPreviewModel(preview.desc.modelIndex, out preview.bpgpuiModelInstIndex, preview.bpgpuiModelId,
                                                                       preview.lpos, preview.lrot, num != 0 ? 1U : 0U, false);
                return;
            }

            if (preview.objId > 0)
            {
                animPool[preview.bpgpuiModelId] = factory.entityAnimPool[preview.objId];
            }

            animPool[preview.bpgpuiModelId].state = (uint)((color.r << 24) + (color.g << 16) + (color.b << 8) + color.a);
            if (preview.objId > 0 && preview.desc.isEjector)
            {
                animPool[preview.bpgpuiModelId].power = factory.factorySystem.ejectorPool[factory.entityPool[preview.objId].ejectorId].localDir.z;
            }

            planet.factoryModel.bpgpuiManager.AddBuildPreviewModel(preview.desc.modelIndex, out preview.bpgpuiModelInstIndex, preview.bpgpuiModelId,
                                                                   preview.lpos, preview.lrot, false);
        }
Пример #10
0
        public static PastedEntity ConcurrentPasteBelt(int threadIndex, BeltCopy belt, Vector2 targetSpr, float yaw, int pasteIndex)
        {
            var actionBuild = _abs[threadIndex];
            int pasteId     = PASTE_INDEX_MULTIPLIER * pasteIndex + belt.originalId;

            if (!BlueprintManager.pastedEntities.TryGetValue(pasteId, out PastedEntity pastedEntity))
            {
                BuildPreview bp = BuildPreview.CreateSingle(belt.itemProto, belt.itemProto.prefabDesc, false);

                pastedEntity = new PastedEntity()
                {
                    pasteIndex   = pasteIndex,
                    pasteId      = pasteId,
                    status       = EPastedStatus.NEW,
                    type         = EPastedType.BELT,
                    sourceBelt   = belt,
                    buildPreview = bp,
                };

                BlueprintManager.pastedEntities.TryAdd(pasteId, pastedEntity);

                lock (actionBuild.buildPreviews)
                {
                    actionBuild.buildPreviews.Add(bp);
                }
            }
            else
            {
                pastedEntity.status = EPastedStatus.UPDATE;
            }

            Vector2 newRelative = belt.cursorRelativePos.Rotate(yaw * Mathf.Deg2Rad, belt.originalSegmentCount);
            Vector2 sprPos      = newRelative + targetSpr;


            int   newSegmentCount = Util.GetSegmentsCount(sprPos);
            float sizeDeviation   = belt.originalSegmentCount / (float)newSegmentCount;

            sprPos = new Vector2(newRelative.x, newRelative.y * sizeDeviation) + targetSpr;

            Vector3 absoluteBeltPos = sprPos.SnapToGrid(belt.altitude * 1.3333333f / 2);

            // belts have always 0 yaw
            Quaternion absoluteBeltRot = Maths.SphericalRotation(absoluteBeltPos, 0f);


            Pose pose = new Pose(absoluteBeltPos, absoluteBeltRot);

            pastedEntity.objId = InserterPoses.AddOverride(pose, belt.itemProto);
            pastedEntity.pose  = pose;

            pastedEntity.buildPreview.lpos = absoluteBeltPos;
            pastedEntity.buildPreview.lrot = absoluteBeltRot;

            pastedEntity.buildPreview.condition = EBuildCondition.Ok;

            return(pastedEntity);
        }
Пример #11
0
        public static void PasteInserter(PlayerAction_Build actionBuild, int index, InserterCopy inserter, float yaw)
        {
            InserterPosition positionData = InserterPoses.GetPositions(actionBuild, inserter, yaw * Mathf.Deg2Rad);

            BuildPreview bp = BuildPreview.CreateSingle(LDB.items.Select(inserter.itemProto.ID), inserter.itemProto.prefabDesc, true);

            bp.lpos  = positionData.absoluteInserterPos;
            bp.lpos2 = positionData.absoluteInserterPos2;

            bp.lrot  = positionData.absoluteInserterRot;
            bp.lrot2 = positionData.absoluteInserterRot2;

            bp.inputToSlot    = 1;
            bp.outputFromSlot = 0;

            bp.inputOffset   = positionData.pickOffset;
            bp.outputOffset  = positionData.insertOffset;
            bp.outputToSlot  = positionData.endSlot;
            bp.inputFromSlot = positionData.startSlot;
            bp.condition     = positionData.condition;

            bp.filterId = inserter.filterId;

            if (pastedEntities.TryGetValue(positionData.inputOriginalId, out PastedEntity inputEntity))
            {
                bp.input = inputEntity.buildPreview;
            }
            else
            {
                bp.inputObjId = positionData.inputObjId;
            }

            if (pastedEntities.TryGetValue(positionData.outputOriginalId, out PastedEntity outputEntity))
            {
                bp.output = outputEntity.buildPreview;
            }
            else
            {
                bp.outputObjId = positionData.outputObjId;
            }

            lock (parallelPastedEntities)
            {
                parallelPastedEntities.Add(inserter.originalId, new PastedEntity()
                {
                    type         = EPastedType.INSERTER,
                    index        = index,
                    buildPreview = bp,
                });
            }
        }
Пример #12
0
        static IEnumerable <CodeInstruction> RemoveBrokenConnections(IEnumerable <CodeInstruction> instructions)
        {
            CodeMatcher matcher = new CodeMatcher(instructions)
                                  .MatchForward(true,
                                                new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(BuildPreview), nameof(BuildPreview.bpgpuiModelId))),
                                                new CodeMatch(OpCodes.Ldc_I4_0)
                                                ).Advance(1);
            Label label = (Label)matcher.Instruction.operand;

            matcher.Advance(-2)
            .InsertAndAdvance(Transpilers.EmitDelegate <Func <BuildPreview, bool> >(bp =>
            {
                if (!isEnabled && !NebulaModAPI.NebulaIsInstalled)
                {
                    return(true);
                }
                if (bp.desc.multiLevel)
                {
                    BuildPreview current = bp;
                    while (current.input != null)
                    {
                        if (!current.input.IsGood())
                        {
                            return(false);
                        }

                        current = current.input;
                    }
                }

                if (bp.desc.isInserter)
                {
                    if (bp.input != null && !bp.input.IsGood())
                    {
                        return(bp.input.desc.isBelt);
                    }

                    if (bp.output != null && !bp.output.IsGood())
                    {
                        return(bp.output.desc.isBelt);
                    }
                }

                return(true);
            }))
            .InsertAndAdvance(new CodeInstruction(OpCodes.Brfalse, label))
            .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_3));

            return(matcher.InstructionEnumeration());
        }
Пример #13
0
        private void SerializeBuildPreview(BuildPreview buildPreview, List <BuildPreview> list, BinaryWriter bw)
        {
            bw.Write(list.IndexOf(buildPreview.output));
            bw.Write(list.IndexOf(buildPreview.input));
            bw.Write(buildPreview.objId);
            int num = buildPreview.nearestPowerObjId == null ? 0 : buildPreview.nearestPowerObjId.Length;

            bw.Write(num);
            for (int i = 0; i < num; i++)
            {
                bw.Write(buildPreview.nearestPowerObjId[i]);
            }
            bw.Write(buildPreview.coverObjId);
            bw.Write(buildPreview.willCover);
            bw.Write(buildPreview.ignoreCollider);
            bw.Write(buildPreview.outputObjId);
            bw.Write(buildPreview.inputObjId);
            bw.Write(buildPreview.outputToSlot);
            bw.Write(buildPreview.inputFromSlot);
            bw.Write(buildPreview.outputFromSlot);
            bw.Write(buildPreview.inputToSlot);
            bw.Write(buildPreview.outputOffset);
            bw.Write(buildPreview.inputOffset);
            bw.Write(buildPreview.recipeId);
            bw.Write(buildPreview.filterId);
            bw.Write(buildPreview.isConnNode);
            bw.Write(buildPreview.desc.modelIndex);
            bw.Write(buildPreview.item.ID);
            bw.Write(buildPreview.refCount);
            for (int i = 0; i < buildPreview.refCount; i++)
            {
                bw.Write(buildPreview.refArr[i]);
            }
            bw.Write(buildPreview.lpos.x);
            bw.Write(buildPreview.lpos.y);
            bw.Write(buildPreview.lpos.z);
            bw.Write(buildPreview.lpos2.x);
            bw.Write(buildPreview.lpos2.y);
            bw.Write(buildPreview.lpos2.z);
            bw.Write(buildPreview.lrot.x);
            bw.Write(buildPreview.lrot.y);
            bw.Write(buildPreview.lrot.z);
            bw.Write(buildPreview.lrot.w);
            bw.Write(buildPreview.lrot2.x);
            bw.Write(buildPreview.lrot2.y);
            bw.Write(buildPreview.lrot2.z);
            bw.Write(buildPreview.lrot2.w);
        }
Пример #14
0
        public static void CheckAfter(BuildTool_BlueprintPaste __instance, ref bool __result, ref bool __state)
        {
            if (__result)
            {
                return;
            }
            if (!BlueprintCopyExtension.isEnabled || !__state)
            {
                return;
            }
            if (!__instance.cannotBuild || reformPreviews.Count <= 0)
            {
                return;
            }

            if (NebulaModAPI.IsMultiplayerActive && NebulaModAPI.MultiplayerSession.Factories.IsIncomingRequest.Value)
            {
                return;
            }

            BPGratBox box = ReformBPUtils.GetBoundingRange(__instance.planet, __instance.actionBuild.planetAux, new int[0], 0, reformPreviews, reformPreviews[0].longitude);

            bool allOk = true;

            for (int i = 0; i < __instance.bpCursor; i++)
            {
                BuildPreview preview = __instance.bpPool[i];
                if (preview.condition == EBuildCondition.NeedGround)
                {
                    Vector3 pos = (preview.lpos + preview.lpos2) * 0.5f;

                    if (box.InGratBox(pos))
                    {
                        preview.condition = EBuildCondition.Ok;
                    }
                }

                if (preview.condition != EBuildCondition.Ok && preview.condition != EBuildCondition.NotEnoughItem)
                {
                    allOk = false;
                }
            }

            if (allOk)
            {
                __result = true;
            }
        }
Пример #15
0
        public BuildPreview GetBuildPreview(int objId)
        {
            int num;

            if (bpRecycleCursor > 0)
            {
                int[] array = bpRecycle;
                num             = bpRecycleCursor - 1;
                bpRecycleCursor = num;
                int          num2         = array[num];
                BuildPreview buildPreview = bpPool[num2];
                if (buildPreview == null)
                {
                    buildPreview = new BuildPreview();
                    bpPool[num2] = buildPreview;
                }

                GeneratePreviewByObjId(buildPreview, objId);
                animPool[num2]             = default;
                buildPreview.previewIndex  = num2;
                buildPreview.bpgpuiModelId = num2;
                return(buildPreview);
            }

            num      = bpCursor;
            bpCursor = num + 1;
            int num3 = num;

            if (num3 == bpPoolCapacity)
            {
                SetDisplayPreviewCapacity(bpPoolCapacity * 2);
            }

            BuildPreview buildPreview2 = bpPool[num3];

            if (buildPreview2 == null)
            {
                buildPreview2 = new BuildPreview();
                bpPool[num3]  = buildPreview2;
            }

            GeneratePreviewByObjId(buildPreview2, objId);
            animPool[num3]              = default(AnimData);
            buildPreview2.previewIndex  = num3;
            buildPreview2.bpgpuiModelId = num3;
            return(buildPreview2);
        }
        public static void CheckBuildConditions_Postfix(PlayerAction_Build __instance, ref bool __result)
        {
            var ci = cachedInserters;

            if (CopyInserters.copyEnabled && ci.Count > 0)
            {
                __instance.cursorText        = __instance.prepareCursorText;
                __instance.prepareCursorText = string.Empty;
                __instance.cursorWarning     = false;
                UICursor.SetCursor(ECursor.Default);
                var flag = true;
                for (int i = 0; i < __instance.buildPreviews.Count; i++)
                {
                    BuildPreview buildPreview = __instance.buildPreviews[i];
                    bool         isInserter   = buildPreview.desc.isInserter;
                    bool         isConnected  = buildPreview.inputObjId != 0 || buildPreview.outputObjId != 0;
                    if (isInserter && (
                            buildPreview.condition == EBuildCondition.TooFar ||
                            buildPreview.condition == EBuildCondition.TooClose ||
                            buildPreview.condition == EBuildCondition.OutOfReach ||
                            // the following fix an incompatibility with AdvanceBuildDestruct where inserter are tagged ascolliding even if they are not
                            (buildPreview.condition == EBuildCondition.Collide && isConnected)
                            ))
                    {
                        buildPreview.condition = EBuildCondition.Ok;
                    }

                    if (buildPreview.condition != EBuildCondition.Ok)
                    {
                        flag = false;
                        if (!__instance.cursorWarning)
                        {
                            __instance.cursorWarning = true;
                            __instance.cursorText    = buildPreview.conditionText;
                        }
                    }
                }

                if (!flag && !VFInput.onGUI)
                {
                    UICursor.SetCursor(ECursor.Ban);
                }

                __result = flag;
            }
        }
Пример #17
0
        public static void PasteBelt(int index, BeltCopy belt, Vector2 targetSpr, float yaw)
        {
            Vector2 newRelative = belt.cursorRelativePos.Rotate(yaw * Mathf.Deg2Rad, belt.originalSegmentCount);
            Vector2 sprPos      = newRelative + targetSpr;

            float rawLatitudeIndex = (sprPos.x - Mathf.PI / 2) / 6.2831855f * 200;
            int   latitudeIndex    = Mathf.FloorToInt(Mathf.Max(0f, Mathf.Abs(rawLatitudeIndex) - 0.1f));
            int   newSegmentCount  = PlanetGrid.DetermineLongitudeSegmentCount(latitudeIndex, 200);

            float sizeDeviation = belt.originalSegmentCount / (float)newSegmentCount;

            sprPos = new Vector2(newRelative.x, newRelative.y * sizeDeviation) + targetSpr;

            Vector3 absoluteBeltPos = sprPos.SnapToGrid(belt.altitude * 1.3333333f / 2);

            // belts have always 0 yaw
            Quaternion absoluteBeltRot = Maths.SphericalRotation(absoluteBeltPos, 0f);

            BuildPreview bp = BuildPreview.CreateSingle(belt.itemProto, belt.itemProto.prefabDesc, false);

            bp.lpos           = absoluteBeltPos;
            bp.lrot           = absoluteBeltRot;
            bp.outputToSlot   = -1;
            bp.outputFromSlot = 0;

            bp.inputFromSlot = -1;
            bp.inputToSlot   = 1;

            bp.outputOffset = 0;
            bp.inputOffset  = 0;

            Pose pose = new Pose(absoluteBeltPos, absoluteBeltRot);

            int objId = InserterPoses.AddOverride(pose, belt.itemProto);

            pastedEntities.Add(belt.originalId, new PastedEntity()
            {
                type         = EPastedType.BELT,
                index        = index,
                pose         = pose,
                objId        = objId,
                buildPreview = bp,
            });

            previews.Add(bp);
        }
Пример #18
0
        private void DeserializeBuildPreview(BuildPreview buildPreview, List <BuildPreview> list, BinaryReader br)
        {
            int outputRef = br.ReadInt32();

            buildPreview.output = outputRef == -1 ? null : list[outputRef];
            int inputRef = br.ReadInt32();

            buildPreview.input = inputRef == -1 ? null : list[inputRef];
            buildPreview.objId = br.ReadInt32();
            int num = br.ReadInt32();

            buildPreview.nearestPowerObjId = num == 0 ? null : new int[num];
            for (int i = 0; i < num; i++)
            {
                buildPreview.nearestPowerObjId[i] = br.ReadInt32();
            }
            buildPreview.coverObjId      = br.ReadInt32();
            buildPreview.willCover       = br.ReadBoolean();
            buildPreview.ignoreCollider  = br.ReadBoolean();
            buildPreview.outputObjId     = br.ReadInt32();
            buildPreview.inputObjId      = br.ReadInt32();
            buildPreview.outputToSlot    = br.ReadInt32();
            buildPreview.inputFromSlot   = br.ReadInt32();
            buildPreview.outputFromSlot  = br.ReadInt32();
            buildPreview.inputToSlot     = br.ReadInt32();
            buildPreview.outputOffset    = br.ReadInt32();
            buildPreview.inputOffset     = br.ReadInt32();
            buildPreview.recipeId        = br.ReadInt32();
            buildPreview.filterId        = br.ReadInt32();
            buildPreview.isConnNode      = br.ReadBoolean();
            buildPreview.desc            = new PrefabDesc();
            buildPreview.desc.modelIndex = br.ReadInt32();
            buildPreview.item            = new ItemProto();
            buildPreview.item.ID         = br.ReadInt32();
            buildPreview.refCount        = br.ReadInt32();
            buildPreview.refArr          = new int[buildPreview.refCount];
            for (int i = 0; i < buildPreview.refCount; i++)
            {
                buildPreview.refArr[i] = br.ReadInt32();
            }
            buildPreview.lpos  = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
            buildPreview.lpos2 = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
            buildPreview.lrot  = new Quaternion(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
            buildPreview.lrot2 = new Quaternion(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
        }
Пример #19
0
 void ToggleBuildMode()
 {
     if (buildPreview == null)
     {
         Structure structure = Instantiate(structurePrefab, Vector3.zero, Quaternion.identity);
         structure.structureType = structureTypes[Mathf.FloorToInt(Random.value * structureTypes.Length)];
         structure.enabled       = false; // TODO Future things to turn off / Destroy later?
         Destroy(structure.GetComponent <Rigidbody>());
         structure.GetComponent <Collider>().isTrigger = true;
         structure.name = "Build Preview";
         buildPreview   = structure.gameObject.AddComponent <BuildPreview>();
     }
     else
     {
         Destroy(buildPreview.gameObject);
         buildPreview = null;
     }
 }
Пример #20
0
            public static void PlayerAction_BuildCheckBuildConditionsPostfix(PlayerAction_Build __instance, ref bool __result)
            {
                var ci = PatchCopyInserters.cachedInserters;

                if (CopyInserters.copyEnabled && ci.Count > 0)
                {
                    __instance.cursorText        = __instance.prepareCursorText;
                    __instance.prepareCursorText = string.Empty;
                    __instance.cursorWarning     = false;
                    UICursor.SetCursor(ECursor.Default);
                    var flag = true;
                    for (int i = 0; i < __instance.buildPreviews.Count; i++)
                    {
                        BuildPreview buildPreview = __instance.buildPreviews[i];
                        bool         isInserter   = buildPreview.desc.isInserter;

                        if (isInserter && buildPreview.ignoreCollider && (
                                buildPreview.condition == EBuildCondition.TooFar ||
                                buildPreview.condition == EBuildCondition.TooClose ||
                                buildPreview.condition == EBuildCondition.OutOfReach))
                        {
                            buildPreview.condition = EBuildCondition.Ok;
                        }

                        if (buildPreview.condition != EBuildCondition.Ok)
                        {
                            flag = false;
                            if (!__instance.cursorWarning)
                            {
                                __instance.cursorWarning = true;
                                __instance.cursorText    = buildPreview.conditionText;
                            }
                        }
                    }

                    if (!flag && !VFInput.onGUI)
                    {
                        UICursor.SetCursor(ECursor.Ban);
                    }

                    __result = flag;
                }
            }
Пример #21
0
        public static void PasteBuilding(int index, BuildingCopy building, Vector2 targetSpr, float yaw)
        {
            Vector2 newRelative = building.cursorRelativePos.Rotate(yaw * Mathf.Deg2Rad, building.originalSegmentCount);
            Vector2 sprPos      = newRelative + targetSpr;

            float rawLatitudeIndex = (sprPos.x - Mathf.PI / 2) / 6.2831855f * 200;
            int   latitudeIndex    = Mathf.FloorToInt(Mathf.Max(0f, Mathf.Abs(rawLatitudeIndex) - 0.1f));
            int   newSegmentCount  = PlanetGrid.DetermineLongitudeSegmentCount(latitudeIndex, 200);

            float sizeDeviation = building.originalSegmentCount / (float)newSegmentCount;

            sprPos = new Vector2(newRelative.x, newRelative.y * sizeDeviation) + targetSpr;

            Vector3 absoluteBuildingPos = sprPos.SnapToGrid();

            Quaternion   absoluteBuildingRot = Maths.SphericalRotation(absoluteBuildingPos, yaw + building.cursorRelativeYaw);
            PrefabDesc   desc = GetPrefabDesc(building);
            BuildPreview bp   = BuildPreview.CreateSingle(building.itemProto, desc, true);

            bp.ResetInfos();
            bp.desc     = desc;
            bp.item     = building.itemProto;
            bp.recipeId = building.recipeId;
            bp.lpos     = absoluteBuildingPos;
            bp.lrot     = absoluteBuildingRot;

            Pose pose = new Pose(absoluteBuildingPos, absoluteBuildingRot);

            int objId = InserterPoses.AddOverride(pose, building.itemProto);

            pastedEntities.Add(building.originalId, new PastedEntity()
            {
                type           = EPastedType.BUILDING,
                index          = index,
                sourceBuilding = building,
                pose           = pose,
                objId          = objId,
                buildPreview   = bp
            });

            ActivateColliders(absoluteBuildingPos);
            previews.Add(bp);
        }
Пример #22
0
        protected bool SaveBuildData(PlanetFactory factory, PlayerAction_Build actionBuild)
        {
            bool anySuccess = false;

            previews = new List <BuildPreview>(objectIds.Count);
            tmpPreviews.Clear();

            foreach (int objectId in objectIds)
            {
                if (objectId > 0)
                {
                    ref EntityData data = ref factory.entityPool[objectId];
                    if (data.id == objectId)
                    {
                        BuildPreview preview = InitPreviewFromObject(factory, actionBuild, data.id);
                        previews.Add(preview);
                        anySuccess = true;
                    }
                }
Пример #23
0
        public void DeterminePreviews()
        {
            HashSet <int> missing = new HashSet <int>(selectObjIds);

            for (int i = 1; i < bpCursor; i++)
            {
                BuildPreview buildPreview = bpPool[i];
                if (buildPreview != null && buildPreview.bpgpuiModelId > 0)
                {
                    if (!selectObjIds.Contains(buildPreview.objId))
                    {
                        if (buildPreview.bpgpuiModelInstIndex >= 0)
                        {
                            planet.factoryModel.bpgpuiManager.RemoveBuildPreviewModel(buildPreview.desc.modelIndex, buildPreview.bpgpuiModelInstIndex, false);
                        }
                        RemoveBuildPreview(i);
                    }
                    else
                    {
                        missing.Remove(buildPreview.objId);
                    }
                }
            }

            foreach (int objId in missing)
            {
                BuildPreview buildPreview = GetBuildPreview(objId);
                AddBPGPUIModel(buildPreview);
            }

            if (castObjectId != 0)
            {
                BuildPreview buildPreview3 = GetBuildPreview(castObjectId);

                AddBPGPUIModel(buildPreview3);
            }

            SyncAnimBuffer();
            planet.factoryModel.bpgpuiManager.animBuffer = animBuffer;
            planet.factoryModel.bpgpuiManager.SyncAllGPUBuffer();
        }
Пример #24
0
        public void ReDeterminePreviews()
        {
            ResetBuildPreviews();
            foreach (int objId in selectObjIds)
            {
                BuildPreview buildPreview = GetBuildPreview(objId);

                AddBPGPUIModel(buildPreview);
            }

            if (castObjectId != 0)
            {
                BuildPreview buildPreview3 = GetBuildPreview(castObjectId);

                AddBPGPUIModel(buildPreview3);
            }

            SyncAnimBuffer();
            planet.factoryModel.bpgpuiManager.animBuffer = animBuffer;
            planet.factoryModel.bpgpuiManager.SyncAllGPUBuffer();
        }
Пример #25
0
 public void SetIndex(int index)
 {
     Debug.Log("Setting build index to: " + index);
     if (index == buildIndex || index > industries.Length - 1 || index < 0)
     {
         buildIndex = -1;
         Destroy(activeGameObject);
         activeGameObject = null;
         _buildPreview    = null;
     }
     else
     {
         if (activeGameObject != null)
         {
             Destroy(activeGameObject);
         }
         buildIndex       = index;
         activeGameObject = Instantiate(industries[buildIndex]);
         _buildPreview    = activeGameObject.GetComponent <BuildPreview>();
     }
 }
        public static void CreatePrebuilds_Prefix(PlayerAction_Build __instance)
        {
            var ci = cachedInserters;

            if (CopyInserters.copyEnabled && ci.Count > 0)
            {
                if (__instance.waitConfirm && VFInput._buildConfirm.onDown && __instance.buildPreviews.Count > 0)
                {
                    // for now we remove the inserters prebuilds. we recreate them after the 'real' buildpreviews have been transformed into prebuilds
                    for (int i = __instance.buildPreviews.Count - 1; i >= 0; i--) // Reverse loop for removing found elements
                    {
                        BuildPreview buildPreview = __instance.buildPreviews[i];
                        bool         isInserter   = buildPreview.desc.isInserter;

                        if (isInserter)
                        {
                            __instance.buildPreviews.RemoveAt(i);
                            __instance.FreePreviewModel(buildPreview);
                        }
                    }
                }
            }
        }
        public static void DetermineBuildPreviews_Postfix(PlayerAction_Build __instance, PlanetFactory ___factory, PlanetAuxData ___planetAux, NearColliderLogic ___nearcdLogic, Player ___player)
        {
            // Do we have cached inserters?
            var ci = cachedInserters;

            if (CopyInserters.copyEnabled && ci.Count > 0 && !__instance.multiLevelCovering)
            {
                var bpCount = __instance.buildPreviews.Count;

                for (int i = 0; i < bpCount; i++)
                {
                    BuildPreview buildPreview = __instance.buildPreviews[i];

                    if (!buildPreview.item.prefabDesc.isInserter)
                    {
                        foreach (var cachedInserter in ci)
                        {
                            var positionData = GetPositions(__instance, ___factory, ___planetAux, ___nearcdLogic, buildPreview, cachedInserter);

                            var bp = BuildPreview.CreateSingle(LDB.items.Select(cachedInserter.protoId), LDB.items.Select(cachedInserter.protoId).prefabDesc, true);
                            bp.ResetInfos();


                            bp.lrot  = buildPreview.lrot * cachedInserter.rot;
                            bp.lrot2 = buildPreview.lrot * cachedInserter.rot2;


                            if (buildPreview.lpos == Vector3.zero)
                            {
                                bp.lpos  = buildPreview.lpos + buildPreview.lrot * positionData.posDelta;
                                bp.lpos2 = buildPreview.lpos + buildPreview.lrot * positionData.pos2Delta;
                            }
                            else
                            {
                                bp.lpos  = positionData.absoluteInserterPos;
                                bp.lpos2 = positionData.absoluteInserterPos2;
                            }



                            if (positionData.condition == null)
                            {
                                positionData.condition = EBuildCondition.Ok;

                                Vector3 lpos    = positionData.absoluteInserterPos;
                                Vector3 lpos2   = positionData.absoluteInserterPos2;
                                Vector3 forward = lpos2 - lpos;

                                Pose pose;
                                pose.position = Vector3.Lerp(lpos, lpos2, 0.5f);
                                pose.rotation = Quaternion.LookRotation(forward, lpos.normalized);


                                var colliderData = bp.desc.buildColliders[0];
                                colliderData.ext = new Vector3(colliderData.ext.x, colliderData.ext.y, Vector3.Distance(lpos2, lpos) * 0.5f + colliderData.ext.z - 0.5f);

                                if (cachedInserter.otherIsBelt)
                                {
                                    if (cachedInserter.incoming)
                                    {
                                        colliderData.pos.z -= 0.4f;
                                        colliderData.ext.z += 0.4f;
                                    }
                                    else
                                    {
                                        colliderData.pos.z += 0.4f;
                                        colliderData.ext.z += 0.4f;
                                    }
                                }

                                if (colliderData.ext.z < 0.1f)
                                {
                                    colliderData.ext.z = 0.1f;
                                }
                                colliderData.pos = pose.position + pose.rotation * colliderData.pos;
                                colliderData.q   = pose.rotation * colliderData.q;


                                //int mask = 165888;// the following is equivalent but explicitly states layers affected
                                int mask            = Convert.ToInt32(LayerMaskConstants.layer12 | LayerMaskConstants.layer16 | LayerMaskConstants.layer18);
                                int collisionsFound = Physics.OverlapBoxNonAlloc(colliderData.pos, colliderData.ext, _tmp_cols, colliderData.q, mask, QueryTriggerInteraction.Collide);

                                int collisionLimit = cachedInserter.otherIsBelt ? 0 : 1;

                                if (collisionsFound > collisionLimit)
                                {
                                    PlanetPhysics physics2 = ___player.planetData.physics;
                                    for (int j = 0; j < collisionsFound; j++)
                                    {
                                        physics2.GetColliderData(_tmp_cols[j], out ColliderData colliderData2);
                                        if (colliderData2.objId != 0)
                                        {
                                            if (colliderData2.usage == EColliderUsage.Build)
                                            {
                                                positionData.condition = EBuildCondition.Collide;
                                            }
                                        }
                                    }
                                }
                            }

                            bp.condition = (EBuildCondition)positionData.condition;

                            if (bp.condition == EBuildCondition.Ok)
                            {
                                if (cachedInserter.incoming)
                                {
                                    bp.inputObjId = positionData.otherId;
                                }
                                else
                                {
                                    bp.outputObjId = positionData.otherId;
                                }
                            }

                            __instance.AddBuildPreview(bp);
                        }
                    }
                }

                SwapPositionCache();
            }
        }
Пример #28
0
        public static List <BuildPreview> Paste(Vector3 targetPos, float yaw, bool pasteInserters = true)
        {
            PlayerAction_Build actionBuild = GameMain.data.mainPlayer.controller.actionBuild;

            pastedEntities.Clear();
            parallelPastedEntities.Clear();
            previews.Clear();
            InserterPoses.ResetOverrides();

            Vector2 targetSpr = targetPos.ToSpherical();
            float   yawRad    = yaw * Mathf.Deg2Rad;


            for (int i = 0; i < data.copiedBuildings.Count; i++)
            {
                PasteBuilding(i, data.copiedBuildings[i], targetSpr, yaw);
            }

            for (int i = 0; i < data.copiedBelts.Count; i++)
            {
                PasteBelt(i, data.copiedBelts[i], targetSpr, yaw);
            }

            if (pasteInserters && data.copiedInserters.Count > 16)
            {
                var maxThreads        = Environment.ProcessorCount - 1;
                var runningThreads    = 0;
                var next              = -1;
                ManualResetEvent done = new ManualResetEvent(false);

                for (int i = 0; i < maxThreads; i++)
                {
                    ThreadPool.QueueUserWorkItem(_ =>
                    {
                        int item;
                        Interlocked.Increment(ref runningThreads);

                        try
                        {
                            PlayerAction_Build ab = BuildLogic.ClonePlayerAction_Build(actionBuild);
                            while ((item = Interlocked.Increment(ref next)) < data.copiedInserters.Count)
                            {
                                PasteInserter(ab, item, data.copiedInserters[item], yaw);
                            }
                        }
                        catch (Exception e)
                        {
                            Console.WriteLine(e.ToString());
                        }
                        finally
                        {
                            if (Interlocked.Decrement(ref runningThreads) == 0)
                            {
                                done.Set();
                            }
                        }
                    });
                }

                done.WaitOne();
            }
            else if (pasteInserters)
            {
                for (var i = 0; i < data.copiedInserters.Count; i++)
                {
                    PasteInserter(actionBuild, i, data.copiedInserters[i], yaw);
                }
            }
            // merge the inserter pastedEntities in the main dictionaries
            foreach (var item in parallelPastedEntities)
            {
                previews.Add(item.Value.buildPreview);
                pastedEntities.Add(item.Key, item.Value);
            }

            // after creating the belt previews this restore the correct connection to other belts and buildings
            foreach (BeltCopy belt in data.copiedBelts)
            {
                BuildPreview preview = pastedEntities[belt.originalId].buildPreview;

                if (belt.outputId != 0 &&
                    pastedEntities.TryGetValue(belt.outputId, out PastedEntity otherEntity) &&
                    Vector3.Distance(preview.lpos, otherEntity.buildPreview.lpos) < 10) // if the belts are too far apart ignore connection
                {
                    preview.output = otherEntity.buildPreview;
                    var otherBelt = data.copiedBelts[otherEntity.index];

                    if (otherBelt.backInputId == belt.originalId)
                    {
                        preview.outputToSlot = 1;
                    }
                    if (otherBelt.leftInputId == belt.originalId)
                    {
                        preview.outputToSlot = 2;
                    }
                    if (otherBelt.rightInputId == belt.originalId)
                    {
                        preview.outputToSlot = 3;
                    }
                }

                if (belt.connectedBuildingId != 0 && pastedEntities.TryGetValue(belt.connectedBuildingId, out PastedEntity otherBuilding))
                {
                    if (belt.connectedBuildingIsOutput)
                    {
                        preview.output       = otherBuilding.buildPreview;
                        preview.outputToSlot = belt.connectedBuildingSlot;
                    }
                    else
                    {
                        preview.input         = otherBuilding.buildPreview;
                        preview.inputFromSlot = belt.connectedBuildingSlot;
                    }
                }

                bool beltHasInput  = pastedEntities.ContainsKey(belt.backInputId) || pastedEntities.ContainsKey(belt.leftInputId) || pastedEntities.ContainsKey(belt.rightInputId);
                bool beltHasOutput = pastedEntities.ContainsKey(belt.outputId);

                if (!beltHasInput || !beltHasOutput)
                {
                    int found = actionBuild.nearcdLogic.GetBuildingsInAreaNonAlloc(preview.lpos, 0.34f, _nearObjectIds, false);
                    for (int x = 0; x < found; x++)
                    {
                        int overlappingEntityId = _nearObjectIds[x];

                        if (overlappingEntityId <= 0)
                        {
                            continue;
                        }

                        EntityData overlappingEntityData = actionBuild.factory.entityPool[overlappingEntityId];

                        if (overlappingEntityData.beltId <= 0)
                        {
                            continue;
                        }

                        BeltComponent overlappingBelt = actionBuild.factory.cargoTraffic.beltPool[overlappingEntityData.beltId];

                        bool overlappingBeltHasInput  = (overlappingBelt.backInputId + overlappingBelt.leftInputId + overlappingBelt.rightInputId) != 0;
                        bool overlappingBeltHasOutput = overlappingBelt.outputId != 0;

                        if ((beltHasOutput && !overlappingBeltHasOutput) || (beltHasInput && !overlappingBeltHasInput))
                        {
                            // found overlapping belt that can be 'replaced' to connect to existing belts
                            preview.coverObjId     = overlappingEntityId;
                            preview.ignoreCollider = true;
                            preview.willCover      = true;
                        }
                    }
                }
            }


            return(previews);
        }
Пример #29
0
        public static void DetermineBuildPreviews_Postfix(ref PlayerAction_Build __instance)
        {
            if (IsMultiBuildRunning())
            {
                __instance.ClearBuildPreviews();

                if (__instance.previewPose.position == Vector3.zero)
                {
                    return;
                }

                __instance.previewPose.position = Vector3.zero;
                __instance.previewPose.rotation = Quaternion.identity;

                int       snapPath = path;
                Vector3[] snaps    = new Vector3[1024];

                var snappedPointCount = __instance.planetAux.SnapLineNonAlloc(startPos, __instance.groundSnappedPos, ref snapPath, snaps);

                var        desc        = __instance.handPrefabDesc;
                Collider[] colliders   = new Collider[desc.buildColliders.Length];
                Vector3    previousPos = Vector3.zero;

                var usedSnaps = new List <Vector3>(10);

                var maxSnaps = Math.Max(1, snappedPointCount - spacing);

                for (int s = 0; s < maxSnaps; s++)
                {
                    var pos = snaps[s];
                    var rot = Maths.SphericalRotation(snaps[s], __instance.yaw);

                    if (s > 0)
                    {
                        var sqrDistance = (previousPos - pos).sqrMagnitude;

                        // power towers
                        if (desc.isPowerNode && sqrDistance < 12.25f)
                        {
                            continue;
                        }

                        // wind turbines
                        if (desc.windForcedPower && sqrDistance < 110.25f)
                        {
                            continue;
                        }

                        // ray receivers
                        if (desc.gammaRayReceiver && sqrDistance < 110.25f)
                        {
                            continue;
                        }

                        // logistic stations
                        if (desc.isStation && sqrDistance < (desc.isStellarStation ? 841f : 225f))
                        {
                            continue;
                        }

                        // ejector
                        if (desc.isEjector && sqrDistance < 110.25f)
                        {
                            continue;
                        }

                        if (desc.hasBuildCollider)
                        {
                            var foundCollision = false;
                            for (var j = 0; j < desc.buildColliders.Length && !foundCollision; j++)
                            {
                                var colliderData = desc.buildColliders[j];
                                colliderData.pos = pos + rot * colliderData.pos;
                                colliderData.q   = rot * colliderData.q;
                                // check only collision with layer 27 (the layer used by the our own building colliders for the previously 'placed' building)
                                foundCollision = Physics.CheckBox(colliderData.pos, colliderData.ext, colliderData.q, 134217728, QueryTriggerInteraction.Collide);
                            }

                            if (foundCollision)
                            {
                                continue;
                            }
                        }
                    }

                    if (s > 0 && spacing > 0)
                    {
                        s  += spacing;
                        pos = snaps[s];
                        rot = Maths.SphericalRotation(snaps[s], __instance.yaw);
                    }

                    previousPos = pos;
                    usedSnaps.Add(pos);

                    var bp = BuildPreview.CreateSingle(__instance.handItem, __instance.handPrefabDesc, true);
                    bp.ResetInfos();
                    bp.desc     = desc;
                    bp.lpos     = pos;
                    bp.lrot     = rot;
                    bp.item     = __instance.handItem;
                    bp.recipeId = __instance.copyRecipeId;
                    bp.filterId = __instance.copyFilterId;

                    if (desc.hasBuildCollider)
                    {
                        for (var j = 0; j < desc.buildColliders.Length; j++)
                        {
                            // create temporary collider entities for the latest 'positioned' building
                            if (colliders[j] != null)
                            {
                                ColliderPool.PutCollider(colliders[j]);
                            }

                            var colliderData = desc.buildColliders[j];
                            colliderData.pos = pos + rot * colliderData.pos;
                            colliderData.q   = rot * colliderData.q;
                            colliders[j]     = ColliderPool.TakeCollider(colliderData);
                            colliders[j].gameObject.layer = 27;
                        }
                    }

                    __instance.AddBuildPreview(bp);
                }

                foreach (var collider in colliders)
                {
                    if (collider != null)
                    {
                        ColliderPool.PutCollider(collider);
                    }
                }


                ActivateColliders(ref __instance.nearcdLogic, usedSnaps);
            }
        }
        private static InserterPosition GetPositions(PlayerAction_Build __instance, PlanetFactory ___factory, PlanetAuxData ___planetAux, NearColliderLogic ___nearcdLogic, BuildPreview buildPreview, CachedInserter cachedInserter)
        {
            Vector3    absoluteBuildingPos;
            Quaternion absoluteBuildingRot;

            // When using AdvancedBuildDestruct mod, all buildPreviews are positioned 'absolutely' on the planet surface.
            // In 'normal' mode the buildPreviews are relative to __instance.previewPose.
            // This means that in 'normal' mode the (only) buildPreview is always positioned at {0,0,0}

            if (buildPreview.lpos == Vector3.zero)
            {
                absoluteBuildingPos = __instance.previewPose.position;
                absoluteBuildingRot = __instance.previewPose.rotation;
            }
            else
            {
                absoluteBuildingPos = buildPreview.lpos;
                absoluteBuildingRot = buildPreview.lrot;
            }

            InserterPosition position = null;

            if (currentPositionCache.Count > 0)
            {
                position = currentPositionCache.Dequeue();
            }

            bool isCacheValid = position != null &&
                                position.cachedInserter == cachedInserter &&
                                position.absoluteBuildingPos == absoluteBuildingPos &&
                                position.absoluteBuildingRot == absoluteBuildingRot;

            if (isCacheValid)
            {
                nextPositionCache.Enqueue(position);
                return(position);
            }


            var posDelta  = cachedInserter.posDelta;
            var pos2Delta = cachedInserter.pos2Delta;

            Vector3 absoluteInserterPos  = absoluteBuildingPos + absoluteBuildingRot * cachedInserter.posDelta;
            Vector3 absoluteInserterPos2 = absoluteBuildingPos + absoluteBuildingRot * cachedInserter.pos2Delta;

            Quaternion absoluteInserterRot  = absoluteBuildingRot * cachedInserter.rot;
            Quaternion absoluteInserterRot2 = absoluteBuildingRot * cachedInserter.rot2;

            int startSlot = cachedInserter.startSlot;
            int endSlot   = cachedInserter.endSlot;

            short pickOffset   = cachedInserter.pickOffset;
            short insertOffset = cachedInserter.insertOffset;

            // Find the desired belt/building position
            // As delta doesn't work over distance, re-trace the Grid Snapped steps from the original
            // to find the target belt/building for this inserters other connection
            var testPos = absoluteBuildingPos;

            // Note: rotates each move relative to the rotation of the new building
            for (int u = 0; u < cachedInserter.snapCount; u++)
            {
                testPos = ___planetAux.Snap(testPos + absoluteBuildingRot * cachedInserter.snapMoves[u], true, false);
            }

            // Find the other entity at the target location
            int otherId = 0;

            // find building nearby
            int found = ___nearcdLogic.GetBuildingsInAreaNonAlloc(testPos, 0.2f, _nearObjectIds);

            // find nearest building
            float maxDistance = 0.2f;

            for (int x = 0; x < found; x++)
            {
                var       id = _nearObjectIds[x];
                float     distance;
                ItemProto proto;
                if (id == 0 || id == buildPreview.objId)
                {
                    continue;
                }
                else if (id > 0)
                {
                    EntityData entityData = ___factory.entityPool[id];
                    proto    = LDB.items.Select((int)entityData.protoId);
                    distance = Vector3.Distance(entityData.pos, testPos);
                }
                else
                {
                    PrebuildData prebuildData = ___factory.prebuildPool[-id];
                    proto = LDB.items.Select((int)prebuildData.protoId);
                    if (proto.prefabDesc.isBelt)
                    {
                        // ignore unbuilt belts
                        continue;
                    }
                    distance = Vector3.Distance(prebuildData.pos, testPos);
                }

                // ignore entitites that ore not (built) belts or don't have inserterPoses
                if ((proto.prefabDesc.isBelt == cachedInserter.otherIsBelt || proto.prefabDesc.insertPoses.Length > 0) && distance < maxDistance)
                {
                    otherId     = id;
                    maxDistance = distance;
                }
            }

            if (otherId != 0)
            {
                var buildingId = buildPreview.objId;

                if (buildingId == 0)
                {
                    // the original calculatePose code doesn't correctly handle calculation where one of the entity is a BuildPreview
                    // as it has objId 0 and is not registered in either the entityPool or prebuildPool
                    // To address that we override the 4 critical methods GetObjectPose/GetObjectProtoId/ObjectIsBelt/GetLocalInserts
                    // only for this specific execution of CalculatePose, by returning the expected value for the current buildPreview
                    overridePoseMethods = true;
                    overriddenProto     = buildPreview.item;
                    overriddenPose      = new Pose(absoluteBuildingPos, absoluteBuildingRot);
                }

                if (cachedInserter.incoming)
                {
                    CalculatePose(__instance, otherId, buildingId);
                }
                else
                {
                    CalculatePose(__instance, buildingId, otherId);
                }


                overridePoseMethods = false;

                bool hasNearbyPose = false;
                if (__instance.posePairs.Count > 0)
                {
                    float minDistance = 1000f;
                    PlayerAction_Build.PosePair bestFit = new PlayerAction_Build.PosePair();

                    for (int j = 0; j < __instance.posePairs.Count; ++j)
                    {
                        var posePair = __instance.posePairs[j];
                        if (
                            (cachedInserter.incoming && cachedInserter.endSlot != posePair.endSlot) ||
                            (!cachedInserter.incoming && cachedInserter.startSlot != posePair.startSlot)
                            )
                        {
                            continue;
                        }
                        float startDistance = Vector3.Distance(posePair.startPose.position, absoluteInserterPos);
                        float endDistance   = Vector3.Distance(posePair.endPose.position, absoluteInserterPos2);
                        float poseDistance  = startDistance + endDistance;

                        if (poseDistance < minDistance)
                        {
                            minDistance   = poseDistance;
                            bestFit       = posePair;
                            hasNearbyPose = true;
                        }
                    }
                    if (hasNearbyPose)
                    {
                        // if we were able to calculate a close enough sensible pose
                        // use that instead of the (visually) imprecise default

                        absoluteInserterPos  = bestFit.startPose.position;
                        absoluteInserterPos2 = bestFit.endPose.position;

                        absoluteInserterRot  = bestFit.startPose.rotation;
                        absoluteInserterRot2 = bestFit.endPose.rotation * Quaternion.Euler(0.0f, 180f, 0.0f);

                        pickOffset   = (short)bestFit.startOffset;
                        insertOffset = (short)bestFit.endOffset;

                        startSlot = bestFit.startSlot;
                        endSlot   = bestFit.endSlot;


                        posDelta  = Quaternion.Inverse(absoluteBuildingRot) * (absoluteInserterPos - absoluteBuildingPos);
                        pos2Delta = Quaternion.Inverse(absoluteBuildingRot) * (absoluteInserterPos2 - absoluteBuildingPos);
                    }
                }
            }

            position = new InserterPosition()
            {
                cachedInserter      = cachedInserter,
                absoluteBuildingPos = absoluteBuildingPos,
                absoluteBuildingRot = absoluteBuildingRot,

                otherId = otherId,

                posDelta             = posDelta,
                pos2Delta            = pos2Delta,
                absoluteInserterPos  = absoluteInserterPos,
                absoluteInserterPos2 = absoluteInserterPos2,

                absoluteInserterRot  = absoluteInserterRot,
                absoluteInserterRot2 = absoluteInserterRot2,

                pickOffset   = pickOffset,
                insertOffset = insertOffset,

                startSlot = startSlot,
                endSlot   = endSlot,
            };


            nextPositionCache.Enqueue(position);
            return(position);
        }