Modify MeshPart.MeshId through plugins/command bar

As a developer, it’s currently painful to have to manually change MeshId for a large number of MeshParts at once. As an example, I have spent a bit over 3 hours changing 100 Special Meshes to MeshParts manually today, while I could have used that time to do other things for the game.

I understand that changing it at runtime has complications, however it’d be great if we are allowed to change them via plugins. If Roblox is able to address this issue, it would save us the time we need to spend manually setting our meshids and spend more time making other things for our games.

72 Likes

Any news on this as its continuing to be a huge road block in development.

5 Likes

Sorry to bump though now that realtime CSG is out is it any easier to get something like this to happen?

1 Like

So, I’m trying to figure out what you need exactly? You want to change:


This for a bunch of meshes all at once, right?

I’m just uncertain under what use case you’d need to change them via Plugin/Command Bar rather than just changing them by selecting all the Special Meshes in studio, and changing them by putting the code in. Idk, maybe I’m misunderstanding what you’re trying to do.

1 Like

This is for MeshParts – not SpecialMeshes. Command bar is needed because manually changing them takes too long. Using command bar to select and properties window to change may not be acceptable in the case that MeshId is calculated instead of all being set to the same.

2 Likes

Ah, yea.
Couldn’t you name all the MeshParts like “Lamp” and run a while loop script that finds all the things called “Lamp” and changes their MeshID? I mean, you’d have to run the game, and then when you stop, it’d revert the changes, but you could grab all the meshes during play, and copy/paste them into edit mode.

The issue here is that MeshPart.MeshId is tagged as NotAccessibleSecurity for ScriptWriteRestricted.

This means that any sort of script, be it a Script, LocalScript, CoreScript, Command Bar, etc. trying to edit the MeshId of the MeshPart will result in an error being thrown, and the property thus can’t be changed.

The purpose of this thread is to be able to efficiently change that property for a bunch of MeshParts that might be too tedious to do manually, as EchoReaper mentioned. This is currently not possible to do with any sort of script.

4 Likes

You can somewhat work around this restriction by cloning the replacement meshpart from somewhere, and copying all the properties of the part you’re replacing.

However, this wouldn’t work for OP’s case as the meshpart instances don’t exist yet and are very varied. It’s disgusting to need to work around this in the first place. I ran into this issue recently and it was an utter waste of time to fight with.

1 Like

Also, to comment on the current issue with MeshPart.MeshId not being accessible for write, a current workaround could be to save the place / model as a .rbxlx or .rbxmx file (XML representation of the place / model), then via some external program scan traverse through the XML structure and identify the tags of
<Item class="MeshPart" referent="..."> containing the following two tags:

<Content name="MeshID"><url>rbxassetid://1234567890</url></Content>
<Content name="MeshId"><url>rbxassetid://1234567890</url></Content>

Which can then be replaced externally.

Of course though, this is a workaround and requires knowledge of traversing the XML structure and such, which could be easier to do with the ability to change the MeshId from Roblox :slightly_smiling_face:

4 Likes

Ran into this problem twice recently. First time was trying to change the CollisionFidelity, which is also locked, on a few hundred trees that had accidentally been left on Default instead of box, and then having to wrestle with studio crashing a ton trying to change it all instead of it taking literally 30 seconds with a command bar script, then again trying to transfer a bunch of SpecialMeshs into MeshParts for efficiency testing, which again, should have taken mere seconds with a script but instead took 40 minutes.

11 Likes

I am running into this issue right now and it is bothering me. I want to convert special meshes into mesh parts but I cannot set the property even through the command bar.

3 Likes

This is an annoying restriction. I am trying to replace the MeshId for a bunch of meshparts in my game after I updated the meshes and I have to manually do it for every part because of this

3 Likes

Why is this still a restriction? This makes developing rojo-managed applications a pain for everyone involved. Since MeshIds are un-writable, it’s impossible to sync them directly into studio, so we’re forced to build a separate place file and transfer the assets across every time instead.

Not to mention the countless inefficiencies everyone mentions below.

Please fix this. There’s no obvious reason to have it restricted to an elevated permission. It’s simply inhibiting our ability to develop.

19 Likes

I had to write a script today to work around this pointless restriction just to experiment with using vertex painting on some of the re-used meshes in my game. I had to clone an existing meshpart and replace the existing ones with the clone. This is stupid and error-prone if I forget to copy children or a property. Note also that it would necessarily break ObjectValue references, WeldConstraint references, etc. I should not have to do this kind of nonsense just to change a mundane visual property that I can already change in Studio via the properties panel.

E.g.

for i,v in pairs(workspace:GetDescendants()) do
	if v:IsA("MeshPart") and v.MeshId == "rbxassetid://xxxxxxxxx" then
		local new = game.Players.MeshPart:Clone()
		new.Size = v.Size
		new.CFrame = v.CFrame
		new.CanCollide = v.CanCollide
		new.Anchored = v.Anchored
		new.Color = v.Color
		new.Material = v.Material
		new.Transparency = v.Transparency
		new.CollisionGroupId = v.CollisionGroupId
		new.Massless = v.Massless
		new.Locked = v.Locked
		new.CustomPhysicalProperties = v.CustomPhysicalProperties
		new.RootPriority = v.RootPriority
		new.Parent = v.Parent
		v:Destroy()
	end
end
5 Likes

This is still an issue that needs changing. I am working on a place and have used some catalog items for scenery, however, I can’t tint them (another issue, we need to be able to tint meshparts) because they are mesh parts, so I thought, I would write up a script to change them to specialmesh, so I can tint them for decorations, however, some of them are scaled, and to get the original meshpart scale, I need to create the meshpart, get its size, and then calculate scale to apply to the specialmesh, only I can not recreate the meshpart to get the original size, because of this issue.

1 Like

Yes you can.

4 Likes

Bump.
Something super annoying with MeshParts is that if you change the render fidelity to performance, it creates a new asset every time. This was problematic for me because I use the same mesh for characters, but they all end up with different asset ids as soon as I change the RenderFidelity property, so it’s not optimal at all for memory, as it increases the amount of unique assets.

I wanted to write a script to change the MeshId to be the same for all characters, but realised I can’t because of this restriction. I am surprised we can’t even do that from the command bar…

1 Like

The same goes for changing the technology of the game’s lighting in real-time: They don’t let you.

2 Likes

First, for anyone running into this thread, the tools are there to work with MeshId via plugin scripts, just not directly via the property.

  • MeshPart:ApplyMesh - Change the geometry of a MeshPart in-place without disrupting physics simulation / game logic that cares about it.

  • InsertService:CreateMeshPartAsync - Create a new MeshPart from a given mesh asset.

  • Combining these two you can set an existing MeshPart to have an arbitrary MeshId using plugin code.

Rundown on why these exist instead of you just being able to set MeshId:

  • MeshParts actually have internal properties representing their collision data.

  • CreateMeshPartAsync and ApplyMesh are both “atomic” operations which set the MeshId and the internal collision data at the same time.

  • If you could set MeshId directly, the mesh data to create the collision data may not be there right away because it has to be requested from the network.

  • If you save before the data gets there or if the request fails the mesh could end up “torn” with different collision data that doesn’t match the MeshId.

  • Also consider that things get complicated with the size property. Setting the MeshId in the properties pane includes a special affordance to also change the size of the MeshPart, but doing that when setting the MeshId via code isn’t allowed because it’s a property dependency.

There are resolutions to this (including just saying “rare cases of torn meshes are okay”) but they haven’t happened yet.

9 Likes

This is what I usually do for setting MeshIds with plugins.

local function changeMeshId(meshId: string, part: MeshPart): boolean
	local InsertService = game:GetService("InsertService")
	
	local success, loadedMesh = pcall(
		InsertService.CreateMeshPartAsync,
		InsertService,
		meshId,
		part.CollisionFidelity,
		part.RenderFidelity
	)
	
	if success then
		part:ApplyMesh(loadedMesh)
		return true
	else
		return false
	end
end

Although I do wish CreateMeshPartAsync could run in game, even if it was server only. I know you can get meshes by parenting them inside a ModuleScript and requiring it with the AssetId, so it’s possible to dynamically load them somehow. Could you share any reasons?

2 Likes