Changed the main page.

Added score info (uses http status).
Added a config to make changing some values easier.
This commit is contained in:
Liam 2022-02-15 19:21:09 +00:00
parent c7da5da956
commit 743e0db093
11 changed files with 275 additions and 26 deletions

5
.idea/.gitignore generated vendored Normal file

@ -0,0 +1,5 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/

12
.idea/beatsaber-overlay.iml generated Normal file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

7
.idea/discord.xml generated Normal file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DiscordProjectSettings">
<option name="show" value="PROJECT_FILES" />
<option name="description" value="" />
</component>
</project>

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
</profile>
</component>

8
.idea/modules.xml generated Normal file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/beatsaber-overlay.iml" filepath="$PROJECT_DIR$/.idea/beatsaber-overlay.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml generated Normal file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

150
components/ScoreStats.js Normal file

@ -0,0 +1,150 @@
import {Component, useState} from "react";
export default class ScoreStats extends Component {
constructor(params) {
super(params);
this.state = {
score: 0,
dataSocket: undefined,
isVisible: false,
leftHand: {
averageCut: [15.00],
averagePreSwing: [70.00],
averagePostSwing: [30.00],
},
rightHand: {
averageCut: [15.00],
averagePreSwing: [70.00],
averagePostSwing: [30.00],
}
}
}
componentDidMount() {
const socket = new WebSocket('ws://localhost:6557/socket');
this.setState({ socket: socket });
socket.addEventListener('error' || 'close', () => {
console.log("Attempting to re-connect to the HTTP Status socket.");
this.setState({ socket: new WebSocket('ws://localhost:6557/socket') });
});
socket.addEventListener('message', (message) => {
//console.log("Received message from HTTP Status.");
const json = JSON.parse(message.data);
if (!handlers[json.event]) {
console.log("Unhandled message from HTTP Status. (" + json.event + ")");
return;
}
handlers[json.event](json || []);
})
const handlers = {
"hello": () => {
console.log("Hello from HTTP Status!");
},
"scoreChanged": (data) => {
const { status } = data;
this.setState({ score: status.performance.score })
},
"noteFullyCut": (data) => {
const { noteCut } = data;
// Left Saber
if (noteCut.saberType === 'SaberA') {
const data = this.state.leftHand;
if (data.averageCut.includes(15) && data.averageCut.length === 1) {
data.averageCut = [];
}
if (data.averagePreSwing.includes(70) && data.averagePreSwing.length === 1) {
data.averagePreSwing = [];
}
if (data.averagePostSwing.includes(30) && data.averagePostSwing.length === 1) {
data.averagePostSwing = [];
}
data.averagePreSwing.push(noteCut.initialScore > 70 ? 70 : noteCut.initialScore);
data.averagePostSwing.push(noteCut.finalScore - noteCut.initialScore);
data.averageCut.push(noteCut.cutDistanceScore);
this.setState({ leftHand: data });
}
// Left Saber
if (noteCut.saberType === 'SaberB') {
const data = this.state.rightHand;
if (data.averageCut.includes(15) && data.averageCut.length === 1) {
data.averageCut = [];
}
if (data.averagePreSwing.includes(70) && data.averagePreSwing.length === 1) {
data.averagePreSwing = [];
}
if (data.averagePostSwing.includes(30) && data.averagePostSwing.length === 1) {
data.averagePostSwing = [];
}
data.averagePreSwing.push(noteCut.initialScore > 70 ? 70 : noteCut.initialScore);
data.averagePostSwing.push(noteCut.finalScore - noteCut.initialScore);
data.averageCut.push(noteCut.cutDistanceScore);
this.setState({ rightHand: data });
}
},
"menu": () => {
console.log("Exiting level, resetting data.")
this.setState({
"leftHand": {
"averageCut": [15.00],
"averagePreSwing": [70.00],
"averagePostSwing": [30.00],
},
"rightHand": {
"averageCut": [15.00],
"averagePreSwing": [70.00],
"averagePostSwing": [30.00],
},
isVisible: false
});
},
"songStart": () => {
console.log("Going into level, resetting data.")
this.setState({
"leftHand": {
"averageCut": [15.00],
"averagePreSwing": [70.00],
"averagePostSwing": [30.00],
},
"rightHand": {
"averageCut": [15.00],
"averagePreSwing": [70.00],
"averagePostSwing": [30.00],
},
isVisible: true
});
},
"noteCut": () => {},
"noteMissed": () => {},
"noteSpawned": () => {},
"bombMissed": () => {},
"beatmapEvent": () => {}
}
}
getAverage(values) {
return values.reduce( ( p, c ) => p + c, 0 ) / values.length;
}
render() {
return <div className={'score-stats'} style={{ display: this.state.isVisible ? "block" : "none" }}>
<p>{this.state.score.toLocaleString()}</p>
<div className={'score-stats-hands'}>
<div>
<p>{this.getAverage(this.state.leftHand.averagePreSwing).toFixed(2)}</p>
<p>{this.getAverage(this.state.leftHand.averagePostSwing).toFixed(2)}</p>
<p>{this.getAverage(this.state.leftHand.averageCut).toFixed(2)}</p>
</div>
<div>
<p>{this.getAverage(this.state.rightHand.averagePreSwing).toFixed(2)}</p>
<p>{this.getAverage(this.state.rightHand.averagePostSwing).toFixed(2)}</p>
<p>{this.getAverage(this.state.rightHand.averageCut).toFixed(2)}</p>
</div>
</div>
</div>
}
}

7
config.json Normal file

@ -0,0 +1,7 @@
{
"name": "BeatSaber Overlay",
"description": "Simple scoresaber overlay",
"color": "#0EBFE9",
"url": "https://bs-overlay.fascinated.cc",
"proxy_url": "https://bangor375.herokuapp.com"
}

@ -1,16 +1,18 @@
import Head from 'next/head' import Head from 'next/head'
import Config from '../config.json';
import '../styles/globals.css' import '../styles/globals.css'
function MyApp({ Component, pageProps }) { function MyApp({ Component, pageProps }) {
return <> return <>
<Head> <Head>
<title>BeatSaber Overlay</title> <title>{Config.name}</title>
<meta name="twitter:title" content='BeatSaber Overlay' /> <meta name="twitter:title" content= {Config.name} />
<meta property="og:site_name" content="BeatSaber Overlay" key="title" /> <meta property="og:site_name" content= {Config.name} key="title" />
<meta property="og:url" content="https://bs-overlay.fascinated.cc" key="title" /> <meta property="og:url" content= {Config.url} key="title" />
<meta property="og:description" content="Simple scoresaber overlay" key="description" /> <meta property="og:description" content= {Config.description} key="description" />
<meta name="theme-color" content='#0EBFE9' /> <meta name="theme-color" content= {Config.color} />
</Head> </Head>
<Component {...pageProps} /> <Component {...pageProps} />
</> </>

@ -2,10 +2,13 @@ import Head from 'next/head'
import { Component } from 'react' import { Component } from 'react'
import Avatar from '../components/Avatar'; import Avatar from '../components/Avatar';
import PlayerStats from '../components/PlayerStats'; import PlayerStats from '../components/PlayerStats';
import ScoreStats from '../components/ScoreStats';
import Config from '../config.json';
// Why do u have to proxy requests... it's so dumb LOL // Why do u have to proxy requests... it's so dumb LOL
const API_URL = "https://bangor375.herokuapp.com/https://scoresaber.com/api/player/%s/full"; const API_URL = Config.proxy_url + "/https://scoresaber.com/api/player/%s/full";
const GUTHUB_URL = "https://github.com/RealFascinated/beatsaber-overlay"; const GITHUB_URL = "https://github.com/RealFascinated/beatsaber-overlay";
export default class Home extends Component { export default class Home extends Component {
@ -16,7 +19,9 @@ export default class Home extends Component {
loading: true, loading: true,
id: undefined, id: undefined,
isValidScoresaber: true, isValidScoresaber: true,
data: undefined data: undefined,
showPlayerStats: true,
showScore: false
} }
} }
@ -25,11 +30,21 @@ export default class Home extends Component {
const params = Object.fromEntries(urlSearchParams.entries()); const params = Object.fromEntries(urlSearchParams.entries());
const id = params.id; const id = params.id;
if (!id) { // Check if the id pararm is valid if (!id) { // Check if the id param is valid
this.setState({ loading: false, isValidScoresaber: false }); this.setState({ loading: false, isValidScoresaber: false });
return; return;
} }
// Check if the player wants to disable their stats (pp, global pos, etc)
if (params.playerstats === 'false') {
this.setState({ showPlayerStats: false });
}
// Check if the player wants to show their current score information on the overlay
if (params.scoreinfo === 'true') {
this.setState({ showScore: true });
}
await this.updateData(id); await this.updateData(id);
setTimeout(async () => { setTimeout(async () => {
if (!this.state.isValidScoresaber) { if (!this.state.isValidScoresaber) {
@ -53,7 +68,6 @@ export default class Home extends Component {
return; return;
} }
this.setState({ loading: false, id: id, data: json }); this.setState({ loading: false, id: id, data: json });
console.log(json);
} }
render() { render() {
@ -71,18 +85,28 @@ export default class Home extends Component {
</div> </div>
: !isValidScoresaber ? : !isValidScoresaber ?
<div className={'invalid-player'}> <div className={'invalid-player'}>
<p>Provide a valid scoresaber id</p> <div style={{ fontWeight: 'bold', marginBottom: '50px' }}>
<p>Example: {document.location.origin}?id=76561198449412074</p>
<div className={'info'}>
<p>This is currently just a simple overlay for OBS displaying ScoreSaber stats.</p> <p>This is currently just a simple overlay for OBS displaying ScoreSaber stats.</p>
<p>If you have any suggestions you can message me on discord @ Fascinated#4719</p> <p>If you have any suggestions you can message me on discord @ Fascinated#4719</p>
</div>
<p>Provide a valid scoresaber id</p>
<p>Example: {document.location.origin}?id=76561198449412074</p>
<p>Example with Score Info: {document.location.origin}?id=76561198449412074&scoreinfo=true</p>
<p>Example with Score Info and without Player Stats: {document.location.origin}?id=76561198449412074&scoreinfo=true&playerstats=false</p>
<div className={'info'}>
<div>
<h3>Options</h3>
<p>scoreinfo - Can be &quot;true&quot; if you want to show your current score (needs HTTP Status)</p>
<p>playerstats - Can be &quot;false&quot; if you disable showing your stats (pp, global pos, etc)</p>
</div>
<div className={'info'}> <div className={'info'}>
<p>If you use this overlay and like it, don&apos;t forget to star the project :3</p> <p>If you use this overlay and like it, don&apos;t forget to star the project :3</p>
<p>Github link: <span><a href={GUTHUB_URL}>{GUTHUB_URL}</a></span></p> <p>Github link: <span><a href={GITHUB_URL}>{GITHUB_URL}</a></span></p>
</div> </div>
</div> </div>
</div> : </div> :
<div className={'overlay'}> <div className={'overlay'}>
{ this.state.showPlayerStats ?
<div className={'player-stats-container'}> <div className={'player-stats-container'}>
<Avatar url={data.profilePicture} /> <Avatar url={data.profilePicture} />
<PlayerStats <PlayerStats
@ -91,7 +115,13 @@ export default class Home extends Component {
country={data.country} country={data.country}
countryRank={data.countryRank.toLocaleString()} countryRank={data.countryRank.toLocaleString()}
/> />
</div> </div> :
""
}
{
this.state.showScore ? <ScoreStats /> :
""
}
</div> </div>
} }
</> </>

@ -50,8 +50,7 @@
} }
.player-country p { .player-country p {
margin: 0; margin: 0 6px 0 0;
margin-right: 6px;
} }
.player-country-icon { .player-country-icon {
@ -68,3 +67,20 @@
margin-left: 10px; margin-left: 10px;
margin-top: -12px; margin-top: -12px;
} }
.score-stats {
text-align: right;
position:absolute;
top:0;
right:0;
margin-right: 15px;
}
.score-stats-hands {
display: flex;
margin-top: -30px;
}
.score-stats-hands div {
padding-left: 10px;
}