1
0
Fork 0

Add colors for players

main
Mari 4 years ago
parent 5a664edb8e
commit 744e09483b
  1. 89
      src/main/kotlin/net/deliciousreya/minecraftportal/MinecraftPortalPlugin.kt
  2. 50
      src/main/kotlin/net/deliciousreya/minecraftportal/extensions/Material.kt
  3. 29
      src/main/kotlin/net/deliciousreya/minecraftportal/model/Portal.kt
  4. 57
      src/main/kotlin/net/deliciousreya/minecraftportal/model/PortalDataStore.kt
  5. 62
      src/main/kotlin/net/deliciousreya/minecraftportal/model/PortalFrame.kt
  6. 17
      src/main/kotlin/net/deliciousreya/minecraftportal/model/PortalType.kt
  7. 26
      src/main/proto/portal-save-data.proto
  8. 7
      src/main/resources/plugin.yml

@ -1,15 +1,19 @@
package net.deliciousreya.minecraftportal package net.deliciousreya.minecraftportal
import com.destroystokyo.paper.event.block.BlockDestroyEvent import com.destroystokyo.paper.event.block.BlockDestroyEvent
import net.deliciousreya.minecraftportal.extensions.COLOR_NAME_MAPPING
import net.deliciousreya.minecraftportal.extensions.MID_BLOCK import net.deliciousreya.minecraftportal.extensions.MID_BLOCK
import net.deliciousreya.minecraftportal.extensions.plus import net.deliciousreya.minecraftportal.extensions.plus
import net.deliciousreya.minecraftportal.model.DOOR_TYPES import net.deliciousreya.minecraftportal.model.DOOR_TYPES
import net.deliciousreya.minecraftportal.model.PortalDataStore import net.deliciousreya.minecraftportal.model.PortalDataStore
import net.deliciousreya.minecraftportal.model.PortalFrame import net.deliciousreya.minecraftportal.model.PortalFrame
import net.deliciousreya.minecraftportal.model.findPortalFrameConnectedTo import net.deliciousreya.minecraftportal.model.findPortalFrameConnectedTo
import org.bukkit.Material
import org.bukkit.Sound import org.bukkit.Sound
import org.bukkit.block.Block import org.bukkit.block.Block
import org.bukkit.block.data.type.Door import org.bukkit.block.data.type.Door
import org.bukkit.command.Command
import org.bukkit.command.CommandSender
import org.bukkit.entity.Entity import org.bukkit.entity.Entity
import org.bukkit.entity.Player import org.bukkit.entity.Player
import org.bukkit.event.EventHandler import org.bukkit.event.EventHandler
@ -21,6 +25,7 @@ import org.bukkit.event.player.PlayerInteractEvent
import org.bukkit.event.player.PlayerMoveEvent import org.bukkit.event.player.PlayerMoveEvent
import org.bukkit.plugin.java.JavaPlugin import org.bukkit.plugin.java.JavaPlugin
import org.bukkit.potion.PotionEffectType import org.bukkit.potion.PotionEffectType
import java.lang.IllegalStateException
class MinecraftPortalPlugin() : JavaPlugin(), Listener class MinecraftPortalPlugin() : JavaPlugin(), Listener
{ {
@ -31,6 +36,8 @@ class MinecraftPortalPlugin() : JavaPlugin(), Listener
portals.loadFromAndAutoSaveTo(server, dataFolder.resolve("portal_data.binproto"), dataFolder.resolve("portal_data.binproto.bak")) portals.loadFromAndAutoSaveTo(server, dataFolder.resolve("portal_data.binproto"), dataFolder.resolve("portal_data.binproto.bak"))
portals.validateWorldOnStartup(logger) portals.validateWorldOnStartup(logger)
portals.launchEffectsOnStartup(this) portals.launchEffectsOnStartup(this)
val setColorCommand = getCommand("portalcolor") ?: throw IllegalStateException("portalcolor command was missing")
setColorCommand.setExecutor { sender, _, _, args -> onPortalColor(sender, args) }
server.pluginManager.registerEvents(this, this) server.pluginManager.registerEvents(this, this)
} }
@ -39,8 +46,65 @@ class MinecraftPortalPlugin() : JavaPlugin(), Listener
portals.unload() portals.unload()
} }
fun onPortalColor(sender: CommandSender, args: Array<String>): Boolean {
val argsList = if (args.isEmpty() && sender is Player) {
listOf("show")
} else {
args.asList()
}
if (argsList.isEmpty() || args.size > 2) {
sender.sendMessage("You must specify one or two arguments.")
return false
}
val colorString = if (argsList.size == 1) {
argsList[0]
} else {
argsList[1]
}
val playerString = when {
argsList.size == 2 -> {
argsList[0]
}
sender is Player -> {
sender.name
}
else -> {
null
}
}
if (playerString == null) {
sender.sendMessage("Only players can set their own color with the one-arg form.")
return false
}
if (colorString == "show") {
if (sender is Player && playerString == sender.name) {
sender.sendMessage("Portals you create are marked with ${portals.getColorFor(playerString).name}.")
} else {
sender.sendMessage("Portals created by $playerString are marked with ${portals.getColorFor(playerString).name}.")
}
return true
}
if (playerString != sender.name && !sender.isOp) {
sender.sendMessage("Only ops can set other players' colors with the two-arg form.")
return false
}
val color = COLOR_NAME_MAPPING[colorString]
if (color == null) {
sender.sendMessage("I don't know that color. Are you sure it's one of the dye colors?")
return false
}
portals.setColorFor(playerString, color)
if (sender is Player && playerString == sender.name) {
sender.sendMessage("Your portals will now be marked with ${portals.getColorFor(playerString).name}.")
} else {
sender.sendMessage("Portals created by $playerString will now be marked with ${portals.getColorFor(playerString).name}")
}
return true
}
@EventHandler @EventHandler
fun onBlockPlaced(e: BlockPlaceEvent) { fun onBlockPlaced(e: BlockPlaceEvent) {
e.player.name
if (e.block.type in PortalFrame.State.INACTIVE.allValidBlocks) { if (e.block.type in PortalFrame.State.INACTIVE.allValidBlocks) {
val newPortal = findPortalFrameConnectedTo( val newPortal = findPortalFrameConnectedTo(
e.block, e.block,
@ -50,6 +114,9 @@ class MinecraftPortalPlugin() : JavaPlugin(), Listener
val replacedPortal = portals.activateAndReplacePortal(newPortal) val replacedPortal = portals.activateAndReplacePortal(newPortal)
val otherPortal = portals.getOtherPortal(newPortal) val otherPortal = portals.getOtherPortal(newPortal)
newPortal.activate() newPortal.activate()
if (newPortal.color == Material.GLASS) {
newPortal.color = portals.getColorFor(e.player.name)
}
replacedPortal?.deactivate() replacedPortal?.deactivate()
if (otherPortal != null) { if (otherPortal != null) {
newPortal.open() newPortal.open()
@ -123,19 +190,15 @@ class MinecraftPortalPlugin() : JavaPlugin(), Listener
} }
} }
fun onPlayerMove(e: PlayerMoveEvent) { //fun onPlayerMove(e: PlayerMoveEvent) {
val player = e.player //val player = e.player
val oldLocation = e.from //val oldLocation = e.from
val portal = portals.isLocationInPortalChamber(oldLocation) ?: return //val portal = portals.isLocationInPortalChamber(oldLocation) ?: return
val newLocation = e.to ?: return //val newLocation = e.to ?: return
if (oldLocation.world != newLocation.world || oldLocation.toVector() !in portal.portalInsideBoundingBox) { //if (oldLocation.world != newLocation.world || oldLocation.toVector() !in portal.portalInsideBoundingBox) {
cancelTeleportFor(player) // TODO: cancelTeleportFor(player)
} //}
} //}
private fun cancelTeleportFor(entity: Entity) {
}
fun onDestroyedBlock(block: Block) { fun onDestroyedBlock(block: Block) {
if (block.type !in PortalFrame.State.ACTIVE.allValidBlocks) { if (block.type !in PortalFrame.State.ACTIVE.allValidBlocks) {

@ -6,6 +6,44 @@ import net.deliciousreya.minecraftportal.proto.PortalSaveDataProtos
import org.bukkit.Material import org.bukkit.Material
import java.lang.IllegalStateException import java.lang.IllegalStateException
val COLOR_NAME_MAPPING: ImmutableBiMap<String, Material> = ImmutableBiMap.builder<String, Material>()
.put("white", Material.WHITE_STAINED_GLASS)
.put("red", Material.RED_STAINED_GLASS)
.put("orange", Material.ORANGE_STAINED_GLASS)
.put("pink", Material.PINK_STAINED_GLASS)
.put("yellow", Material.YELLOW_STAINED_GLASS)
.put("lime", Material.LIME_STAINED_GLASS)
.put("green", Material.GREEN_STAINED_GLASS)
.put("lightblue", Material.LIGHT_BLUE_STAINED_GLASS)
.put("cyan", Material.CYAN_STAINED_GLASS)
.put("blue", Material.BLUE_STAINED_GLASS)
.put("magenta", Material.MAGENTA_STAINED_GLASS)
.put("purple", Material.PURPLE_STAINED_GLASS)
.put("brown", Material.BROWN_STAINED_GLASS)
.put("gray", Material.GRAY_STAINED_GLASS)
.put("lightgray", Material.LIGHT_GRAY_STAINED_GLASS)
.put("black", Material.BLACK_STAINED_GLASS)
.build()
val COLOR_MAPPING: ImmutableBiMap<Material, PortalSaveDataProtos.Portal.Color> = ImmutableBiMap.builder<Material, PortalSaveDataProtos.Portal.Color>()
.put(Material.WHITE_STAINED_GLASS, PortalSaveDataProtos.Portal.Color.WHITE)
.put(Material.RED_STAINED_GLASS, PortalSaveDataProtos.Portal.Color.RED)
.put(Material.ORANGE_STAINED_GLASS, PortalSaveDataProtos.Portal.Color.ORANGE)
.put(Material.PINK_STAINED_GLASS, PortalSaveDataProtos.Portal.Color.PINK)
.put(Material.YELLOW_STAINED_GLASS, PortalSaveDataProtos.Portal.Color.YELLOW)
.put(Material.LIME_STAINED_GLASS, PortalSaveDataProtos.Portal.Color.LIME)
.put(Material.GREEN_STAINED_GLASS, PortalSaveDataProtos.Portal.Color.GREEN)
.put(Material.LIGHT_BLUE_STAINED_GLASS, PortalSaveDataProtos.Portal.Color.LIGHT_BLUE)
.put(Material.CYAN_STAINED_GLASS, PortalSaveDataProtos.Portal.Color.CYAN)
.put(Material.BLUE_STAINED_GLASS, PortalSaveDataProtos.Portal.Color.BLUE)
.put(Material.MAGENTA_STAINED_GLASS, PortalSaveDataProtos.Portal.Color.MAGENTA)
.put(Material.PURPLE_STAINED_GLASS, PortalSaveDataProtos.Portal.Color.PURPLE)
.put(Material.BROWN_STAINED_GLASS, PortalSaveDataProtos.Portal.Color.BROWN)
.put(Material.GRAY_STAINED_GLASS, PortalSaveDataProtos.Portal.Color.GRAY)
.put(Material.LIGHT_GRAY_STAINED_GLASS, PortalSaveDataProtos.Portal.Color.LIGHT_GRAY)
.put(Material.BLACK_STAINED_GLASS, PortalSaveDataProtos.Portal.Color.BLACK)
.build()
val MINERAL_MAPPING: ImmutableBiMap<Material, PortalSaveDataProtos.Portal.Mineral> = ImmutableBiMap.builder<Material, PortalSaveDataProtos.Portal.Mineral>() val MINERAL_MAPPING: ImmutableBiMap<Material, PortalSaveDataProtos.Portal.Mineral> = ImmutableBiMap.builder<Material, PortalSaveDataProtos.Portal.Mineral>()
.put(Material.COAL_BLOCK, PortalSaveDataProtos.Portal.Mineral.COAL) .put(Material.COAL_BLOCK, PortalSaveDataProtos.Portal.Mineral.COAL)
.put(Material.REDSTONE_BLOCK, PortalSaveDataProtos.Portal.Mineral.REDSTONE) .put(Material.REDSTONE_BLOCK, PortalSaveDataProtos.Portal.Mineral.REDSTONE)
@ -18,9 +56,17 @@ val MINERAL_MAPPING: ImmutableBiMap<Material, PortalSaveDataProtos.Portal.Minera
.build() .build()
fun Material.toMineralProto(): PortalSaveDataProtos.Portal.Mineral { fun Material.toMineralProto(): PortalSaveDataProtos.Portal.Mineral {
return MINERAL_MAPPING[this] ?: throw DeserializationException("Not a mineral: ${this}") return MINERAL_MAPPING[this] ?: throw DeserializationException("Not a mineral: $this")
}
fun Material.toColorProto(): PortalSaveDataProtos.Portal.Color {
return COLOR_MAPPING[this] ?: throw DeserializationException("Not a color: $this")
} }
fun PortalSaveDataProtos.Portal.Mineral.toMaterial(): Material { fun PortalSaveDataProtos.Portal.Mineral.toMaterial(): Material {
return MINERAL_MAPPING.inverse()[this] ?: throw DeserializationException("Not a material: ${this}") return MINERAL_MAPPING.inverse()[this] ?: throw DeserializationException("Not a material: $this")
}
fun PortalSaveDataProtos.Portal.Color.toMaterial(): Material {
return COLOR_MAPPING.inverse()[this] ?: throw DeserializationException("Not a material: $this")
} }

@ -1,20 +1,30 @@
package net.deliciousreya.minecraftportal.model package net.deliciousreya.minecraftportal.model
import net.deliciousreya.minecraftportal.extensions.toLocation import net.deliciousreya.minecraftportal.extensions.*
import net.deliciousreya.minecraftportal.extensions.toMaterial
import net.deliciousreya.minecraftportal.extensions.toMineralProto
import net.deliciousreya.minecraftportal.extensions.toProto
import net.deliciousreya.minecraftportal.proto.PortalSaveDataProtos import net.deliciousreya.minecraftportal.proto.PortalSaveDataProtos
import org.bukkit.Material import org.bukkit.Material
import org.bukkit.Server import org.bukkit.Server
import org.bukkit.plugin.Plugin import org.bukkit.plugin.Plugin
import org.bukkit.scheduler.BukkitRunnable
import java.lang.IllegalArgumentException import java.lang.IllegalArgumentException
fun PortalSaveDataProtos.Portal.toPortal(server: Server, portalTypes: Map<Material, PortalType>): Portal { fun PortalSaveDataProtos.Portal.Mineral.asColor(): PortalSaveDataProtos.Portal.Color {
val portalType = portalTypes[mineral.toMaterial()] ?: throw IllegalArgumentException("No portal type for $mineral") if (this == PortalSaveDataProtos.Portal.Mineral.UNKNOWN_MINERAL) {
val result = Portal(PortalFrame(lowerLeftFrontCorner.toLocation(server), exitDirection.toDirection()), portalType) throw IllegalArgumentException("No portal color for $this")
return result }
val material = toMaterial()
val matchingGlass = MINERAL_TYPES[material] ?: throw IllegalArgumentException("No portal color for $this: no glass matches")
return COLOR_MAPPING[matchingGlass] ?: throw IllegalArgumentException("No portal color for $this: no color matches")
}
fun PortalSaveDataProtos.Portal.toPortal(server: Server, portalTypes: Map<Material, Map<Material, PortalType>>): Portal {
val mineralMap = portalTypes[mineral.toMaterial()] ?: throw IllegalArgumentException("No portal type for $mineral")
val effectiveColor = if (color == PortalSaveDataProtos.Portal.Color.UNKNOWN_COLOR) {
mineral.asColor()
} else {
color
}
val portalType = mineralMap[effectiveColor.toMaterial()] ?: throw IllegalArgumentException("No portal type for $color")
return Portal(PortalFrame(lowerLeftFrontCorner.toLocation(server), exitDirection.toDirection()), portalType)
} }
class Portal(val frame: PortalFrame, val type: PortalType) { class Portal(val frame: PortalFrame, val type: PortalType) {
@ -41,6 +51,7 @@ class Portal(val frame: PortalFrame, val type: PortalType) {
.setLowerLeftFrontCorner(frame.lowerLeftFrontCorner.toProto()) .setLowerLeftFrontCorner(frame.lowerLeftFrontCorner.toProto())
.setExitDirection(frame.direction.toProto()) .setExitDirection(frame.direction.toProto())
.setMineral(frame.mineral.toMineralProto()) .setMineral(frame.mineral.toMineralProto())
.setColor(frame.color.toColorProto())
.build() .build()
} }
} }

@ -1,8 +1,12 @@
package net.deliciousreya.minecraftportal.model package net.deliciousreya.minecraftportal.model
import com.google.common.collect.ImmutableList
import com.google.common.collect.ImmutableMap import com.google.common.collect.ImmutableMap
import com.google.protobuf.InvalidProtocolBufferException import com.google.protobuf.InvalidProtocolBufferException
import net.deliciousreya.minecraftportal.extensions.COLOR_MAPPING
import net.deliciousreya.minecraftportal.extensions.MINERAL_MAPPING import net.deliciousreya.minecraftportal.extensions.MINERAL_MAPPING
import net.deliciousreya.minecraftportal.extensions.toColorProto
import net.deliciousreya.minecraftportal.extensions.toMaterial
import net.deliciousreya.minecraftportal.proto.PortalSaveDataProtos import net.deliciousreya.minecraftportal.proto.PortalSaveDataProtos
import org.bukkit.Location import org.bukkit.Location
import org.bukkit.Material import org.bukkit.Material
@ -16,17 +20,27 @@ import java.util.logging.Logger
class PortalDataStore (){ class PortalDataStore (){
var saveDataTo: File? = null var saveDataTo: File? = null
var useBackup: File? = null var useBackup: File? = null
val portalTypes: ImmutableMap<Material, PortalType> private val userColors: MutableMap<String, Material> = mutableMapOf()
private val portalTypes: ImmutableMap<Material, ImmutableMap<Material, PortalType>>
private val allPortals: ImmutableList<PortalType>
init { init {
val portalTypesBuilder = ImmutableMap.builder<Material, PortalType>() val allPortalsBuilder = ImmutableList.builder<PortalType>()
val portalTypesBuilder = ImmutableMap.builder<Material, ImmutableMap<Material, PortalType>>()
for (mineralType in MINERAL_MAPPING.keys) { for (mineralType in MINERAL_MAPPING.keys) {
portalTypesBuilder.put(mineralType, PortalType(mineralType)) val colors = ImmutableMap.Builder<Material, PortalType>()
for (color in COLOR_MAPPING.keys) {
val portalType = PortalType(mineralType, color)
colors.put(color, portalType)
allPortalsBuilder.add(portalType)
}
portalTypesBuilder.put(mineralType, colors.build())
} }
portalTypes = portalTypesBuilder.build() portalTypes = portalTypesBuilder.build()
allPortals = allPortalsBuilder.build()
} }
fun isLocationInPortalOrChamber(location: Location): PortalFrame? { fun isLocationInPortalOrChamber(location: Location): PortalFrame? {
for (type in this.portalTypes.values) { for (type in this.allPortals) {
if (type.isEmpty) { if (type.isEmpty) {
continue continue
} }
@ -39,7 +53,7 @@ class PortalDataStore (){
} }
fun isLocationInPortalChamber(location: Location): PortalFrame? { fun isLocationInPortalChamber(location: Location): PortalFrame? {
for (type in this.portalTypes.values) { for (type in this.allPortals) {
if (type.isEmpty) { if (type.isEmpty) {
continue continue
} }
@ -90,7 +104,7 @@ class PortalDataStore (){
} }
fun validateWorldOnStartup(logger: Logger) { fun validateWorldOnStartup(logger: Logger) {
for (portalType in this.portalTypes.values) { for (portalType in this.allPortals) {
val oldPortal = portalType.oldestActivePortal val oldPortal = portalType.oldestActivePortal
val newPortal = portalType.newestActivePortal val newPortal = portalType.newestActivePortal
if (newPortal != null && !validatePortal(newPortal)) { if (newPortal != null && !validatePortal(newPortal)) {
@ -106,11 +120,11 @@ class PortalDataStore (){
} }
fun validatePortal(portal: Portal): Boolean { fun validatePortal(portal: Portal): Boolean {
return portal.frame.mineral == portal.type.mineral && portal.frame.isActivePortal() return portal.frame.mineral == portal.type.mineral && portal.frame.color == portal.type.color && portal.frame.isActivePortal()
} }
fun launchEffectsOnStartup(plugin: Plugin) { fun launchEffectsOnStartup(plugin: Plugin) {
for (portalType in this.portalTypes.values) { for (portalType in this.allPortals) {
startEffectsFor(portalType, plugin) startEffectsFor(portalType, plugin)
} }
} }
@ -174,7 +188,7 @@ class PortalDataStore (){
} }
fun getPortalType(frame: PortalFrame): PortalType { fun getPortalType(frame: PortalFrame): PortalType {
return portalTypes[frame.mineral] ?: throw IllegalArgumentException("There are no portals of type ${frame.mineral}") return portalTypes[frame.mineral]?.get(frame.color) ?: throw IllegalArgumentException("There are no portals of type ${frame.mineral}/${frame.color}")
} }
/** Gets the other portal, if the given frame is one of the portals in a pair. */ /** Gets the other portal, if the given frame is one of the portals in a pair. */
@ -185,7 +199,7 @@ class PortalDataStore (){
/** Forgets all the data without actually affecting the world. */ /** Forgets all the data without actually affecting the world. */
fun clear() { fun clear() {
for (portalType in this.portalTypes.values) { for (portalType in this.allPortals) {
portalType.oldestActivePortal?.stopEffects() portalType.oldestActivePortal?.stopEffects()
portalType.newestActivePortal?.stopEffects() portalType.newestActivePortal?.stopEffects()
portalType.clear() portalType.clear()
@ -206,11 +220,14 @@ class PortalDataStore (){
} }
olderPortal.type.loadPairedPortals(olderPortal, newerPortal) olderPortal.type.loadPairedPortals(olderPortal, newerPortal)
} }
for (userData in proto.userDataList) {
userColors[userData.name] = userData.color.toMaterial()
}
} }
fun toProto(): PortalSaveDataProtos.PortalSaveData { fun toProto(): PortalSaveDataProtos.PortalSaveData {
val builder = PortalSaveDataProtos.PortalSaveData.newBuilder() val builder = PortalSaveDataProtos.PortalSaveData.newBuilder()
for (portalType in this.portalTypes.values) { for (portalType in this.allPortals) {
when { when {
portalType.isEmpty -> { portalType.isEmpty -> {
// Nothing here to save. Just skip it. // Nothing here to save. Just skip it.
@ -223,6 +240,9 @@ class PortalDataStore (){
} }
} }
} }
for (user in this.userColors.keys) {
builder.addUserData(PortalSaveDataProtos.UserData.newBuilder().setName(user).setColor(this.userColors[user]?.toColorProto()))
}
return builder.build() return builder.build()
} }
@ -233,4 +253,19 @@ class PortalDataStore (){
fun stopTeleporting(portal: PortalFrame) { fun stopTeleporting(portal: PortalFrame) {
getPortalType(portal).cancelTeleportation() getPortalType(portal).cancelTeleportation()
} }
private val defaultColor = Material.GRAY_STAINED_GLASS
fun getColorFor(name: String): Material {
return userColors.getOrDefault(name, defaultColor)
}
fun setColorFor(name: String, color: Material) {
if (color == defaultColor) {
userColors.remove(name)
} else {
userColors[name] = color
}
onAfterChanged()
}
} }

@ -33,11 +33,11 @@ val MINERAL_TYPES: ImmutableMap<Material, Material> = ImmutableMap.Builder<Mater
val DOOR_TYPES: ImmutableSet<Material> = ImmutableSet.of(ACACIA_DOOR, BIRCH_DOOR, DARK_OAK_DOOR, IRON_DOOR, JUNGLE_DOOR, OAK_DOOR, SPRUCE_DOOR) val DOOR_TYPES: ImmutableSet<Material> = ImmutableSet.of(ACACIA_DOOR, BIRCH_DOOR, DARK_OAK_DOOR, IRON_DOOR, JUNGLE_DOOR, OAK_DOOR, SPRUCE_DOOR)
fun findPortalFrameConnectedTo(block:Block, state: PortalFrame.State): PortalFrame? { fun findPortalFrameConnectedTo(block:Block, state: PortalFrame.State): PortalFrame? {
when { for (blockSet in state.blockSets) {
block.type in state.glassBlocks -> for (direction in PortalFrame.ExitDirection.values()) { for (direction in PortalFrame.ExitDirection.values()) {
for (vector in direction.glassOffsets) { for (offset in blockSet.offsets(direction)) {
val scanResult = checkPortalFrameAt( val scanResult = checkPortalFrameAt(
block.location.subtract(vector), block.location.subtract(offset),
direction, direction,
state state
) )
@ -46,28 +46,6 @@ fun findPortalFrameConnectedTo(block:Block, state: PortalFrame.State): PortalFra
} }
} }
} }
block.type in state.doorBlocks -> for (direction in PortalFrame.ExitDirection.values()) {
for (vector in direction.doorOffsets) {
val scanResult = checkPortalFrameAt(
block.location.subtract(vector),
direction,
state
)
if (scanResult != null) {
return scanResult
}
}
}
block.type in state.mineralBlocks -> for (direction in PortalFrame.ExitDirection.values()) {
val scanResult = checkPortalFrameAt(
block.location.subtract(direction.mineralOffset),
direction,
state
)
if (scanResult != null) {
return scanResult
}
}
} }
return null return null
} }
@ -78,6 +56,10 @@ fun checkPortalFrameAt(location:Location, direction: PortalFrame.ExitDirection,
if (mineral.type !in state.mineralBlocks) { if (mineral.type !in state.mineralBlocks) {
return null return null
} }
val color = (location + direction.colorOffset).block
if (color.type !in state.colorBlocks) {
return null
}
for (vector in direction.glassOffsets) { for (vector in direction.glassOffsets) {
val block = (location + vector).block val block = (location + vector).block
if (block.type !in state.glassBlocks) { if (block.type !in state.glassBlocks) {
@ -105,13 +87,20 @@ fun PortalSaveDataProtos.Portal.Direction.toDirection(): PortalFrame.ExitDirecti
/** Information about a portal frame. */ /** Information about a portal frame. */
data class PortalFrame(val lowerLeftFrontCorner: Location, val direction: ExitDirection) { data class PortalFrame(val lowerLeftFrontCorner: Location, val direction: ExitDirection) {
enum class State(val glassBlocks: ImmutableSet<Material>, val doorBlocks: ImmutableSet<Material>, val mineralBlocks: ImmutableSet<Material>) { enum class State(val glassBlocks: ImmutableSet<Material>, val colorBlocks: ImmutableSet<Material>, val doorBlocks: ImmutableSet<Material>, val mineralBlocks: ImmutableSet<Material>) {
ACTIVE(ImmutableSet.copyOf(MINERAL_TYPES.values), ACTIVE(ImmutableSet.copyOf(MINERAL_TYPES.values), ImmutableSet.copyOf(COLOR_MAPPING.keys),
DOOR_TYPES, ImmutableSet.copyOf(MINERAL_TYPES.keys)), DOOR_TYPES, ImmutableSet.copyOf(MINERAL_TYPES.keys)),
INACTIVE(ImmutableSet.of(GLASS), INACTIVE(ImmutableSet.of(GLASS), ImmutableSet.builder<Material>().addAll(COLOR_MAPPING.keys).add(GLASS).build(),
DOOR_TYPES, ImmutableSet.copyOf(MINERAL_TYPES.keys)); DOOR_TYPES, ImmutableSet.copyOf(MINERAL_TYPES.keys));
val allValidBlocks:ImmutableSet<Material> = ImmutableSet.Builder<Material>().addAll(glassBlocks).addAll(doorBlocks).addAll(mineralBlocks).build() val allValidBlocks:ImmutableSet<Material> = ImmutableSet.Builder<Material>().addAll(glassBlocks).addAll(doorBlocks).addAll(mineralBlocks).addAll(colorBlocks).build()
data class BlockSet(val blockTypes: Set<Material>, val offsets: (direction: ExitDirection) -> List<Vector>)
val blockSets = listOf(
BlockSet(glassBlocks, offsets = { it.glassOffsets }),
BlockSet(doorBlocks, offsets = { it.doorOffsets }),
BlockSet(colorBlocks, offsets = { listOf(it.colorOffset) }),
BlockSet(mineralBlocks, offsets = { listOf(it.mineralOffset) })
)
} }
/** The direction a player faces when exiting the portal. */ /** The direction a player faces when exiting the portal. */
enum class ExitDirection(val toRight: Vector, val toBack: Vector, val doorDirection: BlockFace, val protoEnum: PortalSaveDataProtos.Portal.Direction) { enum class ExitDirection(val toRight: Vector, val toBack: Vector, val doorDirection: BlockFace, val protoEnum: PortalSaveDataProtos.Portal.Direction) {
@ -143,8 +132,6 @@ data class PortalFrame(val lowerLeftFrontCorner: Location, val direction: ExitDi
// left front wall // left front wall
UP, UP,
UP * 2, UP * 2,
// top front wall
UP * 3 + toRight,
// right front wall // right front wall
UP + toRight * 2, UP + toRight * 2,
UP * 2 + toRight * 2, UP * 2 + toRight * 2,
@ -164,10 +151,11 @@ data class PortalFrame(val lowerLeftFrontCorner: Location, val direction: ExitDi
) )
val mineralOffset: Vector = toRight val mineralOffset: Vector = toRight
val colorOffset: Vector = UP * 3 + toRight
val doorOffsets: ImmutableList<Vector> = ImmutableList.of( val doorOffsets: ImmutableList<Vector> = ImmutableList.of(
Vector(0, 1, 0) + toRight, UP + toRight,
Vector(0, 2, 0) + toRight UP * 2 + toRight
) )
fun toProto():PortalSaveDataProtos.Portal.Direction { fun toProto():PortalSaveDataProtos.Portal.Direction {
@ -175,6 +163,7 @@ data class PortalFrame(val lowerLeftFrontCorner: Location, val direction: ExitDi
} }
} }
val portalCenter = lowerLeftFrontCorner + direction.doorOffsets[0] val portalCenter = lowerLeftFrontCorner + direction.doorOffsets[0]
val midCenter = portalCenter + MID_BLOCK val midCenter = portalCenter + MID_BLOCK
val fullPortalBoundingBox = BoundingBox.of(lowerLeftFrontCorner.block, (lowerLeftFrontCorner + UP * 3 + direction.toRight * 2 + direction.toBack).block) val fullPortalBoundingBox = BoundingBox.of(lowerLeftFrontCorner.block, (lowerLeftFrontCorner + UP * 3 + direction.toRight * 2 + direction.toBack).block)
@ -209,6 +198,11 @@ data class PortalFrame(val lowerLeftFrontCorner: Location, val direction: ExitDi
} }
val mineral = (lowerLeftFrontCorner + direction.mineralOffset).block.type val mineral = (lowerLeftFrontCorner + direction.mineralOffset).block.type
var color: Material
get() = (lowerLeftFrontCorner + direction.colorOffset).block.type
set(newColor) {
(lowerLeftFrontCorner + direction.colorOffset).block.type = newColor
}
fun open() { fun open() {
val block = portalCenter.block val block = portalCenter.block

@ -4,10 +4,9 @@ import net.deliciousreya.minecraftportal.proto.PortalSaveDataProtos
import org.bukkit.Location import org.bukkit.Location
import org.bukkit.Material import org.bukkit.Material
import org.bukkit.plugin.Plugin import org.bukkit.plugin.Plugin
import java.lang.IllegalArgumentException
import java.lang.IllegalStateException import java.lang.IllegalStateException
class PortalType(val mineral: Material) { class PortalType(val mineral: Material, val color: Material) {
var oldestActivePortal: Portal? = null var oldestActivePortal: Portal? = null
var newestActivePortal: Portal? = null var newestActivePortal: Portal? = null
@ -31,7 +30,7 @@ class PortalType(val mineral: Material) {
fun addOrReplacePortal(portal: Portal): Portal? { fun addOrReplacePortal(portal: Portal): Portal? {
if (portal.type != this) { if (portal.type != this) {
throw DeserializationException("Tried to add $portal which didn't belong to ${this}") throw DeserializationException("Tried to add $portal which didn't belong to $this")
} }
return when { return when {
this.isEmpty -> { this.isEmpty -> {
@ -54,23 +53,23 @@ class PortalType(val mineral: Material) {
fun loadUnpairedPortal(portal: Portal) { fun loadUnpairedPortal(portal: Portal) {
if (!this.isEmpty) { if (!this.isEmpty) {
throw DeserializationException("Already have a value for ${this} when adding $portal") throw DeserializationException("Already have a value for $this when adding $portal")
} }
if (portal.type != this) { if (portal.type != this) {
throw DeserializationException("Tried to add $portal which didn't belong to ${this}") throw DeserializationException("Tried to add $portal which didn't belong to $this")
} }
this.oldestActivePortal = portal this.oldestActivePortal = portal
} }
fun loadPairedPortals(olderPortal: Portal, newerPortal: Portal) { fun loadPairedPortals(olderPortal: Portal, newerPortal: Portal) {
if (!this.isEmpty) { if (!this.isEmpty) {
throw DeserializationException("Already have a value for ${this} when adding $olderPortal and $newerPortal") throw DeserializationException("Already have a value for $this when adding $olderPortal and $newerPortal")
} }
if (olderPortal.type != this) { if (olderPortal.type != this) {
throw DeserializationException("Tried to add $olderPortal which didn't belong to ${this}") throw DeserializationException("Tried to add $olderPortal which didn't belong to $this")
} }
if (newerPortal.type != this) { if (newerPortal.type != this) {
throw DeserializationException("Tried to add $newerPortal which didn't belong to ${this}") throw DeserializationException("Tried to add $newerPortal which didn't belong to $this")
} }
this.oldestActivePortal = olderPortal this.oldestActivePortal = olderPortal
this.newestActivePortal = newerPortal this.newestActivePortal = newerPortal
@ -95,7 +94,7 @@ class PortalType(val mineral: Material) {
} }
override fun toString():String { override fun toString():String {
return "PortalType{mineral=$mineral, oldestActivePortal=$oldestActivePortal, newestActivePortal=$newestActivePortal}" return "PortalType{mineral=$mineral, color=$color, oldestActivePortal=$oldestActivePortal, newestActivePortal=$newestActivePortal}"
} }
/** /**

@ -31,9 +31,29 @@ message Portal {
IRON = 7; IRON = 7;
QUARTZ = 8; QUARTZ = 8;
} }
enum Color {
UNKNOWN_COLOR = 0;
WHITE = 1;
RED = 2;
ORANGE = 3;
PINK = 4;
YELLOW = 5;
LIME = 6;
GREEN = 7;
LIGHT_BLUE = 8;
CYAN = 9;
BLUE = 10;
MAGENTA = 11;
PURPLE = 12;
BROWN = 13;
GRAY = 14;
LIGHT_GRAY = 15;
BLACK = 16;
}
Location lower_left_front_corner = 1; Location lower_left_front_corner = 1;
Direction exit_direction = 2; Direction exit_direction = 2;
Mineral mineral = 3; Mineral mineral = 3;
Color color = 4;
} }
message PortalPair { message PortalPair {
@ -41,7 +61,13 @@ message PortalPair {
Portal newer = 2; Portal newer = 2;
} }
message UserData {
string name = 1;
Portal.Color color = 2;
}
message PortalSaveData { message PortalSaveData {
repeated PortalPair paired_portals = 1; repeated PortalPair paired_portals = 1;
repeated Portal unpaired_portals = 2; repeated Portal unpaired_portals = 2;
repeated UserData user_data = 3;
} }

@ -1 +1,6 @@
api-version: '1.13' api-version: '1.16'
commands:
portalcolor:
description: Sets or gets the color of portals created by you or another player.
usage: "Usage: /portalcolor ([playername]) [show/white/red/orange/pink/yellow/lime/green/lightblue/cyan/blue/magenta/purple/brown/gray/lightgray/black]"

Loading…
Cancel
Save