09.07.2016, 20:49
(
Last edited by Jingles; 09/07/2016 at 09:26 PM.
)
Introduction
Hey there!
This is my first tutorial ever! I have been scripting for this game for a while and I feel it's time to share some of the things I learnt in my journey.
The first thing I'd like to talk about the (hidden) advantages of Incognito's streamer plugin.
If you haven't heard about the streamer before: Incognito's streamer is a plugin that streams all sorts of properties. It's faster than SA:MP's native streamer. You can read the details in their thread!
Let's talk areas first.
1. Areas
An area is a 2D or 3D property a player can interact with. Its most simple form is defined as follows:
We now stored the ID of the area that was created with CreateDynamicRectangle in the iAreaID variable. Whenever a player enters or exit this area, one of the following is triggered:
So this means we can do something with the player when they enter an area!
Let's say you want to make a house system:
- House 1's exterior coordinate teleport you to House 1's interior coordinate.
- House 2's exterior coordinate teleport you to House 2's interior coordinate.
- etc.
Let's sketch a situation in which using the streamer can be very beneficial.
A house system contains 2000 different house properties. Each has a house exterior and an interior you can travel from and to with the /enterhouse and /exithouse command. What I usually see in gamemodes is the following (in ZCMD):
So everytime someone enters (or exits) a house, they run this code to check to what linked coordinate they want to send the player to.
Above code loops through 2000 coordinates, comparing each set with the current player's position. There's nothing wrong with using this kind of vicinity check, but this block of code runs about 1/ms. Thus not very fast, especially when it's called very often!
Now let's give the streamer a go!
Now we created the areas and we have the area ID's stored. Let's see what happens when a player enters the house entrance point:
But we need the corresponding ID of the house to fetch that house ID's interior coordinates.
So let's assign the ID of the house to the area. We do that with:
For our areas (remember, both exterior and interior!), this is:
And now the ID of the house is properly assigned to the area. So when a player enters the entrance point, we can fetch the House ID:
So when they want to enter the house with /enterhouse, you can use:
I benchmarked above code at 250 times/ms. Quite a bit faster than the 1 time/ms version!
Conclusion: we save our server a lot of stress when using the streamer to let the player interact with server properties!
Part II will soon follow!
I hope you enjoyed this first sneak peek into how you can use the streamer for more than just streaming.
Hey there!
This is my first tutorial ever! I have been scripting for this game for a while and I feel it's time to share some of the things I learnt in my journey.
The first thing I'd like to talk about the (hidden) advantages of Incognito's streamer plugin.
If you haven't heard about the streamer before: Incognito's streamer is a plugin that streams all sorts of properties. It's faster than SA:MP's native streamer. You can read the details in their thread!
Let's talk areas first.
1. Areas
An area is a 2D or 3D property a player can interact with. Its most simple form is defined as follows:
Code:
new iAreaID = CreateDynamicRectangle(0.0, 0.0, 10.0, 10.0);
Code:
OnPlayerEnterDynamicArea(playerid, areaid); // When a player enters an area. OnPlayerLeaveDynamicArea(playerid, areaid); // When a player exits an area.
Let's say you want to make a house system:
- House 1's exterior coordinate teleport you to House 1's interior coordinate.
- House 2's exterior coordinate teleport you to House 2's interior coordinate.
- etc.
Let's sketch a situation in which using the streamer can be very beneficial.
A house system contains 2000 different house properties. Each has a house exterior and an interior you can travel from and to with the /enterhouse and /exithouse command. What I usually see in gamemodes is the following (in ZCMD):
Code:
#define MAX_HOUSES 2000 enum HInfo { Float:HouseExteriorX, Float:HouseExteriorY, Float:HouseExteriorZ, Float:HouseInteriorX, Float:HouseInteriorY, Float:HouseInteriorZ } new House[MAX_HOUSES][HInfo]; CMD:enterhouse(playerid, params[]) { for(new h; h < MAX_HOUSES; h++) { if(IsPlayerInRangeOfPoint(playerid, 2.0, House[h][HouseExteriorX], House[h][HouseExteriorY], House[h][HouseExteriorZ])) { // Virtual World checks are left out. SetPlayerPos(playerid, House[h][HouseInteriorX], House[h][HouseInteriorY], House[h][HouseInteriorZ]); // etc. } } return 1; } CMD:exithouse(playerid, params[]) { for(new h; h < MAX_HOUSES; h++) { if(IsPlayerInRangeOfPoint(playerid, 2.0, House[h][HouseInteriorX], House[h][HouseInteriorY], House[h][HouseInteriorZ])) { // Virtual World checks are left out. SetPlayerPos(playerid, House[h][HouseExteriorX], House[h][HouseExteriorY], House[h][HouseExteriorZ]); // etc. } } return 1; }
Above code loops through 2000 coordinates, comparing each set with the current player's position. There's nothing wrong with using this kind of vicinity check, but this block of code runs about 1/ms. Thus not very fast, especially when it's called very often!
Now let's give the streamer a go!
Code:
#define MAX_HOUSES 2000 enum HInfo { Float:HouseExteriorX, // I prefer Float:HousePos[3], but to be clear I use the linguistically more understandable version. Float:HouseExteriorY, Float:HouseExteriorZ, Float:HouseInteriorX, Float:HouseInteriorY, Float:HouseInteriorZ, bool:bExists, // I'd use a bitvar for this, but I won't make it too complicated just yet. iAreaID[2] // We create 2, one for the enter location and one for the exit location. } new House[MAX_HOUSES][HInfo]; House[h][iAreaID][0] = CreateDynamicSphere(House[h][HouseExteriorX], House[h][HouseExteriorY], House[h][HouseExteriorZ], 3.0, House[h][HouseVW]); // The house exterior. House[h][iAreaID][1] = CreateDynamicSphere(House[h][HouseInteriorX], House[h][HouseInteriorY], House[h][HouseInteriorZ], 3.0, House[h][HouseVW]); // The house interior.
Code:
OnPlayerEnterDynamicArea(playerid, areaid) // -> The areaid that we receive is the ID of the house exterior area.
So let's assign the ID of the house to the area. We do that with:
Code:
Streamer_SetIntData(type, STREAMER_ALL_TAGS id, data, value);
Code:
CreateHouse(h) { // Let's say this is where the house is created. Streamer_SetIntData(STREAMER_TYPE_AREA, House[h][iAreaID][0], E_STREAMER_EXTRA_ID, h); Streamer_SetIntData(STREAMER_TYPE_AREA, House[h][iAreaID][1], E_STREAMER_EXTRA_ID, h); }
Code:
OnPlayerEnterDynamicArea(playerid, areaid) { // If you plan on using this in more systems, make sure the areaid equals that of the respective propery too! new h = Streamer_GetIntData(STREAMER_TYPE_AREA, areaid, E_STREAMER_EXTRA_ID); if(0 <= h < MAX_HOUSES) { // A bounds check if(House[h][bExists]) SetPVarInt(playerid, "AtHouse", h); // Just make sure that the house actually exists. For example with a variable. } } OnPlayerExitDynamicArea(playerid, areaid) { new h = Streamer_GetIntData(STREAMER_TYPE_AREA, areaid, E_STREAMER_EXTRA_ID); if(0 <= h < MAX_HOUSES) { // A bounds check if(House[h][bExists]) DeletePVar(playerid); // Make sure to delete the PVar when they go out of the enter/exit point. } }
Code:
CMD:enterhouse(playerid, params[]) { if(GetPVarType(playerid, "AtHouse")) { new h = GetPVarInt(playerid, "AtHouse"); SetPlayerPos(playerid, House[h][HouseInteriorX], House[h][HouseInteriorY], House[h][HouseInteriorZ], 3.0, House[h][HouseVW]); // etc. } else SendClientMessage(playerid, 0xFFFFFFFF, "You are not at a house."); return 1; }
Conclusion: we save our server a lot of stress when using the streamer to let the player interact with server properties!
Part II will soon follow!
I hope you enjoyed this first sneak peek into how you can use the streamer for more than just streaming.