Marking Your Places & Models With Attributes and More! (An upcoming Roblox feature)

Hello fellow developers!
This tutorial is going to talk about attributes, which are in the process of being added to Roblox right now! I will be showing a little bit of how you can use attributes to watermark your places and credit your models (which can be applied elsewhere!). At the end of this tutorial, I additionally have some extra information on how the current Attribute system works as well as how the binary format for attributes currently works!

As you may have seen in Roblox’s release notes (specifically 408) Roblox is in the process of implementing Attributes. These are like custom metadata for instances and my game will be heavily using them! :smile: For a long while now I’ve been looking for reliable ways to “watermark” places. I’ve explored rbxl metadata, instances, tags, etc, and not many turn out to be great solutions or just plain don’t work.

Currently, there are two current easy ways to watermark your places:

  1. Hide an instance
  2. Hide a tag

Hiding an instance is not great since it will be visible in the explorer, and tags are much easier to work with and harder to keep extra information for such as keeping multiple developer names or contact info.

With the upcoming additions of instance Attributes I’ve devised two main ways to create a better watermarking system. People have sometimes asked if this was possible and I think I can safely say that Attributes make this a lot better.

Easy Watermarking

Firstly, I’d like to start with the easier method. Simply setting an attribute on some instance (e.g. workspace). Attributes support many values and even tables. This makes a great way to add credits to models and places. For places you’d usually want to be more subtle though if you don’t intend the place to be public. You’d keep the watermark there more as proof that you own the place.

To set an attribute you’d simply use the SetAttribute function. This attribute will save with the instance or place anywhere it goes! (And yes cloning will copy them!) Here’s an example:

workspace:SetAttribute("Developers", {
	Scripters = {
		"Scripter123"
	},
	Modelers = {
		"Modeler11"
	},
	Sound = {
		"SoundDesigner456"
	}
})

(I know right? My fake naming is so creative!)

Advanced Watermarking (File editing)

With a little knowledge of what instances are hard to get to you can do some file editing to make your attributes super hidden! Yayy! I think one of my favorite services is the CSGDictionaryService because of how utterly locked down it is. (I mean seriously try clicking it in the explorer and watch official Roblox plugins that are built in to studio start spitting out errors)

CSGDictionaryService cannot be accessed by scripts and its children are hidden in the explorer. And we know that GetAttribute(s) requires a script. And we know plugins or even the command bar can’t access it! So this makes it the perfect object to put our attributes on!

In order to do this you’re going to need to:

  1. Save your place to a Roblox xml file (rbxlx)
  2. Apply the attribute you want to a dummy instance
  3. Save the dummy instance to a Roblox xml file (rbxmx)
  4. Open both files in your favorite text editor (even plain old Windows notepad will suffice!)
  5. Find and copy the AttributesSerialize line from your dummy instance. This contains a Base64 encoded representation of the instance’s attributes.
  6. Search for “CSGDictionaryService” using your text editor’s find/search feature.
  7. Paste the entire AttributesSerialize line into the Properties section of the CSGDictionaryService instance.

Now you have attributes applied to CSGDictionaryService! CSGDictionaryService’s Attributes cannot currently be viewed in studio even with a plugin so it’s pretty hard to find them. Now all you need to do to check if there’s a watermark of yours on a place is reverse this process by copying the attributes from CSGDictionaryService to a dummy instance and using GetAttribute!

I hope you find this tutorial to be somewhat useful, or if not, hopefully you’ll have learned new information about Attributes!

Other Uses/Info of Attributes

Attributes have a lot of potential and watermarking is a very basic example of what could be done with them. I mentioned before my game will be using these a lot, and I’d like to share my ideas! Here are some cool uses I’ve come up with for attributes:

  1. Storing data for structures, items, and entities in your games (Since attributes are so easy to work with and are similar to datastores, you can serialize it into a datastore fairly easily using GetAttributes! That means you can store stuff such as item ids, amounts, names, and more in only one spot!)
  2. Storing custom data via a plugin for user submitted content (for example, you could have a plugin which simply stores their script’s sources as an attribute for use in an asset SDK. That would allow your game to automatically make modifications to user code for security)
  3. Compacting simple game data (I use a TON of modules to store game info. Why not organize some storage into attributes now?)
  4. Custom classes (Now your instance based classes can support custom data to remember what they are without cluttering up the game or creating a bunch of data modules!)
  5. Version metadata for your game to keep changelogs and updates (For example, a model you can insert into your game to check version info via LoadAssetVersion and GetLatestAssetVersionAsync to query the model occasionally)

Here are some questions you may have about attributes:

  1. Does attribute data get copied when an instance is cloned? The answer is yes it does as of this post!
  2. Does attribute data save for the game instance (DataModel)? Not currently! The DataModel of your place is not saved as a full instance meaning it doesn’t save its attributes.
  3. Does this attribute data save to the cloud and files? Yep! This data is meant to be saved and it’s a part of your instance.

Attribute Data Format

If you’re looking for how the binary data works, I’ve partially reverse engineered Roblox’s current format used! Keep in mind, these features are not released yet so this could change by the time Attributes are released!

Here’s a specification file I wrote for the current base64 encoded attribute data (I use my own format for this spec file by the way). This data is pretty basic for binary formats and the programmers behind this format did an absolutely great job at keeping things simple and small! RobloxAttributes.spec.xml (1.1 KB)

I don’t have most types in there, but I have the most essential ones down. Using my spec you can understand how most of the current file format works! I may have made a mistake, for example, type id 1 is marked as nil however it could have some special kind of use since there are 4 bytes used by it. Additionally, there are 3 bits missing from the last byte of Roblox numbers which I haven’t figured out the use for.

48 Likes

Great tutorial! I like the methods you posted to watermark a game. This could be useful in the future if someone attempts to steal and republish your game.

On a similar note, where are @colbert2677 and I’s attributes?!!

3 Likes

Why would you need to watermark your places?

2 Likes

I know in the past there have been methods to steal copylocked places, so it is nice to be able to make sure your work is credited in case anyone decides to steal your work.

I would love to see your solution get put into studio, it would make things much more concrete as my current system is just putting

–made by moosee MM/DD/YY

in each of my scripts.

Great tutorial!

3 Likes

Sure, but how will watermarking even help you? I don’t think Roblox would look to see if there is a watermark on the place if you ask them to.

2 Likes

I feel like it’s more a matter of pride and documenting ones work rather than helping someone concretely if a place does end up getting stolen.

3 Likes

Oh I didn’t know that, thank you!

2 Likes

That’s incorrect in the bottom, the only exploit to ever inject a local script was RC7 which is now discontinued. Elysian, Synapse, and ProtoSmasher all do not inject any local script whatsoever, making them impossible to detect injection. The only way to detect them is through foreign objects(guis inserted), or specific error codes.

3 Likes

This is not necessarily true. There have been examples of entire place files, server scripts and all being stolen. There are a few examples that have been somewhat explained before:

  1. Town of Robloxia
    This game, it’s assets, and scripts, as well as the “morph magic” GUI you may have seen other places was stolen a while back. The common story behind this one is that a staff member’s account was either breached or even went rogue. But essentially the game was reset, then restored which caused the uncopylocked flag to remain as true.
  2. Phantom Forces
    The information behind this is not documented but I’ve heard a little info from people on this topic and some of them seem to agree that this was not due to an uncopylock. There are two main ways that PF could have been stolen:
    The hash of the place asset was discovered
    Some type of server Roblox side exploit occured (There have been exploits like these even in the past few years!)
  3. I do not remember the game associated with this or if it was specifically listed but there at one point was a huge issue with the Save Place API. This was pretty obscure and I can’t find much. I know for a fact that some DataStore content may have been breached or modified, and content was (maybe!) stolen from the game.

What I mean to say by giving these examples is that this type of stuff does happen! Watermarking your content like I’ve shown isn’t great protection really, but if it’s well hidden or protected (e.g. by CSGDictionaryService’s permission levels) it can be proof that you are the true owner of a place if there is some kind of disagreement.

2 Likes

If an Instance’s Attributes can be edited by its xml file, wouldn’t that also mean that the exploiters whose goal is to obtain the map could also remove that watermark by editing the xml file, thus destroying the purpose of the “watermark”?

3 Likes

The main purpose of watermarking your places or assets is essentially just to stand as proof that you own something. It doesn’t offer much protection other than some hidden proof saying “I made this game!” If a Team Create member goes rogue, you can prove you own it.

As for @NicholasY4815’s question, yes, they can remove it, however most people will not be looking for watermarks in the place files they steal. Viewing this information in a text editor you can see the binary content of the attributes is stored in base64 thus it’s not readable without base64 decoding it. At that point your strings will be completely readable however most people won’t think to check CSGDictionaryService in a large place file. Most exploiters would be looking for content like this via scripts as well. Keeping it in CSGDictionaryService protects it from the command bar as well as plugins so any automation would have to be done externally.

2 Likes

To add on to this, most exploiters that just steal places have at most 0 dev knowledge, and even then so they might not know if there are attributes attached.

3 Likes

This is surprisingly pretty true. A majority of the exploiting community contains inexperienced scripters (specifically younger Roblox players) who are unfamiliar with most of how Roblox works. The creators of the methods and code to steal content would usually make more money off of it than the people who use their exploits. I’ve heard of those big name exploits (Synapse for example) making tons of money and it’s definitely a huge incentive.

Most incentives for exploits and code to be developed at all from my understanding is power (pretty much support of buyers) and money, while the incentives to use these exploits are usually to have fun (and a lot of younger users are looking for this type of thing).

2 Likes

I just want my attributes already, but I don’t feel like this does any justice to their usage. Disappointed.

I don’t really see the point at all in taking up memory in your game to “watermark” places. It seems like another one of those “try to prevent others from stealing my work and removing the credits from the place” schemes. Wasting memory by serialising developer data on instances just seems inane and pointless. It’s not changing anything in regards to the current dynamic of place ownership.

Attributes have a wide variety of uses and a lot of my upcoming projects completely depend on attributes meaning I can’t release without them being added in (I currently use an attribute emulator in cases where I can’t wait). I have use cases up to

  • DataStore properties (just like the OP: data structures, full data libraries, ids, so on that makes working with DataStores and collating easier)

  • Extending an instance’s properties. Custom classes objects aren’t so much doable unless you’re willing to sacrifice a large dictionary or use a proxy object, plus you can’t attach functions to an instance via attributes. Custom classes are still something I want, where the object is able to have a literal representation in the DataModel.

  • Server meta that I just put on the Workspace, same as OP. If I ever need some kind of global configuration or something, if it doesn’t need to save, I don’t see why I should spend DataStore requests when they’re already very limited per cycle (minute).

  • Substitute for ValueObjects and quick replication without remotes. ValueObjects create too much clutter for me and I’m not really a fan of them, but I use them because they’re of use to me right now. Most of my VOs are going obsolete with attributes.

  • More. A lot more and I’m not clogging the post with my ideas.

This doesn’t seem like a good idea at all though. Like, what’s the point in doing something that itself is just another version of a rehashed concept seen for years? Spend your game memory holding something more useful than something that can get overwritten easily. I’m not banking on the whole “exploiters may not know how” in terms of knowing they exist, where they exist and how to remove them. I always assume exploiters know how for the sake of my own safety.

5 Likes

This may have been a bad example, but I meant for this to 1. Give a simple example of how attributes can be used, and 2. Mitigate place stealing disagreements (they happen a lot!)

I don’t think this is a rehashed concept though and I don’t think it’s likely that most exploiters will spend the time to remove this type of thing since it serves as no obstacle. It’s not any form of advertisement or anything and it’s unlikely people will search for this in a leaked place. It’s mostly for proving you own a place.

I kind of hadn’t thought about the memory footprint of this. You make some good points with that. To reduce memory it would make sense to keep things small. My code example is rather bad in terms of memory usage. I’m fairly sure that the data in the attributes actually has a similar footprint to how you’d traditionally store this type of data though so I’m not sure how much worse this is than storing content in a module.

Here’s my counter argument to this though,
Personally, I don’t ever worry about memory and I’ve legitimately never needed to even with hundreds of instances all storing data on the server. There’s almost no performance cost to storing a lot of data and as long as I properly handle everything my clients will have little to no memory footprint. Keeping data on instances that aren’t replicated (ReplicatedFirst ironically is included in this list, as well as CSGDictionaryService).

So there’s no client-side memory footprint for CSGDictionaryService, ReplicatedFirst, ServerStorage, and ServerScriptService, etc attributes. This brings up an interesting idea as well. By using non replicated instances such as Cameras as storage objects (which are easily creatable) you can safely store server-only Attributes! I’ve tested all of these services/instances and they do indeed prevent attribute replication just like any other property changes. And the client memory footprint isn’t effected at all!

1 Like

It is a rehashed concept. The whole debacle of marking your assets to “fight against theft” is a long-running concept that has had more prominence with ModuleScripts than whole places and it hasn’t had a very well running each time it’s been brought up. It’s easy to just put your name in something and harder to prove that you actually made it, especially when touching down with moderation.

Attributes don’t prove you own a place. Nothing you do does. That’s up to moderation and whatever internal policies and official channels they search through in order to prove that you’re the place owner. They don’t just look at your game, see some script or asset with your name and automatically assume that you are the owner.

As for exploiters, again, it’s a bad idea to take any kind of risk and just assume that exploiters are going to ignore it. You shouldn’t just disregard something because you think it won’t happen or that there’s no likelihood of it happening. Even then, it’s not just exploiters indiscriminately releasing work that are of any worry: there are the people who use your work too who are now actively going to search for this kind of thing. Making this thread just gives thieves fuel and a heads-up that this is a future prospect developers may apply to their works.

With modules, a line of code barely takes up any memory in comparison to using an attribute. Not only are you now serialising some arbitrary data on an instance but you’re also connecting it to the attribute pipeline with all its connections and management processes.

Client-side memory isn’t as much a concern because client machines can tank a lot. That’s not the same with the server. Memory and efficiency are a very big factor and using every bit you can get is valuable. There are developers who often wonder why their games are slow but they don’t understand how memory or code efficiency play a part in the performance of their game. Especially for those who don’t understand that concept, these little things add up into a nightmare of inefficiency and badly managed memory.

4 Likes

I was looking to get rid of ValueObjects once attributes drop but the other meta examples you have listed are super interesting too!

3 Likes

Isn’t this almost like CollectionService? I’m happy the functionality is built directly into instances now.

1 Like

They are somewhat similar but CollectionService offers a ton of useful events and functions. Attributes are meant to store data on an instance rather than identifying them.

1 Like

Pretty much. CollectionService is the medium for working with collections (and understandably so) while attributes work directly on instances. Both attributes and tags are serialised on the instances themselves.

Tags are simple string identifiers which form up a collection of objects you can work with, either for creating streamlined behaviours or whatever your needs may be. Think of it as grouping instances but they can be in multiple groups and hierarchical position doesn’t matter.

Attributes are attribute-value pairs (or key-value pairs) that allow you to add data to an instance. Unlike attributes, you are able to define a field and an assigned value for it, meaning that you’re adding actual instance data rather than creating a collection of objects. Primitive Lua datatypes are acceptable for attributes except for functions, threads and userdata.

Attributes and tags each have their own respective uses and you can even use them similarly in some scenarios. They aren’t necessarily interchangeable however and what you may use in the future is significantly context dependent.

But that doesn’t matter for me. I’m abusing attributes the moment they release.

4 Likes