//#define DEBUG //#define CSGO_WIN #define PLUGIN_NAME "EventQueue fix" #define PLUGIN_AUTHOR "carnifex" #define PLUGIN_DESCRIPTION "" #define PLUGIN_VERSION "1.0" #define PLUGIN_URL "" #include #include #include #include #include #pragma semicolon 1 #define FLT_EPSILON 1.192092896e-07 // How many bits to use to encode an edict. #define MAX_EDICT_BITS 11 // # of bits needed to represent max edicts // Max # of edicts in a level #define MAX_EDICTS (1<(g_iRefOffset), NumberType_Int32); if(m_RefEHandle == INVALID_EHANDLE_INDEX) return INVALID_EHANDLE_INDEX; // https://github.com/perilouswithadollarsign/cstrike15_src/blob/29e4c1fda9698d5cebcdaf1a0de4b829fa149bf8/public/basehandle.h#L137 int entry_idx = m_RefEHandle & ENT_ENTRY_MASK; if(entry_idx >= MAX_EDICTS) return m_RefEHandle | (1 << 31); return entry_idx; } public MRESReturn DHook_AddEventThree(Handle hParams) { event_t event; DHookGetParamString(hParams, 1, event.target, 64); DHookGetParamString(hParams, 2, event.targetInput, 64); DHookGetParamObjectPtrString(hParams, 3, 0, ObjectValueType_String, event.variantValue, sizeof(event.variantValue)); int ticks = RoundToCeil((view_as(DHookGetParam(hParams, 4)) - FLT_EPSILON) / GetTickInterval()); event.delay = float(ticks); event.activator = EntRefToEntIndex(EntityToBCompatRef(view_as
(DHookGetParam(hParams, 5)))); event.caller = EntRefToEntIndex(EntityToBCompatRef(view_as
(DHookGetParam(hParams, 6)))); event.outputID = DHookGetParam(hParams, 7); #if defined DEBUG PrintToChatAll("AddEventThree: %s, %s, %s, %f, %i, %i, %i, time: %f", event.target, event.targetInput, event.variantValue, event.delay, event.activator, event.caller, event.outputID, GetGameTime()); #endif if((event.activator < 65 && event.activator > 0)) { g_aPlayerEvents[event.activator].PushArray(event); return MRES_Supercede; } return MRES_Ignored; } public Action OnTrigger(const char[] output, int caller, int activator, float delay) { if(activator <= MAXPLAYERS && activator > 0) { float m_flWait = GetEntPropFloat(caller, Prop_Data, "m_flWait"); bool bFound; entity_t ent; for(int i = 0; i < g_aOutputWait[activator].Length; i++) { g_aOutputWait[activator].GetArray(i, ent); if(caller == ent.caller) { bFound = true; break; } } if(!bFound) { ent.caller = caller; ent.waitTime = m_flWait; g_aOutputWait[activator].PushArray(ent); return Plugin_Continue; } else { return Plugin_Handled; } } return Plugin_Continue; } int FindEntityByName(int startEntity, char[] targetname, int searchingEnt, int activator, int caller) { if(!IsValidEntity(activator) || !IsValidEntity(caller) || !IsValidEntity(searchingEnt)) return -1; Address targetEntityAddr = SDKCall(g_hFindEntityByName, startEntity, targetname, searchingEnt, activator, caller, 0); if(targetEntityAddr == Address_Null) return -1; return EntRefToEntIndex(EntityToBCompatRef(targetEntityAddr)); } public void ServiceEvent(event_t event) { int targetEntity = -1; // In the context of the event, the searching entity is also the caller while ((targetEntity = FindEntityByName(targetEntity, event.target, event.caller, event.activator, event.caller)) != -1) { SetVariantString(event.variantValue); AcceptEntityInput(targetEntity, event.targetInput, event.activator, event.caller, event.outputID); #if defined DEBUG PrintToChat(event.activator, "Performing output: %s, %i, %i, %s %s, %i, %f", event.target, targetEntity, event.caller, event.targetInput, event.variantValue, event.outputID, GetGameTime()); #endif } } public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3], float angles[3], int &weapon, int &subtype, int &cmdnum, int &tickcount, int &seed, int mouse[2]) { float timescale = 1.0; if(g_bBhopTimer) timescale = Shavit_GetClientTimescale(client) != -1.0 ? Shavit_GetClientTimescale(client) : Shavit_GetStyleSettingFloat(Shavit_GetBhopStyle(client), "speed"); else timescale = g_fTimescale[client]; for(int i = 0; i < g_aOutputWait[client].Length; i++) { entity_t ent; g_aOutputWait[client].GetArray(i, ent); if(ent.waitTime <= GetTickInterval()*1.5 * timescale) { g_aOutputWait[client].Erase(i); i--; } else { ent.waitTime -= GetTickInterval() * timescale; g_aOutputWait[client].SetArray(i, ent); } } for(int i = 0; i < g_aPlayerEvents[client].Length; i++) { event_t event; g_aPlayerEvents[client].GetArray(i, event); event.delay -= 1.0 * timescale; g_aPlayerEvents[client].SetArray(i, event); if(event.delay <= -1.0 * timescale) { ServiceEvent(event); g_aPlayerEvents[client].Erase(i); i--; } } } public any Native_GetClientEvents(Handle plugin, int numParams) { int client = GetNativeCell(1); if(client < 0 || client > MaxClients || !IsClientConnected(client) || !IsClientInGame(client) || IsClientSourceTV(client)) return false; eventpack_t ep; ep.playerEvents = g_aPlayerEvents[client].Clone(); ep.outputWaits = g_aOutputWait[client].Clone(); SetNativeArray(2, ep, sizeof(eventpack_t)); return true; } public any Native_SetClientEvents(Handle plugin, int numParams) { int client = GetNativeCell(1); if(client < 0 || client > MaxClients || !IsClientConnected(client) || !IsClientInGame(client) || IsClientSourceTV(client)) return false; eventpack_t ep; GetNativeArray(2, ep, sizeof(eventpack_t)); delete g_aPlayerEvents[client]; delete g_aOutputWait[client]; g_aPlayerEvents[client] = ep.playerEvents.Clone(); g_aOutputWait[client] = ep.outputWaits.Clone(); return true; } public any Native_SetEventsTimescale(Handle plugin, int numParams) { int client = GetNativeCell(1); if(client < 0 || client > MaxClients || !IsClientConnected(client) || !IsClientInGame(client) || IsClientSourceTV(client)) return false; g_fTimescale[client] = GetNativeCell(2); return true; } public any Native_ClearClientEvents(Handle plugin, int numParams) { int client = GetNativeCell(1); if(client < 0 || client > MaxClients || !IsClientConnected(client) || !IsClientInGame(client) || IsClientSourceTV(client)) return false; g_aOutputWait[client].Clear(); g_aPlayerEvents[client].Clear(); return true; }