@@ -1,27 +0,0 @@
|
||||
import { world, system } from '@minecraft/server';
|
||||
import { MENU_ITEM } from '../consts';
|
||||
import { MenuForm } from './MenuForm';
|
||||
import { structureCollection } from './Structure/StructureCollection';
|
||||
import { Builders } from './Builder/Builders';
|
||||
|
||||
world.beforeEvents.itemUse.subscribe((event) => {
|
||||
if (!event.source || event.itemStack?.typeId !== MENU_ITEM) return;
|
||||
event.cancel = true;
|
||||
const builder = Builders.get(event.source.id);
|
||||
system.run(() => {
|
||||
if (builder.isFlexibleInstanceMoving())
|
||||
return;
|
||||
openMenu(event.source, event);
|
||||
});
|
||||
});
|
||||
|
||||
function openMenu(player, event = void 0) {
|
||||
const options = { jumpToInstance: true };
|
||||
if (event) {
|
||||
const instanceNames = structureCollection.getInstanceNames();
|
||||
const instanceName = event.itemStack?.nameTag;
|
||||
if (instanceNames.includes(instanceName))
|
||||
options.instanceName = instanceName;
|
||||
}
|
||||
new MenuForm(player, options);
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
import { MolangVariableMap, system, TicksPerSecond } from "@minecraft/server";
|
||||
import { Vector } from "../lib/Vector";
|
||||
|
||||
export class Outliner {
|
||||
dimension;
|
||||
min = new Vector();
|
||||
max = new Vector();
|
||||
drawParticle = "construct:outline";
|
||||
drawFrequency;
|
||||
particleLifetime;
|
||||
|
||||
#drawParticles = [];
|
||||
#runner = void 0;
|
||||
|
||||
constructor(dimension, min, max, drawFrequency = 10, particleLifetime = 20) {
|
||||
this.dimension = dimension;
|
||||
this.min = Vector.from(min);
|
||||
this.max = Vector.from(max);
|
||||
this.drawFrequency = drawFrequency;
|
||||
this.particleLifetime = particleLifetime;
|
||||
this.vertices = this.getVertices(min, max);
|
||||
}
|
||||
|
||||
startDraw() {
|
||||
this.#runner = system.runInterval(() => this.draw(), this.drawFrequency);
|
||||
}
|
||||
|
||||
stopDraw() {
|
||||
if (!this.#runner)
|
||||
return;
|
||||
system.clearRun(this.#runner);
|
||||
this.#runner = void 0;
|
||||
}
|
||||
|
||||
draw() {
|
||||
this.drawParticles(this.getVerticeParticles(), () => {
|
||||
return { red: 1, green: 1, blue: 1, alpha: 1 }
|
||||
});
|
||||
this.drawParticles(this.getCubiodEdgeParticles(), this.getNextParticleColor.bind(this));
|
||||
}
|
||||
|
||||
drawParticles(particleLocations, colorCallback) {
|
||||
this.#drawParticles.length = 0;
|
||||
this.#drawParticles.push(...particleLocations);
|
||||
for (const [particleType, location] of this.#drawParticles) {
|
||||
const molang = new MolangVariableMap();
|
||||
molang.setColorRGBA("dot_color", colorCallback());
|
||||
const lifetimeSeconds = this.particleLifetime / TicksPerSecond;
|
||||
molang.setFloat("lifetime", lifetimeSeconds);
|
||||
try {
|
||||
this.dimension.spawnParticle(particleType, location, molang);
|
||||
} catch (e) {
|
||||
/* pass */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getVertices(min, max) {
|
||||
return [
|
||||
new Vector(min.x, min.y, min.z),
|
||||
new Vector(max.x, min.y, min.z),
|
||||
new Vector(min.x, max.y, min.z),
|
||||
new Vector(max.x, max.y, min.z),
|
||||
new Vector(min.x, min.y, max.z),
|
||||
new Vector(max.x, min.y, max.z),
|
||||
new Vector(min.x, max.y, max.z),
|
||||
new Vector(max.x, max.y, max.z)
|
||||
];
|
||||
}
|
||||
|
||||
setVertices(dimension, min, max) {
|
||||
this.dimension = dimension;
|
||||
this.min = Vector.from(min);
|
||||
this.max = Vector.from(max);
|
||||
this.vertices = this.getVertices(min, max);
|
||||
}
|
||||
|
||||
getVerticeParticles() {
|
||||
return this.vertices.map((v) => [this.drawParticle, v]);
|
||||
}
|
||||
|
||||
getCubiodEdgeParticles() {
|
||||
const edges = [
|
||||
[0, 1],
|
||||
[0, 2],
|
||||
[0, 4],
|
||||
[1, 3],
|
||||
[1, 5],
|
||||
[2, 3],
|
||||
[2, 6],
|
||||
[3, 7],
|
||||
[4, 5],
|
||||
[4, 6],
|
||||
[5, 7],
|
||||
[6, 7]
|
||||
];
|
||||
const edgePoints = [];
|
||||
for (const edge of edges) {
|
||||
const [startVertex, endVertex] = [this.vertices[edge[0]], this.vertices[edge[1]]];
|
||||
const resolution = Math.min(Math.floor(endVertex.subtract(startVertex).length), 16);
|
||||
for (let i = 1; i < resolution; i++) {
|
||||
const t = i / resolution;
|
||||
edgePoints.push(startVertex.lerp(endVertex, t));
|
||||
}
|
||||
}
|
||||
return edgePoints.map((v) => [this.drawParticle, v]);
|
||||
}
|
||||
|
||||
addStandaloneParticles(locations) {
|
||||
for (const location of locations)
|
||||
this.vertices.push(Vector.from(location));
|
||||
}
|
||||
|
||||
getNextParticleColor() {
|
||||
if (this.lastWasBlack) {
|
||||
this.lastWasBlack = false;
|
||||
return { red: 0.93333333, green: 0.77647059, blue: 0.13333333, alpha: 1 };
|
||||
} else {
|
||||
this.lastWasBlack = true;
|
||||
return { red: 0.09019608, green: 0.09019608, blue: 0.09019608, alpha: 1 };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
import { MolangVariableMap } from "@minecraft/server";
|
||||
import { BlockVerificationLevel } from "../Enums/BlockVerificationLevel";
|
||||
import { Vector } from "../../lib/Vector";
|
||||
|
||||
export class BlockVerificationLevelRender {
|
||||
opacity = 0.2;
|
||||
lifetimeSeconds = 0;
|
||||
|
||||
constructor(dimensionLocation, verificationLevel, lifetimeSeconds = 5) {
|
||||
this.dimension = dimensionLocation.dimension;
|
||||
this.location = Vector.from(dimensionLocation.location);
|
||||
this.verificationLevel = verificationLevel;
|
||||
this.lifetimeSeconds = lifetimeSeconds;
|
||||
this.renderBlock();
|
||||
}
|
||||
|
||||
renderBlock() {
|
||||
const sizeScalar = this.verificationLevelToSizeScalar();
|
||||
for (const particle of this.getBlockParticles(sizeScalar)) {
|
||||
const color = this.getRGBAMolang();
|
||||
if (!color)
|
||||
return;
|
||||
color.setFloat("lifetime", this.lifetimeSeconds);
|
||||
color.setFloat("width", 0.5*sizeScalar);
|
||||
color.setFloat("height", 0.5*sizeScalar);
|
||||
try {
|
||||
this.dimension.spawnParticle(particle.particleType, particle.location, color);
|
||||
} catch {
|
||||
/* pass */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getBlockParticles(sizeScalar = 1) {
|
||||
const bottomFace = new Vector(0.5, 0, 0.5);
|
||||
const topFace = new Vector(0.5, 1, 0.5);
|
||||
const leftFace = new Vector(1, 0.5, 0.5);
|
||||
const rightFace = new Vector(0, 0.5, 0.5);
|
||||
const frontFace = new Vector(0.5, 0.5, 1);
|
||||
const backFace = new Vector(0.5, 0.5, 0);
|
||||
const center = new Vector(0.5, 0.5, 0.5);
|
||||
return [
|
||||
{ particleType: "construct:blockoverlay_xz", location: this.location.add(center).add(topFace.subtract(center).multiply(sizeScalar)) },
|
||||
{ particleType: "construct:blockoverlay_xz", location: this.location.add(center).add(bottomFace.subtract(center).multiply(sizeScalar)) },
|
||||
{ particleType: "construct:blockoverlay_yz", location: this.location.add(center).add(leftFace.subtract(center).multiply(sizeScalar)) },
|
||||
{ particleType: "construct:blockoverlay_yz", location: this.location.add(center).add(rightFace.subtract(center).multiply(sizeScalar)) },
|
||||
{ particleType: "construct:blockoverlay_xy", location: this.location.add(center).add(frontFace.subtract(center).multiply(sizeScalar)) },
|
||||
{ particleType: "construct:blockoverlay_xy", location: this.location.add(center).add(backFace.subtract(center).multiply(sizeScalar)) }
|
||||
];
|
||||
}
|
||||
|
||||
getRGBAMolang() {
|
||||
const rgb = this.verificationLevelToRGB();
|
||||
if (!rgb) return;
|
||||
rgb.alpha = this.opacity;
|
||||
const molang = new MolangVariableMap();
|
||||
molang.setColorRGBA("face_color", rgb);
|
||||
return molang;
|
||||
}
|
||||
|
||||
verificationLevelToRGB() {
|
||||
switch (this.verificationLevel) {
|
||||
case BlockVerificationLevel.NoMatch:
|
||||
return { red: 1, green: 0, blue: 0};
|
||||
case BlockVerificationLevel.TypeMatch:
|
||||
return { red: 1, green: 1, blue: 0};
|
||||
case BlockVerificationLevel.Missing:
|
||||
return { red: 0, green: 0, blue: 1};
|
||||
default:
|
||||
return void 0;
|
||||
}
|
||||
}
|
||||
|
||||
verificationLevelToSizeScalar() {
|
||||
switch (this.verificationLevel) {
|
||||
case BlockVerificationLevel.NoMatch:
|
||||
return 1.01;
|
||||
case BlockVerificationLevel.TypeMatch:
|
||||
return 1.01;
|
||||
case BlockVerificationLevel.Missing:
|
||||
return 0.90;
|
||||
default:
|
||||
return 1.00;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
import { StructureNotFoundError } from '../Errors/StructureNotFoundError';
|
||||
import { Outliner } from '../Outliner';
|
||||
|
||||
export class StructureOutliner {
|
||||
constructor(instance) {
|
||||
this.instance = instance;
|
||||
this.pullInstanceData();
|
||||
this.outliner = new Outliner(this.dimension, this.bounds.min, this.bounds.max);
|
||||
}
|
||||
|
||||
pullInstanceData() {
|
||||
try {
|
||||
this.dimension = this.instance.getDimension();
|
||||
this.bounds = this.instance.getBounds();
|
||||
this.bounds.min = this.instance.toGlobalCoords(this.bounds.min);
|
||||
this.bounds.max = this.instance.toGlobalCoords(this.bounds.max);
|
||||
} catch (error) {
|
||||
if (error instanceof StructureNotFoundError)
|
||||
this.outliner.stopDraw();
|
||||
else
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
refresh() {
|
||||
this.pullInstanceData();
|
||||
this.refreshDraw();
|
||||
}
|
||||
|
||||
refreshDraw() {
|
||||
this.outliner.stopDraw();
|
||||
if (!this.instance.isEnabled())
|
||||
return;
|
||||
if (this.instance.hasLayerSelected())
|
||||
this.layeredDraw();
|
||||
else
|
||||
this.boxDraw();
|
||||
this.outliner.startDraw();
|
||||
}
|
||||
|
||||
boxDraw() {
|
||||
this.outliner.setVertices(this.dimension, this.bounds.min, this.bounds.max);
|
||||
}
|
||||
|
||||
layeredDraw() {
|
||||
const { min, max } = this.instance.getLayerBounds(this.instance.getLayer());
|
||||
this.outliner.setVertices(this.dimension, this.instance.toGlobalCoords(min), this.instance.toGlobalCoords(max));
|
||||
this.outliner.addStandaloneParticles(this.getCornerVertices());
|
||||
}
|
||||
|
||||
getCornerVertices() {
|
||||
return this.outliner.getVertices(this.bounds.min, this.bounds.max);
|
||||
}
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
import { TicksPerSecond } from "@minecraft/server";
|
||||
import { BlockVerificationLevelRender } from "./BlockVerificationLevelRender";
|
||||
import { system } from "@minecraft/server";
|
||||
|
||||
const RENDER_LIFETIME_FACTOR_TICKS = 1;
|
||||
|
||||
export class VerificationRenderer {
|
||||
instance;
|
||||
lastRenderedChunk;
|
||||
bounds;
|
||||
shortestDimension;
|
||||
#runner;
|
||||
#renderQueue = [];
|
||||
|
||||
constructor(instance) {
|
||||
this.instance = instance;
|
||||
this.lastRenderedChunk = 0;
|
||||
}
|
||||
|
||||
startContinuousRendering() {
|
||||
this.#runner = system.runInterval(() => {
|
||||
if (this.#renderQueue.length === 0)
|
||||
this.prepareRenderQueue();
|
||||
this.renderNextChunk();
|
||||
}, RENDER_LIFETIME_FACTOR_TICKS);
|
||||
}
|
||||
|
||||
stopContinuousRendering() {
|
||||
if (!this.#runner)
|
||||
return;
|
||||
system.clearRun(this.#runner);
|
||||
this.#runner = void 0;
|
||||
this.#renderQueue = [];
|
||||
}
|
||||
|
||||
refresh() {
|
||||
this.stopContinuousRendering();
|
||||
if (!this.instance.isEnabled() || !this.instance.options.verifier.isEnabled)
|
||||
return;
|
||||
this.startContinuousRendering();
|
||||
}
|
||||
|
||||
prepareRenderQueue() {
|
||||
this.#renderQueue = [];
|
||||
const bounds = this.instance.getActiveBounds();
|
||||
for (let y = bounds.min.y; y < bounds.max.y; y++) {
|
||||
this.prepareRenderQueueLayer(bounds, y);
|
||||
}
|
||||
this.lastRenderedChunk = 0;
|
||||
}
|
||||
|
||||
prepareRenderQueueLayer(bounds, y) {
|
||||
if (bounds.max.x < bounds.max.z) {
|
||||
for (let z = bounds.min.z; z < bounds.max.z; z++) {
|
||||
for (let x = bounds.min.x; x < bounds.max.x; x++) {
|
||||
this.#renderQueue.push({ x, y, z });
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (let x = bounds.min.x; x < bounds.max.x; x++) {
|
||||
for (let z = bounds.min.z; z < bounds.max.z; z++) {
|
||||
this.#renderQueue.push({ x, y, z });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
renderNextChunk() {
|
||||
if (this.shouldUseLargeStructureRendering())
|
||||
this.renderNextChunkForLargeStructure();
|
||||
else
|
||||
this.renderNextChunkForSmallStructure();
|
||||
}
|
||||
|
||||
renderNextChunkForLargeStructure() {
|
||||
const bounds = this.instance.getActiveBounds();
|
||||
const shortestSideLength = Math.min(bounds.max.x, bounds.max.z);
|
||||
const maxChunk = (bounds.min.volume(bounds.max) / shortestSideLength) / (bounds.max.y - bounds.min.y);
|
||||
const lifetime = (maxChunk * RENDER_LIFETIME_FACTOR_TICKS) / TicksPerSecond;
|
||||
const verificationLevels = this.instance.verifier.getLastVerificationLevels();
|
||||
const dimension = this.instance.getDimension();
|
||||
const chunk = this.#renderQueue.splice(0, shortestSideLength);
|
||||
for (const location of chunk) {
|
||||
const verificationLevel = verificationLevels[JSON.stringify(location)];
|
||||
if (!verificationLevel)
|
||||
continue;
|
||||
const dimensionLocation = {
|
||||
dimension: dimension,
|
||||
location: this.instance.toGlobalCoords(location)
|
||||
};
|
||||
new BlockVerificationLevelRender(dimensionLocation, verificationLevel, lifetime);
|
||||
}
|
||||
}
|
||||
|
||||
renderNextChunkForSmallStructure() {
|
||||
const bounds = this.instance.getActiveBounds();
|
||||
const lifetime = (bounds.max.x * (bounds.max.y - bounds.min.y) * bounds.max.z * RENDER_LIFETIME_FACTOR_TICKS) / TicksPerSecond;
|
||||
const verificationLevels = this.instance.verifier.getLastVerificationLevels();
|
||||
const dimension = this.instance.getDimension();
|
||||
for (const location of this.#renderQueue.splice(0, 1)) {
|
||||
const verificationLevel = verificationLevels[JSON.stringify(location)];
|
||||
if (!verificationLevel)
|
||||
continue;
|
||||
const dimensionLocation = {
|
||||
dimension: dimension,
|
||||
location: this.instance.toGlobalCoords(location)
|
||||
};
|
||||
new BlockVerificationLevelRender(dimensionLocation, verificationLevel, lifetime);
|
||||
}
|
||||
}
|
||||
|
||||
shouldUseLargeStructureRendering() {
|
||||
const bounds = this.instance.getActiveBounds();
|
||||
const maxVolume = 343;
|
||||
return this.instance.hasLayerSelected() || bounds.min.volume(bounds.max) > maxVolume;
|
||||
}
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
import { InstanceExistsError } from '../Errors/InstanceExistsError';
|
||||
import { InstanceNotFoundError } from '../Errors/InstanceNotFoundError';
|
||||
import { StructureNotFoundError } from '../Errors/StructureNotFoundError';
|
||||
import { InstanceOptions } from '../Instance/InstanceOptions';
|
||||
import { StructureInstance } from '../Instance/StructureInstance';
|
||||
import { InvalidStructureError, world } from '@minecraft/server';
|
||||
|
||||
class StructureCollection {
|
||||
structures;
|
||||
|
||||
constructor() {
|
||||
this.structures = {};
|
||||
}
|
||||
|
||||
loadExistingInstances() {
|
||||
world.getDynamicPropertyIds().filter(id => id.startsWith('instanceOptions:')).forEach(id => {
|
||||
const instanceName = id.replace('instanceOptions:', '');
|
||||
let structureId;
|
||||
try {
|
||||
structureId = InstanceOptions.getInstanceStructureId(instanceName);
|
||||
this.structures[instanceName] = new StructureInstance(instanceName, structureId);
|
||||
} catch (e) {
|
||||
world.sendMessage(`§c[Construct] Error loading structure instance '${instanceName}'. It will be removed.`);
|
||||
world.setDynamicProperty(id, void 0);
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
add(instanceName, structureId) {
|
||||
if (this.structures[instanceName])
|
||||
throw new InstanceExistsError(instanceName);
|
||||
const structure = new StructureInstance(instanceName, structureId);
|
||||
this.structures[instanceName] = structure;
|
||||
return structure;
|
||||
}
|
||||
|
||||
get(instanceName) {
|
||||
const structure = this.structures[instanceName];
|
||||
if (!structure)
|
||||
throw new InstanceNotFoundError(instanceName);
|
||||
return structure;
|
||||
}
|
||||
|
||||
has(instanceName) {
|
||||
return Boolean(this.structures[instanceName]);
|
||||
}
|
||||
|
||||
delete(instanceName) {
|
||||
const struct = this.get(instanceName);
|
||||
struct.delete();
|
||||
delete this.structures[instanceName];
|
||||
}
|
||||
|
||||
getInstanceNames() {
|
||||
return Object.keys(this.structures);
|
||||
}
|
||||
|
||||
getStructures(dimensionId, location, options = {}) {
|
||||
return Object.values(this.structures).filter(structure => {
|
||||
try {
|
||||
return structure.isLocationActive(dimensionId, structure.toStructureCoords(location), options)
|
||||
} catch (error) {
|
||||
if (error instanceof StructureNotFoundError || error instanceof InvalidStructureError) {
|
||||
this.delete(structure.name);
|
||||
return false;
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getStructure(dimensionId, location, options = {}) {
|
||||
return this.getStructures(dimensionId, location, options)[0];
|
||||
}
|
||||
|
||||
fetchStructureBlock(dimensionId, location) {
|
||||
const structure = this.getStructure(dimensionId, location);
|
||||
if (!structure)
|
||||
return void 0;
|
||||
return structure.getBlock(structure.toStructureCoords(location));
|
||||
}
|
||||
|
||||
getWorldStructureIds() {
|
||||
const structureManager = world.structureManager;
|
||||
const packIds = [...new Set(structureManager.getPackStructureIds()
|
||||
.map(id => id.replace('mystructure:', '')))
|
||||
];
|
||||
const packIdSet = new Set(packIds);
|
||||
let worldStructureIds = [];
|
||||
try {
|
||||
worldStructureIds = structureManager.getWorldStructureIds()
|
||||
.filter(id => id.startsWith('mystructure:'))
|
||||
.map(id => id.replace('mystructure:', ''))
|
||||
.filter(id => !packIdSet.has(id));
|
||||
} catch (error) {
|
||||
console.warn('Failed to fetch world structure IDs. They will be ignored. Error:', error);
|
||||
}
|
||||
return [...packIds, ...worldStructureIds];
|
||||
}
|
||||
|
||||
rename(instanceName, newName) {
|
||||
const structure = this.get(instanceName);
|
||||
if (this.structures[newName])
|
||||
throw new InstanceExistsError(newName);
|
||||
structure.rename(newName);
|
||||
this.structures[newName] = structure;
|
||||
delete this.structures[instanceName];
|
||||
structure.name = newName;
|
||||
}
|
||||
}
|
||||
|
||||
export const structureCollection = new StructureCollection();
|
||||
|
||||
world.afterEvents.worldLoad.subscribe(() => {
|
||||
structureCollection.loadExistingInstances();
|
||||
});
|
||||
@@ -1,68 +0,0 @@
|
||||
import { BlockVerificationLevel } from '../Enums/BlockVerificationLevel.js';
|
||||
|
||||
export class StructureStatistics {
|
||||
constructor(instance, verification) {
|
||||
this.instance = instance;
|
||||
this.verification = verification;
|
||||
this.parse();
|
||||
}
|
||||
|
||||
init() {
|
||||
this.statistics = {};
|
||||
for (const verificationLevel of Object.values(BlockVerificationLevel))
|
||||
this.statistics[verificationLevel] = 0;
|
||||
this.statistics.correctlyAir = 0;
|
||||
}
|
||||
|
||||
parse() {
|
||||
this.init();
|
||||
for (const blockVerificationLevel of Object.values(BlockVerificationLevel))
|
||||
this.parseStatistic(blockVerificationLevel);
|
||||
}
|
||||
|
||||
parseStatistic(blockVerificationLevel) {
|
||||
for (const [location, verificationLevel] of Object.entries(this.verification)) {
|
||||
if (location === 'correctlyAir')
|
||||
continue;
|
||||
if (blockVerificationLevel === verificationLevel)
|
||||
this.statistics[verificationLevel]++;
|
||||
}
|
||||
}
|
||||
|
||||
getNonAirBlocks() {
|
||||
const activeBounds = this.instance.getActiveBounds();
|
||||
return activeBounds.min.volume(activeBounds.max) - this.verification.correctlyAir;
|
||||
}
|
||||
|
||||
getStat(blockVerificationLevel) {
|
||||
return { num: this.statistics[blockVerificationLevel], percent: this.statistics[blockVerificationLevel] / (this.getNonAirBlocks()) * 100 };
|
||||
}
|
||||
|
||||
getSkipped() {
|
||||
return this.statistics[BlockVerificationLevel.Skipped] || 0;
|
||||
}
|
||||
|
||||
getMessage() {
|
||||
const message = { rawtext: [] };
|
||||
message.rawtext.push({ translate: 'construct.structure.statistics.header', with: [this.instance.getName()] });
|
||||
if (this.instance.hasLayerSelected())
|
||||
message.rawtext.push({ translate: 'construct.instance.materials.layer', with: [String(this.instance.getLayer())] });
|
||||
message.rawtext.push({ rawtext: [
|
||||
{ text: '\n' },
|
||||
{ translate: 'construct.structure.statistics.blocks', with: [String(this.getNonAirBlocks())] },
|
||||
{ text: '\n' }
|
||||
]});
|
||||
const skipped = this.getSkipped();
|
||||
if (skipped > 0)
|
||||
message.rawtext.push({ rawtext: [{ translate: 'construct.structure.statistics.skipped', with: [String(skipped)] }, { text: '\n' }] });
|
||||
message.rawtext.push({ rawtext: [{ translate: 'construct.structure.statistics.correct', with: [this.formatStat(this.getStat(BlockVerificationLevel.Match))] }, { text: '\n' }] });
|
||||
message.rawtext.push({ rawtext: [{ translate: 'construct.structure.statistics.stateincorrect', with: [this.formatStat(this.getStat(BlockVerificationLevel.TypeMatch))] }, { text: '\n' }] });
|
||||
message.rawtext.push({ rawtext: [{ translate: 'construct.structure.statistics.incorrect', with: [this.formatStat(this.getStat(BlockVerificationLevel.NoMatch))] }, { text: '\n' }] });
|
||||
message.rawtext.push({ rawtext: [{ translate: 'construct.structure.statistics.missing', with: [this.formatStat(this.getStat(BlockVerificationLevel.Missing))] }, { text: '\n' }] });
|
||||
return message;
|
||||
}
|
||||
|
||||
formatStat(stat) {
|
||||
return `${stat.num} (${stat.percent.toFixed(2)}%%)`;
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
import { BlockVerificationLevel } from "../Enums/BlockVerificationLevel";
|
||||
|
||||
export class BlockVerifier {
|
||||
constructor(block, instance) {
|
||||
this.block = block;
|
||||
this.instance = instance;
|
||||
this.blockLocationInStructure = instance.toStructureCoords(block.location);
|
||||
}
|
||||
|
||||
verify() {
|
||||
const structPermutation = this.instance.getBlock(this.blockLocationInStructure);
|
||||
return this.evaluatePermutations(this.block.permutation, structPermutation);
|
||||
}
|
||||
|
||||
evaluatePermutations(worldPermutation, structPermutation) {
|
||||
if (this.isCorrectlyAir(worldPermutation, structPermutation))
|
||||
return BlockVerificationLevel.Air;
|
||||
if (this.isMissing(worldPermutation, structPermutation))
|
||||
return BlockVerificationLevel.Missing;
|
||||
if (this.isExactMatch(worldPermutation, structPermutation))
|
||||
return BlockVerificationLevel.Match;
|
||||
if (this.isTypeMatch(worldPermutation, structPermutation))
|
||||
return BlockVerificationLevel.TypeMatch;
|
||||
return BlockVerificationLevel.NoMatch;
|
||||
}
|
||||
|
||||
isCorrectlyAir(worldPermutation, structPermutation) {
|
||||
return worldPermutation.type.id === "minecraft:air" && structPermutation.type.id === "minecraft:air";
|
||||
}
|
||||
|
||||
isMissing(worldPermutation, structPermutation) {
|
||||
return worldPermutation.type.id === "minecraft:air" && structPermutation.type.id !== "minecraft:air";
|
||||
}
|
||||
|
||||
isTypeMatch(worldPermuation, structurePermuation) {
|
||||
return worldPermuation.type.id === structurePermuation.type.id;
|
||||
}
|
||||
|
||||
isExactMatch(worldPermutation, structurePermutation) {
|
||||
return worldPermutation.matches(structurePermutation.type.id, structurePermutation.getAllStates())
|
||||
&& this.block.isWaterlogged === structurePermutation.isWaterlogged;
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
{
|
||||
"format_version": "1.10.0",
|
||||
"particle_effect": {
|
||||
"description": {
|
||||
"identifier": "construct:blockoverlay_xy",
|
||||
"basic_render_parameters": {
|
||||
"material": "particles_blend",
|
||||
"texture": "textures/particle/white"
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"minecraft:emitter_rate_instant": {
|
||||
"num_particles": 1
|
||||
},
|
||||
"minecraft:emitter_lifetime_once": {
|
||||
"active_time": 1
|
||||
},
|
||||
"minecraft:emitter_shape_point": {},
|
||||
"minecraft:particle_lifetime_expression": {
|
||||
"max_lifetime": "variable.lifetime"
|
||||
},
|
||||
"minecraft:particle_appearance_billboard": {
|
||||
"size": ["variable.width", "variable.height"],
|
||||
"facing_camera_mode": "emitter_transform_xy"
|
||||
},
|
||||
"minecraft:particle_appearance_tinting": {
|
||||
"color": [
|
||||
"variable.face_color.r",
|
||||
"variable.face_color.g",
|
||||
"variable.face_color.b",
|
||||
"variable.face_color.a"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
{
|
||||
"format_version": "1.10.0",
|
||||
"particle_effect": {
|
||||
"description": {
|
||||
"identifier": "construct:blockoverlay_xz",
|
||||
"basic_render_parameters": {
|
||||
"material": "particles_blend",
|
||||
"texture": "textures/particle/white"
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"minecraft:emitter_rate_instant": {
|
||||
"num_particles": 1
|
||||
},
|
||||
"minecraft:emitter_lifetime_once": {
|
||||
"active_time": 1
|
||||
},
|
||||
"minecraft:emitter_shape_point": {},
|
||||
"minecraft:particle_lifetime_expression": {
|
||||
"max_lifetime": "variable.lifetime"
|
||||
},
|
||||
"minecraft:particle_appearance_billboard": {
|
||||
"size": ["variable.width", "variable.height"],
|
||||
"facing_camera_mode": "emitter_transform_xz"
|
||||
},
|
||||
"minecraft:particle_appearance_tinting": {
|
||||
"color": [
|
||||
"variable.face_color.r",
|
||||
"variable.face_color.g",
|
||||
"variable.face_color.b",
|
||||
"variable.face_color.a"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
{
|
||||
"format_version": "1.10.0",
|
||||
"particle_effect": {
|
||||
"description": {
|
||||
"identifier": "construct:blockoverlay_yz",
|
||||
"basic_render_parameters": {
|
||||
"material": "particles_blend",
|
||||
"texture": "textures/particle/white"
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"minecraft:emitter_rate_instant": {
|
||||
"num_particles": 1
|
||||
},
|
||||
"minecraft:emitter_lifetime_once": {
|
||||
"active_time": 1
|
||||
},
|
||||
"minecraft:emitter_shape_point": {},
|
||||
"minecraft:particle_lifetime_expression": {
|
||||
"max_lifetime": "variable.lifetime"
|
||||
},
|
||||
"minecraft:particle_appearance_billboard": {
|
||||
"size": ["variable.width", "variable.height"],
|
||||
"facing_camera_mode": "emitter_transform_yz"
|
||||
},
|
||||
"minecraft:particle_appearance_tinting": {
|
||||
"color": [
|
||||
"variable.face_color.r",
|
||||
"variable.face_color.g",
|
||||
"variable.face_color.b",
|
||||
"variable.face_color.a"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user