2020 rewrite

This commit is contained in:
2020-06-15 00:47:53 +02:00
parent e734033a82
commit 26c04ddefc
18 changed files with 908 additions and 892 deletions

View File

@@ -0,0 +1,29 @@
#include "Interfaces.sp"
public Action:Event_RoundStart(Handle:event, const String:name[], bool:dontBroadcast){
SubmittEventActiveClients();
SubmittEventMapInformation();
/* generate session id for this round */
SetConVarInt(FindConVar("session-id"), GetRandomInt(0, 200000));
return Plugin_Continue;
}
public Action:Event_RoundEnd(Handle:event, const String:name[], bool:dontBroadcast){
SubmittEventActiveClients();
new team_id = GetEventInt(event, "winner");
SubmittEventWinnerTeam(team_id);
SubmittEventRoundEnd();
return Plugin_Continue;
}
public Action:Event_PlayerDisconnect(Handle:event, const String:name[], bool:dontBroadcast){
SubmittEventActiveClients();
return Plugin_Continue;
}
public Action:Event_PlayerChangedTeam(Handle:event, const String:name[], bool:dontBroadcast){
SubmittEventActiveClients();
return Plugin_Continue;
}

View File

@@ -0,0 +1,44 @@
#include <sourcemod>
#include <sdktools>
#include <system2>
#define DEFAULT_LEN 64
#define SNAME_LEN 256
#define VAR_TARGET_PORT "skillbird_target_port"
public void PrintHttpResponse(bool success, const char[] error, System2HTTPRequest request, System2HTTPResponse response, HTTPRequestMethod method) {
if (success) {
if(response.StatusCode == 204 || response.StatusCode == 200){
char[] content = new char[response.ContentLength + 1];
response.GetContent(content, response.ContentLength + 1);
PrintToChatAll("%s", content);
}else if(response.StatusCode == 404){
PrintToChatAll("skillbird:error:player_not_in_db");
}else{
PrintToChatAll("skillbird:error:scheduled_downtime:database_backup");
}
} else {
PrintToChatAll("skillbird:error: backend unavailiable");
}
}
public void DisplayRating(int client){
new String:url[SNAME_LEN];
new String:clientId[DEFAULT_LEN];
GetClientAuthId(client, AuthId_SteamID64, clientId, DEFAULT_LEN);
Format(url, sizeof(url), "http://localhost:%d/get-player-rating-msg?id=%s", GetConVarInt(FindConVar(VAR_TARGET_PORT)), clientId);
System2HTTPRequest httpRequest = new System2HTTPRequest(PrintHttpResponse, url);
httpRequest.GET();
}
public Action Timer_ConnectMessage(Handle timer, int client){
DisplayRating(client);
return Plugin_Continue;
}
public Action CommandRating(int client, int args){
DisplayRating(client);
return Plugin_Continue;
}

99
scripting/Interfaces.sp Normal file
View File

@@ -0,0 +1,99 @@
#pragma tabsize 0
#include <sourcemod>
#include <sdktools>
#include <socket>
#include <system2>
#include <json>
#define DEFAULT_LEN 64
#define SNAME_LEN 256
#define ACTIVE_CLIENTS_LENGTH 8192
#define VAR_TARGET_PORT "skillbird_target_port"
#define VAR_SESSION_ID "session_id"
public void HttpResponseCallback(bool success, const char[] error, System2HTTPRequest request, System2HTTPResponse response, HTTPRequestMethod method) {
}
public void SubmittViaHTTP(char[] jsonString){
new String:url[SNAME_LEN];
Format(url, sizeof(url), "http://localhost:%d/single-event?session=%d", GetConVarInt(FindConVar(VAR_TARGET_PORT)), GetConVarInt(FindConVar(VAR_SESSION_ID)) );
System2HTTPRequest httpRequest = new System2HTTPRequest(HttpResponseCallback, url);
httpRequest.SetHeader("Content-Type", "application/json");
httpRequest.SetData(jsonString);
httpRequest.POST();
}
public void SubmittEventActiveClients(){
/* primary json */
JSON_Object obj = new JSON_Object();
obj.SetString("etype", "active_players");
obj.SetInt("timestamp", GetTime());
/* generate players */
JSON_Array players = new JSON_Array();
for(new i = 1; i <= MaxClients;i++){
if(!IsClientConnected(i)){
continue;
}
JSON_Object player = new JSON_Object();
new String:clientId[DEFAULT_LEN];
new String:clientName[SNAME_LEN];
GetClientAuthId(i, AuthId_SteamID64, clientId, DEFAULT_LEN, true);
GetClientName(i, clientName, SNAME_LEN);
player.SetString("id", clientId);
player.SetString("name", clientName);
player.SetInt("team", GetClientTeam(i));
players.PushObject(player);
}
/* add players array to primary object */
obj.SetObject("players", players);
char output[2048];
obj.Encode(output, sizeof(output));
SubmittViaHTTP(output);
}
public void SubmittEventMapInformation(){
new String:mapname[DEFAULT_LEN];
GetCurrentMap(mapname, sizeof(mapname));
JSON_Object obj = new JSON_Object();
obj.SetString("etype", "map");
obj.SetInt("timestamp", GetTime());
obj.SetString("map", mapname);
char output[2048];
obj.Encode(output, sizeof(output));
SubmittViaHTTP(output);
}
public void SubmittEventWinnerTeam(int team_id){
JSON_Object obj = new JSON_Object();
obj.SetString("etype", "winner");
obj.SetInt("timestamp", GetTime());
obj.SetInt("winnerTeam", team_id);
char output[2048];
obj.Encode(output, sizeof(output));
SubmittViaHTTP(output);
}
public void SubmittEventRoundEnd(){
JSON_Object obj = new JSON_Object();
obj.SetString("etype", "round_end");
obj.SetInt("timestamp", GetTime());
char output[2048];
obj.Encode(output, sizeof(output));
SubmittViaHTTP(output);
}

46
scripting/Skillbird.sp Normal file
View File

@@ -0,0 +1,46 @@
#pragma tabsize 0
#include <sourcemod>
#include <sdktools>
#include "IngameMessages.sp"
#include "EventHandlers.sp"
#define DEFAULT_LEN 64
#define SNAME_LEN 256
#define VAR_SESSION_ID "session_id"
#define VAR_TARGET_PORT "skillbird_target_port"
/* ---------------------- Plugin ---------------------- */
public Plugin:myinfo = {
name = "Skillbird",
author = "FAUSheppy",
description = "Module to interact with the skillbird framework",
version = "3.0",
url = "https://github.com/FAUSheppy/skillbird-sourcemod"
};
public APLRes:AskPluginLoad2(Handle:myself, bool:late, String:error[], err_max){
return APLRes_Success;
}
public OnPluginStart(){
/* Hook Events */
HookEvent("round_end", Event_RoundEnd);
HookEvent("player_team", Event_PlayerChangedTeam);
HookEvent("player_disconnect", Event_PlayerDisconnect);
CreateConVar(VAR_SESSION_ID, "0", "Session in for this round");
CreateConVar(VAR_TARGET_PORT, "6200", "Skillbird backend target port", FCVAR_PROTECTED);
RegConsoleCmd("rating", CommandRating);
}
public OnClientAuthorized(client, const String:auth[]){
CreateTimer(5.0, Timer_ConnectMessage, client);
}
public OnMapStart(){
SetConVarInt(FindConVar(VAR_SESSION_ID), GetRandomInt(1, 200000));
}

View File

@@ -1,92 +0,0 @@
#pragma tabsize 0
#include <sourcemod>
#include <sdktools>
#include <socket>
#include "client.sp"
#include "utils.sp"
#include "query.sp"
#define DEFAULT_LEN 64
#define SNAME_LEN 256
/* ---------------------- Globals ---------------------- */
static Handle:logfile;
/* ---------------------- Timers ---------------------- */
public Action:Timer_MapStart(Handle:timer){
LogActiveClients(logfile, "0x42,map_start_active,");
return Plugin_Continue;
}
public Action:Timer_RoundStart(Handle:timer){
LogActiveClients(logfile, "0x42,round_start_active,");
char map[SNAME_LEN];
MapName("0x42,mapname,", map, sizeof(map));
LogToOpenFile(logfile, map);
return Plugin_Continue;
}
/* ---------------------- Events ---------------------- */
public Action:Event_RoundStart(Handle:event, const String:name[], bool:dontBroadcast){
LogActiveClients(logfile, "0x42,round_start_active,");
return Plugin_Continue;
}
public Action:Event_RoundEnd(Handle:event, const String:name[], bool:dontBroadcast){
char eventWTeam[SNAME_LEN];
EventWinnerTeam(event, "0x42,winner,", eventWTeam, sizeof(eventWTeam));
LogToOpenFile(logfile, eventWTeam);
LogActiveClients(logfile, "0x42,round_end_active,");
return Plugin_Continue;
}
public Action:Event_PlayerDisconnect(Handle:event, const String:name[], bool:dontBroadcast){
LogClientEventFormat(logfile, event, "0x42,disconnect,");
LogActiveClients(logfile, "0x42,dc,");
return Plugin_Continue;
}
public Action:Event_PlayerChangedTeam(Handle:event, const String:name[], bool:dontBroadcast){
LogActiveClients(logfile, "0x42,tc,");
LogClientEventFormat(logfile, event, "0x42,teamchange,");
return Plugin_Continue;
}
public OnMapStart(){
CreateTimer(5.0, Timer_MapStart);
}
/* ---------------------- Plugin ---------------------- */
public Plugin:myinfo = {
name = "skillbird-data-collection,
author = "FAUSheppy",
description = "Module to collect data for the skillbird framework",
version = "2.0",
url = "https://github.com/FAUSheppy/skillbird-sourcemod"
};
public APLRes:AskPluginLoad2(Handle:myself, bool:late, String:error[], err_max){
return APLRes_Success;
}
public OnPluginStart(){
/* get and verify server name for output file */
char server[SNAME_LEN];
ServerName(server, sizeof(server));
logfile = OpenFile(server, "at", false, NULL_STRING);
if strlen(server) < 1:
return ThrowNativeError(SP_ERROR_NATIVE, "Computed Invalid Servername '%s'", server)
/* inial line */
LogToOpenFile(logfile, "0x42,start");
/* Hook Events */
HookEvent("round_end", Event_RoundEnd);
HookEvent("player_team", Event_PlayerChangedTeam);
HookEvent("player_disconnect", Event_PlayerDisconnect);
}
public OnPluginEnd(){
LogToOpenFile(logfile, "0x42,plugin unloaded");
CloseHandle(logfile);
}

View File

@@ -1,61 +0,0 @@
/* no idea, but removes warnings */
#pragma tabsize 0
#include <sourcemod>
#include <sdktools>
#include <socket>
#include "query.sp"
#include "client.sp"
#include "utils.sp"
#define DEFAULT_LEN 64
#define INVALID 0
#define REBUILD_TEAM true
#define NO_REBUILD_TEAM false
/* ---------------------- Hooks ---------------------- */
public OnClientAuthorized(client,const String:auth[]){
CreateTimer(5.0, Timer_ConnectMessage, client);
CreateTimer(5.0, Timer_QueryTeam, client);
}
public OnScrambleTeams(){
QueryTeam(GetSocket(), "NONE", REBUILD_TEAM);
}
/* ---------------------- Timers ---------------------- */
public Action Timer_ConnectMessage(Handle timer, int client){
QueryRating(client);
return Plugin_Continue;
}
public Action Timer_QueryTeam(Handle timer, int client){
char clientIDString[DEFAULT_LEN];
ClientID(client, clientIDString, DEFAULT_LEN);
QueryTeam(GetSocket(), clientIDString, false);
return Plugin_Continue;
}
/* ---------------------- Plugin ---------------------- */
public Plugin:myinfo = {
name = "skillbird-query",
author = "FAUSheppy",
description = "Module for interaction with the skillbird API",
version = "2.0",
url = "https://github.com/FAUSheppy/skillbird-sourcemod"
};
public APLRes:AskPluginLoad2(Handle:myself, bool:late, String:error[], err_max){
return APLRes_Success;
}
public OnPluginStart(){
CreateQuerySocket(7040);
}
public OnPluginEnd(){
if (GetSocket() == INVALID_HANDLE){
return;
}
CloseHandle(GetSocket());
}

View File

@@ -1,63 +0,0 @@
#pragma tabsize 0
#include <sourcemod>
#include <sdktools>
#include <socket>
#define DEFAULT_LEN 64
#define SNAME_LEN 256
#define ACTIVE_CLIENTS_LENGTH 8192
public void ClientName(const client,char[] buf,buflen){
new String:name[DEFAULT_LEN];
if(IsClientConnected(client)){
GetClientName(client, name, DEFAULT_LEN);
/* get fucked if you use my seperators in your name */
ReplaceString(name, DEFAULT_LEN,",","$");
ReplaceString(name, DEFAULT_LEN,"|","&");
ReplaceString(name, DEFAULT_LEN,"0x42","0x21");
}
}
public void ClientID(int client, char[] buf, int buflen){
if(IsClientConnected(client)){
GetClientAuthId(client, AuthId_SteamID64, buf, DEFAULT_LEN, true);
}
}
public void ActiveClients(char[] prefix, char[] buf, buflen){
new String:str_tmp[ACTIVE_CLIENTS_LENGTH];
for(new i = 1; i <= MaxClients;i++){
new String:strCliID[DEFAULT_LEN];
new String:strCliName[DEFAULT_LEN];
ClientID(i, strCliID, DEFAULT_LEN);
ClientName(i, strCliName, DEFAULT_LEN);
Format(str_tmp, ACTIVE_CLIENTS_LENGTH,
"%s|%s|%s|%d,", str_tmp, strCliID, strCliName, GetClientTeam(i));
}
Format(str_tmp, ACTIVE_CLIENTS_LENGTH, "%s%s", prefix,str_tmp);
}
public void LogActiveClients(Handle:logfile, char[] prefix){
char strActiveClients[ACTIVE_CLIENTS_LENGTH];
ActiveClients(prefix, strActiveClients, ACTIVE_CLIENTS_LENGTH);
LogToOpenFile(logfile, strActiveClients);
}
public void LogClientEventFormat(Handle:logfile, Handle:event, char[] prefix){
char strClientEvent[2*DEFAULT_LEN];
ClientEventFormat(event, prefix, strClientEvent, 2*DEFAULT_LEN);
LogToOpenFile(logfile, strClientEvent);
}
public void ClientEventFormat(Handle:event, char[] prefix, char[] buf, buflen){
new client = GetClientOfUserId(GetEventInt(event, "userid"));
char team[4];
Format(team, sizeof(team), "%d", GetClientTeam(client));
char tmp[DEFAULT_LEN*2];
char strCliID[DEFAULT_LEN];
ClientID(client, strCliID, DEFAULT_LEN);
Format(tmp, 2*DEFAULT_LEN, "%s%s,%s", prefix, strCliID, team);
}

View File

@@ -1,487 +0,0 @@
// socket extension include file
#if defined _socket_included
#endinput
#endif
#define _socket_included
#include <core>
enum SocketType {
SOCKET_TCP = 1,
SOCKET_UDP,
SOCKET_RAW
}
#define EMPTY_HOST 1
#define NO_HOST 2
#define CONNECT_ERROR 3
#define SEND_ERROR 4
#define BIND_ERROR 5
#define RECV_ERROR 6
#define LISTEN_ERROR 7
/*************************************************************************************************/
/******************************************** options ********************************************/
/*************************************************************************************************/
/**
* Options available for SocketSetOption()
*
* @note modifying these options is not required for normal operation, you can skip the whole
* section in most cases.
*/
enum SocketOption {
/**
* If this option is set the socket extension will try to concatenate SocketReceive callbacks.
*
* This will possibly lower the amount of callbacks passed to SourceMod plugins and improve the
* performance. The socket extension will preserve the packet order.
*
* @note this doesn't prevent multiple callbacks, it only reduces them for high load.
* @note this will not truncate packets below 4096 bytes, setting it lower will be ignored
* @note set this option if you expect lots of data in a short timeframe
* @note don't forget to set your buffer sizes at least to the value passed to this function, but
* always at least to 4096
*
* @param cell_t 0(=default) to disable or max. chunk size including \0 terminator in bytes
* @return bool true on success
*/
ConcatenateCallbacks = 1,
/**
* If this option is set the socket extension will enforce a mutex lock in the GameFrame() hook.
*
* This will ensure that callbacks will be processed every gameframe as fast as possible with the
* drawback of potentially creating lag. It's not recommended to set this option for most cases.
* If this option is not set the gameframe will be skipped if quietly obtaining a lock fails.
*
* @note combine this with CallbacksPerFrame for best performance
* @note this option will affect all sockets from all plugins, use it with caution!
*
* @param bool whether to force locking or not
* @return bool true on success
*/
ForceFrameLock,
/**
* This will specify the maximum amount of callbacks processed in every gameframe.
*
* The default value for this option is 1, setting it higher will possibly increase networking
* performance but may cause lag if it's set too high.
* The amount of callbacks actually being processed is limited by not being able to quietly obtain
* a lock (see ForceFrameLock) and the amount of callbacks in the queue.
*
* @note this option will affect all sockets from all plugins, use it with caution!
*
* @param cell_t maximum amount of callbacks per gameframe
* @return bool true on success
*/
CallbacksPerFrame,
/**
* If this option is set the socket will be allowed to send broadcast messages in case the protocol
* supports it. This is a wrapper for setting SO_BROADCAST.
*
* @param bool whether to allow broadcasting or not
* @return bool true on success
*/
SocketBroadcast,
/**
* If this option is set SocketBind() will allow reusing local adresses in case the protocol
* supports it. This is a wrapper for setting SO_REUSEADDR.
*
* @param bool whether to allow broadcasting or not
* @return bool true on success
*/
SocketReuseAddr,
/**
* If this option is set the socket will try to keep the connection alive by periodically sending
* messages if the protocol supports it. This is a wrapper for setting SO_KEEPALIVE.
*
* @param bool whether to allow broadcasting or not
* @return bool true on success
*/
SocketKeepAlive,
/**
* This option specifies how long a socket will wait if it's being closed and its send buffer is
* still filled. This is a wrapper for setting SO_LINGER.
*
* @param cell_t 0 (=default) to disable or time in s
* @return bool true on success
*/
SocketLinger,
/**
* If this option is set out-of-band data will be inlined into the normal receive stream. This is a
* wrapper for setting SO_OOBINLINE.
*
* @param bool whether to inline out-of-band data or not
* @return bool true on success
*/
SocketOOBInline,
/**
* This option specifies how large the send buffer will be. This is a wrapper for setting
* SO_SNDBUF.
*
* @param cell_t size in bytes
* @return bool true on success
*/
SocketSendBuffer,
/**
* This option specifies how large the receive buffer will be. This is a wrapper for setting
* SO_RCVBUF.
*
* @param cell_t size in bytes
* @return bool true on success
*/
SocketReceiveBuffer,
/**
* If this option is set outgoing messages will ignore the default routing facilities if the
* protocol implementation supports it. The remote site should be directly connected to the sender.
* This is a wrapper for setting SO_DONTROUTE.
*
* @param bool whether to skip default routing or not
* @return bool true on success
*/
SocketDontRoute,
/**
* This option specifies the minimum amount of data to receive before processing it. This is a
* wrapper for setting SO_RCVLOWAT.
*
* @note this can probably block the extension, use it with caution!
*
* @param cell_t size in bytes
* @return bool true on success
*/
SocketReceiveLowWatermark,
/**
* This option specifies how long a socket will try to receive data before it times out and
* processes the data. This is a wrapper for setting SO_RCVTIMEO.
*
* @param cell_t 0 (=default) to disable or time in ms
* @return bool true on success
*/
SocketReceiveTimeout,
/**
* This option specifies the minimum amount of data required in the send buffer before starting to
* send it. This is a wrapper for setting SO_SNDLOWAT.
*
* @note this can probably block the extension, use it with caution!
*
* @param cell_t size in bytes
* @return bool true on success
*/
SocketSendLowWatermark,
/**
* This option specifies how long a socket will try to send data before it times out and
* retries it later. This is a wrapper for setting SO_SNDTIMEO.
*
* @param cell_t 0 (=default) to disable or time in ms
* @return bool true on success
*/
SocketSendTimeout,
/**
* If this option is set the socket extension will display debugging messages in the server console/logs.
*
* @param bool whether to enable debugging or not
* @return bool true on success
*/
DebugMode
}
/*************************************************************************************************/
/******************************************* callbacks *******************************************/
/*************************************************************************************************/
/**
* triggered if a normal sockets finished connecting and is ready to be used
*
* @param socket The socket handle pointing to the calling socket
* @param arg The argument set by SocketSetArg()
* @noreturn
*/
//funcenum SocketConnectCB
//{
// public(Handle:socket, any:arg)
//};
typeset SocketConnectCB
{
function void (Handle socket, any arg);
};
/**
* triggered if a listening socket received an incoming connection and is ready to be used
*
* @note The child-socket won't work until receive-, disconnect-, and errorcallback for it are set.
*
* @param Handle socket The socket handle pointing to the calling listen-socket
* @param Handle newSocket The socket handle to the newly spawned child socket
* @param String remoteIP The remote IP
* @param any arg The argument set by SocketSetArg() for the listen-socket
* @noreturn
*/
typeset SocketIncomingCB
{
function void (Handle socket, Handle newSocket, const char remoteIP[], int remotePort, any arg)
};
/**
* triggered if a socket receives data
*
* @note This is binary safe if you always use dataSize for operations on receiveData[]
* @note packets may be split up into multiple chunks -> multiple calls to the receive callback
* @note if not set otherwise by SocketSetOption(..., ConcatenateCallbacks, ...) receiveData will
* never be longer than 4096 characters including \0 terminator
*
* @param Handle socket The socket handle pointing to the calling socket
* @param String receiveData The data which arrived, 0-terminated at receiveData[dataSize]
* @param cell_t dataSize The length of the arrived data excluding the 0-termination
* @param any arg The argument set by SocketSetArg() for the socket
* @noreturn
*/
typeset SocketReceiveCB
{
function void (Handle socket, const char receiveData[], const int dataSize, any arg)
};
/**
* called after a socket sent all items in its send queue successfully
*
* @param Handle socket The socket handle pointing to the calling socket
* @param any arg The argument set by SocketSetArg() for the socket
* @noreturn
*/
typeset SocketSendqueueEmptyCB
{
function void (Handle socket, any arg)
};
/**
* called if a socket has been properly disconnected by the remote side
*
* @note You should call CloseHandle(socket) or reuse the socket before this function ends
*
* @param Handle socket The socket handle pointing to the calling socket
* @param any arg The argument set by SocketSetArg() for the socket
* @noreturn
*/
typeset SocketDisconnectCB
{
function void (Handle socket, any arg)
};
/**
* called if an unrecoverable error occured, close the socket without an additional call to a disconnect callback
*
* @note You should call CloseHandle(socket) or reuse the socket before this function ends
*
* @param Handle socket The socket handle pointing to the calling socket
* @param cell_t errorType The error type, see defines above
* @param cell_t errorNum The errno, see errno.h for details
* @param any arg The argument set by SocketSetArg() for the socket
* @noreturn
*/
typeset SocketErrorCB
{
function void (Handle socket, const int errorType, const int errorNum, any arg)
};
/*************************************************************************************************/
/******************************************** natives ********************************************/
/*************************************************************************************************/
/**
* Returns whether a socket is connected or not.
*
* @param socket Socket handle to check
* @return bool The connection status
*/
native bool:SocketIsConnected(Handle:socket);
/**
* Creates a new socket.
*
* @note this function may be relatively expensive, reuse sockets if possible
*
* @param SocketType protocol The protocol to use, SOCKET_TCP is default
* @param SocketErrorCB efunc The error callback
* @return Handle The socket handle. Returns INVALID_HANDLE on failure
*/
native Handle:SocketCreate(SocketType:protocol=SOCKET_TCP, SocketErrorCB:efunc);
/**
* Binds the socket to a local address
*
* @param Handle socket The handle of the socket to be used.
* @param String hostname The hostname (or IP) to bind the socket to.
* @param cell_t port The port to bind the socket to.
* @return bool true on success
*/
native bool:SocketBind(Handle:socket, const String:hostname[], port);
/**
* Connects a socket
*
* @note this native is threaded, it may be still running after it executed, use the connect callback
* @note invokes the SocketError callback with errorType = CONNECT_ERROR or EMPTY_HOST if it fails
* @note invokes the SocketConnect callback if it succeeds
*
* @param Handle socket The handle of the socket to be used.
* @param SocketConnectCB cfunc The connect callback
* @param SocketReceiveCB rfunc The receive callback
* @param SocketDisconnectCB dfunc The disconnect callback
* @param String hostname The hostname (or IP) to connect to.
* @param cell_t port The port to connect to.
* @noreturn
*/
native SocketConnect(Handle:socket, SocketConnectCB:cfunc, SocketReceiveCB:rfunc, SocketDisconnectCB:dfunc, const String:hostname[], port);
/**
* Disconnects a socket
*
* @note this will not close the handle, the socket will be reset to a state similar to after SocketCreate()
* @note this won't trigger any disconnect/error callbacks
*
* @noreturn
*/
native bool:SocketDisconnect(Handle:socket);
/**
* Makes a socket listen for incoming connections
*
* @param Handle socket The handle of the socket to be used.
* @param SocketIncomingCB ifunc The callback for incoming connections
* @return bool true on success
*/
native bool:SocketListen(Handle:socket, SocketIncomingCB:ifunc);
/**
* Sends data through the socket.
*
* @note specify size for binary safe operation
* @note if size is not specified the \0 terminator will not be included
* @note This native is threaded, it may be still running after it executed (not atomic).
* @note Use the SendqueueEmpty callback to determine when all data has been successfully sent.
* @note The socket extension will ensure that the data will be send in the correct order and split
* the data if required.
*
* @param Handle socket The handle of the socket to be used.
* @param String data The data to send.
* @noreturn
*/
native SocketSend(Handle:socket, const String:data[], size=-1);
/**
* Sends UDP data through the socket to a specific destination.
*
* @note specify size for binary safe operation
* @note if size is not specified the \0 terminator will not be included
* @note This native is threaded, it may be still running after it executed (not atomic).
* @note Use the SendqueueEmpty callback to determine when all data has been successfully sent.
* @note The socket extension will ensure that the data will be send in the correct order and split
* the data if required.
*
* @param Handle socket The handle of the socket to be used.
* @param String data The data to send.
* @param String hostname The hostname (or IP) to send to.
* @param cell_t port The port to send to.
* @noreturn
*/
native SocketSendTo(Handle:socket, const String:data[], size=-1, const String:hostname[], port);
/**
* Set a socket option.
*
* @param Handle socket The handle of the socket to be used. May be INVALID_HANDLE if not essential.
* @param SocketOption option The option to modify (see enum SocketOption for details).
* @param cellt_ value The value to set the option to.
* @return cell_t 1 on success.
*/
native SocketSetOption(Handle:socket, SocketOption:option, value);
/**
* Defines the callback function for when the socket receives data
*
* @note this is only useful and required for child-sockets spawned by listen-sockets
* (otherwise you already set it in SocketConnect())
*
* @param Handle socket The handle of the socket to be used.
* @param SocketReceiveCB rfunc The receive callback
* @noreturn
*/
native SocketSetReceiveCallback(Handle:socket, SocketReceiveCB:rfunc);
/**
* Defines the callback function for when the socket sent all items in its send queue
*
* @note this must be called AFTER sending (queueing) the data
* @note if no send-data is queued this will fire the callback itself
* @note the callback is guaranteed to fire
*
* @param Handle socket The handle of the socket to be used.
* @param SocketDisconnectCB dfunc The disconnect callback
* @noreturn
*/
native SocketSetSendqueueEmptyCallback(Handle:socket, SocketSendqueueEmptyCB:sfunc);
/**
* Defines the callback function for when the socket was properly disconnected by the remote side
*
* @note this is only useful and required for child-sockets spawned by listen-sockets
* (otherwise you already set it in SocketConnect())
*
* @param Handle socket The handle of the socket to be used.
* @param SocketDisconnectCB dfunc The disconnect callback
* @noreturn
*/
native SocketSetDisconnectCallback(Handle:socket, SocketDisconnectCB:dfunc);
/**
* Defines the callback function for when the socket triggered an error
*
* @note this is only useful and required for child-sockets spawned by listen-sockets
* (otherwise you already set it in SocketCreate())
*
* @param Handle socket The handle of the socket to be used.
* @param SocketErrorCB efunc The error callback
* @noreturn
*/
native SocketSetErrorCallback(Handle:socket, SocketErrorCB:efunc);
/**
* Sets the argument being passed to callbacks
*
* @param Handle socket The handle of the socket to be used.
* @param any arg The argument to set
* @noreturn
*/
native SocketSetArg(Handle:socket, any:arg);
/**
* Retrieve the local system's hostname as the command "hostname" does.
*
* @param dest Destination string buffer to copy to.
* @param destLen Destination buffer length (includes null terminator).
*
* @return 1 on success
*/
native SocketGetHostName(String:dest[], destLen);
/**
* _________________Do not edit below this line!_______________________
*/
public Extension:__ext_smsock =
{
name = "Socket",
file = "socket.ext",
#if defined AUTOLOAD_EXTENSIONS
autoload = 1,
#else
autoload = 0,
#endif

View File

@@ -1,101 +0,0 @@
/* no idea, but removes warnings */
#pragma tabsize 0
#include <sourcemod>
#include <sdktools>
#include <socket>
#define DEFAULT_LEN 64
#define TAG_LEN 64
#define INDEX_SEP ","
#define ACTIVE_CLIENTS_LENGTH 8192
#define NO_PREFIX ""
/* ---------------------- Globals ---------------------- */
static Handle:socket
/* ---------------------- Queries ---------------------- */
public QueryTeam(Handle:socketl, char[] steamid, bool rebuild){
/* steamid may be used to only query a single player's new team */
char strActiveClients[ACTIVE_CLIENTS_LENGTH];
char request[ACTIVE_CLIENTS_LENGTH + DEFAULT_LEN*2];
ActiveClients(NO_PREFIX, strActiveClients, ACTIVE_CLIENTS_LENGTH);
if(rebuild){
Format(request, sizeof(request), "rebuildteam,%s", strActiveClients);
}else{
Format(request, sizeof(request), "getteam,%s,%s", steamid, strActiveClients);
}
SocketSend(socket, request);
}
public QueryRating(client){
if(client>0 && IsClientConnected(client)){
/* get steamid first */
char pid[DEFAULT_LEN];
GetClientAuthId(client, AuthId_SteamID64, pid, DEFAULT_LEN, true);
/* build the request and send */
char request[2*DEFAULT_LEN];
Format(request, sizeof(request), "player,%s", pid);
SocketSend(socket, request);
}
}
/* ---------------------- Receive ---------------------- */
public CaseSwitchReceive(Handle:socketl, String:receiveData[], const dataSize, any:arg) {
char tag[TAG_LEN];
//TODO why is receiveData and array of strings?!?!
SplitString(receiveData, INDEX_SEP, tag, TAG_LEN);
if(StrEqual(tag, "BALANCE_SINGLE")){
RebuildTeams(INDEX_SEP, "|",receiveData);
}else if(StrEqual(tag, "BALANCE_TEAMS")){
RebuildTeams(INDEX_SEP, "|",receiveData);
}else if(StrEqual(tag, "RATING_SINGLE")){
char ratingInfo[DEFAULT_LEN];
SplitString(receiveData, INDEX_SEP, ratingInfo, DEFAULT_LEN);
PrintToChatAll("%s", receiveData);
}
}
/* ---------------------- Socket ---------------------- */
public CreateQuerySocket(int port){
socket = SocketCreate(SOCKET_TCP, OnSocketError);
SocketConnect(socket, OnSocketConnected, CaseSwitchReceive, OnSocketDisconnected, "127.0.0.1", port);
}
public Action AttemptReconnectSocket(Handle:socketl){
if(socket != INVALID_HANDLE){
CloseHandle(socketl);
}else{
socket = SocketCreate(SOCKET_TCP,OnSocketError);
if(socket != INVALID_HANDLE){
SocketConnect(socket, OnSocketConnected, CaseSwitchReceive,
OnSocketDisconnected, "127.0.0.1", 7040);
}
}
/* check if socket is connected */
if(SocketIsConnected(socketl)){
return Plugin_Stop;
}else{
return Plugin_Continue;
}
}
public Handle GetSocket(){
return socket;
}
public OnSocketConnected(Handle:socketl,any:arg) {
}
public OnSocketDisconnected(Handle:socketl,any:arg) {
CreateTimer(10.0, AttemptReconnectSocket, socketl, TIMER_REPEAT);
}
public OnSocketError(Handle:socketl, const errorType, const errorNum,any:arg) {
LogError("socket error %d (errno %d)", errorType, errorNum);
CloseHandle(socket);
}

View File

@@ -1,58 +0,0 @@
#define DEFAULT_LEN 64
#define MAX_PLAYERS 32
#define MAX_LENGTH_ID_TEAM 128
public void EventWinnerTeam(Handle:event, char[] prefix, char[] buf, int buflen){
new team_id = GetEventInt(event, "winner");
Format(buf, buflen, "%s,%d", prefix, team_id);
}
public void MapName(char[] prefix, char[] buf, int buflen){
new String:map[DEFAULT_LEN];
GetCurrentMap(map, sizeof(map));
Format(buf, buflen, "%s%s", prefix, map);
}
public void ServerName(char[] buf,int buflen){
new String:sname[SNAME_LEN];
ConVar servername = FindConVar("hostname");
servername.GetString(sname,SNAME_LEN);
ReplaceString(sname, SNAME_LEN," ","");
ReplaceString(sname, SNAME_LEN,"[","");
ReplaceString(sname, SNAME_LEN,"]","");
ReplaceString(sname, SNAME_LEN,"(","");
ReplaceString(sname, SNAME_LEN,")","");
}
public void RebuildTeams(char[] SEP, char[] SUBSEP, char[] input){
/* buffers for later */
char buffers[MAX_PLAYERS][MAX_LENGTH_ID_TEAM];
new parts = ExplodeString(input, SEP, buffers, MAX_PLAYERS, MAX_LENGTH_ID_TEAM);
new StringMap:map;
/* i=1 to skip tag in something like TAG,player|team,player|team,... */
for(new i = 1; i < parts; i++){
char idAndTeam[2][MAX_LENGTH_ID_TEAM];
ExplodeString(buffers[i], SUBSEP, idAndTeam, 2, MAX_LENGTH_ID_TEAM);
map.SetString(idAndTeam[0], idAndTeam[1], true);
}
/* hasmap indirection nessesary cause there doesnt exist a "ClientByAuthID-like function */
for(new client=0; client <MaxClients; client++){
/* get Steam-Id to match */
char sid[DEFAULT_LEN];
if(client>0 && IsClientConnected(client)){
GetClientAuthId(client, AuthId_SteamID64, sid, DEFAULT_LEN, true);
}
/* get team for steamid and balance*/
char team[MAX_LENGTH_ID_TEAM];
if(map.GetString(sid, team, sizeof(team))){
new tid = StringToInt(team);
if(tid>0 && IsClientConnected(client)){
ChangeClientTeam(client, tid);
}
}
}
}