Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
0

string.sub() and findfirstchild not working?

Asked by 7 years ago

I'm trying to make a sort of admin command type script, where you can type :moderator Player and it will grant that player moderator permissions, but when I try to index the player through game.Players:FindFirstChild(Player), it returns saying that the Player is not a valid member of game.Players.

if string.sub(chatInput.Text,1,string.len(":moderator")) == ":moderator" then
    local playerToAdd = string.sub(chatInput.Text,string.len(":moderator")+1)
    if game.Players:FindFirstChild(playerToAdd) then
        _M.addModerator(player.UserId,game.Players:FindFirstChild(playerToAdd).UserId)
        _M.getModeratorsInGame()
    else
        addMessage(player,(playerToAdd.." is not a valid member of players!"))
        print'could not find player!'
    end
end

So say if I input the text, :moderator Player1 (Player1 IS a valid member, it's me..) it will respond saying "Player1 is not a valid member of players!"

For the full script

local ContextActionService = game:GetService("ContextActionService")
local _M = require(game.ReplicatedStorage.MainModule) 

local MAX_MESSAGES = 10
local MESSAGE_HEIGHT = 25

local player = game.Players.LocalPlayer
local messages = {}
local chatMessageEvent = game.ReplicatedStorage.ChatMessage

local chatScreen = script.Parent
local chatFrame = chatScreen:WaitForChild("ChatFrame")
local chatInput = chatFrame:WaitForChild("ChatInput")
local messageFrame = chatFrame:WaitForChild("MessageFrame")

local messageTemplate = messageFrame.Message:Clone()
messageFrame.Message:Destroy()

local function findFirstChild(instance, name)
    for _, child in pairs(instance:GetChildren()) do
        if string.lower(child.Name) == string.lower(name) then
            return child
        end
    end
end

local function addMessage(sender, message)
    if #messages >= MAX_MESSAGES then
        table.remove(messages, #messages):Destroy()
    end
    for i = 1, #messages do
        local y = (MAX_MESSAGES - i - 1) * MESSAGE_HEIGHT
        messages[i].Position = UDim2.new(0, 0, 0, y)
    end 
    local newMessage = messageTemplate:Clone()
    newMessage.NameLabel.Text = "[".._M.PlayerType(game.Players.LocalPlayer.UserId).."] "..sender.Name .. ": "
    newMessage.Content.Text = message
    newMessage.Parent = messageFrame
    newMessage.Position = UDim2.new(0, 0, 0, (MAX_MESSAGES - 1) * MESSAGE_HEIGHT)
    newMessage.NameLabel.TextColor3 = _M.chatColors(_M.PlayerType(game.Players.LocalPlayer.UserId))
    newMessage.Content.TextColor3 = Color3.new(1,1,1)
    table.insert(messages, 1, newMessage)
end

local function onFocusLost(enterPressed, inputObject)
    if enterPressed then
        if string.sub(chatInput.Text,1,string.len(":moderator")) == ":moderator" then
            local playerToAdd = string.sub(chatInput.Text,string.len(":moderator")+1)
            if game.Players:FindFirstChild(playerToAdd) then
                _M.addModerator(player.UserId,game.Players:FindFirstChild(playerToAdd).UserId)
                _M.getModeratorsInGame()
            else
                addMessage(player,(playerToAdd.." is not a valid member of players!"))
                print'could not find player!'
            end
        else
            local filtered = game:GetService("Chat"):FilterStringForBroadcast(chatInput.Text,game.Players.LocalPlayer)
            addMessage(player, filtered)            
            chatMessageEvent:FireServer(filtered)
            chatInput.Text = "Click here or press '/' to type!"
        end
    end
end

local function onSlashPressed(actionName, inputState, inputObject)
    if inputState == Enum.UserInputState.End then
        chatInput:CaptureFocus()
    end
end

game.StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.Chat, false)

chatMessageEvent.OnClientEvent:connect(addMessage)
chatInput.FocusLost:connect(onFocusLost)
ContextActionService:BindAction("Chatting", onSlashPressed, false, Enum.KeyCode.Slash)

^ Taken from the tutorial, but I have changed several elements to my needs using a module script, which personally has a lot of the dataStore services and keys for them, sooo.... ^

1 answer

Log in to vote
1
Answered by
BlueTaslem 18071 Moderation Voter Administrator Community Moderator Super Administrator
7 years ago

As a style suggestion: use msg:sub(...) instead of string.sub(msg, ...) because it is much shorter. Similarly for :len(), but really you should use the # operator instead of :len().

The problem is simple; you could debug it by printing the following:

print("/" .. playerToAdd .. "/")

If you input :moderator Player, you will get the following as output:

/ Player1/

Notice that there is a an empty space between the / and Player1?

There isn't a player in the game called " Player1", there is one in the game called "Player1". You have an extra space in front.


There are several paths forward.

  1. Consider this correct, and it's the user using it wrong. You have to say moderator:Player1 with no space.

  2. Modify the pattern to search for to be "moderator: " instead of "moderator:" (with a space at the end), which would make using a singe space mandatory

  3. Actually allow any number of space characters after the :

I think (3) is the most ergonomic and reasonable option.

To accomplish it, first I want to refactor the code.

(TODO)

local moderator = chatInput.Text:match("^moderator:%s*(.+)")
if moderator then
    local player = game.Players:FindFirstChild(moderator)
Ad

Answer this question