Update WebUI to display server, check, and hint info. CURRENT HINT POINTS DO NOT WORK YET
This commit is contained in:
parent
aa7fe2aa9d
commit
e11f33b589
|
@ -48,9 +48,15 @@ class Context():
|
|||
self.snes_address = snes_address
|
||||
self.server_address = server_address
|
||||
|
||||
# WebUI Stuff
|
||||
self.ui_node = WebUI.WebUiClient()
|
||||
self.custom_address = None
|
||||
self.webui_socket_port: typing.Optional[int] = port
|
||||
self.hint_cost = 0
|
||||
self.check_points = 0
|
||||
self.forfeit_mode = ''
|
||||
self.remaining_mode = ''
|
||||
# End WebUI Stuff
|
||||
|
||||
self.exit_event = asyncio.Event()
|
||||
self.watcher_event = asyncio.Event()
|
||||
|
@ -761,7 +767,13 @@ async def process_server_cmd(ctx: Context, cmd, args):
|
|||
if "forfeit_mode" in args: # could also be version > 2.2.1, but going with implicit content here
|
||||
logging.info("Forfeit setting: "+args["forfeit_mode"])
|
||||
logging.info("Remaining setting: "+args["remaining_mode"])
|
||||
logging.info(f"A !hint costs {args['hint_cost']} points and you get {args['location_check_points']} for each location checked.")
|
||||
logging.info(f"A !hint costs {args['hint_cost']} points and you get {args['location_check_points']}"
|
||||
f" for each location checked.")
|
||||
ctx.hint_cost = int(args['hint_cost'])
|
||||
ctx.check_points = int(args['location_check_points'])
|
||||
ctx.forfeit_mode = args['forfeit_mode']
|
||||
ctx.remaining_mode = args['remaining_mode']
|
||||
ctx.ui_node.send_game_info(ctx)
|
||||
if len(args['players']) < 1:
|
||||
ctx.ui_node.log_info('No player connected')
|
||||
else:
|
||||
|
@ -1045,6 +1057,7 @@ async def track_locations(ctx : Context, roomid, roomdata):
|
|||
def new_check(location):
|
||||
ctx.locations_checked.add(location)
|
||||
ctx.ui_node.log_info("New check: %s (%d/216)" % (location, len(ctx.locations_checked)))
|
||||
ctx.ui_node.send_location_check(ctx, location)
|
||||
new_locations.append(Regions.location_table[location][0])
|
||||
|
||||
for location, (loc_roomid, loc_mask) in location_table_uw.items():
|
||||
|
@ -1223,6 +1236,10 @@ async def websocket_server(websocket: websockets.WebSocketServerProtocol, path,
|
|||
ctx.ui_node.send_connection_status(ctx)
|
||||
elif data['content'] == 'devices':
|
||||
await get_snes_devices(ctx)
|
||||
elif data['content'] == 'gameInfo':
|
||||
ctx.ui_node.send_game_info(ctx)
|
||||
elif data['content'] == 'checkData':
|
||||
ctx.ui_node.send_location_check(ctx, 'Waiting for check...')
|
||||
|
||||
elif data['type'] == 'webConfig':
|
||||
if 'serverAddress' in data['content']:
|
||||
|
|
31
WebUI.py
31
WebUI.py
|
@ -57,6 +57,7 @@ class WebUiClient(Node):
|
|||
'serverAddress': server_address,
|
||||
'server': 1 if ctx.server is not None and not ctx.server.socket.closed else 0,
|
||||
}))
|
||||
|
||||
def send_device_list(self, devices):
|
||||
self.broadcast_all(self.build_message('availableDevices', {
|
||||
'devices': devices,
|
||||
|
@ -105,11 +106,20 @@ class WebUiClient(Node):
|
|||
'entranceLocation': entrance_location,
|
||||
}))
|
||||
|
||||
def send_game_state(self, ctx: Context):
|
||||
self.broadcast_all(self.build_message('gameState', {
|
||||
'hintCost': 0,
|
||||
'checkPoints': 0,
|
||||
'playerPoints': 0,
|
||||
def send_game_info(self, ctx: Context):
|
||||
self.broadcast_all(self.build_message('gameInfo', {
|
||||
'serverVersion': Utils.__version__,
|
||||
'hintCost': ctx.hint_cost,
|
||||
'checkPoints': ctx.check_points,
|
||||
'forfeitMode': ctx.forfeit_mode,
|
||||
'remainingMode': ctx.remaining_mode,
|
||||
}))
|
||||
|
||||
def send_location_check(self, ctx: Context, last_check: str):
|
||||
self.broadcast_all(self.build_message('locationCheck', {
|
||||
'totalChecks': len(ctx.locations_checked),
|
||||
'hintPoints': 0,
|
||||
'lastCheck': last_check,
|
||||
}))
|
||||
|
||||
|
||||
|
@ -117,22 +127,27 @@ class WaitingForUiException(Exception):
|
|||
pass
|
||||
|
||||
|
||||
webthread = None
|
||||
web_thread = None
|
||||
PORT = 5050
|
||||
|
||||
|
||||
class RequestHandler(http.server.SimpleHTTPRequestHandler):
|
||||
def log_request(self, code='-', size='-'):
|
||||
pass
|
||||
|
||||
def log_message(self, format, *args):
|
||||
pass
|
||||
|
||||
def log_date_time_string(self):
|
||||
pass
|
||||
|
||||
|
||||
Handler = partial(RequestHandler,
|
||||
directory=Utils.local_path(os.path.join("data", "web", "public")))
|
||||
|
||||
|
||||
def start_server(socket_port: int, on_start=lambda: None):
|
||||
global webthread
|
||||
global web_thread
|
||||
try:
|
||||
server = socketserver.TCPServer(("", PORT), Handler)
|
||||
except OSError:
|
||||
|
@ -152,4 +167,4 @@ def start_server(socket_port: int, on_start=lambda: None):
|
|||
else:
|
||||
print("serving at port", PORT)
|
||||
on_start()
|
||||
webthread = threading.Thread(target=server.serve_forever).start()
|
||||
web_thread = threading.Thread(target=server.serve_forever).start()
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -46,6 +46,7 @@ class MonitorControls extends Component {
|
|||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
// If there is only one SNES device available, connect to it automatically
|
||||
if (
|
||||
prevProps.availableDevices.length !== this.props.availableDevices.length &&
|
||||
this.props.availableDevices.length === 1
|
||||
|
@ -57,6 +58,17 @@ class MonitorControls extends Component {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
// If we have moved from a disconnected state (default) into a connected state, request the game information
|
||||
if (
|
||||
(
|
||||
(prevProps.snesConnected !== this.props.snesConnected) || // SNES status changed
|
||||
(prevProps.serverConnected !== this.props.serverConnected) // OR server status changed
|
||||
) && ((this.props.serverConnected) && (this.props.snesConnected)) // AND both are connected
|
||||
) {
|
||||
this.props.webSocket.send(WebSocketUtils.formatSocketData('webStatus', 'gameInfo'));
|
||||
this.props.webSocket.send(WebSocketUtils.formatSocketData('webStatus', 'checkData'));
|
||||
}
|
||||
}
|
||||
|
||||
increaseTextSize = () => {
|
||||
|
|
|
@ -2,6 +2,17 @@ import React, { Component } from 'react';
|
|||
import { connect } from 'react-redux';
|
||||
import '../../../styles/WidgetArea/containers/WidgetArea.scss';
|
||||
|
||||
const mapReduxStateToProps = (reduxState) => ({
|
||||
serverVersion: reduxState.gameState.serverVersion,
|
||||
forfeitMode: reduxState.gameState.forfeitMode,
|
||||
remainingMode: reduxState.gameState.remainingMode,
|
||||
hintCost: reduxState.gameState.hintCost,
|
||||
checkPoints: reduxState.gameState.checkPoints,
|
||||
hintPoints: reduxState.gameState.hintPoints,
|
||||
totalChecks: reduxState.gameState.totalChecks,
|
||||
lastCheck: reduxState.gameState.lastCheck,
|
||||
});
|
||||
|
||||
class WidgetArea extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
@ -30,10 +41,67 @@ class WidgetArea extends Component {
|
|||
{
|
||||
this.state.collapsed ? null : (
|
||||
<div id="widget-area-contents">
|
||||
<div id="game-info">
|
||||
<div id="game-info-title">
|
||||
Game Info:
|
||||
<button className="collapse-button" onClick={ this.toggleCollapse }>↪</button>
|
||||
</div>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Server Version:</th>
|
||||
<td>{this.props.serverVersion}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Forfeit Mode:</th>
|
||||
<td>{this.props.forfeitMode}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Remaining Mode:</th>
|
||||
<td>{this.props.remainingMode}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div id="check-data">
|
||||
<div id="check-data-title">Checks:</div>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Total Checks:</th>
|
||||
<td>{this.props.totalChecks}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Last Check:</th>
|
||||
<td>{this.props.lastCheck}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div id="hint-data">
|
||||
<div id="hint-data-title">
|
||||
Hint Data:
|
||||
</div>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Hint Cost:</th>
|
||||
<td>{this.props.hintCost}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Check Points:</th>
|
||||
<td>{this.props.checkPoints}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Current Points:</th>
|
||||
<td>{this.props.hintPoints}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div id="notes">
|
||||
<div id="notes-title">
|
||||
<div>Notes:</div>
|
||||
<button className="collapse-button" onClick={ this.toggleCollapse }>↪</button>
|
||||
</div>
|
||||
<textarea defaultValue={ localStorage.getItem('notes') } onKeyUp={ this.saveNotes } />
|
||||
</div>
|
||||
|
@ -46,4 +114,4 @@ class WidgetArea extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
export default connect()(WidgetArea);
|
||||
export default connect(mapReduxStateToProps)(WidgetArea);
|
||||
|
|
|
@ -1,17 +1,20 @@
|
|||
import _assign from 'lodash-es/assign';
|
||||
|
||||
const initialState = {
|
||||
serverVersion: null,
|
||||
forfeitMode: null,
|
||||
remainingMode: null,
|
||||
connections: {
|
||||
snesDevice: '',
|
||||
snesConnected: false,
|
||||
serverAddress: null,
|
||||
serverConnected: false,
|
||||
},
|
||||
hints: {
|
||||
hintCost: null,
|
||||
checkPoints: null,
|
||||
playerPoints: 0,
|
||||
},
|
||||
totalChecks: 0,
|
||||
lastCheck: null,
|
||||
hintCost: null,
|
||||
checkPoints: null,
|
||||
hintPoints: 0,
|
||||
};
|
||||
|
||||
const gameStateReducer = (state = initialState, action) => {
|
||||
|
|
|
@ -60,6 +60,22 @@ class WebSocketUtils {
|
|||
parseInt(data.content.iAmFinder, 10) === 1, parseInt(data.content.iAmRecipient, 10) === 1,
|
||||
data.content.entranceLocation));
|
||||
|
||||
case 'gameInfo':
|
||||
return updateGameState({
|
||||
serverVersion: data.content.serverVersion,
|
||||
forfeitMode: data.content.forfeitMode,
|
||||
remainingMode: data.content.remainingMode,
|
||||
hintCost: parseInt(data.content.hintCost, 10),
|
||||
checkPoints: parseInt(data.content.checkPoints, 10),
|
||||
});
|
||||
|
||||
case 'locationCheck':
|
||||
return updateGameState({
|
||||
totalChecks: parseInt(data.content.totalChecks, 10),
|
||||
lastCheck: data.content.lastCheck,
|
||||
hintPoints: parseInt(data.content.hintPoints, 10),
|
||||
});
|
||||
|
||||
// The client prints several types of messages to the console
|
||||
case 'critical':
|
||||
case 'error':
|
||||
|
|
|
@ -21,15 +21,36 @@
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
#notes{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
table{
|
||||
th{
|
||||
text-align: left;
|
||||
}
|
||||
td{
|
||||
padding-left: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
#notes-title{
|
||||
#game-info{
|
||||
margin-bottom: 1em;
|
||||
|
||||
#game-info-title{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
#check-data{
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
#hint-data{
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
#notes{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
textarea{
|
||||
height: 10em;
|
||||
|
|
Loading…
Reference in New Issue