i see youve got it to work, looks really good
Hmm, I can’t get it to work
My script (changed it so it’s only one server script):
-- Services
local DataStoreService = game:GetService("DataStoreService")
local recordStore = DataStoreService:GetDataStore("RecordStore")
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")
-- Constants
local MAX_CHUNK_SIZE = 500000 -- Define a safe chunk size well below 4MB
-- Variables
local Possessions = {}
local replaying = false
local recording
local regionSize = Vector3.new(50, 50, 50)
local Tracked = {}
-- Unique ID generator
local function generateUniqueId()
return tostring(math.random(100000, 999999))
end
-- Function to save blocks and players in an area
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
if not Tracked[part] then
Tracked[part] = true
end
part:SetAttribute("UniqueId", part:GetAttribute("UniqueId") or generateUniqueId())
table.insert(frameData.blocks, {
uniqueId = part:GetAttribute("UniqueId"),
name = part.Name,
size = {part.Size.X, part.Size.Y, part.Size.Z},
position = {part.Position.X, part.Position.Y, part.Position.Z},
rotation = {part.Orientation.X, part.Orientation.Y, part.Orientation.Z},
color = part.BrickColor.Name,
material = part.Material.Name,
transparency = part.Transparency,
reflectance = part.Reflectance
})
end
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 disable joints and anchor parts
local function disableJoints(rig)
for _, v in pairs(rig:GetDescendants()) do
if v:IsA("JointInstance") then
if v.Part0.Parent ~= rig or v.Part1.Parent ~= rig then
continue
end
v.Enabled = false
elseif v:IsA("BasePart") and v.Parent == rig then
v.Anchored = true
v.CanCollide = false
end
end
end
-- Function to start replay
local function startReplay(currentPossession)
if recording or replaying or currentPossession > #Possessions then
return
end
replaying = true
local Models = {}
local tb = Possessions[currentPossession]
for part, _ in pairs(Tracked) do
part.Archivable = true
local rig = part:Clone()
rig.Parent = workspace
disableJoints(rig)
part.Archivable = false
Models[part.Name] = rig
end
for _, gotPossession in pairs(tb) do
for character, bodyParts in pairs(gotPossession) do
if typeof(bodyParts) == "CFrame" then
Models[character].CFrame = bodyParts
else
for i, v in pairs(bodyParts) do
Models[character][i].CFrame = v
end
end
end
wait()
end
for _, v in pairs(Models) do
v:Destroy()
end
Models = nil
replaying = false
end
-- Function to start recording
local function startRecording(player)
if replaying then return end
if recording then
recording:Disconnect()
recording = nil
print("Recording stopped")
return
end
Possessions[#Possessions + 1] = {}
print("Recording started")
local time = 0
recording = RunService.Heartbeat:Connect(function()
local frameData = saveBlocksAndPlayersAroundCheater(player)
Possessions[#Possessions][time] = frameData
time += 1
end)
end
-- Function to split data into chunks for DataStore
local function splitIntoChunks(data)
local jsonData = game:GetService("HttpService"):JSONEncode(data)
local chunks = {}
for i = 1, #jsonData, MAX_CHUNK_SIZE do
local chunk = jsonData:sub(i, math.min(i + MAX_CHUNK_SIZE - 1, #jsonData))
table.insert(chunks, chunk)
end
return chunks
end
-- Function to save the recording to DataStore in chunks
local function saveRecording(name)
local success, err = pcall(function()
local chunks = splitIntoChunks(Possessions)
-- Save each chunk with a unique key
for i, chunk in ipairs(chunks) do
recordStore:SetAsync(name .. "_Chunk_" .. i, chunk)
end
-- Save the number of chunks
recordStore:SetAsync(name .. "_Meta", { chunkCount = #chunks })
end)
if success then
print("Recording saved as", name)
else
warn("Error saving recording:", err)
end
end
-- Function to load the recording from DataStore in chunks
local function loadRecording(name)
local success, data = pcall(function()
local meta = recordStore:GetAsync(name .. "_Meta")
if not meta then
warn("No metadata found for recording:", name)
return nil
end
local chunks = {}
for i = 1, meta.chunkCount do
local chunk = recordStore:GetAsync(name .. "_Chunk_" .. i)
if chunk then
table.insert(chunks, chunk)
end
end
-- Concatenate all chunks and decode JSON
local jsonData = table.concat(chunks)
return game:GetService("HttpService"):JSONDecode(jsonData)
end)
if success then
Possessions = data or {}
print("Recording loaded:", name)
else
warn("Error loading recording:", data)
end
end
-- Chat commands for saving and loading
Players.PlayerAdded:Connect(function(player)
player.Chatted:Connect(function(message)
local command, arg = string.match(message, "/(%w+)%s?(.*)")
if command == "saverecording" then
saveRecording(arg)
elseif command == "loadrecording" then
loadRecording(arg)
elseif command == "startrecording" then
startRecording(player)
elseif command == "stoprecording" then
if recording then
recording:Disconnect()
recording = nil
print("Recording stopped")
end
end
end)
end)
Thanks!
Forgot to say the error, It prints everything (to record, stop, save, load), but it never loads and plays the thing recorded @makeitxx
This is a horrible idea lol. Really popular games on Roblox just run basic server sided checks on objectives in your game that need to be protected. You can narrow your anti cheat down to something as basic as a player having too much of an item or a statistic which is always 1000% trackable. This is just totally unnecessary. Example: Instead of recording a video of a cheater using fly hacks in an obby with 1000 checkpoints, you can just check how long it took them to finish the 1000 checkpoints and if they completed it too quickly you can kick and/or ban them.
It’s because it’s a better way to make sure there’s no false positives. I wish roblox had cursing
i was replying to his post based on his concept. its obvious im already aware of all that lol. i would do it that way as well
Just so you all know I’m still going to use an anti cheat, I’m making this so I can check if they were actually cheating. Also It’s for inappropriate/rule breaking people in my game not just hackers.