Raised This Month: $51 Target: $400
 12% 

TF2 Stats - Beginning questions


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
Kahl_Drogo
Senior Member
Join Date: Apr 2012
Old 01-20-2019 , 07:46   TF2 Stats - Beginning questions
Reply With Quote #1

Hi,

I started working on my own tf2 stats plugin. Here i will be put my questions regarding coding problems.


So lets start ;)

I have this sample code:

PHP Code:
enum struct PlayerData {
    
char steamId[32];
    
char name[256];
}

PlayerData playersData[MAXPLAYERS+1]; 
I trying fill this enum with data in this part:

PHP Code:
public void OnClientAuthorized(int client)
{
char clientSteamId[32];
    
char clientName[256];
    
char query[256];
    
decl String:error[256];
    
DBResultSet player;
    
    
GetClientAuthId(clientAuthId_Steam2clientSteamIdsizeof(clientSteamId));
    
GetClientName(clientclientNamesizeof(clientName));
    
strcopy(playersData[client].steamIdsizeof(playersData[client].steamId), clientSteamId); 
    
strcopy(playersData[client].namesizeof(playersData[client].name), clientName); 

But compiler return :
PHP Code:
error 001expected token"]"but found "-identifier-" 
In line :
PHP Code:
strcopy(playersData[client].steamIdsizeof(playersData[client].steamId), clientSteamId); 
What i do wrong ?
__________________

Last edited by Kahl_Drogo; 01-20-2019 at 07:50.
Kahl_Drogo is offline
Whai
Senior Member
Join Date: Jul 2018
Old 01-20-2019 , 15:05   Re: TF2 Stats - Beginning questions
Reply With Quote #2

Quote:
Originally Posted by Kahl_Drogo View Post
Hi,

I started working on my own tf2 stats plugin. Here i will be put my questions regarding coding problems.


So lets start ;)

I have this sample code:

PHP Code:
enum struct PlayerData {
    
char steamId[32];
    
char name[256];
}

PlayerData playersData[MAXPLAYERS+1]; 
I trying fill this enum with data in this part:

PHP Code:
public void OnClientAuthorized(int client)
{
char clientSteamId[32];
    
char clientName[256];
    
char query[256];
    
decl String:error[256];
    
DBResultSet player;
    
    
GetClientAuthId(clientAuthId_Steam2clientSteamIdsizeof(clientSteamId));
    
GetClientName(clientclientNamesizeof(clientName));
    
strcopy(playersData[client].steamIdsizeof(playersData[client].steamId), clientSteamId); 
    
strcopy(playersData[client].namesizeof(playersData[client].name), clientName); 

But compiler return :
PHP Code:
error 001expected token"]"but found "-identifier-" 
In line :
PHP Code:
strcopy(playersData[client].steamIdsizeof(playersData[client].steamId), clientSteamId); 
What i do wrong ?
I think it should be this :

PHP Code:
strcopy(playersData[client].steamIdsizeof(playersData[].steamId), clientSteamId); 
we just wanted the size of the array, so no need to to the client index

[EDIT]

This line to :
PHP Code:
strcopy(playersData[client].namesizeof(playersData[client].name), clientName); 
should be :

PHP Code:
strcopy(playersData[client].namesizeof(playersData[].name), clientName); 
__________________

Last edited by Whai; 01-20-2019 at 15:07.
Whai is offline
Kahl_Drogo
Senior Member
Join Date: Apr 2012
Old 01-23-2019 , 14:26   Re: TF2 Stats - Beginning questions
Reply With Quote #3

Thx Whai this is what i needed ;)

Ok so I think i reached my first step.

There I my assumptions:
  • Sample statisticks that insert to DB player kills, deaths and suicides

To achieve it my plugin create 3 tables:
  • servers structure: |id|ip|port|created_at|updated_at|
  • players structure: |id|steam_id|name|created_at|updated_at|
  • players_stats structure: |id|player_id|server_id|kills|deaths|suicides |created_at|updated_at|

Here is full code:
PHP Code:

#define DEBUG

#define PLUGIN_NAME           "TF2 Pro Stats"
#define PLUGIN_AUTHOR         "Szkalownik"
#define PLUGIN_DESCRIPTION    ""
#define PLUGIN_VERSION        "1.0"
#define PLUGIN_URL            ""

#pragma semicolon 1

#include <sourcemod>
#include <sdktools>
#include <SteamWorks>

char dbconfig[] = "tf2_pro_stats";
Database databaseHandler;

enum struct PlayerData {
    
int id[11];
    
char steamId[32];
    
char name[256];
}

PlayerData playersData[MAXPLAYERS+1];

enum struct ServerData {
    
int id[11];
    
char ip[64];
    
char port[16];
}

ServerData serverData;

public 
Plugin:myinfo =
{
    
name PLUGIN_NAME,
    
author PLUGIN_AUTHOR,
    
description PLUGIN_DESCRIPTION,
    
version PLUGIN_VERSION,
    
url PLUGIN_URL
};

public 
OnPluginStart()
{
    
connectToDatabase();
    
createDatabaseTables();
    
setServer();
    
HookEvents();
}

public 
void connectToDatabase()
{
    if(!
SQL_CheckConfig(dbconfig)) {
        
LogError("Could not find %s database configuration."dbconfig);
        return;
    }
    
    
decl String:error[256];
    
databaseHandler SQL_Connect(dbconfigtrueerrorsizeof(error));
    if (
databaseHandler == INVALID_HANDLE) {
        
LogError("Could not connect to database. Error: %s"error);
    }
}

public 
void createDatabaseTables()
{
    if(
databaseHandler == INVALID_HANDLE) {
        return;
    }
    
    
char queries[3][] = 
    {
        
"CREATE TABLE IF NOT EXISTS `servers` (`id` int(11) NOT NULL AUTO_INCREMENT, `ip` int(11) NOT NULL, `port` int(11) NOT NULL, `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=latin1",
        
"CREATE TABLE IF NOT EXISTS `players` (`id` int(11) NOT NULL AUTO_INCREMENT, `steam_id` varchar(255) NOT NULL, `name` varchar(255) NOT NULL, `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=latin1",
        
"CREATE TABLE IF NOT EXISTS `players_stats` (`id` int(11) NOT NULL AUTO_INCREMENT,`player_id` int(11) NOT NULL,`server_id` int(11) NOT NULL,`kills` int(11) NOT NULL DEFAULT '0',`deaths` int(11) NOT NULL DEFAULT '0',`suicides` int(11) NOT NULL DEFAULT '0',`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=latin1;"
    
};
    
    
decl String:error[256];
    for (
int i 03i++) {
        if (!
SQL_FastQuery(databaseHandlerqueries[i])) {
            
SQL_GetError(databaseHandlererrorsizeof(error));
            
LogError("Database query: %s error: %s",queries[i], error);
        }
    }
}

public 
void setServer()
{
    
decl String:query[1500];
    
char serverIp[64];
    
char serverPort[10];
    
int ipaddr[4];
    
    
SteamWorks_GetPublicIP(ipaddr);
    
Format(serverIpsizeof(serverIp), "%d.%d.%d.%d",ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]);
    
strcopy(serverData.ipsizeof(serverData.ip), serverIp); 
    
    
GetConVarString(FindConVar("hostport"), serverPortsizeof(serverPort));
    
strcopy(serverData.portsizeof(serverData.port), serverPort); 

    
Format(querysizeof(query), "SELECT id FROM servers WHERE ip = '%s' AND port='%s' LIMIT 1;"serverIpserverPort);
    
SQL_TQuery(databaseHandlerSQLServerCallbackquery);
}

public 
void SQLServerCallback(Handle ownerHandle hndl, const char[] errorany data)
{
    if (!
StrEqual(""error)) {
        
LogMessage("SQL Error: %s"error);
        return;
    }
    
    if(
SQL_FetchRow(hndl)) {
        
serverData.id SQL_FetchInt(hndl0);
        return;
    }
    
    
decl String:query[1500];
    
Format(querysizeof(query), "INSERT INTO servers (ip, port) VALUES ( '%s', '%s');"serverData.ipserverData.port);
    
SQL_TQuery(databaseHandlerSQLAddServerCallbackquery);
}

public 
void SQLAddServerCallback(Handle ownerHandle hndl, const char[] errorany data)
{
    if (!
StrEqual(""error)) {
        
LogMessage("SQL Error: %s"error);
        return;
    }
    
    
serverData.id SQL_GetInsertId(owner);
}

public 
void OnClientAuthorized(int client)
{
    if(
databaseHandler == INVALID_HANDLE) {
        return;
    }

    
char clientSteamId[32];
    
char clientName[256];
    
decl String:query[1500];
    
    
GetClientAuthId(clientAuthId_Steam2clientSteamIdsizeof(clientSteamId));
    
GetClientName(clientclientNamesizeof(clientName));
    
strcopy(playersData[client].steamIdsizeof(playersData[].steamId), clientSteamId); 
    
strcopy(playersData[client].namesizeof(playersData[].name), clientName); 
    if(
StrEqual(clientSteamId"BOT"true)) {
        
Format(querysizeof(query), "SELECT id,name FROM players WHERE steam_id = '%s' and name='%s' LIMIT 1;"clientSteamIdclientName);
    }else{
        
Format(querysizeof(query), "SELECT id,name FROM players WHERE steam_id = '%s' LIMIT 1;"clientSteamId);
    }
    
SQL_TQuery(databaseHandlerSQLPlayerCallbackqueryGetClientSerial(client));
}

public 
void SQLPlayerCallback(Handle ownerHandle hndl, const char[] errorany data)
{
    
int client GetClientFromSerial(data);
    
    if (
client == 0) {
        return;
    }
    
    
decl String:query[1500];
    
char clientName[256];
    if (!
StrEqual(""error)) {
        
LogMessage("SQL Error: %s"error);
        return;
    }

    if(
SQL_FetchRow(hndl)) {
        
playersData[client].id SQL_FetchInt(hndl,0);
        
SQL_FetchString(hndl,1,clientName,256);
        
        if(!
StrEqual(playersData[client].nameclientNametrue)) {
            
Format(querysizeof(query), "UPDATE players SET name='%s' WHERE id=%d);"playersData[client].nameplayersData[client].id);
            
SQL_TQuery(databaseHandlerSQLUpdateCallbackquery);
        }
        
        return;
    }
    
    
Format(querysizeof(query), "INSERT INTO players (steam_id, name) VALUES ( '%s', '%s');"playersData[client].steamIdplayersData[client].name);
    
SQL_TQuery(databaseHandlerSQLAddPlayerCallbackquerydata);
 }
 
 public 
void SQLAddPlayerCallback(Handle ownerHandle hndl, const char[] errorany data)
 {
     
int client GetClientFromSerial(data);
     
     if (
client == 0) {
        return;
    }
    
     if (!
StrEqual(""error)) {
        
LogMessage("SQL Error: %s"error);
        return;
    }
    
    
playersData[client].id SQL_GetInsertId(owner);
 }

public 
void HookEvents()
{
    
HookEvent("player_death"Event_PlayerDeath);
}

public 
Event_PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast)
{
    if(
databaseHandler == INVALID_HANDLE) {
        return;
    }
    
    new 
attackerId GetClientOfUserId(GetEventInt(event"attacker"));
    new 
victimId GetClientOfUserId(GetEventInt(event"userid"));
    
    if(
attackerId == || victimId == 0) {
        return;
    }
    
    if(
victimId == attackerId) {
        
addPlayerStat(attackerId"suicide");
        return;
    }
    
    
addPlayerStat(attackerId"kill");
    
addPlayerStat(victimId"death");
}

public 
void addPlayerStat(int clientString:type[])
{
    
decl String:query[1500];
    
Format(querysizeof(query), "SELECT player_id, server_id, kills, deaths, suicides FROM players_stats WHERE player_id = %d AND server_id=%d LIMIT 1;"playersData[client].idserverData.id);
    
    if(
StrEqual(type"suicide")){
        
SQL_TQuery(databaseHandlerSQLAddPlayerSuicideCallbackqueryGetClientSerial(client));
        return;
    }
    
    if(
StrEqual(type"kill")){
        
SQL_TQuery(databaseHandlerSQLAddPlayerKillCallbackqueryGetClientSerial(client));
        return;
    }
    
    if(
StrEqual(type"death")){
        
SQL_TQuery(databaseHandlerSQLAddPlayerDeathCallbackqueryGetClientSerial(client));
        return;
    }
}

public 
void SQLAddPlayerSuicideCallback(Handle ownerHandle hndl, const char[] errorany data)
{
    
int client GetClientFromSerial(data);
    
    if (
client == 0) {
        return;
    }
    
     
decl String:query[1500];
     
     if (!
StrEqual(""error)) {
        
LogMessage("SQL Error: %s"error);
        return;
    }
    
    if(
SQL_FetchRow(hndl)) {
        
Format(querysizeof(query), "UPDATE players_stats SET suicides = suicides+1 WHERE player_id=%d AND server_id=%d;"SQL_FetchInt(hndl,0), SQL_FetchInt(hndl,1));
        
SQL_TQuery(databaseHandlerSQLUpdateCallbackquery);
        return;
    }
    
    
Format(querysizeof(query), "INSERT INTO players_stats (player_id, server_id, kills, deaths, suicides) VALUES (%d, %d, %d, %d, %d);"playersData[client].idserverData.id001);
    
SQL_TQuery(databaseHandlerSQLInsertCallbackquery);
}

public 
void SQLAddPlayerKillCallback(Handle ownerHandle hndl, const char[] errorany data)
{
    
int client GetClientFromSerial(data);
    
    if (
client == 0) {
        return;
    }
    
     
decl String:query[1500];
     
     if (!
StrEqual(""error)) {
        
LogMessage("SQL Error: %s"error);
        return;
    }
    
    if(
SQL_FetchRow(hndl)) {
        
Format(querysizeof(query), "UPDATE players_stats SET kills = kills+1 WHERE player_id=%d AND server_id=%d;"SQL_FetchInt(hndl,0), SQL_FetchInt(hndl,1));
        
SQL_TQuery(databaseHandlerSQLUpdateCallbackquery);
        return;
    }
    
    
Format(querysizeof(query), "INSERT INTO players_stats (player_id, server_id, kills, deaths, suicides) VALUES (%d, %d, %d, %d, %d);"playersData[client].idserverData.id100);
    
SQL_TQuery(databaseHandlerSQLInsertCallbackquery);
}

public 
void SQLAddPlayerDeathCallback(Handle ownerHandle hndl, const char[] errorany data)
{
    
int client GetClientFromSerial(data);
    
    if (
client == 0) {
        return;
    }
    
     
decl String:query[1500];
     
     if (!
StrEqual(""error)) {
        
LogMessage("SQL Error: %s"error);
        return;
    }
    
    if(
SQL_FetchRow(hndl)) {
        
Format(querysizeof(query), "UPDATE players_stats SET deaths = deaths+1 WHERE player_id=%d AND server_id=%d;"SQL_FetchInt(hndl,0), SQL_FetchInt(hndl,1));
        
SQL_TQuery(databaseHandlerSQLUpdateCallbackquery);
        return;
    }
    
    
Format(querysizeof(query), "INSERT INTO players_stats (player_id, server_id, kills, deaths, suicides) VALUES (%d, %d, %d, %d, %d);"playersData[client].idserverData.id100);
    
SQL_TQuery(databaseHandlerSQLInsertCallbackquery);
}

public 
void SQLUpdateCallback(Handle ownerHandle hndl, const char[] errorany data)
 {
     if (!
StrEqual(""error)) {
        
LogMessage("SQL Error: %s"error);
        return;
    }
 }
 
 public 
void SQLInsertCallback(Handle ownerHandle hndl, const char[] errorany data)
 {
     if (!
StrEqual(""error)) {
        
LogMessage("SQL Error: %s"error);
        return;
    }
 } 
Can you give me guys some feedback what else should be checked , some bugs etc.

Thi is my first steps in source and i wanna get good practice acknowledge of writing plugins from start
__________________
Kahl_Drogo is offline
sdz
Senior Member
Join Date: Feb 2012
Old 01-24-2019 , 07:03   Re: TF2 Stats - Beginning questions
Reply With Quote #4

Use threaded sql operations or else your server is gonna freeze a lot - https://wiki.alliedmods.net/SQL_(Sou...ing)#Threading

Last edited by sdz; 01-24-2019 at 07:04.
sdz is offline
Kahl_Drogo
Senior Member
Join Date: Apr 2012
Old 02-03-2019 , 09:53   Re: TF2 Stats - Beginning questions
Reply With Quote #5

Quote:
Originally Posted by sidezz View Post
Use threaded sql operations or else your server is gonna freeze a lot - https://wiki.alliedmods.net/SQL_(Sou...ing)#Threading
I using. I used only SQL_Connect to connect to database and run first create tables.
Other queries are in TQuery.
I thinked to use SQL_TConnect but I readed that threads are run only when someon is on server https://forums.alliedmods.net/showpo...0&postcount=16 .

I am wrong ?
__________________

Last edited by Kahl_Drogo; 02-04-2019 at 07:15.
Kahl_Drogo is offline
CliptonHeist
Senior Member
Join Date: Feb 2016
Old 02-03-2019 , 19:01   Re: TF2 Stats - Beginning questions
Reply With Quote #6

They won't run if your server is set to hibernate when empty. When the server is hibernating it doesn't tick and no operations such as database connections or timers will run.
CliptonHeist is offline
Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 00:21.


Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.
Theme made by Freecode