I’m aware that Roblox does not permit obfuscated scripts, as it makes moderating plugins that utilize it nearly impossible, and just not worth inspecting.
However, I’m wondering whether minification is allowed, since it doesn’t try to obscure the functionality, but rather decrease the size of source files, and make them faster to execute by removing comments, and unnecessary characters from the source code.
For example, in JavaScript, source code usually looks like this:
// let the world know you exist
let name = 'Grant';
alert(`Hello World, this is ${name}!`);
Minified code looks something like this:
let n='Grant';alert(`Hello World, this is ${n}!`);
And finally, a simple obfuscated code will look something like this:
const _0x25ddb4=_0x1570;function _0x4119(){const _0x41bf68=['4658335EetETs','477bKtyYa','__proto__','bind','info','Hello\x20World,\x20this\x20is\x20','length','table','4813094qPbTqp','error','{}.constructor(\x22return\x20this\x22)(\x20)','exception','2406686TbAVYd','constructor','search','4200hkzOoV','1kAwSFQ','4mdOcWZ','apply','6278142ZPKoTq','3465717fAgpzS','log','toString','1630pAzeYD','prototype','36NfIjcg','Grant','warn','5992FTDaLA','console'];_0x4119=function(){return _0x41bf68;};return _0x4119();}function _0x1570(_0x213821,_0xda5f55){const _0x82ba0c=_0x4119();return _0x1570=function(_0x1d9438,_0x17e147){_0x1d9438=_0x1d9438-0x15a;let _0xbfe6f6=_0x82ba0c[_0x1d9438];return _0xbfe6f6;},_0x1570(_0x213821,_0xda5f55);}(function(_0x50e94a,_0xcfdb81){const _0x59b16e=_0x1570,_0x14a377=_0x50e94a();while(!![]){try{const _0x2f4616=-parseInt(_0x59b16e(0x15f))/0x1*(-parseInt(_0x59b16e(0x15b))/0x2)+parseInt(_0x59b16e(0x163))/0x3+parseInt(_0x59b16e(0x160))/0x4*(-parseInt(_0x59b16e(0x16d))/0x5)+parseInt(_0x59b16e(0x162))/0x6+parseInt(_0x59b16e(0x15e))/0x7*(-parseInt(_0x59b16e(0x16b))/0x8)+-parseInt(_0x59b16e(0x16e))/0x9*(parseInt(_0x59b16e(0x166))/0xa)+parseInt(_0x59b16e(0x175))/0xb*(-parseInt(_0x59b16e(0x168))/0xc);if(_0x2f4616===_0xcfdb81)break;else _0x14a377['push'](_0x14a377['shift']());}catch(_0x52d8ce){_0x14a377['push'](_0x14a377['shift']());}}}(_0x4119,0xab86b));const _0x2c36fc=(function(){let _0x6865a=!![];return function(_0x494279,_0x246e9d){const _0x22331d=_0x6865a?function(){const _0x252fb5=_0x1570;if(_0x246e9d){const _0x408ead=_0x246e9d[_0x252fb5(0x161)](_0x494279,arguments);return _0x246e9d=null,_0x408ead;}}:function(){};return _0x6865a=![],_0x22331d;};}()),_0x1e24fe=_0x2c36fc(this,function(){const _0xee864a=_0x1570;return _0x1e24fe[_0xee864a(0x165)]()['search']('(((.+)+)+)+$')[_0xee864a(0x165)]()[_0xee864a(0x15c)](_0x1e24fe)[_0xee864a(0x15d)]('(((.+)+)+)+$');});_0x1e24fe();const _0x17e147=(function(){let _0x2690e9=!![];return function(_0x30493c,_0x950ab4){const _0x40b750=_0x2690e9?function(){const _0x178006=_0x1570;if(_0x950ab4){const _0x54013b=_0x950ab4[_0x178006(0x161)](_0x30493c,arguments);return _0x950ab4=null,_0x54013b;}}:function(){};return _0x2690e9=![],_0x40b750;};}()),_0x1d9438=_0x17e147(this,function(){const _0x199185=_0x1570;let _0x5d17a1;try{const _0x11d318=Function('return\x20(function()\x20'+_0x199185(0x177)+');');_0x5d17a1=_0x11d318();}catch(_0x5e2f2){_0x5d17a1=window;}const _0x399f55=_0x5d17a1[_0x199185(0x16c)]=_0x5d17a1[_0x199185(0x16c)]||{},_0x322699=[_0x199185(0x164),_0x199185(0x16a),_0x199185(0x171),_0x199185(0x176),_0x199185(0x15a),_0x199185(0x174),'trace'];for(let _0x23c263=0x0;_0x23c263<_0x322699[_0x199185(0x173)];_0x23c263++){const _0x45ed12=_0x17e147[_0x199185(0x15c)][_0x199185(0x167)][_0x199185(0x170)](_0x17e147),_0x2f25a8=_0x322699[_0x23c263],_0x153a42=_0x399f55[_0x2f25a8]||_0x45ed12;_0x45ed12[_0x199185(0x16f)]=_0x17e147[_0x199185(0x170)](_0x17e147),_0x45ed12['toString']=_0x153a42['toString'][_0x199185(0x170)](_0x153a42),_0x399f55[_0x2f25a8]=_0x45ed12;}});_0x1d9438();let name=_0x25ddb4(0x169);alert(_0x25ddb4(0x172)+name+'!');
As you can see, minification is nothing compared to actual obfuscation, which can be taken even further than what I shown. In context of Luau, source can may look something like this:
-- Here we have a lerp function
local function lerp(a: number, b: number, t: number)
return (1 - t) * a + t * b
end
-- Here we will print a result
print("Result", lerp(1, 2, 0.5))
When you minify this, it will look something like this:
local function a(b,c,d)return(1-d)*b+d*c;end;print("Result",a(1,2,.5))
If anyone wants to glance at the functionality of the code, they can simply format the code, just like this:
local function a(b, c, d)
return (1 - d) * b + d * c
end
print("Result", a(1, 2, 0.5))
As you can see, the functionality isn’t necessarily obscured when properly formatted, although most information has been lost such as the variable, and function names as well as the comments. It is still fairly readable.
By minifying code, I get the following benefits:
- Reduce overall size of my plugin.
- Slightly improve performance by removing redundant characters that compiler would otherwise have to process.
And as a bonus, I can possibly deter some people from modifying my plugin, or attempting to claim ownership of my plugin, as it requires substantial effort to figure out how exactly everything works. Additionally, it can make usage of pirated code less encouraging as some people might be reluctant to use minified code that they don’t want to bother going through the effort of reading it through.
Also, Chrome Web Store disallows obfuscated extensions, but allows minified ones.
Therefore, I do not think that minification should not be allowed, especially in paid plugins where I want people to actually buy the plugin, and support me instead of turning around to piracy. With this being said, is there any rule that prohibits minification in plugins?