diff --git a/metamod/include/dlls/enginecallback.h b/metamod/include/dlls/enginecallback.h index dbe3e71..987ee35 100644 --- a/metamod/include/dlls/enginecallback.h +++ b/metamod/include/dlls/enginecallback.h @@ -67,7 +67,7 @@ extern enginefuncs_t g_engfuncs; #define TRACE_MODEL (*g_engfuncs.pfnTraceModel) #define GET_AIM_VECTOR (*g_engfuncs.pfnGetAimVector) #define SERVER_COMMAND (*g_engfuncs.pfnServerCommand) -#define SERVER_EXECUTE (*g_engfuncs.pfnServerExecute) +//#define SERVER_EXECUTE (*g_engfuncs.pfnServerExecute) #define CLIENT_COMMAND (*g_engfuncs.pfnClientCommand) #define PARTICLE_EFFECT (*g_engfuncs.pfnParticleEffect) #define LIGHT_STYLE (*g_engfuncs.pfnLightStyle) diff --git a/metamod/msvc/metamod.vcxproj b/metamod/msvc/metamod.vcxproj index 4f541fc..f93cbe2 100644 --- a/metamod/msvc/metamod.vcxproj +++ b/metamod/msvc/metamod.vcxproj @@ -48,7 +48,7 @@ $(ProjectName)_mm - $(ProjectName)_mm + $(ProjectName) @@ -130,6 +130,7 @@ true Default precompiled.h + false .\release/metamod.dll @@ -175,6 +176,7 @@ + @@ -204,6 +206,7 @@ + @@ -211,18 +214,16 @@ - + - - diff --git a/metamod/msvc/metamod.vcxproj.filters b/metamod/msvc/metamod.vcxproj.filters index 8bb217f..207f621 100644 --- a/metamod/msvc/metamod.vcxproj.filters +++ b/metamod/msvc/metamod.vcxproj.filters @@ -83,6 +83,9 @@ Source Files + + Source Files + @@ -109,9 +112,6 @@ Source Files - - Source Files - Source Files @@ -130,9 +130,6 @@ Source Files - - Source Files - Source Files @@ -142,9 +139,6 @@ Source Files - - Source Files - Source Files @@ -178,6 +172,12 @@ Source Files + + Source Files + + + Source Files + diff --git a/metamod/src/api_info.cpp b/metamod/src/api_info.cpp index 96229de..8918ef9 100644 --- a/metamod/src/api_info.cpp +++ b/metamod/src/api_info.cpp @@ -1,234 +1,239 @@ #include "precompiled.h" +#define API_ENTRY(table, name, loglevel) { offsetof(table, pfn##name), #table "::" #name, loglevel } +#define DLLAPI_ENTRY(name, loglevel) API_ENTRY(DLL_FUNCTIONS, name, loglevel) +#define NEWAPI_ENTRY(name, loglevel) API_ENTRY(NEW_DLL_FUNCTIONS, name, loglevel) +#define ENGAPI_ENTRY(name, loglevel) API_ENTRY(enginefuncs_t, name, loglevel) + // trace flag, loglevel, name dllapi_info_t dllapi_info = { - { mFALSE, 3, "GameDLLInit" }, // pfnGameInit - { mFALSE, 10, "DispatchSpawn" }, // pfnSpawn - { mFALSE, 16, "DispatchThink" }, // pfnThink - { mFALSE, 9, "DispatchUse" }, // pfnUse - { mFALSE, 11, "DispatchTouch" }, // pfnTouch - { mFALSE, 9, "DispatchBlocked" }, // pfnBlocked - { mFALSE, 10, "DispatchKeyValue" }, // pfnKeyValue - { mFALSE, 9, "DispatchSave" }, // pfnSave - { mFALSE, 9, "DispatchRestore" }, // pfnRestore - { mFALSE, 20, "DispatchObjectCollsionBox" }, // pfnSetAbsBox - { mFALSE, 9, "SaveWriteFields" }, // pfnSaveWriteFields - { mFALSE, 9, "SaveReadFields" }, // pfnSaveReadFields - { mFALSE, 9, "SaveGlobalState" }, // pfnSaveGlobalState - { mFALSE, 9, "RestoreGlobalState" }, // pfnRestoreGlobalState - { mFALSE, 9, "ResetGlobalState" }, // pfnResetGlobalState - { mFALSE, 3, "ClientConnect" }, // pfnClientConnect - { mFALSE, 3, "ClientDisconnect" }, // pfnClientDisconnect - { mFALSE, 3, "ClientKill" }, // pfnClientKill - { mFALSE, 3, "ClientPutInServer" }, // pfnClientPutInServer - { mFALSE, 9, "ClientCommand" }, // pfnClientCommand - { mFALSE, 11, "ClientUserInfoChanged" }, // pfnClientUserInfoChanged - { mFALSE, 3, "ServerActivate" }, // pfnServerActivate - { mFALSE, 3, "ServerDeactivate" }, // pfnServerDeactivate - { mFALSE, 14, "PlayerPreThink" }, // pfnPlayerPreThink - { mFALSE, 14, "PlayerPostThink" }, // pfnPlayerPostThink - { mFALSE, 18, "StartFrame" }, // pfnStartFrame - { mFALSE, 9, "ParmsNewLevel" }, // pfnParmsNewLevel - { mFALSE, 9, "ParmsChangeLevel" }, // pfnParmsChangeLevel - { mFALSE, 9, "GetGameDescription" }, // pfnGetGameDescription - { mFALSE, 9, "PlayerCustomization" }, // pfnPlayerCustomization - { mFALSE, 9, "SpectatorConnect" }, // pfnSpectatorConnect - { mFALSE, 9, "SpectatorDisconnect" }, // pfnSpectatorDisconnect - { mFALSE, 9, "SpectatorThink" }, // pfnSpectatorThink - { mFALSE, 3, "Sys_Error" }, // pfnSys_Error - { mFALSE, 13, "PM_Move" }, // pfnPM_Move - { mFALSE, 9, "PM_Init" }, // pfnPM_Init - { mFALSE, 9, "PM_FindTextureType" }, // pfnPM_FindTextureType - { mFALSE, 12, "SetupVisibility" }, // pfnSetupVisibility - { mFALSE, 12, "UpdateClientData" }, // pfnUpdateClientData - { mFALSE, 16, "AddToFullPack" }, // pfnAddToFullPack - { mFALSE, 9, "CreateBaseline" }, // pfnCreateBaseline - { mFALSE, 9, "RegisterEncoders" }, // pfnRegisterEncoders - { mFALSE, 9, "GetWeaponData" }, // pfnGetWeaponData - { mFALSE, 15, "CmdStart" }, // pfnCmdStart - { mFALSE, 15, "CmdEnd" }, // pfnCmdEnd - { mFALSE, 9, "ConnectionlessPacket" }, // pfnConnectionlessPacket - { mFALSE, 9, "GetHullBounds" }, // pfnGetHullBounds - { mFALSE, 9, "CreateInstancedBaselines" }, // pfnCreateInstancedBaselines - { mFALSE, 3, "InconsistentFile" }, // pfnInconsistentFile - { mFALSE, 20, "AllowLagCompensation" }, // pfnAllowLagCompensation + DLLAPI_ENTRY(GameInit, 1), // pfnGameInit + DLLAPI_ENTRY(Spawn, 2), // pfnSpawn + DLLAPI_ENTRY(Think, 2), // pfnThink + DLLAPI_ENTRY(Use, 2), // pfnUse + DLLAPI_ENTRY(Touch, 2), // pfnTouch + DLLAPI_ENTRY(Blocked, 2), // pfnBlocked + DLLAPI_ENTRY(KeyValue, 4), // pfnKeyValue + DLLAPI_ENTRY(Save, 4), // pfnSave + DLLAPI_ENTRY(Restore, 4), // pfnRestore + DLLAPI_ENTRY(SetAbsBox, 2), // pfnSetAbsBox + DLLAPI_ENTRY(SaveWriteFields, 4), // pfnSaveWriteFields + DLLAPI_ENTRY(SaveReadFields, 4), // pfnSaveReadFields + DLLAPI_ENTRY(SaveGlobalState, 4), // pfnSaveGlobalState + DLLAPI_ENTRY(RestoreGlobalState, 4), // pfnRestoreGlobalState + DLLAPI_ENTRY(ResetGlobalState, 4), // pfnResetGlobalState + DLLAPI_ENTRY(ClientConnect, 1), // pfnClientConnect + DLLAPI_ENTRY(ClientDisconnect, 1), // pfnClientDisconnect + DLLAPI_ENTRY(ClientKill, 2), // pfnClientKill + DLLAPI_ENTRY(ClientPutInServer, 1), // pfnClientPutInServer + DLLAPI_ENTRY(ClientCommand, 2), // pfnClientCommand + DLLAPI_ENTRY(ClientUserInfoChanged, 2), // pfnClientUserInfoChanged + DLLAPI_ENTRY(ServerActivate, 1), // pfnServerActivate + DLLAPI_ENTRY(ServerDeactivate, 1), // pfnServerDeactivate + DLLAPI_ENTRY(PlayerPreThink, 3), // pfnPlayerPreThink + DLLAPI_ENTRY(PlayerPostThink, 3), // pfnPlayerPostThink + DLLAPI_ENTRY(StartFrame, 4), // pfnStartFrame + DLLAPI_ENTRY(ParmsNewLevel, 4), // pfnParmsNewLevel + DLLAPI_ENTRY(ParmsChangeLevel, 4), // pfnParmsChangeLevel + DLLAPI_ENTRY(GetGameDescription, 3), // pfnGetGameDescription + DLLAPI_ENTRY(PlayerCustomization, 4), // pfnPlayerCustomization + DLLAPI_ENTRY(SpectatorConnect, 3), // pfnSpectatorConnect + DLLAPI_ENTRY(SpectatorDisconnect, 3), // pfnSpectatorDisconnect + DLLAPI_ENTRY(SpectatorThink, 3), // pfnSpectatorThink + DLLAPI_ENTRY(Sys_Error, 4), // pfnSys_Error + DLLAPI_ENTRY(PM_Move, 3), // pfnPM_Move + DLLAPI_ENTRY(PM_Init, 1), // pfnPM_Init + DLLAPI_ENTRY(PM_FindTextureType, 3), // pfnPM_FindTextureType + DLLAPI_ENTRY(SetupVisibility, 3), // pfnSetupVisibility + DLLAPI_ENTRY(UpdateClientData, 3), // pfnUpdateClientData + DLLAPI_ENTRY(AddToFullPack, 3), // pfnAddToFullPack + DLLAPI_ENTRY(CreateBaseline, 4), // pfnCreateBaseline + DLLAPI_ENTRY(RegisterEncoders, 4), // pfnRegisterEncoders + DLLAPI_ENTRY(GetWeaponData, 3), // pfnGetWeaponData + DLLAPI_ENTRY(CmdStart, 3), // pfnCmdStart + DLLAPI_ENTRY(CmdEnd, 3), // pfnCmdEnd + DLLAPI_ENTRY(ConnectionlessPacket, 4), // pfnConnectionlessPacket + DLLAPI_ENTRY(GetHullBounds, 3), // pfnGetHullBounds + DLLAPI_ENTRY(CreateInstancedBaselines, 4), // pfnCreateInstancedBaselines + DLLAPI_ENTRY(InconsistentFile, 3), // pfnInconsistentFile + DLLAPI_ENTRY(AllowLagCompensation, 4), // pfnAllowLagCompensation - { mFALSE, 0, nullptr }, + { 0, "", 0 }, }; newapi_info_t newapi_info = { - { mFALSE, 16, "OnFreeEntPrivateData" }, // pfnOnFreeEntPrivateData - { mFALSE, 3, "GameShutdown" }, // pfnGameShutdown - { mFALSE, 14, "ShouldCollide" }, // pfnShouldCollide - { mFALSE, 3, "CvarValue" }, // pfnCvarValue - { mFALSE, 3, "CvarValue2" }, // pfnCvarValue2 + NEWAPI_ENTRY(OnFreeEntPrivateData, 3), // pfnOnFreeEntPrivateData + NEWAPI_ENTRY(GameShutdown, 3), // pfnGameShutdown + NEWAPI_ENTRY(ShouldCollide, 3), // pfnShouldCollide + NEWAPI_ENTRY(CvarValue, 2), // pfnCvarValue + NEWAPI_ENTRY(CvarValue2, 2), // pfnCvarValue2 - { mFALSE, 0, nullptr }, + { 0, "", 0 }, }; engine_info_t engine_info = { - { mFALSE, 13, "PrecacheModel" }, // pfnPrecacheModel - { mFALSE, 13, "PrecacheSound" }, // pfnPrecacheSound - { mFALSE, 18, "SetModel" }, // pfnSetModel - { mFALSE, 34, "ModelIndex" }, // pfnModelIndex - { mFALSE, 10, "ModelFrames" }, // pfnModelFrames - { mFALSE, 14, "SetSize" }, // pfnSetSize - { mFALSE, 9, "ChangeLevel" }, // pfnChangeLevel - { mFALSE, 9, "GetSpawnParms" }, // pfnGetSpawnParms - { mFALSE, 9, "SaveSpawnParms" }, // pfnSaveSpawnParms - { mFALSE, 9, "VecToYaw" }, // pfnVecToYaw - { mFALSE, 14, "VecToAngles" }, // pfnVecToAngles - { mFALSE, 9, "MoveToOrigin" }, // pfnMoveToOrigin - { mFALSE, 9, "ChangeYaw" }, // pfnChangeYaw - { mFALSE, 9, "ChangePitch" }, // pfnChangePitch - { mFALSE, 32, "FindEntityByString" }, // pfnFindEntityByString - { mFALSE, 9, "GetEntityIllum" }, // pfnGetEntityIllum - { mFALSE, 9, "FindEntityInSphere" }, // pfnFindEntityInSphere - { mFALSE, 19, "FindClientInPVS" }, // pfnFindClientInPVS - { mFALSE, 9, "EntitiesInPVS" }, // pfnEntitiesInPVS - { mFALSE, 40, "MakeVectors" }, // pfnMakeVectors - { mFALSE, 9, "AngleVectors" }, // pfnAngleVectors - { mFALSE, 13, "CreateEntity" }, // pfnCreateEntity - { mFALSE, 13, "RemoveEntity" }, // pfnRemoveEntity - { mFALSE, 13, "CreateNamedEntity" }, // pfnCreateNamedEntity - { mFALSE, 9, "MakeStatic" }, // pfnMakeStatic - { mFALSE, 9, "EntIsOnFloor" }, // pfnEntIsOnFloor - { mFALSE, 9, "DropToFloor" }, // pfnDropToFloor - { mFALSE, 9, "WalkMove" }, // pfnWalkMove - { mFALSE, 14, "SetOrigin" }, // pfnSetOrigin - { mFALSE, 12, "EmitSound" }, // pfnEmitSound - { mFALSE, 12, "EmitAmbientSound" }, // pfnEmitAmbientSound - { mFALSE, 20, "TraceLine" }, // pfnTraceLine - { mFALSE, 9, "TraceToss" }, // pfnTraceToss - { mFALSE, 9, "TraceMonsterHull" }, // pfnTraceMonsterHull - { mFALSE, 9, "TraceHull" }, // pfnTraceHull - { mFALSE, 9, "TraceModel" }, // pfnTraceModel - { mFALSE, 15, "TraceTexture" }, // pfnTraceTexture // CS: when moving - { mFALSE, 9, "TraceSphere" }, // pfnTraceSphere - { mFALSE, 9, "GetAimVector" }, // pfnGetAimVector - { mFALSE, 9, "ServerCommand" }, // pfnServerCommand - { mFALSE, 9, "ServerExecute" }, // pfnServerExecute - { mFALSE, 11, "engClientCommand" }, // pfnClientCommand // d'oh, ClientCommand in dllapi too - { mFALSE, 9, "ParticleEffect" }, // pfnParticleEffect - { mFALSE, 9, "LightStyle" }, // pfnLightStyle - { mFALSE, 9, "DecalIndex" }, // pfnDecalIndex - { mFALSE, 15, "PointContents" }, // pfnPointContents // CS: when moving - { mFALSE, 22, "MessageBegin" }, // pfnMessageBegin - { mFALSE, 22, "MessageEnd" }, // pfnMessageEnd - { mFALSE, 30, "WriteByte" }, // pfnWriteByte - { mFALSE, 23, "WriteChar" }, // pfnWriteChar - { mFALSE, 24, "WriteShort" }, // pfnWriteShort - { mFALSE, 23, "WriteLong" }, // pfnWriteLong - { mFALSE, 23, "WriteAngle" }, // pfnWriteAngle - { mFALSE, 23, "WriteCoord" }, // pfnWriteCoord - { mFALSE, 25, "WriteString" }, // pfnWriteString - { mFALSE, 23, "WriteEntity" }, // pfnWriteEntity - { mFALSE, 9, "CVarRegister" }, // pfnCVarRegister - { mFALSE, 21, "CVarGetFloat" }, // pfnCVarGetFloat - { mFALSE, 9, "CVarGetString" }, // pfnCVarGetString - { mFALSE, 10, "CVarSetFloat" }, // pfnCVarSetFloat - { mFALSE, 9, "CVarSetString" }, // pfnCVarSetString - { mFALSE, 15, "AlertMessage" }, // pfnAlertMessage - { mFALSE, 17, "EngineFprintf" }, // pfnEngineFprintf - { mFALSE, 14, "PvAllocEntPrivateData" }, // pfnPvAllocEntPrivateData - { mFALSE, 9, "PvEntPrivateData" }, // pfnPvEntPrivateData - { mFALSE, 9, "FreeEntPrivateData" }, // pfnFreeEntPrivateData - { mFALSE, 9, "SzFromIndex" }, // pfnSzFromIndex - { mFALSE, 10, "AllocString" }, // pfnAllocString - { mFALSE, 9, "GetVarsOfEnt" }, // pfnGetVarsOfEnt - { mFALSE, 14, "PEntityOfEntOffset" }, // pfnPEntityOfEntOffset - { mFALSE, 19, "EntOffsetOfPEntity" }, // pfnEntOffsetOfPEntity - { mFALSE, 14, "IndexOfEdict" }, // pfnIndexOfEdict - { mFALSE, 17, "PEntityOfEntIndex" }, // pfnPEntityOfEntIndex - { mFALSE, 9, "FindEntityByVars" }, // pfnFindEntityByVars - { mFALSE, 14, "GetModelPtr" }, // pfnGetModelPtr - { mFALSE, 9, "RegUserMsg" }, // pfnRegUserMsg - { mFALSE, 9, "AnimationAutomove" }, // pfnAnimationAutomove - { mFALSE, 9, "GetBonePosition" }, // pfnGetBonePosition - { mFALSE, 9, "FunctionFromName" }, // pfnFunctionFromName - { mFALSE, 9, "NameForFunction" }, // pfnNameForFunction - { mFALSE, 9, "ClientPrintf" }, // pfnClientPrintf - { mFALSE, 9, "ServerPrint" }, // pfnServerPrint - { mFALSE, 13, "Cmd_Args" }, // pfnCmd_Args - { mFALSE, 13, "Cmd_Argv" }, // pfnCmd_Argv - { mFALSE, 13, "Cmd_Argc" }, // pfnCmd_Argc - { mFALSE, 9, "GetAttachment" }, // pfnGetAttachment - { mFALSE, 9, "CRC32_Init" }, // pfnCRC32_Init - { mFALSE, 9, "CRC32_ProcessBuffer" }, // pfnCRC32_ProcessBuffer - { mFALSE, 9, "CRC32_ProcessByte" }, // pfnCRC32_ProcessByte - { mFALSE, 9, "CRC32_Final" }, // pfnCRC32_Final - { mFALSE, 16, "RandomLong" }, // pfnRandomLong - { mFALSE, 14, "RandomFloat" }, // pfnRandomFloat // CS: when firing - { mFALSE, 14, "SetView" }, // pfnSetView - { mFALSE, 9, "Time" }, // pfnTime - { mFALSE, 9, "CrosshairAngle" }, // pfnCrosshairAngle - { mFALSE, 10, "LoadFileForMe" }, // pfnLoadFileForMe - { mFALSE, 10, "FreeFile" }, // pfnFreeFile - { mFALSE, 9, "EndSection" }, // pfnEndSection - { mFALSE, 9, "CompareFileTime" }, // pfnCompareFileTime - { mFALSE, 9, "GetGameDir" }, // pfnGetGameDir - { mFALSE, 9, "Cvar_RegisterVariable" }, // pfnCvar_RegisterVariable - { mFALSE, 9, "FadeClientVolume" }, // pfnFadeClientVolume - { mFALSE, 14, "SetClientMaxspeed" }, // pfnSetClientMaxspeed - { mFALSE, 9, "CreateFakeClient" }, // pfnCreateFakeClient - { mFALSE, 9, "RunPlayerMove" }, // pfnRunPlayerMove - { mFALSE, 9, "NumberOfEntities" }, // pfnNumberOfEntities - { mFALSE, 17, "GetInfoKeyBuffer" }, // pfnGetInfoKeyBuffer - { mFALSE, 13, "InfoKeyValue" }, // pfnInfoKeyValue - { mFALSE, 9, "SetKeyValue" }, // pfnSetKeyValue - { mFALSE, 12, "SetClientKeyValue" }, // pfnSetClientKeyValue - { mFALSE, 9, "IsMapValid" }, // pfnIsMapValid - { mFALSE, 9, "StaticDecal" }, // pfnStaticDecal - { mFALSE, 9, "PrecacheGeneric" }, // pfnPrecacheGeneric - { mFALSE, 10, "GetPlayerUserId" }, // pfnGetPlayerUserId - { mFALSE, 9, "BuildSoundMsg" }, // pfnBuildSoundMsg - { mFALSE, 9, "IsDedicatedServer" }, // pfnIsDedicatedServer - { mFALSE, 9, "CVarGetPointer" }, // pfnCVarGetPointer - { mFALSE, 9, "GetPlayerWONId" }, // pfnGetPlayerWONId - { mFALSE, 9, "Info_RemoveKey" }, // pfnInfo_RemoveKey - { mFALSE, 15, "GetPhysicsKeyValue" }, // pfnGetPhysicsKeyValue - { mFALSE, 14, "SetPhysicsKeyValue" }, // pfnSetPhysicsKeyValue - { mFALSE, 15, "GetPhysicsInfoString" }, // pfnGetPhysicsInfoString - { mFALSE, 13, "PrecacheEvent" }, // pfnPrecacheEvent - { mFALSE, 9, "PlaybackEvent" }, // pfnPlaybackEvent - { mFALSE, 31, "SetFatPVS" }, // pfnSetFatPVS - { mFALSE, 31, "SetFatPAS" }, // pfnSetFatPAS - { mFALSE, 50, "CheckVisibility" }, // pfnCheckVisibility - { mFALSE, 37, "DeltaSetField" }, // pfnDeltaSetField - { mFALSE, 38, "DeltaUnsetField" }, // pfnDeltaUnsetField - { mFALSE, 9, "DeltaAddEncoder" }, // pfnDeltaAddEncoder - { mFALSE, 45, "GetCurrentPlayer" }, // pfnGetCurrentPlayer - { mFALSE, 14, "CanSkipPlayer" }, // pfnCanSkipPlayer - { mFALSE, 9, "DeltaFindField" }, // pfnDeltaFindField - { mFALSE, 37, "DeltaSetFieldByIndex" }, // pfnDeltaSetFieldByIndex - { mFALSE, 38, "DeltaUnsetFieldByIndex" }, // pfnDeltaUnsetFieldByIndex - { mFALSE, 9, "SetGroupMask" }, // pfnSetGroupMask - { mFALSE, 9, "engCreateInstancedBaseline" }, // pfnCreateInstancedBaseline // d'oh, CreateInstancedBaseline in dllapi too - { mFALSE, 9, "Cvar_DirectSet" }, // pfnCvar_DirectSet - { mFALSE, 9, "ForceUnmodified" }, // pfnForceUnmodified - { mFALSE, 9, "GetPlayerStats" }, // pfnGetPlayerStats - { mFALSE, 3, "AddServerCommand" }, // pfnAddServerCommand + ENGAPI_ENTRY(PrecacheModel, 2), // pfnPrecacheModel + ENGAPI_ENTRY(PrecacheSound, 2), // pfnPrecacheSound + ENGAPI_ENTRY(SetModel, 2), // pfnSetModel + ENGAPI_ENTRY(ModelIndex, 2), // pfnModelIndex + ENGAPI_ENTRY(ModelFrames, 3), // pfnModelFrames + ENGAPI_ENTRY(SetSize, 2), // pfnSetSize + ENGAPI_ENTRY(ChangeLevel, 2), // pfnChangeLevel + ENGAPI_ENTRY(GetSpawnParms, 4), // pfnGetSpawnParms + ENGAPI_ENTRY(SaveSpawnParms, 4), // pfnSaveSpawnParms + ENGAPI_ENTRY(VecToYaw, 3), // pfnVecToYaw + ENGAPI_ENTRY(VecToAngles, 3), // pfnVecToAngles + ENGAPI_ENTRY(MoveToOrigin, 3), // pfnMoveToOrigin + ENGAPI_ENTRY(ChangeYaw, 3), // pfnChangeYaw + ENGAPI_ENTRY(ChangePitch, 3), // pfnChangePitch + ENGAPI_ENTRY(FindEntityByString, 2), // pfnFindEntityByString + ENGAPI_ENTRY(GetEntityIllum, 4), // pfnGetEntityIllum + ENGAPI_ENTRY(FindEntityInSphere, 2), // pfnFindEntityInSphere + ENGAPI_ENTRY(FindClientInPVS, 2), // pfnFindClientInPVS + ENGAPI_ENTRY(EntitiesInPVS, 2), // pfnEntitiesInPVS + ENGAPI_ENTRY(MakeVectors, 3), // pfnMakeVectors + ENGAPI_ENTRY(AngleVectors, 3), // pfnAngleVectors + ENGAPI_ENTRY(CreateEntity, 2), // pfnCreateEntity + ENGAPI_ENTRY(RemoveEntity, 2), // pfnRemoveEntity + ENGAPI_ENTRY(CreateNamedEntity, 2), // pfnCreateNamedEntity + ENGAPI_ENTRY(MakeStatic, 2), // pfnMakeStatic + ENGAPI_ENTRY(EntIsOnFloor, 2), // pfnEntIsOnFloor + ENGAPI_ENTRY(DropToFloor, 2), // pfnDropToFloor + ENGAPI_ENTRY(WalkMove, 2), // pfnWalkMove + ENGAPI_ENTRY(SetOrigin, 2), // pfnSetOrigin + ENGAPI_ENTRY(EmitSound, 2), // pfnEmitSound + ENGAPI_ENTRY(EmitAmbientSound, 2), // pfnEmitAmbientSound + ENGAPI_ENTRY(TraceLine, 2), // pfnTraceLine + ENGAPI_ENTRY(TraceToss, 2), // pfnTraceToss + ENGAPI_ENTRY(TraceMonsterHull, 2), // pfnTraceMonsterHull + ENGAPI_ENTRY(TraceHull, 2), // pfnTraceHull + ENGAPI_ENTRY(TraceModel, 2), // pfnTraceModel + ENGAPI_ENTRY(TraceTexture, 2), // pfnTraceTexture // CS: when moving + ENGAPI_ENTRY(TraceSphere, 2), // pfnTraceSphere + ENGAPI_ENTRY(GetAimVector, 2), // pfnGetAimVector + ENGAPI_ENTRY(ServerCommand, 3), // pfnServerCommand + ENGAPI_ENTRY(ServerExecute, 3), // pfnServerExecute + ENGAPI_ENTRY(ClientCommand, 3), // pfnClientCommand // d'oh, ClientCommand in dllapi too + ENGAPI_ENTRY(ParticleEffect, 4), // pfnParticleEffect + ENGAPI_ENTRY(LightStyle, 2), // pfnLightStyle + ENGAPI_ENTRY(DecalIndex, 2), // pfnDecalIndex + ENGAPI_ENTRY(PointContents, 2), // pfnPointContents // CS: when moving + ENGAPI_ENTRY(MessageBegin, 3), // pfnMessageBegin + ENGAPI_ENTRY(MessageEnd, 3), // pfnMessageEnd + ENGAPI_ENTRY(WriteByte, 3), // pfnWriteByte + ENGAPI_ENTRY(WriteChar, 3), // pfnWriteChar + ENGAPI_ENTRY(WriteShort, 3), // pfnWriteShort + ENGAPI_ENTRY(WriteLong, 3), // pfnWriteLong + ENGAPI_ENTRY(WriteAngle, 3), // pfnWriteAngle + ENGAPI_ENTRY(WriteCoord, 3), // pfnWriteCoord + ENGAPI_ENTRY(WriteString, 3), // pfnWriteString + ENGAPI_ENTRY(WriteEntity, 3), // pfnWriteEntity + ENGAPI_ENTRY(CVarRegister, 2), // pfnCVarRegister + ENGAPI_ENTRY(CVarGetFloat, 2), // pfnCVarGetFloat + ENGAPI_ENTRY(CVarGetString, 2), // pfnCVarGetString + ENGAPI_ENTRY(CVarSetFloat, 2), // pfnCVarSetFloat + ENGAPI_ENTRY(CVarSetString, 2), // pfnCVarSetString + ENGAPI_ENTRY(AlertMessage, 3), // pfnAlertMessage + ENGAPI_ENTRY(EngineFprintf, 3), // pfnEngineFprintf + ENGAPI_ENTRY(PvAllocEntPrivateData, 2), // pfnPvAllocEntPrivateData + ENGAPI_ENTRY(PvEntPrivateData, 2), // pfnPvEntPrivateData + ENGAPI_ENTRY(FreeEntPrivateData, 2), // pfnFreeEntPrivateData + ENGAPI_ENTRY(SzFromIndex, 3), // pfnSzFromIndex + ENGAPI_ENTRY(AllocString, 3), // pfnAllocString + ENGAPI_ENTRY(GetVarsOfEnt, 2), // pfnGetVarsOfEnt + ENGAPI_ENTRY(PEntityOfEntOffset, 3), // pfnPEntityOfEntOffset + ENGAPI_ENTRY(EntOffsetOfPEntity, 3), // pfnEntOffsetOfPEntity + ENGAPI_ENTRY(IndexOfEdict, 3), // pfnIndexOfEdict + ENGAPI_ENTRY(PEntityOfEntIndex, 3), // pfnPEntityOfEntIndex + ENGAPI_ENTRY(FindEntityByVars, 3), // pfnFindEntityByVars + ENGAPI_ENTRY(GetModelPtr, 3), // pfnGetModelPtr + ENGAPI_ENTRY(RegUserMsg, 3), // pfnRegUserMsg + ENGAPI_ENTRY(AnimationAutomove, 2), // pfnAnimationAutomove + ENGAPI_ENTRY(GetBonePosition, 2), // pfnGetBonePosition + ENGAPI_ENTRY(FunctionFromName, 4), // pfnFunctionFromName + ENGAPI_ENTRY(NameForFunction, 4), // pfnNameForFunction + ENGAPI_ENTRY(ClientPrintf, 3), // pfnClientPrintf + ENGAPI_ENTRY(ServerPrint, 3), // pfnServerPrint + ENGAPI_ENTRY(Cmd_Args, 3), // pfnCmd_Args + ENGAPI_ENTRY(Cmd_Argv, 3), // pfnCmd_Argv + ENGAPI_ENTRY(Cmd_Argc, 3), // pfnCmd_Argc + ENGAPI_ENTRY(GetAttachment, 2), // pfnGetAttachment + ENGAPI_ENTRY(CRC32_Init, 4), // pfnCRC32_Init + ENGAPI_ENTRY(CRC32_ProcessBuffer, 4), // pfnCRC32_ProcessBuffer + ENGAPI_ENTRY(CRC32_ProcessByte, 4), // pfnCRC32_ProcessByte + ENGAPI_ENTRY(CRC32_Final, 4), // pfnCRC32_Final + ENGAPI_ENTRY(RandomLong, 3), // pfnRandomLong + ENGAPI_ENTRY(RandomFloat, 3), // pfnRandomFloat // CS: when firing + ENGAPI_ENTRY(SetView, 2), // pfnSetView + ENGAPI_ENTRY(Time, 2), // pfnTime + ENGAPI_ENTRY(CrosshairAngle, 2), // pfnCrosshairAngle + ENGAPI_ENTRY(LoadFileForMe, 4), // pfnLoadFileForMe + ENGAPI_ENTRY(FreeFile, 4), // pfnFreeFile + ENGAPI_ENTRY(EndSection, 4), // pfnEndSection + ENGAPI_ENTRY(CompareFileTime, 4), // pfnCompareFileTime + ENGAPI_ENTRY(GetGameDir, 3), // pfnGetGameDir + ENGAPI_ENTRY(Cvar_RegisterVariable, 2), // pfnCvar_RegisterVariable + ENGAPI_ENTRY(FadeClientVolume, 2), // pfnFadeClientVolume + ENGAPI_ENTRY(SetClientMaxspeed, 3), // pfnSetClientMaxspeed + ENGAPI_ENTRY(CreateFakeClient, 2), // pfnCreateFakeClient + ENGAPI_ENTRY(RunPlayerMove, 3), // pfnRunPlayerMove + ENGAPI_ENTRY(NumberOfEntities, 2), // pfnNumberOfEntities + ENGAPI_ENTRY(GetInfoKeyBuffer, 2), // pfnGetInfoKeyBuffer + ENGAPI_ENTRY(InfoKeyValue, 2), // pfnInfoKeyValue + ENGAPI_ENTRY(SetKeyValue, 2), // pfnSetKeyValue + ENGAPI_ENTRY(SetClientKeyValue, 2), // pfnSetClientKeyValue + ENGAPI_ENTRY(IsMapValid, 2), // pfnIsMapValid + ENGAPI_ENTRY(StaticDecal, 2), // pfnStaticDecal + ENGAPI_ENTRY(PrecacheGeneric, 2), // pfnPrecacheGeneric + ENGAPI_ENTRY(GetPlayerUserId, 2), // pfnGetPlayerUserId + ENGAPI_ENTRY(BuildSoundMsg, 2), // pfnBuildSoundMsg + ENGAPI_ENTRY(IsDedicatedServer, 2), // pfnIsDedicatedServer + ENGAPI_ENTRY(CVarGetPointer, 3), // pfnCVarGetPointer + ENGAPI_ENTRY(GetPlayerWONId, 4), // pfnGetPlayerWONId + ENGAPI_ENTRY(Info_RemoveKey, 2), // pfnInfo_RemoveKey + ENGAPI_ENTRY(GetPhysicsKeyValue, 2), // pfnGetPhysicsKeyValue + ENGAPI_ENTRY(SetPhysicsKeyValue, 2), // pfnSetPhysicsKeyValue + ENGAPI_ENTRY(GetPhysicsInfoString, 2), // pfnGetPhysicsInfoString + ENGAPI_ENTRY(PrecacheEvent, 2), // pfnPrecacheEvent + ENGAPI_ENTRY(PlaybackEvent, 2), // pfnPlaybackEvent + ENGAPI_ENTRY(SetFatPVS, 2), // pfnSetFatPVS + ENGAPI_ENTRY(SetFatPAS, 2), // pfnSetFatPAS + ENGAPI_ENTRY(CheckVisibility, 2), // pfnCheckVisibility + ENGAPI_ENTRY(DeltaSetField, 3), // pfnDeltaSetField + ENGAPI_ENTRY(DeltaUnsetField, 3), // pfnDeltaUnsetField + ENGAPI_ENTRY(DeltaAddEncoder, 3), // pfnDeltaAddEncoder + ENGAPI_ENTRY(GetCurrentPlayer, 2), // pfnGetCurrentPlayer + ENGAPI_ENTRY(CanSkipPlayer, 2), // pfnCanSkipPlayer + ENGAPI_ENTRY(DeltaFindField, 3), // pfnDeltaFindField + ENGAPI_ENTRY(DeltaSetFieldByIndex, 3), // pfnDeltaSetFieldByIndex + ENGAPI_ENTRY(DeltaUnsetFieldByIndex, 3), // pfnDeltaUnsetFieldByIndex + ENGAPI_ENTRY(SetGroupMask, 2), // pfnSetGroupMask + ENGAPI_ENTRY(CreateInstancedBaseline, 3), // pfnCreateInstancedBaseline // d'oh, CreateInstancedBaseline in dllapi too + ENGAPI_ENTRY(Cvar_DirectSet, 2), // pfnCvar_DirectSet + ENGAPI_ENTRY(ForceUnmodified, 2), // pfnForceUnmodified + ENGAPI_ENTRY(GetPlayerStats, 2), // pfnGetPlayerStats + ENGAPI_ENTRY(AddServerCommand, 2), // pfnAddServerCommand - { mFALSE, 9, "Voice_GetClientListening" }, // Voice_GetClientListening - { mFALSE, 9, "Voice_SetClientListening" }, // Voice_SetClientListening - { mFALSE, 9, "GetPlayerAuthId" }, // pfnGetPlayerAuthId - { mFALSE, 30, "SequenceGet" }, // pfnSequenceGet + ENGAPI_ENTRY(Voice_GetClientListening, 2), // Voice_GetClientListening + ENGAPI_ENTRY(Voice_SetClientListening, 2), // Voice_SetClientListening + ENGAPI_ENTRY(GetPlayerAuthId, 2), // pfnGetPlayerAuthId + ENGAPI_ENTRY(SequenceGet, 2), // pfnSequenceGet - { mFALSE, 30, "SequencePickSentence" }, // pfnSequencePickSentence - { mFALSE, 30, "GetFileSize" }, // pfnGetFileSize - { mFALSE, 30, "GetApproxWavePlayLen" }, // pfnGetApproxWavePlayLen - { mFALSE, 30, "IsCareerMatch" }, // pfnIsCareerMatch - { mFALSE, 30, "GetLocalizedStringLength" }, // pfnGetLocalizedStringLength - { mFALSE, 30, "RegisterTutorMessageShown" }, // pfnRegisterTutorMessageShown - { mFALSE, 30, "GetTimesTutorMessageShown" }, // pfnGetTimesTutorMessageShown - { mFALSE, 30, "ProcessTutorMessageDecayBuffer" }, // pfnProcessTutorMessageDecayBuffer - { mFALSE, 30, "ConstructTutorMessageDecayBuffer" }, // pfnConstructTutorMessageDecayBuffer - { mFALSE, 9, "ResetTutorMessageDecayData" }, // pfnResetTutorMessageDecayData + ENGAPI_ENTRY(SequencePickSentence, 2), // pfnSequencePickSentence + ENGAPI_ENTRY(GetFileSize, 4), // pfnGetFileSize + ENGAPI_ENTRY(GetApproxWavePlayLen, 4), // pfnGetApproxWavePlayLen + ENGAPI_ENTRY(IsCareerMatch, 4), // pfnIsCareerMatch + ENGAPI_ENTRY(GetLocalizedStringLength, 4), // pfnGetLocalizedStringLength + ENGAPI_ENTRY(RegisterTutorMessageShown, 4), // pfnRegisterTutorMessageShown + ENGAPI_ENTRY(GetTimesTutorMessageShown, 4), // pfnGetTimesTutorMessageShown + ENGAPI_ENTRY(ProcessTutorMessageDecayBuffer, 4), // pfnProcessTutorMessageDecayBuffer + ENGAPI_ENTRY(ConstructTutorMessageDecayBuffer, 4), // pfnConstructTutorMessageDecayBuffer + ENGAPI_ENTRY(ResetTutorMessageDecayData, 4), // pfnResetTutorMessageDecayData - { mFALSE, 3, "QueryClientCvarValue" }, //pfnQueryClientCvarValue - { mFALSE, 3, "QueryClientCvarValue2" }, //pfnQueryClientCvarValue2 - { mFALSE, 8, "CheckParm" }, //pfnCheckParm + ENGAPI_ENTRY(QueryClientCvarValue, 2), //pfnQueryClientCvarValue + ENGAPI_ENTRY(QueryClientCvarValue2, 2), //pfnQueryClientCvarValue2 + ENGAPI_ENTRY(EngCheckParm, 2), //pfnCheckParm // end - { mFALSE, 0, NULL }, + { 0, "", 0 }, }; diff --git a/metamod/src/api_info.h b/metamod/src/api_info.h index 63ae60f..eda530c 100644 --- a/metamod/src/api_info.h +++ b/metamod/src/api_info.h @@ -7,9 +7,9 @@ struct api_info_t { - mBOOL trace; // if true, log info about this function - int loglevel; // level at which to log info about this function - const char *name; // string representation of function name + size_t offset; + const char *name; + size_t loglevel; }; // DLL api functions diff --git a/metamod/src/callback_jit.cpp b/metamod/src/callback_jit.cpp new file mode 100644 index 0000000..c38c41d --- /dev/null +++ b/metamod/src/callback_jit.cpp @@ -0,0 +1,369 @@ +#include "precompiled.h" + +CJit g_jit; + +class CUniqueLabel +{ +public: + CUniqueLabel(const char* name) : m_name(name) + { + m_name += m_unique_index++; + } + + operator std::string&() + { + return m_name; + } + +private: + std::string m_name; + static size_t m_unique_index; +}; +size_t CUniqueLabel::m_unique_index; + +class CForwardCallbackJIT : public jitasm::function +{ +public: + CForwardCallbackJIT(jitdata_t *jitdata); + void naked_main(); + void call_func(jitasm::Frontend::Reg32 addr); + +private: + jitdata_t* m_jitdata; + + enum + { + mg_mres = 0, + mg_prev_mres = 4, + mg_status = 8, + mg_orig_ret = 12, + mg_over_ret = 16, + }; +}; + +CForwardCallbackJIT::CForwardCallbackJIT(jitdata_t* jitdata) : m_jitdata(jitdata) +{ +} + +void CForwardCallbackJIT::naked_main() +{ + // prologue + push(ebp); + mov(ebp, esp); + push(ebx); + + enum // stack map + { + orig_ret = 0, + over_ret = 4 + }; + + auto globals = ebx; + auto mg_backup = m_jitdata->has_ret ? 8 : 0; + auto framesize = mg_backup + sizeof(meta_globals_t); + + if (m_jitdata->has_varargs) { + sub(esp, framesize += MAX_STRBUF_LEN); + + // format varargs + lea(edx, dword_ptr[ebp + 8 + m_jitdata->args_count * 4]); // varargs ptr + lea(eax, dword_ptr[esp + mg_backup + sizeof(meta_globals_t)]); // buf ptr + mov(ecx, size_t(vsnprintf)); + + push(edx); + push(dword_ptr[ebp + 8 + (m_jitdata->args_count - 1) * 4]); // last arg of pfn (format) + push(MAX_STRBUF_LEN); + push(eax); + call(ecx); + add(esp, 4 * sizeof(int)); + } + else + sub(esp, framesize); + + // setup globals ptr + mov(globals, size_t(&g_metaGlobals)); + movups(xmm0, xmmword_ptr[globals]); + mov(eax, dword_ptr[globals + 16]); + movups(xmmword_ptr[esp + mg_backup], xmm0); + mov(dword_ptr[esp + mg_backup + 16], eax); + + // call metamod's pre hook if present + if (m_jitdata->mm_hook && m_jitdata->mm_hook_time == P_PRE) { + mov(ecx, m_jitdata->mm_hook); + call_func(ecx); + } + + // setup meta globals + mov(dword_ptr[globals + mg_mres], MRES_UNSET); + + // setup retval pointers + if (m_jitdata->has_ret) { + lea(eax, dword_ptr[esp + over_ret]); + mov(dword_ptr[globals + mg_orig_ret], esp); + mov(dword_ptr[globals + mg_over_ret], eax); + } + + // call pre + for (int i = 0, hookid = 0; i < m_jitdata->plugins_count; i++) { + auto plug = &m_jitdata->plugins[i]; + size_t fn_table = *(size_t *)(size_t(plug) + m_jitdata->table_offset); + + // plugin don't want any hooks from that table + if (!fn_table) + continue; + + CUniqueLabel go_next_plugin("go_next_plugin"); + + // check status and handler set + cmp(byte_ptr[size_t(&plug->status)], PL_RUNNING); + mov(ecx, dword_ptr[fn_table + m_jitdata->pfn_offset]); + jnz(go_next_plugin); + jecxz(go_next_plugin); + + if (hookid++) { + mov(eax, dword_ptr[globals + mg_mres]); + mov(dword_ptr[globals + mg_mres], MRES_IGNORED); + mov(dword_ptr[globals + mg_prev_mres], eax); + } + else { // init + xor_(eax, eax); + mov(dword_ptr[globals + mg_mres], MRES_IGNORED); + mov(dword_ptr[globals + mg_prev_mres], eax); // MRES_UNSET + mov(dword_ptr[globals + mg_status], eax); // NULL + } + + call_func(ecx); + + mov(edx, dword_ptr[globals + mg_mres]); + mov(ecx, dword_ptr[globals + mg_status]); + cmp(edx, ecx); + cmovg(ecx, edx); + mov(dword_ptr[globals + mg_status], ecx); + + if (m_jitdata->has_ret) { + mov(ecx, dword_ptr[esp + over_ret]); + cmp(edx, MRES_SUPERCEDE); + cmovz(ecx, eax); + mov(dword_ptr[esp + over_ret], ecx); + } + + L(go_next_plugin); + } + + // call original if need + cmp(dword_ptr[globals + mg_status], MRES_SUPERCEDE); + jz("skip_original"); + { + if (m_jitdata->pfn_original) { + mov(ecx, m_jitdata->pfn_original); + call_func(ecx); + } + + if (m_jitdata->has_ret) { + if (m_jitdata->pfn_original) + mov(dword_ptr[esp + orig_ret], eax); + else + mov(dword_ptr[esp + orig_ret], TRUE); // for should collide :/ + + jmp("skip_supercede"); + } + } + L("skip_original"); + { + if (m_jitdata->has_ret) { + // if supercede + mov(eax, dword_ptr[esp + over_ret]); + mov(dword_ptr[esp + orig_ret], eax); + + L("skip_supercede"); + } + } + L("skip_all"); + + // call post + for (int i = 0, hookid = 0; i < m_jitdata->plugins_count; i++) { + auto plug = &m_jitdata->plugins[i]; + size_t fn_table = *(size_t *)(size_t(plug) + m_jitdata->post_table_offset); + + // plugin don't want any hooks from that table + if (!fn_table) + continue; + + CUniqueLabel go_next_plugin("go_next_plugin"); + + // check status and handler set + cmp(byte_ptr[size_t(&plug->status)], PL_RUNNING); + mov(ecx, dword_ptr[fn_table + m_jitdata->pfn_offset]); + jnz(go_next_plugin); + jecxz(go_next_plugin); + + if (hookid++) { + mov(eax, dword_ptr[globals + mg_mres]); + mov(dword_ptr[globals + mg_mres], MRES_IGNORED); + mov(dword_ptr[globals + mg_prev_mres], eax); + } + else { // init + xor_(eax, eax); + mov(dword_ptr[globals + mg_mres], MRES_IGNORED); + mov(dword_ptr[globals + mg_prev_mres], eax); // MRES_UNSET + mov(dword_ptr[globals + mg_status], eax); // NULL + } + + call_func(ecx); + + mov(edx, dword_ptr[globals + mg_mres]); + mov(ecx, dword_ptr[globals + mg_status]); + cmp(ecx, edx); + cmovl(ecx, edx); + mov(dword_ptr[globals + mg_status], ecx); + + if (m_jitdata->has_ret) { + cmp(edx, MRES_SUPERCEDE); + mov(ecx, dword_ptr[esp + over_ret]); + cmovz(ecx, eax); + mov(dword_ptr[esp + over_ret], ecx); + } + + L(go_next_plugin); + } + + // call metamod's post hook if present + if (m_jitdata->mm_hook && m_jitdata->mm_hook_time == P_POST) { + mov(ecx, m_jitdata->mm_hook); + call_func(ecx); + } + + movups(xmm0, xmmword_ptr[esp + mg_backup]); + mov(eax, dword_ptr[esp + mg_backup + 16]); + movups(xmmword_ptr[globals], xmm0); + mov(dword_ptr[globals + 16], eax); + + if (m_jitdata->has_ret) { + mov(eax, dword_ptr[esp + orig_ret]); + cmp(dword_ptr[globals + mg_status], MRES_OVERRIDE); + cmovz(eax, dword_ptr[esp + over_ret]); + } + + if (framesize) { + add(esp, framesize); + } + + // epilogue + pop(ebx); + pop(ebp); + ret(); +} + +void CForwardCallbackJIT::call_func(jitasm::Frontend::Reg32 addr) +{ + const size_t normal_args_count = m_jitdata->args_count - (m_jitdata->has_varargs ? 1u : 0u); + const size_t strbuf_stack_offset = (m_jitdata->has_ret ? 8u : 0u) + sizeof(meta_globals_t); + + // push formatted buf + if (m_jitdata->has_varargs) { + lea(eax, dword_ptr[esp + strbuf_stack_offset]); + push(eax); + } + + // push normal args + for (size_t j = normal_args_count; j > 0; j--) + push(dword_ptr[ebp + 8 + (j - 1) * 4]); + + // call + call(addr); + + // pop stack + if (m_jitdata->args_count) + add(esp, m_jitdata->args_count * 4); +} + +class CSimpleJmp : public jitasm::function +{ +public: + CSimpleJmp(size_t addr/*, size_t hook, size_t hook_time, size_t ret_backup*/); + void naked_main(); + +private: + size_t m_addr; + /*size_t m_hook; + size_t m_hook_time; + size_t m_ret_backup;*/ +}; + +CSimpleJmp::CSimpleJmp(size_t addr/*, size_t hook, size_t hook_time, size_t ret_backup*/) : m_addr(addr)/*, m_hook(hook), m_hook_time(hook_time), m_ret_backup(ret_backup)*/ +{ +} + +void CSimpleJmp::naked_main() +{ + /*if (m_hook && m_hook_time == P_PRE) { + mov(ecx, m_hook); + pop(dword_ptr[m_ret_backup]); + call(ecx); + push(dword_ptr[m_ret_backup]); + }*/ + + jmp(dword_ptr[m_addr]); + + /*if (m_hook && m_hook_time == P_POST) { + mov(ecx, m_hook); + pop(dword_ptr[m_ret_backup]); + call(ecx); + push(dword_ptr[m_ret_backup]); + }*/ +} + +size_t CJit::compile_callback(jitdata_t* jitdata) +{ + if (!is_hook_needed(jitdata)) { + return jitdata->pfn_original; + } + + CForwardCallbackJIT callback(jitdata); + callback.Assemble(); + + auto code = callback.GetCode(); + auto codeSize = callback.GetCodeSize(); + auto ptr = m_allocator.allocate(codeSize); + + return (size_t)memcpy(ptr, code, codeSize); +} + +size_t CJit::compile_tramp(size_t ptr_to_func/*, size_t hook, size_t hook_time*/) +{ + CSimpleJmp jmp(ptr_to_func/*, hook, hook_time, size_t(m_static_allocator.allocate(sizeof(int)))*/); + jmp.Assemble(); + + auto code = jmp.GetCode(); + auto codeSize = jmp.GetCodeSize(); + auto ptr = m_static_allocator.allocate(codeSize); + + return (size_t)memcpy(ptr, code, codeSize); +} + +void CJit::clear_callbacks() +{ + m_allocator.deallocate_all(); +} + +bool CJit::is_hook_needed(jitdata_t* jitdata) +{ + if (jitdata->mm_hook) + return true; + + if (!jitdata->plugins) + return false; + + for (int i = 0, hookid = 0; i < jitdata->plugins_count; i++) { + auto plug = &jitdata->plugins[i]; + + const size_t fn_table = *(size_t *)(size_t(plug) + jitdata->table_offset); + const size_t fn_table_post = *(size_t *)(size_t(plug) + jitdata->post_table_offset); + + if (fn_table || fn_table_post) { + return true; + } + } + + return false; +} diff --git a/metamod/src/callback_jit.h b/metamod/src/callback_jit.h new file mode 100644 index 0000000..ebddde8 --- /dev/null +++ b/metamod/src/callback_jit.h @@ -0,0 +1,95 @@ +#pragma once + +#define CDATA_ENTRY(s, x, p, h) {#x, offsetof(s, x), getArgsCount(decltype(s##::##x)()), !is_void(decltype(s##::##x)()), is_varargs(decltype(s##::##x)()), p, h} + +struct jitdata_t +{ + size_t pfn_original; + uint8 args_count; + bool has_ret; + bool has_varargs; + uint8 mm_hook_time; + size_t pfn_offset; // from fn table + size_t mm_hook; + + MPlugin* plugins; + int plugins_count; + size_t table_offset; // from MPlugin + size_t post_table_offset; // from MPlugin +}; + +struct compile_data_t +{ + const char* name; + size_t offset; + uint8 args_count; + bool has_ret; + bool has_varargs; + uint8 mm_hook_time; + size_t mm_hook; +}; + +template +size_t getArgsCount(ret_t (*)(t_args...)) +{ + return sizeof...(t_args); +} + +template +size_t getArgsCount(ret_t (*)(t_args..., ...)) +{ + return sizeof...(t_args); +} + +template +bool is_void(void (*)(t_args...)) +{ + return true; +} + +template +bool is_void(void (*)(t_args..., ...)) +{ + return true; +} + +template +bool is_void(ret_t (*)(t_args..., ...)) +{ + return false; +} + +template +bool is_void(ret_t (*)(t_args...)) +{ + return false; +} + +template +bool is_varargs(ret_t (*)(t_args...)) +{ + return false; +} + +template +bool is_varargs(ret_t (*)(t_args..., ...)) +{ + return true; +} + +class CJit +{ +public: + size_t compile_callback(jitdata_t* jitdata); + size_t compile_tramp(size_t ptr_to_func/*, size_t hook, size_t hook_time*/); + void clear_callbacks(); + +private: + static bool is_hook_needed(jitdata_t* jitdata); + +private: + execmem_allocator m_allocator; + execmem_allocator m_static_allocator; +}; + +extern CJit g_jit; diff --git a/metamod/src/commands_meta.cpp b/metamod/src/commands_meta.cpp index 18b6e20..3712b16 100644 --- a/metamod/src/commands_meta.cpp +++ b/metamod/src/commands_meta.cpp @@ -201,7 +201,7 @@ void cmd_meta_refresh() } META_LOG("Refreshing the plugins on demand..."); - if (g_plugins->refresh(PT_ANYTIME) != mTRUE) + if (g_plugins->refresh(PT_ANYTIME) != true) { META_LOG("Refresh failed."); } diff --git a/metamod/src/conf_meta.cpp b/metamod/src/conf_meta.cpp index 0b7b45b..b492472 100644 --- a/metamod/src/conf_meta.cpp +++ b/metamod/src/conf_meta.cpp @@ -1,8 +1,6 @@ #include "precompiled.h" -MConfig::MConfig() - : list(nullptr), filename(nullptr), debuglevel(0), - plugins_file(nullptr), exec_cfg(nullptr) +MConfig::MConfig() : debuglevel(0), plugins_file(nullptr), exec_cfg(nullptr), list(nullptr), filename(nullptr) { } @@ -19,7 +17,7 @@ option_t *MConfig::find(const char* lookup) const { for (auto optp = list; optp->name; optp++) { - if (!Q_strcmp(optp->name, lookup)) { + if (!strcmp(optp->name, lookup)) { return optp; } } @@ -27,16 +25,16 @@ option_t *MConfig::find(const char* lookup) const RETURN_ERRNO(NULL, ME_NOTFOUND); } -mBOOL MConfig::set(const char* key, const char* value) +bool MConfig::set(const char* key, const char* value) const { option_t* optp = find(key); if (optp) return set(optp, value); - RETURN_ERRNO(mFALSE, ME_NOTFOUND); + RETURN_ERRNO(false, ME_NOTFOUND); } -mBOOL MConfig::set(option_t* setp, const char* setstr) +bool MConfig::set(option_t* setp, const char* setstr) { char pathbuf[PATH_MAX ]; int* optval = (int *) setp->dest; @@ -45,7 +43,7 @@ mBOOL MConfig::set(option_t* setp, const char* setstr) // SETOPT_FN optcmd = (SETOPT_FN) setp->dest; if (!setstr) - return mTRUE; + return true; switch (setp->type) { @@ -53,7 +51,7 @@ mBOOL MConfig::set(option_t* setp, const char* setstr) if (!isdigit(setstr[0])) { META_ERROR("option '%s' invalid format '%s'", setp->name, setstr); - RETURN_ERRNO(mFALSE, ME_FORMAT); + RETURN_ERRNO(false, ME_FORMAT); } *optval = Q_atoi(setstr); META_DEBUG(3, ("set config int: %s = %d", setp->name, *optval)); @@ -71,7 +69,7 @@ mBOOL MConfig::set(option_t* setp, const char* setstr) { META_ERROR("option '%s' invalid format '%s'", setp->name, setstr); - RETURN_ERRNO(mFALSE, ME_FORMAT); + RETURN_ERRNO(false, ME_FORMAT); } META_DEBUG(3, ("set config bool: %s = %s", setp->name, *optval ? "true" : "false")); break; @@ -90,13 +88,13 @@ mBOOL MConfig::set(option_t* setp, const char* setstr) break; default: META_ERROR("unrecognized config type '%d'", setp->type); - RETURN_ERRNO(mFALSE, ME_ARGUMENT); + RETURN_ERRNO(false, ME_ARGUMENT); } - return mTRUE; + return true; } -mBOOL MConfig::load(const char* fn) +bool MConfig::load(const char* fn) { FILE* fp; char loadfile[PATH_MAX ]; @@ -113,7 +111,7 @@ mBOOL MConfig::load(const char* fn) if (!fp) { META_ERROR("unable to open config file '%s': %s", loadfile, strerror(errno)); - RETURN_ERRNO(mFALSE, ME_NOFILE); + RETURN_ERRNO(false, ME_NOFILE); } META_DEBUG(2, ("Loading from config file: %s", loadfile)); @@ -149,7 +147,7 @@ mBOOL MConfig::load(const char* fn) filename = Q_strdup(loadfile); fclose(fp); - return mTRUE; + return true; } void MConfig::show() const diff --git a/metamod/src/conf_meta.h b/metamod/src/conf_meta.h index e5865c4..3b8d949 100644 --- a/metamod/src/conf_meta.h +++ b/metamod/src/conf_meta.h @@ -32,8 +32,8 @@ public: char *exec_cfg; // ie metaexec.cfg, exec.cfg void init(option_t *global_options); - mBOOL load(const char *filename); - mBOOL set(const char *key, const char *value); + bool load(const char *filename); + bool set(const char *key, const char *value) const; void show() const; private: @@ -41,7 +41,7 @@ private: char *filename; option_t *find(const char *lookup) const; - static mBOOL set(option_t *setp, const char *value); + static bool set(option_t *setp, const char *value); // Private; to satisfy -Weffc++ "has pointer data members but does // not override" copy/assignment constructor. void operator=(const MConfig &src); diff --git a/metamod/src/dllapi.cpp b/metamod/src/dllapi.cpp index e41dbf3..f850a78 100644 --- a/metamod/src/dllapi.cpp +++ b/metamod/src/dllapi.cpp @@ -1,178 +1,38 @@ #include "precompiled.h" -// Original DLL routines, functions returning "void". -#define META_DLLAPI_HANDLE_void(FN_TYPE, pfnName, pfn_args) \ - SETUP_API_CALLS_void(FN_TYPE, pfnName, dllapi_info); \ - CALL_PLUGIN_API_void(P_PRE, pfnName, pfn_args, dllapi_table); \ - CALL_GAME_API_void(pfnName, pfn_args, dllapi_table); \ - CALL_PLUGIN_API_void(P_POST, pfnName, pfn_args, dllapi_post_table); +#define CDATA_DLL_H(x, p, h) CDATA_ENTRY(DLL_FUNCTIONS, x, p, size_t(h)) +#define CDATA_DLL(x) CDATA_ENTRY(DLL_FUNCTIONS, x, P_PRE, 0u) +#define CDATA_NEWDLL_H(x, p, h) CDATA_ENTRY(NEW_DLL_FUNCTIONS, x, p, size_t(h)) +#define CDATA_NEWDLL(x) CDATA_ENTRY(NEW_DLL_FUNCTIONS, x, P_PRE, 0u) -// Original DLL routines, functions returning an actual value. -#define META_DLLAPI_HANDLE(ret_t, ret_init, FN_TYPE, pfnName, pfn_args) \ - SETUP_API_CALLS(ret_t, ret_init, FN_TYPE, pfnName, dllapi_info); \ - CALL_PLUGIN_API(P_PRE, ret_init, pfnName, pfn_args, MRES_SUPERCEDE, dllapi_table); \ - CALL_GAME_API(pfnName, pfn_args, dllapi_table); \ - CALL_PLUGIN_API(P_POST, ret_init, pfnName, pfn_args, MRES_OVERRIDE, dllapi_post_table); +DLL_FUNCTIONS sFunctionTable; +DLL_FUNCTIONS sFunctionTable_jit; +DLL_FUNCTIONS *pHookedDllFunctions = &sFunctionTable; +NEW_DLL_FUNCTIONS sNewFunctionTable; +NEW_DLL_FUNCTIONS sNewFunctionTable_jit; +NEW_DLL_FUNCTIONS *pHookedNewDllFunctions = &sNewFunctionTable; - -// The "new" api routines (just 3 right now), functions returning "void". -#define META_NEWAPI_HANDLE_void(FN_TYPE, pfnName, pfn_args) \ - SETUP_API_CALLS_void(FN_TYPE, pfnName, newapi_info); \ - CALL_PLUGIN_API_void(P_PRE, pfnName, pfn_args, newapi_table); \ - CALL_GAME_API_void(pfnName, pfn_args, newapi_table); \ - CALL_PLUGIN_API_void(P_POST, pfnName, pfn_args, newapi_post_table); - -// The "new" api routines (just 3 right now), functions returning an actual value. -#define META_NEWAPI_HANDLE(ret_t, ret_init, FN_TYPE, pfnName, pfn_args) \ - SETUP_API_CALLS(ret_t, ret_init, FN_TYPE, pfnName, newapi_info); \ - CALL_PLUGIN_API(P_PRE, ret_init, pfnName, pfn_args, MRES_SUPERCEDE, newapi_table); \ - CALL_GAME_API(pfnName, pfn_args, newapi_table); \ - CALL_PLUGIN_API(P_POST, ret_init, pfnName, pfn_args, MRES_OVERRIDE, newapi_post_table); - -void mm_GameDLLInit(void) +void mm_ClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ) { - META_DLLAPI_HANDLE_void(FN_GAMEINIT, pfnGameInit, ()); - RETURN_API_void(); -} - -int mm_DispatchSpawn(edict_t *pent) -{ - // Success == 0, Failure == -1 ? - META_DLLAPI_HANDLE(int, 0, FN_DISPATCHSPAWN, pfnSpawn, (pent)); - RETURN_API(); -} - -void mm_DispatchThink(edict_t *pent) -{ - META_DLLAPI_HANDLE_void(FN_DISPATCHTHINK, pfnThink, (pent)); - RETURN_API_void(); -} - -void mm_DispatchUse(edict_t *pentUsed, edict_t *pentOther) -{ - META_DLLAPI_HANDLE_void(FN_DISPATCHUSE, pfnUse, (pentUsed, pentOther)); - RETURN_API_void(); -} - -void mm_DispatchTouch(edict_t *pentTouched, edict_t *pentOther) -{ - META_DLLAPI_HANDLE_void(FN_DISPATCHTOUCH, pfnTouch, (pentTouched, pentOther)); - RETURN_API_void(); -} - -void mm_DispatchBlocked(edict_t *pentBlocked, edict_t *pentOther) -{ - META_DLLAPI_HANDLE_void(FN_DISPATCHBLOCKED, pfnBlocked, (pentBlocked, pentOther)); - RETURN_API_void(); -} - -void mm_DispatchKeyValue(edict_t *pentKeyvalue, KeyValueData *pkvd) -{ - META_DLLAPI_HANDLE_void(FN_DISPATCHKEYVALUE, pfnKeyValue, (pentKeyvalue, pkvd)); - RETURN_API_void(); -} - -void mm_DispatchSave(edict_t *pent, SAVERESTOREDATA *pSaveData) -{ - META_DLLAPI_HANDLE_void(FN_DISPATCHSAVE, pfnSave, (pent, pSaveData)); - RETURN_API_void(); -} - -int mm_DispatchRestore(edict_t *pent, SAVERESTOREDATA *pSaveData, int globalEntity) -{ - // Success == 0, Failure == -1 ? - META_DLLAPI_HANDLE(int, 0, FN_DISPATCHRESTORE, pfnRestore, (pent, pSaveData, globalEntity)); - RETURN_API(); -} - -void mm_DispatchObjectCollsionBox(edict_t *pent) -{ - META_DLLAPI_HANDLE_void(FN_DISPATCHOBJECTCOLLISIONBOX, pfnSetAbsBox, (pent)); - RETURN_API_void(); -} - -void mm_SaveWriteFields(SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount) -{ - META_DLLAPI_HANDLE_void(FN_SAVEWRITEFIELDS, pfnSaveWriteFields, (pSaveData, pname, pBaseData, pFields, fieldCount)); - RETURN_API_void(); -} - -void mm_SaveReadFields(SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount) -{ - META_DLLAPI_HANDLE_void(FN_SAVEREADFIELDS, pfnSaveReadFields, (pSaveData, pname, pBaseData, pFields, fieldCount)); - RETURN_API_void(); -} - -void mm_SaveGlobalState(SAVERESTOREDATA *pSaveData) -{ - META_DLLAPI_HANDLE_void(FN_SAVEGLOBALSTATE, pfnSaveGlobalState, (pSaveData)); - RETURN_API_void(); -} - -void mm_RestoreGlobalState(SAVERESTOREDATA *pSaveData) -{ - META_DLLAPI_HANDLE_void(FN_RESTOREGLOBALSTATE, pfnRestoreGlobalState, (pSaveData)); - RETURN_API_void(); -} - -void mm_ResetGlobalState(void) -{ - META_DLLAPI_HANDLE_void(FN_RESETGLOBALSTATE, pfnResetGlobalState, ()); - RETURN_API_void(); -} - -BOOL mm_ClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ) -{ - g_Players.clear_player_cvar_query(pEntity); - META_DLLAPI_HANDLE(BOOL, TRUE, FN_CLIENTCONNECT, pfnClientConnect, (pEntity, pszName, pszAddress, szRejectReason)); - RETURN_API(); + g_players.clear_player_cvar_query(pEntity); } void mm_ClientDisconnect(edict_t *pEntity) { - g_Players.clear_player_cvar_query(pEntity); - META_DLLAPI_HANDLE_void(FN_CLIENTDISCONNECT, pfnClientDisconnect, (pEntity)); - RETURN_API_void(); -} - -void mm_ClientKill(edict_t *pEntity) -{ - META_DLLAPI_HANDLE_void(FN_CLIENTKILL, pfnClientKill, (pEntity)); - RETURN_API_void(); -} - -void mm_ClientPutInServer(edict_t *pEntity) -{ - META_DLLAPI_HANDLE_void(FN_CLIENTPUTINSERVER, pfnClientPutInServer, (pEntity)); - RETURN_API_void(); + g_players.clear_player_cvar_query(pEntity); } void mm_ClientCommand(edict_t *pEntity) { - if (!Q_strcmp(CMD_ARGV(0), "meta")) - { + if (!strcmp(CMD_ARGV(0), "meta")) { client_meta(pEntity); } - - META_DLLAPI_HANDLE_void(FN_CLIENTCOMMAND, pfnClientCommand, (pEntity)); - RETURN_API_void(); -} - -void mm_ClientUserInfoChanged(edict_t *pEntity, char *infobuffer) -{ - META_DLLAPI_HANDLE_void(FN_CLIENTUSERINFOCHANGED, pfnClientUserInfoChanged, (pEntity, infobuffer)); - RETURN_API_void(); -} - -void mm_ServerActivate(edict_t *pEdictList, int edictCount, int clientMax) -{ - META_DLLAPI_HANDLE_void(FN_SERVERACTIVATE, pfnServerActivate, (pEdictList, edictCount, clientMax)); - RETURN_API_void(); } void mm_ServerDeactivate(void) { - META_DLLAPI_HANDLE_void(FN_SERVERDEACTIVATE, pfnServerDeactivate, ()); + sFunctionTable_jit.pfnServerDeactivate(); + // Update loaded plugins. Look for new plugins in inifile, as well as // any plugins waiting for a changelevel to load. // @@ -189,270 +49,84 @@ void mm_ServerDeactivate(void) g_plugins->refresh(PT_CHANGELEVEL); g_plugins->unpause_all(); // g_plugins->retry_all(PT_CHANGELEVEL); - g_Players.clear_all_cvar_queries(); + g_players.clear_all_cvar_queries(); requestid_counter = 0; - RETURN_API_void(); } -void mm_PlayerPreThink(edict_t *pEntity) +compile_data_t g_dllfunc_cdata[] = { - META_DLLAPI_HANDLE_void(FN_PLAYERPRETHINK, pfnPlayerPreThink, (pEntity)); - RETURN_API_void(); -} + CDATA_DLL(pfnGameInit), // pfnGameInit() Initialize the game (one-time call after loading of game .dll) + CDATA_DLL(pfnSpawn), // pfnSpawn() + CDATA_DLL(pfnThink), // pfnThink() + CDATA_DLL(pfnUse), // pfnUse() + CDATA_DLL(pfnTouch), // pfnTouch() + CDATA_DLL(pfnBlocked), // pfnBlocked() + CDATA_DLL(pfnKeyValue), // pfnKeyValue() + CDATA_DLL(pfnSave), // pfnSave() + CDATA_DLL(pfnRestore), // pfnRestore() + CDATA_DLL(pfnSetAbsBox), // pfnSetAbsBox() -void mm_PlayerPostThink(edict_t *pEntity) -{ - META_DLLAPI_HANDLE_void(FN_PLAYERPOSTTHINK, pfnPlayerPostThink, (pEntity)); - RETURN_API_void(); -} + CDATA_DLL(pfnSaveWriteFields), // pfnSaveWriteFields() + CDATA_DLL(pfnSaveReadFields), // pfnSaveReadFields() -void mm_StartFrame(void) -{ - META_DLLAPI_HANDLE_void(FN_STARTFRAME, pfnStartFrame, ()); - RETURN_API_void(); -} + CDATA_DLL(pfnSaveGlobalState), // pfnSaveGlobalState() + CDATA_DLL(pfnRestoreGlobalState), // pfnRestoreGlobalState() + CDATA_DLL(pfnResetGlobalState), // pfnResetGlobalState() -void mm_ParmsNewLevel(void) -{ - META_DLLAPI_HANDLE_void(FN_PARMSNEWLEVEL, pfnParmsNewLevel, ()); - RETURN_API_void(); -} + CDATA_DLL_H(pfnClientConnect, P_PRE, mm_ClientConnect), // pfnClientConnect() (wd) Client has connected + CDATA_DLL_H(pfnClientDisconnect, P_PRE, mm_ClientDisconnect), // pfnClientDisconnect() (wd) Player has left the game + CDATA_DLL(pfnClientKill), // pfnClientKill() (wd) Player has typed "kill" + CDATA_DLL(pfnClientPutInServer), // pfnClientPutInServer() (wd) Client is entering the game + CDATA_DLL_H(pfnClientCommand, P_PRE, mm_ClientCommand), + CDATA_DLL(pfnClientUserInfoChanged), // pfnClientUserInfoChanged() (wd) Client has updated their setinfo structure + CDATA_DLL(pfnServerActivate), // pfnServerActivate() (wd) Server is starting a new map + CDATA_DLL(pfnServerDeactivate), // pfnServerDeactivate() (wd) Server is leaving the map (shutdown), or changelevel); SDK2 -void mm_ParmsChangeLevel(void) -{ - META_DLLAPI_HANDLE_void(FN_PARMSCHANGELEVEL, pfnParmsChangeLevel, ()); - RETURN_API_void(); -} + CDATA_DLL(pfnPlayerPreThink), // pfnPlayerPreThink() + CDATA_DLL(pfnPlayerPostThink), // pfnPlayerPostThink() -const char *mm_GetGameDescription(void) -{ - META_DLLAPI_HANDLE(const char *, NULL, FN_GETGAMEDESCRIPTION, pfnGetGameDescription, ()); - RETURN_API(); -} + CDATA_DLL(pfnStartFrame), // pfnStartFrame() + CDATA_DLL(pfnParmsNewLevel), // pfnParmsNewLevel() + CDATA_DLL(pfnParmsChangeLevel), // pfnParmsChangeLevel() -void mm_PlayerCustomization(edict_t *pEntity, customization_t *pCust) -{ - META_DLLAPI_HANDLE_void(FN_PLAYERCUSTOMIZATION, pfnPlayerCustomization, (pEntity, pCust)); - RETURN_API_void(); -} + CDATA_DLL(pfnGetGameDescription), // pfnGetGameDescription() Returns string describing current .dll. E.g. "TeamFotrress 2"), "Half-Life" + CDATA_DLL(pfnPlayerCustomization), // pfnPlayerCustomization() Notifies .dll of new customization for player. -void mm_SpectatorConnect(edict_t *pEntity) -{ - META_DLLAPI_HANDLE_void(FN_SPECTATORCONNECT, pfnSpectatorConnect, (pEntity)); - RETURN_API_void(); -} + CDATA_DLL(pfnSpectatorConnect), // pfnSpectatorConnect() Called when spectator joins server + CDATA_DLL(pfnSpectatorDisconnect), // pfnSpectatorDisconnect() Called when spectator leaves the server + CDATA_DLL(pfnSpectatorThink), // pfnSpectatorThink() Called when spectator sends a command packet (usercmd_t) -void mm_SpectatorDisconnect(edict_t *pEntity) -{ - META_DLLAPI_HANDLE_void(FN_SPECTATORDISCONNECT, pfnSpectatorDisconnect, (pEntity)); - RETURN_API_void(); -} + CDATA_DLL(pfnSys_Error), // pfnSys_Error() Notify game .dll that engine is going to shut down. Allows mod authors to set a breakpoint. SDK2 -void mm_SpectatorThink(edict_t *pEntity) -{ - META_DLLAPI_HANDLE_void(FN_SPECTATORTHINK, pfnSpectatorThink, (pEntity)); - RETURN_API_void(); -} + CDATA_DLL(pfnPM_Move), // pfnPM_Move() (wd) SDK2 + CDATA_DLL(pfnPM_Init), // pfnPM_Init() Server version of player movement initialization; (wd) SDK2 + CDATA_DLL(pfnPM_FindTextureType), // pfnPM_FindTextureType() (wd) SDK2 -void mm_Sys_Error(const char *error_string) -{ - META_DLLAPI_HANDLE_void(FN_SYS_ERROR, pfnSys_Error, (error_string)); - RETURN_API_void(); -} - -void mm_PM_Move (struct playermove_s *ppmove, int server) -{ - META_DLLAPI_HANDLE_void(FN_PM_MOVE, pfnPM_Move, (ppmove, server)); - RETURN_API_void(); -} - -void mm_PM_Init(struct playermove_s *ppmove) -{ - META_DLLAPI_HANDLE_void(FN_PM_INIT, pfnPM_Init, (ppmove)); - RETURN_API_void(); -} - -char mm_PM_FindTextureType(char *name) -{ - META_DLLAPI_HANDLE(char, '\0', FN_PM_FINDTEXTURETYPE, pfnPM_FindTextureType, (name)); - RETURN_API(); -} - -void mm_SetupVisibility(edict_t *pViewEntity, edict_t *pClient, unsigned char **pvs, unsigned char **pas) -{ - META_DLLAPI_HANDLE_void(FN_SETUPVISIBILITY, pfnSetupVisibility, (pViewEntity, pClient, pvs, pas)); - RETURN_API_void(); -} - -void mm_UpdateClientData (const struct edict_s *ent, int sendweapons, struct clientdata_s *cd) -{ - META_DLLAPI_HANDLE_void(FN_UPDATECLIENTDATA, pfnUpdateClientData, (ent, sendweapons, cd)); - RETURN_API_void(); -} - -int mm_AddToFullPack(struct entity_state_s *state, int e, edict_t *ent, edict_t *host, int hostflags, int player, unsigned char *pSet) -{ - META_DLLAPI_HANDLE(int, 0, FN_ADDTOFULLPACK, pfnAddToFullPack, (state, e, ent, host, hostflags, player, pSet)); - RETURN_API(); -} - -void mm_CreateBaseline(int player, int eindex, struct entity_state_s *baseline, struct edict_s *entity, int playermodelindex, vec3_t player_mins, vec3_t player_maxs) -{ - META_DLLAPI_HANDLE_void(FN_CREATEBASELINE, pfnCreateBaseline, (player, eindex, baseline, entity, playermodelindex, player_mins, player_maxs)); - RETURN_API_void(); -} - -void mm_RegisterEncoders(void) -{ - META_DLLAPI_HANDLE_void(FN_REGISTERENCODERS, pfnRegisterEncoders, ()); - RETURN_API_void(); -} - -int mm_GetWeaponData(struct edict_s *player, struct weapon_data_s *info) -{ - META_DLLAPI_HANDLE(int, 0, FN_GETWEAPONDATA, pfnGetWeaponData, (player, info)); - RETURN_API(); -} - -void mm_CmdStart(const edict_t *player, const struct usercmd_s *cmd, unsigned int random_seed) -{ - META_DLLAPI_HANDLE_void(FN_CMDSTART, pfnCmdStart, (player, cmd, random_seed)); - RETURN_API_void(); -} - -void mm_CmdEnd (const edict_t *player) -{ - META_DLLAPI_HANDLE_void(FN_CMDEND, pfnCmdEnd, (player)); - RETURN_API_void(); -} - -int mm_ConnectionlessPacket(const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size) -{ - META_DLLAPI_HANDLE(int, 0, FN_CONNECTIONLESSPACKET, pfnConnectionlessPacket, (net_from, args, response_buffer, response_buffer_size)); - RETURN_API(); -} - -int mm_GetHullBounds(int hullnumber, float *mins, float *maxs) -{ - META_DLLAPI_HANDLE(int, 0, FN_GETHULLBOUNDS, pfnGetHullBounds, (hullnumber, mins, maxs)); - RETURN_API(); -} - -void mm_CreateInstancedBaselines (void) -{ - META_DLLAPI_HANDLE_void(FN_CREATEINSTANCEDBASELINES, pfnCreateInstancedBaselines, ()); - RETURN_API_void(); -} - -int mm_InconsistentFile(const edict_t *player, const char *filename, char *disconnect_message) -{ - META_DLLAPI_HANDLE(int, 0, FN_INCONSISTENTFILE, pfnInconsistentFile, (player, filename, disconnect_message)); - RETURN_API(); -} - -int mm_AllowLagCompensation(void) -{ - META_DLLAPI_HANDLE(int, 0, FN_ALLOWLAGCOMPENSATION, pfnAllowLagCompensation, ()); - RETURN_API(); -} - -void mm_OnFreeEntPrivateData(edict_t *pEnt) -{ - META_NEWAPI_HANDLE_void(FN_ONFREEENTPRIVATEDATA, pfnOnFreeEntPrivateData, (pEnt)); - RETURN_API_void(); -} - -void mm_GameShutdown(void) -{ - META_NEWAPI_HANDLE_void(FN_GAMESHUTDOWN, pfnGameShutdown, ()); - RETURN_API_void(); -} - -int mm_ShouldCollide(edict_t *pentTouched, edict_t *pentOther) -{ - META_NEWAPI_HANDLE(int, 1, FN_SHOULDCOLLIDE, pfnShouldCollide, (pentTouched, pentOther)); - RETURN_API(); -} - -void mm_CvarValue(const edict_t *pEdict, const char *value) -{ - g_Players.clear_player_cvar_query(pEdict); - META_NEWAPI_HANDLE_void(FN_CVARVALUE, pfnCvarValue, (pEdict, value)); - RETURN_API_void(); -} - -void mm_CvarValue2(const edict_t *pEdict, int requestID, const char *cvarName, const char *value) -{ - META_NEWAPI_HANDLE_void(FN_CVARVALUE2, pfnCvarValue2, (pEdict, requestID, cvarName, value)); - RETURN_API_void(); -} - -// "(wd)" indicates my comments on the functions -DLL_FUNCTIONS sFunctionTable = -{ - mm_GameDLLInit, // pfnGameInit() Initialize the game (one-time call after loading of game .dll) - mm_DispatchSpawn, // pfnSpawn() - mm_DispatchThink, // pfnThink() - mm_DispatchUse, // pfnUse() - mm_DispatchTouch, // pfnTouch() - mm_DispatchBlocked, // pfnBlocked() - mm_DispatchKeyValue, // pfnKeyValue() - mm_DispatchSave, // pfnSave() - mm_DispatchRestore, // pfnRestore() - mm_DispatchObjectCollsionBox, // pfnSetAbsBox() - - mm_SaveWriteFields, // pfnSaveWriteFields() - mm_SaveReadFields, // pfnSaveReadFields() - - mm_SaveGlobalState, // pfnSaveGlobalState() - mm_RestoreGlobalState, // pfnRestoreGlobalState() - mm_ResetGlobalState, // pfnResetGlobalState() - - mm_ClientConnect, // pfnClientConnect() (wd) Client has connected - mm_ClientDisconnect, // pfnClientDisconnect() (wd) Player has left the game - mm_ClientKill, // pfnClientKill() (wd) Player has typed "kill" - mm_ClientPutInServer, // pfnClientPutInServer() (wd) Client is entering the game - mm_ClientCommand, // pfnClientCommand() (wd) Player has sent a command (typed, or from a bind) - mm_ClientUserInfoChanged, // pfnClientUserInfoChanged() (wd) Client has updated their setinfo structure - mm_ServerActivate, // pfnServerActivate() (wd) Server is starting a new map - mm_ServerDeactivate, // pfnServerDeactivate() (wd) Server is leaving the map (shutdown, or changelevel); SDK2 - - mm_PlayerPreThink, // pfnPlayerPreThink() - mm_PlayerPostThink, // pfnPlayerPostThink() - - mm_StartFrame, // pfnStartFrame() - mm_ParmsNewLevel, // pfnParmsNewLevel() - mm_ParmsChangeLevel, // pfnParmsChangeLevel() - - mm_GetGameDescription, // pfnGetGameDescription() Returns string describing current .dll. E.g. "TeamFotrress 2", "Half-Life" - mm_PlayerCustomization, // pfnPlayerCustomization() Notifies .dll of new customization for player. - - mm_SpectatorConnect, // pfnSpectatorConnect() Called when spectator joins server - mm_SpectatorDisconnect, // pfnSpectatorDisconnect() Called when spectator leaves the server - mm_SpectatorThink, // pfnSpectatorThink() Called when spectator sends a command packet (usercmd_t) - - mm_Sys_Error, // pfnSys_Error() Notify game .dll that engine is going to shut down. Allows mod authors to set a breakpoint. SDK2 - - mm_PM_Move, // pfnPM_Move() (wd) SDK2 - mm_PM_Init, // pfnPM_Init() Server version of player movement initialization; (wd) SDK2 - mm_PM_FindTextureType, // pfnPM_FindTextureType() (wd) SDK2 - - mm_SetupVisibility, // pfnSetupVisibility() Set up PVS and PAS for networking for this client; (wd) SDK2 - mm_UpdateClientData, // pfnUpdateClientData() Set up data sent only to specific client; (wd) SDK2 - mm_AddToFullPack, // pfnAddToFullPack() (wd) SDK2 - mm_CreateBaseline, // pfnCreateBaseline() Tweak entity baseline for network encoding, allows setup of player baselines, too.; (wd) SDK2 - mm_RegisterEncoders, // pfnRegisterEncoders() Callbacks for network encoding; (wd) SDK2 - mm_GetWeaponData, // pfnGetWeaponData() (wd) SDK2 - mm_CmdStart, // pfnCmdStart() (wd) SDK2 - mm_CmdEnd, // pfnCmdEnd() (wd) SDK2 - mm_ConnectionlessPacket, // pfnConnectionlessPacket() (wd) SDK2 - mm_GetHullBounds, // pfnGetHullBounds() (wd) SDK2 - mm_CreateInstancedBaselines, // pfnCreateInstancedBaselines() (wd) SDK2 - mm_InconsistentFile, // pfnInconsistentFile() (wd) SDK2 - mm_AllowLagCompensation, // pfnAllowLagCompensation() (wd) SDK2 + CDATA_DLL(pfnSetupVisibility), // pfnSetupVisibility() Set up PVS and PAS for networking for this client; (wd) SDK2 + CDATA_DLL(pfnUpdateClientData), // pfnUpdateClientData() Set up data sent only to specific client; (wd) SDK2 + CDATA_DLL(pfnAddToFullPack), // pfnAddToFullPack() (wd) SDK2 + CDATA_DLL(pfnCreateBaseline), // pfnCreateBaseline() Tweak entity baseline for network encoding), allows setup of player baselines), too.; (wd) SDK2 + CDATA_DLL(pfnRegisterEncoders), // pfnRegisterEncoders() Callbacks for network encoding; (wd) SDK2 + CDATA_DLL(pfnGetWeaponData), // pfnGetWeaponData() (wd) SDK2 + CDATA_DLL(pfnCmdStart), // pfnCmdStart() (wd) SDK2 + CDATA_DLL(pfnCmdEnd), // pfnCmdEnd() (wd) SDK2 + CDATA_DLL(pfnConnectionlessPacket), // pfnConnectionlessPacket() (wd) SDK2 + CDATA_DLL(pfnGetHullBounds), // pfnGetHullBounds() (wd) SDK2 + CDATA_DLL(pfnCreateInstancedBaselines), // pfnCreateInstancedBaselines() (wd) SDK2 + CDATA_DLL(pfnInconsistentFile), // pfnInconsistentFile() (wd) SDK2 + CDATA_DLL(pfnAllowLagCompensation), // pfnAllowLagCompensation() (wd) SDK2 }; -DLL_FUNCTIONS *pHookedDllFunctions = &sFunctionTable; +compile_data_t g_newdllfunc_cdata[] = +{ + CDATA_NEWDLL(pfnOnFreeEntPrivateData), // pfnOnFreeEntPrivateData() Called right before the object's memory is freed. Calls its destructor. + CDATA_NEWDLL(pfnGameShutdown), // pfnGameShutdown() + CDATA_NEWDLL(pfnShouldCollide), // pfnShouldCollide() + + CDATA_NEWDLL(pfnCvarValue), // pfnCvarValue() (fz) Use mm_CvarValue2 instead + CDATA_NEWDLL(pfnCvarValue2) // pfnCvarValue2() (fz) When pfnQueryClientCvarValue2() completes it will call + // pfnCvarValue2() with the request ID supplied earlier, the name of the cvar requested and the value of that cvar. +}; // It's not clear what the difference is between GetAPI and GetAPI2; they // both appear to return the exact same function table. @@ -477,7 +151,7 @@ C_DLLEXPORT int GetEntityAPI(DLL_FUNCTIONS *pFunctionTable, int interfaceVersion META_ERROR("GetEntityAPI called with null pFunctionTable"); return FALSE; } - else if (interfaceVersion != INTERFACE_VERSION) + if (interfaceVersion != INTERFACE_VERSION) { META_ERROR("GetEntityAPI version mismatch; requested=%d ours=%d", interfaceVersion, INTERFACE_VERSION); return FALSE; @@ -496,7 +170,7 @@ C_DLLEXPORT int GetEntityAPI2(DLL_FUNCTIONS *pFunctionTable, int *interfaceVersi META_ERROR("GetEntityAPI2 called with null pFunctionTable"); return FALSE; } - else if (*interfaceVersion != INTERFACE_VERSION) + if (*interfaceVersion != INTERFACE_VERSION) { META_ERROR("GetEntityAPI2 version mismatch; requested=%d ours=%d", *interfaceVersion, INTERFACE_VERSION); //! Tell engine what version we had, so it can figure out who is out of date. @@ -504,33 +178,10 @@ C_DLLEXPORT int GetEntityAPI2(DLL_FUNCTIONS *pFunctionTable, int *interfaceVersi return FALSE; } - Q_memcpy(pFunctionTable, &sFunctionTable, sizeof(DLL_FUNCTIONS)); + memcpy(pFunctionTable, &sFunctionTable, sizeof(DLL_FUNCTIONS)); return TRUE; } -// I could find _no_ documentation or examples for the intended use of -// NEW_DLL_FUNCTIONS. I wouldn't have even _known_ about the -// GetNewDLLFunctions() function except for the reference in Adminmod.. It -// appears to be new with SDK 2.0. -// -// Obviously, it seems to provide additional functions to the engine, but -// it's unclear why a new table and interface were added, rather than -// appending new functions to the GetAPI table/interface. -// -// Interestingly, it appears to be called by the engine _before_ GetAPI. - -meta_new_dll_functions_t sNewFunctionTable ( - &mm_OnFreeEntPrivateData, // pfnOnFreeEntPrivateData() Called right before the object's memory is freed. Calls its destructor. - &mm_GameShutdown, // pfnGameShutdown() - &mm_ShouldCollide, // pfnShouldCollide() - - &mm_CvarValue, // pfnCvarValue() (fz) Use mm_CvarValue2 instead - &mm_CvarValue2 // pfnCvarValue2() (fz) When pfnQueryClientCvarValue2() completes it will call - // pfnCvarValue2() with the request ID supplied earlier, the name of the cvar requested and the value of that cvar. -); - -NEW_DLL_FUNCTIONS *pHookedNewDllFunctions = &sNewFunctionTable; - C_DLLEXPORT int GetNewDLLFunctions(NEW_DLL_FUNCTIONS *pNewFunctionTable, int *interfaceVersion) { META_DEBUG(6, ("called: GetNewDLLFunctions; version=%d", *interfaceVersion)); @@ -547,7 +198,7 @@ C_DLLEXPORT int GetNewDLLFunctions(NEW_DLL_FUNCTIONS *pNewFunctionTable, int *in META_ERROR("GetNewDLLFunctions called with null pNewFunctionTable"); return FALSE; } - else if (*interfaceVersion != NEW_DLL_FUNCTIONS_VERSION) + if (*interfaceVersion != NEW_DLL_FUNCTIONS_VERSION) { META_ERROR("GetNewDLLFunctions version mismatch; requested=%d ours=%d", *interfaceVersion, NEW_DLL_FUNCTIONS_VERSION); //! Tell engine what version we had, so it can figure out who is out of date. @@ -555,6 +206,76 @@ C_DLLEXPORT int GetNewDLLFunctions(NEW_DLL_FUNCTIONS *pNewFunctionTable, int *in return FALSE; } - sNewFunctionTable.copy_to(pNewFunctionTable); + memcpy(pNewFunctionTable, &sNewFunctionTable, sizeof(NEW_DLL_FUNCTIONS)); return TRUE; } + +void compile_dllfunc_callbacks() +{ + jitdata_t jitdata; + jitdata.plugins = g_plugins ? g_plugins->plist : nullptr; + jitdata.plugins_count = g_plugins ? g_plugins->endlist : 0; + jitdata.table_offset = offsetof(MPlugin, dllapi_table); + jitdata.post_table_offset = offsetof(MPlugin, dllapi_post_table); + + for (auto& cd : g_dllfunc_cdata) { + jitdata.pfn_original = *(size_t *)(size_t(GameDLL.funcs.dllapi_table) + cd.offset); + jitdata.args_count = cd.args_count; + jitdata.has_ret = cd.has_ret; + jitdata.has_varargs = cd.has_varargs; + jitdata.pfn_offset = cd.offset; + jitdata.mm_hook_time = cd.mm_hook_time; + jitdata.mm_hook = cd.mm_hook; + + *(size_t *)(size_t(&sFunctionTable) + cd.offset) = g_jit.compile_callback(&jitdata); + } +} + +void compile_newdllfunc_callbacks() +{ + jitdata_t jitdata; + jitdata.plugins = g_plugins ? g_plugins->plist : nullptr; + jitdata.plugins_count = g_plugins ? g_plugins->endlist : 0; + jitdata.table_offset = offsetof(MPlugin, newapi_table); + jitdata.post_table_offset = offsetof(MPlugin, newapi_post_table); + + for (auto& cd : g_newdllfunc_cdata) { + jitdata.pfn_original = *(size_t *)(size_t(GameDLL.funcs.newapi_table) + cd.offset); + jitdata.args_count = cd.args_count; + jitdata.has_ret = cd.has_ret; + jitdata.has_varargs = cd.has_varargs; + jitdata.pfn_offset = cd.offset; + jitdata.mm_hook_time = cd.mm_hook_time; + jitdata.mm_hook = cd.mm_hook; + + *(size_t *)(size_t(&sNewFunctionTable) + cd.offset) = g_jit.compile_callback(&jitdata); + } +} + +void compile_gamedll_tramps() +{ + // we compile simple static functions that will call dynamic callbacks + for (auto& cd : g_dllfunc_cdata) { + *(size_t *)(size_t(&sFunctionTable) + cd.offset) = g_jit.compile_tramp(size_t(&sFunctionTable_jit) + cd.offset); + } + + // use direct hook + sFunctionTable.pfnServerDeactivate = mm_ServerDeactivate; + + for (auto& cd : g_newdllfunc_cdata) { + *(size_t *)(size_t(&sNewFunctionTable) + cd.offset) = g_jit.compile_tramp(size_t(&sNewFunctionTable_jit) + cd.offset); + } +} + +void compile_gamedll_callbacks() +{ + static bool initialized = false; + + if (!initialized) { + compile_gamedll_tramps(); + initialized = true; + } + + compile_dllfunc_callbacks(); + compile_newdllfunc_callbacks(); +} diff --git a/metamod/src/dllapi.h b/metamod/src/dllapi.h index 567523f..6a75e14 100644 --- a/metamod/src/dllapi.h +++ b/metamod/src/dllapi.h @@ -3,6 +3,8 @@ #include "sdk_util.h" #include "osdep.h" +typedef void (*FN_GAMEINIT)(); + // Typedefs for these are provided in SDK engine/eiface.h, but I didn't // like the names (APIFUNCTION, APIFUNCTION2, NEW_DLL_FUNCTIONS_FN). typedef int (*GETENTITYAPI_FN)(DLL_FUNCTIONS *pFunctionTable, int interfaceVersion); @@ -13,114 +15,4 @@ C_DLLEXPORT int GetEntityAPI(DLL_FUNCTIONS *pFunctionTable, int interfaceVersion C_DLLEXPORT int GetEntityAPI2(DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion); C_DLLEXPORT int GetNewDLLFunctions(NEW_DLL_FUNCTIONS *pNewFunctionTable, int *interfaceVersion); -extern void mm_GameDLLInit(); -extern int mm_DispatchSpawn(edict_t *pent); -extern void mm_DispatchThink(edict_t *pent); -extern void mm_DispatchUse(edict_t *pentUsed, edict_t *pentOther); -extern void mm_DispatchTouch(edict_t *pentTouched, edict_t *pentOther); -extern void mm_DispatchBlocked(edict_t *pentBlocked, edict_t *pentOther); -extern void mm_DispatchKeyValue(edict_t *pentKeyvalue, KeyValueData *pkvd); -extern void mm_DispatchSave(edict_t *pent, SAVERESTOREDATA *pSaveData); -extern int mm_DispatchRestore(edict_t *pent, SAVERESTOREDATA *pSaveData, int globalEntity); -extern void mm_DispatchObjectCollisionBox(edict_t *pent); -extern void mm_SaveWriteFields(SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount); -extern void mm_SaveReadFields(SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount); -extern void mm_SaveGlobalState(SAVERESTOREDATA *pSaveData); -extern void mm_RestoreGlobalState(SAVERESTOREDATA *pSaveData); -extern void mm_ResetGlobalState(); -extern BOOL mm_ClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ]); -extern void mm_ClientDisconnect(edict_t *pEntity); -extern void mm_ClientKill(edict_t *pEntity); -extern void mm_ClientPutInServer(edict_t *pEntity); -extern void mm_ClientCommand(edict_t *pEntity); -extern void mm_ClientUserInfoChanged(edict_t *pEntity, char *infobuffer); -extern void mm_ServerActivate(edict_t *pEdictList, int edictCount, int clientMax); -extern void mm_ServerDeactivate(); -extern void mm_PlayerPreThink(edict_t *pEntity); -extern void mm_PlayerPostThink(edict_t *pEntity); -extern void mm_StartFrame(); -extern void mm_ParmsNewLevel(); -extern void mm_ParmsChangeLevel(); -extern const char *mm_GetGameDescription(); -extern void mm_PlayerCustomization(edict_t *pEntity, customization_t *pCust); -extern void mm_SpectatorConnect (edict_t *pEntity); -extern void mm_SpectatorDisconnect (edict_t *pEntity); -extern void mm_SpectatorThink (edict_t *pEntity); -extern void mm_Sys_Error(const char *error_string); -extern void mm_PM_Move(struct playermove_s *ppmove, int server); -extern void mm_PM_Init(struct playermove_s *ppmove); -extern char mm_PM_FindTextureType (const char *name); -extern void mm_SetupVisibility(edict_t *pViewEntity, edict_t *pClient, unsigned char **pvs, unsigned char **pas); -extern void mm_UpdateClientData (const struct edict_s *ent, int sendweapons, struct clientdata_s *cd); -extern int mm_AddToFullPack(struct entity_state_s *state, int e, edict_t *ent, edict_t *host, int hostflags, int player, unsigned char *pSet); -extern void mm_CreateBaseline(int player, int eindex, struct entity_state_s *baseline, struct edict_s *entity, int playermodelindex, vec3_t player_mins, vec3_t player_maxs); -extern void mm_RegisterEncoders(); -extern int mm_GetWeaponData(struct edict_s *player, struct weapon_data_s *info); -extern void mm_CmdStart(const edict_t *player, const struct usercmd_s *cmd, unsigned int random_seed); -extern void mm_CmdEnd (const edict_t *player); -extern int mm_ConnectionlessPacket(const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size); -extern int mm_GetHullBounds(int hullnumber, float *mins, float *maxs); -extern void mm_CreateInstancedBaselines (); -extern int mm_InconsistentFile(const edict_t *player, const char *filename, char *disconnect_message); -extern int mm_AllowLagCompensation(); -extern void mm_OnFreeEntPrivateData(edict_t pEnt); -extern void mm_GameShutdown(); -extern int mm_ShouldCollide(edict_t *pentTouched, edict_t *pentOther); -extern void mm_CvarValue(const edict_t *pEnt, const char *value); -extern void mm_CvarValue2(const edict_t *pEnt, int requestID, const char *cvarName, const char *value); - -typedef void (*FN_GAMEINIT)(); -typedef int (*FN_DISPATCHSPAWN)(edict_t *pent); -typedef void (*FN_DISPATCHTHINK)(edict_t *pent); -typedef void (*FN_DISPATCHUSE)(edict_t *pentUsed, edict_t *pentOther); -typedef void (*FN_DISPATCHTOUCH)(edict_t *pentTouched, edict_t *pentOther); -typedef void (*FN_DISPATCHBLOCKED)(edict_t *pentBlocked, edict_t *pentOther); -typedef void (*FN_DISPATCHKEYVALUE)(edict_t *pentKeyvalue, KeyValueData *pkvd); -typedef void (*FN_DISPATCHSAVE)(edict_t *pent, SAVERESTOREDATA *pSaveData); -typedef int (*FN_DISPATCHRESTORE)(edict_t *pent, SAVERESTOREDATA *pSaveData, int globalEntity); -typedef void (*FN_DISPATCHOBJECTCOLLISIONBOX)(edict_t *pent); -typedef void (*FN_SAVEWRITEFIELDS)(SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount); -typedef void (*FN_SAVEREADFIELDS)(SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount); -typedef void (*FN_SAVEGLOBALSTATE)(SAVERESTOREDATA *pSaveData); -typedef void (*FN_RESTOREGLOBALSTATE)(SAVERESTOREDATA *pSaveData); -typedef void (*FN_RESETGLOBALSTATE)(); -typedef BOOL (*FN_CLIENTCONNECT)(edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ]); -typedef void (*FN_CLIENTDISCONNECT)(edict_t *pEntity); -typedef void (*FN_CLIENTKILL)(edict_t *pEntity); -typedef void (*FN_CLIENTPUTINSERVER)(edict_t *pEntity); -typedef void (*FN_CLIENTCOMMAND)(edict_t *pEntity); -typedef void (*FN_CLIENTUSERINFOCHANGED)(edict_t *pEntity, char *infobuffer); -typedef void (*FN_SERVERACTIVATE)(edict_t *pEdictList, int edictCount, int clientMax); -typedef void (*FN_SERVERDEACTIVATE)(); -typedef void (*FN_PLAYERPRETHINK)(edict_t *pEntity); -typedef void (*FN_PLAYERPOSTTHINK)(edict_t *pEntity); -typedef void (*FN_STARTFRAME)(); -typedef void (*FN_PARMSNEWLEVEL)(); -typedef void (*FN_PARMSCHANGELEVEL)(); -typedef const char *(*FN_GETGAMEDESCRIPTION)(); -typedef void (*FN_PLAYERCUSTOMIZATION)(edict_t *pEntity, customization_t *pCust); -typedef void (*FN_SPECTATORCONNECT) (edict_t *pEntity); -typedef void (*FN_SPECTATORDISCONNECT) (edict_t *pEntity); -typedef void (*FN_SPECTATORTHINK) (edict_t *pEntity); -typedef void (*FN_SYS_ERROR)(const char *error_string); -typedef void (*FN_PM_MOVE)(struct playermove_s *ppmove, int server); -typedef void (*FN_PM_INIT)(struct playermove_s *ppmove); -typedef char (*FN_PM_FINDTEXTURETYPE)(char *name); -typedef void (*FN_SETUPVISIBILITY)(edict_t *pViewEntity, edict_t *pClient, unsigned char **pvs, unsigned char **pas); -typedef void (*FN_UPDATECLIENTDATA) (const struct edict_s *ent, int sendweapons, struct clientdata_s *cd); -typedef int (*FN_ADDTOFULLPACK)(struct entity_state_s *state, int e, edict_t *ent, edict_t *host, int hostflags, int player, unsigned char *pSet); -typedef void (*FN_CREATEBASELINE)(int player, int eindex, struct entity_state_s *baseline, struct edict_s *entity, int playermodelindex, vec3_t player_mins, vec3_t player_maxs); -typedef void (*FN_REGISTERENCODERS)(); -typedef int (*FN_GETWEAPONDATA)(struct edict_s *player, struct weapon_data_s *info); -typedef void (*FN_CMDSTART)(const edict_t *player, const struct usercmd_s *cmd, unsigned int random_seed); -typedef void (*FN_CMDEND) (const edict_t *player); -typedef int (*FN_CONNECTIONLESSPACKET)(const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size); -typedef int (*FN_GETHULLBOUNDS)(int hullnumber, float *mins, float *maxs); -typedef void (*FN_CREATEINSTANCEDBASELINES) (); -typedef int (*FN_INCONSISTENTFILE)(const edict_t *player, const char *filename, char *disconnect_message); -typedef int (*FN_ALLOWLAGCOMPENSATION)(); -typedef void (*FN_ONFREEENTPRIVATEDATA)(edict_t *pEnt); -typedef void (*FN_GAMESHUTDOWN)(); -typedef int (*FN_SHOULDCOLLIDE)(edict_t *pentTouched, edict_t *pentOther); -typedef void (*FN_CVARVALUE)(const edict_t *pEnt, const char *value); //! Obsolete! Use FN_CVARVALUE2 instead -typedef void (*FN_CVARVALUE2)(const edict_t *pEnt, int requestID, const char *cvarName, const char *value); +void compile_gamedll_callbacks(); diff --git a/metamod/src/engine_api.cpp b/metamod/src/engine_api.cpp index 7f3bd5c..702a26d 100644 --- a/metamod/src/engine_api.cpp +++ b/metamod/src/engine_api.cpp @@ -1,552 +1,26 @@ #include "precompiled.h" -// g_engine routines, functions returning "void". -#define META_ENGINE_HANDLE_void(FN_TYPE, pfnName, pfn_args) \ - SETUP_API_CALLS_void(FN_TYPE, pfnName, engine_info); \ - CALL_PLUGIN_API_void(P_PRE, pfnName, pfn_args, engine_table); \ - CALL_ENGINE_API_void(pfnName, pfn_args); \ - CALL_PLUGIN_API_void(P_POST, pfnName, pfn_args, engine_post_table); +#define CDATA_ENG_H(x, p, h) CDATA_ENTRY(enginefuncs_t, x, p, size_t(h)) +#define CDATA_ENG(x) CDATA_ENTRY(enginefuncs_t, x, P_PRE, 0u) -// g_engine routines, functions returning an actual value. -#define META_ENGINE_HANDLE(ret_t, ret_init, FN_TYPE, pfnName, pfn_args) \ - SETUP_API_CALLS(ret_t, ret_init, FN_TYPE, pfnName, engine_info); \ - CALL_PLUGIN_API(P_PRE, ret_init, pfnName, pfn_args, MRES_SUPERCEDE, engine_table); \ - CALL_ENGINE_API(pfnName, pfn_args); \ - CALL_PLUGIN_API(P_POST, ret_init, pfnName, pfn_args, MRES_OVERRIDE, engine_post_table); +meta_enginefuncs_t meta_engfuncs; // static addresses for gamedll +meta_enginefuncs_t meta_engfuncs_jit; // dynamic jit callbacks - -// g_engine routines, printf-style functions returning "void". -#define META_ENGINE_HANDLE_void_varargs(FN_TYPE, pfnName, pfn_arg, fmt_arg) \ - SETUP_API_CALLS_void(FN_TYPE, pfnName, engine_info); \ - char buf[MAX_STRBUF_LEN]; \ - va_list ap; \ - META_DEBUG(loglevel, ("In %s: fmt=%s", pfn_string, fmt_arg)); \ - va_start(ap, fmt_arg); \ - Q_vsnprintf(buf, sizeof(buf), fmt_arg, ap); \ - va_end(ap); \ - CALL_PLUGIN_API_void(P_PRE, pfnName, (pfn_arg, "%s", buf), engine_table); \ - CALL_ENGINE_API_void(pfnName, (pfn_arg, "%s", buf)); \ - CALL_PLUGIN_API_void(P_POST, pfnName, (pfn_arg, "%s", buf), engine_post_table); - -// g_engine routines, printf-style functions returning an actual value. -#define META_ENGINE_HANDLE_varargs(ret_t, ret_init, FN_TYPE, pfnName, pfn_arg, fmt_arg) \ - SETUP_API_CALLS(ret_t, ret_init, FN_TYPE, pfnName, engine_info); \ - char buf[MAX_STRBUF_LEN]; \ - va_list ap; \ - META_DEBUG(loglevel, ("In %s: fmt=%s", pfn_string, fmt_arg)); \ - va_start(ap, fmt_arg); \ - Q_vsnprintf(buf, sizeof(buf), fmt_arg, ap); \ - va_end(ap); \ - CALL_PLUGIN_API(P_PRE, ret_init, pfnName, (pfn_arg, "%s", buf), MRES_SUPERCEDE, engine_table); \ - CALL_ENGINE_API(pfnName, (pfn_arg, "%s", buf)); \ - CALL_PLUGIN_API(P_POST, ret_init, pfnName, (pfn_arg, "%s", buf), MRES_OVERRIDE, engine_post_table); - -int mm_PrecacheModel(const char *s) -{ - META_ENGINE_HANDLE(int, 0, FN_PRECACHEMODEL, pfnPrecacheModel, (s)); - RETURN_API() -} - -int mm_PrecacheSound(const char *s) -{ - META_ENGINE_HANDLE(int, 0, FN_PRECACHESOUND, pfnPrecacheSound, (s)); - RETURN_API() -} - -void mm_SetModel(edict_t *e, const char *m) -{ - META_ENGINE_HANDLE_void(FN_SETMODEL, pfnSetModel, (e, m)); - RETURN_API_void() -} - -int mm_ModelIndex(const char *m) -{ - META_ENGINE_HANDLE(int, 0, FN_MODELINDEX, pfnModelIndex, (m)); - RETURN_API() -} - -int mm_ModelFrames(int modelIndex) -{ - META_ENGINE_HANDLE(int, 0, FN_MODELFRAMES, pfnModelFrames, (modelIndex)); - RETURN_API() -} - -void mm_SetSize(edict_t *e, const float *rgflMin, const float *rgflMax) -{ - META_ENGINE_HANDLE_void(FN_SETSIZE, pfnSetSize, (e, rgflMin, rgflMax)); - RETURN_API_void() -} - -void mm_ChangeLevel(const char *s1, const char *s2) -{ - META_ENGINE_HANDLE_void(FN_CHANGELEVEL, pfnChangeLevel, (s1, s2)); - RETURN_API_void() -} - -void mm_GetSpawnParms(edict_t *ent) -{ - META_ENGINE_HANDLE_void(FN_GETSPAWNPARMS, pfnGetSpawnParms, (ent)); - RETURN_API_void() -} - -void mm_SaveSpawnParms(edict_t *ent) -{ - META_ENGINE_HANDLE_void(FN_SAVESPAWNPARMS, pfnSaveSpawnParms, (ent)); - RETURN_API_void() -} - -float mm_VecToYaw(const float *rgflVector) -{ - META_ENGINE_HANDLE(float, 0.0, FN_VECTOYAW, pfnVecToYaw, (rgflVector)); - RETURN_API() -} - -void mm_VecToAngles(const float *rgflVectorIn, float *rgflVectorOut) -{ - META_ENGINE_HANDLE_void(FN_VECTOANGLES, pfnVecToAngles, (rgflVectorIn, rgflVectorOut)); - RETURN_API_void() -} - -void mm_MoveToOrigin(edict_t *ent, const float *pflGoal, float dist, int iMoveType) -{ - META_ENGINE_HANDLE_void(FN_MOVETOORIGIN, pfnMoveToOrigin, (ent, pflGoal, dist, iMoveType)); - RETURN_API_void() -} - -void mm_ChangeYaw(edict_t *ent) -{ - META_ENGINE_HANDLE_void(FN_CHANGEYAW, pfnChangeYaw, (ent)); - RETURN_API_void() -} - -void mm_ChangePitch(edict_t *ent) -{ - META_ENGINE_HANDLE_void(FN_CHANGEPITCH, pfnChangePitch, (ent)); - RETURN_API_void() -} - -edict_t *mm_FindEntityByString(edict_t *pEdictStartSearchAfter, const char *pszField, const char *pszValue) -{ - META_ENGINE_HANDLE(edict_t *, NULL, FN_FINDENTITYBYSTRING, pfnFindEntityByString, (pEdictStartSearchAfter, pszField, pszValue)); - RETURN_API() -} - -int mm_GetEntityIllum(edict_t *pEnt) -{ - META_ENGINE_HANDLE(int, 0, FN_GETENTITYILLUM, pfnGetEntityIllum, (pEnt)); - RETURN_API() -} - -edict_t *mm_FindEntityInSphere(edict_t *pEdictStartSearchAfter, const float *org, float rad) -{ - META_ENGINE_HANDLE(edict_t *, NULL, FN_FINDENTITYINSPHERE, pfnFindEntityInSphere, (pEdictStartSearchAfter, org, rad)); - RETURN_API() -} - -edict_t *mm_FindClientInPVS(edict_t *pEdict) -{ - META_ENGINE_HANDLE(edict_t *, NULL, FN_FINDCLIENTINPVS, pfnFindClientInPVS, (pEdict)); - RETURN_API() -} - -edict_t *mm_EntitiesInPVS(edict_t *pplayer) -{ - META_ENGINE_HANDLE(edict_t *, NULL, FN_ENTITIESINPVS, pfnEntitiesInPVS, (pplayer)); - RETURN_API() -} - -void mm_MakeVectors(const float *rgflVector) -{ - META_ENGINE_HANDLE_void(FN_MAKEVECTORS, pfnMakeVectors, (rgflVector)); - RETURN_API_void() -} - -void mm_AngleVectors(const float *rgflVector, float *forward, float *right, float *up) -{ - META_ENGINE_HANDLE_void(FN_ANGLEVECTORS, pfnAngleVectors, (rgflVector, forward, right, up)); - RETURN_API_void() -} - -edict_t *mm_CreateEntity() -{ - META_ENGINE_HANDLE(edict_t *, NULL, FN_CREATEENTITY, pfnCreateEntity, ()); - RETURN_API() -} - -void mm_RemoveEntity(edict_t *e) -{ - META_ENGINE_HANDLE_void(FN_REMOVEENTITY, pfnRemoveEntity, (e)); - RETURN_API_void() -} - -edict_t *mm_CreateNamedEntity(int className) -{ - META_ENGINE_HANDLE(edict_t *, NULL, FN_CREATENAMEDENTITY, pfnCreateNamedEntity, (className)); - RETURN_API() -} - -void mm_MakeStatic(edict_t *ent) -{ - META_ENGINE_HANDLE_void(FN_MAKESTATIC, pfnMakeStatic, (ent)); - RETURN_API_void() -} - -int mm_EntIsOnFloor(edict_t *e) -{ - META_ENGINE_HANDLE(int, 0, FN_ENTISONFLOOR, pfnEntIsOnFloor, (e)); - RETURN_API() -} - -int mm_DropToFloor(edict_t *e) -{ - META_ENGINE_HANDLE(int, 0, FN_DROPTOFLOOR, pfnDropToFloor, (e)); - RETURN_API() -} - -int mm_WalkMove(edict_t *ent, float yaw, float dist, int iMode) -{ - META_ENGINE_HANDLE(int, 0, FN_WALKMOVE, pfnWalkMove, (ent, yaw, dist, iMode)); - RETURN_API() -} - -void mm_SetOrigin(edict_t *e, const float *rgflOrigin) -{ - META_ENGINE_HANDLE_void(FN_SETORIGIN, pfnSetOrigin, (e, rgflOrigin)); - RETURN_API_void() -} - -void mm_EmitSound(edict_t *entity, int channel, const char *sample, /*int*/float volume, float attenuation, int fFlags, int pitch) -{ - META_ENGINE_HANDLE_void(FN_EMITSOUND, pfnEmitSound, (entity, channel, sample, volume, attenuation, fFlags, pitch)); - RETURN_API_void() -} - -void mm_EmitAmbientSound(edict_t *entity, float *pos, const char *samp, float vol, float attenuation, int fFlags, int pitch) -{ - META_ENGINE_HANDLE_void(FN_EMITAMBIENTSOUND, pfnEmitAmbientSound, (entity, pos, samp, vol, attenuation, fFlags, pitch)); - RETURN_API_void() -} - -void mm_TraceLine(const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr) -{ - META_ENGINE_HANDLE_void(FN_TRACELINE, pfnTraceLine, (v1, v2, fNoMonsters, pentToSkip, ptr)); - RETURN_API_void() -} - -void mm_TraceToss(edict_t *pent, edict_t *pentToIgnore, TraceResult *ptr) -{ - META_ENGINE_HANDLE_void(FN_TRACETOSS, pfnTraceToss, (pent, pentToIgnore, ptr)); - RETURN_API_void() -} - -int mm_TraceMonsterHull(edict_t *pEdict, const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr) -{ - META_ENGINE_HANDLE(int, 0, FN_TRACEMONSTERHULL, pfnTraceMonsterHull, (pEdict, v1, v2, fNoMonsters, pentToSkip, ptr)); - RETURN_API() -} - -void mm_TraceHull(const float *v1, const float *v2, int fNoMonsters, int hullNumber, edict_t *pentToSkip, TraceResult *ptr) -{ - META_ENGINE_HANDLE_void(FN_TRACEHULL, pfnTraceHull, (v1, v2, fNoMonsters, hullNumber, pentToSkip, ptr)); - RETURN_API_void() -} - -void mm_TraceModel(const float *v1, const float *v2, int hullNumber, edict_t *pent, TraceResult *ptr) -{ - META_ENGINE_HANDLE_void(FN_TRACEMODEL, pfnTraceModel, (v1, v2, hullNumber, pent, ptr)); - RETURN_API_void() -} - -const char *mm_TraceTexture(edict_t *pTextureEntity, const float *v1, const float *v2) -{ - META_ENGINE_HANDLE(const char *, NULL, FN_TRACETEXTURE, pfnTraceTexture, (pTextureEntity, v1, v2)); - RETURN_API() -} - -void mm_TraceSphere(const float *v1, const float *v2, int fNoMonsters, float radius, edict_t *pentToSkip, TraceResult *ptr) -{ - META_ENGINE_HANDLE_void(FN_TRACESPHERE, pfnTraceSphere, (v1, v2, fNoMonsters, radius, pentToSkip, ptr)); - RETURN_API_void() -} - -void mm_GetAimVector(edict_t *ent, float speed, float *rgflReturn) -{ - META_ENGINE_HANDLE_void(FN_GETAIMVECTOR, pfnGetAimVector, (ent, speed, rgflReturn)); - RETURN_API_void() -} - -void mm_ServerCommand(char *str) -{ - META_ENGINE_HANDLE_void(FN_SERVERCOMMAND, pfnServerCommand, (str)); - RETURN_API_void() -} - -void mm_ServerExecute() -{ - META_ENGINE_HANDLE_void(FN_SERVEREXECUTE, pfnServerExecute, ()); - RETURN_API_void() -} - -void mm_engClientCommand(edict_t *pEdict, char *szFmt, ...) -{ - META_ENGINE_HANDLE_void_varargs(FN_CLIENTCOMMAND_ENG, pfnClientCommand, pEdict, szFmt); - RETURN_API_void() -} - -void mm_ParticleEffect(const float *org, const float *dir, float color, float count) -{ - META_ENGINE_HANDLE_void(FN_PARTICLEEFFECT, pfnParticleEffect, (org, dir, color, count)); - RETURN_API_void() -} - -void mm_LightStyle(int style, char *val) -{ - META_ENGINE_HANDLE_void(FN_LIGHTSTYLE, pfnLightStyle, (style, val)); - RETURN_API_void() -} - -int mm_DecalIndex(const char *name) -{ - META_ENGINE_HANDLE(int, 0, FN_DECALINDEX, pfnDecalIndex, (name)); - RETURN_API() -} - -int mm_PointContents(const float *rgflVector) -{ - META_ENGINE_HANDLE(int, 0, FN_POINTCONTENTS, pfnPointContents, (rgflVector)); - RETURN_API() -} - -void mm_MessageBegin(int msg_dest, int msg_type, const float *pOrigin, edict_t *ed) -{ - META_ENGINE_HANDLE_void(FN_MESSAGEBEGIN, pfnMessageBegin, (msg_dest, msg_type, pOrigin, ed)); - RETURN_API_void() -} - -void mm_MessageEnd() -{ - META_ENGINE_HANDLE_void(FN_MESSAGEEND, pfnMessageEnd, ()); - RETURN_API_void() -} - -void mm_WriteByte(int iValue) -{ - META_ENGINE_HANDLE_void(FN_WRITEBYTE, pfnWriteByte, (iValue)); - RETURN_API_void() -} - -void mm_WriteChar(int iValue) -{ - META_ENGINE_HANDLE_void(FN_WRITECHAR, pfnWriteChar, (iValue)); - RETURN_API_void() -} - -void mm_WriteShort(int iValue) -{ - META_ENGINE_HANDLE_void(FN_WRITESHORT, pfnWriteShort, (iValue)); - RETURN_API_void() -} - -void mm_WriteLong(int iValue) -{ - META_ENGINE_HANDLE_void(FN_WRITELONG, pfnWriteLong, (iValue)); - RETURN_API_void() -} - -void mm_WriteAngle(float flValue) -{ - META_ENGINE_HANDLE_void(FN_WRITEANGLE, pfnWriteAngle, (flValue)); - RETURN_API_void() -} - -void mm_WriteCoord(float flValue) -{ - META_ENGINE_HANDLE_void(FN_WRITECOORD, pfnWriteCoord, (flValue)); - RETURN_API_void() -} - -void mm_WriteString(const char *sz) -{ - META_ENGINE_HANDLE_void(FN_WRITESTRING, pfnWriteString, (sz)); - RETURN_API_void() -} - -void mm_WriteEntity(int iValue) -{ - META_ENGINE_HANDLE_void(FN_WRITEENTITY, pfnWriteEntity, (iValue)); - RETURN_API_void() -} - -void mm_CVarRegister(cvar_t *pCvar) -{ - META_ENGINE_HANDLE_void(FN_CVARREGISTER, pfnCVarRegister, (pCvar)); - RETURN_API_void() -} - -float mm_CVarGetFloat(const char *szVarName) +void mm_QueryClientCvarValue(const edict_t* pEdict, const char* cvarName) { - META_ENGINE_HANDLE(float, 0.0, FN_CVARGETFLOAT, pfnCVarGetFloat, (szVarName)); - RETURN_API() + g_players.set_player_cvar_query(pEdict, cvarName); } -const char *mm_CVarGetString(const char *szVarName) +void mm_RegUserMsg(const char* pszName, int iSize) { - META_ENGINE_HANDLE(const char *, NULL, FN_CVARGETSTRING, pfnCVarGetString, (szVarName)); - RETURN_API() -} - -void mm_CVarSetFloat(const char *szVarName, float flValue) -{ - META_ENGINE_HANDLE_void(FN_CVARSETFLOAT, pfnCVarSetFloat, (szVarName, flValue)); - RETURN_API_void() -} - -void mm_CVarSetString(const char *szVarName, const char *szValue) -{ - META_ENGINE_HANDLE_void(FN_CVARSETSTRING, pfnCVarSetString, (szVarName, szValue)); - RETURN_API_void() -} - -void mm_AlertMessage(ALERT_TYPE atype, const char *szFmt, ...) -{ -#ifndef UNFINISHED - META_ENGINE_HANDLE_void_varargs(FN_ALERTMESSAGE, pfnAlertMessage, atype, szFmt); -#else - // Expand macro, since we need to do extra work here. - // usual setup - - SETUP_API_CALLS_void(FN_ALERTMESSAGE, pfnAlertMessage, engine_info); - char buf[MAX_STRBUF_LEN]; - va_list ap; - - META_DEBUG(loglevel, ("In %s: fmt=%s", pfn_string, szFmt)); - va_start(ap, szFmt); - int len = Q_vsnprintf(buf, sizeof(buf), szFmt, ap) + 1; - va_end(ap); - - // pass logmsg string to log parsing thread - /// qmsg = Q_strdup(buf); - char *qmsg = (char *)Q_malloc(len * sizeof(char)); - if (!qmsg) - META_ERROR("malloc failed for logmsg to thread queue"); - else - { - STRNCPY(qmsg, buf, len); - LogQueue->push(qmsg); - } - - // usual passing to plugins/engine - CALL_PLUGIN_API_void(P_PRE, pfnAlertMessage, (atype, "%s", buf), engine_table); - CALL_ENGINE_API_void(pfnAlertMessage, (atype, "%s", buf)); - CALL_PLUGIN_API_void(P_POST, pfnAlertMessage, (atype, "%s", buf), engine_post_table); -#endif // UNFINISHED - - // usual return. - RETURN_API_void() -} - -void mm_EngineFprintf(void *pfile, const char *szFmt, ...) -{ - META_ENGINE_HANDLE_void_varargs(FN_ENGINEFPRINTF, pfnEngineFprintf, pfile, szFmt); - RETURN_API_void() -} - -void *mm_PvAllocEntPrivateData(edict_t *pEdict, int32 cb) -{ - META_ENGINE_HANDLE(void *, NULL, FN_PVALLOCENTPRIVATEDATA, pfnPvAllocEntPrivateData, (pEdict, cb)); - RETURN_API() -} - -void *mm_PvEntPrivateData(edict_t *pEdict) -{ - META_ENGINE_HANDLE(void *, NULL, FN_PVENTPRIVATEDATA, pfnPvEntPrivateData, (pEdict)); - RETURN_API() -} - -void mm_FreeEntPrivateData(edict_t *pEdict) -{ - META_ENGINE_HANDLE_void(FN_FREEENTPRIVATEDATA, pfnFreeEntPrivateData, (pEdict)); - RETURN_API_void() -} - -const char *mm_SzFromIndex(int iString) -{ - META_ENGINE_HANDLE(const char *, NULL, FN_SZFROMINDEX, pfnSzFromIndex, (iString)); - RETURN_API() -} - -int mm_AllocString(const char *szValue) -{ - META_ENGINE_HANDLE(int, 0, FN_ALLOCSTRING, pfnAllocString, (szValue)); - RETURN_API() -} - -struct entvars_s *mm_GetVarsOfEnt(edict_t *pEdict) -{ - META_ENGINE_HANDLE(struct entvars_s *, NULL, FN_GETVARSOFENT, pfnGetVarsOfEnt, (pEdict)); - RETURN_API() -} - -edict_t *mm_PEntityOfEntOffset(int iEntOffset) -{ - META_ENGINE_HANDLE(edict_t *, NULL, FN_PENTITYOFENTOFFSET, pfnPEntityOfEntOffset, (iEntOffset)); - RETURN_API() -} - -int mm_EntOffsetOfPEntity(const edict_t *pEdict) -{ - META_ENGINE_HANDLE(int, 0, FN_ENTOFFSETOFPENTITY, pfnEntOffsetOfPEntity, (pEdict)); - RETURN_API() -} - -int mm_IndexOfEdict(const edict_t *pEdict) -{ - META_ENGINE_HANDLE(int, 0, FN_INDEXOFEDICT, pfnIndexOfEdict, (pEdict)); - RETURN_API() -} - -edict_t *mm_PEntityOfEntIndex(int iEntIndex) -{ - META_ENGINE_HANDLE(edict_t *, NULL, FN_PENTITYOFENTINDEX, pfnPEntityOfEntIndex, (iEntIndex)); - RETURN_API() -} - -edict_t *mm_FindEntityByVars(struct entvars_s *pvars) -{ - META_ENGINE_HANDLE(edict_t *, NULL, FN_FINDENTITYBYVARS, pfnFindEntityByVars, (pvars)); - RETURN_API() -} - -void *mm_GetModelPtr(edict_t *pEdict) -{ - META_ENGINE_HANDLE(void *, NULL, FN_GETMODELPTR, pfnGetModelPtr, (pEdict)); - RETURN_API() -} - -int mm_RegUserMsg(const char *pszName, int iSize) -{ - int imsgid; - MRegMsg *nmsg = nullptr; - META_ENGINE_HANDLE(int, 0, FN_REGUSERMSG, pfnRegUserMsg, (pszName, iSize)); - - // Expand the macro, since we need to do extra work. - /// RETURN_API() - if (--CALL_API_count > 0) - PublicMetaGlobals = backup_meta_globals; - - if (status == MRES_OVERRIDE) - { - META_DEBUG(loglevel, ("Returning (override) %s()", pfn_string)); - imsgid = override_ret; - } - else - imsgid = orig_ret; + /*__asm int 3; // Add the msgid, name, and size to our saved list, if we haven't // already. - nmsg = g_regMsgs->find(imsgid); - if (nmsg) - { - if (FStrEq(pszName, nmsg->name)) + auto imsgid = *(int *)(g_metaGlobals.status == MRES_OVERRIDE ? g_metaGlobals.override_ret : g_metaGlobals.orig_ret); + auto nmsg = g_regMsgs->find(imsgid); + + if (nmsg) { + if (!strcmp(pszName, nmsg->name)) // This name/msgid pair was already registered. META_DEBUG(3, ("user message registered again: name=%s, msgid=%d", pszName, imsgid)); else @@ -554,719 +28,252 @@ int mm_RegUserMsg(const char *pszName, int iSize) META_ERROR("user message id reused: msgid=%d, oldname=%s, newname=%s", imsgid, nmsg->name, pszName); } else - g_regMsgs->add(pszName, imsgid, iSize); + g_regMsgs->add(pszName, imsgid, iSize);*/ +} + +compile_data_t g_engfuncs_cdata[] = +{ + CDATA_ENG(pfnPrecacheModel), // pfnPrecacheModel() + CDATA_ENG(pfnPrecacheSound), // pfnPrecacheSound() + CDATA_ENG(pfnSetModel), // pfnSetModel() + CDATA_ENG(pfnModelIndex), // pfnModelIndex() + CDATA_ENG(pfnModelFrames), // pfnModelFrames() + + CDATA_ENG(pfnSetSize), // pfnSetSize() + CDATA_ENG(pfnChangeLevel), // pfnChangeLevel() + CDATA_ENG(pfnGetSpawnParms), // pfnGetSpawnParms() + CDATA_ENG(pfnSaveSpawnParms), // pfnSaveSpawnParms() + + CDATA_ENG(pfnVecToYaw), // pfnVecToYaw() + CDATA_ENG(pfnVecToAngles), // pfnVecToAngles() + CDATA_ENG(pfnMoveToOrigin), // pfnMoveToOrigin() + CDATA_ENG(pfnChangeYaw), // pfnChangeYaw() + CDATA_ENG(pfnChangePitch), // pfnChangePitch() + + CDATA_ENG(pfnFindEntityByString), // pfnFindEntityByString() + CDATA_ENG(pfnGetEntityIllum), // pfnGetEntityIllum() + CDATA_ENG(pfnFindEntityInSphere), // pfnFindEntityInSphere() + CDATA_ENG(pfnFindClientInPVS), // pfnFindClientInPVS() + CDATA_ENG(pfnEntitiesInPVS), // pfnEntitiesInPVS() + + CDATA_ENG(pfnMakeVectors), // pfnMakeVectors() + CDATA_ENG(pfnAngleVectors), // pfnAngleVectors() - return imsgid; -} - -void mm_AnimationAutomove(const edict_t *pEdict, float flTime) -{ - META_ENGINE_HANDLE_void(FN_ANIMATIONAUTOMOVE, pfnAnimationAutomove, (pEdict, flTime)); - RETURN_API_void() -} - -void mm_GetBonePosition(const edict_t *pEdict, int iBone, float *rgflOrigin, float *rgflAngles) -{ - META_ENGINE_HANDLE_void(FN_GETBONEPOSITION, pfnGetBonePosition, (pEdict, iBone, rgflOrigin, rgflAngles)); - RETURN_API_void() -} - -uint32 mm_FunctionFromName(const char *pName) -{ - META_ENGINE_HANDLE(uint32, 0, FN_FUNCTIONFROMNAME, pfnFunctionFromName, (pName)); - RETURN_API() -} - -const char *mm_NameForFunction(uint32 function) -{ - META_ENGINE_HANDLE(const char *, NULL, FN_NAMEFORFUNCTION, pfnNameForFunction, (function)); - RETURN_API() -} - -// JOHN: engine callbacks so game DLL can print messages to individual clients -void mm_ClientPrintf(edict_t *pEdict, PRINT_TYPE ptype, const char *szMsg) -{ - META_ENGINE_HANDLE_void(FN_CLIENTPRINTF, pfnClientPrintf, (pEdict, ptype, szMsg)); - RETURN_API_void() -} - -void mm_ServerPrint(const char *szMsg) -{ - META_ENGINE_HANDLE_void(FN_SERVERPRINT, pfnServerPrint, (szMsg)); - RETURN_API_void() -} - -// these 3 added so game DLL can easily access client 'cmd' strings -const char *mm_Cmd_Args() -{ - META_ENGINE_HANDLE(const char *, NULL, FN_CMD_ARGS, pfnCmd_Args, ()); - RETURN_API() -} - -const char *mm_Cmd_Argv(int argc) -{ - META_ENGINE_HANDLE(const char *, NULL, FN_CMD_ARGV, pfnCmd_Argv, (argc)); - RETURN_API() -} - -int mm_Cmd_Argc() -{ - META_ENGINE_HANDLE(int, 0, FN_CMD_ARGC, pfnCmd_Argc, ()); - RETURN_API() -} - -void mm_GetAttachment(const edict_t *pEdict, int iAttachment, float *rgflOrigin, float *rgflAngles) -{ - META_ENGINE_HANDLE_void(FN_GETATTACHMENT, pfnGetAttachment, (pEdict, iAttachment, rgflOrigin, rgflAngles)); - RETURN_API_void() -} - -void mm_CRC32_Init(CRC32_t *pulCRC) -{ - META_ENGINE_HANDLE_void(FN_CRC32_INIT, pfnCRC32_Init, (pulCRC)); - RETURN_API_void() -} -void mm_CRC32_ProcessBuffer(CRC32_t *pulCRC, void *p, int len) -{ - META_ENGINE_HANDLE_void(FN_CRC32_PROCESSBUFFER, pfnCRC32_ProcessBuffer, (pulCRC, p, len)); - RETURN_API_void() -} -void mm_CRC32_ProcessByte(CRC32_t *pulCRC, unsigned char ch) -{ - META_ENGINE_HANDLE_void(FN_CRC32_PROCESSBYTE, pfnCRC32_ProcessByte, (pulCRC, ch)); - RETURN_API_void() -} -CRC32_t mm_CRC32_Final(CRC32_t pulCRC) -{ - META_ENGINE_HANDLE(CRC32_t, 0, FN_CRC32_FINAL, pfnCRC32_Final, (pulCRC)); - RETURN_API() -} - -int32 mm_RandomLong(int32 lLow, int32 lHigh) -{ - META_ENGINE_HANDLE(int32, 0, FN_RANDOMLONG, pfnRandomLong, (lLow, lHigh)); - RETURN_API() -} - -float mm_RandomFloat(float flLow, float flHigh) -{ - META_ENGINE_HANDLE(float, 0.0, FN_RANDOMFLOAT, pfnRandomFloat, (flLow, flHigh)); - RETURN_API() -} - -void mm_SetView(const edict_t *pClient, const edict_t *pViewent) -{ - META_ENGINE_HANDLE_void(FN_SETVIEW, pfnSetView, (pClient, pViewent)); - RETURN_API_void() -} - -float mm_Time() -{ - META_ENGINE_HANDLE(float, 0.0, FN_TIME, pfnTime, ()); - RETURN_API() -} - -void mm_CrosshairAngle(const edict_t *pClient, float pitch, float yaw) -{ - META_ENGINE_HANDLE_void(FN_CROSSHAIRANGLE, pfnCrosshairAngle, (pClient, pitch, yaw)); - RETURN_API_void() -} - -byte *mm_LoadFileForMe(char *filename, int *pLength) -{ - META_ENGINE_HANDLE(byte *, NULL, FN_LOADFILEFORME, pfnLoadFileForMe, (filename, pLength)); - RETURN_API() -} - -void mm_FreeFile(void *buffer) -{ - META_ENGINE_HANDLE_void(FN_FREEFILE, pfnFreeFile, (buffer)); - RETURN_API_void() -} - -// trigger_endsection -void mm_EndSection(const char *pszSectionName) -{ - META_ENGINE_HANDLE_void(FN_ENDSECTION, pfnEndSection, (pszSectionName)); - RETURN_API_void() -} - -int mm_CompareFileTime(char *filename1, char *filename2, int *iCompare) -{ - META_ENGINE_HANDLE(int, 0, FN_COMPAREFILETIME, pfnCompareFileTime, (filename1, filename2, iCompare)); - RETURN_API() -} - -void mm_GetGameDir(char *szGetGameDir) -{ - META_ENGINE_HANDLE_void(FN_GETGAMEDIR, pfnGetGameDir, (szGetGameDir)); - RETURN_API_void() -} - -void mm_Cvar_RegisterVariable(cvar_t *variable) -{ - META_ENGINE_HANDLE_void(FN_CVAR_REGISTERVARIABLE, pfnCvar_RegisterVariable, (variable)); - RETURN_API_void() -} - -void mm_FadeClientVolume(const edict_t *pEdict, int fadePercent, int fadeOutSeconds, int holdTime, int fadeInSeconds) -{ - META_ENGINE_HANDLE_void(FN_FADECLIENTVOLUME, pfnFadeClientVolume, (pEdict, fadePercent, fadeOutSeconds, holdTime, fadeInSeconds)); - RETURN_API_void() -} - -void mm_SetClientMaxspeed(edict_t *pEdict, float fNewMaxspeed) -{ - META_ENGINE_HANDLE_void(FN_SETCLIENTMAXSPEED, pfnSetClientMaxspeed, (pEdict, fNewMaxspeed)); - RETURN_API_void() -} - -// returns NULL if fake client can't be created -edict_t *mm_CreateFakeClient(const char *netname) -{ - META_ENGINE_HANDLE(edict_t *, NULL, FN_CREATEFAKECLIENT, pfnCreateFakeClient, (netname)); - RETURN_API() -} - -void mm_RunPlayerMove(edict_t *fakeclient, const float *viewangles, float forwardmove, float sidemove, float upmove, unsigned short buttons, byte impulse, byte msec) -{ - META_ENGINE_HANDLE_void(FN_RUNPLAYERMOVE, pfnRunPlayerMove, (fakeclient, viewangles, forwardmove, sidemove, upmove, buttons, impulse, msec)); - RETURN_API_void() -} - -int mm_NumberOfEntities() -{ - META_ENGINE_HANDLE(int, 0, FN_NUMBEROFENTITIES, pfnNumberOfEntities, ()); - RETURN_API() -} - -// passing in NULL gets the serverinfo -char *mm_GetInfoKeyBuffer(edict_t *e) -{ - META_ENGINE_HANDLE(char *, NULL, FN_GETINFOKEYBUFFER, pfnGetInfoKeyBuffer, (e)); - RETURN_API() -} - -char *mm_InfoKeyValue(char *infobuffer, const char *key) -{ - META_ENGINE_HANDLE(char *, NULL, FN_INFOKEYVALUE, pfnInfoKeyValue, (infobuffer, key)); - RETURN_API() -} - -void mm_SetKeyValue(char *infobuffer, const char *key, const char *value) -{ - META_ENGINE_HANDLE_void(FN_SETKEYVALUE, pfnSetKeyValue, (infobuffer, key, value)); - RETURN_API_void() -} - -void mm_SetClientKeyValue(int clientIndex, char *infobuffer, const char *key, const char *value) -{ - META_ENGINE_HANDLE_void(FN_SETCLIENTKEYVALUE, pfnSetClientKeyValue, (clientIndex, infobuffer, key, value)); - RETURN_API_void() -} - -int mm_IsMapValid(char *filename) -{ - META_ENGINE_HANDLE(int, 0, FN_ISMAPVALID, pfnIsMapValid, (filename)); - RETURN_API() -} - -void mm_StaticDecal(const float *origin, int decalIndex, int entityIndex, int modelIndex) -{ - META_ENGINE_HANDLE_void(FN_STATICDECAL, pfnStaticDecal, (origin, decalIndex, entityIndex, modelIndex)); - RETURN_API_void() -} - -int mm_PrecacheGeneric(char *s) -{ - META_ENGINE_HANDLE(int, 0, FN_PRECACHEGENERIC, pfnPrecacheGeneric, (s)); - RETURN_API() -} - -// returns the server assigned userid for this player. useful for logging frags, etc. returns -1 if the edict couldn't be found in the list of clients -int mm_GetPlayerUserId(edict_t *e) -{ - META_ENGINE_HANDLE(int, 0, FN_GETPLAYERUSERID, pfnGetPlayerUserId, (e)); - RETURN_API() -} - -void mm_BuildSoundMsg(edict_t *entity, int channel, const char *sample, /*int*/float volume, float attenuation, int fFlags, int pitch, int msg_dest, int msg_type, const float *pOrigin, edict_t *ed) -{ - META_ENGINE_HANDLE_void(FN_BUILDSOUNDMSG, pfnBuildSoundMsg, (entity, channel, sample, volume, attenuation, fFlags, pitch, msg_dest, msg_type, pOrigin, ed)); - RETURN_API_void() -} - -// is this a dedicated server? -int mm_IsDedicatedServer() -{ - META_ENGINE_HANDLE(int, 0, FN_ISDEDICATEDSERVER, pfnIsDedicatedServer, ()); - RETURN_API() -} - -cvar_t *mm_CVarGetPointer(const char *szVarName) -{ - META_ENGINE_HANDLE(cvar_t *, NULL, FN_CVARGETPOINTER, pfnCVarGetPointer, (szVarName)); - RETURN_API() -} - -// returns the server assigned WONid for this player. useful for logging frags, etc. returns -1 if the edict couldn't be found in the list of clients -unsigned int mm_GetPlayerWONId(edict_t *e) -{ - META_ENGINE_HANDLE(unsigned int, 0, FN_GETPLAYERWONID, pfnGetPlayerWONId, (e)); - RETURN_API() -} - -// YWB 8/1/99 TFF Physics additions -void mm_Info_RemoveKey(char *s, const char *key) -{ - META_ENGINE_HANDLE_void(FN_INFO_REMOVEKEY, pfnInfo_RemoveKey, (s, key)); - RETURN_API_void() -} - -const char *mm_GetPhysicsKeyValue(const edict_t *pClient, const char *key) -{ - META_ENGINE_HANDLE(const char *, NULL, FN_GETPHYSICSKEYVALUE, pfnGetPhysicsKeyValue, (pClient, key)); - RETURN_API() -} - -void mm_SetPhysicsKeyValue(const edict_t *pClient, const char *key, const char *value) -{ - META_ENGINE_HANDLE_void(FN_SETPHYSICSKEYVALUE, pfnSetPhysicsKeyValue, (pClient, key, value)); - RETURN_API_void() -} - -const char *mm_GetPhysicsInfoString(const edict_t *pClient) -{ - META_ENGINE_HANDLE(const char *, NULL, FN_GETPHYSICSINFOSTRING, pfnGetPhysicsInfoString, (pClient)); - RETURN_API() -} - -unsigned short mm_PrecacheEvent(int type, const char *psz) -{ - META_ENGINE_HANDLE(unsigned short, 0, FN_PRECACHEEVENT, pfnPrecacheEvent, (type, psz)); - RETURN_API() -} - -void mm_PlaybackEvent(int flags, const edict_t *pInvoker, unsigned short eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2) -{ - META_ENGINE_HANDLE_void(FN_PLAYBACKEVENT, pfnPlaybackEvent, (flags, pInvoker, eventindex, delay, origin, angles, fparam1, fparam2, iparam1, iparam2, bparam1, bparam2)); - RETURN_API_void() -} - -unsigned char *mm_SetFatPVS(float *org) -{ - META_ENGINE_HANDLE(unsigned char *, 0, FN_SETFATPVS, pfnSetFatPVS, (org)); - RETURN_API() -} - -unsigned char *mm_SetFatPAS(float *org) -{ - META_ENGINE_HANDLE(unsigned char *, 0, FN_SETFATPAS, pfnSetFatPAS, (org)); - RETURN_API() -} - -int mm_CheckVisibility(edict_t *entity, unsigned char *pset) -{ - META_ENGINE_HANDLE(int, 0, FN_CHECKVISIBILITY, pfnCheckVisibility, (entity, pset)); - RETURN_API() -} - -void mm_DeltaSetField(struct delta_s *pFields, const char *fieldname) -{ - META_ENGINE_HANDLE_void(FN_DELTASETFIELD, pfnDeltaSetField, (pFields, fieldname)); - RETURN_API_void() -} - -void mm_DeltaUnsetField(struct delta_s *pFields, const char *fieldname) -{ - META_ENGINE_HANDLE_void(FN_DELTAUNSETFIELD, pfnDeltaUnsetField, (pFields, fieldname)); - RETURN_API_void() -} - -void mm_DeltaAddEncoder(char *name, void (*conditionalencode)(struct delta_s *pFields, const unsigned char *from, const unsigned char *to)) -{ - META_ENGINE_HANDLE_void(FN_DELTAADDENCODER, pfnDeltaAddEncoder, (name, conditionalencode)); - RETURN_API_void() -} - -int mm_GetCurrentPlayer() -{ - META_ENGINE_HANDLE(int, 0, FN_GETCURRENTPLAYER, pfnGetCurrentPlayer, ()); - RETURN_API() -} - -int mm_CanSkipPlayer(const edict_t *player) -{ - META_ENGINE_HANDLE(int, 0, FN_CANSKIPPLAYER, pfnCanSkipPlayer, (player)); - RETURN_API() -} - -int mm_DeltaFindField(struct delta_s *pFields, const char *fieldname) -{ - META_ENGINE_HANDLE(int, 0, FN_DELTAFINDFIELD, pfnDeltaFindField, (pFields, fieldname)); - RETURN_API() -} - -void mm_DeltaSetFieldByIndex(struct delta_s *pFields, int fieldNumber) -{ - META_ENGINE_HANDLE_void(FN_DELTASETFIELDBYINDEX, pfnDeltaSetFieldByIndex, (pFields, fieldNumber)); - RETURN_API_void() -} - -void mm_DeltaUnsetFieldByIndex(struct delta_s *pFields, int fieldNumber) -{ - META_ENGINE_HANDLE_void(FN_DELTAUNSETFIELDBYINDEX, pfnDeltaUnsetFieldByIndex, (pFields, fieldNumber)); - RETURN_API_void() -} - -void mm_SetGroupMask(int mask, int op) -{ - META_ENGINE_HANDLE_void(FN_SETGROUPMASK, pfnSetGroupMask, (mask, op)); - RETURN_API_void() -} - -int mm_engCreateInstancedBaseline(int classname, struct entity_state_s *baseline) -{ - META_ENGINE_HANDLE(int, 0, FN_CREATEINSTANCEDBASELINE, pfnCreateInstancedBaseline, (classname, baseline)); - RETURN_API() -} - -void mm_Cvar_DirectSet(struct cvar_s *var, const char *value) -{ - META_ENGINE_HANDLE_void(FN_CVAR_DIRECTSET, pfnCvar_DirectSet, (var, value)); - RETURN_API_void() -} - -// Forces the client and server to be running with the same version of the specified file (e.g., a player model). -// Calling this has no effect in single player -void mm_ForceUnmodified(FORCE_TYPE type, float *mins, float *maxs, const char *filename) -{ - META_ENGINE_HANDLE_void(FN_FORCEUNMODIFIED, pfnForceUnmodified, (type, mins, maxs, filename)); - RETURN_API_void() -} - -void mm_GetPlayerStats(const edict_t *pClient, int *ping, int *packet_loss) -{ - META_ENGINE_HANDLE_void(FN_GETPLAYERSTATS, pfnGetPlayerStats, (pClient, ping, packet_loss)); - RETURN_API_void() -} - -void mm_AddServerCommand(char *cmd_name, void (*function)()) -{ - META_ENGINE_HANDLE_void(FN_ADDSERVERCOMMAND, pfnAddServerCommand, (cmd_name, function)); - RETURN_API_void() -} - -// For voice communications, set which clients hear eachother. -// NOTE: these functions take player entity indices (starting at 1). -qboolean mm_Voice_GetClientListening(int iReceiver, int iSender) -{ - META_ENGINE_HANDLE(qboolean, false, FN_VOICE_GETCLIENTLISTENING, pfnVoice_GetClientListening, (iReceiver, iSender)); - RETURN_API() -} - -qboolean mm_Voice_SetClientListening(int iReceiver, int iSender, qboolean bListen) -{ - META_ENGINE_HANDLE(qboolean, false, FN_VOICE_SETCLIENTLISTENING, pfnVoice_SetClientListening, (iReceiver, iSender, bListen)); - RETURN_API() -} - -const char *mm_GetPlayerAuthId(edict_t *e) -{ - META_ENGINE_HANDLE(const char *, NULL, FN_GETPLAYERAUTHID, pfnGetPlayerAuthId, (e)); - RETURN_API() -} - -sequenceEntry_s *mm_SequenceGet(const char *fileName, const char *entryName) -{ - META_ENGINE_HANDLE(sequenceEntry_s *, NULL, FN_SEQUENCEGET, pfnSequenceGet, (fileName, entryName)); - RETURN_API() -} - -sentenceEntry_s *mm_SequencePickSentence(const char *groupName, int pickMethod, int *picked) -{ - META_ENGINE_HANDLE(sentenceEntry_s *, NULL, FN_SEQUENCEPICKSENTENCE, pfnSequencePickSentence, (groupName, pickMethod, picked)); - RETURN_API() -} - -int mm_GetFileSize(char *filename) -{ - META_ENGINE_HANDLE(int, 0, FN_GETFILESIZE, pfnGetFileSize, (filename)); - RETURN_API() -} - -unsigned int mm_GetApproxWavePlayLen(const char *filepath) -{ - META_ENGINE_HANDLE(unsigned int, 0, FN_GETAPPROXWAVEPLAYLEN, pfnGetApproxWavePlayLen, (filepath)); - RETURN_API() -} - -int mm_IsCareerMatch() -{ - META_ENGINE_HANDLE(int, 0, FN_ISCAREERMATCH, pfnIsCareerMatch, ()); - RETURN_API() -} - -int mm_GetLocalizedStringLength(const char *label) -{ - META_ENGINE_HANDLE(int, 0, FN_GETLOCALIZEDSTRINGLENGTH, pfnGetLocalizedStringLength, (label)); - RETURN_API() -} - -void mm_RegisterTutorMessageShown(int mid) -{ - META_ENGINE_HANDLE_void(FN_REGISTERTUTORMESSAGESHOWN, pfnRegisterTutorMessageShown, (mid)); - RETURN_API_void() -} - -int mm_GetTimesTutorMessageShown(int mid) -{ - META_ENGINE_HANDLE(int, 0, FN_GETTIMESTUTORMESSAGESHOWN, pfnGetTimesTutorMessageShown, (mid)); - RETURN_API() -} - -void mm_ProcessTutorMessageDecayBuffer(int *buffer, int bufferLength) -{ - META_ENGINE_HANDLE_void(FN_PROCESSTUTORMESSAGEDECAYBUFFER, pfnProcessTutorMessageDecayBuffer, (buffer, bufferLength)); - RETURN_API_void() -} - -void mm_ConstructTutorMessageDecayBuffer(int *buffer, int bufferLength) -{ - META_ENGINE_HANDLE_void(FN_CONSTRUCTTUTORMESSAGEDECAYBUFFER, pfnConstructTutorMessageDecayBuffer, (buffer, bufferLength)); - RETURN_API_void() -} - -void mm_ResetTutorMessageDecayData() -{ - META_ENGINE_HANDLE_void(FN_RESETTUTORMESSAGEDECAYDATA, pfnResetTutorMessageDecayData, ()); - RETURN_API_void() -} - -void mm_QueryClientCvarValue(const edict_t *pEdict, const char *cvarName) -{ - g_Players.set_player_cvar_query(pEdict, cvarName); - - META_ENGINE_HANDLE_void(FN_QUERYCLIENTCVARVALUE, pfnQueryClientCvarValue, (pEdict, cvarName)); - RETURN_API_void(); -} - -void mm_QueryClientCvarValue2(const edict_t *pEdict, const char *cvarName, int requestId) -{ - META_ENGINE_HANDLE_void(FN_QUERYCLIENTCVARVALUE2, pfnQueryClientCvarValue2, (pEdict, cvarName, requestId)); - RETURN_API_void(); -} - -int mm_EngCheckParm(const char *pchCmdLineToken, char **ppnext) -{ - META_ENGINE_HANDLE(int, 0, FN_CHECKPARM, pfnEngCheckParm, (pchCmdLineToken, ppnext)); - RETURN_API(); -} - -enginefuncs_t _engfuncs = -{ - &mm_PrecacheModel, // pfnPrecacheModel() - &mm_PrecacheSound, // pfnPrecacheSound() - &mm_SetModel, // pfnSetModel() - &mm_ModelIndex, // pfnModelIndex() - &mm_ModelFrames, // pfnModelFrames() - - &mm_SetSize, // pfnSetSize() - &mm_ChangeLevel, // pfnChangeLevel() - &mm_GetSpawnParms, // pfnGetSpawnParms() - &mm_SaveSpawnParms, // pfnSaveSpawnParms() - - &mm_VecToYaw, // pfnVecToYaw() - &mm_VecToAngles, // pfnVecToAngles() - &mm_MoveToOrigin, // pfnMoveToOrigin() - &mm_ChangeYaw, // pfnChangeYaw() - &mm_ChangePitch, // pfnChangePitch() - - &mm_FindEntityByString, // pfnFindEntityByString() - &mm_GetEntityIllum, // pfnGetEntityIllum() - &mm_FindEntityInSphere, // pfnFindEntityInSphere() - &mm_FindClientInPVS, // pfnFindClientInPVS() - &mm_EntitiesInPVS, // pfnEntitiesInPVS() - - &mm_MakeVectors, // pfnMakeVectors() - &mm_AngleVectors, // pfnAngleVectors() - - &mm_CreateEntity, // pfnCreateEntity() - &mm_RemoveEntity, // pfnRemoveEntity() - &mm_CreateNamedEntity, // pfnCreateNamedEntity() - - &mm_MakeStatic, // pfnMakeStatic() - &mm_EntIsOnFloor, // pfnEntIsOnFloor() - &mm_DropToFloor, // pfnDropToFloor() - - &mm_WalkMove, // pfnWalkMove() - &mm_SetOrigin, // pfnSetOrigin() - - &mm_EmitSound, // pfnEmitSound() - &mm_EmitAmbientSound, // pfnEmitAmbientSound() - - &mm_TraceLine, // pfnTraceLine() - &mm_TraceToss, // pfnTraceToss() - &mm_TraceMonsterHull, // pfnTraceMonsterHull() - &mm_TraceHull, // pfnTraceHull() - &mm_TraceModel, // pfnTraceModel() - &mm_TraceTexture, // pfnTraceTexture() - &mm_TraceSphere, // pfnTraceSphere() - &mm_GetAimVector, // pfnGetAimVector() - - &mm_ServerCommand, // pfnServerCommand() - &mm_ServerExecute, // pfnServerExecute() - &mm_engClientCommand, // pfnClientCommand() // D'oh, ClientCommand in dllapi too. - - &mm_ParticleEffect, // pfnParticleEffect() - &mm_LightStyle, // pfnLightStyle() - &mm_DecalIndex, // pfnDecalIndex() - &mm_PointContents, // pfnPointContents() - - &mm_MessageBegin, // pfnMessageBegin() - &mm_MessageEnd, // pfnMessageEnd() - - &mm_WriteByte, // pfnWriteByte() - &mm_WriteChar, // pfnWriteChar() - &mm_WriteShort, // pfnWriteShort() - &mm_WriteLong, // pfnWriteLong() - &mm_WriteAngle, // pfnWriteAngle() - &mm_WriteCoord, // pfnWriteCoord() - &mm_WriteString, // pfnWriteString() - &mm_WriteEntity, // pfnWriteEntity() - - &mm_CVarRegister, // pfnCVarRegister() - &mm_CVarGetFloat, // pfnCVarGetFloat() - &mm_CVarGetString, // pfnCVarGetString() - &mm_CVarSetFloat, // pfnCVarSetFloat() - &mm_CVarSetString, // pfnCVarSetString() - - &mm_AlertMessage, // pfnAlertMessage() - &mm_EngineFprintf, // pfnEngineFprintf() - - &mm_PvAllocEntPrivateData, // pfnPvAllocEntPrivateData() - &mm_PvEntPrivateData, // pfnPvEntPrivateData() - &mm_FreeEntPrivateData, // pfnFreeEntPrivateData() - - &mm_SzFromIndex, // pfnSzFromIndex() - &mm_AllocString, // pfnAllocString() - - &mm_GetVarsOfEnt, // pfnGetVarsOfEnt() - &mm_PEntityOfEntOffset, // pfnPEntityOfEntOffset() - &mm_EntOffsetOfPEntity, // pfnEntOffsetOfPEntity() - &mm_IndexOfEdict, // pfnIndexOfEdict() - &mm_PEntityOfEntIndex, // pfnPEntityOfEntIndex() - &mm_FindEntityByVars, // pfnFindEntityByVars() - &mm_GetModelPtr, // pfnGetModelPtr() - - &mm_RegUserMsg, // pfnRegUserMsg() - - &mm_AnimationAutomove, // pfnAnimationAutomove() - &mm_GetBonePosition, // pfnGetBonePosition() - - &mm_FunctionFromName, // pfnFunctionFromName() - &mm_NameForFunction, // pfnNameForFunction() - - &mm_ClientPrintf, // pfnClientPrintf() // JOHN: engine callbacks so game DLL can print messages to individual clients - &mm_ServerPrint, // pfnServerPrint() - - &mm_Cmd_Args, // pfnCmd_Args() // these 3 added - &mm_Cmd_Argv, // pfnCmd_Argv() // so game DLL can easily - &mm_Cmd_Argc, // pfnCmd_Argc() // access client 'cmd' strings - - &mm_GetAttachment, // pfnGetAttachment() - - &mm_CRC32_Init, // pfnCRC32_Init() - &mm_CRC32_ProcessBuffer, // pfnCRC32_ProcessBuffer() - &mm_CRC32_ProcessByte, // pfnCRC32_ProcessByte() - &mm_CRC32_Final, // pfnCRC32_Final() - - &mm_RandomLong, // pfnRandomLong() - &mm_RandomFloat, // pfnRandomFloat() - - &mm_SetView, // pfnSetView() - &mm_Time, // pfnTime() - &mm_CrosshairAngle, // pfnCrosshairAngle() - - &mm_LoadFileForMe, // pfnLoadFileForMe() - &mm_FreeFile, // pfnFreeFile() - - &mm_EndSection, // pfnEndSection() // trigger_endsection - &mm_CompareFileTime, // pfnCompareFileTime() - &mm_GetGameDir, // pfnGetGameDir() - &mm_Cvar_RegisterVariable, // pfnCvar_RegisterVariable() - &mm_FadeClientVolume, // pfnFadeClientVolume() - &mm_SetClientMaxspeed, // pfnSetClientMaxspeed() - &mm_CreateFakeClient, // pfnCreateFakeClient() // returns NULL if fake client can't be created - &mm_RunPlayerMove, // pfnRunPlayerMove() - &mm_NumberOfEntities, // pfnNumberOfEntities() - - &mm_GetInfoKeyBuffer, // pfnGetInfoKeyBuffer() // passing in NULL gets the serverinfo - &mm_InfoKeyValue, // pfnInfoKeyValue() - &mm_SetKeyValue, // pfnSetKeyValue() - &mm_SetClientKeyValue, // pfnSetClientKeyValue() - - &mm_IsMapValid, // pfnIsMapValid() - &mm_StaticDecal, // pfnStaticDecal() - &mm_PrecacheGeneric, // pfnPrecacheGeneric() - &mm_GetPlayerUserId, // pfnGetPlayerUserId() // returns the server assigned userid for this player. - &mm_BuildSoundMsg, // pfnBuildSoundMsg() - &mm_IsDedicatedServer, // pfnIsDedicatedServer() // is this a dedicated server? - &mm_CVarGetPointer, // pfnCVarGetPointer() - &mm_GetPlayerWONId, // pfnGetPlayerWONId() // returns the server assigned WONid for this player. - - &mm_Info_RemoveKey, // pfnInfo_RemoveKey() - &mm_GetPhysicsKeyValue, // pfnGetPhysicsKeyValue() - &mm_SetPhysicsKeyValue, // pfnSetPhysicsKeyValue() - &mm_GetPhysicsInfoString, // pfnGetPhysicsInfoString() - &mm_PrecacheEvent, // pfnPrecacheEvent() - &mm_PlaybackEvent, // pfnPlaybackEvent() - - &mm_SetFatPVS, // pfnSetFatPVS() - &mm_SetFatPAS, // pfnSetFatPAS() - - &mm_CheckVisibility, // pfnCheckVisibility() - - &mm_DeltaSetField, // pfnDeltaSetField() - &mm_DeltaUnsetField, // pfnDeltaUnsetField() - &mm_DeltaAddEncoder, // pfnDeltaAddEncoder() - &mm_GetCurrentPlayer, // pfnGetCurrentPlayer() - &mm_CanSkipPlayer, // pfnCanSkipPlayer() - &mm_DeltaFindField, // pfnDeltaFindField() - &mm_DeltaSetFieldByIndex, // pfnDeltaSetFieldByIndex() - &mm_DeltaUnsetFieldByIndex, // pfnDeltaUnsetFieldByIndex() - - &mm_SetGroupMask, // pfnSetGroupMask() - - &mm_engCreateInstancedBaseline, // pfnCreateInstancedBaseline() // D'oh, CreateInstancedBaseline in dllapi too. - &mm_Cvar_DirectSet, // pfnCvar_DirectSet() - - &mm_ForceUnmodified, // pfnForceUnmodified() - - &mm_GetPlayerStats, // pfnGetPlayerStats() - - &mm_AddServerCommand, // pfnAddServerCommand() - - &mm_Voice_GetClientListening, // pfnVoice_GetClientListening() - &mm_Voice_SetClientListening, // pfnVoice_SetClientListening() - - &mm_GetPlayerAuthId, // pfnGetPlayerAuthId() - - &mm_SequenceGet, // pfnSequenceGet() - &mm_SequencePickSentence, // pfnSequencePickSentence() - &mm_GetFileSize, // pfnGetFileSize() - &mm_GetApproxWavePlayLen, // pfnGetApproxWavePlayLen() - &mm_IsCareerMatch, // pfnIsCareerMatch() - &mm_GetLocalizedStringLength, // pfnGetLocalizedStringLength() - &mm_RegisterTutorMessageShown, // pfnRegisterTutorMessageShown() - &mm_GetTimesTutorMessageShown, // pfnGetTimesTutorMessageShown() - &mm_ProcessTutorMessageDecayBuffer, // pfnProcessTutorMessageDecayBuffer() - &mm_ConstructTutorMessageDecayBuffer, // pfnConstructTutorMessageDecayBuffer() - &mm_ResetTutorMessageDecayData, // pfnResetTutorMessageDecayData() - - &mm_QueryClientCvarValue, // pfnQueryClientCvarValue() - &mm_QueryClientCvarValue2, // pfnQueryClientCvarValue2() - &mm_EngCheckParm // pfnCheckParm() + CDATA_ENG(pfnCreateEntity), // pfnCreateEntity() + CDATA_ENG(pfnRemoveEntity), // pfnRemoveEntity() + CDATA_ENG(pfnCreateNamedEntity), // pfnCreateNamedEntity() + + CDATA_ENG(pfnMakeStatic), // pfnMakeStatic() + CDATA_ENG(pfnEntIsOnFloor), // pfnEntIsOnFloor() + CDATA_ENG(pfnDropToFloor), // pfnDropToFloor() + + CDATA_ENG(pfnWalkMove), // pfnWalkMove() + CDATA_ENG(pfnSetOrigin), // pfnSetOrigin() + + CDATA_ENG(pfnEmitSound), // pfnEmitSound() + CDATA_ENG(pfnEmitAmbientSound), // pfnEmitAmbientSound() + + CDATA_ENG(pfnTraceLine), // pfnTraceLine() + CDATA_ENG(pfnTraceToss), // pfnTraceToss() + CDATA_ENG(pfnTraceMonsterHull), // pfnTraceMonsterHull() + CDATA_ENG(pfnTraceHull), // pfnTraceHull() + CDATA_ENG(pfnTraceModel), // pfnTraceModel() + CDATA_ENG(pfnTraceTexture), // pfnTraceTexture() + CDATA_ENG(pfnTraceSphere), // pfnTraceSphere() + CDATA_ENG(pfnGetAimVector), // pfnGetAimVector() + + CDATA_ENG(pfnServerCommand), // pfnServerCommand() + CDATA_ENG(pfnServerExecute), // pfnServerExecute() + CDATA_ENG(pfnClientCommand), // pfnClientCommand() // D'oh, ClientCommand in dllapi too. + + CDATA_ENG(pfnParticleEffect), // pfnParticleEffect() + CDATA_ENG(pfnLightStyle), // pfnLightStyle() + CDATA_ENG(pfnDecalIndex), // pfnDecalIndex() + CDATA_ENG(pfnPointContents), // pfnPointContents() + + CDATA_ENG(pfnMessageBegin), // pfnMessageBegin() + CDATA_ENG(pfnMessageEnd), // pfnMessageEnd() + + CDATA_ENG(pfnWriteByte), // pfnWriteByte() + CDATA_ENG(pfnWriteChar), // pfnWriteChar() + CDATA_ENG(pfnWriteShort), // pfnWriteShort() + CDATA_ENG(pfnWriteLong), // pfnWriteLong() + CDATA_ENG(pfnWriteAngle), // pfnWriteAngle() + CDATA_ENG(pfnWriteCoord), // pfnWriteCoord() + CDATA_ENG(pfnWriteString), // pfnWriteString() + CDATA_ENG(pfnWriteEntity), // pfnWriteEntity() + + CDATA_ENG(pfnCVarRegister), // pfnCVarRegister() + CDATA_ENG(pfnCVarGetFloat), // pfnCVarGetFloat() + CDATA_ENG(pfnCVarGetString), // pfnCVarGetString() + CDATA_ENG(pfnCVarSetFloat), // pfnCVarSetFloat() + CDATA_ENG(pfnCVarSetString), // pfnCVarSetString() + + CDATA_ENG(pfnAlertMessage), // pfnAlertMessage() + CDATA_ENG(pfnEngineFprintf), // pfnEngineFprintf() + + CDATA_ENG(pfnPvAllocEntPrivateData), // pfnPvAllocEntPrivateData() + CDATA_ENG(pfnPvEntPrivateData), // pfnPvEntPrivateData() + CDATA_ENG(pfnFreeEntPrivateData), // pfnFreeEntPrivateData() + + CDATA_ENG(pfnSzFromIndex), // pfnSzFromIndex() + CDATA_ENG(pfnAllocString), // pfnAllocString() + + CDATA_ENG(pfnGetVarsOfEnt), // pfnGetVarsOfEnt() + CDATA_ENG(pfnPEntityOfEntOffset), // pfnPEntityOfEntOffset() + CDATA_ENG(pfnEntOffsetOfPEntity), // pfnEntOffsetOfPEntity() + CDATA_ENG(pfnIndexOfEdict), // pfnIndexOfEdict() + CDATA_ENG(pfnPEntityOfEntIndex), // pfnPEntityOfEntIndex() + CDATA_ENG(pfnFindEntityByVars), // pfnFindEntityByVars() + CDATA_ENG(pfnGetModelPtr), // pfnGetModelPtr() + + CDATA_ENG_H(pfnRegUserMsg, P_POST, mm_RegUserMsg), // pfnRegUserMsg() + + CDATA_ENG(pfnAnimationAutomove), // pfnAnimationAutomove() + CDATA_ENG(pfnGetBonePosition), // pfnGetBonePosition() + + CDATA_ENG(pfnFunctionFromName), // pfnFunctionFromName() + CDATA_ENG(pfnNameForFunction), // pfnNameForFunction() + + CDATA_ENG(pfnClientPrintf), // pfnClientPrintf() // JOHN: engine callbacks so game DLL can print messages to individual clients + CDATA_ENG(pfnServerPrint), // pfnServerPrint() + + CDATA_ENG(pfnCmd_Args), // pfnCmd_Args() // these 3 added + CDATA_ENG(pfnCmd_Argv), // pfnCmd_Argv() // so game DLL can easily + CDATA_ENG(pfnCmd_Argc), // pfnCmd_Argc() // access client 'cmd' strings + + CDATA_ENG(pfnGetAttachment), // pfnGetAttachment() + + CDATA_ENG(pfnCRC32_Init), // pfnCRC32_Init() + CDATA_ENG(pfnCRC32_ProcessBuffer), // pfnCRC32_ProcessBuffer() + CDATA_ENG(pfnCRC32_ProcessByte), // pfnCRC32_ProcessByte() + CDATA_ENG(pfnCRC32_Final), // pfnCRC32_Final() + + CDATA_ENG(pfnRandomLong), // pfnRandomLong() + CDATA_ENG(pfnRandomFloat), // pfnRandomFloat() + + CDATA_ENG(pfnSetView), // pfnSetView() + CDATA_ENG(pfnTime), // pfnTime() + CDATA_ENG(pfnCrosshairAngle), // pfnCrosshairAngle() + + CDATA_ENG(pfnLoadFileForMe), // pfnLoadFileForMe() + CDATA_ENG(pfnFreeFile), // pfnFreeFile() + + CDATA_ENG(pfnEndSection), // pfnEndSection() // trigger_endsection + CDATA_ENG(pfnCompareFileTime), // pfnCompareFileTime() + CDATA_ENG(pfnGetGameDir), // pfnGetGameDir() + CDATA_ENG(pfnCvar_RegisterVariable), // pfnCvar_RegisterVariable() + CDATA_ENG(pfnFadeClientVolume), // pfnFadeClientVolume() + CDATA_ENG(pfnSetClientMaxspeed), // pfnSetClientMaxspeed() + CDATA_ENG(pfnCreateFakeClient), // pfnCreateFakeClient() // returns NULL if fake client can't be created + CDATA_ENG(pfnRunPlayerMove), // pfnRunPlayerMove() + CDATA_ENG(pfnNumberOfEntities), // pfnNumberOfEntities() + + CDATA_ENG(pfnGetInfoKeyBuffer), // pfnGetInfoKeyBuffer() // passing in NULL gets the serverinfo + CDATA_ENG(pfnInfoKeyValue), // pfnInfoKeyValue() + CDATA_ENG(pfnSetKeyValue), // pfnSetKeyValue() + CDATA_ENG(pfnSetClientKeyValue), // pfnSetClientKeyValue() + + CDATA_ENG(pfnIsMapValid), // pfnIsMapValid() + CDATA_ENG(pfnStaticDecal), // pfnStaticDecal() + CDATA_ENG(pfnPrecacheGeneric), // pfnPrecacheGeneric() + CDATA_ENG(pfnGetPlayerUserId), // pfnGetPlayerUserId() // returns the server assigned userid for this player. + CDATA_ENG(pfnBuildSoundMsg), // pfnBuildSoundMsg() + CDATA_ENG(pfnIsDedicatedServer), // pfnIsDedicatedServer() // is this a dedicated server? + CDATA_ENG(pfnCVarGetPointer), // pfnCVarGetPointer() + CDATA_ENG(pfnGetPlayerWONId), // pfnGetPlayerWONId() // returns the server assigned WONid for this player. + + CDATA_ENG(pfnInfo_RemoveKey), // pfnInfo_RemoveKey() + CDATA_ENG(pfnGetPhysicsKeyValue), // pfnGetPhysicsKeyValue() + CDATA_ENG(pfnSetPhysicsKeyValue), // pfnSetPhysicsKeyValue() + CDATA_ENG(pfnGetPhysicsInfoString), // pfnGetPhysicsInfoString() + CDATA_ENG(pfnPrecacheEvent), // pfnPrecacheEvent() + CDATA_ENG(pfnPlaybackEvent), // pfnPlaybackEvent() + + CDATA_ENG(pfnSetFatPVS), // pfnSetFatPVS() + CDATA_ENG(pfnSetFatPAS), // pfnSetFatPAS() + + CDATA_ENG(pfnCheckVisibility), // pfnCheckVisibility() + + CDATA_ENG(pfnDeltaSetField), // pfnDeltaSetField() + CDATA_ENG(pfnDeltaUnsetField), // pfnDeltaUnsetField() + CDATA_ENG(pfnDeltaAddEncoder), // pfnDeltaAddEncoder() + CDATA_ENG(pfnGetCurrentPlayer), // pfnGetCurrentPlayer() + CDATA_ENG(pfnCanSkipPlayer), // pfnCanSkipPlayer() + CDATA_ENG(pfnDeltaFindField), // pfnDeltaFindField() + CDATA_ENG(pfnDeltaSetFieldByIndex), // pfnDeltaSetFieldByIndex() + CDATA_ENG(pfnDeltaUnsetFieldByIndex), // pfnDeltaUnsetFieldByIndex() + + CDATA_ENG(pfnSetGroupMask), // pfnSetGroupMask() + + CDATA_ENG(pfnCreateInstancedBaseline), // pfnCreateInstancedBaseline() // D'oh, CreateInstancedBaseline in dllapi too. + CDATA_ENG(pfnCvar_DirectSet), // pfnCvar_DirectSet() + + CDATA_ENG(pfnForceUnmodified), // pfnForceUnmodified() + + CDATA_ENG(pfnGetPlayerStats), // pfnGetPlayerStats() + + CDATA_ENG(pfnAddServerCommand), // pfnAddServerCommand() + + CDATA_ENG(pfnVoice_GetClientListening), // pfnVoice_GetClientListening() + CDATA_ENG(pfnVoice_SetClientListening), // pfnVoice_SetClientListening() + + CDATA_ENG(pfnGetPlayerAuthId), // pfnGetPlayerAuthId() + + CDATA_ENG(pfnSequenceGet), // pfnSequenceGet() + CDATA_ENG(pfnSequencePickSentence), // pfnSequencePickSentence() + CDATA_ENG(pfnGetFileSize), // pfnGetFileSize() + CDATA_ENG(pfnGetApproxWavePlayLen), // pfnGetApproxWavePlayLen() + CDATA_ENG(pfnIsCareerMatch), // pfnIsCareerMatch() + CDATA_ENG(pfnGetLocalizedStringLength), // pfnGetLocalizedStringLength() + CDATA_ENG(pfnRegisterTutorMessageShown), // pfnRegisterTutorMessageShown() + CDATA_ENG(pfnGetTimesTutorMessageShown), // pfnGetTimesTutorMessageShown() + CDATA_ENG(pfnProcessTutorMessageDecayBuffer), // pfnProcessTutorMessageDecayBuffer() + CDATA_ENG(pfnConstructTutorMessageDecayBuffer), // pfnConstructTutorMessageDecayBuffer() + CDATA_ENG(pfnResetTutorMessageDecayData), // pfnResetTutorMessageDecayData() + + CDATA_ENG_H(pfnQueryClientCvarValue, P_PRE, mm_QueryClientCvarValue), // pfnQueryClientCvarValue() + CDATA_ENG(pfnQueryClientCvarValue2), // pfnQueryClientCvarValue2() + CDATA_ENG(pfnEngCheckParm) // pfnCheckParm()*/ }; -meta_enginefuncs_t meta_engfuncs(&_engfuncs); +void compile_engfuncs_callbacks() +{ + jitdata_t jitdata; + jitdata.plugins = g_plugins ? g_plugins->plist : nullptr; + jitdata.plugins_count = g_plugins ? g_plugins->endlist : 0; + jitdata.table_offset = offsetof(MPlugin, engine_table); + jitdata.post_table_offset = offsetof(MPlugin, engine_post_table); + + for (auto& cd : g_engfuncs_cdata) { + jitdata.pfn_original = *(size_t *)(size_t(&g_engfuncs) + cd.offset); + jitdata.args_count = cd.args_count; + jitdata.has_ret = cd.has_ret; + jitdata.has_varargs = cd.has_varargs; + jitdata.pfn_offset = cd.offset; + jitdata.mm_hook_time = cd.mm_hook_time; + jitdata.mm_hook = cd.mm_hook; + + *(size_t *)(size_t(&meta_engfuncs_jit) + cd.offset) = g_jit.compile_callback(&jitdata); + } +} + +void compile_engine_tramps() +{ + // we compile simple static functions that will call dynamic callbacks + for (auto& cd : g_engfuncs_cdata) { + *(size_t *)(size_t(&meta_engfuncs) + cd.offset) = g_jit.compile_tramp(size_t(&meta_engfuncs_jit) + cd.offset/*, cd.mm_hook, cd.mm_hook_time*/); + } +} + +void compile_engine_callbacks() +{ + static bool initialized = false; + + if (!initialized) { + compile_engine_tramps(); + initialized = true; + } + + compile_engfuncs_callbacks(); +} diff --git a/metamod/src/engine_api.h b/metamod/src/engine_api.h index a805384..702cb7d 100644 --- a/metamod/src/engine_api.h +++ b/metamod/src/engine_api.h @@ -18,359 +18,4 @@ typedef int (*GET_ENGINE_FUNCTIONS_FN)(enginefuncs_t *pengfuncsFromEngine, int * extern enginefuncs_t meta_engfuncs; #endif -extern int mm_PrecacheModel(const char *s); -extern int mm_PrecacheSound(const char *s); -extern void mm_SetModel(edict_t *e, const char *m); -extern int mm_ModelIndex(const char *m); -extern int mm_ModelFrames(int modelIndex); - -extern void mm_SetSize(edict_t *e, const float *rgflMin, const float *rgflMax); -extern void mm_ChangeLevel(const char *s1, const char *s2); -extern void mm_GetSpawnParms(edict_t *ent); -extern void mm_SaveSpawnParms(edict_t *ent); - -extern float mm_VecToYaw(const float *rgflVector); -extern void mm_VecToAngles(const float *rgflVectorIn, float *rgflVectorOut); -extern void mm_MoveToOrigin(edict_t *ent, const float *pflGoal, float dist, int iMoveType); -extern void mm_ChangeYaw(edict_t *ent); -extern void mm_ChangePitch(edict_t *ent); - -extern edict_t *mm_FindEntityByString(edict_t *pEdictStartSearchAfter, const char *pszField, const char *pszValue); -extern int mm_GetEntityIllum(edict_t *pEnt); -extern edict_t *mm_FindEntityInSphere(edict_t *pEdictStartSearchAfter, const float *org, float rad); -extern edict_t *mm_FindClientInPVS(edict_t *pEdict); -extern edict_t *mm_EntitiesInPVS(edict_t *pplayer); - -extern void mm_MakeVectors(const float *rgflVector); -extern void mm_AngleVectors(const float *rgflVector, float *forward, float *right, float *up); - -extern edict_t *mm_CreateEntity(); -extern void mm_RemoveEntity(edict_t *e); -extern edict_t *mm_CreateNamedEntity(int className); - -extern void mm_MakeStatic(edict_t *ent); -extern int mm_EntIsOnFloor(edict_t *e); -extern int mm_DropToFloor(edict_t *e); - -extern int mm_WalkMove(edict_t *ent, float yaw, float dist, int iMode); -extern void mm_SetOrigin(edict_t *e, const float *rgflOrigin); - -extern void mm_EmitSound(edict_t *entity, int channel, const char *sample, /*int*/float volume, float attenuation, int fFlags, int pitch); -extern void mm_EmitAmbientSound(edict_t *entity, float *pos, const char *samp, float vol, float attenuation, int fFlags, int pitch); - -extern void mm_TraceLine(const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr); -extern void mm_TraceToss(edict_t *pent, edict_t *pentToIgnore, TraceResult *ptr); -extern int mm_TraceMonsterHull(edict_t *pEdict, const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr); -extern void mm_TraceHull(const float *v1, const float *v2, int fNoMonsters, int hullNumber, edict_t *pentToSkip, TraceResult *ptr); -extern void mm_TraceModel(const float *v1, const float *v2, int hullNumber, edict_t *pent, TraceResult *ptr); -extern const char *mm_TraceTexture(edict_t *pTextureEntity, const float *v1, const float *v2); -extern void mm_TraceSphere(const float *v1, const float *v2, int fNoMonsters, float radius, edict_t *pentToSkip, TraceResult *ptr); -extern void mm_GetAimVector(edict_t *ent, float speed, float *rgflReturn); - -extern void mm_ServerCommand(const char *str); -extern void mm_ServerExecute(); -extern void ClientCommand(edict_t *pEdict, const char *szFmt, ...); - -extern void mm_ParticleEffect(const float *org, const float *dir, float color, float count); -extern void mm_LightStyle(int style, const char *val); -extern int mm_DecalIndex(const char *name); -extern int mm_PointContents(const float *rgflVector); - -extern void mm_MessageBegin(int msg_dest, int msg_type, const float *pOrigin, edict_t *ed); -extern void mm_MessageEnd(); - -extern void mm_WriteByte(int iValue); -extern void mm_WriteChar(int iValue); -extern void mm_WriteShort(int iValue); -extern void mm_WriteLong(int iValue); -extern void mm_WriteAngle(float flValue); -extern void mm_WriteCoord(float flValue); -extern void mm_WriteString(const char *sz); -extern void mm_WriteEntity(int iValue); - -extern void mm_CVarRegister(cvar_t *pCvar); -extern float mm_CVarGetFloat(const char *szVarName); -extern const char *mm_CVarGetString(const char *szVarName); -extern void mm_CVarSetFloat(const char *szVarName, float flValue); -extern void mm_CVarSetString(const char *szVarName, const char *szValue); - -extern void mm_AlertMessage(ALERT_TYPE atype, const char *szFmt, ...); -extern void mm_EngineFprintf(void *pfile, const char *szFmt, ...); -extern void *mm_PvAllocEntPrivateData(edict_t *pEdict, int32 cb); -extern void *mm_PvEntPrivateData(edict_t *pEdict); -extern void mm_FreeEntPrivateData(edict_t *pEdict); - -extern const char *mm_SzFromIndex(int iString); -extern int mm_AllocString(const char *szValue); - -extern struct entvars_s *mm_GetVarsOfEnt(edict_t *pEdict); -extern edict_t *mm_PEntityOfEntOffset(int iEntOffset); -extern int mm_EntOffsetOfPEntity(const edict_t *pEdict); -extern int mm_IndexOfEdict(const edict_t *pEdict); -extern edict_t *mm_PEntityOfEntIndex(int iEntIndex); -extern edict_t *mm_FindEntityByVars(struct entvars_s *pvars); -extern void *mm_GetModelPtr(edict_t *pEdict); - -extern int mm_RegUserMsg(const char *pszName, int iSize); - -extern void mm_AnimationAutomove(const edict_t *pEdict, float flTime); -extern void mm_GetBonePosition(const edict_t *pEdict, int iBone, float *rgflOrigin, float *rgflAngles); - -extern uint32 mm_FunctionFromName(const char *pName); -extern const char *mm_NameForFunction(uint32 function); - -extern void mm_ClientPrintf(edict_t *pEdict, PRINT_TYPE ptype, const char *szMsg); //! JOHN: engine callbacks so game DLL can print messages to individual clients -extern void mm_ServerPrint(const char *szMsg); - -extern const char *mm_Cmd_Args(); //! these 3 added -extern const char *mm_Cmd_Argv(int argc); //! so game DLL can easily -extern int mm_Cmd_Argc(); //! access client 'cmd' strings - -extern void mm_GetAttachment(const edict_t *pEdict, int iAttachment, float *rgflOrigin, float *rgflAngles); - -extern void mm_CRC32_Init(CRC32_t *pulCRC); -extern void mm_CRC32_ProcessBuffer(CRC32_t *pulCRC, void *p, int len); -extern void mm_CRC32_ProcessByte(CRC32_t *pulCRC, unsigned char ch); -extern CRC32_t mm_CRC32_Final(CRC32_t pulCRC); - -extern int32 mm_RandomLong(int32 lLow, int32 lHigh); -extern float mm_RandomFloat(float flLow, float flHigh); - -extern void mm_SetView(const edict_t *pClient, const edict_t *pViewent); -extern float mm_Time(); -extern void mm_CrosshairAngle(const edict_t *pClient, float pitch, float yaw); - -extern byte *mm_LoadFileForMe(const char *filename, int *pLength); -extern void mm_FreeFile(void *buffer); - -extern void mm_EndSection(const char *pszSectionName); //! trigger_endsection -extern int mm_CompareFileTime(char *filename1, char *filename2, int *iCompare); -extern void mm_GetGameDir(char *szGetGameDir); -extern void mm_Cvar_RegisterVariable(cvar_t *variable); -extern void mm_FadeClientVolume(const edict_t *pEdict, int fadePercent, int fadeOutSeconds, int holdTime, int fadeInSeconds); -extern void mm_SetClientMaxspeed(const edict_t *pEdict, float fNewMaxspeed); -extern edict_t *mm_CreateFakeClient(const char *netname); //! returns NULL if fake client can't be created -extern void mm_RunPlayerMove(edict_t *fakeclient, const float *viewangles, float forwardmove, float sidemove, float upmove, unsigned short buttons, byte impulse, byte msec); -extern int mm_NumberOfEntities(); - -extern char *mm_GetInfoKeyBuffer(edict_t *e); //! passing in NULL gets the serverinfo -extern char *mm_InfoKeyValue(char *infobuffer, const char *key); -extern void mm_SetKeyValue(char *infobuffer, const char *key, const char *value); -extern void mm_SetClientKeyValue(int clientIndex, char *infobuffer, const char *key, const char *value); - -extern int mm_IsMapValid(char *filename); -extern void mm_StaticDecal(const float *origin, int decalIndex, int entityIndex, int modelIndex); -extern int mm_PrecacheGeneric(const char *s); -extern int mm_GetPlayerUserId(edict_t *e); //! returns the server assigned userid for this player. useful for logging frags, etc. returns -1 if the edict couldn't be found in the list of clients -extern void mm_BuildSoundMsg(edict_t *entity, int channel, const char *sample, /*int*/float volume, float attenuation, int fFlags, int pitch, int msg_dest, int msg_type, const float *pOrigin, edict_t *ed); -extern int mm_IsDedicatedServer();//! is this a dedicated server? -extern cvar_t *mm_CVarGetPointer(const char *szVarName); -extern unsigned int mm_GetPlayerWONId(edict_t *e); //! returns the server assigned WONid for this player. useful for logging frags, etc. returns -1 if the edict couldn't be found in the list of clients - -// 8/1/99 TFF Physics additions -extern void mm_Info_RemoveKey(char *s, const char *key); -extern const char *mm_GetPhysicsKeyValue(const edict_t *pClient, const char *key); -extern void mm_SetPhysicsKeyValue(const edict_t *pClient, const char *key, const char *value); -extern const char *mm_GetPhysicsInfoString(const edict_t *pClient); -extern unsigned short mm_PrecacheEvent(int type, const char *psz); -extern void mm_PlaybackEvent(int flags, const edict_t *pInvoker, unsigned short eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2); -extern unsigned char *mm_SetFatPVS(float *org); -extern unsigned char *mm_SetFatPAS(float *org); -extern int mm_CheckVisibility(edict_t *entity, unsigned char *pset); - -extern void mm_DeltaSetField(struct delta_s *pFields, const char *fieldname); -extern void mm_DeltaUnsetField(struct delta_s *pFields, const char *fieldname); -extern void mm_DeltaAddEncoder(const char *name, void (*conditionalencode)(struct delta_s *pFields, const unsigned char *from, const unsigned char *to)); -extern int mm_GetCurrentPlayer(); -extern int mm_CanSkipPlayer(const edict_t *player); -extern int mm_DeltaFindField(struct delta_s *pFields, const char *fieldname); -extern void mm_DeltaSetFieldByIndex(struct delta_s *pFields, int fieldNumber); -extern void mm_DeltaUnsetFieldByIndex(struct delta_s *pFields, int fieldNumber); -extern void mm_SetGroupMask(int mask, int op); -extern int CreateInstancedBaseline(int classname, struct entity_state_s *baseline); -extern void mm_Cvar_DirectSet(struct cvar_s *var, const char *value); - -// Forces the client and server to be running with the same version of the specified file e.g., a player model). -// Calling this has no effect in single player -extern void mm_ForceUnmodified(FORCE_TYPE type, float *mins, float *maxs, const char *filename); -extern void mm_GetPlayerStats(const edict_t *pClient, int *ping, int *packet_loss); - -extern void mm_AddServerCommand(const char *cmd_name, void (*function)()); -extern qboolean mm_Voice_GetClientListening(int iReceiver, int iSender); -extern qboolean mm_Voice_SetClientListening(int iReceiver, int iSender, qboolean bListen); -extern const char *mm_pfnGetPlayerAuthId(edict_t *e); -extern sequenceEntry_s *mm_SequenceGet(const char *fileName, const char *entryName); -extern sentenceEntry_s *mm_SequencePickSentence(const char *groupName, int pickMethod, int *picked); -extern int mm_GetFileSize(const char *filename); -extern unsigned int mm_GetApproxWavePlayLen(const char *filepath); -extern int mm_IsCareerMatch(); -extern int mm_GetLocalizedStringLength(const char *label); -extern void mm_RegisterTutorMessageShown(int mid); -extern int mm_GetTimesTutorMessageShown(int mid); -extern void mm_ProcessTutorMessageDecayBuffer(int *buffer, int bufferLength); -extern void mm_ConstructTutorMessageDecayBuffer(int *buffer, int bufferLength); -extern void mm_ResetTutorMessageDecayData(); - -extern void mm_QueryClientCvarValue(const edict_t *pEdict, const char *cvarName); //! Obsolete! Use mm_QueryClientCvarValue2 instead -extern void mm_QueryClientCvarValue2(const edict_t *pEdict, const char *cvarName, int requestID); -extern int mm_EngCheckParm(const char *pchCmdLineToken, char **ppnext); - -// Typedefs for the above functions: -typedef int (*FN_PRECACHEMODEL)(const char *s); -typedef int (*FN_PRECACHESOUND)(const char *s); -typedef void (*FN_SETMODEL)(edict_t *e, const char *m); -typedef int (*FN_MODELINDEX)(const char *m); -typedef int (*FN_MODELFRAMES)(int modelIndex); -typedef void (*FN_SETSIZE)(edict_t *e, const float *rgflMin, const float *rgflMax); -typedef void (*FN_CHANGELEVEL)(const char *s1, const char *s2); -typedef void (*FN_GETSPAWNPARMS)(edict_t *ent); -typedef void (*FN_SAVESPAWNPARMS)(edict_t *ent); -typedef float (*FN_VECTOYAW)(const float *rgflVector); -typedef void (*FN_VECTOANGLES)(const float *rgflVectorIn, float *rgflVectorOut); -typedef void (*FN_MOVETOORIGIN)(edict_t *ent, const float *pflGoal, float dist, int iMoveType); -typedef void (*FN_CHANGEYAW)(edict_t *ent); -typedef void (*FN_CHANGEPITCH)(edict_t *ent); -typedef edict_t *(*FN_FINDENTITYBYSTRING)(edict_t *pEdictStartSearchAfter, const char *pszField, const char *pszValue); -typedef int (*FN_GETENTITYILLUM)(edict_t *pEnt); -typedef edict_t *(*FN_FINDENTITYINSPHERE)(edict_t *pEdictStartSearchAfter, const float *org, float rad); -typedef edict_t *(*FN_FINDCLIENTINPVS)(edict_t *pEdict); -typedef edict_t *(*FN_ENTITIESINPVS)(edict_t *pplayer); -typedef void (*FN_MAKEVECTORS)(const float *rgflVector); -typedef void (*FN_ANGLEVECTORS)(const float *rgflVector, float *forward, float *right, float *up); -typedef edict_t *(*FN_CREATEENTITY)(); -typedef void (*FN_REMOVEENTITY)(edict_t *e); -typedef edict_t *(*FN_CREATENAMEDENTITY)(int className); -typedef void (*FN_MAKESTATIC)(edict_t *ent); -typedef int (*FN_ENTISONFLOOR)(edict_t *e); -typedef int (*FN_DROPTOFLOOR)(edict_t *e); -typedef int (*FN_WALKMOVE)(edict_t *ent, float yaw, float dist, int iMode); -typedef void (*FN_SETORIGIN)(edict_t *e, const float *rgflOrigin); -typedef void (*FN_EMITSOUND)(edict_t *entity, int channel, const char *sample, /*int*/float volume, float attenuation, int fFlags, int pitch); -typedef void (*FN_EMITAMBIENTSOUND)(edict_t *entity, float *pos, const char *samp, float vol, float attenuation, int fFlags, int pitch); -typedef void (*FN_TRACELINE)(const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr); -typedef void (*FN_TRACETOSS)(edict_t *pent, edict_t *pentToIgnore, TraceResult *ptr); -typedef int (*FN_TRACEMONSTERHULL)(edict_t *pEdict, const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr); -typedef void (*FN_TRACEHULL)(const float *v1, const float *v2, int fNoMonsters, int hullNumber, edict_t *pentToSkip, TraceResult *ptr); -typedef void (*FN_TRACEMODEL)(const float *v1, const float *v2, int hullNumber, edict_t *pent, TraceResult *ptr); -typedef const char *(*FN_TRACETEXTURE)(edict_t *pTextureEntity, const float *v1, const float *v2); -typedef void (*FN_TRACESPHERE)(const float *v1, const float *v2, int fNoMonsters, float radius, edict_t *pentToSkip, TraceResult *ptr); -typedef void (*FN_GETAIMVECTOR)(edict_t *ent, float speed, float *rgflReturn); -typedef void (*FN_SERVERCOMMAND)(char *str); -typedef void (*FN_SERVEREXECUTE)(); -typedef void (*FN_CLIENTCOMMAND_ENG)(edict_t *pEdict, char *szFmt, ...); -typedef void (*FN_PARTICLEEFFECT)(const float *org, const float *dir, float color, float count); -typedef void (*FN_LIGHTSTYLE)(int style, char *val); -typedef int (*FN_DECALINDEX)(const char *name); -typedef int (*FN_POINTCONTENTS)(const float *rgflVector); -typedef void (*FN_MESSAGEBEGIN)(int msg_dest, int msg_type, const float *pOrigin, edict_t *ed); -typedef void (*FN_MESSAGEEND)(); -typedef void (*FN_WRITEBYTE)(int iValue); -typedef void (*FN_WRITECHAR)(int iValue); -typedef void (*FN_WRITESHORT)(int iValue); -typedef void (*FN_WRITELONG)(int iValue); -typedef void (*FN_WRITEANGLE)(float flValue); -typedef void (*FN_WRITECOORD)(float flValue); -typedef void (*FN_WRITESTRING)(const char *sz); -typedef void (*FN_WRITEENTITY)(int iValue); -typedef void (*FN_CVARREGISTER)(cvar_t *pCvar); -typedef float (*FN_CVARGETFLOAT)(const char *szVarName); -typedef const char *(*FN_CVARGETSTRING)(const char *szVarName); -typedef void (*FN_CVARSETFLOAT)(const char *szVarName, float flValue); -typedef void (*FN_CVARSETSTRING)(const char *szVarName, const char *szValue); -typedef void (*FN_ALERTMESSAGE)(ALERT_TYPE atype, const char *szFmt, ...); -typedef void (*FN_ENGINEFPRINTF)(void *pfile, const char *szFmt, ...); -typedef void *(*FN_PVALLOCENTPRIVATEDATA)(edict_t *pEdict, int32 cb); -typedef void *(*FN_PVENTPRIVATEDATA)(edict_t *pEdict); -typedef void (*FN_FREEENTPRIVATEDATA)(edict_t *pEdict); -typedef const char *(*FN_SZFROMINDEX)(int iString); -typedef int (*FN_ALLOCSTRING)(const char *szValue); -typedef struct entvars_s *(*FN_GETVARSOFENT)(edict_t *pEdict); -typedef edict_t *(*FN_PENTITYOFENTOFFSET)(int iEntOffset); -typedef int (*FN_ENTOFFSETOFPENTITY)(const edict_t *pEdict); -typedef int (*FN_INDEXOFEDICT)(const edict_t *pEdict); -typedef edict_t *(*FN_PENTITYOFENTINDEX)(int iEntIndex); -typedef edict_t *(*FN_FINDENTITYBYVARS)(struct entvars_s *pvars); -typedef void *(*FN_GETMODELPTR)(edict_t *pEdict); -typedef int (*FN_REGUSERMSG)(const char *pszName, int iSize); -typedef void (*FN_ANIMATIONAUTOMOVE)(const edict_t *pEdict, float flTime); -typedef void (*FN_GETBONEPOSITION)(const edict_t *pEdict, int iBone, float *rgflOrigin, float *rgflAngles); -typedef uint32 (*FN_FUNCTIONFROMNAME)(const char *pName); -typedef const char *(*FN_NAMEFORFUNCTION)(uint32 function); -typedef void (*FN_CLIENTPRINTF)(edict_t *pEdict, PRINT_TYPE ptype, const char *szMsg); -typedef void (*FN_SERVERPRINT)(const char *szMsg); -typedef const char *(*FN_CMD_ARGS)(); -typedef const char *(*FN_CMD_ARGV)(int argc); -typedef int (*FN_CMD_ARGC)(); -typedef void (*FN_GETATTACHMENT)(const edict_t *pEdict, int iAttachment, float *rgflOrigin, float *rgflAngles); -typedef void (*FN_CRC32_INIT)(CRC32_t *pulCRC); -typedef void (*FN_CRC32_PROCESSBUFFER)(CRC32_t *pulCRC, void *p, int len); -typedef void (*FN_CRC32_PROCESSBYTE)(CRC32_t *pulCRC, unsigned char ch); -typedef CRC32_t (*FN_CRC32_FINAL)(CRC32_t pulCRC); -typedef int32 (*FN_RANDOMLONG)(int32 lLow, int32 lHigh); -typedef float (*FN_RANDOMFLOAT)(float flLow, float flHigh); -typedef void (*FN_SETVIEW)(const edict_t *pClient, const edict_t *pViewent); -typedef float (*FN_TIME)(); -typedef void (*FN_CROSSHAIRANGLE)(const edict_t *pClient, float pitch, float yaw); -typedef byte *(*FN_LOADFILEFORME)(char *filename, int *pLength); -typedef void (*FN_FREEFILE)(void *buffer); -typedef void (*FN_ENDSECTION)(const char *pszSectionName); -typedef int (*FN_COMPAREFILETIME)(char *filename1, char *filename2, int *iCompare); -typedef void (*FN_GETGAMEDIR)(char *szGetGameDir); -typedef void (*FN_CVAR_REGISTERVARIABLE)(cvar_t *variable); -typedef void (*FN_FADECLIENTVOLUME)(const edict_t *pEdict, int fadePercent, int fadeOutSeconds, int holdTime, int fadeInSeconds); -typedef void (*FN_SETCLIENTMAXSPEED)(edict_t *pEdict, float fNewMaxspeed); -typedef edict_t *(*FN_CREATEFAKECLIENT)(const char *netname); -typedef void (*FN_RUNPLAYERMOVE)(edict_t *fakeclient, const float *viewangles, float forwardmove, float sidemove, float upmove, unsigned short buttons, byte impulse, byte msec); -typedef int (*FN_NUMBEROFENTITIES)(); -typedef char *(*FN_GETINFOKEYBUFFER)(edict_t *e); -typedef char *(*FN_INFOKEYVALUE)(char *infobuffer, const char *key); -typedef void (*FN_SETKEYVALUE)(char *infobuffer, const char *key, const char *value); -typedef void (*FN_SETCLIENTKEYVALUE)(int clientIndex, char *infobuffer, const char *key, const char *value); -typedef int (*FN_ISMAPVALID)(char *filename); -typedef void (*FN_STATICDECAL)(const float *origin, int decalIndex, int entityIndex, int modelIndex); -typedef int (*FN_PRECACHEGENERIC)(char *s); -typedef int (*FN_GETPLAYERUSERID)(edict_t *e); -typedef void (*FN_BUILDSOUNDMSG)(edict_t *entity, int channel, const char *sample, /*int*/float volume, float attenuation, int fFlags, int pitch, int msg_dest, int msg_type, const float *pOrigin, edict_t *ed); -typedef int (*FN_ISDEDICATEDSERVER)(); -typedef cvar_t *(*FN_CVARGETPOINTER)(const char *szVarName); -typedef unsigned int (*FN_GETPLAYERWONID)(edict_t *e); -typedef void (*FN_INFO_REMOVEKEY)(char *s, const char *key); -typedef const char *(*FN_GETPHYSICSKEYVALUE)(const edict_t *pClient, const char *key); -typedef void (*FN_SETPHYSICSKEYVALUE)(const edict_t *pClient, const char *key, const char *value); -typedef const char *(*FN_GETPHYSICSINFOSTRING)(const edict_t *pClient); -typedef unsigned short (*FN_PRECACHEEVENT)(int type, const char *psz); -typedef void (*FN_PLAYBACKEVENT)(int flags, const edict_t *pInvoker, unsigned short eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2); -typedef unsigned char *(*FN_SETFATPVS)(float *org); -typedef unsigned char *(*FN_SETFATPAS)(float *org); -typedef int (*FN_CHECKVISIBILITY)(edict_t *entity, unsigned char *pset); -typedef void (*FN_DELTASETFIELD)(struct delta_s *pFields, const char *fieldname); -typedef void (*FN_DELTAUNSETFIELD)(struct delta_s *pFields, const char *fieldname); -typedef void (*FN_DELTAADDENCODER)(char *name, void (*conditionalencode)(struct delta_s *pFields, const unsigned char *from, const unsigned char *to)); -typedef int (*FN_GETCURRENTPLAYER)(); -typedef int (*FN_CANSKIPPLAYER)(const edict_t *player); -typedef int (*FN_DELTAFINDFIELD)(struct delta_s *pFields, const char *fieldname); -typedef void (*FN_DELTASETFIELDBYINDEX)(struct delta_s *pFields, int fieldNumber); -typedef void (*FN_DELTAUNSETFIELDBYINDEX)(struct delta_s *pFields, int fieldNumber); -typedef void (*FN_SETGROUPMASK)(int mask, int op); -typedef int (*FN_CREATEINSTANCEDBASELINE)(int classname, struct entity_state_s *baseline); -typedef void (*FN_CVAR_DIRECTSET)(struct cvar_s *var, const char *value); -typedef void (*FN_FORCEUNMODIFIED)(FORCE_TYPE type, float *mins, float *maxs, const char *filename); -typedef void (*FN_GETPLAYERSTATS)(const edict_t *pClient, int *ping, int *packet_loss); -typedef void (*FN_ADDSERVERCOMMAND)(char *cmd_name, void (*function)()); -typedef qboolean (*FN_VOICE_GETCLIENTLISTENING)(int iReceiver, int iSender); -typedef qboolean (*FN_VOICE_SETCLIENTLISTENING)(int iReceiver, int iSender, qboolean bListen); -typedef const char *(*FN_GETPLAYERAUTHID)(edict_t *e); -typedef sequenceEntry_s *(*FN_SEQUENCEGET)(const char *fileName, const char *entryName); -typedef sentenceEntry_s *(*FN_SEQUENCEPICKSENTENCE)(const char *groupName, int pickMethod, int *picked); -typedef int (*FN_GETFILESIZE)(char *filename); -typedef unsigned int (*FN_GETAPPROXWAVEPLAYLEN)(const char *filepath); -typedef int (*FN_ISCAREERMATCH)(); -typedef int (*FN_GETLOCALIZEDSTRINGLENGTH)(const char *label); -typedef void (*FN_REGISTERTUTORMESSAGESHOWN)(int mid); -typedef int (*FN_GETTIMESTUTORMESSAGESHOWN)(int mid); -typedef void (*FN_PROCESSTUTORMESSAGEDECAYBUFFER)(int *buffer, int bufferLength); -typedef void (*FN_CONSTRUCTTUTORMESSAGEDECAYBUFFER)(int *buffer, int bufferLength); -typedef void (*FN_RESETTUTORMESSAGEDECAYDATA)(); -typedef void (*FN_QUERYCLIENTCVARVALUE)(const edict_t *pEdict, const char *cvarName); // Use FN_QUERYCLIENTCVARVALUE2 instead -typedef void (*FN_QUERYCLIENTCVARVALUE2)(const edict_t *pEdict, const char *cvarName, int requestID); -typedef int (*FN_CHECKPARM)(const char *pchCmdLineToken, char **ppnext); +void compile_engine_callbacks(); diff --git a/metamod/src/game_support.cpp b/metamod/src/game_support.cpp index 86ef3bb..2dd35a9 100644 --- a/metamod/src/game_support.cpp +++ b/metamod/src/game_support.cpp @@ -10,7 +10,7 @@ const game_modinfo_t known_games[] = { // Previously enumerated in this sourcefile, the list is now kept in a // separate file, generated based on game information stored in a // convenient db. - { "cstrike", "cs.so", "mp.dll", "Counter-Strike" }, + { "cstrike", "cs.so", "mp.dll", "Counter-Strike" }, { "czero", "cs.so", "mp.dll", "Counter-Strike:Condition Zero" }, // End of list terminator: @@ -22,7 +22,7 @@ inline const game_modinfo_t *lookup_game(const char *name) { for (auto& known : known_games) { - if (known.name && Q_stricmp(known.name, name)) + if (known.name && !Q_stricmp(known.name, name)) return &known; } @@ -31,13 +31,13 @@ inline const game_modinfo_t *lookup_game(const char *name) } // Installs gamedll from Steam cache -mBOOL install_gamedll(char *from, const char *to) +bool install_gamedll(char *from, const char *to) { int length_in; int length_out; if (!from) - return mFALSE; + return false; if (!to) to = from; @@ -52,7 +52,7 @@ mBOOL install_gamedll(char *from, const char *to) { META_DEBUG(3, ("Installing gamedll from cache: Failed to create file %s: %s", to, strerror(errno)) ); FREE_FILE(cachefile); - return mFALSE; + return false; } length_out = Q_write(fd, cachefile, length_in); @@ -68,7 +68,7 @@ mBOOL install_gamedll(char *from, const char *to) if (length_out >= 0) _unlink(to); - return mFALSE; + return false; } META_LOG("Installed gamedll %s from cache.", to); @@ -76,10 +76,10 @@ mBOOL install_gamedll(char *from, const char *to) else { META_DEBUG(3, ("Failed to install gamedll from cache: file %s not found in cache.", from)); - return mFALSE; + return false; } - return mTRUE; + return true; } // Set all the fields in the gamedll struct, - based either on an entry in @@ -88,7 +88,7 @@ mBOOL install_gamedll(char *from, const char *to) // // meta_errno values: // - ME_NOTFOUND couldn't recognize game -mBOOL setup_gamedll(gamedll_t *gamedll) +bool setup_gamedll(gamedll_t *gamedll) { const game_modinfo_t *known; const char *knownfn = nullptr; @@ -121,7 +121,7 @@ mBOOL setup_gamedll(gamedll_t *gamedll) else { // Neither known-list found a gamedll. - RETURN_ERRNO(mFALSE, ME_NOTFOUND); + RETURN_ERRNO(false, ME_NOTFOUND); } Q_snprintf(gamedll->pathname, sizeof(gamedll->pathname), "%s/dlls/%s", gamedll->gamedir, knownfn); @@ -141,5 +141,5 @@ mBOOL setup_gamedll(gamedll_t *gamedll) gamedll->desc = known->desc; META_LOG("Recognized game '%s'; using dllfile '%s'", gamedll->name, gamedll->file); - return mTRUE; + return true; } diff --git a/metamod/src/game_support.h b/metamod/src/game_support.h index e564570..9c89d2d 100644 --- a/metamod/src/game_support.h +++ b/metamod/src/game_support.h @@ -13,4 +13,4 @@ struct game_modinfo_t const char *desc; // our long-name description }; -mBOOL setup_gamedll(gamedll_t *gamedll); +bool setup_gamedll(gamedll_t *gamedll); diff --git a/metamod/src/h_export.cpp b/metamod/src/h_export.cpp index a2d517b..789fd1b 100644 --- a/metamod/src/h_export.cpp +++ b/metamod/src/h_export.cpp @@ -57,31 +57,3 @@ void WINAPI GiveFnptrsToDll(enginefuncs_t *pengfuncsFromEngine, globalvars_t *pG // Load plugins, load game dll. metamod_startup(); } - -// Avoid linking to libstdc++ -#if defined(linux) -extern "C" void __cxa_pure_virtual(void) -{ -} - -void *operator new(size_t size) -{ - return Q_malloc(size); -} - -void *operator new[](size_t size) -{ - return Q_malloc(size); -} - -void operator delete(void *ptr) -{ - Q_free(ptr); -} - -void operator delete[](void * ptr) -{ - Q_free(ptr); -} -#endif - diff --git a/metamod/src/jitasm.h b/metamod/src/jitasm.h new file mode 100644 index 0000000..f74840d --- /dev/null +++ b/metamod/src/jitasm.h @@ -0,0 +1,8968 @@ +// Copyright (c) 2009-2011, Hikaru Inoue, Akihiro Yamasaki, +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * The names of the contributors may not be used to endorse or promote +// products derived from this software without specific prior written +// permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#pragma once +#ifndef JITASM_H +#define JITASM_H + +#if defined(_WIN32) +#define JITASM_WIN // Windows +#endif + +#if (defined(_WIN64) && (defined(_M_AMD64) || defined(_M_X64))) || defined(__x86_64__) +#define JITASM64 +#endif + +#if defined(__GNUC__) +#define JITASM_GCC +#endif + +#if !defined(JITASM_MMINTRIN) + #if !defined(__GNUC__) || defined(__MMX__) + #define JITASM_MMINTRIN 1 + #else + #define JITASM_MMINTRIN 0 + #endif +#endif +#if !defined(JITASM_XMMINTRIN) + #if !defined(__GNUC__) || defined(__SSE__) + #define JITASM_XMMINTRIN 1 + #else + #define JITASM_XMMINTRIN 0 + #endif +#endif +#if !defined(JITASM_EMMINTRIN) + #if !defined(__GNUC__) || defined(__SSE2__) + #define JITASM_EMMINTRIN 1 + #else + #define JITASM_EMMINTRIN 0 + #endif +#endif + + +#include +#include +#include +#include +#include +#include + +#if defined(JITASM_WIN) +#include +#else +#include +#include +#include +#endif + +#if JITASM_MMINTRIN + #include +#endif +#if JITASM_XMMINTRIN + #include +#endif +#if JITASM_EMMINTRIN + #include +#endif + +#if _MSC_VER >= 1400 // VC8 or later +#include +#endif + +#if defined(_MSC_VER) +#pragma warning( push ) +#pragma warning( disable : 4127 ) // conditional expression is constant. +#pragma warning( disable : 4201 ) // nonstandard extension used : nameless struct/union +#endif + +#ifdef ASSERT +#define JITASM_ASSERT ASSERT +#else +#include +#define JITASM_ASSERT assert +#endif + +//#define JITASM_DEBUG_DUMP +#ifdef JITASM_DEBUG_DUMP + #if defined(JITASM_GCC) + #include + #define JITASM_TRACE printf + #else + #define JITASM_TRACE jitasm::detail::Trace + #endif +#elif defined(JITASM_GCC) + #define JITASM_TRACE(...) ((void)0) +#else + #define JITASM_TRACE __noop +#endif + +namespace jitasm +{ + +typedef signed char sint8; +typedef signed short sint16; +typedef signed int sint32; +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned int uint32; +#if defined(JITASM_GCC) +typedef signed long long sint64; +typedef unsigned long long uint64; +#else +typedef signed __int64 sint64; +typedef unsigned __int64 uint64; +#endif + +template inline void avoid_unused_warn(const T&) {} + +namespace detail +{ +#if defined(JITASM_GCC) + inline long interlocked_increment(long *addend) { return __sync_add_and_fetch(addend, 1); } + inline long interlocked_decrement(long *addend) { return __sync_sub_and_fetch(addend, 1); } + inline long interlocked_exchange(long *target, long value) { return __sync_lock_test_and_set(target, value); } +#elif defined(JITASM_WIN) + inline long interlocked_increment(long *addend) { return _InterlockedIncrement(addend); } + inline long interlocked_decrement(long *addend) { return _InterlockedDecrement(addend); } + inline long interlocked_exchange(long *target, long value) { return _InterlockedExchange(target, value); } +#endif +} // namespace detail + +/// Physical register ID +enum PhysicalRegID +{ + INVALID=-1, + EAX=0, ECX, EDX, EBX, ESP, EBP, ESI, EDI, R8D, R9D, R10D, R11D, R12D, R13D, R14D, R15D, + AL=0, CL, DL, BL, AH, CH, DH, BH, R8B, R9B, R10B, R11B, R12B, R13B, R14B, R15B, + AX=0, CX, DX, BX, SP, BP, SI, DI, R8W, R9W, R10W, R11W, R12W, R13W, R14W, R15W, + RAX=0, RCX, RDX, RBX, RSP, RBP, RSI, RDI, R8, R9, R10, R11, R12, R13, R14, R15, + ST0=0, ST1, ST2, ST3, ST4, ST5, ST6, ST7, + MM0=0, MM1, MM2, MM3, MM4, MM5, MM6, MM7, + XMM0=0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7, XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15, + YMM0=0, YMM1, YMM2, YMM3, YMM4, YMM5, YMM6, YMM7, YMM8, YMM9, YMM10, YMM11, YMM12, YMM13, YMM14, YMM15, +}; + +enum +{ + /** \var NUM_OF_PHYSICAL_REG + * Number of physical register + */ + /** \var SIZE_OF_GP_REG + * Size of general-purpose register + */ +#ifdef JITASM64 + NUM_OF_PHYSICAL_REG = 16, + SIZE_OF_GP_REG = 8 +#else + NUM_OF_PHYSICAL_REG = 8, + SIZE_OF_GP_REG = 4 +#endif +}; + +/// Register type +enum RegType +{ + R_TYPE_GP, ///< General purpose register + R_TYPE_MMX, ///< MMX register + R_TYPE_XMM, ///< XMM register + R_TYPE_YMM, ///< YMM register + R_TYPE_FPU, ///< FPU register + R_TYPE_SYMBOLIC_GP, ///< Symbolic general purpose register + R_TYPE_SYMBOLIC_MMX, ///< Symbolic MMX register + R_TYPE_SYMBOLIC_XMM, ///< Symbolic XMM register + R_TYPE_SYMBOLIC_YMM ///< Symbolic YMM register +}; + +/// Register identifier +struct RegID +{ + RegType type; + int id; ///< PhysicalRegID or symbolic register id + + bool operator==(const RegID& rhs) const {return type == rhs.type && id == rhs.id;} + bool operator!=(const RegID& rhs) const {return !(*this == rhs);} + bool operator<(const RegID& rhs) const {return type != rhs.type ? type < rhs.type : id < rhs.id;} + bool IsInvalid() const {return type == R_TYPE_GP && id == INVALID;} + bool IsSymbolic() const {return type == R_TYPE_SYMBOLIC_GP || type == R_TYPE_SYMBOLIC_MMX || type == R_TYPE_SYMBOLIC_XMM;} + + static RegID Invalid() { + RegID reg; + reg.type = R_TYPE_GP; + reg.id = INVALID; + return reg; + } + static RegID CreatePhysicalRegID(RegType type_, PhysicalRegID id_) { + RegID reg; + reg.type = type_; + reg.id = id_; + return reg; + } + static RegID CreateSymbolicRegID(RegType type_) { + static long s_id = 0; + RegID reg; + reg.type = type_; + reg.id = static_cast(detail::interlocked_increment(&s_id)); + return reg; + } +}; + +/// Operand type +enum OpdType +{ + O_TYPE_NONE, + O_TYPE_REG, + O_TYPE_MEM, + O_TYPE_IMM, + O_TYPE_TYPE_MASK = 0x0F, + + O_TYPE_DUMMY = 1 << 8, ///< The operand which has this flag is not encoded. This is for register allocator. + O_TYPE_READ = 1 << 9, ///< The operand is used for reading. + O_TYPE_WRITE = 1 << 10 ///< The operand is used for writing. +}; + +/// Operand size +enum OpdSize +{ + O_SIZE_8 = 8, + O_SIZE_16 = 16, + O_SIZE_32 = 32, + O_SIZE_64 = 64, + O_SIZE_80 = 80, + O_SIZE_128 = 128, + O_SIZE_224 = 224, + O_SIZE_256 = 256, + O_SIZE_864 = 864, + O_SIZE_4096 = 4096, +}; + +namespace detail +{ + /// Operand base class + struct Opd + { + OpdType opdtype_; + OpdSize opdsize_; + + union { + // REG + struct { + RegID reg_; + uint32 reg_assignable_; + }; + // MEM + struct { + RegID base_; + RegID index_; + sint64 scale_; + sint64 disp_; + OpdSize addrsize_; + }; + // IMM + sint64 imm_; + }; + + /// NONE + Opd() : opdtype_(O_TYPE_NONE) {} + /// REG + Opd(OpdSize opdsize, const RegID& reg, uint32 reg_assignable = 0xFFFFFFFF) : opdtype_(O_TYPE_REG), opdsize_(opdsize), reg_(reg), reg_assignable_(reg_assignable) {} + /// MEM + Opd(OpdSize opdsize, OpdSize addrsize, const RegID& base, const RegID& index, sint64 scale, sint64 disp) + : opdtype_(O_TYPE_MEM), opdsize_(opdsize), base_(base), index_(index), scale_(scale), disp_(disp), addrsize_(addrsize) {} + protected: + /// IMM + explicit Opd(OpdSize opdsize, sint64 imm) : opdtype_(O_TYPE_IMM), opdsize_(opdsize), imm_(imm) {} + + public: + bool IsNone() const {return (opdtype_ & O_TYPE_TYPE_MASK) == O_TYPE_NONE;} + bool IsReg() const {return (opdtype_ & O_TYPE_TYPE_MASK) == O_TYPE_REG;} + bool IsGpReg() const {return IsReg() && (reg_.type == R_TYPE_GP || reg_.type == R_TYPE_SYMBOLIC_GP);} + bool IsFpuReg() const {return IsReg() && reg_.type == R_TYPE_FPU;} + bool IsMmxReg() const {return IsReg() && (reg_.type == R_TYPE_MMX || reg_.type == R_TYPE_SYMBOLIC_MMX);} + bool IsXmmReg() const {return IsReg() && (reg_.type == R_TYPE_XMM || reg_.type == R_TYPE_SYMBOLIC_XMM);} + bool IsYmmReg() const {return IsReg() && (reg_.type == R_TYPE_YMM || reg_.type == R_TYPE_SYMBOLIC_YMM);} + bool IsMem() const {return (opdtype_ & O_TYPE_TYPE_MASK) == O_TYPE_MEM;} + bool IsImm() const {return (opdtype_ & O_TYPE_TYPE_MASK) == O_TYPE_IMM;} + bool IsDummy() const {return (opdtype_ & O_TYPE_DUMMY) != 0;} + + OpdSize GetSize() const {return opdsize_;} + OpdSize GetAddressSize() const {return addrsize_;} + RegID GetReg() const {JITASM_ASSERT(IsReg()); return reg_;} + RegID GetBase() const {JITASM_ASSERT(IsMem()); return base_;} + RegID GetIndex() const {JITASM_ASSERT(IsMem()); return index_;} + sint64 GetScale() const {JITASM_ASSERT(IsMem()); return scale_;} + sint64 GetDisp() const {JITASM_ASSERT(IsMem()); return disp_;} + sint64 GetImm() const {JITASM_ASSERT(IsImm()); return imm_;} + + bool operator==(const Opd& rhs) const + { + if ((opdtype_ & O_TYPE_TYPE_MASK) != (rhs.opdtype_ & O_TYPE_TYPE_MASK) || rhs.opdsize_ != opdsize_) {return false;} + if (IsReg()) {return reg_ == rhs.reg_ && reg_assignable_ == rhs.reg_assignable_;} + if (IsMem()) {return base_ == rhs.base_ && index_ == rhs.index_ && scale_ == rhs.scale_ && disp_ == rhs.disp_ && addrsize_ == rhs.addrsize_;} + if (IsImm()) {return imm_ == rhs.imm_;} + return true; + } + bool operator!=(const Opd& rhs) const {return !(*this == rhs);} + }; + + /// Add O_TYPE_DUMMY to the specified operand + inline Opd Dummy(const Opd& opd) + { + Opd o(opd); + o.opdtype_ = static_cast(static_cast(o.opdtype_) | O_TYPE_DUMMY); + return o; + } + + /// Add O_TYPE_DUMMY to the specified operand and constraint of register assignment + inline Opd Dummy(const Opd& opd, const Opd& constraint) + { + JITASM_ASSERT(opd.IsReg() && (opd.opdtype_ & O_TYPE_TYPE_MASK) == (constraint.opdtype_ & O_TYPE_TYPE_MASK) && !constraint.GetReg().IsSymbolic()); + Opd o(opd); + o.opdtype_ = static_cast(static_cast(o.opdtype_) | O_TYPE_DUMMY); + o.reg_assignable_ = (1 << constraint.reg_.id); + return o; + } + + /// Add O_TYPE_READ to the specified operand + inline Opd R(const Opd& opd) + { + Opd o(opd); + o.opdtype_ = static_cast(static_cast(o.opdtype_) | O_TYPE_READ); + return o; + } + + /// Add O_TYPE_WRITE to the specified operand + inline Opd W(const Opd& opd) + { + Opd o(opd); + o.opdtype_ = static_cast(static_cast(o.opdtype_) | O_TYPE_WRITE); + return o; + } + + /// Add O_TYPE_READ | O_TYPE_WRITE to the specified operand + inline Opd RW(const Opd& opd) + { + Opd o(opd); + o.opdtype_ = static_cast(static_cast(o.opdtype_) | O_TYPE_READ | O_TYPE_WRITE); + return o; + } + + template + struct OpdT : Opd + { + /// NONE + OpdT() : Opd() {} + /// REG + explicit OpdT(const RegID& reg, uint32 reg_assignable = 0xFFFFFFFF) : Opd(static_cast(Size), reg, reg_assignable) {} + /// MEM + OpdT(OpdSize addrsize, const RegID& base, const RegID& index, sint64 scale, sint64 disp) + : Opd(static_cast(Size), addrsize, base, index, scale, disp) {} + protected: + /// IMM + OpdT(sint64 imm) : Opd(static_cast(Size), imm) {} + }; + +} // namespace detail + +typedef detail::OpdT Opd8; +typedef detail::OpdT Opd16; +typedef detail::OpdT Opd32; +typedef detail::OpdT Opd64; +typedef detail::OpdT Opd80; +typedef detail::OpdT Opd128; +typedef detail::OpdT Opd224; // FPU environment +typedef detail::OpdT Opd256; +typedef detail::OpdT Opd864; // FPU state +typedef detail::OpdT Opd4096; // FPU, MMX, XMM, MXCSR state + +/// 8bit general purpose register +struct Reg8 : Opd8 { + Reg8() : Opd8(RegID::CreateSymbolicRegID(R_TYPE_SYMBOLIC_GP), 0xFFFFFF0F) {} + explicit Reg8(PhysicalRegID id) : Opd8(RegID::CreatePhysicalRegID(R_TYPE_GP, id)) {} +}; +/// 16bit general purpose register +struct Reg16 : Opd16 { + Reg16() : Opd16(RegID::CreateSymbolicRegID(R_TYPE_SYMBOLIC_GP)) {} + explicit Reg16(PhysicalRegID id) : Opd16(RegID::CreatePhysicalRegID(R_TYPE_GP, id)) {} +}; +/// 32bit general purpose register +struct Reg32 : Opd32 { + Reg32() : Opd32(RegID::CreateSymbolicRegID(R_TYPE_SYMBOLIC_GP)) {} + explicit Reg32(PhysicalRegID id) : Opd32(RegID::CreatePhysicalRegID(R_TYPE_GP, id)) {} +}; +#ifdef JITASM64 +/// 64bit general purpose register +struct Reg64 : Opd64 { + Reg64() : Opd64(RegID::CreateSymbolicRegID(R_TYPE_SYMBOLIC_GP)) {} + explicit Reg64(PhysicalRegID id) : Opd64(RegID::CreatePhysicalRegID(R_TYPE_GP, id)) {} +}; +typedef Reg64 Reg; +#else +typedef Reg32 Reg; +#endif +/// FPU register +struct FpuReg : Opd80 { + explicit FpuReg(PhysicalRegID id) : Opd80(RegID::CreatePhysicalRegID(R_TYPE_FPU, id)) {} +}; +/// MMX register +struct MmxReg : Opd64 { + MmxReg() : Opd64(RegID::CreateSymbolicRegID(R_TYPE_SYMBOLIC_MMX)) {} + explicit MmxReg(PhysicalRegID id) : Opd64(RegID::CreatePhysicalRegID(R_TYPE_MMX, id)) {} +}; +/// XMM register +struct XmmReg : Opd128 { + XmmReg() : Opd128(RegID::CreateSymbolicRegID(R_TYPE_SYMBOLIC_XMM)) {} + explicit XmmReg(PhysicalRegID id) : Opd128(RegID::CreatePhysicalRegID(R_TYPE_XMM, id)) {} +}; +/// YMM register +struct YmmReg : Opd256 { + YmmReg() : Opd256(RegID::CreateSymbolicRegID(R_TYPE_SYMBOLIC_YMM)) {} + explicit YmmReg(PhysicalRegID id) : Opd256(RegID::CreatePhysicalRegID(R_TYPE_YMM, id)) {} +}; + +struct Reg8_al : Reg8 {Reg8_al() : Reg8(AL) {}}; +struct Reg8_cl : Reg8 {Reg8_cl() : Reg8(CL) {}}; +struct Reg16_ax : Reg16 {Reg16_ax() : Reg16(AX) {}}; +struct Reg16_dx : Reg16 {Reg16_dx() : Reg16(DX) {}}; +struct Reg32_eax : Reg32 {Reg32_eax() : Reg32(EAX) {}}; +#ifdef JITASM64 +struct Reg64_rax : Reg64 {Reg64_rax() : Reg64(RAX) {}}; +#endif +struct FpuReg_st0 : FpuReg {FpuReg_st0() : FpuReg(ST0) {}}; + +template +struct MemT : OpdN +{ + MemT(OpdSize addrsize, const RegID& base, const RegID& index, sint64 scale, sint64 disp) : OpdN(addrsize, base, index, scale, disp) {} +}; +typedef MemT Mem8; +typedef MemT Mem16; +typedef MemT Mem32; +typedef MemT Mem64; +typedef MemT Mem80; +typedef MemT Mem128; +typedef MemT Mem224; // FPU environment +typedef MemT Mem256; +typedef MemT Mem864; // FPU state +typedef MemT Mem4096; // FPU, MMX, XMM, MXCSR state + +struct MemOffset64 +{ + sint64 offset_; + explicit MemOffset64(sint64 offset) : offset_(offset) {} + sint64 GetOffset() const {return offset_;} +}; + +template +struct ImmT : OpdN +{ + ImmT(U imm) : OpdN((S) imm) {} +}; +typedef ImmT Imm8; ///< 1 byte immediate +typedef ImmT Imm16; ///< 2 byte immediate +typedef ImmT Imm32; ///< 4 byte immediate +typedef ImmT Imm64; ///< 8 byte immediate + +namespace detail +{ + inline bool IsInt8(sint64 n) {return (sint8) n == n;} + inline bool IsInt16(sint64 n) {return (sint16) n == n;} + inline bool IsInt32(sint64 n) {return (sint32) n == n;} + inline Opd ImmXor8(const Imm16& imm) {return IsInt8(imm.GetImm()) ? (Opd) Imm8((sint8) imm.GetImm()) : (Opd) imm;} + inline Opd ImmXor8(const Imm32& imm) {return IsInt8(imm.GetImm()) ? (Opd) Imm8((sint8) imm.GetImm()) : (Opd) imm;} + inline Opd ImmXor8(const Imm64& imm) {return IsInt8(imm.GetImm()) ? (Opd) Imm8((sint8) imm.GetImm()) : (Opd) imm;} +} // namespace detail + + +/// 32bit address (base, displacement) +struct Addr32 +{ + RegID reg_; + sint64 disp_; + Addr32(const Reg32& obj) : reg_(obj.reg_), disp_(0) {} // implicit + Addr32(const RegID& reg, sint64 disp) : reg_(reg), disp_(disp) {} +}; +inline Addr32 operator+(const Reg32& lhs, sint64 rhs) {return Addr32(lhs.reg_, rhs);} +inline Addr32 operator+(sint64 lhs, const Reg32& rhs) {return rhs + lhs;} +inline Addr32 operator-(const Reg32& lhs, sint64 rhs) {return lhs + -rhs;} +inline Addr32 operator+(const Addr32& lhs, sint64 rhs) {return Addr32(lhs.reg_, lhs.disp_ + rhs);} +inline Addr32 operator+(sint64 lhs, const Addr32& rhs) {return rhs + lhs;} +inline Addr32 operator-(const Addr32& lhs, sint64 rhs) {return lhs + -rhs;} + +/// 32bit address (base, index, displacement) +struct Addr32BI +{ + RegID base_; + RegID index_; + sint64 disp_; + Addr32BI(const RegID& base, const RegID& index, sint64 disp) : base_(base), index_(index), disp_(disp) {} +}; +inline Addr32BI operator+(const Addr32& lhs, const Addr32& rhs) {return Addr32BI(rhs.reg_, lhs.reg_, lhs.disp_ + rhs.disp_);} +inline Addr32BI operator+(const Addr32BI& lhs, sint64 rhs) {return Addr32BI(lhs.base_, lhs.index_, lhs.disp_ + rhs);} +inline Addr32BI operator+(sint64 lhs, const Addr32BI& rhs) {return rhs + lhs;} +inline Addr32BI operator-(const Addr32BI& lhs, sint64 rhs) {return lhs + -rhs;} + +/// 32bit address (index, scale, displacement) +struct Addr32SI +{ + RegID index_; + sint64 scale_; + sint64 disp_; + Addr32SI(const RegID& index, sint64 scale, sint64 disp) : index_(index), scale_(scale), disp_(disp) {} +}; +inline Addr32SI operator*(const Reg32& lhs, sint64 rhs) {return Addr32SI(lhs.reg_, rhs, 0);} +inline Addr32SI operator*(sint64 lhs, const Reg32& rhs) {return rhs * lhs;} +inline Addr32SI operator*(const Addr32SI& lhs, sint64 rhs) {return Addr32SI(lhs.index_, lhs.scale_ * rhs, lhs.disp_);} +inline Addr32SI operator*(sint64 lhs, const Addr32SI& rhs) {return rhs * lhs;} +inline Addr32SI operator+(const Addr32SI& lhs, sint64 rhs) {return Addr32SI(lhs.index_, lhs.scale_, lhs.disp_ + rhs);} +inline Addr32SI operator+(sint64 lhs, const Addr32SI& rhs) {return rhs + lhs;} +inline Addr32SI operator-(const Addr32SI& lhs, sint64 rhs) {return lhs + -rhs;} + +/// 32bit address (base, index, scale, displacement) +struct Addr32SIB +{ + RegID base_; + RegID index_; + sint64 scale_; + sint64 disp_; + Addr32SIB(const RegID& base, const RegID& index, sint64 scale, sint64 disp) : base_(base), index_(index), scale_(scale), disp_(disp) {} +}; +inline Addr32SIB operator+(const Addr32& lhs, const Addr32SI& rhs) {return Addr32SIB(lhs.reg_, rhs.index_, rhs.scale_, lhs.disp_ + rhs.disp_);} +inline Addr32SIB operator+(const Addr32SI& lhs, const Addr32& rhs) {return rhs + lhs;} +inline Addr32SIB operator+(const Addr32SIB& lhs, sint64 rhs) {return Addr32SIB(lhs.base_, lhs.index_, lhs.scale_, lhs.disp_ + rhs);} +inline Addr32SIB operator+(sint64 lhs, const Addr32SIB& rhs) {return rhs + lhs;} +inline Addr32SIB operator-(const Addr32SIB& lhs, sint64 rhs) {return lhs + -rhs;} + +#ifdef JITASM64 +/// 64bit address (base, displacement) +struct Addr64 +{ + RegID reg_; + sint64 disp_; + Addr64(const Reg64& obj) : reg_(obj.reg_), disp_(0) {} // implicit + Addr64(const RegID& reg, sint64 disp) : reg_(reg), disp_(disp) {} +}; +inline Addr64 operator+(const Reg64& lhs, sint64 rhs) {return Addr64(lhs.reg_, rhs);} +inline Addr64 operator+(sint64 lhs, const Reg64& rhs) {return rhs + lhs;} +inline Addr64 operator-(const Reg64& lhs, sint64 rhs) {return lhs + -rhs;} +inline Addr64 operator+(const Addr64& lhs, sint64 rhs) {return Addr64(lhs.reg_, lhs.disp_ + rhs);} +inline Addr64 operator+(sint64 lhs, const Addr64& rhs) {return rhs + lhs;} +inline Addr64 operator-(const Addr64& lhs, sint64 rhs) {return lhs + -rhs;} + +/// 64bit address (base, index, displacement) +struct Addr64BI +{ + RegID base_; + RegID index_; + sint64 disp_; + Addr64BI(const RegID& base, const RegID& index, sint64 disp) : base_(base), index_(index), disp_(disp) {} +}; +inline Addr64BI operator+(const Addr64& lhs, const Addr64& rhs) {return Addr64BI(rhs.reg_, lhs.reg_, lhs.disp_ + rhs.disp_);} +inline Addr64BI operator+(const Addr64BI& lhs, sint64 rhs) {return Addr64BI(lhs.base_, lhs.index_, lhs.disp_ + rhs);} +inline Addr64BI operator+(sint64 lhs, const Addr64BI& rhs) {return rhs + lhs;} +inline Addr64BI operator-(const Addr64BI& lhs, sint64 rhs) {return lhs + -rhs;} + +/// 64bit address (index, scale, displacement) +struct Addr64SI +{ + RegID index_; + sint64 scale_; + sint64 disp_; + Addr64SI(const RegID& index, sint64 scale, sint64 disp) : index_(index), scale_(scale), disp_(disp) {} +}; +inline Addr64SI operator*(const Reg64& lhs, sint64 rhs) {return Addr64SI(lhs.reg_, rhs, 0);} +inline Addr64SI operator*(sint64 lhs, const Reg64& rhs) {return rhs * lhs;} +inline Addr64SI operator*(const Addr64SI& lhs, sint64 rhs) {return Addr64SI(lhs.index_, lhs.scale_ * rhs, lhs.disp_);} +inline Addr64SI operator*(sint64 lhs, const Addr64SI& rhs) {return rhs * lhs;} +inline Addr64SI operator+(const Addr64SI& lhs, sint64 rhs) {return Addr64SI(lhs.index_, lhs.scale_, lhs.disp_ + rhs);} +inline Addr64SI operator+(sint64 lhs, const Addr64SI& rhs) {return rhs + lhs;} +inline Addr64SI operator-(const Addr64SI& lhs, sint64 rhs) {return lhs + -rhs;} + +/// 64bit address (base, index, scale, displacement) +struct Addr64SIB +{ + RegID base_; + RegID index_; + sint64 scale_; + sint64 disp_; + Addr64SIB(const RegID& base, const RegID& index, sint64 scale, sint64 disp) : base_(base), index_(index), scale_(scale), disp_(disp) {} +}; +inline Addr64SIB operator+(const Addr64& lhs, const Addr64SI& rhs) {return Addr64SIB(lhs.reg_, rhs.index_, rhs.scale_, lhs.disp_ + rhs.disp_);} +inline Addr64SIB operator+(const Addr64SI& lhs, const Addr64& rhs) {return rhs + lhs;} +inline Addr64SIB operator+(const Addr64SIB& lhs, sint64 rhs) {return Addr64SIB(lhs.base_, lhs.index_, lhs.scale_, lhs.disp_ + rhs);} +inline Addr64SIB operator+(sint64 lhs, const Addr64SIB& rhs) {return rhs + lhs;} +inline Addr64SIB operator-(const Addr64SIB& lhs, sint64 rhs) {return lhs + -rhs;} + +typedef Addr64 Addr; +typedef Addr64BI AddrBI; +typedef Addr64SI AddrSI; +typedef Addr64SIB AddrSIB; +#else +typedef Addr32 Addr; +typedef Addr32BI AddrBI; +typedef Addr32SI AddrSI; +typedef Addr32SIB AddrSIB; +#endif + +template +struct AddressingPtr +{ + // 32bit-Addressing + MemT operator[](const Addr32& obj) {return MemT(O_SIZE_32, obj.reg_, RegID::Invalid(), 0, obj.disp_);} + MemT operator[](const Addr32BI& obj) {return MemT(O_SIZE_32, obj.base_, obj.index_, 0, obj.disp_);} + MemT operator[](const Addr32SI& obj) {return MemT(O_SIZE_32, RegID::Invalid(), obj.index_, obj.scale_, obj.disp_);} + MemT operator[](const Addr32SIB& obj) {return MemT(O_SIZE_32, obj.base_, obj.index_, obj.scale_, obj.disp_);} +#ifdef JITASM64 + MemT operator[](sint32 disp) {return MemT(O_SIZE_64, RegID::Invalid(), RegID::Invalid(), 0, disp);} + MemT operator[](uint32 disp) {return MemT(O_SIZE_64, RegID::Invalid(), RegID::Invalid(), 0, (sint32) disp);} +#else + MemT operator[](sint32 disp) {return MemT(O_SIZE_32, RegID::Invalid(), RegID::Invalid(), 0, disp);} + MemT operator[](uint32 disp) {return MemT(O_SIZE_32, RegID::Invalid(), RegID::Invalid(), 0, (sint32) disp);} +#endif + +#ifdef JITASM64 + // 64bit-Addressing + MemT operator[](const Addr64& obj) {return MemT(O_SIZE_64, obj.reg_, RegID::Invalid(), 0, obj.disp_);} + MemT operator[](const Addr64BI& obj) {return MemT(O_SIZE_64, obj.base_, obj.index_, 0, obj.disp_);} + MemT operator[](const Addr64SI& obj) {return MemT(O_SIZE_64, RegID::Invalid(), obj.index_, obj.scale_, obj.disp_);} + MemT operator[](const Addr64SIB& obj) {return MemT(O_SIZE_64, obj.base_, obj.index_, obj.scale_, obj.disp_);} + MemOffset64 operator[](sint64 offset) {return MemOffset64(offset);} + MemOffset64 operator[](uint64 offset) {return MemOffset64((sint64) offset);} +#endif +}; + +/// Instruction ID +enum InstrID +{ + I_ADC, I_ADD, I_AND, + I_BSF, I_BSR, I_BSWAP, I_BT, I_BTC, I_BTR, I_BTS, + I_CALL, I_CBW, I_CLC, I_CLD, I_CLI, I_CLTS, I_CMC, I_CMOVCC, I_CMP, I_CMPS_B, I_CMPS_W, I_CMPS_D, I_CMPS_Q, I_CMPXCHG, + I_CMPXCHG8B, I_CMPXCHG16B, I_CPUID, I_CWD, I_CDQ, I_CQO, + I_DEC, I_DIV, + I_ENTER, + I_HLT, + I_IDIV, I_IMUL, I_IN, I_INC, I_INS_B, I_INS_W, I_INS_D, I_INVD, I_INVLPG, I_INT3, I_INTN, I_INTO, I_IRET, I_IRETD, I_IRETQ, + I_JMP, I_JCC, + I_LAR, I_LEA, I_LEAVE, I_LLDT, I_LMSW, I_LSL, I_LTR, I_LODS_B, I_LODS_W, I_LODS_D, I_LODS_Q, I_LOOP, + I_MOV, I_MOVBE, I_MOVS_B, I_MOVS_W, I_MOVS_D, I_MOVS_Q, I_MOVZX, I_MOVSX, I_MOVSXD, I_MUL, + I_NEG, I_NOP, I_NOT, + I_OR, I_OUT, I_OUTS_B, I_OUTS_W, I_OUTS_D, + I_POP, I_POPAD, I_POPF, I_POPFD, I_POPFQ, I_PUSH, I_PUSHAD, I_PUSHF, I_PUSHFD, I_PUSHFQ, + I_RDMSR, I_RDPMC, I_RDTSC, I_RET, I_RCL, I_RCR, I_ROL, I_ROR, I_RSM, + I_SAR, I_SHL, I_SHR, I_SBB, I_SCAS_B, I_SCAS_W, I_SCAS_D, I_SCAS_Q, I_SETCC, I_SHLD, I_SHRD, I_SGDT, I_SIDT, I_SLDT, I_SMSW, I_STC, I_STD, I_STI, + I_STOS_B, I_STOS_W, I_STOS_D, I_STOS_Q, I_SUB, I_SWAPGS, I_SYSCALL, I_SYSENTER, I_SYSEXIT, I_SYSRET, + I_TEST, + I_UD2, + I_VERR, I_VERW, + I_WAIT, I_WBINVD, I_WRMSR, + I_XADD, I_XCHG, I_XGETBV, I_XLATB, I_XOR, + + I_F2XM1, I_FABS, I_FADD, I_FADDP, I_FIADD, + I_FBLD, I_FBSTP, I_FCHS, I_FCLEX, I_FNCLEX, I_FCMOVCC, I_FCOM, I_FCOMP, I_FCOMPP, I_FCOMI, I_FCOMIP, I_FCOS, + I_FDECSTP, I_FDIV, I_FDIVP, I_FIDIV, I_FDIVR, I_FDIVRP, I_FIDIVR, + I_FFREE, + I_FICOM, I_FICOMP, I_FILD, I_FINCSTP, I_FINIT, I_FNINIT, I_FIST, I_FISTP, + I_FLD, I_FLD1, I_FLDCW, I_FLDENV, I_FLDL2E, I_FLDL2T, I_FLDLG2, I_FLDLN2, I_FLDPI, I_FLDZ, + I_FMUL, I_FMULP, I_FIMUL, + I_FNOP, + I_FPATAN, I_FPREM, I_FPREM1, I_FPTAN, + I_FRNDINT, I_FRSTOR, + I_FSAVE, I_FNSAVE, I_FSCALE, I_FSIN, I_FSINCOS, I_FSQRT, I_FST, I_FSTP, I_FSTCW, I_FNSTCW, I_FSTENV, I_FNSTENV, I_FSTSW, I_FNSTSW, + I_FSUB, I_FSUBP, I_FISUB, I_FSUBR, I_FSUBRP, I_FISUBR, + I_FTST, + I_FUCOM, I_FUCOMP, I_FUCOMPP, I_FUCOMI, I_FUCOMIP, + I_FXAM, I_FXCH, I_FXRSTOR, I_FXSAVE, I_FXTRACT, + I_FYL2X, I_FYL2XP1, + + I_ADDPS, I_ADDSS, I_ADDPD, I_ADDSD, I_ADDSUBPS, I_ADDSUBPD, I_ANDPS, I_ANDPD, I_ANDNPS, I_ANDNPD, + I_BLENDPS, I_BLENDPD, I_BLENDVPS, I_BLENDVPD, + I_CLFLUSH, I_CMPPS, I_CMPSS, I_CMPPD, I_CMPSD, I_COMISS, I_COMISD, I_CRC32, + I_CVTDQ2PD, I_CVTDQ2PS, I_CVTPD2DQ, I_CVTPD2PI, I_CVTPD2PS, I_CVTPI2PD, I_CVTPI2PS, I_CVTPS2DQ, I_CVTPS2PD, I_CVTPS2PI, I_CVTSD2SI, + I_CVTSD2SS, I_CVTSI2SD, I_CVTSI2SS, I_CVTSS2SD, I_CVTSS2SI, I_CVTTPD2DQ, I_CVTTPD2PI, I_CVTTPS2DQ, I_CVTTPS2PI, I_CVTTSD2SI, I_CVTTSS2SI, + I_DIVPS, I_DIVSS, I_DIVPD, I_DIVSD, I_DPPS, I_DPPD, + I_EMMS, I_EXTRACTPS, + I_FISTTP, + I_HADDPS, I_HADDPD, I_HSUBPS, I_HSUBPD, + I_INSERTPS, + I_LDDQU, I_LDMXCSR, I_LFENCE, + I_MASKMOVDQU, I_MASKMOVQ, I_MAXPS, I_MAXSS, I_MAXPD, I_MAXSD, I_MFENCE, I_MINPS, I_MINSS, I_MINPD, I_MINSD, I_MONITOR, + I_MOVAPD, I_MOVAPS, I_MOVD, I_MOVDDUP, I_MOVDQA, I_MOVDQU, I_MOVDQ2Q, I_MOVHLPS, I_MOVLHPS, I_MOVHPS, I_MOVHPD, I_MOVLPS, I_MOVLPD, + I_MOVMSKPS, I_MOVMSKPD, I_MOVNTDQ, I_MOVNTDQA, I_MOVNTI, I_MOVNTPD, I_MOVNTPS, I_MOVNTQ, I_MOVQ, I_MOVQ2DQ, I_MOVSD, I_MOVSS, + I_MOVSHDUP, I_MOVSLDUP, I_MOVUPS, I_MOVUPD, I_MPSADBW, I_MULPS, I_MULSS, I_MULPD, I_MULSD, I_MWAIT, + I_ORPS, I_ORPD, + I_PABSB, I_PABSD, I_PABSW, I_PACKSSDW, I_PACKSSWB, I_PACKUSDW, I_PACKUSWB, I_PADDB, I_PADDD, I_PADDQ, I_PADDSB, I_PADDSW, I_PADDUSB, + I_PADDUSW, I_PADDW, I_PALIGNR, I_PAND, I_PANDN, I_PAUSE, I_PAVGB, I_PAVGW, + I_PBLENDVB, I_PBLENDW, + I_PCMPEQB, I_PCMPEQW, I_PCMPEQD, I_PCMPEQQ, I_PCMPESTRI, I_PCMPESTRM, I_PCMPISTRI, I_PCMPISTRM, I_PCMPGTB, I_PCMPGTW, I_PCMPGTD, I_PCMPGTQ, + I_PEXTRB, I_PEXTRW, I_PEXTRD, I_PEXTRQ, + I_PHADDW, I_PHADDD, I_PHADDSW, I_PHMINPOSUW, I_PHSUBW, I_PHSUBD, I_PHSUBSW, + I_PINSRB, I_PINSRW, I_PINSRD, I_PINSRQ, + I_PMADDUBSW, I_PMADDWD, I_PMAXSB, I_PMAXSW, I_PMAXSD, I_PMAXUB, I_PMAXUW, I_PMAXUD, I_PMINSB, I_PMINSW, I_PMINSD, I_PMINUB, I_PMINUW, + I_PMINUD, I_PMOVMSKB, I_PMOVSXBW, I_PMOVSXBD, I_PMOVSXBQ, I_PMOVSXWD, I_PMOVSXWQ, I_PMOVSXDQ, I_PMOVZXBW, I_PMOVZXBD, I_PMOVZXBQ, I_PMOVZXWD, + I_PMOVZXWQ, I_PMOVZXDQ, I_PMULDQ, I_PMULHRSW, I_PMULHUW, I_PMULHW, I_PMULLW, I_PMULLD, I_PMULUDQ, + I_POPCNT, I_POR, + I_PREFETCH, + I_PSADBW, I_PSHUFB, I_PSHUFD, I_PSHUFHW, I_PSHUFLW, I_PSHUFW, I_PSIGNB, I_PSIGNW, I_PSIGND, I_PSLLW, I_PSLLD, I_PSLLQ, I_PSLLDQ, I_PSRAW, + I_PSRAD, I_PSRLW, I_PSRLD, I_PSRLQ, I_PSRLDQ, I_PSUBB, I_PSUBW, I_PSUBD, I_PSUBQ, I_PSUBSB, I_PSUBSW, I_PSUBUSB, I_PSUBUSW, + I_PTEST, + I_PUNPCKHBW, I_PUNPCKHWD, I_PUNPCKHDQ, I_PUNPCKHQDQ, I_PUNPCKLBW, I_PUNPCKLWD, I_PUNPCKLDQ, I_PUNPCKLQDQ, + I_PXOR, + I_RCPPS, I_RCPSS, I_ROUNDPS, I_ROUNDPD, I_ROUNDSS, I_ROUNDSD, I_RSQRTPS, I_RSQRTSS, + I_SFENCE, I_SHUFPS, I_SHUFPD, I_SQRTPS, I_SQRTSS, I_SQRTPD, I_SQRTSD, I_STMXCSR, I_SUBPS, I_SUBSS, I_SUBPD, I_SUBSD, + I_UCOMISS, I_UCOMISD, I_UNPCKHPS, I_UNPCKHPD, I_UNPCKLPS, I_UNPCKLPD, + I_XORPS, I_XORPD, + + I_VBROADCASTSS, I_VBROADCASTSD, I_VBROADCASTF128, + I_VEXTRACTF128, + I_VINSERTF128, + I_VMASKMOVPS, I_VMASKMOVPD, + I_VPERMILPD, I_VPERMILPS, I_VPERM2F128, + I_VTESTPS, I_VTESTPD, + I_VZEROALL, I_VZEROUPPER, + + I_AESENC, I_AESENCLAST, I_AESDEC, I_AESDECLAST, I_AESIMC, I_AESKEYGENASSIST, + I_PCLMULQDQ, + + // FMA + I_VFMADD132PD, I_VFMADD213PD, I_VFMADD231PD, I_VFMADD132PS, I_VFMADD213PS, I_VFMADD231PS, + I_VFMADD132SD, I_VFMADD213SD, I_VFMADD231SD, I_VFMADD132SS, I_VFMADD213SS, I_VFMADD231SS, + I_VFMADDSUB132PD, I_VFMADDSUB213PD, I_VFMADDSUB231PD, I_VFMADDSUB132PS, I_VFMADDSUB213PS, I_VFMADDSUB231PS, + I_VFMSUBADD132PD, I_VFMSUBADD213PD, I_VFMSUBADD231PD, I_VFMSUBADD132PS, I_VFMSUBADD213PS, I_VFMSUBADD231PS, + I_VFMSUB132PD, I_VFMSUB213PD, I_VFMSUB231PD, I_VFMSUB132PS, I_VFMSUB213PS, I_VFMSUB231PS, + I_VFMSUB132SD, I_VFMSUB213SD, I_VFMSUB231SD, I_VFMSUB132SS, I_VFMSUB213SS, I_VFMSUB231SS, + I_VFNMADD132PD, I_VFNMADD213PD, I_VFNMADD231PD, I_VFNMADD132PS, I_VFNMADD213PS, I_VFNMADD231PS, + I_VFNMADD132SD, I_VFNMADD213SD, I_VFNMADD231SD, I_VFNMADD132SS, I_VFNMADD213SS, I_VFNMADD231SS, + I_VFNMSUB132PD, I_VFNMSUB213PD, I_VFNMSUB231PD, I_VFNMSUB132PS, I_VFNMSUB213PS, I_VFNMSUB231PS, + I_VFNMSUB132SD, I_VFNMSUB213SD, I_VFNMSUB231SD, I_VFNMSUB132SS, I_VFNMSUB213SS, I_VFNMSUB231SS, + + // F16C + I_RDFSBASE, I_RDGSBASE, I_RDRAND, I_WRFSBASE, I_WRGSBASE, I_VCVTPH2PS, I_VCVTPS2PH, + + // XOP + I_VFRCZPD, I_VFRCZPS, I_VFRCZSD, I_VFRCZSS, + I_VPCMOV, I_VPCOMB, I_VPCOMD, I_VPCOMQ, I_VPCOMUB, I_VPCOMUD, I_VPCOMUQ, I_VPCOMUW, I_VPCOMW, I_VPERMIL2PD, I_VPERMIL2PS, + I_VPHADDBD, I_VPHADDBQ, I_VPHADDBW, I_VPHADDDQ, I_VPHADDUBD, I_VPHADDUBQ, I_VPHADDUBW, I_VPHADDUDQ, I_VPHADDUWD, I_VPHADDUWQ, + I_VPHADDWD, I_VPHADDWQ, I_VPHSUBBW, I_VPHSUBDQ, I_VPHSUBWD, + I_VPMACSDD, I_VPMACSDQH, I_VPMACSDQL, I_VPMACSSDD, I_VPMACSSDQH, I_VPMACSSDQL, I_VPMACSSWD, I_VPMACSSWW, I_VPMACSWD, I_VPMACSWW, + I_VPMADCSSWD, I_VPMADCSWD, + I_VPPERM, I_VPROTB, I_VPROTD, I_VPROTQ, I_VPROTW, I_VPSHAB, I_VPSHAD, I_VPSHAQ, I_VPSHAW, I_VPSHLB, I_VPSHLD, I_VPSHLQ, I_VPSHLW, + + // FMA4 + I_VFMADDPD, I_VFMADDPS, I_VFMADDSD, I_VFMADDSS, + I_VFMADDSUBPD, I_VFMADDSUBPS, + I_VFMSUBADDPD, I_VFMSUBADDPS, + I_VFMSUBPD, I_VFMSUBPS, I_VFMSUBSD, I_VFMSUBSS, + I_VFNMADDPD, I_VFNMADDPS, I_VFNMADDSD, I_VFNMADDSS, + I_VFNMSUBPD, I_VFNMSUBPS, I_VFNMSUBSD, I_VFNMSUBSS, + + // jitasm compiler instructions + I_COMPILER_DECLARE_REG_ARG, ///< Declare register argument + I_COMPILER_DECLARE_STACK_ARG, ///< Declare stack argument + I_COMPILER_DECLARE_RESULT_REG, ///< Declare result register (eax/rax/xmm0) + I_COMPILER_PROLOG, ///< Function prolog + I_COMPILER_EPILOG ///< Function epilog +}; + +enum JumpCondition +{ + JCC_O, JCC_NO, JCC_B, JCC_AE, JCC_E, JCC_NE, JCC_BE, JCC_A, JCC_S, JCC_NS, JCC_P, JCC_NP, JCC_L, JCC_GE, JCC_LE, JCC_G, + JCC_CXZ, JCC_ECXZ, JCC_RCXZ, +}; + +enum EncodingFlags +{ + E_SPECIAL = 1 << 0, + E_OPERAND_SIZE_PREFIX = 1 << 1, ///< Operand-size override prefix + E_REP_PREFIX = 1 << 2, ///< REP prefix + E_REXW_PREFIX = 1 << 3, ///< REX.W + E_MANDATORY_PREFIX_66 = 1 << 4, ///< Mandatory prefix 66 + E_MANDATORY_PREFIX_F2 = 1 << 5, ///< Mandatory prefix F2 + E_MANDATORY_PREFIX_F3 = 1 << 6, ///< Mandatory prefix F3 + E_VEX = 1 << 7, + E_XOP = 1 << 8, + E_VEX_L = 1 << 9, + E_VEX_W = 1 << 10, + E_VEX_MMMMM_SHIFT = 11, + E_VEX_MMMMM_MASK = 0x1F << E_VEX_MMMMM_SHIFT, + E_VEX_0F = 1 << E_VEX_MMMMM_SHIFT, + E_VEX_0F38 = 2 << E_VEX_MMMMM_SHIFT, + E_VEX_0F3A = 3 << E_VEX_MMMMM_SHIFT, + E_XOP_M00011 = 3 << E_VEX_MMMMM_SHIFT, + E_XOP_M01000 = 8 << E_VEX_MMMMM_SHIFT, + E_XOP_M01001 = 9 << E_VEX_MMMMM_SHIFT, + E_VEX_PP_SHIFT = 16, + E_VEX_PP_MASK = 0x3 << E_VEX_PP_SHIFT, + E_VEX_66 = 1 << E_VEX_PP_SHIFT, + E_VEX_F3 = 2 << E_VEX_PP_SHIFT, + E_VEX_F2 = 3 << E_VEX_PP_SHIFT, + E_XOP_P00 = 0 << E_VEX_PP_SHIFT, + E_XOP_P01 = 1 << E_VEX_PP_SHIFT, + + E_VEX_128 = E_VEX, + E_VEX_256 = E_VEX | E_VEX_L, + E_VEX_LIG = E_VEX, + E_VEX_LZ = E_VEX, + E_VEX_66_0F = E_VEX_66 | E_VEX_0F, + E_VEX_66_0F38 = E_VEX_66 | E_VEX_0F38, + E_VEX_66_0F3A = E_VEX_66 | E_VEX_0F3A, + E_VEX_F2_0F = E_VEX_F2 | E_VEX_0F, + E_VEX_F2_0F38 = E_VEX_F2 | E_VEX_0F38, + E_VEX_F2_0F3A = E_VEX_F2 | E_VEX_0F3A, + E_VEX_F3_0F = E_VEX_F3 | E_VEX_0F, + E_VEX_F3_0F38 = E_VEX_F3 | E_VEX_0F38, + E_VEX_F3_0F3A = E_VEX_F3 | E_VEX_0F3A, + E_VEX_W0 = 0, + E_VEX_W1 = E_VEX_W, + E_VEX_WIG = 0, + E_XOP_128 = E_XOP, + E_XOP_256 = E_XOP | E_VEX_L, + E_XOP_W0 = 0, + E_XOP_W1 = E_VEX_W, + + // Aliases + E_VEX_128_0F_WIG = E_VEX_128 | E_VEX_0F | E_VEX_WIG, + E_VEX_256_0F_WIG = E_VEX_256 | E_VEX_0F | E_VEX_WIG, + E_VEX_128_66_0F_WIG = E_VEX_128 | E_VEX_66_0F | E_VEX_WIG, + E_VEX_256_66_0F_WIG = E_VEX_256 | E_VEX_66_0F | E_VEX_WIG, + E_VEX_128_66_0F38_WIG = E_VEX_128 | E_VEX_66_0F38 | E_VEX_WIG, + E_VEX_256_66_0F38_WIG = E_VEX_256 | E_VEX_66_0F38 | E_VEX_WIG, + E_VEX_128_66_0F38_W0 = E_VEX_128 | E_VEX_66_0F38 | E_VEX_W0, + E_VEX_256_66_0F38_W0 = E_VEX_256 | E_VEX_66_0F38 | E_VEX_W0, + E_VEX_128_66_0F38_W1 = E_VEX_128 | E_VEX_66_0F38 | E_VEX_W1, + E_VEX_256_66_0F38_W1 = E_VEX_256 | E_VEX_66_0F38 | E_VEX_W1, + E_VEX_128_66_0F3A_W0 = E_VEX_128 | E_VEX_66_0F3A | E_VEX_W0, + E_VEX_256_66_0F3A_W0 = E_VEX_256 | E_VEX_66_0F3A | E_VEX_W0, +}; + +/// Instruction +struct Instr +{ + static const size_t MAX_OPERAND_COUNT = 6; + + InstrID id_; ///< Instruction ID + uint32 opcode_; ///< Opcode + uint32 encoding_flag_; ///< EncodingFlags + detail::Opd opd_[MAX_OPERAND_COUNT]; ///< Operands + + Instr(InstrID id, uint32 opcode, uint32 encoding_flag, const detail::Opd& opd1 = detail::Opd(), const detail::Opd& opd2 = detail::Opd(), const detail::Opd& opd3 = detail::Opd(), const detail::Opd& opd4 = detail::Opd(), const detail::Opd& opd5 = detail::Opd(), const detail::Opd& opd6 = detail::Opd()) + : id_(id), opcode_(opcode), encoding_flag_(encoding_flag) {opd_[0] = opd1, opd_[1] = opd2, opd_[2] = opd3, opd_[3] = opd4, opd_[4] = opd5, opd_[5] = opd6;} + + InstrID GetID() const {return id_;} + const detail::Opd& GetOpd(size_t index) const {return opd_[index];} + detail::Opd& GetOpd(size_t index) {return opd_[index];} +}; + +/// Assembler backend +struct Backend +{ + uint8* pbuff_; + size_t buffsize_; + size_t size_; + + Backend(void* pbuff = NULL, size_t buffsize = 0) : pbuff_((uint8*) pbuff), buffsize_(buffsize), size_(0) + { + memset(pbuff, 0xCC, buffsize); // INT3 + } + + size_t GetSize() const + { + return size_; + } + + void put_bytes(void* p, size_t n) + { + uint8* pb = (uint8*) p; + while (n--) { + if (pbuff_) { + if (size_ == buffsize_) JITASM_ASSERT(0); + pbuff_[size_] = *pb++; + } + size_++; + } + } + void db(uint64 b) {put_bytes(&b, 1);} + void dw(uint64 w) {put_bytes(&w, 2);} + void dd(uint64 d) {put_bytes(&d, 4);} + void dq(uint64 q) {put_bytes(&q, 8);} + + uint8 GetWRXB(int w, const detail::Opd& reg, const detail::Opd& r_m) + { + uint8 wrxb = w ? 8 : 0; + if (reg.IsReg()) { + if (!reg.GetReg().IsInvalid() && reg.GetReg().id >= R8) wrxb |= 4; + } + if (r_m.IsReg()) { + if (r_m.GetReg().id >= R8) wrxb |= 1; + } + if (r_m.IsMem()) { + if (!r_m.GetIndex().IsInvalid() && r_m.GetIndex().id >= R8) wrxb |= 2; + if (!r_m.GetBase().IsInvalid() && r_m.GetBase().id >= R8) wrxb |= 1; + } + return wrxb; + } + + void EncodePrefixes(uint32 flag, const detail::Opd& reg, const detail::Opd& r_m, const detail::Opd& vex) + { + if (flag & (E_VEX | E_XOP)) { + // Encode VEX prefix +#ifdef JITASM64 + if (r_m.IsMem() && r_m.GetAddressSize() != O_SIZE_64) db(0x67); +#endif + uint8 vvvv = vex.IsReg() ? 0xF - (uint8) vex.GetReg().id : 0xF; + uint8 mmmmm = (flag & E_VEX_MMMMM_MASK) >> E_VEX_MMMMM_SHIFT; + uint8 pp = static_cast((flag & E_VEX_PP_MASK) >> E_VEX_PP_SHIFT); + uint8 wrxb = GetWRXB(flag & E_VEX_W, reg, r_m); + if (flag & E_XOP) { + db(0x8F); + db((~wrxb & 7) << 5 | mmmmm); + db((wrxb & 8) << 4 | vvvv << 3 | (flag & E_VEX_L ? 4 : 0) | pp); + } else if (wrxb & 0xB || (flag & E_VEX_MMMMM_MASK) == E_VEX_0F38 || (flag & E_VEX_MMMMM_MASK) == E_VEX_0F3A) { + db(0xC4); + db((~wrxb & 7) << 5 | mmmmm); + db((wrxb & 8) << 4 | vvvv << 3 | (flag & E_VEX_L ? 4 : 0) | pp); + } else { + db(0xC5); + db((~wrxb & 4) << 5 | vvvv << 3 | (flag & E_VEX_L ? 4 : 0) | pp); + } + } else { + uint8 wrxb = GetWRXB(flag & E_REXW_PREFIX, reg, r_m); + if (wrxb) { + // Encode REX prefix + JITASM_ASSERT(!reg.IsReg() || reg.GetSize() != O_SIZE_8 || reg.GetReg().id < AH || reg.GetReg().id >= R8B); // AH, BH, CH, or DH may not be used with REX. + JITASM_ASSERT(!r_m.IsReg() || r_m.GetSize() != O_SIZE_8 || r_m.GetReg().id < AH || r_m.GetReg().id >= R8B); // AH, BH, CH, or DH may not be used with REX. + + if (flag & E_REP_PREFIX) db(0xF3); +#ifdef JITASM64 + if (r_m.IsMem() && r_m.GetAddressSize() != O_SIZE_64) db(0x67); +#endif + if (flag & E_OPERAND_SIZE_PREFIX) db(0x66); + + if (flag & E_MANDATORY_PREFIX_66) db(0x66); + else if (flag & E_MANDATORY_PREFIX_F2) db(0xF2); + else if (flag & E_MANDATORY_PREFIX_F3) db(0xF3); + + db(0x40 | wrxb); + } else { + if (flag & E_MANDATORY_PREFIX_66) db(0x66); + else if (flag & E_MANDATORY_PREFIX_F2) db(0xF2); + else if (flag & E_MANDATORY_PREFIX_F3) db(0xF3); + + if (flag & E_REP_PREFIX) db(0xF3); +#ifdef JITASM64 + if (r_m.IsMem() && r_m.GetAddressSize() != O_SIZE_64) db(0x67); +#endif + if (flag & E_OPERAND_SIZE_PREFIX) db(0x66); + } + } + } + + void EncodeModRM(uint8 reg, const detail::Opd& r_m) + { + reg &= 0x7; + + if (r_m.IsReg()) { + db(0xC0 | (reg << 3) | (r_m.GetReg().id & 0x7)); + } else if (r_m.IsMem()) { + JITASM_ASSERT(r_m.GetBase().type == R_TYPE_GP && r_m.GetIndex().type == R_TYPE_GP); + int base = r_m.GetBase().id; if (base != INVALID) base &= 0x7; + int index = r_m.GetIndex().id; if (index != INVALID) index &= 0x7; + + if (base == INVALID && index == INVALID) { +#ifdef JITASM64 + db(reg << 3 | 4); + db(0x25); +#else + db(reg << 3 | 5); +#endif + dd(r_m.GetDisp()); + } else { + JITASM_ASSERT(base != ESP || index != ESP); + JITASM_ASSERT(index != ESP || r_m.GetScale() == 0); + + if (index == ESP) { + index = base; + base = ESP; + } + bool sib = index != INVALID || r_m.GetScale() || base == ESP; + + // ModR/M + uint8 mod = 0; + if (r_m.GetDisp() == 0 || (sib && base == INVALID)) mod = base != EBP ? 0 : 1; + else if (detail::IsInt8(r_m.GetDisp())) mod = 1; + else if (detail::IsInt32(r_m.GetDisp())) mod = 2; + else JITASM_ASSERT(0); + db(mod << 6 | reg << 3 | (sib ? 4 : base)); + + // SIB + if (sib) { + uint8 ss = 0; + if (r_m.GetScale() == 0) ss = 0; + else if (r_m.GetScale() == 2) ss = 1; + else if (r_m.GetScale() == 4) ss = 2; + else if (r_m.GetScale() == 8) ss = 3; + else JITASM_ASSERT(0); + if (index != INVALID && base != INVALID) { + db(ss << 6 | index << 3 | base); + } else if (base != INVALID) { + db(ss << 6 | 4 << 3 | base); + } else if (index != INVALID) { + db(ss << 6 | index << 3 | 5); + } else { + JITASM_ASSERT(0); + } + } + + // Displacement + if (mod == 0 && sib && base == INVALID) dd(r_m.GetDisp()); + if (mod == 1) db(r_m.GetDisp()); + if (mod == 2) dd(r_m.GetDisp()); + } + } else { + JITASM_ASSERT(0); + } + } + + void EncodeOpcode(uint32 opcode) + { + if (opcode & 0xFF000000) db((opcode >> 24) & 0xFF); + if (opcode & 0xFFFF0000) db((opcode >> 16) & 0xFF); + if (opcode & 0xFFFFFF00) db((opcode >> 8) & 0xFF); + db(opcode & 0xFF); + } + + void EncodeImm(const detail::Opd& imm) + { + const OpdSize size = imm.GetSize(); + if (size == O_SIZE_8) db(imm.GetImm()); + else if (size == O_SIZE_16) dw(imm.GetImm()); + else if (size == O_SIZE_32) dd(imm.GetImm()); + else if (size == O_SIZE_64) dq(imm.GetImm()); + else JITASM_ASSERT(0); + } + + void Encode(const Instr& instr) + { + uint32 opcode = instr.opcode_; + + const detail::Opd& opd1 = instr.GetOpd(0).IsDummy() ? detail::Opd() : instr.GetOpd(0); JITASM_ASSERT(!(opd1.IsReg() && opd1.GetReg().IsSymbolic())); + const detail::Opd& opd2 = instr.GetOpd(1).IsDummy() ? detail::Opd() : instr.GetOpd(1); JITASM_ASSERT(!(opd2.IsReg() && opd2.GetReg().IsSymbolic())); + const detail::Opd& opd3 = instr.GetOpd(2).IsDummy() ? detail::Opd() : instr.GetOpd(2); JITASM_ASSERT(!(opd3.IsReg() && opd3.GetReg().IsSymbolic())); + const detail::Opd& opd4 = instr.GetOpd(3).IsDummy() ? detail::Opd() : instr.GetOpd(3); JITASM_ASSERT(!(opd4.IsReg() && opd4.GetReg().IsSymbolic())); + + // +rb, +rw, +rd, +ro + if (opd1.IsReg() && (opd2.IsNone() || opd2.IsImm())) { + opcode += opd1.GetReg().id & 0x7; + } + + if ((opd1.IsImm() || opd1.IsReg()) && (opd2.IsReg() || opd2.IsMem())) { // ModR/M + const detail::Opd& reg = opd1; + const detail::Opd& r_m = opd2; + const detail::Opd& vex = opd3; + EncodePrefixes(instr.encoding_flag_, reg, r_m, vex); + EncodeOpcode(opcode); + EncodeModRM((uint8) (reg.IsImm() ? reg.GetImm() : reg.GetReg().id), r_m); + + // /is4 + if (opd4.IsReg()) { + EncodeImm(Imm8(static_cast(opd4.GetReg().id << 4))); + } + } else { + const detail::Opd& reg = detail::Opd(); + const detail::Opd& r_m = opd1.IsReg() ? opd1 : detail::Opd(); + const detail::Opd& vex = detail::Opd(); + EncodePrefixes(instr.encoding_flag_, reg, r_m, vex); + EncodeOpcode(opcode); + } + + if (opd1.IsImm() && !opd2.IsReg() && !opd2.IsMem()) EncodeImm(opd1); + if (opd2.IsImm()) EncodeImm(opd2); + if (opd3.IsImm()) EncodeImm(opd3); + if (opd4.IsImm()) EncodeImm(opd4); + } + + void EncodeALU(const Instr& instr, uint32 opcode) + { + const detail::Opd& reg = instr.GetOpd(1); + const detail::Opd& imm = instr.GetOpd(2); + JITASM_ASSERT(instr.GetOpd(0).IsImm() && reg.IsReg() && imm.IsImm()); + + if (reg.GetReg().id == EAX && (reg.GetSize() == O_SIZE_8 || !detail::IsInt8(imm.GetImm()))) { + opcode |= (reg.GetSize() == O_SIZE_8 ? 0 : 1); + Encode(Instr(instr.GetID(), opcode, instr.encoding_flag_, reg, imm)); + } else { + Encode(instr); + } + } + + void EncodeJMP(const Instr& instr) + { + const detail::Opd& imm = instr.GetOpd(0); + if (instr.GetID() == I_JMP) { + Encode(Instr(instr.GetID(), imm.GetSize() == O_SIZE_8 ? 0xEB : 0xE9, instr.encoding_flag_, imm)); + } else if (instr.GetID() == I_JCC) { +#ifndef JITASM64 + uint32 tttn = instr.opcode_; + if (tttn == JCC_CXZ) Encode(Instr(instr.GetID(), 0x67E3, instr.encoding_flag_, imm)); + else if (tttn == JCC_ECXZ) Encode(Instr(instr.GetID(), 0xE3, instr.encoding_flag_, imm)); + else Encode(Instr(instr.GetID(), (imm.GetSize() == O_SIZE_8 ? 0x70 : 0x0F80) | tttn, instr.encoding_flag_, imm)); +#else + uint32 tttn = instr.opcode_; + if (tttn == JCC_ECXZ) Encode(Instr(instr.GetID(), 0x67E3, instr.encoding_flag_, imm)); + else if (tttn == JCC_RCXZ) Encode(Instr(instr.GetID(), 0xE3, instr.encoding_flag_, imm)); + else Encode(Instr(instr.GetID(), (imm.GetSize() == O_SIZE_8 ? 0x70 : 0x0F80) | tttn, instr.encoding_flag_, imm)); +#endif + } else if (instr.GetID() == I_LOOP) { + Encode(Instr(instr.GetID(), instr.opcode_, instr.encoding_flag_, imm)); + } else { + JITASM_ASSERT(0); + } + } + + void EncodeMOV(const Instr& instr) + { +#ifndef JITASM64 + const detail::Opd& reg = instr.GetOpd(0); + const detail::Opd& mem = instr.GetOpd(1); + JITASM_ASSERT(reg.IsReg() && mem.IsMem()); + + if (reg.GetReg().id == EAX && mem.GetBase().IsInvalid() && mem.GetIndex().IsInvalid()) { + uint32 opcode = 0xA0 | (~instr.opcode_ & 0x2) | (instr.opcode_ & 1); + Encode(Instr(instr.GetID(), opcode, instr.encoding_flag_, Imm32((sint32) mem.GetDisp()))); + } else { + Encode(instr); + } +#else + Encode(instr); +#endif + } + + void EncodeTEST(const Instr& instr) + { + const detail::Opd& reg = instr.GetOpd(1); + const detail::Opd& imm = instr.GetOpd(2); + JITASM_ASSERT(instr.GetOpd(0).IsImm() && reg.IsReg() && imm.IsImm()); + + if (reg.GetReg().id == EAX) { + uint32 opcode = 0xA8 | (reg.GetSize() == O_SIZE_8 ? 0 : 1); + Encode(Instr(instr.GetID(), opcode, instr.encoding_flag_, reg, imm)); + } else { + Encode(instr); + } + } + + void EncodeXCHG(const Instr& instr) + { + const detail::Opd& dst = instr.GetOpd(0); + const detail::Opd& src = instr.GetOpd(1); + JITASM_ASSERT(dst.IsReg() && src.IsReg()); + + if (dst.GetReg().id == EAX) { + Encode(Instr(instr.GetID(), 0x90, instr.encoding_flag_, src)); + } else if (src.GetReg().id == EAX) { + Encode(Instr(instr.GetID(), 0x90, instr.encoding_flag_, dst)); + } else { + Encode(instr); + } + } + + void Assemble(const Instr& instr) + { + if (instr.encoding_flag_ & E_SPECIAL) { + switch (instr.GetID()) { + case I_ADD: EncodeALU(instr, 0x04); break; + case I_OR: EncodeALU(instr, 0x0C); break; + case I_ADC: EncodeALU(instr, 0x14); break; + case I_SBB: EncodeALU(instr, 0x1C); break; + case I_AND: EncodeALU(instr, 0x24); break; + case I_SUB: EncodeALU(instr, 0x2C); break; + case I_XOR: EncodeALU(instr, 0x34); break; + case I_CMP: EncodeALU(instr, 0x3C); break; + case I_JMP: EncodeJMP(instr); break; + case I_JCC: EncodeJMP(instr); break; + case I_LOOP: EncodeJMP(instr); break; + case I_MOV: EncodeMOV(instr); break; + case I_TEST: EncodeTEST(instr); break; + case I_XCHG: EncodeXCHG(instr); break; + default: JITASM_ASSERT(0); break; + } + } else { + Encode(instr); + } + } + + static size_t GetInstrCodeSize(const Instr& instr) + { + Backend backend; + backend.Assemble(instr); + return backend.GetSize(); + } +}; + +namespace detail +{ + /// Counting 1-Bits + inline uint32 Count1Bits(uint32 x) + { + x = x - ((x >> 1) & 0x55555555); + x = (x & 0x33333333) + ((x >> 2) & 0x33333333); + x = (x + (x >> 4)) & 0x0F0F0F0F; + x = x + (x >> 8); + x = x + (x >> 16); + return x & 0x0000003F; + } + + /// The bit position of the first bit 1. + inline uint32 bit_scan_forward(uint32 x) + { + JITASM_ASSERT(x != 0); +#if defined(JITASM_GCC) + return __builtin_ctz(x); +#else + unsigned long index; + _BitScanForward(&index, x); + return index; +#endif + } + + /// The bit position of the last bit 1. + inline uint32 bit_scan_reverse(uint32 x) + { + JITASM_ASSERT(x != 0); +#if defined(JITASM_GCC) + return 31 - __builtin_clz(x); +#else + unsigned long index; + _BitScanReverse(&index, x); + return index; +#endif + } + + /// Prior iterator + template It prior(const It &it) { + It i = it; + return --i; + } + + /// Next iterator + template It next(const It &it) { + It i = it; + return ++i; + } + + /// Iterator range + template struct Range : std::pair { + typedef It Iterator; + Range() : std::pair() {} + Range(const It& f, const It& s) : std::pair(f, s) {} + Range(T& container) : std::pair(container.begin(), container.end()) {} + bool empty() const {return this->first == this->second;} + size_t size() const {return std::distance(this->first, this->second);} + }; + + /// Const iterator range + template struct ConstRange : Range { + ConstRange() : Range() {} + ConstRange(const typename T::const_iterator& f, const typename T::const_iterator& s) : Range(f, s) {} + ConstRange(const T& container) : Range(container.begin(), container.end()) {} + }; + + inline void append_num(std::string& str, size_t num) + { + if (num >= 10) + append_num(str, num / 10); + str.append(1, static_cast('0' + num % 10)); + } + +#if defined(JITASM_WIN) + /// Debug trace + inline void Trace(const char *format, ...) + { + char szBuf[256]; + va_list args; + va_start(args, format); +#if _MSC_VER >= 1400 // VC8 or later + _vsnprintf_s(szBuf, sizeof(szBuf) / sizeof(char), format, args); +#else + vsnprintf(szBuf, sizeof(szBuf) / sizeof(char), format, args); +#endif + va_end(args); + ::OutputDebugStringA(szBuf); + } +#endif + + /// Executable code buffer + class CodeBuffer + { + void* pbuff_; + size_t codesize_; + size_t buffsize_; + + public: + CodeBuffer() : pbuff_(NULL), codesize_(0), buffsize_(0) {} + ~CodeBuffer() {Reset(0);} + + void* GetPointer() const {return pbuff_;} + size_t GetCodeSize() const {return codesize_;} + size_t GetBufferSize() const {return buffsize_;} + + bool Reset(size_t codesize) + { + if (pbuff_) { +#if defined(JITASM_WIN) + ::VirtualFree(pbuff_, 0, MEM_RELEASE); +#else + munmap(pbuff_, buffsize_); +#endif + pbuff_ = NULL; + codesize_ = 0; + buffsize_ = 0; + } + if (codesize) { +#if defined(JITASM_WIN) + void* pbuff = ::VirtualAlloc(NULL, codesize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if (!pbuff) { + JITASM_ASSERT(0); + return false; + } + MEMORY_BASIC_INFORMATION info; + ::VirtualQuery(pbuff, &info, sizeof(info)); + buffsize_ = info.RegionSize; +#else + int pagesize = getpagesize(); + size_t buffsize = (codesize + pagesize - 1) / pagesize * pagesize; + void* pbuff = mmap(NULL, buffsize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, -1, 0); + if (!pbuff) { + JITASM_ASSERT(0); + return false; + } + buffsize_ = buffsize; +#endif + + pbuff_ = pbuff; + codesize_ = codesize; + } + return true; + } + }; + + /// Stack manager + /** + * Stack layout + * \verbatim + * +-----------------------+ + * | Caller return address | + * +=======================+======== + * | ebp (rbp) | + * +-----------------------+ <-- ebp (rbp) + * | Saved gp registers | + * +-----------------------+ + * | Padding for alignment | + * +-----------------------+ <-- Stack base + * | Spill slots and | + * | local variable | + * +-----------------------+ <-- esp (rsp) + * \endverbatim + */ + class StackManager + { + private: + Addr stack_base_; + uint32 stack_size_; + + public: + StackManager() : stack_base_(RegID::CreatePhysicalRegID(R_TYPE_GP, EBX), 0), stack_size_(0) {} + + /// Get allocated stack size + uint32 GetSize() const {return (stack_size_ + 15) / 16 * 16; /* 16 bytes aligned*/} + + /// Get stack base + Addr GetStackBase() const {return stack_base_;} + + /// Set stack base + void SetStackBase(const Addr& stack_base) {stack_base_ = stack_base;} + + /// Allocate stack + Addr Alloc(uint32 size, uint32 alignment) + { + stack_size_ = (stack_size_ + alignment - 1) / alignment * alignment; + stack_size_ += size; + return stack_base_ - stack_size_; + } + }; + + /// Spin lock + class SpinLock + { + long lock_; + public: + SpinLock() : lock_(0) {} + void Lock() {while (interlocked_exchange(&lock_, 1));} + void Unlock() {interlocked_exchange(&lock_, 0);} + }; + + template + class ScopedLock + { + Ty& lock_; + ScopedLock& operator=(const ScopedLock&); + public: + ScopedLock(Ty& lock) : lock_(lock) {lock.Lock();} + ~ScopedLock() {lock_.Unlock();} + }; +} // namespace detail + +// compiler prototype declaration +struct Frontend; +namespace compiler { + void Compile(Frontend& f); +} + +/// jitasm frontend +struct Frontend +{ + typedef jitasm::Addr Addr; + typedef jitasm::Reg Reg; + typedef jitasm::Reg8 Reg8; + typedef jitasm::Reg16 Reg16; + typedef jitasm::Reg32 Reg32; +#ifdef JITASM64 + typedef jitasm::Reg64 Reg64; +#endif + typedef jitasm::MmxReg MmxReg; + typedef jitasm::XmmReg XmmReg; + typedef jitasm::YmmReg YmmReg; + + Reg8_al al; + Reg8_cl cl; + Reg8 dl, bl, ah, ch, dh, bh; + Reg16_ax ax; + Reg16_dx dx; + Reg16 cx, bx, sp, bp, si, di; + Reg32_eax eax; + Reg32 ecx, edx, ebx, esp, ebp, esi, edi; + FpuReg_st0 st0; + FpuReg st1, st2, st3, st4, st5, st6, st7; + MmxReg mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7; + XmmReg xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7; + YmmReg ymm0, ymm1, ymm2, ymm3, ymm4, ymm5, ymm6, ymm7; +#ifdef JITASM64 + Reg8 r8b, r9b, r10b, r11b, r12b, r13b, r14b, r15b; + Reg16 r8w, r9w, r10w, r11w, r12w, r13w, r14w, r15w; + Reg32 r8d, r9d, r10d, r11d, r12d, r13d, r14d, r15d; + Reg64_rax rax; + Reg64 rcx, rdx, rbx, rsp, rbp, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15; + XmmReg xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15; + YmmReg ymm8, ymm9, ymm10, ymm11, ymm12, ymm13, ymm14, ymm15; +#endif + + AddressingPtr byte_ptr; + AddressingPtr word_ptr; + AddressingPtr dword_ptr; + AddressingPtr qword_ptr; + AddressingPtr mmword_ptr; + AddressingPtr xmmword_ptr; + AddressingPtr ymmword_ptr; + AddressingPtr real4_ptr; + AddressingPtr real8_ptr; + AddressingPtr real10_ptr; + AddressingPtr m2byte_ptr; + AddressingPtr m28byte_ptr; + AddressingPtr m108byte_ptr; + AddressingPtr m512byte_ptr; + + Reg zcx, zdx, zbx, zsp, zbp, zsi, zdi; +#ifdef JITASM64 + Reg64_rax zax; + AddressingPtr ptr; +#else + Reg32_eax zax; + AddressingPtr ptr; +#endif + + Frontend() + : dl(DL), bl(BL), ah(AH), ch(CH), dh(DH), bh(BH), + cx(CX), bx(BX), sp(SP), bp(BP), si(SI), di(DI), + ecx(ECX), edx(EDX), ebx(EBX), esp(ESP), ebp(EBP), esi(ESI), edi(EDI), + st1(ST1), st2(ST2), st3(ST3), st4(ST4), st5(ST5), st6(ST6), st7(ST7), + mm0(MM0), mm1(MM1), mm2(MM2), mm3(MM3), mm4(MM4), mm5(MM5), mm6(MM6), mm7(MM7), + xmm0(XMM0), xmm1(XMM1), xmm2(XMM2), xmm3(XMM3), xmm4(XMM4), xmm5(XMM5), xmm6(XMM6), xmm7(XMM7), + ymm0(YMM0), ymm1(YMM1), ymm2(YMM2), ymm3(YMM3), ymm4(YMM4), ymm5(YMM5), ymm6(YMM6), ymm7(YMM7), +#ifdef JITASM64 + r8b(R8B), r9b(R9B), r10b(R10B), r11b(R11B), r12b(R12B), r13b(R13B), r14b(R14B), r15b(R15B), + r8w(R8W), r9w(R9W), r10w(R10W), r11w(R11W), r12w(R12W), r13w(R13W), r14w(R14W), r15w(R15W), + r8d(R8D), r9d(R9D), r10d(R10D), r11d(R11D), r12d(R12D), r13d(R13D), r14d(R14D), r15d(R15D), + rcx(RCX), rdx(RDX), rbx(RBX), rsp(RSP), rbp(RBP), rsi(RSI), rdi(RDI), + r8(R8), r9(R9), r10(R10), r11(R11), r12(R12), r13(R13), r14(R14), r15(R15), + xmm8(XMM8), xmm9(XMM9), xmm10(XMM10), xmm11(XMM11), xmm12(XMM12), xmm13(XMM13), xmm14(XMM14), xmm15(XMM15), + ymm8(YMM8), ymm9(YMM9), ymm10(YMM10), ymm11(YMM11), ymm12(YMM12), ymm13(YMM13), ymm14(YMM14), ymm15(YMM15), + zcx(RCX), zdx(RDX), zbx(RBX), zsp(RSP), zbp(RBP), zsi(RSI), zdi(RDI), +#else + zcx(ECX), zdx(EDX), zbx(EBX), zsp(ESP), zbp(EBP), zsi(ESI), zdi(EDI), +#endif + assembled_(false) + { + } + + virtual ~Frontend() {} + + typedef std::vector InstrList; + InstrList instrs_; + bool assembled_; + detail::CodeBuffer codebuff_; + detail::SpinLock codelock_; + detail::StackManager stack_manager_; + + struct Label + { + std::string name; + size_t instr_number; + explicit Label(const std::string& name_) : name(name_), instr_number(0) {} + }; + typedef std::deque