mirror of
https://github.com/roflmuffin/CounterStrikeSharp.git
synced 2025-12-06 16:06:37 -08:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
49974d23fc | ||
|
|
89ef4a6323 | ||
|
|
1b194318af | ||
|
|
22d0dd8200 | ||
|
|
7baf0a25e2 | ||
|
|
9fdbb9500b | ||
|
|
0ab3cf429a | ||
|
|
5211fde474 | ||
|
|
1f9630b92d | ||
|
|
02bf2483d3 | ||
|
|
cb181b6a49 | ||
|
|
291c0db25e | ||
|
|
cc21dca5a0 | ||
|
|
5721d060ea | ||
|
|
220521d571 | ||
|
|
5698b511e9 | ||
|
|
48c9d195ff | ||
|
|
0f994b4ae1 | ||
|
|
64ddf3ef19 | ||
|
|
9b11af112c | ||
|
|
1b6bd22e06 | ||
|
|
8cf9024ee5 |
@@ -83,7 +83,7 @@ SET(SOURCE_FILES
|
||||
src/core/managers/server_manager.h
|
||||
src/scripting/natives/natives_server.cpp
|
||||
libraries/nlohmann/json.hpp
|
||||
src/scripting/natives/natives_dynamichooks.cpp
|
||||
src/scripting/natives/natives_dynamichooks.cpp
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -164,5 +164,12 @@
|
||||
"windows": 91,
|
||||
"linux": 91
|
||||
}
|
||||
},
|
||||
"CEntityIOOutput_FireOutputInternal": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "\\x48\\x8B\\xC4\\x4C\\x89\\x48\\x20\\x55\\x57\\x41\\x54\\x41\\x56",
|
||||
"linux": "\\x55\\x48\\x89\\xE5\\x41\\x57\\x41\\x56\\x41\\x55\\x41\\x54\\x53\\x48\\x83\\xEC\\x58\\x4C\\x8B\\x6F\\x08"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -609,6 +609,30 @@ namespace CounterStrikeSharp.API.Core
|
||||
}
|
||||
}
|
||||
|
||||
public static void HookEntityOutput(string classname, string outputname, InputArgument callback){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
ScriptContext.GlobalScriptContext.Push(classname);
|
||||
ScriptContext.GlobalScriptContext.Push(outputname);
|
||||
ScriptContext.GlobalScriptContext.Push((InputArgument)callback);
|
||||
ScriptContext.GlobalScriptContext.SetIdentifier(0x15245242);
|
||||
ScriptContext.GlobalScriptContext.Invoke();
|
||||
ScriptContext.GlobalScriptContext.CheckErrors();
|
||||
}
|
||||
}
|
||||
|
||||
public static void UnhookEntityOutput(string classname, string outputname, InputArgument callback){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
ScriptContext.GlobalScriptContext.Push(classname);
|
||||
ScriptContext.GlobalScriptContext.Push(outputname);
|
||||
ScriptContext.GlobalScriptContext.Push((InputArgument)callback);
|
||||
ScriptContext.GlobalScriptContext.SetIdentifier(0x87DBD139);
|
||||
ScriptContext.GlobalScriptContext.Invoke();
|
||||
ScriptContext.GlobalScriptContext.CheckErrors();
|
||||
}
|
||||
}
|
||||
|
||||
public static void HookEvent(string name, InputArgument callback, bool ispost){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
|
||||
namespace CounterStrikeSharp.API.Core.Attributes.Registration;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
|
||||
public class EntityOutputHookAttribute : Attribute
|
||||
{
|
||||
public string Classname { get; }
|
||||
public string OutputName { get; }
|
||||
|
||||
public EntityOutputHookAttribute(string classname, string outputName)
|
||||
{
|
||||
Classname = classname;
|
||||
OutputName = outputName;
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ using CounterStrikeSharp.API.Modules.Commands;
|
||||
using CounterStrikeSharp.API.Modules.Events;
|
||||
using CounterStrikeSharp.API.Modules.Timers;
|
||||
using CounterStrikeSharp.API.Modules.Config;
|
||||
using CounterStrikeSharp.API.Modules.Entities;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace CounterStrikeSharp.API.Core
|
||||
@@ -36,6 +37,13 @@ namespace CounterStrikeSharp.API.Core
|
||||
|
||||
public BasePlugin()
|
||||
{
|
||||
RegisterListener<Listeners.OnMapEnd>(() =>
|
||||
{
|
||||
foreach (KeyValuePair<Delegate, EntityIO.EntityOutputCallback> callback in EntitySingleOutputHooks)
|
||||
{
|
||||
UnhookSingleEntityOutputInternal(callback.Value.Classname, callback.Value.Output, callback.Value.Handler);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public abstract string ModuleName { get; }
|
||||
@@ -108,6 +116,12 @@ namespace CounterStrikeSharp.API.Core
|
||||
public readonly Dictionary<Delegate, CallbackSubscriber> Listeners =
|
||||
new Dictionary<Delegate, CallbackSubscriber>();
|
||||
|
||||
public readonly Dictionary<Delegate, CallbackSubscriber> EntityOutputHooks =
|
||||
new Dictionary<Delegate, CallbackSubscriber>();
|
||||
|
||||
internal readonly Dictionary<Delegate, EntityIO.EntityOutputCallback> EntitySingleOutputHooks =
|
||||
new Dictionary<Delegate, EntityIO.EntityOutputCallback>();
|
||||
|
||||
public readonly List<Timer> Timers = new List<Timer>();
|
||||
|
||||
public delegate HookResult GameEventHandler<T>(T @event, GameEventInfo info) where T : GameEvent;
|
||||
@@ -354,6 +368,7 @@ namespace CounterStrikeSharp.API.Core
|
||||
{
|
||||
this.RegisterAttributeHandlers(instance);
|
||||
this.RegisterConsoleCommandAttributeHandlers(instance);
|
||||
this.RegisterEntityOutputAttributeHandlers(instance);
|
||||
}
|
||||
|
||||
public void InitializeConfig(object instance, Type pluginType)
|
||||
@@ -430,6 +445,75 @@ namespace CounterStrikeSharp.API.Core
|
||||
}
|
||||
}
|
||||
|
||||
public void RegisterEntityOutputAttributeHandlers(object instance)
|
||||
{
|
||||
var handlers = instance.GetType()
|
||||
.GetMethods()
|
||||
.Where(method => method.GetCustomAttributes<EntityOutputHookAttribute>().Any())
|
||||
.ToArray();
|
||||
|
||||
foreach (var handler in handlers)
|
||||
{
|
||||
var attributes = handler.GetCustomAttributes<EntityOutputHookAttribute>();
|
||||
foreach (var outputInfo in attributes)
|
||||
{
|
||||
HookEntityOutput(outputInfo.Classname, outputInfo.OutputName, handler.CreateDelegate<EntityIO.EntityOutputHandler>(instance));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void HookEntityOutput(string classname, string outputName, EntityIO.EntityOutputHandler handler)
|
||||
{
|
||||
var subscriber = new CallbackSubscriber(handler, handler,
|
||||
() => UnhookEntityOutput(classname, outputName, handler));
|
||||
|
||||
NativeAPI.HookEntityOutput(classname, outputName, subscriber.GetInputArgument());
|
||||
EntityOutputHooks[handler] = subscriber;
|
||||
}
|
||||
|
||||
public void UnhookEntityOutput(string classname, string outputName, EntityIO.EntityOutputHandler handler)
|
||||
{
|
||||
if (!EntityOutputHooks.TryGetValue(handler, out var subscriber)) return;
|
||||
|
||||
NativeAPI.UnhookEntityOutput(classname, outputName, subscriber.GetInputArgument());
|
||||
FunctionReference.Remove(subscriber.GetReferenceIdentifier());
|
||||
EntityOutputHooks.Remove(handler);
|
||||
}
|
||||
|
||||
public void HookSingleEntityOutput(CEntityInstance entityInstance, string outputName, EntityIO.EntityOutputHandler handler)
|
||||
{
|
||||
// since we wrap around the plugin handler we need to do this to ensure that the plugin callback is only called
|
||||
// if the entity instance is the same.
|
||||
EntityIO.EntityOutputHandler internalHandler = (string name, CEntityInstance activator, CEntityInstance caller, float delay) =>
|
||||
{
|
||||
if (caller == entityInstance)
|
||||
{
|
||||
handler(name, activator, caller, delay);
|
||||
}
|
||||
};
|
||||
|
||||
HookEntityOutput(entityInstance.DesignerName, outputName, internalHandler);
|
||||
|
||||
// because of ^ we would not be able to unhook since we passed the 'internalHandler' and that's what is being stored, not the original handler
|
||||
// but the plugin could only pass the original handler for unhooking.
|
||||
// (this dictionary does not needed to be cleared on dispose as it has no unmanaged reference and those are already being disposed, but on map end)
|
||||
// (the internal class is needed to be able to remove them on map start)
|
||||
EntitySingleOutputHooks[handler] = new EntityIO.EntityOutputCallback(entityInstance.DesignerName, outputName, internalHandler);
|
||||
}
|
||||
|
||||
public void UnhookSingleEntityOutput(CEntityInstance entityInstance, string outputName, EntityIO.EntityOutputHandler handler)
|
||||
{
|
||||
UnhookSingleEntityOutputInternal(entityInstance.DesignerName, outputName, handler);
|
||||
}
|
||||
|
||||
private void UnhookSingleEntityOutputInternal(string classname, string outputName, EntityIO.EntityOutputHandler handler)
|
||||
{
|
||||
if (!EntitySingleOutputHooks.TryGetValue(handler, out var internalHandler)) return;
|
||||
|
||||
UnhookEntityOutput(classname, outputName, internalHandler.Handler);
|
||||
EntitySingleOutputHooks.Remove(handler);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
@@ -464,6 +548,11 @@ namespace CounterStrikeSharp.API.Core
|
||||
subscriber.Dispose();
|
||||
}
|
||||
|
||||
foreach (var subscriber in EntityOutputHooks.Values)
|
||||
{
|
||||
subscriber.Dispose();
|
||||
}
|
||||
|
||||
foreach (var timer in Timers)
|
||||
{
|
||||
timer.Kill();
|
||||
|
||||
@@ -36,12 +36,12 @@ public partial class CEntityInstance : IEquatable<CEntityInstance>
|
||||
|
||||
public bool Equals(CEntityInstance? other)
|
||||
{
|
||||
return this.EntityHandle.Equals(other?.EntityHandle);
|
||||
return this.EntityHandle == other?.EntityHandle;
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is CEntityInstance other && Equals(other);
|
||||
return ReferenceEquals(this, obj) || obj is CEntityInstance other && Equals(other);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
|
||||
39
managed/CounterStrikeSharp.API/Modules/Entities/EntityIO.cs
Normal file
39
managed/CounterStrikeSharp.API/Modules/Entities/EntityIO.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* This file is part of CounterStrikeSharp.
|
||||
* CounterStrikeSharp is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CounterStrikeSharp is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Entities
|
||||
{
|
||||
public class EntityIO
|
||||
{
|
||||
public delegate void EntityOutputHandler(string name, CEntityInstance activator, CEntityInstance caller, float delay);
|
||||
|
||||
internal class EntityOutputCallback
|
||||
{
|
||||
public string Classname;
|
||||
|
||||
public string Output;
|
||||
|
||||
public EntityOutputHandler Handler;
|
||||
|
||||
public EntityOutputCallback(string classname, string output, EntityOutputHandler handler)
|
||||
{
|
||||
Classname = classname;
|
||||
Output = output;
|
||||
Handler = handler;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -62,12 +62,17 @@ public class CHandle<T> : IEquatable<CHandle<T>> where T : NativeEntity
|
||||
|
||||
public bool Equals(CHandle<T>? other)
|
||||
{
|
||||
return other != null && Raw == other.Raw;
|
||||
if (ReferenceEquals(null, other)) return false;
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
return Raw == other.Raw;
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return Equals(obj as CHandle<T>);
|
||||
if (ReferenceEquals(null, obj)) return false;
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
if (obj.GetType() != this.GetType()) return false;
|
||||
return Equals((CHandle<T>)obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
|
||||
@@ -93,6 +93,7 @@ namespace TestPlugin
|
||||
SetupListeners();
|
||||
SetupCommands();
|
||||
SetupMenus();
|
||||
SetupEntityOutputHooks();
|
||||
|
||||
// ValveInterface provides pointers to loaded modules via Interface Name exposed from the engine (e.g. Source2Server001)
|
||||
var server = ValveInterface.Server;
|
||||
@@ -406,6 +407,14 @@ namespace TestPlugin
|
||||
});
|
||||
}
|
||||
|
||||
private void SetupEntityOutputHooks()
|
||||
{
|
||||
HookEntityOutput("weapon_knife", "OnPlayerPickup", (string name, CEntityInstance activator, CEntityInstance caller, float delay) =>
|
||||
{
|
||||
Logger.LogInformation("weapon_knife called OnPlayerPickup ({name}, {activator}, {caller}, {delay})", name, activator.DesignerName, caller.DesignerName, delay);
|
||||
});
|
||||
}
|
||||
|
||||
[GameEventHandler]
|
||||
public HookResult OnPlayerConnect(EventPlayerConnect @event, GameEventInfo info)
|
||||
{
|
||||
@@ -544,5 +553,11 @@ namespace TestPlugin
|
||||
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
[EntityOutputHook("weapon_knife", "OnPlayerPickup")]
|
||||
public void OnKnifePickup(string name, CEntityInstance activator, CEntityInstance caller, float delay)
|
||||
{
|
||||
Logger.LogInformation("[EntityOutputHook Attribute] weapon_knife called OnPlayerPickup ({name}, {activator}, {caller}, {delay})", name, activator.DesignerName, caller.DesignerName, delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
*/
|
||||
|
||||
#include "core/managers/entity_manager.h"
|
||||
#include "core/gameconfig.h"
|
||||
#include "core/log.h"
|
||||
|
||||
#include <funchook.h>
|
||||
|
||||
#include <public/eiface.h>
|
||||
#include "scripting/callback_manager.h"
|
||||
@@ -30,6 +34,19 @@ void EntityManager::OnAllInitialized() {
|
||||
on_entity_created_callback = globals::callbackManager.CreateCallback("OnEntityCreated");
|
||||
on_entity_deleted_callback = globals::callbackManager.CreateCallback("OnEntityDeleted");
|
||||
on_entity_parent_changed_callback = globals::callbackManager.CreateCallback("OnEntityParentChanged");
|
||||
|
||||
m_pFireOutputInternal = reinterpret_cast<FireOutputInternal>(
|
||||
modules::server->FindSignature(globals::gameConfig->GetSignature("CEntityIOOutput_FireOutputInternal")));
|
||||
|
||||
if (m_pFireOutputInternal == nullptr) {
|
||||
CSSHARP_CORE_ERROR("Failed to find signature for \'CEntityIOOutput_FireOutputInternal\'");
|
||||
return;
|
||||
}
|
||||
|
||||
auto m_hook = funchook_create();
|
||||
funchook_prepare(m_hook, (void**)&m_pFireOutputInternal, (void*)&DetourFireOutputInternal);
|
||||
funchook_install(m_hook, 0);
|
||||
|
||||
// Listener is added in ServerStartup as entity system is not initialised at this stage.
|
||||
}
|
||||
|
||||
@@ -79,4 +96,68 @@ void CEntityListener::OnEntityParentChanged(CEntityInstance *pEntity, CEntityIns
|
||||
}
|
||||
}
|
||||
|
||||
void EntityManager::HookEntityOutput(const char* szClassname, const char* szOutput,
|
||||
CallbackT fnCallback)
|
||||
{
|
||||
auto outputKey = OutputKey_t(szClassname, szOutput);
|
||||
counterstrikesharp::ScriptCallback* callback;
|
||||
|
||||
auto search = m_pHookMap.find(outputKey);
|
||||
if (search == m_pHookMap.end()) {
|
||||
callback = globals::callbackManager.CreateCallback("");
|
||||
m_pHookMap[outputKey] = callback;
|
||||
}
|
||||
else
|
||||
callback = search->second;
|
||||
|
||||
callback->AddListener(fnCallback);
|
||||
}
|
||||
|
||||
void EntityManager::UnhookEntityOutput(const char* szClassname, const char* szOutput,
|
||||
CallbackT fnCallback)
|
||||
{
|
||||
auto outputKey = OutputKey_t(szClassname, szOutput);
|
||||
counterstrikesharp::ScriptCallback* callback;
|
||||
|
||||
auto search = m_pHookMap.find(outputKey);
|
||||
if (search != m_pHookMap.end()) {
|
||||
auto callback = search->second;
|
||||
callback->RemoveListener(fnCallback);
|
||||
|
||||
if (!callback->GetFunctionCount()) {
|
||||
globals::callbackManager.ReleaseCallback(callback);
|
||||
m_pHookMap.erase(outputKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DetourFireOutputInternal(CEntityIOOutput* const pThis, CEntityInstance* pActivator,
|
||||
CEntityInstance* pCaller, const CVariant* const value, float flDelay)
|
||||
{
|
||||
if (pCaller) {
|
||||
CSSHARP_CORE_TRACE("[EntityManager][FireOutputHook] - {}, {}", pThis->m_pDesc->m_pName,
|
||||
pCaller->GetClassname());
|
||||
|
||||
auto outputKey = OutputKey_t(pCaller->GetClassname(), pThis->m_pDesc->m_pName);
|
||||
auto& hookMap = globals::entityManager.m_pHookMap;
|
||||
|
||||
auto search = hookMap.find(outputKey);
|
||||
if (search != hookMap.end()) {
|
||||
auto callback = search->second;
|
||||
|
||||
if (callback && callback->GetFunctionCount()) {
|
||||
callback->ScriptContext().Reset();
|
||||
callback->ScriptContext().Push(pThis->m_pDesc->m_pName);
|
||||
callback->ScriptContext().Push(pActivator);
|
||||
callback->ScriptContext().Push(pCaller);
|
||||
callback->ScriptContext().Push(flDelay);
|
||||
callback->Execute();
|
||||
}
|
||||
}
|
||||
} else
|
||||
CSSHARP_CORE_TRACE("[EntityManager][FireOutputHook] - {}, unknown caller", pThis->m_pDesc->m_pName);
|
||||
|
||||
m_pFireOutputInternal(pThis, pActivator, pCaller, value, flDelay);
|
||||
}
|
||||
|
||||
} // namespace counterstrikesharp
|
||||
@@ -24,9 +24,16 @@
|
||||
#include "scripting/script_engine.h"
|
||||
#include "entitysystem.h"
|
||||
|
||||
// variant.h depends on ivscript.h, lets not include the whole thing
|
||||
DECLARE_POINTER_HANDLE(HSCRIPT);
|
||||
|
||||
#include <variant.h>
|
||||
|
||||
namespace counterstrikesharp {
|
||||
class ScriptCallback;
|
||||
|
||||
typedef std::pair<std::string, std::string> OutputKey_t;
|
||||
|
||||
class CEntityListener : public IEntityListener {
|
||||
void OnEntitySpawned(CEntityInstance *pEntity) override;
|
||||
void OnEntityCreated(CEntityInstance *pEntity) override;
|
||||
@@ -41,7 +48,10 @@ public:
|
||||
~EntityManager();
|
||||
void OnAllInitialized() override;
|
||||
void OnShutdown() override;
|
||||
void HookEntityOutput(const char* szClassname, const char* szOutput, CallbackT fnCallback);
|
||||
void UnhookEntityOutput(const char* szClassname, const char* szOutput, CallbackT fnCallback);
|
||||
CEntityListener entityListener;
|
||||
std::map<OutputKey_t, counterstrikesharp::ScriptCallback*> m_pHookMap;
|
||||
private:
|
||||
ScriptCallback *on_entity_spawned_callback;
|
||||
ScriptCallback *on_entity_created_callback;
|
||||
@@ -49,4 +59,58 @@ private:
|
||||
ScriptCallback *on_entity_parent_changed_callback;
|
||||
};
|
||||
|
||||
|
||||
enum EntityIOTargetType_t
|
||||
{
|
||||
ENTITY_IO_TARGET_INVALID = 0xFFFFFFFF,
|
||||
ENTITY_IO_TARGET_CLASSNAME = 0x0,
|
||||
ENTITY_IO_TARGET_CLASSNAME_DERIVES_FROM = 0x1,
|
||||
ENTITY_IO_TARGET_ENTITYNAME = 0x2,
|
||||
ENTITY_IO_TARGET_CONTAINS_COMPONENT = 0x3,
|
||||
ENTITY_IO_TARGET_SPECIAL_ACTIVATOR = 0x4,
|
||||
ENTITY_IO_TARGET_SPECIAL_CALLER = 0x5,
|
||||
ENTITY_IO_TARGET_EHANDLE = 0x6,
|
||||
ENTITY_IO_TARGET_ENTITYNAME_OR_CLASSNAME = 0x7,
|
||||
};
|
||||
|
||||
struct EntityIOConnectionDesc_t
|
||||
{
|
||||
string_t m_targetDesc;
|
||||
string_t m_targetInput;
|
||||
string_t m_valueOverride;
|
||||
CEntityHandle m_hTarget;
|
||||
EntityIOTargetType_t m_nTargetType;
|
||||
int32 m_nTimesToFire;
|
||||
float m_flDelay;
|
||||
};
|
||||
|
||||
struct EntityIOConnection_t : EntityIOConnectionDesc_t
|
||||
{
|
||||
bool m_bMarkedForRemoval;
|
||||
EntityIOConnection_t* m_pNext;
|
||||
};
|
||||
|
||||
struct EntityIOOutputDesc_t
|
||||
{
|
||||
const char* m_pName;
|
||||
uint32 m_nFlags;
|
||||
uint32 m_nOutputOffset;
|
||||
};
|
||||
|
||||
class CEntityIOOutput
|
||||
{
|
||||
public:
|
||||
void* vtable;
|
||||
EntityIOConnection_t* m_pConnections;
|
||||
EntityIOOutputDesc_t* m_pDesc;
|
||||
};
|
||||
|
||||
typedef void (*FireOutputInternal)(CEntityIOOutput* const, CEntityInstance*, CEntityInstance*,
|
||||
const CVariant* const, float);
|
||||
|
||||
static void DetourFireOutputInternal(CEntityIOOutput* const pThis, CEntityInstance* pActivator,
|
||||
CEntityInstance* pCaller, const CVariant* const value, float flDelay);
|
||||
|
||||
static FireOutputInternal m_pFireOutputInternal = nullptr;
|
||||
|
||||
} // namespace counterstrikesharp
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "core/memory.h"
|
||||
#include "core/log.h"
|
||||
#include "core/managers/player_manager.h"
|
||||
#include "core/managers/entity_manager.h"
|
||||
|
||||
#include <public/entity2/entitysystem.h>
|
||||
|
||||
@@ -132,6 +133,22 @@ unsigned long GetPlayerAuthorizedSteamID(ScriptContext& script_context) {
|
||||
return pSteamId->ConvertToUint64();
|
||||
}
|
||||
|
||||
void HookEntityOutput(ScriptContext& script_context)
|
||||
{
|
||||
auto szClassname = script_context.GetArgument<const char*>(0);
|
||||
auto szOutput = script_context.GetArgument<const char*>(1);
|
||||
auto callback = script_context.GetArgument<CallbackT>(2);
|
||||
globals::entityManager.HookEntityOutput(szClassname, szOutput, callback);
|
||||
}
|
||||
|
||||
void UnhookEntityOutput(ScriptContext& script_context)
|
||||
{
|
||||
auto szClassname = script_context.GetArgument<const char*>(0);
|
||||
auto szOutput = script_context.GetArgument<const char*>(1);
|
||||
auto callback = script_context.GetArgument<CallbackT>(2);
|
||||
globals::entityManager.UnhookEntityOutput(szClassname, szOutput, callback);
|
||||
}
|
||||
|
||||
REGISTER_NATIVES(entities, {
|
||||
ScriptEngine::RegisterNativeHandler("GET_ENTITY_FROM_INDEX", GetEntityFromIndex);
|
||||
ScriptEngine::RegisterNativeHandler("GET_USERID_FROM_INDEX", GetUserIdFromIndex);
|
||||
@@ -145,5 +162,7 @@ REGISTER_NATIVES(entities, {
|
||||
ScriptEngine::RegisterNativeHandler("PRINT_TO_CONSOLE", PrintToConsole);
|
||||
ScriptEngine::RegisterNativeHandler("GET_FIRST_ACTIVE_ENTITY", GetFirstActiveEntity);
|
||||
ScriptEngine::RegisterNativeHandler("GET_PLAYER_AUTHORIZED_STEAMID", GetPlayerAuthorizedSteamID);
|
||||
ScriptEngine::RegisterNativeHandler("HOOK_ENTITY_OUTPUT", HookEntityOutput);
|
||||
ScriptEngine::RegisterNativeHandler("UNHOOK_ENTITY_OUTPUT", UnhookEntityOutput);
|
||||
})
|
||||
} // namespace counterstrikesharp
|
||||
@@ -8,4 +8,6 @@ GET_CONCRETE_ENTITY_LIST_POINTER: -> pointer
|
||||
IS_REF_VALID_ENTITY: entityRef:uint -> bool
|
||||
PRINT_TO_CONSOLE: index:int, message:string -> void
|
||||
GET_FIRST_ACTIVE_ENTITY: -> pointer
|
||||
GET_PLAYER_AUTHORIZED_STEAMID: slot:int -> uint64
|
||||
GET_PLAYER_AUTHORIZED_STEAMID: slot:int -> uint64
|
||||
HOOK_ENTITY_OUTPUT: classname:string, outputName:string, callback:func -> void
|
||||
UNHOOK_ENTITY_OUTPUT: classname:string, outputName:string, callback:func -> void
|
||||
Reference in New Issue
Block a user