Esempio n. 1
0
        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);
        }
Esempio n. 2
0
        /// <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;
                }
            }
        }