Implement parts of clientchunkpool and fix softlock in the process
This commit is contained in:
parent
c5af7c2480
commit
23da1ea5d9
5 changed files with 90 additions and 31 deletions
20
chunks.py
20
chunks.py
|
|
@ -1,6 +1,6 @@
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
from utils import CHUNK_WIDTH, CHUNK_HEIGHT
|
from utils import CHUNK_WIDTH, CHUNK_HEIGHT, Position
|
||||||
|
|
||||||
class ChunkDiff():
|
class ChunkDiff():
|
||||||
"""
|
"""
|
||||||
|
|
@ -134,14 +134,28 @@ class ChunkPool():
|
||||||
def __exit__(self, type, value, tb):
|
def __exit__(self, type, value, tb):
|
||||||
self._lock.release()
|
self._lock.release()
|
||||||
|
|
||||||
|
def set(self, pos, chunk):
|
||||||
|
self._chunks[pos] = chunk
|
||||||
|
|
||||||
def get(self, pos):
|
def get(self, pos):
|
||||||
return self._chunks.get(pos)
|
return self._chunks.get(pos)
|
||||||
|
|
||||||
def create(self, pos):
|
def create(self, pos):
|
||||||
chunk = Chunk()
|
chunk = Chunk()
|
||||||
self._chunks[pos] = chunk
|
self.set(pos, chunk)
|
||||||
return 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):
|
def commit_changes(self):
|
||||||
changes = []
|
changes = []
|
||||||
|
|
||||||
|
|
@ -174,6 +188,8 @@ class ChunkPool():
|
||||||
# old list comprehension which became too long:
|
# 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)]
|
#coords = [pos for pos, chunk in self._chunks.items() if not pos in except_for and condition(chunk)]
|
||||||
|
|
||||||
|
self.save_changes()
|
||||||
|
|
||||||
coords = []
|
coords = []
|
||||||
|
|
||||||
for pos, chunk in self._chunks.items():
|
for pos, chunk in self._chunks.items():
|
||||||
|
|
|
||||||
41
client.py
41
client.py
|
|
@ -1,20 +1,20 @@
|
||||||
import curses
|
import curses
|
||||||
|
import os
|
||||||
import string
|
import string
|
||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
from maps import Map, ChunkMap
|
from maps import Map, ChunkMap
|
||||||
|
from chunks import ChunkDiff
|
||||||
from clientchunkpool import ClientChunkPool
|
from clientchunkpool import 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.chunkmap_active = False
|
||||||
|
|
||||||
self.address = address
|
self.address = address
|
||||||
self.drawevent = threading.Event()
|
self._drawevent = threading.Event()
|
||||||
self.pool = ClientChunkPool()
|
self.pool = ClientChunkPool(self)
|
||||||
#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,7 +22,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)
|
||||||
self.chunkmap = ChunkMap(self.map_)
|
self.chunkmap = ChunkMap(self.map_)
|
||||||
|
|
||||||
# start input thread
|
# start input thread
|
||||||
|
|
@ -35,7 +35,8 @@ class Client():
|
||||||
self.inputthread.start()
|
self.inputthread.start()
|
||||||
|
|
||||||
while not self.stopping:
|
while not self.stopping:
|
||||||
self.drawevent.wait()
|
self._drawevent.wait()
|
||||||
|
self._drawevent.clear()
|
||||||
stdscr.noutrefresh()
|
stdscr.noutrefresh()
|
||||||
with self.map_ as m:
|
with self.map_ as m:
|
||||||
m.draw()
|
m.draw()
|
||||||
|
|
@ -46,11 +47,13 @@ class Client():
|
||||||
else:
|
else:
|
||||||
curses.curs_set(True)
|
curses.curs_set(True)
|
||||||
|
|
||||||
#m.update_cursor()
|
#m.update_cursor()
|
||||||
#m.noutrefresh()
|
#m.noutrefresh()
|
||||||
|
|
||||||
curses.doupdate()
|
curses.doupdate()
|
||||||
self.drawevent.clear()
|
|
||||||
|
def redraw(self):
|
||||||
|
self._drawevent.set()
|
||||||
|
|
||||||
def input_thread(self, scr):
|
def input_thread(self, scr):
|
||||||
while True:
|
while True:
|
||||||
|
|
@ -59,7 +62,7 @@ class Client():
|
||||||
if i == "\x1b": self.stop()
|
if i == "\x1b": self.stop()
|
||||||
elif i == "KEY_F(2)":
|
elif i == "KEY_F(2)":
|
||||||
self.chunkmap_active = not self.chunkmap_active
|
self.chunkmap_active = not self.chunkmap_active
|
||||||
self.drawevent.set()
|
self.redraw()
|
||||||
elif i == "KEY_F(5)": self.map_.redraw()
|
elif i == "KEY_F(5)": self.map_.redraw()
|
||||||
# scrolling the map (10 vertical, 20 horizontal)
|
# scrolling the map (10 vertical, 20 horizontal)
|
||||||
elif i == "kUP5": self.map_.scroll(0, -10)
|
elif i == "kUP5": self.map_.scroll(0, -10)
|
||||||
|
|
@ -86,11 +89,23 @@ class Client():
|
||||||
elif i == "\x7f": self.map_.delete()
|
elif i == "\x7f": self.map_.delete()
|
||||||
elif i == "\n": self.map_.newline()
|
elif i == "\n": self.map_.newline()
|
||||||
|
|
||||||
else: sys.stdout.write(repr(i) + "\n")
|
else: sys.stderr.write(repr(i) + "\n")
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
self.stopping = True
|
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):
|
def main(argv):
|
||||||
if len(argv) != 2:
|
if len(argv) != 2:
|
||||||
|
|
@ -98,6 +113,8 @@ def main(argv):
|
||||||
print(" {} address".format(argv[0]))
|
print(" {} address".format(argv[0]))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
os.environ.setdefault('ESCDELAY', '25') # only a 25 millisecond delay
|
||||||
|
|
||||||
client = Client(argv[1])
|
client = Client(argv[1])
|
||||||
curses.wrapper(client.launch)
|
curses.wrapper(client.launch)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,31 @@ class ClientChunkPool(ChunkPool):
|
||||||
A ChunkPool that requests/loads chunks from a client.
|
A ChunkPool that requests/loads chunks from a client.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, client):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.max_age = 10 #s
|
|
||||||
|
|
||||||
pass
|
self._client = client
|
||||||
|
|
||||||
|
#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)
|
||||||
|
|
|
||||||
23
maps.py
23
maps.py
|
|
@ -4,15 +4,13 @@ import math
|
||||||
import threading
|
import threading
|
||||||
from utils import CHUNK_HEIGHT, CHUNK_WIDTH, chunkx, chunky, inchunkx, inchunky, Position
|
from utils import CHUNK_HEIGHT, CHUNK_WIDTH, chunkx, chunky, inchunkx, inchunky, Position
|
||||||
|
|
||||||
import sys
|
|
||||||
|
|
||||||
class Map():
|
class Map():
|
||||||
"""
|
"""
|
||||||
A map which displays chunks and a cursor on the screen.
|
A map which displays chunks and a cursor on the screen.
|
||||||
Allows for user to modify chunks in an intuitive way.
|
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._lock = threading.RLock()
|
||||||
|
|
||||||
self.chunkpreload = 0 # preload chunks in this radius (they will count as "visible")
|
self.chunkpreload = 0 # preload chunks in this radius (they will count as "visible")
|
||||||
|
|
@ -26,7 +24,7 @@ class Map():
|
||||||
self.lastcury = self.cursory
|
self.lastcury = self.cursory
|
||||||
|
|
||||||
self.chunkpool = chunkpool
|
self.chunkpool = chunkpool
|
||||||
self.drawevent = drawevent
|
self.client = client
|
||||||
|
|
||||||
self._pad = curses.newpad(5, 5)
|
self._pad = curses.newpad(5, 5)
|
||||||
self.resize(width, height)
|
self.resize(width, height)
|
||||||
|
|
@ -44,7 +42,7 @@ class Map():
|
||||||
def redraw(self):
|
def redraw(self):
|
||||||
self._pad.redrawwin()
|
self._pad.redrawwin()
|
||||||
|
|
||||||
self.drawevent.set()
|
self.client.redraw()
|
||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
with self.chunkpool as pool:
|
with self.chunkpool as pool:
|
||||||
|
|
@ -93,7 +91,7 @@ class Map():
|
||||||
pool.load_list(coords)
|
pool.load_list(coords)
|
||||||
pool.clean_up(except_for=coords, condition=self._unload_condition)
|
pool.clean_up(except_for=coords, condition=self._unload_condition)
|
||||||
|
|
||||||
self.drawevent.set()
|
self.client.redraw()
|
||||||
|
|
||||||
def resize(self, width, height):
|
def resize(self, width, height):
|
||||||
self.width = width
|
self.width = width
|
||||||
|
|
@ -208,7 +206,7 @@ class ChunkMap():
|
||||||
styles = {
|
styles = {
|
||||||
"empty": ChunkStyle("()", 2),
|
"empty": ChunkStyle("()", 2),
|
||||||
"normal": ChunkStyle("[]", 3),
|
"normal": ChunkStyle("[]", 3),
|
||||||
"old": ChunkStyle("{}", 4),
|
"unload": ChunkStyle("{}", 4),
|
||||||
"visible": ChunkStyle("##", 5),
|
"visible": ChunkStyle("##", 5),
|
||||||
"modified": ChunkStyle("!!", 6),
|
"modified": ChunkStyle("!!", 6),
|
||||||
}
|
}
|
||||||
|
|
@ -225,7 +223,7 @@ class ChunkMap():
|
||||||
if curses.has_colors():
|
if curses.has_colors():
|
||||||
curses.init_pair(2, curses.COLOR_BLACK, curses.COLOR_BLUE) # empty chunk
|
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(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(5, curses.COLOR_BLACK, curses.COLOR_GREEN) # visible chunk
|
||||||
curses.init_pair(6, curses.COLOR_BLACK, curses.COLOR_RED) # modified chunk
|
curses.init_pair(6, curses.COLOR_BLACK, curses.COLOR_RED) # modified chunk
|
||||||
|
|
||||||
|
|
@ -236,7 +234,10 @@ class ChunkMap():
|
||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
with self.chunkpool as pool:
|
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
|
sizex = maxx - minx
|
||||||
sizey = maxy - miny
|
sizey = maxy - miny
|
||||||
self.update_size(sizex, sizey)
|
self.update_size(sizex, sizey)
|
||||||
|
|
@ -281,8 +282,8 @@ class ChunkMap():
|
||||||
if pos in self.map_.visible_chunk_coords():
|
if pos in self.map_.visible_chunk_coords():
|
||||||
return "visible"
|
return "visible"
|
||||||
|
|
||||||
if chunk.age() > self.chunkpool.max_age:
|
if self.map_._unload_condition(pos, chunk):
|
||||||
return "old"
|
return "unload"
|
||||||
|
|
||||||
if chunk.empty():
|
if chunk.empty():
|
||||||
return "empty"
|
return "empty"
|
||||||
|
|
|
||||||
6
utils.py
6
utils.py
|
|
@ -2,8 +2,10 @@ from collections import namedtuple
|
||||||
|
|
||||||
Position = namedtuple("Position", "x y")
|
Position = namedtuple("Position", "x y")
|
||||||
|
|
||||||
CHUNK_WIDTH = 64
|
#CHUNK_WIDTH = 64
|
||||||
CHUNK_HEIGHT = 32
|
#CHUNK_HEIGHT = 32
|
||||||
|
CHUNK_WIDTH = 32
|
||||||
|
CHUNK_HEIGHT = 16
|
||||||
|
|
||||||
def chunkx(value):
|
def chunkx(value):
|
||||||
return value//CHUNK_WIDTH
|
return value//CHUNK_WIDTH
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue