diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..80e2cdb --- /dev/null +++ b/.gitignore @@ -0,0 +1,225 @@ +# The following command works for downloading when using Git for Windows: +# curl -LOf http://gist.githubusercontent.com/kmorcinek/2710267/raw/.gitignore +# +# Download this file using PowerShell v3 under Windows with the following comand: +# Invoke-WebRequest https://gist.githubusercontent.com/kmorcinek/2710267/raw/ -OutFile .gitignore +# +# or wget: +# wget --no-check-certificate http://gist.githubusercontent.com/kmorcinek/2710267/raw/.gitignore + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Rr]elease/ +x64/ +[Bb]in/ +[Oo]bj/ +# build folder is nowadays used for build scripts and should not be ignored +#build/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# OS generated files # +.DS_Store* +Icon? + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.Publish.xml + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.[Pp]ublish.xml +*.pfx +*.publishsettings +modulesbin/ +tempbin/ + +# EPiServer Site file (VPP) +AppData/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# vim +*.txt~ +*.swp +*.swo + +# Temp files when opening LibreOffice on ubuntu +.~lock.* + +# svn +.svn + +# CVS - Source Control +**/CVS/ + +# Remainings from resolving conflicts in Source Control +*.orig + +# SQL Server files +**/App_Data/*.mdf +**/App_Data/*.ldf +**/App_Data/*.sdf + + +#LightSwitch generated files +GeneratedArtifacts/ +_Pvt_Extensions/ +ModelManifest.xml + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac desktop service store files +.DS_Store + +# SASS Compiler cache +.sass-cache + +# Visual Studio 2014 CTP +**/*.sln.ide + +# Visual Studio temp something +.vs/ + +# dotnet stuff +project.lock.json + +# VS 2015+ +*.vc.vc.opendb +*.vc.db + +# Rider +.idea/ + +# Visual Studio Code +.vscode/ + +# Output folder used by Webpack or other FE stuff +**/node_modules/* +**/wwwroot/* + +# SpecFlow specific +*.feature.cs +*.feature.xlsx.* +*.Specs_*.html + +##### +# End of core ignore list, below put you custom 'per project' settings (patterns or path) +##### \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..803933f --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Lê Hiếu + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/NieR-Text-Tool.sln b/NieR-Text-Tool.sln new file mode 100644 index 0000000..f841750 --- /dev/null +++ b/NieR-Text-Tool.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31402.337 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NieR-Text-Tool", "NieR-Text-Tool\NieR-Text-Tool.csproj", "{6EDB4357-2F91-48EE-8A54-0998F025C8C1}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6EDB4357-2F91-48EE-8A54-0998F025C8C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6EDB4357-2F91-48EE-8A54-0998F025C8C1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6EDB4357-2F91-48EE-8A54-0998F025C8C1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6EDB4357-2F91-48EE-8A54-0998F025C8C1}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {3E022B72-1C99-4507-83D6-CCB5420A9CA4} + EndGlobalSection +EndGlobal diff --git a/NieR-Text-Tool/App.config b/NieR-Text-Tool/App.config new file mode 100644 index 0000000..56efbc7 --- /dev/null +++ b/NieR-Text-Tool/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/NieR-Text-Tool/CSV.cs b/NieR-Text-Tool/CSV.cs new file mode 100644 index 0000000..550b7d8 --- /dev/null +++ b/NieR-Text-Tool/CSV.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.IO; +using Microsoft.VisualBasic.FileIO; + +namespace NieR_Text_Tool +{ + public static class CSV + { + public static string ToCSV(byte[] input) + { + string str = Encoding.UTF8.GetString(input); + string[] lines = str.Split(new string[] { "\r\n" }, StringSplitOptions.None); + List strings = new List(); + for (int i = 0; i < lines.Length; i++) + { + string[] line = lines[i].Replace("\n", "").Split(new string[] { "\t" }, StringSplitOptions.None).Select(entry => $"\"{entry.Replace("\"", "\"\"")}\"").ToArray(); + strings.Add(string.Join(",", line)); + } + string result = string.Join("\r\n", strings.ToArray()); + Dictionary gameCode = GameCode.GetGameCode(); + foreach (KeyValuePair entry in gameCode) + { + result = result.Replace(Encoding.UTF8.GetString(entry.Value), entry.Key); + } + return result; + } + + public static byte[] ToGameFormat(string input) + { + List strings = new List(); + using (TextFieldParser parser = new TextFieldParser(input)) + { + parser.TextFieldType = FieldType.Delimited; + parser.SetDelimiters(","); + parser.TrimWhiteSpace = false; + while (!parser.EndOfData) + { + string[] fields = parser.ReadFields(); + strings.Add(string.Join("\t", fields)); + } + } + string result = string.Join("\r\n", strings.ToArray()); + result = result.Replace("", "\n"); + Dictionary gameCode = GameCode.GetGameCode(); + foreach (KeyValuePair entry in gameCode) + { + result = result.Replace(entry.Key, Encoding.UTF8.GetString(entry.Value)); + } + return Encoding.UTF8.GetBytes(result); + } + } +} diff --git a/NieR-Text-Tool/GameCode.cs b/NieR-Text-Tool/GameCode.cs new file mode 100644 index 0000000..073d233 --- /dev/null +++ b/NieR-Text-Tool/GameCode.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NieR_Text_Tool +{ + public class GameCode + { + private static Dictionary _Instance; + private static Dictionary Instance() + { + Dictionary gameCode = new Dictionary(); + gameCode.Add("{01C280}", new byte[] { 0x1, 0xC2, 0x80 }); + gameCode.Add("{01C299}", new byte[] { 0x1, 0xC2, 0x99 }); + gameCode.Add("{01C29C}", new byte[] { 0x1, 0xC2, 0x9C }); + gameCode.Add("{01C297}", new byte[] { 0x1, 0xC2, 0x97 }); + gameCode.Add("{01C298}", new byte[] { 0x1, 0xC2, 0x98 }); + gameCode.Add("{01C286}", new byte[] { 0x1, 0xC2, 0x86 }); + gameCode.Add("{017E}", new byte[] { 0x1, 0x7E }); + gameCode.Add("{01C285}", new byte[] { 0x1, 0xC2, 0x85 }); + gameCode.Add("{01C2B6}", new byte[] { 0x1, 0xC2, 0xB6 }); + gameCode.Add("{01C2B5}", new byte[] { 0x1, 0xC2, 0xB5 }); + gameCode.Add("{01C28A}", new byte[] { 0x1, 0xC2, 0x8A }); + gameCode.Add("{017F}", new byte[] { 0x1, 0x7F }); + gameCode.Add("{017D}", new byte[] { 0x1, 0x7D }); + gameCode.Add("{0166}", new byte[] { 0x1, 0x66 }); + gameCode.Add("{0167}", new byte[] { 0x1, 0x67 }); + gameCode.Add("{0168}", new byte[] { 0x1, 0x68 }); + gameCode.Add("{016A}", new byte[] { 0x1, 0x6A }); + gameCode.Add("{0169}", new byte[] { 0x1, 0x69 }); + gameCode.Add("{016B}", new byte[] { 0x1, 0x6B }); + gameCode.Add("{0164}", new byte[] { 0x1, 0x64 }); + gameCode.Add("{0165}", new byte[] { 0x1, 0x65 }); + gameCode.Add("{016C}", new byte[] { 0x1, 0x6C }); + gameCode.Add("{016D}", new byte[] { 0x1, 0x6D }); + gameCode.Add("{01C283}", new byte[] { 0x1, 0xC2, 0x83 }); + gameCode.Add("{01C284}", new byte[] { 0x1, 0xC2, 0x84 }); + gameCode.Add("{01C287}", new byte[] { 0x1, 0xC2, 0x87 }); + gameCode.Add("{01C288}", new byte[] { 0x1, 0xC2, 0x88 }); + gameCode.Add("{01C289}", new byte[] { 0x1, 0xC2, 0x89 }); + gameCode.Add("{01C28B}", new byte[] { 0x1, 0xC2, 0x8B }); + gameCode.Add("{01C282}", new byte[] { 0x1, 0xC2, 0x82 }); + gameCode.Add("{01C281}", new byte[] { 0x1, 0xC2, 0x81 }); + gameCode.Add("{01C2A3}", new byte[] { 0x1, 0xC2, 0xA3 }); + gameCode.Add("{01C290}", new byte[] { 0x1, 0xC2, 0x90 }); + gameCode.Add("{01C291}", new byte[] { 0x1, 0xC2, 0x91 }); + gameCode.Add("{01C292}", new byte[] { 0x1, 0xC2, 0x92 }); + gameCode.Add("{01C293}", new byte[] { 0x1, 0xC2, 0x93 }); + gameCode.Add("{01C2A4}", new byte[] { 0x1, 0xC2, 0xA4 }); + gameCode.Add("{01C28C}", new byte[] { 0x1, 0xC2, 0x8C }); + gameCode.Add("{01C28D}", new byte[] { 0x1, 0xC2, 0x8D }); + gameCode.Add("{01C28E}", new byte[] { 0x1, 0xC2, 0x8E }); + gameCode.Add("{01C28F}", new byte[] { 0x1, 0xC2, 0x8F }); + gameCode.Add("{01C2A8}", new byte[] { 0x1, 0xC2, 0xA8 }); + return gameCode; + + } + public static Dictionary GetGameCode() + { + if (_Instance == null) + { + _Instance = Instance(); + } + return _Instance; + } + } +} diff --git a/NieR-Text-Tool/NieR-Text-Tool.csproj b/NieR-Text-Tool/NieR-Text-Tool.csproj new file mode 100644 index 0000000..eb64dc8 --- /dev/null +++ b/NieR-Text-Tool/NieR-Text-Tool.csproj @@ -0,0 +1,58 @@ + + + + + Debug + AnyCPU + {6EDB4357-2F91-48EE-8A54-0998F025C8C1} + Exe + NieR_Text_Tool + NieR-Text-Tool + v4.7.2 + 512 + true + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/NieR-Text-Tool/PACK.cs b/NieR-Text-Tool/PACK.cs new file mode 100644 index 0000000..72896d8 --- /dev/null +++ b/NieR-Text-Tool/PACK.cs @@ -0,0 +1,167 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.IO; + +namespace NieR_Text_Tool +{ + public static class PACK + { + #region Structure + public struct PackHeader + { + public int Magic; + public int Version; + public int PackSize; + public int UnkDataOffset; + public int Unk; + public int NameCount; + public int NameTableOffset; + public int Table1FileCount; + public int Table1Offset; + public int Table1RealOffset; + public int Table2FileCount; + public int Table2Offset; + public int Table2RealOffset; + } + public struct PackEntry + { + public int NameHash; + public int NameOffset; + public int RealNameOffset; + public int DataLength; + public int DataOffset; + public int RealDataOffset; + public int Unk; + public string FileName; + public byte[] FileData; + } + #endregion + public static PackHeader ReadHeader(ref BinaryReader reader) + { + reader.BaseStream.Seek(0, SeekOrigin.Begin); + PackHeader header = new PackHeader(); + header.Magic = reader.ReadInt32(); + if (header.Magic != 0x4B434150) throw new Exception("Unsupported file type."); + header.Version = reader.ReadInt32(); + header.PackSize = reader.ReadInt32(); + header.UnkDataOffset = reader.ReadInt32(); + header.Unk = reader.ReadInt32(); + header.NameCount = reader.ReadInt32(); + header.NameTableOffset = reader.ReadInt32(); + header.Table1FileCount = reader.ReadInt32(); + header.Table1Offset = reader.ReadInt32(); + header.Table1RealOffset = (int)(reader.BaseStream.Position - 4) + header.Table1Offset; + header.Table2FileCount = reader.ReadInt32(); + header.Table2Offset = reader.ReadInt32(); + header.Table2RealOffset = (int)(reader.BaseStream.Position - 4) + header.Table2Offset; + return header; + } + public static string ReadString(ref BinaryReader reader) + { + StringBuilder str = new StringBuilder(); + byte[] ch = reader.ReadBytes(1); + while (ch[0] != 0 && reader.BaseStream.Position < reader.BaseStream.Length) + { + str.Append(Encoding.ASCII.GetString(ch)); + ch = reader.ReadBytes(1); + } + return str.ToString(); + } + public static PackEntry[] ReadEntries(ref BinaryReader reader, PackHeader header) + { + List result = new List(); + reader.BaseStream.Position = header.Table2RealOffset; + for (int i = 0; i < header.Table2FileCount; i++) + { + PackEntry entry = new PackEntry(); + entry.NameHash = reader.ReadInt32(); + entry.NameOffset = reader.ReadInt32(); + entry.RealNameOffset = (int)(reader.BaseStream.Position - 4) + entry.NameOffset; + entry.DataLength = reader.ReadInt32(); + entry.DataOffset = reader.ReadInt32(); + entry.RealDataOffset = (int)(reader.BaseStream.Position - 4) + entry.DataOffset; + entry.Unk = reader.ReadInt32(); + long temp = reader.BaseStream.Position; + reader.BaseStream.Position = entry.RealNameOffset; + entry.FileName = ReadString(ref reader); + reader.BaseStream.Position = entry.RealDataOffset; + entry.FileData = reader.ReadBytes(entry.DataLength); + reader.BaseStream.Position = temp; + result.Add(entry); + } + return result.ToArray(); + } + private static byte[] Padding(int len) + { + byte[] padding = new byte[len]; + for (int i = 0; i < len; i++) + { + if (i < 8) padding[i] = 0x26; + else padding[i] = 0x40; + } + return padding; + } + public static void Unpack(string file, string des) + { + BinaryReader reader = new BinaryReader(File.OpenRead(file)); + PackHeader header = ReadHeader(ref reader); + PackEntry[] files = ReadEntries(ref reader, header); + foreach (PackEntry entry in files) + { + string filePath = Path.Combine(des, $"{entry.FileName}.csv"); + string data = CSV.ToCSV(entry.FileData); + if (!Directory.Exists(des)) Directory.CreateDirectory(des); + File.WriteAllText(filePath, data, Encoding.UTF8); + Console.WriteLine($">> {Path.GetFileName(filePath)}"); + } + reader.Close(); + } + public static void Repack(string file, string dir, string outFile) + { + MemoryStream input = new MemoryStream(File.ReadAllBytes(file)); + BinaryReader reader = new BinaryReader(input); + MemoryStream stream = new MemoryStream(); + BinaryWriter writer = new BinaryWriter(stream); + PackHeader header = ReadHeader(ref reader); + PackEntry[] entries = ReadEntries(ref reader, header); + reader.BaseStream.Seek(0, SeekOrigin.Begin); + writer.Write(reader.ReadBytes(header.Table2RealOffset)); + long tocPos = writer.BaseStream.Position; + writer.Write(new byte[0x14 * header.Table2FileCount]); + for (int i = 0; i < entries.Length; i++) + { + string filePath = Path.Combine(dir, $"{entries[i].FileName}.csv"); + if (File.Exists(filePath)) + { + entries[i].FileData = CSV.ToGameFormat(filePath); + entries[i].DataLength = entries[i].FileData.Length; + Console.WriteLine($"<< {Path.GetFileName(filePath)}"); + } + entries[i].RealDataOffset = (int)writer.BaseStream.Position; + writer.Write(entries[i].FileData); + entries[i].RealNameOffset = (int)writer.BaseStream.Position; + writer.Write(Encoding.ASCII.GetBytes(entries[i].FileName)); + writer.Write(new byte()); + long temp = writer.BaseStream.Position; + writer.BaseStream.Position = tocPos + (0x14 * i); + writer.Write(entries[i].NameHash); + writer.Write(entries[i].RealNameOffset - (int)writer.BaseStream.Position); + writer.Write(entries[i].DataLength); + writer.Write(entries[i].RealDataOffset - (int)writer.BaseStream.Position); + writer.Write(entries[i].Unk); + writer.BaseStream.Position = temp; + } + writer.BaseStream.Seek(8, SeekOrigin.Begin); + writer.Write((int)writer.BaseStream.Length); + writer.Write((int)writer.BaseStream.Length); + File.WriteAllBytes(outFile, stream.ToArray()); + reader.Close(); + writer.Close(); + input.Close(); + stream.Close(); + } + } +} diff --git a/NieR-Text-Tool/Program.cs b/NieR-Text-Tool/Program.cs new file mode 100644 index 0000000..a77bd74 --- /dev/null +++ b/NieR-Text-Tool/Program.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.IO; + +namespace NieR_Text_Tool +{ + class Program + { + static void Main(string[] args) + { + Console.Title = "NieR Replicant Text Tool by LeHieu - VietHoaGame"; + if (args.Length > 0) + { + switch (args[0]) + { + case "-e": + if (args.Length >= 3) + { + PACK.Unpack(args[1], args[2]); + } + else + { + Console.WriteLine("-> Type \"-e [Input File] [Extract Folder]\" to extract the files."); + } + break; + case "-i": + if (args.Length >= 4) + { + PACK.Repack(args[1], args[2], args[3]); + Console.WriteLine($"\n>> {args[3]}"); + } + else + { + Console.WriteLine("-> Type \"-i [Input File] [Extracted Folder] [Output File]\" to re-import the files."); + } + break; + default: + Help(); + break; + } + } + else + { + Help(); + } + } + static void Help() + { + Console.WriteLine("Usage:\n-> Type \"-e [Input File] [Extract Folder]\" to extract the files.\n-> Type \"-i [Input File] [Extracted Folder] [Output File]\" to re-import the files."); + } + } +} diff --git a/NieR-Text-Tool/Properties/AssemblyInfo.cs b/NieR-Text-Tool/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..f94441e --- /dev/null +++ b/NieR-Text-Tool/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("NieR-Text-Tool")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("NieR-Text-Tool")] +[assembly: AssemblyCopyright("Copyright © 2021")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("6edb4357-2f91-48ee-8a54-0998f025c8c1")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/NieR-Text-Tool/TXT.cs b/NieR-Text-Tool/TXT.cs new file mode 100644 index 0000000..b4a3a1d --- /dev/null +++ b/NieR-Text-Tool/TXT.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.IO; + +namespace NieR_Text_Tool +{ + public static class TXT + { + public static string ToTXT(byte[] bytes) + { + string str = Encoding.UTF8.GetString(bytes); + string[] lines = str.Split(new string[] { "\r\n" }, StringSplitOptions.None); + for (int i = 0; i < lines.Length; i++) + { + lines[i] = lines[i].Replace("\n", "").Replace("\t", ""); + } + str = string.Join("\r\n", lines); + Dictionary gameCode = GameCode.GetGameCode(); + foreach (KeyValuePair entry in gameCode) + { + str = str.Replace(Encoding.UTF8.GetString(entry.Value), entry.Key); + } + return str; + } + public static byte[] ToGameFormat(string input) + { + string str = input.Replace("", "\n").Replace("", "\t"); + Dictionary gameCode = GameCode.GetGameCode(); + foreach (KeyValuePair entry in gameCode) + { + str = str.Replace(entry.Key, Encoding.UTF8.GetString(entry.Value)); + } + return Encoding.UTF8.GetBytes(str); + } + } +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..4c0c3c0 --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +# NieR Replicant ver1.22 Text Tool + +Requires [emil.exe](https://github.com/yretenai/kaine/releases) to extract game assets. +Text files can be found at: *\snow\text*. + +## Usage: +* Type "-e [Input Text File] [Extract Folder]" to extract the file. +* Type "-i [Input Text File] [Extracted Folder] [Output File]" to re-import the file. \ No newline at end of file