#include "sv_sandbox.qh"
+string autocvar_g_sandbox;
int autocvar_g_sandbox_info;
bool autocvar_g_sandbox_readonly;
string autocvar_g_sandbox_storage_name;
float autosave_time;
void sandbox_Database_Load();
-REGISTER_MUTATOR(sandbox, cvar("g_sandbox"))
+REGISTER_MUTATOR(sandbox, expr_evaluate(autocvar_g_sandbox))
{
MUTATOR_ONADD
{
// 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;
{
// 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;
// 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
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;
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;
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;
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, "; ");
// 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);
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
void sandbox_Database_Save()
{
// saves all objects to the database file
- entity head;
string file_name;
float file_get;
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);
}
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
{
}
}
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);
}
_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 ----------------
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;
}
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;
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");
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");
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
}
// 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;
}
// 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");
}
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");
}
// 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));