Init
This commit is contained in:
@@ -0,0 +1,242 @@
|
||||
#include <sourcemod>
|
||||
#include <sdktools>
|
||||
#include <dhooks>
|
||||
#pragma semicolon 1
|
||||
#pragma newdecls required
|
||||
|
||||
#define PLUGIN_VERSION "1.0"
|
||||
|
||||
public Plugin myinfo =
|
||||
{
|
||||
name = "CS:GO Fixes",
|
||||
author = "xen",
|
||||
description = "Fix some CS:GO entity issues",
|
||||
version = PLUGIN_VERSION,
|
||||
url = ""
|
||||
}
|
||||
|
||||
Handle g_hSetParent;
|
||||
|
||||
// Entity solid types
|
||||
enum
|
||||
{
|
||||
SOLID_NONE = 0, // no solid model
|
||||
SOLID_BSP = 1, // a BSP tree
|
||||
SOLID_BBOX = 2, // an AABB
|
||||
SOLID_OBB = 3, // an OBB (not implemented yet)
|
||||
SOLID_OBB_YAW = 4, // an OBB, constrained so that it can only yaw
|
||||
SOLID_CUSTOM = 5, // Always call into the entity for tests
|
||||
SOLID_VPHYSICS = 6, // solid vphysics object, get vcollide from the model and collide with that
|
||||
SOLID_LAST,
|
||||
};
|
||||
|
||||
// Entity collision groups
|
||||
enum
|
||||
{
|
||||
COLLISION_GROUP_NONE = 0, // 0
|
||||
COLLISION_GROUP_DEBRIS, // 1 - Collides with nothing but world and static stuff
|
||||
COLLISION_GROUP_DEBRIS_TRIGGER, // 2 - Same as debris, but hits triggers
|
||||
COLLISION_GROUP_INTERACTIVE_DEBRIS, // 3 - Collides with everything except other interactive debris or debris
|
||||
COLLISION_GROUP_INTERACTIVE, // 4 - Collides with everything except interactive debris or debris
|
||||
COLLISION_GROUP_PLAYER, // 5
|
||||
COLLISION_GROUP_BREAKABLE_GLASS, // 6
|
||||
COLLISION_GROUP_VEHICLE, // 7
|
||||
COLLISION_GROUP_PLAYER_MOVEMENT, // 8 - For HL2, same as Collision_Group_Player, for
|
||||
// TF2, this filters out other players and CBaseObjects
|
||||
COLLISION_GROUP_NPC, // 9 - Generic NPC group
|
||||
COLLISION_GROUP_IN_VEHICLE, // 10 - for any entity inside a vehicle
|
||||
COLLISION_GROUP_WEAPON, // 11 - for any weapons that need collision detection
|
||||
COLLISION_GROUP_VEHICLE_CLIP, // 12 - vehicle clip brush to restrict vehicle movement
|
||||
COLLISION_GROUP_PROJECTILE, // 13 - Projectiles!
|
||||
COLLISION_GROUP_DOOR_BLOCKER, // 14 - Blocks entities not permitted to get near moving doors
|
||||
COLLISION_GROUP_PASSABLE_DOOR, // 15 - Doors that the player shouldn't collide with
|
||||
COLLISION_GROUP_DISSOLVING, // 16 - Things that are dissolving are in this group
|
||||
COLLISION_GROUP_PUSHAWAY, // 17 - Nonsolid on client and server, pushaway in player code
|
||||
|
||||
COLLISION_GROUP_NPC_ACTOR, // 18 - Used so NPCs in scripts ignore the player.
|
||||
COLLISION_GROUP_NPC_SCRIPTED, // 19 - USed for NPCs in scripts that should not collide with each other
|
||||
|
||||
LAST_SHARED_COLLISION_GROUP
|
||||
};
|
||||
|
||||
// Physbox spawnflags
|
||||
enum
|
||||
{
|
||||
SF_PHYSBOX_ASLEEP = 0x01000,
|
||||
SF_PHYSBOX_IGNOREUSE = 0x02000,
|
||||
SF_PHYSBOX_DEBRIS = 0x04000,
|
||||
SF_PHYSBOX_MOTIONDISABLED = 0x08000,
|
||||
SF_PHYSBOX_USEPREFERRED = 0x10000,
|
||||
SF_PHYSBOX_ENABLE_ON_PHYSCANNON = 0x20000,
|
||||
SF_PHYSBOX_NO_ROTORWASH_PUSH = 0x40000, // The rotorwash doesn't push these
|
||||
SF_PHYSBOX_ENABLE_PICKUP_OUTPUT = 0x80000,
|
||||
SF_PHYSBOX_ALWAYS_PICK_UP = 0x100000, // Physcannon can always pick this up, no matter what mass or constraints may apply.
|
||||
SF_PHYSBOX_NEVER_PICK_UP = 0x200000, // Physcannon will never be able to pick this up.
|
||||
SF_PHYSBOX_NEVER_PUNT = 0x400000, // Physcannon will never be able to punt this object.
|
||||
SF_PHYSBOX_PREVENT_PLAYER_TOUCH_ENABLE = 0x800000 // If set, the player will not cause the object to enable its motion when bumped into
|
||||
};
|
||||
|
||||
enum struct Patch
|
||||
{
|
||||
char sPatchName[64]; // Signature name to lookup in gamedata
|
||||
bool bNOP; // Whether it's a full-on NOP patch
|
||||
Address iPatchAddress; // Patch address to be later filled in from gamedata
|
||||
char aPatch[128]; // The patch itself
|
||||
char aPatchRestore[128]; // Buffer to store the original bytes
|
||||
int iPatchSize; // Length of the patch
|
||||
}
|
||||
|
||||
Patch g_Patches[] =
|
||||
{
|
||||
{"GameUILag"}, // Prevent game_ui from setting FL_ONTRAIN flag which disables prediction
|
||||
//{"SpeedModFL"} // Prevent player_speedmod from disabling flashlight
|
||||
};
|
||||
|
||||
#define NOP 0x90
|
||||
|
||||
public void OnPluginStart()
|
||||
{
|
||||
Handle hGameConf = LoadGameConfigFile("CSGOFixes.games");
|
||||
if(!hGameConf)
|
||||
{
|
||||
SetFailState("Can't find CSGOFixes.games.txt gamedata.");
|
||||
return;
|
||||
}
|
||||
|
||||
int offset = GameConfGetOffset(hGameConf, "CBaseEntity::SetParent");
|
||||
if (offset == -1)
|
||||
SetFailState("Failed to find CBaseEntity::SetParent offset");
|
||||
|
||||
// DHooks.
|
||||
g_hSetParent = DHookCreate(offset, HookType_Entity, ReturnType_Void, ThisPointer_CBaseEntity, Hook_SetParent);
|
||||
DHookAddParam(g_hSetParent, HookParamType_CBaseEntity);
|
||||
DHookAddParam(g_hSetParent, HookParamType_Int);
|
||||
|
||||
for (int i = 0; i < sizeof(g_Patches); i++)
|
||||
{
|
||||
char sPatchName[128], sPatchOffset[128], sPatchSize[128], sPatch[128];
|
||||
strcopy(sPatchName, 128, g_Patches[i].sPatchName);
|
||||
strcopy(sPatchOffset, 128, g_Patches[i].sPatchName);
|
||||
strcopy(sPatchSize, 128, g_Patches[i].sPatchName);
|
||||
strcopy(sPatch, 128, g_Patches[i].sPatchName);
|
||||
|
||||
Address iAddr = GameConfGetAddress(hGameConf, sPatchName);
|
||||
if(iAddr == Address_Null)
|
||||
{
|
||||
CloseHandle(hGameConf);
|
||||
PrintToServer("Can't find %s address.", sPatchName);
|
||||
return;
|
||||
}
|
||||
|
||||
StrCat(sPatchOffset, 128, "_Offset");
|
||||
// Get the offset from the start of the signature to the start of our patch area.
|
||||
int iOffset = GameConfGetOffset(hGameConf, sPatchOffset);
|
||||
if(iOffset == -1)
|
||||
{
|
||||
CloseHandle(hGameConf);
|
||||
PrintToServer("Can't find Offset for %s in gamedata.", sPatchName);
|
||||
return;
|
||||
}
|
||||
|
||||
// Move right in front of the instructions we want to NOP.
|
||||
iAddr += view_as<Address>(iOffset);
|
||||
g_Patches[i].iPatchAddress = iAddr;
|
||||
|
||||
StrCat(sPatchSize, 128, "_PatchSize");
|
||||
// Get how many bytes we want to NOP.
|
||||
int iPatchSize = GameConfGetOffset(hGameConf, sPatchSize);
|
||||
if(iPatchSize == -1)
|
||||
{
|
||||
CloseHandle(hGameConf);
|
||||
PrintToServer("Can't find PatchBytes for %s in gamedata.", sPatchName);
|
||||
return;
|
||||
}
|
||||
g_Patches[i].iPatchSize = iPatchSize;
|
||||
|
||||
StrCat(sPatch, 128, "_Patch");
|
||||
// Assume it's a NOP patch unless we get an actual patch array
|
||||
if(GameConfGetKeyValue(hGameConf, sPatch, g_Patches[i].aPatch, 128))
|
||||
{
|
||||
PrintToServer("%s isn't a NOP patch.", sPatchName);
|
||||
g_Patches[i].bNOP = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintToServer("%s is a NOP patch.", sPatchName);
|
||||
g_Patches[i].bNOP = false;
|
||||
}
|
||||
}
|
||||
CloseHandle(hGameConf);
|
||||
|
||||
ApplyPatches();
|
||||
}
|
||||
|
||||
public void OnPluginEnd()
|
||||
{
|
||||
RevertPatches();
|
||||
}
|
||||
|
||||
public void ApplyPatches()
|
||||
{
|
||||
for (int i = 0; i < sizeof(g_Patches); i++)
|
||||
{
|
||||
Address iAddr = g_Patches[i].iPatchAddress;
|
||||
|
||||
for(int j = 0; j < g_Patches[i].iPatchSize; j++)
|
||||
{
|
||||
// Save the current instructions, so we can restore them on unload.
|
||||
g_Patches[i].aPatchRestore[j] = LoadFromAddress(iAddr, NumberType_Int8);
|
||||
|
||||
if (g_Patches[i].bNOP)
|
||||
StoreToAddress(iAddr, NOP, NumberType_Int8);
|
||||
else
|
||||
StoreToAddress(iAddr, g_Patches[i].aPatch[j], NumberType_Int8);
|
||||
|
||||
iAddr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RevertPatches()
|
||||
{
|
||||
for (int i = 0; i < sizeof(g_Patches); i++)
|
||||
{
|
||||
Address iAddr = g_Patches[i].iPatchAddress;
|
||||
|
||||
// Restore the original instructions only if we actually patched them
|
||||
if (iAddr != Address_Null)
|
||||
{
|
||||
for(int j = 0; j < g_Patches[i].iPatchSize; j++)
|
||||
{
|
||||
StoreToAddress(iAddr, g_Patches[i].aPatchRestore[j], NumberType_Int8);
|
||||
iAddr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnEntityCreated(int iEntity, const char[] sClassname)
|
||||
{
|
||||
if(StrEqual(sClassname, "func_physbox_multiplayer", false))
|
||||
{
|
||||
RequestFrame(SetDebrisCollisionGroup, iEntity);
|
||||
DHookEntity(g_hSetParent, false, iEntity);
|
||||
}
|
||||
}
|
||||
|
||||
public MRESReturn Hook_SetParent(int iEntity, Handle hReturn, Handle hParams)
|
||||
{
|
||||
RequestFrame(SetDebrisCollisionGroup, iEntity);
|
||||
return MRES_Ignored;
|
||||
}
|
||||
|
||||
public void SetDebrisCollisionGroup(int iEntity)
|
||||
{
|
||||
if (IsValidEntity(iEntity))
|
||||
{
|
||||
// Set collisiongroup to WEAPON to replicate CS:S behavior when parented
|
||||
char parent[64];
|
||||
if(GetEntPropString(iEntity, Prop_Data, "m_iParent", parent, sizeof(parent)))
|
||||
SetEntProp(iEntity, Prop_Data, "m_CollisionGroup", COLLISION_GROUP_WEAPON);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user