Skip to content

Commit

Permalink
Update 2.1.27: fixed random Spore crashes with certain edited RW4s
Browse files Browse the repository at this point in the history
  • Loading branch information
emd4600 committed Jan 7, 2023
1 parent ded6660 commit 41c90c0
Show file tree
Hide file tree
Showing 5 changed files with 169 additions and 28 deletions.
2 changes: 1 addition & 1 deletion src/sporemodder/UpdateManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public class UpdateManager {
*/
public static final TimeZone TIMEZONE = TimeZone.getTimeZone("UTC");

public final VersionInfo versionInfo = new VersionInfo(2, 1, 26, null);
public final VersionInfo versionInfo = new VersionInfo(2, 1, 27, null);

public static UpdateManager get() {
return MainApp.get().getUpdateManager();
Expand Down
137 changes: 137 additions & 0 deletions src/sporemodder/file/creaturedata/CreatureData.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package sporemodder.file.creaturedata;

import java.io.IOException;
import java.util.Arrays;

import sporemodder.HashManager;
import sporemodder.MainApp;
import sporemodder.file.filestructures.FileStream;
import sporemodder.file.filestructures.StreamReader;

public class CreatureData {
private void readBuffer(StreamReader stream, byte[] dst) throws IOException {
int length = dst.length;
int dstIndex = 0;
byte lastByte = 0;
int indexInBuffer = 0;
byte[] currentBuffer = null;
while (dstIndex < length) {
if (currentBuffer == null || indexInBuffer >= currentBuffer.length) {
int size = stream.readLEUShort();
if (size < 1 || size > 0x800)
throw new IOException("Found size too big (" + Integer.toString(size) + " in compressed buffer");

indexInBuffer = 0;
currentBuffer = new byte[size];
stream.read(currentBuffer);
}

if (Byte.toUnsignedInt(currentBuffer[indexInBuffer]) != 254) {
lastByte = currentBuffer[0];
dst[dstIndex] = lastByte;
dstIndex++;
}
else {
indexInBuffer++;
if (indexInBuffer < currentBuffer.length) {
int count = Byte.toUnsignedInt(currentBuffer[indexInBuffer]);
if (count == 0) {
lastByte = (byte)0xFE;
dst[dstIndex] = lastByte;
dstIndex++;
}
else {
for (int i = 0; i < count; ++i) {
dst[dstIndex + i] = lastByte;
}
dstIndex += count;
}
}
}
indexInBuffer++;
}
}

public void read(StreamReader stream) throws IOException {
int header = stream.readLEInt();
int version = stream.readLEInt();

if (header != 0xABB455B7)
throw new IOException("Unexpected header 0x" + Integer.toHexString(header));

if (version < 9 || version > 10)
throw new IOException("Unsupported version " + Integer.toString(version));

int[] counts = new int[version < 10 ? 3 : 4];
stream.readLEInts(counts);

System.out.println("Counts: " + Arrays.toString(counts));

byte[] uncompressedBuffer = new byte[version >= 8 ? (0x80 - 0x3C) : 0x80];
readBuffer(stream, uncompressedBuffer);

System.out.println("Data 0 offset: " + stream.getFilePointer());
for (int i = 0; i < counts[0]; i++) {
System.out.println(stream.getFilePointer());
stream.skip(0x8C);
}

char[][] capabilities = new char[counts[1]][4];
int[] capabilityNumbers = new int[counts[1]];

// PCTP identifiers
System.out.println("Data 1 offset 0: " + stream.getFilePointer());
for (int i = 0; i < counts[1]; i++) {
capabilities[i] = new char[4];
for (int j = 0; j < 4; j++) {
capabilities[i][j] = (char) stream.readUByte();
}
}
System.out.println("Data 1 offset 1: " + stream.getFilePointer());
for (int i = 0; i < counts[1]; i++) {
capabilityNumbers[i] = stream.readUByte();
}

int[] morphIDs = new int[counts[2]];
float[] morphValues1 = new float[counts[2]];
float[] morphValues2 = new float[counts[2]];

System.out.println("Data 2 offset 0: " + stream.getFilePointer());
stream.readLEInts(morphIDs);
System.out.println("Data 2 offset 1: " + stream.getFilePointer());
stream.readLEFloats(morphValues1);
System.out.println("Data 2 offset 2: " + stream.getFilePointer());
stream.readLEFloats(morphValues2);

int field_110 = stream.readLEInt();
System.out.println("field_110: " + HashManager.get().getFileName(field_110));
System.out.println();
System.out.println("CAPABILTIES:");
for (int i = 0; i < capabilities.length; i++) {
System.out.println("\t" + new String(capabilities[i]) + ": " + capabilityNumbers[i]);
}
System.out.println();
System.out.println("MORPHS:");
for (int i = 0; i < morphIDs.length; i++) {
System.out.println("\t" + HashManager.get().getFileName(morphIDs[i]) + ": " + morphValues1[i] + " " + morphValues2[i]);
}

if (version >= 10) {
System.out.println("Data 3 offset: " + stream.getFilePointer());
for (int i = 0; i < counts[3]; i++) {
stream.skip(0x38);
}
}
}

public static void main(String[] args) throws IOException {
MainApp.testInit();

String path = "E:\\Eric\\Eclipse Projects\\SporeModder FX\\Projects\\Player Creations\\creature_editorModel~\\0x1D79B75D.creaturedata";

try (FileStream stream = new FileStream(path, "r")) {
CreatureData creatureData = new CreatureData();
creatureData.read(stream);
}
}
}
2 changes: 1 addition & 1 deletion src/sporemodder/file/effects/SkinpaintSettingsEffect.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public class SkinpaintSettingsEffect extends EffectComponent {
public static final int FLAG_PARTBUMPSCALE = 0x10;
public static final int FLAG_PARTSPECSCALE = 0x20;
public static final int FLAG_HAIR = 0x40;
public static final int FLAG_HAIRTEXTURE = 0x40;
public static final int FLAG_HAIRTEXTURE = 0x80;
public static final int FLAG_HAIRPRINTGEOM = 0x100;
public static final int FLAG_GLOSS = 0x200;
public static final int FLAG_PHONG = 0x400;
Expand Down
16 changes: 8 additions & 8 deletions src/sporemodder/file/rw4/RWHeader.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,19 +74,19 @@ public RWHeader(RenderWare renderWare) {
*/
public List<RWSectionInfo> read(StreamReader stream, List<RWSectionInfo> sectionInfos) throws IOException {
// magic
stream.skip(28);
type = RenderWareType.get(stream.readLEInt());
stream.skip(28); // 00h
type = RenderWareType.get(stream.readLEInt()); // 1Ch

// This one is sectionCount too, but apparently Spore uses the second one
stream.skip(1 * 4);
int sectionCount = stream.readLEInt();
stream.skip(1 * 4); // 20h
int sectionCount = stream.readLEInt(); // 24h
// 0x10 if it's a model, 4 if it's a texture
// Always 0?
stream.skip(2 * 4);
long pSectionInfo = stream.readLEUInt();
stream.skip(2 * 4); // 28h
long pSectionInfo = stream.readLEUInt(); // 30h
// Always 0x98, 0, 0, 0 ?
stream.skip(4 * 4);
long pBufferData = stream.readLEUInt();
stream.skip(4 * 4); // 40h
long pBufferData = stream.readLEUInt(); // 44h

// Nothing important here
stream.skip(7 * 4);
Expand Down
40 changes: 22 additions & 18 deletions src/sporemodder/file/rw4/RenderWare.java
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,9 @@ public void write(StreamWriter stream) throws IOException {
}

// Without this, shape keys crash
stream.writePadding(48);
// To be precise, this is part of the subReferences section, this extra space is used at runtime,
// so memory gets corrupted if it doesn't have enough space
stream.writePadding(Math.max(48, header.sectionManifest.subReferences.references.size() * 0x18));

// Now write the BaseResources
long pBufferData = stream.getFilePointer();
Expand Down Expand Up @@ -420,28 +422,30 @@ public String getName(RWObject object) {
return object.getClass().getSimpleName() + '-' + sectionInfos.indexOf(object.sectionInfo);
}

public static void main(String[] args) throws IOException {
public static void main(String[] args) throws Exception {
MainApp.testInit();
//String path = "C:\\Users\\Eric\\Desktop\\ce_grasper_radial_03.rw4";
//String path = "C:\\Users\\Eric\\Desktop\\be_classic_01.rw4";
//String path = "C:\\Users\\Eric\\Desktop\\Willosaur Mouth rig 4.rw4";
//String path = "C:\\Users\\Eric\\Desktop\\ce_grasper_radial_01.rw4";
//String path = "C:\\Users\\Eric\\Desktop\\ce_mouth_beak_herbivore_04.rw4"; // ce_mouth_jaw_carnivore_01
//String path = "C:\\Users\\Eric\\Desktop\\ShapeKeys.rw4";
//String path = "C:\\Users\\Eric\\Desktop\\ce_weapon_slasher_04.rw4";
//String path = "C:\\Users\\Eric\\Downloads\\raw.rw4";
//String path = "E:\\Eric\\Eclipse Projects\\SporeModder FX\\Projects\\CustomPartTutorial\\editor_rigblocks~\\PartTutorial_ce_mouths_test.rw4";
//String path = "E:\\Eric\\Eclipse Projects\\SporeModder FX\\Projects\\DebuggingTest\\editor_rigblocks~\\ve_DI_spikeChest_01.rw4";
//String path = "E:\\Eric\\Eclipse Projects\\SporeModder FX\\Projects\\DebuggingTest\\editor_rigblocks~\\be_details_house_10.rw4";
//String path = "E:\\Eric\\Eclipse Projects\\SporeModder FX\\Projects\\GridProject\\TestModels\\ce_mouth_mandible_carnivore_04.rw4";
//String path = "C:\\Users\\Eric\\Desktop\\ce_shapes_droneBase_polished_01.rw4";
// String path = "E:\\Eric\\Eclipse Projects\\SporeModder FX\\Projects\\Spore (Game & Graphics)\\editor_rigblocks~";
//String path = "C:\\Users\\Eric\\Downloads\\ce_cubesUpdated_drone_02_B(1).rw4";
String path = "E:\\Eric\\Eclipse Projects\\SporeModder FX\\Projects\\PartTesting\\editor_rigblocks~\\ce_cubesUpdated_drone_02_B.rw4";

String path = "E:\\Eric\\Eclipse Projects\\SporeModder FX\\Projects\\Valla_SporePartsXtended\\editor_rigblock~\\ce_sense_ear_side_04.rw4";
RenderWare renderWare = RenderWare.fromFile(new File(path));
renderWare.printInfo();

System.out.println();

/*String path = "E:\\Eric\\Eclipse Projects\\SporeModder FX\\Projects\\Spore (Game & Graphics)\\editor_rigblock~";
for (String name : new File(path).list()) {
if (name.endsWith(".rw4")) {
RenderWare renderWare = RenderWare.fromFile(new File(path, name));
List<RWBlendShapeBuffer> list = renderWare.getObjects(RWBlendShapeBuffer.class);
for (RWBlendShapeBuffer obj : list) {
for (int i = 4; i <= 8; i++) {
if (obj.data[i] != null) {
System.out.println(name + ": has data index " + i);
}
}
}
}
}*/

/*String inputPath = "E:\\Eric\\Eclipse Projects\\SporeModder FX\\Projects\\ModCreatorKit_\\camera_properties~\\ce_prisms_drone_01_A_TL.rw4";
String outputPath = "E:\\Eric\\Eclipse Projects\\SporeModder FX\\Projects\\ModCreatorKit_\\camera_properties~\\ce_prisms_drone_01_A_TL test.rw4";
Expand Down

0 comments on commit 41c90c0

Please sign in to comment.