Now is standalone from Canopy
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { world } from "@minecraft/server";
|
||||
import { Vector } from "../lib/Vector";
|
||||
import { Vector } from "../../lib/Vector";
|
||||
|
||||
export class Structure {
|
||||
structureId;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { InstanceOptions } from './InstanceOptions';
|
||||
import { StructureInstance } from './StructureInstance';
|
||||
import { InvalidInstanceError } from '../Errors/InvalidInstanceError';
|
||||
import { InstanceOptions } from '../Instance/InstanceOptions';
|
||||
import { StructureInstance } from '../Instance/StructureInstance';
|
||||
import { world } from '@minecraft/server';
|
||||
|
||||
class StructureCollection {
|
||||
@@ -26,7 +27,7 @@ class StructureCollection {
|
||||
|
||||
add(instanceName, structureId) {
|
||||
if (this.structures[instanceName])
|
||||
throw new Error(`Instance ${instanceName} already exists.`);
|
||||
throw new InvalidInstanceError(`Instance ${instanceName} already exists.`);
|
||||
const structure = new StructureInstance(instanceName, structureId);
|
||||
this.structures[instanceName] = structure;
|
||||
return structure;
|
||||
@@ -34,9 +35,8 @@ class StructureCollection {
|
||||
|
||||
get(instanceName) {
|
||||
const structure = this.structures[instanceName];
|
||||
if (!structure) {
|
||||
throw new Error(`Instance ${instanceName} not found.`);
|
||||
}
|
||||
if (!structure)
|
||||
throw new InvalidInstanceError(`Instance ${instanceName} not found.`);
|
||||
return structure;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,232 +0,0 @@
|
||||
import { Vector } from "../lib/Vector";
|
||||
import { StructureOutliner } from "./StructureOutliner";
|
||||
import { StructureVerifier } from "./StructureVerifier";
|
||||
import { InstanceOptions } from "./InstanceOptions";
|
||||
import { Structure } from "./Structure";
|
||||
import { TicksPerSecond } from "@minecraft/server";
|
||||
|
||||
export class StructureInstance {
|
||||
options;
|
||||
structure = void 0;
|
||||
verifier = void 0;
|
||||
outliner = void 0;
|
||||
|
||||
constructor(instanceName, structureId) {
|
||||
this.structure = new Structure(structureId);
|
||||
this.options = new InstanceOptions(instanceName, structureId);
|
||||
this.refreshBox();
|
||||
}
|
||||
|
||||
delete() {
|
||||
this.disable();
|
||||
delete this.options;
|
||||
delete this.structure;
|
||||
delete this.outliner;
|
||||
delete this.verifier;
|
||||
this.options.clear();
|
||||
}
|
||||
|
||||
refreshBox() {
|
||||
if (!this.hasLocation())
|
||||
return;
|
||||
if (!this.outliner)
|
||||
this.outliner = new StructureOutliner(this);
|
||||
if (!this.verifier)
|
||||
this.verifier = new StructureVerifier(this, { isEnabled: this.options.verifier.isEnabled, trackPlayerDistance: this.options.verifier.trackPlayerDistance });
|
||||
this.outliner.refresh();
|
||||
this.verifier.refresh();
|
||||
}
|
||||
|
||||
getName() {
|
||||
return this.options.instanceName;
|
||||
}
|
||||
|
||||
getStructureId() {
|
||||
return this.options.structureId;
|
||||
}
|
||||
|
||||
getLocation() {
|
||||
return { dimensionId: this.options.dimensionId, location: this.options.worldLocation };
|
||||
}
|
||||
|
||||
getDimension() {
|
||||
return this.options.getDimension();
|
||||
}
|
||||
|
||||
getLayer() {
|
||||
return this.options.currentLayer;
|
||||
}
|
||||
|
||||
getMaxLayer() {
|
||||
return this.structure.getHeight();
|
||||
}
|
||||
|
||||
getBounds() {
|
||||
return {
|
||||
min: this.structure.getMin(),
|
||||
max: this.structure.getMax()
|
||||
}
|
||||
}
|
||||
|
||||
getActiveBounds() {
|
||||
if (!this.options.isEnabled)
|
||||
throw new Error(`[Construct] Instance '${this.options.instanceName}' is not placed.`);
|
||||
if (this.hasLayerSelected())
|
||||
return this.getLayerBounds(this.getLayer());
|
||||
return this.getBounds();
|
||||
}
|
||||
|
||||
getLayerBounds(layer) {
|
||||
if (!this.options.isEnabled)
|
||||
throw new Error(`[Construct] Instance '${this.options.instanceName}' is not placed.`);
|
||||
const min = this.structure.getMin();
|
||||
const max = this.structure.getMax();
|
||||
return {
|
||||
min: new Vector(min.x, layer - 1, min.z),
|
||||
max: new Vector(max.x, layer, max.z)
|
||||
};
|
||||
}
|
||||
|
||||
getBlock(structureLocation) {
|
||||
return this.structure.getBlock(structureLocation);
|
||||
}
|
||||
|
||||
getBlocks(structureLocations) {
|
||||
return this.structure.getBlocks(structureLocations);
|
||||
}
|
||||
|
||||
getLayerBlocks(layer) {
|
||||
return this.structure.getLayerBlocks(layer);
|
||||
}
|
||||
|
||||
getAllBlocks() {
|
||||
return this.structure.getAllBlocks();
|
||||
}
|
||||
|
||||
getActiveBlocks() {
|
||||
if (!this.options.isEnabled)
|
||||
throw new Error(`[Construct] Instance '${this.options.instanceName}' is not placed.`);
|
||||
if (this.hasLayerSelected())
|
||||
return this.getLayerBlocks(this.getLayer());
|
||||
return this.getAllBlocks();
|
||||
}
|
||||
|
||||
isLocationActive(dimensionId, structureLocation, { useActiveLayer = true } = {}) {
|
||||
if (!this.options.isEnabled || this.options.dimensionId !== dimensionId)
|
||||
return false;
|
||||
let bounds;
|
||||
if (useActiveLayer)
|
||||
bounds = this.getActiveBounds();
|
||||
else
|
||||
bounds = this.getBounds();
|
||||
return structureLocation.x >= bounds.min.x && structureLocation.x < bounds.max.x
|
||||
&& structureLocation.y >= bounds.min.y && structureLocation.y < bounds.max.y
|
||||
&& structureLocation.z >= bounds.min.z && structureLocation.z < bounds.max.z;
|
||||
}
|
||||
|
||||
getAllActiveLocations() {
|
||||
if (!this.options.isEnabled)
|
||||
throw new Error(`[Construct] Instance '${this.options.instanceName}' is not placed.`);
|
||||
if (this.hasLayerSelected())
|
||||
return this.structure.getLayerLocations(this.getLayer()-1);
|
||||
else
|
||||
return this.structure.getAllLocations();
|
||||
}
|
||||
|
||||
isEnabled() {
|
||||
return this.options.isEnabled;
|
||||
}
|
||||
|
||||
hasLocation() {
|
||||
return this.options.dimensionId && this.options.worldLocation.x !== 0 && this.options.worldLocation.y !== 0 && this.options.worldLocation.z !== 0;
|
||||
}
|
||||
|
||||
hasLayers() {
|
||||
return this.getMaxLayer() > 1;
|
||||
}
|
||||
|
||||
hasLayerSelected() {
|
||||
return this.hasLayers() && this.options.currentLayer !== 0;
|
||||
}
|
||||
|
||||
hasWholeStructureSelected() {
|
||||
return this.hasLocation() && this.options.currentLayer === 0;
|
||||
}
|
||||
|
||||
isAtMaxLayer() {
|
||||
return !this.hasLayers || this.options.currentLayer >= this.getMaxLayer();
|
||||
}
|
||||
|
||||
isAtMinLayer() {
|
||||
return !this.hasLayers || this.options.currentLayer <= 0;
|
||||
}
|
||||
|
||||
enable() {
|
||||
this.options.enable();
|
||||
this.refreshBox();
|
||||
}
|
||||
|
||||
disable() {
|
||||
this.options.disable();
|
||||
this.refreshBox();
|
||||
}
|
||||
|
||||
rename(newName) {
|
||||
this.options.rename(newName);
|
||||
}
|
||||
|
||||
place(dimensionId, worldLocation) {
|
||||
this.move(dimensionId, worldLocation);
|
||||
this.enable();
|
||||
}
|
||||
|
||||
move(dimensionId, worldLocation) {
|
||||
this.options.move(dimensionId, worldLocation);
|
||||
this.refreshBox();
|
||||
}
|
||||
|
||||
setLayer(layer) {
|
||||
if (layer < 0 || layer > this.getMaxLayer())
|
||||
throw new Error(`[Construct] Layer ${layer} is out of bounds.`);
|
||||
this.options.setLayer(layer);
|
||||
this.refreshBox();
|
||||
}
|
||||
|
||||
setVerifierEnabled(enable) {
|
||||
this.options.setVerifierEnabled(enable);
|
||||
this.verifier.refresh();
|
||||
}
|
||||
|
||||
setVerifierDistance(distance) {
|
||||
this.options.setVerifierDistance(distance);
|
||||
if (this.options.verifier.trackPlayerDistance === 0) {
|
||||
const bounds = this.getBounds();
|
||||
this.options.verifier.intervalOrLifetime = Math.max(bounds.min.volume(bounds.max) / TicksPerSecond, 2*TicksPerSecond);
|
||||
} else {
|
||||
this.options.verifier.intervalOrLifetime = 10;
|
||||
}
|
||||
this.verifier.refresh();
|
||||
}
|
||||
|
||||
increaseLayer() {
|
||||
if (this.isAtMaxLayer())
|
||||
this.setLayer(0);
|
||||
else
|
||||
this.setLayer(this.options.currentLayer + 1);
|
||||
}
|
||||
|
||||
decreaseLayer() {
|
||||
if (this.isAtMinLayer())
|
||||
this.setLayer(this.getMaxLayer());
|
||||
else
|
||||
this.setLayer(this.options.currentLayer - 1);
|
||||
}
|
||||
|
||||
toGlobalCoords(structureLocation) {
|
||||
return Vector.from(structureLocation).add(this.options.worldLocation);
|
||||
}
|
||||
|
||||
toStructureCoords(worldLocation) {
|
||||
return Vector.from(worldLocation).subtract(this.options.worldLocation);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Outliner } from './Outliner';
|
||||
import { Outliner } from '../Outliner';
|
||||
|
||||
export class StructureOutliner {
|
||||
constructor(instance) {
|
||||
@@ -42,7 +42,7 @@ export class StructureOutliner {
|
||||
}
|
||||
|
||||
layeredDraw() {
|
||||
const { min, max } = this.instance.getLayeredBounds();
|
||||
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());
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { BlockVerificationLevel } from './enums/BlockVerificationLevel.js';
|
||||
import { BlockVerificationLevel } from '../Enums/BlockVerificationLevel.js';
|
||||
|
||||
export class StructureStatistics {
|
||||
constructor(instance, verification) {
|
||||
|
||||
@@ -1,146 +0,0 @@
|
||||
import { BlockVerifier } from "./BlockVerifier";
|
||||
import { BlockVerificationLevel } from "./enums/BlockVerificationLevel";
|
||||
import { BlockVerificationLevelRender } from "./BlockVerificationLevelRender";
|
||||
import { system, TicksPerSecond } from "@minecraft/server";
|
||||
import { Vector } from "../lib/Vector";
|
||||
|
||||
const MIN_TRACK_PLAYER_DISTANCE = 0;
|
||||
const MAX_TRACK_PLAYER_DISTANCE = 7;
|
||||
const MIN_LIFETIME = 8;
|
||||
|
||||
export class StructureVerifier {
|
||||
instance;
|
||||
intervalOrLifetime;
|
||||
|
||||
locationsToVerify;
|
||||
blockVerificationLevels;
|
||||
isLocationPopulationComplete;
|
||||
isVerificationComplete;
|
||||
|
||||
#runner;
|
||||
#verifyJob;
|
||||
#populateJob = {};
|
||||
|
||||
constructor(instance, { isEnabled = false, trackPlayerDistance = 0, intervalOrLifetime = 10 } = {}) {
|
||||
this.instance = instance;
|
||||
this.intervalOrLifetime = Math.max(intervalOrLifetime, MIN_LIFETIME);
|
||||
this.instance.options.setVerifierEnabled(isEnabled);
|
||||
this.instance.options.setVerifierDistance(trackPlayerDistance);
|
||||
this.locationsToVerify = new Set();
|
||||
}
|
||||
|
||||
startContinuousVerification() {
|
||||
this.#runner = system.runInterval(() => {
|
||||
this.verifyStructure();
|
||||
}, this.intervalOrLifetime);
|
||||
}
|
||||
|
||||
stopContinuousVerification() {
|
||||
if (!this.#runner)
|
||||
return;
|
||||
system.clearRun(this.#runner);
|
||||
this.#runner = void 0;
|
||||
}
|
||||
|
||||
refresh() {
|
||||
this.stopContinuousVerification();
|
||||
if (!this.instance.isEnabled())
|
||||
return;
|
||||
this.startContinuousVerification();
|
||||
}
|
||||
|
||||
isEnabled() {
|
||||
return this.instance.options.verifier.isEnabled;
|
||||
}
|
||||
|
||||
getTrackPlayerDistance() {
|
||||
return Math.min(MAX_TRACK_PLAYER_DISTANCE, Math.max(MIN_TRACK_PLAYER_DISTANCE, this.instance.options.verifier.trackPlayerDistance));
|
||||
}
|
||||
|
||||
init() {
|
||||
this.locationsToVerify.clear();
|
||||
this.blockVerificationLevels = { correctlyAir: 0 };
|
||||
this.isLocationPopulationComplete = false;
|
||||
this.isVerificationComplete = false;
|
||||
}
|
||||
|
||||
async verifyStructure(shouldRender = true) {
|
||||
if (!this.isEnabled())
|
||||
return;
|
||||
this.init();
|
||||
return new Promise(async (resolve) => {
|
||||
await this.populateLocationsToVerify();
|
||||
if (this.#verifyJob)
|
||||
system.clearJob(this.#verifyJob);
|
||||
this.verifyJob = system.runJob(this.verifyBlocks(this.locationsToVerify, shouldRender));
|
||||
const checker = system.runInterval(() => {
|
||||
if (this.isVerificationComplete) {
|
||||
system.clearRun(checker);
|
||||
resolve(this.blockVerificationLevels);
|
||||
}
|
||||
}, 1);
|
||||
});
|
||||
}
|
||||
|
||||
async populateLocationsToVerify() {
|
||||
return new Promise((resolve) => {
|
||||
if (this.getTrackPlayerDistance() === 0) {
|
||||
this.locationsToVerify = this.instance.getAllActiveLocations();
|
||||
resolve();
|
||||
} else {
|
||||
for (const job of Object.values(this.#populateJob))
|
||||
system.clearJob(job);
|
||||
for (const player of this.instance.getDimension().getPlayers())
|
||||
this.#populateJob[player.id] = system.runJob(this.populateActiveLocationsNearPlayer(player));
|
||||
const checker = system.runInterval(() => {
|
||||
if (this.isLocationPopulationComplete) {
|
||||
system.clearRun(checker);
|
||||
resolve();
|
||||
}
|
||||
}, 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
*populateActiveLocationsNearPlayer(player) {
|
||||
const distance = this.getTrackPlayerDistance();
|
||||
for (let x = -distance; x < distance; x++) {
|
||||
for (let y = -distance; y < distance; y++) {
|
||||
for (let z = -distance; z < distance; z++) {
|
||||
const worldLocation = Vector.from(player.location).add(new Vector(x, y, z)).floor();;
|
||||
const structureLocation = this.instance.toStructureCoords(worldLocation);
|
||||
if (this.instance.isLocationActive(player.dimension.id, structureLocation, { useActiveLayer: true })) {
|
||||
this.locationsToVerify.add(structureLocation);
|
||||
}
|
||||
yield void 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.isLocationPopulationComplete = true;
|
||||
}
|
||||
|
||||
*verifyBlocks(locations, shouldRender) {
|
||||
for (const location of locations) {
|
||||
const verificationLevel = this.verifyBlock(location);
|
||||
if (verificationLevel === BlockVerificationLevel.Air) {
|
||||
this.blockVerificationLevels.correctlyAir++;
|
||||
} else {
|
||||
this.blockVerificationLevels[JSON.stringify(location)] = verificationLevel;
|
||||
if (shouldRender) {
|
||||
const dimensionLocation = { dimension: this.instance.getDimension(), location: this.instance.toGlobalCoords(location) };
|
||||
new BlockVerificationLevelRender(dimensionLocation, verificationLevel, this.intervalOrLifetime/TicksPerSecond);
|
||||
}
|
||||
}
|
||||
yield void 0;
|
||||
}
|
||||
this.isVerificationComplete = true;
|
||||
}
|
||||
|
||||
verifyBlock(location) {
|
||||
const worldBlock = this.instance.getDimension().getBlock(this.instance.toGlobalCoords(location));
|
||||
if (!worldBlock)
|
||||
return BlockVerificationLevel.Skipped;
|
||||
const blockVerifier = new BlockVerifier(worldBlock, this.instance);
|
||||
return blockVerifier.verify();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user