PartCache, for all your quick part-creation needs

I’ve never imaginged the use of caching parts like that. I’ll end up using your module for my gun script.

Thanks for the module!

4 Likes

Wow, that’s pretty cool. I hope I can find a use for it!

2 Likes

It’s not likely that it’ll be default behavior, but it is certainly an option for the user writing the gun script.

Update for people of the future: This was added to FC.

11 Likes

I might do that with my FastCast rewrite.

3 Likes

It would be nice if you could give us some concrete statistics (ie percentages in script performance tab) on how much more efficient this is compared to reparenting / repeated instancing.

1 Like

@zeuxcg is CFrame being the only ‘fast’ updated property still the case?

Or has there been an update in this regard?

I don’t know if you meant to say that to me, but yeah, I’ll check as soon as possible.

Edit: I’m not sure of a good way to actually benchmark it. My benchmark tests seem to indicated the opposite of what zeuxcg said, so I probably implemented it wrong.

1 Like

I hope I don’t get blasted into low Earth orbit for bumping, but your module came in really handy when I was optimizing my arrow tracers. Now instead of rendering everything on the server, I just send some data off to the clients that use this module to render the tracers and I am in love with how it performs!

My own little stress test:

I did notice your API reference doesn’t accurately reflect the module. The latest version of your module creates PartCaches via .new() but your API reference in the OP claims it’s done with :CreateNewCache()

With that aside, you saved me a boatload of work and testing. Thanks for the module!

22 Likes

Thanks for pointing this out. It’s been fixed.

I’m really glad you managed to find such a good use for this, it helps to show how handy this module can get to be! :stuck_out_tongue:

7 Likes

Read the docs – The DestroyPart method returns a part to the cache so that it can be used later. The Destroy method deletes the cache itself and deletes all of the parts that are within it so that it can no longer be used.

If you see it as a good idea, I could rename the method.
Edit: I may do that anyway actually, since I’m sure other users may have stumbled upon the same confusion.
Edit 2: The proper method is now PCache:ReturnPart – DestroyPart will still work for backwards compatibility.

3 Likes

Finally got to testing this module.

PartCache:
	ON_RAY_HIT: 0.007ms
	FIRE: 0.114ms

No PartCache:
	ON_RAY_HIT: 0.014ms 
	FIRE: 0.139ms

I was using this free model along with the microprofiler to test it out. With some optimizations, I got these mildly better results:

Optimized PartCache:
	ON_RAY_HIT: 0.006ms
	FIRE: 0.109ms

So it is faster.

10 Likes

Sorry for the bump, but I have a question as to how I would actually use this module. I’m using a custom implementation of this module for an ambient particle system, but I’m not sure how I would actually return a part to the open list.

100 parts are used every second/few seconds (depends on the algorithm) like this:

local part = Pool:GetUnusedPart()
part.CFrame = CFrame.new(pos.X, pos.Y, pos.Z)
part.ParticleEmitter.Acceleration = Vector3.new(rand:NextInteger(-5, 5), rand:NextInteger(-5, 5), rand:NextInteger(-5, 5))
part.ParticleEmitter:Emit(1)

I assume to put the part back into the open list, I would just use a coroutine:

local part = Pool:GetUnusedPart()
part.CFrame = CFrame.new(pos.X, pos.Y, pos.Z)
part.ParticleEmitter.Acceleration = Vector3.new(rand:NextInteger(-5, 5), rand:NextInteger(-5, 5), rand:NextInteger(-5, 5))
part.ParticleEmitter:Emit(1)
coroutine.wrap(function()
     wait(3)
     Pool:Return(part)
end)()

But I worry that creating a coroutine for every part could cause lag, defeating the entire purpose of such a module. Is this true? Is there some other way that people should add parts back to the unused list? Thanks for the help.

1 Like

I wonder if this module can now be further optimized with the new method :BulkMoveTo()?

1 Like

Correct me if I’m wrong, but BulkMoveTo doesn’t replicate the movements to clients for optimization?
If so, then it’s not a good solution as the parts will still be visible after being moved to the Cache.

You can specify a CFrame property change (basically replicated to client) I believe but its hard to know since there’s not much API information on it but I think I am correct, as you can specify something like that within a parameter.

It depends on your implementation. In your specific case, I’d advise against using parts if your goal is to have single particles emit at random locations. A better choice might (I say might because I don’t actually know what you’re trying to do) be to parent an Attachment to terrain. CFrame the attachment, emit the particle, delay, repeat. You could have a single attachment + emitter and just randomly emit around your area. That, or better yet, just make a big part and use Roblox’s random placement (but I assume you’re avoiding that for a reason).

To answer your question, I’d advise having it all in one single function, wait included. That, or use spawn instead of coroutine.wrap as spawn ties into Roblox’s scheduler (same system as wait for the most part)

It could be done relatively easily, the issue is that there’s no real purpose for it unless you’re building close to the preset position, which would cause other far more severe problems for your game

3 Likes

Cool module, any chance you would add the Luau type annotations to it?

Oh yeah! I hadn’t actually realized it was released. I can do that ASAP.

Edit: Update is out. Of course, scripts may show a number of false warnings due to type checking beta. There is now a “README” script in the module that goes over what to expect.

1 Like

I am looking through the module code but unable to figure out :exploding_head: where I change the default parent object for the cached parts.
Now they are all parented to the Workspace.
Is it possible to specify the parent object for each cache?

Look at the main post, at the bottom. There’s a ref sheet.

1 Like