/* =========================================================================== Copyright (C) 2015 the OpenMoHAA team This file is part of OpenMoHAA source code. OpenMoHAA source code is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. OpenMoHAA source code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenMoHAA source code; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ // scriptvm.h: Script virtual machine interpreter. #ifndef __SCRIPTVM_H__ #define __SCRIPTVM_H__ #include "listener.h" #include "../fgame/gamescript.h" #include "scriptvariable.h" #include "scriptopcodes.h" #include "../qcommon/con_set.h" #define MAX_STACK_DEPTH 20 // 9 in mohaa //#define LOCALSTACK_SIZE 255 // pre-allocated localstack size for each VM #define MAX_SCRIPTCYCLES 9999 // max cmds #define STATE_RUNNING 0 // Running #define STATE_SUSPENDED 1 // Suspended #define STATE_WAITING 2 // Waiting for something #define STATE_EXECUTION 3 // Resume to execution #define STATE_DESTROYED 4 // Pending deletion #define THREAD_RUNNING 0 // Running #define THREAD_WAITING 1 // Waiting #define THREAD_SUSPENDED 2 // Suspended #define THREAD_CONTEXT_SWITCH 3 // Resume from context switch class ScriptException; class ScriptThread; class ScriptVM; class ScriptCallStack { public: // opcode variable unsigned char *codePos; // opcode will be restored once a DONE was hit // stack variables ScriptVariable *localStack; ScriptVariable *pTop; // return variable ScriptVariable returnValue; // OLD self value SafePtr m_Self; }; class ScriptStack { public: ScriptVariable *m_Array; int m_Count; }; class ScriptVMStack { public: ScriptVMStack(); ScriptVMStack(size_t stackSize); ~ScriptVMStack(); ScriptVMStack(const ScriptVMStack& other) = delete; ScriptVMStack& operator=(const ScriptVMStack& other) = delete; ScriptVMStack(ScriptVMStack&& other); ScriptVMStack& operator=(ScriptVMStack&& other); size_t GetStackSize() const; ScriptVariable& SetTop(ScriptVariable& newTop); ScriptVariable& GetTop() const; ScriptVariable& GetTop(size_t offset) const; ScriptVariable *GetTopPtr() const; ScriptVariable *GetTopPtr(size_t offset) const; ScriptVariable *GetTopArray(size_t offset = 0) const; uintptr_t GetIndex() const; void MoveTop(ScriptVariable &&other); ScriptVariable *GetListenerVar(uintptr_t index); void SetListenerVar(uintptr_t index, ScriptVariable *newVar); /** Pop and return the previous value. */ ScriptVariable& Pop(); ScriptVariable& Pop(size_t offset); ScriptVariable& PopAndGet(); ScriptVariable& PopAndGet(size_t offset); /** Push and return the previous value. */ ScriptVariable& Push(); ScriptVariable& Push(size_t offset); ScriptVariable& PushAndGet(); ScriptVariable& PushAndGet(size_t offset); private: /** The VM's local stack. */ ScriptVariable *localStack; /** The local stack size. */ ScriptVariable *stackBottom; /** Variable from the top stack of the local stack. */ ScriptVariable *pTop; ScriptVariable **listenerVarPtr; }; class ScriptVM { friend class ScriptThread; public: // important thread variables ScriptVM *next; // next VM in the current ScriptClass ScriptThread *m_Thread; // script thread ScriptClass *m_ScriptClass; // current group of threads public: // return variables ScriptStack *m_Stack; // Currently unused ScriptVMStack m_VMStack; ScriptVariable m_ReturnValue; // VM return value // opcode variables unsigned char *m_PrevCodePos; // previous opcode, for use with script exceptions unsigned char *m_CodePos; // check compiler.h for the list of all opcodes public: // states unsigned char state; // current VM state unsigned char m_ThreadState; // current thread state // stack variables Container callStack; // thread's call stack ScriptVariable *m_StackPos; // marked stack position // parameters variables ScriptVariable *m_pOldData; // old fastEvent data, to cleanup int m_OldDataSize; bool m_bMarkStack; // changed by OP_MARK_STACK_POS and OP_RESTORE_STACK_POS Event fastEvent; // parameter list, set when the VM is executed private: void error(const char *format, ...); template void executeCommand(Listener *listener, op_parmNum_t iParamCount, op_evName_t eventnum); template void executeCommandInternal(Event& ev, Listener *listener, ScriptVariable *fromVar, op_parmNum_t iParamCount); bool executeGetter(Listener *listener, op_evName_t eventName); bool executeSetter(Listener *listener, op_evName_t eventName); void transferVarsToEvent(Event& ev, ScriptVariable *fromVar, op_parmNum_t count); void jump(int offset); void jumpBool(int offset, bool value); void loadTopInternal(Listener *listener); ScriptVariable *storeTopInternal(Listener *listener); template void loadTop(Listener *listener); template ScriptVariable *storeTop(Listener *listener); void fetchOpcodeValue(void *outValue, size_t size); void fetchActualOpcodeValue(void *outValue, size_t size); template T fetchOpcodeValue() { T value; fetchOpcodeValue(&value, sizeof(T)); return value; } template T fetchOpcodeValue(size_t offset) { T value; fetchOpcodeValue(&value, sizeof(T)); return value; } template T fetchActualOpcodeValue() { T value; fetchActualOpcodeValue(&value, sizeof(T)); return value; } void execCmdCommon(op_parmNum_t param); void execCmdMethodCommon(op_parmNum_t param); void execMethodCommon(op_parmNum_t param); void execFunction(ScriptMaster& Director); void SetFastData(ScriptVariable *data, int dataSize); bool Switch(StateScript *stateScript, ScriptVariable& var); unsigned char *ProgBuffer(); void HandleScriptException(ScriptException &exc); public: #ifndef _DEBUG_MEM void *operator new(size_t size); void operator delete(void *ptr); #endif ScriptVM(ScriptClass *scriptClass, unsigned char *pCodePos, ScriptThread *thread); ~ScriptVM(); void Archive(Archiver& arc); void EnterFunction(Container&&); void LeaveFunction(); void End(const ScriptVariable& returnValue); void End(void); void Execute(ScriptVariable *data = NULL, int dataSize = 0, str label = ""); void NotifyDelete(void); void Resume(qboolean bForce = false); void Suspend(void); str Filename(void); str Label(void); ScriptClass *GetScriptClass(void); bool IsSuspended(void); int State(void); int ThreadState(void); void EventGoto(Event *ev); bool EventThrow(Event *ev); bool CanScriptTracePrint(void); }; extern MEM_BlockAlloc ScriptClass_allocator; #endif