From c7a72886fae962a0df27533831469ab2a4aa2348 Mon Sep 17 00:00:00 2001 From: Pan32 Date: Fri, 2 Oct 2020 05:48:02 +0100 Subject: [PATCH] SetCollisionGroup: Initial Commit --- .../gamedata/SetCollisionGroup.games.txt | 14 + .../scripting/SetCollisionGroup.sp | 76 ++++ .../scripting/include/SetCollisionGroup.inc | 62 +++ .../scripting/sample_edited_noblock.sp | 393 ++++++++++++++++++ 4 files changed, 545 insertions(+) create mode 100644 SetCollisionGroup/gamedata/SetCollisionGroup.games.txt create mode 100644 SetCollisionGroup/scripting/SetCollisionGroup.sp create mode 100644 SetCollisionGroup/scripting/include/SetCollisionGroup.inc create mode 100644 SetCollisionGroup/scripting/sample_edited_noblock.sp diff --git a/SetCollisionGroup/gamedata/SetCollisionGroup.games.txt b/SetCollisionGroup/gamedata/SetCollisionGroup.games.txt new file mode 100644 index 00000000..69f45e19 --- /dev/null +++ b/SetCollisionGroup/gamedata/SetCollisionGroup.games.txt @@ -0,0 +1,14 @@ +"Games" +{ + "cstrike" + { + "Signatures" + { + "SetCollisionGroup" + { + "library" "server" + "linux" "@_ZN11CBaseEntity17SetCollisionGroupEi" + } + } + } +} diff --git a/SetCollisionGroup/scripting/SetCollisionGroup.sp b/SetCollisionGroup/scripting/SetCollisionGroup.sp new file mode 100644 index 00000000..4bc888cf --- /dev/null +++ b/SetCollisionGroup/scripting/SetCollisionGroup.sp @@ -0,0 +1,76 @@ +#define PLUGIN_NAME "SetCollisionGroup Interface" +#define PLUGIN_AUTHOR "Pan32 (Thanks organ-harvester)" +#define PLUGIN_DESCRIPTION "Properly sets the collision group of a player by using the source SDK" +#define PLUGIN_VERSION "1.0" +#define PLUGIN_URL "unloze.gay" + +#include +#include + +#pragma semicolon 1 + +//https://github.com/ValveSoftware/source-sdk-2013/blob/master/mp/src/public/const.h#L397 +#define MAX_GROUP_VALUE 20 + +Handle g_hSetCollisionGroupCall = INVALID_HANDLE; + + +public Plugin:myinfo = +{ + name = PLUGIN_NAME, + author = PLUGIN_AUTHOR, + description = PLUGIN_DESCRIPTION, + version = PLUGIN_VERSION, + url = PLUGIN_URL +}; + +public OnPluginStart() +{ + Handle temp = LoadGameConfigFile("SetCollisionGroup.games"); + + if(temp == INVALID_HANDLE) + { + SetFailState("Gamedata file SetCollisionGroup.games.txt not found or invalid."); + } + + //https://github.com/ValveSoftware/source-sdk-2013/blob/master/mp/src/game/shared/baseentity_shared.cpp#L2493 + StartPrepSDKCall(SDKCall_Entity); + if(!PrepSDKCall_SetFromConf(temp, SDKConf_Signature, "SetCollisionGroup")) + { + SetFailState("Function signature for CBaseEntity::SetCollisionGroup not found or invalid."); + } + + PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); + g_hSetCollisionGroupCall = EndPrepSDKCall(); + + if(g_hSetCollisionGroupCall == INVALID_HANDLE) + { + SetFailState("Failed to create a SDKCall for CBaseEntity::SetCollisionGroup."); + } +} + +public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) +{ + CreateNative("SetCollisionGroup", Native_SetCollisionGroup); + + RegPluginLibrary("SetCollisionGroup"); + return APLRes_Success; +} + +public void SetCollisionGroup(int entity, int group) +{ + SDKCall(g_hSetCollisionGroupCall, entity, group); +} + +public int Native_SetCollisionGroup(Handle hPlugin, int numParams) +{ + int entity = GetNativeCell(1); + int group = GetNativeCell(2); + + //Check if valid entity (sanity check) + //https://github.com/ValveSoftware/source-sdk-2013/blob/master/mp/src/public/const.h#L397 + if (IsValidEntity(entity) && (group < MAX_GROUP_VALUE)) + { + SetCollisionGroup(entity, group); + } +} \ No newline at end of file diff --git a/SetCollisionGroup/scripting/include/SetCollisionGroup.inc b/SetCollisionGroup/scripting/include/SetCollisionGroup.inc new file mode 100644 index 00000000..c0788d8c --- /dev/null +++ b/SetCollisionGroup/scripting/include/SetCollisionGroup.inc @@ -0,0 +1,62 @@ +#if defined _SetCollisionGroup_included + #endinput +#endif + +#define _SetCollisionGroup_included + +//https://github.com/ValveSoftware/source-sdk-2013/blob/master/mp/src/public/const.h#L397 +/*enum COLLISION_GROUP +{ + COLLISION_GROUP_NONE = 0, + COLLISION_GROUP_DEBRIS, // Collides with nothing but world and static stuff + COLLISION_GROUP_DEBRIS_TRIGGER, // Same as debris, but hits triggers + COLLISION_GROUP_INTERACTIVE_DEBRIS, // Collides with everything except other interactive debris or debris + COLLISION_GROUP_INTERACTIVE, // Collides with everything except interactive debris or debris + COLLISION_GROUP_PLAYER, + COLLISION_GROUP_BREAKABLE_GLASS, + COLLISION_GROUP_VEHICLE, + COLLISION_GROUP_PLAYER_MOVEMENT, // For HL2, same as Collision_Group_Player, for + // TF2, this filters out other players and CBaseObjects + COLLISION_GROUP_NPC, // Generic NPC group + COLLISION_GROUP_IN_VEHICLE, // for any entity inside a vehicle + COLLISION_GROUP_WEAPON, // for any weapons that need collision detection + COLLISION_GROUP_VEHICLE_CLIP, // vehicle clip brush to restrict vehicle movement + COLLISION_GROUP_PROJECTILE, // Projectiles! + COLLISION_GROUP_DOOR_BLOCKER, // Blocks entities not permitted to get near moving doors + COLLISION_GROUP_PASSABLE_DOOR, // Doors that the player shouldn't collide with + COLLISION_GROUP_DISSOLVING, // Things that are dissolving are in this group + COLLISION_GROUP_PUSHAWAY, // Nonsolid on client and server, pushaway in player code + + COLLISION_GROUP_NPC_ACTOR, // Used so NPCs in scripts ignore the player. + COLLISION_GROUP_NPC_SCRIPTED, // USed for NPCs in scripts that should not collide with each other +}*/ + +/** + * Sets a entity collision group + * + * @param entity The entity index. + * @param group The group index. + * + * no return + */ +native void SetCollisionGroup(int entity, int group); + + +public SharedPlugin __pl_PlayerManager = +{ + name = "SetCollisionGroup", + file = "SetCollisionGroup.smx", + + #if defined REQUIRE_PLUGIN + required = 1 + #else + required = 0 + #endif +}; + +#if !defined REQUIRE_PLUGIN + public void __pl_PlayerManager_SetNTVOptional() + { + MarkNativeAsOptional("SetCollisionGroup"); + } +#endif diff --git a/SetCollisionGroup/scripting/sample_edited_noblock.sp b/SetCollisionGroup/scripting/sample_edited_noblock.sp new file mode 100644 index 00000000..5241fd17 --- /dev/null +++ b/SetCollisionGroup/scripting/sample_edited_noblock.sp @@ -0,0 +1,393 @@ +/** + * This is a very crude edit of https://forums.alliedmods.net/showthread.php?t=91617 Noblock plugin, only just editing the BlockEntity() and UnblockEntity() functions to use the forward. + * They are also harcoded values, as I havent implemented the COLLISION enum yet. + */ + + +#pragma semicolon 1 + +#include +#include +#include + +#define cDefault 0x01 +#define cLightGreen 0x03 +#define cGreen 0x04 +#define cDarkGreen 0x05 + +#define PLUGIN_VERSION "1.5" + +// Uncomment for debugging +// #define DEBUG 1 + +public Plugin:myinfo = +{ + name = "NoBlock", + author = "Otstrel.ru Team", + description = "Removes player collisions.", + version = PLUGIN_VERSION, + url = "http://otstrel.ru" +}; + +// =========================================================================== +// GLOBALS +// =========================================================================== + +//new g_offsCollisionGroup; +new bool:g_enabled; +new bool:g_enabled_nades; +new bool:g_enabled_hostages; +new bool:g_noblock_allow_block; +new Float:g_noblock_allow_block_time; + +new Handle:sm_noblock; +new Handle:sm_noblock_nades; +new Handle:sm_noblock_hostages; +new Handle:sm_noblock_allow_block; +new Handle:sm_noblock_allow_block_time; +new Handle:g_hTimer[MAXPLAYERS+1]; + +new Handle:sm_noblock_blockafterspawn_time; +new Float:g_blockTime; + +// =========================================================================== +// LOAD & UNLOAD +// =========================================================================== + +public OnPluginStart() +{ + #if defined DEBUG + LogError("[DEBUG] Plugin started."); + #endif + + new Handle:Cvar_Version = CreateConVar("sm_noblock_version", PLUGIN_VERSION, "NoBlock Version", FCVAR_SPONLY|FCVAR_REPLICATED|FCVAR_NOTIFY); + /* Just to make sure they it updates the convar version if they just had the plugin reload on map change */ + SetConVarString(Cvar_Version, PLUGIN_VERSION); + +// g_offsCollisionGroup = FindSendPropOffs("CBaseEntity", "m_CollisionGroup"); +// if (g_offsCollisionGroup == -1) +// { +// SetFailState("[NoBlock] Failed to get offset for CBaseEntity::m_CollisionGroup."); +// } + + sm_noblock = CreateConVar("sm_noblock", "1", "Removes player vs. player collisions"); + g_enabled = GetConVarBool(sm_noblock); + HookConVarChange(sm_noblock, OnConVarChange); + + sm_noblock_nades = CreateConVar("sm_noblock_nades", "1", "Removes player vs. nade collisions"); + g_enabled_nades = GetConVarBool(sm_noblock_nades); + HookConVarChange(sm_noblock_nades, OnConVarChange); + + sm_noblock_hostages = CreateConVar("sm_noblock_hostages", "0", "Removes player vs. hostage collisions"); + g_enabled_hostages = GetConVarBool(sm_noblock_hostages); + HookConVarChange(sm_noblock_hostages, OnConVarChange); + + sm_noblock_allow_block = CreateConVar("sm_noblock_allow_block", "1.0", "Allow players to use say !block", _, true, 0.0, true, 1.0); + g_noblock_allow_block = GetConVarBool(sm_noblock_allow_block); + HookConVarChange(sm_noblock_allow_block, OnConVarChange); + + sm_noblock_allow_block_time = CreateConVar("sm_noblock_allow_block_time", "20.0", "Time limit to say !block command", _, true, 0.0, true, 600.0); + g_noblock_allow_block_time = GetConVarFloat(sm_noblock_allow_block_time); + HookConVarChange(sm_noblock_allow_block_time, OnConVarChange); + + sm_noblock_blockafterspawn_time = CreateConVar("sm_noblock_blockafterspawn_time", "0.0", "Disable blocking only for that time from spawn.", _, true, 0.0, true, 600.0); + g_blockTime = GetConVarFloat(sm_noblock_blockafterspawn_time); + HookConVarChange(sm_noblock_blockafterspawn_time, OnConVarChange); + + + if ( g_enabled ) { + StartHook(); + } + + RegConsoleCmd("say", Command_Say); + RegConsoleCmd("say_team", Command_Say); +} + +// =========================================================================== +// EVENTS +// =========================================================================== + +public OnConVarChange(Handle:hCvar, const String:oldValue[], const String:newValue[]) +{ + #if defined DEBUG + LogError("[DEBUG] Cvar changed."); + #endif + if ( hCvar == sm_noblock ) { + g_enabled = GetConVarBool(sm_noblock); + if ( g_enabled ) { + UnblockClientAll(); + if ( sm_noblock_hostages ) { + UnblockHostages(); + } + StartHook(); + } else { + StopHook(); + BlockClientAll(); + if ( sm_noblock_hostages ) { + BlockHostages(); + } + } + return; + } + if ( hCvar == sm_noblock_nades ) { + g_enabled_nades = GetConVarBool(sm_noblock_nades); + return; + } + if ( hCvar == sm_noblock_hostages ) { + g_enabled_hostages = GetConVarBool(sm_noblock_hostages); + if ( g_enabled ) { + if ( g_enabled_hostages ) { + UnblockHostages(); + HookEvent("round_start", OnRoundStart, EventHookMode_Post); + } else { + UnhookEvent("round_start", OnRoundStart, EventHookMode_Post); + BlockHostages(); + } + } + return; + } + if ( hCvar == sm_noblock_blockafterspawn_time ) { + g_blockTime = GetConVarFloat(sm_noblock_blockafterspawn_time); + return; + } + if ( hCvar == sm_noblock_allow_block ) { + g_noblock_allow_block = GetConVarBool(sm_noblock_allow_block); + return; + } + if ( hCvar == sm_noblock_allow_block_time ) { + g_noblock_allow_block_time = GetConVarFloat(sm_noblock_allow_block_time); + return; + } +} + +public OnSpawn(Handle:event, const String:name[], bool:dontBroadcast) +{ + #if defined DEBUG + LogError("[DEBUG] Player spawned."); + #endif + + new userid = GetEventInt(event, "userid"); + new client = GetClientOfUserId(userid); + #if defined DEBUG + LogError("[DEBUG] ... player %i.", client); + #endif + if ( g_hTimer[client] != INVALID_HANDLE ) + { + CloseHandle(g_hTimer[client]); + g_hTimer[client] = INVALID_HANDLE; + PrintToChat(client, "%c[NoBlock] %cBlocking has been Disabled because of respawn", cLightGreen, cDefault); + } + + UnblockEntity(client); + + if ( g_blockTime ) + { + CreateTimer(g_blockTime, Timer_PlayerBlock, client); + } +} + +//Enable NoBlock on hostages on roundstart +public OnRoundStart(Handle:event, const String:name[], bool:dontBroadcast) +{ + #if defined DEBUG + LogError("[DEBUG] Round started."); + #endif + + UnblockHostages(); +} + +public Action:Command_Say(client, args) +{ + #if defined DEBUG + LogError("[DEBUG] Player %i sayd something.", client); + #endif + if ( !g_enabled || !client || !g_noblock_allow_block ) + { + return Plugin_Continue; + } + + decl String:text[192], String:command[64]; + new startidx = 0; + if (GetCmdArgString(text, sizeof(text)) < 1) + { + return Plugin_Continue; + } + + if (text[strlen(text)-1] == '"') + { + text[strlen(text)-1] = '\0'; + startidx = 1; + } + + if (strcmp(command, "say2", false) == 0) + { + startidx += 4; + } + + if ( (strcmp(text[startidx], "!block", false) == 0) && !g_blockTime ) + { + if ( g_hTimer[client] != INVALID_HANDLE ) + { + CloseHandle(g_hTimer[client]); + g_hTimer[client] = INVALID_HANDLE; + PrintToChat(client, "%c[NoBlock] %cBlocking has been Disabled by the client", cLightGreen, cDefault); + + UnblockEntity(client); + return Plugin_Continue; + } + + g_hTimer[client] = CreateTimer(g_noblock_allow_block_time, Timer_PlayerUnblock, client); + PrintToChat(client, "%c[NoBlock] %cBlocking has been Enabled for %.0f seconds", cLightGreen, cDefault, g_noblock_allow_block_time); + + BlockEntity(client); + } + + return Plugin_Continue; +} + +//Player Blocking Expires +public Action:Timer_PlayerUnblock(Handle:timer, any:client) +{ + #if defined DEBUG + LogError("[DEBUG] Timer unblocks client %i.", client); + #endif + //Disable Blocking on the Client + g_hTimer[client] = INVALID_HANDLE; + if ( !g_enabled || !client || !IsClientInGame(client) || !IsPlayerAlive(client) ) + { + return Plugin_Continue; + } + + PrintToChat(client, "%c[NoBlock] %cBlocking is now Disabled", cLightGreen, cDefault); + + UnblockEntity(client); + return Plugin_Continue; +} + +public Action:Timer_PlayerBlock(Handle:timer, any:client) +{ + //Enable Blocking on the Client + if ( !g_enabled || !client || !IsClientInGame(client) || !IsPlayerAlive(client) ) + { + return Plugin_Continue; + } + + BlockEntity(client); + return Plugin_Continue; +} + +public OnEntityCreated(entity, const String:classname[]) +{ + if ( g_enabled_nades ) + { + //Enable NoBlock on Nades + if (StrEqual(classname, "hegrenade_projectile")) { + UnblockEntity(entity); + } else if (StrEqual(classname, "flashbang_projectile")) { + UnblockEntity(entity); + } else if (StrEqual(classname, "smokegrenade_projectile")) { + UnblockEntity(entity); + } + } +} + +// =========================================================================== +// HELPERS +// =========================================================================== + +StartHook() { + HookEvent("player_spawn", OnSpawn, EventHookMode_Post); + if ( g_enabled_hostages ) { + HookEvent("round_start", OnRoundStart, EventHookMode_Post); + } +} + +StopHook() { + UnhookEvent("player_spawn", OnSpawn, EventHookMode_Post); + if ( g_enabled_hostages ) { + UnhookEvent("round_start", OnRoundStart, EventHookMode_Post); + } +} + +UnblockHostages() { + new String:sClassName[32]; + new iMaxEntities = GetMaxEntities(); + + /* Apparently the clients are always at the start of the entity list, + so we can skip them in hopes of reducing roundstart lag */ + + for ( new iEntity = MaxClients + 1; iEntity < iMaxEntities; iEntity++ ) + { + if ( !IsValidEntity(iEntity) || !IsValidEdict(iEntity) ) { + continue; + } + GetEdictClassname(iEntity, sClassName, sizeof(sClassName)); + if ( StrEqual("hostage_entity", sClassName) ) { + UnblockEntity(iEntity); + } + } +} + +BlockHostages() { + new String:sClassName[32]; + new iMaxEntities = GetMaxEntities(); + + /* Apparently the clients are always at the start of the entity list, + so we can skip them in hopes of reducing roundstart lag */ + + for ( new iEntity = MaxClients + 1; iEntity < iMaxEntities; iEntity++ ) + { + if ( !IsValidEntity(iEntity) || !IsValidEdict(iEntity) ) { + continue; + } + GetEdictClassname(iEntity, sClassName, sizeof(sClassName)); + if ( StrEqual("hostage_entity", sClassName) ) { + BlockEntity(iEntity); + } + } +} + +BlockEntity(client) +{ + #if defined DEBUG + LogError("[DEBUG] BLOCK client %i.", client); + #endif + SetCollisionGroup(client, 5); +} + +UnblockEntity(client) +{ + #if defined DEBUG + LogError("[DEBUG] UNBLOCK client %i.", client); + #endif + SetCollisionGroup(client, 2); +} + +BlockClientAll() +{ + #if defined DEBUG + LogError("[DEBUG] Block all."); + #endif + for (new i = 1; i <= MaxClients; i++) + { + if ( IsClientInGame(i) && IsPlayerAlive(i) ) + { + BlockEntity(i); + } + } +} + +UnblockClientAll() +{ + #if defined DEBUG + LogError("[DEBUG] Unblock all."); + #endif + for (new i = 1; i <= MaxClients; i++) + { + if ( IsClientInGame(i) && IsPlayerAlive(i) ) + { + UnblockEntity(i); + } + } +} +