Quantcast
Jump to content
Search In
  • More options...
Find results that contain...
Find results in...
    1. Welcome to GTAForums!

    1. GTANet.com

    1. GTA Online

      1. Los Santos Summer Special
      2. The Diamond Casino Heist
      3. Find Lobbies & Players
      4. Guides & Strategies
      5. Vehicles
      6. Content Creator
      7. Help & Support
    2. Red Dead Online

      1. Frontier Pursuits
      2. Find Lobbies & Outlaws
      3. Help & Support
    3. Crews

    1. Red Dead Redemption 2

      1. PC
      2. Help & Support
    2. Red Dead Redemption

    1. Grand Theft Auto Series

    2. GTA VI

      1. St. Andrews Cathedral
    3. GTA V

      1. Guides & Strategies
      2. Help & Support
    4. GTA IV

      1. The Lost and Damned
      2. The Ballad of Gay Tony
      3. Guides & Strategies
      4. Help & Support
    5. GTA San Andreas

      1. Guides & Strategies
      2. Help & Support
    6. GTA Vice City

      1. Guides & Strategies
      2. Help & Support
    7. GTA III

      1. Guides & Strategies
      2. Help & Support
    8. Portable Games

      1. GTA Chinatown Wars
      2. GTA Vice City Stories
      3. GTA Liberty City Stories
    9. Top-Down Games

      1. GTA Advance
      2. GTA 2
      3. GTA
    1. GTA Mods

      1. GTA V
      2. GTA IV
      3. GTA III, VC & SA
      4. Tutorials
    2. Red Dead Mods

      1. Documentation
    3. Mod Showroom

      1. Scripts & Plugins
      2. Maps
      3. Total Conversions
      4. Vehicles
      5. Textures
      6. Characters
      7. Tools
      8. Other
      9. Workshop
    4. Featured Mods

      1. Design Your Own Mission
      2. OpenIV
      3. GTA: Underground
      4. GTA: Liberty City
      5. GTA: State of Liberty
    1. Rockstar Games

    2. Rockstar Collectors

    1. Off-Topic

      1. General Chat
      2. Gaming
      3. Technology
      4. Movies & TV
      5. Music
      6. Sports
      7. Vehicles
    2. Expression

      1. Graphics / Visual Arts
      2. GFX Requests & Tutorials
      3. Writers' Discussion
      4. Debates & Discussion
    3. Gangs

    1. Announcements

    2. Support

    3. Suggestions

Sign in to follow this  
goodidea82

[CLEO Plugin] How to call an opcode within a cleo plugin?

Recommended Posts

goodidea82

Using cleo-sdk I want to define a new opcode X which calls an existing opcode Y. How do I make a call to opcode Y within the implementation of X? How do I pass parameters to Y?

 

The reason I want to do this is to apply transformations on the input and output parameter before/after calling Y. Opcode X will be a wrapper of Y.

 

For convenience here is cleo.h from cleo 4.3

 

 

/*    CLEO 4.3 header file;    Copyright © 2014 Alien, Deji;*/#pragma once#include <wtypes.h>#define CLEO_VERSION 0x04031400#define CLEO_VERSIONTEXT "4.3"//result of CLEO_GetGameVersion()#define GV_US10 0    //1.0 us#define GV_US11 1    //1.01 us - not supported#define GV_EU10 2    //1.0 eu#define GV_EU11 3    //1.01 eu#define GV_UNK -1    //any othertypedef union{    DWORD    dwParam;    int        nParam;    float    fParam;    void *    pParam;    char *    szParam;} SCRIPT_VAR;//operand types#define    globalVar            2        //$#define    localVar            3        //@#define    globalArr            7        //$(,)#define    localArr             8        //@(,)#define    imm8                 4        //char#define    imm16                 5        //short#define    imm32                 6        //long, unsigned long#define    imm32f                 1        //float#define    vstring             0x0E    //""#define    sstring             9        //''#define    globalVarVString     0x10    //v$#define    localVarVString     0x11    //@v#define    globalVarSString     0x0A    //s$#define    localVarSString     0x0B    //@stypedef int SCRIPT_HANDLE;typedef SCRIPT_HANDLE HANDLE_ACTOR, ACTOR, HACTOR, PED, HPED, HANDLE_PED;typedef SCRIPT_HANDLE HANDLE_CAR, CAR, HCAR, VEHICLE, HVEHICLE, HANDLE_VEHICLE;typedef SCRIPT_HANDLE HANDLE_OBJECT, OBJECT, HOBJECT;typedef struct CScriptThread CScriptThread;#pragma pack(push,1)struct CScriptThread{    CScriptThread    *next;                    //next script in queue    CScriptThread    *prev;                    //previous script in queue    char            threadName[8];            //name of thread, given by 03A4 opcode    BYTE            *baseIp;                //pointer to begin of script in memory    BYTE            *ip;                    //current index pointer    BYTE            *stack[8];                //return stack for 0050, 0051    WORD            sp;                        //current item in stack    WORD            _f3A;                    //padding    SCRIPT_VAR        tls[34];                //thread's local variables    BYTE            isActive;                //is current thread active    char            condResult;                //condition result (true or false)    char            missionCleanupFlag;        //clean mission    char            external;                //is thread external (from script.img)    BYTE            _fC8;                    //unknown    BYTE            _fC9;                    //unknown    BYTE            _fCA;                    //unknown    BYTE            _fCB;                    //unknown    DWORD            wakeTime;                //time, when script starts again after 0001 opcode    WORD            logicalOp;                //00D6 parameter    BYTE            notFlag;                //opcode & 0x8000 != 0    BYTE            wbCheckEnabled;            //wasted_or_busted check flag    BYTE            wastedOrBusted;            //is player wasted or busted    BYTE            _fD5;                    //unknown    WORD            _fD6;                    //unknown    DWORD            sceneSkip;                //scene skip label ptr    BYTE            missionFlag;            //is mission thread    BYTE            _fDD[3];                //padding};#pragma pack(pop)#define OR_CONTINUE 0#define OR_INTERRUPT 1typedef int OpcodeResult;typedef OpcodeResult (CALLBACK* _pOpcodeHandler)(CScriptThread*);#ifdef __cplusplusextern "C" {#endif    //__cplusplusDWORD WINAPI CLEO_GetVersion();int   WINAPI CLEO_GetGameVersion();BOOL  WINAPI CLEO_RegisterOpcode(WORD opcode, _pOpcodeHandler callback);DWORD WINAPI CLEO_GetIntOpcodeParam(CScriptThread* thread);float WINAPI CLEO_GetFloatOpcodeParam(CScriptThread* thread);void  WINAPI CLEO_SetIntOpcodeParam(CScriptThread* thread, DWORD value);void  WINAPI CLEO_SetFloatOpcodeParam(CScriptThread* thread, float value);LPSTR WINAPI CLEO_ReadStringOpcodeParam(CScriptThread* thread, LPSTR buf, int size);void  WINAPI CLEO_WriteStringOpcodeParam(CScriptThread* thread, LPCSTR str);void  WINAPI CLEO_SetThreadCondResult(CScriptThread* thread, BOOL result);void  WINAPI CLEO_SkipOpcodeParams(CScriptThread* thread, int count);void  WINAPI CLEO_ThreadJumpAtLabelPtr(CScriptThread* thread, int labelPtr);int   WINAPI CLEO_GetOperandType(CScriptThread* thread);SCRIPT_VAR *opcodeParams;SCRIPT_VAR *missionLocals;//intermediate data is stored in opcodeParams arrayvoid WINAPI CLEO_RetrieveOpcodeParams(CScriptThread *thread, int count);void WINAPI CLEO_RecordOpcodeParams(CScriptThread *thread, int count);SCRIPT_VAR * WINAPI CLEO_GetPointerToScriptVariable(CScriptThread *thread);#ifdef __cplusplus}#endif    //__cplusplus

 

 

and here is an example from the sdk of a custom opcode

 

 

OpcodeResult WINAPI Script_IntOp_AND(CScriptThread* thread)/****************************************************************						Opcode Format0B10=3,%3d% = %1d% AND %2d%****************************************************************/{	int a = CLEO_GetIntOpcodeParam(thread);	int b = CLEO_GetIntOpcodeParam(thread);	CLEO_SetIntOpcodeParam(thread, a & b);	return OR_CONTINUE;}

 

 

Edited by goodidea82

Share this post


Link to post
Share on other sites
Seemann

I guess you can't do it easy. Instead try running a function or method that the desired opcode calls itself. Say, you want to call 0B10, then just call CLEO_SetIntOpcodeParam(thread, a & b);

 

Otherwise you need to make a proper hex code to parse with CRunningScript::ProcessOneCommand().

  • Like 1

Share this post


Link to post
Share on other sites
fastman92

use my CRunningScriptWrapper

coming in SA Plugin SDK

  • Like 2

Share this post


Link to post
Share on other sites
goodidea82

@Seemann. Despite fastman's solution, if you know how to pass parameters and call an opcode using ProcessOneCommand() that would be interesting to see. I suppose methods from Plugin SDK are needed?

 

 

#pragma once#include <plugin/plugin.h>#include "ePedType.h"#include "eCommandName.h"#include "eWeaponType.h"#define FUNC_CRunningScript__Init 0x4648E0#define FUNC_CRunningScript__GetArrayOffsetAndValueOfIndexVariable 0x463CF0#define FUNC_CRunningScript__GetOffsetOfGlobalVariable 0x464700#define FUNC_CRunningScript__GetPointerToScriptVariable 0x464790#define FUNC_CRunningScript__GetPointerLocalVariableByArrayIndex 0x463CC0#define FUNC_CRunningScript__ProcessOneCommand 0x469EB0#define FUNC_CRunningScript__CollectParameters 0x464080#define FUNC_CRunningScript__CollectStringParameter 0x463D50#define FUNC_CRunningScript__StoreParameters 0x464370#define FUNC_CRunningScript__CollectParametersToNewScript 0x464500#define FUNC_CRunningScript__Process 0x469F00#define FUNC_CRunningScript__DoDeatharrestCheck 0x485A50#define FUNC_CRunningScript__CollectNextParameterWithoutIncreasingPC 0x464250#define FUNC_CRunningScript__SetIntructionPointer 0x464DA0#define FUNC_CRunningScript__UpdateCompareFlag 0x4859D0#define FUNC_CRunningScript__AddScriptToList 0x464C00#define FUNC_CRunningScript__RemoveScriptFromList 0x464BD0#define FUNC_CRunningScript__GetPadState 0x485B10#define FUNC_CRunningScript__TerminateThisScript 0x465AA0#define FUNC_CRunningScript__CheckDamagedWeaponType 0x43D9E0#define FUNC_CRunningScript__CarInAreaCheckCommand 0x488EC0#define FUNC_CRunningScript__CharInAreaCheckCommand 0x488B50#define FUNC_CRunningScript__LocateCarCommand 0x487A20#define FUNC_CRunningScript__LocateCharCarCommand 0x487420#define FUNC_CRunningScript__LocateCharCharCommand 0x4870F0#define FUNC_CRunningScript__LocateCharCommand 0x486D80#define FUNC_CRunningScript__LocateCharObjectCommand 0x487720#define FUNC_CRunningScript__LocateObjectCommand 0x487D10#define FUNC_CRunningScript__ObjectInAreaCheckCommand 0x489150#define FUNC_CRunningScript__ThisIsAValidRandomPed 0x489490// Command handlers#define FUNC_CRunningScript__ProcessCommands_0To99 0x465E60#define FUNC_CRunningScript__ProcessCommands_100To199 0x466DE0#define FUNC_CRunningScript__ProcessCommands_200To299 0x469390#define FUNC_CRunningScript__ProcessCommands_300To399 0x47C100#define FUNC_CRunningScript__ProcessCommands_400To499 0x47D210#define FUNC_CRunningScript__ProcessCommands_500To599 0x47E090#define FUNC_CRunningScript__ProcessCommands_600To699 0x47F370#define FUNC_CRunningScript__ProcessCommands_700To799 0x47FA30#define FUNC_CRunningScript__ProcessCommands_800To899 0x481300#define FUNC_CRunningScript__ProcessCommands_900To999 0x483BD0#define FUNC_CRunningScript__ProcessCommands_1000To1099 0x489500#define FUNC_CRunningScript__ProcessCommands_1100To1199 0x48A320#define FUNC_CRunningScript__ProcessCommands_1200To1299 0x48B590#define FUNC_CRunningScript__ProcessCommands_1300To1399 0x48CDD0#define FUNC_CRunningScript__ProcessCommands_1400To1499 0x48EAA0#define FUNC_CRunningScript__ProcessCommands_1500To1599 0x490DB0#define FUNC_CRunningScript__ProcessCommands_1600To1699 0x493FE0#define FUNC_CRunningScript__ProcessCommands_1700To1799 0x496E00#define FUNC_CRunningScript__ProcessCommands_1800To1899 0x46D050#define FUNC_CRunningScript__ProcessCommands_1900To1999 0x46B460#define FUNC_CRunningScript__ProcessCommands_2000To2099 0x472310#define FUNC_CRunningScript__ProcessCommands_2100To2199 0x470A90#define FUNC_CRunningScript__ProcessCommands_2200To2299 0x474900#define FUNC_CRunningScript__ProcessCommands_2300To2399 0x4762D0#define FUNC_CRunningScript__ProcessCommands_2400To2499 0x478000#define FUNC_CRunningScript__ProcessCommands_2500To2599 0x47A760#define FUNC_CRunningScript__ProcessCommands_2600To2699 0x479DA0enum eArgumentDataTypesFormat_GTA_III_VC_SA : __int8{    SCM_ARGUMENT_TYPE_END_OF_ARGUMENTS,    SCM_ARGUMENT_TYPE_STATIC_INT_32BITS,    SCM_ARGUMENT_TYPE_GLOBAL_NUMBER_VARIABLE,    SCM_ARGUMENT_TYPE_LOCAL_NUMBER_VARIABLE,    SCM_ARGUMENT_TYPE_STATIC_INT_8BITS,    SCM_ARGUMENT_TYPE_STATIC_INT_16BITS,    SCM_ARGUMENT_TYPE_STATIC_FLOAT,    // Types below are only available in GTA SA    SCM_ARGUMENT_TYPES_INTRODUCED_IN_GTASA,    // Number arrays    SCM_ARGUMENT_TYPE_GLOBAL_NUMBER_ARRAY = SCM_ARGUMENT_TYPES_INTRODUCED_IN_GTASA,    SCM_ARGUMENT_TYPE_LOCAL_NUMBER_ARRAY,    SCM_ARGUMENT_TYPE_STATIC_SHORT_STRING,    SCM_ARGUMENT_TYPE_GLOBAL_SHORT_STRING_VARIABLE,    SCM_ARGUMENT_TYPE_LOCAL_SHORT_STRING_VARIABLE,    SCM_ARGUMENT_TYPE_GLOBAL_SHORT_STRING_ARRAY,    SCM_ARGUMENT_TYPE_LOCAL_SHORT_STRING_ARRAY,    SCM_ARGUMENT_TYPE_STATIC_PASCAL_STRING,    SCM_ARGUMENT_TYPE_STATIC_LONG_STRING,    SCM_ARGUMENT_TYPE_GLOBAL_LONG_STRING_VARIABLE,    SCM_ARGUMENT_TYPE_LOCAL_LONG_STRING_VARIABLE,    SCM_ARGUMENT_TYPE_GLOBAL_LONG_STRING_ARRAY,    SCM_ARGUMENT_TYPE_LOCAL_LONG_STRING_ARRAY,};union tScriptVarValue{    unsigned __int32    dwParam;    __int32            nParam;    float            fParam;    void        *pParam;    char        *szParam;};VALIDATE_SIZE(tScriptVarValue, 0x4);#pragma pack(push, 1)class PLUGIN_API CRunningScript{public:    // FUNCTIONS    CRunningScript    *next;    CRunningScript    *prev;    char            threadName[8];    uint8_t            *baseIP;    uint8_t            *curIP;                uint8_t            *gosubStack[8];    uint16_t        gosubStackLevel;    uint16_t            _f3A;    tScriptVarValue    tls[32];        uint32_t        timers[2];        bool            isActive;    bool            condResult;        bool            MissionCleanUpFlag;    bool            IsExternalThread;    uint8_t            _fC8;    char            scrType;    uint8_t            _fCA;    uint8_t            _fCB;    uint32_t        wakeTime;    uint16_t        logicalOp;    bool            notFlag;    bool            bDeathArrestCheckEnabled;    bool            wastedOrBusted;    uint8_t            _fD5;    uint16_t        _fD6;    uint32_t        sceneSkipOffset;    bool            missionFlag;    // VARIABLES    // bellow is align in 4 bytes    uint16_t        scmFunction;    uint8_t            IsCustom;    // Initializes member variables.    void Init();    // Processes running script    void Process();    // Processes one command    char ProcessOneCommand();    // Performs death arrest check    void DoDeatharrestCheck();    /////// USED HEAVILY IN COMMANDS //////    // Reads array offset and value from array index variable.    void GetArrayOffsetAndValueOfIndexVariable(__int16 *pOffset, __int32 *pIdx);    // Returns offset of global variable    __int16 GetOffsetOfGlobalVariable();    // Returns pointer to script variable of any type.    tScriptVarValue* GetPointerToScriptVariable(unsigned __int8 variableType);    // Collects parameters    void CollectParameters(__int16 count);    // Collects parameter and returns it.    tScriptVarValue CollectNextParameterWithoutIncreasingPC();    // Collects string parameter    void CollectStringParameter(char *pBuffer, unsigned __int8 nBufferLength);    // Stores parameters    void StoreParameters(__int16 count);    // Collects parameters and puts them to local variables of new script    void CollectParametersToNewScript(CRunningScript* pNewScript);    // Sets instruction pointer, used in GOTO-like commands    void SetIntructionPointer(__int32 newIP);    // Updates comparement flag, used in conditional commands    void UpdateCompareFlag(bool state);    // Terminates a script    void TerminateThisScript();    ///////////////////    // Returns condition result    bool GetConditionResult();    // Returns pointer to local variable pointed by offset and array index as well as multiplier.    void GetPointerLocalVariableByArrayIndex(__int16 off, __int16 idx, unsigned __int8 mul);    // Adds script to list    void AddScriptToList(CRunningScript ** list);    // Removes script from list    void RemoveScriptFromList(CRunningScript ** list);    // Returns state of pad button.    short GetPadState(unsigned short playerIndex, unsigned short buttonID);    // Command handlers    char ProcessCommands_0To99(eCommandName commandID);    char ProcessCommands_100To199(eCommandName commandID);    char ProcessCommands_200To299(eCommandName commandID);    char ProcessCommands_300To399(eCommandName commandID);    char ProcessCommands_400To499(eCommandName commandID);    char ProcessCommands_500To599(eCommandName commandID);    char ProcessCommands_600To699(eCommandName commandID);    char ProcessCommands_700To799(eCommandName commandID);    char ProcessCommands_800To899(eCommandName commandID);    char ProcessCommands_900To999(eCommandName commandID);    char ProcessCommands_1000To1099(eCommandName commandID);    char ProcessCommands_1100To1199(eCommandName commandID);    char ProcessCommands_1200To1299(eCommandName commandID);    char ProcessCommands_1300To1399(eCommandName commandID);    char ProcessCommands_1400To1499(eCommandName commandID);    char ProcessCommands_1500To1599(eCommandName commandID);    char ProcessCommands_1600To1699(eCommandName commandID);    char ProcessCommands_1700To1799(eCommandName commandID);    char ProcessCommands_1800To1899(eCommandName commandID);    char ProcessCommands_1900To1999(eCommandName commandID);    char ProcessCommands_2000To2099(eCommandName commandID);    char ProcessCommands_2100To2199(eCommandName commandID);    char ProcessCommands_2200To2299(eCommandName commandID);    char ProcessCommands_2300To2399(eCommandName commandID);    char ProcessCommands_2400To2499(eCommandName commandID);    char ProcessCommands_2500To2599(eCommandName commandID);    char ProcessCommands_2600To2699(eCommandName commandID);    // Checks if damage ID is valid to expected damage weapon ID.    static bool CheckDamagedWeaponType(eWeaponType damageWeaponID, eWeaponType expectedDamageWeaponID);    // Processes commands that check if car is in specified area.    void CarInAreaCheckCommand(eCommandName commandID);    // Processes commands that check if char is in specified area.    void CharInAreaCheckCommand(eCommandName commandID);    // Processes commands that locate a vehicle    void LocateCarCommand(eCommandName commandID);    // Processes commands where char locates car    void LocateCharCarCommand(eCommandName commandID);    // Processes commands where char locates another char    void LocateCharCharCommand(eCommandName commandID);    // Processes commands where char locates map point    void LocateCharCommand(eCommandName commandID);    // Processes commands where char locates object    void LocateCharObjectCommand(eCommandName commandID);    // Processes commands where object locates map point    void LocateObjectCommand(eCommandName commandID);    // Processes commands that check if object is in area    void ObjectInAreaCheckCommand(eCommandName commandID);    // Checks if ped type conforms to valid ped types.    bool ThisIsAValidRandomPed(ePedType pedType, bool civilian, bool gang, bool criminal);};#pragma pack(pop)VALIDATE_SIZE(CRunningScript, 0xE0);

 



@fastman92. Can you tell us more about it and perhaps show an example how passing parameters and calling an opcode will work with your api.

Edited by goodidea82

Share this post


Link to post
Share on other sites
fastman92

In my LUA library I have a Script class which uses SCM wrapper itself.

 

#pragma once#include "Commands_PED.h"using namespace ScriptManager;namespace Commands_PED{	const luaL_Reg Commands_PED::CommandList[] =	{		luaL_reg_function(GetWorldPosition),		luaL_reg_end	};	// Returns position	// Example: local x, y, z = PED.GetWorldPosition(playerHandle)	int Commands_PED::GetWorldPosition(lua_State* L)	{		int pedHandle = pCurrentScriptInfo -> GetInt(1);			pCurrentScriptInfo -> TheSCMwrapper.PushInt(pedHandle, false);		pCurrentScriptInfo -> TheSCMwrapper.PushReturnArguments(RUNNING_SCRIPT_VALUE_TYPE_FLOAT, 3);		pCurrentScriptInfo -> TheSCMwrapper.CallCommand(COMMAND_GET_CHAR_COORDINATES);				pCurrentScriptInfo -> PushFloat(*pCurrentScriptInfo -> TheSCMwrapper.ReturnedValues[0].data.pFloat);		pCurrentScriptInfo -> PushFloat(*pCurrentScriptInfo -> TheSCMwrapper.ReturnedValues[1].data.pFloat);		pCurrentScriptInfo -> PushFloat(*pCurrentScriptInfo -> TheSCMwrapper.ReturnedValues[2].data.pFloat);		return 3;	}}
You need CRunningScriptWrapper, not CRunningScript.

https://github.com/DK22Pac/plugin-sdk/blob/master/src/sdk/plugin/script/wrapper.h

 

Using this class requires pushing the arguments and calling a command by CallCommand.

The returned values will be accessible from ReturnedValues after calling a command.

They can also be saved into structure by SaveReturnedValues method.

Share this post


Link to post
Share on other sites
goodidea82

Thanks, this is just what I have been looking for. The example is very good. I will leave the thread open in case I have a question.

Share this post


Link to post
Share on other sites
goodidea82

Thanks. Meanwhile I have returned from traveling.

Where can I find the implementation of CRunningScriptWrapper or are you still working on it?

 

Edit: Ok found it. It is part of wrapper.cpp.

Edited by goodidea82

Share this post


Link to post
Share on other sites
goodidea82

The CLEO sdk (version 4.3) provides the following functions to read and write strings.

LPSTR WINAPI CLEO_ReadStringOpcodeParam(CScriptThread* thread, LPSTR buf, int size);void  WINAPI CLEO_WriteStringOpcodeParam(CScriptThread* thread, LPCSTR str);

Do these functions support short strings, long strings, or variables strings, or do they handle all of them?

 

For example, wrapper.h provides different function for different string types:

 

 

	// Pushes a short string value	void PushShortString(const char* value, bool bIsReturnedValue = true);	// Pushes a long string value	void PushLongString(const char* value, bool bIsReturnedValue = true);	// Pushes a varlen string	void PushVarlenString(const char* value);	void PushReturnArgument(eRunningScriptWrapperDataValueType valueType);//withenum eRunningScriptWrapperDataValueType{	RUNNING_SCRIPT_VALUE_TYPE_INT = 1,			// 4 bytes, integer	RUNNING_SCRIPT_VALUE_TYPE_FLOAT = 2,		// 4 bytes, float	RUNNING_SCRIPT_VALUE_TYPE_TEXT_LABEL = 3,	// 8 bytes, short string	RUNNING_SCRIPT_VALUE_TYPE_STRING = 4		// 16 bytes, long string};

 

 

 

---------

Edit:

Here is an excerpt from the implementation of CLEO 4.2.

 

 

	LPSTR STDCALL CLEO_ReadStringOpcodeParam(CScriptThread* thread, char *buf, int size)	{		static char internal_buf[100];		if (!buf) { buf = internal_buf; size = 100; }		if (!size) size = 100;		std::fill(buf, buf  + size, '\0');		GetScriptStringParam(thread, buf, size);			return buf;	}	void STDCALL CLEO_WriteStringOpcodeParam(CScriptThread* thread, LPCSTR str)	{		auto dst = (char *)GetScriptParamPointer(thread);		memcpy(dst, str, 16);		dst[15] = '\0';	}

It seams that 16bytes are written by the second function to it seems that this is for long strings. Is this assumption correct? If so, then how to handle short strings and varlenght strings?

 

 

 

Edited by goodidea82

Share this post


Link to post
Share on other sites
Link2012

Since variables can only handle 16 characters you have that.on the writer but not on the reader. So yeah, the reader handles varlens fine.

Both don't handle integer values being pointers to a string, you have to handle that yourself.

  • Like 1

Share this post


Link to post
Share on other sites
goodidea82

In SCMWrapper what is the meaning of the parameter bIsReturnedValue which appears in several function? For example,

void PushInt(__int32 value, bool bIsReturnedValue = true)

When should I use the default value true and when should I set it to false?

 

 

 

class PLUGIN_API CRunningScriptWrapper : public CRunningScript{// private:public:	// Used to put code of command into	uint8_t CommandSpace[2000];	uint8_t* CommandSpaceArguments;	// VARIABLES	int pushArgIndex;	int pushReturnValueIndex;public:	// Number of returned values	int numberOfReturnedValues;	// Returned values	tRunningScriptWrapperDataValue ReturnedValues[maxNumberOfReturnedValues];private:	char reserved[32];	// for the future purpose of extending a struct.	public:	// FUNCTIONS	// Constructor	CRunningScriptWrapper();	// Saves returned values to object of type tRunningScriptWrapper_SavedReturnedValuesArray.		// This function may only be called after execution of CallCommand - pushing values past the execution of CallCommand will overwrite values	void SaveReturnedValues(tRunningScriptWrapper_SavedReturnedValuesArray& arrayOfSavedReturnedValues);	// Calls a command. Return values: (-1 : invalid command ID, 0: continue, 1: WAIT)	char CallCommand(eCommandName commandID);	// Calls a command. Return values: (-1 : invalid command ID, 0: continue, 1: WAIT)	char CallCommand(__int16 commandID);	// Returns offset of global variable by number of variable	static int GetGlobalVariableOffsetByNumber(int variableNum);	// Returns pointer to global variable	tScriptVarValue* GetPointerToGlobalVariableByOffset(int variableOffset);	///////// Functions to pass arguments /////////	// Pushes boolean argument	void PushBoolean(bool value, bool bIsReturnedValue = true);	// Pushes float value	void PushFloat(float value, bool bIsReturnedValue = true);	// Pushes integer value	void PushInt(__int32 value, bool bIsReturnedValue = true);	// Pushes a pointer	void PushPointer(void* value, bool bIsReturnedValue = true);	// Pushes a short string value	void PushShortString(const char* value, bool bIsReturnedValue = true);	// Pushes a long string value	void PushLongString(const char* value, bool bIsReturnedValue = true);	// Pushes a varlen string	void PushVarlenString(const char* value);	// Push a global variable value	void PushGlobalVariable(int globalVarOffset, eRunningScriptWrapperDataValueType valueType, bool bIsReturnedValue = true);	// Pushes a return argument	void PushReturnArgument(eRunningScriptWrapperDataValueType valueType);	// Pushes return arguments	void PushReturnArguments(eRunningScriptWrapperDataValueType valueType, int count);private:	// Initializes wrapper variables	void InitWrapperVars();	// Pushes string value	void PushStringAsVar(const char* value, eRunningScriptWrapperDataValueType valueType, bool bIsReturnedValue);	// Writes an argument a local/global variable	void WriteArgumentVariable(eArgumentDataTypesFormat_GTA_III_VC_SA argumentType, int numberOfLocalVarsTaken);};

 

 

 

Here is the implementation:

 

 

// Pushes integer valuevoid CRunningScriptWrapper::PushInt(__int32 value, bool bIsReturnedValue){	this -> tls[pushArgIndex].nParam = value;		if(bIsReturnedValue)	{		tRunningScriptWrapperDataValue& returnedValue = this -> ReturnedValues[this -> pushReturnValueIndex++];		returnedValue.type = RUNNING_SCRIPT_VALUE_TYPE_INT;		returnedValue.data.pInt = &this -> tls[pushArgIndex].nParam;	}	this -> WriteArgumentVariable(SCM_ARGUMENT_TYPE_LOCAL_NUMBER_VARIABLE, 1);}

 

 

 

For passing return variables the following function is used:

SCMwrapper.PushReturnArgument(RUNNING_SCRIPT_VALUE_TYPE_INT);
Edited by goodidea82

Share this post


Link to post
Share on other sites
fastman92

Some SCM commands (mostly related to pickups) not only will read a value a value from variable, but also update a value.

The variable must be passed then. bIsReturnedValue needs to be true.

Basically, it's never wrong if bIsReturnedValue will be set true.

 

New possible value can be found within ReturnedValues.

According to order of values that were said to be "returned".

Edited by fastman92

Share this post


Link to post
Share on other sites
goodidea82

Is there a way to find out which opcodes have arguments with such double roles?

 

FYI. So far I'm using the gtag database to find out which parameters are input and output parameters, I'm not aware how to recognize if a parameter is both input and output.

Share this post


Link to post
Share on other sites
fastman92

Is there a way to find out which opcodes have arguments with such double roles?

 

FYI. So far I'm using the gtag database to find out which parameters are input and output parameters, I'm not aware how to recognize if a parameter is both input and output.

The SCM commands that use this function:

 

.text:00464250     ; ScriptVar __thiscall CRunningScript::CollectNextParameterWithoutIncreasingPC(CRunningScript *this).text:00464250     _ZN14CRunningScript39CollectNextParameterWithoutIncreasingPCEv proc near
Example:

 

    case 0x186:      CRunningScript::CollectParameters(this, 1u);      v65 = CRunningScript::CollectNextParameterWithoutIncreasingPC(v2).dwParam;      CRadar::GetActualBlipArrayIndex(v65);      v64 = CRadar::setEntityBlip(1, CollectiveArray[0].dwParam, 0, 3);      goto LABEL_114;LABEL_114:      v66 = v64;      CRadar::setBlipScaleMode(v64, 3);      goto LABEL_120;LABEL_120:      CollectiveArray[0].dwParam = v66;      CRunningScript__StoreParameters(v2, 1);      return 0;
http://gtag.gtagaming.com/opcode-database/opcode/0186/

 

The second parameter is read and written.

Edited by fastman92
  • Like 1

Share this post


Link to post
Share on other sites
goodidea82

I'm not an IDA user. Could you or someone create a complete list of opcodes (up to opcode 05A8) which have these special parameters?

(I only need to create wrappers for opcodes that exist either in VC or LC, so do not need opcodes above 05A8)

 

Edit: perhaps, providing the surrounding code where it appears is sufficient (as done above), because it's possible to see which opcode it is.

 

Edit2: And I don't need opcodes that do arithmetic operations, e.g. +=, *=, -= because they behave the same in all games, so I don't need wrappers for opcodes below 004B.

Edited by goodidea82

Share this post


Link to post
Share on other sites
fastman92

I'm not an IDA user. Could you or someone create a complete list of opcodes (up to opcode 05A8) which have these special parameters?

(I only need to create wrappers for opcodes that exist either in VC or LC, so do not need opcodes above 05A8)

 

Edit: perhaps, providing the surrounding code where it appears is sufficient (as done above), because it's possible to see which opcode it is.

 

Edit2: And I don't need opcodes that do arithmetic operations, e.g. +=, *=, -= because they behave the same in all games, so I don't need wrappers for opcodes below 004B.

You could consider all the values to be returned.

Nothing bad will happen.

Share this post


Link to post
Share on other sites
goodidea82

Here is an example how my wrapper looks for 0186 (it's automatically generated):

/* add blip for car    PARAMS: carHandle,varInt */OpcodeResult WINAPI opcode1186(CScriptThread* t){    DWORD carHandle1 = CLEO_GetIntOpcodeParam(t);    SCMwrapper.PushInt(carHandle1, false);    SCMwrapper.PushReturnArgument(RUNNING_SCRIPT_VALUE_TYPE_INT);    SCMwrapper.CallCommand(0x0186);    SCMwrapper.SaveReturnedValues(retVal);    CLEO_SetIntOpcodeParam(t, retVal.returnedValues[0].Int);    return OR_CONTINUE;}

The problem in this code is that the second parameter is treated only as a return parameter. There is an input file for my generator which tells it that the scond parameter is a return parameter and therefore it generates not call to a CLEO function which reads the second parameters as input.

 

If I understand you correctly, you suggest that I should read for all opcodes, all parameters as input parameters (using functions such as CLEO_GetIntOpcodeParam(t);) and never use the function SCMwrapper.PushReturnArgument(RUNNING_SCRIPT_VALUE_TYPE_INT);, but only SCMwrapper.PushInt(carHandle1, true); on all parameters. Is that correct?

 

The code would look like this:

/* add blip for car    PARAMS: carHandle,varInt */OpcodeResult WINAPI opcode1186(CScriptThread* t){    DWORD carHandle1 = CLEO_GetIntOpcodeParam(t);    DWORD blibInt    = CLEO_GetIntOpcodeParam(t);    SCMwrapper.PushInt(carHandle1, true);    SCMwrapper.PushInt(blibInt, true); //SCMwrapper.PushReturnArgument(RUNNING_SCRIPT_VALUE_TYPE_INT);    SCMwrapper.CallCommand(0x0186);    SCMwrapper.SaveReturnedValues(retVal);    CLEO_SetIntOpcodeParam(t, retVal.returnedValues[1].Int);    return OR_CONTINUE;}

However, a problem here is that when CLEO_SetIntOpcodeParam(t, retVal.returnedValues[1].Int); is called, this is like a third parameter, but the opcode has only 2 parameters. So somehow the second parameters would have to be read and written without incrementing the parameter index (or program counter).

 

Edit:

I guess the problem can be solved when using the the fuction SCRIPT_VAR * WINAPI CLEO_GetPointerToScriptVariable(CScriptThread *thread); for all return variables. Using this functions variable parameter can be read and written via the pointer while progressing the program counter only once (not twice).

 

 

/* add blip for car    PARAMS: carHandle,varInt */OpcodeResult WINAPI opcode1186(CScriptThread* t){    DWORD carHandle1 = CLEO_GetIntOpcodeParam(t);    SCRIPT_VAR * blibIntVar = CLEO_GetPointerToScriptVariable(t);    DWORD blibInt = blibIntVar->dwParam;    SCMwrapper.PushInt(carHandle1, true);    SCMwrapper.PushInt(blibInt, true); //SCMwrapper.PushReturnArgument(RUNNING_SCRIPT_VALUE_TYPE_INT);    SCMwrapper.CallCommand(0x0186);    SCMwrapper.SaveReturnedValues(retVal);    blibIntVar->dwParam = retVal.returnedValues[1].Int;  //CLEO_SetIntOpcodeParam(t, retVal.returnedValues[1].Int);    return OR_CONTINUE;}

 

 

However, this makes the whole thing more complicated. If the number of opcodes in the range 004B - 05A8 which have these special parameters is very small, then it would be better to treat only those in a special way instead of doing this for all the opcodes. So if a simple text search for "CollectNextParameterWithoutIncreasingPC" in IDA would do the job, that would be helpful.

Edited by goodidea82

Share this post


Link to post
Share on other sites
fastman92

However, a problem here is that when CLEO_SetIntOpcodeParam(t, retVal.returnedValues[1].Int); is called, this is like a third parameter, but the opcode has only 2 parameters. So somehow the second parameters would have to be read and written without incrementing the parameter index (or program counter).

That's not SCM wrapper problem, but maybe a functionality of CLEO.

Share this post


Link to post
Share on other sites
goodidea82

That's right, this is not an SCM wrapper problem but a problem how I must read and write parameters of (a) the wrapper opcode using CLEO (e.g. 1186), and (b) of the original opcode using SCMwrapper (e.g. 0186). The wrapper must have the same signature as the original one.

 

At the end of my last post I describe how to probably solve it, but I would like to apply this solution only to the opcodes which use the CollectNextParameterWithoutIncreasingPC function.

Share this post


Link to post
Share on other sites
fastman92

That's right, this is not an SCM wrapper problem but a problem how I must read and write parameters of (a) the wrapper opcode using CLEO (e.g. 1186), and (b) of the original opcode using SCMwrapper (e.g. 0186). The wrapper must have the same signature as the original one.

 

At the end of my last post I describe how to probably solve it, but I would like to apply this solution only to the opcodes which use the CollectNextParameterWithoutIncreasingPC function.

You need to use a function to push a local variable for these opcodes.

Share this post


Link to post
Share on other sites
goodidea82

Back in 2016 I have solved the problem as described at the very bottom (last code snipet) of this post. I save the pointers to all the parameters to make them available for writing after callling the original opcode. I guess this is what you mean with "push a local variable for these opcodes". Thanks

Share this post


Link to post
Share on other sites
goodidea82

Dumping information here for later use because I close the issue on Github.

 

 

 

Some earlier version had a wrapper (SCMWrapper) for opcodes (developed by fastman92), but now the API is missing:
https://github.com/DK22Pac/plugin-sdk/blob/master/src/sdk/plugin/script/wrapper.h
This API is important for because I already have a lot of custom code that depend on it.

(Some background: http://gtaforums.com/topic/838490-cleo-plugin-how-to-call-an-opcode-within-a-cleo-plugin/?p=1068513051)

Owner DK22Pac commented 22 days ago edited

It's possible to "call" an opcode in this way:

#include "extensions\ScriptCommands.h"using namespace plugin::test;// ...ScriptCommand<PRINT_NOW>("FEC_INC", 150, 1);
#include "plugin_III.h"#include "extensions\ScriptCommands.h"using namespace plugin;using namespace plugin::test;class Gta3ScriptCommandsTest {public:    Gta3ScriptCommandsTest() {        Events::processScriptsEvent += [] {            int PlayerChar, PlayerCar;            float CoordX, CoordY, CoordZ;            if (ScriptCommand<IS_PLAYER_PLAYING>(0))            {                ScriptCommand<GET_PLAYER_CHAR>(0, &PlayerChar);                if (ScriptCommand<IS_CHAR_IN_ANY_CAR>(PlayerChar))                {                    ScriptCommand<STORE_CAR_CHAR_IS_IN_NO_SAVE>(PlayerChar, &PlayerCar);                    ScriptCommand<GET_CAR_COORDINATES>(PlayerCar, &CoordX, &CoordY, &CoordZ);                    ScriptCommand<DRAW_SHADOW>(3, CoordX, CoordY, CoordZ, 0.0f, 3.0f, 150, 255, 0, 0);                    ScriptCommand<PRINT_NOW>("FEC_INC", 150, 1);                }            }        };    }} test;
goodidea82 commented 21 days ago edited

Thanks for the quick reply.
I have a special use case where wrapper functions are automatically generated for opcodes.

Can I use hex-numbers instead of opcode names? E.g.
ScriptCommand< 0x00AA >(PlayerCar, &CoordX, &CoordY, &CoordZ);

Do I need the "Events::processScriptsEvent += [] {...}" to call an opcode and what does it mean?

I want the called opcode have the same effect on the current thread as a normal opcode would have. How do I pass the thread-pointer to the ScriptCommand? (or obtain a thread pointer if it has its own thread) In my code I have a function "copyThreadAttrToWrapper" that translates the state from the current thread to the fastman's SCMwrapper's thread and "copyWrapperToThread" to translate it back.

Here is an example of what I mean:

void op00A0(DWORD actHandle1, float& varX2, float& varY3, float& varZ4){
SCMwrapper.PushInt(actHandle1, true);
SCMwrapper.PushFloat(varX2, true);
SCMwrapper.PushFloat(varY3, true);
SCMwrapper.PushFloat(varZ4, true);
copyThreadAttrToWrapper(curThread, SCMwrapper, (curThread->notFlag? 0x80A0: 0x00A0));
cmdResult = SCMwrapper.CallCommand(curThread->notFlag? 0x80A0: 0x00A0);
copyWrapperToThread(SCMwrapper, curThread);
SCMwrapper.SaveReturnedValues(retVal);
varX2 = varX(retVal.returnedValues[1].Float);
varY3 = varY(retVal.returnedValues[2].Float);
varZ4 = varZ(retVal.returnedValues[3].Float);
}

The easiest for me would be if fastman's SCMwrapper API would be added back.

Owner DK22Pac commented 18 days ago edited

Yes.

Can I use hex-numbers instead of opcode names?

 

 

Do I need the "Events::processScriptsEvent += [] {...}" to call an opcode and what does it mean?

 

It's recommended to 'call' opcodes when scripts are 'processed' (i.e. executed). That's why processScriptsEvent event is used in this example.

 

 

How do I pass the thread-pointer to the ScriptCommand?

 

Not possible yet.

 

 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this  

  • 2 Users Currently Viewing
    0 members, 0 Anonymous, 2 Guests

×
×
  • Create New...

Important Information

By using GTAForums.com, you agree to our Terms of Use and Privacy Policy.