Hello, I have a serious issue with our game (Stand Proud - Roblox) related to network ownerships. It randomly started on 08/27/2023. I tried reverting to older versions of my game to check if this was due anything within our code but it still happened. All of the previous versions of the game are currently permanently bugged and it seems to be due to a Roblox error which has made our game go from 1k CCU to less than 200 CCU as it’s barely playable anymore.
Our community server and group wall is filled with people discussing this bug, where the NetworkOwnership of custom characters (stands) keep getting set to the server which causes a lot of issues. Our game has “Stands” as custom characters and the network ownership of these is set to the player they belong to. We use AlignPosition and AlignOrientation to control their movement and rotation.
So, how does this bug happen? There are three ways to replicate it:
-
Join into the game and select a stand and it randomly happens.
-
During PVP/or just walking around, it happens out of no where. Rare occasion but still breaks the game.
-
Use the Barrage ability. The issue is this multiple arms effect that we have, this isn’t possible anymore as we “patched” it but we have NO clue how this was fixed, but basically, if you set the “task.delay(.25)” to literally any number higher like 0.3, it messes with the network ownership of the stand HumanoidRootPart
Some videos:
https://gyazo.com/2914f4ea406e5ed65df519edfbef0223.mp4
The barrage FX script:
local function quadBezier(p1, p2, p3, t)
return (1 - t)^2 * p1 + 2 * (1 - t) * t * p2 + t^2 * p3
end
FX["Barrage"] = function(Character, Duration, Stretch, Length, Stand, StandName, cfr, kicks)
local CFR = if cfr then cfr else Character.HumanoidRootPart.CFrame
local Stretch = Stretch or 1
for i = 1, 2 do
local lookTo = (CFR * CFrame.new(0,0,-10)).Position
local P1, P2
local Arm
local function Point(Side)
local rand1
if Side == "Right" then
rand1 = math.random(5,40) / 10 * Stretch
else
rand1 = math.random(-40, -5) / 10 * Stretch
end
local rand2 = math.random(-60,60) / 100 * Stretch
local rand3 = math.random()
local p1 = (CFR * CFrame.new(rand1,rand2,-2)).Position
local p2 = (CFR * CFrame.new(rand1 * 2,rand2 * 6,-4)).Position
return p1,p2
end
if math.random(10) > 5 then
local CharacterArm = game.ReplicatedStorage.Stands.Arms[StandName..if kicks then "Right Leg" else "Right Arm"]:Clone()
Arm = CharacterArm:Clone()
Arm.Parent = workspace.Visuals
Arm.Anchored = false
P1, P2 = Point("Right")
else
local CharacterArm = game.ReplicatedStorage.Stands.Arms[StandName..if kicks then "Left Leg" else "Left Arm"]:Clone()
Arm = CharacterArm:Clone()
Arm.Parent = workspace.Visuals
Arm.Anchored = false
P1, P2 = Point("Left")
end
local tA = Instance.new("Attachment")
tA.Parent = Arm
tA.Position = Vector3.new(-0.394,0.793,0.477)
local bA = Instance.new("Attachment")
bA.Parent = Arm
bA.Position = Vector3.new(0.329, -0.847, -0.348)
local trail = script["MotionBlur"..math.random(1,2)]:Clone()
trail.Attachment0 = tA
trail.Attachment1 = bA
trail.Color = ColorSequence.new{
ColorSequenceKeypoint.new(0, Arm.Color),
ColorSequenceKeypoint.new(1, Arm.Color)
}
trail.Enabled = true
trail.Parent = Arm
Arm.Transparency = 1
local count = 0
local Connection
local Duration = Duration or 0.7
local Rate = 1/Duration
task.delay(.2, function()
for i,v in pairs(Arm:GetChildren()) do
if v:IsA("BasePart") or v:IsA("MeshPart") then
v.Transparency = 1
end
for i,f in pairs(v:GetChildren()) do
if f:IsA("BasePart") or f:IsA("MeshPart") then
TweenService:Create(f, TweenInfo.new(0.2), {Transparency = 1}):Play()
end
end
end
Arm.Transparency = 1
trail.Enabled = false
task.delay(.3, function()
Arm:Destroy()
end)
end)
Connection = RunService.Heartbeat:Connect(function(r)
count += r * Rate
if count > 1 then
Connection:Disconnect()
count = 1
end
if count + r * Rate <= 0.8 then
local val = TweenService:GetValue(count, Enum.EasingStyle.Cubic, Enum.EasingDirection.Out)
local nextVal = TweenService:GetValue(count + r * Rate, Enum.EasingStyle.Cubic, Enum.EasingDirection.Out)
local pos = quadBezier(P1, P2, lookTo, val)
local nextPos = quadBezier(P1, P2, lookTo, nextVal)
Arm.CFrame = CFrame.new(pos, nextPos) * CFrame.Angles(math.rad(90),math.rad(0),math.rad(0))
else
local val = TweenService:GetValue(count, Enum.EasingStyle.Cubic, Enum.EasingDirection.Out)
local pos = quadBezier(P1, P2, lookTo, val)
Arm.CFrame = CFrame.new(pos, lookTo) * CFrame.Angles(math.rad(90),math.rad(0),math.rad(0))
end
end)
end
end
One of the reasons why we are so focused on this barrage arms script is because it’s been our only form of replication of this bug, and yes, in the game right now the task.delay is set to .25 instead of .3, which does help reduce the frequency of this bug happening. It still doesn’t explain how it happens anywhere else, it is the the only clue we have and we would really appreciate to know how this happened, so that this “fix” can applied to the rest of the game’s scripts.
This causes a lot of strange issues, where the position of the HumanoidRootPart of the “stand”, in this case being the custom character is set to nan,nan,nan. The CurrentCamera’s CFrame is set to nan,nan,nan as well, disabling all shadows and making the camera stuck. I have tried setting the network ownership back to the owner through a loop manually, but the issue still persists and it seems like the network ownership is changed every frame automatically.
This issue was encountered by other people, such as:
I couldn’t find a proper cause or solution yet. Any help is greatly appreciated!