Merge branch 'StructureVerifier'
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
export class InvalidStructureError extends Error {
|
||||
constructor(message) {
|
||||
super(message);
|
||||
this.name = 'InvalidStructureError';
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,8 @@ import { EntityComponentTypes, TicksPerSecond } from '@minecraft/server';
|
||||
import { BlockVerificationLevel } from '../Enums/BlockVerificationLevel';
|
||||
|
||||
export class InstanceFormBuilder {
|
||||
static structureVerifier;
|
||||
|
||||
static buildInstance(instance, options) {
|
||||
const location = instance.getLocation();
|
||||
const form = new ActionFormData()
|
||||
@@ -32,10 +34,11 @@ export class InstanceFormBuilder {
|
||||
.title(MenuFormBuilder.menuTitle)
|
||||
if (this.structureVerifier)
|
||||
throw new Error('StructureVerifier is already running.');
|
||||
const structureVerifier = new StructureVerifier(instance, { isEnabled: true, particleLifetime: 1*TicksPerSecond, isStandalone: true });
|
||||
const verification = await structureVerifier.verifyStructure(true);
|
||||
this.structureVerifier = new StructureVerifier(instance, { isEnabled: true, particleLifetime: 1*TicksPerSecond, isStandalone: true });
|
||||
const verification = await this.structureVerifier.verifyStructure(true);
|
||||
const statistics = new StructureStatistics(instance, verification);
|
||||
const statsMessage = statistics.getMessage();
|
||||
this.structureVerifier = void 0;
|
||||
buildStatisticsForm.body(statsMessage);
|
||||
return { form: buildStatisticsForm, stats: statsMessage };
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ export class InstanceOptions extends Option {
|
||||
particleLifetime: 10
|
||||
};
|
||||
|
||||
static getInstanceStrucetureId(instanceName) {
|
||||
static getInstanceStructureId(instanceName) {
|
||||
const options = new InstanceOptions(instanceName, void 0);
|
||||
return options.structureId;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { ItemStack } from "@minecraft/server";
|
||||
import { ItemStack, system } from "@minecraft/server";
|
||||
import { Vector } from "../../lib/Vector";
|
||||
|
||||
class StructureMaterials {
|
||||
instance;
|
||||
@@ -16,10 +17,10 @@ class StructureMaterials {
|
||||
|
||||
populateInstance() {
|
||||
try {
|
||||
if (this.instance.hasLocation())
|
||||
this.populateActive();
|
||||
if (this.instance.hasLocation() && this.instance.isEnabled())
|
||||
system.runJob(this.populateActive());
|
||||
else
|
||||
this.populateAll();
|
||||
system.runJob(this.populateAll());
|
||||
} catch (e) {
|
||||
if (e.name === 'InstanceNotPlacedError')
|
||||
this.clear();
|
||||
@@ -47,19 +48,28 @@ class StructureMaterials {
|
||||
delete this.materials[itemType];
|
||||
}
|
||||
|
||||
populateAll() {
|
||||
for (let layer = 0; layer < this.instance.getMaxLayer(); layer++)
|
||||
this.populateLayer(layer)
|
||||
*populateAll() {
|
||||
for (let layer = 0; layer < this.instance.getMaxLayer(); layer++) {
|
||||
for (const block of this.instance.getLayerBlocks(layer)) {
|
||||
this.countBlock(block)
|
||||
yield void 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
populateLayer(layer) {
|
||||
for (const block of this.instance.getLayerBlocks(layer))
|
||||
this.countBlock(block)
|
||||
}
|
||||
|
||||
populateActive() {
|
||||
for (const block of this.instance.getActiveBlocks())
|
||||
this.countBlock(block)
|
||||
*populateActive() {
|
||||
const bounds = this.instance.getActiveBounds();
|
||||
for (let y = bounds.min.y; y < bounds.max.y; y++) {
|
||||
for (let z = bounds.min.z; z < bounds.max.z; z++) {
|
||||
for (let x = bounds.min.x; x < bounds.max.x; x++) {
|
||||
const location = new Vector(x, y, z);
|
||||
const block = this.instance.getBlock(location);
|
||||
if (!block) continue;
|
||||
this.countBlock(block);
|
||||
yield void 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
countBlock(block) {
|
||||
|
||||
@@ -66,6 +66,11 @@ export class MenuForm {
|
||||
this.player.sendMessage(`§cInstance '${instanceName}' already exists. Try again with a new name.`);
|
||||
return void 0;
|
||||
}
|
||||
if (e.name === 'InvalidStructureError') {
|
||||
this.player.sendMessage(`§cStructure ID '${structureId}' not found. If you're looking for a structure that you put in the structures folder, please restart your world and try again.`);
|
||||
return void 0;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
return instanceName;
|
||||
});
|
||||
@@ -91,10 +96,6 @@ export class MenuForm {
|
||||
const structureId = response.formValues[0];
|
||||
if (structureId === '')
|
||||
return void 0;
|
||||
if (!structureCollection.getWorldStructureIds().some(id => id.replace('mystructure:', '') === structureId)) {
|
||||
this.player.sendMessage(`§cStructure ID '${structureId}' not found. If you're looking for a structure that you put in the structures folder, please restart your world and try again.`);
|
||||
return void 0;
|
||||
}
|
||||
return structureId;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ export class VerificationRenderer {
|
||||
instance;
|
||||
lastRenderedChunk;
|
||||
bounds;
|
||||
shortestDimension;
|
||||
#runner;
|
||||
#renderQueue = [];
|
||||
|
||||
@@ -42,14 +43,26 @@ export class VerificationRenderer {
|
||||
prepareRenderQueue() {
|
||||
this.#renderQueue = [];
|
||||
const bounds = this.instance.getActiveBounds();
|
||||
for (let y = bounds.min.y; y < bounds.max.y; y++) {
|
||||
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 });
|
||||
}
|
||||
}
|
||||
}
|
||||
this.lastRenderedChunk = 0;
|
||||
}
|
||||
|
||||
renderNextChunk() {
|
||||
@@ -61,11 +74,12 @@ export class VerificationRenderer {
|
||||
|
||||
renderNextChunkForLargeStructure() {
|
||||
const bounds = this.instance.getActiveBounds();
|
||||
const maxChunk = (bounds.min.volume(bounds.max) / bounds.max.x) / (bounds.max.y - bounds.min.y);
|
||||
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, bounds.max.x);
|
||||
const chunk = this.#renderQueue.splice(0, shortestSideLength);
|
||||
for (const location of chunk) {
|
||||
const verificationLevel = verificationLevels[JSON.stringify(location)];
|
||||
if (!verificationLevel)
|
||||
@@ -97,6 +111,7 @@ export class VerificationRenderer {
|
||||
|
||||
shouldUseLargeStructureRendering() {
|
||||
const bounds = this.instance.getActiveBounds();
|
||||
return this.instance.hasLayerSelected() || bounds.min.volume(bounds.max) > 300;
|
||||
const maxVolume = 343;
|
||||
return this.instance.hasLayerSelected() || bounds.min.volume(bounds.max) > maxVolume;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { world } from "@minecraft/server";
|
||||
import { Vector } from "../../lib/Vector";
|
||||
import { InvalidStructureError } from "../Errors/InvalidStructureError";
|
||||
|
||||
export class Structure {
|
||||
structureId;
|
||||
@@ -9,7 +10,7 @@ export class Structure {
|
||||
this.structureId = structureId;
|
||||
this.#structure = world.structureManager.get(structureId);
|
||||
if (!this.#structure)
|
||||
throw new Error(`[Construct] Structure '${structureId}' not found.`);
|
||||
throw new InvalidStructureError(`[Construct] Structure '${structureId}' not found on world.`);
|
||||
this.#structure.saveToWorld();
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ class StructureCollection {
|
||||
const instanceName = id.replace('instanceOptions:', '');
|
||||
let structureId;
|
||||
try {
|
||||
structureId = InstanceOptions.getInstanceStrucetureId(instanceName);
|
||||
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.`);
|
||||
|
||||
@@ -79,10 +79,9 @@ export class StructureVerifier {
|
||||
return;
|
||||
this.initVerification();
|
||||
return new Promise(async (resolve) => {
|
||||
await this.populateLocationsToVerify();
|
||||
if (this.#verifyJob)
|
||||
system.clearJob(this.#verifyJob);
|
||||
this.#verifyJob = system.runJob(this.verifyBlocks(this.locationsToVerify, shouldRender));
|
||||
this.#verifyJob = system.runJob(this.verifyBlocks(shouldRender));
|
||||
const checker = system.runInterval(() => {
|
||||
if (this.isVerificationComplete) {
|
||||
system.clearRun(checker);
|
||||
@@ -101,65 +100,35 @@ export class StructureVerifier {
|
||||
this.isLocationPopulationComplete = false;
|
||||
this.isVerificationComplete = false;
|
||||
}
|
||||
|
||||
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()) {
|
||||
if (!player)
|
||||
continue;
|
||||
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);
|
||||
}
|
||||
|
||||
*verifyBlocks(shouldRender) {
|
||||
const bounds = this.instance.getActiveBounds();
|
||||
for (let y = bounds.min.y; y < bounds.max.y; y++) {
|
||||
for (let z = bounds.min.z; z < bounds.max.z; z++) {
|
||||
for (let x = bounds.min.x; x < bounds.max.x; x++) {
|
||||
const location = new Vector(x, y, z);
|
||||
this.verifyBlock(location, shouldRender);
|
||||
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.particleLifetime/TicksPerSecond);
|
||||
}
|
||||
}
|
||||
yield void 0;
|
||||
}
|
||||
this.isVerificationComplete = true;
|
||||
}
|
||||
|
||||
verifyBlock(location) {
|
||||
verifyBlock(location, shouldRender) {
|
||||
const verificationLevel = this.getVerificationLevel(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.particleLifetime/TicksPerSecond);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getVerificationLevel(location) {
|
||||
const worldBlock = this.instance.getDimension()?.getBlock(this.instance.toGlobalCoords(location));
|
||||
if (!worldBlock)
|
||||
return BlockVerificationLevel.Skipped;
|
||||
|
||||
Reference in New Issue
Block a user