From c6f462ca454588289382ebe3c4953c52d524f871 Mon Sep 17 00:00:00 2001 From: sophie Date: Tue, 16 Jul 2024 23:54:30 +0300 Subject: [PATCH] first commit --- .gitignore | 175 ++++++++ README.md | 27 ++ bun.lockb | Bin 0 -> 7573 bytes index.ts | 186 +++++++++ package.json | 24 ++ pianoverse.proto | 149 +++++++ pianoverse_pb.ts | 1023 ++++++++++++++++++++++++++++++++++++++++++++++ tsconfig.json | 27 ++ 8 files changed, 1611 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100755 bun.lockb create mode 100644 index.ts create mode 100644 package.json create mode 100644 pianoverse.proto create mode 100644 pianoverse_pb.ts create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9b1ee42 --- /dev/null +++ b/.gitignore @@ -0,0 +1,175 @@ +# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore + +# Logs + +logs +_.log +npm-debug.log_ +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Caches + +.cache + +# 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/) + +.parcel-cache + +# Next.js build output + +.next +out + +# Nuxt.js build / generate output + +.nuxt +dist + +# Gatsby files + +# 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 + +# 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.* + +# IntelliJ based IDEs +.idea + +# Finder (MacOS) folder config +.DS_Store diff --git a/README.md b/README.md new file mode 100644 index 0000000..5aefb53 --- /dev/null +++ b/README.md @@ -0,0 +1,27 @@ +# pianoverse client for TS + +## install +run `bun add https://git.sad.ovh/sophie/pianoverse` +then import `pianoverse` + +## requirements +1. bun +2. a brain + +## example +```ts +import { Client } from "pianoverse" + +const client = new Client("https://pianoverse.net"); + +client.on("open", () => { + client.setRoom("Lobby") + client.setProfile("My Bot!") +}) + +client.on("message", (user, content) => { + if(content == "!help") { + client.message("Hi :P") + } +}) +``` \ No newline at end of file diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..4e5bc45f4486b2a18c158f322df59dd5311e0ae0 GIT binary patch literal 7573 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 literal 0 HcmV?d00001 diff --git a/index.ts b/index.ts new file mode 100644 index 0000000..c5624bb --- /dev/null +++ b/index.ts @@ -0,0 +1,186 @@ +import * as proto from "./pianoverse_pb"; +import EventEmitter from "node:events"; +import type TypedEmitter from "typed-emitter"; +import UserAgent from "user-agents"; + +const CEventType = proto.ClientMessage_EventType; +const SEventType = proto.ServerMessage_EventType; + +type MessageEvents = { + open: () => void; + close: () => void; + message: ( + user: { id: string; name: string; color: string }, + content: string + ) => void; + welcome: () => void; + rooms: (rooms: proto.ServerMessage_Room[]) => void; + join: (join: proto.ServerMessage_Join) => void; + leave: (id: string) => void; +}; + +interface Player { + id: string; + name: string; + color: string; + role?: number; + x?: number; + y?: number; +} + +export class Client extends (EventEmitter as new () => TypedEmitter) { + private ws: WebSocket; + me!: Player; + chatHistory: proto.ServerMessage_Chat[] = []; + room: { + name?: string; + owner?: string; + } = {}; + rooms: proto.ServerMessage_Room[] = []; + + players = new Map(); + move(x: number, y: number) { + this.ws.send( + new proto.ClientMessage({ + event: CEventType.MOVE, + move: { + x, + y, + }, + }).toBinary() + ); + } + message(chat: string) { + chat.match(/.{1,200}/gm)?.forEach((z, i) => { + setTimeout(() => { + this.ws.send( + new proto.ClientMessage({ + event: CEventType.CHAT, + chat: z, + }).toBinary() + ); + }, 500 * i); + }); + } + keyDown(key: number, velocity: number) { + this.ws.send( + new proto.ClientMessage({ + event: CEventType.PRESS, + press: { + key, + vel: velocity, + }, + }).toBinary() + ); + } + keyUp(key: number) { + this.ws.send( + new proto.ClientMessage({ + event: CEventType.RELEASE, + release: { + key, + }, + }).toBinary() + ); + } + setProfile(name: string, color: string) { + this.ws.send( + new proto.ClientMessage({ + event: CEventType.PROFILE, + profile: { + name, + color, + }, + }).toBinary() + ); + } + + setRoom(room: string, priv?: boolean) { + this.ws.send( + new proto.ClientMessage({ + event: CEventType.ROOM, + room: { + room: room, + private: priv, + }, + }).toBinary() + ); + } + constructor(url: string) { + super(); + this.ws = new WebSocket(url.replace("http", "ws"), { + //@ts-expect-error + headers: { + Origin: url, + "User-Agent": new UserAgent().toString(), + }, + protocol: "pianoverse", + }); + + this.ws.addEventListener("open", () => { + this.ws.binaryType = "arraybuffer"; + setInterval(() => { + this.ws.send( + new proto.ClientMessage({ + event: CEventType.HEARTBEAT, + }).toBinary() + ); + }, 2000); + this.emit("open"); + }); + + this.ws.addEventListener("message", (e) => { + let data = new Uint8Array(e.data); + let decode; + try { + decode = proto.ServerMessage.fromBinary(data); + } catch { + console.log("Could not decode data."); + console.log(data); + return; + } + if (decode.event == SEventType.RATELIMIT) { + console.log("Ratelimit reached! Type: " + decode.rateLimit); + } + if (decode.event == SEventType.JOIN) { + this.players.set(decode.join!.id, decode.join!); + this.emit("join", decode.join!); + } + + if (decode.event == SEventType.LEAVE) { + this.emit("leave", decode.leave); + this.players.delete(decode.leave!); + } + + if (decode.event == SEventType.ROOMS) { + this.rooms = decode.rooms; + this.emit("rooms", decode.rooms); + } + if (decode.event == SEventType.WELCOME) { + this.me = { + id: decode.welcome!.id, + name: decode.welcome!.name, + color: decode.welcome!.color, + }; + this.room = { + name: decode.welcome!.room, + owner: decode.welcome!.owner, + }; + this.chatHistory = decode.welcome!.chat; + + this.emit("welcome"); + } + if (decode.event == SEventType.CHAT) { + this.emit( + "message", + { + id: decode.chat!.id, + name: decode.chat!.name, + color: decode.chat!.color, + }, + decode.chat!.content + ); + } + }); + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..dda8a5a --- /dev/null +++ b/package.json @@ -0,0 +1,24 @@ +{ + "name": "pianoverse", + "module": "index.ts", + "type": "module", + "license": "GPL-3.0-only", + "homepage": "https://git.sad.ovh/sophie/pianoverse", + "bugs": "https://git.sad.ovh/sophie/pianoverse/issues", + "author": "Sophie", + "scripts": { + "build-proto": "protoc -I . --plugin ./node_modules/.bin/protoc-gen-es --es_out . --es_opt target=ts pianoverse.proto" + }, + "devDependencies": { + "@types/bun": "latest" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "dependencies": { + "@bufbuild/protoc-gen-es": "^1.10.0", + "@types/user-agents": "^1.0.4", + "typed-emitter": "^2.1.0", + "user-agents": "^1.1.267" + } +} \ No newline at end of file diff --git a/pianoverse.proto b/pianoverse.proto new file mode 100644 index 0000000..feea096 --- /dev/null +++ b/pianoverse.proto @@ -0,0 +1,149 @@ +syntax = "proto3"; + +package pianoverse; + +message ClientMessage { + enum EventType { + PING = 0; + ROOM = 1; + PROFILE = 2; + CHAT = 3; + MOVE = 4; + MUTE = 5; + UNMUTE = 6; + KICK = 7; + PRESS = 8; + RELEASE = 9; + SUSTAIN = 10; + HEARTBEAT = 11; + BAN = 12; + } + + EventType event = 1; + + Room room = 3; + message Room { + string room = 1; + bool private = 2; + } + + Profile profile = 4; + string chat = 5; + + Move move = 6; + + string mute = 7; + string unmute = 8; + string kick = 9; + + Press press = 10; + Release release = 11; + + bool sustain = 12; + + Heartbeat heartbeat = 13; + message Heartbeat {} + + Ban ban = 14; + message Ban { + string id = 1; + uint32 hours = 2; + } + +} + +message ServerMessage { + enum EventType { + PONG = 0; + CHAT = 1; + ROOMS = 2; + WELCOME = 3; + MOVE = 4; + PRESS = 5; + RELEASE = 6; + SUSTAIN = 7; + PROFILE = 8; + JOIN = 9; + LEAVE = 10; + RATELIMIT = 11; + } + + EventType event = 1; + + Pong pong = 2; + message Pong {} + + Chat chat = 3; + message Chat { + string id = 1; + string content = 2; + string name = 3; + string color = 4; + } + + repeated Room rooms = 4; + message Room { + string room = 1; + uint32 count = 2; + } + + Welcome welcome = 5; + message Welcome { + string id = 1; + string name = 2; + string color = 3; + string room = 4; + string owner = 5; + repeated Chat chat = 6; + } + + Move move = 6; + Press press = 7; + Release release = 8; + + Sustain sustain = 9; + message Sustain { + string id = 1; + bool enabled = 2; + } + + Profile profile = 10; + Join join = 11; + message Join { + string id = 1; + string name = 2; + string color = 3; + int32 role = 4; + float x = 6; + float y = 7; + } + string leave = 12; + + int32 rateLimit = 13; +} + +message Profile { + string id = 1; + string name = 2; + string color = 3; + string sound = 4; + bool muted = 5; + float x = 6; + float y = 7; +} + +message Move { + string id = 1; + float x = 2; + float y = 3; +} + +message Press { + uint32 key = 2; + uint32 vel = 3; +} + +message Release { + string id = 1; + uint32 key = 2; +} diff --git a/pianoverse_pb.ts b/pianoverse_pb.ts new file mode 100644 index 0000000..315d66b --- /dev/null +++ b/pianoverse_pb.ts @@ -0,0 +1,1023 @@ +// @generated by protoc-gen-es v1.10.0 with parameter "target=ts" +// @generated from file pianoverse.proto (package pianoverse, syntax proto3) +/* eslint-disable */ +// @ts-nocheck + +import type { BinaryReadOptions, FieldList, JsonReadOptions, JsonValue, PartialMessage, PlainMessage } from "@bufbuild/protobuf"; +import { Message, proto3 } from "@bufbuild/protobuf"; + +/** + * @generated from message pianoverse.ClientMessage + */ +export class ClientMessage extends Message { + /** + * @generated from field: pianoverse.ClientMessage.EventType event = 1; + */ + event = ClientMessage_EventType.PING; + + /** + * @generated from field: pianoverse.ClientMessage.Room room = 3; + */ + room?: ClientMessage_Room; + + /** + * @generated from field: pianoverse.Profile profile = 4; + */ + profile?: Profile; + + /** + * @generated from field: string chat = 5; + */ + chat = ""; + + /** + * @generated from field: pianoverse.Move move = 6; + */ + move?: Move; + + /** + * @generated from field: string mute = 7; + */ + mute = ""; + + /** + * @generated from field: string unmute = 8; + */ + unmute = ""; + + /** + * @generated from field: string kick = 9; + */ + kick = ""; + + /** + * @generated from field: pianoverse.Press press = 10; + */ + press?: Press; + + /** + * @generated from field: pianoverse.Release release = 11; + */ + release?: Release; + + /** + * @generated from field: bool sustain = 12; + */ + sustain = false; + + /** + * @generated from field: pianoverse.ClientMessage.Heartbeat heartbeat = 13; + */ + heartbeat?: ClientMessage_Heartbeat; + + /** + * @generated from field: pianoverse.ClientMessage.Ban ban = 14; + */ + ban?: ClientMessage_Ban; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "pianoverse.ClientMessage"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "event", kind: "enum", T: proto3.getEnumType(ClientMessage_EventType) }, + { no: 3, name: "room", kind: "message", T: ClientMessage_Room }, + { no: 4, name: "profile", kind: "message", T: Profile }, + { no: 5, name: "chat", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 6, name: "move", kind: "message", T: Move }, + { no: 7, name: "mute", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 8, name: "unmute", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 9, name: "kick", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 10, name: "press", kind: "message", T: Press }, + { no: 11, name: "release", kind: "message", T: Release }, + { no: 12, name: "sustain", kind: "scalar", T: 8 /* ScalarType.BOOL */ }, + { no: 13, name: "heartbeat", kind: "message", T: ClientMessage_Heartbeat }, + { no: 14, name: "ban", kind: "message", T: ClientMessage_Ban }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): ClientMessage { + return new ClientMessage().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): ClientMessage { + return new ClientMessage().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): ClientMessage { + return new ClientMessage().fromJsonString(jsonString, options); + } + + static equals(a: ClientMessage | PlainMessage | undefined, b: ClientMessage | PlainMessage | undefined): boolean { + return proto3.util.equals(ClientMessage, a, b); + } +} + +/** + * @generated from enum pianoverse.ClientMessage.EventType + */ +export enum ClientMessage_EventType { + /** + * @generated from enum value: PING = 0; + */ + PING = 0, + + /** + * @generated from enum value: ROOM = 1; + */ + ROOM = 1, + + /** + * @generated from enum value: PROFILE = 2; + */ + PROFILE = 2, + + /** + * @generated from enum value: CHAT = 3; + */ + CHAT = 3, + + /** + * @generated from enum value: MOVE = 4; + */ + MOVE = 4, + + /** + * @generated from enum value: MUTE = 5; + */ + MUTE = 5, + + /** + * @generated from enum value: UNMUTE = 6; + */ + UNMUTE = 6, + + /** + * @generated from enum value: KICK = 7; + */ + KICK = 7, + + /** + * @generated from enum value: PRESS = 8; + */ + PRESS = 8, + + /** + * @generated from enum value: RELEASE = 9; + */ + RELEASE = 9, + + /** + * @generated from enum value: SUSTAIN = 10; + */ + SUSTAIN = 10, + + /** + * @generated from enum value: HEARTBEAT = 11; + */ + HEARTBEAT = 11, + + /** + * @generated from enum value: BAN = 12; + */ + BAN = 12, +} +// Retrieve enum metadata with: proto3.getEnumType(ClientMessage_EventType) +proto3.util.setEnumType(ClientMessage_EventType, "pianoverse.ClientMessage.EventType", [ + { no: 0, name: "PING" }, + { no: 1, name: "ROOM" }, + { no: 2, name: "PROFILE" }, + { no: 3, name: "CHAT" }, + { no: 4, name: "MOVE" }, + { no: 5, name: "MUTE" }, + { no: 6, name: "UNMUTE" }, + { no: 7, name: "KICK" }, + { no: 8, name: "PRESS" }, + { no: 9, name: "RELEASE" }, + { no: 10, name: "SUSTAIN" }, + { no: 11, name: "HEARTBEAT" }, + { no: 12, name: "BAN" }, +]); + +/** + * @generated from message pianoverse.ClientMessage.Room + */ +export class ClientMessage_Room extends Message { + /** + * @generated from field: string room = 1; + */ + room = ""; + + /** + * @generated from field: bool private = 2; + */ + private = false; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "pianoverse.ClientMessage.Room"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "room", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "private", kind: "scalar", T: 8 /* ScalarType.BOOL */ }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): ClientMessage_Room { + return new ClientMessage_Room().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): ClientMessage_Room { + return new ClientMessage_Room().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): ClientMessage_Room { + return new ClientMessage_Room().fromJsonString(jsonString, options); + } + + static equals(a: ClientMessage_Room | PlainMessage | undefined, b: ClientMessage_Room | PlainMessage | undefined): boolean { + return proto3.util.equals(ClientMessage_Room, a, b); + } +} + +/** + * @generated from message pianoverse.ClientMessage.Heartbeat + */ +export class ClientMessage_Heartbeat extends Message { + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "pianoverse.ClientMessage.Heartbeat"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): ClientMessage_Heartbeat { + return new ClientMessage_Heartbeat().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): ClientMessage_Heartbeat { + return new ClientMessage_Heartbeat().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): ClientMessage_Heartbeat { + return new ClientMessage_Heartbeat().fromJsonString(jsonString, options); + } + + static equals(a: ClientMessage_Heartbeat | PlainMessage | undefined, b: ClientMessage_Heartbeat | PlainMessage | undefined): boolean { + return proto3.util.equals(ClientMessage_Heartbeat, a, b); + } +} + +/** + * @generated from message pianoverse.ClientMessage.Ban + */ +export class ClientMessage_Ban extends Message { + /** + * @generated from field: string id = 1; + */ + id = ""; + + /** + * @generated from field: uint32 hours = 2; + */ + hours = 0; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "pianoverse.ClientMessage.Ban"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "hours", kind: "scalar", T: 13 /* ScalarType.UINT32 */ }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): ClientMessage_Ban { + return new ClientMessage_Ban().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): ClientMessage_Ban { + return new ClientMessage_Ban().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): ClientMessage_Ban { + return new ClientMessage_Ban().fromJsonString(jsonString, options); + } + + static equals(a: ClientMessage_Ban | PlainMessage | undefined, b: ClientMessage_Ban | PlainMessage | undefined): boolean { + return proto3.util.equals(ClientMessage_Ban, a, b); + } +} + +/** + * @generated from message pianoverse.ServerMessage + */ +export class ServerMessage extends Message { + /** + * @generated from field: pianoverse.ServerMessage.EventType event = 1; + */ + event = ServerMessage_EventType.PONG; + + /** + * @generated from field: pianoverse.ServerMessage.Pong pong = 2; + */ + pong?: ServerMessage_Pong; + + /** + * @generated from field: pianoverse.ServerMessage.Chat chat = 3; + */ + chat?: ServerMessage_Chat; + + /** + * @generated from field: repeated pianoverse.ServerMessage.Room rooms = 4; + */ + rooms: ServerMessage_Room[] = []; + + /** + * @generated from field: pianoverse.ServerMessage.Welcome welcome = 5; + */ + welcome?: ServerMessage_Welcome; + + /** + * @generated from field: pianoverse.Move move = 6; + */ + move?: Move; + + /** + * @generated from field: pianoverse.Press press = 7; + */ + press?: Press; + + /** + * @generated from field: pianoverse.Release release = 8; + */ + release?: Release; + + /** + * @generated from field: pianoverse.ServerMessage.Sustain sustain = 9; + */ + sustain?: ServerMessage_Sustain; + + /** + * @generated from field: pianoverse.Profile profile = 10; + */ + profile?: Profile; + + /** + * @generated from field: pianoverse.ServerMessage.Join join = 11; + */ + join?: ServerMessage_Join; + + /** + * @generated from field: string leave = 12; + */ + leave = ""; + + /** + * @generated from field: int32 rateLimit = 13; + */ + rateLimit = 0; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "pianoverse.ServerMessage"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "event", kind: "enum", T: proto3.getEnumType(ServerMessage_EventType) }, + { no: 2, name: "pong", kind: "message", T: ServerMessage_Pong }, + { no: 3, name: "chat", kind: "message", T: ServerMessage_Chat }, + { no: 4, name: "rooms", kind: "message", T: ServerMessage_Room, repeated: true }, + { no: 5, name: "welcome", kind: "message", T: ServerMessage_Welcome }, + { no: 6, name: "move", kind: "message", T: Move }, + { no: 7, name: "press", kind: "message", T: Press }, + { no: 8, name: "release", kind: "message", T: Release }, + { no: 9, name: "sustain", kind: "message", T: ServerMessage_Sustain }, + { no: 10, name: "profile", kind: "message", T: Profile }, + { no: 11, name: "join", kind: "message", T: ServerMessage_Join }, + { no: 12, name: "leave", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 13, name: "rateLimit", kind: "scalar", T: 5 /* ScalarType.INT32 */ }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): ServerMessage { + return new ServerMessage().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): ServerMessage { + return new ServerMessage().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): ServerMessage { + return new ServerMessage().fromJsonString(jsonString, options); + } + + static equals(a: ServerMessage | PlainMessage | undefined, b: ServerMessage | PlainMessage | undefined): boolean { + return proto3.util.equals(ServerMessage, a, b); + } +} + +/** + * @generated from enum pianoverse.ServerMessage.EventType + */ +export enum ServerMessage_EventType { + /** + * @generated from enum value: PONG = 0; + */ + PONG = 0, + + /** + * @generated from enum value: CHAT = 1; + */ + CHAT = 1, + + /** + * @generated from enum value: ROOMS = 2; + */ + ROOMS = 2, + + /** + * @generated from enum value: WELCOME = 3; + */ + WELCOME = 3, + + /** + * @generated from enum value: MOVE = 4; + */ + MOVE = 4, + + /** + * @generated from enum value: PRESS = 5; + */ + PRESS = 5, + + /** + * @generated from enum value: RELEASE = 6; + */ + RELEASE = 6, + + /** + * @generated from enum value: SUSTAIN = 7; + */ + SUSTAIN = 7, + + /** + * @generated from enum value: PROFILE = 8; + */ + PROFILE = 8, + + /** + * @generated from enum value: JOIN = 9; + */ + JOIN = 9, + + /** + * @generated from enum value: LEAVE = 10; + */ + LEAVE = 10, + + /** + * @generated from enum value: RATELIMIT = 11; + */ + RATELIMIT = 11, +} +// Retrieve enum metadata with: proto3.getEnumType(ServerMessage_EventType) +proto3.util.setEnumType(ServerMessage_EventType, "pianoverse.ServerMessage.EventType", [ + { no: 0, name: "PONG" }, + { no: 1, name: "CHAT" }, + { no: 2, name: "ROOMS" }, + { no: 3, name: "WELCOME" }, + { no: 4, name: "MOVE" }, + { no: 5, name: "PRESS" }, + { no: 6, name: "RELEASE" }, + { no: 7, name: "SUSTAIN" }, + { no: 8, name: "PROFILE" }, + { no: 9, name: "JOIN" }, + { no: 10, name: "LEAVE" }, + { no: 11, name: "RATELIMIT" }, +]); + +/** + * @generated from message pianoverse.ServerMessage.Pong + */ +export class ServerMessage_Pong extends Message { + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "pianoverse.ServerMessage.Pong"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): ServerMessage_Pong { + return new ServerMessage_Pong().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): ServerMessage_Pong { + return new ServerMessage_Pong().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): ServerMessage_Pong { + return new ServerMessage_Pong().fromJsonString(jsonString, options); + } + + static equals(a: ServerMessage_Pong | PlainMessage | undefined, b: ServerMessage_Pong | PlainMessage | undefined): boolean { + return proto3.util.equals(ServerMessage_Pong, a, b); + } +} + +/** + * @generated from message pianoverse.ServerMessage.Chat + */ +export class ServerMessage_Chat extends Message { + /** + * @generated from field: string id = 1; + */ + id = ""; + + /** + * @generated from field: string content = 2; + */ + content = ""; + + /** + * @generated from field: string name = 3; + */ + name = ""; + + /** + * @generated from field: string color = 4; + */ + color = ""; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "pianoverse.ServerMessage.Chat"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "content", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 3, name: "name", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 4, name: "color", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): ServerMessage_Chat { + return new ServerMessage_Chat().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): ServerMessage_Chat { + return new ServerMessage_Chat().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): ServerMessage_Chat { + return new ServerMessage_Chat().fromJsonString(jsonString, options); + } + + static equals(a: ServerMessage_Chat | PlainMessage | undefined, b: ServerMessage_Chat | PlainMessage | undefined): boolean { + return proto3.util.equals(ServerMessage_Chat, a, b); + } +} + +/** + * @generated from message pianoverse.ServerMessage.Room + */ +export class ServerMessage_Room extends Message { + /** + * @generated from field: string room = 1; + */ + room = ""; + + /** + * @generated from field: uint32 count = 2; + */ + count = 0; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "pianoverse.ServerMessage.Room"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "room", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "count", kind: "scalar", T: 13 /* ScalarType.UINT32 */ }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): ServerMessage_Room { + return new ServerMessage_Room().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): ServerMessage_Room { + return new ServerMessage_Room().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): ServerMessage_Room { + return new ServerMessage_Room().fromJsonString(jsonString, options); + } + + static equals(a: ServerMessage_Room | PlainMessage | undefined, b: ServerMessage_Room | PlainMessage | undefined): boolean { + return proto3.util.equals(ServerMessage_Room, a, b); + } +} + +/** + * @generated from message pianoverse.ServerMessage.Welcome + */ +export class ServerMessage_Welcome extends Message { + /** + * @generated from field: string id = 1; + */ + id = ""; + + /** + * @generated from field: string name = 2; + */ + name = ""; + + /** + * @generated from field: string color = 3; + */ + color = ""; + + /** + * @generated from field: string room = 4; + */ + room = ""; + + /** + * @generated from field: string owner = 5; + */ + owner = ""; + + /** + * @generated from field: repeated pianoverse.ServerMessage.Chat chat = 6; + */ + chat: ServerMessage_Chat[] = []; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "pianoverse.ServerMessage.Welcome"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "name", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 3, name: "color", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 4, name: "room", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 5, name: "owner", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 6, name: "chat", kind: "message", T: ServerMessage_Chat, repeated: true }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): ServerMessage_Welcome { + return new ServerMessage_Welcome().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): ServerMessage_Welcome { + return new ServerMessage_Welcome().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): ServerMessage_Welcome { + return new ServerMessage_Welcome().fromJsonString(jsonString, options); + } + + static equals(a: ServerMessage_Welcome | PlainMessage | undefined, b: ServerMessage_Welcome | PlainMessage | undefined): boolean { + return proto3.util.equals(ServerMessage_Welcome, a, b); + } +} + +/** + * @generated from message pianoverse.ServerMessage.Sustain + */ +export class ServerMessage_Sustain extends Message { + /** + * @generated from field: string id = 1; + */ + id = ""; + + /** + * @generated from field: bool enabled = 2; + */ + enabled = false; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "pianoverse.ServerMessage.Sustain"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "enabled", kind: "scalar", T: 8 /* ScalarType.BOOL */ }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): ServerMessage_Sustain { + return new ServerMessage_Sustain().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): ServerMessage_Sustain { + return new ServerMessage_Sustain().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): ServerMessage_Sustain { + return new ServerMessage_Sustain().fromJsonString(jsonString, options); + } + + static equals(a: ServerMessage_Sustain | PlainMessage | undefined, b: ServerMessage_Sustain | PlainMessage | undefined): boolean { + return proto3.util.equals(ServerMessage_Sustain, a, b); + } +} + +/** + * @generated from message pianoverse.ServerMessage.Join + */ +export class ServerMessage_Join extends Message { + /** + * @generated from field: string id = 1; + */ + id = ""; + + /** + * @generated from field: string name = 2; + */ + name = ""; + + /** + * @generated from field: string color = 3; + */ + color = ""; + + /** + * @generated from field: int32 role = 4; + */ + role = 0; + + /** + * @generated from field: float x = 6; + */ + x = 0; + + /** + * @generated from field: float y = 7; + */ + y = 0; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "pianoverse.ServerMessage.Join"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "name", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 3, name: "color", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 4, name: "role", kind: "scalar", T: 5 /* ScalarType.INT32 */ }, + { no: 6, name: "x", kind: "scalar", T: 2 /* ScalarType.FLOAT */ }, + { no: 7, name: "y", kind: "scalar", T: 2 /* ScalarType.FLOAT */ }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): ServerMessage_Join { + return new ServerMessage_Join().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): ServerMessage_Join { + return new ServerMessage_Join().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): ServerMessage_Join { + return new ServerMessage_Join().fromJsonString(jsonString, options); + } + + static equals(a: ServerMessage_Join | PlainMessage | undefined, b: ServerMessage_Join | PlainMessage | undefined): boolean { + return proto3.util.equals(ServerMessage_Join, a, b); + } +} + +/** + * @generated from message pianoverse.Profile + */ +export class Profile extends Message { + /** + * @generated from field: string id = 1; + */ + id = ""; + + /** + * @generated from field: string name = 2; + */ + name = ""; + + /** + * @generated from field: string color = 3; + */ + color = ""; + + /** + * @generated from field: string sound = 4; + */ + sound = ""; + + /** + * @generated from field: bool muted = 5; + */ + muted = false; + + /** + * @generated from field: float x = 6; + */ + x = 0; + + /** + * @generated from field: float y = 7; + */ + y = 0; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "pianoverse.Profile"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "name", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 3, name: "color", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 4, name: "sound", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 5, name: "muted", kind: "scalar", T: 8 /* ScalarType.BOOL */ }, + { no: 6, name: "x", kind: "scalar", T: 2 /* ScalarType.FLOAT */ }, + { no: 7, name: "y", kind: "scalar", T: 2 /* ScalarType.FLOAT */ }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): Profile { + return new Profile().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): Profile { + return new Profile().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): Profile { + return new Profile().fromJsonString(jsonString, options); + } + + static equals(a: Profile | PlainMessage | undefined, b: Profile | PlainMessage | undefined): boolean { + return proto3.util.equals(Profile, a, b); + } +} + +/** + * @generated from message pianoverse.Move + */ +export class Move extends Message { + /** + * @generated from field: string id = 1; + */ + id = ""; + + /** + * @generated from field: float x = 2; + */ + x = 0; + + /** + * @generated from field: float y = 3; + */ + y = 0; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "pianoverse.Move"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "x", kind: "scalar", T: 2 /* ScalarType.FLOAT */ }, + { no: 3, name: "y", kind: "scalar", T: 2 /* ScalarType.FLOAT */ }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): Move { + return new Move().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): Move { + return new Move().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): Move { + return new Move().fromJsonString(jsonString, options); + } + + static equals(a: Move | PlainMessage | undefined, b: Move | PlainMessage | undefined): boolean { + return proto3.util.equals(Move, a, b); + } +} + +/** + * @generated from message pianoverse.Press + */ +export class Press extends Message { + /** + * @generated from field: uint32 key = 2; + */ + key = 0; + + /** + * @generated from field: uint32 vel = 3; + */ + vel = 0; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "pianoverse.Press"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 2, name: "key", kind: "scalar", T: 13 /* ScalarType.UINT32 */ }, + { no: 3, name: "vel", kind: "scalar", T: 13 /* ScalarType.UINT32 */ }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): Press { + return new Press().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): Press { + return new Press().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): Press { + return new Press().fromJsonString(jsonString, options); + } + + static equals(a: Press | PlainMessage | undefined, b: Press | PlainMessage | undefined): boolean { + return proto3.util.equals(Press, a, b); + } +} + +/** + * @generated from message pianoverse.Release + */ +export class Release extends Message { + /** + * @generated from field: string id = 1; + */ + id = ""; + + /** + * @generated from field: uint32 key = 2; + */ + key = 0; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "pianoverse.Release"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "key", kind: "scalar", T: 13 /* ScalarType.UINT32 */ }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): Release { + return new Release().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): Release { + return new Release().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): Release { + return new Release().fromJsonString(jsonString, options); + } + + static equals(a: Release | PlainMessage | undefined, b: Release | PlainMessage | undefined): boolean { + return proto3.util.equals(Release, a, b); + } +} + diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..238655f --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + // Enable latest features + "lib": ["ESNext", "DOM"], + "target": "ESNext", + "module": "ESNext", + "moduleDetection": "force", + "jsx": "react-jsx", + "allowJs": true, + + // Bundler mode + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "noEmit": true, + + // Best practices + "strict": true, + "skipLibCheck": true, + "noFallthroughCasesInSwitch": true, + + // Some stricter flags (disabled by default) + "noUnusedLocals": false, + "noUnusedParameters": false, + "noPropertyAccessFromIndexSignature": false + } +}