import { int32, int64, PackedVector2Array, Vector2 } from 'godot' export class InputBufferError extends Error { constructor(message: string) { super(`InputBufferError: ${message}`) } static empty() { return new InputBufferError('cannot perform operation, buffer is empty') } static outOfBounds(index: int64) { return new InputBufferError(`cannot access ${index}: index out of bounds`) } } export default class InputBuffer { readonly capacity: int32 private _buffer: PackedVector2Array private _head: int32 = 0 private _tail: int32 = 0 private _size: int32 = 0 constructor(capacity: int32) { this.capacity = capacity this._buffer = new PackedVector2Array() this._buffer.resize(capacity) this._buffer.fill(Vector2.ZERO) } is_empty() { return this._size === 0 } is_full() { return this._size === this.capacity } push(value: Vector2) { this._buffer.set_indexed(this._head, value) this._head = (this._head + 1) % this.capacity if (this.is_full()) { this._tail = this._head } else { this._size += 1 } } pop(): Vector2 { if (this.is_empty()) { throw InputBufferError.empty() } const value = this.tail() this._tail = (this._tail + 1) % this.capacity this._size += 1 return value } at(index: int64) { if (index >= this._size) { throw InputBufferError.outOfBounds(index) } const n = index < 0 ? this._head - index : this._tail + index const idx = n % this.capacity return this._buffer.get_indexed(idx) } size() { return this._size } head() { return this._buffer.get_indexed(this._head) } tail() { return this._buffer.get_indexed(this._tail) } slice(begin: int64, end?: int64) { return this._buffer.slice(begin, end) } clear() { this._size = 0 this._head = 0 this._tail = 0 } }