I had this idea for a moderation system that when my anti-cheat detects a player hacking it will “record a video” of when it detected it. It would work by copying everything in an certain area and then record all the data for a certain time. Then when you want to view the hacker (maybe not a hacker) you could just go to the game, do some command, let it load, and then you could watch what happened (so it replays in the game). This would provide sufficient evidence and would help get rid of all real hackers. Also it might record chat or keypresses. Please input your idea, thanks!
honestly seems good, the only issue would be recording all the data in a certain area, hackers could take advantage of that and overload the data by causing parts to spawn or som idk, since im guessing everything will be recorded on the client and then sent to the server to save to a datastore for viewing
well maybe you could just record all the stuff that the player interacts with so if they spawn stuff it cant be seen on the “recordings”
honestly seems pretty good tho, im guessing the best way to do this is:
obviously detect them and then start the recording proccess, to record; the game can save the players info, like coins, level, position, lookvector, and only neccessary info, every, lets say 0.5 to 0.25 seconds depending if the amount of info cant load fast enough, and then it will be transfered to the server via remote event, which immedietly sends the info to a datastore, which would be the players, and could maybe be called “DetectionInfo” which would hold each value in a table, then obviously if you want to load it, first you create a rig, and then make a script get each position value, and either tween to it every 0.25 to 0.5 seconds depending how long it was before, or to just teleport to it, and then it will print out each value if its changed
thanks, I was thinking about doing it on server, because the client could change all of the data to nothing
yeah its better to detect everything on the client first;
since hackers can only run things on the client anyway, and maybe even add a feature where it also records on the server to match things up to see if lets say hes supposed to have a certain amount of something, and then send it to the server
thanks for that great idea! I’ll make a client part which sends lots of detailed data (not too much) and a server part which saves low data (just enough to tell whats happening). Also why wouldn’t I want to save the data on the server, because I’m not doing any calculations, just saving cframes (and other stuff)
the only question is how would you store the recorded data. Obviously storing the “Video” using datastoreservice is impossible. encoding and decoding the data would still take up resources, but it shouldn’t matter if it’s used just to watch a playback.
the exploiter can just make it so it doesn’t send data from the client.
Make a server check, if client stopped sending important data, kick the player?
this is technically impossible without exploiting, unless the client lags so much it didn’t send the data.
OR the exploiter can send data that isn’t suspicious while still exploiting. also it’s hard to detect exploiting (except for common ones like flying or teleporting)
fair enough…
if you really need to defend the game you can prevent some injections by garbage collection (aka Citadel AC)
uhhh? cheaters usually aren’t problem if you can write safe code, make your game safe instead, learn about how remotes work and how to prevent basic exploits, creating comparison debounce or checking if player have item before saving it can be 100x better than recording video and wasting performance for this
Everyone I got it to work!!! @0786ideal @Fan_Len4ika1Tvink123 @MikeartsRBLX @p49p0 @makeitxx
The time and frames are changeable
Server script:
local DataStoreService = game:GetService("DataStoreService")
local recordStore = DataStoreService:GetDataStore("RecordStore")
local Players = game:GetService("Players")
local recordingDuration = 10 -- Record for 10 seconds
local recordingInterval = .1 -- Save data every second
local regionSize = Vector3.new(50, 50, 50) -- Define region size around cheater
-- Anti-Cheat system
local maxSpeed = 20 -- Example speed limit
local function generateUniqueId()
local random = Random.new()
return tostring(random:NextInteger(1, 100000000)) .. tostring(tick())
end
-- Function to save block and player data around a cheater
local function saveBlocksAndPlayersAroundCheater(player)
local position = player.Character.HumanoidRootPart.Position
local region = Region3.new(position - (regionSize / 2), position + (regionSize / 2))
local parts = workspace:FindPartsInRegion3(region, nil, math.huge)
local frameData = { blocks = {}, players = {} }
for _, part in ipairs(parts) do
if part:IsA("BasePart") then
-- Generate a unique ID for each part if it doesn't have one already
part:SetAttribute("UniqueId", part:GetAttribute("UniqueId") or generateUniqueId())
-- Get the mesh if the part has one (MeshPart or SpecialMesh)
local meshId, meshType, textureId
if part:IsA("MeshPart") then
meshId = part.MeshId
textureId = part.TextureID
elseif part:FindFirstChild("SpecialMesh") then
local mesh = part:FindFirstChild("SpecialMesh")
meshId = mesh.MeshId
meshType = mesh.MeshType.Name
textureId = mesh.TextureId
end
-- Save part properties, including the unique ID
table.insert(frameData.blocks, {
uniqueId = part:GetAttribute("UniqueId"), -- Save the unique ID
name = part.Name,
size = {part.Size.X, part.Size.Y, part.Size.Z},
position = {part.Position.X, part.Position.Y, part.Position.Z},
color = part.BrickColor.Name,
material = part.Material.Name,
transparency = part.Transparency,
reflectance = part.Reflectance,
meshId = meshId,
textureId = textureId,
meshType = meshType
})
end
-- Save player information
if part.Parent:FindFirstChild("Humanoid") then
local playerName = part.Parent.Name
if not table.find(frameData.players, playerName) then
table.insert(frameData.players, playerName)
end
end
end
return frameData
end
-- Function to start recording after detecting a cheater
local function startRecording(player)
local data = {}
local startTime = tick()
while tick() - startTime < recordingDuration do
-- Save block and player data
local frameData = saveBlocksAndPlayersAroundCheater(player)
table.insert(data, frameData)
wait(recordingInterval)
end
-- Save data to DataStore after recording
local success, err = pcall(function()
recordStore:SetAsync(player.Name, data)
end)
if success then
print("Recording saved successfully!")
else
warn("Error saving data: " .. err)
end
end
-- Anti-Cheat: Detect if player is cheating by exceeding speed limit
Players.PlayerAdded:Connect(function(player)
player.CharacterAdded:Connect(function(character)
local humanoid = character:WaitForChild("Humanoid")
while humanoid do
if humanoid.WalkSpeed > maxSpeed then
print(player.Name .. " is possibly hacking!")
startRecording(player)
end
wait(1)
end
end)
end)
-- Function to load recording data from DataStore
local function loadRecording(player)
local success, data = pcall(function()
return recordStore:GetAsync(player.Name)
end)
if success and data then
print("Recording loaded successfully!")
return data
else
warn("Error loading data or no recording found.")
return nil
end
end
-- Chat command to load recording
Players.PlayerAdded:Connect(function(player)
player.Chatted:Connect(function(message)
if message == "!load" then
local data = loadRecording(player)
if data then
-- Send data to the player's client to start playback
game.ReplicatedStorage:WaitForChild("PlaybackControl"):FireClient(player, data)
end
end
end)
end)
Local script (to render it):
local currentFrame = 1
local isPaused = false
local data = {} -- Will be populated with the loaded recording data
-- Clear all parts
function clearParts(loadedParts) -- Changed from local to global
-- Ensure loadedParts is a table
if loadedParts == nil then
warn("loadedParts is nil, expected a table.")
return -- Exit the function if loadedParts is nil
end
for _, part in pairs(workspace:GetChildren()) do
-- Check if the part's UniqueId matches any in the loadedParts
if part:IsA("BasePart") and table.find(loadedParts, part:GetAttribute("UniqueId")) then
part:Destroy()
end
end
end
-- Pause playback
function pausePlayback()
isPaused = true
end
-- Play playback
function playPlayback()
isPaused = false
startPlayback(data) -- Resume where it left off
end
-- Create parts from frame data
function createParts(frameData)
for _, partInfo in pairs(frameData.blocks) do
-- Check if a part with the same UniqueId exists
local partExists = false
for _, existingPart in pairs(workspace:GetChildren()) do
if existingPart:IsA("BasePart") and existingPart:GetAttribute("UniqueId") == partInfo.uniqueId then
partExists = true
break
end
end
-- Only create the part if it doesn't already exist
if not partExists then
local part = Instance.new("Part")
-- Apply saved properties
part.Size = Vector3.new(partInfo.size[1], partInfo.size[2], partInfo.size[3])
part.Position = Vector3.new(partInfo.position[1], partInfo.position[2], partInfo.position[3])
part.BrickColor = BrickColor.new(partInfo.color)
part.Material = Enum.Material[partInfo.material]
part.Transparency = partInfo.transparency
part.Reflectance = partInfo.reflectance
part.Anchored = true -- Ensure the part is anchored
-- Handle mesh properties
if partInfo.meshId then
if part:IsA("MeshPart") then
part.MeshId = partInfo.meshId
part.TextureID = partInfo.textureId
else
local mesh = Instance.new("SpecialMesh", part)
mesh.MeshId = partInfo.meshId
if partInfo.meshType then
mesh.MeshType = Enum.MeshType[partInfo.meshType]
end
mesh.TextureId = partInfo.textureId
end
end
-- Assign the unique ID to the new part
part:SetAttribute("UniqueId", partInfo.uniqueId)
part.Parent = workspace
end
end
end
-- Start playback
function startPlayback(data)
currentFrame = 1
while currentFrame <= #data and not isPaused do
-- Collect the unique IDs from the current frame's data
local loadedParts = {}
for _, partInfo in ipairs(data[currentFrame].blocks) do
table.insert(loadedParts, partInfo.uniqueId)
end
clearParts(loadedParts) -- Pass the loadedParts to clearParts
createParts(data[currentFrame]) -- Create parts for the current frame
wait(0.1) -- Frame delay, adjust as needed
currentFrame = currentFrame + 1
end
end
-- Next frame
function nextFrame()
if currentFrame < #data then
-- Collect unique IDs for the current frame
local loadedParts = {}
for _, partInfo in ipairs(data[currentFrame].blocks) do
table.insert(loadedParts, partInfo.uniqueId)
end
clearParts(loadedParts) -- Pass the loadedParts to clearParts
currentFrame = currentFrame + 1 -- Move to the next frame
clearParts(loadedParts) -- Pass the loadedParts to clearParts
createParts(data[currentFrame]) -- Create parts for the new current frame
end
end
-- Previous frame
function backFrame()
if currentFrame > 1 then
-- Collect unique IDs for the current frame
local loadedParts = {}
for _, partInfo in ipairs(data[currentFrame].blocks) do
table.insert(loadedParts, partInfo.uniqueId)
end
clearParts(loadedParts) -- Pass the loadedParts to clearParts
currentFrame = currentFrame - 1 -- Move to the previous frame
clearParts(loadedParts) -- Pass the loadedParts to clearParts
createParts(data[currentFrame]) -- Create parts for the new current frame
end
end
-- Setup button events (GUI button events)
local playButton = script.Parent:WaitForChild("Play")
local pauseButton = script.Parent:WaitForChild("Pause")
local nextButton = script.Parent:WaitForChild("Forward")
local backButton = script.Parent:WaitForChild("Backward")
playButton.MouseButton1Click:Connect(playPlayback)
pauseButton.MouseButton1Click:Connect(pausePlayback)
nextButton.MouseButton1Click:Connect(nextFrame)
backButton.MouseButton1Click:Connect(backFrame)
-- Handle playback control data from server
game.ReplicatedStorage:WaitForChild("PlaybackControl").OnClientEvent:Connect(function(recordingData)
data = recordingData
startPlayback(data)
end)
I’ll be adding more, mostly fixing somethings
also I know the anti cheat doesn’t work (it checks for server value). I’m just using it to test
i think that’s a great idea mate.
i feel like if you were doing it video related it would impact performance of the game a lot more but i could be wrong. my idea is that you could clone the character model of every player in the game; only viewable for you as the owner and focus the camera mode to that hacker’s character model upon command request. (:view player_charactermodel)
i suppose then you could store the CFrame with the time using math.osclock or something. the CFrame will store the players rotation and position so that you can see if they’re flying, etc.
that’s just my idea and how i would go about it. hopefully it helps!
there’s a tutorial on how you would do something like this:
wow, thanks a lot! I think about this