Update WebUI to display server, check, and hint info. CURRENT HINT POINTS DO NOT WORK YET

This commit is contained in:
Chris 2020-06-14 18:04:03 -04:00
parent aa7fe2aa9d
commit e11f33b589
8 changed files with 173 additions and 21 deletions

View File

@ -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']:

View File

@ -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

View File

@ -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 = () => {

View File

@ -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);

View File

@ -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) => {

View File

@ -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':

View File

@ -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;