initial commit
This commit is contained in:
commit
dcf885a7b0
26
.gitignore
vendored
Normal file
26
.gitignore
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
node_modules
|
||||
|
||||
# Output
|
||||
.output
|
||||
.vercel
|
||||
.netlify
|
||||
.wrangler
|
||||
/.svelte-kit
|
||||
/build
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Env
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
!.env.test
|
||||
|
||||
# Vite
|
||||
vite.config.js.timestamp-*
|
||||
vite.config.ts.timestamp-*
|
||||
|
||||
*.pem
|
||||
jack/
|
4
.vscode/settings.json
vendored
Normal file
4
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"files.autoSave": "onFocusChange"
|
||||
}
|
38
README.md
Normal file
38
README.md
Normal file
|
@ -0,0 +1,38 @@
|
|||
# sv
|
||||
|
||||
Everything you need to build a Svelte project, powered by [`sv`](https://github.com/sveltejs/cli).
|
||||
|
||||
## Creating a project
|
||||
|
||||
If you're seeing this, you've probably already done this step. Congrats!
|
||||
|
||||
```bash
|
||||
# create a new project in the current directory
|
||||
npx sv create
|
||||
|
||||
# create a new project in my-app
|
||||
npx sv create my-app
|
||||
```
|
||||
|
||||
## Developing
|
||||
|
||||
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
|
||||
# or start the server and open the app in a new browser tab
|
||||
npm run dev -- --open
|
||||
```
|
||||
|
||||
## Building
|
||||
|
||||
To create a production version of your app:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
You can preview the production build with `npm run preview`.
|
||||
|
||||
> To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment.
|
25
package.json
Normal file
25
package.json
Normal file
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"name": "proximity-chat",
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite dev",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-node": "^5.2.0",
|
||||
"@sveltejs/kit": "^2.9.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^5.0.0",
|
||||
"@vitejs/plugin-basic-ssl": "^1.2.0",
|
||||
"svelte": "^5.0.0",
|
||||
"svelte-check": "^4.0.0",
|
||||
"typescript": "^5.0.0",
|
||||
"vite": "^6.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"peerjs": "^1.5.4"
|
||||
}
|
||||
}
|
1145
pnpm-lock.yaml
Normal file
1145
pnpm-lock.yaml
Normal file
File diff suppressed because it is too large
Load diff
13
src/app.d.ts
vendored
Normal file
13
src/app.d.ts
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
// See https://svelte.dev/docs/kit/types#app.d.ts
|
||||
// for information about these interfaces
|
||||
declare global {
|
||||
namespace App {
|
||||
// interface Error {}
|
||||
// interface Locals {}
|
||||
// interface PageData {}
|
||||
// interface PageState {}
|
||||
// interface Platform {}
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
12
src/app.html
Normal file
12
src/app.html
Normal file
|
@ -0,0 +1,12 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
149
src/lib/binary/reader.ts
Normal file
149
src/lib/binary/reader.ts
Normal file
|
@ -0,0 +1,149 @@
|
|||
// import { BinaryStreamReader } from "./readerStream";
|
||||
// import { AsyncReadMethod, AsyncReadMethodReturnValue, ObjectValue, ObjectValueType, ReadMethod, ReadMethodReturnValue } from "./types";
|
||||
|
||||
// export class BinaryReader {
|
||||
// protected index: number = 0;
|
||||
|
||||
// constructor(
|
||||
// protected readonly buffer: DataView,
|
||||
// ) {}
|
||||
|
||||
// readBoolean(): boolean {
|
||||
// return this.readUInt8() != 0;
|
||||
// }
|
||||
|
||||
// readSInt8(): number {
|
||||
// const value = this.buffer.getInt8(this.index);
|
||||
|
||||
// this.index++;
|
||||
|
||||
// return value;
|
||||
// }
|
||||
|
||||
// readUInt8(): number {
|
||||
// const value = this.buffer.getUint8(this.index);
|
||||
|
||||
// this.index++;
|
||||
|
||||
// return value;
|
||||
// }
|
||||
|
||||
// readSInt16(): number {
|
||||
// const value = this.buffer.getInt16(this.index, true);
|
||||
|
||||
// this.index += 2;
|
||||
|
||||
// return value;
|
||||
// }
|
||||
|
||||
// readUInt16(): number {
|
||||
// const value = this.buffer.getUint16(this.index, true);
|
||||
|
||||
// this.index += 2;
|
||||
|
||||
// return value;
|
||||
// }
|
||||
|
||||
// readSInt32(): number {
|
||||
// const value = this.buffer.getInt32(this.index, true);
|
||||
|
||||
// this.index += 4;
|
||||
|
||||
// return value;
|
||||
// }
|
||||
|
||||
// readUInt32(): number {
|
||||
// const value = this.buffer.getUint32(this.index, true);
|
||||
|
||||
// this.index += 4;
|
||||
|
||||
// return value;
|
||||
// }
|
||||
|
||||
// readSInt64(): bigint {
|
||||
// const value = this.buffer.getBigInt64(this.index, true);
|
||||
|
||||
// this.index += 8;
|
||||
|
||||
// return value;
|
||||
// }
|
||||
|
||||
// readUInt64(): bigint {
|
||||
// const value = this.buffer.getBigUint64(this.index, true);
|
||||
|
||||
// this.index += 8;
|
||||
|
||||
// return value;
|
||||
// }
|
||||
|
||||
// readFloat32(): number {
|
||||
// const value = this.buffer.getFloat32(this.index, true);
|
||||
|
||||
// this.index += 4;
|
||||
|
||||
// return value;
|
||||
// }
|
||||
|
||||
// readFloat64(): number {
|
||||
// const value = this.buffer.getFloat64(this.index, true);
|
||||
|
||||
// this.index += 8;
|
||||
|
||||
// return value;
|
||||
// }
|
||||
|
||||
// readString(length: number, encoding?: string): string {
|
||||
// const decoder = new TextDecoder(encoding);
|
||||
|
||||
// return decoder.decode(this.buffer.buffer.slice(this.index, this.index += length));
|
||||
// }
|
||||
|
||||
// async readArray<T>(size: number, readMethod: ReadMethod<T> | AsyncReadMethod<T>): Promise<T[]> {
|
||||
// const array = new Array<T>(size);
|
||||
|
||||
// for (let i = 0; i < size; i++) {
|
||||
// array[i] = await this.read(readMethod);
|
||||
// }
|
||||
|
||||
// return array;
|
||||
// }
|
||||
|
||||
// async readObject(): Promise<ObjectValue> {
|
||||
// return await this.readMappedShortEnum({
|
||||
// [ObjectValueType.Object]: async (r: BinaryReader | BinaryStreamReader) => Object.fromEntries(await r.readArray(await r.readUInt32(), async r2 => [ await r2.readString(await r2.readUInt32()), await r2.readObject() ])),
|
||||
// [ObjectValueType.Array]: async (r: BinaryReader | BinaryStreamReader) => await r.readArray(await r.readUInt32(), async (r2: BinaryReader | BinaryStreamReader) => await r2.readObject()),
|
||||
// [ObjectValueType.Boolean]: async (r: BinaryReader | BinaryStreamReader) => await r.readBoolean(),
|
||||
// [ObjectValueType.Null]: () => null,
|
||||
// [ObjectValueType.Number]: async (r: BinaryReader | BinaryStreamReader) => await r.readFloat64(),
|
||||
// [ObjectValueType.String]: async (r: BinaryReader | BinaryStreamReader) => await r.readString(await r.readUInt32()),
|
||||
// })
|
||||
// }
|
||||
|
||||
// async read<T>(readMethod: ReadMethod<T> | AsyncReadMethod<T>): Promise<T> {
|
||||
// if ("deserialize" in readMethod) {
|
||||
// return await readMethod.deserialize(this);
|
||||
// }
|
||||
|
||||
// return await readMethod(this);
|
||||
// }
|
||||
|
||||
// readShortEnum<T extends number>(): T {
|
||||
// return this.readUInt8() as T;
|
||||
// }
|
||||
|
||||
// readEnum<T extends number>(): T {
|
||||
// return this.readUInt16() as T;
|
||||
// }
|
||||
|
||||
// readDate(): Date {
|
||||
// return new Date(Number(this.readUInt64()));
|
||||
// }
|
||||
|
||||
// async readMappedEnum<T extends number, R extends Record<T, ReadMethod<any> | AsyncReadMethod<T>>>(mappedType: R): Promise<ReadMethodReturnValue<R[keyof R]> | AsyncReadMethodReturnValue<R[keyof R]>> {
|
||||
// return await this.read(mappedType[this.readEnum<T>()]);
|
||||
// }
|
||||
|
||||
// async readMappedShortEnum<T extends number, R extends Record<T, ReadMethod<any> | AsyncReadMethod<T>>>(mappedType: R): Promise<ReadMethodReturnValue<R[keyof R]> | AsyncReadMethodReturnValue<R[keyof R]>> {
|
||||
// return await this.read(mappedType[this.readShortEnum<T>()]);
|
||||
// }
|
||||
// }
|
166
src/lib/binary/readerStream.ts
Normal file
166
src/lib/binary/readerStream.ts
Normal file
|
@ -0,0 +1,166 @@
|
|||
import type { AsyncReadMethod } from "./types";
|
||||
|
||||
export class BinaryStreamReader {
|
||||
chunks: { view: ArrayBuffer, index: number }[] = [];
|
||||
readStack: { size: number, resolve: (value: DataView | PromiseLike<DataView>) => void, reject: (reason?: any) => void }[] = [];
|
||||
|
||||
constructor() { }
|
||||
|
||||
push(view: ArrayBuffer): void {
|
||||
this.chunks.push({ view, index: 0 });
|
||||
|
||||
let next = this.readStack[0];
|
||||
|
||||
while (next && this.hasFree(next.size)) {
|
||||
this.readStack.shift()!.resolve(this.get(next.size));
|
||||
|
||||
next = this.readStack[0];
|
||||
}
|
||||
}
|
||||
|
||||
static fromReader(reader: ReadableStreamDefaultReader): BinaryStreamReader {
|
||||
const streamReader = new BinaryStreamReader();
|
||||
|
||||
(async () => {
|
||||
while (true) {
|
||||
const data = await reader.read();
|
||||
console.log("got data", data);
|
||||
streamReader.push(data.value);
|
||||
}
|
||||
})();
|
||||
|
||||
return streamReader;
|
||||
}
|
||||
|
||||
private get(size: number): DataView {
|
||||
const b = new Uint8Array(size);
|
||||
let bHead: number = 0;
|
||||
|
||||
for (let i = 0; i < this.chunks.length; i++) {
|
||||
const buf = this.chunks[i];
|
||||
|
||||
let wantedBytes = (size - bHead)
|
||||
let availableBytes = (buf.view.byteLength - buf.index);
|
||||
|
||||
if (wantedBytes < availableBytes) {
|
||||
b.set(new Uint8Array(buf.view.slice(buf.index, buf.index += wantedBytes)), bHead);
|
||||
bHead += wantedBytes;
|
||||
break;
|
||||
} else {
|
||||
b.set(new Uint8Array(buf.view.slice(buf.index, buf.index += availableBytes)), bHead);
|
||||
bHead += availableBytes;
|
||||
}
|
||||
}
|
||||
|
||||
while (this.chunks[0] && this.chunks[0].view.byteLength == this.chunks[0].index) {
|
||||
this.chunks.shift();
|
||||
}
|
||||
|
||||
return new DataView(b.buffer);
|
||||
}
|
||||
|
||||
private hasFree(size: number) {
|
||||
let accumulated: number = 0;
|
||||
|
||||
for (let i = 0; i < this.chunks.length; i++) {
|
||||
accumulated += this.chunks[i].view.byteLength - this.chunks[i].index;
|
||||
|
||||
if (accumulated >= size) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
async bytes(size: number): Promise<DataView> {
|
||||
return new Promise((res, rej) => {
|
||||
if (this.hasFree(size)) {
|
||||
return res(this.get(size));
|
||||
}
|
||||
|
||||
this.readStack.push({ size, resolve: res, reject: rej });
|
||||
})
|
||||
}
|
||||
|
||||
async readBoolean(): Promise<boolean> {
|
||||
return await this.readUInt8() != 0;
|
||||
}
|
||||
|
||||
async readSInt8(): Promise<number> {
|
||||
return (await this.bytes(1)).getInt8(0);
|
||||
}
|
||||
|
||||
async readUInt8(): Promise<number> {
|
||||
return (await this.bytes(1)).getUint8(0);
|
||||
}
|
||||
|
||||
async readSInt16(): Promise<number> {
|
||||
return (await this.bytes(2)).getInt16(0);
|
||||
}
|
||||
|
||||
async readUInt16(): Promise<number> {
|
||||
return (await this.bytes(2)).getUint16(0);
|
||||
}
|
||||
|
||||
async readSInt32(): Promise<number> {
|
||||
return (await this.bytes(4)).getInt32(0);
|
||||
}
|
||||
|
||||
async readUInt32(): Promise<number> {
|
||||
return (await this.bytes(4)).getUint32(0);
|
||||
}
|
||||
|
||||
async readSInt64(): Promise<bigint> {
|
||||
return (await this.bytes(8)).getBigInt64(0);
|
||||
}
|
||||
|
||||
async readUInt64(): Promise<bigint> {
|
||||
return (await this.bytes(8)).getBigUint64(0);
|
||||
}
|
||||
|
||||
async readFloat32(): Promise<number> {
|
||||
return (await this.bytes(4)).getFloat32(0);
|
||||
}
|
||||
|
||||
async readFloat64(): Promise<number> {
|
||||
return (await this.bytes(8)).getFloat64(0);
|
||||
}
|
||||
|
||||
async readString(length: number, encoding?: string): Promise<string> {
|
||||
const decoder = new TextDecoder(encoding);
|
||||
|
||||
return decoder.decode(await this.bytes(length));
|
||||
}
|
||||
|
||||
async readFixedString(length: number, encoding?: string): Promise<string> {
|
||||
const decoder = new TextDecoder(encoding);
|
||||
|
||||
const bytes = await this.bytes(length);
|
||||
const slice = new Uint8Array(bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength));
|
||||
const end = slice.findIndex(byte => byte == 0);
|
||||
console.log(bytes.byteOffset, bytes.byteOffset + end, end, bytes.byteLength);
|
||||
|
||||
return decoder.decode(bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + end));
|
||||
}
|
||||
|
||||
async readArray<T>(size: number, readMethod: AsyncReadMethod<T, this>): Promise<T[]> {
|
||||
const array = new Array<T>(size);
|
||||
|
||||
for (let i = 0; i < size; i++) {
|
||||
array[i] = await this.read(readMethod);
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
async read<T>(readMethod: AsyncReadMethod<T, this>): Promise<T> {
|
||||
if ("deserialize" in readMethod) {
|
||||
return await readMethod.deserialize(this);
|
||||
}
|
||||
|
||||
return await readMethod(this);
|
||||
}
|
||||
|
||||
async readDate(): Promise<Date> {
|
||||
return new Date(Number(await this.readUInt64()));
|
||||
}
|
||||
}
|
18
src/lib/binary/types.ts
Normal file
18
src/lib/binary/types.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
type Method<T, R, F extends string> = ((reader: R) => T) | { [key in F]: (reader: R) => T };
|
||||
|
||||
export type ReadMethod<T, R> = Method<T, R, "deserialize">;
|
||||
export type WriteMethod<W> = Method<void, W, "serialize">;
|
||||
export type AsyncReadMethod<T, R> = Method<T | Promise<T>, R, "deserialize">;
|
||||
|
||||
export type ReadMethodReturnValue<X> = X extends ReadMethod<infer Y, any> ? (Y extends Promise<infer Z> ? Z : Y) : never;
|
||||
|
||||
export enum ObjectValueType {
|
||||
Object,
|
||||
Array,
|
||||
String,
|
||||
Number,
|
||||
Boolean,
|
||||
Null,
|
||||
}
|
||||
|
||||
export type ObjectValue = { [key: string]: ObjectValue } | ObjectValue[] | null | string | number | boolean
|
130
src/lib/binary/writer.ts
Normal file
130
src/lib/binary/writer.ts
Normal file
|
@ -0,0 +1,130 @@
|
|||
import type { ObjectValue, ObjectValueType, WriteMethod } from "./types";
|
||||
|
||||
export class BinaryWriter {
|
||||
protected index: number = 0;
|
||||
protected buffer: DataView;
|
||||
|
||||
constructor(baseSize?: number) {
|
||||
this.buffer = new DataView(new ArrayBuffer(baseSize ?? 0));
|
||||
}
|
||||
|
||||
protected request(size: number) {
|
||||
let needSize = size - (this.buffer.byteLength - this.index);
|
||||
|
||||
if (needSize > 0) {
|
||||
let newBuffer = new Uint8Array(this.buffer.byteLength + needSize);
|
||||
|
||||
newBuffer.set(new Uint8Array(this.buffer.buffer), 0);
|
||||
|
||||
this.buffer = new DataView(newBuffer.buffer);
|
||||
}
|
||||
}
|
||||
|
||||
writeBoolean(value: boolean): void {
|
||||
this.writeUInt8(value ? 1 : 0);
|
||||
}
|
||||
|
||||
writeSInt8(value: number): void {
|
||||
this.request(1);
|
||||
|
||||
this.buffer.setInt8(this.index, value);
|
||||
|
||||
this.index++;
|
||||
}
|
||||
|
||||
writeUInt8(value: number): void {
|
||||
this.request(1);
|
||||
|
||||
this.buffer.setUint8(this.index, value);
|
||||
|
||||
this.index++;
|
||||
}
|
||||
|
||||
writeSInt16(value: number): void {
|
||||
this.request(2);
|
||||
|
||||
this.buffer.setInt16(this.index, value);
|
||||
|
||||
this.index += 2;
|
||||
}
|
||||
|
||||
writeUInt16(value: number): void {
|
||||
this.request(2);
|
||||
|
||||
this.buffer.setUint16(this.index, value);
|
||||
|
||||
this.index += 2;
|
||||
}
|
||||
|
||||
writeSInt32(value: number): void {
|
||||
this.request(4);
|
||||
|
||||
this.buffer.setInt32(this.index, value);
|
||||
|
||||
this.index += 4;
|
||||
}
|
||||
|
||||
writeUInt32(value: number): void {
|
||||
this.request(4);
|
||||
|
||||
this.buffer.setUint32(this.index, value);
|
||||
|
||||
this.index += 4;
|
||||
}
|
||||
|
||||
writeSInt64(value: bigint): void {
|
||||
this.request(8);
|
||||
|
||||
this.buffer.setBigInt64(this.index, value);
|
||||
|
||||
this.index += 8;
|
||||
}
|
||||
|
||||
writeUInt64(value: bigint): void {
|
||||
this.request(8);
|
||||
|
||||
this.buffer.setBigUint64(this.index, value);
|
||||
|
||||
this.index += 8;
|
||||
}
|
||||
|
||||
writeFloat32(value: number): void {
|
||||
this.request(4);
|
||||
|
||||
this.buffer.setFloat32(this.index, value);
|
||||
|
||||
this.index += 4;
|
||||
}
|
||||
|
||||
writeFloat64(value: number): void {
|
||||
this.request(8);
|
||||
|
||||
this.buffer.setFloat64(this.index, value);
|
||||
|
||||
this.index += 8;
|
||||
}
|
||||
|
||||
writeString(string: string): void {
|
||||
const encoder = new TextEncoder();
|
||||
const encoded = encoder.encode(string);
|
||||
this.request(encoded.byteLength);
|
||||
|
||||
new Uint8Array(this.buffer.buffer).set(encoded, this.index);
|
||||
|
||||
this.index += encoded.byteLength;
|
||||
}
|
||||
|
||||
writeArray(array: WriteMethod<BinaryWriter>[]): void {
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
this.write(array[i]);
|
||||
}
|
||||
}
|
||||
write(writeMethod: WriteMethod<BinaryWriter>): void {
|
||||
if ("serialize" in writeMethod) {
|
||||
writeMethod.serialize(this);
|
||||
return;
|
||||
}
|
||||
|
||||
writeMethod(this);
|
||||
}
|
||||
}
|
49
src/lib/client.svelte.ts
Normal file
49
src/lib/client.svelte.ts
Normal file
|
@ -0,0 +1,49 @@
|
|||
import Peer from "peerjs";
|
||||
import { readHello } from "./protocol/hello";
|
||||
import { BinaryStreamReader } from "./binary/readerStream";
|
||||
|
||||
export class Client {
|
||||
static async connect() {
|
||||
const transport = new WebTransport(`https://${location.hostname}:4433`, { allowPooling: false });
|
||||
await transport.ready;
|
||||
const stream = await transport.createBidirectionalStream();
|
||||
|
||||
const peer = new Peer();
|
||||
await new Promise((res) => {
|
||||
peer.on("open", () => {
|
||||
console.log("open!", peer.id)
|
||||
res(void 0);
|
||||
});
|
||||
});
|
||||
|
||||
await stream.writable.getWriter().write(new TextEncoder().encode(peer.id));
|
||||
const reader = BinaryStreamReader.fromReader(stream.readable.getReader());
|
||||
const players = $state(await readHello(reader));
|
||||
|
||||
return new Client(players, peer, transport, stream);
|
||||
}
|
||||
|
||||
private constructor(
|
||||
public players: Player[],
|
||||
private peer: Peer,
|
||||
private transport: WebTransport,
|
||||
private stream: WebTransportBidirectionalStream
|
||||
) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
get id() {
|
||||
return this.peer.id;
|
||||
}
|
||||
|
||||
closed() {
|
||||
// return transport.closed;
|
||||
}
|
||||
}
|
||||
|
||||
export class Player {
|
||||
constructor(public name: string, public id: number, public position: number[], public stage: string) { }
|
||||
|
||||
|
||||
}
|
24
src/lib/protocol/hello.ts
Normal file
24
src/lib/protocol/hello.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
import { BinaryStreamReader } from "../binary/readerStream";
|
||||
import { Player } from "../client.svelte";
|
||||
|
||||
export async function readHello(reader: BinaryStreamReader) {
|
||||
console.log("reading");
|
||||
const count = await reader.readUInt8();
|
||||
console.log("reading", count);
|
||||
const players = await reader.readArray(count, async (reader) => {
|
||||
const name = await reader.readFixedString(0x20);
|
||||
console.log(name);
|
||||
const id = await reader.readUInt32();
|
||||
const position = await reader.readArray(3, async reader => await reader.readFloat32());
|
||||
const stage = await reader.readFixedString(0x40);
|
||||
|
||||
return new Player(
|
||||
name,
|
||||
id,
|
||||
position,
|
||||
stage,
|
||||
);
|
||||
});
|
||||
|
||||
return players;
|
||||
}
|
1
src/lib/protocol/index.ts
Normal file
1
src/lib/protocol/index.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export { } from "./hello";
|
36
src/routes/+page.svelte
Normal file
36
src/routes/+page.svelte
Normal file
|
@ -0,0 +1,36 @@
|
|||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { Client } from "$lib/client.svelte.ts";
|
||||
import { BinaryStreamReader } from "$lib/binary/readerStream";
|
||||
|
||||
let name = $state("none");
|
||||
let client: Client = undefined as any;
|
||||
let players = $derived(client?.players ?? []);
|
||||
async function a() {
|
||||
client = await Client.connect();
|
||||
console.log(client);
|
||||
}
|
||||
|
||||
onMount(a);
|
||||
</script>
|
||||
|
||||
<div>
|
||||
I am <input type="text" maxlength="32" list="connectedPlayers" />
|
||||
</div>
|
||||
<datalist>
|
||||
{#each players as player}
|
||||
<option>{player.name}</option>
|
||||
{/each}
|
||||
</datalist>
|
||||
<div>
|
||||
Connected players - {players.length}<br />
|
||||
{#each players as player}
|
||||
<pre class="name">{player.name}</pre>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.name {
|
||||
font-style: italic;
|
||||
}
|
||||
</style>
|
BIN
static/favicon.png
Normal file
BIN
static/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
18
svelte.config.js
Normal file
18
svelte.config.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
import adapter from '@sveltejs/adapter-node';
|
||||
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
||||
|
||||
/** @type {import('@sveltejs/kit').Config} */
|
||||
const config = {
|
||||
// Consult https://svelte.dev/docs/kit/integrations
|
||||
// for more information about preprocessors
|
||||
preprocess: vitePreprocess(),
|
||||
|
||||
kit: {
|
||||
// adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.
|
||||
// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
|
||||
// See https://svelte.dev/docs/kit/adapters for more information about adapters.
|
||||
adapter: adapter()
|
||||
}
|
||||
};
|
||||
|
||||
export default config;
|
22
tsconfig.json
Normal file
22
tsconfig.json
Normal file
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"extends": "./.svelte-kit/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"moduleResolution": "bundler"
|
||||
},
|
||||
"include": [
|
||||
"./webtransport.d.ts"
|
||||
]
|
||||
// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
|
||||
// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
|
||||
//
|
||||
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
|
||||
// from the referenced tsconfig.json - TypeScript does not merge them in
|
||||
}
|
15
vite.config.ts
Normal file
15
vite.config.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
import { sveltekit } from '@sveltejs/kit/vite';
|
||||
import { defineConfig } from 'vite';
|
||||
import { readFileSync } from 'node:fs';
|
||||
|
||||
export default defineConfig({
|
||||
server: {
|
||||
https: {
|
||||
key: readFileSync('key.pem'),
|
||||
cert: readFileSync('cert.pem'),
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
sveltekit(),
|
||||
]
|
||||
});
|
29392
webtransport.d.ts
vendored
Normal file
29392
webtransport.d.ts
vendored
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue