Prototype of web streaming

This commit is contained in:
Yohann D'ANELLO 2020-12-02 16:01:32 +01:00
parent e5886bbe44
commit 1ba6b1fbec
3 changed files with 77 additions and 2 deletions

View File

@ -15,6 +15,8 @@ class Display:
height: int height: int
pad: Any pad: Any
screen_lines: list = []
def __init__(self, screen: Any, pack: Optional[TexturePack] = None): def __init__(self, screen: Any, pack: Optional[TexturePack] = None):
self.screen = screen self.screen = screen
self.pack = pack or TexturePack.get_pack("ascii") self.pack = pack or TexturePack.get_pack("ascii")
@ -83,6 +85,14 @@ class Display:
# Refresh the pad only if coordinates are valid # Refresh the pad only if coordinates are valid
pad.refresh(top_y, top_x, window_y, window_x, last_y, last_x) pad.refresh(top_y, top_x, window_y, window_x, last_y, last_x)
height, width = self.pad.getmaxyx()
height = min(height, last_y - window_y + 1)
width = min(width, last_x - window_x + 1)
pad_str = "\n".join(pad.instr(y, top_x).decode("utf-8")[:-1]
for y in range(top_y, top_y + height))
pad_str = self.truncate(pad_str, height, width)
Display.insert_message_in_screen(pad_str, window_y, window_x)
def display(self) -> None: def display(self) -> None:
raise NotImplementedError raise NotImplementedError
@ -94,6 +104,42 @@ class Display:
def cols(self) -> int: def cols(self) -> int:
return curses.COLS if self.screen else 42 return curses.COLS if self.screen else 42
@classmethod
def resize_screen_lines(cls, height: int, width: int) -> None:
cls.screen_lines = cls.screen_lines[:height]
cls.screen_lines += [width * " "
for _ in range(height - len(cls.screen_lines))]
for i in range(len(cls.screen_lines)):
cls.screen_lines[i] = cls.screen_lines[i][:width]
@classmethod
def insert_message_in_screen(cls, message: str, y: int, x: int) -> None:
for i, line in enumerate(message.split("\n")):
if i + y <= len(cls.screen_lines):
line = line[:len(cls.screen_lines[i + y]) - x]
width = len(line)
tmp_width = 0
true_line = ""
for c in line:
tmp_width += 1
true_line += c
if c in TexturePack.SQUIRREL_PACK and c != " " and c != "":
tmp_width += 1
if tmp_width >= width:
break
line = true_line
cls.screen_lines[i + y] = cls.screen_lines[i + y][:x] + line + \
cls.screen_lines[i + y][x + len(line):]
@classmethod
def erase_screen_lines(cls) -> None:
cls.screen_lines = [" " * len(cls.screen_lines[i])
for i in range(len(cls.screen_lines))]
@classmethod
def print_screen(cls) -> str:
return "\n".join(cls.screen_lines)
class VerticalSplit(Display): class VerticalSplit(Display):

View File

@ -2,7 +2,7 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
import curses import curses
from squirrelbattle.display.display import VerticalSplit, HorizontalSplit from squirrelbattle.display.display import VerticalSplit, HorizontalSplit, Display
from squirrelbattle.display.mapdisplay import MapDisplay from squirrelbattle.display.mapdisplay import MapDisplay
from squirrelbattle.display.messagedisplay import MessageDisplay from squirrelbattle.display.messagedisplay import MessageDisplay
from squirrelbattle.display.statsdisplay import StatsDisplay from squirrelbattle.display.statsdisplay import StatsDisplay
@ -51,6 +51,9 @@ class DisplayManager:
self.messagedisplay.update_message(self.game.message) self.messagedisplay.update_message(self.game.message)
def refresh(self) -> None: def refresh(self) -> None:
self.resize_window()
Display.erase_screen_lines()
if self.game.state == GameMode.PLAY: if self.game.state == GameMode.PLAY:
# The map pad has already the good size # The map pad has already the good size
self.mapdisplay.refresh(0, 0, self.rows * 4 // 5, self.mapdisplay.refresh(0, 0, self.rows * 4 // 5,
@ -77,13 +80,30 @@ class DisplayManager:
y, x = (self.rows - height) // 2, (self.cols - width) // 2 y, x = (self.rows - height) // 2, (self.cols - width) // 2
self.messagedisplay.refresh(y, x, height, width) self.messagedisplay.refresh(y, x, height, width)
self.resize_window() with open("squirrel-battle.html", "w") as f:
f.write("<!doctype html>\n<html>\n<head></head>\n<body>\n"
"<div style=\"font-family: Monospace, Noto Color Emoji;\">\n")
f.write("<table style=\"border-collapse: collapse;\"><tbody>\n")
for line in Display.print_screen().split("\n"):
f.write("<tr style=\"margin: 0; padding: 0;\">")
for c in line:
if c in TexturePack.SQUIRREL_PACK.PLAYER and c != TexturePack.SQUIRREL_PACK.PLAYER[0] and c != " ":
continue
squirrel_pack = TexturePack.SQUIRREL_PACK
width = 2 if c in squirrel_pack and c != " " and c != "" else 1
f.write(f"<td style=\"margin: 0; padding: 0;\" colspan=\"{width}\">{c}</td>")
f.write("</tr>")
f.write("\n</tbody></table>\n</div>\n</body>\n<script>\n"
"function reload() {location.reload()}\n"
"setTimeout(reload, 300)\n"
"</script>\n</html>")
def resize_window(self) -> bool: def resize_window(self) -> bool:
""" """
If the window got resized, ensure that the screen size got updated. If the window got resized, ensure that the screen size got updated.
""" """
y, x = self.screen.getmaxyx() if self.screen else (0, 0) y, x = self.screen.getmaxyx() if self.screen else (0, 0)
Display.resize_screen_lines(y, x)
if self.screen and curses.is_term_resized(self.rows, if self.screen and curses.is_term_resized(self.rows,
self.cols): # pragma: nocover self.cols): # pragma: nocover
curses.resizeterm(y, x) curses.resizeterm(y, x)

View File

@ -18,6 +18,12 @@ class TexturePack:
WALL: str WALL: str
FLOOR: str FLOOR: str
PLAYER: str PLAYER: str
HEDGEHOG: str
HEART: str
BOMB: str
RABBIT: str
TIGER: str
TEDDY_BEAR: str
ASCII_PACK: "TexturePack" ASCII_PACK: "TexturePack"
SQUIRREL_PACK: "TexturePack" SQUIRREL_PACK: "TexturePack"
@ -30,6 +36,9 @@ class TexturePack:
def __getitem__(self, item: str) -> Any: def __getitem__(self, item: str) -> Any:
return self.__dict__[item] return self.__dict__[item]
def __contains__(self, item) -> bool:
return any(self[key] == item for key in self.__dict__ if key.isupper())
@classmethod @classmethod
def get_pack(cls, name: str) -> "TexturePack": def get_pack(cls, name: str) -> "TexturePack":
return cls._packs[name.lower()] return cls._packs[name.lower()]