]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/mutators/sandbox.qc
Read-only mode. When enabled, no sandbox commands can be used, and objects cannot...
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / mutators / sandbox.qc
index 2a38941d2eaaedde0a660a89d1ba1d32d194c3b6..264aa83a7d9e62c9a827431e9e47f4fcfe556716 100644 (file)
@@ -1,5 +1,6 @@
 const float MAX_STORAGE_ATTACHMENTS = 16;
 float object_count;
 const float MAX_STORAGE_ATTACHMENTS = 16;
 float object_count;
+.float object_flood;
 .entity object_attach;
 .string material;
 
 .entity object_attach;
 .string material;
 
@@ -29,6 +30,34 @@ void sandbox_ObjectFunction_Touch()
        pointparticles(particleeffectnum(strcat("impact_", self.material)), self.origin, '0 0 0', ceil(intensity * 10)); // allow a count from 1 to 10
 }
 
        pointparticles(particleeffectnum(strcat("impact_", self.material)), self.origin, '0 0 0', ceil(intensity * 10)); // allow a count from 1 to 10
 }
 
+void sandbox_ObjectFunction_Think()
+{
+       entity e;
+
+       // decide if and how this object can be grabbed
+       if(autocvar_g_sandbox_readonly)
+               self.grab = 0; // no grabbing
+       else if(autocvar_g_sandbox_editor_free < 2 && self.crypto_idfp)
+               self.grab = 1; // owner only
+       else
+               self.grab = 3; // anyone
+
+       // Object owner is stored via player UID, but we also need the owner as an entity (if the player is available on the server).
+       // Therefore, scan for all players, and update the owner as long as the player is present. We must always do this,
+       // since if the owning player disconnects, the object's owner should also be reset.
+       FOR_EACH_REALPLAYER(e) // bots can't have objects
+       {
+               if(self.crypto_idfp == e.crypto_idfp)
+               {
+                       self.realowner = e;
+                       break;
+               }
+               self.realowner = world;
+       }
+
+       self.nextthink = time;
+}
+
 entity sandbox_ObjectEdit_Get(float permissions)
 {
        // returns the traced entity if the player can edit it, and world if not
 entity sandbox_ObjectEdit_Get(float permissions)
 {
        // returns the traced entity if the player can edit it, and world if not
@@ -44,7 +73,7 @@ entity sandbox_ObjectEdit_Get(float permissions)
                return trace_ent; // don't check permissions, anyone can edit this object
        if(!trace_ent.crypto_idfp)
                return trace_ent; // the player who spawned this object did not have an UID, so anyone can edit it
                return trace_ent; // don't check permissions, anyone can edit this object
        if(!trace_ent.crypto_idfp)
                return trace_ent; // the player who spawned this object did not have an UID, so anyone can edit it
-       if not(trace_ent.crypto_idfp != self.crypto_idfp && autocvar_g_sandbox_editor_free < 2)
+       if not(trace_ent.realowner != self && autocvar_g_sandbox_editor_free < 2)
                return trace_ent; // object does not belong to the player, and players can only edit their own objects on this server
        return world;
 }
                return trace_ent; // object does not belong to the player, and players can only edit their own objects on this server
        return world;
 }
@@ -117,6 +146,8 @@ entity sandbox_ObjectSpawn(float database)
        e.skin = 0;
        e.material = string_null;
        e.touch = sandbox_ObjectFunction_Touch;
        e.skin = 0;
        e.material = string_null;
        e.touch = sandbox_ObjectFunction_Touch;
+       e.think = sandbox_ObjectFunction_Think;
+       e.nextthink = time;
        //e.effects |= EF_SELECTABLE; // don't do this all the time, maybe just when editing objects?
 
        if(!database)
        //e.effects |= EF_SELECTABLE; // don't do this all the time, maybe just when editing objects?
 
        if(!database)
@@ -371,9 +402,14 @@ MUTATOR_HOOKFUNCTION(sandbox_PlayerCommand)
                return FALSE;
        if(cmd_name == "g_sandbox")
        {
                return FALSE;
        if(cmd_name == "g_sandbox")
        {
+               if(autocvar_g_sandbox_readonly)
+               {
+                       print_to(self, "^2SANDBOX - INFO: ^7Sandbox mode is active, but in read-only mode. Sandbox commands cannot be used");
+                       return TRUE;
+               }
                if(cmd_argc < 2)
                {
                if(cmd_argc < 2)
                {
-                       print_to(self, "Sandbox mode is active. For usage information, type 'sandbox help'");
+                       print_to(self, "^2SANDBOX - INFO: ^7Sandbox mode is active. For usage information, type 'sandbox help'");
                        return TRUE;
                }
 
                        return TRUE;
                }
 
@@ -415,6 +451,12 @@ MUTATOR_HOOKFUNCTION(sandbox_PlayerCommand)
 
                        // ---------------- COMMAND: OBJECT, SPAWN ----------------
                        case "object_spawn":
 
                        // ---------------- COMMAND: OBJECT, SPAWN ----------------
                        case "object_spawn":
+                               if(time < self.object_flood)
+                               {
+                                       print_to(self, strcat("^1SANDBOX - WARNING: ^7Flood protection active. Please wait ^3", ftos(self.object_flood - time), " ^7seconds beofore spawning another object"));
+                                       return TRUE;
+                               }
+                               self.object_flood = time + autocvar_g_sandbox_editor_flood;
                                if(object_count >= autocvar_g_sandbox_editor_maxobjects)
                                {
                                        print_to(self, strcat("^1SANDBOX - WARNING: ^7Cannot spawn any more objects. Up to ^3", ftos(autocvar_g_sandbox_editor_maxobjects), " ^7objects may exist at a time"));
                                if(object_count >= autocvar_g_sandbox_editor_maxobjects)
                                {
                                        print_to(self, strcat("^1SANDBOX - WARNING: ^7Cannot spawn any more objects. Up to ^3", ftos(autocvar_g_sandbox_editor_maxobjects), " ^7objects may exist at a time"));
@@ -425,7 +467,7 @@ MUTATOR_HOOKFUNCTION(sandbox_PlayerCommand)
                                        print_to(self, "^1SANDBOX - WARNING: ^7Attempted to spawn an object without specifying a model. Please specify the path to your model file after the 'object_spawn' command");
                                        return TRUE;
                                }
                                        print_to(self, "^1SANDBOX - WARNING: ^7Attempted to spawn an object without specifying a model. Please specify the path to your model file after the 'object_spawn' command");
                                        return TRUE;
                                }
-                               else if not(fexists(argv(2)))
+                               if not(fexists(argv(2)))
                                {
                                        print_to(self, "^1SANDBOX - WARNING: ^7Attempted to spawn an object with a non-existent model. Make sure the path to your model file is correct");
                                        return TRUE;
                                {
                                        print_to(self, "^1SANDBOX - WARNING: ^7Attempted to spawn an object with a non-existent model. Make sure the path to your model file is correct");
                                        return TRUE;
@@ -473,6 +515,12 @@ MUTATOR_HOOKFUNCTION(sandbox_PlayerCommand)
 
                                        case "paste":
                                                // spawns a new object using the properties in the player's clipboard cvar
 
                                        case "paste":
                                                // spawns a new object using the properties in the player's clipboard cvar
+                                               if(time < self.object_flood)
+                                               {
+                                                       print_to(self, strcat("^1SANDBOX - WARNING: ^7Flood protection active. Please wait ^3", ftos(self.object_flood - time), " ^7seconds beofore spawning another object"));
+                                                       return TRUE;
+                                               }
+                                               self.object_flood = time + autocvar_g_sandbox_editor_flood;
                                                if(!argv(3)) // no object in clipboard
                                                {
                                                        print_to(self, "^1SANDBOX - WARNING: ^7No object in clipboard. You must copy an object before you can paste it");
                                                if(!argv(3)) // no object in clipboard
                                                {
                                                        print_to(self, "^1SANDBOX - WARNING: ^7No object in clipboard. You must copy an object before you can paste it");
@@ -704,31 +752,6 @@ MUTATOR_HOOKFUNCTION(sandbox_PlayerCommand)
        return FALSE;
 }
 
        return FALSE;
 }
 
-MUTATOR_HOOKFUNCTION(sandbox_PlayerPreThink)
-{
-       // if the player is close enough to their object, they can drag it
-
-       if(autocvar_sv_cheats)
-               return FALSE; // cheat dragging is used instead
-
-       // grab is TRUE if the object can be picked up. While an object is being carried, the Drag() function
-       // must execute for it either way, otherwise it would cause bugs if it went out of the player's trace.
-       // This also makes sure that an object can only pe picked up if in range, but does not get dropped if
-       // it goes out of range while slinging it around.
-
-       entity e;
-       float grab;
-
-       e = sandbox_ObjectEdit_Get(TRUE);
-       if(e != world && vlen(e.origin - self.origin) <= autocvar_g_sandbox_editor_distance_edit)
-               grab = TRUE;
-
-       if(Drag(e, grab)) // execute dragging
-               return TRUE;
-
-       return FALSE;
-}
-
 float autosave_time;
 MUTATOR_HOOKFUNCTION(sandbox_StartFrame)
 {
 float autosave_time;
 MUTATOR_HOOKFUNCTION(sandbox_StartFrame)
 {
@@ -747,7 +770,6 @@ MUTATOR_DEFINITION(sandbox)
 {
        MUTATOR_HOOK(SV_ParseClientCommand, sandbox_PlayerCommand, CBC_ORDER_ANY);
        MUTATOR_HOOK(SV_StartFrame, sandbox_StartFrame, CBC_ORDER_ANY);
 {
        MUTATOR_HOOK(SV_ParseClientCommand, sandbox_PlayerCommand, CBC_ORDER_ANY);
        MUTATOR_HOOK(SV_StartFrame, sandbox_StartFrame, CBC_ORDER_ANY);
-       MUTATOR_HOOK(PlayerPreThink, sandbox_PlayerPreThink, CBC_ORDER_ANY);
 
        MUTATOR_ONADD
        {
 
        MUTATOR_ONADD
        {