In my efforts to reduce network latency whilst also getting server sided hit registration to work, someone had suggested to save the player avatar each frame for up to a second. So that in the future, the server can get which worldmodel was closest to the point in time when the player swung their sword, and raycast onto that instead.
The problem is, the way I had done it is extremely performance intensive, and not at all like how CloneTrooper had did it in his tweet.
-- Game services
local RunService = game:GetService("RunService")
local ServerStorage = game:GetService("ServerStorage")
local function AddModels()
for _, Characters in pairs(workspace:GetChildren()) do
if Characters:FindFirstChildWhichIsA("Humanoid") then
local WorldModel = Instance.new("WorldModel", workspace.Folder)
WorldModel.Name = Characters.Name.."_"..tostring(tick())
Characters.Archivable = true
local CharModel = Characters:Clone()
CharModel.Parent = WorldModel
CharModel.PrimaryPart.Anchored = true
for _, part in CharModel:GetDescendants() do
if part:IsA("BasePart") and part.Parent == CharModel then
part.CanCollide = false
part.Anchored = true
else
part:Destroy()
end
end
end
end
end
local function RemoveOldModels()
for _, WorldModel in pairs(workspace.Folder:GetChildren()) do
local split = WorldModel.Name:split("_")
local PrevTick = tonumber(split[2])
if tick() - PrevTick > 1 then
WorldModel:Destroy()
end
end
end
local timeConsumed = 0
RunService.Heartbeat:Connect(function(dt)
AddModels()
timeConsumed += dt
if (timeConsumed >= 1) then
RemoveOldModels()
timeConsumed = 0
end
end)
If you want to recreate my problem, put this into a script in ServerScriptService and create a folder in workspace.
I’ve never used this module before so I have some questions.
Since I need to save the state of the player avatar every frame for up to a second, would I have to created a bunch of precreated parts? How many precreated parts would I need?
And what if a new player joins, would I have to create a part cache for each individual player?
You can just play test it. One crude solution I use is to just set it to 1 precreated part and increase it whenever you get the warning. Otherwise you should be able to calculate it IDK the parameters and inputs into your current system my brain isn’t working rn.
’
I’m not sure if this is the cause, but you shouldn’t be creating a new world model per character per frame, but only one a frame for all characters;
-- Replacement for AddModels (I think this name is better)
local function CreateNewSnapshot()
local Snapshot = Instance.new("WorldModel")
Snapshot.Name = workspace.DistributedGameTime
Snapshot.Parent = ServerStorage.Snapshots
for _, Character in workspace:GetChildren() do
if not Character:FindFirstChildWhichIsA("Humanoid") then
continue
end
Character.Archivable = true;
-- Because it's a world model and we are cloning everything,
-- all of the joints SHOULD be rotated correctly.
-- And also, there's not really a point in removing extra objects since
-- WorldModels will not even attempt to interpret them.
Character:Clone().Parent = Snapshot
end
end
-- Replacement for RemoveModels (I think this name is better as well)
local function RemoveOldSnapshots()
for _, Snapshot in ServerStorage.Snapshots:GetChildren() do
local SnapshotTime = tonumber(Snapshot.Name)
if workspace.DistributedGameTime - SnapshotTime > 1 then
Snapshot:Destroy()
end
end
end
RunService.Heartbeat:Connect(function(dt)
CreateNewSnapshot()
RemoveOldSnapshots()
end)
Yeah I just don’t know what is making it so laggy, even using your suggestion, and when it’s only one player character in workspace, it runs quite poorly.
One other thing to note, the player animation doesn’t replicate to the worldmodel, unlike in CloneTrooper’s example.
So I tried your suggestion, and I have a feeling I’m using the module wrong.
Nothing in this code actually works, mostly because, whenever the player spawns in, it spawns them in the same place where the partcache are stored for whatever reason.
-- Modules
local PartCacheModule = require(script:WaitForChild("PartCache"))
local PlayerCache = {}
-- Replacement for AddModels (I think this name is better)
local function CreateNewSnapshot()
local Snapshot = Instance.new("WorldModel")
Snapshot.Name = workspace.DistributedGameTime
Snapshot.Parent = workspace.Snapshots
for _, Character in workspace:GetChildren() do
if not Character:FindFirstChildWhichIsA("Humanoid") then
continue
end
local Model = Instance.new("Model", Snapshot)
Model.Name = Character.Name
for _, part in pairs(Character:GetChildren()) do
if part:IsA("BasePart") then
local Part = PlayerCache[Character.Name][part.Name]:GetPart()
Part.Parent = Model
Part.CFrame = part.CFrame
Part.Anchored = true
Part.CanCollide = false
end
end
end
end
-- Replacement for RemoveModels (I think this name is better as well)
local function RemoveOldSnapshots()
for _, Snapshot in workspace.Snapshots:GetChildren() do
local SnapshotTime = tonumber(Snapshot.Name)
if workspace.DistributedGameTime - SnapshotTime > 1 then
for _, Character in pairs(Snapshot:GetChildren()) do
for _, Part in pairs(Character:GetChildren()) do
PlayerCache[Character.Name][Part.Name]:ReturnPart()
end
end
Snapshot:Destroy()
end
end
end
RunService.Heartbeat:Connect(function(dt)
CreateNewSnapshot()
RemoveOldSnapshots()
end)
-- Also have a start function which saves NPC character to a table too
local function CreateCache(player)
local Table = {}
player.CharacterAdded:Wait()
for _, part in pairs(player.Character:GetChildren()) do
if part:IsA("BasePart") then
local Part = part:Clone()
Table[part.Name] = PartCacheModule.new(Part, 1)
end
end
PlayerCache[player.Name] = Table
print(PlayerCache)
end
local function onPlayerAdded(player)
CreateCache(player)
end
Players.PlayerAdded:Connect(onPlayerAdded)
Are you sure this module accepts models? Because I run into this error when I changed the code.
local function CreateCache(player)
player.CharacterAdded:Wait()
PlayerCache[player.Name] = PartCacheModule.new(player.Character, 1)
print(PlayerCache)
end
local function onPlayerAdded(player)
CreateCache(player)
end
Players.PlayerAdded:Connect(onPlayerAdded)
Old post but there’s no reason to copy the entire character model. Think of it as just adding in a brand new dummy but with the player’s position and pose in that frame.