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

Solved Enum or array inside query callback


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
McSnaggit
Junior Member
Join Date: Feb 2019
Old 03-24-2019 , 12:12   Enum or array inside query callback
Reply With Quote #1

Hi all,

I'm having trouble with sending parameters in my threaded query callback. The thing is that I need more than 1 variable to pass through to the callback.

Background Information
When a player death is inserted in the database. I need to link it to foreign keys like killtypeid, weaponid, and teamid. For that I need to query 3 times to different tables to get the correct id to use as foreign key. So I want to do that after I get the event ID I just inserted. Therefore I need to pass more information through the callback.

Code I am trying
PHP Code:
enum eventContent 

    
String:m_eventType[64], 
    
String:m_weapon[64], 
    
String:m_victimTeamName[64],
    
String:m_attackerTeamName[64],
    
m_gameEventIdentifier
}; 

//Just demo content
new eventInfo[eventContent] = 
{
    
"kill""ak47""T""CT"1920394
}

new 
String:eventQuery[200];
FormatEx(eventQuerysizeof(eventQuery), "INSERT INTO matchEvents (timestamp, tickTime, matchId, playerId, targetId, roundNumber, isWarmup) VALUES ('%d', '%f', '%d', '%d', '%d', '%d', '%d')"timestamptickTimeg_matchIdg_playerDatabaseIds[attackerId], g_playerDatabaseIds[victimId], g_roundNumberg_isWarmup);

//Normally as data you insert here the client id or just an int. I want it to be an array of multiple data types (ints and chars).
g_Database.Query(SQL_Insert_DeatheventQueryeventInfo); 
In the SQL_Insert_Death callback I want get the last inserted event id. And in that next callback I want to use the different information stored in eventInfo to update that event with the ID's I achieved in the next queries. Does that make sense?

How can I send an array or an enum as parameter with a callback?

Last edited by McSnaggit; 04-16-2019 at 08:28. Reason: Typo
McSnaggit is offline
Fyren
FyrenFyrenFyrenFyrenFyren FyrenFyrenFyrenFyrenFyren FyrenFyrenFyrenFyrenFyren FyrenFyrenFyrenFyrenFyren
Join Date: Feb 2106
Old 03-24-2019 , 18:43   Re: Enum or array inside query callback
Reply With Quote #2

Use a handle-based type like ArrayList or StringMap. You can't pass a basic array.
Fyren is offline
adma
Senior Member
Join Date: Oct 2015
Old 03-24-2019 , 22:30   Re: Enum or array inside query callback
Reply With Quote #3

To add onto Fyren's answer, you can also use DataPacks.
In your case,
PHP Code:
enum eventContent 

    
String:m_eventType[64], 
    
String:m_weapon[64], 
    
String:m_victimTeamName[64],
    
String:m_attackerTeamName[64],
    
m_gameEventIdentifier
}; 

//Just demo content
DataPack hEventInfo = new DataPack();
hEventInfo.WriteString("kill");
hEventInfo.WriteString("ak47");
hEventInfo.WriteString("T");
hEventInfo.WriteString("CT");
hEventInfo.WriteCell(1920394);

//new eventInfo[eventContent] = 
//{
//    "kill", "ak47", "T", "CT", 1920394
//}

char eventQuery[200];
FormatEx(eventQuerysizeof(eventQuery), "INSERT INTO matchEvents (timestamp, tickTime, matchId, playerId, targetId, roundNumber, isWarmup) VALUES ('%d', '%f', '%d', '%d', '%d', '%d', '%d')"timestamptickTimeg_matchIdg_playerDatabaseIds[attackerId], g_playerDatabaseIds[victimId], g_roundNumberg_isWarmup);

//Normally as data you insert here the client id or just an int. I want it to be an array of multiple data types (ints and chars).
g_Database.Query(SQL_Insert_DeatheventQueryhEventInfo);

public 
void eventQuery(Database dbDBResultSet results, const char[] errorDataPack hEventInfo) {
  
hEventInfo.Reset(); // reset datapack pos, you need to do this before reading a datapack 
  
static char szBuffer[32];
  
hEventInfo.ReadString(szBuffersizeof(szBuffer)); // "kill"
  
hEventInfo.ReadString(szBuffersizeof(szBuffer)); // "ak47"
  
hEventInfo.ReadString(szBuffersizeof(szBuffer)); // "T"
  
hEventInfo.ReadString(szBuffersizeof(szBuffer)); // "CT"
  
int iNumber hEventInfo.ReadCell(); // 1920394

  // make sure to close the datapack handle
  
delete hEventInfo;

I'd also urge you to use transitional syntax, e.g. String:blah[size] -> char blah[size]. Removes the need tags amongst other things, and keeps your plugin maintainable for other developers if you were to pass it on (who would most likely prefer to write in contemporary syntax).

Last edited by adma; 03-24-2019 at 22:33. Reason: Fix
adma is offline
McSnaggit
Junior Member
Join Date: Feb 2019
Old 03-25-2019 , 04:29   Re: Enum or array inside query callback
Reply With Quote #4

Wow, thanks guys. I knew there was something that I missed. I'm still learning sourcepawn as I am used to javascript.

I'm going to try this asap.

About the transitional syntax. I have read about it but I use code from different plugins and see different uses. Therefore I didn't know what is the right one. So the modern way to do it is just define the type by saying char test[64] instead of String:test[64]?

I will change my code to be up to date. Thanks a lot.
McSnaggit is offline
adma
Senior Member
Join Date: Oct 2015
Old 03-25-2019 , 07:08   Re: Enum or array inside query callback
Reply With Quote #5

Quote:
Originally Posted by McSnaggit View Post
About the transitional syntax. I have read about it but I use code from different plugins and see different uses. Therefore I didn't know what is the right one. So the modern way to do it is just define the type by saying char test[64] instead of String:test[64]?
Before SourcePawn 1.7, you used to use a concept called a "tag" on variables instead of actual "types" as there was only one type known by the compiler, called a "cell" (4 bytes). Tags were prepended to the variable name (declared using 'new' keyword) with a colon, e.g. new bool:bVariable. Nowadays, Sourcepawn has "true" data types:
Code:
bool - true or false.
char - an 8-bit ASCII character.
int - a 32-bit signed integer.
float - a 32-bit IEEE-754 floating point number.
Handle - the base type of a SourceMod object
These types are more akin to conventional types seen in langs like Java/C and are declared by putting the type before the variable, e.g. int iNum = 1. T̶h̶e̶y̶ ̶a̶r̶e̶ ̶t̶r̶u̶e̶ ̶t̶y̶p̶e̶s̶ ̶a̶n̶d̶ ̶a̶r̶e̶ ̶o̶n̶l̶y̶ ̶c̶a̶p̶a̶b̶l̶e̶ ̶o̶f̶ ̶s̶t̶o̶r̶i̶n̶g̶ ̶t̶h̶e̶ ̶a̶m̶o̶u̶n̶t̶ ̶o̶f̶ ̶m̶e̶m̶o̶r̶y̶ ̶t̶h̶e̶ ̶t̶y̶p̶e̶ ̶i̶s̶ ̶d̶e̶s̶i̶g̶n̶e̶d̶ ̶f̶o̶r̶.̶ Basically, avoid declaring variables with tags like bool: or String: and the new keyword. You can enforce this in the compiler by using #pragma newdecls required.

P̶.̶S̶.̶ ̶I̶ ̶d̶o̶n̶'̶t̶ ̶a̶c̶t̶u̶a̶l̶l̶y̶ ̶k̶n̶o̶w̶ ̶h̶o̶w̶ ̶t̶h̶e̶ ̶c̶o̶m̶p̶i̶l̶e̶r̶ ̶t̶r̶e̶a̶t̶s̶ ̶o̶l̶d̶e̶r̶ ̶s̶y̶n̶t̶a̶x̶,̶ ̶s̶o̶ ̶i̶t̶s̶ ̶p̶o̶s̶s̶i̶b̶l̶e̶ ̶t̶h̶a̶t̶ ̶t̶h̶e̶ ̶c̶o̶m̶p̶i̶l̶e̶r̶ ̶o̶p̶t̶i̶m̶i̶z̶e̶s̶ ̶o̶l̶d̶ ̶s̶y̶n̶t̶a̶x̶ ̶t̶o̶ ̶u̶s̶e̶ ̶t̶r̶u̶e̶ ̶t̶y̶p̶e̶s̶ ̶f̶o̶r̶ ̶m̶e̶m̶o̶r̶y̶ ̶o̶p̶t̶i̶m̶i̶z̶a̶t̶i̶o̶n̶.̶ ̶E̶v̶e̶n̶ ̶i̶f̶ ̶t̶h̶i̶s̶ ̶i̶s̶ ̶t̶h̶e̶ ̶c̶a̶s̶e̶,̶ ̶i̶t̶s̶ ̶s̶t̶i̶l̶l̶ ̶a̶ ̶g̶o̶o̶d̶ ̶i̶d̶e̶a̶ ̶t̶o̶ ̶a̶d̶o̶p̶t̶ ̶t̶r̶a̶n̶s̶i̶t̶i̶o̶n̶a̶l̶ ̶s̶y̶n̶t̶a̶x̶.̶

Last edited by adma; 03-26-2019 at 22:42. Reason: All variables are still 32 bit cells
adma is offline
McSnaggit
Junior Member
Join Date: Feb 2019
Old 03-26-2019 , 03:41   Re: Enum or array inside query callback
Reply With Quote #6

Great!

One question about the datapacks. When I want to send the datapack through to a second callback. Can I use it again without deleting it, or do I need to delete it first and create it again?

Like this:

PHP Code:
//Just demo content
DataPack hEventInfo = new DataPack();
hEventInfo.WriteString("kill");
hEventInfo.WriteString("ak47");
hEventInfo.WriteString("T");
hEventInfo.WriteString("CT");
hEventInfo.WriteCell(1920394);

char eventQuery[200];
FormatEx(eventQuerysizeof(eventQuery), "INSERT INTO matchEvents (timestamp, tickTime, matchId, playerId, targetId, roundNumber, isWarmup) VALUES ('%d', '%f', '%d', '%d', '%d', '%d', '%d')"timestamptickTimeg_matchIdg_playerDatabaseIds[attackerId], g_playerDatabaseIds[victimId], g_roundNumberg_isWarmup);

g_Database.Query(SQL_Insert_DeatheventQueryhEventInfo);

public 
void SQL_Insert_Death(Database dbDBResultSet results, const char[] errorDataPack hEventInfo) {
  
  
hEventInfo.Reset(); // reset datapack pos, you need to do this before reading a datapack 
  
  
char type[32]; hEventInfo.ReadString(typesizeof(type)); // "kill"
  
char weapon[32]; hEventInfo.ReadString(weaponsizeof(weapon)); // "ak47"
  
char killerTeam[32]; hEventInfo.ReadString(killerTeamsizeof(killerTeam)); // "T"
  
char victimTeam[32]; hEventInfo.ReadString(victimTeamsizeof(victimTeam)); // "CT"
  
int iNumber hEventInfo.ReadCell(); // 1920394

  //Create Type
  
char createTypeQuery[256]; FormatEx(createTypeQuerysizeof(createTypeQuery), "INSERT INTO types (name) VALUES ('%s');"eventDetail);
  
db.Query(SQL_Create_TypecreateTypeQueryhEventInfo);
}

public 
void SQL_Create_Type(Database dbDBResultSet results, const char[] errorDataPack hEventInfo) {
  
  
hEventInfo.Reset(); // reset datapack pos, you need to do this before reading a datapack 
  
  
char type[32]; hEventInfo.ReadString(typesizeof(type)); // "kill"
  
char weapon[32]; hEventInfo.ReadString(weaponsizeof(weapon)); // "ak47"
  
char killerTeam[32]; hEventInfo.ReadString(killerTeamsizeof(killerTeam)); // "T"
  
char victimTeam[32]; hEventInfo.ReadString(victimTeamsizeof(victimTeam)); // "CT"
  
int iNumber hEventInfo.ReadCell(); // 1920394

  // make sure to close the datapack handle
  
delete hEventInfo;


Last edited by McSnaggit; 03-26-2019 at 03:42.
McSnaggit is offline
adma
Senior Member
Join Date: Oct 2015
Old 03-26-2019 , 08:24   Re: Enum or array inside query callback
Reply With Quote #7

Quote:
Originally Posted by McSnaggit View Post
Can I use it again without deleting it, or do I need to delete it first and create it again?[/PHP]
You can use the datapack until all Handles pointing to the datapack are closed, so yes, you can pass it through multiple callbacks and then close the handle at the end - as long as it is guaranteed you close it otherwise you'll end up with potential memory leaks. When you create a datapack using new DataPack() or CreateDataPack() you're actually creating a single data structure, and then Sourcemod returns a Handle which points to this data structure/memory. When a data structure no longer has any more Handles pointing to it, the internal data structure gets freed from memory.
adma is offline
McSnaggit
Junior Member
Join Date: Feb 2019
Old 03-26-2019 , 08:47   Re: Enum or array inside query callback
Reply With Quote #8

So the above code is OK? Or should I send it to the callback and after sending in the same function close it again?

So like this:

PHP Code:

public void SQL_Insert_Death(Database dbDBResultSet results, const char[] errorDataPack hEventInfo) {
  
  
hEventInfo.Reset(); // reset datapack pos, you need to do this before reading a datapack 
  
  
char type[32]; hEventInfo.ReadString(typesizeof(type)); // "kill"
  
char weapon[32]; hEventInfo.ReadString(weaponsizeof(weapon)); // "ak47"
  
char killerTeam[32]; hEventInfo.ReadString(killerTeamsizeof(killerTeam)); // "T"
  
char victimTeam[32]; hEventInfo.ReadString(victimTeamsizeof(victimTeam)); // "CT"
  
int iNumber hEventInfo.ReadCell(); // 1920394

  //Create Type
  
char createTypeQuery[256]; FormatEx(createTypeQuerysizeof(createTypeQuery), "INSERT INTO types (name) VALUES ('%s');"eventDetail);
  
db.Query(SQL_Create_TypecreateTypeQueryhEventInfo);

  
// make sure to close the datapack handle
  
delete hEventInfo;

Or just close it after I use it for the last time?
McSnaggit is offline
adma
Senior Member
Join Date: Oct 2015
Old 03-26-2019 , 08:54   Re: Enum or array inside query callback
Reply With Quote #9

Quote:
Originally Posted by McSnaggit View Post
So the above code is OK? Or should I send it to the callback and after sending in the same function close it again?

So like this:

PHP Code:

public void SQL_Insert_Death(Database dbDBResultSet results, const char[] errorDataPack hEventInfo) {
  
  
hEventInfo.Reset(); // reset datapack pos, you need to do this before reading a datapack 
  
  
char type[32]; hEventInfo.ReadString(typesizeof(type)); // "kill"
  
char weapon[32]; hEventInfo.ReadString(weaponsizeof(weapon)); // "ak47"
  
char killerTeam[32]; hEventInfo.ReadString(killerTeamsizeof(killerTeam)); // "T"
  
char victimTeam[32]; hEventInfo.ReadString(victimTeamsizeof(victimTeam)); // "CT"
  
int iNumber hEventInfo.ReadCell(); // 1920394

  //Create Type
  
char createTypeQuery[256]; FormatEx(createTypeQuerysizeof(createTypeQuery), "INSERT INTO types (name) VALUES ('%s');"eventDetail);
  
db.Query(SQL_Create_TypecreateTypeQueryhEventInfo);

  
// make sure to close the datapack handle
  
delete hEventInfo;

Or just close it after I use it for the last time?
You close it after you use it for the last time. If you try to use a handle after you've closed it, you will run into errors because that handle doesn't exist anymore.
adma is offline
Fyren
FyrenFyrenFyrenFyrenFyren FyrenFyrenFyrenFyrenFyren FyrenFyrenFyrenFyrenFyren FyrenFyrenFyrenFyrenFyren
Join Date: Feb 2106
Old 03-26-2019 , 12:07   Re: Enum or array inside query callback
Reply With Quote #10

Quote:
Originally Posted by adma View Post
Before SourcePawn 1.7...
Everything is still a cell. The only thing that changed was the syntax.
Fyren is offline
Reply


Thread Tools
Display Modes

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 05:24.


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