Difference between revisions of "Sonic Generations"
From Sonic Retro
Line 18: | Line 18: | ||
=File Specifications= | =File Specifications= | ||
Over the past few months, several files have had their formats cracked thanks to community member DarioFF. Here are some of the cracked format specifications: | Over the past few months, several files have had their formats cracked thanks to community member DarioFF. Here are some of the cracked format specifications: | ||
+ | ==.instanceinfo== | ||
+ | <pre> | ||
+ | // 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] | ||
+ | </pre> | ||
Line 23: | Line 119: | ||
{{SCHGuides}} | {{SCHGuides}} | ||
[[Category:Sonic Community Hacking Guide]] | [[Category:Sonic Community Hacking Guide]] | ||
+ | |||
+ | ==.material== | ||
+ | <pre> | ||
+ | // 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)] | ||
+ | </pre> |
Revision as of 15:44, 24 February 2012
SCHG: Sonic Generations |
---|
Main Article |
File Index |
BB |
How-To |
Import Levels |
This is the Sonic Community Hacking Guide for the 2011 US/European PC version of Sonic Generations
Contents
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 member DarioFF. Here are some of the cracked format specifications:
.instanceinfo
// 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)]