Best way to arrange maps?
#1

Here's the deal. My server has over 200 maps, resulting in about 100K of lines of code. What we used to do is the following:

1) Cram everything in 1 filterscript we named "maps", this didn't seem like a very good solution to me

2) Organise everything by category: stunt, dmzones, races, drifts, etc... This was a good idea but still required lots of work to add a new map. We had to edit the include files to add the actual map, add a teleport and add a menu item in the game mode.

My idea would be to store all the maps in a folder "maps", in the root directory. Then use the FileManager plugin to read data from the file and so generate all the objects. This way adding a map doesn't require the server to restart and doesn't require anything to be recompiled. The same thing can be done for teleports: store the coordinates in a file and make a function that reads data from that file to generate those teleports.

This, though, may not be the best idea. So I'm asking you, the much more experienced SA-MP community: what would be the best solution to store maps?
Reply
#2

I usually store maps or objects in mysql.
Reply
#3

Quote:
Originally Posted by Cameltoe
View Post
I usually store maps or objects in mysql.
Sounds like a plan
Reply
#4

Quote:
Originally Posted by Cameltoe
View Post
I usually store maps or objects in mysql.
If you have hundreds of objects, and you place them all in a MySQL database it will take a while before all the objects are loaded from the database and created on the server. You'll notice this time when you (re)start the server.

You could give it a try though. See how much time it takes up on your server, and decide if it's fast enough or takes too long.
Reply
#5

Y_Less summed up what I wanted to say. In my game mode I use mysql for everything, logging stuff to vehicles you name it. The actual creating of it takes longer than obtaining it from the database!

I also had a side mode I stopped developing but might pick up later. It used an MTA map loader which also worked fine but is significantly slower, I wouldn't suggest it if you have a lot of objects in the map.

I used to have these .map files in a folder, in mysql I had the name of the file (and a display name), I had a dialog to display all the maps, it would just take all the names from the database and display them, make an array to index the actual file name, and let the players vote, then use that array to obtain the filename by dialog listitem and use the loader to load the map - that loading however takes a while and might halt the server. The reason I did it that way because members would have the possibility to upload their own maps. They would be dynamically loaded in the game mode without ever having to touch the script.
Reply
#6

I spent the last few hours coding a tool in PHP that converts and places all my maps (vehicles & objects) in a mysql database. It was a bitch but now that it's done I'm seeing the advantages of it.

I will now start creating the script in pawn, making the map & teleport loader.

EDIT: I figured I should present you guys with some hard numbers. This is the time it takes to load 40K+ objects and create them (streamer plugin). I ran the test 10 times.

Code:
[21:26:08] [LOADER] Created 41240 dynamic objects in 1821ms seconds.
[21:26:10] [LOADER] Created 41240 dynamic objects in 2303ms seconds.
[21:26:13] [LOADER] Created 41240 dynamic objects in 2484ms seconds.
[21:26:15] [LOADER] Created 41240 dynamic objects in 1941ms seconds.
[21:26:16] [LOADER] Created 41240 dynamic objects in 1747ms seconds.
[21:26:18] [LOADER] Created 41240 dynamic objects in 1766ms seconds.
[21:26:20] [LOADER] Created 41240 dynamic objects in 1814ms seconds.
[21:26:22] [LOADER] Created 41240 dynamic objects in 1698ms seconds.
[21:26:24] [LOADER] Created 41240 dynamic objects in 1819ms seconds.
[21:26:26] [LOADER] Created 41240 dynamic objects in 1933ms seconds.
Reply
#7

Nicely done, check how much time the query takes to execute and fetch the data compared to the actual creating. You will be amazed.
Reply
#8

imo the best solution is to use your mentioned map-loader. imagine you get some maps from different sources (script, mta-map, custom format), then you will want to load them instantly - copying a file per ftp and then a simple /reloadobjects or better /scanmaps, combined with yor MTA parser will satify you. i can promise that coz iam using this method for 10k's of objects - works fine. the most awesome sideeffect is the option to script a /savepwn, /savemta or just your format to save objects (like 2nd position after moving, maybe vehicles, not to forget replaced textures?) - all stored in one location, where you can pick/delete a single file, or (let some1 else) update it.
Reply
#9

Quote:
Originally Posted by Babul
View Post
imo the best solution is to use your mentioned map-loader. imagine you get some maps from different sources (script, mta-map, custom format), then you will want to load them instantly - copying a file per ftp and then a simple /reloadobjects or better /scanmaps, combined with yor MTA parser will satify you. i can promise that coz iam using this method for 10k's of objects - works fine. the most awesome sideeffect is the option to script a /savepwn, /savemta or just your format to save objects (like 2nd position after moving, maybe vehicles, not to forget replaced textures?) - all stored in one location, where you can pick/delete a single file, or (let some1 else) update it.
Dafuq did I just read?
Reply
#10

Quote:
Originally Posted by Babul
View Post
imo the best solution is to use your mentioned map-loader. imagine you get some maps from different sources (script, mta-map, custom format), then you will want to load them instantly - copying a file per ftp and then a simple /reloadobjects or better /scanmaps, combined with yor MTA parser will satify you. i can promise that coz iam using this method for 10k's of objects - works fine. the most awesome sideeffect is the option to script a /savepwn, /savemta or just your format to save objects (like 2nd position after moving, maybe vehicles, not to forget replaced textures?) - all stored in one location, where you can pick/delete a single file, or (let some1 else) update it.
Exactly, but then I figured why not go the extra mile and script a loader for SQL aswel. With any loader really all it comes down to is strip the lines to extract the basic data (x, y, z, rotation, ...) and store them for whatever reason you may need it, doing this with files or a database it really doesn't make that much of a difference. I did however prefer SQL because now I can make an online map uploader (which I plan on doing today).
Reply
#11

@Sinner:
NOT go the extra mile? for me its vice-versa! i admit, it would be 100 more miles for me to get used to sql - i guess each way got its advantages, why not combine all of them? ^^
@Sniper Kitty:
basically, you have read a description of:
pawn Код:
// Map loader by Babul
#include <a_samp>
#include <sscanf2>// credits to Y_Less
#include <streamer>//credits to Incognito
#include <zcmd>//credits to Zeex
#include <dir>//credits to Terminator3
#include <filemanager>//credits to JaTochNietDan
#include <gvar>//credits to Incognito

#define FILTERSCRIPT

#define MSGCASH_COLOR 0x44cc22ff
#define MSGSUCC_COLOR 0x55ffaaff
#define MSGFAIL_COLOR 0xff55aaff
#define MSGCOMM_COLOR 0x55aaff77
#define MSGINFO_COLOR 0xffffff77
#define MSGDBUG_COLOR 0xaa5555ff
#define MSGTITL_COLOR 0xffffaaff
#define MSGCMDS_COLOR 0xffaa55ff

#define DIALOG_MAPS 3495

new ObjectMaps;
new ObjectMap[100][64];
new ListItemMapID[100];

const ObjectsMax=500000;
new ObjectsUsed;
new Object[ObjectsMax];

public OnFilterScriptInit(){
    SendClientMessageToAll(MSGTITL_COLOR,">>>{aa5500}M{ffaa55}a{ffffaa}p{ffffff}s");
    LoadObjectsDir();
    new string[128];
    format(string,sizeof(string),"%d Objects loaded.",ObjectsUsed);
    SendClientMessageToAll(MSGINFO_COLOR,string);
    printf("%d",ObjectsUsed);
    return 1;
}

public OnFilterScriptExit(){
    for (new p=1;p<ObjectsMax;p++)
    {
        DestroyDynamicObject(Object[p]);
    }
    return 1;
}

public  OnDialogResponse(playerid, dialogid, response, listitem, inputtext[]){
    if(response)
    {
        switch(dialogid)
        {
            case DIALOG_MAPS:
            {
                new MapName[64];
                format(MapName,sizeof(MapName),"%s",ObjectMap[ListItemMapID[listitem]]);
                new string[128];
                new Objects=GetGVarInt(MapName,0);
                format(string,sizeof(string),"Objects in '%s':%d",MapName,Objects);
                SendClientMessage(playerid,MSGDBUG_COLOR,string);
                new Float:ox,Float:oy,Float:oz;
                new Float:mx,Float:my,Float:mz;
               
                new ID=GetGVarInt(MapName,1);
                GetDynamicObjectPos(ID,ox,oy,oz);
                for(new o=1;o<Objects+1;o++)
                {
                    ID=GetGVarInt(MapName,o);
                    GetDynamicObjectPos(ID,ox,oy,oz);
                    mx=(mx+ox)/2.0;
                    my=(my+oy)/2.0;
                    mz=(mz+oz)/2.0;
                    format(string,sizeof(string),"ID:%d X:%f Y:%f Z:%f",GetGVarInt(MapName,o),ox,oy,oz);
                }
                SetPlayerPos(playerid,ox,oy,oz+20);
                TogglePlayerControllable(playerid,0);
                SetPlayerCameraPos(playerid,ox+40,oy+40,oz+20);
                SetPlayerCameraLookAt(playerid,ox+20,oy+20,oz);
                return cmd_maps(playerid,"");
            }
        }
    }
    else
    {
        TogglePlayerControllable(playerid,1);
        SetCameraBehindPlayer(playerid);
    }
}

stock LoadObjectsDir(){
    new string[160];
    new entry[64];
    new type;
   
    new ValidFireworks;
    new BuyableFireworks;
    new filename[64];
    new Val[256];
    new Type;
    new Name[32],Price,Grav,StartSpeedZ,StartSpeedXY,Entail,Seek,GroundBump,LifeTime,LifeTimeRndAdd,ExplosionDeath,EmitDeath,EmitDeathAmount,EmitRing,RotationOffset,RotationSpread,RotationRandom,Emitter,EmitOnce,Generations,EmitTime,EmitterTypeRnd[20],EmitterSelectMax,ObjectType,ObjectAmount;
    new DIR:dir=DirOpen("Objects/Maps");
    if(!dir)return SendClientMessageToAll(MSGFAIL_COLOR,"Directory \"Objects\" not found.");
    while((type=DirRead(dir,entry)))
    {
        format(string,sizeof(string),"type %d:%s",type,entry);
        ValidFireworks++;
        new ObjectFile[64];
        format(ObjectFile,sizeof(ObjectFile),"Objects/Maps/%s",entry);
        if(type==1)
        {
            if(strfind(ObjectFile,".txt",true,0)>-1)
            {
                OLoad(ObjectFile);
                ObjectMap[ObjectMaps]=ObjectFile;
                ObjectMaps++;
            }
            if(strfind(ObjectFile,".map",true,0)>-1)
            {
                MapLoad(ObjectFile);
                ObjectMap[ObjectMaps]=ObjectFile;
                ObjectMaps++;
            }
            if(strfind(ObjectFile,".pwn",true,0)>-1)
            {
                PwnLoad(ObjectFile);
                ObjectMap[ObjectMaps]=ObjectFile;
                ObjectMaps++;
            }
        }
        SendClientMessageToAll(MSGCMDS_COLOR,ObjectFile);
    }
    return 1;
}

forward OLoad(filename[]); public OLoad(filename[]){
    new File:fObjects=fopen(filename,io_read);
    new string[128];
    new sID,virtualworld;
    new ObjectsAdded;
    new Float:sPosX,Float:sPosY,Float:sPosZ,Float:sRotX,Float:sRotY,Float:sRotZ,sName[64];
    new Float:sPosX2,Float:sPosY2,Float:sPosZ2,Float:sRotX2,Float:sRotY2,Float:sRotZ2;
    new Float:Speed1,Float:Speed2,TrigSel1,TrigSel2,TrigDir1,TrigDir2,TrigTime1,TrigTime2;
    new TrigPTO1,TrigPTO2,TrigPTODir1,TrigPTODir2;
    new Val[192];
    fread(fObjects,Val);
    if(!sscanf(Val,"dD(0)",sID,virtualworld))
    {
        format(string,sizeof(string),"Objects:%d VWorld:%d",sID,virtualworld);
        SendClientMessageToAll(MSGSUCC_COLOR,string);
    }
    {
        new Objects=sID;
        for(new o=1;o<Objects+1;o++)
        {
            fread(fObjects,Val);
            if(sscanf(Val,"dS( )[96]",sID,sName))
            {
                format(string,sizeof(string),"Object '%s' loading failed.",filename);
                SendClientMessageToAll(MSGFAIL_COLOR,string);
                return 1;
            }
            {
                format(sName,strlen(sName)-1,"%s",sName);
            }
            fread(fObjects,Val);
            if(sscanf(Val,"ffffffF(0)F(0)F(0)F(0)F(0)F(0)F(10)F(10)D(0)D(0)D(0)D(0)D(0)D(0)D(0)D(0)D(0)D(0)",sPosX,sPosY,sPosZ,sRotX,sRotY,sRotZ,sPosX2,sPosY2,sPosZ2,sRotX2,sRotY2,sRotZ2,Speed1,Speed2,TrigSel1,TrigSel2,TrigDir1,TrigDir2,TrigTime1,TrigTime2,TrigPTO1,TrigPTO2,TrigPTODir1,TrigPTODir2))
            {
                return 1;
            }
            Object[o]=CreateDynamicObject(sID,sPosX,sPosY,sPosZ,sRotX,sRotY,sRotZ,virtualworld,-1,-1,500);
            ObjectsAdded++;
            SetGVarInt(filename,Object[o],ObjectsAdded);
        }
        SetGVarInt(filename,ObjectsAdded,0);
        fclose(fObjects);
    }
    ObjectsUsed+=ObjectsAdded;
    return 1;
}

forward MapLoad(filename[]);public MapLoad(filename[]){
    new File:source = fopen(filename,io_read);
    new string[384],tmp[384];
    new objid,Float:px,Float:py,Float:pz,Float:rx,Float:ry,Float:rz;
    new ObjectsAdded;
    new paintjob,i = 0,o = 0;
    new modelstr[32],pjstr[32],npstr[2][32],intstr[32],pxstr[32],pystr[32],pzstr[32],rxstr[32],rystr[32],rzstr[32];
    while(fread(source,string,sizeof(string)))
    {
        if(!sscanf(string,"'<object's[384]",tmp))
        {
            if(!sscanf(string,"'doublesided=\"false\"'s[32]{s[32]s[32]}s[32]s[32]s[32]s[32]s[32]s[32] ",modelstr,pxstr,pystr,pzstr,rxstr,rystr,rzstr) && !sscanf(modelstr,"p<\">{s[32]}d",objid) && !sscanf(pxstr,"p<\">{s[32]}f",px) && !sscanf(pystr,"p<\">{s[32]}f",py) && !sscanf(pzstr,"p<\">{s[32]}f",pz) && !sscanf(rxstr,"p<\">{s[32]}f",rx) && !sscanf(rystr,"p<\">{s[32]}f",ry) && !sscanf(rzstr,"p<\">{s[32]}f",rz))
            {
                switch(objid)
                {
                    case 14383..14483: objid += 4248;
                    case 14770..14856: objid += 4063;
                    case 14858..14871: objid += 4062;
                    case 18000..18036: objid += 934;
                    case 18038..18101: objid += 933;
                    case 14872..14883: objid += 4163;
                    case 14885..14891: objid += 4162;
                    case 13590..13667: objid += 5142;
                    case 14500..14522: objid += 4310;
                    case 12835..12944: objid += 6219;
                    case 16000..16143: objid += 3164;
                    case 14892: objid += 5009;
                }
                Object[o]=CreateDynamicObject(objid,px,py,pz,rx,ry,rz,0,-1,-1,500);
                ObjectsAdded++;
                SetGVarInt(filename,Object[o],ObjectsAdded);
                o++;
            }
            else
            {
                print("Error: Incorrect object format.");
            }
        }
    }
    SetGVarInt(filename,ObjectsAdded,0);
    fclose(source);
    ObjectsUsed+=ObjectsAdded;
    return 1;
}

forward PwnLoad(filename[]);public PwnLoad(filename[]){
    new File:source = fopen(filename,io_read);
    new string[384],rest[128];
    new objid,Float:px,Float:py,Float:pz,Float:rx,Float:ry,Float:rz,vworld,interior,player,Float:distance;
    new ObjectsAdded;
    new paintjob,i = 0,o = 0;
    while(fread(source,string,sizeof(string)))
    {
        if(!sscanf(string,"'Create''Object''('p<,>dfffffp<)>f{s[128]}",objid,px,py,pz,rx,ry,rz))
        {
            Object[o]=CreateDynamicObject(objid,px,py,pz,rx,ry,rz,0,-1,-1,500);
            ObjectsAdded++;
            SetGVarInt(filename,Object[o],ObjectsUsed);
            o++;
        }
        else if(!sscanf(string,"'CreateDynamicObject''('p<,>dffffffdddp<)>f{s[128]}",objid,px,py,pz,rx,ry,rz,vworld,interior,player,distance))
        {
            Object[o]=CreateDynamicObject(objid,px,py,pz,rx,ry,rz,0,-1,-1,500);
            ObjectsAdded++;
            SetGVarInt(filename,Object[o],ObjectsAdded);
            o++;
        }
        else if(!sscanf(string,"'CDO''('p<,>dffffffdddp<)>f{s[128]}",objid,px,py,pz,rx,ry,rz,vworld,interior,player,distance))
        {
            Object[o]=CreateDynamicObject(objid,px,py,pz,rx,ry,rz,0,-1,-1,500);
            ObjectsAdded++;
            SetGVarInt(filename,Object[o],ObjectsAdded);
            o++;
        }
        else
        {
        }
        SetGVarInt(filename,ObjectsAdded,0);
    }
    SetGVarInt(filename,ObjectsAdded,0);
    fclose(source);
    ObjectsUsed+=ObjectsAdded;
    return 1;
}

CMD:maps(playerid,params[]){
    new DialogString[4096];
    new string[128];
    new ListItemsAdded;
    for(new map=0;map<ObjectMaps;map++)
    {
        ListItemMapID[ListItemsAdded]=map;
        ListItemsAdded++;
        format(string,sizeof(string),"%d\t%s",GetGVarInt(ObjectMap[map],0),ObjectMap[map]);
        format(DialogString,sizeof(DialogString),"%s\n%s",DialogString,string);
    }
    ShowPlayerDialog(playerid,DIALOG_MAPS,DIALOG_STYLE_LIST,"Maps",DialogString,"Close","");
    return 1;
}

CMD:mapcmds(playerid,cmdtext[]){
    SendClientMessage(playerid,MSGTITL_COLOR,">>>{aa5500}M{ffaa55}a{ffffaa}p{ffffff}s");
    SendClientMessage(playerid,MSGCMDS_COLOR,"      /cmds /Mapcmds /Maps /MapsReload*");
    return 1;
}

CMD:cmds(playerid,cmdtext[]){
    cmd_mapcmds(playerid,"");
}
Reply
#12

Okay well, a MySQL/PHP version would be a whole lot simpler and efficient than that will ever be.
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)