Having the server use Advanced Duplicator

Here is a theoretical situation:
Assume an RP style of play

There is a map that has a square room inside, decorated with various tables and props, most of them not welded together. The map can be created specifically for this function. At a set interval, the server uses the advanced duplicator tool (or one of its functions) to save a cube section of the map, such as an entire room, and saves it to a file. The player is still in the map, so you can reference them for saving prop information. The room could either be hard-coded map dependent world coordinates ( x, y, z ) or by a specially made “event” (or whatever its called) area in the map.

A player joins an RP server, he buys and decorates a room, a script automatically saves the room every minute using advanced duplicator to a file. The player leaves the server, the room still belongs to him, and all of his props are purged. When he rejoins, the server waits for him to spawn, and then sees that he owns a room, and goes looking for the most recent save of it. The server pastes the latest save into the room, and the player can go about his business like his props have always been there.

The only section of this I need help with is for server-side operation of advanced duplicator. (how to have it save a section of the map)

The operation would be threaded to cut down on latency.

Sorry for all the text.

Thanks

P.S. Also a suggestion for saving an entire map’s props ( Xmin, Ymin, Zmin to Xmax, Ymax, Zmax,) would be useful.

What exactly is the purpose of this post? A request? And project?

He’s asking how it’s done.

Anyway, I don’t know how, but it can be done. I don’t think you need to use Adv. dupe. Try looking through the wiki for a function.

Also, just a suggestion: I’d have it only save when the player wants, or when the player leaves. Otherwise your servers would get full of the txt files and start t lag when it saves.

Thanks. I have been looking for such a function and I can’t find anything, maybe I’m just missing it. I want to use advanced duplicator because in general it does a very good job of saving contraptions, even wire entities. I would probably want the saving to be automatic in case of a server crash or something along those lines, and also if there is a button that makes lag you just know that someone is going to abuse it. I would thread the operation using gm_lanes to cut down on lag.

Edit:
ents.FindInBox maybe?

So from what I can gather, using the ents.FindInBox returns a table of entities. This sounds about right for what I want, but how would I save the constraints as well? Would I need to measure how the entity is oriented in space manually or is that saved in the entity properties in the table? Any tips on how to recreate all the entities in the list without everything exploding?

This is tested and works
[ul]
[li]Don’t ever have different coordinates for the same room. The room argument is for having multiple player saves.[/li][li]Do as the comment says. Pick a corner on the floor of the room, then pick an opposite side upper corner.[/li][li]Define ply in each. For SteamID purposes.[/li][li]Does not include constraints, this is just to give you an idea.[/li][li]If your room is complex and is not just one box. Try doing multiple saves with room1a or room2a, room has to be a string.[/li][li]One more thing glon would be a better choice, or sqlite, but I didn’t have the time. Good luck.[/li][li] Ref: ply = player object, room = room name string, corner1 = vector, corner2 = vector[/li][/ul]

[lua]function GM:SaveRoomProps( ply, room, corner1, corner2 ) – Replace corner1 with a bottom corner of the room, and replace corner2 with an opposite side, top corner of the room
local prop_table = { };
local ents = ents.FindInBox( corner1, corner2 );

for k, v in pairs( ents ) do
	local idx = v:EntIndex( );
	local pos = v:GetPos( );
	local ang = v:GetAngles( );
	
	prop_table[ idx ] = { };
	prop_table[ idx ][ "pos" ] = { };
	prop_table[ idx ][ "pos" ][ "x" ] = pos.x;
	prop_table[ idx ][ "pos" ][ "y" ] = pos.y;
	prop_table[ idx ][ "pos" ][ "z" ] = pos.z;
	prop_table[ idx ][ "angles" ] = { };
	prop_table[ idx ][ "angles" ][ "p" ] = ang.p;
	prop_table[ idx ][ "angles" ][ "y" ] = ang.y;
	prop_table[ idx ][ "angles" ][ "r" ] = ang.r;
	prop_table[ idx ][ "model" ] = v:GetModel( );
end;

file.Write( "rp/room_props/" .. room .. "/" .. ply:SteamID( ) .. ".txt", util.TableToKeyValues( prop_table ) );

end;

function GM:LoadRoomProps( ply, room )
local prop_table = util.KeyValuesToTable( file.Read( “rp/room_props/” … room … “/” … ply:SteamID( ) … “.txt” ) );

for k, v in pairs( prop_table ) do
	local ent = ents.Create( "prop_physics" );
	if not ent:IsValid( ) then return; end;
	
	ent:SetPos( Vector( tonumber( prop_table[ k ][ "pos" ][ "x" ] ), tonumber( prop_table[ k ][ "pos" ][ "y" ] ), tonumber( prop_table[ k ][ "pos" ][ "z" ] ) ) );
	ent:SetAngles( Angle( tonumber( prop_table[ k ][ "angles" ][ "p" ] ), tonumber( prop_table[ k ][ "angles" ][ "y" ] ), tonumber( prop_table[ k ][ "angles" ][ "r" ] ) ) );
	ent:SetModel( prop_table[ k ][ "model" ] );
	
	ent:Spawn( );
	
	local phys = ent:GetPhysicsObject( );
	
	if phys:IsValid( ) then
		phys:EnableGravity( true );
		phys:EnableMotion( false );
		phys:Wake( );
	end;
end;

end;[/lua]

Wow! Thanks. I was thinking it was something along those lines but that looks correct. I’m testing it now.

Did it work alright?

My steam is stalker1095, if you ever need more help.

Only thing iv found so far is that you cant save a file named as a SteamID anymore, because it doesn’t support special characters ‘_’. Still working on it.

[editline]11:55PM[/editline]

[lua]“Out”
{
“1”
{
“angles”
{
“Y” “20.941806793213”
“p” “0”
“r” “0”
}
“model” “models/player/group01/male_07.mdl”
“pos”
{
“Y” “467.283203125”
“x” “-760.55847167969”
“z” “64.03125”
}
}
“153”
{
“angles”
{
“Y” “-180”
“p” “-6.6172258783581e-009”
“r” “-2.1010910131736e-006”
}
“model” “models/props_c17/oildrum001_explosive.mdl”
“pos”
{
“Y” “525.48461914063”
“x” “-605.62036132813”
“z” “180.72685241699”
}
}
“137”
{
“angles”
{
“Y” “20.941806793213”
“p” “0”
“r” “0”
}
“model” “models/weapons/v_superphyscannon.mdl”
“pos”
{
“Y” “467.283203125”
“x” “-760.55847167969”
“z” “64.03125”
}
}
“136”
{
“angles”
{
“Y” “0”
“p” “0”
“r” “0”
}
“pos”
{
“Y” “512”
“x” “-928”
“z” “65”
}
}
“151”
{
“angles”
{
“Y” “20.941806793213”
“p” “0”
“r” “0”
}
“pos”
{
“Y” “467.283203125”
“x” “-760.55847167969”
“z” “64.03125”
}
}
}
[/lua]

theres the file output for an empty room with an explosive barrel in it. It saved myself and my current weapon as well, but I can filter those out.

Edit:
After manually editing out the non props in the file, it loads them with the correct heading in the correct place, but don’t belong to the player.

Yea try adding. If v:GetClass( ) == “prop_physics” then code end;

As for SteamID I would just format it, and delete those characters.

Belong? That must be a mod. Maybe prop protection, you will have to find the addownership function yourself.

Im still working on it, the script itself works pretty well. What I meant by ‘belong’ is having the prop listed in the ‘cleanup’ menu and be able to undo it by pressing ‘z’. I figured that part out:

goes after ent:Spawn();
[lua]
cleanup.Add(ply, “props”, ent);

undo.Create(“prop”)
undo.AddEntity(ent)
undo.SetPlayer(ply)
undo.Finish()
[/lua]

I might use this in my lobby gamemode hub later on.

isn’t this what Gmod Tower did?

Yea thats kind of what I’m trying, except less stupid and vertical. I started the project awhile ago and someone online was like “lulz gmod tower is kind of like that”. Before then I hadn’t heard of it. Ill post my changes to the script when I get done commenting it.
Edit:
Heres the code with debug text still included
I’m still refining it but you get the idea.
[Lua]
function SaveRoomProps( ply, building, room, corner1, corner2 ) – Saves all props inside a room to a file
local prop_table = { };
local ents = ents.FindInBox( corner1, corner2 );

for k, v in pairs( ents ) do
	if v:GetClass( ) == "prop_physics" then --Gets if the current prop is the fun kind
		if v:GetModel() == nil then --Gets if the current prop is "empty"
			print("empty prop");
		elseif string.find( string.lower( v:GetModel() ), "models/weapons/" ) then --Ignores any model in the weapon catagory
			print("weapon scrapped");
		elseif string.find( string.lower( v:GetModel() ), "models/gibs/" ) then --Ignores any gibs
			print("gib ignored");
		else
		local idx = v:EntIndex( ); --Loads the current prop's Index into idx
		local pos = v:GetPos( ); --Loads the current prop's position into pos
		local ang = v:GetAngles( ); --Loads the current prop's angles into ang
		
		prop_table[ idx ] = { }; --Makes aa table for the index
		prop_table[ idx ][ "pos" ] = { }; --makes a table for the position
		prop_table[ idx ][ "pos" ][ "x" ] = pos.x;
		prop_table[ idx ][ "pos" ][ "y" ] = pos.y;
		prop_table[ idx ][ "pos" ][ "z" ] = pos.z;
		prop_table[ idx ][ "angles" ] = { }; --makes a table for the angles
		prop_table[ idx ][ "angles" ][ "p" ] = ang.p; --pitch
		prop_table[ idx ][ "angles" ][ "y" ] = ang.y; --yaw
		prop_table[ idx ][ "angles" ][ "r" ] = ang.r; --roll
		prop_table[ idx ][ "model" ] = v:GetModel( ); --saves the prop's model
		prop_table[ idx ][ "material" ] = v:GetMaterial( ); --saves the prop's material
		prop_table[ idx ][ "skin" ] = v:GetSkin( ); --saves the skin index number thing
		print(v:GetModel(), "Pos: ".. pos.x.." "..pos.y.." "..pos.z)
		end;
	end;
end;

if (not file.IsDir("rp/room_props/" .. building .. "/" .. room .. "/" .. ply:UniqueID( ) .. "/")) then --if the directory doesn't exist
	file.CreateDir("rp/room_props/" .. building .. "/" .. room .. "/" .. ply:UniqueID( ) .. "/") --make it
end

file.Write( "rp/room_props/" .. building .. "/" .. room .. "/" .. ply:UniqueID( ) .. "/main-" .. ply:UniqueID( ) .. ".txt", util.TableToKeyValues( prop_table ) ); --write current copy
file.Write( "rp/room_props/" .. building .. "/" .. room .. "/" .. ply:UniqueID( ) .. "/bak-" .. tostring(os.date("%y%m%d%H%M%S")) .. ".txt", util.TableToKeyValues( prop_table ) ); --make a backup

end;

function LoadRoomProps( ply, building, room ) --loads the saved props back where they came from
print(“loading…”);
if file.Exists( “rp/room_props/” … building … “/” … room … “/” … ply:UniqueID( ) … “/main-” … ply:UniqueID( ) … “.txt” ) then --if a stored version exists (for the GM:PlayerInitialSpawn when you first enter the map)
local prop_table = util.KeyValuesToTable( file.Read( “rp/room_props/” … building … “/” … room … “/” … ply:UniqueID( ) … “/main-” … ply:UniqueID( ) … “.txt” ) ); --read the save

	for k, v in pairs( prop_table ) do --iterate thru the save file table thing
		local ent = ents.Create( "prop_physics" ); --make a new ent
		if not ent:IsValid( ) then return; end;
		
		ent:SetPos( Vector( tonumber( prop_table[ k ][ "pos" ][ "x" ] ), tonumber( prop_table[ k ][ "pos" ][ "y" ] ), tonumber( prop_table[ k ][ "pos" ][ "z" ] ) ) ); --sets the ent's position
		ent:SetAngles( Angle( tonumber( prop_table[ k ][ "angles" ][ "p" ] ), tonumber( prop_table[ k ][ "angles" ][ "y" ] ), tonumber( prop_table[ k ][ "angles" ][ "r" ] ) ) ); --sets the ent's angles
		ent:SetModel( prop_table[ k ][ "model" ] ); --set the ent's model
		ent:SetMaterial( prop_table[ k ][ "material" ] ); --set the ent's material
		ent:SetSkin( tonumber( prop_table[ k ][ "skin" ] )); --set the ent's skin
		
		--ent:SetOwner( ply );
		print(ent:GetModel());
		ent:Spawn( ); --spawn the new ent
		cleanup.Add(ply, "props", ent); --puts an entry for the entity in the "Props" cleanup thing
		
		undo.Create("prop") --make an undo entry
			undo.AddEntity(ent)
			undo.SetPlayer(ply)
		undo.Finish()
		
		local phys = ent:GetPhysicsObject( );
		
		if phys:IsValid( ) then
			phys:EnableGravity( true );
			phys:EnableMotion( false ); --false is spawn frozen
			phys:Wake( ); --make physics happen
		end;
	end;
	print("All props for room " .. room .. " have been loaded");
else
	print("Nothing to load from")
end;

end;

function RemoveRoomProps( corner1, corner2 )
for _,v in pairs ( ents.FindInBox( corner1, corner2 ) ) do
if v:GetClass( ) == “prop_physics” then
print("Removed "…v:GetModel());
v:Remove();
end;
end;
end
[/Lua]

Yea, but the same as zero said. I came up with this idea way before gmod tower was even thought of. Gmod Tower in my opinion is extremely boring.

You came up with an idea of saving prop_physics into a table, and loading them? I wonder why this hasn’t been ever done before, bravo!

Oh, I am being sarcastic.

You don’t have to get all smart about it. I was just helping him out with his problem, because there was no other convenience other than adv dupe. It would be easier just to start from the ground up just like I did.

There are many ideas people come up with, but never implement. Leaving hyped things like Gmod Tower to get all the credit.

Either way, people like you just help me get more posts :wink:

This is just one critical part of a gamemode I’m working on. I really wanted to make something work with advanced duplicator but this works pretty well too.

Real motherfucking G