nms custom villager and restructuring for teams

This commit is contained in:
ruby
2025-01-05 01:27:42 +13:00
parent 35c7124451
commit f8825d535f
17 changed files with 347 additions and 162 deletions

View File

@ -1,6 +1,7 @@
plugins {
kotlin("jvm") version "2.1.20-Beta1"
id("com.github.johnrengelman.shadow") version "8.1.1"
id("io.papermc.paperweight.userdev") version "2.0.0-beta.11"
// id("de.nilsdruyen.gradle-ftp-upload-plugin") version "0.5.0"
}
@ -24,13 +25,13 @@ repositories {
}
dependencies {
compileOnly("io.papermc.paper:paper-api:1.21.3-R0.1-SNAPSHOT")
// compileOnly("io.papermc.paper:paper-api:1.21.3-R0.1-SNAPSHOT")
// compileOnly("com.comphenix.protocol:ProtocolLib:5.3.0")
compileOnly("com.fastasyncworldedit:FastAsyncWorldEdit-Bukkit")
compileOnly(files("libs/ProtocolLib.jar"))
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation(platform("com.intellectualsites.bom:bom-newest:1.51")) // Ref: https://github.com/IntellectualSites/bom
// implementation("de.nilsdruyen.gradle-ftp-upload-plugin:de.nilsdruyen.gradle-ftp-upload-plugin.gradle.plugin:0.5.0")
paperweight.paperDevBundle("1.21.4-R0.1-SNAPSHOT")
}
val targetJavaVersion = 21

View File

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

View File

@ -1,15 +1,22 @@
package com.pobnellion.aoe
import com.pobnellion.aoe.command.TestCommand
import com.pobnellion.aoe.team.Team
import com.pobnellion.aoe.ui.PlaceHint
import com.pobnellion.aoe.ui.PlaceItem
import org.bukkit.Bukkit
import org.bukkit.entity.Player
import org.bukkit.plugin.java.JavaPlugin
import java.io.File
class Aoe : JavaPlugin() {
companion object {
private var instance: Aoe? = null
val teams: MutableList<Team> = mutableListOf()
fun getTeam(player: Player): Team? {
return teams.singleOrNull() { team -> team.players.contains(player) }
}
fun getSchematicsFolder(): File = File(instance!!.dataFolder, "schematics")
}
@ -18,8 +25,8 @@ class Aoe : JavaPlugin() {
instance = this
// Events
Bukkit.getPluginManager().registerEvents(PlaceHint, this)
Bukkit.getPluginManager().registerEvents(PlaceItem(), this)
Bukkit.getPluginManager().registerEvents(PlaceHint, this)
// Commands
this.getCommand("debug")!!.setExecutor(TestCommand())

View File

@ -6,12 +6,8 @@ import org.bukkit.Location
import org.bukkit.Material
import org.bukkit.entity.Player
class Blacksmith: Building {
override fun showPlaceHint(player: Player) {
PlaceHint.add(player, "house2", ::place, PlaceHintValidators::allReplaceable)
}
fun place(location: Location, sizeX: Float, sizeY: Float, sizeZ: Float) {
class Blacksmith(location: Location, variant: Int): Building(location, variant) {
fun place(location: Location, sizeX: Float, sizeY: Float, sizeZ: Float, offsetY: Int) {
for (x in 0..<sizeX.toInt())
for (y in 0..<sizeY.toInt())
for (z in 0..<sizeZ.toInt())

View File

@ -3,6 +3,12 @@ package com.pobnellion.aoe.building
import org.bukkit.Location
import org.bukkit.entity.Player
interface Building {
fun showPlaceHint(player: Player)
abstract class Building(val location: Location, val variant: Int) {
}
interface BuildingInfo {
val buildingType: BuildingType
val schematicNames: List<String>
fun validate(location: Location): Boolean
fun create(location: Location, variant: Int): Building
}

View File

@ -0,0 +1,12 @@
package com.pobnellion.aoe.building
enum class BuildingType {
BARRACKS,
FARM,
HOUSE,
MILL,
TOWN_CENTER,
UNIQUE,
WALL,
WATCH_TOWER,
}

View File

@ -1,17 +1,22 @@
package com.pobnellion.aoe.building
import com.pobnellion.aoe.ui.PlaceHint
import com.pobnellion.aoe.ui.PlaceHintValidators
import org.bukkit.Location
import org.bukkit.Material
import org.bukkit.entity.Player
class House: Building {
override fun showPlaceHint(player: Player) {
PlaceHint.add(player, "house1", ::place, PlaceHintValidators::allReplaceable)
class House(location: Location, variant: Int): Building(location, variant) {
companion object Info: BuildingInfo {
override val buildingType: BuildingType = BuildingType.HOUSE
override val schematicNames: List<String> = listOf("house1")
override fun validate(location: Location): Boolean {
return PlaceHintValidators.allReplaceable(location, 5f, 5f, 5f, -1)
}
override fun create(location: Location, variant: Int): Building = House(location, variant)
}
fun place(location: Location, sizeX: Float, sizeY: Float, sizeZ: Float) {
fun place(location: Location, sizeX: Float, sizeY: Float, sizeZ: Float, int: Int) {
for (x in 0..<sizeX.toInt())
for (y in 0..<sizeY.toInt())
for (z in 0..<sizeZ.toInt())

View File

@ -1,14 +1,13 @@
package com.pobnellion.aoe.command
import com.pobnellion.aoe.ui.PlaceHint
import org.bukkit.Material
import com.pobnellion.aoe.entity.AoeVillager
import org.bukkit.command.Command
import org.bukkit.command.CommandExecutor
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player
class TestCommand : CommandExecutor {
override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array<out String>?): Boolean {
override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array<out String>): Boolean {
if (sender !is Player) {
sender.sendMessage("Command can only be executed by players")
return true

View File

@ -0,0 +1,21 @@
package com.pobnellion.aoe.entity
import com.pobnellion.aoe.building.Building
import com.pobnellion.aoe.entity.goals.GoToBuildingGoal
import net.minecraft.world.entity.EntityType
import net.minecraft.world.entity.npc.Villager
import org.bukkit.Location
import org.bukkit.craftbukkit.CraftWorld
class AoeVillager(location: Location) : Villager(EntityType.VILLAGER, (location.world as CraftWorld).handle) {
init {
setPos(location.x, location.y, location.z)
level().addFreshEntity(this)
targetSelector.removeAllGoals { true }
}
fun goToBuilding(building: Building) {
targetSelector.addGoal(0, GoToBuildingGoal(this, building, 1.0))
}
}

View File

@ -0,0 +1,35 @@
package com.pobnellion.aoe.entity.goals
import com.pobnellion.aoe.building.Building
import net.minecraft.world.entity.PathfinderMob
import net.minecraft.world.entity.ai.goal.Goal
import java.util.*
class GoToBuildingGoal(
private val mob: PathfinderMob,
private val building: Building,
private var speedModifier: Double
): Goal() {
private var recalculateTicks = 0
init {
this.setFlags(EnumSet.of(Flag.MOVE, Flag.JUMP))
}
override fun canUse(): Boolean {
return true
}
override fun start() {
mob.navigation.moveTo(building.location.x, building.location.y, building.location.z, speedModifier)
}
override fun tick() {
recalculateTicks++
if (recalculateTicks % 40 == 0)
mob.navigation.moveTo(building.location.x, building.location.y, building.location.z, speedModifier)
}
override fun requiresUpdateEveryTick(): Boolean = true
}

View File

@ -0,0 +1,23 @@
package com.pobnellion.aoe.team
import com.pobnellion.aoe.building.BuildingInfo
import com.pobnellion.aoe.building.BuildingType
import com.pobnellion.aoe.building.House
import org.bukkit.entity.Player
class Plains(players: List<Player>) : Team(players) {
override fun getBuildingInfo(type: BuildingType): BuildingInfo {
return when (type) {
BuildingType.BARRACKS -> TODO()
BuildingType.FARM -> TODO()
BuildingType.HOUSE -> House.Info
BuildingType.MILL -> TODO()
BuildingType.TOWN_CENTER -> TODO()
BuildingType.UNIQUE -> TODO()
BuildingType.WALL -> TODO()
BuildingType.WATCH_TOWER -> TODO()
}
}
}

View File

@ -1,7 +1,25 @@
package com.pobnellion.aoe.team
import com.pobnellion.aoe.building.Building
import com.pobnellion.aoe.building.BuildingInfo
import com.pobnellion.aoe.building.BuildingType
import com.pobnellion.aoe.ui.BuildingPlaceHint
import org.bukkit.Location
import org.bukkit.entity.Player
import kotlin.random.Random
class Team {
public val Buildings: List<Building> = listOf()
abstract class Team(val players: List<Player>) {
val buildings: MutableList<Building> = mutableListOf()
protected abstract fun getBuildingInfo(type: BuildingType): BuildingInfo
fun addBuilding(location: Location, building: BuildingInfo, variant: Int) {
buildings.add(building.create(location, variant))
}
fun showBuildingPlaceHint(type: BuildingType, player: Player) {
val info = getBuildingInfo(type)
val variant = Random.nextInt(info.schematicNames.size)
BuildingPlaceHint.add(player, info, ::addBuilding, variant)
}
}

View File

@ -0,0 +1,80 @@
package com.pobnellion.aoe.ui
import com.comphenix.protocol.PacketType
import com.comphenix.protocol.ProtocolLibrary
import com.comphenix.protocol.events.PacketContainer
import com.comphenix.protocol.wrappers.BukkitConverters
import com.comphenix.protocol.wrappers.Pair
import com.comphenix.protocol.wrappers.WrappedBlockData
import com.comphenix.protocol.wrappers.WrappedDataValue
import com.comphenix.protocol.wrappers.WrappedDataWatcher.Registry
import org.bukkit.Location
import org.bukkit.Material
import org.bukkit.entity.Player
import org.bukkit.util.Vector
import org.joml.Math
import org.joml.Vector3f
import java.util.*
class AreaPlaceHint(
override val player: Player,
private val sizeX: Float,
private val sizeY: Float,
private val sizeZ: Float,
private val onConfirm: (Location, Float, Float, Float) -> Unit,
private val validate: (Location, Float, Float, Float) -> Boolean
) : PlaceHint() {
companion object {
fun add(
player: Player,
sizeX: Float,
sizeY: Float,
sizeZ: Float,
onConfirm: (Location, Float, Float, Float) -> Unit,
validate: (Location, Float, Float, Float) -> Boolean,
) {
remove(player)
createOutlineTeam(player)
playerHints[player.uniqueId] = AreaPlaceHint(player, sizeX, sizeY, sizeZ, onConfirm, validate)
val block = player.getTargetBlockExact(MAX_TARGET_DISTANCE)
playerHints[player.uniqueId]!!.moveTo(block?.location)
}
}
private var base: Pair<Int, UUID> = Pair((Math.random() * Int.MAX_VALUE).toInt(), UUID.randomUUID())
init {
this.offset = Vector(sizeX / 2.0, 0.0, sizeZ / 2.0)
}
override fun validate(location: Location) = validate(location, sizeX, sizeY, sizeZ)
override fun confirm() = onConfirm(currentLocation!!, sizeX, sizeY, sizeZ)
override fun addDisplays(initialLocation: Location) {
base = spawnBlockDisplay(initialLocation, Material.GRAY_STAINED_GLASS.createBlockData(),
scale = Vector3f(sizeX + 0.1f, 0.2f, sizeZ + 0.1f), offset = Vector3f(-0.05f, -0.05f, -0.05f))
}
override fun updateColour() {
super.updateColour()
// base
val dataPacket = PacketContainer(PacketType.Play.Server.ENTITY_METADATA)
dataPacket.integers.write(0, base.first)
val material = if (isValid) Material.LIME_STAINED_GLASS else Material.RED_STAINED_GLASS
val blockData = BukkitConverters
.getWrappedBlockDataConverter()
.getGeneric(WrappedBlockData.createData(material))
val metadata = listOf(
WrappedDataValue(23, Registry.getBlockDataSerializer(false), blockData)
)
dataPacket.dataValueCollectionModifier.write(0, metadata)
ProtocolLibrary.getProtocolManager().sendServerPacket(player, dataPacket)
}
}

View File

@ -0,0 +1,75 @@
package com.pobnellion.aoe.ui
import com.pobnellion.aoe.Aoe
import com.pobnellion.aoe.building.BuildingInfo
import com.sk89q.worldedit.bukkit.BukkitAdapter
import com.sk89q.worldedit.extent.clipboard.Clipboard
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats
import com.sk89q.worldedit.math.BlockVector3
import org.bukkit.Location
import org.bukkit.entity.Player
import org.bukkit.util.Vector
import org.joml.Vector3f
import java.io.File
import java.io.FileInputStream
import kotlin.math.floor
class BuildingPlaceHint(
override val player: Player,
private val buildingInfo: BuildingInfo,
private val onConfirm: (Location, BuildingInfo, Int) -> Unit,
private val buildingVariant: Int = 0
) : PlaceHint() {
companion object {
fun add(
player: Player,
buildingInfo: BuildingInfo,
onConfirm: (Location, BuildingInfo, Int) -> Unit,
buildingVariant: Int = 0
) {
remove(player)
createOutlineTeam(player)
playerHints[player.uniqueId] = BuildingPlaceHint(player, buildingInfo, onConfirm, buildingVariant)
val block = player.getTargetBlockExact(MAX_TARGET_DISTANCE)
playerHints[player.uniqueId]!!.moveTo(block?.location)
}
}
private val schematic: Clipboard
init {
val schematicName = buildingInfo.schematicNames[buildingVariant]
val file = File(Aoe.getSchematicsFolder(),
if (schematicName.endsWith(".schem")) schematicName else "$schematicName.schem")
val format = ClipboardFormats.findByFile(file)
val reader = format?.getReader(FileInputStream(file))
val clipboard = reader?.read() ?: throw NullPointerException("Could not load schematic ${file.path}. Is it present?")
clipboard.origin = BlockVector3.ZERO
this.schematic = clipboard
this.offset = Vector(
-floor(clipboard.dimensions.x() / 2.0),
clipboard.minY.toDouble(),
-floor(clipboard.dimensions.z() / 2.0))
}
override fun validate(location: Location) = buildingInfo.validate(location)
override fun confirm() = onConfirm(currentLocation!!, buildingInfo, buildingVariant)
override fun addDisplays(initialLocation: Location) {
schematic.iterator().forEach { blockPosition ->
val block = BukkitAdapter.adapt(schematic.getBlock(blockPosition))
if (!block.material.isAir && !block.material.isEmpty) {
val x = (blockPosition.x() - schematic.minimumPoint.x()).toFloat()
val y = blockPosition.y().toFloat()
val z = (blockPosition.z() - schematic.minimumPoint.z()).toFloat()
displayIds.add(spawnBlockDisplay(initialLocation, block, offset = Vector3f(x, y, z), options = 0b01000000))
}
}
}
}

View File

@ -6,12 +6,7 @@ import com.comphenix.protocol.events.PacketContainer
import com.comphenix.protocol.wrappers.*
import com.comphenix.protocol.wrappers.WrappedDataWatcher.Registry
import com.destroystokyo.paper.MaterialSetTag
import com.pobnellion.aoe.Aoe
import com.sk89q.worldedit.bukkit.BukkitAdapter
import com.sk89q.worldedit.extent.clipboard.Clipboard
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats
import org.bukkit.Location
import org.bukkit.Material
import org.bukkit.block.data.BlockData
import org.bukkit.entity.EntityType
import org.bukkit.entity.Player
@ -20,47 +15,16 @@ import org.bukkit.event.Listener
import org.bukkit.event.block.Action
import org.bukkit.event.player.PlayerInteractEvent
import org.bukkit.event.player.PlayerMoveEvent
import org.bukkit.util.Vector
import org.joml.Math
import org.joml.Vector3f
import java.io.File
import java.io.FileInputStream
import java.util.*
import kotlin.math.floor
class PlaceHint {
abstract class PlaceHint {
companion object : Listener {
private const val MAX_TARGET_DISTANCE = 64
private val playerHints = HashMap<UUID, PlaceHint>()
fun add(
player: Player,
sizeX: Float,
sizeY: Float,
sizeZ: Float,
onConfirm: (Location, Float, Float, Float) -> Unit,
validate: (Location, Float, Float, Float) -> Boolean,
) {
remove(player)
createOutlineTeam(player)
playerHints[player.uniqueId] = PlaceHint(player, sizeX, sizeY, sizeZ, onConfirm, validate)
val block = player.getTargetBlockExact(MAX_TARGET_DISTANCE)
playerHints[player.uniqueId]!!.moveTo(block?.location)
}
fun add(
player: Player,
schematicName: String,
onConfirm: (Location, Float, Float, Float) -> Unit,
validate: (Location, Float, Float, Float) -> Boolean,
) {
remove(player)
createOutlineTeam(player)
playerHints[player.uniqueId] = PlaceHint(player, schematicName, onConfirm, validate)
val block = player.getTargetBlockExact(MAX_TARGET_DISTANCE)
playerHints[player.uniqueId]!!.moveTo(block?.location)
}
const val MAX_TARGET_DISTANCE = 64
@JvmStatic
protected val playerHints = HashMap<UUID, PlaceHint>()
fun remove(player: Player) {
if (!playerHints.containsKey(player.uniqueId))
@ -79,7 +43,8 @@ class PlaceHint {
return playerHints.containsKey(player.uniqueId)
}
private fun createOutlineTeam(player: Player) {
@JvmStatic
protected fun createOutlineTeam(player: Player) {
val packet = PacketContainer(PacketType.Play.Server.SCOREBOARD_TEAM)
packet.strings.write(0, "placeValid")
packet.integers.write(0, 0)
@ -105,13 +70,12 @@ class PlaceHint {
event.isCancelled = true
// left click - place
// left click - confirm
if (event.action == Action.LEFT_CLICK_BLOCK || event.action == Action.LEFT_CLICK_AIR) {
if (!playerHints[event.player.uniqueId]!!.isValid)
return
val marker = playerHints[event.player.uniqueId]!!
marker.onConfirm(marker.currentLocation!!, marker.sizeX, marker.sizeY, marker.sizeZ)
playerHints[event.player.uniqueId]!!.confirm()
remove(event.player)
}
@ -132,53 +96,19 @@ class PlaceHint {
.build()
}
private val player: Player
private val sizeX: Float
private val sizeY: Float
private val sizeZ: Float
val onConfirm: (Location, Float, Float, Float) -> Unit
val validate: (Location, Float, Float, Float) -> Boolean
private val schematic: Clipboard?
protected abstract val player: Player
protected lateinit var offset: Vector
private var marker: Pair<Int, UUID> = Pair((Math.random() * Int.MAX_VALUE).toInt(), UUID.randomUUID())
private var base: Pair<Int, UUID> = Pair((Math.random() * Int.MAX_VALUE).toInt(), UUID.randomUUID())
private val displayIds: MutableList<Pair<Int, UUID>> = mutableListOf()
protected val displayIds: MutableList<Pair<Int, UUID>> = mutableListOf()
var currentLocation: Location? = null
var isValid = false
constructor(player: Player, sizeX: Float, sizeY: Float, sizeZ: Float,
onConfirm: (Location, Float, Float, Float) -> Unit,
validate: (Location, Float, Float, Float) -> Boolean) {
this.player = player
this.sizeX = sizeX
this.sizeY = sizeY
this.sizeZ = sizeZ
this.onConfirm = onConfirm
this.validate = validate
this.schematic = null
}
protected abstract fun addDisplays(initialLocation: Location)
protected abstract fun confirm()
protected abstract fun validate(location: Location): Boolean
constructor(player: Player, schematicName: String,
onConfirm: (Location, Float, Float, Float) -> Unit,
validate: (Location, Float, Float, Float) -> Boolean) {
this.player = player
this.onConfirm = onConfirm
this.validate = validate
val file = File(Aoe.getSchematicsFolder(),
if (schematicName.endsWith(".schem")) schematicName else "$schematicName.schem")
val format = ClipboardFormats.findByFile(file)
val reader = format?.getReader(FileInputStream(file))
val clipboard = reader?.read() ?: throw NullPointerException("Could not load schematic ${file.path}. Is it present?")
this.schematic = clipboard
this.sizeX = clipboard.dimensions.x().toFloat()
this.sizeY = clipboard.dimensions.y().toFloat()
this.sizeZ = clipboard.dimensions.z().toFloat()
}
private fun show(initialLocation: Location) {
initialLocation.add(-floor(sizeX / 2.0), 1.0, -floor(sizeZ / 2.0))
protected fun show(initialLocation: Location) {
initialLocation.add(this.offset)
currentLocation = initialLocation
val spawnMarkerPacket = PacketContainer(PacketType.Play.Server.SPAWN_ENTITY)
@ -190,20 +120,7 @@ class PlaceHint {
.write(1, initialLocation.y)
.write(2, initialLocation.z)
base = spawnBlockDisplay(initialLocation, Material.GRAY_STAINED_GLASS.createBlockData(),
scale = Vector3f(sizeX + 0.1f, 0.2f, sizeZ + 0.1f), offset = Vector3f(-0.05f, -0.05f, -0.05f))
schematic?.iterator()?.forEach { blockPosition ->
val block = BukkitAdapter.adapt(schematic.getBlock(blockPosition))
if (!block.material.isAir && !block.material.isEmpty) {
val x = (blockPosition.x() - schematic.minimumPoint.x()).toFloat()
val y = (blockPosition.y() - schematic.minimumPoint.y()).toFloat()
val z = (blockPosition.z() - schematic.minimumPoint.z()).toFloat()
displayIds.add(spawnBlockDisplay(initialLocation, block, offset = Vector3f(x, y, z), options = 0b01000000))
}
}
addDisplays(initialLocation)
val outlineTeamPacket = PacketContainer(PacketType.Play.Server.SCOREBOARD_TEAM)
outlineTeamPacket.strings.write(0, "placeValid")
@ -211,7 +128,6 @@ class PlaceHint {
outlineTeamPacket.getSpecificModifier(Collection::class.java).write(0, displayIds.map { it.second.toString() })
val ids = displayIds.map { it.first }.toMutableList()
ids.add(base.first)
val passengerPacket = PacketContainer(PacketType.Play.Server.MOUNT)
passengerPacket.integers.write(0, marker.first)
@ -221,7 +137,7 @@ class PlaceHint {
ProtocolLibrary.getProtocolManager().sendServerPacket(player, outlineTeamPacket)
ProtocolLibrary.getProtocolManager().sendServerPacket(player, passengerPacket)
isValid = validate(initialLocation, sizeX, sizeY, sizeZ)
isValid = validate(initialLocation)
updateColour()
}
@ -229,7 +145,6 @@ class PlaceHint {
val packet = PacketContainer(PacketType.Play.Server.ENTITY_DESTROY)
val ids = displayIds.map { it.first }.toMutableList()
ids.add(marker.first)
ids.add(base.first)
packet.intLists.write(0, ids)
ProtocolLibrary.getProtocolManager().sendServerPacket(player, packet)
@ -245,11 +160,11 @@ class PlaceHint {
}
if (currentLocation == null) {
show(newLocation)
addDisplays(newLocation)
return
}
newLocation.add(-floor(sizeX / 2.0), 1.0, -floor(sizeZ / 2.0))
newLocation.add(this.offset)
val basePacket = PacketContainer(PacketType.Play.Server.ENTITY_POSITION_SYNC)
basePacket.integers.write(0, marker.first)
@ -266,7 +181,7 @@ class PlaceHint {
currentLocation = newLocation
// Update material
val valid = validate(newLocation, sizeX, sizeY, sizeZ)
val valid = validate(newLocation)
if (valid != isValid) {
isValid = valid
@ -276,7 +191,7 @@ class PlaceHint {
// region helper functions
private fun spawnBlockDisplay(
protected fun spawnBlockDisplay(
location: Location,
block: BlockData,
scale: Vector3f = Vector3f(1f, 1f, 1f),
@ -318,23 +233,7 @@ class PlaceHint {
return Pair<Int, UUID>(id, uuid)
}
private fun updateColour() {
// base
val dataPacket = PacketContainer(PacketType.Play.Server.ENTITY_METADATA)
dataPacket.integers.write(0, base.first)
val material = if (isValid) Material.LIME_STAINED_GLASS else Material.RED_STAINED_GLASS
val blockData = BukkitConverters
.getWrappedBlockDataConverter()
.getGeneric(WrappedBlockData.createData(material))
val metadata = listOf(
WrappedDataValue(23, Registry.getBlockDataSerializer(false), blockData)
)
dataPacket.dataValueCollectionModifier.write(0, metadata)
ProtocolLibrary.getProtocolManager().sendServerPacket(player, dataPacket)
protected open fun updateColour() {
// outline
val outlineTeamPacket = PacketContainer(PacketType.Play.Server.SCOREBOARD_TEAM)
outlineTeamPacket.strings.write(0, "placeValid")

View File

@ -5,13 +5,13 @@ import org.bukkit.Location
class PlaceHintValidators {
companion object {
fun alwaysTrue(location: Location, sizeX: Float, sizeY: Float, sizeZ: Float): Boolean {
fun alwaysTrue(location: Location, sizeX: Float, sizeY: Float, sizeZ: Float, offsetY: Int): Boolean {
return true
}
fun allAir(location: Location, sizeX: Float, sizeY: Float, sizeZ: Float): Boolean {
fun allAir(location: Location, sizeX: Float, sizeY: Float, sizeZ: Float, offsetY: Int): Boolean {
for (x in 0..<sizeX.toInt())
for (y in 0..<sizeY.toInt())
for (y in -offsetY..<sizeY.toInt())
for (z in 0..<sizeZ.toInt())
if (!location.world.getBlockAt(
location.blockX + x,
@ -22,9 +22,9 @@ class PlaceHintValidators {
return true
}
fun allReplaceable(location: Location, sizeX: Float, sizeY: Float, sizeZ: Float): Boolean {
fun allReplaceable(location: Location, sizeX: Float, sizeY: Float, sizeZ: Float, offsetY: Int): Boolean {
for (x in 0..<sizeX.toInt())
for (y in 0..<sizeY.toInt())
for (y in -offsetY..<sizeY.toInt())
for (z in 0..<sizeZ.toInt())
if (!location.world.getBlockAt(
location.blockX + x,

View File

@ -1,7 +1,7 @@
package com.pobnellion.aoe.ui
import com.pobnellion.aoe.building.Blacksmith
import com.pobnellion.aoe.building.House
import com.pobnellion.aoe.Aoe
import com.pobnellion.aoe.building.BuildingType
import net.kyori.adventure.text.Component
import org.bukkit.Bukkit
import org.bukkit.Material
@ -14,22 +14,26 @@ import org.bukkit.event.inventory.InventoryCloseEvent
import org.bukkit.event.inventory.InventoryDragEvent
import org.bukkit.event.player.PlayerInteractEvent
import org.bukkit.inventory.ItemStack
import java.util.*
class PlaceItem : Listener {
private val buildingInventory = Bukkit.createInventory(null, 9, Component.text("Buildings"))
init {
buildingInventory.addItem(createGuiItem(Material.BELL, "Town center", "middle of the town :D"))
buildingInventory.addItem(createGuiItem(Material.OAK_LOG, "House", "Just a house bro"))
buildingInventory.addItem(createGuiItem(Material.ANVIL, "Blacksmith", "smith ."))
buildingInventory.addItem(createGuiItem(Material.EMERALD, "Villager", "willager"))
}
@EventHandler
fun onRightClickItem(event: PlayerInteractEvent) {
if (event.material != Material.BRICKS
|| (event.action != Action.RIGHT_CLICK_AIR && event.action != Action.RIGHT_CLICK_BLOCK)
|| PlaceHint.contains(event.player))
if (event.action != Action.RIGHT_CLICK_AIR && event.action != Action.RIGHT_CLICK_BLOCK)
return
if (PlaceHint.contains(event.player))
return
if (event.material != Material.BRICKS)
return
event.isCancelled = true
@ -38,6 +42,9 @@ class PlaceItem : Listener {
@EventHandler
fun onInventoryClick(event: InventoryClickEvent) {
val player = event.whoClicked as Player
val team = Aoe.getTeam(player) ?: return
if (event.inventory != buildingInventory)
return
@ -45,8 +52,9 @@ class PlaceItem : Listener {
var validClick = true
when (event.currentItem?.type) {
Material.OAK_LOG -> House().showPlaceHint(event.whoClicked as Player)
Material.ANVIL -> Blacksmith().showPlaceHint(event.whoClicked as Player)
Material.OAK_LOG -> team.showBuildingPlaceHint(BuildingType.HOUSE, player)
Material.BELL -> team.showBuildingPlaceHint(BuildingType.TOWN_CENTER, player)
Material.EMERALD -> {}
else -> validClick = false
}