Sonic Generations
From Sonic Retro
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)]