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