The HaruhiChokuretsuLib project is the primary library on which the rest of the solution depends. It contains a Helpers class with various helper methods as well as three namespaces.
Before reading this documentation, it is recommended you familiarize yourself with the reverse engineering documentation as it will provide context for what is being described here.
The following helper methods are available:
DecompressData()
andCompressData()
– Implementations of the Shade compression algorithm that accept and return byte arrays.GetPaletteFromImage()
– A simplified implementation of this palette extraction routine. Creates an arbitrarily sized palette of colors used in an image. Used for changing palette data in Shade texture files.ByteArrayFromString()
andStringFromByteArray()
– This pair of methods converts to and from hexadecimal strings and byte arrays.BytesInARowLessThan()
– Returns true if a specific byte is repeated less than a certain number of times in a row in a given sequence.AddWillCauseCarry()
– Returns true if an addition operation will cause a carry (used in the unhinged file length routine).ClosestColorIndex()
– Returns the closest match of a color in a given palette.
This namespace contains the logic for interacting with the .bin
archives in the game (dat.bin
, evt.bin
, grp.bin
, and scn.bin
).
The classes it contains are:
This is the top-level class which abstracts the .bin
file itself. It's a generic class which can be instantiated to contain a list of files of
any of the other classes in this namespace. It contains methods for instantiating all of the files in a given archive and keeping track of their
offsets and file sizes.
- The standard way to instantiate an
ArchiveFile
is with theArchiveFile<T>.FromFile()
method. - Since file indices do not necessarily match up with the position in
Archive.Files
, the proper way to access a file by index is:archiveFile.GetFileByIndex(index);
- To replace a file in a repo, you should create a new file of the archive's type, initialize it, set the
Edited
flag on the file, and then set the file inarchive.Files
at the replacement index to the new file. Example:ArchiveFile<GraphicsFile> grpArchive = ArchiveFile<GraphicsFile>.FromFile("path/to/grp.bin"); int replacementIndex = 0xC1A; string decompressedFilePath = "path/to/decompressed_file"; GraphicsFile currentFile = grpArchive.GetFileByIndex(index); GraphicsFile newGraphicsFile = new(); newGraphicsFile.Initialize(File.ReadAllBytes(decompressedFilePath), currentFile.Offset); newGraphicsFile.Edited = true; grpArchive.Files[grpArchive.Files.IndexOf(currentFile)] = newGraphicsFile;
- To add a file to an archive, simply instatiate a new file and use
archive.AddFile()
.
This is the base class for all other file types. All FileInArchive
types have the following properties:
uint MagicInteger
– The "magic integer" in the archive header that contains the file's offset and compressed length.int Index
– The index of the file in the archive (not the same as its absolute position).int Offset
– The offset of the file in the archive. Contained in the MagicInteger.int Length
– The compressed length of the file. Contained in the MagicInteger.List<byte> Data
– The decompressed binary data of the file.byte[] CompressedData
– The compressed binary data of the file (what's found in the archive).bool Edited
– A flag indicating that this file has been edited. This is used to determine if the file's data should be recompressed or if the compressed data should be used on reinsertion.
Additionally, FileInArchive
types have the following methods:
Initialize()
– Initializes the file given decompressed data and an offset.GetBytes()
– Constructs the decompressed binary data of the file.NewFile()
– Creates a new file from scratch.
This is a basic implementation of archive files whose types are not fully understood. It simply is a container for their binary data.
This is an implementation of the event files found in evt.bin
. These files are mostly composed of pointers and Shift-JIS encoded strings.
While it's designed to represent event files, the EventFile
class can also be used to represent special string files.
In addition to the properties it inherits from FileInArchive
, EventFile
s contain the following properties:
List<int> FrontPointers
– A list containing all of the pointers that appear at the beginning of the file.int PointerToEndPointerSection
– The pointer to the end pointers section.List<int> EndPointers
– A list containing all of the pointers that appear at the end of the file.List<int> EndPointerPointers
– A list containing all of the pointers that the end pointers point to.string Title
– If one exists, the title of the event file (e.g., EV1_001).Dictionary<int, string> DramatisPersonae
– A dictionary containing the offsets and names of the characters denoted in the dramatis personae section.int DialogueSectionPointer
– A pointer to the dialogue section.List<DialogueLine> DialogueLines
– The dialogue lines contained in this event.List<TopicStruct> TopicStructs
– In #0x245 (the Topic file), this represents all of the topic structs in the file. In main event files, this represents the obtainable topics in that event.FontReplacementDictionary FontReplacementMap
– The font replacement (charset) map.
It also has the following methods:
InitializeDialogueForSpecialFiles()
– This initializes files that are not standard event files but still have strings (the string files indat.bin
and files #0x244 and #0x245 inevt.bin
are the primary examples).InitializeTopicFile()
– An initialization routine that is called specifically for #0x245 inevt.bin
afterInitializeDialougeForSpecialFiles
is called.IdentifyEventFileTopics()
– Identify the topics from the Control Section of main event files.ShiftPointers()
– Shifts all pointers in the file based on a location in the file and an amount to shift. Every pointer that points to something after the specified location has its value shifted by the specified amount.EditDialogueLine()
– Edits a line of dialogue, including callingShiftPointers()
after editing.WriteResxFile()
– Writes all dialogue lines to a .NET Resource (RESX) file.ImportResxFile()
– Reads all dialogue lines from a .NET Resource (RESX) file and replaces the dialogue in the file with those lines. The following changes are made to strings in the file:- Three dots (
...
) are replaced by an ellipsis character (…
) - Two hyphens (
--
) are replaced by an em-dash character (—
) - Replaces Windows linebreaks (
\r\n
) with Unix-style ones (\n
) - Replaces text according to the
FontReplacementMap
. - Automatically introduces line breaks past to prevent text from going off the screen (in non-dat files)
- Three dots (
NewFile()
is not implemented for EventFile
s.
The following sub-classes are used by the EventFile
class:
The DialogueLine
class abstracts the structs in the Dialogue Section of the event file. It has the following properties:
int Pointer
– The pointer to the dialogue text; corresponds to the third int in the struct.byte[] Data
– The binary data of the dialogue text string.int NumPaddingZeroes
– The number of zeroes added to pad the string to four-byte alignment.string Text
– An string abstraction of theData
property.int Length
– The length of theData
property.int SpeakerPointer
– The pointer to the Dramatis Personae section speaker name, corresponds to the second int of the struct.Speaker Speaker
– An enum value representing the speaker of the dialogue line. Corresponds to the first int of the struct.string SpeakerName
– The string value found at theSpeakerPointer
position.
The TopicStruct
class abstracts the structs found in the Topics file #0x245. It has the following properties:
int ToipcDialogueIndex
– An index representing whichDialogueLine
this Topic corresponds to.string Title
– The title of the Topic (equivalent to the text of the dialogue line).short Id
– The ID of the topic, corresponding to the first short of the struct.short EventIndex
– The event this topic triggers during the puzzle phase, corresponding to the second short of the struct.short[] UnknownShorts
– The following 16 unknown shorts in the struct (0x20 bytes).
The GraphicsFile
class is designed to implement the files found in grp.bin
; however, while most of the files are understood and can be parsed, there are still
some that remain unknown.
The property that determines what type of graphic a given file is is the FileFunction
property which uses the Function
enum. The options are SHTX
, LAYOUT
, and UNKNOWN
.
When FileFunction
is set to Function.SHTX
(which happens if the first four bytes of the file are SHTX
), the class implements a Shade Texture file. The following properties
become relevant:
List<byte> PaletteData
– Contains the binary palette data of the image.List<SKColor> Palette
– Contains the colors of the image's palette.List<byte> PixelData
– Contains the image's binary pixel data.int Width
– The image's width.int Height
– The image's height.TileForm ImageTileForm
– Whether the image is a 16-color/4BPP image or a 256-color/8BPP image.Form ImageForm
– Whether the image is a texture, a tile image, or unknown.public string Determinant
– The two bits followingSHTX
(eitherDS
orD5
).
Furthermore, the following methods are relevant:
NewFile()
– Only implemented for SHTX files.InitializeFontFile()
– Initializes the font file (#0xE50) which is a special file only containing pixel data.IsTexture()
– Manually determines whether a file is ofForm
TILE
orTEXTURE
. Since there isn't a known way to determine this from file data, this is manually constructed based on position within the archive.GetImage()
– Returns a bitmap image of the SHTX file. Optionally allows specifying a transparent index, an index into the palette that will be made transparent (in reality almost always 0).SetImage()
– Sets the pixel data to that of a bitmap in memory or bitmap file provided. Optionally, can set a flag to create a new palette from the image, and can set a transparent index.GetPalette()
– Gets a bitmap image representing the palette data of the image.SetPalette()
– Accepts aList<SKColor>
to set as the palette for the image.
When FileFunction
is set to Function.LAYOUT
(which happens if the first four bytes are either 0x0001C000 or 0x10048802), the class implements a layout file. The only
relevant property for layouts is List<LayoutEntry> LayoutEntries
, which abstracts the layout entry struct.
The only relevant method is GetLayout()
, which returns a bitmap representation of the given layout entries as well as those layout entries.
The LayoutEntry
class, however, is immediately relevant. All of its properties are self-explanatory and line up exactly with those described in the reverse engineering documentation.
The Font namespace is composed of two classes and simply provides the logic for interacting with the font-width ASM hack we have implemented. The first class, the FontReplacement
class,
is an abstraction of the font replacement JSON and contains information on the OriginalCharacter
in the script, the character we replace it with (ReplacedCharacter
), the Shift-JIS
CodePoint
where the replacement occurs, and the amount the character is Offset
. This then feeds into a FontReplacementDictionary
, a class which implements IDictionary
and allows for
easy lookup into a List<FontReplacement>
.
This namespace contains the methods to aid in interacting with the game's overlays.
The Overlay
class is an abstraction of an overlay. It contains the following properties:
string Name
– The name of the overlay (e.g., main_0001).int Id
– The overlay's ID (e.g., 1). This is determined by parsing the last four characters of the overlay's name as a hex number.List<byte> Data
– The binary assembled instructions of the overlay.
It also contains the following methods:
Overlay(string file)
– The constructor takes a file and uses its name as theName
and its contents as theData
.Save()
– Writes the contents ofData
to a given file.Patch()
– Replaces binary data at a particular point with provided patch data.Append()
– Takes data to append and the path to an NDS project file that contains an XML representation of the overlay table. This method appends the data to the end of the array and then modifies the overlay table to reflect the updated size of the overlay.
This class simply serializes the Riivolution-style overlay patch documents.