Skip to content

Commit

Permalink
Implement block entity data interface
Browse files Browse the repository at this point in the history
  • Loading branch information
Gjum committed Jan 31, 2016
1 parent 84dff18 commit e93b109
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 0 deletions.
24 changes: 24 additions & 0 deletions spockbot/plugins/helpers/world.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from spockbot.mcdata import constants as const
from spockbot.plugins.base import PluginBase, pl_announce
from spockbot.plugins.tools import smpmap
from spockbot.vector import Vector3


class WorldData(smpmap.Dimension):
Expand Down Expand Up @@ -38,6 +39,8 @@ class WorldPlugin(PluginBase):
'PLAY<Multi Block Change': 'handle_multi_block_change',
'PLAY<Block Change': 'handle_block_change',
'PLAY<Map Chunk Bulk': 'handle_map_chunk_bulk',
'PLAY<Update Sign': 'handle_update_sign',
'PLAY<Update Block Entity': 'handle_update_block_entity',
'net_disconnect': 'handle_disconnect',
}

Expand Down Expand Up @@ -89,6 +92,27 @@ def handle_map_chunk_bulk(self, name, packet):
"""Map Chunk Bulk - Update World state"""
self.world.unpack_bulk(packet.data)

def handle_update_sign(self, event, packet):
location = Vector3(packet.data['location'])
sign_data = smpmap.SignData(packet.data)
old_data = self.world.set_block_entity_data(location, data=sign_data)
self.event.emit('world_block_entity_data', {
'location': location,
'data': sign_data,
'old_data': old_data,
})

def handle_update_block_entity(self, event, packet):
location = Vector3(packet.data['location'])
block_entity_class = smpmap.block_entities[packet.data['action']]
data = block_entity_class(packet.data['nbt'])
old_data = self.world.set_block_entity_data(location, data=data)
self.event.emit('world_block_entity_data', {
'location': location,
'data': data,
'old_data': old_data,
})

def handle_disconnect(self, name, data):
self.world.reset()
self.event.emit('world_reset')
94 changes: 94 additions & 0 deletions spockbot/plugins/tools/smpmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,69 @@ def mapshort2id(data):
return data >> 4, data & 0x0F


class BlockEntityData(object):
def __init__(self, nbt):
self.nbt = nbt

def __getattr__(self, key):
return getattr(self.nbt, key)

def __str__(self):
return str(self.nbt)

def __repr__(self):
return repr(self.nbt)


class SpawnerData(BlockEntityData):
pass # TODO get entity class from mcdata?


class CommandBlockData(BlockEntityData):
pass


class BeaconData(BlockEntityData):
pass


class HeadData(BlockEntityData):
pass


class FlowerPotData(BlockEntityData):
def __init__(self, nbt):
super(FlowerPotData, self).__init__(nbt)
self.block = nbt['Item'].value, nbt['Data'].value
# TODO get block instance from mcdata?


class BannerData(BlockEntityData):
pass


class SignData(BlockEntityData):
def __init__(self, line_data):
super(SignData, self).__init__(self)
self.lines = [line_data['line_%i' % (i + 1)] for i in range(4)]

def __str__(self):
return 'Sign%s' % str(self.lines)

def __repr__(self):
return '<SignData %s>' % repr(self.lines)


block_entities = {
1: SpawnerData,
2: CommandBlockData,
3: BeaconData,
4: HeadData,
5: FlowerPotData,
6: BannerData,
}


class ChunkData(object):
length = 16 * 16 * 16
ty = 'B'
Expand Down Expand Up @@ -132,6 +195,9 @@ def __init__(self, dimension):
self.dimension = dimension
self.columns = {} # chunk columns are address by a tuple (x, z)

# BlockEntityData subclass instances, adressed by (x,y,z)
self.block_entities = {}

def unpack_bulk(self, data):
bbuff = BoundBuffer(data['data'])
skylight = data['sky_light']
Expand Down Expand Up @@ -192,6 +258,34 @@ def set_block(self, pos_or_x, y=None, z=None,
data = (block_id << 4) | (meta & 0x0F)
chunk.block_data.set(rx, ry, rz, data)

def get_block_entity_data(self, pos_or_x, y=None, z=None):
"""
Access block entity data.
Returns:
BlockEntityData subclass instance or
None if no block entity data is stored for that location.
"""
if None not in (y, z): # x y z supplied
pos_or_x = pos_or_x, y, z
coord_tuple = tuple(floor(c) for c in pos_or_x)
return self.block_entities.get(coord_tuple, None)

def set_block_entity_data(self, pos_or_x, y=None, z=None, data=None):
"""
Update block entity data.
Returns:
Old data if block entity data was already stored for that location,
None otherwise.
"""
if None not in (y, z): # x y z supplied
pos_or_x = pos_or_x, y, z
coord_tuple = tuple(floor(c) for c in pos_or_x)
old_data = self.block_entities.get(coord_tuple, None)
self.block_entities[coord_tuple] = data
return old_data

def get_light(self, pos_or_x, y=None, z=None):
if None in (y, z): # pos supplied
pos_or_x, y, z = pos_or_x
Expand Down

0 comments on commit e93b109

Please sign in to comment.