resource manager overhaul

This commit is contained in:
Emmaline Autumn 2025-02-16 11:46:12 -07:00
parent b30a241d09
commit 01081706b1
14 changed files with 1922 additions and 19 deletions

3
.gitignore vendored
View File

@ -23,3 +23,6 @@ dist-ssr
*.njsproj
*.sln
*.sw?
# Packed devtools
devtools.zip

View File

@ -3,7 +3,8 @@
"dev": "deno run -A --node-modules-dir npm:vite",
"build": "deno run -A --node-modules-dir npm:vite build",
"preview": "deno run -A --node-modules-dir npm:vite preview",
"serve": "deno run --allow-net --allow-read jsr:@std/http@1/file-server dist/"
"serve": "deno run --allow-net --allow-read jsr:@std/http@1/file-server dist/",
"pack-devtools": "rm -rf devtools.zip && deno run -A npm:web-ext build -o --source-dir devtools --artifacts-dir devtools.zip"
},
"compilerOptions": {
"lib": [

1843
deno.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,9 @@
{
"manifest_version": 2,
"name": "Context Stack DevTools",
"name": "SNR DevTools",
"version": "1.0",
"description": "A devtools panel to view and edit context stack values.",
"author": "Emmaline Autumn",
"devtools_page": "devtools.html",
"background": {
"scripts": [
@ -24,5 +25,13 @@
"devtools",
"tabs",
"*://*/*"
]
],
"icons": {
"48": "train icon.png"
},
"browser_specific_settings": {
"gecko": {
"id": "snrdt@cyborggrizzly.com"
}
}
}

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -1,16 +1,39 @@
// namespace:type/location
type NamespacedId = `${string}:${"img" | "audio" | "sprite"}/${string}`;
/**
* Resources are stored in namespaces, and can be accessed by their namespaced id.
* Sprites are located in blob storage as a single png file.
* Audio is located in blob storage as a single mp3 file.
*
* Custom resources can be loaded via the public API, however they will not be loaded on other clients.
* Ideally, engine and car definitions should be stored in the resource manager so that custom cars can be created.
*/
export class ResourceManager {
private resources: Map<string, unknown> = new Map();
private statuses: Map<string, Promise<boolean>> = new Map();
get<T>(name: string): T {
get<T>(name: NamespacedId): T {
if (!this.resources.has(name)) {
throw new Error(`Resource ${name} not found`);
}
return this.resources.get(name) as T;
}
set(name: string, value: unknown) {
set(
name: NamespacedId,
value: unknown,
) {
const identifier = parseNamespacedId(name);
if (typeof (value as EventSource).addEventListener === "function") {
if (value instanceof Image) {
// During development, we can use the local file system
value.src =
`/blobs/${identifier.namespace}/${identifier.type}/${identifier.name}${
extensionByType(identifier.type)
}`;
console.log(value.src);
}
this.statuses.set(
name,
new Promise((resolve) => {
@ -36,3 +59,28 @@ export class ResourceManager {
return Promise.all(Array.from(this.statuses.values()));
}
}
type ResourceType = "img" | "audio" | "sprite";
function extensionByType(type: ResourceType) {
switch (type) {
case "img":
return ".png";
case "audio":
return ".mp3";
case "sprite":
return ".png";
}
}
type NamespaceIdentifier = {
namespace: string;
type: ResourceType;
name: string;
};
function parseNamespacedId(id: NamespacedId): NamespaceIdentifier {
const [namespace, location] = id.split(":");
const [type, ...name] = location.split("/");
return { namespace, type: type as ResourceType, name: name.join("/") };
}

View File

@ -34,9 +34,10 @@ export class LoadState extends State<States> {
bootstrapInputs();
resources.set("engine-sprites", new Image());
resources.get<HTMLImageElement>("engine-sprites")!.src =
"/sprites/EngineSprites.png";
// This should be driven by a manifest
resources.set("snr:sprite/engine", new Image());
// resources.get<HTMLImageElement>("snr:sprite/engine")!.src =
// "/sprites/EngineSprites.png";
resources.ready().then(() => {
this.stateMachine.transitionTo(States.RUNNING);
});

View File

@ -6,7 +6,7 @@ import { getContextItem } from "../lib/context.ts";
export class Tender extends TrainCar {
constructor() {
const resources = getContextItem<ResourceManager>("resources");
super(25, resources.get<HTMLImageElement>("engine-sprites")!, 40, 20, {
super(25, resources.get<HTMLImageElement>("snr:sprite/engine")!, 40, 20, {
at: new Vector(80, 0),
width: 40,
height: 20,
@ -16,7 +16,7 @@ export class Tender extends TrainCar {
export class Tank extends TrainCar {
constructor() {
const resources = getContextItem<ResourceManager>("resources");
super(50, resources.get<HTMLImageElement>("engine-sprites")!, 70, 20, {
super(50, resources.get<HTMLImageElement>("snr:sprite/engine")!, 70, 20, {
at: new Vector(80, 20),
width: 70,
height: 20,
@ -26,7 +26,7 @@ export class Tank extends TrainCar {
export class YellowDumpCar extends TrainCar {
constructor() {
const resources = getContextItem<ResourceManager>("resources");
super(50, resources.get<HTMLImageElement>("engine-sprites")!, 70, 20, {
super(50, resources.get<HTMLImageElement>("snr:sprite/engine")!, 70, 20, {
at: new Vector(80, 40),
width: 70,
height: 20,
@ -36,7 +36,7 @@ export class YellowDumpCar extends TrainCar {
export class GrayDumpCar extends TrainCar {
constructor() {
const resources = getContextItem<ResourceManager>("resources");
super(50, resources.get<HTMLImageElement>("engine-sprites")!, 70, 20, {
super(50, resources.get<HTMLImageElement>("snr:sprite/engine")!, 70, 20, {
at: new Vector(80, 60),
width: 70,
height: 20,
@ -46,7 +46,7 @@ export class GrayDumpCar extends TrainCar {
export class NullCar extends TrainCar {
constructor() {
const resources = getContextItem<ResourceManager>("resources");
super(50, resources.get<HTMLImageElement>("engine-sprites")!, 70, 20, {
super(50, resources.get<HTMLImageElement>("snr:sprite/engine")!, 70, 20, {
at: new Vector(80, 80),
width: 70,
height: 20,

View File

@ -6,7 +6,7 @@ import { ResourceManager } from "../lib/resources.ts";
export class RedEngine extends TrainCar {
constructor() {
const resources = getContextItem<ResourceManager>("resources");
super(55, resources.get<HTMLImageElement>("engine-sprites")!, 80, 20, {
super(55, resources.get<HTMLImageElement>("snr:sprite/engine")!, 80, 20, {
at: new Vector(0, 60),
width: 80,
height: 20,
@ -16,7 +16,7 @@ export class RedEngine extends TrainCar {
export class PurpleEngine extends TrainCar {
constructor() {
const resources = getContextItem<ResourceManager>("resources");
super(55, resources.get<HTMLImageElement>("engine-sprites")!, 80, 20, {
super(55, resources.get<HTMLImageElement>("snr:sprite/engine")!, 80, 20, {
at: new Vector(0, 60),
width: 80,
height: 20,
@ -26,7 +26,7 @@ export class PurpleEngine extends TrainCar {
export class GreenEngine extends TrainCar {
constructor() {
const resources = getContextItem<ResourceManager>("resources");
super(55, resources.get<HTMLImageElement>("engine-sprites")!, 80, 20, {
super(55, resources.get<HTMLImageElement>("snr:sprite/engine")!, 80, 20, {
at: new Vector(0, 40),
width: 80,
height: 20,
@ -36,7 +36,7 @@ export class GreenEngine extends TrainCar {
export class GrayEngine extends TrainCar {
constructor() {
const resources = getContextItem<ResourceManager>("resources");
super(55, resources.get<HTMLImageElement>("engine-sprites")!, 80, 20, {
super(55, resources.get<HTMLImageElement>("snr:sprite/engine")!, 80, 20, {
at: new Vector(0, 20),
width: 80,
height: 20,
@ -46,7 +46,7 @@ export class GrayEngine extends TrainCar {
export class BlueEngine extends TrainCar {
constructor() {
const resources = getContextItem<ResourceManager>("resources");
super(55, resources.get<HTMLImageElement>("engine-sprites")!, 80, 20, {
super(55, resources.get<HTMLImageElement>("snr:sprite/engine")!, 80, 20, {
at: new Vector(0, 0),
width: 80,
height: 20,