From f84b51d1c123608dc09d953ec6f39480adf060b9 Mon Sep 17 00:00:00 2001 From: dexy Date: Fri, 14 Dec 2018 21:23:05 +1100 Subject: [PATCH] Save RSC Meta files to RPF directly from Meta Editor form --- .../GameFiles/MetaTypes/MetaNames.cs | 2 + .../GameFiles/MetaTypes/MetaXml.cs | 11 ++ .../GameFiles/MetaTypes/PsoTypes.cs | 12 +- ExploreForm.cs | 55 ++++-- Forms/MetaForm.cs | 172 +++++++++++++++++- 5 files changed, 233 insertions(+), 19 deletions(-) diff --git a/CodeWalker.Core/GameFiles/MetaTypes/MetaNames.cs b/CodeWalker.Core/GameFiles/MetaTypes/MetaNames.cs index af51960..33f366d 100644 --- a/CodeWalker.Core/GameFiles/MetaTypes/MetaNames.cs +++ b/CodeWalker.Core/GameFiles/MetaTypes/MetaNames.cs @@ -3426,6 +3426,8 @@ namespace CodeWalker.GameFiles LODLights = 1326371921, BoxOccluder = 975711773, OccludeModel = 2741784237, + sirenLight = 4091688452, + sirenCorona = 472016577, diff --git a/CodeWalker.Core/GameFiles/MetaTypes/MetaXml.cs b/CodeWalker.Core/GameFiles/MetaTypes/MetaXml.cs index 18613a1..b40c0ef 100644 --- a/CodeWalker.Core/GameFiles/MetaTypes/MetaXml.cs +++ b/CodeWalker.Core/GameFiles/MetaTypes/MetaXml.cs @@ -1763,4 +1763,15 @@ namespace CodeWalker.GameFiles } + + + public enum MetaFormat + { + XML = 0, + RSC = 1, + PSO = 2, + RBF = 3, + CacheFile = 4, + } + } diff --git a/CodeWalker.Core/GameFiles/MetaTypes/PsoTypes.cs b/CodeWalker.Core/GameFiles/MetaTypes/PsoTypes.cs index a534dba..83a5c58 100644 --- a/CodeWalker.Core/GameFiles/MetaTypes/PsoTypes.cs +++ b/CodeWalker.Core/GameFiles/MetaTypes/PsoTypes.cs @@ -487,18 +487,18 @@ namespace CodeWalker.GameFiles new PsoStructureEntryInfo(MetaName.leftTailLightMultiples, PsoDataType.UByte, 122, 0, 0), new PsoStructureEntryInfo(MetaName.rightTailLightMultiples, PsoDataType.UByte, 123, 0, 0), new PsoStructureEntryInfo(MetaName.useRealLights, PsoDataType.Bool, 124, 0, 0), - new PsoStructureEntryInfo(MetaName.ARRAYINFO, PsoDataType.Structure, 0, 0, (MetaName)4091688452), + new PsoStructureEntryInfo(MetaName.ARRAYINFO, PsoDataType.Structure, 0, 0, MetaName.sirenLight), new PsoStructureEntryInfo((MetaName)2047330294, PsoDataType.Array, 128, 1, (MetaName)1310739) ); case (MetaName)188820339: return new PsoStructureInfo((MetaName)188820339, 0, 0, 16, new PsoStructureEntryInfo(MetaName.sequencer, PsoDataType.UInt, 8, 0, 0) ); - case (MetaName)4091688452: - return new PsoStructureInfo((MetaName)4091688452, 0, 0, 112, + case MetaName.sirenLight: + return new PsoStructureInfo(MetaName.sirenLight, 0, 0, 112, new PsoStructureEntryInfo(MetaName.rotation, PsoDataType.Structure, 8, 0, (MetaName)1356743507), new PsoStructureEntryInfo(MetaName.flashiness, PsoDataType.Structure, 40, 0, (MetaName)1356743507), - new PsoStructureEntryInfo(MetaName.corona, PsoDataType.Structure, 72, 0, (MetaName)472016577), + new PsoStructureEntryInfo(MetaName.corona, PsoDataType.Structure, 72, 0, MetaName.sirenCorona), new PsoStructureEntryInfo(MetaName.color, PsoDataType.UInt, 96, 1, 0), new PsoStructureEntryInfo(MetaName.intensity, PsoDataType.Float, 100, 0, 0), new PsoStructureEntryInfo(MetaName.lightGroup, PsoDataType.UByte, 104, 0, 0), @@ -520,8 +520,8 @@ namespace CodeWalker.GameFiles new PsoStructureEntryInfo(MetaName.direction, PsoDataType.Bool, 25, 0, 0), new PsoStructureEntryInfo(MetaName.syncToBpm, PsoDataType.Bool, 26, 0, 0) ); - case (MetaName)472016577: - return new PsoStructureInfo((MetaName)472016577, 0, 0, 24, + case MetaName.sirenCorona: + return new PsoStructureInfo(MetaName.sirenCorona, 0, 0, 24, new PsoStructureEntryInfo(MetaName.intensity, PsoDataType.Float, 8, 0, 0), new PsoStructureEntryInfo(MetaName.size, PsoDataType.Float, 12, 0, 0), new PsoStructureEntryInfo(MetaName.pull, PsoDataType.Float, 16, 0, 0), diff --git a/ExploreForm.cs b/ExploreForm.cs index 352e3b9..812da28 100644 --- a/ExploreForm.cs +++ b/ExploreForm.cs @@ -44,7 +44,7 @@ namespace CodeWalker private GameFileCache FileCache { get; set; } = GameFileCacheFactory.Create(); private object FileCacheSyncRoot = new object(); - private bool EditMode = false; + public bool EditMode { get; private set; } = false; public ThemeBase Theme { get; private set; } @@ -905,7 +905,6 @@ namespace CodeWalker RecurseAddMainTreeViewNodes(f, CurrentFolder.TreeNode); CurrentFolder.AddChild(f); - CurrentFolder.ListItems = null; RefreshMainListView(); } @@ -1053,11 +1052,23 @@ namespace CodeWalker } } + public void RefreshMainListViewInvoke() + { + if (InvokeRequired) + { + BeginInvoke(new Action(() => { RefreshMainListView(); })); + } + else + { + RefreshMainListView(); + } + } private void RefreshMainListView() { MainListView.VirtualListSize = 0; if (CurrentFolder != null) { + CurrentFolder.ListItems = null; //makes sure to rebuild the current files list CurrentFiles = CurrentFolder.GetListItems(); foreach (var file in CurrentFiles) //cache all the data for use by the list view. @@ -1314,6 +1325,13 @@ namespace CodeWalker try #endif { + var exform = FindExistingForm(item?.File); + if (exform != null) + { + exform.Focus(); + return; + } + byte[] data = null; string name = ""; string path = ""; @@ -1469,35 +1487,35 @@ namespace CodeWalker private void ViewYmt(string name, string path, byte[] data, RpfFileEntry e) { var ymt = RpfFile.GetFile(e, data); - MetaForm f = new MetaForm(); + MetaForm f = new MetaForm(this); f.Show(); f.LoadMeta(ymt); } private void ViewYmf(string name, string path, byte[] data, RpfFileEntry e) { var ymf = RpfFile.GetFile(e, data); - MetaForm f = new MetaForm(); + MetaForm f = new MetaForm(this); f.Show(); f.LoadMeta(ymf); } private void ViewYmap(string name, string path, byte[] data, RpfFileEntry e) { var ymap = RpfFile.GetFile(e, data); - MetaForm f = new MetaForm(); + MetaForm f = new MetaForm(this); f.Show(); f.LoadMeta(ymap); } private void ViewYtyp(string name, string path, byte[] data, RpfFileEntry e) { var ytyp = RpfFile.GetFile(e, data); - MetaForm f = new MetaForm(); + MetaForm f = new MetaForm(this); f.Show(); f.LoadMeta(ytyp); } private void ViewJPso(string name, string path, byte[] data, RpfFileEntry e) { var pso = RpfFile.GetFile(e, data); - MetaForm f = new MetaForm(); + MetaForm f = new MetaForm(this); f.Show(); f.LoadMeta(pso); } @@ -1538,7 +1556,7 @@ namespace CodeWalker private void ViewCut(string name, string path, byte[] data, RpfFileEntry e) { var cut = RpfFile.GetFile(e, data); - MetaForm f = new MetaForm(); + MetaForm f = new MetaForm(this); f.Show(); f.LoadMeta(cut); } @@ -1594,12 +1612,29 @@ namespace CodeWalker private void ViewCacheDat(string name, string path, byte[] data, RpfFileEntry e) { var cachedat = RpfFile.GetFile(e, data); - MetaForm f = new MetaForm(); + MetaForm f = new MetaForm(this); f.Show(); f.LoadMeta(cachedat); } + private Form FindExistingForm(RpfFileEntry e) + { + if (e == null) return null; + var allforms = Application.OpenForms; + var path = e.Path.ToLowerInvariant(); + foreach (var form in allforms) + { + var metaform = form as MetaForm; + if (metaform?.rpfFileEntry == e) return metaform; + if (metaform?.rpfFileEntry?.Path?.ToLowerInvariant() == path) + return metaform; //need to test the path as well since the file entry may have been replaced by a new version..! + + } + return null; + } + + private void ShowTreeContextMenu(TreeNode n, Point p) { var f = n?.Tag as MainTreeFolder; @@ -2265,7 +2300,6 @@ namespace CodeWalker } - CurrentFolder.ListItems = null; RefreshMainListView(); } @@ -2407,7 +2441,6 @@ namespace CodeWalker } } - CurrentFolder.ListItems = null; RefreshMainListView(); } private void CopySelected() diff --git a/Forms/MetaForm.cs b/Forms/MetaForm.cs index 17e8fe2..87848f9 100644 --- a/Forms/MetaForm.cs +++ b/Forms/MetaForm.cs @@ -11,6 +11,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; +using System.Xml; namespace CodeWalker.Forms { @@ -44,8 +45,15 @@ namespace CodeWalker.Forms private bool DelayHighlight = false; - public MetaForm() + private ExploreForm exploreForm = null; + public RpfFileEntry rpfFileEntry { get; private set; } = null; + private MetaFormat metaFormat = MetaFormat.XML; + + + public MetaForm(ExploreForm owner) { + exploreForm = owner; + InitializeComponent(); } @@ -119,14 +127,18 @@ namespace CodeWalker.Forms Xml = ""; RawPropertyGrid.SelectedObject = null; modified = false; + rpfFileEntry = null; return true; } private void NewDocument() { - if (!CloseDocument()) return; //same thing really.. + if (!CloseDocument()) return; FileName = "New.xml"; + rpfFileEntry = null; + + //TODO: decide XML/RSC/PSO/RBF format..? } private void OpenDocument() { @@ -144,9 +156,32 @@ namespace CodeWalker.Forms FilePath = fn; FileName = new FileInfo(fn).Name; RawPropertyGrid.SelectedObject = null; + rpfFileEntry = null; + + //TODO: open RSC/PSO/RBF..? } private void SaveDocument(bool saveAs = false) { + if ((metaFormat != MetaFormat.XML) && (saveAs == false)) + { + var doc = new XmlDocument(); + try + { + doc.LoadXml(xml); + } + catch (Exception ex) + { + MessageBox.Show("There's something wrong with your XML document:\r\n" + ex.Message, "Unable to parse XML"); + return; + } + if (SaveMeta(doc)) + { + return; + } + //if Meta saving failed for whatever reason, fallback to saving the XML in the filesystem. + saveAs = true; + } + if (string.IsNullOrEmpty(FileName)) saveAs = true; if (string.IsNullOrEmpty(FilePath)) saveAs = true; else if ((FilePath.ToLowerInvariant().StartsWith(GTAFolder.CurrentGTAFolder.ToLowerInvariant()))) saveAs = true; @@ -171,6 +206,7 @@ namespace CodeWalker.Forms modified = false; FilePath = fn; FileName = new FileInfo(fn).Name; + metaFormat = MetaFormat.XML; } @@ -181,7 +217,15 @@ namespace CodeWalker.Forms Xml = MetaXml.GetXml(ymt, out fn); FileName = fn; RawPropertyGrid.SelectedObject = ymt; + rpfFileEntry = ymt?.RpfFileEntry; modified = false; + metaFormat = MetaFormat.XML; + if (ymt != null) + { + if (ymt.Meta != null) metaFormat = MetaFormat.RSC; + if (ymt.Pso != null) metaFormat = MetaFormat.PSO; + if (ymt.Rbf != null) metaFormat = MetaFormat.RBF; + } } public void LoadMeta(YmfFile ymf) { @@ -189,7 +233,15 @@ namespace CodeWalker.Forms Xml = MetaXml.GetXml(ymf, out fn); FileName = fn; RawPropertyGrid.SelectedObject = ymf; + rpfFileEntry = ymf?.FileEntry; modified = false; + metaFormat = MetaFormat.XML; + if (ymf != null) + { + if (ymf.Meta != null) metaFormat = MetaFormat.RSC; + if (ymf.Pso != null) metaFormat = MetaFormat.PSO; + if (ymf.Rbf != null) metaFormat = MetaFormat.RBF; + } } public void LoadMeta(YmapFile ymap) { @@ -197,7 +249,15 @@ namespace CodeWalker.Forms Xml = MetaXml.GetXml(ymap, out fn); FileName = fn; RawPropertyGrid.SelectedObject = ymap; + rpfFileEntry = ymap?.RpfFileEntry; modified = false; + metaFormat = MetaFormat.XML; + if (ymap != null) + { + if (ymap.Meta != null) metaFormat = MetaFormat.RSC; + if (ymap.Pso != null) metaFormat = MetaFormat.PSO; + if (ymap.Rbf != null) metaFormat = MetaFormat.RBF; + } } public void LoadMeta(YtypFile ytyp) { @@ -205,7 +265,15 @@ namespace CodeWalker.Forms Xml = MetaXml.GetXml(ytyp, out fn); FileName = fn; RawPropertyGrid.SelectedObject = ytyp; + rpfFileEntry = ytyp?.RpfFileEntry; modified = false; + metaFormat = MetaFormat.XML; + if (ytyp != null) + { + if (ytyp.Meta != null) metaFormat = MetaFormat.RSC; + if (ytyp.Pso != null) metaFormat = MetaFormat.PSO; + if (ytyp.Rbf != null) metaFormat = MetaFormat.RBF; + } } public void LoadMeta(JPsoFile jpso) { @@ -213,7 +281,13 @@ namespace CodeWalker.Forms Xml = MetaXml.GetXml(jpso, out fn); FileName = fn; RawPropertyGrid.SelectedObject = jpso; + rpfFileEntry = jpso?.FileEntry; modified = false; + metaFormat = MetaFormat.XML; + if (jpso != null) + { + if (jpso.Pso != null) metaFormat = MetaFormat.PSO; + } } public void LoadMeta(CutFile cut) { @@ -221,7 +295,13 @@ namespace CodeWalker.Forms Xml = MetaXml.GetXml(cut, out fn); FileName = fn; RawPropertyGrid.SelectedObject = cut; + rpfFileEntry = cut?.FileEntry; modified = false; + metaFormat = MetaFormat.XML; + if (cut != null) + { + if (cut.Pso != null) metaFormat = MetaFormat.PSO; + } } public void LoadMeta(CacheDatFile cachedat) { @@ -229,11 +309,99 @@ namespace CodeWalker.Forms Xml = cachedat.GetXml(); FileName = fn; RawPropertyGrid.SelectedObject = cachedat; + rpfFileEntry = cachedat?.FileEntry; modified = false; + metaFormat = MetaFormat.XML; + if (cachedat?.FileEntry != null) + { + metaFormat = MetaFormat.CacheFile; + } } + public bool SaveMeta(XmlDocument doc) + { + //if explorer is in edit mode, and the current RpfFileEntry is valid, convert XML to the + //current meta format and then save the file into the RPF. + //otherwise, save the generated file to disk? + //(currently just return false and revert to XML file save) + + if (!(exploreForm?.EditMode ?? false)) return false; + if (rpfFileEntry?.Parent == null) return false; + + byte[] data = null; + + try + { + switch (metaFormat) + { + default: + case MetaFormat.XML: return false;//what are we even doing here? + case MetaFormat.RSC: + var meta = XmlMeta.GetMeta(doc); + if ((meta.DataBlocks?.Data == null) || (meta.DataBlocks.Count == 0)) + { + MessageBox.Show("Schema not supported.", "Cannot import Meta XML"); + return false; + } + data = ResourceBuilder.Build(meta, 2); //meta is RSC "Version":2 (it's actually a type identifier, not a version!) + break; + case MetaFormat.PSO: + MessageBox.Show("Sorry, PSO import is not supported yet.", "Cannot import PSO XML"); + return false; + case MetaFormat.RBF: + MessageBox.Show("Sorry, RBF import is not supported.", "Cannot import RBF XML"); + return false; + case MetaFormat.CacheFile: + MessageBox.Show("Sorry, CacheFile import is not supported.", "Cannot import CacheFile XML"); + return false; + } + } + catch (Exception ex) + { + MessageBox.Show("Exception encountered!\r\n" + ex.Message, "Cannot convert XML"); + return false; + } + if (data == null) + { + MessageBox.Show("Schema not supported. (Unspecified error - data was null!)", "Cannot convert XML"); + return false; + } + + if (!rpfFileEntry.Path.ToLowerInvariant().StartsWith("mods")) + { + if (MessageBox.Show("This file is NOT located in the mods folder - Are you SURE you want to save this file?\r\nWARNING: This could cause permanent damage to your game!!!", "WARNING: Are you sure about this?", MessageBoxButtons.YesNo) != DialogResult.Yes) + { + return false;//that was a close one + } + } + + try + { + + var newentry = RpfFile.CreateFile(rpfFileEntry.Parent, rpfFileEntry.Name, data); + if (newentry != rpfFileEntry) + { } + rpfFileEntry = newentry; + + exploreForm?.RefreshMainListViewInvoke(); //update the file details in explorer... + + modified = false; + + return true; //victory! + } + catch (Exception ex) + { + MessageBox.Show("Error saving file to RPF! The RPF archive may be corrupted...\r\n" + ex.Message, "Really Bad Error"); + } + + return false; + } + + + + Style BlueStyle = new TextStyle(Brushes.Blue, null, FontStyle.Regular); Style RedStyle = new TextStyle(Brushes.Red, null, FontStyle.Regular); Style MaroonStyle = new TextStyle(Brushes.Maroon, null, FontStyle.Regular);