Skip to content

Commit

Permalink
feat: minearea region
Browse files Browse the repository at this point in the history
  • Loading branch information
leaftail1880 committed Aug 24, 2024
1 parent e83b13b commit e4e24a0
Show file tree
Hide file tree
Showing 18 changed files with 242 additions and 192 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vitest'
import { FlattenedSphereArea } from './flattened-shpere'
import { FlattenedSphereArea } from './flattened-sphere'

describe('rectangle', () => {
it('should detect if vector is in region', () => {
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion src/lib/region/areas/sphere.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { describe, expect, it } from 'vitest'
import { SphereArea } from './sphere'

describe('shpere', () => {
describe('sphere', () => {
it('should detect if vector is in region', () => {
const sphere = new SphereArea({ center: { x: 0, y: 0, z: 0 }, radius: 2 })

Expand Down
21 changes: 11 additions & 10 deletions src/lib/region/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ import { Region } from 'lib/region/kinds/region'
import { textTable } from 'lib/text'
import { inspect } from 'lib/util'
import { Vector } from 'lib/vector'
import { BaseRegion } from '../../modules/places/base/region'
import { MineshaftRegion } from '../../modules/places/mineshaft/mineshaft-region'
import { SphereArea } from './areas/sphere'
import { SafeAreaRegion } from './kinds/safe-area'
import { RegionWithStructure } from './kinds/with-structure'

const addableRegions: { name: string; region: typeof Region }[] = []
export function addAddableRegion(name: string, region: typeof Region) {
addableRegions.push({ name, region })
}

new Command('region')
.setPermissions('techAdmin')
.setGroup('public')
Expand All @@ -36,11 +38,10 @@ function regionForm(player: Player) {
() => editRegion(player, currentRegion, () => regionForm(player)),
)

form
.addButton('Базы', reg(BaseRegion))
.addButton('Шахты', reg(MineshaftRegion))
.addButton('Мирные зоны', reg(SafeAreaRegion))
.show(player)
for (const r of addableRegions) {
form.addButton(r.name, reg(r.region))
}
form.show(player)
}

function regionList(player: Player, RegionType: typeof Region, back = () => regionForm(player)) {
Expand All @@ -63,7 +64,7 @@ function regionList(player: Player, RegionType: typeof Region, back = () => regi
})
})

for (const region of Region.regionInstancesOf(RegionType)) {
for (const region of RegionType.instances()) {
form.addButton(region.name, () => editRegion(player, region, () => regionList(player, RegionType, back)))
}
form.show(player)
Expand All @@ -77,7 +78,7 @@ function editRegion(player: Player, region: Region, back: () => void) {
'Регион ' + region.name,
textTable({
'Тип региона': region.creator.name,
'Центр': region.area.center,
'Центр': Vector.string(region.area.center, true),
'Радиус': region.area instanceof SphereArea ? region.area.radius : 'не поддерживается',
}),
)
Expand Down
25 changes: 3 additions & 22 deletions src/lib/region/kinds/region.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,20 +68,9 @@ export class Region<LDB extends RLDB = any> {
/**
* Filters an array of regions to return instances of a specific region type.
*
* @param {R} type - Region subclass to get
* @returns Array of instances that match the specified type `R` of Region.
*/
static regionInstancesOf<R extends typeof Region>(type: R): InstanceType<R>[] {
return this.regions.filter((e => e instanceof type) as (e: Region) => e is InstanceType<R>)
}

/**
* Filters an array of regions to return instances of a specific region type.
*
* @returns Array of instances that match the specified type `R` of Region.
*/
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
static instances<I extends Region, T extends { new (): I; regions: Region[] }>(this: T) {
static instances<I extends Region>(this: { new (...args: any[]): I; regions: Region[] }) {
return this.regions.filter((e => e instanceof this) as (e: Region) => e is I)
}

Expand All @@ -104,10 +93,10 @@ export class Region<LDB extends RLDB = any> {
* block location is located.
*/
static nearestRegions(location: Vector3, dimensionId: Dimensions) {
const regions = this === Region ? this.regions : this.regionInstancesOf(this)
const regions = this === Region ? this.regions : this.instances()

return regions
.filter(region => region.isVectorInRegion(location, dimensionId))
.filter(region => region.area.isVectorIn(location, dimensionId))
.sort((a, b) => b.priority - a.priority)
}

Expand Down Expand Up @@ -166,14 +155,6 @@ export class Region<LDB extends RLDB = any> {
// Hook
}

/** Checks if the vector is in the region */
isVectorInRegion(vector: Vector3, dimensionId: Dimensions) {
if (this.dimensionId !== dimensionId) return false

// See the implementation in the sub class
return true
}

get dimension() {
return world[this.dimensionId]
}
Expand Down
2 changes: 2 additions & 0 deletions src/lib/region/kinds/safe-area.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { MinecraftEntityTypes } from '@minecraft/vanilla-data'
import { addAddableRegion } from 'lib'
import { Area } from '../areas/area'
import { Region, RegionCreationOptions } from './region'

Expand Down Expand Up @@ -41,3 +42,4 @@ export class SafeAreaRegion extends Region {
return this.safeAreaName
}
}
addAddableRegion('Мирные зоны', SafeAreaRegion)
8 changes: 3 additions & 5 deletions src/lib/region/kinds/with-structure.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { BlockPermutation, Dimension, StructureSaveMode, world } from '@minecraft/server'
import { Region } from './region'
import { Vector } from 'lib/vector'
import { Region } from './region'

export abstract class RegionWithStructure extends Region {
protected readonly saveable = true
Expand Down Expand Up @@ -43,13 +43,11 @@ export abstract class RegionWithStructure extends Region {
const structure = world.structureManager.get(this.structureName)
if (!structure) throw new TypeError('No structure found!')

const edges = this.area.edges
const [, edge] = this.area.edges

return this.area.forEachVector((vector, isIn, dimension) => {
if (isIn) {
const structureSavedBlock = structure.getBlockPermutation(
Vector.multiply(Vector.subtract(edges[1], vector), -1),
)
const structureSavedBlock = structure.getBlockPermutation(Vector.multiply(Vector.subtract(edge, vector), -1))
callback(vector, structureSavedBlock, dimension)
}
})
Expand Down
2 changes: 1 addition & 1 deletion src/modules/commands/tp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ function location(
fallback: string,
players: { location: Vector3; dimension: Dimensions }[],
) {
const playersC = players.filter(e => place.safeArea?.isVectorInRegion(e.location, e.dimension)).length
const playersC = players.filter(e => place.safeArea?.area.isVectorIn(e.location, e.dimension)).length

if (place.portalTeleportsTo.valid) {
return {
Expand Down
2 changes: 1 addition & 1 deletion src/modules/places/anarchy/anarchy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ class AnarchyBuilder extends AreaWithInventory {
)

// Do not save location if on spawn
if (Spawn.region?.isVectorInRegion(player.location, player.dimension.type)) return
if (Spawn.region?.area.isVectorIn(player.location, player.dimension.type)) return
player.database.survival.anarchy = {
x: Math.round(player.location.x),
z: Math.round(player.location.z),
Expand Down
2 changes: 1 addition & 1 deletion src/modules/places/base/base-menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export function openBaseMenu(
) {
if (LockAction.locked(player)) return

const base = Region.regionInstancesOf(BaseRegion).find(r => r.getMemberRole(player))
const base = BaseRegion.instances().find(r => r.getMemberRole(player))

if (!base) return onFail('§cУ вас нет базы! Вступите в существующую или создайте свою.')

Expand Down
4 changes: 2 additions & 2 deletions src/modules/places/base/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ world.beforeEvents.playerPlaceBlock.subscribe(event => {
)
}

const region = Region.regionInstancesOf(BaseRegion).find(e => e.getMemberRole(player) !== false)
const region = BaseRegion.instances().find(e => e.getMemberRole(player) !== false)

if (region) {
event.cancel = true
Expand Down Expand Up @@ -77,7 +77,7 @@ system.runInterval(
() => {
const playersLocations = world.getAllPlayers().map(p => ({ d: p.dimension.type, l: p.location }))

for (const base of Region.regionInstancesOf(BaseRegion)) {
for (const base of BaseRegion.instances()) {
const block = getBlockStatus({ location: base.area.center, dimensionId: base.dimensionId })
if (block === 'unloaded') continue

Expand Down
2 changes: 2 additions & 0 deletions src/modules/places/base/region.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { addAddableRegion } from 'lib/region/command'
import { registerRegionKind } from 'lib/region/database'
import { type RegionPermissions } from 'lib/region/kinds/region'
import { RegionWithStructure } from 'lib/region/kinds/with-structure'
Expand All @@ -20,3 +21,4 @@ export class BaseRegion extends RegionWithStructure {
}
}
registerRegionKind(BaseRegion)
addAddableRegion('Базы', BaseRegion)
95 changes: 95 additions & 0 deletions src/modules/places/minearea/minearea-region.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { Player, PlayerBreakBlockBeforeEvent } from '@minecraft/server'
import { isNotPlaying } from 'lib/game-utils'
import { actionGuard, addAddableRegion } from 'lib/region'
import { registerRegionKind } from 'lib/region/database'
import { Region, type RegionPermissions } from 'lib/region/kinds/region'
import { RegionWithStructure } from 'lib/region/kinds/with-structure'
import { t } from 'lib/text'
import { ms } from 'lib/utils/ms'
import { onScheduledBlockPlace, scheduleBlockPlace } from 'modules/survival/scheduled-block-place'

export class MineareaRegion extends RegionWithStructure {
static readonly kind: string = 'minearea'

/** MineArea is more prior then other regions */
protected readonly priority = 1

protected readonly defaultPermissions: RegionPermissions = {
allowedEntities: 'all',
doorsAndSwitches: true,
openContainers: true,
pvp: true,
owners: [],
}

protected onCreate(): void {
this.saveStructure()
console.log('Created new MineArea region and saved structure')
}

onBlockBreak(player: Player, event: PlayerBreakBlockBeforeEvent) {
const { block, dimension } = event
scheduleBlockPlace({
dimension: dimension.type,
location: block.location,
typeId: block.typeId,
states: block.permutation.getAllStates(),
restoreTime: ms.from('sec', 10), // ms.from('min', Math.randomInt(1, 3)),
})
console.log('ON BLOCK BREAK MINEAREA')

return true
}

// eslint-disable-next-line @typescript-eslint/class-literal-property-style
get displayName() {
return '§7Зона добычи'
}
}

addAddableRegion('Зоны добычи', MineareaRegion)
registerRegionKind(MineareaRegion)

actionGuard((player, region, ctx) => {
if (isNotPlaying(player)) return
if (!(region instanceof MineareaRegion)) return

switch (ctx.type) {
case 'interactWithBlock':
case 'interactWithEntity':
return true

case 'break': {
return region.onBlockBreak(player, ctx.event)
}

case 'place': {
const { block, dimension } = ctx.event
scheduleBlockPlace({
dimension: dimension.type,
location: block.location,
typeId: block.typeId,
states: block.permutation.getAllStates(),
restoreTime: ms.from('min', Math.randomInt(3, 10)),
})

return true
}
}
})

onScheduledBlockPlace.subscribe(({ block, schedules, schedule }) => {
const regions = Region.nearestRegions(block, block.dimension.type)
for (const region of regions) {
if (!(region instanceof MineareaRegion)) continue

const toRestore = schedules.filter(e => region.area.isVectorIn(e.location, region.dimensionId) && e !== schedule)
if (toRestore.length) {
// console.log(t`Still blocks to restore: ${toRestore.length}`)
continue
}

console.log(t`All blocks in region ${region.name} kind ${region.creator.kind} are restored.`)
region.loadStructure()
}
})
46 changes: 30 additions & 16 deletions src/modules/places/mineshaft/mineshaft-region.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,13 @@
import { Player, PlayerBreakBlockBeforeEvent, system } from '@minecraft/server'
import { addAddableRegion, ms } from 'lib'
import { registerRegionKind } from 'lib/region/database'
import { type RegionPermissions } from 'lib/region/kinds/region'
import { RegionWithStructure } from 'lib/region/kinds/with-structure'
import { ores } from './algo'
import { scheduleBlockPlace } from 'modules/survival/scheduled-block-place'
import { MineareaRegion } from '../minearea/minearea-region'
import { ores, placeOre } from './algo'

export class MineshaftRegion extends RegionWithStructure {
export class MineshaftRegion extends MineareaRegion {
static readonly kind = 'mine'

/** MineShaft is more prior then other regions */
protected readonly priority = 1

protected readonly defaultPermissions: RegionPermissions = {
allowedEntities: 'all',
doorsAndSwitches: true,
openContainers: true,
pvp: true,
owners: [],
}

protected onCreate(): void {
let oresFound = 0
this.area.forEachVector((vector, isIn, dimension) => {
Expand All @@ -31,9 +22,32 @@ export class MineshaftRegion extends RegionWithStructure {
})

this.saveStructure()

console.log('Created new mineshaft region. Ores found:', oresFound)
}

onBlockBreak(player: Player, event: PlayerBreakBlockBeforeEvent) {
const { block, dimension } = event
const ore = ores.getOre(block.typeId)

const typeId = block.typeId
system.delay(() => placeOre(block, typeId, dimension, player))

scheduleBlockPlace({
dimension: dimension.type,
location: block.location,
typeId: ore ? ore.empty : block.typeId,
states: ore ? undefined : block.permutation.getAllStates(),
restoreTime: ms.from('min', Math.randomInt(1, 3)),
})

return true
}

// eslint-disable-next-line @typescript-eslint/class-literal-property-style
get displayName() {
return '§7Шахта'
}
}

addAddableRegion('Шахты', MineshaftRegion)
registerRegionKind(MineshaftRegion)
Loading

0 comments on commit e4e24a0

Please sign in to comment.