public void OnSettingsUI(UIHelperBase helper) { try { UIHelper group = helper.AddGroup(Name) as UIHelper; UIPanel panel = group.self as UIPanel; UICheckBox checkBox = (UICheckBox)group.AddCheckbox("Hide tips", MoveItTool.hideTips.value, (b) => { MoveItTool.hideTips.value = b; if (UITipsWindow.instance != null) { UITipsWindow.instance.isVisible = false; } }); checkBox.tooltip = "Check this if you don't want to see the tips.\n"; checkBox = (UICheckBox)group.AddCheckbox("Use cardinal movements", MoveItTool.useCardinalMoves.value, (b) => { MoveItTool.useCardinalMoves.value = b; }); checkBox.tooltip = "If checked, Up will move in the North direction, Down is South, Left is West, Right is East.\n"; group.AddSpace(10); panel.gameObject.AddComponent <OptionsKeymapping>(); group.AddSpace(10); } catch (Exception e) { DebugUtils.Log("OnSettingsUI failed"); DebugUtils.LogException(e); } }
public virtual void SaveIntegrations() { foreach (var integration in MoveItTool.Integrations) { try { IntegrationData[integration] = integration.Copy(instance.id); } catch (Exception e) { Debug.LogError($"integration {integration} Failed to copy {instance?.id}" + integration); DebugUtils.LogException(e); } } }
public ModInfo() { try { // Creating setting file GameSettings.AddSettingsFile(new SettingsFile[] { new SettingsFile() { fileName = MoveItTool.settingsFileName } }); } catch (Exception e) { DebugUtils.Log("Could load/create the setting file."); DebugUtils.LogException(e); } }
private void ImportImpl(string filename, bool restore) { lock (ActionQueue.instance) { StopCloning(); StopTool(); //bool activatePO = true; //if (!PO.Active) //{ // activatePO = false; // PO.InitialiseTool(true); //} XmlSerializer xmlSerializer = new XmlSerializer(typeof(Selection)); Selection selectionState; string path = Path.Combine(saveFolder, filename + ".xml"); try { // Trying to Deserialize the file using (FileStream stream = new FileStream(path, FileMode.Open)) { selectionState = xmlSerializer.Deserialize(stream) as Selection; } } catch (Exception e) { // Couldn't Deserialize (XML malformed?) DebugUtils.Log("Couldn't load file"); DebugUtils.LogException(e); UIView.library.ShowModal <ExceptionPanel>("ExceptionPanel").SetMessage("Import failed", "Couldn't load '" + path + "'\n\n" + e.Message, true); return; } //if (!activatePO && !selectionState.includesPO) //{ // PO.InitialiseTool(false); //} ImportFromArray(selectionState, restore); } }
public ModInfo() { try { // Creating setting file if (GameSettings.FindSettingsFileByName(MoveItTool.settingsFileName) == null) { GameSettings.AddSettingsFile(new SettingsFile[] { new SettingsFile() { fileName = MoveItTool.settingsFileName } }); } } catch (Exception e) { DebugUtils.Log("Could not load/create the setting file."); DebugUtils.LogException(e); } }
public void Delete(string filename) { try { string path = Path.Combine(saveFolder, filename + ".xml"); if (File.Exists(path)) { File.Delete(path); } } catch (Exception ex) { DebugUtils.Log("Couldn't delete file"); DebugUtils.LogException(ex); return; } }
public virtual void SaveIntegrations(bool integrate) { //Log.Debug($"AAA1 {Info.Name} - {integrate}\n{ActionQueue.instance.current.GetType()}"); if (!integrate) { return; } foreach (var integration in MoveItTool.Integrations) { try { IntegrationData[integration] = integration.Copy(instance.id); } catch (Exception e) { Log.Error($"integration {integration} Failed to copy {instance?.id}" + integration); DebugUtils.LogException(e); } } }
public override void Do() { base.Do(); // Clone integrations foreach (var item in m_stateToClone) { foreach (var data in item.Key.IntegrationData) { try { data.Key.Paste(item.Value.id, data.Value, m_InstanceID_origToClone); } catch (Exception e) { InstanceID sourceInstanceID = item.Key.instance.id; InstanceID targetInstanceID = item.Value.id; Log.Error($"integration {data.Key} Failed to paste from " + $"{sourceInstanceID.Type}:{sourceInstanceID.Index} to {targetInstanceID.Type}:{targetInstanceID.Index}"); DebugUtils.LogException(e); } } } }
public void OnSettingsUI(UIHelperBase helper) { try { UIHelperBase group = helper.AddGroup(Name); UIPanel panel = ((UIPanel)((UIHelper)group).self) as UIPanel; UICheckBox checkBox = (UICheckBox)group.AddCheckbox("Auto-close Toolbox menu", MoveItTool.autoCloseAlignTools.value, (b) => { MoveItTool.autoCloseAlignTools.value = b; if (UIMoreTools.MoreToolsPanel != null) { UIMoreTools.CloseMenu(); } }); checkBox.tooltip = "Check this to close the Toolbox menu after choosing a tool."; group.AddSpace(10); checkBox = (UICheckBox)group.AddCheckbox("Prefer fast, low-detail moving (hold Shift to temporarily switch)", MoveItTool.fastMove.value, (b) => { MoveItTool.fastMove.value = b; }); checkBox.tooltip = "Helps you position objects when your frame-rate is poor."; group.AddSpace(10); checkBox = (UICheckBox)group.AddCheckbox("Hide selectors/overlays when in low-sensitivity mode", MoveItTool.hideSelectorsOnLowSensitivity.value, (b) => { MoveItTool.hideSelectorsOnLowSensitivity.value = b; }); checkBox.tooltip = "When holding control, the selection overlays are hidden"; group.AddSpace(10); checkBox = (UICheckBox)group.AddCheckbox("Select pylons and pillars by holding Alt only", MoveItTool.altSelectNodeBuildings.value, (b) => { MoveItTool.altSelectNodeBuildings.value = b; }); group.AddSpace(10); checkBox = (UICheckBox)group.AddCheckbox("Use cardinal movements", MoveItTool.useCardinalMoves.value, (b) => { MoveItTool.useCardinalMoves.value = b; }); checkBox.tooltip = "If checked, Up will move in the North direction, Down is South, Left is West, Right is East."; group.AddSpace(10); checkBox = (UICheckBox)group.AddCheckbox("Right click cancels cloning", MoveItTool.rmbCancelsCloning.value, (b) => { MoveItTool.rmbCancelsCloning.value = b; }); checkBox.tooltip = "If checked, Right click will cancel cloning instead of rotating 45°."; group.AddSpace(10); group = helper.AddGroup("General Shortcuts"); panel = ((UIPanel)((UIHelper)group).self) as UIPanel; group.AddSpace(10); ((UIPanel)((UIHelper)group).self).gameObject.AddComponent <OptionsKeymappingMain>(); group.AddSpace(10); group = helper.AddGroup("Toolbox Shortcuts"); panel = ((UIPanel)((UIHelper)group).self) as UIPanel; group.AddSpace(10); ((UIPanel)((UIHelper)group).self).gameObject.AddComponent <OptionsKeymappingToolbox>(); group.AddSpace(10); group = helper.AddGroup("Extra Options"); panel = ((UIPanel)((UIHelper)group).self) as UIPanel; group.AddSpace(10); UIButton button = (UIButton)group.AddButton("Remove Ghost Nodes", MoveItTool.CleanGhostNodes); button.tooltip = "Use this button when in-game to remove ghost nodes (nodes with no segments attached). Note: this will clear Move It's undo history!"; group.AddSpace(20); checkBox = (UICheckBox)group.AddCheckbox("Disable debug messages logging", DebugUtils.hideDebugMessages.value, (b) => { DebugUtils.hideDebugMessages.value = b; }); checkBox.tooltip = "If checked, debug messages won't be logged."; checkBox = (UICheckBox)group.AddCheckbox("Show Move It debug panel\n", MoveItTool.showDebugPanel.value, (b) => { MoveItTool.showDebugPanel.value = b; if (MoveItTool.m_debugPanel != null) { MoveItTool.m_debugPanel.Visible(b); } }); checkBox.name = "MoveIt_DebugPanel"; UILabel debugLabel = panel.AddUIComponent <UILabel>(); debugLabel.name = "debugLabel"; debugLabel.text = " Shows information about the last highlighted object. Slightly decreases\n" + " performance, do not enable unless you have a specific reason.\n "; group.AddSpace(5); UILabel nsLabel = panel.AddUIComponent <UILabel>(); nsLabel.name = "nsLabel"; nsLabel.text = NS_Manager.getVersionText(); UILabel ncLabel = panel.AddUIComponent <UILabel>(); ncLabel.name = "ncLabel"; ncLabel.text = NodeController_Manager.getVersionText(); UILabel tmpeLabel = panel.AddUIComponent <UILabel>(); tmpeLabel.name = "tmpeLabel"; tmpeLabel.text = TMPE_Manager.getVersionText(); group = helper.AddGroup("Procedural Objects"); panel = ((UIPanel)((UIHelper)group).self) as UIPanel; UILabel poLabel = panel.AddUIComponent <UILabel>(); poLabel.name = "poLabel"; poLabel.text = PO_Manager.getVersionText(); UILabel poWarning = panel.AddUIComponent <UILabel>(); poWarning.name = "poWarning"; poWarning.text = " Please note: you can not undo Bulldozed PO. This means if you delete \n" + " PO objects with Move It, they are immediately PERMANENTLY gone.\n "; checkBox = (UICheckBox)group.AddCheckbox("Hide the PO deletion warning", !MoveItTool.POShowDeleteWarning.value, (b) => { MoveItTool.POShowDeleteWarning.value = !b; }); checkBox = (UICheckBox)group.AddCheckbox("Highlight unselected visible PO objects", MoveItTool.POHighlightUnselected.value, (b) => { MoveItTool.POHighlightUnselected.value = b; if (MoveItTool.PO != null) { try { MoveItTool.PO.ToolEnabled(); } catch (ArgumentException e) { Debug.Log($"PO Integration failed:\n{e}"); } } }); checkBox.tooltip = "Show a faded purple circle around PO objects that aren't selected."; group.AddSpace(15); panel.gameObject.AddComponent <OptionsKeymappingPO>(); group.AddSpace(15); } catch (Exception e) { DebugUtils.Log("OnSettingsUI failed"); DebugUtils.LogException(e); } }
public override void Do() { if (MoveItTool.POProcessing > 0) { return; } MoveItTool.instance.m_lastInstance = null; m_clones = new HashSet <Instance>(); m_origToCloneUpdate = new Dictionary <Instance, Instance>(); m_nodeOrigToClone = new Dictionary <ushort, ushort>(); m_stateToClone = new Dictionary <InstanceState, Instance>(); m_InstanceID_origToClone = new Dictionary <InstanceID, InstanceID>(); matrix4x.SetTRS(center + moveDelta, Quaternion.AngleAxis(angleDelta * Mathf.Rad2Deg, Vector3.down), Vector3.one); // Clone nodes first foreach (InstanceState state in m_states) { if (state is NodeState) { Instance clone = state.instance.Clone(state, ref matrix4x, moveDelta.y, angleDelta, center, followTerrain, m_nodeOrigToClone, this); if (clone != null) { m_clones.Add(clone); m_stateToClone.Add(state, clone); m_InstanceID_origToClone.Add(state.instance.id, clone.id); m_origToCloneUpdate.Add(state.instance.id, clone.id); m_nodeOrigToClone.Add(state.instance.id.NetNode, clone.id.NetNode); } } } // Clone everything else except PO foreach (InstanceState state in m_states) { if (!(state is NodeState || state is ProcState)) { Instance clone = state.instance.Clone(state, ref matrix4x, moveDelta.y, angleDelta, center, followTerrain, m_nodeOrigToClone, this); if (clone == null) { Log.Debug($"Failed to clone {state}"); continue; } m_clones.Add(clone); m_stateToClone.Add(state, clone); m_InstanceID_origToClone.Add(state.instance.id, clone.id); m_origToCloneUpdate.Add(state.instance.id, clone.id); ; if (state is SegmentState segmentState) { MoveItTool.NS.SetSegmentModifiers(clone.id.NetSegment, segmentState); if (segmentState.LaneIDs != null) { // old version does not store lane ids var clonedLaneIds = MoveableSegment.GetLaneIds(clone.id.NetSegment); DebugUtils.AssertEq(clonedLaneIds.Count, segmentState.LaneIDs.Count, "clonedLaneIds.Count, segmentState.LaneIDs.Count"); for (int i = 0; i < clonedLaneIds.Count; ++i) { var lane0 = new InstanceID { NetLane = segmentState.LaneIDs[i] }; var lane = new InstanceID { NetLane = clonedLaneIds[i] }; // Log.Debug($"Mapping lane:{lane0.NetLane} to {lane.NetLane}"); m_InstanceID_origToClone.Add(lane0, lane); } } } } } // Clone PO foreach (InstanceState state in m_states) { if (state is ProcState) { _ = state.instance.Clone(state, ref matrix4x, moveDelta.y, angleDelta, center, followTerrain, m_nodeOrigToClone, this); } } if (m_origToClone != null) { Dictionary <Instance, Instance> toReplace = new Dictionary <Instance, Instance>(); foreach (Instance key in m_origToClone.Keys) { toReplace.Add(m_origToClone[key], m_origToCloneUpdate[key]); DebugUtils.Log("To replace: " + m_origToClone[key].id.RawData + " -> " + m_origToCloneUpdate[key].id.RawData); } ActionQueue.instance.ReplaceInstancesForward(toReplace); } m_origToClone = m_origToCloneUpdate; // Select clones selection = m_clones; MoveItTool.m_debugPanel.UpdatePanel(); UpdateArea(GetTotalBounds(false)); try { MoveItTool.UpdatePillarMap(); } catch (Exception e) { DebugUtils.Log("CloneActionBase.Do failed"); DebugUtils.LogException(e); } }
public void OnSettingsUI(UIHelperBase helper) { try { LocaleManager.eventLocaleChanged -= MoveItLoader.LocaleChanged; MoveItLoader.LocaleChanged(); LocaleManager.eventLocaleChanged += MoveItLoader.LocaleChanged; UIHelperBase group = helper.AddGroup(Name); UIPanel panel = ((UIHelper)group).self as UIPanel; UICheckBox checkBox = (UICheckBox)group.AddCheckbox(Str.options_AutoCloseToolbox, MoveItTool.autoCloseAlignTools.value, (b) => { MoveItTool.autoCloseAlignTools.value = b; if (UIMoreTools.MoreToolsPanel != null) { UIMoreTools.CloseMenu(); } }); checkBox.tooltip = Str.options_AutoCloseToolbox_Tooltip; group.AddSpace(10); checkBox = (UICheckBox)group.AddCheckbox(Str.options_PreferFastmove, MoveItTool.fastMove.value, (b) => { MoveItTool.fastMove.value = b; }); checkBox.tooltip = Str.options_PreferFastmove_Tooltip; group.AddSpace(10); checkBox = (UICheckBox)group.AddCheckbox(Str.options_UseCompass, MoveItTool.useCardinalMoves.value, (b) => { MoveItTool.useCardinalMoves.value = b; }); checkBox.tooltip = Str.options_UseCompass_Tooltip; group.AddSpace(10); checkBox = (UICheckBox)group.AddCheckbox(Str.options_RightClickCancel, MoveItTool.rmbCancelsCloning.value, (b) => { MoveItTool.rmbCancelsCloning.value = b; }); checkBox.tooltip = Str.options_RightClickCancel_Tooltip; group.AddSpace(10); checkBox = (UICheckBox)group.AddCheckbox(Str.options_AdvancedPillarControl, MoveItTool.advancedPillarControl.value, (b) => { MoveItTool.advancedPillarControl.value = b; }); checkBox.tooltip = Str.options_AdvancedPillarControl_Tooltip; group.AddSpace(10); checkBox = (UICheckBox)group.AddCheckbox(Str.options_AltForPillars, MoveItTool.altSelectNodeBuildings.value, (b) => { MoveItTool.altSelectNodeBuildings.value = b; }); group.AddSpace(10); group = helper.AddGroup(Str.options_ShortcutsGeneral); panel = ((UIHelper)group).self as UIPanel; group.AddSpace(10); ((UIPanel)((UIHelper)group).self).gameObject.AddComponent <OptionsKeymappingMain>(); group.AddSpace(10); group = helper.AddGroup(Str.options_ShortcutsToolbox); panel = ((UIHelper)group).self as UIPanel; group.AddSpace(10); ((UIPanel)((UIHelper)group).self).gameObject.AddComponent <OptionsKeymappingToolbox>(); group.AddSpace(10); group = helper.AddGroup(Str.options_ExtraOptions); panel = ((UIHelper)group).self as UIPanel; group.AddSpace(10); UIButton button = (UIButton)group.AddButton(Str.options_RemoveGhostNodes, MoveItTool.CleanGhostNodes); button.tooltip = Str.options_RemoveGhostNodes_Tooltip; group.AddSpace(10); button = (UIButton)group.AddButton(Str.options_ResetButtonPosition, () => { UIMoveItButton.savedX.value = -1000; UIMoveItButton.savedY.value = -1000; MoveItTool.instance?.m_button?.ResetPosition(); }); group.AddSpace(20); checkBox = (UICheckBox)group.AddCheckbox(Str.options_DisableDebugLogging, DebugUtils.hideDebugMessages.value, (b) => { DebugUtils.hideDebugMessages.value = b; }); checkBox.tooltip = Str.options_DisableDebugLogging_Tooltip; checkBox = (UICheckBox)group.AddCheckbox(Str.options_ShowDebugPanel, MoveItTool.showDebugPanel.value, (b) => { MoveItTool.showDebugPanel.value = b; if (MoveItTool.m_debugPanel != null) { MoveItTool.m_debugPanel.Visible(b); } }); checkBox.name = "MoveIt_DebugPanel"; group.AddSpace(5); UILabel nsLabel = panel.AddUIComponent <UILabel>(); nsLabel.name = "nsLabel"; nsLabel.text = NS_Manager.getVersionText(); group = helper.AddGroup(Str.options_ProceduralObjects); panel = ((UIHelper)group).self as UIPanel; UILabel poLabel = panel.AddUIComponent <UILabel>(); poLabel.name = "poLabel"; poLabel.text = PO_Manager.getVersionText(); // TODO add users of MoveITIntegration.dll here by name/description UILabel poWarning = panel.AddUIComponent <UILabel>(); poWarning.name = "poWarning"; poWarning.padding = new RectOffset(25, 0, 0, 15); poWarning.text = Str.options_PODeleteWarning; checkBox = (UICheckBox)group.AddCheckbox(Str.options_HidePODeletionWarning, !MoveItTool.POShowDeleteWarning.value, (b) => { MoveItTool.POShowDeleteWarning.value = !b; }); group.AddSpace(15); panel.gameObject.AddComponent <OptionsKeymappingPO>(); group.AddSpace(15); } catch (Exception e) { DebugUtils.Log("OnSettingsUI failed"); DebugUtils.LogException(e); } }
public void DoProcess() { Dictionary <Instance, float> instanceRotations = new Dictionary <Instance, float>(); Matrix4x4 matrix4x = default; foreach (Instance instance in m_clones) { if (instance.isValid) { InstanceState state = null; foreach (KeyValuePair <Instance, Instance> pair in m_origToClone) { if (pair.Value.id.RawData == instance.id.RawData) { if (pair.Value is MoveableSegment) { // Segments need original state because nodes move before clone's position is saved state = pair.Key.SaveToState(); } else { // Buildings need clone state to access correct subInstances. Others don't matter, but clone makes most sense state = pair.Value.SaveToState(); } break; } } if (state == null) { throw new NullReferenceException($"Original for cloned object not found."); } float faceDelta = getMirrorFacingDelta(state.angle, mirrorAngle); float posDelta = getMirrorPositionDelta(state.position, mirrorPivot, mirrorAngle); instanceRotations[instance] = faceDelta; matrix4x.SetTRS(mirrorPivot, Quaternion.AngleAxis(posDelta * Mathf.Rad2Deg, Vector3.down), Vector3.one); instance.Transform(state, ref matrix4x, 0f, faceDelta, mirrorPivot, followTerrain); } } // Mirror integrations foreach (var item in m_stateToClone) { foreach (var data in item.Key.IntegrationData) { try { CallIntegration(data.Key, item.Value.id, data.Value, m_InstanceID_origToClone, instanceRotations[item.Value], mirrorAngle); //data.Key.Mirror(item.Value.id, data.Value, m_InstanceID_origToClone); } catch (MissingMethodException e) { Log.Debug($"Failed to find Mirror method, a mod {data.Key.Name} needs updated.\n{e}"); } catch (Exception e) { InstanceID sourceInstanceID = item.Key.instance.id; InstanceID targetInstanceID = item.Value.id; Log.Error($"integration {data.Key} Failed to paste from " + $"{sourceInstanceID.Type}:{sourceInstanceID.Index} to {targetInstanceID.Type}:{targetInstanceID.Index}"); DebugUtils.LogException(e); } } } bool fast = MoveItTool.fastMove != Event.current.shift; UpdateArea(originalBounds, !fast || ((TypeMask & TypeMasks.Network) != TypeMasks.None)); UpdateArea(GetTotalBounds(false), !fast); }
public void OnSettingsUI(UIHelperBase helper) { try { UIHelperBase group = helper.AddGroup(Name); UIPanel panel = ((UIPanel)((UIHelper)group).self) as UIPanel; UICheckBox checkBox = (UICheckBox)group.AddCheckbox("Hide tips", MoveItTool.hideTips.value, (b) => { MoveItTool.hideTips.value = b; if (UITipsWindow.instance != null) { UITipsWindow.instance.isVisible = false; } }); checkBox.tooltip = "Check this if you don't want to see the tips."; group.AddSpace(10); checkBox = (UICheckBox)group.AddCheckbox("Auto-close Align Tools menu", MoveItTool.autoCloseAlignTools.value, (b) => { MoveItTool.autoCloseAlignTools.value = b; if (UIAlignTools.AlignToolsPanel != null) { UIAlignTools.AlignToolsPanel.isVisible = false; } }); checkBox.tooltip = "Check this to close the Align Tools menu after choosing a tool."; group.AddSpace(10); checkBox = (UICheckBox)group.AddCheckbox("Prefer fast, low-detail moving (hold Shift to temporarily switch)", MoveItTool.fastMove.value, (b) => { MoveItTool.fastMove.value = b; }); checkBox.tooltip = "Helps you position objects when your frame-rate is poor."; group.AddSpace(10); checkBox = (UICheckBox)group.AddCheckbox("Select pylons and pillars by holding Alt only", MoveItTool.altSelectNodeBuildings.value, (b) => { MoveItTool.altSelectNodeBuildings.value = b; }); group.AddSpace(10); checkBox = (UICheckBox)group.AddCheckbox("Use cardinal movements", MoveItTool.useCardinalMoves.value, (b) => { MoveItTool.useCardinalMoves.value = b; }); checkBox.tooltip = "If checked, Up will move in the North direction, Down is South, Left is West, Right is East."; group.AddSpace(10); checkBox = (UICheckBox)group.AddCheckbox("Right click cancels cloning", MoveItTool.rmbCancelsCloning.value, (b) => { MoveItTool.rmbCancelsCloning.value = b; }); checkBox.tooltip = "If checked, Right click will cancel cloning instead of rotating 45°."; group.AddSpace(15); ((UIPanel)((UIHelper)group).self).gameObject.AddComponent <OptionsKeymappingMain>(); group.AddSpace(15); UIButton button = (UIButton)group.AddButton("Remove Ghost Nodes", _cleanGhostNodes); button.tooltip = "Use this button when in-game to remove ghost nodes (nodes with no segments attached). Note: this will clear Move It's undo history!"; group.AddSpace(20); checkBox = (UICheckBox)group.AddCheckbox("Disable debug messages logging", DebugUtils.hideDebugMessages.value, (b) => { DebugUtils.hideDebugMessages.value = b; }); checkBox.tooltip = "If checked, debug messages won't be logged."; checkBox = (UICheckBox)group.AddCheckbox("Show Move It debug panel\n", MoveItTool.showDebugPanel.value, (b) => { MoveItTool.showDebugPanel.value = b; if (MoveItTool.m_debugPanel != null) { MoveItTool.m_debugPanel.Visible(b); } }); checkBox.name = "MoveIt_DebugPanel"; UILabel debugLabel = panel.AddUIComponent <UILabel>(); debugLabel.name = "debugLabel"; debugLabel.text = "Shows information about the last highlighted object. Slightly decreases\nperformance, do not enable unless you have a specific reason.\n "; group.AddSpace(5); if (!MoveItTool.HidePO) { group = helper.AddGroup("Procedural Objects"); panel = ((UIPanel)((UIHelper)group).self) as UIPanel; UILabel poLabel = panel.AddUIComponent <UILabel>(); poLabel.name = "poLabel"; poLabel.text = PO_Manager.getVersionText(); UILabel poWarning = panel.AddUIComponent <UILabel>(); poWarning.name = "poWarning"; poWarning.text = "Procedural Objects (PO) support is in beta. At present you can not clone PO objects, \n" + "redo Convert-to-PO actions or undo Bulldoze actions. This means if you delete PO objects \n" + "with Move It, they are immediately PERMANENTLY gone.\n "; checkBox = (UICheckBox)group.AddCheckbox("Limit Move It to only PO objects selected in PO", MoveItTool.POOnlySelectedAreVisible.value, (b) => { MoveItTool.POOnlySelectedAreVisible.value = b; if (MoveItTool.PO != null) { MoveItTool.PO.ToolEnabled(); } }); checkBox.tooltip = "If you have a lot of PO objects (250 or more), this is recommended."; checkBox = (UICheckBox)group.AddCheckbox("Highlight unselected visible PO objects", MoveItTool.POHighlightUnselected.value, (b) => { MoveItTool.POHighlightUnselected.value = b; if (MoveItTool.PO != null) { MoveItTool.PO.ToolEnabled(); } }); checkBox.tooltip = "Show a faded purple circle around PO objects that aren't selected."; group.AddSpace(15); panel.gameObject.AddComponent <OptionsKeymappingPO>(); group.AddSpace(15); } } catch (Exception e) { DebugUtils.Log("OnSettingsUI failed"); DebugUtils.LogException(e); } }
public void UndoImplementation(bool reset = false) { if (m_states == null) { return; } Dictionary <Instance, Instance> toReplace = new Dictionary <Instance, Instance>(); Dictionary <ushort, ushort> clonedNodes = new Dictionary <ushort, ushort>(); var stateToClone = new Dictionary <InstanceState, Instance>(); var InstanceID_origToClone = new Dictionary <InstanceID, InstanceID>(); Building[] buildingBuffer = BuildingManager.instance.m_buildings.m_buffer; // Recreate nodes foreach (InstanceState state in m_states) { try { if (state.instance.id.Type == InstanceType.NetNode) { Instance clone = state.instance.Clone(state, null); toReplace.Add(state.instance, clone); stateToClone.Add(state, clone); InstanceID_origToClone.Add(state.instance.id, clone.id); clonedNodes.Add(state.instance.id.NetNode, clone.id.NetNode); ActionQueue.instance.UpdateNodeIdInStateHistory(state.instance.id.NetNode, clone.id.NetNode); } } catch (Exception e) { Debug.Log($"Undo Bulldoze failed on {(state is InstanceState ? state.prefabName : "unknown")}\n{e}"); } } // Recreate everything except nodes and segments foreach (InstanceState state in m_states) { try { if (state.instance.id.Type == InstanceType.NetNode) { continue; } if (state.instance.id.Type == InstanceType.NetSegment) { continue; } if (state is ProcState) { continue; } Instance clone = state.instance.Clone(state, clonedNodes); toReplace.Add(state.instance, clone); stateToClone.Add(state, clone); InstanceID_origToClone.Add(state.instance.id, clone.id); if (state.instance.id.Type == InstanceType.Prop) { PropManager.instance.m_props.m_buffer[clone.id.Prop].FixedHeight = ((PropState)state).fixedHeight; } else if (state.instance.id.Type == InstanceType.Building) { // Add attached nodes to the clonedNode list so other segments reconnect BuildingState buildingState = state as BuildingState; List <ushort> origNodeIds = new List <ushort>(); MoveableBuilding cb = clone as MoveableBuilding; ushort cloneNodeId = ((Building)cb.data).m_netNode; if (reset) { ushort cloneId = cb.id.Building; buildingBuffer[cloneId].m_flags = buildingBuffer[cloneId].m_flags & ~Building.Flags.BurnedDown; buildingBuffer[cloneId].m_flags = buildingBuffer[cloneId].m_flags & ~Building.Flags.Collapsed; buildingBuffer[cloneId].m_flags = buildingBuffer[cloneId].m_flags & ~Building.Flags.Abandoned; buildingBuffer[cloneId].m_flags = buildingBuffer[cloneId].m_flags | Building.Flags.Active; Thread.Sleep(50); } if (cloneNodeId != 0) { int c = 0; foreach (InstanceState i in buildingState.subStates) { if (i is NodeState ns) { InstanceID instanceID = default; instanceID.RawData = ns.id; origNodeIds.Insert(c++, instanceID.NetNode); } } c = 0; while (cloneNodeId != 0) { ushort origNodeId = origNodeIds[c]; NetNode clonedAttachedNode = Singleton <NetManager> .instance.m_nodes.m_buffer[cloneNodeId]; if (clonedAttachedNode.Info.GetAI() is TransportLineAI) { cloneNodeId = clonedAttachedNode.m_nextBuildingNode; continue; } if (clonedNodes.ContainsKey(origNodeId)) { Debug.Log($"Node #{origNodeId} is already in clone list!"); } clonedNodes.Add(origNodeId, cloneNodeId); cloneNodeId = clonedAttachedNode.m_nextBuildingNode; if (++c > 32768) { CODebugBase <LogChannel> .Error(LogChannel.Core, "Nodes: Invalid list detected!\n" + Environment.StackTrace); break; } } } } } catch (Exception e) { Debug.Log($"Undo Bulldoze failed on {(state is InstanceState ? state.prefabName : "unknown")}\n{e}"); } } // Recreate segments foreach (InstanceState state in m_states) { try { if (state is SegmentState segmentState) { if (!clonedNodes.ContainsKey(segmentState.startNodeId)) { InstanceID instanceID = InstanceID.Empty; instanceID.NetNode = segmentState.startNodeId; // Don't clone if node is missing if (!((Instance)instanceID).isValid) { continue; } clonedNodes.Add(segmentState.startNodeId, segmentState.startNodeId); } if (!clonedNodes.ContainsKey(segmentState.endNodeId)) { InstanceID instanceID = InstanceID.Empty; instanceID.NetNode = segmentState.endNodeId; // Don't clone if node is missing if (!((Instance)instanceID).isValid) { continue; } clonedNodes.Add(segmentState.endNodeId, segmentState.endNodeId); } Instance clone = state.instance.Clone(state, clonedNodes); toReplace.Add(state.instance, clone); stateToClone.Add(state, clone); InstanceID_origToClone.Add(state.instance.id, clone.id); MoveItTool.NS.SetSegmentModifiers(clone.id.NetSegment, segmentState); } } catch (Exception e) { Debug.Log($"Undo Bulldoze failed on {(state is InstanceState ? state.prefabName : "unknown")}\n{e}"); } } // clone integrations. foreach (var item in stateToClone) { foreach (var data in item.Key.IntegrationData) { try { data.Key.Paste(item.Value.id, data.Value, InstanceID_origToClone); } catch (Exception e) { InstanceID sourceInstanceID = item.Key.instance.id; InstanceID targetInstanceID = item.Value.id; Debug.LogError($"integration {data.Key} Failed to paste from " + $"{sourceInstanceID.Type}:{sourceInstanceID.Index} to {targetInstanceID.Type}:{targetInstanceID.Index}"); DebugUtils.LogException(e); } } } if (replaceInstances) { ReplaceInstances(toReplace); ActionQueue.instance.ReplaceInstancesBackward(toReplace); selection = new HashSet <Instance>(); foreach (Instance i in m_oldSelection) { if (i is MoveableProc) { continue; } selection.Add(i); } MoveItTool.m_debugPanel.UpdatePanel(); } // Does not check MoveItTool.advancedPillarControl, because even if disabled now advancedPillarControl may have been active earlier in action queue foreach (KeyValuePair <BuildingState, BuildingState> pillarClone in pillarsOriginalToClone) { BuildingState originalState = pillarClone.Key; originalState.instance.isHidden = false; buildingBuffer[originalState.instance.id.Building].m_flags &= ~Building.Flags.Hidden; selection.Add(originalState.instance); m_states.Add(originalState); } if (pillarsOriginalToClone.Count > 0) { MoveItTool.UpdatePillarMap(); } }
public bool Export(string filename) { string path = Path.Combine(saveFolder, filename + ".xml"); try { HashSet <Instance> selection = CloneActionBase.GetCleanSelection(out Vector3 center); if (selection.Count == 0) { return(false); } bool includesPO = false; //foreach (Instance ins in selection) //{ // if (ins is MoveableProc) // { // includesPO = true; // break; // } //} Selection selectionState = new Selection { version = ModInfo.version, center = center, includesPO = includesPO, states = new InstanceState[selection.Count] }; int i = 0; foreach (Instance instance in selection) { selectionState.states[i++] = instance.SaveToState(); } Directory.CreateDirectory(saveFolder); //Log.Debug($"selectionState:{selectionState.states.Length}\n" + ObjectDumper.Dump(selectionState)); using (FileStream stream = new FileStream(path, FileMode.OpenOrCreate)) { stream.SetLength(0); // Emptying the file XmlSerializer xmlSerializer = new XmlSerializer(typeof(Selection)); XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); ns.Add("", ""); xmlSerializer.Serialize(stream, selectionState, ns); } } catch (Exception e) { DebugUtils.Log("Couldn't export selection"); DebugUtils.LogException(e); UIView.library.ShowModal <ExceptionPanel>("ExceptionPanel").SetMessage("Export failed", "The selection couldn't be exported to '" + path + "'\n\n" + e.Message, true); return(false); } return(true); }
public override void Do() { if (MoveItTool.POProcessing > 0) { return; } MoveItTool.instance.m_lastInstance = null; m_clones = new HashSet <Instance>(); m_origToCloneUpdate = new Dictionary <Instance, Instance>(); m_nodeOrigToClone = new Dictionary <ushort, ushort>(); var stateToClone = new Dictionary <InstanceState, Instance>(); var InstanceID_origToClone = new Dictionary <InstanceID, InstanceID>(); matrix4x.SetTRS(center + moveDelta, Quaternion.AngleAxis(angleDelta * Mathf.Rad2Deg, Vector3.down), Vector3.one); // Clone nodes first foreach (InstanceState state in m_states) { if (state is NodeState) { Instance clone = state.instance.Clone(state, ref matrix4x, moveDelta.y, angleDelta, center, followTerrain, m_nodeOrigToClone, this); if (clone != null) { m_clones.Add(clone); stateToClone.Add(state, clone); InstanceID_origToClone.Add(state.instance.id, clone.id); m_origToCloneUpdate.Add(state.instance.id, clone.id); m_nodeOrigToClone.Add(state.instance.id.NetNode, clone.id.NetNode); } } } // Clone everything else except PO foreach (InstanceState state in m_states) { if (!(state is NodeState || state is ProcState)) { Instance clone = state.instance.Clone(state, ref matrix4x, moveDelta.y, angleDelta, center, followTerrain, m_nodeOrigToClone, this); if (clone == null) { Debug.Log($"Failed to clone {state}"); continue; } m_clones.Add(clone); stateToClone.Add(state, clone); InstanceID_origToClone.Add(state.instance.id, clone.id); m_origToCloneUpdate.Add(state.instance.id, clone.id); ; if (state is SegmentState segmentState) { MoveItTool.NS.SetSegmentModifiers(clone.id.NetSegment, segmentState); if (segmentState.LaneIDs != null) { // old version does not store lane ids var clonedLaneIds = MoveableSegment.GetLaneIds(clone.id.NetSegment); DebugUtils.AssertEq(clonedLaneIds.Count, segmentState.LaneIDs.Count, "clonedLaneIds.Count, segmentState.LaneIDs.Count"); for (int i = 0; i < clonedLaneIds.Count; ++i) { var lane0 = new InstanceID { NetLane = segmentState.LaneIDs[i] }; var lane = new InstanceID { NetLane = clonedLaneIds[i] }; // Debug.Log($"Mapping lane:{lane0.NetLane} to {lane.NetLane}"); InstanceID_origToClone.Add(lane0, lane); } } } } } // backward compatibility. // Clone NodeController after segments have been added. foreach (var item in stateToClone) { if (item.Key is NodeState nodeState) { Instance clone = item.Value; ushort nodeID = clone.id.NetNode; MoveItTool.NodeController.PasteNode(nodeID, nodeState); } } // Clone TMPE rules // TODO remove when TMPE switches to integration foreach (var state in m_states) { if (state is NodeState nodeState) { MoveItTool.TMPE.Paste(nodeState.TMPE_NodeRecord, InstanceID_origToClone); } else if (state is SegmentState segmentState) { MoveItTool.TMPE.Paste(segmentState.TMPE_SegmentRecord, InstanceID_origToClone); MoveItTool.TMPE.Paste(segmentState.TMPE_SegmentStartRecord, InstanceID_origToClone); MoveItTool.TMPE.Paste(segmentState.TMPE_SegmentEndRecord, InstanceID_origToClone); } } // Clone PO foreach (InstanceState state in m_states) { if (state is ProcState) { _ = state.instance.Clone(state, ref matrix4x, moveDelta.y, angleDelta, center, followTerrain, m_nodeOrigToClone, this); } } // clone integrations. foreach (var item in stateToClone) { foreach (var data in item.Key.IntegrationData) { try { data.Key.Paste(item.Value.id, data.Value, InstanceID_origToClone); } catch (Exception e) { InstanceID sourceInstanceID = item.Key.instance.id; InstanceID targetInstanceID = item.Value.id; Debug.LogError($"integration {data.Key} Failed to paste from " + $"{sourceInstanceID.Type}:{sourceInstanceID.Index} to {targetInstanceID.Type}:{targetInstanceID.Index}"); DebugUtils.LogException(e); } } } if (m_origToClone != null) { Dictionary <Instance, Instance> toReplace = new Dictionary <Instance, Instance>(); foreach (Instance key in m_origToClone.Keys) { toReplace.Add(m_origToClone[key], m_origToCloneUpdate[key]); DebugUtils.Log("To replace: " + m_origToClone[key].id.RawData + " -> " + m_origToCloneUpdate[key].id.RawData); } ActionQueue.instance.ReplaceInstancesForward(toReplace); } m_origToClone = m_origToCloneUpdate; // Select clones selection = m_clones; MoveItTool.m_debugPanel.UpdatePanel(); UpdateArea(GetTotalBounds(false)); MoveItTool.UpdatePillarMap(); }