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