resource manager overhaul
3
.gitignore
vendored
@ -23,3 +23,6 @@ dist-ssr
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
# Packed devtools
|
||||
devtools.zip
|
||||
|
@ -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": [
|
||||
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
@ -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("/") };
|
||||
}
|
||||
|
@ -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);
|
||||
});
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|