[HELP] Anvil disappears/hits too fast due to goofy client replication

[EDIT: I’ve found the problem, please skip to this post]

I am making an anvil, which drops from the sky and if the anvil’s base hits a player’s character, it will deal damage to them.

Anvil

This is the base -

Every other part inside the anvil has been welded to the base.

The problem is, when the anvil is dropping on top of the rig, it detects a collision and gets destroyed way too fast:

I suspect this may due to collision shenanigans, but I’m not sure how I can fix it, here’s the script:

local runService = game:GetService("RunService")
local playerService = game:GetService("Players")
local anvil: Model = workspace:WaitForChild("Anvil")
local base: Part = anvil:WaitForChild("Base") -- this is the lowest part, that should be the first to hit

task.wait(3)

local heartbeatConnection: RBXScriptConnection -- store connection here

local function onHeartbeat()
	local overlapParams = OverlapParams.new()
	overlapParams.FilterType = Enum.RaycastFilterType.Exclude -- to not detect any parts inside anvil, including base
	overlapParams.FilterDescendantsInstances = anvil:GetChildren()
	
	-- get overlapping parts
	local overlaps = workspace:GetPartBoundsInBox(base.CFrame, base.Size, overlapParams)
	
	for _, part: Part in pairs(overlaps) do
		print("Checking part "..part.Name.." which is a child of "..part.Parent.Name)
		-- some parts inside rig aren't a direct child of character, so using this instead of part.Parent for character
		local character = part:FindFirstAncestorWhichIsA("Model")
		if character:FindFirstChild("Humanoid") then
			local player = playerService:GetPlayerFromCharacter(character)
			if player or character then -- or character added for testing, in actual game anvil will only hurt players
				character.Humanoid:TakeDamage(50)
				heartbeatConnection:Disconnect()
				anvil:Destroy()
				break
			end
		end
	end
end

heartbeatConnection = runService.Heartbeat:Connect(onHeartbeat) -- run that function every frame

-- drop the anvil
for _, part: Part in anvil:GetChildren() do
	part.Anchored = false
end
4 Likes

Whoops, just realized that the video link does not work, I’m uploading to google drive and sharing the video in a bit.

EDIT: the link has been changed, you should be able to view the video now.

3 Likes

if you change this to


                character.Humanoid:TakeDamage(50)
				heartbeatConnection:Disconnect()
               task.delay(1,function()
				    anvil:Destroy()
				    break
                 end)

then it will wait 1 second (without delaying your script) and then destroy the anvil

1 Like

Wow, I didn’t realize the solution would be that simple, excluding the break from that function, it seems to work pretty well, except the player takes damage too soon:

However, I am still unsure as to why it was disappearing so soon, and why this works…

1 Like

First question - Disappearing too soon

your previous function for collision

was being called every frame (is what heartbeat does).

so when the part collided with something here

it will break instantly due to there being no delay between collision and breaking.

second question - why it works

task.Delay - Task.Delay Function Documentation

Task.delay(1,function()
-- code
end)

the number given is how long to wait, the function is what to do after.

so in this case, it delays 1 second, and then destroys the anvil.

if you want a longer delay time, just change the number “1” to something like 5

hope this helps!

So, delaying actually doesn’t solve the problem completely. I realized that the player is taking damage even before the anvil hits them. When I tried putting humanoid:TakeDamage(50) inside the delayed function, it would damage the player too late. It’s really weird.

To demonstrate the problem, I replaced the code that does all that, with code that anchors the anvil, look at what’s happening:

fyi, here's the new code

At this point, I have no idea what I’m doing wrong, please send help.

i dont exactly know what the problem is…

is the player taking damage more than once? is the damage happening too soon?

Answer to question 2

if the damaging of the player is too soon then do this – i meant too soon not delayed, sorry.

               task.delay(0.5,function()
                 -- this will wait a little longer to delay health being taken away
                -- adjust the time to how long the delay should be
                character.Humanoid:TakeDamage(50)
               end)
				heartbeatConnection:Disconnect()
               task.delay(1,function()
				    anvil:Destroy()
				    
                 end)
             break

Thanks for your help. Unfortunately, I do not think hard coding a time to delay damage and the anvil’s destruction is going to be sustainable. If I dropped the anvil from a different height, then my code would break again. It seems I’ll have to dig a little bit deeper to figure out what’s going on. I tried other methods like workspace:GetPartsInPart() too, but the result is identical. It detects a collision, while it’s not even close to the rig.

Looks like I’ve found the problem, it’s good old replication shenanigans.

Server:

Client:

The script has some changes, for debugging purposes, I’m highlighting the part that script says is the overlapping one, and also anchoring the anvil instead of destroying it.

here's the changed part of the script, rest is the same

That being said, I’m not sure how I’m supposed to deal with these replication issues, anyone know how to deal with this?

Physics seems to load on last when you test in Studio.
Try waiting for 30 seconds to be sure when you test it. There may be a big difference in what happens.
I had huge issues when trying to test a simple swinging door using a HingeConstraint and a SpringConstraint. I’d try to walk through it as soon as I hit Play Here and it would barely move.
After multiple tries and changing settings on both Constraints I realized when I spawned about 50 studs away and walked to the door it worked perfectly.
Now when I test physics parts of my game I generally wait about 10 seconds, but if it doesn’t work correctly I just wait a bit longer to see if it makes a difference.

Unfortunately, the results are the same: