diff --git a/README.md b/README.md index 8995b19..63ce336 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,24 @@ -# MCPI Hacks -by Nitro +# MCPI Hacks / MCPI Enhancer +by MegaTKC ## Requirements - Minecraft-PI / Minecraft-Pi-Reborn -- Python 3.6 +- Python 2.7 ## Usage -Download this repo from git clone or from zip. If downloaded repo from zip you must extract it. Now open the repo and run python filename.py. These hacks are in real clients such as WURST and Sigma. +Download this repo from git clone or from zip. If downloaded repo from zip you must extract it. Now open the repo and run python2 app.py. These hacks are in real clients such as WURST, Sigma and Zeroday. ### Known Issues and Bugs -Hacks such as scaffold are invisible to players, so users / mobs can walk through your client-side blocks. When in the sky with scaffold players will see you walking on invisible blocks or just floating in the air. You can run this in survival mode and creative mode in MCPI. +- Hacks such as scaffold are invisible to players, so users / mobs can walk through your client-side blocks. When in the sky with scaffold players will see you walking on invisible blocks or just floating in the air. You can run this in survival mode and creative mode in MCPI. +- To stop Scaffold or ChatSpammer, you need to go into the terminal and hit CTRL + C on your keyboard to remove the previously selected module. + +## Changelog (0.2) +- Added NameTags +- Renamed to MCPI Enhancer +- Added AutoJump +- Added GUI for Ease of use + ### Join my Minecraft-Pi Server! - nitro.pocket-server.net:19132 + diff --git a/app.py b/app.py new file mode 100644 index 0000000..70f0667 --- /dev/null +++ b/app.py @@ -0,0 +1,53 @@ +# MCPI Hacks GUI Panel / Requires Python 3 + +import Tkinter +import tkMessageBox +import os +import sys + +root = Tkinter.Tk() + +root.title("MCPI Enhancer") +root.geometry('350x200') + +# Hacks / Modules Start +def chatSpammer(): + print "chat-spammer.py running" + os.system('python2 chat-spammer.py') + +B = Tkinter.Button(root, text ="ChatSpammer", command = chatSpammer) + +B.pack() + +def scaffoldWalk(): + print "scaffold.py running" + os.system('python2 scaffold.py') + +B = Tkinter.Button(root, text ="Scaffold", command = scaffoldWalk) + +B.pack() + +def nametags(): + print "nametagsGui running" + os.system('python2 mcpisettings/NameTags/gui.py') + +B = Tkinter.Button(root, text ="NameTags", command = nametags) + +B.pack() + +def autojump(): + print "autojumpGui running" + os.system('python2 mcpisettings/AutoJump/gui.py') + +B = Tkinter.Button(root, text ="AutoJump", command = autojump) + +B.pack() + +def quit(): + print "Good Bye!" + root.destroy() + +B = Tkinter.Button(root, text ="Quit", command = quit) + +B.pack() +root.mainloop() diff --git a/mcpisettings/AutoJump/autojump-disable.py b/mcpisettings/AutoJump/autojump-disable.py new file mode 100644 index 0000000..a9626fd --- /dev/null +++ b/mcpisettings/AutoJump/autojump-disable.py @@ -0,0 +1,5 @@ +import minecraft.minecraft as minecraft + +mc = minecraft.Minecraft.create() + +mc.setting("autojump", False) \ No newline at end of file diff --git a/mcpisettings/AutoJump/autojump-enable.py b/mcpisettings/AutoJump/autojump-enable.py new file mode 100644 index 0000000..e56d96e --- /dev/null +++ b/mcpisettings/AutoJump/autojump-enable.py @@ -0,0 +1,5 @@ +import minecraft.minecraft as minecraft + +mc = minecraft.Minecraft.create() + +mc.setting("autojump", True) \ No newline at end of file diff --git a/mcpisettings/AutoJump/gui.py b/mcpisettings/AutoJump/gui.py new file mode 100644 index 0000000..a13bb20 --- /dev/null +++ b/mcpisettings/AutoJump/gui.py @@ -0,0 +1,34 @@ +import Tkinter +import tkMessageBox +import os +import sys + +root = Tkinter.Tk() + +root.title("AutoJump") +root.geometry('350x200') + +def enable(): + print "Enabled" + os.system('python2 mcpisettings/AutoJump/autojump-enable.py') + +B = Tkinter.Button(root, text ="Enable", command = enable) + +B.pack() + +def disable(): + print "Disabled" + os.system('python2 mcpisettings/AutoJump/autojump-disable.py') + +B = Tkinter.Button(root, text ="Disable", command = disable) + +B.pack() + +def quit(): + print "Quit AutoJump Gui" + root.destroy() + +B = Tkinter.Button(root, text ="Quit", command = quit) + +B.pack() +root.mainloop() diff --git a/mcpisettings/AutoJump/minecraft/__init__.py b/mcpisettings/AutoJump/minecraft/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mcpisettings/AutoJump/minecraft/__init__.pyc b/mcpisettings/AutoJump/minecraft/__init__.pyc new file mode 100644 index 0000000..182a137 Binary files /dev/null and b/mcpisettings/AutoJump/minecraft/__init__.pyc differ diff --git a/mcpisettings/AutoJump/minecraft/block.py b/mcpisettings/AutoJump/minecraft/block.py new file mode 100644 index 0000000..82dea7d --- /dev/null +++ b/mcpisettings/AutoJump/minecraft/block.py @@ -0,0 +1,89 @@ +class Block: + """Minecraft PI block description. Can be sent to Minecraft.setBlock/s""" + def __init__(self, id, data=0): + self.id = id + self.data = data + + def __cmp__(self, rhs): + return hash(self) - hash(rhs) + + def __hash__(self): + return (self.id << 8) + self.data + + def withData(self, data): + return Block(self.id, data) + + def __iter__(self): + """Allows a Block to be sent whenever id [and data] is needed""" + return iter((self.id, self.data)) + +AIR = Block(0) +STONE = Block(1) +GRASS = Block(2) +DIRT = Block(3) +COBBLESTONE = Block(4) +WOOD_PLANKS = Block(5) +SAPLING = Block(6) +BEDROCK = Block(7) +WATER_FLOWING = Block(8) +WATER_STATIONARY = Block(9) +LAVA_FLOWING = Block(10) +LAVA_STATIONARY = Block(11) +SAND = Block(12) +GRAVEL = Block(13) +GOLD_ORE = Block(14) +IRON_ORE = Block(15) +COAL_ORE = Block(16) +WOOD = Block(17) +LEAVES = Block(18) +GLASS = Block(20) +LAPIS_LAZULI_ORE = Block(21) +LAPIS_LAZULI_BLOCK = Block(22) +SANDSTONE = Block(24) +BED = Block(26) +COBWEB = Block(30) +GRASS_TALL = Block(31) +WOOL = Block(35) +FLOWER_YELLOW = Block(37) +FLOWER_CYAN = Block(38) +MUSHROOM_BROWN = Block(39) +MUSHROOM_RED = Block(40) +GOLD_BLOCK = Block(41) +IRON_BLOCK = Block(42) +STONE_SLAB_DOUBLE = Block(43) +STONE_SLAB = Block(44) +BRICK_BLOCK = Block(45) +TNT = Block(46) +BOOKSHELF = Block(47) +MOSS_STONE = Block(48) +OBSIDIAN = Block(49) +TORCH = Block(50) +FIRE = Block(51) +STAIRS_WOOD = Block(53) +CHEST = Block(54) +DIAMOND_ORE = Block(56) +DIAMOND_BLOCK = Block(57) +CRAFTING_TABLE = Block(58) +FARMLAND = Block(60) +FURNACE_INACTIVE = Block(61) +FURNACE_ACTIVE = Block(62) +DOOR_WOOD = Block(64) +LADDER = Block(65) +STAIRS_COBBLESTONE = Block(67) +DOOR_IRON = Block(71) +REDSTONE_ORE = Block(73) +SNOW = Block(78) +ICE = Block(79) +SNOW_BLOCK = Block(80) +CACTUS = Block(81) +CLAY = Block(82) +SUGAR_CANE = Block(83) +FENCE = Block(85) +GLOWSTONE_BLOCK = Block(89) +BEDROCK_INVISIBLE = Block(95) +STONE_BRICK = Block(98) +GLASS_PANE = Block(102) +MELON = Block(103) +FENCE_GATE = Block(107) +GLOWING_OBSIDIAN = Block(246) +NETHER_REACTOR_CORE = Block(247) diff --git a/mcpisettings/AutoJump/minecraft/block.pyc b/mcpisettings/AutoJump/minecraft/block.pyc new file mode 100644 index 0000000..92c1f7f Binary files /dev/null and b/mcpisettings/AutoJump/minecraft/block.pyc differ diff --git a/mcpisettings/AutoJump/minecraft/connection.py b/mcpisettings/AutoJump/minecraft/connection.py new file mode 100644 index 0000000..88f417b --- /dev/null +++ b/mcpisettings/AutoJump/minecraft/connection.py @@ -0,0 +1,50 @@ +import socket +import select +import sys +from util import flatten_parameters + +""" @author: Aron Nieminen, Mojang AB""" + +class RequestError(Exception): + pass + +class Connection: + """Connection to a Minecraft Pi game""" + RequestFailed = "Fail" + + def __init__(self, address, port): + self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.socket.connect((address, port)) + self.lastSent = "" + + def drain(self): + """Drains the socket of incoming data""" + while True: + readable, _, _ = select.select([self.socket], [], [], 0.0) + if not readable: + break + data = self.socket.recv(1500) + e = "Drained Data: <%s>\n"%data.strip() + e += "Last Message: <%s>\n"%self.lastSent.strip() + sys.stderr.write(e) + + def send(self, f, *data): + """Sends data. Note that a trailing newline '\n' is added here""" + s = "%s(%s)\n"%(f, flatten_parameters(data)) + #print "f,data:",f,data + #print "s",s + self.drain() + self.lastSent = s + self.socket.sendall(s) + + def receive(self): + """Receives data. Note that the trailing newline '\n' is trimmed""" + s = self.socket.makefile("r").readline().rstrip("\n") + if s == Connection.RequestFailed: + raise RequestError("%s failed"%self.lastSent.strip()) + return s + + def sendReceive(self, *data): + """Sends and receive data""" + self.send(*data) + return self.receive() diff --git a/mcpisettings/AutoJump/minecraft/connection.pyc b/mcpisettings/AutoJump/minecraft/connection.pyc new file mode 100644 index 0000000..f5d9bf1 Binary files /dev/null and b/mcpisettings/AutoJump/minecraft/connection.pyc differ diff --git a/mcpisettings/AutoJump/minecraft/event.py b/mcpisettings/AutoJump/minecraft/event.py new file mode 100644 index 0000000..f884e0d --- /dev/null +++ b/mcpisettings/AutoJump/minecraft/event.py @@ -0,0 +1,23 @@ +from vec3 import Vec3 + +class BlockEvent: + """An Event related to blocks (e.g. placed, removed, hit)""" + HIT = 0 + + def __init__(self, type, x, y, z, face, entityId): + self.type = type + self.pos = Vec3(x, y, z) + self.face = face + self.entityId = entityId + + def __repr__(self): + sType = { + BlockEvent.HIT: "BlockEvent.HIT" + }.get(self.type, "???") + + return "BlockEvent(%s, %d, %d, %d, %d, %d)"%( + sType,self.pos.x,self.pos.y,self.pos.z,self.face,self.entityId); + + @staticmethod + def Hit(x, y, z, face, entityId): + return BlockEvent(BlockEvent.HIT, x, y, z, face, entityId) diff --git a/mcpisettings/AutoJump/minecraft/event.pyc b/mcpisettings/AutoJump/minecraft/event.pyc new file mode 100644 index 0000000..cb2c180 Binary files /dev/null and b/mcpisettings/AutoJump/minecraft/event.pyc differ diff --git a/mcpisettings/AutoJump/minecraft/minecraft.py b/mcpisettings/AutoJump/minecraft/minecraft.py new file mode 100644 index 0000000..3cc3aa0 --- /dev/null +++ b/mcpisettings/AutoJump/minecraft/minecraft.py @@ -0,0 +1,159 @@ +from connection import Connection +from vec3 import Vec3 +from event import BlockEvent + +""" Minecraft PI low level api v0.1_0 + + 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""" + + +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, 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", args)) + + def setBlock(self, *args): + """Set block (x,y,z,id,[data])""" + self.conn.send("world.setBlock", args) + + def setBlocks(self, *args): + """Set a cuboid of blocks (x0,y0,z0,x1,y1,z1,id,[data])""" + self.conn.send("world.setBlocks", args) + + def getHeight(self, *args): + """Get the height of the world (x,z) => int""" + return int(self.conn.sendReceive("world.getHeight", 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!") diff --git a/mcpisettings/AutoJump/minecraft/minecraft.pyc b/mcpisettings/AutoJump/minecraft/minecraft.pyc new file mode 100644 index 0000000..168e62f Binary files /dev/null and b/mcpisettings/AutoJump/minecraft/minecraft.pyc differ diff --git a/mcpisettings/AutoJump/minecraft/util.py b/mcpisettings/AutoJump/minecraft/util.py new file mode 100644 index 0000000..8e8d1ca --- /dev/null +++ b/mcpisettings/AutoJump/minecraft/util.py @@ -0,0 +1,10 @@ +import collections + +def flatten(l): + for e in l: + if isinstance(e, collections.Iterable) and not isinstance(e, basestring): + for ee in flatten(e): yield ee + else: yield e + +def flatten_parameters(l): + return ",".join(map(str, flatten(l))) diff --git a/mcpisettings/AutoJump/minecraft/util.pyc b/mcpisettings/AutoJump/minecraft/util.pyc new file mode 100644 index 0000000..de5c6c4 Binary files /dev/null and b/mcpisettings/AutoJump/minecraft/util.pyc differ diff --git a/mcpisettings/AutoJump/minecraft/vec3.py b/mcpisettings/AutoJump/minecraft/vec3.py new file mode 100644 index 0000000..ea701f3 --- /dev/null +++ b/mcpisettings/AutoJump/minecraft/vec3.py @@ -0,0 +1,115 @@ +class Vec3: + def __init__(self, x=0, y=0, z=0): + self.x = x + self.y = y + self.z = z + + def __add__(self, rhs): + c = self.clone() + c += rhs + return c + + def __iadd__(self, rhs): + self.x += rhs.x + self.y += rhs.y + self.z += rhs.z + return self + + def length(self): + return self.lengthSqr ** .5 + + def lengthSqr(self): + return self.x * self.x + self.y * self.y + self.z * self.z + + def __mul__(self, k): + c = self.clone() + c *= k + return c + + def __imul__(self, k): + self.x *= k + self.y *= k + self.z *= k + return self + + def clone(self): + return Vec3(self.x, self.y, self.z) + + def __neg__(self): + return Vec3(-self.x, -self.y, -self.z) + + def __sub__(self, rhs): + return self.__add__(-rhs) + + def __isub__(self, rhs): + return self.__iadd__(-rhs) + + def __repr__(self): + return "Vec3(%s,%s,%s)"%(self.x,self.y,self.z) + + def __iter__(self): + return iter((self.x, self.y, self.z)) + + def _map(self, func): + self.x = func(self.x) + self.y = func(self.y) + self.z = func(self.z) + + def __cmp__(self, rhs): + dx = self.x - rhs.x + if dx != 0: return dx + dy = self.y - rhs.y + if dy != 0: return dy + dz = self.z - rhs.z + if dz != 0: return dz + return 0 + + def iround(self): self._map(lambda v:int(v+0.5)) + def ifloor(self): self._map(int) + + def rotateLeft(self): self.x, self.z = self.z, -self.x + def rotateRight(self): self.x, self.z = -self.z, self.x + + @staticmethod + def y(n=1): return Vec3(0, n, 0) + @staticmethod + def up(n=1): return Vec3.y(n) + @staticmethod + def down(n=1): return Vec3.y(-n) + +def testVec3(): + # Note: It's not testing everything + + # 1.1 Test initialization + it = Vec3(1, -2, 3) + assert it.x == 1 + assert it.y == -2 + assert it.z == 3 + + assert it.x != -1 + assert it.y != +2 + assert it.z != -3 + + # 2.1 Test cloning and equality + clone = it.clone() + assert it == clone + it.x += 1 + assert it != clone + + # 3.1 Arithmetic + a = Vec3(10, -3, 4) + b = Vec3(-7, 1, 2) + c = a + b + assert c - a == b + assert c - b == a + assert a + a == a * 2 + + assert a - a == Vec3(0,0,0) + assert a + (-a) == Vec3(0,0,0) + + # Test repr + e = eval(repr(it)) + assert e == it + +if __name__ == "__main__": + testVec3() diff --git a/mcpisettings/AutoJump/minecraft/vec3.pyc b/mcpisettings/AutoJump/minecraft/vec3.pyc new file mode 100644 index 0000000..fb2ff07 Binary files /dev/null and b/mcpisettings/AutoJump/minecraft/vec3.pyc differ diff --git a/mcpisettings/NameTags/gui.py b/mcpisettings/NameTags/gui.py new file mode 100644 index 0000000..3af6087 --- /dev/null +++ b/mcpisettings/NameTags/gui.py @@ -0,0 +1,34 @@ +import Tkinter +import tkMessageBox +import os +import sys + +root = Tkinter.Tk() + +root.title("NameTags") +root.geometry('350x200') + +def enable(): + print "Enabled" + os.system('python2 mcpisettings/NameTags/nametag-enable.py') + +B = Tkinter.Button(root, text ="Enable", command = enable) + +B.pack() + +def disable(): + print "Disabled" + os.system('python2 mcpisettings/NameTags/nametag-disable.py') + +B = Tkinter.Button(root, text ="Disable", command = disable) + +B.pack() + +def quit(): + print "Quit NameTags Gui" + root.destroy() + +B = Tkinter.Button(root, text ="Quit", command = quit) + +B.pack() +root.mainloop() diff --git a/mcpisettings/NameTags/minecraft/__init__.py b/mcpisettings/NameTags/minecraft/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mcpisettings/NameTags/minecraft/__init__.pyc b/mcpisettings/NameTags/minecraft/__init__.pyc new file mode 100644 index 0000000..182a137 Binary files /dev/null and b/mcpisettings/NameTags/minecraft/__init__.pyc differ diff --git a/mcpisettings/NameTags/minecraft/block.py b/mcpisettings/NameTags/minecraft/block.py new file mode 100644 index 0000000..82dea7d --- /dev/null +++ b/mcpisettings/NameTags/minecraft/block.py @@ -0,0 +1,89 @@ +class Block: + """Minecraft PI block description. Can be sent to Minecraft.setBlock/s""" + def __init__(self, id, data=0): + self.id = id + self.data = data + + def __cmp__(self, rhs): + return hash(self) - hash(rhs) + + def __hash__(self): + return (self.id << 8) + self.data + + def withData(self, data): + return Block(self.id, data) + + def __iter__(self): + """Allows a Block to be sent whenever id [and data] is needed""" + return iter((self.id, self.data)) + +AIR = Block(0) +STONE = Block(1) +GRASS = Block(2) +DIRT = Block(3) +COBBLESTONE = Block(4) +WOOD_PLANKS = Block(5) +SAPLING = Block(6) +BEDROCK = Block(7) +WATER_FLOWING = Block(8) +WATER_STATIONARY = Block(9) +LAVA_FLOWING = Block(10) +LAVA_STATIONARY = Block(11) +SAND = Block(12) +GRAVEL = Block(13) +GOLD_ORE = Block(14) +IRON_ORE = Block(15) +COAL_ORE = Block(16) +WOOD = Block(17) +LEAVES = Block(18) +GLASS = Block(20) +LAPIS_LAZULI_ORE = Block(21) +LAPIS_LAZULI_BLOCK = Block(22) +SANDSTONE = Block(24) +BED = Block(26) +COBWEB = Block(30) +GRASS_TALL = Block(31) +WOOL = Block(35) +FLOWER_YELLOW = Block(37) +FLOWER_CYAN = Block(38) +MUSHROOM_BROWN = Block(39) +MUSHROOM_RED = Block(40) +GOLD_BLOCK = Block(41) +IRON_BLOCK = Block(42) +STONE_SLAB_DOUBLE = Block(43) +STONE_SLAB = Block(44) +BRICK_BLOCK = Block(45) +TNT = Block(46) +BOOKSHELF = Block(47) +MOSS_STONE = Block(48) +OBSIDIAN = Block(49) +TORCH = Block(50) +FIRE = Block(51) +STAIRS_WOOD = Block(53) +CHEST = Block(54) +DIAMOND_ORE = Block(56) +DIAMOND_BLOCK = Block(57) +CRAFTING_TABLE = Block(58) +FARMLAND = Block(60) +FURNACE_INACTIVE = Block(61) +FURNACE_ACTIVE = Block(62) +DOOR_WOOD = Block(64) +LADDER = Block(65) +STAIRS_COBBLESTONE = Block(67) +DOOR_IRON = Block(71) +REDSTONE_ORE = Block(73) +SNOW = Block(78) +ICE = Block(79) +SNOW_BLOCK = Block(80) +CACTUS = Block(81) +CLAY = Block(82) +SUGAR_CANE = Block(83) +FENCE = Block(85) +GLOWSTONE_BLOCK = Block(89) +BEDROCK_INVISIBLE = Block(95) +STONE_BRICK = Block(98) +GLASS_PANE = Block(102) +MELON = Block(103) +FENCE_GATE = Block(107) +GLOWING_OBSIDIAN = Block(246) +NETHER_REACTOR_CORE = Block(247) diff --git a/mcpisettings/NameTags/minecraft/block.pyc b/mcpisettings/NameTags/minecraft/block.pyc new file mode 100644 index 0000000..92c1f7f Binary files /dev/null and b/mcpisettings/NameTags/minecraft/block.pyc differ diff --git a/mcpisettings/NameTags/minecraft/connection.py b/mcpisettings/NameTags/minecraft/connection.py new file mode 100644 index 0000000..88f417b --- /dev/null +++ b/mcpisettings/NameTags/minecraft/connection.py @@ -0,0 +1,50 @@ +import socket +import select +import sys +from util import flatten_parameters + +""" @author: Aron Nieminen, Mojang AB""" + +class RequestError(Exception): + pass + +class Connection: + """Connection to a Minecraft Pi game""" + RequestFailed = "Fail" + + def __init__(self, address, port): + self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.socket.connect((address, port)) + self.lastSent = "" + + def drain(self): + """Drains the socket of incoming data""" + while True: + readable, _, _ = select.select([self.socket], [], [], 0.0) + if not readable: + break + data = self.socket.recv(1500) + e = "Drained Data: <%s>\n"%data.strip() + e += "Last Message: <%s>\n"%self.lastSent.strip() + sys.stderr.write(e) + + def send(self, f, *data): + """Sends data. Note that a trailing newline '\n' is added here""" + s = "%s(%s)\n"%(f, flatten_parameters(data)) + #print "f,data:",f,data + #print "s",s + self.drain() + self.lastSent = s + self.socket.sendall(s) + + def receive(self): + """Receives data. Note that the trailing newline '\n' is trimmed""" + s = self.socket.makefile("r").readline().rstrip("\n") + if s == Connection.RequestFailed: + raise RequestError("%s failed"%self.lastSent.strip()) + return s + + def sendReceive(self, *data): + """Sends and receive data""" + self.send(*data) + return self.receive() diff --git a/mcpisettings/NameTags/minecraft/connection.pyc b/mcpisettings/NameTags/minecraft/connection.pyc new file mode 100644 index 0000000..f5d9bf1 Binary files /dev/null and b/mcpisettings/NameTags/minecraft/connection.pyc differ diff --git a/mcpisettings/NameTags/minecraft/event.py b/mcpisettings/NameTags/minecraft/event.py new file mode 100644 index 0000000..f884e0d --- /dev/null +++ b/mcpisettings/NameTags/minecraft/event.py @@ -0,0 +1,23 @@ +from vec3 import Vec3 + +class BlockEvent: + """An Event related to blocks (e.g. placed, removed, hit)""" + HIT = 0 + + def __init__(self, type, x, y, z, face, entityId): + self.type = type + self.pos = Vec3(x, y, z) + self.face = face + self.entityId = entityId + + def __repr__(self): + sType = { + BlockEvent.HIT: "BlockEvent.HIT" + }.get(self.type, "???") + + return "BlockEvent(%s, %d, %d, %d, %d, %d)"%( + sType,self.pos.x,self.pos.y,self.pos.z,self.face,self.entityId); + + @staticmethod + def Hit(x, y, z, face, entityId): + return BlockEvent(BlockEvent.HIT, x, y, z, face, entityId) diff --git a/mcpisettings/NameTags/minecraft/event.pyc b/mcpisettings/NameTags/minecraft/event.pyc new file mode 100644 index 0000000..cb2c180 Binary files /dev/null and b/mcpisettings/NameTags/minecraft/event.pyc differ diff --git a/mcpisettings/NameTags/minecraft/minecraft.py b/mcpisettings/NameTags/minecraft/minecraft.py new file mode 100644 index 0000000..3cc3aa0 --- /dev/null +++ b/mcpisettings/NameTags/minecraft/minecraft.py @@ -0,0 +1,159 @@ +from connection import Connection +from vec3 import Vec3 +from event import BlockEvent + +""" Minecraft PI low level api v0.1_0 + + 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""" + + +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, 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", args)) + + def setBlock(self, *args): + """Set block (x,y,z,id,[data])""" + self.conn.send("world.setBlock", args) + + def setBlocks(self, *args): + """Set a cuboid of blocks (x0,y0,z0,x1,y1,z1,id,[data])""" + self.conn.send("world.setBlocks", args) + + def getHeight(self, *args): + """Get the height of the world (x,z) => int""" + return int(self.conn.sendReceive("world.getHeight", 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!") diff --git a/mcpisettings/NameTags/minecraft/minecraft.pyc b/mcpisettings/NameTags/minecraft/minecraft.pyc new file mode 100644 index 0000000..168e62f Binary files /dev/null and b/mcpisettings/NameTags/minecraft/minecraft.pyc differ diff --git a/mcpisettings/NameTags/minecraft/util.py b/mcpisettings/NameTags/minecraft/util.py new file mode 100644 index 0000000..8e8d1ca --- /dev/null +++ b/mcpisettings/NameTags/minecraft/util.py @@ -0,0 +1,10 @@ +import collections + +def flatten(l): + for e in l: + if isinstance(e, collections.Iterable) and not isinstance(e, basestring): + for ee in flatten(e): yield ee + else: yield e + +def flatten_parameters(l): + return ",".join(map(str, flatten(l))) diff --git a/mcpisettings/NameTags/minecraft/util.pyc b/mcpisettings/NameTags/minecraft/util.pyc new file mode 100644 index 0000000..de5c6c4 Binary files /dev/null and b/mcpisettings/NameTags/minecraft/util.pyc differ diff --git a/mcpisettings/NameTags/minecraft/vec3.py b/mcpisettings/NameTags/minecraft/vec3.py new file mode 100644 index 0000000..ea701f3 --- /dev/null +++ b/mcpisettings/NameTags/minecraft/vec3.py @@ -0,0 +1,115 @@ +class Vec3: + def __init__(self, x=0, y=0, z=0): + self.x = x + self.y = y + self.z = z + + def __add__(self, rhs): + c = self.clone() + c += rhs + return c + + def __iadd__(self, rhs): + self.x += rhs.x + self.y += rhs.y + self.z += rhs.z + return self + + def length(self): + return self.lengthSqr ** .5 + + def lengthSqr(self): + return self.x * self.x + self.y * self.y + self.z * self.z + + def __mul__(self, k): + c = self.clone() + c *= k + return c + + def __imul__(self, k): + self.x *= k + self.y *= k + self.z *= k + return self + + def clone(self): + return Vec3(self.x, self.y, self.z) + + def __neg__(self): + return Vec3(-self.x, -self.y, -self.z) + + def __sub__(self, rhs): + return self.__add__(-rhs) + + def __isub__(self, rhs): + return self.__iadd__(-rhs) + + def __repr__(self): + return "Vec3(%s,%s,%s)"%(self.x,self.y,self.z) + + def __iter__(self): + return iter((self.x, self.y, self.z)) + + def _map(self, func): + self.x = func(self.x) + self.y = func(self.y) + self.z = func(self.z) + + def __cmp__(self, rhs): + dx = self.x - rhs.x + if dx != 0: return dx + dy = self.y - rhs.y + if dy != 0: return dy + dz = self.z - rhs.z + if dz != 0: return dz + return 0 + + def iround(self): self._map(lambda v:int(v+0.5)) + def ifloor(self): self._map(int) + + def rotateLeft(self): self.x, self.z = self.z, -self.x + def rotateRight(self): self.x, self.z = -self.z, self.x + + @staticmethod + def y(n=1): return Vec3(0, n, 0) + @staticmethod + def up(n=1): return Vec3.y(n) + @staticmethod + def down(n=1): return Vec3.y(-n) + +def testVec3(): + # Note: It's not testing everything + + # 1.1 Test initialization + it = Vec3(1, -2, 3) + assert it.x == 1 + assert it.y == -2 + assert it.z == 3 + + assert it.x != -1 + assert it.y != +2 + assert it.z != -3 + + # 2.1 Test cloning and equality + clone = it.clone() + assert it == clone + it.x += 1 + assert it != clone + + # 3.1 Arithmetic + a = Vec3(10, -3, 4) + b = Vec3(-7, 1, 2) + c = a + b + assert c - a == b + assert c - b == a + assert a + a == a * 2 + + assert a - a == Vec3(0,0,0) + assert a + (-a) == Vec3(0,0,0) + + # Test repr + e = eval(repr(it)) + assert e == it + +if __name__ == "__main__": + testVec3() diff --git a/mcpisettings/NameTags/minecraft/vec3.pyc b/mcpisettings/NameTags/minecraft/vec3.pyc new file mode 100644 index 0000000..fb2ff07 Binary files /dev/null and b/mcpisettings/NameTags/minecraft/vec3.pyc differ diff --git a/mcpisettings/NameTags/nametag-disable.py b/mcpisettings/NameTags/nametag-disable.py new file mode 100644 index 0000000..764c23e --- /dev/null +++ b/mcpisettings/NameTags/nametag-disable.py @@ -0,0 +1,5 @@ +import minecraft.minecraft as minecraft + +mc = minecraft.Minecraft.create() + +mc.setting("nametags_visible", False) \ No newline at end of file diff --git a/mcpisettings/NameTags/nametag-enable.py b/mcpisettings/NameTags/nametag-enable.py new file mode 100644 index 0000000..6000e6c --- /dev/null +++ b/mcpisettings/NameTags/nametag-enable.py @@ -0,0 +1,5 @@ +import minecraft.minecraft as minecraft + +mc = minecraft.Minecraft.create() + +mc.setting("nametags_visible", True) \ No newline at end of file diff --git a/minecraft/__init__.py b/minecraft/__init__.py old mode 100755 new mode 100644 diff --git a/minecraft/__init__.pyc b/minecraft/__init__.pyc index a846f5a..182a137 100644 Binary files a/minecraft/__init__.pyc and b/minecraft/__init__.pyc differ diff --git a/minecraft/block.py b/minecraft/block.py old mode 100755 new mode 100644 diff --git a/minecraft/block.pyc b/minecraft/block.pyc index 6126dc0..92c1f7f 100644 Binary files a/minecraft/block.pyc and b/minecraft/block.pyc differ diff --git a/minecraft/connection.py b/minecraft/connection.py old mode 100755 new mode 100644 diff --git a/minecraft/connection.pyc b/minecraft/connection.pyc index b9dc7a9..f5d9bf1 100644 Binary files a/minecraft/connection.pyc and b/minecraft/connection.pyc differ diff --git a/minecraft/event.py b/minecraft/event.py old mode 100755 new mode 100644 diff --git a/minecraft/event.pyc b/minecraft/event.pyc index 9595179..cb2c180 100644 Binary files a/minecraft/event.pyc and b/minecraft/event.pyc differ diff --git a/minecraft/minecraft.py b/minecraft/minecraft.py old mode 100755 new mode 100644 diff --git a/minecraft/minecraft.pyc b/minecraft/minecraft.pyc index fb0d62a..168e62f 100644 Binary files a/minecraft/minecraft.pyc and b/minecraft/minecraft.pyc differ diff --git a/minecraft/util.py b/minecraft/util.py old mode 100755 new mode 100644 diff --git a/minecraft/util.pyc b/minecraft/util.pyc index 404801b..de5c6c4 100644 Binary files a/minecraft/util.pyc and b/minecraft/util.pyc differ diff --git a/minecraft/vec3.py b/minecraft/vec3.py old mode 100755 new mode 100644 diff --git a/minecraft/vec3.pyc b/minecraft/vec3.pyc index c7ccc5d..fb2ff07 100644 Binary files a/minecraft/vec3.pyc and b/minecraft/vec3.pyc differ