This commit is contained in:
xbl
2025-12-23 10:18:50 +01:00
parent 6b4445b538
commit c648a99439
3 changed files with 18 additions and 42 deletions

1
.gitignore vendored
View File

@ -1,4 +1,3 @@
__pycache__/
venv3/
.gitignore
*.log

View File

@ -1,8 +1,6 @@
# QLPyCon - Quake Live Python Console
A modular, refactored terminal-based client for monitoring Quake Live servers via ZMQ.
## Version 0.8.0 - Modular Architecture
A modular, refactored terminal-based client for monitoring and remote controlling Quake Live servers via ZMQ.
### Features
@ -93,15 +91,6 @@ python main.py --unknown-log my_unknown.log
- Threaded input queue for non-blocking commands
- Color rendering with curses
### Key Improvements Over v0.7.0
1. **Modular Design** - Separated concerns into focused modules
2. **Clean Classes** - OOP design for state and connections
3. **Better Maintainability** - Each module has a single responsibility
4. **Easier Testing** - Components can be tested independently
5. **Clear Interfaces** - Well-defined APIs between modules
6. **Improved Comments** - Every module, class, and function documented
### Event Types Supported
- `PLAYER_SWITCHTEAM` - Team changes
@ -125,20 +114,6 @@ Quake Live uses `^N` color codes where N is 0-7:
- `^6` - Magenta
- `^7` - White (default)
### Development
To extend QLPyCon:
1. **Add new event types** - Edit `parser.py`, add handler method
2. **Change UI layout** - Edit `ui.py`, modify window creation
3. **Add new commands** - Edit `main.py`, handle in main loop
4. **Modify formatting** - Edit `formatter.py`, adjust color/timestamp logic
5. **Add configuration** - Edit `config.py`, add constants
### License
MIT License - See original qlpycon.py for details
### Credits
Refactored from qlpycon.py v0.7.0
WTFPL

30
ui.py
View File

@ -36,38 +36,40 @@ class CursesHandler(logging.Handler):
except:
self.handleError(record)
def print_colored(window, message, attributes=0):
"""
Print message with Quake color codes (^N)
^0 = black, ^1 = red, ^2 = green, ^3 = yellow, ^4 = blue, ^5 = cyan, ^6 = magenta, ^7 = white
^0 = bold, ^1 = red, ^2 = green, ^3 = yellow, ^4 = blue, ^5 = cyan, ^6 = magenta, ^7 = white/reset
"""
if not curses.has_colors:
window.addstr(message)
return
color = 0
bold = False
parse_color = False
for ch in message:
val = ord(ch)
if parse_color:
if ord('0') <= val <= ord('7'):
if ch == '0':
bold = True
elif ch == '7':
color = 0
bold = False
elif ord('1') <= val <= ord('6'):
color = val - ord('0')
if color == 7:
color = 0
else:
window.addch('^', curses.color_pair(color) | attributes)
window.addch(ch, curses.color_pair(color) | attributes)
window.addch('^', curses.color_pair(color) | (curses.A_BOLD if bold else 0) | attributes)
window.addch(ch, curses.color_pair(color) | (curses.A_BOLD if bold else 0) | attributes)
parse_color = False
elif ch == '^':
parse_color = True
else:
window.addch(ch, curses.color_pair(color) | attributes)
window.addch(ch, curses.color_pair(color) | (curses.A_BOLD if bold else 0) | attributes)
window.refresh()
class UIManager:
"""Manages curses windows and display"""
@ -196,7 +198,7 @@ class UIManager:
# Line 1: Hostname
hostname = server_info.hostname
print_colored(self.info_window, f"^6═══ {hostname} ^6═══^7\n", 0)
print_colored(self.info_window, f"^6═══^0 {hostname} ^7^6═══^7\n", 0)
# Line 2: Game info
gametype = server_info.gametype
@ -209,14 +211,14 @@ class UIManager:
maxclients = server_info.maxclients
print_colored(self.info_window,
f"^3Type:^7 {gametype} ^3Map:^7 {mapname} ^3Players:^7 {curclients}/{maxclients} "
f"^3Limits (T/F/R/C):^7 {timelimit}/{fraglimit}/{roundlimit}/{caplimit}\n", 0)
f"^3Type:^7^0 {gametype} ^7^3Map:^7^0 {mapname} ^7^3Players:^7^0 {curclients}/{maxclients} "
f"^7^3Limits (T/F/R/C):^7 {timelimit}/{fraglimit}/{roundlimit}/{caplimit}\n", 0)
# Line 3: Team headers and player lists
teams = game_state.player_tracker.get_players_by_team()
if server_info.gametype in TEAM_MODES:
print_colored(self.info_window, f"^1(RED) ^4(BLUE) ^3(SPEC)\n", 0)
print_colored(self.info_window, f"^0^1(RED) ^4(BLUE) ^3(SPEC)\n", 0)
red_players = teams['RED'][:4]
blue_players = teams['BLUE'][:4]
@ -240,7 +242,7 @@ class UIManager:
line = f"{red}{' ' * red_pad}{blue}{' ' * blue_pad}{spec}\n"
print_colored(self.info_window, line, 0)
else:
print_colored(self.info_window, f"^3(FREE)\n", 0)
print_colored(self.info_window, f"^0^3(FREE)\n", 0)
free_players = teams['FREE'][:4]
for player in free_players:
print_colored(self.info_window, f"{player}\n", 0)