diff --git a/src/lib/weak-player-storage.ts b/src/lib/weak-player-storage.ts index d1c54261..6b967e8a 100644 --- a/src/lib/weak-player-storage.ts +++ b/src/lib/weak-player-storage.ts @@ -79,6 +79,7 @@ interface WeakStorageOptions { function createWeakStorage(storage: WeakStorage, options?: WeakStorageOptions) { if (options?.removeOnLeave ?? true) weakStorages.push(storage) if (options?.onLeave) storage.onLeave = options.onLeave + if (options?.onDelete) storage.onDelete = options.onDelete } const weakStorages: WeakStorage[] = [] diff --git a/src/modules/world-edit/builder.ts b/src/modules/world-edit/builder.ts index cca4971d..93b0f2e6 100644 --- a/src/modules/world-edit/builder.ts +++ b/src/modules/world-edit/builder.ts @@ -3,7 +3,7 @@ import { InventoryStore } from 'lib/database/inventory' import { CURRENT_BUILDERS, isBuilding } from 'lib/game-utils' import { Join } from 'lib/player-join' -const builderInventory = new InventoryStore('build') +const builderInventory = new InventoryStore('build2') Join.onMoveAfterJoin.subscribe(({ player }) => { // First time set diff --git a/src/modules/world-edit/lib/world-edit-multi-tool.ts b/src/modules/world-edit/lib/world-edit-multi-tool.ts index 10e50c7c..c0382f57 100644 --- a/src/modules/world-edit/lib/world-edit-multi-tool.ts +++ b/src/modules/world-edit/lib/world-edit-multi-tool.ts @@ -1,9 +1,9 @@ import { ContainerSlot, ItemStack, Player } from '@minecraft/server' -import { ArrayForm, BUTTON, ModalForm, prompt } from 'lib' +import { ArrayForm, BUTTON, doNothing, ModalForm, prompt } from 'lib' import { t } from 'lib/text' import { WorldEditTool } from './world-edit-tool' -interface ToolsDataStorage { +export interface ToolsDataStorage { /** Version */ version: number @@ -106,20 +106,17 @@ export abstract class WorldEditMultiTool extends WorldEditTool } private selectToolForm(slot: ContainerSlot, player: Player, toolsData: ToolData[], back: VoidFunction) { + const select = (tool: WorldEditTool) => () => { + const toolData: ToolData = { name: `T#: ${tool.name}`, tpid: tool.id } + toolsData.push(toolData) + this.editOneToolForm(slot, player, toolsData, toolData, tool, back) + } + + if (this.tools.length === 0) return select(this.tools[0]) + new ArrayForm('Тип инструмента', this.tools) .back(back) - .button(tool => { - return [ - tool.name, - () => { - const toolData: ToolData = { name: `T#: ${tool.name}`, tpid: tool.id } - toolsData.push(toolData) - this.editOneToolForm(slot, player, toolsData, toolData, tool, () => - this.selectToolForm(slot, player, toolsData, back), - ) - }, - ] - }) + .button(tool => [tool.name, select.bind(undefined, tool)]) .show(player) } @@ -148,35 +145,27 @@ export abstract class WorldEditMultiTool extends WorldEditTool tool: WorldEditTool, back: VoidFunction, ) { - const proxiedTool = this.proxyTool(tool, toolData) + const onBack = () => (back(), this.updateItemSlot(slot, toolsData)) + const proxiedTool = this.proxyTool(tool, toolData, slot, toolsData, onBack) if (!proxiedTool.editToolForm) return player.fail('Инструмент неизменяем') - const onBack = () => (back(), this.updateItemSlot(slot, toolsData)) - proxiedTool.editToolForm(this.proxySlot(slot, toolsData, toolData, onBack), player) + proxiedTool.editToolForm(this.proxySlot(toolData) as ContainerSlot, player) } forEachTool( slot: T, - callback: (proxiedSlot: T, proxiedTool: WorldEditTool) => void, + callback: (proxiedSlot: T, tool: WorldEditTool, toolData: ToolData) => void, + toolsData = this.getToolsData(slot), ) { - const toolsData = this.getToolsData(slot) - for (const item of toolsData) { - const itemTool = this.getToolByData(item) - if (!itemTool) continue - - const proxiedTool = this.proxyTool(itemTool, item) - const proxiedSlot = this.proxySlot(slot, toolsData, item) + for (const toolData of toolsData) { + const tool = this.getToolByData(toolData) + if (!tool) continue - callback(proxiedSlot, proxiedTool) + callback(this.proxySlot(toolData) as typeof slot, tool, toolData) } } - proxySlot( - slot: T, - toolsData: ToolData[], - toolData: ToolData, - back?: VoidFunction, - ): T { + proxySlot(toolData: ToolData) { return { get nameTag() { return toolData.name @@ -184,30 +173,35 @@ export abstract class WorldEditMultiTool extends WorldEditTool set nameTag(name) { toolData.name = name }, - setLore: () => { - // Set lore always happens last, so save all data - if (slot instanceof ContainerSlot) this.saveToolsData(slot, toolsData) - back?.() - }, - getLore() { - return [] - }, - } satisfies Partial as unknown as T + setLore: doNothing, + getLore: () => [], + } satisfies Partial as unknown as ContainerSlot | ItemStack } - proxyTool(tool: WorldEditTool, toolSettings: ToolData) { + proxyTool( + tool: WorldEditTool, + toolData: ToolData, + slot: ContainerSlot | ItemStack, + tools: ToolData[], + back?: VoidFunction, + ) { + const save = () => { + slot instanceof ContainerSlot && this.saveToolsData(slot, tools) + back?.() + } return Object.setPrototypeOf( { getStorage(_, returnUndefined) { - if (toolSettings.d) { - return toolSettings.d + if (toolData.d) { + return toolData.d } else { if (returnUndefined) return undefined return JSON.parse(JSON.stringify(this.storageSchema)) as object } }, saveStorage(_, storage: object) { - toolSettings.d = storage + toolData.d = storage + save() }, } satisfies Partial, tool, diff --git a/src/modules/world-edit/lib/world-edit-tool-brush.ts b/src/modules/world-edit/lib/world-edit-tool-brush.ts index 81febb75..119f9823 100644 --- a/src/modules/world-edit/lib/world-edit-tool-brush.ts +++ b/src/modules/world-edit/lib/world-edit-tool-brush.ts @@ -1,4 +1,4 @@ -import { BlockRaycastHit, ContainerSlot, ItemStack, Player } from '@minecraft/server' +import { BlockRaycastHit, ItemStack, Player } from '@minecraft/server' import { isInvalidLocation } from 'lib' import stringifyError from 'lib/utils/error' import { worldEditPlayerSettings } from 'modules/world-edit/settings' @@ -17,15 +17,8 @@ interface BrushStorage { export abstract class WorldEditToolBrush extends WorldEditTool { abstract onBrushUse(player: Player, lore: BrushStorage & MoreStorage, hit: BlockRaycastHit): void - override isOurItemType(lore: ItemStack | ContainerSlot | (BrushStorage & MoreStorage)) { - if (lore instanceof ItemStack || lore instanceof ContainerSlot) { - if (!super.isOurItemType(lore)) return false - lore = this.getStorage(lore) - } - - if (lore.type !== this.storageSchema.type) return false - - return true + isOurBrush(storage: BrushStorage & MoreStorage) { + return storage.type === this.storageSchema.type } override onUse(player: Player, item: ItemStack) { @@ -33,7 +26,7 @@ export abstract class WorldEditToolBrush extends Wor if (settings.enableMobile) return const storage = this.getStorage(item) - if (!this.isOurItemType(storage)) return + if (!this.isOurBrush(storage)) return const hit = player.getBlockFromViewDirection({ maxDistance: storage.maxDistance }) const fail = (reason: string) => player.fail(`§7Кисть§f: §c${reason}`) diff --git a/src/modules/world-edit/lib/world-edit-tool.ts b/src/modules/world-edit/lib/world-edit-tool.ts index fefe7aa9..a7b0be73 100644 --- a/src/modules/world-edit/lib/world-edit-tool.ts +++ b/src/modules/world-edit/lib/world-edit-tool.ts @@ -4,9 +4,9 @@ import { textTable } from 'lib/text' import { BlocksSetRef, stringifyBlocksSetRef } from 'modules/world-edit/utils/blocks-set' import { worldEditPlayerSettings } from '../settings' -export type WorldEditToolInterval = ( - this: Tool, +export type WorldEditToolInterval = ( player: Player, + storage: T, slot: ContainerSlot, settings: ReturnType, ) => void @@ -34,21 +34,28 @@ type StorageType = Partial> & { export abstract class WorldEditTool { static loreBlockRefKeys: string[] = ['blocksSet', 'replaceBlocksSet'] satisfies StorageKey[] static tools: WorldEditTool[] = [] - static intervals: OmitThisParameter>[] = [] abstract id: string abstract name: string abstract typeId: string abstract storageSchema: Storage - command?: Command + private command?: Command editToolForm?(this: WorldEditTool, slot: ContainerSlot, player: Player, initial?: boolean): void - onUse?(player: Player, item: ItemStack): void + onUse?(player: Player, item: ItemStack, storage: Storage): void - interval0?: WorldEditToolInterval - interval10?: WorldEditToolInterval - interval20?: WorldEditToolInterval + onGlobalInterval(ticks: 'global', interval: WorldEditToolInterval): void { + this[`interval${ticks}`] = interval + } + onInterval(ticks: 0 | 10 | 20, interval: WorldEditToolInterval): void { + this[`interval${ticks}`] = interval + } + + interval0?: WorldEditToolInterval + interval10?: WorldEditToolInterval + interval20?: WorldEditToolInterval + intervalglobal?: WorldEditToolInterval constructor() { WorldEditTool.tools.push(this) @@ -73,7 +80,13 @@ export abstract class WorldEditTool { } isOurItemType(slot: ContainerSlot | ItemStack) { - return slot.typeId === this.typeId && !!this.getStorage(slot, true) + return ( + slot.typeId === this.typeId && + // Has our storage + (!!this.getStorage(slot, true) || + // Or doesnt have storage at all + slot.getDynamicPropertyIds().length === 0) + ) } getToolSlot(player: Player) { @@ -100,10 +113,6 @@ export abstract class WorldEditTool { const empty = !slot.typeId const color = our ? '§a' : empty ? '' : '§8' - if (our) { - console.log({ id: this.id, abc: !!this.getStorage(slot, true) }) - } - return `${color}${our ? 'Редактировать' : 'Создать'} ${this.name}` } @@ -131,7 +140,7 @@ export abstract class WorldEditTool { getStorage(slot: ContainerSlot | ItemStack, returnUndefined = false): Storage | undefined { const property = slot.getDynamicProperty(this.storageProperty) const propertyParsed = typeof property === 'string' ? this.parse(property, true) : undefined - return propertyParsed ?? this.parseLore(slot.getLore(), returnUndefined as true) + return propertyParsed ?? this.parseLore(slot, returnUndefined as true) } saveStorage(slot: ContainerSlot | ItemStack, storage: Storage, writeLore = true) { @@ -152,11 +161,12 @@ export abstract class WorldEditTool { } /** @deprecated */ - private parseLore(lore: string[], returnUndefined?: false): Storage - /** @deprecated */ - private parseLore(lore: string[], returnUndefined: true): Storage | undefined - /** @deprecated */ - private parseLore(lore: string[], returnUndefined = false): Storage | undefined { + private parseLore(slot: ContainerSlot | ItemStack, returnUndefined = false): Storage | undefined { + let lore: string[] = [] + try { + lore = slot.getLore() + } catch {} + return this.parse( lore .slice(lore.findIndex(e => e.includes(LORE_SEPARATOR)) + 1) @@ -223,7 +233,7 @@ export abstract class WorldEditTool { WorldEditTool.tools .filter(tool => tool.onUse && tool.isOurItemType(item)) - .forEach(tool => util.catch(() => tool.onUse?.(player, item))) + .forEach(tool => util.catch(() => tool.onUse?.(player, item, tool.getStorage(item, true)))) }) } @@ -235,17 +245,21 @@ export abstract class WorldEditTool { for (const player of world.getAllPlayers()) { if (!player.isValid()) continue - const item = player.mainhand() - const tools = WorldEditTool.tools.filter(e => e.typeId === item.typeId) + const slot = player.mainhand() + const tools = WorldEditTool.tools.filter(e => e.typeId === slot.typeId) const settings = worldEditPlayerSettings(player) - WorldEditTool.intervals.forEach(e => e(player, item, settings)) + WorldEditTool.tools.forEach(tool => + util.catch(() => tool.intervalglobal?.(player, tool.getStorage(slot, true), slot, settings)), + ) for (const tool of tools) { - const fn: (undefined | OmitThisParameter>)[] = [tool.interval0?.bind(tool)] + const storage = tool.getStorage(slot, true) as unknown + if (!storage) continue + const fn: (undefined | OmitThisParameter>)[] = [tool.interval0?.bind(tool)] if (this.ticks % 10 === 0) fn.push(tool.interval10?.bind(tool)) if (this.ticks % 20 === 0) fn.push(tool.interval20?.bind(tool)) - fn.forEach(e => e?.(player, item, settings)) + fn.forEach(e => e && util.catch(() => e(player, storage, slot, settings))) } yield } diff --git a/src/modules/world-edit/tools/brush.ts b/src/modules/world-edit/tools/brush.ts index f69f71d9..9827ac0d 100644 --- a/src/modules/world-edit/tools/brush.ts +++ b/src/modules/world-edit/tools/brush.ts @@ -7,7 +7,6 @@ import { WeakPlayerMap } from 'lib/weak-player-storage' import { WE_CONFIG } from '../config' import { Cuboid } from '../lib/cuboid' import { WorldEdit } from '../lib/world-edit' -import { WorldEditTool, WorldEditToolInterval } from '../lib/world-edit-tool' import { WorldEditToolBrush } from '../lib/world-edit-tool-brush' import { skipForBlending } from '../utils/blending' import { @@ -145,36 +144,6 @@ class BrushTool extends WorldEditToolBrush { }) } - interval0: WorldEditToolInterval = (player, slot, settings) => { - const storage = this.getStorage(slot) - const hit = player.getBlockFromViewDirection({ - maxDistance: storage.maxDistance, - }) - - if (hit && !settings.noBrushParticles) { - const location = Vector.add(hit.block.location, { - x: 0.5, - y: 0, - z: 0.5, - }) - - if (!this.brushLocators.has(player.id)) { - try { - const entity = player.dimension.spawnEntity(CustomEntityTypes.FloatingText, location) - entity.addTag(player.name) - entity.nameTag = WE_CONFIG.BRUSH_LOCATOR - - this.brushLocators.set(player.id, entity) - } catch (error) { - if (isInvalidLocation(error)) return - console.error(error) - } - } else this.brushLocators.get(player.id)?.teleport(location) - } else { - this.brushLocators.delete(player.id) - } - } - ensureShape(player: Player, shape: string) { if (!isKeyof(shape, SHAPES)) { player.warn(t`Неизвестная кисть: ${shape}`) @@ -206,15 +175,36 @@ class BrushTool extends WorldEditToolBrush { type: CustomEntityTypes.FloatingText, name: WE_CONFIG.BRUSH_LOCATOR, }) - .forEach(e => e.remove()) - WorldEditTool.intervals.push((player, slot) => { + this.onGlobalInterval('global', (player, _, slot) => { if (slot.typeId !== this.typeId && this.brushLocators.has(player.id)) { - this.brushLocators.get(player)?.remove() this.brushLocators.delete(player) } }) + + this.onInterval(0, (player, storage, _, settings) => { + const hit = player.getBlockFromViewDirection({ maxDistance: storage.maxDistance }) + + if (hit && !settings.noBrushParticles) { + const location = Vector.add(hit.block.location, { x: 0.5, y: 0, z: 0.5 }) + + if (!this.brushLocators.has(player.id)) { + try { + const entity = player.dimension.spawnEntity(CustomEntityTypes.FloatingText, location) + entity.addTag(player.name) + entity.nameTag = WE_CONFIG.BRUSH_LOCATOR + + this.brushLocators.set(player.id, entity) + } catch (error) { + if (isInvalidLocation(error)) return + console.error(error) + } + } else this.brushLocators.get(player.id)?.teleport(location) + } else { + this.brushLocators.delete(player.id) + } + }) } brushLocators = new WeakPlayerMap({ diff --git a/src/modules/world-edit/tools/clipboard.ts b/src/modules/world-edit/tools/clipboard.ts index e96e56b8..8ebf9eb9 100644 --- a/src/modules/world-edit/tools/clipboard.ts +++ b/src/modules/world-edit/tools/clipboard.ts @@ -3,7 +3,7 @@ import { Items } from 'lib/assets/custom-items' import { ActionbarPriority } from 'lib/extensions/on-screen-display' import { spawnParticlesInArea } from 'modules/world-edit/config' import { WorldEdit } from 'modules/world-edit/lib/world-edit' -import { WorldEditTool, WorldEditToolInterval } from 'modules/world-edit/lib/world-edit-tool' +import { WorldEditTool } from 'modules/world-edit/lib/world-edit-tool' interface Storage { version: number @@ -34,20 +34,23 @@ class ClipboardTool extends WorldEditTool { else we.paste() } - interval20: WorldEditToolInterval = (player, slot) => { - if (this.getStorage(slot, true)?.mode !== 'paste') return - const we = WorldEdit.forPlayer(player) - - if (we.currentCopy) { - const { pastePos1, pastePos2 } = we.pastePositions(StructureRotation.None, we.currentCopy) - system.delay(() => spawnParticlesInArea(pastePos1, pastePos2)) - player.onScreenDisplay.setActionBar( - `Используйте предмет чтобы\n${ - player.isSneaking ? '<Отменить последнее действие>' : '<Вставить скопированную область>' - }`, - ActionbarPriority.UrgentNotificiation, - ) - } else player.onScreenDisplay.setActionBar('§cВы ничего не копировали!', ActionbarPriority.UrgentNotificiation) + constructor() { + super() + this.onInterval(20, (player, storage) => { + if (storage.mode !== 'paste') return + const we = WorldEdit.forPlayer(player) + + if (we.currentCopy) { + const { pastePos1, pastePos2 } = we.pastePositions(StructureRotation.None, we.currentCopy) + system.delay(() => spawnParticlesInArea(pastePos1, pastePos2)) + player.onScreenDisplay.setActionBar( + `Используйте предмет чтобы\n${ + player.isSneaking ? '<Отменить последнее действие>' : '<Вставить скопированную область>' + }`, + ActionbarPriority.UrgentNotificiation, + ) + } else player.onScreenDisplay.setActionBar('§cВы ничего не копировали!', ActionbarPriority.UrgentNotificiation) + }) } } diff --git a/src/modules/world-edit/tools/create-region.ts b/src/modules/world-edit/tools/create-region.ts index 01271b90..3ae2bc24 100644 --- a/src/modules/world-edit/tools/create-region.ts +++ b/src/modules/world-edit/tools/create-region.ts @@ -4,7 +4,7 @@ import { Items } from 'lib/assets/custom-items' import { ActionbarPriority } from 'lib/extensions/on-screen-display' import { SphereArea } from 'lib/region/areas/sphere' import { t } from 'lib/text' -import { WorldEditTool, WorldEditToolInterval } from '../lib/world-edit-tool' +import { WorldEditTool } from '../lib/world-edit-tool' interface Storage { version: number @@ -55,28 +55,31 @@ class RegionTool extends WorldEditTool { }) } - interval10: WorldEditToolInterval = (player, slot) => { - const storage = this.getStorage(slot) + constructor() { + super() - if (!storage.regionKind) return + this.onInterval(10, (player, storage) => { + if (!storage.regionKind) return - const createableRegion = createableRegions.find(e => e.region.kind === storage.regionKind) - if (!createableRegion) - return player.onScreenDisplay.setActionBar( - `§cUnknown region type: ${storage.regionKind}`, - ActionbarPriority.UrgentNotificiation, - ) + const createableRegion = createableRegions.find(e => e.region.kind === storage.regionKind) + if (!createableRegion) + return player.onScreenDisplay.setActionBar( + `§cUnknown region type: ${storage.regionKind}`, + ActionbarPriority.UrgentNotificiation, + ) - const regions = storage.minDistanceSameKind ? createableRegion.region.instances() : Region.regions - if (regions.some(r => r.area.isNear(player.location, storage.minDistance))) - return player.onScreenDisplay.setActionBar(`§7Рядом другие регионы`, ActionbarPriority.PvP) + const regions = storage.minDistanceSameKind ? createableRegion.region.instances() : Region.regions + if (regions.some(r => r.area.isNear(player.location, storage.minDistance))) + return player.onScreenDisplay.setActionBar(`§7Рядом другие регионы`, ActionbarPriority.PvP) + + createableRegion.region.create( + new SphereArea({ center: player.location, radius: storage.radius }, player.dimension.type), + ) - createableRegion.region.create( - new SphereArea({ center: player.location, radius: storage.radius }, player.dimension.type), - ) - const msg = t`§aРегион создан!` - player.success(msg) - player.onScreenDisplay.setActionBar(msg, ActionbarPriority.UrgentNotificiation) + const msg = t`§aРегион создан!` + player.success(msg) + player.onScreenDisplay.setActionBar(msg, ActionbarPriority.UrgentNotificiation) + }) } } diff --git a/src/modules/world-edit/tools/multi-brush.ts b/src/modules/world-edit/tools/multi-brush.ts index 68f09ffb..c1327fa1 100644 --- a/src/modules/world-edit/tools/multi-brush.ts +++ b/src/modules/world-edit/tools/multi-brush.ts @@ -1,7 +1,7 @@ import { Direction, ItemStack, Player } from '@minecraft/server' import { Vector } from 'lib' import { Items } from 'lib/assets/custom-items' -import { WorldEditMultiTool } from '../lib/world-edit-multi-tool' +import { ToolsDataStorage, WorldEditMultiTool } from '../lib/world-edit-multi-tool' import { WorldEditTool } from '../lib/world-edit-tool' import { weBrushTool } from './brush' @@ -11,40 +11,37 @@ class MultiBrushTool extends WorldEditMultiTool { name = 'Мульти-кисть' typeId = Items.WeBrush - onUse(player: Player, itemStack: ItemStack) { - this.forEachTool(itemStack, (proxiedItem, proxiedTool) => { - if (!proxiedTool.onUse) return + onUse(player: Player, itemStack: ItemStack, storage: ToolsDataStorage | undefined) { + this.forEachTool(itemStack, (proxiedItem, tool, toolData) => { + if (!tool.onUse) return - let proxiedPlayer = player - const storage = this.getStorage(itemStack, true) - - if (storage?.spread) { - const { spread } = storage - proxiedPlayer = Object.setPrototypeOf( - { - getBlockFromViewDirection(options) { - const hit = player.getBlockFromViewDirection(options) - if (hit) { - const half = spread / 2 - const rd = () => Math.randomInt(-half, half) - const location = Vector.add(hit.block, { x: rd(), y: rd(), z: rd() }) - const block = hit.block.dimension.getBlock(location) - if (!block) return - return { - block, - face: Direction.Down, - faceLocation: Vector.down, - } - } else return - }, - } satisfies Partial, - player, - ) as Player - } - - proxiedTool.onUse(proxiedPlayer, proxiedItem) + const proxiedPlayer = storage?.spread ? this.proxyPlayer(player, storage.spread) : player + tool.onUse(proxiedPlayer, proxiedItem, toolData) }) } + + private proxyPlayer(player: Player, spread: number): Player { + return Object.setPrototypeOf( + { + getBlockFromViewDirection(options) { + const hit = player.getBlockFromViewDirection(options) + if (hit) { + const half = spread / 2 + const rd = () => Math.randomInt(-half, half) + const location = Vector.add(hit.block, { x: rd(), y: rd(), z: rd() }) + const block = hit.block.dimension.getBlock(location) + if (!block) return + return { + block, + face: Direction.Down, + faceLocation: Vector.down, + } + } else return + }, + } satisfies Partial, + player, + ) as Player + } } new MultiBrushTool() diff --git a/src/modules/world-edit/tools/multi-shovel.ts b/src/modules/world-edit/tools/multi-shovel.ts index efcdfc7b..070ec3f4 100644 --- a/src/modules/world-edit/tools/multi-shovel.ts +++ b/src/modules/world-edit/tools/multi-shovel.ts @@ -1,6 +1,6 @@ import { Items } from 'lib/assets/custom-items' import { WorldEditMultiTool } from '../lib/world-edit-multi-tool' -import { WorldEditTool, WorldEditToolInterval } from '../lib/world-edit-tool' +import { WorldEditTool } from '../lib/world-edit-tool' import { weRegionTool } from './create-region' import { weShovelTool } from './shovel' @@ -11,9 +11,18 @@ class MultiShovelTool extends WorldEditMultiTool { name = 'Мульти-лопата' typeId = Items.WeShovel - interval10: WorldEditToolInterval = (player, slot, settings) => { - this.forEachTool(slot, (proxiedSlot, proxiedTool) => { - proxiedTool.interval10?.(player, proxiedSlot, settings) + constructor() { + super() + this.onInterval(10, (player, storage, slot, settings) => { + this.forEachTool( + slot, + (proxiedSlot, tool, toolStorage) => { + if (!tool.interval10) return + + tool.interval10(player, toolStorage.d, proxiedSlot, settings) + }, + storage.tools, + ) }) } } diff --git a/src/modules/world-edit/tools/randomizer.ts b/src/modules/world-edit/tools/randomizer.ts index 526aafe4..e988deef 100644 --- a/src/modules/world-edit/tools/randomizer.ts +++ b/src/modules/world-edit/tools/randomizer.ts @@ -9,11 +9,8 @@ import { BlocksSetRef, blocksSetDropdown, getBlocksInSet, stringifyBlocksSetRef class RandomizerTool extends WorldEditTool<{ blocksSet: BlocksSetRef; version: number }> { id = 'randomizer' - name = 'слуйчайный блок из набора' - typeId = Items.WeRandomizer - storageSchema = { version: 2, diff --git a/src/modules/world-edit/tools/shovel.ts b/src/modules/world-edit/tools/shovel.ts index 39ea00cb..f854f3e2 100644 --- a/src/modules/world-edit/tools/shovel.ts +++ b/src/modules/world-edit/tools/shovel.ts @@ -1,10 +1,10 @@ -import { ContainerSlot, ItemStack, Player, world } from '@minecraft/server' +import { ContainerSlot, Player, world } from '@minecraft/server' import { ModalForm, Vector } from 'lib' import { Items } from 'lib/assets/custom-items' import { ActionbarPriority } from 'lib/extensions/on-screen-display' import { t } from 'lib/text' import { WorldEdit } from 'modules/world-edit/lib/world-edit' -import { WorldEditTool, WorldEditToolInterval } from '../lib/world-edit-tool' +import { WorldEditTool } from '../lib/world-edit-tool' import { skipForBlending } from '../utils/blending' import { BlocksSetRef, @@ -85,56 +85,65 @@ class ShovelTool extends WorldEditTool { else storage.replaceBlocksSet = ['', ''] this.saveStorage(slot, storage) - player.success( t`${storage.blocksSet[0] ? 'Отредактирована' : 'Создана'} лопата с ${blocksSet} набором блоков и радиусом ${radius}`, ) }) } - interval10: WorldEditToolInterval = (player, slot) => { - const lookingUp = Math.round(player.getRotation().x) === -90 - if (lookingUp) return - - const storage = this.getStorage(slot, true) - if (!storage) return - - const permutations = getBlocksInSet(storage.blocksSet) - if (!permutations.length) - return player.onScreenDisplay.setActionBar('§cНабор блоков лопаты пустой!', ActionbarPriority.UrgentNotificiation) - - const { offset, radius, height } = storage - const replaceTargets = getReplaceTargets(storage.replaceBlocksSet) - const center = Vector.floor(player.location) - const from = Vector.add(center, new Vector(-radius, offset - height, -radius)) - const to = Vector.add(center, new Vector(radius, offset, radius)) + constructor() { + super() + this.onGlobalInterval('global', player => { + const { container } = player + if (!container) return + for (const [, item] of container.entries()) { + if (item?.typeId === this.typeId && this.isLookingUp(player)) { + const lookingUp = this.isLookingUp(player) + if (lookingUp) + return player.onScreenDisplay.setActionBar( + 'Лопата выключена,\nможно настраивать', + ActionbarPriority.UrgentNotificiation, + ) + } + } + }) + this.onInterval(10, (player, storage) => { + if (this.isLookingUp(player)) return + + const permutations = getBlocksInSet(storage.blocksSet) + if (!permutations.length) + return player.onScreenDisplay.setActionBar( + '§cНабор блоков лопаты пустой!', + ActionbarPriority.UrgentNotificiation, + ) - WorldEdit.forPlayer(player).backup( - `§eЛопата §7радиус §f${radius} §7высота §f${height} §7сдвиг §f${ - offset - }\n§7блоки: §f${stringifyBlockWeights(permutations.map(toReplaceTarget))}`, - from, - to, - ) + const { offset, radius, height } = storage + const replaceTargets = getReplaceTargets(storage.replaceBlocksSet) + const center = Vector.floor(player.location) + const from = Vector.add(center, new Vector(-radius, offset - height, -radius)) + const to = Vector.add(center, new Vector(radius, offset, radius)) + + WorldEdit.forPlayer(player).backup( + `§eЛопата §7радиус §f${radius} §7высота §f${height} §7сдвиг §f${ + offset + }\n§7блоки: §f${stringifyBlockWeights(permutations.map(toReplaceTarget))}`, + from, + to, + ) - for (const vector of Vector.foreach(from, to)) { - if (skipForBlending(storage, { vector, center })) continue + for (const vector of Vector.foreach(from, to)) { + if (skipForBlending(storage, { vector, center })) continue - const block = world.overworld.getBlock(vector) - if (!block) continue + const block = world.overworld.getBlock(vector) + if (!block) continue - replaceWithTargets(replaceTargets, getReplaceMode(storage.replaceMode), block, permutations) - } + replaceWithTargets(replaceTargets, getReplaceMode(storage.replaceMode), block, permutations) + } + }) } - onUse(player: Player, item: ItemStack) { - const lore = item.getLore() - if (lore[0] === '§aEnabled') { - lore[0] = '§cDisabled' - } else lore[0] = '§aEnabled' - - player.onScreenDisplay.setActionBar(lore[0], ActionbarPriority.UrgentNotificiation) - item.setLore(lore) + private isLookingUp(player: Player) { + return Math.round(player.getRotation().x) === -90 } } diff --git a/src/modules/world-edit/tools/smooth.ts b/src/modules/world-edit/tools/smooth.ts index c61a34fe..c3d80035 100644 --- a/src/modules/world-edit/tools/smooth.ts +++ b/src/modules/world-edit/tools/smooth.ts @@ -50,9 +50,7 @@ class SmoothTool extends WorldEditToolBrush { .show(player, (ctx, size, smoothLevel, replaceBlocksSet) => { storage.size = size - storage.smoothLevel = smoothLevel - if (replaceBlocksSet) storage.replaceBlocksSet = [player.id, replaceBlocksSet] slot.nameTag = `§r§3Сглаживание §6${size}§r §f${shortenBlocksSetName(replaceBlocksSet)}` diff --git a/src/modules/world-edit/tools/wand.ts b/src/modules/world-edit/tools/wand.ts index 38e075a7..d10cdaa6 100644 --- a/src/modules/world-edit/tools/wand.ts +++ b/src/modules/world-edit/tools/wand.ts @@ -22,7 +22,7 @@ class WandTool extends WorldEditTool { return color.slice(0, 2) + (tool ? (selection ? 'Действия с областью' : '§cЗона не выделена!') : 'Получить топор') } - editToolForm(slot: ContainerSlot, player: Player, initial: boolean) { + editToolForm(_: ContainerSlot, player: Player, initial: boolean) { if (initial) return new ActionForm('Действия с областью') .addButton('Заполнить/Заменить блоки', () => setSelectionMenu(player))