]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/common/mutators/mutator/sandbox/sv_sandbox.qc
Merge branch 'master' into martin-t/effects
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / mutators / mutator / sandbox / sv_sandbox.qc
index d0739c2e4443a4e2e1820079bb7a6a7eb581dbb1..9458189fd0ed20a448b9da906b3f654c12632452 100644 (file)
@@ -1,5 +1,6 @@
 #include "sv_sandbox.qh"
 
+string autocvar_g_sandbox;
 int autocvar_g_sandbox_info;
 bool autocvar_g_sandbox_readonly;
 string autocvar_g_sandbox_storage_name;
@@ -18,7 +19,7 @@ float autocvar_g_sandbox_object_material_velocity_factor;
 float autosave_time;
 void sandbox_Database_Load();
 
-REGISTER_MUTATOR(sandbox, cvar("g_sandbox"))
+REGISTER_MUTATOR(sandbox, expr_evaluate(autocvar_g_sandbox))
 {
        MUTATOR_ONADD
        {
@@ -75,14 +76,14 @@ void sandbox_ObjectFunction_Think(entity this)
        // since if the owning player disconnects, the object's owner should also be reset.
 
        // bots can't have objects
-       FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it), LAMBDA(
+       FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it), {
                if(this.crypto_idfp == it.crypto_idfp)
                {
                        this.realowner = it;
                        break;
                }
                this.realowner = NULL;
-       ));
+       });
 
        this.nextthink = time;
 
@@ -143,12 +144,9 @@ void sandbox_ObjectAttach_Remove(entity e)
 {
        // detaches any object attached to e
 
-       FOREACH_ENTITY_ENT(owner, e,
+       IL_EACH(g_sandbox_objects, it.owner == e,
        {
-               if(it.classname != "object") continue;
-
-               vector org;
-               org = gettaginfo(it, 0);
+               vector org = gettaginfo(it, 0);
                setattachment(it, NULL, "");
                it.owner = NULL;
 
@@ -167,6 +165,7 @@ entity sandbox_ObjectSpawn(entity this, float database)
        // spawn a new object with default properties
 
        entity e = new(object);
+       IL_PUSH(g_sandbox_objects, e);
        e.takedamage = DAMAGE_AIM;
        e.damageforcescale = 1;
        e.solid = SOLID_BBOX; // SOLID_BSP would be best, but can lag the server badly
@@ -211,13 +210,13 @@ void sandbox_ObjectRemove(entity e)
        sandbox_ObjectAttach_Remove(e); // detach child objects
 
        // if the object being removed has been selected for attachment by a player, unset it
-       FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it) && it.object_attach == e, LAMBDA(it.object_attach = NULL));
+       FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it) && it.object_attach == e, { it.object_attach = NULL; });
 
-       if(e.material)  {       strunzone(e.material);  e.material = string_null;       }
-       if(e.crypto_idfp)       {       strunzone(e.crypto_idfp);       e.crypto_idfp = string_null;    }
-       if(e.netname)   {       strunzone(e.netname);   e.netname = string_null;        }
-       if(e.message)   {       strunzone(e.message);   e.message = string_null;        }
-       if(e.message2)  {       strunzone(e.message2);  e.message2 = string_null;       }
+       strfree(e.material);
+       strfree(e.crypto_idfp);
+       strfree(e.netname);
+       strfree(e.message);
+       strfree(e.message2);
        delete(e);
        e = NULL;
 
@@ -226,30 +225,28 @@ void sandbox_ObjectRemove(entity e)
 
 string port_string[MAX_STORAGE_ATTACHMENTS]; // fteqcc crashes if this isn't defined as a global
 
-string sandbox_ObjectPort_Save(entity e, float database)
+string sandbox_ObjectPort_Save(entity e, bool database)
 {
        // save object properties, and return them as a string
-       float i = 0;
-       string s;
-       entity head;
+       int o = 0;
 
-       for(head = NULL; (head = find(head, classname, "object")); )
-       {
+       // order doesn't really matter, as we're writing the file fresh
+       IL_EACH(g_sandbox_objects, it == e || it.owner == e, LAMBDA(
                // the main object needs to be first in the array [0] with attached objects following
-               float slot, physics, solidity;
-               if(head == e) // this is the main object, place it first
+               int slot, physics, solidity;
+               if(it == e) // this is the main object, place it first
                {
                        slot = 0;
-                       solidity = head.solid; // applied solidity is normal solidity for children
-                       physics = head.move_movetype; // applied physics are normal physics for parents
+                       solidity = it.solid; // applied solidity is normal solidity for children
+                       physics = it.move_movetype; // applied physics are normal physics for parents
                }
-               else if(head.owner == e) // child object, list them in order
+               else if(it.owner == e) // child object, list them in order
                {
-                       i += 1; // children start from 1
-                       slot = i;
-                       solidity = head.old_solid; // persisted solidity is normal solidity for children
-                       physics = head.old_movetype; // persisted physics are normal physics for children
-                       gettaginfo(head.owner, head.tag_index); // get the name of the tag our object is attached to, used further below
+                       o += 1; // children start from 1
+                       slot = o;
+                       solidity = it.old_solid; // persisted solidity is normal solidity for children
+                       physics = it.old_movetype; // persisted physics are normal physics for children
+                       gettaginfo(it.owner, it.tag_index); // get the name of the tag our object is attached to, used further below
                }
                else
                        continue;
@@ -258,46 +255,55 @@ string sandbox_ObjectPort_Save(entity e, float database)
                if(slot)
                {
                        // properties stored only for child objects
-                       if(gettaginfo_name)     port_string[slot] = strcat(port_string[slot], "\"", gettaginfo_name, "\" ");    else    port_string[slot] = strcat(port_string[slot], "\"\" "); // none
+                       if(gettaginfo_name)
+                               port_string[slot] = strcat(port_string[slot], "\"", gettaginfo_name, "\" ");
+                       else
+                               port_string[slot] = strcat(port_string[slot], "\"\" "); // none
                }
                else
                {
                        // properties stored only for parent objects
                        if(database)
                        {
-                               port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", head.origin), " ");
-                               port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", head.angles), " ");
+                               port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", it.origin), " ");
+                               port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", it.angles), " ");
                        }
                }
                // properties stored for all objects
-               port_string[slot] = strcat(port_string[slot], "\"", head.model, "\" ");
-               port_string[slot] = strcat(port_string[slot], ftos(head.skin), " ");
-               port_string[slot] = strcat(port_string[slot], ftos(head.alpha), " ");
-               port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", head.colormod), " ");
-               port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", head.glowmod), " ");
-               port_string[slot] = strcat(port_string[slot], ftos(head.frame), " ");
-               port_string[slot] = strcat(port_string[slot], ftos(head.scale), " ");
+               port_string[slot] = strcat(port_string[slot], "\"", it.model, "\" ");
+               port_string[slot] = strcat(port_string[slot], ftos(it.skin), " ");
+               port_string[slot] = strcat(port_string[slot], ftos(it.alpha), " ");
+               port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", it.colormod), " ");
+               port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", it.glowmod), " ");
+               port_string[slot] = strcat(port_string[slot], ftos(it.frame), " ");
+               port_string[slot] = strcat(port_string[slot], ftos(it.scale), " ");
                port_string[slot] = strcat(port_string[slot], ftos(solidity), " ");
                port_string[slot] = strcat(port_string[slot], ftos(physics), " ");
-               port_string[slot] = strcat(port_string[slot], ftos(head.damageforcescale), " ");
-               if(head.material)       port_string[slot] = strcat(port_string[slot], "\"", head.material, "\" ");      else    port_string[slot] = strcat(port_string[slot], "\"\" "); // none
+               port_string[slot] = strcat(port_string[slot], ftos(it.damageforcescale), " ");
+               if(it.material)
+                       port_string[slot] = strcat(port_string[slot], "\"", it.material, "\" ");
+               else
+                       port_string[slot] = strcat(port_string[slot], "\"\" "); // none
                if(database)
                {
                        // properties stored only for the database
-                       if(head.crypto_idfp)    port_string[slot] = strcat(port_string[slot], "\"", head.crypto_idfp, "\" ");   else    port_string[slot] = strcat(port_string[slot], "\"\" "); // none
+                       if(it.crypto_idfp)
+                               port_string[slot] = strcat(port_string[slot], "\"", it.crypto_idfp, "\" ");
+                       else
+                               port_string[slot] = strcat(port_string[slot], "\"\" "); // none
                        port_string[slot] = strcat(port_string[slot], "\"", e.netname, "\" ");
                        port_string[slot] = strcat(port_string[slot], "\"", e.message, "\" ");
                        port_string[slot] = strcat(port_string[slot], "\"", e.message2, "\" ");
                }
-       }
+       ));
 
        // now apply the array to a simple string, with the ; symbol separating objects
-       s = "";
-       for(i = 0; i <= MAX_STORAGE_ATTACHMENTS; ++i)
+       string s = "";
+       for(int j = 0; j <= MAX_STORAGE_ATTACHMENTS; ++j)
        {
-               if(port_string[i])
-                       s = strcat(s, port_string[i], "; ");
-               port_string[i] = string_null; // fully clear the string
+               if(port_string[j])
+                       s = strcat(s, port_string[j], "; ");
+               port_string[j] = string_null; // fully clear the string
        }
 
        return s;
@@ -306,8 +312,9 @@ string sandbox_ObjectPort_Save(entity e, float database)
 entity sandbox_ObjectPort_Load(entity this, string s, float database)
 {
        // load object properties, and spawn a new object with them
-       float n, i;
+       int n, i;
        entity e = NULL, parent = NULL;
+       string arg = string_null;
 
        // separate objects between the ; symbols
        n = tokenizebyseparator(s, "; ");
@@ -317,9 +324,10 @@ entity sandbox_ObjectPort_Load(entity this, string s, float database)
        // now separate and apply the properties of each object
        for(i = 0; i < n; ++i)
        {
-               float argv_num;
+               #define SANDBOX_GETARG arg = argv(++argv_num);
+               int argv_num = -1; // starts at -1 so I don't need postincrement
+
                string tagname = string_null;
-               argv_num = 0;
                tokenize_console(port_string[i]);
                e = sandbox_ObjectSpawn(this, database);
 
@@ -327,38 +335,40 @@ entity sandbox_ObjectPort_Load(entity this, string s, float database)
                if(i)
                {
                        // properties stored only for child objects
-                       if(argv(argv_num) != "")        tagname = argv(argv_num);       else tagname = string_null;     ++argv_num;
+                       SANDBOX_GETARG; tagname = (arg != "") ? arg : string_null;
                }
                else
                {
                        // properties stored only for parent objects
                        if(database)
                        {
-                               setorigin(e, stov(argv(argv_num)));     ++argv_num;
-                               e.angles = stov(argv(argv_num));        ++argv_num;
+                               SANDBOX_GETARG; setorigin(e, stov(arg));
+                               SANDBOX_GETARG; e.angles = stov(arg);
                        }
                        parent = e; // mark parent objects as such
                }
                // properties stored for all objects
-               _setmodel(e, argv(argv_num));   ++argv_num;
-               e.skin = stof(argv(argv_num));  ++argv_num;
-               e.alpha = stof(argv(argv_num)); ++argv_num;
-               e.colormod = stov(argv(argv_num));      ++argv_num;
-               e.glowmod = stov(argv(argv_num));       ++argv_num;
-               e.frame = stof(argv(argv_num)); ++argv_num;
-               sandbox_ObjectEdit_Scale(e, stof(argv(argv_num)));      ++argv_num;
-               e.solid = e.old_solid = stof(argv(argv_num));   ++argv_num;
-               e.old_movetype = stof(argv(argv_num));  ++argv_num;
+               SANDBOX_GETARG; _setmodel(e, arg);
+               SANDBOX_GETARG; e.skin = stof(arg);
+               SANDBOX_GETARG; e.alpha = stof(arg);
+               SANDBOX_GETARG; e.colormod = stov(arg);
+               SANDBOX_GETARG; e.glowmod = stov(arg);
+               SANDBOX_GETARG; e.frame = stof(arg);
+               SANDBOX_GETARG; sandbox_ObjectEdit_Scale(e, stof(arg));
+               SANDBOX_GETARG; e.solid = e.old_solid = stof(arg);
+               SANDBOX_GETARG; e.old_movetype = stof(arg);
                set_movetype(e, e.old_movetype);
-               e.damageforcescale = stof(argv(argv_num));      ++argv_num;
-               if(e.material)  strunzone(e.material);  if(argv(argv_num) != "")        e.material = strzone(argv(argv_num));   else    e.material = string_null;       ++argv_num;
+               SANDBOX_GETARG; e.damageforcescale = stof(arg);
+               strfree(e.material);
+               SANDBOX_GETARG; e.material = (arg != "") ? strzone(arg) : string_null;
                if(database)
                {
                        // properties stored only for the database
-                       if(e.crypto_idfp)       strunzone(e.crypto_idfp);       if(argv(argv_num) != "")        e.crypto_idfp = strzone(argv(argv_num));        else    e.crypto_idfp = string_null;    ++argv_num;
-                       if(e.netname)   strunzone(e.netname);   e.netname = strzone(argv(argv_num));    ++argv_num;
-                       if(e.message)   strunzone(e.message);   e.message = strzone(argv(argv_num));    ++argv_num;
-                       if(e.message2)  strunzone(e.message2);  e.message2 = strzone(argv(argv_num));   ++argv_num;
+                       strfree(e.crypto_idfp);
+                       SANDBOX_GETARG; e.crypto_idfp = (arg != "") ? strzone(arg) : string_null;
+                       SANDBOX_GETARG; strcpy(e.netname, arg);
+                       SANDBOX_GETARG; strcpy(e.message, arg);
+                       SANDBOX_GETARG; strcpy(e.message2, arg);
                }
 
                // attach last
@@ -375,7 +385,6 @@ entity sandbox_ObjectPort_Load(entity this, string s, float database)
 void sandbox_Database_Save()
 {
        // saves all objects to the database file
-       entity head;
        string file_name;
        float file_get;
 
@@ -384,15 +393,11 @@ void sandbox_Database_Save()
        fputs(file_get, strcat("// sandbox storage \"", autocvar_g_sandbox_storage_name, "\" for map \"", GetMapname(), "\" last updated ", strftime(true, "%d-%m-%Y %H:%M:%S")));
        fputs(file_get, strcat(" containing ", ftos(object_count), " objects\n"));
 
-       for(head = NULL; (head = find(head, classname, "object")); )
+       IL_EACH(g_sandbox_objects, !it.owner, // attached objects are persisted separately, ignore them here
        {
-               // attached objects are persisted separately, ignore them here
-               if(head.owner != NULL)
-                       continue;
-
                // use a line of text for each object, listing all properties
-               fputs(file_get, strcat(sandbox_ObjectPort_Save(head, true), "\n"));
-       }
+               fputs(file_get, strcat(sandbox_ObjectPort_Save(it, true), "\n"));
+       });
        fclose(file_get);
 }
 
@@ -407,7 +412,7 @@ void sandbox_Database_Load()
        if(file_get < 0)
        {
                if(autocvar_g_sandbox_info > 0)
-                       LOG_INFO(strcat("^3SANDBOX - SERVER: ^7could not find storage file ^3", file_name, "^7, no objects were loaded\n"));
+                       LOG_INFO("^3SANDBOX - SERVER: ^7could not find storage file ^3", file_name, "^7, no objects were loaded");
        }
        else
        {
@@ -432,7 +437,7 @@ void sandbox_Database_Load()
                        }
                }
                if(autocvar_g_sandbox_info > 0)
-                       LOG_INFO(strcat("^3SANDBOX - SERVER: ^7successfully loaded storage file ^3", file_name, "\n"));
+                       LOG_INFO("^3SANDBOX - SERVER: ^7successfully loaded storage file ^3", file_name);
        }
        fclose(file_get);
 }
@@ -524,7 +529,7 @@ MUTATOR_HOOKFUNCTION(sandbox, SV_ParseClientCommand)
                                _setmodel(e, argv(2));
 
                                if(autocvar_g_sandbox_info > 0)
-                                       LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", player.netname, " spawned an object at origin ^3", vtos(e.origin), "\n"));
+                                       LOG_INFO("^3SANDBOX - SERVER: ^7", player.netname, " spawned an object at origin ^3", vtos(e.origin));
                                return true;
 
                        // ---------------- COMMAND: OBJECT, REMOVE ----------------
@@ -533,7 +538,7 @@ MUTATOR_HOOKFUNCTION(sandbox, SV_ParseClientCommand)
                                if(e != NULL)
                                {
                                        if(autocvar_g_sandbox_info > 0)
-                                               LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", player.netname, " removed an object at origin ^3", vtos(e.origin), "\n"));
+                                               LOG_INFO("^3SANDBOX - SERVER: ^7", player.netname, " removed an object at origin ^3", vtos(e.origin));
                                        sandbox_ObjectRemove(e);
                                        return true;
                                }
@@ -582,7 +587,7 @@ MUTATOR_HOOKFUNCTION(sandbox, SV_ParseClientCommand)
 
                                                print_to(player, "^2SANDBOX - INFO: ^7Object pasted successfully");
                                                if(autocvar_g_sandbox_info > 0)
-                                                       LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", player.netname, " pasted an object at origin ^3", vtos(e.origin), "\n"));
+                                                       LOG_INFO("^3SANDBOX - SERVER: ^7", player.netname, " pasted an object at origin ^3", vtos(e.origin));
                                                return true;
                                }
                                return true;
@@ -617,7 +622,7 @@ MUTATOR_HOOKFUNCTION(sandbox, SV_ParseClientCommand)
                                                        player.object_attach = NULL; // object was attached, no longer keep it scheduled for attachment
                                                        print_to(player, "^2SANDBOX - INFO: ^7Object attached successfully");
                                                        if(autocvar_g_sandbox_info > 1)
-                                                               LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", player.netname, " attached objects at origin ^3", vtos(e.origin), "\n"));
+                                                               LOG_INFO("^3SANDBOX - SERVER: ^7", player.netname, " attached objects at origin ^3", vtos(e.origin));
                                                        return true;
                                                }
                                                print_to(player, "^1SANDBOX - WARNING: ^7Object could not be attached to the parent. Make sure you are facing an object that you have edit rights over");
@@ -630,7 +635,7 @@ MUTATOR_HOOKFUNCTION(sandbox, SV_ParseClientCommand)
                                                        sandbox_ObjectAttach_Remove(e);
                                                        print_to(player, "^2SANDBOX - INFO: ^7Child objects detached successfully");
                                                        if(autocvar_g_sandbox_info > 1)
-                                                               LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", player.netname, " detached objects at origin ^3", vtos(e.origin), "\n"));
+                                                               LOG_INFO("^3SANDBOX - SERVER: ^7", player.netname, " detached objects at origin ^3", vtos(e.origin));
                                                        return true;
                                                }
                                                print_to(player, "^1SANDBOX - WARNING: ^7Child objects could not be detached. Make sure you are facing an object that you have edit rights over");
@@ -701,7 +706,7 @@ MUTATOR_HOOKFUNCTION(sandbox, SV_ParseClientCommand)
                                                        e.damageforcescale = stof(argv(3));
                                                        break;
                                                case "material":
-                                                       if(e.material)  strunzone(e.material);
+                                                       strfree(e.material);
                                                        if(argv(3))
                                                        {
                                                                for (j = 1; j <= 5; j++) // precache material sounds, 5 in total
@@ -717,11 +722,10 @@ MUTATOR_HOOKFUNCTION(sandbox, SV_ParseClientCommand)
                                        }
 
                                        // update last editing time
-                                       if(e.message2)  strunzone(e.message2);
-                                       e.message2 = strzone(strftime(true, "%d-%m-%Y %H:%M:%S"));
+                                       strcpy(e.message2, strftime(true, "%d-%m-%Y %H:%M:%S"));
 
                                        if(autocvar_g_sandbox_info > 1)
-                                               LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", player.netname, " edited property ^3", argv(2), " ^7of an object at origin ^3", vtos(e.origin), "\n"));
+                                               LOG_INFO("^3SANDBOX - SERVER: ^7", player.netname, " edited property ^3", argv(2), " ^7of an object at origin ^3", vtos(e.origin));
                                        return true;
                                }
 
@@ -744,8 +748,7 @@ MUTATOR_HOOKFUNCTION(sandbox, SV_ParseClientCommand)
                                        // also update the player's nickname if he changed it (but has the same player UID)
                                        if(e.netname != player.netname)
                                        {
-                                               if(e.netname)   strunzone(e.netname);
-                                               e.netname = strzone(player.netname);
+                                               strcpy(e.netname, player.netname);
                                                print_to(player, "^2SANDBOX - INFO: ^7Object owner name updated");
                                        }
 
@@ -755,8 +758,7 @@ MUTATOR_HOOKFUNCTION(sandbox, SV_ParseClientCommand)
                                                return true;
                                        }
 
-                                       if(e.crypto_idfp)       strunzone(e.crypto_idfp);
-                                       e.crypto_idfp = strzone(player.crypto_idfp);
+                                       strcpy(e.crypto_idfp, player.crypto_idfp);
 
                                        print_to(player, "^2SANDBOX - INFO: ^7Object claimed successfully");
                                }
@@ -784,10 +786,8 @@ MUTATOR_HOOKFUNCTION(sandbox, SV_ParseClientCommand)
                                                        // this should show the same info as 'mesh' but for attachments
                                                        s = "";
                                                        j = 0;
-                                                       FOREACH_ENTITY_ENT(owner, e,
+                                                       IL_EACH(g_sandbox_objects, it.owner == e,
                                                        {
-                                                               if(it.classname != "object") continue;
-
                                                                ++j; // start from 1
                                                                gettaginfo(e, it.tag_index);
                                                                s = strcat(s, "^1attachment ", ftos(j), "^7 has mesh \"^3", it.model, "^7\" at animation frame ^3", ftos(it.frame));