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.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.InventoryManager
|
import com.pobnellion.aoe.ui.UiManager
|
||||||
import org.bukkit.Bukkit
|
import org.bukkit.Bukkit
|
||||||
import org.bukkit.GameMode
|
import org.bukkit.GameMode
|
||||||
import org.bukkit.entity.Player
|
import org.bukkit.entity.Player
|
||||||
@ -21,7 +21,7 @@ class Aoe : JavaPlugin() {
|
|||||||
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 players: MutableMap<Player, CivilisationType> = mutableMapOf()
|
||||||
val inventoryManager: InventoryManager = InventoryManager()
|
val uiManager: UiManager = UiManager()
|
||||||
|
|
||||||
fun isPlaying(player: Player) = players.containsKey(player)
|
fun isPlaying(player: Player) = players.containsKey(player)
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ class Aoe : JavaPlugin() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
civilisations.values.forEach { civ -> civ.initSetup() }
|
civilisations.values.forEach { civ -> civ.initSetup() }
|
||||||
inventoryManager.initHotbars()
|
UiManager.setup()
|
||||||
|
|
||||||
gameInProgress = true
|
gameInProgress = true
|
||||||
}
|
}
|
||||||
@ -54,7 +54,7 @@ class Aoe : JavaPlugin() {
|
|||||||
instance = this
|
instance = this
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
Bukkit.getPluginManager().registerEvents(InventoryManager(), this)
|
Bukkit.getPluginManager().registerEvents(UiManager(), this)
|
||||||
Bukkit.getPluginManager().registerEvents(PlaceHint, this)
|
Bukkit.getPluginManager().registerEvents(PlaceHint, this)
|
||||||
|
|
||||||
// Commands
|
// Commands
|
||||||
|
|||||||
@ -3,4 +3,6 @@ package com.pobnellion.aoe
|
|||||||
object Constants {
|
object Constants {
|
||||||
const val MAX_POP_CAP = 200
|
const val MAX_POP_CAP = 200
|
||||||
const val STARTING_VILLAGER_COUNT = 5
|
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
|
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.pobnellion.aoe.entity.goals.EntityWorkTarget
|
||||||
import com.sk89q.worldedit.WorldEdit
|
import com.sk89q.worldedit.WorldEdit
|
||||||
import com.sk89q.worldedit.bukkit.BukkitAdapter
|
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.Operation
|
||||||
import com.sk89q.worldedit.function.operation.Operations
|
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 org.bukkit.util.Vector
|
||||||
import java.io.File
|
|
||||||
import java.io.FileInputStream
|
|
||||||
|
|
||||||
abstract class Building(val location: Location, val variant: Int): EntityWorkTarget {
|
abstract class Building(val location: Location, val variant: Int): EntityWorkTarget {
|
||||||
override var currentProgressPercent: Float = 0f
|
override var currentProgressPercent: Float = 0f
|
||||||
@ -26,16 +22,14 @@ abstract class Building(val location: Location, val variant: Int): EntityWorkTar
|
|||||||
var sizeX: Int
|
var sizeX: Int
|
||||||
var sizeZ: Int
|
var sizeZ: Int
|
||||||
fun center(): Location = location.clone().add(sizeX / 2.0, 0.0, sizeZ / 2.0)
|
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
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val file: File = Aoe.getSchematicFile(this.getSchematicName(variant))
|
val clipboard = SchematicManager.get(this.getSchematicName(variant))
|
||||||
val format = ClipboardFormats.findByFile(file)
|
|
||||||
format!!.getReader(FileInputStream(file)).use { reader ->
|
if (clipboard == null)
|
||||||
clipboard = reader.read()
|
throw NullPointerException("Schematic ${this.getSchematicName(variant)} not found")
|
||||||
}
|
|
||||||
|
|
||||||
sizeX = clipboard.maximumPoint.x() - clipboard.minimumPoint.x()
|
sizeX = clipboard.maximumPoint.x() - clipboard.minimumPoint.x()
|
||||||
sizeZ = clipboard.maximumPoint.z() - clipboard.minimumPoint.z()
|
sizeZ = clipboard.maximumPoint.z() - clipboard.minimumPoint.z()
|
||||||
@ -43,7 +37,8 @@ abstract class Building(val location: Location, val variant: Int): EntityWorkTar
|
|||||||
|
|
||||||
fun placeFull() {
|
fun placeFull() {
|
||||||
currentProgressPercent = 1f
|
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 ->
|
WorldEdit.getInstance().newEditSession(BukkitAdapter.adapt(location.world)).use { editSession ->
|
||||||
val operation: Operation = ClipboardHolder(clipboard)
|
val operation: Operation = ClipboardHolder(clipboard)
|
||||||
@ -58,7 +53,18 @@ 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
|
||||||
|
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.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 com.pobnellion.aoe.ui.inventory.BuildingInventory
|
||||||
import org.bukkit.Location
|
import org.bukkit.Location
|
||||||
import org.bukkit.craftbukkit.CraftWorld
|
import org.bukkit.Material
|
||||||
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
|
||||||
@ -20,17 +19,20 @@ abstract class Civilisation(
|
|||||||
private val setupLocation: Location
|
private val setupLocation: Location
|
||||||
) {
|
) {
|
||||||
private val buildings: MutableList<Building> = mutableListOf()
|
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 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 fun getBuildingInfo(type: BuildingType): BuildingInfo
|
||||||
protected abstract val name: String
|
protected abstract val name: String
|
||||||
protected abstract val type: CivilisationType
|
protected abstract val type: CivilisationType
|
||||||
|
|
||||||
init {
|
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 {
|
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 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.BuildingInfo
|
||||||
import com.pobnellion.aoe.building.BuildingType
|
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.PlainsHouse
|
||||||
import com.pobnellion.aoe.building.plains.PlainsTownCenter
|
import com.pobnellion.aoe.building.plains.PlainsTownCenter
|
||||||
import org.bukkit.Location
|
import org.bukkit.Location
|
||||||
@ -10,6 +11,11 @@ class Plains(setupLocation: Location) : Civilisation(setupLocation) {
|
|||||||
override val name: String = "Plains"
|
override val name: String = "Plains"
|
||||||
override val type: CivilisationType = CivilisationType.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 {
|
override fun getBuildingInfo(type: BuildingType): BuildingInfo {
|
||||||
return when (type) {
|
return when (type) {
|
||||||
BuildingType.ARCHERY_RANGE -> TODO()
|
BuildingType.ARCHERY_RANGE -> TODO()
|
||||||
|
|||||||
@ -18,6 +18,8 @@ class AoeVillager(location: Location, var civilisationType: CivilisationType)
|
|||||||
targetSelector.removeAllGoals { true }
|
targetSelector.removeAllGoals { true }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var isActive: Boolean = false;
|
||||||
|
|
||||||
fun leaveBuilding(building: Building) {
|
fun leaveBuilding(building: Building) {
|
||||||
targetSelector.addGoal(0, LeaveBuildingGoal(this, building, 1.0))
|
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,
|
onTick: (Location, Float, Float, Float) -> Unit,
|
||||||
) {
|
) {
|
||||||
remove(player)
|
remove(player)
|
||||||
createOutlineTeam(player)
|
|
||||||
|
|
||||||
playerHints[player.uniqueId] = AreaPlaceHint(player, sizeX, sizeY, sizeZ, onConfirm, onTick)
|
playerHints[player.uniqueId] = AreaPlaceHint(player, sizeX, sizeY, sizeZ, onConfirm, onTick)
|
||||||
val block = player.getTargetBlockExact(MAX_TARGET_DISTANCE)
|
val block = player.getTargetBlockExact(MAX_TARGET_DISTANCE)
|
||||||
|
|||||||
@ -28,7 +28,6 @@ class BuildingPlaceHint(
|
|||||||
buildingVariant: Int = 0
|
buildingVariant: Int = 0
|
||||||
) {
|
) {
|
||||||
remove(player)
|
remove(player)
|
||||||
createOutlineTeam(player)
|
|
||||||
|
|
||||||
playerHints[player.uniqueId] = BuildingPlaceHint(player, buildingInfo, onConfirm, buildingVariant)
|
playerHints[player.uniqueId] = BuildingPlaceHint(player, buildingInfo, onConfirm, buildingVariant)
|
||||||
val block = player.getTargetBlockExact(MAX_TARGET_DISTANCE)
|
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.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 com.pobnellion.aoe.Constants
|
||||||
import org.bukkit.Location
|
import org.bukkit.Location
|
||||||
import org.bukkit.block.data.BlockData
|
import org.bukkit.block.data.BlockData
|
||||||
import org.bukkit.entity.EntityType
|
import org.bukkit.entity.EntityType
|
||||||
@ -44,16 +45,6 @@ abstract class PlaceHint {
|
|||||||
return playerHints.containsKey(player.uniqueId)
|
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
|
@EventHandler
|
||||||
fun onPlayerLook(event: PlayerMoveEvent) {
|
fun onPlayerLook(event: PlayerMoveEvent) {
|
||||||
if (!playerHints.containsKey(event.player.uniqueId))
|
if (!playerHints.containsKey(event.player.uniqueId))
|
||||||
@ -83,16 +74,6 @@ abstract class PlaceHint {
|
|||||||
remove(event.player)
|
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
|
protected abstract val player: Player
|
||||||
@ -120,19 +101,12 @@ abstract class PlaceHint {
|
|||||||
|
|
||||||
addDisplays(initialLocation)
|
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)
|
val passengerPacket = PacketContainer(PacketType.Play.Server.MOUNT)
|
||||||
passengerPacket.integers.write(0, marker.first)
|
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, spawnMarkerPacket)
|
||||||
ProtocolLibrary.getProtocolManager().sendServerPacket(player, outlineTeamPacket)
|
|
||||||
ProtocolLibrary.getProtocolManager().sendServerPacket(player, passengerPacket)
|
ProtocolLibrary.getProtocolManager().sendServerPacket(player, passengerPacket)
|
||||||
|
|
||||||
tick()
|
tick()
|
||||||
@ -227,9 +201,9 @@ abstract class PlaceHint {
|
|||||||
protected open fun updateGlowColour(colour: ChatFormatting) {
|
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, Constants.PLACE_HINT_TEAM)
|
||||||
outlineTeamPacket.integers.write(0, 2)
|
outlineTeamPacket.integers.write(0, 2)
|
||||||
val params = WrappedTeamParameters.newBuilder(teamParamsTemplate)
|
val params = WrappedTeamParameters.newBuilder(UiManager.teamParamsTemplate)
|
||||||
.color(colour)
|
.color(colour)
|
||||||
.build()
|
.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