How to set Material by string?

Hello again…

So I was trying to test an idea that came to mind about being able to place parts at the position of your cursor which is working all fine and dandy ofc. So I decided to make a more complex version of this script by allowing the player to set Materials to the part of their choice, and later on Transparency and BrickColor which seems to be way easier than Materials…

So what am I trying to achieve? I’m trying to make it so people click on one of these GUI buttons:

Which then updates this by setting a string to the Enum Material of the selected Material from the GUI which also works, and then when the player clicks it fires the server with the material name in mind:

And then when it reaches the server I’m given an error:
image

Here’s my 3 scripts:

Button Script

local MaterialModule = require(script.Parent.Parent.Parent.Modules.Materials)

local MaterialButton = script.Parent

local Material_Name_Attribute = script:GetAttribute("Material_Name")

-- Get the Config string value to override --
local MaterialValue = script.Parent.Parent.Parent.Config.Material

-- Get the ClickSound for extra effect :D --
local ClickSound = script.Parent.Parent.Click

MaterialButton.MouseButton1Click:Connect(function()
	ClickSound:Play()
	
	local toStringMaterial = tostring(MaterialModule[Material_Name_Attribute])
	
	MaterialValue.Value = toStringMaterial
end)

Click To Spawn Part Script

Player = game:GetService("Players").LocalPlayer

local ConfigurationFolder = Player.PlayerGui:WaitForChild("PartConfig").Config

local MaterialConfig = ConfigurationFolder:WaitForChild("Material").Value
local BrickColorConfig = ConfigurationFolder:WaitForChild("BrickColor").Value
local TransparencyConfig = ConfigurationFolder:WaitForChild("Transparency").Value

-- Use this to check if the player disabled part placement --
local SpawnConfig = ConfigurationFolder:WaitForChild("SpawnEnabled").Value

Mouse = Player:GetMouse()

TowerPlaceEvent = game:GetService("ReplicatedStorage").TowerPlaceEvent

Mouse.Button1Down:Connect(function(mouse)
	if not SpawnConfig then
		-- do nothing
	else
		local MousePosition = Mouse.Hit.p

		-- Tell Server to Place Specific Tower --
		TowerPlaceEvent:FireServer(MousePosition, MaterialConfig, BrickColorConfig, TransparencyConfig, SpawnConfig) -- doesn't really need SpawnConfig, but will add anyways.

		-- :)
	end
end)

TowerPlaceEvent.OnClientEvent:Connect(function()
	
	local NoGui = Player:WaitForChild("PlayerGui").No
	
	if NoGui.Enabled == true then
		-- do nothing
	else
		NoGui.Enabled = true
		local ErrorSound = NoGui.Text.Error

		NoGui.Text.Text = "Sorry but you're broke bro 😭"
		ErrorSound:Play()
		
		wait(3)
		
		NoGui.Enabled = false
	end
	
end)

And finally the server script which adapts all the information needed for this event with some other edits that didn’t seem to work either, hence why you see table.find because that was for reading the official Enumerations dev hub post

TowerPlaceEvent = game:GetService("ReplicatedStorage").TowerPlaceEvent

local Materials = require(script.Materials)

local PriceOfTower = 1

TowerPlaceEvent.OnServerEvent:Connect(function(Player, MousePosition, MaterialConfig, BrickColorConfig, TransparencyConfig, SpawnConfig)
	MyMoney = Player:WaitForChild("leaderstats").Bobux
	
	if MyMoney.Value >= 1 then
		local NewPartToPlace = Instance.new("Part")
		local SoundToPlay = Instance.new("Sound")

		SoundToPlay.SoundId = "rbxassetid://12221967"
		
		-- Set our Configurations to our Part --
		--local FoundEnum = table.find(Materials, MaterialConfig)
		NewPartToPlace.Material = table.find(Materials, MaterialConfig)
		NewPartToPlace.BrickColor = BrickColorConfig
		NewPartToPlace.Transparency = TransparencyConfig

		NewPartToPlace.Parent = workspace
		NewPartToPlace.Anchored = true
		NewPartToPlace.CanCollide = true
		NewPartToPlace.Position = MousePosition

		SoundToPlay.Parent = NewPartToPlace
		SoundToPlay:Play()
		
		MyMoney.Value = MyMoney.Value - PriceOfTower
		
	else
		TowerPlaceEvent:FireClient(Player)
		print(Player.Name.." didn't have enough money")
	end
end)

And this is the module script that both Server + Client (separate copies for each, was too lazy to move it over to ReplicatedStorage)

local Roblox_Materials = {
	
	Brick = Enum.Material.Brick,
	Cobblestone = Enum.Material.Cobblestone,
	Concrete = Enum.Material.Concrete,
	CorrodedMetal = Enum.Material.CorrodedMetal,
	DiamondPlate = Enum.Material.DiamondPlate,
	Fabric = Enum.Material.Fabric,
	Foil = Enum.Material.Foil,
	ForceField = Enum.Material.ForceField,
	Glass = Enum.Material.Glass,
	Granite = Enum.Material.Granite,
	Grass = Enum.Material.Grass,
	Ice = Enum.Material.Ice,
	Marble = Enum.Material.Marble,
	Metal = Enum.Material.Metal,
	Neon = Enum.Material.Neon,
	Pebble = Enum.Material.Pebble,
	Plastic = Enum.Material.Plastic,
	Sand = Enum.Material.Sand,
	Slate = Enum.Material.Slate,
	SmoothPlastic = Enum.Material.SmoothPlastic,
	Wood = Enum.Material.Wood,
	WoodPlanks = Enum.Material.WoodPlanks
	
}

return Roblox_Materials

Any help would be greatly appreciated on how to fix this because I’m super stumped…

Should be

NewPartToPlace.Material =  Materials[MaterialCOnfig]
1 Like

I will make this quick change and let you know if this solved it.

couldn’t you use

Enum.Material:GetEnumItems()
2 Likes

I never even knew that was a function! I typed all for nothing :pensive:

I’ll keep that in mind for next time I do something like this.

You could just make every button, on Activation they just get all the bricks to that material or what ever you want it.

1 Like

I see what you tried here, but unfortunately this goes by a similar system, such as script.Parent.Parent.

In short, it didn’t work because it tries to find the long enum title ex: Enum.Material.Cobblestone as one of the table values.

I tried replacing the Material string value that I created with just “Cobblestone” but it still errored with the exact same issue. Darn

I’m a bit confused on what you just said here.

In every button, you have a function which would start when the button is activated.

Example:

script.Parent.Activated:Connect(function()
--your code here (turn brick(s) to the material button
end

I already have this, but I don’t want to have to go inside each script to change the material that I want each button to do. I rather make it find it from a table, then set it based on one easily changable value

For context, this is what my GUI button does:

local MaterialModule = require(script.Parent.Parent.Parent.Modules.Materials)

local MaterialButton = script.Parent

local Material_Name_Attribute = script:GetAttribute("Material_Name")

-- Get the Config string value to override --
local MaterialValue = script.Parent.Parent.Parent.Config.Material

-- Get the ClickSound for extra effect :D --
local ClickSound = script.Parent.Parent.Click

MaterialButton.MouseButton1Click:Connect(function()
	ClickSound:Play()
	
	local toStringMaterial = tostring(MaterialModule[Material_Name_Attribute])
	
	MaterialValue.Value = toStringMaterial
end)

Then my spawn part script gets the Enum from the String value saved in the GUI and submits that to the server to apply with the part when spawned.

I’m heading to sleep now, I will check responses in the morning but any further help with this will be greatly appreciated in advance. Thank you

local Material = Enum.Material["InsertMaterialNameHere"]

Enum is essentially a dictionary

1 Like

Good morning! So I have decided to swap out the “Materials” dictionary that I made with a dictionary full of strings. So Plastic = "Plastic", would be my answer here as since the Enum.Material thing is a dictionary itself, I can plug the string in to get it’s actual material because apparently roblox supports that, so I’ll try sending just that over the server. I’ll post here if that fixed anything.

This method seemed to work just fine, it now applys materials, however it only does it depending on what the server sees in the “MaterialConfig” string value. So if I change it to Brick on the client then fire the server with the newly edited MaterialConfig string, it still comes out as Cobblestone. What is happening here…? It makes no sense as to why it’s doing this. Could be because of the module?

This is all fixed now! I found a working fix on the server. I fire the server with my MaterialConfig value then set the result from the client officially on the server than use that file now found on the server to index the proper material from the Enum.Material dictionary and that works just fine now:

Before:

Player = game:GetService("Players").LocalPlayer

local ConfigurationFolder = Player.PlayerGui:WaitForChild("PartConfig").Config

local MaterialConfig = ConfigurationFolder:WaitForChild("Material").Value
local BrickColorConfig = ConfigurationFolder:WaitForChild("BrickColor").Value
local TransparencyConfig = ConfigurationFolder:WaitForChild("Transparency").Value

-- Use this to check if the player disabled part placement --
local SpawnConfig = ConfigurationFolder:WaitForChild("SpawnEnabled").Value

Mouse = Player:GetMouse()

TowerPlaceEvent = game:GetService("ReplicatedStorage").TowerPlaceEvent

Mouse.Button1Down:Connect(function(mouse)
	if not SpawnConfig then
		-- do nothing
	else
		local MousePosition = Mouse.Hit.p

		-- Tell Server to Place Specific Tower --
		TowerPlaceEvent:FireServer(MousePosition, MaterialConfig, BrickColorConfig, TransparencyConfig, SpawnConfig) -- doesn't really need SpawnConfig, but will add anyways.

		-- :)
	end
end)

TowerPlaceEvent.OnClientEvent:Connect(function()
	
	local NoGui = Player:WaitForChild("PlayerGui").No
	
	if NoGui.Enabled == true then
		-- do nothing
	else
		NoGui.Enabled = true
		local ErrorSound = NoGui.Text.Error

		NoGui.Text.Text = "Sorry but you're broke bro 😭"
		ErrorSound:Play()
		
		wait(3)
		
		NoGui.Enabled = false
	end
	
end)

After fix:

Player = game:GetService("Players").LocalPlayer

Mouse = Player:GetMouse()

TowerPlaceEvent = game:GetService("ReplicatedStorage").TowerPlaceEvent

Mouse.Button1Down:Connect(function(mouse)
	
	local ConfigurationFolder = Player.PlayerGui:WaitForChild("PartConfig").Config

	local MaterialConfig = ConfigurationFolder:WaitForChild("Material").Value
	local BrickColorConfig = ConfigurationFolder:WaitForChild("BrickColor").Value
	local TransparencyConfig = ConfigurationFolder:WaitForChild("Transparency").Value

	-- Use this to check if the player disabled part placement --
	local SpawnConfig = ConfigurationFolder:WaitForChild("SpawnEnabled").Value
	
	if not SpawnConfig then
		-- do nothing
	else
		local MousePosition = Mouse.Hit.p

		-- Tell Server to Place Specific Tower --
		TowerPlaceEvent:FireServer(MousePosition, MaterialConfig, BrickColorConfig, TransparencyConfig, SpawnConfig) -- doesn't really need SpawnConfig, but will add anyways.

		-- :)
	end
end)

TowerPlaceEvent.OnClientEvent:Connect(function()
	
	local NoGui = Player:WaitForChild("PlayerGui").No
	
	if NoGui.Enabled == true then
		-- do nothing
	else
		NoGui.Enabled = true
		local ErrorSound = NoGui.Text.Error

		NoGui.Text.Text = "Sorry but you're broke bro 😭"
		ErrorSound:Play()
		
		wait(3)
		
		NoGui.Enabled = false
	end
	
end)
1 Like

Shouldn’t it be part.Material = "WoodPlanks" -- set it to whatever you want here?

EDIT: I may just be bad at this, I have never tried this out.

1 Like

This is all fixed now, but the way I wanted to do it was by using a Attribute. Each button would have an attribute that I can easily set without having to go and edit the script for each individual button, so I can keep things cleaner, hence why I used a Module script to list all Materials on Roblox then have that index the actual Enum dictionary, but I forgot to check to see if the value changed when clicked each time so it’s fixed now.

Thanks anyways!

https://gyazo.com/afb6c6ea62ec5c068510f0e0d5306e7d

1 Like