├── .editorconfig
├── .eslintignore
├── .eslintrc.cjs
├── .gitignore
├── .prettierignore
├── .prettierrc.yaml
├── LICENSE
├── README.md
├── VERSION
├── docs
├── CNAME
├── css
│ └── styles.css
├── files
│ ├── background.svg
│ ├── discord.svg
│ ├── github.svg
│ ├── icon-premium.png
│ ├── icon.png
│ └── info.svg
├── index.html
└── js
│ └── script.js
├── electron-builder.yml
├── electron.vite.config.mjs
├── package.json
└── src
├── main
├── index.js
└── js
│ ├── misc
│ ├── antiafk.js
│ ├── customAuth.js
│ └── utils.js
│ └── proxy
│ ├── proxycheck.js
│ ├── proxyhandler.js
│ └── proxyscrape.js
├── preload
└── index.js
└── renderer
├── assets
├── css
│ ├── base.css
│ └── main.css
└── icons
│ ├── alert.svg
│ ├── background.svg
│ ├── clock.svg
│ ├── discord.svg
│ ├── icon.png
│ ├── min.svg
│ ├── settings.svg
│ ├── spinner.svg
│ ├── user.svg
│ └── x.svg
├── index.html
└── src
└── index.js
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 | out
4 | .gitignore
5 |
--------------------------------------------------------------------------------
/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: ['eslint:recommended', '@electron-toolkit', '@electron-toolkit/eslint-config-prettier']
3 | }
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 | out
4 | package-lock.json
5 | .DS_Store
6 | *.log*
7 | .vscode
8 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | out
2 | dist
3 | pnpm-lock.yaml
4 | LICENSE.md
5 | tsconfig.json
6 | tsconfig.*.json
7 |
--------------------------------------------------------------------------------
/.prettierrc.yaml:
--------------------------------------------------------------------------------
1 | singleQuote: true
2 | semi: false
3 | printWidth: 100
4 | trailingComma: none
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 RattlesHyper
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 |
2 |
3 |
4 | The best, free and open source Minecraft botting tool.
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | ## Features
17 | TrafficerMC has a variety of features. Some of them are:
18 | - Anti AFK
19 | - Spam with Bypass
20 | - Name Generator
21 | - Full Inventory Control
22 | - Movement Control
23 | - EasyMC Support
24 | - Auto Reconnect
25 | - Killaura
26 | - [Scripting](#scripting)
27 | - [Proxies](#proxies)
28 | - and way more!
29 |
30 | #### Minecraft Version 1.8.x - 1.20
31 |
32 | ##### Check out [Build Guide](#build-guide) to build TrafficerMC for your machine.
33 |
34 | ## Media
35 |
36 | 
37 | **TrafficerMC v3.0**
38 |
39 | 
40 | **Settings**
41 |
42 | 
43 | **Botting**
44 |
45 | 
46 | **Scripting**
47 |
48 | 
49 | **Proxy**
50 |
51 | ## Tutorials
52 | [](https://www.youtube.com/watch?v=lD3poymjVAk)
53 | TrafficerMC v2.1 Tutorial Video
54 |
55 | [](https://www.youtube.com/watch?v=eAe9m-d-el0)
56 | TrafficerMC v0.4 Preview Video (Outdated)
57 |
58 | # Scripting
59 | Scripting can allow the bot to do things automatically without any user input. It can also help if you are making multiple bots do the same things. All script executions will be shown on manual inputs, it can be used in scripting.
60 |
61 | ## What a script would look like
62 | ```
63 | chat Hello from TrafficerMC!
64 | delay 1000
65 | useheld
66 | delay 2000
67 | winclick 36 0
68 | delay 1000
69 | disconnect
70 | ```
71 | ## Features
72 | - [Chat](#chat)
73 | - [Use Held Item](#useheld)
74 | - [Set Hotbar Slot](#sethotbar)
75 | - [Click Inventory Item](#winclick)
76 | - [Close Window](#closewindow)
77 | - [Drop](#drop)
78 | - [Movement](#movement)
79 | - [Anti-AFK](#anti-afk)
80 | - [Disconnect](#disconnect)
81 | - [Reconnect](#reconnect)
82 | - [Loop](#startscript)
83 | - [Delay](#delay)
84 |
85 | ### Chat
86 | Sends a message to the servers chat.
87 | Usage: `chat `
88 |
89 | Variables: Player Name: `{player}`, Random String: `{random}`
90 |
91 | Example:
92 | ```
93 | chat Hello there! {player}
94 | chat /help
95 | ```
96 | ### useHeld
97 | Uses the current held item.
98 | Usage: `useHeld`
99 | ### setHotbar
100 | Sets hotbar to the selected slot.
101 | Usage: `setHotbar `
102 |
103 | Example:
104 | ```
105 | setHotbar 0
106 | setHotbar 3
107 | ```
108 | ### winClick
109 | Clicks on a window item. To left click, use `0`. Otherwise, to right click, use `1`.
110 | Usage: `winClick `
111 |
112 | Example:
113 | ```
114 | winClick 36 0
115 | winClick 24 1
116 | ```
117 | **If you are struggling on what slots you should click, here are some images to represent!**
118 |
119 | **Every chest starts from `0`**
120 |
121 | #### Chest interface:
122 |
123 | 
124 |
125 | #### Inventory interface:
126 |
127 | 
128 |
129 | ### closeWindow
130 | Closes the current window.
131 | Usage: `closeWindow`
132 | ### Drop
133 | Drops the slot item if none specified drops all.
134 | Usage: `drop `
135 |
136 | Example:
137 | ```
138 | drop
139 | drop 36
140 | ```
141 | ### Movement
142 | Controls the bot movement.
143 | Usage: `startMove/stopMove `
144 |
145 | Reset controls: `resetMove`
146 |
147 | Example:
148 | ```
149 | startControl forward
150 | startControl jump
151 | stopControl forward
152 | ```
153 | ### Anti-AFK
154 | Enables/Disables Anti-AFK on the bot.
155 | Usage: `afkOn/afkOff`
156 | ### Disconnect
157 | Disconnects the Bot.
158 | Usage: `disconnect`
159 | ### Reconnect
160 | Reconnects the bot.
161 | Usage: `reconnect`
162 | ### startScript
163 | Starts the script.
164 | Usage: `startScript`
165 | ### Delay
166 | Delays the next task.
167 | Usage: `delay ` default 1000
168 |
169 | Example:
170 | ```
171 | chat Hi
172 | delay 1200
173 | chat Hello
174 | ```
175 | # Account File
176 | Account file must be a `.txt` file. Put the usernames of the accounts you want to use line by line. Microsoft accounts can be used the same way.
177 |
178 | **Please note that you can set Max Accounts in General Tab or it will use all the names**
179 | ## What an account file would look like
180 | ```
181 | vampers
182 | nVoid
183 | Danilo764
184 | ```
185 | # Proxies
186 | TrafficerMC currently support all protocols and Auth proxies, HTTP is premium only.
187 | ## What a proxy file would look like
188 | ```
189 | ProxyIP:ProxyPORT:Username:Password
190 | 98.7.65.4:32101
191 | ```
192 |
193 | # Build Guide
194 |
195 | **Requirements:** [NodeJS](https://nodejs.org/en/download)
196 |
197 | Clone TrafficerMC repo with Git Clone: `git clone https://github.com/RattlesHyper/TrafficerMC` or Download the Source Code, then navigate to the folder. and open Terminal/Command Prompt/PowerShell
198 |
199 | **Build Commands:**
200 |
201 | **Install Dependencies** `npm install`
202 |
203 | **Windows:** `build:win`
204 |
205 | **Mac:** `build:mac`
206 |
207 | **Linux:** `build:linux`
208 |
209 | If you want to run from source code use `npm run dev`
210 |
--------------------------------------------------------------------------------
/VERSION:
--------------------------------------------------------------------------------
1 | 3.1
2 |
--------------------------------------------------------------------------------
/docs/CNAME:
--------------------------------------------------------------------------------
1 | trafficermc.com
--------------------------------------------------------------------------------
/docs/css/styles.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Poppins&display=swap');
2 |
3 | body {
4 | font-weight: 600;
5 | color: var(--text-primary);
6 | background: radial-gradient(circle, rgb(26, 9, 65) 0%, rgb(28, 8, 44) 100%);
7 | }
8 |
9 | .space-h {
10 | align-items: center;
11 | justify-content: space-between;
12 | }
13 |
14 | .flex {
15 | display: flex;
16 | }
17 |
18 | .center {
19 | align-items: center;
20 | }
21 |
22 | .center-items {
23 | display: flex;
24 | align-items: center;
25 | justify-content: center;
26 | }
27 |
28 | .p-4 {
29 | padding: 1rem;
30 | }
31 |
32 | .pl-1 {
33 | padding-left: 10px;
34 | }
35 |
36 | .space {
37 | margin-left: 5px;
38 | }
39 |
40 | .mu-8 {
41 | margin-top: 4rem;
42 | }
43 |
44 | .mu-4 {
45 | margin-top: 1rem;
46 | }
47 |
48 | .icon {
49 | height: 25px;
50 | width: 25px;
51 | }
52 |
53 | .icon-big {
54 | height: 35px;
55 | width: 35px;
56 | }
57 |
58 | .tip-sm {
59 | font-size: 12px;
60 | color: var(--text-secondary);
61 | }
62 |
63 | .background {
64 | width: 100%;
65 | top: 0px;
66 | left: 0px;
67 | }
68 |
69 | .main-container {
70 | overflow: hidden;
71 | min-height: 20rem;
72 | display: flex;
73 | align-items: center;
74 | background-size: cover;
75 | }
76 |
77 | .bg {
78 | background: url(../files/background.svg);
79 | }
80 |
81 | .container {
82 | padding: 0 4rem;
83 | width: 100%;
84 | }
85 |
86 | .options {
87 | justify-content: center;
88 | display: grid;
89 | grid-template-columns: repeat(auto-fit, 495px);
90 | }
91 |
92 | .title {
93 | display: flex;
94 | justify-content: center
95 | }
96 |
97 | .title-text {
98 | font-size: 2rem;
99 | }
100 |
101 | .section-2 {
102 | overflow: hidden;
103 | display: flex;
104 | align-items: center;
105 | justify-content: center;
106 | }
107 |
108 | .row {
109 | display: flex;
110 | padding: 0px 15px;
111 | justify-content: space-between;
112 | box-sizing: border-box;
113 | border-top: solid 2px var(--accent);
114 | background-color: var(--accent-secondary);
115 | }
116 |
117 | .row-first {
118 | width: 200px;
119 | }
120 |
121 | .row-second {
122 | width: 100px;
123 | }
124 |
125 | .row-third {
126 | margin-right: 30px;
127 | }
128 |
129 | .box {
130 | display: flex;
131 | justify-content: space-between;
132 | flex-direction: column;
133 | padding: 1rem;
134 | margin: 10px;
135 | border-radius: 10px;
136 | box-sizing: border-box;
137 | min-height: 13rem;
138 | background-color: var(--accent-secondary);
139 | box-shadow: var(--accent) 0px 0px 15px;
140 | }
141 |
142 | .button {
143 | background-color: var(--accent);
144 | width: fit-content;
145 | height: fit-content;
146 | cursor: pointer;
147 | border-radius: 5px;
148 | text-decoration: none;
149 | transition: all 0.3s ease 0s;
150 | }
151 |
152 | .button .inner {
153 | padding: 0px 25px;
154 | justify-content: space-between;
155 | width: 6rem;
156 | }
157 |
158 | .button:hover {
159 | background-color: var(--button-hover-bg);
160 | box-shadow: var(--text-primary) 0px 0px 4px;
161 | }
162 |
163 | .menu {
164 | position: sticky;
165 | top: calc(50% - 150px);
166 | height: 160px;
167 | list-style-type: none;
168 | padding: 0 10px 0 4rem;
169 | margin-top: 5rem;
170 | border-right: solid 2px var(--accent);
171 | }
172 |
173 | .sticky {
174 | position: sticky;
175 | top: 0;
176 | }
177 |
178 | .menu a {
179 | color: var(--text-disabled);
180 | text-decoration: none;
181 | transition: color 0.5s ease;
182 | }
183 |
184 | .menu .active {
185 | position: relative;
186 | left: 10px;
187 | color: var(--text-primary);
188 | }
189 |
190 | .menu a:hover {
191 | color: var(--text-primary);
192 | }
193 |
194 | .table-content {
195 | border-top: solid 4px var(--accent);
196 | margin: 0 4rem 100px 50px;
197 | line-height: 1;
198 | width: 100%;
199 | }
200 |
201 | .checkmark {
202 | margin: 15px 35px 0px 0px;
203 | width: 6px;
204 | height: 10px;
205 | border: solid var(--text-secondary);
206 | border-width: 0 3px 3px 0;
207 | -webkit-transform: rotate(45deg);
208 | -ms-transform: rotate(45deg);
209 | transform: rotate(45deg);
210 | }
211 |
212 | .checks {
213 | display: flex;
214 | justify-content: space-between;
215 | width: 210px;
216 | }
217 |
218 | .video {
219 | height: 320px;
220 | display: flex;
221 | width: fit-content;
222 | }
223 |
224 | .video-title {
225 | margin: 15px 0 0 0;
226 | font-size: 12px;
227 | }
228 |
229 | .footer {
230 | background-color: var(--accent);
231 | height: 100px;
232 | }
233 |
234 | .footer-text {
235 | margin-top: 80px;
236 | font-size: 10px;
237 | color: var(--text-disabled);
238 | }
239 |
240 | .text-disabled {
241 | color: var(--text-disabled);
242 | }
243 |
244 | .hidden {
245 | display: none;
246 | }
247 |
248 | :root {
249 | --accent: #140e0e;
250 | --accent-secondary: rgba(54, 41, 90, 0.3);
251 | --button-hover-bg: rgba(47, 1, 139, 0.1);
252 | --text-primary: white;
253 | --text-secondary: #E6E6E6;
254 | --text-disabled: #7b7b7b;
255 | --discord: #7388da;
256 | --paypal: #026fba;
257 | --github: #242a2e;
258 | --youtube: #ff0201;
259 | font-family: 'Poppins', sans-serif;
260 | }
261 |
--------------------------------------------------------------------------------
/docs/files/background.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/files/discord.svg:
--------------------------------------------------------------------------------
1 |
2 |
5 |
--------------------------------------------------------------------------------
/docs/files/github.svg:
--------------------------------------------------------------------------------
1 |
2 |
5 |
--------------------------------------------------------------------------------
/docs/files/icon-premium.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RattlesHyper/TrafficerMC/e9bd554ffd695ab56781104d357363aa3442b347/docs/files/icon-premium.png
--------------------------------------------------------------------------------
/docs/files/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RattlesHyper/TrafficerMC/e9bd554ffd695ab56781104d357363aa3442b347/docs/files/icon.png
--------------------------------------------------------------------------------
/docs/files/info.svg:
--------------------------------------------------------------------------------
1 |
2 |
5 |
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | TrafficerMC - Botting Tool
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |

19 |
TrafficerMC
20 |
21 |
Access Your Botting Arsenal Here!
22 |
Best Free and Open Source Minecraft Botting Tool
23 |
43 |
44 |
45 |
46 |
47 |
Downloads:
48 |
?
49 |
50 |
51 |
52 |
53 |
54 |
55 |

56 |
TrafficerMC
57 |
58 |
Everything you need to get started. It comes with all the essential features for your
59 | basic botting needs.
60 |
61 |
62 |
63 |

64 |
Download
65 |
66 |
67 |
68 |
69 |
70 |
71 |

72 |
TrafficerMC Premium
73 |
74 |
Enjoy better stability and advanced botting capabilities. With enhanced performance and
75 | exclusive features.
76 |
77 |
78 |
79 |

80 |
Contact
81 |
82 |
83 |
84 |
85 |
86 |
87 |
90 |
91 |
92 |
93 |
94 |
98 |
TrafficerMC Premium v1.0 Preview
99 |
100 |
101 |
105 |
TrafficerMC v2.1 Usage Tutorial
106 |
107 |
108 |
109 |
110 |
111 |
112 |
115 |
116 |
117 |
137 |
138 |
139 |
140 |
Features
141 |
142 |
Premium
143 |
Free
144 |
145 |
146 |
149 |
150 |
Name Generator
151 |
152 |
153 |
154 |
155 |
156 |
157 |
EasyMC
158 |
159 |
160 |
161 |
162 |
163 |
164 |
TheAltening
165 |
166 |
167 |
168 |
169 |
170 |
Minimal Mode
171 |
172 |
173 |
174 |
175 |
176 |
179 |
180 |
Chat
181 |
182 |
183 |
184 |
185 |
186 |
187 |
Spam
188 |
189 |
190 |
191 |
192 |
193 |
194 |
Chat Variables
195 |
196 |
197 |
198 |
199 |
200 |
201 |
Hotbar
202 |
203 |
204 |
205 |
206 |
207 |
208 |
Inventory
209 |
210 |
211 |
212 |
213 |
214 |
215 |
Move
216 |
217 |
218 |
219 |
220 |
221 |
222 |
Look
223 |
224 |
225 |
226 |
227 |
228 |
229 |
Anti AFK
230 |
231 |
232 |
233 |
234 |
235 |
236 |
KillAura
237 |
238 |
239 |
240 |
241 |
242 |
243 |
Interact
244 |
245 |
246 |
247 |
248 |
249 |
Nuker
250 |
251 |
252 |
253 |
254 |
255 |
Pathfinder
256 |
257 |
258 |
259 |
260 |
263 |
264 |
Full Functionality
265 |
266 |
267 |
268 |
269 |
270 |
273 |
274 |
Proxy Scrape
275 |
276 |
277 |
278 |
279 |
280 |
281 |
Proxy Checker
282 |
283 |
284 |
285 |
286 |
287 |
288 |
SOCKS4
289 |
290 |
291 |
292 |
293 |
294 |
295 |
SOCKS5
296 |
297 |
298 |
299 |
300 |
301 |
302 |
HTTP
303 |
304 |
305 |
306 |
307 |
310 |
311 |
Discord Webhook
312 |
313 |
314 |
315 |
316 |
319 |
320 |
Linear Delay
321 |
322 |
323 |
324 |
325 |
326 |
327 |
Auto Reconnect
328 |
329 |
330 |
331 |
332 |
333 |
334 |
Map Image Viewer
335 |
336 |
337 |
338 |
339 |
340 |
Accept Resource Pack
341 |
342 |
343 |
344 |
345 |
346 |
Selective Chat Logs
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
--------------------------------------------------------------------------------
/docs/js/script.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-unused-vars */
2 | const ul = document.getElementById('menu')
3 | const links = ul.getElementsByTagName('a')
4 |
5 | for (let i = 0; i < links.length; i++) {
6 | links[i].addEventListener('click', function (event) {
7 | for (let j = 0; j < links.length; j++) {
8 | links[j].classList.remove('active')
9 | }
10 | this.classList.add('active')
11 | })
12 | }
13 |
14 | document.addEventListener('mousemove', (e) => {
15 | const { clientX: mouseX, clientY: mouseY } = e
16 | const { innerWidth: windowWidth, innerHeight: windowHeight } = window
17 |
18 | const percentX = mouseX / windowWidth
19 | const percentY = mouseY / windowHeight
20 |
21 | const moveX = (percentX - 0.5) * 50
22 | const moveY = (percentY - 0.5) * 50
23 |
24 | const background = document.getElementById('container')
25 | background.style.backgroundPosition = `${50 + moveX}% ${50 + moveY}%`
26 | })
27 |
28 | fetch('https://api.github.com/repos/RattlesHyper/TrafficerMC/releases')
29 | .then((response) => response.json())
30 | .then((data) => {
31 | let totalDownloadCount = 0
32 | data.forEach((release) => {
33 | release.assets.forEach((asset) => {
34 | totalDownloadCount += asset.download_count
35 | })
36 | })
37 | const downloadTitle = document.getElementById('download-title')
38 | const count = document.getElementById('downloadcount')
39 | downloadTitle.className = ''
40 | count.innerHTML = totalDownloadCount
41 | })
42 | .catch((error) => console.error('Error:', error))
43 |
--------------------------------------------------------------------------------
/electron-builder.yml:
--------------------------------------------------------------------------------
1 | appId: com.rattleshyper.trafficermc
2 | productName: TrafficerMC
3 | directories:
4 | buildResources: build
5 | files:
6 | - '!**/.vscode/*'
7 | - '!src/*'
8 | - '!electron.vite.config.{js,ts,mjs,cjs}'
9 | - '!{.eslintignore,.eslintrc.cjs,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}'
10 | - '!{.env,.env.*,.npmrc,pnpm-lock.yaml}'
11 | asarUnpack:
12 | - resources/**
13 | win:
14 | target: portable
15 | icon: src/renderer/assets/icons/icon.png
16 | nsis:
17 | artifactName: ${name}-${version}-setup.${ext}
18 | shortcutName: ${productName}
19 | uninstallDisplayName: ${productName}
20 | createDesktopShortcut: always
21 | mac:
22 | entitlementsInherit: build/entitlements.mac.plist
23 | extendInfo:
24 | - NSCameraUsageDescription: Application requests access to the device's camera.
25 | - NSMicrophoneUsageDescription: Application requests access to the device's microphone.
26 | - NSDocumentsFolderUsageDescription: Application requests access to the user's Documents folder.
27 | - NSDownloadsFolderUsageDescription: Application requests access to the user's Downloads folder.
28 | notarize: false
29 | dmg:
30 | artifactName: ${name}-${version}.${ext}
31 | linux:
32 | target:
33 | - AppImage
34 | - snap
35 | - deb
36 | maintainer: electronjs.org
37 | category: Utility
38 | appImage:
39 | artifactName: ${name}-${version}.${ext}
40 | npmRebuild: false
41 | publish:
42 | provider: generic
43 | url:
44 |
--------------------------------------------------------------------------------
/electron.vite.config.mjs:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'electron-vite'
2 |
3 | export default defineConfig({
4 | main: {
5 | plugins: []
6 | },
7 | preload: {
8 | plugins: []
9 | },
10 | renderer: {}
11 | })
12 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "trafficermc",
3 | "version": "3.1.0",
4 | "description": "A Minecraft botting tool with Anti-AFK, Chat spammer, Inventory/Chest manager features.",
5 | "main": "./out/main/index.js",
6 | "author": "RattlesHyper",
7 | "scripts": {
8 | "format": "prettier --write .",
9 | "lint": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix",
10 | "start": "electron-vite preview",
11 | "dev": "electron-vite dev",
12 | "build": "electron-vite build",
13 | "postinstall": "electron-builder install-app-deps",
14 | "build:unpack": "npm run build && electron-builder --dir",
15 | "build:win": "npm run build && electron-builder --win",
16 | "build:mac": "npm run build && electron-builder --mac",
17 | "build:linux": "npm run build && electron-builder --linux"
18 | },
19 | "dependencies": {
20 | "@electron-toolkit/preload": "^3.0.0",
21 | "@electron-toolkit/utils": "^3.0.0",
22 | "electron-store": "^8.2.0",
23 | "mineflayer": "^4.20.1",
24 | "socks": "^2.8.3"
25 | },
26 | "devDependencies": {
27 | "@electron-toolkit/eslint-config": "^1.0.2",
28 | "@electron-toolkit/eslint-config-prettier": "^2.0.0",
29 | "electron": "^28.2.0",
30 | "electron-builder": "^24.9.1",
31 | "electron-vite": "^2.0.0",
32 | "eslint": "^8.56.0",
33 | "prettier": "^3.2.4",
34 | "vite": "^5.0.12"
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/index.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-case-declarations */
2 | import { app, shell, BrowserWindow, ipcMain, dialog } from 'electron'
3 | import { join } from 'path'
4 | import crypto from 'crypto'
5 | import { electronApp, optimizer, is } from '@electron-toolkit/utils'
6 | import fs from 'fs'
7 | import { connection } from './js/proxy/proxyhandler'
8 | import { checkProxy } from './js/proxy/proxycheck'
9 | import { scrapeProxy } from './js/proxy/proxyscrape'
10 | import {
11 | salt,
12 | delay,
13 | genName,
14 | botMode,
15 | sendEvent,
16 | proxyEvent,
17 | notify,
18 | cleanText
19 | } from './js/misc/utils'
20 | import { easyMcAuth } from './js/misc/customAuth'
21 | import EventEmitter from 'node:events'
22 | const Store = require('electron-store')
23 | const mineflayer = require('mineflayer')
24 | import { antiafk } from './js/misc/antiafk'
25 | process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
26 |
27 | const botApi = new EventEmitter()
28 | botApi.setMaxListeners(0)
29 | const store = new Store()
30 |
31 | let stopBot = false
32 | let stopScript = false
33 | let stopProxyTest = false
34 | let currentProxy = 0
35 | let proxyUsed = 0
36 |
37 | function storeinfo() {
38 | return store.get('config')
39 | }
40 |
41 | let clientVersion = 3.1
42 |
43 | let playerList = []
44 |
45 | function createMainWindow() {
46 | const mainWindow = new BrowserWindow({
47 | width: 1000,
48 | height: 500,
49 | show: false,
50 | autoHideMenuBar: true,
51 | frame: false,
52 | resizable: is.dev,
53 | maximizable: is.dev,
54 | webPreferences: {
55 | devTools: is.dev,
56 | preload: join(__dirname, '../preload/index.js'),
57 | sandbox: false
58 | }
59 | })
60 |
61 | ipcMain.on('loaded', () => {
62 | store.set('version', {
63 | current: clientVersion
64 | })
65 | mainWindow.webContents.send('setConfig', store.get('config'), store.get('version'))
66 | if (!storeinfo()) {
67 | mainWindow.webContents.send('initConfig')
68 | }
69 | if (store.get('config.namefile')) {
70 | mainWindow.webContents.send('fileSelected', 'nameFileLabel', store.get('config.namefile'))
71 | }
72 | mainWindow.show()
73 | })
74 |
75 | ipcMain.on('playerList', (event, list) => {
76 | playerList = list
77 | })
78 |
79 | ipcMain.on('open', (event, id, name) => {
80 | dialog
81 | .showOpenDialog(mainWindow, {
82 | title: name,
83 | filters: [{ name: 'Text File', extensions: ['txt'] }],
84 | properties: ['openFile', 'multiSelections']
85 | })
86 | .then((result) => {
87 | if (!result.canceled) {
88 | store.set('config.namefile', result.filePaths[0])
89 | mainWindow.webContents.send('fileSelected', id, result.filePaths[0])
90 | }
91 | })
92 | .catch((error) => {
93 | console.log(error)
94 | return
95 | })
96 | })
97 |
98 | mainWindow.webContents.setWindowOpenHandler((details) => {
99 | shell.openExternal(details.url)
100 | return { action: 'deny' }
101 | })
102 |
103 | if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
104 | mainWindow.loadURL(`${process.env['ELECTRON_RENDERER_URL']}/index.html`)
105 | } else {
106 | mainWindow.loadFile(join(__dirname, '../renderer/index.html'))
107 | }
108 | }
109 |
110 | app.whenReady().then(() => {
111 | electronApp.setAppUserModelId('com.rattleshyper.trafficermc')
112 |
113 | app.on('browser-window-created', (_, window) => {
114 | optimizer.watchWindowShortcuts(window)
115 | optimizer.registerFramelessWindowIpc(window)
116 | })
117 |
118 | createMainWindow()
119 | })
120 |
121 | ipcMain.on('setConfig', (event, type, id, value) => {
122 | store.set(`config.${type}.${id}`, value)
123 | })
124 |
125 | ipcMain.on('deleteConfig', () => {
126 | store.delete('config')
127 | })
128 |
129 | ipcMain.on('checkboxClick', (event, id, state) => {
130 | switch (id) {
131 | case 'test':
132 | console.log(state)
133 | break
134 | default:
135 | }
136 | })
137 |
138 | ipcMain.on('btnClick', (event, btn) => {
139 | switch (btn) {
140 | case 'btnStart':
141 | connectBot()
142 | break
143 | case 'btnStop':
144 | stopBot = true
145 | notify('Info', 'Stopped sending bots.', 'success')
146 | break
147 | case 'btnChat':
148 | exeAll('chat ' + storeinfo().value.chatMsg)
149 | break
150 | case 'btnDisconnect':
151 | exeAll('disconnect')
152 | break
153 | case 'btnSetHotbar':
154 | exeAll('sethotbar ' + storeinfo().value.hotbarSlot)
155 | break
156 | case 'btnUseheld':
157 | exeAll('useheld')
158 | break
159 | case 'btnWinClickRight':
160 | exeAll('winclick ' + storeinfo().value.invSlot + ' 1')
161 | break
162 | case 'btnWinClickLeft':
163 | exeAll('winclick ' + storeinfo().value.invSlot + ' 0')
164 | break
165 | case 'btnDropSlot':
166 | exeAll('drop ' + storeinfo().value.invSlot)
167 | break
168 | case 'btnDropAll':
169 | exeAll('dropall')
170 | break
171 | case 'btnCloseWindow':
172 | exeAll('closewindow')
173 | break
174 | case 'btnStartMove':
175 | exeAll('startmove ' + storeinfo().value.moveType)
176 | break
177 | case 'btnStopMove':
178 | exeAll('stopmove ' + storeinfo().value.moveType)
179 | break
180 | case 'btnResetMove':
181 | exeAll('resetmove')
182 | break
183 | case 'btnLook':
184 | exeAll('look ' + storeinfo().value.lookDirection)
185 | break
186 | case 'btnAfkOn':
187 | exeAll('afkon')
188 | break
189 | case 'btnAfkOff':
190 | exeAll('afkoff')
191 | break
192 | case 'runScript':
193 | playerList.forEach((username) => {
194 | startScript(username)
195 | })
196 | break
197 | case 'stopScript':
198 | stopScript = true
199 | break
200 | case 'proxyTestStart':
201 | testProxy(storeinfo().value.proxyList)
202 | break
203 | case 'proxyTestStop':
204 | stopProxyTest = true
205 | proxyEvent('', 'stop', '', '')
206 | break
207 | case 'proxyScrape':
208 | if (storeinfo().value.proxyType === 'none')
209 | return notify('Error', 'Select proxy type', 'error')
210 | notify('Info', 'Scraping proxies...', 'success')
211 | setProxy()
212 | break
213 | default:
214 | break
215 | }
216 | })
217 |
218 | function setProxy() {
219 | scrapeProxy(storeinfo().value.proxyType)
220 | .then((result) => {
221 | proxyEvent('', 'scraped', result, '')
222 | })
223 | .catch((err) => {
224 | console.log(err)
225 | notify('Error', 'Failed to scrape proxies', 'error')
226 | })
227 | }
228 |
229 | async function testProxy(list) {
230 | stopProxyTest = false
231 | const server = storeinfo().value.server
232 | const [serverHost, serverPort] = server.split(':')
233 | if (!serverHost) return notify('Error', 'Invalid server address', 'error')
234 | if (!list) return notify('Error', 'Please enter proxy list', 'error')
235 | if (storeinfo().value.proxyType === 'none') return notify('Error', 'Select proxy type', 'error')
236 | notify('Info', 'Testing proxies...', 'success')
237 | proxyEvent('', 'start', '', '')
238 | const lines = list.split(/\r?\n/)
239 | for (let i = 0; i < lines.length; i++) {
240 | if (stopProxyTest) break
241 | const count = `${i + 1}/${lines.length}`
242 | const [host, port, username, password] = lines[i].split(':')
243 | checkProxy(
244 | storeinfo().value.proxyType,
245 | host,
246 | port,
247 | username,
248 | password,
249 | serverHost,
250 | serverPort || 25565,
251 | storeinfo().value.proxyCheckTimeout || 5000
252 | )
253 | .then((result) => {
254 | proxyEvent(result.proxy, 'success', '', count)
255 | })
256 | .catch((error) => {
257 | proxyEvent(error.proxy, 'fail', error.reason, count)
258 | })
259 | if (lines.length == i + 1) {
260 | proxyEvent('', 'stop', '', '')
261 | }
262 | await delay(storeinfo().value.proxyCheckDelay || 100)
263 | }
264 | }
265 |
266 | async function startScript(username) {
267 | stopScript = false
268 | if (!storeinfo().value.scriptText) return
269 | const scriptLines = storeinfo().value.scriptText.split(/\r?\n/)
270 | for (let i = 0; i < scriptLines.length; i++) {
271 | if (stopScript) break
272 | const args = scriptLines[i].split(' ')
273 | const command = args.shift().toLowerCase()
274 | switch (command) {
275 | case 'delay':
276 | await delay(parseInt(args[0]))
277 | break
278 | default:
279 | botApi.emit('botEvent', username, command, args.slice(0))
280 | }
281 | }
282 | }
283 |
284 | async function exeAll(command) {
285 | if (!command) return
286 | const list = playerList
287 | const cmd = command.split(' ')
288 | if (list.length == 0) return notify('Error', 'No bots selected', 'error')
289 | for (let i = 0; i < list.length; i++) {
290 | botApi.emit('botEvent', list[i], cmd[0], cmd.slice(1))
291 | if (storeinfo().boolean.isLinear) {
292 | await delay(storeinfo().value.linearDelay || 100)
293 | }
294 | }
295 | sendEvent('Executed', 'chat', 'Script: ' + command)
296 | }
297 |
298 | async function startFile() {
299 | BrowserWindow.getAllWindows()[0].webContents.send('showBottab')
300 | const filePath = storeinfo().namefile
301 | const lines = fs.readFileSync(filePath, 'utf-8').split(/\r?\n/)
302 | const count = storeinfo().value.botMax || lines.length
303 |
304 | for (let i = 0; i < count; i++) {
305 | if (stopBot) break
306 | newBot(getBotInfo(lines[i]))
307 | await delay(storeinfo().value.joinDelay || 1000)
308 | }
309 | }
310 |
311 | async function connectBot() {
312 | stopBot = false
313 | currentProxy = 0
314 | proxyUsed = 0
315 | const count = storeinfo().value.botMax || 1
316 |
317 | if (storeinfo().value.nameType === 'file' && storeinfo().namefile) {
318 | BrowserWindow.getAllWindows()[0].webContents.send('showBottab')
319 | } else if (storeinfo().value.nameType !== 'file' && storeinfo().value.nameType !== 'default') {
320 | BrowserWindow.getAllWindows()[0].webContents.send('showBottab')
321 | }
322 |
323 | for (let i = 0; i < count; i++) {
324 | if (stopBot) break
325 |
326 | let botInfo
327 |
328 | switch (storeinfo().value.nameType) {
329 | case 'random':
330 | botInfo = getBotInfo(salt(10))
331 | break
332 | case 'legit':
333 | botInfo = getBotInfo(genName())
334 | break
335 | case 'file':
336 | if (!storeinfo().namefile) {
337 | notify('Error', 'Please select name file', 'error')
338 | } else {
339 | startFile()
340 | }
341 | return
342 | default:
343 | if (!storeinfo().value.username) return notify('Error', 'Please insert username', 'error')
344 | const username =
345 | count == 1 ? storeinfo().value.username : storeinfo().value.username + '_' + i
346 | botInfo = getBotInfo(username)
347 | if (i == 0) BrowserWindow.getAllWindows()[0].webContents.send('showBottab')
348 | }
349 |
350 | newBot(botInfo)
351 | await delay(storeinfo().value.joinDelay || 1000)
352 | }
353 | }
354 |
355 | function getBotInfo(botName) {
356 | const server = storeinfo().value.server || 'localhost:25565'
357 | const [serverHost, serverPort] = server.split(':')
358 | const parsedPort = parseInt(serverPort) || 25565
359 |
360 | const options = {
361 | host: serverHost,
362 | port: parsedPort,
363 | username: botName,
364 | version: storeinfo().value.version,
365 | auth: storeinfo().value.authType,
366 | hideErrors: true,
367 | joinMessage: storeinfo().value.joinMessage,
368 | ...botMode(storeinfo().value.botMode),
369 | ...getProxy(storeinfo().value.proxyType)
370 | }
371 |
372 | if (options.auth === 'easymc') {
373 | options.auth = easyMcAuth
374 | options.sessionServer = 'https://sessionserver.easymc.io'
375 | }
376 |
377 | return options
378 | }
379 |
380 | function getProxy(proxyType) {
381 | if (proxyType === 'none' || !storeinfo().value.proxyList) return
382 |
383 | const proxyList = storeinfo().value.proxyList.split(/\r?\n/)
384 | const randomIndex = crypto.randomInt(0, proxyList.length)
385 |
386 | const proxyPerBot = storeinfo().value.proxyPerBot
387 |
388 | if (proxyUsed >= proxyPerBot) {
389 | proxyUsed = 0
390 | currentProxy++
391 | if (currentProxy >= proxyList.length) {
392 | currentProxy = 0
393 | }
394 | }
395 |
396 | proxyUsed++
397 |
398 | const index = storeinfo().boolean.randomizeOrder ? randomIndex : currentProxy
399 | const [host, port, username, password] = proxyList[index].split(':')
400 | return {
401 | protocol: proxyType,
402 | proxyHost: host,
403 | proxyPort: port,
404 | proxyUsername: username,
405 | proxyPassword: password
406 | }
407 | }
408 |
409 | function newBot(options) {
410 | let bot
411 |
412 | if (options.auth === 'easymc') {
413 | if (options.easyMcToken?.length !== 20) {
414 | return sendEvent(options.username, 'easymcAuth')
415 | }
416 | options.auth = easyMcAuth
417 | options.sessionServer ||= 'https://sessionserver.easymc.io'
418 | }
419 |
420 | const connectProxy = async (client) => {
421 | try {
422 | const socket = await connection(
423 | storeinfo().value.proxyType,
424 | options.proxyHost,
425 | options.proxyPort,
426 | options.proxyUsername,
427 | options.proxyPassword,
428 | options.host,
429 | options.port
430 | )
431 | client.setSocket(socket)
432 | client.emit('connect')
433 | } catch (error) {
434 | if (storeinfo().boolean.proxyLogChat) {
435 | sendEvent(
436 | client.username,
437 | 'chat',
438 | options.proxyHost + ':' + options.proxyPort + ' ' + error
439 | )
440 | }
441 | return
442 | }
443 | }
444 |
445 | if (storeinfo().value.proxyType !== 'none') {
446 | options.connect = connectProxy
447 | }
448 |
449 | bot = mineflayer.createBot({
450 | ...options,
451 | plugins: {
452 | anvil: false,
453 | book: false,
454 | boss_bar: false,
455 | breath: false,
456 | chest: false,
457 | command_block: false,
458 | craft: false,
459 | creative: false,
460 | enchantment_table: false,
461 | experience: false,
462 | explosion: false,
463 | fishing: false,
464 | furnace: false,
465 | generic_place: false,
466 | painting: false,
467 | particle: false,
468 | place_block: false,
469 | place_entity: false,
470 | rain: false,
471 | ray_trace: false,
472 | scoreboard: false,
473 | sound: false,
474 | spawn_point: false,
475 | tablist: false,
476 | team: false,
477 | time: false,
478 | title: false,
479 | villager: false
480 | },
481 | onMsaCode: (data) => {
482 | sendEvent(options.username, 'authmsg', data.user_code)
483 | }
484 | })
485 |
486 | let hitTimer = 0
487 |
488 | bot.once('login', () => {
489 | sendEvent(bot._client.username, 'login')
490 | if (storeinfo().boolean.runOnConnect) {
491 | startScript(bot._client.username)
492 | }
493 | if (storeinfo().value.joinMessage) {
494 | bot.chat(storeinfo().value.joinMessage)
495 | }
496 | })
497 | bot.once('spawn', () => {
498 | bot.loadPlugin(antiafk)
499 | })
500 | bot.on('spawn', () => {
501 | if (storeinfo().boolean.runOnSpawn) {
502 | startScript(bot._client.username)
503 | }
504 | })
505 | bot.on('messagestr', (msg) => {
506 | sendEvent(bot._client.username, 'chat', msg)
507 | })
508 | bot.on('windowOpen', (window) => {
509 | sendEvent(
510 | bot._client.username,
511 | 'chat',
512 | `Window Opened ' ${window.title ? ':' + window.title : ''}`
513 | )
514 | })
515 | bot.on('windowClose', (window) => {
516 | sendEvent(
517 | bot._client.username,
518 | 'chat',
519 | `Window Closed ' ${window.title ? ':' + window.title : ''}`
520 | )
521 | })
522 | bot.once('kicked', (reason) => {
523 | const parsed = JSON.parse(reason)
524 | sendEvent(bot._client.username, 'kicked', cleanText(parsed))
525 | })
526 | bot.once('end', (reason) => {
527 | sendEvent(bot._client.username, 'end', reason)
528 | if (storeinfo().boolean.autoReconnect) {
529 | setTimeout(() => {
530 | newBot(options)
531 | }, storeinfo().value.reconnectDelay || 1000)
532 | }
533 | })
534 |
535 | bot.on('physicTick', () => {
536 | if (storeinfo().boolean.killauraToggle && playerList.includes(bot._client.username)) {
537 | killaura()
538 | }
539 | })
540 |
541 | function killaura() {
542 | if (hitTimer <= 0) {
543 | hit(
544 | storeinfo().boolean.targetPlayer,
545 | storeinfo().boolean.targetVehicle,
546 | storeinfo().boolean.targetMob,
547 | storeinfo().boolean.targetAnimal,
548 | storeinfo().value.killauraRange,
549 | storeinfo().boolean.killauraRotate
550 | )
551 | hitTimer = storeinfo().value.killauraDelay || 10
552 | } else {
553 | hitTimer--
554 | }
555 | }
556 |
557 | function hit(player, vehicle, mob, animal, maxDistance, rotate) {
558 | let targetEntities = []
559 | const entities = Object.values(bot.entities)
560 | entities.forEach((entity) => {
561 | const distance = bot.entity.position.distanceTo(entity.position)
562 | if (distance >= parseFloat(maxDistance)) return
563 | if (entity.type === 'player' && entity.username !== bot.username && player) {
564 | targetEntities.push(entity)
565 | }
566 | if (entity.kind === 'Vehicles' && vehicle) {
567 | targetEntities.push(entity)
568 | }
569 | if (entity.kind === 'Hostile mobs' && mob) {
570 | targetEntities.push(entity)
571 | }
572 | if (entity.kind === 'Passive mobs' && animal) {
573 | targetEntities.push(entity)
574 | }
575 | })
576 | targetEntities.forEach((entity) => {
577 | if (rotate) {
578 | bot.lookAt(entity.position, true)
579 | bot.attack(entity)
580 | } else {
581 | bot.attack(entity)
582 | }
583 | })
584 | }
585 |
586 | botApi.on('botEvent', (target, event, ...options) => {
587 | if (target !== bot._client.username) return
588 | const optionsArray = options[0]
589 | switch (event) {
590 | case 'disconnect':
591 | bot.quit()
592 | break
593 | case 'chat':
594 | const bypass = storeinfo().boolean.bypassChat ? ' ' + salt(crypto.randomInt(2, 6)) : ''
595 | bot.chat(
596 | optionsArray
597 | .join(' ')
598 | .replaceAll('{random}', salt(4))
599 | .replaceAll('{player}', bot._client.username) + bypass
600 | )
601 | break
602 | case 'notify':
603 | notify(
604 | 'Bot',
605 | bot._client.username +
606 | ': ' +
607 | optionsArray
608 | .join(' ')
609 | .replaceAll('{random}', salt(4))
610 | .replaceAll('{player}', bot._client.username),
611 | 'success'
612 | )
613 | break
614 | case 'sethotbar':
615 | bot.setQuickBarSlot(parseInt(optionsArray[0] ? optionsArray[0] : 0))
616 | break
617 | case 'useheld':
618 | bot.activateItem()
619 | break
620 | case 'winclick':
621 | bot.clickWindow(parseInt(optionsArray[0]), parseInt(optionsArray[1]), 0)
622 | break
623 | case 'drop':
624 | bot.clickWindow(-999, 0, 0)
625 | bot.clickWindow(parseInt(optionsArray[0]), 0, 0)
626 | bot.clickWindow(-999, 0, 0)
627 | break
628 | case 'dropall':
629 | ;(async () => {
630 | const itemCount = bot.inventory.items().length
631 | for (var i = 0; i < itemCount; i++) {
632 | if (bot.inventory.items().length === 0) return
633 | const item = bot.inventory.items()[0]
634 | bot.tossStack(item)
635 | await delay(10)
636 | }
637 | })()
638 | break
639 | case 'closewindow':
640 | bot.closeWindow(bot.currentWindow || '')
641 | break
642 | case 'startmove':
643 | bot.setControlState(optionsArray[0], true)
644 | break
645 | case 'stopmove':
646 | bot.setControlState(optionsArray[0], false)
647 | break
648 | case 'resetmove':
649 | bot.clearControlStates()
650 | break
651 | case 'look':
652 | bot.look(parseFloat(optionsArray[0]), 0, true)
653 | break
654 | case 'afkon':
655 | bot.afk.start()
656 | break
657 | case 'afkoff':
658 | bot.afk.stop()
659 | break
660 | case 'hit':
661 | const player = optionsArray[0]
662 | const vehicle = optionsArray[1]
663 | const mob = optionsArray[2]
664 | const animal = optionsArray[3]
665 | const maxDistance = parseFloat(optionsArray[4])
666 | const rotate = optionsArray[5]
667 | hit(player, vehicle, mob, animal, maxDistance, rotate)
668 | break
669 | default:
670 | }
671 | })
672 | }
673 |
674 | process.on('uncaughtException', (err) => {
675 | console.log(err)
676 | })
677 | process.on('UnhandledPromiseRejectionWarning', (err) => {
678 | console.log(err)
679 | })
680 |
--------------------------------------------------------------------------------
/src/main/js/misc/antiafk.js:
--------------------------------------------------------------------------------
1 | async function rotate(bot) {
2 | let yaw = 2 * Math.random() * Math.PI - 0.5 * Math.PI
3 | let pitch = Math.random() * Math.PI - 0.5 * Math.PI
4 | await bot.look(yaw, pitch, false)
5 | }
6 |
7 | function jump(bot) {
8 | return new Promise((resolve) => {
9 | bot.setControlState('jump', true)
10 | if (!bot.entity.isInWater) bot.setControlState('jump', false)
11 | setTimeout(resolve, 1000)
12 | })
13 | }
14 | async function swingArm(bot) {
15 | let arm = Math.random() < 0.5 ? 'right' : 'left'
16 | await bot.swingArm(arm)
17 | }
18 | async function start(bot) {
19 | if (bot.afk.stopping) {
20 | bot.afk.stopped = true
21 | return
22 | }
23 | if (bot._client.state != 'play') {
24 | bot.once('spawn', () => start(bot))
25 | return
26 | }
27 | if (bot.entity.isInWater) bot.setControlState('jump', true)
28 | await bot.afk[bot.afk.config.actions[Math.floor(Math.random() * 3)]]()
29 | start(bot)
30 | }
31 |
32 | function setOptions(bot) {
33 | let config = bot.afk.config
34 | config.actions = ['rotate', 'jump', 'swingArm']
35 | }
36 |
37 | function stop(bot) {
38 | bot.afk.stopping = true
39 | return new Promise((resolve) => {
40 | if (!bot.afk.enabled) resolve('nothing to stop')
41 | setInterval(() => {
42 | if (bot.afk.stopped) {
43 | bot.afk.stopping = null
44 | bot.afk.stopped = null
45 | bot.afk.enabled = false
46 | resolve('stopped successfully')
47 | }
48 | }, 500)
49 | })
50 | }
51 |
52 | export function antiafk(bot) {
53 | bot.afk = {
54 | config: {},
55 | enabled: false,
56 | start: async () => {
57 | bot.afk.enabled = true
58 | await start(bot)
59 | },
60 | stop: async () => await stop(bot),
61 | setOptions: (opt) =>
62 | setOptions(bot, {
63 | ...opt
64 | }),
65 | rotate: async () => await rotate(bot),
66 | jump: async () => await jump(bot),
67 | swingArm: async () => await swingArm(bot)
68 | }
69 | bot.afk.setOptions()
70 | }
71 |
--------------------------------------------------------------------------------
/src/main/js/misc/customAuth.js:
--------------------------------------------------------------------------------
1 | import { sendEvent } from './utils'
2 |
3 | export async function easyMcAuth(client, options) {
4 | if (options.username?.length !== 20) return sendEvent(options.username, 'easymcAuth')
5 | const fetchOptions = {
6 | method: 'POST',
7 | headers: { 'Content-Type': 'application/json' },
8 | body: `{"token":"${options.username}"}`
9 | }
10 | try {
11 | const res = await fetch('https://api.easymc.io/v1/token/redeem', fetchOptions)
12 | const resJson = await res.json()
13 | if (resJson.error) return sendEvent('EasyMC', 'chat', `${resJson.error}`)
14 | if (!resJson) return sendEvent('EasyMC', 'chat', 'Empty response from EasyMC.')
15 | if (resJson.session?.length !== 43 || resJson.mcName?.length < 3 || resJson.uuid?.length !== 36)
16 | return sendEvent('EasyMC', 'chat', 'Invalid response from EasyMC.')
17 | const session = {
18 | accessToken: resJson.session,
19 | selectedProfile: {
20 | name: resJson.mcName,
21 | id: resJson.uuid
22 | }
23 | }
24 | options.haveCredentials = true
25 | client.session = session
26 | client.username = session.selectedProfile.name
27 | options.accessToken = session.accessToken
28 | client.emit('session', session)
29 | } catch (error) {
30 | return client.emit('error', error.message)
31 | }
32 | options.connect(client)
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/js/misc/utils.js:
--------------------------------------------------------------------------------
1 | import { BrowserWindow } from 'electron'
2 |
3 | export function salt(length) {
4 | var result = ''
5 | var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
6 | for (var i = 0; i < length; i++) {
7 | result += characters.charAt(Math.floor(Math.random() * characters.length))
8 | }
9 | return result
10 | }
11 |
12 | export function delay(ms) {
13 | return new Promise((res) => setTimeout(res, ms))
14 | }
15 |
16 | export function botMode(mode) {
17 | switch (mode) {
18 | case 'minimal':
19 | return {
20 | physicsEnabled: false,
21 | viewDistance: 'tiny',
22 | plugins: {
23 | anvil: false,
24 | block_actions: false,
25 | blocks: false,
26 | book: false,
27 | boss_bar: false,
28 | breath: false,
29 | chest: false,
30 | command_block: false,
31 | conversions: false,
32 | craft: false,
33 | creative: false,
34 | digging: false,
35 | enchantment_table: false,
36 | entities: false,
37 | experience: false,
38 | explosion: false,
39 | fishing: false,
40 | furnace: false,
41 | generic_place: false,
42 | health: false,
43 | inventory: false,
44 | loader: false,
45 | painting: false,
46 | particle: false,
47 | place_block: false,
48 | place_entity: false,
49 | physics: false,
50 | rain: false,
51 | ray_trace: false,
52 | resource_pack: false,
53 | scoreboard: false,
54 | simple_inventory: false,
55 | sound: false,
56 | spawn_point: false,
57 | tablist: false,
58 | team: false,
59 | time: false,
60 | title: false,
61 | villager: false
62 | }
63 | }
64 | default:
65 | return
66 | }
67 | }
68 |
69 | export function genName() {
70 | const adjectives = [
71 | 'Red',
72 | 'Hot',
73 | 'Big',
74 | 'Old',
75 | 'New',
76 | 'Dry',
77 | 'Wet',
78 | 'Tall',
79 | 'Soft',
80 | 'Loud',
81 | 'Cold',
82 | 'Warm',
83 | 'Dark',
84 | 'Fair',
85 | 'Blue',
86 | 'Gray',
87 | 'Rich',
88 | 'Poor',
89 | 'Fast',
90 | 'Slow',
91 | 'Thin',
92 | 'Tiny',
93 | 'Wide',
94 | 'High',
95 | 'Deep',
96 | 'Dear',
97 | 'Neat',
98 | 'Cool',
99 | 'Fine',
100 | 'Lame',
101 | 'Sharp',
102 | 'Dull',
103 | 'Cute',
104 | 'Long',
105 | 'Short',
106 | 'Hard',
107 | 'Mean',
108 | 'Kind',
109 | 'Sick',
110 | 'Weak',
111 | 'Pure',
112 | 'Evil',
113 | 'Bold',
114 | 'Mild',
115 | 'Wild',
116 | 'Mad',
117 | 'Calm',
118 | 'Wise',
119 | 'Dumb',
120 | 'Slim',
121 | 'Thick',
122 | 'Pale',
123 | 'Stale',
124 | 'Ugly'
125 | ]
126 | const nouns = [
127 | '_',
128 | 'Dog',
129 | 'Cat',
130 | 'Pen',
131 | 'Car',
132 | 'Cup',
133 | 'Hat',
134 | 'Sun',
135 | 'Bed',
136 | 'Box',
137 | 'Key',
138 | 'Arm',
139 | 'Ball',
140 | 'Book',
141 | 'Cake',
142 | 'Duck',
143 | 'Fish',
144 | 'Fork',
145 | 'Hand',
146 | 'Bird',
147 | 'Moon',
148 | 'Star',
149 | 'Tree',
150 | 'Ring',
151 | 'Shoe',
152 | 'Bear',
153 | 'Coat',
154 | 'Flag',
155 | 'Lamp',
156 | 'Leaf',
157 | 'Desk',
158 | 'Nail',
159 | 'Sock',
160 | 'Rose',
161 | 'Boat',
162 | 'Frog',
163 | 'Pipe',
164 | 'Rock',
165 | 'Seal',
166 | 'Boot',
167 | 'Worm',
168 | 'Bat',
169 | 'Bell',
170 | 'Belt',
171 | 'Door',
172 | 'Drum',
173 | 'Gate',
174 | 'Hair',
175 | 'Head',
176 | 'Heart',
177 | 'Kiss',
178 | 'Lady',
179 | 'Lark',
180 | 'Lion',
181 | 'Bowl',
182 | 'Deer',
183 | 'Goat',
184 | 'Nose',
185 | 'Bone',
186 | 'Bull',
187 | 'Food',
188 | 'Gown',
189 | 'Gulf',
190 | 'Horn',
191 | 'Joke',
192 | 'Jute',
193 | 'Milk',
194 | 'Mole',
195 | 'Navy',
196 | 'Pony',
197 | 'Queen',
198 | 'Rope',
199 | 'Ruff',
200 | 'Shin',
201 | 'Tong',
202 | 'Light',
203 | 'Trot',
204 | 'Vase',
205 | 'Wren',
206 | 'Yoke',
207 | 'Zulu'
208 | ]
209 | const adjectivesLength = adjectives.length
210 | const nounsLength = nouns.length
211 | let name = ''
212 |
213 | while (name.length < 6 || name.length + 1 > 16) {
214 | const adjectiveIndex = Math.floor(Math.random() * adjectivesLength)
215 | const nounIndex = Math.floor(Math.random() * nounsLength)
216 | const newName = `${adjectives[adjectiveIndex]}${nouns[nounIndex]}`
217 |
218 | if (newName.length + name.length > 16) {
219 | break
220 | }
221 |
222 | name += newName
223 |
224 | if (Math.random() < 0.15) {
225 | const num = Math.floor(Math.random() * 999 + 1)
226 | if (name.length + num.toString().length > 16) {
227 | break
228 | }
229 | name += num
230 | }
231 | }
232 |
233 | const lowerCaseName = name.toLowerCase()
234 | const hasLowerCase = name !== lowerCaseName
235 | name += hasLowerCase ? lowerCaseName.slice(0, 16 - name.length) : ''
236 |
237 | return name
238 | }
239 |
240 | export function sendEvent(username, event, message) {
241 | const info = {
242 | id: username,
243 | event: event,
244 | message: message
245 | }
246 | BrowserWindow.getAllWindows()[0].webContents.send('botEvent', info)
247 | }
248 |
249 | export function proxyEvent(proxy, event, message, count) {
250 | const info = {
251 | proxy: proxy,
252 | event: event,
253 | message: message,
254 | count: count
255 | }
256 | BrowserWindow.getAllWindows()[0].webContents.send('proxyEvent', info)
257 | }
258 |
259 | export function notify(title, body, type, img, keep) {
260 | BrowserWindow.getAllWindows()[0].webContents.send('notify', title, body, type, img, keep)
261 | }
262 |
263 | export function cleanText(string) {
264 | let texts = []
265 |
266 | function recurse(obj) {
267 | if (obj.text) {
268 | texts.push(obj.text.replace(/\n/g, ' '))
269 | }
270 | if (obj.extra) {
271 | for (let item of obj.extra) {
272 | recurse(item)
273 | }
274 | }
275 | }
276 |
277 | recurse(string)
278 | return texts.join('').replaceAll(' ', ' ')
279 | }
280 |
--------------------------------------------------------------------------------
/src/main/js/proxy/proxycheck.js:
--------------------------------------------------------------------------------
1 | const mc = require('minecraft-protocol')
2 | import { connection } from './proxyhandler'
3 | import { salt } from '../misc/utils'
4 |
5 | export function checkProxy(
6 | proxyType,
7 | proxyHost,
8 | proxyPort,
9 | proxyUsername,
10 | proxyPassword,
11 | dHost,
12 | dPort,
13 | timeout
14 | ) {
15 | return new Promise((resolve, reject) => {
16 | const bot = mc.createClient({
17 | host: dHost,
18 | port: parseInt(dPort),
19 | username: salt(10),
20 | auth: 'offline',
21 | connect: async (client) => {
22 | try {
23 | const socket = await connection(
24 | proxyType,
25 | proxyHost,
26 | proxyPort,
27 | proxyUsername,
28 | proxyPassword,
29 | dHost,
30 | dPort
31 | )
32 | client.setSocket(socket)
33 | client.emit('connect')
34 | } catch (error) {
35 | const info = {
36 | reason: 'bad',
37 | error: error,
38 | proxy: proxyHost + ':' + proxyPort
39 | }
40 | return reject(info)
41 | }
42 | }
43 | })
44 |
45 | setTimeout(() => {
46 | bot.end()
47 | const info = {
48 | reason: 'timeout',
49 | proxy: proxyHost + ':' + proxyPort
50 | }
51 | return reject(info)
52 | }, timeout)
53 |
54 | bot.on('connect', () => {
55 | bot.end()
56 | const info = {
57 | reason: 'success',
58 | proxy: `${proxyHost}:${proxyPort}${proxyUsername ? `:${proxyUsername}` : ''}${proxyPassword ? `:${proxyPassword}` : ''}`
59 | }
60 | return resolve(info)
61 | })
62 |
63 | bot.on('error', (error) => {
64 | const info = {
65 | reason: 'bad',
66 | error: error.message,
67 | proxy: proxyHost + ':' + proxyPort
68 | }
69 | return reject(info)
70 | })
71 | })
72 | }
73 |
--------------------------------------------------------------------------------
/src/main/js/proxy/proxyhandler.js:
--------------------------------------------------------------------------------
1 | import { SocksClient } from 'socks'
2 | import { Socket } from 'net'
3 |
4 | export function connection(
5 | proxyType,
6 | proxyHost,
7 | proxyPort,
8 | proxyUsername,
9 | proxyPassword,
10 | dHost,
11 | dPort
12 | ) {
13 | return new Promise((resolve, reject) => {
14 | if (proxyType === 'socks5' || proxyType === 'socks4') {
15 | SocksClient.createConnection(
16 | {
17 | proxy: {
18 | host: proxyHost,
19 | port: parseInt(proxyPort),
20 | userId: proxyUsername,
21 | password: proxyPassword,
22 | type: proxyType === 'socks5' ? 5 : 4
23 | },
24 | command: 'connect',
25 | destination: {
26 | host: dHost,
27 | port: parseInt(dPort)
28 | }
29 | },
30 | (err, info) => {
31 | if (err) {
32 | return reject(err.message)
33 | }
34 | resolve(info.socket)
35 | }
36 | )
37 | } else {
38 | const socket = new Socket().connect({
39 | host: dHost,
40 | port: parseInt(dPort)
41 | })
42 | socket.on('connect', () => {
43 | resolve(socket)
44 | })
45 | socket.on('error', (err) => {
46 | return reject(err.message)
47 | })
48 | }
49 | })
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/js/proxy/proxyscrape.js:
--------------------------------------------------------------------------------
1 | export async function scrapeProxy(proxyType) {
2 | const proxyLink = `https://raw.githubusercontent.com/RattlesHyper/proxy/main/${proxyType}`
3 | const proxySources = await fetchList(proxyLink)
4 | const promises = proxySources.map(fetchList)
5 | const proxyLists = await Promise.all(promises)
6 | let list = ''
7 | for (const proxies of proxyLists) {
8 | list += proxies.join('\n')
9 | }
10 | return list
11 | }
12 |
13 | async function fetchList(link) {
14 | const res = await fetch(link, { cache: 'force-cache' })
15 | const text = await res.text()
16 | const result = []
17 | let start = 0
18 | let i = 0
19 | while (i !== -1) {
20 | i = text.indexOf('\n', start)
21 | if (i === -1) {
22 | if (start < text.length) result.push(text.slice(start))
23 | } else {
24 | result.push(text.slice(start, i))
25 | start = i + 1
26 | }
27 | }
28 | return result
29 | }
30 |
--------------------------------------------------------------------------------
/src/preload/index.js:
--------------------------------------------------------------------------------
1 | import { contextBridge } from 'electron'
2 | import { electronAPI } from '@electron-toolkit/preload'
3 |
4 | const api = {}
5 | if (process.contextIsolated) {
6 | try {
7 | contextBridge.exposeInMainWorld('electron', electronAPI)
8 | contextBridge.exposeInMainWorld('api', api)
9 | } catch (error) {
10 | console.error(error)
11 | }
12 | } else {
13 | window.electron = electronAPI
14 | window.api = api
15 | }
16 |
--------------------------------------------------------------------------------
/src/renderer/assets/css/base.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --ev-c-white: #ffffff;
3 | --ev-c-white-soft: #f8f8f8;
4 | --ev-c-white-mute: #f2f2f2;
5 |
6 | --ev-c-black: rgb(27, 27, 31);
7 | --ev-c-black-soft: rgb(34, 34, 34);
8 | --ev-c-black-mute: rgb(40, 40, 40);
9 |
10 | --ev-c-gray-1: #515c67;
11 | --ev-c-gray-2: #414853;
12 | --ev-c-gray-3: #32363f;
13 |
14 | --ev-c-blue-1: #50928f;
15 | --ev-c-blue-2: #3e7f88;
16 |
17 | --ev-c-success: #f8f8f8;
18 | --ev-c-warning: #ffaa00;
19 | --ev-c-error: #ff5555;
20 |
21 | --ev-c-text-1: rgba(255, 255, 245, 0.86);
22 | --ev-c-text-2: rgba(235, 235, 245, 0.6);
23 | --ev-c-text-3: rgba(235, 235, 245, 0.38);
24 |
25 | --ev-button-alt-border: transparent;
26 | --ev-button-alt-text: var(--ev-c-text-1);
27 | --ev-button-alt-bg: var(--ev-c-gray-3);
28 | --ev-button-alt-hover-border: transparent;
29 | --ev-button-alt-hover-text: var(--ev-c-text-1);
30 | --ev-button-alt-hover-bg: var(--ev-c-gray-2);
31 | }
32 |
33 | :root {
34 | --color-background: var(--ev-c-black);
35 | --color-background-soft: var(--ev-c-black-soft);
36 | --color-background-mute: var(--ev-c-black-mute);
37 | --color-text: var(--ev-c-text-1);
38 | }
39 |
40 | *,
41 | *::before,
42 | *::after {
43 | box-sizing: border-box;
44 | margin: 0;
45 | font-weight: normal;
46 | }
47 |
48 | ul {
49 | list-style: none;
50 | }
51 |
52 | body {
53 | min-height: 100vh;
54 | color: var(--color-text);
55 | background: var(--color-background);
56 | line-height: 1.6;
57 | font-family:
58 | Inter,
59 | -apple-system,
60 | BlinkMacSystemFont,
61 | 'Segoe UI',
62 | Roboto,
63 | Oxygen,
64 | Ubuntu,
65 | Cantarell,
66 | 'Fira Sans',
67 | 'Droid Sans',
68 | 'Helvetica Neue',
69 | sans-serif;
70 | text-rendering: optimizeLegibility;
71 | -webkit-font-smoothing: antialiased;
72 | -moz-osx-font-smoothing: grayscale;
73 | }
74 |
--------------------------------------------------------------------------------
/src/renderer/assets/css/main.css:
--------------------------------------------------------------------------------
1 | @import './base.css';
2 |
3 | body {
4 | display: flex;
5 | overflow: hidden;
6 | background-image: url('../icons/background.svg');
7 | background-size: cover;
8 | user-select: none;
9 | }
10 |
11 | code {
12 | font-weight: 600;
13 | padding: 3px 5px;
14 | border-radius: 2px;
15 | background-color: var(--color-background-mute);
16 | font-family:
17 | ui-monospace,
18 | SFMono-Regular,
19 | SF Mono,
20 | Menlo,
21 | Consolas,
22 | Liberation Mono,
23 | monospace;
24 | font-size: 85%;
25 | }
26 |
27 | .disabled {
28 | color: var(--ev-c-text-3);
29 | }
30 |
31 | .content {
32 | width: 725px;
33 | height: 400px;
34 | }
35 |
36 | .topbar {
37 | width: 725px;
38 | height: 30px;
39 | background-color: rgba(40, 40, 40, 0.8);
40 | display: flex;
41 | justify-content: space-between;
42 | align-items: center;
43 | padding: 0 20px;
44 | }
45 |
46 | .sidebar {
47 | position: fixed;
48 | top: 30px;
49 | left: 0px;
50 | height: 440px;
51 | width: 110px;
52 | background-color: rgba(40, 40, 40, 0.8);
53 |
54 | list-style-type: none;
55 | }
56 |
57 | .sidebar li {
58 | cursor: pointer;
59 | position: relative;
60 | left: 15px;
61 | font-size: 20px;
62 | font-weight: 700;
63 | }
64 |
65 | .sidebar li:hover {
66 | color: var(--ev-c-text-2);
67 | }
68 |
69 | .sidebar li.selected {
70 | left: 2px;
71 | padding-left: 10px;
72 | border-left: #e8eaed 3px solid;
73 | }
74 |
75 | .notification {
76 | position: absolute;
77 | max-height: 440px;
78 | bottom: 35px;
79 | right: 10px;
80 | display: flex;
81 | flex-direction: column-reverse;
82 | overflow: hidden;
83 | }
84 |
85 | .n-message {
86 | word-wrap: break-word;
87 | }
88 |
89 | .n-progress {
90 | position: relative;
91 | top: 10px;
92 | right: 10px;
93 | height: 4px;
94 | background: var(--ev-c-white-soft);
95 | animation: toastProgress 3s ease-in-out forwards;
96 | }
97 |
98 | .notification li {
99 | overflow: hidden;
100 | margin-top: 5px;
101 | width: 300px;
102 | max-width: 300px;
103 | padding: 0.5rem;
104 | border-radius: 4px;
105 | background: var(--color-background-mute);
106 | animation: slideInRight 0.3s ease-in-out forwards;
107 | opacity: 0.9;
108 | }
109 |
110 | .notification li:hover {
111 | opacity: 1;
112 | }
113 |
114 | .notification .fade {
115 | animation: fadeOut 0.3s ease-in-out forwards;
116 | }
117 |
118 | .notification .success {
119 | border-left: solid 1px var(--ev-c-success);
120 | }
121 | .notification .warning {
122 | border-left: solid 1px var(--ev-c-warning);
123 | }
124 | .notification .error {
125 | border-left: solid 1px var(--ev-c-error);
126 | }
127 |
128 | .control-tab {
129 | text-align: center;
130 | }
131 |
132 | .controlArea {
133 | position: fixed;
134 | top: 30px;
135 | left: 110px;
136 | height: 440px;
137 | width: 890px;
138 | }
139 |
140 | .containerCheckbox {
141 | text-align: start;
142 | display: block;
143 | position: relative;
144 | padding-left: 30px;
145 | cursor: pointer;
146 | font-weight: 600;
147 | }
148 |
149 | .containerCheckbox input {
150 | opacity: 0;
151 | height: 0;
152 | width: 0;
153 | }
154 |
155 | .checkmark {
156 | position: absolute;
157 | top: 0;
158 | left: 0;
159 | height: 25px;
160 | width: 25px;
161 | background-color: transparent;
162 | background-color: transparent;
163 | border: solid 1px var(--ev-c-gray-1);
164 | }
165 |
166 | .containerCheckbox:hover input~.checkmark {
167 | background-color: var(--ev-c-gray-2);
168 | }
169 |
170 | .containerCheckbox input:checked~.checkmark {
171 | background-color: var(--ev-c-gray-1);
172 | }
173 |
174 | .checkmark:after {
175 | content: "";
176 | position: absolute;
177 | display: none;
178 | }
179 |
180 | .containerCheckbox input:checked~.checkmark:after {
181 | display: block;
182 | }
183 |
184 | .containerCheckbox .checkmark:after {
185 | left: 9px;
186 | top: 6px;
187 | width: 6px;
188 | height: 10px;
189 | border: solid var(--ev-c-white);
190 | border-width: 0 3px 3px 0;
191 | -webkit-transform: rotate(45deg);
192 | -ms-transform: rotate(45deg);
193 | transform: rotate(45deg);
194 | }
195 |
196 | .slidecontainer {
197 | width: 100%;
198 | }
199 |
200 | .slider {
201 | appearance: none;
202 | position: relative;
203 | left: 5px;
204 | top: 5px;
205 | height: 10px;
206 | background: var(--ev-c-gray-2);
207 | border-radius: 4px;
208 | }
209 |
210 | .slider:hover {
211 | background: var(--ev-c-gray-1);
212 | }
213 |
214 | .slider::-webkit-slider-thumb {
215 | -webkit-appearance: none;
216 | appearance: none;
217 | width: 10px;
218 | height: 15px;
219 | border-radius: 2px;
220 | background: var(--ev-c-white);
221 | cursor: pointer;
222 | }
223 |
224 | ::-webkit-scrollbar {
225 | width: 5px;
226 | height: 0px;
227 | }
228 |
229 | ::-webkit-scrollbar-thumb {
230 | background-color: var(--ev-c-gray-1);
231 | }
232 |
233 | ::-webkit-scrollbar-thumb:hover {
234 | background-color: var(--ev-c-gray-2);
235 | }
236 |
237 | .downbar {
238 | background-color: #1b3c6e;
239 | }
240 |
241 | .area {
242 | display: flex;
243 | justify-content: space-between;
244 | padding: 10px 20px;
245 | }
246 |
247 | .textinput {
248 | background-color: rgba(40, 40, 40, 0.8);
249 | border: none;
250 | color: #e8eaed;
251 | word-wrap: break-word;
252 | outline: none;
253 | display: flex;
254 | padding: 10px;
255 | margin-top: 10px;
256 | font-size: 14px;
257 | border-bottom: 1px solid #B0B3B9;
258 | -webkit-tap-highlight-color: transparent;
259 | }
260 |
261 | .textbox {
262 | resize: none;
263 | color: var(--ev-c-text-1);
264 | font-weight: 600;
265 | padding: 3px 5px;
266 | border-radius: 2px;
267 | background-color: var(--color-background-mute);
268 | font-family:
269 | ui-monospace,
270 | SFMono-Regular,
271 | SF Mono,
272 | Menlo,
273 | Consolas,
274 | Liberation Mono,
275 | monospace;
276 | font-size: 85%;
277 | opacity: 0.9;
278 | }
279 |
280 | input {
281 | width: 165px;
282 | color: var(--ev-c-white);
283 | background-color: transparent;
284 | border: none;
285 |
286 | font-size: 14px;
287 | color: var(--ev-c-text-1);
288 | font-weight: 600;
289 | }
290 |
291 | input[type=number] {
292 | border-bottom: solid 1px var(--ev-c-gray-1);
293 | }
294 |
295 | input[type=text] {
296 | border-bottom: solid 1px var(--ev-c-gray-1);
297 | }
298 |
299 | input::placeholder {
300 | color: var(--ev-c-gray-1);
301 | }
302 |
303 | input[type=number]::-webkit-inner-spin-button,
304 | input[type=number]::-webkit-outer-spin-button {
305 | -webkit-appearance: none;
306 | margin: 0;
307 | }
308 |
309 | input[type=file]::-webkit-file-upload-button {
310 | display: none;
311 | }
312 |
313 | input[type=file]::before {
314 | content: 'Select files';
315 | display: inline-block;
316 | border: 1px solid #999;
317 | border-radius: 3px;
318 | padding: 2px 5px;
319 | margin: 5px;
320 | cursor: pointer;
321 | }
322 |
323 | .input-file {
324 | border: solid 1px var(--ev-c-gray-1);
325 | color: var(--ev-c-text-1);
326 | font-size: 14px;
327 | font-weight: 600;
328 | padding: 0px 5px 0px 5px;
329 | border-radius: 3px;
330 | background-color: transparent;
331 | cursor: pointer;
332 | }
333 |
334 | *:focus {
335 | outline: none;
336 | }
337 |
338 | ul {
339 | padding: 0px;
340 | }
341 |
342 | .settings-tab {
343 | position: fixed;
344 | left: 0;
345 | top: 30px;
346 | bottom: 30px;
347 | width: 100%;
348 | overflow: auto;
349 | background-color: rgba(0, 0, 0, 0.4);
350 | display: none;
351 | }
352 |
353 | .settings-tab-content {
354 | position: fixed;
355 | background-color: var(--color-background-mute);
356 | margin-top: 50px;
357 | margin-left: 10%;
358 | padding: 20px;
359 | border: 1px solid var(--ev-c-gray-2);
360 | overflow: scroll;
361 | width: 80%;
362 | height: 350px;
363 | }
364 |
365 | #chatBox {
366 | width: 340px;
367 | height: 380px;
368 | overflow: scroll;
369 | }
370 |
371 | #chatBox li {
372 | padding: 5px 10px;
373 | word-wrap: break-word;
374 | border: solid 1px var(--ev-c-gray-2);
375 | animation: fadeIn 0.3s;
376 | }
377 |
378 | #proxyLogbox {
379 | height: 122px;
380 | overflow: scroll;
381 | }
382 |
383 | #proxyLogbox li {
384 | padding: 5px 10px;
385 | word-wrap: break-word;
386 | border: solid 1px var(--ev-c-gray-2);
387 | }
388 |
389 | #proxyLogbox .success {
390 | background: -webkit-linear-gradient(180deg, #2a5038 5%, #2d535100);
391 | }
392 |
393 | #proxyLogbox .timeout {
394 | background: -webkit-linear-gradient(180deg, #4e572e 5%, #2d535100);
395 | }
396 |
397 | #proxyLogbox .fail {
398 | background: -webkit-linear-gradient(180deg, #572d2b 5%, #2d535100);
399 | }
400 |
401 | #controlList {
402 | height: 220px;
403 | overflow: scroll;
404 | }
405 |
406 | #controlList li {
407 | text-align: center;
408 | font-size: 14px;
409 | cursor: pointer;
410 | font-weight: 600;
411 | position: relative;
412 | left: 1px;
413 | padding: 2px 0px 2px 0px;
414 | word-wrap: break-word;
415 | overflow-wrap: break-word;
416 | border: 1px solid var(--ev-c-gray-1);
417 | }
418 |
419 | #controlList li.selected {
420 | position: relative;
421 | left: -1px;
422 | border-right: none;
423 | border-left: #e8eaed 6px solid;
424 | }
425 |
426 | #controlList li:hover {
427 | background-color: var(--ev-c-gray-2);
428 | }
429 |
430 | #botList {
431 | width: 200px;
432 | overflow: scroll;
433 | list-style-type: none;
434 | }
435 |
436 | #botList li {
437 | font-weight: 600;
438 | padding: 0px 0px 3px 10px;
439 | word-wrap: break-word;
440 | overflow-wrap: break-word;
441 | }
442 |
443 | #botList li:hover {
444 | background-color: var(--ev-c-gray-2);
445 | }
446 |
447 | #botList .selected {
448 | border-right: solid 2px var(--ev-c-text-2);
449 | border-left: solid 2px var(--ev-c-text-2);
450 | background: var(--ev-c-gray-1);
451 | }
452 |
453 | #botList .selected:hover {
454 | border-right: solid 2px var(--ev-c-text-2);
455 | border-left: solid 2px var(--ev-c-text-2);
456 | background: var(--ev-c-gray-2);
457 | }
458 |
459 |
460 | select {
461 | background-color: transparent;
462 | border: none;
463 | font-size: 14px;
464 | color: var(--ev-c-text-1);
465 | font-weight: 600;
466 | padding: 0px 0px 0px 10px;
467 | background-color: transparent;
468 | cursor: pointer;
469 | }
470 |
471 | select option {
472 | background: var(--color-background-mute);
473 | font-size: 14px;
474 | color: var(--ev-c-text-1);
475 | font-weight: 600;
476 | }
477 |
478 | button {
479 | background: var(--ev-c-gray-3);
480 | color: var(--ev-c-text-1);
481 | font-size: 14px;
482 | font-weight: 600;
483 | padding: 5px 30px;
484 | cursor: pointer;
485 | border: solid 1px var(--ev-c-gray-2);
486 | opacity: 0.9;
487 | }
488 |
489 | button:hover {
490 | background-color: var(--ev-c-gray-2);
491 | opacity: 0.9;
492 | }
493 |
494 | .drag {
495 | -webkit-app-region: drag;
496 | }
497 |
498 | .border {
499 | border: solid 1px var(--ev-c-gray-2);
500 | }
501 |
502 | .logo {
503 | margin-bottom: 20px;
504 | -webkit-user-drag: none;
505 | height: 128px;
506 | width: 128px;
507 | will-change: filter;
508 | transition: filter 300ms;
509 | }
510 |
511 | .logo:hover {
512 | filter: drop-shadow(0 0 1.2em #6988e6aa);
513 | }
514 |
515 | .creator {
516 | font-size: 14px;
517 | line-height: 16px;
518 | color: var(--ev-c-text-2);
519 | font-weight: 600;
520 | margin-bottom: 10px;
521 | }
522 |
523 | .space-h {
524 | justify-content: space-between;
525 | display: flex;
526 | }
527 |
528 | .space-h-f {
529 | width: 100%;
530 | display: flex;
531 | }
532 |
533 | .text {
534 | font-size: 28px;
535 | font-weight: 700;
536 | color: var(--ev-c-text-1);
537 | }
538 |
539 | .text-sm {
540 | font-size: 16px;
541 | color: var(--ev-c-text-1);
542 | font-weight: 600;
543 | }
544 |
545 | .text-sm-2 {
546 | font-size: 12px;
547 | color: var(--ev-c-text-1);
548 | font-weight: 600;
549 | }
550 |
551 | .tip {
552 | font-size: 16px;
553 | color: var(--ev-c-text-2);
554 | font-weight: 600;
555 | }
556 |
557 | .tip-sm {
558 | font-size: 12px;
559 | color: var(--ev-c-text-2);
560 | font-weight: 600;
561 | }
562 |
563 | .pointer {
564 | cursor: pointer;
565 | }
566 |
567 | .link {
568 | color: var(--ev-c-blue-1);
569 | }
570 |
571 | .vl {
572 | border-left: 2px solid var(--ev-c-gray-2);
573 | }
574 |
575 | img {
576 | -webkit-user-drag: none;
577 | }
578 |
579 | .icon-sm {
580 | position: relative;
581 | top: 4px;
582 | width: 18px;
583 | height: 18px;
584 | margin-right: 3px;
585 | -webkit-app-region: no-drag;
586 | }
587 |
588 | .icon-sm:hover {
589 | filter: blur(1px) brightness(1.5);
590 | }
591 |
592 | .gradient {
593 | background: -webkit-linear-gradient(180deg, #c1b5c7 5%, #332c96);
594 | background-clip: text;
595 | -webkit-background-clip: text;
596 | -webkit-text-fill-color: transparent;
597 | font-weight: 700;
598 | }
599 |
600 | .flex {
601 | display: flex;
602 | }
603 |
604 | .flex-c {
605 | display: flex;
606 | flex-direction: column;
607 | }
608 |
609 | .m-4 {
610 | margin: 1rem;
611 | }
612 |
613 | .mu-4 {
614 | margin-top: 1rem;
615 | }
616 |
617 | .mu-2 {
618 | margin-top: 0.5rem;
619 | }
620 |
621 | .mu-1 {
622 | margin-top: 0.2rem;
623 | }
624 |
625 | .pl-4 {
626 | padding-left: 1rem;
627 | }
628 |
629 | .pl-2 {
630 | padding-left: 0.5rem;
631 | }
632 |
633 | .pr-4 {
634 | padding-right: 0.50rem;
635 | }
636 |
637 | .action {
638 | flex-shrink: 0;
639 | padding: 10px 0px;
640 | }
641 |
642 | .float-right {
643 | float: right;
644 | }
645 |
646 | .float-left {
647 | float: left;
648 | }
649 |
650 | .action a {
651 | cursor: pointer;
652 | text-decoration: none;
653 | display: inline-block;
654 | border: 1px solid transparent;
655 | text-align: center;
656 | font-weight: 600;
657 | white-space: nowrap;
658 | border-radius: 3px;
659 | padding: 0 20px;
660 | line-height: 25px;
661 | font-size: 14px;
662 | border-color: var(--ev-button-alt-border);
663 | color: var(--ev-button-alt-text);
664 | background-color: var(--ev-button-alt-bg);
665 | }
666 |
667 | .action a:hover {
668 | border-color: var(--ev-button-alt-hover-border);
669 | color: var(--ev-button-alt-hover-text);
670 | background-color: var(--ev-button-alt-hover-bg);
671 | }
672 |
673 | .versions {
674 | position: absolute;
675 | bottom: 30px;
676 | margin: 0 auto;
677 | padding: 15px 0;
678 | font-family: 'Menlo', 'Lucida Console', monospace;
679 | display: inline-flex;
680 | overflow: hidden;
681 | align-items: center;
682 | border-radius: 22px;
683 | background-color: #202127;
684 | backdrop-filter: blur(24px);
685 | }
686 |
687 | .versions li {
688 | display: block;
689 | float: left;
690 | border-right: 1px solid var(--ev-c-gray-1);
691 | padding: 0 20px;
692 | font-size: 14px;
693 | line-height: 14px;
694 | opacity: 0.8;
695 |
696 | &:last-child {
697 | border: none;
698 | }
699 | }
700 |
701 | @media (max-width: 720px) {
702 | .text {
703 | font-size: 20px;
704 | }
705 | }
706 |
707 | @media (max-width: 620px) {
708 | .versions {
709 | display: none;
710 | }
711 | }
712 |
713 | @media (max-width: 350px) {
714 |
715 | .tip,
716 | .actions {
717 | display: none;
718 | }
719 | }
720 |
721 | @keyframes slideInRight {
722 | 0% {
723 | transform: translateX(110%);
724 | }
725 |
726 | 100% {
727 | transform: translateX(0%);
728 | }
729 | }
730 |
731 | @keyframes fadeOut {
732 | 0% {
733 | opacity: 0.9;
734 | }
735 |
736 | 100% {
737 | opacity: 0;
738 | }
739 | }
740 |
741 | @keyframes fadeIn {
742 | 0% {
743 | opacity: 0;
744 | }
745 |
746 | 100% {
747 | opacity: 1;
748 | }
749 | }
750 |
751 | @keyframes toastProgress {
752 | 0% {
753 | width: 300px;
754 | }
755 |
756 | 100% {
757 | width: 0px;
758 | }
759 | }
760 |
--------------------------------------------------------------------------------
/src/renderer/assets/icons/alert.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/assets/icons/background.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/assets/icons/clock.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/assets/icons/discord.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/assets/icons/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RattlesHyper/TrafficerMC/e9bd554ffd695ab56781104d357363aa3442b347/src/renderer/assets/icons/icon.png
--------------------------------------------------------------------------------
/src/renderer/assets/icons/min.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/assets/icons/settings.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/renderer/assets/icons/spinner.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/renderer/assets/icons/user.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/assets/icons/x.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |

15 |
TrafficerMC
16 |
17 |
18 |
19 |

20 |

21 |
22 |
23 |
24 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
58 |
59 |
60 |
Server:
61 |
62 |
63 |
64 |
65 |
66 |
Max accounts:
67 |
68 |
69 |
70 |
71 |
Join delay:
72 |
73 |
74 |
75 |
76 |
Join message:
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
Options
89 |
90 |
91 |
Name:
92 |
93 |
99 |
100 |
101 |
102 |
103 |
File:
104 |
105 |
106 |
107 |
108 |
109 |
Auth:
110 |
116 |
117 |
118 |
119 |
Version:
120 |
164 |
165 |
166 |
167 |
Mode:
168 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
192 |
193 |
194 |
195 |
196 |
197 | - Controls
198 | - Chat
199 | - Hotbar
200 | - Inventory
201 | - Move
202 | - Look
203 | - AntiAFK
204 | - KillAura
205 | - Interact
206 | - Nuker
207 | - Pathfinder
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
Controls
216 |
217 |
218 |
219 |
220 |
221 |
222 |
Chat
223 |
224 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
239 |
240 |
244 |
245 |
246 |
247 |
252 |
253 |
258 |
259 |
260 |
261 |
262 |
263 |
Hotbar
264 |
265 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
Inventory
287 |
288 |
292 |
293 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
Move
323 |
324 |
325 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
Look
347 |
348 |
349 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
Anti AFK
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
Interact [Premium]
371 |
372 |
376 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
KillAura
389 |
390 |
391 |
421 |
422 |
423 |
426 |
427 |
431 |
432 |
433 |
Range
434 |
435 |
1
436 |
437 |
6
438 |
439 |
440 |
441 |
442 |
447 |
448 |
453 |
454 |
455 |
456 |
457 |
458 |
459 |
Nuker [Premium]
460 |
461 |
462 |
465 |
466 |
467 |
Up
468 |
469 |
0
470 |
471 |
6
472 |
473 |
474 |
475 |
476 |
Down
477 |
478 |
0
479 |
480 |
6
481 |
482 |
483 |
484 |
485 |
Left
486 |
487 |
0
488 |
489 |
6
490 |
491 |
492 |
493 |
494 |
Right
495 |
496 |
0
497 |
498 |
6
499 |
500 |
501 |
502 |
503 |
Forward
504 |
505 |
0
506 |
507 |
6
508 |
509 |
510 |
511 |
512 |
Back
513 |
514 |
0
515 |
516 |
6
517 |
518 |
519 |
520 |
523 |
524 |
525 |
Target mode
526 |
530 |
531 |
532 |
536 |
537 |
538 |
Blcks/tick
539 |
540 |
541 |
542 |
547 |
548 |
553 |
554 |
555 |
556 |
557 |
558 |
Pathfinder
559 |
560 |
561 |
568 |
569 |
570 |
Commands
571 |
follow (player)
Follows a player
572 |
followLine (player)
Forms a line
573 |
goto X Y Z / X Z
Walks to a location
574 |
stop
Stops pathfinder
575 |
576 |
577 |
578 |
579 |
580 |
581 |
582 |
604 |
605 |
606 |
607 |
608 |
609 |
610 |
611 |
Script
612 |
613 |
614 |
615 |
616 |
617 |
618 |
619 |
620 |
621 |
622 |
638 |
639 |
640 |
641 |
642 |
643 |
644 |
645 |
646 |
647 |
648 |
Proxy
649 |
650 |
Type:
651 |
657 |
658 |
659 |
660 |
661 |
662 |
663 |
664 |
665 |
666 |
667 |
668 |
669 |
670 |
671 |
Options
672 |
673 |
674 |
Proxy per bot
675 |
676 |
1
677 |
678 |
10
679 |
680 |
681 |
682 |
687 |
688 |
689 |
690 |
691 |
Proxy test
692 |
693 |
697 |
698 |
699 |
Timeout
700 |
701 |
702 |
703 |
Logs
704 |
705 |
706 |
707 |
708 |
713 |
714 |
715 |
716 |
717 |
718 |
719 |
720 |
721 |
722 |
723 |
724 |
725 |
740 |
741 |
787 |
788 |
789 |
790 |
791 |
792 |
793 |
794 |
795 |
796 |
797 |
798 |
799 |

800 |
TrafficerMC
801 |
802 |
803 |
808 |
809 |
810 |
811 |
812 |
813 |
814 |
815 |
816 |
817 |
818 |
819 |
820 |
914 |
915 |
916 |
917 |
918 |

919 |
0
920 |
921 |
922 |

923 |
00:00
924 |
925 |
926 |
927 |

928 |
/
929 |
930 |
931 |
932 |
933 |

934 |
935 |
936 |
937 |
938 |
939 |
940 |
1004 |
1005 |
1006 |
1007 |
--------------------------------------------------------------------------------
/src/renderer/src/index.js:
--------------------------------------------------------------------------------
1 | window.addEventListener('DOMContentLoaded', () => {
2 | window.electron?.ipcRenderer.send('loaded')
3 |
4 | window.electron?.ipcRenderer.on('setConfig', (event, config, version) => {
5 | setConfigValues(config)
6 | fetch('https://raw.githubusercontent.com/RattlesHyper/TrafficerMC/main/VERSION', {
7 | method: 'GET'
8 | })
9 | .then((response) => response.text())
10 | .then((result) => {
11 | const liveVersion = parseFloat(result)
12 | const currentVersion = version.current
13 | if (currentVersion != liveVersion) {
14 | notify('Warning', 'New version available. Please update your client', 'warning')
15 | }
16 | })
17 | document.getElementById('versionString').innerHTML = `v${version.current}`
18 | })
19 |
20 | window.electron?.ipcRenderer.on('fileSelected', (event, id, path) => {
21 | const filename = path.match(/[^\\]+$/)[0]
22 | document.getElementById(id).innerHTML = filename
23 | })
24 |
25 | window.electron?.ipcRenderer.on('showBottab', () => {
26 | document.getElementById('bottingTab').click()
27 | })
28 |
29 | const valueElements = document.querySelectorAll(
30 | 'input[type="text"], input[type="number"], input[type="range"], select, textarea'
31 | )
32 | valueElements.forEach((select) => {
33 | select.addEventListener('change', valueChange)
34 | })
35 |
36 | const checkboxElements = document.querySelectorAll('input[type="checkbox"]')
37 | checkboxElements.forEach((check) => {
38 | check.addEventListener('click', checkboxClick)
39 | })
40 |
41 | const buttonElements = document.querySelectorAll('button, .button')
42 | buttonElements.forEach((button) => {
43 | button.addEventListener('click', buttonClick)
44 | })
45 |
46 | const tabElements = document.querySelectorAll('.tab, .tab-2')
47 | tabElements.forEach((tab) => {
48 | tab.addEventListener('click', navClick)
49 | })
50 |
51 | window.electron?.ipcRenderer.on('initConfig', () => {
52 | valueElements.forEach((select) => {
53 | if (!select.id) return
54 | window.electron?.ipcRenderer.send('setConfig', 'value', select.id, select.value)
55 | })
56 | checkboxElements.forEach((check) => {
57 | if (!check.id) return
58 | window.electron?.ipcRenderer.send('setConfig', 'boolean', check.id, check.checked)
59 | })
60 | })
61 |
62 | window.electron?.ipcRenderer.on('notify', (event, title, body, type, img, keep) => {
63 | notify(title, body, type, img, keep)
64 | })
65 |
66 | window.electron?.ipcRenderer.on('proxyEvent', (event, info) => {
67 | if (info.event === 'scraped') {
68 | logProxy('Scraped', 'success', '')
69 | } else {
70 | logProxy(info.proxy, info.event, info.message)
71 | }
72 | document.getElementById('proxyCheckStatusCount').innerHTML = info.count
73 | switch (info.event) {
74 | case 'start':
75 | document.getElementById('proxyCheckStatus').style.display = 'block'
76 | document.getElementById('proxyList').value = ''
77 | break
78 | case 'stop':
79 | document.getElementById('proxyCheckStatus').style.display = 'none'
80 | notify('Info', 'Stopped proxy test.', 'success')
81 | updateProxyList()
82 | break
83 | case 'success':
84 | document.getElementById('proxyList').value += `${info.proxy}\n`
85 | updateProxyList()
86 | break
87 | case 'scraped':
88 | document.getElementById('proxyList').value += `\n${info.message}\n`
89 | clearProxyEmpty()
90 | updateProxyList()
91 | break
92 | default:
93 | }
94 | })
95 |
96 | window.electron?.ipcRenderer.on('botEvent', (event, info) => {
97 | switch (info.event) {
98 | case 'login':
99 | addPlayer(info.id)
100 | logChat('Bot', info.id, 'Connected to the server.')
101 | break
102 | case 'authmsg':
103 | directChat(
104 | ` First time signing in. Use a web browser to open the page https://www.microsoft.com/link and enter the code: ${info.message} [click to copy]
`
105 | )
106 | break
107 | case 'easymcAuth':
108 | directChat(
109 | ` EasyMC authentication requires an alt token. Check https://easymc.io/get to get a token.
`
110 | )
111 | break
112 | case 'chat':
113 | logChat('Bot', info.id, info.message)
114 | break
115 | case 'kicked':
116 | logChat('Bot', info.id, 'Kicked: ' + info.message)
117 | removePlayer(info.id)
118 | break
119 | case 'end':
120 | logChat('Bot', info.id, 'Connection: ' + info.message)
121 | removePlayer(info.id)
122 | break
123 | default:
124 | }
125 | })
126 | // setInterval(() => {
127 | // logChat('Bot', 'Username', 'TEST')
128 | // notify('TEST', 'Welcome back User', 'success')
129 | // logProxy('proxy:port', 'fail', 'Test')
130 | // }, 1000)
131 | })
132 |
133 | function valueChange(event) {
134 | const selectedValue = event.target.value
135 | const selectId = event.target.id
136 | window.electron?.ipcRenderer.send('setConfig', 'value', selectId, selectedValue)
137 |
138 | switch (selectId) {
139 | case 'nameType':
140 | checkUsername()
141 | break
142 | default:
143 | }
144 | }
145 |
146 | function buttonClick(event) {
147 | const buttonId = event.target.id
148 | switch (buttonId) {
149 | case 'minimize':
150 | window.electron?.ipcRenderer.send('win:invoke', 'min')
151 | break
152 | case 'close':
153 | window.electron?.ipcRenderer.send('win:invoke', 'close')
154 | break
155 | case 'resetConfig':
156 | window.electron?.ipcRenderer.send('deleteConfig')
157 | notify('Info', 'Config has been reset. Please restart the app', 'success')
158 | break
159 | case 'nameFileLabel':
160 | window.electron?.ipcRenderer.send('open', 'nameFileLabel', 'Name File')
161 | break
162 | case 'selectAll':
163 | selectAll()
164 | break
165 | case 'proxyClearDupe':
166 | clearDupe()
167 | notify('Info', 'Cleared duplicate proxies', 'success')
168 | break
169 | default:
170 | window.electron?.ipcRenderer.send('btnClick', buttonId)
171 | break
172 | }
173 | }
174 |
175 | function checkboxClick(event) {
176 | const checkId = event.target.id
177 | const state = event.target.checked
178 | window.electron?.ipcRenderer.send('setConfig', 'boolean', checkId, state)
179 | window.electron?.ipcRenderer.send('checkboxClick', checkId, state)
180 | }
181 |
182 | function navClick(event) {
183 | const classes = event.target.classList
184 | const navName = event.target.innerText.toLowerCase()
185 | const tabContent = document.getElementsByClassName(classes[1])
186 |
187 | Array.from(tabContent).forEach((content) => {
188 | if (!content.classList.contains(classes[0])) {
189 | content.style.display = 'none'
190 | }
191 | })
192 |
193 | const selectedContent = document.getElementById(navName)
194 | selectedContent.style.display = 'block'
195 |
196 | const tabs = document.getElementsByClassName(classes[0])
197 | Array.from(tabs).forEach((tab) => {
198 | tab.classList.remove('selected')
199 | })
200 |
201 | event.currentTarget.classList.add('selected')
202 | }
203 |
204 | function checkUsername() {
205 | const nameType = document.getElementById('nameType')
206 | const fileDiv = document.getElementById('nameFileDiv')
207 |
208 | const isFileBased = nameType.value === 'file'
209 | fileDiv.style.display = isFileBased ? 'block' : 'none'
210 | }
211 |
212 | function setConfigValues(obj) {
213 | for (const keyType in obj) {
214 | const keys = Object.keys(obj[keyType])
215 | for (const key of keys) {
216 | const element = document.getElementById(key)
217 | if (element) {
218 | if (keyType === 'value') {
219 | element.value = obj.value[key]
220 | } else if (keyType === 'boolean') {
221 | element.checked = obj.boolean[key]
222 | }
223 | }
224 | }
225 | }
226 | checkUsername()
227 | }
228 |
229 | function notify(title, body, type, img, keep) {
230 | const notification = document.createElement('li')
231 | notification.className = type
232 |
233 | const top = document.createElement('div')
234 | top.className = 'space-h'
235 |
236 | const topbar = document.createElement('div')
237 | topbar.className = 'flex'
238 |
239 | const titleText = document.createElement('p')
240 | titleText.className = 'text-sm'
241 | titleText.innerHTML = title
242 | topbar.appendChild(titleText)
243 |
244 | const closeDiv = document.createElement('div')
245 | const closeBtn = document.createElement('p')
246 | closeBtn.className = 'text-sm'
247 | closeBtn.innerHTML = 'X'
248 | closeBtn.onclick = () => rmNotification()
249 | closeDiv.appendChild(closeBtn)
250 |
251 | top.appendChild(topbar)
252 | top.appendChild(closeDiv)
253 |
254 | const bodyDiv = document.createElement('div')
255 | bodyDiv.className = 'n-message'
256 | const bodyText = document.createElement('p')
257 | bodyText.className = 'tip-sm'
258 | bodyText.innerText = body
259 | bodyDiv.appendChild(bodyText)
260 | if (img) {
261 | const imgTag = document.createElement('img')
262 | imgTag.src = img
263 | bodyDiv.appendChild(imgTag)
264 | }
265 |
266 | notification.appendChild(top)
267 | notification.appendChild(bodyDiv)
268 |
269 | document.getElementById('notifications').appendChild(notification)
270 |
271 | if (!keep) {
272 | const progress = document.createElement('div')
273 | progress.className = 'n-progress'
274 | notification.appendChild(progress)
275 | setTimeout(() => {
276 | rmNotification()
277 | }, 3000)
278 | }
279 | function rmNotification() {
280 | notification.classList.add('fade')
281 | setTimeout(() => {
282 | notification.remove()
283 | }, 300)
284 | }
285 | }
286 |
287 | function addPlayer(name) {
288 | const list = document.getElementById('botList')
289 | const auto = document.getElementById('autoSelect').checked
290 | const b = document.createElement('li')
291 | b.className = 'botListItem'
292 | b.innerHTML = name
293 | b.onclick = () => {
294 | b.classList.toggle('selected')
295 | updateSelected()
296 | }
297 | list.appendChild(b)
298 | list.scrollTop = list.scrollHeight
299 | updateBotCount()
300 | if (auto) {
301 | selectAll('auto')
302 | }
303 | }
304 |
305 | function removePlayer(name) {
306 | const list = document.querySelectorAll('.botListItem')
307 | list.forEach((bot) => {
308 | if (bot.innerHTML === name) {
309 | bot.remove()
310 | updateSelected()
311 | }
312 | })
313 | updateBotCount()
314 | }
315 |
316 | function updateBotCount() {
317 | const count = document.getElementById('botCount')
318 | const list = document.getElementById('botList')
319 | count.innerHTML = list.children.length
320 | }
321 |
322 | function selectAll(auto) {
323 | const list = document.getElementById('botList')
324 | const allSelected = Array.from(list.children).every((li) => li.classList.contains('selected'))
325 | Array.from(list.children).forEach((bot) => {
326 | if (auto) {
327 | bot.classList.toggle('selected', true)
328 | } else {
329 | bot.classList.toggle('selected', !allSelected)
330 | }
331 | })
332 | updateSelected()
333 | }
334 |
335 | function updateSelected() {
336 | const list = document.getElementById('botList')
337 | const selectedBots = Array.from(list.children).filter((bot) => bot.classList.contains('selected'))
338 | window.electron?.ipcRenderer.send(
339 | 'playerList',
340 | selectedBots.map((bot) => bot.innerHTML)
341 | )
342 | }
343 |
344 | function logProxy(proxy, type, message) {
345 | const scroll = document.getElementById('autoScrollProxy').checked
346 | const logBox = document.getElementById('proxyLogbox')
347 | const li = document.createElement('li')
348 | li.className = type
349 | const updiv = document.createElement('div')
350 | updiv.className = 'space-h'
351 |
352 | const ddiv = document.createElement('div')
353 | const msg = document.createElement('p')
354 | msg.className = 'text-sm-2 mu-1'
355 | msg.style = 'user-select: text;'
356 | msg.innerHTML = message
357 | ddiv.appendChild(msg)
358 |
359 | const pl = document.createElement('p')
360 | pl.style = 'user-select: text;'
361 | pl.className = 'text-sm'
362 | pl.innerHTML = proxy
363 | updiv.appendChild(pl)
364 |
365 | const pr = document.createElement('p')
366 | pr.className = 'text-sm'
367 | pr.innerHTML = type
368 |
369 | updiv.appendChild(pr)
370 |
371 | li.appendChild(updiv)
372 | li.appendChild(ddiv)
373 |
374 | logBox.appendChild(li)
375 | if (scroll) {
376 | logBox.scrollTop = logBox.scrollHeight
377 | }
378 | }
379 |
380 | function clearProxyEmpty() {
381 | const textarea = document.getElementById('proxyList')
382 | const lines = textarea.value.split('\n')
383 | const nonEmptyLines = lines.filter(function (line) {
384 | return line.trim() !== ''
385 | })
386 | textarea.value = nonEmptyLines.join('\n')
387 | }
388 |
389 | function clearDupe() {
390 | const textarea = document.getElementById('proxyList')
391 | const lines = textarea.value.split('\n')
392 | const uniqueLines = {}
393 | for (let i = 0; i < lines.length; i++) {
394 | const line = lines[i].trim()
395 | uniqueLines[line] = true
396 | }
397 | const uniqueLinesArray = Object.keys(uniqueLines)
398 | const result = uniqueLinesArray.join('\n')
399 | textarea.value = result
400 | }
401 |
402 | function updateProxyList() {
403 | window.electron?.ipcRenderer.send(
404 | 'setConfig',
405 | 'value',
406 | 'proxyList',
407 | document.getElementById('proxyList').value
408 | )
409 | }
410 |
411 | function logChat(prefix, name, text) {
412 | const enable = document.getElementById('enableChat').checked
413 | if (!enable) return
414 | const chatBox = document.getElementById('chatBox')
415 | const scroll = document.getElementById('autoScrollChat').checked
416 |
417 | const li = document.createElement('li')
418 |
419 | const spaceHDiv = document.createElement('div')
420 | spaceHDiv.className = 'space-h'
421 |
422 | const flexDiv = document.createElement('div')
423 | flexDiv.className = 'flex'
424 |
425 | const prefixP = document.createElement('p')
426 | prefixP.className = 'text-sm link'
427 | prefixP.textContent = prefix
428 |
429 | flexDiv.appendChild(prefixP)
430 |
431 | const spaceHFDiv = document.createElement('div')
432 | spaceHFDiv.className = 'space-h-f pl-2'
433 |
434 | const nameP = document.createElement('p')
435 | nameP.className = 'text-sm'
436 | nameP.style = 'user-select: text;'
437 | nameP.textContent = name
438 |
439 | spaceHFDiv.appendChild(nameP)
440 |
441 | spaceHDiv.appendChild(flexDiv)
442 | spaceHDiv.appendChild(spaceHFDiv)
443 |
444 | const textP = document.createElement('p')
445 | textP.className = 'text-sm-2'
446 | textP.style = 'user-select: text;'
447 | textP.textContent = text
448 |
449 | li.appendChild(spaceHDiv)
450 | li.appendChild(textP)
451 |
452 | chatBox.appendChild(li)
453 |
454 | if (scroll) {
455 | chatBox.scrollTop = chatBox.scrollHeight
456 | }
457 | }
458 |
459 | function directChat(string) {
460 | const chatBox = document.getElementById('chatBox')
461 | const li = document.createElement('li')
462 | li.innerHTML = string
463 | chatBox.appendChild(li)
464 | }
465 |
--------------------------------------------------------------------------------