@csegames/camelot-unchained
Version:
Camelot Unchained Client Library
155 lines (128 loc) • 5.92 kB
text/typescript
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
import BuildingMaterial from './classes/BuildingMaterial';
import BuildingBlock from './classes/BuildingBlock';
import client from '../core/client';
import events from '../events';
const materialsLoaded: boolean = false;
let materialsRequested: boolean = false;
let numBlocksToLoad: number = 0;
const loadCallbacks: { (subs: BuildingMaterial[]): void }[] = [];
const materialsMap: { [key: number]: BuildingMaterial } = {};
const materialsList: BuildingMaterial[] = [];
const blocks: { [key: number]: BuildingBlock } = {};
// tslint:disable-next-line
const BLANK_IMAGE = 'iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuOWwzfk4AAALxSURBVHhe5dlLiI1xGMfx30pCRFkJCyXFYiRSsmBByWIipMiOWYiNjZSirCxcsrUZuUzKZSGxULNT5JJsKaXspJlcVsd7zDn1zPN+z5n38v/bPIvP5nee37//M73TnN5Rp9MJDcNIMIwEw0gwjATDSDCMBMNIMIwEw0gwjATDSDCMBMNIMIwEw8akHYXNhU1gBXaqkrYWuufvLKH5ijBsTDr470j2BjtVSNfdWdYe7FSEYSvShLmcdx47w0ij7gzrKnZqwLA1adpc0tuIHSItLnwzXesjdmrCsDVpxFzUm8QOke65rrUQOzVhmIR00VzWO4MdSxpzHWsXdhrAMBnptbm0tx47XdLawh8za13GTkMYJiMtMBf3nmKnS3rmZvve4XwLGCYlHTELeKdg/qybsZaX5lvCMDnpllnC+llYbea2mc+80VlnJoJhFtIXs4x118x8dp/1Jf29tzDMQtpiFvJOF+64rO8VnpcIhtlI58xiVa3CsxLBMCvpuVluLofxjIQwzEpaUvjdW3CYG9hPDMPspP1mUfIWexlg+F9I18zC3hh2MsAwu5lviN97y5IfhfnYTQzD7KT7vUWHeYjdxDDMSjphlpxL+atyYhhmI60xy1W1Ds9KBMNspJdmMWuy8Mhlfe/xrEQwzEK6YJbyFvVmvrq870rpvEQwTE7abpbxjpm5ve4za/esMxPBMDlpyixiPYHZQa/Ap0qzCWCYlDRulvBmHn1Lmlf4ZGasx6X5ljBMZvg/Sg5hp0va52at49hpCMMkpGXm0t4EdizpputYS7HTAIZJDH8jXH70vZkf4KCvyx+w0wCGrQ1/8TH40feko65rXcJOTRi2Im0wl/TGsTOM9MCdYY1gpwYMW5F+mQta3T+Fcz/6nrTSnOFNY6cGDBsb/GKzq/qj70kn3VnWbexUhGEj0gFzKa/+o+9JL9yZVuP/GWAYCYaRYBgJhpFgGAmGkWAYCYaRYBgJhpFgGAmGkWAYCYaRYBhHR38Boj2hpYws8QsAAAAASUVORK5CYII=';
function getBlockForShapeId(shapeId: number, blocks: BuildingBlock[]) {
for (const i in blocks) {
const block = blocks[i];
if (block.shapeId === shapeId) {
return block;
}
}
return blocks[0];
}
function getShapeIdFromBlockId(id: number) {
return id >> 21 & 31;
}
function getMaterialIdFromBlockId(id: number) {
return id >> 2 & 4095;
}
function recieveMaterials(subsRecieved: { [key: number]: string }) {
for (const i in subsRecieved) {
const id = parseInt(i, 10);
const material = new BuildingMaterial({
id,
icon: subsRecieved[i],
tags: [],
blocks: [],
} as BuildingMaterial);
materialsMap[id] = material;
materialsList.push(material);
}
client.RequestBlocks();
}
function recieveBlocks(blocksRecieved: any) {
for (const i in blocksRecieved) {
numBlocksToLoad++;
const id = parseInt(i, 10);
blocks[id] = {
id,
icon: blocksRecieved[i],
materialTags: [],
shapeTags: [],
} as BuildingBlock;
}
for (const i in blocksRecieved) {
const id = parseInt(i, 10);
client.RequestBlockTags(id);
}
}
function recieveBlockTags(id: number, tags: any) {
const block: BuildingBlock = blocks[id];
block.shapeId = getShapeIdFromBlockId(id);
block.shapeTags = tags.Shapes;
block.materialId = getMaterialIdFromBlockId(id);
block.materialTags = tags.Types;
const material = materialsMap[block.materialId];
if (material == null) {
console.log('unknown material ' + block.materialId + ' for block ' + id + '-' + tags.Types.join(','));
} else {
material.tags = tags.Types;
material.blocks.push(block);
}
if (--numBlocksToLoad === 0) {
// finished loading shapes and types
events.fire(events.buildingEventTopics.handlesBlocks, { materials: materialsList });
}
}
function getBlockForBlockId(blockid: number): BuildingBlock {
const matId = getMaterialIdFromBlockId(blockid);
const shapeId = getShapeIdFromBlockId(blockid);
const sub = materialsMap[matId];
if (sub == null)
return null;
// select by shape instead of by block id, it is more reliable, the block id sent back
// can have extra information stored in it
return getBlockForShapeId(shapeId, sub.blocks);
}
function getMaterialForBlockId(blockid: number): BuildingMaterial {
const matId = getMaterialIdFromBlockId(blockid);
return materialsMap[matId];
}
function requestBlockSelect(block: BuildingBlock): void {
client.ChangeBlockType(block.id);
}
// some blocks don't show up in the list retrieved by Request Substances or RequestBlocks
// make up the information based on the block id, so we can at least display the shape and material type to the user
// returning this information as a promise in case it is possible to request meta data on the material
function getMissingMaterial(blockid: number): { material: BuildingMaterial, block: BuildingBlock } {
const block: BuildingBlock = new BuildingBlock({
id: blockid,
shapeId: getShapeIdFromBlockId(blockid),
materialId: getMaterialIdFromBlockId(blockid),
icon: BLANK_IMAGE,
} as BuildingBlock);
blocks[block.id] = block;
const material: BuildingMaterial =
new BuildingMaterial({ id: block.materialId, blocks: [block], icon: BLANK_IMAGE } as BuildingMaterial);
materialsMap[material.id] = material;
materialsList.push(material);
events.fire(events.buildingEventTopics.handlesBlocks, { materials: materialsList });
return { material, block };
}
function requestMaterials() {
if (!materialsRequested) {
materialsRequested = false;
client.OnReceiveSubstances(recieveMaterials);
client.OnReceiveBlocks(recieveBlocks);
client.OnReceiveBlockTags(recieveBlockTags);
client.RequestSubstances();
}
}
export * from './blueprints';
export * from './building-actions';
export { requestMaterials, getMissingMaterial, requestBlockSelect, getBlockForBlockId, getMaterialForBlockId };