openmohaa/code/script/scriptvm.h

278 lines
8.1 KiB
C
Raw Normal View History

2016-03-27 11:49:47 +02:00
/*
===========================================================================
Copyright (C) 2023 the OpenMoHAA team
2016-03-27 11:49:47 +02:00
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.
2023-10-01 22:47:25 +02:00
#pragma once
2016-03-27 11:49:47 +02:00
#include "listener.h"
#include "../fgame/gamescript.h"
2016-03-27 11:49:47 +02:00
#include "scriptvariable.h"
#include "scriptopcodes.h"
#include "../qcommon/con_set.h"
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
#define MAX_STACK_DEPTH 20 // 9 in mohaa
2016-03-27 11:49:47 +02:00
//#define LOCALSTACK_SIZE 255 // pre-allocated localstack size for each VM
2023-10-01 22:47:25 +02:00
#define MAX_SCRIPTCYCLES 9999 // max cmds
2016-03-27 11:49:47 +02:00
2023-10-26 20:13:07 +02:00
enum eVMState {
2023-10-27 20:00:48 +02:00
STATE_RUNNING, // Running
2023-10-26 20:13:07 +02:00
STATE_SUSPENDED, // Suspended
2023-10-27 20:00:48 +02:00
STATE_WAITING, // Waiting for something
2023-10-26 20:13:07 +02:00
STATE_EXECUTION, // Resume to execution
2023-10-27 20:00:48 +02:00
STATE_DESTROYED // Pending deletion
2023-10-26 20:13:07 +02:00
};
enum eThreadState {
THREAD_RUNNING,
THREAD_WAITING,
THREAD_SUSPENDED
};
2016-03-27 11:49:47 +02:00
2023-04-29 21:56:38 +02:00
class ScriptException;
2016-03-27 11:49:47 +02:00
class ScriptThread;
class ScriptVM;
2023-07-05 21:23:39 +02:00
class ScriptCallStack
{
2016-03-27 11:49:47 +02:00
public:
2023-07-05 21:23:39 +02:00
// opcode variable
unsigned char *codePos; // opcode will be restored once a DONE was hit
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
// stack variables
ScriptVariable *localStack;
ScriptVariable *pTop;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
// return variable
ScriptVariable returnValue;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
// OLD self value
SafePtr<Listener> m_Self;
2016-03-27 11:49:47 +02:00
};
class ScriptStack
{
public:
2023-07-05 21:23:39 +02:00
ScriptVariable *m_Array;
int m_Count;
2016-03-27 11:49:47 +02:00
};
class ScriptVMStack
{
public:
2023-07-05 21:23:39 +02:00
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);
2023-07-05 21:23:39 +02:00
/** 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);
void Archive(Archiver& arc);
private:
void Allocate(size_t stackSize);
void Free();
private:
2023-07-05 21:23:39 +02:00
/** The VM's local stack. */
ScriptVariable *localStack;
/** The local stack size. */
ScriptVariable *stackBottom;
/** Variable from the top stack of the local stack. */
ScriptVariable* pTop;
public:
/** Whether or not the stack is marked. */
/** changed by OP_MARK_STACK_POS and OP_RESTORE_STACK_POS */
bool m_bMarkStack;
};
2016-03-27 11:49:47 +02:00
class ScriptVM
{
2023-07-05 21:23:39 +02:00
friend class ScriptThread;
2016-03-27 11:49:47 +02:00
public:
2023-07-05 21:23:39 +02:00
// important thread variables
ScriptVM *next; // next VM in the current ScriptClass
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
ScriptThread *m_Thread; // script thread
ScriptClass *m_ScriptClass; // current group of threads
2016-03-27 11:49:47 +02:00
public:
2023-07-05 21:23:39 +02:00
// return variables
ScriptStack *m_Stack; // Currently unused
ScriptVMStack m_VMStack;
ScriptVariable m_ReturnValue; // VM return value
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
// 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
2016-03-27 11:49:47 +02:00
public:
2023-07-05 21:23:39 +02:00
// states
unsigned char state; // current VM state
unsigned char m_ThreadState; // current thread state
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
// stack variables
Container<ScriptCallStack *> callStack; // thread's call stack
ScriptVariable *m_StackPos; // marked stack position
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
// 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
2023-07-05 21:23:39 +02:00
Event fastEvent; // parameter list, set when the VM is executed
2016-03-27 11:49:47 +02:00
private:
2023-07-05 21:23:39 +02:00
void error(const char *format, ...);
template<bool bMethod = false, bool bReturn = false>
void executeCommand(Listener *listener, op_parmNum_t iParamCount, op_evName_t eventnum);
template<bool bReturn>
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 checkValidEvent(Event& ev, Listener *listener);
2023-07-05 21:23:39 +02:00
void loadTopInternal(Listener *listener);
ScriptVariable *storeTopInternal(Listener *listener);
template<bool noTop = false>
void loadTop(Listener *listener);
template<bool noTop = false>
2023-10-01 22:47:25 +02:00
ScriptVariable *storeTop(Listener *listener);
void loadStoreTop(Listener *listener);
void skipField();
2023-07-05 21:23:39 +02:00
void SetFastData(ScriptVariable *data, int dataSize);
bool Switch(StateScript *stateScript, ScriptVariable& var);
unsigned char *ProgBuffer();
void HandleScriptException(ScriptException& exc);
2016-03-27 11:49:47 +02:00
public:
2023-07-05 21:23:39 +02:00
void *operator new(size_t size);
void operator delete(void *ptr);
2016-03-27 11:49:47 +02:00
ScriptVM();
2023-07-05 21:23:39 +02:00
ScriptVM(ScriptClass *scriptClass, unsigned char *pCodePos, ScriptThread *thread);
~ScriptVM();
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
void Archive(Archiver& arc);
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
void EnterFunction(Container<ScriptVariable>&&);
void LeaveFunction();
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
void End(const ScriptVariable& returnValue);
void End(void);
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
void Execute(ScriptVariable *data = NULL, int dataSize = 0, str label = "");
void NotifyDelete(void);
void Resume(qboolean bForce = false);
void Suspend(void);
2016-03-27 11:49:47 +02:00
2023-10-27 20:00:48 +02:00
str Filename(void) const;
str Label(void) const;
ScriptClass *GetScriptClass(void) const;
GameScript *GetScript() const;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
bool IsSuspended(void);
int State(void);
int ThreadState(void);
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
void EventGoto(Event *ev);
bool EventThrow(Event *ev);
2016-03-27 11:49:47 +02:00
2023-10-27 20:00:48 +02:00
bool CanScriptTracePrint(void);
void ScriptTrace1() const;
void ScriptTrace2() const;
const char *GetSourcePos() const;
2023-08-13 17:59:49 +02:00
private:
2023-10-01 22:47:25 +02:00
void jump(unsigned int offset);
void jumpBack(unsigned int offset);
void jumpBool(unsigned int offset, bool booleanValue);
bool jumpVar(unsigned int offset, bool booleanValue);
void doJumpIf(bool booleanValue);
bool doJumpVarIf(bool booleanValue);
void fetchOpcodeValue(void *outValue, size_t size);
void fetchActualOpcodeValue(void *outValue, size_t size);
template<typename T>
T fetchOpcodeValue()
{
T value;
fetchOpcodeValue(&value, sizeof(T));
return value;
}
template<typename T>
T fetchOpcodeValue(size_t offset)
{
T value;
fetchOpcodeValue(&value, sizeof(T));
return value;
}
template<typename T>
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);
2016-03-27 11:49:47 +02:00
};
extern MEM_BlockAlloc<ScriptClass> ScriptClass_allocator;