diff --git a/chunks.py b/chunks.py index 6107c21..d64163e 100644 --- a/chunks.py +++ b/chunks.py @@ -1,6 +1,6 @@ import threading import time -from utils import CHUNK_WIDTH, CHUNK_HEIGHT +from utils import CHUNK_WIDTH, CHUNK_HEIGHT, Position class ChunkDiff(): """ @@ -134,14 +134,28 @@ class ChunkPool(): def __exit__(self, type, value, tb): self._lock.release() + def set(self, pos, chunk): + self._chunks[pos] = chunk + def get(self, pos): return self._chunks.get(pos) def create(self, pos): chunk = Chunk() - self._chunks[pos] = chunk + self.set(pos, chunk) return chunk + def apply_changes(self, changes): + for change in changes: + pos = Position(change[0][0], change[0][1]) + diff = change[1] + + chunk = self.get(pos) + if not chunk: + chunk = self.create(pos) + + chunk.commit_diff(diff) + def commit_changes(self): changes = [] @@ -174,6 +188,8 @@ class ChunkPool(): # old list comprehension which became too long: #coords = [pos for pos, chunk in self._chunks.items() if not pos in except_for and condition(chunk)] + self.save_changes() + coords = [] for pos, chunk in self._chunks.items(): diff --git a/client.py b/client.py index 15b99f4..c9ebd40 100644 --- a/client.py +++ b/client.py @@ -1,20 +1,20 @@ import curses +import os import string import sys import threading from maps import Map, ChunkMap +from chunks import ChunkDiff from clientchunkpool import ClientChunkPool -# import fron chunks, maps, clientchunkpool - class Client(): def __init__(self, address): self.stopping = False self.chunkmap_active = False self.address = address - self.drawevent = threading.Event() - self.pool = ClientChunkPool() + self._drawevent = threading.Event() + self.pool = ClientChunkPool(self) #self.map_ = Map(sizex, sizey, self.pool) #self.chunkmap = Chunkmap(sizex, sizey, self.pool) # size changeable by +/-? @@ -22,7 +22,7 @@ class Client(): def launch(self, stdscr): sizey, sizex = stdscr.getmaxyx() - self.map_ = Map(sizex, sizey, self.pool, self.drawevent) + self.map_ = Map(sizex, sizey, self.pool, self) self.chunkmap = ChunkMap(self.map_) # start input thread @@ -35,7 +35,8 @@ class Client(): self.inputthread.start() while not self.stopping: - self.drawevent.wait() + self._drawevent.wait() + self._drawevent.clear() stdscr.noutrefresh() with self.map_ as m: m.draw() @@ -45,12 +46,14 @@ class Client(): curses.curs_set(False) else: curses.curs_set(True) - - #m.update_cursor() - #m.noutrefresh() + + #m.update_cursor() + #m.noutrefresh() curses.doupdate() - self.drawevent.clear() + + def redraw(self): + self._drawevent.set() def input_thread(self, scr): while True: @@ -59,7 +62,7 @@ class Client(): if i == "\x1b": self.stop() elif i == "KEY_F(2)": self.chunkmap_active = not self.chunkmap_active - self.drawevent.set() + self.redraw() elif i == "KEY_F(5)": self.map_.redraw() # scrolling the map (10 vertical, 20 horizontal) elif i == "kUP5": self.map_.scroll(0, -10) @@ -86,11 +89,23 @@ class Client(): elif i == "\x7f": self.map_.delete() elif i == "\n": self.map_.newline() - else: sys.stdout.write(repr(i) + "\n") + else: sys.stderr.write(repr(i) + "\n") def stop(self): self.stopping = True - self.drawevent.set() + self.redraw() + + def request_chunks(self, coords): + def execute(): + changes = [(pos, ChunkDiff()) for pos in coords] + with self.pool as pool: + pool.apply_changes(changes) + + tx = threading.Timer(1, execute) + tx.start() + + def send_changes(self, changes): + pass def main(argv): if len(argv) != 2: @@ -98,6 +113,8 @@ def main(argv): print(" {} address".format(argv[0])) return + os.environ.setdefault('ESCDELAY', '25') # only a 25 millisecond delay + client = Client(argv[1]) curses.wrapper(client.launch) diff --git a/clientchunkpool.py b/clientchunkpool.py index c67cff9..40732e7 100644 --- a/clientchunkpool.py +++ b/clientchunkpool.py @@ -5,8 +5,31 @@ class ClientChunkPool(ChunkPool): A ChunkPool that requests/loads chunks from a client. """ - def __init__(self): + def __init__(self, client): super().__init__() - self.max_age = 10 #s + + self._client = client - pass + #def commit_changes(self): + #changes = [] + + #for pos, chunk in self._chunks.items(): + #changes.append((pos, chunk.get_changes())) + #chunk.commit_changes() + + #return changes + + def apply_changes(self, changes): + super().apply_changes(changes) + + self._client.redraw() + + def save_changes(self): + changes = self.commit_changes() + self._client.send_changes(changes) + + def load(self, pos): + raise Exception + + def load_list(self, coords): + self._client.request_chunks(coords) diff --git a/maps.py b/maps.py index 043d243..62ca5f0 100644 --- a/maps.py +++ b/maps.py @@ -4,15 +4,13 @@ import math import threading from utils import CHUNK_HEIGHT, CHUNK_WIDTH, chunkx, chunky, inchunkx, inchunky, Position -import sys - class Map(): """ A map which displays chunks and a cursor on the screen. Allows for user to modify chunks in an intuitive way. """ - def __init__(self, width, height, chunkpool, drawevent): + def __init__(self, width, height, chunkpool, client): self._lock = threading.RLock() self.chunkpreload = 0 # preload chunks in this radius (they will count as "visible") @@ -26,7 +24,7 @@ class Map(): self.lastcury = self.cursory self.chunkpool = chunkpool - self.drawevent = drawevent + self.client = client self._pad = curses.newpad(5, 5) self.resize(width, height) @@ -44,7 +42,7 @@ class Map(): def redraw(self): self._pad.redrawwin() - self.drawevent.set() + self.client.redraw() def draw(self): with self.chunkpool as pool: @@ -93,7 +91,7 @@ class Map(): pool.load_list(coords) pool.clean_up(except_for=coords, condition=self._unload_condition) - self.drawevent.set() + self.client.redraw() def resize(self, width, height): self.width = width @@ -208,7 +206,7 @@ class ChunkMap(): styles = { "empty": ChunkStyle("()", 2), "normal": ChunkStyle("[]", 3), - "old": ChunkStyle("{}", 4), + "unload": ChunkStyle("{}", 4), "visible": ChunkStyle("##", 5), "modified": ChunkStyle("!!", 6), } @@ -225,7 +223,7 @@ class ChunkMap(): 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(4, curses.COLOR_BLACK, curses.COLOR_YELLOW) # chunk to be unloaded curses.init_pair(5, curses.COLOR_BLACK, curses.COLOR_GREEN) # visible chunk curses.init_pair(6, curses.COLOR_BLACK, curses.COLOR_RED) # modified chunk @@ -236,7 +234,10 @@ class ChunkMap(): def draw(self): with self.chunkpool as pool: - minx, maxx, miny, maxy = self.get_min_max(pool) + if pool._chunks: + minx, maxx, miny, maxy = self.get_min_max(pool) + else: + minx, maxx, miny, maxy = 0, 0, 0, 0 sizex = maxx - minx sizey = maxy - miny self.update_size(sizex, sizey) @@ -281,8 +282,8 @@ class ChunkMap(): if pos in self.map_.visible_chunk_coords(): return "visible" - if chunk.age() > self.chunkpool.max_age: - return "old" + if self.map_._unload_condition(pos, chunk): + return "unload" if chunk.empty(): return "empty" diff --git a/utils.py b/utils.py index 5c5b1cc..9aaf61f 100644 --- a/utils.py +++ b/utils.py @@ -2,8 +2,10 @@ from collections import namedtuple Position = namedtuple("Position", "x y") -CHUNK_WIDTH = 64 -CHUNK_HEIGHT = 32 +#CHUNK_WIDTH = 64 +#CHUNK_HEIGHT = 32 +CHUNK_WIDTH = 32 +CHUNK_HEIGHT = 16 def chunkx(value): return value//CHUNK_WIDTH