fix close handling for websocket
This commit is contained in:
parent
205eb6e7c0
commit
afd26c89b4
26
raspberryjammod/LICENSE
Normal file
26
raspberryjammod/LICENSE
Normal file
@ -0,0 +1,26 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
RaspberryJamMod Copyright (c) 2015 Alexander R. Pruss
|
||||
Lua Copyright (c) 1994–2015 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
178
raspberryjammod/base64.lua
Normal 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
|
@ -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"..
|
||||
|
321
raspberryjammod/mcpipy/NeuroPy/NeuroPy.py
Normal file
321
raspberryjammod/mcpipy/NeuroPy/NeuroPy.py
Normal 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)
|
94
raspberryjammod/mcpipy/NeuroPy/README.txt
Normal file
94
raspberryjammod/mcpipy/NeuroPy/README.txt
Normal 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.
|
||||
|
0
raspberryjammod/mcpipy/NeuroPy/__init__.py
Normal file
0
raspberryjammod/mcpipy/NeuroPy/__init__.py
Normal file
16
raspberryjammod/mcpipy/README.md
Normal file
16
raspberryjammod/mcpipy/README.md
Normal 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
|
237
raspberryjammod/mcpipy/astrotutor_magic.py
Normal file
237
raspberryjammod/mcpipy/astrotutor_magic.py
Normal 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
|
17
raspberryjammod/mcpipy/benchmark.py
Normal file
17
raspberryjammod/mcpipy/benchmark.py
Normal 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.)
|
73
raspberryjammod/mcpipy/blocks_to_bombs.py
Normal file
73
raspberryjammod/mcpipy/blocks_to_bombs.py
Normal 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")
|
58
raspberryjammod/mcpipy/borromean.py
Normal file
58
raspberryjammod/mcpipy/borromean.py
Normal 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
|
25
raspberryjammod/mcpipy/bridge.py
Normal file
25
raspberryjammod/mcpipy/bridge.py
Normal 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)
|
24
raspberryjammod/mcpipy/brooksc_findpos.py
Executable file
24
raspberryjammod/mcpipy/brooksc_findpos.py
Executable 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)
|
21
raspberryjammod/mcpipy/brooksc_flatmap50.py
Executable file
21
raspberryjammod/mcpipy/brooksc_flatmap50.py
Executable 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()
|
27
raspberryjammod/mcpipy/brooksc_teleport_pad.py
Executable file
27
raspberryjammod/mcpipy/brooksc_teleport_pad.py
Executable 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)
|
17
raspberryjammod/mcpipy/brooksc_template.py
Executable file
17
raspberryjammod/mcpipy/brooksc_template.py
Executable 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()
|
127
raspberryjammod/mcpipy/brooksc_tntsnake.py
Executable file
127
raspberryjammod/mcpipy/brooksc_tntsnake.py
Executable 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)
|
||||
|
106
raspberryjammod/mcpipy/burnaron_bunkermatic.py
Executable file
106
raspberryjammod/mcpipy/burnaron_bunkermatic.py
Executable 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)
|
95
raspberryjammod/mcpipy/burnaron_bunkermatic2.py
Executable file
95
raspberryjammod/mcpipy/burnaron_bunkermatic2.py
Executable 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)
|
100
raspberryjammod/mcpipy/camera.py
Normal file
100
raspberryjammod/mcpipy/camera.py
Normal 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')
|
128
raspberryjammod/mcpipy/castle.py
Normal file
128
raspberryjammod/mcpipy/castle.py
Normal 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")
|
417
raspberryjammod/mcpipy/chess.py
Normal file
417
raspberryjammod/mcpipy/chess.py
Normal 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
|
61
raspberryjammod/mcpipy/clock.py
Normal file
61
raspberryjammod/mcpipy/clock.py
Normal 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)
|
||||
|
38
raspberryjammod/mcpipy/console.py
Normal file
38
raspberryjammod/mcpipy/console.py
Normal 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())
|
114
raspberryjammod/mcpipy/danielbates_minecraft_basic.py
Normal file
114
raspberryjammod/mcpipy/danielbates_minecraft_basic.py
Normal 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
|
439
raspberryjammod/mcpipy/danielbates_setblockdemo.py
Executable file
439
raspberryjammod/mcpipy/danielbates_setblockdemo.py
Executable 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()
|
143
raspberryjammod/mcpipy/davef21370_maze.py
Executable file
143
raspberryjammod/mcpipy/davef21370_maze.py
Executable 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
|
||||
|
261
raspberryjammod/mcpipy/daviewales_minesweeper.py
Executable file
261
raspberryjammod/mcpipy/daviewales_minesweeper.py
Executable 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()
|
43
raspberryjammod/mcpipy/digitalclock.py
Normal file
43
raspberryjammod/mcpipy/digitalclock.py
Normal 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)
|
31
raspberryjammod/mcpipy/donut.py
Normal file
31
raspberryjammod/mcpipy/donut.py
Normal 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")
|
41
raspberryjammod/mcpipy/dragoncurve.py
Normal file
41
raspberryjammod/mcpipy/dragoncurve.py
Normal 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)
|
523
raspberryjammod/mcpipy/drawing.py
Normal file
523
raspberryjammod/mcpipy/drawing.py
Normal 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)
|
33
raspberryjammod/mcpipy/explosify.py
Normal file
33
raspberryjammod/mcpipy/explosify.py
Normal 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")
|
41
raspberryjammod/mcpipy/fancytree.py
Normal file
41
raspberryjammod/mcpipy/fancytree.py
Normal 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)
|
53
raspberryjammod/mcpipy/fleap_railgen.py
Executable file
53
raspberryjammod/mcpipy/fleap_railgen.py
Executable 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()
|
71234
raspberryjammod/mcpipy/fonts.py
Normal file
71234
raspberryjammod/mcpipy/fonts.py
Normal file
File diff suppressed because it is too large
Load Diff
17
raspberryjammod/mcpipy/gf_clearZone.py
Executable file
17
raspberryjammod/mcpipy/gf_clearZone.py
Executable 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 )
|
44
raspberryjammod/mcpipy/gf_drawbuilding.py
Executable file
44
raspberryjammod/mcpipy/gf_drawbuilding.py
Executable 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 )
|
38
raspberryjammod/mcpipy/glasscube.py
Normal file
38
raspberryjammod/mcpipy/glasscube.py
Normal 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()
|
||||
|
108
raspberryjammod/mcpipy/grenade.py
Normal file
108
raspberryjammod/mcpipy/grenade.py
Normal 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)
|
8
raspberryjammod/mcpipy/helloworld.py
Normal file
8
raspberryjammod/mcpipy/helloworld.py
Normal 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)
|
35
raspberryjammod/mcpipy/hilbert.py
Normal file
35
raspberryjammod/mcpipy/hilbert.py
Normal 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]))
|
130
raspberryjammod/mcpipy/import.py
Normal file
130
raspberryjammod/mcpipy/import.py
Normal 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)
|
21
raspberryjammod/mcpipy/interpreter.py
Normal file
21
raspberryjammod/mcpipy/interpreter.py
Normal 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)
|
93
raspberryjammod/mcpipy/jjinux_sierpinski_triangle.py
Executable file
93
raspberryjammod/mcpipy/jjinux_sierpinski_triangle.py
Executable 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)
|
42
raspberryjammod/mcpipy/klein.py
Normal file
42
raspberryjammod/mcpipy/klein.py
Normal 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")
|
89
raspberryjammod/mcpipy/klein2.py
Normal file
89
raspberryjammod/mcpipy/klein2.py
Normal 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")
|
27
raspberryjammod/mcpipy/knot.py
Normal file
27
raspberryjammod/mcpipy/knot.py
Normal 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
|
36
raspberryjammod/mcpipy/knot2.py
Normal file
36
raspberryjammod/mcpipy/knot2.py
Normal 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
|
106
raspberryjammod/mcpipy/lforest.py
Normal file
106
raspberryjammod/mcpipy/lforest.py
Normal 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()
|
||||
|
92
raspberryjammod/mcpipy/life.py
Normal file
92
raspberryjammod/mcpipy/life.py
Normal 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)
|
123
raspberryjammod/mcpipy/lsystem.py
Normal file
123
raspberryjammod/mcpipy/lsystem.py
Normal 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)
|
29
raspberryjammod/mcpipy/ltree.py
Normal file
29
raspberryjammod/mcpipy/ltree.py
Normal 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)
|
156
raspberryjammod/mcpipy/mandelbrot.py
Normal file
156
raspberryjammod/mcpipy/mandelbrot.py
Normal 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
|
174
raspberryjammod/mcpipy/mandelbulb.py
Normal file
174
raspberryjammod/mcpipy/mandelbulb.py
Normal 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
|
9
raspberryjammod/mcpipy/mc.py
Normal file
9
raspberryjammod/mcpipy/mc.py
Normal 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 *
|
46
raspberryjammod/mcpipy/mcdragoncurve.py
Normal file
46
raspberryjammod/mcpipy/mcdragoncurve.py
Normal 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()
|
1
raspberryjammod/mcpipy/mcpi/__init__.py
Normal file
1
raspberryjammod/mcpipy/mcpi/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
__all__ = ['minecraft', 'block', 'entity', 'connection']
|
237
raspberryjammod/mcpipy/mcpi/block.py
Normal file
237
raspberryjammod/mcpipy/mcpi/block.py
Normal 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
|
118
raspberryjammod/mcpipy/mcpi/connection.py
Normal file
118
raspberryjammod/mcpipy/mcpi/connection.py
Normal 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()
|
62
raspberryjammod/mcpipy/mcpi/entity.py
Normal file
62
raspberryjammod/mcpipy/mcpi/entity.py
Normal 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)"
|
45
raspberryjammod/mcpipy/mcpi/event.py
Normal file
45
raspberryjammod/mcpipy/mcpi/event.py
Normal 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)
|
||||
|
69
raspberryjammod/mcpipy/mcpi/mcpi_protocol_spec.txt
Normal file
69
raspberryjammod/mcpipy/mcpi/mcpi_protocol_spec.txt
Normal 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
|
@ -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
|
293
raspberryjammod/mcpipy/mcpi/minecraft.py
Normal file
293
raspberryjammod/mcpipy/mcpi/minecraft.py
Normal 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!")
|
624
raspberryjammod/mcpipy/mcpi/nbt.py
Normal file
624
raspberryjammod/mcpipy/mcpi/nbt.py
Normal 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"
|
15
raspberryjammod/mcpipy/mcpi/settings.py
Normal file
15
raspberryjammod/mcpipy/mcpi/settings.py
Normal 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 )
|
||||
|
21
raspberryjammod/mcpipy/mcpi/util.py
Normal file
21
raspberryjammod/mcpipy/mcpi/util.py
Normal 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)))
|
108
raspberryjammod/mcpipy/mcpi/vec3.py
Normal file
108
raspberryjammod/mcpipy/mcpi/vec3.py
Normal 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()
|
104
raspberryjammod/mcpipy/mcpipy.pyproj
Normal file
104
raspberryjammod/mcpipy/mcpipy.pyproj
Normal 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>
|
25
raspberryjammod/mcpipy/mcpipy.sln
Normal file
25
raspberryjammod/mcpipy/mcpipy.sln
Normal 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
|
BIN
raspberryjammod/mcpipy/mcpipy.v12.suo
Normal file
BIN
raspberryjammod/mcpipy/mcpipy.v12.suo
Normal file
Binary file not shown.
368
raspberryjammod/mcpipy/mcturtle.py
Normal file
368
raspberryjammod/mcpipy/mcturtle.py
Normal 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)
|
58
raspberryjammod/mcpipy/mengersponge.py
Normal file
58
raspberryjammod/mcpipy/mengersponge.py
Normal 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)
|
41
raspberryjammod/mcpipy/mobius.py
Normal file
41
raspberryjammod/mcpipy/mobius.py
Normal 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")
|
78
raspberryjammod/mcpipy/models/1701d.txt
Normal file
78
raspberryjammod/mcpipy/models/1701d.txt
Normal 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
|
||||
|
1
raspberryjammod/mcpipy/models/COPYRIGHT
Normal file
1
raspberryjammod/mcpipy/models/COPYRIGHT
Normal file
@ -0,0 +1 @@
|
||||
See copyright and credits for the meshes in the individual txt files.
|
49
raspberryjammod/mcpipy/models/City_Ground-Notts.txt
Normal file
49
raspberryjammod/mcpipy/models/City_Ground-Notts.txt
Normal 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.
|
60
raspberryjammod/mcpipy/models/NY_LIL.txt
Normal file
60
raspberryjammod/mcpipy/models/NY_LIL.txt
Normal 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.
|
51
raspberryjammod/mcpipy/models/RaspberryPi.txt
Normal file
51
raspberryjammod/mcpipy/models/RaspberryPi.txt
Normal 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.
|
12
raspberryjammod/mcpipy/models/atat.txt
Normal file
12
raspberryjammod/mcpipy/models/atat.txt
Normal 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
|
90
raspberryjammod/mcpipy/models/bop.txt
Normal file
90
raspberryjammod/mcpipy/models/bop.txt
Normal 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]
|
13
raspberryjammod/mcpipy/models/cessna.txt
Normal file
13
raspberryjammod/mcpipy/models/cessna.txt
Normal 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
|
||||
|
4
raspberryjammod/mcpipy/models/cube.txt
Normal file
4
raspberryjammod/mcpipy/models/cube.txt
Normal 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
|
10
raspberryjammod/mcpipy/models/dragon.txt
Normal file
10
raspberryjammod/mcpipy/models/dragon.txt
Normal 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
|
116
raspberryjammod/mcpipy/models/ds9.txt
Normal file
116
raspberryjammod/mcpipy/models/ds9.txt
Normal 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
|
6
raspberryjammod/mcpipy/models/head.txt
Normal file
6
raspberryjammod/mcpipy/models/head.txt
Normal 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
|
3
raspberryjammod/mcpipy/models/humanoid_quad.txt
Normal file
3
raspberryjammod/mcpipy/models/humanoid_quad.txt
Normal 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
|
25
raspberryjammod/mcpipy/models/jemcruiser.txt
Normal file
25
raspberryjammod/mcpipy/models/jemcruiser.txt
Normal 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]
|
54
raspberryjammod/mcpipy/models/neghvar.txt
Normal file
54
raspberryjammod/mcpipy/models/neghvar.txt
Normal 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
|
9
raspberryjammod/mcpipy/models/redstardestroyer.txt
Normal file
9
raspberryjammod/mcpipy/models/redstardestroyer.txt
Normal 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
|
38
raspberryjammod/mcpipy/models/shuttle.txt
Normal file
38
raspberryjammod/mcpipy/models/shuttle.txt
Normal 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.
|
6
raspberryjammod/mcpipy/models/skyscraper.txt
Normal file
6
raspberryjammod/mcpipy/models/skyscraper.txt
Normal 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
|
65
raspberryjammod/mcpipy/models/stardestroyer.txt
Normal file
65
raspberryjammod/mcpipy/models/stardestroyer.txt
Normal 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
|
30
raspberryjammod/mcpipy/models/yt1300.txt
Normal file
30
raspberryjammod/mcpipy/models/yt1300.txt
Normal 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
|
52
raspberryjammod/mcpipy/neurosky.py
Normal file
52
raspberryjammod/mcpipy/neurosky.py
Normal 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)
|
24
raspberryjammod/mcpipy/nt7s_sphere.py
Executable file
24
raspberryjammod/mcpipy/nt7s_sphere.py
Executable 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)
|
86
raspberryjammod/mcpipy/obsidz_teleport.py
Executable file
86
raspberryjammod/mcpipy/obsidz_teleport.py
Executable 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)
|
757
raspberryjammod/mcpipy/polyhedron.py
Normal file
757
raspberryjammod/mcpipy/polyhedron.py
Normal 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)
|
854
raspberryjammod/mcpipy/render.py
Normal file
854
raspberryjammod/mcpipy/render.py
Normal 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
Loading…
x
Reference in New Issue
Block a user