Save RSC Meta files to RPF directly from Meta Editor form

This commit is contained in:
dexy 2018-12-14 21:23:05 +11:00
parent e7f5238c33
commit f84b51d1c1
5 changed files with 233 additions and 19 deletions

View File

@ -3426,6 +3426,8 @@ namespace CodeWalker.GameFiles
LODLights = 1326371921, LODLights = 1326371921,
BoxOccluder = 975711773, BoxOccluder = 975711773,
OccludeModel = 2741784237, OccludeModel = 2741784237,
sirenLight = 4091688452,
sirenCorona = 472016577,

View File

@ -1763,4 +1763,15 @@ namespace CodeWalker.GameFiles
} }
public enum MetaFormat
{
XML = 0,
RSC = 1,
PSO = 2,
RBF = 3,
CacheFile = 4,
}
} }

View File

@ -487,18 +487,18 @@ namespace CodeWalker.GameFiles
new PsoStructureEntryInfo(MetaName.leftTailLightMultiples, PsoDataType.UByte, 122, 0, 0), new PsoStructureEntryInfo(MetaName.leftTailLightMultiples, PsoDataType.UByte, 122, 0, 0),
new PsoStructureEntryInfo(MetaName.rightTailLightMultiples, PsoDataType.UByte, 123, 0, 0), new PsoStructureEntryInfo(MetaName.rightTailLightMultiples, PsoDataType.UByte, 123, 0, 0),
new PsoStructureEntryInfo(MetaName.useRealLights, PsoDataType.Bool, 124, 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) new PsoStructureEntryInfo((MetaName)2047330294, PsoDataType.Array, 128, 1, (MetaName)1310739)
); );
case (MetaName)188820339: case (MetaName)188820339:
return new PsoStructureInfo((MetaName)188820339, 0, 0, 16, return new PsoStructureInfo((MetaName)188820339, 0, 0, 16,
new PsoStructureEntryInfo(MetaName.sequencer, PsoDataType.UInt, 8, 0, 0) new PsoStructureEntryInfo(MetaName.sequencer, PsoDataType.UInt, 8, 0, 0)
); );
case (MetaName)4091688452: case MetaName.sirenLight:
return new PsoStructureInfo((MetaName)4091688452, 0, 0, 112, return new PsoStructureInfo(MetaName.sirenLight, 0, 0, 112,
new PsoStructureEntryInfo(MetaName.rotation, PsoDataType.Structure, 8, 0, (MetaName)1356743507), new PsoStructureEntryInfo(MetaName.rotation, PsoDataType.Structure, 8, 0, (MetaName)1356743507),
new PsoStructureEntryInfo(MetaName.flashiness, PsoDataType.Structure, 40, 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.color, PsoDataType.UInt, 96, 1, 0),
new PsoStructureEntryInfo(MetaName.intensity, PsoDataType.Float, 100, 0, 0), new PsoStructureEntryInfo(MetaName.intensity, PsoDataType.Float, 100, 0, 0),
new PsoStructureEntryInfo(MetaName.lightGroup, PsoDataType.UByte, 104, 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.direction, PsoDataType.Bool, 25, 0, 0),
new PsoStructureEntryInfo(MetaName.syncToBpm, PsoDataType.Bool, 26, 0, 0) new PsoStructureEntryInfo(MetaName.syncToBpm, PsoDataType.Bool, 26, 0, 0)
); );
case (MetaName)472016577: case MetaName.sirenCorona:
return new PsoStructureInfo((MetaName)472016577, 0, 0, 24, return new PsoStructureInfo(MetaName.sirenCorona, 0, 0, 24,
new PsoStructureEntryInfo(MetaName.intensity, PsoDataType.Float, 8, 0, 0), new PsoStructureEntryInfo(MetaName.intensity, PsoDataType.Float, 8, 0, 0),
new PsoStructureEntryInfo(MetaName.size, PsoDataType.Float, 12, 0, 0), new PsoStructureEntryInfo(MetaName.size, PsoDataType.Float, 12, 0, 0),
new PsoStructureEntryInfo(MetaName.pull, PsoDataType.Float, 16, 0, 0), new PsoStructureEntryInfo(MetaName.pull, PsoDataType.Float, 16, 0, 0),

View File

@ -44,7 +44,7 @@ namespace CodeWalker
private GameFileCache FileCache { get; set; } = GameFileCacheFactory.Create(); private GameFileCache FileCache { get; set; } = GameFileCacheFactory.Create();
private object FileCacheSyncRoot = new object(); private object FileCacheSyncRoot = new object();
private bool EditMode = false; public bool EditMode { get; private set; } = false;
public ThemeBase Theme { get; private set; } public ThemeBase Theme { get; private set; }
@ -905,7 +905,6 @@ namespace CodeWalker
RecurseAddMainTreeViewNodes(f, CurrentFolder.TreeNode); RecurseAddMainTreeViewNodes(f, CurrentFolder.TreeNode);
CurrentFolder.AddChild(f); CurrentFolder.AddChild(f);
CurrentFolder.ListItems = null;
RefreshMainListView(); RefreshMainListView();
} }
@ -1053,11 +1052,23 @@ namespace CodeWalker
} }
} }
public void RefreshMainListViewInvoke()
{
if (InvokeRequired)
{
BeginInvoke(new Action(() => { RefreshMainListView(); }));
}
else
{
RefreshMainListView();
}
}
private void RefreshMainListView() private void RefreshMainListView()
{ {
MainListView.VirtualListSize = 0; MainListView.VirtualListSize = 0;
if (CurrentFolder != null) if (CurrentFolder != null)
{ {
CurrentFolder.ListItems = null; //makes sure to rebuild the current files list
CurrentFiles = CurrentFolder.GetListItems(); CurrentFiles = CurrentFolder.GetListItems();
foreach (var file in CurrentFiles) //cache all the data for use by the list view. foreach (var file in CurrentFiles) //cache all the data for use by the list view.
@ -1314,6 +1325,13 @@ namespace CodeWalker
try try
#endif #endif
{ {
var exform = FindExistingForm(item?.File);
if (exform != null)
{
exform.Focus();
return;
}
byte[] data = null; byte[] data = null;
string name = ""; string name = "";
string path = ""; string path = "";
@ -1469,35 +1487,35 @@ namespace CodeWalker
private void ViewYmt(string name, string path, byte[] data, RpfFileEntry e) private void ViewYmt(string name, string path, byte[] data, RpfFileEntry e)
{ {
var ymt = RpfFile.GetFile<YmtFile>(e, data); var ymt = RpfFile.GetFile<YmtFile>(e, data);
MetaForm f = new MetaForm(); MetaForm f = new MetaForm(this);
f.Show(); f.Show();
f.LoadMeta(ymt); f.LoadMeta(ymt);
} }
private void ViewYmf(string name, string path, byte[] data, RpfFileEntry e) private void ViewYmf(string name, string path, byte[] data, RpfFileEntry e)
{ {
var ymf = RpfFile.GetFile<YmfFile>(e, data); var ymf = RpfFile.GetFile<YmfFile>(e, data);
MetaForm f = new MetaForm(); MetaForm f = new MetaForm(this);
f.Show(); f.Show();
f.LoadMeta(ymf); f.LoadMeta(ymf);
} }
private void ViewYmap(string name, string path, byte[] data, RpfFileEntry e) private void ViewYmap(string name, string path, byte[] data, RpfFileEntry e)
{ {
var ymap = RpfFile.GetFile<YmapFile>(e, data); var ymap = RpfFile.GetFile<YmapFile>(e, data);
MetaForm f = new MetaForm(); MetaForm f = new MetaForm(this);
f.Show(); f.Show();
f.LoadMeta(ymap); f.LoadMeta(ymap);
} }
private void ViewYtyp(string name, string path, byte[] data, RpfFileEntry e) private void ViewYtyp(string name, string path, byte[] data, RpfFileEntry e)
{ {
var ytyp = RpfFile.GetFile<YtypFile>(e, data); var ytyp = RpfFile.GetFile<YtypFile>(e, data);
MetaForm f = new MetaForm(); MetaForm f = new MetaForm(this);
f.Show(); f.Show();
f.LoadMeta(ytyp); f.LoadMeta(ytyp);
} }
private void ViewJPso(string name, string path, byte[] data, RpfFileEntry e) private void ViewJPso(string name, string path, byte[] data, RpfFileEntry e)
{ {
var pso = RpfFile.GetFile<JPsoFile>(e, data); var pso = RpfFile.GetFile<JPsoFile>(e, data);
MetaForm f = new MetaForm(); MetaForm f = new MetaForm(this);
f.Show(); f.Show();
f.LoadMeta(pso); f.LoadMeta(pso);
} }
@ -1538,7 +1556,7 @@ namespace CodeWalker
private void ViewCut(string name, string path, byte[] data, RpfFileEntry e) private void ViewCut(string name, string path, byte[] data, RpfFileEntry e)
{ {
var cut = RpfFile.GetFile<CutFile>(e, data); var cut = RpfFile.GetFile<CutFile>(e, data);
MetaForm f = new MetaForm(); MetaForm f = new MetaForm(this);
f.Show(); f.Show();
f.LoadMeta(cut); f.LoadMeta(cut);
} }
@ -1594,12 +1612,29 @@ namespace CodeWalker
private void ViewCacheDat(string name, string path, byte[] data, RpfFileEntry e) private void ViewCacheDat(string name, string path, byte[] data, RpfFileEntry e)
{ {
var cachedat = RpfFile.GetFile<CacheDatFile>(e, data); var cachedat = RpfFile.GetFile<CacheDatFile>(e, data);
MetaForm f = new MetaForm(); MetaForm f = new MetaForm(this);
f.Show(); f.Show();
f.LoadMeta(cachedat); 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) private void ShowTreeContextMenu(TreeNode n, Point p)
{ {
var f = n?.Tag as MainTreeFolder; var f = n?.Tag as MainTreeFolder;
@ -2265,7 +2300,6 @@ namespace CodeWalker
} }
CurrentFolder.ListItems = null;
RefreshMainListView(); RefreshMainListView();
} }
@ -2407,7 +2441,6 @@ namespace CodeWalker
} }
} }
CurrentFolder.ListItems = null;
RefreshMainListView(); RefreshMainListView();
} }
private void CopySelected() private void CopySelected()

View File

@ -11,6 +11,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Forms; using System.Windows.Forms;
using System.Xml;
namespace CodeWalker.Forms namespace CodeWalker.Forms
{ {
@ -44,8 +45,15 @@ namespace CodeWalker.Forms
private bool DelayHighlight = false; 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(); InitializeComponent();
} }
@ -119,14 +127,18 @@ namespace CodeWalker.Forms
Xml = ""; Xml = "";
RawPropertyGrid.SelectedObject = null; RawPropertyGrid.SelectedObject = null;
modified = false; modified = false;
rpfFileEntry = null;
return true; return true;
} }
private void NewDocument() private void NewDocument()
{ {
if (!CloseDocument()) return; //same thing really.. if (!CloseDocument()) return;
FileName = "New.xml"; FileName = "New.xml";
rpfFileEntry = null;
//TODO: decide XML/RSC/PSO/RBF format..?
} }
private void OpenDocument() private void OpenDocument()
{ {
@ -144,9 +156,32 @@ namespace CodeWalker.Forms
FilePath = fn; FilePath = fn;
FileName = new FileInfo(fn).Name; FileName = new FileInfo(fn).Name;
RawPropertyGrid.SelectedObject = null; RawPropertyGrid.SelectedObject = null;
rpfFileEntry = null;
//TODO: open RSC/PSO/RBF..?
} }
private void SaveDocument(bool saveAs = false) 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(FileName)) saveAs = true;
if (string.IsNullOrEmpty(FilePath)) saveAs = true; if (string.IsNullOrEmpty(FilePath)) saveAs = true;
else if ((FilePath.ToLowerInvariant().StartsWith(GTAFolder.CurrentGTAFolder.ToLowerInvariant()))) saveAs = true; else if ((FilePath.ToLowerInvariant().StartsWith(GTAFolder.CurrentGTAFolder.ToLowerInvariant()))) saveAs = true;
@ -171,6 +206,7 @@ namespace CodeWalker.Forms
modified = false; modified = false;
FilePath = fn; FilePath = fn;
FileName = new FileInfo(fn).Name; FileName = new FileInfo(fn).Name;
metaFormat = MetaFormat.XML;
} }
@ -181,7 +217,15 @@ namespace CodeWalker.Forms
Xml = MetaXml.GetXml(ymt, out fn); Xml = MetaXml.GetXml(ymt, out fn);
FileName = fn; FileName = fn;
RawPropertyGrid.SelectedObject = ymt; RawPropertyGrid.SelectedObject = ymt;
rpfFileEntry = ymt?.RpfFileEntry;
modified = false; 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) public void LoadMeta(YmfFile ymf)
{ {
@ -189,7 +233,15 @@ namespace CodeWalker.Forms
Xml = MetaXml.GetXml(ymf, out fn); Xml = MetaXml.GetXml(ymf, out fn);
FileName = fn; FileName = fn;
RawPropertyGrid.SelectedObject = ymf; RawPropertyGrid.SelectedObject = ymf;
rpfFileEntry = ymf?.FileEntry;
modified = false; 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) public void LoadMeta(YmapFile ymap)
{ {
@ -197,7 +249,15 @@ namespace CodeWalker.Forms
Xml = MetaXml.GetXml(ymap, out fn); Xml = MetaXml.GetXml(ymap, out fn);
FileName = fn; FileName = fn;
RawPropertyGrid.SelectedObject = ymap; RawPropertyGrid.SelectedObject = ymap;
rpfFileEntry = ymap?.RpfFileEntry;
modified = false; 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) public void LoadMeta(YtypFile ytyp)
{ {
@ -205,7 +265,15 @@ namespace CodeWalker.Forms
Xml = MetaXml.GetXml(ytyp, out fn); Xml = MetaXml.GetXml(ytyp, out fn);
FileName = fn; FileName = fn;
RawPropertyGrid.SelectedObject = ytyp; RawPropertyGrid.SelectedObject = ytyp;
rpfFileEntry = ytyp?.RpfFileEntry;
modified = false; 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) public void LoadMeta(JPsoFile jpso)
{ {
@ -213,7 +281,13 @@ namespace CodeWalker.Forms
Xml = MetaXml.GetXml(jpso, out fn); Xml = MetaXml.GetXml(jpso, out fn);
FileName = fn; FileName = fn;
RawPropertyGrid.SelectedObject = jpso; RawPropertyGrid.SelectedObject = jpso;
rpfFileEntry = jpso?.FileEntry;
modified = false; modified = false;
metaFormat = MetaFormat.XML;
if (jpso != null)
{
if (jpso.Pso != null) metaFormat = MetaFormat.PSO;
}
} }
public void LoadMeta(CutFile cut) public void LoadMeta(CutFile cut)
{ {
@ -221,7 +295,13 @@ namespace CodeWalker.Forms
Xml = MetaXml.GetXml(cut, out fn); Xml = MetaXml.GetXml(cut, out fn);
FileName = fn; FileName = fn;
RawPropertyGrid.SelectedObject = cut; RawPropertyGrid.SelectedObject = cut;
rpfFileEntry = cut?.FileEntry;
modified = false; modified = false;
metaFormat = MetaFormat.XML;
if (cut != null)
{
if (cut.Pso != null) metaFormat = MetaFormat.PSO;
}
} }
public void LoadMeta(CacheDatFile cachedat) public void LoadMeta(CacheDatFile cachedat)
{ {
@ -229,8 +309,96 @@ namespace CodeWalker.Forms
Xml = cachedat.GetXml(); Xml = cachedat.GetXml();
FileName = fn; FileName = fn;
RawPropertyGrid.SelectedObject = cachedat; RawPropertyGrid.SelectedObject = cachedat;
rpfFileEntry = cachedat?.FileEntry;
modified = false; 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;
}