moving things around and inventory stuff

This commit is contained in:
ruby
2025-01-12 21:32:12 +13:00
parent 57626e4f95
commit 685a1af396
13 changed files with 244 additions and 81 deletions

View File

@ -6,8 +6,9 @@ import com.pobnellion.aoe.civilisation.Civilisation
import com.pobnellion.aoe.civilisation.CivilisationType import com.pobnellion.aoe.civilisation.CivilisationType
import com.pobnellion.aoe.map.AoeMap import com.pobnellion.aoe.map.AoeMap
import com.pobnellion.aoe.ui.PlaceHint import com.pobnellion.aoe.ui.PlaceHint
import com.pobnellion.aoe.ui.PlaceItem import com.pobnellion.aoe.ui.InventoryManager
import org.bukkit.Bukkit import org.bukkit.Bukkit
import org.bukkit.GameMode
import org.bukkit.entity.Player import org.bukkit.entity.Player
import org.bukkit.plugin.java.JavaPlugin import org.bukkit.plugin.java.JavaPlugin
import java.io.File import java.io.File
@ -19,6 +20,10 @@ class Aoe : JavaPlugin() {
private var instance: Aoe? = null private var instance: Aoe? = null
val civilisations: MutableMap<CivilisationType, Civilisation> = mutableMapOf() val civilisations: MutableMap<CivilisationType, Civilisation> = mutableMapOf()
val map: AoeMap = AoeMap() val map: AoeMap = AoeMap()
val players: MutableMap<Player, CivilisationType> = mutableMapOf()
val inventoryManager: InventoryManager = InventoryManager()
fun isPlaying(player: Player) = players.containsKey(player)
fun getTeam(player: Player): Civilisation? { fun getTeam(player: Player): Civilisation? {
return civilisations.values.singleOrNull { team -> team.players.contains(player) } return civilisations.values.singleOrNull { team -> team.players.contains(player) }
@ -28,8 +33,18 @@ class Aoe : JavaPlugin() {
Paths.get(instance!!.dataFolder.path, "schematics", "$schematicName.schem").toFile() Paths.get(instance!!.dataFolder.path, "schematics", "$schematicName.schem").toFile()
fun startGame() { fun startGame() {
if (!gameInProgress) if (gameInProgress)
return
for (player in Bukkit.getOnlinePlayers()) {
if (isPlaying(player))
player.gameMode = GameMode.CREATIVE
else
player.gameMode = GameMode.SPECTATOR
}
civilisations.values.forEach { civ -> civ.initSetup() } civilisations.values.forEach { civ -> civ.initSetup() }
inventoryManager.initHotbars()
gameInProgress = true gameInProgress = true
} }
@ -39,7 +54,7 @@ class Aoe : JavaPlugin() {
instance = this instance = this
// Events // Events
Bukkit.getPluginManager().registerEvents(PlaceItem(), this) Bukkit.getPluginManager().registerEvents(InventoryManager(), this)
Bukkit.getPluginManager().registerEvents(PlaceHint, this) Bukkit.getPluginManager().registerEvents(PlaceHint, this)
// Commands // Commands

View File

@ -0,0 +1,8 @@
package com.pobnellion.aoe
import com.pobnellion.aoe.civilisation.Civilisation
import org.bukkit.entity.Player
fun Player.getCivilisation(): Civilisation? {
return Aoe.civilisations[Aoe.players[this]]
}

View File

@ -11,6 +11,7 @@ import com.sk89q.worldedit.function.operation.Operations
import com.sk89q.worldedit.math.BlockVector3 import com.sk89q.worldedit.math.BlockVector3
import com.sk89q.worldedit.session.ClipboardHolder import com.sk89q.worldedit.session.ClipboardHolder
import org.bukkit.Location import org.bukkit.Location
import org.bukkit.util.Vector
import java.io.File import java.io.File
import java.io.FileInputStream import java.io.FileInputStream
@ -22,19 +23,26 @@ abstract class Building(val location: Location, val variant: Int): EntityWorkTar
override fun removeProgress(amount: Float) {} override fun removeProgress(amount: Float) {}
override fun onComplete() {} override fun onComplete() {}
var sizeX: Int
var sizeZ: Int
fun center(): Location = location.clone().add(sizeX / 2.0, 0.0, sizeZ / 2.0)
private val clipboard: Clipboard
abstract var populationCapacity: Int abstract var populationCapacity: Int
abstract fun getSchematicName(variant: Int): String abstract fun getSchematicName(variant: Int): String
fun placeFull() { init {
currentProgressPercent = 1f val file: File = Aoe.getSchematicFile(this.getSchematicName(variant))
var clipboard: Clipboard
val file: File = Aoe.getSchematicFile(getSchematicName(variant))
val format = ClipboardFormats.findByFile(file) val format = ClipboardFormats.findByFile(file)
format!!.getReader(FileInputStream(file)).use { reader -> format!!.getReader(FileInputStream(file)).use { reader ->
clipboard = reader.read() clipboard = reader.read()
} }
sizeX = clipboard.maximumPoint.x() - clipboard.minimumPoint.x()
sizeZ = clipboard.maximumPoint.z() - clipboard.minimumPoint.z()
}
fun placeFull() {
currentProgressPercent = 1f
val offset = clipboard.region.minimumPoint.subtract(clipboard.origin) val offset = clipboard.region.minimumPoint.subtract(clipboard.origin)
WorldEdit.getInstance().newEditSession(BukkitAdapter.adapt(location.world)).use { editSession -> WorldEdit.getInstance().newEditSession(BukkitAdapter.adapt(location.world)).use { editSession ->
@ -50,6 +58,7 @@ abstract class Building(val location: Location, val variant: Int): EntityWorkTar
interface BuildingInfo { interface BuildingInfo {
val buildingType: BuildingType val buildingType: BuildingType
val schematicNames: List<String> val schematicNames: List<String>
fun getSize(variant: Int): Vector
fun validate(location: Location): Boolean fun validate(location: Location): Boolean
fun create(location: Location, variant: Int): Building fun create(location: Location, variant: Int): Building
} }

View File

@ -1,13 +1,17 @@
package com.pobnellion.aoe.civilisation package com.pobnellion.aoe.civilisation
import com.pobnellion.aoe.Aoe
import com.pobnellion.aoe.Constants import com.pobnellion.aoe.Constants
import com.pobnellion.aoe.building.Building import com.pobnellion.aoe.building.Building
import com.pobnellion.aoe.building.BuildingInfo import com.pobnellion.aoe.building.BuildingInfo
import com.pobnellion.aoe.building.BuildingType import com.pobnellion.aoe.building.BuildingType
import com.pobnellion.aoe.building.TownCenter import com.pobnellion.aoe.building.TownCenter
import com.pobnellion.aoe.entity.AoeVillager import com.pobnellion.aoe.entity.AoeVillager
import com.pobnellion.aoe.ui.AoeInventory
import com.pobnellion.aoe.ui.BuildingPlaceHint import com.pobnellion.aoe.ui.BuildingPlaceHint
import net.minecraft.world.phys.AABB
import org.bukkit.Location import org.bukkit.Location
import org.bukkit.craftbukkit.CraftWorld
import org.bukkit.entity.Player import org.bukkit.entity.Player
import kotlin.math.min import kotlin.math.min
import kotlin.random.Random import kotlin.random.Random
@ -17,15 +21,17 @@ abstract class Civilisation(
) { ) {
private val buildings: MutableList<Building> = mutableListOf() private val buildings: MutableList<Building> = mutableListOf()
private val villagers: MutableList<AoeVillager> = mutableListOf() private val villagers: MutableList<AoeVillager> = mutableListOf()
val players: MutableList<Player> = mutableListOf()
fun addPlayer(player: Player) { val players get() = Aoe.players.filter { player -> player.value == this.type }.keys
players.add(player) val buildingInventory = AoeInventory("Buildings", BuildingType.entries.size)
player.sendMessage("Joined team ${name()}")
}
protected abstract fun getBuildingInfo(type: BuildingType): BuildingInfo protected abstract fun getBuildingInfo(type: BuildingType): BuildingInfo
protected abstract fun name(): String protected abstract val name: String
protected abstract val type: CivilisationType
init {
buildingInventory.addItem()
}
fun addBuilding(location: Location, buildingInfo: BuildingInfo, variant: Int): Building { fun addBuilding(location: Location, buildingInfo: BuildingInfo, variant: Int): Building {
val building = buildingInfo.create(location, variant) val building = buildingInfo.create(location, variant)
@ -47,9 +53,31 @@ abstract class Civilisation(
townCenter.placeFull() townCenter.placeFull()
// Spawn initial villagers // Spawn initial villagers
for (i in 0..Constants.STARTING_VILLAGER_COUNT) for (i in 0..< Constants.STARTING_VILLAGER_COUNT) {
villagers.add(AoeVillager(townCenter.villagerSpawnLocation)) val villager = AoeVillager(townCenter.villagerSpawnLocation, type)
villager.leaveBuilding(townCenter)
villagers.add(villager)
}
// tp players above town center
for (player in players) {
player.teleport(townCenter.location
.clone()
.add(townCenterInfo.getSize(variant).x / 2, 0.0, townCenterInfo.getSize(variant).z / 2)
.toHighestLocation()
.add(0.0, 10.0, 0.0))
player.isFlying = true
}
} }
fun populationCap() = min(Constants.MAX_POP_CAP, buildings.sumOf { building -> building.populationCapacity }) fun populationCap() = min(Constants.MAX_POP_CAP, buildings.sumOf { building -> building.populationCapacity })
fun selectVillagers(location: Location, sizeX: Float, sizeY: Float, sizeZ: Float) {
(location.world as CraftWorld).handle.getEntitiesOfClass(
AoeVillager::class.java,
AABB(location.x, location.y, location.z, location.x + sizeX, location.y + sizeY, location.z + sizeZ)
)
{ villager -> villager.civilisationType == type }
}
} }

View File

@ -7,7 +7,8 @@ import com.pobnellion.aoe.building.plains.PlainsTownCenter
import org.bukkit.Location import org.bukkit.Location
class Plains(setupLocation: Location) : Civilisation(setupLocation) { class Plains(setupLocation: Location) : Civilisation(setupLocation) {
override fun name(): String = "Plains" override val name: String = "Plains"
override val type: CivilisationType = CivilisationType.PLAINS
override fun getBuildingInfo(type: BuildingType): BuildingInfo { override fun getBuildingInfo(type: BuildingType): BuildingInfo {
return when (type) { return when (type) {

View File

@ -48,7 +48,7 @@ class TestCommand : CommandExecutor {
CivilisationType.PLAINS -> Aoe.civilisations[CivilisationType.PLAINS] = Plains(Aoe.map.getStartingLocations()[0]) CivilisationType.PLAINS -> Aoe.civilisations[CivilisationType.PLAINS] = Plains(Aoe.map.getStartingLocations()[0])
} }
Aoe.civilisations[civilisationType]!!.addPlayer(player) Aoe.players[player] = civilisationType
} }
} }

View File

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

View File

@ -0,0 +1,52 @@
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 net.minecraft.world.entity.ai.util.DefaultRandomPos
import net.minecraft.world.level.pathfinder.Path
import net.minecraft.world.phys.Vec3
import java.util.*
import kotlin.math.sqrt
import kotlin.math.pow
class LeaveBuildingGoal(
private val mob: PathfinderMob,
private val building: Building,
private var speedModifier: Double
): Goal() {
private var path: Path? = null
init {
this.setFlags(EnumSet.of(Flag.MOVE))
}
override fun canUse(): Boolean {
val buildingCornerDistance = sqrt((building.sizeX.toFloat().pow(2) + building.sizeZ.toFloat().pow(2)))
val buildingCenter = building.center()
val fromPosition = Vec3(buildingCenter.x, buildingCenter.y, buildingCenter.z)
val posAway = DefaultRandomPos.getPosAway(mob, (buildingCornerDistance / 2).toInt(), 2, fromPosition)
if (posAway == null)
return false
if (fromPosition.distanceToSqr(posAway.x, posAway.y, posAway.z) < fromPosition.distanceToSqr(mob.position()))
return false
path = mob.navigation.createPath(posAway.x, posAway.y, posAway.z, 0)
return path != null
}
override fun start() {
mob.navigation.moveTo(path, speedModifier)
}
override fun tick() {
if (!canContinueToUse())
mob.targetSelector.removeGoal(this)
}
override fun canContinueToUse(): Boolean {
return !mob.navigation.isDone
}
}

View File

@ -0,0 +1,13 @@
package com.pobnellion.aoe.ui
import net.kyori.adventure.text.Component
import org.bukkit.Bukkit
import org.bukkit.inventory.Inventory
class AoeInventory(name: String, size: Int) {
val inventory: Inventory = Bukkit.createInventory(null, size + size % 9, Component.text(name))
fun addItem() {
}
}

View File

@ -1,13 +1,6 @@
package com.pobnellion.aoe.ui 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.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.Location
import org.bukkit.Material import org.bukkit.Material
import org.bukkit.entity.Player import org.bukkit.entity.Player
@ -22,7 +15,7 @@ class AreaPlaceHint(
private val sizeY: Float, private val sizeY: Float,
private val sizeZ: Float, private val sizeZ: Float,
private val onConfirm: (Location, Float, Float, Float) -> Unit, private val onConfirm: (Location, Float, Float, Float) -> Unit,
private val validate: (Location, Float, Float, Float) -> Boolean private val onTick: (Location, Float, Float, Float) -> Unit,
) : PlaceHint() { ) : PlaceHint() {
companion object { companion object {
fun add( fun add(
@ -31,12 +24,12 @@ class AreaPlaceHint(
sizeY: Float, sizeY: Float,
sizeZ: Float, sizeZ: Float,
onConfirm: (Location, Float, Float, Float) -> Unit, onConfirm: (Location, Float, Float, Float) -> Unit,
validate: (Location, Float, Float, Float) -> Boolean, onTick: (Location, Float, Float, Float) -> Unit,
) { ) {
remove(player) remove(player)
createOutlineTeam(player) createOutlineTeam(player)
playerHints[player.uniqueId] = AreaPlaceHint(player, sizeX, sizeY, sizeZ, onConfirm, validate) playerHints[player.uniqueId] = AreaPlaceHint(player, sizeX, sizeY, sizeZ, onConfirm, onTick)
val block = player.getTargetBlockExact(MAX_TARGET_DISTANCE) val block = player.getTargetBlockExact(MAX_TARGET_DISTANCE)
playerHints[player.uniqueId]!!.moveTo(block?.location) playerHints[player.uniqueId]!!.moveTo(block?.location)
} }
@ -48,9 +41,14 @@ class AreaPlaceHint(
this.offset = Vector(sizeX / 2.0, 0.0, sizeZ / 2.0) this.offset = Vector(sizeX / 2.0, 0.0, sizeZ / 2.0)
} }
override fun validate(location: Location) = validate(location, sizeX, sizeY, sizeZ) override fun tick() {
currentLocation?.let { onTick(it, sizeX, sizeY, sizeZ) }
}
override fun confirm() = onConfirm(currentLocation!!, sizeX, sizeY, sizeZ) override fun confirm(): Boolean {
currentLocation?.let { onConfirm(it, sizeX, sizeY, sizeZ) }
return true
}
override fun addDisplays(initialLocation: Location) { override fun addDisplays(initialLocation: Location) {
base = spawnBlockDisplay(initialLocation, Material.GRAY_STAINED_GLASS.createBlockData(), base = spawnBlockDisplay(initialLocation, Material.GRAY_STAINED_GLASS.createBlockData(),
@ -58,23 +56,23 @@ class AreaPlaceHint(
} }
override fun updateColour() { // override fun updateGlowColour(colour: ChatFormatting) {
super.updateColour() // super.updateGlowColour(colour)
//
// base // // base
val dataPacket = PacketContainer(PacketType.Play.Server.ENTITY_METADATA) // val dataPacket = PacketContainer(PacketType.Play.Server.ENTITY_METADATA)
dataPacket.integers.write(0, base.first) // dataPacket.integers.write(0, base.first)
//
val material = if (isValid) Material.LIME_STAINED_GLASS else Material.RED_STAINED_GLASS // val material = if (isValid) Material.LIME_STAINED_GLASS else Material.RED_STAINED_GLASS
val blockData = BukkitConverters // val blockData = BukkitConverters
.getWrappedBlockDataConverter() // .getWrappedBlockDataConverter()
.getGeneric(WrappedBlockData.createData(material)) // .getGeneric(WrappedBlockData.createData(material))
//
val metadata = listOf( // val metadata = listOf(
WrappedDataValue(23, Registry.getBlockDataSerializer(false), blockData) // WrappedDataValue(23, Registry.getBlockDataSerializer(false), blockData)
) // )
//
dataPacket.dataValueCollectionModifier.write(0, metadata) // dataPacket.dataValueCollectionModifier.write(0, metadata)
ProtocolLibrary.getProtocolManager().sendServerPacket(player, dataPacket) // ProtocolLibrary.getProtocolManager().sendServerPacket(player, dataPacket)
} // }
} }

View File

@ -1,5 +1,6 @@
package com.pobnellion.aoe.ui package com.pobnellion.aoe.ui
import com.comphenix.protocol.wrappers.EnumWrappers
import com.pobnellion.aoe.Aoe import com.pobnellion.aoe.Aoe
import com.pobnellion.aoe.building.BuildingInfo import com.pobnellion.aoe.building.BuildingInfo
import com.sk89q.worldedit.bukkit.BukkitAdapter import com.sk89q.worldedit.bukkit.BukkitAdapter
@ -36,6 +37,7 @@ class BuildingPlaceHint(
} }
private val schematic: Clipboard private val schematic: Clipboard
private var isValid = false
init { init {
val schematicName = buildingInfo.schematicNames[buildingVariant] val schematicName = buildingInfo.schematicNames[buildingVariant]
@ -53,9 +55,23 @@ class BuildingPlaceHint(
-floor(clipboard.dimensions.z() / 2.0)) -floor(clipboard.dimensions.z() / 2.0))
} }
override fun validate(location: Location) = buildingInfo.validate(location) override fun tick() {
// Update material
val valid = currentLocation?.let { buildingInfo.validate(it) } ?: false
override fun confirm() = onConfirm(currentLocation!!, buildingInfo, buildingVariant) if (valid != isValid) {
isValid = valid
updateGlowColour(if (isValid) EnumWrappers.ChatFormatting.GREEN else EnumWrappers.ChatFormatting.RED)
}
}
override fun confirm(): Boolean {
if (!isValid || currentLocation == null)
return false
onConfirm(currentLocation!!, buildingInfo, buildingVariant)
return true
}
override fun addDisplays(initialLocation: Location) { override fun addDisplays(initialLocation: Location) {
schematic.iterator().forEach { blockPosition -> schematic.iterator().forEach { blockPosition ->

View File

@ -2,8 +2,8 @@ package com.pobnellion.aoe.ui
import com.pobnellion.aoe.Aoe import com.pobnellion.aoe.Aoe
import com.pobnellion.aoe.building.BuildingType import com.pobnellion.aoe.building.BuildingType
import com.pobnellion.aoe.getCivilisation
import net.kyori.adventure.text.Component import net.kyori.adventure.text.Component
import org.bukkit.Bukkit
import org.bukkit.Material import org.bukkit.Material
import org.bukkit.entity.Player import org.bukkit.entity.Player
import org.bukkit.event.EventHandler import org.bukkit.event.EventHandler
@ -16,8 +16,8 @@ import org.bukkit.event.player.PlayerInteractEvent
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
class PlaceItem : Listener { class InventoryManager : Listener {
private val buildingInventory = Bukkit.createInventory(null, 9, Component.text("Buildings")) private val buildingInventory =
init { init {
buildingInventory.addItem(createGuiItem(Material.BELL, "Town center", "middle of the town :D")) buildingInventory.addItem(createGuiItem(Material.BELL, "Town center", "middle of the town :D"))
@ -25,6 +25,25 @@ class PlaceItem : Listener {
buildingInventory.addItem(createGuiItem(Material.EMERALD, "Villager", "willager")) buildingInventory.addItem(createGuiItem(Material.EMERALD, "Villager", "willager"))
} }
fun initHotbars() {
for (player in Aoe.players.keys) {
player.inventory.clear()
player.inventory.setItem(0, createGuiItem(Material.BRICKS, "Buildings"))
// TODO: double click select selects all of looking at type
player.inventory.setItem(6, createGuiItem(Material.WOODEN_HOE, "Select inactive villagers"))
player.inventory.setItem(7, createGuiItem(Material.IRON_HOE, "Select villagers"))
player.inventory.setItem(8, createGuiItem(Material.IRON_SWORD, "Select army"))
}
}
fun showBuildingInventory(player: Player) {
if (Aoe.isPlaying(player))
player.openInventory(player.getCivilisation()!!.buildingInventory.inventory)
}
// region events
@EventHandler @EventHandler
fun onRightClickItem(event: PlayerInteractEvent) { fun onRightClickItem(event: PlayerInteractEvent) {
if (event.action != Action.RIGHT_CLICK_AIR && event.action != Action.RIGHT_CLICK_BLOCK) if (event.action != Action.RIGHT_CLICK_AIR && event.action != Action.RIGHT_CLICK_BLOCK)
@ -40,18 +59,20 @@ class PlaceItem : Listener {
return return
event.isCancelled = true event.isCancelled = true
event.player.openInventory(buildingInventory) showBuildingInventory(event.player)
} }
@EventHandler @EventHandler
fun onInventoryClick(event: InventoryClickEvent) { fun onInventoryClick(event: InventoryClickEvent) {
if (Aoe.players.containsKey(event.whoClicked as Player))
event.isCancelled = true
val player = event.whoClicked as Player val player = event.whoClicked as Player
val team = Aoe.getTeam(player) ?: return val team = Aoe.getTeam(player) ?: return
if (event.inventory != buildingInventory) if (event.inventory != buildingInventory)
return return
event.isCancelled = true
var validClick = true var validClick = true
when (event.currentItem?.type) { when (event.currentItem?.type) {
@ -67,14 +88,19 @@ class PlaceItem : Listener {
@EventHandler @EventHandler
fun onInventoryClick(event: InventoryDragEvent) { fun onInventoryClick(event: InventoryDragEvent) {
if (event.inventory == buildingInventory) if (Aoe.players.containsKey(event.whoClicked as Player))
event.isCancelled = true event.isCancelled = true
} }
private fun createGuiItem(material: Material, name: String, lore: String): ItemStack { // endregion
private fun createGuiItem(material: Material, name: String, lore: String? = null): ItemStack {
val item = ItemStack(material, 1) val item = ItemStack(material, 1)
item.itemMeta.displayName(Component.text(name)) item.itemMeta.displayName(Component.text(name))
if (lore != null)
item.itemMeta.lore(mutableListOf(Component.text(lore))) item.itemMeta.lore(mutableListOf(Component.text(lore)))
return item return item
} }
} }

View File

@ -4,6 +4,7 @@ import com.comphenix.protocol.PacketType
import com.comphenix.protocol.ProtocolLibrary import com.comphenix.protocol.ProtocolLibrary
import com.comphenix.protocol.events.PacketContainer import com.comphenix.protocol.events.PacketContainer
import com.comphenix.protocol.wrappers.* import com.comphenix.protocol.wrappers.*
import com.comphenix.protocol.wrappers.EnumWrappers.ChatFormatting
import com.comphenix.protocol.wrappers.WrappedDataWatcher.Registry import com.comphenix.protocol.wrappers.WrappedDataWatcher.Registry
import com.destroystokyo.paper.MaterialSetTag import com.destroystokyo.paper.MaterialSetTag
import org.bukkit.Location import org.bukkit.Location
@ -73,10 +74,7 @@ abstract class PlaceHint {
// left click - confirm // left click - confirm
if (event.action == Action.LEFT_CLICK_BLOCK || event.action == Action.LEFT_CLICK_AIR) { if (event.action == Action.LEFT_CLICK_BLOCK || event.action == Action.LEFT_CLICK_AIR) {
if (!playerHints[event.player.uniqueId]!!.isValid) if (playerHints[event.player.uniqueId]!!.confirm())
return
playerHints[event.player.uniqueId]!!.confirm()
remove(event.player) remove(event.player)
} }
@ -91,7 +89,7 @@ abstract class PlaceHint {
.collisionRule("never") .collisionRule("never")
.nametagVisibility("never") .nametagVisibility("never")
.options(0) .options(0)
.color(EnumWrappers.ChatFormatting.RED) .color(ChatFormatting.RED)
.prefix(WrappedChatComponent.fromText("")) .prefix(WrappedChatComponent.fromText(""))
.suffix(WrappedChatComponent.fromText("")) .suffix(WrappedChatComponent.fromText(""))
.build() .build()
@ -102,11 +100,10 @@ abstract class PlaceHint {
private var marker: Pair<Int, UUID> = Pair((Math.random() * Int.MAX_VALUE).toInt(), UUID.randomUUID()) private var marker: Pair<Int, UUID> = Pair((Math.random() * Int.MAX_VALUE).toInt(), UUID.randomUUID())
protected val displayIds: MutableList<Pair<Int, UUID>> = mutableListOf() protected val displayIds: MutableList<Pair<Int, UUID>> = mutableListOf()
var currentLocation: Location? = null var currentLocation: Location? = null
var isValid = false
protected abstract fun addDisplays(initialLocation: Location) protected abstract fun addDisplays(initialLocation: Location)
protected abstract fun confirm() protected abstract fun confirm(): Boolean
protected abstract fun validate(location: Location): Boolean protected abstract fun tick()
private fun show(initialLocation: Location) { private fun show(initialLocation: Location) {
initialLocation.add(this.offset) initialLocation.add(this.offset)
@ -138,8 +135,7 @@ abstract class PlaceHint {
ProtocolLibrary.getProtocolManager().sendServerPacket(player, outlineTeamPacket) ProtocolLibrary.getProtocolManager().sendServerPacket(player, outlineTeamPacket)
ProtocolLibrary.getProtocolManager().sendServerPacket(player, passengerPacket) ProtocolLibrary.getProtocolManager().sendServerPacket(player, passengerPacket)
isValid = validate(initialLocation) tick()
updateColour()
} }
private fun hide() { private fun hide() {
@ -181,13 +177,7 @@ abstract class PlaceHint {
currentLocation = newLocation currentLocation = newLocation
// Update material this.tick()
val valid = validate(newLocation)
if (valid != isValid) {
isValid = valid
updateColour()
}
} }
// region helper functions // region helper functions
@ -234,13 +224,13 @@ abstract class PlaceHint {
return Pair<Int, UUID>(id, uuid) return Pair<Int, UUID>(id, uuid)
} }
protected open fun updateColour() { protected open fun updateGlowColour(colour: ChatFormatting) {
// outline glow // outline glow
val outlineTeamPacket = PacketContainer(PacketType.Play.Server.SCOREBOARD_TEAM) val outlineTeamPacket = PacketContainer(PacketType.Play.Server.SCOREBOARD_TEAM)
outlineTeamPacket.strings.write(0, "placeValid") outlineTeamPacket.strings.write(0, "placeValid")
outlineTeamPacket.integers.write(0, 2) outlineTeamPacket.integers.write(0, 2)
val params = WrappedTeamParameters.newBuilder(teamParamsTemplate) val params = WrappedTeamParameters.newBuilder(teamParamsTemplate)
.color(if (isValid) EnumWrappers.ChatFormatting.GREEN else EnumWrappers.ChatFormatting.RED) .color(colour)
.build() .build()
outlineTeamPacket.optionalTeamParameters.write(0, Optional.of(params)) outlineTeamPacket.optionalTeamParameters.write(0, Optional.of(params))