nms custom villager and restructuring for teams
This commit is contained in:
@ -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
|
||||
|
||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -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
|
||||
|
||||
@ -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())
|
||||
|
||||
@ -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())
|
||||
|
||||
@ -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
|
||||
}
|
||||
12
src/main/kotlin/com/pobnellion/aoe/building/BuildingType.kt
Normal file
12
src/main/kotlin/com/pobnellion/aoe/building/BuildingType.kt
Normal file
@ -0,0 +1,12 @@
|
||||
package com.pobnellion.aoe.building
|
||||
|
||||
enum class BuildingType {
|
||||
BARRACKS,
|
||||
FARM,
|
||||
HOUSE,
|
||||
MILL,
|
||||
TOWN_CENTER,
|
||||
UNIQUE,
|
||||
WALL,
|
||||
WATCH_TOWER,
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
|
||||
fun place(location: Location, sizeX: Float, sizeY: Float, sizeZ: Float) {
|
||||
override fun create(location: Location, variant: Int): Building = House(location, variant)
|
||||
}
|
||||
|
||||
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())
|
||||
|
||||
@ -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
|
||||
|
||||
21
src/main/kotlin/com/pobnellion/aoe/entity/Villager.kt
Normal file
21
src/main/kotlin/com/pobnellion/aoe/entity/Villager.kt
Normal 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))
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
23
src/main/kotlin/com/pobnellion/aoe/team/Plains.kt
Normal file
23
src/main/kotlin/com/pobnellion/aoe/team/Plains.kt
Normal 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()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
80
src/main/kotlin/com/pobnellion/aoe/ui/AreaPlaceHint.kt
Normal file
80
src/main/kotlin/com/pobnellion/aoe/ui/AreaPlaceHint.kt
Normal 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)
|
||||
}
|
||||
}
|
||||
75
src/main/kotlin/com/pobnellion/aoe/ui/BuildingPlaceHint.kt
Normal file
75
src/main/kotlin/com/pobnellion/aoe/ui/BuildingPlaceHint.kt
Normal 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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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")
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user