CancerCraft is a wrapper based on pyCraft that should make coding Minecraft bots with Python easier and more organised.
Note: CancerCraft has fully moved to Microsoft login and does not support Mojang accounts anymore.
You have to have at least Python 3.5 and Pip installed.
Install the Python module requirements using pip3 install -r requirements.txt
As this uses default Python curses, it is not (yet) compatible with Windows. Either remove all curses related code or use the Windows Subsystem for Linux.
The bot requires Azure app credentials which request the needed claims from the users. One does not need to do this for every account. Here's a short guide on creating an Azure app.
- Visit https://portal.azure.com/ and log in.
- Select
App registrations
underAll services
or use the search functionality. - Press
new Registration
:- Choose a name which the people will see logging in later.
- Set
Supported account types
toPersonal Microsoft accounts only
. - In
Redirect URI
selectWeb
and enterhttp://localhost:6969
. One can freely choose the port but keep in mind to set--redirect-port
if it deviates from the default. Register
.
- Select
Authentication
:- Tick
Access tokens (used for implicit flows)
. Save
.
- Tick
- Select
Certificates & secrets
:- Press
New client secret
. - Choose a name.
Add
.- Save the
Value
somewhere.
- Press
- The
Application (client) ID
can be found inOverview
.
A more detailed explanation can be found here.
As this is based on pyCraft you need to clone (or download) it. Only the minecraft
folder is required. Since pyCraft does not have all packets implemented, you have to add additional ones yourself. Helpful resources are Current Protocol Specification and MC Dev Data. It would be nice to contribute created packet implementations to pyCraft.
This wrapper requires one additional packet:
class SetExperiencePacket(Packet):
@staticmethod
def get_id(context):
return 0x51 if context.protocol_version >= 755 else \
0x48 if context.protocol_version >= 721 else \
0x49 if context.protocol_version >= 707 else \
0x48 if context.protocol_version >= 550 else \
0x47 if context.protocol_version >= 471 else \
0x43 if context.protocol_version >= 461 else \
0x44 if context.protocol_version >= 451 else \
0x43 if context.protocol_version >= 389 else \
0x42 if context.protocol_version >= 352 else \
0x41 if context.protocol_version >= 345 else \
0x40 if context.protocol_version >= 336 else \
0x3F if context.protocol_version >= 318 else \
0x3D if context.protocol_version >= 70 else \
0x1f
packet_name = 'set experience'
definition = [
{'experience_bar': Float},
{'level': VarInt},
{'total_experience': VarInt}
]
Add it to minecraft/networking/packets/clientbound/play/__init__.py
. Don't forget to extend packets
at the top of the file.
def get_packets(context):
packets = {
...,
SetExperiencePacket
}
Execute python3 main.py -h
for help or just run python3 main.py
for it to guide you through the process.
I would advise against providing your client secret directly as an argument as it will be logged in your shell's command history. Most shells however support not logging a command if you add a leading space.
Press q
to quit and use the arrow keys (up and down) or the scroll wheel to scroll the output pad up and down.
In the case you want to run the bot on a server without a browser you can execute python3 main.py -a ""
on a machine with a browser first. This will provide you with the auth code which you then can use on your server with python3 main.py -a <AUTHCODE>
.
To create a bot, simply make a new python file and create a class called Bot
.
Keybinds can be set by creating a class / instance variable called keys
which is a dict that maps a key returned by getkey to a function.
To listen to a certain packet, add the corresponding method to your class. Currently available methods:
login_success
join_game
disconnect
player_position_and_lock
respawn
chat_message
set_experience
update_health
spawn_object
entity_position_delta
destroy_entities
sound_effect
entity_teleport
class Bot:
def __init__(self):
...
def login_success(self, packet):
...
Currently, only predefined methods that are linked to packets can be used in the Bot
definition. Feel free to open an issue or make a pull request if you need one that is missing.
The fisher requires two additional packets:
class DestroyEntitiesPacket(Packet):
@staticmethod
def get_id(context):
return 0x3A if context.protocol_version >= 756 else \
0x36 if context.protocol_version >= 741 else \
0x37 if context.protocol_version >= 721 else \
0x38 if context.protocol_version >= 550 else \
0x37 if context.protocol_version >= 471 else \
0x35 if context.protocol_version >= 461 else \
0x36 if context.protocol_version >= 451 else \
0x35 if context.protocol_version >= 389 else \
0x34 if context.protocol_version >= 352 else \
0x33 if context.protocol_version >= 345 else \
0x32 if context.protocol_version >= 336 else \
0x31 if context.protocol_version >= 332 else \
0x32 if context.protocol_version >= 318 else \
0x30 if context.protocol_version >= 70 else \
0x13
packet_name = 'destroy entities'
fields = 'count', 'entity_ids'
def read(self, file_object):
self.count = VarInt.read(file_object)
self.entity_ids = []
for i in range(self.count):
self.entity_ids.append(VarInt.read(file_object))
class EntityTeleportPacket(Packet):
@staticmethod
def get_id(context):
return 0x62 if context.protocol_version >= 757 else \
0x61 if context.protocol_version >= 755 else \
0x56 if context.protocol_version >= 721 else \
0x57 if context.protocol_version >= 550 else \
0x56 if context.protocol_version >= 471 else \
0x51 if context.protocol_version >= 461 else \
0x52 if context.protocol_version >= 451 else \
0x51 if context.protocol_version >= 441 else \
0x50 if context.protocol_version >= 389 else \
0x4F if context.protocol_version >= 352 else \
0x4E if context.protocol_version >= 345 else \
0x4D if context.protocol_version >= 343 else \
0x4C if context.protocol_version >= 336 else \
0x4B if context.protocol_version >= 318 else \
0x49 if context.protocol_version >= 110 else \
0x4A if context.protocol_version >= 94 else \
0x48 if context.protocol_version >= 70 else \
0x18
packet_name = 'entity teleport'
definition = [
{'entity_id': VarInt},
{'x': Double},
{'y': Double},
{'z': Double},
{'yaw': Angle},
{'pitch': Angle},
{'on_ground': Boolean}
]
They can be added with the same procedure as mentioned above.
To start/stop fishing press f
.
The fisher disconnects as soon as the player has less than 15 health. This is to prevent dying under normal circumstances.
The fisher also replies to messages based on replies.json
in which a key is the regex to match and the value corresponds to the reply.
This serves mainly as an example and depending on the plugins on a server could crash as errors are not handled fully.
- Huge thanks to Ammar Askar for pyCraft