sumting
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,4 +1,3 @@
|
||||
__pycache__/
|
||||
venv3/
|
||||
.gitignore
|
||||
*.log
|
||||
|
||||
29
README.md
29
README.md
@ -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
30
ui.py
@ -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'):
|
||||
color = val - ord('0')
|
||||
if color == 7:
|
||||
if ch == '0':
|
||||
bold = True
|
||||
elif ch == '7':
|
||||
color = 0
|
||||
bold = False
|
||||
elif ord('1') <= val <= ord('6'):
|
||||
color = val - ord('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)
|
||||
|
||||
Reference in New Issue
Block a user