diff --git a/Quad64.csproj b/Quad64.csproj index 4b2da88..a570548 100644 --- a/Quad64.csproj +++ b/Quad64.csproj @@ -302,6 +302,7 @@ Always + @@ -351,11 +352,11 @@ - - \ No newline at end of file + diff --git a/src/Forms/MainForm.cs b/src/Forms/MainForm.cs index efd101a..c42a12e 100644 --- a/src/Forms/MainForm.cs +++ b/src/Forms/MainForm.cs @@ -13,6 +13,7 @@ using System.Runtime.InteropServices; using Quad64.src.Forms.ToolStripRenderer; using System.IO; +using Newtonsoft.Json; namespace Quad64 { @@ -97,9 +98,26 @@ public MainForm() myTimer.Enabled = false; cameraMode.SelectedIndex = 0; menuStrip1.Renderer = new ToolStripProfessionalRenderer(new CustomToolStripColorTable()); + + this.KeyDown += Handle_KeyDown; } // New functions for MainForm.cs + void Handle_KeyDown( object sender, KeyEventArgs e ) + { + switch (e.KeyCode) + { + case Keys.F1: SaveSelectedObjectsToFile(1); break; + case Keys.F2: SaveSelectedObjectsToFile(2); break; + case Keys.F3: SaveSelectedObjectsToFile(3); break; + case Keys.F4: SaveSelectedObjectsToFile(4); break; + case Keys.F5: LoadObjectsFromFile(1); break; + case Keys.F6: LoadObjectsFromFile(2); break; + case Keys.F7: LoadObjectsFromFile(3); break; + case Keys.F8: LoadObjectsFromFile(4); break; + } + } + private void SetColorsForMenuStripItem(ref ToolStripItemCollection items) { for (int i = 0; i < items.Count; i++) @@ -2290,7 +2308,89 @@ public static void forceGC() { GC.Collect(); GC.WaitForPendingFinalizers(); - SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1); + //SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1); + } + + private void SaveSelectedObjectsToFile( int slot ) + { + List selectedObjects = new List(); + + if( Globals.isMultiSelected ) + { + if( + Globals.isMultiSelectedFromMultipleLists || + Globals.multi_selected_nodes[0].Count < 1 + ) return; + + foreach( int index in Globals.multi_selected_nodes[0] ) + { + selectedObjects.Add(level.getCurrentArea().Objects[index].Data); + } + } else + { + if ( Globals.list_selected != 0 || Globals.item_selected < 0 ) return; + + selectedObjects.Add(level.getCurrentArea().Objects[Globals.item_selected].Data); + } + + using( StreamWriter tempFile = new StreamWriter( "./data/profiles/default/saved-objects-" + slot.ToString() + ".json" ) ) + { + tempFile.WriteLine(JsonConvert.SerializeObject(selectedObjects)); + } } + + private void LoadObjectsFromFile( int slot ) + { + ObjectData[] objectsToLoad; + try { + using( StreamReader tempFile = new StreamReader( "./data/profiles/default/saved-objects-" + slot.ToString() + ".json" ) ) + { + string json = tempFile.ReadLine(); + objectsToLoad = JsonConvert.DeserializeObject( json ); + } + } catch( Exception ex ) + { + Console.Error.WriteLine( ex ); + return; + } + + List objects = level.getCurrentArea().Objects; + if( Globals.isMultiSelected ) + { + if ( Globals.isMultiSelectedFromMultipleLists || + Globals.multi_selected_nodes[0].Count != objectsToLoad.Length + ) return; + + for( int i = 0; i < objectsToLoad.Length; i++) + { + Object3D objectToUpdate = objects[Globals.multi_selected_nodes[0][i]]; + objectToUpdate.ReplaceData(objectsToLoad[i]); + objectToUpdate.updateROMData(); + } + } else + { + if ( + Globals.list_selected != 0 || + Globals.item_selected < 0 || + objectsToLoad.Length < 1 + ) return; + + int j = 0; + for( int i = Globals.item_selected; i < level.getCurrentArea().Objects.Count && j < objectsToLoad.Length; i++ ) + { + objects[i].ReplaceData(objectsToLoad[j]); + objects[i].updateROMData(); + j++; + } + + } + refreshObjectsInList(); + + glControl1.Invalidate(); + propertyGrid1.Refresh(); + glControl1.Update(); + Globals.needToSave = true; + } + } } diff --git a/src/JSON/ObjectData.cs b/src/JSON/ObjectData.cs new file mode 100644 index 0000000..ce6cb52 --- /dev/null +++ b/src/JSON/ObjectData.cs @@ -0,0 +1,26 @@ +using Newtonsoft.Json; + +namespace Quad64.src.JSON +{ + [JsonObject] + internal sealed class ObjectData + { + + public byte ModelId { get; set; } + public uint Behaviour { get; set; } + public byte[] BehaviourArgs { get; set; } = new byte[4]; + + public bool AllActs { get; set; } + public bool[] Acts { get; set; } = new bool[6]; + + public short X { get; set; } + public short Y { get; set; } + public short Z { get; set; } + + public short RX { get; set; } + public short RY { get; set; } + public short RZ { get; set; } + + } + +} diff --git a/src/LevelInfo/Object3D.cs b/src/LevelInfo/Object3D.cs index dfd2afa..296d9fb 100644 --- a/src/LevelInfo/Object3D.cs +++ b/src/LevelInfo/Object3D.cs @@ -35,13 +35,38 @@ public enum FLAGS { public enum FROM_LS_CMD { CMD_24, CMD_39, CMD_2E_8, CMD_2E_10, CMD_2E_12 } - + private const ushort NUM_OF_CATERGORIES = 7; bool isBehaviorReadOnly = false; bool isModelIDReadOnly = false; bool isTempHidden = false; + public Object3D(){ + m_data = new ObjectData(); + } + + public Object3D( + string address, + ObjectData objectData + ) + { + m_data = objectData; + Address = address; + UpdateProperties(); + } + + public void ReplaceData( ObjectData newData ) + { + m_data = newData; + UpdateProperties(); + } + + private ObjectData m_data = new ObjectData(); + + [Browsable(false)] + public ObjectData Data { get => m_data; } + [Browsable(false)] public bool canEditModelID { get { return !isModelIDReadOnly; } } [Browsable(false)] @@ -63,14 +88,13 @@ public enum FROM_LS_CMD { [DisplayName("Address")] [ReadOnly(true)] public string Address { get; set; } - - private byte modelID = 0; + [CustomSortedCategory("Model", 2, NUM_OF_CATERGORIES)] [Browsable(true)] [Description("Model identifer used by the object")] [DisplayName("Model ID")] [TypeConverter(typeof(HexNumberTypeConverter))] - public byte ModelID { get { return modelID; } set { modelID = value; } } + public byte ModelID { get { return m_data.ModelId; } set { m_data.ModelId = value; } } [CustomSortedCategory("Model", 2, NUM_OF_CATERGORIES)] [Browsable(false)] @@ -78,59 +102,59 @@ public enum FROM_LS_CMD { [DisplayName("Model ID")] [TypeConverter(typeof(HexNumberTypeConverter))] [ReadOnly(true)] - public byte ModelID_ReadOnly { get { return modelID; } } + public byte ModelID_ReadOnly { get { return m_data.ModelId; } } - private short _xPos, _yPos, _zPos; [CustomSortedCategory("Position", 3, NUM_OF_CATERGORIES)] [Browsable(true)] [DisplayName("X")] [TypeConverter(typeof(HexNumberTypeConverter))] - public short xPos { get { return _xPos; } set { _xPos = value; } } + public short xPos { get { return m_data.X; } set { m_data.X = value; } } [CustomSortedCategory("Position", 3, NUM_OF_CATERGORIES)] [Browsable(true)] [DisplayName("Y")] [TypeConverter(typeof(HexNumberTypeConverter))] - public short yPos { get { return _yPos; } set { _yPos = value; } } + public short yPos { get { return m_data.Y; } set { m_data.Y = value; } } [CustomSortedCategory("Position", 3, NUM_OF_CATERGORIES)] [Browsable(true)] [DisplayName("Z")] [TypeConverter(typeof(HexNumberTypeConverter))] - public short zPos { get { return _zPos; } set { _zPos = value; } } - - private short _xRot, _yRot, _zRot; + public short zPos { get { return m_data.Z; } set { m_data.Z = value; } } + [CustomSortedCategory("Rotation", 4, NUM_OF_CATERGORIES)] [Browsable(true)] [DisplayName("RX")] [TypeConverter(typeof(HexNumberTypeConverter))] - public short xRot { get { return _xRot; } set { _xRot = value; } } + public short xRot { get { return m_data.RX; } set { m_data.RX = value; } } [CustomSortedCategory("Rotation", 4, NUM_OF_CATERGORIES)] [Browsable(true)] [DisplayName("RY")] [TypeConverter(typeof(HexNumberTypeConverter))] - public short yRot { get { return _yRot; } set { _yRot = value; } } + public short yRot { get { return m_data.RY; } set { m_data.RY = value; } } [CustomSortedCategory("Rotation", 4, NUM_OF_CATERGORIES)] [Browsable(true)] [DisplayName("RZ")] [TypeConverter(typeof(HexNumberTypeConverter))] - public short zRot { get { return _zRot; } set { _zRot = value; } } + public short zRot { get { return m_data.RZ; } set { m_data.RZ = value; } } [CustomSortedCategory("Behavior", 5, NUM_OF_CATERGORIES)] [Browsable(true)] [DisplayName("Behavior")] - //[ReadOnly(true)] - public string Behavior { get; set; } + public string Behavior { + get => "0x" + m_data.Behaviour.ToString("X8"); + set { m_data.Behaviour = uint.Parse(value.Substring(2), NumberStyles.HexNumber); } + } [CustomSortedCategory("Behavior", 5, NUM_OF_CATERGORIES)] [Browsable(false)] [DisplayName("Behavior")] [ReadOnly(true)] - public string Behavior_ReadOnly { get; set; } - + public string Behavior_ReadOnly => this.Behavior; + [CustomSortedCategory("Behavior", 5, NUM_OF_CATERGORIES)] [Browsable(true)] [DisplayName("Beh. Name")] [ReadOnly(true)] - public string Behavior_Name { get; set; } + public string Behavior_Name => Globals.getBehaviorNameEntryFromSegAddress(m_data.Behaviour).Name; // default names private const string BP1DNAME = "B.Param 1"; @@ -143,57 +167,106 @@ public enum FROM_LS_CMD { [DisplayName(BP1DNAME)] [TypeConverter(typeof(HexNumberTypeConverter))] [Description("")] - public byte BehaviorParameter1 { get; set; } + public byte BehaviorParameter1 + { + get { return m_data.BehaviourArgs[0]; } + set { m_data.BehaviourArgs[0] = value; } + } [CustomSortedCategory("Behavior", 5, NUM_OF_CATERGORIES)] [Browsable(true)] [DisplayName(BP2DNAME)] [TypeConverter(typeof(HexNumberTypeConverter))] [Description("")] - public byte BehaviorParameter2 { get; set; } + public byte BehaviorParameter2 + { + get { return m_data.BehaviourArgs[1]; } + set { m_data.BehaviourArgs[1] = value; } + } [CustomSortedCategory("Behavior", 5, NUM_OF_CATERGORIES)] [Browsable(true)] [DisplayName(BP3DNAME)] [TypeConverter(typeof(HexNumberTypeConverter))] [Description("")] - public byte BehaviorParameter3 { get; set; } + public byte BehaviorParameter3 + { + get { return m_data.BehaviourArgs[2]; } + set { m_data.BehaviourArgs[2] = value; } + } [CustomSortedCategory("Behavior", 5, NUM_OF_CATERGORIES)] [Browsable(true)] [DisplayName(BP4DNAME)] [TypeConverter(typeof(HexNumberTypeConverter))] [Description("")] - public byte BehaviorParameter4 { get; set; } + public byte BehaviorParameter4 + { + get { return m_data.BehaviourArgs[3]; } + set { m_data.BehaviourArgs[3] = value; } + } [CustomSortedCategory("Acts", 6, NUM_OF_CATERGORIES)] [Browsable(true)] [DisplayName("All Acts")] - public bool AllActs { get; set; } + public bool AllActs + { + get { return m_data.AllActs; } + set { m_data.AllActs = value; } + } [CustomSortedCategory("Acts", 6, NUM_OF_CATERGORIES)] [Browsable(true)] [DisplayName("Act 1")] - public bool Act1 { get; set; } + public bool Act1 + { + get { return m_data.Acts[0]; } + set { m_data.Acts[0] = value; } + } + [CustomSortedCategory("Acts", 6, NUM_OF_CATERGORIES)] [Browsable(true)] [DisplayName("Act 2")] - public bool Act2 { get; set; } + public bool Act2 + { + get { return m_data.Acts[1]; } + set { m_data.Acts[1] = value; } + } + [CustomSortedCategory("Acts", 6, NUM_OF_CATERGORIES)] [Browsable(true)] [DisplayName("Act 3")] - public bool Act3 { get; set; } + public bool Act3 + { + get { return m_data.Acts[2]; } + set { m_data.Acts[2] = value; } + } + [CustomSortedCategory("Acts", 6, NUM_OF_CATERGORIES)] [Browsable(true)] [DisplayName("Act 4")] - public bool Act4 { get; set; } + public bool Act4 + { + get { return m_data.Acts[3]; } + set { m_data.Acts[3] = value; } + } + [CustomSortedCategory("Acts", 6, NUM_OF_CATERGORIES)] [Browsable(true)] [DisplayName("Act 5")] - public bool Act5 { get; set; } + public bool Act5 + { + get { return m_data.Acts[4]; } + set { m_data.Acts[4] = value; } + } + [CustomSortedCategory("Acts", 6, NUM_OF_CATERGORIES)] [Browsable(true)] [DisplayName("Act 6")] - public bool Act6 { get; set; } + public bool Act6 + { + get { return m_data.Acts[5]; } + set { m_data.Acts[5] = value; } + } private ulong Flags = 0; @@ -239,27 +312,10 @@ public byte getActMask() public void setBehaviorFromAddress(uint address) { - Behavior = "0x"+address.ToString("X8"); - Behavior_ReadOnly = Behavior; - Behavior_Name = Globals.getBehaviorNameEntryFromSegAddress(address).Name; + m_data.Behaviour = address; } - public uint getBehaviorAddress() - { - uint value = 0; - bool succeded = false; - if(Behavior.ToUpper().StartsWith("0X")) - succeded = uint.TryParse(Behavior.Substring(2), NumberStyles.HexNumber, new CultureInfo("en-US"), out value); - else if (Behavior.ToUpper().StartsWith("$")) - succeded = uint.TryParse(Behavior.Substring(1), NumberStyles.HexNumber, new CultureInfo("en-US"), out value); - else - succeded = uint.TryParse(Behavior, out value); - - if (succeded) - return value; - else - return 0; - } + public uint getBehaviorAddress() => m_data.Behaviour; public void updateROMData() { @@ -619,7 +675,7 @@ public string getObjectComboName() } objectComboEntry = null; - Title = "Undefined Combo (0x" + modelID.ToString("X2") + ", 0x" + behaviorAddr.ToString("X8") + ")"; + Title = "Undefined Combo (0x" + m_data.ModelId.ToString("X2") + ", 0x" + behaviorAddr.ToString("X8") + ")"; return Title; }