Skip to content

Commit

Permalink
feat: add OnClientAuthorized listener & steamid class
Browse files Browse the repository at this point in the history
  • Loading branch information
roflmuffin committed Oct 15, 2023
1 parent 54f3f9a commit 4ccb091
Show file tree
Hide file tree
Showing 11 changed files with 137 additions and 14 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;

namespace CounterStrikeSharp.API.Core.Attributes;

/**
* Indicates that the parameter should be pulled from the ScriptContext as the passed in type,
* then cast/converted to the parameter type.
*/
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
public class CastFromAttribute : Attribute
{
public Type Type { get; }

public CastFromAttribute(Type type)
{
Type = type;
}
}
25 changes: 16 additions & 9 deletions managed/CounterStrikeSharp.API/Core/BasePlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public BasePlugin()

public abstract string ModuleName { get; }
public abstract string ModuleVersion { get; }

public string ModulePath { get; internal set; }

public string ModuleDirectory => Path.GetDirectoryName(ModulePath);
Expand Down Expand Up @@ -189,7 +189,7 @@ public void UnhookConVarChange(ConVar convar, ConVar.ConVarChangedCallback handl
CommandHandlers.Remove(handler);
}
}*/

// Adds global listener, e.g. OnTick, OnClientConnect
protected void RegisterListener<T>(T handler) where T : Delegate
{
Expand All @@ -198,23 +198,29 @@ protected void RegisterListener<T>(T handler) where T : Delegate
{
throw new Exception("Listener of type T is invalid and does not have a name attribute");
}

var parameterTypes = typeof(T).GetMethod("Invoke").GetParameters().Select(p => p.ParameterType).ToArray();
var castedParameterTypes = typeof(T).GetMethod("Invoke").GetParameters()
.Select(p => p.GetCustomAttribute<CastFromAttribute>()?.Type)
.ToArray();

Console.WriteLine($"Registering listener for {listenerName} with {parameterTypes.Length}");

var wrappedHandler = new Action<ScriptContext>(context =>
{
var args = new object[parameterTypes.Length];
for (int i = 0; i < parameterTypes.Length; i++)
{
args[i] = context.GetArgument(parameterTypes[i], i);
args[i] = context.GetArgument(castedParameterTypes[i] ?? parameterTypes[i], i);
if (castedParameterTypes[i] != null)
args[i] = Activator.CreateInstance(parameterTypes[i], new[] { args[i] });
}

handler.DynamicInvoke(args);
});

var subscriber = new CallbackSubscriber(handler, wrappedHandler, () => { RemoveListener(listenerName, handler); });

var subscriber =
new CallbackSubscriber(handler, wrappedHandler, () => { RemoveListener(listenerName, handler); });

NativeAPI.AddListener(listenerName, subscriber.GetInputArgument());
Listeners[handler] = subscriber;
Expand All @@ -235,7 +241,7 @@ public Timer AddTimer(float interval, Action callback, TimerFlags? flags = null)
Timers.Add(timer);
return timer;
}


public void RegisterAllAttributes(object instance)
{
Expand Down Expand Up @@ -281,7 +287,8 @@ public void RegisterConsoleCommandAttributeHandlers(object instance)
foreach (var eventHandler in eventHandlers)
{
var commandInfo = eventHandler.GetCustomAttribute<ConsoleCommandAttribute>();
AddCommand(commandInfo.Command, commandInfo.Description, eventHandler.CreateDelegate<CommandInfo.CommandCallback>(instance));
AddCommand(commandInfo.Command, commandInfo.Description,
eventHandler.CreateDelegate<CommandInfo.CommandCallback>(instance));
}
}

Expand Down
4 changes: 4 additions & 0 deletions managed/CounterStrikeSharp.API/Core/Listeners.g.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

using System;
using CounterStrikeSharp.API.Core.Attributes;
using CounterStrikeSharp.API.Modules.Entities;

namespace CounterStrikeSharp.API.Core
{
Expand Down Expand Up @@ -29,5 +30,8 @@ public partial class Listeners {

[ListenerName("OnClientDisconnectPost")]
public delegate void OnClientDisconnectPost(int index);

[ListenerName("OnClientAuthorized")]
public delegate void OnClientAuthorized(int index, [CastFrom(typeof(ulong))]SteamID steamId);
}
}
44 changes: 44 additions & 0 deletions managed/CounterStrikeSharp.API/Modules/Entities/SteamID.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using System;

namespace CounterStrikeSharp.API.Modules.Entities
{
public class SteamID
{
const long Base = 76561197960265728;
public ulong SteamId64 { get; set; }

public SteamID(ulong id) => SteamId64 = id;
public SteamID(string id) => SteamId64 = id.StartsWith("[") ? ParseId3(id) : ParseId(id);

public static explicit operator SteamID(ulong u) => new(u);
public static explicit operator SteamID(string s) => new(s);

ulong ParseId(string id)
{
var parts = id.Split(':');
if (parts.Length != 3 || !ulong.TryParse(parts[2], out var num)) throw new FormatException();
return Base + num * 2 + (parts[1] == "1" ? 1UL : 0);
}

ulong ParseId3(string id)
{
var parts = id.Replace("[", "").Replace("]", "").Split(':');
if (parts.Length != 3 || !ulong.TryParse(parts[2], out var num)) throw new FormatException();
return Base + num;
}

public string SteamId2
{
get => $"STEAM_0:{(SteamId64 - Base) % 2}:{(SteamId64 - Base) / 2}";
set => SteamId64 = ParseId(value);
}

public string SteamId3
{
get => $"[U:1:{SteamId64 - Base}]";
set => SteamId64 = ParseId3(value);
}

public override string ToString() => $"[SteamID {SteamId64}, {SteamId2}, {SteamId3}]";
}
}
7 changes: 6 additions & 1 deletion managed/TestPlugin/TestPlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
using CounterStrikeSharp.API.Core.Attributes;
using CounterStrikeSharp.API.Core.Attributes.Registration;
using CounterStrikeSharp.API.Modules.Commands;
using CounterStrikeSharp.API.Modules.Entities;
using CounterStrikeSharp.API.Modules.Events;
using CounterStrikeSharp.API.Modules.Memory;

Expand Down Expand Up @@ -54,7 +55,11 @@ public override void Load(bool hotReload)
{
Log($"Client {name} from {ip} has connected!");
});

RegisterListener<Listeners.OnClientAuthorized>((index, id) =>
{
Log($"Client {index} with address {id}");
});

// You can use `ModuleDirectory` to get the directory of the plugin (for storing config files, saving database files etc.)
File.WriteAllText(Path.Join(ModuleDirectory, "example.txt"),
$"Test file created by TestPlugin at {DateTime.Now}");
Expand Down
36 changes: 34 additions & 2 deletions src/core/managers/player_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ void PlayerManager::OnAllInitialized() {
m_on_client_disconnect_callback = globals::callbackManager.CreateCallback("OnClientDisconnect");
m_on_client_disconnect_post_callback =
globals::callbackManager.CreateCallback("OnClientDisconnectPost");
m_on_client_authorized_callback = globals::callbackManager.CreateCallback("OnClientAuthorized");
}

void PlayerManager::OnShutdown() {
Expand All @@ -125,6 +126,7 @@ void PlayerManager::OnShutdown() {
globals::callbackManager.ReleaseCallback(m_on_client_put_in_server_callback);
globals::callbackManager.ReleaseCallback(m_on_client_disconnect_callback);
globals::callbackManager.ReleaseCallback(m_on_client_disconnect_post_callback);
globals::callbackManager.ReleaseCallback(m_on_client_authorized_callback);
}

bool PlayerManager::OnClientConnect(CPlayerSlot slot,
Expand Down Expand Up @@ -397,8 +399,6 @@ IPlayerInfo *CPlayer::GetPlayerInfo() const { return m_info; }

const char *CPlayer::GetName() const { return strdup(m_name.c_str()); }

const char *CPlayer::GetAuthString() { return ""; }

bool CPlayer::IsConnected() const { return m_is_connected; }

bool CPlayer::IsFakeClient() const { return m_is_fake_client; }
Expand Down Expand Up @@ -453,6 +453,36 @@ PlayerManager::PlayerManager() {
memset(m_user_id_lookup, 0, sizeof(int) * (USHRT_MAX + 1));
}

void PlayerManager::RunAuthChecks() {
if (globals::getGlobalVars()->curtime - m_last_auth_check_time < 0.5F) {
return;
}

m_last_auth_check_time = globals::getGlobalVars()->curtime;

for (int i = 1; i <= m_max_clients; i++) {
if (m_players[i].IsConnected()) {
if (m_players[i].IsAuthorized() || m_players[i].IsFakeClient()) continue;

if (globals::engine->IsClientFullyAuthenticated(i)) {
m_players[i].Authorize();
m_players[i].SetSteamId(globals::engine->GetClientSteamID(i));
OnAuthorized(&m_players[i]);
}
}
}
}

void PlayerManager::OnAuthorized(CPlayer *player) const {
CSSHARP_CORE_TRACE("[PlayerManager][OnAuthorized] - {} {}", player->GetName(),
player->GetSteamId()->ConvertToUint64());

m_on_client_authorized_callback->ScriptContext().Reset();
m_on_client_authorized_callback->ScriptContext().Push(player->m_slot.Get());
m_on_client_authorized_callback->ScriptContext().Push(player->GetSteamId()->ConvertToUint64());
m_on_client_authorized_callback->Execute();
}

bool CPlayer::WasCountedAsInGame() const { return m_is_in_game; }

int CPlayer::GetUserId() {
Expand Down Expand Up @@ -543,5 +573,7 @@ bool CPlayer::IsAlive() const {

return !m_info->IsDead();
}
const CSteamID *CPlayer::GetSteamId() { return m_steamId; }
void CPlayer::SetSteamId(const CSteamID *steam_id) { m_steamId = steam_id; }

} // namespace counterstrikesharp
8 changes: 7 additions & 1 deletion src/core/managers/player_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ class CPlayer {

public:
const char *GetName() const;
const char *GetAuthString();
const CSteamID *GetSteamId();
void SetSteamId(const CSteamID *steam_id);
bool IsConnected() const;
bool IsFakeClient() const;
bool IsAuthorized() const;
Expand Down Expand Up @@ -102,6 +103,7 @@ class CPlayer {
bool m_is_authorized = false;
int m_user_id = 1;
CPlayerSlot m_slot = CPlayerSlot(-1);
const CSteamID* m_steamId;
std::string m_ip_address;
void SetName(const char *name);
INetChannelInfo *GetNetInfo() const;
Expand Down Expand Up @@ -137,12 +139,14 @@ class PlayerManager : public GlobalClass {
const char *pszName,
uint64 xuid,
const char *pszNetworkID) const;
void OnAuthorized(CPlayer* player) const;
void OnServerActivate(edict_t *pEdictList, int edictCount, int clientMax) const;
void OnThink(bool last_tick) const;
void OnShutdown() override;
void OnLevelEnd() override;
void OnClientCommand(CPlayerSlot slot, const CCommand &args) const;
int ListenClient() const;
void RunAuthChecks();

public:
int NumPlayers() const;
Expand All @@ -159,12 +163,14 @@ class PlayerManager : public GlobalClass {
int *m_user_id_lookup;
int m_listen_client;
bool m_is_listen_server;
float m_last_auth_check_time = 0;

ScriptCallback *m_on_client_connect_callback;
ScriptCallback *m_on_client_put_in_server_callback;
ScriptCallback *m_on_client_connected_callback;
ScriptCallback *m_on_client_disconnect_callback;
ScriptCallback *m_on_client_disconnect_post_callback;
ScriptCallback *m_on_client_authorized_callback;
};

} // namespace counterstrikesharp
3 changes: 3 additions & 0 deletions src/core/timer_system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "core/globals.h"
#include "core/log.h"
#include "scripting/callback_manager.h"
#include "core/managers/player_manager.h"

namespace counterstrikesharp {
namespace timers {
Expand Down Expand Up @@ -95,6 +96,8 @@ void TimerSystem::OnGameFrame(bool simulating) {
m_on_tick_callback_->ScriptContext().Reset();
m_on_tick_callback_->Execute();
}

globals::playerManager.RunAuthChecks();
}

double TimerSystem::CalculateNextThink(double last_think_time, float interval) {
Expand Down
3 changes: 2 additions & 1 deletion src/scripting/listeners/players.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ OnClientConnect: index:int, name:string, ipAddress:string
OnClientConnected: index:int
OnClientPutInServer: index:int
OnClientDisconnect: index:int
OnClientDisconnectPost: index:int
OnClientDisconnectPost: index:int
OnClientAuthorized: index:int, steamId:SteamID
2 changes: 2 additions & 0 deletions tooling/CodeGen.Natives/Mapping.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ public static string GetCSharpType(string type)
return "InputArgument";
case "object[]":
return "object[]";
case "SteamID":
return "[CastFrom(typeof(ulong))]SteamID";
}

return "object";
Expand Down
1 change: 1 addition & 0 deletions tooling/CodeGen.Natives/Scripts/GenerateListeners.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public static void GenerateListeners()
var result = $@"
using System;
using CounterStrikeSharp.API.Core.Attributes;
using CounterStrikeSharp.API.Modules.Entities;
namespace CounterStrikeSharp.API.Core
{{
Expand Down

0 comments on commit 4ccb091

Please sign in to comment.