Skip to content

Commit

Permalink
Add copy paste and fix issue with ungenerated chunk sections
Browse files Browse the repository at this point in the history
  • Loading branch information
DonoA committed Jan 5, 2019
1 parent 3626e6e commit 3452dee
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 28 deletions.
82 changes: 61 additions & 21 deletions canvas.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,42 @@
import sys, math
from schematic import Schematic

class WorldTask:
def __init__(self, location, new_state):
self.location = location
self.new_state = new_state

class Canvas:

def __init__(self, world, auto_commit=True):
self.world = world
self.work_queue = []
self.auto_commit = auto_commit
self.selection = set()

def brush(self, state):
self.state = state.clone()
return self
def fill(self, state):
my_state = state.clone()
for b in list(self.selection):
self.work_queue.append(WorldTask(b, my_state))

self.selection.clear()

if self.auto_commit:
self.commit()

def deselect(self):
self.selection.clear()

def copy(self):
min_x = min([l[0] for l in self.selection])
min_y = min([l[1] for l in self.selection])
min_z = min([l[2] for l in self.selection])
print(min_x, min_y, min_z)
new_schem = Schematic({
(loc[0] - min_x, loc[1] - min_y, loc[2] - min_z): self.world.get_block(loc).get_state() for loc in self.selection
})
self.selection.clear()
return new_schem

def commit(self):
region_work = {}
Expand All @@ -29,25 +52,42 @@ def commit(self):
self.world.get_block(task.location).set_state(task.new_state)
self.world.flush()

def square(self, center, side_len):
strt = math.floor(side_len/2.0)
end = math.ceil(side_len/2.0)
for x in range(-strt, end):
for z in range(-strt, end):
loc = (center[0] + x, center[1], center[2] + z)
self.work_queue.append(WorldTask(loc, self.state))
if self.auto_commit:
self.commit()
def select_rectangle(self, p1, p2):
self._rect(p1, p2, True)
return self

def disk(self, center, radius):
ss = radius+1
for x in range(-ss, ss):
for z in range(-ss, ss):
loc = (center[0] + x, center[1], center[2] + z)
if Canvas._dist(loc, center) <= (radius + 0.5):
self.world.get_block((center[0] + x, center[1], center[2] + z)).set_state(self.state)
if self.auto_commit:
self.commit()
def deselect_rectangle(self, p1, p2):
self._rect(p1, p2, False)
return self

def _rect(self, p1, p2, select):
for x in range(p1[0], p2[0] + 1):
for y in range(p1[1], p2[1] + 1):
for z in range(p1[2], p2[2] + 1):
loc = (x, y, z)
if select:
self.selection.add(loc)
else:
self.selection.remove(loc)

# def select_oval(self, p1, p2):
# self._oval(center, radius, True)
# return self

# def deselect_oval(self, p1, p2):
# self._oval(center, radius, False)
# return self

# def _oval(self, p1, p2, select):
# ss = radius+1
# for x in range(-ss, ss):
# for z in range(-ss, ss):
# loc = (center[0] + x, center[1], center[2] + z)
# if Canvas._dist(loc, center) <= (radius + 0.5):
# if select:
# self.selection.add(loc)
# else:
# self.selection.remove(loc)

def _dist(loc1, loc2):
dx = abs(loc1[0] - loc2[0]) ** 2
Expand Down
3 changes: 2 additions & 1 deletion main.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
with World('A', save_location='/home/dallen/.minecraft/saves', debug=True) as wrld:
print('World loaded!')
cv = wrld.get_canvas()
cv.brush(BlockState(Material.diamond_block, {})).square((106, 90, -252), 100)
cv.select_rectangle((50, 90, -260), (60, 92, -220)).fill(BlockState(Material.diamond_block, {}))
cv.select_rectangle((156, 96, -271), (177, 131, -249)).copy().paste(wrld, (100, 110, -250))

print('Saved!')
9 changes: 9 additions & 0 deletions schematic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class Schematic:

def __init__(self, state_map):
self.state_map = state_map

def paste(self, world, corner):
for loc, state in self.state_map.items():
shift_loc = (loc[0] + corner[0], loc[1] + corner[1], loc[2] + corner[2])
world.get_block(shift_loc).set_state(state)
13 changes: 7 additions & 6 deletions world.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ def __init__(self, name, props):
self.id = None

def __str__(self):
return 'BlockState(' + self.name + ',' + str(self.props) + ')'
return f'BlockState({self.name}, {str(self.props)})'

def __hash__(self):
return hash(self.name)
Expand All @@ -21,11 +21,11 @@ def clone(self):
return BlockState(self.name, self.props.copy())

class Block:
def __init__(self, state, block_light, sky_light):
def __init__(self, state, block_light, sky_light, dirty=False):
self._state = state
self.block_light = 0
self.sky_light = 0
self._dirty = False
self._dirty = dirty

def __str__(self):
return f'Block({str(self._state)}, {self.block_light}, {self.sky_light})'
Expand Down Expand Up @@ -122,7 +122,7 @@ def get_section(self, y):
key = int(y/16)
if key not in self.sections:
self.sections[key] = ChunkSection(
[Block(BlockState('minecraft:air', {}), 0, 0) for i in range(4096)],
[Block(BlockState('minecraft:air', {}), 0, 0, dirty=True) for i in range(4096)],
nbt.CompoundTag('None'),
key
)
Expand Down Expand Up @@ -216,7 +216,7 @@ def _read_bits(num, width, start):
return comp

def __str__(self):
return "Chunk(" + str(self.xpos) + "," + str(self.zpos) + ")"
return f'Chunk({str(self.xpos)},{str(self.zpos)})'

class World:
def __init__(self, file_name, save_location='', debug=False, read=True, write=True):
Expand Down Expand Up @@ -287,7 +287,7 @@ def close(self):
locations[((chunk.xpos % 32) + (chunk.zpos % 32) * 32)][1] = block_data_len

if loc[0] == 0 or loc[1] == 0:
print("Chunk not generated", chunk)
print('Chunk not generated', chunk)
sys.exit(0)

# Adjust sectors after this one that need their locations recalculated
Expand All @@ -300,6 +300,7 @@ def close(self):
if self.debug:
print(f'Saving {chunk} with', {'loc': loc, 'new_len': datalen, 'old_len': chunk.orig_size, 'sector_len': block_data_len})

# rewrite entire file with new chunks and locations recorded
region.seek(0)

for c_loc in locations:
Expand Down

0 comments on commit 3452dee

Please sign in to comment.