diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 7400ce3..a216b3d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -21,13 +21,13 @@ jobs: - name: "Setup pnpm" uses: pnpm/action-setup@v4 - with: - run_install: false + # with: + # run_install: false - name: "Setup node" - uses: actions/setup-node@v2 + uses: actions/setup-node@v4 with: - node-version: "23.6.0" + node-version: 23.6.0 cache: "pnpm" - name: "Install dependencies" diff --git a/example/pong/package.json b/example/pong/package.json index f7a4d20..cfb787e 100644 --- a/example/pong/package.json +++ b/example/pong/package.json @@ -53,7 +53,8 @@ "@nanoforge/core": "latest", "@nanoforge/asset-manager": "latest", "@nanoforge/ecs": "latest", - "@nanoforge/graphics-2d": "latest" + "@nanoforge/graphics-2d": "latest", + "@nanoforge/sound": "latest" }, "engines": { "node": "23.6.0", diff --git a/example/pong/src/index.ts b/example/pong/src/index.ts index 1b97b6c..004aea7 100644 --- a/example/pong/src/index.ts +++ b/example/pong/src/index.ts @@ -5,6 +5,7 @@ import { ECSLibrary } from "@nanoforge/ecs"; import { Graphics2DLibrary } from "@nanoforge/graphics-2d"; import { InputLibrary } from "@nanoforge/input"; import { InputEnum } from "@nanoforge/input"; +import { SoundLibrary } from "@nanoforge/sound"; import { Bounce, @@ -22,15 +23,20 @@ export const ecsLibrary = new ECSLibrary(); export const app = NanoforgeFactory.createClient(); export const graphics = new Graphics2DLibrary(); export const inputs = new InputLibrary(); +export const sounds = new SoundLibrary(); +export const assetManager = new AssetManagerLibrary(); export const main = async (options: IRunOptions) => { app.useGraphics(graphics); app.useComponentSystem(ecsLibrary); - app.useAssetManager(new AssetManagerLibrary()); + app.useAssetManager(assetManager); app.useInput(inputs); + app.useSound(sounds); await app.init(options); + sounds.load("test", "https://universal-soundbank.com/sounds/18782.mp3"); + const ball = ecsLibrary.spawnEntity(); ecsLibrary.addComponent(ball, new Velocity(0.04, 0)); ecsLibrary.addComponent(ball, new Position(0.5, 0)); diff --git a/example/pong/src/systems.ts b/example/pong/src/systems.ts index 2a2f6a3..cc55d67 100644 --- a/example/pong/src/systems.ts +++ b/example/pong/src/systems.ts @@ -8,7 +8,7 @@ import { RectangleComponent, Velocity, } from "./components"; -import { ecsLibrary, graphics, inputs } from "./index"; +import { ecsLibrary, graphics, inputs, sounds } from "./index"; export function move() { const entities = ecsLibrary.getZipper([Bounce, Position, Velocity]); @@ -25,9 +25,13 @@ export function bounce() { entities.forEach((entity) => { if (entity.Position.x >= 1.6 || entity.Position.x <= -1.6) { entity.Velocity.x = -entity.Velocity.x; + + sounds.play("test"); } if (entity.Position.y >= 1 || entity.Position.y <= -1) { entity.Velocity.y = -entity.Velocity.y; + + sounds.play("test"); } }); } diff --git a/packages/common/src/exceptions/index.ts b/packages/common/src/exceptions/index.ts new file mode 100644 index 0000000..459344b --- /dev/null +++ b/packages/common/src/exceptions/index.ts @@ -0,0 +1 @@ +export { NfNotFound } from "./notFound"; diff --git a/packages/common/src/exceptions/nfException.ts b/packages/common/src/exceptions/nfException.ts new file mode 100644 index 0000000..33ea46d --- /dev/null +++ b/packages/common/src/exceptions/nfException.ts @@ -0,0 +1,3 @@ +export interface INfException extends Error { + get code(): number; +} diff --git a/packages/common/src/exceptions/notFound.ts b/packages/common/src/exceptions/notFound.ts new file mode 100644 index 0000000..e52828c --- /dev/null +++ b/packages/common/src/exceptions/notFound.ts @@ -0,0 +1,16 @@ +import { type INfException } from "./nfException"; + +export class NfNotFound implements INfException { + get code(): number { + return 404; + } + + message: string; + name: string; + stack?: string | undefined; + cause?: unknown; + + constructor(item: string) { + this.message = `${item} not found.`; + } +} diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts index 12d9d7a..2b868c1 100644 --- a/packages/common/src/index.ts +++ b/packages/common/src/index.ts @@ -1,3 +1,4 @@ export * from "./context"; export * from "./library"; export * from "./options"; +export * from "./exceptions"; diff --git a/packages/common/src/library/libraries/abstracts/index.ts b/packages/common/src/library/libraries/abstracts/index.ts index 7d2d8a1..720cb0b 100644 --- a/packages/common/src/library/libraries/abstracts/index.ts +++ b/packages/common/src/library/libraries/abstracts/index.ts @@ -2,4 +2,5 @@ export { BaseAssetManagerLibrary } from "./asset-manager.library.abstract"; export { BaseComponentSystemLibrary } from "./component-system.library.abstract"; export { BaseGraphicsLibrary } from "./graphics.library.abstract"; export { BaseInputLibrary } from "./input.library.abstract"; +export { BaseSoundLibrary } from "./sound.library.abstract"; export { BaseNetworkLibrary } from "./network.library.abstract"; diff --git a/packages/common/src/library/libraries/abstracts/sound.library.abstract.ts b/packages/common/src/library/libraries/abstracts/sound.library.abstract.ts new file mode 100644 index 0000000..7096c3c --- /dev/null +++ b/packages/common/src/library/libraries/abstracts/sound.library.abstract.ts @@ -0,0 +1,14 @@ +import { type InitContext } from "../../../context"; +import { type ISoundLibrary } from "../interfaces"; +import { Library } from "../library"; + +export abstract class BaseSoundLibrary extends Library implements ISoundLibrary { + public abstract init(context: InitContext): Promise; + + public abstract play(sound: string): void; + + /** + * mutes or unmutes the sound. + */ + public abstract mute(): void; +} diff --git a/packages/common/src/library/libraries/consts/library-label.const.ts b/packages/common/src/library/libraries/consts/library-label.const.ts index 0e487ff..c99a6c1 100644 --- a/packages/common/src/library/libraries/consts/library-label.const.ts +++ b/packages/common/src/library/libraries/consts/library-label.const.ts @@ -1,5 +1,6 @@ export const COMPONENT_SYSTEM_LIBRARY = Symbol("COMPONENT_SYSTEM_LIBRARY"); export const GRAPHICS_LIBRARY = Symbol("GRAPHICS_LIBRARY"); export const NETWORK_LIBRARY = Symbol("NETWORK_LIBRARY"); +export const SOUND_LIBRARY = Symbol("SOUND_LIBRARY"); export const ASSET_MANAGER_LIBRARY = Symbol("ASSET_MANAGER_LIBRARY"); export const INPUT_LIBRARY = Symbol("INPUT_LIBRARY"); diff --git a/packages/common/src/library/libraries/interfaces/finals/sound.library.type.ts b/packages/common/src/library/libraries/interfaces/finals/sound.library.type.ts new file mode 100644 index 0000000..37755fa --- /dev/null +++ b/packages/common/src/library/libraries/interfaces/finals/sound.library.type.ts @@ -0,0 +1,8 @@ +import { type IExposedLibrary } from "../bases/exposed.library.type"; + +export interface ISoundLibrary extends IExposedLibrary { + /** + * mutes or unmutes the sound. + */ + mute(): void; +} diff --git a/packages/common/src/library/libraries/interfaces/index.ts b/packages/common/src/library/libraries/interfaces/index.ts index 50807a1..166cbb0 100644 --- a/packages/common/src/library/libraries/interfaces/index.ts +++ b/packages/common/src/library/libraries/interfaces/index.ts @@ -4,4 +4,5 @@ export { IAssetManagerLibrary } from "./finals/asset-manager.library.type"; export { IComponentSystemLibrary } from "./finals/component-system.library.type"; export { IGraphicsLibrary } from "./finals/graphics.library.type"; export { IInputLibrary } from "./finals/input.library.type"; +export { ISoundLibrary } from "./finals/sound.library.type"; export { INetworkLibrary } from "./finals/network.library.type"; diff --git a/packages/common/src/library/manager/managers/library.manager.ts b/packages/common/src/library/manager/managers/library.manager.ts index 7939a48..542e45a 100644 --- a/packages/common/src/library/manager/managers/library.manager.ts +++ b/packages/common/src/library/manager/managers/library.manager.ts @@ -7,7 +7,9 @@ import { type IGraphicsLibrary, type IInputLibrary, type INetworkLibrary, + type ISoundLibrary, NETWORK_LIBRARY, + SOUND_LIBRARY, } from "../../libraries"; import { type LibraryHandle } from "../handle/library.handle"; import { BaseLibraryManager } from "./base-library.manager"; @@ -18,6 +20,7 @@ export enum DefaultLibrariesEnum { GRAPHICS, INPUT, NETWORK, + SOUND, } const DEFAULT_LIBRARIES: { index: DefaultLibrariesEnum; sym: symbol }[] = [ @@ -25,6 +28,7 @@ const DEFAULT_LIBRARIES: { index: DefaultLibrariesEnum; sym: symbol }[] = [ { index: DefaultLibrariesEnum.COMPONENT_SYSTEM, sym: COMPONENT_SYSTEM_LIBRARY }, { index: DefaultLibrariesEnum.GRAPHICS, sym: GRAPHICS_LIBRARY }, { index: DefaultLibrariesEnum.NETWORK, sym: NETWORK_LIBRARY }, + { index: DefaultLibrariesEnum.SOUND, sym: SOUND_LIBRARY }, ]; export class LibraryManager extends BaseLibraryManager { @@ -59,4 +63,8 @@ export class LibraryManager extends BaseLibraryManager { >(): LibraryHandle { return this._get(DefaultLibrariesEnum.ASSET_MANAGER); } + + public getSound(): LibraryHandle { + return this._get(DefaultLibrariesEnum.SOUND); + } } diff --git a/packages/core/src/application/application-config.ts b/packages/core/src/application/application-config.ts index e29dbbd..f4d9ecc 100644 --- a/packages/core/src/application/application-config.ts +++ b/packages/core/src/application/application-config.ts @@ -5,6 +5,7 @@ import { type IInputLibrary, type ILibrary, type INetworkLibrary, + type ISoundLibrary, type LibraryHandle, } from "@nanoforge/common"; @@ -68,4 +69,12 @@ export class ApplicationConfig { public useInputLibrary(library: IInputLibrary) { this._libraryManager.setInput(library); } + + public getSoundLibrary() { + return this._libraryManager.getSound(); + } + + public useSoundLibrary(library: ISoundLibrary) { + this._libraryManager.setSound(library); + } } diff --git a/packages/core/src/application/nanoforge-application.ts b/packages/core/src/application/nanoforge-application.ts index 0ab3b19..0ea6823 100644 --- a/packages/core/src/application/nanoforge-application.ts +++ b/packages/core/src/application/nanoforge-application.ts @@ -49,4 +49,8 @@ export abstract class NanoforgeApplication { public run() { this._core.run(); } + + public mute() { + this._core.mute(); + } } diff --git a/packages/core/src/application/nanoforge-client.ts b/packages/core/src/application/nanoforge-client.ts index 66d0534..ffa7782 100644 --- a/packages/core/src/application/nanoforge-client.ts +++ b/packages/core/src/application/nanoforge-client.ts @@ -1,4 +1,4 @@ -import { type IGraphicsLibrary, type IInputLibrary } from "@nanoforge/common"; +import { type IGraphicsLibrary, type IInputLibrary, type ISoundLibrary } from "@nanoforge/common"; import { NanoforgeApplication } from "./nanoforge-application"; @@ -10,4 +10,8 @@ export class NanoforgeClient extends NanoforgeApplication { public useInput(library: IInputLibrary) { this.applicationConfig.useInputLibrary(library); } + + public useSound(library: ISoundLibrary) { + this.applicationConfig.useSoundLibrary(library); + } } diff --git a/packages/core/src/common/library/manager/library.manager.ts b/packages/core/src/common/library/manager/library.manager.ts index b07e281..56629e5 100644 --- a/packages/core/src/common/library/manager/library.manager.ts +++ b/packages/core/src/common/library/manager/library.manager.ts @@ -11,9 +11,11 @@ import { INPUT_LIBRARY, type INetworkLibrary, type IRunnerLibrary, + type ISoundLibrary, type LibraryHandle, LibraryManager, NETWORK_LIBRARY, + SOUND_LIBRARY, } from "@nanoforge/common"; import { EditableLibraryContext } from "../../context/contexts/library.editable-context"; @@ -59,6 +61,10 @@ export class EditableLibraryManager extends LibraryManager { this._set(DefaultLibrariesEnum.INPUT, INPUT_LIBRARY, library, new EditableLibraryContext()); } + public setSound(library: ISoundLibrary): void { + this._set(DefaultLibrariesEnum.SOUND, SOUND_LIBRARY, library, new EditableLibraryContext()); + } + public getLibraries(): LibraryHandle[] { return this._libraries; } diff --git a/packages/core/src/core/core.ts b/packages/core/src/core/core.ts index a0013a3..73f7d35 100644 --- a/packages/core/src/core/core.ts +++ b/packages/core/src/core/core.ts @@ -50,6 +50,15 @@ export class Core { const intervalHandle = setInterval(render, 1000 / this.options.tickRate); } + /** + * mutes / unmutes sounds. + */ + public mute(): void { + const soundLibrary = this.config.getSoundLibrary(); + + soundLibrary.library.mute(); + } + private getInitContext(options: IRunOptions): InitContext { return new InitContext(this.context, this.config.libraryManager, options); } diff --git a/packages/sound/.gitignore b/packages/sound/.gitignore new file mode 100644 index 0000000..9f6061c --- /dev/null +++ b/packages/sound/.gitignore @@ -0,0 +1,272 @@ +### VisualStudioCode template +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +### C++ template +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Node template +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp +.cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +### Private + +# NX +.nx/ + +# Compiled files +src/**/*.js +src/**/*.d.ts + +# pubilc directory +public/ +compile_commands.json +emsdk/ diff --git a/packages/sound/.nvmrc b/packages/sound/.nvmrc new file mode 100644 index 0000000..c9758a5 --- /dev/null +++ b/packages/sound/.nvmrc @@ -0,0 +1 @@ +v23.6.0 diff --git a/packages/sound/.prettierignore b/packages/sound/.prettierignore new file mode 100644 index 0000000..e814a63 --- /dev/null +++ b/packages/sound/.prettierignore @@ -0,0 +1,8 @@ +# Ignore files for PNPM, NPM and YARN +pnpm-lock.yaml +package-lock.json +yarn.lock +bun.lock + +*.js +*.d.ts diff --git a/packages/sound/.prettierrc b/packages/sound/.prettierrc new file mode 100644 index 0000000..d5f635c --- /dev/null +++ b/packages/sound/.prettierrc @@ -0,0 +1,11 @@ +{ + "plugins": ["@trivago/prettier-plugin-sort-imports"], + "importOrderSeparation": true, + "importOrderSortSpecifiers": true, + "importOrderParserPlugins": ["typescript", "decorators-legacy"], + "importOrder": ["^~/(.*)$", "^[./]"], + "useTabs": false, + "singleQuote": false, + "trailingComma": "all", + "printWidth": 100 +} diff --git a/packages/sound/README.md b/packages/sound/README.md new file mode 100644 index 0000000..33e4d47 --- /dev/null +++ b/packages/sound/README.md @@ -0,0 +1 @@ +# Engine Input diff --git a/packages/sound/eslint.config.js b/packages/sound/eslint.config.js new file mode 100644 index 0000000..4a7529e --- /dev/null +++ b/packages/sound/eslint.config.js @@ -0,0 +1,63 @@ +import pluginJs from "@eslint/js"; +import eslintConfigPrettier from "eslint-config-prettier"; +import globals from "globals"; +import tseslint from "typescript-eslint"; +import pluginJest from "eslint-plugin-jest"; + +export default [ + { + files: ["src/**/*.{ts}"], + }, + { languageOptions: { globals: globals.node } }, + + + pluginJs.configs.recommended, + ...tseslint.configs.recommended, + ...tseslint.configs.strict, + eslintConfigPrettier, + { ignores: ["**/*.js"] }, + { + rules: { + "@typescript-eslint/consistent-type-imports": [ + "error", + { + disallowTypeAnnotations: true, + fixStyle: "inline-type-imports", + prefer: "type-imports", + }, + ], + "@typescript-eslint/no-extraneous-class": "off", + "@typescript-eslint/no-empty-object-type": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/ban-ts-comment": "off", + "@typescript-eslint/member-ordering": [ + "error", + { + default: [ + "static-field", + "field", + "public-static-method", + "constructor", + "method", + "protected-method", + "private-method", + ], + }, + ], + }, + }, + { + files: ["**/*.spec.ts"], + plugins: { jest: pluginJest }, + languageOptions: { + globals: pluginJest.environments.globals.globals, + }, + rules: { + "jest/no-disabled-tests": "warn", + "jest/no-focused-tests": "error", + "jest/no-identical-title": "error", + "jest/prefer-to-have-length": "warn", + "jest/valid-expect": "error", + } + } +]; diff --git a/packages/sound/package.json b/packages/sound/package.json new file mode 100644 index 0000000..18ddb17 --- /dev/null +++ b/packages/sound/package.json @@ -0,0 +1,66 @@ +{ + "name": "@nanoforge/sound", + "version": "1.0.0", + "description": "NanoForge Engine - sound", + "homepage": "https://github.com/NanoForge-dev/Engine#readme", + "license": "MIT", + "contributors": [ + "Bill", + "Exelo", + "Fexkoser", + "Tchips" + ], + "funding": { + "type": "individual", + "url": "" + }, + "type": "module", + "main": "src/index.ts", + "repository": { + "type": "git", + "url": "git+https://github.com/NanoForge-dev/Engine.git", + "directory": "packages/sound" + }, + "scripts": { + "build": "tsc -b .", + "clean": "pnpm clean:types && pnpm clean:scripts && rm -f tsconfig.build.tsbuildinfo", + "clean:types": "find src -name '*.d.ts' -delete", + "clean:scripts": "find src -name '*.js' -delete", + "lint": "eslint . && prettier --check .", + "fix": "eslint . --fix && prettier --write .", + "taze": "taze major -w", + "lint-staged": "lint-staged" + }, + "dependencies": { + "@nanoforge/common": "workspace:^" + }, + "devDependencies": { + "@commitlint/cli": "^19.8.0", + "@commitlint/config-conventional": "^19.8.0", + "@eslint/js": "^9.23.0", + "@trivago/prettier-plugin-sort-imports": "^5.2.2", + "@types/node": "^22.13.13", + "eslint": "^9.23.0", + "eslint-config-prettier": "^10.1.1", + "eslint-plugin-format": "^1.0.1", + "eslint-plugin-jest": "^28.11.0", + "eslint-plugin-prettier": "^5.2.5", + "globals": "^16.0.0", + "lint-staged": "^15.5.0", + "prettier": "^3.5.3", + "taze": "^19.0.2", + "typescript": "^5.8.2", + "typescript-eslint": "^8.28.0" + }, + "engines": { + "node": "23.6.0", + "pnpm": "10.6.5" + }, + "packageManager": "pnpm@10.6.5", + "lint-staged": { + "**/*.{js,ts}": [ + "eslint --fix", + "prettier --write" + ] + } +} diff --git a/packages/sound/src/index.ts b/packages/sound/src/index.ts new file mode 100644 index 0000000..ebf9eec --- /dev/null +++ b/packages/sound/src/index.ts @@ -0,0 +1 @@ +export { SoundLibrary } from "./sound.library"; diff --git a/packages/sound/src/sound.library.ts b/packages/sound/src/sound.library.ts new file mode 100644 index 0000000..1a6b1a3 --- /dev/null +++ b/packages/sound/src/sound.library.ts @@ -0,0 +1,50 @@ +import { BaseSoundLibrary } from "@nanoforge/common"; +import { NfNotFound } from "@nanoforge/common/src/exceptions"; + +export class SoundLibrary extends BaseSoundLibrary { + private muted: boolean; + private sounds: Map; + + get name(): string { + return "NfSound"; + } + + public async init(): Promise { + this.sounds = new Map(); + this.muted = true; + } + + public mute(): void { + this.muted = !this.muted; + for (const key in this.sounds) { + const element = this.sounds[key]; + + if (element) { + element.muted = this.muted; + } + } + } + + public play(sound: string): void { + const soundElement = this.sounds.get(sound); + + if (soundElement) { + soundElement + .play() + .then(() => {}) + .catch((e) => { + console.error(`Got error: ${e}`); + }); + } else { + throw new NfNotFound(sound); + } + } + + public load(sound: string, file: string) { + const element = new Audio(file); + if (element) { + element.muted = this.muted; + } + this.sounds.set(sound, element); + } +} diff --git a/packages/sound/tsconfig.build.json b/packages/sound/tsconfig.build.json new file mode 100644 index 0000000..a7e09c7 --- /dev/null +++ b/packages/sound/tsconfig.build.json @@ -0,0 +1,16 @@ +{ + "extends": "../tsconfig.build.json", + "compilerOptions": { + "outDir": ".", + "rootDir": ".", + "paths": { + "@nanoforge/common": ["../common"] + } + }, + "exclude": ["node_modules", "dist", "test/**/*", "*.spec.ts"], + "references": [ + { + "path": "../common/tsconfig.build.json" + } + ] +} diff --git a/packages/sound/tsconfig.json b/packages/sound/tsconfig.json new file mode 100644 index 0000000..a74c8e2 --- /dev/null +++ b/packages/sound/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../tsconfig.build.json", + "compilerOptions": { + "types": ["jest", "node"] + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.build.json" + } + ] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fb382d4..959e243 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -411,6 +411,61 @@ importers: specifier: ^8.28.0 version: 8.28.0(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2) + packages/sound: + dependencies: + '@nanoforge/common': + specifier: workspace:^ + version: link:../common + devDependencies: + '@commitlint/cli': + specifier: ^19.8.0 + version: 19.8.0(@types/node@22.13.13)(typescript@5.8.2) + '@commitlint/config-conventional': + specifier: ^19.8.0 + version: 19.8.0 + '@eslint/js': + specifier: ^9.23.0 + version: 9.23.0 + '@trivago/prettier-plugin-sort-imports': + specifier: ^5.2.2 + version: 5.2.2(prettier@3.5.3) + '@types/node': + specifier: ^22.13.13 + version: 22.13.13 + eslint: + specifier: ^9.23.0 + version: 9.23.0(jiti@2.4.2) + eslint-config-prettier: + specifier: ^10.1.1 + version: 10.1.1(eslint@9.23.0(jiti@2.4.2)) + eslint-plugin-format: + specifier: ^1.0.1 + version: 1.0.1(eslint@9.23.0(jiti@2.4.2)) + eslint-plugin-jest: + specifier: ^28.11.0 + version: 28.11.0(@typescript-eslint/eslint-plugin@8.28.0(@typescript-eslint/parser@8.28.0(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.23.0(jiti@2.4.2))(jest@29.7.0(@types/node@22.13.13))(typescript@5.8.2) + eslint-plugin-prettier: + specifier: ^5.2.5 + version: 5.2.5(eslint-config-prettier@10.1.1(eslint@9.23.0(jiti@2.4.2)))(eslint@9.23.0(jiti@2.4.2))(prettier@3.5.3) + globals: + specifier: ^16.0.0 + version: 16.0.0 + lint-staged: + specifier: ^15.5.0 + version: 15.5.0 + prettier: + specifier: ^3.5.3 + version: 3.5.3 + taze: + specifier: ^19.0.2 + version: 19.0.2 + typescript: + specifier: ^5.8.2 + version: 5.8.2 + typescript-eslint: + specifier: ^8.28.0 + version: 8.28.0(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2) + packages: '@ampproject/remapping@2.3.0': @@ -7518,7 +7573,7 @@ snapshots: ora@5.3.0: dependencies: bl: 4.1.0 - chalk: 4.1.0 + chalk: 4.1.2 cli-cursor: 3.1.0 cli-spinners: 2.6.1 is-interactive: 1.0.0