Require appears to not require

I am making a zone system, where the player touches a part, and then various effects happen on the client.
I have multiple zones set up in a module script like so:

local StarterPack = game.StarterPack

local ZoneStats = {}

ZoneStats["Test Area"] = {}
ZoneStats["Test Area"].FogEnd = 100
ZoneStats["Test Area"].FogColor = Color3.fromRGB(255,0,0)
ZoneStats["Test Area"].Ambient = Color3.fromRGB(0,0,255)
ZoneStats["Test Area"].Brightness = 0
ZoneStats["Test Area"].Music = StarterPack.ZoneMusic.TEST
ZoneStats["Test Area"].LocationText = tostring("Test Area")
ZoneStats["Test Area"].LocationDescription = tostring("Test Description")

return ZoneStats

The server script works exactly how I want it to work, but here it is for context:

local ReplicatedStorage = game.ReplicatedStorage
local UpdateZone = ReplicatedStorage:WaitForChild("UpdateZone")
local ZoneParts = workspace.ZoneParts

for _, v in pairs(ZoneParts:GetChildren()) do
	v.Touched:Connect(function(hit)
		local Player = game.Players:GetPlayerFromCharacter(hit.Parent)
		local Backpack = Player.Backpack
		if Backpack.CurrentZone.Value == v.Name then return end
		--print(v:GetFullName())
			if hit and hit.Parent and hit.Parent:FindFirstChild("Humanoid") then
			--print(hit:GetFullName())
			if Player == nil then return end
			Backpack.CurrentZone.Value = v.Name
			UpdateZone:FireClient(Player)
		end
	end)	
end

The problem lies within the client script in ReplicatedFirst:

local ReplicatedStorage = game.ReplicatedStorage
local ZoneModule = require(ReplicatedStorage:WaitForChild("ZoneModule"))
local ZoneData = ZoneModule.ZoneStats
local UpdateZone = ReplicatedStorage:WaitForChild("UpdateZone")
local ZoneParts = workspace.ZoneParts

function GetCurrentZone()
	for _, v in pairs(ZoneParts:GetChildren()) do
		local CurrentZone = ZoneData[v.name]
		if CurrentZone ~= nil then
			return v, CurrentZone
		else
			warn("No stats for this zone!")
		end
	end
end

UpdateZone.OnClientEvent:Connect(function()
GetCurrentZone()
-- stuff happens
end)


This is the error that it keeps throwing.
I’m drawing a blank here because I have defined ZoneData, or so I thought anyhow.
As the topic suggests, to me it appears that the module script is just not being required for some reason.
I’m assuming that there’s something about module scripts that I’m not understanding.

Any ideas?

The way you’re setting your nested table is abnormal but I believe that all you need to do to fix it is returning it!

return ZoneStats[“Test Area”]

1 Like

Odd. ZoneStats module does not have ZoneStats.ZoneStats. If you understand exactly what a module script does, the table returned from the module is on the variable already after requiring. The value is, but not the variable name from it.

I can’t do it that way because in the future there will be multiple zones in the module.
Not all of them will be ZoneStats[“Test Area”]

Have you considered using OOP? (Will probably get jumped for saying that haha)

Would that mean that I can define ZoneData as ZoneStats?
Like this:

local ZoneData = ZoneStats

That’s what I’ve gathered from what you said, but I’m not sure that’s right.

Let me clarify this again.


local ReplicatedStorage = game.ReplicatedStorage
-- This is wrong
local ZoneModule = require(ReplicatedStorage:WaitForChild("ZoneModule"))
local ZoneData = ZoneModule.ZoneStats
local UpdateZone = ReplicatedStorage:WaitForChild("UpdateZone")
local ZoneParts = workspace.ZoneParts

function GetCurrentZone()
	for _, v in pairs(ZoneParts:GetChildren()) do
		local CurrentZone = ZoneData[v.name]
		if CurrentZone ~= nil then
			return v, CurrentZone
		else
			warn("No stats for this zone!")
		end
	end
end

UpdateZone.OnClientEvent:Connect(function()
GetCurrentZone()
-- stuff happens
end)
local ReplicatedStorage = game.ReplicatedStorage
local ZoneData = require(ReplicatedStorage:WaitForChild("ZoneModule"))
local UpdateZone = ReplicatedStorage:WaitForChild("UpdateZone")
local ZoneParts = workspace.ZoneParts

function GetCurrentZone()
	for _, v in pairs(ZoneParts:GetChildren()) do
		local CurrentZone = ZoneData[v.name]
		if CurrentZone ~= nil then
			return v, CurrentZone
		else
			warn("No stats for this zone!")
		end
	end
end

UpdateZone.OnClientEvent:Connect(function()
GetCurrentZone()
-- stuff happens
end)

Compare between, a variable in a script that required a module “inherits” all of its contents.

2 Likes

That seems a tad bit ambitious for what I’m trying to accomplish…

I don’t believe so!

local StarterPack = game.StarterPack

local Zone = {}
Zone.__index = Zone

function Zone.new(name)
    return setmetatable({
        Name = name,
        FogEnd = 1000,
        FogColor = Color3.fromRGB(255,0,0),
        Ambient = Color3.fromRGB(0,0,255),
        Brightness = 0,
        Music = StarterPack.ZoneMusic.TEST,
        LocationText = tostring("Test Area"),
        LocationDescription = tostring("Test Description"),


    }, Zone)
end




return Zone


--Script

local ReplicatedStorage = game.ReplicatedStorage
local ZoneModule = require(ReplicatedStorage:WaitForChild("ZoneModule"))
local UpdateZone = ReplicatedStorage:WaitForChild("UpdateZone")
local ZoneParts = workspace.ZoneParts

function GetCurrentZone()
	for _, v in pairs(ZoneParts:GetChildren()) do
		local CurrentZone = ZoneModule.new(v.Name)
		if CurrentZone ~= nil then
			return v, CurrentZone
		else
			warn("No stats for this zone!")
		end
	end
end

UpdateZone.OnClientEvent:Connect(function()
GetCurrentZone()
-- stuff happens
end)  ```


Keep in mind that OOP is known as the worst paradigm in terms of performance, but for how you've set things up, I believe you could use this!

I see! That was the issue. Thanks!

That’s fairly interesting. How would that work with setting different stats though?

        FogEnd = 1000,
        FogColor = Color3.fromRGB(255,0,0),
        Ambient = Color3.fromRGB(0,0,255),
        Brightness = 0,
        Music = StarterPack.ZoneMusic.TEST,
        LocationText = tostring("Test Area"),
        LocationDescription = tostring("Test Description")

This is not universal across all zones. I’ll be honest though. I don’t really understand metatables all that much. They’re basically magic in my eyes. :sweat_smile:

If you expect properties to change, you can add them as an argument.

When I wrote function Zone.new(name). You can continously add new things such as lighting.

Ex:

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

function Zone.new(name, brightness)
    return setmetatable({
        Name = name,
        Brightness = brightness,
       
    }, Zone)
end

function Zone:GetName()
return self.Name --> Looks inside the metatable for an attribute named "Name" and returns the value
end

function Zone:GetBrightness()
return self.Brightness 
end
--Script

local ZoneModule = require(ReplicatedStorage:WaitForChild("ZoneModule"))

local zone = ZoneModule.new("DEF", 100)
print(zone:GetName()) --> "DEF"
print(zone:GetBrightness()) --> "DEF", "100"

local zone2 = ZoneModule.new("CAB", 200)
print(zone:GetName()) --> "CAB"
print(zone:GetBrightness()) --> "ABC", "200"

OUTPUT: 

And then when you return the metatable, you just set an attribute after the argument!

There are many tutorials on OOP, go check them out :slight_smile:. If you’d prefer me explaining it further, I could do it in DMS as I don’t want to spam this thread with information that derails from the topic.

Note: That OOP is not always the solution and actually very rarely is the solution as there are many more performant approaches, but I believe that OOP allows me to structure and think of code easier. So use it wisely!