/// <summary> /// Serialize the reference chain. This functions assumes that the Reference objects have already been written to file (i.e. the CODE chunk was before FUNC/VARI, /// which is normally always the case) /// </summary> public static void SerializeReferenceChain(UndertaleWriter writer, IList <UndertaleCode> codeList, IList <T> varList) { Dictionary <T, List <UndertaleInstruction> > references = CollectReferences(codeList); uint pos = writer.Position; foreach (T var in varList) { var.Occurrences = references.ContainsKey(var) ? (uint)references[var].Count : 0; if (var.Occurrences > 0) { var.FirstAddress = references[var][0]; for (int i = 0; i < references[var].Count; i++) { uint thisAddr = writer.GetAddressForUndertaleObject(references[var][i]); int addrDiff; if (i < references[var].Count - 1) { uint nextAddr = writer.GetAddressForUndertaleObject(references[var][i + 1]); addrDiff = (int)(nextAddr - thisAddr); } else { addrDiff = var.UnknownChainEndingValue; } writer.Position = writer.GetAddressForUndertaleObject(references[var][i].GetReference <T>()); writer.WriteInt24(addrDiff); } } else { var.FirstAddress = null; } } writer.Position = pos; }
internal override void SerializeChunk(UndertaleWriter writer) { // Update references Dictionary <UndertaleVariable, List <UndertaleInstruction> > references = UndertaleInstruction.Reference <UndertaleVariable> .CollectReferences(writer.undertaleData.Code); uint pos = writer.Position; foreach (UndertaleVariable var in List) { var.Occurrences = references.ContainsKey(var) ? (uint)references[var].Count : 0; if (var.Occurrences > 0) { var.FirstAddress = references[var][0]; for (int i = 0; i < references[var].Count; i++) { uint thisAddr = writer.GetAddressForUndertaleObject(references[var][i]); int addrDiff; if (i < references[var].Count - 1) { uint nextAddr = writer.GetAddressForUndertaleObject(references[var][i + 1]); addrDiff = (int)(nextAddr - thisAddr); } else { addrDiff = var.UnknownChainEndingValue; } // references[var][i].GetReference<UndertaleVariable>().NextOccurrenceOffset = addrDiff; /*if (addrDiff != references[var][i].GetReference<UndertaleVariable>().NextOccurrenceOffset) * Debug.WriteLine("VARI Changes at " + writer.GetAddressForUndertaleObject(references[var][i].GetReference<UndertaleVariable>()) + ": " + references[var][i].GetReference<UndertaleVariable>().NextOccurrenceOffset + " to " + addrDiff);*/ writer.Position = writer.GetAddressForUndertaleObject(references[var][i].GetReference <UndertaleVariable>()); writer.WriteInt24(addrDiff); } } else { var.FirstAddress = null; } } writer.Position = pos; writer.Write(InstanceVarCount); writer.Write(InstanceVarCountAgain); writer.Write(MaxLocalVarCount); foreach (UndertaleVariable var in List) { writer.WriteUndertaleObject(var); } }
internal override void SerializeChunk(UndertaleWriter writer) { // Update references Dictionary <UndertaleFunction, List <UndertaleInstruction> > references = UndertaleInstruction.Reference <UndertaleFunction> .CollectReferences(writer.undertaleData.Code); uint pos = writer.Position; // TODO: don't repeat the code from VARI, I spent 6 hours debugging the fact that I didn't copy one change from 0 to 1 between them :P foreach (UndertaleFunction var in Functions) { var.Occurrences = references.ContainsKey(var) ? (uint)references[var].Count : 0; if (var.Occurrences > 0) { var.FirstAddress = references[var][0]; for (int i = 0; i < references[var].Count; i++) { uint thisAddr = writer.GetAddressForUndertaleObject(references[var][i]); int addrDiff; if (i < references[var].Count - 1) { uint nextAddr = writer.GetAddressForUndertaleObject(references[var][i + 1]); addrDiff = (int)(nextAddr - thisAddr); } else { addrDiff = var.UnknownChainEndingValue; } // references[var][i].GetReference<UndertaleFunction>().NextOccurrenceOffset = addrDiff; /*if (addrDiff != references[var][i].GetReference<UndertaleFunction>().NextOccurrenceOffset) * Debug.WriteLine("FUNC Changes at " + writer.GetAddressForUndertaleObject(references[var][i].GetReference<UndertaleFunction>()) + ": " + references[var][i].GetReference<UndertaleFunction>().NextOccurrenceOffset + " to " + addrDiff);*/ writer.Position = writer.GetAddressForUndertaleObject(references[var][i].GetReference <UndertaleFunction>()); writer.WriteInt24(addrDiff); } } else { var.FirstAddress = null; } } writer.Position = pos; writer.WriteUndertaleObject(Functions); writer.WriteUndertaleObject(CodeLocals); }
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()); } }
public void Serialize(UndertaleWriter writer) { NextOccurrenceOffset = 0xdead; writer.WriteInt24(NextOccurrenceOffset); writer.Write((byte)Type); }
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: { // See unserialize if (JumpOffsetPopenvExitMagic) { writer.WriteInt24(0xF00000); } else { uint JumpOffsetFixed = (uint)JumpOffset; JumpOffsetFixed &= ~0xFF800000; writer.WriteInt24((int)JumpOffsetFixed); } writer.Write((byte)Kind); } break; case InstructionType.PopInstruction: { if (Type1 == DataType.Int16) { // Special scenario - the swap instruction // TODO: Figure out the proper syntax, see #129 writer.Write(SwapExtra); byte TypePair = (byte)((byte)Type2 << 4 | (byte)Type1); writer.Write(TypePair); writer.Write((byte)Kind); } else { 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, UndertaleChunkSTRG>)); writer.WriteUndertaleObject((UndertaleResourceById <UndertaleString, UndertaleChunkSTRG>)Value); 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()); } }