Making a Crate break only on Player's Client

What I want to achieve:
Make it so a crate is only broken on the client, not being replicated to other clients.

Issue:
The crate is being destroyed on all clients.

Notes:

  • The game has StreamingEnabled on.
  • The Crate’s Model is Tagged with the “BreakableCrate” Tag.
    • The Model’s ModelStreamingMode is Atomic.
  • There is a table that is updated when the player enters a new world/level. And, it’s also supposed to update when Roblox’s API for tags loading in are detected through GetInstanceAddedSignal and GetInstanceRemovedSignal.
  • The code is inside a LocalScript, located under StarterGui.
    image

Code:

Click to open
local CollectionService = game:GetService("CollectionService")
local PlayerEnteredAWorld_RemoteEvent = game.Workspace.RemoteEventsFolder.PlayerEnteredAWorld_RemoteEvent
local tagForThisScript = "BreakableCrate"
---
local UseHapticFeedback = game.Workspace.RemoteEventsFolder.UseHapticFeedback
local item_dropped_by_crate = game.ReplicatedStorage.Coin
---
-----

local objectsLoadedIn_Table: {Part} = {}

local function listUpdatedFireFuncion()
	
	print("listUpdatedFireFuncion fired!")
	
	for i, objectModel_v in pairs(objectsLoadedIn_Table) do

		local objectDebounce = false
		local hitbox
		local hitbox_b
		local BreakingSound
		local WorldThisObjectModelIsIn

		local success, errorMessage = pcall(function()

			hitbox = objectModel_v:FindFirstChild("hitbox")
			hitbox_b = objectModel_v:FindFirstChild("hitbox_b")
			BreakingSound = objectModel_v:FindFirstChild("BreakingSound")
			WorldThisObjectModelIsIn = objectModel_v:FindFirstChild("WorldThisObjectModelIsIn")

		end)

		print(success,errorMessage)

		-- if the object is loaded in where the script can run properly, meaning that the..
		-- script can find all parts that should be loaded in, then success.

		if success then

			local function resetObjectModelLogic()

				objectDebounce = false

				for i, v in pairs(objectModel_v:GetDescendants()) do
					if v:IsA("Decal") or v:IsA("MeshPart") then
						v.LocalTransparencyModifier = 0
					end
				end

				objectModel_v.mainBoxBit.CanCollide = true

			end

			hitbox.Touched:Connect(function(hit)
				if game.Players:GetPlayerFromCharacter(hit.Parent) then
					if objectDebounce == false and hit.Parent.Animate.playerIsSprintingBoolValue.Value == true  then
						objectDebounce = true
						
						
						for i, v in pairs(objectModel_v:GetDescendants()) do
							if v:IsA("Decal") or v:IsA("MeshPart") then
								v.LocalTransparencyModifier = 1
							end
						end

						objectModel_v.mainBoxBit.CanCollide = false

						print(hit.Parent.Name.." sprinted into the crate!")

						BreakingSound.PlaybackSpeed = 4
						BreakingSound:Play()

						local howLongShouldTheRumbleLast = 0.185
						local howIntenseShouldTheRumbleBe = 0.25
						local whatMotorShouldBeMoving = Enum.VibrationMotor.Large
						UseHapticFeedback:FireServer(whatMotorShouldBeMoving,howLongShouldTheRumbleLast,howIntenseShouldTheRumbleBe)

						hitbox_b.woodPlankParticle.Enabled = true
						task.wait(0.6)
						hitbox_b.woodPlankParticle.Enabled = false

						local clone_of_item_dropped_by_crate = item_dropped_by_crate:Clone()
						clone_of_item_dropped_by_crate.Parent = game.Workspace
						clone_of_item_dropped_by_crate.hitbox.CFrame = hitbox_b.CFrame
						clone_of_item_dropped_by_crate.mainCoin.CFrame = hitbox_b.CFrame

						CollectionService:AddTag(clone_of_item_dropped_by_crate,"Coin")

					end


				end

			end)

			PlayerEnteredAWorld_RemoteEvent.OnClientEvent:Connect(function(whatWorldDidThePlayerEnter)
				if WorldThisObjectModelIsIn.Value == whatWorldDidThePlayerEnter then

					if objectDebounce == false then
						resetObjectModelLogic()
					end

				end
			end)


		end

	end


end

-- gets loaded parts:
for _, taggedObject in pairs(CollectionService:GetTagged(tagForThisScript)) do
	table.insert(objectsLoadedIn_Table, taggedObject :: Part)
	listUpdatedFireFuncion()
end

-- to get future parts:
CollectionService:GetInstanceAddedSignal(tagForThisScript):Connect(function(newpart: Part)
	print(newpart:GetFullName())
	if table.find(objectsLoadedIn_Table, newpart) == nil then
		table.insert(objectsLoadedIn_Table, newpart)
		listUpdatedFireFuncion()
	end
end)

-- to remove parts as they are unloaded:
CollectionService:GetInstanceRemovedSignal(tagForThisScript):Connect(function(oldpart: Part)
	local index = table.find(objectsLoadedIn_Table, oldpart)
	if index then
		table.remove(objectsLoadedIn_Table, index)
	end
end)

PlayerEnteredAWorld_RemoteEvent.OnClientEvent:Connect(function()
	listUpdatedFireFuncion()
end)

----------

Solutions tried so far:

I’ve looked around on the forum, this seems to exist: https://create.roblox.com/docs/reference/engine/classes/BasePart#LocalTransparencyModifier

But, with it in the code, the transparency is still replicating.

Video:

3 Likes
  1. You run this script for every player
  2. As long as game.Players:GetPlayerFromCharacter(hit.Parent) the create will break

→ On every client, when a character that belongs to a player touches the crate, the crate breaks

What you want:
When the character of the local player touches the crate, the crate breaks

1 Like

make the code for the crate on the server, and when a character touches it, get the player, send a remote event to the players client, and then in a local script, break the crate/make it transparent

2 Likes

This worked perfectly, a simple == game.Players.LocalPlayer is all it took.


This is how I originally did it. I’m sure I can get it working that way, with the same conclusion from above.

However, I think having one script for all of an assets/tag behavior is better for organization reasons. There’s also less remote event work happening in this way. It might be more performant. I’ll bookmark this so I can check later down the line in my projects development.


Thanks to both of you for your responses!

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.