Pottus / ColAndreas

Collision Plugin For San Andreas Multiplayer

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Using CA_RemoveBuilding after plugin initiation

NexiusTailer opened this issue Β· comments

Hello. Currently I really lack the ability to remove some collisions after the server and plugin starts.

Are you saving the objects or not? Last parameter of the CreateObject function has an option to save the id of the collision for removal.

Yes, I do it and keep that ID in my script enum arrays. But the question is about default SA map objects which I can't remove in game while the server is running.

Yeah, CA_RemoveBuilding can only be used BEFORE CA_Init. The GTASA map is not handled like other objects.

So the suggestion is to add that ability when CA_RemoveBuilding could work after plugin load, if it's possible of course.

It's possible, the original idea is just meant to be similar to the SA-MP RemoveBuilding natives.

Doing this would simply require that we add the collision as you can using CA_CreateObject with "add" enabled. You could currently do this in pawn using TextureStudio's GTA object database to identify and create the objects. It would still take about the same amount of memory and usage, but you'll need to raise the max number of collisions for the "add" manager.

You could currently do this in pawn using TextureStudio's GTA object database to identify and create the objects. It would still take about the same amount of memory and usage, but you'll need to raise the max number of collisions for the "add" manager.

I could do it if I didn't use ColAndreas in my map editor, but I'm using it, so I think it would be more effective to have such an opportunity in the plugin itself, not including another object collision database. One more thing is that I have deep integration with ray casts in the plugin as a player should see if any collision detected right in the direction he looks and right in that time when he do it.

I'm not sure if I'm not understanding or if you misunderstood, but either way it would still work like the regular collision map? Your map editor would still be the same.

it would be more effective to have such an opportunity in the plugin itself, not including another object collision database

Yes, it would be more effective since it would take less time to execute functions but that's literally the only difference. Either way we're going to be using the same GTASA map object database. And there wouldn't be another object collision database, in fact CURRENTLY there is and if we were to add this there wouldn't be.

Am I not understanding you correctly?

I'm not sure if I'm not understanding or if you misunderstood, but either way it would still work like the regular collision map? Your map editor would still be the same.

I need to draw a raycast line and get the collision (including the collision with default gta sa map objects) depending on the fact is there such default gta sa object on that place (so I'll have a collision with it instantly) or was it removed (no collision detected or it's detected with another different object). As far as I understood, additional gta sa object database will only provide me an ability to pre-mark some gta sa objects with 3d texts (for example), but not directly affect the raycast check, so in this case that's not for me unfortunately.

Either way we're going to be using the same GTASA map object database. And there wouldn't be another object collision database, in fact CURRENTLY there is and if we were to add this there wouldn't be.

I mean there is little sense to use external object collision db when such database exist "inside the plugin".

As far as I understood, additional gta sa object database will only provide me an ability to pre-mark some gta sa objects with 3d texts (for example), but not directly affect the raycast check, so in this case that's not for me unfortunately.

Okay so yeah, you have misunderstood and that's good!

For example, in CA you can flag collisions via the "extra" ID's. We could simply assign one of the extra variable slots to indicate whether the object is a building or created object. The extra ID's are detectable on collision!

CA_RayCastLineID can be used to get the ID of the collided object.
CA_GetObjectExtraID can be used to get the extra variable values of the collision ID from above.
CA_RayCastLineExtraID is a shortcut to get the extra variable identifier directly with a RayCast.


Now, to further explain how this is relative to what I mentioned above. Instead of buildings being added and handled separately, we would handle them like normal/script-created collisions. We would set one of the extra variables so we know it's either a created object or GTASA building. The rest would work normally after raising the max collisions. It's exactly what you're asking for, if you need further explaining please don't hesitate to ask... I'm not good at explaining things.

For the PAWN example I was explaining above, we would simply ignore the CA_Init function, raise the limit, create the objects like we would for any other collision object, set the extra ID, and the rest is normal. But yes of course this is something we'll want to implement in the plugin, I was just giving an example and noting that it could be done without changes to the plugin aside from the limit (there are 44763 GTASA objects).

EDIT: Okay, so you wouldn't IGNORE the CA_Init function since it handles the water planes as well. We would need to remove the building creation in colandreasInitMap or perhaps a boolean parameter in CA_Init to either add them like they are now or add them as managed objects.

EDIT2: Holy shit I forgot the limit was already raised to 50000 instead of 20000. So that part we don't have to worry about. #define MAX_MAP_OBJECTS 50000


Side note: If you've never played with the extra variables I would suggest checking that feature out! Something I've done with it is mark planes as "paintable" and only allow blood splatter on the marked objects.

Thanks for the detailed answer! Now I understand that we need to manually create our map with "buildings" (default GTA objects) to replace the existing one in the .cadb database which the plugin loads at startup. Through "additional per-collision variables" we can set flags of whether they were removed and thus, at any time, reset this flag and restore the collision. Sounds good exept the very first thing: we're still have original cadb which we don't use to the full extent and at the same time duplicate its data on our own, thereby increasing memory consumption and occupied collision slots. And thus, as I understand, we'll have only about 5000-6000 slots for other objects that could be created up to the limit?

Precisely πŸ€™

For testing purposes this is fine. I was just playing with things at work. In reality this would would be 44763 added to the preserved indexes for 0-MAX, not consuming the currently supplied slots. The removed building slots would not be handlable by modifying-functions like SetPos and such. And I'm not sure what you meant by duplicated data, the only duplicate data I could think you mean is like a manager for the map editor. The memory consumption from the plugin would be roughly the same as loading the objects with CA_Init. It would still use the cadb.

Here's a working proof of concept in PAWN, with no changes to the plugin. Doing this in the plugin is going to require rewriting basically all of the current removedbuilding manager.

With what the following code provides you can completely identify the objects by collision ID and vice versa (by the building ID in the database). (as provided below Remove and Restore both have guards, but CreateBuildings should only be used in initialization)

#include <a_samp>
#include <sqlitei>
#include <colandreas>
#include <YSI_Data\y_iterate>

#define CA_EX_BUILDINGID		(0)
#define BUILDING_DB_SIZE		(44763)

new bool:JustConnected[MAX_PLAYERS];
new DB:buildingDB, DBResult:buildingRS;
new Iterator:buildingCol<BUILDING_DB_SIZE + 1>, buildingColID[BUILDING_DB_SIZE];

main()
{
}

public OnGameModeInit()
{
	UsePlayerPedAnims();

	AddPlayerClass(265, 1322.1832, 1564.2081, 10.8203, 300.1425, 0, 0, 0, 0, -1, -1);
	
	if((buildingDB = db_open("allbuildings.db")) == DB:0)
	{
		print("ERROR: Failed to load building database.");
	}
	
	CreateBuildings();

	return 1;
}

stock Float:GetDistance3D(Float:x1, Float:y1, Float:z1, Float:x2, Float:y2, Float:z2)
{
	return floatsqroot(floatpower(floatabs(x2 - x1), 2.0) + floatpower(floatabs(y2 - y1), 2.0) + floatpower(floatabs(z2 - z1), 2.0));
}

stock CreateBuildings()
{
	new index, model, cid, Float:tmp, Float:bsR;
	buildingRS = db_query(buildingDB, "SELECT * FROM `buildings`");
	
	do
	{
		index = db_get_field_int(buildingRS, 0);
		model = db_get_field_int(buildingRS, 1);
		
		if(CA_GetModelBoundingSphere(model, tmp, tmp, tmp, bsR))
		{
			if(bsR > 0.0001)
			{
				cid = CA_CreateObject(model, db_get_field_float(buildingRS, 4), db_get_field_float(buildingRS, 5), db_get_field_float(buildingRS, 6), db_get_field_float(buildingRS, 7), db_get_field_float(buildingRS, 8), db_get_field_float(buildingRS, 9), true);
				
				CA_SetObjectExtraID(cid, CA_EX_BUILDINGID, index); // By default all extra variables are -1, so this is an easy soltuion to identify the objects as buildings.
				
				Iter_Add(buildingCol, index); // Mark the building index as an added collision.
				buildingColID[index] = cid; // Store the CA ID with the marked building index.
			}
		}
		
	}
	while(db_next_row(buildingRS));
	
	return 1;
}

stock RemoveBuilding(rmodel, Float:x, Float:y, Float:z, Float:r)
{
	new index, model, cid, Float:bx, Float:by, Float:bz;
	buildingRS = db_query(buildingDB, "SELECT * FROM `buildings`");
	
	do
	{
		model = db_get_field_int(buildingRS, 1);
		
		if(model != rmodel)
		{
			continue; // Skip models that aren't relative.
		}
		
		index = db_get_field_int(buildingRS, 0);
		
		if(!Iter_Contains(buildingCol, index))
		{
			continue; // It's already removed.
		}
		
		bx = db_get_field_float(buildingRS, 4);
		by = db_get_field_float(buildingRS, 5);
		bz = db_get_field_float(buildingRS, 6);
		
		if(GetDistance3D(x, y, z, bx, by, bz) <= r)
		{
			CA_DestroyObject(buildingColID[index]);
			
			// Extra variables are automatically reset by the plugin for destroyed objects.
			
			Iter_Remove(buildingCol, index);
			buildingColID[index] = -1;
		}
	}
	while(db_next_row(buildingRS));
	
	return 1;
}

stock RestoreBuilding(rmodel, Float:x, Float:y, Float:z, Float:r)
{
	new index, model, cid, Float:tmp, Float:bsR, Float:bx, Float:by, Float:bz;
	buildingRS = db_query(buildingDB, "SELECT * FROM `buildings`");
		
	if(CA_GetModelBoundingSphere(model, tmp, tmp, tmp, bsR))
	{
		if(bsR < 0.0001)
		{
			return 0; // Model has no collision.
		}
	}
	
	do
	{
		model = db_get_field_int(buildingRS, 1);
		
		if(model != rmodel)
		{
			continue; // Skip models that aren't relative.
		}
		
		index = db_get_field_int(buildingRS, 0);
		
		if(Iter_Contains(buildingCol, index))
		{
			continue; // It's already added.
		}
		
		bx = db_get_field_float(buildingRS, 4);
		by = db_get_field_float(buildingRS, 5);
		bz = db_get_field_float(buildingRS, 6);
		
		if(GetDistance3D(x, y, z, bx, by, bz) <= r)
		{
			cid = CA_CreateObject(model, bx, by, bz, db_get_field_float(buildingRS, 7), db_get_field_float(buildingRS, 8), db_get_field_float(buildingRS, 9), true);
			
			CA_SetObjectExtraID(cid, CA_EX_BUILDINGID, index); // By default all extra variables are -1, so this is an easy soltuion to identify the objects as buildings.
			
			Iter_Add(buildingCol, index); // Mark the building index as an added collision.
			buildingColID[index] = cid; // Store the CA ID with the marked building index.
		}
	}
	while(db_next_row(buildingRS));
	
	return 1;
}

public OnPlayerRequestClass(playerid, classid)
{
	TogglePlayerSpectating(playerid, true);
	if(JustConnected[playerid])
	{
		JustConnected[playerid] = false;
		SetTimerEx("OnPlayerRequestClass", 100, false, "ii", playerid, classid);
	}
	else
	{
		TogglePlayerSpectating(playerid, false);
		SpawnPlayer(playerid);
	}
	return 1;
}

public OnPlayerConnect(playerid)
{
	JustConnected[playerid] = true;
	return 1;
}

This should act fine as a temporary alternative for what you need if I'm not mistaken. However, since with this you shouldn't use CA_Init you will not be able to detect water. πŸ‘‰

EDIT: Also CreateBuildings worked surprisingly fast on my work computer. Probably much faster on my home PC, but either way I expected it to be much slower at adding 45000 objects to the collision map.

commented

Just saying, with current code base, it's kinda impossible to make CA_RemoveBuilding work after initialization without tricky and hacky ways

@NexiusTailer
I was going to do required changes in code base to make it possible, but lack of time and uni exams are holding me back for now cause this is going to take effort and a bit of my time that I need almost each minute of it these days.
Anyway, if you think this way Crayder provided is gonna work for you and tastes good, then it's all right then I guess πŸ˜„

(And sorry if I didn't reply to your messages on VK, I used a temporary email to sign up and thought I don't need to log in later cause I had it on my phone, but guess what, worst case scenario, phone got stolen... πŸ€¦β€β™‚οΈ)

@AmyrAhmady What required changes were you going to make? I think the best way is going to be treating buildings like normally created objects as described above (but of course in the plugin itself, not PAWN, my PAWN example was just proof of concept and for testing).

commented

@Crayder well, here's the short explanation:
(Note: I might be over-complicating it, who knows)
It's similar to what you said, treating them all as normal objects, and use CA_DestroyObject code for gtasa buildings to remove them, but there's a problem here, ID, it's not easy to provide a good referrer id for gtasa objects/buildings so user can use it and remove them easily

It's already using ColAndreasMapObject to create collisions for GTASA default objects, but we need to change the structures to provide an ID for already made/initialized objects (not for users, it's an internal thing), so we can use RemoveBuilding code to search for all objects around our point, get their IDs, and add them to removed objects pool, so you can be able to restore them later if you still want to keep RestoreBuilding

PS: again, I think I'm over-engineering it πŸ˜„ cause right now that I wrote it I'm thinking about some simpler ways

Nah that wouldn't be over doing it or anything, isn't that precisely how I described it? πŸ˜†

If you check out the PAWN example for example, I have a removed object pool using an iterator. πŸ‘‰

commented

Well I was saying that with this way we can also make it work like CA_Init(), so we can be able to detect water as well
and yea I actually didn't go through all of that code, my bad πŸ˜„ thought it's using CA_Init but it's not

so uhhh.. yea.. the whole point here is forcing plugin to do what we talked about in CA_Init, then be able to remove what we created

I have some time in the coming days so I think I could help with test or something to any solutions on this issue (ofc if there's already something but you doubt it is ready)