Skip to content

Instantly share code, notes, and snippets.

View sstashy's full-sized avatar

stashy sstashy

View GitHub Profile
-- doing my own billiards physics engine here using metatables and cframe
-- using robloxs native solver for fast moving small balls sucks because they tunnel thru thin rails
-- so im doing custom sub-stepping and elastic collision math to fix that
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local Workspace = game:GetService("Workspace")
-- config stuff
local ENGINE_TICK_RATE = 1 / 120
// A standard synchronous event emitter for handling pub/sub logic.
// We use an ES6 Map for storing events instead of a plain object. This prevents
// prototype pollution vulnerabilities and gives us better iteration performance.
class EventEmitter {
constructor() {
this.events = new Map();
}
// Registers a callback to an event channel.
// Returns 'this' to allow method chaining (e.g., emitter.on('a', cb).on('b', cb)).
// Delays execution of a function until after 'delay' milliseconds have elapsed since the last call.
// This is critical for search bars so we don't spam the server or freeze the UI on every single keystroke.
// Uses a closure to keep track of the timer ID across multiple calls.
function debounce(fn, delay) {
let timer = null;
return function (...args) {
// Clear the existing timer if the user typed something again before the delay finished
if (timer) clearTimeout(timer);
// A min-heap priority queue for scheduling tasks.
// We use a flat array representation instead of node objects to improve cache locality
// and avoid the overhead of constant garbage collection when adding/removing tasks.
// In this min-heap, a lower priority number means it executes first.
class PriorityTaskManager {
constructor() {
this.heap = [];
this.taskIdCounter = 1;
}