All pastes #769771 Raw Edit

Miscellany

public text v1 · immutable
·published 2007-11-11 17:39 UTC
rendered paste body
Using the YSI object system.

Creation:

The YSI object system is very similar to the default SA:MP object system, it just supports more objects.  In the normal system if you wanted to create an object you would do:

[pawn]CreateObject(model, x, y, z, rx, ry, rz);[/pawn]

This is VERY similar to what you do in YSI:

[pawn]CreateDynamicObject(model, x, y, z, rx, ry, rz);[/pawn]

Simple as, all you need to do to convert your code is add the word "Dynamic", which is dead easy with the find and replace feature.

In SA:MP if you want to create an object for just one player you would do:

[pawn]CreatePlayerObject(playerid, model, x, y, z, rx, ry, rz);[/pawn]

Again, this is VERY similar in YSI, just add "Dynamic" again and you're done:

[pawn]CreatePlayerDynamicObject(playerid, model, x, y, z, rx, ry, rz);[/pawn]

One thing SA:MP doesn't provide by default is support for objects only appearing in certain virtual worlds, this is achieved in YSI with:

[pawn]CreateVWDynamicObject(world, model, x, y, z, rx, ry, rz);[/pawn]

Again, a very simple function.

What if you want to do something a little more complicated like make an object visible from a long way away?  Again that's very simple, just do:

[pawn]Object_SetViewDistance(objectid, distance);[/pawn]

objectid is, as with normal objects, the value returned by the CreateDynamicObject function, distance is how far away you want the object to be visible (default is 200), so for example:

[pawn]new
    myObj1;
myObj1 = CreateDynamicObject(1337, 10.0, 20.0, 30.0, 0.0, 0.0, 0.0);
Object_SetViewDistance(myObj1, 500.0);[/pawn]

Note: You don't have to put the rotation if they're all 0.0.

That code will make your new object (a black wheely bin in the sky near the GTAHost farm) visible from 500 units away (although objects that smaall can't actually be seen from that distance as they're too small, but the engine will be creating it and larger items will be visible).

With most object streamers, if you can see more than 150ish objects at once (as in, if more than that number are in range) you will just see a random selection of them, which could mean you can't see the object you're stood on, despite the fact it's one of the closest to you.  YSI orders the objects so if too many are in range you will see the closest ones, so no problems with falling through the floor.

Now what if we've created an object but we want two people to be able to see it?  We can create two identical objects, one for each person, as you would in other systems, or you can use YSI's feature of being able to set a complete list of who can and can't see an object.  There are a few functions involved in this system:

[pawn]Object_AddToPlayer(objectid, playerid);
Object_RemoveFromPlayer(objectid, playerid);
Object_AddToAllPlayers(objectid);
Object_RemoveFromAllPlayers(objectid);[/pawn]

The first function allows a player who can't see an object to see it.  The second object stops a player who can see an object from being able to see it.  The third object allows all players to see an object.  The fourth object, as you've probably guessed by now, allows no-one to see an object.  Doing:

[pawn]CreatePlayerDynamicObject(playerid, model, x, y, z);[/pawn]

Is the same as doing:

[pawn]new
    myObj2 = CreateDynamicObject(model, x, y, z);
Object_RemoveFromAllPlayers(myObj2);
Object_AddToPlayer(myObj2, playerid);[/pawn]

(note the absence of rotation for easier code as described above).

Both those pieces of code will end up with the object only visible by one player.  A more complex example is given below.  This will allow all members of KFC to see an object but no-one else (not a very secure method as you can just change your name but it's an example):

At the top of your file:

[pawn]new
    gKFCObject;[/pawn]

This just declares a global variable to store the object id in.

In Script_OnGameModeInit:

[pawn]gKFCObject = CreateDynamicObject(1337, 10.0, 20.0, 30.0);
Object_RemoveFromAllPlayers(gKFCObject);[/pawn]

That creates the object and doesn't let anyone see it.

In Script_OnPlayerConnect:

[pawn]new
    playerName[MAX_PLAYER_NAME];
GetPlayerName(playerid, playerName, sizoef (playerName));
if (strfind(playerName, "[KFC]") != -1)
{
    Object_AddToPlayer(gKFCObject, playerid);
}[/pawn]

That will check to see if the player connecting has "[KFC]" in their name and if so allow them to see the object (strfind returns -1 if the string isn't found).

In Script_OnPlayerDisconnect:

[pawn]Object_RemoveFromPlayer(gKFCObject, playerid);[/pawn]

This just ensures that people connecting after a KFC member leaves can't see the object.

Obviously more than one player can connect with [KFC] in their name and they will all be able to see the object while no-one else can.

There are also equivalent functions for virtual worlds, so you can have an object visible in worlds 2, 3, and 4 but no others.  You can also combine these functions so only certain people can see an object when they're in a certain world (there is also CreatePlayerVWDynamicObject which will create an object for one player in one world only, similar to others listed above).

Movement:

Now we've covered creating you object and setting who can and can't see it lets move onto something a little different - object movement.  This can range from simply changing it's position to attaching 12 objects together and having them go round a course repeatedly.

Much of what was just mentioned is again very similar to the default ways of doing things, to set an object's position use SetDynamicObjectPos with exactly the same parameters as SetObjectPos:

[pawn]SetDynamicObjectPos(objectid, x, y, z);[/pawn]

Same for the new versions of GetObjectPos, SetObjectRot and GetObjectRot:

[pawn]GetDynamicObjectPos(objectid, x, y, z);
SetDynamicObjectPos(objectid, rx, ry, rz);
GetDynamicObjectPos(objectid, rx, ry, rz);[/pawn]

There are also movement functions, these operate exactly the same as the normal versions but will still work even if no-one can see the object.  This also has a new callback: OnDynamicObjectMoved, this is exactly the same as OnObjectMoved (which you now shouldn't use) but is called even when an object no-one can see reaches it's destination.  There is no OnPlayerObjectMoved equivalent because of the way objects are handled for people explained above.

[pawn]Script_OnDynamicObjectMoved(objectdid)
{
    printf("Object %d moved", objectid);
	return 1;
}[/pawn]

From there you can obviously do whatever, move it again to make it follow a course, trigger something else to move or anything.  There is also AttachDynamicObjectToPlayer and, possible more importantly, DetachDynamicObjectFromPlayer to take it off again, something not available in SA:MP alone.  These will work even if the player you are attaching the object to can't see the object.

In a similar vein but again unique to YSI are the AttachObjectToObject and DetachObjectFromObject functions, these do exactly as they sound and mean any movements done to the object your attaching to will be done by the objects attached to it.  Note however that moving a 'child' object (an object which is attached to another object) will not move the 'parent' object (the object the child is attached to).

[pawn]new
    parent = CreateDynamicObject(1337, 0.0, 0.0, 0.0),
    child = CreateDynamicObject(1337, 0.0, 0.0, 10.0);
AttachObjectToObject(child, parent);
MoveDynamicObject(parent, 10.0, 10.0, 0.0);[/pawn]

That code will mean the parent object will end up at: 10.0, 10.0, 0.0 and the child object, which will be moved as well, keeping it's original offset, will end up at: 10.0, 10.0, 10.0.

[pawn]new
    parent = CreateDynamicObject(1337, 0.0, 0.0, 0.0),
    child = CreateDynamicObject(1337, 0.0, 0.0, 10.0);
AttachObjectToObject(child, parent);
MoveDynamicObject(child, 10.0, 10.0, 10.0);[/pawn]

In that code you are moving the child, not the parent, so the child will end up at: 10.0, 10.0, 10.0, as above, however the parent will not have moved.  This will modify the relative offset of the child from the parent, so then doing:

[pawn]MoveDynamicObject(child, 10.0, 10.0, 0.0);[/pawn]

Will mean the parent will end up at: 10.0, 10.0, 0.0 and the child, with it's new 10.0, 10.0, 10.0 offset from the parent will end up at: 20.0, 20.0, 10.0.

There is no limit to the number of children an object can have:

[pawn]new
    parent = CreateDynamicObject(1337, 0.0, 0.0, 0.0),
    child0 = CreateDynamicObject(1337, 0.0, 0.0, 10.0),
    child1 = CreateDynamicObject(1337, 0.0, 0.0, 20.0),
    child2 = CreateDynamicObject(1337, 0.0, 0.0, 30.0),
    child3 = CreateDynamicObject(1337, 0.0, 0.0, 40.0);
AttachObjectToObject(child0, parent);
AttachObjectToObject(child1, parent);
AttachObjectToObject(child2, parent);
AttachObjectToObject(child3, parent);
MoveDynamicObject(parent, 10.0, 10.0, 0.0);[/pawn]

After that code the positions of the objects will be:

parent: 10.0, 10.0, 0.0
child0: 10.0, 10.0, 10.0
child1: 10.0, 10.0, 20.0
child2: 10.0, 10.0, 30.0
child3: 10.0, 10.0, 40.0

As moving a child will not move it's parent moving a child will also not move it's siblings (objects attached to the same parent).

You can also attach objects to children:

[pawn]new
    grandparent = CreateDynamicObject(1337, 0.0, 0.0, 0.0),
    parent = CreateDynamicObject(1337, 0.0, 0.0, 10.0),
    child = CreateDynamicObject(1337, 0.0, 0.0, 20.0);
AttachObjectToObject(parent, grandparent);
AttachObjectToObject(child, parent);[/pawn]

Moving the grandparent will move all three objects, moving the parent will not move it's parent (the grandparent) but will move the child, moving the child will only move the child.

WARNING, this code:

[pawn]new
    obj1 = CreateDynamicObject(1337, 0.0, 0.0, 0.0),
    obj2 = CreateDynamicObject(1337, 0.0, 0.0, 10.0),
AttachObjectToObject(obj1, obj2);
AttachObjectToObject(obj2, obj1);[/pawn]

Will create a possible infinate loop so if you try to move either of these objects the server will hang.  This is because the first object will be moved, then it's children, then their children and so on and as they're each other's children it will keep looping and looping.

Configuration:

By default YSI supports 10,000 (ten thousand) streamed objects however it has done 1,000,000 (one million) objects with one player, compared to other streamers which get very laggy at only 10,000 and hang entirely LONG before 1,000,000.  If you want to increase the number of objects from 10,000 (or indeed decrease it to make your mode faster still if you have less objects).  Simply add:

[pawn]#define MAX_DYN_OBJECTS <number>[/pawn]

ABOVE your "#include <YSI>" line.  To speed up streaming YSI uses a zone system, you can have objects anywhere you like but by default they are best if placed between -3000x/y and +3000x/y.  Most people don't need to worry about this but if you are going to have a lot of objects outside these bounds you may want to adjust the area.  There are two ways of doing this, one is:

[pawn]#define OBJECT_BOUNDS <number>[/pawn]

That will set the x and y boundaries to +/- that number, so for example:

[pawn]#define OBJECT_BOUNDS 500[/pawn]

Will set the lower x boundary to -500, the upper x boundary to 500 and the same for the y axies.  This option is for compatability with older versions of YSI.  The other way is to set each boundary separately, so for example a mode based in Las Venturas may do:

[pawn]#define OBJECT_BOUNDS_MINX 0
#define OBJECT_BOUNDS_MAXX 5000
#define OBJECT_BOUNDS_MINY 0
#define OBJECT_BOUNDS_MAXY 5000[/pawn]

Note: Both these methods must be placed ABOVE your "#include <YSI>" line.  Also objects placed outside the boundaries will still appear they will just use a slightly slower streaming method (infact they use almost exactly the same method as other object streamers as it's not area dependent).