SA-MP Forums

Go Back   SA-MP Forums > SA-MP Scripting and Plugins > Plugin Development

Reply
 
Thread Tools Display Modes
Old 25/03/2017, 09:06 PM   #351
WopsS
Huge Clucker
 
WopsS's Avatar
 
Join Date: Nov 2011
Posts: 491
Reputation: 70
Default Re: Gamemode SDK for C/C++ (GDK)

Sorry for the double post, but here is a prototype for SetTimerEx.

Code:
template<typename... Args>
const int SetTimerEx(const std::string& func_name, const int interval, const bool repeating, const size_t total_arguments, const std::string& format, Args&& ...args)
{
	static AMX_NATIVE native = sampgdk::FindNative("SetTimerEx");
	return sampgdk::InvokeNative(native, (std::string("sibs") + std::string(total_arguments, 'r')).c_str(), func_name.c_str(), interval, repeating, format.c_str(), std::forward<Args>(args)...);
}
or

Code:
template<typename... Args>
const int SetTimerEx(const std::string& func_name, const int interval, const bool repeating, const std::string& format, Args&& ...args)
{
	static AMX_NATIVE native = sampgdk::FindNative("SetTimerEx");
	return sampgdk::InvokeNative(native, (std::string("sibs") + std::string(format.length(), 'r')).c_str(), func_name.c_str(), interval, repeating, format.c_str(), std::forward<Args>(args)...);
}
The second one is better since you don't need total_arguments anymore.

You can use it like this:

Code:
int test = 10;
int test2 = 20;
int test3 = 30;

SetTimerEx("TestTimer", 1000, true, 3, "iii", &test, &test2, &test3);
At OnPublicCall I have this

Code:
PLUGIN_EXPORT bool PLUGIN_CALL OnPublicCall(AMX *amx, const char *name, cell *params, cell *retval)
{
	auto Name = std::string(name);

	if (Name == "TestTimer")
	{
		std::cout << "TestTimer(" << params[1] << ", " << params[2] << ", " << params[3] << ")" << std::endl;
	}

	return true;
}
For floats use amx_ctof(param[index]).

// The only problem is with the strings, I cannot manage to get them, but maybe I'm doing it wrong.

I managed to get the strings using sampgdk_fakeamx_get_string and handle a special case for s. Now SetTimerEx looks like

Code:
template<typename... Args>
const int SetTimerEx(const std::string& func_name, const  int interval, const bool repeating, const std::string& format, Args&& ...args)
{
	static AMX_NATIVE native = sampgdk::FindNative("SetTimerEx");

	std::string function_format = "sibs";

	for (size_t i = 0; i < format.length(); i++)
	{
		function_format += format[i] == 's' ? "s" : "r";
	}

	return sampgdk::InvokeNative(native, function_format.c_str(), func_name.c_str(), interval, repeating, format.c_str(), std::forward<Args>(args)...);
}
and OnPublicCall

Code:
PLUGIN_EXPORT bool PLUGIN_CALL OnPublicCall(AMX *amx, const char *name, cell *params, cell *retval)
{
	auto Name = std::string(name);

	if (Name == "TestTimer")
	{
		char string[7];
		sampgdk_fakeamx_get_string(params[5], string, params[4] + 1);

		std::cout << "TestTimer(" << params[1] << ", " << params[2] << ", " << amx_ctof(params[3]) << ", \"" << string << "\")" << std::endl;
	}

	return true;
}
At the top of the file add

Code:
extern void sampgdk_fakeamx_get_string(cell address, char *dest, int size);
The call:

Code:
int test = 10;
int test2 = 20;
float test3 = 30.456f;
std::string test4 = "Hello!";
size_t test4_length = test4.length();
	
SetTimerEx("TestTimer", 1000, true, "iifis", &test, &test2, &test3, &test4_length, test4.c_str());
I can't find another way to pass strings for this function.

P.S: You need to pass the length of the string if you want to get it back.

Last edited by WopsS; 25/03/2017 at 10:54 PM.
WopsS is offline   Reply With Quote
Old 04/04/2017, 10:04 PM   #352
IstuntmanI
High-roller
 
IstuntmanI's Avatar
 
Join Date: Mar 2009
Location: Romania
Posts: 1,832
Reputation: 375
Default Re: Gamemode SDK for C/C++ (GDK)

I worked around these things, with help from your responses (thanks !) and now I came back with additional things:

--------------------------------------------------------
--------------------------------------------------------

Quote:
Originally Posted by WopsS View Post
...
This is for AttachDynamicObjectToObject
Code:
const bool Object::AttachToObject(int32_t ID, int32_t AttachToID, float X, float Y, float Z, float RotationX, float RotationY, float RotationZ, bool SyncRotation)
{
	static AMX_NATIVE Native = sampgdk::FindNative("AttachDynamicObjectToObject");
	return !!sampgdk::InvokeNative(Native, "iiffffffb", ID, AttachToID, X, Y, Z, RotationX, RotationY, RotationZ, SyncRotation);
}
...
Thanks for these examples, you gave me an idea to use namespaces for plugins functions. For example, CreateDynamicObject from streamer now looks like Plugins::Streamer::Object::Create now (a bit too long, but perfectly organised). Here is how it looks like, for who wants to see it:
Code:
namespace Plugins
{
	namespace Streamer
	{
		namespace Object
		{
				int Create( int modelid, float x, float y, float z, float rx, float ry, float rz, int worldid = -1, int interiorid = -1, int playerid = -1, float streamdistance = STREAMER_OBJECT_SD, float drawdistance = STREAMER_OBJECT_DD, int areaid = -1, int priority = 0 )
				{
					static AMX_NATIVE Native = sampgdk::FindNative( "CreateDynamicObject" );
					return sampgdk::InvokeNative( Native, "iffffffiiiffii", modelid, x, y, z, rx, ry, rz, worldid, interiorid, playerid, streamdistance, drawdistance, areaid, priority );
				}
		};
	};
};
--------------------------------------------------------

Quote:
Originally Posted by WopsS View Post
I don't have anything in mind for mysql_pquery, but you can try to use a single parameter as a class or a struct.
A problem: I made this:
Code:
template< typename... Args >
const bool pquery( int connectionHandle, const char query[ ], const char callback[ ] = "", const char format[ ] = "", Args && ... args )
{
	static AMX_NATIVE Native = sampgdk::FindNative( "mysql_pquery" );

	std::string function_format = "isss";

	for( int i = 0, s = std::strlen( format ); i < s; i ++ )
	{
		function_format += ( format[ i ] == 's' ? "s" : "r" );
	}

	return !!sampgdk::InvokeNative( Native, function_format.c_str( ), connectionHandle, query, callback, format, std::forward< Args >( args ) ... );
}
Code:
Plugins::MySQL::pquery( 1, "<query>", "Callback", "iii", &varint1, &varint2, &varint3 );
But the function is not called:
Quote:
Originally Posted by mysql_log.html
Log("00:19:31","mysql_pquery",4,"connection: 1, query: \"<query>\", callback: \"Callback\", format: \"iii\"",0);
Log("00:19:31","CMySQLQuery::Execute[OnQueryFinish]",4,"starting query execution",1);
Log("00:19:31","CMySQLQuery::Execute[Callback]",4,"starting query execution",1);
Log("00:19:31","CMySQLQuery::Execute[Callback]",4,"query was successfully executed within x.xxx milliseconds",1);
Log("00:19:31","CMySQLResult::CMySQLResult()",4,"c onstructor called",1);
OnPublicCall with the name of that Callback isn't called (I'm printing in console all calls with the parameters). I even added that callback in the .def file. By the way, is it needed to add callbacks called by functions like mysql_pquery in the .def file ? Is it a problem of the MySQL, or I can solve this somehow ? I could really use some informations about this thing. Also, thanks for the idea of using &&, allowing me to pass both lvalues and rvalues, I just understood why you used that instead of pointers as arguments and "args ..." in InvokeNative.

--------------------------------------------------------

Quote:
Originally Posted by WopsS View Post
When you call SetTimer you will pass a void* for parameters, in your function you need to know how to use that void*, that's why he is using a struct for that (you can use a class). This is the easy way. But if you want to use std::tuple go ahead, take a look here to see how you can achieve that.
Not that, I was asking if we can't make a more advanced timer system, using ProcessTick. Instead of passing some struct and doing retarded casts we could simply pass a std::tuple with a variable number of elements.
I actually did this, using variadic templates from newer C++ standards, which means that it is also type safe, as everything is known at compile time. Here is what it looks like:
Code:
Timers::SetTimerEx( TimerFunction, 1000, 0, std::make_tuple( playerid, 10.0, "hello" ) );

void TimerFunction( int timerid, std::tuple< int, float, char * > params )
{
    int playerid = std::get< 0 >( params );
    float posX = std::get< 1 >( params );
    char * message = std::get< 2 >( params );
}
C++ compiler is really powerful. Maybe I'll release this timer system. It is based on Dan's timer system. It's a lot better than sampGDK's timer system.

--------------------------------------------------------

By the way, if anyone is interested in keeping to use the sscanf of ******, I also used these methods to call the sscanf function:
Code:
namespace Plugins
{
	namespace SSCANF
	{
		template< typename... Args >
		const int unformat( const char data[ ], const char format[ ], Args * ... args )
		{
			static AMX_NATIVE Native = sampgdk::FindNative( "sscanf" );

			std::string function_format = "ss";

			for( int i = 0, s = std::strlen( format ); i < s; i ++ )
			{
				switch( format[ i ] )
				{
					case 's': function_format += "S[128]"; break;
					case 'i': case 'd': case 'c': case 'l': case 'b': case 'h': case 'x': case 'o': case 'n': case 'f': case 'g': case 'u': case 'q': case 'r': function_format += "R"; break;
					default: break;
				}
			}

			return sampgdk::InvokeNative( Native, function_format.c_str( ), data, format, args ... );
		}
	};
};
Usage:
Code:
Plugins::SSCANF::unformat( "Data 5.0 hello", "p< >s[5]fs[6]", varstring1, &varfloat, varstring2 );
I know that C has sscanf and this looks stupid, but I find the variant of ****** a lot better for SA-MP's needs. By the way, I know that my method of doing it won't work fine with all usage cases of sscanf, but it's better than nothing. It fits perfectly for my needs. I don't use sscanf's "a" specifier, kustom (I only used it in 4 cases, but I converted to "d" ) or other more advanced things. In future maybe I'll try to convert sscanf and include it in my gamemode.
__________________



Last edited by IstuntmanI; 06/04/2017 at 11:02 PM.
IstuntmanI is offline   Reply With Quote
Old 05/04/2017, 12:21 AM   #353
WopsS
Huge Clucker
 
WopsS's Avatar
 
Join Date: Nov 2011
Posts: 491
Reputation: 70
Default Re: Gamemode SDK for C/C++ (GDK)

Quote:
Originally Posted by IstuntmanI View Post
I worked around these things, with help from your responses (thanks !) and now I came back with additional things:
No problem.

About mysql_pquery I think it doesn't call your function because of this line
Code:
if (amx_FindPublic(amx, query->Callback.Name.c_str(), &amx_index) == AMX_ERR_NONE && amx_index >= 0)
try to replace it to

Code:
if (!amx_FindPublic(amx, query->Callback.Name.c_str(), &amx_index))
You need to recompile MySQL R39 from source.
WopsS is offline   Reply With Quote
Old 05/04/2017, 05:35 PM   #354
maddinat0r
Banned
 
Join Date: Jun 2010
Location: Germany
Posts: 848
Reputation: 482
Default Re: Gamemode SDK for C/C++ (GDK)

Doing the change Wopss wrote is okay, here's the commit that introduced this.

However I'd suggest you incorporate the source of the MySQL plugin R40 or higher directly into your C++ gamemode. I've redesigned the internal API with the potential usage in a sampgdk gamemode back in my mind. Creating a connection, sending a query and processing the result is as easy as this:
Code:
CError<CHandle> handle_error;
Handle_t handle = CHandleManager::Get()->Create(
	"localhost", "root", "pass", "database",
	options, handle_error);

if (handle_error)
{
	// some error happened
	return 0;
}

Query_t query = CQuery::Create("SELECT * FROM stuff");
query->OnExecutionFinished([callback](ResultSet_t resultset)
{
	Result_t result = resultset->GetActiveResult();
	
	std::string stuff;
	result->GetRowDataByName(0, "fieldname", stuff);
	
	printf("stuff is %s\n", stuff.c_str());
});
handle->Execute(CHandle::ExecutionType::PARALLEL, query);
You basically just have to copy over (almost) all plugin source files into your project and link it with the MySQL C connector library. Oh, and your compiler should be C++11-compliant.
maddinat0r is offline   Reply With Quote
Old 09/05/2017, 01:45 AM   #355
TheRealSphinx
Little Clucker
 
TheRealSphinx's Avatar
 
Join Date: Nov 2016
Posts: 21
Reputation: 12
Default Re: Gamemode SDK for C/C++ (GDK)

Quote:
Originally Posted by WopsS View Post
Hello,

I want to leave a response here about Streamer with SAMPGDK. You can use it as xeeZ said here, but you don't need to invoke Streamer_CallbackHook since it is deprecated in version 2.7.8.

Why?
Because Incognito decided to use SAMPGDK for OnPlayerConnect and OnPlayerDisconnect.

All you need to do is to invoke CreateDynamicObject as xeeZ do in his gist.
Code:
int CreateDynamicObject(int modelid, float x, float y, float z, float rx, float ry, float rz, int worldid = -1, int interiorid = -1, int playerid = -1, float streamdistance = 200.0, float drawdistance = 0.0)
{
  static AMX_NATIVE native = sampgdk::FindNative("CreateDynamicObject");
  return sampgdk::InvokeNative(native, "iffffffiiiff", modelid, x, y, z, rx, ry, rz, worldid, interiorid, playerid, streamdistance, drawdistance);
}
And then call it.

Now, I want to know your opinion. If we want to use Streamer with SAMPGDK it is better to invoke a native (like the method above) or to combine streamer plugin with our project (which will be a pain in the a** with plugin updates and with the combination)?

By the way, can we register a Streamer's callback in our plugins?
I tried this
Code:
SAMPGDK_CALLBACK(bool, OnPlayerEditDynamicObject(int playerid, int  objectid, int  response, float x, float y, float z, float rx, float ry, float rz));
SAMPGDK_CALLBACK(bool, OnPlayerSelectDynamicObject(int playerid, int objectid, int modelid, float x, float y, float z));

PLUGIN_EXPORT bool PLUGIN_CALL OnPlayerEditDynamicObject(int playerid, int  objectid, int  response, float x, float y, float z, float rx, float ry, float rz)
{
	sampgdk::logprintf("OnPlayerEditDynamicObject: %i | %f | %f | %f", objectid, x, y, z);
	return true;
}

PLUGIN_EXPORT bool PLUGIN_CALL OnPlayerSelectDynamicObject(int playerid, int objectid, int modelid, float x, float y, float z)
{
	sampgdk::logprintf("OnPlayerSelectDynamicObject: %i | %f | %f | %f", objectid, x, y, z);
	return true;
}
And this functions aren't called, instead OnPlayerEditObject is called. If I edit an object.
Hi,

you can use this streamer version that supports direct implementation of the streamer in the gamemode.
Then you just need to call the events in your gamemode.

All needed events are listed in the header file.
https://github.com/Sphinxila/samp-pl...r/streamer.hpp

I think its self explanatory.
Feel free to use it or just ignore it ^^.

I rewrote this just for my usage cause "InvokeNative"...
It's not the point of using the SampGDK.

Kind regards
Sphinx
TheRealSphinx is offline   Reply With Quote
Old 17/07/2018, 05:07 PM   #356
ChronosX
Little Clucker
 
ChronosX's Avatar
 
Join Date: Dec 2017
Location: Russia, Volgograd
Posts: 2
Reputation: 0
Default Re: Gamemode SDK for C/C++ (GDK)

Zeex, I have one question. I really want to write my gamemode using SampGDK. But, as I understand, third-party plug-ins (such as Streamer, sscanf, mxINI, etc.) Can not be inserted into the GM simply #include "*plugin*", because the syntax of header files is incompatible with C++. How can I port it then?
__________________
SAMP 4EVER!!!
ChronosX is offline   Reply With Quote
Old 17/07/2018, 05:42 PM   #357
J0sh...
Banned
 
Join Date: Aug 2014
Location: Hamburger
Posts: 1,298
Reputation: 461
Default Re: Gamemode SDK for C/C++ (GDK)

https://github.com/IstuntmanI/samp-s...sampgdk-invoke for streamer (or just port it).
sscanf is already supplied in C.
mxINI... create your own INI parser or find one on github, there's tons.
J0sh... is offline   Reply With Quote
Old 17/07/2018, 06:40 PM   #358
BigETI
Banned
 
Join Date: Mar 2010
Location: Germany
Posts: 1,054
Reputation: 359
Default Re: Gamemode SDK for C/C++ (GDK)

Quote:
Originally Posted by Freshncool View Post
https://github.com/IstuntmanI/samp-s...sampgdk-invoke for streamer (or just port it).
sscanf is already supplied in C.
mxINI... create your own INI parser or find one on github, there's tons.
There should be ways to link streamer function with your library.
In C++ there are better ways to interpret command arguments, without ever touching sscanf from the standard C library.
BigETI is offline   Reply With Quote
Old 30/05/2019, 06:09 AM   #359
Xxhype
Little Clucker
 
Xxhype's Avatar
 
Join Date: Feb 2019
Posts: 16
Reputation: 4
Default Re: Gamemode SDK for C/C++ (GDK)

Plugin failed to load, any solutions?
Edit:
1. I followed all steps correctly, gamemode loads
2. I compiled plugin in x64 instead of x86 since I don't see option to compile it in x86.
3. I have all MS bullshit .dlls for server to run this plugin
Xxhype is offline   Reply With Quote
Old 02/06/2019, 11:41 AM   #360
xeeZ
Huge Clucker
 
Join Date: Feb 2013
Posts: 320
Reputation: 382
Default Re: Gamemode SDK for C/C++ (GDK)

Usually the server fails to load plugins on Windows because of missing libraries (DLLs). You can use Dependency Walker (http://www.dependencywalker.com/) to open your compiled DLL and see if something is missing. If you are using a dynamic version of sampgdk (dynamic library), you have to put the corresponding sampgdk.dll file in the server root directory.

Regarding x64: the SA-MP server is a 32-bit app, so you must compile the plugin for the x86 architecture. I can't remember how it's done in Visual Studio, sorry.
xeeZ is offline   Reply With Quote
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


Similar Threads
Thread Thread Starter Forum Replies Last Post
Gamemode is unknown. When i connect theres no gamemode. Shannon_Brown Server Support 11 09/09/2012 08:49 AM
[GameMode] Brasil Drift Show [BDS] - Primeiro GameMode vitorzero3um PortuguÍs/Portuguese 3 29/02/2012 06:48 PM
[ENG] Ideas for new GameMode [NL] Ideeen voor nieuwe Gamemode Xtreme-Nicole Everything and Nothing 10 10/07/2011 11:20 AM
[ENG] Ideas for new GameMode [NL] Ideeen voor nieuwe GameMode Xtreme-Nicole Help Archive 2 09/07/2011 11:24 AM


All times are GMT. The time now is 04:15 AM.


Powered by vBulletin® Version 3.8.6
Copyright ©2000 - 2019, Jelsoft Enterprises Ltd.