├── LICENSE ├── README.md ├── assets ├── dat │ └── items.dat └── ssl │ ├── server.crt │ └── server.key ├── data └── dev.db ├── dist ├── abstracts │ ├── Action.js │ ├── Command.js │ ├── Dialog.js │ └── Listener.js ├── actions │ ├── DialogReturn.js │ ├── Drop.js │ ├── EnterGame.js │ ├── Input.js │ ├── JoinRequest.js │ ├── Quit.js │ ├── QuitToExit.js │ ├── RefreshItemData.js │ ├── Respawn.js │ ├── RespawnSpike.js │ ├── Store.js │ ├── Trash.js │ └── Wrench.js ├── commands │ ├── CarnivalEnd.js │ ├── CarnivalStart.js │ ├── DQ.js │ ├── Event.js │ ├── Find.js │ ├── GiveGems.js │ ├── Help.js │ ├── Invis.js │ ├── SB.js │ ├── Warp.js │ └── pv.js ├── database │ └── db.js ├── dialogs │ ├── BanUser.js │ ├── Carnival.js │ ├── DQend.js │ ├── DailyQuest.js │ ├── DoorEdit.js │ ├── DropEnd.js │ ├── FindItem.js │ ├── FindItemEnd.js │ ├── Noob.js │ ├── SignEdit.js │ ├── Telephone.js │ ├── TrashEnd.js │ └── Xenonite.js ├── events │ ├── Connect.js │ ├── Disconnect.js │ └── Raw.js ├── structures │ ├── BaseServer.js │ ├── Collection.js │ ├── Logger.js │ ├── Peer.js │ ├── TileExtra.js │ ├── Webserver.js │ └── World.js └── utils │ ├── Constants.js │ ├── Utils.js │ ├── builders │ └── DialogBuilder.js │ └── enums │ ├── DataTypes.js │ ├── ItemTypes.js │ ├── TankTypes.js │ └── Tiles.js ├── json.sqlite ├── knexfile.js ├── migrations ├── 20230809144402_growtopia_users.js └── 20230809145200_growtopia_worlds.js ├── package-lock.json ├── package.json ├── scripts ├── crypto.js └── setup.js ├── seeds └── growtopia_users.js ├── setupNrun.bat ├── src ├── abstracts │ ├── Action.ts │ ├── Command.ts │ ├── Dialog.ts │ └── Listener.ts ├── actions │ ├── DialogReturn.ts │ ├── Drop.ts │ ├── EnterGame.ts │ ├── FriendsDialog.ts │ ├── Input.ts │ ├── JoinRequest.ts │ ├── Quit.ts │ ├── QuitToExit.ts │ ├── RefreshItemData.ts │ ├── Respawn.ts │ ├── RespawnSpike.ts │ ├── Store.ts │ ├── Trash.ts │ └── Wrench.ts ├── app.ts ├── commands │ ├── AddFriend.ts │ ├── CarnivalEnd.ts │ ├── CarnivalStart.ts │ ├── CheckInventory.ts │ ├── Cry.ts │ ├── DQ.ts │ ├── DanceCmd.ts │ ├── Event.ts │ ├── Find.ts │ ├── GemEventEnd.ts │ ├── GemEventStart.ts │ ├── GiveGems.ts │ ├── GiveRole.ts │ ├── Help.ts │ ├── Invis.ts │ ├── MsgCmd.ts │ ├── SB.ts │ ├── TradeCmd.ts │ ├── Warp.ts │ └── pv.ts ├── database │ └── db.ts ├── dialogs │ ├── BanUser.ts │ ├── CGDialog.ts │ ├── Carnival.ts │ ├── DQend.ts │ ├── DailyQuest.ts │ ├── DoorEdit.ts │ ├── DropEnd.ts │ ├── FindItem.ts │ ├── FindItemEnd.ts │ ├── FriendList.ts │ ├── GuiildCreate.ts │ ├── LockEdit.ts │ ├── Noob.ts │ ├── RegisterEnd.ts │ ├── SignEdit.ts │ ├── Surgery.ts │ ├── Surgery1(1).ts │ ├── Telephone.ts │ ├── TrashEnd.ts │ └── Xenonite.ts ├── events │ ├── Connect.ts │ ├── Disconnect.ts │ └── Raw.ts ├── structures │ ├── BaseServer.ts │ ├── Collection.ts │ ├── Logger.ts │ ├── Peer.ts │ ├── TileExtra.ts │ ├── Webserver.ts │ └── World.ts ├── tanks │ ├── BlockPlacing.ts │ ├── BlockWrench.ts │ ├── Effects.ts │ ├── Place.ts │ ├── Punch.ts │ ├── game_events.json │ └── game_events.ts ├── types │ ├── action.d.ts │ ├── command.d.ts │ ├── database.d.ts │ ├── dialog.d.ts │ ├── events.d.ts │ ├── peer.d.ts │ └── world.d.ts └── utils │ ├── Constants.ts │ ├── Utils.ts │ ├── builders │ └── DialogBuilder.ts │ └── enums │ ├── DataTypes.ts │ ├── ItemTypes.ts │ ├── TankTypes.ts │ └── Tiles.ts ├── tsconfig.json └── web └── views └── register.ejs /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Hendra Gunawan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > [!NOTE] 2 | > I am remaking GrowJS project soon! Do join my Discord to suggest what to add. 3 | > 4 | 5 | # GrowJS-Project 6 | Growtopia private server made with nodejs! 7 | 8 | > [!WARNING] 9 | > This project has been discontinued and is outdated. Please wait for further notice in our Discord. 10 | > DO USE THE ORIGINAL SOURCE, NEW LOGIN SYSTEM IS NOT ADDED HERE! 11 | > 12 | 13 | # Views 14 | [![](https://visitcount.itsvg.in/api?id=GrowJS&label=Project%20Views&pretty=false)](https://visitcount.itsvg.in) 15 | 16 | # How To Setup 17 | (Any module error, do `npm install `) 18 | ``` 19 | $ npm install 20 | ``` 21 | 22 | ``` 23 | $ npm run setup 24 | ``` 25 | 26 | ``` 27 | $ npm run dev 28 | ``` 29 | __If needed:__ 30 | 31 | ``` 32 | $ npm install knex 33 | ``` 34 | 35 | ``` 36 | $ npm install quick.db 37 | ``` 38 | 39 | # Note 40 | - Server was based from credits, huge thanks to JadlionHD [Credit below](https://github.com/HTPGTDev/GrowJS-Project/blob/main/README.md#credits--how-to-setup) 41 | - Do not sell it(Dumb person will do it) 42 | - Databases used: knex & quick.db(Alternative). 43 | 44 | # Change-logs 45 | - Added Surgery (Surg-e) 46 | - Added World Lock wrench 47 | - Added Guild (UI and database only ~ todo) 48 | - Improved gem drops (No longer drops visual 1 gem, and collects more than 1) 49 | - Fixed /invis 50 | - Added Growtopia store (OUTDATED/Broken - Fetch from gt) 51 | - Added players profile like rgt 52 | - Added /trade (Example only, might work on it soon) 53 | - Added in-game GrowID creation 54 | - Added chicken plow and harvester 55 | - Added Jammers (Todo) 56 | - Added roulette (Broken) 57 | - Listed many packets useful for your changes.
58 | **There's still more, join my server for future cool updates** - [GrowJS Project](https://discord.gg/G8uBgagYcf) 59 | 60 | # Features 61 | - Xenoite 62 | - Gem Store (Not finished) 63 | - /punishview (To-do) 64 | - Ringmaster 65 | - Gem drops 66 | - Telephone (Daily Quest) 67 | - /sb (Not fixed) 68 | - /help 69 | - /invis 70 | - /dq (Generate new dq) 71 | - /event (start world event) 72 | - /carnivalstart & /carnivalend (Start & End carnival anytime.) 73 | 74 | # To-do list 75 | - Fixed all bugs. 76 | 77 | # Found any bugs? Contact me on Discord 78 | how_to_play#0 79 | [Discord Server](https://discord.gg/ZqxeqhGZG8) 80 | 81 | # Contributors 82 | Feel free to do so. 83 | 84 | # Credits & How to setup 85 | [Credits](https://github.com/JadlionHD/GrowServer/tree/main#credits) | 86 | [Original repo & Learn to setup](https://github.com/JadlionHD/GrowServer) 87 | -------------------------------------------------------------------------------- /assets/dat/items.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTPDeveloper/GrowJS-Project/8525bb8b7ece2f1878b24ce168792c12484e3bcc/assets/dat/items.dat -------------------------------------------------------------------------------- /assets/ssl/server.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDezCCAmMCFEwc7lnwQW3YD2GTvN9sOzJeyp9/MA0GCSqGSIb3DQEBCwUAMHox 3 | CzAJBgNVBAYTAklEMRAwDgYDVQQIDAdKYWthcnRhMRAwDgYDVQQHDAdKYWthcnRh 4 | MRQwEgYDVQQKDAtHcm93dG9waWFJTzEUMBIGA1UECwwLR3Jvd3RvcGlhSU8xGzAZ 5 | BgNVBAMMEnd3dy5ncm93dG9waWExLmNvbTAeFw0yMjEwMDkwOTAwMjRaFw0yMzEw 6 | MDkwOTAwMjRaMHoxCzAJBgNVBAYTAklEMRAwDgYDVQQIDAdKYWthcnRhMRAwDgYD 7 | VQQHDAdKYWthcnRhMRQwEgYDVQQKDAtHcm93dG9waWFJTzEUMBIGA1UECwwLR3Jv 8 | d3RvcGlhSU8xGzAZBgNVBAMMEnd3dy5ncm93dG9waWExLmNvbTCCASIwDQYJKoZI 9 | hvcNAQEBBQADggEPADCCAQoCggEBAKwGwqNCrChP6ZtQuayR7Ntr8koAlwg1terj 10 | A3PQgSllGCLDJtAIA+iXNKL09okIzV0rd8HoBCles8l3xBCd7dsgrghpPcpC1q/M 11 | EhA39Eq0shODm7I5YGDoI9CWOPnutwmQ+H3SjfmOiFFX0lIldA6EL4yvtWyXDGGn 12 | QeBOZOYb114KXm1mqpN/YbYA51IE0/dJqNC5Lf5Wa45Hn2oTA+fUKCyIMSPjk8nF 13 | rcYqd+cdCnuEC4oWqhbpR+jE76X/ZSFwWSVmdAflbxNAtBH9xm8lT/QL5tD/2DMw 14 | rVs9HGvro7uW8FBmdSL4btSZYU0DdNURJAaIC8bpOGVVPbp34McCAwEAATANBgkq 15 | hkiG9w0BAQsFAAOCAQEAMWzTZ5iS0sOA3YQ3gisqCAtPjLPkeGVh9o11iCRR8rS/ 16 | Ld0ufgIatGq3+iCZg7ihhGXoO6mQ8nzB7h1hQefeh/nuFwaZrqgAN3w5Sfm7Luh9 17 | JyLXRKG/QrTW4jcUy4DF7wIBK3mlLQM2czKXO+PlOX4zlj7fSUMAgQr8ikTZpLiF 18 | Y4r/Q3Gj8n7ocrBfDo5S1/ufUjUd+0A7Z7XCGz0V+k6qAslgfoAwxNwedKwhFGhp 19 | fBXKiBrDNrB+xkbDGq2i+8wecbjo1ksjVBEcnkb9/ReQII7ukmwouFQAbxv6zO5f 20 | 61a6wKf7Rz24Fxs5TxoqXOPKB5yxwJ2lDjpkz2MlKw== 21 | -----END CERTIFICATE----- 22 | -------------------------------------------------------------------------------- /assets/ssl/server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpQIBAAKCAQEArAbCo0KsKE/pm1C5rJHs22vySgCXCDW16uMDc9CBKWUYIsMm 3 | 0AgD6Jc0ovT2iQjNXSt3wegEKV6zyXfEEJ3t2yCuCGk9ykLWr8wSEDf0SrSyE4Ob 4 | sjlgYOgj0JY4+e63CZD4fdKN+Y6IUVfSUiV0DoQvjK+1bJcMYadB4E5k5hvXXgpe 5 | bWaqk39htgDnUgTT90mo0Lkt/lZrjkefahMD59QoLIgxI+OTycWtxip35x0Ke4QL 6 | ihaqFulH6MTvpf9lIXBZJWZ0B+VvE0C0Ef3GbyVP9Avm0P/YMzCtWz0ca+uju5bw 7 | UGZ1Ivhu1JlhTQN01REkBogLxuk4ZVU9unfgxwIDAQABAoIBAFFBcDaFi6QO+x0t 8 | 6EYnN2X9exiRZsWt+RvV1w+hcSEIa3ogC/k/j/kRUv+WDc10puxXV93zpeOUo/+J 9 | 3saqkmtq6El4zIL5R0cKcY3PoEiZSXQGOkjY6Tlc7W3dR1Rm+XY/T+C+z+kM9j7V 10 | 6LZ8knE45uzhIiUExAhsZKV64hX+UlC0ge6kwaF9CZC0K/UknVypNn7aX7ViQPQs 11 | etS4uohhH7pLRO3XhfIzD8XnRsj/TianzgI09NTv5sNgKaV/IhI2Vnh6FDp1MOee 12 | fgeWBxuBRyFkcYZur44ij2fDEV6Lq/FQ1oNBncgYdws0btE3FO27z1FZj0zXBsHT 13 | rkwqM0ECgYEA1yL5KJ0pyOashAejI2N8fqRmC6emiMwFd9zNUdA4b3F6GfipiVqP 14 | hIacbIYUyFtsEepXKV4EYMh29WbnPDR6pmpnc65ZvW935qTDNVqEaEcqRW//N1zj 15 | R8zMrO5PJ2d2ea18KN7CBPKoEgeqzt4f2rPV0ChF2yw5F8UMhqp9BM8CgYEAzLON 16 | K1WXSOWQyBDlFkFKwI5YIDg/voEPxDzUHxTpgTvvzd5NWEm0fL2DR7nS9ZJ0itO/ 17 | YsR51QzpHLn6LHdu6pEfYnK2NI5+C3OfWr4ObvsWxdJAmHkJ5BVlLgXEob5jJgta 18 | Qm5/rbwne9TgEQv3bo7Isw+BmOqOF58bKfsaUokCgYEAxsTqXerve04dYJNJ2F2H 19 | 3d545hXM2SFfgAJCtW9jZRv8S1ijE2PXrANPLTmopAFL1TWluHPEKcOtnUipJsf5 20 | 9h3jXU9eXJdLuY7LSVVLdqkh1iwHKpio6WLATJqWCXsfTIbMa1p8+mNUg+wPlbhG 21 | yCNVzlAXUswGJ/8Idre4cKMCgYEAjb32jn8h1nQ/oIkyWAq1/EeUdhr86KjthfCo 22 | 4SzV04rxLhg0bmH6/DUt5kih7zGOSWL+LyHlSsU51Y5h0NCSmRIMLVtJF3NjjAJv 23 | 4aGg1PBAgJJp8Co/0xONkCSmV2lBtmI+CaoB9wdGP9TTonoqxv9Psc2W64/e/DRL 24 | 1vHs9CECgYEAm9Ti2NmuJzDAeA+cSQdMJNpJiorwxCaspf29HphXyEuoXAxPSBPu 25 | Lrr9/QZm+zaNhJX3MY3Mx5K15R3IWqThqggj2KZ1U4g0sgsgHRrcavQQ0ysYAsEh 26 | 83fLmrGgemdW2J4j7KBfLV9U6UP4TbdbarbYng8dGPNNqAjw1I98bfE= 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /data/dev.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTPDeveloper/GrowJS-Project/8525bb8b7ece2f1878b24ce168792c12484e3bcc/data/dev.db -------------------------------------------------------------------------------- /dist/abstracts/Action.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.Action = void 0; 4 | class Action { 5 | constructor() { 6 | this.config = { 7 | eventName: undefined 8 | }; 9 | } 10 | handle(base, peer, db, action) { } 11 | } 12 | exports.Action = Action; 13 | -------------------------------------------------------------------------------- /dist/abstracts/Command.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.Command = void 0; 4 | class Command { 5 | constructor() { 6 | this.opt = { 7 | name: "", 8 | description: "", 9 | cooldown: 1, 10 | ratelimit: 1, 11 | category: "", 12 | usage: "", 13 | example: [], 14 | permission: [] 15 | }; 16 | } 17 | async execute(base, peer, text, args) { } 18 | } 19 | exports.Command = Command; 20 | -------------------------------------------------------------------------------- /dist/abstracts/Dialog.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.Dialog = void 0; 4 | const quick_db_1 = require("quick.db"); 5 | const data = new quick_db_1.QuickDB; 6 | class Dialog { 7 | constructor() { 8 | this.config = { 9 | dialogName: undefined 10 | }; 11 | } 12 | handle(base, peer, db, action) { } 13 | } 14 | exports.Dialog = Dialog; 15 | -------------------------------------------------------------------------------- /dist/abstracts/Listener.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.Listener = void 0; 4 | class Listener { 5 | constructor() { 6 | this.name = undefined; 7 | } 8 | run(base, ...args) { } 9 | } 10 | exports.Listener = Listener; 11 | -------------------------------------------------------------------------------- /dist/actions/DialogReturn.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const Action_1 = require("../abstracts/Action"); 4 | class default_1 extends Action_1.Action { 5 | constructor() { 6 | super(); 7 | this.config = { 8 | eventName: "dialog_return" 9 | }; 10 | } 11 | handle(base, peer, db, action) { 12 | let name = action.dialog_name; 13 | try { 14 | if (!base.dialogs.has(name)) 15 | return; 16 | base.dialogs.get(name).handle(base, peer, db, action); 17 | } 18 | catch (err) { 19 | console.log(err); 20 | } 21 | } 22 | } 23 | exports.default = default_1; 24 | -------------------------------------------------------------------------------- /dist/actions/Drop.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const Action_1 = require("../abstracts/Action"); 4 | const DialogBuilder_1 = require("../utils/builders/DialogBuilder"); 5 | const growtopia_js_1 = require("growtopia.js"); 6 | class default_1 extends Action_1.Action { 7 | constructor() { 8 | super(); 9 | this.config = { 10 | eventName: "drop" 11 | }; 12 | } 13 | handle(base, peer, db, action) { 14 | const itemID = parseInt(action.itemID); 15 | const item = base.items.metadata.items.find((v) => v.id === itemID); 16 | const peerItem = peer.data.inventory?.items.find((v) => v.id === itemID); 17 | let dialog = new DialogBuilder_1.DialogBuilder() 18 | .defaultColor() 19 | .addLabelWithIcon(`Drop ${item?.name}`, item?.id, "big") 20 | .addTextBox("How many to drop?") 21 | .addInputBox("drop_count", "", peerItem?.amount, 5) 22 | .embed("itemID", itemID) 23 | .endDialog("drop_end", "Cancel", "OK") 24 | .str(); 25 | peer.send(growtopia_js_1.Variant.from("OnDialogRequest", dialog)); 26 | } 27 | } 28 | exports.default = default_1; 29 | -------------------------------------------------------------------------------- /dist/actions/EnterGame.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const growtopia_js_1 = require("growtopia.js"); 4 | const Action_1 = require("../abstracts/Action"); 5 | const DialogBuilder_1 = require("../utils/builders/DialogBuilder"); 6 | const quick_db_1 = require("quick.db"); 7 | const data = new quick_db_1.QuickDB; 8 | class default_1 extends Action_1.Action { 9 | constructor() { 10 | super(); 11 | this.config = { 12 | eventName: "enter_game" 13 | }; 14 | } 15 | async handle(base, peer, db, action) { 16 | // Carnival Message 17 | const carnival = await data.get(`Carnival`); 18 | const tes = new DialogBuilder_1.DialogBuilder() 19 | .defaultColor() 20 | .addLabelWithIcon("Hello", "1000", "big") 21 | .addSpacer("small") 22 | .addTextBox("Welcome to GrowServer") 23 | .raw("add_image_button||interface/large/news_banner1.rttex|bannerlayout|||\n") 24 | .addQuickExit() 25 | .endDialog("gazzette_end", "Cancel", "Ok") 26 | .str(); 27 | peer.send(growtopia_js_1.Variant.from("OnRequestWorldSelectMenu"), growtopia_js_1.Variant.from("OnConsoleMessage", `Welcome! ${peer.name} Where would you like to go?`), growtopia_js_1.Variant.from({ delay: 100 }, "OnDialogRequest", tes)); 28 | if (carnival) { 29 | peer.send(growtopia_js_1.Variant.from("OnRequestWorldSelectMenu"), growtopia_js_1.Variant.from("OnConsoleMessage", "`2Carnival has come to town`0, visit the world `9CARNIVAL`0, try your luck at winning one of the ringmaster's fabulous rings!")); 30 | } 31 | } 32 | } 33 | exports.default = default_1; 34 | -------------------------------------------------------------------------------- /dist/actions/Input.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const growtopia_js_1 = require("growtopia.js"); 4 | const Action_1 = require("../abstracts/Action"); 5 | class default_1 extends Action_1.Action { 6 | constructor() { 7 | super(); 8 | this.config = { 9 | eventName: "input" 10 | }; 11 | } 12 | async handle(base, peer, db, action) { 13 | let text = action.text.trim(); 14 | if (!text || text.replace(/`.|`/g, "").length < 1) 15 | return; 16 | if (text.startsWith("/")) { 17 | const args = text.slice("/".length).split(" "); 18 | const commandName = args.shift()?.toLowerCase(); 19 | if (!base.commands.has(commandName)) { 20 | return peer.send(growtopia_js_1.Variant.from("OnConsoleMessage", "`4Unknown command.`` Enter `$/help`` for a list of valid commands")); 21 | } 22 | peer.send(growtopia_js_1.Variant.from("OnConsoleMessage", `\`6/${commandName} ${args.join(" ")}\`\``)); 23 | // Cooldown & Ratelimit 24 | if (!base.cooldown.get(`${commandName}-netID-${peer.data.netID}`)) { 25 | base.cooldown.set(`${commandName}-netID-${peer.data.netID}`, { 26 | limit: 1, 27 | time: Date.now() 28 | }); 29 | } 30 | else { 31 | let expireTime = base.cooldown.get(`${commandName}-netID-${peer.data.netID}`).time + 32 | base.commands.get(commandName).opt.cooldown * 1000; 33 | let timeLeft = expireTime - Date.now(); 34 | if (base.cooldown.get(`${commandName}-netID-${peer.data.netID}`).limit >= 35 | base.commands.get(commandName).opt.ratelimit) { 36 | return peer.send(growtopia_js_1.Variant.from("OnConsoleMessage", `\`6${peer.data.tankIDName}\`0 you're being ratelimited, please wait \`9${timeLeft / 1000}s\`0`)); 37 | } 38 | } 39 | base.cooldown.get(`${commandName}-netID-${peer.data.netID}`).limit += 1; 40 | setTimeout(() => { 41 | base.cooldown.delete(`${commandName}-netID-${peer.data.netID}`); 42 | }, base.commands.get(commandName).opt.cooldown * 1000); 43 | try { 44 | if (base.commands.get(commandName)?.opt.permission.some((perm) => perm === peer.data.role)) { 45 | await base.commands.get(commandName)?.execute(base, peer, text, args); 46 | } 47 | else { 48 | peer.send(growtopia_js_1.Variant.from("OnConsoleMessage", `You dont have permission to use this command.`)); 49 | } 50 | } 51 | catch (err) { 52 | console.log(err); 53 | } 54 | return; 55 | } 56 | peer.everyPeer((p) => { 57 | if (p.data.world === peer.data.world && peer.data.world !== "EXIT") { 58 | p.send(growtopia_js_1.Variant.from("OnTalkBubble", peer.data.netID, action.text, 0), growtopia_js_1.Variant.from("OnConsoleMessage", `CP:0_PL:0_OID:_CT:[W]_ <\`w${peer.data.tankIDName}\`\`> ${action.text}`)); 59 | } 60 | }); 61 | } 62 | } 63 | exports.default = default_1; 64 | -------------------------------------------------------------------------------- /dist/actions/JoinRequest.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const growtopia_js_1 = require("growtopia.js"); 4 | const Action_1 = require("../abstracts/Action"); 5 | const quick_db_1 = require("quick.db"); 6 | const data = new quick_db_1.QuickDB; 7 | class default_1 extends Action_1.Action { 8 | constructor() { 9 | super(); 10 | this.config = { 11 | eventName: "join_request" 12 | }; 13 | } 14 | async handle(base, peer, db, action) { 15 | const worldName = action.name || ""; 16 | if (worldName.length <= 0) { 17 | return peer.send(growtopia_js_1.Variant.from("OnFailedToEnterWorld", 1), growtopia_js_1.Variant.from("OnConsoleMessage", "That world name is uhh `9empty``")); 18 | } 19 | if (worldName.match(/\W+|_|EXIT/gi)) { 20 | return peer.send(growtopia_js_1.Variant.from("OnFailedToEnterWorld", 1), growtopia_js_1.Variant.from("OnConsoleMessage", "That world name is too `9special`` to be entered.")); 21 | } 22 | setTimeout(() => { 23 | peer.enterWorld(worldName.toUpperCase()); 24 | }, 300); 25 | } 26 | } 27 | exports.default = default_1; 28 | -------------------------------------------------------------------------------- /dist/actions/Quit.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const Action_1 = require("../abstracts/Action"); 4 | class default_1 extends Action_1.Action { 5 | constructor() { 6 | super(); 7 | this.config = { 8 | eventName: "quit" 9 | }; 10 | } 11 | handle(base, peer, db, action) { 12 | peer.disconnect(); 13 | } 14 | } 15 | exports.default = default_1; 16 | -------------------------------------------------------------------------------- /dist/actions/QuitToExit.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const Action_1 = require("../abstracts/Action"); 4 | class default_1 extends Action_1.Action { 5 | constructor() { 6 | super(); 7 | this.config = { 8 | eventName: "quit_to_exit" 9 | }; 10 | } 11 | handle(base, peer, db, action) { 12 | peer.leaveWorld(); 13 | } 14 | } 15 | exports.default = default_1; 16 | -------------------------------------------------------------------------------- /dist/actions/RefreshItemData.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const growtopia_js_1 = require("growtopia.js"); 4 | const Action_1 = require("../abstracts/Action"); 5 | const TankTypes_1 = require("../utils/enums/TankTypes"); 6 | class default_1 extends Action_1.Action { 7 | constructor() { 8 | super(); 9 | this.config = { 10 | eventName: "refresh_item_data" 11 | }; 12 | } 13 | handle(base, peer, db, action) { 14 | peer.send(growtopia_js_1.Variant.from("OnConsoleMessage", "One moment. Updating item data..."), growtopia_js_1.TankPacket.from({ type: TankTypes_1.TankTypes.PEER_ITEMS_DAT, data: () => base.items.content })); 15 | } 16 | } 17 | exports.default = default_1; 18 | -------------------------------------------------------------------------------- /dist/actions/Respawn.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const Action_1 = require("../abstracts/Action"); 4 | class default_1 extends Action_1.Action { 5 | constructor() { 6 | super(); 7 | this.config = { 8 | eventName: "respawn" 9 | }; 10 | } 11 | handle(base, peer, db, action) { 12 | peer.respawn(); 13 | // TODO: respawn back to previous checkpoint 14 | } 15 | } 16 | exports.default = default_1; 17 | -------------------------------------------------------------------------------- /dist/actions/RespawnSpike.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const Action_1 = require("../abstracts/Action"); 4 | class default_1 extends Action_1.Action { 5 | constructor() { 6 | super(); 7 | this.config = { 8 | eventName: "respawn_spike" 9 | }; 10 | } 11 | handle(base, peer, db, action) { 12 | peer.respawn(); 13 | // TODO: respawn back to previous checkpoint 14 | } 15 | } 16 | exports.default = default_1; 17 | -------------------------------------------------------------------------------- /dist/actions/Store.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const Action_1 = require("../abstracts/Action"); 4 | const DialogBuilder_1 = require("../utils/builders/DialogBuilder"); 5 | const growtopia_js_1 = require("growtopia.js"); 6 | class default_1 extends Action_1.Action { 7 | constructor() { 8 | super(); 9 | this.config = { 10 | eventName: "store" 11 | }; 12 | } 13 | handle(base, peer, db, action) { 14 | const itemID = parseInt(action.itemID); 15 | const item = base.items.metadata.items.find((v) => v.id === itemID); 16 | const peerItem = peer.data.inventory?.items.find((v) => v.id === itemID); 17 | let dialog = new DialogBuilder_1.DialogBuilder() 18 | .defaultColor() 19 | .addLabelWithIcon("Gem Store", 112, "big") //.addLabelWithIcon(`Drop ${item?.name}`, item?.id!, "big") 20 | .addButton("lock", "Locks Store") 21 | .addSpacer("small") 22 | .addButton("wings", "Wings Store") 23 | .addSpacer("small") 24 | .addButton("Title", "Title Store") 25 | .addSpacer("small") 26 | .addButton("sitems", "Special Items Store") 27 | .addSpacer("big") 28 | .addSmallText("* `9Lock converter`0 *") 29 | .addButtonWithIcon("dl", 1796, "Diamond Lock") 30 | .addButtonWithIcon("bgl", 7188, "Blue Gem Lock") 31 | //.addInputBox("drop_count", "", peerItem?.amount, 5) 32 | .embed("itemID", itemID) 33 | //.endDialog("drop_end", "Cancel", "OK") 34 | .addQuickExit() 35 | .str(); 36 | peer.send(growtopia_js_1.Variant.from("OnDialogRequest", dialog)); 37 | } 38 | } 39 | exports.default = default_1; 40 | -------------------------------------------------------------------------------- /dist/actions/Trash.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const Action_1 = require("../abstracts/Action"); 4 | const DialogBuilder_1 = require("../utils/builders/DialogBuilder"); 5 | const growtopia_js_1 = require("growtopia.js"); 6 | class default_1 extends Action_1.Action { 7 | constructor() { 8 | super(); 9 | this.config = { 10 | eventName: "trash" 11 | }; 12 | } 13 | handle(base, peer, db, action) { 14 | const itemID = parseInt(action.itemID); 15 | const item = base.items.metadata.items.find((v) => v.id === itemID); 16 | const peerItem = peer.data.inventory?.items.find((v) => v.id === itemID); 17 | if (peerItem?.id === 32 || peerItem?.id === 18) 18 | return peer.send(growtopia_js_1.Variant.from("OnTextOverlay", "Cannot trash this item.")); 19 | let dialog = new DialogBuilder_1.DialogBuilder() 20 | .defaultColor() 21 | .addLabelWithIcon(`\`4Trash\`\` ${item?.name}`, item?.id, "big") 22 | .addTextBox(`How many to \`4destroy\`\`? (you have ${peerItem?.amount})`) 23 | .addInputBox("trash_count", "", peerItem?.amount, 5) 24 | .embed("itemID", itemID) 25 | .endDialog("trash_end", "Cancel", "OK") 26 | .str(); 27 | peer.send(growtopia_js_1.Variant.from("OnDialogRequest", dialog)); 28 | } 29 | } 30 | exports.default = default_1; 31 | -------------------------------------------------------------------------------- /dist/actions/Wrench.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const Action_1 = require("../abstracts/Action"); 4 | const DialogBuilder_1 = require("../utils/builders/DialogBuilder"); 5 | const growtopia_js_1 = require("growtopia.js"); 6 | class default_1 extends Action_1.Action { 7 | constructor() { 8 | super(); 9 | this.config = { 10 | eventName: "wrench" 11 | }; 12 | } 13 | handle(base, peer, db, action) { 14 | let dialog = new DialogBuilder_1.DialogBuilder() 15 | .defaultColor() 16 | .addButton("account_s", "Account Settings") 17 | .addButton("title", "Title") 18 | .addSpacer("small") 19 | .addLabelWithIcon(peer.data.tankIDName, "32", "small") 20 | .addTextBox(`Hello your name is ${peer.data.tankIDName}`) 21 | .addTextBox(`And your netID is ${peer.data.netID}`) 22 | .addQuickExit() 23 | .str(); 24 | peer.send(growtopia_js_1.Variant.from({ delay: 100 }, "OnDialogRequest", dialog)); 25 | } 26 | } 27 | exports.default = default_1; 28 | -------------------------------------------------------------------------------- /dist/commands/CarnivalEnd.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const growtopia_js_1 = require("growtopia.js"); 4 | const Command_1 = require("../abstracts/Command"); 5 | const Constants_1 = require("../utils/Constants"); 6 | const quick_db_1 = require("quick.db"); 7 | const data = new quick_db_1.QuickDB; 8 | class default_1 extends Command_1.Command { 9 | constructor() { 10 | super(); 11 | this.opt = { 12 | name: "endcarnival", 13 | description: "Close Carnival.", 14 | cooldown: 0, 15 | ratelimit: 1, 16 | category: "Basic", 17 | usage: "/endcarnival", 18 | example: ["/endcarnival"], 19 | permission: [Constants_1.Role.BASIC, Constants_1.Role.SUPPORTER, Constants_1.Role.DEVELOPER] 20 | }; 21 | } 22 | async execute(base, peer, text, args) { 23 | peer.everyPeer((p) => { 24 | p.send(growtopia_js_1.Variant.from("OnConsoleMessage", "`2Carnival has left to town`0, The Ringmaster will be back in afew days.")); 25 | data.set(`Carnival`, false); 26 | }); 27 | } 28 | } 29 | exports.default = default_1; 30 | -------------------------------------------------------------------------------- /dist/commands/CarnivalStart.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const growtopia_js_1 = require("growtopia.js"); 4 | const Command_1 = require("../abstracts/Command"); 5 | const Constants_1 = require("../utils/Constants"); 6 | const quick_db_1 = require("quick.db"); 7 | const data = new quick_db_1.QuickDB; 8 | class default_1 extends Command_1.Command { 9 | constructor() { 10 | super(); 11 | this.opt = { 12 | name: "startcarnival", 13 | description: "Open Carnival.", 14 | cooldown: 0, 15 | ratelimit: 1, 16 | category: "Basic", 17 | usage: "/startcarnival", 18 | example: ["/startcarnival"], 19 | permission: [Constants_1.Role.BASIC, Constants_1.Role.SUPPORTER, Constants_1.Role.DEVELOPER] 20 | }; 21 | } 22 | async execute(base, peer, text, args) { 23 | peer.everyPeer((p) => { 24 | p.send(growtopia_js_1.Variant.from("OnConsoleMessage", "`2Carnival has come to town`0, visit the world `9CARNIVAL`0, try your luck at winning one of the ringmaster's fabulous rings!")); 25 | data.set(`Carnival`, true); 26 | }); 27 | } 28 | } 29 | exports.default = default_1; 30 | -------------------------------------------------------------------------------- /dist/commands/DQ.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const growtopia_js_1 = require("growtopia.js"); 4 | const Command_1 = require("../abstracts/Command"); 5 | const DialogBuilder_1 = require("../utils/builders/DialogBuilder"); 6 | const Constants_1 = require("../utils/Constants"); 7 | const quick_db_1 = require("quick.db"); 8 | const data = new quick_db_1.QuickDB; 9 | class default_1 extends Command_1.Command { 10 | constructor() { 11 | super(); 12 | this.opt = { 13 | name: "dq", 14 | description: "Change daily quest deliver items", 15 | cooldown: 0, 16 | ratelimit: 1, 17 | category: "Basic", 18 | usage: "/dq", 19 | example: ["/dq "], 20 | permission: [Constants_1.Role.BASIC, Constants_1.Role.SUPPORTER, Constants_1.Role.DEVELOPER] 21 | }; 22 | } 23 | async execute(base, peer, text, args) { 24 | function getRandomInt(min, max) { 25 | min = Math.ceil(min); 26 | max = Math.floor(max); 27 | return Math.floor(Math.random() * (max - min)) + min; 28 | } 29 | // Example: Generate a random number between 1 and 10 (inclusive) 30 | const randomNum = getRandomInt(4, 1005); 31 | function getRandomInt1(min, max) { 32 | min = Math.ceil(min); 33 | max = Math.floor(max); 34 | return Math.floor(Math.random() * (max - min)) + min; 35 | } 36 | // Example: Generate a random number between 1 and 10 (inclusive) 37 | const randomNum2 = getRandomInt1(4, 1005); 38 | const items = base.items.metadata.items; 39 | const foundItem = items.find((item) => item.id === randomNum); 40 | const foundItem2 = items.find((item) => item.id === randomNum2); 41 | function getRandomInt3(min, max) { 42 | min = Math.ceil(min); 43 | max = Math.floor(max); 44 | return Math.floor(Math.random() * (max - min)) + min; 45 | } 46 | // Example: Generate a random number between 1 and 10 (inclusive) 47 | const randomNum3 = getRandomInt3(1, 150); 48 | function getRandomInt4(min, max) { 49 | min = Math.ceil(min); 50 | max = Math.floor(max); 51 | return Math.floor(Math.random() * (max - min)) + min; 52 | } 53 | // Example: Generate a random number between 1 and 10 (inclusive) 54 | const randomNum4 = getRandomInt4(1, 150); 55 | peer.everyPeer((p) => { 56 | const dialog = new DialogBuilder_1.DialogBuilder() 57 | .defaultColor() 58 | .addLabelWithIcon("Today's Daily Quest", 3902, "big") 59 | .addSpacer("small") 60 | .addLabelWithIcon(`<- Deliver ${randomNum3} \`2${foundItem?.name}`, randomNum, "small") 61 | .addSmallText("And") 62 | .addLabelWithIcon(`<- Deliver ${randomNum4} \`2${foundItem2?.name}`, randomNum2, "small") 63 | .addQuickExit() 64 | .str(); 65 | p.send(growtopia_js_1.Variant.from("OnDialogRequest", dialog)); 66 | p.send(growtopia_js_1.Variant.from("OnConsoleMessage", "`2New Daily Quest for today`0, `9Check with Crazy Jim for items to deliver and get a reward of 1 Growtoken!")); 67 | data.set(`dqItem1`, randomNum); 68 | data.set(`dqItem2`, randomNum2); 69 | data.set(`dqCount1`, randomNum3); 70 | data.set(`dqCount2`, randomNum4); 71 | // remove those who have dqCompleted on 72 | data.set(`dqCompleted`, false); 73 | }); 74 | } 75 | } 76 | exports.default = default_1; 77 | -------------------------------------------------------------------------------- /dist/commands/Event.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const growtopia_js_1 = require("growtopia.js"); 4 | const Command_1 = require("../abstracts/Command"); 5 | const Constants_1 = require("../utils/Constants"); 6 | const quick_db_1 = require("quick.db"); 7 | const data = new quick_db_1.QuickDB; 8 | class default_1 extends Command_1.Command { 9 | constructor() { 10 | super(); 11 | this.opt = { 12 | name: "event", 13 | description: "Start a new world event.", 14 | cooldown: 0, 15 | ratelimit: 1, 16 | category: "Basic", 17 | usage: "/event", 18 | example: ["/event"], 19 | permission: [Constants_1.Role.BASIC, Constants_1.Role.SUPPORTER, Constants_1.Role.DEVELOPER] 20 | }; 21 | } 22 | async execute(base, peer, text, args) { 23 | peer.everyPeer((p) => { 24 | p.send(growtopia_js_1.Variant.from("OnTextOverlay", "`2Starting Event...!")); 25 | data.set(`onEvent_${peer.data.world}`, true); 26 | }); 27 | } 28 | } 29 | exports.default = default_1; 30 | -------------------------------------------------------------------------------- /dist/commands/Find.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const growtopia_js_1 = require("growtopia.js"); 4 | const Command_1 = require("../abstracts/Command"); 5 | const DialogBuilder_1 = require("../utils/builders/DialogBuilder"); 6 | const Constants_1 = require("../utils/Constants"); 7 | class default_1 extends Command_1.Command { 8 | constructor() { 9 | super(); 10 | this.opt = { 11 | name: "find", 12 | description: "Find some items", 13 | cooldown: 5, 14 | ratelimit: 5, 15 | category: "Basic", 16 | usage: "/find", 17 | example: ["/find"], 18 | permission: [Constants_1.Role.BASIC, Constants_1.Role.SUPPORTER, Constants_1.Role.DEVELOPER] 19 | }; 20 | } 21 | async execute(base, peer, text, args) { 22 | let dialog = new DialogBuilder_1.DialogBuilder() 23 | .defaultColor() 24 | .addLabelWithIcon("Find the item", "6016", "big") 25 | .addCheckbox("seed_only", "Only seed", "not_selected") 26 | .addInputBox("find_item_name", "", "", 30) 27 | .addQuickExit() 28 | .endDialog("find_item", "Cancel", "Find") 29 | .str(); 30 | peer.send(growtopia_js_1.Variant.from("OnDialogRequest", dialog)); 31 | } 32 | } 33 | exports.default = default_1; 34 | -------------------------------------------------------------------------------- /dist/commands/GiveGems.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const growtopia_js_1 = require("growtopia.js"); 4 | const Command_1 = require("../abstracts/Command"); 5 | const Constants_1 = require("../utils/Constants"); 6 | const Utils_1 = require("../utils/Utils"); 7 | class default_1 extends Command_1.Command { 8 | constructor() { 9 | super(); 10 | this.opt = { 11 | name: "givegems", 12 | description: "Give gems to someone or self", 13 | cooldown: 5, 14 | ratelimit: 5, 15 | category: "Developer", 16 | usage: "/givegems ", 17 | example: ["/givegems 100", "/givegems 100 JadlionHD"], 18 | permission: [Constants_1.Role.DEVELOPER] 19 | }; 20 | } 21 | async execute(base, peer, text, args) { 22 | if (!args[0]) 23 | return peer.send(growtopia_js_1.Variant.from("OnConsoleMessage", `Gems amount are required.`)); 24 | if (!/\d/.test(args[0])) 25 | return peer.send(growtopia_js_1.Variant.from("OnConsoleMessage", `Gems amount are must be a number.`)); 26 | if (args.length > 1) { 27 | const targetPeer = (0, Utils_1.find)(base, base.cache.users, (user) => user.data.tankIDName.toLowerCase().includes(args[1].toLowerCase())); 28 | if (!targetPeer) 29 | return peer.send(growtopia_js_1.Variant.from("OnConsoleMessage", `Make sure that player is online.`)); 30 | targetPeer.send(growtopia_js_1.Variant.from("OnSetBux", parseInt(args[0]))); 31 | targetPeer.data.gems = parseInt(args[0]); 32 | targetPeer.saveToCache(); 33 | targetPeer.saveToDatabase(); 34 | peer.send(growtopia_js_1.Variant.from("OnConsoleMessage", `Sucessfully sending \`w${args[0]}\`\` gems to ${targetPeer.name}`)); 35 | } 36 | else { 37 | peer.send(growtopia_js_1.Variant.from("OnSetBux", parseInt(args[0]))); 38 | peer.data.gems = parseInt(args[0]); 39 | peer.saveToCache(); 40 | // peer.saveToDatabase(); 41 | peer.send(growtopia_js_1.Variant.from("OnConsoleMessage", `Sucessfully received \`w${args[0]}\`\` gems.`)); 42 | } 43 | } 44 | } 45 | exports.default = default_1; 46 | -------------------------------------------------------------------------------- /dist/commands/Help.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const growtopia_js_1 = require("growtopia.js"); 4 | const Command_1 = require("../abstracts/Command"); 5 | const DialogBuilder_1 = require("../utils/builders/DialogBuilder"); 6 | const Constants_1 = require("../utils/Constants"); 7 | class default_1 extends Command_1.Command { 8 | constructor() { 9 | super(); 10 | this.opt = { 11 | name: "help", 12 | description: "Shows every available commands", 13 | cooldown: 5, 14 | ratelimit: 5, 15 | category: "Basic", 16 | usage: "/help ", 17 | example: ["/help", "/help ping"], 18 | permission: [Constants_1.Role.BASIC, Constants_1.Role.SUPPORTER, Constants_1.Role.DEVELOPER] 19 | }; 20 | } 21 | async execute(base, peer, text, args) { 22 | if (args.length > 0) { 23 | if (!base.commands.has(args[0])) 24 | return peer.send(growtopia_js_1.Variant.from("OnConsoleMessage", `It seems that commands doesn't exist.`)); 25 | let cmd = base.commands.get(args[0]); 26 | let dialog = new DialogBuilder_1.DialogBuilder() 27 | .defaultColor() 28 | .addLabelWithIcon(cmd?.opt.name, "32", "small") 29 | .addSpacer("small") 30 | .addSmallText(`Description: ${cmd?.opt.description}`) 31 | .addSmallText(`Cooldown: ${cmd?.opt.cooldown}`) 32 | .addSmallText(`Ratelimit: ${cmd?.opt.ratelimit}`) 33 | .addSmallText(`Permissions: ${cmd?.opt.permission.length ? cmd.opt.permission : "None"}`) 34 | .addSmallText(`Usage: ${cmd?.opt.usage}`) 35 | .addSmallText(`Example: ${cmd?.opt.example.join(", ")}`) 36 | .endDialog("help_end", "", "Ok") 37 | .addQuickExit(); 38 | return peer.send(growtopia_js_1.Variant.from("OnDialogRequest", dialog.str())); 39 | } 40 | let dialog = new DialogBuilder_1.DialogBuilder() 41 | .defaultColor() 42 | .addLabelWithIcon("Help", "32", "small") 43 | .addSpacer("small"); 44 | base.commands.forEach((cmd) => { 45 | dialog.addLabelWithIcon(cmd.opt.usage, "482", "small"); 46 | }); 47 | dialog.endDialog("help_end", "", "Ok"); 48 | dialog.addQuickExit(); 49 | peer.send(growtopia_js_1.Variant.from("OnDialogRequest", dialog.str())); 50 | } 51 | } 52 | exports.default = default_1; 53 | -------------------------------------------------------------------------------- /dist/commands/Invis.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const growtopia_js_1 = require("growtopia.js"); 4 | const Command_1 = require("../abstracts/Command"); 5 | const Constants_1 = require("../utils/Constants"); 6 | class default_1 extends Command_1.Command { 7 | constructor() { 8 | super(); 9 | this.opt = { 10 | name: "invis", 11 | description: "Super broadcast to players online.", 12 | cooldown: 10, 13 | ratelimit: 1, 14 | category: "Basic", 15 | usage: "/invis", 16 | example: ["/invis"], 17 | permission: [Constants_1.Role.BASIC, Constants_1.Role.SUPPORTER, Constants_1.Role.DEVELOPER] 18 | }; 19 | } 20 | async execute(base, peer, text, args) { 21 | growtopia_js_1.TankTypes.SET_CHARACTER_STATE; 22 | peer.send(growtopia_js_1.Variant.from({ delay: -1 }, "OnSpawn", "spawn|avatar\n" + 23 | `netID|${peer.data.netID}\n` + 24 | `userID|${peer.data.id_user}\n` + 25 | `colrect|0|0|20|30\n` + 26 | `posXY|${peer.data.x}|${peer.data.y}\n` + 27 | `name|\`w${peer.name}\`\`\n` + 28 | `country|${peer.data.country}\n` + 29 | "invis|1\n" + 30 | "mstate|0\n" + 31 | "smstate|0\n" + 32 | "onlineID|\n")); 33 | } 34 | } 35 | exports.default = default_1; 36 | -------------------------------------------------------------------------------- /dist/commands/SB.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const growtopia_js_1 = require("growtopia.js"); 4 | const Command_1 = require("../abstracts/Command"); 5 | const Constants_1 = require("../utils/Constants"); 6 | class default_1 extends Command_1.Command { 7 | constructor() { 8 | super(); 9 | this.opt = { 10 | name: "sb", 11 | description: "Super broadcast to players online.", 12 | cooldown: 10, 13 | ratelimit: 1, 14 | category: "Basic", 15 | usage: "/sb", 16 | example: ["/sb"], 17 | permission: [Constants_1.Role.BASIC, Constants_1.Role.SUPPORTER, Constants_1.Role.DEVELOPER] 18 | }; 19 | } 20 | async execute(base, peer, text, args) { 21 | let gemsLeft = peer.data.gems - 1000; 22 | const broadcastMessage = args.join(" "); 23 | if (peer.data.gems < 1000) 24 | return peer.send(growtopia_js_1.Variant.from("OnConsoleMessage", "Could'nt broadcast, not enough gems.")); 25 | if (!args[0]) 26 | return peer.send(growtopia_js_1.Variant.from("OnConsoleMessage", "Could'nt broadcast, try again with interesting words.")); 27 | peer.send(growtopia_js_1.Variant.from("OnConsoleMessage", `** \`pSuper-Broadcast \`0from ${peer.data.tankIDName} (in \`o${peer.data.world}\`0) **: \`#${broadcastMessage}`)); 28 | peer.send(growtopia_js_1.Variant.from("OnSetBux", parseInt(`${gemsLeft}`))); 29 | peer.data.gems = parseInt(`${gemsLeft}`); 30 | peer.saveToCache(); 31 | peer.saveToDatabase(); 32 | } 33 | } 34 | exports.default = default_1; 35 | -------------------------------------------------------------------------------- /dist/commands/Warp.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const growtopia_js_1 = require("growtopia.js"); 4 | const Command_1 = require("../abstracts/Command"); 5 | const Constants_1 = require("../utils/Constants"); 6 | class default_1 extends Command_1.Command { 7 | constructor() { 8 | super(); 9 | this.opt = { 10 | name: "warp", 11 | description: "Warp to a world, using command.", 12 | cooldown: 10, 13 | ratelimit: 1, 14 | category: "Basic", 15 | usage: "/warp", 16 | example: ["/warp "], 17 | permission: [Constants_1.Role.BASIC, Constants_1.Role.SUPPORTER, Constants_1.Role.DEVELOPER] 18 | }; 19 | } 20 | async execute(base, peer, text, args) { 21 | const inapp = ["fuck", "porn", "dick", "pussy", "vargina", "kontol", "memek"]; 22 | if (!args[0]) 23 | return peer.send(growtopia_js_1.Variant.from("OnConsoleMessage", "Please mention a world that is vaild.")); 24 | if (args[0].match(/\W+|_|EXIT/gi) || args[0].match("fuck") || args[0].match("porn") || args[0].match("dick") || args[0].match("pussy") || args[0].match("vargina") || args[0].match("kontol") || args[0].match("dick")) 25 | return peer.send(growtopia_js_1.Variant.from("OnConsoleMessage", "Please mention a world that is vaild.")); 26 | peer.enterWorld(args[0]); 27 | return peer.send(growtopia_js_1.Variant.from("OnConsoleMessage", "Entering world >>> " + args[0] + "...")); 28 | } 29 | } 30 | exports.default = default_1; 31 | -------------------------------------------------------------------------------- /dist/commands/pv.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const growtopia_js_1 = require("growtopia.js"); 4 | const Command_1 = require("../abstracts/Command"); 5 | const Constants_1 = require("../utils/Constants"); 6 | const Utils_1 = require("../utils/Utils"); 7 | const DialogBuilder_1 = require("../utils/builders/DialogBuilder"); 8 | class default_1 extends Command_1.Command { 9 | constructor() { 10 | super(); 11 | this.opt = { 12 | name: "punishview", 13 | description: "Ban/Mute/Warn user", 14 | cooldown: 5, 15 | ratelimit: 5, 16 | category: "Developer", 17 | usage: "/punishview ", 18 | example: ["/givegems 100", "/givegems 100 JadlionHD"], 19 | permission: [Constants_1.Role.DEVELOPER] 20 | }; 21 | } 22 | async execute(base, peer, text, args) { 23 | if (!args[0]) 24 | return; 25 | const targetPeer = (0, Utils_1.find)(base, base.cache.users, (user) => user.data.tankIDName.toLowerCase().includes(args[0].toLowerCase())); 26 | if (!targetPeer) 27 | return peer.send(growtopia_js_1.Variant.from("OnConsoleMessage", `Make sure that player is online.`)); 28 | let p; 29 | if (targetPeer.data.role === "1") 30 | p = "Developer"; 31 | if (targetPeer.data.role === "2") 32 | p = "Basic"; 33 | if (targetPeer.data.role === "3") 34 | p = "Supporter"; 35 | let dialog = new DialogBuilder_1.DialogBuilder() 36 | .defaultColor() 37 | .addLabelWithIcon("Editing " + targetPeer.name + ` #${targetPeer.data.id_user}`, "32", "small") 38 | .addSpacer("small") 39 | .addSmallText("`bAccount information:") 40 | .addSmallText(`[!] Raw name: ${targetPeer.data.tankIDName}`) 41 | .addSmallText(`[!] UserID: #${targetPeer.data.id_user}`) 42 | .addSmallText(`[!] NetID: ${targetPeer.data.netID}`) 43 | .addSmallText(`[!] Country: ${targetPeer.data.country}`) 44 | .addSmallText(`[!] Gems: ${targetPeer.data.gems}`) 45 | .addSmallText(`[!] Role: ${p}`) 46 | .addSmallText(`[!] Current world: ${targetPeer.data.world}`) 47 | .addSpacer("big") 48 | .addCustomBreak() 49 | .addButtonWithIcon("ban_users", "732", " Ban ") 50 | .addButtonWithIcon("curse_user", "278", " Curse ") 51 | .addButtonWithIcon("mute_user", "408", "Duct tape") 52 | .addButtonWithIcon("warn_user", "1432", " Warn user") 53 | .addCustomBreak() 54 | .addSpacer("small") 55 | .addInputBox("time", "Time:", "In minutes.", 15) 56 | .addInputBox("reason", "Reason:", "", 25) 57 | .addSpacer("small") 58 | .addSmallText("`4(This is only for warning user, DO NOT ABUSE!)") 59 | .addInputBox("warning", "Warning:", "", 30) 60 | .addSpacer("small") 61 | .endDialog("ban_user", "Cancel", "Ok") 62 | .str(); 63 | peer.send(growtopia_js_1.Variant.from("OnDialogRequest", dialog)); 64 | } 65 | } 66 | exports.default = default_1; 67 | -------------------------------------------------------------------------------- /dist/database/db.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | exports.Database = void 0; 7 | const knex_1 = __importDefault(require("knex")); 8 | const Utils_1 = require("../utils/Utils"); 9 | class Database { 10 | constructor() { 11 | this.knex = (0, knex_1.default)({ 12 | client: "better-sqlite3", 13 | connection: { 14 | filename: "./data/dev.db" 15 | }, 16 | log: { 17 | error(m) { 18 | console.log(m); 19 | } 20 | }, 21 | useNullAsDefault: true 22 | }); 23 | } 24 | async getUser(username) { 25 | let res = await this.knex.select("*").from("users").where({ name: username }); 26 | if (res.length) 27 | return res[0]; 28 | else 29 | return undefined; 30 | } 31 | async saveUser(data) { 32 | if (!data.id_user) 33 | return; 34 | let res = await this.knex("users") 35 | .where({ id_user: data.id_user }) 36 | .update({ 37 | inventory: Buffer.from(JSON.stringify(data.inventory)), 38 | clothing: Buffer.from(JSON.stringify(data.clothing)), 39 | gems: data.gems 40 | }, []); 41 | if (res.length) 42 | return true; 43 | else 44 | return undefined; 45 | } 46 | async createUser(username, password) { 47 | const encPass = (0, Utils_1.encrypt)(password); 48 | let res = await this.knex("users").insert({ name: username, password: encPass, role: "1" }); 49 | if (res.length) 50 | return res[0]; 51 | else 52 | return undefined; 53 | } 54 | async getWorld(name) { 55 | let res = await this.knex.select("*").from("worlds").where({ name }); 56 | if (res.length) { 57 | // Parse buffer to json 58 | res[0].dropped = res[0].dropped 59 | ? JSON.parse(res[0].dropped.toString()) 60 | : { uid: 0, items: [] }; 61 | return res[0]; 62 | } 63 | else 64 | return undefined; 65 | } 66 | async saveWorld({ name, ownedBy = null, blockCount, blocks, width, height, owner, dropped, }) { 67 | if (!name && !blockCount && !blocks && !width && !height) 68 | return; 69 | let res = await this.knex("worlds").insert({ 70 | name: name, 71 | ownedBy: ownedBy ? ownedBy : null, 72 | blockCount, 73 | width, 74 | height, 75 | blocks, 76 | owner, 77 | dropped 78 | }); 79 | if (res.length) 80 | return true; 81 | else 82 | return undefined; 83 | } 84 | async updateWorld({ name, ownedBy = null, blockCount, blocks, width, height, owner, dropped }) { 85 | if (!name && !blockCount && !blocks && !width && !height) 86 | return; 87 | let res = await this.knex("worlds") 88 | .where({ name }) 89 | .update({ 90 | ownedBy: ownedBy ? ownedBy : null, 91 | blockCount, 92 | width, 93 | height, 94 | blocks, 95 | owner, 96 | dropped, 97 | }, []); 98 | if (res.length) 99 | return res[0]; 100 | else 101 | return undefined; 102 | } 103 | } 104 | exports.Database = Database; 105 | -------------------------------------------------------------------------------- /dist/dialogs/BanUser.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const growtopia_js_1 = require("growtopia.js"); 4 | const Dialog_1 = require("../abstracts/Dialog"); 5 | class default_1 extends Dialog_1.Dialog { 6 | constructor() { 7 | super(); 8 | this.config = { 9 | dialogName: "ban_user" 10 | }; 11 | } 12 | handle(base, peer, db, action) { 13 | if (!action.time) 14 | return peer.send(growtopia_js_1.Variant.from("OnTextOverlay", "Could not specify time of ban.")); 15 | if (!action.reason) 16 | return peer.send(growtopia_js_1.Variant.from("OnTextOverlay", "Could not specify time of ban.")); 17 | //if(!action.buttonClicked) return; 18 | if (action.buttonClicked === "ban_users") { 19 | peer.send(growtopia_js_1.Variant.from("OnAddNotification", "", "Warning from `4System`0: You've been `4BANNED `0from GrowJS for " + action.time + "days.")); 20 | //peer.disconnect() 21 | peer.data.clothing?.mask == 408; 22 | peer.sendClothes(); 23 | } 24 | else { 25 | return; 26 | } 27 | } 28 | } 29 | exports.default = default_1; 30 | -------------------------------------------------------------------------------- /dist/dialogs/Carnival.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const growtopia_js_1 = require("growtopia.js"); 4 | const Dialog_1 = require("../abstracts/Dialog"); 5 | const DialogBuilder_1 = require("../utils/builders/DialogBuilder"); 6 | const quick_db_1 = require("quick.db"); 7 | const data = new quick_db_1.QuickDB; 8 | class default_1 extends Dialog_1.Dialog { 9 | constructor() { 10 | super(); 11 | this.config = { 12 | dialogName: "ring_master" 13 | }; 14 | } 15 | async handle(base, peer, db, action) { 16 | // 17 | const OnQuest = await data.get(`OnQuest_${peer.data.id_user}`); 18 | /** 19 | * Randomiser 20 | */ 21 | function shuffleArray(array) { 22 | const shuffledArray = [...array]; 23 | for (let i = shuffledArray.length - 1; i > 0; i--) { 24 | const j = Math.floor(Math.random() * (i + 1)); 25 | [shuffledArray[i], shuffledArray[j]] = [shuffledArray[j], shuffledArray[i]]; 26 | } 27 | return shuffledArray[0]; // Return the first (random) item 28 | } 29 | // Example usage: 30 | const deliverItems = ["Dirts", "World Locks", "Fire Escape", "Buffalo", "Diamond Wings", "Blazing Electro Wings", "Diamond Diaper"]; 31 | const randomItem = shuffleArray(deliverItems); 32 | //console.log(randomItem); // Log the randomly selected item 33 | /**Random num */ 34 | function getRandomInt(min, max) { 35 | min = Math.ceil(min); 36 | max = Math.floor(max); 37 | return Math.floor(Math.random() * (max - min)) + min; 38 | } 39 | // Example: Generate a random number between 1 and 10 (inclusive) 40 | const randomNum = getRandomInt(1, 200); 41 | if (action.buttonClicked === "ring_masters") { 42 | console.log("Clicked!"); 43 | const items = peer.data.inventory?.items; 44 | if (items) { 45 | //const itemNameToFind = 'SpecificItemName'; // Replace with the name of the item you want to find 46 | const foundItem = items.find(item => item.id === 1898); 47 | const amount = items.find(item => item.amount === 10); 48 | if (foundItem && amount) { 49 | const dialog = new DialogBuilder_1.DialogBuilder() 50 | .defaultColor() 51 | .addLabelWithIcon(`\`9Quest For The Ring`, 1900, "big") 52 | .addSmallText(`(Step 1/1)`) 53 | .addSpacer("small") 54 | .addSmallText(`Your task is to bring me ${randomNum} of them ${randomItem} things!`) 55 | .addSpacer("small") 56 | .addSmallText(`(Current progress 0/${randomNum})`) 57 | .addButton("deliver", `\`9Deliver ${randomNum} ${randomItem}`) 58 | .addButton("giveup", "\`9Give up this quest") 59 | .addSpacer("small") 60 | .addSmallText("If you had 10 rings of the same type maybe we could have made a deal...") 61 | .addSpacer("small") 62 | .endDialog("noob", "Goodbye", "") 63 | .str(); 64 | peer.send(growtopia_js_1.Variant.from("OnDialogRequest", dialog)); 65 | data.set(`OnQuest_${peer.data.id_user}`, true); 66 | data.set(`Item_${peer.data.id_user}`, `${randomItem}`); 67 | data.set(`Count_${peer.data.id_user}`, `${randomNum}`); 68 | } 69 | } 70 | } 71 | } 72 | } 73 | exports.default = default_1; 74 | -------------------------------------------------------------------------------- /dist/dialogs/DQend.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const growtopia_js_1 = require("growtopia.js"); 4 | const Dialog_1 = require("../abstracts/Dialog"); 5 | const quick_db_1 = require("quick.db"); 6 | const data = new quick_db_1.QuickDB; 7 | class default_1 extends Dialog_1.Dialog { 8 | constructor() { 9 | super(); 10 | this.config = { 11 | dialogName: "crazy_jims" 12 | }; 13 | } 14 | async handle(base, peer, db, action) { 15 | if (action.buttonClicked === "turn_in") { 16 | peer.send(growtopia_js_1.Variant.from("OnAddNotification", peer.data.netID, "Received 1 `2Growtoken`0!")); 17 | peer.addItemInven(1486, 1); 18 | peer.inventory(); 19 | peer.saveToCache(); 20 | data.set(`dqCompleted`, true); 21 | } 22 | } 23 | } 24 | exports.default = default_1; 25 | -------------------------------------------------------------------------------- /dist/dialogs/DailyQuest.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const growtopia_js_1 = require("growtopia.js"); 4 | const Dialog_1 = require("../abstracts/Dialog"); 5 | const DialogBuilder_1 = require("../utils/builders/DialogBuilder"); 6 | const quick_db_1 = require("quick.db"); 7 | const data = new quick_db_1.QuickDB; 8 | class default_1 extends Dialog_1.Dialog { 9 | constructor() { 10 | super(); 11 | this.config = { 12 | dialogName: "crazy_jim" 13 | }; 14 | } 15 | async handle(base, peer, db, action) { 16 | const dqItem1 = await data.get(`dqItem1`); 17 | const dqItem2 = await data.get(`dqItem2`); 18 | const dqCount1 = await data.get(`dqCount1`); 19 | const dqCount2 = await data.get(`dqCount2`); 20 | const dqCompleted = await data.get(`dqCompleted`); 21 | const items = base.items.metadata.items; 22 | const peerInv = peer.data.inventory?.items; 23 | const foundItem = items.find((item) => item.id === dqItem1); 24 | const foundItem2 = items.find((item) => item.id === dqItem2); 25 | // Vaildation 26 | const peerHave = peerInv?.find(item => item.id === dqItem1); 27 | //const amount = peerInv?.find(item => item.amount === dqCount1) 28 | const peerHave2 = peerInv?.find(item => item.id === dqItem2); 29 | // const amount2 = peerInv?.find(item => item.amount === dqCount2) 30 | let i; 31 | if (peerHave?.amount === undefined && peerHave2?.amount === undefined) 32 | i = 0; 33 | if (action.buttonClicked === "dq") { 34 | let dialog = new DialogBuilder_1.DialogBuilder() 35 | .defaultColor() 36 | .addLabelWithIcon("Crazy Jim's Daily Quest", "3902", "big") 37 | .addSmallText("I guess some people call me Crazy Jim because I'am a bit of a hoarder. But I'm very particular about what I want! And today, what I want is this:") 38 | .addLabelWithIcon(`\`2${dqCount1} ${foundItem?.name}`, `${dqItem1}`, "small") 39 | .addSmallText("and") 40 | .addLabelWithIcon(`\`2${dqCount2} ${foundItem2?.name}`, `${dqItem2}`, "small") 41 | .addSpacer("small") 42 | .addSmallText("You shave all that through the phone (It works, I've tried it), and I will hand you one of the `2Growtokens `0from my personal collection! But hurry, this offer is only good until midnight, and only one `2Growtoken `0per person.") 43 | .addSpacer("small") 44 | .addSmallText(`\`8(You have ${peerHave?.amount !== undefined ? peerHave.amount : 0} ${foundItem?.name} and ${peerHave2?.amount !== undefined ? peerHave2.amount : 0} ${foundItem2?.name})`); 45 | if (peerHave?.amount == dqCount1 && peerHave2?.amount == dqCount2 && dqCompleted === false) { 46 | dialog.addButton("turn_in", "Turn in!"); 47 | } 48 | if (dqCompleted === true) { 49 | dialog.addSmallText("`4(You have completed today's Daily Quest task, come back tommorrow)"); 50 | } 51 | dialog.endDialog("crazy_jims", "Hang Up", "Back"); 52 | //.str() 53 | peer.send(growtopia_js_1.Variant.from("OnDialogRequest", dialog.str())); 54 | } 55 | } 56 | } 57 | exports.default = default_1; 58 | -------------------------------------------------------------------------------- /dist/dialogs/DoorEdit.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const Dialog_1 = require("../abstracts/Dialog"); 4 | const BlockPlacing_1 = require("../tanks/BlockPlacing"); 5 | class default_1 extends Dialog_1.Dialog { 6 | constructor() { 7 | super(); 8 | this.config = { 9 | dialogName: "door_edit" 10 | }; 11 | } 12 | handle(base, peer, db, action) { 13 | const world = peer.hasWorld(peer.data.world); 14 | const pos = parseInt(action.tilex) + parseInt(action.tiley) * world?.data.width; 15 | const block = world?.data.blocks[pos]; 16 | const itemMeta = base.items.metadata.items.find((i) => i.id === parseInt(action.itemID)); 17 | if (world?.data.owner) { 18 | if (world?.data.owner.id !== peer.data.id_user) 19 | return; 20 | } 21 | block.door.label = action.label || ""; 22 | block.door.destination = action.target?.toUpperCase() || ""; 23 | block.door.id = action.id?.toUpperCase() || ""; 24 | (0, BlockPlacing_1.tileUpdate)(base, peer, itemMeta?.type, block, world); 25 | } 26 | } 27 | exports.default = default_1; 28 | -------------------------------------------------------------------------------- /dist/dialogs/DropEnd.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const growtopia_js_1 = require("growtopia.js"); 4 | const Dialog_1 = require("../abstracts/Dialog"); 5 | class default_1 extends Dialog_1.Dialog { 6 | constructor() { 7 | super(); 8 | this.config = { 9 | dialogName: "drop_end" 10 | }; 11 | } 12 | handle(base, peer, db, action) { 13 | if (!/\d/.test(action.drop_count) || !/\d/.test(action.itemID)) { 14 | return peer.send(growtopia_js_1.Variant.from("OnTalkBubble", peer.data.netID, "Uh oh, thats not a valid number")); 15 | } 16 | const itemID = parseInt(action.itemID); 17 | const count = parseInt(action.drop_count); 18 | const itemExist = peer.data.inventory?.items.find((i) => i.id === itemID); 19 | if (!itemExist || itemExist.amount <= 0) { 20 | return peer.send(growtopia_js_1.Variant.from("OnTalkBubble", peer.data.netID, "That item, seems not exist in your inventory")); 21 | } 22 | if (count > itemExist.amount) { 23 | return peer.send(growtopia_js_1.Variant.from("OnTalkBubble", peer.data.netID, "Really?")); 24 | } 25 | if (count <= 0) { 26 | return peer.send(growtopia_js_1.Variant.from("OnTalkBubble", peer.data.netID, "Nice try. You remind me of myself at that age.")); 27 | } 28 | peer.drop(itemID, count); 29 | peer.removeItemInven(itemID, count); 30 | peer.inventory(); 31 | peer.sendClothes(); 32 | } 33 | } 34 | exports.default = default_1; 35 | -------------------------------------------------------------------------------- /dist/dialogs/FindItem.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const growtopia_js_1 = require("growtopia.js"); 4 | const Dialog_1 = require("../abstracts/Dialog"); 5 | const DialogBuilder_1 = require("../utils/builders/DialogBuilder"); 6 | class default_1 extends Dialog_1.Dialog { 7 | constructor() { 8 | super(); 9 | this.config = { 10 | dialogName: "find_item" 11 | }; 12 | } 13 | handle(base, peer, db, action) { 14 | const isSeed = parseInt(action.seed_only) ? true : false; 15 | let dialog = new DialogBuilder_1.DialogBuilder() 16 | .defaultColor() 17 | .addQuickExit() 18 | .addLabelWithIcon("Find the item", "6016", "big") 19 | .addSpacer("small"); 20 | const items = base.items.metadata.items.filter((v) => v.name?.toLowerCase().includes(action.find_item_name.toLowerCase())); 21 | items.forEach((item) => { 22 | if (isSeed) { 23 | if (item.id % 2 === 1) 24 | dialog.addButtonWithIcon(item.id, item.id, item.name, "staticBlueFrame", item.id); 25 | } 26 | else { 27 | if (item.id % 2 === 0) 28 | dialog.addButtonWithIcon(item.id, item.id, item.name, "staticBlueFrame", item.id); 29 | } 30 | }); 31 | // fix spacing dialog later 32 | // dialog.addSpacer("big"); 33 | dialog.endDialog("find_item_end", "Cancel", ""); 34 | // console.log(dialog.str()); 35 | peer.send(growtopia_js_1.Variant.from("OnDialogRequest", dialog.str())); 36 | } 37 | } 38 | exports.default = default_1; 39 | -------------------------------------------------------------------------------- /dist/dialogs/FindItemEnd.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const growtopia_js_1 = require("growtopia.js"); 4 | const Dialog_1 = require("../abstracts/Dialog"); 5 | class default_1 extends Dialog_1.Dialog { 6 | constructor() { 7 | super(); 8 | this.config = { 9 | dialogName: "find_item_end" 10 | }; 11 | } 12 | handle(base, peer, db, action) { 13 | const itemID = parseInt(action.buttonClicked); 14 | peer.data.inventory?.items.push({ id: itemID, amount: 200 }); 15 | peer.send(growtopia_js_1.Variant.from("OnConsoleMessage", `Added \`6${base.items.metadata.items.find((v) => v.id === itemID)?.name}\`\` to your inventory.`)); 16 | peer.inventory(); 17 | peer.saveToCache(); 18 | // peer.saveToDatabase(); 19 | } 20 | } 21 | exports.default = default_1; 22 | -------------------------------------------------------------------------------- /dist/dialogs/Noob.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const growtopia_js_1 = require("growtopia.js"); 4 | const Dialog_1 = require("../abstracts/Dialog"); 5 | const quick_db_1 = require("quick.db"); 6 | const data = new quick_db_1.QuickDB; 7 | class default_1 extends Dialog_1.Dialog { 8 | constructor() { 9 | super(); 10 | this.config = { 11 | dialogName: "noob" 12 | }; 13 | } 14 | async handle(base, peer, db, action) { 15 | //const items = peer.data.inventory?.items 16 | if (action.buttonClicked === "deliver") { 17 | const items = peer.data.inventory?.items; 18 | const DataItem = await data.get(`Item_${peer.data.id_user}`); 19 | console.log(DataItem); 20 | const Count = await data.get(`Count_${peer.data.id_user}`); 21 | console.log(Count); 22 | let i; 23 | if (DataItem === "Dirts") 24 | i = 2; 25 | if (DataItem === "World Locks") 26 | i = 242; 27 | if (DataItem === "Fire Escape") 28 | i = 998; 29 | if (DataItem === "Buffalo") 30 | i = 1044; 31 | if (DataItem === "Diamond Wings") 32 | i = 1938; 33 | if (DataItem === "Blazing Electro Wings") 34 | i = 1936; 35 | if (DataItem === "Diamond Diaper") 36 | i = 1944; 37 | // Vaild Data 38 | const foundItem = items?.find(item => item.id === i); 39 | const amount = items?.find(item => item.amount === Count); 40 | if (!foundItem && !amount) { 41 | return peer.send(growtopia_js_1.Variant.from("OnTextOverlay", "Get to work!")); 42 | } 43 | /// if(foundItem && amount){ 44 | // Reward 45 | function shuffleArray(array) { 46 | const shuffledArray = [...array]; 47 | for (let i = shuffledArray.length - 1; i > 0; i--) { 48 | const j = Math.floor(Math.random() * (i + 1)); 49 | [shuffledArray[i], shuffledArray[j]] = [shuffledArray[j], shuffledArray[i]]; 50 | } 51 | return shuffledArray[0]; // Return the first (random) item 52 | } 53 | // Example usage: 54 | const deliverItems = ["Gemini Ring", "Ring Of Winds", "Ring Of Force", "Ring Of Water"]; 55 | const randomItem = shuffleArray(deliverItems); 56 | console.log(randomItem); 57 | let ok; 58 | if (randomItem === "Gemini Ring") 59 | ok = 1986; 60 | if (randomItem === "Ring Of Winds") 61 | ok = 1876; 62 | if (randomItem === "Ring Of Force") 63 | ok = 1874; 64 | if (randomItem === "Ring Of Water") 65 | ok = 2970; 66 | data.set(`OnQuest_${peer.data.id_user}`, false); 67 | peer.send(growtopia_js_1.Variant.from("OnAddNotification", 200, "Congratulations! You got " + randomItem)); 68 | //peer.data.inventory?.items.push({ id: i!, amount: Count }); 69 | peer.addItemInven(ok, 1); 70 | //peer.sendClothes() 71 | peer.inventory(); 72 | peer.saveToCache(); 73 | //} 74 | } 75 | if (action.buttonClicked === "giveup") { 76 | data.set(`OnQuest_${peer.data.id_user}`, false); 77 | } 78 | //peer.send(Variant.from("OnTextOverlay", "Goodbye!")) 79 | } 80 | } 81 | exports.default = default_1; 82 | -------------------------------------------------------------------------------- /dist/dialogs/SignEdit.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const Dialog_1 = require("../abstracts/Dialog"); 4 | const BlockPlacing_1 = require("../tanks/BlockPlacing"); 5 | class default_1 extends Dialog_1.Dialog { 6 | constructor() { 7 | super(); 8 | this.config = { 9 | dialogName: "sign_edit" 10 | }; 11 | } 12 | handle(base, peer, db, action) { 13 | const world = peer.hasWorld(peer.data.world); 14 | const pos = parseInt(action.tilex) + parseInt(action.tiley) * world?.data.width; 15 | const block = world?.data.blocks[pos]; 16 | const itemMeta = base.items.metadata.items.find((i) => i.id === parseInt(action.itemID)); 17 | if (world?.data.owner) { 18 | if (world.data.owner.id !== peer.data.id_user) 19 | return; 20 | } 21 | block.sign.label = action.label || ""; 22 | (0, BlockPlacing_1.tileUpdate)(base, peer, itemMeta?.type, block, world); 23 | } 24 | } 25 | exports.default = default_1; 26 | -------------------------------------------------------------------------------- /dist/dialogs/Telephone.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const growtopia_js_1 = require("growtopia.js"); 4 | const Dialog_1 = require("../abstracts/Dialog"); 5 | const DialogBuilder_1 = require("../utils/builders/DialogBuilder"); 6 | class default_1 extends Dialog_1.Dialog { 7 | constructor() { 8 | super(); 9 | this.config = { 10 | dialogName: "phone" 11 | }; 12 | } 13 | handle(base, peer, db, action) { 14 | if (action.number === "12345") { 15 | let dialog = new DialogBuilder_1.DialogBuilder() 16 | .defaultColor() 17 | .addLabelWithIcon("Crazy Jim's Quest Emporium", "3902", "big") 18 | .addSmallText("HEEEEYYY there Growtopian! I'm Crazy Jim, and my quest are so crazy they're KERRRRAAAAZZY!! And that is clearly very crazy, so please, be cautions around them. What can I do ya for, partner?") 19 | .addButton("dq", "Daily Quest") 20 | .addButton("goals", "Goals") 21 | .addButton("epic_quests", "Epic Quests") 22 | .endDialog("crazy_jim", "Hang Up", "") 23 | .str(); 24 | peer.send(growtopia_js_1.Variant.from("OnDialogRequest", dialog)); 25 | } 26 | else { 27 | return peer.send(growtopia_js_1.Variant.from("OnTextOverlay", "Hmmm... wrong number, could'nt reach anyone.")); 28 | } 29 | } 30 | } 31 | exports.default = default_1; 32 | -------------------------------------------------------------------------------- /dist/dialogs/TrashEnd.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const Dialog_1 = require("../abstracts/Dialog"); 4 | class default_1 extends Dialog_1.Dialog { 5 | constructor() { 6 | super(); 7 | this.config = { 8 | dialogName: "trash_end" 9 | }; 10 | } 11 | handle(base, peer, db, action) { 12 | const itemID = parseInt(action.itemID); 13 | let invenItem = peer.data.inventory?.items.find((item) => item.id === itemID); 14 | if (!/\d/.test(action.trash_count)) 15 | return; 16 | const count = parseInt(action.trash_count); 17 | invenItem.amount = invenItem.amount - count; 18 | // Check if inventory amount is empty, then delete it. 19 | if (invenItem.amount <= 0) { 20 | peer.data.inventory.items = peer.data.inventory?.items.filter((i) => i.amount !== 0); 21 | } 22 | peer.saveToCache(); 23 | peer.inventory(); 24 | } 25 | } 26 | exports.default = default_1; 27 | -------------------------------------------------------------------------------- /dist/dialogs/Xenonite.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const growtopia_js_1 = require("growtopia.js"); 4 | const Dialog_1 = require("../abstracts/Dialog"); 5 | const quick_db_1 = require("quick.db"); 6 | const data = new quick_db_1.QuickDB; 7 | class default_1 extends Dialog_1.Dialog { 8 | constructor() { 9 | super(); 10 | this.config = { 11 | dialogName: "xeno_edit" 12 | }; 13 | } 14 | handle(base, peer, db, action) { 15 | const hit = parseInt(action.strong_hit) ? true : false; 16 | if (hit) { 17 | peer.send(growtopia_js_1.Variant.from("OnTalkBubble", peer.data.netID, "Xenonite has changed everyone's powers! `2Strong Punch granted`0!")); 18 | peer.send(growtopia_js_1.Variant.from("OnConsoleMessage", "Xenonite has changed everyone's powers! `2Strong Punch granted`0!")); 19 | // db.haveXeno({haveBuff : true}) 20 | data.set(`haveXeno_${peer.data.world}`, true); 21 | } 22 | else { 23 | data.set(`haveXeno_${peer.data.world}`, false); 24 | } 25 | } 26 | } 27 | exports.default = default_1; 28 | -------------------------------------------------------------------------------- /dist/events/Connect.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const growtopia_js_1 = require("growtopia.js"); 4 | const Listener_1 = require("../abstracts/Listener"); 5 | const Peer_1 = require("../structures/Peer"); 6 | class default_1 extends Listener_1.Listener { 7 | constructor() { 8 | super(); 9 | this.name = "connect"; 10 | } 11 | run(base, netID) { 12 | console.log("Peer", netID, "connected."); 13 | const peer = new Peer_1.Peer(base, netID); 14 | const packet = growtopia_js_1.TextPacket.from(0x1); 15 | peer.send(packet); 16 | base.cache.users.setSelf(netID, peer.data); 17 | } 18 | } 19 | exports.default = default_1; 20 | -------------------------------------------------------------------------------- /dist/events/Disconnect.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const Listener_1 = require("../abstracts/Listener"); 4 | class default_1 extends Listener_1.Listener { 5 | constructor() { 6 | super(); 7 | this.name = "disconnect"; 8 | } 9 | run(base, netID) { 10 | console.log("Peer", netID, "disconnected"); 11 | let peer = base.cache.users.getSelf(netID); 12 | peer?.leaveWorld(); 13 | peer?.saveToDatabase(); 14 | base.cache.users.delete(netID); 15 | } 16 | } 17 | exports.default = default_1; 18 | -------------------------------------------------------------------------------- /dist/structures/Collection.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.Collection = void 0; 4 | const Peer_1 = require("./Peer"); 5 | const World_1 = require("./World"); 6 | class Collection extends Map { 7 | constructor(base) { 8 | if (!base) 9 | throw new Error("Server are required."); 10 | super(); 11 | this.base = base; 12 | } 13 | getSelf(key) { 14 | const peerData = this.get(key); 15 | let peer = new Peer_1.Peer(this.base, peerData?.netID); 16 | peer.data = peerData; 17 | return peer; 18 | } 19 | setSelf(key, value) { 20 | this.set(key, value); 21 | } 22 | getWorld(key) { 23 | const worldData = this.get(key); 24 | let world = new World_1.World(this.base, worldData?.name); 25 | world.data = worldData; 26 | return world; 27 | } 28 | setWorld(key, value) { 29 | this.set(key, value); 30 | } 31 | findPeer(func) { 32 | const users = this; 33 | for (const item of users.values()) { 34 | const peer = users.getSelf(item.netID); 35 | if (func(peer)) { 36 | return peer; 37 | } 38 | } 39 | return undefined; 40 | } 41 | filterPeer(func) { 42 | const arr = []; 43 | for (const item of this.values()) { 44 | if (func(item)) { 45 | arr.push(item); 46 | } 47 | } 48 | return arr; 49 | } 50 | } 51 | exports.Collection = Collection; 52 | -------------------------------------------------------------------------------- /dist/structures/Logger.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | exports.Logger = void 0; 7 | const chalk_1 = __importDefault(require("chalk")); 8 | class Logger { 9 | constructor() { } 10 | get time() { 11 | return new Date().toLocaleString("en-US", { timeZone: "Asia/Jakarta" }); 12 | } 13 | info(...content) { 14 | console.log(`[${this.time} - INFO ]`, ...content); 15 | } 16 | ready(...content) { 17 | console.log(`[${this.time} - ${chalk_1.default.greenBright("READY")} ]`, ...content); 18 | } 19 | event(...content) { 20 | console.log(`[${this.time} - ${chalk_1.default.blueBright("EVENT")} ]`, ...content); 21 | } 22 | update(...content) { 23 | console.log(`[${this.time} - ${chalk_1.default.cyan("UPDATE")} ]`, ...content); 24 | } 25 | action(...content) { 26 | console.log(`[${this.time} - ${chalk_1.default.rgb(242, 124, 27)("ACTION")} ]`, ...content); 27 | } 28 | dialog(...content) { 29 | console.log(`[${this.time} - ${chalk_1.default.rgb(69, 214, 200)("DIALOG")} ]`, ...content); 30 | } 31 | command(...content) { 32 | console.log(`[${this.time} - ${chalk_1.default.rgb(95, 232, 150)("COMMAND")} ]`, ...content); 33 | } 34 | debug(...content) { 35 | console.log(`[${this.time} - ${chalk_1.default.rgb(211, 237, 64)("DEBUG")} ]`, ...content); 36 | } 37 | warn(...content) { 38 | console.log(`[${this.time} - ${chalk_1.default.rgb(255, 168, 18)("WARN")} ]`, ...content); 39 | } 40 | error(...content) { 41 | console.log(`[${this.time} - ${chalk_1.default.rgb(230, 68, 28)("ERROR")} ]`, ...content); 42 | } 43 | } 44 | exports.Logger = Logger; 45 | -------------------------------------------------------------------------------- /dist/structures/Webserver.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | exports.WebServer = void 0; 7 | const express_1 = __importDefault(require("express")); 8 | const node_fs_1 = require("node:fs"); 9 | const node_http_1 = __importDefault(require("node:http")); 10 | const node_https_1 = __importDefault(require("node:https")); 11 | const body_parser_1 = __importDefault(require("body-parser")); 12 | const express_rate_limit_1 = __importDefault(require("express-rate-limit")); 13 | const node_path_1 = __importDefault(require("node:path")); 14 | const app = (0, express_1.default)(); 15 | const options = { 16 | key: (0, node_fs_1.readFileSync)("./assets/ssl/server.key"), 17 | cert: (0, node_fs_1.readFileSync)("./assets/ssl/server.crt") 18 | }; 19 | const apiLimiter = (0, express_rate_limit_1.default)({ 20 | windowMs: 10800000, 21 | max: 5, 22 | message: "Too many accounts created from this IP, please try again after 3 hour", 23 | standardHeaders: true, 24 | legacyHeaders: false // Disable the `X-RateLimit-*` headers 25 | }); 26 | function WebServer(log, db) { 27 | app.use(body_parser_1.default.urlencoded({ extended: true })); 28 | app.use(body_parser_1.default.json()); 29 | app.set("view engine", "ejs"); 30 | app.set("views", node_path_1.default.join(__dirname, "../../web/views")); 31 | app.use("/growtopia/server_data.php", (req, res) => { 32 | res.send(`server|${process.env.WEB_ADDRESS}\nport|17091\ntype|1\n#maint|Maintenance woi\nmeta|lolwhat\nRTENDMARKERBS1001`); 33 | }); 34 | app.get("/register", (req, res) => { 35 | res.render("register.ejs"); 36 | }); 37 | app.post("/api/register", apiLimiter, async (req, res) => { 38 | if (req.body && req.body.username && req.body.password) { 39 | let result = await db.createUser(req.body.username, req.body.password); 40 | if (result) 41 | res.send("OK, Successfully creating account"); 42 | else 43 | res.send("Error"); 44 | } 45 | }); 46 | if (process.env.WEB_ENV === "production") { 47 | app.listen(3000, () => { 48 | log.ready(`Starting development web server on: http://${process.env.WEB_ADDRESS}:3000`); 49 | log.info(`To register account you need to register at: http://${process.env.WEB_ADDRESS}:3000/register`); 50 | }); 51 | } 52 | else if (process.env.WEB_ENV === "development") { 53 | let httpServer = node_http_1.default.createServer(app); 54 | let httpsServer = node_https_1.default.createServer(options, app); 55 | httpServer.listen(80); 56 | httpsServer.listen(443); 57 | httpsServer.on("listening", function () { 58 | log.ready(`Starting web server on: http://${process.env.WEB_ADDRESS}:80`); 59 | log.info(`To register account you need to register at: http://${process.env.WEB_ADDRESS}:80/register`); 60 | }); 61 | } 62 | } 63 | exports.WebServer = WebServer; 64 | -------------------------------------------------------------------------------- /dist/utils/Constants.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.Role = exports.Y_END_DIRT = exports.Y_LAVA_START = exports.Y_START_DIRT = exports.WORLD_SIZE = void 0; 4 | exports.WORLD_SIZE = { 5 | WIDTH: 100, 6 | HEIGHT: 60 7 | }; 8 | exports.Y_START_DIRT = 24; 9 | exports.Y_LAVA_START = 50; 10 | exports.Y_END_DIRT = 55; 11 | exports.Role = { 12 | DEVELOPER: "1", 13 | BASIC: "2", 14 | SUPPORTER: "3" 15 | }; 16 | -------------------------------------------------------------------------------- /dist/utils/Utils.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | exports.handleSaveAll = exports.decrypt = exports.encrypt = exports.hashItemsDat = exports.find = exports.parseAction = void 0; 7 | const crypto_js_1 = __importDefault(require("crypto-js")); 8 | const World_1 = require("../structures/World"); 9 | function parseAction(chunk) { 10 | let data = {}; 11 | chunk[chunk.length - 1] = 0; 12 | let str = chunk.toString("utf-8", 4); 13 | const lines = str.split("\n"); 14 | lines.forEach((line) => { 15 | if (line.startsWith("|")) 16 | line = line.slice(1); 17 | const info = line.split("|"); 18 | let key = info[0]; 19 | let val = info[1]; 20 | if (key && val) { 21 | if (val.endsWith("\x00")) 22 | val = val.slice(0, -1); 23 | data[key] = val; 24 | } 25 | }); 26 | return data; 27 | } 28 | exports.parseAction = parseAction; 29 | function find(base, users, func) { 30 | for (const item of users.values()) { 31 | const peer = users.getSelf(item.netID); 32 | if (func(peer)) { 33 | return peer; 34 | } 35 | } 36 | return undefined; 37 | } 38 | exports.find = find; 39 | function hashItemsDat(file) { 40 | let hash = 0x55555555; 41 | file.forEach((x) => (hash = (hash >>> 27) + (hash << 5) + x)); 42 | return hash >>> 0; 43 | } 44 | exports.hashItemsDat = hashItemsDat; 45 | function encrypt(data) { 46 | return crypto_js_1.default.AES.encrypt(data, process.env.ENCRYPT_SECRET).toString(); 47 | } 48 | exports.encrypt = encrypt; 49 | function decrypt(data) { 50 | return crypto_js_1.default.AES.decrypt(data, process.env.ENCRYPT_SECRET).toString(crypto_js_1.default.enc.Utf8); 51 | } 52 | exports.decrypt = decrypt; 53 | function handleSaveAll(server, dcAll = false) { 54 | server.log.warn(`Saving ${server.cache.users.size} peers & ${server.cache.worlds.size} worlds.`); 55 | const saveWorlds = () => { 56 | if (server.cache.worlds.size === 0) 57 | process.exit(); 58 | else { 59 | let o = 0; 60 | server.cache.worlds.forEach(async (wrld) => { 61 | const world = new World_1.World(server, wrld.name); 62 | if (typeof world.worldName === "string") 63 | await world.saveToDatabase(); 64 | else 65 | server.log.warn(`Oh no there's undefined (${o}) world, skipping..`); 66 | o += 1; 67 | if (o === server.cache.worlds.size) 68 | process.exit(); 69 | }); 70 | } 71 | }; 72 | if (server.cache.users.size === 0) 73 | process.exit(); 74 | else { 75 | let i = 0; 76 | server.cache.users.forEach(async (peer) => { 77 | const player = server.cache.users.getSelf(peer.netID); 78 | await player.saveToDatabase(); 79 | if (dcAll) { 80 | player.disconnect("now"); 81 | } 82 | else { 83 | // send onconsolemessage for auto saving 84 | } 85 | i += 1; 86 | if (i === server.cache.users.size) 87 | saveWorlds(); 88 | }); 89 | } 90 | } 91 | exports.handleSaveAll = handleSaveAll; 92 | -------------------------------------------------------------------------------- /dist/utils/enums/DataTypes.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.DataTypes = void 0; 4 | var DataTypes; 5 | (function (DataTypes) { 6 | DataTypes[DataTypes["HELLO"] = 1] = "HELLO"; 7 | DataTypes[DataTypes["STR"] = 2] = "STR"; 8 | DataTypes[DataTypes["ACTION"] = 3] = "ACTION"; 9 | DataTypes[DataTypes["TANK"] = 4] = "TANK"; 10 | })(DataTypes = exports.DataTypes || (exports.DataTypes = {})); 11 | -------------------------------------------------------------------------------- /dist/utils/enums/ItemTypes.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.ClothTypes = void 0; 4 | var ClothTypes; 5 | (function (ClothTypes) { 6 | ClothTypes[ClothTypes["HAIR"] = 0] = "HAIR"; 7 | ClothTypes[ClothTypes["SHIRT"] = 1] = "SHIRT"; 8 | ClothTypes[ClothTypes["PANTS"] = 2] = "PANTS"; 9 | ClothTypes[ClothTypes["FEET"] = 3] = "FEET"; 10 | ClothTypes[ClothTypes["FACE"] = 4] = "FACE"; 11 | ClothTypes[ClothTypes["HAND"] = 5] = "HAND"; 12 | ClothTypes[ClothTypes["BACK"] = 6] = "BACK"; 13 | ClothTypes[ClothTypes["MASK"] = 7] = "MASK"; 14 | ClothTypes[ClothTypes["NECKLACE"] = 8] = "NECKLACE"; 15 | ClothTypes[ClothTypes["ANCES"] = 9] = "ANCES"; 16 | })(ClothTypes = exports.ClothTypes || (exports.ClothTypes = {})); 17 | -------------------------------------------------------------------------------- /dist/utils/enums/TankTypes.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.TankTypes = void 0; 4 | var TankTypes; 5 | (function (TankTypes) { 6 | TankTypes[TankTypes["PEER_MOVE"] = 0] = "PEER_MOVE"; 7 | TankTypes[TankTypes["TILE_PUNCH"] = 3] = "TILE_PUNCH"; 8 | TankTypes[TankTypes["PEER_WORLD"] = 4] = "PEER_WORLD"; 9 | TankTypes[TankTypes["TILE_UPDATE"] = 5] = "TILE_UPDATE"; 10 | TankTypes[TankTypes["PEER_ENTER_DOOR"] = 7] = "PEER_ENTER_DOOR"; 11 | TankTypes[TankTypes["TILE_DAMAGE"] = 8] = "TILE_DAMAGE"; 12 | TankTypes[TankTypes["PEER_INVENTORY"] = 9] = "PEER_INVENTORY"; 13 | TankTypes[TankTypes["PEER_CLOTH"] = 10] = "PEER_CLOTH"; 14 | TankTypes[TankTypes["PEER_COLLECT"] = 11] = "PEER_COLLECT"; 15 | TankTypes[TankTypes["TILE_TREE"] = 12] = "TILE_TREE"; 16 | TankTypes[TankTypes["PEER_DROP"] = 14] = "PEER_DROP"; 17 | TankTypes[TankTypes["TILE_APPLY_LOCK"] = 15] = "TILE_APPLY_LOCK"; 18 | TankTypes[TankTypes["PEER_ITEMS_DAT"] = 16] = "PEER_ITEMS_DAT"; 19 | TankTypes[TankTypes["PEER_ICON"] = 18] = "PEER_ICON"; 20 | TankTypes[TankTypes["PEER_PING_RESPONSE"] = 21] = "PEER_PING_RESPONSE"; 21 | TankTypes[TankTypes["PEER_PING_REQUEST"] = 22] = "PEER_PING_REQUEST"; 22 | TankTypes[TankTypes["SET_CHARACTER_STATE"] = 23] = "SET_CHARACTER_STATE"; 23 | })(TankTypes = exports.TankTypes || (exports.TankTypes = {})); 24 | -------------------------------------------------------------------------------- /json.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTPDeveloper/GrowJS-Project/8525bb8b7ece2f1878b24ce168792c12484e3bcc/json.sqlite -------------------------------------------------------------------------------- /knexfile.js: -------------------------------------------------------------------------------- 1 | // Update with your config settings. 2 | 3 | /** 4 | * @type { Object. } 5 | */ 6 | module.exports = { 7 | development: { 8 | client: "better-sqlite3", 9 | connection: { 10 | filename: "./data/dev.db" 11 | } 12 | }, 13 | 14 | staging: { 15 | client: "better-sqlite3", 16 | connection: { 17 | filename: "./data/staging.db" 18 | }, 19 | migrations: { 20 | tableName: "knex_migrations" 21 | } 22 | }, 23 | 24 | production: { 25 | client: "better-sqlite3", 26 | connection: { 27 | filename: "./data/production.db" 28 | }, 29 | migrations: { 30 | tableName: "knex_migrations" 31 | } 32 | } 33 | 34 | // staging: { 35 | // client: 'postgresql', 36 | // connection: { 37 | // database: 'my_db', 38 | // user: 'username', 39 | // password: 'password' 40 | // }, 41 | // pool: { 42 | // min: 2, 43 | // max: 10 44 | // }, 45 | // migrations: { 46 | // tableName: 'knex_migrations' 47 | // } 48 | // }, 49 | 50 | // production: { 51 | // client: 'postgresql', 52 | // connection: { 53 | // database: 'my_db', 54 | // user: 'username', 55 | // password: 'password' 56 | // }, 57 | // pool: { 58 | // min: 2, 59 | // max: 10 60 | // }, 61 | // migrations: { 62 | // tableName: 'knex_migrations' 63 | // } 64 | // } 65 | }; 66 | -------------------------------------------------------------------------------- /migrations/20230809144402_growtopia_users.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param { import("knex").Knex } knex 3 | * @returns { Promise } 4 | */ 5 | exports.up = function (knex) { 6 | return knex.schema.createTable("users", (tb) => { 7 | tb.increments("id_user").primary().notNullable(); 8 | tb.string("name", 255).notNullable(); 9 | tb.string("password", 255).notNullable(); 10 | tb.string("role", 255).notNullable(); 11 | tb.integer("gems", 11).nullable(); 12 | tb.binary("clothing").nullable(); 13 | tb.binary("inventory").nullable(); 14 | tb.timestamp("created_at", { useTz: false }).nullable(); 15 | }); 16 | }; 17 | 18 | /** 19 | * @param { import("knex").Knex } knex 20 | * @returns { Promise } 21 | */ 22 | exports.down = function (knex) { 23 | return knex.schema.dropTableIfExists("users"); 24 | }; 25 | -------------------------------------------------------------------------------- /migrations/20230809145200_growtopia_worlds.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param { import("knex").Knex } knex 3 | * @returns { Promise } 4 | */ 5 | exports.up = function (knex) { 6 | return knex.schema.createTable("worlds", (tb) => { 7 | tb.increments("id").primary().notNullable(); 8 | tb.string("name", 255).notNullable(); 9 | tb.integer("ownedBy", 11).nullable(); 10 | tb.binary("owner").nullable(); 11 | tb.integer("width", 11).notNullable(); 12 | tb.integer("height", 11).notNullable(); 13 | tb.integer("blockCount", 11).notNullable(); 14 | tb.binary("blocks").nullable(); 15 | tb.binary("dropped").nullable(); 16 | tb.timestamp("created_at", { useTz: false }).nullable(); 17 | tb.timestamp("updated_at", { useTz: false }).nullable(); 18 | }); 19 | }; 20 | 21 | /** 22 | * @param { import("knex").Knex } knex 23 | * @returns { Promise } 24 | */ 25 | exports.down = function (knex) { 26 | return knex.schema.dropTableIfExists("worlds"); 27 | }; 28 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "growserver", 3 | "version": "2.0.0", 4 | "description": "a growtopia private server", 5 | "main": "dist/app.js", 6 | "scripts": { 7 | "build": "tsc", 8 | "start": "node -r dotenv/config dist/app.js", 9 | "migrate": "knex migrate:latest", 10 | "seed": "knex seed:run", 11 | "dev": "rimraf dist && npm run build && npm start", 12 | "setup": "(node scripts/setup.js) && npm run migrate && npm run seed && echo Setup Completed" 13 | }, 14 | "author": "JadlionHD ", 15 | "license": "MIT", 16 | "devDependencies": { 17 | "@types/crypto-js": "^4.1.1", 18 | "@types/express": "^4.17.14", 19 | "@types/node": "^18.11.9", 20 | "rimraf": "^3.0.2", 21 | "typescript": "^4.9.3" 22 | }, 23 | "dependencies": { 24 | "better-sqlite3": "^8.5.0", 25 | "body-parser": "^1.20.1", 26 | "chalk": "4.1.1", 27 | "crypto-js": "^4.1.1", 28 | "dotenv": "^16.0.3", 29 | "ejs": "^3.1.8", 30 | "express": "^4.18.2", 31 | "express-rate-limit": "^6.7.0", 32 | "growtopia.js": "^1.2.7", 33 | "itemsdat": "github:JadlionHD/itemsdat", 34 | "knex": "^2.5.1" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /scripts/crypto.js: -------------------------------------------------------------------------------- 1 | const CryptoJS = require("crypto-js"); 2 | require("dotenv").config(); 3 | 4 | /** 5 | * @param {string} data 6 | * @returns {string} 7 | */ 8 | function encrypt(data) { 9 | return CryptoJS.AES.encrypt(data, process.env.ENCRYPT_SECRET).toString(); 10 | } 11 | 12 | /** 13 | * @param {string} data 14 | * @returns {string} 15 | */ 16 | function decrypt(data) { 17 | return CryptoJS.AES.decrypt(data, process.env.ENCRYPT_SECRET).toString(CryptoJS.enc.Utf8); 18 | } 19 | 20 | module.exports = { 21 | encrypt, 22 | decrypt 23 | }; 24 | -------------------------------------------------------------------------------- /scripts/setup.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | 3 | if (!fs.existsSync("./data")) { 4 | fs.mkdirSync("./data"); 5 | } 6 | 7 | if (!fs.existsSync("./.env")) { 8 | fs.writeFileSync( 9 | "./.env", 10 | "ENCRYPT_SECRET=SUPERSECRET # Default encrypt secret\nWEB_ADDRESS=127.0.0.1\nWEB_ENV=development" 11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /seeds/growtopia_users.js: -------------------------------------------------------------------------------- 1 | const { encrypt } = require("../scripts/crypto"); 2 | 3 | /** 4 | * @param { import("knex").Knex } knex 5 | * @returns { Promise } 6 | */ 7 | exports.seed = async function (knex) { 8 | // Deletes ALL existing entries 9 | await knex("users").del(); 10 | await knex("users").insert([ 11 | { 12 | id_user: 1, 13 | name: "admin", 14 | password: encrypt("admin"), 15 | role: "2", 16 | gems: 1000, 17 | clothing: null, 18 | inventory: null, 19 | created_at: null 20 | } 21 | ]); 22 | }; 23 | -------------------------------------------------------------------------------- /setupNrun.bat: -------------------------------------------------------------------------------- 1 | call npm install -g typescript 2 | call npm install quick.db 3 | call npm install knex 4 | call npm install 5 | call npm run setup 6 | call npm run dev 7 | -------------------------------------------------------------------------------- /src/abstracts/Action.ts: -------------------------------------------------------------------------------- 1 | import { Peer } from "../structures/Peer"; 2 | import { ActionConfig, ActionType } from "../types/action"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { World } from "../structures/World"; 5 | import { TankPacket } from "growtopia.js"; 6 | import { Database } from "../database/db"; 7 | 8 | export abstract class Action { 9 | public config: ActionConfig; 10 | 11 | constructor() { 12 | this.config = { 13 | eventName: undefined 14 | }; 15 | } 16 | 17 | public handle(base: BaseServer, peer: Peer, db: Database, action: ActionType) {} 18 | } 19 | -------------------------------------------------------------------------------- /src/abstracts/Command.ts: -------------------------------------------------------------------------------- 1 | import { Database } from "../database/db"; 2 | import { BaseServer } from "../structures/BaseServer"; 3 | import { Peer } from "../structures/Peer"; 4 | import { World } from "../structures/World"; 5 | import { CommandOptions } from "../types/command"; 6 | 7 | export abstract class Command { 8 | public opt: CommandOptions; 9 | 10 | constructor() { 11 | this.opt = { 12 | name: "", 13 | description: "", 14 | cooldown: 1, 15 | ratelimit: 1, 16 | category: "", 17 | usage: "", 18 | example: [], 19 | permission: [] 20 | }; 21 | } 22 | 23 | public async execute(base: BaseServer, peer: Peer, text: string, args: string[], db: Database): Promise {} 24 | } 25 | -------------------------------------------------------------------------------- /src/abstracts/Dialog.ts: -------------------------------------------------------------------------------- 1 | import { Peer } from "../structures/Peer"; 2 | import { BaseServer } from "../structures/BaseServer"; 3 | import { DialogConfig, DialogReturnType } from "../types/dialog"; 4 | import { World } from "../structures/World"; 5 | import { TankPacket } from "growtopia.js"; 6 | import { Database } from "../database/db"; 7 | import { QuickDB } from "quick.db"; 8 | const data = new QuickDB 9 | 10 | export abstract class Dialog { 11 | public config: DialogConfig; 12 | 13 | constructor() { 14 | this.config = { 15 | dialogName: undefined 16 | }; 17 | } 18 | 19 | public handle(base: BaseServer, peer: Peer, db: Database, action: DialogReturnType) {} 20 | } 21 | -------------------------------------------------------------------------------- /src/abstracts/Listener.ts: -------------------------------------------------------------------------------- 1 | import { ListenerEventTypes } from "../types/events"; 2 | import { BaseServer } from "../structures/BaseServer"; 3 | import { Database } from "../database/db"; 4 | 5 | export abstract class Listener { 6 | public name: keyof ListenerEventTypes | undefined; 7 | constructor() { 8 | this.name = undefined; 9 | } 10 | 11 | public run(base: BaseServer, ...args: ListenerEventTypes[K]): void {} 12 | } 13 | -------------------------------------------------------------------------------- /src/actions/DialogReturn.ts: -------------------------------------------------------------------------------- 1 | import { Action } from "../abstracts/Action"; 2 | import { Peer } from "../structures/Peer"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { ActionType } from "../types/action"; 5 | import { Database } from "../database/db"; 6 | 7 | export default class extends Action { 8 | constructor() { 9 | super(); 10 | this.config = { 11 | eventName: "dialog_return" 12 | }; 13 | } 14 | 15 | public handle( 16 | base: BaseServer, 17 | peer: Peer, 18 | db: Database, 19 | action: ActionType<{ action: string; dialog_name: string }>, 20 | ): void { 21 | let name = action.dialog_name; 22 | try { 23 | if (!base.dialogs.has(name)) return; 24 | base.dialogs.get(name)!.handle(base, peer,db , action); 25 | } catch (err) { 26 | console.log(err); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/actions/Drop.ts: -------------------------------------------------------------------------------- 1 | import { Action } from "../abstracts/Action"; 2 | import { Peer } from "../structures/Peer"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { ActionType } from "../types/action"; 5 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 6 | import { Variant } from "growtopia.js"; 7 | import { Database } from "../database/db"; 8 | 9 | export default class extends Action { 10 | constructor() { 11 | super(); 12 | this.config = { 13 | eventName: "drop" 14 | }; 15 | } 16 | 17 | public handle( 18 | base: BaseServer, 19 | peer: Peer, 20 | db: Database, 21 | action: ActionType<{ action: string; itemID: string }> 22 | ): void { 23 | const itemID = parseInt(action.itemID); 24 | const item = base.items.metadata.items.find((v) => v.id === itemID); 25 | 26 | const peerItem = peer.data.inventory?.items.find((v) => v.id === itemID); 27 | 28 | if(peerItem?.id === 32 || peerItem?.id === 18) return peer.send(Variant.from("OnTextOverlay", "Cannot drop this item.")) 29 | 30 | let dialog = new DialogBuilder() 31 | .defaultColor() 32 | .addLabelWithIcon(`Drop ${item?.name}`, item?.id!, "big") 33 | .addTextBox("How many to drop?") 34 | .addInputBox("drop_count", "", peerItem?.amount, 5) 35 | .embed("itemID", itemID) 36 | .endDialog("drop_end", "Cancel", "OK") 37 | .str(); 38 | peer.send(Variant.from("OnDialogRequest", dialog)); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/actions/EnterGame.ts: -------------------------------------------------------------------------------- 1 | import { Variant } from "growtopia.js"; 2 | import { Peer } from "../structures/Peer"; 3 | import { Action } from "../abstracts/Action"; 4 | import { BaseServer } from "../structures/BaseServer"; 5 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 6 | import { ActionType } from "../types/action"; 7 | import { Database } from "../database/db"; 8 | import { QuickDB } from "quick.db"; 9 | const data = new QuickDB 10 | import * as fs from 'fs'; 11 | 12 | 13 | export default class extends Action { 14 | constructor() { 15 | super(); 16 | this.config = { 17 | eventName: "enter_game" 18 | }; 19 | } 20 | 21 | public async handle(base: BaseServer, peer: Peer,db: Database, action: ActionType<{ action: string }>): Promise { 22 | let filePath = 'number.txt'; 23 | const carnival = await data.get(`Carnival`) 24 | const GemEvnt = await data.get(`GemEvent`) 25 | const Gems = await data.get(`GemEventGems`) 26 | 27 | fs.readFile(filePath, 'utf8', (err, data) => { 28 | if (err) { 29 | console.error(`Error reading file ${filePath}:`, err); 30 | return; 31 | } 32 | //console.log(`File contents of ${filePath}:`); 33 | //console.log(data); 34 | 35 | 36 | 37 | // Carnival Message 38 | const tes = new DialogBuilder() 39 | .defaultColor() 40 | .addLabelWithIcon("Hello", "1000", "big") 41 | .addSpacer("small") 42 | .addTextBox("Welcome to GrowServer") 43 | .raw("add_image_button||interface/large/news_banner.rttex|bannerlayout|||\n") 44 | .addQuickExit() 45 | .endDialog("gazzette_end", "Cancel", "Ok") 46 | .str(); 47 | peer.send( 48 | Variant.from("OnRequestWorldSelectMenu", "add_filter|\nadd_heading|Top Worlds|\nadd_floater|wotd_world|START|0|0.5|2147418367|"), 49 | 50 | Variant.from("OnConsoleMessage", `Welcome! ${peer.name} Where would you like to go? ( online)`), 51 | Variant.from({ delay: 100 }, "OnDialogRequest", tes) 52 | ); 53 | if(carnival){ 54 | peer.send( 55 | Variant.from("OnRequestWorldSelectMenu", "add_filter|\nadd_heading|Top Worlds|\nadd_floater|wotd_world|START|0|0.5|2147418367|"), 56 | Variant.from("OnConsoleMessage", "`2Carnival has come to town`0, visit the world `9CARNIVAL`0, try your luck at winning one of the ringmaster's fabulous rings!") 57 | ) 58 | } 59 | 60 | if(GemEvnt){ 61 | peer.send( 62 | Variant.from("OnRequestWorldSelectMenu", "add_filter|\nadd_heading|Top Worlds|\nadd_floater|wotd_world|START|0|0.5|2147418367|"), 63 | Variant.from("OnConsoleMessage", `\`2x${Gems} Gem Event is ongoing, \`5Try get as much gems as you can!`) 64 | ) 65 | } 66 | }); 67 | 68 | 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/actions/FriendsDialog.ts: -------------------------------------------------------------------------------- 1 | import { Action } from "../abstracts/Action"; 2 | import { Peer } from "../structures/Peer"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { ActionType } from "../types/action"; 5 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 6 | import { Variant } from "growtopia.js"; 7 | import { Database } from "../database/db"; 8 | import e from "express"; 9 | import { Z_UNKNOWN } from "zlib"; 10 | 11 | export default class extends Action { 12 | constructor() { 13 | super(); 14 | this.config = { 15 | eventName: "friends" 16 | }; 17 | } 18 | 19 | public async handle( 20 | base: BaseServer, 21 | peer: Peer, 22 | db: Database, 23 | action: ActionType<{ action: string; delay: number, netID: string, tankIDName: string }> 24 | ): Promise { 25 | //let getGuild = await db.getGuild(undefined as any, peer.data.tankIDName); 26 | let dialog = new DialogBuilder() 27 | .defaultColor() 28 | .addLabelWithIcon("Social Portal", "1366", "big") 29 | .addButton("friendsList", "Show Friends") 30 | // if(getGuild){ 31 | // dialog.addButton("GM", "Show Guild Members(`2Coming soon!`0)") 32 | // dialog.addButton("GC", "Guild Challenge(`2Coming soon!`0)") 33 | // dialog.addButton("top_players", "Show `9Top Players(`2Coming soon!`0)") 34 | // }else { 35 | .addButton("CG", "Create Guild") 36 | // } 37 | .addButton("top_players", "Show `9Top Players(`2Coming soon!`0)") 38 | .endDialog("FriendsDialog", "Close", "") 39 | .addQuickExit() 40 | //.str(); 41 | 42 | peer.send(Variant.from({ delay: 100 }, "OnDialogRequest", dialog.str())); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/actions/Input.ts: -------------------------------------------------------------------------------- 1 | import { Variant } from "growtopia.js"; 2 | import { Peer } from "../structures/Peer"; 3 | import { Action } from "../abstracts/Action"; 4 | import { BaseServer } from "../structures/BaseServer"; 5 | import { ActionType } from "../types/action"; 6 | import { Database } from "../database/db"; 7 | import { World } from "../structures/World"; 8 | 9 | export default class extends Action { 10 | constructor() { 11 | super(); 12 | this.config = { 13 | eventName: "input" 14 | }; 15 | } 16 | 17 | public async handle( 18 | base: BaseServer, 19 | peer: Peer, 20 | db: Database, 21 | action: ActionType<{ action: string; text: string }> 22 | ): Promise { 23 | let text = action.text.trim(); 24 | if (!text || text.replace(/`.|`/g, "").length < 1) return; 25 | 26 | if (text.startsWith("/")) { 27 | const args = text.slice("/".length).split(" "); 28 | const commandName = args.shift()?.toLowerCase()!; 29 | 30 | if (!base.commands.has(commandName)) { 31 | return peer.send( 32 | Variant.from( 33 | "OnConsoleMessage", 34 | "`4Unknown command.`` Enter `$/help`` for a list of valid commands" 35 | ) 36 | ); 37 | } 38 | peer.send(Variant.from("OnConsoleMessage", `\`6/${commandName} ${args.join(" ")}\`\``)); 39 | 40 | // Cooldown & Ratelimit 41 | if (!base.cooldown.get(`${commandName}-netID-${peer.data.netID}`)) { 42 | base.cooldown.set(`${commandName}-netID-${peer.data.netID}`, { 43 | limit: 1, 44 | time: Date.now() 45 | }); 46 | } else { 47 | let expireTime = 48 | base.cooldown.get(`${commandName}-netID-${peer.data.netID}`)!.time + 49 | base.commands.get(commandName)!.opt.cooldown * 1000; 50 | let timeLeft = expireTime - Date.now(); 51 | if ( 52 | base.cooldown.get(`${commandName}-netID-${peer.data.netID}`)!.limit >= 53 | base.commands.get(commandName)!.opt.ratelimit 54 | ) { 55 | return peer.send( 56 | Variant.from( 57 | "OnConsoleMessage", 58 | `\`6${peer.data.tankIDName}\`0 you're being ratelimited, please wait \`9${ 59 | timeLeft / 1000 60 | }s\`0` 61 | ) 62 | ); 63 | } 64 | } 65 | 66 | base.cooldown.get(`${commandName}-netID-${peer.data.netID}`)!.limit += 1; 67 | 68 | setTimeout(() => { 69 | base.cooldown.delete(`${commandName}-netID-${peer.data.netID}`); 70 | }, base.commands.get(commandName)!.opt.cooldown * 1000); 71 | 72 | try { 73 | if ( 74 | base.commands.get(commandName)?.opt.permission.some((perm) => perm === peer.data.role) 75 | ) { 76 | await base.commands.get(commandName)?.execute(base, peer, text, args, db); 77 | } else { 78 | peer.send( 79 | Variant.from("OnConsoleMessage", `You dont have permission to use this command.`) 80 | ); 81 | } 82 | } catch (err) { 83 | console.log(err); 84 | } 85 | return; 86 | } 87 | 88 | peer.everyPeer((p) => { 89 | if (p.data.world === peer.data.world && peer.data.world !== "EXIT") { 90 | p.send( 91 | Variant.from("OnTalkBubble", peer.data.netID, action.text, 0), 92 | Variant.from( 93 | "OnConsoleMessage", 94 | `CP:0_PL:0_OID:_CT:[W]_ <\`w${peer.data.tankIDName}\`\`> ${action.text}` 95 | ) 96 | ); 97 | } 98 | }); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/actions/JoinRequest.ts: -------------------------------------------------------------------------------- 1 | import { TankPacket, Variant } from "growtopia.js"; 2 | import { Action } from "../abstracts/Action"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import { ActionType } from "../types/action"; 6 | import { Database } from "../database/db"; 7 | import { QuickDB } from "quick.db"; 8 | const data = new QuickDB 9 | 10 | export default class extends Action { 11 | constructor() { 12 | super(); 13 | this.config = { 14 | eventName: "join_request" 15 | }; 16 | } 17 | 18 | public async handle( 19 | base: BaseServer, 20 | peer: Peer, 21 | db: Database, 22 | action: ActionType<{ action: string; name: string }> 23 | ): Promise { 24 | const worldName: string = action.name || ""; 25 | const worldEntering = base.cache.worlds.getWorld(worldName) 26 | 27 | if (worldName.length <= 0) { 28 | return peer.send( 29 | Variant.from("OnFailedToEnterWorld", 1), 30 | Variant.from("OnConsoleMessage", "That world name is uhh `9empty``") 31 | ); 32 | } 33 | if (worldName.match(/\W+|_|EXIT/gi)) { 34 | return peer.send( 35 | Variant.from("OnFailedToEnterWorld", 1), 36 | Variant.from("OnConsoleMessage", "That world name is too `9special`` to be entered.") 37 | ); 38 | } 39 | if(worldEntering.data?.playerCount! >= 10){ 40 | peer.send(Variant.from("OnFailedToEnterWorld", 1), Variant.from("OnConsoleMessage", `Oops, \`5${worldName.toLocaleUpperCase()} already has \`410\`\` people in it. Try again later.`)); 41 | return; 42 | } 43 | 44 | 45 | 46 | setTimeout(() => { 47 | peer.enterWorld(worldName.toUpperCase()); 48 | }, 300); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/actions/Quit.ts: -------------------------------------------------------------------------------- 1 | import { Action } from "../abstracts/Action"; 2 | import { Peer } from "../structures/Peer"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { ActionType } from "../types/action"; 5 | import { Database } from "../database/db"; 6 | 7 | export default class extends Action { 8 | constructor() { 9 | super(); 10 | this.config = { 11 | eventName: "quit" 12 | }; 13 | } 14 | 15 | public handle(base: BaseServer, peer: Peer,db: Database, action: ActionType<{ action: string }>): void { 16 | peer.disconnect(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/actions/QuitToExit.ts: -------------------------------------------------------------------------------- 1 | import { Action } from "../abstracts/Action"; 2 | import { Peer } from "../structures/Peer"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { ActionType } from "../types/action"; 5 | import { Database } from "../database/db"; 6 | 7 | export default class extends Action { 8 | constructor() { 9 | super(); 10 | this.config = { 11 | eventName: "quit_to_exit" 12 | }; 13 | } 14 | 15 | public handle(base: BaseServer, peer: Peer,db: Database, action: ActionType<{ action: string }>): void { 16 | peer.leaveWorld(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/actions/RefreshItemData.ts: -------------------------------------------------------------------------------- 1 | import { TankPacket, Variant } from "growtopia.js"; 2 | import { Peer } from "../structures/Peer"; 3 | import { Action } from "../abstracts/Action"; 4 | import { BaseServer } from "../structures/BaseServer"; 5 | import { TankTypes } from "../utils/enums/TankTypes"; 6 | import { ActionType } from "../types/action"; 7 | import { Database } from "../database/db"; 8 | 9 | export default class extends Action { 10 | constructor() { 11 | super(); 12 | this.config = { 13 | eventName: "refresh_item_data" 14 | }; 15 | } 16 | 17 | public handle(base: BaseServer, peer: Peer,db: Database, action: ActionType<{ action: string }>): void { 18 | peer.send( 19 | Variant.from("OnConsoleMessage", "One moment. Updating item data..."), 20 | //TankPacket.from({ type: TankTypes.PEER_ITEMS_DAT, data: () => base.items.hash }), 21 | TankPacket.from({ type: TankTypes.PEER_ITEMS_DAT, data: () => base.items.content }) 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/actions/Respawn.ts: -------------------------------------------------------------------------------- 1 | import { Action } from "../abstracts/Action"; 2 | import { Peer } from "../structures/Peer"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { ActionType } from "../types/action"; 5 | import { Database } from "../database/db"; 6 | 7 | export default class extends Action { 8 | constructor() { 9 | super(); 10 | this.config = { 11 | eventName: "respawn" 12 | }; 13 | } 14 | 15 | public handle(base: BaseServer, peer: Peer,db: Database, action: ActionType<{ action: string }>): void { 16 | peer.respawn(); 17 | // TODO: respawn back to previous checkpoint 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/actions/RespawnSpike.ts: -------------------------------------------------------------------------------- 1 | import { Action } from "../abstracts/Action"; 2 | import { Peer } from "../structures/Peer"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { ActionType } from "../types/action"; 5 | import { Database } from "../database/db"; 6 | 7 | export default class extends Action { 8 | constructor() { 9 | super(); 10 | this.config = { 11 | eventName: "respawn_spike" 12 | }; 13 | } 14 | 15 | public handle(base: BaseServer, peer: Peer,db: Database, action: ActionType<{ action: string }>): void { 16 | peer.respawn(); 17 | // TODO: respawn back to previous checkpoint 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/actions/Trash.ts: -------------------------------------------------------------------------------- 1 | import { Action } from "../abstracts/Action"; 2 | import { Peer } from "../structures/Peer"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { ActionType } from "../types/action"; 5 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 6 | import { Variant } from "growtopia.js"; 7 | import { Database } from "../database/db"; 8 | 9 | export default class extends Action { 10 | constructor() { 11 | super(); 12 | this.config = { 13 | eventName: "trash" 14 | }; 15 | } 16 | 17 | public handle( 18 | base: BaseServer, 19 | peer: Peer, 20 | db: Database, 21 | action: ActionType<{ action: string; itemID: string }> 22 | ): void { 23 | const itemID = parseInt(action.itemID); 24 | const item = base.items.metadata.items.find((v) => v.id === itemID); 25 | const peerItem = peer.data.inventory?.items.find((v) => v.id === itemID); 26 | 27 | if(peerItem?.id === 32 || peerItem?.id === 18) return peer.send(Variant.from("OnTextOverlay", "Cannot trash this item.")) 28 | 29 | let dialog = new DialogBuilder() 30 | .defaultColor() 31 | .addLabelWithIcon(`\`4Trash\`\` ${item?.name}`, item?.id!, "big") 32 | .addTextBox(`How many to \`4destroy\`\`? (you have ${peerItem?.amount})`) 33 | .addInputBox("trash_count", "", peerItem?.amount, 5) 34 | .embed("itemID", itemID) 35 | .endDialog("trash_end", "Cancel", "OK") 36 | .str(); 37 | 38 | peer.send(Variant.from("OnDialogRequest", dialog)); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/actions/Wrench.ts: -------------------------------------------------------------------------------- 1 | import { Action } from "../abstracts/Action"; 2 | import { Peer } from "../structures/Peer"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { ActionType } from "../types/action"; 5 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 6 | import { Variant } from "growtopia.js"; 7 | import { Database } from "../database/db"; 8 | import { Role } from "../utils/Constants"; 9 | 10 | export default class extends Action { 11 | constructor() { 12 | super(); 13 | this.config = { 14 | eventName: "wrench" 15 | }; 16 | } 17 | 18 | public handle( 19 | base: BaseServer, 20 | peer: Peer, 21 | db: Database, 22 | action: ActionType<{ action: string; netID: number}> 23 | ): void { 24 | let world = peer.hasWorld(peer.data.world); 25 | 26 | if (action.action === "wrench" && peer.data.netID === action.netID) { // Updates 27 | 28 | let dialog = new DialogBuilder() 29 | .defaultColor() 30 | .addLabelWithIcon(peer.name, "32", "big") 31 | .addSpacer("small") 32 | .addButton("trade", "Trade(Coming soon!)") 33 | //.raw("add_player_picker|playerNetID|`wAdd``\n") 34 | .addSpacer("small") 35 | .addSmallText("Level: `2Coming soon!") 36 | .addSpacer("small") 37 | if(peer.data.role === Role.DEVELOPER || peer.data.role === Role.ADMIN || peer.data.role === Role.MOD){ 38 | dialog.addSmallText("Role: " + peer.data.role) 39 | dialog.addSmallText("`3Player last visit: Coming soon!") 40 | dialog.addSmallText(`My NetID: ${peer.data.netID}`) 41 | } 42 | dialog.addQuickExit() 43 | //.str(); 44 | 45 | peer.send(Variant.from({ delay: 100 }, "OnDialogRequest", dialog.str())); 46 | }else{ 47 | let dialog = new DialogBuilder() 48 | .defaultColor() 49 | .addLabelWithIcon(peer.data.tankIDName, "32", "big") 50 | .addSmallText("Level: 1 (0/1000000000) [`2Coming soon!]") 51 | .raw("\nadd_progress_bar|Level 1 ") 52 | .addSpacer("small") 53 | //.addButton("account_s", "Account Settings") 54 | //.addButton("title", "Title") 55 | .addSpacer("small") 56 | .addCustomBreak() 57 | .addCustomButton("test1", "interface/large/gui_wrench_goals_quests.rttex", { width: 404, height: 324 }) 58 | .addCustomButton("test2", "interface/large/gui_wrench_personalize_profile.rttex", { width: 404, height: 324 }) 59 | .addCustomButton("test3", "interface/large/gui_wrench_growmojis.rttex", { width: 404, height: 324 }) 60 | .addCustomButton("test4", "interface/large/gui_wrench_online_status_1green.rttex", { width: 404, height: 324 }) 61 | .addCustomButton("test5", "interface/large/gui_wrench_my_worlds.rttex", { width: 404, height: 324 }) 62 | .addCustomButton("test6", "interface/large/gui_wrench_notebook.rttex", { width: 404, height: 324 }) 63 | .addCustomButton("test7", "interface/large/gui_wrench_title.rttex", { width: 404, height: 324 }) 64 | .addCustomButton("test8", "interface/large/gui_wrench_trade.rttex", { width: 404, height: 324 }) 65 | .addCustomBreak() 66 | .addSpacer("small") 67 | .addSmallText(`Active effects: Coming soon!`) 68 | .addSpacer("small") 69 | .addSmallText(`You have ${peer.data.inventory?.items.length} items`) 70 | .addSmallText(`Current world: ${peer.data.world} (${peer.data.x}, ${peer.data.y}) (${world?.data.playerCount} person) Total time played: 0 hours`) 71 | .addQuickExit() 72 | .endDialog("profile_end", "", "Continue") 73 | .str(); 74 | 75 | peer.send(Variant.from({ delay: 100 }, "OnDialogRequest", dialog)); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/app.ts: -------------------------------------------------------------------------------- 1 | import { BaseServer } from "./structures/BaseServer"; 2 | import fs from "node:fs"; 3 | import { handleSaveAll } from "./utils/Utils"; 4 | 5 | if (!fs.existsSync("./assets")) 6 | throw new Error("Could not find 'assets' folder, please create new one."); 7 | 8 | if (!fs.existsSync("./assets/ssl")) 9 | throw new Error("SSL certificate are required for https web server."); 10 | 11 | if (!fs.existsSync("./assets/ssl/server.crt")) 12 | throw new Error("'assets/ssl/server.crt' are required for https web server."); 13 | 14 | if (!fs.existsSync("./assets/ssl/server.key")) 15 | throw new Error("assets/ssl/server.key are required for https web server."); 16 | 17 | if (!fs.existsSync("./assets/dat/items.dat")) 18 | throw new Error("items.dat not exist on 'assets/dat/items.dat'"); 19 | 20 | const server = new BaseServer(); 21 | 22 | server.start(); 23 | 24 | //process.on("SIGINT", () => handleSaveAll(server, true)); 25 | process.on("SIGQUIT", () => handleSaveAll(server, true)); 26 | process.on("SIGTERM", () => handleSaveAll(server, true)); 27 | 28 | process.on('SIGINT', () => { 29 | // This function will be executed when Ctrl+C is pressed 30 | handleSaveAll(server, true) 31 | 32 | const filePath = '/Users/macbook/Desktop/GrowAsia/number.txt'; 33 | 34 | // Open the file for writing 35 | try { 36 | // Write "0" to the file synchronously 37 | fs.writeFileSync(filePath, '0'); 38 | console.log('File content updated to "0"'); 39 | } catch (err) { 40 | console.error(`Error writing to file: ${err}`); 41 | } 42 | 43 | console.log('Ctrl+C pressed. Stopping the application...'); 44 | 45 | 46 | // You can add any cleanup or exit logic here 47 | process.exit(0); // Exit the application 48 | }); 49 | -------------------------------------------------------------------------------- /src/commands/AddFriend.ts: -------------------------------------------------------------------------------- 1 | import { TankPacket, TextPacket, Variant, TankTypes } from "growtopia.js"; 2 | import { Command } from "../abstracts/Command"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import { CommandOptions } from "../types/command"; 6 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 7 | import { Role } from "../utils/Constants"; 8 | import { DataTypes } from "../utils/enums/DataTypes"; 9 | import { find } from "../utils/Utils"; 10 | import { QuickDB } from "quick.db"; 11 | const data = new QuickDB 12 | 13 | export default class extends Command { 14 | public opt: CommandOptions; 15 | 16 | constructor() { 17 | super(); 18 | this.opt = { 19 | name: "addfriend", 20 | description: "Add friend", 21 | cooldown: 0, 22 | ratelimit: 1, 23 | category: "Basic", 24 | usage: "/addfriend", 25 | example: ["/addfriend "], 26 | permission: [Role.BASIC, Role.ADMIN, Role.MOD, Role.DEVELOPER] 27 | }; 28 | } 29 | 30 | public async execute(base: BaseServer, peer: Peer, text: string, args: string[]): Promise { 31 | const targetPeers = find(base, base.cache.users, (user) => 32 | user.data.tankIDName.toLowerCase().includes(args[0].toLowerCase()) 33 | ); 34 | const targetPeer = { 35 | data: { 36 | tankIDName: targetPeers?.data.tankIDName, 37 | // Other properties of targetPeer 38 | }, 39 | }; 40 | 41 | 42 | 43 | if(!targetPeers) return peer.send(Variant.from("OnConsoleMessage", "User not found! (User must be online to use this command.)")); 44 | 45 | // Fetch the array from the database 46 | const existingArray: any[] = await data.get(`Friend_${targetPeer.data.tankIDName}`) || []; 47 | 48 | // Add an element (in this case, targetPeer) to the array 49 | existingArray.push(targetPeer); 50 | 51 | // Set the modified array back in the database 52 | 53 | peer.send(Variant.from("OnTalkBuble", `Waiting for ${targetPeer.data.tankIDName} to accept the friend request...`)); 54 | 55 | 56 | data.set(`Friend_${targetPeer.data.tankIDName}`, existingArray); 57 | 58 | const tankIDName = targetPeer.data.tankIDName; 59 | console.log(tankIDName); 60 | 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/commands/CarnivalEnd.ts: -------------------------------------------------------------------------------- 1 | import { TextPacket, Variant } from "growtopia.js"; 2 | import { Command } from "../abstracts/Command"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import { CommandOptions } from "../types/command"; 6 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 7 | import { Role } from "../utils/Constants"; 8 | import { DataTypes } from "../utils/enums/DataTypes"; 9 | import { World } from "../structures/World"; 10 | import { QuickDB } from "quick.db"; 11 | const data = new QuickDB 12 | 13 | export default class extends Command { 14 | public opt: CommandOptions; 15 | 16 | constructor() { 17 | super(); 18 | this.opt = { 19 | name: "endcarnival", 20 | description: "Close Carnival.", 21 | cooldown: 0, 22 | ratelimit: 1, 23 | category: "Basic", 24 | usage: "/endcarnival", 25 | example: ["/endcarnival"], 26 | permission: [Role.BASIC, Role.ADMIN, Role.DEVELOPER] 27 | }; 28 | } 29 | 30 | public async execute(base: BaseServer, peer: Peer, text: string, args: string[]): Promise { 31 | peer.everyPeer((p) => { 32 | p.send(Variant.from("OnConsoleMessage", "`2Carnival has left to town`0, The Ringmaster will be back in afew days.")) 33 | data.set(`Carnival`, false) 34 | }) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/commands/CarnivalStart.ts: -------------------------------------------------------------------------------- 1 | import { TextPacket, Variant } from "growtopia.js"; 2 | import { Command } from "../abstracts/Command"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import { CommandOptions } from "../types/command"; 6 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 7 | import { Role } from "../utils/Constants"; 8 | import { DataTypes } from "../utils/enums/DataTypes"; 9 | import { World } from "../structures/World"; 10 | import { QuickDB } from "quick.db"; 11 | const data = new QuickDB 12 | 13 | export default class extends Command { 14 | public opt: CommandOptions; 15 | 16 | constructor() { 17 | super(); 18 | this.opt = { 19 | name: "startcarnival", 20 | description: "Open Carnival.", 21 | cooldown: 0, 22 | ratelimit: 1, 23 | category: "Basic", 24 | usage: "/startcarnival", 25 | example: ["/startcarnival"], 26 | permission: [Role.BASIC, Role.ADMIN, Role.DEVELOPER] 27 | }; 28 | } 29 | 30 | public async execute(base: BaseServer, peer: Peer, text: string, args: string[]): Promise { 31 | peer.everyPeer((p) => { 32 | p.send(Variant.from("OnConsoleMessage", "`2Carnival has come to town`0, visit the world `9CARNIVAL`0, try your luck at winning one of the ringmaster's fabulous rings!")) 33 | data.set(`Carnival`, true) 34 | }) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/commands/CheckInventory.ts: -------------------------------------------------------------------------------- 1 | import { TextPacket, Variant } from "growtopia.js"; 2 | import { Command } from "../abstracts/Command"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import { CommandOptions } from "../types/command"; 6 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 7 | import { Role } from "../utils/Constants"; 8 | import { DataTypes } from "../utils/enums/DataTypes"; 9 | import { World } from "../structures/World"; 10 | import { QuickDB } from "quick.db"; 11 | const data = new QuickDB 12 | 13 | export default class extends Command { 14 | public opt: CommandOptions; 15 | 16 | constructor() { 17 | super(); 18 | this.opt = { 19 | name: "inv", 20 | description: "Start a new world event.", 21 | cooldown: 0, 22 | ratelimit: 1, 23 | category: "Developer", 24 | usage: "/inventory", 25 | example: ["/inventory"], 26 | permission: [Role.MOD, Role.ADMIN, Role.DEVELOPER] 27 | }; 28 | } 29 | 30 | public async execute(base: BaseServer, peer: Peer, text: string, args: string[]): Promise { 31 | const pInv = peer.data.inventory?.items 32 | 33 | 34 | const dialog = new DialogBuilder() 35 | .defaultColor() 36 | .addLabelWithIcon(`${peer.name}'s inventory`, "32", "small") 37 | .addSpacer("small") 38 | .addCustomBreak() 39 | const transformedArray = pInv!.map((element) => { 40 | dialog.addButtonWithIcon(element.id!, element.id!, "", "staticBlueFrame", element.amount!) 41 | }); 42 | dialog.addCustomBreak() 43 | dialog.endDialog("endInv", "Cancel", "") 44 | 45 | peer.send(Variant.from("OnDialogRequest", dialog.str())); 46 | 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/commands/Cry.ts: -------------------------------------------------------------------------------- 1 | import { TankPacket, TextPacket, Variant, TankTypes } from "growtopia.js"; 2 | import { Command } from "../abstracts/Command"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import { CommandOptions } from "../types/command"; 6 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 7 | import { Role } from "../utils/Constants"; 8 | import { DataTypes } from "../utils/enums/DataTypes"; 9 | 10 | export default class extends Command { 11 | public opt: CommandOptions; 12 | 13 | constructor() { 14 | super(); 15 | this.opt = { 16 | name: "cry", 17 | description: "Cry", 18 | cooldown: 0, 19 | ratelimit: 1, 20 | category: "Basic", 21 | usage: "/cry", 22 | example: ["/cry"], 23 | permission: [Role.BASIC, Role.ADMIN, Role.DEVELOPER] 24 | }; 25 | } 26 | 27 | public async execute(base: BaseServer, peer: Peer, text: string, args: string[]): Promise { 28 | peer.send(Variant.from("OnTalkBubble", peer.data.netID, ":'(")); 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/commands/DanceCmd.ts: -------------------------------------------------------------------------------- 1 | import { TankPacket, TextPacket, Variant, TankTypes } from "growtopia.js"; 2 | import { Command } from "../abstracts/Command"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import { CommandOptions } from "../types/command"; 6 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 7 | import { Role } from "../utils/Constants"; 8 | import { DataTypes } from "../utils/enums/DataTypes"; 9 | 10 | export default class extends Command { 11 | public opt: CommandOptions; 12 | 13 | constructor() { 14 | super(); 15 | this.opt = { 16 | name: "dance", 17 | description: "dance", 18 | cooldown: 0, 19 | ratelimit: 1, 20 | category: "Basic", 21 | usage: "/dance", 22 | example: ["/dance"], 23 | permission: [Role.BASIC, Role.ADMIN, Role.DEVELOPER] 24 | }; 25 | } 26 | 27 | public async execute(base: BaseServer, peer: Peer, text: string, args: string[]): Promise { 28 | peer.send(Variant.from("OnAction", text)); 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/commands/Event.ts: -------------------------------------------------------------------------------- 1 | import { TextPacket, Variant } from "growtopia.js"; 2 | import { Command } from "../abstracts/Command"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import { CommandOptions } from "../types/command"; 6 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 7 | import { Role } from "../utils/Constants"; 8 | import { DataTypes } from "../utils/enums/DataTypes"; 9 | import { World } from "../structures/World"; 10 | import { QuickDB } from "quick.db"; 11 | const data = new QuickDB 12 | 13 | export default class extends Command { 14 | public opt: CommandOptions; 15 | 16 | constructor() { 17 | super(); 18 | this.opt = { 19 | name: "event", 20 | description: "Start a new world event.", 21 | cooldown: 0, 22 | ratelimit: 1, 23 | category: "Basic", 24 | usage: "/event", 25 | example: ["/event"], 26 | permission: [Role.BASIC, Role.ADMIN, Role.DEVELOPER] 27 | }; 28 | } 29 | 30 | public async execute(base: BaseServer, peer: Peer, text: string, args: string[]): Promise { 31 | 32 | let world = peer.hasWorld(peer.data.world); 33 | 34 | peer.everyPeer((p) => { 35 | peer.send(Variant.from("OnTextOverlay", "`2Starting World Event!")) 36 | 37 | if(p.data.world === peer.data.world){ 38 | 39 | p.send(Variant.from("OnAddNotification", "", "`2Beautiful Crystal:`` `wYou have 30 seconds to find and grab the `6Crystal Block Seed.")) 40 | 41 | 42 | 43 | world!.drop(peer, p.data.x! / world?.data.playerCount! * 3, p.data.y! / 3, 263, 1) 44 | //data.set(`onEvent_${peer.data.world}`, true) 45 | } 46 | }) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/commands/Find.ts: -------------------------------------------------------------------------------- 1 | import { TextPacket, Variant } from "growtopia.js"; 2 | import { Command } from "../abstracts/Command"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import { CommandOptions } from "../types/command"; 6 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 7 | import { Role } from "../utils/Constants"; 8 | import { DataTypes } from "../utils/enums/DataTypes"; 9 | 10 | export default class extends Command { 11 | public opt: CommandOptions; 12 | 13 | constructor() { 14 | super(); 15 | this.opt = { 16 | name: "find", 17 | description: "Find some items", 18 | cooldown: 5, 19 | ratelimit: 5, 20 | category: "Basic", 21 | usage: "/find", 22 | example: ["/find"], 23 | permission: [Role.BASIC, Role.ADMIN, Role.DEVELOPER] 24 | }; 25 | } 26 | 27 | public async execute(base: BaseServer, peer: Peer, text: string, args: string[]): Promise { 28 | let dialog = new DialogBuilder() 29 | .defaultColor() 30 | .addLabelWithIcon("Find the item", "6016", "big") 31 | if(peer.data.role === Role.DEVELOPER){ 32 | dialog.addCheckbox("seed_only", "Only seed", "not_selected") 33 | } 34 | dialog.addInputBox("find_item_name", "", "", 30) 35 | 36 | 37 | dialog.addQuickExit() 38 | .endDialog("find_item", "Cancel", "Find") 39 | .str(); 40 | 41 | peer.send(Variant.from("OnDialogRequest", dialog.str())); 42 | } 43 | } 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/commands/GemEventEnd.ts: -------------------------------------------------------------------------------- 1 | import { TextPacket, Variant } from "growtopia.js"; 2 | import { Command } from "../abstracts/Command"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import { CommandOptions } from "../types/command"; 6 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 7 | import { Role } from "../utils/Constants"; 8 | import { DataTypes } from "../utils/enums/DataTypes"; 9 | import { World } from "../structures/World"; 10 | import { QuickDB } from "quick.db"; 11 | const data = new QuickDB 12 | 13 | export default class extends Command { 14 | public opt: CommandOptions; 15 | 16 | constructor() { 17 | super(); 18 | this.opt = { 19 | name: "gemeventend", 20 | description: "NO gems!", 21 | cooldown: 0, 22 | ratelimit: 1, 23 | category: "Developer", 24 | usage: "/gemeventend", 25 | example: ["/gemeventend"], 26 | permission: [Role.DEVELOPER] 27 | }; 28 | } 29 | 30 | public async execute(base: BaseServer, peer: Peer, text: string, args: string[]): Promise { 31 | const GemEvnt = await data.get(`GemEvent`) 32 | const Gems = await data.get(`GemEventGems`) 33 | 34 | //if(!args[0]) return peer.send(Variant.from("OnConsoleMessage", "Please enter a number!")) 35 | //if(GemEvnt) return peer.send(Variant.from("OnConsoleMessage", "Event has already started! `bEnd the event to start a new one!")) 36 | 37 | peer.everyPeer((p) => { 38 | p.send(Variant.from("OnConsoleMessage", `${Gems}x \`2Gem Event has ended!`)) 39 | // p.send(Variant.from("OnAddNotification", "interface/atomic_button.rttex" ,`${args[0]}x \`2Gem Event has began!\``, "audio/hub_open.wav")) 40 | data.set(`GemEvent`, false) 41 | data.set(`GemEventGems`, 1) 42 | }) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/commands/GemEventStart.ts: -------------------------------------------------------------------------------- 1 | import { TextPacket, Variant } from "growtopia.js"; 2 | import { Command } from "../abstracts/Command"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import { CommandOptions } from "../types/command"; 6 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 7 | import { Role } from "../utils/Constants"; 8 | import { DataTypes } from "../utils/enums/DataTypes"; 9 | import { World } from "../structures/World"; 10 | import { QuickDB } from "quick.db"; 11 | const data = new QuickDB 12 | 13 | export default class extends Command { 14 | public opt: CommandOptions; 15 | 16 | constructor() { 17 | super(); 18 | this.opt = { 19 | name: "gemevent", 20 | description: "Free gems!", 21 | cooldown: 0, 22 | ratelimit: 1, 23 | category: "Developer", 24 | usage: "/gemevent", 25 | example: ["/gemevent"], 26 | permission: [Role.DEVELOPER] 27 | }; 28 | } 29 | 30 | public async execute(base: BaseServer, peer: Peer, text: string, args: string[]): Promise { 31 | const GemEvnt = await data.get(`GemEvent`) 32 | 33 | if(!args[0]) return peer.send(Variant.from("OnConsoleMessage", "Please enter a number!")) 34 | if(GemEvnt) return peer.send(Variant.from("OnConsoleMessage", "Event has already started! `bEnd the event to start a new one!")) 35 | 36 | peer.everyPeer((p) => { 37 | p.send(Variant.from("OnConsoleMessage", `x${args[0]} \`2Gem Event has began! \`9Happy farming everyone!`)) 38 | p.send(Variant.from("OnAddNotification", "interface/atomic_button.rttex" ,`x${args[0]} \`2Gem Event has began!\``, "audio/hub_open.wav")) 39 | data.set(`GemEvent`, true) 40 | data.set(`GemEventGems`, parseInt(args[0])) 41 | }) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/commands/GiveGems.ts: -------------------------------------------------------------------------------- 1 | import { Variant } from "growtopia.js"; 2 | import { Command } from "../abstracts/Command"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import { CommandOptions } from "../types/command"; 6 | import { Role } from "../utils/Constants"; 7 | import { find } from "../utils/Utils"; 8 | 9 | export default class extends Command { 10 | public opt: CommandOptions; 11 | 12 | constructor() { 13 | super(); 14 | this.opt = { 15 | name: "givegems", 16 | description: "Give gems to someone or self", 17 | cooldown: 5, 18 | ratelimit: 5, 19 | category: "Developer", 20 | usage: "/givegems ", 21 | example: ["/givegems 100", "/givegems 100 JadlionHD"], 22 | permission: [Role.DEVELOPER] 23 | }; 24 | } 25 | 26 | public async execute(base: BaseServer, peer: Peer, text: string, args: string[]): Promise { 27 | if (!args[0]) return peer.send(Variant.from("OnConsoleMessage", `Gems amount are required.`)); 28 | if (!/\d/.test(args[0])) 29 | return peer.send(Variant.from("OnConsoleMessage", `Gems amount are must be a number.`)); 30 | if (args.length > 1) { 31 | const targetPeer = find(base, base.cache.users, (user) => 32 | user.data.tankIDName.toLowerCase().includes(args[1].toLowerCase()) 33 | ); 34 | if (!targetPeer) 35 | return peer.send(Variant.from("OnConsoleMessage", `Make sure that player is online.`)); 36 | 37 | targetPeer.send(Variant.from("OnSetBux", parseInt(args[0]))); 38 | targetPeer.data.gems = parseInt(args[0]); 39 | targetPeer.saveToCache(); 40 | targetPeer.saveToDatabase(); 41 | 42 | peer.send( 43 | Variant.from( 44 | "OnConsoleMessage", 45 | `Sucessfully sending \`w${args[0]}\`\` gems to ${targetPeer.name}` 46 | ) 47 | ); 48 | } else { 49 | peer.send(Variant.from("OnSetBux", parseInt(args[0]))); 50 | peer.data.gems = parseInt(args[0]); 51 | peer.saveToCache(); 52 | // peer.saveToDatabase(); 53 | peer.send(Variant.from("OnConsoleMessage", `Sucessfully received \`w${args[0]}\`\` gems.`)); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/commands/GiveRole.ts: -------------------------------------------------------------------------------- 1 | import { TankPacket, TextPacket, Variant, TankTypes } from "growtopia.js"; 2 | import { Command } from "../abstracts/Command"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import { CommandOptions } from "../types/command"; 6 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 7 | import { Role } from "../utils/Constants"; 8 | import { DataTypes } from "../utils/enums/DataTypes"; 9 | import { find } from "../utils/Utils"; 10 | import { Database } from "../database/db"; 11 | import { QuickDB } from "quick.db"; 12 | const data = new QuickDB 13 | 14 | export default class extends Command { 15 | public opt: CommandOptions; 16 | 17 | constructor() { 18 | super(); 19 | this.opt = { 20 | name: "role", 21 | description: "Role giver", 22 | cooldown: 0, 23 | ratelimit: 1, 24 | category: "Basic", 25 | usage: "/role", 26 | example: ["/role "], 27 | permission: [Role.BASIC, Role.ADMIN, Role.MOD, Role.DEVELOPER] 28 | }; 29 | } 30 | 31 | public async execute(base: BaseServer, peer: Peer, text: string, args: string[], db: Database): Promise { 32 | const targetPeer = find(base, base.cache.users, (user) => 33 | user.data.tankIDName.toLowerCase().includes(args[0].toLowerCase()) 34 | ); 35 | 36 | if(!args[1]) return peer.send(Variant.from("OnConsoleMessage", "Invalid argument.")); 37 | if(parseInt(args[1]) > 4) return peer.send(Variant.from("OnConsoleMessage", "Role is 1,2,3,4")); 38 | 39 | if(!targetPeer) { 40 | peer.send(Variant.from("OnConsoleMessage", "User not found! (User must be online to use this command.)")); 41 | return 42 | } 43 | let role: string = ""; 44 | 45 | if(args[1] === "1") role = Role.DEVELOPER 46 | if(args[1] === "2") role = Role.BASIC 47 | if(args[1] === "3") role = Role.MOD 48 | if(args[1] === "4") role = Role.ADMIN 49 | 50 | //data.set(`Role_${targetPeer.name}`, role) 51 | db.updateRole(targetPeer.data.tankIDName, role) 52 | 53 | targetPeer.data.role = role; 54 | targetPeer.send(Variant.from("OnConsoleMessage", `[ROLE] >> from (${peer.name}) in (${peer.data.world}) > ` + args[1])); 55 | 56 | targetPeer.send(Variant.from("OnTextOverlay", "`4Please wait... saving data and setting role...")) 57 | targetPeer.saveToCache() 58 | targetPeer.saveToDatabase().then(() => { 59 | targetPeer.send(Variant.from("OnTextOverlay", "`2Received`` " + role + "role!")) 60 | }) 61 | 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/commands/Help.ts: -------------------------------------------------------------------------------- 1 | import { Variant } from "growtopia.js"; 2 | import { Command } from "../abstracts/Command"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import { CommandOptions } from "../types/command"; 6 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 7 | import { Role } from "../utils/Constants"; 8 | 9 | export default class extends Command { 10 | public opt: CommandOptions; 11 | 12 | constructor() { 13 | super(); 14 | this.opt = { 15 | name: "help", 16 | description: "Shows every available commands", 17 | cooldown: 5, 18 | ratelimit: 5, 19 | category: "Basic", 20 | usage: "/help ", 21 | example: ["/help", "/help ping"], 22 | permission: [Role.BASIC, Role.ADMIN, Role.DEVELOPER] 23 | }; 24 | } 25 | 26 | public async execute(base: BaseServer, peer: Peer, text: string, args: string[]): Promise { 27 | if (args.length > 0) { 28 | if (!base.commands.has(args[0])) 29 | return peer.send(Variant.from("OnConsoleMessage", `It seems that commands doesn't exist.`)); 30 | let cmd = base.commands.get(args[0]); 31 | 32 | let dialog = new DialogBuilder() 33 | .defaultColor() 34 | .addLabelWithIcon(cmd?.opt.name!, "32", "small") 35 | .addSpacer("small") 36 | .addSmallText(`Description: ${cmd?.opt.description}`) 37 | .addSmallText(`Cooldown: ${cmd?.opt.cooldown}`) 38 | .addSmallText(`Ratelimit: ${cmd?.opt.ratelimit}`) 39 | .addSmallText(`Permissions: ${cmd?.opt.permission.length ? cmd.opt.permission : "None"}`) 40 | .addSmallText(`Usage: ${cmd?.opt.usage}`) 41 | .addSmallText(`Example: ${cmd?.opt.example.join(", ")}`) 42 | .endDialog("help_end", "", "Ok") 43 | .addQuickExit(); 44 | return peer.send(Variant.from("OnDialogRequest", dialog.str())); 45 | 46 | } 47 | 48 | let dialog = new DialogBuilder() 49 | .defaultColor() 50 | .addLabelWithIcon("Help", "32", "small") 51 | .addSpacer("small"); 52 | 53 | base.commands.forEach((cmd) => { 54 | dialog.addLabelWithIcon(cmd.opt.usage, "482", "small"); 55 | }); 56 | 57 | dialog.endDialog("help_end", "", "Ok"); 58 | dialog.addQuickExit(); 59 | peer.send(Variant.from("OnDialogRequest", dialog.str())); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/commands/Invis.ts: -------------------------------------------------------------------------------- 1 | import { TankPacket, TextPacket, Variant, TankTypes } from "growtopia.js"; 2 | import { Command } from "../abstracts/Command"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import { CommandOptions } from "../types/command"; 6 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 7 | import { Role } from "../utils/Constants"; 8 | import { DataTypes } from "../utils/enums/DataTypes"; 9 | import { World } from "../structures/World"; 10 | 11 | export default class extends Command { 12 | public opt: CommandOptions; 13 | 14 | constructor() { 15 | super(); 16 | this.opt = { 17 | name: "invis", 18 | description: "Super broadcast to players online.", 19 | cooldown: 0, 20 | ratelimit: 1, 21 | category: "Basic", 22 | usage: "/invis", 23 | example: ["/invis"], 24 | permission: [Role.BASIC, Role.ADMIN, Role.DEVELOPER] 25 | }; 26 | } 27 | 28 | public async execute(base: BaseServer, peer: Peer, text: string, args: string[]): Promise { 29 | const isInvis = true 30 | const tank = TankPacket.from({ 31 | type: 20, 32 | state: 0x8, 33 | packetType: 17 34 | 35 | 36 | }); 37 | peer.send(tank) 38 | 39 | const world = peer.hasWorld(peer.data.world); 40 | 41 | peer.send(Variant.from({ netID: peer.data.netID }, "OnInvis", 1)) 42 | 43 | 44 | 45 | } 46 | } 47 | 48 | -------------------------------------------------------------------------------- /src/commands/MsgCmd.ts: -------------------------------------------------------------------------------- 1 | import { TankPacket, TextPacket, Variant, TankTypes } from "growtopia.js"; 2 | import { Command } from "../abstracts/Command"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import { CommandOptions } from "../types/command"; 6 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 7 | import { Role } from "../utils/Constants"; 8 | import { DataTypes } from "../utils/enums/DataTypes"; 9 | import { find } from "../utils/Utils"; 10 | import { parseArgs } from "util"; 11 | 12 | export default class extends Command { 13 | public opt: CommandOptions; 14 | 15 | constructor() { 16 | super(); 17 | this.opt = { 18 | name: "msg", 19 | description: "msg", 20 | cooldown: 1, 21 | ratelimit: 1, 22 | category: "Basic", 23 | usage: "/msg", 24 | example: ["/msg"], 25 | permission: [Role.BASIC, Role.ADMIN, Role.DEVELOPER] 26 | }; 27 | } 28 | 29 | public async execute(base: BaseServer, peer: Peer, text: string, args: string[]): Promise { 30 | const targetPeer = find(base, base.cache.users, (user) => 31 | user.data.tankIDName.toLowerCase().includes(args[0].toLowerCase()) 32 | ); 33 | 34 | const cleanedString = args.join(" ").slice(targetPeer?.data.tankIDName.length || 0); 35 | 36 | if(!targetPeer || targetPeer === null) { 37 | peer.send(Variant.from("OnConsoleMessage", "User not found! (User must be online to use this command.)")); 38 | return 39 | } 40 | targetPeer.send(Variant.from("OnConsoleMessage", `[MSG] >> from (${peer.name}) in (${peer.data.world}) > ${cleanedString}`)); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/commands/SB.ts: -------------------------------------------------------------------------------- 1 | import { TextPacket, Variant } from "growtopia.js"; 2 | import { Command } from "../abstracts/Command"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import { CommandOptions } from "../types/command"; 6 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 7 | import { Role } from "../utils/Constants"; 8 | import { DataTypes } from "../utils/enums/DataTypes"; 9 | 10 | export default class extends Command { 11 | public opt: CommandOptions; 12 | 13 | constructor() { 14 | super(); 15 | this.opt = { 16 | name: "sb", 17 | description: "Super broadcast to players online.", 18 | cooldown: 10, 19 | ratelimit: 1, 20 | category: "Basic", 21 | usage: "/sb", 22 | example: ["/sb"], 23 | permission: [Role.BASIC, Role.MOD, Role.DEVELOPER] 24 | }; 25 | } 26 | 27 | public async execute(base: BaseServer, peer: Peer, text: string, args: string[]): Promise { 28 | let gemsLeft = peer.data.gems - 1000 29 | const broadcastMessage = args.join(" "); 30 | 31 | 32 | if(peer.data.gems < 1000) return peer.send(Variant.from("OnConsoleMessage", "Could'nt broadcast, not enough gems.")) 33 | 34 | if(!args[0]) return peer.send(Variant.from("OnConsoleMessage", "Could'nt broadcast, try again with interesting words.")) 35 | 36 | peer.everyPeer((p) => { 37 | p.send(Variant.from("OnConsoleMessage", `** \`pSuper-Broadcast \`0from ${peer.data.tankIDName} (in \`o${peer.data.world}\`0) **: \`#${broadcastMessage}`)); 38 | 39 | 40 | }) 41 | peer.send(Variant.from("OnSetBux", parseInt(`${gemsLeft}`))); 42 | peer.data.gems = parseInt(`${gemsLeft}`); 43 | peer.saveToCache(); 44 | peer.saveToDatabase(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/commands/TradeCmd.ts: -------------------------------------------------------------------------------- 1 | import { TextPacket, Variant } from "growtopia.js"; 2 | import { Command } from "../abstracts/Command"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import { CommandOptions } from "../types/command"; 6 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 7 | import { Role } from "../utils/Constants"; 8 | import { DataTypes } from "../utils/enums/DataTypes"; 9 | import { find } from "../utils/Utils"; 10 | 11 | export default class extends Command { 12 | public opt: CommandOptions; 13 | 14 | constructor() { 15 | super(); 16 | this.opt = { 17 | name: "trade", 18 | description: "Warp to a world, using command.", 19 | cooldown: 1, 20 | ratelimit: 1, 21 | category: "Basic", 22 | usage: "/trade", 23 | example: ["/trade "], 24 | permission: [Role.BASIC, Role.MOD, Role.DEVELOPER] 25 | }; 26 | } 27 | 28 | public async execute(base: BaseServer, peer: Peer, text: string, args: string[]): Promise { 29 | 30 | const world = peer.hasWorld(peer.data.world); 31 | const targetPeer = find(base, base.cache.users, (user) => 32 | user.data.tankIDName.toLowerCase().includes(args[0].toLowerCase()) 33 | ); 34 | 35 | 36 | 37 | // Check for arguments 38 | if (!args[0] || !targetPeer) return peer.send(Variant.from("OnConsoleMessage", "Player not found. Try again with a vaid name.")); 39 | if(!world) return peer.send(Variant.from("OnConsoleMessage", "You must be in a world to use this command.")) 40 | // if(peer.data.world === targetPeer.data.world) return peer.send(Variant.from("OnConsoleMessage", "Hmm... something went wrong, could not find the player in the current world.")) 41 | 42 | peer.send(Variant.from("OnTextOverlay", "Sending trade request to " + targetPeer.name + "...")) 43 | peer.send(Variant.from("OnStartTrade", targetPeer.data.tankIDName, targetPeer.data.netID)) 44 | 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/commands/Warp.ts: -------------------------------------------------------------------------------- 1 | import { TextPacket, Variant } from "growtopia.js"; 2 | import { Command } from "../abstracts/Command"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import { CommandOptions } from "../types/command"; 6 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 7 | import { Role } from "../utils/Constants"; 8 | import { DataTypes } from "../utils/enums/DataTypes"; 9 | 10 | export default class extends Command { 11 | public opt: CommandOptions; 12 | 13 | constructor() { 14 | super(); 15 | this.opt = { 16 | name: "warp", 17 | description: "Warp to a world, using command.", 18 | cooldown: 10, 19 | ratelimit: 1, 20 | category: "Basic", 21 | usage: "/warp", 22 | example: ["/warp "], 23 | permission: [Role.BASIC, Role.MOD, Role.DEVELOPER] 24 | }; 25 | } 26 | 27 | public async execute(base: BaseServer, peer: Peer, text: string, args: string[]): Promise { 28 | 29 | const inapp = ["fuck", "porn", "dick", "pussy", "vargina", "kontol", "memek"] 30 | 31 | if(!args[0]) return peer.send(Variant.from("OnConsoleMessage", "Please mention a world that is vaild.")) 32 | if(args[0].match(/\W+|_|EXIT/gi) || args[0].match("fuck") || args[0].match("porn") || args[0].match("dick") || args[0].match("pussy") || args[0].match("vargina") || args[0].match("kontol") || args[0].match("dick")) 33 | return peer.send(Variant.from("OnConsoleMessage", "Please mention a world that is vaild.")) 34 | 35 | peer.enterWorld(args[0].toUpperCase()) 36 | return peer.send(Variant.from("OnTextOverlay", "Entering world >>> " + args[0] + "...")) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/commands/pv.ts: -------------------------------------------------------------------------------- 1 | import { Variant } from "growtopia.js"; 2 | import { Command } from "../abstracts/Command"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import { CommandOptions } from "../types/command"; 6 | import { Role } from "../utils/Constants"; 7 | import { find } from "../utils/Utils"; 8 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 9 | 10 | export default class extends Command { 11 | public opt: CommandOptions; 12 | 13 | constructor() { 14 | super(); 15 | this.opt = { 16 | name: "punishview", 17 | description: "Ban/Mute/Warn user", 18 | cooldown: 5, 19 | ratelimit: 5, 20 | category: "Developer", 21 | usage: "/punishview ", 22 | example: ["/givegems 100", "/givegems 100 JadlionHD"], 23 | permission: [Role.DEVELOPER] 24 | }; 25 | } 26 | 27 | public async execute(base: BaseServer, peer: Peer, text: string, args: string[]): Promise { 28 | if(!args[0]) return; 29 | 30 | const targetPeer = find(base, base.cache.users, (user) => 31 | user.data.tankIDName.toLowerCase().includes(args[0].toLowerCase()) 32 | ); 33 | 34 | if(!targetPeer) 35 | return peer.send(Variant.from("OnConsoleMessage", `Make sure that player is online.`)); 36 | 37 | let p; 38 | 39 | if(targetPeer.data.role === "1") p = "Developer" 40 | if(targetPeer.data.role === "2") p = "Basic" 41 | if(targetPeer.data.role === "3") p = "Moderator" 42 | if(targetPeer.data.role === "4") p = "Admin" 43 | 44 | let dialog = new DialogBuilder() 45 | .defaultColor() 46 | .addLabelWithIcon("Editing " + targetPeer.name + ` #${targetPeer.data.id_user}`, "32", "small") 47 | .addSpacer("small") 48 | .addSmallText("`bAccount information:") 49 | .addSmallText(`[!] Raw name: ${targetPeer.data.tankIDName}`) 50 | .addSmallText(`[!] UserID: #${targetPeer.data.id_user}`) 51 | .addSmallText(`[!] NetID: ${targetPeer.data.netID}`) 52 | .addSmallText(`[!] Country: ${targetPeer.data.country}`) 53 | .addSmallText(`[!] Gems: ${targetPeer.data.gems}`) 54 | .addSmallText(`[!] Role: ${p}`) 55 | .addSmallText(`[!] Current world: ${targetPeer.data.world}`) 56 | .addSpacer("big") 57 | .addCustomBreak() 58 | .addButtonWithIcon("ban_users", "732", " Ban ") 59 | .addButtonWithIcon("curse_user", "278", " Curse ") 60 | .addButtonWithIcon("mute_user", "408", "Duct tape") 61 | .addButtonWithIcon("warn_user", "1432", " Warn user") 62 | .addCustomBreak() 63 | .addSpacer("small") 64 | .addInputBox("time", "Time:", "In minutes.", 15) 65 | .addInputBox("reason", "Reason:", "", 25) 66 | .addSpacer("small") 67 | .addSmallText("`4(This is only for warning user, DO NOT ABUSE!)") 68 | .addInputBox("warning", "Warning:", "", 30) 69 | .addSpacer("small") 70 | .endDialog("ban_user", "Cancel", "Ok") 71 | .str() 72 | 73 | peer.send(Variant.from("OnDialogRequest", dialog)); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/dialogs/BanUser.ts: -------------------------------------------------------------------------------- 1 | import { Variant } from "growtopia.js"; 2 | import { Dialog } from "../abstracts/Dialog"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import { DialogReturnType } from "../types/dialog"; 6 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 7 | import { parseAction } from "../utils/Utils"; 8 | import { Database } from "../database/db"; 9 | import { World } from "../structures/World"; 10 | 11 | export default class extends Dialog { 12 | constructor() { 13 | super(); 14 | this.config = { 15 | dialogName: "ban_user" 16 | }; 17 | } 18 | 19 | public handle( 20 | base: BaseServer, 21 | peer: Peer, 22 | db: Database, 23 | // world: World, 24 | action: DialogReturnType<{ 25 | action: string; 26 | dialog_name: string; 27 | find_item_name: string; 28 | seed_only: string; 29 | time: string; 30 | reason: string; 31 | buttonClicked: string; 32 | targetPeer: Peer; 33 | }> 34 | ): void {//OnAddNotification 35 | 36 | 37 | if(!action.time) return peer.send(Variant.from("OnTextOverlay", "Could not specify time of ban.")) 38 | if(!action.reason) return peer.send(Variant.from("OnTextOverlay", "Could not specify time of ban.")) 39 | //if(!action.buttonClicked) return; 40 | 41 | if(action.buttonClicked === "ban_users"){ 42 | peer.send(Variant.from("OnAddNotification", "", "Warning from `4System`0: You've been `4BANNED `0from GrowJS for " + action.time + "days.")) 43 | //peer.disconnect() 44 | peer.data.clothing?.mask == 408 45 | peer.sendClothes() 46 | 47 | }else{ 48 | return; 49 | } 50 | 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/dialogs/CGDialog.ts: -------------------------------------------------------------------------------- 1 | import { TankPacket, TextPacket, Variant } from "growtopia.js"; 2 | import { Dialog } from "../abstracts/Dialog"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import { tileUpdate } from "../tanks/BlockPlacing"; 6 | import { DialogReturnType } from "../types/dialog"; 7 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 8 | import { DataTypes } from "../utils/enums/DataTypes"; 9 | import { TankTypes } from "../utils/enums/TankTypes"; 10 | import { Database } from "../database/db"; 11 | import { World } from "../structures/World"; 12 | import { QuickDB } from "quick.db"; 13 | import { Block } from "../types/world"; 14 | import { ActionTypes } from "../utils/enums/Tiles"; 15 | const data = new QuickDB 16 | 17 | 18 | 19 | 20 | export default class extends Dialog { 21 | constructor() { 22 | super(); 23 | this.config = { 24 | dialogName: "CGDialog" 25 | }; 26 | } 27 | 28 | public handle( 29 | base: BaseServer, 30 | peer: Peer, 31 | db: Database, 32 | action: DialogReturnType<{ 33 | action: string; 34 | dialog_name: string; 35 | buttonClicked: string; 36 | guild_name: string; 37 | guild_statement: string; 38 | }> 39 | ): void { 40 | 41 | // const world = peer.hasWorld(peer.data.world); 42 | //const pos = t.data.xPunch! + tank.data.yPunch! * world?.data.width!; 43 | //const block = world?.data.blocks![pos]!; 44 | 45 | if(action.buttonClicked === "create"){ 46 | if(!action.guild_name || !action.guild_statement) return peer.send(Variant.from("OnTalkBubble", peer.data.netID, "`4Guild Creation Failed`0: Please fill all the fields.")); 47 | const world = peer.hasWorld(peer.data.world); 48 | if(world?.data.owner?.id !== peer.data.id_user) return peer.send(Variant.from("OnTalkBubble", peer.data.netID, "You need to be in a empty world to create a guild!")); 49 | //peer.send(Variant.from({ netID: peer.data.netID }, "OnGuildDataChanged", 50478, 79289404, 100)); 50 | //peer.send(Variant.from({ netID: peer.data.netID }, "OnNameChanged", peer.data.tankIDName + " of Legend" + "``")); 51 | 52 | peer.send(Variant.from("OnTalkBubble", peer.data.netID, "Guild created!")); 53 | 54 | world.place({ 55 | peer: peer, 56 | x: peer.data.x!, 57 | y: peer.data.y!, 58 | id: 5814, 59 | fruit: 1, 60 | }) 61 | //tileUpdate(base, peer, ActionTypes.LOCK, block, world) 62 | //peer.send(Variant.from({ netID: peer.data.netID }, "OnCountryState", "|showGuild")); 63 | //peer.send(Variant.from({ netID: peer.data.netID }, "OnParticleEffect", 48, peer.data.x! + 10, peer.data.y! + 16)) 64 | //peer.send(Variant.from({ netID: peer.data.netID }, "OnInvis", 1)) 65 | // db.guildCreate(action.guild_name, peer.data.tankIDName, 1, true) 66 | data.set(`guild_${peer.data.tankIDName}`, action.guild_name) // guild name , 67 | data.set(`guildDescription_${action.guild_name}`, action.guild_statement) // description 68 | data.set(`guildLeader_${action.guild_name}`, peer.data.tankIDName) //guild leader 69 | data.set(`guildMembers_${action.guild_name}`, []) ////guild members, 70 | data.set(`guildLevel_${action.guild_name}`, 1) //guild level, 71 | data.set(`guildMascot_${action.guild_name}`, 0) //guild mascot, 72 | data.set(`guildWorld_${action.guild_name}`, peer.data.world)//guild world 73 | peer.saveToCache() 74 | peer.saveToDatabase() 75 | } 76 | } 77 | } -------------------------------------------------------------------------------- /src/dialogs/Carnival.ts: -------------------------------------------------------------------------------- 1 | import { Variant } from "growtopia.js"; 2 | import { Dialog } from "../abstracts/Dialog"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import { DialogReturnType } from "../types/dialog"; 6 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 7 | import { Database } from "../database/db"; 8 | import { WorldData, WorldDB } from "../types/world"; 9 | import { QuickDB } from "quick.db"; 10 | import { World } from "../structures/World"; 11 | const data = new QuickDB 12 | 13 | export default class extends Dialog { 14 | constructor() { 15 | super(); 16 | this.config = { 17 | dialogName: "ring_master" 18 | }; 19 | } 20 | 21 | public async handle( 22 | base: BaseServer, 23 | peer: Peer, 24 | db: Database, 25 | // world: World, 26 | action: DialogReturnType<{ 27 | action: string; 28 | dialog_name: string; 29 | buttonClicked: string; 30 | }> 31 | ): Promise { 32 | // 33 | const OnQuest = await data.get(`OnQuest_${peer.data.id_user}`) 34 | /** 35 | * Randomiser 36 | */ 37 | function shuffleArray(array: string[]): string { 38 | const shuffledArray = [...array]; 39 | for (let i = shuffledArray.length - 1; i > 0; i--) { 40 | const j = Math.floor(Math.random() * (i + 1)); 41 | [shuffledArray[i], shuffledArray[j]] = [shuffledArray[j], shuffledArray[i]]; 42 | } 43 | return shuffledArray[0]; // Return the first (random) item 44 | } 45 | 46 | // Example usage: 47 | const deliverItems = ["Dirts", "World Locks", "Fire Escape", "Buffalo", "Diamond Wings", "Blazing Electro Wings", "Diamond Diaper"]; 48 | const randomItem = shuffleArray(deliverItems); 49 | 50 | //console.log(randomItem); // Log the randomly selected item 51 | 52 | 53 | 54 | 55 | /**Random num */ 56 | function getRandomInt(min: number, max: number): number { 57 | min = Math.ceil(min); 58 | max = Math.floor(max); 59 | return Math.floor(Math.random() * (max - min)) + min; 60 | } 61 | 62 | // Example: Generate a random number between 1 and 10 (inclusive) 63 | const randomNum = getRandomInt(1, 200); 64 | 65 | if(action.buttonClicked === "ring_masters"){ 66 | console.log("Clicked!") 67 | const items = peer.data.inventory?.items 68 | 69 | if (items) { 70 | //const itemNameToFind = 'SpecificItemName'; // Replace with the name of the item you want to find 71 | 72 | const foundItem = items.find(item => item.id === 1898); 73 | const amount = items.find(item => item.amount === 10) 74 | 75 | if(foundItem && amount) { 76 | const dialog = new DialogBuilder() 77 | .defaultColor() 78 | .addLabelWithIcon(`\`9Quest For The Ring`, 1900, "big") 79 | .addSmallText(`(Step 1/1)`) 80 | .addSpacer("small") 81 | .addSmallText(`Your task is to bring me ${randomNum} of them ${randomItem} things!`) 82 | .addSpacer("small") 83 | .addSmallText(`(Current progress 0/${randomNum})`) 84 | .addButton("deliver", `\`9Deliver ${randomNum} ${randomItem}`) 85 | .addButton("giveup", "\`9Give up this quest") 86 | .addSpacer("small") 87 | .addSmallText("If you had 10 rings of the same type maybe we could have made a deal...") 88 | .addSpacer("small") 89 | .endDialog("noob", "Goodbye", "") 90 | .str() 91 | 92 | peer.send(Variant.from("OnDialogRequest", dialog)); 93 | 94 | data.set(`OnQuest_${peer.data.id_user}`, true) 95 | data.set(`Item_${peer.data.id_user}`, `${randomItem}`) 96 | data.set(`Count_${peer.data.id_user}`, `${randomNum}`) 97 | 98 | } 99 | 100 | 101 | } 102 | 103 | } 104 | 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/dialogs/DQend.ts: -------------------------------------------------------------------------------- 1 | import { Variant } from "growtopia.js"; 2 | import { Dialog } from "../abstracts/Dialog"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import { DialogReturnType } from "../types/dialog"; 6 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 7 | import { Database } from "../database/db"; 8 | import { ItemsDat } from "itemsdat"; 9 | import { QuickDB } from "quick.db"; 10 | const data = new QuickDB 11 | 12 | export default class extends Dialog { 13 | constructor() { 14 | super(); 15 | this.config = { 16 | dialogName: "crazy_jims" 17 | }; 18 | } 19 | 20 | public async handle( 21 | base: BaseServer, 22 | peer: Peer, 23 | db: Database, 24 | action: DialogReturnType<{ 25 | action: string; 26 | dialog_name: string; 27 | number: string; 28 | //seed_only: string; 29 | buttonClicked: string; 30 | }> 31 | ): Promise { 32 | 33 | if(action.buttonClicked === "turn_in"){ 34 | peer.send(Variant.from("OnAddNotification", peer.data.netID, "Received 1 `2Growtoken`0!")) 35 | 36 | peer.addItemInven(1486, 1) 37 | peer.inventory() 38 | peer.saveToCache() 39 | 40 | data.set(`dqCompleted`, true) 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/dialogs/DailyQuest.ts: -------------------------------------------------------------------------------- 1 | import { Variant } from "growtopia.js"; 2 | import { Dialog } from "../abstracts/Dialog"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import { DialogReturnType } from "../types/dialog"; 6 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 7 | import { Database } from "../database/db"; 8 | import { ItemsDat } from "itemsdat"; 9 | import { QuickDB } from "quick.db"; 10 | import { World } from "../structures/World"; 11 | const data = new QuickDB 12 | 13 | export default class extends Dialog { 14 | constructor() { 15 | super(); 16 | this.config = { 17 | dialogName: "crazy_jim" 18 | }; 19 | } 20 | 21 | public async handle( 22 | base: BaseServer, 23 | peer: Peer, 24 | db: Database, 25 | // world: World, 26 | action: DialogReturnType<{ 27 | action: string; 28 | dialog_name: string; 29 | number: string; 30 | //seed_only: string; 31 | buttonClicked: string; 32 | }> 33 | ): Promise { 34 | 35 | const dqItem1 = await data.get(`dqItem1`) 36 | const dqItem2 = await data.get(`dqItem2`) 37 | const dqCount1 = await data.get(`dqCount1`) 38 | const dqCount2 = await data.get(`dqCount2`) 39 | const dqCompleted = await data.get(`dqCompleted`) 40 | 41 | const items = base.items.metadata.items 42 | const peerInv = peer.data.inventory?.items 43 | 44 | const foundItem = items.find((item) => item.id === dqItem1); 45 | const foundItem2 = items.find((item) => item.id === dqItem2); 46 | // Vaildation 47 | const peerHave = peerInv?.find(item => item.id === dqItem1); 48 | //const amount = peerInv?.find(item => item.amount === dqCount1) 49 | 50 | const peerHave2 = peerInv?.find(item => item.id === dqItem2); 51 | // const amount2 = peerInv?.find(item => item.amount === dqCount2) 52 | 53 | let i; 54 | if(peerHave?.amount === undefined && peerHave2?.amount === undefined) i = 0 55 | 56 | 57 | if(action.buttonClicked === "dq") { 58 | let dialog = new DialogBuilder() 59 | .defaultColor() 60 | .addLabelWithIcon("Crazy Jim's Daily Quest", "3902", "big") 61 | .addSmallText("I guess some people call me Crazy Jim because I'am a bit of a hoarder. But I'm very particular about what I want! And today, what I want is this:") 62 | .addLabelWithIcon(`\`2${dqCount1} ${foundItem?.name}`, `${dqItem1}`, "small") 63 | .addSmallText("and") 64 | .addLabelWithIcon(`\`2${dqCount2} ${foundItem2?.name}`, `${dqItem2}`, "small") 65 | .addSpacer("small") 66 | .addSmallText("You shave all that through the phone (It works, I've tried it), and I will hand you one of the `2Growtokens `0from my personal collection! But hurry, this offer is only good until midnight, and only one `2Growtoken `0per person.") 67 | .addSpacer("small") 68 | .addSmallText(`\`8(You have ${peerHave?.amount !== undefined ? peerHave.amount : 0} ${foundItem?.name} and ${peerHave2?.amount !== undefined ? peerHave2.amount : 0} ${foundItem2?.name})`) 69 | 70 | if(peerHave?.amount! == dqCount1 && peerHave2?.amount == dqCount2 && dqCompleted === false){ 71 | dialog.addButton("turn_in", "Turn in!") 72 | } 73 | if(dqCompleted === true){ 74 | dialog.addSmallText("`4(You have completed today's Daily Quest task, come back tommorrow)") 75 | } 76 | 77 | dialog.endDialog("crazy_jims", "Hang Up", "Back") 78 | //.str() 79 | 80 | peer.send(Variant.from("OnDialogRequest", dialog.str())); 81 | 82 | 83 | 84 | 85 | 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/dialogs/DoorEdit.ts: -------------------------------------------------------------------------------- 1 | import { TankPacket, TextPacket, Variant } from "growtopia.js"; 2 | import { Dialog } from "../abstracts/Dialog"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import { tileUpdate } from "../tanks/BlockPlacing"; 6 | import { DialogReturnType } from "../types/dialog"; 7 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 8 | import { DataTypes } from "../utils/enums/DataTypes"; 9 | import { TankTypes } from "../utils/enums/TankTypes"; 10 | import { Database } from "../database/db"; 11 | import { World } from "../structures/World"; 12 | 13 | export default class extends Dialog { 14 | constructor() { 15 | super(); 16 | this.config = { 17 | dialogName: "door_edit" 18 | }; 19 | } 20 | 21 | public handle( 22 | base: BaseServer, 23 | peer: Peer, 24 | db: Database, 25 | // world: World, 26 | action: DialogReturnType<{ 27 | action: string; 28 | dialog_name: string; 29 | tilex: string; 30 | tiley: string; 31 | itemID: string; 32 | label?: string; 33 | target?: string; 34 | id?: string; 35 | }> 36 | ): void { 37 | const world = peer.hasWorld(peer.data.world); 38 | const pos = parseInt(action.tilex) + parseInt(action.tiley) * world?.data.width!; 39 | const block = world?.data.blocks![pos]!; 40 | const itemMeta = base.items.metadata.items.find((i) => i.id === parseInt(action.itemID)); 41 | 42 | if (world?.data.owner) { 43 | if (world?.data.owner.id !== peer.data.id_user) return; 44 | } 45 | 46 | block.door!.label = action.label || ""; 47 | block.door!.destination = action.target?.toUpperCase() || ""; 48 | block.door!.id = action.id?.toUpperCase() || ""; 49 | 50 | tileUpdate(base, peer, itemMeta?.type!, block, world!); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/dialogs/FindItemEnd.ts: -------------------------------------------------------------------------------- 1 | import { Variant } from "growtopia.js"; 2 | import { Dialog } from "../abstracts/Dialog"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import { DialogReturnType } from "../types/dialog"; 6 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 7 | import { Database } from "../database/db"; 8 | 9 | export default class extends Dialog { 10 | constructor() { 11 | super(); 12 | this.config = { 13 | dialogName: "find_item_end" 14 | }; 15 | } 16 | 17 | public handle( 18 | base: BaseServer, 19 | peer: Peer, 20 | db: Database, 21 | action: DialogReturnType<{ 22 | action: string; 23 | dialog_name: string; 24 | find_item_name: string; 25 | buttonClicked: string; 26 | }> 27 | ): void { 28 | const itemID = parseInt(action.buttonClicked); 29 | peer.data.inventory?.items.push({ id: itemID, amount: 200 }); 30 | peer.send( 31 | Variant.from( 32 | "OnConsoleMessage", 33 | `Added \`6${ 34 | base.items.metadata.items.find((v) => v.id === itemID)?.name 35 | }\`\` to your inventory.` 36 | ) 37 | ); 38 | peer.inventory(); 39 | peer.saveToCache(); 40 | // peer.saveToDatabase(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/dialogs/FriendList.ts: -------------------------------------------------------------------------------- 1 | import { Variant } from "growtopia.js"; 2 | import { Dialog } from "../abstracts/Dialog"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import { DialogReturnType } from "../types/dialog"; 6 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 7 | import { parseAction } from "../utils/Utils"; 8 | import { Database } from "../database/db"; 9 | import { World } from "../structures/World"; 10 | import { QuickDB } from "quick.db"; 11 | const data = new QuickDB 12 | 13 | export default class extends Dialog { 14 | constructor() { 15 | super(); 16 | this.config = { 17 | dialogName: "FriendsDialog" 18 | }; 19 | } 20 | 21 | public async handle( 22 | base: BaseServer, 23 | peer: Peer, 24 | db: Database, 25 | // world: World, 26 | action: DialogReturnType<{ 27 | action: string; 28 | dialog_name: string; 29 | find_item_name: string; 30 | seed_only: string; 31 | time: string; 32 | reason: string; 33 | buttonClicked: string; 34 | targetPeer: Peer; 35 | }> 36 | ): Promise {//OnAddNotification 37 | const friends = await data.get(`Friend_${peer.data.tankIDName}`) || []; 38 | 39 | 40 | if(action.buttonClicked === "friendsList"){ 41 | 42 | if (Array.isArray(friends)) { 43 | const numberOfFriends = friends.length; 44 | 45 | let g; 46 | 47 | if(numberOfFriends < 1 || !numberOfFriends) g = 0 48 | 49 | 50 | const dialog = new DialogBuilder() 51 | .defaultColor() 52 | .addLabelWithIcon(`0 of ${numberOfFriends || g} Friends Online`, "1366", "big") 53 | .endDialog("close", "", "Close") 54 | .addSpacer("big") 55 | if (Array.isArray(friends)) { 56 | for (const friend of friends) { 57 | const friendTankIDName = friend.data.tankIDName; 58 | const targetPeer = base.cache.users.findPeer((p) => p.data.tankIDName === friendTankIDName); 59 | 60 | 61 | if(targetPeer){ 62 | // console.log(friendTankIDName); 63 | dialog.addButton(friendTankIDName, `${friendTankIDName} (Status: \`2Online\`0)`); 64 | } 65 | // Do something with the friend data 66 | } 67 | } else { 68 | dialog.addSmallText("Such a lonely person, get a friend by doing /addfriend .") 69 | } 70 | dialog.addSpacer("big") 71 | dialog.addQuickExit() 72 | dialog.addButton("friends_settings", "Friends Settings") 73 | dialog.addButton("offline", "Show offline") 74 | dialog.endDialog("Friends1", "", "Close") 75 | 76 | peer.send(Variant.from({ delay: 100 }, "OnDialogRequest", dialog.str())); 77 | 78 | } 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/dialogs/GuiildCreate.ts: -------------------------------------------------------------------------------- 1 | import { TankPacket, TextPacket, Variant } from "growtopia.js"; 2 | import { Dialog } from "../abstracts/Dialog"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import { tileUpdate } from "../tanks/BlockPlacing"; 6 | import { DialogReturnType } from "../types/dialog"; 7 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 8 | import { DataTypes } from "../utils/enums/DataTypes"; 9 | import { TankTypes } from "../utils/enums/TankTypes"; 10 | import { Database } from "../database/db"; 11 | import { World } from "../structures/World"; 12 | 13 | export default class extends Dialog { 14 | constructor() { 15 | super(); 16 | this.config = { 17 | dialogName: "FriendsDialog" 18 | }; 19 | } 20 | 21 | public handle( 22 | base: BaseServer, 23 | peer: Peer, 24 | db: Database, 25 | action: DialogReturnType<{ 26 | action: string; 27 | dialog_name: string; 28 | buttonClicked: string; 29 | }> 30 | ): void { 31 | if(action.buttonClicked === "CG"){ 32 | const dialog1 = new DialogBuilder() 33 | .defaultColor() 34 | .addLabelWithIcon("GrowAsia Guild Creation", 5814, "big") 35 | .addSmallText("[`4BETA``] To create guild, fill all the empty fields.") 36 | .addSmallText("`4Disclaimer``: Guild creation is currently in beta.") 37 | .addSmallText("`4Inappropriate guild creation will result in a ban.") 38 | .addSpacer("small") 39 | .addInputBox("guild_name", "Guild Name:", "", 10) 40 | .addSpacer("small") 41 | .addInputBox("guild_statement", "Guild Statement:", "", 30) 42 | .addSpacer("small") 43 | .addButton("create", "Create!") 44 | .endDialog("CGDialog", "", "Close") 45 | .addQuickExit() 46 | //.str(); 47 | 48 | peer.send(Variant.from("OnDialogRequest", dialog1.str())); 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /src/dialogs/LockEdit.ts: -------------------------------------------------------------------------------- 1 | import { TankPacket, TextPacket, Variant } from "growtopia.js"; 2 | import { Dialog } from "../abstracts/Dialog"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import { tileUpdate } from "../tanks/BlockPlacing"; 6 | import { DialogReturnType } from "../types/dialog"; 7 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 8 | import { DataTypes } from "../utils/enums/DataTypes"; 9 | import { TankTypes } from "../utils/enums/TankTypes"; 10 | import { Database } from "../database/db"; 11 | import { World } from "../structures/World"; 12 | 13 | export default class extends Dialog { 14 | constructor() { 15 | super(); 16 | this.config = { 17 | dialogName: "lock_edit" 18 | }; 19 | } 20 | 21 | public handle( 22 | base: BaseServer, 23 | peer: Peer, 24 | db: Database, 25 | action: DialogReturnType<{ 26 | action: string; 27 | dialog_name: string; 28 | playerNetID: number; 29 | }> 30 | ): void { 31 | const world = peer.hasWorld(peer.data.world); 32 | const newAdminsArray: number[] = [action.playerNetID]; 33 | 34 | if (action.playerNetID) { 35 | if (action.playerNetID === peer.data.netID) { 36 | return peer.send(Variant.from("OnTalkBubble", "You already have access!")); 37 | } 38 | 39 | const data = world?.data; 40 | 41 | // Assign the admins property to the variable 42 | data!.admins = newAdminsArray; 43 | 44 | //world?.saveToDatabase(); // Save the world to the database 45 | 46 | // Send a chat message to notify the player 47 | peer.send(Variant.from("OnConsoleMessage", "New admin added!")); 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /src/dialogs/Noob.ts: -------------------------------------------------------------------------------- 1 | import { Variant } from "growtopia.js"; 2 | import { Dialog } from "../abstracts/Dialog"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import { DialogReturnType } from "../types/dialog"; 6 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 7 | import { Database } from "../database/db"; 8 | import { WorldData, WorldDB } from "../types/world"; 9 | import { QuickDB } from "quick.db"; 10 | import { parseAction } from "../utils/Utils"; 11 | const data = new QuickDB 12 | 13 | export default class extends Dialog { 14 | constructor() { 15 | super(); 16 | this.config = { 17 | dialogName: "noob" 18 | }; 19 | } 20 | 21 | public async handle( 22 | base: BaseServer, 23 | peer: Peer, 24 | db: Database, 25 | action: DialogReturnType<{ 26 | action: string; 27 | dialog_name: string; 28 | buttonClicked: string; 29 | }> 30 | ): Promise { 31 | //const items = peer.data.inventory?.items 32 | 33 | 34 | 35 | if(action.buttonClicked === "deliver"){ 36 | const items = peer.data.inventory?.items 37 | 38 | 39 | const DataItem = await data.get(`Item_${peer.data.id_user}`) 40 | console.log(DataItem) 41 | const Count = await data.get(`Count_${peer.data.id_user}`) 42 | console.log(Count) 43 | let i: number; 44 | if(DataItem === "Dirts") i = 2 45 | if(DataItem === "World Locks") i = 242 46 | if(DataItem === "Fire Escape") i = 998 47 | if(DataItem === "Buffalo") i = 1044 48 | if(DataItem === "Diamond Wings") i = 1938 49 | if(DataItem === "Blazing Electro Wings") i = 1936 50 | if(DataItem === "Diamond Diaper") i = 1944 51 | 52 | 53 | 54 | // Vaild Data 55 | const foundItem = items?.find(item => item.id === i); 56 | const amount = items?.find(item => item.amount === Count) 57 | 58 | if(!foundItem && !amount){ 59 | return peer.send(Variant.from("OnTextOverlay", "Get to work!")) 60 | } 61 | /// if(foundItem && amount){ 62 | // Reward 63 | function shuffleArray(array: string[]): string { 64 | const shuffledArray = [...array]; 65 | for (let i = shuffledArray.length - 1; i > 0; i--) { 66 | const j = Math.floor(Math.random() * (i + 1)); 67 | [shuffledArray[i], shuffledArray[j]] = [shuffledArray[j], shuffledArray[i]]; 68 | } 69 | return shuffledArray[0]; // Return the first (random) item 70 | } 71 | 72 | // Example usage: 73 | const deliverItems = ["Gemini Ring", "Ring Of Winds", "Ring Of Force", "Ring Of Water"]; 74 | const randomItem = shuffleArray(deliverItems); 75 | console.log(randomItem) 76 | 77 | let ok: number; 78 | if(randomItem === "Gemini Ring") ok = 1986 79 | if(randomItem === "Ring Of Winds") ok = 1876 80 | if(randomItem === "Ring Of Force") ok = 1874 81 | if(randomItem === "Ring Of Water") ok = 2970 82 | 83 | data.set(`OnQuest_${peer.data.id_user}`, false) 84 | peer.send(Variant.from("OnAddNotification", 200, "Congratulations! You got " + randomItem)) 85 | //peer.data.inventory?.items.push({ id: i!, amount: Count }); 86 | peer.addItemInven(ok!, 1) 87 | //peer.sendClothes() 88 | peer.inventory() 89 | peer.saveToCache() 90 | 91 | 92 | //} 93 | } 94 | 95 | 96 | if(action.buttonClicked === "giveup"){ 97 | data.set(`OnQuest_${peer.data.id_user}`, false) 98 | } 99 | 100 | //peer.send(Variant.from("OnTextOverlay", "Goodbye!")) 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/dialogs/RegisterEnd.ts: -------------------------------------------------------------------------------- 1 | import { Variant } from "growtopia.js"; 2 | import { Dialog } from "../abstracts/Dialog"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import { DialogReturnType } from "../types/dialog"; 6 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 7 | import { Database } from "../database/db"; 8 | import { WorldData, WorldDB } from "../types/world"; 9 | import { QuickDB } from "quick.db"; 10 | const data = new QuickDB 11 | 12 | export default class extends Dialog { 13 | constructor() { 14 | super(); 15 | this.config = { 16 | dialogName: "register_end" 17 | }; 18 | } 19 | 20 | public async handle( 21 | base: BaseServer, 22 | peer: Peer, 23 | db: Database, 24 | action: DialogReturnType<{ 25 | action: string; 26 | dialog_name: string; 27 | register_name: string; 28 | register_password: string; 29 | }> 30 | ): Promise { 31 | 32 | let checkuser = await db.getUser(action.register_name) 33 | 34 | if(action.register_name.length < 3 || null){ 35 | return peer.send(Variant.from("OnConsoleMessage", "`4GrowID: Too short")) 36 | } else if(action.register_password.length < 3 || null){ 37 | return peer.send(Variant.from("OnConsoleMessage", "`4Password: Too short")) 38 | }else if(checkuser?.name.toLocaleLowerCase(action.register_name)){ 39 | console.log('checkuser?.name:', checkuser?.name); 40 | console.log('action.register_name:', action.register_name); 41 | 42 | return peer.send(Variant.from("OnConsoleMessage", "`4GrowID: Already registered")) 43 | }else{ 44 | 45 | 46 | 47 | 48 | 49 | db.createUser(action.register_name, action.register_password) 50 | return peer.send(Variant.from("OnConsoleMessage", "`2Successfully registered! Re-log required.")) 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/dialogs/SignEdit.ts: -------------------------------------------------------------------------------- 1 | import { TankPacket, TextPacket, Variant } from "growtopia.js"; 2 | import { Dialog } from "../abstracts/Dialog"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import { tileUpdate } from "../tanks/BlockPlacing"; 6 | import { DialogReturnType } from "../types/dialog"; 7 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 8 | import { DataTypes } from "../utils/enums/DataTypes"; 9 | import { TankTypes } from "../utils/enums/TankTypes"; 10 | import { Database } from "../database/db"; 11 | 12 | export default class extends Dialog { 13 | constructor() { 14 | super(); 15 | this.config = { 16 | dialogName: "sign_edit" 17 | }; 18 | } 19 | 20 | public handle( 21 | base: BaseServer, 22 | peer: Peer, 23 | db: Database, 24 | action: DialogReturnType<{ 25 | action: string; 26 | dialog_name: string; 27 | tilex: string; 28 | tiley: string; 29 | itemID: string; 30 | label?: string; 31 | }> 32 | ): void { 33 | const world = peer.hasWorld(peer.data.world); 34 | const pos = parseInt(action.tilex) + parseInt(action.tiley) * world?.data.width!; 35 | const block = world?.data.blocks![pos]!; 36 | const itemMeta = base.items.metadata.items.find((i) => i.id === parseInt(action.itemID)); 37 | 38 | if (world?.data.owner) { 39 | if (world.data.owner.id !== peer.data.id_user) return; 40 | } 41 | 42 | block.sign!.label = action.label || ""; 43 | 44 | tileUpdate(base, peer, itemMeta?.type!, block, world!); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/dialogs/Surgery.ts: -------------------------------------------------------------------------------- 1 | import { Variant } from "growtopia.js"; 2 | import { Dialog } from "../abstracts/Dialog"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import { DialogReturnType } from "../types/dialog"; 6 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 7 | import { Database } from "../database/db"; 8 | import { WorldData, WorldDB } from "../types/world"; 9 | import { QuickDB } from "quick.db"; 10 | const data = new QuickDB 11 | 12 | export default class extends Dialog { 13 | constructor() { 14 | super(); 15 | this.config = { 16 | dialogName: "surgery" 17 | }; 18 | } 19 | 20 | public handle( 21 | base: BaseServer, 22 | peer: Peer, 23 | db: Database, 24 | action: DialogReturnType<{ 25 | action: string; 26 | dialog_name: string; 27 | buttonClicked: string; 28 | }> 29 | ): void { 30 | // Set 31 | let onSurgery = false 32 | let finished = false 33 | 34 | 35 | function shuffleArray(array: T[]): T | undefined { 36 | if (array.length === 0) { 37 | return undefined; // Return undefined for an empty array 38 | } 39 | const randomIndex = Math.floor(Math.random() * array.length); 40 | return array[randomIndex]; 41 | } 42 | 43 | 44 | // Example usage: 45 | const originalArray = ["Patient broke his leg.", "Patient has flu.", "Patient ate a world lock!"]; 46 | const pulseArray = ["`2Strong", "`1Steady", "`4Weak"] 47 | const statusArray = ["`4Awake", "`2Unconscious", "`8Coming too..."] 48 | const tempArray = ["`298.6", "`4100.6", "`290.6", "`4103.6", "`4106.6"] 49 | const OperationArray = ["`8Unclean", "`2Clean", "`1Not sanitized", "`4Unsanitary"] 50 | 51 | const patient = shuffleArray(originalArray) as unknown as string 52 | const pulse = shuffleArray(pulseArray) as unknown as string 53 | const status = shuffleArray(statusArray) as unknown as string 54 | const temp = shuffleArray(tempArray) as unknown as string 55 | const Operation = shuffleArray(OperationArray) as unknown as string 56 | 57 | if(action.buttonClicked === "button_ok"){ 58 | let onSurgery = true 59 | // 1 60 | console.log(pulse); 61 | console.log(patient) 62 | 63 | 64 | const dialog = new DialogBuilder() 65 | .defaultColor() 66 | .addLabelWithIcon("Surg-E Robot", "18", "big") 67 | .addSmallText(`\`4The patient has not been diagnosed!`) 68 | .addSmallText(`Pulse: \`1${pulse} \`0Status: \`4Awake`) 69 | .addSmallText("Temp: `298.6\`0 Operation site: `8Unclean") 70 | .addSmallText("Incisions: `10") 71 | .addSpacer("big") 72 | .addCustomBreak() 73 | .addButtonWithIcon(1258, 1258, "", "staticBlueFrame") // sponge 74 | .addButtonWithIcon(1260, 1260, "", "staticBlueFrame") // scalpe 75 | .addButtonWithIcon(1270, 1270, "", "staticBlueFrame") // stitches 76 | .addButtonWithIcon(1266, 1266, "", "staticBlueFrame") // anti-boi 77 | .addButtonWithIcon(1264, 1264, "", "staticBlueFrame") // anti-spectic 78 | .addButtonWithIcon(4316, 4316, "", "staticBlueFrame") // unltrasound 79 | .addCustomBreak() 80 | .addButtonWithIcon(4320, 4320, "", "staticBlueFrame") // tray 81 | .addButtonWithIcon(1262, 1262, "", "staticBlueFrame") // anes 82 | .addButtonWithIcon(4320, 4320, "", "staticBlueFrame") // tray 83 | .addButtonWithIcon(4320, 4320, "", "staticBlueFrame") // tray 84 | .addButtonWithIcon(4320, 4320, "", "staticBlueFrame") // tray 85 | .addButtonWithIcon(4310, 4310, "", "staticBlueFrame") // trans 86 | .addCustomBreak() 87 | .addSpacer("small") 88 | .endDialog("surgery_end", "", "Give up!") 89 | 90 | 91 | peer.send(Variant.from("OnDialogRequest", dialog.str())); 92 | 93 | 94 | 95 | } 96 | 97 | 98 | 99 | 100 | } 101 | } 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /src/dialogs/Telephone.ts: -------------------------------------------------------------------------------- 1 | import { Variant } from "growtopia.js"; 2 | import { Dialog } from "../abstracts/Dialog"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import { DialogReturnType } from "../types/dialog"; 6 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 7 | import { Database } from "../database/db"; 8 | 9 | export default class extends Dialog { 10 | constructor() { 11 | super(); 12 | this.config = { 13 | dialogName: "phone" 14 | }; 15 | } 16 | 17 | public handle( 18 | base: BaseServer, 19 | peer: Peer, 20 | db: Database, 21 | action: DialogReturnType<{ 22 | action: string; 23 | dialog_name: string; 24 | number: string; 25 | //seed_only: string; 26 | }> 27 | ): void { 28 | 29 | if(action.number === "12345") { 30 | let dialog = new DialogBuilder() 31 | .defaultColor() 32 | .addLabelWithIcon("Crazy Jim's Quest Emporium", "3902", "big") 33 | .addSmallText("HEEEEYYY there Growtopian! I'm Crazy Jim, and my quest are so crazy they're KERRRRAAAAZZY!! And that is clearly very crazy, so please, be cautions around them. What can I do ya for, partner?") 34 | .addButton("dq", "Daily Quest") 35 | .addButton("goals", "Goals") 36 | .addButton("epic_quests", "Epic Quests") 37 | .endDialog("crazy_jim", "Hang Up", "") 38 | .str() 39 | 40 | peer.send(Variant.from("OnDialogRequest", dialog)); 41 | 42 | }else{ 43 | return peer.send(Variant.from("OnTextOverlay", "Hmmm... wrong number, could'nt reach anyone.")) 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/dialogs/TrashEnd.ts: -------------------------------------------------------------------------------- 1 | import { TankPacket, TextPacket, Variant } from "growtopia.js"; 2 | import { Dialog } from "../abstracts/Dialog"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import { DialogReturnType } from "../types/dialog"; 6 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 7 | import { DataTypes } from "../utils/enums/DataTypes"; 8 | import { TankTypes } from "../utils/enums/TankTypes"; 9 | import { Database } from "../database/db"; 10 | 11 | export default class extends Dialog { 12 | constructor() { 13 | super(); 14 | this.config = { 15 | dialogName: "trash_end" 16 | }; 17 | } 18 | 19 | public handle( 20 | base: BaseServer, 21 | peer: Peer, 22 | db: Database, 23 | action: DialogReturnType<{ 24 | action: string; 25 | dialog_name: string; 26 | trash_count: string; 27 | itemID: string; 28 | }> 29 | ): void { 30 | const itemID = parseInt(action.itemID); 31 | let invenItem = peer.data.inventory?.items.find((item) => item.id === itemID)!; 32 | if (!/\d/.test(action.trash_count)) return; 33 | 34 | 35 | 36 | const count = parseInt(action.trash_count); 37 | invenItem.amount = invenItem.amount - count; 38 | 39 | // Check if inventory amount is empty, then delete it. 40 | if (invenItem.amount <= 0) { 41 | peer.data.inventory!.items! = peer.data.inventory?.items.filter((i) => i.amount !== 0)!; 42 | } 43 | 44 | peer.saveToCache(); 45 | peer.inventory(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/dialogs/Xenonite.ts: -------------------------------------------------------------------------------- 1 | import { Variant } from "growtopia.js"; 2 | import { Dialog } from "../abstracts/Dialog"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import { DialogReturnType } from "../types/dialog"; 6 | import { DialogBuilder } from "../utils/builders/DialogBuilder"; 7 | import { Database } from "../database/db"; 8 | import { WorldData, WorldDB } from "../types/world"; 9 | import { QuickDB } from "quick.db"; 10 | const data = new QuickDB 11 | 12 | export default class extends Dialog { 13 | constructor() { 14 | super(); 15 | this.config = { 16 | dialogName: "xeno_edit" 17 | }; 18 | } 19 | 20 | public handle( 21 | base: BaseServer, 22 | peer: Peer, 23 | db: Database, 24 | action: DialogReturnType<{ 25 | action: string; 26 | dialog_name: string; 27 | strong_hit: string; 28 | }> 29 | ): void { 30 | const hit = parseInt(action.strong_hit) ? true : false; 31 | 32 | 33 | if(hit){ 34 | peer.send(Variant.from( "OnTalkBubble", 35 | peer.data.netID, "Xenonite has changed everyone's powers! `2Strong Punch granted`0!")) 36 | peer.send(Variant.from( "OnConsoleMessage", "Xenonite has changed everyone's powers! `2Strong Punch granted`0!")) 37 | // db.haveXeno({haveBuff : true}) 38 | data.set(`haveXeno_${peer.data.world}`, true) 39 | }else{ 40 | data.set(`haveXeno_${peer.data.world}`, false) 41 | } 42 | 43 | 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/events/Connect.ts: -------------------------------------------------------------------------------- 1 | import { TextPacket } from "growtopia.js"; 2 | import { Listener } from "../abstracts/Listener"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import { Peer } from "../structures/Peer"; 5 | import * as fs from 'fs'; 6 | import { QuickDB } from "quick.db"; 7 | import { Database } from "../database/db"; 8 | const data = new QuickDB 9 | 10 | 11 | 12 | export default class extends Listener<"connect"> { 13 | constructor() { 14 | super(); 15 | this.name = "connect"; 16 | } 17 | 18 | public async run(base: BaseServer, netID: number): Promise { 19 | console.log("Peer", netID, "connected."); 20 | 21 | const peer = new Peer(base, netID); 22 | const packet = TextPacket.from(0x1); 23 | 24 | peer.send(packet); 25 | base.cache.users.setSelf(netID, peer.data); 26 | 27 | 28 | 29 | 30 | const filePath = 'number.txt'; 31 | 32 | // Read the current number from the file 33 | fs.readFile(filePath, 'utf8', (err, data) => { 34 | if (err) { 35 | console.error('Error reading file:', err); 36 | return; 37 | } 38 | 39 | // Parse the data as an integer 40 | const currentNumber = parseInt(data, 10); 41 | 42 | // Check if the parsed value is a valid number 43 | if (!isNaN(currentNumber)) { 44 | // Increment the number by 1 45 | const updatedNumber = currentNumber + 1; 46 | 47 | // Write the updated number back to the file 48 | fs.writeFile(filePath, updatedNumber.toString(), 'utf8', (err) => { 49 | if (err) { 50 | console.error('Error writing file:', err); 51 | } else { 52 | console.log('File updated. New number:', updatedNumber); 53 | } 54 | }); 55 | } else { 56 | console.error('File does not contain a valid number.'); 57 | } 58 | }); 59 | 60 | const time = new Date() 61 | 62 | 63 | data.set(`PlayerLastJoined_${peer.data.id_user}`, { user_id: peer.data.id_user, time: time.getDate() }) 64 | 65 | console.log(time.getDate()) 66 | 67 | 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/events/Disconnect.ts: -------------------------------------------------------------------------------- 1 | import { Listener } from "../abstracts/Listener"; 2 | import { Database } from "../database/db"; 3 | import { BaseServer } from "../structures/BaseServer"; 4 | import * as fs from 'fs'; 5 | 6 | export default class extends Listener<"disconnect"> { 7 | constructor() { 8 | super(); 9 | this.name = "disconnect"; 10 | } 11 | 12 | public run(base: BaseServer, netID: number): void { 13 | console.log("Peer", netID, "disconnected"); 14 | let peer = base.cache.users.getSelf(netID); 15 | peer?.leaveWorld(); 16 | peer?.saveToDatabase(); 17 | 18 | base.cache.users.delete(netID); 19 | 20 | 21 | const filePath = 'number.txt'; 22 | 23 | // Function to read and decrement a number in a file 24 | const decrementNumberInFile = (filePath: string) => { 25 | fs.readFile(filePath, 'utf8', (err, data) => { 26 | if (err) { 27 | console.error(`Error reading file ${filePath}:`, err); 28 | return; 29 | } 30 | 31 | // Parse the data as an integer 32 | let currentNumber = parseInt(data, 10); 33 | 34 | // Check if the parsed value is a valid number 35 | if (!isNaN(currentNumber) && currentNumber > 0) { 36 | // Decrement the number by 1 37 | currentNumber -= 1; 38 | 39 | // Write the updated number back to the file 40 | fs.writeFile(filePath, currentNumber.toString(), 'utf8', (err) => { 41 | if (err) { 42 | console.error(`Error writing file ${filePath}:`, err); 43 | } else { 44 | console.log(`File ${filePath} updated. New number:`, currentNumber); 45 | } 46 | }); 47 | } else { 48 | console.error(`File ${filePath} does not contain a valid number.`); 49 | } 50 | }); 51 | }; 52 | 53 | // Example usage: Decrement the number in "number.txt" by 1 54 | decrementNumberInFile(filePath); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/structures/Collection.ts: -------------------------------------------------------------------------------- 1 | import { PeerDataType } from "../types/peer"; 2 | import { WorldData } from "../types/world"; 3 | import { BaseServer } from "./BaseServer"; 4 | import { Peer } from "./Peer"; 5 | import { World } from "./World"; 6 | 7 | export class Collection extends Map { 8 | public base: BaseServer; 9 | 10 | constructor(base: BaseServer) { 11 | if (!base) throw new Error("Server are required."); 12 | super(); 13 | 14 | this.base = base; 15 | } 16 | 17 | public getSelf(key: K): Peer { 18 | const peerData = this.get(key) as PeerDataType | undefined; 19 | let peer = new Peer(this.base, peerData?.netID as number); 20 | peer.data = peerData!; 21 | 22 | return peer; 23 | } 24 | 25 | public setSelf(key: K, value: PeerDataType) { 26 | this.set(key, value as V); 27 | } 28 | 29 | public getWorld(key: K) { 30 | const worldData = this.get(key) as WorldData | undefined; 31 | let world = new World(this.base, worldData?.name as string); 32 | world.data = worldData!; 33 | 34 | return world; 35 | } 36 | 37 | public setWorld(key: K, value: WorldData) { 38 | this.set(key, value as V); 39 | } 40 | 41 | public findPeer(func: (user: Peer) => boolean) { 42 | const users = this as Collection; 43 | 44 | for (const item of users.values()) { 45 | const peer = users.getSelf(item.netID); 46 | if (func(peer)) { 47 | return peer; 48 | } 49 | } 50 | return undefined; 51 | } 52 | 53 | public filterPeer(func: (user: Peer) => boolean) { 54 | const arr = []; 55 | for (const item of this.values()) { 56 | if (func(item as Peer)) { 57 | arr.push(item); 58 | } 59 | } 60 | return arr; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/structures/Logger.ts: -------------------------------------------------------------------------------- 1 | import chalk from "chalk"; 2 | 3 | export class Logger { 4 | constructor() {} 5 | get time() { 6 | return new Date().toLocaleString("en-US", { timeZone: "Asia/Jakarta" }); 7 | } 8 | 9 | public info(...content: unknown[]) { 10 | console.log(`[${this.time} - INFO ]`, ...content); 11 | } 12 | 13 | public ready(...content: unknown[]) { 14 | console.log(`[${this.time} - ${chalk.greenBright("READY")} ]`, ...content); 15 | } 16 | 17 | public event(...content: unknown[]) { 18 | console.log(`[${this.time} - ${chalk.blueBright("EVENT")} ]`, ...content); 19 | } 20 | 21 | public update(...content: unknown[]) { 22 | console.log(`[${this.time} - ${chalk.cyan("UPDATE")} ]`, ...content); 23 | } 24 | 25 | public action(...content: unknown[]) { 26 | console.log(`[${this.time} - ${chalk.rgb(242, 124, 27)("ACTION")} ]`, ...content); 27 | } 28 | 29 | public dialog(...content: unknown[]) { 30 | console.log(`[${this.time} - ${chalk.rgb(69, 214, 200)("DIALOG")} ]`, ...content); 31 | } 32 | 33 | public command(...content: unknown[]) { 34 | console.log(`[${this.time} - ${chalk.rgb(95, 232, 150)("COMMAND")} ]`, ...content); 35 | } 36 | 37 | public debug(...content: unknown[]) { 38 | console.log(`[${this.time} - ${chalk.rgb(211, 237, 64)("DEBUG")} ]`, ...content); 39 | } 40 | 41 | public warn(...content: unknown[]) { 42 | console.log(`[${this.time} - ${chalk.rgb(255, 168, 18)("WARN")} ]`, ...content); 43 | } 44 | 45 | public error(...content: unknown[]) { 46 | console.log(`[${this.time} - ${chalk.rgb(230, 68, 28)("ERROR")} ]`, ...content); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/structures/Webserver.ts: -------------------------------------------------------------------------------- 1 | import express from "express"; 2 | import { readFileSync } from "node:fs"; 3 | import http from "node:http"; 4 | import https from "node:https"; 5 | import { Logger } from "./Logger"; 6 | import bodyparser from "body-parser"; 7 | import rateLimit from "express-rate-limit"; 8 | import path from "node:path"; 9 | import { Database } from "../database/db"; 10 | const app = express(); 11 | 12 | const options = { 13 | key: readFileSync("./assets/ssl/server.key"), 14 | cert: readFileSync("./assets/ssl/server.crt") 15 | }; 16 | 17 | const apiLimiter = rateLimit({ 18 | windowMs: 10800000, // 3 hour 19 | max: 5, // Limit each IP to 5 requests per `window` 20 | message: "Too many accounts created from this IP, please try again after 3 hour", 21 | standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers 22 | legacyHeaders: false // Disable the `X-RateLimit-*` headers 23 | }); 24 | 25 | export function WebServer(log: Logger, db: Database) { 26 | app.use(bodyparser.urlencoded({ extended: true })); 27 | app.use(bodyparser.json()); 28 | app.set("view engine", "ejs"); 29 | 30 | app.set("views", path.join(__dirname, "../../web/views")); 31 | 32 | app.use("/growtopia/server_data.php", (req, res) => { 33 | res.send( 34 | `server|${process.env.WEB_ADDRESS}\nport|17091\ntype|1\n#maint|Maintenance woi\nmeta|lolwhat\nRTENDMARKERBS1001` 35 | ); 36 | }); 37 | 38 | app.get("/register", (req, res) => { 39 | res.render("register.ejs"); 40 | }); 41 | 42 | app.post("/api/register", apiLimiter, async (req, res) => { 43 | if (req.body && req.body.username && req.body.password) { 44 | let result = await db.createUser(req.body.username, req.body.password); 45 | 46 | if (result) res.send("OK, Successfully creating account"); 47 | else res.send("Error"); 48 | } 49 | }); 50 | 51 | if (process.env.WEB_ENV === "production") { 52 | app.listen(3000, () => { 53 | log.ready(`Starting development web server on: http://${process.env.WEB_ADDRESS}:3000`); 54 | log.info( 55 | `To register account you need to register at: http://${process.env.WEB_ADDRESS}:3000/register` 56 | ); 57 | }); 58 | } else if (process.env.WEB_ENV === "development") { 59 | let httpServer = http.createServer(app); 60 | let httpsServer = https.createServer(options, app); 61 | 62 | httpServer.listen(80); 63 | httpsServer.listen(443); 64 | 65 | httpsServer.on("listening", function () { 66 | log.ready(`Starting web server on: http://${process.env.WEB_ADDRESS}:80`); 67 | log.info( 68 | `To register account you need to register at: http://${process.env.WEB_ADDRESS}:80/register` 69 | ); 70 | }); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/tanks/game_events.json: -------------------------------------------------------------------------------- 1 | { 2 | "Harvestfest": "false", 3 | "Halloween": "true", 4 | "Christmas": "false", 5 | "New Years": "false", 6 | "Valentines": "false", 7 | "Easter": "false", 8 | "StPatricks": "false" 9 | } -------------------------------------------------------------------------------- /src/tanks/game_events.ts: -------------------------------------------------------------------------------- 1 | export const gameEvents = { 2 | Harvestfest: false, 3 | Halloween: true, 4 | Christmas: false, 5 | New_Years: false, 6 | Valentines: false, 7 | Easter: false, 8 | StPatricks: false 9 | }; 10 | -------------------------------------------------------------------------------- /src/types/action.d.ts: -------------------------------------------------------------------------------- 1 | export interface ActionConfig { 2 | eventName?: string; 3 | } 4 | 5 | // TODO: when there's a something on generic type, then add it to property type. 6 | export interface ActionDefault { 7 | action: string; 8 | } 9 | export type ActionType = T; 10 | -------------------------------------------------------------------------------- /src/types/command.d.ts: -------------------------------------------------------------------------------- 1 | export interface CommandOptions { 2 | name: string; 3 | description: string; 4 | /** Cooldown command per seconds. */ 5 | cooldown: number; 6 | /** Limiting command usage. */ 7 | ratelimit: number; 8 | category: string; 9 | usage: string; 10 | example: string[]; 11 | permission: string[]; 12 | } 13 | 14 | export interface CooldownOptions { 15 | limit: number; 16 | time: number; 17 | } 18 | -------------------------------------------------------------------------------- /src/types/database.d.ts: -------------------------------------------------------------------------------- 1 | export interface User { 2 | [x: string]: any; 3 | id_user: string; 4 | name: string; 5 | password: string; 6 | role: string; 7 | gems?: number; 8 | inventory?: Buffer; 9 | clothing?: Buffer; 10 | created_at: Date; 11 | } 12 | -------------------------------------------------------------------------------- /src/types/dialog.d.ts: -------------------------------------------------------------------------------- 1 | // TODO: when there's a something on generic type, then add it to property type. 2 | // export interface DialogReturnType { 3 | // action: string; 4 | // } 5 | export interface DialogConfig { 6 | dialogName?: string; 7 | } 8 | 9 | export type DialogReturnType = T; 10 | -------------------------------------------------------------------------------- /src/types/events.d.ts: -------------------------------------------------------------------------------- 1 | export interface ListenerEventTypes { 2 | connect: [netID: number]; 3 | raw: [netID: number, data: Buffer]; 4 | disconnect: [netID: number]; 5 | } 6 | -------------------------------------------------------------------------------- /src/types/peer.d.ts: -------------------------------------------------------------------------------- 1 | export interface InventoryItems { 2 | id: number; 3 | amount: number; 4 | } 5 | 6 | export interface PeerDataType { 7 | [x: string]: number; 8 | x?: number; 9 | y?: number; 10 | world: string; 11 | inventory?: { 12 | max: number; 13 | items: InventoryItems[]; 14 | }; 15 | rotatedLeft: boolean; 16 | requestedName: string; 17 | tankIDName: string; 18 | netID: number; 19 | country: string; 20 | id_user: string | number; 21 | role: string; 22 | gems: number; 23 | clothing?: Clothing; 24 | } 25 | 26 | export interface Clothing { 27 | hair: number; 28 | shirt: number; 29 | pants: number; 30 | feet: number; 31 | face: number; 32 | hand: number; 33 | back: number; 34 | mask: number; 35 | necklace: number; 36 | ances: number; 37 | } 38 | -------------------------------------------------------------------------------- /src/types/world.d.ts: -------------------------------------------------------------------------------- 1 | import { Peer } from "../structures/Peer"; 2 | 3 | export interface Place { 4 | peer: Peer; 5 | x: number; 6 | y: number; 7 | id: number; 8 | isBg?: boolean; 9 | fruit?: number; 10 | } 11 | 12 | export interface WorldDB { 13 | name: string; 14 | ownedBy?: string | null; 15 | blockCount: number; 16 | blocks: Buffer; 17 | width: number; 18 | height: number; 19 | owner?: Buffer | null; 20 | dropped?: Buffer; 21 | //admins: number[]; 22 | } 23 | 24 | export interface Jammer { 25 | type: "zombie" | "punch" | "signal"; 26 | enabled: boolean; 27 | } 28 | 29 | export interface BlockPosition { 30 | x: number; 31 | y: number; 32 | } 33 | 34 | export interface DroppedItem { 35 | id: number; 36 | amount: number; 37 | block: BlockPosition; 38 | x: number; 39 | y: number; 40 | uid: number; 41 | } 42 | 43 | export interface Dropped { 44 | uid: number; 45 | items: DroppedItem[]; 46 | } 47 | 48 | export interface WorldData { 49 | name?: string; 50 | width?: number; 51 | height?: number; 52 | blockCount?: number; 53 | blocks?: Block[]; 54 | owner?: { 55 | name: string; 56 | displayName: string; 57 | id: number; 58 | }; 59 | admins?: number[]; 60 | playerCount?: number; 61 | bpm?: number; 62 | customMusicBlocksDisabled?: boolean; 63 | invisMusicBlocks?: boolean; 64 | jammers?: Jammer[]; 65 | dropped?: Dropped; 66 | } 67 | 68 | export interface LockedBlocked { 69 | ownerFg?: number; 70 | ownerUserID?: number; 71 | ownerX?: number; 72 | ownerY?: number; 73 | isOwner?: boolean; 74 | ignoreEmptyAir?: boolean; 75 | adminIDs?: number[]; 76 | } 77 | 78 | export interface Door { 79 | label?: string; 80 | destination?: string; 81 | id?: string; 82 | locked?: boolean; 83 | } 84 | 85 | export interface Sign { 86 | label?: string; 87 | } 88 | 89 | export interface Boombox { 90 | open?: boolean; 91 | public?: boolean; 92 | silenced?: boolean; 93 | } 94 | 95 | export interface Entrance { 96 | open?: boolean; 97 | } 98 | 99 | export interface Tree { 100 | fruit: number; 101 | fruitCount: number; 102 | fullyGrownAt: number; 103 | plantedAt: number; 104 | } 105 | 106 | export interface HeartMonitor { 107 | name: string; 108 | user_id: number; 109 | } 110 | 111 | export interface Block { 112 | fg?: number; 113 | bg?: number; 114 | x?: number; 115 | y?: number; 116 | lock?: LockedBlocked; 117 | door?: Door; 118 | sign?: Sign; 119 | heartMonitor?: HeartMonitor; 120 | dblockID?: number; 121 | damage?: number; 122 | resetStateAt?: number; 123 | worldLock?: boolean; 124 | boombox?: Boombox; 125 | rotatedLeft?: boolean; 126 | entrace?: Entrance; 127 | tree?: Tree; 128 | } 129 | 130 | export interface EnterArg { 131 | x?: number; 132 | y?: number; 133 | } 134 | 135 | export interface GetBlockArg { 136 | x: number; 137 | y: number; 138 | peer: Peer; 139 | } 140 | -------------------------------------------------------------------------------- /src/utils/Constants.ts: -------------------------------------------------------------------------------- 1 | export const WORLD_SIZE = { 2 | WIDTH: 100, 3 | HEIGHT: 60 4 | }; 5 | 6 | export const Y_START_DIRT = 24; 7 | export const Y_LAVA_START = 50; 8 | export const Y_END_DIRT = 55; 9 | 10 | export const Role = { 11 | DEVELOPER: "1", 12 | BASIC: "2", 13 | MOD: "3", 14 | ADMIN: "4" 15 | 16 | }; 17 | -------------------------------------------------------------------------------- /src/utils/Utils.ts: -------------------------------------------------------------------------------- 1 | import CryptoJS from "crypto-js"; 2 | import { BaseServer } from "../structures/BaseServer"; 3 | import { Peer } from "../structures/Peer"; 4 | import { Collection } from "../structures/Collection"; 5 | import { PeerDataType } from "../types/peer"; 6 | import { World } from "../structures/World"; 7 | interface DataObject { 8 | [key: string]: string | number; 9 | } 10 | 11 | export function parseAction(chunk: Buffer): DataObject | undefined { 12 | let data: DataObject = {}; 13 | chunk[chunk.length - 1] = 0; 14 | 15 | let str = chunk.toString("utf-8", 4); 16 | const lines = str.split("\n"); 17 | 18 | lines.forEach((line) => { 19 | if (line.startsWith("|")) line = line.slice(1); 20 | const info = line.split("|"); 21 | 22 | let key = info[0]; 23 | let val = info[1]; 24 | 25 | if (key && val) { 26 | if (val.endsWith("\x00")) val = val.slice(0, -1); 27 | data[key] = val; 28 | } 29 | }); 30 | 31 | return data; 32 | } 33 | 34 | export function find( 35 | base: BaseServer, 36 | users: Collection, 37 | func: (user: Peer) => boolean 38 | ) { 39 | for (const item of users.values()) { 40 | const peer = users.getSelf(item.netID); 41 | if (func(peer)) { 42 | return peer; 43 | } 44 | } 45 | return undefined; 46 | } 47 | 48 | export function hashItemsDat(file: Buffer) { 49 | let hash = 0x55555555; 50 | file.forEach((x) => (hash = (hash >>> 27) + (hash << 5) + x)); 51 | return hash >>> 0; 52 | } 53 | 54 | export function encrypt(data: string): string { 55 | return CryptoJS.AES.encrypt(data, process.env.ENCRYPT_SECRET!).toString(); 56 | } 57 | export function decrypt(data: string): string { 58 | return CryptoJS.AES.decrypt(data, process.env.ENCRYPT_SECRET!).toString(CryptoJS.enc.Utf8); 59 | } 60 | 61 | export function handleSaveAll(server: BaseServer, dcAll = false) { 62 | server.log.warn(`Saving ${server.cache.users.size} peers & ${server.cache.worlds.size} worlds.`); 63 | 64 | const saveWorlds = () => { 65 | if (server.cache.worlds.size === 0) process.exit(); 66 | else { 67 | let o = 0; 68 | server.cache.worlds.forEach(async (wrld) => { 69 | const world = new World(server, wrld.name!); 70 | if (typeof world.worldName === "string") await world.saveToDatabase(); 71 | else server.log.warn(`Oh no there's undefined (${o}) world, skipping..`); 72 | 73 | o += 1; 74 | if (o === server.cache.worlds.size) process.exit(); 75 | }); 76 | } 77 | }; 78 | 79 | if (server.cache.users.size === 0) process.exit(); 80 | else { 81 | let i = 0; 82 | server.cache.users.forEach(async (peer) => { 83 | const player = server.cache.users.getSelf(peer.netID); 84 | await player.saveToDatabase(); 85 | if (dcAll) { 86 | player.disconnect("now"); 87 | } else { 88 | // send onconsolemessage for auto saving 89 | } 90 | i += 1; 91 | if (i === server.cache.users.size) saveWorlds(); 92 | }); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/utils/enums/DataTypes.ts: -------------------------------------------------------------------------------- 1 | export enum DataTypes { 2 | HELLO = 1, 3 | STR, 4 | ACTION, 5 | TANK 6 | } 7 | -------------------------------------------------------------------------------- /src/utils/enums/ItemTypes.ts: -------------------------------------------------------------------------------- 1 | export enum ClothTypes { 2 | HAIR, 3 | SHIRT, 4 | PANTS, 5 | FEET, 6 | FACE, 7 | HAND, 8 | BACK, 9 | MASK, 10 | NECKLACE, 11 | ANCES 12 | } 13 | -------------------------------------------------------------------------------- /src/utils/enums/TankTypes.ts: -------------------------------------------------------------------------------- 1 | export enum TankTypes { 2 | PEER_MOVE, 3 | TILE_PUNCH = 3, 4 | PEER_WORLD, 5 | TILE_UPDATE, 6 | PEER_ENTER_DOOR = 7, 7 | TILE_DAMAGE, 8 | PEER_INVENTORY, 9 | PEER_CLOTH, 10 | PEER_COLLECT = 11, 11 | TILE_TREE, 12 | PEER_DROP = 14, 13 | TILE_APPLY_LOCK, 14 | PEER_ITEMS_DAT, 15 | PEER_ICON = 18, 16 | PEER_PING_RESPONSE = 21, 17 | PEER_PING_REQUEST, 18 | SET_CHARACTER_STATE 19 | } 20 | -------------------------------------------------------------------------------- /web/views/register.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Register 8 | 9 | 10 |
11 |

Create new account

12 |
13 | 14 | 15 |
16 |
17 | 18 | 19 |
20 |
21 | 22 |
23 |
24 | 25 | 26 | --------------------------------------------------------------------------------