Does net.WriteTable and net.ReadTable take metatables?

Hello everybody! I looked on the Garry’s Mod wiki and did some researches but I couldn’t find an answer. So here’s the question, does net.WriteTable and net.ReadTable take metatables in account? Let me give you an example:

  1. I create a table SERVER SIDE;
  2. I create another table, this time, SHARED, and I set this table as the metatable for my first table (with setmetatable);
  3. Then, I send my first table to a client using the net library with net.WriteTable;
  4. My client receives the table with net.ReadTable;

In this scenario, will the table my client received have the same metatable as my server side one? Thank you in advance!

PS: I’m sorry for asking so many questions in such a little time span, but I encountered a lot of problems and questions as I didn’t touch Lua for a while.

All it does is send the key and value https://github.com/garrynewman/garrysmod/blob/master/garrysmod/lua/includes/extensions/net.lua#L101

Ok then, is it possible to tell the client to set the received table’s metatable to the server side table one? It would be easy if the metatable was set in a global variable and that there was a way to get a variable name (which, in Lua, isn’t possible). In this case we would just have to send the name of the variable to the client and it would set the metatable.
Sending the whole metatable to the client is impossible (And would be really freakin’ bad if possible) as the net library can’t send functions. If anyone knows an efficient way, please tell me, I am currently looking out for one and doing researches but nothing came up yet. Thank you in advance!

PS: Why the hell do I always find myself trying to make some insane things like these…

You might want to explain what you are trying to accomplish - why are you trying to send a metatable to the client in the first place?

Would it properly send __index if it were set to a parent table? I don’t see why it shouldn’t. The thing is it won’t send functions.

I have been working on a system to allow object oriented programming in Gmod Lua (for a gamemode). The shared objects must be automatically networked between the server and the clients. To do so, I just mark the variables I want to network as “networkable” (by putting them in a table) and when a networked var of an object is set/changed server side, it sends it to the clients. But if a networked var is itself an object, it only networks the table, without its metatable, making it just a basic table, not an object anymore. If you want to know more, here is my current code for this system (And thanks for the quick replies):


net.objects = {};

if (SERVER) then
	util.AddNetworkString('OORPObjectNW'); -- Used to network vars between server side and client side objects.
	util.AddNetworkString('OORPObjNWSynch'); -- Used to sync an object between the server and clients.
	
	--[[
		Description: Called when the client request to sync an object, 
		sends the currently networked vars of a server side object to its client self.
	]]--
	net.Receive('OORPObjNWSynch', function()
		local netUID = net.ReadString();
		local obj = net.objects[netUID];
		
		if (obj) then
			net.Start('OORPObjNWSynch')
				net.WriteString(netUID);
				for k in pairs(obj.vars) do
					if (obj[k]) then
						net.WriteString(k);
						net.WriteType(obj[k]);
					end
				end
			net.Broadcast();

			obj.synced = true;
		end		
	end)
	
else
	local function ReadVar(netUID, obj)
		local key = net.ReadString();
		local value = net.ReadType(net.ReadUInt(8));
		net.objects[netUID][key] = value;
	end

	--[[
		Description: Called when the server anwsers a request to sync an object,
		applies the received networked vars of the server side object to the client side one.
	]]--
	net.Receive('OORPObjNWSynch', function()
		local netUID = net.ReadString();
		local obj = net.objects[netUID];
		
		if (obj) then
			for k, v in pairs(obj.vars) do
				ReadVar(netUID, obj)
			end
		
			obj.synced = true;
		
			if (obj._synced != nil) then
				obj:_synced(LocalPlayer())
			end
		end
	end)
	
	--[[
		Description: Called when the server wants to set a networked var of an object,
		just sets the var to the received value.
	]]--
	net.Receive('OORPObjectNW', function()
		local netUID = net.ReadString();
		local obj = net.objects[netUID];
		ReadVar(netUID, obj);
	end)
end

--[[
	Description: Creates a class table ready to be used.

	Arguments:	cls		table		Class table, should only contain basics such as the parent.

	Returns:	table				A class table ready to be used.	
]]--
function class(args)
	cls = args || {};
	cls.__index = cls;
	cls.type = 'class';
	
	cls.networked = cls.networked || false;
	
	-- Basic inheritance.
	if (cls.parent) then
		for k, v in pairs(cls.parent) do
			if (cls[k] == nil) then
				cls[k] = v;
			end
		end
	end
	
	-- For networked classes only.
	if (cls.networked) then
		--[[
			Description: Mark a var to be networked when changed.	
		]]--
		cls.NetworkVar = function(self, name)
			self.vars[name] = true;
		end
	
		if (SERVER) then
			cls.__newindex = function(self, key, value)
				if (self.synced && self.vars[key]) then
					net.Start('OORPObjectNW')
						net.WriteString(self.netUID);
						net.WriteString(key);
						net.WriteType(value);
					net.Broadcast();
				end
				rawset(self, key, value);
			end
		end
	end
	
	local meta = {};
	
	return setmetatable(cls, {__call = function(cls, ...)
		local obj = setmetatable({}, cls);
		rawset(obj, 'type', 'object')
		local arg = {...}; -- Handling variable number of arguments.
				
		if (obj.networked) then
			local netUID = arg[1];
			
			rawset(obj, 'netUID', netUID);
			rawset(obj, 'vars', {});
			table.remove(arg, 1); -- The first argument needs to be removed as it is now useless.
	
			obj.synced = false; -- Not synced yet...
			net.objects[obj.netUID] = obj;
		end

		if (obj._construct != nil) then
			obj:_construct(unpack(arg));
		end
		
		-- Requesting for sync if the object is client side. 
		if (CLIENT && obj.networked) then
			net.Start('OORPObjNWSynch');
				net.WriteString(obj.netUID);
			net.SendToServer();
		end
	
		return obj; -- obvs
	end})
end

That’d require __index being stored in your table rather than a separate metatable. You’d also still have to re-set the metatable yourself, as you’ll get a metatable-less table from net.ReadTable.