-
Notifications
You must be signed in to change notification settings - Fork 1
/
minecraft.py
executable file
·176 lines (134 loc) · 6.05 KB
/
minecraft.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
from connection import Connection
from vec3 import Vec3
from event import BlockEvent
from block import Block
import math
from util import flatten
""" Minecraft PI low level api v0.1_1
Note: many methods have the parameter *arg. This solution makes it
simple to allow different types, and variable number of arguments.
The actual magic is a mix of flatten_parameters() and __iter__. Example:
A Cube class could implement __iter__ to work in Minecraft.setBlocks(c, id).
(Because of this, it's possible to "erase" arguments. CmdPlayer removes
entityId, by injecting [] that flattens to nothing)
@author: Aron Nieminen, Mojang AB"""
def intFloor(*args):
return [int(math.floor(x)) for x in flatten(args)]
class CmdPositioner:
"""Methods for setting and getting positions"""
def __init__(self, connection, packagePrefix):
self.conn = connection
self.pkg = packagePrefix
def getPos(self, id):
"""Get entity position (entityId:int) => Vec3"""
s = self.conn.sendReceive(self.pkg + ".getPos", id)
return Vec3(*map(float, s.split(",")))
def setPos(self, id, *args):
"""Set entity position (entityId:int, x,y,z)"""
self.conn.send(self.pkg + ".setPos", id, args)
def getTilePos(self, id):
"""Get entity tile position (entityId:int) => Vec3"""
s = self.conn.sendReceive(self.pkg + ".getTile", id)
return Vec3(*map(int, s.split(",")))
def setTilePos(self, id, *args):
"""Set entity tile position (entityId:int) => Vec3"""
self.conn.send(self.pkg + ".setTile", id, intFloor(*args))
def setting(self, setting, status):
"""Set a player setting (setting, status). keys: autojump"""
self.conn.send(self.pkg + ".setting", setting, 1 if bool(status) else 0)
class CmdEntity(CmdPositioner):
"""Methods for entities"""
def __init__(self, connection):
CmdPositioner.__init__(self, connection, "entity")
class CmdPlayer(CmdPositioner):
"""Methods for the host (Raspberry Pi) player"""
def __init__(self, connection):
CmdPositioner.__init__(self, connection, "player")
self.conn = connection
def getPos(self):
return CmdPositioner.getPos(self, [])
def setPos(self, *args):
return CmdPositioner.setPos(self, [], args)
def getTilePos(self):
return CmdPositioner.getTilePos(self, [])
def setTilePos(self, *args):
return CmdPositioner.setTilePos(self, [], args)
class CmdCamera:
def __init__(self, connection):
self.conn = connection
def setNormal(self, *args):
"""Set camera mode to normal Minecraft view ([entityId])"""
self.conn.send("camera.mode.setNormal", args)
def setFixed(self):
"""Set camera mode to fixed view"""
self.conn.send("camera.mode.setFixed")
def setFollow(self, *args):
"""Set camera mode to follow an entity ([entityId])"""
self.conn.send("camera.mode.setFollow", args)
def setPos(self, *args):
"""Set camera entity position (x,y,z)"""
self.conn.send("camera.setPos", args)
class CmdEvents:
"""Events"""
def __init__(self, connection):
self.conn = connection
def clearAll(self):
"""Clear all old events"""
self.conn.send("events.clear")
def pollBlockHits(self):
"""Only triggered by sword => [BlockEvent]"""
s = self.conn.sendReceive("events.block.hits")
events = [e for e in s.split("|") if e]
return [BlockEvent.Hit(*map(int, e.split(","))) for e in events]
class Minecraft:
"""The main class to interact with a running instance of Minecraft Pi."""
def __init__(self, connection):
self.conn = connection
self.camera = CmdCamera(connection)
self.entity = CmdEntity(connection)
self.player = CmdPlayer(connection)
self.events = CmdEvents(connection)
def getBlock(self, *args):
"""Get block (x,y,z) => id:int"""
return int(self.conn.sendReceive("world.getBlock", intFloor(args)))
def getBlockWithData(self, *args):
"""Get block with data (x,y,z) => Block"""
ans = self.conn.sendReceive("world.getBlockWithData", intFloor(args))
return Block(*map(int, ans.split(",")))
"""
@TODO
"""
def getBlocks(self, *args):
"""Get a cuboid of blocks (x0,y0,z0,x1,y1,z1) => [id:int]"""
return int(self.conn.sendReceive("world.getBlocks", intFloor(args)))
def setBlock(self, *args):
"""Set block (x,y,z,id,[data])"""
self.conn.send("world.setBlock", intFloor(args))
def setBlocks(self, *args):
"""Set a cuboid of blocks (x0,y0,z0,x1,y1,z1,id,[data])"""
self.conn.send("world.setBlocks", intFloor(args))
def getHeight(self, *args):
"""Get the height of the world (x,z) => int"""
return int(self.conn.sendReceive("world.getHeight", intFloor(args)))
def getPlayerEntityIds(self):
"""Get the entity ids of the connected players => [id:int]"""
ids = self.conn.sendReceive("world.getPlayerIds")
return map(int, ids.split("|"))
def saveCheckpoint(self):
"""Save a checkpoint that can be used for restoring the world"""
self.conn.send("world.checkpoint.save")
def restoreCheckpoint(self):
"""Restore the world state to the checkpoint"""
self.conn.send("world.checkpoint.restore")
def postToChat(self, msg):
"""Post a message to the game chat"""
self.conn.send("chat.post", msg)
def setting(self, setting, status):
"""Set a world setting (setting, status). keys: world_immutable, nametags_visible"""
self.conn.send("world.setting", setting, 1 if bool(status) else 0)
@staticmethod
def create(address = "localhost", port = 4711):
return Minecraft(Connection(address, port))
if __name__ == "__main__":
mc = Minecraft.create()
mc.postToChat("Hello, Minecraft!")