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

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

Hello, hope everyone is feeling great. How long is it going to take for SetAttribute() to be added by Roblox? :thinking:

2 Likes

I think that Roblox’s teams mainly just have other priorities atm but eventually it will definitely be released. There’s a lot of stuff that’s being held back from production at the moment, likely due to a lot of reasons (the ongoing epidemic, backlogs everywhere, server/code performance, avatar and lighting engine updates, etc, etc). There are tons of features I’ve been messing with, and they’re all definitely planned to be finalized but it’s going to be a while is my guess.

Keep in mind that attributes have yet to be announced publicly and are not listed on the roadmap, documented, etc.

2 Likes

Are instance methods considered to be attributes? If so… how would you assign a method as an attribute to achieve Model:Test()?

1 Like

No attributes can’t be directly indexed on the Instance. They’re very similar to Tags. You can use GetAttribute, SetAttribute, GetAttributes, AttributeChanged, and a couple others. They save on the instance like tags, and you can set them to basically any primitive you can think of excluding functions, userdatas (and Instances).

However, you can sort of achieve what you’re trying to do using metatables:

function wrapInstance(custom, instance)
    local wrapped = newproxy(true) -- This creates a userdata you can change the metatable of. There's no way to make typeof return "Instance" without creating a custom typeof
    local meta = getmetatable(wrapped) -- This will get the metatable of the userdata we created
    meta.__index = function(self, index)
        if custom[index] ~= nil and index:sub(1, 2) ~= "__" then
            return custom[index]
        end
        return instance[index]
    end
    meta.__newindex = function(self, index, value)
        local success, err = pcall(function()return instance[index]end)
        if success or not err:find("is not a valid member of") then -- The property exists on the instance or causes a unique error
            instance[index] = value
            return
        end
        if typeof(custom.__newindex) ~= "function" and custom.__newindex then -- Allow the __newindex property of the custom table to be a table or userdata
            custom.__newindex[index] = value
            return
        end
        return custom:__newindex(index, value, instance) -- Call __newindex on the custom table and pass three extra arguments (index, value, and the original instance)
    end
    meta.__call = function(self, ...) -- This used to actually do stuff but recently this functionality was removed because it was unintended behaviour. (It has to do with how Roblox interfaces with lua)
        return instance(...)
    end
    meta.__metatable = getmetatable(instance) -- This returns the "Locked" message
    return wrapped -- Return the wrapped metatable
end

If you call wrapInstance with a table of functions and properties it will return a new userdata which has those functions and properties. Any properties/functions you set with __ at the beginning will be nil when you try to get them on the wrapped instance. You can add a __newindex function on the custom table (not in a metatable) to allow them to set custom properties (or even functions if you want) which will have one extra argument compared to the normal metamethod, the actual instance.

Basically the way it works is it just creates a new userdata to work with and uses metatables to decide what gets returned. It prioritizes things from the custom table, and uses stuff from the instance otherwise.

If you want to talk more I’d suggest doing it through PMs though so this post doesn’t keep getting bumped.

2 Likes

Any updates on when attributes will be released? It’s been a long time since this blog :slight_smile:

1 Like

Well, I have no idea. I’m not too sure the cause of the delay, but, I’m hoping sometime soon as I still have code ready to use them. They’re definitely going to be a huge QOL improvement for me!

1 Like

Is this feature still coming? The api was added over a year ago now and it’s still not enabled https://developer.roblox.com/en-us/resources/release-note/Release-Notes-for-408

3 Likes

Welp, this will make most of my serialization code useless. Yay! Not only this though, but with it you will be able to make serializers better than ever before!

1 Like

Even if having a watermark saying ‘I own this game!’ meant Roblox would take further action, exploiters on other sites would start releasing methods to instantly remove these tags.

All it takes is one exploiter with some developer knowledge to create an automated tag remover and then make it public on one of these off-site exploiter forums.

Personally I think setting attributes as watermarks for your game is a waste of time and Roblox probably won’t ever ban a user for having a watermark attribute that says they don’t own it. If anything setting attributes is just like writing ‘Written by WinterGoons’ at the bottom of a script.

Edit: Didn’t realize this topic was so old. My bad.

since luau, script source is never sent to clients, only luau bytecode, which does not include cmments, and only few exploits can decompile the bytecode to lua code