Path: blob/master/src/editor/modules/brushes/index.ts
1785 views
import {1CursorControlMode,2CursorTargetMode,3ActionTypes,4EditorInputContext,5KeyboardKey,6InputModifier,7MouseActionType,8MouseInputType,9LogChannel,10PaintCompletionState,11IPlayerUISession,12IModalTool,13IRootPropertyPane,14CursorProperties,15} from "@minecraft/server-editor";16import { EditorModule } from "../base";17import { getInputMarkup } from "./util";18import { getEditorBrushManager } from "./manager";19import { brushTypes } from "server/brushes/base_brush";20import { CursorModeControl } from "editor/control";21import { BrushPaintSharedControl } from "./control";2223export class BrushPainterModule extends EditorModule {24private readonly tool: IModalTool;25private readonly rootPane: IRootPropertyPane;2627private readonly cursorProperties: CursorProperties;28private readonly cursorModeControl: CursorModeControl;29private readonly brushControl: BrushPaintSharedControl;3031private paintingActive = false;3233constructor(session: IPlayerUISession) {34super(session);35this.cursorProperties = {36outlineColor: {37red: 0,38green: 0.5,39blue: 0.5,40alpha: 0.2,41},42controlMode: CursorControlMode.KeyboardAndMouse,43targetMode: CursorTargetMode.Block,44visible: true,45};46const activationAction = this.session.actionManager.createAction({47actionType: ActionTypes.NoArgsAction,48onExecute: () => this.session.toolRail.setSelectedToolId(this.tool.id),49});50this.tool = this.session.toolRail.addTool("worldedit:modalTool:brushPainter", {51title: "resourcePack.editor.brushPaint.title",52icon: "pack://textures/editor/Brush.png?filtering=point",53action: activationAction,54});55this.session.inputManager.registerKeyBinding(56EditorInputContext.GlobalToolMode,57activationAction,58{59key: KeyboardKey.KEY_B,60modifier: InputModifier.Control,61},62{63uniqueId: "worldedit:toolModeKeyBinding:toggleBrushMode",64label: "resourcePack.editor.brushPaint.inputContext.activateBrushPaint.title",65tooltip: "resourcePack.editor.brushPaint.inputContext.activateBrushPaint.tooltip",66}67);68this.rootPane = this.session.createPropertyPane({69title: "resourcePack.editor.brushPaint.title",70infoTooltip: {71description: [72{73id: "resourcePack.editor.brushPaint.tool.tooltip",74props: [getInputMarkup("worldedit:toolModeKeyBinding:togglePencilBrushMode")],75},76],77},78});79this.tool.bindPropertyPane(this.rootPane);80this.cursorModeControl = new CursorModeControl(this.session, this.tool, this.rootPane, true, this.cursorProperties);81this.cursorModeControl.initialize();82this.brushControl = new BrushPaintSharedControl(83this.session,84this.tool,85this.rootPane,86Array.from(brushTypes.keys()).filter((type) => type !== "structure_brush")87);88this.brushControl.initialize();89this.tool.onModalToolActivation.subscribe((data) => {90if (data.isActiveTool) {91this.cursorModeControl.activateControl();92this.brushControl.activateControl();93} else {94this.onLeave();95}96});97this.registerMouseUpDownAction();98this.registerKeyboardInputActions();99}100101teardown() {102this.onLeave();103this.cursorModeControl.shutdown();104this.brushControl.shutdown();105}106107private registerMouseUpDownAction() {108const action = this.session.actionManager.createAction({109actionType: ActionTypes.MouseRayCastAction,110onExecute: (_mouseRay, mouseProps) => {111if (mouseProps.mouseAction !== MouseActionType.LeftButton) return;112113// FIXME: There are circumstances where paintingActive is false on mouse release.114if (mouseProps.inputType === MouseInputType.ButtonDown) {115this.beginPainting();116} else if (mouseProps.inputType === MouseInputType.ButtonUp && this.paintingActive) {117this.endPainting();118}119},120});121this.tool.registerMouseButtonBinding(action);122}123124private registerKeyboardInputActions() {125const singlePressPaintAction = this.session.actionManager.createAction({126actionType: ActionTypes.NoArgsAction,127onExecute: () => {128if (this.paintingActive) return;129getEditorBrushManager(this.session).singlePaint((state) => {130if (state !== PaintCompletionState.Success) {131this.session.log.error(`Error during painting`, { channelMask: LogChannel.All });132}133this.paintingActive = false;134});135},136});137this.tool.registerKeyBinding(138singlePressPaintAction,139{ key: KeyboardKey.ENTER },140{141uniqueId: "worldedit:brushPainter:paintAtCursor",142label: "resourcePack.editor.brushPaint.inputContext.oneshot.title",143tooltip: "resourcePack.editor.brushPaint.inputContext.oneshot.tooltip",144}145);146}147148private beginPainting() {149if (getEditorBrushManager(this.session).isBrushPaintBusy() || this.session.extensionContext.transactionManager.isBusy()) {150this.session.log.warning(`Brush already active`);151return;152}153this.paintingActive = true;154getEditorBrushManager(this.session).beginPainting((state) => {155if (state !== PaintCompletionState.Success) {156this.session.log.error(`Error during painting`, {157channelMask: LogChannel.All,158});159}160this.paintingActive = false;161});162}163164private endPainting() {165this.paintingActive = false;166getEditorBrushManager(this.session).endPainting(false);167}168169private onLeave() {170if (this.paintingActive) this.endPainting();171if (this.cursorModeControl.isActive) this.cursorModeControl.deactivateControl();172if (this.brushControl.isActive) this.brushControl.deactivateControl();173}174}175176177