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); }
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); }