//----------------------------------------------------------

//

//   xStreamer - By Boylett

//

//----------------------------------------------------------



//#define LINUX 1

//#define DEBUG 1



#include <iostream>

#include <new>

#include <memory>

#include <math.h>



#ifdef LINUX



#include <sys/time.h>

#include <time.h>



#else



#include <Windows.h>

#include <Winbase.h>



#endif



#include "../SDK/amx/amx.h"

#include "../SDK/plugincommon.h"



using namespace std;



#define MAX_PLAYERS 200

#define MAX_OBJECTS 150



#ifdef DEBUG



#define debug(a,b) logprintf("%d: %s",a,b);



#else



#define debug(a,b)



#endif



//----------------------------------------------------------



typedef void (*logprintf_t)(char* format, ...);



logprintf_t logprintf;

void **ppPluginData;

extern void *pAMXFunctions;



//----------------------------------------------------------



#define MIN_AREA -4000.0 // map is -3000, but allow for maps over the sea

#define MAX_AREA 4000.0

#define AREA_SIZE 100.0 // This means only objects within a 300.0 by 300.0 square around the player are checked.



#define TOTAL_SIZE (MAX_AREA - MIN_AREA)

#define AREA_SPLIT (TOTAL_SIZE / AREA_SIZE)



//----------------------------------------------------------



struct object_layout

{

	int objid;

	int modelid;

	float x;

	float y;

	float z;

	float rx;

	float ry;

	float rz;

	bool moving;

	float speed;

	float mx;

	float my;

	float mz;

	int moving_start;

	int vw;

	int interior;

	object_layout * prevobj;

	object_layout * nextobj;

	AMX * amx;

};



object_layout * objects;



struct playerobj_list

{

	object_layout * objectid;

	float dist;

	int sampid;

};



playerobj_list player_objects[MAX_PLAYERS][MAX_OBJECTS];



struct area_layout

{

	object_layout * object;

	area_layout * prevobj;

	area_layout * nextobj;

};



area_layout * areas[(int)AREA_SPLIT][(int)AREA_SPLIT];



int fs_loaded = 0;

AMX * fs_amx;



//----------------------------------------------------------



PLUGIN_EXPORT unsigned int PLUGIN_CALL Supports() 

{

	return SUPPORTS_VERSION | SUPPORTS_AMX_NATIVES;

}



//----------------------------------------------------------



PLUGIN_EXPORT bool PLUGIN_CALL Load(void **ppData) 

{

	pAMXFunctions = ppData[PLUGIN_DATA_AMX_EXPORTS];

	logprintf = (logprintf_t)ppData[PLUGIN_DATA_LOGPRINTF];



	logprintf("xStreamer plugin loaded");

	return true;

}



//----------------------------------------------------------



PLUGIN_EXPORT void PLUGIN_CALL Unload()

{

	logprintf("xStreamer plugin unloaded");

}



//----------------------------------------------------------



#ifdef LINUX



int TickCount()

{

    long ticks, usec, sec;

    struct timeval tempo;

    gettimeofday(&tempo, NULL);

    usec = tempo.tv_usec;

    sec = tempo.tv_sec;

    ticks = (1000 * sec) + (usec / 1000);

	return (int)ticks;

}



#else



int TickCount()

{

	return (int)GetTickCount();

}



#endif



float GetPointDistanceToPointSquared(float x,float y,float z,float x2,float y2,float z2)

{

	return pow(x - x2,2) + pow(y - y2,2) + pow(z - z2,2);

}



int GetPlayerObjectID(int playerid,object_layout * objectid)

{

	for(int i = 0; i < MAX_OBJECTS; i++)

	{

		if(player_objects[playerid][i].objectid == objectid)

		{

			return i;

		}

	}

	return -1;

}



int GetFurtherstPlayerObject(int playerid, float * dist)

{

	int furtherst = -1;

	*dist = -1.0;

	for(int i = 0; i < MAX_OBJECTS; i++)

	{

		if(player_objects[playerid][i].objectid == 0)

		{

			*dist = 1000000000.0;

			return i;

		}

		else if(player_objects[playerid][i].dist > *dist)

		{

			*dist = player_objects[playerid][i].dist;

			furtherst = i;

		}

	}

	return furtherst;

}



int sampDestroyPlayerObject(int playerid,int objectid)

{

	if(objectid == -1) return 0;

	if(fs_amx == 0) return 0;

	int idx;

	if(!amx_FindPublic(fs_amx, "sampDestroyPlayerObject", &idx))

	{

		cell ret;

		amx_Push(fs_amx, objectid);

		amx_Push(fs_amx, playerid);

		amx_Exec(fs_amx, &ret, idx);

		return (int)ret;

	}

	return 0;

}



int sampCreatePlayerObject(int playerid,int modelid,float x,float y,float z,float rx,float ry,float rz)

{

	if(fs_amx == 0) return -1;

	int idx;

	if(!amx_FindPublic(fs_amx, "sampCreatePlayerObject", &idx))

	{

		cell ret;

		amx_Push(fs_amx, amx_ftoc(rz));

		amx_Push(fs_amx, amx_ftoc(ry));

		amx_Push(fs_amx, amx_ftoc(rx));

		amx_Push(fs_amx, amx_ftoc(z));

		amx_Push(fs_amx, amx_ftoc(y));

		amx_Push(fs_amx, amx_ftoc(x));

		amx_Push(fs_amx, modelid);

		amx_Push(fs_amx, playerid);

		amx_Exec(fs_amx, &ret, idx);

		return (int)ret;

	}

	return -1;

}



int sampMovePlayerObject(int playerid,int objectid,float x,float y,float z,float speed)

{

	if(fs_amx == 0) return 0;

	int idx;

	if(!amx_FindPublic(fs_amx, "sampMovePlayerObject", &idx))

	{

		cell ret;

		amx_Push(fs_amx, amx_ftoc(speed));

		amx_Push(fs_amx, amx_ftoc(z));

		amx_Push(fs_amx, amx_ftoc(y));

		amx_Push(fs_amx, amx_ftoc(x));

		amx_Push(fs_amx, objectid);

		amx_Push(fs_amx, playerid);

		amx_Exec(fs_amx, &ret, idx);

		return (int)ret;

	}

	return 0;

}



int sampOnStreamedObjectMoved(AMX * amx, int objectid)

{

	int idx;

	if(!amx_FindPublic(amx, "OnStreamedObjectMoved", &idx))

	{

		cell ret;

		amx_Push(amx, objectid);

		amx_Exec(amx, &ret, idx);

		return (int)ret;

	}

	return 0;

}



int sampStopPlayerObject(int playerid,int objectid)

{

	if(fs_amx == 0) return 0;

	int idx;

	if(!amx_FindPublic(fs_amx, "sampStopPlayerObject", &idx))

	{

		cell ret;

		amx_Push(fs_amx, objectid);

		amx_Push(fs_amx, playerid);

		amx_Exec(fs_amx, &ret, idx);

		return (int)ret;

	}

	return 0;

}



int GetAreaID(float position)

{

	int id = (int)((position - MIN_AREA) / AREA_SIZE);

	if(id < 0) id = -1;

	else if(id >= AREA_SPLIT) id = -1;

	return id;

}



void AddToArea(int x,int y,object_layout * object)

{

	if(areas[x][y] == 0)

	{

		areas[x][y] = new area_layout;

		(*areas[x][y]).object = object;

		(*areas[x][y]).prevobj = 0;

		(*areas[x][y]).nextobj = 0;

	}

	else

	{

		area_layout * oldarea;

		oldarea = areas[x][y];

		areas[x][y] = new area_layout;

		(*areas[x][y]).object = object;

		(*areas[x][y]).prevobj = oldarea;

		(*oldarea).nextobj = areas[x][y];

		(*areas[x][y]).nextobj = 0; // dimonml

	}

}



void RemFromArea(int x,int y,object_layout * object)

{

	area_layout * curarea;

	curarea = areas[x][y];



	while(curarea != 0)

	{

		if((*curarea).object == object)

		{

			if((*curarea).nextobj != 0)

			{

				(*(*curarea).nextobj).prevobj = (*curarea).prevobj;

			}



			if((*curarea).prevobj != 0)

			{

				(*(*curarea).prevobj).nextobj = (*curarea).nextobj;

			}



			if(curarea == areas[x][y])

			{

				if((*curarea).prevobj != 0)

				{

					areas[x][y] = (*curarea).prevobj;

				}

				else

				{

					areas[x][y] = 0;

				}

			}



			delete curarea;;

			break;

		}

		else

		{

			curarea = (*curarea).prevobj;

		}

	}

}



void GetMovementXYZ(object_layout * objectid)

{

	if((*(objectid)).moving)

	{

		int time = TickCount() - (*(objectid)).moving_start;

		float utime = ((float)time) / 1000.0;

		float dist = sqrt(GetPointDistanceToPointSquared(

			(*(objectid)).x,

			(*(objectid)).y,

			(*(objectid)).z,

			(*(objectid)).mx,

			(*(objectid)).my,

			(*(objectid)).mz

		));

		float donedist = (*(objectid)).speed * utime;

		int oldx = GetAreaID((*(objectid)).x);

		int oldy = GetAreaID((*(objectid)).y);

		if(donedist >= dist)

		{

			(*(objectid)).moving = false;

			(*(objectid)).x = (*(objectid)).mx;

			(*(objectid)).y = (*(objectid)).my;

			(*(objectid)).z = (*(objectid)).mz;

			sampOnStreamedObjectMoved((*(objectid)).amx,(*(objectid)).objid);

		}

		else

		{

			float frdone = (donedist / dist);

			(*(objectid)).x += ((*(objectid)).mx - (*(objectid)).x) * frdone;

			(*(objectid)).y += ((*(objectid)).my - (*(objectid)).y) * frdone;

			(*(objectid)).z += ((*(objectid)).mz - (*(objectid)).z) * frdone;

			(*(objectid)).moving_start = TickCount();

		}

		int newx = GetAreaID((*(objectid)).x);

		int newy = GetAreaID((*(objectid)).y);

		if(newx != oldx || newy != oldy)

		{

			if(oldx != -1 && oldy != -1)

			{

				RemFromArea(oldx,oldy,objectid);

			}

			if(newx != -1 && newy != -1)

			{

				AddToArea(newx,newy,objectid);

			}

		}

	}

}



//----------------------------------------------------------

// native ConnectPlayer(playerid);



static cell AMX_NATIVE_CALL n_ConnectPlayer( AMX* amx, cell* params ) // These are only called by the filterscript, so no fs_loaded check is needed

{

	if(params[0] != 4)

	{

		logprintf("ConnectPlayer: Expecting 1 param, but found %d",params[0] / 4);

		return 0;

	}



	int playerid = params[1];



	for(int i = 0; i < MAX_OBJECTS; i++)

	{

		player_objects[playerid][i].objectid = 0;

	}



	return 1;

}



//----------------------------------------------------------

// native DisconnectPlayer(playerid);



static cell AMX_NATIVE_CALL n_DisconnectPlayer( AMX* amx, cell* params )

{

	if(params[0] != 4)

	{

		logprintf("DisconnectPlayer: Expecting 1 param, but found %d",params[0] / 4);

		return 0;

	}



	int playerid = params[1];



	for(int i = 0; i < MAX_OBJECTS; i++)

	{

		player_objects[playerid][i].objectid = 0;

	}



	return 1;

}



//----------------------------------------------------------

// native UpdateMovingObjects();



static cell AMX_NATIVE_CALL n_UpdateMovingObjects( AMX* amx, cell* params )

{

	if(fs_loaded != 1)

	{

		if(fs_loaded != -1)

		{

			logprintf("xStreamer error: xStreamer.amx filterscript not loaded!");

			fs_loaded = -1;

		}

	}



	object_layout * curobj = objects;

	while(curobj != 0)

	{

		GetMovementXYZ(curobj);

		curobj = (*curobj).prevobj;

	}



	return 1;

}



//----------------------------------------------------------

// native StreamObjects(playerid,Float:x,Float:y,Float:z,virtualworld,interior);



static cell AMX_NATIVE_CALL n_StreamObjects( AMX* amx, cell* params )

{

	if(fs_loaded != 1)

	{

		if(fs_loaded != -1)

		{

			logprintf("xStreamer error: xStreamer.amx filterscript not loaded!");

			fs_loaded = -1;

		}

		return 0; // this function won't work without the filterscript...

	}



	if(params[0] != 24)

	{

		logprintf("StreamObjects: Expecting 6 params, but found %d",params[0] / 4);

		return 0;

	}



	debug(0,"-- StreamObjects")



	int playerid = params[1];

	float

		x = amx_ctof(params[2]),

		y = amx_ctof(params[3]),

		z = amx_ctof(params[4]);

	int vw = params[5];

	int interior = params[6];

	int farobj = 0;

	float fardist = -1.0;

	bool objchanged[MAX_OBJECTS];

	int startx = GetAreaID(x) - 1;

	int endx = startx + 3;

	int starty = GetAreaID(y) - 1;

	int endy = starty + 3;



	debug(0,"Defined variables")



	if(startx < 0) startx = 0;

	if(starty < 0) starty = 0;

	if(startx >= AREA_SPLIT) startx = AREA_SPLIT - 1;

	if(starty >= AREA_SPLIT) starty = AREA_SPLIT - 1;

	if(endx < 0) endx = 0;

	if(endy < 0) endy = 0;

	if(endx > AREA_SPLIT) endx = AREA_SPLIT;

	if(endy > AREA_SPLIT) endy = AREA_SPLIT;



	debug(0,"Set up area")



	for(int i = 0; i < MAX_OBJECTS; i++)

	{

		objchanged[i] = false;

		debug(0,"Loop 1")

		if(player_objects[playerid][i].objectid != 0)

		{

			debug(0,"Got object")

			if((*(player_objects[playerid][i].objectid)).vw != vw || (*(player_objects[playerid][i].objectid)).interior != interior)

			{

				debug(0,"Not in same int/vw")

				sampDestroyPlayerObject(playerid,player_objects[playerid][i].sampid);

				debug(0,"Destroyed")

				player_objects[playerid][i].objectid = 0;

				debug(0,"Zeroed")

				farobj = i;

				fardist = 1000000000.0;

			}

			else

			{

				debug(0,"In same int/vw")

				player_objects[playerid][i].dist = GetPointDistanceToPointSquared(x,y,z,

						(*(player_objects[playerid][i].objectid)).x,

						(*(player_objects[playerid][i].objectid)).y,

						(*(player_objects[playerid][i].objectid)).z

					);

				debug(0,"Distance")

				if(player_objects[playerid][i].dist > fardist)

				{

					debug(0,"Far distance")

					farobj = i;

					fardist = player_objects[playerid][i].dist;

				}

				debug(0,"Done distance")

			}

		}

		else

		{

			debug(0,"Set far")

			farobj = i;

			fardist = 1000000000.0;

		}

	}



	debug(0,"Done loop 1")



	for(int ix = startx; ix < endx; ix++)

	{

		for(int iy = starty; iy < endy; iy++)

		{

			debug(0,"Loop 2")

			area_layout * curareaobj = areas[ix][iy];

			debug(0,"Area")

			while(curareaobj != 0)

			{

				debug(0,"Exists")

				int playerobj = GetPlayerObjectID(playerid,(*curareaobj).object);

				debug(0,"Player objects")

				if(playerobj == -1)

				{

					debug(0,"Is -1")

					if((*(*curareaobj).object).vw == vw && (*(*curareaobj).object).interior == interior)

					{

						debug(0,"Distance check 2")

						float dist = GetPointDistanceToPointSquared(x,y,z,

							(*(*curareaobj).object).x,

							(*(*curareaobj).object).y,

							(*(*curareaobj).object).z

						);

						debug(0,"Done distance check 2")

						if(dist < fardist)

						{

							debug(0,"Smaller than far distance")

							if(player_objects[playerid][farobj].objectid != 0 && !objchanged[farobj])

							{

								debug(0,"Destroy 2")

								sampDestroyPlayerObject(playerid,player_objects[playerid][farobj].sampid);

							}

							debug(0,"Destroyed 2")

							player_objects[playerid][farobj].dist = dist;

							debug(0,"Dist 2")

							player_objects[playerid][farobj].objectid = (*curareaobj).object;

							debug(0,"object 2")

							objchanged[farobj] = true;

							farobj = GetFurtherstPlayerObject(playerid,&fardist);

							debug(0,"Far distance 2")

						}

					}

				}

				debug(0,"Next object 2")

				curareaobj = (*curareaobj).prevobj;

				debug(0,"Next object done 2")

			}

		}

	}

	

	debug(0,"Loop 2 done")



	for(int i = 0; i < MAX_OBJECTS; i++)

	{

		debug(0,"Loop 3")

		if(objchanged[i])

		{

			debug(0,"Changed")

			player_objects[playerid][i].sampid = sampCreatePlayerObject(playerid,

					(*(player_objects[playerid][i].objectid)).modelid,

					(*(player_objects[playerid][i].objectid)).x,

					(*(player_objects[playerid][i].objectid)).y,

					(*(player_objects[playerid][i].objectid)).z,

					(*(player_objects[playerid][i].objectid)).rx,

					(*(player_objects[playerid][i].objectid)).ry,

					(*(player_objects[playerid][i].objectid)).rz						

				);

			debug(0,"Created")

			if((*(player_objects[playerid][i].objectid)).moving)

			{

				debug(0,"Moving")

				sampMovePlayerObject(playerid,player_objects[playerid][i].sampid,

					(*(player_objects[playerid][i].objectid)).mx,

					(*(player_objects[playerid][i].objectid)).my,

					(*(player_objects[playerid][i].objectid)).mz,

					(*(player_objects[playerid][i].objectid)).speed

				);

				debug(0,"Moved")

			}

		}

	}



	debug(0,"Return")



	return 1;

}



//----------------------------------------------------------

// native CreateStreamedObject(modelid,Float:x,Float:y,Float:z,Float:rx,Float:ry,Float:rz,virtualworld = 0,interior = 0);



static cell AMX_NATIVE_CALL n_CreateStreamedObject( AMX* amx, cell* params )

{

	if(fs_loaded != 1)

	{

		if(fs_loaded != -1)

		{

			logprintf("xStreamer error: xStreamer filterscript not loaded!");

			fs_loaded = -1;

		}

	}



	if(params[0] != 36)

	{

		logprintf("CreateStreamedObject: Expecting 9 params, but found %d",params[0] / 4);

		return -1;

	}



	object_layout newobj;



	newobj.modelid = params[1];

	newobj.x = amx_ctof(params[2]),

	newobj.y = amx_ctof(params[3]),

	newobj.z = amx_ctof(params[4]);

	newobj.rx = amx_ctof(params[5]),

	newobj.ry = amx_ctof(params[6]),

	newobj.rz = amx_ctof(params[7]);

	newobj.vw = params[8];

	newobj.interior = params[9];

	newobj.prevobj = 0;

	newobj.nextobj = 0;

	newobj.moving = false;

	newobj.amx = amx;



	int xid = GetAreaID(newobj.x);

	int yid = GetAreaID(newobj.y);



	if(xid == -1 || yid == -1)

	{

		return -1;

	}



	if(objects == 0)

	{

		newobj.objid = 0;

		objects = new object_layout;

		*objects = newobj;

	}

	else

	{

		object_layout * oldobj;

		oldobj = objects;

		objects = new object_layout;

		newobj.objid = (*oldobj).objid + 1;

		*objects = newobj;

		(*objects).prevobj = oldobj;

		(*oldobj).nextobj = objects;

	}



	AddToArea(xid,yid,objects);



	return newobj.objid;

}



//----------------------------------------------------------

// native DestroyStreamedObject(objectid);



static cell AMX_NATIVE_CALL n_DestroyStreamedObject( AMX* amx, cell* params )

{

	if(fs_loaded != 1)

	{

		if(fs_loaded != -1)

		{

			logprintf("xStreamer error: xStreamer filterscript not loaded!");

			fs_loaded = -1;

		}

	}



	if(params[0] != 4)

	{

		logprintf("DestroyStreamedObject: Expecting 1 param, but found %d",params[0] / 4);

		return 0;

	}



	int objectid = params[1];



	if(objectid == -1)

	{

		return 0;

	}



	object_layout * curobj = objects;



	while(curobj != 0)

	{

		if((*curobj).objid == objectid)

		{

			if((*curobj).nextobj != 0)

			{

				(*(*curobj).nextobj).prevobj = (*curobj).prevobj;

			}



			if((*curobj).prevobj != 0)

			{

				(*(*curobj).prevobj).nextobj = (*curobj).nextobj;

			}



			if(objects == curobj)

			{

				if((*curobj).prevobj != 0)

				{

					objects = (*curobj).prevobj;

				}

				else

				{

					objects = 0;

				}

			}



			for(int playerid = 0; playerid < MAX_PLAYERS; playerid++)

			{

				for(int i = 0; i < MAX_OBJECTS; i++)

				{

					if(player_objects[playerid][i].objectid == curobj)

					{

						sampDestroyPlayerObject(playerid,player_objects[playerid][i].sampid);

						player_objects[playerid][i].objectid = 0;

					}

				}

			}



			int xid = GetAreaID((*curobj).x);

			int yid = GetAreaID((*curobj).y);

			if(xid != -1 && yid != -1)

			{

				RemFromArea(xid,yid,curobj);

			}



			delete curobj;



			return 1;

		}

		else

		{

			curobj = (*curobj).prevobj;

		}

	}



	return 0;

}



//----------------------------------------------------------

// native MoveStreamedObject(objectid,float x,float y,float z,float speed);



static cell AMX_NATIVE_CALL n_MoveStreamedObject( AMX* amx, cell* params )

{

	if(fs_loaded != 1)

	{

		if(fs_loaded != -1)

		{

			logprintf("xStreamer error: xStreamer filterscript not loaded!");

			fs_loaded = -1;

		}

	}



	if(params[0] != 20)

	{

		logprintf("MoveStreamedObject: Expecting 5 params, but found %d",params[0] / 4);

		return 0;

	}



	int objectid = params[1];



	if(objectid == -1)

	{

		return 0;

	}



	object_layout * curobj = objects;



	while(curobj != 0)

	{

		if((*curobj).objid == objectid)

		{

			GetMovementXYZ(curobj);

			(*(curobj)).mx = amx_ctof(params[2]);

			(*(curobj)).my = amx_ctof(params[3]);

			(*(curobj)).mz = amx_ctof(params[4]);

			(*(curobj)).speed = amx_ctof(params[5]);

			(*(curobj)).moving_start = TickCount();

			(*(curobj)).moving = true;



			for(int playerid = 0; playerid < MAX_PLAYERS; playerid++)

			{

				for(int i = 0; i < MAX_OBJECTS; i++)

				{

					if(player_objects[playerid][i].objectid == curobj)

					{

						sampMovePlayerObject(playerid,

							player_objects[playerid][i].sampid,

							(*curobj).mx,

							(*curobj).my,

							(*curobj).mz,

							(*curobj).speed

						);

						break;

					}

				}

			}



			return 1;

		}

		else

		{

			curobj = (*curobj).prevobj;

		}

	}

	return 0;

}



//----------------------------------------------------------

// native StopStreamedObject(objectid);



static cell AMX_NATIVE_CALL n_StopStreamedObject( AMX* amx, cell* params )

{

	if(fs_loaded != 1)

	{

		if(fs_loaded != -1)

		{

			logprintf("xStreamer error: xStreamer filterscript not loaded!");

			fs_loaded = -1;

		}

	}



	if(params[0] != 4)

	{

		logprintf("StopStreamedObject: Expecting 1 param, but found %d",params[0] / 4);

		return 0;

	}



	int objectid = params[1];



	if(objectid == -1)

	{

		return 0;

	}



	object_layout * curobj = objects;



	while(curobj != 0)

	{

		if((*curobj).objid == objectid)

		{



			if(!(*(curobj)).moving) return 0;

			GetMovementXYZ(curobj);

			(*(curobj)).moving = false;



			for(int playerid = 0; playerid < MAX_PLAYERS; playerid++)

			{

				for(int i = 0; i < MAX_OBJECTS; i++)

				{

					if(player_objects[playerid][i].objectid == curobj)

					{

						sampStopPlayerObject(playerid,

							player_objects[playerid][i].sampid

						);

						break;

					}

				}

			}



			return 1;

		}

		curobj = (*curobj).prevobj;

	}



	return 0;

}



//----------------------------------------------------------

// native DestroyObjectsCreatedByMe();



static cell AMX_NATIVE_CALL n_DestroyObjectsCreatedByMe( AMX* amx, cell* params )

{

	if(fs_loaded != 1)

	{

		if(fs_loaded != -1)

		{

			logprintf("xStreamer error: xStreamer filterscript not loaded!");

			fs_loaded = -1;

		}

	}



	object_layout * curobj = objects;



	while(curobj != 0)

	{

		if((*curobj).amx == amx)

		{

			if((*curobj).nextobj != 0)

			{

				(*(*curobj).nextobj).prevobj = (*curobj).prevobj;

			}



			if((*curobj).prevobj != 0)

			{

				(*(*curobj).prevobj).nextobj = (*curobj).nextobj;

			}

			if(objects == curobj)

			{

				if((*curobj).prevobj != 0)

				{

					objects = (*curobj).prevobj;

				}

				else

				{

					objects = 0;

				}

			}



			for(int playerid = 0; playerid < MAX_PLAYERS; playerid++)

			{

				for(int i = 0; i < MAX_OBJECTS; i++)

				{

					if(player_objects[playerid][i].objectid == curobj)

					{

						sampDestroyPlayerObject(playerid,player_objects[playerid][i].sampid);

						player_objects[playerid][i].objectid = 0;

						break;

					}

				}

			}



			int xid = GetAreaID((*curobj).x);

			int yid = GetAreaID((*curobj).y);

			if(xid != -1 && yid != -1)

			{

				RemFromArea(xid,yid,curobj);

			}



			object_layout * tempobj = curobj;

			curobj = (*curobj).prevobj;

			delete tempobj;

		}

		else

		{

			curobj = (*curobj).prevobj;

		}

	}



	return 1;

}



//----------------------------------------------------------

// native xStreamer_Filterscript();



static cell AMX_NATIVE_CALL n_xStreamer_Filterscript( AMX* amx, cell* params )

{

	fs_amx = amx;

	fs_loaded = 1;

	logprintf("xStreamer: xStreamer filterscript has been detected");

	return 1;

}



//----------------------------------------------------------



AMX_NATIVE_INFO Natives[ ] =

{

	{ "ConnectPlayer",					n_ConnectPlayer },

	{ "DisconnectPlayer",				n_DisconnectPlayer },

	{ "StreamObjects",					n_StreamObjects },

	{ "CreateStreamedObject",			n_CreateStreamedObject },

	{ "DestroyStreamedObject",			n_DestroyStreamedObject },

	{ "MoveStreamedObject",				n_MoveStreamedObject },

	{ "StopStreamedObject",				n_StopStreamedObject },

	{ "DestroyObjectsCreatedByMe",		n_DestroyObjectsCreatedByMe },

	{ "xStreamer_Filterscript",			n_xStreamer_Filterscript },

	{ "UpdateMovingObjects",			n_UpdateMovingObjects },

	{ 0,0 }

};



//----------------------------------------------------------



PLUGIN_EXPORT int PLUGIN_CALL AmxLoad( AMX *amx ) 

{

	return amx_Register( amx, Natives, -1 );

}



//----------------------------------------------------------



PLUGIN_EXPORT int PLUGIN_CALL AmxUnload( AMX *amx ) 

{

	if(amx == fs_amx)

	{

		logprintf("xStreamer: xStreamer filterscript has just unloaded! The streamer won't work until you reload it");

		fs_amx = 0;

		fs_loaded = -1;

	}

	return AMX_ERR_NONE;

}

