This is definitely a big pain when trying to populate or change anything with decals scriptwise. Would love to see this functionality extended to faces as well, as they follow a very similar flow and issue.
In the meantime if you just need to do it off the website you can do this
But I definitely support having API support for it
That’s with the use of a plugin (I believe BTRoblox?) I don’t believe you can directly reach the Image ID at all from the Decal page right now.
Ah, you’re right. BTRoblox has so many nifty well integrated features that I forget they’re not vanilla - most of them should be. I’ve also had it for so long so I hardly remember what the roblox site was like before it lol
The fact that we need third party tools highlights how important this feature request really is. Images and Decals are an ambiguous mess at the moment.
Does inserting the decal and reading its ID not work? This is what we do internally for the Properties widget when an assetId is pasted in. For Lua it would look something like
local InsertService = game:GetService("InsertService")
local MarketplaceService = game:GetService("MarketplaceService")
function getImageIdFromDecal(decalId)
local assetInfo = MarketplaceService:GetProductInfo(decalId, Enum.InfoType.Asset)
assert(assetInfo.IsPublicDomain)
assert(assetInfo.AssetTypeId == Enum.AssetType.Decal.Value)
local decal = InsertService:LoadAsset(decalId):FindFirstChildWhichIsA("Decal")
return decal.Texture
end
print(getImageIdFromDecal(3339338289))
This is also likely what the requested API would do behind the scenes.
I’m surprised decals are even a thing still, it feels really strange that we have a web asset that doesn’t actually do anything (since decal instances need an image id, not a decal id).
I’d be much happier if Decals were hidden from the website, and stopped being created when an image is uploaded - it’s much easier to view the actual image assets now with the create.roblox.com/creations page.
Linking this thread from a couple of years ago: Stop creating decal assets
An exposed method which handles this for us would be much more generous than us having to use (and some day, people will find) this example (which honestly I did not know you could do this).
The API would be a quality of life change that would be well received with opened arms.
I never knew this existed. I’ll be updating my codebase with this method for now, but a proper API would still be preferable.
Also, I’m not sure how no one knew about this method. Is there any documentation for it?
Both are pretty thoroughly documented.
This seems really esoteric and is not common knowledge nor easy for people to figure out; if you browse the forum you can see that the general approach people take towards doing this is to use crazy hacks or simply do something else. This is too close to being a hidden trick that I don’t think doing this in this manner should be considered canonical.
If we add something akin to MarketplaceService:GetAssetFromDecal() or AssetService:GetAssetFromDecal(), how would it be any more discoverable than those two methods? If developers cannot find either of the existing ones, is this new API different?
This workaround relies on knowing that creating a decal results in the texture field being set to the image id. This behavior is only directly observed in Studio through the properties widget when you try to set the texture property and it’s easy to assume that it is Studio doing that conversion, not the instance itself.
Developers will go to Google or to the DevHub first and will typically try searching directly, or else browsing API pages for related services. In many cases they may just try intellisense directly in Studio and hope they get lucky. It is massively easier to discover an API function that directly does this than it is to connect the dots and come up with some workaround that jumps through InsertService. The existence of this function in intellisense under a logical service would improve discovery without leaving Studio, and the existence of the DevHub API page for a function like this with sufficient keywords on the page would solve this through search engine indexing.
There’s a big difference between a method designed and advertised to do a specific task and a sequence of methods that happen to make the functionality possible via a still overly complex workaround. Kind of like how we have helpful coordinate math functions like CFrame.lookAt despite us technically being able to achieve the same functionality through other more complex means.
LoadAsset doesn’t allow us to import assets that are not owned by Roblox or the Game owner.
For players to use decals their own, how exactly can this suffice that use case?
An asset loaded by this function must be created or owned by either the game creator or Roblox. Additionally, benign asset types such as t-shirts, shirts, pants and avatar accessories are loadable from any game as they are public.
I know this method exist but never cared for it because of this flaw
Clearly there’s metadata somewhere in a decal asset that links it to the image ID. I agree that this would be great to have without needing to go through both MarketplaceService and InsertService.
Whoops, I shouldn’t have used the word “method” as it has multiple meanings here. I understand that the API methods are well documented, I meant the method (as in technique/solution) that you shared uses those APIs in a clever way that doesn’t seem to be mentioned anywhere and is only obvious if you already know about it.
After switching the -n technique to your given InsertService technique, I was met with this:
InsertService cannot be used to load assets from the client
The workaround you provided doesn’t work on the client, which is extremely inconvenient.
After reworking it to be on the server, I found that this suggested workaround is still does not work, since InsertService cannot insert assets that you don’t own.
HTTP 403 (Forbidden)
An asset loaded by this function must be created or owned by either the game creator or Roblox. (Source)
The goal in our aforementioned use cases is to allow players to use custom images that they own, so this completely defeats the purpose.
So, unfortunately, my original post’s method is still the only currently available hack.
To add onto this, we shouldn’t have to ask users to open their inventory for us to grab the image that we need. The current method supplied depends on us making sure the client’s inventory is available for us to view, which seems really sketchy if you ask your players to open their inventory. A solution that provides the image without this hassle would again be a quality of life feature that we need.
Even if they make the decal public, the InsertService call will still throw an error.
The documentation is correct in stating that the asset must be owned by you or Roblox.
Here’s a simple test to prove that. This decal, kindly provided by @PeZsmistic, is public.
https://www.roblox.com/library/5376310957/logo
local InsertService = game:GetService("InsertService")
local MarketplaceService = game:GetService("MarketplaceService")
local DecalID = "5376310957"
local AssetInfo = MarketplaceService:GetProductInfo(DecalID, Enum.InfoType.Asset)
print("Public =", AssetInfo.IsPublicDomain)
print("IsDecal =", AssetInfo.AssetTypeId == 13)
local Decal = InsertService:LoadAsset(DecalID):FindFirstChildWhichIsA("Decal") -- ERRORS 403
local ImageID = Decal.Texture
I believe this needs to be an API member as well.
I would say “I’m surprised this was suggested so late”, but you consider how these assets are created, and anything earlier than the past three years or so didn’t need this API because it was as easy as ID-1
, simply because asset uploads were less frequent than they are today. This worked beautifully for years but these days it’s just not viable anymore with how many people are uploading content onto the platform.
This has been a huge issue for me as well. I flat out don’t even know how to automate this, and have always resorted to just manually grabbing the image ID for my assets and baking them into my scripts as hardcoded strings. User input has always relied on the user just getting the ID on their own.
I think something like a marketplace API call would be the best because it doesn’t rely on having a script insert assets into your game, it doesn’t require you to own the ID as per the limitations of InsertService, and it’s straightforward.
If anything, I’d vouch for it being a member of ContentProvider
because that seems more mnemonic in my opinion (ContentProvider:GetImageFromDecalAsync(decal)
makes more sense to me than MarketplaceService:GetImageFromDecalAsync(decal)
does, for example)