看板素材対応・クリック方向対応
This commit is contained in:
parent
84c4252592
commit
65b3cfd8e2
|
|
@ -17,6 +17,60 @@ object ShopVisuals {
|
||||||
org.bukkit.Material.COPPER_CHEST
|
org.bukkit.Material.COPPER_CHEST
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val VALID_SIGNS = setOfNotNull(
|
||||||
|
// Standard Standing Signs
|
||||||
|
org.bukkit.Material.OAK_SIGN, org.bukkit.Material.BIRCH_SIGN, org.bukkit.Material.SPRUCE_SIGN, org.bukkit.Material.JUNGLE_SIGN,
|
||||||
|
org.bukkit.Material.ACACIA_SIGN, org.bukkit.Material.DARK_OAK_SIGN, org.bukkit.Material.MANGROVE_SIGN, org.bukkit.Material.CHERRY_SIGN,
|
||||||
|
org.bukkit.Material.BAMBOO_SIGN, org.bukkit.Material.CRIMSON_SIGN, org.bukkit.Material.WARPED_SIGN, org.bukkit.Material.getMaterial("PALE_OAK_SIGN"),
|
||||||
|
|
||||||
|
// Wall Signs
|
||||||
|
org.bukkit.Material.OAK_WALL_SIGN, org.bukkit.Material.BIRCH_WALL_SIGN, org.bukkit.Material.SPRUCE_WALL_SIGN, org.bukkit.Material.JUNGLE_WALL_SIGN,
|
||||||
|
org.bukkit.Material.ACACIA_WALL_SIGN, org.bukkit.Material.DARK_OAK_WALL_SIGN, org.bukkit.Material.MANGROVE_WALL_SIGN, org.bukkit.Material.CHERRY_WALL_SIGN,
|
||||||
|
org.bukkit.Material.BAMBOO_WALL_SIGN, org.bukkit.Material.CRIMSON_WALL_SIGN, org.bukkit.Material.WARPED_WALL_SIGN, org.bukkit.Material.getMaterial("PALE_OAK_WALL_SIGN"),
|
||||||
|
|
||||||
|
// Hanging Signs (Ceiling)
|
||||||
|
org.bukkit.Material.OAK_HANGING_SIGN, org.bukkit.Material.BIRCH_HANGING_SIGN, org.bukkit.Material.SPRUCE_HANGING_SIGN, org.bukkit.Material.JUNGLE_HANGING_SIGN,
|
||||||
|
org.bukkit.Material.ACACIA_HANGING_SIGN, org.bukkit.Material.DARK_OAK_HANGING_SIGN, org.bukkit.Material.MANGROVE_HANGING_SIGN, org.bukkit.Material.CHERRY_HANGING_SIGN,
|
||||||
|
org.bukkit.Material.BAMBOO_HANGING_SIGN, org.bukkit.Material.CRIMSON_HANGING_SIGN, org.bukkit.Material.WARPED_HANGING_SIGN, org.bukkit.Material.getMaterial("PALE_OAK_HANGING_SIGN"),
|
||||||
|
|
||||||
|
// Wall Hanging Signs
|
||||||
|
org.bukkit.Material.OAK_WALL_HANGING_SIGN, org.bukkit.Material.BIRCH_WALL_HANGING_SIGN, org.bukkit.Material.SPRUCE_WALL_HANGING_SIGN, org.bukkit.Material.JUNGLE_WALL_HANGING_SIGN,
|
||||||
|
org.bukkit.Material.ACACIA_WALL_HANGING_SIGN, org.bukkit.Material.DARK_OAK_WALL_HANGING_SIGN, org.bukkit.Material.MANGROVE_WALL_HANGING_SIGN, org.bukkit.Material.CHERRY_WALL_HANGING_SIGN,
|
||||||
|
org.bukkit.Material.BAMBOO_WALL_HANGING_SIGN, org.bukkit.Material.CRIMSON_WALL_HANGING_SIGN, org.bukkit.Material.WARPED_WALL_HANGING_SIGN, org.bukkit.Material.getMaterial("PALE_OAK_WALL_HANGING_SIGN")
|
||||||
|
)
|
||||||
|
|
||||||
|
fun isShopSign(material: org.bukkit.Material): Boolean {
|
||||||
|
return VALID_SIGNS.contains(material)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isWallSign(material: org.bukkit.Material): Boolean {
|
||||||
|
return material.name.contains("WALL_SIGN") && !material.name.contains("HANGING")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isHangingSign(material: org.bukkit.Material): Boolean {
|
||||||
|
return material.name.contains("HANGING_SIGN")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getSignMaterial(key: String): org.bukkit.Material? {
|
||||||
|
val upperKey = key.uppercase()
|
||||||
|
// Map short names to materials
|
||||||
|
return when (upperKey) {
|
||||||
|
"OAK" -> org.bukkit.Material.OAK_SIGN
|
||||||
|
"BIRCH" -> org.bukkit.Material.BIRCH_SIGN
|
||||||
|
"SPRUCE" -> org.bukkit.Material.SPRUCE_SIGN
|
||||||
|
"JUNGLE" -> org.bukkit.Material.JUNGLE_SIGN
|
||||||
|
"ACACIA" -> org.bukkit.Material.ACACIA_SIGN
|
||||||
|
"DARK_OAK" -> org.bukkit.Material.DARK_OAK_SIGN
|
||||||
|
"MANGROVE" -> org.bukkit.Material.MANGROVE_SIGN
|
||||||
|
"CHERRY" -> org.bukkit.Material.CHERRY_SIGN
|
||||||
|
"BAMBOO" -> org.bukkit.Material.BAMBOO_SIGN
|
||||||
|
"CRIMSON" -> org.bukkit.Material.CRIMSON_SIGN
|
||||||
|
"WARPED" -> org.bukkit.Material.WARPED_SIGN
|
||||||
|
"PALE" -> org.bukkit.Material.getMaterial("PALE_OAK_SIGN")
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun updateSign(plugin: JavaPlugin, block: org.bukkit.block.Block, shopData: ShopData, side: Side) {
|
fun updateSign(plugin: JavaPlugin, block: org.bukkit.block.Block, shopData: ShopData, side: Side) {
|
||||||
val state = block.state as? Sign ?: return
|
val state = block.state as? Sign ?: return
|
||||||
val signSide = state.getSide(side)
|
val signSide = state.getSide(side)
|
||||||
|
|
@ -84,24 +138,28 @@ object ShopVisuals {
|
||||||
}
|
}
|
||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
fun removeDisplay(location: org.bukkit.Location, face: String) {
|
fun removeDisplay(plugin: JavaPlugin, location: org.bukkit.Location, shopId: Int? = null) {
|
||||||
val world = location.world ?: return
|
val world = location.world ?: return
|
||||||
val block = location.block
|
|
||||||
val data = block.blockData as? org.bukkit.block.data.Rotatable ?: return
|
|
||||||
val rotation = data.rotation
|
|
||||||
|
|
||||||
val yaw = yawFromBlockFace(rotation) + 90f
|
// Search at center of block (0.5, 0.5, 0.5)
|
||||||
|
val center = location.clone().add(0.5, 0.5, 0.5)
|
||||||
|
|
||||||
val offset = if (face == "FRONT") org.joml.Vector3f(0.25f, 0.25f, 0.0f) else org.joml.Vector3f(-0.25f, 0.25f, 0.0f)
|
val key = org.bukkit.NamespacedKey(plugin, "shop_id")
|
||||||
val rad = Math.toRadians(yaw.toDouble())
|
|
||||||
offset.rotateY(-rad.toFloat())
|
|
||||||
|
|
||||||
val center = location.clone().add(0.5, 0.0, 0.5)
|
// Search for entity within strict block bounds
|
||||||
val targetPos = center.clone().add(offset.x.toDouble(), offset.y.toDouble(), offset.z.toDouble())
|
val nearby = world.getNearbyEntities(center, 0.45, 0.45, 0.45)
|
||||||
|
nearby.filterIsInstance<org.bukkit.entity.ItemDisplay>()
|
||||||
// Search for entity
|
.filter { it.scoreboardTags.contains("shop_display") }
|
||||||
val nearby = world.getNearbyEntities(targetPos, 0.2, 0.2, 0.2)
|
.forEach { entity ->
|
||||||
nearby.filterIsInstance<org.bukkit.entity.ItemDisplay>().forEach { it.remove() }
|
if (shopId == null) {
|
||||||
|
entity.remove() // Wipe all
|
||||||
|
} else {
|
||||||
|
val storedId = entity.persistentDataContainer.get(key, org.bukkit.persistence.PersistentDataType.STRING)
|
||||||
|
if (storedId == shopId.toString()) {
|
||||||
|
entity.remove() // Target match
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun yawFromBlockFace(face: org.bukkit.block.BlockFace): Float {
|
fun yawFromBlockFace(face: org.bukkit.block.BlockFace): Float {
|
||||||
|
|
|
||||||
|
|
@ -37,16 +37,47 @@ object ShopCommands {
|
||||||
defaultValue = org.bukkit.permissions.PermissionDefault.OP
|
defaultValue = org.bukkit.permissions.PermissionDefault.OP
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logic for /shop give (No tier specified, default 1)
|
// Logic for /shop give (No arguments -> Oak, Tier 1)
|
||||||
executes {
|
executes {
|
||||||
giveShopSign(plugin, sender, 1, tierKey)
|
giveShopSign(plugin, sender, 1, tierKey, Material.OAK_SIGN)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logic for /shop give <tier>
|
// Logic for /shop give <tier> (Default Oak)
|
||||||
integer("tier", min = 1, max = 5) {
|
integer("tier", min = 1, max = 5) {
|
||||||
executes {
|
executes {
|
||||||
val tier: Int = argument("tier")
|
val tier: Int = argument("tier")
|
||||||
giveShopSign(plugin, sender, tier, tierKey)
|
giveShopSign(plugin, sender, tier, tierKey, Material.OAK_SIGN)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logic for /shop give <type> [tier]
|
||||||
|
string("type") {
|
||||||
|
suggests {
|
||||||
|
listOf("oak", "birch", "spruce", "jungle", "acacia", "dark_oak", "mangrove", "cherry", "bamboo", "crimson", "warped", "pale")
|
||||||
|
}
|
||||||
|
executes {
|
||||||
|
val typeName: String = argument("type")
|
||||||
|
val material = net.hareworks.hcu.shop.ShopVisuals.getSignMaterial(typeName)
|
||||||
|
|
||||||
|
if (material != null) {
|
||||||
|
giveShopSign(plugin, sender, 1, tierKey, material)
|
||||||
|
} else {
|
||||||
|
sender.sendMessage(Component.text("Invalid sign type: $typeName", NamedTextColor.RED))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
integer("tier", min = 1, max = 5) {
|
||||||
|
executes {
|
||||||
|
val typeName: String = argument("type")
|
||||||
|
val tier: Int = argument("tier")
|
||||||
|
val material = net.hareworks.hcu.shop.ShopVisuals.getSignMaterial(typeName)
|
||||||
|
|
||||||
|
if (material != null) {
|
||||||
|
giveShopSign(plugin, sender, tier, tierKey, material)
|
||||||
|
} else {
|
||||||
|
sender.sendMessage(Component.text("Invalid sign type: $typeName", NamedTextColor.RED))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -81,13 +112,13 @@ object ShopCommands {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun giveShopSign(plugin: JavaPlugin, sender: org.bukkit.command.CommandSender, tier: Int, key: NamespacedKey) {
|
private fun giveShopSign(plugin: JavaPlugin, sender: org.bukkit.command.CommandSender, tier: Int, key: NamespacedKey, signType: Material) {
|
||||||
if (sender !is Player) {
|
if (sender !is Player) {
|
||||||
sender.sendMessage(Component.text("Only players can use this command.", NamedTextColor.RED))
|
sender.sendMessage(Component.text("Only players can use this command.", NamedTextColor.RED))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val signItem = ItemStack(Material.OAK_SIGN)
|
val signItem = ItemStack(signType)
|
||||||
val meta = signItem.itemMeta
|
val meta = signItem.itemMeta
|
||||||
|
|
||||||
meta.displayName(Component.text("Shop Sign (Tier $tier)").color(NamedTextColor.GOLD))
|
meta.displayName(Component.text("Shop Sign (Tier $tier)").color(NamedTextColor.GOLD))
|
||||||
|
|
@ -96,7 +127,7 @@ object ShopCommands {
|
||||||
signItem.itemMeta = meta
|
signItem.itemMeta = meta
|
||||||
|
|
||||||
sender.inventory.addItem(signItem)
|
sender.inventory.addItem(signItem)
|
||||||
sender.sendMessage(Component.text("Given Shop Sign Tier $tier", NamedTextColor.GREEN))
|
sender.sendMessage(Component.text("Given Shop Sign Tier $tier (${signType.name.lowercase()})", NamedTextColor.GREEN))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun displayShopList(plugin: ShopPlugin, player: Player) {
|
private fun displayShopList(plugin: ShopPlugin, player: Player) {
|
||||||
|
|
@ -150,10 +181,10 @@ object ShopCommands {
|
||||||
val world = org.bukkit.Bukkit.getWorld(shop.worldUid)
|
val world = org.bukkit.Bukkit.getWorld(shop.worldUid)
|
||||||
if (world != null) {
|
if (world != null) {
|
||||||
val location = org.bukkit.Location(world, shop.x.toDouble(), shop.y.toDouble(), shop.z.toDouble())
|
val location = org.bukkit.Location(world, shop.x.toDouble(), shop.y.toDouble(), shop.z.toDouble())
|
||||||
net.hareworks.hcu.shop.ShopVisuals.removeDisplay(location, shop.face)
|
net.hareworks.hcu.shop.ShopVisuals.removeDisplay(plugin, location, shop.id)
|
||||||
|
|
||||||
val block = location.block
|
val block = location.block
|
||||||
if (block.type == Material.OAK_SIGN) {
|
if (net.hareworks.hcu.shop.ShopVisuals.isShopSign(block.type)) {
|
||||||
// Check for other shops at this location
|
// Check for other shops at this location
|
||||||
val otherFace = if (shop.face == "FRONT") "BACK" else "FRONT"
|
val otherFace = if (shop.face == "FRONT") "BACK" else "FRONT"
|
||||||
val otherShop = net.hareworks.hcu.shop.database.ShopRepository.findByLocationAndFace(location, otherFace)
|
val otherShop = net.hareworks.hcu.shop.database.ShopRepository.findByLocationAndFace(location, otherFace)
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,8 @@ class ShopListener(private val plugin: ShopPlugin) : Listener {
|
||||||
// Check if it is a shop sign
|
// Check if it is a shop sign
|
||||||
val tier = meta.persistentDataContainer.get(tierKey, PersistentDataType.INTEGER) ?: return
|
val tier = meta.persistentDataContainer.get(tierKey, PersistentDataType.INTEGER) ?: return
|
||||||
|
|
||||||
// Check block type (Standing Sign)
|
// Check block type (Standing Sign, Wall Sign, Hanging Sign)
|
||||||
if (event.blockPlaced.type != Material.OAK_SIGN) {
|
if (!ShopVisuals.isShopSign(event.blockPlaced.type)) {
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -99,13 +99,21 @@ class ShopListener(private val plugin: ShopPlugin) : Listener {
|
||||||
)
|
)
|
||||||
plugin.logger.info("Front shop created: ${frontShop != null} (ID: ${frontShop?.id})")
|
plugin.logger.info("Front shop created: ${frontShop != null} (ID: ${frontShop?.id})")
|
||||||
|
|
||||||
// Create BACK shop
|
// Create BACK shop handling
|
||||||
val backShop = ShopRepository.create(
|
val backShop = if (!ShopVisuals.isWallSign(event.blockPlaced.type)) {
|
||||||
actorId = actorId,
|
ShopRepository.create(
|
||||||
location = event.blockPlaced.location,
|
actorId = actorId,
|
||||||
face = "BACK"
|
location = event.blockPlaced.location,
|
||||||
)
|
face = "BACK"
|
||||||
plugin.logger.info("Back shop created: ${backShop != null} (ID: ${backShop?.id})")
|
)
|
||||||
|
} else {
|
||||||
|
null // Wall signs don't have a back shop
|
||||||
|
}
|
||||||
|
if (backShop != null) {
|
||||||
|
plugin.logger.info("Back shop created: (ID: ${backShop.id})")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Close UI and Update Visuals (Delayed to override client-side editor opening)
|
// Close UI and Update Visuals (Delayed to override client-side editor opening)
|
||||||
// Close UI immediately (Next tick)
|
// Close UI immediately (Next tick)
|
||||||
|
|
@ -128,10 +136,17 @@ class ShopListener(private val plugin: ShopPlugin) : Listener {
|
||||||
plugin.logger.info("Updating BACK sign.")
|
plugin.logger.info("Updating BACK sign.")
|
||||||
ShopVisuals.updateSign(plugin, event.blockPlaced, backShop, Side.BACK)
|
ShopVisuals.updateSign(plugin, event.blockPlaced, backShop, Side.BACK)
|
||||||
} else {
|
} else {
|
||||||
plugin.logger.warning("Back shop was null in delayed task.")
|
// For wall signs, back shop is null is expected
|
||||||
}
|
}
|
||||||
|
|
||||||
spawnDisplays(event.blockPlaced)
|
// Spawn Displays Only for Standard Standing Signs
|
||||||
|
// User requested "DisplayEntity無しで" for the new types (Wall/Hanging)
|
||||||
|
// Existing Standing Signs logic uses Rotatable (which Wall/Hanging might not fully support in spawnDisplays logic)
|
||||||
|
// So restrict to Standing Signs (Rotatable && !Wall && !Hanging)
|
||||||
|
val type = event.blockPlaced.type
|
||||||
|
if (!ShopVisuals.isWallSign(type) && !ShopVisuals.isHangingSign(type)) {
|
||||||
|
spawnDisplays(event.blockPlaced)
|
||||||
|
}
|
||||||
}, 1L)
|
}, 1L)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -141,61 +156,125 @@ class ShopListener(private val plugin: ShopPlugin) : Listener {
|
||||||
val data = block.blockData as? Rotatable ?: return
|
val data = block.blockData as? Rotatable ?: return
|
||||||
val rotation = data.rotation // BlockFace
|
val rotation = data.rotation // BlockFace
|
||||||
|
|
||||||
val yaw = ShopVisuals.yawFromBlockFace(rotation) + 90f
|
// Keys
|
||||||
|
val shopIdKey = org.bukkit.NamespacedKey(plugin, "shop_id")
|
||||||
|
|
||||||
// Calculate offsets relative to center (0.5, 0, 0.5)
|
// Find Shops
|
||||||
// Original request assumes 0,0,0 is block origin.
|
val frontShop = net.hareworks.hcu.shop.database.ShopRepository.findByLocationAndFace(origin, "FRONT")
|
||||||
// Front: 0.75 0.25 0.5 -> Rel: 0.25, 0.25, 0.0
|
val backShop = net.hareworks.hcu.shop.database.ShopRepository.findByLocationAndFace(origin, "BACK")
|
||||||
// Back: 0.25 0.25 0.5 -> Rel: -0.25, 0.25, 0.0
|
|
||||||
|
|
||||||
val frontOffset = Vector3f(0.25f, 0.25f, 0.0f)
|
val rawYaw = ShopVisuals.yawFromBlockFace(rotation)
|
||||||
val backOffset = Vector3f(-0.25f, 0.25f, 0.0f)
|
|
||||||
|
|
||||||
// Rotate offsets
|
// Final positions (No offsets, just center of block)
|
||||||
|
|
||||||
val rad = Math.toRadians(yaw.toDouble())
|
|
||||||
frontOffset.rotateY(-rad.toFloat())
|
|
||||||
backOffset.rotateY(-rad.toFloat())
|
|
||||||
|
|
||||||
// Final positions
|
|
||||||
val center = origin.clone().add(0.5, 0.0, 0.5)
|
val center = origin.clone().add(0.5, 0.0, 0.5)
|
||||||
val frontPos = center.clone().add(frontOffset.x.toDouble(), frontOffset.y.toDouble(), frontOffset.z.toDouble())
|
|
||||||
val backPos = center.clone().add(backOffset.x.toDouble(), backOffset.y.toDouble(), backOffset.z.toDouble())
|
|
||||||
|
|
||||||
val world = block.world
|
val world = block.world
|
||||||
|
|
||||||
// Spawn Front
|
// Check existing entities in block area
|
||||||
world.spawn(frontPos, ItemDisplay::class.java) { display ->
|
// Search at center of block (0.5, 0.5, 0.5)
|
||||||
display.setRotation(yaw, 0f)
|
val blockCenter = origin.clone().add(0.5, 0.5, 0.5)
|
||||||
|
val existing = world.getNearbyEntities(blockCenter, 0.45, 0.45, 0.45)
|
||||||
|
.filterIsInstance<ItemDisplay>()
|
||||||
|
.filter { it.scoreboardTags.contains("shop_display") }
|
||||||
|
|
||||||
// Transformation
|
// --- FRONT ---
|
||||||
val left = Quaternionf(0.0f, -0.7071068f, 0.0f, 0.7071068f)
|
if (frontShop != null) {
|
||||||
val right = Quaternionf(0.0f, 0.0f, 0.0f, 1.0f)
|
val frontPos = center.clone().add( // Recalculate Front Pos for spawning if needed (though now we use center... wait, step 178 restored offsets?)
|
||||||
val scale = Vector3f(0.5f, 0.5f, 0.5f)
|
// Step 178 restored offsets. I need to keep that logic if I want positions.
|
||||||
val translation = Vector3f(0.0f, 0.0f, 0.0f)
|
// Re-reading Step 178: "Final positions ... frontPos ... backPos"
|
||||||
|
// My previous spawnDisplays (Step 255) used frontPos/backPos.
|
||||||
|
// I need to calculate them here again.
|
||||||
|
0.0, 0.0, 0.0 // Placeholder, will fix below
|
||||||
|
)
|
||||||
|
// recalculate offsets
|
||||||
|
val yawForOffset = rawYaw + 90f
|
||||||
|
val frontOffset = Vector3f(0.25f, 0.25f, 0.0f)
|
||||||
|
val rad = Math.toRadians(yawForOffset.toDouble())
|
||||||
|
frontOffset.rotateY(-rad.toFloat())
|
||||||
|
frontPos.set(center.x + frontOffset.x, center.y + frontOffset.y, center.z + frontOffset.z)
|
||||||
|
|
||||||
display.setTransformation(Transformation(translation, left, scale, right))
|
val existingEntity = existing.find {
|
||||||
display.interpolationDuration = 0
|
it.persistentDataContainer.get(shopIdKey, org.bukkit.persistence.PersistentDataType.STRING) == frontShop.id.toString()
|
||||||
|
}
|
||||||
|
|
||||||
// Add custom tag or PDC to link to sign if needed?
|
val itemStack = frontShop.item ?: ItemStack(Material.AIR)
|
||||||
|
|
||||||
|
if (existingEntity != null) {
|
||||||
|
// Update
|
||||||
|
existingEntity.setItemStack(itemStack)
|
||||||
|
} else {
|
||||||
|
// Spawn
|
||||||
|
world.spawn(frontPos, ItemDisplay::class.java) { display ->
|
||||||
|
display.setItemDisplayTransform(org.bukkit.entity.ItemDisplay.ItemDisplayTransform.FIXED)
|
||||||
|
display.setRotation(rawYaw, 0f)
|
||||||
|
|
||||||
|
val left = Quaternionf()
|
||||||
|
val right = Quaternionf()
|
||||||
|
val scale = Vector3f(1.0f, 1.0f, 1.0f)
|
||||||
|
val translation = Vector3f(0.0f, 0.0f, 0.0f)
|
||||||
|
|
||||||
|
display.addScoreboardTag("shop_display")
|
||||||
|
display.persistentDataContainer.set(shopIdKey, org.bukkit.persistence.PersistentDataType.STRING, frontShop.id.toString())
|
||||||
|
|
||||||
|
display.setTransformation(Transformation(translation, left, scale, right))
|
||||||
|
display.interpolationDuration = 0
|
||||||
|
|
||||||
|
display.setItemStack(itemStack)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spawn Back
|
// --- BACK ---
|
||||||
world.spawn(backPos, ItemDisplay::class.java) { display ->
|
if (backShop != null) {
|
||||||
// display.setItemStack(ItemStack(Material.AIR)) // Default empty
|
// recalculate offsets
|
||||||
display.setRotation(yaw - 90f, 0f)
|
val yawForOffset = rawYaw + 90f
|
||||||
|
val backOffset = Vector3f(-0.25f, 0.25f, 0.0f)
|
||||||
|
val rad = Math.toRadians(yawForOffset.toDouble())
|
||||||
|
backOffset.rotateY(-rad.toFloat())
|
||||||
|
val backPos = center.clone().add(backOffset.x.toDouble(), backOffset.y.toDouble(), backOffset.z.toDouble())
|
||||||
|
|
||||||
// Transformation
|
val existingEntity = existing.find {
|
||||||
val left = Quaternionf(0.0f, 1.0f, 0.0f, 0.0f)
|
it.persistentDataContainer.get(shopIdKey, org.bukkit.persistence.PersistentDataType.STRING) == backShop.id.toString()
|
||||||
val right = Quaternionf(0.0f, 0.0f, 0.0f, 1.0f)
|
}
|
||||||
val scale = Vector3f(0.5f, 0.5f, 0.5f)
|
|
||||||
val translation = Vector3f(0.0f, 0.0f, 0.0f)
|
|
||||||
|
|
||||||
display.setTransformation(Transformation(translation, left, scale, right))
|
val itemStack = backShop.item ?: ItemStack(Material.AIR)
|
||||||
display.interpolationDuration = 0
|
|
||||||
|
if (existingEntity != null) {
|
||||||
|
// Update
|
||||||
|
existingEntity.setItemStack(itemStack)
|
||||||
|
} else {
|
||||||
|
// Spawn
|
||||||
|
world.spawn(backPos, ItemDisplay::class.java) { display ->
|
||||||
|
display.setItemDisplayTransform(org.bukkit.entity.ItemDisplay.ItemDisplayTransform.FIXED)
|
||||||
|
display.setRotation(rawYaw + 180f, 0f)
|
||||||
|
|
||||||
|
val left = Quaternionf()
|
||||||
|
val right = Quaternionf()
|
||||||
|
val scale = Vector3f(1.0f, 1.0f, 1.0f)
|
||||||
|
val translation = Vector3f(0.0f, 0.0f, 0.0f)
|
||||||
|
|
||||||
|
display.addScoreboardTag("shop_display")
|
||||||
|
display.persistentDataContainer.set(shopIdKey, org.bukkit.persistence.PersistentDataType.STRING, backShop.id.toString())
|
||||||
|
|
||||||
|
display.setTransformation(Transformation(translation, left, scale, right))
|
||||||
|
display.interpolationDuration = 0
|
||||||
|
|
||||||
|
display.setItemStack(itemStack)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private fun updateShopDisplay(shopData: net.hareworks.hcu.shop.database.ShopData) {
|
||||||
|
val world = org.bukkit.Bukkit.getWorld(shopData.worldUid) ?: return
|
||||||
|
val block = world.getBlockAt(shopData.x, shopData.y, shopData.z)
|
||||||
|
|
||||||
|
// Spawn/Update displays
|
||||||
|
spawnDisplays(block)
|
||||||
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
fun onSignChange(event: SignChangeEvent) {
|
fun onSignChange(event: SignChangeEvent) {
|
||||||
val player = event.player
|
val player = event.player
|
||||||
|
|
@ -275,15 +354,61 @@ class ShopListener(private val plugin: ShopPlugin) : Listener {
|
||||||
// Check if shop sign
|
// Check if shop sign
|
||||||
if (!state.persistentDataContainer.has(tierKey, PersistentDataType.INTEGER)) return
|
if (!state.persistentDataContainer.has(tierKey, PersistentDataType.INTEGER)) return
|
||||||
|
|
||||||
// Determine Face (Front/Back)
|
// Use Player vs Block relative position
|
||||||
val data = block.blockData as? Rotatable ?: return
|
val playerLoc = event.player.location
|
||||||
val rotation = data.rotation
|
val blockCenter = block.location.add(0.5, 0.5, 0.5)
|
||||||
val clickedFace = event.blockFace
|
val vectorToPlayer = playerLoc.toVector().subtract(blockCenter.toVector())
|
||||||
|
|
||||||
val face = when (clickedFace) {
|
var face = "FRONT"
|
||||||
rotation -> "FRONT"
|
|
||||||
rotation.oppositeFace -> "BACK"
|
// Handle Directional vs Rotatable
|
||||||
else -> return // Clicked side/top/bottom, ignore or handle? Ignoring for now.
|
// Standard Standing Sign: Rotatable
|
||||||
|
// Wall Sign: Directional
|
||||||
|
// Hanging Sign (Ceiling): Rotatable (but different?) -> It is Rotatable.
|
||||||
|
// Hanging Sign (Wall): Directional
|
||||||
|
|
||||||
|
val bData = block.blockData
|
||||||
|
val forwardVector: org.bukkit.util.Vector
|
||||||
|
|
||||||
|
if (bData is org.bukkit.block.data.Directional) {
|
||||||
|
// Wall Sign / Wall Hanging Sign
|
||||||
|
val facing = bData.facing // The direction the text faces (usually)
|
||||||
|
// Create vector from facing
|
||||||
|
forwardVector = facing.direction
|
||||||
|
|
||||||
|
// Dot product
|
||||||
|
val dot = vectorToPlayer.normalize().dot(forwardVector)
|
||||||
|
|
||||||
|
// For Wall Signs (Strict), Back is impossible/invalid.
|
||||||
|
// If dot < 0 (Behind), it means player is inside the wall? Or side?
|
||||||
|
// User said: "Wall signs: Back unclickable".
|
||||||
|
|
||||||
|
if (dot > 0) {
|
||||||
|
face = "FRONT"
|
||||||
|
} else {
|
||||||
|
face = "BACK"
|
||||||
|
// If it is strictly a Wall Sign (not hanging), BACK is disabled.
|
||||||
|
if (ShopVisuals.isWallSign(block.type)) {
|
||||||
|
// Ignore click
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (bData is Rotatable) {
|
||||||
|
// Standing Sign / Ceiling Hanging Sign
|
||||||
|
val rotation = bData.rotation
|
||||||
|
val signYaw = ShopVisuals.yawFromBlockFace(rotation)
|
||||||
|
val rad = Math.toRadians(signYaw.toDouble())
|
||||||
|
// Sign Yaw 0 = South (0,1).
|
||||||
|
val signDirX = -Math.sin(rad)
|
||||||
|
val signDirZ = Math.cos(rad)
|
||||||
|
forwardVector = org.bukkit.util.Vector(signDirX, 0.0, signDirZ)
|
||||||
|
|
||||||
|
val dot = vectorToPlayer.normalize().dot(forwardVector)
|
||||||
|
face = if (dot > 0) "FRONT" else "BACK"
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check Owner
|
// Check Owner
|
||||||
|
|
@ -363,7 +488,7 @@ class ShopListener(private val plugin: ShopPlugin) : Listener {
|
||||||
|
|
||||||
// Check for Shop Sign above
|
// Check for Shop Sign above
|
||||||
val signBlock = block.getRelative(BlockFace.UP)
|
val signBlock = block.getRelative(BlockFace.UP)
|
||||||
if (signBlock.type != Material.OAK_SIGN) return
|
if (!ShopVisuals.isShopSign(signBlock.type)) return
|
||||||
|
|
||||||
val state = signBlock.state as? Sign ?: return
|
val state = signBlock.state as? Sign ?: return
|
||||||
if (!state.persistentDataContainer.has(tierKey, PersistentDataType.INTEGER)) return
|
if (!state.persistentDataContainer.has(tierKey, PersistentDataType.INTEGER)) return
|
||||||
|
|
@ -491,7 +616,7 @@ class ShopListener(private val plugin: ShopPlugin) : Listener {
|
||||||
updateShopDisplay(updatedShop)
|
updateShopDisplay(updatedShop)
|
||||||
val world = org.bukkit.Bukkit.getWorld(updatedShop.worldUid)
|
val world = org.bukkit.Bukkit.getWorld(updatedShop.worldUid)
|
||||||
val block = world?.getBlockAt(updatedShop.x, updatedShop.y, updatedShop.z)
|
val block = world?.getBlockAt(updatedShop.x, updatedShop.y, updatedShop.z)
|
||||||
if (block != null && block.type == Material.OAK_SIGN) {
|
if (block != null && ShopVisuals.isShopSign(block.type)) {
|
||||||
val side = if (updatedShop.face == "FRONT") Side.FRONT else Side.BACK
|
val side = if (updatedShop.face == "FRONT") Side.FRONT else Side.BACK
|
||||||
ShopVisuals.updateSign(plugin, block, updatedShop, side)
|
ShopVisuals.updateSign(plugin, block, updatedShop, side)
|
||||||
}
|
}
|
||||||
|
|
@ -517,7 +642,7 @@ class ShopListener(private val plugin: ShopPlugin) : Listener {
|
||||||
updateShopDisplay(updatedShop)
|
updateShopDisplay(updatedShop)
|
||||||
val world = org.bukkit.Bukkit.getWorld(updatedShop.worldUid)
|
val world = org.bukkit.Bukkit.getWorld(updatedShop.worldUid)
|
||||||
val block = world?.getBlockAt(updatedShop.x, updatedShop.y, updatedShop.z)
|
val block = world?.getBlockAt(updatedShop.x, updatedShop.y, updatedShop.z)
|
||||||
if (block != null && block.type == Material.OAK_SIGN) {
|
if (block != null && ShopVisuals.isShopSign(block.type)) {
|
||||||
val side = if (updatedShop.face == "FRONT") Side.FRONT else Side.BACK
|
val side = if (updatedShop.face == "FRONT") Side.FRONT else Side.BACK
|
||||||
ShopVisuals.updateSign(plugin, block, updatedShop, side)
|
ShopVisuals.updateSign(plugin, block, updatedShop, side)
|
||||||
}
|
}
|
||||||
|
|
@ -560,7 +685,7 @@ class ShopListener(private val plugin: ShopPlugin) : Listener {
|
||||||
shopData.z.toDouble()
|
shopData.z.toDouble()
|
||||||
)
|
)
|
||||||
val block = location.block
|
val block = location.block
|
||||||
if (block.type != Material.OAK_SIGN) return
|
if (!ShopVisuals.isShopSign(block.type)) return
|
||||||
|
|
||||||
val sign = block.state as? Sign ?: return
|
val sign = block.state as? Sign ?: return
|
||||||
|
|
||||||
|
|
@ -595,7 +720,7 @@ class ShopListener(private val plugin: ShopPlugin) : Listener {
|
||||||
// Handle Container Break Protection
|
// Handle Container Break Protection
|
||||||
if (block.type in ShopVisuals.VALID_CONTAINERS) {
|
if (block.type in ShopVisuals.VALID_CONTAINERS) {
|
||||||
val signBlock = block.getRelative(BlockFace.UP)
|
val signBlock = block.getRelative(BlockFace.UP)
|
||||||
if (signBlock.type == Material.OAK_SIGN) {
|
if (ShopVisuals.isShopSign(signBlock.type)) {
|
||||||
val state = signBlock.state as? Sign
|
val state = signBlock.state as? Sign
|
||||||
if (state != null && state.persistentDataContainer.has(tierKey, PersistentDataType.INTEGER)) {
|
if (state != null && state.persistentDataContainer.has(tierKey, PersistentDataType.INTEGER)) {
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
|
|
@ -606,7 +731,7 @@ class ShopListener(private val plugin: ShopPlugin) : Listener {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle Shop Sign Break
|
// Handle Shop Sign Break
|
||||||
if (block.type != Material.OAK_SIGN) return
|
if (!ShopVisuals.isShopSign(block.type)) return
|
||||||
|
|
||||||
val state = block.state as? Sign ?: return
|
val state = block.state as? Sign ?: return
|
||||||
if (!state.persistentDataContainer.has(tierKey, PersistentDataType.INTEGER)) return
|
if (!state.persistentDataContainer.has(tierKey, PersistentDataType.INTEGER)) return
|
||||||
|
|
@ -635,50 +760,24 @@ class ShopListener(private val plugin: ShopPlugin) : Listener {
|
||||||
// Delete Shops
|
// Delete Shops
|
||||||
if (frontShop != null) {
|
if (frontShop != null) {
|
||||||
ShopRepository.delete(frontShop.id)
|
ShopRepository.delete(frontShop.id)
|
||||||
ShopVisuals.removeDisplay(location, "FRONT")
|
ShopVisuals.removeDisplay(plugin, location, frontShop.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (backShop != null) {
|
if (backShop != null) {
|
||||||
ShopRepository.delete(backShop.id)
|
ShopRepository.delete(backShop.id)
|
||||||
ShopVisuals.removeDisplay(location, "BACK")
|
ShopVisuals.removeDisplay(plugin, location, backShop.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
event.player.sendMessage(Component.text("Shop removed.", NamedTextColor.GREEN))
|
event.player.sendMessage(Component.text("Shop removed.", NamedTextColor.GREEN))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private fun updateShopDisplay(shopData: net.hareworks.hcu.shop.database.ShopData) {
|
|
||||||
val world = org.bukkit.Bukkit.getWorld(shopData.worldUid) ?: return
|
|
||||||
val block = world.getBlockAt(shopData.x, shopData.y, shopData.z)
|
|
||||||
|
|
||||||
// Ensure block is still a sign and rotatable
|
|
||||||
val data = block.blockData as? Rotatable ?: return
|
|
||||||
val rotation = data.rotation
|
|
||||||
|
|
||||||
val yaw = ShopVisuals.yawFromBlockFace(rotation) + 90f
|
|
||||||
|
|
||||||
val offset = if (shopData.face == "FRONT") Vector3f(0.25f, 0.25f, 0.0f) else Vector3f(-0.25f, 0.25f, 0.0f)
|
|
||||||
val rad = Math.toRadians(yaw.toDouble())
|
|
||||||
offset.rotateY(-rad.toFloat())
|
|
||||||
|
|
||||||
val center = block.location.clone().add(0.5, 0.0, 0.5)
|
|
||||||
val targetPos = center.clone().add(offset.x.toDouble(), offset.y.toDouble(), offset.z.toDouble())
|
|
||||||
|
|
||||||
// Search for entity
|
|
||||||
val nearby = world.getNearbyEntities(targetPos, 0.2, 0.2, 0.2)
|
|
||||||
val display = nearby.filterIsInstance<ItemDisplay>().firstOrNull()
|
|
||||||
|
|
||||||
if (display != null) {
|
|
||||||
if (shopData.item != null) {
|
|
||||||
display.setItemStack(shopData.item)
|
|
||||||
} else {
|
|
||||||
display.setItemStack(ItemStack(Material.AIR))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
object ShopGuiMap {
|
object ShopGuiMap {
|
||||||
val openInvs = java.util.WeakHashMap<Inventory, Int>()
|
val openInvs = java.util.WeakHashMap<Inventory, Int>()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user