diff --git a/src/main/kotlin/net/deliciousreya/minecraftportal/MinecraftPortalPlugin.kt b/src/main/kotlin/net/deliciousreya/minecraftportal/MinecraftPortalPlugin.kt index 9e31644..3a2209c 100644 --- a/src/main/kotlin/net/deliciousreya/minecraftportal/MinecraftPortalPlugin.kt +++ b/src/main/kotlin/net/deliciousreya/minecraftportal/MinecraftPortalPlugin.kt @@ -1,15 +1,19 @@ package net.deliciousreya.minecraftportal 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.plus import net.deliciousreya.minecraftportal.model.DOOR_TYPES import net.deliciousreya.minecraftportal.model.PortalDataStore import net.deliciousreya.minecraftportal.model.PortalFrame import net.deliciousreya.minecraftportal.model.findPortalFrameConnectedTo +import org.bukkit.Material import org.bukkit.Sound import org.bukkit.block.Block 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.Player import org.bukkit.event.EventHandler @@ -21,6 +25,7 @@ import org.bukkit.event.player.PlayerInteractEvent import org.bukkit.event.player.PlayerMoveEvent import org.bukkit.plugin.java.JavaPlugin import org.bukkit.potion.PotionEffectType +import java.lang.IllegalStateException 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.validateWorldOnStartup(logger) 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) } @@ -39,8 +46,65 @@ class MinecraftPortalPlugin() : JavaPlugin(), Listener portals.unload() } + fun onPortalColor(sender: CommandSender, args: Array): 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 fun onBlockPlaced(e: BlockPlaceEvent) { + e.player.name if (e.block.type in PortalFrame.State.INACTIVE.allValidBlocks) { val newPortal = findPortalFrameConnectedTo( e.block, @@ -50,6 +114,9 @@ class MinecraftPortalPlugin() : JavaPlugin(), Listener val replacedPortal = portals.activateAndReplacePortal(newPortal) val otherPortal = portals.getOtherPortal(newPortal) newPortal.activate() + if (newPortal.color == Material.GLASS) { + newPortal.color = portals.getColorFor(e.player.name) + } replacedPortal?.deactivate() if (otherPortal != null) { newPortal.open() @@ -123,19 +190,15 @@ class MinecraftPortalPlugin() : JavaPlugin(), Listener } } - fun onPlayerMove(e: PlayerMoveEvent) { - val player = e.player - val oldLocation = e.from - val portal = portals.isLocationInPortalChamber(oldLocation) ?: return - val newLocation = e.to ?: return - if (oldLocation.world != newLocation.world || oldLocation.toVector() !in portal.portalInsideBoundingBox) { - cancelTeleportFor(player) - } - } - - private fun cancelTeleportFor(entity: Entity) { - - } + //fun onPlayerMove(e: PlayerMoveEvent) { + //val player = e.player + //val oldLocation = e.from + //val portal = portals.isLocationInPortalChamber(oldLocation) ?: return + //val newLocation = e.to ?: return + //if (oldLocation.world != newLocation.world || oldLocation.toVector() !in portal.portalInsideBoundingBox) { + // TODO: cancelTeleportFor(player) + //} + //} fun onDestroyedBlock(block: Block) { if (block.type !in PortalFrame.State.ACTIVE.allValidBlocks) { diff --git a/src/main/kotlin/net/deliciousreya/minecraftportal/extensions/Material.kt b/src/main/kotlin/net/deliciousreya/minecraftportal/extensions/Material.kt index 8687744..f8f7f25 100644 --- a/src/main/kotlin/net/deliciousreya/minecraftportal/extensions/Material.kt +++ b/src/main/kotlin/net/deliciousreya/minecraftportal/extensions/Material.kt @@ -6,6 +6,44 @@ import net.deliciousreya.minecraftportal.proto.PortalSaveDataProtos import org.bukkit.Material import java.lang.IllegalStateException +val COLOR_NAME_MAPPING: ImmutableBiMap = ImmutableBiMap.builder() + .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 = ImmutableBiMap.builder() + .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 = ImmutableBiMap.builder() .put(Material.COAL_BLOCK, PortalSaveDataProtos.Portal.Mineral.COAL) .put(Material.REDSTONE_BLOCK, PortalSaveDataProtos.Portal.Mineral.REDSTONE) @@ -18,9 +56,17 @@ val MINERAL_MAPPING: ImmutableBiMap): Portal { - val portalType = portalTypes[mineral.toMaterial()] ?: throw IllegalArgumentException("No portal type for $mineral") - val result = Portal(PortalFrame(lowerLeftFrontCorner.toLocation(server), exitDirection.toDirection()), portalType) - return result +fun PortalSaveDataProtos.Portal.Mineral.asColor(): PortalSaveDataProtos.Portal.Color { + if (this == PortalSaveDataProtos.Portal.Mineral.UNKNOWN_MINERAL) { + throw IllegalArgumentException("No portal color for $this") + } + 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>): 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) { @@ -41,6 +51,7 @@ class Portal(val frame: PortalFrame, val type: PortalType) { .setLowerLeftFrontCorner(frame.lowerLeftFrontCorner.toProto()) .setExitDirection(frame.direction.toProto()) .setMineral(frame.mineral.toMineralProto()) + .setColor(frame.color.toColorProto()) .build() } } \ No newline at end of file diff --git a/src/main/kotlin/net/deliciousreya/minecraftportal/model/PortalDataStore.kt b/src/main/kotlin/net/deliciousreya/minecraftportal/model/PortalDataStore.kt index 659fc0f..bf02a9f 100644 --- a/src/main/kotlin/net/deliciousreya/minecraftportal/model/PortalDataStore.kt +++ b/src/main/kotlin/net/deliciousreya/minecraftportal/model/PortalDataStore.kt @@ -1,8 +1,12 @@ package net.deliciousreya.minecraftportal.model +import com.google.common.collect.ImmutableList import com.google.common.collect.ImmutableMap import com.google.protobuf.InvalidProtocolBufferException +import net.deliciousreya.minecraftportal.extensions.COLOR_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 org.bukkit.Location import org.bukkit.Material @@ -16,17 +20,27 @@ import java.util.logging.Logger class PortalDataStore (){ var saveDataTo: File? = null var useBackup: File? = null - val portalTypes: ImmutableMap + private val userColors: MutableMap = mutableMapOf() + private val portalTypes: ImmutableMap> + private val allPortals: ImmutableList init { - val portalTypesBuilder = ImmutableMap.builder() + val allPortalsBuilder = ImmutableList.builder() + val portalTypesBuilder = ImmutableMap.builder>() for (mineralType in MINERAL_MAPPING.keys) { - portalTypesBuilder.put(mineralType, PortalType(mineralType)) + val colors = ImmutableMap.Builder() + 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() + allPortals = allPortalsBuilder.build() } fun isLocationInPortalOrChamber(location: Location): PortalFrame? { - for (type in this.portalTypes.values) { + for (type in this.allPortals) { if (type.isEmpty) { continue } @@ -39,7 +53,7 @@ class PortalDataStore (){ } fun isLocationInPortalChamber(location: Location): PortalFrame? { - for (type in this.portalTypes.values) { + for (type in this.allPortals) { if (type.isEmpty) { continue } @@ -90,7 +104,7 @@ class PortalDataStore (){ } fun validateWorldOnStartup(logger: Logger) { - for (portalType in this.portalTypes.values) { + for (portalType in this.allPortals) { val oldPortal = portalType.oldestActivePortal val newPortal = portalType.newestActivePortal if (newPortal != null && !validatePortal(newPortal)) { @@ -106,11 +120,11 @@ class PortalDataStore (){ } 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) { - for (portalType in this.portalTypes.values) { + for (portalType in this.allPortals) { startEffectsFor(portalType, plugin) } } @@ -174,7 +188,7 @@ class PortalDataStore (){ } 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. */ @@ -185,7 +199,7 @@ class PortalDataStore (){ /** Forgets all the data without actually affecting the world. */ fun clear() { - for (portalType in this.portalTypes.values) { + for (portalType in this.allPortals) { portalType.oldestActivePortal?.stopEffects() portalType.newestActivePortal?.stopEffects() portalType.clear() @@ -206,11 +220,14 @@ class PortalDataStore (){ } olderPortal.type.loadPairedPortals(olderPortal, newerPortal) } + for (userData in proto.userDataList) { + userColors[userData.name] = userData.color.toMaterial() + } } fun toProto(): PortalSaveDataProtos.PortalSaveData { val builder = PortalSaveDataProtos.PortalSaveData.newBuilder() - for (portalType in this.portalTypes.values) { + for (portalType in this.allPortals) { when { portalType.isEmpty -> { // 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() } @@ -233,4 +253,19 @@ class PortalDataStore (){ fun stopTeleporting(portal: PortalFrame) { 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() + } } \ No newline at end of file diff --git a/src/main/kotlin/net/deliciousreya/minecraftportal/model/PortalFrame.kt b/src/main/kotlin/net/deliciousreya/minecraftportal/model/PortalFrame.kt index 16b1faa..c03373c 100644 --- a/src/main/kotlin/net/deliciousreya/minecraftportal/model/PortalFrame.kt +++ b/src/main/kotlin/net/deliciousreya/minecraftportal/model/PortalFrame.kt @@ -33,11 +33,11 @@ val MINERAL_TYPES: ImmutableMap = ImmutableMap.Builder = 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? { - when { - block.type in state.glassBlocks -> for (direction in PortalFrame.ExitDirection.values()) { - for (vector in direction.glassOffsets) { + for (blockSet in state.blockSets) { + for (direction in PortalFrame.ExitDirection.values()) { + for (offset in blockSet.offsets(direction)) { val scanResult = checkPortalFrameAt( - block.location.subtract(vector), + block.location.subtract(offset), direction, 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 } @@ -78,6 +56,10 @@ fun checkPortalFrameAt(location:Location, direction: PortalFrame.ExitDirection, if (mineral.type !in state.mineralBlocks) { return null } + val color = (location + direction.colorOffset).block + if (color.type !in state.colorBlocks) { + return null + } for (vector in direction.glassOffsets) { val block = (location + vector).block if (block.type !in state.glassBlocks) { @@ -105,13 +87,20 @@ fun PortalSaveDataProtos.Portal.Direction.toDirection(): PortalFrame.ExitDirecti /** Information about a portal frame. */ data class PortalFrame(val lowerLeftFrontCorner: Location, val direction: ExitDirection) { - enum class State(val glassBlocks: ImmutableSet, val doorBlocks: ImmutableSet, val mineralBlocks: ImmutableSet) { - ACTIVE(ImmutableSet.copyOf(MINERAL_TYPES.values), + enum class State(val glassBlocks: ImmutableSet, val colorBlocks: ImmutableSet, val doorBlocks: ImmutableSet, val mineralBlocks: ImmutableSet) { + ACTIVE(ImmutableSet.copyOf(MINERAL_TYPES.values), ImmutableSet.copyOf(COLOR_MAPPING.keys), DOOR_TYPES, ImmutableSet.copyOf(MINERAL_TYPES.keys)), - INACTIVE(ImmutableSet.of(GLASS), + INACTIVE(ImmutableSet.of(GLASS), ImmutableSet.builder().addAll(COLOR_MAPPING.keys).add(GLASS).build(), DOOR_TYPES, ImmutableSet.copyOf(MINERAL_TYPES.keys)); - val allValidBlocks:ImmutableSet = ImmutableSet.Builder().addAll(glassBlocks).addAll(doorBlocks).addAll(mineralBlocks).build() + val allValidBlocks:ImmutableSet = ImmutableSet.Builder().addAll(glassBlocks).addAll(doorBlocks).addAll(mineralBlocks).addAll(colorBlocks).build() + data class BlockSet(val blockTypes: Set, val offsets: (direction: ExitDirection) -> List) + 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. */ 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 UP, UP * 2, - // top front wall - UP * 3 + toRight, // right front wall UP + toRight * 2, UP * 2 + toRight * 2, @@ -164,10 +151,11 @@ data class PortalFrame(val lowerLeftFrontCorner: Location, val direction: ExitDi ) val mineralOffset: Vector = toRight + val colorOffset: Vector = UP * 3 + toRight val doorOffsets: ImmutableList = ImmutableList.of( - Vector(0, 1, 0) + toRight, - Vector(0, 2, 0) + toRight + UP + toRight, + UP * 2 + toRight ) 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 midCenter = portalCenter + MID_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 + var color: Material + get() = (lowerLeftFrontCorner + direction.colorOffset).block.type + set(newColor) { + (lowerLeftFrontCorner + direction.colorOffset).block.type = newColor + } fun open() { val block = portalCenter.block diff --git a/src/main/kotlin/net/deliciousreya/minecraftportal/model/PortalType.kt b/src/main/kotlin/net/deliciousreya/minecraftportal/model/PortalType.kt index b581443..c8564fb 100644 --- a/src/main/kotlin/net/deliciousreya/minecraftportal/model/PortalType.kt +++ b/src/main/kotlin/net/deliciousreya/minecraftportal/model/PortalType.kt @@ -4,10 +4,9 @@ import net.deliciousreya.minecraftportal.proto.PortalSaveDataProtos import org.bukkit.Location import org.bukkit.Material import org.bukkit.plugin.Plugin -import java.lang.IllegalArgumentException import java.lang.IllegalStateException -class PortalType(val mineral: Material) { +class PortalType(val mineral: Material, val color: Material) { var oldestActivePortal: Portal? = null var newestActivePortal: Portal? = null @@ -31,7 +30,7 @@ class PortalType(val mineral: Material) { fun addOrReplacePortal(portal: Portal): Portal? { 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 { this.isEmpty -> { @@ -54,23 +53,23 @@ class PortalType(val mineral: Material) { fun loadUnpairedPortal(portal: Portal) { 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) { - 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 } fun loadPairedPortals(olderPortal: Portal, newerPortal: Portal) { 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) { - 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) { - 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.newestActivePortal = newerPortal @@ -95,7 +94,7 @@ class PortalType(val mineral: Material) { } override fun toString():String { - return "PortalType{mineral=$mineral, oldestActivePortal=$oldestActivePortal, newestActivePortal=$newestActivePortal}" + return "PortalType{mineral=$mineral, color=$color, oldestActivePortal=$oldestActivePortal, newestActivePortal=$newestActivePortal}" } /** diff --git a/src/main/proto/portal-save-data.proto b/src/main/proto/portal-save-data.proto index e7f1c01..075c928 100644 --- a/src/main/proto/portal-save-data.proto +++ b/src/main/proto/portal-save-data.proto @@ -31,9 +31,29 @@ message Portal { IRON = 7; 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; Direction exit_direction = 2; Mineral mineral = 3; + Color color = 4; } message PortalPair { @@ -41,7 +61,13 @@ message PortalPair { Portal newer = 2; } +message UserData { + string name = 1; + Portal.Color color = 2; +} + message PortalSaveData { repeated PortalPair paired_portals = 1; repeated Portal unpaired_portals = 2; + repeated UserData user_data = 3; } \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index d08f7fc..6484872 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -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]"