UNPKG

@minecraft/creator-tools

Version:

Minecraft Creator Tools command line and libraries.

332 lines (330 loc) 24.2 kB
"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. Object.defineProperty(exports, "__esModule", { value: true }); exports.WorldDataInfoGeneratorTest = void 0; const ProjectInfoItem_1 = require("./ProjectInfoItem"); const IProjectItemData_1 = require("../app/IProjectItemData"); const MCWorld_1 = require("../minecraft/MCWorld"); const Log_1 = require("../core/Log"); const IInfoItemData_1 = require("./IInfoItemData"); const CommandBlockActor_1 = require("../minecraft/blockActors/CommandBlockActor"); const Status_1 = require("../app/Status"); const CommandStructure_1 = require("../app/CommandStructure"); const CommandRegistry_1 = require("../app/CommandRegistry"); const Dialogue_1 = require("../minecraft/Dialogue"); const ContentIndex_1 = require("../core/ContentIndex"); const NbtBinaryTag_1 = require("../minecraft/NbtBinaryTag"); const AnimationControllerBehaviorDefinition_1 = require("../minecraft/AnimationControllerBehaviorDefinition"); const AnimationBehaviorDefinition_1 = require("../minecraft/AnimationBehaviorDefinition"); const ProjectInfoUtilities_1 = require("./ProjectInfoUtilities"); var WorldDataInfoGeneratorTest; (function (WorldDataInfoGeneratorTest) { WorldDataInfoGeneratorTest[WorldDataInfoGeneratorTest["blocks"] = 1] = "blocks"; WorldDataInfoGeneratorTest[WorldDataInfoGeneratorTest["blockData"] = 2] = "blockData"; WorldDataInfoGeneratorTest[WorldDataInfoGeneratorTest["command"] = 3] = "command"; WorldDataInfoGeneratorTest[WorldDataInfoGeneratorTest["executeSubCommand"] = 4] = "executeSubCommand"; WorldDataInfoGeneratorTest[WorldDataInfoGeneratorTest["levelDat"] = 5] = "levelDat"; WorldDataInfoGeneratorTest[WorldDataInfoGeneratorTest["levelDatExperiments"] = 6] = "levelDatExperiments"; WorldDataInfoGeneratorTest[WorldDataInfoGeneratorTest["subchunklessChunks"] = 7] = "subchunklessChunks"; WorldDataInfoGeneratorTest[WorldDataInfoGeneratorTest["chunks"] = 8] = "chunks"; WorldDataInfoGeneratorTest[WorldDataInfoGeneratorTest["unexpectedCommandInMCFunction"] = 101] = "unexpectedCommandInMCFunction"; WorldDataInfoGeneratorTest[WorldDataInfoGeneratorTest["minX"] = 103] = "minX"; WorldDataInfoGeneratorTest[WorldDataInfoGeneratorTest["minZ"] = 104] = "minZ"; WorldDataInfoGeneratorTest[WorldDataInfoGeneratorTest["maxX"] = 105] = "maxX"; WorldDataInfoGeneratorTest[WorldDataInfoGeneratorTest["maxZ"] = 106] = "maxZ"; WorldDataInfoGeneratorTest[WorldDataInfoGeneratorTest["unexpectedCommandInCommandBlock"] = 102] = "unexpectedCommandInCommandBlock"; WorldDataInfoGeneratorTest[WorldDataInfoGeneratorTest["containsWorldImpactingCommand"] = 112] = "containsWorldImpactingCommand"; WorldDataInfoGeneratorTest[WorldDataInfoGeneratorTest["commandIsFromOlderMinecraftVersion"] = 212] = "commandIsFromOlderMinecraftVersion"; WorldDataInfoGeneratorTest[WorldDataInfoGeneratorTest["errorProcessingWorld"] = 400] = "errorProcessingWorld"; })(WorldDataInfoGeneratorTest = exports.WorldDataInfoGeneratorTest || (exports.WorldDataInfoGeneratorTest = {})); class WorldDataInfoGenerator { constructor() { this.id = "WORLDDATA"; this.title = "World Data Validation"; this.modernCommandVersion = 33; // corresponds to 1.20.0 versions of Minecraft. this.performAddOnValidations = false; this.performPlatformVersionValidations = false; } getTopicData(topicId) { return { title: ProjectInfoUtilities_1.default.getTitleFromEnum(WorldDataInfoGeneratorTest, topicId), }; } summarize(info, infoSet) { info.chunkCount = infoSet.getSummedNumberValue("WORLDDATA", WorldDataInfoGeneratorTest.unexpectedCommandInMCFunction); info.subchunkLessChunkCount = infoSet.getSummedNumberValue("WORLDDATA", WorldDataInfoGeneratorTest.subchunklessChunks); info.worldLoadErrors = infoSet.getCount("WORLDDATA", WorldDataInfoGeneratorTest.errorProcessingWorld); } processListOfCommands(commandList, items, projectItem, commandsPi, subCommandsPi, checkForSlash) { for (let i = 0; i < commandList.length; i++) { if (commandList[i].trim().length > 2 && (!checkForSlash || commandList[i].startsWith("/"))) { const command = CommandStructure_1.default.parse(commandList[i]); if (CommandRegistry_1.default.isMinecraftBuiltInCommand(command.name)) { if (this.performAddOnValidations && CommandRegistry_1.default.isAddOnBlockedCommand(command.name)) { items.push(new ProjectInfoItem_1.default(IInfoItemData_1.InfoItemType.warning, this.id, WorldDataInfoGeneratorTest.containsWorldImpactingCommand, "Contains command '" + command.name + "' which is impacts the state of the entire world, and generally shouldn't be used in an add-on", projectItem, command.name, undefined, commandList[i])); } commandsPi.incrementFeature(command.name); if (command.name === "execute") { let foundRun = false; for (const arg of command.commandArguments) { if (arg === "run") { foundRun = true; } else if (foundRun && CommandRegistry_1.default.isMinecraftBuiltInCommand(arg)) { subCommandsPi.incrementFeature(arg); break; } } } } else if (!this.performPlatformVersionValidations && !this.performAddOnValidations) { items.push(new ProjectInfoItem_1.default(IInfoItemData_1.InfoItemType.error, this.id, 401, "Unexpected command '" + command.name + "'", projectItem, command.name, undefined, commandList[i])); } } } } async generate(projectItem, contentIndex) { const items = []; if (projectItem.itemType !== IProjectItemData_1.ProjectItemType.MCWorld && projectItem.itemType !== IProjectItemData_1.ProjectItemType.MCTemplate && projectItem.itemType !== IProjectItemData_1.ProjectItemType.worldFolder && projectItem.itemType !== IProjectItemData_1.ProjectItemType.dialogueBehaviorJson && projectItem.itemType !== IProjectItemData_1.ProjectItemType.animationControllerBehaviorJson && projectItem.itemType !== IProjectItemData_1.ProjectItemType.animationBehaviorJson && projectItem.itemType !== IProjectItemData_1.ProjectItemType.MCFunction) { return items; } const blocksPi = new ProjectInfoItem_1.default(IInfoItemData_1.InfoItemType.featureAggregate, this.id, WorldDataInfoGeneratorTest.blocks, ProjectInfoUtilities_1.default.getTitleFromEnum(WorldDataInfoGeneratorTest, WorldDataInfoGeneratorTest.blocks), projectItem); items.push(blocksPi); const blockActorsPi = new ProjectInfoItem_1.default(IInfoItemData_1.InfoItemType.featureAggregate, this.id, WorldDataInfoGeneratorTest.blockData, ProjectInfoUtilities_1.default.getTitleFromEnum(WorldDataInfoGeneratorTest, WorldDataInfoGeneratorTest.blockData), projectItem); items.push(blockActorsPi); const commandsPi = new ProjectInfoItem_1.default(IInfoItemData_1.InfoItemType.featureAggregate, this.id, WorldDataInfoGeneratorTest.command, ProjectInfoUtilities_1.default.getTitleFromEnum(WorldDataInfoGeneratorTest, WorldDataInfoGeneratorTest.command), projectItem); items.push(commandsPi); const subCommandsPi = new ProjectInfoItem_1.default(IInfoItemData_1.InfoItemType.featureAggregate, this.id, WorldDataInfoGeneratorTest.executeSubCommand, ProjectInfoUtilities_1.default.getTitleFromEnum(WorldDataInfoGeneratorTest, WorldDataInfoGeneratorTest.executeSubCommand), projectItem); items.push(subCommandsPi); const nbtPi = new ProjectInfoItem_1.default(IInfoItemData_1.InfoItemType.featureAggregate, this.id, WorldDataInfoGeneratorTest.levelDat, ProjectInfoUtilities_1.default.getTitleFromEnum(WorldDataInfoGeneratorTest, WorldDataInfoGeneratorTest.levelDat), projectItem); items.push(nbtPi); const nbtExperimentsPi = new ProjectInfoItem_1.default(IInfoItemData_1.InfoItemType.featureAggregate, this.id, WorldDataInfoGeneratorTest.levelDatExperiments, ProjectInfoUtilities_1.default.getTitleFromEnum(WorldDataInfoGeneratorTest, WorldDataInfoGeneratorTest.levelDatExperiments), projectItem); items.push(nbtExperimentsPi); if (projectItem.itemType === IProjectItemData_1.ProjectItemType.dialogueBehaviorJson) { await projectItem.ensureFileStorage(); if (projectItem.file) { const diaManifest = await Dialogue_1.default.ensureOnFile(projectItem.file); if (diaManifest && diaManifest.definition && diaManifest.definition["minecraft:npc_dialogue"]) { let scenes = diaManifest.definition["minecraft:npc_dialogue"].scenes; for (const scene of scenes) { if (scene.on_open_commands) { this.processListOfCommands(scene.on_open_commands, items, projectItem, commandsPi, subCommandsPi, true); } if (scene.on_close_commands) { this.processListOfCommands(scene.on_close_commands, items, projectItem, commandsPi, subCommandsPi, true); } } let buttons = diaManifest.getAllButtons(); for (const button of buttons) { if (button.commands) { this.processListOfCommands(button.commands, items, projectItem, commandsPi, subCommandsPi, true); } } } } } else if (projectItem.itemType === IProjectItemData_1.ProjectItemType.animationControllerBehaviorJson) { await projectItem.ensureFileStorage(); if (projectItem.file) { const acManifest = await AnimationControllerBehaviorDefinition_1.default.ensureOnFile(projectItem.file); if (acManifest && acManifest.data && acManifest.data.animation_controllers) { let states = acManifest.getAllStates(); for (const state of states) { if (state.state.on_entry) { this.processListOfCommands(state.state.on_entry, items, projectItem, commandsPi, subCommandsPi, true); } if (state.state.on_exit) { this.processListOfCommands(state.state.on_exit, items, projectItem, commandsPi, subCommandsPi, true); } } } } } else if (projectItem.itemType === IProjectItemData_1.ProjectItemType.animationBehaviorJson) { await projectItem.ensureFileStorage(); if (projectItem.file) { const animManifest = await AnimationBehaviorDefinition_1.default.ensureOnFile(projectItem.file); if (animManifest && animManifest.data && animManifest.data.animations) { let timelines = animManifest.getAllTimeline(); for (const timeline of timelines) { if (timeline.timeline) { this.processListOfCommands(timeline.timeline, items, projectItem, commandsPi, subCommandsPi, true); } } } } } else if (projectItem.itemType === IProjectItemData_1.ProjectItemType.MCFunction) { let content = await projectItem.getStringContent(); if (content !== undefined) { let contentLines = content.split("\n"); this.processListOfCommands(contentLines, items, projectItem, commandsPi, subCommandsPi, false); } } if (projectItem.itemType === IProjectItemData_1.ProjectItemType.MCWorld || projectItem.itemType === IProjectItemData_1.ProjectItemType.MCTemplate || projectItem.itemType === IProjectItemData_1.ProjectItemType.worldFolder) { let mcworld = await MCWorld_1.default.ensureOnItem(projectItem); if (!mcworld) { Log_1.default.debugAlert("Could not find respective world."); return items; } await mcworld.load(false); await mcworld.loadData(false); if (mcworld.isInErrorState && mcworld.errorMessages && !this.performAddOnValidations && !this.performPlatformVersionValidations) { for (const err of mcworld.errorMessages) { items.push(new ProjectInfoItem_1.default(IInfoItemData_1.InfoItemType.error, this.id, WorldDataInfoGeneratorTest.errorProcessingWorld, ProjectInfoUtilities_1.default.getTitleFromEnum(WorldDataInfoGeneratorTest, WorldDataInfoGeneratorTest.errorProcessingWorld), projectItem, err.message + (err.context ? " - " + err.context : ""), mcworld.name)); } } if (projectItem.projectPath && contentIndex && mcworld.levelData && mcworld.levelData.nbt && mcworld.levelData.nbt.singleRoot) { const children = mcworld.levelData.nbt.singleRoot.getTagChildren(); for (const child of children) { if (child.name === "experiments") { for (const experimentChild of child.getTagChildren()) { if (experimentChild.type === NbtBinaryTag_1.NbtTagType.int || experimentChild.type === NbtBinaryTag_1.NbtTagType.byte || experimentChild.type === NbtBinaryTag_1.NbtTagType.string) { nbtExperimentsPi.incrementFeature(experimentChild.name, experimentChild.valueAsString); contentIndex.insert(experimentChild.name + "==" + experimentChild.valueAsString, projectItem.projectPath, ContentIndex_1.AnnotationCategory.experiment); } } } else if (child.type === NbtBinaryTag_1.NbtTagType.int || child.type === NbtBinaryTag_1.NbtTagType.byte || child.type === NbtBinaryTag_1.NbtTagType.string) { if (child.name !== "LevelName" && child.name !== "FlatWorldLayers" && child.name !== "lightningTime" && child.name !== "EducationOid" && child.name !== "EducationProductId" && child.name !== "rainTime" && child.name !== "worldTemplateUUID" && !child.name.startsWith("LimitedWorld") && !child.name.startsWith("SpawnX") && !child.name.startsWith("SpawnY") && !child.name.startsWith("SpawnZ")) { if (child.name.indexOf("ersion") >= 0 && !child.valueAsString.startsWith("1.")) { nbtPi.incrementFeature(child.name, "(unknown version)"); } else { nbtPi.incrementFeature(child.name, child.valueAsString); } contentIndex.insert(child.name + "==" + child.valueAsString, projectItem.projectPath, ContentIndex_1.AnnotationCategory.worldProperty); } } } } items.push(new ProjectInfoItem_1.default(IInfoItemData_1.InfoItemType.info, this.id, WorldDataInfoGeneratorTest.chunks, ProjectInfoUtilities_1.default.getTitleFromEnum(WorldDataInfoGeneratorTest, WorldDataInfoGeneratorTest.chunks), projectItem, mcworld.chunkCount, mcworld.name)); let blockCount = 0; let chunkCount = 0; let subchunkLessChunkCount = 0; for (const dimIndex in mcworld.chunks) { let dim = mcworld.chunks[dimIndex]; for (const chunkSliverIndex in dim) { const chunkSliver = dim[chunkSliverIndex]; if (chunkSliver) { for (const chunkId in chunkSliver) { const chunk = chunkSliver[chunkId]; if (chunk) { chunkCount++; if (chunk.subChunks.length <= 0) { subchunkLessChunkCount++; } if (chunkCount % 1000 === 0) { await projectItem.project.carto.notifyStatusUpdate("World data validation: scanned " + chunkCount / 1000 + "K of " + Math.floor(mcworld.chunkCount / 1000) + "K chunks in " + mcworld.name, Status_1.StatusTopic.validation); } const blockActors = chunk.blockActors; for (let i = 0; i < blockActors.length; i++) { const blockActor = blockActors[i]; if (blockActor.id) { blockActorsPi.incrementFeature(blockActor.id); } if (blockActor instanceof CommandBlockActor_1.default) { let cba = blockActor; if (cba.version) { blockActorsPi.spectrumIntFeature("Command Version", cba.version); } if (cba.version && cba.version < this.modernCommandVersion) { items.push(new ProjectInfoItem_1.default(IInfoItemData_1.InfoItemType.recommendation, this.id, WorldDataInfoGeneratorTest.commandIsFromOlderMinecraftVersion, "Command '" + cba.command + "' is from an older Minecraft version (" + cba.version + ") ", projectItem, "(Command at location " + cba.x + ", " + cba.y + ", " + cba.z + ")", undefined, cba.command)); } if (cba.command && cba.command.trim().length > 2) { let command = CommandStructure_1.default.parse(cba.command); if (CommandRegistry_1.default.isMinecraftBuiltInCommand(command.name)) { if (this.performAddOnValidations && CommandRegistry_1.default.isAddOnBlockedCommand(command.name)) { items.push(new ProjectInfoItem_1.default(IInfoItemData_1.InfoItemType.warning, this.id, WorldDataInfoGeneratorTest.containsWorldImpactingCommand, "Contains command '" + command.name + "' which is impacts the state of the entire world, and generally shouldn't be used in an add-on", projectItem, command.name, undefined, cba.command)); } commandsPi.incrementFeature(command.name); if (command.name === "execute") { let foundRun = false; for (const arg of command.commandArguments) { if (arg === "run") { foundRun = true; } else if (foundRun && CommandRegistry_1.default.isMinecraftBuiltInCommand(arg)) { subCommandsPi.incrementFeature(arg); break; } } } } else if (!this.performAddOnValidations && !this.performPlatformVersionValidations) { items.push(new ProjectInfoItem_1.default(IInfoItemData_1.InfoItemType.error, this.id, WorldDataInfoGeneratorTest.unexpectedCommandInCommandBlock, "Unexpected command '" + command.name + "'", projectItem, command.name, undefined, cba.command)); } } } } const blockList = chunk.getBlockList(); for (let i = 0; i < blockList.length; i++) { const block = blockList[i]; if (block) { blockCount++; if (block.typeName) { let type = block.typeName; if (type.indexOf(":") >= 0 && type.indexOf("minecraft:") < 0) { type = "(custom)"; } blocksPi.incrementFeature(type); } } } chunk.clearCachedData(); } } } } } blocksPi.data = blockCount; items.push(new ProjectInfoItem_1.default(IInfoItemData_1.InfoItemType.info, this.id, WorldDataInfoGeneratorTest.minX, ProjectInfoUtilities_1.default.getTitleFromEnum(WorldDataInfoGeneratorTest, WorldDataInfoGeneratorTest.minX), projectItem, mcworld.minX, mcworld.name)); items.push(new ProjectInfoItem_1.default(IInfoItemData_1.InfoItemType.info, this.id, WorldDataInfoGeneratorTest.minZ, ProjectInfoUtilities_1.default.getTitleFromEnum(WorldDataInfoGeneratorTest, WorldDataInfoGeneratorTest.minZ), projectItem, mcworld.minZ, mcworld.name)); items.push(new ProjectInfoItem_1.default(IInfoItemData_1.InfoItemType.info, this.id, WorldDataInfoGeneratorTest.maxX, ProjectInfoUtilities_1.default.getTitleFromEnum(WorldDataInfoGeneratorTest, WorldDataInfoGeneratorTest.maxX), projectItem, mcworld.maxX, mcworld.name)); items.push(new ProjectInfoItem_1.default(IInfoItemData_1.InfoItemType.info, this.id, WorldDataInfoGeneratorTest.maxZ, ProjectInfoUtilities_1.default.getTitleFromEnum(WorldDataInfoGeneratorTest, WorldDataInfoGeneratorTest.maxZ), projectItem, mcworld.maxZ, mcworld.name)); items.push(new ProjectInfoItem_1.default(IInfoItemData_1.InfoItemType.info, this.id, WorldDataInfoGeneratorTest.subchunklessChunks, "Subchunkless Chunks", projectItem, subchunkLessChunkCount, mcworld.name)); } return items; } } exports.default = WorldDataInfoGenerator; //# sourceMappingURL=../maps/info/WorldDataInfoGenerator.js.map