diff --git a/Loader/Config/InGameSettingsEditorSettings/Descriptions.luau b/Loader/Config/InGameSettingsEditorSettings/Descriptions.luau new file mode 100644 index 0000000000..8ee9318abf --- /dev/null +++ b/Loader/Config/InGameSettingsEditorSettings/Descriptions.luau @@ -0,0 +1,121 @@ +return { + HideScript = [[ Disable if your game saves; When the game starts the Adonis_Loader model will be hidden so other scripts cannot access the settings module ]]; + DataStore = [[ DataStore the script will use for saving data; Changing this will lose any saved data ]]; + DataStoreKey = [[ Key used to encode all datastore entries; Changing this will lose any saved data ]]; + DataStoreEnabled = [[ Disable if you don't want settings and admins to be saveable in-game; PlayerData will still save ]]; + LocalDatastore = [[ If this is turned on, a mock DataStore will forcibly be used instead and shall never save across servers ]]; + + Storage = [[ Where things like tools are stored ]]; + RecursiveTools = [[ Whether tools that are included in sub-containers within settings.Storage will be available via the :give command (useful if your tools are organized into multiple folders) ]]; + + Theme = [[ UI theme; ]]; + MobileTheme = [[ Theme to use on mobile devices; Mobile themes are optimized for smaller screens; Some GUIs are disabled ]]; + + Ranks = [[ All admin permission level ranks; ]]; + Moderators = [[ Mods; Format: {"Username"; "Username:UserId"; UserId; "Group:GroupId:GroupRank"; "Group:GroupId"; "Item:ItemID";} ]]; + Admins = [[ Admins; Format: {"Username"; "Username:UserId"; UserId; "Group:GroupId:GroupRank"; "Group:GroupId"; "Item:ItemID";} ]]; + HeadAdmins = [[ Head Admins; Format: {"Username"; "Username:UserId"; UserId; "Group:GroupId:GroupRank"; "Group:GroupId"; "Item:ItemID";} ]]; + Creators = [[ Anyone to be identified as a place owner; Format: {"Username"; "Username:UserId"; UserId; "Group:GroupId:GroupRank"; "Group:GroupId"; "Item:ItemID";} ]]; + + Permissions = [[ Command permissions; Format: {"Command:NewLevel";} ]]; + Aliases = [[ Command aliases; Format: {[":alias ..."] = ":command ..."} ]]; + Cameras = [[ Cameras; Format: {Name = "CamName", Position = Vector3.new(X, Y, Z)} ]]; + + Commands = [[ Custom commands ]]; + Banned = [[ List of people banned from the game; Format: {"Username"; "Username:UserId"; UserId; "Group:GroupId:GroupRank"; "Group:GroupId"; "Item:ItemID";} ]]; + Muted = [[ List of people muted; Format: {"Username"; "Username:UserId"; UserId; "Group:GroupId:GroupRank"; "Group:GroupId"; "Item:ItemID";} ]]; + Blacklist = [[ List of people banned from using admin; Format: {"Username"; "Username:UserId"; UserId; "Group:GroupId:GroupRank"; "Group:GroupId"; "Item:ItemID";} ]]; + Whitelist = [[ People who can join if whitelist enabled; Format: {"Username"; "Username:UserId"; UserId; "Group:GroupId:GroupRank"; "Group:GroupId"; "Item:ItemID";} ]]; + MusicList = [[ List of songs to appear in the script; Format: {{Name = "somesong",ID = 1234567},{Name = "anotherone",ID = 1243562}} ]]; + CapeList = [[ List of capes; Format: {{Name = "somecape",Material = "Fabric",Color = "Bright yellow",ID = 12345567,Reflectance = 1},{etc more stuff here}} ]]; + InsertList = [[ List of models to appear in the script; Format: {{Name = "somemodel",ID = 1234567},{Name = "anotherone",ID = 1243562}} ]]; + Waypoints = [[ List of waypoints you can teleport via ':to wp-WAYPOINTNAME' or ':teleport PLAYER tp.WAYPOINTNAME' Format {YOURNAME1 = Vector3.new(1,2,3), YOURNAME2 = Vector(231,666,999)} ]]; + CustomRanks = [[ List of custom AdminLevel ranks Format: {RankName = {"Username"; "Username:UserId"; UserId; "Group:GroupId:GroupRank"; "Group:GroupId"; "Item:ItemID";};} ]]; + + OnStartup = [[ List of commands ran at server start Format: {":notif TestNotif"} ]]; + OnJoin = [[ List of commands ran as player on join (ignores adminlevel) Format: {":cmds"} ]]; + OnSpawn = [[ List off commands ran as player on spawn (ignores adminlevel) Format: {"!fire Really red",":ff me"} ]]; + + SaveAdmins = [[ If true anyone you :mod, :admin, or :headadmin in-game will save]]; + LoadAdminsFromDS = [[ If false, any admins saved in your DataStores will not load ]]; + WhitelistEnabled = [[ If true enables the whitelist/server lock; Only lets admins & whitelisted users join ]]; + + Prefix = [[ The : in :kill me ]]; + PlayerPrefix = [[ The ! in !donate; Mainly used for commands that any player can run ]]; + SpecialPrefix = [[ Used for things like "all", "me" and "others" (If changed to ! you would do :kill !me) ]]; + SplitKey = [[ The space in ;kill me (eg if you change it to / :kill me would be :kill/me) ]]; + BatchKey = [[ :kill me | :ff bob | :explode scel ]]; + ConsoleKeyCode = [[ Keybind to open the console ]]; + + HttpWait = [[ How long things that use the HttpService will wait before updating again ]]; + Trello_Enabled = [[ Are the Trello features enabled? ]]; + Trello_Primary = [[ Primary Trello board ]]; + Trello_Secondary = [[ Secondary Trello boards; Format: {"BoardID";"BoardID2","etc"} ]]; + Trello_AppKey = [[ Your Trello AppKey; ]]; + Trello_Token = [[ Trello token (DON'T SHARE WITH ANYONE!) ]]; + Trello_HideRanks = [[ If true, Trello-assigned ranks won't be shown in the admins list UI (accessed via :admins) ]]; + + G_API = [[ If true, allows other server scripts to access certain functions described in the API module through _G.Adonis ]]; + G_Access = [[ If enabled, allows other scripts to access Adonis using _G.Adonis.Access; Scripts will still be able to do things like _G.Adonis.CheckAdmin(player) ]]; + G_Access_Key = [[ Key required to use the _G access API; Example_Key will not work for obvious reasons ]]; + G_Access_Perms = [[ Access perms level ]]; + Allowed_API_Calls = [[ Allowed calls ]]; + + FunCommands = [[ Are fun commands enabled? ]]; + PlayerCommands = [[ Are players commands enabled? ]]; + AgeRestrictedCommands = [[ Are age-restricted commands enabled? ]]; + WarnDangerousCommand = [[ Do dangerous commands ask for confirmation before executing?]]; + CommandFeedback = [[ Should players be notified when commands with non-obvious effects are run on them? ]]; + CrossServerCommands = [[ Are commands which affect more than one server enabled? ]]; + ChatCommands = [[ If false you will not be able to run commands via the chat; Instead, you MUST use the console or you will be unable to run commands ]]; + SilentCommandDenials = [[ If true, there will be no differences between the error messages shown when a user enters an invalid command and when they have insufficient permissions for the command ]]; + OverrideChatCallbacks = [[ If the TextChatService ShouldDeliverCallbacks of all channels are overridden by Adonis on load. Required for muting ]]; + + BanMessage = [[ Message shown to banned users ]]; + LockMessage = [[ Message shown to people when they are kicked while the game is :slocked ]]; + SystemTitle = [[ Title to display in :sm ]]; + + CreatorPowers = [[ Gives me creator-level admin; This is strictly used for debugging; I can't debug without access to the script and specific owner commands ]]; + MaxLogs = [[ Maximum logs to save before deleting the oldest; Too high can lag the game ]]; + SaveCommandLogs = [[ If command logs are saved to the datastores ]]; + Notification = [[ Whether or not to show the "You're an admin" and "Updated" notifications ]]; + CodeExecution = [[ Enables the use of code execution in Adonis; Scripting related and a few other commands require this ]]; + SongHint = [[ Display a hint with the current song name and ID when a song is played via :music ]]; + TopBarShift = [[ By default hints and notifs will appear from the top edge of the window. Set this to true if you don't want hints/notifications to appear in that region. ]]; + DefaultTheme = [[ Theme to be used as a replacement for "Default". The new replacement theme can still use "Default" as its Base_Theme however any other theme that references "Default" as its redirects to this theme. ]]; + ReJail = [[ If true then when a player rejoins they'll go back into jail. Or if the moderator leaves everybody gets unjailed ]]; + + Messages = [[ A list of notifications shown on join. Messages can either be strings or tables. Messages are shown to HeadAdmins+ by default but tables can define a different minimum level via .Level ]]; + + AutoClean = [[ Will auto clean workspace of things like hats and tools ]]; + AutoBackup = [[ (not recommended) Run a map backup command when the server starts, this is mostly useless as clients cannot modify the server. To restore the map run :restoremap ]]; + AutoCleanDelay = [[ Time between auto cleans ]] +; + PlayerList = [[ Custom playerlist ]]; + + Console = [[ Command console ]]; + Console_AdminsOnly = [[ Makes it so if the console is enabled, only admins will see it ]]; + + DonorCommands = [[ Show your support for the script and let donors use commands like !sparkles ]]; + DonorCapes = [[ Determines if donors have capes ]]; + LocalCapes = [[ Makes Donor capes local instead of removing them ]]; + + HelpSystem = [[ Allows players to call admins for help using !help ]]; + HelpButton = [[ Shows a little help button in the bottom right corner ]]; + HelpButtonImage = [[ Change this to change the help button's image ]]; + + AllowClientAntiExploit = [[ Enables client-sided anti-exploit functionality ]]; + Detection = [[ (Extremely important, makes all protection systems work) A global toggle for all the other protection settings ]]; + CheckClients = [[ (Important, makes sure Adonis clients are connected to the server) Checks clients every minute or two to make sure they are still active ]]; + + ExploitNotifications = [[ Notify all moderators and higher-ups when a player is kicked or crashed from the AntiExploit ]]; + CharacterCheckLogs = [[If the character checks appear in exploit logs and exploit notifications]]; + AntiNoclip = [[ Attempts to detect noclipping and kills the player if found ]]; + AntiRootJointDeletion = [[ Attempts to detect paranoid and kills the player if found ]]; + AntiMultiTool = [[ Prevents multitool and because of that many other exploits ]]; + AntiGod = [[ If a player does not respawn when they should have they get respawned ]]; + + AntiSpeed = [[ (Client-Sided) Attempts to detect speed exploits ]]; + AntiBuildingTools = [[ (Client-Sided) Attempts to detect any HopperBin(s)/Building Tools added to the client ]]; + AntiAntiIdle = [[ (Client-Sided) Kick the player if they are using an anti-idle exploit. Highly useful for grinding/farming games ]]; +}; \ No newline at end of file diff --git a/Loader/Config/InGameSettingsEditorSettings/Order.luau b/Loader/Config/InGameSettingsEditorSettings/Order.luau new file mode 100644 index 0000000000..3e6e18e54e --- /dev/null +++ b/Loader/Config/InGameSettingsEditorSettings/Order.luau @@ -0,0 +1,113 @@ +return { + "HideScript"; + "DataStore"; + "DataStoreKey"; + "DataStoreEnabled"; + "LocalDatastore"; + " "; + "Storage"; + "RecursiveTools"; + " "; + "Theme"; + "MobileTheme"; + " "; + "Ranks"; + " "; + "Permissions"; + "Aliases"; + "Cameras"; + " "; + "Commands"; + "Banned"; + "Muted"; + "Blacklist"; + "Whitelist"; + "MusicList"; + "CapeList"; + "InsertList"; + "Waypoints"; + "CustomRanks"; + " "; + "OnStartup"; + "OnJoin"; + "OnSpawn"; + " "; + "SaveAdmins"; + "WhitelistEnabled"; + " "; + "Prefix"; + "PlayerPrefix"; + "SpecialPrefix"; + "SplitKey"; + "BatchKey"; + "ConsoleKeyCode"; + " "; + "HttpWait"; + "Trello_Enabled"; + "Trello_Primary"; + "Trello_Secondary"; + "Trello_AppKey"; + "Trello_Token"; + "Trello_HideRanks"; + " "; + "G_API"; + "G_Access"; + "G_Access_Key"; + "G_Access_Perms"; + "Allowed_API_Calls"; + " "; + "FunCommands"; + "PlayerCommands"; + "AgeRestrictedCommands"; + "WarnDangerousCommand"; + "CommandFeedback"; + "CrossServerCommands"; + "ChatCommands"; + "CreatorPowers"; + ""; + "SilentCommandDenials"; + "OverrideChatCallbacks"; + " "; + "BanMessage"; + "LockMessage"; + "SystemTitle"; + " "; + "MaxLogs"; + "SaveCommandLogs"; + "Notification"; + "SongHint"; + "TopBarShift"; + "DefaultTheme"; + "ReJail"; + ""; + "AutoClean"; + "AutoCleanDelay"; + "AutoBackup"; + " "; + "PlayerList"; + "Console"; + "Console_AdminsOnly"; + " "; + "HelpSystem"; + "HelpButton"; + "HelpButtonImage"; + " "; + "DonorCommands"; + "DonorCapes"; + "LocalCapes"; + " "; + "AllowClientAntiExploit"; + "Detection"; + "CheckClients"; + " "; + "ExploitNotifications"; + "CharacterCheckLogs"; + "AntiNoclip"; + "AntiRootJointDeletion"; + "AntiMultiTool"; + "AntiGod"; + " "; + "AntiSpeed"; + "AntiBuildingTools"; + "AntiAntiIdle"; +}; \ No newline at end of file diff --git a/Loader/Config/Settings.luau b/Loader/Config/Settings.luau deleted file mode 100644 index 786beb98d0..0000000000 --- a/Loader/Config/Settings.luau +++ /dev/null @@ -1,630 +0,0 @@ ----------------------------------------------- ---- Scroll down for settings --- ---- Do not alter the three variables below --- ----------------------------------------------- -local settings = {}; --// The settings table which contains all settings -local Settings = settings; --// For custom commands that use 'Settings' rather than the lowercase 'settings' -local descs = {}; --// Contains settings descriptions ----------------------------------------------- - --------------- --- SETTINGS -- --------------- - --[[ - - --// Basic Luau Info - - This is only here to help you when editing settings so you understand how they work - and don't break something. - - In case you don't know what Luau is; Luau is the scripting language Roblox uses... - so every script you see (such as this one) and pretty much any code on Roblox is - written in Luau. - - Anything that looks like {} is known as a table. - Tables contain things, like the Luau version of a box. - An example of a table would be setting = {"John", "Mary", "Bill"} - You can have tables inside of tables, such in the case of setting = {{Group = 1234, Rank = 123, Type = "Admin"}} - Just like real boxes, tables can contain pretty much anything including other tables. - - Note: Commas (,) as well as semicolons (;) can both be used to separate things inside a table. - - Anything that looks like "Bob" is what's known as a string. Strings - are basically plain text; setting = "Bob" would be correct however - setting = Bob would not; because if it's not surrounded by quotes Luau will think - that Bob is a variable; Quotes indicate something is a string and therefore not a variable/number/code - - Numbers do not use quotes. setting = 56 - - This block of text you are reading is called a comment. It's like a message - from the programmer to anyone who reads their stuff. Anything in a comment will - not be seen by Luau when the script is run. - - - - --// Settings [READ IF CONFUSED] - - If you see something like "Format: 'Username:UserId'" it means that anything you put - in that table must follow one of the formats next to Format: - - For instance, if I wanted to give admin to a player using their username, userId, a group they are in - or an item they own I would do the following with the settings.Admins table: - - The format for the Admins' table's entries is "Username"; or "Username:UserId"; or UserId; or "Group:GroupId:GroupRank" or "Item:ItemID" - This means that if I want to admin Bobjenkins123 who has a userId of 1234567, is in - group "BobFans" (group ID 7463213) under the rank number 234, or owns the item belonging to ID 1237465 - I can do any of the following: - - settings.Ranks["Admins"] = { - Level = 200 - Users = { - "Bobjenkins123", "Bobjenkins123:1234567", 1234567, "Group:7463213:234", "Item:1237465" - } - } - - - If I wanted to make it so rank 134 in group 1029934 and BobJenkins123 had mod admin I would do - settings.Ranks["Moderators"] = { - Level = 100 - Users = { - "Group:1029943:134", "BobJenkins123" - } - } - - !NOTE! When adding a group to a table, you may be tempted to replace the word Group with the name of your group – DON'T. - The group name is IRRELEVANT! If one's group was named 2Drool4School and it had the ID 2847031, the correct form is {"Group:2847031"} - and not {"2Drool4School:2847031"} - - --// Command Permissions - - You can set the permission level for specific commands using setting.Permissions - If I wanted to make it so only HeadAdmins+ can use :ff player then I would do: - - settings.Permissions = {"ff:HeadAdmins"} - - ff is the Command ":ff scel" and HeadAdmins is the NewLevel - - Built-In Permissions Levels: - Players - 0 - Moderators - 100 - Admins - 200 - HeadAdmins - 300 - Creators - 900 - - Note that when changing command permissions you MUST include the prefix; - So if you change the prefix to $ you would need to do $ff instead of :ff - - - --// Trello - - The Trello abilities of the script allow you to manage lists and permissions via - a Trello board; The following will guide you through the process of setting up a board; - - 1. Sign up for an account at trello - 2. Create a new board - 3. Get the board ID; - 4. Set settings.Trello_Primary to your board ID - 5. Set settings.Trello.Enabled to true - 6. Congrats! The board is ready to be used; - 7. Create a list and add cards to it; - - - You can view lists in-game using :viewlist ListNameHere - - Lists: - Moderators - Card Format: Same as settings.Moderators - Admins - Card Format: Same as settings.Admins - HeadAdmins - Card Format: Same as settings.HeadAdmins - Creators - Card Format: Same as settings.Creators - Banlist - Card Format: Same as settings.Banned - Mutelist - Card Format: Same as settings.Muted - Blacklist - Card Format: Same as settings.Blacklist - Whitelist - Card Format: Same as settings.Whitelist - Permissions - Card Format: Same as settings.Permissions - Music - Card Format: SongName:AudioID - Commands - Card Format: Command (eg. :ff bob) - - Card format refers to how card names should look - - - MAKE SURE YOU SET settings.DataStoreKey TO ANYTHING RANDOM. - --]] - -settings.HideScript = true -- When the game starts the Adonis_Loader model will be hidden so other scripts cannot access the settings module; Disable if your game uses AssetService:SavePlaceAsync() -settings.DataStore = "Adonis_1" -- DataStore the script will use for saving data; Changing this will lose any saved data -settings.DataStoreKey = "CHANGE_THIS" -- CHANGE THIS TO ANYTHING RANDOM! Key used to encrypt all datastore entries; Changing this will lose any saved data -settings.DataStoreEnabled = true -- Disable if you don't want to load settings and admins from the datastore; PlayerData will still save -settings.LocalDatastore = false -- If this is turned on, a mock DataStore will forcibly be used instead and shall never save across servers - -settings.Storage = game:GetService("ServerStorage") -- Where things like tools are stored -settings.RecursiveTools = false -- Whether tools that are included in sub-containers within settings.Storage will be available via the :give command (useful if your tools are organized into multiple folders) - -settings.Theme = "Default" -- UI theme; -settings.MobileTheme = "Mobilius" -- Theme to use on mobile devices; Some UI elements are disabled - --[[ - **HOW TO ADD ADMINISTRATORS:** - Below are the administrator permission levels/ranks (Mods, Admins, HeadAdmins, Creators, StuffYouAdd, etc) - Simply place users into the respective "Users" table for whatever level/rank you want to give them. - - Format Example: - settings.Ranks = { - ["Moderators"] = { - Level = 100; - Users = { - "Username"; "Username:UserId"; UserId; "Group:GroupId:GroupRank"; "Group:GroupId"; "Item:ItemID"; "GamePass:GamePassID"; "Subscription:SubscriptionId"; - } - } - } - - If you use custom ranks, existing custom ranks will be imported with a level of 1. - Add all new CustomRanks to the table below with the respective level you want them to be. - - NOTE: Changing the level of built-in ranks (Moderators, Admins, HeadAdmins, Creators) - will also change the permission level for any built-in commands associated with that rank. - -]] - -settings.Ranks = { - ["Moderators"] = { - Level = 100; - Users = { - --// Add users here - }; - }; - - ["Admins"] = { - Level = 200; - Users = { - --// Add users here - }; - }; - - ["HeadAdmins"] = { - Level = 300; - Users = { - --// Add users here - }; - }; - - ["Creators"] = { - Level = 900; --// Anything 900 or higher will be considered a creator and will bypass all perms & be allowed to edit settings in-game. - Users = { - --// Add users here (Also, don't forget quotations and all that) - }; - }; -}; - ---// Use the below table to set command permissions; Commented commands are included for example purposes -settings.Permissions = { - -- "ff:HeadAdmins"; --// Changes :ff to HeadAdmins and higher (HeadAdmins = Level 300 by default) - -- "kill:300"; --// Changes :kill to level 300 and higher (Level 300 = HeadAdmins by default) - -- "ban:200,300" --// Makes it so :ban is only usable by levels 200 and 300 specifically (nothing higher or lower or in between) -}; -- Format: {"Command:NewLevel"; "Command:Customrank1,Customrank2,Customrank3";} - ---// Use the below table to define "pre-set" command aliases ---// Command aliases; Format: {[":alias ..."] = ":command ..."} -settings.Aliases = { - [":examplealias "] = ":ff | :fling | :fire " --// Order arguments appear in alias string determines their required order in the command message when ran later -}; - ---// Use the below table to define pre-set cameras -settings.Cameras = { ---[[ - "Camera Name" would be the name of your camera - { - Name = "Camera Name"; - Position = Vector3.new(0, 0, 0) - } -]] -} - -settings.Banned = {} -- List of people banned from the game Format: {"Username"; "Username:UserId"; UserId; "Group:GroupId:GroupRank"; "Group:GroupId"; "Item:ItemID"; "GamePass:GamePassID";} -settings.Muted = {} -- List of people muted (cannot send chat messages) Format: {"Username"; "Username:UserId"; UserId; "Group:GroupId:GroupRank"; "Group:GroupId"; "Item:ItemID"; "GamePass:GamePassID";} -settings.Blacklist = {} -- List of people banned from running commands Format: {"Username"; "Username:UserId"; UserId; "Group:GroupId:GroupRank"; "Group:GroupId"; "Item:ItemID"; "GamePass:GamePassID";} -settings.Whitelist = {} -- People who can join if whitelist enabled Format: {"Username"; "Username:UserId"; UserId; "Group:GroupId:GroupRank"; "Group:GroupId"; "Item:ItemID"; "GamePass:GamePassID";} - -settings.MusicList = {} -- List of songs to appear in the :musiclist Format: {{Name = "somesong", ID = 1234567}, {Name = "anotherone", ID = 1243562}} -settings.CapeList = {} -- List of capes Format: {{Name = "somecape", Material = "Fabric", Color = "Bright yellow", ID = 12345567, Reflectance = 1}; {etc more stuff here}} -settings.InsertList = {} -- List of models to appear in the :insertlist and can be inserted using ':insert ' Format: {{Name = "somemodel", ID = 1234567}; {Name = "anotherone", ID = 1243562}} -settings.Waypoints = {} -- List of waypoints you can teleport via ':to wp-WAYPOINTNAME' or ':teleport PLAYER tp.WAYPOINTNAME' Format {YOURNAME1 = Vector3.new(1,2,3), YOURNAME2 = Vector(231,666,999)} - -settings.OnStartup = {} -- List of commands ran at server start Format: {":notif TestNotif"} -settings.OnJoin = {} -- List of commands ran as player on join (ignores adminlevel) Format: {":cmds"} -settings.OnSpawn = {} -- List off commands ran as player on spawn (ignores adminlevel) Format: {"!fire Really red",":ff me"} - -settings.SaveAdmins = true -- If true anyone you :admin or :headadmin in-game will save -settings.LoadAdminsFromDS = true -- If false, any admins saved in your DataStores will not load -settings.WhitelistEnabled = false -- If true enables the whitelist/server lock; Only lets admins & whitelisted users join - -settings.Prefix = {":", ";"} -- A list of prefixes for commands, the : in :kill me -settings.PlayerPrefix = "!" -- The ! in !donate; Mainly used for commands that any player can run; Do not make it the same as settings.Prefix -settings.SpecialPrefix = "" -- Used for things like "all", "me" and "others" (If changed to ! you would do :kill !me) -settings.SplitKey = " " -- The space in :kill me (eg if you change it to / :kill me would be :kill/me) -settings.BatchKey = "|" -- :kill me | :ff bob | :explode scel -settings.ConsoleKeyCode = "Quote" -- Keybind to open the console; Rebindable per player in userpanel; KeyCodes: https://developer.roblox.com/en-us/api-reference/enum/KeyCode - ---// Easily add new custom commands below (without needing to create a plugin module) ---// You can also use this to overwrite existing commands if you know the command's index (found in the command's respective module within the Adonis MainModule) -settings.Commands = { - ExampleCommand1 = { --// The index & table of the command - Prefix = Settings.Prefix; --// The prefix the command will use, this is the ':' in ':ff me' - Commands = {"examplecommand1", "examplealias1", "examplealias2"}; --// A table containing the command strings (the things you chat in-game to run the command, the 'ff' in ':ff me') - Args = {"arg1", "arg2", "etc"}; --// Command arguments, these will be available in order as args[1], args[2], args[3], etc; This is the 'me' in ':ff me' - Description = "Example command";--// The description of the command - AdminLevel = 100; -- Moderators --// The commands minimum admin level; This can also be a table containing specific levels rather than a minimum level: {124, 152, "HeadAdmins", etc}; - -- Alternative option: AdminLevel = "Moderators" - Filter = true; --// Should user-supplied text passed to this command be filtered automatically? Use this if you plan to display a user-defined message to other players - Hidden = true; --// Should this command be hidden from the command list? - Disabled = true; --// If set to true this command won't be usable. - Function = function(plr: Player, args: {string}, data) --// The command's function; This is the actual code of the command which runs when you run the command - --// "plr" is the player running the command - --// "args" is an array of strings containing command arguments supplied by the user - --// "data" is a table containing information related to the command and the player running it, such as data.PlayerData.Level (the player's admin level) [Refer to API docs] - print("This is 'arg1':", tostring(args[1])) - print("This is 'arg2':", tostring(args[2])) - print("This is 'etc'(arg 3):", tostring(args[3])) - error("this is an example error :o !") --// Errors raised in the function during command execution will be displayed to the user. - end - }; -} - -settings.CommandCooldowns = { ---[[ - REFERENCE: - command_full_name: The name of a command (e.g. :cmds) - - [command_full_name] = { - Player = 0; - Server = 0; - Cross = 0; - } -]] -} - -settings.FunCommands = true -- Are fun commands enabled? -settings.PlayerCommands = true -- Are player-level utility commands enabled? -settings.AgeRestrictedCommands = true -- Are age-locked commands enabled? -settings.WarnDangerousCommand = false -- Do dangerous commands ask for confirmation? -settings.CommandFeedback = false -- Should players be notified when commands with non-obvious effects are run on them? -settings.CrossServerCommands = true -- Are commands which affect more than one server enabled? -settings.ChatCommands = true -- If false you will not be able to run commands via the chat; Instead, you MUST use the console or you will be unable to run commands -settings.CreatorPowers = true -- Gives me creator-level admin; This is strictly used for debugging; I can't debug without full access to the script -settings.CodeExecution = false -- Enables the use of code execution in Adonis. Scripting related (such as :s) and a few other commands require this -settings.SilentCommandDenials = false -- If true, there will be no differences between the error messages shown when a user enters an invalid command and when they have insufficient permissions for the command -settings.OverrideChatCallbacks = true -- If the TextChatService ShouldDeliverCallbacks of all channels are overridden by Adonis on load. Required for slowmode. Mutes use a CanSend method to mute when this is set to false. -settings.ChatCreateRobloxCommands = false -- Whether "/" commands for Roblox should get created in new Chat - -settings.BanMessage = "Banned" -- Message shown to banned users upon kick -settings.LockMessage = "Not Whitelisted" -- Message shown to people when they are kicked while the game is :slocked -settings.SystemTitle = "System Message" -- Title to display in :sm and :bc - -settings.MaxLogs = 5000 -- Maximum logs to save before deleting the oldest -settings.SaveCommandLogs = true -- If command logs are saved to the datastores -settings.Notification = true -- Whether or not to show the "You're an admin" and "Updated" notifications -settings.SongHint = true -- Display a hint with the current song name and ID when a song is played via :music -settings.TopBarShift = false -- By default hints and notifications will appear from the top edge of the window. Set this to true if you don't want hints/notifications to appear in that region. -settings.DefaultTheme = "Default" -- Theme to be used as a replacement for "Default". The new replacement theme can still use "Default" as its Base_Theme however any other theme that references "Default" as its redirects to this theme. -settings.HiddenThemes = {} -- Hide themes from the theme selector tab inside the userpanel. Each theme name must be the specific name such as "Mobilius" -settings.Messages = {} -- A list of notifications shown on join. Messages can either be strings or tables. Messages are shown to HeadAdmins+ by default but tables can define a different minimum level via .Level -settings.AutoClean = false -- Will auto clean workspace of things like hats and tools -settings.AutoCleanDelay = 60 -- Time between auto cleans -settings.AutoBackup = false -- Run :backupmap automatically when the server starts. To restore the map, run :restoremap -settings.ReJail = false -- If true then when a player rejoins they'll go back into jail. Or if the moderator leaves everybody gets unjailed - -settings.Console = true -- Whether the command console is enabled -settings.Console_AdminsOnly = false -- If true, only admins will be able to access the console - -settings.HelpSystem = true -- Allows players to call admins for help using !help -settings.HelpButton = true -- Shows a little help button in the bottom right corner. -settings.HelpButtonImage = "rbxassetid://357249130" -- Sets the image used for the Adonis help button above. - - --------------------- --- DONOR SETTINGS -- --------------------- - -settings.DonorCapes = true -- Donors get to show off their capes; Not disruptive :) -settings.DonorCommands = true -- Show your support for the script and let donors use harmless commands like !sparkles -settings.LocalCapes = false -- Makes Donor capes local so only the donors see their cape [All players can still disable capes locally] - - --------------------------- --- HTTP/TRELLO SETTINGS -- --------------------------- - -settings.HttpWait = 60 -- How long things that use the HttpService will wait before updating again -settings.Trello_Enabled = false -- Are the Trello features enabled? -settings.Trello_Primary = "" -- Primary Trello board -settings.Trello_Secondary = {} -- Secondary Trello boards (read-only) Format: {"BoardID";"BoardID2","etc"} -settings.Trello_AppKey = "" -- Your Trello AppKey -settings.Trello_Token = "" -- Trello token (DON'T SHARE WITH ANYONE!) Get API key: /1/connect?name=Trello_API_Module&response_type=token&expires=never&scope=read,write&key=YOUR_APP_KEY_HERE -settings.Trello_HideRanks = false -- If true, Trello-assigned ranks won't be shown in the admins list UI (accessed via :admins) - - ---------------------- --- _G API SETTINGS -- ---------------------- - -settings.G_API = true -- If true, allows other server scripts to access certain functions described in the API module through _G.Adonis -settings.G_Access = false -- If enabled, allows other scripts to access Adonis using _G.Adonis.Access; Scripts will still be able to do things like _G.Adonis.CheckAdmin(player) -settings.G_Access_Key = "Example_Key" -- Key required to use the _G access API; Example_Key will not work for obvious reasons -settings.G_Access_Perms = "Read" -- Access perms -settings.Allowed_API_Calls = { - Client = false; -- Allow access to the Client (not recommended) - Settings = false; -- Allow access to settings (not recommended) - DataStore = false; -- Allow access to the DataStore (not recommended) - Core = false; -- Allow access to the script's core table (REALLY not recommended) - Service = false; -- Allow access to the script's service metatable - Remote = false; -- Communication table - HTTP = false; -- HTTP-related things like Trello functions - Anti = false; -- Anti-Exploit table - Logs = false; - UI = false; -- Client UI table - Admin = false; -- Admin related functions - Functions = false; -- Functions table (contains functions used by the script that don't have a subcategory) - Variables = true; -- Variables table - API_Specific = true; -- API Specific functions -} - - ---------------------------- --- ANTI-EXPLOIT SETTINGS -- ---------------------------- - ---// IF YOU EXPERIENCE ISSUES WITH FALSE POSITIVES/RANDOM KICKING/CRASHING DISABLE ALL OF THESE! - -settings.AllowClientAntiExploit = false -- (Default: false) Allows use of client-sided anti exploit functionality if true -settings.Detection = false -- (Default: false) If true: enables built-in anti-exploit detections that do not have their own settings. -settings.CheckClients = true -- (Default: true) Checks clients every minute or two to make sure they are still active. - -settings.ExploitNotifications = true -- (Default: true) Notify all moderators and higher-ups when a player is kicked or crashed from the AntiExploit. -settings.CharacterCheckLogs = false -- (Default: false) If the character checks appear in exploit logs and exploit notifications. -settings.AntiNoclip = false -- (Default: false) Attempts to detect noclipping and kills the player if found. -settings.AntiRootJointDeletion = false -- (Default: false) Attempts to detect paranoid and kills the player if found. -settings.AntiMultiTool = false -- (Default: false) Prevents multitool and because of that many other exploits. -settings.AntiGod = false -- (Default: false) If a player does not respawn when they should have they get respawned. - -settings.AntiSpeed = false -- (Default: false) (Client-Sided) Attempts to detect speed exploits. -settings.AntiBuildingTools = false -- (Default: false) (Client-Sided) Attempts to detect any HopperBin(s)/Building Tools added to the client. -settings.AntiAntiIdle = false -- (Default: false) (Client-Sided) Kick the player if they are using an anti-idle exploit. Highly useful for grinding/farming games. - ---------------------- --- END OF SETTINGS -- ---------------------- - ---// Setting descriptions used for the in-game settings editor; - -descs.HideScript = [[ Disable if your game saves; When the game starts the Adonis_Loader model will be hidden so other scripts cannot access the settings module ]] -descs.DataStore = [[ DataStore the script will use for saving data; Changing this will lose any saved data ]] -descs.DataStoreKey = [[ Key used to encode all datastore entries; Changing this will lose any saved data ]] -descs.DataStoreEnabled = [[ Disable if you don't want settings and admins to be saveable in-game; PlayerData will still save ]] -descs.LocalDatastore = [[ If this is turned on, a mock DataStore will forcibly be used instead and shall never save across servers ]] - -descs.Storage = [[ Where things like tools are stored ]] -descs.RecursiveTools = [[ Whether tools that are included in sub-containers within settings.Storage will be available via the :give command (useful if your tools are organized into multiple folders) ]] - -descs.Theme = [[ UI theme; ]] -descs.MobileTheme = [[ Theme to use on mobile devices; Mobile themes are optimized for smaller screens; Some GUIs are disabled ]] - -descs.Ranks = [[ All admin permission level ranks; ]]; -descs.Moderators = [[ Mods; Format: {"Username"; "Username:UserId"; UserId; "Group:GroupId:GroupRank"; "Group:GroupId"; "Item:ItemID";} ]] -descs.Admins = [[ Admins; Format: {"Username"; "Username:UserId"; UserId; "Group:GroupId:GroupRank"; "Group:GroupId"; "Item:ItemID";} ]] -descs.HeadAdmins = [[ Head Admins; Format: {"Username"; "Username:UserId"; UserId; "Group:GroupId:GroupRank"; "Group:GroupId"; "Item:ItemID";} ]] -descs.Creators = [[ Anyone to be identified as a place owner; Format: {"Username"; "Username:UserId"; UserId; "Group:GroupId:GroupRank"; "Group:GroupId"; "Item:ItemID";} ]] - -descs.Permissions = [[ Command permissions; Format: {"Command:NewLevel";} ]] -descs.Aliases = [[ Command aliases; Format: {[":alias ..."] = ":command ..."} ]] -descs.Cameras = [[ Cameras; Format: {Name = "CamName", Position = Vector3.new(X, Y, Z)} ]] - -descs.Commands = [[ Custom commands ]] -descs.Banned = [[ List of people banned from the game; Format: {"Username"; "Username:UserId"; UserId; "Group:GroupId:GroupRank"; "Group:GroupId"; "Item:ItemID";} ]] -descs.Muted = [[ List of people muted; Format: {"Username"; "Username:UserId"; UserId; "Group:GroupId:GroupRank"; "Group:GroupId"; "Item:ItemID";} ]] -descs.Blacklist = [[ List of people banned from using admin; Format: {"Username"; "Username:UserId"; UserId; "Group:GroupId:GroupRank"; "Group:GroupId"; "Item:ItemID";} ]] -descs.Whitelist = [[ People who can join if whitelist enabled; Format: {"Username"; "Username:UserId"; UserId; "Group:GroupId:GroupRank"; "Group:GroupId"; "Item:ItemID";} ]] -descs.MusicList = [[ List of songs to appear in the script; Format: {{Name = "somesong",ID = 1234567},{Name = "anotherone",ID = 1243562}} ]] -descs.CapeList = [[ List of capes; Format: {{Name = "somecape",Material = "Fabric",Color = "Bright yellow",ID = 12345567,Reflectance = 1},{etc more stuff here}} ]] -descs.InsertList = [[ List of models to appear in the script; Format: {{Name = "somemodel",ID = 1234567},{Name = "anotherone",ID = 1243562}} ]] -descs.Waypoints = [[ List of waypoints you can teleport via ':to wp-WAYPOINTNAME' or ':teleport PLAYER tp.WAYPOINTNAME' Format {YOURNAME1 = Vector3.new(1,2,3), YOURNAME2 = Vector(231,666,999)} ]] -descs.CustomRanks = [[ List of custom AdminLevel ranks Format: {RankName = {"Username"; "Username:UserId"; UserId; "Group:GroupId:GroupRank"; "Group:GroupId"; "Item:ItemID";};} ]] - -descs.OnStartup = [[ List of commands ran at server start Format: {":notif TestNotif"} ]] -descs.OnJoin = [[ List of commands ran as player on join (ignores adminlevel) Format: {":cmds"} ]] -descs.OnSpawn = [[ List off commands ran as player on spawn (ignores adminlevel) Format: {"!fire Really red",":ff me"} ]] - -descs.SaveAdmins = [[ If true anyone you :mod, :admin, or :headadmin in-game will save]] -descs.LoadAdminsFromDS = [[ If false, any admins saved in your DataStores will not load ]] -descs.WhitelistEnabled = [[ If true enables the whitelist/server lock; Only lets admins & whitelisted users join ]] - -descs.Prefix = [[ The : in :kill me ]] -descs.PlayerPrefix = [[ The ! in !donate; Mainly used for commands that any player can run ]] -descs.SpecialPrefix = [[ Used for things like "all", "me" and "others" (If changed to ! you would do :kill !me) ]] -descs.SplitKey = [[ The space in ;kill me (eg if you change it to / :kill me would be :kill/me) ]] -descs.BatchKey = [[ :kill me | :ff bob | :explode scel ]] -descs.ConsoleKeyCode = [[ Keybind to open the console ]] - -descs.HttpWait = [[ How long things that use the HttpService will wait before updating again ]] -descs.Trello_Enabled = [[ Are the Trello features enabled? ]] -descs.Trello_Primary = [[ Primary Trello board ]] -descs.Trello_Secondary = [[ Secondary Trello boards; Format: {"BoardID";"BoardID2","etc"} ]] -descs.Trello_AppKey = [[ Your Trello AppKey; ]] -descs.Trello_Token = [[ Trello token (DON'T SHARE WITH ANYONE!) ]] -descs.Trello_HideRanks = [[ If true, Trello-assigned ranks won't be shown in the admins list UI (accessed via :admins) ]] - -descs.G_API = [[ If true, allows other server scripts to access certain functions described in the API module through _G.Adonis ]] -descs.G_Access = [[ If enabled, allows other scripts to access Adonis using _G.Adonis.Access; Scripts will still be able to do things like _G.Adonis.CheckAdmin(player) ]] -descs.G_Access_Key = [[ Key required to use the _G access API; Example_Key will not work for obvious reasons ]] -descs.G_Access_Perms = [[ Access perms level ]] -descs.Allowed_API_Calls = [[ Allowed calls ]] - -descs.FunCommands = [[ Are fun commands enabled? ]] -descs.PlayerCommands = [[ Are players commands enabled? ]] -descs.AgeRestrictedCommands = [[ Are age-restricted commands enabled? ]] -descs.WarnDangerousCommand = [[ Do dangerous commands ask for confirmation before executing?]] -descs.CommandFeedback = [[ Should players be notified when commands with non-obvious effects are run on them? ]] -descs.CrossServerCommands = [[ Are commands which affect more than one server enabled? ]] -descs.ChatCommands = [[ If false you will not be able to run commands via the chat; Instead, you MUST use the console or you will be unable to run commands ]] -descs.SilentCommandDenials = [[ If true, there will be no differences between the error messages shown when a user enters an invalid command and when they have insufficient permissions for the command ]] -descs.OverrideChatCallbacks = [[ If the TextChatService ShouldDeliverCallbacks of all channels are overridden by Adonis on load. Required for muting ]] - -descs.BanMessage = [[ Message shown to banned users ]] -descs.LockMessage = [[ Message shown to people when they are kicked while the game is :slocked ]] -descs.SystemTitle = [[ Title to display in :sm ]] - -descs.CreatorPowers = [[ Gives me creator-level admin; This is strictly used for debugging; I can't debug without access to the script and specific owner commands ]] -descs.MaxLogs = [[ Maximum logs to save before deleting the oldest; Too high can lag the game ]] -descs.SaveCommandLogs = [[ If command logs are saved to the datastores ]] -descs.Notification = [[ Whether or not to show the "You're an admin" and "Updated" notifications ]] -descs.CodeExecution = [[ Enables the use of code execution in Adonis; Scripting related and a few other commands require this ]] -descs.SongHint = [[ Display a hint with the current song name and ID when a song is played via :music ]] -descs.TopBarShift = [[ By default hints and notifs will appear from the top edge of the window. Set this to true if you don't want hints/notifications to appear in that region. ]] -descs.DefaultTheme = [[ Theme to be used as a replacement for "Default". The new replacement theme can still use "Default" as its Base_Theme however any other theme that references "Default" as its redirects to this theme. ]] -descs.ReJail = [[ If true then when a player rejoins they'll go back into jail. Or if the moderator leaves everybody gets unjailed ]] - -descs.Messages = [[ A list of notifications shown on join. Messages can either be strings or tables. Messages are shown to HeadAdmins+ by default but tables can define a different minimum level via .Level ]] - -descs.AutoClean = [[ Will auto clean workspace of things like hats and tools ]] -descs.AutoBackup = [[ (not recommended) Run a map backup command when the server starts, this is mostly useless as clients cannot modify the server. To restore the map run :restoremap ]] -descs.AutoCleanDelay = [[ Time between auto cleans ]] - -descs.PlayerList = [[ Custom playerlist ]] - -descs.Console = [[ Command console ]] -descs.Console_AdminsOnly = [[ Makes it so if the console is enabled, only admins will see it ]] - -descs.DonorCommands = [[ Show your support for the script and let donors use commands like !sparkles ]] -descs.DonorCapes = [[ Determines if donors have capes ]] -descs.LocalCapes = [[ Makes Donor capes local instead of removing them ]] - -descs.HelpSystem = [[ Allows players to call admins for help using !help ]] -descs.HelpButton = [[ Shows a little help button in the bottom right corner ]] -descs.HelpButtonImage = [[ Change this to change the help button's image ]] - -descs.AllowClientAntiExploit = [[ Enables client-sided anti-exploit functionality ]] -descs.Detection = [[ (Extremely important, makes all protection systems work) A global toggle for all the other protection settings ]] -descs.CheckClients = [[ (Important, makes sure Adonis clients are connected to the server) Checks clients every minute or two to make sure they are still active ]] - -descs.ExploitNotifications = [[ Notify all moderators and higher-ups when a player is kicked or crashed from the AntiExploit ]] -descs.CharacterCheckLogs = [[If the character checks appear in exploit logs and exploit notifications]] -descs.AntiNoclip = [[ Attempts to detect noclipping and kills the player if found ]] -descs.AntiRootJointDeletion = [[ Attempts to detect paranoid and kills the player if found ]] -descs.AntiMultiTool = [[ Prevents multitool and because of that many other exploits ]] -descs.AntiGod = [[ If a player does not respawn when they should have they get respawned ]] - -descs.AntiSpeed = [[ (Client-Sided) Attempts to detect speed exploits ]] -descs.AntiBuildingTools = [[ (Client-Sided) Attempts to detect any HopperBin(s)/Building Tools added to the client ]] -descs.AntiAntiIdle = [[ (Client-Sided) Kick the player if they are using an anti-idle exploit. Highly useful for grinding/farming games ]] -descs.ExploitGuiDetection = [[ (Client-Sided) If any exploit GUIs are found in the CoreGui the exploiter gets kicked (If you use StarterGui:SetCore("SendNotification") with an image this will kick you) ]] - -order = { - "HideScript"; - "DataStore"; - "DataStoreKey"; - "DataStoreEnabled"; - "LocalDatastore"; - " "; - "Storage"; - "RecursiveTools"; - " "; - "Theme"; - "MobileTheme"; - " "; - "Ranks"; - " "; - "Permissions"; - "Aliases"; - "Cameras"; - " "; - "Commands"; - "Banned"; - "Muted"; - "Blacklist"; - "Whitelist"; - "MusicList"; - "CapeList"; - "InsertList"; - "Waypoints"; - "CustomRanks"; - " "; - "OnStartup"; - "OnJoin"; - "OnSpawn"; - " "; - "SaveAdmins"; - "WhitelistEnabled"; - " "; - "Prefix"; - "PlayerPrefix"; - "SpecialPrefix"; - "SplitKey"; - "BatchKey"; - "ConsoleKeyCode"; - " "; - "HttpWait"; - "Trello_Enabled"; - "Trello_Primary"; - "Trello_Secondary"; - "Trello_AppKey"; - "Trello_Token"; - "Trello_HideRanks"; - " "; - "G_API"; - "G_Access"; - "G_Access_Key"; - "G_Access_Perms"; - "Allowed_API_Calls"; - " "; - "FunCommands"; - "PlayerCommands"; - "AgeRestrictedCommands"; - "WarnDangerousCommand"; - "CommandFeedback"; - "CrossServerCommands"; - "ChatCommands"; - "CreatorPowers"; - ""; - "SilentCommandDenials"; - "OverrideChatCallbacks"; - " "; - "BanMessage"; - "LockMessage"; - "SystemTitle"; - " "; - "MaxLogs"; - "SaveCommandLogs"; - "Notification"; - "SongHint"; - "TopBarShift"; - "DefaultTheme"; - "ReJail"; - ""; - "AutoClean"; - "AutoCleanDelay"; - "AutoBackup"; - " "; - "PlayerList"; - "Console"; - "Console_AdminsOnly"; - " "; - "HelpSystem"; - "HelpButton"; - "HelpButtonImage"; - " "; - "DonorCommands"; - "DonorCapes"; - "LocalCapes"; - " "; - "AllowClientAntiExploit"; - "Detection"; - "CheckClients"; - " "; - "ExploitNotifications"; - "CharacterCheckLogs"; - "AntiNoclip"; - "AntiRootJointDeletion"; - "AntiMultiTool"; - "AntiGod"; - " "; - "AntiSpeed"; - "AntiBuildingTools"; - "AntiAntiIdle"; - "ExploitGuiDetection"; -} - -return {Settings = settings, Descriptions = descs, Order = order} diff --git a/Loader/Config/Settings/AntiExploit.luau b/Loader/Config/Settings/AntiExploit.luau new file mode 100644 index 0000000000..23eb43e4bc --- /dev/null +++ b/Loader/Config/Settings/AntiExploit.luau @@ -0,0 +1,25 @@ +--[[ + IMPORTANT: + + IF YOU EXPERIENCE ISSUES WITH FALSE POSITIVES/RANDOM KICKING/CRASHING DISABLE ALL OF THESE SETTINGS! +]] + +--------------------------- +-- ANTI-EXPLOIT SETTINGS -- +--------------------------- + +return { + AllowClientAntiExploit = false; -- (Default: false) Allows use of client-sided anti exploit functionality if true + Detection = false; -- (Default: false) If true: enables built-in anti-exploit detections that do not have their own + CheckClients = true; -- (Default: true) Checks clients every minute or two to make sure they are still active. + ExploitNotifications = true; -- (Default: true) Notify all moderators and higher-ups when a player is kicked or crashed from the AntiExploit. + CharacterCheckLogs = false; -- (Default: false) If the character checks appear in exploit logs and exploit notifications. + + AntiNoclip = false; -- (Default: false) Attempts to detect noclipping and kills the player if found. + AntiRootJointDeletion = false; -- (Default: false) Attempts to detect paranoid and kills the player if found. + AntiMultiTool = false; -- (Default: false) Prevents multitool and because of that many other exploits. + AntiGod = false; -- (Default: false) If a player does not respawn when they should have they get respawned. + AntiSpeed = false; -- (Default: false) (Client-Sided) Attempts to detect speed exploits. + AntiBuildingTools = false; -- (Default: false) (Client-Sided) Attempts to detect any HopperBin(s)/Building Tools added to the client. + AntiAntiIdle = false; -- (Default: false) (Client-Sided) Kick the player if they are using an anti-idle exploit. Highly useful for grinding/farming games. +}; \ No newline at end of file diff --git a/Loader/Config/Settings/Cameras.luau b/Loader/Config/Settings/Cameras.luau new file mode 100644 index 0000000000..4cbe61fe59 --- /dev/null +++ b/Loader/Config/Settings/Cameras.luau @@ -0,0 +1,25 @@ +--[[ + Use the below table to define "pre-set" cameras + + Format example: + + Cameras = { + { + Name = "CameraName"; + Position = Vector3; -- Example: Vector3.new(0, 0, 0) or workspace.ExampleCameraPart.Position + } + } +]] + +---------------------- +-- CAMERAS SETTINGS -- +---------------------- + +return { + Cameras = { + -- { + -- Name = "ExampleCamera1; + -- Position = Vector3.new(0, 50, 0) + -- } + } +} \ No newline at end of file diff --git a/Loader/Config/Settings/CommandAliases.luau b/Loader/Config/Settings/CommandAliases.luau new file mode 100644 index 0000000000..61e9962633 --- /dev/null +++ b/Loader/Config/Settings/CommandAliases.luau @@ -0,0 +1,19 @@ +--[[ + Use the below table to define "pre-set" command aliases + + Format example: + + Aliases = { + [":alias ..."] = ":command ..." + } +]] + +------------------------------ +-- COMMAND ALIASES SETTINGS -- +------------------------------ + +return { + Aliases = { + -- [":examplealias "] = ":ff | :fling | :fire " -- Order arguments appear in alias string determines their required order in the command message when ran later + }; +}; \ No newline at end of file diff --git a/Loader/Config/Settings/CommandCooldowns.luau b/Loader/Config/Settings/CommandCooldowns.luau new file mode 100644 index 0000000000..5a85665c41 --- /dev/null +++ b/Loader/Config/Settings/CommandCooldowns.luau @@ -0,0 +1,23 @@ +--[[ + Format example: + + ["commandname"] = { + Player = 0; -- (optional) Per player cooldown in seconds + Server = 0; -- (optional) Per server cooldown in seconds + Cross = 0; -- (optional) Global cooldown in seconds + } + + Make sure to include the prefix infront of the command name. +]] + +-------------------------------- +-- COMMAND COOLDOWNS SETTINGS -- +-------------------------------- + +return { + CommandCooldowns = { + -- [":logs"] = { + -- Player = 5; -- 5 seconds + -- } + } +} \ No newline at end of file diff --git a/Loader/Config/Settings/CommandPermissions.luau b/Loader/Config/Settings/CommandPermissions.luau new file mode 100644 index 0000000000..19583c54a1 --- /dev/null +++ b/Loader/Config/Settings/CommandPermissions.luau @@ -0,0 +1,20 @@ +--[[ + Format example: + + Permissions = { + "CommandName:NewLevel"; + "CommandName:CustomRank1,CustomRank2,CustomRank3"; + }; +]] + +---------------------------------- +-- COMMAND PERMISSIONS SETTINGS -- +---------------------------------- + +return { + Permissions = { + -- "ff:HeadAdmins"; -- Changes :ff to HeadAdmins and higher (HeadAdmins = Level 300 by default) + -- "kill:300"; -- Changes :kill to level 300 and higher (Level 300 = HeadAdmins by default) + -- "ban:200,300"; -- Makes it so :ban is only usable by levels 200 and 300 specifically (nothing higher or lower or in between) + }; +}; \ No newline at end of file diff --git a/Loader/Config/Settings/Donor.luau b/Loader/Config/Settings/Donor.luau new file mode 100644 index 0000000000..177437e662 --- /dev/null +++ b/Loader/Config/Settings/Donor.luau @@ -0,0 +1,9 @@ +-------------------- +-- DONOR SETTINGS -- +-------------------- + +return { + DonorCapes = true; -- Donors get to show off their capes; Not disruptive :) + DonorCommands = true; -- Show your support for the script and let donors use harmless commands like !sparkles + LocalCapes = false; -- Makes Donor capes local so only the donors see their cape [All players can still disable capes locally] +}; \ No newline at end of file diff --git a/Loader/Config/Settings/General.luau b/Loader/Config/Settings/General.luau new file mode 100644 index 0000000000..14b6a49def --- /dev/null +++ b/Loader/Config/Settings/General.luau @@ -0,0 +1,98 @@ +---------------------- +-- GENERAL SETTINGS -- +---------------------- + +return { + Prefix = {":", ";"}; -- A list of prefixes for commands, the : in :kill me + PlayerPrefix = "!"; -- The ! in !donate; Mainly used for commands that any player can run; Do not make it the same as Prefix + SpecialPrefix = ""; -- Used for things like "all", "me" and "others" (If changed to ! you would do :kill !me) + SplitKey = " "; -- The space in :kill me (eg if you change it to / :kill me would be :kill/me) + BatchKey = "|"; -- :kill me | :ff bob | :explode scel + ConsoleKeyCode = "Quote"; -- Keybind to open the console; Rebindable per player in userpanel; KeyCodes: https://developer.roblox.com/en-us/api-reference/enum/KeyCode + + HideScript = true; -- When the game starts the Adonis_Loader model will be hidden so other scripts cannot access the settings module; Disable if your game uses AssetService:SavePlaceAsync() + + DataStoreEnabled = true; -- Disable if you don't want to load settings and admins from the datastore; PlayerData will still save + LocalDatastore = false; -- If this is turned on, a mock DataStore will forcibly be used instead and shall never save across servers + DataStore = "Adonis_1"; -- DataStore the script will use for saving data; Changing this will lose any saved data + DataStoreKey = "CHANGE_THIS"; -- CHANGE THIS TO ANYTHING RANDOM! Key used to encrypt all datastore entries; Changing this will lose any saved data + + SaveAdmins = true; -- If true anyone you :admin or :headadmin in-game will save + LoadAdminsFromDS = true; -- If false, any admins saved in your DataStores will not load + + SaveCommandLogs = true; -- If command logs are saved to the datastores + MaxLogs = 5000; -- Maximum logs to save before deleting the oldest + + Storage = game:GetService("ServerStorage"); -- Where things like tools are stored + RecursiveTools = false; -- Whether tools that are included in sub-containers within Storage will be available via the :give command (useful if your tools are organized into multiple folders) + + Theme = "Default"; -- UI theme + MobileTheme = "Mobilius"; -- Theme to use on mobile devices; Some UI elements are disabled + DefaultTheme = "Default"; -- Theme to be used as a replacement for "Default". The new replacement theme can still use "Default" as its Base_Theme however any other theme that references "Default" as its redirects to this theme. + HiddenThemes = {}; -- Hide themes from the theme selector tab inside the userpanel. Each theme name must be the specific name such as "Mobilius" + + BanMessage = "Banned"; -- Message shown to banned users upon kick + LockMessage = "Not Whitelisted"; -- Message shown to people when they are kicked while :slock is on in the server + SystemTitle = "System Message"; -- Title to display in :sm and :bc + + --[[ + Format example for Banned, Muted, Blacklist and Whitelist: + + Banned, Muted, Blacklist or Whitelist = { + "Username"; -- Example: "roblox" + "Username:UserId"; -- Example: "roblox:1" + UserId; -- Example: 1 + "Group:GroupId:GroupRank"; -- Example: "Group:123456:50" + "Group:GroupId"; -- Example: "Group:123456" + "Item:ItemID"; -- Example: "Item:123456" + "GamePass:GamePassID"; -- Example: "GamePass:123456" + "Subscription:SubscriptionId"; -- Example: "Subscription:123456" + } + ]] + + Banned = {}; -- List of people banned from the game Format: See the above format example + Muted = {}; -- List of people muted (cannot send chat messages) Format: See the above format example + Blacklist = {}; -- List of people banned from running commands Format: See the above format example + Whitelist = {}; -- People who can join if whitelist enabled Format: See the above format example + + WhitelistEnabled = false; -- If true enables the whitelist/server lock; Only lets admins & whitelisted users join + + MusicList = {}; -- List of songs to appear in the :musiclist Format: {{Name = "somesong", ID = 1234567}, {Name = "anotherone", ID = 1243562}} + CapeList = {}; -- List of capes Format: {{Name = "somecape", Material = "Fabric", Color = "Bright yellow", ID = 12345567, Reflectance = 1}; {etc more stuff here}} + InsertList = {}; -- List of models to appear in the :insertlist and can be inserted using ':insert ' Format: {{Name = "somemodel", ID = 1234567}; {Name = "anotherone", ID = 1243562}} + + OnStartup = {}; -- List of commands ran at server start Format: {":notif TestNotif"} + OnJoin = {}; -- List of commands ran as player on join (ignores adminlevel) Format: {":cmds"} + OnSpawn = {}; -- List of commands ran as player on spawn (ignores adminlevel) Format: {"!fire Really red",":ff me"} + + FunCommands = true; -- Are fun commands enabled? + PlayerCommands = true; -- Are player-level utility commands enabled? + AgeRestrictedCommands = true; -- Are age restricted commands enabled? + ChatCommands = true; -- If false you will not be able to run commands via the chat; Instead, you MUST use the console or you will be unable to run commands + CrossServerCommands = true; -- Are commands which affect more than one server enabled? + WarnDangerousCommand = false; -- Do dangerous commands ask for confirmation? + CommandFeedback = false; -- Should players be notified when commands with non-obvious effects are run on them? + SilentCommandDenials = false; -- If true, there will be no differences between the error messages shown when a user enters an invalid command and when they have insufficient permissions for the command + OverrideChatCallbacks = true; -- If the TextChatService ShouldDeliverCallbacks of all channels are overridden by Adonis on load. Required for slowmode. Mutes use a CanSend method to mute when this is set to false. + ChatCreateRobloxCommands = false; -- Whether "/" commands for Roblox should get created in new Chat + + CodeExecution = false; -- Enables the use of code execution in Adonis. Scripting related (such as :s) and a few other commands require this + + Notification = true; -- Whether or not to show the "You're an admin" and "Updated" notifications + SongHint = true; -- Display a hint with the current song name and ID when a song is played via :music + TopBarShift = false; -- By default hints and notifications will appear from the top edge of the window. Set this to true if you don't want hints/notifications to appear in that region. + + AutoClean = false; -- Will auto clean workspace of things like hats and tools + AutoCleanDelay = 60; -- Time between auto cleans + AutoBackup = false; -- Run :backupmap automatically when the server starts. To restore the map, run :restoremap + ReJail = false; -- If true then when a player rejoins they'll go back into jail. Or if the moderator leaves everybody gets unjailed + + Console = true; -- Whether the command console is enabled + Console_AdminsOnly = false; -- If true, only admins will be able to access the console + + HelpSystem = true; -- Allows players to call admins for help using !help + HelpButton = true; -- Shows a little help button in the bottom right corner. + HelpButtonImage = "rbxassetid://357249130"; -- Sets the image used for the Adonis help button above. + + HttpWait = 60; -- How long things that use the HttpService will wait before updating again +}; \ No newline at end of file diff --git a/Loader/Config/Settings/JoinMessages.luau b/Loader/Config/Settings/JoinMessages.luau new file mode 100644 index 0000000000..efc23c7256 --- /dev/null +++ b/Loader/Config/Settings/JoinMessages.luau @@ -0,0 +1,28 @@ +--[[ + Format example for Join Messages: + + Messages = { + "This is a message using the defaults!"; + { + Title = "Message title"; + Message = "Message body"; + Time = 10; + Icon = "rbxassetid://7510999669"; + Level = 300; + }; + } + + Messages are shown to HeadAdmins+ (300) by default but tables can define a different minimum level via .Level +]] + +return { + Messages = { + -- { + -- Title = "Message title"; + -- Message = "Message body"; + -- Time = 10; + -- Icon = "rbxassetid://7510999669"; + -- Level = 300; + -- }; + }; -- A list of notifications shown on join. Messages can either be strings or tables. +}; \ No newline at end of file diff --git a/Loader/Config/Settings/Ranks.luau b/Loader/Config/Settings/Ranks.luau new file mode 100644 index 0000000000..bb66a5b510 --- /dev/null +++ b/Loader/Config/Settings/Ranks.luau @@ -0,0 +1,71 @@ +------------------------------- +-- Scroll down for settings -- +------------------------------- + +--[[ + How to add administrators: + Below are the administrator permission levels/ranks (Mods, Admins, HeadAdmins, Creators, StuffYouAdd, etc) + Simply place users into the respective "Users" table for whatever level/rank you want to give them. + + Format example: + + Ranks = { + ["Moderators"] = { + Level = 100; + Users = { + "Username"; -- Example: "roblox" + "Username:UserId"; -- Example: "roblox:1" + UserId; -- Example: 1 + "Group:GroupId:GroupRank"; -- Example: "Group:123456:50" + "Group:GroupId"; -- Example: "Group:123456" + "Item:ItemID"; -- Example: "Item:123456" + "GamePass:GamePassID"; -- Example: "GamePass:123456" + "Subscription:SubscriptionId"; -- Example: "Subscription:123456" + } + } + } + + If you use custom ranks, existing custom ranks will be imported with a level of 1. + Add all new CustomRanks to the table below with the respective level you want them to be. + + NOTE: Changing the level of built-in ranks (Moderators, Admins, HeadAdmins, Creators) + will also change the permission level for any built-in commands associated with that rank. +]] + +-------------------- +-- RANKS SETTINGS -- +-------------------- + +return { + CreatorPowers = false; -- Gives me creator-level admin; This is strictly used for debugging; I can't debug without full access to the script + + Ranks = { + ["Moderators"] = { + Level = 100; + Users = { + -- Add users here + }; + }; + + ["Admins"] = { + Level = 200; + Users = { + -- Add users here + }; + }; + + ["HeadAdmins"] = { + Level = 300; + Users = { + -- Add users here + }; + }; + + ["Creators"] = { + Level = 900; -- Anything 900 or higher will be considered a creator and will bypass all perms & be allowed to edit settings in-game. + Users = { + -- Add users here (Also, don't forget quotations and all that) + }; + }; + }; +}; \ No newline at end of file diff --git a/Loader/Config/Settings/Trello.luau b/Loader/Config/Settings/Trello.luau new file mode 100644 index 0000000000..0e5b859368 --- /dev/null +++ b/Loader/Config/Settings/Trello.luau @@ -0,0 +1,68 @@ +------------------------------- +-- Scroll down for settings -- +------------------------------- + +--[[ + The Trello abilities of the script allow you to manage lists and permissions via a Trello board. + The following will guide you through the process of setting up a board: + + 1. Sign up for an account at trello + 2. Create a new board + 3. Get the board ID + 4. Set Trello_Primary to your board ID + 5. Set Trello_Enabled to true + 6. Congrats! The board is ready to be used + 7. Create a list and add cards to it + + You can view lists in-game using :viewlist ListNameHere + + Lists: + Moderators - Card Format: Same as settings.Moderators + Admins - Card Format: Same as settings.Admins + HeadAdmins - Card Format: Same as settings.HeadAdmins + Creators - Card Format: Same as settings.Creators + Banlist - Card Format: Same as settings.Banned + Mutelist - Card Format: Same as settings.Muted + Blacklist - Card Format: Same as settings.Blacklist + Whitelist - Card Format: Same as settings.Whitelist + Permissions - Card Format: Same as settings.Permissions + Music - Card Format: SongName:AudioID + Commands - Card Format: Command (eg. :ff bob) + + Card format refers to how card names should look + + It is recommended you setup secrets in your experiences settings on the creator dashboard for + the Trello_AppKey and Trello_Token variables. + + The following guide will help you through the process of setting set up secrets: + + 1. Go to https://create.roblox.com/docs/cloud-services/secrets#add-secrets and follow the guide on + how to add a secret (not local secret). + + 2. Steps for the first secret: Trello_AppKey + 3. Set the Name of the first secret to: Adonis_Trello_AppKey + 4. Set the Domain of the first secret to the trello domain + 5. Set the Value of the first secret to: your trello AppKey + 6. Set the Trello_AppKey variable to: game:GetService("HttpService"):GetSecret("Adonis_Trello_AppKey") + + 7. Steps for the second secret: Trello_Token + 8. Set the Name of the second secret to: Adonis_Trello_Token + 9. Set the Domain of the second secret to the trello domain + 10. Set the Value of the second secret to: your trello Token + 11. Set the Trello_AppKey variable to: game:GetService("HttpService"):GetSecret("Adonis_Trello_Token") + + You can get your trello token at: /1/connect?name=Trello_API_Module&response_type=token&expires=never&scope=read,write&key=YOUR_APP_KEY_HERE +]] + +--------------------- +-- TRELLO SETTINGS -- +--------------------- + +return { + Trello_Enabled = false; -- Are the Trello features enabled? + Trello_Primary = ""; -- Primary Trello board + Trello_Secondary = {}; -- Secondary Trello boards (read-only) Format: {"BoardID";"BoardID2","etc"} + Trello_AppKey = ""; -- Your Trello AppKey + Trello_Token = ""; -- Trello token (DON'T SHARE WITH ANYONE!) Get API key: /1/connect?name=Trello_API_Module&response_type=token&expires=never&scope=read,write&key=YOUR_APP_KEY_HERE + Trello_HideRanks = false; -- If true, Trello-assigned ranks won't be shown in the admins list UI (accessed via :admins) +}; \ No newline at end of file diff --git a/Loader/Config/Settings/Waypoints.luau b/Loader/Config/Settings/Waypoints.luau new file mode 100644 index 0000000000..30f2d08b34 --- /dev/null +++ b/Loader/Config/Settings/Waypoints.luau @@ -0,0 +1,21 @@ +--[[ + List of waypoints you can teleport via ':to wp-WAYPOINTNAME' or ':teleport PLAYER tp.WAYPOINTNAME' + + Use the below table to define "pre-set" waypoints + + Format example: + + Waypoints = { + EXAMPLEWAYPOINT1NAME = Vector3; -- Example: Vector3.new(0, 0, 0) or workspace.ExampleWaypointPart.Position + } +]] + +------------------------ +-- WAYPOINTS SETTINGS -- +------------------------ + +return { + Waypoints = { + -- YOURNAME1 = Vector3.new(5, 20, 10) + }; +}; \ No newline at end of file diff --git a/Loader/Config/Settings/_GAPI.luau b/Loader/Config/Settings/_GAPI.luau new file mode 100644 index 0000000000..80f2a9bdf9 --- /dev/null +++ b/Loader/Config/Settings/_GAPI.luau @@ -0,0 +1,26 @@ +--------------------- +-- _G API SETTINGS -- +--------------------- + +return { + G_API = true; -- If true, allows other server scripts to access certain functions described in the API module through _G.Adonis + G_Access = false; -- If enabled, allows other scripts to access Adonis using _G.Adonis.Access; Scripts will still be able to do things like _G.Adonis.CheckAdmin(player) + G_Access_Key = "Example_Key"; -- Key required to use the _G access API; Example_Key will not work for obvious reasons + G_Access_Perms = "Read"; -- Access perms + Allowed_API_Calls = { + Client = false; -- Allow access to the Client (not recommended) + Settings = false; -- Allow access to settings (not recommended) + DataStore = false; -- Allow access to the DataStore (not recommended) + Core = false; -- Allow access to the script's core table (REALLY not recommended) + Service = false; -- Allow access to the script's service metatable + Remote = false; -- Communication table + HTTP = false; -- HTTP-related things like Trello functions + Anti = false; -- Anti-Exploit table + Logs = false; + UI = false; -- Client UI table + Admin = false; -- Admin related functions + Functions = false; -- Functions table (contains functions used by the script that don't have a subcategory) + Variables = true; -- Variables table + API_Specific = true; -- API Specific functions + }; +}; \ No newline at end of file diff --git a/Loader/Loader/Loader.server.luau b/Loader/Loader/Loader.server.luau index ed3db7fb33..e4e18e0317 100644 --- a/Loader/Loader/Loader.server.luau +++ b/Loader/Loader/Loader.server.luau @@ -16,7 +16,7 @@ -- Adonis Loader -- -- By Epix Incorporated -- ---------------------------------------------------------------------------------- --- Edit settings using the Settings module in the Config folder -- +-- Edit settings inside the Config -> Settings folder -- ---------------------------------------------------------------------------------- -- This script loads the Adonis source (MainModule) into the game. -- -- Only edit this script if you know what you're doing! -- @@ -86,9 +86,10 @@ else local loader = loaderFolder.Loader local runner = script - local settingsModule = configFolder.Settings + local settingsFolder = configFolder.Settings local pluginsFolder = configFolder.Plugins local themesFolder = configFolder.Themes + local inGameSettingsEditorSettingsFolder = configFolder.InGameSettingsEditorSettings local backup = model:Clone() @@ -154,23 +155,61 @@ else end end - local success, setTab = pcall(require, settingsModule) - if success then - data.Messages = setTab.Settings.Messages - else - warn("[DEVELOPER ERROR] Settings module errored while loading; Using defaults; Error Message: ", setTab) + local erroredSettingsModules = {} + + for _, module in settingsFolder:GetChildren() do + xpcall(function() + local requiredModule = require(module) + + for key, value in requiredModule do + if key == "Messages" then + data.Messages = value + end + + data.Settings[key] = value + end + end, function(err) + table.insert(erroredSettingsModules, {Name = module.Name, Error = err}) + end) + end + + for _, erroredSettingModule in erroredSettingsModules do + warn(`[DEVELOPER ERROR] The Settings.{erroredSettingModule.Name} module errored while loading; Using defaults for this module; Error Message: {erroredSettingModule.Error}`) table.insert(data.Messages, { Title = "Warning!"; - Icon = "maticon://Dangerous"; - Message = "Settings module error detected; using default settings."; + Icon = "MatIcon://Dangerous"; + Message = `The Settings.{erroredSettingModule.Name} module errored while loading; Using defaults for this module.`; Time = 15; }) - setTab = {} end - data.Settings = setTab.Settings - data.Descriptions = setTab.Description - data.Order = setTab.Order + if #erroredSettingsModules > 0 then + data.Settings.Ranks = {} -- This is for security reasons because settings may reset back to unintended defaults. + end + + xpcall(function() + data.Descriptions = require(inGameSettingsEditorSettingsFolder.Descriptions) + end, function(err) + warn("[DEVELOPER ERROR] The InGameSettingsEditorSettings.Descriptions module errored while loading; Using defaults; Error Message:", err) + table.insert(data.Messages, { + Title = "Warning!"; + Icon = "MatIcon://Dangerous"; + Message = "The InGameSettingsEditorSettings.Descriptions module errored while loading; Using defaults."; + Time = 15; + }) + end) + + xpcall(function() + data.Order = require(inGameSettingsEditorSettingsFolder.Order) + end, function(err) + warn("[DEVELOPER ERROR] The InGameSettingsEditorSettings.Order module errored while loading; Using defaults; Error Message:", err) + table.insert(data.Messages, { + Title = "Warning!"; + Icon = "MatIcon://Dangerous"; + Message = "The InGameSettingsEditorSettings.Order module errored while loading; Using defaults."; + Time = 15; + }) + end) for _, module in pluginsFolder:GetChildren() do local name = string.lower(module.Name) @@ -197,7 +236,7 @@ else local success, module = pcall(require, moduleId) --// Backup method for loading Adonis - if not success and type(moduleId) == "number" then -- ccuser44 was here + if not success and type(moduleId) == "number" then warn(`Failed to load Adonis MainModule {moduleId} due to {module}! If this does not work please purchase the Adonis MainModule to your inventory. Using backup method...`) yxpcall(function() module = loadModuleAsset(moduleId) diff --git a/Loader/READ_ME.luau b/Loader/READ_ME.luau new file mode 100644 index 0000000000..9885aee159 --- /dev/null +++ b/Loader/READ_ME.luau @@ -0,0 +1,58 @@ +--[[ + -------------------------------------------- + -- Adonis -- + -- By Epix Incorporated -- + -------------------------------------------- + -- Not Everything is so Black and White -- + -------------------------------------------- + + A lot of time goes into maintaining and updating Adonis. If you enjoy using Adonis, + please consider leaving us a review, as your feedback means a lot: + https://create.roblox.com/store/asset/7510622625/ + + + --------------------- + -- Getting started -- + --------------------- + + - It's recommend you store Adonis_Loader in 'ServerScriptService'. + - Configure Ranks in Config -> Settings -> Ranks module. + - Configure general settings like prefixes, command settings, etc in Config -> Settings -> General module. + - You can find the rest of the settings modules at Config -> Settings. They are sorted by categories. + - You can create custom commands and plugins in Config -> Plugins. + + + --------------------- + -- Basic luau info -- + --------------------- + + This is only here to help you when editing settings so you understand how they work + and don't break something. + + In case you don't know what Luau is; Luau is the scripting language Roblox uses... + so every script you see (such as this one) and pretty much any code on Roblox is + written in Luau. + + Anything that looks like {} is known as a table. + Tables contain things, like the Luau version of a box. + An example of a table would be setting = {"John", "Mary", "Bill"} + You can have tables inside of tables, such in the case of setting = {{Group = 1234, Rank = 123, Type = "Admin"}} + Just like real boxes, tables can contain pretty much anything including other tables. + + Note: Commas (,) as well as semicolons (;) can both be used to separate things inside a table. + + Anything that looks like "Bob" is what's known as a string. Strings + are basically plain text; setting = "Bob" would be correct however + setting = Bob would not; because if it's not surrounded by quotes Luau will think + that Bob is a variable; Quotes indicate something is a string and therefore not a variable/number/code + + Numbers do not use quotes. setting = 56 + + This block of text you are reading is called a comment. It's like a message + from the programmer to anyone who reads their stuff. Anything in a comment will + not be seen by Luau when the script is run. + + Comments can be made by putting -- at the start of a line + + For more information about roblox luau visit: https://create.roblox.com/docs/luau +]] \ No newline at end of file diff --git a/MainModule/Client/Core/Functions.luau b/MainModule/Client/Core/Functions.luau index 3283fdcabe..865c0166c6 100644 --- a/MainModule/Client/Core/Functions.luau +++ b/MainModule/Client/Core/Functions.luau @@ -1432,6 +1432,10 @@ return function(Vargs, GetEnv) service.StarterGui:SetCore(...) end; + InspectPlayerFromUserId = function(...) + service.GuiService:InspectPlayerFromUserId(...) + end; + UnCape = function() local cape = service.LocalContainer():FindFirstChild("::Adonis::Cape") if cape then cape:Destroy() end diff --git a/MainModule/Client/UI/Default/Coords.luau b/MainModule/Client/UI/Default/Coords.luau index 32eb932780..4bb91c1de7 100644 --- a/MainModule/Client/UI/Default/Coords.luau +++ b/MainModule/Client/UI/Default/Coords.luau @@ -1,9 +1,10 @@ -client, service = nil, nil - return function(data, env) - if env then - setfenv(1, env) - end + if env then setfenv(1, env) end + + local client = env.client + local service = env.service + + local Player = service.Player local active = true local gTable @@ -11,9 +12,9 @@ return function(data, env) local window = client.UI.Make("Window", { Name = "Coords", Title = "Coordinates", - Icon = client.MatIcons.LocationOn, - Size = { 200, 60 }, - Position = UDim2.new(0, 10, 1, -120), + Icon = client.MatIcons.Broadcast, + Size = { 200, 100 }, + Position = UDim2.new(0, 10, 1, -110), AllowMultiple = false, NoHide = true, Walls = true, @@ -29,25 +30,19 @@ return function(data, env) BackgroundTransparency = 1, TextSize = 18, Size = UDim2.new(1, 0, 1, 0), - Position = UDim2.new(0, 0, 0, 0), + Position = UDim2.new() }) gTable = window.gTable window:Ready() - local function updateCoords() - if service.Players.LocalPlayer.Character then - local rootPart = service.Players.LocalPlayer.Character:FindFirstChild("HumanoidRootPart") - if rootPart then - return string.format("X: %.2f\nY: %.2f\nZ: %.2f", rootPart.Position.X, rootPart.Position.Y, rootPart.Position.Z) - end - end - return "..." - end - repeat - label.Text = updateCoords() - task.wait(0.5) - until not active or not gTable.Active + local PrimaryPart = Player.Character and Player.Character.PrimaryPart + label.Text = if PrimaryPart + then string.format("X: %.2f\nY: %.2f\nZ: %.2f", PrimaryPart.Position.X, PrimaryPart.Position.Y, PrimaryPart.Position.Z) + else "..." + + task.wait(0.25) + until not active or not gTable.Active or gTable.Destroyed end end \ No newline at end of file diff --git a/MainModule/Client/UI/Default/PrivateChat.luau b/MainModule/Client/UI/Default/PrivateChat.luau index f4312fe6fc..12e386c7e9 100644 --- a/MainModule/Client/UI/Default/PrivateChat.luau +++ b/MainModule/Client/UI/Default/PrivateChat.luau @@ -213,7 +213,7 @@ return function(data, env) AutomaticSize = "Y"; TextWrapped = true; TextScaled = false; - RichText = true; + RichText = data.RichText; BackgroundTransparency = 1; }; } @@ -342,11 +342,19 @@ return function(data, env) if data.History then for i,data in ipairs(data.History) do local p = data.Sender; + local message = data.Message + if p.IsMessageRestricted then + message = "Message unavailable due to chat restrictions." + elseif p.IsMessageRestrictedError then + message = "Message unavailable due to an error." + end + newMessage({ PlayerName = p.Name; PlayerDisplayName = p.DisplayName; - Message = data.Message; + Message = message; Icon = p.Icon or 0; + RichText = p.IsMessageRestricted or p.IsMessageRestrictedError; }); end end @@ -358,11 +366,18 @@ return function(data, env) local p = vargs[1] local message = vargs[2] if newMessage then + if p.IsMessageRestricted then + message = "Message unavailable due to chat restrictions." + elseif p.IsMessageRestrictedError then + message = "Message unavailable due to an error." + end + newMessage({ PlayerName = p.Name; PlayerDisplayName = p.DisplayName; Message = message; Icon = p.Icon or 0; + RichText = p.IsMessageRestricted or p.IsMessageRestrictedError; }) end elseif cmd == "UpdatePeerList" then diff --git a/MainModule/Server/Commands/Admins.luau b/MainModule/Server/Commands/Admins.luau index 6f9b897d02..f3a8ebc415 100644 --- a/MainModule/Server/Commands/Admins.luau +++ b/MainModule/Server/Commands/Admins.luau @@ -514,7 +514,20 @@ return function(Vargs, env) Description = "Get someone's attention"; AdminLevel = "Admins"; Function = function(plr: Player, args: {string}) - for _, v in service.GetPlayers(plr,string.lower(args[1]))do + for _, v in service.GetPlayers(plr,string.lower(args[1])) do + if v.UserId ~= plr.UserId then + local success, canUserChatData = pcall(service.TextChatService.CanUsersDirectChatAsync, service.TextChatService, plr.UserId, {v.UserId}) + if not success then + Functions.Hint(`Unable to alert {service.FormatPlayer(v)} due an error.`, {plr}) + continue + end + + if #canUserChatData == 0 then + Functions.Hint(`Unable to alert {service.FormatPlayer(v)} due to chat restrictions.`, {plr}) + continue + end + end + Remote.MakeGui(v, "Alert", {Message = args[2] and service.Filter(args[2],plr, v) or "Wake up; Your attention is required"}) end end diff --git a/MainModule/Server/Commands/Moderators.luau b/MainModule/Server/Commands/Moderators.luau index 6aa19fd052..14cbf0fa11 100644 --- a/MainModule/Server/Commands/Moderators.luau +++ b/MainModule/Server/Commands/Moderators.luau @@ -139,6 +139,19 @@ return function(Vargs, env) assert(args[2], "Missing message") for _, v in service.GetPlayers(plr, assert(args[1], "Missing player name")) do + if v.UserId ~= plr.UserId then + local success, canUserChatData = pcall(service.TextChatService.CanUsersDirectChatAsync, service.TextChatService, plr.UserId, {v.UserId}) + if not success then + Functions.Hint(`Unable to send {service.FormatPlayer(v)} a notification due an error.`, {plr}) + continue + end + + if #canUserChatData == 0 then + Functions.Hint(`Unable to send {service.FormatPlayer(v)} a notification due to chat restrictions.`, {plr}) + continue + end + end + Functions.Notification("Notification", service.Filter(args[2], plr, v), {v}) end end @@ -264,7 +277,7 @@ return function(Vargs, env) Commands = {"mpm", "messagepm"}; Args = {"player", "message"}; Filter = true; - Description = "Makes a message on the target player(s) screen."; + Description = "Makes a private message on the target player(s) screen."; AdminLevel = "Moderators"; Function = function(plr: Player, args: {string}) assert(args[1], "Missing player name") @@ -272,6 +285,19 @@ return function(Vargs, env) local Sender = string.format("Message from %s", service.FormatPlayer(plr)) for _, v in service.GetPlayers(plr, args[1]) do + if v.UserId ~= plr.UserId then + local success, canUserChatData = pcall(service.TextChatService.CanUsersDirectChatAsync, service.TextChatService, plr.UserId, {v.UserId}) + if not success then + Functions.Hint(`Unable to private message {service.FormatPlayer(v)} due an error.`, {plr}) + continue + end + + if #canUserChatData == 0 then + Functions.Hint(`Unable to private message {service.FormatPlayer(v)} due to chat restrictions.`, {plr}) + continue + end + end + Functions.Message(Sender, service.Filter(args[2], plr, v), {v}, true) end end @@ -306,12 +332,25 @@ return function(Vargs, env) Commands = {"npm", "smallmessagepm", "nmessagepm", "nmsgpm", "npmmsg", "smsgpm", "spmmsg", "smessagepm"}; Args = {"player", "message"}; Filter = true; - Description = "Makes a small message on the target player(s) screen."; + Description = "Makes a small private message on the target player(s) screen."; AdminLevel = "Moderators"; Function = function(plr: Player, args: {string}) assert(args[1], "Missing player name") assert(args[2], "Missing message") for _, v in service.GetPlayers(plr, args[1]) do + if v.UserId ~= plr.UserId then + local success, canUserChatData = pcall(service.TextChatService.CanUsersDirectChatAsync, service.TextChatService, plr.UserId, {v.UserId}) + if not success then + Functions.Hint(`Unable to private message {service.FormatPlayer(v)} due an error.`, {plr}) + continue + end + + if #canUserChatData == 0 then + Functions.Hint(`Unable to private message {service.FormatPlayer(v)} due to chat restrictions.`, {plr}) + continue + end + end + Remote.RemoveGui(v, "Notify") Functions.Notify(`Message from {service.FormatPlayer(plr)}`, service.Filter(args[2], plr, v), {v}) end @@ -552,6 +591,19 @@ return function(Vargs, env) AdminLevel = "Moderators"; Function = function(plr: Player, args: {string}, data: {any}) for _, v in service.GetPlayers(plr, args[1]) do + if v.UserId ~= plr.UserId then + local success, canUserChatData = pcall(service.TextChatService.CanUsersDirectChatAsync, service.TextChatService, plr.UserId, {v.UserId}) + if not success then + Functions.Hint(`Unable to send {service.FormatPlayer(v)} a chat message due an error.`, {plr}) + continue + end + + if #canUserChatData == 0 then + Functions.Hint(`Unable to send {service.FormatPlayer(v)} a chat message due to chat restrictions.`, {plr}) + continue + end + end + if service.TextChatService and service.TextChatService.ChatVersion == Enum.ChatVersion.TextChatService then local TextToUse = args[2] if data.Options.Chat ~= true then @@ -928,6 +980,47 @@ return function(Vargs, env) return peers end + local function getFilteredHistory(player) + local canUsersDirectChatAsyncCache = {} + local newHistory = {} + + for _, historyItem in history do + local canUsersChat = false + local newHistoryItem = { + Message = nil, + Sender = { + Name = historyItem.Sender.Name, + DisplayName = historyItem.Sender.DisplayName, + UserId = historyItem.Sender.UserId, + Icon = historyItem.Sender.Icon + } + } + + if player.UserId == historyItem.Sender.UserId or historyItem.Sender.UserId == 0 then + canUsersChat = true + newHistoryItem.Sender.IsMessageRestricted = false + elseif canUsersDirectChatAsyncCache[historyItem.Sender.UserId] ~= nil then + canUsersChat = canUsersDirectChatAsyncCache[historyItem.Sender.UserId] + newHistoryItem.Sender.IsMessageRestricted = not canUsersDirectChatAsyncCache[historyItem.Sender.UserId] + else + local success, canUserChatData = pcall(service.TextChatService.CanUsersDirectChatAsync, service.TextChatService, player.UserId, {historyItem.Sender.UserId}) + if success then + canUsersChat = #canUserChatData > 0 + canUsersDirectChatAsyncCache[historyItem.Sender.UserId] = canUsersChat + newHistoryItem.Sender.IsMessageRestricted = not canUsersChat + else + newHistoryItem.Sender.IsMessageRestrictedError = true + end + end + + newHistoryItem.Message = canUsersChat and historyItem.Message or nil + + table.insert(newHistory, newHistoryItem) + end + + return newHistory + end + local function systemMessage(msg) local data = { Name = "* SYSTEM *"; @@ -976,7 +1069,31 @@ return function(Vargs, env) table.remove(history, 1) end - newSession:SendToUsers("PlayerSentMessage", data, msg) + for sessionPlayer in newSession.Users do + local newData = { + Name = data.Name, + DisplayName = data.DisplayName, + UserId = data.UserId, + Icon = data.Icon + } + + local canUsersChat = false + if p.UserId == sessionPlayer.UserId then + canUsersChat = true + else + local success, canUserChatData = pcall(service.TextChatService.CanUsersDirectChatAsync, service.TextChatService, p.UserId, {sessionPlayer.UserId}) + if success then + canUsersChat = #canUserChatData > 0 + newData.IsMessageRestricted = not canUsersChat + else + newData.IsMessageRestrictedError = true + end + end + + local messageToSend = canUsersChat and msg or nil + + newSession:SendToUser(sessionPlayer, "PlayerSentMessage", newData, messageToSend) + end end elseif cmd == "LeaveSession" or cmd == "RemovedFromSession" then newSession:RemoveUser(p) @@ -991,18 +1108,28 @@ return function(Vargs, env) systemMessage("Session ended") newSession:End() elseif cmd == "AddPlayerToSession" and (p == plr or Admin.CheckAdmin(p)) then - local player = args[1] + local peer = args[1] + local filteredHistory = getFilteredHistory(peer) - if player then - newSession:AddUser(player) - newSession:SendToUser(player, "AddedToSession") - systemMessage(string.format("%s added %s to the session", p.Name, player.Name)) - Remote.MakeGui(player, "PrivateChat", { + if peer then + local canUserChatSuccess, canUserChatData = pcall(service.TextChatService.CanUserChatAsync, service.TextChatService, peer.UserId) + if not canUserChatSuccess then + return Functions.Hint(`Unable to add {service.FormatPlayer(peer)} to the session because an error occurred.`, {p}) + end + + if not canUserChatData then + return Functions.Hint(`Unable to add {service.FormatPlayer(peer)} to the session due to them not being able to chat.`, {p}) + end + + newSession:AddUser(peer) + newSession:SendToUser(peer, "AddedToSession") + systemMessage(string.format("%s added %s to the session", service.FormatPlayer(p), service.FormatPlayer(peer))) + Remote.MakeGui(peer, "PrivateChat", { Owner = plr; SessionKey = newSession.SessionKey; SessionName = sessionName; - History = history; - CanManageUsers = Admin.CheckAdmin(player); + History = filteredHistory; + CanManageUsers = Admin.CheckAdmin(peer); }) newSession:SendToUsers("UpdatePeerList", getPeerList()) end @@ -1048,18 +1175,29 @@ return function(Vargs, env) Owner = plr; SessionKey = newSession.SessionKey; SessionName = sessionName; - History = history; + History = getFilteredHistory(plr); CanManageUsers = true; }) for i, v in service.GetPlayers(plr, args[1]) do if v ~= plr then + local success, canUserChatData = pcall(service.TextChatService.CanUserChatAsync, service.TextChatService, v.UserId) + if not success then + Functions.Hint(`Unable to add {service.FormatPlayer(v)} to the session because an error occurred.`, {plr}) + continue + end + + if not canUserChatData then + Functions.Hint(`Unable to add {service.FormatPlayer(v)} to the session due to them not being able to chat.`, {plr}) + continue + end + newSession:AddUser(v) Remote.MakeGui(v, "PrivateChat", { Owner = plr; SessionKey = newSession.SessionKey; SessionName = sessionName; - History = history; + History = getFilteredHistory(v); CanManageUsers = Admin.CheckAdmin(v); }) end @@ -1078,6 +1216,19 @@ return function(Vargs, env) assert(args[1], "Missing player name") assert(args[2], "Missing message") for _, v in service.GetPlayers(plr, args[1]) do + if v.UserId ~= plr.UserId then + local success, canUserChatData = pcall(service.TextChatService.CanUsersDirectChatAsync, service.TextChatService, plr.UserId, {v.UserId}) + if not success then + Functions.Hint(`Unable to private message {service.FormatPlayer(v)} due an error.`, {plr}) + continue + end + + if #canUserChatData == 0 then + Functions.Hint(`Unable to private message {service.FormatPlayer(v)} due to chat restrictions.`, {plr}) + continue + end + end + local replyTicket = service.HttpService:GenerateGUID(false) Variables.PMtickets[replyTicket] = plr @@ -6959,6 +7110,19 @@ return function(Vargs, env) AdminLevel = "Moderators"; Function = function(plr: Player, args: {string}) for _, v in service.GetPlayers(plr, args[1]) do + if v.UserId ~= plr.UserId then + local success, data = pcall(service.TextChatService.CanUsersDirectChatAsync, service.TextChatService, plr.UserId, {v.UserId}) + if not success then + Functions.Hint(`Unable to send {service.FormatPlayer(v)} a tts message due to an error.`, {plr}) + continue + end + + if #data == 0 then + Functions.Hint(`Unable to send {service.FormatPlayer(v)} a tts message due to chat restrictions.`, {plr}) + continue + end + end + Remote.Send(v, "Function", "TextToSpeech", args[2]) end end @@ -7318,5 +7482,38 @@ return function(Vargs, env) end end }; + + Join = { + Prefix = Settings.Prefix; + Commands = {"join", "follow", "followplayer"}; + Args = {"username"}; + Description = "Makes you follow the player you gave the username of to the server they are in"; + NoStudio = true; + AdminLevel = "Moderators"; + Function = function(plr: Player, args: {string}) + assert(args[1], "Argument #1 (username) is required") + assert(#args[1] <= 20 and args[1]:match("^[%a%d_]+$"), "Invalid username provided") + + local UserId = Functions.GetUserIdFromNameAsync(args[1]) + if UserId then + local success, samePlace, errorMessage, placeId, jobId = pcall(service.TeleportService.GetPlayerPlaceInstanceAsync, service.TeleportService, UserId) + if success then + assert(samePlace, "You're already in this server") + if placeId and jobId then + service.TeleportService:TeleportAsync(placeId, {plr}, service.New("TeleportOptions", { + ServerInstanceId = jobId + })) + Functions.Hint("Teleporting...", {plr}) + else + Functions.Hint(`{args[1]} was not found playing this game`, {plr}) + end + else + Functions.Hint(`Unexpected internal error: {errorMessage or samePlace}`, {plr}) + end + else + Functions.Hint(`'{args[1]}' is not a valid Roblox user`, {plr}) + end + end + }; } end diff --git a/MainModule/Server/Commands/Players.luau b/MainModule/Server/Commands/Players.luau index 3710585598..132ddd2bb5 100644 --- a/MainModule/Server/Commands/Players.luau +++ b/MainModule/Server/Commands/Players.luau @@ -9,7 +9,6 @@ return function(Vargs, env) if env then setfenv(1, env) end local Routine = env.Routine - local Pcall = env.Pcall return { ViewCommands = { @@ -450,78 +449,6 @@ return function(Vargs, env) end }; - Join = { - Prefix = Settings.PlayerPrefix; - Commands = {"join", "follow", "followplayer"}; - Args = {"username"}; - Description = "Makes you follow the player you gave the username of to the server they are in"; - NoStudio = true; -- TeleportService cannot be used in Roblox Studio - AdminLevel = "Players"; - Function = function(plr: Player, args: {string}) - assert(args[1], "Argument #1 (username) is required") - assert(#args[1] <= 20 and args[1]:match("^[%a%d_]+$"), "Invalid username provided") - - local UserId = Functions.GetUserIdFromNameAsync(args[1]) - if UserId then - local success, samePlace, errorMessage, placeId, jobId = pcall(service.TeleportService.GetPlayerPlaceInstanceAsync, service.TeleportService, UserId) - - if success then - if samePlace then - error("You're already in this server!") - end - - if placeId and jobId then - service.TeleportService:TeleportAsync(placeId, {plr}, service.New("TeleportOptions", { - ServerInstanceId = jobId - })) - Functions.Hint("Teleporting...", {plr}) - else - Functions.Hint(`{service.Players:GetNameFromUserIdAsync(UserId)} was not found playing this game`, {plr}) - end - else - Functions.Hint(`Unexpected internal error: {errorMessage or samePlace}`, {plr}) - end - else - Functions.Hint(`'{args[1]}' is not a valid Roblox user`, {plr}) - end - end - }; - - GlobalJoin = { - Prefix = Settings.PlayerPrefix; - Commands = {"joinfriend", "globaljoin"}; - Args = {"username"}; - Description = "Joins your friend outside/inside of the game (must be online)"; - NoStudio = true; - AdminLevel = "Players"; - Function = function(plr: Player, args: {string}) -- uses Player:GetFriendsOnline() - --// NOTE: MAY NOT WORK IF "ALLOW THIRD-PARTY GAME TELEPORTS" (GAME SECURITY PERMISSION) IS DISABLED - - assert(args[1], "Argument #1 (username) is required") - assert(#args[1] <= 20 and args[1]:match("^[%a%d_]+$"), "Invalid username provided") - - local UserId = Functions.Functions.GetUserIdFromNameAsync(args[1]) - if UserId then - for _, v in plr:GetFriendsOnline() do - if v.VisitorId == UserId then - if v.IsOnline and v.PlaceId and v.GameId then - service.TeleportService:TeleportAsync(v.PlaceId, {plr}) - Functions.Hint(string.format("Joining %s (%s)...", v.UserName, v.LastLocation or "unknown game"), {plr}) - else - Functions.Hint("{v.UserName} is not currently playing a game", {plr}) - end - - return - end - end - - Functions.Hint("You are not a friend of the specified user", {plr}) - else - Functions.Hint(`'{args[1]}' is not a valid Roblox user`, {plr}) - end - end - }; - Credits = { Prefix = Settings.PlayerPrefix; Commands = {"credit", "credits"}; @@ -652,7 +579,7 @@ return function(Vargs, env) Message = if args[1] then `UI theme set to '{args[1]}'!` else `UI theme reset to default.`; Time = 5; }) - Remote.LoadCode(plr, `client.Variables.CustomTheme = {if args[1] then `[[{args[1]}]]` else "nil"}`) + Remote.Send(plr, "SetVariables", { CustomTheme = args[1] or false }) end }; @@ -733,38 +660,6 @@ return function(Vargs, env) end }; - AddFriend = { - Prefix = Settings.PlayerPrefix; - Commands = {"addfriend", "friendrequest", "sendfriendrequest"}; - Args = {"player"}; - Description = "Send a friend request to the specified player"; - Hidden = true; - AdminLevel = "Players"; - Function = function(plr: Player, args: {string}) - for _, v: Player in service.GetPlayers(plr, args[1]) do - assert(v ~= plr, "Cannot friend yourself!") - assert(not plr:IsFriendsWith(v.UserId), `You are already friends with {v.Name}`) - Remote.Send(plr, "Function", "SetCore", "PromptSendFriendRequest", v) - end - end - }; - - UnFriend = { - Prefix = Settings.PlayerPrefix; - Commands = {"unfriend", "removefriend"}; - Args = {"player"}; - Description = "Prompts you to unfriend the specified player"; - Hidden = true; - AdminLevel = "Players"; - Function = function(plr: Player, args: {string}) - for i, v: Player in service.GetPlayers(plr, args[1]) do - assert(v ~= plr, "Cannot unfriend yourself!") - assert(plr:IsFriendsWith(v.UserId), `You are not currently friends with {v.Name}`) - Remote.Send(plr, "Function", "SetCore", "PromptUnfriend", v) - end - end - }; - InspectAvatar = { Prefix = Settings.PlayerPrefix; Commands = {"inspectavatar", "avatarinspect", "viewavatar", "examineavatar"}; @@ -773,7 +668,9 @@ return function(Vargs, env) AdminLevel = "Players"; Function = function(plr: Player, args: {string}) for _, v: Player in service.GetPlayers(plr, args[1], {UseFakePlayer = true}) do - Remote.LoadCode(plr, `service.GuiService:InspectPlayerFromUserId({v.UserId})`) + if v.UserId > 0 then + Remote.Send(plr, "Function", "InspectPlayerFromUserId", v.UserId) + end end end }; @@ -796,64 +693,7 @@ return function(Vargs, env) Description = "Tells you how many players are in the server"; AdminLevel = "Players"; Function = function(plr: Player, args: {string}) - local num = 0 - local nilNum = 0 - for _, v in service.GetPlayers() do - if v.Parent ~= service.Players then - nilNum += 1 - end - num += 1 - end - - if nilNum > 0 and Admin.GetLevel(plr) >= Settings.Ranks.Moderators.Level then - Functions.Hint(`There are currently {num} player(s); {nilNum} are nil or loading`, {plr}) - else - Functions.Hint(`There are {num} player(s)`, {plr}) - end - end - }; - - TimeDate = { - Prefix = Settings.PlayerPrefix; - Commands = {"timedate", "date", "datetime"}; - Args = {}; - Description = "Shows you the current time and date."; - AdminLevel = "Players"; - ListUpdater = function(plr: Player) - local ostime = os.time() - local tab = { - {Text = "―――――――――――――――――――――――"}, - {"Date"; os.date("%x", ostime)}, - {"Time"; os.date("%H:%M | %I:%M %p", ostime)}, - {"Timezone"; os.date("%Z", ostime)}, - {Text = "―――――――――――――――――――――――"}, - {"Minute"; os.date("%M", ostime)}, - {"Hour"; os.date("%H | %I %p" , ostime)}, - {"Day"; os.date("%d %A", ostime)}, - {"Week (first Sunday)"; os.date("%U", ostime)}, - {"Week (first Monday)"; os.date("%W", ostime)}, - {"Month"; os.date("%m %B", ostime)}, - {"Year"; os.date("%Y", ostime)}, - {Text = "―――――――――――――――――――――――"}, - {"Day of the year"; os.date("%j", ostime)}, - {"Day of the month"; os.date("%d", ostime)}, - {Text = "―――――――――――――――――――――――"}, - } - for i, v in tab do - if not v[2] then continue end - tab[i] = {Text = `{v[1]}: {v[2]}`; Desc = v[2];} - end - return tab - end; - Function = function(plr: Player, args: {string}) - Remote.MakeGui(plr, "List", { - Title = "Date"; - Table = Logs.ListUpdaters.TimeDate(plr); - RichText = true; - Update = "TimeDate"; - AutoUpdate = 59; - Size = {288, 390}; - }) + Functions.Hint(`There are {#service.Players:GetPlayers()} player(s)`, {plr}) end }; @@ -906,12 +746,17 @@ return function(Vargs, env) if elevated then local level, rank = Admin.GetLevel(v) gameData = { - IsMuted = table.find(Settings.Muted, `{v.Name}:{v.UserId}`) and true or false; + IsMuted = Admin.IsMuted(v); AdminLevel = `[{level}] {rank or "Unknown"}`; - SourcePlaceId = v:GetJoinData().SourcePlaceId or "N/A"; + SourcePlaceId = v:GetJoinData().SourcePlaceId or "N/A" } - for k, d in Remote.Get(v, "Function", "GetUserInputServiceData") do - gameData[k] = d + + local inputData = Remote.Get(v, "Function", "GetUserInputServiceData") + if type(inputData) == "table" then + for k, d in inputData do + if type(k) ~= "string" then break end + gameData[k] = d + end end end @@ -942,7 +787,7 @@ return function(Vargs, env) IsServerOwner = v.UserId == game.PrivateServerOwnerId; CmdPrefix = Functions.GetMainPrefix(); CmdSplitKey = Settings.SplitKey; - OnlineFriends = Remote.Get(v, "Function", "GetFriendsOnline"); + OnlineFriends = elevated and Remote.Get(v, "Function", "GetFriendsOnline"); }) end) end @@ -956,9 +801,6 @@ return function(Vargs, env) Description = "Shows you details about the current server"; AdminLevel = "Players"; ListUpdater = function(plr: Player) - local elevated = Admin.CheckAdmin(plr) - local data = {} - local donorList = {} for _, v in service.GetPlayers() do if not Variables.IncognitoPlayers[v] and Admin.CheckDonor(v) then @@ -967,7 +809,7 @@ return function(Vargs, env) end local adminDictionary, workspaceInfo - if elevated then + if Admin.CheckAdmin(plr) then adminDictionary = {} for _, v in service.GetPlayers() do local level, rank = Admin.GetLevel(v) @@ -977,7 +819,7 @@ return function(Vargs, env) end local nilPlayers = 0 for _, v in service.NetworkServer:GetChildren() do - if v and v:GetPlayer() and not service.Players:FindFirstChild(v:GetPlayer().Name) then + if v:IsA("NetworkReplicator") and v:GetPlayer() and not service.Players:FindFirstChild(v:GetPlayer().Name) then nilPlayers += 1 end end @@ -1028,96 +870,6 @@ return function(Vargs, env) end }; - GetGroupInfo = { - Prefix = Settings.PlayerPrefix; - Commands = {"getgroupinfo", "groupinfo", "viewgroupinfo"}; - Args = {"group ID"}; - Description = "Shows you information about the specified Roblox group"; - AdminLevel = "Players"; - Function = function(plr: Player, args: {string}) - local groupId = assert(args[1] and tonumber(args[1]), "Missing/invalid group ID") - local groupInfo = assert(select(2, xpcall(service.GroupService.GetGroupInfoAsync, function() return nil end, service.GroupService, groupId)), "Error fetching data") - local tab = { - `Name: {groupInfo.Name}`, - `ID: {groupInfo.Id}`, - if groupInfo.Owner then string.format("Owner: %s [%d]", groupInfo.Owner.Name or "???", groupInfo.Owner.Id) else "[No Owner]", - {Text = string.format("――― Roles (%d): ―――――――――――――――――", #groupInfo.Roles)}, - } - for _, role in groupInfo.Roles do - table.insert(tab, string.format("[%d] %s", role.Rank, role.Name)) - end - - local function getPageItems(pages: StandardPages, res: {any}) - res = res or {} - for _, item in pages:GetCurrentPage() do - table.insert(res, item) - end - if not pages.IsFinished then - pages:AdvanceToNextPageAsync() - getPageItems(pages, res) - end - return res - end - - local done = false - local startTime = os.clock() - task.defer(function() - local allies = getPageItems(service.GroupService:GetAlliesAsync(groupId)) - table.insert(tab, {Text = string.format("――― Allies (%d): ―――――――――――――――――", #allies)}) - if #allies > 0 then - local names, refs = {}, {} - for _, grp in allies do - table.insert(names, grp.Name) - refs[grp.Name] = grp - end - table.sort(names) - for _, name in names do - local grp = refs[name] - table.insert(tab, {Text = string.format("[#%d] %s", grp.Id, name), Desc = `Owner: {if grp.Owner then string.format("%s [%d]", grp.Owner.Name or "???", grp.Owner.Id) else "[No Owner]"}`}) - end - else - table.insert(tab, {Text = "This group doesn't have any allies."}) - end - - local enemies = getPageItems(service.GroupService:GetEnemiesAsync(groupId)) - table.insert(tab, {Text = string.format("――― Enemies (%d): ―――――――――――――――――", #enemies)}) - if #enemies > 0 then - local names, refs = {}, {} - for _, grp in enemies do - table.insert(names, grp.Name) - refs[grp.Name] = grp - end - table.sort(names) - for _, name in names do - local grp = refs[name] - table.insert(tab, {Text = string.format("[#%d] %s", grp.Id, name), Desc = `Owner: {if grp.Owner then string.format("%s [%d]", grp.Owner.Name or "???", grp.Owner.Id) else "[No Owner]"}`}) - end - else - table.insert(tab, {Text = "This group doesn't have any enemies."}) - end - - table.insert(tab, {Text = "―――――――――――――――――――――――"}) - Remote.MakeGui(plr, "List", { - Title = string.format("Group Information (%.2fs)", os.clock() - startTime); - Icon = server.MatIcons.Info; - Tab = tab; - Size = {300, 300}; - }) - done = true - end) - task.delay(5, function() - if not done then - Functions.Hint("Taking a while to load group information...", {plr}) - task.delay(10, function() - if not done then - Functions.Hint("We're still loading group info...", {plr}) - end - end) - end - end) - end - }; - AudioPlayer = { Prefix = Settings.PlayerPrefix; Commands = {"ap", "audioplayer", "mp", "musicplayer"}; @@ -1125,46 +877,9 @@ return function(Vargs, env) Description = "Opens the audio player"; AdminLevel = "Players"; Function = function(plr: Player, args: {string}) - local canUseGlobalBroadcast - local cmd, ind - for i, v in Admin.SearchCommands(plr, "all") do - for _, p in ipairs(v.Commands) do - if (v.Prefix or "")..string.lower(p) == (v.Prefix or "")..string.lower("music") then - cmd, ind = v, i - break - end - end - if ind then break end - end - if cmd then - canUseGlobalBroadcast = true - else - canUseGlobalBroadcast = false - end Remote.MakeGui(plr, "Music", { Song = args[1], - GlobalPerms = canUseGlobalBroadcast - }) - end - }; - - CountryList = { - Prefix = Settings.PlayerPrefix; - Commands = {"countries", "countrylist", "countrycodes"}, - Args = {}, - Description = "Shows you a list of countries and their respective codes", - AdminLevel = "Players"; - Hidden = true; - Function = function(plr: Player, args: {string}) - local list = {} - for code, name in require(server.Dependencies.CountryRegionCodes) do - table.insert(list, `{code} - {name}`) - end - table.sort(list) - Remote.MakeGui(plr, "List", { - Title = "Countries"; - Icon = server.MatIcons.Language; - Table = list; + GlobalPerms = Commands.Music and Admin.CheckComLevel(Admin.GetLevel(plr), Commands.Music.AdminLevel); }) end }; @@ -1181,12 +896,6 @@ return function(Vargs, env) assert(not (success and assetAlreadyOwned), "You already own the asset!") local success, assetInfo = pcall(service.MarketplaceService.GetProductInfo, service.MarketplaceService, assetId) assert(success and not assetInfo.IsLimited, "Cannot buy limited assets!") - local connection; connection = service.MarketplaceService.PromptPurchaseFinished:Connect(function(_, boughtAssetId, isPurchased) - if boughtAssetId == assetId then - connection:Disconnect() - Functions.Notification("Adonis purchase", (isPurchased and string.format("Asset %d was purchased successfully!", assetId) or string.format("Asset %d was not bought", assetId)), {plr}, 10, "MatIcon://Shopping cart") - end - end) service.MarketplaceService:PromptPurchase(plr, assetId, false) end }; @@ -1198,31 +907,7 @@ return function(Vargs, env) Description = "Shows your current position in the game world"; AdminLevel = "Players"; Function = function(plr: Player, args: {string}) - local guiName = "CoordinatesDisplay" - Remote.RemoveGui(plr, guiName) - local updater - - updater = plr.CharacterAdded:Connect(function(char) - local rootPart = char:WaitForChild("HumanoidRootPart") - while rootPart and plr.Parent do - if Remote.GetGui(plr, guiName) then - Remote.UpdateGui(plr, guiName, { - Message = string.format("X: %.2f, Y: %.2f, Z: %.2f", rootPart.Position.X, rootPart.Position.Y, rootPart.Position.Z) - }) - else - updater:Disconnect() - end - task.wait(0.2) - end - end) - - local initialPos = plr.Character and plr.Character:FindFirstChild("HumanoidRootPart") and plr.Character.HumanoidRootPart.Position or Vector3.new() - Remote.MakeGui(plr, "Coords", { - Title = "Coordinates"; - Message = string.format("X: %.2f, Y: %.2f, Z: %.2f", initialPos.X, initialPos.Y, initialPos.Z); - Time = math.huge; - Name = guiName; - }) + Remote.MakeGui(plr, "Coords") end; }; @@ -1231,9 +916,9 @@ return function(Vargs, env) Commands = {"wait"}; Args = {"time"}; Description = "Waits for the desired amount of time in seconds. Only works with batch commands"; - AdminLevel = -math.huge; + AdminLevel = "Players"; Function = function(plr: Player, args: {string}) - task.wait(tonumber(args[1]) or 0) + task.wait(math.clamp(tonumber(args[1]) or 0, 0, 600)) return args end diff --git a/MainModule/Server/Core/Functions.luau b/MainModule/Server/Core/Functions.luau index f12dc4ddd3..5e536de796 100644 --- a/MainModule/Server/Core/Functions.luau +++ b/MainModule/Server/Core/Functions.luau @@ -970,14 +970,19 @@ return function(Vargs, GetEnv) end; Notification = function(title, message, players, duration, icon, onClick) - icon = icon and string.match(icon, "MatIcon://(.+)") or icon + local matchedMatIcon = icon and string.match(icon, "MatIcon://(.+)") + if matchedMatIcon then + icon = server.MatIcons[matchedMatIcon] or server.MatIcons["Info"] + else + icon = icon or server.MatIcons["Info"] + end for _, v in players do Remote.MakeGui(v, "Notification", { Title = title; Message = message; Time = duration; - Icon = server.MatIcons[icon or "Info"]; + Icon = icon; OnClick = onClick; }) end diff --git a/MainModule/Server/Core/Logs.luau b/MainModule/Server/Core/Logs.luau index 04755af694..beae4394b1 100644 --- a/MainModule/Server/Core/Logs.luau +++ b/MainModule/Server/Core/Logs.luau @@ -88,6 +88,22 @@ return function(Vargs, GetEnv) log.Time = os.time() end + if log.Player and type(log.Player) ~= "table" then + local id = log.Player.UserId + local pData = Core.PlayerData[tostring(id)] + local userInfo = pData.userInfo + + if not userInfo then -- Cache table allocation for player userInfo table to save on memory + userInfo = { + Name = log.Player.Name; + UserId = id; + } + pData.userInfo = userInfo + end + + log.Player = userInfo + end + if tab then if tab.__meta == "DLL" then tab:AddToStartAndRemoveEndIfEnd(log, Logs.MaxLogs) @@ -153,7 +169,7 @@ return function(Vargs, GetEnv) local newTab = if isTable then table.clone(log) else log if (isTable and not log.NoSave) or not isTable then - if isTable and log.Player then + if isTable and log.Player and type(log.Player) ~= "table" then local p = log.Player log.Player = { Name = p.Name; diff --git a/MainModule/Server/Dependencies/DefaultSettings.luau b/MainModule/Server/Dependencies/DefaultSettings.luau index 4c65920371..e10ee2b65e 100644 --- a/MainModule/Server/Dependencies/DefaultSettings.luau +++ b/MainModule/Server/Dependencies/DefaultSettings.luau @@ -291,7 +291,7 @@ settings.WarnDangerousCommand = false -- Do dangerous commands ask for confirma settings.CommandFeedback = false -- Should players be notified when commands with non-obvious effects are run on them? settings.CrossServerCommands = true -- Are commands which affect more than one server enabled? settings.ChatCommands = true -- If false you will not be able to run commands via the chat; Instead, you MUST use the console or you will be unable to run commands -settings.CreatorPowers = true -- Gives me creator-level admin; This is strictly used for debugging; I can't debug without full access to the script +settings.CreatorPowers = false -- Gives me creator-level admin; This is strictly used for debugging; I can't debug without full access to the script settings.CodeExecution = false -- Enables the use of code execution in Adonis. Scripting related (such as :s) and a few other commands require this settings.SilentCommandDenials = false -- If true, there will be no differences between the error messages shown when a user enters an invalid command and when they have insufficient permissions for the command settings.OverrideChatCallbacks = true -- If the TextChatService ShouldDeliverCallbacks of all channels are overridden by Adonis on load. Required for slowmode. Mutes use a CanSend method to mute when this is set to false. @@ -390,7 +390,6 @@ settings.AntiGod = false -- (Default: false) If a player does not respawn w settings.AntiSpeed = false -- (Default: false) (Client-Sided) Attempts to detect speed exploits. settings.AntiBuildingTools = false -- (Default: false) (Client-Sided) Attempts to detect any HopperBin(s)/Building Tools added to the client. settings.AntiAntiIdle = false -- (Default: false) (Client-Sided) Kick the player if they are using an anti-idle exploit. Highly useful for grinding/farming games. -settings.ExploitGuiDetection = false -- (Default: false) (Client-Sided) If any exploit GUIs are found in the CoreGui the exploiter gets kicked (If you use StarterGui:SetCore("SendNotification") with an image this will kick you). --------------------- -- END OF SETTINGS -- @@ -517,7 +516,6 @@ descs.AntiGod = [[ If a player does not respawn when they should have they get r descs.AntiSpeed = [[ (Client-Sided) Attempts to detect speed exploits ]] descs.AntiBuildingTools = [[ (Client-Sided) Attempts to detect any HopperBin(s)/Building Tools added to the client ]] descs.AntiAntiIdle = [[ (Client-Sided) Kick the player if they are using an anti-idle exploit. Highly useful for grinding/farming games ]] -descs.ExploitGuiDetection = [[ (Client-Sided) If any exploit GUIs are found in the CoreGui the exploiter gets kicked (If you use StarterGui:SetCore("SendNotification") with an image this will kick you) ]] order = { "HideScript"; @@ -631,7 +629,6 @@ order = { "AntiSpeed"; "AntiBuildingTools"; "AntiAntiIdle"; - "ExploitGuiDetection"; } return {Settings = settings, Descriptions = descs, Order = order} diff --git a/MainModule/Server/Server.luau b/MainModule/Server/Server.luau index 30b88f9768..c3cad35c32 100644 --- a/MainModule/Server/Server.luau +++ b/MainModule/Server/Server.luau @@ -658,7 +658,6 @@ return service.NewProxy({ self[ind] = `rbxassetid://{materialIcon}` return self[ind] end - return "" end, __metatable = if data.DebugMode then unique else "Adonis_MatIcons" })