public uint StartNamedScript(string name, byte [] args) { if (!namedScripts.ContainsKey(name)) { throw new ArgumentException("The specified script name does not exist"); } GTXScriptData scData = namedScripts [name]; GTXScript script = new GTXScript(this, scData.MemorySize, scData.StackSize); Support.Stack <byte> stk = new Support.Stack <byte> (scData.StackSize); script.Stack = stk; uint pID = (uint)script.GetHashCode(); script.PID = pID; runningScripts.Add(pID, script); return(pID); }
/// <summary> /// Runs the script /// </summary> /// <param name="execSingleOp">Whether to execute normally or only execute a single instruction (Useful for debugging)</param> public void Run(bool execSingleOp = false) { #pragma warning disable CS0168 // Variable is declared but never used uint runaway = 0; uint uTMP1, uTMP2, uTMP3; int sTMP1, sTMP2, sTMP3; #pragma warning restore CS0168 // Variable is declared but never used switch (state) { case GTXScriptState.Initialized: State = GTXScriptState.Running; break; case GTXScriptState.Delayed: if (--stateData == 0) { State = GTXScriptState.Running; } break; } while (state == GTXScriptState.Running) { if (++runaway == 2000000 || codePointer >= ramSize) { State = GTXScriptState.Runaway; break; } switch ((GTXPCodes)memory [codePointer++]) { case GTXPCodes.Nop: // Do nothing break; /** Flow Control **/ case GTXPCodes.Jmp: uTMP1 = PopInt(false); // pointer DoJump(uTMP1); break; case GTXPCodes.CJmp: uTMP2 = stack.Pop(); // condition uTMP1 = PopInt(false); // pointer if (uTMP2 > 0) { DoJump(uTMP1); } break; /** Comparison **/ case GTXPCodes.Eq: uTMP1 = PopInt(false); // rhs uTMP2 = PopInt(false); // lhs stack.Push(uTMP2 == uTMP1 ? byte.MinValue : (byte)byte.MaxValue); break; case GTXPCodes.Neq: uTMP1 = PopInt(false); // rhs uTMP2 = PopInt(false); // lhs stack.Push(uTMP2 != uTMP1 ? byte.MinValue : (byte)byte.MaxValue); break; // Unsigned comparison case GTXPCodes.ULt: uTMP1 = PopInt(false); // rhs uTMP2 = PopInt(false); // lhs stack.Push(uTMP2 < uTMP1 ? byte.MinValue : (byte)byte.MaxValue); break; case GTXPCodes.UGt: uTMP1 = PopInt(false); // rhs uTMP2 = PopInt(false); // lhs stack.Push(uTMP2 > uTMP1 ? byte.MinValue : (byte)byte.MaxValue); break; case GTXPCodes.ULeq: uTMP1 = PopInt(false); // rhs uTMP2 = PopInt(false); // lhs stack.Push(uTMP2 <= uTMP1 ? byte.MinValue : (byte)byte.MaxValue); break; case GTXPCodes.UGeq: uTMP1 = PopInt(false); // rhs uTMP2 = PopInt(false); // lhs stack.Push(uTMP2 >= uTMP1 ? byte.MinValue : (byte)byte.MaxValue); break; // Signed comparison case GTXPCodes.Lt: sTMP1 = PopInt(true); // rhs sTMP2 = PopInt(true); // lhs stack.Push(sTMP2 < sTMP1 ? byte.MinValue : (byte)byte.MaxValue); break; case GTXPCodes.Gt: sTMP1 = PopInt(true); // rhs sTMP2 = PopInt(true); // lhs stack.Push(sTMP2 > sTMP1 ? byte.MinValue : (byte)byte.MaxValue); break; case GTXPCodes.Leq: sTMP1 = PopInt(true); // rhs sTMP2 = PopInt(true); // lhs stack.Push(sTMP2 <= sTMP1 ? byte.MinValue : (byte)byte.MaxValue); break; case GTXPCodes.Geq: sTMP1 = PopInt(true); // rhs sTMP2 = PopInt(true); // lhs stack.Push(sTMP2 >= sTMP1 ? byte.MinValue : (byte)byte.MaxValue); break; /** Arithmetics (On stack) **/ // Unsigned arithmetic case GTXPCodes.UAdd: uTMP1 = PopInt(false); // rhs uTMP2 = PopInt(false); // lhs stack.Push(BitConverter.GetBytes(uTMP2 + uTMP1)); break; case GTXPCodes.USub: uTMP1 = PopInt(false); // rhs uTMP2 = PopInt(false); // lhs stack.Push(BitConverter.GetBytes(uTMP2 - uTMP1)); break; case GTXPCodes.UMul: uTMP1 = PopInt(false); // rhs uTMP2 = PopInt(false); // lhs stack.Push(BitConverter.GetBytes(uTMP2 * uTMP1)); break; case GTXPCodes.UDiv: uTMP1 = PopInt(false); // rhs uTMP2 = PopInt(false); // lhs if (uTMP1 == 0) { State = GTXScriptState.DivisionByZero; } else { stack.Push(BitConverter.GetBytes(uTMP2 / uTMP1)); } break; case GTXPCodes.UMod: uTMP1 = PopInt(false); // rhs uTMP2 = PopInt(false); // lhs if (uTMP1 == 0) { State = GTXScriptState.ModulusByZero; } else { stack.Push(BitConverter.GetBytes(uTMP2 % uTMP1)); } break; case GTXPCodes.UInc: uTMP1 = PopInt(false); // val stack.Push(BitConverter.GetBytes(uTMP1++)); break; case GTXPCodes.UDec: uTMP1 = PopInt(false); // val stack.Push(BitConverter.GetBytes(uTMP1--)); break; // Signed arithmetic case GTXPCodes.Add: sTMP1 = PopInt(true); // rhs sTMP2 = PopInt(true); // lhs stack.Push(BitConverter.GetBytes(sTMP2 + sTMP1)); break; case GTXPCodes.Sub: sTMP1 = PopInt(true); // rhs sTMP2 = PopInt(true); // lhs stack.Push(BitConverter.GetBytes(sTMP2 - sTMP1)); break; case GTXPCodes.Mul: sTMP1 = PopInt(true); // rhs sTMP2 = PopInt(true); // lhs stack.Push(BitConverter.GetBytes(sTMP2 * sTMP1)); break; case GTXPCodes.Div: sTMP1 = PopInt(true); // rhs sTMP2 = PopInt(true); // lhs if (sTMP1 == 0) { State = GTXScriptState.DivisionByZero; } else { stack.Push(BitConverter.GetBytes(sTMP2 / sTMP1)); } break; case GTXPCodes.Mod: sTMP1 = PopInt(true); // rhs sTMP2 = PopInt(true); // lhs if (sTMP1 == 0) { State = GTXScriptState.ModulusByZero; } else { stack.Push(BitConverter.GetBytes(sTMP2 % sTMP1)); } break; case GTXPCodes.Inc: sTMP1 = PopInt(true); // val stack.Push(BitConverter.GetBytes(sTMP1++)); break; case GTXPCodes.Dec: sTMP1 = PopInt(true); // val stack.Push(BitConverter.GetBytes(sTMP1--)); break; // Fixed-point arithmetic case GTXPCodes.KMul: sTMP1 = PopInt(true); // rhs sTMP2 = PopInt(true); // lhs stack.Push(BitConverter.GetBytes((int)(((long)sTMP2 * sTMP1) >> 16))); break; case GTXPCodes.KDiv: sTMP1 = PopInt(true); // rhs sTMP2 = PopInt(true); // lhs if (sTMP1 == 0) { State = GTXScriptState.DivisionByZero; } else { stack.Push(BitConverter.GetBytes(FixedDiv(sTMP2, sTMP1))); } break; case GTXPCodes.KMod: sTMP1 = PopInt(true); // rhs sTMP2 = PopInt(true); // lhs if (sTMP1 == 0) { State = GTXScriptState.ModulusByZero; } else { stack.Push(BitConverter.GetBytes(sTMP2 % sTMP1)); } break; /** Arithmetics (On memory) **/ // Unsigned arithmetic case GTXPCodes.UAddM: uTMP1 = BitConverter.ToUInt32(GetFromMemory(PopInt(false), 4), 0); // rhs uTMP3 = PopInt(false); // lhsPtr uTMP2 = BitConverter.ToUInt32(GetFromMemory(uTMP3, 4), 0); // lhs SetMemory(uTMP3, BitConverter.GetBytes(uTMP2 + uTMP1)); break; case GTXPCodes.USubM: uTMP1 = BitConverter.ToUInt32(GetFromMemory(PopInt(false), 4), 0); // rhs uTMP3 = PopInt(false); // lhsPtr uTMP2 = BitConverter.ToUInt32(GetFromMemory(uTMP3, 4), 0); // lhs SetMemory(uTMP3, BitConverter.GetBytes(uTMP2 - uTMP1)); break; case GTXPCodes.UMulM: uTMP1 = BitConverter.ToUInt32(GetFromMemory(PopInt(false), 4), 0); // rhs uTMP3 = PopInt(false); // lhsPtr uTMP2 = BitConverter.ToUInt32(GetFromMemory(uTMP3, 4), 0); // lhs SetMemory(uTMP3, BitConverter.GetBytes(uTMP2 * uTMP1)); break; case GTXPCodes.UDivM: uTMP1 = BitConverter.ToUInt32(GetFromMemory(PopInt(false), 4), 0); // rhs uTMP3 = PopInt(false); // lhsPtr uTMP2 = BitConverter.ToUInt32(GetFromMemory(uTMP3, 4), 0); // lhs if (uTMP1 == 0) { State = GTXScriptState.DivisionByZero; } else { SetMemory(uTMP3, BitConverter.GetBytes(uTMP2 / uTMP1)); } break; case GTXPCodes.UModM: uTMP1 = BitConverter.ToUInt32(GetFromMemory(PopInt(false), 4), 0); // rhs uTMP3 = PopInt(false); // lhsPtr uTMP2 = BitConverter.ToUInt32(GetFromMemory(uTMP3, 4), 0); // lhs if (uTMP1 == 0) { State = GTXScriptState.ModulusByZero; } else { SetMemory(uTMP3, BitConverter.GetBytes(uTMP2 % uTMP1)); } break; case GTXPCodes.UIncM: uTMP2 = PopInt(false); // valPtr uTMP1 = BitConverter.ToUInt32(GetFromMemory(uTMP2, 4), 0); // val SetMemory(uTMP2, BitConverter.GetBytes(uTMP1++)); break; case GTXPCodes.UDecM: uTMP2 = PopInt(false); // valPtr uTMP1 = BitConverter.ToUInt32(GetFromMemory(uTMP2, 4), 0); // val SetMemory(uTMP2, BitConverter.GetBytes(uTMP1--)); break; // Signed arithmetic case GTXPCodes.AddM: sTMP1 = BitConverter.ToInt32(GetFromMemory(PopInt(false), 4), 0); // rhs uTMP1 = PopInt(false); // lhsPtr sTMP2 = BitConverter.ToInt32(GetFromMemory(uTMP1, 4), 0); // lhs SetMemory(uTMP1, BitConverter.GetBytes(sTMP2 + sTMP1)); break; case GTXPCodes.SubM: sTMP1 = BitConverter.ToInt32(GetFromMemory(PopInt(false), 4), 0); // rhs uTMP1 = PopInt(false); // lhsPtr sTMP2 = BitConverter.ToInt32(GetFromMemory(uTMP1, 4), 0); // lhs SetMemory(uTMP1, BitConverter.GetBytes(sTMP2 - sTMP1)); break; case GTXPCodes.MulM: sTMP1 = BitConverter.ToInt32(GetFromMemory(PopInt(false), 4), 0); // rhs uTMP1 = PopInt(false); // lhsPtr sTMP2 = BitConverter.ToInt32(GetFromMemory(uTMP1, 4), 0); // lhs SetMemory(uTMP1, BitConverter.GetBytes(sTMP2 * sTMP1)); break; case GTXPCodes.DivM: sTMP1 = BitConverter.ToInt32(GetFromMemory(PopInt(false), 4), 0); // rhs uTMP1 = PopInt(false); // lhsPtr sTMP2 = BitConverter.ToInt32(GetFromMemory(uTMP1, 4), 0); // lhs if (sTMP1 == 0) { State = GTXScriptState.DivisionByZero; } else { SetMemory(uTMP1, BitConverter.GetBytes(sTMP2 / sTMP1)); } break; case GTXPCodes.ModM: sTMP1 = BitConverter.ToInt32(GetFromMemory(PopInt(false), 4), 0); // rhs uTMP1 = PopInt(false); // lhsPtr sTMP2 = BitConverter.ToInt32(GetFromMemory(uTMP1, 4), 0); // lhs if (sTMP1 == 0) { State = GTXScriptState.ModulusByZero; } else { SetMemory(uTMP1, BitConverter.GetBytes(sTMP2 % sTMP1)); } break; case GTXPCodes.IncM: uTMP1 = PopInt(false); // valPtr sTMP1 = BitConverter.ToInt32(GetFromMemory(uTMP1, 4), 0); // val SetMemory(uTMP1, BitConverter.GetBytes(sTMP1++)); break; case GTXPCodes.DecM: uTMP1 = PopInt(false); // valPtr sTMP1 = BitConverter.ToInt32(GetFromMemory(uTMP1, 4), 0); // val SetMemory(uTMP1, BitConverter.GetBytes(sTMP1--)); break; // Fixed-point arithmetic case GTXPCodes.KMulM: sTMP1 = BitConverter.ToInt32(GetFromMemory(PopInt(false), 4), 0); // rhs uTMP1 = PopInt(false); // lhsPtr sTMP2 = BitConverter.ToInt32(GetFromMemory(uTMP1, 4), 0); // lhs stack.Push(BitConverter.GetBytes((int)(((long)sTMP2 * sTMP1) >> 16))); break; case GTXPCodes.KDivM: sTMP1 = BitConverter.ToInt32(GetFromMemory(PopInt(false), 4), 0); // rhs uTMP1 = PopInt(false); // lhsPtr sTMP2 = BitConverter.ToInt32(GetFromMemory(uTMP1, 4), 0); // lhs if (sTMP1 == 0) { State = GTXScriptState.DivisionByZero; } else { stack.Push(BitConverter.GetBytes(FixedDiv(sTMP2, sTMP1))); } break; case GTXPCodes.KModM: sTMP1 = BitConverter.ToInt32(GetFromMemory(PopInt(false), 4), 0); // rhs uTMP1 = PopInt(false); // lhsPtr sTMP2 = BitConverter.ToInt32(GetFromMemory(uTMP1, 4), 0); // lhs if (sTMP1 == 0) { State = GTXScriptState.ModulusByZero; } else { stack.Push(BitConverter.GetBytes(sTMP2 % sTMP1)); } break; /** Script Control **/ case GTXPCodes.Terminate: State = GTXScriptState.Terminated; break; case GTXPCodes.Delay: stateData = PopInt(false); // time State = GTXScriptState.Delayed; break; case GTXPCodes.CallSpecial: uTMP1 = PopInt(false); // idx uTMP2 = PopInt(false); // amount ownerLib.Specials [uTMP1] (this, stack.PopReverse(uTMP2)); break; case GTXPCodes.CallScript: uTMP1 = PopInt(false); // idx uTMP2 = PopInt(false); // amount ownerLib.StartScript(uTMP1, stack.PopReverse(uTMP2)); break; case GTXPCodes.CallNamedScript: uTMP1 = PopInt(false); // strId uTMP2 = PopInt(false); // amount if (!ownerLib.StringTable.ContainsKey(uTMP2)) { State = GTXScriptState.Invalid; } else { ownerLib.StartNamedScript(ownerLib.StringTable [uTMP1], stack.PopReverse(uTMP2)); } break; case GTXPCodes.SWait: { uTMP1 = PopInt(false); // pID GTXScript sc = ownerLib.GetRunningScript(uTMP1); if (sc != null) { State = GTXScriptState.Delayed; uint id = pID; sc.OnStateChange += delegate { GTXScript script = ownerLib.GetRunningScript(id); script.State = GTXScriptState.Running; }; } } break; /** Stack Control **/ case GTXPCodes.Push: uTMP2 = PopInt(false); // pointer uTMP1 = PopInt(false); // amount stack.Push(GetFromMemory(uTMP2, uTMP1)); break; case GTXPCodes.PushLit: uTMP1 = BitConverter.ToUInt32(GetFromMemory(codePointer, 4), 0); // amount stack.Push(GetFromMemory(codePointer + 4, uTMP1)); codePointer += uTMP1 + 4; break; case GTXPCodes.Pop: uTMP2 = PopInt(false); // pointer uTMP1 = PopInt(false); // amount SetMemory(uTMP2, stack.PopReverse(uTMP1)); break; case GTXPCodes.Peek: uTMP2 = PopInt(false); // pointer uTMP1 = PopInt(false); // amount SetMemory(uTMP2, stack.PopReverse(uTMP1)); break; /** Memory Manipulation **/ case GTXPCodes.GStr: uTMP1 = PopInt(false); // pointer uTMP2 = PopInt(false); // strId if (!ownerLib.StringTable.ContainsKey(uTMP2)) { State = GTXScriptState.Invalid; } else { SetMemory(uTMP1, Encoding.ASCII.GetBytes(ownerLib.StringTable [uTMP2])); } break; case GTXPCodes.SetMem: sTMP1 = GetFromMemory(codePointer++, 1) [0]; // which if (sTMP1 > 0) { State = GTXScriptState.Invalid; // Not implemented break; } uTMP1 = PopInt(false); // amount uTMP2 = PopInt(false); // pointer Buffer.BlockCopy(memory, (int)codePointer, memory, (int)uTMP2, (int)uTMP1); // Not using SetMemory and GetFromMemory here for performance codePointer += uTMP1; break; case GTXPCodes.Mov: sTMP3 = GetFromMemory(codePointer++, 1) [0]; // which byte sTMP1 = (sTMP3 >> 4) & 0x0F; // src sTMP2 = sTMP3 & 0x0F; // dst if ((sTMP1 | sTMP2) > 0) { State = GTXScriptState.Invalid; // Not implemented break; } uTMP1 = PopInt(false); // amount uTMP2 = PopInt(false); // dstPointer uTMP3 = PopInt(false); // srcPointer Buffer.BlockCopy(memory, (int)uTMP3, memory, (int)uTMP2, (int)uTMP1); // Not using SetMemory and GetFromMemory here for performance break; /** Bitwise functions **/ case GTXPCodes.BShiftLeft: // Bitshifting sTMP1 = PopInt(true); // rhs uTMP1 = PopInt(false); // lhs stack.Push(BitConverter.GetBytes(uTMP1 << sTMP1)); break; case GTXPCodes.BShiftRight: sTMP1 = PopInt(true); // rhs uTMP1 = PopInt(false); // lhs stack.Push(BitConverter.GetBytes(uTMP1 >> sTMP1)); break; case GTXPCodes.BShiftLeftSign: sTMP1 = PopInt(true); // rhs sTMP2 = PopInt(true); // lhs stack.Push(BitConverter.GetBytes(sTMP2 << sTMP1)); break; case GTXPCodes.BShiftRightSign: sTMP1 = PopInt(true); // rhs sTMP2 = PopInt(true); // lhs stack.Push(BitConverter.GetBytes(sTMP2 >> sTMP1)); break; case GTXPCodes.BitXOR: uTMP1 = PopInt(false); // rhs uTMP2 = PopInt(false); // lhs stack.Push(BitConverter.GetBytes(uTMP2 ^ uTMP1)); break; case GTXPCodes.BitOR: uTMP1 = PopInt(false); // rhs uTMP2 = PopInt(false); // lhs stack.Push(BitConverter.GetBytes(uTMP2 | uTMP1)); break; case GTXPCodes.BitAND: uTMP1 = PopInt(false); // rhs uTMP2 = PopInt(false); // lhs stack.Push(BitConverter.GetBytes(uTMP2 & uTMP1)); break; case GTXPCodes.BitNOT: uTMP1 = PopInt(false); // val stack.Push(BitConverter.GetBytes(~uTMP1)); break; default: State = GTXScriptState.Invalid; // Not implemented or non-existant break; } if (execSingleOp) { break; } } }