This commit is contained in:
Michael Zhang 2024-05-03 21:38:17 -05:00
parent 3dd301a334
commit 132524eba3
8 changed files with 130 additions and 53 deletions

1
.gitignore vendored
View file

@ -1 +1,2 @@
node_modules
dist

1
.tokeignore Normal file
View file

@ -0,0 +1 @@
pnpm-lock.yaml

View file

@ -1,25 +1,28 @@
{
"name": "osuplayer.js",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "vite"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@biomejs/biome": "1.7.2",
"@types/three": "^0.164.0",
"vite": "^5.2.11",
"vite-plugin-node-polyfills": "^0.21.0"
},
"dependencies": {
"@zip.js/zip.js": "^2.7.43",
"osu-classes": "^3.1.0",
"osu-parsers": "^4.1.7",
"rosu-pp-js": "https://github.com/MaxOhn/rosu-pp-js/releases/download/v1.0.2/rosu_pp_js_web.tar.gz",
"three": "^0.164.1"
}
"name": "osuplayer.js",
"version": "1.0.0",
"description": "",
"main": "index.js",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@biomejs/biome": "1.7.2",
"@types/three": "^0.164.0",
"vite": "^5.2.11",
"vite-bundle-analyzer": "^0.9.4",
"vite-plugin-node-polyfills": "^0.21.0"
},
"dependencies": {
"@zip.js/zip.js": "^2.7.43",
"osu-classes": "^3.1.0",
"osu-parsers": "^4.1.7",
"rosu-pp-js": "https://github.com/MaxOhn/rosu-pp-js/releases/download/v1.0.2/rosu_pp_js_web.tar.gz",
"three": "^0.164.1"
}
}

View file

@ -31,6 +31,9 @@ devDependencies:
vite:
specifier: ^5.2.11
version: 5.2.11
vite-bundle-analyzer:
specifier: ^0.9.4
version: 0.9.4
vite-plugin-node-polyfills:
specifier: ^0.21.0
version: 0.21.0(vite@5.2.11)
@ -1379,6 +1382,11 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
/source-map@0.7.4:
resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==}
engines: {node: '>= 8'}
dev: true
/stream-browserify@3.0.0:
resolution: {integrity: sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==}
dependencies:
@ -1452,6 +1460,13 @@ packages:
which-typed-array: 1.1.15
dev: true
/vite-bundle-analyzer@0.9.4:
resolution: {integrity: sha512-a/w4ShKQEbTe7wllLXI+3D8ELgRv7iHDuWEPaXokA+FhWBXJCdtOZYIvLzvnn8vxHf+7pm1c23AeGyW/0Ge0Yw==}
dependencies:
picocolors: 1.0.0
source-map: 0.7.4
dev: true
/vite-plugin-node-polyfills@0.21.0(vite@5.2.11):
resolution: {integrity: sha512-Sk4DiKnmxN8E0vhgEhzLudfJQfaT8k4/gJ25xvUPG54KjLJ6HAmDKbr4rzDD/QWEY+Lwg80KE85fGYBQihEPQA==}
peerDependencies:

View file

@ -20,6 +20,8 @@ class OsuPlayer {
beatmapSet: BeatmapSet = new BeatmapSet();
diffsByStarRating: [number, number][] = [];
diffs: Map<number, Beatmap> = new Map();
audioTimestamp: number;
audioBuffer: AudioBuffer;
constructor(opts?: OsuPlayerOpts) {
if (opts) this.opts = opts;
@ -66,29 +68,7 @@ class OsuPlayer {
}
this.diffsByStarRating.sort((a, b) => a[0] - b[0]);
/*
const listEl = document.createElement("ul");
listEl.style.margin = "0";
for (const [stars, id] of this.diffsByStarRating) {
// biome-ignore lint/style/noNonNullAssertion: <explanation>
const diff = this.diffs.get(id)!;
const liEl = document.createElement("li");
const aEl = document.createElement("a");
aEl.href = "javascript:void(0)";
aEl.text = `${diff.osuInner.metadata.version} (${
Math.round(stars * 100) / 100
}*)`;
aEl.addEventListener("click", (evt) => {
this.setBeatmap(id);
});
liEl.appendChild(aEl);
listEl.appendChild(liEl);
}
console.log([...this.beatmapSet.assets.entries()]);
this.el?.replaceChildren(listEl);
*/
// TODO: Debug
this.setBeatmap(
this.diffsByStarRating[this.diffsByStarRating.length - 1][1],
);
@ -99,6 +79,29 @@ class OsuPlayer {
});
}
showDiffSelector() {
const listEl = document.createElement("ul");
listEl.style.margin = "0";
for (const [stars, id] of this.diffsByStarRating) {
// biome-ignore lint/style/noNonNullAssertion: <explanation>
const diff = this.diffs.get(id)!;
const liEl = document.createElement("li");
const aEl = document.createElement("a");
aEl.href = "javascript:void(0)";
aEl.text = `${diff.osuInner.metadata.version} (${
Math.round(stars * 100) / 100
}*)`;
aEl.addEventListener("click", (evt) => {
this.setBeatmap(id);
});
liEl.appendChild(aEl);
listEl.appendChild(liEl);
}
console.log([...this.beatmapSet.assets.entries()]);
this.el?.replaceChildren(listEl);
}
setBeatmap(id: number) {
this.canvasEl = document.createElement("canvas");
this.canvasEl.width = 1024;
@ -111,14 +114,17 @@ class OsuPlayer {
const beatmap = this.diffs.get(id)!;
const backgroundUrl = URL.createObjectURL(beatmap.background());
const audioUrl = beatmap.audioFile();
console.log(audioUrl);
const scene = new THREE.Scene();
const camera = new THREE.OrthographicCamera(-512, 512, -384, 384, 1, 1000);
scene.add(camera);
scene.add(new THREE.AmbientLight());
const clock = new THREE.Clock();
const loader = new THREE.TextureLoader();
const audioContext = new AudioContext();
let backgroundPlane: THREE.Mesh;
{
@ -140,15 +146,46 @@ class OsuPlayer {
const renderer = new THREE.WebGLRenderer({ canvas: this.canvasEl });
const stats = new Stats();
this.el?.replaceChildren(this.canvasEl, stats.dom);
function animate() {
requestAnimationFrame(animate);
const loadMusic = async () => {
const audioStream = audioUrl.stream();
const buffer = await new Response(audioStream).arrayBuffer();
const musicBuffer = await audioContext.decodeAudioData(buffer);
this.audioBuffer = musicBuffer;
};
renderer.render(scene, camera);
}
const loadStuff = () => {
return Promise.all([loadMusic()]);
};
animate();
const play = () => {
const gainNode = audioContext.createGain();
gainNode.gain.value = 0.01;
gainNode.connect(audioContext.destination);
const audioSource = audioContext.createBufferSource();
audioSource.buffer = this.audioBuffer;
audioSource.connect(gainNode);
audioSource.start();
const updateObjects = () => {};
const animate = () => {
requestAnimationFrame(animate);
this.audioTimestamp = audioContext.getOutputTimestamp().contextTime;
updateObjects();
renderer.render(scene, camera);
};
animate();
};
loadStuff().then(() => {
console.log("loaded!");
play();
});
}
}

View file

@ -16,6 +16,12 @@ export class Beatmap {
return this.osuInner.metadata.beatmapId;
}
public audioFile(): Blob {
const filename = this.osuInner.general.audioFilename;
// biome-ignore lint/style/noNonNullAssertion: <explanation>
return this.set.assets.get(filename)!;
}
public background(): Blob {
// biome-ignore lint/style/noNonNullAssertion: <explanation>
const filename = this.osuInner.events.backgroundPath!;

7
tsconfig.json Normal file
View file

@ -0,0 +1,7 @@
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "Bundler"
}
}

View file

@ -1,7 +1,14 @@
import { analyzer } from "vite-bundle-analyzer";
import { defineConfig } from "vite";
import { nodePolyfills } from "vite-plugin-node-polyfills";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [],
build: {
lib: {
entry: "src/index.ts",
name: "osuplayer",
},
},
plugins: [analyzer()],
});