public static Vector3 SnapModified(this PlanetAuxData auxData, Vector3 pos, bool onTerrain) { if (auxData.activeGridIndex < auxData.customGrids.Count) { Vector3 vector3 = auxData.customGrids[auxData.activeGridIndex].SnapModifiedInternal(pos); float radius = auxData.planet.realRadius + 0.2f; if (!onTerrain) { radius = Mathf.Max(auxData.planet.radius, Mathf.Floor((float)((pos.magnitude - (double)auxData.planet.radius) / 1.33333325386047)) * 1.333333f + auxData.planet.radius) + 0.2f; } pos = vector3 * radius; } return(pos); }
public static void CalculateOffset(this PlanetAuxData auxData, Vector3 pos, GridData gridData) { if (auxData.activeGridIndex >= auxData.customGrids.Count) { return; } PlanetGrid grid = auxData.customGrids[auxData.activeGridIndex]; pos.Normalize(); float latitude = BlueprintUtils.GetLatitudeRad(pos); float longitude = BlueprintUtils.GetLongitudeRad(pos); float latitudeCount = latitude / 6.28318548202515f * grid.segment; float longitudeSegmentCount = PlanetGrid.DetermineLongitudeSegmentCount(Mathf.FloorToInt(Mathf.Max(0.0f, Mathf.Abs(latitudeCount) - 0.1f)), grid.segment); float longtitudeCount = longitude / 6.283185f * longitudeSegmentCount; float offsetLat = Snap(latitudeCount) * 5f; float offsetLong = Snap(longtitudeCount) * 5f; gridData.snapOffset = new Vector2(offsetLong % gridData.snapGrid.x, offsetLat % gridData.snapGrid.y); }
public static void AfterPrebuild_Postfix(PlayerAction_Build __instance, PlanetFactory ___factory, PlanetAuxData ___planetAux, NearColliderLogic ___nearcdLogic) { // Do we have cached inserters? var ci = cachedInserters; if (CopyInserters.copyEnabled && ci.Count > 0 && !__instance.multiLevelCovering) { foreach (var cachedInserter in ci) { var protoId = cachedInserter.protoId; var modelIndex = (short)LDB.items.Select(cachedInserter.protoId).ModelIndex; foreach (BuildPreview buildPreview in __instance.buildPreviews) { var positionData = GetPositions(__instance, ___factory, ___planetAux, ___nearcdLogic, buildPreview, cachedInserter); if (positionData.otherId != 0) { // Create inserter Prebuild data var pbdata = new PrebuildData { protoId = (short)protoId, modelIndex = modelIndex, insertOffset = positionData.insertOffset, pickOffset = positionData.pickOffset, filterId = cachedInserter.filterId, refCount = cachedInserter.refCount, pos = positionData.absoluteInserterPos, pos2 = positionData.absoluteInserterPos2, rot = positionData.absoluteInserterRot, rot2 = positionData.absoluteInserterRot2 }; // Check the player has the item in inventory, no cheating here var pc = CopyInserters.pc; var itemcount = pc.player.package.GetItemCount(protoId); // If player has none; skip this request, as we dont create prebuild ghosts, must avoid confusion if (itemcount > 0) { var qty = 1; pc.player.package.TakeTailItems(ref protoId, ref qty); int pbCursor = ___factory.AddPrebuildDataWithComponents(pbdata); // Add the inserter request to Prebuild pool if (cachedInserter.incoming) { ___factory.WriteObjectConn(-pbCursor, 0, true, buildPreview.objId, positionData.endSlot); // assembler connection ___factory.WriteObjectConn(-pbCursor, 1, false, positionData.otherId, positionData.startSlot); // other connection } else { ___factory.WriteObjectConn(-pbCursor, 0, false, buildPreview.objId, positionData.startSlot); // assembler connection ___factory.WriteObjectConn(-pbCursor, 1, true, positionData.otherId, positionData.endSlot); // other connection } } } } } } }
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 void SetCopyInfo_Postfix(PlayerAction_Build __instance, PlanetFactory ___factory, PlanetAuxData ___planetAux, int objectId, int protoId) { cachedInserters.Clear(); // Remove previous copy info if (objectId < 0) // Copied item is a ghost, no inserters to cache { return; } var sourceEntityProto = LDB.items.Select(protoId); var sourceEntityId = objectId; var sourceEntity = ___factory.entityPool[sourceEntityId]; var sourcePos = sourceEntity.pos; var sourceRot = sourceEntity.rot; // Set the current build rotation to the copied building rotation Quaternion zeroRot = Maths.SphericalRotation(sourcePos, 0f); float yaw = Vector3.SignedAngle(zeroRot.Forward(), sourceRot.Forward(), zeroRot.Up()); if (sourceEntityProto.prefabDesc.minerType != EMinerType.Vein) { yaw = Mathf.Round(yaw / 90f) * 90f; } __instance.yaw = yaw; // Ignore building without inserter slots if (sourceEntityProto.prefabDesc.insertPoses.Length == 0) { return; } // Find connected inserters var inserterPool = ___factory.factorySystem.inserterPool; var entityPool = ___factory.entityPool; for (int i = 1; i < ___factory.factorySystem.inserterCursor; i++) { if (inserterPool[i].id == i) { var inserter = inserterPool[i]; var inserterEntity = entityPool[inserter.entityId]; var pickTarget = inserter.pickTarget; var insertTarget = inserter.insertTarget; if (pickTarget == sourceEntityId || insertTarget == sourceEntityId) { ItemProto itemProto = LDB.items.Select(inserterEntity.protoId); bool incoming = insertTarget == sourceEntityId; var otherId = incoming ? pickTarget : insertTarget; // The belt or other building this inserter is attached to Vector3 otherPos; ItemProto otherProto; if (otherId > 0) { otherPos = entityPool[otherId].pos; otherProto = LDB.items.Select((int)___factory.entityPool[otherId].protoId); } else { otherPos = ___factory.prebuildPool[-otherId].pos; otherProto = LDB.items.Select((int)___factory.prebuildPool[-otherId].protoId); } // Store the Grid-Snapped moves from assembler to belt/other int path = 0; Vector3[] snaps = new Vector3[6]; var snappedPointCount = ___planetAux.SnapLineNonAlloc(sourcePos, otherPos, ref path, snaps); Vector3 lastSnap = sourcePos; Vector3[] snapMoves = new Vector3[snappedPointCount]; for (int s = 0; s < snappedPointCount; s++) { // note: reverse rotation of the delta so that rotation works Vector3 snapMove = Quaternion.Inverse(sourceRot) * (snaps[s] - lastSnap); snapMoves[s] = snapMove; lastSnap = snaps[s]; } bool otherIsBelt = otherProto != null && otherProto.prefabDesc.isBelt; // Cache info for this inserter CachedInserter ci = new CachedInserter { incoming = incoming, protoId = inserterEntity.protoId, // rotations + deltas relative to the source building's rotation rot = Quaternion.Inverse(sourceRot) * inserterEntity.rot, rot2 = Quaternion.Inverse(sourceRot) * inserter.rot2, posDelta = Quaternion.Inverse(sourceRot) * (inserterEntity.pos - sourcePos), // Delta from copied building to inserter pos pos2Delta = Quaternion.Inverse(sourceRot) * (inserter.pos2 - sourcePos), // Delta from copied building to inserter pos2 // store to restore inserter speed refCount = Mathf.RoundToInt((float)(inserter.stt - 0.499f) / itemProto.prefabDesc.inserterSTT), // not important? pickOffset = inserter.pickOffset, insertOffset = inserter.insertOffset, // needed for pose? t1 = inserter.t1, t2 = inserter.t2, filterId = inserter.filter, snapMoves = snapMoves, snapCount = snappedPointCount, startSlot = -1, endSlot = -1, otherIsBelt = otherIsBelt }; // compute the start and end slot that the cached inserter uses CalculatePose(__instance, pickTarget, insertTarget); if (__instance.posePairs.Count > 0) { float minDistance = 1000f; for (int j = 0; j < __instance.posePairs.Count; ++j) { var posePair = __instance.posePairs[j]; float startDistance = Vector3.Distance(posePair.startPose.position, inserterEntity.pos); float endDistance = Vector3.Distance(posePair.endPose.position, inserter.pos2); float poseDistance = startDistance + endDistance; if (poseDistance < minDistance) { minDistance = poseDistance; ci.startSlot = posePair.startSlot; ci.endSlot = posePair.endSlot; } } } cachedInserters.Add(ci); } } } }
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(); } }
public static void PlayerAction_BuildNotifyBuiltPrefix(int postObjId, PlanetAuxData ___planetAux) { var entityBuilt = pc.player.factory.entityPool[postObjId]; ModelProto modelProto = LDB.models.Select(entityBuilt.modelIndex); var prefabDesc = modelProto.prefabDesc; if (!prefabDesc.isInserter) { // Check for pending inserter requests if (PatchCopyInserters.pendingInserters.Count > 0) { var factory = pc.player.factory; for (int i = pendingInserters.Count - 1; i >= 0; i--) // Reverse loop for removing found elements { var pi = pendingInserters[i]; // Is the NotifyBuilt assembler in the expected position for this pending inserter? var distance = Vector3.Distance(entityBuilt.pos, pi.AssemblerPos); if (distance < 0.2) { var assemblerId = entityBuilt.id; //Debug.Log($"!!! found assembler id={assemblerId} at Pos={entityBuilt.pos} expected {pi.AssemblerPos} distance={distance}"); // Create inserter Prebuild data var pbdata = new PrebuildData(); pbdata.protoId = (short)pi.ci.protoId; pbdata.modelIndex = (short)LDB.items.Select(pi.ci.protoId).ModelIndex; pbdata.modelId = factory.entityPool[pi.otherId].modelId; pbdata.insertOffset = pi.ci.insertOffset; pbdata.pickOffset = pi.ci.pickOffset; pbdata.filterId = pi.ci.filterId; // YukkuriC: recover absolute transforms Helper.AbsTransform(entityBuilt.pos, pi.ci.posDelta, pi.ci.rot, out pbdata.pos, out pbdata.rot); Helper.AbsTransform(entityBuilt.pos, pi.ci.pos2delta, pi.ci.rot2, out pbdata.pos2, out pbdata.rot2); pbdata.pos = ___planetAux.Snap(pbdata.pos, true, false); pbdata.pos2 = ___planetAux.Snap(pbdata.pos2, true, false); // Check the player has the item in inventory, no cheating here var itemcount = pc.player.package.GetItemCount(pi.ci.protoId); // If player has none; skip this request, as we dont create prebuild ghosts, must avoid confusion if (itemcount > 0) { var qty = 1; pc.player.package.TakeTailItems(ref pi.ci.protoId, ref qty); int pbCursor = factory.AddPrebuildData(pbdata); // Add the inserter request to Prebuild pool // Otherslot -1 will try to find one, otherwise could cache this from original assembler if it causes problems if (pi.ci.incoming) { factory.WriteObjectConn(-pbCursor, 0, true, assemblerId, -1); // assembler connection factory.WriteObjectConn(-pbCursor, 1, false, pi.otherId, -1); // other connection } else { factory.WriteObjectConn(-pbCursor, 0, false, assemblerId, -1); // assembler connection factory.WriteObjectConn(-pbCursor, 1, true, pi.otherId, -1); // other connection } } pendingInserters.RemoveAt(i); } } } } }
public static void PlayerAction_BuildAfterPrebuildPostfix(PlayerAction_Build __instance, ref PlanetFactory ___factory, PlanetAuxData ___planetAux) { // Do we have cached inserters? var ci = PatchCopyInserters.cachedInserters; if (ci.Count > 0) { var targetPos = __instance.buildTargetPositionWanted; var entityPool = ___factory.entityPool; foreach (var inserter in ci) { // 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 currentPos = targetPos; for (int u = 0; u < inserter.snapCount; u++) { currentPos = ___planetAux.Snap(currentPos + inserter.snapMoves[u], true, false); } var testPos = currentPos; // Find the other entity at the target location int otherId = 0; for (int x = 1; x < ___factory.entityCursor; x++) { if (entityPool[x].id == x) { var distance = Vector3.Distance(entityPool[x].pos, testPos); if (distance < 0.2) { otherId = entityPool[x].id; break; } } } if (otherId != 0) { // Order an inserter var pi = new PatchCopyInserters.PendingInserter(); pi.otherId = otherId; pi.ci = inserter; pi.AssemblerPos = targetPos; PatchCopyInserters.pendingInserters.Add(pi); } } } }
public static void PlayerAction_BuildSetCopyInfoPostfix(ref PlanetFactory ___factory, int objectId, PlanetAuxData ___planetAux) { cachedInserters.Clear(); // Remove previous copy info var sourceEntity = objectId; var sourcePos = ___factory.entityPool[objectId].pos; var sourceRot = ___factory.entityPool[objectId].rot; // Find connected inserters int matches = 0; var inserterPool = ___factory.factorySystem.inserterPool; var entityPool = ___factory.entityPool; for (int i = 1; i < ___factory.factorySystem.inserterCursor; i++) { if (inserterPool[i].id == i) { var inserter = inserterPool[i]; var pickTarget = inserter.pickTarget; var insertTarget = inserter.insertTarget; if (pickTarget == sourceEntity || insertTarget == sourceEntity) { matches++; var inserterType = ___factory.entityPool[inserter.entityId].protoId; bool incoming = insertTarget == sourceEntity; var otherId = incoming ? pickTarget : insertTarget; // The belt or other building this inserter is attached to var otherPos = ___factory.entityPool[otherId].pos; // Store the Grid-Snapped moves from assembler to belt/other Vector3 begin = sourcePos; Vector3 end = otherPos; int path = 0; Vector3[] snaps = new Vector3[6]; var snappedPointCount = ___planetAux.SnapLineNonAlloc(begin, end, ref path, snaps); Vector3 lastSnap = begin; Vector3[] snapMoves = new Vector3[snappedPointCount]; for (int s = 0; s < snappedPointCount; s++) { Vector3 snapMove = snaps[s] - lastSnap; snapMoves[s] = snapMove; lastSnap = snaps[s]; } // Cache info for this inserter var ci = new CachedInserter(); ci.incoming = incoming; ci.protoId = inserterType; ci.rot = ___factory.entityPool[inserter.entityId].rot; ci.rot2 = inserter.rot2; ci.pos2delta = inserter.pos2; // YukkuriC: record abs pos first ci.posDelta = entityPool[inserter.entityId].pos; // YukkuriC: dump relative transforms Helper.RelTransform(sourcePos, entityPool[inserter.entityId].pos, ___factory.entityPool[inserter.entityId].rot, out ci.posDelta, out ci.rot); Helper.RelTransform(sourcePos, inserter.pos2, inserter.rot2, out ci.pos2delta, out ci.rot2); // not important? ci.pickOffset = inserter.pickOffset; ci.insertOffset = inserter.insertOffset; // needed for pose? ci.t1 = inserter.t1; ci.t2 = inserter.t2; ci.filterId = inserter.filter; ci.snapMoves = snapMoves; ci.snapCount = snappedPointCount; cachedInserters.Add(ci); } } } }
public static BPGratBox GetBoundingRange(PlanetData _planet, PlanetAuxData aux, int[] _objIds, int _objCount, List <ReformData> reforms, float _divideLongitude) { if (reforms.Count == 0 && _objCount == 0) { return(BPGratBox.zero); } float startlong = float.MaxValue; float startLat = float.MaxValue; float endLong = float.MinValue; float endLat = float.MinValue; bool isPole = true; EntityData[] entityPool = _planet.factory.entityPool; PrebuildData[] prebuildPool = _planet.factory.prebuildPool; for (int i = 0; i < _objCount; i++) { int id = _objIds[i]; Vector3 pos = (id > 0) ? entityPool[id].pos.normalized : prebuildPool[-id].pos.normalized; Vector3 normalized = aux.Snap(pos, true).normalized; float num6 = Mathf.Asin(normalized.y); float num7 = Mathf.Atan2(normalized.x, -normalized.z); if (normalized.x * normalized.x + normalized.z * normalized.z >= 5E-07f) { isPole = false; float correctLong = num7 - _divideLongitude; if (correctLong <= -1.8E-05f) { correctLong += 6.2831855f; } if (correctLong < 0f) { correctLong = 0f; } startlong = ((startlong < correctLong) ? startlong : correctLong); endLong = ((endLong > correctLong) ? endLong : correctLong); } startLat = ((startLat < num6) ? startLat : num6); endLat = ((endLat > num6) ? endLat : num6); } if (BlueprintCopyExtension.isEnabled) { foreach (var data in reforms) { if (data.longitude != 0) { isPole = false; float correctLong = data.longitude - _divideLongitude; if (correctLong <= -1.8E-05f) { correctLong += 6.2831855f; } if (correctLong < 0f) { correctLong = 0f; } startlong = startlong < correctLong ? startlong : correctLong; endLong = endLong > correctLong ? endLong : correctLong; } startLat = startLat < data.latitude ? startLat : data.latitude; endLat = endLat > data.latitude ? endLat : data.latitude; } } if (startlong < 0f) { startlong = 0f; } else if (startlong > 6.2831674f) { startlong = 6.2831674f; } if (endLong < 0f) { endLong = 0f; } else if (endLong > 6.2831674f) { endLong = 6.2831674f; } if (isPole) { startlong = 0f; endLong = 6.2831674f; } startlong += _divideLongitude; endLong += _divideLongitude; if (startlong < -3.1415927f) { startlong += 6.2831855f; } else if (startlong > 3.1415927f) { startlong -= 6.2831855f; } if (endLong < -3.1415927f) { endLong += 6.2831855f; } else if (endLong > 3.1415927f) { endLong -= 6.2831855f; } return(new BPGratBox(startlong, startLat, endLong, endLat)); }
public static void PlayerAction_BuildAfterPrebuildPostfix(PlayerAction_Build __instance, ref PlanetFactory ___factory, PlanetAuxData ___planetAux) { // Do we have cached inserters? var ci = PatchCopyInserters.cachedInserters; if (CopyInserters.copyEnabled && ci.Count > 0) { foreach (BuildPreview buildPreview in __instance.buildPreviews) { Vector3 targetPos; Quaternion targetRot; if (__instance.buildPreviews.Count > 1) { targetPos = buildPreview.lpos; targetRot = buildPreview.lrot; } else { targetPos = __instance.previewPose.position + __instance.previewPose.rotation * buildPreview.lpos; targetRot = __instance.previewPose.rotation; } // ignore buildings not being built at ground level if (__instance.multiLevelCovering) { continue; } var entityPool = ___factory.entityPool; foreach (var inserter in ci) { // 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 = targetPos; // Note: rotates each move relative to the rotation of the new building for (int u = 0; u < inserter.snapCount; u++) { testPos = ___planetAux.Snap(testPos + targetRot * inserter.snapMoves[u], true, false); } // Find the other entity at the target location int otherId = 0; for (int x = 1; x < ___factory.entityCursor; x++) { if (entityPool[x].id == x) { var distance = Vector3.Distance(entityPool[x].pos, testPos); if (distance < 0.2) { otherId = entityPool[x].id; break; } } } if (otherId != 0) { // Order an inserter var pi = new PatchCopyInserters.PendingInserter(); pi.otherId = otherId; pi.ci = inserter; pi.AssemblerPos = targetPos; PatchCopyInserters.pendingInserters.Add(pi); } } } } }
public static void PlayerAction_BuildSetCopyInfoPostfix(PlayerAction_Build __instance, ref PlanetFactory ___factory, PlanetAuxData ___planetAux, int objectId, int protoId) { cachedInserters.Clear(); // Remove previous copy info if (objectId < 0) // Copied item is a ghost, no inserters to cache { return; } var sourceEntityProto = LDB.items.Select(protoId); // Ignore building without inserter slots if (sourceEntityProto.prefabDesc.insertPoses.Length == 0) { return; } var sourceEntityId = objectId; var sourceEntity = ___factory.entityPool[sourceEntityId]; var sourcePos = sourceEntity.pos; var sourceRot = sourceEntity.rot; // Find connected inserters var inserterPool = ___factory.factorySystem.inserterPool; var entityPool = ___factory.entityPool; for (int i = 1; i < ___factory.factorySystem.inserterCursor; i++) { if (inserterPool[i].id == i) { var inserter = inserterPool[i]; var inserterEntity = entityPool[inserter.entityId]; var pickTarget = inserter.pickTarget; var insertTarget = inserter.insertTarget; if (pickTarget == sourceEntityId || insertTarget == sourceEntityId) { bool incoming = insertTarget == sourceEntityId; var otherId = incoming ? pickTarget : insertTarget; // The belt or other building this inserter is attached to var otherPos = entityPool[otherId].pos; // Store the Grid-Snapped moves from assembler to belt/other int path = 0; Vector3[] snaps = new Vector3[6]; var snappedPointCount = ___planetAux.SnapLineNonAlloc(sourcePos, otherPos, ref path, snaps); Vector3 lastSnap = sourcePos; Vector3[] snapMoves = new Vector3[snappedPointCount]; for (int s = 0; s < snappedPointCount; s++) { // note: reverse rotation of the delta so that rotation works Vector3 snapMove = Quaternion.Inverse(sourceRot) * (snaps[s] - lastSnap); snapMoves[s] = snapMove; lastSnap = snaps[s]; } // Cache info for this inserter var ci = new CachedInserter(); ci.incoming = incoming; ci.protoId = inserterEntity.protoId; // rotations + deltas relative to the source building's rotation ci.rot = Quaternion.Inverse(sourceRot) * inserterEntity.rot; ci.rot2 = Quaternion.Inverse(sourceRot) * inserter.rot2; ci.posDelta = Quaternion.Inverse(sourceRot) * (inserterEntity.pos - sourcePos); // Delta from copied building to inserter pos ci.pos2Delta = Quaternion.Inverse(sourceRot) * (inserter.pos2 - sourcePos); // Delta from copied building to inserter pos2 ItemProto itemProto = LDB.items.Select(ci.protoId); ci.refCount = Mathf.RoundToInt((float)(inserter.stt - 0.499f) / itemProto.prefabDesc.inserterSTT); // compute the start and end slot that the cached inserter uses if (!incoming) { CalculatePose(__instance, sourceEntityId, otherId); } else { CalculatePose(__instance, otherId, sourceEntityId); } if (__instance.posePairs.Count > 0) { float minDistance = 1000f; PlayerAction_Build.PosePair bestFit = new PlayerAction_Build.PosePair(); bool hasNearbyPose = false; for (int j = 0; j < __instance.posePairs.Count; ++j) { float startDistance = Vector3.Distance(__instance.posePairs[j].startPose.position, inserterEntity.pos); float endDistance = Vector3.Distance(__instance.posePairs[j].endPose.position, inserter.pos2); float poseDistance = startDistance + endDistance; if (poseDistance < minDistance) { minDistance = poseDistance; bestFit = __instance.posePairs[j]; hasNearbyPose = true; } } if (hasNearbyPose) { ci.startSlot = bestFit.startSlot; ci.endSlot = bestFit.endSlot; } } // not important? ci.pickOffset = inserter.pickOffset; ci.insertOffset = inserter.insertOffset; // needed for pose? ci.t1 = inserter.t1; ci.t2 = inserter.t2; ci.filterId = inserter.filter; ci.snapMoves = snapMoves; ci.snapCount = snappedPointCount; cachedInserters.Add(ci); } } } }
public static void PlayerAction_BuildNotifyBuiltPrefix(PlayerAction_Build __instance, int postObjId, PlanetAuxData ___planetAux) { var entityBuilt = pc.player.factory.entityPool[postObjId]; ModelProto modelProto = LDB.models.Select(entityBuilt.modelIndex); var prefabDesc = modelProto.prefabDesc; if (!prefabDesc.isInserter) { // Check for pending inserter requests if (PatchCopyInserters.pendingInserters.Count > 0) { var factory = pc.player.factory; for (int i = pendingInserters.Count - 1; i >= 0; i--) // Reverse loop for removing found elements { var pi = pendingInserters[i]; // Is the NotifyBuilt assembler in the expected position for this pending inserter? var distance = Vector3.Distance(entityBuilt.pos, pi.AssemblerPos); if (distance < 0.2) { var assemblerId = entityBuilt.id; // Create inserter Prebuild data var pbdata = new PrebuildData(); pbdata.protoId = (short)pi.ci.protoId; pbdata.modelIndex = (short)LDB.items.Select(pi.ci.protoId).ModelIndex; pbdata.insertOffset = pi.ci.insertOffset; pbdata.pickOffset = pi.ci.pickOffset; pbdata.filterId = pi.ci.filterId; pbdata.refCount = pi.ci.refCount; // Calculate inserter start and end positions from stored deltas and the building's rotation pbdata.pos = ___planetAux.Snap(entityBuilt.pos + entityBuilt.rot * pi.ci.posDelta, true, false); pbdata.pos2 = ___planetAux.Snap(entityBuilt.pos + entityBuilt.rot * pi.ci.pos2Delta, true, false); // Get inserter rotation relative to the building's pbdata.rot = entityBuilt.rot * pi.ci.rot; pbdata.rot2 = entityBuilt.rot * pi.ci.rot2; if (!pi.ci.incoming) { CalculatePose(__instance, assemblerId, pi.otherId); } else { CalculatePose(__instance, pi.otherId, assemblerId); } if (__instance.posePairs.Count > 0) { float minDistance = 1000f; PlayerAction_Build.PosePair bestFit = new PlayerAction_Build.PosePair(); bool hasNearbyPose = false; for (int j = 0; j < __instance.posePairs.Count; ++j) { if (__instance.posePairs[j].startSlot != pi.ci.startSlot || __instance.posePairs[j].endSlot != pi.ci.endSlot) { continue; } float startDistance = Vector3.Distance(__instance.posePairs[j].startPose.position, pbdata.pos); float endDistance = Vector3.Distance(__instance.posePairs[j].endPose.position, pbdata.pos2); float poseDistance = startDistance + endDistance; if (poseDistance < minDistance) { minDistance = poseDistance; bestFit = __instance.posePairs[j]; hasNearbyPose = true; } } if (hasNearbyPose) { // if we were able to calculate a close enough sensible pose // use that instead of the (visually) ugly default pbdata.pos = bestFit.startPose.position; pbdata.pos2 = bestFit.endPose.position; pbdata.rot = bestFit.startPose.rotation; pbdata.rot2 = bestFit.endPose.rotation * Quaternion.Euler(0.0f, 180f, 0.0f); } } // Check the player has the item in inventory, no cheating here var itemcount = pc.player.package.GetItemCount(pi.ci.protoId); // If player has none; skip this request, as we dont create prebuild ghosts, must avoid confusion if (itemcount > 0) { var qty = 1; pc.player.package.TakeTailItems(ref pi.ci.protoId, ref qty); int pbCursor = factory.AddPrebuildData(pbdata); // Add the inserter request to Prebuild pool // Otherslot -1 will try to find one, otherwise could cache this from original assembler if it causes problems if (pi.ci.incoming) { factory.WriteObjectConn(-pbCursor, 0, true, assemblerId, -1); // assembler connection factory.WriteObjectConn(-pbCursor, 1, false, pi.otherId, -1); // other connection } else { factory.WriteObjectConn(-pbCursor, 0, false, assemblerId, -1); // assembler connection factory.WriteObjectConn(-pbCursor, 1, true, pi.otherId, -1); // other connection } } pendingInserters.RemoveAt(i); } } } } }
public static void PlayerAction_BuildSetCopyInfoPostfix(PlayerAction_Build __instance, ref PlanetFactory ___factory, int objectId, PlanetAuxData ___planetAux) { cachedInserters.Clear(); // Remove previous copy info if (objectId < 0) // Copied item is a ghost, no inserters to cache { return; } var sourceEntity = objectId; var sourcePos = ___factory.entityPool[objectId].pos; // Find connected inserters int matches = 0; var inserterPool = ___factory.factorySystem.inserterPool; var entityPool = ___factory.entityPool; for (int i = 1; i < ___factory.factorySystem.inserterCursor; i++) { if (inserterPool[i].id == i) { var inserter = inserterPool[i]; var pickTarget = inserter.pickTarget; var insertTarget = inserter.insertTarget; if (pickTarget == sourceEntity || insertTarget == sourceEntity) { matches++; var inserterType = ___factory.entityPool[inserter.entityId].protoId; bool incoming = insertTarget == sourceEntity; var otherId = incoming ? pickTarget : insertTarget; // The belt or other building this inserter is attached to var otherPos = ___factory.entityPool[otherId].pos; // Store the Grid-Snapped moves from assembler to belt/other Vector3 begin = sourcePos; Vector3 end = otherPos; int path = 0; Vector3[] snaps = new Vector3[6]; var snappedPointCount = ___planetAux.SnapLineNonAlloc(begin, end, ref path, snaps); Vector3 lastSnap = begin; Vector3[] snapMoves = new Vector3[snappedPointCount]; for (int s = 0; s < snappedPointCount; s++) { Vector3 snapMove = snaps[s] - lastSnap; snapMoves[s] = snapMove; lastSnap = snaps[s]; } // Cache info for this inserter var ci = new CachedInserter(); ci.otherDelta = (otherPos - sourcePos); // Delta from copied building to other belt/building ci.incoming = incoming; ci.protoId = inserterType; ci.rot = ___factory.entityPool[inserter.entityId].rot; ci.rot2 = inserter.rot2; ci.pos2delta = (inserter.pos2 - entityPool[inserter.entityId].pos); // Delta from inserter pos2 to copied building var posDelta = entityPool[inserter.entityId].pos - sourcePos; // Delta from copied building to inserter pos if (!incoming) { posDelta = sourcePos - entityPool[inserter.entityId].pos; // Reverse for outgoing inserters } ci.posDelta = posDelta; // compute the start and end slot that the cached inserter uses if (!incoming) { CalculatePose(__instance, sourceEntity, otherId); } else { CalculatePose(__instance, otherId, sourceEntity); } if (__instance.posePairs.Count > 0) { float minDistance = 1000f; PlayerAction_Build.PosePair bestFit = new PlayerAction_Build.PosePair(); bool hasNearbyPose = false; for (int j = 0; j < __instance.posePairs.Count; ++j) { float startDistance = Vector3.Distance(__instance.posePairs[j].startPose.position, entityPool[inserter.entityId].pos); float endDistance = Vector3.Distance(__instance.posePairs[j].endPose.position, inserter.pos2); float poseDistance = startDistance + endDistance; if (poseDistance < minDistance) { minDistance = poseDistance; bestFit = __instance.posePairs[j]; hasNearbyPose = true; } } if (hasNearbyPose) { ci.startSlot = bestFit.startSlot; ci.endSlot = bestFit.endSlot; } } // not important? ci.pickOffset = inserter.pickOffset; ci.insertOffset = inserter.insertOffset; // needed for pose? ci.t1 = inserter.t1; ci.t2 = inserter.t2; ci.filterId = inserter.filter; ci.snapMoves = snapMoves; ci.snapCount = snappedPointCount; cachedInserters.Add(ci); } } } }