Actions

SCHG

Difference between revisions of "Sonic Generations"

From Sonic Retro

(.terrain-group)
Line 1: Line 1:
 
{{SCHG SG}}
 
{{SCHG SG}}
This is the '''[[Sonic Community Hacking Guide]] for the 2011 US/European PC version of ''[[Sonic Generations]]'''''
+
This is the '''[[Sonic Community Hacking Guide]]''' for the 2011 US/European PC version of '''[[Sonic Generations]]'''
  
 
=Hacking Tools=
 
=Hacking Tools=

Revision as of 20:02, 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 various members in and outside of the Sonic Retro community. 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.tbst

// 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_bounding_sphere;
   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 bounding_sphere_center[3]; // XYZ Coordinates
   float32_be bounding_sphere_radius;
}


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