mirror of
https://mirror.ghproxy.com/https://github.com/dexyfex/CodeWalker
synced 2026-05-14 22:54:46 +08:00
Audio dat.rel XML editing
This commit is contained in:
+342
-9
@@ -1,18 +1,31 @@
|
||||
using CodeWalker.GameFiles;
|
||||
using FastColoredTextBoxNS;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using System.Xml;
|
||||
|
||||
namespace CodeWalker.Forms
|
||||
{
|
||||
public partial class RelForm : Form
|
||||
{
|
||||
private string xml;
|
||||
public string Xml
|
||||
{
|
||||
get { return xml; }
|
||||
set
|
||||
{
|
||||
xml = value;
|
||||
UpdateTextBoxFromData();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private string fileName;
|
||||
@@ -30,9 +43,19 @@ namespace CodeWalker.Forms
|
||||
private RelFile CurrentFile { get; set; }
|
||||
|
||||
|
||||
private bool modified = false;
|
||||
private bool LoadingXml = false;
|
||||
private bool DelayHighlight = false;
|
||||
|
||||
public RelForm()
|
||||
private ExploreForm exploreForm = null;
|
||||
public RpfFileEntry rpfFileEntry { get; private set; } = null;
|
||||
private MetaFormat metaFormat = MetaFormat.XML;
|
||||
|
||||
|
||||
public RelForm(ExploreForm owner)
|
||||
{
|
||||
exploreForm = owner;
|
||||
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
@@ -40,7 +63,49 @@ namespace CodeWalker.Forms
|
||||
|
||||
private void UpdateFormTitle()
|
||||
{
|
||||
Text = fileName + " - REL Viewer - CodeWalker by dexyfex";
|
||||
Text = fileName + " - Audio dat.rel Editor - CodeWalker by dexyfex";
|
||||
}
|
||||
|
||||
private void UpdateTextBoxFromData()
|
||||
{
|
||||
LoadingXml = true;
|
||||
XmlTextBox.Text = "";
|
||||
XmlTextBox.Language = Language.XML;
|
||||
DelayHighlight = false;
|
||||
|
||||
if (string.IsNullOrEmpty(xml))
|
||||
{
|
||||
LoadingXml = false;
|
||||
return;
|
||||
}
|
||||
//if (xml.Length > (1048576 * 5))
|
||||
//{
|
||||
// XmlTextBox.Language = Language.Custom;
|
||||
// XmlTextBox.Text = "[XML size > 10MB - Not shown due to performance limitations - Please use an external viewer for this file.]";
|
||||
// return;
|
||||
//}
|
||||
//else
|
||||
if (xml.Length > (1024 * 512))
|
||||
{
|
||||
XmlTextBox.Language = Language.Custom;
|
||||
DelayHighlight = true;
|
||||
}
|
||||
//else
|
||||
//{
|
||||
// XmlTextBox.Language = Language.XML;
|
||||
//}
|
||||
|
||||
|
||||
Cursor = Cursors.WaitCursor;
|
||||
|
||||
|
||||
|
||||
XmlTextBox.Text = xml;
|
||||
//XmlTextBox.IsChanged = false;
|
||||
XmlTextBox.ClearUndo();
|
||||
|
||||
Cursor = Cursors.Default;
|
||||
LoadingXml = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +124,11 @@ namespace CodeWalker.Forms
|
||||
|
||||
CurrentFile = rel;
|
||||
|
||||
XmlTextBox.Text = RelXml.GetXml(rel);
|
||||
rpfFileEntry = rel?.RpfFileEntry;
|
||||
|
||||
Xml = RelXml.GetXml(rel);
|
||||
|
||||
metaFormat = MetaFormat.AudioRel;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (rel != null)
|
||||
@@ -106,6 +175,216 @@ namespace CodeWalker.Forms
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private bool SaveRel(XmlDocument doc)
|
||||
{
|
||||
|
||||
if (!(exploreForm?.EditMode ?? false)) return false;
|
||||
if (rpfFileEntry?.Parent == null) return false;
|
||||
|
||||
byte[] data = null;
|
||||
|
||||
#if !DEBUG
|
||||
try
|
||||
#endif
|
||||
{
|
||||
switch (metaFormat)
|
||||
{
|
||||
default:
|
||||
case MetaFormat.XML:
|
||||
return false;//what are we even doing here?
|
||||
case MetaFormat.AudioRel:
|
||||
var rel = XmlRel.GetRel(doc);
|
||||
if ((rel?.RelDatasSorted == null) || (rel.RelDatasSorted.Length == 0))
|
||||
{
|
||||
MessageBox.Show("Schema not supported.", "Cannot import REL XML");
|
||||
return false;
|
||||
}
|
||||
data = rel.Save();
|
||||
break;
|
||||
}
|
||||
}
|
||||
#if !DEBUG
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show("Exception encountered!\r\n" + ex.ToString(), "Cannot convert XML");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
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
|
||||
{
|
||||
if (!(exploreForm?.EnsureRpfValidEncryption(rpfFileEntry.File) ?? false)) return false;
|
||||
|
||||
var newentry = RpfFile.CreateFile(rpfFileEntry.Parent, rpfFileEntry.Name, data);
|
||||
if (newentry != rpfFileEntry)
|
||||
{ }
|
||||
rpfFileEntry = newentry;
|
||||
|
||||
exploreForm?.RefreshMainListViewInvoke(); //update the file details in explorer...
|
||||
|
||||
modified = false;
|
||||
|
||||
StatusLabel.Text = metaFormat.ToString() + " file saved successfully at " + DateTime.Now.ToString();
|
||||
|
||||
return true; //victory!
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show("Error saving file to RPF! The RPF archive may be corrupted...\r\n" + ex.ToString(), "Really Bad Error");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private bool CloseDocument()
|
||||
{
|
||||
if (modified)
|
||||
{
|
||||
var res = MessageBox.Show("Do you want to save the current document before closing it?", "Save before closing", MessageBoxButtons.YesNoCancel);
|
||||
switch (res)
|
||||
{
|
||||
case DialogResult.Yes:
|
||||
SaveDocument();
|
||||
break;
|
||||
case DialogResult.Cancel:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
FilePath = "";
|
||||
FileName = "";
|
||||
Xml = "";
|
||||
RelPropertyGrid.SelectedObject = null;
|
||||
MainTextBox.Text = "";
|
||||
modified = false;
|
||||
rpfFileEntry = null;
|
||||
|
||||
return true;
|
||||
}
|
||||
private void NewDocument()
|
||||
{
|
||||
if (!CloseDocument()) return;
|
||||
|
||||
FileName = "New.xml";
|
||||
rpfFileEntry = null;
|
||||
|
||||
//TODO: decide XML/REL format..?
|
||||
}
|
||||
private void OpenDocument()
|
||||
{
|
||||
if (OpenFileDialog.ShowDialog() != DialogResult.OK) return;
|
||||
|
||||
if (!CloseDocument()) return;
|
||||
|
||||
var fn = OpenFileDialog.FileName;
|
||||
|
||||
if (!File.Exists(fn)) return; //couldn't find file?
|
||||
|
||||
Xml = File.ReadAllText(fn);
|
||||
|
||||
modified = false;
|
||||
FilePath = fn;
|
||||
FileName = new FileInfo(fn).Name;
|
||||
RelPropertyGrid.SelectedObject = null;
|
||||
MainTextBox.Text = "";
|
||||
rpfFileEntry = null;
|
||||
|
||||
//TODO: open raw REL..?
|
||||
}
|
||||
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 (SaveRel(doc))
|
||||
{
|
||||
return;
|
||||
}
|
||||
//if REL 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;
|
||||
if (!File.Exists(FilePath)) saveAs = true;
|
||||
|
||||
var fn = FilePath;
|
||||
if (saveAs)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(fn))
|
||||
{
|
||||
var dir = new FileInfo(fn).DirectoryName;
|
||||
if (!Directory.Exists(dir)) dir = "";
|
||||
SaveFileDialog.InitialDirectory = dir;
|
||||
}
|
||||
SaveFileDialog.FileName = FileName;
|
||||
if (SaveFileDialog.ShowDialog() != DialogResult.OK) return;
|
||||
fn = SaveFileDialog.FileName;
|
||||
}
|
||||
|
||||
File.WriteAllText(fn, xml);
|
||||
|
||||
modified = false;
|
||||
FilePath = fn;
|
||||
FileName = new FileInfo(fn).Name;
|
||||
metaFormat = MetaFormat.XML;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
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);
|
||||
|
||||
private void HTMLSyntaxHighlight(Range range)
|
||||
{
|
||||
//clear style of changed range
|
||||
range.ClearStyle(BlueStyle, MaroonStyle, RedStyle);
|
||||
//tag brackets highlighting
|
||||
range.SetStyle(BlueStyle, @"<|/>|</|>");
|
||||
//tag name
|
||||
range.SetStyle(MaroonStyle, @"<(?<range>[!\w]+)");
|
||||
//end of tag
|
||||
range.SetStyle(MaroonStyle, @"</(?<range>\w+)>");
|
||||
//attributes
|
||||
range.SetStyle(RedStyle, @"(?<range>\S+?)='[^']*'|(?<range>\S+)=""[^""]*""|(?<range>\S+)=\S+");
|
||||
//attribute values
|
||||
range.SetStyle(BlueStyle, @"\S+?=(?<range>'[^']*')|\S+=(?<range>""[^""]*"")|\S+=(?<range>\S+)");
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void Search()
|
||||
{
|
||||
SearchResultsGrid.SelectedObject = null;
|
||||
@@ -167,12 +446,6 @@ namespace CodeWalker.Forms
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void CloseButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
private void SearchButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
Search();
|
||||
@@ -185,5 +458,65 @@ namespace CodeWalker.Forms
|
||||
Search();
|
||||
}
|
||||
}
|
||||
|
||||
private void FileNewMenu_Click(object sender, EventArgs e)
|
||||
{
|
||||
NewDocument();
|
||||
}
|
||||
|
||||
private void FileOpenMenu_Click(object sender, EventArgs e)
|
||||
{
|
||||
OpenDocument();
|
||||
}
|
||||
|
||||
private void FileSaveMenu_Click(object sender, EventArgs e)
|
||||
{
|
||||
SaveDocument();
|
||||
}
|
||||
|
||||
private void FileSaveAsMenu_Click(object sender, EventArgs e)
|
||||
{
|
||||
SaveDocument(true);
|
||||
}
|
||||
|
||||
private void FileCloseMenu_Click(object sender, EventArgs e)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
private void NewButton_ButtonClick(object sender, EventArgs e)
|
||||
{
|
||||
NewDocument();
|
||||
}
|
||||
|
||||
private void OpenButton_ButtonClick(object sender, EventArgs e)
|
||||
{
|
||||
OpenDocument();
|
||||
}
|
||||
|
||||
private void SaveButton_ButtonClick(object sender, EventArgs e)
|
||||
{
|
||||
SaveDocument();
|
||||
}
|
||||
|
||||
private void XmlTextBox_TextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
if (!LoadingXml)
|
||||
{
|
||||
xml = XmlTextBox.Text;
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void XmlTextBox_VisibleRangeChangedDelayed(object sender, EventArgs e)
|
||||
{
|
||||
//this approach is much faster to load, but no outlining is available
|
||||
|
||||
//highlight only visible area of text
|
||||
if (DelayHighlight)
|
||||
{
|
||||
HTMLSyntaxHighlight(XmlTextBox.VisibleRange);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user