Compare commits

...

No commits in common. '6c8b7ffc90aeb99f26661aef81f144d77c9037a8' and 'main' have entirely different histories.

63
.gitattributes vendored

@ -1,63 +0,0 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain

41
.gitignore vendored

@ -1,7 +1,8 @@
# ---> VisualStudio
## Ignore Visual Studio temporary files, build results, and ## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons. ## files generated by popular Visual Studio add-ons.
## ##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
# User-specific files # User-specific files
*.rsuser *.rsuser
@ -29,7 +30,6 @@ x86/
bld/ bld/
[Bb]in/ [Bb]in/
[Oo]bj/ [Oo]bj/
[Oo]ut/
[Ll]og/ [Ll]og/
[Ll]ogs/ [Ll]ogs/
@ -91,6 +91,7 @@ StyleCopReport.xml
*.tmp_proj *.tmp_proj
*_wpftmp.csproj *_wpftmp.csproj
*.log *.log
*.tlog
*.vspscc *.vspscc
*.vssscc *.vssscc
.builds .builds
@ -294,6 +295,17 @@ node_modules/
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw *.vbw
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
*.vbp
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
*.dsw
*.dsp
# Visual Studio 6 technical files
*.ncb
*.aps
# Visual Studio LightSwitch build output # Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts **/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts
@ -350,6 +362,9 @@ ASALocalRun/
# Local History for Visual Studio # Local History for Visual Studio
.localhistory/ .localhistory/
# Visual Studio History (VSHistory) files
.vshistory/
# BeatPulse healthcheck temp database # BeatPulse healthcheck temp database
healthchecksdb healthchecksdb
@ -361,3 +376,25 @@ MigrationBackup/
# Fody - auto-generated XML schema # Fody - auto-generated XML schema
FodyWeavers.xsd FodyWeavers.xsd
# VS Code files for those working on multiple tools
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace
# Local History for Visual Studio Code
.history/
# Windows Installer files from build outputs
*.cab
*.msi
*.msix
*.msm
*.msp
# JetBrains Rider
*.sln.iml

@ -1,25 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.14.36109.1 d17.14
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KgK _alr regenerator", "KgK _alr regenerator\KgK _alr regenerator.csproj", "{76B5F35D-7A5E-4D10-87FD-EB3E2E057DA8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{76B5F35D-7A5E-4D10-87FD-EB3E2E057DA8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{76B5F35D-7A5E-4D10-87FD-EB3E2E057DA8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{76B5F35D-7A5E-4D10-87FD-EB3E2E057DA8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{76B5F35D-7A5E-4D10-87FD-EB3E2E057DA8}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {63C2861D-EA7E-4084-AD27-8A668278BA06}
EndGlobalSection
EndGlobal

@ -1,11 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>KgK___alr_regenerator</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -1,348 +0,0 @@
using System;
using System.Drawing;
using System.IO;
using System.Text;
using static Program;
using static System.Net.Mime.MediaTypeNames;
using static System.Runtime.InteropServices.JavaScript.JSType;
class Program
{
static void Main()
{
//TEST REMOVE LATER
string[] args = new string[] { "--all", "C:\\Users\\Lauren\\Desktop\\Ken Ga Kimi\\TEST", "C:\\Users\\Lauren\\Desktop\\Ken Ga Kimi\\TEST\\OUTPUT" };
if (args.Length < 1)
{
PrintUsage();
return;
}
string outputDirectory;
switch (args[0])
{
case "--all":
if (args.Length != 3)
{
Console.WriteLine("ERROR: incorrect number of arguments");
PrintUsage();
return;
}
string inputDirectory = args[1];
outputDirectory = args[2];
// Validate and process folders
RegenerateAll(inputDirectory, outputDirectory);
break;
case "--single":
if (args.Length != 4)
{
Console.WriteLine("ERROR: incorrect number of arguments");
PrintUsage();
return;
}
string scriptName = args[1];
string alrName = args[2];
outputDirectory = args[3];
// Validate and process files
break;
default:
PrintUsage();
break;
}
}
static void PrintUsage()
{
Console.WriteLine("Console tool for regenerating Ken ga Kimi _alr files");
Console.WriteLine("Use to regenerate all _alr files or a single file");
Console.WriteLine("Adding or removing \n<ANY_TAG>\nor\n@ANY_NAME\nANY_DIALOGUE\n<pb>\n breaks single file mode");
Console.WriteLine("Usage:");
Console.WriteLine(" --all <scriptFolder> <outputDirectory>");
Console.WriteLine(" --single <scriptFile> <alrFile> <outputDirectory>");
}
public static void RegenerateAll(string inputDirectory, string outputDirectory)
{
if (!Directory.Exists(inputDirectory))
{
Console.WriteLine($"ERROR: Input folder '{inputDirectory}' does not exist.");
return;
}
//Read both _alr and script files from the input directory
List<string> alrFileNames = Directory.GetFiles(inputDirectory)
.Where(f => Path.GetFileName(f).Contains("_alr", StringComparison.OrdinalIgnoreCase))
.ToList();
List<string> scriptFileNames = Directory.GetFiles(inputDirectory)
.Where(f => !Path.GetFileName(f).Contains("_alr", StringComparison.OrdinalIgnoreCase))
.ToList();
//Create lists to hold the files
List<AlrFile> alrFiles = new List<AlrFile>();
List<ScriptFile> scriptFiles = new List<ScriptFile>();
if (alrFileNames.Count == 0)
{
Console.WriteLine("No _alr files found");
return;
}
else
{
if (!Directory.Exists(outputDirectory))
{
Directory.CreateDirectory(outputDirectory);
}
foreach (var file in alrFileNames)
{
alrFiles.Add(ReadAlrFile(file));
}
foreach (var file in scriptFileNames)
{
scriptFiles.Add(ReadScriptFile(file));
}
// Sort alrFiles by StartingFlag, with nulls first
alrFiles = alrFiles
.OrderBy(f => f.StartingFlag.HasValue ? 1 : 0) // nulls first
.ThenBy(f => f.StartingFlag)
.ToList();
int position = 0;
foreach (var alrFile in alrFiles)
{
ScriptFile? matchingScript = scriptFiles.FirstOrDefault(s => string.Equals(s.ScriptTitle, alrFile.ScriptTitle.Substring(0, alrFile.ScriptTitle.Length - 4), StringComparison.OrdinalIgnoreCase));
if (matchingScript != null)
{
byte[] alr = RegenerateAlrFile(alrFile, matchingScript, ref position);
File.WriteAllBytes(Path.Combine(outputDirectory, alrFile.FileName), alr);
}
else
{
Console.WriteLine($"No matching script file found for alr: {alrFile.ScriptTitle}");
}
}
Console.WriteLine($"Found {alrFiles.Count} _alr files in {inputDirectory}");
}
}
public static AlrFile ReadAlrFile(string filePath)
{
byte[] data = File.ReadAllBytes(filePath);
int offset = 0;
int nameLen = BitConverter.ToInt32(data, offset);
offset += 4;
if (nameLen < 0 || data.Length < offset + nameLen) {
throw new InvalidDataException("Invalid file name length in _alr file.");
}
string scriptFileName = Encoding.UTF8.GetString(data, offset, nameLen);
offset += nameLen;
int size = BitConverter.ToInt32(data, offset);
offset += 4;
offset = RoundUpToNextMultipleOf4(offset);
int uabeaOffset = offset;
var entries = new List<KeyValuePair>();
if (size > 0)
{
while (offset + 8 <= data.Length)
{
int key = BitConverter.ToInt32(data, offset);
int value = BitConverter.ToInt32(data, offset + 4);
entries.Add(new KeyValuePair { Key = key, Value = value });
offset += 8;
}
}
return new AlrFile
{
FileName = Path.GetFileName(filePath),
ScriptTitleLength = nameLen,
ScriptTitle = scriptFileName,
DataSize = size,
UabeaHeaderSize = uabeaOffset,
StartingFlag = entries.Count > 0 ? entries[0].Value : null,
Entries = entries
};
}
public static ScriptFile ReadScriptFile(string filePath)
{
string allScriptText = File.ReadAllText(filePath, Encoding.Unicode);
byte[] data = Encoding.Unicode.GetBytes(allScriptText);
int offset = 0;
int nameLen = BitConverter.ToInt32(data, offset);
offset += 4;
if (nameLen < 0 || data.Length < offset + nameLen)
{
throw new InvalidDataException("Invalid file name length in _alr file.");
}
string scriptFileName = Encoding.UTF8.GetString(data, offset, nameLen);
offset += nameLen;
offset = RoundUpToNextMultipleOf4(offset);
int size = BitConverter.ToInt32(data, offset);
offset += 4;
if (data[offset+1] == 255 && data[offset + 2] == 254) {
offset += 2;
}
//offset = RoundUpToNextMultipleOf4(offset);
int uabeaOffset = offset;
byte[] scriptText = data.Skip(uabeaOffset).ToArray();
return new ScriptFile
{
FileName = Path.GetFileName(filePath),
ScriptTitleLength = nameLen,
ScriptTitle = scriptFileName,
DataSize = size,
UabeaHeaderSize = uabeaOffset,
ScriptText = scriptText,
};
}
public static byte[] RegenerateAlrFile(AlrFile alr, ScriptFile script, ref int position)
{
List<byte> newAlr = new List<byte>();
newAlr.AddRange(BitConverter.GetBytes(alr.ScriptTitleLength));
newAlr.AddRange(Encoding.UTF8.GetBytes(alr.ScriptTitle));
if (alr.StartingFlag == null)
{
newAlr.AddRange(BitConverter.GetBytes(0));
int padding = (4 - (newAlr.Count % 4)) % 4;
for (int i = 0; i < padding; i++)
{
newAlr.Add(0x00);
}
return newAlr.ToArray();
}
else
{
//Padding for title
int padding = (4 - (newAlr.Count % 4)) % 4;
for (int i = 0; i < padding; i++)
{
newAlr.Add(0x00);
}
}
List<string> searchStrings = new List<string>() {
"\n",
"\n<voice name=",
"\n<textboxtype type=\"monologue",
"\n<textboxtype type=\"dialogue\">",
"\n<monologue background=\"on\">",
};
List<(string, int)> stringPositions = FindStringPositions(script.ScriptText, searchStrings);
//Add length of data
newAlr.AddRange(BitConverter.GetBytes(stringPositions.Count * 8));
//position += 1;
for (int i = 0; i < stringPositions.Count; i++)
{
newAlr.AddRange(BitConverter.GetBytes(stringPositions[i].Item2));
newAlr.AddRange(BitConverter.GetBytes(position));
if (stringPositions[i].Item1 != "\n")
{
position += 1;
}
else if (stringPositions[i].Item1 == "\n" && i > 0 && stringPositions[i - 1].Item1 != "\n")
{
//Don't add to position if the previous string was a tag
}
else if (stringPositions.Count == 1)
{
position += 1;
}
}
return newAlr.ToArray();
}
public static List<(string SearchString, int Position)> FindStringPositions(byte[] scriptBytes, IEnumerable<string> searchStrings)
{
var results = new List<(string, int)>();
// Decode the script bytes to string for line analysis
string scriptText = Encoding.Unicode.GetString(scriptBytes);
foreach (var search in searchStrings)
{
byte[] searchBytes = Encoding.Unicode.GetBytes(search);
int index = 0;
while (index <= scriptBytes.Length - searchBytes.Length)
{
bool match = true;
for (int j = 0; j < searchBytes.Length; j++)
{
if (scriptBytes[index + j] != searchBytes[j])
{
match = false;
break;
}
}
if (match)
{
// Find the character index in the string corresponding to this byte index
int charIndex = Encoding.Unicode.GetString(scriptBytes, 0, index).Length;
// Find the start of the line
int lineStart = scriptText.LastIndexOf('\n', charIndex - 1);
if (lineStart == -1) lineStart = 0; else lineStart++;
int lineEnd = scriptText.IndexOf('\n', charIndex);
if (lineEnd == -1) lineEnd = scriptText.Length;
string line = scriptText.Substring(lineStart, lineEnd - lineStart).TrimStart();
// Only add if the line does NOT start with //
if (!line.StartsWith("//"))
{
results.Add((search, index));
}
index += searchBytes.Length; // Move past this match
}
else
{
index++;
}
}
}
// Sort by position in order of appearance
return results.OrderBy(r => r.Item2).ToList();
}
public static int RoundUpToNextMultipleOf4(int number)
{
return (number % 4 == 0) ? number : number + (4 - (number % 4));
}
public class AlrFile
{
public string? FileName;
public int ScriptTitleLength;
public string? ScriptTitle;
public int DataSize;
public int UabeaHeaderSize;
public int? StartingFlag;
public List<KeyValuePair> Entries = new List<KeyValuePair>();
}
public class ScriptFile
{
public string? FileName;
public int ScriptTitleLength;
public string? ScriptTitle;
public int DataSize;
public int? UabeaHeaderSize;
public byte[]? ScriptText;
}
public struct KeyValuePair
{
public int Key;
public int Value;
}
}

@ -0,0 +1,4 @@
# KgK_alr_regenerator
Ken ga Kimi alr file regenerator.
Fixes the already read flags for modified scripts
Loading…
Cancel
Save