fix close handling for websocket

This commit is contained in:
arpruss 2015-09-28 08:41:18 -05:00
parent 205eb6e7c0
commit afd26c89b4
136 changed files with 83553 additions and 6 deletions

26
raspberryjammod/LICENSE Normal file
View File

@ -0,0 +1,26 @@
The MIT License (MIT)
RaspberryJamMod Copyright (c) 2015 Alexander R. Pruss
Lua Copyright (c) 19942015 Lua.org, PUC-Rio.
luasocket Copyright (c) Diego Nehab
tools.lua adapted from lua-websockets Copyright (c) 2012 Gerhard Lipp
base64.lua Copyright (c) 2014 Mark Rogaski and (C) 2012 Paul Moore (changed to MIME encoding)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

178
raspberryjammod/base64.lua Normal file
View File

@ -0,0 +1,178 @@
--[[--------------------------------------------------------------------------
The MIT License (MIT)
Copyright (c) 2014 Mark Rogaski
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
----------------------------------------------------------------------------
This software includes portions of base64.lua, available at:
https://gist.github.com/paulmoore/2563975
Copyright (C) 2012 by Paul Moore
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
--]]--------------------------------------------------------------------------
----------------------------------------------------------------------------
-- Package Definition
----------------------------------------------------------------------------
local Base64 = {}
----------------------------------------------------------------------------
-- Imports
----------------------------------------------------------------------------
require("bit")
local band, bor, lshift, rshift = bit.band, bit.bor, bit.lshift, bit.rshift
----------------------------------------------------------------------------
-- Constants and tables
----------------------------------------------------------------------------
local ENCODE = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '+', '/' --- ARP: changed to Mime version
}
local DECODE = {}
for i, c in ipairs(ENCODE) do
DECODE[c] = i - 1
end
----------------------------------------------------------------------------
-- Utility functions
----------------------------------------------------------------------------
--- Converts a 6-bit octet into the associated Base64 character.
--
-- @param octet A 6-bit integer.
-- @return The Base64 representation of the character
local function toChar(octet)
return assert(ENCODE[octet + 1], "No Base64 character for octet: " .. tostring(octet))
end
--- Converts a Base64 character into the associated octet.
--
-- @param char The single Base64 character.
-- @return The 6-bit integer representing the Base64 character.
local function toOctet(char)
return assert(DECODE[char], "Not a valid Base64 character: " .. tostring(char))
end
----------------------------------------------------------------------------
-- User functions
----------------------------------------------------------------------------
--- Encodes a string into a Base64 string.
-- The input can be any string of arbitrary bytes.
-- If the input is not a string, or the string is empty, an error will be thrown.
--
-- @param input The input string.
-- @return The Base64 representation of the input string.
function Base64.encode(sInput)
assert(type(sInput) == "string", "Invalid input, expected type string but got: " .. tostring(sInput) .. " as a: " .. type(sInput))
assert(#sInput > 0, "Invalid input, cannot encode an empty string.")
local b = { sInput:byte(1, #sInput) }
local tOutput = {}
for i = 1, #b, 3 do
local c = {}
c[1] = rshift(b[i], 2)
if b[i + 1] ~= nil then
c[2] = band(lshift(b[i], 4) + rshift(b[i + 1], 4), 0x3F)
if b[i + 2] ~= nil then
c[3] = band(lshift(b[i + 1], 2) + rshift(b[i + 2], 6), 0x3F)
c[4] = band(b[i + 2], 0x3F)
else
c[3] = band(lshift(b[i + 1], 2), 0x3F)
end
else
c[2] = band(lshift(b[i], 4), 0x3F)
end
for j = 1, 4 do
if c[j] ~= nil then
tOutput[#tOutput + 1] = toChar(c[j])
else
tOutput[#tOutput + 1] = '='
end
end
end
return table.concat(tOutput)
end
--- Decodes a Base64 string into an output string of arbitrary bytes.
-- If the input is not a string, or the string is empty, or the string is not well-formed Base64, an error will be thrown.
--
-- @param input The Base64 input to decode.
-- @return The decoded Base64 string, as a string of bytes.
function Base64.decode (sInput)
assert(type(sInput) == "string", "Invalid input, expected type string but got: " .. tostring(sInput) .. " as a: " .. type(sInput))
assert(#sInput > 0, "Invalid input, cannot decode an empty string.")
local tOutput = {}
for i = 1, #sInput, 4 do
local block, pad = string.gsub(string.sub(sInput, i, i + 3), '=', '')
local buffer, b = 0, 0
for j = 1, 4 - pad do
b = toOctet(string.sub(block, j, j))
b = lshift(b, (4 - j) * 6)
buffer = bor(buffer, b)
end
for j = 1, 3 - pad do
b = rshift(buffer, (3 - j) * 8) % 256
tOutput[#tOutput + 1] = string.char(b)
end
end
return table.concat(tOutput)
end
----------------------------------------------------------------------------
-- Package Registration
----------------------------------------------------------------------------
--Apollo.RegisterPackage(Base64, "Encoding:Base64-1.0", 1, {})
return Base64

View File

@ -75,6 +75,7 @@ local ws_server = nil
if ws then
tools = require("tools")
base64 = require("base64")
ws_server = socket.bind(remote_address, 14711)
ws_server:setoption('tcp-nodelay',true)
ws_server:settimeout(0)
@ -97,7 +98,7 @@ minetest.register_globalstep(function(dtime)
newclient,err = ws_server:accept()
if not err then
newclient:settimeout(0)
table.insert(socket_client_list,
table.insert(socket_client_list,
{client=newclient,handler=handle_websocket_header,ws={},read_mode="*l"})
minetest.log("action", "RJM websocket client attempting handshake")
end
@ -118,6 +119,7 @@ minetest.register_globalstep(function(dtime)
err = source:handler(line)
if err then
source.client:close()
table.remove(socket_client_list,i)
if err ~= "closed" then
minetest.log("error", "Error "..err.." in command: RJM socket client disconnected")
end
@ -590,9 +592,12 @@ function handle_websocket_frame(source,data)
data = complete_data(source,data)
if data == nil then return nil end
local x = data:byte(1)
--print(string.format("frame %02x %02x",data:byte(1),data:byte(2)))
source.ws.frame_end = (0 ~= bit.band(0x80, x))
local opcode = bit.band(0xF, x)
if opcode == 0x08 then
--print("closing")
source.client:close()
return "closed"
end
if opcode ~= 0 then
@ -629,7 +634,7 @@ function handle_websocket_header(source,line)
if line == "" then
if source.ws.isWebsocket and source.ws.key then
local new_key = tools.base64.encode(tools.sha1(source.ws.key .. '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'))
local new_key = base64.encode(tools.sha1(source.ws.key .. '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'))
source.ws = {}
local response = "HTTP/1.1 101 Switching Protocols\r\n"..
"Upgrade: websocket\r\n"..

View File

@ -0,0 +1,321 @@
##Copyright (c) 2013, sahil singh
##
##All rights reserved.
##
##Redistribution and use in source and binary forms, with or without modification,
##are permitted provided that the following conditions are met:
##
## * Redistributions of source code must retain the above copyright notice,
## this list of conditions and the following disclaimer.
## * Redistributions in binary form must reproduce the above copyright notice,
## this list of conditions and the following disclaimer in the documentation
## and/or other materials provided with the distribution.
## * Neither the name of NeuroPy nor the names of its contributors
## may be used to endorse or promote products derived from this software
## without specific prior written permission.
##
##THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
##"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
##LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
##A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
##CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
##EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
##PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
##PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
##LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
##NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
##SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import serial
import thread
class NeuroPy(object):
"""NeuroPy libraby, to get data from neurosky mindwave.
Initialising: object1=NeuroPy("COM6",57600) #windows
After initialising , if required the callbacks must be set
then using the start method the library will start fetching data from mindwave
i.e. object1.start()
similarly stop method can be called to stop fetching the data
i.e. object1.stop()
The data from the device can be obtained using either of the following methods or both of them together:
Obtaining value: variable1=object1.attention #to get value of attention
#other variables: attention,meditation,rawValue,delta,theta,lowAlpha,highAlpha,lowBeta,highBeta,lowGamma,midGamma, poorSignal and blinkStrength
Setting callback:a call back can be associated with all the above variables so that a function is called when the variable is updated. Syntax: setCallBack("variable",callback_function)
for eg. to set a callback for attention data the syntax will be setCallBack("attention",callback_function)"""
__attention=0
__meditation=0
__rawValue=0
__delta=0
__theta=0
__lowAlpha=0
__highAlpha=0
__lowBeta=0
__highBeta=0
__lowGamma=0
__midGamma=0
__poorSignal=0
__blinkStrength=0
srl=None
__port=None
__baudRate=None
__mindFlexHack=False
threadRun=True #controlls the running of thread
callBacksDictionary={} #keep a track of all callbacks
def __init__(self,port,baudRate=57600,mindFlexHack=False):
self.__port,self.__baudRate,self.__mindFlexHack=port,baudRate,mindFlexHack
def __del__(self):
self.srl.close()
def start(self):
"""starts packetparser in a separate thread"""
self.threadRun=True
self.srl=serial.Serial(self.__port,self.__baudRate)
if self.__mindFlexHack:
"""
emit the magic hex sequence for a MindFlex toy set up to run at 57600 baud
using the hack described here:
http://www.instructables.com/id/Mindflex-EEG-with-raw-data-over-Bluetooth/
"""
self.srl.write(b'\x00\xF8\x00\x00\x00\xE0')
thread.start_new_thread(self.__packetParser,(self.srl,))
def __packetParser(self,srl):
"packetParser runs continously in a separate thread to parse packets from mindwave and update the corresponding variables"
#srl.open()
while self.threadRun:
p1=srl.read(1).encode("hex") #read first 2 packets
p2=srl.read(1).encode("hex")
while p1!='aa' or p2!='aa':
p1=p2
p2=srl.read(1).encode("hex")
else:
#a valid packet is available
payload=[]
checksum=0;
payloadLength=int(srl.read(1).encode("hex"),16)
for i in range(payloadLength):
tempPacket=srl.read(1).encode("hex")
payload.append(tempPacket)
checksum+=int(tempPacket,16)
checksum=~checksum&0x000000ff
if checksum==int(srl.read(1).encode("hex"),16):
i=0
while i<payloadLength:
code=payload[i]
if(code=='02'):#poorSignal
i=i+1; self.poorSignal=int(payload[i],16)
elif(code=='04'):#attention
i=i+1; self.attention=int(payload[i],16)
elif(code=='05'):#meditation
i=i+1; self.meditation=int(payload[i],16)
elif(code=='16'):#blink strength
i=i+1; self.blinkStrength=int(payload[i],16)
elif(code=='80'):#raw value
i=i+1 #for length/it is not used since length =1 byte long and always=2
i=i+1; val0=int(payload[i],16)
i=i+1; self.rawValue=val0*256+int(payload[i],16)
if self.rawValue>32768 :
self.rawValue=self.rawValue-65536
elif(code=='83'):#ASIC_EEG_POWER
i=i+1;#for length/it is not used since length =1 byte long and always=2
#delta:
i=i+1; val0=int(payload[i],16)
i=i+1; val1=int(payload[i],16)
i=i+1; self.delta=val0*65536+val1*256+int(payload[i],16)
#theta:
i=i+1; val0=int(payload[i],16)
i=i+1; val1=int(payload[i],16)
i=i+1; self.theta=val0*65536+val1*256+int(payload[i],16)
#lowAlpha:
i=i+1; val0=int(payload[i],16)
i=i+1; val1=int(payload[i],16)
i=i+1; self.lowAlpha=val0*65536+val1*256+int(payload[i],16)
#highAlpha:
i=i+1; val0=int(payload[i],16)
i=i+1; val1=int(payload[i],16)
i=i+1; self.highAlpha=val0*65536+val1*256+int(payload[i],16)
#lowBeta:
i=i+1; val0=int(payload[i],16)
i=i+1; val1=int(payload[i],16)
i=i+1; self.lowBeta=val0*65536+val1*256+int(payload[i],16)
#highBeta:
i=i+1; val0=int(payload[i],16)
i=i+1; val1=int(payload[i],16)
i=i+1; self.highBeta=val0*65536+val1*256+int(payload[i],16)
#lowGamma:
i=i+1; val0=int(payload[i],16)
i=i+1; val1=int(payload[i],16)
i=i+1; self.lowGamma=val0*65536+val1*256+int(payload[i],16)
#midGamma:
i=i+1; val0=int(payload[i],16)
i=i+1; val1=int(payload[i],16)
i=i+1; self.midGamma=val0*65536+val1*256+int(payload[i],16)
else:
pass
i=i+1
def stop(self):
"stops packetparser's thread and releases com port i.e disconnects mindwave"
self.threadRun=False
self.srl.close()
def setCallBack(self,variable_name,callback_function):
"""Setting callback:a call back can be associated with all the above variables so that a function is called when the variable is updated. Syntax: setCallBack("variable",callback_function)
for eg. to set a callback for attention data the syntax will be setCallBack("attention",callback_function)"""
self.callBacksDictionary[variable_name]=callback_function
#setting getters and setters for all variables
#attention
@property
def attention(self):
"Get value for attention"
return self.__attention
@attention.setter
def attention(self,value):
self.__attention=value
if self.callBacksDictionary.has_key("attention"): #if callback has been set, execute the function
self.callBacksDictionary["attention"](self.__attention)
#meditation
@property
def meditation(self):
"Get value for meditation"
return self.__meditation
@meditation.setter
def meditation(self,value):
self.__meditation=value
if self.callBacksDictionary.has_key("meditation"): #if callback has been set, execute the function
self.callBacksDictionary["meditation"](self.__meditation)
#rawValue
@property
def rawValue(self):
"Get value for rawValue"
return self.__rawValue
@rawValue.setter
def rawValue(self,value):
self.__rawValue=value
if self.callBacksDictionary.has_key("rawValue"): #if callback has been set, execute the function
self.callBacksDictionary["rawValue"](self.__rawValue)
#delta
@property
def delta(self):
"Get value for delta"
return self.__delta
@delta.setter
def delta(self,value):
self.__delta=value
if self.callBacksDictionary.has_key("delta"): #if callback has been set, execute the function
self.callBacksDictionary["delta"](self.__delta)
#theta
@property
def theta(self):
"Get value for theta"
return self.__theta
@theta.setter
def theta(self,value):
self.__theta=value
if self.callBacksDictionary.has_key("theta"): #if callback has been set, execute the function
self.callBacksDictionary["theta"](self.__theta)
#lowAlpha
@property
def lowAlpha(self):
"Get value for lowAlpha"
return self.__lowAlpha
@lowAlpha.setter
def lowAlpha(self,value):
self.__lowAlpha=value
if self.callBacksDictionary.has_key("lowAlpha"): #if callback has been set, execute the function
self.callBacksDictionary["lowAlpha"](self.__lowAlpha)
#highAlpha
@property
def highAlpha(self):
"Get value for highAlpha"
return self.__highAlpha
@highAlpha.setter
def highAlpha(self,value):
self.__highAlpha=value
if self.callBacksDictionary.has_key("highAlpha"): #if callback has been set, execute the function
self.callBacksDictionary["highAlpha"](self.__highAlpha)
#lowBeta
@property
def lowBeta(self):
"Get value for lowBeta"
return self.__lowBeta
@lowBeta.setter
def lowBeta(self,value):
self.__lowBeta=value
if self.callBacksDictionary.has_key("lowBeta"): #if callback has been set, execute the function
self.callBacksDictionary["lowBeta"](self.__lowBeta)
#highBeta
@property
def highBeta(self):
"Get value for highBeta"
return self.__highBeta
@highBeta.setter
def highBeta(self,value):
self.__highBeta=value
if self.callBacksDictionary.has_key("highBeta"): #if callback has been set, execute the function
self.callBacksDictionary["highBeta"](self.__highBeta)
#lowGamma
@property
def lowGamma(self):
"Get value for lowGamma"
return self.__lowGamma
@lowGamma.setter
def lowGamma(self,value):
self.__lowGamma=value
if self.callBacksDictionary.has_key("lowGamma"): #if callback has been set, execute the function
self.callBacksDictionary["lowGamma"](self.__lowGamma)
#midGamma
@property
def midGamma(self):
"Get value for midGamma"
return self.__midGamma
@midGamma.setter
def midGamma(self,value):
self.__midGamma=value
if self.callBacksDictionary.has_key("midGamma"): #if callback has been set, execute the function
self.callBacksDictionary["midGamma"](self.__midGamma)
#poorSignal
@property
def poorSignal(self):
"Get value for poorSignal"
return self.__poorSignal
@poorSignal.setter
def poorSignal(self,value):
self.__poorSignal=value
if self.callBacksDictionary.has_key("poorSignal"): #if callback has been set, execute the function
self.callBacksDictionary["poorSignal"](self.__poorSignal)
#blinkStrength
@property
def blinkStrength(self):
"Get value for blinkStrength"
return self.__blinkStrength
@blinkStrength.setter
def blinkStrength(self,value):
self.__blinkStrength=value
if self.callBacksDictionary.has_key("blinkStrength"): #if callback has been set, execute the function
self.callBacksDictionary["blinkStrength"](self.__blinkStrength)

View File

@ -0,0 +1,94 @@
NeuroPy
=======
NeuroPy library written in python to connect, interact and get data from __neurosky's MindWave__ EEG headset.
This library is based on the minwave mindset communication protocol published by [Neurosky](http:://neurosky.com) and is tested
with Neurosky Mindwave EEG headset.
##Installation##
1. Download the source distribution (zip file) from [dist directory](https://github.com/lihas/NeuroPy/tree/master/dist)
2. unzip and navigate to the folder containing _setup.py_ and other files
3. run the following command:
`python setup.py install`
##Usage##
1. Importing the module: `from NeuroPy import NeuroPy`
2. Initialising: `object1=NeuroPy("COM6",57600)` _#windows_ <br /> `object1=NeuroPy("/dev/rfcomm0",57600)` _#linux_
Note: Add a True argument to emit the magic hex sequence for a MindFlex toy set up to run at 57600 baud
using the hack described here: http://www.instructables.com/id/Mindflex-EEG-with-raw-data-over-Bluetooth/
3. After initialising , if required the callbacks must be set
then using the start method the library will start fetching data from mindwave
i.e. `object1.start()`
similarly stop method can be called to stop fetching the data
i.e. `object1.stop()`
###The data from the device can be obtained using either of the following methods or bot of them together:###
* Obtaining value: `variable1=object1.attention` _\#to get value of attention_
>__\#other variables:__ attention,meditation,rawValue,delta,theta,lowAlpha,highAlpha,lowBeta,highBeta,lowGamma,midGamma, poorSignal and blinkStrength
* Setting callback:a call back can be associated with all the above variables so that a function is called when the variable is updated. Syntax: `setCallBack("variable",callback_function)` <br />
__for eg.__ to set a callback for attention data the syntax will be `setCallBack("attention",callback_function)`
>__\#other variables:__ attention,meditation,rawValue,delta,theta,lowAlpha,highAlpha,lowBeta,highBeta,lowGamma,midGamma, poorSignal and blinkStrength
##Sample Program##
from NeuroPy import NeuroPy
object1=NeuroPy("COM6") #If port not given 57600 is automatically assumed
#object1=NeuroPy("/dev/rfcomm0") for linux
def attention_callback(attention_value):
"this function will be called everytime NeuroPy has a new value for attention"
print "Value of attention is",attention_value
#do other stuff (fire a rocket), based on the obtained value of attention_value
#do some more stuff
return None
#set call back:
object1.setCallBack("attention",attention_callback)
#call start method
object1.start()
while True:
if(object1.meditation>70): #another way of accessing data provided by headset (1st being call backs)
object1.stop() #if meditation level reaches above 70, stop fetching data from the headset
Copyright (c) sahil singh
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/
or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,16 @@
mcpipy
======
Python scripts for controlling Minecraft Pi Edition on Raspberry Pi, as highlighted at mcpipy.com
This is a collection of python scripts that can be used to control Minecraft Pi Edition running on Raspberry Pi, or alternatively on a CraftBukkit server using the RaspberryJuice plugin.
Most (if not all) of the scripts are NOT of my own creation, but rather were created by others and collected to make it easy for others to enjoy them. The scripts are unmodified with a few exceptions:
1. A comment was added near the top of each file noting the author and original URL where it was posted.
2. The mcpi python libraries are assumed to be in the "mcpi" folder and require this as a prefix to import. As needed, scripts are updated to comply with this.
3. Minor formatting/bug fixing may be done to make the script run.
Thanks to everyone who has written with the scripts and I hope you enjoy it!
If you have questions or comments, email me at mcpipy at mcpipy.com or via twitter @mcpipy

View File

@ -0,0 +1,237 @@
# mcpipy.com retrieved from URL below, written by astrotutor
# http://www.minecraftforum.net/topic/1698103-camerasetpos-not-working-magic-trick/
import mcpi.minecraft as minecraft
import mcpi.block as block
import time as time
mc = minecraft.Minecraft.create()
# Find player position
playerPos = mc.player.getPos()
#Find block type below player
Block = mc.getBlock(playerPos.x, playerPos.y - 1, playerPos.z)
# Set camera to above player position
mc.camera.setFollow()
# Build 1st wall across in front to right
length = 0
height = 0
while length < 5:
mc.setBlock(playerPos.x + 2, playerPos.y + height, playerPos.z - 2 + length, 4)
while height < 3:
mc.setBlock(playerPos.x + 2, playerPos.y + height, playerPos.z - 2 + length, 4)
time.sleep(0.2)
height += 1
length += 1
height = 0
# Build second wall on right towards
length = 0
height = 0
while length < 4:
mc.setBlock(playerPos.x + 1 - length, playerPos.y + height, playerPos.z + 2, 4)
while height < 3:
mc.setBlock(playerPos.x + 1 - length, playerPos.y + height, playerPos.z + 2, 4)
time.sleep(0.2)
height += 1
length += 1
height = 0
# Build third wall on left towards
length = 0
height = 0
while length < 4:
mc.setBlock(playerPos.x + 1 - length, playerPos.y + height, playerPos.z - 2, 4)
while height < 3:
mc.setBlock(playerPos.x + 1 - length, playerPos.y + height, playerPos.z - 2 , 4)
time.sleep(0.2)
height += 1
length += 1
height = 0
# Build last wall behind to right
length = 0
height = 0
while length < 3:
mc.setBlock(playerPos.x - 2, playerPos.y + height, playerPos.z - 1 + length, 4)
while height < 3:
mc.setBlock(playerPos.x - 2, playerPos.y + height, playerPos.z - 1 + length, 4)
time.sleep(0.2)
height += 1
length += 1
height = 0
# Build the roof
length = 1
width = 0
while length < 4:
while width < 3:
mc.setBlock(playerPos.x + 2 - length, playerPos.y + 2, playerPos.z - 1 + width, 5)
time.sleep(0.2)
width += 1
length += 1
width = 0
# Create void below house
length = 1
width = 0
while length < 4:
while width < 3:
mc.setBlock(playerPos.x + 2 - length, playerPos.y - 2, playerPos.z - 1 + width, 0)
time.sleep(0.2)
width += 1
length += 1
width = 0
length = 1
width = 0
while length < 4:
while width < 3:
mc.setBlock(playerPos.x + 2 - length, playerPos.y - 3, playerPos.z - 1 + width, 0)
time.sleep(0.2)
width += 1
length += 1
width = 0
# Remove the floor
length = 1
width = 0
while length < 4:
while width < 3:
mc.setBlock(playerPos.x + 2 - length, playerPos.y - 1, playerPos.z - 1 + width, 0)
time.sleep(0.2)
width += 1
length += 1
width = 0
# Build the floor
length = 1
width = 0
while length < 4:
while width < 3:
mc.setBlock(playerPos.x + 2 - length, playerPos.y - 1, playerPos.z - 1 + width, Block)
time.sleep(0.2)
width += 1
length += 1
width = 0
# Remove the roof
length = 1
width = 0
while length < 4:
while width < 3:
mc.setBlock(playerPos.x + 2 - length, playerPos.y + 2, playerPos.z - 1 + width, 0)
time.sleep(0.2)
width += 1
length += 1
width = 0
# Remove 1st wall across in front to right
length = 0
height = 0
while length < 5:
mc.setBlock(playerPos.x + 2, playerPos.y + height, playerPos.z - 2 + length, 0)
while height < 3:
mc.setBlock(playerPos.x + 2, playerPos.y + height, playerPos.z - 2 + length, 0)
time.sleep(0.2)
height += 1
length += 1
height = 0
# Remove second wall on right towards
length = 0
height = 0
while length < 4:
mc.setBlock(playerPos.x + 1 - length, playerPos.y + height, playerPos.z + 2, 0)
while height < 3:
mc.setBlock(playerPos.x + 1 - length, playerPos.y + height, playerPos.z + 2, 0)
time.sleep(0.2)
height += 1
length += 1
height = 0
# Remove third wall on left towards
length = 0
height = 0
while length < 4:
mc.setBlock(playerPos.x + 1 - length, playerPos.y + height, playerPos.z - 2, 0)
while height < 3:
mc.setBlock(playerPos.x + 1 - length, playerPos.y + height, playerPos.z - 2 , 0)
time.sleep(0.2)
height += 1
length += 1
height = 0
# Remove last wall behind to right
length = 0
height = 0
while length < 3:
mc.setBlock(playerPos.x - 2, playerPos.y + height, playerPos.z - 1 + length, 0)
while height < 3:
mc.setBlock(playerPos.x - 2, playerPos.y + height, playerPos.z - 1 + length, 0)
time.sleep(0.2)
height += 1
length += 1
height = 0

View File

@ -0,0 +1,17 @@
from time import time
from mcpi.minecraft import Minecraft
mc = Minecraft.create()
t = time()
for i in range(1000):
mc.getBlock(0,0,0)
print "getBlock : {}ms".format(1000.*(time()-t)/1000.)
t = time()
for i in range(10000):
mc.setBlock(0,0,0,1)
mc.getBlock(0,0,0)
print "setBlock same : {}ms".format(1000.*(time()-t)/10000.)
t = time()
for i in range(10000):
mc.setBlock(0,0,0,i&1)
mc.getBlock(0,0,0)
print "setBlock different : {}ms".format(1000.*(time()-t)/10000.)

View File

@ -0,0 +1,73 @@
#www.stuffaboutcode.com
#Raspberry Pi, Minecraft Bombs - Turn any block into a bomb!
#import the minecraft.py module from the minecraft directory
import mcpi.minecraft as minecraft
#import minecraft block module
import mcpi.block as block
#import time, so delays can be used
import time
#import threading, so threads can be used
import threading
class ExplodingBlock(threading.Thread):
def __init__(self, pos, fuseInSecs, blastRadius):
#Setup object
threading.Thread.__init__(self)
self.pos = pos
self.fuseInSecs = fuseInSecs
self.blastRadius = blastRadius
def run(self):
#Open connect to minecraft
mc = minecraft.Minecraft.create()
#Get values
pos = self.pos
blastRadius = self.blastRadius
#Explode the block!
# get block type
blockType = mc.getBlock(pos.x, pos.y, pos.z)
# flash the block
for fuse in range(0, self.fuseInSecs):
mc.setBlock(pos.x, pos.y, pos.z, block.AIR)
time.sleep(0.5)
mc.setBlock(pos.x, pos.y, pos.z, blockType)
time.sleep(0.5)
# create sphere of air
for x in range(blastRadius*-1,blastRadius):
for y in range(blastRadius*-1, blastRadius):
for z in range(blastRadius*-1,blastRadius):
if x**2 + y**2 + z**2 < blastRadius**2:
mc.setBlock(pos.x + x, pos.y + y, pos.z + z, block.AIR)
if __name__ == "__main__":
time.sleep(5)
#Connect to minecraft by creating the minecraft object
# - minecraft needs to be running and in a game
mc = minecraft.Minecraft.create()
#Post a message to the minecraft chat window
mc.postToChat("Minecraft Bombs, Hit (Right Click) a Block, www.stuffaboutcode.com")
#loop until Ctrl C
try:
while True:
#Get the block hit events
blockHits = mc.events.pollBlockHits()
# if a block has been hit
if blockHits:
# for each block that has been hit
for blockHit in blockHits:
#Create and run the exploding block class in its own thread
# pass the position of the block, fuse time in seconds and blast radius
# threads are used so multiple exploding blocks can be created
explodingBlock = ExplodingBlock(blockHit.pos, 3, 3)
explodingBlock.daemon
explodingBlock.start()
time.sleep(0.1)
except KeyboardInterrupt:
print("stopped")

View File

@ -0,0 +1,58 @@
#
# Code under the MIT license by Alexander Pruss
#
#
# Draw Borromean rings
#
from mc import *
def ball(x0,y0,z0,r,block_type,done):
for x in range(-r,r):
for y in range(-r,r):
for z in range(-r,r):
if (x**2 + y**2 + z**2 <= r**2):
if not (x0+x,y0+y,z0+z) in done:
mc.setBlock(x0+x,y0+y,z0+z,block_type)
done.add((x0+x,y0+y,z0+z))
mc = Minecraft()
playerPos = mc.player.getPos()
scale = 30
r = sqrt(3)/3
x0 = int(playerPos.x)
y0 = int(playerPos.y + 4 + (r/2+1) * scale)
z0 = int(playerPos.z)
# parametrization by I.J.McGee
done = set()
t = 0
while t < 2*pi:
x = x0+int( scale * cos(t) )
y = y0+int( scale * ( sin(t) + r) )
z = z0+int( scale * - cos(3*t)/3 )
ball(x,y,z,4,GOLD_BLOCK,done)
t += 2*pi / 10000
done = set()
t = 0
while t < 2*pi:
x = x0+int( scale * (cos(t) + 0.5) )
y = y0+int( scale * ( sin(t) - r/2) )
z = z0+int( scale * - cos(3*t)/3 )
ball(x,y,z,4,LAPIS_LAZULI_BLOCK,done)
t += 2*pi / 10000
done = set()
t = 0
while t < 2*pi:
x = x0+int( scale * ( cos(t) - 0.5 ) )
y = y0+int( scale * ( sin(t) - r/2) )
z = z0+int( scale * - cos(3*t)/3 )
ball(x,y,z,4,DIAMOND_BLOCK,done)
t += 2*pi / 10000

View File

@ -0,0 +1,25 @@
#
# Code under the MIT license by Alexander Pruss
#
from mc import *
import time
import os
mc = Minecraft()
bridge = []
while True:
pos = mc.player.getTilePos()
pos.y = pos.y - 1
belowBlock = mc.getBlock(pos)
if belowBlock == AIR.id or belowBlock == WATER_FLOWING.id or belowBlock == WATER_STATIONARY.id:
bridge.append(pos)
mc.setBlock(pos, STAINED_GLASS_BLUE)
if len(bridge) > 10:
firstPos = bridge.pop(0)
if not firstPos in bridge:
mc.setBlock(firstPos, AIR)
time.sleep(0.05)

View File

@ -0,0 +1,24 @@
#!/usr/bin/env python
#import the minecraft.py module from the minecraft directory
import mcpi.minecraft as minecraft
#import minecraft block module
import mcpi.block as block
#import time, so delays can be used
import time
import server
if __name__ == "__main__":
mc = minecraft.Minecraft.create(server.address)
# mc.postToChat("Flattening surface")
# mc.setBlocks(-128,0,-128,128,64,128,0)
# mc.setBlocks(-128,0,-128,128,-64,128,block.SANDSTONE.id)
# mc.postToChat("Putting a diamong block at 0,0,0")
# mc.setBlock(0,0,0,block.DIAMOND_BLOCK.id)
while True:
#Find out your players position
playerPos = mc.player.getPos()
mc.postToChat("Find your position - its x=%s y=%s z=%s" % (int(playerPos.x), int(playerPos.y), int(playerPos.z)))
# mc.postToChat("Find your position - its x=%.2f y=%.2f z=%.2f" % (playerPos.x, playerPos.y, playerPos.z))
time.sleep(1)

View File

@ -0,0 +1,21 @@
#!/usr/bin/env python
#import the minecraft.py module from the minecraft directory
import mcpi.minecraft as minecraft
#import minecraft block module
import mcpi.block as block
#import time, so delays can be used
import server
def main():
mc = minecraft.Minecraft.create(server.address)
# write the rest of your code here...
mc.postToChat("Erasing a 50x50 block...")
mc.setBlocks(-50,-10,-50,50,10,50,block.AIR.id)
mc.setBlocks(-50,0,-50,50,-10,50,block.GRASS.id)
mc.postToChat("Done Erasing a 50x50 block!")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,27 @@
#!/usr/bin/env python
# as shared on mcpipy.com
import mcpi.minecraft as minecraft
import mcpi.block as block
import time
import server
# If you are running this script with the bukkit mod, then use a diamond block as the magic center block for teleporting
# comment/uncomment below as appropriate
magic_block = block.DIAMOND_BLOCK # for bukkit server
#magic_block = block.NETHER_REACTOR_CORE # for raspberry pi
if __name__ == "__main__": # The script
mc = minecraft.Minecraft.create(server.address)
loc = mc.player.getPos()
x = loc.x
y = loc.y - 1
z = loc.z
for z_z in range (int(z-1), int(z+2)):
for x_x in range(int(x-1), int(x+2)):
mc.setBlock(x_x,y,z_z, block.COBBLESTONE)
mc.setBlock(x_x,y+1,z_z, block.AIR)
mc.setBlock(x,y,z, magic_block)

View File

@ -0,0 +1,17 @@
#!/usr/bin/env python
#import the minecraft.py module from the minecraft directory
import mcpi.minecraft as minecraft
#import minecraft block module
import mcpi.block as block
#import time, so delays can be used
import server
def main():
mc = minecraft.Minecraft.create(server.address)
# write the rest of your code here...
mc.postToChat("Hello MCPIPY World!")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,127 @@
#!/usr/bin/env python
# Posted to mcpipy.com, created by brooksc and fleap3 aka mrfleap :)
# This script will:
# 1. Create a snake that will pick a random direction.
# if max_direction is set to 3, it will go backward/forward/left/right. Set to 5 and it goes up/down.
# 2. Head in that direction for a random # of blocks from min_distance and max_distance
# leave a 5 block "plus" of TNT in it's path
# 3. Pick a new direction and go in that direction
# It should not double back on itself or go the same direction...
#import the minecraft.py module from the minecraft directory
import mcpi.minecraft as minecraft
#import minecraft block module
import mcpi.block as block
#import time, so delays can be used
import time
import random
import math
import server
def new_direction(old_direction):
max_direction = 5
# max_direction = 3
directions = ["Forward", "Left", "Right", "Backward", "Up", "Down"]
direction_opposite = [3,2,1,0,5,4]
direction = old_direction
while direction == old_direction and direction != direction_opposite[direction]:
direction = random.randint(0, max_direction)
print "changing direction from %s to %s" % (directions[old_direction], directions[direction])
return direction
if __name__ == "__main__":
#Connect to minecraft by creating the minecraft object
# - minecraft needs to be running and in a game
mc = minecraft.Minecraft.create(server.address)
mc.setBlocks(-10,-10,-10,10,100,10,block.AIR)
x = 0.0
y = 0.0
z = 0.0
max_x = 50
max_y = 10
max_z = 50
min_distance = 10
max_distance = 100
direction = -1
directions = ["Forward", "Left", "Right", "Backward", "Up", "Down"]
while True:
mc.setBlock(x, y, z, block.DIAMOND_BLOCK)
time.sleep(2)
direction = new_direction(direction)
duration = random.randint(min_distance, max_distance)
print "New Roll: %s direction (%d) for %s more cycles!" % (directions[direction], direction, duration)
# time.sleep(3)
while duration > 0:
mc.setBlock(x, y, z, block.TNT)
if direction == 0 or direction == 3:
# Going forward or back Adjust Z
mc.setBlock(x, y, z-1, block.TNT)
mc.setBlock(x, y, z+1, block.TNT)
mc.setBlock(x, y-1, z, block.TNT)
mc.setBlock(x, y+1, z, block.TNT)
elif direction == 1 or direction == 2:
# Going left or right Adjust X
mc.setBlock(x-1, y, z, block.TNT)
mc.setBlock(x+1, y, z, block.TNT)
mc.setBlock(x, y-1, z, block.TNT)
mc.setBlock(x, y+1, z, block.TNT)
else:
# Going up or down, Adjust Y
mc.setBlock(x-1, y, z, block.TNT)
mc.setBlock(x+1, y, z, block.TNT)
mc.setBlock(x, y, z-1, block.TNT)
mc.setBlock(x, y, z+1, block.TNT)
time.sleep(.25)
if direction == 0:
# forward
x += 1
if math.fabs(x) > max_x:
direction = new_direction(direction)
x -= 2
elif direction == 1:
# left
z -= 1
if math.fabs(z) > max_z:
direction = new_direction(direction)
z += 2
elif direction == 2:
# right
z += 1
if math.fabs(z) > max_z:
direction = new_direction(direction)
z -= 2
elif direction == 3:
# backward
x -= 1
if math.fabs(x) > max_x:
direction = new_direction(direction)
x += 2
elif direction == 4:
# up
y += 1
if math.fabs(y) > max_y:
# if it's going further than max_y allows, turn it around
direction = new_direction(direction)
y -= 2
elif direction == 5:
# down
y -= 1
if math.fabs(y) > max_y:
# if it's going further than max_y allows, turn it around
direction = new_direction(direction)
y += 2
else:
print "Error! %s" % (direction)
duration -= 1
print "Going %s for %s more cycles" % (directions[direction],duration)

View File

@ -0,0 +1,106 @@
#!/usr/bin/env python
# mcpipy.com retrieved from URL below, written by burnaron
# http://www.minecraftforum.net/topic/1689199-my-first-script-bunkermaticpy/
import mcpi.minecraft as minecraft
import mcpi.block as block
from math import *
import server
mc = minecraft.Minecraft.create(server.address)
x1 = 0
y1 = 0
z1 = 0
# FASE 1: cleaning zone
mc.setBlocks(x1-2,y1,z1-2,x1+2,y1+20,z1+2,0)
mc.setBlocks(x1-51,y1-61,z1-51,x1+51,y1-19,z1+51,1)
# FASE 2: establishing access
mc.setBlocks(x1-1.5,y1+2,z1-1.5,x1+1.5,y1-60,z1+1.5,1)
mc.setBlocks(x1-1,y1+2,z1-1,x1-1,y1-60,z1-1,0)
# FASE 3: establishing main tunnels
mc.setBlocks(x1-1,y1-60,z1-1,x1+1,y1-56,z1+1,0)
mc.setBlocks(x1-50,y1-60,z1,x1+50,y1-58,z1,0)
mc.setBlocks(x1,y1-60,z1-50,x1,y1-58,z1+50,0)
mc.setBlocks(x1-1,y1+2,z1-1,x1-1,y1-60,z1-1,65,3)
# FASE 4: establishing main chambers
for pos in range(0,8):
mc.setBlocks(x1+10+pos,y1-60,z1-pos,x1+10+pos,y1-58+pos,z1+pos,0)
mc.setBlocks(x1-10-pos,y1-60,z1-pos,x1-10-pos,y1-58+pos,z1+pos,0)
mc.setBlocks(x1-pos,y1-60,z1+10+pos,x1+pos,y1-58+pos,z1+10+pos,0)
mc.setBlocks(x1-pos,y1-60,z1-10-pos,x1+pos,y1-58+pos,z1-10-pos,0)
mc.setBlocks(x1+18,y1-60,z1-8,x1+18+24,y1-50,z1+8,0)
mc.setBlocks(x1-18,y1-60,z1-8,x1-18-24,y1-50,z1+8,0)
mc.setBlocks(x1-8,y1-60,z1+18,x1+8,y1-50,z1+18+24,0)
mc.setBlocks(x1-8,y1-60,z1-18,x1+8,y1-50,z1-18-24,0)
for pos in range(0,8):
mc.setBlocks(x1+18+24+pos,y1-60,z1-8+pos,x1+18+24+pos,y1-50-pos,z1+8-pos,0)
mc.setBlocks(x1-18-24-pos,y1-60,z1-8+pos,x1-18-24-pos,y1-50-pos,z1+8-pos,0)
mc.setBlocks(x1-8+pos,y1-60,z1+18+24+pos,x1+8-pos,y1-50-pos,z1+18+24+pos,0)
mc.setBlocks(x1-8+pos,y1-60,z1-18-24-pos,x1+8-pos,y1-50-pos,z1-18-24-pos,0)
# FASE 5: establishing lights & doors:
# FASE 5.1: central chamber lights:
mc.setBlock(0,-57,1,50)
mc.setBlock(1,-57,0,50)
mc.setBlock(0,-57,-1,50)
mc.setBlock(-1,-57,0,50)
# FASE 5.2: main chambers lights
for pos in range(2,8):
mc.setBlock(x1+pos,y1-58,z1+10+pos,50)
mc.setBlock(x1-pos,y1-58,z1+10+pos,50)
mc.setBlock(x1+pos,y1-58,z1-10-pos,50)
mc.setBlock(x1-pos,y1-58,z1-10-pos,50)
mc.setBlock(x1+10+pos,y1-58,z1+pos,50)
mc.setBlock(x1+10+pos,y1-58,z1-pos,50)
mc.setBlock(x1-10-pos,y1-58,z1+pos,50)
mc.setBlock(x1-10-pos,y1-58,z1-pos,50)
for pos in range(0,24,2):
mc.setBlock(x1+8,y1-58,z1+18+pos,50)
mc.setBlock(x1-8,y1-58,z1+18+pos,50)
mc.setBlock(x1+8,y1-58,z1-18-pos,50)
mc.setBlock(x1-8,y1-58,z1-18-pos,50)
mc.setBlock(x1+18+pos,y1-58,z1+8,50)
mc.setBlock(x1+18+pos,y1-58,z1-8,50)
mc.setBlock(x1-18-pos,y1-58,z1+8,50)
mc.setBlock(x1-18-pos,y1-58,z1-8,50)
for pos in range(0,7):
mc.setBlock(x1+8-pos,y1-58,z1+18+24+pos,50)
mc.setBlock(x1-8+pos,y1-58,z1+18+24+pos,50)
mc.setBlock(x1+8-pos,y1-58,z1-18-24-pos,50)
mc.setBlock(x1-8+pos,y1-58,z1-18-24-pos,50)
mc.setBlock(x1+18+24+pos,y1-58,z1+8-pos,50)
mc.setBlock(x1+18+24+pos,y1-58,z1-8+pos,50)
mc.setBlock(x1-18-24-pos,y1-58,z1+8-pos,50)
mc.setBlock(x1-18-24-pos,y1-58,z1-8+pos,50)
# FASE 5.3: doors
mc.setBlock(x1,y1-60,z1+2,64,1)
mc.setBlock(x1,y1-59,z1+2,64,8)
mc.setBlock(x1,y1-58,z1+2,1)
mc.setBlock(x1,y1-60,z1+10,64,3)
mc.setBlock(x1,y1-59,z1+10,64,8)
mc.setBlock(x1,y1-58,z1+10,1)
mc.setBlock(x1,y1-60,z1-2,64,3)
mc.setBlock(x1,y1-59,z1-2,64,8)
mc.setBlock(x1,y1-58,z1-2,1)
mc.setBlock(x1,y1-60,z1-10,64,1)
mc.setBlock(x1,y1-59,z1-10,64,8)
mc.setBlock(x1,y1-58,z1-10,1)
mc.setBlock(x1+2,y1-60,z1,64,4)
mc.setBlock(x1+2,y1-59,z1,64,8)
mc.setBlock(x1+2,y1-58,z1,1)
mc.setBlock(x1+10,y1-60,z1,64,2)
mc.setBlock(x1+10,y1-59,z1,64,8)
mc.setBlock(x1+10,y1-58,z1,1)
mc.setBlock(x1-2,y1-60,z1,64,2)
mc.setBlock(x1-2,y1-59,z1,64,8)
mc.setBlock(x1-2,y1-58,z1,1)
mc.setBlock(x1-10,y1-60,z1,64,4)
mc.setBlock(x1-10,y1-59,z1,64,8)
mc.setBlock(x1-10,y1-58,z1,1)

View File

@ -0,0 +1,95 @@
#!/usr/bin/env python
# mcpipy.com retrieved from URL below, written by burnaron
# http://www.minecraftforum.net/topic/1689199-my-first-script-bunkermaticpy/
import mcpi.minecraft as minecraft
import mcpi.block as block
from math import *
import server
mc = minecraft.Minecraft.create(server.address)
x1 = -4
y1 = 3
z1 = 9
long_tun = 10
long_arc_ch = 8
long_ch = 26
long_m_ch = long_ch - 2 * long_arc_ch
deepness = 60
high_c_ch = 3
# FASE 1: cleaning zone
mc.setBlocks(x1-2,y1,z1-2,x1+2,y1+20,z1+2,0)
mc.setBlocks(x1-(long_tun+long_ch+1),y1-(deepness+1),z1-(long_tun+long_ch+1),x1+long_tun+long_ch+1,y1-(deepness-long_arc_ch-2-1),z1+long_tun+long_ch+1,1)
# FASE 2: establishing access
mc.setBlocks(x1-1.5,y1+2,z1-1.5,x1+1.5,y1-deepness,z1+1.5,1)
mc.setBlocks(x1-1,y1+2,z1-1,x1-1,y1-deepness,z1-1,0)
# FASE 3: establishing main tunnels, central chamber & and access stairs
# FASE 3.1: establishing central chamber
mc.setBlocks(x1-1,y1-deepness,z1-1,x1+1,y1-(deepness-high_c_ch),z1+1,0)
# FASE 3.2: establishing main tunnels
mc.setBlocks(x1-(long_tun+long_ch),y1-deepness,z1,x1+long_tun+long_ch,y1-(deepness-1),z1,0)
mc.setBlocks(x1,y1-deepness,z1-(long_tun+long_ch),x1,y1-(deepness-1),z1+long_tun+long_ch,0)
# FASE 3.3: establishing access stairs
mc.setBlocks(x1-1,y1+2,z1-1,x1-1,y1-deepness,z1-1,65,3)
# FASE 4: establishing main chambers
for pos in range(0,long_arc_ch):
mc.setBlocks(x1+long_tun+pos,y1-deepness,z1-pos,x1+long_tun+pos,y1-(deepness-2)+pos,z1+pos,0)
mc.setBlocks(x1-long_tun-pos,y1-deepness,z1-pos,x1-long_tun-pos,y1-(deepness-2)+pos,z1+pos,0)
mc.setBlocks(x1-pos,y1-deepness,z1+long_tun+pos,x1+pos,y1-(deepness-2)+pos,z1+long_tun+pos,0)
mc.setBlocks(x1-pos,y1-deepness,z1-long_tun-pos,x1+pos,y1-(deepness-2)+pos,z1-long_tun-pos,0)
mc.setBlocks(x1+long_tun+long_arc_ch,y1-deepness,z1-long_arc_ch,x1+long_tun+long_arc_ch+long_m_ch,y1-(deepness-2)+long_arc_ch,z1+long_arc_ch,0)
mc.setBlocks(x1-(long_tun+long_arc_ch),y1-deepness,z1-long_arc_ch,x1-(long_tun+long_arc_ch)-long_m_ch,y1-(deepness-2)+long_arc_ch,z1+long_arc_ch,0)
mc.setBlocks(x1-long_arc_ch,y1-deepness,z1+long_tun+long_arc_ch,x1+long_arc_ch,y1-(deepness-2)+long_arc_ch,z1+long_tun+long_arc_ch+long_m_ch,0)
mc.setBlocks(x1-long_arc_ch,y1-deepness,z1-(long_tun+long_arc_ch),x1+long_arc_ch,y1-(deepness-2)+long_arc_ch,z1-(long_tun+long_arc_ch)-(long_m_ch),0)
for pos in range(0,long_arc_ch):
mc.setBlocks(x1+long_tun+long_arc_ch+long_m_ch+pos,y1-deepness,z1-long_arc_ch+pos,x1+long_tun+long_arc_ch+long_m_ch+pos,y1-(deepness-2)+long_arc_ch-pos,z1+long_arc_ch-pos,0)
mc.setBlocks(x1-(long_tun+long_arc_ch)-long_m_ch-pos,y1-deepness,z1-long_arc_ch+pos,x1-(long_tun+long_arc_ch)-long_m_ch-pos,y1-(deepness-2)+long_arc_ch-pos,z1+long_arc_ch-pos,0)
mc.setBlocks(x1-long_arc_ch+pos,y1-deepness,z1+long_tun+long_arc_ch+long_m_ch+pos,x1+long_arc_ch-pos,y1-(deepness-2)+long_arc_ch-pos,z1+long_tun+long_arc_ch+long_m_ch+pos,0)
mc.setBlocks(x1-long_arc_ch+pos,y1-deepness,z1-(long_tun+long_arc_ch)-long_m_ch-pos,x1+long_arc_ch-pos,y1-(deepness-2)+long_arc_ch-pos,z1-(long_tun+long_arc_ch)-long_m_ch-pos,0)
# FASE 5: establishing lights & doors:
# FASE 5.1: central chamber lights:
mc.setBlock(x1,y1-(deepness-2),z1+1,50)
mc.setBlock(x1+1,y1-(deepness-2),z1,50)
mc.setBlock(x1,y1-(deepness-2),z1-1,50)
mc.setBlock(x1-1,y1-(deepness-2),z1,50)
# FASE 5.2: main chambers lights
for pos in range(2,long_arc_ch):
mc.setBlock(x1+pos,y1-(deepness-2),z1+long_tun+pos,50)
mc.setBlock(x1-pos,y1-(deepness-2),z1+long_tun+pos,50)
mc.setBlock(x1+pos,y1-(deepness-2),z1-long_tun-pos,50)
mc.setBlock(x1-pos,y1-(deepness-2),z1-long_tun-pos,50)
mc.setBlock(x1+long_tun+pos,y1-(deepness-2),z1+pos,50)
mc.setBlock(x1+long_tun+pos,y1-(deepness-2),z1-pos,50)
mc.setBlock(x1-long_tun-pos,y1-(deepness-2),z1+pos,50)
mc.setBlock(x1-long_tun-pos,y1-(deepness-2),z1-pos,50)
for pos in range(0,long_m_ch,2):
mc.setBlock(x1+long_arc_ch,y1-(deepness-2),z1+long_tun+long_arc_ch+pos,50)
mc.setBlock(x1-long_arc_ch,y1-(deepness-2),z1+long_tun+long_arc_ch+pos,50)
mc.setBlock(x1+long_arc_ch,y1-(deepness-2),z1-(long_tun+long_arc_ch)-pos,50)
mc.setBlock(x1-long_arc_ch,y1-(deepness-2),z1-(long_tun+long_arc_ch)-pos,50)
mc.setBlock(x1+long_tun+long_arc_ch+pos,y1-(deepness-2),z1+long_arc_ch,50)
mc.setBlock(x1+long_tun+long_arc_ch+pos,y1-(deepness-2),z1-long_arc_ch,50)
mc.setBlock(x1-(long_tun+long_arc_ch)-pos,y1-(deepness-2),z1+long_arc_ch,50)
mc.setBlock(x1-(long_tun+long_arc_ch)-pos,y1-(deepness-2),z1-long_arc_ch,50)
for pos in range(0,7):
mc.setBlock(x1+long_arc_ch-pos,y1-(deepness-2),z1+long_tun+long_arc_ch+long_m_ch+pos,50)
mc.setBlock(x1-long_arc_ch+pos,y1-(deepness-2),z1+long_tun+long_arc_ch+long_m_ch+pos,50)
mc.setBlock(x1+long_arc_ch-pos,y1-(deepness-2),z1-(long_tun+long_arc_ch)-long_m_ch-pos,50)
mc.setBlock(x1-long_arc_ch+pos,y1-(deepness-2),z1-(long_tun+long_arc_ch)-long_m_ch-pos,50)
mc.setBlock(x1+long_tun+long_arc_ch+long_m_ch+pos,y1-(deepness-2),z1+long_arc_ch-pos,50)
mc.setBlock(x1+long_tun+long_arc_ch+long_m_ch+pos,y1-(deepness-2),z1-long_arc_ch+pos,50)
mc.setBlock(x1-(long_tun+long_arc_ch)-long_m_ch-pos,y1-(deepness-2),z1+long_arc_ch-pos,50)
mc.setBlock(x1-(long_tun+long_arc_ch)-long_m_ch-pos,y1-(deepness-2),z1-long_arc_ch+pos,50)

View File

@ -0,0 +1,100 @@
from mc import *
import pygame.camera
from time import sleep
from sys import argv
COLORS = ( (35,0, 222,222,222),
(35,1, 219,125,63),
(35,2, 180,81,189),
(35,3, 107,138,201),
(35,4, 177,166,39),
(35,5, 66,174,57),
(35,6, 208,132,153),
(35,7, 64,64,64),
(35,8, 155,161,161),
(35,9, 47,111,137),
(35,10, 127,62,182),
(35,11, 46,57,142),
(35,12, 79,50,31),
(35,13, 53,71,27),
(35,14, 151,52,49),
(35,15, 26,22,22),
(159,0,210,178,161),
(159,1,162,84,38),
(159,2,150,88,109),
(159,3,113,109,138),
(159,4,186,133,35),
(159,5,104,118,53),
(159,6,162,78,79),
(159,7,58,42,36),
(159,8,135,107,98),
(159,9,87,91,91),
(159,10,118,70,86),
(159,11,74,60,91),
(159,12,77,51,36),
(159,13,76,83,42),
(159,14,143,61,47),
(159,15,37,23,16),
(155,0,232,228,220),
(152,0,164,26,9),
(41,0,250,239,80),
(173,0,19,19,19) )
def colorDist(a,b):
return (a[0]-b[0])*(a[0]-b[0])+(a[1]-b[1])*(a[1]-b[1])+(a[2]-b[2])*(a[2]-b[2])
def getBestColor(rgb):
bestColor = COLORS[0]
bestDist = 255*255*3
for c in COLORS:
d = colorDist(c[2:],rgb)
if d < bestDist:
bestDist = d
bestColor = c
return bestColor
mc = Minecraft()
pos = mc.player.getTilePos()
dither = True
width = 80
if len(argv) >= 2:
width = int(argv[1])
height = width * 3 // 4
pygame.camera.init()
camlist = pygame.camera.list_cameras()
if camlist:
cam = pygame.camera.Camera(camlist[0],(640,480))
current = [[(-1,-1) for y in range(height)] for x in range(width)]
while True:
image = pygame.transform.scale(cam.get_image(), (width,height))
if not dither:
for x in range(width):
for y in range(height):
block = getBestColor(image.get_at((x,y)))[0:2]
if current[x][y] != block:
mc.setBlock(pos.x+x,pos.y+height-1-y,pos.z,block)
current[x][y] = block
else:
pixels = [[list(image.get_at((x,y))[0:3]) for y in range(height)] for x in range(width)]
for x in range(width):
for y in range(height):
color = getBestColor(pixels[x][y])
block = color[0:2]
if current[x][y] != block:
mc.setBlock(pos.x+x,pos.y+height-1-y,pos.z,block)
current[x][y] = block
for i in range(3):
err = pixels[x][y][i] - color[2+i]
if x + 1 < width:
pixels[x+1][y][i] += err * 7 // 16
if y + 1 < height:
if 0 < x:
pixels[x-1][y+1][i] += err * 3 // 16
pixels[x][y+1][i] += err * 5 // 16
if x + 1 < width:
pixels[x+1][y+1][i] += err // 16
else:
mc.postToChat('Camera not found')

View File

@ -0,0 +1,128 @@
#
# Code under the MIT license by Alexander Pruss
#
from mc import *
import random
import sys
def getHeightBelow(x,y,z):
if isPE:
return min(mc.getHeight(x,z),y)
else:
y0 = y - 255
while y > y0:
if mc.getBlock(x,y,z) != AIR.id:
return y
y -= 1
return min(mc.getHeight(x,z),y)
def rectangularPrism(x1,y1,z1, x2,y2,z2, distribution):
for x in range(min(x1,x2),max(x1,x2)+1):
for y in range(min(y1,y2),max(y1,y2)+1):
for z in range(min(z1,z2),max(z1,z2)+1):
if isinstance(distribution, Block):
mc.setBlock(x,y,z,distribution)
else:
r = random.random()
for p,b in distribution:
r -= p
if r<0:
mc.setBlock(x,y,z,b)
break
# Note: the first set of coordinates must be smaller than the second
def wall(x1,y1,z1, x2,y2,z2, baseHeight, altHeight, distribution):
x = x1
z = z1
while True:
if (x-x1+z-z1) % 2 == 0:
height = altHeight
else:
height = baseHeight
y0 = getHeightBelow(x,y1,z)
rectangularPrism(x,y0,z,x,y1+height,z,distribution)
if x >= x2 and z >= z2:
return
if x < x2:
x = x + 1
if z < z2:
z = z + 1
# Note: the first set of coordinates must be smaller than the second
def moatSide(x1,y1,z1, x2,y2,z2, depth):
x = x1
z = z1
while True:
y0 = getHeightBelow(x,y1,z)
mc.setBlocks(x,y0-depth+1,z,x,y0,z,WATER_STATIONARY)
if x >= x2 and z >= z2:
return
if x < x2:
x = x + 1
if z < z2:
z = z + 1
def crenellatedSquare(x1,y1,z1,width,height,altHeight,distribution):
wall(x1, y1, z1, x1+width-1, y1, z1, height, altHeight,distribution)
wall(x1, y1, z1, x1, y1, z1+width-1, height, altHeight,distribution)
wall(x1+width-1, y1, z1, x1+width-1, y1, z1+width-1, height, altHeight,distribution)
wall(x1, y1, z1+width-1, x1+width-1, y1, z1+width-1, height, altHeight,distribution)
def square(x,y,z,width,height,distribution):
crenellatedSquare(x,y,z,width,height,height,distribution)
def moatSquare(x1,y1,z1,width,depth):
moatSide(x1, y1, z1, x1+width-1, y1, z1, depth)
moatSide(x1, y1, z1, x1, y1, z1+width-1, depth)
moatSide(x1+width-1, y1, z1, x1+width-1, y1, z1+width-1, depth)
moatSide(x1, y1, z1+width-1, x1+width-1, y1, z1+width-1, depth)
def crenellatedSquareWithInnerWall(x,y,z,width,baseHeight,altHeight,distribution):
crenellatedSquare(x,y,z,width,baseHeight,altHeight,distribution)
square(x+1,y,z+1,width-2,baseHeight-1,distribution)
def tower(x,y,z,width,baseHeight,altHeight,innerHeight,distribution):
crenellatedSquareWithInnerWall(x,y,z,width,baseHeight,altHeight,distribution)
rectangularPrism(x+2,y+innerHeight-1,z+2, x+width-3,y+innerHeight-1,z+width-3, distribution)
mc = Minecraft()
pos = mc.player.getTilePos()
distribution = ((.05,MOSS_STONE), (.1,Block(STONE_BRICK.id, 1)), (.2,Block(STONE_BRICK.id, 2)),
(.651,Block(STONE_BRICK.id, 0)))
wallSize = 51
groundY = 1+getHeightBelow(pos.x, pos.y, pos.z)
# outer walls
mc.postToChat("Outer walls")
crenellatedSquareWithInnerWall(pos.x,groundY,pos.z, wallSize, 9, 10, distribution)
# towers
mc.postToChat("Towers")
tower(pos.x-7,groundY,pos.z-7, 9, 12, 13, 11, distribution)
tower(pos.x+wallSize-2,groundY,pos.z+wallSize-2, 9, 12, 13, 11, distribution)
tower(pos.x-7,groundY,pos.z+wallSize-2, 9, 12, 13, 11, distribution)
tower(pos.x+wallSize-1,groundY,pos.z-7, 9, 12, 13, 11, distribution)
# keep
mc.postToChat("Keep")
keepStartX = pos.x+wallSize/4
keepStartZ = pos.z+wallSize/4
keepWidth = wallSize / 6 * 3
tower(keepStartX,groundY, keepStartZ,keepWidth, 16, 17, 15, distribution)
# moat
if len(sys.argv) <= 1 or sys.argv[1][0] != 'n':
mc.postToChat("Moat")
moatStartX = pos.x - 12
moatStartZ = pos.z - 12
moatInnerSize = wallSize+24
for i in range(6):
moatSquare(moatStartX-i,groundY-1,moatStartZ-i,moatInnerSize+2*i,2)
mc.postToChat("Castle done")

View File

@ -0,0 +1,417 @@
#
# Chess interface for Thomas Ahle's sunfish engine
# Code by Alexander Pruss under the MIT license
#
#
# To work, this needs sunfish.py:
# https://raw.githubusercontent.com/thomasahle/sunfish/master/sunfish.py
#
from collections import OrderedDict
from mc import *
from vehicle import *
from text import *
from fonts import *
import drawing
import time
import sys
LABEL_BLOCK = REDSTONE_BLOCK
try:
import _sunfish as sunfish
except:
try:
import urllib2
import os.path
content = urllib2.urlopen("https://raw.githubusercontent.com/thomasahle/sunfish/master/sunfish.py").read()
f=open(os.path.join(os.path.dirname(sys.argv[0]),"_sunfish.py"),"w")
f.write("# From: https://raw.githubusercontent.com/thomasahle/sunfish/master/sunfish.py\n")
f.write("# Covered by the GPL 2 license\n")
f.write(content)
f.close()
import _sunfish as sunfish
except:
print "Failed download: You need sunfish.py for this script."
def getCoords(row,col):
return (corner.x+8*row+4,corner.y,corner.z+8*col+4)
def toRowCol(n, black):
row = 7 - ((n - 20) / 10)
col = n % 10 - 1
if black:
col = 7 - col
row = 7 - row
return row,col
def toRowColMove(m, black):
return toRowCol(m[0],black),toRowCol(m[1],black)
def toNumeric(rowCol,black):
if black:
col = 7 - rowCol[1]
row = 7 - rowCol[0]
else:
row, col = rowCol
return 20 + 10 * (7-row) + 1 + col
def toNumericMove(rowColMove,black):
return toNumeric(rowColMove[0],black),toNumeric(rowColMove[1],black)
def toAlgebraicMove(rowColMove):
(r0,c0),(r1,c1) = rowColMove
return 'abcdefgh'[c0]+str(r0+1)+'abcdefgh'[c1]+str(r1+1)
def drawSquare(row,col):
block = OBSIDIAN if (col + row) % 2 == 0 else QUARTZ_BLOCK
mc.setBlocks(corner.x+row*8,corner.y-1,corner.z+col*8,corner.x+row*8+7,corner.y-1,corner.z+col*8+7,block)
def highlightSquare(row,col):
mc.setBlocks(corner.x+row*8,corner.y-1,corner.z+col*8,
corner.x+row*8+7,corner.y-1,corner.z+col*8,REDSTONE_BLOCK)
mc.setBlocks(corner.x+row*8,corner.y-1,corner.z+col*8,
corner.x+row*8,corner.y-1,corner.z+col*8+7,REDSTONE_BLOCK)
mc.setBlocks(corner.x+row*8+7,corner.y-1,corner.z+col*8,
corner.x+row*8+7,corner.y-1,corner.z+col*8+7,REDSTONE_BLOCK)
mc.setBlocks(corner.x+row*8,corner.y-1,corner.z+col*8+7,
corner.x+row*8+7,corner.y-1,corner.z+col*8+7,REDSTONE_BLOCK)
def drawEmptyBoard():
mc.setBlocks(corner.x,corner.y,corner.z,corner.x+63,corner.y+MAXHEIGHT,corner.z+63,0)
for row in range(8):
for col in range(8):
drawSquare(row,col)
for col in range(8):
c = getCoords(-1,col)
drawText(mc,FONTS['8x8'],Vec3(c[0]-4,corner.y-1,c[2]-4),Vec3(0,0,1),Vec3(1,0,0),"ABCDEFGH"[col],LABEL_BLOCK)
c = getCoords(8,col)
drawText(mc,FONTS['8x8'],Vec3(c[0]+4,corner.y-1,c[2]+4),Vec3(0,0,-1),Vec3(-1,0,0),"ABCDEFGH"[col],LABEL_BLOCK)
for row in range(8):
c = getCoords(row,-1)
drawText(mc,FONTS['8x8'],Vec3(c[0]-4,corner.y-1,c[2]-4),Vec3(0,0,1),Vec3(1,0,0),str(row+1),LABEL_BLOCK)
c = getCoords(row,8)
drawText(mc,FONTS['8x8'],Vec3(c[0]+4,corner.y-1,c[2]+4),Vec3(0,0,-1),Vec3(-1,0,0),str(row+1),LABEL_BLOCK)
PAWN = (
(".xx.",
"xxxx",
".xx.",
".xx.",
"xxxx"),
(".xx.",
"xxxx",
".xx.",
".xx.",
"xxxx"))
KNIGHT = (
("...xx.",
"..xxxx",
".xxxxx",
"xxxx.x",
".xxx..",
".xxxx.",
"xxxxxx"),
("...xx.",
"..xxxx",
".xxxxx",
"xxxx.x",
".xxx..",
".xxxx.",
"xxxxxx")
)
BISHOP = (
(".xx.",
"xx.x",
"x.xx",
"xxxx",
".xx.",
".xx.",
"xxxx"),
(".xx.",
"xx.x",
"x.xx",
"xxxx",
".xx.",
".xx.",
"xxxx"))
ROOK = (
("x.xx.x",
"x.xx.x",
"xxxxxx",
".xxxx.",
".xxxx.",
"xxxxxx"),
("x.xx.x",
"x.xx.x",
"xxxxxx",
".xxxx.",
".xxxx.",
"xxxxxx"))
QUEEN = (
("..xx..",
"x.xx.x",
"x.xx.x",
"xxxxxx",
"xxxxxx",
"xxxxxx",
"xxxxxx"),
("..xx..",
"x.xx.x",
"x.xx.x",
"xxxxxx",
"xxxxxx",
"xxxxxx",
"xxxxxx"))
KING = (
("..xx..",
"xxxxxx",
"..xx..",
"xxxxxx",
"xxxxxx",
".xxxx.",
"xxxxxx"),
("..xx..",
"xxxxxx",
"..xx..",
"xxxxxx",
"xxxxxx",
".xxxx.",
"xxxxxx"))
BLACK = WOOL_GRAY
WHITE = WOOL_WHITE
pieceBitmaps = {
'P':PAWN,
'N':KNIGHT,
'B':BISHOP,
'R':ROOK,
'Q':QUEEN,
'K':KING
}
MAXHEIGHT = 8
def toVehicle(bitmaps,block,piece):
dict = {}
depth = len(bitmaps)
height = len(bitmaps[0])
width = len(bitmaps[0][0])
for plane in range(depth):
x = plane-depth/2
for row in range(height):
y = row
for col in range(width):
z = col-width/2
if bitmaps[plane][height-1-row][col] == 'x':
dict[(x,y,z)] = block
v = Vehicle(mc,True)
v.setVehicle(dict)
v.name = piece
return v
def animateMovePiece(start,stop):
a = getCoords(start[0],start[1])
b = getCoords(stop[0],stop[1])
piece = pieces[start]
if not fast:
line = drawing.getLine(a[0],a[1],a[2],b[0],b[1],b[2])
for point in line[1:]:
piece.moveTo(point[0],point[1],point[2])
time.sleep(0.1)
piece.moveTo(b[0],b[1],b[2])
del pieces[start]
pieces[stop] = piece
def parse(message):
try:
if len(message) != 4:
raise ValueError
col0 = ord(message[0].lower()) - ord('a')
if col0 < 0 or col0 > 7:
raise ValueError
row0 = ord(message[1]) - ord('1')
if row0 < 0 or row0 > 7:
raise ValueError
col1 = ord(message[2].lower()) - ord('a')
if col1 < 0 or col1 > 7:
raise ValueError
row1 = ord(message[3]) - ord('1')
if row1 < 0 or row1 > 7:
raise ValueError
return (row0,col0),(row1,col1)
except:
raise ValueError
def getPiece(row,col):
try:
return pieces[(row,col)].name
except KeyError:
return None
def inputMove():
moves = []
mc.events.clearAll()
while len(moves) < 2:
try:
chats = mc.events.pollChatPosts()
move = parse(chats[0].message)
for m in moves:
drawSquare(m[0],m[1])
return move
except:
pass
hits = mc.events.pollBlockHits()
if len(hits) > 0:
c = hits[0].pos
if ( corner.x <= c.x and corner.y -1 <= c.y and corner.z <= c.z and
c.x < corner.x + 64 and c.y < corner.y + MAXHEIGHT and c.z < corner.z + 64 ):
m = (c.x - corner.x) / 8, (c.z - corner.z) /8
if len(moves) == 0 or m[0] != moves[0][0] or m[1] != moves[0][1]:
highlightSquare(m[0],m[1])
moves.append(m)
time.sleep(0.2)
mc.events.clearAll() # debounce
continue
for m in moves:
drawSquare(m[0],m[1])
moves = []
mc.postToChat('Canceled. Enter another move.')
time.sleep(0.2)
mc.events.clearAll() # debounce
time.sleep(0.2)
for m in moves:
drawSquare(m[0],m[1])
return tuple(moves)
def animateMove(rowColMove):
pos1 = rowColMove[0]
pos2 = rowColMove[1]
highlightSquare(pos1[0],pos1[1])
piece = getPiece(pos1[0],pos1[1])
if piece.upper() == 'K' and abs(pos1[1]-pos2[1]) > 1:
# castling
animateMovePiece(pos1,pos2)
if pos2[1] > pos1[1]:
animateMovePiece((pos1[0],7),(pos1[0],pos2[1]-1))
else:
animateMovePiece((pos1[0],0),(pos1[0],pos2[1]+1))
elif piece.upper() == 'P' and abs(pos2[0]==7):
# promote to queen (all that's supported by the engine)
animateMovePiece(pos1,pos2)
piece = pieces[pos2]
piece.erase()
if pos.board[move].islower():
v = toVehicle(QUEEN, BLACK, 'q')
else:
v = toVehicle(QUEEN, WHITE, 'Q')
pieces[pos2] = v
c = getCoords(pos2[0],pos2[1])
v.draw(c[0],c[1],c[2])
v.blankBehind()
return
else:
victim = None
redrawPiece = False
if piece.upper() == 'P' and pos1[1] != pos2[1] and pos2 not in pieces:
# en Passant
if pos2[1] > pos1[1]:
victim = pieces[(pos2[0],pos2[1]-1)]
else:
victim = pieces[(pos2[0],pos2[1]+1)]
elif pos2 in pieces:
victim = pieces[pos2]
redrawPiece = True
animateMovePiece(pos1,pos2)
if victim is not None:
victim.erase()
if redrawPiece:
piece = pieces[pos2]
piece.draw(piece.curLocation[0],piece.curLocation[1],piece.curLocation[2])
piece.blankBehind()
drawSquare(pos1[0],pos1[1])
drawSquare(pos2[0],pos2[1])
mc = Minecraft()
options = ''.join(sys.argv[1:])
black = 'b' in options
demo = 'd' in options
fast = 'f' in options
mc.postToChat("Please wait: setting up board.")
corner = mc.player.getTilePos()
corner.x -= 32
corner.z -= 32
drawEmptyBoard()
def myGetBlockWithData(pos):
"""
On RaspberryJuice, this is a lot faster than querying the server.
"""
for boardPos in pieces:
if pos in pieces[boardPos].curVehicle:
return pieces[boardPos].curVehicle[pos]
return AIR
# z coordinate is cols
# x coordinate is rows
pieces = {}
pos = sunfish.Position(sunfish.initial, 0, (True,True), (True,True), 0, 0)
for row in range(8):
for col in range(8):
piece = pos.board[toNumeric((row,col),False)]
if piece in pieceBitmaps:
v = toVehicle(pieceBitmaps[piece], WHITE, piece)
elif piece.capitalize() in pieceBitmaps:
v = toVehicle(pieceBitmaps[piece.capitalize()], BLACK, piece)
else:
continue
#uncomment the following line to optimize speed
v.getBlockWithData = myGetBlockWithData
pieces[(row,col)] = v
c = getCoords(row,col)
v.draw(c[0],c[1],c[2])
v.blankBehind()
playerMovesNext = not black
while True:
if playerMovesNext:
if black:
mc.postToChat("Black to move.")
else:
mc.postToChat("White to move.")
if demo:
sunfish.tp = OrderedDict()
move,score = sunfish.search(pos)
else:
moves = tuple(pos.genMoves())
move = None
while move not in moves:
if move is not None:
mc.postToChat("Illegal move.")
mc.postToChat("Right-click the start and end points with a sword.")
move = toNumericMove(inputMove(),black)
rowColMove = toRowColMove(move,black)
mc.postToChat("Player: "+ toAlgebraicMove(rowColMove))
animateMove(rowColMove)
pos = pos.move(move)
mc.postToChat("Thinking...")
if demo: sunfish.tp = OrderedDict()
move,score = sunfish.search(pos)
if score <= -sunfish.MATE_VALUE:
mc.postToChat("I resign. You won the game.")
break
rowColMove = toRowColMove(move,not black)
mc.postToChat("Computer: "+toAlgebraicMove(rowColMove))
animateMove(rowColMove)
if sunfish.MATE_VALUE <= score:
mc.postToChat("You lost the game.")
break
pos = pos.move(move)
playerMovesNext = True

View File

@ -0,0 +1,61 @@
#
# Code under the MIT license by Alexander Pruss
#
from drawing import *
import time
d = Drawing()
class Hand:
def __init__(self, center, scale, length, width, material, backMaterial):
self.center = center
self.length = length
self.width = width
self.scale = scale
self.previousValue = None
self.material = material
self.backMaterial = backMaterial
def update(self, value):
d.penwidth(self.width)
if self.previousValue != None and self.previousValue != value:
self.drawLine(self.previousValue, self.backMaterial)
self.drawLine(value, self.material)
self.previousValue = value
def drawLine(self, value, block):
angle = pi / 2 - (value % self.scale) * 2 * pi / self.scale
d.line(self.center[0],self.center[1],self.center[2],
self.center[0] + self.length * cos(angle),
self.center[1] + self.length * sin(angle),
self.center[2], block)
radius = 20
playerPos = d.mc.player.getPos();
center = (playerPos.x, playerPos.y + radius, playerPos.z - radius)
for x in range(-radius, radius+1):
for y in range(-radius, radius+1):
if x**2+y**2 <= radius**2:
d.point(center[0]+x, center[1]+y, center[2]-3, WOOL_BLACK)
d.penwidth(1)
for tick in range(0,12):
d.line(center[0]+0.85*radius*cos(tick * 2 * pi / 12),center[1]+0.85*radius*sin(tick * 2 * pi / 12), center[2]-3,
center[0]+radius*cos(tick * 2 * pi / 12),center[1]+radius*sin(tick * 2 * pi / 12), center[2]-3,
WOOL_BLUE)
hourHand = Hand(center, 12, radius * 0.5, 3, GOLD_BLOCK, AIR)
minuteHand = Hand(center, 60, radius * 0.8, 2, GOLD_BLOCK, AIR)
secondHand = Hand((center[0],center[1],center[2]+1), 60, radius * 0.8, 1, WOOL_RED, AIR)
while True:
t = time.localtime()
hourHand.update(t[3])
minuteHand.update(t[4])
secondHand.update(t[5])
time.sleep(1)

View File

@ -0,0 +1,38 @@
#
# Code under the MIT license by Alexander Pruss
#
# This script only works on Raspberry Jam
#
import mcpi.minecraft as minecraft
import time
from math import *
from mcpi.block import *
import code
import sys
def quit():
sys.exit()
def inputLine(prompt):
mc.events.clearAll()
while True:
chats = mc.events.pollChatPosts()
for c in chats:
if c.entityId == playerId:
print c.message
if c.message == 'quit':
return 'quit()'
elif c.message == ' ':
return ''
else:
return c.message
time.sleep(0.2)
mc = minecraft.Minecraft()
playerPos = mc.player.getPos()
playerId = mc.getPlayerId()
mc.postToChat("Enter python code into chat, type 'quit' to quit.")
i = code.interact(banner="Minecraft Python ready", readfunc=inputLine, local=locals())

View File

@ -0,0 +1,114 @@
# Don't execute this directory -- this is a support script for danielbates_setblockdemo.py
import sys
# Add some common locations where the main API might be. Feel free to add/change
# these to suit you.
sys.path.append("mcpi")
sys.path.append("api/python/mcpi")
sys.path.append("mcpi/api/python/mcpi")
# Attempt to import Mojang's API.
try:
import connection
import minecraft
except ImportError:
print "Unable to find Minecraft API. Please place minecraft_basic.py in the mcpi directory."
exit()
_server = None
_blockedit = None
_playeredit = None
def connect(ip="127.0.0.1", port=4711):
global _server, _blockedit, _playeredit
try:
_server = connection.Connection(ip, port)
_blockedit = minecraft.Minecraft(_server)
_playeredit = _blockedit.player
except Exception:
print "Unable to connect to Minecraft server at {0}:{1}".format(ip,port)
return
print "Connected to Minecraft server at {0}:{1}".format(ip,port)
def setblock(x,y,z,*typedata):
_blockedit.setBlock(x,y,z,typedata)
def getblock(x,y,z):
return _blockedit.getBlock(x,y,z)
def moveplayer(x,y,z):
_playeredit.setPos(x,y,z)
AIR = 0
STONE = 1
GRASS = 2
DIRT = 3
COBBLESTONE = 4
WOOD_PLANK = 5
SAPLING = 6
BEDROCK = 7
WATER_FLOWING = 8
WATER = 9
LAVA_FLOWING = 10
LAVA = 11
SAND = 12
GRAVEL = 13
GOLD_ORE = 14
IRON_ORE = 15
COAL_ORE = 16
WOOD = 17
LEAVES = 18
GLASS = 20
LAPIS_ORE = 21
LAPIS = 22
SANDSTONE = 24
BED = 26
COBWEB = 30
TALL_GRASS = 31
WOOL = 35
FLOWER_YELLOW = 37
FLOWER_RED = 38
MUSHROOM_BROWN = 39
MUSHROOM_RED = 40
GOLD = 41
IRON = 42
STONE_SLAB_DOUBLE = 43
STONE_SLAB = 44
BRICK = 45
TNT = 46
BOOKSHELF = 47
MOSSY_STONE = 48
TORCH = 50
FIRE = 51
WOOD_STAIRS = 53
CHEST = 54
DIAMOND_ORE = 56
DIAMOND = 57
CRAFTING_TABLE = 58
FARMLAND = 60
FURNACE = 61
FURNACE_ACTIVE = 62
WOOD_DOOR = 64
LADDER = 65
COBBLESTONE_STAIRS = 67
IRON_DOOR = 71
REDSTONE_ORE = 73
SNOW_COVER = 78
ICE = 79
SNOW = 80
CACTUS = 81
CLAY = 82
SUGAR_CANE = 83
FENCE = 85
GLOWSTONE = 89
INVISIBLE_BEDROCK = 95
STONE_BRICK = 98
GLASS_PANE = 102
MELON = 103
FENCE_GATE = 107
GLOWING_OBSIDIAN = 246
NETHER_REACTOR_CORE = 247
UPDATE_GAME_BLOCK = 249

View File

@ -0,0 +1,439 @@
#!/usr/bin/env python
#
from math import sin, cos, radians
import danielbates_minecraft_basic as mc
#import pygame.image # comment this out if not using images - it's slow to import. If you uncomment, uncomment the image reference below.
import random
import server
# TODO: use numpy matrices/vectors instead of my own ones.
class coordinate3d:
"""Class used to represent a point in 3D space."""
def __init__(self,x,y,z):
self.x = x
self.y = y
self.z = z
def __add__(self, other):
return coordinate3d(self.x+other.x, self.y+other.y, self.z+other.z)
class transformation:
"""Representation of homogeneous matrices used to apply transformations to
coordinates - using a 4x4 matrix allows shifts as well as scales/rotations.
Transformations can be combined by multiplying them together."""
def __init__(self, matrix):
self.matrix = matrix
def __mul__(self, other):
if isinstance(other, transformation):
return self.compose(other)
elif isinstance(other, coordinate3d):
return self.apply(other)
else:
print "Can't multiply transformation by {0}".format(type(other))
def compose(self, other):
"""Compose this transformation with another, returning a new transformation."""
newmatrix = [[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]]
for i in range(4):
for j in range(4):
for k in range(4):
newmatrix[i][k] += self.matrix[i][j]*other.matrix[j][k]
return transformation(newmatrix)
def apply(self, point):
"""Apply this transformation to a coordinate, returning a new coordinate."""
return coordinate3d(
self.matrix[0][0]*point.x + self.matrix[0][1]*point.y + self.matrix[0][2]*point.z + self.matrix[0][3],
self.matrix[1][0]*point.x + self.matrix[1][1]*point.y + self.matrix[1][2]*point.z + self.matrix[1][3],
self.matrix[2][0]*point.x + self.matrix[2][1]*point.y + self.matrix[2][2]*point.z + self.matrix[2][3])
## Shape functions
def cuboid(dx,dy,dz):
for x in range(dx):
for y in range(dy):
for z in range(dz):
yield coordinate3d(x,y,z)
def floor(dx,dz):
return cuboid(dx,1,dz)
def hollowcuboid(dx,dy,dz):
# Iterating through the six faces would be more efficient, but I'm lazy.
for x in range(dx):
for y in range(dy):
for z in range(dz):
if x==0 or x==(dx-1) or y==0 or y==(dy-1) or z==0 or z==(dz-1):
yield coordinate3d(x,y,z)
def sphere(r):
for x in range(-r,r):
for y in range(-r,r):
for z in range(-r,r):
if x**2 + y**2 + z**2 < r**2:
yield coordinate3d(x,y,z)
def pyramid(h):
for level in range(h):
for point in floor(2*(h-level),2*(h-level)):
yield point + coordinate3d(level,level,level)
def cylinder(r,h):
for x in range(-int(r),int(r)):
for z in range(-int(r),int(r)):
if x**2 + z**2 < r**2:
for y in range(h):
yield coordinate3d(x,y,z)
def cone(r,h):
for level in range(h):
for point in cylinder((float(h-level)/h)*r,1):
yield point + coordinate3d(0,level,0)
def line(x0,y0,z0,x1,y1,z1):
"""Draw a line using a 3D adaptation of Bressenham's algorithm.
http://www.cobrabytes.com/index.php?topic=1150.0"""
# Check for steep xy line
swap_xy = abs(y1-y0) > abs(x1-x0)
if swap_xy:
x0,y0 = y0,x0
x1,y1 = y1,x1
# Check for steep xz line
swap_xz = abs(z1-z0) > abs(x1-x0)
if swap_xz:
x0,z0 = z0,x0
x1,z1 = z1,x1
# Lengths in each direction
delta_x = abs(x1-x0)
delta_y = abs(y1-y0)
delta_z = abs(z1-z0)
# Drift tells us when to take a step in a direction
drift_xy = delta_x/2
drift_xz = delta_x/2
# Direction of line
step_x = 1
if x0 > x1: step_x = -1
step_y = 1
if y0 > y1: step_y = -1
step_z = 1
if z0 > z1: step_z = -1
# Starting point
y = y0
z = z0
for x in range(x0,x1,step_x):
cx,cy,cz = x,y,z
# Perform any necessary unswaps
if swap_xz: cx,cz = cz,cx
if swap_xy: cx,cy = cy,cx
# Place a block
yield coordinate3d(cx,cy,cz)
# Update progress
drift_xy -= delta_y
drift_xz -= delta_z
# Step in y direction
if drift_xy < 0:
y += step_y
drift_xy += delta_x
# Step in z direction
if drift_xz < 0:
z += step_z
drift_xz += delta_x
# Final block
yield coordinate3d(x1,y1,z1)
def text(data):
# Not implemented yet - create an image from the text, and search for coloured
# pixels.
pass
def mengersponge(depth):
"""3D cube-based fractal."""
if depth == 0:
yield coordinate3d(0,0,0)
else:
scale = 3**(depth-1) # size of each sub-cube
for x in range(3):
for y in range(3):
for z in range(3):
if not(x==1 and y==1 or x==1 and z==1 or y==1 and z==1):
for block in mengersponge(depth-1):
yield block + coordinate3d(x*scale,y*scale,z*scale)
def building(width, height, depth):
"""All dimensions are specified in the number of windows."""
for point in hollowcuboid(width*5-1, height*5+1, depth*5-1):
# Shift the building down by 1 so the floor is the right height.
yield point + coordinate3d(0,-1,0)
def revolvingdoor():
# A couple of shifts we need to get the doors to cross.
# This does work, but it was a bit too jerky to show off in the video.
xshift = shift(-2,0,0)
zshift = shift(0,0,-2)
for point in cuboid(1,3,5):
yield zshift*point
for point in cuboid(5,3,1):
yield xshift*point
def maze(width, depth):
"""Credit to autophil! http://jsfiddle.net/q7DSY/4/"""
# Ensure width and depth are odd so we get outer walls
if width%2==0: width += 1
if depth%2==0: depth += 1
maze.location = (1,1)
history = []
# Initialise 2d grid: 0 = wall; 1 = passageway.
grid = [depth*[0] for x in range(width)]
grid[maze.location[0]][maze.location[1]] = 1
history.append(maze.location)
def randomiseDirections():
directions = [(0,1),(1,0),(0,-1),(-1,0)]
random.shuffle(directions)
return directions
# Work out where to go next - don't want to leave the maze or go somewhere
# we've already been.
def nextDirection():
for direction in randomiseDirections():
x = maze.location[0] + 2*direction[0]
z = maze.location[1] + 2*direction[1]
if 0<x<width and 0<z<depth and grid[x][z]==0:
return direction
# Dig two squares or backtrack
def dig():
direction = nextDirection()
if direction:
for i in range(2):
maze.location = (maze.location[0] + direction[0], maze.location[1] + direction[1])
grid[maze.location[0]][maze.location[1]] = 1
history.append(maze.location)
return True
elif history:
maze.location = history.pop()
return maze.location
else:
return None
# Keep digging out the maze until we can't dig any more.
while dig():
pass
# Finally, start returning the blocks to draw.
for x in range(width):
for z in range(depth):
if grid[x][z] == 0:
yield coordinate3d(x,0,z)
yield coordinate3d(x,1,z)
yield coordinate3d(x,2,z)
arrow = [coordinate3d(0,0,0), coordinate3d(0,1,0), coordinate3d(0,2,0),
coordinate3d(0,3,0), coordinate3d(0,4,0), coordinate3d(-2,2,0),
coordinate3d(-1,3,0), coordinate3d(1,3,0), coordinate3d(2,2,0)]
## Fill functions
def solid(material):
"""All one material."""
def f(point):
return material
return f
def randomfill(materials):
"""Choose a random material from those listed. A material may be repeated to
increase its chance of being chosen."""
def f(point):
return random.choice(materials)
return f
def chequers(material1, material2):
"""Alternate between materials (in all directions)."""
def f(point):
if (point.x+point.y+point.z) % 2 == 0:
return material1
else:
return material2
return f
def officeblock(wallmaterial):
"""Create a repeating pattern of 2x2 windows."""
def f(point):
goodx = (point.x%5 == 1) or (point.x%5 == 2)
goody = (point.y%5 == 1) or (point.y%5 == 2)
goodz = (point.z%5 == 1) or (point.z%5 == 2)
if (goodx and goody) or (goodz and goody):
return mc.GLASS
else:
return wallmaterial
return f
def image(path, w, h):
"""Scale the image to the given size."""
img = pygame.image.load(path)
width = img.get_width()
height = img.get_height()
scale_x = width/w
scale_y = height/h
def f(point):
x = int(scale_x/2) + scale_x*point.x
y = height - int(scale_y/2) - scale_y*point.y
material = None
# Anti-aliasing means that some pixels are a mix of colours.
# Keep trying until we get one we can deal with.
while material == None:
r,g,b,a = img.get_at((x,y))
material = tomaterial(r,g,b)
x += 1
return material
return f
def tomaterial(r,g,b):
# Just a quick hack for now - could of course add more colours
# and a way of finding the nearest supported colour.
if (r,g,b) == (255,255,255): # white
return mc.AIR
elif (r,g,b) == (0,0,0): # black
return mc.OBSIDIAN
elif (r,g,b) == (188,17,66): # pink
return mc.REDSTONE_ORE
elif (r,g,b) == (117,169,40): # green
return mc.MELON
else:
return None
## Transformation functions
def identity():
return transformation([[1,0,0,0],
[0,1,0,0],
[0,0,1,0],
[0,0,0,1]])
def shift(x,y,z):
"""Move by a given offset."""
return transformation([[1,0,0,x],
[0,1,0,y],
[0,0,1,z],
[0,0,0,1]])
def rotationx(angle):
"""Rotate about the x axis by the given number of degrees."""
angle = radians(angle)
return transformation([[1, 0, 0, 0],
[0, cos(angle), sin(angle), 0],
[0, -sin(angle), cos(angle), 0],
[0, 0, 0, 1]])
def rotationy(angle):
"""Rotate about the y axis by the given number of degrees."""
angle = radians(angle)
return transformation([[ cos(angle), 0, sin(angle), 0],
[ 0, 1, 0, 0],
[-sin(angle), 0, cos(angle), 0],
[ 0, 0, 0, 1]])
def rotationz(angle):
"""Rotate about the z axis by the given number of degrees."""
angle = radians(angle)
return transformation([[ cos(angle), sin(angle), 0, 0],
[-sin(angle), cos(angle), 0, 0],
[ 0, 0, 1, 0],
[ 0, 0, 0, 1]])
## Other functions
def fillshape(shape, transform=identity(), material=None,fillfunc=None):
"""Build a shape in the Minecraft world.
shape must be iterable: it can be a list, tuple, etc., or a generator function.
transform is of type transformation - multiple transformations can be combined
by multiplying them together.
material or fillfunc specify which material(s) to build the shape out of."""
if fillfunc == None:
fillfunc = solid(material)
for point in shape:
point2 = transform * point
mc.setblock(int(point2.x), int(point2.y), int(point2.z), fillfunc(point))
def clear(shape, transform=identity()):
"""Remove any non-air blocks in the given shape."""
fillshape(shape,transform,mc.AIR)
def main():
"""Function used to build my demo world. Extra clearing may be required for
hilly worlds."""
mc.connect(server.address)
# Create a large empty space with a neat, grassy floor. Takes a long time!
clear(cuboid(100,10,120))
fillshape(floor(100,120), shift(0,-1,0), material=mc.GRASS)
# Introduce basic shapes/transformations/fill functions.
fillshape(arrow, material=mc.STONE)
fillshape(arrow, shift(6,0,0), mc.STONE)
fillshape(arrow, shift(12,0,0)*rotationx(90), mc.STONE)
fillshape(arrow, shift(18,0,0)*rotationx(45), mc.STONE)
fillshape(arrow, shift(24,0,0), fillfunc=chequers(mc.WOOD, mc.STONE))
# Introduce generator functions.
fillshape(cuboid(4,4,4), shift(30,0,0), mc.STONE)
fillshape(cuboid(3,8,2), shift(36,0,0), mc.STONE)
# Show other simple shapes.
fillshape(sphere(5), shift(45,5,0), mc.STONE)
fillshape(pyramid(5), shift(50,0,0), mc.STONE)
fillshape(cylinder(5,4), shift(65,0,0), mc.STONE)
fillshape(cone(5,5), shift(75,0,0), mc.STONE)
# Show some fill functions.
fillshape(cuboid(4,4,4), shift(80,0,5), fillfunc=chequers(mc.GOLD, mc.IRON))
fillshape(pyramid(5), shift(80,0,10), fillfunc=randomfill([mc.SAND, mc.SANDSTONE]))
fillshape(hollowcuboid(4,6,4), shift(80,0,22), mc.WOOD_PLANK)
fillshape(building(2,6,2), shift(80,0,30), fillfunc=officeblock(mc.COBBLESTONE))
# Line drawing.
fillshape(line(80,0,40,85,5,45), material=mc.WOOL)
fillshape(line(80,0,40,80,2,50), material=mc.WOOL)
fillshape(line(80,2,50,85,5,45), material=mc.WOOL)
# Fun lava sphere.
fillshape(sphere(10), shift(80,10,60), mc.GLASS)
fillshape(sphere(9), shift(80,10,60), mc.LAVA)
# Fractals - far easier to code than to build by hand.
fillshape(mengersponge(0), shift(70,0,75), mc.IRON)
fillshape(mengersponge(1), shift(66,0,75), mc.IRON)
fillshape(mengersponge(2), shift(56,0,75), mc.IRON)
fillshape(mengersponge(3), shift(28,0,75), mc.IRON)
# Maze.
fillshape(maze(25,25), shift(0,0,75), mc.STONE)
# Picture - can use the same technique to draw text.
# fillshape(cuboid(24,30,1), shift(0,0,30), fillfunc=image("pi.png",24,30))
if __name__ == "__main__":
main()

View File

@ -0,0 +1,143 @@
#!/usr/bin/env python
# Quick rough & ready maze generator for Minecraft Pi edition.
# Dave Finch 2013
# mcpipy.com retrieved from URL below, written by davef21370
# https://github.com/brooksc/mcpipy/blob/master/davef21370_maze.py
import mcpi.minecraft as minecraft
import mcpi.block as block
import sys, random
from random import randint as rand
import server
# Connect to Minecraft.
try:
mc = minecraft.Minecraft.create(server.address)
except:
print "Cannot connect to Minecraft."
sys.exit(0)
# Create a function for picking a random direction.
def randDir():
r = rand(0,3)
if r == 0: rv = (0,-1) # Up.
if r == 1: rv = (0,1) # Down.
if r == 2: rv = (-1,0) # Left.
if r == 3: rv = (1,0) # Right.
return rv
# Create a function to initialize the maze.
# w and h are the width and height respectively.
def initMaze(w,h):
global maze,spl
# Create a 2 dimensional array.
maze = [[0]*h for x in range(w)]
# Create four walls around the maze.
# 1=wall, 0=walkway.
for x in range(0,w):
maze[x][0] = maze[x][h-1] = 1
makeWall(ppos.x+x,ppos.z+0)
makeWall(ppos.x+x,ppos.z+h-1)
for y in range(0,mazeYSize):
maze[0][y] = maze[w-1][y] = 1
makeWall(ppos.x,ppos.z+y)
makeWall(ppos.x+w-1,ppos.z+y)
# Make every other cell a starting point.
# 2=starting point.
# Also create a list of these points to speed up the main loop.
spl = []
for y in range(2,h-2,2):
for x in range(2,w-2,2):
maze[x][y] = 2
spl.append((x,y))
# Shuffle the list of points and we can choose a random point by
# simply "popping" it off the list.
random.shuffle(spl)
def makeWall(x,z):
mc.setBlock(x,ppos.y,z,block.STONE)
mc.setBlock(x,ppos.y+1,z,block.STONE)
mc.setBlock(x,ppos.y+2,z,block.STONE)
# Define the X and Y size of the maze including the outer walls.
# These values aren't checked but must be positive odd integers above 3.
mazeXSize = 35
mazeYSize = 35
# Set the maximum length of a wall.
maxWallLen = 1
# Find position of player and set base of maze 3 blocks lower.
ppos = mc.player.getPos()
ppos.y -= 3
# Clear an area for the maze.
for x in range(0,mazeXSize-1):
for z in range(mazeYSize-1):
mc.setBlock(ppos.x+x,ppos.y,ppos.z+z,block.STONE)
for y in range(1,5):
mc.setBlock(ppos.x+x,ppos.y+y,ppos.z+z,block.AIR)
# Create an empty maze.
initMaze(mazeXSize,mazeYSize)
# Loop until we have no more starting points (2's in the empty maze)
while filter(lambda x: 2 in x, maze):
# Get the X and Y values of the first point in our randomized list.
rx = spl[0][0]
ry = spl[0][1]
# Pop the first entry in the list, this deletes it and the rest move down.
spl.pop(0)
# Check to see if our chosen point is still a valid starting point.
ud = False
if maze[rx][ry] == 2:
ud = True
# Pick a random wall length up to the maximum.
rc = rand(0,maxWallLen)
# Pick a random direction.
rd = randDir()
fc = rd
loop = True
while loop:
# Look in each direction, if the current wall being built is stuck inside itself start again.
if maze[rx][ry-2] == 3 and maze[rx][ry+2] == 3 and maze[rx-2][ry] == 3 and maze[rx+2][ry] == 3:
#
# Code to clear maze area required
#
initMaze(mazeXSize,mazeYSize)
break
# Look ahead to see if we're okay to go in this direction.....
cx = rx + (rd[0]*2)
cy = ry + (rd[1]*2)
nc = maze[cx][cy]
if nc != 3:
for i in range(0,2):
maze[rx][ry] = 3
makeWall(ppos.x+rx,ppos.z+ry)
rx += rd[0]
ry += rd[1]
# .....if not choose another direction.
else: rd = randDir()
# If we hit an existing wall break out of the loop.
if nc == 1: loop = False
# Update our wall length counter. When this hits zero pick another direction.
# This also makes sure the new direction isn't the same as the current one.
rc -= 1
if rc <= 0:
rc = rand(0,maxWallLen)
dd = rd
de = (fc[0]*-1,fc[1]*-1)
while dd == rd or rd == de:
rd = randDir()
# The latest wall has been built so change all 3's (new wall) to 1's (existing wall)
if ud:
for x in range(0,mazeXSize):
for y in range(0,mazeYSize):
if maze[x][y] == 3: maze[x][y] = 1

View File

@ -0,0 +1,261 @@
#!/usr/bin/env python
# mcpipy.com retrieved from URL below, written by Davie Wales
# https://bitbucket.org/dwales/minesweeper-for-minecraft-pi-edition/src
import sys
import random
import threading
import mcpi.minecraft as minecraft
import server
defaultDifficulty = 0.1
setDifficulty = defaultDifficulty
class board:
""" The cartesian grid can be done as follows:
board = [["?", "*", "?", "?", "*", "?", "?", "?", "?", "*",],
["?", "?", "*", "?", "?", "?", "?", "?", "?", "?",],
["?", "*", "*", "?", "*", "?", "?", "*", "*", "?",],
["?", "?", "?", "?", "?", "?", "*", "?", "*", "?",],
["*", "?", "?", "?", "?", "*", "?", "?", "?", "?",],
["?", "?", "?", "?", "?", "?", "?", "?", "?", "?",],
["?", "*", "?", "*", "?", "?", "?", "*", "?", "*",],
["?", "?", "?", "?", "?", "?", "?", "?", "?", "?",],
["?", "*", "?", "?", "*", "*", "?", "?", "*", "?",],
["?", "?", "*", "?", "?", "?", "?", "*", "?", "?",]]
Obviously the grid will be randomly generated on run to fit
within the bounds of the terminal window.
Notice that you can access the state of any tile on the grid with
the simple command "board[x][y]"
i.e. a = board[0][0] makes a == "?", a = board[0][9] makes a == "*"
NOTE: I subsequently changed the code to use nested dictionaries,
rather than lists to represent the board. The general idea is
still the same...
If we use a dictionary rather than a list in the following
function, we will get a KeyError if we try to access a
negative index, assuming we construct the dictionary such
that it has identical indexes to the list equivalent.
i.e. dictionary = {0:{0:" ", 1:" ", 2"*"}, 1:{0:"*", 1:" ", 2:" "}}
This will be helpful, as it will negate the need to explicitly
check whether a particular coordinate is legitimate. i.e. a
dictionary won't match negative values for x, y, but a list will..."""
""" At the moment we are getting the window size before curses is
initialised, which means that we have to use "stty size". If
we can move this code into the curses section, we can use the
built in window.getmaxyx(). This will make it easier to use
windows smaller than the size of the terminal for the game,
which will in turn allow us to add timers and minecounts."""
def __init__(self):
global width, height
width = 10
height = 10
def options(self):
totalTiles = width * height
#possible choices of tile: either "*" or " "
self.mineNumber = int(setDifficulty * totalTiles)
choices = list(self.mineNumber * "*")
choices.extend(list((totalTiles-len(choices))*" "))
return choices
# For every x and y, check all the squares around to see if there is a mine,
# add together the number of mines touching the original square and replace
# the original square with the final count.
def numberise(self, board):
for x in xrange(width):
for y in xrange(height):
count = 0
if board[x][y] != "*":
for i in xrange(-1, 2):
for n in xrange(-1, 2):
try:
if board[x+i][y+n] == "*":
count += 1
except KeyError:
pass
if count != 0:
board[x][y] = str(count)
def create(self):
self.mineCoords = []
choices = self.options()
board = {}
for i in xrange(0, width):
board[i] = {}
for n in xrange(0, height):
board[i][n] = choices.pop(choices.index(random.choice(choices)))
if board[i][n] == "*":
self.mineCoords.append([i,n])
self.numberise(board)
for i in xrange(width):
for n in xrange(height):
minecraftAddBlock(i, n, 1, board[i][n])
return board
def visibleScreen(self):
board = {}
for i in xrange(0, width):
board[i] = {}
for n in xrange(0, height):
board[i][n] = " "
return board
def minecraftAddBlock(X, Y, Z, mineAttribute):
# This equates values passed through mineAttribute with the actual
# block IDs from Minecraft.
# 0 is Air, 5 is Wood Planks, 4 is cobblestone, coal is 16
# Iron is 15, Gold is 14, Diamond is 56, Gold Block is 41,
# Diamond Block is 57
mineDict = {"dirt":3, "*":46, " ":20, 0:0, "1":5, "2":4, "3":16, "4":15, "5":14, "6":56, "7":41, "8":57}
mc.setBlock(X, Y, Z, mineDict[mineAttribute])
def explore(x, y, Z): # Z is capitalised because it doesn't
# need to be changed by the function.
""" This is the bit that happens when you click on a blank square
First it checks the squares directly around the clicked square
If the square it checks is a number, it will display it, and
if the square it checks is blank, it will add the blank square's
coordinates to a list or dictionary, then it will keep doing the
same process to all the coordinates in the list, deleting squares
that have been checked, and adding new squares, until the list is
empty. At that point, the area around the original square will be
revealed, as you would expect to happen in minesweeper."""
checked = [[x,y]] # Has been checked and contains either a number or ' '
toBeCentre = [[x, y]] # Each point in this list will be checked on all sides for the above conditions
centred = [] # These points have already been checked on all sides
global cleared
cleared = []
while len(toBeCentre) > 0:
X, Y = toBeCentre.pop(0)
centred.append([X,Y])
minecraftAddBlock(X, Y, Z, 0)
if [X,Y] not in cleared:
cleared.append([X,Y])
for i in xrange(-1, 2):
for n in xrange(-1, 2):
# When I was writing this section, it wouldn't work, and wouldn't work
# and then after changing it around a million times, suddenly it started working...
# The only problem is that I don't actually know what I did to make it work... =P
try:
if ((newBoard[X+i][Y+n] in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'])and ([X+i, Y+n] not in checked)):
minecraftAddBlock(X+i, Y+n, Z, 0) #newBoard[X+i][Y+n])
checked.append([X+i, Y+n])
if [X+i,Y+n] not in cleared:
cleared.append([X+i,Y+n])
elif newBoard[X+i][Y+n] == " ":
if (([X+i, Y+n] not in checked) and ([X+i, Y+n] not in toBeCentre)):
toBeCentre.append([X+i, Y+n])
checked.append([X+i, Y+n])
except KeyError:
pass
class WinningCheckThread (threading.Thread):
def __init__(self, mineCoords, mineNumber, z):
self.mineCoords = mineCoords
self.mineNumber = mineNumber
self.z = z
threading.Thread.__init__(self)
def run(self):
global running
running = True
mc = minecraft.Minecraft.create()
while running:
### This is the winning condition... ###
flagCount = 0
correctFlagCount = 0
for x in xrange(width):
for y in xrange(height):
if mc.getBlock(x, y, 0-1) == 50:
flagCount += 1
if [x,y] in self.mineCoords:
correctFlagCount += 1
if (self.mineNumber == correctFlagCount) and (self.mineNumber == flagCount):
for x in xrange(width):
for y in xrange(height):
mc.setBlock(x, y, self.z, 20)
mc.postToChat("You Win!!!")
running = False
sys.exit()
class BlockCheckThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
global running
running = True
mc = minecraft.Minecraft.create()
while running:
event = mc.events.pollBlockHits()
if event:
# mc.postToChat("Hit detected")
eventSplit = str(event[0]).split()
eventSplit = [eventSplit[1][0], eventSplit[2][0], eventSplit[3][0]]
cursorX, cursorY, cursorZ = eventSplit
cursorX = int(cursorX)
cursorY = int(cursorY)
cursorZ = int(cursorZ)
if newBoard[cursorX][cursorY] == "*":
for y in xrange(height):
for x in xrange(width):
# This bit of code's dodgy, because it relies on the
# creation of "newBoard" external to the function...
mc.setBlock(x, y, z, 0) # (If you hit a mine it clears the board.)
mc.postToChat("You Lose!")
running = False
sys.exit()
if newBoard[cursorX][cursorY] in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']:
#visibleScreen[x][y] = newBoard[x][y]
mc.setBlock(cursorX, cursorY, cursorZ, 0) # We just remove the top layer.
if newBoard[cursorX][cursorY] == " ":
explore(cursorX, cursorY, cursorZ)
#def main():
global running
running = True
mc = minecraft.Minecraft.create(server.address)
board = board()
newBoard = board.create()
visibleScreen = board.visibleScreen()
for x in xrange(width):
for y in xrange(height):
mc.setBlock(x,y,-1,0)
z = 0 # For now... We can make this dynamic later.
for y in xrange(height):
for x in xrange(width):
# This bit of code's dodgy, because it relies on the
# creation of "visibleScreen" external to the function...
minecraftAddBlock(x, y, z, "dirt")
WinningCheck = WinningCheckThread(board.mineCoords, board.mineNumber, z)
BlockCheck = BlockCheckThread()
BlockCheck.daemon
WinningCheck.start()
BlockCheck.start()
#main()

View File

@ -0,0 +1,43 @@
#
# Code under the MIT license by Alexander Pruss
#
from mc import *
import text
import datetime
import time
import sys
import fonts
foreground = SEA_LANTERN # this needs Minecraft 1.8
background = AIR
try:
if len(sys.argv) > 1 and not "__" in sys.argv[1]:
foreground = eval(sys.argv[1])
except:
pass
try:
if len(sys.argv) > 2 and not "__" in sys.argv[2]:
background = eval(sys.argv[2])
except:
pass
mc = Minecraft()
pos = mc.player.getTilePos()
forward = text.angleToTextDirection(mc.player.getRotation())
prevTime = ""
while True:
curTime = datetime.datetime.now().strftime("%I:%M:%S %p")
if curTime[0]=='0':
curTime = ' ' + curTime[1:]
if prevTime != curTime:
for i in range(len(curTime)):
if i >= len(prevTime) or prevTime[i] != curTime[i]:
text.drawText(mc, fonts.FONTS['8x8'], pos + forward * (8*i), forward, Vec3(0,1,0), curTime[i:], foreground, background)
break
prevTime = curTime
time.sleep(0.1)

View File

@ -0,0 +1,31 @@
#
# Code under the MIT license by Alexander Pruss
#
#
# Draw a water-filled donut
#
from mc import *
def draw_donut(mcx,mcy,mcz,R,r,mcblock):
for x in range(-R-r,R+r):
for y in range(-R-r,R+r):
xy_dist = sqrt(x**2 + y**2)
if (xy_dist > 0):
ringx = x / xy_dist * R # nearest point on major ring
ringy = y / xy_dist * R
ring_dist_sq = (x-ringx)**2 + (y-ringy)**2
for z in range(-R-r,R+r):
if (ring_dist_sq + z**2 <= r**2):
mc.setBlock(mcx+x, mcy+z, mcz+y, mcblock)
mc = Minecraft()
playerPos = mc.player.getPos()
draw_donut(playerPos.x, playerPos.y + 9, playerPos.z, 18, 9, GLASS)
mc.postToChat("Glass donut done")
draw_donut(playerPos.x, playerPos.y + 9, playerPos.z, 18, 6, WATER)
mc.postToChat("Water donut done")

View File

@ -0,0 +1,41 @@
#
# Code under the MIT license by Alexander Pruss
#
from mcturtle import *
import lsystem
t = Turtle()
t.pendelay(0)
t.turtle(None)
t.penblock(BRICK_BLOCK)
# ensure angles are always integral multiples of 90 degrees
t.gridalign()
rules = {'X':'X+YF+', 'Y':'-FX-Y'}
def go():
# draw a wall segment with a door
t.pendown()
t.penblock(BRICK_BLOCK)
t.startface()
for i in range(4):
t.go(4)
t.pitch(90)
t.endface()
t.penup()
t.go(2)
t.pendown()
t.penblock(AIR)
t.pitch(90)
t.go(1)
t.penup()
t.pitch(180)
t.go(1)
t.pitch(90)
t.go(2)
dictionary = { '+': lambda: t.yaw(90),
'-': lambda: t.yaw(-90),
'F': lambda: go() }
lsystem.lsystem('FX', rules, dictionary, 14)

View File

@ -0,0 +1,523 @@
#
# Code under the MIT license by Alexander Pruss
#
import mcpi.minecraft as minecraft
import mcpi.block as block
from mcpi.block import *
from mcpi.entity import *
from math import *
from numbers import Number,Integral
class V3(tuple):
def __new__(cls,*args):
if len(args) == 1:
return tuple.__new__(cls,tuple(*args))
else:
return tuple.__new__(cls,args)
def dot(self,other):
return self[0]*other[0]+self[1]*other[1]+self[2]*other[2]
@property
def x(self):
return self[0]
@property
def y(self):
return self[1]
@property
def z(self):
return self[2]
def __add__(self,other):
other = tuple(other)
return V3(self[0]+other[0],self[1]+other[1],self[2]+other[2])
def __radd__(self,other):
other = tuple(other)
return V3(self[0]+other[0],self[1]+other[1],self[2]+other[2])
def __sub__(self,other):
other = tuple(other)
return V3(self[0]-other[0],self[1]-other[1],self[2]-other[2])
def __rsub__(self,other):
other = tuple(other)
return V3(other[0]-self[0],other[1]-self[1],other[2]-self[2])
def __neg__(self):
return V3(-self[0],-self[1],-self[2])
def __pos__(self):
return self
def len2(self):
return self[0]*self[0]+self[1]*self[1]+self[2]*self[2]
def __abs__(self):
return sqrt(self.len2())
def __div__(self,other):
if isinstance(other,Number):
y = float(other)
return V3(self[0]/y,self[1]/y,self[2]/y)
else:
return NotImplemented
def __mul__(self,other):
if isinstance(other,Number):
return V3(self[0]*other,self[1]*other,self[2]*other)
else:
other = tuple(other)
# cross product
return V3(self[1]*other[2]-self[2]*other[1],self[2]*other[0]-self[0]*other[2],self[0]*other[1]-self[1]*other[0])
def __rmul__(self,other):
return self.__mul__(other)
def __repr__(self):
return "V3"+repr(tuple(self))
def ifloor(self):
return V3(int(floor(self[0])),int(floor(self[1])),int(floor(self[2])))
def iceil(self):
return V3(int(ceil(self[0])),int(ceil(self[1])),int(ceil(self[2])))
TO_RADIANS = pi / 180.
TO_DEGREES = 180. / pi
ICOS = [1,0,-1,0]
ISIN = [0,1,0,-1]
def makeMatrix(compass,vertical,roll):
m0 = matrixMultiply(yawMatrix(compass), pitchMatrix(vertical))
return matrixMultiply(m0, rollMatrix(roll))
def applyMatrix(m,v):
if m is None:
return v
else:
return V3(m[i][0]*v[0]+m[i][1]*v[1]+m[i][2]*v[2] for i in range(3))
def matrixDistanceSquared(m1,m2):
d2 = 0.
for i in range(3):
for j in range(3):
d2 += (m1[i][j]-m2[i][j])**2
return d2
def iatan2(y,x):
"""One coordinate must be zero"""
if x == 0:
return 90 if y > 0 else -90
else:
return 0 if x > 0 else 180
def icos(angleDegrees):
"""Calculate a cosine of an angle that must be a multiple of 90 degrees"""
return ICOS[(angleDegrees % 360) // 90]
def isin(angleDegrees):
"""Calculate a sine of an angle that must be a multiple of 90 degrees"""
return ISIN[(angleDegrees % 360) // 90]
def matrixMultiply(a,b):
c = [[0,0,0],[0,0,0],[0,0,0]]
for i in range(3):
for j in range(3):
c[i][j] = a[i][0]*b[0][j] + a[i][1]*b[1][j] + a[i][2]*b[2][j]
return c
def yawMatrix(angleDegrees):
if isinstance(angleDegrees, Integral) and angleDegrees % 90 == 0:
return [[icos(angleDegrees), 0, -isin(angleDegrees)],
[0, 1, 0],
[isin(angleDegrees), 0, icos(angleDegrees)]]
else:
theta = angleDegrees * TO_RADIANS
return [[cos(theta), 0., -sin(theta)],
[0., 1., 0.],
[sin(theta), 0., cos(theta)]]
def rollMatrix(angleDegrees):
if isinstance(angleDegrees, Integral) and angleDegrees % 90 == 0:
return [[icos(angleDegrees), -isin(angleDegrees), 0],
[isin(angleDegrees), icos(angleDegrees),0],
[0, 0, 1]]
else:
theta = angleDegrees * TO_RADIANS
return [[cos(theta), -sin(theta), 0.],
[sin(theta), cos(theta),0.],
[0., 0., 1.]]
def pitchMatrix(angleDegrees):
if isinstance(angleDegrees, Integral) and angleDegrees % 90 == 0:
return [[1, 0, 0],
[0, icos(angleDegrees),isin(angleDegrees)],
[0, -isin(angleDegrees),icos(angleDegrees)]]
else:
theta = angleDegrees * TO_RADIANS
return [[1., 0., 0.],
[0., cos(theta),sin(theta)],
[0., -sin(theta),cos(theta)]]
def get2DTriangle(a,b,c):
"""get the points of the 2D triangle"""
minX = {}
maxX = {}
for line in (traverse2D(a,b), traverse2D(b,c), traverse2D(a,c)):
for p in line:
minX0 = minX.get(p[1])
if minX0 == None:
minX[p[1]] = p[0]
maxX[p[1]] = p[0]
yield(p)
elif p[0] < minX0:
for x in xrange(p[0],minX0):
yield(x,p[1])
minX[p[1]] = p[0]
else:
maxX0 = maxX[p[1]]
if maxX0 < p[0]:
for x in range(maxX0,p[0]):
yield(x,p[1])
maxX[p[1]] = p[0]
def getFace(vertices):
if len(vertices) < 1:
raise StopIteration
if len(vertices) <= 2:
for p in traverse(V3(vertices[0]), V3(vertices[1])):
yield p
v0 = V3(vertices[0])
for i in range(2,len(vertices)):
for p in traverse(V3(vertices[i-1]), V3(vertices[i])):
for q in traverse(p, v0):
yield q
def getTriangle(p1, p2, p3):
"""
Note that this will return many duplicate poitns
"""
p1,p2,p3 = V3(p1),V3(p2),V3(p3)
for u in traverse(p2,p3):
for w in traverse(p1,u):
yield w
def frac(x):
return x - floor(x)
def traverse2D(a,b):
"""
equation of line: a + t(b-a), t from 0 to 1
Based on Amantides and Woo's ray traversal algorithm with some help from
http://stackoverflow.com/questions/12367071/how-do-i-initialize-the-t-variables-in-a-fast-voxel-traversal-algorithm-for-ray
"""
inf = float("inf")
if b[0] == a[0]:
if b[1] == a[1]:
yield (int(floor(a[0])),int(floor(a[1])))
return
tMaxX = inf
tDeltaX = 0
else:
tDeltaX = 1./abs(b[0]-a[0])
tMaxX = tDeltaX * (1. - frac(a[0]))
if b[1] == a[1]:
tMaxY = inf
tDeltaY = 0
else:
tDeltaY = 1./abs(b[1]-a[1])
tMaxY = tDeltaY * (1. - frac(a[1]))
endX = int(floor(b[0]))
endY = int(floor(b[1]))
x = int(floor(a[0]))
y = int(floor(a[1]))
if x <= endX:
stepX = 1
else:
stepX = -1
if y <= endY:
stepY = 1
else:
stepY = -1
yield (x,y)
if x == endX:
if y == endY:
return
tMaxX = inf
if y == endY:
tMaxY = inf
while True:
if tMaxX < tMaxY:
x += stepX
yield (x,y)
if x == endX:
tMaxX = inf
else:
tMaxX += tDeltaX
else:
y += stepY
yield (x,y)
if y == endY:
tMaxY = inf
else:
tMaxY += tDeltaY
if tMaxX == inf and tMaxY == inf:
return
def traverse(a,b):
"""
equation of line: a + t(b-a), t from 0 to 1
Based on Amantides and Woo's ray traversal algorithm with some help from
http://stackoverflow.com/questions/12367071/how-do-i-initialize-the-t-variables-in-a-fast-voxel-traversal-algorithm-for-ray
"""
inf = float("inf")
if b.x == a.x:
if b.y == a.y and b.z == a.z:
yield a.ifloor()
return
tMaxX = inf
tDeltaX = 0
else:
tDeltaX = 1./abs(b.x-a.x)
tMaxX = tDeltaX * (1. - frac(a.x))
if b.y == a.y:
tMaxY = inf
tDeltaY = 0
else:
tDeltaY = 1./abs(b.y-a.y)
tMaxY = tDeltaY * (1. - frac(a.y))
if b.z == a.z:
tMaxZ = inf
tDeltaZ = 0
else:
tDeltaZ = 1./abs(b.z-a.z)
tMaxZ = tDeltaZ * (1. - frac(a.z))
end = b.ifloor()
x = int(floor(a.x))
y = int(floor(a.y))
z = int(floor(a.z))
if x <= end.x:
stepX = 1
else:
stepX = -1
if y <= end.y:
stepY = 1
else:
stepY = -1
if z <= end.z:
stepZ = 1
else:
stepZ = -1
yield V3(x,y,z)
if x == end.x:
if y == end.y and z == end.z:
return
tMaxX = inf
if y == end.y:
tMaxY = inf
if z == end.z:
tMaxZ = inf
while True:
if tMaxX < tMaxY:
if tMaxX < tMaxZ:
x += stepX
yield V3(x,y,z)
if x == end.x:
tMaxX = inf
else:
tMaxX += tDeltaX
else:
z += stepZ
yield V3(x,y,z)
if z == end.z:
tMaxZ = inf
else:
tMaxZ += tDeltaZ
else:
if tMaxY < tMaxZ:
y += stepY
yield V3(x,y,z)
if y == end.y:
tMaxY = inf
else:
tMaxY += tDeltaY
else:
z += stepZ
yield V3(x,y,z)
if z == end.z:
tMaxZ = inf
else:
tMaxZ += tDeltaZ
if tMaxX == inf and tMaxY == inf and tMaxZ == inf:
return
# Brasenham's algorithm
def getLine(x1, y1, z1, x2, y2, z2):
line = []
x1 = int(floor(x1))
y1 = int(floor(y1))
z1 = int(floor(z1))
x2 = int(floor(x2))
y2 = int(floor(y2))
z2 = int(floor(z2))
point = [x1,y1,z1]
dx = x2 - x1
dy = y2 - y1
dz = z2 - z1
x_inc = -1 if dx < 0 else 1
l = abs(dx)
y_inc = -1 if dy < 0 else 1
m = abs(dy)
z_inc = -1 if dz < 0 else 1
n = abs(dz)
dx2 = l << 1
dy2 = m << 1
dz2 = n << 1
if l >= m and l >= n:
err_1 = dy2 - l
err_2 = dz2 - l
for i in range(0,l-1):
line.append(V3(point[0],point[1],point[2]))
if err_1 > 0:
point[1] += y_inc
err_1 -= dx2
if err_2 > 0:
point[2] += z_inc
err_2 -= dx2
err_1 += dy2
err_2 += dz2
point[0] += x_inc
elif m >= l and m >= n:
err_1 = dx2 - m;
err_2 = dz2 - m;
for i in range(0,m-1):
line.append(V3(point[0],point[1],point[2]))
if err_1 > 0:
point[0] += x_inc
err_1 -= dy2
if err_2 > 0:
point[2] += z_inc
err_2 -= dy2
err_1 += dx2
err_2 += dz2
point[1] += y_inc
else:
err_1 = dy2 - n;
err_2 = dx2 - n;
for i in range(0, n-1):
line.append(V3(point[0],point[1],point[2]))
if err_1 > 0:
point[1] += y_inc
err_1 -= dz2
if err_2 > 0:
point[0] += x_inc
err_2 -= dz2
err_1 += dy2
err_2 += dx2
point[2] += z_inc
line.append(V3(point[0],point[1],point[2]))
if point[0] != x2 or point[1] != y2 or point[2] != z2:
line.append(V3(x2,y2,z2))
return line
class Drawing:
TO_RADIANS = pi / 180.
TO_DEGREES = 180. / pi
def __init__(self,mc=None):
if mc:
self.mc = mc
else:
self.mc = minecraft.Minecraft()
self.width = 1
self.nib = [(0,0,0)]
def penwidth(self,w):
self.width = int(w)
if self.width == 0:
self.nib = []
elif self.width == 1:
self.nib = [(0,0,0)]
elif self.width == 2:
self.nib = []
for x in range(-1,1):
for y in range(0,2):
for z in range(-1,1):
self.nib.append((x,y,z))
else:
self.nib = []
r2 = self.width * self.width / 4.
for x in range(-self.width//2 - 1,self.width//2 + 1):
for y in range(-self.width//2 - 1, self.width//2 + 1):
for z in range(-self.width//2 -1, self.width//2 + 1):
if x*x + y*y + z*z <= r2:
self.nib.append((x,y,z))
def point(self, x, y, z, block):
for p in self.nib:
self.mc.setBlock(x+p[0],y+p[1],z+p[2],block)
def face(self, vertices, block):
self.drawPoints(getFace(vertices), block)
def line(self, x1,y1,z1, x2,y2,z2, block):
self.drawPoints(getLine(x1,y1,z1, x2,y2,z2), block)
def drawPoints(self, points, block):
if self.width == 1:
done = set()
for p in points:
if p not in done:
self.mc.setBlock(p, block)
done.add(p)
else:
done = set()
for p in points:
for point in self.nib:
x0 = p[0]+point[0]
y0 = p[1]+point[1]
z0 = p[2]+point[2]
if (x0,y0,z0) not in self.done:
self.mc.setBlock(x0,y0,z0,block)
done.add((x0,y0,z0))
if __name__ == "__main__":
d = Drawing()
pos = d.mc.player.getPos()
d.face([(pos.x,pos.y,pos.z),(pos.x+20,pos.y+20,pos.z),(pos.x+20,pos.y+20,pos.z+20),
(pos.x,pos.y,pos.z+20)], GLASS)
n = 20
for t in range(0,n):
(x1,z1) = (100*cos(t*2*pi/n),80*sin(t*2*pi/n))
for p in traverse(V3(pos.x,pos.y-1,pos.z),V3(pos.x+x1,pos.y-1,pos.z+z1)):
d.mc.setBlock(p,OBSIDIAN)
n = 40
vertices = []
for t in range(0,n):
(x1,z1) = (100*cos(t*2*pi/n),80*sin(t*2*pi/n))
vertices.append((pos.x+x1,pos.y,pos.z+z1))
d.face(vertices, STAINED_GLASS_BLUE)

View File

@ -0,0 +1,33 @@
#
# Code under the MIT license by Alexander Pruss
#
import mcpi.minecraft as minecraft
import mcpi.block as block
import math
import sys
def replace(mcx,mcy,mcz,R,mcblock,mcmeta):
for x in range(-R,R):
for y in range(-R,R):
for z in range(-R,R):
if (x**2 + y**2 + z**2 <= R**2 and mc.getBlock(mcx+x,mcy+y,mcz+z) != block.AIR.id):
mc.setBlock(mcx+x,mcy+y,mcz+z,mcblock,mcmeta)
mc = minecraft.Minecraft()
playerPos = mc.player.getPos()
R = 20
b = block.TNT.id
m = 0
if len(sys.argv) >= 2:
R = int(sys.argv[1])
if len(sys.argv) >= 3:
b = int(sys.argv[2])
if len(sys.argv) >= 4:
m = int(sys.argv[3])
replace(playerPos.x, playerPos.y, playerPos.z, R, b, m)
mc.postToChat("Explosify done")

View File

@ -0,0 +1,41 @@
#
# Code under the MIT license by Alexander Pruss
#
from mcturtle import *
import random
def tree(depth,thickness,branchLen):
if depth <= 0:
return
if random.random() < 0.2:
return
if branchLen < 4:
t.penblock(LEAVES_OAK_PERMANENT)
else:
t.penblock(WOOD)
t.penwidth(thickness)
t.go(branchLen)
newThickness = thickness / 2
if newThickness < 1:
newThickness = 1
newBranchLen = branchLen * 0.75
if branchLen < 1:
branchLen = 1
for i in range(4):
t.pitch(30)
tree(depth-1,newThickness,newBranchLen)
t.pitch(-30)
t.roll(90)
t.penup()
t.back(branchLen)
t.pendown()
t = Turtle()
t.turtle(None)
t.pendelay(0)
t.penup()
t.go(10)
t.verticalangle(90)
t.pendown()
tree(8,8,20)

View File

@ -0,0 +1,53 @@
#!/usr/bin/env python
#import the minecraft.py module from the minecraft directory
import mcpi.minecraft as minecraft
#import minecraft block module
import mcpi.block as block
#import time, so delays can be used
import server
def main():
mc = minecraft.Minecraft.create(server.address)
# an abbrieviated flatmap
# mc.setBlocks(-50,-10,-50,50,10,50,block.AIR.id)
# mc.setBlocks(-50,0,-50,50,-10,50,block.SANDSTONE.id)
# The original flatmap
mc.setBlocks(-128,0,-128,128,64,128,0)
mc.setBlocks(-128,0,-128,128,-64,128,block.SANDSTONE.id)
# exit()
mc.postToChat("Hello you have successfully ran Rail Gen :).")
# create the station
mc.setBlock(1,3,0,block.GLOWSTONE_BLOCK.id)
mc.setBlock(0,0,0,block.STONE_SLAB.id)
mc.setBlock(-1,1,0,block.DOOR_WOOD.id,0)
mc.setBlock(-1,2,0,block.DOOR_WOOD.id,8)
mc.setBlock(0,1,1,block.STONE.id)
mc.setBlock(0,2,1,block.STONE.id)
mc.setBlock(0,1,-1,block.STONE.id)
mc.setBlock(0,2,-1,block.STONE.id)
mc.setBlock(1,1,1,block.STONE.id)
mc.setBlock(-1,1,1,block.STONE.id)
mc.setBlock(0,1,1,block.STONE.id)
mc.setBlock(1,1,-1,block.STONE.id)
mc.setBlock(-1,1,-1,block.STONE.id)
mc.setBlock(-1,2,-1,block.GLOWSTONE_BLOCK.id)
mc.setBlock(1,2,-1,block.STONE.id)
mc.setBlock(1,2,1,block.STONE.id)
mc.setBlock(-1,2,1,block.GLOWSTONE_BLOCK.id)
mc.setBlock(-1,3,0,block.STONE_SLAB.id)
mc.setBlock(0,3,0,block.STONE_SLAB.id)
# Create the path one direction
mc.setBlocks(129,0,1,0,0,-1,block.STONE_SLAB)
mc.setBlocks(0,1,2,128,1,2,block.STONE.id)
mc.setBlocks(128,1,-2,0,1,-2,block.STONE.id)
mc.setBlocks(128,0,2,0,0,2,block.GLOWSTONE_BLOCK.id)
mc.setBlocks(128,0,-2,0,0,-2,block.GLOWSTONE_BLOCK.id)
if __name__ == "__main__":
main()

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,17 @@
#! /usr/bin/python
import mcpi.minecraft as minecraft
import mcpi.block as block
import server
""" clearZone clears an area and sets a stone floor
takes two x,z pairs clears everything above 0y and then sets
a stone floor at -1y
@author: goldfish"""
def clearZone( alocx, alocz, blocx, blocz ):
mc.setBlocks( alocx, 0, alocz, blocx, 64, blocz, block.AIR )
mc.setBlocks( alocx, -1, alocz, blocx, -1, blocz, block.STONE )
if __name__ == "__main__":
mc = minecraft.Minecraft.create( server.address )
clearZone( -20, -20, 20, 20 )

View File

@ -0,0 +1,44 @@
#! /usr/bin/python
import mcpi.minecraft as minecraft
import mcpi.block as block
import server
import random
""" draw a building
@author: goldfish"""
def drawBuilding( locx, locy, locz, floors, width, depth, floorheight, wallmaterial, floormaterial ):
topx = locx+width
topy = locy+((floorheight+1)*floors)
topz = locz+depth
#draw building shell
mc.setBlocks( locx, locy, locz, topx, topy, topz, wallmaterial )
mc.setBlocks( locx+1, locy+1, locz+1, topx-1, topy-1, topz-1, block.AIR )
#draw floors
if( floors > 1 ):
for i in range( floors -1 ):
floorYloc = locy+( (floorheight+1)*(i+1) )
mc.setBlocks( locx+1, floorYloc, locz+1, topx-1, floorYloc, topz-1, floormaterial )
#draw door
doorloc = random.randint( 1, width-2 )
mc.setBlock( locx, locy+1, locz+doorloc, block.AIR )
mc.setBlock( locx, locy+2, locz+doorloc, block.AIR )
#draw front windows
if( floors > 1 ):
for i in range( floors-1 ):
windowYloc = locy+2+( (floorheight+1)*(i+1) )
for j in range( floorheight-1 ):
mc.setBlocks( locx, windowYloc+j , locz+1, locx, windowYloc+j, locz+(width-1), block.GLASS_PANE )
#draw back windows
if( floors > 1 ):
for i in range( floors-1 ):
windowYloc = locy+2+( (floorheight+1)*(i+1) )
for j in range( floorheight-1 ):
mc.setBlocks( locx+depth, windowYloc+j , locz+1, locx+depth, windowYloc+j, locz+(width-1), block.GLASS_PANE )
#connect levels with ladder
#mc.setBlocks( topx-1, locy+1, topz-1, topx-1, topy-1, topz-1, block.LADDER )
if __name__ == "__main__":
mc = minecraft.Minecraft.create( server.address )
drawBuilding( 0, 0, 0, 5, 5, 5, 3, block.STONE, block.WOOD_PLANKS )

View File

@ -0,0 +1,38 @@
#
# Code under the MIT license by Alexander Pruss
#
from mcturtle import *
t = Turtle()
t.turtle(None)
t.pendelay(0)
t.angle(0) # align to grid
def face():
t.startface()
for i in range(4):
t.go(20)
t.yaw(90)
t.endface()
t.penblock(GLASS)
for i in range(2):
face()
t.roll(-90)
face()
t.roll(90)
t.pitch(90)
face()
t.pitch(-90)
t.penup()
t.go(20)
t.yaw(90)
t.go(20)
t.pitch(90)
t.go(20)
t.pitch(-90)
t.yaw(90)
t.pitch(-90)
t.pendown()

View File

@ -0,0 +1,108 @@
#
# Code under the MIT license by Alexander Pruss
#
#
# python grenade.py [speed [gravity]]
#
# Throws a grenade with the specified speed in m/s (default: 15) and specified
# gravitational acceleration (default: earth) in m/s^2 or given by listing a planet,
# sun, moon or pluto.
#
from mc import *
from vehicle import *
import time
import sys
GRAVITIES = {
'sun':274,
'mercury':3.59,
'venus':8.87,
'earth':9.81,
'moon':1.62,
'mars':3.77,
'jupiter':25.95,
'saturn':11.08,
'uranus':10.67,
'neptune':14.07,
'pluto':0.42
}
def getPath(center, azi, alt, v0):
vx = v0 * cos(alt) * sin(-azi)
vy = v0 * sin(alt)
vz = v0 * cos(alt) * cos(-azi)
t = 0
x = center.x + cos(alt) * sin(-azi) * 2
y = center.y + sin(alt) * 2 + 2
z = center.z + cos(alt) * cos(-azi) * 2
path = [(t,Vec3(round(x),round(y),round(z)))]
while not mc.getBlock(x,y,z):
v = sqrt(vx*vx+vy*vy+vz*vz)
if v < 1:
dt = 0.5
else:
dt = 0.5/v
v1x = vx
v1y = vy - g * dt
v1z = vz
x += (vx+v1x)/2 * dt
y += (vy+v1y)/2 * dt
z += (vz+v1z)/2 * dt
vx = v1x
vy = v1y
vz = v1z
t += dt
path.append( ( t,Vec3(round(x),round(y),round(z)) ) )
return path
def getXYZ(path, t1):
for t,xyz in path:
if t1<=t:
return xyz
return path[-1][1]
mc = Minecraft()
try:
v0 = int(sys.argv[1])
except:
v0 = 15
if 3 <= len(sys.argv):
try:
g = float(sys.argv[2])
except:
g = GRAVITIES[sys.argv[2].lower()]
else:
g = GRAVITIES['earth']
center = mc.player.getPos()
azi = mc.player.getRotation() * pi/180.
alt = -mc.player.getPitch() * pi/180.
GRENADE = { (-1,0,0):TNT, (1,0,0):TNT, (0,-1,0):TNT, (0,1,0):TNT, (0,0,1):TNT, (0,0,-1):TNT }
grenade = Vehicle(mc, False)
grenade.setVehicle(GRENADE)
path = getPath(center, azi, alt, v0)
dictionary = {}
prev = path[0][1]
grenade.draw(prev.x,prev.y,prev.z)
t0 = time.time()
while True:
t = time.time() - t0
pos = getXYZ(path,t)
grenade.moveTo(pos.x,pos.y,pos.z)
prev=pos
time.sleep(0.1)
if t > path[-1][0]:
break
mc.setBlock(path[-1][1],REDSTONE_BLOCK)

View File

@ -0,0 +1,8 @@
import mcpi.minecraft as minecraft
import mcpi.block as block
import server
import sys
mc = minecraft.Minecraft.create(server.address)
mc.postToChat("Hello world!")
playerPos = mc.player.getPos()
mc.setBlock(playerPos.x,playerPos.y-1,playerPos.z,block.DIAMOND_ORE)

View File

@ -0,0 +1,35 @@
#
# Code under the MIT license by Alexander Pruss
#
import lsystem
from mcturtle import *
from sys import argv
t = Turtle()
t.pendelay(0)
t.turtle(None)
t.gridalign()
# Hilbert curve axiom and production rule by Stan Wagon, Mathematica in Action (chapter 6), W. H. Freeman and Co., 1991
rules = { 'X': '^<XF^<XFX+F^>>XFX&F->>XFX+F>X+>' }
count = 0
def go():
global count
# seven segments per basic unit
if count % 7 == 0:
t.penblock(Block(WOOL.id, (count/7)%16))
count += 1
t.go(4)
dictionary = {
'F': go,
'+': lambda: t.yaw(90),
'-': lambda: t.yaw(-90),
'^': lambda: t.pitch(90),
'&': lambda: t.pitch(-90),
'>': lambda: t.roll(90),
'<': lambda: t.roll(-90)
}
lsystem.lsystem('X', rules, dictionary, 3 if len(argv)<2 else int(argv[1]))

View File

@ -0,0 +1,130 @@
#
# Import .schematic file
# Copyright (c) 2015 Alexander Pruss
#
# Under MIT License
#
from mc import *
from sys import argv
import mcpi.nbt as nbt
import json
NEED_SUPPORT = set((SAPLING.id,WATER_FLOWING.id,LAVA_FLOWING.id,GRASS_TALL.id,34,FLOWER_YELLOW.id,
FLOWER_CYAN.id,MUSHROOM_BROWN.id,MUSHROOM_RED.id,TORCH.id,63,DOOR_WOOD.id,LADDER.id,
66,68,69,70,DOOR_IRON.id,72,75,76,77,SUGAR_CANE.id,93,94,96,104,105,106,108,111,
113,115,116,117,122,127,131,132,141,142,143,145,147,148,149,150,151,154,157,
167,SUNFLOWER.id,176,177,178,183,184,185,186,187,188,189,190,191,192,
193,194,195,196,197))
def getValue(v):
if isinstance(v,nbt.TAG_Compound):
return getCompound(v)
elif isinstance(v,nbt.TAG_List):
out = []
for a in v:
out.append(getValue(a))
return out
else:
return v.value
def getCompound(nbt):
out = {}
for key in nbt:
out[key] = getValue(nbt[key])
return out
def nbtToJson(nbt):
return json.dumps(getCompound(nbt))
def importSchematic(mc,path,x0,y0,z0,centerX=False,centerY=False,centerZ=False,clear=False,movePlayer=True):
mc.postToChat("Reading "+path);
schematic = nbt.NBTFile(path, "rb")
sizeX = schematic["Width"].value
sizeY = schematic["Height"].value
sizeZ = schematic["Length"].value
def offset(x,y,z):
return x + (y*sizeZ + z)*sizeX
px,pz = x0,z0
if centerX:
x0 -= sizeX // 2
if centerY:
y0 -= sizeY // 2
if centerZ:
z0 -= sizeZ // 2
corner1 = (x0,y0,z0)
corner2 = (x0+sizeX-1,y0+sizeY-1,z0+sizeZ-1)
if clear:
mc.setBlocks(corner1,corner2,AIR)
blocks = schematic["Blocks"].value
data = schematic["Data"].value
tileEntities = schematic["TileEntities"]
tileEntityDict = {}
if not isPE:
for e in tileEntities:
origCoords = e['x'].value,e['y'].value,e['z'].value
e['x'].value += x0
e['y'].value += y0
e['z'].value += z0
tileEntityDict[origCoords] = nbtToJson(e)
check1 = lambda b : b != CARPET.id and b not in NEED_SUPPORT
check2 = lambda b : b in NEED_SUPPORT
check3 = lambda b : b == CARPET.id
mc.postToChat("Rendering");
for check in (check1,check2,check3):
for y in range(sizeY):
if check == check1 and movePlayer:
mc.player.setTilePos(px,y0+y,pz)
for x in range(sizeX):
for z in range(sizeZ):
i = offset(x,y,z)
b = blocks[i]
if b == AIR.id:
continue
d = data[i]
if not check(b):
if check == check1:
b = AIR.id
d = 0
else:
continue
if b==33 and (d&7)==7:
d = (d&8)
if (x,y,z) in tileEntityDict:
# if b==33: \print x0+x,y0+y,z0+z,x,y,z,b,d,e
mc.setBlockWithNBT(x0+x,y0+y,z0+z,b,d,tileEntityDict[(x,y,z)])
else:
# if b==33: print x0+x,y0+y,z0+z,x,y,z,b,d
mc.setBlock(x0+x,y0+y,z0+z,b,d)
print "done"
# TODO: entities
return corner1,corner2
if __name__=='__main__':
if len(argv) >= 2:
path = argv[1]
else:
import Tkinter
from tkFileDialog import askopenfilename
master = Tkinter.Tk()
master.attributes("-topmost", True)
path = askopenfilename(filetypes=['schematic {*.schematic}'],title="Open")
master.destroy()
if not path:
exit()
mc = Minecraft()
pos = mc.player.getTilePos()
(corner0,corner1)=importSchematic(mc,path,pos.x,pos.y,pos.z,centerX=True,centerZ=True)
mc.postToChat("Done drawing, putting player on top")
y = corner1[1]
while y > -256 and mc.getBlock(pos.x,y-1,pos.z) == AIR.id:
y -= 1
mc.player.setTilePos(pos.x,y,pos.z)

View File

@ -0,0 +1,21 @@
#
# Code under the MIT license by Alexander R. Pruss
#
# Useful for checking which interpreter RaspberryJamMod's /py command is picking up.
#
import mc
import sys
import os
mc = mc.Minecraft()
mc.postToChat("Python interpreter "+sys.executable+" "+sys.version)
try:
userName = os.environ['MINECRAFT_PLAYER_NAME']
except:
userName = "unspecified"
try:
userId = os.environ['MINECRAFT_PLAYER_ID']
except:
userId = "unspecified"
mc.postToChat("Invoked by user "+userName+" "+userId)

View File

@ -0,0 +1,93 @@
#!/usr/bin/env python
# mcpipy.com retrieved from URL below, written by jjinux
# http://jjinux.blogspot.com/2013/05/drawing-sierpinskis-triangle-in.html
"""Draw Sierpinski's triangle in Minecraft.
See: http://jjinux.blogspot.com/2013/05/drawing-sierpinskis-triangle-in.html
"""
import random
import mcpi.minecraft
import mcpi.block as block
import server
# It goes from -MAX_XZ to MAX_XZ.
MAX_XZ = 128
MAX_Y = 64
# These are the vertices of the triangle. It's a list of points. Each point
# is an (X, Y, X) tuple.
TRIANGLE_HEIGHT = MAX_Y - 1
TOP = (-MAX_XZ, TRIANGLE_HEIGHT, 0)
BOTTOM_LEFT = (MAX_XZ, TRIANGLE_HEIGHT, MAX_XZ)
BOTTOM_RIGHT = (MAX_XZ, TRIANGLE_HEIGHT, -MAX_XZ)
TRIANGLE_VERTICES = [TOP, BOTTOM_LEFT, BOTTOM_RIGHT]
BASE_BLOCK_ID = block.SANDSTONE.id
TRIANGLE_BLOCK_ID = block.SNOW.id
# This is the maximum number of iterations to let the algorithm run. The
# algorithm relies on randomness, so I'm just picking a sensible value.
MAX_ITERATIONS = MAX_XZ ** 2
PRINT_FREQ = 1000
def clear_board(minecraft):
minecraft.setBlocks(-MAX_XZ, 0, -MAX_XZ, MAX_XZ, MAX_Y, MAX_XZ, 0)
minecraft.setBlocks(-MAX_XZ, 0, -MAX_XZ, MAX_XZ, -MAX_Y, MAX_XZ, BASE_BLOCK_ID)
def draw_sierpinski_triangle(minecraft):
def random_in_range():
return random.randint(-MAX_XZ, MAX_XZ)
def int_average(a, b):
return int(round((a + b) / 2.0))
# Draw the triangle vertices.
for (x, y, z) in TRIANGLE_VERTICES:
minecraft.setBlock(x, y, z, TRIANGLE_BLOCK_ID)
# Pick a random point to start at.
current = (random_in_range(),
TRIANGLE_HEIGHT,
random_in_range())
for i in xrange(MAX_ITERATIONS):
if i % PRINT_FREQ == 0:
print("Drew %s blocks" % i)
# Pick a random vertex to "walk" toward.
destination = random.choice(TRIANGLE_VERTICES)
# Draw a block in the middle of the current location and the
# destination.
(c_x, c_y, c_z) = current
(d_x, d_y, d_z) = destination
current = (
int_average(c_x, d_x),
TRIANGLE_HEIGHT,
int_average(c_z, d_z)
)
(x, y, z) = current
minecraft.setBlock(x, y, z, TRIANGLE_BLOCK_ID)
if __name__ == "__main__":
minecraft = mcpi.minecraft.Minecraft.create(server.address)
# Uncomment this if you need it.
# clear_board(minecraft)
draw_sierpinski_triangle(minecraft)

View File

@ -0,0 +1,42 @@
#
# Code under the MIT license by Alexander Pruss
#
from mc import *
import sys
def draw_surface(xf,yf,zf,a0,a1,asteps,b0,b1,bsteps,ox,oy,oz,scalex,scaley,scalez,mcblock,mcmeta):
cfx = compile(xf,'<string>','eval')
cfy = compile(yf,'<string>','eval')
cfz = compile(zf,'<string>','eval')
for i in xrange(asteps):
a = (a0 * (asteps-1-i) + a1 * i) / asteps
for j in xrange(bsteps):
b = (b0 * (bsteps-1-j) + b1 * j) / bsteps
x = eval(cfx)
y = eval(cfy)
z = eval(cfz)
mc.setBlock(ox+x * scalex, oy+y * scaley, oz+z * scalez, mcblock, mcmeta)
mc = Minecraft()
playerPos = mc.player.getPos()
# formula from http://paulbourke.net/geometry/klein/
xformula = '(6 * cos(a) * (1 + sin(a)) + 4 * (1 - cos(a) / 2) * cos(a) * cos(b)) if (a <= pi) else (6 * cos(a) * (1 + sin(a)) + 4 * (1 - cos(a) / 2) * cos(b + pi))'
yformula = '16 * sin(a) + 4 * (1-cos(a)) * sin(a) * cos(b) if a <= pi else 16 * sin(a)'
zformula = '4 * (1- cos(a)/2) * sin(b)'
scale = 3
b = STAINED_GLASS.id
m = 5
if (len(sys.argv)>1):
b = int(sys.argv[1])
if (len(sys.argv)>2):
m = int(sys.argv[2])
draw_surface(xformula,yformula,zformula,0,2*pi,150*scale,0,2*pi,150*scale,playerPos.x,playerPos.y+16*scale,playerPos.z,scale,scale,scale,b, m)
#mc.postToChat("Formula done")

View File

@ -0,0 +1,89 @@
#
# Code under the MIT license by Alexander Pruss
#
from mc import *
import sys
def draw_surface(xf,yf,zf,a0,a1,asteps,b0,b1,bsteps,ox,oy,oz,scalex,scaley,scalez,mcblock,mcmeta):
cfx = compile(xf,'<string>','eval')
cfy = compile(yf,'<string>','eval')
cfz = compile(zf,'<string>','eval')
for i in xrange(asteps):
u = (a0 * (asteps-1-i) + a1 * i) / asteps
for j in xrange(bsteps):
v = (b0 * (bsteps-1-j) + b1 * j) / bsteps
x = eval(cfx)
y = eval(cfy)
z = eval(cfz)
mc.setBlock(ox+x * scalex, oy+y * scaley, oz+z * scalez, mcblock, mcmeta)
mc = Minecraft()
playerPos = mc.player.getPos()
scale = 3
b = STAINED_GLASS.id
m = 5
arg = 1
if (len(sys.argv)>arg):
b = int(sys.argv[arg])
arg += 1
if (len(sys.argv)>arg):
m = int(sys.argv[arg])
arg += 1
# http://www.gnuplotting.org/klein-bottle/
xformula = '(2.5-1.5*cos(v))*cos(u)'
zformula = '(2.5-1.5*cos(v))*sin(u)'
yformula = '-2.5*sin(v)'
draw_surface(xformula,yformula,zformula,0,2*pi,50*scale,0,pi,50*scale,playerPos.x,playerPos.y+2.5*scale,playerPos.z,scale,scale,scale,b, m)
mc.postToChat("Part 1 done")
if (len(sys.argv)>arg):
b = int(sys.argv[arg])
arg += 1
if (len(sys.argv)>arg):
m = int(sys.argv[arg])
arg += 1
xformula = '(2.5-1.5*cos(v))*cos(u)'
zformula = '(2.5-1.5*cos(v))*sin(u)'
yformula = '3*v - 3*pi'
draw_surface(xformula,yformula,zformula,0,2*pi,50*scale,pi,2*pi,50*scale,playerPos.x,playerPos.y+2.5*scale,playerPos.z,scale,scale,scale,b,m)
mc.postToChat("Part 2 done")
if (len(sys.argv)>arg):
b = int(sys.argv[arg])
arg += 1
if (len(sys.argv)>arg):
m = int(sys.argv[arg])
arg += 1
xformula = '-2+2*cos(v)-cos(u)'
zformula = 'sin(u)'
yformula = '(2+cos(u))*sin(v)+3*pi'
draw_surface(xformula,yformula,zformula,0,2*pi,50*scale,2*pi,3*pi,50*scale,playerPos.x,playerPos.y+2.5*scale,playerPos.z,scale,scale,scale,b,m)
mc.postToChat("Part 3 done")
if (len(sys.argv)>arg):
b = int(sys.argv[arg])
arg += 1
if (len(sys.argv)>arg):
m = int(sys.argv[arg])
arg += 1
xformula = '-2+2*cos(v)-cos(u)'
zformula = 'sin(u)'
yformula = '-3*v+12*pi'
draw_surface(xformula,yformula,zformula,0,2*pi,50*scale,3*pi,4*pi,50*scale,playerPos.x,playerPos.y+2.5*scale,playerPos.z,scale,scale,scale,b,m)
mc.postToChat("Formula done")

View File

@ -0,0 +1,27 @@
#
# Code under the MIT license by Alexander Pruss
#
#
# Draw a knot
#
from mc import *
mc = Minecraft()
playerPos = mc.player.getPos()
scale = 10
x0 = int(playerPos.x)
y0 = int(playerPos.y+5*scale)
z0 = int(playerPos.z)
t = 0
done = set()
while t < 2*pi:
# cinquefoil from http://www.maa.org/sites/default/files/images/upload_library/23/stemkoski/knots/page6.html
x = x0+int( scale * cos(2*t) * (3 + cos(5*t)) )
y = y0+5*scale+int( scale * sin(2*t) * (3 + cos(5*t)) )
z = z0+int( scale * sin(5*t) )
if (x,y,z) not in done:
mc.setBlock(x,y,z,GOLD_BLOCK)
done[x,y,z] = GOLD_BLOCK
t += 2*pi / 10000

View File

@ -0,0 +1,36 @@
#
# Code under the MIT license by Alexander Pruss
#
#
# Draw a knot
#
from mc import *
def ball(x0,y0,z0,r,block_type,done):
for x in range(-r,r):
for y in range(-r,r):
for z in range(-r,r):
if (x**2 + y**2 + z**2 <= r**2):
if not (x0+x,y0+y,z0+z) in done:
mc.setBlock(x0+x,y0+y,z0+z,block_type)
done.add((x0+x,y0+y,z0+z))
mc = Minecraft()
playerPos = mc.player.getPos()
scale = 10
x0 = int(playerPos.x)
y0 = int(playerPos.y + 5*scale)
z0 = int(playerPos.z)
done = set()
t = 0
while t < 2*pi:
# cinquefoil from http://www.maa.org/sites/default/files/images/upload_library/23/stemkoski/knots/page6.html
x = playerPos.x+int( scale * cos(2*t) * (3 + cos(5*t)) )
y = playerPos.y+int( scale * sin(2*t) * (3 + cos(5*t)) )
z = playerPos.z+int( scale * sin(5*t) )
ball(x,y,z,4,GLOWSTONE_BLOCK,done)
t += 2*pi / 10000

View File

@ -0,0 +1,106 @@
#
# Code under the MIT license by Alexander Pruss
#
# L-system with turtle graphics
#
import lsystem
import random
from mcturtle import *
t = Turtle()
t.pendelay(0)
t.turtle(None)
t.verticalangle(90)
def tree():
global angle
global thickness
global length
angle = 15
thickness = 8
length = 10
t.pendown()
t.penblock(WOOD)
rules = {'A': [(0.55,'^f[^^f>>>>>>A]>>>[^^f>>>>>>A]>>>>>[^^f>>>>>>A]'),
(0.25,'^f>>[^^f>>>>>>A]>>>[^^f>>>>>>A]')]}
axiom = 'fA'
material = WOOD
t.penwidth(thickness)
t.penblock(material)
stack = []
def push():
global length
global thickness
stack.append((length,thickness))
t.push()
thickness = thickness * 0.6
if length == 10:
length = 9
elif length == 9:
length = 8.4
else:
length = length * 0.75
if thickness < 1:
thickness = 1
if length <= 1.6:
t.penblock(LEAVES_OAK_PERMANENT)
t.penwidth(thickness)
def pop():
global length
global thickness
length,thickness = stack.pop()
t.pop()
dictionary = {
'[': push,
']': pop,
'^': lambda: t.pitch(angle),
'>': lambda: t.roll(angle),
'f': lambda: t.go(length)
}
lsystem.lsystem(axiom, rules, dictionary, 11)
#tree()
MIN_DISTANCE = 30
MAX_TRIES = 100
SIZE = MIN_DISTANCE * 10
OVALITY = 1.5
cx = t.position.x
cy = t.position.y
cz = t.position.z
tryCount = 0
positions = []
while tryCount < MAX_TRIES:
x = random.uniform(-1,1)
z = random.uniform(-1,1)
if x**2 + z**2 > 1:
continue
x = cx + SIZE/2 * x
z = cz + SIZE/2 * OVALITY * z
ok = True
for x0,z0 in positions:
if (x-x0)**2 + (z-z0)**2 < MIN_DISTANCE**2:
ok = False
break
if not ok:
tryCount += 1
continue
positions.append((x,z))
tryCount = 0
t.goto(x,cy,z)
print x,cy,z
t.push()
t.roll(random.uniform(0,30))
tree()
t.pop()

View File

@ -0,0 +1,92 @@
#
# Conway's Game of Life
# Copyright (c) 2015 Alexander R. Pruss
# MIT License
#
# life.py [[size [fraction]]
#
# Default size: 50
# If fraction is omitted, you can draw whatever you like. Otherwise, the specified fraction is used.
# E.g.,
# life.py 100 0.2
# will draw a 100x100 square, and fill in 20% of the cells.
from mc import *
from time import sleep
from random import random
import sys
def evolve(board):
height = len(board)
width = len(board[0])
newBoard = [[False for i in range(width)] for j in range(height)]
for row in range(height):
for col in range(width):
liveNeighbors = 0
for i in range(-1,2):
for j in range(-1,2):
if row+i >= 0 and row+i < height and col+j >= 0 and col+j < width and (i != 0 or j != 0) and board[row+i][col+j]:
liveNeighbors += 1
if liveNeighbors == 3:
newBoard[row][col] = True
elif board[row][col] and liveNeighbors == 2:
newBoard[row][col] = True
return newBoard
def border(mc,x0,y0,z0,width,height,block=STONE):
mc.setBlocks(x0-1,y0,z0-1,x0+width,y0,z0-1,block)
mc.setBlocks(x0-1,y0,z0+height,x0+width,y0,z0+height,block)
mc.setBlocks(x0-1,y0,z0,x0-1,y0,z0+height-1,block)
mc.setBlocks(x0+width,y0,z0,x0+width,y0,z0+height-1,block)
def draw(mc,x0,y0,z0,width,height,oldBoard,newBoard,full,empty):
for row in range(height):
for col in range(width):
if oldBoard == None or oldBoard[row][col] != newBoard[row][col]:
mc.setBlock(x0+col,y0,z0+row,full if newBoard[row][col] else empty)
def life(mc,x0,y0,z0,width,height,empty=AIR,full=GOLD_BLOCK,delay=0.5,board=None):
generation = 0
if board == None:
board = [[False for i in range(width)] for j in range(height)]
for row in range(height):
for col in range(width):
if mc.getBlock(x0+col,y0,z0+row) != AIR.id:
board[row][col] = True
draw(mc,x0,y0,z0,width,height,None,board,full,empty)
while True:
if generation % 10 == 0:
mc.postToChat("Generation %d" % generation)
sleep(delay)
newBoard = evolve(board)
draw(mc,x0,y0,z0,width,height,board,newBoard,full,empty)
board = newBoard
generation += 1
if __name__=='__main__':
mc = Minecraft()
pos = mc.player.getTilePos();
x0 = pos.x-25
y0 = pos.y
z0 = pos.z-25
if len(sys.argv) >= 2:
width = int(sys.argv[1])
height = width
else:
width = 50
height = 50
border(mc,x0,y0,z0,width,height)
if len(sys.argv) >= 3:
p = float(sys.argv[2])
mc.postToChat("Occupied fraction: %.3f" % p)
for row in range(height):
for col in range(width):
mc.setBlock(x0+col,y0,z0+row,GOLD_BLOCK if random() < p else AIR)
else:
mc.postToChat("Set up board and right click with sword when ready to go")
mc.events.clearAll()
while not mc.events.pollBlockHits():
sleep(0.1)
life(mc,x0,y0,z0,width,height)

View File

@ -0,0 +1,123 @@
#
# Code under the MIT license by Alexander Pruss
#
# L-system with turtle graphics
#
import collections
import random
import mcpi.settings
from mcturtle import *
def playProgram(s, dictionary):
for c in s:
if c in dictionary:
dictionary[c]()
def transform(c, t):
if isinstance(t, basestring):
return t
else:
r = random.random()
for p,out in t:
if r<p:
return out
r -= p
return c
def evolveGenerator(axiom,rules):
for c in axiom:
if c in rules:
yield transform(c, rules[c])
else:
yield c
def evolve(axiom, rules, levelCount):
for i in range(levelCount):
axiom = ''.join(evolveGenerator(axiom,rules))
return axiom
def lsystem(axiom, rules, dictionary, levelCount):
out = evolve(axiom, rules, levelCount)
playProgram(out, dictionary)
if __name__ == "__main__":
t = Turtle()
t.pendelay(0)
t.penup()
t.turtle(None)
t.go(10)
t.verticalangle(90)
t.pendown()
t.penblock(WOOD)
# a fairly simple example with rules from http://www.nbb.cornell.edu/neurobio/land/OldStudentProjects/cs490-94to95/hwchen/
# rules = {'F':'F[-&<F][<++&F]||F[--&>F][+&F]'}
#
# angle = 22.5
#
# dictionary = {
# '[': t.push,
# ']': t.pop,
# 'F': lambda: t.go(5),
# '-': lambda: t.yaw(-angle),
# '+': lambda: t.yaw(angle),
# '&': lambda: t.pitch(angle),
# '^': lambda: t.pitch(-angle),
# '<': lambda: t.roll(-angle),
# '>': lambda: t.roll(angle),
# '|': lambda: t.pitch(180)
# }
#
# lsystem('F', rules, dictionary, 3)
#
# A more complex example with
# rules based on http://www.geekyblogger.com/2008/04/tree-and-l-system.html
#
rules = {'A': '^f[^^f>>>>>>A]>>>[^^f>>>>>>A]>>>>>[^^f>>>>>>A]'}
#randomized version:
# rules = {'A': [(0.75,'^f[^^f>>>>>>A]>>>[^^f>>>>>>A]>>>>>[^^f>>>>>>A]'),
# (0.25,'^f>>[^^f>>>>>>A]>>>[^^f>>>>>>A]')]}
axiom = 'fA'
angle = 15
thickness = 8
length = 10 if mcpi.settings.isPE else 15;
material = WOOD
t.penwidth(thickness)
t.penblock(material)
stack = []
def push():
global length
global thickness
stack.append((length,thickness))
t.push()
thickness = thickness * 0.6
length = length * 0.75
if thickness < 1:
thickness = 1
if length <= 1:
t.penblock(LEAVES_OAK_PERMANENT)
t.penwidth(thickness)
def pop():
global length
global thickness
length,thickness = stack.pop()
t.pop()
dictionary = {
'[': push,
']': pop,
'^': lambda: t.pitch(angle),
'>': lambda: t.roll(angle),
'f': lambda: t.go(length)
}
lsystem(axiom, rules, dictionary, 9 if mcpi.settings.isPE else 11)

View File

@ -0,0 +1,29 @@
#
# Code under the MIT license by Alexander Pruss
#
import lsystem
from mcturtle import *
t = Turtle()
t.pendelay(0)
t.penblock(WOOD)
t.turtle(None)
t.pitch(90)
rules = {'L':'[^FL]>[^FL]>[^FL]'}
axiom = 'FL'
dictionary = {
'F': lambda: t.go(10),
'+': lambda: t.yaw(90),
'-': lambda: t.yaw(-90),
'^': lambda: t.pitch(20),
'&': lambda: t.pitch(-20),
'>': lambda: t.roll(120),
'<': lambda: t.roll(-120),
'[': lambda: t.push(),
']': lambda: t.pop()
}
lsystem.lsystem(axiom,rules,dictionary,5)

View File

@ -0,0 +1,156 @@
#
# Code under the MIT license by Alexander Pruss
#
from mc import *
import mcpi.settings
import cmath
import time
import sys
ESCAPE = 256
if len(sys.argv) < 2:
SIZE = 640 if not mcpi.settings.isPE else 400
else:
SIZE = int(sys.argv[1])
if len(sys.argv) < 3:
formula = lambda z,c : z * z + c
else:
formula = eval('lambda z,c : '+sys.argv[2])
black = WOOL_BLACK
#palette = ( WOOL_WHITE, WOOL_ORANGE, WOOL_MAGENTA, WOOL_LIGHT_BLUE,
# WOOL_YELLOW, WOOL_LIME, WOOL_PINK, WOOL_GRAY, WOOL_LIGHT_GRAY,
# WOOL_CYAN, WOOL_PURPLE, WOOL_BLUE, WOOL_BROWN, WOOL_GREEN,
# WOOL_RED, 152 )
# palette generated by solving traveling salesman problems in RGB space
#palette = (WOOL_WHITE,WOOL_LIGHT_GRAY,WOOL_LIGHT_BLUE,WOOL_CYAN,WOOL_LIME,WOOL_YELLOW,WOOL_ORANGE,152,WOOL_RED,WOOL_BROWN,WOOL_GREEN,WOOL_GRAY,WOOL_BLUE,WOOL_PURPLE,WOOL_MAGENTA,WOOL_PINK)
palette = (WOOL_WHITE,HARDENED_CLAY_STAINED_WHITE,WOOL_PINK,WOOL_MAGENTA,WOOL_PURPLE,HARDENED_CLAY_STAINED_LIGHT_BLUE,HARDENED_CLAY_STAINED_CYAN,HARDENED_CLAY_STAINED_PURPLE,HARDENED_CLAY_STAINED_LIGHT_GRAY,HARDENED_CLAY_STAINED_MAGENTA,HARDENED_CLAY_STAINED_PINK,HARDENED_CLAY_STAINED_RED,WOOL_RED,REDSTONE_BLOCK,HARDENED_CLAY_STAINED_ORANGE,WOOL_ORANGE,HARDENED_CLAY_STAINED_YELLOW,WOOL_YELLOW,WOOL_LIME,HARDENED_CLAY_STAINED_LIME,HARDENED_CLAY_STAINED_GREEN,WOOL_GREEN,HARDENED_CLAY_STAINED_GRAY,WOOL_BROWN,HARDENED_CLAY_STAINED_BROWN,WOOL_GRAY,HARDENED_CLAY_STAINED_BLUE,WOOL_BLUE,WOOL_CYAN,WOOL_LIGHT_BLUE,WOOL_LIGHT_GRAY)
def escapeTime(c):
i = 0
z = c
try:
while abs(z) < 2 and i < ESCAPE:
i = i + 1
z = formula(z,c)
return i
except:
return -1
#
# we could of course just do for x in range(0,size): for y in range(0,size): yield(x,y)
# but it will make users happier if we start at the player
#
def loopGenerator(size, cenX, cenY):
yield (cenX, cenY)
for r in range(1,size):
# right line segment
if cenX+r < size:
y = cenY - r
if y < 0:
y = 0
while y < cenY + r and y < size:
yield (cenX+r, y)
y += 1
# top line segment
if cenY+r < size:
x = cenX + r
if x >= size:
x = size - 1
while cenX - r < x and 0 <= x:
yield (x, cenY+r)
x -= 1
# left line segment
if 0 <= cenX-r:
y = cenY + r
if y >= size:
y = size - 1
while cenY - r < y and 0 <= y:
yield (cenX-r, y)
y -= 1
# bottom line segment
if 0 <= cenY-r:
x = cenX - r
if x < 0:
x = 0
while x < cenX + r and x < size:
yield(x, cenY - r)
x += 1
def pollZoom():
global lastHitEvent
events = mc.events.pollBlockHits()
if len(events) == 0:
return lastHitEvent != None
lastHitEvent = events[-1]
return True
def toComplex(x,y):
return complex((x - centerMC.x) * scale + centerCx.real,
(y - centerMC.z) * scale + centerCx.imag)
def draw():
count = 0
for (x,y) in loopGenerator(SIZE, SIZE/2, SIZE/2):
mcX = x + centerMC.x - SIZE/2
mcY = y + centerMC.z - SIZE/2
c = toComplex(mcX, mcY)
esc = escapeTime(c)
if esc < 0:
block = AIR
elif esc < ESCAPE:
block = palette[esc % len(palette)]
else:
block = black
mc.setBlock(mcX, centerMC.y, mcY,block)
if count >= 1000:
if pollZoom():
break
else:
count = 0
else:
count += 1
def formatComplex(z):
return "%.2g+%.2gi" % (z.real,z.imag)
def getInfo():
return ( "Center: "+formatComplex(centerCx)+", range from "+
formatComplex(toComplex(centerMC.x - SIZE/2, centerMC.z - SIZE/2))+" to "+
formatComplex(toComplex(centerMC.x + SIZE/2 - 1, centerMC.z + SIZE/2 - 1)) )
mc = Minecraft()
centerMC = mc.player.getPos()
centerMC.ifloor()
adjustedPlayer = centerMC.clone()
adjustedPlayer.y += 1
centerCx = complex(0,0)
scale = 4. / SIZE
lastHitEvent = None
while True:
mc.player.setPos(adjustedPlayer)
mc.postToChat(getInfo())
draw()
mc.postToChat("Rendered")
while not pollZoom():
time.sleep(0.25)
if ( lastHitEvent.pos.y != centerMC.y or
lastHitEvent.pos.x < centerMC.x - SIZE / 2 or
lastHitEvent.pos.x >= centerMC.x + SIZE / 2 or
lastHitEvent.pos.z < centerMC.z - SIZE / 2 or
lastHitEvent.pos.z >= centerMC.z + SIZE / 2 ):
mc.postToChat("resetting")
centerCx = complex(0,0)
scale = 4. / SIZE
else:
mc.postToChat("zooming")
centerCx = toComplex(lastHitEvent.pos.x,lastHitEvent.pos.z)
scale /= 2
lastHitEvent = None

View File

@ -0,0 +1,174 @@
#
# Code under the MIT license by Alexander Pruss
#
#
# mandelbulb.py [size [power [half]]]
#
# Options for half: south, north, east, west, up, down
from mc import *
import mcpi.settings as settings
import cmath
import time
import sys
from random import uniform
# setting this to 0 makes for more isolated blocks because the connecting filigree was
# missed; increasing slows down rendering
AVOID_ISOLATES = 12 if not settings.isPE else 0
ESCAPE = 250
if len(sys.argv) < 2:
size = 100
else:
size = int(sys.argv[1])
if len(sys.argv) < 3:
power = 8
else:
power = int(sys.argv[2])
if power == 8:
fractalSize = 2.16
else:
fractalSize = 4.
if len(sys.argv) < 4:
half = None
else:
half = sys.argv[3].lower()[0]
palette = list(reversed([WOOL_WHITE,HARDENED_CLAY_STAINED_WHITE,WOOL_PINK,WOOL_LIGHT_GRAY,WOOL_LIGHT_BLUE,WOOL_MAGENTA,WOOL_PURPLE,HARDENED_CLAY_STAINED_LIGHT_BLUE,HARDENED_CLAY_STAINED_LIGHT_GRAY,HARDENED_CLAY_STAINED_MAGENTA,HARDENED_CLAY_STAINED_PINK,HARDENED_CLAY_STAINED_RED,WOOL_RED,REDSTONE_BLOCK,HARDENED_CLAY_STAINED_ORANGE,WOOL_ORANGE,HARDENED_CLAY_STAINED_YELLOW,WOOL_YELLOW,WOOL_LIME,HARDENED_CLAY_STAINED_LIME,HARDENED_CLAY_STAINED_PURPLE,HARDENED_CLAY_STAINED_CYAN,WOOL_CYAN,WOOL_BLUE,HARDENED_CLAY_STAINED_BLUE,WOOL_GRAY,HARDENED_CLAY_STAINED_GREEN,WOOL_GREEN,HARDENED_CLAY_STAINED_BROWN,WOOL_BROWN,HARDENED_CLAY_STAINED_GRAY,WOOL_BLACK]));
def positions(pos,scale):
yield pos
for i in range(AVOID_ISOLATES):
yield (uniform(pos[0]-0.5*scale,pos[0]+0.5*scale),
uniform(pos[1]-0.5*scale,pos[1]+0.5*scale),
uniform(pos[2]-0.5*scale,pos[2]+0.5*scale))
def calculate0(pos):
x,z,y = pos[0],pos[1],pos[2]
cx,cy,cz = x,y,z
i = 0
try:
wentOut = 0
while i<ESCAPE:
r = sqrt(x*x+y*y+z*z)
if r > 2:
return -1
if r > wentOut:
wentOut = r
theta = acos(z/r)
phi = atan2(y,x)
zr = r**power
theta *= power
phi *= power
x = cx+zr*sin(theta)*cos(phi)
y = cy+zr*sin(phi)*sin(theta)
z = cz+zr*cos(theta)
i = i + 1
return wentOut
except:
return 0
def calculate(pos0,scale):
for pos in positions(pos0,scale):
r = calculate0(pos)
if r >= 0:
return r
return r
#
# we could of course just do for x in range(0,size): for y in range(0,size): yield(x,y)
# but it will make users happier if we start at the player
#
def pollZoom():
global lastHitEvent,lastHitPos
events = mc.events.pollBlockHits()
if len(events) == 0:
return lastHitEvent != None
lastHitEvent = events[-1]
lastHitPos = mc.player.getPos()
return True
def toBulb(centerMC,centerBulb,scale,x,y,z):
return ((x - centerMC.x) * scale + centerBulb[0],
(y - centerMC.y) * scale + centerBulb[1],
(z - centerMC.z) * scale + centerBulb[2])
def draw():
count = 0
rangeX = range(cornerMC.x, cornerMC.x+size)
rangeY = range(cornerMC.y, cornerMC.y+size)
rangeZ = range(cornerMC.z, cornerMC.z+size)
if not half is None:
if half == 'w':
rangeX = range(cornerMC.x, cornerMC.x+size/2)
elif half == 'e':
rangeX = range(cornerMC.x+size/2, cornerMC.x+size)
elif half == 'n':
rangeZ = range(cornerMC.z, cornerMC.z+size/2)
elif half == 's':
rangeZ = range(cornerMC.z+size/2, cornerMC.z+size)
elif half == 'u':
rangeY = range(cornerMC.y+size/2, cornerMC.y+size)
elif half == 'd':
rangeY = range(cornerMC.y, cornerMC.y+size/2)
for mcX in rangeX:
for mcY in rangeY:
for mcZ in rangeZ:
radius = calculate(toBulb(centerMC,centerBulb,scale,mcX,mcY,mcZ),scale)
if radius < 0:
mc.setBlock(mcX,mcY,mcZ,AIR)
else:
i = int(len(palette) / (fractalSize/2) * radius)
if i >= len(palette):
i = len(palette) - 1
mc.setBlock(mcX,mcY,mcZ,palette[i])
if pollZoom():
return
mc.postToChat("Rendered")
if __name__=='__main__':
mc = Minecraft()
startPos = mc.player.getTilePos()
cornerMC = startPos + Vec3(1,0,1)
centerMC = cornerMC + Vec3(size/2,size/2,size/2)
centerBulb = (0,0,0)
initial = True
scale = fractalSize / size
lastHitEvent = None
while True:
mc.player.setPos(startPos)
mc.postToChat("Scale: "+str(fractalSize/size/scale))
draw()
if not initial:
mc.player.setPos(centerMC)
while not pollZoom():
time.sleep(0.25)
if ( lastHitEvent.pos.x < cornerMC.x or
lastHitEvent.pos.x >= cornerMC.x + size or
lastHitEvent.pos.y < cornerMC.y or
lastHitEvent.pos.y >= cornerMC.y + size or
lastHitEvent.pos.z < cornerMC.z or
lastHitEvent.pos.z >= cornerMC.z + size ):
mc.postToChat("resetting")
centerBulb = (0,0,0)
scale = fractalSize / size
initial = True
else:
mc.postToChat("zooming")
centerBulb = toBulb(centerMC,centerBulb,scale,lastHitPos.x,lastHitPos.y,lastHitPos.z)
scale /= 8
initial = False
lastHitEvent = None

View File

@ -0,0 +1,9 @@
#
# Code under the MIT license by Alexander Pruss
#
from mcpi.minecraft import *
from mcpi.entity import *
from mcpi.block import *
from mcpi.settings import *
from math import *

View File

@ -0,0 +1,46 @@
#
# Code under the MIT license by Alexander Pruss
#
import mcpi.minecraft as minecraft
import mcpi.block as block
import lsystem
mc = minecraft.Minecraft()
playerPos = mc.player.getPos()
DIRECTIONS = ((1,0),(0,1),(-1,0),(0,-1))
pos = (int(playerPos.x),int(playerPos.y),int(playerPos.z))
direction = 0
def go():
global pos
dx = DIRECTIONS[direction][0]
dz = DIRECTIONS[direction][1]
# draw a wall
mc.setBlocks(pos,pos[0]+dx*4,pos[1]+4,pos[2]+dz*4,block.BRICK_BLOCK)
# draw a door in it
mc.setBlocks(pos[0]+dx*2,pos[1],pos[2]+dz*2,pos[0]+dx*2,pos[1]+1,pos[2]+dz*2,block.AIR)
pos = (pos[0]+dx*4, pos[1], pos[2]+dz*4)
def left():
global direction
direction -= 1
if direction == -1:
direction = 3
def right():
global direction
direction += 1
if direction == 4:
direction = 0
rules = {'X':'X+YF+', 'Y':'-FX-Y'}
dictionary = { '+': left,
'-': right,
'F': go }
lsystem.lsystem('FX', rules, dictionary, 14)
#go()

View File

@ -0,0 +1 @@
__all__ = ['minecraft', 'block', 'entity', 'connection']

View File

@ -0,0 +1,237 @@
import settings
class Block:
"""Minecraft PI block description. Can be sent to Minecraft.setBlock/s"""
def __init__(self, id, data=0, nbt=None):
self.id = id
self.data = data
if nbt is not None and len(nbt)==0:
self.nbt = None
else:
self.nbt = nbt
def __eq__(self, rhs):
return self.id == rhs.id and self.data == rhs.data and self.nbt == rhs.nbt
def __ne__(self, rhs):
return not self.__eq__(rhs)
def __hash__(self):
h = (self.id << 8) + self.data
if self.nbt is not None:
h ^= hash(self.nbt)
def withData(self, data):
return Block(self.id, data)
def __iter__(self):
"""Allows a Block to be sent whenever id [and data] is needed"""
if self.nbt is not None:
return iter((self.id, self.data, self.nbt))
else:
return iter((self.id, self.data))
def __repr__(self):
if self.nbt is None:
return "Block(%d, %d)"%(self.id, self.data)
else:
return "Block(%d, %d, %s)"%(self.id, self.data, repr(self.nbt))
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 = WATER_FLOWING
WATER_STATIONARY = Block(9)
LAVA_FLOWING = Block(10)
LAVA = LAVA_FLOWING
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)
STONE_BUTTON = Block(77)
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)
if settings.isPE:
STAINED_GLASS = WOOL
else:
STAINED_GLASS = Block(95)
STONE_BRICK = Block(98)
GLASS_PANE = Block(102)
MELON = Block(103)
FENCE_GATE = Block(107)
WOOD_BUTTON = Block(143)
REDSTONE_BLOCK = Block(152)
QUARTZ_BLOCK = Block(155)
if settings.isPE:
HARDENED_CLAY_STAINED = WOOL
else:
HARDENED_CLAY_STAINED = Block(159)
if settings.isPE:
SEA_LANTERN = Block(246) # glowing obsidian
else:
SEA_LANTERN = Block(169)
CARPET = Block(171)
COAL_BLOCK = Block(173)
if settings.isPE:
GLOWING_OBSIDIAN = Block(246)
NETHER_REACTOR_CORE = Block(247)
REDSTONE_LAMP_INACTIVE = OBSIDIAN
REDSTONE_LAMP_ACTIVE = GLOWING_OBSIDIAN
else:
GLOWING_OBSIDIAN = SEA_LANTERN
NETHER_REACTOR_CORE = SEA_LANTERN
REDSTONE_LAMP_INACTIVE = Block(123)
REDSTONE_LAMP_ACTIVE = Block(124)
SUNFLOWER = Block(175,0)
LILAC = Block(175,1)
DOUBLE_TALLGRASS = Block(175,2)
LARGE_FERN = Block(175,3)
ROSE_BUSH = Block(175,4)
PEONY = Block(175,5)
WOOL_WHITE = Block(WOOL.id, 0)
WOOL_ORANGE = Block(WOOL.id, 1)
WOOL_MAGENTA = Block(WOOL.id, 2)
WOOL_LIGHT_BLUE = Block(WOOL.id, 3)
WOOL_YELLOW = Block(WOOL.id, 4)
WOOL_LIME = Block(WOOL.id, 5)
WOOL_PINK = Block(WOOL.id, 6)
WOOL_GRAY = Block(WOOL.id, 7)
WOOL_LIGHT_GRAY = Block(WOOL.id, 8)
WOOL_CYAN = Block(WOOL.id, 9)
WOOL_PURPLE = Block(WOOL.id, 10)
WOOL_BLUE = Block(WOOL.id, 11)
WOOL_BROWN = Block(WOOL.id, 12)
WOOL_GREEN = Block(WOOL.id, 13)
WOOL_RED = Block(WOOL.id, 14)
WOOL_BLACK = Block(WOOL.id, 15)
CARPET_WHITE = Block(CARPET.id, 0)
CARPET_ORANGE = Block(CARPET.id, 1)
CARPET_MAGENTA = Block(CARPET.id, 2)
CARPET_LIGHT_BLUE = Block(CARPET.id, 3)
CARPET_YELLOW = Block(CARPET.id, 4)
CARPET_LIME = Block(CARPET.id, 5)
CARPET_PINK = Block(CARPET.id, 6)
CARPET_GRAY = Block(CARPET.id, 7)
CARPET_LIGHT_GRAY = Block(CARPET.id, 8)
CARPET_CYAN = Block(CARPET.id, 9)
CARPET_PURPLE = Block(CARPET.id, 10)
CARPET_BLUE = Block(CARPET.id, 11)
CARPET_BROWN = Block(CARPET.id, 12)
CARPET_GREEN = Block(CARPET.id, 13)
CARPET_RED = Block(CARPET.id, 14)
CARPET_BLACK = Block(CARPET.id, 15)
STAINED_GLASS_WHITE = Block(STAINED_GLASS.id, 0)
STAINED_GLASS_ORANGE = Block(STAINED_GLASS.id, 1)
STAINED_GLASS_MAGENTA = Block(STAINED_GLASS.id, 2)
STAINED_GLASS_LIGHT_BLUE = Block(STAINED_GLASS.id, 3)
STAINED_GLASS_YELLOW = Block(STAINED_GLASS.id, 4)
STAINED_GLASS_LIME = Block(STAINED_GLASS.id, 5)
STAINED_GLASS_PINK = Block(STAINED_GLASS.id, 6)
STAINED_GLASS_GRAY = Block(STAINED_GLASS.id, 7)
STAINED_GLASS_LIGHT_GRAY = Block(STAINED_GLASS.id, 8)
STAINED_GLASS_CYAN = Block(STAINED_GLASS.id, 9)
STAINED_GLASS_PURPLE = Block(STAINED_GLASS.id, 10)
STAINED_GLASS_BLUE = Block(STAINED_GLASS.id, 11)
STAINED_GLASS_BROWN = Block(STAINED_GLASS.id, 12)
STAINED_GLASS_GREEN = Block(STAINED_GLASS.id, 13)
STAINED_GLASS_RED = Block(STAINED_GLASS.id, 14)
STAINED_GLASS_BLACK = Block(STAINED_GLASS.id, 15)
HARDENED_CLAY_STAINED_WHITE = Block(HARDENED_CLAY_STAINED.id, 0)
HARDENED_CLAY_STAINED_ORANGE = Block(HARDENED_CLAY_STAINED.id, 1)
HARDENED_CLAY_STAINED_MAGENTA = Block(HARDENED_CLAY_STAINED.id, 2)
HARDENED_CLAY_STAINED_LIGHT_BLUE = Block(HARDENED_CLAY_STAINED.id, 3)
HARDENED_CLAY_STAINED_YELLOW = Block(HARDENED_CLAY_STAINED.id, 4)
HARDENED_CLAY_STAINED_LIME = Block(HARDENED_CLAY_STAINED.id, 5)
HARDENED_CLAY_STAINED_PINK = Block(HARDENED_CLAY_STAINED.id, 6)
HARDENED_CLAY_STAINED_GRAY = Block(HARDENED_CLAY_STAINED.id, 7)
HARDENED_CLAY_STAINED_LIGHT_GRAY = Block(HARDENED_CLAY_STAINED.id, 8)
HARDENED_CLAY_STAINED_CYAN = Block(HARDENED_CLAY_STAINED.id, 9)
HARDENED_CLAY_STAINED_PURPLE = Block(HARDENED_CLAY_STAINED.id, 10)
HARDENED_CLAY_STAINED_BLUE = Block(HARDENED_CLAY_STAINED.id, 11)
HARDENED_CLAY_STAINED_BROWN = Block(HARDENED_CLAY_STAINED.id, 12)
HARDENED_CLAY_STAINED_GREEN = Block(HARDENED_CLAY_STAINED.id, 13)
HARDENED_CLAY_STAINED_RED = Block(HARDENED_CLAY_STAINED.id, 14)
HARDENED_CLAY_STAINED_BLACK = Block(HARDENED_CLAY_STAINED.id, 15)
LEAVES_OAK_DECAYABLE = Block(LEAVES.id, 0)
LEAVES_SPRUCE_DECAYABLE = Block(LEAVES.id, 1)
LEAVES_BIRCH_DECAYABLE = Block(LEAVES.id, 2)
LEAVES_JUNGLE_DECAYABLE = Block(LEAVES.id, 3)
LEAVES_OAK_PERMANENT = Block(LEAVES.id, 4)
LEAVES_SPRUCE_PERMANENT = Block(LEAVES.id, 5)
LEAVES_BIRCH_PERMANENT = Block(LEAVES.id, 6)
LEAVES_JUNGLE_PERMANENT = Block(LEAVES.id, 7)
if settings.isPE:
LEAVES_ACACIA_DECAYABLE = Block(161,0)
LEAVES_DARK_OAK_DECAYABLE = Block(161,1)
LEAVES_ACACIA_PERMANENT = Block(161,2)
LEAVES_DARK_OAK_PERMANENT = Block(161,3)
else:
LEAVES_ACACIA_DECAYABLE = LEAVES_OAK_DECAYABLE
LEAVES_DARK_OAK_DECAYABLE = LEAVES_JUNGLE_DECAYABLE
LEAVES_ACACIA_PERMANENT = LEAVES_OAK_PERMANENT
LEAVES_DARK_OAK_PERMANENT = LEAVES_JUNGLE_PERMANENT

View File

@ -0,0 +1,118 @@
import socket
import select
import sys
import atexit
import os
import platform
from util import flatten_parameters_to_string
""" @author: Aron Nieminen, Mojang AB"""
class RequestError(Exception):
pass
class Connection:
"""Connection to a Minecraft Pi game"""
RequestFailed = "Fail"
def __init__(self, address=None, port=None):
if address==None:
try:
address = os.environ['MINECRAFT_API_HOST']
except KeyError:
address = "localhost"
if port==None:
try:
port = int(os.environ['MINECRAFT_API_PORT'])
except KeyError:
port = 4711
if int(sys.version[0]) >= 3:
self.send = self.send_python3
self.send_flat = self.send_flat_python3
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.connect((address, port))
self.readFile = self.socket.makefile("r")
self.lastSent = ""
if platform.system() == "Windows":
atexit.register(self.close)
def __del__(self):
if platform.system() == "Windows":
self.close()
try:
atexit.unregister(self.close)
except:
pass
def close(self):
try:
self.readFile.close()
except:
pass
try:
self.socket.close()
except:
pass
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)
if not data:
self.socket.close()
raise ValueError('Socket got closed')
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_to_string(data))
#print "f,data:",f,data
self.drain()
self.lastSent = s
self.socket.sendall(s)
def send_python3(self, f, *data):
"""Sends data. Note that a trailing newline '\n' is added here"""
s = "%s(%s)\n"%(f, flatten_parameters_to_string(data))
#print "f,data:",f,data
self.drain()
self.lastSent = s
self.socket.sendall(s.encode("utf-8"))
def send_flat(self, f, data):
"""Sends data. Note that a trailing newline '\n' is added here"""
# print "f,data:",f,list(data)
s = "%s(%s)\n"%(f, ",".join(data))
self.drain()
self.lastSent = s
self.socket.sendall(s)
def send_flat_python3(self, f, data):
"""Sends data. Note that a trailing newline '\n' is added here"""
# print "f,data:",f,list(data)
s = "%s(%s)\n"%(f, ",".join(data))
self.drain()
self.lastSent = s
self.socket.sendall(s.encode("utf-8"))
def receive(self):
"""Receives data. Note that the trailing newline '\n' is trimmed"""
s = self.readFile.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()
def sendReceive_flat(self, f, data):
"""Sends and receive data"""
self.send_flat(f, data)
return self.receive()

View File

@ -0,0 +1,62 @@
ITEM = "Item"
XPORB = "XPOrb"
LEASHKNOT = "LeashKnot"
PAINTING = "Painting"
ARROW = "Arrow"
SNOWBALL = "Snowball"
FIREBALL = "Fireball"
SMALLFIREBALL = "SmallFireball"
THROWNENDERPEARL = "ThrownEnderpearl"
EYEOFENDERSIGNAL = "EyeOfEnderSignal"
THROWNPOTION = "ThrownPotion"
THROWNEXPBOTTLE = "ThrownExpBottle"
ITEMFRAME = "ItemFrame"
WITHERSKULL = "WitherSkull"
PRIMEDTNT = "PrimedTnt"
FALLINGSAND = "FallingSand"
FIREWORKSROCKETENTITY = "FireworksRocketEntity"
ARMORSTAND = "ArmorStand"
BOAT = "Boat"
MINECARTRIDEABLE = "MinecartRideable"
MINECARTCHEST = "MinecartChest"
MINECARTFURNACE = "MinecartFurnace"
MINECARTTNT = "MinecartTNT"
MINECARTHOPPER = "MinecartHopper"
MINECARTSPAWNER = "MinecartSpawner"
MINECARTCOMMANDBLOCK = "MinecartCommandBlock"
MOB = "Mob"
MONSTER = "Monster"
CREEPER = "Creeper"
SKELETON = "Skeleton"
SPIDER = "Spider"
GIANT = "Giant"
ZOMBIE = "Zombie"
SLIME = "Slime"
GHAST = "Ghast"
PIGZOMBIE = "PigZombie"
ENDERMAN = "Enderman"
CAVESPIDER = "CaveSpider"
SILVERFISH = "Silverfish"
BLAZE = "Blaze"
LAVASLIME = "LavaSlime"
ENDERDRAGON = "EnderDragon"
WITHERBOSS = "WitherBoss"
BAT = "Bat"
WITCH = "Witch"
ENDERMITE = "Endermite"
GUARDIAN = "Guardian"
PIG = "Pig"
SHEEP = "Sheep"
COW = "Cow"
CHICKEN = "Chicken"
SQUID = "Squid"
WOLF = "Wolf"
MUSHROOMCOW = "MushroomCow"
SNOWMAN = "SnowMan"
OZELOT = "Ozelot"
VILLAGERGOLEM = "VillagerGolem"
HORSE = "EntityHorse"
RABBIT = "Rabbit"
VILLAGER = "Villager"
ENDERCRYSTAL = "EnderCrystal"
PLAYER = "(ThePlayer)"

View File

@ -0,0 +1,45 @@
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)
class ChatEvent:
"""An Event related to chat (e.g. posts)"""
POST = 0
def __init__(self, type, entityId, message):
self.type = type
self.entityId = entityId
self.message = message
def __repr__(self):
sType = {
ChatEvent.POST: "ChatEvent.POST"
}.get(self.type, "???")
return "ChatEvent(%s, %d, %s)"%(
sType,self.entityId,self.message);
@staticmethod
def Post(entityId, message):
return ChatEvent(ChatEvent.POST, entityId, message)

View File

@ -0,0 +1,69 @@
MCPI-PROTOCOL 0.1
OVERVIEW
The mcpi-protocol enables an external process (program) to interact with a
running instance of Minecraft Pi Edition.
The protocol can easily be implemented and used from any programming language
that has network socket support. The mcpi release includes api libraries (with
source) for Python and Java.
* Tcp-socket, port 4711
* Commands are clear text lines (ASCII, LF terminated)
DEFINITIONS
x,y,z -- vector of three integers.
xf,yf,zf -- vector of three floats.
blockTypeId -- integer 0-108. 0 is air.
blockData -- integer 0-15. Block data beyond the type, for example wool color.
See: http://www.minecraftwiki.net/wiki/Data_values_(Pocket_Edition)
COORDINATE SYSTEM
Most coordinates are in the form of a three integer vector (x,y,z) which
address a specific tile in the game world. (0,0,0) is the spawn point sea
level. (X,Z) is the ground plane and Y is towards the sky.
COMMANDS
-- World --
world.getBlock(x,y,z) --> blockTypeId
world.setBlock(x,y,z,blockTypeId)
world.setBlock(x,y,z,blockTypeId,blockData)
world.setBlocks(x1,y1,z1,x2,y2,z2,blockTypeId)
world.setBlocks(x1,y1,z1,x2,y2,z2,blockTypeId,blockData)
world.getHeight(x,z) --> Integer
world.checkpoint.save()
world.checkpoint.restore()
TODO: skriva ut KEYs
world.setting(KEY,0/1)
chat.post(message)
-- Camera --
camera.mode.setNormal()
camera.mode.setThirdPerson()
camera.mode.setFixed()
camera.mode.setPos(x,y,z)
-- Player --
player.getTile() --> x,y,z
player.setTile(x,y,z)
player.getPos() --> xf,yf,zf
player.setPos(xf,yf,zf)
-- Entities --
TBD
-- Events --
events.block.hits() --> pos,surface,entityId|pos,surface,entityId|... (pos is x,y,z surface is x,y,z, entityId is int)
events.clear

View File

@ -0,0 +1,6 @@
*** The real license isn't finished yet, here's what goes in plain english ***
You may execute the minecraft-pi binary on a Raspberry Pi or an emulator
You may use any of the source code included in the distribution for any purpose (except evil)
You may not redistribute any modified binary parts of the distribution

View File

@ -0,0 +1,293 @@
from connection import Connection,RequestError
from vec3 import Vec3
from event import BlockEvent,ChatEvent
from block import Block
import math
from os import environ
from util import flatten,floorFlatten
""" 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 strFloor(*args):
# return [str(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 getBlock(self, *args):
"""Get block (x,y,z) => id:int"""
return int(self.conn.sendReceive_flat("world.getBlock", floorFlatten(args)))
def getPitch(self, id):
"""Get entity direction (entityId:int) => Vec3"""
s = self.conn.sendReceive(self.pkg + ".getPitch", id)
return float(s)
def getRotation(self, id):
"""Get entity direction (entityId:int) => Vec3"""
s = self.conn.sendReceive(self.pkg + ".getRotation", id)
return float(s)
def getDirection(self, id):
"""Get entity direction (entityId:int) => Vec3"""
s = self.conn.sendReceive(self.pkg + ".getDirection", id)
return Vec3(*map(float, s.split(",")))
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 setDirection(self, id, *args):
"""Set entity pitch (entityId:int, x,y,z)"""
self.conn.send(self.pkg + ".setDirection", id, args)
def setRotation(self, id, *args):
"""Set entity rotation (entityId:int, angle)"""
self.conn.send(self.pkg + ".setRotation", id, args)
def setPitch(self, id, *args):
"""Set entity pitch (entityId:int, angle)"""
self.conn.send(self.pkg + ".setPitch", id, args)
def getTilePos(self, id, *args):
"""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, floorFlatten(*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, playerId=()):
CmdPositioner.__init__(self, connection, "player" if playerId==() else "entity")
self.id = playerId
self.conn = connection
def getDirection(self):
return CmdPositioner.getDirection(self, self.id)
def getPitch(self):
return CmdPositioner.getPitch(self, self.id)
def getRotation(self):
return CmdPositioner.getRotation(self, self.id)
def setPitch(self, *args):
return CmdPositioner.setPitch(self, self.id, args)
def setRotation(self, *args):
return CmdPositioner.setRotation(self, self.id, args)
def setDirection(self, *args):
return CmdPositioner.setDirection(self, self.id, args)
def getRotation(self):
return CmdPositioner.getRotation(self, self.id)
def getPos(self):
return CmdPositioner.getPos(self, self.id)
def setPos(self, *args):
return CmdPositioner.setPos(self, self.id, args)
def getTilePos(self):
return CmdPositioner.getTilePos(self, self.id)
def setTilePos(self, *args):
return CmdPositioner.setTilePos(self, self.id, 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]
def pollChatPosts(self):
"""Triggered by posts to chat => [ChatEvent]"""
s = self.conn.sendReceive("events.chat.posts")
events = [e for e in s.split("|") if e]
return [ChatEvent.Post(int(e[:e.find(",")]), e[e.find(",") + 1:]) for e in events]
class Minecraft:
"""The main class to interact with a running instance of Minecraft Pi."""
def __init__(self, connection=None, autoId=True):
if connection:
self.conn = connection
else:
self.conn = Connection()
self.camera = CmdCamera(self.conn)
self.entity = CmdEntity(self.conn)
if autoId:
try:
playerId = int(environ['MINECRAFT_PLAYER_ID'])
self.player = CmdPlayer(self.conn,playerId=playerId)
except:
self.player = CmdPlayer(self.conn)
else:
self.player = CmdPlayer(self.conn)
self.events = CmdEvents(self.conn)
self.enabledNBT = False
def spawnEntity(self, *args):
"""Spawn entity (type,x,y,z,tags) and get its id => id:int"""
return int(self.conn.sendReceive("world.spawnEntity", args))
def removeEntity(self, *args):
"""Remove entity (id)"""
self.conn.send("world.removeEntity", args)
def getBlock(self, *args):
"""Get block (x,y,z) => id:int"""
return int(self.conn.sendReceive_flat("world.getBlock", floorFlatten(args)))
def getBlockWithData(self, *args):
"""Get block with data (x,y,z) => Block"""
ans = self.conn.sendReceive_flat("world.getBlockWithData", floorFlatten(args))
return Block(*map(int, ans.split(",")[:2]))
def getBlockWithNBT(self, *args):
"""
Get block with data and nbt (x,y,z) => Block (if no NBT) or (Block,nbt)
For this to work, you first need to do setting("include_nbt_with_data",1)
"""
if not self.enabledNBT:
self.setting("include_nbt_with_data",1)
self.enabledNBT = True
try:
ans = self.conn.sendReceive_flat("world.getBlockWithData", floorFlatten(args))
except RequestError:
# retry in case we had a Fail from the setting
ans = self.conn.receive()
else:
ans = self.conn.sendReceive_flat("world.getBlockWithData", floorFlatten(args))
id,data = (map(int, ans.split(",")[:2]))
commas = 0
for i in range(0,len(ans)):
if ans[i] == ',':
commas += 1
if commas == 2:
if '{' in ans[i+1:]:
return Block(id,data,ans[i+1:])
else:
break
return Block(id,data)
"""
@TODO
"""
# must have no NBT tags in any Block instances
def getBlocks(self, *args):
"""Get a cuboid of blocks (x0,y0,z0,x1,y1,z1) => [id:int]"""
return int(self.conn.sendReceive_flat("world.getBlocks", floorFlatten(args)))
# must have no NBT tags in Block instance
def setBlock(self, *args):
"""Set block (x,y,z,id,[data])"""
self.conn.send_flat("world.setBlock", floorFlatten(args))
def setBlockWithNBT(self, *args):
"""Set block (x,y,z,id,data,nbt)"""
data = list(flatten(args))
self.conn.send_flat("world.setBlock", list(floorFlatten(data[:5]))+data[5:])
# must have no NBT tags in Block instance
def setBlocks(self, *args):
"""Set a cuboid of blocks (x0,y0,z0,x1,y1,z1,id,[data])"""
self.conn.send_flat("world.setBlocks", floorFlatten(args))
def setBlocksWithNBT(self, *args):
"""Set a cuboid of blocks (x0,y0,z0,x1,y1,z1,id,data,nbt)"""
data = list(flatten(args))
self.conn.send_flat("world.setBlocks", list(floorFlatten(data[:8]))+data[8:])
def getHeight(self, *args):
"""Get the height of the world (x,z) => int"""
return int(self.conn.sendReceive_flat("world.getHeight", floorFlatten(args)))
def getPlayerId(self, *args):
"""Get the id of the current player"""
return int(self.conn.sendReceive_flat("world.getPlayerId", floorFlatten(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 = None, port = None):
return Minecraft(Connection(address, port))
if __name__ == "__main__":
mc = Minecraft.create()
mc.postToChat("Hello, Minecraft!")

View File

@ -0,0 +1,624 @@
"""
Handle the NBT (Named Binary Tag) data format
Copyright (c) 2010-2013 Thomas Woolford and contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
from struct import Struct, error as StructError
from gzip import GzipFile
import zlib
from collections import MutableMapping, MutableSequence, Sequence
import os, io
try:
unicode
basestring
except NameError:
unicode = str # compatibility for Python 3
basestring = str # compatibility for Python 3
TAG_END = 0
TAG_BYTE = 1
TAG_SHORT = 2
TAG_INT = 3
TAG_LONG = 4
TAG_FLOAT = 5
TAG_DOUBLE = 6
TAG_BYTE_ARRAY = 7
TAG_STRING = 8
TAG_LIST = 9
TAG_COMPOUND = 10
TAG_INT_ARRAY = 11
class MalformedFileError(Exception):
"""Exception raised on parse error."""
pass
class TAG(object):
"""TAG, a variable with an intrinsic name."""
id = None
def __init__(self, value=None, name=None):
self.name = name
self.value = value
#Parsers and Generators
def _parse_buffer(self, buffer):
raise NotImplementedError(self.__class__.__name__)
def _render_buffer(self, buffer):
raise NotImplementedError(self.__class__.__name__)
#Printing and Formatting of tree
def tag_info(self):
"""Return Unicode string with class, name and unnested value."""
return self.__class__.__name__ + \
('(%r)' % self.name if self.name else "") + \
": " + self.valuestr()
def valuestr(self):
"""Return Unicode string of unnested value. For iterators, this returns a summary."""
return unicode(self.value)
def pretty_tree(self, indent=0):
"""Return formated Unicode string of self, where iterable items are recursively listed in detail."""
return ("\t"*indent) + self.tag_info()
# Python 2 compatibility; Python 3 uses __str__ instead.
def __unicode__(self):
"""Return a unicode string with the result in human readable format. Unlike valuestr(), the result is recursive for iterators till at least one level deep."""
return unicode(self.value)
def __str__(self):
"""Return a string (ascii formated for Python 2, unicode for Python 3) with the result in human readable format. Unlike valuestr(), the result is recursive for iterators till at least one level deep."""
return str(self.value)
# Unlike regular iterators, __repr__() is not recursive.
# Use pretty_tree for recursive results.
# iterators should use __repr__ or tag_info for each item, like regular iterators
def __repr__(self):
"""Return a string (ascii formated for Python 2, unicode for Python 3) describing the class, name and id for debugging purposes."""
return "<%s(%r) at 0x%x>" % (self.__class__.__name__,self.name,id(self))
class _TAG_Numeric(TAG):
"""_TAG_Numeric, comparable to int with an intrinsic name"""
def __init__(self, value=None, name=None, buffer=None):
super(_TAG_Numeric, self).__init__(value, name)
if buffer:
self._parse_buffer(buffer)
#Parsers and Generators
def _parse_buffer(self, buffer):
# Note: buffer.read() may raise an IOError, for example if buffer is a corrupt gzip.GzipFile
self.value = self.fmt.unpack(buffer.read(self.fmt.size))[0]
def _render_buffer(self, buffer):
buffer.write(self.fmt.pack(self.value))
class _TAG_End(TAG):
id = TAG_END
fmt = Struct(">b")
def _parse_buffer(self, buffer):
# Note: buffer.read() may raise an IOError, for example if buffer is a corrupt gzip.GzipFile
value = self.fmt.unpack(buffer.read(1))[0]
if value != 0:
raise ValueError("A Tag End must be rendered as '0', not as '%d'." % (value))
def _render_buffer(self, buffer):
buffer.write(b'\x00')
#== Value Tags ==#
class TAG_Byte(_TAG_Numeric):
"""Represent a single tag storing 1 byte."""
id = TAG_BYTE
fmt = Struct(">b")
class TAG_Short(_TAG_Numeric):
"""Represent a single tag storing 1 short."""
id = TAG_SHORT
fmt = Struct(">h")
class TAG_Int(_TAG_Numeric):
"""Represent a single tag storing 1 int."""
id = TAG_INT
fmt = Struct(">i")
"""Struct(">i"), 32-bits integer, big-endian"""
class TAG_Long(_TAG_Numeric):
"""Represent a single tag storing 1 long."""
id = TAG_LONG
fmt = Struct(">q")
class TAG_Float(_TAG_Numeric):
"""Represent a single tag storing 1 IEEE-754 floating point number."""
id = TAG_FLOAT
fmt = Struct(">f")
class TAG_Double(_TAG_Numeric):
"""Represent a single tag storing 1 IEEE-754 double precision floating point number."""
id = TAG_DOUBLE
fmt = Struct(">d")
class TAG_Byte_Array(TAG, MutableSequence):
"""
TAG_Byte_Array, comparable to a collections.UserList with
an intrinsic name whose values must be bytes
"""
id = TAG_BYTE_ARRAY
def __init__(self, name=None, buffer=None):
# TODO: add a value parameter as well
super(TAG_Byte_Array, self).__init__(name=name)
if buffer:
self._parse_buffer(buffer)
#Parsers and Generators
def _parse_buffer(self, buffer):
length = TAG_Int(buffer=buffer)
self.value = bytearray(buffer.read(length.value))
def _render_buffer(self, buffer):
length = TAG_Int(len(self.value))
length._render_buffer(buffer)
buffer.write(bytes(self.value))
# Mixin methods
def __len__(self):
return len(self.value)
def __iter__(self):
return iter(self.value)
def __contains__(self, item):
return item in self.value
def __getitem__(self, key):
return self.value[key]
def __setitem__(self, key, value):
# TODO: check type of value
self.value[key] = value
def __delitem__(self, key):
del(self.value[key])
def insert(self, key, value):
# TODO: check type of value, or is this done by self.value already?
self.value.insert(key, value)
#Printing and Formatting of tree
def valuestr(self):
return "[%i byte(s)]" % len(self.value)
def __unicode__(self):
return '['+",".join([unicode(x) for x in self.value])+']'
def __str__(self):
return '['+",".join([str(x) for x in self.value])+']'
class TAG_Int_Array(TAG, MutableSequence):
"""
TAG_Int_Array, comparable to a collections.UserList with
an intrinsic name whose values must be integers
"""
id = TAG_INT_ARRAY
def __init__(self, name=None, buffer=None):
# TODO: add a value parameter as well
super(TAG_Int_Array, self).__init__(name=name)
if buffer:
self._parse_buffer(buffer)
def update_fmt(self, length):
""" Adjust struct format description to length given """
self.fmt = Struct(">" + str(length) + "i")
#Parsers and Generators
def _parse_buffer(self, buffer):
length = TAG_Int(buffer=buffer).value
self.update_fmt(length)
self.value = list(self.fmt.unpack(buffer.read(self.fmt.size)))
def _render_buffer(self, buffer):
length = len(self.value)
self.update_fmt(length)
TAG_Int(length)._render_buffer(buffer)
buffer.write(self.fmt.pack(*self.value))
# Mixin methods
def __len__(self):
return len(self.value)
def __iter__(self):
return iter(self.value)
def __contains__(self, item):
return item in self.value
def __getitem__(self, key):
return self.value[key]
def __setitem__(self, key, value):
self.value[key] = value
def __delitem__(self, key):
del(self.value[key])
def insert(self, key, value):
self.value.insert(key, value)
#Printing and Formatting of tree
def valuestr(self):
return "[%i int(s)]" % len(self.value)
class TAG_String(TAG, Sequence):
"""
TAG_String, comparable to a collections.UserString with an
intrinsic name
"""
id = TAG_STRING
def __init__(self, value=None, name=None, buffer=None):
super(TAG_String, self).__init__(value, name)
if buffer:
self._parse_buffer(buffer)
#Parsers and Generators
def _parse_buffer(self, buffer):
length = TAG_Short(buffer=buffer)
read = buffer.read(length.value)
if len(read) != length.value:
raise StructError()
self.value = read.decode("utf-8")
def _render_buffer(self, buffer):
save_val = self.value.encode("utf-8")
length = TAG_Short(len(save_val))
length._render_buffer(buffer)
buffer.write(save_val)
# Mixin methods
def __len__(self):
return len(self.value)
def __iter__(self):
return iter(self.value)
def __contains__(self, item):
return item in self.value
def __getitem__(self, key):
return self.value[key]
#Printing and Formatting of tree
def __repr__(self):
return self.value
#== Collection Tags ==#
class TAG_List(TAG, MutableSequence):
"""
TAG_List, comparable to a collections.UserList with an intrinsic name
"""
id = TAG_LIST
def __init__(self, type=None, value=None, name=None, buffer=None):
super(TAG_List, self).__init__(value, name)
if type:
self.tagID = type.id
else:
self.tagID = None
self.tags = []
if buffer:
self._parse_buffer(buffer)
if self.tagID == None:
raise ValueError("No type specified for list: %s" % (name))
#Parsers and Generators
def _parse_buffer(self, buffer):
self.tagID = TAG_Byte(buffer=buffer).value
self.tags = []
length = TAG_Int(buffer=buffer)
for x in range(length.value):
self.tags.append(TAGLIST[self.tagID](buffer=buffer))
def _render_buffer(self, buffer):
TAG_Byte(self.tagID)._render_buffer(buffer)
length = TAG_Int(len(self.tags))
length._render_buffer(buffer)
for i, tag in enumerate(self.tags):
if tag.id != self.tagID:
raise ValueError("List element %d(%s) has type %d != container type %d" %
(i, tag, tag.id, self.tagID))
tag._render_buffer(buffer)
# Mixin methods
def __len__(self):
return len(self.tags)
def __iter__(self):
return iter(self.tags)
def __contains__(self, item):
return item in self.tags
def __getitem__(self, key):
return self.tags[key]
def __setitem__(self, key, value):
self.tags[key] = value
def __delitem__(self, key):
del(self.tags[key])
def insert(self, key, value):
self.tags.insert(key, value)
#Printing and Formatting of tree
def __repr__(self):
return "%i entries of type %s" % (len(self.tags), TAGLIST[self.tagID].__name__)
#Printing and Formatting of tree
def valuestr(self):
return "[%i %s(s)]" % (len(self.tags), TAGLIST[self.tagID].__name__)
def __unicode__(self):
return "["+", ".join([tag.tag_info() for tag in self.tags])+"]"
def __str__(self):
return "["+", ".join([tag.tag_info() for tag in self.tags])+"]"
def pretty_tree(self, indent=0):
output = [super(TAG_List, self).pretty_tree(indent)]
if len(self.tags):
output.append(("\t"*indent) + "{")
output.extend([tag.pretty_tree(indent + 1) for tag in self.tags])
output.append(("\t"*indent) + "}")
return '\n'.join(output)
class TAG_Compound(TAG, MutableMapping):
"""
TAG_Compound, comparable to a collections.OrderedDict with an
intrinsic name
"""
id = TAG_COMPOUND
def __init__(self, buffer=None, name=None):
# TODO: add a value parameter as well
super(TAG_Compound, self).__init__()
self.tags = []
self.name = ""
if buffer:
self._parse_buffer(buffer)
#Parsers and Generators
def _parse_buffer(self, buffer):
while True:
type = TAG_Byte(buffer=buffer)
if type.value == TAG_END:
#print("found tag_end")
break
else:
name = TAG_String(buffer=buffer).value
try:
tag = TAGLIST[type.value](buffer=buffer, name=name)
tag.name = name
self.tags.append(tag)
except KeyError:
raise ValueError("Unrecognised tag type")
def _render_buffer(self, buffer):
for tag in self.tags:
TAG_Byte(tag.id)._render_buffer(buffer)
TAG_String(tag.name)._render_buffer(buffer)
tag._render_buffer(buffer)
buffer.write(b'\x00') #write TAG_END
# Mixin methods
def __len__(self):
return len(self.tags)
def __iter__(self):
for key in self.tags:
yield key.name
def __contains__(self, key):
if isinstance(key, int):
return key <= len(self.tags)
elif isinstance(key, basestring):
for tag in self.tags:
if tag.name == key:
return True
return False
elif isinstance(key, TAG):
return key in self.tags
return False
def __getitem__(self, key):
if isinstance(key, int):
return self.tags[key]
elif isinstance(key, basestring):
for tag in self.tags:
if tag.name == key:
return tag
else:
raise KeyError("Tag %s does not exist" % key)
else:
raise TypeError("key needs to be either name of tag, or index of tag, not a %s" % type(key).__name__)
def __setitem__(self, key, value):
assert isinstance(value, TAG), "value must be an nbt.TAG"
if isinstance(key, int):
# Just try it. The proper error will be raised if it doesn't work.
self.tags[key] = value
elif isinstance(key, basestring):
value.name = key
for i, tag in enumerate(self.tags):
if tag.name == key:
self.tags[i] = value
return
self.tags.append(value)
def __delitem__(self, key):
if isinstance(key, int):
del(self.tags[key])
elif isinstance(key, basestring):
self.tags.remove(self.__getitem__(key))
else:
raise ValueError("key needs to be either name of tag, or index of tag")
def keys(self):
return [tag.name for tag in self.tags]
def iteritems(self):
for tag in self.tags:
yield (tag.name, tag)
#Printing and Formatting of tree
def __unicode__(self):
return "{"+", ".join([tag.tag_info() for tag in self.tags])+"}"
def __str__(self):
return "{"+", ".join([tag.tag_info() for tag in self.tags])+"}"
def valuestr(self):
return '{%i Entries}' % len(self.tags)
def pretty_tree(self, indent=0):
output = [super(TAG_Compound, self).pretty_tree(indent)]
if len(self.tags):
output.append(("\t"*indent) + "{")
output.extend([tag.pretty_tree(indent + 1) for tag in self.tags])
output.append(("\t"*indent) + "}")
return '\n'.join(output)
TAGLIST = {TAG_END: _TAG_End, TAG_BYTE:TAG_Byte, TAG_SHORT:TAG_Short, TAG_INT:TAG_Int, TAG_LONG:TAG_Long, TAG_FLOAT:TAG_Float, TAG_DOUBLE:TAG_Double, TAG_BYTE_ARRAY:TAG_Byte_Array, TAG_STRING:TAG_String, TAG_LIST:TAG_List, TAG_COMPOUND:TAG_Compound, TAG_INT_ARRAY:TAG_Int_Array}
class NBTFile(TAG_Compound):
"""Represent an NBT file object."""
def __init__(self, filename=None, buffer=None, fileobj=None):
"""
Create a new NBTFile object.
Specify either a filename, file object or data buffer.
If filename of file object is specified, data should be GZip-compressed.
If a data buffer is specified, it is assumed to be uncompressed.
If filename is specified, the file is closed after reading and writing.
If file object is specified, the caller is responsible for closing the file.
"""
super(NBTFile, self).__init__()
self.filename = filename
self.type = TAG_Byte(self.id)
closefile = True
#make a file object
if filename:
self.filename = filename
self.file = GzipFile(filename, 'rb')
elif buffer:
if hasattr(buffer, 'name'):
self.filename = buffer.name
self.file = buffer
closefile = False
elif fileobj:
if hasattr(fileobj, 'name'):
self.filename = fileobj.name
self.file = GzipFile(fileobj=fileobj)
else:
self.file = None
closefile = False
#parse the file given initially
if self.file:
self.parse_file()
if closefile:
# Note: GzipFile().close() does NOT close the fileobj,
# So we are still responsible for closing that.
try:
self.file.close()
except (AttributeError, IOError):
pass
self.file = None
def parse_file(self, filename=None, buffer=None, fileobj=None):
"""Completely parse a file, extracting all tags."""
if filename:
self.file = GzipFile(filename, 'rb')
elif buffer:
if hasattr(buffer, 'name'):
self.filename = buffer.name
self.file = buffer
elif fileobj:
if hasattr(fileobj, 'name'):
self.filename = fileobj.name
self.file = GzipFile(fileobj=fileobj)
if self.file:
try:
type = TAG_Byte(buffer=self.file)
if type.value == self.id:
name = TAG_String(buffer=self.file).value
self._parse_buffer(self.file)
self.name = name
self.file.close()
else:
raise MalformedFileError("First record is not a Compound Tag")
except StructError as e:
raise MalformedFileError("Partial File Parse: file possibly truncated.")
else:
raise ValueError("NBTFile.parse_file(): Need to specify either a filename or a file object")
def write_file(self, filename=None, buffer=None, fileobj=None):
"""Write this NBT file to a file."""
closefile = True
if buffer:
self.filename = None
self.file = buffer
closefile = False
elif filename:
self.filename = filename
self.file = GzipFile(filename, "wb")
elif fileobj:
self.filename = None
self.file = GzipFile(fileobj=fileobj, mode="wb")
elif self.filename:
self.file = GzipFile(self.filename, "wb")
elif not self.file:
raise ValueError("NBTFile.write_file(): Need to specify either a filename or a file object")
#Render tree to file
TAG_Byte(self.id)._render_buffer(self.file)
TAG_String(self.name)._render_buffer(self.file)
self._render_buffer(self.file)
#make sure the file is complete
try:
self.file.flush()
except (AttributeError, IOError):
pass
if closefile:
try:
self.file.close()
except (AttributeError, IOError):
pass
def __repr__(self):
"""
Return a string (ascii formated for Python 2, unicode
for Python 3) describing the class, name and id for
debugging purposes.
"""
if self.filename:
return "<%s(%r) with %s(%r) at 0x%x>" % (self.__class__.__name__, self.filename, \
TAG_Compound.__name__, self.name, id(self))
else:
return "<%s with %s(%r) at 0x%x>" % (self.__class__.__name__, \
TAG_Compound.__name__, self.name, id(self))
if __name__=="__main__":
print "NBT library"

View File

@ -0,0 +1,15 @@
from os import environ
MINECRAFT_POCKET_EDITION = 0
MINECRAFT_PI = 1
MINECRAFT_DESKTOP = 2
minecraftType = MINECRAFT_DESKTOP
try:
minecraftType = int(environ['MINECRAFT_TYPE'])
except:
pass
isPE = ( minecraftType != MINECRAFT_DESKTOP )

View File

@ -0,0 +1,21 @@
import collections
import math
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
# this is highly optimized to iterables consisting at base level of ints and floats only
def floorFlatten(l):
for e in l:
if isinstance(e, int):
yield str(e)
elif isinstance(e, float):
yield str(int(math.floor(e)))
elif not e is None:
for ee in floorFlatten(e): yield ee
def flatten_parameters_to_string(l):
return ",".join(map(str, flatten(l)))

View File

@ -0,0 +1,108 @@
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
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()

View File

@ -0,0 +1,104 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{ad0b690c-a698-4ce0-9b50-3069e7e8660d}</ProjectGuid>
<ProjectHome />
<StartupFile>scan.py</StartupFile>
<SearchPath />
<WorkingDirectory>.</WorkingDirectory>
<OutputPath>.</OutputPath>
<ProjectTypeGuids>{888888a0-9f3d-457c-b088-3a5042f75d52}</ProjectTypeGuids>
<LaunchProvider>Standard Python launcher</LaunchProvider>
<InterpreterId />
<InterpreterVersion />
<IsWindowsApplication>False</IsWindowsApplication>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Debug'" />
<PropertyGroup Condition="'$(Configuration)' == 'Release'" />
<PropertyGroup>
<VisualStudioVersion Condition=" '$(VisualStudioVersion)' == '' ">10.0</VisualStudioVersion>
<PtvsTargetsFile>$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Python Tools\Microsoft.PythonTools.targets</PtvsTargetsFile>
</PropertyGroup>
<ItemGroup>
<Compile Include="borromean.py" />
<Compile Include="donut.py" />
<Compile Include="dragoncurve.py" />
<Compile Include="drawing.py" />
<Compile Include="glasscube.py" />
<Compile Include="hilbert.py" />
<Compile Include="klein.py" />
<Compile Include="klein2.py" />
<Compile Include="knot.py" />
<Compile Include="knot2.py" />
<Compile Include="lforest.py" />
<Compile Include="lsystem.py" />
<Compile Include="ltree.py" />
<Compile Include="mandelbrot.py" />
<Compile Include="mc.py" />
<Compile Include="mcdragoncurve.py" />
<Compile Include="mcpi\block.py" />
<Compile Include="mcpi\connection.py" />
<Compile Include="mcpi\entity.py" />
<Compile Include="mcpi\event.py" />
<Compile Include="mcpi\minecraft.py" />
<Compile Include="mcpi\util.py" />
<Compile Include="mcpi\vec3.py" />
<Compile Include="mcpi\__init__.py" />
<Compile Include="mcturtle.py" />
<Compile Include="mengersponge.py" />
<Compile Include="sphere.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="NeuroPy\NeuroPy.py" />
<Compile Include="NeuroPy\__init__.py" />
<Compile Include="polyhedron.py" />
<Compile Include="render\ds9.py" />
<Compile Include="render\minecraft-renderObj.py" />
<Compile Include="render\minecraft-renderObjv2.py" />
<Compile Include="render\minecraft\block.py" />
<Compile Include="render\minecraft\connection.py" />
<Compile Include="render\minecraft\event.py" />
<Compile Include="render\minecraft\minecraft.py" />
<Compile Include="render\minecraft\util.py" />
<Compile Include="render\minecraft\vec3.py" />
<Compile Include="render\minecraft\__init__.py" />
<Compile Include="render\render.py" />
<Compile Include="scan.py" />
<Compile Include="server.py" />
<Compile Include="sierpinski3d.py" />
<Compile Include="simpletree.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="snowflake.py" />
<Compile Include="spacefill.py" />
<Compile Include="squarecurve.py" />
<Compile Include="star.py" />
<Compile Include="symmetry.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="turtle.py" />
<Compile Include="turtledonut.py" />
<Compile Include="vehicle.py" />
</ItemGroup>
<ItemGroup>
<Content Include="mcpi\mcpi_protocol_spec.txt" />
<Content Include="NeuroPy\README.txt" />
<Content Include="render\blockstructure_tex_0.jpg" />
<Content Include="render\cessna.png" />
<Content Include="render\NY_LIL.png" />
<Content Include="render\RaspberryPi.png" />
<Content Include="render\shuttle.png" />
<Content Include="render\skyscraper.png" />
</ItemGroup>
<ItemGroup>
<Folder Include="backup" />
<Folder Include="mcpi" />
<Folder Include="NeuroPy" />
<Folder Include="render" />
<Folder Include="render\minecraft" />
</ItemGroup>
<Import Project="$(PtvsTargetsFile)" Condition="Exists($(PtvsTargetsFile))" />
<Import Project="$(MSBuildToolsPath)\Microsoft.Common.targets" Condition="!Exists($(PtvsTargetsFile))" />
</Project>

View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Express 2013 for Windows Desktop
VisualStudioVersion = 12.0.31101.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "mcpipy", "mcpipy.pyproj", "{AD0B690C-A698-4CE0-9B50-3069E7E8660D}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7CD6D1CE-4B00-4E16-94F0-FB3BF4F0D6F8}"
ProjectSection(SolutionItems) = preProject
render.py = render.py
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{AD0B690C-A698-4CE0-9B50-3069E7E8660D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AD0B690C-A698-4CE0-9B50-3069E7E8660D}.Release|Any CPU.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

Binary file not shown.

View File

@ -0,0 +1,368 @@
#
# Code under the MIT license by Alexander Pruss
#
import mcpi.minecraft as minecraft
import mcpi.block as block
from mcpi.block import *
from mcpi.entity import *
import numbers
import copy
import time
from drawing import *
from operator import itemgetter
from math import *
import numbers
class Turtle:
QUICK_SAVE = ( 'block', 'width', 'pen', 'matrix', 'nib', 'fan' )
def __init__(self,mc=None):
if mc:
self.mc = mc
else:
self.mc = minecraft.Minecraft()
self.block = GOLD_BLOCK
self.width = 1
self.pen = True
self.directionIn()
self.positionIn()
self.delayTime = 0.05
self.nib = [(0,0,0)]
self.turtleType = PLAYER
self.turtleId = None
self.fan = None
self.stack = []
self.setEntityCommands()
def setEntityCommands(self):
if self.turtleId == None:
self.setPos = self.mc.player.setPos
self.setPitch = self.mc.player.setPitch
self.setRotation = self.mc.player.setRotation
else:
self.setPos = lambda *pos: self.mc.entity.setPos(self.turtleId,*pos)
self.setPitch = lambda angle: self.mc.entity.setPitch(self.turtleId,angle)
self.setRotation = lambda angle: self.mc.entity.setRotation(self.turtleId,angle)
def save(self):
dict = {}
for attribute in Turtle.QUICK_SAVE:
dict[attribute] = copy.deepcopy(getattr(self, attribute))
dict['position'] = (self.position.x, self.position.y, self.position.z)
return dict
def restore(self, dict):
for attribute in Turtle.QUICK_SAVE:
setattr(self, attribute, dict[attribute])
p = dict['position']
self.position = minecraft.Vec3(p[0], p[1], p[2])
self.positionOut()
self.directionOut()
def push(self):
"""Save current drawing state to stack"""
self.stack.append(self.save())
def pop(self):
"""Restore current drawing state from stack"""
self.restore(self.stack.pop())
def turtle(self,turtleType):
"""Set turtle type. Use PLAYER for moving the player as the turtle and None for none"""
if self.turtleType == turtleType:
return
if self.turtleType and self.turtleType != PLAYER:
self.mc.removeEntity(self.turtleId)
self.turtleType = turtleType
if turtleType == PLAYER:
self.turtleId = None
elif turtleType:
self.turtleId = self.mc.spawnEntity(turtleType,
self.position.x,self.position.y,self.position.z,
"{NoAI:1}")
self.setEntityCommands()
self.positionOut()
self.directionOut()
def follow(self): # deprecated
self.turtle(PLAYER)
def nofollow(self): # deprecated
if self.turtleType == PLAYER:
self.turtle(None)
def penwidth(self,w):
"""Set pen stroke width (width:int)"""
self.width = int(w)
if self.width == 0:
self.nib = []
elif self.width == 1:
self.nib = [(0,0,0)]
elif self.width == 2:
self.nib = []
for x in range(-1,1):
for y in range(0,2):
for z in range(-1,1):
self.nib.append((x,y,z))
else:
self.nib = []
r2 = self.width * self.width / 4.
for x in range(-self.width//2 - 1,self.width//2 + 1):
for y in range(-self.width//2 - 1, self.width//2 + 1):
for z in range(-self.width//2 -1, self.width//2 + 1):
if x*x + y*y + z*z <= r2:
self.nib.append((x,y,z))
def goto(self,x,y,z):
"""Teleport turtle to location (x:int, y:int, z:int)"""
self.position.x = x
self.position.y = y
self.position.z = z
self.positionOut()
self.delay()
def rollangle(self,angle):
"""Set roll angle of turtle (angle:float/int) in degrees: 0=up vector points up"""
angles = self.getMinecraftAngles()
m0 = matrixMultiply(yawMatrix(angles[0]), pitchMatrix(angles[1]))
self.matrix = matrixMultiply(m0, rollMatrix(angle))
def angles(self,compass=0,vertical=0,roll=0):
"""Set roll angle of turtle (compass, vertical, roll) in degrees"""
self.matrix = makeMatrix(compass,vertical,roll)
def verticalangle(self,angle):
"""Vertical angle of turtle (angle:float/int) in degrees: 0=horizontal, 90=directly up, -90=directly down"""
angles = self.getMinecraftAngles();
self.matrix = matrixMultiply(yawMatrix(angles[0]), pitchMatrix(angle))
self.directionOut()
def angle(self,angle):
"""Compass angle of turtle (angle:float/int) in degrees: 0=south, 90=west, 180=north, 270=west"""
angles = self.getMinecraftAngles()
self.matrix = matrixMultiply(yawMatrix(angle), pitchMatrix(angles[1]))
self.directionOut()
def penup(self):
"""Move without drawing"""
self.pen = False
def pendown(self):
"""Move with drawing"""
self.pen = True
def penblock(self, block):
"""Set material of pen block"""
self.block = block
def positionIn(self):
pos = self.mc.player.getPos()
self.position = minecraft.Vec3(int(round(pos.x)),int(round(pos.y)),int(round(pos.z)))
def positionOut(self):
if self.turtleType:
self.setPos(self.position)
def delay(self):
if self.delayTime > 0:
time.sleep(self.delayTime)
def directionIn(self):
rotation = self.mc.player.getRotation()
pitch = 0 #self.mc.player.getPitch()
self.matrix = matrixMultiply(yawMatrix(rotation), pitchMatrix(-pitch))
def yaw(self,angleDegrees):
self.matrix = matrixMultiply(self.matrix, yawMatrix(angleDegrees))
self.directionOut()
self.delay()
def roll(self,angleDegrees):
self.matrix = matrixMultiply(self.matrix, rollMatrix(angleDegrees))
self.directionOut()
self.delay()
def pitch(self,angleDegrees):
self.matrix = matrixMultiply(self.matrix, pitchMatrix(angleDegrees))
self.directionOut()
self.delay()
def getHeading(self):
return [self.matrix[0][2],self.matrix[1][2],self.matrix[2][2]]
def getMinecraftAngles(self):
heading = self.getHeading()
if isinstance(heading[0], numbers.Integral) and isinstance(heading[1], numbers.Integral) and isinstance(heading[2], numbers.Integral):
# the only way all coordinates of the heading can be integers is if we are
# grid aligned
# no need for square roots; could also use absolute value
xz = abs(heading[0]) + abs(heading[2])
if xz != 0:
rotation = iatan2(-heading[0], heading[2])
else:
rotation = 0
pitch = iatan2(-heading[1], xz)
else:
xz = sqrt(heading[0]*heading[0] + heading[2]*heading[2])
if xz >= 1e-9:
rotation = atan2(-heading[0], heading[2]) * TO_DEGREES
else:
rotation = 0.
pitch = atan2(-heading[1], xz) * TO_DEGREES
return [rotation,pitch]
def directionOut(self):
if self.turtleType:
heading = self.getHeading()
xz = sqrt(heading[0]*heading[0] + heading[2]*heading[2])
pitch = atan2(-heading[1], xz) * TO_DEGREES
self.setPitch(pitch)
if xz >= 1e-9:
rotation = atan2(-heading[0], heading[2]) * TO_DEGREES
self.setRotation(rotation)
def pendelay(self, t):
"""Set pen delay in seconds (t: float)"""
self.delayTime = t
def left(self, angle):
"""Turn counterclockwise relative to compass heading"""
self.right(-angle)
def right(self, angle):
"""Turn clockwise relative to compass heading"""
self.matrix = matrixMultiply(yawMatrix(angle), self.matrix)
self.directionOut()
self.delay()
def up(self, angle):
"""Turn upwards (increase pitch)"""
self.pitch(angle)
def down(self, angle):
"""Turn downwards (decrease pitch)"""
self.up(-angle)
def go(self, distance):
"""Advance turtle, drawing as needed (distance: float)"""
# pitch = self.pitch * pi/180.
# rot = self.rotation * pi/180.
# at pitch=0: rot=0 -> [0,0,1], rot=90 -> [-1,0,0]
# dx = cos(-pitch) * sin(-rot)
# dy = sin(-pitch)
# dz = cos(-pitch) * cos(-rot)
[dx,dy,dz] = self.getHeading()
newX = self.position.x + dx * distance
newY = self.position.y + dy * distance
newZ = self.position.z + dz * distance
self.drawLine(self.position.x, self.position.y, self.position.z,
newX, newY, newZ)
self.position.x = newX
self.position.y = newY
self.position.z = newZ
self.positionOut()
self.delay()
def back(self, distance):
"""Move turtle backwards, drawing as needed (distance: float), and keeping heading unchanged"""
# pitch = self.pitch * pi/180.
# rot = self.rotation * pi/180.
# dx = - cos(-pitch) * sin(-rot)
# dy = - sin(-pitch)
# dz = - cos(-pitch) * cos(-rot)
[dx,dy,dz] = self.getHeading()
newX = self.position.x - dx * distance
newY = self.position.y - dy * distance
newZ = self.position.z - dz * distance
self.drawLine(self.position.x, self.position.y, self.position.z,
newX, newY, newZ)
self.position.x = newX
self.position.y = newY
self.position.z = newZ
self.positionOut()
self.delay()
def startface(self):
"""Start drawing a convex polygon"""
self.fan = (self.position.x,self.position.y,self.position.z)
def endface(self):
"""Finish polygon"""
self.fan = None
def gridalign(self):
"""Align positions to grid"""
self.position.x = int(round(self.position.x))
self.position.y = int(round(self.position.y))
self.position.z = int(round(self.position.z))
if self.fan:
self.fan = (int(round(self.fan[0])),int(round(self.fan[1])),int(round(self.fan[2])))
bestDist = 2*9
bestMatrix = makeMatrix(0,0,0)
for compass in [0, 90, 180, 270]:
for pitch in [0, 90, 180, 270]:
for roll in [0, 90, 180, 270]:
m = makeMatrix(compass,pitch,roll)
dist = matrixDistanceSquared(self.matrix, m)
if dist < bestDist:
bestMatrix = m
bestDist = dist
self.matrix = bestMatrix
self.positionOut()
self.directionOut()
def drawLine(self, x1,y1,z1, x2,y2,z2):
def drawPoint(p, fast=False):
if self.pen:
if self.width == 1 and not self.fan:
self.mc.setBlock(p[0],p[1],p[2],self.block)
else:
for point in self.nib:
x0 = p[0]+point[0]
y0 = p[1]+point[1]
z0 = p[2]+point[2]
if (x0,y0,z0) not in done:
self.mc.setBlock(x0,y0,z0,self.block)
done.add((x0,y0,z0))
if not fast and self.delayTime > 0:
self.position.x = p[0]
self.position.y = p[1]
self.position.z = p[2]
self.positionOut()
self.delay()
if not self.pen and self.delayTime == 0:
return
# dictinary to avoid duplicate drawing
done = set()
if self.pen and self.fan:
if self.delayTime > 0:
for a in getLine(x1,y1,z1, x2,y2,z2):
drawPoint(a)
triangle = getTriangle(self.fan, (x1,y1,z1), (x2,y2,z2))
for a in triangle:
drawPoint(a, True)
else:
for a in getLine(x1,y1,z1, x2,y2,z2):
drawPoint(a)
if __name__ == "__main__":
t = Turtle()
for i in range(7):
t.back(80)
t.right(180-180./7)
t.turtle(None)

View File

@ -0,0 +1,58 @@
#
# Code under the MIT license by Alexander Pruss
#
# mengersponge [levels [options]]
# levels is a level count, up to 5
# options is a string of characters containing possibly the options 's' for 'slice' (cut off a diagonal slice) and 'c' for 'color'
#
from mc import *
import mcpi.settings as settings
import sys
RAINBOW = (STAINED_GLASS_RED,STAINED_GLASS_ORANGE,STAINED_GLASS_YELLOW,STAINED_GLASS_GREEN,STAINED_GLASS_BLUE,STAINED_GLASS_PURPLE)
def deleteCubes(x0,y0,z0,length,colorIndex=None):
nextColorIndex = colorIndex + 1 if colorIndex is not None else None
length /= 3
if length < 1:
return
for x in range(3):
for y in range(3):
for z in range(3):
posX = x0+x*length
posY = y0+y*length
posZ = z0+z*length
if (x == 1 and y == 1) or (x == 1 and z == 1) or (y == 1 and z == 1):
if colorIndex is not None:
mc.setBlocks(posX,posY,posZ,
posX+length-1,posY+length-1,posZ+length-1,RAINBOW[colorIndex])
else:
mc.setBlocks(posX,posY,posZ,
posX+length-1,posY+length-1,posZ+length-1,AIR)
else:
deleteCubes(posX,posY,posZ,length,nextColorIndex)
def slice(x0,y0,z0,length):
for x in range(0,length):
for y in range(0,length):
for z in range(0,length):
if x+y+z >= 1.5*length:
mc.setBlock(x0+x,y0+y,z0+z,AIR)
mc = Minecraft()
playerPos = mc.player.getPos()
if settings.isPE:
length = 3*3*3
else:
length = 3*3*3*3
if len(sys.argv) > 1:
length = 3**int(sys.argv[1])
colorIndex = None
if len(sys.argv) > 2:
colorIndex = 0 if 'c' in sys.argv[2] else None
mc.setBlocks(playerPos.x,playerPos.y,playerPos.z,
playerPos.x+length-1,playerPos.y+length-1,playerPos.z+length-1,WOOL_PURPLE)
deleteCubes(playerPos.x,playerPos.y,playerPos.z,length,colorIndex=colorIndex)
if len(sys.argv)>2 and 's' in sys.argv[2]:
mc.postToChat("Slicing")
slice(playerPos.x,playerPos.y,playerPos.z,length)

View File

@ -0,0 +1,41 @@
#
# Code under the MIT license by Alexander Pruss
#
from mc import *
import sys
def draw_surface(xf,yf,zf,a0,a1,asteps,b0,b1,bsteps,ox,oy,oz,scalex,scaley,scalez,mcblock,mcmeta):
cfx = compile(xf,'<string>','eval')
cfy = compile(yf,'<string>','eval')
cfz = compile(zf,'<string>','eval')
for i in xrange(asteps):
a = (a0 * (asteps-1-i) + a1 * i) / asteps
for j in xrange(bsteps):
b = (b0 * (bsteps-1-j) + b1 * j) / bsteps
x = eval(cfx)
y = eval(cfy)
z = eval(cfz)
# print a,b,ox+x * scalex, oy+y * scaley, oz+z * scalez
mc.setBlock(ox+x * scalex, oy+y * scaley, oz+z * scalez, mcblock, mcmeta)
mc = Minecraft()
playerPos = mc.player.getPos()
xformula = '(3 + a * cos(b/2)) * cos(b)'
yformula = 'a * sin(b/2)'
zformula = '(3 + a * cos(b/2)) * sin(b)'
scale = 15
b = STONE
m = 0
if (len(sys.argv)>1):
b = int(sys.argv[1])
if (len(sys.argv)>2):
m = int(sys.argv[2])
draw_surface(xformula,yformula,zformula,-1.,1.,10*scale,0,2*pi,30*scale,playerPos.x,playerPos.y+scale,playerPos.z,scale,scale,scale,b, m)
mc.postToChat("Formula done")

View File

@ -0,0 +1,78 @@
file 1701d.obj
swapyz 0
urlgz https://raw.githubusercontent.com/arpruss/raspberryjammod/master/models/1701d.obj.gz
size 200
default QUARTZ_BLOCK
order entdnacelle -1
order phaserstrips 1
order bluethingies 1
order warpblue 1
credits Enterprise-D by David Metlesits. Not for profit. Star Trek is copyright Paramount Pictures.
materials
boosters default
phaserstrips SEA_LANTERN
entdsaucbot default
grey WOOL_LIGHT_GRAY
entdhangarmod default
lum GLOWSTONE_BLOCK
entdbasichull default
thrusters default
coil default
entdnacelle default
warpblue SEA_LANTERN
Material__21 default
winoff default
bluethingies SEA_LANTERN
defring default
impulseengines default
entdstripes default
redmarkings WOOL_RED
blackmarkings WOOL_BLACK
greenlight default
redlight default
whitelight default
Material__22 default
entdsauctop default
yellowlet default
windows default
entdmainhulltop default
lifeboats default
entdmainhullbot default
end
Copyright information:
Non-commercial use only.
Star Trek (including but not limited to Star Trek: Deep Space Nine, Star Trek:
The Next Generation, Star Trek: Voyager, Star Trek: Enterprise), and the
various logo devices used in them, are copyright Paramount Pictures, as are the
characters, related images, and sound from the productions. None of these web
pages are either endorsed or supported by Paramount Pictures. Star Trek (
including but not limited to Star Trek: Deep Space Nine, Star Trek: The Next
Generation, Star Trek: Voyager, Star Trek: Enterprise), and the various logo
devices used in them, are copyright Paramount Pictures, as are the characters,
related images, and sound from the productions. None of these web pages are
either endorsed or supported by Paramount Pictures.
Mesh converted by Alexander Pruss from 3DS MAX mesh:
http://www.trekmeshes.ch/meshes/meshesdetails.php?Name=1701DMETLESITS
--Information from original mesh--
USS ENTERPRISE NCC-1701-D
Galaxy class starship, under the command of Jean-Luc Picard.
Conditions of use:
Please put credits on the images made with this mesh, something like "Enterprise-D by David Metlesits", or similar.
You may use this mesh for any non-profit work.
You may edit, kitbash or do anything with this mesh. Just have fun with it :D
Live long and prosper!
David "KnightRider" Metlesits

View File

@ -0,0 +1 @@
See copyright and credits for the meshes in the individual txt files.

View File

@ -0,0 +1,49 @@
file City_Ground-Notts.obj
url https://raw.githubusercontent.com/martinohanlon/minecraft-renderObj/master/City_Ground-Notts.obj
credits Downloaded from Martin O'Hanlon's repository
size 200
default DIRT
materials
Default_Material STONE.id
Black WOOL.id 15
Asphalt_Old WOOL.id 7
GhostWhite WOOL
Brick_Flemish_Bond BRICK_BLOCK
Concrete_Brushed STONE.id
Metal_Brushed IRON_BLOCK
Roofing_Metal_Standing_Seam_Blue WOOL.id 8
White WOOL
Metal_Brushed1 IRON_BLOCK
Rouge3141 WOOL.id 14
roof WOOL.id 8
Metal_Aluminum_Anodized IRON_BLOCK
Translucent_Glass_Safety GLASS.id
Translucent_Glass_Safety1 GLASS.id
Safety_Glass2 GLASS.id
Red WOOL.id 14
goal_net1 WOOL
Black WOOL.id 15
end
I do not know the credits for the .obj original mesh.
License for material selection only:
Copyright (c) Martin O'Hanlon
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,60 @@
obj NY_LIL.obj
url https://raw.githubusercontent.com/martinohanlon/minecraft-renderObj/master/NY_LIL.obj
credits Downloaded from Martin O'Hanlon's repository
swapyz 0
size 200
default IRON_BLOCK
materials
Default_Material WOOL.id 0
Color_A01 WOOL.id 14
0131_Silver IRON_BLOCK
0075_ForestGreen WOOL.id 13
0137_Black WOOL.id 15
Black WOOL.id 15
Medium_Brown WOOL.id 12
0056_Yellow WOOL.id 4
0020_Red WOOL.id 14
0102_RoyalBlue WOOL.id 11
Color_E01 WOOL.id 4
Color_E02 WOOL.id 4
Color_B01 WOOL.id 1
Charcoal WOOL.id 7
Material2 WOOL.id 0
Beige2 SANDSTONE
DarkGoldenrod GOLD_BLOCK
Beige1 SANDSTONE
jean_blue WOOL.id 3
Gold1 GOLD_BLOCK
WhiteSmoke WOOL.id 8
0118_Thistle WOOL.id 6
Color_D23 WOOL.id 7
Color_B23 WOOL.id 12
Color_009 WOOL.id 15
Color_D01 WOOL.id 1
Color_A06 WOOL.id 14
Color_D03 WOOL.id 4
0063_GreenYellow WOOL.id 5
end
I do not know the credits for the .obj original mesh.
License for material selection only:
Copyright (c) Martin O'Hanlon
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,51 @@
file RaspberryPi.obj
swapyz 0
size 100
default DIRT
url https://raw.githubusercontent.com/martinohanlon/minecraft-renderObj/master/RaspberryPi.obj
credits Downloaded from Martin O'Hanlon's repository
materials
Default_Material WOOL.id 0
Material1 WOOL.id 5
Goldenrod WOOL.id 1
0136_Charcoal WOOL.id 7
Gray61 WOOL.id 7
Charcoal WOOL.id 7
Color_002 WOOL.id 8
Color_008 WOOL.id 4
Plastic_Green WOOL.id 5
MB_Pastic_White WOOL.id 0
IO_Shiny IRON_BLOCK
Material4 GRASS
Gainsboro3 WOOL.id 5
CorrogateShiny1 IRON_BLOCK
Gold GOLD_BLOCK
0129_WhiteSmoke WOOL
Color_005 WOOL
USB_IO WOOL.id 11
_Metal IRON_BLOCK
0132_LightGray WOOL.id 8
end
I do not know the credits for the .obj original mesh.
License for material selection only:
Copyright (c) Martin O'Hanlon
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,12 @@
file 'atat.obj'
urlgz https://raw.githubusercontent.com/arpruss/raspberryjammod/master/models/atat.obj.gz
swapyz 0
credits Brad Blackburn <fatjack@mac.com>. Downloaded from scifi3d.com. Star Wars is copyright (c) Lucasfilm. Noncommercial use only.
yaw 90
size 100
default STONE
#order material position
materials
New.2 default
New.1 default
end

View File

@ -0,0 +1,90 @@
file 'bop.3ds'
swapyz 1
credits Klingon Bird of Prey by William Burningham, 3DS conversion by Erik Timmermans. trekmeshes.ch. Star Trek is copyright Paramount Pictures. Non-commercial use only.
urlgz https://raw.githubusercontent.com/arpruss/raspberryjammod/master/models/bop.3ds.gz
yaw 180
pitch 0
roll 0
size 100
default WOOL_GREEN
order photon-red 1
order photon-red2 1
order marker-light_#2 1
order wht-light_#2 1
order marker-light 1
order red-glow 1
order red-windo-glow 1
order red-window 1
order wht-light 1
order yellow-glow 1
materials
inner-cooler-2_# default
radiator1_#2 default
radiator2_#2 default
Metal2_#4 default
bop-green_#4 default
bop-green3_#4 default
bop-green4_#4 default
bop-green5_#4 default
metal3_#4 default
photon-red STAINED_GLASS_RED
photon-red2 STAINED_GLASS_RED
rust_#4 default
BOP-flat-red WOOL_RED
BOP-flat-red1 WOOL_RED
Metal2_#3 default
bop-cut default
bop-green_#3 default
bop-green2_#3 default
bop-green3_#3 default
bop-green4_#3 default
bop-green5_#3 default
cut-2 default
gun-metal_#3 IRON_BLOCK
inner-cooler-2 default
inner-cooler1 default
inner-cooler3 default
metal3_#3 IRON_BLOCK
radiator1 default
radiator2 default
red-glow_#2 default
rust_#3 default
vent-grey IRON_BLOCK
wing-rear-edge default
Metal2_#2 IRON_BLOCK
black WOOL_BLACK
bop-green_#2 default
bop-green2_#2 default
bop-green3_#2 default
bop-green4_#2 default
bop-green5_#2 default
gun-metal_#2 default
marker-light_#2 SEA_LANTERN
metal3_#2 IRON_BLOCK
rust_#2 default
wht-light_#2 SEA_LANTERN
Metal2 IRON_BLOCK
bop-green default
bop-green2 default
bop-green3 default
bop-green4 default
bop-green5 default
flat-blk default
gun-metal IRON_BLOCK
gunshipgry IRON_BLOCK
gunshipgry2 IRON_BLOCK
lt-grey IRON_BLOCK
marker-light SEA_LANTERN
metal3 default
red-glow STAINED_GLASS_RED
red-windo-glow STAINED_GLASS_RED
red-window STAINED_GLASS_RED
rust default
sidegrn default
sidegrncut default
wht-light SEA_LANTERN
yellow-glow STAINED_GLASS_YELLOW
end
[Insert any detailed licensing information here]

View File

@ -0,0 +1,13 @@
file cessna.obj
size 100
url https://raw.githubusercontent.com/martinohanlon/minecraft-renderObj/master/cessna.obj
credits Downloaded from Martin O'Hanlon's repository
default IRON_BLOCK
materials
yellow WOOL_YELLOW
red WOOL_RED
white WOOL_WHITE
black WOOL_BLACK
glass GLASS
dkgrey WOOL_GRAY

View File

@ -0,0 +1,4 @@
file cube.obj
size 50
url https://raw.githubusercontent.com/martinohanlon/minecraft-renderObj/master/cube.obj
credits Downloaded from Martin O'Hanlon's repository

View File

@ -0,0 +1,10 @@
file 'dragon.ply'
urlgz http://www.cc.gatech.edu/data_files/large_models/dragon.ply.gz
swapyz 0
credits Mesh from Georgia Tech's Website (based on Stanford's scan)
yaw 0
pitch 0
roll 0
size 100
default REDSTONE_BLOCK
end

View File

@ -0,0 +1,116 @@
file ds9.obj
urlgz https://raw.githubusercontent.com/arpruss/raspberryjammod/master/models/ds9.obj.gz
swapyz 0
size 200
default STONE
credits Star Trek is copyright Paramount Pictures; mesh is by Joerg Gerlach
materials
Yellow_self_illum GLOWSTONE_BLOCK
Lamps SEA_LANTERN
Windows GLASS
Phaser REDSTONE_BLOCK
Antenna 173
Round_Neck default
Pylon_inside default
Pylon_Side default
Round_Inside default
Pylon_Neck_outside default
Outer_Ring_Fill default
Outer_Ring_inside default
Outer_Ring_upper default
Outer_Ring_lower default
Habitat_upper_part default
Habitat_lower_part default
Habitat_side default
Connect default
ConnectIn default
Bridge default
Klammer default
Outside_Core default
Core_House_lower_p default
Core_House_upper_p default
Inside_Core default
OPS_upper_part default
OPS default
end
Copyright information:
Non-commercial use only.
Star Trek (including but not limited to Star Trek: Deep Space Nine, Star Trek:
The Next Generation, Star Trek: Voyager, Star Trek: Enterprise), and the
various logo devices used in them, are copyright Paramount Pictures, as are the
characters, related images, and sound from the productions. None of these web
pages are either endorsed or supported by Paramount Pictures.Star Trek (
including but not limited to Star Trek: Deep Space Nine, Star Trek: The Next
Generation, Star Trek: Voyager, Star Trek: Enterprise), and the various logo
devices used in them, are copyright Paramount Pictures, as are the characters,
related images, and sound from the productions. None of these web pages are
either endorsed or supported by Paramount Pictures.
Mesh converted by Alexander Pruss from 3DS MAX mesh at http://www.trekmeshes.ch/
(Probably: http://www.trekmeshes.ch/meshes/meshesdetails.php?Name=JORGDS9)
--Information from original mesh--
README.TXT for the mesh of Deep Space 9 by Joerg Gerlach
--------------------------------------------------------
Thank you for downloading this big monster file. I´m sorry about the size,
but I wasn´t able to reduce the file size any more. Every single object is
collapsed, but any more face count optimization wasn´t possible without
a decrease of smoothness. I use this mesh and all its textures on the
following system (I recommend a much better system!):
Intel Pentium 150
96 MB RAM
200 MB swap disk
WinNT4 Workstation Servicepack 5
Rendering time 640x480 (including DS9, Noise starfield background, RLF Pro Glows): 10 mins
The MAX file contains also some helper objects representing the glows used
by RealLensFlare Pro. If you don´t use RLF Pro or if you don´t have it
you can delete them without problems. If you want to use my glow settings feel
free to do so.
Usage of different textures:
----------------------------
Although this mesh looks exactly the same as the first release of my DS9 I divided
several objects into different parts for texturing. So you aren´t able to use all
my textures with the old mesh. If you want to use either the grey or the brown texture
version you only have to change the bitmap paths in MAX. The grey and brown versions
are using the same file names, so be sure to copy them into different folders. To activate
the different color versions disable one bitmap path and enable the other path using
the File/Configure Paths.../Bitmaps command in MAX. That´s all. You don´t have to
change anything on the mesh or the texture settings. It´s that simple...:-)
I hope you have that fun with the mesh I have...
Bye
Joerg
-----
Copyright Info
--------------
Original design and name copyright by Paramount Communications/Viacom.
Original design and name copyright by Paramount Communications/Viacom.
Mesh and texture copyright by Joerg Gerlach 1999.
Distribution of the mesh or the textures only with this README.TXT included.
All contents of this zip file copyrighted under german law.
You are allowed to change, rework or reassemble the mesh or the textures if you
include a copyright link to Joerg Gerlach, Germany 1999.
ANY commercial use is NOT allowed!!!
Joerg Gerlach
jger@01019freenet.de
http://www.tu-chemnitz.de/~jger
Member of the WolfPak359
http://www.wolfpak359.co.uk

View File

@ -0,0 +1,6 @@
file head.obj
url https://raw.githubusercontent.com/martinohanlon/minecraft-renderObj/master/head.obj
credits Downloaded from Martin O'Hanlon's repository
swapyz 0
size 50
default GOLD_BLOCK

View File

@ -0,0 +1,3 @@
file humanoid_quad.obj
url https://raw.githubusercontent.com/martinohanlon/minecraft-renderObj/master/humanoid_quad.obj
credits Downloaded from Martin O'Hanlon's repository

View File

@ -0,0 +1,25 @@
file 'jemcruiser.3ds'
urlgz https://raw.githubusercontent.com/arpruss/raspberryjammod/master/models/jemcruiser.3ds.gz
swapyz 1
credits Jemhadar Cruiser by William Burningham, 3DS conversion by Erik Timmermans. trekmeshes.ch. Star Trek is copyright Paramount Pictures. Non-commercial use only.
yaw 180
pitch 0
roll 0
size 100
default WOOL_PURPLE
order jh-blue-glow 1
order blue-glow 1
order blue-glow-rear 1
materials
jem'hadar-black WOOL_BLACK
jem'hadar-drk WOOL_GRAY
jem'hadar-grey1 WOOL_GRAY
jem'hadar1 default
jem'hadar2 default
jem'hadar3 default
jh-blue-glow SEA_LANTERN
blue-glow SEA_LANTERN
blue-glow-rear SEA_LANTERN
end
[Insert any detailed licensing information here]

View File

@ -0,0 +1,54 @@
file 'neghvar.3ds'
swapyz 1
credits Klingon Negh'Var Flagship by William Burningham, 3DS conversion by Erik Timmermans. trekmeshes.ch. Star Trek is copyright Paramount Pictures. Non-commercial use only.
urlgz https://raw.githubusercontent.com/arpruss/raspberryjammod/master/models/neghvar.3ds.gz
yaw 180
pitch 0
roll 0
size 100
default WOOL_GREEN
order red-glow 1
order warp-glow 1
order window 1
order flat-yelow 1
materials
default#1 default
metal2 IRON_BLOCK
negh'bar1 default
negh'bar2 default
negh'bar3 default
negh'bar4 default
negh'bar5 default
negh'bar6 default
dullred default
flat-black WOOL_BLACK
flat-yelow WOOL_YELLOW
grey1 IRON_BLOCK
gun-metal IRON_BLOCK
main-hull default
marker-light SEA_LANTERN
metal3 IRON_BLOCK
raised default
red-glow STAINED_GLASS_RED
warp-glow STAINED_GLASS_RED
window SEA_LANTERN
end
Mesh history:
Klingon Negh'Var LWO object by William Burningham. (http://www.burninghamstudios.com)
Conversion from LWO to MAX by Erik Timmermans
Texture conversion by Admiral Corrigan <> David Bishop
Conversion to 3DS by Erik Timmermans
You can get the textures for this mesh at the Star Trek Meshes Collection (http://trekmeshes.starfleet.ch)
You'll have to rename shinimap2.jpg to shinimap.jpg
Please credit the original author (William Burningham) and preferably David Bishop as well when you use this mesh.
Erik Timmermans
The Star Trek Meshes collection

View File

@ -0,0 +1,9 @@
file stardestroyer.obj
#urlgz https://raw.githubusercontent.com/arpruss/raspberryjammod/master/models/ds9.obj.gz
swapyz 0
size 200
default WOOL_RED
credits Model and Maps by Alex Lukachuk chimaera@club-internet.fr. Source: scifi3d.com. Star Wars is copyright (c) Lucasfilm. Noncommercial use only.
materials
end

View File

@ -0,0 +1,38 @@
file shuttle.obj
url https://raw.githubusercontent.com/martinohanlon/minecraft-renderObj/master/shuttle.obj
credits Downloaded from Martin O'Hanlon's repository
swapyz 1
size 100
default WOOL
materials
glass GLASS
bone WOOL
fldkdkgrey WOOL.id 7
redbrick WOOL.id 14
black WOOL.id 15
brass WOOL.id 1
dkdkgrey WOOL.id 7
end
I do not know the credits for the .obj original mesh.
License for material selection only:
Copyright (c) Martin O'Hanlon
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,6 @@
file skyscraper.obj
url https://raw.githubusercontent.com/martinohanlon/minecraft-renderObj/master/skyscraper.obj
credits Downloaded from Martin O'Hanlon's repository
swapyz 0
size 100
default IRON_BLOCK

View File

@ -0,0 +1,65 @@
file stardestroyer.obj
urlgz https://raw.githubusercontent.com/arpruss/raspberryjammod/master/models/stardestroyer.obj.gz
swapyz 0
size 200
default IRON_BLOCK
credits Model and Maps by Alex Lukachuk chimaera@club-internet.fr. Source: scifi3d.com. Star Wars is copyright (c) Lucasfilm. Noncommercial use only.
materials
sml_lights default
wire_213154229 default
wire_008061138 default
wire_088177026 default
wire_108008136 default
wire_006134113 default
wire_153228153 default
wire_006134006 default
wire_176026026 default
wire_008008136 default
Material__1 default
wire_087224143 default
sml_lights_3 default
wire_087224198 default
wire_088088225 default
wire_214228153 default
wire_166229229 default
Lights_1a default
wire_154154229 default
wire_229166215 default
wire_224198087 default
sml_lights_2 default
wire_177028149 default
wire_061134006 default
wire_006134058 default
wire_177148026 default
wire_196088225 default
wire_229154215 default
wire_153228214 default
wire_028149177 default
wire_224086086 default
wire_057008136 default
wire_134059008 default
wire_177088026 default
wire_228153184 default
wire_148177026 default
wire_198224087 default
wire_138008110 default
wire_228214153 default
wire_134110008 default
wire_088143225 default
wire_227152152 default
wire_026177148 default
wire_177026088 default
wire_000169000 default
wire_028028177 default
wire_134006006 default
wire_154185229 default
wire_255000112 default
wire_141007058 default
wire_228184153 default
wire_153228184 default
wire_236255169 default
wire_000083055 default
wire_255255169 default
wire_169000000 default
end

View File

@ -0,0 +1,30 @@
file 'yt1300.3ds'
swapyz 1
credits Model by MOJO courtesy of ROBOTFARM and scifi3d.com. Star Wars is copyright (c) Lucasfilm. Non-commercial use only.
urlgz https://raw.githubusercontent.com/arpruss/raspberryjammod/master/models/yt1300.3ds.gz
yaw 180
pitch 0
roll 0
size 100
default STONE
order LIGHTS 2
order GLASS 1
materials
LIGHTS SEA_LANTERN
Default default
HULL default
SOLAR_PANALS default
GUN default
GLASS GLASS
radar default
Material_#13 default
detail1 default
end
Star Wars is copyright (c) Lucasfilm. Non-commercial use only.
Model courtesy of ROBOTFARM
http://www.robotfarm.de/launch.html
See the site for additional info.
Main author of meshes: MOJO
Downloaded from scifi3d.com

View File

@ -0,0 +1,52 @@
#
# Code under the MIT license by Alexander Pruss
#
from mc import *
import sys
import time
from NeuroPy.NeuroPy import NeuroPy
mc = Minecraft()
#
# the True argument is needed for a BrainFlex unit hacked to work
# at 57600 using
# http://www.instructables.com/id/Mindflex-EEG-with-raw-data-over-Bluetooth/
#
eeg = NeuroPy("COM11",57600,True)
meditation = len(sys.argv) > 1 and sys.argv[1].startswith("m")
up = 60
down = 40
def callback(a):
mc.postToChat(a)
if a > up:
pos = mc.player.getPos()
pos.y = pos.y + 1
if mc.getBlock(pos.x,pos.y,pos.z) == AIR.id:
mc.player.setPos(pos)
elif a < down:
pos = mc.player.getPos()
pos.y = pos.y - 1
if mc.getBlock(pos.x,pos.y,pos.z) == AIR.id:
mc.player.setPos(pos)
if meditation:
eeg.setCallBack("meditation", callback)
else:
eeg.setCallBack("attention", callback)
mc.postToChat("Connecting to EEG")
eeg.start()
if meditation:
mc.postToChat("To fly up, be meditative")
else:
mc.postToChat("To fly up, be attentive")
while True:
time.sleep(10)

View File

@ -0,0 +1,24 @@
#!/usr/bin/env python
# mcpipy.com retrieved from URL below, written by Jason Milldrum, NT7S
# http://www.nt7s.com/blog/2013/02/exploring-minecraft-pi-edition/
import mcpi.minecraft as minecraft
import mcpi.block as block
import server
mc = minecraft.Minecraft.create(server.address)
radius = 8
mc.postToChat("Hello, here's your sphere")
playerPos = mc.player.getPos()
for x in range(radius*-1,radius):
for y in range(radius*-1, radius):
for z in range(radius*-1,radius):
if x**2 + y**2 + z**2 < radius**2:
mc.setBlock(playerPos.x + x, playerPos.y + y + radius, playerPos.z - z - 10, block.GLASS)

View File

@ -0,0 +1,86 @@
#!/usr/bin/env python
import mcpi.minecraft as minecraft
import mcpi.block as block
import time
import server
#Author: Obsidz
#
#Description: This is a teleport pad script.
# To create a pad, place a nether reactor core onto a location and ring with cobbledtone blocks
# To add to locations list walk over it
#
#Notes: Pads added to list by walking over them
# Pads not removed if destroyed but can be teleported to but not from
# You cannot teleport to the same pad without modifying script
# Pads need to be added each time the script is run
# modified version - as shared on mcpipy.com
# original post @ http://www.minecraftforum.net/topic/1691618-teleportation-python-script/
LPLoc = list()
Pads = 0
Cpad = 0
# If you are running this script with the bukkit mod, then use a diamond block as the magic center block for teleporting
# comment/uncomment below as appropriate
magic_block = block.DIAMOND_BLOCK.id # for bukkit server
#magic_block = block.NETHER_REACTOR_CORE.id # for raspberry pi
def isLaunchPad(): #checks if the the location below the player is a teleporting pad
loc = mc.player.getPos()
if ((mc.getBlock(loc.x,loc.y-1,loc.z) == magic_block) and
(mc.getBlock(loc.x-1,loc.y-1,loc.z-1) == block.COBBLESTONE.id) and
(mc.getBlock(loc.x-1,loc.y-1,loc.z) == block.COBBLESTONE.id) and
(mc.getBlock(loc.x-1,loc.y-1,loc.z+1) == block.COBBLESTONE.id) and
(mc.getBlock(loc.x,loc.y-1,loc.z+1) == block.COBBLESTONE.id) and
(mc.getBlock(loc.x,loc.y-1,loc.z-1) == block.COBBLESTONE.id) and
(mc.getBlock(loc.x+1,loc.y-1,loc.z-1) == block.COBBLESTONE.id) and
(mc.getBlock(loc.x+1,loc.y-1,loc.z) == block.COBBLESTONE.id) and
(mc.getBlock(loc.x+1,loc.y-1,loc.z+1) == block.COBBLESTONE.id)):
addLPLoc(loc)
return True
else:
return False
def addLPLoc(Vec3): #Loggs the location of the pad for future use
global Pads
global LPLoc
inList = False
if Pads > 0:
for loc in LPLoc:
if (loc.x == Vec3.x and loc.y == Vec3.y and loc.z == Vec3.z):
inList = True
if not inList:
LPLoc.append(Vec3)
mc.postToChat("I'll remember this pad location!")
Pads = len(LPLoc)
def locCheck(): #Checks that you are not teleporting to the same pad
global Cpad
global LPLoc
loc = mc.player.getPos()
if (loc.x == LPLoc[Cpad].x and loc.y == LPLoc[Cpad].y and loc.z == LPLoc[Cpad].z):
Cpad = Cpad + 1
def TPChar(): #sends the character to the next pad
global Pads
global Cpad
global LPLoc
if Pads > 1:
mc.player.setPos(LPLoc[Cpad].x,LPLoc[Cpad].y + 1,LPLoc[Cpad].z)
Cpad = ( Cpad + 1) % Pads
time.sleep(3.0)
if __name__ == "__main__": # The script
mc = minecraft.Minecraft.create(server.address)
while True:
if isLaunchPad():
TPChar()
time.sleep(0.1)

View File

@ -0,0 +1,757 @@
#The software in this file is copyright 2003,2004 Simon Tatham and copyright 2015 Alexander Pruss
#Based on code from http://www.chiark.greenend.org.uk/~sgtatham/polyhedra/
#
#Permission is hereby granted, free of charge, to any person
#obtaining a copy of this software and associated documentation files
#(the "Software"), to deal in the Software without restriction,
#including without limitation the rights to use, copy, modify, merge,
#publish, distribute, sublicense, and/or sell copies of the Software,
#and to permit persons to whom the Software is furnished to do so,
#subject to the following conditions:
#
#The above copyright notice and this permission notice shall be
#included in all copies or substantial portions of the Software.
#
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
#EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
#MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
#NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE
#FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
#CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
#WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
from math import pi, asin, atan2, cos, sin, sqrt
import string
import random
import drawing
import sys
# Python code to find the crossing point of two lines.
# This function is optimised for big-integer or FP arithmetic: it
# multiplies up to find two big numbers, and then divides them. So
# if you use it on integers it will give the most accurate answer
# it possibly can within integers, but might overflow if you don't
# use longs. I haven't carefully analysed the FP properties, but I
# can't see it going _too_ far wrong.
#
# Of course there's no reason you can't feed it rationals if you
# happen to have a Rational class. It only does adds, subtracts,
# multiplies, divides and tests of equality on its arguments, so
# any data type supporting those would be fine.
def crosspoint(xa1,ya1,xa2,ya2,xb1,yb1,xb2,yb2):
"Give the intersection point of the (possibly extrapolated) lines\n"\
"segments (xa1,ya1)-(xa2,ya2) and (xb1,yb1)-(xb2,yb2)."
dxa = xa2-xa1
dya = ya2-ya1
dxb = xb2-xb1
dyb = yb2-yb1
# Special case: if gradients are equal, die.
if dya * dxb == dxa * dyb:
return None
# Second special case: if either gradient is horizontal or
# vertical.
if dxa == 0:
# Because we've already dealt with the parallel case, dxb
# is now known to be nonzero. So we can simply extrapolate
# along the b line until it hits the common value xa1==xa2.
return (xa1, (xa1 - xb1) * dyb / dxb + yb1)
# Similar cases for dya == 0, dxb == 0 and dyb == 0.
if dxb == 0:
return (xb1, (xb1 - xa1) * dya / dxa + ya1)
if dya == 0:
return ((ya1 - yb1) * dxb / dyb + xb1, ya1)
if dyb == 0:
return ((yb1 - ya1) * dxa / dya + xa1, yb1)
# General case: all four gradient components are nonzero. In
# this case, we have
#
# y - ya1 dya y - yb1 dyb
# ------- = --- and ------- = ---
# x - xa1 dxa x - xb1 dxb
#
# We rewrite these equations as
#
# y = ya1 + dya (x - xa1) / dxa
# y = yb1 + dyb (x - xb1) / dxb
#
# and equate the RHSes of each
#
# ya1 + dya (x - xa1) / dxa = yb1 + dyb (x - xb1) / dxb
# => ya1 dxa dxb + dya dxb (x - xa1) = yb1 dxb dxa + dyb dxa (x - xb1)
# => (dya dxb - dyb dxa) x =
# dxb dxa (yb1 - ya1) + dya dxb xa1 - dyb dxa xb1
#
# So we have a formula for x
#
# dxb dxa (yb1 - ya1) + dya dxb xa1 - dyb dxa xb1
# x = -----------------------------------------------
# dya dxb - dyb dxa
#
# and by a similar derivation we also obtain a formula for y
#
# dya dyb (xa1 - xb1) + dxb dya yb1 - dxa dyb ya1
# y = -----------------------------------------------
# dya dxb - dyb dxa
det = dya * dxb - dyb * dxa
xtop = dxb * dxa * (yb1-ya1) + dya * dxb * xa1 - dyb * dxa * xb1
ytop = dya * dyb * (xa1-xb1) + dxb * dya * yb1 - dxa * dyb * ya1
return (xtop / det, ytop / det)
def makePoints(n):
points = []
for i in range(n):
# Invent a randomly distributed point.
#
# To distribute points uniformly over a spherical surface, the
# easiest thing is to invent its location in polar coordinates.
# Obviously theta (longitude) must be chosen uniformly from
# [0,2*pi]; phi (latitude) must be chosen in such a way that
# the probability of falling within any given band of latitudes
# must be proportional to the total surface area within that
# band. In other words, the probability _density_ function at
# any value of phi must be proportional to the circumference of
# the circle around the sphere at that latitude. This in turn
# is proportional to the radius out from the sphere at that
# latitude, i.e. cos(phi). Hence the cumulative probability
# should be proportional to the integral of that, i.e. sin(phi)
# - and since we know the cumulative probability needs to be
# zero at -pi/2 and 1 at +pi/2, this tells us it has to be
# (1+sin(phi))/2.
#
# Given an arbitrary cumulative probability function, we can
# select a number from the represented probability distribution
# by taking a uniform number in [0,1] and applying the inverse
# of the function. In this case, this means we take a number X
# in [0,1], scale and translate it to obtain 2X-1, and take the
# inverse sine. Conveniently, asin() does the Right Thing in
# that it maps [-1,+1] into [-pi/2,pi/2].
theta = random.random() * 2*pi
phi = asin(random.random() * 2 - 1)
points.append((cos(theta)*cos(phi), sin(theta)*cos(phi), sin(phi)))
# For the moment, my repulsion function will be simple
# inverse-square, followed by a normalisation step in which we pull
# each point back to the surface of the sphere.
while 1:
# Determine the total force acting on each point.
forces = []
for i in range(len(points)):
p = points[i]
f = (0,0,0)
ftotal = 0
for j in range(len(points)):
if j == i: continue
q = points[j]
# Find the distance vector, and its length.
dv = (p[0]-q[0], p[1]-q[1], p[2]-q[2])
dl = sqrt(dv[0]**2 + dv[1]**2 + dv[2]**2)
# The force vector is dv divided by dl^3. (We divide by
# dl once to make dv a unit vector, then by dl^2 to
# make its length correspond to the force.)
dl3 = dl ** 3
fv = (dv[0]/dl3, dv[1]/dl3, dv[2]/dl3)
# Add to the total force on the point p.
f = (f[0]+fv[0], f[1]+fv[1], f[2]+fv[2])
# Stick this in the forces array.
forces.append(f)
# Add to the running sum of the total forces/distances.
ftotal = ftotal + sqrt(f[0]**2 + f[1]**2 + f[2]**2)
# Scale the forces to ensure the points do not move too far in
# one go. Otherwise there will be chaotic jumping around and
# never any convergence.
if ftotal > 0.25:
fscale = 0.25 / ftotal
else:
fscale = 1
# Move each point, and normalise. While we do this, also track
# the distance each point ends up moving.
dist = 0
for i in range(len(points)):
p = points[i]
f = forces[i]
p2 = (p[0] + f[0]*fscale, p[1] + f[1]*fscale, p[2] + f[2]*fscale)
pl = sqrt(p2[0]**2 + p2[1]**2 + p2[2]**2)
p2 = (p2[0] / pl, p2[1] / pl, p2[2] / pl)
dv = (p[0]-p2[0], p[1]-p2[1], p[2]-p2[2])
dl = sqrt(dv[0]**2 + dv[1]**2 + dv[2]**2)
dist = dist + dl
points[i] = p2
# Done. Check for convergence and finish.
#sys.stderr.write(str(dist) + "\n")
if dist < 1e-6:
return points
def genFacesFace(points,x0,y0,z0,scale):
# Draw each face of the polyhedron.
#
# Originally this function produced a PostScript diagram of
# each plane, showing the intersection lines with all the other
# planes, numbering which planes they were, and outlining the
# central polygon. This gives enough information to construct a
# net of the solid. However, it now seems more useful to output
# a 3D model of the polygon, but the PS output option is still
# available if required.
faces = []
vertices = {}
for i in range(len(points)):
x, y, z = points[i]
# Begin by rotating the point set so that this point
# appears at (0,0,1). To do this we must first find the
# point's polar coordinates...
theta = atan2(y, x)
phi = asin(z)
# ... and construct a matrix which first rotates by -theta
# about the z-axis, thus bringing the point to the
# meridian, and then rotates by pi/2-phi about the y-axis
# to bring the point to (0,0,1).
#
# That matrix is therefore
#
# ( cos(pi/2-phi) 0 -sin(pi/2-phi) ) ( cos(-theta) -sin(-theta) 0 )
# ( 0 1 0 ) ( sin(-theta) cos(-theta) 0 )
# ( sin(pi/2-phi) 0 cos(pi/2-phi) ) ( 0 0 1 )
#
# which comes to
#
# ( cos(theta)*sin(phi) sin(theta)*sin(phi) -cos(phi) )
# ( -sin(theta) cos(theta) 0 )
# ( cos(theta)*cos(phi) sin(theta)*cos(phi) sin(phi) )
matrix = [
[ cos(theta)*sin(phi), sin(theta)*sin(phi), -cos(phi) ],
[ -sin(theta) , cos(theta) , 0 ],
[ cos(theta)*cos(phi), sin(theta)*cos(phi), sin(phi) ]]
rpoints = []
for j in range(len(points)):
if j == i: continue
xa, ya, za = points[j]
xb = matrix[0][0] * xa + matrix[0][1] * ya + matrix[0][2] * za
yb = matrix[1][0] * xa + matrix[1][1] * ya + matrix[1][2] * za
zb = matrix[2][0] * xa + matrix[2][1] * ya + matrix[2][2] * za
rpoints.append((j, xb, yb, zb))
# Now. For each point in rpoints, we find the tangent plane
# to the sphere at that point, and find the line where it
# intersects the uppermost plane Z=1.
edges = []
for j, x, y, z in rpoints:
# The equation of the plane is xX + yY + zZ = 1.
# Combining this with the equation Z=1 is trivial, and
# yields the linear equation xX + yY = (1-z). Two
# obvious points on this line are those with X=0 and
# Y=0, which have coordinates (0,(1-z)/y) and
# ((1-z)/x,0).
if x == 0 or y == 0:
continue # this point must be diametrically opposite us
x1, y1 = 0, (1-z)/y
x2, y2 = (1-z)/x, 0
# Find the point of closest approach between this line
# and the origin. This is most easily done by returning
# to the original equation xX+yY=(1-z); this clearly
# shows the line to be perpendicular to the vector
# (x,y), and so the closest-approach point is where X
# and Y are in that ratio, i.e. X=kx and Y=ky. Thus
# kx^2+ky^2=(1-z), whence k = (1-z)/(x^2+y^2).
k = (1-z)/(x*x+y*y)
xx = k*x
yy = k*y
# Store details of this line.
edges.append((x1,y1, x2,y2, xx,yy, i, j))
# Find the intersection points of this line with the
# edges of the square [-2,2] x [-2,2].
xyl = crosspoint(x1, y1, x2, y2, -2, -2, -2, +2)
xyr = crosspoint(x1, y1, x2, y2, +2, -2, +2, +2)
xyu = crosspoint(x1, y1, x2, y2, -2, +2, +2, +2)
xyd = crosspoint(x1, y1, x2, y2, -2, -2, +2, -2)
# Throw out any which don't exist, or which are beyond
# the limits.
xys = []
for xy in [xyl, xyr, xyu, xyd]:
if xy == None: continue
if xy[0] < -2 or xy[0] > 2: continue
if xy[1] < -2 or xy[1] > 2: continue
xys.append(xy)
# The diagram we have just drawn is going to be a complex
# stellated thing, with many intersection lines shown that
# aren't part of the actual face of the polyhedron because
# they are beyond its edges. Now we narrow our focus to
# find the actual edges of the polygon.
# We begin by notionally growing a circle out from the
# centre point until it touches one of the lines. This line
# will be an edge of the polygon, and furthermore the point
# of contact will be _on_ the edge of the polygon. In other
# words, we pick the edge whose closest-approach point is
# the shortest distance from the origin.
best = None
n = None
for j in range(len(edges)):
xx,yy = edges[j][4:6]
d2 = xx * xx + yy * yy
if best == None or d2 < best:
best = d2
n = j
assert n != None
e = edges[n]
startn = n
# We choose to look anticlockwise along the edge. This
# means mapping the vector (xx,yy) into (-yy,xx).
v = (-e[5],e[4])
p = (e[4],e[5])
omit = -1 # to begin with we omit the intersection with no other edge
poly = []
while 1:
# Now we have an edge e, a point p on the edge, and a
# direction v in which to look along the edge. Examine
# this edge's intersection points with all other edges,
# and pick the one which is closest to p in the
# direction of v (discarding any which are _behind_ p).
xa1, ya1, xa2, ya2 = e[0:4]
best = None
n2 = None
xp = yp = None
for j in range(len(edges)):
if j == omit or j == n:
continue # ignore this one
xb1, yb1, xb2, yb2 = edges[j][0:4]
xcyc = crosspoint(xa1, ya1, xa2, ya2, xb1, yb1, xb2, yb2)
if xcyc == None:
continue # this edge is parallel to e
xc, yc = xcyc
dotprod = (xc - p[0]) * v[0] + (yc - p[1]) * v[1]
if dotprod < 0:
continue
if best == None or dotprod < best:
best = dotprod
n2 = j
xp, yp = xc, yc
assert n2 != None
# Found a definite corner of the polygon. Save its
# coordinates, and also save the numbers of the three
# planes at whose intersection the point lies.
poly.append((xp, yp, e[6], e[7], edges[n2][7]))
# Now move on. We must now look along the new edge.
e = edges[n2]
p = xp, yp # start looking from the corner we've found
omit = n # next time, ignore the corner we've just hit!
n = n2
# v is slightly tricky. We are moving anticlockwise
# around the polygon; so we first rotate the previous v
# 90 degrees left, and then we choose whichever
# direction along the new edge has a positive dot
# product with this vector.
vtmp = (-v[1], v[0])
v = (-e[5],e[4])
if v[0] * vtmp[0] + v[1] * vtmp[1] < 0:
v = (e[5], -e[4])
# Terminate the loop if we have returned to our
# starting edge.
if n == startn:
break
# Save everything we need to write out a 3D model later on.
# In particular this involves keeping the coordinates of
# the points, for which we will need to find the inverse of
# the rotation matrix so as to put the points back where
# they started.
#
# The inverse rotation matrix is
#
# ( cos(-theta) sin(-theta) 0 ) ( cos(pi/2-phi) 0 sin(pi/2-phi) )
# ( -sin(-theta) cos(-theta) 0 ) ( 0 1 0 )
# ( 0 0 1 ) ( -sin(pi/2-phi) 0 cos(pi/2-phi) )
#
# which comes to
#
# ( cos(theta)*sin(phi) -sin(theta) cos(theta)*cos(phi) )
# ( sin(theta)*sin(phi) cos(theta) sin(theta)*cos(phi) )
# ( -cos(phi) 0 sin(phi) )
imatrix = [
[ cos(theta)*sin(phi), -sin(theta), cos(theta)*cos(phi) ],
[ sin(theta)*sin(phi), cos(theta), sin(theta)*cos(phi) ],
[ -cos(phi) , 0 , sin(phi) ]]
facelist = []
for p in poly:
xa, ya = p[0:2]
za = 1
xb = imatrix[0][0] * xa + imatrix[0][1] * ya + imatrix[0][2] * za
yb = imatrix[1][0] * xa + imatrix[1][1] * ya + imatrix[1][2] * za
zb = imatrix[2][0] * xa + imatrix[2][1] * ya + imatrix[2][2] * za
planes = list(p[2:5])
planes.sort()
planes = tuple(planes)
if not vertices.has_key(planes):
vertices[planes] = []
vertices[planes].append((xb, yb, zb))
facelist.append(planes)
faces.append((i, facelist))
# Now output the polygon description.
#
# Each polygon has been prepared in its own frame of reference,
# so the absolute coordinates of the vertices will vary
# depending on which polygon they were prepared in. For this
# reason I have kept _every_ version of the coordinates of each
# vertex, so we can now average them into a single canonical value.
pointDict = {}
for key, value in vertices.items():
xt = yt = zt = n = 0
xxt = yyt = zzt = 0
for x, y, z in value:
xt = xt + x
yt = yt + y
zt = zt + z
xxt = xxt + x*x
yyt = yyt + y*y
zzt = zzt + z*z
n = n + 1
pointDict[key] = (x0+scale*xt/n, y0+scale*yt/n, z0+scale*zt/n)
faceList = []
for i, vlist in faces:
f = []
for key in vlist:
f.append(pointDict[key])
faceList.append(f)
return faceList
def genFacesVertex(points,x0,y0,z0,size):
n = len(points)
hulledges = {}
for i in range(n-1):
xi, yi, zi = points[i]
for j in range(i+1, n):
xj, yj, zj = points[j]
# We begin by rotating our frame of reference so that both
# points are in the x=0 plane, have the same z coordinate,
# and that z coordinate is positive. In other words, we
# rotate the sphere so that the radius bisecting the line
# between the two points is the vector (0,0,1), and then
# rotate around the z-axis so that the two points hit
# opposite sides of the x-y plane. We expect to end up with
# our two points being of the form (0,y,z) and (0,-y,z)
# with z > 0.
# Begin by rotating so that the midway point appears at
# (0,0,1). To do this we must first find the midway point
# and its polar coordinates...
mx = (xi + xj) / 2
my = (yi + yj) / 2
mz = (zi + zj) / 2
md = sqrt(mx**2 + my**2 + mz**2)
# Very silly special case here: md might be zero. This
# means that the midway point between the two points is the
# origin, i.e. the points are exactly diametrically
# opposite on the sphere. In this situation we can
# legitimately pick _any_ point on the great circle half
# way between them as a representative mid-way point; so
# we'll simply take an arbitrary vector perpendicular to
# point i.
if md == 0:
# We'll take the vector product of point i with some
# arbitrarily chosen vector which isn't parallel to it.
# I'll find the absolute-smallest of the three
# coordinates of i, and choose my arbitrary vector to
# be the corresponding basis vector.
if abs(mx) <= abs(my) and abs(mx) <= abs(mz):
mx, my, mz = 0, -zi, yi
elif abs(my) <= abs(mx) and abs(my) <= abs(mz):
mx, my, mz = zi, 0, -xi
else: # abs(mz) <= abs(mx) and abs(mz) <= abs(my)
mx, my, mz = -yi, xi, 0
# Now recompute the distance so we can normalise as
# before.
md = sqrt(mx**2 + my**2 + mz**2)
mx = mx / md
my = my / md
mz = mz / md
theta = atan2(my, mx)
phi = asin(mz)
# ... and construct a matrix which first rotates by -theta
# about the z-axis, thus bringing the point to the
# meridian, and then rotates by pi/2-phi about the y-axis
# to bring the point to (0,0,1).
#
# That matrix is therefore
#
# ( cos(pi/2-phi) 0 -sin(pi/2-phi) ) ( cos(-theta) -sin(-theta) 0 )
# ( 0 1 0 ) ( sin(-theta) cos(-theta) 0 )
# ( sin(pi/2-phi) 0 cos(pi/2-phi) ) ( 0 0 1 )
#
# which comes to
#
# ( cos(theta)*sin(phi) sin(theta)*sin(phi) -cos(phi) )
# ( -sin(theta) cos(theta) 0 )
# ( cos(theta)*cos(phi) sin(theta)*cos(phi) sin(phi) )
matrix1 = [
[ cos(theta)*sin(phi), sin(theta)*sin(phi), -cos(phi) ],
[ -sin(theta) , cos(theta) , 0 ],
[ cos(theta)*cos(phi), sin(theta)*cos(phi), sin(phi) ]]
# Now pick an arbitrary point out of the two (point i will
# do fine), rotate it via this matrix, determine its angle
# psi from the y-axis, and construct the simple rotation
# matrix
#
# ( cos(-psi) -sin(-psi) 0 )
# ( sin(-psi) cos(-psi) 0 )
# ( 0 0 1 )
#
# which brings it back to the y-axis.
xi1 = matrix1[0][0] * xi + matrix1[0][1] * yi + matrix1[0][2] * zi
yi1 = matrix1[1][0] * xi + matrix1[1][1] * yi + matrix1[1][2] * zi
# (no need to compute zi since we don't use it in this case)
psi = atan2(-xi1, yi1)
matrix2 = [
[ cos(-psi), -sin(-psi), 0 ],
[ sin(-psi), cos(-psi), 0 ],
[ 0 , 0 , 1 ]]
# Now combine those matrices to produce the real one.
matrix = []
for y in range(3):
mrow = []
for x in range(3):
s = 0
for k in range(3):
s = s + matrix2[y][k] * matrix1[k][x]
mrow.append(s)
matrix.append(mrow)
# Test code to check that all that worked.
#
# This prints the transformed values of the two points, so
# we can check that they have zero x coordinates, the y
# coordinates are negatives of each other, and the z
# coordinates are the same.
#
#xi1 = matrix[0][0] * xi + matrix[0][1] * yi + matrix[0][2] * zi
#yi1 = matrix[1][0] * xi + matrix[1][1] * yi + matrix[1][2] * zi
#zi1 = matrix[2][0] * xi + matrix[2][1] * yi + matrix[2][2] * zi
#print (100000 + xi1) - 100000, yi1, zi1
#xj1 = matrix[0][0] * xj + matrix[0][1] * yj + matrix[0][2] * zj
#yj1 = matrix[1][0] * xj + matrix[1][1] * yj + matrix[1][2] * zj
#zj1 = matrix[2][0] * xj + matrix[2][1] * yj + matrix[2][2] * zj
#print (100000 + xj1) - 100000, yj1, zj1
#
# And this computes the product of the matrix and its
# transpose, which should come to the identity matrix since
# it's supposed to be orthogonal.
#
#testmatrix = []
#for y in range(3):
# mrow = []
# for x in range(3):
# s = 0
# for k in range(3):
# s = s + matrix[y][k] * matrix[x][k]
# mrow.append((10000000 + s) - 10000000)
# testmatrix.append(mrow)
#print testmatrix
# Whew. So after that moderately hairy piece of linear
# algebra, we can now transform our point set so that when
# projected into the x-z plane our two chosen points become
# 1. Do so.
ppoints = []
for k in range(n):
xk, yk, zk = points[k]
xk1 = matrix[0][0] * xk + matrix[0][1] * yk + matrix[0][2] * zk
#yk1 = matrix[1][0] * xk + matrix[1][1] * yk + matrix[1][2] * zk
zk1 = matrix[2][0] * xk + matrix[2][1] * yk + matrix[2][2] * zk
ppoints.append((xk1, zk1))
# The point of all that was to produce a plane projection
# of the point set, under which the entire edge we're
# considering becomes a single point. Now what we do is to
# see whether that _point_ is on the 2-D convex hull of the
# projected point set.
#
# To do this we will go through all the other points and
# figure out their bearings from the fulcrum point. Then
# we'll sort those bearings into angle order (which is of
# course cyclic modulo 2pi). If the fulcrum is part of the
# convex hull, we expect there to be a gap of size > pi
# somewhere in that set of angles, indicating that a line
# can be drawn through the fulcrum at some angle such that
# all the other points are on the same side of it.
# First, compensate for any rounding errors in the above
# linear algebra by averaging the (theoretically exactly
# equal) projected coordinates of points i and j to get
# coords which we will use as our canonical fulcrum.
fx = (ppoints[i][0] + ppoints[j][0]) / 2
fz = (ppoints[i][1] + ppoints[j][1]) / 2
# Now find the list of angles.
angles = []
for k in range(n):
if k == i or k == j: continue
x, z = ppoints[k]
angle = atan2(z - fz, x - fx)
angles.append(angle)
# Sort them.
angles.sort()
# Now go through and look for a gap of size pi. There are
# two possible ways this can happen: either two adjacent
# elements in the list are separated by more than pi, or
# the two end elements are separated by _less_ than pi.
hull = 0
for k in range(len(angles)-1):
if angles[k+1] - angles[k] > pi:
hull = 1
break
if angles[-1] - angles[0] < pi:
hull = 1
if hull:
hulledges[(i,j)] = 1
# Now we know the set of edges involved in the polyhedron, we need
# to combine them into faces. To do this we will have to consider
# each edge, going _both_ ways.
followedges = {}
for i in range(n):
xi, yi, zi = points[i]
for j in range(n):
xj, yj, zj = points[j]
if i == j: continue
if not (hulledges.has_key((i,j)) or hulledges.has_key((j,i))): continue
# So we have an edge from point i to point j. We imagine we
# are walking along that edge from i to j with the
# intention of circumnavigating the face to our left. So
# when we reach j, we must turn left on to another edge,
# and the question is which edge that is.
#
# To do this we will begin by rotating so that point j is
# at (0,0,1). This has been done in several other parts of
# this code base so I won't comment it in full yet again...
theta = atan2(yj, xj)
phi = asin(zj)
matrix = [
[ cos(theta)*sin(phi), sin(theta)*sin(phi), -cos(phi) ],
[ -sin(theta) , cos(theta) , 0 ],
[ cos(theta)*cos(phi), sin(theta)*cos(phi), sin(phi) ]]
# Now we are looking directly down on point j. We can see
# some number of convex-hull edges coming out of it; we
# determine the angle at which each one emerges, and find
# the one which is closest to the i-j edge on the left.
angles = []
for k in range(n):
if k == j: continue
if not (hulledges.has_key((k,j)) or hulledges.has_key((j,k))):
continue
xk, yk, zk = points[k]
xk1 = matrix[0][0] * xk + matrix[0][1] * yk + matrix[0][2] * zk
yk1 = matrix[1][0] * xk + matrix[1][1] * yk + matrix[1][2] * zk
#zk1 = matrix[2][0] * xk + matrix[2][1] * yk + matrix[2][2] * zk
angles.append((atan2(xk1, yk1), k))
# Sort by angle, in reverse order.
angles.sort(key=lambda x : -x[0])
# Search for i and take the next thing below it. Wrap
# round, of course: if angles[0] is i then we want
# angles[-1]. Conveniently this will be done for us by
# Python's array semantics :-)
k = None
for index in range(len(angles)):
if angles[index][1] == i:
k = angles[index-1][1]
break
assert k != None
followedges[(i,j)] = (j,k)
# Now we're about ready to output our polyhedron definition. The
# only thing we're missing is the surface normals, and we'll do
# those as we go along.
# Now, the faces. We'll simply delete entries from followedges() as
# we go around, so as to avoid doing any face more than once.
faceList = []
while len(followedges) > 0:
# Pick an arbitrary key in followedges.
start = this = followedges.keys()[0]
vertices = []
while 1:
p = points[this[0]]
vertices.append((x0+size*p[0],y0+size*p[1],z0+size*p[2]))
next = followedges[this]
del followedges[this]
this = next
if this == start:
break
faceList.append(vertices)
return faceList
def polyhedron(d,n,faceMode,x,y,z,size,faceBlock,edgeBlock=None):
print "Generating points"
points = makePoints(n)
if faceMode:
print "Generating faces with face construction"
faces = genFacesFace(points,x,y,z,size/2)
else:
print "Generating faces with vertex construction"
faces = genFacesVertex(points,x,y,z,size/2)
print "Drawing faces"
for face in faces:
d.face(face,faceBlock)
print "Drawing edges"
if edgeBlock:
for face in faces:
prev = face[-1]
for vertex in face:
d.line(prev[0],prev[1],prev[2],vertex[0],vertex[1],vertex[2],edgeBlock)
prev = vertex
if __name__ == "__main__":
d = drawing.Drawing()
if len(sys.argv)>1:
n = int(sys.argv[1])
else:
n = 7
faceMode = len(sys.argv)>2 and sys.argv[2][0] == "f"
if len(sys.argv)>3:
size = int(sys.argv[3])
else:
size = 50
pos = d.mc.player.getPos()
polyhedron(d,n,faceMode,pos.x, pos.y, pos.z, size,drawing.GLASS,drawing.STONE)

View File

@ -0,0 +1,854 @@
#www.stuffaboutcode.com
#Raspberry Pi, Minecraft - Create 3D Model from Obj file
# Version 2 - draws complete faces rather than wireframes and uses materials
"""
Copyright (c) Martin O'Hanlon and Alexander Pruss
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
from zipfile import ZipFile
from StringIO import StringIO
import sys
import urllib2
import struct
from collections import OrderedDict
import mcpi.minecraft as minecraft
from copy import copy
from mcpi.block import *
import mcpi.settings as settings
#import time, so delays can be used
import time
#import datetime, to get the time!
import datetime
import gzip
from drawing import *
import math
import os
import re
IDENTITY44 = ((1.,0.,0.,0.),(0.,1.,0.,0.),(0.,0.,1.,0.),(0.,0.,0.,1.))
def determinant44(m):
inv00=m[1][1]*m[2][2]*m[3][3]-m[1][1]*m[3][2]*m[2][3]-m[1][2]*m[2][1]*m[3][3]+m[1][2]*m[3][1]*m[2][3]+m[1][3]*m[2][1]*m[3][2]-m[1][3]*m[3][1]*m[2][2]
inv01=-m[0][1]*m[2][2]*m[3][3]+m[0][1]*m[3][2]*m[2][3]+m[0][2]*m[2][1]*m[3][3]-m[0][2]*m[3][1]*m[2][3]-m[0][3]*m[2][1]*m[3][2]+m[0][3]*m[3][1]*m[2][2]
inv02=m[0][1]*m[1][2]*m[3][3]-m[0][1]*m[3][2]*m[1][3]-m[0][2]*m[1][1]*m[3][3]+m[0][2]*m[3][1]*m[1][3]+m[0][3]*m[1][1]*m[3][2]-m[0][3]*m[3][1]*m[1][2]
inv03=-m[0][1]*m[1][2]*m[2][3]+m[0][1]*m[2][2]*m[1][3]+m[0][2]*m[1][1]*m[2][3]-m[0][2]*m[2][1]*m[1][3]-m[0][3]*m[1][1]*m[2][2]+m[0][3]*m[2][1]*m[1][2]
return m[0][0]*inv00 + m[1][0]*inv01 + m[2][0]*inv02 + m[3][0]*inv03
def invertMatrix44(m):
inv = [[0 for i in range(4)] for j in range(4)]
inv[0][0]=m[1][1]*m[2][2]*m[3][3]-m[1][1]*m[3][2]*m[2][3]-m[1][2]*m[2][1]*m[3][3]+m[1][2]*m[3][1]*m[2][3]+m[1][3]*m[2][1]*m[3][2]-m[1][3]*m[3][1]*m[2][2]
inv[0][1]=-m[0][1]*m[2][2]*m[3][3]+m[0][1]*m[3][2]*m[2][3]+m[0][2]*m[2][1]*m[3][3]-m[0][2]*m[3][1]*m[2][3]-m[0][3]*m[2][1]*m[3][2]+m[0][3]*m[3][1]*m[2][2]
inv[0][2]=m[0][1]*m[1][2]*m[3][3]-m[0][1]*m[3][2]*m[1][3]-m[0][2]*m[1][1]*m[3][3]+m[0][2]*m[3][1]*m[1][3]+m[0][3]*m[1][1]*m[3][2]-m[0][3]*m[3][1]*m[1][2]
inv[0][3]=-m[0][1]*m[1][2]*m[2][3]+m[0][1]*m[2][2]*m[1][3]+m[0][2]*m[1][1]*m[2][3]-m[0][2]*m[2][1]*m[1][3]-m[0][3]*m[1][1]*m[2][2]+m[0][3]*m[2][1]*m[1][2]
inv[1][0]=-m[1][0]*m[2][2]*m[3][3]+m[1][0]*m[3][2]*m[2][3]+m[1][2]*m[2][0]*m[3][3]-m[1][2]*m[3][0]*m[2][3]-m[1][3]*m[2][0]*m[3][2]+m[1][3]*m[3][0]*m[2][2]
inv[1][1]=m[0][0]*m[2][2]*m[3][3]-m[0][0]*m[3][2]*m[2][3]-m[0][2]*m[2][0]*m[3][3]+m[0][2]*m[3][0]*m[2][3]+m[0][3]*m[2][0]*m[3][2]-m[0][3]*m[3][0]*m[2][2]
inv[1][2]=-m[0][0]*m[1][2]*m[3][3]+m[0][0]*m[3][2]*m[1][3]+m[0][2]*m[1][0]*m[3][3]-m[0][2]*m[3][0]*m[1][3]-m[0][3]*m[1][0]*m[3][2]+m[0][3]*m[3][0]*m[1][2]
inv[1][3]=m[0][0]*m[1][2]*m[2][3]-m[0][0]*m[2][2]*m[1][3]-m[0][2]*m[1][0]*m[2][3]+m[0][2]*m[2][0]*m[1][3]+m[0][3]*m[1][0]*m[2][2]-m[0][3]*m[2][0]*m[1][2]
inv[2][0]=m[1][0]*m[2][1]*m[3][3]-m[1][0]*m[3][1]*m[2][3]-m[1][1]*m[2][0]*m[3][3]+m[1][1]*m[3][0]*m[2][3]+m[1][3]*m[2][0]*m[3][1]-m[1][3]*m[3][0]*m[2][1]
inv[2][1]=-m[0][0]*m[2][1]*m[3][3]+m[0][0]*m[3][1]*m[2][3]+m[0][1]*m[2][0]*m[3][3]-m[0][1]*m[3][0]*m[2][3]-m[0][3]*m[2][0]*m[3][1]+m[0][3]*m[3][0]*m[2][1]
inv[2][2]=m[0][0]*m[1][1]*m[3][3]-m[0][0]*m[3][1]*m[1][3]-m[0][1]*m[1][0]*m[3][3]+m[0][1]*m[3][0]*m[1][3]+m[0][3]*m[1][0]*m[3][1]-m[0][3]*m[3][0]*m[1][1]
inv[2][3]=-m[0][0]*m[1][1]*m[2][3]+m[0][0]*m[2][1]*m[1][3]+m[0][1]*m[1][0]*m[2][3]-m[0][1]*m[2][0]*m[1][3]-m[0][3]*m[1][0]*m[2][1]+m[0][3]*m[2][0]*m[1][1]
inv[3][0]=-m[1][0]*m[2][1]*m[3][2]+m[1][0]*m[3][1]*m[2][2]+m[1][1]*m[2][0]*m[3][2]-m[1][1]*m[3][0]*m[2][2]-m[1][2]*m[2][0]*m[3][1]+m[1][2]*m[3][0]*m[2][1]
inv[3][1]=m[0][0]*m[2][1]*m[3][2]-m[0][0]*m[3][1]*m[2][2]-m[0][1]*m[2][0]*m[3][2]+m[0][1]*m[3][0]*m[2][2]+m[0][2]*m[2][0]*m[3][1]-m[0][2]*m[3][0]*m[2][1]
inv[3][2]=-m[0][0]*m[1][1]*m[3][2]+m[0][0]*m[3][1]*m[1][2]+m[0][1]*m[1][0]*m[3][2]-m[0][1]*m[3][0]*m[1][2]-m[0][2]*m[1][0]*m[3][1]+m[0][2]*m[3][0]*m[1][1]
inv[3][3]=m[0][0]*m[1][1]*m[2][2]-m[0][0]*m[2][1]*m[1][2]-m[0][1]*m[1][0]*m[2][2]+m[0][1]*m[2][0]*m[1][2]+m[0][2]*m[1][0]*m[2][1]-m[0][2]*m[2][0]*m[1][1]
invdet = 1./ (m[0][0]*inv[0][0] + m[1][0]*inv[0][1] + m[2][0]*inv[0][2] + m[3][0]*inv[0][3])
for i in range(4):
for j in range(4):
inv[i][j] = invdet * inv[i][j]
return inv
def mulMatrix44(a,b):
return tuple( tuple(a[i][0]*b[0][j]+a[i][1]*b[1][j]+a[i][2]*b[2][j]+a[i][3]*b[3][j] for j in xrange(4)) for i in xrange(4) )
def applyMatrix44(a,v):
if a is None:
return v
return V3(a[i][0]*v[0]+a[i][1]*v[1]+a[i][2]*v[2]+a[i][3] for i in range(3))
def translMatrix44(v):
return tuple( tuple((IDENTITY44[i][j] if j < 3 or i == 3 else v[i]) for j in range(4)) for i in range(4))
def safeEval(p):
if '__' in p:
raise ValueError("Insecure entry")
return eval(p)
def parseBlock(data,default):
if '__' in data:
raise ValueError("Insecure entry")
b = Block(0,0)
tokens = re.split("[\\s,]+", data)
haveBlock = False
start = eval(tokens[0])
if isinstance(start,Block):
b = copy(start)
else:
b.id = int(start)
if len(tokens)>1:
b.data = int(eval(tokens[1]))
return Block(b.id,b.data)
class MeshFile(object):
def __init__(self):
self.vertices = []
self.faces = []
self.materialIndexDict = {None:0}
self.materials = []
self.objectData = {}
self.objects = []
class MeshPLY(MeshFile):
"""
Currently doesn't support materials or binary data or any data. :-)
"""
def __init__(self, filename, myopen=open, swapYZ=False):
super(MeshPLY,self).__init__()
with myopen(filename, "r") as f:
assert f.readline().strip() == "ply"
assert f.readline().strip().startswith("format ascii")
elementCounts = []
while True:
line = f.readline().strip()
if line == "end_header":
break
args = re.split("\\s+",line)
if len(args)>=3 and args[0]=='element':
elementCounts.append((args[1],int(args[2])))
assert len(elementCounts) >= 2
for element,count in elementCounts:
for i in range(count):
line = f.readline().strip()
if element == 'vertex':
args = re.split("\\s+",line)
if swapYZ:
v = V3(float(args[0]),float(args[2]),-float(args[1]))
else:
v = V3(float(args[0]),float(args[1]),float(args[2]))
self.vertices.append(v)
elif element == 'face':
args = re.split("\\s+",line)
count = int(args.pop(0))
v = tuple(int(args[j]) for j in range(count))
self.faces.append((0,v))
assert self.vertices
assert self.faces
class Mesh3DS(MeshFile):
MAIN3DS = 0x4D4D
EDIT3DS = 0x3D3D
KEYF3DS = 0xB000
KEYF_OBJDES = 0xB002
KEYF_OBJHIERARCH = 0xB010
KEYF_PIVOT = 0xB013
EDIT_OBJECT = 0x4000
OBJ_TRIMESH = 0x4100
TRI_VERTEXL = 0x4110
TRI_FACEL1 = 0x4120
TRI_LOCAL = 0x4160
TRI_MATERIAL = 0x4130
def __init__(self, filename, myopen=open, swapYZ=False):
super(Mesh3DS,self).__init__()
self.swapYZ = swapYZ
if int(sys.version[0]) >= 3:
self.readAsciiz = self.readAsciiz_python3
with myopen(filename, "rb") as self.file:
id,lengthRemaining = self.readChunkHeader()
lengthRemaining -= 6
if id != Mesh3DS.MAIN3DS:
raise IOError("Cannot find main chunk")
while 0 < lengthRemaining:
id,chunkLength = self.readChunkHeader()
lengthRemaining -= 6
if id == Mesh3DS.EDIT3DS:
self.handle_EDIT3DS(chunkLength - 6)
lengthRemaining -= chunkLength - 6
elif id == Mesh3DS.KEYF3DS:
self.handle_KEYF3DS(chunkLength - 6)
lengthRemaining -= chunkLength - 6
else:
self.skip(chunkLength - 6)
lengthRemaining -= chunkLength - 6
self.processObjects()
if not self.faces:
raise IOError("No faces found")
def processObjects(self):
i = 0
for (name,parent,pivot) in self.objects:
try:
(object_vertices,object_faces,object_material_data,object_matrix) = self.objectData[name]
except KeyError:
continue
if not object_vertices:
continue
if determinant44(object_matrix) < 0:
transform = mulMatrix44(object_matrix, mulMatrix44(((-1,0,0,0),(0,1,0,0),(0,0,1,0),(0,0,0,1)), invertMatrix44(object_matrix)))
else:
transform = None
if pivot != V3(0,0,0):
delta = applyMatrix(object_matrix, -pivot)
else:
delta = None
firstObjectVertex = len(self.vertices)
for v in object_vertices:
if transform:
v = applyMatrix44(transform, v)
if delta:
v = v + delta
if self.swapYZ:
self.vertices.append(V3(v[0],v[2],-v[1]))
else:
self.vertices.append(v1)
for (faceIndex,face) in enumerate(object_faces):
material = None
for (name,faces) in object_material_data:
if faceIndex in faces:
material = name
break
try:
materialIndex = self.materialIndexDict[material]
except KeyError:
materialIndex = len(self.materials)
self.materials.append(material)
self.materialIndexDict[material] = materialIndex
self.faces.append((materialIndex, tuple(v + firstObjectVertex for v in face)))
def readChunkHeader(self):
return struct.unpack("<HL", self.file.read(6))
def skip(self,length):
if length:
self.file.seek(length,1)
def readAsciiz(self,lengthRemaining):
name = ""
while lengthRemaining > 0:
byte = self.file.read(1)
lengthRemaining -= 1
if ord(byte) == 0:
return lengthRemaining, name
name += byte
raise IOError("Name overflowing chunk")
def readAsciiz_python3(self,lengthRemaining):
name = ""
while lengthRemaining > 0:
byte = self.file.read(1)
lengthRemaining -= 1
if ord(byte) == 0:
return lengthRemaining, name
name += byte.decode("cp1252")
raise IOError("Name overflowing chunk")
def handle_EDIT3DS(self,lengthRemaining):
while lengthRemaining > 0:
id,chunkLength = self.readChunkHeader()
lengthRemaining -= 6
if id == Mesh3DS.EDIT_OBJECT:
self.handle_EDIT_OBJECT(chunkLength - 6)
lengthRemaining -= chunkLength - 6
else:
self.skip(chunkLength - 6)
lengthRemaining -= chunkLength - 6
def handle_KEYF3DS(self,lengthRemaining):
while lengthRemaining > 0:
id,chunkLength = self.readChunkHeader()
lengthRemaining -= 6
if id == Mesh3DS.KEYF_OBJDES:
self.handle_KEYF_OBJDES(chunkLength - 6)
lengthRemaining -= chunkLength - 6
else:
self.skip(chunkLength - 6)
lengthRemaining -= chunkLength - 6
def handle_KEYF_OBJDES(self,lengthRemaining):
self.object_name = None
self.object_pivot = None
self.object_parent = None
while lengthRemaining > 0:
id,chunkLength = self.readChunkHeader()
lengthRemaining -= 6
if id == Mesh3DS.KEYF_OBJHIERARCH:
self.handle_KEYF_OBJHIERARCH(chunkLength - 6)
lengthRemaining -= chunkLength - 6
elif id == Mesh3DS.KEYF_PIVOT:
self.handle_KEYF_PIVOT(chunkLength - 6)
lengthRemaining -= chunkLength - 6
else:
self.skip(chunkLength - 6)
lengthRemaining -= chunkLength - 6
self.objects.append((self.object_name,self.object_parent,self.object_pivot))
def handle_KEYF_OBJHIERARCH(self,lengthRemaining):
lengthRemaining, self.object_name = self.readAsciiz(lengthRemaining)
self.skip(4)
lengthRemaining -= 4
self.object_parent = struct.unpack("<h", self.file.read(2))[0]
lengthRemaining -= 2
self.skip(lengthRemaining)
def handle_KEYF_PIVOT(self,lengthRemaining):
self.object_pivot = V3(struct.unpack("<fff", self.file.read(3*4)))
lengthRemaining -= 3*4
self.skip(lengthRemaining)
def handle_EDIT_OBJECT(self,lengthRemaining):
self.object_vertices = []
self.object_faces = []
self.object_material_data = []
self.object_matrix = None
lengthRemaining, self.object_name = self.readAsciiz(lengthRemaining)
while lengthRemaining > 0:
id,chunkLength = self.readChunkHeader()
lengthRemaining -= 6
if id == Mesh3DS.OBJ_TRIMESH:
self.handle_OBJ_TRIMESH(chunkLength - 6)
lengthRemaining -= chunkLength - 6
else:
self.skip(chunkLength - 6)
lengthRemaining -= chunkLength - 6
def handle_OBJ_TRIMESH(self,lengthRemaining):
while lengthRemaining > 0:
id,chunkLength = self.readChunkHeader()
lengthRemaining -= 6
if id == Mesh3DS.TRI_VERTEXL:
self.handle_TRI_VERTEXL(chunkLength - 6)
lengthRemaining -= chunkLength - 6
elif id == Mesh3DS.TRI_FACEL1:
self.handle_TRI_FACEL1(chunkLength - 6)
lengthRemaining -= chunkLength - 6
elif id == Mesh3DS.TRI_LOCAL:
self.handle_TRI_LOCAL(chunkLength - 6)
lengthRemaining -= chunkLength - 6
else:
self.skip(chunkLength - 6)
lengthRemaining -= chunkLength - 6
if self.object_matrix is None:
self.object_matrix = IDENTITY44
self.objectData[self.object_name] = (self.object_vertices,self.object_faces,self.object_material_data, self.object_matrix)
def handle_TRI_VERTEXL(self,lengthRemaining):
count = struct.unpack("<H", self.file.read(2))[0]
lengthRemaining -= 2
for i in xrange(count):
self.object_vertices.append(V3(struct.unpack("<fff", self.file.read(3*4))))
lengthRemaining -= 3*4
self.skip(lengthRemaining)
def handle_TRI_FACEL1(self,lengthRemaining):
count = struct.unpack("<H", self.file.read(2))[0]
lengthRemaining -= 2
for i in xrange(count):
self.object_faces.append(struct.unpack("<HHH", self.file.read(2*3)))
lengthRemaining -= 2*3
self.skip(2)
lengthRemaining -= 2
while lengthRemaining > 0:
id,chunkLength = self.readChunkHeader()
lengthRemaining -= 6
if id == Mesh3DS.TRI_MATERIAL:
self.handle_TRI_MATERIAL(chunkLength - 6)
lengthRemaining -= chunkLength - 6
else:
self.skip(chunkLength - 6)
lengthRemaining -= chunkLength - 6
def handle_TRI_LOCAL(self,lengthRemaining):
m = [ [1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1] ]
for i in xrange(4):
for j in xrange(3):
m[j][i] = struct.unpack("<f", self.file.read(4))[0]
lengthRemaining -= 4
self.object_matrix = m
self.skip(lengthRemaining)
def handle_TRI_MATERIAL(self,lengthRemaining):
lengthRemaining,name = self.readAsciiz(lengthRemaining)
name = name.replace(' ', '_') # TODO: handle "A_B" and "A B" collision
count = struct.unpack("<H", self.file.read(2))[0]
lengthRemaining -= 2
faces = set()
for i in xrange(count):
faces.add(struct.unpack("<H", self.file.read(2))[0])
lengthRemaining -= 2
self.object_material_data.append( (name, faces) )
self.skip(lengthRemaining)
class Mesh(object):
UNSPECIFIED = None
SUPPORTED_ARCHIVES = set(['gz','zip'])
def __init__(self,infile,minecraft=None,rewrite=True):
if minecraft:
self.setBlock = minecraft.setBlock
self.message = minecraft.postToChat
else:
self.output = OrderedDict()
def setBlock(v,b):
self.output[v] = b
self.setBlock = setBlock
def message(m):
print m
self.message = message
self.rewrite = rewrite
self.url = None
self.urlgz = None
self.urlzip = None
self.swapYZ = None
self.credits = None
self.size = 100
self.preYaw = 0
self.prePitch = 0
self.preRoll = 0
self.archive = None
self.default = STONE
self.materialBlockDict = {}
self.materialOrderDict = {}
self.baseVertices = []
self.vertices = []
#self.textures = []
#self.normals = []
self.faces = []
self.materials = []
self.materialNames = []
self.haveMaterialArea = False
self.corner1 = None
self.corner2 = None
self.endLineIndex = None
self.specifiedMeshName = None
base,ext = os.path.splitext(infile)
if ext.lower() == '.obj' or ext.lower() == ".3ds" or ext.lower() == ".ply":
self.meshName = infile
self.controlFile = base + ".txt"
else:
if os.path.isfile(base + ".3ds") or os.path.isfile(base + ".3ds.gz"):
self.meshName = base + ".3ds"
elif os.path.isfile(base + ".ply") or os.path.isfile(base + ".ply.gz"):
self.meshName = base + ".ply"
else:
self.meshName = base + ".obj"
if ext == '':
self.controlFile = base + ".txt"
else:
self.controlFile = infile
if os.path.isfile(self.controlFile):
with open(self.controlFile) as f:
self.controlFileLines = f.readlines()
dirname = os.path.dirname(self.controlFile)
materialMode = False
for i,line in enumerate(self.controlFileLines):
line = line.strip()
if len(line) == 0 or line[0] == '#':
continue
found = re.match('([^\\s]+) (.*)$', line)
if found:
def getString():
if found.group(2).startswith('"') or found.group(2).startswith("'"):
return safeEval(found.group(2))
else:
return found.group(2)
token = found.group(1).lower()
if materialMode:
self.materialBlockDict[found.group(1)] = parseBlock(found.group(2),self.default)
elif token == "file":
self.specifiedMeshName = getString()
self.meshName = dirname + "/" + self.specifiedMeshName
elif token == "archive":
self.archive = getString()
if self.archive.lower() not in Mesh.SUPPORTED_ARCHIVES:
self.archive = dirname + '/' + self.archive
elif token == "swapyz":
self.swapYZ = bool(safeEval(found.group(2).capitalize()))
elif token == "credits":
self.credits = found.group(2)
elif token == "url":
self.url = found.group(2)
elif token == "urlgz":
self.urlgz = found.group(2)
elif token == "size":
self.size = safeEval(found.group(2))
elif token == "default":
self.default = parseBlock(found.group(2),self.default)
elif token == "yaw":
self.preYaw = safeEval(found.group(2))
elif token == "pitch":
self.prePitch = safeEval(found.group(2))
elif token == "roll":
self.preRoll = safeEval(found.group(2))
elif token == "order":
args = re.split("[\\s,]+", found.group(2))
self.materialOrderDict[args[0]] = int(args[1])
elif line.strip().lower() == "materials":
materialMode = True
self.haveMaterialArea = True
elif line.strip().lower() == "end":
self.endLineIndex = i
break
if self.endLineIndex is None:
self.endLineIndex = len(self.controlFileLines)
if self.archive in Mesh.SUPPORTED_ARCHIVES:
self.archive = self.meshName + "." + self.archive
if self.swapYZ is None:
self.swapYZ = self.meshName.lower().endswith(".3ds")
elif rewrite:
if not os.path.isfile(self.meshName):
raise IOError("Cannot find mesh file")
if self.meshName.lower().endswith(".3ds"):
self.swapYZ = True
self.message("Creating a default control file")
with open(self.controlFile,"w") as f:
self.controlFileLines = []
self.controlFileLines.append("file "+repr(os.path.basename(self.meshName))+"\n")
if self.swapYZ:
self.controlFileLines.append("swapyz 1\n")
else:
self.controlFileLines.append("swapyz 0\n")
self.controlFileLines.append("#credits Mesh by ..., copyright (c) ...\n")
self.controlFileLines.append("yaw 0\n")
self.controlFileLines.append("pitch 0\n")
self.controlFileLines.append("roll 0\n")
self.controlFileLines.append("size "+str(self.size)+"\n")
self.controlFileLines.append("default STONE\n")
self.controlFileLines.append("#order material position\n")
self.controlFileLines.append("materials\n")
self.haveMaterialArea = True
self.endLineIndex = len(self.controlFileLines)
self.controlFileLines.append("end\n\n")
self.controlFileLines.append("[Insert any detailed licensing information here]")
for line in self.controlFileLines:
f.write(line)
if settings.isPE:
self.size /= 2
def getFile(self, tryDownload=True):
if self.archive and os.path.isfile(self.archive):
if self.archive.lower().endswith(".gz"):
return self.archive, gzip.open, None
elif self.archive.lower().endswith(".zip"):
z = ZipFile(self.archive)
return self.specifiedMeshName, z.open, z.close
else:
raise IOError("Unsupported archive type")
if os.path.isfile(self.meshName):
return self.meshName, open, None
if os.path.isfile(self.meshName+".gz"):
return self.meshName+".gz", gzip.open, None
if tryDownload and (self.url or self.urlgz):
self.message("Downloading mesh")
urlzip = False
if self.urlgz:
url = self.urlgz
outName = self.meshName+".gz"
elif self.url:
url = self.url
if self.archive:
outName = self.archive
else:
outName = self.meshName
content = urllib2.urlopen(url).read()
with open(outName+".tempDownload","wb") as f:
f.write(content)
os.rename(outName+".tempDownload", outName)
self.message("Downloaded")
return self.getFile()
else:
raise IOError("File not found")
def read(self, rewriteControlFile = None):
if self.swapYZ:
fix = lambda list : V3(list[0], list[2], -list[1])
else:
fix = lambda list : V3(list)
warned = set()
currentMaterialIndex = 0
if self.preYaw != 0 or self.prePitch != 0 or self.preRoll != 0:
matrix = makeMatrix(self.preYaw, self.prePitch, self.preRoll)
else:
matrix = None
name,myopen,closeArchive = self.getFile()
if self.credits:
self.message("Credits: "+self.credits)
if name.endswith(".3ds") or name.endswith(".3ds.gz") or name.endswith(".ply") or name.endswith(".ply.gz"):
MeshFormat = Mesh3DS if name.endswith(".3ds") or name.endswith(".3ds.gz") else MeshPLY
mesh = MeshFormat(name,myopen=myopen,swapYZ=self.swapYZ)
self.baseVertices = mesh.vertices
self.faces = mesh.faces
self.materialBlocks = []
self.materialOrders = []
for name in mesh.materials:
self.materialOrders.append(self.materialOrderDict.get(name, 0))
self.materialBlocks.append(self.materialBlockDict.get(name, self.default))
if name not in self.materialBlockDict and name not in warned:
self.message("Material "+name+" not defined")
warned.add(name)
if len(self.materialBlocks) == 0:
self.materialBlocks.append(self.default)
else:
self.materialBlocks = [ self.default ]
self.materialOrders = [ 0 ]
materialIndexDict = { Mesh.UNSPECIFIED: 0 }
with myopen(name) as fh:
for line in fh :
line = line.strip()
if len(line) == 0 or line[0] == '#' : continue
line = re.split('\s+', line)
if line[0] == 'v' :
self.baseVertices.append(applyMatrix(matrix,V3(fix([float(x) for x in line[1:]]))))
#elif line[0] == 'vt' : #tex-coord
# self.textures.append(fix(line[1:]))
#elif line[0] == 'vn' : #normal vector
# self.normals.append(fix(line[1:]))
elif line[0] == 'f' : #face
face = line[1:]
for i in xrange(0, len(face)) :
# OBJ indexies are 1 based not 0 based hence the -1
# convert indexes to integer
face[i] = int( face[i].split('/')[0] ) - 1
# skip texture and normal
# for j in xrange(0, len(face[i])) :
# if face[i][j] != "":
# face[i][j] = int(face[i][j]) - 1
#prepend the material currently in use to the face
self.faces.append((currentMaterialIndex,face))
elif line[0] == 'usemtl': # material
name = line[1]
try:
currentMaterialIndex = materialIndexDict[name]
except KeyError:
currentMaterialIndex = len(self.materialBlocks)
materialIndexDict[name] = currentMaterialIndex
self.materialOrders.append(self.materialOrderDict.get(name, 0))
self.materialBlocks.append(self.materialBlockDict.get(name, self.default))
if name not in self.materialBlockDict and name not in warned:
self.message("Material "+name+" not defined")
warned.add(name)
if closeArchive:
closeArchive()
if self.rewrite and warned:
try:
self.message("Rewriting control file to include missing materials")
with open(self.controlFile+".tempFile", "w") as f:
f.write(''.join(self.controlFileLines[:self.endLineIndex]))
if not self.haveMaterialArea:
f.write('\nmaterials\n')
for material in warned:
f.write(material+' default\n')
f.write(''.join(self.controlFileLines[self.endLineIndex:]))
try:
os.unlink(self.controlFile+".bak")
except:
pass
try:
os.rename(self.controlFile, self.controlFile+".bak")
except:
pass
os.rename(self.controlFile+".tempFile", self.controlFile)
except:
self.message("Couldn't rewrite control file")
def scale(self, bottomCenter, matrix=None):
bottomCenter = V3(bottomCenter)
minimum = [None, None, None]
maximum = [None, None, None]
self.vertices = []
for v in self.baseVertices:
vertex = applyMatrix(matrix,v)
self.vertices.append(vertex)
for i in range(3):
if minimum[i] == None or vertex[i] < minimum[i]:
minimum[i] = vertex[i]
if maximum[i] == None or vertex[i] > maximum[i]:
maximum[i] = vertex[i]
center = [(maximum[i] + minimum[i])/2 for i in range(3)]
maxsize = max( ( maximum[i]-minimum[i] for i in range(3) ) )
scale = self.size / maxsize
translate = V3(bottomCenter.x-scale*center[0], bottomCenter.y-scale*minimum[1], bottomCenter.z-scale*center[2])
for i in range(len(self.vertices)):
self.vertices[i] = self.vertices[i] * scale + translate
self.corner1 = (V3(minimum) * scale + translate).ifloor()
self.corner2 = (V3(maximum) * scale + translate).iceil()
def drawVertices(self, vertices, material):
block = self.materialBlocks[material]
for vertex in vertices:
if material != self.drawRecord.get(vertex):
self.setBlock(vertex, block)
self.drawRecord[vertex] = material
def render(self):
self.drawRecord = {}
if len(self.materialOrderDict):
faces = sorted(self.faces, key=lambda a : self.materialOrders[a[0]])
else:
faces = self.faces
for faceCount,(material,face) in enumerate(faces):
if faceCount % 4000 == 0:
self.message("{0:.1f}%".format(100. * faceCount / len(self.faces)))
faceVertices = [self.vertices[v] for v in face]
self.drawVertices(getFace(faceVertices), material)
def go(filename, args=[]):
mc = minecraft.Minecraft()
playerPos = mc.player.getPos()
mc.postToChat("Preparing")
mesh = Mesh(filename, minecraft=mc)
mc.postToChat("Reading")
mesh.read()
mc.postToChat("Scaling")
opts = ""
if args and (args[0] == '-' or re.match("^-?[a-zA-Z]", args[0])):
opts = args.pop(0)
if args:
s = args.pop(0)
if s and int(s):
mesh.size = int(s)
matrix = None
if args:
yaw = float(args.pop(0))
pitch = 0
roll = 0
if args:
pitch = float(args.pop(0))
if args:
roll = float(args.pop(0))
matrix = makeMatrix(yaw, pitch, roll)
mesh.scale(playerPos, matrix)
if 'n' not in opts:
mc.postToChat("Clearing")
mc.setBlocks(mesh.corner1,mesh.corner2,AIR)
mc.postToChat("Rendering")
mesh.render()
mc.postToChat("Done!")
# main program
if __name__ == "__main__":
if len(sys.argv)<2:
if settings.isPE:
go("models/RaspberryPi.txt")
else:
from Tkinter import *
from tkFileDialog import askopenfilename
master = Tk()
master.wm_title("render")
master.attributes("-topmost", True)
Label(master, text='Size').grid(row=0)
size = Entry(master)
size.grid(row=0,column=1)
size.delete(0,END)
Label(master, text='Yaw').grid(row=1)
yaw = Entry(master)
yaw.grid(row=1,column=1)
yaw.delete(0,END)
yaw.insert(0,"0")
Label(master, text='Pitch:').grid(row=2)
pitch = Entry(master)
pitch.grid(row=2,column=1)
pitch.delete(0,END)
pitch.insert(0,"0")
Label(master, text='Roll:').grid(row=3)
roll = Entry(master)
roll.grid(row=3,column=1)
roll.delete(0,END)
roll.insert(0,"0")
clearing = IntVar()
c = Checkbutton(master, text="Clear area", variable = clearing)
c.grid(row=4,column=0,columnspan=2)
c.select()
def selectFileAndGo():
name=askopenfilename(initialdir='models',filetypes=['controlfile {*.txt}'])
if name:
options = '-'
if not clearing:
options += 'n'
args = [options, size.get(), yaw.get(), pitch.get(), roll.get()]
master.destroy()
go(name, args)
else:
master.destroy()
b = Button(master, text="Select file and go",command = selectFileAndGo)
b.grid(row=5,column=0,columnspan=2,rowspan=2)
mainloop()
else:
go(os.path.dirname(os.path.realpath(sys.argv[0])) + "/" + "models/" + sys.argv[1] + ".txt", sys.argv[2:])

Some files were not shown because too many files have changed in this diff Show More