Add ChunkMap for better debugging

This commit is contained in:
Joscha 2017-04-07 19:35:05 +00:00
parent 42d72422c6
commit 68c50f894b
5 changed files with 153 additions and 33 deletions

View file

@ -58,7 +58,7 @@ class ChunkDiff():
return [s[i:i+CHUNK_WIDTH] for i in range(0, CHUNK_WIDTH*CHUNK_HEIGHT, CHUNK_WIDTH)] return [s[i:i+CHUNK_WIDTH] for i in range(0, CHUNK_WIDTH*CHUNK_HEIGHT, CHUNK_WIDTH)]
def empty(self): def empty(self):
return bool(self._chars) return not bool(self._chars)
class Chunk(): class Chunk():
@ -96,8 +96,11 @@ class Chunk():
def get_changes(self): def get_changes(self):
return self._modifications return self._modifications
def touch(self): def touch(self, now=None):
self.last_modified = time.time() self.last_modified = now or time.time()
def age(self, now=None):
return self.last_modified - (now or time.time())
def draw_to(self, x, y, window): def draw_to(self, x, y, window):
for line in self._content.combine(self._modifications).lines(): for line in self._content.combine(self._modifications).lines():
@ -136,9 +139,21 @@ class ChunkPool():
if not pos in self._chunks: if not pos in self._chunks:
self.create(pos) self.create(pos)
def unload(self, pos):
if pos in self._chunks:
del self._chunks[pos]
def load_list(self, coords): def load_list(self, coords):
for pos in coords: for pos in coords:
self.load(pos) self.load(pos)
def unload_list(self, coords):
for pos in coords:
self.unload(pos)
def clean_up(self, except_for=[]):
coords = [pos for pos in self._chunks if not pos in except_for]
self.unload_list(coords)
def get(self, pos): def get(self, pos):
return self._chunks.get(pos) return self._chunks.get(pos)

View file

@ -2,18 +2,19 @@ import curses
import string import string
import sys import sys
import threading import threading
from maps import Map from maps import Map, ChunkMap
from chunks import ChunkPool from clientchunkpool import ClientChunkPool
# import fron chunks, maps, clientchunkpool # import fron chunks, maps, clientchunkpool
class Client(): class Client():
def __init__(self, address): def __init__(self, address):
self.stopping = False self.stopping = False
self.chunkmap_active = False
self.address = address self.address = address
self.drawevent = threading.Event() self.drawevent = threading.Event()
self.pool = ChunkPool() self.pool = ClientChunkPool()
#self.map_ = Map(sizex, sizey, self.pool) #self.map_ = Map(sizex, sizey, self.pool)
#self.chunkmap = Chunkmap(sizex, sizey, self.pool) # size changeable by +/-? #self.chunkmap = Chunkmap(sizex, sizey, self.pool) # size changeable by +/-?
@ -22,6 +23,7 @@ class Client():
def launch(self, stdscr): def launch(self, stdscr):
sizey, sizex = stdscr.getmaxyx() sizey, sizex = stdscr.getmaxyx()
self.map_ = Map(sizex, sizey, self.pool, self.drawevent) self.map_ = Map(sizex, sizey, self.pool, self.drawevent)
self.chunkmap = ChunkMap(self.map_)
# start input thread # start input thread
self.inputthread = threading.Thread( self.inputthread = threading.Thread(
@ -37,6 +39,16 @@ class Client():
stdscr.noutrefresh() stdscr.noutrefresh()
with self.map_ as m: with self.map_ as m:
m.draw() m.draw()
if self.chunkmap_active:
self.chunkmap.draw()
curses.curs_set(False)
else:
curses.curs_set(True)
#m.update_cursor()
#m.noutrefresh()
curses.doupdate() curses.doupdate()
self.drawevent.clear() self.drawevent.clear()
@ -45,7 +57,10 @@ class Client():
i = scr.getkey() i = scr.getkey()
if i == "\x1b": self.stop() if i == "\x1b": self.stop()
#elif i == "r": self.map_.redraw() elif i == "KEY_F(2)":
self.chunkmap_active = not self.chunkmap_active
self.drawevent.set()
elif i == "KEY_F(5)": self.map_.redraw()
# normal cursor movement # normal cursor movement
elif i == "KEY_UP": self.map_.move_cursor(0, -1) elif i == "KEY_UP": self.map_.move_cursor(0, -1)
elif i == "KEY_DOWN": self.map_.move_cursor(0, 1) elif i == "KEY_DOWN": self.map_.move_cursor(0, 1)

View file

@ -1,8 +1,12 @@
from .chunks.py import ChunkPool from chunks import ChunkPool
class ClientChunkPool(ChunkPool): class ClientChunkPool(ChunkPool):
""" """
A ChunkPool that requests/loads chunks from a client. A ChunkPool that requests/loads chunks from a client.
""" """
def __init__(self):
super().__init__()
self.max_age = 10 #s
pass pass

128
maps.py
View file

@ -1,3 +1,4 @@
from collections import namedtuple
import curses import curses
import math import math
import threading import threading
@ -29,6 +30,9 @@ class Map():
self._pad = curses.newpad(5, 5) self._pad = curses.newpad(5, 5)
self.resize(width, height) self.resize(width, height)
if curses.has_colors():
curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_WHITE) # chunk not loaded
def __enter__(self): def __enter__(self):
self._lock.acquire() self._lock.acquire()
return self return self
@ -51,14 +55,18 @@ class Map():
else: else:
self.draw_empty_to(x*CHUNK_WIDTH, y*CHUNK_HEIGHT) self.draw_empty_to(x*CHUNK_WIDTH, y*CHUNK_HEIGHT)
# set cursor position in world self.update_cursor()
self.noutrefresh()
def noutrefresh(self):
self._pad.noutrefresh(inchunky(self.worldy), inchunkx(self.worldx), 0, 0, self.height-1, self.width-1)
def update_cursor(self):
self._pad.move( self._pad.move(
self.cursory - chunky(self.worldy)*CHUNK_HEIGHT, self.cursory - chunky(self.worldy)*CHUNK_HEIGHT,
self.cursorx - chunkx(self.worldx)*CHUNK_WIDTH self.cursorx - chunkx(self.worldx)*CHUNK_WIDTH
) )
self._pad.noutrefresh(inchunky(self.worldy), inchunkx(self.worldx), 0, 0, self.height-1, self.width-1)
def draw_empty_to(self, x, y): def draw_empty_to(self, x, y):
if curses.has_colors(): if curses.has_colors():
curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_WHITE) curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_WHITE)
@ -71,7 +79,9 @@ class Map():
def load_visible(self): def load_visible(self):
with self.chunkpool as pool: with self.chunkpool as pool:
pool.load_list(self.visible_chunk_coords()) coords = self.visible_chunk_coords()
pool.load_list(coords)
#pool.clean_up(except_for=coords)
self.drawevent.set() self.drawevent.set()
@ -103,12 +113,11 @@ class Map():
def write(self, char): def write(self, char):
with self.chunkpool as pool: with self.chunkpool as pool:
chunk = pool.get(Position(chunkx(self.cursorx), chunky(self.cursory))) chunk = pool.get(Position(chunkx(self.cursorx), chunky(self.cursory)))
if not chunk:
chunk = pool.create(Position(chunkx(self.cursorx), chunky(self.cursory)))
chunk.set(inchunkx(self.cursorx), inchunky(self.cursory), char) if chunk:
chunk.set(inchunkx(self.cursorx), inchunky(self.cursory), char)
self.move_cursor(1, 0, False) self.move_cursor(1, 0, False)
def delete(self): def delete(self):
with self.chunkpool as pool: with self.chunkpool as pool:
@ -178,6 +187,7 @@ class Map():
#self.load_visible() #self.load_visible()
ChunkStyle = namedtuple("ChunkStyle", "string color")
class ChunkMap(): class ChunkMap():
""" """
@ -185,17 +195,93 @@ class ChunkMap():
Might show additional details too (i.e. if a chunk has been modified). Might show additional details too (i.e. if a chunk has been modified).
""" """
def __init__(self, chunkpool): styles = {
self.cpool = chunkpool "empty": ChunkStyle("()", 2),
# "normal": ChunkStyle("[]", 3),
# def draw(self): "old": ChunkStyle("{}", 4),
# pass "visible": ChunkStyle("##", 5),
# "modified": ChunkStyle("!!", 6),
# def resize(self, size): }
# pass
#
def move(self, x, y, corner):
pass
def toggle(self): def __init__(self, map_):
pass self.map_ = map_
self.chunkpool = map_.chunkpool
self.corner = "ur" # upper right
#minx, maxx, miny, maxy = self.get_min_max()
#self.win = curses.newwin(maxy-miny+2, maxx-minx+2)
self.win = curses.newwin(2, 2)
if curses.has_colors():
curses.init_pair(2, curses.COLOR_BLACK, curses.COLOR_BLUE) # empty chunk
curses.init_pair(3, curses.COLOR_BLACK, curses.COLOR_WHITE) # chunk
curses.init_pair(4, curses.COLOR_BLACK, curses.COLOR_YELLOW) # old chunk
curses.init_pair(5, curses.COLOR_BLACK, curses.COLOR_GREEN) # visible chunk
curses.init_pair(6, curses.COLOR_BLACK, curses.COLOR_RED) # modified chunk
def update_size(self, sizex, sizey):
winy, winx = self.win.getmaxyx()
if winx != 2*sizex + 4 or winy != sizey + 3:
self.win.resize(sizey + 3, 2*sizex + 4)
sys.stderr.write("{}\n".format(self.win.getmaxyx()))
def draw(self):
with self.chunkpool as pool:
minx, maxx, miny, maxy = self.get_min_max(pool)
sizex = maxx - minx
sizey = maxy - miny
sys.stderr.write("{} {} {} {} | {} {}\n".format(minx, maxx, miny, maxy, sizex, sizey))
self.update_size(sizex, sizey)
self.win.erase()
self.win.border()
for pos, chunk in pool._chunks.items():
tp = self.type_of(pos, chunk)
sys.stderr.write(tp + "\n")
sys.stderr.write("{} {}\n".format(pos.x - minx + 1, pos.y - miny + 1))
if curses.has_colors():
self.win.addstr(
pos.y - miny + 1,
2*(pos.x - minx) + 1,
" ",
curses.color_pair(self.styles[tp].color)
)
else:
self.win.addstr(
pos.y - miny + 1,
2*(pos.x - minx) + 1,
self.styles[tp].string
)
self.win.noutrefresh()
def get_min_max(self, pool):
minx = min(pos.x for pos in pool._chunks)
maxx = max(pos.x for pos in pool._chunks)
miny = min(pos.y for pos in pool._chunks)
maxy = max(pos.y for pos in pool._chunks)
return minx, maxx, miny, maxy
def get_size(self):
minx, maxx, miny, maxy = self.get_min_max()
return maxx - minx, maxy - miny
def type_of(self, pos, chunk):
if chunk.modified():
return "modified"
if pos in self.map_.visible_chunk_coords():
return "visible"
if chunk.age() > self.chunkpool.max_age:
return "old"
if chunk.empty():
return "empty"
return "normal"
#def move(self, x, y, corner):
#pass

View file

@ -2,8 +2,8 @@ from collections import namedtuple
Position = namedtuple("Position", "x y") Position = namedtuple("Position", "x y")
CHUNK_WIDTH = 16 CHUNK_WIDTH = 64
CHUNK_HEIGHT = 8 CHUNK_HEIGHT = 32
def chunkx(value): def chunkx(value):
return value//CHUNK_WIDTH return value//CHUNK_WIDTH