Premier commit - Introdution au système git.

This commit is contained in:
2021-05-19 00:04:11 +02:00
commit 3ecabe62fa
84 changed files with 8742 additions and 0 deletions
+153
View File
@@ -0,0 +1,153 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Aug 28 17:39:43 2019
Module contanant les classes générales structurant les données, ainsi que les
@author: mysaa
"""
import numpy as np
def appendeur(l1,l2):
"""
Effectue l1=l1+l2 de manière opti
"""
for l in l2:
l1.append(l)
class WorldChunk():
def getSize(self):
raise NotImplementedError("Vous avez fait un monde qui n'implemente pas cette méthode. Vous êtes bizzare vous savez ? Un monde sans taille !!!")
def getColumn(self,x,y):
raise NotImplementedError("Vous avez fait un monde qui n'implemente pas cette méthode. Vous êtes bizzare vous savez ?")
def asList(self):
return [ [self.getColumn(x,y) for y in range(self.size[1])] for x in range(self.size[0]) ]
def getIndexed(self,fullCoords=False,addZero=False):
points = []
pointIndexes = [0]
for pos in np.ndindex(self.getSize()):
col = self.getColumn(pos[0],pos[1])
if(addZero): col = np.insert(col,0,0)
if(fullCoords): col = [(pos[0],pos[1],c) for c in col]
appendeur(points,col)
pointIndexes.append(pointIndexes[-1]+len(col))
return points,pointIndexes
class CollageWorldChunk(WorldChunk):
def __init__(self,chunk,xp,yp,xy):
self.orgChunk,self.xp,self.yp,self.xy = chunk,xp,yp,xy
self.orgSize = chunk.getSize()
def getSize(self) : return (self.orgChunk.size[0]+1,self.orgChunk.size[1]+1)
def getColumn(self,x,y):
xout,yout = x>=self.orgSize[0],y>=self.orgSize[1]
if(xout and yout):
return self.xy.getColumn(x-self.orgSize[0],y-self.orgSize[1])
if(xout):
return self.xp.getColumn(x-self.orgSize[0],y)
if(yout):
return self.yp.getColumn(x,y-self.orgSize[1])
return self.orgChunk.getColumn(x,y)
class ArrayedWorldChunk(WorldChunk):
def fromList(liste):
size = len(liste),len(liste[0])
indexes=np.empty(size[0]*size[1]+1,dtype=np.uint32)
index = 0
data = []
for y in range(size[1]):
for x in range(size[0]):
indexes[x+size[0]*y]=index
data += liste[x][y]
index += len(liste[x][y])
indexes[size[0]*size[1]] = index
data = np.array(data,dtype=np.float)
return ArrayedWorldChunk(size,indexes,data)
def __init__(self,size,indexes,data):
self.size = size
self.indexes=indexes
self.data=data
def getColumn(self,x,y):
i0,i1 = self.indexes[x+self.size[0]*y],self.indexes[x+self.size[0]*y+1]
return self.data[i0:i1]
def getSize(self) : return self.size
class Noise:
def getChunk(self,x,y,n):
"""
Cette fonction renvoie un array numpy de taille rx*ry correspondant au chunk x y avec le seed donné.
Cette fonction doit être déterministe (si les attributs de l'objets ne sont pas changés bien sur)
"""
raise NotImplementedError("Vous avez fait un bruit qui n'implemente pas cette méthode. Vous êtes bizzare vous savez ?")
def __add__(self,other):
def addedChunk(self,x,y,n):
return self.noise1.getChunk(x,y,n) + self.noise2.getChunk(x,y,n)
noise = Noise()
noise.noise1 = self
noise.noise2 = other
noise.getChunk = addedChunk
return noise
def __iadd__(self,other):
return self.__add__(other)
def __rmul__(self,other):
if type(other) in ['float','int']:
def mulChunk(self,x,y,n):
return self.prop*self.noise1.getChunk(x,y,n)
noise = Noise()
noise.noise1 = self
noise.prop = other
noise.getChunk = mulChunk
else:
def mulChunk(self,x,y,n):
return self.noise1.getChunk(x,y,n) * self.noise2.getChunk(x,y,n)
noise = Noise()
noise.noise1 = self
noise.noise2 = other
noise.getChunk = mulChunk
return noise
def __sub__(self,other):
def subChunk(self,x,y,n):
return self.noise1.getChunk(x,y,n) - self.noise2.getChunk(x,y,n)
noise = Noise()
noise.noise1 = self
noise.noise2 = other
noise.getChunk = subChunk
return noise
Binary file not shown.

After

Width:  |  Height:  |  Size: 982 KiB

+264
View File
@@ -0,0 +1,264 @@
# -*- coding: utf-8 -*-
from PyQt5.QtWidgets import (QWidget, QSlider, QApplication,
QHBoxLayout, QVBoxLayout, QLabel, QLineEdit, QDesktopWidget, QPushButton, QComboBox)
from PyQt5.QtCore import QObject, Qt
from PyQt5.QtGui import QPainter, QFont, QColor, QPen, QImage, QPixmap
from perlin import PerlinNoise
import matplotlib.pyplot as pp
import numpy as np
from math import floor,ceil
import threading
import sys
try: application
except NameError: application = QApplication([])
class MapNavigator(QWidget):
carte = QLabel()
def __init__(self):
super().__init__()
self.setWindowTitle("Navigateur")
### Centrer la fenetre ###
self.resize(750,505)
self.initFrame()
self.show()
self.centrer()
def centrer(self):
qtRectangle = self.frameGeometry()
centerPoint = QDesktopWidget().availableGeometry().center()
qtRectangle.moveCenter(centerPoint)
self.move(qtRectangle.topLeft())
def initFrame(self):
##### Config #####
globalayout = QHBoxLayout()
configl = QVBoxLayout()
configl.setAlignment(Qt.AlignTop)
## Fichier ##
fichier = QHBoxLayout()
fichierlabel = QLabel("Fichier :")
fichiertext = QLineEdit()
fichier.addWidget(fichierlabel)
fichier.addWidget(fichiertext)
## Refresh ##
refresh = QPushButton("Refresh")
## Coords ##
Xs = QHBoxLayout()
posxlabel = QLabel("x:")
posxtext = QLineEdit()
lxlabel = QLabel("lx:")
lxtext = QLineEdit()
Xs.addWidget(posxlabel)
Xs.addWidget(posxtext)
Xs.addWidget(lxlabel)
Xs.addWidget(lxtext)
Ys = QHBoxLayout()
posylabel = QLabel("y:")
posytext = QLineEdit()
lylabel = QLabel("ly:")
lytext = QLineEdit()
Ys.addWidget(posylabel)
Ys.addWidget(posytext)
Ys.addWidget(lylabel)
Ys.addWidget(lytext)
## Redraw ##
redraw = QPushButton("Redraw")
## Colormap ##
colormap = QHBoxLayout()
colormaplabel = QLabel("Color map :")
colormapchooser = QComboBox()#["Noir","Blanc","Rouge","Vert","Bleu"])
colormap.addWidget(colormaplabel)
colormap.addWidget(colormapchooser)
configl.addLayout(fichier)
configl.addWidget(refresh)
configl.addLayout(Xs)
configl.addLayout(Ys)
configl.addWidget(redraw)
configl.addLayout(colormap)
globalayout.addLayout(configl)
globalayout.addWidget(self.carte)
self.setLayout(globalayout)
lastx,lasty = None,None
def mouseMoveEvent(self,e):
dx,dy = e.x() - self.lastx,e.y() - self.lasty
print(dx/self.generator.w*self.generator.rx,dy/self.generator.h*self.generator.ry)
self.lastx,self.lasty = e.x(),e.y()
self.generator.x += dx/self.generator.w*self.generator.rx
self.generator.y += dy/self.generator.h*self.generator.ry
def mousePressEvent(self,e):
self.lastx,self.lasty = e.x(),e.y()
def mouseReleaseEvent(self,e):
self.lastx,self.lasty = None,None
def closeEvent(self,e):
self.generator.running = False
def getChunk(self,x,y,rx,ry):
if (x,y) not in self.generated:
self.genqueue.append((x,y))
return np.zeroes((rx,ry))
return self.generated[(x,y)]
def updateImage(self):
x,y = self.x,self.y
rx,ry = self.rx,self.ry
w,h = self.w,self.h
lx,ly = w/rx,h/ry
#out = np.zeros((self.WIDTH,self.HEIGTH))
x0 = x-lx/2
x1 = x+lx/2
y0 = y-ly/2
y1 = y+ly/2
cx0,cy0 = int((x0-floor(x0))*rx),int((y0-floor(y0))*ry)
cx1,cy1 = int((x1-floor(x1))*rx),int((y1-floor(y1))*ry)
zx,zy = int((1+floor(x0)-x0)*rx),int((1+floor(y0)-y0)*ry)
print(x0,x1,y0,y1,cx0,cy0,w,h,lx,ly)
for i in range(floor(x0),floor(x1)+1):
for j in range(floor(y0),floor(y1)+1):
chk = self.getChunk(i,j,rx,ry)
cx,dx = cx0 if i==floor(x0) else 0 , cx1 if i==floor(x1) else rx
cy,dy = cy0 if j==floor(y0) else 0 , cy1 if j==floor(y1) else ry
ax,ay = 0 if i==floor(x0) else zx+(i-floor(x0)-1)*rx , 0 if j==floor(y0) else zy+(j-floor(y0)-1)*ry
bx,by = ax + (dx-cx) , ay + (dy-cy)
print(i,j,"->",ax,bx,cx,dx,ay,by,cy,dy)
out[ax:bx,ay:by] = chk[cx:dx,cy:dy]
self.setImage(out)
class Generator(threading.Thread):
label = None
noise = None
generated = {}
genqueue = []
running = True
x,y = 0,0
rx,ry = 256,256
w,h = 512,512
def __init__(self,linkedLabel,noise):
super().__init__()
self.label = linkedLabel
self.noise = noise
def getChunk(self,x,y,rx,ry):
if (x,y) not in self.generated:
self.genqueue.append((x,y))
chunk = self.noise.getChunk(x,y,(rx,ry))
self.generated[(x,y)] = chunk
return self.generated[(x,y)]
def setImage(self,im):
im = np.uint8((im - im.min())/im.ptp()*255.0)
qi = QImage(im.data, im.shape[1], im.shape[0], im.shape[1], QImage.Format_Indexed8)
qp = QPixmap.fromImage(qi)
self.label.setPixmap(qp)
def run(self):
out = np.zeros((self.w,self.h))
while(self.running):
x,y = self.x,self.y
rx,ry = self.rx,self.ry
w,h = self.w,self.h
lx,ly = w/rx,h/ry
#out = np.zeros((self.WIDTH,self.HEIGTH))
x0 = x-lx/2
x1 = x+lx/2
y0 = y-ly/2
y1 = y+ly/2
cx0,cy0 = int((x0-floor(x0))*rx),int((y0-floor(y0))*ry)
cx1,cy1 = int((x1-floor(x1))*rx),int((y1-floor(y1))*ry)
zx,zy = int((1+floor(x0)-x0)*rx),int((1+floor(y0)-y0)*ry)
print(x0,x1,y0,y1,cx0,cy0,w,h,lx,ly)
for i in range(floor(x0),floor(x1)+1):
for j in range(floor(y0),floor(y1)+1):
self.setImage(out)
chk = self.getChunk(i,j,rx,ry)
cx,dx = cx0 if i==floor(x0) else 0 , cx1 if i==floor(x1) else rx
cy,dy = cy0 if j==floor(y0) else 0 , cy1 if j==floor(y1) else ry
ax,ay = 0 if i==floor(x0) else zx+(i-floor(x0)-1)*rx , 0 if j==floor(y0) else zy+(j-floor(y0)-1)*ry
bx,by = ax + (dx-cx) , ay + (dy-cy)
print(i,j,"->",ax,bx,cx,dx,ay,by,cy,dy)
out[ax:bx,ay:by] = chk[cx:dx,cy:dy]
self.setImage(out)
print('Bybye !')
nav = MapNavigator()
seed=42
perl1 = PerlinNoise(10 ,seed)
perl2 = PerlinNoise(5 ,seed)
perl3 = PerlinNoise(1 ,seed)
noise = perl1+.1*perl2+.03*perl3
generator = Generator(nav.carte,noise)
nav.generator = generator
generator.start()
###### Content #####
+234
View File
@@ -0,0 +1,234 @@
# -*- coding: utf-8 -*-
from PyQt5.QtWidgets import (QWidget, QSlider, QApplication,
QHBoxLayout, QVBoxLayout, QLabel, QLineEdit, QDesktopWidget, QPushButton, QComboBox)
from PyQt5.QtCore import QObject, Qt
from PyQt5.QtGui import QPainter, QFont, QColor, QPen, QImage, QPixmap
from perlin import PerlinNoise,FractalNoise
import matplotlib.pyplot as pp
import numpy as np
from math import floor,ceil
from time import sleep
import threading
import sys
#application = QApplication([])
class MapNavigator(QWidget):
carte = QLabel()
def __init__(self):
super().__init__()
self.setWindowTitle("Navigateur")
### Centrer la fenetre ###
self.resize(750,505)
self.initFrame()
self.show()
self.centrer()
def centrer(self):
qtRectangle = self.frameGeometry()
centerPoint = QDesktopWidget().availableGeometry().center()
qtRectangle.moveCenter(centerPoint)
self.move(qtRectangle.topLeft())
def initFrame(self):
##### Config #####
globalayout = QHBoxLayout()
configl = QVBoxLayout()
configl.setAlignment(Qt.AlignTop)
## Fichier ##
fichier = QHBoxLayout()
fichierlabel = QLabel("Fichier :")
fichiertext = QLineEdit()
fichier.addWidget(fichierlabel)
fichier.addWidget(fichiertext)
## Refresh ##
refresh = QPushButton("Refresh")
## Coords ##
Xs = QHBoxLayout()
posxlabel = QLabel("x:")
posxtext = QLineEdit()
lxlabel = QLabel("lx:")
lxtext = QLineEdit()
Xs.addWidget(posxlabel)
Xs.addWidget(posxtext)
Xs.addWidget(lxlabel)
Xs.addWidget(lxtext)
Ys = QHBoxLayout()
posylabel = QLabel("y:")
posytext = QLineEdit()
lylabel = QLabel("ly:")
lytext = QLineEdit()
Ys.addWidget(posylabel)
Ys.addWidget(posytext)
Ys.addWidget(lylabel)
Ys.addWidget(lytext)
## Redraw ##
redraw = QPushButton("Redraw")
## Colormap ##
colormap = QHBoxLayout()
colormaplabel = QLabel("Color map :")
colormapchooser = QComboBox()#["Noir","Blanc","Rouge","Vert","Bleu"])
colormap.addWidget(colormaplabel)
colormap.addWidget(colormapchooser)
configl.addLayout(fichier)
configl.addWidget(refresh)
configl.addLayout(Xs)
configl.addLayout(Ys)
configl.addWidget(redraw)
configl.addLayout(colormap)
globalayout.addLayout(configl)
globalayout.addWidget(self.carte)
self.setLayout(globalayout)
lastx,lasty = None,None
def mouseMoveEvent(self,e):
dx,dy = e.x() - self.lastx,e.y() - self.lasty
print(dx/self.rx,dy/self.ry)
self.lastx,self.lasty = e.x(),e.y()
self.x += -dy/self.rx
self.y += -dx/self.ry
self.updateImage()# TODO separer le updateImage dans un autre thread pour éviter de l'appeler 1000 fois. Plutot set un tag indiquant qu'il faudrait l'appeler.
def mousePressEvent(self,e):
self.lastx,self.lasty = e.x(),e.y()
def mouseReleaseEvent(self,e):
self.lastx,self.lasty = None,None
def closeEvent(self,e):
self.generator.running = False
x,y = 0,0
rx,ry = 256,256
w,h = 512,512
def getChunk(self,x,y,rx,ry):
if (x,y) not in self.generator.generated:
self.generator.genqueue.append((x,y))
return np.zeros((rx,ry))
return self.generator.generated[(x,y)]
def updateImage(self):
x,y = self.x,self.y
rx,ry = self.rx,self.ry
w,h = self.w,self.h
lx,ly = w/rx,h/ry
out = np.zeros((self.w,self.h))
x0 = x-lx/2
x1 = x+lx/2
y0 = y-ly/2
y1 = y+ly/2
cx0,cy0 = int((x0-floor(x0))*rx),int((y0-floor(y0))*ry)
cx1,cy1 = int((x1-floor(x1))*rx),int((y1-floor(y1))*ry)
zx,zy = int((1+floor(x0)-x0)*rx),int((1+floor(y0)-y0)*ry)
print(x0,x1,y0,y1,cx0,cy0,w,h,lx,ly)
for i in range(floor(x0),floor(x1)+1):
for j in range(floor(y0),floor(y1)+1):
chk = self.getChunk(i,j,rx,ry)
cx,dx = cx0 if i==floor(x0) else 0 , cx1 if i==floor(x1) else rx
cy,dy = cy0 if j==floor(y0) else 0 , cy1 if j==floor(y1) else ry
ax,ay = 0 if i==floor(x0) else zx+(i-floor(x0)-1)*rx , 0 if j==floor(y0) else zy+(j-floor(y0)-1)*ry
bx,by = ax + (dx-cx) , ay + (dy-cy)
print(i,j,"->",ax,bx,cx,dx,ay,by,cy,dy)
out[ax:bx,ay:by] = chk[cx:dx,cy:dy]
self.setImage(out)
def setImage(self,im):
im = np.uint8((im - im.min())/im.ptp()*255.0)
qi = QImage(im.data, im.shape[1], im.shape[0], im.shape[1], QImage.Format_Indexed8)
qp = QPixmap.fromImage(qi)
self.carte.setPixmap(qp)
class Generator(threading.Thread):
updatefunc = None
noise = None
res = None
generated = {}
genqueue = []
running = True
def __init__(self,updatefunc,noise,res):
super().__init__()
self.updatefunc = updatefunc
self.noise = noise
self.res = res
def run(self):
while(self.running):
if(len(self.genqueue) > 0):
x,y = self.genqueue.pop(0)
if (x,y) in self.generated:
continue
chunk = self.noise.getChunk(x,y,self.res)
self.generated[(x,y)] = chunk
self.updatefunc()
else:
sleep(0.01)
print('Bybye !')
nav = MapNavigator()
seed=42
perl1 = PerlinNoise(10 ,seed)
perl2 = PerlinNoise(5 ,seed)
perl3 = PerlinNoise(1 ,seed)
noise = perl1+.1*perl2+.03*perl3
generator = Generator(nav.updateImage,noise,(nav.rx,nav.ry))
nav.generator = generator
generator.start()
nav.updateImage()
###### Content #####
+22
View File
@@ -0,0 +1,22 @@
# Auto detect text files and perform LF normalization
* text=auto
# Custom for Visual Studio
*.cs diff=csharp
*.sln merge=union
*.csproj merge=union
*.vbproj merge=union
*.fsproj merge=union
*.dbproj merge=union
# Standard to msysgit
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain
+33
View File
@@ -0,0 +1,33 @@
*.py[cdo]
pythonhosted/
# Editor detritus
*.vim
*.swp
tags
.vscode
# Packaging detritus
*.egg
*.egg-info
dist
build
eggs
parts
bin
var
sdist
develop-eggs
.installed.cfg
# Installer logs
pip-log.txt
# Unit test / coverage reports
coverage
.coverage
.tox
.cache
# Generated documentation
docs/_build
+10
View File
@@ -0,0 +1,10 @@
# Change Log
## 2018-05-01 v1.1.0
+ packaged and released onto [PyPI](https://pypi.org)
+ it seemed ridiculous calling this v1.0.0 given the maturity of this library, so it has become v1.1.0
## in the past v1.0.0
+ the library was created it was used but never packaged.
+5
View File
@@ -0,0 +1,5 @@
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.
+46
View File
@@ -0,0 +1,46 @@
# Minecraft: Pi edition API Python Library
`mcpi` Python library for communicating with [Minecraft: Pi edition](https://minecraft.net/en-us/edition/pi/) and [RaspberryJuice](https://github.com/zhuowei/RaspberryJuice).
## Installation
### Windows
```
pip3 install mcpi
```
### Linux / MacOS
```bash
sudo pip3 install mcpi
```
## History
The [Minecraft: Pi edition](https://minecraft.net/en-us/edition/pi/) Python library was originally created by Mojang and released with Minecraft: Pi edition.
Initial supported was provided for Python 2 only, but during a sprint at PyconUK 2014 it was migrated to Python 3 and [py3minepi](https://github.com/py3minepi/py3minepi) was created.
The ability to hack Minecraft from Python was very popular and the [RaspberryJuice](https://github.com/zhuowei/RaspberryJuice) plugin was created for Minecraft Java edition. RaspberryJuice also extended the API adding additional features.
This python library supports Python 2 & 3 and Minecraft: Pi edition and RaspberryJuice.
Documentation for the Minecraft: Pi edition and RaspberryJuice API's can be found at [www.stuffaboutcode.com/p/minecraft-api-reference.html](http://www.stuffaboutcode.com/p/minecraft-api-reference.html).
It was released onto [PyPI](https://pypi.org) in May 2018.
If you want some cool additional tools for modifying Minecraft, check out [minecraft-stuff](https://minecraft-stuff.readthedocs.io/en/latest/).
## Sources
This library is a collection of the following sources:
+ [Minecraft: Pi edition](https://minecraft.net/en-us/edition/pi/)
+ [Python 3 Minecraft: Pi edition library](https://github.com/py3minepi/py3minepi)
## Licenses
+ mcpi - [LICENSE.txt](https://github.com/martinohanlon/mcpi/blob/master/LICENSE)
+ Minecraft: Pi edition LICENSE - [minecraft-pi-edition-LICENSE.txt](https://github.com/martinohanlon/mcpi/blob/master/minecraft-pi-edition-LICENSE.txt)
View File
+97
View File
@@ -0,0 +1,97 @@
class Block:
"""Minecraft PI block description. Can be sent to Minecraft.setBlock/s"""
def __init__(self, id, data=0):
self.id = id
self.data = data
def __cmp__(self, rhs):
return hash(self) - hash(rhs)
def __eq__(self, rhs):
return self.id == rhs.id and self.data == rhs.data
def __hash__(self):
return (self.id << 8) + self.data
def withData(self, data):
return Block(self.id, data)
def __iter__(self):
"""Allows a Block to be sent whenever id [and data] is needed"""
return iter((self.id, self.data))
def __repr__(self):
return "Block(%d, %d)"%(self.id, self.data)
AIR = Block(0)
STONE = Block(1)
GRASS = Block(2)
DIRT = Block(3)
COBBLESTONE = Block(4)
WOOD_PLANKS = Block(5)
SAPLING = Block(6)
BEDROCK = Block(7)
WATER_FLOWING = Block(8)
WATER = 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)
SNOW = Block(78)
ICE = Block(79)
SNOW_BLOCK = Block(80)
CACTUS = Block(81)
CLAY = Block(82)
SUGAR_CANE = Block(83)
FENCE = Block(85)
GLOWSTONE_BLOCK = Block(89)
BEDROCK_INVISIBLE = Block(95)
STONE_BRICK = Block(98)
GLASS_PANE = Block(102)
MELON = Block(103)
FENCE_GATE = Block(107)
GLOWING_OBSIDIAN = Block(246)
NETHER_REACTOR_CORE = Block(247)
+63
View File
@@ -0,0 +1,63 @@
import socket
import select
import sys
from .util import flatten_parameters_to_bytestring
""" @author: Aron Nieminen, Mojang AB"""
class RequestError(Exception):
pass
class Connection:
"""Connection to a Minecraft Pi game"""
RequestFailed = "Fail"
def __init__(self, address, port):
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.connect((address, port))
self.lastSent = ""
def drain(self):
"""Drains the socket of incoming data"""
while True:
readable, _, _ = select.select([self.socket], [], [], 0.0)
if not readable:
break
data = self.socket.recv(1500)
e = "Drained Data: <%s>\n"%data.strip()
e += "Last Message: <%s>\n"%self.lastSent.strip()
sys.stderr.write(e)
def send(self, f, *data):
"""
Sends data. Note that a trailing newline '\n' is added here
The protocol uses CP437 encoding - https://en.wikipedia.org/wiki/Code_page_437
which is mildly distressing as it can't encode all of Unicode.
"""
s = b"".join([f, b"(", flatten_parameters_to_bytestring(data), b")", b"\n"])
self._send(s)
def _send(self, s):
"""
The actual socket interaction from self.send, extracted for easier mocking
and testing
"""
self.drain()
self.lastSent = s
self.socket.sendall(s)
def receive(self):
"""Receives data. Note that the trailing newline '\n' is trimmed"""
s = self.socket.makefile("r").readline().rstrip("\n")
if s == Connection.RequestFailed:
raise RequestError("%s failed"%self.lastSent.strip())
return s
def sendReceive(self, *data):
"""Sends and receive data"""
self.send(*data)
return self.receive()
+45
View File
@@ -0,0 +1,45 @@
from .vec3 import Vec3
class BlockEvent:
"""An Event related to blocks (e.g. placed, removed, hit)"""
HIT = 0
def __init__(self, type, x, y, z, face, entityId):
self.type = type
self.pos = Vec3(x, y, z)
self.face = face
self.entityId = entityId
def __repr__(self):
sType = {
BlockEvent.HIT: "BlockEvent.HIT"
}.get(self.type, "???")
return "BlockEvent(%s, %d, %d, %d, %d, %d)"%(
sType,self.pos.x,self.pos.y,self.pos.z,self.face,self.entityId);
@staticmethod
def Hit(x, y, z, face, entityId):
return BlockEvent(BlockEvent.HIT, x, y, z, face, entityId)
class ChatEvent:
"""An Event related to chat (e.g. posts)"""
POST = 0
def __init__(self, type, entityId, message):
self.type = type
self.entityId = entityId
self.message = message
def __repr__(self):
sType = {
ChatEvent.POST: "ChatEvent.POST"
}.get(self.type, "???")
return "ChatEvent(%s, %d, %s)"%(
sType,self.entityId,self.message);
@staticmethod
def Post(entityId, message):
return ChatEvent(ChatEvent.POST, entityId, message)
@@ -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
+210
View File
@@ -0,0 +1,210 @@
from .connection import Connection
from .vec3 import Vec3
from .event import BlockEvent, ChatEvent
from .block import Block
import math
from .util import flatten
""" Minecraft PI low level api v0.1_1
Note: many methods have the parameter *arg. This solution makes it
simple to allow different types, and variable number of arguments.
The actual magic is a mix of flatten_parameters() and __iter__. Example:
A Cube class could implement __iter__ to work in Minecraft.setBlocks(c, id).
(Because of this, it's possible to "erase" arguments. CmdPlayer removes
entityId, by injecting [] that flattens to nothing)
@author: Aron Nieminen, Mojang AB"""
""" Updated to include functionality provided by RaspberryJuice:
- getBlocks()
- getDirection()
- getPitch()
- getRotation()
- getPlayerEntityId()
- pollChatPosts() """
def intFloor(*args):
return [int(math.floor(x)) for x in flatten(args)]
class CmdPositioner:
"""Methods for setting and getting positions"""
def __init__(self, connection, packagePrefix):
self.conn = connection
self.pkg = packagePrefix
def getPos(self, id):
"""Get entity position (entityId:int) => Vec3"""
s = self.conn.sendReceive(self.pkg + b".getPos", id)
return Vec3(*list(map(float, s.split(","))))
def setPos(self, id, *args):
"""Set entity position (entityId:int, x,y,z)"""
self.conn.send(self.pkg + b".setPos", id, args)
def getTilePos(self, id):
"""Get entity tile position (entityId:int) => Vec3"""
s = self.conn.sendReceive(self.pkg + b".getTile", id)
return Vec3(*list(map(int, s.split(","))))
def setTilePos(self, id, *args):
"""Set entity tile position (entityId:int) => Vec3"""
self.conn.send(self.pkg + b".setTile", id, intFloor(*args))
def getDirection(self, id):
"""Get entity direction (entityId:int) => Vec3"""
s = self.conn.sendReceive(self.pkg + b".getDirection", id)
return Vec3(*map(float, s.split(",")))
def getRotation(self, id):
"""get entity rotation (entityId:int) => float"""
return float(self.conn.sendReceive(self.pkg + b".getRotation", id))
def getPitch(self, id):
"""get entity pitch (entityId:int) => float"""
return float(self.conn.sendReceive(self.pkg + b".getPitch", id))
def setting(self, setting, status):
"""Set a player setting (setting, status). keys: autojump"""
self.conn.send(self.pkg + b".setting", setting, 1 if bool(status) else 0)
class CmdEntity(CmdPositioner):
"""Methods for entities"""
def __init__(self, connection):
CmdPositioner.__init__(self, connection, b"entity")
class CmdPlayer(CmdPositioner):
"""Methods for the host (Raspberry Pi) player"""
def __init__(self, connection):
CmdPositioner.__init__(self, connection, b"player")
self.conn = connection
def getPos(self):
return CmdPositioner.getPos(self, [])
def setPos(self, *args):
return CmdPositioner.setPos(self, [], args)
def getTilePos(self):
return CmdPositioner.getTilePos(self, [])
def setTilePos(self, *args):
return CmdPositioner.setTilePos(self, [], args)
def getDirection(self):
return CmdPositioner.getDirection(self, [])
def getRotation(self):
return CmdPositioner.getRotation(self, [])
def getPitch(self):
return CmdPositioner.getPitch(self, [])
class CmdCamera:
def __init__(self, connection):
self.conn = connection
def setNormal(self, *args):
"""Set camera mode to normal Minecraft view ([entityId])"""
self.conn.send(b"camera.mode.setNormal", args)
def setFixed(self):
"""Set camera mode to fixed view"""
self.conn.send(b"camera.mode.setFixed")
def setFollow(self, *args):
"""Set camera mode to follow an entity ([entityId])"""
self.conn.send(b"camera.mode.setFollow", args)
def setPos(self, *args):
"""Set camera entity position (x,y,z)"""
self.conn.send(b"camera.setPos", args)
class CmdEvents:
"""Events"""
def __init__(self, connection):
self.conn = connection
def clearAll(self):
"""Clear all old events"""
self.conn.send(b"events.clear")
def pollBlockHits(self):
"""Only triggered by sword => [BlockEvent]"""
s = self.conn.sendReceive(b"events.block.hits")
events = [e for e in s.split("|") if e]
return [BlockEvent.Hit(*list(map(int, e.split(",")))) for e in events]
def pollChatPosts(self):
"""Triggered by posts to chat => [ChatEvent]"""
s = self.conn.sendReceive(b"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):
self.conn = connection
self.camera = CmdCamera(connection)
self.entity = CmdEntity(connection)
self.player = CmdPlayer(connection)
self.events = CmdEvents(connection)
def getBlock(self, *args):
"""Get block (x,y,z) => id:int"""
return int(self.conn.sendReceive(b"world.getBlock", intFloor(args)))
def getBlockWithData(self, *args):
"""Get block with data (x,y,z) => Block"""
ans = self.conn.sendReceive(b"world.getBlockWithData", intFloor(args))
return Block(*list(map(int, ans.split(","))))
def getBlocks(self, *args):
"""Get a cuboid of blocks (x0,y0,z0,x1,y1,z1) => [id:int]"""
s = self.conn.sendReceive(b"world.getBlocks", intFloor(args))
return map(int, s.split(","))
def setBlock(self, *args):
"""Set block (x,y,z,id,[data])"""
self.conn.send(b"world.setBlock", intFloor(args))
def setBlocks(self, *args):
"""Set a cuboid of blocks (x0,y0,z0,x1,y1,z1,id,[data])"""
self.conn.send(b"world.setBlocks", intFloor(args))
def getHeight(self, *args):
"""Get the height of the world (x,z) => int"""
return int(self.conn.sendReceive(b"world.getHeight", intFloor(args)))
def getPlayerEntityIds(self):
"""Get the entity ids of the connected players => [id:int]"""
ids = self.conn.sendReceive(b"world.getPlayerIds")
return list(map(int, ids.split("|")))
def getPlayerEntityId(self, name):
"""Get the entity id of the named player => [id:int]"""
return int(self.conn.sendReceive(b"world.getPlayerId", name))
def saveCheckpoint(self):
"""Save a checkpoint that can be used for restoring the world"""
self.conn.send(b"world.checkpoint.save")
def restoreCheckpoint(self):
"""Restore the world state to the checkpoint"""
self.conn.send(b"world.checkpoint.restore")
def postToChat(self, msg):
"""Post a message to the game chat"""
self.conn.send(b"chat.post", msg)
def setting(self, setting, status):
"""Set a world setting (setting, status). keys: world_immutable, nametags_visible"""
self.conn.send(b"world.setting", setting, 1 if bool(status) else 0)
@staticmethod
def create(address = "localhost", port = 4711):
return Minecraft(Connection(address, port))
if __name__ == "__main__":
mc = Minecraft.create()
mc.postToChat("Hello, Minecraft!")
+36
View File
@@ -0,0 +1,36 @@
from setuptools import setup
__project__ = 'mcpi'
__desc__ = 'Python library for the Minecraft Pi edition and RaspberryJuice API'
__version__ = '1.1.0'
__author__ = "Martin O'Hanlon"
__author_email__ = 'martin@ohanlonweb.com'
__license__ = 'MIT'
__url__ = 'https://github.com/martinohanlon/mcpi'
__classifiers__ = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Education",
"Intended Audience :: Developers",
"Topic :: Education",
"Topic :: Games/Entertainment",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
]
setup(name=__project__,
version = __version__,
description = __desc__,
url = __url__,
author = __author__,
author_email = __author_email__,
license = __license__,
packages = [__project__],
classifiers = __classifiers__,
zip_safe=False)
+18
View File
@@ -0,0 +1,18 @@
import collections
def flatten(l):
for e in l:
if isinstance(e, collections.Iterable) and not isinstance(e, str):
for ee in flatten(e): yield ee
else: yield e
def flatten_parameters_to_bytestring(l):
return b",".join(map(_misc_to_bytes, flatten(l)))
def _misc_to_bytes(m):
"""
Convert an arbitrary object into a string encoded as a CP437 series of bytes.
See `Connection.send` for more details.
"""
return str(m).encode("cp437")
+114
View File
@@ -0,0 +1,114 @@
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 __eq__(self, rhs):
if self.x == rhs.x and self.y == rhs.y and self.z == rhs.z:
return True
return False
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()
+69
View File
@@ -0,0 +1,69 @@
# -*- coding: utf-8 -*-
"""
Created on Fri Jun 14 14:16:11 2019
@author: savrillon
"""
from data import WorldChunk
import math
import numpy as np
import mcpi.minecraft as minecraft
import random
import mcpi.block as block
from perlin import CavernedNoise2
mc = minecraft.Minecraft.create()
mc.postToChat("Hello World !")
playerPos = mc.player.getPos()
tp = True
lights = True
chunk = (math.floor(playerPos.x/16),math.floor(playerPos.z/16))
noise = CavernedNoise2(456)
size = 64
for i in range(0,size):
for j in range(0,size):
cx,cy = chunk[0]+i,chunk[1]+j
print("Géneration de "+str(i)+","+str(j))
mc.postToChat("Géneration de "+str(i)+","+str(j))
if tp:
mc.player.setPos(cx*16+8,playerPos.y,cy*16+8)
data = noise.getChunk(cx,cy,(16,16))
#print(data)
#data = np.abs(data)
x0,z0 = cx*16,cy*16
x1,z1 = x0 + 15 , z0 + 15
y0,y1 = 4,128-1
h = y1-y0
mc.setBlocks(x0,y0,z0,x1,y1,z1,block.IRON_BLOCK)
for dx in range(0,16):
for dz in range(0,16):
x,z = x0+dx,z0+dz
boule = True
fm1 = y0
for f in sorted(data[dx][dz]):
if f < 0 :print(f)
mc.setBlocks(x,y0+fm1,z,x,y0+f,z,block.STONE if boule else block.AIR)
#mc.setBlock(x,y0+fm1,z,x,d,z,block.STONE if boule else block.AIR)
boule = not boule
fm1 = f
mc.setBlocks(x,y0+fm1,z,x,y1,z,block.AIR)
if(lights):
for _ in range(256*size**2):
x=random.randint(0,size*16)+chunk[0]*16
y=random.randint(y0,y1)
x=random.randint(0,size*16)+chunk[1]*16
if(mc.getBlock(x,y,z)==block.STONE.id):
mc.setBlock(x,y,z,block.GLOWSTONE_BLOCK)
print(chunk)
+374
View File
@@ -0,0 +1,374 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Aug 22 19:46:36 2019
@author: mysaa
"""
import numpy as np
from data import CollageWorldChunk
from perlin import CavernedNoise2,TestNoise
def getTriangles(x0,y0,chunk,xp,yp,xy):
nx,ny = chunk.size
newChunk = CollageWorldChunk(chunk,xp,yp,xy)
# pointIndexes = np.zeros((nx+1,ny+1),dtype=np.uint32)
# pointLengthes = np.zeros((nx+1,ny+1),dtype=np.uint32)
# points = []
#
#
# pos = 0
# for j in range(ny):
# for i in range(nx):
# carotte = [(x0+i/nx,y0+j/ny,z) for z in sorted([0.]+list(chunk.getColumn(i,j)))]
# points += carotte
# pointLengthes[i,j] = len(carotte)
# pointIndexes[i,j] = pos
# pos+=len(carotte)
# carotte = [(x0+1,y0+j/ny,z) for z in sorted([0.]+list(xp.getColumn(0,j)))]
# points += carotte
# pointLengthes[nx,j]= len(carotte)
# pointIndexes[nx,j] = pos
# pos+=len(carotte)
# for i in range(nx):
# carotte = [(x0+i/nx,y0+1,z) for z in sorted([0.]+list(yp.getColumn(i,0)))]
# points += carotte
# pointLengthes[i,ny] = len(carotte)
# pointIndexes[i,ny] = pos
# pos+=len(carotte)
# carotte = [(x0+1,y0+1,z) for z in sorted([0.]+list(xy.getColumn(0,0)))]
# points += carotte
# pointLengthes[nx,ny] = len(carotte)
# pointIndexes[nx,ny] = pos
points,pointIndexes = newChunk.getIndexed(fullCoords=True,addZero=True)
points=[(p[0]/nx+x0,p[1]/ny+y0,p[2]) for p in points]
pointLengthes = np.reshape([pointIndexes[i+1]-pointIndexes[i] for i in range(len(pointIndexes)-1)],(nx+1,ny+1))
pointIndexes = np.reshape(pointIndexes[:-1],(nx+1,ny+1))
print(points,pointIndexes,pointLengthes)
triangles = []
for x in range(nx*2):
for y in range(ny):
# On récupère les coordonées entières du triangle indicé (x,y)
if(x%2==0):
col0=(x//2 ,y )
col1=(x//2+1,y )
col2=(x//2 ,y+1)
else:
col0=(x//2+1,y+1)
col1=(x//2+1,y )
col2=(x//2 ,y+1)
# On récupère la liste des points dans la colonne
colonne0 = points[pointIndexes[col0[0],col0[1]]:pointIndexes[col0[0],col0[1]]+pointLengthes[col0[0],col0[1]]]
colonne1 = points[pointIndexes[col1[0],col1[1]]:pointIndexes[col1[0],col1[1]]+pointLengthes[col1[0],col1[1]]]
colonne2 = points[pointIndexes[col2[0],col2[1]]:pointIndexes[col2[0],col2[1]]+pointLengthes[col2[0],col2[1]]]
#print("colonne:",colonne1)
# st contient des triplets (numéro de colonne,index interne dans la colonne,coordonée z)
st = [(0,i,colonne0[i][2]) for i in range(len(colonne0))]
st += [(1,i,colonne1[i][2]) for i in range(len(colonne1))]
st += [(2,i,colonne2[i][2]) for i in range(len(colonne2))]
# On y trie par coordonée z
st = sorted(st,key=lambda c:c[2])
#Liste des coordonées des colonnes, pour pouvoir sélectionner les coordonées selon l'index de la colonne
cols = [col0,col1,col2]
# Là, tout est bon à peu près
i=0
try:
while i<len(st):
v1 = st[i] ; i+=1
v2 = st[i] ; i+=1
if v1[0]==v2[0]: continue #Cas où une colonne apparait puis disparaît
von = [v1,v2,None]
voff = [None,None,None]
while not None in von and voff!=[None,None,None]:
# On est dans la chaine aller-retour 2/1
v3 = st[i] ; i+=1
if voff[v3[0]]==None and von[v3[0]]!=None:
# Il s'agit d'un changement plein->vide
voff[v3[0]] = v3
else:
# Changement vide->plein
von[v3[0]] = v3
voff[v3[0]] = None
if not None in von and not None in voff:
# Les deux colonnes ont disparu
# On peut créer le rectangle entre les deux derniers à avoir disparu et leur point d'apparitions
v3,v4 = st[i],st[i-1]
v1,v2 = von[v3[0]],von[v4[0]]
triangle1 = [pointIndexes[cols[v[0]]] + v[1] for v in (v1,v2,v3)]
triangle2 = [pointIndexes[cols[v[0]]] + v[1] for v in (v1,v3,v4)]
triangles.append(triangle1)
triangles.append(triangle2)
break
else:
# On est dans le cas ou v1,v2,v3 correspondent à trois colonnes
# différentes (le cas (1,1,1) ayant déjà été filtré par la première condition)
# On ajoute le triangle en dessous
triangle = [pointIndexes[cols[v[0]]] + v[1] for v in (v1,v2,v3)]
triangles.append(triangle)
# On "attends" jusqu'à ce que les trois colonnes soient à nouveau vides
vs = [None,None,None]
while None in vs:
print("Quentin",st,i,vs)
v = st[i] ; i+=1
vs[v[0]] = v if vs[v[0]]==None else None
# Avec cette mthode, on déssine le triangle avec les derniers points étant apparus (les plus hauts)
triangle = [pointIndexes[cols[v[0]]] + v[1] for v in vs]
triangles.append(triangle)
continue
except ValueError:
# Une fin de liste a été atteinte, la colonne n'a pas été refermée: lance un warn
print("Attention ! Une colonne n'avait pas de toit. veuillez vérifier que vos colonnes aient un nombre impair de coordonées, merci !")
return points,triangles
########################################
# while i<len(st):
# #Plein
# v0 = st[i]
# i+=1
# v1 = st[i]
# i+=1
# if(v0[0] == v1[0]): # S'est la même colonne qui est apparu puis disparu
#
# print("Tribord")
# colz = cols[v0[0]]
# # Triangle sur les bords
# # Demis-points
# halfZ = (v0[2]+v1[2])/2
# #Les deux autres colonnes sont :
# cola = cols[(v0[0]+1)%3]
# colb = cols[(v0[0]+2)%3]
#
# zi1,zi2=pointIndexes[colz]+v0[1],pointIndexes[colz]+v1[1]
# print('OoOOoO',points[zi1],points[zi2])
#
## points.append( (x0+(cola[0])/nx,y0+(cola[1])/ny,halfZ) )
## points.append( (x0+(colb[0])/nx,y0+(colb[1])/ny,halfZ) )
##
## triangles.append([zi1,len(points)-1,len(points)-2])
## triangles.append([zi2,len(points)-1,len(points)-2])
# print("Tribord-fin")
# # print(points[-1],points[-2],points[zi1])
# #print(cola,colb,points[triangles[-1][0]-1],points[triangles[-1][1]-1],points[triangles[-1][2]-1])
#
# else: # Deux colonnes différentes ont apparus successivement
# # vs stoque les états des colonnes
# # vs[i] est l'état de la ième colonne, le point de st, dernier à apparaître si
# # cette colonne est présente, None sinon
# vs=[None,None,None]
# vs[v0[0]] = v0
# vs[v1[0]] = v1
# while None in vs and vs != [None,None,None]:# Tant qu'il y a une abscente ou une présente
# v2 = st[i]
# i+=1
# vs[v2[0]] = v2 if vs[v2[0]]==None else None
#
# if not None in vs:
# # Une face complète a été créée
# # Triangle complet
# # Face dessous (apparition de la colonne)
# triangle = [pointIndexes[cols[i]] + vs[i][1] for i in range(3)]
# triangles.append(triangle)
# #print("#",[points[triangle[i]] for i in range(0,3)])
#
#
# # On inverse le sens de vs, et stoque les premiers points à apparaître
# vs = [None,None,None]
# while None in vs and i<len(st):
# v2 = st[i]
# i+=1
# vs[v2[0]] = v2 if vs[v2[0]]==None else None
#
# #Face dessus
# if not None in vs:
# triangle = [pointIndexes[cols[i]] + vs[i][1] for i in range(3)]
# triangles.append(triangle)
# #print("0",[points[triangle[i]] for i in range(3)])
# else:
# # Il faut placer un carré
# #########################################
# print(points)
# return points,triangles
def getRectangles(x0,y0,chunk):
nx,ny = chunk.size
triangles = []
points = []
for x in range(nx) :
for y in range(ny):
for z in [0]+chunk.getColumn(x,y):
points.append([x/nx+x0,y/ny+y0,z])
points.append([x/nx+x0+1/nx,y/ny+y0,z])
points.append([x/nx+x0,y/ny+y0+1/ny,z])
points.append([x/nx+x0+1/nx,y/ny+y0+1/ny,z])
triangles.append([len(points)-4,len(points)-3,len(points)-2])
triangles.append([len(points)-3,len(points)-2,len(points)-1])
return points,triangles
def getRectCols(x0,y0,chunk):
nx,ny = chunk.size
triangles = []
points = []
e=0.3
for x in range(nx) :
for y in range(ny):
for z in [0]+chunk.getColumn(x,y):
points.append([x/nx+x0-e,y/ny+y0-e,z])
points.append([x/nx+x0+e,y/ny+y0-e,z])
points.append([x/nx+x0-e,y/ny+y0+e,z])
points.append([x/nx+x0+e,y/ny+y0+e/ny,z])
triangles.append([len(points)-4,len(points)-3,len(points)-2])
triangles.append([len(points)-3,len(points)-2,len(points)-1])
return points,triangles
def getFilled(x0,y0,chunk):
nx,ny = chunk.size
triangles = []
points = []
for x in range(nx) :
for y in range(ny):
boule = True
lz = 0
for z in sorted(chunk.getColumn(x,y)):
if boule:
points.append([x/nx+x0 ,y/ny+y0 ,z ])
points.append([x/nx+x0+1/nx,y/ny+y0 ,z ])
points.append([x/nx+x0 ,y/ny+y0+1/ny,z ])
points.append([x/nx+x0+1/nx,y/ny+y0+1/ny,z ])
points.append([x/nx+x0 ,y/ny+y0 ,lz])
points.append([x/nx+x0+1/nx,y/ny+y0 ,lz])
points.append([x/nx+x0 ,y/ny+y0+1/ny,lz])
points.append([x/nx+x0+1/nx,y/ny+y0+1/ny,lz])
l = len(points)
triangles.append([l-4,l-2,l-1])
triangles.append([l-4,l-3,l-1])
triangles.append([l-4,l-2,l-6])
triangles.append([l-4,l-8,l-6])
triangles.append([l-4,l-3,l-7])
triangles.append([l-4,l-8,l-7])
triangles.append([l-5,l-1,l-2])
triangles.append([l-5,l-6,l-2])
triangles.append([l-5,l-6,l-8])
triangles.append([l-5,l-7,l-8])
triangles.append([l-5,l-7,l-3])
triangles.append([l-5,l-1,l-3])
boule = not boule
lz = z
return points,triangles
def printObject(file,name,delta,points,triangles):
file.write("o "+name+"\n\n")
sf = lambda x : "%.6f" % float(x)
si = lambda x : str(int(x+1)+delta)
for p in points:
file.write("v "+sf(p[0])+" "+sf(p[1])+" "+sf(np.array(p[2])/20.)+"\n")
file.write("\n")
for t in triangles:
file.write("f "+" ".join([si(tp) for tp in t])+"\n")
def writeMap(filePath,noise,x0,y0,sx,sy,cx,cy,objType='triangle',log=print):
log("Génération de la carte")
generated = {}
formatter='\rÉcriture du chunk {};{} '+" "*(sx//10+sy//10)
for i in range(x0,sx+x0+(1 if objType=='triangle' else 0)):
for j in range(y0,sy+y0+(1 if objType=='triangle' else 0)):
log(formatter.format(i,j), end='\r')
generated[(i,j)] = noise.getChunk(i,j,(cx,cy))
log("Génération des objets")
file = open(filePath,"w+")
file.write("g carte\n")
delta=0
for i in range(x0,sx+x0):
for j in range(y0,sy+y0):
log(formatter.format(i,j), end='\r')
if objType=='triangle':
points,triangles = getTriangles(i,j,generated[(i,j)],generated[(i+1,j)],generated[(i,j+1)],generated[(i+1,j+1)])
elif objType=='rectangle':
points,triangles = getRectangles(i,j,generated[(i,j)])
elif objType=='filled':
points,triangles = getFilled(i,j,generated[(i,j)])
elif objType=='rectcols':
points,triangles = getRectCols(i,j,generated[(i,j)])
else:
raise ValueError("Je en connais pas le type d'objet "+objType)
printObject(file,"chunk_"+objType+"_"+str(i)+"-"+str(j),delta,points,triangles)
file.write("\n\n")
delta+=len(points)
log("\nTerminé ! "+" "*(sx//10+sy//10))
file.close()
noise = CavernedNoise2(93152)
size = 12
taille=16
#writeMap("gros.obj",noise,-size//2+1,-size//2+1,size,size,taille,taille,'triangle')
#writeMap("carte.obj",noise,2,1,1,1,16,16,'triangle')
writeMap("carteTri.obj",noise,-8,-8,16,16,16,16,'triangle')
#writeMap("carteRec.obj",noise,-8,-8,16,16,16,16,'rectangle')
#writeMap("carteFil.obj",noise,-8,-8,16,16,16,16,'filled')
#writeMap("carteRCo.obj",noise,-8,-8,16,16,16,16,'rectcols')
#xy0=-taille*size
#for x in range(2*taille):
# for y in range(2*taille):
#
# writeMap("render2/carte"+str(x)+","+str(y)+".obj",noise,xy0-size//2+x*size,xy0-size//2+y*size,size,size,'rectangle')
Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

+461
View File
@@ -0,0 +1,461 @@
# -*- coding: utf-8 -*-
"""
Created on Fri Mar 8 15:13:12 2019
Ce module contient de nombreuses implémentations de Noise, permetant en les assemblant de créer des mondes
@author: mysaa
"""
from data import ArrayedWorldChunk,Noise
import random as r
import numpy as np
from math import sqrt,floor,ceil,pi
##### Paramètres #####
G = 4.5
F = 5.2
class RandNoise(Noise):
"""
Ce bruit renvoie une carte de vecteurs complexes (2d) du cercle trigonométrique (de module 1)
"""
seed = None
f = None
def __init__(self,seed,f=lambda r : r.random()):
self.seed = seed
self.f = f
def getRandomly(self,xg,yg):
"""
Cette fonction renvoie un nombre complexe aléatoire du cercle
trigonométrique, uniformément distribué selon l'argument.
Cette fonction est déterministe pour un même seed demandé.
"""
s = ((self.seed & 0xFFFFFFFFFFFFFFFF) << 64) | ((int(xg) & 0xFFFFFFFF) << 32) | (int(yg) & 0xFFFFFFFF)
r.seed(s)
return self.f(r)
def getChunk(self,x,y,n):
"""
x,y sont les coordonées du chunk à considérer (boucle au bout de 4294967296=2^32) java:int
n est un couple ou une liste d'aumoins deux éléments contenant la précision suivant x et y du chunk
"""
randomizer = lambda i,j : self.getRandomly(x+i,y+j)
return np.fromfunction(np.vectorize(randomizer),(n[0],n[1]))
class RandLinNoise(RandNoise):
y0 = 0
y1 = 1
def __init__(self,seed,y0,y1):
super().__init__(seed,lambda r : (y1-y0)*r.random() + y0)
class RandTrigNoise(RandNoise):
def __init__(self,seed):
super().__init__(seed,lambda r : np.exp(1j*2*pi*r.random()))
class DroiteNoise(Noise):
seed = None
F,D = 0,0
def __init__(self,seed,F,D):
self.seed = seed
self.F,self.D = F,D
def getChunk(self,x,y,n=None):
return self.getLoadedDroites(x,y)
# randomizer = lambda i,j : self.getRandomGradient(x+i,y+j)
#
# return np.fromfunction(np.vectorize(randomizer),(n,))
def getLoadedDroites(self,x,y):
"""
Cette fonction renvoie la liste des droites devant être considérées dans la génération du chunk x,y. Cela permet d'effectuer la génération procédurale.
"""
def dst(x0,x1,y0,y1):
"""
Cette fonction renvoie la ditance eucildienne 2D entre les points (x0,y0) et (x1,y1)
"""
return sqrt( (x1-x0)**2 + (y1-y0)**2 )
F = self.F
x0 = floor(x-F)
x1 = floor(x+F+1)
y0 = floor(y-F)
y1 = floor(y+F+1)
# print(x0,x1,y0,y1)
drts = []
for i in range(x0,x1+1):
for j in range(y0,y1+1):
for d in self.getDroitesOnChunk(i,j):
# Tester si la droite sera utile
dx = d[0]+i
dy = d[1]+j
if (x <= dx <= x+1 and y-F <= dy <= y+F+1) or (y <= dy <= y+1 and x-F <= dx <= x+F+1) or (min(dst(x,dx,y,dy),dst(x+1,dx,y,dy),dst(x+1,dx,y+1,dy),dst(x,dx,y+1,dy)) <= F):
drts.append((dx,dy,d[2]))
# print(len(drts))
return drts
def getDroitesOnChunk(self,xg,yg):
s = ((self.seed & 0xFFFFFFFFFFFFFFFF) << 64) | ((int(xg) & 0xFFFFFFFF) << 32) | (int(yg) & 0xFFFFFFFF)
r.seed(s)
L = []
for i in range(self.D):
lx = r.random()
ly = r.random()
theta = r.random()*2*pi
L.append((lx,ly,theta))
return L
class PerlinNoise(Noise):
G = None
randomizer = None
interpol = None
wrapper = None
def __init__(self,G,randomizer,interpol=lambda a,b,w : (b-a)*w**2*6*(1/2-w/3)+a,wrapper = lambda x : np.tanh(x*3.8622)): # Par défaut, un banale interpolation linéaire
self.G = G
if type(randomizer) == int:
randomizer = RandTrigNoise(randomizer)
self.randomizer = randomizer
self.interpol = interpol
self.wrapper = wrapper
def getChunkGradients(self,x,y):
G=self.G # Python de merde !
x0 = floor(x/G)
x1 = ceil((x+1)/G)
y0 = floor(y/G)
y1 = ceil((y+1)/G)
nx = x1-x0+1
ny = y1-y0+1
# grads = np.fromfunction(np.vectorize(lambda x,y : self.getPerlinGradient(x+x0,y+y0)),(nx,ny))
grads = self.randomizer.getChunk(x0,y0,(nx,ny))
return grads,x0,y0
def getChunk(self,x,y,n):
G = self.G
chunk = np.zeros(n) # Initialise la sortie
gradients,x0,y0 = self.getChunkGradients(x,y)
def dotGridGradient(ix, iy, tx, ty):
dx = tx - ix
dy = ty - iy
return (np.conj(gradients[ix-x0][iy-y0])*(dx+1j*dy)).real
for i in range(n[0]):
for j in range(n[1]):
#C------------D#
#| |#
#| |#
#| |#
#| x M |#
#| |#
#A------------B#
posx = x + i/n[0]
posy = y + j/n[1]
xx = posx / G
yy = posy / G
xx0 = floor(xx)
yy0 = floor(yy)
xx1 = xx0 + 1
yy1 = yy0 + 1
gA = dotGridGradient(xx0, yy0, xx, yy);
gB = dotGridGradient(xx1, yy0, xx, yy);
gC = dotGridGradient(xx0, yy1, xx, yy);
gD = dotGridGradient(xx1, yy1, xx, yy);
haut = self.interpol(gA, gB, xx - xx0);
bas = self.interpol(gC, gD, xx - xx0);
valeur = self.interpol(haut, bas, yy - yy0);
chunk[i,j] = valeur
return self.wrapper(chunk)
class FractalNoise(Noise):
F = None
D = None
epsilon = None
interpol = None
droiteMaker = None
def interpolizer(n,F):
"""
Retourne une fonction polynomiale réelle sur [-F,F] et nulle autre part, s'annule en F et -F, vaut 1 en 0 et a comme dérivée 0 en -F,0 et F. n+1 est le degré de la racine 0.
"""
return lambda x : 0 if abs(x)>F else 1 + (2*n**2+6*n+4)/(F**(2*n+4)) * ((x**2)/(2*n+4)-(F**2)/(2*n+2))*abs(x)**(2*n+2)
def __init__(self,F,D,epsilon,droiteMaker,n = 1):
self.F = F
self.D = D
self.epsilon = epsilon
if type(droiteMaker) == int:
droiteMaker = DroiteNoise(droiteMaker,F,D)
self.droiteMaker = droiteMaker
self.interpol = FractalNoise.interpolizer(n,F)
def getChunk(self,x,y,n):
drts = self.droiteMaker.getChunk(x,y)
chunk = np.zeros(n)
epsilon = self.epsilon
interpol = self.interpol
def dst(x0,x1,y0,y1):
return sqrt( (x1-x0)**2 + (y1-y0)**2 )
def kelkote(drt,x,y):
dx = drt[0]
dy = drt[1]
#print(x,y,dx,dy)
return 1 if (np.exp(1j*(drt[2]+pi/2)) * ((x-dx)+(dy-y)*1j)).real >= 0 else -1
# FractalNoise(0.7,511,0.01,42).getChunk(3,3,(16,16))
#33.8 s ± 72.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
for d in drts:
drteffect = lambda i,j : interpol(dst(d[0],i/n[0] + x,d[1],j/n[1] + y))*kelkote(d,i/n[0] + x,j/n[1] + y)*epsilon
chunk += np.fromfunction(np.vectorize(drteffect),n)
# FractalNoise(0.7,511,0.01,42).getChunk(3,3,(16,16))
#28.9 s ± 344 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
# for i in range(n[0]):
# for j in range(n[1]):
# posx = i/n[0] + x
# posy = j/n[1] + y
# value = 0
## print(i,j)
# for d in drts:
# value += interpol(dst(d[0],posx,d[1],posy))*kelkote(d,posx,posy)*epsilon
# chunk[i,j] = value
return chunk
class TestNoise(Noise):
nn = PerlinNoise
def getChunk(self,x,y,n):
indexes = np.array([i for i in range(n[0]*n[1]+1)])
data = np.ones((n[0]*n[1]))
return WorldChunk(n,indexes,data)
class CavernedNoise(Noise):
perlinSurface = None
perlinGrotte = None
perlinFond = None
def __init__(self):
self.perlinSurface = PerlinNoise(.5,64)
self.perlinGrotte = PerlinNoise(7 ,77)
self.perlinFond = PerlinNoise(.3 ,23)
def getChunk(self,x,y,n):
chk = self.perlinSurface.getChunk(x,y,n)
fond = self.perlinFond.getChunk(x,y,n)
grotte=self.perlinGrotte.getChunk(x,y,n)
out = []
for i in range(n[0]):
lig = []
for j in range(n[1]):
if(grotte[i,j]>.2): # Pas de grotte
lig.append([chk[i,j]])
elif(grotte[i,j]>0):
lig.append([fond[i,j]])
else:
lig.append([fond[i,j],chk[i,j]-0.1*abs(grotte[i,j]),chk[i,j]])
out.append(lig)
return out
class CavernedNoise2(Noise):
perlinCielH = None
perlinGHaut = None
perlinGH = None
perlinGHp = None
perlinGBas = None
#-x^(4)+4x^(3)-6x^(2)+4x
def __init__(self,seed):
self.perlinCielH = PerlinNoise(7 ,seed)
self.perlinGHaut = PerlinNoise(5 ,seed)
self.perlinGH = PerlinNoise(25 ,seed)
self.perlinGHp = PerlinNoise(1 ,seed)
self.perlinGBas = PerlinNoise(5 ,seed)
def getChunk(self,x,y,n):
gtTransform = np.vectorize(lambda x : 0 if x<0 else sqrt(2*x-x**2)**1.5)
transform=lambda M,a,b : M*b+a
cielH = transform(self.perlinCielH.getChunk(x,y,n),28,28)
gHaut = transform(self.perlinGHaut.getChunk(x,y,n),60,20)
ghp = transform(self.perlinGHp.getChunk(x,y,n) ,0.005,0.005)
ghh = transform(self.perlinGHp.getChunk(x,y,n) ,0.5,0.5)
gBas = transform(self.perlinGBas.getChunk(x,y,n),10,10)
gh = gtTransform(ghp+ghh)
toit = 128
out = []
for i in range(n[0]):
lig = []
for j in range(n[1]):
ch = cielH[i,j] # la hauteur entre la surface et le ciel
ght = gHaut[i,j] # haut limite de la grotte
gbs = gBas[i,j] # bas limite de la grotte
hauteur=gh[i,j] # pourcentage de hauteur de la grotte
grh = (ght+gbs +hauteur*(ght-gbs))/2 # vrai plafond de la grotte
grb = (ght+gbs -hauteur*(ght-gbs))/2 # vrai sol de la grotte
if(ght<=40):print(ght)
if hauteur==0:
# Pas de grotte
lig.append([toit-ch])
elif(grh+ch>=toit):
# La grotte est ouverte sur la surface
lig.append([grb])
else:
# Grotte souterraine et surface
lig.append([grb,grh,toit-ch])
out.append(lig)
return ArrayedWorldChunk.fromList(out)
#for c in cmaps:
# pp.figure()
# print(c)
# pp.imshow(I, cmap=c)
#sys.exit()
####### Fenêtre graphique #######
#from PyQt5.QtWidgets import QVBoxLayout,QHBoxLayout,QPushButton,QWidget,QApplication,QFormLayout,QLabel,QTextEdit,QDial
#
#app = QApplication([])
#
#class ExplorerWidget(QWidget):
#
# def __init__():
# print('wow')
#
##### Control Panel ####
#seedSelector = QTextEdit()
#ndroitesSelector = QDial()
#
#cPanel = QFormLayout()
#cPanel.addWidget(QLabel("Seed : "))
#cPanel.addWidget(seedSelector)
#cPanel.addWidget(QLabel("Nombre de droites :"))
#cPanel.addWidget(ndroitesSelector)
#
#globalL = QHBoxLayout()
#globalL.addStretch(1)
#globalL.addLayout(cPanel)
#
#window = QWidget()
#window.setLayout(globalL)
#window.show()
#
#app.exec_()
#
#(x0,x1,y0,y1) = (0,4,0,4)
#n = 100
#
#
#x = np.linspace(x0,x1,n)
#y = np.linspace(y0,y1,n)
#x00 = int(x0)-1
#y00 = int(y0)-1
#x11 = int(x1)+1
#y11 = int(y1)+1
#gradient = np.exp(np.random.rand(x11-x00+1,y11-y00+1)*2*np.pi*1j)
#X,Y = np.meshgrid(x,y)
##print(gradient)
#
#def lerp(a0, a1, w):
# return a0 + (a1-a0)*(-2*w*w*w+3*w*w)
#
#def dotGridGradient(ix, iy, x, y):
# dx = x - ix
# dy = y - iy
# return (np.conj(gradient[iy-y00][ix-x00])*(dx+1j*dy)).real
#
#def bruit(x,y):
# (x0,y0) = (int(x),int(y))
# (x1,y1) = (x0+1,y0+1)
#
# sx = x - x0;
# sy = y - y0;
#
# n0 = dotGridGradient(x0, y0, x, y);
# n1 = dotGridGradient(x1, y0, x, y);
# ix0 = lerp(n0, n1, sx);
# n0 = dotGridGradient(x0, y1, x, y);
# n1 = dotGridGradient(x1, y1, x, y);
# ix1 = lerp(n0, n1, sx);
# return lerp(ix0, ix1, sy);
#
#
#
#Z = np.zeros((n,n))
#for i in range(n):
# for j in range(n):
# Z[i,j] = bruit(x[i],y[j])
#
#pp.imshow(Z,cmap='autumn')
#
#fig = pp.figure()
#ax = pp.axes(projection='3d')
#
#ax.view_init(80, 42)
#ax.plot_surface(X,Y,Z, rstride=1, cstride=1,
# cmap='autumn', edgecolor='none')
Binary file not shown.

After

Width:  |  Height:  |  Size: 229 KiB

+23
View File
@@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
"""
Created on Thu Nov 21 11:49:30 2019
@author: savrillon
"""
from perlin import PerlinNoise
import numpy as np
graine = 42
zoom=0.2
pos = np.random.randint(0,0xFFFFFFF,(2,))
taille=(100,100)
P = PerlinNoise(zoom,graine)
chunk = P.getChunk(pos[0],pos[1],taille)
chunk -= (chunk<0)*chunk
chunk *= 1000
chunk = chunk.astype(int)
print(chunk)
+35
View File
@@ -0,0 +1,35 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Aug 29 23:53:47 2019
@author: mysaa
"""
import numpy as np
import matplotlib.pyplot as pp
import random as rnd
import perlin
N = 42
values = []
pp.xlabel('valeur')
pp.ylabel('compte')
pp.title('Valeur du bruit de perlin')
#tt = np.vectorize(lambda x : x//0.01)
noise = perlin.PerlinNoise(2.3,42)#,wrapper = lambda x : np.tanh(x*3.8622))
while True:
#print("\r{}".format(i), end='\r')
for _ in range(N):
chunk = noise.getChunk(rnd.randint(0,167342),rnd.randint(0,941132),(16,16))
values += np.reshape(chunk, (1,256))[0].tolist()
[n,X, V]=pp.hist(values,range=(-1,1),bins=201,log=True, color = '#2aff00',edgecolor = 'black')
pp.draw()
pp.pause(0.1)
#pp.figure()
#X = np.linspace(-1,1,2000)
#pp.plot(X,X)
+14
View File
@@ -0,0 +1,14 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Module contant les fonctions permettant de lire et écrire des fichiers dans le format TMF
@author: mysaa
"""
class WorldSaver():
def __init__():
regSize=0
Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB