resource manager overhaul
3
.gitignore
vendored
@ -23,3 +23,6 @@ dist-ssr
|
|||||||
*.njsproj
|
*.njsproj
|
||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
|
|
||||||
|
# Packed devtools
|
||||||
|
devtools.zip
|
||||||
|
@ -3,7 +3,8 @@
|
|||||||
"dev": "deno run -A --node-modules-dir npm:vite",
|
"dev": "deno run -A --node-modules-dir npm:vite",
|
||||||
"build": "deno run -A --node-modules-dir npm:vite build",
|
"build": "deno run -A --node-modules-dir npm:vite build",
|
||||||
"preview": "deno run -A --node-modules-dir npm:vite preview",
|
"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": {
|
"compilerOptions": {
|
||||||
"lib": [
|
"lib": [
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
{
|
{
|
||||||
"manifest_version": 2,
|
"manifest_version": 2,
|
||||||
"name": "Context Stack DevTools",
|
"name": "SNR DevTools",
|
||||||
"version": "1.0",
|
"version": "1.0",
|
||||||
"description": "A devtools panel to view and edit context stack values.",
|
"description": "A devtools panel to view and edit context stack values.",
|
||||||
|
"author": "Emmaline Autumn",
|
||||||
"devtools_page": "devtools.html",
|
"devtools_page": "devtools.html",
|
||||||
"background": {
|
"background": {
|
||||||
"scripts": [
|
"scripts": [
|
||||||
@ -24,5 +25,13 @@
|
|||||||
"devtools",
|
"devtools",
|
||||||
"tabs",
|
"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 {
|
export class ResourceManager {
|
||||||
private resources: Map<string, unknown> = new Map();
|
private resources: Map<string, unknown> = new Map();
|
||||||
private statuses: Map<string, Promise<boolean>> = 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)) {
|
if (!this.resources.has(name)) {
|
||||||
throw new Error(`Resource ${name} not found`);
|
throw new Error(`Resource ${name} not found`);
|
||||||
}
|
}
|
||||||
return this.resources.get(name) as T;
|
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 (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(
|
this.statuses.set(
|
||||||
name,
|
name,
|
||||||
new Promise((resolve) => {
|
new Promise((resolve) => {
|
||||||
@ -36,3 +59,28 @@ export class ResourceManager {
|
|||||||
return Promise.all(Array.from(this.statuses.values()));
|
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();
|
bootstrapInputs();
|
||||||
|
|
||||||
resources.set("engine-sprites", new Image());
|
// This should be driven by a manifest
|
||||||
resources.get<HTMLImageElement>("engine-sprites")!.src =
|
resources.set("snr:sprite/engine", new Image());
|
||||||
"/sprites/EngineSprites.png";
|
// resources.get<HTMLImageElement>("snr:sprite/engine")!.src =
|
||||||
|
// "/sprites/EngineSprites.png";
|
||||||
resources.ready().then(() => {
|
resources.ready().then(() => {
|
||||||
this.stateMachine.transitionTo(States.RUNNING);
|
this.stateMachine.transitionTo(States.RUNNING);
|
||||||
});
|
});
|
||||||
|
@ -6,7 +6,7 @@ import { getContextItem } from "../lib/context.ts";
|
|||||||
export class Tender extends TrainCar {
|
export class Tender extends TrainCar {
|
||||||
constructor() {
|
constructor() {
|
||||||
const resources = getContextItem<ResourceManager>("resources");
|
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),
|
at: new Vector(80, 0),
|
||||||
width: 40,
|
width: 40,
|
||||||
height: 20,
|
height: 20,
|
||||||
@ -16,7 +16,7 @@ export class Tender extends TrainCar {
|
|||||||
export class Tank extends TrainCar {
|
export class Tank extends TrainCar {
|
||||||
constructor() {
|
constructor() {
|
||||||
const resources = getContextItem<ResourceManager>("resources");
|
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),
|
at: new Vector(80, 20),
|
||||||
width: 70,
|
width: 70,
|
||||||
height: 20,
|
height: 20,
|
||||||
@ -26,7 +26,7 @@ export class Tank extends TrainCar {
|
|||||||
export class YellowDumpCar extends TrainCar {
|
export class YellowDumpCar extends TrainCar {
|
||||||
constructor() {
|
constructor() {
|
||||||
const resources = getContextItem<ResourceManager>("resources");
|
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),
|
at: new Vector(80, 40),
|
||||||
width: 70,
|
width: 70,
|
||||||
height: 20,
|
height: 20,
|
||||||
@ -36,7 +36,7 @@ export class YellowDumpCar extends TrainCar {
|
|||||||
export class GrayDumpCar extends TrainCar {
|
export class GrayDumpCar extends TrainCar {
|
||||||
constructor() {
|
constructor() {
|
||||||
const resources = getContextItem<ResourceManager>("resources");
|
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),
|
at: new Vector(80, 60),
|
||||||
width: 70,
|
width: 70,
|
||||||
height: 20,
|
height: 20,
|
||||||
@ -46,7 +46,7 @@ export class GrayDumpCar extends TrainCar {
|
|||||||
export class NullCar extends TrainCar {
|
export class NullCar extends TrainCar {
|
||||||
constructor() {
|
constructor() {
|
||||||
const resources = getContextItem<ResourceManager>("resources");
|
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),
|
at: new Vector(80, 80),
|
||||||
width: 70,
|
width: 70,
|
||||||
height: 20,
|
height: 20,
|
||||||
|
@ -6,7 +6,7 @@ import { ResourceManager } from "../lib/resources.ts";
|
|||||||
export class RedEngine extends TrainCar {
|
export class RedEngine extends TrainCar {
|
||||||
constructor() {
|
constructor() {
|
||||||
const resources = getContextItem<ResourceManager>("resources");
|
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),
|
at: new Vector(0, 60),
|
||||||
width: 80,
|
width: 80,
|
||||||
height: 20,
|
height: 20,
|
||||||
@ -16,7 +16,7 @@ export class RedEngine extends TrainCar {
|
|||||||
export class PurpleEngine extends TrainCar {
|
export class PurpleEngine extends TrainCar {
|
||||||
constructor() {
|
constructor() {
|
||||||
const resources = getContextItem<ResourceManager>("resources");
|
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),
|
at: new Vector(0, 60),
|
||||||
width: 80,
|
width: 80,
|
||||||
height: 20,
|
height: 20,
|
||||||
@ -26,7 +26,7 @@ export class PurpleEngine extends TrainCar {
|
|||||||
export class GreenEngine extends TrainCar {
|
export class GreenEngine extends TrainCar {
|
||||||
constructor() {
|
constructor() {
|
||||||
const resources = getContextItem<ResourceManager>("resources");
|
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),
|
at: new Vector(0, 40),
|
||||||
width: 80,
|
width: 80,
|
||||||
height: 20,
|
height: 20,
|
||||||
@ -36,7 +36,7 @@ export class GreenEngine extends TrainCar {
|
|||||||
export class GrayEngine extends TrainCar {
|
export class GrayEngine extends TrainCar {
|
||||||
constructor() {
|
constructor() {
|
||||||
const resources = getContextItem<ResourceManager>("resources");
|
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),
|
at: new Vector(0, 20),
|
||||||
width: 80,
|
width: 80,
|
||||||
height: 20,
|
height: 20,
|
||||||
@ -46,7 +46,7 @@ export class GrayEngine extends TrainCar {
|
|||||||
export class BlueEngine extends TrainCar {
|
export class BlueEngine extends TrainCar {
|
||||||
constructor() {
|
constructor() {
|
||||||
const resources = getContextItem<ResourceManager>("resources");
|
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),
|
at: new Vector(0, 0),
|
||||||
width: 80,
|
width: 80,
|
||||||
height: 20,
|
height: 20,
|
||||||
|