Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
c058ab6
Add tournament mode state, labels for drawings
noahm Aug 28, 2022
71f06ff
Add 'send to stream' button
noahm Aug 28, 2022
6bb839d
Try out handling individual drawings in zustand
noahm Aug 28, 2022
211c717
Upgrade react
noahm Sep 2, 2022
f6a238a
Merge remote-tracking branch 'origin/main' into react18
noahm Sep 2, 2022
a117187
switch to modern react-dom api
noahm Sep 2, 2022
9743837
Use concurrent mode for eligible charts
noahm Sep 2, 2022
6be3cbc
Remove border from dark navbar
noahm Sep 2, 2022
3f89514
Merge branch 'react18' into tournament-mode
noahm Sep 9, 2022
be0d931
First mostly working version of p2p sharing
noahm Sep 9, 2022
6b8ce87
UI pass on remote sharing
noahm Sep 9, 2022
682707a
Burn in variant data to drawing objects
noahm Sep 9, 2022
8e7a6da
Slightly cleaner peerjs import hassle
noahm Sep 10, 2022
b3d07dd
Fix bad webpack config
noahm Sep 10, 2022
7343ed8
Start experimenting with bundle split
noahm Sep 10, 2022
5ffb7f9
Networking UI overhaul
noahm Sep 17, 2022
26f9417
More networking UX polish
noahm Sep 18, 2022
000fb06
Switch to random ids for drawings
noahm Sep 18, 2022
020441e
Fix sending to single peers
noahm Sep 18, 2022
3d57c85
Mostly working real-time-sync
noahm Sep 19, 2022
7db15bc
Switch to supporting a single peer per drawing
noahm Sep 19, 2022
c6e1e6c
Use player names instead of P1/P2
noahm Sep 19, 2022
5597cab
Better menu feedback for peer states
noahm Sep 19, 2022
47658cf
Add offset for apple icons
noahm Sep 19, 2022
51d788c
Replace round label with Select dropdown
Thanhqd90 Sep 22, 2022
d478d84
Removed HTMLSelect import
Thanhqd90 Sep 22, 2022
4065d09
Added right element prop to InputGroup
Thanhqd90 Sep 23, 2022
4e86d74
Added copy to keyboard button
Thanhqd90 Sep 23, 2022
c5a08c7
Merge pull request #102 from Thanhqd90/tournament-mode
noahm Sep 23, 2022
29a9fd0
Simplify tournament round entry
noahm Sep 23, 2022
0ff98ae
Tiny cleanup for remote peer menu
noahm Sep 23, 2022
a01d062
Add option to hide vetoed charts
noahm Sep 24, 2022
6806288
Merge remote-tracking branch 'origin/main' into tournament-mode
noahm Sep 24, 2022
e1bb6fa
Merge branch 'main' into tournament-mode
noahm Oct 7, 2022
02b5525
Merge branch 'main' into tournament-mode
noahm Oct 28, 2022
2d53fab
Add ability to mark winners on song cards
noahm Oct 29, 2022
b6a931b
Merge branch 'main' into tournament-mode
noahm Nov 1, 2022
730a759
Merge branch 'main' into tournament-mode
noahm Nov 24, 2022
cf1f039
Merge branch 'main' into tournament-mode
noahm May 29, 2023
4f51c8f
Merge branch 'main' into event-mode
noahm May 29, 2023
a08ab63
Allow node back to 18.15
noahm May 29, 2023
3231317
Commit lockfile changes
noahm May 30, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 13 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"version": "1.0.0",
"description": "Tools for music game tournaments and training",
"engines": {
"node": "^18.16.0"
"node": "^18.15.0"
},
"scripts": {
"start": "webpack serve --env dev=true",
Expand Down Expand Up @@ -45,10 +45,10 @@
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.8",
"@types/better-sqlite3": "^7.6.0",
"@types/fuzzy-search": "^2.1.0",
"@types/react": "^17.0.34",
"@types/react-dom": "^17.0.11",
"autoprefixer": "^10.4.14",
"babel-loader": "^9.1.2",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"autoprefixer": "^10.4.0",
"babel-loader": "^9.0.0",
"better-sqlite3": "^8.0.0",
"cacheable-lookup": "^7.0.0",
"classnames": "^2.3.1",
Expand All @@ -72,17 +72,19 @@
"json-schema-to-typescript": "^12.0.0",
"jsonschema": "^1.4.1",
"mini-css-extract-plugin": "^2.7.6",
"nanoid": "^4.0.0",
"node-fetch": "^2.6.7",
"normalize.css": "^8.0.1",
"p-queue": "^6.0.0",
"peerjs": "^2.0.0-beta.3",
"postcss": "^8.4.4",
"postcss-loader": "^6.2.1",
"prettier": "^2.8.0",
"query-string": "^6.13.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"react-feather": "^2.0.9",
"react-intl": "^6.3.0",
"react-intl": "^6.0.0",
"react-refresh": "^0.14.0",
"sanitize-filename": "^1.6.3",
"simfile-parser": "^0.4.0",
Expand All @@ -95,14 +97,16 @@
"webpack-sources": "^3.2.1",
"xml2js": "^0.5.0",
"zip-webpack-plugin": "^4.0.0",
"zustand": "^3.6.4"
"zustand": "^4.1.0"
},
"resolutions": {
"loader-utils": "^2.0.0",
"xml2js": "^0.5.0"
},
"dependencies": {
"@reduxjs/toolkit": "^1.9.5",
"@vercel/analytics": "^1.0.1",
"react-redux": "^8.0.5",
"web-vitals": "^3.3.1"
}
}
6 changes: 5 additions & 1 deletion src/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ body:global(.bp4-dark) {
background-color: #222;
}

:global(.bp4-dark) :global(.bp4-navbar) {
box-shadow: none;
}

.container {
display: flex;
flex-direction: column;
Expand All @@ -38,7 +42,7 @@ input[type="number"],
input[type="password"],
input[type="search"],
input[type="tel"],
input[type="text"],
input[type="text"]:not(:global(.bp4-editable-text-input)),
input[type="time"],
input[type="url"],
input[type="week"],
Expand Down
6 changes: 4 additions & 2 deletions src/assets/i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@
"ban": "Veto",
"pocketPick": "Pocket Pick",
"reset": "Reset",
"cancel": "Cancel"
"cancel": "Cancel",
"winner": "Pick Winner"
},
"noValidCharts": "No valid charts",
"showSongPool": "Show eligible charts",
Expand Down Expand Up @@ -179,7 +180,8 @@
"ban": "Veto",
"pocketPick": "Pocket Pick",
"reset": "Reset",
"cancel": "Cancel"
"cancel": "Cancel",
"winner": "Pick Winner"
},
"noValidCharts": "No valid charts",
"showSongPool": "Show eligible charts",
Expand Down
44 changes: 25 additions & 19 deletions src/card-draw.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,32 @@
import { nanoid } from "nanoid";
import { GameData, Song, Chart } from "./models/SongData";
import { times } from "./utils";
import { DrawnChart, Drawing } from "./models/Drawing";
import { DrawnChart, EligibleChart, Drawing } from "./models/Drawing";
import { ConfigState } from "./config-state";

export function getDrawnChart(currentSong: Song, chart: Chart): DrawnChart {
import { getDifficultyColor } from "./hooks/useDifficultyColor";
import { getDiffAbbr } from "./game-data-utils";

export function getDrawnChart(
gameData: GameData,
currentSong: Song,
chart: Chart
): EligibleChart {
return {
name: currentSong.name,
jacket: chart.jacket || currentSong.jacket,
nameTranslation: currentSong.name_translation,
artist: currentSong.artist,
artistTranslation: currentSong.artist_translation,
bpm: currentSong.bpm,
difficultyClass: chart.diffClass,
level: chart.lvl,
flags: (chart.flags || []).concat(currentSong.flags || []),
song: currentSong,
// Fill in variant data per game
diffAbbr: getDiffAbbr(gameData, chart.diffClass),
diffColor: getDifficultyColor(gameData, chart.diffClass),
};
}

/**
* Used to give each drawing an auto-incrementing id
*/
let drawingID = 0;

/** returns true if song matches configured flags */
export function songIsValid(
config: ConfigState,
Expand Down Expand Up @@ -53,8 +57,8 @@ export function chartIsValid(
);
}

export function* eligibleCharts(config: ConfigState, songs: Song[]) {
for (const currentSong of songs) {
export function* eligibleCharts(config: ConfigState, gameData: GameData) {
for (const currentSong of gameData.songs) {
if (!songIsValid(config, currentSong)) {
continue;
}
Expand All @@ -66,7 +70,7 @@ export function* eligibleCharts(config: ConfigState, songs: Song[]) {
}

// add chart to deck
yield getDrawnChart(currentSong, chart);
yield getDrawnChart(gameData, currentSong, chart);
}
}
}
Expand All @@ -88,12 +92,12 @@ export function draw(gameData: GameData, configData: ConfigState): Drawing {
weights,
} = configData;

const validCharts: Record<string, Array<DrawnChart>> = {};
const validCharts: Record<string, Array<EligibleChart>> = {};
times(gameData.meta.lvlMax, (n) => {
validCharts[n.toString()] = [];
});

for (const chart of eligibleCharts(configData, gameData.songs)) {
for (const chart of eligibleCharts(configData, gameData)) {
validCharts[chart.level].push(chart);
}

Expand Down Expand Up @@ -159,10 +163,12 @@ export function draw(gameData: GameData, configData: ConfigState): Drawing {
const randomChart = selectableCharts[randomIndex];

if (randomChart) {
// Give this random chart a unique id within this drawing
randomChart.id = drawnCharts.length;
// Save it in our list of drawn charts
drawnCharts.push(randomChart);
drawnCharts.push({
...randomChart,
// Give this random chart a unique id within this drawing
id: drawnCharts.length,
});
// remove drawn chart from deck so it cannot be re-drawn
selectableCharts.splice(randomIndex, 1);
if (!difficultyCounts[chosenDifficulty]) {
Expand All @@ -184,12 +190,12 @@ export function draw(gameData: GameData, configData: ConfigState): Drawing {
}
}

drawingID += 1;
return {
id: drawingID,
id: nanoid(10),
charts: drawnCharts,
bans: [],
protects: [],
pocketPicks: [],
winners: [],
};
}
6 changes: 4 additions & 2 deletions src/config-state.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,28 @@
import createStore, { SetState } from "zustand";
import createStore, { StoreApi } from "zustand";

export interface ConfigState {
chartCount: number;
upperBound: number;
lowerBound: number;
useWeights: boolean;
orderByAction: boolean;
showVeto: boolean;
weights: number[];
forceDistribution: boolean;
constrainPocketPicks: boolean;
style: string;
difficulties: ReadonlySet<string>;
flags: ReadonlySet<string>;
showPool: boolean;
update: SetState<ConfigState>;
update: StoreApi<ConfigState>["setState"];
}

export const useConfigState = createStore<ConfigState>((set, get) => ({
chartCount: 5,
upperBound: 0,
lowerBound: 0,
useWeights: false,
showVeto: true,
orderByAction: true,
weights: [],
forceDistribution: true,
Expand Down
10 changes: 2 additions & 8 deletions src/controls/controls.css
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
.form {
.drawer {
padding: 1em 1.5em;
overflow-y: auto;
}

.form hr {
border-color: rgba(17, 20, 24, 0.8);
border-style: solid;
border-bottom-width: 0;
}

.form label {
.drawer label {
user-select: none;
}

Expand Down
61 changes: 47 additions & 14 deletions src/controls/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,19 @@ import {
Switch,
NavbarDivider,
DrawerSize,
Divider,
Tabs,
Tab,
Icon,
} from "@blueprintjs/core";
import { Tooltip2 } from "@blueprintjs/popover2";
import { IconNames } from "@blueprintjs/icons";
import { useIsNarrow } from "../hooks/useMediaQuery";
import { EligibleChartsListFilter } from "../eligible-charts-list";
import { EligibleChartsListFilter } from "../eligible-charts/filter";
import shallow from "zustand/shallow";
import { TournamentModeToggle } from "../tournament-mode/tournament-mode-toggle";
import { RemotePeerControls } from "../tournament-mode/remote-peer-menu";
import { useRemotePeers } from "../tournament-mode/remote-peers";

function getAvailableDifficulties(gameData: GameData, selectedStyle: string) {
let s = new Set<string>();
Expand Down Expand Up @@ -100,10 +107,7 @@ export function HeaderControls() {

function handleDraw() {
useConfigState.setState({ showPool: false });
const couldDraw = drawSongs(useConfigState.getState());
if (couldDraw !== !lastDrawFailed) {
setLastDrawFailed(!couldDraw);
}
drawSongs(useConfigState.getState());
}

function openSettings() {
Expand All @@ -119,13 +123,10 @@ export function HeaderControls() {
size={isNarrow ? DrawerSize.LARGE : "500px"}
onClose={() => setSettingsOpen(false)}
title={
<FormattedMessage
id="settings.title"
defaultMessage="Card Draw Options"
/>
<FormattedMessage id="settings.title" defaultMessage="Settings" />
}
>
<Controls />
<ControlsDrawer />
</Drawer>
{!isNarrow && (
<>
Expand Down Expand Up @@ -158,7 +159,28 @@ export function HeaderControls() {
);
}

function Controls() {
function ControlsDrawer() {
const isConnected = useRemotePeers((r) => !!r.thisPeer);
const hasPeers = useRemotePeers((r) => !!r.remotePeers.size);
return (
<div className={styles.drawer}>
<Tabs id="settings" large>
<Tab id="general" panel={<GeneralSettings />}>
<Icon icon={IconNames.Settings} /> General
</Tab>
<Tab id="network" panel={<RemotePeerControls />}>
<Icon
icon={hasPeers ? IconNames.ThirdParty : IconNames.GlobeNetwork}
intent={isConnected ? "success" : "none"}
/>{" "}
Networking
</Tab>
</Tabs>
</div>
);
}

function GeneralSettings() {
const { t } = useIntl();
const [dataSetName, gameData] = useDrawState(
(s) => [s.dataSetName, s.gameData],
Expand All @@ -169,6 +191,7 @@ function Controls() {
useWeights,
constrainPocketPicks,
orderByAction,
showVeto,
lowerBound,
upperBound,
update: updateState,
Expand Down Expand Up @@ -209,7 +232,7 @@ function Controls() {
};

return (
<form className={styles.form} onSubmit={(e) => e.preventDefault()}>
<>
{isNarrow && (
<>
<FormGroup>
Expand All @@ -220,7 +243,7 @@ function Controls() {
<EligibleChartsListFilter />
</FormGroup>
)}
<hr />
<Divider />
</>
)}
<div className={isNarrow ? undefined : styles.inlineControls}>
Expand Down Expand Up @@ -358,6 +381,15 @@ function Controls() {
}}
label={t("orderByAction")}
/>
<Checkbox
id="showVeto"
checked={showVeto}
onChange={(e) => {
const next = !!e.currentTarget.checked;
updateState({ showVeto: next });
}}
label={t("showVeto", undefined, "Show vetoed charts")}
/>
<Checkbox
id="constrainPocketPicks"
checked={constrainPocketPicks}
Expand All @@ -367,6 +399,7 @@ function Controls() {
}}
label={t("constrainPocketPicks")}
/>
<TournamentModeToggle />
<Checkbox
id="weighted"
checked={useWeights}
Expand All @@ -378,6 +411,6 @@ function Controls() {
/>
{useWeights && <WeightsControls high={upperBound} low={lowerBound} />}
</FormGroup>
</form>
</>
);
}
Loading