Making give tool command accept spaces

So i have this give tool command, but it doesn’t work with spaces. How can i make the tool argument accept spaces in the string? (e.g “/give player Special Tool”)

			-- Handle /give plr tool command to give players special tools
			if giveCommand then
				local args = {}

				-- Split message into individual words for command arguments
				for word in message:gmatch("%S+") do
					table.insert(args, word)
				end

				-- Parse target player and tool name
				local targetPlayerName = args[2]
				local toolName = args[3]  -- Keep original case for tool name check

				-- Determine if "all" is being used as the tool name
				local giveToAllTools = (toolName and string.lower(toolName) == "all")

				-- Look for a specific tool by matching lowercase names in toolsFolder
				local tool = nil
				if not giveToAllTools then
					for _, t in pairs(toolsFolder:GetChildren()) do
						if string.lower(t.Name) == string.lower(toolName) then
							tool = t
							break
						end
					end
				end

				-- Check if tool exists if "all" is not specified
				if not giveToAllTools and not tool then
					
					sendNotifEV:FireClient(player, "Invalid Tool", "Tool not found. Please check the name and try again.")
					return
						
				end

				-- Distribute tool based on the target player argument
				if targetPlayerName == "me" then
					-- Give tool to the player who issued the command
					if giveToAllTools then
						
						-- If "all" is specified, give all tools in the toolsFolder
						for _, t in pairs(toolsFolder:GetChildren()) do
							local clone = t:Clone()
							clone.Parent = player.Backpack
						end
						sendNotifEV:FireClient(player, "All Tools Given", "All tools were successfully awarded to you.")
					else
						local clone = tool:Clone()
						clone.Parent = player.Backpack
						sendNotifEV:FireClient(player, "Tool Given", tool.Name.." was successfully awarded to you.")
					end
					
				elseif targetPlayerName == "all" then
					-- Give all tools to all players in the aliveTeam
					for _, p in pairs(Players:GetPlayers()) do
						if p.Team == aliveTeam then
							if giveToAllTools then
								-- Give all tools to the player
								for _, t in pairs(toolsFolder:GetChildren()) do
									local clone = t:Clone()
									clone.Parent = p.Backpack
								end
							else
								local clone = tool:Clone()
								clone.Parent = p.Backpack
							end
						end
					end

					if giveToAllTools then
						sendNotifEV:FireClient(player, "All Tools Given", "All tools were successfully awarded to all players in the server.")
						sendNotifEV:FireAllClients("All Tools Given", "All tools were given to all players in the server.")
					else
						sendNotifEV:FireClient(player, "Tools Given", tool.Name.." was successfully awarded to all players in the server.")
						sendNotifEV:FireAllClients("Tools Given", tool.Name.." was given to all players in the server.")
					end
					
				else
					-- Try to find the specified target player by name
					local targetPlayer = game.Players:FindFirstChild(targetPlayerName)
					if targetPlayer and targetPlayer.Team == aliveTeam then
						if giveToAllTools then
							-- Give all tools to the specified player
							for _, t in pairs(toolsFolder:GetChildren()) do
								local clone = t:Clone()
								clone.Parent = targetPlayer.Backpack
							end
							sendNotifEV:FireClient(player, "All Tools Given", "All tools were successfully awarded to "..targetPlayer.DisplayName)
						else
							local clone = tool:Clone()
							clone.Parent = targetPlayer.Backpack
							sendNotifEV:FireClient(player, "Tool Given", tool.Name.." was successfully awarded to "..targetPlayer.DisplayName)
						end
					else
						sendNotifEV:FireClient(player, "Invalid Command", "That player or tool was not found. Make sure you aren't using their DisplayName, and that the player is alive.")
					end
				end
			end

sorry its messy :sob:

2 Likes

still cant wrap my head around this, srry

1 Like

You can split the string using string:split(" ") or string.split(string, " "). Which will return arguments that you can use.

1 Like

so where would i put this in the code? local toolName = string.split(string, " ")?

I didn’t have enough time to read all of your code, but assuming those are the arguments you would essentially replace the empty table with it.

			-- Handle /give plr tool command to give players special tools
			if giveCommand then
				local args = message:split(" ")

				-- Parse target player and tool name
				local targetPlayerName = args[2]
				local toolName = args[3]  -- Keep original case for tool name check

				-- Determine if "all" is being used as the tool name
				local giveToAllTools = (toolName and string.lower(toolName) == "all")

				-- Look for a specific tool by matching lowercase names in toolsFolder
				local tool = nil
				if not giveToAllTools then
					for _, t in pairs(toolsFolder:GetChildren()) do
						if string.lower(t.Name) == string.lower(toolName) then
							tool = t
							break
						end
					end
				end

				-- Check if tool exists if "all" is not specified
				if not giveToAllTools and not tool then
					
					sendNotifEV:FireClient(player, "Invalid Tool", "Tool not found. Please check the name and try again.")
					return
						
				end

				-- Distribute tool based on the target player argument
				if targetPlayerName == "me" then
					-- Give tool to the player who issued the command
					if giveToAllTools then
						
						-- If "all" is specified, give all tools in the toolsFolder
						for _, t in pairs(toolsFolder:GetChildren()) do
							local clone = t:Clone()
							clone.Parent = player.Backpack
						end
						sendNotifEV:FireClient(player, "All Tools Given", "All tools were successfully awarded to you.")
					else
						local clone = tool:Clone()
						clone.Parent = player.Backpack
						sendNotifEV:FireClient(player, "Tool Given", tool.Name.." was successfully awarded to you.")
					end
					
				elseif targetPlayerName == "all" then
					-- Give all tools to all players in the aliveTeam
					for _, p in pairs(Players:GetPlayers()) do
						if p.Team == aliveTeam then
							if giveToAllTools then
								-- Give all tools to the player
								for _, t in pairs(toolsFolder:GetChildren()) do
									local clone = t:Clone()
									clone.Parent = p.Backpack
								end
							else
								local clone = tool:Clone()
								clone.Parent = p.Backpack
							end
						end
					end

					if giveToAllTools then
						sendNotifEV:FireClient(player, "All Tools Given", "All tools were successfully awarded to all players in the server.")
						sendNotifEV:FireAllClients("All Tools Given", "All tools were given to all players in the server.")
					else
						sendNotifEV:FireClient(player, "Tools Given", tool.Name.." was successfully awarded to all players in the server.")
						sendNotifEV:FireAllClients("Tools Given", tool.Name.." was given to all players in the server.")
					end
					
				else
					-- Try to find the specified target player by name
					local targetPlayer = game.Players:FindFirstChild(targetPlayerName)
					if targetPlayer and targetPlayer.Team == aliveTeam then
						if giveToAllTools then
							-- Give all tools to the specified player
							for _, t in pairs(toolsFolder:GetChildren()) do
								local clone = t:Clone()
								clone.Parent = targetPlayer.Backpack
							end
							sendNotifEV:FireClient(player, "All Tools Given", "All tools were successfully awarded to "..targetPlayer.DisplayName)
						else
							local clone = tool:Clone()
							clone.Parent = targetPlayer.Backpack
							sendNotifEV:FireClient(player, "Tool Given", tool.Name.." was successfully awarded to "..targetPlayer.DisplayName)
						end
					else
						sendNotifEV:FireClient(player, "Invalid Command", "That player or tool was not found. Make sure you aren't using their DisplayName, and that the player is alive.")
					end
				end
			end
2 Likes

Concat all of the arguments.

local toolName = table.concat(Args, " ", 3, -1)
1 Like

this doesnt seem to work or error :sad:

1 Like

Would you be able to send how the callback is being called? For example a message, a specific event, etc.?

1 Like

it listens for player chat events, then it will see if it is any of the available command types

local giveCommand = string.match(message, "^/give%s+(%S+)%s+(%S+)$")

if it is, start the code for the command

1 Like

Why can’t you just do a player.Chatted event?

1 Like

it does, i just only shared the code block im having problems with.

1 Like

Have you tried removing the dollar sign? I feel like the anchor operator is useful, but not entirely used in this setting.

2 Likes

Actually, nevermind. I just realized you were using the string.match function. I will try and set up something like this in a game so that I can test it and come up with results.

2 Likes

just get the players to put an underscore (look at Minecraft commands for example). If the tool names have spaces in them then you can use string.gsub to replace the underscores with spaces

1 Like

lol thanks this works as a simple band-aid for now

if string.match(toolName, "_") then
    toolName = string.gsub(toolName, "_", " ")
end
1 Like

So basically this is what I assumed your system looked like.

This should solve the problem, but it would have to be done this way.

You can use this as an example if you want to keep your current method, but this way makes it pretty easy in my opinion to add commands and stuff. Essentially all you have to do is make a command in the “Commands” table with an array of the arguments it takes and a function in the last spot.

Here is the code. Enjoy!

local Players = game:GetService("Players")
local Storage = game:GetService("ServerStorage")
local Folder = Storage:WaitForChild("Tools")

local Prefix = "!"

local Commands = {
	["give"] = {"Player", "Tool", function(Player, Args)
		if not Player or not Player:IsA("Player") then return end
		
		local ToolName = table.concat(Args, " ")

		if ToolName == "all" then
			for _, child in pairs(Folder:GetChildren()) do
				if not child:IsA("Tool") then continue end
				
				child:Clone().Parent = Player:WaitForChild("Backpack")
			end
		end

		for _, child in pairs(Folder:GetChildren()) do
			if not child:IsA("Tool") then continue end
			
			if child.Name:lower():sub(1, #ToolName) == ToolName then 
				child:Clone().Parent = Player:WaitForChild("Backpack")

				break
			end
		end
	end;}
}

local function DoForAll(Message)
	if Message:sub(1, 1) ~= Prefix then return end

	local Splits = Message:sub(2):lower():split(" ")

	local CommandTable = Commands[Splits[1]]

	if not CommandTable then return end

	for i = 1, #CommandTable - 1 do
		if not Splits[i] then return end
	end

	if Splits[2] ~= "all" then return end

	table.remove(Splits, 1)
	table.remove(Splits, 1)

	for _, player in pairs(Players:GetPlayers()) do
		CommandTable[#CommandTable](player, Splits)
	end
end


local function ExecuteCommand(Message)
	if Message:sub(1, 1) ~= Prefix then return end

	local Splits = Message:sub(2):lower():split(" ")

	local CommandTable = Commands[Splits[1]]

	if not CommandTable then return end

	for i = 1, #CommandTable - 1 do
		if not Splits[i] then return end
	end
	
	if Splits[2] == "all" then DoForAll(Message) return end

	local Player = nil

	for _, player in pairs(Players:GetPlayers()) do
		if player.Name:lower():sub(1, #Splits[2]) ~= Splits[2] and player.DisplayName:lower():sub(1, #Splits[2]) ~= Splits[2] then continue end

		Player = player
	end

	table.remove(Splits, 1)
	table.remove(Splits, 1)

	CommandTable[#CommandTable](Player, Splits)
end

local function PlayerAdded(Player)
	Player.Chatted:Connect(function(Message)
		ExecuteCommand(Message)
	end)
end

Players.PlayerAdded:Connect(PlayerAdded)

Hope this helps!

1 Like

Here’s how i structured my code. It doesn’t work or error. What am i doing wrong?

local Commands = {
	["setDiff"] = {"Difficulty", function(Player, Args)
		local difficultyValue = tonumber(Args[1])
		if difficultyValue and difficultyValue >= 1 then
			difficulty = difficultyValue
			refreshGameForDifficulty()
			sendNotifEV:FireAllClients("Difficulty Adjustment", "The round difficulty was set to " .. difficulty .. " by " .. Player.DisplayName .. ".")
		else
			sendNotifEV:FireClient(Player, "Invalid Difficulty", "Please enter a valid difficulty level.")
		end
	end};

	["setRate"] = {"SpawnRate", function(Player, Args)
		local spawnRateValue = tonumber(Args[1])
		if spawnRateValue and spawnRateValue > 0 then
			minSpawnInterval, maxSpawnInterval = spawnRateValue, spawnRateValue
			sendNotifEV:FireAllClients("Spawn Rate Adjustment", "The zombie spawn rate was set to " .. spawnRateValue .. " by " .. Player.DisplayName .. ".")
		else
			sendNotifEV:FireClient(Player, "Invalid Spawn Rate", "Please enter a valid spawn rate.")
		end
	end};

	["resetRate"] = {"Reset", function(Player)
		minSpawnInterval = math.max(BASE_MIN_SPAWN_INTERVAL - math.log(difficulty + 1), 1)
		maxSpawnInterval = math.max(BASE_MAX_SPAWN_INTERVAL - math.log(difficulty + 1), 2)
		sendNotifEV:FireAllClients("Reset Spawn Rate", "The zombie spawn rate was reset by ".. Player.DisplayName .. ".")
	end};

	["god"] = {"Player", function(Player, Args)
		local targetPlayer = Args[1] == "me" and Player or Players:FindFirstChild(Args[1])
		if targetPlayer then
			local targetChar = targetPlayer.Character or targetPlayer.CharacterAdded:Wait()
			local ff = targetChar:FindFirstChildOfClass("ForceField")
			if ff then ff:Destroy() else Instance.new("ForceField", targetChar) end
			sendNotifEV:FireClient(targetPlayer, "Forcefield Toggled", "Your forcefield was toggled by " .. Player.DisplayName .. ".")
		else
			sendNotifEV:FireClient(Player, "Invalid Player", "Player not found.")
		end
	end};

	["give"] = {"Player", "Tool", function(Player, Args)
		local targetPlayerName, toolName = Args[1], Args[2]
		local targetPlayer = targetPlayerName == "me" and Player or Players:FindFirstChild(targetPlayerName)
		local tool = toolsFolder:FindFirstChild(toolName)
		
		if targetPlayer and tool then
			tool:Clone().Parent = targetPlayer.Backpack
			sendNotifEV:FireClient(Player, "Tool Given", toolName .. " given to " .. targetPlayer.DisplayName)
		else
			sendNotifEV:FireClient(Player, "Invalid Command", "Check player and tool name.")
		end
	end};
}

local function DoForAll(Message)
	if Message:sub(1, 1) ~= COMMAND_PREFIX then return end
	local Splits = Message:sub(2):lower():split(" ")
	local CommandTable = Commands[Splits[1]]
	if not CommandTable then return end
	for _, player in pairs(Players:GetPlayers()) do
		CommandTable[#CommandTable](player, {table.unpack(Splits, 2)})
	end
end

local function ExecuteCommand(Message, Player)
	if Message:sub(1, 1) ~= COMMAND_PREFIX then return end
	local Splits = Message:sub(2):lower():split(" ")
	local CommandTable = Commands[Splits[1]]
	if not CommandTable then return end
	table.remove(Splits, 1)
	CommandTable[#CommandTable](Player, Splits)
end

Players.PlayerAdded:Connect(function(player)
	player.Chatted:Connect(function(message)
		if player.UserId == game.CreatorId or player.UserId == game.PrivateServerOwnerId then
			ExecuteCommand(message, player)
		end
	end)
end)

Nah I was under the assumption that every single command was going to need a player.

You kind of have to edit the lines where I removed the first two arguments. Just do something like remove the first one, then use an if statement on the second one to check if u should remove another one.

Like this:

if CommandTable[1]:lower() == "player" then table.remove(Splits, 1) end

Essentially just replace the second table.remove with this. From now on, you have to make sure you are using some variation (any amount of capital or lowercase letters) when you want a player to be an arguement. For example, this command has player as an argument so I used “Player” in the table. All of this is to say don’t make “plr” an argument.

1 Like

tysm for your help guys, but i think that the underscore option is the best for me incase i want to add any more arguments to the give command :slight_smile:

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.