Skip to content

Instantly share code, notes, and snippets.

@WamWooWam
Created April 9, 2020 22:37
Show Gist options
  • Save WamWooWam/ff233622fd46beb31fbd2f2718fa0d7d to your computer and use it in GitHub Desktop.
Save WamWooWam/ff233622fd46beb31fbd2f2718fa0d7d to your computer and use it in GitHub Desktop.
Sonic 4 PC AMB Repacker
using System;
using System.IO;
using System.Text;
namespace AMBRepack
{
class Program
{
private const uint MAGIC = 0x424d4123u; // #AMB
private const uint MAGIC_2 = 0x00000020u;
private const uint MAGIC_WITH_A_VENGEANCE = 0x00040000u;
private const uint LIVE_FREE_OR_MAGIC_HARD = 0xFFFFFFFFu;
static void Main(string[] args)
{
if (args.Length < 1)
return;
var directory = args[0];
var output = args[1];
output = Path.ChangeExtension(output, "AMB").ToUpperInvariant();
var files = new DirectoryInfo(directory).GetFiles();
using (var fileStream = File.Create(output))
using (var writer = new BinaryWriter(fileStream, Encoding.ASCII, true))
{
writer.Write(MAGIC);
writer.Write(MAGIC_2); // unused in game :omegalul:
writer.Write(MAGIC_WITH_A_VENGEANCE);
writer.Write(0);
// file count now
writer.Write(files.Length);
// entry table offset next
writer.Write(0x20); // safe to assume
// then data offset
writer.Write(0x20 + (0x10 * files.Length)); // easy to calculate
// then string table offset (we'll write this later)
fileStream.Position = 0x20;
var offset = (long)(0x20 + (0x10 * files.Length));
// let's write the entries then
for (var i = 0; i < files.Length; i++)
{
var file = files[i];
writer.Write((uint)offset);
writer.Write((uint)file.Length);
writer.Write(LIVE_FREE_OR_MAGIC_HARD);
writer.Write(0);
offset += file.Length;
}
// now the content
for (int i = 0; i < files.Length; i++)
{
var file = files[i];
using (var newFileStream = file.OpenRead())
{
newFileStream.CopyTo(fileStream);
}
}
// now we're at the string offset table
var stringTablePosition = (uint)fileStream.Position;
// let's write that
fileStream.Seek(0x1C, SeekOrigin.Begin);
writer.Write(stringTablePosition);
fileStream.Seek(stringTablePosition, SeekOrigin.Begin);
var array = new char[0x20];
// and let's write the table itself
for (int i = 0; i < files.Length; i++)
{
for (int j = 0; j < array.Length; j++)
array[j] = (char)0; // clear the array
var file = files[i];
var fileName = file.Name.ToUpperInvariant();
if (fileName.Length > 0x20)
{
Console.WriteLine($"Truncating {fileName}! This is bad!!");
fileName = fileName.Substring(0, 0x20);
}
fileName.CopyTo(0, array, 0, fileName.Length);
for (int j = 0; j < array.Length; j++)
writer.Write((byte)array[j]);
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment