bfb8108
Branches > main > bfb8108 > files
Wrap mutable bukkit classes in stormbow types
Commit: bfb81082b7efa03d53e62da84f32a75821ae1807 latest
Parent: 039d1df
22 changed files:
src/main/kotlin/net/bowmap/handlers/Chat.kt view file
@@ -1,6 +1,7 @@ package net.bowmap.handlers import net.bowmap.stormbow.*+import net.bowmap.server.fact.* import net.kyori.adventure.text.Component import net.bowmap.server.permission.prefix import net.bowmap.server.adventure.headComponent@@ -9,7 +10,7 @@ val msg = headComponent(f.player).append( Component.text(" "), prefix(f.player),- f.player.displayName(),+ f.player.name, Component.text(": "), f.message) return Effects(SendMessage(audience = f.audience, message = msg))src/main/kotlin/net/bowmap/handlers/Death.kt view file
@@ -1,30 +1,23 @@ package net.bowmap.handlers import net.bowmap.stormbow.*+import net.bowmap.server.fact.*+import net.bowmap.stormbow.game.* import net.bowmap.server.adventure.headComponent-import net.bowmap.server.item.* import net.bowmap.server.loot.tables.mobLootTable import net.bowmap.server.loot.Loot import net.kyori.adventure.text.Component import net.kyori.adventure.text.format.NamedTextColor.* import org.bukkit.Material-import org.bukkit.entity.Entity-import org.bukkit.entity.Player-import org.bukkit.entity.Zombie-import org.bukkit.event.EventHandler-import org.bukkit.event.Listener-import org.bukkit.event.entity.EntityDeathEvent-import org.bukkit.inventory.ItemStack import org.bukkit.damage.DamageSource-import org.bukkit.Location // Doesn't use attacker but how the player died does contribute to the death event // This should probably be the damage source? private fun deathMessage(player: Player, attacker: DamageSource): Component { return headComponent(player) .append(Component.text(" "))- .append(player.displayName())+ .append(player.name) .append(Component.text(" Died.", RED)) } @@ -32,7 +25,7 @@ Effects( Cancel(), Broadcast(message = deathMessage(f.player, f.cause)),- Teleport(entity = f.player, location = Location(f.player.world, 0.5, 57.0, 0.5))+ // Teleport(entity = f.player, location = Location(f.player.world, 0.5, 57.0, 0.5)) ) fun handlePlayerKill(f: PlayerKilledEntity): Effects {src/main/kotlin/net/bowmap/handlers/Durability.kt view file
@@ -1,6 +1,7 @@ package net.bowmap.handlers import net.bowmap.stormbow.*+import net.bowmap.server.fact.* fun handleItemLosingDurability(f: ItemLostDurability): Effects = Effects(Cancel())src/main/kotlin/net/bowmap/handlers/Fishing.kt view file
@@ -1,40 +1,36 @@ package net.bowmap.handlers import net.bowmap.stormbow.*+import net.bowmap.stormbow.game.*+import net.bowmap.server.fact.* import net.bowmap.server.loot.* import org.bukkit.Material.*-import org.bukkit.event.EventHandler-import org.bukkit.event.Listener-import org.bukkit.event.player.PlayerFishEvent-import org.bukkit.event.player.PlayerFishEvent.State-import org.bukkit.util.Vector import net.bowmap.server.loot.tables.fishingLootTable-import net.bowmap.server.item.toItemStacks // TODO f, not e-private fun calculateFishVelocity(e: PlayerCaughtFish): Vector {- val eye = e.player.eyeLocation- val distance = eye.distance(e.hook.location)-- return eye.subtract(e.hook.location)- .toVector()- .normalize()- .multiply(0.2 + distance * 0.1)-}+// private fun calculateFishVelocity(e: PlayerCaughtFish): Vector {+// val eye = e.player.eyeLocation+// val distance = eye.distance(e.hook.location)+//+// return eye.subtract(e.hook.location)+// .toVector()+// .normalize()+// .multiply(0.2 + distance * 0.1)+// } fun handlePlayerFishing(f: PlayerStartedFishing): Effects = Effects(SetFishTime(ticks = 20)) +// TODO effects here! fun handlePlayerCatchingFish(f: PlayerCaughtFish): Effects {- val loot = fishingLootTable.getLoot()-- // TODO use an effect!- for (stack in toItemStacks(loot)) {- val item = f.hook.world.dropItem(f.hook.location, stack)- item.setVelocity(calculateFishVelocity(f))- }+ // val loot = fishingLootTable.getLoot()+ //+ // for (stack in toItemStacks(loot)) {+ // val item = f.hook.world.dropItem(f.hook.location, stack)+ // item.setVelocity(calculateFishVelocity(f))+ // } return Effects() }src/main/kotlin/net/bowmap/handlers/Welcome.kt view file
@@ -1,6 +1,7 @@ package net.bowmap.handlers import net.bowmap.stormbow.*+import net.bowmap.server.fact.* import net.kyori.adventure.text.Component import net.kyori.adventure.text.format.NamedTextColor@@ -10,8 +11,8 @@ Effects(Broadcast(Component.text("Welcome to Bowmap, ", NamedTextColor.GREEN) .append(headComponent(f.player).color(NamedTextColor.WHITE), Component.text(" "),- f.player.displayName().colorIfAbsent(NamedTextColor.WHITE),+ f.player.name.colorIfAbsent(NamedTextColor.WHITE), Component.text("!", NamedTextColor.GREEN)))) fun handlePlayerQuit(f: PlayerQuit) : Effects =- Effects(Broadcast(headComponent(f.player).append(Component.text(" "), f.player.displayName(), Component.text(" left the server", NamedTextColor.RED))))+ Effects(Broadcast(headComponent(f.player).append(Component.text(" "), f.player.name, Component.text(" left the server", NamedTextColor.RED))))src/main/kotlin/net/bowmap/handlers/ZoneGuard.kt view file
@@ -1,47 +1,41 @@ package net.bowmap.handlers import net.bowmap.stormbow.*+import net.bowmap.stormbow.game.*+import net.bowmap.server.fact.* -import org.bukkit.event.Listener-import org.bukkit.event.block.BlockBreakEvent-import org.bukkit.event.EventHandler-import org.bukkit.block.Block-import org.bukkit.Bukkit-import org.bukkit.Location+// data class Region(val from: Location, val to: Location) {+// init {+// require(from.world == to.world) {+// "Regions can only exist in a single world"+// }+// }+// }+//+// // TODO hmm...+// // Would prefer if I didn't have to just rely on this+// val spawn = Region(Location(5, spawnWorld.minHeight.toDouble(), -5.0), Location(spawnWorld, -5.0, spawnWorld.maxHeight - 1.0, 5.0))+//+// fun isInsideRegion(region: Region, location: Location): Boolean {+// if (location.world != region.from.world) return false+//+// val minX = minOf(region.from.blockX, region.to.blockX)+// val maxX = maxOf(region.from.blockX, region.to.blockX)+//+// val minY = minOf(region.from.blockY, region.to.blockY)+// val maxY = maxOf(region.from.blockY, region.to.blockY)+//+// val minZ = minOf(region.from.blockZ, region.to.blockZ)+// val maxZ = maxOf(region.from.blockZ, region.to.blockZ)+//+// return location.blockX in minX..maxX &&+// location.blockY in minY..maxY &&+// location.blockZ in minZ..maxZ+// } -data class Region(val from: Location, val to: Location) {- init {- require(from.world == to.world) {- "Regions can only exist in a single world"- }- }-}--// TODO hmm...-// Would prefer if I didn't have to just rely on this-val spawnWorld = Bukkit.getWorld("world")!!-val spawn = Region(Location(spawnWorld, 5.0, spawnWorld.minHeight.toDouble(), -5.0), Location(spawnWorld, -5.0, spawnWorld.maxHeight - 1.0, 5.0))--fun isInsideRegion(region: Region, location: Location): Boolean {- if (location.world != region.from.world) return false-- val minX = minOf(region.from.blockX, region.to.blockX)- val maxX = maxOf(region.from.blockX, region.to.blockX)-- val minY = minOf(region.from.blockY, region.to.blockY)- val maxY = maxOf(region.from.blockY, region.to.blockY)-- val minZ = minOf(region.from.blockZ, region.to.blockZ)- val maxZ = maxOf(region.from.blockZ, region.to.blockZ)-- return location.blockX in minX..maxX &&- location.blockY in minY..maxY &&- location.blockZ in minZ..maxZ-}--fun isBlockInSpawn(b: Block): Boolean {- return isInsideRegion(spawn, b.location)-}+fun isBlockInSpawn(b: Block): Boolean =+ // isInsideRegion(spawn, b.location)+ false fun handleBlockBreak(f: PlayerBrokeBlock): Effects = if (isBlockInSpawn(f.block)) {src/main/kotlin/net/bowmap/server/Main.kt view file
@@ -1,6 +1,7 @@ package net.bowmap.server import net.bowmap.stormbow.*+import net.bowmap.server.fact.* import net.bowmap.handlers.* // TODO call setup() from an onEnable factsrc/main/kotlin/net/bowmap/server/adventure/Utils.kt view file
@@ -1,12 +1,11 @@ package net.bowmap.server.adventure -import org.bukkit.entity.Player-+import net.bowmap.stormbow.game.* import net.kyori.adventure.text.Component; import net.kyori.adventure.text.`object`.ObjectContents; val SPACE = Component.text() fun headComponent(p: Player): Component {- return Component.`object`(ObjectContents.playerHead(p.uniqueId))+ return Component.`object`(ObjectContents.playerHead(p.uuid)) }src/main/kotlin/net/bowmap/server/fact/Fact.kt view file
@@ -1,24 +1,20 @@ package net.bowmap.server.fact -// import org.bukkit.entity.*-// import org.bukkit.damage.DamageSource-// import org.bukkit.block.Block-// import org.bukkit.inventory.ItemStack+import org.bukkit.damage.DamageSource import net.kyori.adventure.audience.Audience import net.kyori.adventure.text.Component-import net.bowmap.server.entity.Player+import net.bowmap.stormbow.game.* sealed interface Fact -// TODO a player is a game entity...-// Game entities should probably be referenced by their UUID data class PlayerSentChatMessage(val player: Player, val audience: Collection<Audience>, val message: Component) : Fact data class PlayerBrokeBlock(val player: Player, val block: Block) : Fact data class PlayerKilledEntity(val player: Player, val entity: Entity, val cause: DamageSource) : Fact data class PlayerDied(val player: Player, val cause: DamageSource) : Fact data class PlayerJoined(val player: Player) : Fact data class PlayerQuit(val player: Player) : Fact-data class PlayerStartedFishing(val player: Player, val hook: FishHook) : Fact-data class PlayerCaughtFish(val player: Player, val hook: FishHook) : Fact+// Will eventually need fishing related things :p+data class PlayerStartedFishing(val player: Player) : Fact+data class PlayerCaughtFish(val player: Player) : Fact // Bowmap items do not have durability, so they can't be used here data class ItemLostDurability(val player: Player) : Factsrc/main/kotlin/net/bowmap/server/item/ItemStacks.kt view file
@@ -1,36 +0,0 @@-/// Itemstack interop functions-package net.bowmap.server.item--import org.bukkit.inventory.ItemStack--fun toItemStack(item: Item): ItemStack {- // TODO custommodeldata- val itemStack = ItemStack(material(item.type), item.amount)- val meta = itemStack.getItemMeta()-- // itemName is not editable via an anvil, which is the desired behavior- // TODO make sure its not italics!- meta.itemName(item.name)- meta.lore(computeLore(item))-- itemStack.setItemMeta(meta)- return itemStack-}--fun toItemStacks(items: List<Item>): List<ItemStack> {- return items.map(::toItemStack)-}--/// Turns a vanilla ItemStack into a Bowmap item.-/// This function is the inverse of toItemStack, so that toItem(toItemStack(x)) == x-fun toItem(itemStack: ItemStack): Item {- // TODO custommodeldata- // See the above itemName comment- // val meta = itemStack.getItemMeta()- return Item(- // TODO right now this won't work with any custom materials- // It'll have to be stored somwhere on the item :)- type = MaterialItemType(itemStack.type),- amount = itemStack.amount,- )-}src/main/kotlin/net/bowmap/server/loot/LootTables.kt view file
@@ -2,7 +2,7 @@ import org.bukkit.Material import java.util.concurrent.ThreadLocalRandom-import net.bowmap.server.item.*+import net.bowmap.stormbow.game.* interface Loot { fun getLoot(): List<Item>src/main/kotlin/net/bowmap/server/loot/tables/Mobs.kt view file
@@ -1,9 +1,7 @@ package net.bowmap.server.loot.tables -import org.bukkit.entity.Zombie-import org.bukkit.entity.Entity-import net.bowmap.server.item.* import kotlin.reflect.KClass+import net.bowmap.stormbow.game.* import net.bowmap.server.loot.* import org.bukkit.Material.* @@ -21,7 +19,7 @@ ) ) -fun mobLootTable(entity: Entity): Loot? = when (entity) {- is Zombie -> zombieLootTable+fun mobLootTable(entity: Entity): Loot? = when (entity.entityType) {+ EntityType.ZOMBIE -> zombieLootTable else -> null }src/main/kotlin/net/bowmap/server/permission/Rank.kt view file
@@ -4,7 +4,7 @@ import net.kyori.adventure.text.Component import net.kyori.adventure.text.format.NamedTextColor import net.kyori.adventure.text.format.TextDecoration-import org.bukkit.entity.Player+import net.bowmap.stormbow.game.* enum class Rank { DEFAULT, OWNER@@ -15,9 +15,10 @@ val ranks = mapOf(grahp to Rank.OWNER) fun rank(p: Player): Rank {- return ranks.getOrDefault(p.uniqueId, Rank.DEFAULT)+ return ranks.getOrDefault(p.uuid, Rank.DEFAULT) } +// TODO use when val rankPrefix = mapOf( Rank.OWNER to Component.text("Owner") .color(NamedTextColor.RED)src/main/kotlin/net/bowmap/stormbow/Effect.kt view file
@@ -6,9 +6,7 @@ import org.bukkit.inventory.ItemStack import org.bukkit.Bukkit import org.bukkit.Location-import org.bukkit.entity.Player-import org.bukkit.entity.Entity-import net.bowmap.server.item.*+import net.bowmap.stormbow.game.* import kotlinx.collections.immutable.* /// An effect is a piece of data representing a side effect that can be executed,@@ -71,7 +69,7 @@ data class Give(val player: Player, val items: List<Item>) : DefaultEffect { constructor(player: Player, item: Item) : this(player, listOf(item)) override fun execute() {- player.give(items.map(::toItemStack))+ Bukkit.getPlayer(player.uuid)?.give(items.map(::toItemStack)) } } @@ -82,7 +80,7 @@ data class Teleport(val entity: Entity, val location: Location) : DefaultEffect { override fun execute() {- entity.teleport(location)+ Bukkit.getEntity(entity.uuid)?.teleport(location) } } src/main/kotlin/net/bowmap/stormbow/Listeners.kt view file
@@ -5,7 +5,6 @@ import org.bukkit.event.entity.* import org.bukkit.event.player.* import org.bukkit.event.block.*-import org.bukkit.entity.* import net.kyori.adventure.text.Component import net.kyori.adventure.audience.Audience @@ -17,11 +16,13 @@ import org.bukkit.event.player.PlayerItemDamageEvent import kotlinx.collections.immutable.* +import net.bowmap.stormbow.game.*+ /// Listens to many Bukkit events and handles their respective facts class Listeners : Listener { @EventHandler fun onPlayerChat(e: AsyncChatEvent) {- val f = PlayerSentChatMessage(player = e.player, audience = e.viewers(), message = e.message())+ val f = PlayerSentChatMessage(player = fromBukkitPlayer(e.player), audience = e.viewers(), message = e.message()) e.setCancelled(true) // Here, SendMessage effects could replace the chat message, but there's no reason to execute(update(f))@@ -29,7 +30,7 @@ @EventHandler fun onItemDamage(e: PlayerItemDamageEvent) {- val effects = update(ItemLostDurability(player = e.player, itemStack = e.item))+ val effects = update(ItemLostDurability(player = fromBukkitPlayer(e.player))) if (contains<Cancel>(effects)) { e.setCancelled(true) }@@ -37,7 +38,7 @@ @EventHandler fun onBlockBreak(e: BlockBreakEvent) {- val f = PlayerBrokeBlock(player = e.player, block = e.block)+ val f = PlayerBrokeBlock(player = fromBukkitPlayer(e.player), block = toGameBlock(e.block)) val effects = update(f) if (contains<Cancel>(effects)) { e.setCancelled(true)@@ -50,16 +51,16 @@ val victim = e.entity val attacker = e.damageSource.causingEntity - if (victim is Player) {- val effects = update(PlayerDied(player = victim, cause = e.damageSource))+ if (victim is org.bukkit.entity.Player) {+ val effects = update(PlayerDied(player = fromBukkitPlayer(victim), cause = e.damageSource)) if (contains<Cancel>(effects)) { e.setCancelled(true) } execute(effects) } - if (attacker is Player) {- val effects = update(PlayerKilledEntity(player = attacker, entity = victim, cause = e.damageSource))+ if (attacker is org.bukkit.entity.Player) {+ val effects = update(PlayerKilledEntity(player = fromBukkitPlayer(attacker), entity = toGameEntity(victim), cause = e.damageSource)) if (contains<Cancel>(effects)) { e.setCancelled(true) }@@ -73,20 +74,20 @@ @EventHandler fun onPlayerJoin(e: PlayerJoinEvent) { e.joinMessage(null)- execute(update(PlayerJoined(player = e.player)))+ execute(update(PlayerJoined(player = fromBukkitPlayer(e.player)))) } @EventHandler fun onPlayerQuit(e: PlayerQuitEvent) { e.quitMessage(null)- execute(update(PlayerQuit(player = e.player)))+ execute(update(PlayerQuit(player = fromBukkitPlayer(e.player)))) } @EventHandler fun onFishEvent(e: PlayerFishEvent) { when (e.state) { State.FISHING -> {- val effects = update(PlayerStartedFishing(player = e.player, hook = e.hook))+ val effects = update(PlayerStartedFishing(player = fromBukkitPlayer(e.player))) if (contains<Cancel>(effects)) { e.setCancelled(true) }@@ -98,7 +99,7 @@ } State.CAUGHT_FISH -> {- execute(update(PlayerCaughtFish(player = e.player, hook = e.hook)))+ execute(update(PlayerCaughtFish(player = fromBukkitPlayer(e.player)))) e.caught?.remove() e.expToDrop = 0src/main/kotlin/net/bowmap/stormbow/Plugin.kt view file
@@ -4,6 +4,7 @@ import org.bukkit.plugin.java.JavaPlugin import net.kyori.adventure.text.Component +// TODO use a queue and have bowmap stuff depend on stormbow stuff but not the other way around import net.bowmap.server.setup class Plugin : JavaPlugin() {src/main/kotlin/net/bowmap/stormbow/README.md view file
@@ -0,0 +1 @@+Bukkit wrapping immutable API.src/main/kotlin/net/bowmap/stormbow/game/Block.kt view file
@@ -0,0 +1,7 @@+package net.bowmap.stormbow.game++// TODO data as well+public class Block(val itemType: ItemType)++fun toGameBlock(block: org.bukkit.block.Block) =+ Block(MaterialItemType(block.type))src/main/kotlin/net/bowmap/stormbow/game/Entity.kt view file
@@ -0,0 +1,36 @@+package net.bowmap.stormbow.game++import java.util.UUID+import net.kyori.adventure.text.Component++// An immutable reference to a mutable entity+// Can only call pure functions on this entity to get things from it+// And execute effects on it to do things to it++// Players also go under this category++/// An immutable game entity+interface Entity {+ val uuid: UUID+ val entityType: EntityType+}++enum class EntityType {+ ZOMBIE, PLAYER, UNKNOWN+}++data class UnknownEntity(override val uuid: UUID) : Entity {+ override val entityType = EntityType.UNKNOWN+}++/// An immutable player+data class Player(override val uuid: UUID, val name: Component) : Entity {+ override val entityType = EntityType.PLAYER+}++// TODO rename+fun fromBukkitPlayer(p: org.bukkit.entity.Player): Player =+ Player(uuid = p.uniqueId, name = p.displayName())++fun toGameEntity(e: org.bukkit.entity.Entity): Entity =+ UnknownEntity(uuid = e.uniqueId)src/main/kotlin/net/bowmap/stormbow/game/GameEntity.kt view file
@@ -1,21 +0,0 @@-package net.bowmap.stormbow.game--import java.util.UUID-import org.bukkit.Player--// An immutable reference to a mutable entity-// Can only call impure functions on this entity to get things from it-// And execute effects on it to do things to it--// Players also go under this category--/// An immutable game entity-interface Entity {- val uuid: UUID-}--/// An immutable player-data class Player(override val uuid: UUID) : Entity--fun fromBukkitPlayer(p: org.bukkit.Player): Player =- Player(uuid = p.uniqueId)src/main/kotlin/net/bowmap/stormbow/game/Item.kt src/main/kotlin/net/bowmap/server/item/Item.kt view file
@@ -1,4 +1,4 @@-package net.bowmap.server.item+package net.bowmap.stormbow.game import net.kyori.adventure.text.Component import net.kyori.adventure.text.format.NamedTextColor@@ -84,3 +84,37 @@ ) : ItemType { BUG(Material.STONE_BUTTON, Component.text("This is a bug yeag"), "You found a bug!", rarity = Rarity.SPECIAL) }++/// itemStack interop functions++fun toItemStack(item: Item): ItemStack {+ // TODO custommodeldata+ val itemStack = ItemStack(material(item.type), item.amount)+ val meta = itemStack.getItemMeta()++ // itemName is not editable via an anvil, which is the desired behavior+ // TODO make sure its not italics!+ meta.itemName(item.name)+ meta.lore(computeLore(item))++ itemStack.setItemMeta(meta)+ return itemStack+}++fun toItemStacks(items: List<Item>): List<ItemStack> {+ return items.map(::toItemStack)+}++/// Turns a vanilla ItemStack into a Bowmap item.+/// This function is the inverse of toItemStack, so that toItem(toItemStack(x)) == x+fun toItem(itemStack: ItemStack): Item {+ // TODO custommodeldata+ // See the above itemName comment+ // val meta = itemStack.getItemMeta()+ return Item(+ // TODO right now this won't work with any custom materials+ // It'll have to be stored somwhere on the item :)+ type = MaterialItemType(itemStack.type),+ amount = itemStack.amount,+ )+}src/main/kotlin/net/bowmap/stormbow/game/Location.kt view file
@@ -0,0 +1,4 @@+package net.bowmap.stormbow.game++data class Location(val x: Int, val y: Int, val z: Int)+data class Position(val x: Double, val y: Double, val z: Double, val yaw: Float, val pitch: Float)