Functions of metatable not working

I am creating a networking module, based on something I found a while ago but cannot find anymore.

Network Module (part of it)
function network:new(networkName) -- Server ONLY function to create a network.

if Networks:FindFirstChild(networkName) ~= nil then -- Check to see if it already exists.

error("A network with that name already exists!");

end

local self = setmetatable( {}, network );

--

-- Setup the network folder.

self.NetworkName = networkName;

self.NetworkFolder = Instance.new("Folder", Networks);

self.NetworkFolder.Name = self.NetworkName;

self.Ports = {};

--

table.insert(shared.Networks, self);

return self;

end

function network:DisplayName()

print(self.NetworkName);

end

This is a modulescript in replicatedstorage. When I require the module from the client, and do
local PartNetwork = Network:GetNetwork(“PartNetwork”);
print(PartNetwork.NetworkName)
everything works fine.

But, if I do
PartNetwork:DisplayName()
I get this error: [attempt to call method ‘DisplayName’ (a nil value)

There’s probably something really dumb I am forgetting to do. I swear I have done this same method many times and have had no problems.

Edit: Sorry for the ugly formatting, couldn’t figure out how to just copy and paste the script in here, so I had to space out every line manually.

1 Like

Why are you inserting it into shared.Networks? Also, where’s GetNetwork?

Pretty sure it was a thread created by @ForPizzaSake

Original thread has done it because apparently shared wasn’t shared between contexts.
This was proven to be wrong though.

I’m inserting it into shared.Networks because I get the Networks from another server script, for when the client requests it. The GetNetwork function is this:

function network:GetNetwork(networkName)
	local IsClient = RunService:IsClient();
	if not IsClient then
		for _,a in pairs(shared.Networks) do
			if a.NetworkName == networkName then
				return a;
			end
		end
		return nil;
	else
		local found = RS.GetNetServ:InvokeServer(networkName);
		return found;
	end
end

Edit: here is GetNetServ:
local GetNetworkServer = Instance.new("RemoteFunction", RS);

GetNetworkServer.Name = "GetNetServ";

local function GetNetwork(Player, networkName)

for _,a in pairs(shared.Networks) do

if a.NetworkName == networkName then

return a;

end

end

return nil;

end

GetNetworkServer.OnServerInvoke = GetNetwork;

I don’t know why the formatting is so weird here. Sometimes it works, sometimes not.

Does network have a __index set to itself?

Yep.

Also, Networks is a folder.

-- Module
local network = {}
network.__index = network

function network:new(networkName)
	local self = setmetatable({}, network)
	self.NetName = networkName
	return self
end

function network:DisplayName()
	print(self.NetName)
end

return network


-- Server Script
local A = require(script.Parent.ModuleScript)
local B = A:new("yes")
B:DisplayName()

I ran this rough code in Studio and there wasn’t any issues with it. Perhaps you’ve set up your code incorrectly? If not, I’ll have to take another look at the code and see where yours is going wrong.

By the way, if you’re intending for this Network module to be a class, why not use the method network.new? Keep in mind that network:new(networkName) passes 2 arguments, not one - that is self (a variable representation of the table that the method is in) and any other arguments specified in the function. In this code, you’re basically overwriting self with something else and pushing that back out.

I’m not sure if this is it, but it seems you can’t pass functions within a table through a RemoteFunction. I’m either doing something wrong, or you just really can’t do that.

1 Like

It seems more that OP is trying to pass a name through, not a function. The main issue seems to be that OP isn’t receiving the methods for the table that is created and returned from the New method. However that may be, you are correct - you cannot pass functions through remotes.

Yes, this is my problem. I am recieving the metatable on the client, and I have the properties such as .NetworkName working, but when I try and use the methods, it does not work.

This means that when a table is created via network:new, it is not attaching the “network” table as __index. Try changing how the method is called (network:new → network.new) or using a variable that isn’t self. I’ve also supplied some module code that I believe looks like yours and does function as far as I’ve tested.

Just to clarify, classes usually are set up like this:

local Class = {}
Class.__index = Class

function Class.new(args)
	local this = {}
	this.args = args
	
	setmetatable(this, Class)
	
	return this
end

function Class:Method(args)
	print(self.args, args)
end

return Class

Or at least mine are.

You’re correct that the syntax for a constructor would be .new and not :new, but I don’t think that causes much of an issue since ‘self’ isn’t used until after it’s changed.

I’m pretty sure that he can invoke DisplayName up until it goes through the RemoteFunction, and then it loses all functions since they don’t pass through.

1 Like

I have set my classes up like this for a while now and never had any problems. But, I never had them go between server and client.

1 Like

Yeah I’m starting to think this is the problem too.

OH. Okay, now that I read the RemoteFunction, I see what the problem is. “GetNetworks” is supposed to return the table of networks, right? You’re trying to access networks created on one environment on another? Chasing is right then - you cannot pass functions through remotes.

RIP. How should I go about making this module then? I know someone has done it before.
Edit: I guess they didn’t implement OOP as much as I did…?

I’m not entirely sure, because I don’t know your use case nor do I often come across situations where I implement classes in my work.

Maybe within your new function, you could check if it’s from the client, and simply apply the network metamethod to the function-less set of properties. You’d have to do network:new(...) on whatever you receive from the server, though.

Alternatively, you could put that in another function, which would probably be more clean.

2 Likes