Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update project to Python3 (2.7 -> 3.6) #91

Merged
merged 9 commits into from
Apr 21, 2019
17 changes: 13 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,19 @@ For git:

For optimal performance, you can compile the code to C using Cython.

To do so, you have to install Cython and Python dev files
(`sudo apt-get install cython python-dev` under Ubuntu), then run
`python setup.py build_ext --inplace`. You will have
to run this last command each time you update the game.
```
pip install cython
python setup.py build_ext --inplace
```
This will generate `.pyd` files, which Python will prefer to load instead of your `.py` files,
so you will need to rebuild or delete the `.pyd` each time you make changes.

setup.py will also compile Pyglet using Cython, if you download
the pyglet source code and put the *pyglet* folder inside the game repository.

## Building Windows Executables
```
pip install cython cx_Freeze
python setup.py build
```
This builds Cython-optimized `.pyd`'s, and bundles together all libraries including Python itself, into `build/exe.win-amd64-3.7/`
2 changes: 1 addition & 1 deletion biome.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ cimport perlin
#cython: wraparound=False
#cython: cdivision=True

cdef class BiomeGenerator(object):
cdef class BiomeGenerator:
cdef public:
object temperature_gen, humidity_gen

Expand Down
2 changes: 1 addition & 1 deletion biome.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

__all__ = ("BiomeGenerator")

class BiomeGenerator(object):
class BiomeGenerator:
def __init__(self, seed):
self.temperature_gen = SimplexNoiseGen(seed + "97", zoom_level=0.01)
self.humidity_gen = SimplexNoiseGen(seed + "147", zoom_level=0.01)
Expand Down
8 changes: 4 additions & 4 deletions biome_explorer.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from terrain import BiomeGenerator
import globals as G

with open(os.path.join(G.game_dir, "world", "seed"), "rb") as f:
with open(os.path.join(G.game_dir, "world", "seed"), "r") as f:
SEED = f.read()

b = BiomeGenerator(SEED)
Expand All @@ -13,10 +13,10 @@
xsize = 79
ysize = 28

DESERT, PLAINS, MOUNTAINS, SNOW, FOREST = range(5)
DESERT, PLAINS, MOUNTAINS, SNOW, FOREST = list(range(5))
letters = ["D","P","M","S","F"]

print "Okay, click on the console window again, then use the arrow keys."
print("Okay, click on the console window again, then use the arrow keys.")

while True:
base = getch()
Expand All @@ -38,4 +38,4 @@
for x in range(curx,curx+xsize):
string += letters[b.get_biome_type(x,y)]
string += "\n"
print string + "Current position: (%s-%s %s-%s)" % (curx*8, (curx+xsize)*8, cury*8, (cury+ysize)*8)
print(string + "Current position: (%s-%s %s-%s)" % (curx*8, (curx+xsize)*8, cury*8, (cury+ysize)*8))
37 changes: 20 additions & 17 deletions blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# Imports, sorted alphabetically.

# Future imports
from __future__ import unicode_literals

from math import floor

# Python packages
Expand Down Expand Up @@ -103,7 +103,7 @@ def unset_state(self):
glDisable(self.texture.target)


class BlockID(object):
class BlockID:
"""
Datatype for Block and Item IDs

Expand All @@ -121,7 +121,7 @@ class BlockID(object):
def __init__(self, main, sub=0, icon_name=None):
if isinstance(main, tuple):
self.main, self.sub = main
elif isinstance(main, basestring):
elif isinstance(main, str):
# Allow "35", "35.0", or "35,0"
spl = main.split(".") if "." in main else main.split(",") if "," in main else (main, 0)
if len(spl) == 2:
Expand All @@ -148,30 +148,33 @@ def __repr__(self):
def __hash__(self):
return hash((self.main, self.sub))

def __cmp__(self, other):
def __eq__(self, other):
if isinstance(other, tuple):
return cmp((self.main, self.sub), other)
return (self.main, self.sub) == other
if isinstance(other, float):
return cmp(float(repr(self.main)), other)
return float(repr(self.main)) == other
if isinstance(other, int):
return cmp(self.main, other)
return self.main == other
if isinstance(other, BlockID):
return cmp(self.main, other.main) or cmp(self.sub, other.sub)
return self.main == other.main and self.sub == other.sub

def __ne__(self, other):
return not (self == other)

def __nonzero__(self):
def __bool__(self):
"""Checks whether it is an AirBlock."""
return self.main != 0

def is_item(self):
return self.main > 255
return self.main >= G.ITEM_ID_MIN

def filename(self):
if self.icon_name != None: return ["textures", "blocks" if self.main < G.ITEM_ID_MIN else "items", str(self.icon_name) + ".png"]
if self.icon_name != None: return ["textures", "items" if self.is_item() else "blocks", str(self.icon_name) + ".png"]
if self.sub == 0: return ["textures", "icons", str(self.main) + ".png"]
return ["textures", "icons", '%d.%d.png' % (self.main, self.sub)]


class Block(object):
class Block:
id = None # Original minecraft id (also called data value).
# Verify on http://www.minecraftwiki.net/wiki/Data_values
# when creating a new "official" block.
Expand Down Expand Up @@ -361,7 +364,7 @@ def on_neighbor_change(self, world, neighbor_pos, self_pos):
def can_place_on(self, block_id):
return False

class BlockColorizer(object):
class BlockColorizer:
def __init__(self, filename):
self.color_data = G.texture_pack_list.selected_texture_pack.load_texture(['misc', filename])
# if the texture is not available, don't colorize it
Expand All @@ -378,7 +381,7 @@ def get_color(self, temperature, humidity):
if self.color_data is None:
return 1, 1, 1
pos = int(floor(humidity * 255) * BYTE_PER_LINE + 3 * floor((temperature) * 255))
return float(ord(self.color_data[pos])) / 255, float(ord(self.color_data[pos + 1])) / 255, float(ord(self.color_data[pos + 2])) / 255
return float(self.color_data[pos]) / 255, float(self.color_data[pos + 1]) / 255, float(self.color_data[pos + 2]) / 255

class AirBlock(Block):
max_stack_size = 0
Expand Down Expand Up @@ -1393,7 +1396,7 @@ def growth_stage(self, value):
def fertilize(self):
if self.growth_stage == self.max_growth_stage:
return False
G.CLIENT.update_tile_entity(self.entity.position, make_nbt_from_dict({'action'.encode(): 'fertilize'.encode()}))
G.CLIENT.update_tile_entity(self.entity.position, make_nbt_from_dict({'action': 'fertilize'}))
return True

def update_tile_entity(self, value):
Expand Down Expand Up @@ -1717,15 +1720,15 @@ def can_place_on(self, block_id):
return (block_id != 0)

def set_metadata(self, metadata):
print 'metadata: ', metadata
print('metadata: ', metadata)
if self.sub_id_as_metadata:
self.id.sub = metadata

CRACK_LEVELS = 10


# not a real block, used to store crack texture data
class CrackTextureBlock(object):
class CrackTextureBlock:
def __init__(self):
self.crack_level = CRACK_LEVELS
self.texture_data = []
Expand Down
2 changes: 1 addition & 1 deletion cameras.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ cdef extern from "math.h":
float cosf(float theta)
float sinf(float theta)

cdef class Camera3D(object):
cdef class Camera3D:
cdef public:
object target
double x
Expand Down
2 changes: 1 addition & 1 deletion cameras.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
)


class Camera3D(object):
class Camera3D:
def __init__(self, target=None):
self.target = target
self.x = 0.0
Expand Down
Empty file removed client.pxd
Empty file.
46 changes: 23 additions & 23 deletions client.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,40 +32,40 @@ def run(self):
except socket.error as e:
if e[0] in (10053, 10054):
#TODO: GUI tell the client they were disconnected
print "Disconnected from server."
print("Disconnected from server.")
else:
raise e
self.controller.back_to_main_menu.set()

# loop() is run once in its own thread
def loop(self):
packetcache, packetsize = "", 0
packetcache, packetsize = b"", 0

append_to_sector_packets = self.world.sector_packets.append
while 1:
resp = self.sock.recv(16384)
if self._stop.isSet() or not resp:
print "Client PacketReceiver:",self._stop.isSet() and "Shutting down" or "We've been disconnected by the server"
print("Client PacketReceiver:",self._stop.isSet() and "Shutting down" or "We've been disconnected by the server")
self.sock.shutdown(SHUT_RDWR)
return

# Sometimes data is sent in multiple pieces, just because sock.recv returned data doesn't mean its complete
# So we write the datalength in the beginning of all messages, and don't look at the packet until we have enough data
packetcache += resp
if not packetsize:
if not packetsize and len(packetcache) >= 4:
packetsize = struct.unpack("i", packetcache[:4])[0]

# Sometimes we get multiple packets in a single burst, so loop through packetcache until we lack the data
while packetsize and len(packetcache) >= packetsize:
#Once we've obtained the whole packet
packetid = struct.unpack("B",packetcache[4])[0] # Server Packet Type
packetid = struct.unpack_from("B",packetcache, 4)[0] # Server Packet Type
packet = packetcache[5:packetsize]

with self.lock:
append_to_sector_packets((packetid, packet))

packetcache = packetcache[packetsize:] # Cut off the part we just read
packetsize = struct.unpack("i", packetcache[:4])[0] if packetcache else 0 # Get the next packet's size
packetsize = struct.unpack("i", packetcache[:4])[0] if len(packetcache) >= 4 else 0 # Get the next packet's size


#=== The following functions are run by the Main Thread ===#
Expand All @@ -81,9 +81,9 @@ def dequeue_packet(self):
cx, cy, cz = sector_to_blockpos(secpos)
fpos = 12
exposed_pos = fpos + 1024
for x in xrange(cx, cx+8):
for y in xrange(cy, cy+8):
for z in xrange(cz, cz+8):
for x in range(cx, cx+8):
for y in range(cy, cy+8):
for z in range(cz, cz+8):
read = packet[fpos:fpos+2]
fpos += 2
unpacked = structuchar2.unpack(read)
Expand All @@ -100,7 +100,7 @@ def dequeue_packet(self):
blocks[position] = type(main_blk)()
blocks[position].set_metadata(unpacked[-1])
sector.append(position)
if packet[exposed_pos] is "1":
if packet[exposed_pos:exposed_pos+1] == b"1":
blocks.show_block(position)
exposed_pos += 1
if secpos in self.world.sector_queue:
Expand All @@ -122,14 +122,14 @@ def dequeue_packet(self):
player = self.controller.player
caret = 0
for inventory in (player.quick_slots.slots, player.inventory.slots, player.armor.slots):
for i in xrange(len(inventory)):
for i in range(len(inventory)):
id_main, id_sub, amount = struct.unpack("HBB", packet[caret:caret+4])
caret += 4
if id_main == 0: continue
durability = -1
if id_main >= G.ITEM_ID_MIN and (id_main, id_sub) not in G.ITEMS_DIR:
#The subid must be durability
durability = id_sub * G.ITEMS_DIR[(id_main, 0)].durability / 255
durability = id_sub * G.ITEMS_DIR[(id_main, 0)].durability // 255
id_sub = 0
inventory[i] = ItemStack(type=BlockID(id_main, id_sub), amount=amount, durability=durability)
self.controller.item_list.update_items()
Expand Down Expand Up @@ -161,31 +161,31 @@ def dequeue_packet(self):
# Helper Functions for sending data to the Server

def request_sector(self, sector):
self.sock.sendall("\1"+struct.pack("iii", *sector))
self.sock.sendall(b"\1"+struct.pack("iii", *sector))
def add_block(self, position, block):
self.sock.sendall("\3"+struct.pack("iiiBB", *(position+(block.id.main, block.id.sub))))
self.sock.sendall(b"\3"+struct.pack("iiiBB", *(position+(block.id.main, block.id.sub))))
def remove_block(self, position):
self.sock.sendall("\4"+struct.pack("iii", *position))
self.sock.sendall(b"\4"+struct.pack("iii", *position))
def send_chat(self, msg):
msg = msg.encode('utf-8')
self.sock.sendall("\5"+struct.pack("i", len(msg))+msg)
self.sock.sendall(b"\5"+struct.pack("i", len(msg))+msg)
def request_spawnpos(self):
name = G.USERNAME.encode('utf-8')
self.sock.sendall(struct.pack("B", 255)+struct.pack("i",len(name)) + name)
def send_player_inventory(self):
packet = ""
packet = b""
for item in (self.controller.player.quick_slots.slots + self.controller.player.inventory.slots + self.controller.player.armor.slots):
if item:
packet += struct.pack("HBB", item.type.main, item.type.sub if item.max_durability == -1 else item.durability * 255 / item.max_durability, item.amount)
packet += struct.pack("HBB", item.type.main, item.type.sub if item.max_durability == -1 else item.durability * 255 // item.max_durability, item.amount)
else:
packet += "\0\0\0\0"
self.sock.sendall("\6"+packet)
packet += b"\0\0\0\0"
self.sock.sendall(b"\6"+packet)
def send_movement(self, momentum, position):
self.sock.sendall("\x08"+struct.pack("fff", *momentum) + struct.pack("ddd", *position))
self.sock.sendall(b"\x08"+struct.pack("fff", *momentum) + struct.pack("ddd", *position))
def send_jump(self):
self.sock.sendall("\x09")
self.sock.sendall(b"\x09")
def update_tile_entity(self, position, value):
self.sock.sendall("\x0A" + struct.pack("iii", *position) + struct.pack("i", len(value)) + value)
self.sock.sendall(b"\x0A" + struct.pack("iii", *position) + struct.pack("i", len(value)) + value)


def stop(self):
Expand Down
Loading