Changed the main page.
Added score info (uses http status). Added a config to make changing some values easier.
This commit is contained in:
parent
c7da5da956
commit
743e0db093
5
.idea/.gitignore
generated
vendored
Normal file
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
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
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>
|
6
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
6
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@ -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
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
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
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
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,27 +85,43 @@ 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 "true" if you want to show your current score (needs HTTP Status)</p>
|
||||||
|
<p>playerstats - Can be "false" 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't forget to star the project :3</p>
|
<p>If you use this overlay and like it, don'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'}>
|
||||||
<div className={'player-stats-container'}>
|
{ this.state.showPlayerStats ?
|
||||||
<Avatar url={data.profilePicture} />
|
<div className={'player-stats-container'}>
|
||||||
<PlayerStats
|
<Avatar url={data.profilePicture} />
|
||||||
pp={data.pp.toLocaleString()}
|
<PlayerStats
|
||||||
globalPos={data.rank.toLocaleString()}
|
pp={data.pp.toLocaleString()}
|
||||||
country={data.country}
|
globalPos={data.rank.toLocaleString()}
|
||||||
countryRank={data.countryRank.toLocaleString()}
|
country={data.country}
|
||||||
/>
|
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;
|
||||||
|
}
|
Reference in New Issue
Block a user