⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xvm.cpp

📁 < Game Script Mastery>> source code
💻 CPP
📖 第 1 页 / 共 5 页
字号:

        g_Scripts [ iThreadIndex ].FuncTable.iSize = iFuncTableSize;

		// Allocate the table

		if ( ! ( g_Scripts [ iThreadIndex ].FuncTable.pFuncs = ( Func * ) malloc ( iFuncTableSize * sizeof ( Func ) ) ) )
			return XS_LOAD_ERROR_OUT_OF_MEMORY;

		// Read each function

		for ( int iCurrFuncIndex = 0; iCurrFuncIndex < iFuncTableSize; ++ iCurrFuncIndex )
		{
			// Read the entry point (4 bytes)

			int iEntryPoint;
			fread ( & iEntryPoint, 4, 1, pScriptFile );

			// Read the parameter count (1 byte)

			int iParamCount = 0;
			fread ( & iParamCount, 1, 1, pScriptFile );

			// Read the local data size (4 bytes)

			int iLocalDataSize;
			fread ( & iLocalDataSize, 4, 1, pScriptFile );

			// Calculate the stack size

			int iStackFrameSize = iParamCount + 1 + iLocalDataSize;

            // Read the function name length (1 byte)

            int iFuncNameLength = 0;
            fread ( & iFuncNameLength, 1, 1, pScriptFile );

            // Read the function name (N bytes) and append a null-terminator

            fread ( & g_Scripts [ iThreadIndex ].FuncTable.pFuncs [ iCurrFuncIndex ].pstrName, iFuncNameLength, 1, pScriptFile );
            g_Scripts [ iThreadIndex ].FuncTable.pFuncs [ iCurrFuncIndex ].pstrName [ iFuncNameLength ] = '\0';

			// Write everything to the function table

			g_Scripts [ iThreadIndex ].FuncTable.pFuncs [ iCurrFuncIndex ].iEntryPoint = iEntryPoint;
			g_Scripts [ iThreadIndex ].FuncTable.pFuncs [ iCurrFuncIndex ].iParamCount = iParamCount;
			g_Scripts [ iThreadIndex ].FuncTable.pFuncs [ iCurrFuncIndex ].iLocalDataSize = iLocalDataSize;
			g_Scripts [ iThreadIndex ].FuncTable.pFuncs [ iCurrFuncIndex ].iStackFrameSize = iStackFrameSize;
		}

		// ---- Read the host API call table

		// Read the host API call count

		fread ( & g_Scripts [ iThreadIndex ].HostAPICallTable.iSize, 4, 1, pScriptFile );

		// Allocate the table

		if ( ! ( g_Scripts [ iThreadIndex ].HostAPICallTable.ppstrCalls = ( char ** ) malloc ( g_Scripts [ iThreadIndex ].HostAPICallTable.iSize * sizeof ( char * ) ) ) )
			return XS_LOAD_ERROR_OUT_OF_MEMORY;

		// Read each host API call

		for ( int iCurrCallIndex = 0; iCurrCallIndex < g_Scripts [ iThreadIndex ].HostAPICallTable.iSize; ++ iCurrCallIndex )
		{
			// Read the host API call string size (1 byte)

			int iCallLength = 0;
			fread ( & iCallLength, 1, 1, pScriptFile );

			// Allocate space for the string plus the null terminator in a temporary pointer

			char * pstrCurrCall;
			if ( ! ( pstrCurrCall = ( char * ) malloc ( iCallLength + 1 ) ) )
				return XS_LOAD_ERROR_OUT_OF_MEMORY;

			// Read the host API call string data and append the null terminator

			fread ( pstrCurrCall, iCallLength, 1, pScriptFile );
			pstrCurrCall [ iCallLength ] = '\0';

			// Assign the temporary pointer to the table

			g_Scripts [ iThreadIndex ].HostAPICallTable.ppstrCalls [ iCurrCallIndex ] = pstrCurrCall;
		}

        // ---- Close the input file

        fclose ( pScriptFile );

		// The script is fully loaded and ready to go, so set the active flag

		g_Scripts [ iThreadIndex ].iIsActive = TRUE;

		// Reset the script

		XS_ResetScript ( iThreadIndex );

		// Return a success code

		return XS_LOAD_OK;
	}

	/******************************************************************************************
	*
	*	XS_UnloadScript ()
	*
	*	Unloads a script from memory.
	*/

    void XS_UnloadScript ( int iThreadIndex )
    {
		// Exit if the script isn't active

		if ( ! g_Scripts [ iThreadIndex ].iIsActive )
			return;

        // ---- Free The instruction stream

		// First check to see if any instructions have string operands, and free them if they
		// do

		for ( int iCurrInstrIndex = 0; iCurrInstrIndex < g_Scripts [ iThreadIndex ].InstrStream.iSize; ++ iCurrInstrIndex )
		{
			// Make a local copy of the operand count and operand list

			int iOpCount = g_Scripts [ iThreadIndex ].InstrStream.pInstrs [ iCurrInstrIndex ].iOpCount;
			Value * pOpList = g_Scripts [ iThreadIndex ].InstrStream.pInstrs [ iCurrInstrIndex ].pOpList;

			// Loop through each operand and free its string pointer

			for ( int iCurrOpIndex = 0; iCurrOpIndex < iOpCount; ++ iCurrOpIndex )
				if ( pOpList [ iCurrOpIndex ].pstrStringLiteral )
					pOpList [ iCurrOpIndex ].pstrStringLiteral;
		}

		// Now free the stream itself

		if ( g_Scripts [ iThreadIndex ].InstrStream.pInstrs )
			free ( g_Scripts [ iThreadIndex ].InstrStream.pInstrs );

		// ---- Free the runtime stack

		// Free any strings that are still on the stack

		for ( int iCurrElmtnIndex = 0; iCurrElmtnIndex < g_Scripts [ iThreadIndex ].Stack.iSize; ++ iCurrElmtnIndex )
			if ( g_Scripts [ iThreadIndex ].Stack.pElmnts [ iCurrElmtnIndex ].iType == OP_TYPE_STRING )
				free ( g_Scripts [ iThreadIndex ].Stack.pElmnts [ iCurrElmtnIndex ].pstrStringLiteral );

		// Now free the stack itself

		if ( g_Scripts [ iThreadIndex ].Stack.pElmnts )
			free ( g_Scripts [ iThreadIndex ].Stack.pElmnts );

		// ---- Free the function table

		if ( g_Scripts [ iThreadIndex ].FuncTable.pFuncs )
			free ( g_Scripts [ iThreadIndex ].FuncTable.pFuncs );

		// --- Free the host API call table

		// First free each string in the table individually

		for ( int iCurrCallIndex = 0; iCurrCallIndex < g_Scripts [ iThreadIndex ].HostAPICallTable.iSize; ++ iCurrCallIndex )
			if ( g_Scripts [ iThreadIndex ].HostAPICallTable.ppstrCalls [ iCurrCallIndex ] )
				free ( g_Scripts [ iThreadIndex ].HostAPICallTable.ppstrCalls [ iCurrCallIndex ] );

		// Now free the table itself

		if ( g_Scripts [ iThreadIndex ].HostAPICallTable.ppstrCalls )
			free ( g_Scripts [ iThreadIndex ].HostAPICallTable.ppstrCalls );
    }

	/******************************************************************************************
	*
	*	XS_ResetScript ()
	*
	*	Resets the script. This function accepts a thread index rather than relying on the
	*	currently active thread, because scripts can (and will) need to be reset arbitrarily.
	*/

	void XS_ResetScript ( int iThreadIndex )
	{
        // Get _Main ()'s function index in case we need it

        int iMainFuncIndex = g_Scripts [ iThreadIndex ].iMainFuncIndex;

		// If the function table is present, set the entry point

		if ( g_Scripts [ iThreadIndex ].FuncTable.pFuncs )
		{
			// If _Main () is present, read _Main ()'s index of the function table to get its
            // entry point

			if ( g_Scripts [ iThreadIndex ].iIsMainFuncPresent )
            {
				g_Scripts [ iThreadIndex ].InstrStream.iCurrInstr = g_Scripts [ iThreadIndex ].FuncTable.pFuncs [ iMainFuncIndex ].iEntryPoint;
            }
		}

		// Clear the stack

		g_Scripts [ iThreadIndex ].Stack.iTopIndex = 0;
        g_Scripts [ iThreadIndex ].Stack.iFrameIndex = 0;

        // Set the entire stack to null

        for ( int iCurrElmntIndex = 0; iCurrElmntIndex < g_Scripts [ iThreadIndex ].Stack.iSize; ++ iCurrElmntIndex )
            g_Scripts [ iThreadIndex ].Stack.pElmnts [ iCurrElmntIndex ].iType = OP_TYPE_NULL;

		// Unpause the script

		g_Scripts [ iThreadIndex ].iIsPaused = FALSE;

        // Allocate space for the globals

        PushFrame ( iThreadIndex, g_Scripts [ iThreadIndex ].iGlobalDataSize );

        // If _Main () is present, push its stack frame (plus one extra stack element to
        // compensate for the function index that usually sits on top of stack frames and
        // causes indices to start from -2)

        PushFrame ( iThreadIndex, g_Scripts [ iThreadIndex ].FuncTable.pFuncs [ iMainFuncIndex ].iLocalDataSize + 1 );
	}

	/******************************************************************************************
	*
	*	XS_RunScripts ()
	*
	*	Runs the currenty loaded script array for a given timeslice duration.
	*/

	void XS_RunScripts ( int iTimesliceDur )
	{
		// Begin a loop that runs until a keypress. The instruction pointer has already been
		// initialized with a prior call to ResetScripts (), so execution can begin

        // Create a flag that instructions can use to break the execution loop

        int iExitExecLoop = FALSE;

        // Create a variable to hold the time at which the main timeslice started

        int iMainTimesliceStartTime = GetCurrTime ();

		// Create a variable to hold the current time

		int iCurrTime;

		while ( TRUE )
		{
			// Check to see if all threads have terminated, and if so, break the execution
            // cycle

			int iIsStillActive = FALSE;
			for ( int iCurrThreadIndex = 0; iCurrThreadIndex < MAX_THREAD_COUNT; ++ iCurrThreadIndex )
			{
				if ( g_Scripts [ iCurrThreadIndex ].iIsActive && g_Scripts [ iCurrThreadIndex ].iIsRunning )
					iIsStillActive = TRUE;
			}
			if ( ! iIsStillActive )
			    break;

			// Update the current time

			iCurrTime = GetCurrTime ();

            // Check for a context switch if the threading mode is set for multithreading

            if ( g_iCurrThreadMode == THREAD_MODE_MULTI )
            {
			    // If the current thread's timeslice has elapsed, or if it's terminated switch
			    // to the next valid thread

			    if ( iCurrTime > g_iCurrThreadActiveTime + g_Scripts [ g_iCurrThread ].iTimesliceDur ||
				     ! g_Scripts [ g_iCurrThread ].iIsRunning )
			    {
				    // Loop until the next thread is found

				    while ( TRUE )
				    {
					    // Move to the next thread in the array

					    ++ g_iCurrThread;

					    // If we're past the end of the array, loop back around

					    if ( g_iCurrThread >= MAX_THREAD_COUNT )
						    g_iCurrThread = 0;

                        // If the thread we've chosen is active and running, break the loop

					    if ( g_Scripts [ g_iCurrThread ].iIsActive && g_Scripts [ g_iCurrThread ].iIsRunning )
					        break;
                    }

                    // Reset the timeslice

                    g_iCurrThreadActiveTime = iCurrTime;
			    }
            }

            // Is the script currently paused?

            if ( g_Scripts [ g_iCurrThread ].iIsPaused )
            {
                // Has the pause duration elapsed yet?

                if ( iCurrTime >= g_Scripts [ g_iCurrThread ].iPauseEndTime )
                {
                    // Yes, so unpause the script

                    g_Scripts [ g_iCurrThread ].iIsPaused = FALSE;
                }
                else
                {
                    // No, so skip this iteration of the execution cycle

                    continue;
                }
            }

			// Make a copy of the instruction pointer to compare later

			int iCurrInstr = g_Scripts [ g_iCurrThread ].InstrStream.iCurrInstr;

            // Get the current opcode

            int iOpcode = g_Scripts [ g_iCurrThread ].InstrStream.pInstrs [ iCurrInstr ].iOpcode;

  		    // Execute the current instruction based on its opcode, as long as we aren't
            // currently paused

			switch ( iOpcode )
			{
                // ---- Binary Operations

                // All of the binary operation instructions (move, arithmetic, and bitwise)
                // are combined into a single case that keeps us from having to rewrite the
                // otherwise redundant operand resolution and result storage phases over and
                // over. We then use an additional switch block to determine which operation
                // should be performed.

                // Move

				case INSTR_MOV:

                // Arithmetic Operations

                case INSTR_ADD:
                case INSTR_SUB:
                case INSTR_MUL:
                case INSTR_DIV:
                case INSTR_MOD:
                case INSTR_EXP:

                // Bitwise Operations

                case INSTR_AND:
                case INSTR_OR:
                case INSTR_XOR:
                case INSTR_SHL:
                case INSTR_SHR:
                {
                    // Get a local copy of the destination operand (operand index 0)

                    Value Dest = ResolveOpValue ( 0 );

                    // Get a local copy of the source operand (operand index 1)

                    Value Source = ResolveOpValue ( 1 );

                    // Depending on the instruction, perform a binary operation

                    switch ( iOpcode )
                    {
                        // Move

                        case INSTR_MOV:

                            // Skip cases where the two operands are the same

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -