Ui management reshuffling and start on schematic manager
This commit is contained in:
@ -6,7 +6,7 @@ import com.pobnellion.aoe.civilisation.Civilisation
|
||||
import com.pobnellion.aoe.civilisation.CivilisationType
|
||||
import com.pobnellion.aoe.map.AoeMap
|
||||
import com.pobnellion.aoe.ui.PlaceHint
|
||||
import com.pobnellion.aoe.ui.InventoryManager
|
||||
import com.pobnellion.aoe.ui.UiManager
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.GameMode
|
||||
import org.bukkit.entity.Player
|
||||
@ -21,7 +21,7 @@ class Aoe : JavaPlugin() {
|
||||
val civilisations: MutableMap<CivilisationType, Civilisation> = mutableMapOf()
|
||||
val map: AoeMap = AoeMap()
|
||||
val players: MutableMap<Player, CivilisationType> = mutableMapOf()
|
||||
val inventoryManager: InventoryManager = InventoryManager()
|
||||
val uiManager: UiManager = UiManager()
|
||||
|
||||
fun isPlaying(player: Player) = players.containsKey(player)
|
||||
|
||||
@ -44,7 +44,7 @@ class Aoe : JavaPlugin() {
|
||||
}
|
||||
|
||||
civilisations.values.forEach { civ -> civ.initSetup() }
|
||||
inventoryManager.initHotbars()
|
||||
UiManager.setup()
|
||||
|
||||
gameInProgress = true
|
||||
}
|
||||
@ -54,7 +54,7 @@ class Aoe : JavaPlugin() {
|
||||
instance = this
|
||||
|
||||
// Events
|
||||
Bukkit.getPluginManager().registerEvents(InventoryManager(), this)
|
||||
Bukkit.getPluginManager().registerEvents(UiManager(), this)
|
||||
Bukkit.getPluginManager().registerEvents(PlaceHint, this)
|
||||
|
||||
// Commands
|
||||
|
||||
@ -3,4 +3,6 @@ package com.pobnellion.aoe
|
||||
object Constants {
|
||||
const val MAX_POP_CAP = 200
|
||||
const val STARTING_VILLAGER_COUNT = 5
|
||||
const val ENTITY_SELECTION_TEAM = "entitySelection"
|
||||
const val PLACE_HINT_TEAM = "placeValid"
|
||||
}
|
||||
@ -1,19 +1,15 @@
|
||||
package com.pobnellion.aoe.building
|
||||
|
||||
import com.pobnellion.aoe.Aoe
|
||||
import com.pobnellion.aoe.building.plains.PlainsTownCenter
|
||||
import com.pobnellion.aoe.entity.goals.EntityWorkTarget
|
||||
import com.sk89q.worldedit.WorldEdit
|
||||
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.function.operation.Operation
|
||||
import com.sk89q.worldedit.function.operation.Operations
|
||||
import com.sk89q.worldedit.math.BlockVector3
|
||||
import com.sk89q.worldedit.session.ClipboardHolder
|
||||
import org.bukkit.Location
|
||||
import org.bukkit.util.Vector
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
|
||||
abstract class Building(val location: Location, val variant: Int): EntityWorkTarget {
|
||||
override var currentProgressPercent: Float = 0f
|
||||
@ -26,16 +22,14 @@ abstract class Building(val location: Location, val variant: Int): EntityWorkTar
|
||||
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 fun getSchematicName(variant: Int): String
|
||||
|
||||
init {
|
||||
val file: File = Aoe.getSchematicFile(this.getSchematicName(variant))
|
||||
val format = ClipboardFormats.findByFile(file)
|
||||
format!!.getReader(FileInputStream(file)).use { reader ->
|
||||
clipboard = reader.read()
|
||||
}
|
||||
val clipboard = SchematicManager.get(this.getSchematicName(variant))
|
||||
|
||||
if (clipboard == null)
|
||||
throw NullPointerException("Schematic ${this.getSchematicName(variant)} not found")
|
||||
|
||||
sizeX = clipboard.maximumPoint.x() - clipboard.minimumPoint.x()
|
||||
sizeZ = clipboard.maximumPoint.z() - clipboard.minimumPoint.z()
|
||||
@ -43,7 +37,8 @@ abstract class Building(val location: Location, val variant: Int): EntityWorkTar
|
||||
|
||||
fun placeFull() {
|
||||
currentProgressPercent = 1f
|
||||
val offset = clipboard.region.minimumPoint.subtract(clipboard.origin)
|
||||
val clipboard = SchematicManager.get(this.getSchematicName(variant))
|
||||
val offset = clipboard!!.region.minimumPoint.subtract(clipboard.origin)
|
||||
|
||||
WorldEdit.getInstance().newEditSession(BukkitAdapter.adapt(location.world)).use { editSession ->
|
||||
val operation: Operation = ClipboardHolder(clipboard)
|
||||
@ -58,7 +53,18 @@ abstract class Building(val location: Location, val variant: Int): EntityWorkTar
|
||||
interface BuildingInfo {
|
||||
val buildingType: BuildingType
|
||||
val schematicNames: List<String>
|
||||
fun getSize(variant: Int): Vector
|
||||
fun validate(location: Location): Boolean
|
||||
fun create(location: Location, variant: Int): Building
|
||||
fun getSize(variant: Int): Vector {
|
||||
val clipboard = SchematicManager.get(schematicNames[variant])
|
||||
|
||||
if (clipboard == null)
|
||||
throw NullPointerException("Schematic ${schematicNames[variant]} not found")
|
||||
|
||||
val sizeX = clipboard.maximumPoint.x() - clipboard.minimumPoint.x()
|
||||
val sizeY = clipboard.maximumPoint.y() - clipboard.minimumPoint.y()
|
||||
val sizeZ = clipboard.maximumPoint.z() - clipboard.minimumPoint.z()
|
||||
|
||||
return Vector(sizeX, sizeY, sizeZ)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
package com.pobnellion.aoe.building
|
||||
|
||||
import com.pobnellion.aoe.Aoe
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard
|
||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
|
||||
object SchematicManager {
|
||||
private val schematics: MutableMap<String, Clipboard> = mutableMapOf()
|
||||
|
||||
fun add(schematicName: String) {
|
||||
if (!schematics.containsKey(schematicName))
|
||||
loadSchematic(schematicName)
|
||||
}
|
||||
|
||||
fun add(schematicNames: List<String>) {
|
||||
for (schematicName in schematicNames)
|
||||
if (!schematics.containsKey(schematicName))
|
||||
loadSchematic(schematicName)
|
||||
}
|
||||
|
||||
fun get(schematicName: String): Clipboard? = schematics[schematicName]
|
||||
|
||||
private fun loadSchematic(schematicName: String) {
|
||||
// TODO: do this in the background async style
|
||||
val clipboard: Clipboard
|
||||
val file: File = Aoe.getSchematicFile(schematicName)
|
||||
val format = ClipboardFormats.findByFile(file)
|
||||
format!!.getReader(FileInputStream(file)).use { reader ->
|
||||
clipboard = reader.read()
|
||||
}
|
||||
schematics[schematicName] = clipboard
|
||||
}
|
||||
}
|
||||
@ -7,11 +7,10 @@ import com.pobnellion.aoe.building.BuildingInfo
|
||||
import com.pobnellion.aoe.building.BuildingType
|
||||
import com.pobnellion.aoe.building.TownCenter
|
||||
import com.pobnellion.aoe.entity.AoeVillager
|
||||
import com.pobnellion.aoe.ui.AoeInventory
|
||||
import com.pobnellion.aoe.ui.BuildingPlaceHint
|
||||
import net.minecraft.world.phys.AABB
|
||||
import com.pobnellion.aoe.ui.inventory.BuildingInventory
|
||||
import org.bukkit.Location
|
||||
import org.bukkit.craftbukkit.CraftWorld
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.entity.Player
|
||||
import kotlin.math.min
|
||||
import kotlin.random.Random
|
||||
@ -20,17 +19,20 @@ abstract class Civilisation(
|
||||
private val setupLocation: Location
|
||||
) {
|
||||
private val buildings: MutableList<Building> = mutableListOf()
|
||||
private val villagers: MutableList<AoeVillager> = mutableListOf()
|
||||
public val villagers: MutableList<AoeVillager> = mutableListOf()
|
||||
|
||||
val players get() = Aoe.players.filter { player -> player.value == this.type }.keys
|
||||
val buildingInventory = AoeInventory("Buildings", BuildingType.entries.size)
|
||||
val buildingInventory = BuildingInventory()
|
||||
|
||||
protected abstract fun addSchematicsToManager()
|
||||
protected abstract fun getBuildingInfo(type: BuildingType): BuildingInfo
|
||||
protected abstract val name: String
|
||||
protected abstract val type: CivilisationType
|
||||
|
||||
init {
|
||||
buildingInventory.addItem()
|
||||
buildingInventory.add(BuildingType.TOWN_CENTER, Material.BELL, "Town center")
|
||||
buildingInventory.add(BuildingType.HOUSE, Material.OAK_DOOR, "House")
|
||||
addSchematicsToManager()
|
||||
}
|
||||
|
||||
fun addBuilding(location: Location, buildingInfo: BuildingInfo, variant: Int): Building {
|
||||
@ -72,12 +74,4 @@ abstract class Civilisation(
|
||||
}
|
||||
|
||||
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 }
|
||||
}
|
||||
}
|
||||
@ -2,6 +2,7 @@ package com.pobnellion.aoe.civilisation
|
||||
|
||||
import com.pobnellion.aoe.building.BuildingInfo
|
||||
import com.pobnellion.aoe.building.BuildingType
|
||||
import com.pobnellion.aoe.building.SchematicManager
|
||||
import com.pobnellion.aoe.building.plains.PlainsHouse
|
||||
import com.pobnellion.aoe.building.plains.PlainsTownCenter
|
||||
import org.bukkit.Location
|
||||
@ -10,6 +11,11 @@ class Plains(setupLocation: Location) : Civilisation(setupLocation) {
|
||||
override val name: String = "Plains"
|
||||
override val type: CivilisationType = CivilisationType.PLAINS
|
||||
|
||||
override fun addSchematicsToManager() {
|
||||
SchematicManager.add(PlainsTownCenter.Info.schematicNames)
|
||||
SchematicManager.add(PlainsHouse.Info.schematicNames)
|
||||
}
|
||||
|
||||
override fun getBuildingInfo(type: BuildingType): BuildingInfo {
|
||||
return when (type) {
|
||||
BuildingType.ARCHERY_RANGE -> TODO()
|
||||
|
||||
@ -18,6 +18,8 @@ class AoeVillager(location: Location, var civilisationType: CivilisationType)
|
||||
targetSelector.removeAllGoals { true }
|
||||
}
|
||||
|
||||
var isActive: Boolean = false;
|
||||
|
||||
fun leaveBuilding(building: Building) {
|
||||
targetSelector.addGoal(0, LeaveBuildingGoal(this, building, 1.0))
|
||||
}
|
||||
|
||||
@ -1,13 +0,0 @@
|
||||
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() {
|
||||
|
||||
}
|
||||
}
|
||||
@ -27,7 +27,6 @@ class AreaPlaceHint(
|
||||
onTick: (Location, Float, Float, Float) -> Unit,
|
||||
) {
|
||||
remove(player)
|
||||
createOutlineTeam(player)
|
||||
|
||||
playerHints[player.uniqueId] = AreaPlaceHint(player, sizeX, sizeY, sizeZ, onConfirm, onTick)
|
||||
val block = player.getTargetBlockExact(MAX_TARGET_DISTANCE)
|
||||
|
||||
@ -28,7 +28,6 @@ class BuildingPlaceHint(
|
||||
buildingVariant: Int = 0
|
||||
) {
|
||||
remove(player)
|
||||
createOutlineTeam(player)
|
||||
|
||||
playerHints[player.uniqueId] = BuildingPlaceHint(player, buildingInfo, onConfirm, buildingVariant)
|
||||
val block = player.getTargetBlockExact(MAX_TARGET_DISTANCE)
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
package com.pobnellion.aoe.ui
|
||||
|
||||
enum class EntitySelectionMode {
|
||||
RADIUS,
|
||||
AREA_HINT,
|
||||
TWO_POINTS
|
||||
}
|
||||
@ -1,106 +0,0 @@
|
||||
package com.pobnellion.aoe.ui
|
||||
|
||||
import com.pobnellion.aoe.Aoe
|
||||
import com.pobnellion.aoe.building.BuildingType
|
||||
import com.pobnellion.aoe.getCivilisation
|
||||
import net.kyori.adventure.text.Component
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.block.Action
|
||||
import org.bukkit.event.inventory.InventoryClickEvent
|
||||
import org.bukkit.event.inventory.InventoryCloseEvent
|
||||
import org.bukkit.event.inventory.InventoryDragEvent
|
||||
import org.bukkit.event.player.PlayerInteractEvent
|
||||
import org.bukkit.inventory.ItemStack
|
||||
|
||||
|
||||
class InventoryManager : Listener {
|
||||
private val buildingInventory =
|
||||
|
||||
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.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
|
||||
fun onRightClickItem(event: PlayerInteractEvent) {
|
||||
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
|
||||
|
||||
if (Aoe.getTeam(event.player) == null)
|
||||
return
|
||||
|
||||
event.isCancelled = true
|
||||
showBuildingInventory(event.player)
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onInventoryClick(event: InventoryClickEvent) {
|
||||
if (Aoe.players.containsKey(event.whoClicked as Player))
|
||||
event.isCancelled = true
|
||||
|
||||
val player = event.whoClicked as Player
|
||||
val team = Aoe.getTeam(player) ?: return
|
||||
|
||||
if (event.inventory != buildingInventory)
|
||||
return
|
||||
|
||||
var validClick = true
|
||||
|
||||
when (event.currentItem?.type) {
|
||||
Material.OAK_LOG -> team.showBuildingPlaceHint(BuildingType.HOUSE, player)
|
||||
Material.BELL -> team.showBuildingPlaceHint(BuildingType.TOWN_CENTER, player)
|
||||
Material.EMERALD -> {}
|
||||
else -> validClick = false
|
||||
}
|
||||
|
||||
if (validClick)
|
||||
event.whoClicked.closeInventory(InventoryCloseEvent.Reason.PLUGIN)
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onInventoryClick(event: InventoryDragEvent) {
|
||||
if (Aoe.players.containsKey(event.whoClicked as Player))
|
||||
event.isCancelled = true
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
private fun createGuiItem(material: Material, name: String, lore: String? = null): ItemStack {
|
||||
val item = ItemStack(material, 1)
|
||||
item.itemMeta.displayName(Component.text(name))
|
||||
|
||||
if (lore != null)
|
||||
item.itemMeta.lore(mutableListOf(Component.text(lore)))
|
||||
|
||||
return item
|
||||
}
|
||||
}
|
||||
@ -7,6 +7,7 @@ import com.comphenix.protocol.wrappers.*
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.ChatFormatting
|
||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher.Registry
|
||||
import com.destroystokyo.paper.MaterialSetTag
|
||||
import com.pobnellion.aoe.Constants
|
||||
import org.bukkit.Location
|
||||
import org.bukkit.block.data.BlockData
|
||||
import org.bukkit.entity.EntityType
|
||||
@ -44,16 +45,6 @@ abstract class PlaceHint {
|
||||
return playerHints.containsKey(player.uniqueId)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
protected fun createOutlineTeam(player: Player) {
|
||||
val packet = PacketContainer(PacketType.Play.Server.SCOREBOARD_TEAM)
|
||||
packet.strings.write(0, "placeValid")
|
||||
packet.integers.write(0, 0)
|
||||
packet.optionalTeamParameters.write(0, Optional.of(teamParamsTemplate))
|
||||
|
||||
ProtocolLibrary.getProtocolManager().sendServerPacket(player, packet)
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onPlayerLook(event: PlayerMoveEvent) {
|
||||
if (!playerHints.containsKey(event.player.uniqueId))
|
||||
@ -83,16 +74,6 @@ abstract class PlaceHint {
|
||||
remove(event.player)
|
||||
}
|
||||
}
|
||||
|
||||
private val teamParamsTemplate: WrappedTeamParameters = WrappedTeamParameters.newBuilder()
|
||||
.displayName(WrappedChatComponent.fromText(""))
|
||||
.collisionRule("never")
|
||||
.nametagVisibility("never")
|
||||
.options(0)
|
||||
.color(ChatFormatting.RED)
|
||||
.prefix(WrappedChatComponent.fromText(""))
|
||||
.suffix(WrappedChatComponent.fromText(""))
|
||||
.build()
|
||||
}
|
||||
|
||||
protected abstract val player: Player
|
||||
@ -120,19 +101,12 @@ abstract class PlaceHint {
|
||||
|
||||
addDisplays(initialLocation)
|
||||
|
||||
val outlineTeamPacket = PacketContainer(PacketType.Play.Server.SCOREBOARD_TEAM)
|
||||
outlineTeamPacket.strings.write(0, "placeValid")
|
||||
outlineTeamPacket.integers.write(0, 3)
|
||||
outlineTeamPacket.getSpecificModifier(Collection::class.java).write(0, displayIds.map { it.second.toString() })
|
||||
|
||||
val ids = displayIds.map { it.first }.toMutableList()
|
||||
|
||||
val passengerPacket = PacketContainer(PacketType.Play.Server.MOUNT)
|
||||
passengerPacket.integers.write(0, marker.first)
|
||||
passengerPacket.integerArrays.write(0, ids.toIntArray())
|
||||
passengerPacket.integerArrays.write(0, displayIds.map { it.first }.toIntArray())
|
||||
|
||||
UiManager.updateTeamEntities(player, Constants.PLACE_HINT_TEAM, displayIds.map { it.second.toString() })
|
||||
ProtocolLibrary.getProtocolManager().sendServerPacket(player, spawnMarkerPacket)
|
||||
ProtocolLibrary.getProtocolManager().sendServerPacket(player, outlineTeamPacket)
|
||||
ProtocolLibrary.getProtocolManager().sendServerPacket(player, passengerPacket)
|
||||
|
||||
tick()
|
||||
@ -227,9 +201,9 @@ abstract class PlaceHint {
|
||||
protected open fun updateGlowColour(colour: ChatFormatting) {
|
||||
// outline glow
|
||||
val outlineTeamPacket = PacketContainer(PacketType.Play.Server.SCOREBOARD_TEAM)
|
||||
outlineTeamPacket.strings.write(0, "placeValid")
|
||||
outlineTeamPacket.strings.write(0, Constants.PLACE_HINT_TEAM)
|
||||
outlineTeamPacket.integers.write(0, 2)
|
||||
val params = WrappedTeamParameters.newBuilder(teamParamsTemplate)
|
||||
val params = WrappedTeamParameters.newBuilder(UiManager.teamParamsTemplate)
|
||||
.color(colour)
|
||||
.build()
|
||||
|
||||
|
||||
173
src/main/kotlin/com/pobnellion/aoe/ui/UiManager.kt
Normal file
173
src/main/kotlin/com/pobnellion/aoe/ui/UiManager.kt
Normal file
@ -0,0 +1,173 @@
|
||||
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.EnumWrappers.ChatFormatting
|
||||
import com.comphenix.protocol.wrappers.WrappedChatComponent
|
||||
import com.comphenix.protocol.wrappers.WrappedTeamParameters
|
||||
import com.pobnellion.aoe.Aoe
|
||||
import com.pobnellion.aoe.Constants
|
||||
import com.pobnellion.aoe.building.BuildingType
|
||||
import com.pobnellion.aoe.getCivilisation
|
||||
import net.kyori.adventure.text.Component
|
||||
import net.minecraft.world.entity.Entity
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.block.Action
|
||||
import org.bukkit.event.inventory.InventoryClickEvent
|
||||
import org.bukkit.event.inventory.InventoryCloseEvent
|
||||
import org.bukkit.event.inventory.InventoryDragEvent
|
||||
import org.bukkit.event.player.PlayerInteractEvent
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import org.bukkit.util.BoundingBox
|
||||
import java.util.Optional
|
||||
import kotlin.math.pow
|
||||
|
||||
|
||||
class UiManager : Listener {
|
||||
companion object {
|
||||
fun createGuiItem(material: Material, name: String, lore: String? = null): ItemStack {
|
||||
val item = ItemStack(material, 1)
|
||||
item.itemMeta.displayName(Component.text(name))
|
||||
|
||||
if (lore != null)
|
||||
item.itemMeta.lore(mutableListOf(Component.text(lore)))
|
||||
|
||||
return item
|
||||
}
|
||||
|
||||
fun setup() {
|
||||
for (player in Aoe.players.keys) {
|
||||
// Init hotbars
|
||||
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"))
|
||||
|
||||
// TODO: resend these on rejoin
|
||||
// Send teams
|
||||
createTeamForPlayer(player, Constants.ENTITY_SELECTION_TEAM)
|
||||
createTeamForPlayer(player, Constants.PLACE_HINT_TEAM)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun createTeamForPlayer(player: Player, teamName: String) {
|
||||
val packet = PacketContainer(PacketType.Play.Server.SCOREBOARD_TEAM)
|
||||
packet.strings.write(0, teamName)
|
||||
packet.integers.write(0, 0)
|
||||
packet.optionalTeamParameters.write(0, Optional.of(teamParamsTemplate))
|
||||
|
||||
ProtocolLibrary.getProtocolManager().sendServerPacket(player, packet)
|
||||
}
|
||||
|
||||
fun updateTeamEntities(player: Player, teamName: String, entityIds: List<String>, remove: Boolean = false) {
|
||||
val teamEntitiesPacket = PacketContainer(PacketType.Play.Server.SCOREBOARD_TEAM)
|
||||
teamEntitiesPacket.strings.write(0, teamName)
|
||||
teamEntitiesPacket.integers.write(0, if (remove) 4 else 3)
|
||||
teamEntitiesPacket.getSpecificModifier(Collection::class.java).write(0, entityIds)
|
||||
ProtocolLibrary.getProtocolManager().sendServerPacket(player, teamEntitiesPacket)
|
||||
}
|
||||
|
||||
val teamParamsTemplate: WrappedTeamParameters = WrappedTeamParameters.newBuilder()
|
||||
.displayName(WrappedChatComponent.fromText(""))
|
||||
.collisionRule("never")
|
||||
.nametagVisibility("never")
|
||||
.options(0)
|
||||
.color(ChatFormatting.WHITE)
|
||||
.prefix(WrappedChatComponent.fromText(""))
|
||||
.suffix(WrappedChatComponent.fromText(""))
|
||||
.build()
|
||||
}
|
||||
|
||||
private val playerSelections: MutableMap<Player, List<Entity>> = mutableMapOf()
|
||||
private val playerSelectionModes: MutableMap<Player, EntitySelectionMode> = mutableMapOf()
|
||||
|
||||
private fun selectEntities(player: Player, entities: List<Entity>) {
|
||||
deselectEntities(player)
|
||||
playerSelections[player] = entities
|
||||
updateTeamEntities(player, Constants.ENTITY_SELECTION_TEAM, entities.map { it.uuid.toString() })
|
||||
}
|
||||
|
||||
private fun deselectEntities(player: Player) {
|
||||
if (!playerSelections.containsKey(player))
|
||||
return
|
||||
|
||||
updateTeamEntities(player, Constants.ENTITY_SELECTION_TEAM, playerSelections[player]!!.map { it.uuid.toString() }, true)
|
||||
playerSelections.remove(player)
|
||||
}
|
||||
|
||||
// region events
|
||||
|
||||
@EventHandler
|
||||
fun onRightClickItem(event: PlayerInteractEvent) {
|
||||
if (event.action != Action.RIGHT_CLICK_AIR && event.action != Action.RIGHT_CLICK_BLOCK)
|
||||
return
|
||||
|
||||
if (Aoe.isPlaying(event.player))
|
||||
return
|
||||
|
||||
if (PlaceHint.contains(event.player))
|
||||
return
|
||||
|
||||
val civilisation = event.player.getCivilisation()
|
||||
|
||||
if (civilisation == null)
|
||||
return
|
||||
|
||||
when (event.material) {
|
||||
Material.BRICKS -> event.player.openInventory(civilisation.buildingInventory.inventory)
|
||||
Material.WOODEN_HOE -> selectEntities(event.player, civilisation.villagers.filter { !it.isActive })
|
||||
Material.IRON_HOE -> selectEntities(event.player, civilisation.villagers)
|
||||
Material.IRON_SWORD -> {}
|
||||
else -> return
|
||||
}
|
||||
|
||||
event.isCancelled = true
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onInventoryClick(event: InventoryClickEvent) {
|
||||
if (Aoe.players.containsKey(event.whoClicked as Player))
|
||||
event.isCancelled = true
|
||||
|
||||
val player = event.whoClicked as Player
|
||||
val team = Aoe.getTeam(player) ?: return
|
||||
|
||||
var validClick = true
|
||||
|
||||
when (event.currentItem?.type) {
|
||||
Material.OAK_LOG -> team.showBuildingPlaceHint(BuildingType.HOUSE, player)
|
||||
Material.BELL -> team.showBuildingPlaceHint(BuildingType.TOWN_CENTER, player)
|
||||
Material.EMERALD -> {}
|
||||
else -> validClick = false
|
||||
}
|
||||
|
||||
if (validClick)
|
||||
event.whoClicked.closeInventory(InventoryCloseEvent.Reason.PLUGIN)
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onInventoryClick(event: InventoryDragEvent) {
|
||||
if (Aoe.players.containsKey(event.whoClicked as Player))
|
||||
event.isCancelled = true
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region helper functions
|
||||
|
||||
fun getEntitiesInArea(entities: List<Entity>, boundingBox: BoundingBox) =
|
||||
entities.filter { entity -> boundingBox.contains(entity.x, entity.y, entity.z) }
|
||||
|
||||
fun getEntitiesAroundPlayer(entities: List<Entity>, player: Player, distance: Float) =
|
||||
entities.filter { villager -> villager.distanceToSqr(player.x, player.y, player.z) <= distance.pow(2) }
|
||||
|
||||
// endregion
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
package com.pobnellion.aoe.ui.inventory
|
||||
|
||||
import com.pobnellion.aoe.ui.UiManager
|
||||
import net.kyori.adventure.text.Component
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.inventory.Inventory
|
||||
|
||||
abstract class AoeInventory(name: String, size: Int) {
|
||||
val inventory: Inventory = Bukkit.createInventory(null, size + size % 9, Component.text(name))
|
||||
|
||||
fun addItem(material: Material, name: String, lore: String? = null) {
|
||||
inventory.addItem(UiManager.Companion.createGuiItem(material, name, lore))
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
package com.pobnellion.aoe.ui.inventory
|
||||
|
||||
import com.pobnellion.aoe.building.BuildingType
|
||||
import org.bukkit.Material
|
||||
|
||||
class BuildingInventory: AoeInventory("Buildings", BuildingType.entries.size) {
|
||||
private val buildings: MutableMap<Material, BuildingType> = mutableMapOf()
|
||||
|
||||
fun add(buildingType: BuildingType, material: Material, name: String, lore: String? = null) {
|
||||
addItem(material, name, lore)
|
||||
buildings[material] = buildingType
|
||||
}
|
||||
|
||||
fun getBuilding(material: Material) = buildings[material]
|
||||
}
|
||||
Reference in New Issue
Block a user