Refactoring

Removes a bit of file r/w to the hard disk, speeds up subform opening
times.
Use the built in settings instead of config.ini / command line arguments
This commit is contained in:
Kurt
2016-11-20 17:11:20 -08:00
parent c920a1b589
commit e963283b70
13 changed files with 451 additions and 200 deletions

View File

@@ -506,10 +506,167 @@ private static GARCFile unpackGARC(Stream stream)
return garc;
}
public static MemGARC packGARC(byte[][] data, int version)
{
// Set Up the GARC template.
GARCFile garc = new GARCFile
{
ContentPadToNearest = 4,
fato =
{
// Magic = new[] { 'O', 'T', 'A', 'F' },
Entries = new FATO_Entry[data.Length],
EntryCount = (ushort) data.Length,
HeaderSize = 0xC + data.Length*4,
Padding = 0xFFFF
},
fatb =
{
// Magic = new[] { 'B', 'T', 'A', 'F' },
Entries = new FATB_Entry[data.Length],
FileCount = data.Length
}
};
if (version == VER_6)
garc.ContentPadToNearest = 4;
int op = 0;
int od = 0;
for (int i = 0; i < garc.fatb.Entries.Length; i++)
{
garc.fato.Entries[i].Offset = op; // FATO offset
garc.fatb.Entries[i].SubEntries = new FATB_SubEntry[32];
op += 4; // Vector
garc.fatb.Entries[i].IsFolder = false;
garc.fatb.Entries[i].SubEntries[0].Exists = true;
// Assemble Entry
int actualLength = data[i].Length%4 == 0 ? data[i].Length : data[i].Length + 4 - data[i].Length%4;
garc.fatb.Entries[i].SubEntries[0].Start = od;
garc.fatb.Entries[i].SubEntries[0].End = actualLength + garc.fatb.Entries[i].SubEntries[0].Start;
garc.fatb.Entries[i].SubEntries[0].Length = data[i].Length;
od += actualLength;
op += 12;
garc.fatb.Entries[i].Vector = 1;
}
garc.fatb.HeaderSize = 0xC + op;
// Set up the Header Info
using (MemoryStream newGARC = new MemoryStream())
using (MemoryStream GARCdata = new MemoryStream())
using (BinaryWriter gw = new BinaryWriter(newGARC))
{
#region Write GARC Headers
// Write GARC
gw.Write((uint) 0x47415243); // GARC
gw.Write((uint) (version == VER_6 ? 0x24 : 0x1C)); // Header Length
gw.Write((ushort) 0xFEFF); // Endianness BOM
gw.Write((ushort) version); // Version
gw.Write((uint) 0x00000004); // Section Count (4)
gw.Write((uint) 0x00000000); // Data Offset (temp)
gw.Write((uint) 0x00000000); // File Length (temp)
gw.Write((uint) 0x00000000); // Largest File Size (temp)
if (version == VER_6)
{
gw.Write((uint) 0x0);
gw.Write((uint) 0x0);
}
// Write FATO
gw.Write((uint) 0x4641544F); // FATO
gw.Write(garc.fato.HeaderSize); // Header Size
gw.Write(garc.fato.EntryCount); // Entry Count
gw.Write(garc.fato.Padding); // Padding
for (int i = 0; i < garc.fato.Entries.Length; i++)
gw.Write((uint) garc.fato.Entries[i].Offset);
// Write FATB
gw.Write((uint) 0x46415442); // FATB
gw.Write(garc.fatb.HeaderSize); // Header Size
gw.Write(garc.fatb.FileCount); // File Count
foreach (var e in garc.fatb.Entries)
{
gw.Write(e.Vector);
foreach (var s in e.SubEntries.Where(s => s.Exists))
{
gw.Write((uint) s.Start);
gw.Write((uint) s.End);
gw.Write((uint) s.Length);
}
}
#endregion
#region Write Files
long largestSize = 0; // Required memory to allocate to handle the largest file
long largestPadded = 0; // Required memory to allocate to handle the largest PADDED file (Ver6 only)
foreach (byte[] e in data)
{
// Update largest file length if necessary
long len = e.Length;
bool largest = len > largestSize;
if (largest)
{
largestSize = len;
largestPadded = len;
}
// Write to FIMB
using (var input = new MemoryStream(e))
input.CopyTo(GARCdata);
// While length is not divisible by 4, pad with FF (unused byte)
while (GARCdata.Length%garc.ContentPadToNearest != 0)
{
GARCdata.WriteByte(0xFF);
if (largest)
largestPadded++;
}
}
garc.ContentLargestUnpadded = (uint) largestSize;
garc.ContentLargestPadded = (uint) largestPadded;
#endregion
gw.Write((uint) 0x46494D42); // FIMB
gw.Write((uint) 0x0000000C); // Header Length
gw.Write((uint) GARCdata.Length); // Data Length
gw.Seek(0x10, SeekOrigin.Begin); // Goto the start of the un-set 0 data we set earlier and set it.
gw.Write((uint) newGARC.Length); // Write Data Offset
gw.Write((uint) (newGARC.Length + GARCdata.Length)); // Write total GARC Length
// Write Handling information
if (version == VER_4)
{
gw.Write(garc.ContentLargestUnpadded); // Write Largest File stat
}
else if (version == VER_6)
{
gw.Write(garc.ContentLargestPadded); // Write Largest With Padding
gw.Write(garc.ContentLargestUnpadded); // Write Largest Without Padding
gw.Write(garc.ContentPadToNearest);
}
newGARC.Seek(0, SeekOrigin.End); // Goto the end so we can copy the filedata after the GARC headers.
// Write in the data
GARCdata.Position = 0;
GARCdata.CopyTo(newGARC); // Copy the data.
// New File is ready to be saved (memstream newGARC)
return new MemGARC(newGARC.ToArray());
}
}
public class MemGARC
{
private GARCFile garc;
private readonly byte[] Data;
internal byte[] Data;
public int FileCount => garc.fato.EntryCount;
public MemGARC(byte[] data)
@@ -517,6 +674,8 @@ public MemGARC(byte[] data)
Data = data;
garc = unpackGARC(data);
}
// Returns an individual file
public byte[] getFile(int file, int subfile = 0)
{
var Entry = garc.fatb.Entries[file];
@@ -528,6 +687,27 @@ public byte[] getFile(int file, int subfile = 0)
Array.Copy(Data, offset, data, 0, data.Length);
return data;
}
// Returns all files (excluding language vectorized)
public byte[][] Files
{
get
{
byte[][] data = new byte[FileCount][];
for (int i = 0; i < data.Length; i++)
data[i] = getFile(i);
return data;
}
set
{
if (value == null || value.Length != FileCount)
throw new ArgumentException();
var ng = packGARC(value, garc.Version);
garc = ng.garc;
Data = ng.Data;
}
}
}
public struct GARCFile

31
pk3DS/Game/GARCFile.cs Normal file
View File

@@ -0,0 +1,31 @@
using System;
using System.IO;
using CTR;
namespace pk3DS
{
public class GARCFile
{
private readonly GARC.MemGARC GARC;
private readonly GARCReference Reference;
private readonly string Path;
public GARCFile(GARC.MemGARC g, GARCReference r, string p)
{
GARC = g;
Reference = r;
Path = p;
}
// Shorthand Alias
public byte[] getFile(int file, int subfile = 0) { return GARC.getFile(file, subfile); }
public byte[][] Files { get { return GARC.Files; } set { GARC.Files = value; } }
public int FileCount => GARC.FileCount;
public void Save()
{
File.WriteAllBytes(Path, GARC.Data);
Console.WriteLine($"Wrote {Reference.Name} to {Reference.Reference}");
}
}
}

View File

@@ -87,30 +87,81 @@ public void Initialize(string romFSpath, string exeFSpath, int lang)
ExeFS = exeFSpath;
Language = lang;
getGameData(Version);
InitializeAll();
}
public void InitializeAll()
{
InitializePersonal();
InitializeLearnset();
InitializeGameText();
InitializeMoves();
}
public void InitializePersonal()
{
var pG = getROMFSFile("personal");
Personal = new PersonalTable(pG.getFile(pG.FileCount - 1), Version);
GARCPersonal = getGARCData("personal");
Personal = new PersonalTable(GARCPersonal.getFile(GARCPersonal.FileCount - 1), Version);
}
public void InitializeLearnset()
{
GARCLearnsets = getGARCData("levelup");
switch (Generation)
{
case 6:
Learnsets = GARCLearnsets.Files.Select(file => new Learnset6(file)).ToArray();
break;
case 7:
Learnsets = GARCLearnsets.Files.Select(file => new Learnset7(file)).ToArray();
break;
}
}
public void InitializeGameText()
{
GARCGameText = getGARCData("gametext");
GameTextStrings = GARCGameText.Files.Select(file => new TextFile(file).Lines).ToArray();
}
public void InitializeMoves()
{
GARCMoves = getGARCData("move");
switch (Generation)
{
case 6:
if (XY)
Moves = GARCMoves.Files.Select(file => new Move(file)).ToArray();
if (ORAS)
Moves = mini.unpackMini(GARCMoves.getFile(0), "WD").Select(file => new Move(file)).ToArray();
break;
case 7:
Moves = mini.unpackMini(GARCMoves.getFile(0), "WD").Select(file => new Move(file)).ToArray();
break;
}
}
public GARCFile getGARCData(string file)
{
return new GARCFile(getMemGARC(file), getGARCReference(file), getGARCPath(file));
}
private string getGARCPath(string file)
{
var gr = getGARCReference(file);
gr = gr.LanguageVariant ? gr.getRelativeGARC(Language, gr.Name) : gr;
string subloc = gr.Reference;
return Path.Combine(RomFS, subloc);
}
private GARC.MemGARC getROMFSFile(string file)
private GARC.MemGARC getMemGARC(string file)
{
string path = Path.Combine(RomFS, getGARC(file).Reference);
return new GARC.MemGARC(File.ReadAllBytes(path));
return new GARC.MemGARC(File.ReadAllBytes(getGARCPath(file)));
}
private string RomFS, ExeFS;
public GARCReference getGARC(string name) { return Files.FirstOrDefault(f => f.Name == name); }
public GARCReference getGARCReference(string name) { return Files.FirstOrDefault(f => f.Name == name); }
public TextVariableCode getVariableCode(string name) { return Variables.FirstOrDefault(v => v.Name == name); }
public TextVariableCode getVariableName(int value) { return Variables.FirstOrDefault(v => v.Code == value); }
public TextReference getGameText(TextName name) { return GameText.FirstOrDefault(f => f.Name == name); }
public string getGARCFileName(string requestedGARC)
{
var garc = getGARC(requestedGARC);
var garc = getGARCReference(requestedGARC);
if (garc.LanguageVariant)
garc = garc.getRelativeGARC(Language);
@@ -118,7 +169,13 @@ public string getGARCFileName(string requestedGARC)
}
public int Language { get; set; }
public PersonalTable Personal;
public GARCFile GARCPersonal, GARCLearnsets, GARCMoves, GARCGameText;
public PersonalTable Personal { get; private set; }
public Learnset[] Learnsets { get; private set; }
public string[][] GameTextStrings { get; private set; }
public Move[] Moves { get; private set; }
public bool XY => Version == GameVersion.XY;
public bool ORAS => Version == GameVersion.ORAS || Version == GameVersion.ORASDEMO;
public bool SM => Version == GameVersion.SM || Version == GameVersion.SMDEMO;

View File

@@ -29,9 +29,6 @@ public Main()
// Initialize the Main Form
InitializeComponent();
// Set the Current Language to English
CB_Lang.SelectedIndex = 2;
// Prepare DragDrop Functionality
AllowDrop = TB_Path.AllowDrop = true;
DragEnter += tabMain_DragEnter;
@@ -45,29 +42,14 @@ public Main()
t.DragDrop += tabMain_DragDrop;
}
// Load with special arguments if supplied via command line
string[] args = Environment.GetCommandLineArgs();
if (args.Length > 1)
{
int lang;
if (args.Length > 2 && int.TryParse(args[2], out lang))
CB_Lang.SelectedIndex = lang;
string path = args[1];
if (path.Length > 0) openQuick(path);
}
// Reload Previous Editing Files if the file exists
else if (File.Exists("config.ini"))
{
string[] lines = File.ReadAllLines("config.ini");
string path = lines[0];
int lang;
if (lines.Length > 1 && int.TryParse(lines[1], out lang))
CB_Lang.SelectedIndex = lang;
if (Directory.Exists("personal") && !skipBoth) { Directory.Delete("personal", true); } // Clear data on form load.
if (path.Length > 0) openQuick(path);
}
string filename = Path.GetFileNameWithoutExtension(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
CB_Lang.SelectedIndex = Properties.Settings.Default.Language;
if (!string.IsNullOrWhiteSpace(Properties.Settings.Default.GamePath))
openQuick(Properties.Settings.Default.GamePath);
string[] args = Environment.GetCommandLineArgs();
string filename = args.Length > 0 ? Path.GetFileNameWithoutExtension(args[0])?.ToLower() : "";
skipBoth = filename.IndexOf("3DSkip", StringComparison.Ordinal) >= 0;
}
internal static GameConfig Config;
@@ -132,26 +114,9 @@ private void changeLanguage(object sender, EventArgs e)
}
updateGameInfo();
new Thread(() =>
{
// Let all other operations finish first (ie, if the user quickly switches languages on load)
while (threads > 0) Thread.Sleep(50);
// Gather the Text Language Strings
updateStatus($"GARC Get: {"gametext"} @ {Config.getGARCFileName("gametext")}... ");
threadGet(Path.Combine(RomFSPath, Config.getGARCFileName("gametext")), "gametext", true, true);
while (threads > 0) Thread.Sleep(50);
if (!Directory.Exists("personal"))
{
updateStatus($"GARC Get: {"personal"} @ {Config.getGARCFileName("personal")}... ");
threadGet(Path.Combine(RomFSPath, Config.getGARCFileName("personal")), "personal", true, true);
}
while (threads > 0) Thread.Sleep(50);
// Refresh Personal Stats
Config.InitializePersonal();
resetStatus();
}).Start();
Config.InitializeGameText();
Properties.Settings.Default.Language = Language;
Properties.Settings.Default.Save();
}
private void Menu_Exit_Click(object sender, EventArgs e)
{
@@ -159,30 +124,13 @@ private void Menu_Exit_Click(object sender, EventArgs e)
}
private void formClosing(object sender, FormClosingEventArgs e)
{
while (threads > 0) { Util.Alert("Please wait for all operations to finish first."); }
updateStatus(Environment.NewLine + Environment.NewLine + "Saving data and closing the program...");
try
{
if (TB_Path.Text.Length > 0) File.WriteAllLines("config.ini", new[] { TB_Path.Text, CB_Lang.SelectedIndex.ToString() });
if (!Tab_RomFS.Enabled || skipBoth) return; // No data/threads need to be addressed if we haven't loaded anything.
// Set the GameText back as other forms may have edited it.
updateStatus($"GARC Get: {"gametext"} @ {Config.getGARCFileName("gametext")}... ");
threadSet(Path.Combine(RomFSPath, Config.getGARCFileName("gametext")), "gametext", false);
while (threads > 0) Thread.Sleep(100);
Thread.Sleep(200); // Small gap between beeps for faster computers.
updateStatus($"GARC Get: {"personal"} @ {Config.getGARCFileName("personal")}... ");
threadSet(Path.Combine(RomFSPath, Config.getGARCFileName("personal")), "personal", false);
while (threads > 0) Thread.Sleep(100);
if (Directory.Exists("gametext")) Directory.Delete("gametext", true);
if (Directory.Exists("personal")) Directory.Delete("personal", true);
}
catch { }
var g = Config.GARCGameText;
string[][] files = Config.GameTextStrings;
Invoke((Action)(() => new TextEditor(files, "gametext").ShowDialog()));
g.Files = files.Select(TextFile.getBytes).ToArray();
g.Save();
}
private void openQuick(string path)
{
if (threadActive()) return;
@@ -257,7 +205,6 @@ private void openQuick(string path)
Config.Initialize(RomFSPath, ExeFSPath, Language);
backupGARCs(false, Config.Files.Select(file => file.Name).ToArray());
backupCROs(false, RomFSPath);
changeLanguage(null, null);
}
// Enable Rebuilding options if all files have been found
@@ -276,6 +223,9 @@ private void openQuick(string path)
TB_Path.Select(TB_Path.TextLength, 0);
// Method finished.
System.Media.SystemSounds.Asterisk.Play();
resetStatus();
Properties.Settings.Default.GamePath = path;
Properties.Settings.Default.Save();
}
}
@@ -468,10 +418,11 @@ private void B_GameText_Click(object sender, EventArgs e)
if (threadActive()) return;
new Thread(() =>
{
string[] files = { "gametext" };
fileGet(files, false, true);
Invoke((Action)(() => new TextEditor(Directory.GetFiles("gametext")).ShowDialog()));
fileSet(files, true);
var g = Config.GARCGameText;
string[][] files = Config.GameTextStrings;
Invoke((Action)(() => new TextEditor(files, "gametext").ShowDialog()));
g.Files = files.Select(TextFile.getBytes).ToArray();
Config.GARCGameText.Save();
}).Start();
}
private void B_StoryText_Click(object sender, EventArgs e)
@@ -479,10 +430,11 @@ private void B_StoryText_Click(object sender, EventArgs e)
if (threadActive()) return;
new Thread(() =>
{
string[] files = { "storytext" };
fileGet(files);
Invoke((Action)(() => new TextEditor(Directory.GetFiles("storytext")).ShowDialog()));
fileSet(files);
var g = Config.getGARCData("storytext");
string[][] files = g.Files.Select(file => new TextFile(file).Lines).ToArray();
Invoke((Action)(() => new TextEditor(files, "storytext").ShowDialog()));
g.Files = files.Select(TextFile.getBytes).ToArray();
g.Save();
}).Start();
}
private void B_Maison_Click(object sender, EventArgs e)
@@ -505,21 +457,22 @@ private void B_Personal_Click(object sender, EventArgs e)
if (threadActive()) return;
new Thread(() =>
{
string[] files = { "personal" };
fileGet(files, false, true);
byte[][] d = Config.GARCPersonal.Files;
switch (Config.Generation)
{
case 6:
Invoke((Action)(() => new PersonalEditor6().ShowDialog()));
Invoke((Action)(() => new PersonalEditor6(d).ShowDialog()));
break;
case 7:
Invoke((Action)(() => new PersonalEditor7().ShowDialog()));
Invoke((Action)(() => new PersonalEditor7(d).ShowDialog()));
break;
}
// Refresh Personal Stats
// Set Master Table back
for (int i = 0; i < d.Length - 1; i++)
d[i].CopyTo(d[d.Length-1], i * d[i].Length);
Config.GARCPersonal.Save();
Config.InitializePersonal();
fileSet(files, true);
}).Start();
}
private void B_Trainer_Click(object sender, EventArgs e)
@@ -567,22 +520,29 @@ private void B_Wild_Click(object sender, EventArgs e)
}
private void B_OWSE_Click(object sender, EventArgs e)
{
bool reload = (ModifierKeys == Keys.Control) || ModifierKeys == (Keys.Alt | Keys.Control);
string[] files = { "encdata", "storytext", "mapGR", "mapMatrix" };
if (reload || files.Sum(t => Directory.Exists(t) ? 0 : 1) != 0) // Dev bypass if all exist already
fileGet(files, false);
// Only want to set back encdata.
files = new[] { "encdata" };
Invoke((MethodInvoker)delegate { Enabled = false; });
if (threadActive()) return;
new Thread(() =>
{
Invoke((Action)(() => new TextEditor(Directory.GetFiles("storytext")).Show()));
Invoke((Action)(() => new OWSE().Show()));
while (Application.OpenForms.Count > 1)
Thread.Sleep(200);
}
Invoke((MethodInvoker)delegate { Enabled = true; });
fileSet(files);
bool reload = (ModifierKeys == Keys.Control) || ModifierKeys == (Keys.Alt | Keys.Control);
string[] files = {"encdata", "storytext", "mapGR", "mapMatrix"};
if (reload || files.Sum(t => Directory.Exists(t) ? 0 : 1) != 0) // Dev bypass if all exist already
fileGet(files, false);
// Only want to set back encdata.
files = new[] {"encdata"};
Invoke((MethodInvoker) delegate { Enabled = false; });
{
var g = Config.getGARCData("storytext");
string[][] tfiles = g.Files.Select(file => new TextFile(file).Lines).ToArray();
Invoke((Action)(() => new TextEditor(tfiles, "storytext").ShowDialog()));
while (Application.OpenForms.Count > 1)
Thread.Sleep(200);
g.Files = tfiles.Select(TextFile.getBytes).ToArray();
g.Save();
}
Invoke((MethodInvoker) delegate { Enabled = true; });
fileSet(files);
}).Start();
}
private void B_Evolution_Click(object sender, EventArgs e)
{
@@ -1029,7 +989,7 @@ private void Menu_Shuffler_Click(object sender, EventArgs e)
// GARC Requests
internal static string getGARCFileName(string requestedGARC, int lang)
{
var garc = Config.getGARC(requestedGARC);
var garc = Config.getGARCReference(requestedGARC);
if (garc.LanguageVariant)
garc = garc.getRelativeGARC(lang);
@@ -1109,14 +1069,11 @@ private static void restoreGARCs(params string[] g)
// Text Requests
internal static string[] getText(TextName file)
{
string path = Path.Combine("gametext", $"{Config.getGameText(file).Index.ToString("000")}.bin");
return TextFile.getStrings(path);
return Config.GameTextStrings[Config.getGameText(file).Index];
}
internal static bool setText(TextName file, string[] strings)
{
byte[] data = TextFile.getBytes(strings);
string path = Path.Combine("gametext", $"{Config.getGameText(file).Index.ToString("000")}.bin");
File.WriteAllBytes(path, data);
Config.GameTextStrings[Config.getGameText(file).Index] = strings;
return true;
}

View File

@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.17929
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -12,7 +12,7 @@ namespace pk3DS.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
@@ -22,5 +22,29 @@ internal sealed partial class Settings : global::System.Configuration.Applicatio
return defaultInstance;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("2")]
public int Language {
get {
return ((int)(this["Language"]));
}
set {
this["Language"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string GamePath {
get {
return ((string)(this["GamePath"]));
}
set {
this["GamePath"] = value;
}
}
}
}

View File

@@ -1,7 +1,12 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="pk3DS.Properties" GeneratedClassName="Settings">
<Profiles />
<Settings>
<Setting Name="Language" Type="System.Int32" Scope="User">
<Value Profile="(Default)">2</Value>
</Setting>
<Setting Name="GamePath" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
</Settings>
</SettingsFile>

View File

@@ -15,7 +15,10 @@ public partial class LevelUpEditor6 : Form
public LevelUpEditor6()
{
InitializeComponent();
string[] specieslist = PersonalEditor6.getSpeciesIndexStrings(Main.Config.ORAS);
string[] species = Main.getText(TextName.SpeciesNames);
string[][] AltForms = Main.Config.Personal.getFormList(species, Main.Config.MaxSpeciesID);
int[] baseForm, formVal;
string[] specieslist = Main.Config.Personal.getPersonalEntryList(AltForms, species, Main.Config.MaxSpeciesID, out baseForm, out formVal);
specieslist[0] = movelist[0] = "";
string[] sortedspecies = (string[])specieslist.Clone();

View File

@@ -1,7 +1,6 @@
using System;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Media;
using System.Text;
using System.Windows.Forms;
@@ -11,7 +10,7 @@ namespace pk3DS
{
public partial class PersonalEditor6 : Form
{
public PersonalEditor6()
public PersonalEditor6(byte[][] infiles)
{
InitializeComponent();
helditem_boxes = new[] { CB_HeldItem1, CB_HeldItem2, CB_HeldItem3 };
@@ -21,22 +20,29 @@ public PersonalEditor6()
byte_boxes = new[] { TB_BaseHP, TB_BaseATK, TB_BaseDEF, TB_BaseSPA, TB_BaseSPD, TB_BaseSPE, TB_Gender, TB_HatchCycles, TB_Friendship, TB_CatchRate };
ev_boxes = new[] { TB_HPEVs, TB_ATKEVs, TB_DEFEVs, TB_SPEEVs, TB_SPAEVs, TB_SPDEVs };
rstat_boxes = new[] { CHK_rHP, CHK_rATK, CHK_rDEF, CHK_rSPA, CHK_rSPD, CHK_rSPE };
files = infiles;
abilities = Main.getText(TextName.AbilityNames);
moves = Main.getText(TextName.MoveNames);
items = Main.getText(TextName.ItemNames);
species = Main.getText(TextName.SpeciesNames);
types = Main.getText(TextName.Types);
species[0] = "---";
abilities[0] = items[0] = moves[0] = "";
string[][] AltForms = Main.Config.Personal.getFormList(species, Main.Config.MaxSpeciesID);
species = Main.Config.Personal.getPersonalEntryList(AltForms, species, Main.Config.MaxSpeciesID, out baseForms, out formVal);
data = File.ReadAllBytes(paths.Last()); // Load last to data.
Setup(); //Turn string resources into arrays
CB_Species.SelectedIndex = 1;
}
#region Global Variables
private readonly string[] paths = Directory.GetFiles("personal", "*.*", SearchOption.TopDirectoryOnly);
private readonly string mode = Main.Config.ORAS ? "ORAS" : "XY";
private readonly byte[][] files;
private string[] items = { };
private string[] moves = { };
private string[] species = { };
private string[] abilities = { };
private string[] forms = { };
private readonly byte[] data = { };
private readonly ComboBox[] helditem_boxes;
private readonly ComboBox[] ability_boxes;
@@ -66,23 +72,11 @@ public PersonalEditor6()
public ushort[] tutor3 = { 20, 173, 282, 235, 257, 272, 215, 366, 143, 220, 202, 409, 314, 264, 351, 352 };
public ushort[] tutor4 = { 380, 388, 180, 495, 270, 271, 478, 472, 283, 200, 278, 289, 446, 214, 285 };
private string[][] AltForms;
int entrysize = Main.Config.ORAS ? 0x50 : 0x40;
private readonly int[] baseForms, formVal;
int entry = -1;
#endregion
private void Setup()
{
abilities = Main.getText(TextName.AbilityNames);
moves = Main.getText(TextName.MoveNames);
items = Main.getText(TextName.ItemNames);
species = Main.getText(TextName.SpeciesNames);
types = Main.getText(TextName.Types);
forms = Main.getText(TextName.Forms);
species[0] = "---";
abilities[0] = items[0] = moves[0] = "";
AltForms = getFormList(data, Main.Config.ORAS, species, forms, types, items);
species = getPersonalEntryList(data, Main.Config.ORAS, AltForms, species);
ushort[] TMs = new ushort[0];
ushort[] HMs = new ushort[0];
TMHMEditor6.getTMHMList(Main.Config.ORAS, ref TMs, ref HMs);
@@ -255,7 +249,11 @@ private void readEntry()
readInfo();
if (dumping) return;
int[] specForm = getSpecies(data, Main.Config.ORAS, CB_Species.SelectedIndex);
int s = baseForms[entry];
int f = formVal[entry];
if (entry <= Main.Config.MaxSpeciesID)
s = entry;
int[] specForm = { s, f };
string filename = "_" + specForm[0] + (CB_Species.SelectedIndex > 721 ? "_" + (specForm[1] + 1) : "");
Bitmap rawImg = (Bitmap)Resources.ResourceManager.GetObject(filename);
Bitmap bigImg = new Bitmap(rawImg.Width * 2, rawImg.Height * 2);
@@ -334,9 +332,7 @@ private void saveEntry()
{
savePersonal();
byte[] edits = pkm.Write();
File.WriteAllBytes(paths[entry], edits);
Array.Copy(edits, 0, data, entry * edits.Length, edits.Length);
File.WriteAllBytes(paths[paths.Length - 1], data);
files[entry] = edits;
}
private void B_Randomize_Click(object sender, EventArgs e)
@@ -608,19 +604,5 @@ internal static void setForms(int species, ComboBox cb, string[][] AltForms)
}
cb.SelectedIndex = 0;
}
internal static string[] getSpeciesIndexStrings(bool oras)
{
string[] items = Main.getText(TextName.ItemNames);
string[] species = Main.getText(TextName.SpeciesNames);
string[] types = Main.getText(TextName.Types);
string[] forms = Main.getText(TextName.Forms);
species[0] = "---";
byte[] data = File.ReadAllBytes(Directory.GetFiles("personal").Last());
string[][] AltForms = getFormList(data, Main.Config.ORAS, species, forms, types, items);
species = getPersonalEntryList(data, Main.Config.ORAS, AltForms, species);
Array.Resize(ref species, oras ? species.Length : 799);
return species;
}
}
}

View File

@@ -1,7 +1,6 @@
using System;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Media;
using System.Text;
using System.Windows.Forms;
@@ -11,7 +10,7 @@ namespace pk3DS
{
public partial class PersonalEditor7 : Form
{
public PersonalEditor7()
public PersonalEditor7(byte[][] infiles)
{
InitializeComponent();
helditem_boxes = new[] { CB_HeldItem1, CB_HeldItem2, CB_HeldItem3 };
@@ -21,19 +20,18 @@ public PersonalEditor7()
byte_boxes = new[] { TB_BaseHP, TB_BaseATK, TB_BaseDEF, TB_BaseSPA, TB_BaseSPD, TB_BaseSPE, TB_Gender, TB_HatchCycles, TB_Friendship, TB_CatchRate };
ev_boxes = new[] { TB_HPEVs, TB_ATKEVs, TB_DEFEVs, TB_SPEEVs, TB_SPAEVs, TB_SPDEVs };
rstat_boxes = new[] { CHK_rHP, CHK_rATK, CHK_rDEF, CHK_rSPA, CHK_rSPD, CHK_rSPE };
data = File.ReadAllBytes(paths.Last()); // Load last to data.
Personal = new PersonalTable(data, GameVersion.SM);
files = infiles;
species[0] = "---";
abilities[0] = items[0] = moves[0] = "";
AltForms = Personal.getFormList(species, Main.Config.MaxSpeciesID);
entryNames = Personal.getPersonalEntryList(AltForms, species, Main.Config.MaxSpeciesID, out baseForms, out formVal);
var altForms = Main.Config.Personal.getFormList(species, Main.Config.MaxSpeciesID);
entryNames = Main.Config.Personal.getPersonalEntryList(altForms, species, Main.Config.MaxSpeciesID, out baseForms, out formVal);
Setup();
CB_Species.SelectedIndex = 1;
}
#region Global Variables
private readonly string[] paths = Directory.GetFiles("personal", "*.*", SearchOption.TopDirectoryOnly);
private readonly byte[][] files;
private readonly string[] items = Main.getText(TextName.ItemNames);
private readonly string[] moves = Main.getText(TextName.MoveNames);
@@ -41,8 +39,7 @@ public PersonalEditor7()
private readonly string[] abilities = Main.getText(TextName.AbilityNames);
private readonly string[] forms = Main.getText(TextName.Forms);
private readonly string[] types = Main.getText(TextName.Types);
private readonly byte[] data;
private readonly string[] entryNames;
private readonly ComboBox[] helditem_boxes;
@@ -59,9 +56,7 @@ public PersonalEditor7()
private readonly string[] colors = { "Red", "Blue", "Yellow", "Green", "Black", "Brown", "Purple", "Gray", "White", "Pink" };
private readonly ushort[] tutormoves = { 338, 307, 308, 520, 519, 518, 434, 620 };
private readonly PersonalTable Personal;
private string[][] AltForms;
private int[] baseForms, formVal;
private readonly int[] baseForms, formVal;
int entry = -1;
#endregion
private void Setup()
@@ -264,9 +259,7 @@ private void saveEntry()
{
savePersonal();
byte[] edits = pkm.Write();
File.WriteAllBytes(paths[entry], edits);
Array.Copy(edits, 0, data, entry * edits.Length, edits.Length);
File.WriteAllBytes(paths[paths.Length - 1], data);
files[entry] = edits;
}
private void B_Randomize_Click(object sender, EventArgs e)

View File

@@ -9,16 +9,19 @@ namespace pk3DS
{
public partial class TextEditor : Form
{
public TextEditor(string[] infiles)
public TextEditor(string[][] infiles, string mode)
{
InitializeComponent();
files = infiles;
Mode = mode;
for (int i = 0; i < files.Length; i++)
CB_Entry.Items.Add(i.ToString());
CB_Entry.SelectedIndex = 0;
}
private readonly string[] files;
private readonly string[][] files;
private readonly string Mode;
private int entry = -1;
// IO
private void B_Export_Click(object sender, EventArgs e)
{
@@ -54,7 +57,7 @@ private void exportTextFile(string fileName, bool newline)
for (int i = 0; i < files.Length; i++)
{
// Get Strings for the File
string[] data = TextFile.getStrings(files[i]);
string[] data = files[i];
// Append the File Header
tw.WriteLine("~~~~~~~~~~~~~~~");
tw.WriteLine("Text File : " + i);
@@ -117,7 +120,7 @@ private bool importTextFile(string fileName)
// All Text Lines received. Store all back.
for (int i = 0; i < files.Length; i++)
try { File.WriteAllBytes(files[i], TextFile.getBytes(textLines[i])); }
try { files[i] = textLines[i]; }
catch (Exception e) { Util.Error($"The input Text File (# {i}) failed to convert:", e.ToString()); return false; }
return true;
}
@@ -128,18 +131,16 @@ private void changeEntry(object sender, EventArgs e)
{
try
{
byte[] bin = TextFile.getBytes(getCurrentDGLines());
File.WriteAllBytes(files[entry], bin);
files[entry] = getCurrentDGLines();
}
catch (Exception ex) { Util.Error(ex.ToString()); }
}
// Reset
entry = CB_Entry.SelectedIndex;
string file = files[entry];
string[] data = TextFile.getStrings(file);
setStringsDataGridView(data);
setStringsDataGridView(files[entry]);
}
// Main Handling
private void setStringsDataGridView(string[] textArray)
{
@@ -229,14 +230,13 @@ private void B_RemoveLine_Click(object sender, EventArgs e)
private void xytext_FormClosing(object sender, FormClosingEventArgs e)
{
// Save All the old text
if (entry > -1) File.WriteAllBytes(files[entry], TextFile.getBytes(getCurrentDGLines()));
if (entry > -1) files[entry] = getCurrentDGLines();
}
private void B_Randomize_Click(object sender, EventArgs e)
{
// gametext can be horribly broken if randomized
string dirname = Directory.GetParent(files[entry]).Name;
if (dirname == "gametext" && DialogResult.Yes !=
if (Mode == "gametext" && DialogResult.Yes !=
Util.Prompt(MessageBoxButtons.YesNo, "Randomizing Game Text is dangerous?", "Continue?"))
return;
@@ -258,7 +258,8 @@ private void B_Randomize_Click(object sender, EventArgs e)
bool smart = drs == DialogResult.Yes;
// save current
if (entry > -1) File.WriteAllBytes(files[entry], TextFile.getBytes(getCurrentDGLines()));
if (entry > -1)
files[entry] = getCurrentDGLines();
// single-entire looping
int start = all ? 0 : entry;
@@ -268,7 +269,7 @@ private void B_Randomize_Click(object sender, EventArgs e)
List<string> strings = new List<string>();
for (int i = start; i <= end; i++)
{
string[] data = TextFile.getStrings(files[i]);
string[] data = files[i];
strings.AddRange(smart
? data.Where(line => !line.Contains("["))
: data);
@@ -282,18 +283,17 @@ private void B_Randomize_Click(object sender, EventArgs e)
int ctr = 0;
for (int i = start; i <= end; i++)
{
string[] data = TextFile.getStrings(files[i]);
string[] data = files[i];
for (int j = 0; j < data.Length; j++) // apply lines
if (!smart || !data[j].Contains("["))
data[j] = pool[ctr++];
byte[] file = TextFile.getBytes(data);
File.WriteAllBytes(files[i], file);
files[i] = data;
}
// Load current text file
setStringsDataGridView(TextFile.getStrings(files[entry]));
setStringsDataGridView(files[entry]);
Util.Alert("Strings randomized!");
}

View File

@@ -46,7 +46,7 @@ private LineInfo[] LineOffsets
result[i] = new LineInfo
{
Offset = BitConverter.ToInt32(Data, i * 8 + sdo + 4) + sdo,
Length = BitConverter.ToInt32(Data, i * 8 + sdo + 8)
Length = BitConverter.ToInt16(Data, i * 8 + sdo + 8)
};
return result;
}
@@ -319,9 +319,8 @@ private static string getVariableString(ushort variable)
}
// Exposed Methods
internal static string[] getStrings(string path)
internal static string[] getStrings(byte[] data)
{
byte[] data = File.ReadAllBytes(path);
TextFile t;
try { t = new TextFile(data); } catch { return null; }
return t.Lines;

18
pk3DS/app.config Normal file
View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="pk3DS.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
</sectionGroup>
</configSections>
<userSettings>
<pk3DS.Properties.Settings>
<setting name="Language" serializeAs="String">
<value>2</value>
</setting>
<setting name="GamePath" serializeAs="String">
<value />
</setting>
</pk3DS.Properties.Settings>
</userSettings>
</configuration>

View File

@@ -62,6 +62,7 @@
<Compile Include="3DS\BCLIM.cs" />
<Compile Include="Game\GameRNG.cs" />
<Compile Include="Game\GameVersion.cs" />
<Compile Include="Game\GARCFile.cs" />
<Compile Include="Game\GARCReference.cs" />
<Compile Include="Game\TextReference.cs" />
<Compile Include="Game\TextVariableCode.cs" />
@@ -482,6 +483,7 @@
<EmbeddedResource Include="Tools\ToolsUI.resx">
<DependentUpon>ToolsUI.cs</DependentUpon>
</EmbeddedResource>
<None Include="app.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>