Module script thingy returning as nil

I am trying to make a skin system for the StarterCharacter in my game.
Sometimes when I am trying to test it, the module script thing returns as nil.

Module script:

local SkinModule = {}
local Skin1 = Instance.new("IntValue")
Skin1.Name = "Skin1"
Skin1.Parent = game.ReplicatedStorage
local Skin2 = Instance.new("IntValue")
Skin2.Name = "Skin2"
Skin2.Parent = game.ReplicatedStorage
local Skin3 = Instance.new("IntValue")
Skin3.Name = "Skin3"
Skin3.Parent = game.ReplicatedStorage
SkinModule.Skins = {
	
	["Skin1"] = {
		Skin1;
	};
	
	["Skin2"] = {
		Skin2;
	};
	
	["Skin3"] = {
		
		Skin3;
		
	};
}

SkinModule.Raritites = {
	
	["Skin1"] = 10;
	["Skin2"] = 11;
	["Skin3"] = 12;
	
	
}



SkinModule.ChooseRandomSkin = function()
	local randomNumber = math.random(1,100)
	local counter = 0
	for rarity, weight in pairs(SkinModule.Raritites) do
		counter += weight
		if randomNumber <= counter then

			local rarityTable = SkinModule.Skins[rarity]
			local chosenSkin = rarityTable[math.random(1, #rarityTable)]
			if chosenSkin == nil then
				print("Choosing skin")
				SkinModule.ChooseRandomSkin()
			else
				print("Success")
				return chosenSkin
			end
		end
	end
end


return SkinModule

Skin choosing script (I apologize if it looks really bad, this is the first time I have tried to do something like this):

game.Players.PlayerAdded:Connect(function()
	
	local acc = game.ReplicatedStorage.RandomizedAccessory
	acc.OnServerEvent:Connect(function(player)
	local skinModule = require(script.Parent.Skins)
		local skins = skinModule.ChooseRandomSkin()
		if skins == nil then
			print(skins)
			skinModule.ChooseRandomSkin()
			wait(3)
			print(skins)
		end
		if skins == "Skin1" then
			print(skins)
			print("h")
			local shirt = game.ReplicatedStorage.Shirt:Clone()
			local pants = game.ReplicatedStorage.Pants:Clone()
			local hat = game.ReplicatedStorage.Hat:Clone()
			local face = game.ReplicatedStorage.Face:Clone()
			shirt.Parent = player.Character
			pants.Parent = player.Character
			hat.Parent = player.Character:WaitForChild("Head")
			face.Parent = player.Character:WaitForChild("Head")
			hat.Handle.Position = player.Character:WaitForChild("Head").Position + Vector3.new(0,0.208,0)
		elseif skins == "Skin2" then
			print(skins)
			local shirt = game.ReplicatedStorage.Shirt2:Clone()
			local pants = game.ReplicatedStorage.Pants2:Clone()
			local hat = game.ReplicatedStorage.Hat2:Clone()
			local face = game.ReplicatedStorage.Face2:Clone()
			face.Parent = player.Character:WaitForChild("Head")
			shirt.Parent = player.Character
			pants.Parent = player.Character
			hat.Parent = player.Character:WaitForChild("Head")
			hat.Handle.Position = player.Character:WaitForChild("Head").Position + Vector3.new(0,0.208,0)
		elseif skins == "Skin3" then
			print(skins)
			local shirt = game.ReplicatedStorage.Shirt3:Clone()
			local pants = game.ReplicatedStorage.Pants3:Clone()
			local hat = game.ReplicatedStorage.Hat3:Clone()
			local face = game.ReplicatedStorage.Face3:Clone()
			face.Parent = player.Character:WaitForChild("Head")
			shirt.Parent = player.Character
			pants.Parent = player.Character
			hat.Parent = player.Character:WaitForChild("Head")
			hat.Handle.Position = player.Character:WaitForChild("Head").Position + Vector3.new(0,0.208,0)
		end
                end)
		end)

In my case, what should I define it as?

local SkinModule = { ["Skin1"] = Instance.new("IntValue",game.ReplicatedStorage),
                     ["Skin2"] = Instance.new("IntValue",game.ReplicatedStorage), 
                     ["Skin3"] = Instance.new("IntValue",game.ReplicatedStorage)

}

--Accessing these values = 

local Skin1 = SkinModule["Skin1"]

Try this

1 Like

Did this work at all? Let me know!

Am I supposed to change the parts below too? Should I change this part to this:

SkinModule.Skins = {
	
	Skin1;
	
	Skin2;
	
	Skin3;
}

Or should I change it to this:

SkinModule.Skins = {
	
	["Skin1"] = {
		Skin1;
	};
	
	["Skin2"] = {
		Skin2;
	};
	
	["Skin3"] = {
		Skin3;
	};
}

SkinModule.Skins = {

["Skin1"] = {
SkinModule["Skin1"]},

["Skin2"] = {
SkinModule["Skin2"]},

["Skin3"] = {
SkinModule["Skin3"]}
}
1 Like

It’s not working, I don’t really know why.

The same error is ocurring. Sometimes it returns as nil and sometimes it doesnt.

What do I do now? Are you still there?

What is returning nil? the Module??

or the function inside the module?

Screen Shot 2022-01-01 at 2.19.06 PM
Screen Shot 2022-01-01 at 2.19.22 PM

Oh, the function is returning nil.

For the skin module I would do this

local Skin = {}
-- the key is the skin's name and the value is the rarity
local skins = {
	Skin1 = 10,
	Skin2 = 20,
	Skin3 = 30
}

local mostCommonSkin = "Skin3"

function Skin.chooseRandomSkin()
	local randomNumber = math.random(1,100)
	local count = 0
	for skinName, rarity in pairs(skins) do
		count += rarity
		if randomNumber <= count then
			return skinName
		end
	end
	return mostCommonSkin
end

return Skin

Then in the server script I would do this

local Skin = require(script.Parent.Skin)
game.Players.PlayerAdded:Connect(function()
	local acc = game.ReplicatedStorage.RandomizedAccessory
	acc.OnServerEvent:Connect(function(player)
		local randomSkinName = Skin.chooseRandomSkin()
		
		local skinFolder = game.ServerStorage.Skins[randomSkinName]
		local shirt = skinFolder.Shirt:Clone()
		local pants = skinFolder.Pants:Clone()
		local hat = skinFolder.Hat:Clone()
		local face = skinFolder.Face:Clone()
		shirt.Parent = player.Character
		pants.Parent = player.Character
		hat.Parent = player.Character:WaitForChild("Head")
		face.Parent = player.Character:WaitForChild("Head")
		hat.Handle.Position = player.Character:WaitForChild("Head").Position + Vector3.new(0,0.208,0)
	end)
end)

You would add folders in server storage that have the assets for one skin.
Doing it this way would save you time writing the extra if statements and the code should also run faster. Although the algorithm for the randomness may not be what you want exactly.

1 Like

I think it always returns as nil so it always returns the mostCommonSkin but other than that, it works.

Is there any way to prevent it from returning as nil? It’s the entire reason I made the topic.

The reason it’s returning nil is most likely because you return chosenSkin inside

if randomNumber <= counter then

If randomNumber is never less than the counter, then it will end up returning nil because the code goes outside of the for loop instead of calling the function again. Functions return nil on default in Luau.

The solution I gave returns the mostCommonSkin the most because there is a 40% chance it will choose any other skin with the current numbers in the table and the way the randomness was coded.

I think I see what you’re trying to say, but is there any other way to do it?

I think the most simple way to do is to add a return statement outside the for loop in the function.

SkinModule.ChooseRandomSkin = function()
	local randomNumber = math.random(1,100)
	local counter = 0
	for rarity, weight in pairs(SkinModule.Raritites) do
		counter += weight
		if randomNumber <= counter then
			local rarityTable = SkinModule.Skins[rarity]
			local chosenSkin = rarityTable[math.random(1, #rarityTable)]
			print("Success")
			return chosenSkin
		end
	end
    return defaultSkin
end

The nested if statement inside of if randomNumber <= counter was removed because I don’t think chosenSkin can be nil.

2 Likes