├── .gitignore
├── Battle.py
├── LICENSE.txt
├── Pixelverse.py
├── README.md
├── config.json
├── images
├── image-1.png
├── image-2.png
├── image.png
└── screen.png
├── main.py
└── requirements.txt
/.gitignore:
--------------------------------------------------------------------------------
1 | *env
2 | __pycache__
3 | *.bat
4 | *.zip
5 | test*
6 | *copy*
7 | config.json
--------------------------------------------------------------------------------
/Battle.py:
--------------------------------------------------------------------------------
1 | import asyncio
2 | import websockets
3 | import json
4 | from random import randint
5 | from colorama import Fore, Style, Back
6 | from time import sleep
7 | from time import time
8 |
9 | class Battle:
10 | """Represents a battle session in the Pixelverse game."""
11 |
12 | def __init__(self):
13 | """Initializes the Battle object with game settings."""
14 | self.url = 'https://api-clicker.pixelverse.xyz/api/users'
15 | with open('./config.json', 'r') as file:
16 | config = json.load(file)
17 |
18 | self.secret = config['secret']
19 | self.tgId = config['tgId']
20 | self.initData = config['initData']
21 | self.hitRate = config['hitRate']
22 |
23 | self.websocket: websockets.WebSocketClientProtocol = None
24 | self.battleId = ""
25 | self.superHit = False
26 | self.strike = {
27 | "defense": False,
28 | "attack": False
29 | }
30 |
31 | self.space = " "
32 | self.stop_event = asyncio.Event()
33 |
34 | async def sendHit(self):
35 | """Continuously sends 'HIT' actions during the battle."""
36 | while not self.stop_event.is_set():
37 | if self.superHit:
38 | await asyncio.sleep(0.3)
39 | continue
40 |
41 | content = [
42 | "HIT",
43 | {
44 | "battleId": self.battleId
45 | }
46 | ]
47 | try:
48 | await self.websocket.send(f"42{json.dumps(content)}")
49 | except:
50 | return
51 | await asyncio.sleep(self.hitRate)
52 |
53 | async def listenerMsg(self):
54 | """Listens for and processes incoming messages from the game server."""
55 | while not self.stop_event.is_set():
56 | try:
57 | data = await self.websocket.recv()
58 | except Exception as err:
59 | self.stop_event.set()
60 | return
61 |
62 | if data.startswith('42'):
63 | data = json.loads(data[2:]) # Remove prefix "42"
64 |
65 | if data[0] == "HIT":
66 | print(
67 | f"{self.space}> {self.player1['name']} ({data[1]['player1']['energy']}) {Back.WHITE + Fore.BLACK}VERSUS{Style.RESET_ALL} ({data[1]['player2']['energy']}) {self.player2['name']}",
68 | end="\r", flush=True)
69 |
70 | elif data[0] == "SET_SUPER_HIT_PREPARE":
71 | self.superHit = True
72 |
73 | elif data[0] == "SET_SUPER_HIT_ATTACK_ZONE":
74 | content = [
75 | "SET_SUPER_HIT_ATTACK_ZONE",
76 | {
77 | "battleId": self.battleId,
78 | "zone": randint(1, 4)
79 | }
80 | ]
81 | await self.websocket.send(f"42{json.dumps(content)}")
82 | self.strike['attack'] = True
83 |
84 | elif data[0] == "SET_SUPER_HIT_DEFEND_ZONE":
85 | content = [
86 | "SET_SUPER_HIT_DEFEND_ZONE",
87 | {
88 | "battleId": self.battleId,
89 | "zone": randint(1, 4)
90 | }
91 | ]
92 | await self.websocket.send(f"42{json.dumps(content)}")
93 | self.strike['defense'] = True
94 |
95 | elif data[0] == "END":
96 | result = data[1]['result']
97 | reward = data[1]['reward']
98 |
99 | await asyncio.sleep(0.5)
100 | print('')
101 | print(
102 | f"{self.space}> You {Fore.WHITE}{Back.GREEN if result == 'WIN' else Back.RED}{result}{Style.RESET_ALL} {Style.BRIGHT}{reward}{Style.RESET_ALL} coins !")
103 |
104 | await self.websocket.recv()
105 | self.stop_event.set()
106 | return
107 |
108 | try:
109 | if (self.strike['attack'] and not self.strike['defense']) or (
110 | self.strike['defense'] and not self.strike['attack']):
111 | await self.websocket.recv()
112 | await self.websocket.recv()
113 |
114 | if self.strike['attack'] and self.strike['defense']:
115 | await self.websocket.recv()
116 | await self.websocket.send("3")
117 | await self.websocket.recv()
118 | self.superHit = False
119 | except:
120 | pass
121 |
122 | async def handleWssFreeze(self, seconds: int):
123 | timeToReach = time() + seconds
124 |
125 | while not self.stop_event.is_set():
126 | if time() > timeToReach:
127 | print("time is reach wss is close")
128 | self.websocket.close()
129 | print(f"bot wss has froze, bot is restarting ...")
130 |
131 | await asyncio.sleep(0.001)
132 |
133 | async def connect(self):
134 | """Establishes a connection to the game server and starts the battle."""
135 | uri = "wss://api-clicker.pixelverse.xyz/socket.io/?EIO=4&transport=websocket"
136 |
137 | async with websockets.connect(uri) as websocket:
138 | self.websocket = websocket
139 |
140 | data = await websocket.recv()
141 |
142 | content = {
143 | "tg-id": self.tgId,
144 | "secret": self.secret,
145 | "initData": self.initData
146 | }
147 | await websocket.send(f"40{json.dumps(content)}")
148 |
149 | await websocket.recv()
150 | data = await websocket.recv()
151 |
152 | data = json.loads(data[2:]) # Remove prefix "42"
153 |
154 | self.battleId = data[1]['battleId']
155 | self.player1 = {
156 | "name": data[1]['player1']['username']
157 | }
158 | self.player2 = {
159 | "name": data[1]['player2']['username']
160 | }
161 |
162 | for i in range(5, 0, -1):
163 | print(
164 | f"{self.space}> The fight start in {Back.RED + Fore.WHITE}{i}{Style.RESET_ALL} seconds.",
165 | end="\r", flush=True)
166 | await asyncio.sleep(1)
167 |
168 | listenerMsgTask = asyncio.create_task(self.listenerMsg())
169 | hitTask = asyncio.create_task(self.sendHit())
170 | # handleWssFreeze = asyncio.create_task(self.handleWssFreeze(180))
171 |
172 | await asyncio.gather(listenerMsgTask, hitTask)
173 |
174 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Othneil Drew
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 |
--------------------------------------------------------------------------------
/Pixelverse.py:
--------------------------------------------------------------------------------
1 | import requests
2 | import json
3 | from time import sleep
4 | from colorama import Fore, Back, Style
5 |
6 | class UserPixel:
7 | """Represents a user in the Pixelverse game, handling user data, actions, and interactions."""
8 |
9 | def __init__(self):
10 | """Initializes the UserPixel object by loading user configuration."""
11 | with open('./config.json', 'r') as file:
12 | self.config = json.load(file)
13 |
14 | self.headers = {
15 | "user-agent": "Mozilla/5.0 (Windows NT 6.2; Win64; x64; rv:102.0) Gecko/20100101 Firefox/102.0",
16 | "secret": self.config['secret'],
17 | "tg-id": self.config['tgId'],
18 | "initData": self.config['initData']
19 | }
20 | self.space = " "
21 |
22 | def isBroken(self):
23 | url = "https://api-clicker.pixelverse.xyz/api/tasks/my"
24 | req = requests.get(url, headers=self.headers)
25 | return req.status_code == 500
26 |
27 | def claim(self):
28 | """Claims mining rewards for the user."""
29 | url = "https://api-clicker.pixelverse.xyz/api/mining/claim"
30 | req = requests.post(url, headers=self.headers)
31 | data = req.json()
32 | print(f"{self.space}> Claimed {Back.YELLOW + Fore.BLACK}{int(data['claimedAmount'])}{Style.RESET_ALL} coins !")
33 |
34 | def getUser(self):
35 | """Retrieves and returns the user's information."""
36 | url = "https://api-clicker.pixelverse.xyz/api/users"
37 | req = requests.get(url, headers=self.headers)
38 | return req.json()
39 |
40 | def upgrade(self, petId: str):
41 | """Upgrades the specified pet for the user."""
42 | url = f"https://api-clicker.pixelverse.xyz/api/pets/user-pets/{petId}/level-up"
43 | req = requests.post(url, headers=self.headers)
44 | data = req.json()
45 | return data
46 |
47 | def upgradePets(self, auto_upgrade: bool):
48 | """Manages pet upgrades based on the auto_upgrade parameter.
49 |
50 | Args:
51 | auto_upgrade (bool):
52 | If True, automatically upgrades affordable pets.
53 | If False, prints a message indicating which pets can be upgraded.
54 | """
55 | print(f"{self.space}> Checking pets to upgrade ...")
56 | data = self.getUser()
57 | currBalance = data['clicksCount']
58 |
59 | petsUrl = "https://api-clicker.pixelverse.xyz/api/pets"
60 | req = requests.get(petsUrl, headers=self.headers)
61 | pets = req.json()['data']
62 |
63 | for pet in pets:
64 | if currBalance >= pet['userPet']['levelUpPrice']:
65 | if auto_upgrade:
66 | self.upgrade(pet['userPet']['id'])
67 | print(f"{self.space}> Successfully {Style.BRIGHT}upgraded{Style.RESET_ALL} pet {Back.YELLOW + Fore.BLACK}{pet['name']}{Style.RESET_ALL}")
68 | sleep(0.5)
69 | else:
70 | print(f"{self.space}> Pet {Back.YELLOW + Fore.BLACK}{pet['name']}{Style.RESET_ALL} can be upgraded!")
71 |
72 | def getStats(self):
73 | """Retrieves the user's battle statistics."""
74 | url = "https://api-clicker.pixelverse.xyz/api/battles/my/stats"
75 | req = requests.get(url, headers=self.headers)
76 | return req.json()
77 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PixelTap Bot by S1NJED
2 |
3 | ⚠️ Pixelverse don't work on PC anymore **BUT** you can still retrieve the needed credentials in the Network tab and the bot still work (22/06/24)
4 |
5 | 
6 |
7 | ✅ Auto claim rewards
8 | ✅ Auto fight
9 | ✅ Auto upgrade pets
10 |
11 | TODO:
12 |
13 | ❌ Auto Claim Daily
14 | ❌ Auto buy pets
15 |
16 | ## Installation
17 |
18 | NOTE: for some people `pip` don't work, use `pip3` instead
19 |
20 | You will need `python` (__[Download here](https://www.python.org/downloads/)__)
21 |
22 | - Download the code and open a terminal in the good directory
23 | - Or `clone` the repo
24 | > `git clone https://github.com/S1NJED/PixelTapBot.git`
25 | - Change the directory
26 | > `cd PixelTapBot`
27 | - Install the dependencies
28 | > `pip install -r requirements.txt`
29 |
30 | ## Setup
31 |
32 | NOTE: for some people `python` does not work, use `python3` instead.
33 |
34 | In order to make the bot work you will need to retrieve some tokens.
35 |
36 | - Open telegram web and open the `Network` panel by pressing `F12`.
37 | - Open the PixelTap telegram bot
38 | - Find the request '`my`' and click on it:
39 |
40 | 
41 |
42 | - Then click on the `Headers` part and scroll down until you are in the `Request headers` part.
43 | - In this section you will need to retrieve the value of `initData`, `secret`, `tg-id`:
44 |
45 | 
46 |
47 | - Add them in the `config.json` file so it look like this and save the file:
48 |
49 | 
50 |
51 | ## Start
52 |
53 | Great, now your bot is ready to fight !
54 |
55 | To start the bot simply use this command:
56 |
57 | > `python main.py`
58 |
59 | And voila, your bot will run 24/7 unless their servers are broken, which you will need to restart manually the bot (I suppose)
60 |
61 | ## My advice
62 |
63 | - You can change the `hitRate` but you can decrease it until 0.08, if you go further, the bot will not work anymore because you will make too many requests too fast. And do not need to restart the bot if you make changes in the `config.json` file.
64 | - You can run more than 1 instances **BUT** i do not recomend it, but you can still do it.
65 |
66 | ## Educational Purposes
67 |
68 | This project is designed and intended for educational purposes only.
69 |
70 | ## License
71 |
72 | Distributed under the MIT License. See `LICENSE.txt` for more information.
73 |
74 | ## Support me
75 |
76 | If you want to support me:
77 |
78 | **`$USDT`** (ERC20 or BEP20) `0x0A9072E3C4Fae8e239Db12B3287eF88A3e9Da5A2`
79 |
--------------------------------------------------------------------------------
/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "secret": "",
3 | "tgId": "",
4 | "initData": "",
5 | "hitRate": 0.1,
6 | "auto_upgrade": true
7 | }
--------------------------------------------------------------------------------
/images/image-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/S1NJED/PixelTapBot/b514aabfa5b8a962fa96e1626e17b77d2d54d613/images/image-1.png
--------------------------------------------------------------------------------
/images/image-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/S1NJED/PixelTapBot/b514aabfa5b8a962fa96e1626e17b77d2d54d613/images/image-2.png
--------------------------------------------------------------------------------
/images/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/S1NJED/PixelTapBot/b514aabfa5b8a962fa96e1626e17b77d2d54d613/images/image.png
--------------------------------------------------------------------------------
/images/screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/S1NJED/PixelTapBot/b514aabfa5b8a962fa96e1626e17b77d2d54d613/images/screen.png
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | from Battle import Battle
2 | from Pixelverse import UserPixel
3 | import json
4 | from random import randint
5 | import asyncio
6 | from colorama import Fore, Style, init, Back
7 | import os
8 | import time
9 | import sys
10 |
11 | def clear():
12 | """Clears the terminal screen."""
13 | if os.name == 'nt':
14 | os.system('cls')
15 | else:
16 | os.system('clear')
17 |
18 | def split_chunk(var):
19 | """Splits a string or number into chunks of 3, separated by spaces.
20 |
21 | Args:
22 | var: The string or number to be split.
23 |
24 | Returns:
25 | The formatted string with chunks of 3.
26 | """
27 | if isinstance(var, int):
28 | var = str(var)
29 | n = 3
30 | var = var[::-1]
31 | return ' '.join([var[i:i + n] for i in range(0, len(var), n)])[::-1]
32 |
33 | async def main():
34 | """Main asynchronous function to run the Pixelverse bot."""
35 |
36 | init()
37 | user = UserPixel()
38 |
39 | while True:
40 | try:
41 | userInfo = user.getUser()
42 | stats = user.getStats()
43 |
44 | message = f"""
45 | {Back.MAGENTA}{Fore.WHITE}PixelBot{Style.RESET_ALL} | Made by {Back.MAGENTA + Fore.WHITE}S1NJED{Style.RESET_ALL}
46 |
47 | Support me please :)
48 | {Fore.GREEN}$USDT{Style.RESET_ALL} (ERC20 or BEP20): {Back.WHITE + Fore.BLACK}0x0A9072E3C4Fae8e239Db12B3287eF88A3e9Da5A2{Style.RESET_ALL}
49 |
50 | Logged in as {Style.BRIGHT + Fore.GREEN}{userInfo['username']}{Style.RESET_ALL}{Fore.GREEN + Style.BRIGHT}
51 |
52 | ============================================== {Style.RESET_ALL} {Back.YELLOW + Fore.BLACK}STATS{Style.RESET_ALL} {Fore.GREEN + Style.BRIGHT} ============================================== {Style.RESET_ALL}
53 |
54 | > {Back.YELLOW + Fore.BLACK}Balance{Style.RESET_ALL}: {Style.BRIGHT}{split_chunk(str(int(userInfo['clicksCount'])))}{Style.RESET_ALL}
55 |
56 | > battlesCount{Style.RESET_ALL}: {Style.BRIGHT}{split_chunk(str(stats['battlesCount']))}{Style.RESET_ALL}
57 | > {Back.GREEN}Wins{Style.RESET_ALL}: {Style.BRIGHT}{split_chunk(str(stats['wins']))}{Style.RESET_ALL}
58 | > {Back.RED}Loses{Style.RESET_ALL}: {Style.BRIGHT}{split_chunk(str(stats['loses']))}{Style.RESET_ALL}
59 | > {Back.GREEN}Money Won{Style.RESET_ALL}: {Style.BRIGHT}{split_chunk(str(stats['winsReward']))}{Style.RESET_ALL}
60 | > {Back.RED}Money Lost{Style.RESET_ALL}: {Style.BRIGHT}-{split_chunk(str(abs(stats['losesReward'])))}{Style.RESET_ALL}
61 | > {Back.GREEN}Total earned{Style.RESET_ALL}: {Style.BRIGHT}{split_chunk(str(stats['winsReward'] - stats['losesReward']))}{Style.RESET_ALL}
62 |
63 | """
64 | print(message)
65 |
66 | # Read config file
67 | with open('./config.json', 'r') as config_file:
68 | config = json.load(config_file)
69 |
70 |
71 | # Battle logic
72 | battle = Battle()
73 | await battle.connect()
74 | del battle
75 |
76 | user.claim()
77 | user.upgradePets(auto_upgrade=config['auto_upgrade']) # Pass auto_upgrade choice
78 |
79 | timeToWait = randint(5, 10)
80 | print(f"{user.space}> Waiting {Back.RED + Fore.WHITE}{timeToWait}{Style.RESET_ALL} seconds.")
81 | await asyncio.sleep(timeToWait)
82 | clear()
83 |
84 | except Exception as e:
85 | print(f"{user.space}> Encountered an error: {type(e).__name__} - {e}")
86 | print(f"{user.space}> Restarting in 5 seconds...")
87 | await asyncio.sleep(5)
88 | clear()
89 |
90 | if __name__ == '__main__':
91 | while True:
92 | try:
93 | asyncio.run(main())
94 | except KeyboardInterrupt:
95 | print(f"{UserPixel().space}> Goodbye :)")
96 | sys.exit(0)
97 | except Exception as e:
98 |
99 | if UserPixel().isBroken():
100 | print(f"{UserPixel().space}> The server seems down, restarting in 5 minutes ...")
101 | time.sleep(60*5)
102 | else:
103 | print(f"{UserPixel().space}> Critical error: {type(e).__name__} - {e}")
104 | print(f"{UserPixel().space}> Restarting in 10 seconds...")
105 | time.sleep(10)
106 |
107 | clear()
108 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | certifi==2024.6.2
2 | charset-normalizer==3.3.2
3 | colorama==0.4.6
4 | idna==3.7
5 | requests==2.32.3
6 | urllib3==2.2.1
7 | websockets==12.0
8 |
--------------------------------------------------------------------------------