Keeping players in jail after attempt to rejoin

Hi everyone,

I am creating an arrest tool for my city project, but I need to know if there is a simple function in a script to teleport a player back into the ‘Incarcerated’ team after they rejoin the server during their jail time. I am asking for this because rejoining the server is a common way to break out of jail.

I snipped this from a freemodel I looked at, just to help give an idea or something:

if player:LoadBoolean("inJail" == false) then player.leaderstats["Time In Jail"].Value = 0 return end
if player:LoadNumber("TimeInJail")>1 or time > 1  then
player.TeamColor = BrickColor.new("Bright violet")
end

Is this something to do with a data store? I would like some help with this.

I’m happy to clarify more if needed. Thanks!

1 Like

Instead of recording their jailtime via the player’s leaderstats, you could record it in a dictionary on the server instead:

local players = game:GetService("Players")
local jailed = {}

--Jail function
local function jailPlayer(player)
	player.TeamColor = BrickColor.new("Bright violet")
	player:LoadCharacter()
end

--Jail player
jailed[player.Name] = true
jailPlayer(player)

--Unjail player
jailed[player.Name] = nil

--Check if player jailed when entering the game
players.PlayerAdded:Connect(function(player)
	if jailed[player.Name] then
		jailPlayer(player)
	end
end)

This would save jail information for the given server. For a global jail system, use @anon81993163 example.

2 Likes

Data Persistence is deprecated. Consider using Data Stores, through DataStoreService.

What You’ll Need


  • A table which saves the relevant data.
  • Starting data example:
local data = {
    inJail = false
    timeInJail = 0
}
  • Setting data store through DataStoreService:GetDataStore() – name the data store in the parameter
  • Assigning the “template” to player upon join.
local sessionData = {}

game:GetService("Players").PlayerAdded:Connect(function(player)
    sessionData[player.UserId] = data -- any default data and you may change the key name(but be sure you're using the same key through out all functions!)
end)
  • Make sure you load the data using DataStore:GetAsync()
  • Saving data through the signal of PlayerRemoving, method DataStore:SetAsync()
  • Upon PlayerAdded if the player has data, check its boolean and jail time. Start the timer once jailing is done.
  • Remember to wrap in pcall() for the methods from the DataStore for error handling.

Full Script Sample


local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")

local DataStore = DataStoreService:GetDataStore("cooldatastorename") -- lol
local session = {}

local function jailPlayer(player)
    player.TeamColor = BrickColor.new("Bright violet")
    player:LoadCharacter()
    spawn(function()
        while session[player.UserId]["jailTime"] >= 0 and player do -- not sure, but if player leaves at this point, is the player set nil?
            session[player.UserId]["jailTime"] = session[player.UserId]["jailTime"] - 1
            wait(1)
        end

        if player then
            session[player.UserId]["jailTime"] = 0
            player.TeamColor -- anyTeamColor that is not bright violet
        end
    end)
end

Players.PlayerAdded:Connect(function(player)
    local success, data = pcall(function()
        return DataStore:GetAsync(player.UserId)
    end)

    if success then
        if data then
            session[player.UserId] = data
            if data["jailTime"] > 0 then
               jailPlayer(player)
            end
        else
            session[player.UserId] = {jailTime = 0} -- or the starter data
        end
    else
        warn("oh no my data failed")
    end
end)

Players.PlayerRemoving:Connect(function(player)
    local success, errorMessage = pcall(function()
        DataStore:SetAsync(player.UserId, session[player.UserId])
    end)

    -- something if it fails
end)

Side note: This script is not tested yet, I have no access to Studio at the time of writing.

5 Likes

Cool, but an extra thing I might need help with is linking the script to the arrest tool (like, where to place the script and how it’s going to work.) When I learn how to properly link it to the tool, I’ll have to create a function where when you click on a player, you get a confirmation GUI, and if you click ‘Yes’, then the script you wrote activates. Thanks for your help so far.

That requires a local script which fires a RemoteEvent that sets another player’s jailTime.

This block is not sanity checked, and this is on server.

local Remote = game:GetService("ReplicatedStorage").Remote -- this is a remote event

Remote.OnServerEvent:Connect(function(player, tPlayer, timeSet)
    session[tPlayer.UserId] = timeSet
    jailPlayer(tPlayer)
end)

For the local script:

local Remote = game:GetService("ReplicatedStorage").Remote -- this is a remote event

-- some code for the UI, input and stuff
Remote:FireServer(tPlayer, timeSet) -- tPlayer as the player who will be arrested and the setTime for amount of time

Help, you’re making me miss my lunch schedule! :joy:

Do I place the data store script in ServerScriptService?

Yes, it’s obvious all server scripts should exist in ServerScriptService in order to work(sometimes they can be in Workspace, they are not limited to ServerScriptService).

Hi friend! I am here to inform you of this cool way to use pcalls!

-- Your code:
local success, data = pcall(function()
    return DataStore:GetAsync(player.UserId)
end)

-- This thing! Wow!
local success, data = pcall(DataStore.GetAsync, DataStore, player.UserId)

Nothing wrong with your current code, but I just wanted to drop in there that this is another way to use pcalls (and a preferable one too, since it directly wraps the function instead of wrapping an anonymous function - doesn’t matter though).

By the way, thank you dearly for not using “while wait do”.

That being said, one little comment: remember to clean up map entries that you no longer need. It’s good that you aren’t using player objects so you won’t have a memory leak, but seeing as you create a new entry for the player when they join, you should also clean it up when they leave.

If you were caching data to be used for the rest of the server’s uptime then that’d be a different story altogether.

ServerScriptService superseded Workspace as the canonical location for scripts, unless your script exists inside an object in the Workspace (you should still strive to keep scripts in SSS).

cc @ForeverRuffian

1 Like

If I want to make a GUI that informs the player how long they have left in jail, how can I implement that into the jailPlayer function? I’ll also need help with a basic script function in the arrest tool that ‘handcuffs’ the player (prevents them from moving while the officer is arresting them, and may also play a ‘handcuffed’ animation). Thanks!

Have the server call FireClient on a remote to tell the client how much time they have left in jail, then let the client count that number down and update the Gui in real time. Doesn’t matter if there’s a discrepancy with the time, necessarily.

Alternatively, you can have the client call InvokeServer on a RemoteFunction and have the server return the time left in jail from that invocation - accomplishes the same thing.

It’d probably be better to use the latter over the former.


That is something you’re going to have to code yourself, as Scripting Support is not a place to ask for code. It’s generous enough that Operatik actually provided a full script.

There are several open source arrest tools that you can reference for this kind of item. The main catch is that you’ll need a hitbox in your arrest tool which will allow the user to determine who exactly it is that they’re attempting to arrest. The hitbox would of course be a Touched connection.

In terms of checking what the touched item belongs to, you can check if it descends a certain character:

local Players = game:GetService("Players")

part.Touched:Connect(function (hit)
    local Target do
        for _, Player in pairs(Players:GetPlayers()) do
            if Player.Character and hit:IsDescendantOf(Player.Character) then
                Target = Player
                break
            end
        end
    -- Something
    end
end)

To make the victim play an animation, simply incorporate a line of code in the above function that makes the victim’s humanoid load the handcuffed animation and play it. Most of your code will dependent on the hitbox’s Touched function.

Preventing players from moving is fairly simple. There’s two ways I know out of many:

  • Set their WalkSpeed to 0
  • Sink their input via ContextActionService

I’m really stuck. I tried to modify some scripts from FM handcuff models, but nothing’s working in terms of the handcuff’s communication with the script that Operatik provided. :slightly_frowning_face:

Did you have a look at my solution or attempt to apply any of those concepts? Most free models are fairly outdated and don’t necessarily have the best practices, though do have salvageable code.