PartCache, for all your quick part-creation needs

I noticed if you use this with any part with trails it becomes quite weird, with the trail being visible as the part teleports to the proper location. How could I fix this?

Disable the trail right before it’s teleported, and just enable on parent.

Running into a critical issue right now, in conjunction with FastCast. Whenever I return a bullet to the container while the camera is looking in certain directions, nearby parts flash for precisely one frame. It’s uncomfortable to look at, breaks immersion, and is - most importantly - a health and safety risk to players with epilepsy.

EPILEPSY WARNING

4 Likes

I’m getting this errror
Attempted to return part "AcidRain" (Workspace.Debris.AcidRain) to the cache, but it's not in-use! Did you call this on the wrong part?
However, I can’t see how this could ever be possible? As the only way the .Touched on a part is being called, is when it’s repositioned, which is after the GetPart is called

self.AcidRainCache = PartCache.new(AcidRain, PART_CACHE_LIMIT, workspace.Debris)

	for _, acidRain in workspace.Debris:GetChildren() do
		self.Trove:Connect(acidRain.Touched, function(hit)
			if hit:IsDescendantOf(workspace.Debris) then
				return -- Ignore other acid rain pars
			end

			self.AcidRainCache:ReturnPart(acidRain) -- ERROR
		end)
	end

	task.spawn(function()
		local Interval = 0

		while self.Active do
			for _ = 1, 10 do
				local NewAcidRain = self.AcidRainCache:GetPart()
				NewAcidRain.Position = MapContainer.Position
					+ Vector3.new(
						math.random(-MapContainer.Size.X / 2, MapContainer.Size.X / 2),
						MapContainer.Size.Y / 2,
						math.random(-MapContainer.Size.Z / 2, MapContainer.Size.Z / 2)
					)
				NewAcidRain.Anchored = false
			end

			task.wait(0.05)

			Interval += 0.05
		end
	end)

Seems like the issue is that the .Touched event remains connected while the part is cached. PartCache keeps parts in the workspace - thousands of studs away. Try connecting .Touched when the part is taken from the cache, and disconnecting the event immediately before the part is returned to the cache.

2 Likes

Unsure what I am doing wrong, but I have a part structured like this. When using PartCache however, the Fure part isn’t attached to the bomb, even tho the weld constraint is connected properly.
image
So when they spawn in, the fuse is seperated from the part for some reason.

Note, when just using Bomb:Clone() it works fine, so it’s definitely not the weld/etc.

bit late but I ran into this same issue with my part caching implementation and realized that it’s caused by the cframe location where parts are sent to when they’re in cache. parts being sent >10e8 studs away causes this to happen semi consistently when looking downward near adjacent walls in first person, I currently have the cache at CFrame.new(0, 10e7, 0) which doesn’t have this issue

3 Likes

Does this support multiple caches?

Example, im making a tycoon, and so far i have at least two planned things i want to use it
#1 being the droppers, pull from here, edit properties, drop, once drop is collected send back
#2 a collect effect that needs a certain type to edit and use, and then put back

Yeah you can create multiple Cache object with .new

I use a similar method in caching particle effects and it works very well. :slight_smile:

For anyone who’s thinking of using PartCache, it’s excellent!

But please, make sure to change the CFrame position it comes with because Roblox has an engine bug that can cause your maps to flicker. This only happened to our team in areas where PartCache was used at a Y axis of >100, why? I have no idea.

Some severe bug within the engine is causing this all and Roblox does not seem to do well with parts that are positioned so far away.

1 Like

does PartCache:Dispose() run if the script that made PartCache.new() is destroyed?

Hello! Does this module work with StreamingEnabled? I’ve been tweaking my game to enable StreamingEnabled for performance purposes but my script using this module doesn’t seem to be working properly, i have it set so 10 bullets should be created on startup, but that doesnt seem to be working, instead bullets are only created when shot out.

local bullet = RP.Misc:WaitForChild("Bullet")

cache = PartCacheModule.new(bullet, 10)
cache:SetCacheParent(workspace:WaitForChild("Bullets"))

I’ve noticed the expansion part of the code works properly when more than 10 bullets are created, so it seems everything else is working properly other than the initial creation of parts

1 Like

Sorry for the double reply but i managed to fix the issue by making a small tweak to the PartCache script, i made it so bullets were created in a closer position to the player’s spawn under the map and then moved them back towards the storage area after a wait()

local function MakeFromTemplate(template: BasePart, currentCacheParent: Instance): BasePart
	local part: BasePart = template:Clone()
	-- ^ Ignore W000 type mismatch between Instance and BasePart. False alert.

	part.CFrame = CFrame.new(0, 0, 0) --modified from part.CFrame = CF_REALLY_FAR_AWAY
	part.Anchored = true
	part.Parent = currentCacheParent
	return part
end

function PartCacheStatic.new(template: BasePart, numPrecreatedParts: number?, currentCacheParent: Instance?): PartCache
...
for _ = 1, newNumPrecreatedParts do
		local part = MakeFromTemplate(template, object.CurrentCacheParent)
		wait()
		part.CFrame = CF_REALLY_FAR_AWAY
		table.insert(object.Open, part)
	end
...

function PartCacheStatic:GetPart(): BasePart
...
if #self.Open == 0 then
		warn("No parts available in the cache! Creating [" .. self.ExpansionSize .. "] new part instance(s) - this amount can be edited by changing the ExpansionSize property of the PartCache instance... (This cache now contains a grand total of " .. tostring(#self.Open + #self.InUse + self.ExpansionSize) .. " parts.)")
		for i = 1, self.ExpansionSize, 1 do
			local part = MakeFromTemplate(self.Template, self.CurrentCacheParent)
			wait()
			part.CFrame = CF_REALLY_FAR_AWAY
			table.insert(self.Open, part)
		end
	end
...

Not sure if this is the cleanest solution but hopefully it helps anyone having a similar issue

Have you tried putting the parts in a model with ModelStreamingMode Persistent?

Can you add in a new function named PCache:GetAvailableParts() or PCache:GetUsingParts(), or even PCache:GetPreCreatedPart()? I am trying to detect when there are no using parts, so that when the ReturnPart() function is called, i can check whether it is the last one to delete the part cache. Basically, i am using FastCast, but i encountered a problem in which the bullets completely disappear. My most recent solution is to create a new partcache with a relatively low precreated part amount, then dispose it once all bullets has been returned.

Putting this here for anyone else who gets this issue:

Sometimes when you return parts to their cache, the shadows glitch and flash off an back on. This is undesirable especially if you’re returning a bunch of parts frequently.

To resolve this just go in the module and change the huge CFrame constant to something smaller. I did 1e7

6 Likes

.CFrame do be taking performances however it is only possible to notify at around thousands of parts, which lets be real will probably not happen in a single frame often, but if you somehow manage to get conditions like this, i’m pretty sure you can use something called workspace:BulkMoveTo(partList, cframeList)

basically it allows you to update more parts cframes in a single frame way faster, here we could kinda get every moved part in the frame, then use bulkmoveto to move all of them at once, which could probably make performances better?

Is this also possible with other instances than only BaseParts like SurfaceGuis for example?

Is there a way to get an already existing partcache?