String.sub not working!

Hi, I’m making a feature for admins where they type in chat

/a Hi this is an announcement

and then players near the admin will receive a gui that shows the announcement text.

I’m having trouble because it’s not working

--Event Variable
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local announceevent = Instance.new("RemoteFunction")
announceevent.Name = "AnnounceEvent"
announceevent.Parent = ReplicatedStorage
--

game.Players.PlayerAdded:connect(function(p)
p.Chatted:connect(function(message)
	
--Detection
        if string.sub(message,1,3) == "/a " then
	    if p.Name == "ZacBytes" then
		
--Triggered
local atext = string.sub(message,4)
print(atext)

--Call Event
for _, player in pairs(game.Players:GetPlayers()) do
	if player.Character and player:DistanceFromCharacter(p.Character.Head.Position) < 100 then
announceevent:InvokeClient(player,atext)
    end
end
--

        end
		end

end)
end)

Error:
string expected, got nil

Could you fix the formatting and state the line?

2 Likes

Could you also include your code for the announceevent RemoteFunction if the error is coming from there?

This isn’t going to be a helpful reply, but for security reasons I’d recommend not using InvokeClient(), as malicious players can hang the server by tampering with their LocalScripts.

On topic, though, you should change

for _, player in pairs(game.Players:GetPlayers()) do
	if player.Character and player:DistanceFromCharacter(p.Character.Head.Position) < 100 then
          announceevent:InvokeClient(player,atext)
    end
end

to run in a coroutine or spawn. The way you have it set will yield for every player it finds within 100 studs. You could do something like this;

for _, player in pairs(game.Players:GetPlayers()) do
   coroutine.resume(coroutine.create(function()
      	if player.Character and player:DistanceFromCharacter(p.Character.Head.Position) < 100 then
           announceevent:InvokeClient(player,atext)
       end
   end))
end

This might not fix it but it’s a start.

1 Like

There’s a couple issues with both your code and your thread.

Thread:

  • Lack of information to work off of - what’s at work with your remotes?
  • No indication that solutions were prior attempted or searched for.
  • Error as a comment rather than a screenshot of the Developer Console. What line is your issue at?

Code:

  • Indenting is bad (sorry chief, going to be blunt with you)
  • Using “player.Name” as a player check (use UserId instead, or Players::GetUserIdFromNameAsync)
  • Running this Chatted function for every single player that chats
  • Putting your player check in after the Chatted event fires and the message is processed

Can’t provide solutions without the appropriate pre-post measures being taken.

6 Likes

There are two for what is causing this issue:

  • message is somehow nil
  • The code bound to announceevent's OnClientInvoke property is what is erroring, and not the code you provided

I recommend to find the solution, you use prints to find out what exactly the value of message is, and also to take a look at your client-side code (put it on here too so we can help).


Selecting and quoting is broken for me right now so I’ll mention you instead @colbert2677

  • Using “player.Name” as a player check (use UserId instead, or Players::GetUserIdFromNameAsync)

To explain, the issue with using names is that players can change their names. If you change your name, you’ll need to go into this code and update it manually – if you used your user ID you’d never need to think about it again. Another player could get admin permissions if they had your old name and you didn’t update the script, either. For this reason, :GetUserIdFromNameAsync() isn’t a valid solution if this correct player identification is what you’re going for, as it still relies on the player’s name.

As for actually implementing user ID, it’s pretty straightforward and similar to using names. If you don’t how, you can easily get your user ID to put in a script like this by going to your profile page and copying the number in the URL: https://www.roblox.com/users/000000/profile.

  • Running this Chatted function for every single player that chats
  • Putting your player check in after the Chatted event fires and the message is processed

Yep, the solution to this here is vaguely implied so I’ll clarify it – the solution to this would be to check who the player is before you make the connection instead of within it. So if a player is the game owner, listen for the Chatted event, instead of the other way around.

Also, what are pre-post measures? You mean the issues with the thread that need to be fixed?

1 Like

Kind of. They were more in reference to the lack of information to work from on the thread.

1 Like

A player can’t use your old username. The only time you’d need to account for player usernames is if a Microsoft user for XBox One had a gamertag matching your name. As well, the function accepts old usernames. Put “colbert2677” as an argument (my current name) and you’ll get 6809102. Put “SentientCrow” (one of my past usernames) and you’ll get 6809102. A username gets permanently associated with a UserId, whether that’s from a sign up or bought username change.

1 Like

Huh, weird, that behavior is good. My bad then, I swear it used to be free for all lol

image

:ok_hand:

2 Likes

Seems to be formatted on my screen so I’m not sure

Error is in this section, line 13, the first string.sub

I’ll try to get the screenshots

1 Like

@Darkmist101 is referring to the poor indentation (your ends are all over the place), Try print()ing where you need to figure out at what point the message stops going through. Is this the exact same code you have in Studio?

1 Like

Sorry it’s just my personal preference of indenting lol

Thanks for all the replies, I added a wait for character and seems to be working now, silly me