I am trying to make an in-game system for banning players. I have a button that fires a remote event with a player's name and a message for why they were banned. But every time I hit the button, I get this error :
ServerScriptService.Event_Handler:21: attempt to call a nil value
I have no idea why this is not working can someone help me understand what's going wrong?
EVENT_HANDLER
local dss = game:GetService("DataStoreService")
local bands = dss:GetDataStore("banDataStore")
BanPlayer.OnServerEvent:Connect(function(player, playertoban, reason)
local pui = player.UserId
local success, errormessage = pcall(function()
bands:SetAsync("Banned-", pui, true)
end)
if success then
print("Player Successfuly Banned")
end
game.Players:FindFirstChild(playertoban):Kick(reason)
end)
Since you are searching for players by name, it's possible that you could be spelling the name wrong. In that case, game.Players:FindFirstChild() will return nil. You can sanitize this call by making sure that the player exists before calling Kick()
Also, as a side note, it looks like you are banning the player that calls the BanPlayer RemoteEvent, not the one whose name is stored in playertoban.
local dss = game:GetService("DataStoreService")
local bands = dss:GetDataStore("banDataStore")
BanPlayer.OnServerEvent:Connect(function(player, playertoban, reason)
-- check that playertoban is a real player's name
local bannedPlayer = game.Players:FindFirstChild(playertoban)
if not bannedPlayer then
warn("Could not find a player named " .. playertoban)
return
end
-- record their user-id so we can ban them when they rejoin
local pui = bannedPlayer.UserId
local success, errormessage = pcall(function()
bands:SetAsync("Banned-", pui, true)
end)
if success then
print(playertoban .. " Successfully Banned")
else
warn(string.format("Failed to ban %s permanently with error : %s", playertoban, errormessage))
end
-- remove them from the game
bannedPlayer:Kick(reason)
end)
Related
I wrote a door save system.
That is, if the user previously bought them, then when re-entering the game, they must be open.
My code works, but the door doesn't save at all.
-- DoorsDataStore
-- Save Stats Doors
local opend = false
local datastorage = game:GetService("DataStoreService")
local isitopen_1 = datastorage:GetDataStore("Door")
game.Players.PlayerAdded:Connect(function(player)
local boolValueDoors = Instance.new("Folder")
boolValueDoors.Name = "BoolValueDoors"
boolValueDoors.Parent = player
local door_1 = Instance.new("BoolValue")
door_1.Parent = boolValueDoors
door_1.Name = "BoolValueDoor_1"
door_1.Value = isitopen_1:GetAsync(player.UserId)
print("True or False")
print(player.BoolValueDoor_1.Value)
end)
game.Players.PlayerRemoving:Connect(function(player)
local success, erromsg = pcall(function()
isitopen_1:SetAsync(player.UserId, player.BoolValueDoor_1.Value)
end)
if erromsg then
warn("Error")
end
end)
-- TouchDoor
script.Parent.Touched:Connect(function(hit)
local humanoid = hit.Parent:FindFirstChild("Humanoid")
if (humanoid ~= nil) then
local player = game.Players:GetPlayerFromCharacter(hit.Parent)
if player.leaderstats.Coins.Value >= script.Parent.Price.Value then
player.leaderstats.Coins.Value -= script.Parent.Price.Value
player.leaderstats.Level.Value += 1
script.Parent:Destroy()
player.BoolValueDoors.BoolValueDoor_1.Value = true
print("Save Door")
end
end
end)
I tried writing this code in different ways, in different versions, tried through validation. My code still doesn't do what I want.
There are multiple possible problems I see:
1.
SetAsync takes a string as the first argument, you are giving it a number value. To fix this use tostring(player.UserId)
2.
When the player first joins, the value will be set to nil, because there is no data in the datastore under the UserId, and nil is not a boolean.
I’m not sure if these are actual issues and I currently cannot check if these are real problems because I’m not on my computer but they may be something you want to change.
Also it would be nice to know if you encountered any errors when executing the code.
You should also make trigger a remote event that opens the door on the clientside in the PlayerAdded function if the value is true.
This script is designed so that when you say "!kick [user]" it kicks that user from the game. But, when I test it out, nothing happens with no errors in the output box. Whats going on?
game.Players.PlayerAdded:Connect(function(player)
player.Chatted:Connect(function(player,message)
if player.Name == "playername" then
local words = string.split(message," ")
if string.lower(words[1]) == "!kick" then
words[2]:Kick("You have been kicked.")
end
end
end)
end)
Thanks
The reason nothing is happening right now is because your very first check is failing. You have the parameters for the Player.Chatted connection backwards. The message comes first and the recipient comes second. So what you've named player is actually the message and if player.Name == "playername" then is likely failing because strings don't have a Name property and player.Name is nil.
After that, the next issue you will run into is that after you've split the command into two parts, the second half of the command is still a string, and not a Player. So you need to find a Player with a matching name as the input string.
Try something like this:
local Players = game.Players
local function findPlayerByName(name)
-- escape if nothing is provided
if name == nil then
return nil
end
-- check if any players match the name provided
local allPlayers = Players:GetPlayers()
for _, player in ipairs(allPlayers) do
if player.Name == name or string.lower(player.Name) == name then
return player
end
end
-- couldn't find any players that matched
return nil
end
-- define all the players that can use commands
local admins = {
["playername"] = true,
}
Players.PlayerAdded:Connect(function(player)
player.Chatted:Connect(function(message, recipient)
if admins[player.Name] then
local words = string.split(message, " ")
local cmd = string.lower(words[1])
if cmd == "!kick" then
local playerName = words[2]
local targetPlayer = findPlayerByName(playerName)
if targetPlayer then
targetPlayer:Kick("You have been kicked.")
end
end
end
end)
end)
I have made a major part of the code, but I am stuck in the important part. Here is what I'm doing:
local Players = game:GetService("Players")
local MarketplaceService = game:GetService("MarketplaceService")
local productID = 1218445231
local productInfo = MarketplaceService:GetProductInfo(productID, Enum.InfoType.Product)
script.Parent.MouseButton1Click:Connect(function()
local function promptPurchase()
local player = Players.LocalPlayer
MarketplaceService:PromptProductPurchase(player, productID)
purchased = true
end
end)
if purchased == true then
--stuck here (if you don't understand, the tsunami that I've made is supposed to become visible and start moving towards the map, however the part is in "Workspace". The button is in "StarterGUI". Please help.)
end
EDIT: Now updated the code, still don't know what to do. Do I get the workspace Service? If so, how do I code it that it sets the transparency of the tsunami to "0", and starts moving? This is my code:
local MarketplaceService = game:GetService("MarketplaceService")
local player = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local PurchaseEvent = ReplicatedStorage.PurchaseEvent
local productID = 1218445231
script.Parent.MouseButton1Click:Connect(function()
PurchaseEvent:FireServer(productID)
end)
if MarketplaceService:PlayerOwnsAsset(1218445231) then
--Make tsunami become visible and start moving
end
In the docs for MarketplaceService, there's a note
the callback ProcessReceipt which must be well defined so that transactions do not fail.
After the purchase prompt is shown to the player, ProcessReceipt is called with the results of their choice. So that callback is how you make something happen after a user buys something.
A good structure for this kind of code is to have product purchases handled in a server Script, and to have UI elements communicate purchase intents using RemoteEvents. So do some setup :
Create a RemoteEvent in ReplicatedStorage, name it something like "PurchaseEvent"
Create a Script in ServerScriptService
Then update your LocalScript to look like this :
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local PurchaseEvent = ReplicatedStorage.PurchaseEvent
local productID = 1218445231
-- listen for when players click the button to buy the product
script.Parent.MouseButton1Click:Connect(function()
-- tell the server that we want this product
PurchaseEvent:FireServer(productID)
end)
Then add this code to the server Script to handle the purchase :
local MarketplaceService = game:GetService("MarketplaceService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local PurchaseEvent = ReplicatedStorage.PurchaseEvent
-- listen for when players want to buy things :
PurchaseEvent.OnServerEvent:Connect(function(player, productID)
-- show the purchase prompt to the user
MarketplaceService:PromptProductPurchase(player, productID)
end)
-- Define what should happen if a player buys something
-- NOTE - ADD FUNCTIONS FOR EACH SPECIFIC PRODUCT
local productHandlers = {}
productHandlers[1218445231] = function(player)
print("TODO : spawn a tsunami")
end
-- Listen for when someone clicks on any of the buttons in the purchase prompt
MarketplaceService.ProcessReceipt = function(receiptInfo)
-- Find the player who made the purchase in the server
local player = Players:GetPlayerByUserId(receiptInfo.PlayerId)
if not player then
-- The player probably left the game, don't charge them yet
return Enum.ProductPurchaseDecision.NotProcessedYet
end
-- Look up handler function from 'productHandlers' table above
local handler = productHandlers[receiptInfo.ProductId]
if not handler then
error(string.format("No handler is defined for %d", receiptInfo.ProductId))
end
-- Call the handler function and catch any errors
local success, result = pcall(handler, player)
if not success or not result then
local message = table.concat({
"Error occurred while processing a product purchase",
" - ProductId: " .. tostring(receiptInfo.ProductId),
" - Player: " .. player.Name,
}, "\n")
warn(message)
return Enum.ProductPurchaseDecision.NotProcessedYet
end
-- IMPORTANT: Tell Roblox that the game successfully handled the purchase
return Enum.ProductPurchaseDecision.PurchaseGranted
end
If you want to check if a user has bought something in the past and you don't want to charge them again, you can always check before you show the purchase prompt with the MarketplaceService:PlayerOwnsAsset function.
So I'm making a game on Roblox where you can pick up objects and sell them. however, the selling script is a normal Script (ran on the server), and I can't use
Game:GetService("Players").LocalPlayer
to find who to give the money to. the object that the user picks up has an
Owner
value, and when they touch it, it changes it to their username. so when the object touches the selling part, it looks at the owner, and gives the money to them (which is stored in a number value called Owner).
Here is my current code:
local part = script.Parent
local function onPartTouched(otherPart)--otherPart is the part that touched it
if otherPart:FindFirstChild("Owner") == nil then
else
local owner = game.Players..otherPart.Owner.Value
getowner.leaderstats.Bucks.Value = getprice.leaderstats.Bucks.Value + otherPart.Price.Value
otherPart.Parent = game.ServerStorage
end
end
part.Touched:Connect(onPartTouched)
you can just do game.Players[value.Value]
just use
Game.Players.LocalPlayer
also just writing #agents answer too in proper format.
local part = script.Parent
local function onPartTouched(otherPart)
if otherPart:FindFirstChild("Owner") == nil then
else
local owner = game.Players[otherPart.Owner.Value]
getowner.leaderstats.Bucks.Value = getprice.leaderstats.Bucks.Value +otherPart.Price.Value
otherPart.Parent = game.ServerStorage
end
end
part.Touched:Connect(onPartTouched)
I made a cash for kill script in Roblox, but wanted to go further than that and implement a script where when a player has a gamepass, then that player would recieve more cash than another normal player would.
This is for a battle royale styled game in Roblox, and when I playtested it, there were no errors, but the script didn't work.
game.Players.PlayerAdded:connect(function(player)
local folder = Instance.new("Folder",player)
folder.Name = "leaderstats"
local currency1 = Instance.new("IntValue",folder)
currency1.Name = "Cash"
local increment = 50
if game:GetService("MarketplaceService"):PlayerOwnsAsset(player,7382818)then
increment = increment + 50
end
player:WaitForChild("Humanoid").Died:connect(function()
local tag = player.Humanoid:FindFirstChild("creator")
if tag ~= nil then
local killer = tag.Value
if killer ~= nil then
-- Find the killer's leaderstats folder
local killerStats = killer:FindFirstChild("leaderstats")
if killerStats ~= nil then
-- Find the killer's Cash IntValue
local killerCash = killerStats:FindFirstChild("Cash")
-- Increase cash as before
killerCash.Value = killerCash.Value + increment
end
end
end
end)
I expected a VIP player, who has the gamepass, to receive more cash, but when I tested it, no player received any cash for killing another player at all.
How to fix an end expected error near eof
If the Lua interpreter complains about a missing end you`re missing it somewhere.
Read through your code and make sure everything that is supposed to be closed with an end has one. Read through the Lua Reference Manual to find out which keywords need an end.
In your code it's if statements and function definitions. Checking each pair from inside out you'll end up one end) short to close this game.Players.PlayerAdded:connect(function(player) as mentioned in the comments.