UNPKG

5.51 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', { value: true });
4
5var resourcepack = require('@xmcl/resourcepack');
6var system = require('@xmcl/system');
7
8/**
9 * The model loader load the resource
10 */
11class ModelLoader {
12 /**
13 * @param manager The resource manager
14 */
15 constructor(manager) {
16 this.manager = manager;
17 /**
18 * All required texture raw resources
19 */
20 this.textures = {};
21 /**
22 * All the resolved model
23 */
24 this.models = {};
25 }
26 static findRealTexturePath(model, variantKey) {
27 let texturePath = model.textures[variantKey];
28 while (texturePath.startsWith("#")) {
29 const next = model.textures[texturePath.substring(1, texturePath.length)];
30 if (!next) {
31 return undefined;
32 }
33 texturePath = next;
34 }
35 return texturePath;
36 }
37 /**
38 * Load a model by search its parent. It will throw an error if the model is not found.
39 */
40 async loadModel(modelPath) {
41 const res = await this.manager.load(resourcepack.ResourceLocation.ofModelPath(modelPath));
42 if (!res) {
43 throw new Error(`Model ${modelPath} (${resourcepack.ResourceLocation.ofModelPath(modelPath)}) not found`);
44 }
45 const raw = JSON.parse(system.System.bufferToText(res.content));
46 if (!raw.textures) {
47 raw.textures = {};
48 }
49 if (raw.parent) {
50 const parentModel = await this.loadModel(raw.parent);
51 if (!parentModel) {
52 throw new Error(`Missing parent model ${raw.parent} for ${location.toString()}`);
53 }
54 if (!raw.elements) {
55 raw.elements = parentModel.elements;
56 }
57 if (!raw.ambientocclusion) {
58 raw.ambientocclusion = parentModel.ambientocclusion;
59 }
60 if (!raw.display) {
61 raw.display = parentModel.display;
62 }
63 if (!raw.overrides) {
64 raw.overrides = parentModel.overrides;
65 }
66 if (parentModel.textures) {
67 Object.assign(raw.textures, parentModel.textures);
68 }
69 }
70 raw.ambientocclusion = raw.ambientocclusion || false;
71 raw.overrides = raw.overrides || [];
72 delete raw.parent;
73 const model = raw;
74 this.models[modelPath] = model;
75 const reg = this.textures;
76 for (const variant of Object.keys(model.textures)) {
77 const texPath = ModelLoader.findRealTexturePath(model, variant);
78 if (texPath) {
79 const load = await this.manager.load(resourcepack.ResourceLocation.ofTexturePath(texPath));
80 if (load) {
81 reg[texPath] = load;
82 }
83 }
84 }
85 return model;
86 }
87}
88
89/**
90 * The resource manager. Design to be able to use in both nodejs and browser environment.
91 * @template T The type of the resource content. If you use this in node, it's probably `Buffer`. If you are in browser, it might be `string`. Just align this with your `ResourceSource`
92 */
93class ResourceManager {
94 constructor(list = []) {
95 this.list = list;
96 this.cache = {};
97 }
98 get allResourcePacks() { return this.list.map((l) => l.info); }
99 /**
100 * Add a new resource source to the end of the resource list.
101 */
102 async addResourcePack(resourcePack) {
103 let info;
104 try {
105 info = await resourcePack.info();
106 }
107 catch (_a) {
108 info = { pack_format: -1, description: "" };
109 }
110 const domains = await resourcePack.domains();
111 const wrapper = { info, source: resourcePack, domains };
112 this.list.push(wrapper);
113 }
114 /**
115 * Clear all cache
116 */
117 clearCache() { this.cache = {}; }
118 /**
119 * Clear all resource source and cache
120 */
121 clearAll() {
122 this.cache = {};
123 this.list.splice(0, this.list.length);
124 }
125 /**
126 * Swap the resource source priority.
127 */
128 swap(first, second) {
129 if (first >= this.list.length || first < 0 || second >= this.list.length || second < 0) {
130 throw new Error("Illegal index");
131 }
132 const fir = this.list[first];
133 this.list[first] = this.list[second];
134 this.list[second] = fir;
135 this.clearCache();
136 }
137 /**
138 * Invalidate the resource cache
139 */
140 invalidate(location) {
141 delete this.cache[`${location.domain}:${location.path}`];
142 }
143 /**
144 * Load the resource in that location. This will walk through current resource source list to load the resource.
145 * @param location The resource location
146 * @param urlOnly If true, it will force return uri, else it will return the normal resource content
147 */
148 async load(location, urlOnly = false) {
149 const cached = this.cache[`${location.domain}:${location.path}`];
150 if (cached) {
151 return cached;
152 }
153 for (const src of this.list) {
154 const loaded = await src.source.load(location, urlOnly);
155 if (!loaded) {
156 continue;
157 }
158 this.putCache(loaded);
159 return loaded;
160 }
161 return undefined;
162 }
163 putCache(res) {
164 this.cache[`${res.location.domain}:${res.location.path}`] = res;
165 }
166}
167
168exports.ModelLoader = ModelLoader;
169exports.ResourceManager = ResourceManager;