added functionality to check the map on a bunch of map specific plugins. this way we dont have to load/unload plugins that usually causes slow map changes or even causes crashes. momsurffix was compiled with sourcemod 1.11

This commit is contained in:
jenz 2024-08-04 16:56:23 +02:00
parent 0e5cc3175c
commit a296dd400c
8 changed files with 1575 additions and 882 deletions

View File

@ -30,7 +30,7 @@ public int GetEntityIndexByName(const char[] name, const char[] classname){
return -1;
}
public int FindEntityByClassnameWithin(int startEnt, const char[] classname, const float[3] origin, const float radius){ //Tested. Works properly.
public int FindEntityByClassnameWithin(int startEnt, const char[] classname, const float origin[3], const float radius){ //Tested. Works properly.
float torigin[3];
while((startEnt = FindEntityByClassname(startEnt,classname))!= -1){
GetOrigin(startEnt, torigin);
@ -39,7 +39,7 @@ public int FindEntityByClassnameWithin(int startEnt, const char[] classname, con
return -1;
}
public float TraceLine(const float[3] origin, const float[3] v2, int entity){ //Tested. Works properly
public float TraceLine(const float origin[3], const float v2[3], int entity){ //Tested. Works properly
Handle trace = TR_TraceRayFilterEx(origin, v2, CONTENTS_SOLID, RayType_EndPoint, TraceEntityFilterSelf, entity);
float pos[3], dist = 1.0;
if(TR_DidHit(trace)){
@ -55,27 +55,27 @@ public bool TraceEntityFilterSelf(int entity, int contentsMask, any data)
return (data != entity && entity > 64);
}
public void GetOrigin(int entity, float[3] buffer){ //Tested. Works properly.
public void GetOrigin(int entity, float buffer[3]){ //Tested. Works properly.
if(IsValidEntity(entity))
GetEntPropVector(entity, Prop_Send, "m_vecOrigin", buffer);
}
public void GetAngles(int entity, float[3] buffer){ //Gives you wrong values after spawn it via env_entity_maker
public void GetAngles(int entity, float buffer[3]){ //Gives you wrong values after spawn it via env_entity_maker
if(IsValidEntity(entity))
GetEntPropVector(entity, Prop_Send, "m_angRotation", buffer);
}
public void SetAngles(int entity, const float[3] buffer){ //Tested. Works properly.
public void SetAngles(int entity, const float buffer[3]){ //Tested. Works properly.
if(IsValidEntity(entity))
TeleportEntity(entity, NULL_VECTOR, buffer, NULL_VECTOR);
}
public void SetOrigin(int entity, const float[3] buffer){ //Tested. Works properly.
public void SetOrigin(int entity, const float buffer[3]){ //Tested. Works properly.
if(IsValidEntity(entity))
TeleportEntity(entity, buffer, NULL_VECTOR, NULL_VECTOR);
}
public void GetForwardVector(int entity, float[3] buffer) //Tested. Works properly.
public void GetForwardVector(int entity, float buffer[3]) //Tested. Works properly.
{
if(IsValidEntity(entity))
{
@ -85,7 +85,7 @@ public void GetForwardVector(int entity, float[3] buffer) //Tested. Works proper
}
}
public void SetForwardVector(int entity, const float[3] buffer) //Tested. Works properly.
public void SetForwardVector(int entity, const float buffer[3]) //Tested. Works properly.
{
if(IsValidEntity(entity))
{

View File

@ -208,7 +208,7 @@ const float DEFAULT_PER_FRAME_MAX_VEL_DELTA = 0.0003333; // 2.0 / (120.0 * 50.0)
const float DEFAULT_PER_FRAME_MAX_ACC_DELTA = 0.0000125; // 0.075 / (120.0 * 50.0);
#define PI 3.14159
public bool SphereCollideWithWorld(const float[3] orig, const float radius, float degree, float[3] buffer, int entity)
public bool SphereCollideWithWorld(const float orig[3], const float radius, float degree, float buffer[3], int entity)
{
float inc = PI / degree;
@ -371,22 +371,22 @@ methodmap Eye < Basic
}
}
public void GetVel(float[3] vel)
public void GetVel(float vel[3])
{
this.GetVector("vVel", vel);
}
public void SetVel(const float[3] vel)
public void SetVel(const float vel[3])
{
this.SetVector("vVel", vel);
}
public void GetAcc(float[3] acc)
public void GetAcc(float acc[3])
{
this.GetVector("vAcc", acc);
}
public void SetAcc(const float[3] acc)
public void SetAcc(const float acc[3])
{
this.SetVector("vAcc", acc);
}

View File

@ -12,14 +12,14 @@
#define SPEED_FORWARD 1.0
#define SPEED_TURNING 0.5
stock float FloatMod(float num, float denom)
stock float FloatMod1(float num, float denom)
{
return num - denom * RoundToFloor(num / denom);
}
stock float operator%(float oper1, float oper2)
{
return FloatMod(oper1, oper2);
return FloatMod1(oper1, oper2);
}
public bool IsValidPlayer(int player)
@ -27,7 +27,7 @@ public bool IsValidPlayer(int player)
return player >= 1 && player <= 64 && IsValidEntity(player) && IsPlayerAlive(player);
}
public float GetDistance(const float[3] v1, const float[3] v2)
public float GetDistance(const float v1[3], const float v2[3])
{
return SquareRoot((v1[0] - v2[0]) * (v1[0] - v2[0]) + (v1[1] - v2[1]) * (v1[1] - v2[1]) + (v1[2] - v2[2]) * (v1[2] - v2[2]));
}
@ -130,9 +130,8 @@ methodmap MovingNpc < Basic
}
}
public float GetTargetYaw(const float[3] start, const float[3] target)
public float GetTargetYaw(const float start[3], const float target[3])
{
float yaw = 0.00;
float v[3];
SubtractVectors(start, target, v);

View File

@ -36,19 +36,12 @@ public void OnMapStart()
HookEvent("round_end", OnRoundEnd, EventHookMode_PostNoCopy);
g_aEyes = new ArrayList();
}
else
{
char sFilename[256];
GetPluginFilename(INVALID_HANDLE, sFilename, sizeof(sFilename));
ServerCommand("sm plugins unload %s", sFilename);
}
}
public void OnRoundStart(Event event, const char[] name, bool dontBroadcast)
{
if(!bValidMap)
return;
if(bValidMap)
{
g_Chess = new Chess(GetEntityIndexByName("GreenStart", "path_track"), GetEntityIndexByName("GreenEnd", "path_track"),
GetEntityIndexByName("PurpleStart", "path_track"), GetEntityIndexByName("PurpleEnd", "path_track"));
int tmp = GetEntityIndexByName("GreenEnd", "path_track");
@ -113,6 +106,7 @@ public void OnRoundStart(Event event, const char[] name, bool dontBroadcast)
tmp = GetEntityIndexByHammerID(445713, "trigger_push");
HookSingleEntityOutput(tmp, "OnStartTouch", OnPushTrigger2);
}
}
public void OnPushTrigger2(const char[] output, int caller, int activator, float delay)
@ -304,8 +298,8 @@ public void OnPurpleEndPass(const char[] output, int caller, int activator, floa
public void OnEntitySpawned(int entity, const char[] classname)
{
if(!bValidMap)
return;
if(bValidMap)
{
if(IsValidEntity(entity))
{
if(strcmp(classname, "func_breakable") == 0)
@ -327,6 +321,7 @@ public void OnEntitySpawned(int entity, const char[] classname)
}
}
}
}
}
public void OnEyeMove(const char[] output, int caller, int activator, float delay)
@ -345,8 +340,8 @@ public void OnEyeMove(const char[] output, int caller, int activator, float dela
public void OnEntityDestroyed(int entity)
{
if(!bValidMap)
return;
if(bValidMap)
{
if(IsValidEntity(entity))
{
char sClassname[64];
@ -372,6 +367,7 @@ public void OnEntityDestroyed(int entity)
}
}
}
}
}
public void Cleanup()

View File

@ -34,19 +34,12 @@ public void OnMapStart()
{
g_aMovingNpc = new ArrayList();
}
else
{
char sFilename[256];
GetPluginFilename(INVALID_HANDLE, sFilename, sizeof(sFilename));
ServerCommand("sm plugins unload %s", sFilename);
}
}
public void OnEntitySpawned(int entity, const char[] classname)
{
if(!bValidMap)
return;
if(bValidMap)
{
if(IsValidEntity(entity))
{
if(strcmp(classname, "phys_thruster") == 0)
@ -94,12 +87,13 @@ public void OnEntitySpawned(int entity, const char[] classname)
}
}
}
}
}
public void OnEntityDestroyed(int entity)
{
if(!bValidMap)
return;
if(bValidMap)
{
if(IsValidEntity(entity))
{
char sClassname[128];
@ -119,6 +113,7 @@ public void OnEntityDestroyed(int entity)
}
}
}
}
}

View File

@ -5,6 +5,8 @@
#pragma semicolon 1
#pragma newdecls required
bool g_bIsDreamingv2 = false;
//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
@ -22,6 +24,7 @@ public Plugin myinfo =
//----------------------------------------------------------------------------------------------------
public void OnPluginStart()
{
VerifyMap();
HookEvent("round_start", OnRoundStart);
}
@ -40,14 +43,7 @@ public void VerifyMap()
{
char sCurrentMap[64];
GetCurrentMap(sCurrentMap, sizeof(sCurrentMap));
if (strncmp(sCurrentMap, "ze_dreamin_v2", 13, false) != 0)
{
char sFilename[256];
GetPluginFilename(INVALID_HANDLE, sFilename, sizeof(sFilename));
ServerCommand("sm plugins unload %s", sFilename);
}
g_bIsDreamingv2 = strncmp(sCurrentMap, "ze_dreamin_v2", 13, false) == 0;
}
//----------------------------------------------------------------------------------------------------
@ -55,6 +51,8 @@ public void VerifyMap()
//----------------------------------------------------------------------------------------------------
public void OnRoundStart(Event hEvent, const char[] sEvent, bool bDontBroadcast)
{
if (g_bIsDreamingv2)
{
int iEntity = INVALID_ENT_REFERENCE;
iEntity = FindEntityByTargetName("reflect_logic");
@ -190,6 +188,7 @@ public void OnRoundStart(Event hEvent, const char[] sEvent, bool bDontBroadcast)
HookSingleEntityOutput(iEntity, "OnHitMin", math_counter_11288_display, false);
CreateTimer(12.0, Credits, INVALID_HANDLE, TIMER_FLAG_NO_MAPCHANGE);
}
}
//----------------------------------------------------------------------------------------------------

View File

@ -5,6 +5,8 @@
#pragma semicolon 1
#pragma newdecls required
bool g_bIsDreamingv3 = false;
//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
@ -22,6 +24,7 @@ public Plugin myinfo =
//----------------------------------------------------------------------------------------------------
public void OnPluginStart()
{
VerifyMap();
HookEvent("round_start", OnRoundStart);
}
@ -41,13 +44,7 @@ public void VerifyMap()
char sCurrentMap[64];
GetCurrentMap(sCurrentMap, sizeof(sCurrentMap));
if (strncmp(sCurrentMap, "ze_dreamin_v3", 12, false) != 0)
{
char sFilename[256];
GetPluginFilename(INVALID_HANDLE, sFilename, sizeof(sFilename));
ServerCommand("sm plugins unload %s", sFilename);
}
g_bIsDreamingv3 = strncmp(sCurrentMap, "ze_dreamin_v3", 12, false) == 0;
}
//----------------------------------------------------------------------------------------------------
@ -55,6 +52,8 @@ public void VerifyMap()
//----------------------------------------------------------------------------------------------------
public void OnRoundStart(Event hEvent, const char[] sEvent, bool bDontBroadcast)
{
if (g_bIsDreamingv3)
{
int iEntity = INVALID_ENT_REFERENCE;
iEntity = FindEntityByTargetName("reflect_logic");
@ -225,6 +224,7 @@ public void OnRoundStart(Event hEvent, const char[] sEvent, bool bDontBroadcast)
HookSingleEntityOutput(iEntity, "OnHitMin", math_counter_11288_display, false);
CreateTimer(12.0, Credits, INVALID_HANDLE, TIMER_FLAG_NO_MAPCHANGE);
}
}
//----------------------------------------------------------------------------------------------------

View File

@ -0,0 +1,704 @@
#include "sourcemod"
#include "sdktools"
#include "sdkhooks"
#include "dhooks"
#define SNAME "[momsurffix2] "
#define GAME_DATA_FILE "momsurffix2.games"
//#define DEBUG_PROFILE
//#define DEBUG_MEMTEST
public Plugin myinfo = {
name = "Momentum surf fix \2",
author = "GAMMA CASE",
description = "Ported surf fix from momentum mod.",
version = "1.1.5",
url = "http://steamcommunity.com/id/_GAMMACASE_/"
};
#define FLT_EPSILON 1.192092896e-07
#define MAX_CLIP_PLANES 5
#define ASM_PATCH_LEN 17
#define ASM_START_OFFSET 100
enum OSType
{
OSUnknown = -1,
OSWindows = 1,
OSLinux = 2
};
OSType gOSType;
EngineVersion gEngineVersion;
#define ASSERTUTILS_FAILSTATE_FUNC SetFailStateCustom
#define MEMUTILS_PLUGINENDCALL
#include "glib/memutils"
#undef MEMUTILS_PLUGINENDCALL
#include "momsurffix/utils.sp"
#include "momsurffix/baseplayer.sp"
#include "momsurffix/gametrace.sp"
#include "momsurffix/gamemovement.sp"
ConVar gRampBumpCount,
gBounce,
gRampInitialRetraceLength,
gNoclipWorkAround;
float vec3_origin[3] = {0.0, 0.0, 0.0};
bool gBasePlayerLoadedTooEarly;
bool bValidMap = false;
#define DEBUG_PROFILE
#if defined DEBUG_PROFILE
#include "profiler"
Profiler gProf;
ArrayList gProfData;
float gProfTime;
void PROF_START()
{
if(gProf)
gProf.Start();
}
void PROF_STOP(int idx)
{
if(gProf)
{
gProf.Stop();
Prof_Check(idx);
}
}
#else
#define PROF_START%1;
#define PROF_STOP%1;
#endif
public void OnPluginStart()
{
char sCurMap[256];
GetCurrentMap(sCurMap, sizeof(sCurMap));
bValidMap = (strcmp("ze_atix_helicopter_i3d_c1", sCurMap, false) == 0);
#if defined DEBUG_MEMTEST
RegAdminCmd("sm_mom_dumpmempool", SM_Dumpmempool, ADMFLAG_ROOT, "Dumps active momory pool. Mainly for debugging.");
#endif
#if defined DEBUG_PROFILE
RegAdminCmd("sm_mom_prof", SM_Prof, ADMFLAG_ROOT, "Profiles performance of some expensive parts. Mainly for debugging.");
#endif
gRampBumpCount = CreateConVar("momsurffix_ramp_bumpcount", "8", "Helps with fixing surf/ramp bugs", .hasMin = true, .min = 4.0, .hasMax = true, .max = 16.0);
gRampInitialRetraceLength = CreateConVar("momsurffix_ramp_initial_retrace_length", "0.2", "Amount of units used in offset for retraces", .hasMin = true, .min = 0.2, .hasMax = true, .max = 5.0);
gNoclipWorkAround = CreateConVar("momsurffix_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_MSG(gBounce, "\"sv_bounce\" convar wasnt found!");
AutoExecConfig();
GameData gd = new GameData(GAME_DATA_FILE);
ASSERT_FINAL(gd);
ValidateGameAndOS(gd);
InitUtils(gd);
InitGameTrace(gd);
gBasePlayerLoadedTooEarly = InitBasePlayer(gd);
InitGameMovement(gd);
SetupDhooks(gd);
delete gd;
}
public void OnMapStart()
{
char sCurMap[256];
GetCurrentMap(sCurMap, sizeof(sCurMap));
bValidMap = (strcmp("ze_atix_helicopter_i3d_c1", sCurMap, false) == 0);
if(gBasePlayerLoadedTooEarly)
{
GameData gd = new GameData(GAME_DATA_FILE);
LateInitBasePlayer(gd);
gBasePlayerLoadedTooEarly = false;
delete gd;
}
}
public void OnPluginEnd()
{
CleanUpUtils();
}
#if defined DEBUG_MEMTEST
public Action SM_Dumpmempool(int client, int args)
{
DumpMemoryUsage();
return Plugin_Handled;
}
#endif
#if defined DEBUG_PROFILE
public Action SM_Prof(int client, int args)
{
if(args < 1)
{
ReplyToCommand(client, SNAME..."Usage: sm_prof <seconds>");
return Plugin_Handled;
}
char buff[32];
GetCmdArg(1, buff, sizeof(buff));
gProfTime = StringToFloat(buff);
if(gProfTime <= 0.1)
{
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 %.2f seconds.", gProfTime);
return Plugin_Handled;
}
stock void Prof_Check(int idx)
{
int idx2;
if(gProfData.Length - 1 < idx)
{
idx2 = gProfData.Push(gProf.Time);
gProfData.Set(idx2, 1, 1);
gProfData.Set(idx2, idx, 2);
}
else
{
idx2 = gProfData.FindValue(idx, 2);
gProfData.Set(idx2, view_as<float>(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<float>(gProfData.Get(i)) / float(gProfData.Get(i, 1)), gProfData.Get(i, 1));
delete gProf;
delete gProfData;
return Plugin_Handled;
}
#endif
void ValidateGameAndOS(GameData gd)
{
gOSType = view_as<OSType>(gd.GetOffset("OSType"));
ASSERT_FINAL_MSG(gOSType != OSUnknown, "Failed to get OS type or you are trying to load it on unsupported OS!");
gEngineVersion = GetEngineVersion();
ASSERT_FINAL_MSG(gEngineVersion == Engine_CSS || gEngineVersion == Engine_CSGO, "Only CSGO and CSS are supported by this plugin!");
}
void SetupDhooks(GameData gd)
{
Handle dhook = DHookCreateDetour(Address_Null, CallConv_THISCALL, ReturnType_Int, ThisPointer_Address);
DHookSetFromConf(dhook, gd, SDKConf_Signature, "CGameMovement::TryPlayerMove");
DHookAddParam(dhook, HookParamType_Int);
DHookAddParam(dhook, HookParamType_Int);
ASSERT(DHookEnableDetour(dhook, false, TryPlayerMove_Dhook));
}
public MRESReturn TryPlayerMove_Dhook(Address pThis, Handle hReturn, Handle hParams)
{
if (!bValidMap) //only on atix helicopter we want to disable the fix.
{
Address pFirstDest = DHookGetParam(hParams, 1);
Address pFirstTrace = DHookGetParam(hParams, 2);
DHookSetReturn(hReturn, TryPlayerMove(view_as<CGameMovement>(pThis), view_as<Vector>(pFirstDest), view_as<CGameTrace>(pFirstTrace)));
}
return MRES_Supercede;
}
int TryPlayerMove(CGameMovement pThis, Vector pFirstDest, CGameTrace pFirstTrace)
{
float original_velocity[3], primal_velocity[3], fixed_origin[3], valid_plane[3], new_velocity[3], end[3], dir[3];
float allFraction, d, time_left = GetGameFrameTime(), planes[MAX_CLIP_PLANES][3];
int bumpcount, blocked, numplanes, numbumps = gRampBumpCount.IntValue, i, j, h;
bool stuck_on_ramp, has_valid_plane;
CGameTrace pm = CGameTrace();
Vector vecVelocity = pThis.mv.m_vecVelocity;
vecVelocity.ToArray(original_velocity);
vecVelocity.ToArray(primal_velocity);
Vector vecAbsOrigin = pThis.mv.m_vecAbsOrigin;
vecAbsOrigin.ToArray(fixed_origin);
Vector plane_normal;
static Vector alloced_vector, alloced_vector2;
if(alloced_vector.Address == Address_Null)
alloced_vector = Vector();
if(alloced_vector2.Address == Address_Null)
alloced_vector2 = Vector();
for(bumpcount = 0; bumpcount < numbumps; bumpcount++)
{
if(vecVelocity.LengthSqr() == 0.0)
break;
if(stuck_on_ramp)
{
if(!has_valid_plane)
{
plane_normal = pm.plane.normal;
if(!CloseEnough(VectorToArray(plane_normal), view_as<float>({0.0, 0.0, 0.0})) &&
!IsEqual(valid_plane, VectorToArray(plane_normal)))
{
plane_normal.ToArray(valid_plane);
has_valid_plane = true;
}
else
{
for(i = numplanes; i-- > 0;)
{
if(!CloseEnough(planes[i], view_as<float>({0.0, 0.0, 0.0})) &&
FloatAbs(planes[i][0]) <= 1.0 && FloatAbs(planes[i][1]) <= 1.0 && FloatAbs(planes[i][2]) <= 1.0 &&
!IsEqual(valid_plane, planes[i]))
{
VectorCopy(planes[i], valid_plane);
has_valid_plane = true;
break;
}
}
}
}
if(has_valid_plane)
{
alloced_vector.FromArray(valid_plane);
if(valid_plane[2] >= 0.7 && valid_plane[2] <= 1.0)
{
ClipVelocity(pThis, vecVelocity, alloced_vector, vecVelocity, 1.0);
vecVelocity.ToArray(original_velocity);
}
else
{
ClipVelocity(pThis, vecVelocity, alloced_vector, vecVelocity, 1.0 + gBounce.FloatValue * (1.0 - pThis.player.m_surfaceFriction));
vecVelocity.ToArray(original_velocity);
}
alloced_vector.ToArray(valid_plane);
}
//TODO: should be replaced with normal solution!! Currently hack to fix issue #1.
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];
offsets[0] = (float(bumpcount) * 2.0) * -gRampInitialRetraceLength.FloatValue;
offsets[2] = (float(bumpcount) * 2.0) * gRampInitialRetraceLength.FloatValue;
int valid_planes = 0;
VectorCopy(view_as<float>({0.0, 0.0, 0.0}), valid_plane);
float offset[3], offset_mins[3], offset_maxs[3], buff[3];
static Ray_t ray;
// Keep this variable allocated only once
// since ray.Init should take care of removing any left garbage values
if(ray.Address == Address_Null)
ray = Ray_t();
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];
VectorCopy(offset, offset_mins);
ScaleVector(offset_mins, 0.5);
VectorCopy(offset, offset_maxs);
ScaleVector(offset_maxs, 0.5);
if(offset[0] > 0.0)
offset_mins[0] /= 2.0;
if(offset[1] > 0.0)
offset_mins[1] /= 2.0;
if(offset[2] > 0.0)
offset_mins[2] /= 2.0;
if(offset[0] < 0.0)
offset_maxs[0] /= 2.0;
if(offset[1] < 0.0)
offset_maxs[1] /= 2.0;
if(offset[2] < 0.0)
offset_maxs[2] /= 2.0;
PROF_STOP(0);
PROF_START();
AddVectors(fixed_origin, offset, buff);
SubtractVectors(end, offset, offset);
if(gEngineVersion == Engine_CSGO)
{
SubtractVectors(VectorToArray(GetPlayerMins(pThis)), offset_mins, offset_mins);
AddVectors(VectorToArray(GetPlayerMaxs(pThis)), offset_maxs, offset_maxs);
}
else
{
SubtractVectors(VectorToArray(GetPlayerMinsCSS(pThis, alloced_vector)), offset_mins, offset_mins);
AddVectors(VectorToArray(GetPlayerMaxsCSS(pThis, alloced_vector2)), offset_maxs, offset_maxs);
}
PROF_STOP(1);
PROF_START();
ray.Init(buff, offset, offset_mins, offset_maxs);
PROF_STOP(2);
PROF_START();
UTIL_TraceRay(ray, MASK_PLAYERSOLID, pThis, COLLISION_GROUP_PLAYER_MOVEMENT, pm);
PROF_STOP(3);
PROF_START();
plane_normal = pm.plane.normal;
if(FloatAbs(plane_normal.x) <= 1.0 && FloatAbs(plane_normal.y) <= 1.0 &&
FloatAbs(plane_normal.z) <= 1.0 && pm.fraction > 0.0 && pm.fraction < 1.0 && !pm.startsolid)
{
valid_planes++;
AddVectors(valid_plane, VectorToArray(plane_normal), valid_plane);
}
PROF_STOP(4);
}
}
}
if(valid_planes != 0 && !CloseEnough(valid_plane, view_as<float>({0.0, 0.0, 0.0})))
{
has_valid_plane = true;
NormalizeVector(valid_plane, valid_plane);
continue;
}
}
if(has_valid_plane)
{
VectorMA(fixed_origin, gRampInitialRetraceLength.FloatValue, valid_plane, fixed_origin);
}
else
{
stuck_on_ramp = false;
continue;
}
}
VectorMA(fixed_origin, time_left, VectorToArray(vecVelocity), end);
if(pFirstDest.Address != Address_Null && IsEqual(end, VectorToArray(pFirstDest)))
{
pm.Free();
pm = pFirstTrace;
}
else
{
alloced_vector2.FromArray(end);
if(stuck_on_ramp && has_valid_plane)
{
alloced_vector.FromArray(fixed_origin);
TracePlayerBBox(pThis, alloced_vector, alloced_vector2, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, pm);
pm.plane.normal.FromArray(valid_plane);
}
else
{
TracePlayerBBox(pThis, vecAbsOrigin, alloced_vector2, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, pm);
}
}
if(bumpcount > 0 && pThis.player.m_hGroundEntity == view_as<Address>(-1) && !IsValidMovementTrace(pThis, pm))
{
has_valid_plane = false;
stuck_on_ramp = true;
continue;
}
if(pm.fraction > 0.0)
{
if((bumpcount == 0 || pThis.player.m_hGroundEntity != view_as<Address>(-1)) && numbumps > 0 && pm.fraction == 1.0)
{
CGameTrace stuck = CGameTrace();
TracePlayerBBox(pThis, pm.endpos, pm.endpos, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, stuck);
if((stuck.startsolid || stuck.fraction != 1.0) && bumpcount == 0)
{
has_valid_plane = false;
stuck_on_ramp = true;
stuck.Free();
continue;
}
else if(stuck.startsolid || stuck.fraction != 1.0)
{
vecVelocity.FromArray(vec3_origin);
stuck.Free();
break;
}
stuck.Free();
}
has_valid_plane = false;
stuck_on_ramp = false;
vecVelocity.ToArray(original_velocity);
vecAbsOrigin.FromArray(VectorToArray(pm.endpos));
vecAbsOrigin.ToArray(fixed_origin);
allFraction += pm.fraction;
numplanes = 0;
}
if(CloseEnoughFloat(pm.fraction, 1.0))
break;
MoveHelper().AddToTouched(pm, vecVelocity);
if(pm.plane.normal.z >= 0.7)
blocked |= 1;
if(CloseEnoughFloat(pm.plane.normal.z, 0.0))
blocked |= 2;
time_left -= time_left * pm.fraction;
if(numplanes >= MAX_CLIP_PLANES)
{
vecVelocity.FromArray(vec3_origin);
break;
}
pm.plane.normal.ToArray(planes[numplanes]);
numplanes++;
if(numplanes == 1 && pThis.player.m_MoveType == MOVETYPE_WALK && pThis.player.m_hGroundEntity != view_as<Address>(-1))
{
Vector vec1 = Vector();
PROF_START();
if(planes[0][2] >= 0.7)
{
vec1.FromArray(original_velocity);
alloced_vector2.FromArray(planes[0]);
alloced_vector.FromArray(new_velocity);
ClipVelocity(pThis, vec1, alloced_vector2, alloced_vector, 1.0);
alloced_vector.ToArray(original_velocity);
alloced_vector.ToArray(new_velocity);
}
else
{
vec1.FromArray(original_velocity);
alloced_vector2.FromArray(planes[0]);
alloced_vector.FromArray(new_velocity);
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);
vec1.Free();
}
else
{
for(i = 0; i < numplanes; i++)
{
alloced_vector2.FromArray(original_velocity);
alloced_vector.FromArray(planes[i]);
ClipVelocity(pThis, alloced_vector2, alloced_vector, vecVelocity, 1.0);
alloced_vector.ToArray(planes[i]);
for(j = 0; j < numplanes; j++)
if(j != i)
if(vecVelocity.Dot(planes[j]) < 0.0)
break;
if(j == numplanes)
break;
}
if(i != numplanes)
{
}
else
{
if(numplanes != 2)
{
vecVelocity.FromArray(vec3_origin);
break;
}
if(CloseEnough(planes[0], planes[1]))
{
VectorMA(original_velocity, 20.0, planes[0], new_velocity);
vecVelocity.x = new_velocity[0];
vecVelocity.y = new_velocity[1];
break;
}
GetVectorCrossProduct(planes[0], planes[1], dir);
NormalizeVector(dir, dir);
d = vecVelocity.Dot(dir);
ScaleVector(dir, d);
vecVelocity.FromArray(dir);
}
d = vecVelocity.Dot(primal_velocity);
if(d <= 0.0)
{
vecVelocity.FromArray(vec3_origin);
break;
}
}
}
if(CloseEnoughFloat(allFraction, 0.0))
vecVelocity.FromArray(vec3_origin);
pm.Free();
return blocked;
}
stock void VectorMA(float start[3], float scale, float dir[3], float dest[3])
{
dest[0] = start[0] + dir[0] * scale;
dest[1] = start[1] + dir[1] * scale;
dest[2] = start[2] + dir[2] * scale;
}
stock void VectorCopy(float from[3], float to[3])
{
to[0] = from[0];
to[1] = from[1];
to[2] = from[2];
}
stock float[] VectorToArray(Vector vec)
{
float ret[3];
vec.ToArray(ret);
return ret;
}
stock bool IsEqual(float a[3], float b[3])
{
return a[0] == b[0] && a[1] == b[1] && a[2] == b[2];
}
stock bool CloseEnough(float a[3], float b[3], float eps = FLT_EPSILON)
{
return FloatAbs(a[0] - b[0]) <= eps &&
FloatAbs(a[1] - b[1]) <= eps &&
FloatAbs(a[2] - b[2]) <= eps;
}
stock bool CloseEnoughFloat(float a, float b, float eps = FLT_EPSILON)
{
return FloatAbs(a - b) <= eps;
}
public void SetFailStateCustom(const char[] fmt, any ...)
{
char buff[512];
VFormat(buff, sizeof(buff), fmt, 2);
CleanUpUtils();
char ostype[32];
switch(gOSType)
{
case OSLinux: ostype = "LIN";
case OSWindows: ostype = "WIN";
default: ostype = "UNK";
}
SetFailState("[%s | %i] %s", ostype, gEngineVersion, buff);
}
stock bool IsValidMovementTrace(CGameMovement pThis, CGameTrace tr)
{
if(tr.allsolid || tr.startsolid)
return false;
if(CloseEnoughFloat(tr.fraction, 0.0))
return false;
Vector plane_normal = tr.plane.normal;
if(FloatAbs(plane_normal.x) > 1.0 || FloatAbs(plane_normal.y) > 1.0 || FloatAbs(plane_normal.z) > 1.0)
return false;
CGameTrace stuck = CGameTrace();
TracePlayerBBox(pThis, tr.endpos, tr.endpos, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, stuck);
if(stuck.startsolid || !CloseEnoughFloat(stuck.fraction, 1.0))
{
stuck.Free();
return false;
}
stuck.Free();
return true;
}
stock void UTIL_TraceRay(Ray_t ray, int mask, CGameMovement gm, int collisionGroup, CGameTrace trace)
{
if(gEngineVersion == Engine_CSGO)
{
CTraceFilterSimple filter = LockTraceFilter(gm, collisionGroup);
gm.m_nTraceCount++;
ITraceListData tracelist = gm.m_pTraceListData;
if(tracelist.Address != Address_Null && tracelist.CanTraceRay(ray))
TraceRayAgainstLeafAndEntityList(ray, tracelist, mask, filter, trace);
else
TraceRay(ray, mask, filter, trace);
UnlockTraceFilter(gm, filter);
}
else if(gEngineVersion == Engine_CSS)
{
CTraceFilterSimple filter = CTraceFilterSimple();
filter.Init(LookupEntity(gm.mv.m_nPlayerHandle), collisionGroup);
TraceRay(ray, mask, filter, trace);
filter.Free();
}
}