833 lines
19 KiB
JavaScript
833 lines
19 KiB
JavaScript
var neighborData = [
|
|
{
|
|
"position": [-1, 0, 0],
|
|
"corners": [
|
|
[0, 0, 0, 0, 0],
|
|
[0, 0, 1, 1, 0],
|
|
[0, 1, 0, 0, 1],
|
|
[0, 1, 1, 1, 1]
|
|
]
|
|
},
|
|
{
|
|
"position": [1, 0, 0],
|
|
"corners": [
|
|
[1, 0, 1, 0, 0],
|
|
[1, 0, 0, 1, 0],
|
|
[1, 1, 1, 0, 1],
|
|
[1, 1, 0, 1, 1]
|
|
]
|
|
},
|
|
{
|
|
"position": [0, -1, 0],
|
|
"corners": [
|
|
[0, 0, 0, 0, 1],
|
|
[1, 0, 0, 1, 1],
|
|
[0, 0, 1, 0, 0],
|
|
[1, 0, 1, 1, 0]
|
|
]
|
|
},
|
|
{
|
|
"position": [0, 1, 0],
|
|
"corners": [
|
|
[0, 1, 1, 0, 0],
|
|
[1, 1, 1, 1, 0],
|
|
[0, 1, 0, 0, 1],
|
|
[1, 1, 0, 1, 1]
|
|
]
|
|
},
|
|
{
|
|
"position": [0, 0, -1],
|
|
"corners": [
|
|
[1, 0, 0, 0, 0],
|
|
[0, 0, 0, 1, 0],
|
|
[1, 1, 0, 0, 1],
|
|
[0, 1, 0, 1, 1]
|
|
]
|
|
},
|
|
{
|
|
"position": [0, 0, 1],
|
|
"corners": [
|
|
[0, 0, 1, 0, 0],
|
|
[1, 0, 1, 1, 0],
|
|
[0, 1, 1, 0, 1],
|
|
[1, 1, 1, 1, 1]
|
|
]
|
|
}
|
|
];
|
|
|
|
var timePalette = {
|
|
"21600": 0x081632, // Marine Blue (#081632)
|
|
"25200": 0xFF7656,
|
|
"28800": 0xBDE4F5,
|
|
"61200": 0xBDE4F5,
|
|
"64800": 0xFA88AF,
|
|
"68400": 0x081632
|
|
};
|
|
|
|
var textureData = {
|
|
"resolution": [16, 16],
|
|
"size": [256, 256],
|
|
"textures": {
|
|
|
|
}
|
|
};
|
|
|
|
class World extends global.three.Scene {
|
|
constructor (parameters) {
|
|
super();
|
|
|
|
this.generator = parameters.generator || "flat";
|
|
|
|
this.chunks = new global.Map();
|
|
this.chunkSize = parameters.chunkSize || [16, 16, 16];
|
|
|
|
this.background = new global.three.Color(0xBDE4F5);
|
|
|
|
this.ambientLight = new global.three.AmbientLight(0xFFFFFF, 1);
|
|
this.directionalLight = new global.three.DirectionalLight(0xFFFFFF, 1);
|
|
|
|
this.directionalLight.position.set(1, 1, 1);
|
|
|
|
this.add(this.ambientLight);
|
|
this.add(this.directionalLight);
|
|
|
|
this.worker = new global.Worker("./modules/world_worker.js");
|
|
|
|
this.callbackObjects = {};
|
|
|
|
global.core.on("resourcepack-load", (function (pack) {
|
|
var textureData = {
|
|
"resolution": pack.meta.textures["block-atlas"].size,
|
|
"size": pack.meta.textures["block-atlas"].totalSize,
|
|
"textures": pack.meta.textures
|
|
};
|
|
|
|
this.worker.postMessage({
|
|
"command": "config",
|
|
"arguments": {
|
|
"textureData": textureData
|
|
}
|
|
});
|
|
|
|
this.chunks.forEach((chunk, chunkID) => {
|
|
chunk.material.map = pack.textures.get("block-atlas").map;
|
|
});
|
|
}).bind(this));
|
|
|
|
var resourcePackNames = Object.keys(global.resourcePacks);
|
|
if (resourcePackNames.length > 0) {
|
|
var pack = global.resourcePacks[resourcePackNames[0]];
|
|
|
|
var textureData = {
|
|
"resolution": pack.meta.textures["block-atlas"].size,
|
|
"size": pack.meta.textures["block-atlas"].totalSize,
|
|
"textures": pack.meta.textures
|
|
};
|
|
|
|
this.worker.postMessage({
|
|
"command": "config",
|
|
"arguments": {
|
|
"world": {
|
|
"chunkSize": this.chunkSize
|
|
},
|
|
"textureData": textureData
|
|
}
|
|
});
|
|
}
|
|
|
|
this.worker.postMessage({
|
|
"command": "create-world",
|
|
"arguments": {
|
|
"uuid": this.uuid
|
|
}
|
|
});
|
|
|
|
this.worker.onmessage = (function (message) {
|
|
var event = message.data["event"];
|
|
var data = message.data["data"];
|
|
|
|
var callbackID = data["callbackID"];
|
|
|
|
var callbackObject = this.callbackObjects[callbackID];
|
|
|
|
switch (event) {
|
|
case "generated":
|
|
var newChunk = new Chunk(this.chunkSize, this);
|
|
|
|
for (var b = 0; b < data.blocks.length; b++) {
|
|
var block = data.blocks[b];
|
|
|
|
if (!block) continue;
|
|
newChunk.blocks[b] = block;
|
|
}
|
|
|
|
this.setChunk(newChunk, callbackObject.position);
|
|
callbackObject.resolve(newChunk);
|
|
break;
|
|
case "constructed":
|
|
var properties = data.properties;
|
|
var chunk = callbackObject.chunk;
|
|
|
|
chunk.geometry.setAttribute("position", new global.three.Float32BufferAttribute(properties["positions"], 3));
|
|
chunk.geometry.setAttribute("normal", new global.three.Float32BufferAttribute(properties["normals"], 3));
|
|
chunk.geometry.setAttribute("uv", new global.three.Float32BufferAttribute(properties["uvs"], 2));
|
|
chunk.geometry.setIndex(properties["indexes"]);
|
|
chunk.geometry.computeBoundingSphere();
|
|
|
|
var resourcePackNames = Object.keys(global.resourcePacks);
|
|
if (resourcePackNames.length > 0) {
|
|
var pack = global.resourcePacks[resourcePackNames[0]];
|
|
|
|
chunk.material.map = pack.textures.get("block-atlas").map;
|
|
}
|
|
|
|
// this.worker.postMessage({
|
|
// "command": "set-body",
|
|
// "arguments": {
|
|
// "uuid": chunk.uuid,
|
|
// "position": [
|
|
// chunk.position.x,
|
|
// chunk.position.y,
|
|
// chunk.position.z
|
|
// ],
|
|
// "shape": {
|
|
// "vertices": chunk.geometry.attributes["position"].array,
|
|
// "indices": chunk.geometry.index.array
|
|
// },
|
|
// "type": "static"
|
|
// }
|
|
// });
|
|
|
|
callbackObject.resolve(chunk);
|
|
break;
|
|
case "simulation-stepped":
|
|
for (var uuid in data.updates) {
|
|
if (data.updates.hasOwnProperty(uuid)) {
|
|
var meshUpdate = data.updates[uuid];
|
|
|
|
var mesh = this.children.find(function (m) {
|
|
return m.uuid === uuid;
|
|
});
|
|
|
|
if (!mesh) continue;
|
|
|
|
mesh.position.set(
|
|
meshUpdate.position[0],
|
|
meshUpdate.position[1],
|
|
meshUpdate.position[2]
|
|
);
|
|
|
|
mesh.quaternion.set(
|
|
meshUpdate.quaternion[0],
|
|
meshUpdate.quaternion[1],
|
|
meshUpdate.quaternion[2],
|
|
meshUpdate.quaternion[3]
|
|
);
|
|
}
|
|
}
|
|
|
|
callbackObject.resolve(data.updates);
|
|
break;
|
|
default:
|
|
|
|
}
|
|
}).bind(this);
|
|
}
|
|
addChunk (chunk) {
|
|
if (!chunk) return new Error("First argument is not a chunk. ");
|
|
if (!(chunk instanceof Chunk)) return new Error("First argument is not an instance of Chunk. ");
|
|
|
|
this.add(chunk);
|
|
|
|
var blockIndices = [];
|
|
|
|
for (var b = 0; b < chunk.blocks.length; b++) {
|
|
if (chunk.blocks[b]) blockIndices.push(b);
|
|
}
|
|
|
|
// this.worker.postMessage({
|
|
// "command": "put-voxels",
|
|
// "arguments": {
|
|
// "worldUUID": this.uuid,
|
|
// "chunkUUID": chunk.uuid,
|
|
// "chunkPosition": chunk.position,
|
|
// "indices": blockIndices
|
|
// }
|
|
// });
|
|
|
|
|
|
return chunk;
|
|
}
|
|
setChunk (chunk, position) {
|
|
if (!chunk) return new Error("First argument is not a chunk. ");
|
|
if (!(chunk instanceof Chunk)) return new Error("First argument is not an instance of Chunk. ");
|
|
if (!position) return new Error("Second argument is not a position. ");
|
|
|
|
var worldPosition = [
|
|
this.chunkSize[0] * position[0],
|
|
this.chunkSize[1] * position[1],
|
|
this.chunkSize[2] * position[2]
|
|
];
|
|
|
|
if (this.chunks.has(position.join(":"))) {
|
|
var oldChunk = this.chunks.get(position.join(":"));
|
|
|
|
var voxelIndices = [];
|
|
|
|
for (var b = 0; b < oldChunk.blocks.length; b++) {
|
|
if (oldChunk.blocks[b]) voxelIndices.push(b);
|
|
}
|
|
|
|
// this.worker.postMessage({
|
|
// "command": "remove-voxels",
|
|
// "arguments": {
|
|
// "worldUUID": this.uuid,
|
|
// "chunkUUID": oldChunk.uuid
|
|
// }
|
|
// });
|
|
}
|
|
|
|
var blockIndices = [];
|
|
|
|
for (var b = 0; b < chunk.blocks.length; b++) {
|
|
if (chunk.blocks[b]) blockIndices.push(b);
|
|
}
|
|
|
|
// this.worker.postMessage({
|
|
// "command": "put-voxels",
|
|
// "arguments": {
|
|
// "worldUUID": this.uuid,
|
|
// "chunkUUID": chunk.uuid,
|
|
// "chunkPosition": position,
|
|
// "indices": blockIndices
|
|
// }
|
|
// });
|
|
|
|
chunk.position.set(
|
|
worldPosition[0],
|
|
worldPosition[1],
|
|
worldPosition[2]
|
|
);
|
|
|
|
// this.worker.postMessage({
|
|
// "command": "set-body",
|
|
// "arguments": {
|
|
// "uuid": chunk.uuid,
|
|
// "position": worldPosition
|
|
// }
|
|
// });
|
|
|
|
return this.chunks.set(position.join(":"), chunk);
|
|
}
|
|
addEntity (entity) {
|
|
if (!entity) return new Error("First argument is not an entity. ");
|
|
if (!(entity instanceof Entity)) return new Error("First argument is not an instance of Entity. ");
|
|
|
|
this.add(entity);
|
|
|
|
this.worker.postMessage({
|
|
"command": "add-body",
|
|
"arguments": {
|
|
"worldUUID": this.uuid,
|
|
"bodyUUID": entity.uuid,
|
|
"type": "dynamic"
|
|
}
|
|
});
|
|
|
|
return entity;
|
|
}
|
|
removeChunk (position) {
|
|
if (!position) return new Error("First argument is not a position. ");
|
|
|
|
if (this.chunks.has(position.join(":"))) return this.chunks.delete(position.join(":"));
|
|
return false;
|
|
}
|
|
generateChunk (position, data) {
|
|
return new Promise((function (resolve, reject) {
|
|
var callbackID = "G" + Math.round(Math.random() * 65536);
|
|
|
|
this.callbackObjects[callbackID] = {
|
|
"position": position,
|
|
"resolve": resolve,
|
|
"reject": reject
|
|
};
|
|
|
|
this.worker.postMessage({
|
|
"command": "generate",
|
|
"arguments": {
|
|
"callbackID": callbackID,
|
|
"position": position,
|
|
"generator": this.generator
|
|
}
|
|
});
|
|
}).bind(this));
|
|
}
|
|
constructChunk (position) {
|
|
return new Promise((function (resolve, reject) {
|
|
var callbackID = "C" + Math.round(Math.random() * 65536);
|
|
|
|
this.callbackObjects[callbackID] = {
|
|
"chunk": this.chunks.get(position.join(":")),
|
|
"position": position,
|
|
"resolve": resolve,
|
|
"reject": reject
|
|
};
|
|
|
|
var neighbors = [];
|
|
|
|
for (var n = 0; n < neighborData.length; n++) {
|
|
var neighborPosition = addPositions(position, neighborData[n].position);
|
|
var neighborKey = neighborPosition.join(":");
|
|
|
|
if (this.chunks.has(neighborKey)) {
|
|
neighbors.push(this.chunks.get(neighborKey).toJSON());
|
|
} else {
|
|
neighbors.push(null);
|
|
}
|
|
}
|
|
|
|
this.worker.postMessage({
|
|
"command": "construct",
|
|
"arguments": {
|
|
"callbackID": callbackID,
|
|
"position": position,
|
|
"chunk": this.chunks.get(position.join(":")).toJSON(),
|
|
"neighbors": neighbors
|
|
}
|
|
});
|
|
}).bind(this));
|
|
}
|
|
stepSimulation (delta) {
|
|
return new Promise((function (resolve, reject) {
|
|
var callbackID = "C" + Math.round(Math.random() * 65536);
|
|
|
|
this.callbackObjects[callbackID] = {
|
|
"resolve": resolve,
|
|
"reject": reject
|
|
};
|
|
|
|
this.worker.postMessage({
|
|
"command": "step-simulation",
|
|
"arguments": {
|
|
"callbackID": callbackID,
|
|
"uuid": this.uuid,
|
|
"delta": delta
|
|
}
|
|
});
|
|
}).bind(this));
|
|
}
|
|
toJSON () {
|
|
var chunksObject = {};
|
|
|
|
this.chunks.forEach(function (value, key) {
|
|
chunksObject[key] = value;
|
|
});
|
|
|
|
return {
|
|
"generator": this.generator,
|
|
"chunks": chunksObject
|
|
};
|
|
}
|
|
}
|
|
|
|
class Chunk extends global.three.Mesh {
|
|
constructor (size = [16, 16, 16], world) {
|
|
super(
|
|
new global.three.BufferGeometry(),
|
|
new global.three.MeshStandardMaterial({
|
|
"side": global.three.DoubleSide,
|
|
"transparent": true,
|
|
"alphaTest": 0.5
|
|
})
|
|
);
|
|
|
|
this._size = size;
|
|
this.blocks = new global.Array(size[0] * size[1] * size[2]);
|
|
|
|
if (world instanceof World) {
|
|
this.world = world;
|
|
// world.worker.postMessage({
|
|
// "command": "create-body",
|
|
// "arguments": {
|
|
// "uuid": this.uuid,
|
|
// "type": "static"
|
|
// }
|
|
// });
|
|
}
|
|
}
|
|
get size () {
|
|
return this._size;
|
|
}
|
|
setBlock (position, block) {
|
|
if (!position) return new Error("First argument is not a position. ");
|
|
if (!block) return new Error("Second argument is not a block. ");
|
|
if (!(block instanceof Block)) return new Error("Second argument is not an instance of Block. ");
|
|
|
|
var blockIndex = computeBlockIndex(this.size, position);
|
|
|
|
if (this.world) {
|
|
// this.world.worker.postMessage({
|
|
// "command": "remove-body",
|
|
// "arguments": {
|
|
// "uuid": this.uuid + ";" + position.join(":")
|
|
// }
|
|
// });
|
|
if (!this.blocks[blockIndex]) {
|
|
this.world.worker.postMessage({
|
|
"command": "create-body",
|
|
"arguments": {
|
|
"uuid": this.uuid + ";" + blockIndex,
|
|
"type": "static",
|
|
"position": [
|
|
this.position.x + position[0],
|
|
this.position.y + position[1],
|
|
this.position.z + position[2],
|
|
]
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
this.blocks[blockIndex] = block;
|
|
}
|
|
removeBlock (position) {
|
|
if (!position) return new Error("First argument is not a position. ");
|
|
|
|
var blockIndex = computeBlockIndex(this.size, position);
|
|
|
|
delete this.blocks[blockIndex];
|
|
|
|
if (this.world) {
|
|
this.world.worker.postMessage({
|
|
"command": "remove-body",
|
|
"arguments": {
|
|
"worldUUID": this.world.uuid,
|
|
"bodyUUID": this.uuid + ";" + blockIndex
|
|
}
|
|
});
|
|
this.world.worker.postMessage({
|
|
"command": "destroy-body",
|
|
"arguments": {
|
|
"uuid": this.uuid + ";" + blockIndex
|
|
}
|
|
});
|
|
}
|
|
}
|
|
toJSON () {
|
|
return {
|
|
"size": this.size,
|
|
"blocks": this.blocks
|
|
};
|
|
}
|
|
}
|
|
|
|
class Block extends global.Array {
|
|
constructor (type, data = {}) {
|
|
super();
|
|
|
|
if (!type) return new Error("Block type must be non-null. ");
|
|
this[0] = type;
|
|
this[1] = new global.Map();
|
|
|
|
for (var key in data) {
|
|
if (data.hasOwnProperty(key)) {
|
|
var value = data[key];
|
|
|
|
this[1].set(key, value);
|
|
}
|
|
}
|
|
}
|
|
get type () {
|
|
return this[0];
|
|
}
|
|
get tags () {
|
|
return this[1];
|
|
}
|
|
setTagValue (tag, value) {
|
|
return this[1].set(tag, value);
|
|
}
|
|
removeTagValue (tag) {
|
|
if (this[1].has(tag)) return this[1].delete(tag);
|
|
return false;
|
|
}
|
|
toJSON () {
|
|
var tagsObject = {};
|
|
|
|
this[1].forEach(function (value, key) {
|
|
tagsObject[key] = value;
|
|
});
|
|
|
|
return {
|
|
"type": this[0],
|
|
"tags": tagsObject
|
|
};
|
|
}
|
|
}
|
|
|
|
class Entity extends global.three.Mesh {
|
|
constructor (type, world) {
|
|
super(
|
|
new global.three.BoxBufferGeometry(0.8, 0.8, 0.8),
|
|
new global.three.MeshStandardMaterial({
|
|
"side": global.three.DoubleSide,
|
|
"transparent": true,
|
|
"alphaTest": 0.5,
|
|
"opacity": 0.0,
|
|
"wireframe": true
|
|
})
|
|
);
|
|
|
|
this.type = type;
|
|
this.parts = {};
|
|
|
|
this._texture = null;
|
|
|
|
for (var p = 0; p < global.resourcePacks.length; p++) {
|
|
var pack = global.resourcePacks[p];
|
|
|
|
if (pack.models.has(this.type) && Object.keys(this.parts).length < 1) {
|
|
this.model = pack.models.get(this.type);
|
|
}
|
|
if (pack.textures.has(this.type) && !this.material.map) {
|
|
this.texture = pack.textures.get(this.type).map;
|
|
}
|
|
}
|
|
|
|
if (world instanceof World) {
|
|
world.worker.postMessage({
|
|
"command": "create-body",
|
|
"arguments": {
|
|
"uuid": this.uuid,
|
|
"mass": 16,
|
|
"shape": {
|
|
"vertices": this.geometry.attributes["position"].array,
|
|
"indices": this.geometry.index.array
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
get texture () {
|
|
if (this._texture) return this._texture;
|
|
|
|
for (var partName in this.parts) {
|
|
if (this.parts.hasOwnProperty(partName)) {
|
|
var part = this.parts[partName];
|
|
|
|
if (!part.material || !part.material.map) continue;
|
|
return part.material.map;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
set texture (texture) {
|
|
this._texture = texture;
|
|
|
|
for (var partName in this.parts) {
|
|
if (this.parts.hasOwnProperty(partName)) {
|
|
var part = this.parts[partName];
|
|
|
|
if (part.isGroup) continue;
|
|
|
|
part.material.map = texture;
|
|
}
|
|
}
|
|
}
|
|
set model (model) {
|
|
this.geometry = new global.three.BoxBufferGeometry(
|
|
model.hitbox[0],
|
|
model.hitbox[1],
|
|
model.hitbox[2]
|
|
);
|
|
|
|
for (var partName in model.parts) {
|
|
if (model.parts.hasOwnProperty(partName)) {
|
|
var part = model.parts[partName];
|
|
|
|
let partObject;
|
|
|
|
switch (part.type) {
|
|
case "group":
|
|
partObject = new global.three.Group();
|
|
break;
|
|
case "geometry":
|
|
partObject = new global.three.Mesh(
|
|
new global.three.BoxBufferGeometry(
|
|
part.geometry[0],
|
|
part.geometry[1],
|
|
part.geometry[2]
|
|
),
|
|
new global.three.MeshStandardMaterial({
|
|
"side": global.three.FrontSide,
|
|
"transparent": true,
|
|
"alphaTest": 0.5,
|
|
"map": this.texture
|
|
})
|
|
);
|
|
|
|
if ("uvMap" in part) {
|
|
var uvArray = partObject.geometry.attributes["uv"].array;
|
|
|
|
for (var f = 0; f < part.uvMap.length; f++) {
|
|
var faceMap = part.uvMap[f];
|
|
|
|
var firstUVIndex = f * 8;
|
|
|
|
uvArray[firstUVIndex + 0] = faceMap[0][0];
|
|
uvArray[firstUVIndex + 1] = faceMap[1][1];
|
|
uvArray[firstUVIndex + 2] = faceMap[1][0];
|
|
uvArray[firstUVIndex + 3] = faceMap[1][1];
|
|
uvArray[firstUVIndex + 4] = faceMap[0][0];
|
|
uvArray[firstUVIndex + 5] = faceMap[0][1];
|
|
uvArray[firstUVIndex + 6] = faceMap[1][0];
|
|
uvArray[firstUVIndex + 7] = faceMap[0][1];
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
|
|
}
|
|
|
|
if (part.position) partObject.position.set(
|
|
part.position[0],
|
|
part.position[1],
|
|
part.position[2]
|
|
);
|
|
|
|
var modelPart = this.parts[partName] = partObject;
|
|
}
|
|
}
|
|
|
|
for (var partName in model.parts) {
|
|
if (model.parts.hasOwnProperty(partName)) {
|
|
var part = model.parts[partName];
|
|
|
|
if (part.children) {
|
|
for (var c = 0; c < part.children.length; c++) {
|
|
this.parts[partName].add(this.parts[part.children[c]]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ("root" in this.parts) this.add(this.parts["root"]);
|
|
}
|
|
setPosition (position) {
|
|
this.position.set(
|
|
position[0],
|
|
position[1],
|
|
position[2]
|
|
);
|
|
|
|
if (this.parent instanceof World) {
|
|
this.parent.worker.postMessage({
|
|
"command": "set-body",
|
|
"arguments": {
|
|
"uuid": this.uuid,
|
|
"position": position
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
var computeBlockIndex = function (chunkSize, blockPosition) {
|
|
var x = blockPosition[0] % chunkSize[0];
|
|
var z = blockPosition[2] % chunkSize[2];
|
|
var y = blockPosition[1] % chunkSize[1];
|
|
|
|
return (x * (chunkSize[1] * chunkSize[2])) + y + (z * chunkSize[1]);
|
|
};
|
|
|
|
var computeBlockPosition = function (chunkSize, blockIndex) {
|
|
var blockPosition = [0, 0, 0];
|
|
var subtractedIndex = 0 + blockIndex;
|
|
|
|
blockPosition[1] = subtractedIndex % chunkSize[1];
|
|
subtractedIndex -= blockPosition[1];
|
|
|
|
blockPosition[2] = (subtractedIndex / chunkSize[1]) % chunkSize[2];
|
|
subtractedIndex -= blockPosition[2] * chunkSize[1];
|
|
|
|
blockPosition[0] = (subtractedIndex / (chunkSize[1] * chunkSize[2])) % chunkSize[0];
|
|
subtractedIndex -= blockPosition[0] * chunkSize[0];
|
|
|
|
return blockPosition;
|
|
};
|
|
|
|
var splitRGBComponents = function (hex) {
|
|
var subtracted = hex;
|
|
|
|
var blue = hex % 0x100;
|
|
subtracted -= blue;
|
|
|
|
var green = (subtracted / 0x100) % 0x100;
|
|
subtracted -= subtracted * 0x100;
|
|
|
|
var red = (subtracted / 0x10000) % 0x100;
|
|
subtracted -= subtracted * 0x10000;
|
|
|
|
return [red, green, blue];
|
|
};
|
|
|
|
var computeTimeColor = function (palette, time) {
|
|
var times = Object.keys(palette);
|
|
if (times.length == 1) return palette[times[0]];
|
|
|
|
var seconds = ((time[0] * 3600) + (time[1] * 60) + time[2]);
|
|
var timesBefore = times.filter(function (timeFloat) {
|
|
return parseFloat(timeFloat) <= seconds;
|
|
});
|
|
var timesAfter = times.filter(function (timeFloat) {
|
|
return parseFloat(timeFloat) > seconds;
|
|
});
|
|
let startTime, startTimeFloat;
|
|
let endTime, endTimeFloat;
|
|
if (timesBefore.length < 1) {
|
|
startTime = times[times.length - 1];
|
|
startTimeFloat = parseFloat(times[times.length - 1]) - (24 * 3600);
|
|
}
|
|
if (timesAfter.length < 1) {
|
|
endTime = times[0];
|
|
endTimeFloat = (24 * 3600) + parseFloat(times[0]);
|
|
}
|
|
|
|
var startComponents = splitRGBComponents(palette[startTime]);
|
|
var endComponents = splitRGBComponents(palette[endTime]);
|
|
|
|
var redDiff = endComponents[0] - startComponents[0];
|
|
var greenDiff = endComponents[1] - startComponents[1];
|
|
var blueDiff = endComponents[2] - startComponents[2];
|
|
|
|
progress = (seconds - startTimeFloat) / (endTimeFloat - startTimeFloat);
|
|
|
|
return (Math.round(startComponents[0] + (progress * redDiff)) * 65536)
|
|
+ (Math.round((startComponents[1] + (progress * greenDiff))) * 256)
|
|
+ Math.round(startComponents[2] + (progress * blueDiff));
|
|
};
|
|
|
|
var addPositions = function (positionA, positionB) {
|
|
var position = new Array(positionA.length);
|
|
|
|
for (var p = 0; p < position.length; p++) {
|
|
position[p] = positionA[p] + positionB[p];
|
|
}
|
|
|
|
return position;
|
|
};
|
|
|
|
module.exports = {
|
|
"World": World,
|
|
"Chunk": Chunk,
|
|
"Block": Block,
|
|
"Entity": Entity,
|
|
"utils": {
|
|
"computeBlockIndex": computeBlockIndex,
|
|
"computeBlockPosition": computeBlockPosition,
|
|
"splitRGBComponents": splitRGBComponents,
|
|
"computeTimeColor": computeTimeColor,
|
|
"addPositions": addPositions
|
|
}
|
|
};
|