public virtual void Unserialize(UndertaleReader reader) { if (reader.ReadBoolean()) { // The curve data is embedded in this sequence, right here IsCurveEmbedded = true; if (reader.ReadInt32() != -1) { throw new IOException("Expected -1"); } EmbeddedAnimCurve = reader.ReadUndertaleObject <UndertaleAnimationCurve>(); } else { // The curve data is an asset in the project IsCurveEmbedded = false; AssetAnimCurve = new UndertaleResourceById <UndertaleAnimationCurve, UndertaleChunkACRV>(); AssetAnimCurve.Unserialize(reader); } }
public void Unserialize(UndertaleReader reader) { uint instructionStartAddress = reader.Position; reader.ReadByte(); reader.ReadByte(); reader.ReadByte(); // skip for now, we'll read them later Kind = (Opcode)reader.ReadByte(); reader.Position = instructionStartAddress; switch (GetInstructionType(Kind)) { case InstructionType.SingleTypeInstruction: case InstructionType.DoubleTypeInstruction: case InstructionType.ComparisonInstruction: { DupExtra = reader.ReadByte(); if (DupExtra != 0 && Kind != Opcode.Dup) { throw new IOException("Invalid padding in " + Kind.ToString().ToUpper()); } ComparisonKind = (ComparisonType)reader.ReadByte(); if ((Kind == Opcode.Cmp) != ((byte)ComparisonKind != 0)) { throw new IOException("Got unexpected comparison type in " + Kind.ToString().ToUpper() + " (should be only in CMP)"); } byte TypePair = reader.ReadByte(); Type1 = (DataType)(TypePair & 0xf); Type2 = (DataType)(TypePair >> 4); if (GetInstructionType(Kind) == InstructionType.SingleTypeInstruction && Type2 != (byte)0) { throw new IOException("Second type should be 0 in " + Kind.ToString().ToUpper()); } if (reader.ReadByte() != (byte)Kind) { throw new Exception("really shouldn't happen"); } } break; case InstructionType.GotoInstruction: { uint v = reader.ReadUInt24(); // TODO: This is SO WRONG that I don't even believe it. Is that Int24 or Int23?!?! uint r = v & 0x003FFFFF; if ((v & 0x00C00000) != 0) { r |= 0xFFC00000; } JumpOffset = (int)r; JumpOffsetIsWeird = (v & 0x00800000) != 0; if (reader.ReadByte() != (byte)Kind) { throw new Exception("really shouldn't happen"); } } break; case InstructionType.PopInstruction: { TypeInst = (InstanceType)reader.ReadInt16(); byte TypePair = reader.ReadByte(); Type1 = (DataType)(TypePair & 0xf); Type2 = (DataType)(TypePair >> 4); if (reader.ReadByte() != (byte)Kind) { throw new Exception("really shouldn't happen"); } Destination = reader.ReadUndertaleObject <Reference <UndertaleVariable> >(); } break; case InstructionType.PushInstruction: { short val = reader.ReadInt16(); Type1 = (DataType)reader.ReadByte(); if (reader.ReadByte() != (byte)Kind) { throw new Exception("really shouldn't happen"); } switch (Type1) { case DataType.Double: Value = reader.ReadDouble(); break; case DataType.Float: Value = reader.ReadSingle(); break; case DataType.Int32: Value = reader.ReadInt32(); break; case DataType.Int64: Value = reader.ReadInt64(); break; case DataType.Boolean: Value = (reader.ReadUInt32() == 1); // TODO: double check break; case DataType.Variable: TypeInst = (InstanceType)val; Value = reader.ReadUndertaleObject <Reference <UndertaleVariable> >(); break; case DataType.String: UndertaleResourceById <UndertaleString> str = new UndertaleResourceById <UndertaleString>("STRG"); str.Unserialize(reader, reader.ReadInt32()); Value = str; break; case DataType.Int16: Value = val; break; } } break; case InstructionType.CallInstruction: { ArgumentsCount = reader.ReadUInt16(); Type1 = (DataType)reader.ReadByte(); if (reader.ReadByte() != (byte)Kind) { throw new Exception("really shouldn't happen"); } Function = reader.ReadUndertaleObject <Reference <UndertaleFunction> >(); } break; case InstructionType.BreakInstruction: { Value = reader.ReadInt16(); Type1 = (DataType)reader.ReadByte(); if (reader.ReadByte() != (byte)Kind) { throw new Exception("really shouldn't happen"); } } break; default: throw new IOException("Unknown opcode " + Kind.ToString().ToUpper()); } }
public void Serialize(UndertaleWriter writer) { switch (GetInstructionType(Kind)) { case InstructionType.SingleTypeInstruction: case InstructionType.DoubleTypeInstruction: case InstructionType.ComparisonInstruction: { writer.Write(DupExtra); writer.Write((byte)ComparisonKind); byte TypePair = (byte)((byte)Type2 << 4 | (byte)Type1); writer.Write(TypePair); writer.Write((byte)Kind); } break; case InstructionType.GotoInstruction: { // TODO: see unserialize // TODO: why the hell is there exactly ONE number that was NOT encoded in a weird way? If you just rewrite the file with the 'fix' it differs one one byte uint JumpOffsetFixed = (uint)JumpOffset; JumpOffsetFixed &= ~0xFF800000; if (JumpOffsetIsWeird) { JumpOffsetFixed |= 0x00800000; } writer.WriteInt24((int)JumpOffsetFixed); writer.Write((byte)Kind); } break; case InstructionType.PopInstruction: { writer.Write((short)TypeInst); byte TypePair = (byte)((byte)Type2 << 4 | (byte)Type1); writer.Write(TypePair); writer.Write((byte)Kind); writer.WriteUndertaleObject(Destination); } break; case InstructionType.PushInstruction: { if (Type1 == DataType.Int16) { Debug.Assert(Value.GetType() == typeof(short)); writer.Write((short)Value); } else if (Type1 == DataType.Variable) { writer.Write((short)TypeInst); } else { writer.Write((short)0); } writer.Write((byte)Type1); writer.Write((byte)Kind); switch (Type1) { case DataType.Double: Debug.Assert(Value.GetType() == typeof(double)); writer.Write((double)Value); break; case DataType.Float: Debug.Assert(Value.GetType() == typeof(float)); writer.Write((float)Value); break; case DataType.Int32: Debug.Assert(Value.GetType() == typeof(int)); writer.Write((int)Value); break; case DataType.Int64: Debug.Assert(Value.GetType() == typeof(long)); writer.Write((long)Value); break; case DataType.Boolean: Debug.Assert(Value.GetType() == typeof(bool)); writer.Write((bool)Value ? 1 : 0); break; case DataType.Variable: Debug.Assert(Value.GetType() == typeof(Reference <UndertaleVariable>)); writer.WriteUndertaleObject((Reference <UndertaleVariable>)Value); break; case DataType.String: Debug.Assert(Value.GetType() == typeof(UndertaleResourceById <UndertaleString>)); UndertaleResourceById <UndertaleString> str = (UndertaleResourceById <UndertaleString>)Value; writer.Write(str.Serialize(writer)); break; case DataType.Int16: break; } } break; case InstructionType.CallInstruction: { writer.Write(ArgumentsCount); writer.Write((byte)Type1); writer.Write((byte)Kind); writer.WriteUndertaleObject(Function); } break; case InstructionType.BreakInstruction: { Debug.Assert(Value.GetType() == typeof(short)); writer.Write((short)Value); writer.Write((byte)Type1); writer.Write((byte)Kind); } break; default: throw new IOException("Unknown opcode " + Kind.ToString().ToUpper()); } }