Actions

SCHG

Difference between revisions of "Sonic Generations"

From Sonic Retro

(File Specifications)
(.terrainblock)
Line 274: Line 274:
 
[Addresses to any declared offset in any structure whatsoever in order of writing]
 
[Addresses to any declared offset in any structure whatsoever in order of writing]
 
</pre>
 
</pre>
==.terrainblock==
+
==.terrain-block==
 
<pre>
 
<pre>
 
// Terrain Block files
 
// Terrain Block files
Line 319: Line 319:
 
[Addresses to any declared offset in any structure whatsoever in order of writing]
 
[Addresses to any declared offset in any structure whatsoever in order of writing]
 
</pre>
 
</pre>
 +
 
==.terrain-group==
 
==.terrain-group==
 
<pre>
 
<pre>

Revision as of 15:49, 24 February 2012

SCHG: Sonic Generations
Main Article

Objects
Collision Properties

File Index
BB

BB2
BB3

How-To
Import Levels

Create Breakable Objects
Create Splines

This is the Sonic Community Hacking Guide for the 2011 US/European PC version of Sonic Generations

Hacking Tools

QuickBMS

  • QuickBMS is used to extract files from Sonic Generations.
  • Primarily it is used to unpack .CPK files with this script (right click => save as).
  • However, it can also be used to unpack .ar.** files with this script. For editing purposes, it is best not to use QuickBMS to hack .ar.** files.

Cri Packed File Maker

  • Crifilesystem has a tool used specifically for hacking Sonic Generations; CriPackedFileMaker.exe
  • While QuickBMS is the best tool for extracting .CPK files, CRI Packed File Maker is the best tool for repacking (or making, rather) .CPK files.
  • Do not pack .cpk files with compression; it is unnecessary and takes extra time out of your life.
  • Data alignment is usually set to 64. Presumably this is unnecessary, but for precautionary purposes, it's best to just leave data alignment at 64.

Generations Archive Editor

  • Community member MainMemory has adapted his tool SADXsndSharp to work with Generations' .ar.** files, available here.
  • Generally this can be considered an easier way to edit .ar.** files, since individual files can be brought out for editing and put back in without having to make new .ar.** files.

File Specifications

Over the past few months, several files have had their formats cracked thanks to community members DarioFF and darkspines35. Here are some of the cracked format specifications:

.instanceinfo

// instanceinfo files
// All offsets not specified as absolute needs to be added 0x18(dec 24) to reach the right referenced address


struct header {
  uint32_be file_size; 
  uint32_be root_node_type; (likely 5)
  uint32_be sub_offset_to_offset_table;
  uint32_be offset_to_root; (absolute)
  uint32_be offset_to_offset_table; (absolute)
  uint32_be offset_to_eof; (absolute)
}


struct root_node {
  uint32_be offset_model_filename;
  uint32_be offset_matrix;
  uint32_be offset_filename;
  uint32_be instance_total; // Unknown what's this total used for?
  uint32_be offset_filename_end;
}



struct instance_matrix {
  float32_be m[16]; // 4x4 matrix, has position, scale, and rotation info
}



struct filename {
  char name[]; // Use as many characters are needed, must be null terminated, 
               // add extra padding to align the end to a 0x4 address
}


// Write after filename

// Code names for mesh loaders: alpha, beta, gamma

struct face_loader {
  uint32_be loader_offset; // offset to this struct + 4, points to the next value

  uint32_be alpha_mesh_loader_total;
  uint32_be alpha_mesh_loader_offset; // If loader total is 0, use the biggest address out of the 3 offsets

  uint32_be beta_mesh_loader_total;
  uint32_be beta_mesh_loader_offset;  // Same case as with alpha

  uint32_be gamma_mesh_loader_total;
  uint32_be gamma_mesh_loader_offset; // Same case as with alpha
}


@alpha_mesh_loader_offset

// Follow each of these offsets to reach yet another loader
uint32_be alpha_mesh_offset[alpha_mesh_loader_total];


struct alpha_mesh_loader {
   uint32_be alpha_mesh_total;
   uint32_be alpha_mesh_offset; // Leads to sub_alpha_mesh_offset
}

// Follow these to reach a sub_loader_alpha_mesh_offset
uint32_be sub_alpha_mesh_offset[alpha_mesh_total];

// Offset to sub_alpha_mesh
uint32_be sub_loader_alpha_mesh_offset;

struct sub_alpha_mesh {
  uint32_be unknown_total;
  uint32_be unknown_offset;
  uint32_be face_count;
  uint32_be face_data_start_offset;
  uint32_be unknown_value; // Most of the time 4. unknown_offset points to it

  // Read new faces as triangle strips, each 65535 value means a new strip starts
  uint16_be face_data[face_count];
  
  uint16_be optional_padding; // Add if face_count is an odd value so the structure aligns to 0x4
} 

// *  Repeat the above structures for beta and gamma mesh loaders  *

struct final_offset_table {
   uint32_be offset_count;
   uint32_be offset_table[offset_count];
   uint32_be padding=0; // Marks end of file
}

Offset table contents:
[Addresses to any declared offset in any structure whatsoever in order of writing]

.material

// Material files

// Any offsets not declared as absolute must be added 0x18(dec 24) to reach the proper referenced address

struct header {
   uint32_be file_size;
   uint32_be root_node_type; // Most of the time 3 for Generations
                             // 1 for Unleashed

   uint32_be offset_final_table;
   uint32_be root_node_offset; // Always 24
   uint32_be offset_final_table_abs; // (Absolute)
   uint32_be padding=0;
}


struct root_node {
   uint32_be offset_type_string;
   uint32_be offset_type_string_2;

   uint32_be texset_offset;
   uint32_be texture_offset;
   
   uint32_be unknown_value; // Probably 2 short ints, or 1 byte multipler/scale uv components
 
   uint8 total_material_definitions;
   uint8 unknown_ints[2]={0,0};
   uint8 total_texture_info; // Used for texset and texture tables
   
   uint32_be offset_to_material_offset_table;
   uint32_be unknown_value_2=0;
   uint32_be unknown_value_3=0;

   char type_string_1[]; // Null terminated, no padding needed
   char type_string_2[]; // Null terminated, add padding to reach 0x4 address at the end

   
   uint32_be material_definition_offset_table[total_material_definitions];
}

// Write this structure total_material_definitions times, fill with 0s and null strings
// the marked values if not used

struct material_definition {
   uint16_be map_size_width;
   uint16_be map_size_height;
   uint32_be offset_mat_name;
   uint32_be offset_rgba;
   
   char mat_name[]; // Null terminated, add padding to reach 0x4 address at the end
                    // Write 4 null bytes in case there's no name
   
   float32_be rgba_values[4]; // 4th value is 0 most of the time
                              // Fill with 0s if not used
}


// Read at texset_offset, only 1 structure
uint32_be texset_name_offset_table[total_texture_info];


// Read on each offset a null terminated string
// last string adds padding to reach a 0x4 address
char texset_name[total_texture_info][];




uint32_be texture_offset_table[total_texture_info];


struct texture_info {
   uint32_be offset_tex_name;
   uint32_be unknown_total=0;
   uint32_be offset_tex_type_name;
   char tex_name[]; // Null terminated, no padding needed
   char tex_type_name[]; // Null terminated, add padding to reach a 0x4 address at the end
}


// Final offset table

struct final_offset_table {
  uint32_be offset_total;
  uint32_be offset_table[offset_total];
}

// Since the first EOF offset in the header is 0, there's no need to write an extra 0 value at the end
// of the offset table

Offset table contents: 
[Addresses to any declared offset in any structure whatsoever in order of writing the file(non-absolute)]

.pfi

struct header {

  uint32_be file_size;
  uint32_be root_node_type; // most cases for pfis is 0
  uint32_be struct_table_offset; // Add 0x18(dec 24) to reach it
  uint32_be root_node_offset; // always 0x18(dec 24)
  uint32_be struct_table_offset_2; // Same as before but already has an additional 0x18
  uint32_be end_of_file_offset; // file_size - 4

}

// Write the root node after the main header. Only 1 root node is needed

struct root_node {

  uint32_be ar_package_total;  // Ammount of AR files the PFD has.
  uint32_be ar_offset_table_address;  // Add 0x18(dec 24) to it to reach the table

}

struct ar_offset_table {

  // For writing this one, just fill it with blank if you want
  // then fill it after you're done with the rest

  // Each address is relative to the start of the file plus 0x18(as with any other pointers)
  // The address points to each of the package info structs below

  uint32_be ar_package_offset[ar_package_total];

}

// Write the following structure ar_package_total times
// And fill the offsets of the previous table with them

struct ar_package_info {

  uint32_be package_name_offset; // Pointer to the name of the AR file
  uint32_be package_pfd_offset;  // Absolute offset of the ar file inside the PFD(not needed to add 0x18)
  uint32_be package_size; // Absolute size of the AR file, in bytes
  char name[]; // Size is as long as the ar filename, adds padding if it doesn't align to 0x4 at the end.
}



// There's another extra offsets table of structures written at the end
// After writing all of the above, you have to write the following

struct final_offset_table {
  uint32_be offset_total; // Considering PFIs, this would be ar_package_total*2 + 1
  uint32_be offset_table[offset_total];
  uint32_be padding; // Just an extra 0 to fill the end of file
}

// This final offset table is filled with the following
// All of them use the pointer math I mentioned before(add 0x18(dec 24) to all of them)


Offset table contents:
[Addresses to any declared offset in any structure whatsoever in order of writing]

.terrain-block

// Terrain Block files

struct header {
   uint32_be file_size;
   uint32_be root_node_type; // Most of the time 1
   uint32_be offset_final_table;
   uint32_be root_node_offset; // Always 24
   uint32_be offset_final_table_abs; // (Absolute)
   uint32_be offset_eof; (Absolute)
}


struct root_node {
   uint32_be instance_total;
   uint32_be instance_table_offset;
   uint32_be unknown_total; // Equals instance_total - 1?
}

// Offset to each Instanceinfo structure
uint32_be instance_offset_table[instance_total];

struct instance_info {
   uint32_be unknown_total_1;
   uint32_be stage_block_id_1;
   uint32_be stage_block_id_2;
   uint32_be offset_to_bounding_sphere_center;
   float32_be bounding_sphere_center[3]; // XYZ coordinates
   float32_be bounding_sphere_radius;
}



// Final offset table

struct final_offset_table {
  uint32_be offset_total;
  uint32_be offset_table[offset_total];
  uint32_be extra_padding_eof=0;
}

Offset table contents:
[Addresses to any declared offset in any structure whatsoever in order of writing]

.terrain-group

// Terrain Group file

struct header {
   uint32_be file_size;
   uint32_be root_node_type; // Most of the time 1
   uint32_be offset_final_table;
   uint32_be root_node_offset; // Always 24
   uint32_be offset_final_table_abs; // (Absolute)
   uint32_be offset_eof; (Absolute)
}

struct root_node {
   uint32_be instanceinfo_total;
   uint32_be instanceinfo_offset_table; // Address to a table
   uint32_be terrainmodel_total;
   uint32_be terrainmodel_offset_table; // Address to a table
}

uint32_be instanceinfo_offsets[instanceinfo_total];


struct instance_info {
   uint32_be filename_total;
   uint32_be offset_to_filename_offset;
   uint32_be offset_to_quaternion;
   uint32_be offset_to_filename[filename_total];
   char filename[filename_total][]; // Null-terminated, add padding to reach a 0x4 multiple at the end of each string
   float32_be unknown_quaternion[4];
}


uint32_be terrainmodel_offsets[terrainmodel_total];


struct terrainmodel_info {
   char filename[]; // Null-terminated, add padding to reach a 0x4 multiple
}


// All filenames don't have the extension

// Final offset table

struct final_offset_table {
  uint32_be offset_total;
  uint32_be offset_table[offset_total];
  uint32_be extra_padding_eof=0;
}

Offset table contents:
[Addresses to any declared offset in any structure whatsoever in order of writing]

==========
EOF

.terrain

// Terrain.terrain files

// Any offsets not declared as absolute must be added 0x18(dec 24) to reach the proper referenced address

struct header {
   uint32_be file_size;
   uint32_be root_node_type; // Most of the time 1
   uint32_be offset_final_table;
   uint32_be root_node_offset; // Always 24
   uint32_be offset_final_table_abs; // (Absolute)
   uint32_be offset_eof; (Absolute)
}


struct root_node {
   uint32_be group_total;
   uint32_be group_table_offset;
}


// Offset to each group_info structure
uint32_be group_offset_table[group_total];

struct group_info {
   uint32_be offset_to_bounding_sphere_center;
   uint32_be offset_to_center_position;
   uint32_be unknown_offset;
   uint32_be spheres_total; // Matches up to the ammount of unique instances, as in, the ones that don't start
                            // with the same prefix name
   uint32_be offset_to_sphere_offset_table;
   int32_be unknown_value=-1;

   float32_be center_position_x;
   float32_be center_position_y;
   float32_be center_position_z;
   float32_be center_position_radius;

   char filename[]; // Null terminated, add padding to reach a 0x4 address at the end

   // Offset to each group_instance_info_sphere structure
   uint32_be sphere_offset_table[spheres_total];
}


// Write this structure after it spheres_total times

struct group_instance_info_sphere {
   float32_be center_x;
   float32_be center_y;
   float32_be center_z;
   float32_be center_radius;
}



// Final offset table

struct final_offset_table {
  uint32_be offset_total;
  uint32_be offset_table[offset_total];
  uint32_be extra_padding_eof=0;
}

Offset table contents: 
[Addresses to any declared offset in any structure whatsoever in order of writing the file(non-absolute)]


Sonic Community Hacking Guide
General
SonED2 Manual | Subroutine Equivalency List
Game-Specific
Sonic the Hedgehog (16-bit) | Sonic the Hedgehog (8-bit) | Sonic CD (prototype 510) | Sonic CD | Sonic CD (PC) | Sonic CD (2011) | Sonic 2 (Simon Wai prototype) | Sonic 2 (16-bit) | Sonic 2 (Master System) | Sonic 3 | Sonic 3 & Knuckles | Chaotix | Sonic Jam | Sonic Jam 6 | Sonic Adventure | Sonic Adventure DX: Director's Cut | Sonic Adventure DX: PC | Sonic Adventure (2010) | Sonic Adventure 2 | Sonic Adventure 2: Battle | Sonic Adventure 2 (PC) | Sonic Heroes | Sonic Riders | Sonic the Hedgehog (2006) | Sonic & Sega All-Stars Racing | Sonic Unleashed (Xbox 360/PS3) | Sonic Colours | Sonic Generations | Sonic Forces
Technical information
Sonic Eraser | Sonic 2 (Nick Arcade prototype) | Sonic CD (prototype; 1992-12-04) | Dr. Robotnik's Mean Bean Machine | Sonic Triple Trouble | Tails Adventures | Sonic Crackers | Sonic 3D: Flickies' Island | Sonic & Knuckles Collection | Sonic R | Sonic Shuffle | Sonic Advance | Sonic Advance 3 | Sonic Battle | Shadow the Hedgehog | Sonic Rush | Sonic Classic Collection | Sonic Free Riders | Sonic Lost World
Legacy Guides
The Nemesis Hacking Guides The Esrael Hacking Guides
ROM: Sonic 1 | Sonic 2 | Sonic 2 Beta | Sonic 3

Savestate: Sonic 1 | Sonic 2 Beta/Final | Sonic 3

Sonic 1 (English / Portuguese) | Sonic 2 Beta (English / Portuguese) | Sonic 2 and Knuckles (English / Portuguese)
Move to Sega Retro
Number Systems (or scrap) | Assembly Hacking Guide | 68000 Instruction Set | 68000 ASM-to-Hex Code Reference | SMPS Music Hacking Guide | Mega Drive technical information