UNPKG

@minecraft/creator-tools

Version:

Minecraft Creator Tools command line and libraries.

434 lines (402 loc) 13.3 kB
// Copyright (c) Mojang AB. All rights reserved. import { VECTOR3_ZERO } from "@minecraft/math"; import { ActionTypes, EditorInputContext, IModalTool, IObservable, IPlayerUISession, InputModifier, KeyboardKey, MouseActionType, MouseInputType, MouseProps, Ray, makeObservable, registerEditorExtension, } from "@minecraft/server-editor"; import { Player, Vector3 } from "@minecraft/server"; import { MinecraftBlockTypes, MinecraftEntityTypes } from "@minecraft/vanilla-data"; type CommonSettingsType = { farmWidth: IObservable<number>; farmLength: IObservable<number>; irrigation: IObservable<boolean>; fenceType: IObservable<number>; }; type CropSettingsType = { wheat: IObservable<boolean>; pumpkin: IObservable<boolean>; potato: IObservable<boolean>; carrot: IObservable<boolean>; beetroot: IObservable<boolean>; }; type AnimalSettingsType = { pig: IObservable<boolean>; sheep: IObservable<boolean>; cow: IObservable<boolean>; }; function getRandomInt(upper: number) { return Math.floor(Math.random() * (upper + 1)); } function fenceTypeToBlockType(fenceType: number): string { switch (fenceType) { case 0: return MinecraftBlockTypes.OakFence; case 1: return MinecraftBlockTypes.BirchFence; case 2: return MinecraftBlockTypes.AcaciaFence; case 3: return MinecraftBlockTypes.BambooFence; case 4: return MinecraftBlockTypes.CherryFence; case 5: return MinecraftBlockTypes.JungleFence; case 6: return MinecraftBlockTypes.SpruceFence; case 7: return MinecraftBlockTypes.WarpedFence; case 8: return MinecraftBlockTypes.CrimsonFence; default: return MinecraftBlockTypes.OakFence; } } const buildFarm = ( targetCorner: Vector3, x: number, z: number, length: number, width: number, possibleAnimals: MinecraftEntityTypes[], possibleCrops: string[], player: Player, commonSettings: CommonSettingsType ) => { let didPlaceAnimal = false; for (let i = 0; i < width; i++) { for (let j = length - 1; j > -1; j--) { const xOffset = i * x; const zOffset = z * j; const location: Vector3 = { x: targetCorner.x + xOffset, y: targetCorner.y, z: targetCorner.z + zOffset }; const locationAbove: Vector3 = { x: targetCorner.x + xOffset, y: targetCorner.y + 1, z: targetCorner.z + zOffset, }; const block = player.dimension.getBlock(location); const blockAbove = player.dimension.getBlock(locationAbove); const isBorder = i === 0 || i === width - 1 || j === 0 || j === length - 1; if (xOffset % 3 === 0 && !isBorder && commonSettings.irrigation.value) { block?.setType(MinecraftBlockTypes.Water); } else { block?.setType(MinecraftBlockTypes.Farmland); } if (isBorder) { blockAbove?.setType(fenceTypeToBlockType(commonSettings.fenceType.value)); } else if (possibleAnimals.length > 0 && getRandomInt(5) === 5) { const animal = getRandomInt(possibleAnimals.length - 1); const entityType = possibleAnimals[animal]; player.dimension.spawnEntity(entityType, blockAbove?.location ?? VECTOR3_ZERO, { initialPersistence: true, }); didPlaceAnimal = true; } else if (!block?.isLiquid && possibleCrops.length > 0) { const crop = getRandomInt(possibleCrops.length - 1); const blockType = possibleCrops[crop]; blockAbove?.setType(blockType); } } } // Guarantee there is at least one animal spawned if we haven't placed one yet and there is room to place one if (!didPlaceAnimal && possibleAnimals.length > 0 && width > 2 && length > 2) { const locationAbove: Vector3 = { x: targetCorner.x + x, y: targetCorner.y + 1, z: targetCorner.z + z, }; const blockAbove = player.dimension.getBlock(locationAbove); const animal = getRandomInt(possibleAnimals.length - 1); const entityType = possibleAnimals[animal]; player.dimension.spawnEntity(entityType, blockAbove?.location ?? VECTOR3_ZERO, { initialPersistence: true }); } }; function addFarmGeneratorSettingsPane(uiSession: IPlayerUISession, tool: IModalTool) { const windowPane = uiSession.createPropertyPane({ title: "sample.farmgenerator.pane.title", infoTooltip: { description: [ "sample.farmgenerator.tool.tooltip", { link: "https://aka.ms/BedrockEditorFarmGenerator", text: "resourcePack.editor.help.learnMore" }, ], }, }); const cropPane = windowPane.createSubPane({ title: "sample.farmgenerator.pane.crops.title", }); const animalPane = windowPane.createSubPane({ title: "sample.farmgenerator.pane.animals.title", }); const commonSettings: CommonSettingsType = { farmWidth: makeObservable(10), farmLength: makeObservable(10), irrigation: makeObservable(false), fenceType: makeObservable(0), }; const cropSettings: CropSettingsType = { wheat: makeObservable(false), pumpkin: makeObservable(false), potato: makeObservable(false), carrot: makeObservable(false), beetroot: makeObservable(false), }; const animalSettings: AnimalSettingsType = { pig: makeObservable(false), sheep: makeObservable(false), cow: makeObservable(false), }; const onExecuteGenerator = (ray?: Ray) => { const player: Player = uiSession.extensionContext.player; // Use the mouse ray if it is available const raycastResult = ray !== undefined ? player.dimension.getBlockFromRay(ray.location, ray.direction) : player.getBlockFromViewDirection(); if (!raycastResult) { uiSession.log.error("No block from view vector"); return; } const targetBlock = raycastResult.block; let targetCorner: Vector3 = { x: targetBlock.location.x, y: targetBlock.location.y, z: targetBlock.location.z }; const possibleCrops: string[] = []; if (cropSettings.beetroot.value) { possibleCrops.push(MinecraftBlockTypes.Beetroot); } if (cropSettings.carrot.value) { possibleCrops.push(MinecraftBlockTypes.Carrots); } if (cropSettings.pumpkin.value) { possibleCrops.push(MinecraftBlockTypes.Pumpkin); } if (cropSettings.wheat.value) { possibleCrops.push(MinecraftBlockTypes.Wheat); } if (cropSettings.potato.value) { possibleCrops.push(MinecraftBlockTypes.Potatoes); } const possibleAnimals: MinecraftEntityTypes[] = []; if (animalSettings.sheep.value) { possibleAnimals.push(MinecraftEntityTypes.Sheep); } if (animalSettings.cow.value) { possibleAnimals.push(MinecraftEntityTypes.Cow); } if (animalSettings.pig.value) { possibleAnimals.push(MinecraftEntityTypes.Pig); } let x = 1; let z = 1; let length = commonSettings.farmLength.value; let width = commonSettings.farmWidth.value; if (Math.round(player.getViewDirection().z) === -1) { targetCorner = { x: targetCorner.x + (commonSettings.farmWidth.value / 2 - 1), y: targetCorner.y, z: targetCorner.z - (commonSettings.farmLength.value / 2 - 1), }; uiSession.log.info("Facing north"); x = -1; } else if (Math.round(player.getViewDirection().x) === 1) { targetCorner = { x: targetCorner.x + (commonSettings.farmWidth.value / 2 - 1), y: targetCorner.y, z: targetCorner.z + (commonSettings.farmLength.value / 2 - 1), }; uiSession.log.info("Facing east"); length = commonSettings.farmWidth.value; width = commonSettings.farmLength.value; x = -1; z = -1; } if (Math.round(player.getViewDirection().z) === 1) { targetCorner = { x: targetCorner.x - (commonSettings.farmWidth.value / 2 - 1), y: targetCorner.y, z: targetCorner.z + (commonSettings.farmLength.value / 2 - 1), }; uiSession.log.info("Facing south"); z = -1; } else if (Math.round(player.getViewDirection().x) === -1) { targetCorner = { x: targetCorner.x - (commonSettings.farmWidth.value / 2 - 1), y: targetCorner.y, z: targetCorner.z - (commonSettings.farmLength.value / 2 - 1), }; uiSession.log.info("Facing west"); length = commonSettings.farmWidth.value; width = commonSettings.farmLength.value; } buildFarm(targetCorner, x, z, length, width, possibleAnimals, possibleCrops, player, commonSettings); }; // Create an action that will be executed on left mouse click const executeMouseAction = uiSession.actionManager.createAction({ actionType: ActionTypes.MouseRayCastAction, onExecute: (mouseRay: Ray, mouseProps: MouseProps) => { if (mouseProps.mouseAction === MouseActionType.LeftButton && mouseProps.inputType === MouseInputType.ButtonDown) { onExecuteGenerator(mouseRay); } }, }); // Create and an action that will be executed on CTRL + P const executeKeyAction = uiSession.actionManager.createAction({ actionType: ActionTypes.NoArgsAction, onExecute: () => { onExecuteGenerator(); }, }); // Register actions as input bindings to tool context tool.registerKeyBinding( executeKeyAction, { key: KeyboardKey.KEY_P, modifier: InputModifier.Control }, { uniqueId: "editorSamples:farmGenerator:place", label: "sample.farmgenerator.keyBinding.place", } ); tool.registerMouseButtonBinding(executeMouseAction); windowPane.addNumber(commonSettings.farmLength, { title: "sample.farmgenerator.pane.length", min: 2, max: 20, isInteger: true, }); windowPane.addNumber(commonSettings.farmWidth, { title: "sample.farmgenerator.pane.width", min: 2, max: 20, isInteger: true, }); windowPane.addDropdown(commonSettings.fenceType, { title: "sample.farmgenerator.pane.fence", enable: true, entries: [ { label: "Oak", value: 0, }, { label: "Birch", value: 1, }, { label: "Acacia", value: 2, }, { label: "Bamboo", value: 3, }, { label: "Cherry", value: 4, }, { label: "Jungle", value: 5, }, { label: "Spruce", value: 6, }, { label: "Warped", value: 7, }, { label: "Crimson", value: 8, }, ], }); windowPane.addBool(commonSettings.irrigation, { title: "sample.farmgenerator.pane.irrigation", tooltip: "sample.farmgenerator.pane.irrigation.tooltip", }); cropPane.addBool(cropSettings.wheat, { title: "sample.farmgenerator.pane.crops.wheat", }); cropPane.addBool(cropSettings.potato, { title: "sample.farmgenerator.pane.crops.potato", }); cropPane.addBool(cropSettings.beetroot, { title: "sample.farmgenerator.pane.crops.beets", }); cropPane.addBool(cropSettings.pumpkin, { title: "sample.farmgenerator.pane.crops.pumpkin", }); cropPane.addBool(cropSettings.carrot, { title: "sample.farmgenerator.pane.crops.carrot", }); animalPane.addBool(animalSettings.cow, { title: "sample.farmgenerator.pane.animals.cow", }); animalPane.addBool(animalSettings.sheep, { title: "sample.farmgenerator.pane.animals.sheep", }); animalPane.addBool(animalSettings.pig, { title: "sample.farmgenerator.pane.animals.pig", }); tool.bindPropertyPane(windowPane); } /** * Create a new tool rail item for farm generator */ function addFarmGeneratorTool(uiSession: IPlayerUISession) { // Create action const toolToggleAction = uiSession.actionManager.createAction({ actionType: ActionTypes.NoArgsAction, onExecute: () => { uiSession.toolRail.setSelectedToolId(tool.id); }, }); const tool = uiSession.toolRail.addTool("editorSample:farmTool", { title: "sample.farmgenerator.tool.title", icon: "pack://textures/farm-generator.png", tooltip: "sample.farmgenerator.tool.tooltip", action: toolToggleAction, }); // Register a global shortcut (CTRL + SHIFT + P) to select the tool uiSession.inputManager.registerKeyBinding( EditorInputContext.GlobalToolMode, toolToggleAction, { key: KeyboardKey.KEY_F, modifier: InputModifier.Control | InputModifier.Shift }, { uniqueId: "editorSamples:farmGenerator:toggleTool", label: "sample.farmgenerator.keyBinding.toggleTool", } ); return tool; } /** * Register Farm Generator extension */ export function registerFarmGeneratorExtension() { registerEditorExtension( "FarmGenerator-sample", (uiSession: IPlayerUISession) => { uiSession.log.debug(`Initializing [${uiSession.extensionContext.extensionInfo.name}] extension`); // Add tool to tool rail const farmGeneratorTool = addFarmGeneratorTool(uiSession); // Create settings pane/window addFarmGeneratorSettingsPane(uiSession, farmGeneratorTool); return []; }, (uiSession: IPlayerUISession) => { uiSession.log.debug(`Initializing [${uiSession.extensionContext.extensionInfo.name}] extension`); }, { description: '"Farm Generator" Sample Extension', notes: "by Molly", } ); }