SA-MP Forums Archive
[Include] y_areas - Printable Version

+- SA-MP Forums Archive (https://sampforum.blast.hk)
+-- Forum: SA-MP Scripting and Plugins (https://sampforum.blast.hk/forumdisplay.php?fid=8)
+--- Forum: Filterscripts (https://sampforum.blast.hk/forumdisplay.php?fid=17)
+---- Forum: Includes (https://sampforum.blast.hk/forumdisplay.php?fid=83)
+---- Thread: [Include] y_areas (/showthread.php?tid=571302)



y_areas - corne - 17.04.2015

y_areas
Introduction

This is one of the higher-level YSI libraries that has been in existence for a while, but which I never got around to documenting. It provides two callbacks:

Код:
forward OnPlayerEnterArea(playerid, areaid);

forward OnPlayerLeaveArea(playerid, areaid);
These are called whenever a player enters or leaves one of the pre-defiend regions of space defined in your mode through a variety of functions.

Use

This library provides a number of functions for declaring areas. For example, to detect when a player is in Fort Carson do:

Код:
#include <YSI\y_areas>

new
    gAreaFortCarson

public OnScriptInit()
{
    gAreaFortCarson = Area_AddCuboid(-376.20, 826.30, -3.00, 123.70, 1220.40, 200.00);
}

public OnPlayerEnterArea(playerid, areaid)
{
    if (areaid == gAreaFortCarson) SendClientMessage(playerid, X11_GREEN, "Welcome to Fort Carson");
}
You can also have more complex shapes. A "Poly" is any "polygon", and is defined by a series of co-ordinates, each one representing a corner of the shape. A simple triangle would look something like:

Код:
Area_AddPoly(/* First Point */ -100.0, -100.0, /* Second Point */ 100.0, -100.0, /* Third Point */ 0.0, 100.0);
Note that this shape is equivalent:

Код:
Area_AddPoly(/* First Point */ -100.0, -100.0, /* Third Point */ 0.0, 100.0, /* Second Point */ 100.0, -100.0);
The points must be in an order such that drawing lines between them will trace the outline of the shape. This is a valid square:

Код:
Area_AddPoly(
    -100.0, -100.0, // Bottom left
     100.0, -100.0, // Bottom right
     100.0,  100.0, // Top right
    -100.0,  100.0  // Top left
);
This is NOT a square, even though it has the same points. Instead, the order draws out an egg-timer shape (the last and first points are implicitly connected):

Код:
Area_AddPoly(
    -100.0, -100.0, // Bottom left
     100.0,  100.0, // Top right
    -100.0,  100.0, // Top left
     100.0, -100.0 // Bottom right
);
The (x, Y) pairs imply an even number of parameters; however, with an odd number the last one (335.90 below) is the HEIGHT - any players above this point are not in the area. Currently you can't have a lower-bound on polygons, but can on most other shapes. To detect when a player enters Downtown Los Santos (which is not a simple square) do:

Код:
#include <YSI\y_areas>

new
    gAreaDowntownLosSantos;

public OnScriptInit()
{
    gAreaDowntownLosSantos= Area_AddPoly(
        1812.60, -1430.80,
        1812.60, -1150.80,
        1463.90, -1150.80,
        1463.90, - 926.90,
        1391.00, - 926.90,
        1391.00, -1026.30,
        1378.30, -1026.30,
        1378.30, -1130.80,
        1370.80, -1130.80,
        1370.80, -1384.90,
        1463.90, -1384.90,
        1463.90, -1430.80, 335.90);
}

public OnPlayerEnterArea(playerid, areaid)
{
    if (areaid == gAreaDowntownLosSantos) SendClientMessage(playerid, X11_GREEN, "Welcome to Downtown Los Santos");
}
Area FunctionsOther Functions

As well as functions to add areas, there are several helper functions:Download

This library is a part of YSI, which can be found here. Keep your eye on that topic and your server log for updates.

YSI Download Topic

Advanced

This system uses a (IMHO) quite complex zoning system to stream areas - only the ones known to be near the player are checked. The world is split in to a grid and areas added to the grid square in which they fit entirely. If an area does not fit in to a single square there are numerous pregressively larger zones in which they can be placed - quarter of the map, half the map, the whole map, several areas outside the map, and the whole world (i.e. everywhere). This means that a player is in several zones at once and only these ones are checked. You can see the (quite ugly and hand-unrolled) code for this zone determination in "Area_DetermineZone".

In addition to this zoning, the more complex zones (i.e. polygons) have extra optimisations in the form of bounding circles. A circle is drawn around the whole area - if the player is not in this circle (which is easy to check) then they can't possibly be in the polygon (which is hard to check). Only if they are in the circle is the polygon checked too.

As already mentioned, a player can be in multiple areas at once. Several of these areas are stored in an array for fast access - if they are in a great number of areas at once (which is unlikely) then the extras are stored in slower but more dynamic PVars. The limit at which this happens is defined by "AREAS_MAX_OVERLAPS" and defaults to 3.

Finally, this code contains the most complex "enum" that I've ever written! An area has certain pieces of data such as players and worlds that all areas need, but some areas need more storage for co-ordinates than others. To accommodate this, multiple areas are used to store a single one, but in those cases the space used to store things like player permissions is not needed and is instead used for extra co-ordinate space. This is done through this enum:

Код:
// =============================================================================
// =============================================================================
// IMPORTANT NOTE: The order of elements in this enum is INCREDIBLY important.
// Because this is three enums in one, they share some pieces of data that must
// not get overridden.
// =============================================================================
// =============================================================================
// This might just be the most complex enum I've ever made!
enum E_AREA
{
    //union
    //{
    //    struct
    //    {
            #if YSIM_HAS_MASTER
                E_AREA_MASTER,
            #endif
            // This has increased from 4 to 6, so we can store cubes and ovoids
            // in a single slot.
            Float:E_AREA_POS[6],
            PlayerArray:E_AREA_PLAYERS<MAX_PLAYERS>,
            // This MUST go between "E_AREA_PLAYERS" and "E_AREA_FLAGS" to
            // remain constant in subsequent unions.
            //#if defined AREA_VERY_FAST
            //    Float:E_AREA_BOUNDING[4],
            //#endif
            // As must this.
            #if AREA_WORLDS > 0
                BitArray:E_AREA_WORLDS<AREA_WORLDS>,
            #endif
            // ALWAYS last (actually used by EVERY type).
            e_AREA_FLAGS:E_AREA_FLAGS,
    //    }
    //    // Start of poly data.
    //    struct
    //    {
            // Reset the enum counter to 0 (on the next item).
            _E_AREA_RESET_@1 = -1,
            // Now restart.
            #if YSIM_HAS_MASTER
                // Skip the master flag if it exists.
                _E_AREA_MASTER_@1,
            #endif
            // This is where polys differ from all others.
            E_AREA_POLY_COUNT,
            E_AREA_POLY_NEXT,
            //Float:E_AREA_POLY_POS[4],
            // This slot holds ONLY the polygon bounding data, it doesn't hold
            // any co-ordinates AT ALL.
            //Float:E_AREA_BOUNDING[4],
            Float:E_AREA_POLY_BOUND_X,
            Float:E_AREA_POLY_BOUND_Y,
            Float:E_AREA_POLY_BOUND_R,
            Float:E_AREA_POLY_BOUND_H,
            // Skip all the array and flag data, they stay the same.
            _E_AREA_ARRAYS_@1[E_AREA_FLAGS - E_AREA_PLAYERS],
            // Skip the flags.
            E_AREA_UNUSED_NEXT,
    //    }
    //    // Start of poly child data.
    //    struct
    //    {
            // Reset the enum counter to 0 (on the next item).
            _E_AREA_RESET_@2 = -1,
            // Now restart.
            #if YSIM_HAS_MASTER
                // Skip the master flag if it exists.
                _E_AREA_MASTER_@2,
            #endif
            // Store a link to the parent of this poly child.
            E_AREA_CHILD_PARENT,
            // And the next one in VERY rare cases (I hope).
            // THIS SHARES A SLOT WITH "E_AREA_POLY_NEXT", so we can always just
            // use that slot when iterating.
            #if _:(E_AREA_FLAGS - E_AREA_CHILD_PARENT) & 1
                // There are an ODD number of available slots.  We can store an
                // extra pair iff we don't need to use "NEXT".
                //_E_AREA_SKIP_@2,
                E_AREA_CHILD_OPT_Y,
            #endif
            E_AREA_CHILD_OPT_X,
            // Just store a vast number of X/Y pairs in this child.
            Float:E_AREA_CHILD_ELEMS[_:E_AREA_FLAGS - _:E_AREA_CHILD_OPT_X - 1],
            // Skip the flags.
            _E_AREA_CHILD_ELEMS_END
    //    }
}

#define CHILD_AREA_SLOTS ((_:_E_AREA_CHILD_ELEMS_END - _:E_AREA_CHILD_ELEMS))
Credits
I am reposting this include (made by ******) with the thought of what he said to several members of the community. Everything that could help someone should not be deleted from the forums, which is something I agree with since I learned a lot by reading the tutorials on here. He made a lot of things that are used by lots of servers and that knowledge should not be lost for present and future developers.


Re: y_areas - Qu3esL - 17.04.2015

This was a quiet useless one! Streamer have more range of functions and its dynamic, lastly its a plugin+