samp-streamer-plugin icon indicating copy to clipboard operation
samp-streamer-plugin copied to clipboard

Easier to integrate with sampGDK

Open IstuntmanI opened this issue 7 years ago • 13 comments

I noticed that forks are being created to make the Streamer Plugin compatible natively with sampGDK, which requires pretty many changes. I'm also using sampGDK since a few months ago, but for now I want to keep using the pretty bad sampgdk::invokeNative because in this way it is easier for me to upgrade to future Streamer Plugin versions, without doing too many changes by myself. The ability to add some preprocessor definitions while compiling the Streamer Plugin with our sampGDK gamemode could be pure gold and could make upgrading really easy for us, while safely removing the AMX files.

Theoretically, I think that we only have to modify the AMX stuff to be perfectly compatible with C++ . The only AMX stuff I found is in the natives.h/"natives/" .h and .cpp files.

I suggest:

  1. Two preprocessor definitions:
  • "STREAMER_USE_CPP" which would remove all the AMX stuff with "#if defined STREAMER_USE_CPP" and natives would look like:
#if defined STREAMER_USE_CPP
// default values should be in the natives.h file
int CreateDynamicActor(int modelid, float x, float y, float z, float r, bool invulnerable, int health, int worldid, int interiorid, int playerid, int streamdistance, int areaid, int priority)
{
#else
cell AMX_NATIVE_CALL Natives::CreateDynamicActor(AMX *amx, cell *params)
{
	CHECK_PARAMS(13, "CreateDynamicActor");
	int modelid = static_cast<int>(params[1]);
	float x = amx_ctof(params[2]), y = amx_ctof(params[3]), z = amx_ctof(params[4]);
	float r = amx_ctof(params[5]);
	bool invulnerable = static_cast<int>(params[6]) != 0;
	float health = amx_ctof(params[7]);
	int worldid = static_cast<int>(params[8]);
	int interiorid = static_cast<int>(params[9]);
	int playerid = static_cast<int>(params[10]);
	float streamdistance = amx_ctof(params[11]);
	int areaid = static_cast<int>(params[12]);
	int priority = static_cast<int>(params[13]);
#endif
	if (core->getData()->getGlobalMaxItems(STREAMER_TYPE_ACTOR) == core->getData()->actors.size())
	{
		return 0;
	}
	int actorID = Item::Actor::identifier.get();
	Item::SharedActor actor(new Item::Actor);
	actor->amx = amx;
	actor->actorID = actorID;
	actor->inverseAreaChecking = false;
	actor->originalComparableStreamDistance = -1.0f;
	actor->positionOffset = Eigen::Vector3f::Zero();
	actor->modelID = modelid;
	actor->position = Eigen::Vector3f(x, y, z);
	actor->rotation = r;
	actor->invulnerable = invulnerable;
	actor->health = health;
	Utility::addToContainer(actor->worlds, worlid);
	Utility::addToContainer(actor->interiors, interiorid);
	Utility::addToContainer(actor->players, playerid);
	actor->comparableStreamDistance = streamdistance < STREAMER_STATIC_DISTANCE_CUTOFF ? streamdistance : streamdistance * streamdistance;
	actor->streamDistance = streamdistance;
	Utility::addToContainer(actor->areas, areaid);
	actor->priority = priority;
	core->getGrid()->addActor(actor);
	core->getData()->actors.insert(std::make_pair(actorID, actor));

	#if defined STREAMER_USE_CPP
		return static_cast<cell>(actorID);
	#else
		return actorID;
	#endif
}
  • "STREAMER_REMOVE_AMX_CALL", it would affect callbacks.cpp and natives.h files. This can be useful if you would like to remove the additional dependency for the amx files (there should be checks for this before including amx files in the files from this plugin), so you won't be able to use the "dynamic" callbacks and natives in filterscripts or a Pawn gamemode. It will disable the ability to call natives in filterscripts anymore (also, the callbacks won't be called there anymore). I guess that this definition should also change how a native should look like, from the first example (of STREAMER_USE_CPP).

For callback hooking, we would need to add, for example, a "OnPlayerPickUpDynamicPickup( playerid, pickupid );" call to our sampGDK's gamemode OnPlayerPickUpPickup callback. A callback would look like this:

PLUGIN_EXPORT bool PLUGIN_CALL OnPlayerPickUpPickup(int playerid, int pickupid)
{
	for (boost::unordered_map<int, int>::iterator i = core->getData()->internalPickups.begin(); i != core->getData()->internalPickups.end(); ++i)
	{
		if (i->second == pickupid)
		{
			#if defined STREAMER_USE_CPP
				OnPlayerPickUpDynamicPickup(playerid, i->first);
/*
There should be a callbacks.h for the declarations of all callbacks, included at the top of callbacks.cpp.
If STREAMER_USE_CPP is defined the callbacks.h file could be included in natives.h.
*/
			#endif

			#if !defined STREAMER_REMOVE_AMX_CALL
				int pickupid = i->first;
				for (std::set<AMX*>::iterator a = core->getData()->interfaces.begin(); a != core->getData()->interfaces.end(); ++a)
				{
					int amxIndex = 0;
					if (!amx_FindPublic(*a, "OnPlayerPickUpDynamicPickup", &amxIndex))
					{
						amx_Push(*a, static_cast<cell>(pickupid));
						amx_Push(*a, static_cast<cell>(playerid));
						amx_Exec(*a, NULL, amxIndex);
					}
				}
			#endif
			break;
		}
	}
	return true;
}
  1. All the AMX functions declarations should be in natives.h, just like now, only if STREAMER_REMOVE_AMX_CALL isn't defined. For other natives, create a .h file for each "natives/" file and just include them in the main natives.h file, if STREAMER_USE_CPP is defined.

  2. Maybe it should be provided a better C++ namespacing ? For example, instead of Natives::CreateDynamicObject we should have Streamer::Natives::Object::Create (this should look like this internally, without any additional preprocessor definition, users should keep using this method in C++, it looks great and is really organised, Visual Studio can provide great autocomplete with this). Maybe you would like to offer some wrappers for the regular documented functions, so CreateDynamicObject would "redirect" to Streamer::Natives::Object::Create. Also, the CPP callbacks should have namespaces too: OnPlayerPickUpDynamicPickup should be something like Streamer::Callbacks::OnPlayerPickUpDynamicPickup, not sure if we could find a better name for this, maybe these:

OnDynamicObjectMoved -> Streamer::Callbacks::Object::OnMoved
OnPlayerEditDynamicObject -> Streamer::Callbacks::Object::OnEdit
OnPlayerSelectDynamicObject -> Streamer::Callbacks::Object::OnSelect
OnPlayerShootDynamicObject -> Streamer::Callbacks::Object::OnShoot
OnPlayerPickUpDynamicPickup -> Streamer::Callbacks::Pickup::OnPickUp
OnPlayerEnterDynamicCP -> Streamer::Callbacks::CP::OnEnter
OnPlayerLeaveDynamicCP -> Streamer::Callbacks::CP::OnLeave
OnPlayerEnterDynamicRaceCP -> Streamer::Callbacks::RaceCP::OnEnter
OnPlayerLeaveDynamicRaceCP -> Streamer::Callbacks::RaceCP::OnLeave
OnPlayerEnterDynamicArea -> Streamer::Callbacks::Area::OnEnter
OnPlayerLeaveDynamicArea -> Streamer::Callbacks::Area::OnLeave
OnPlayerGiveDamageDynamicActor -> Streamer::Callbacks::Actor::OnGiveDamage
OnDynamicActorStreamIn -> Streamer::Callbacks::Actor::OnStreamIn
OnDynamicActorStreamOut -> Streamer::Callbacks::Actor::OnStreamOut
Streamer_OnItemStreamIn -> Streamer::Callbacks::Item::OnStreamIn
Streamer_OnItemStreamOut -> Streamer::Callbacks::Item::OnStreamOut
Streamer_OnPluginError -> Streamer::Callbacks::OnError
  1. We should also be able to use the regular streamer.inc definitions, just like in Pawn.

  2. The current tags, like STREAMER_TAG_ACTOR, could be replaced with enum types in C++ . I didn't think too much about this, maybe you could think of something about this, or just let us use regular "int" values.

We could include it just like

#define STREAMER_OBJECT_SD 500.00
#include <streamer/natives.h>

I tried to be as detailed as possible with this issue, so I could give you a better idea about the implementation. You could create a base model commit (how it should look in the end, but without all natives if you don't have enough time, because they are a lot) for this issue and we could help with pull requests for the rest of natives.

I wonder why didn't anyone else thought about this, because sampGDK is getting more popular, as Pawn is a dead and really limited language.

EDIT: By the way, I made a "streamer.h" out of the regular "streamer.inc", by using sampgdk::InvokeNative to call functions. If I remember correctly, I didn't implement only a few functions (the extended creation functions, only the one from MapIcons [I only used this extended function] and the deprecated ones) and it has 1300 lines, which is huge and, of course, inefficient because of the AMX layer.

IstuntmanI avatar May 11 '17 19:05 IstuntmanI

I am in favor of this! Right now, I'm in the process of converting a fork of the plugin to be compatible with my sampgdk gamemode. It has taken considerable time to strip out the amx stuff, so this would be useful! Perhaps it would attract more users to C++ and the gdk, as you mentioned PAWN is limited and outdated. :)

Edit: finalized the converting of the latest branch to be fully compatible with the gamemode. Took ~3 days to accomplish it. Again, this would be awesome if it were possible. If anyone is interested I can provide you with the converted plugin. I have modified some things for performance benefit (removing the amx layer makes it faster as it is :D), and stripped things out that can be done in a better fashion in native C++ code.

ghost avatar May 11 '17 19:05 ghost

It's not a bad idea. I agree about the PAWN limitations (it's why this plugin was created, after all). I'd imagine that the majority of people using this are still running PAWN scripts on their server, though.

I suppose I could make a separate repository, and someone could open a pull request from there. It seems to me that it might work better as a fork, though. If someone else wants to maintain it, I could just link to it on the wiki.

samp-incognito avatar May 20 '17 18:05 samp-incognito

Well, of course that the majority is still running PAWN scripts, because that's the native way to create a SA-MP server, which sucks.

This should be in the same branch, in this main repository, so it will be updated instantly in future. Compiler "tricks" (just like I specified in the first post) can make this really easy. Pull requests could be made in time, I don't think anyone needs this thing to be finished too fast.

AFAIK, other guys already made forks of this to make it easier to integrate it with C++ gamemodes, but I don't want to use one of those forks mainly because they aren't updated at the same time with this branch and they could abandon that fork. I think that my suggestion is the best way to keep the plugin up-to-date really easy.

Just like I said in the first post, you could make a commit with the base structure of this thing and we could do the same thing for natives for the other ones, you could provide just a "demo" native with this method, so we can see exactly how you want it to look like. Of course, you can do it when you have time, it isn't urgent.

IstuntmanI avatar May 20 '17 19:05 IstuntmanI

Yes, that would probably be a better solution. It would be easier to maintain as well. I'll see about setting it up some time.

samp-incognito avatar May 21 '17 17:05 samp-incognito

Excuse me, I write gamemode for samp on GDK too, and use this streamer plugin. So... What about a version for GDK ?

buridan1999 avatar Jul 15 '17 16:07 buridan1999

This may help, I guess: https://github.com/Y-Less/plugin-natives . I think it will simplify things a lot, but it won't allow us to use smarter names in namespaces, like Streamer::Functions::Object::Create.

But it uses C++11, so it will break compatibility with older systems, it's your call, @samp-incognito. Maybe the streamer plugin should finally upgrade, C++11 is a lot better.

IstuntmanI avatar Aug 04 '17 16:08 IstuntmanI

It would be better to this like this:

  • https://github.com/Sphinxila/samp-plugin-streamer/blob/master/src/implements/extended_impl.cpp

This file contains the functionality as an example (CreateDynamicPickupEx):

int CreateDynamicPickupEx(
	int modelid,
	int type,
	float x,
	float y,
	float z,
	float streamDistance,
	boost::unordered_set<int> &worlds,
	boost::unordered_set<int> &interiors,
	std::bitset<MAX_PLAYERS> &players,
	boost::unordered_set<int> &areas,
	int priority
)

And then we just need to create the pawn wrapper functions:

cell AMX_NATIVE_CALL Natives::CreateDynamicObjectEx(AMX *amx, cell *params)
{
	return CreateDynamicPickupEx(params[0],params[1].....)
}

That's it....

Cause we also want to provide the streamer functionality for the gamemodes ;)... I have combined it and my plugin provides the streamer functionality also for gamemodes / filterscripts.

Kind regards Sphinx

philip1337 avatar Aug 05 '17 15:08 philip1337

That idea is even better too (I thought about it before seeing what Y_Less created), mainly because a lot of AMX code will be removed, while it will be kept only for the AMX functions and callbacks calling, with this method we will also be able to have some definitions like I said in the first post: STREAMER_USE_CPP and STREAMER_REMOVE_AMX_CALL, it would offer bigger flexibility. Hopefully functions/callbacks will make use of a call structure like Streamer::Natives::Object::Create, it will help navigation through IDE's suggestions, while being able to easily see a list with all the functions of objects, pickups and more. Also, it should make use of std::string and other containers as parameters where necessary (like the boost::unordered_set< int > arguments you gave in your example).

IstuntmanI avatar Aug 10 '17 20:08 IstuntmanI

I may start doing this. This is how I manually invoke Streamer functions right now (for example, in Streamer::Object::GetPos you see pointers because they are changed using sampGDK and they need addresses, but they will be passed by reference in the source of Streamer, of course) and it works perfectly with the Visual Studio Intellisense, giving me nice suggestions when trying to find a function for objects for example. We should use namespaces and functions names like these. I really need this now because I want to start debugging the issues with objects vanishing and I can't really do that without porting the plugin easily. @samp-incognito is this structure ok?:

namespace Streamer
{
	namespace Settings
	{
		int GetTickRate( );
		bool SetTickRate( int rate );
		int GetPlayerTickRate( int playerid );
		bool SetPlayerTickRate( int playerid, int rate );
		int GetChunkTickRate( int type, int playerid = -1 );
		bool SetChunkTickRate( int type, int rate, int playerid = -1 );
		int GetChunkSize( int type );
		bool SetChunkSize( int type, int size );
		int GetMaxItems( int type );
		bool SetMaxItems( int type, int items );
		int GetVisibleItems( int type, int playerid = -1 );
		bool SetVisibleItems( int type, int items, int playerid = -1 );
		bool GetRadiusMultiplier( int type, float * multiplier, int playerid = -1 );
		bool SetRadiusMultiplier( int type, float multiplier, int playerid = -1 );
		bool GetTypePriority( int types[ ], int maxtypes );
		bool SetTypePriority( const int types[ ], int maxtypes );
		bool GetCellDistance( float * distance );
		bool SetCellDistance( float distance );
		bool GetCellSize( float * size );
		bool SetCellSize( float size );
		bool ToggleItemStatic( int type, int id, bool toggle );
		bool IsToggleItemStatic( int type, int id );
		bool ToggleItemInvAreas( int type, int id, bool toggle );
		bool IsToggleItemInvAreas( int type, int id );
		bool ToggleItemCallbacks( int type, int id, bool toggle );
		bool IsToggleItemCallbacks( int type, int id );
		bool ToggleErrorCallback( bool toggle );
		bool IsToggleErrorCallback( );
	};

	namespace Updates
	{
		bool ProcessActiveItems( );
		bool ToggleIdleUpdate( int playerid, bool toggle );
		bool IsToggleIdleUpdate( int playerid );
		bool ToggleCameraUpdate( int playerid, bool toggle );
		bool IsToggleCameraUpdate( int playerid );
		bool ToggleItemUpdate( int playerid, int type, bool toggle );
		bool IsToggleItemUpdate( int playerid, int type );
		bool GetLastUpdateTime( float * time );
		bool Update( int playerid, int type = -1 );
		bool UpdateEx( int playerid, float x, float y, float z, int worldid = -1, int interiorid = -1, int type = -1, int compensatedtime = -1, bool freezeplayer = 1 );
	};

	namespace Data
	{
		bool GetFloatData( int type, int id, int data, float * result );
		bool SetFloatData( int type, int id, int data, float value );
		int GetIntData( int type, int id, int data );
		bool SetIntData( int type, int id, int data, int value );
		bool GetArrayData( int type, int id, int data, int dest[ ], int maxdest );
		bool SetArrayData( int type, int id, int data, const int src[ ], int maxsrc );
		bool IsInArrayData( int type, int id, int data, int value );
		bool AppendArrayData( int type, int id, int data, int value );
		bool RemoveArrayData( int type, int id, int data, int value );
		int GetUpperBound( int type );
	};

	namespace Miscellaneous
	{
		bool GetDistanceToItem( float x, float y, float z, int type, int id, float * distance, int dimensions = 3 );
		bool ToggleItem( int playerid, int type, int id, int toggle );
		bool IsToggleItem( int playerid, int type, int id );
		bool ToggleAllItems( int playerid, int type, int toggle, int exceptions[ ], int maxexceptions );
		int GetItemInternalID( int playerid, int type, int streamerid );
		int GetItemStreamerID( int playerid, int type, int internalid );
		bool IsItemVisible( int playerid, int type, int id );
		bool DestroyAllVisibleItems( int playerid, int type, int serverwide = 1 );
		int CountVisibleItems( int playerid, int type, int serverwide = 1 );
		bool DestroyAllItems( int type, int serverwide = 1 );
		int CountItems( int type, int serverwide = 1 );
		int GetNearbyItems( float x, float y, float z, int type, int items[ ], int maxitems, float range = 300.0 );
		int GetAllVisibleItems( int playerid, int type, int items[ ], int maxitems );
		bool GetItemOffset( int type, int id, float * x, float * y, float * z );
		bool SetItemOffset( int type, int id, float x, float y, float z );
	};

	namespace Object
	{
		int Create( int modelid, double x, double y, double z, double rx, double ry, double 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 );
		bool Destroy( int objectid );
		bool IsValid( int objectid );
		bool SetPos( int objectid, float x, float y, float z );
		bool GetPos( int objectid, float * x, float * y, float * z );
		bool SetRot( int objectid, float rx, float ry, float rz );
		bool GetRot( int objectid, float * rx, float * ry, float * rz );
		bool SetNoCameraCol( int objectid );
		bool GetNoCameraCol( int objectid );
		bool Move( int objectid, float x, float y, float z, float speed, float rx = -1000.0, float ry = -1000.0, float rz = -1000.0 );
		bool Stop( int objectid );
		bool IsMoving( int objectid );
		bool AttachCameraTo( int playerid, int objectid );
		bool AttachToObject( int objectid, int attachtoid, float offsetx, float offsety, float offsetz, float rx, float ry, float rz, int syncrotation = 1 );
		bool AttachToPlayer( int objectid, int playerid, float offsetx, float offsety, float offsetz, float rx, float ry, float rz );
		bool AttachToVehicle( int objectid, int vehicleid, float offsetx, float offsety, float offsetz, float rx, float ry, float rz );
		bool Edit( int playerid, int objectid );
		bool IsMaterialUsed( int objectid, int materialindex );
		bool GetMaterial( int objectid, int materialindex, int * modelid, char txdname[ ], char texturename[ ], int * materialcolor, int maxtxdname, int maxtexturename );
		bool SetMaterial( int objectid, int materialindex, int modelid, const char txdname[ ], const char texturename[ ], int materialcolor = 0 );
		bool IsMaterialTextUsed( int objectid, int materialindex );
		bool GetMaterialText( int objectid, int materialindex, char text[ ], int * materialsize, char fontface[ ], int * fontsize, int * bold, int * fontcolor, int * backcolor, int * textalignment, int maxtext, int maxfontface );
		bool SetMaterialText( int objectid, int materialindex, const char text[ ], int materialsize = OBJECT_MATERIAL_SIZE_256x128, const char fontface[ ] = "Arial", int fontsize = 24, int bold = 1, int fontcolor = 0xFFFFFFFF, int backcolor = 0, int textalignment = 0 );
	};

	namespace Pickup
	{
		int Create( int modelid, int type, float x, float y, float z, int worldid = -1, int interiorid = -1, int playerid = -1, float streamdistance = STREAMER_PICKUP_SD, int areaid = -1, int priority = 0 );
		bool Destroy( int pickupid );
		bool IsValid( int pickupid );
	};

	namespace CP
	{
		int Create( float x, float y, float z, float size, int worldid = -1, int interiorid = -1, int playerid = -1, float streamdistance = STREAMER_CP_SD, int areaid = -1, int priority = 0 );
		bool Destroy( int checkpointid );
		bool IsValid( int checkpointid );
		bool IsPlayerIn( int playerid, int checkpointid );
		int GetPlayerVisible( int playerid );
	};

	namespace RaceCP
	{
		int Create( int type, float x, float y, float z, float nextx, float nexty, float nextz, float size, int worldid = -1, int interiorid = -1, int playerid = -1, float streamdistance = STREAMER_RACE_CP_SD, int areaid = -1, int priority = 0 );
		bool Destroy( int checkpointid );
		bool IsValid( int checkpointid );
		bool IsPlayerIn( int playerid, int checkpointid );
		int IsPlayerIn( int playerid );
	};

	namespace MapIcon
	{
		int Create( float x, float y, float z, int type, int color, int worldid = -1, int interiorid = -1, int playerid = -1, float streamdistance = STREAMER_MAP_ICON_SD, int style = MAPICON_LOCAL, int areaid = -1, int priority = 0 );
		int CreateEx( float x, float y, float z, int type, int color, int style, float streamdistance, const int worlds[], const int interiors[], const int players[], const int areas[], int priority, int maxworlds, int maxinteriors, int maxplayers, int maxareas );
		bool Destroy( int iconid );
		bool IsValid( int iconid );
	};

	namespace TextLabel
	{
		int Create( const char text[], int color, float x, float y, float z, float drawdistance, int attachedplayer = INVALID_PLAYER_ID, int attachedvehicle = INVALID_VEHICLE_ID, bool testlos = 0, int worldid = -1, int interiorid = -1, int playerid = -1, float streamdistance = STREAMER_3D_TEXT_LABEL_SD, int areaid = -1, int priority = 0 );
		bool Destroy( int id );
		bool IsValid( int id );
		bool GetText( int id, char text[ ], int maxtext );
		bool UpdateText( int id, int color, const char text[ ] );
	};

	namespace Area
	{
		int CreateCircle( float x, float y, float size, int worldid = -1, int interiorid = -1, int playerid = -1, int priority = 0 );
		int CreateCylinder( float x, float y, float minz, float maxz, float size, int worldid = -1, int interiorid = -1, int playerid = -1, int priority = 0 );
		int CreateSphere( float x, float y, float z, float size, int worldid = -1, int interiorid = -1, int playerid = -1, int priority = 0 );
		int CreateRectangle( float minx, float miny, float maxx, float maxy, int worldid = -1, int interiorid = -1, int playerid = -1, int priority = 0 );
		int CreateCuboid( float minx, float miny, float minz, float maxx, float maxy, float maxz, int worldid = -1, int interiorid = -1, int playerid = -1, int priority = 0 );
		int CreateCube( float minx, float miny, float minz, float maxx, float maxy, float maxz, int worldid = -1, int interiorid = -1, int playerid = -1, int priority = 0 );
		int CreatePolygon( const float points[ ], float minz, float maxz, int maxpoints, int worldid = -1, int interiorid = -1, int playerid = -1, int priority = 0 );
		bool Destroy( int areaid );
		bool IsValid( int areaid );
		int GetDynamicPolygonPoints( int areaid, float points[ ], int maxpoints );
		int GetDynamicPolygonNumberPoints( int areaid );
		bool IsPlayerIn( int playerid, int areaid, bool recheck = 0 );
		bool IsPlayerInAny( int playerid, bool recheck = 0 );
		bool IsAnyPlayerIn( int areaid, bool recheck = 0 );
		bool IsAnyPlayerInAny( bool recheck = 0 );
		int GetPlayerDynamicAreas( int playerid, int areas[ ], int maxareas );
		int GetPlayerNumber( int playerid );
		bool IsPointIn( int areaid, float x, float y, float z );
		bool IsPointInAny( float x, float y, float z );
		bool IsLineIn( int areaid, float x1, float y1, float z1, float x2, float y2, float z2 );
		bool IsLineInAny( float x1, float y1, float z1, float x2, float y2, float z2 );
		int GetDynamicAreasForPoint( float x, float y, float z, int areas[ ], int maxareas );
		int GetNumberDynamicAreasForPoint( float x, float y, float z );
		int GetDynamicAreasForLine( float x1, float y1, float z1, float x2, float y2, float z2, int areas[ ], int maxareas );
		int GetNumberForLine( float x1, float y1, float z1, float x2, float y2, float z2 );
		bool AttachToObject( int areaid, int objectid, int type = STREAMER_OBJECT_TYPE_DYNAMIC, int playerid = INVALID_PLAYER_ID, float offsetx = 0.0, float offsety = 0.0, float offsetz = 0.0 );
		bool AttachToPlayer( int areaid, int playerid, float offsetx = 0.0, float offsety = 0.0, float offsetz = 0.0 );
		bool AttachToVehicle( int areaid, int vehicleid, float offsetx = 0.0, float offsety = 0.0, float offsetz = 0.0 );
		bool ToggleSpectateMode( int areaid, bool toggle );
		bool IsToggleSpectateMode( int areaid );
	};

	namespace Actor
	{
		int Create( int modelid, float x, float y, float z, float r, bool invulnerable = 1, float health = 100.0, int worldid = -1, int interiorid = -1, int playerid = -1, float streamdistance = STREAMER_ACTOR_SD, int areaid = -1, int priority = 0 );
		bool Destroy( int actorid );
		bool IsValid( int actorid );
		bool IsStreamedIn( int actorid, int forplayerid );
		int GetVirtualWorld( int actorid );
		bool SetVirtualWorld( int actorid, int vworld );
		bool ApplyAnimation( int actorid, const char animlib[ ], const char animname[ ], float fdelta, bool loop, int lockx, int locky, int freeze, int time );
		bool ClearAnimations( int actorid );
		bool GetFacingAngle( int actorid, float * ang );
		bool SetFacingAngle( int actorid, float ang );
		bool GetPos( int actorid, float * x, float * y, float * z );
		bool SetPos( int actorid, float x, float y, float z );
		bool GetHealth( int actorid, float * health );
		bool SetHealth( int actorid, float health );
		bool SetInvulnerable( int actorid, bool invulnerable = 1 );
		bool IsInvulnerable( int actorid );
		int GetPlayerTarget( int playerid );
		int GetPlayerCameraTarget( int playerid );
	};
};

bool OnDynamicObjectMoved( int objectid );
bool OnPlayerEditDynamicObject( int playerid, int objectid, int response, float x, float y, float z, float rx, float ry, float rz );
bool OnPlayerSelectDynamicObject( int playerid, int objectid, int modelid, float x, float y, float z );
bool OnPlayerShootDynamicObject( int playerid, int weaponid, int objectid, float x, float y, float z );
bool OnPlayerPickUpDynamicPickup( int playerid, int pickupid );
bool OnPlayerEnterDynamicCP( int playerid, int checkpointid );
bool OnPlayerLeaveDynamicCP( int playerid, int checkpointid );
bool OnPlayerEnterDynamicRaceCP( int playerid, int checkpointid );
bool OnPlayerLeaveDynamicRaceCP( int playerid, int checkpointid );
bool OnPlayerEnterDynamicArea( int playerid, int areaid );
bool OnPlayerLeaveDynamicArea( int playerid, int areaid );
bool OnPlayerGiveDamageDynamicActor( int playerid, int actorid, float amount, int weaponid, int bodypart );
bool OnDynamicActorStreamIn( int actorid, int forplayerid );
bool OnDynamicActorStreamOut( int actorid, int forplayerid );
bool Streamer_OnItemStreamIn( int type, int id );
bool Streamer_OnItemStreamOut( int type, int id );
bool Streamer_OnPluginError( char error[ ] );

IstuntmanI avatar Nov 10 '17 15:11 IstuntmanI

That looks fine.

samp-incognito avatar Nov 11 '17 00:11 samp-incognito

Great.


By the way, for anyone who wants to run Streamer Plugin for now with their sampGDK gamemode, without having to manually edit the Streamer source to call any function/callback or write all the functions invoking, this is what I'm currently using in my gamemode: https://github.com/IstuntmanI/streamer-plugin-sampgdk-invoke . I will update this repository when new functions will be added, probably until this issue will be solved (because you shouldn't keep using invoke if you can simply copy-paste the Streamer Plugin source and compile it).

IstuntmanI avatar Nov 19 '17 21:11 IstuntmanI

I thought again about the possibility to do this. It would take a lot to solve this and I'm kinda busy (also, now I'll need to make sure that CMake would be fine with any new file, compiling just got harder with the latest commits - I dislike CMake). Instead, the repository I linked to looks stable (I fix any discovered bug ASAP - for now there's no discovered bug in it, I use the Streamer Plugin with that invoking code a lot in my server and everything works flawless).

I think that the code in that repository is now even better than directly implementing the Streamer Plugin in our own plugins. It is keeping the regular way of loading the Streamer Plugin (even easier to upgrade the Streamer Plugin, compared to copy-pasting in our server plugin's source and recompiling everything), while also being able to easily invoke the functions. The compiling time of our plugins won't increase because the Streamer Plugin source isn't implemented. I can't see downsides for now.

For now I have no need anymore to directly implement the Streamer Plugin in my gamemode plugin. I think that for now you should link users that want to use the Streamer Plugin within a sampGDK plugin to that repository (maybe somewhere in the wiki ?).

IstuntmanI avatar Feb 03 '18 17:02 IstuntmanI

I can add it to the wiki.

samp-incognito avatar Feb 04 '18 00:02 samp-incognito