Veteran Member
|
04-25-2019
, 21:49
Re: Teleporting Player Check "Non-Stuck"
|
#6
|
Quote:
Originally Posted by scorpius2k1
Thanks for the replies everyone! This is a slightly different scenario than just a player being stuck on spawn or on another player. I don't need to worry about player movement, but only need to do a problematic check on a previously defined coordinate IF we teleported the player to that particular coordinate.
Let's say we have an X,Y,Z coordinate of 100,200,300 and if I were to move the player there with "TeleportEntity", they would be stuck in the ceiling (left pic below). Essentially what I am aiming to do is check, and if need be, fix up those coordinates so the player would not be stuck when I moved them (right pic below).
Here is a good visual (notice the bounding box of the player not being clipped in the right side pic after fix):
The plugin link Franc1sco shared seemed to be close, except it didn't work 100% of the time. I would still be left stuck sometimes, especially in ceilings for some reason. It was pretty close to what I'm after because it seemed to check in a radius around the player and act accordingly.
Again, I am sure this can somehow be done with TR_TraceRayFilter to check X,Y,Z with the player bounding box dimensions in mind (32,32,72), just how to go about it is what I am stuck on.
Thanks again all!!
|
Launch your trace from the said origin in the x/y/z direction, and check when it hits some other entity (including worldspawn), if the distance between the hit entity and the origin is less or equal 32 units in X/Y then you can't spawn there, same for Z axis, if it's greater then you can safely spawn there.
PS: I might support you with some code tomorrow. have a good night for now.
EDIT: Here it is,
PHP Code:
#include <sourcemod> #include <sdktools> #include <sdkhooks>
/* X: 32.000000Y: 32.000000Z: 72.000000 Mins[0]: -16.000000, Mins[1]: -16.000000, Mins[2]: 0.000000 Maxs[0]: 16.000000, Maxs[1]: 16.000000, Maxs[2]: 72.000000 Min/Maxs: 85.041168 Min/Origin: 2477.570312 Max/Origin: 2446.154785 */
#pragma newdecls required
#define PLAYER_WIDTH 32.0 #define PLAYER_HEIGHT 72.0
int g_LaserBeam;
public void OnPluginStart() { }
public void OnMapStart() { g_LaserBeam = PrecacheModel("materials/sprites/laserbeam.vmt", true); }
public void OnClientSayCommand_Post(int client, const char[] command, const char[] sArgs) { if( !IsPlayerAlive(client) ) { return; } if( strcmp(sArgs, "check_fitness", false) == 0 ) { float oldPos[3], newPos[3]; GetClientAbsOrigin(client, oldPos); AddVectors(oldPos, {0.0, 0.0, 25.0}, oldPos); // Just elevating it a little bit, this fixes some problems with the trace collision for some reason VectorCopy(oldPos, newPos); // CanPlayerFit fct is gonna modify the origin we give it, so we better store the old one for comparasion purposes if( CanPlayerFit(client, newPos) && !VectorsEqual(oldPos, newPos) ) { PrintToChat(client, "Teleported from %f %f %f to %f %f %f", oldPos[0], oldPos[1], oldPos[2], newPos[0], newPos[1], newPos[2]); PrintToChat(client, "Distance new/old: %f", GetVectorDistance(oldPos, newPos)); TeleportEntity(client, newPos, NULL_VECTOR, NULL_VECTOR); } } }
bool CanPlayerFit(int client, float pos[3]) { float radius = SquareRoot(2 * (PLAYER_WIDTH * PLAYER_WIDTH) + PLAYER_HEIGHT * PLAYER_HEIGHT); float heads[4][3]; heads[0][0] = pos[0] + PLAYER_WIDTH / 2; heads[0][1] = pos[1] + PLAYER_WIDTH / 2; heads[0][2] = pos[2] + PLAYER_HEIGHT / 2; heads[1][0] = pos[0] - PLAYER_WIDTH / 2; heads[1][1] = pos[1] - PLAYER_WIDTH / 2; heads[1][2] = pos[2] - PLAYER_HEIGHT / 2; heads[2][0] = pos[0] + PLAYER_WIDTH / 2; heads[2][1] = pos[1] - PLAYER_WIDTH / 2; heads[2][2] = pos[2] - PLAYER_HEIGHT / 2; heads[3][0] = pos[0] - PLAYER_WIDTH / 2; heads[3][1] = pos[1] + PLAYER_WIDTH / 2; heads[3][2] = pos[2] + PLAYER_HEIGHT / 2; TE_SetupBeamPoints(heads[0], heads[1], g_LaserBeam, 0, 0, 0, 30.0, 2.0, 2.0, 1, 0.0, {0, 0, 255, 255}, 15); TE_SendToAll(); TE_SetupBeamPoints(heads[3], heads[2], g_LaserBeam, 0, 0, 0, 30.0, 2.0, 2.0, 1, 0.0, {255, 0, 0, 255}, 15); TE_SendToAll(); int i = 0, trials = 0, dirSelection = -1; Handle ray = INVALID_HANDLE; float startPos[3], endPos[3], dir[3]; float dist = 0.0, lastDist = 0.0; do { PrintToChat(client, "Trial: %d", trials + 1); SubtractVectors(heads[1], heads[0], dir); ray = TR_TraceRayFilterEx(heads[0], dir, MASK_PLAYERSOLID, RayType_Infinite, CollisionCheck, client); if( ray ) { if( TR_DidHit(ray) ) { TR_GetEndPosition(endPos, ray); TR_GetStartPosition(ray, startPos); if( GetVectorDistance(startPos, endPos) > radius ) { PrintToChat(client, "Point does not belong to %f", radius); delete ray; return true; } if( dirSelection == -1 || GetRandomInt(0, 3) == 0 ) { for( i = 0; i < 4; i++ ) { dist = GetVectorDistance(endPos, heads[i]); if( i == 0 ) { lastDist = dist; dirSelection = 0; } else if( dist < lastDist ) { lastDist = dist; dirSelection = i; } } } TE_SetupBeamPoints(pos, endPos, g_LaserBeam, 0, 0, 0, 30.0, 2.0, 2.0, 1, 0.0, {0, 255, 0, 255}, 15); TE_SendToAll(); SubtractVectors(heads[dirSelection], pos, dir); NormalizeVector(dir, dir); PrintToChat(client, "Point does belong to: %f", radius); ScaleVector(dir, radius / 2.0); AddVectors(pos, dir, pos); for( i = 0; i < 4; i++ ) { AddVectors(heads[i], dir, heads[i]); } } else { PrintToChat(client, "Trace not hitting it"); delete ray; return false; } delete ray; } } while( ++trials < 1000 ) return false; }
public bool CollisionCheck(int entity, int contentsMask, any data) { return entity != view_as<int> (data); }
void VectorCopy(float a[3], float b[3]) { b[0] = a[0]; b[1] = a[1]; b[2] = a[2]; }
bool VectorsEqual(float a[3], float b[3]) { return a[0] == b[0] && a[1] == b[1] && a[2] == b[2] ? true : false; }
I tried with this, now this work in the simplest cases... if a you have only a portion of the player stuck in a wall or something, it'll teleport you to a close point where you can actually move.
But, playing Dust2 on CSGO, CT spawn here have a little inaccessible room, if a player gets stuck near it there's a possibility he'll go inside, since it's not really solid, as you can see here:
Otherwise, if the position you're questioning is outside the playable map then you'll how to use the function multiple times and I tried detecting if a certain point is inside/outside the playable map but it didn't work... hopefully someone will let us know.
I did only a few tests with this, you should try more and see if it works for "your" own special cases. also, as you can see you can't go on looping forever.. especially doing this kind of dirty work, this function is kinda heavy so I limited the number of trials, but in my most cases I got no more than 5 trials each so it's a good sign, and bare in mind, you can't go on using this everytime the player spawns, if it somehow worked for you, you should really be considering saving the corrected origins into some files once you generate them and then use them next time the map loads.
Last edited by TheDS1337; 04-26-2019 at 16:29.
|
|