diff --git a/addons/sourcemod/gamedata/momsurffix2.games.txt b/addons/sourcemod/gamedata/momsurffix2.games.txt index 60d606d..fffdf1c 100644 --- a/addons/sourcemod/gamedata/momsurffix2.games.txt +++ b/addons/sourcemod/gamedata/momsurffix2.games.txt @@ -47,6 +47,22 @@ "CTraceFilterSimple::size" "16" } + "Addresses" + { + "CGameMovement::TryPlayerMove_Start" + { + "windows" + { + "signature" "CGameMovement::TryPlayerMove" + } + "linux" + { + "signature" "CGameMovement::TryPlayerMove" + } + "offset" "0" + } + } + "Offsets" { "OSType" diff --git a/addons/sourcemod/scripting/momsurffix/gamemovement.sp b/addons/sourcemod/scripting/momsurffix/gamemovement.sp index c331b9d..34ac84f 100644 --- a/addons/sourcemod/scripting/momsurffix/gamemovement.sp +++ b/addons/sourcemod/scripting/momsurffix/gamemovement.sp @@ -67,7 +67,7 @@ methodmap CGameMovement < AddressBase property int m_nTraceCount { public get() { return LoadFromAddress(this.Address + offsets.cgmoffsets.m_nTraceCount, NumberType_Int32); } - public set(int _tracecount) { StoreToAddress(this.Address + offsets.cgmoffsets.m_nTraceCount, _tracecount, NumberType_Int32); } + public set(int _tracecount) { StoreToAddressCustom(this.Address + offsets.cgmoffsets.m_nTraceCount, _tracecount, NumberType_Int32); } } } diff --git a/addons/sourcemod/scripting/momsurffix/gametrace.sp b/addons/sourcemod/scripting/momsurffix/gametrace.sp index c839566..6c7a795 100644 --- a/addons/sourcemod/scripting/momsurffix/gametrace.sp +++ b/addons/sourcemod/scripting/momsurffix/gametrace.sp @@ -279,25 +279,25 @@ methodmap CTraceFilterSimple < AllocatableBase property Address vptr { public get() { return view_as
(LoadFromAddress(this.Address + offsets.ctfsoffsets.vptr, NumberType_Int32)); } - public set(Address _vtbladdr) { StoreToAddress(this.Address + offsets.ctfsoffsets.vptr, view_as(_vtbladdr), NumberType_Int32); } + public set(Address _vtbladdr) { StoreToAddressCustom(this.Address + offsets.ctfsoffsets.vptr, view_as(_vtbladdr), NumberType_Int32); } } property CBaseHandle m_pPassEnt { public get() { return view_as(LoadFromAddress(this.Address + offsets.ctfsoffsets.m_pPassEnt, NumberType_Int32)); } - public set(CBaseHandle _passent) { StoreToAddress(this.Address + offsets.ctfsoffsets.m_pPassEnt, view_as(_passent), NumberType_Int32); } + public set(CBaseHandle _passent) { StoreToAddressCustom(this.Address + offsets.ctfsoffsets.m_pPassEnt, view_as(_passent), NumberType_Int32); } } property int m_collisionGroup { public get() { return LoadFromAddress(this.Address + offsets.ctfsoffsets.m_collisionGroup, NumberType_Int32); } - public set(int _collisiongroup) { StoreToAddress(this.Address + offsets.ctfsoffsets.m_collisionGroup, _collisiongroup, NumberType_Int32); } + public set(int _collisiongroup) { StoreToAddressCustom(this.Address + offsets.ctfsoffsets.m_collisionGroup, _collisiongroup, NumberType_Int32); } } property Address m_pExtraShouldHitCheckFunction { public get() { return view_as
(LoadFromAddress(this.Address + offsets.ctfsoffsets.m_pExtraShouldHitCheckFunction, NumberType_Int32)); } - public set(Address _checkfnc) { StoreToAddress(this.Address + offsets.ctfsoffsets.m_pExtraShouldHitCheckFunction, view_as(_checkfnc), NumberType_Int32); } + public set(Address _checkfnc) { StoreToAddressCustom(this.Address + offsets.ctfsoffsets.m_pExtraShouldHitCheckFunction, view_as(_checkfnc), NumberType_Int32); } } public CTraceFilterSimple() diff --git a/addons/sourcemod/scripting/momsurffix/utils.sp b/addons/sourcemod/scripting/momsurffix/utils.sp index 7aa081f..6c2e240 100644 --- a/addons/sourcemod/scripting/momsurffix/utils.sp +++ b/addons/sourcemod/scripting/momsurffix/utils.sp @@ -71,19 +71,19 @@ methodmap Vector < AllocatableBase property float x { - public set(float _x) { StoreToAddress(this.Address, view_as(_x), NumberType_Int32); } + public set(float _x) { StoreToAddressCustom(this.Address, view_as(_x), NumberType_Int32); } public get() { return view_as(LoadFromAddress(this.Address, NumberType_Int32)); } } property float y { - public set(float _y) { StoreToAddress(this.Address + 4, view_as(_y), NumberType_Int32); } + public set(float _y) { StoreToAddressCustom(this.Address + 4, view_as(_y), NumberType_Int32); } public get() { return view_as(LoadFromAddress(this.Address + 4, NumberType_Int32)); } } property float z { - public set(float _z) { StoreToAddress(this.Address + 8, view_as(_z), NumberType_Int32); } + public set(float _z) { StoreToAddressCustom(this.Address + 8, view_as(_z), NumberType_Int32); } public get() { return view_as(LoadFromAddress(this.Address + 8, NumberType_Int32)); } } diff --git a/addons/sourcemod/scripting/momsurffix2.sp b/addons/sourcemod/scripting/momsurffix2.sp index 37805d3..1b884a3 100644 --- a/addons/sourcemod/scripting/momsurffix2.sp +++ b/addons/sourcemod/scripting/momsurffix2.sp @@ -11,13 +11,16 @@ public Plugin myinfo = { name = "Momentum surf fix \'2", author = "GAMMA CASE", description = "Ported surf fix from momentum mod.", - version = "1.0.5", + version = "1.0.6", url = "http://steamcommunity.com/id/_GAMMACASE_/" }; #define FLT_EPSILON 1.192092896e-07 #define MAX_CLIP_PLANES 5 +#define ASM_PATCH_LEN 24 +#define ASM_START_OFFSET 100 + enum OSType { OSUnknown = -1, @@ -36,23 +39,31 @@ EngineVersion gEngineVersion; #include "momsurffix/gametrace.sp" #include "momsurffix/gamemovement.sp" -ConVar gRampBumpCount, gBounce, gRampInitialRetraceLength; +ConVar gRampBumpCount, + gBounce, + gRampInitialRetraceLength, + gASMOptimizations, + gNoclipWorkAround; float vec3_origin[3] = {0.0, 0.0, 0.0}; bool gBasePlayerLoadedTooEarly; +PatchHandler gASMPatch; +Handle gStoreToAddressFast; +Address gTryPlayerMoveStart; + #if defined DEBUG_PROFILE #include "profiler" -#define PROF_START if(gProf) gProf.Start() -#define PROF_STOP%1; if(gProf)\ +#define PROF_START() if(gProf) gProf.Start() +#define PROF_STOP(%1)%2; if(gProf)\ {\ gProf.Stop();\ - Prof_Check();\ + Prof_Check(%1);\ } Profiler gProf; -float gTotal; -int gTotalCount, gTotalCountNeeded; +ArrayList gProfData; +float gProfTime; #else #define PROF_START%1; #define PROF_STOP%1; @@ -68,8 +79,10 @@ public void OnPluginStart() gRampBumpCount = CreateConVar("momsuffix_ramp_bumpcount", "8", "Helps with fixing surf/ramp bugs", .hasMin = true, .min = 4.0, .hasMax = true, .max = 16.0); gRampInitialRetraceLength = CreateConVar("momsuffix_ramp_initial_retrace_length", "0.2", "Amount of units used in offset for retraces", .hasMin = true, .min = 0.2, .hasMax = true, .max = 5.0); + gASMOptimizations = CreateConVar("momsuffix_enable_asm_optimizations", "1", "Enables ASM optimizations, that may improve performance of the plugin", .hasMin = true, .min = 0.0, .hasMax = true, .max = 1.0); + gNoclipWorkAround = CreateConVar("momsuffix_enable_noclip_workaround", "1", "Enables workaround to prevent issue #1, can actually help if momsuffix_enable_asm_optimizations is 0", .hasMin = true, .min = 0.0, .hasMax = true, .max = 1.0); gBounce = FindConVar("sv_bounce"); - ASSERT(gBounce); + ASSERT_MSG(gBounce, "\"sv_bounce\" convar wasn't found!"); AutoExecConfig(); @@ -84,6 +97,7 @@ public void OnPluginStart() InitGameMovement(gd); SetupDhooks(gd); + SetupASMOptimizations(gd); delete gd; } @@ -102,6 +116,8 @@ public void OnMapStart() public void OnPluginEnd() { CleanUpUtils(); + if(gASMPatch.Address != Address_Null) + gASMPatch.Restore(); } public Action SM_Dumpmempool(int client, int args) @@ -116,39 +132,59 @@ public Action SM_Prof(int client, int args) { if(args < 1) { - ReplyToCommand(client, SNAME..."Usage: sm_prof "); + ReplyToCommand(client, SNAME..."Usage: sm_prof "); return Plugin_Handled; } char buff[32]; GetCmdArg(1, buff, sizeof(buff)); - gTotalCountNeeded = StringToInt(buff); + gProfTime = StringToFloat(buff); - if(gTotalCountNeeded <= 0) + if(gProfTime <= 0.1) { - ReplyToCommand(client, SNAME..."Only positive values allowed.") + ReplyToCommand(client, SNAME..."Time should be higher then 0.1 seconds.") return Plugin_Handled; } + gProfData = new ArrayList(3); gProf = new Profiler(); + CreateTimer(gProfTime, Prof_Check_Timer, client); - ReplyToCommand(client, SNAME..."Profiler started, awaiting %i iterations.", gTotalCountNeeded); + ReplyToCommand(client, SNAME..."Profiler started, awaiting %.2f seconds.", gProfTime); return Plugin_Handled; } -stock void Prof_Check() +stock void Prof_Check(int idx) { - gTotal += gProf.Time; - gTotalCount++; - - if(gTotalCount >= gTotalCountNeeded) + int idx2; + if(gProfData.Length - 1 < idx) + { + idx2 = gProfData.Push(gProf.Time); + gProfData.Set(idx2, 1, 1); + gProfData.Set(idx2, idx, 2); + } + else { - PrintToServer(SNAME..."Prifiling completed, avg time: %f", gTotal / float(gTotalCount)); + idx2 = gProfData.FindValue(idx, 2); - delete gProf; + gProfData.Set(idx2, view_as(gProfData.Get(idx2)) + gProf.Time); + gProfData.Set(idx2, gProfData.Get(idx2, 1) + 1, 1); } } + +public Action Prof_Check_Timer(Handle timer, int client) +{ + ReplyToCommand(client, SNAME..."Profiler finished:"); + if(gProfData.Length == 0) + ReplyToCommand(client, SNAME..."There was no profiling data..."); + + for(int i = 0; i < gProfData.Length; i++) + ReplyToCommand(client, SNAME..."[%i] Avg time: %f | Calls: %i", i, view_as(gProfData.Get(i)) / float(gProfData.Get(i, 1)), gProfData.Get(i, 1)); + + delete gProf; + delete gProfData; +} #endif /*CGameMovement dummy; @@ -158,6 +194,48 @@ public Action SM_TestMem(int client, int args) return Plugin_Handled; }*/ +void SetupASMOptimizations(GameData gd) +{ + //CGameMovement::TryPlayerMove_Start + gTryPlayerMoveStart = gd.GetAddress("CGameMovement::TryPlayerMove_Start"); + ASSERT_MSG(gTryPlayerMoveStart, "Can't find start of the \"CGameMovement::TryPlayerMove\" function."); + + gASMPatch = PatchHandler(gTryPlayerMoveStart + ASM_START_OFFSET); + gASMPatch.Save(ASM_PATCH_LEN); + + Address start = gASMPatch.Address; + + /*StoreToAddressFast asm: + * push ebp + * mov ebp, esp + * + * mov eax, [ebp + 12] + * mov ecx, [ebp + 8] + * mov [ecx], eax + * + * mov esp, ebp + * pop ebp + * ret 8 + */ + + StoreToAddress(start, 0x8B_EC_8B_55, NumberType_Int32); + StoreToAddress(start + 4, 0x4D_8B_0C_45, NumberType_Int32); + StoreToAddress(start + 8, 0x8B_01_89_08, NumberType_Int32); + StoreToAddress(start + 12, 0x08_C2_5D_E5, NumberType_Int32); + StoreToAddress(start + 16, 0x00, NumberType_Int8); + + //StoreToAddressFast + StartPrepSDKCall(SDKCall_Static); + + PrepSDKCall_SetAddress(start); + PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); + PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); + PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain); + + gStoreToAddressFast = EndPrepSDKCall(); + ASSERT(gStoreToAddressFast); +} + void ValidateGameAndOS(GameData gd) { gOSType = view_as(gd.GetOffset("OSType")); @@ -202,7 +280,8 @@ int TryPlayerMove(CGameMovement pThis, Vector pFirstDest, CGameTrace pFirstTrace Vector vecVelocity = pThis.mv.m_vecVelocity; vecVelocity.ToArray(original_velocity); vecVelocity.ToArray(primal_velocity); - pThis.mv.m_vecAbsOrigin.ToArray(fixed_origin); + Vector vecAbsOrigin = pThis.mv.m_vecAbsOrigin; + vecAbsOrigin.ToArray(fixed_origin); Vector plane_normal; static Vector alloced_vector, alloced_vector2; @@ -263,7 +342,7 @@ int TryPlayerMove(CGameMovement pThis, Vector pFirstDest, CGameTrace pFirstTrace alloced_vector.ToArray(valid_plane); } //TODO: should be replaced with normal solution!! Currently hack to fix issue #1. - else if(vecVelocity.z < -6.25 && vecVelocity.z > 0.0) + else if(!gNoclipWorkAround.BoolValue || (vecVelocity.z < -6.25 && vecVelocity.z > 0.0)) { //Quite heavy part of the code, should not be triggered much or else it'll impact performance by a lot!!! float offsets[3]; @@ -275,13 +354,13 @@ int TryPlayerMove(CGameMovement pThis, Vector pFirstDest, CGameTrace pFirstTrace float offset[3], offset_mins[3], offset_maxs[3], buff[3]; Ray_t ray = Ray_t(); - PROF_START; for(i = 0; i < 3; i++) { for(j = 0; j < 3; j++) { for(h = 0; h < 3; h++) { + PROF_START(); offset[0] = offsets[i]; offset[1] = offsets[j]; offset[2] = offsets[h]; @@ -304,7 +383,9 @@ int TryPlayerMove(CGameMovement pThis, Vector pFirstDest, CGameTrace pFirstTrace offset_maxs[1] /= 2.0; if(offset[2] < 0.0) offset_maxs[2] /= 2.0; + PROF_STOP(0); + PROF_START(); if(gEngineVersion == Engine_CSGO) ray.Init((AddVectors(fixed_origin, offset, buff), buff), (SubtractVectors(end, offset, offset), offset), (SubtractVectors(VectorToArray(GetPlayerMins(pThis)), offset_mins, offset_mins), offset_mins), @@ -313,11 +394,17 @@ int TryPlayerMove(CGameMovement pThis, Vector pFirstDest, CGameTrace pFirstTrace ray.Init((AddVectors(fixed_origin, offset, buff), buff), (SubtractVectors(end, offset, offset), offset), (SubtractVectors(VectorToArray(GetPlayerMinsCSS(pThis, alloced_vector)), offset_mins, offset_mins), offset_mins), (AddVectors(VectorToArray(GetPlayerMaxsCSS(pThis, alloced_vector2)), offset_maxs, offset_maxs), offset_maxs)); + PROF_STOP(1); + PROF_START(); UTIL_TraceRay(ray, MASK_PLAYERSOLID, pThis, COLLISION_GROUP_PLAYER_MOVEMENT, pm); + PROF_STOP(2); + PROF_START(); pm.plane.normal.FromArray(vec3_origin); + PROF_STOP(3); + PROF_START(); plane_normal = pm.plane.normal; //PrintToServer(SNAME..."DEBUG: TraceFired! plane_normal: [%f | %f | %f]", plane_normal.x, plane_normal.y, plane_normal.z); @@ -327,10 +414,10 @@ int TryPlayerMove(CGameMovement pThis, Vector pFirstDest, CGameTrace pFirstTrace valid_planes++; plane_normal.ToArray(valid_plane); } + PROF_STOP(4); } } } - PROF_STOP; ray.Free(); if(valid_planes > 0 && !CloseEnough(valid_plane, view_as({0.0, 0.0, 0.0}))) @@ -366,13 +453,11 @@ int TryPlayerMove(CGameMovement pThis, Vector pFirstDest, CGameTrace pFirstTrace if(stuck_on_ramp && has_valid_plane) { alloced_vector.FromArray(fixed_origin); - //TracePlayerBBoxCustom(pThis, fixed_origin, end, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, pm); TracePlayerBBox(pThis, alloced_vector, alloced_vector2, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, pm); pm.plane.normal.FromArray(valid_plane); } else - //TracePlayerBBoxCustom(pThis, VectorToArray(pThis.mv.m_vecAbsOrigin), end, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, pm); - TracePlayerBBox(pThis, pThis.mv.m_vecAbsOrigin, alloced_vector2, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, pm); + TracePlayerBBox(pThis, vecAbsOrigin, alloced_vector2, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, pm); } if(bumpcount > 0 && pThis.player.m_hGroundEntity == view_as
(-1) && !IsValidMovementTrace(pThis, pm)) @@ -382,20 +467,11 @@ int TryPlayerMove(CGameMovement pThis, Vector pFirstDest, CGameTrace pFirstTrace continue; } - /*if(pm.allsolid) - { - vecVelocity.FromArray(vec3_origin); - - pm.Free(); - return 4; - }*/ - if(pm.fraction > 0.0) { if((bumpcount == 0 || pThis.player.m_hGroundEntity != view_as
(-1)) && numbumps > 0 && pm.fraction == 1.0) { CGameTrace stuck = CGameTrace(); - //TracePlayerBBoxCustom(pThis, VectorToArray(pm.endpos), VectorToArray(pm.endpos), MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, stuck); TracePlayerBBox(pThis, pm.endpos, pm.endpos, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, stuck); if((stuck.startsolid || stuck.fraction != 1.0) && bumpcount == 0) @@ -421,8 +497,8 @@ int TryPlayerMove(CGameMovement pThis, Vector pFirstDest, CGameTrace pFirstTrace stuck_on_ramp = false; vecVelocity.ToArray(original_velocity); - pThis.mv.m_vecAbsOrigin.FromArray(VectorToArray(pm.endpos)); - pThis.mv.m_vecAbsOrigin.ToArray(fixed_origin); + vecAbsOrigin.FromArray(VectorToArray(pm.endpos)); + vecAbsOrigin.ToArray(fixed_origin); allFraction += pm.fraction; numplanes = 0; } @@ -452,6 +528,7 @@ int TryPlayerMove(CGameMovement pThis, Vector pFirstDest, CGameTrace pFirstTrace if(numplanes == 1 && pThis.player.m_MoveType == MOVETYPE_WALK && pThis.player.m_hGroundEntity != view_as
(-1)) { Vector vec1 = Vector(); + PROF_START(); if(planes[0][2] >= 0.7) { vec1.FromArray(original_velocity); @@ -469,6 +546,7 @@ int TryPlayerMove(CGameMovement pThis, Vector pFirstDest, CGameTrace pFirstTrace ClipVelocity(pThis, vec1, alloced_vector2, alloced_vector, 1.0 + gBounce.FloatValue * (1.0 - pThis.player.m_surfaceFriction)); alloced_vector.ToArray(new_velocity); } + PROF_STOP(5); vecVelocity.FromArray(new_velocity); VectorCopy(new_velocity, original_velocity); @@ -623,16 +701,6 @@ stock bool IsValidMovementTrace(CGameMovement pThis, CGameTrace tr) return true; } -/*stock void TracePlayerBBoxCustom(CGameMovement pThis, float start[3], float end[3], int mask, int collisionGroup, CGameTrace trace) -{ - Ray_t ray = Ray_t(); - - ray.Init(start, end, VectorToArray(GetPlayerMins(pThis)), VectorToArray(GetPlayerMaxs(pThis))); - UTIL_TraceRay(ray, mask, pThis, collisionGroup, trace); - - ray.Free(); -}*/ - stock void UTIL_TraceRay(Ray_t ray, int mask, CGameMovement gm, int collisionGroup, CGameTrace trace) { if(gEngineVersion == Engine_CSGO) @@ -658,4 +726,21 @@ stock void UTIL_TraceRay(Ray_t ray, int mask, CGameMovement gm, int collisionGro filter.Free(); } +} + +//Faster then native StoreToAddress by ~45 times. +stock void StoreToAddressFast(Address addr, any data) +{ + ASSERT(gStoreToAddressFast); + + int ret = SDKCall(gStoreToAddressFast, addr, data); + ASSERT(ret == data); +} + +stock void StoreToAddressCustom(Address addr, any data, NumberType type) +{ + if(gASMOptimizations.BoolValue && gStoreToAddressFast) + StoreToAddressFast(addr, data); + else + StoreToAddress(addr, view_as(data), type); } \ No newline at end of file