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);
        }
示例#2
0
            public static bool DetermineDestructPreviewsPatch(PlayerAction_Build __instance,
                                                              ref NearColliderLogic ___nearcdLogic,
                                                              ref PlanetFactory ___factory)
            {
                if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.LeftControl))
                {
                    if (!VFInput.onGUI)
                    {
                        UICursor.SetCursor(ECursor.Delete);
                    }
                }
                else
                {
                    return(true);
                }

                if (!Utils.CheckIfInBuildDistance(__instance.cursorTarget))
                {
                    // Out of reach
                    UnityEngine.Debug.Log("out of reach");
                    return(true);
                }

                List <EntityData> deleteEntitiesList = new List <EntityData>();
                ItemProto         itemProto          = Traverse.Create(__instance).Method(
                    "GetItemProto", __instance.castObjId).GetValue <ItemProto>();

                __instance.ClearBuildPreviews();

                if (VFInput.reformMinusKey.onDown)
                {
                    if (__instance.reformSize >= 0)
                    {
                        __instance.reformSize--;
                    }
                }

                if (VFInput.reformPlusKey.onDown)
                {
                    if (__instance.reformSize < _configDisassemblingRadiusMax.Value)
                    {
                        __instance.reformSize++;
                    }
                }

                // Management of the sphere delete
                if (Input.GetKey(KeyCode.LeftControl))
                {
                    int[] buildingIdsToDelete = new int[_maxArrayOfBuildingSize.Value];
                    if (itemProto != null)
                    {
                        ___nearcdLogic.GetBuildingsInAreaNonAlloc(__instance.castObjPos, __instance.reformSize, buildingIdsToDelete);
                    }
                    else
                    {
                        ___nearcdLogic.GetBuildingsInAreaNonAlloc(__instance.cursorTarget, __instance.reformSize, buildingIdsToDelete);
                    }

                    List <int> listBuildingIdsToDelete = new List <int>();

                    foreach (var id in buildingIdsToDelete)
                    {
                        if (id != 0)
                        {
                            listBuildingIdsToDelete.Add(id);
                        }
                    }

                    foreach (var item in listBuildingIdsToDelete)
                    {
                        deleteEntitiesList.Add(___factory.entityPool[item]);
                    }

                    // Management of both
                    if (Input.GetKey(KeyCode.LeftShift))
                    {
                        if (itemProto != null)
                        {
                            deleteEntitiesList = Utils.GetEntitySortedByTypeAndRadius(itemProto, deleteEntitiesList,
                                                                                      __instance.castObjPos, __instance.reformSize);
                        }
                    }
                }

                // Management of the Mass Item delete
                if (Input.GetKey(KeyCode.LeftShift) && !Input.GetKey(KeyCode.LeftControl))
                {
                    __instance.previewPose.position = Vector3.zero;
                    __instance.previewPose.rotation = Quaternion.identity;
                    if ((uint)__instance.castObjId > 0U)
                    {
                        if (itemProto != null)
                        {
                            if ((uint)___factory.entityPool[__instance.castObjId].beltId > 0U)
                            {
                                CargoPath pathByBeltId = Utils.GetPathWithBeltId(___factory,
                                                                                 ___factory.entityPool[__instance.castObjId].beltId);
                                deleteEntitiesList = Utils.GetBeltsEntitiesByCargoPathBuildRange(___factory, pathByBeltId);
                            }
                            else
                            {
                                // deleteEntitiesList = Utils.GetEntitiesByProtoBuildRange(___factory, itemProto);
                                return(true);
                            }
                        }
                    }
                }


                foreach (var entityData in deleteEntitiesList)
                {
                    __instance.AddBuildPreview(new BuildPreview());
                }

                // Common Code
                for (int index = 0; index < __instance.buildPreviews.Count; ++index)
                {
                    BuildPreview buildPreview = __instance.buildPreviews[index];
                    ItemProto    itemProto2   = Traverse.Create(__instance).Method(
                        "GetItemProto", deleteEntitiesList[index].id).GetValue <ItemProto>();
                    buildPreview.item  = itemProto2;
                    buildPreview.desc  = itemProto2.prefabDesc;
                    buildPreview.lpos  = deleteEntitiesList[index].pos;
                    buildPreview.lrot  = deleteEntitiesList[index].rot;
                    buildPreview.objId = deleteEntitiesList[index].id;
                    int num = buildPreview.desc.lodCount <= 0
                        ? 0
                        : ((Object)buildPreview.desc.lodMeshes[0] != (Object)null ? 1 : 0);
                    buildPreview.needModel  = num != 0;
                    buildPreview.isConnNode = true;
                    if (buildPreview.desc.isInserter)
                    {
                        Pose pose = Traverse.Create(__instance).Method("GetObjectPose2", buildPreview.objId)
                                    .GetValue <Pose>();
                        buildPreview.lpos2 = pose.position;
                        buildPreview.lrot2 = pose.rotation;
                    }

                    if ((buildPreview.lpos - __instance.player.position).sqrMagnitude >
                        __instance.player.mecha.buildArea *
                        __instance.player.mecha.buildArea)
                    {
                        buildPreview.condition   = EBuildCondition.OutOfReach;
                        __instance.cursorText    = "目标超出范围".Translate();
                        __instance.cursorWarning = true;
                    }
                    else
                    {
                        buildPreview.condition = EBuildCondition.Ok;
                        __instance.cursorText  = "拆除".Translate() + buildPreview.item.name;
                    }

                    if (buildPreview.desc.multiLevel)
                    {
                        ___factory.ReadObjectConn(buildPreview.objId, 15, out bool _, out int otherObjId,
                                                  out int _);
                        if ((uint)otherObjId > 0U)
                        {
                            buildPreview.condition = EBuildCondition.Covered;
                            __instance.cursorText  = buildPreview.conditionText;
                        }
                    }
                }


                return(false);
            }