parent
289db444d0
commit
cc17c0da71
@ -0,0 +1,26 @@ |
||||
package net.deliciousreya.minecraftportal.extensions |
||||
|
||||
import com.google.common.collect.ImmutableBiMap |
||||
import net.deliciousreya.minecraftportal.model.DeserializationException |
||||
import net.deliciousreya.minecraftportal.proto.PortalSaveDataProtos |
||||
import org.bukkit.Material |
||||
import java.lang.IllegalStateException |
||||
|
||||
val MINERAL_MAPPING: ImmutableBiMap<Material, PortalSaveDataProtos.Portal.Mineral> = ImmutableBiMap.builder<Material, PortalSaveDataProtos.Portal.Mineral>() |
||||
.put(Material.COAL_BLOCK, PortalSaveDataProtos.Portal.Mineral.COAL) |
||||
.put(Material.REDSTONE_BLOCK, PortalSaveDataProtos.Portal.Mineral.REDSTONE) |
||||
.put(Material.LAPIS_BLOCK, PortalSaveDataProtos.Portal.Mineral.LAPIS) |
||||
.put(Material.GOLD_BLOCK, PortalSaveDataProtos.Portal.Mineral.GOLD) |
||||
.put(Material.DIAMOND_BLOCK, PortalSaveDataProtos.Portal.Mineral.DIAMOND) |
||||
.put(Material.EMERALD_BLOCK, PortalSaveDataProtos.Portal.Mineral.EMERALD) |
||||
.put(Material.IRON_BLOCK, PortalSaveDataProtos.Portal.Mineral.IRON) |
||||
.put(Material.QUARTZ_BLOCK, PortalSaveDataProtos.Portal.Mineral.QUARTZ) |
||||
.build() |
||||
|
||||
fun Material.toMineralProto(): PortalSaveDataProtos.Portal.Mineral { |
||||
return MINERAL_MAPPING[this] ?: throw DeserializationException("Not a mineral: ${this}") |
||||
} |
||||
|
||||
fun PortalSaveDataProtos.Portal.Mineral.toMaterial(): Material { |
||||
return MINERAL_MAPPING.inverse()[this] ?: throw DeserializationException("Not a material: ${this}") |
||||
} |
@ -0,0 +1,5 @@ |
||||
package net.deliciousreya.minecraftportal.model |
||||
|
||||
import java.lang.Exception |
||||
|
||||
class DeserializationException (message: String? = null, cause: Throwable? = null) : Exception(message, cause) |
@ -0,0 +1,27 @@ |
||||
package net.deliciousreya.minecraftportal.model |
||||
|
||||
import net.deliciousreya.minecraftportal.extensions.toLocation |
||||
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 org.bukkit.Material |
||||
import org.bukkit.Server |
||||
import java.lang.IllegalArgumentException |
||||
|
||||
fun PortalSaveDataProtos.Portal.toPortal(server: Server, portalTypes: Map<Material, PortalType>): Portal { |
||||
val portalType = portalTypes[mineral.toMaterial()] ?: throw IllegalArgumentException("No portal type for $mineral") |
||||
val result = Portal(PortalFrame(lowerLeftFrontCorner.toLocation(server), entranceDirection.toDirection()), portalType) |
||||
// TODO: assert that the saved portal and mineral match the actual state of the world |
||||
return result |
||||
} |
||||
|
||||
class Portal(val frame: PortalFrame, val type: PortalType) { |
||||
fun toProto(): PortalSaveDataProtos.Portal { |
||||
return PortalSaveDataProtos.Portal.newBuilder() |
||||
.setLowerLeftFrontCorner(frame.lowerLeftFrontCorner.toProto()) |
||||
.setEntranceDirection(frame.direction.toProto()) |
||||
.setMineral(frame.mineral.toMineralProto()) |
||||
.build() |
||||
} |
||||
} |
@ -0,0 +1,82 @@ |
||||
package net.deliciousreya.minecraftportal.model |
||||
|
||||
import com.google.common.collect.ImmutableMap |
||||
import net.deliciousreya.minecraftportal.extensions.MINERAL_MAPPING |
||||
import net.deliciousreya.minecraftportal.proto.PortalSaveDataProtos |
||||
import org.bukkit.Material |
||||
import org.bukkit.Server |
||||
import java.io.File |
||||
import java.lang.IllegalArgumentException |
||||
|
||||
class PortalDataStore() { |
||||
val portalTypes: ImmutableMap<Material, PortalType> |
||||
init { |
||||
val portalTypesBuilder = ImmutableMap.builder<Material, PortalType>() |
||||
for (mineralType in MINERAL_MAPPING.keys) { |
||||
portalTypesBuilder.put(mineralType, PortalType(mineralType)) |
||||
} |
||||
portalTypes = portalTypesBuilder.build() |
||||
} |
||||
|
||||
fun onAfterChanged() { |
||||
// Does nothing for now. |
||||
// TODO: Save the data. |
||||
} |
||||
|
||||
/** Marks the new portal as active, and removes the one that needs to be deactivated, if any. */ |
||||
fun activateAndReplacePortal(frame: PortalFrame): PortalFrame? { |
||||
val type = portalTypes[frame.mineral] ?: throw IllegalArgumentException("Can't create a portal of type ${frame.mineral}") |
||||
val result = type.addOrReplacePortal(Portal(frame, type))?.frame |
||||
onAfterChanged() |
||||
return result |
||||
} |
||||
|
||||
/** Deactivates the given portal. */ |
||||
fun deactivatePortal(frame: PortalFrame): Boolean { |
||||
val type = portalTypes[frame.mineral] ?: throw IllegalArgumentException("There are no portals of type ${frame.mineral}") |
||||
val result = type.removePortalWithFrame(frame) |
||||
onAfterChanged() |
||||
return result |
||||
} |
||||
|
||||
/** Forgets all the data without actually affecting the world. */ |
||||
fun clear() { |
||||
for (portalType in this.portalTypes.values) { |
||||
portalType.clear() |
||||
} |
||||
} |
||||
|
||||
fun loadFromProto(server: Server, proto: PortalSaveDataProtos.PortalSaveData) { |
||||
clear() |
||||
for (portalProto in proto.unpairedPortalsList) { |
||||
val portal = portalProto.toPortal(server, portalTypes) |
||||
portal.type.loadUnpairedPortal(portal) |
||||
} |
||||
for (portalPair in proto.pairedPortalsList) { |
||||
val olderPortal = portalPair.older.toPortal(server, portalTypes) |
||||
val newerPortal = portalPair.newer.toPortal(server, portalTypes) |
||||
if (olderPortal.type != newerPortal.type) { |
||||
throw DeserializationException("Pair had non-matching types: ${olderPortal.type} and ${newerPortal.type}") |
||||
} |
||||
olderPortal.type.loadPairedPortals(olderPortal, newerPortal) |
||||
} |
||||
} |
||||
|
||||
fun toProto(): PortalSaveDataProtos.PortalSaveData { |
||||
val builder = PortalSaveDataProtos.PortalSaveData.newBuilder() |
||||
for (portalType in this.portalTypes.values) { |
||||
when { |
||||
portalType.isEmpty -> { |
||||
// Nothing here to save. Just skip it. |
||||
} |
||||
portalType.isPaired -> { |
||||
builder.addPairedPortals(portalType.toProto()) |
||||
} |
||||
else -> { |
||||
builder.addUnpairedPortals(portalType.getOnlyPortal.toProto()) |
||||
} |
||||
} |
||||
} |
||||
return builder.build() |
||||
} |
||||
} |
@ -0,0 +1,89 @@ |
||||
package net.deliciousreya.minecraftportal.model |
||||
|
||||
import net.deliciousreya.minecraftportal.proto.PortalSaveDataProtos |
||||
import org.bukkit.Material |
||||
import java.lang.IllegalArgumentException |
||||
import java.lang.IllegalStateException |
||||
|
||||
class PortalType(val mineral: Material) { |
||||
var oldestActivePortal: Portal? = null |
||||
var newestActivePortal: Portal? = null |
||||
|
||||
val isEmpty: Boolean get() = oldestActivePortal == null && newestActivePortal == null |
||||
val isPaired: Boolean get() = oldestActivePortal != null && newestActivePortal != null |
||||
|
||||
val getOnlyPortal: Portal get() = if (!isEmpty && !isPaired) oldestActivePortal!! else throw IllegalStateException("Can't getOnlyPortal for empty or paired portal type $this") |
||||
|
||||
fun toProto(): PortalSaveDataProtos.PortalPair { |
||||
val builder = PortalSaveDataProtos.PortalPair.newBuilder() |
||||
val oldestPortal = oldestActivePortal |
||||
val newestPortal = newestActivePortal |
||||
if (oldestPortal != null) { |
||||
builder.older = oldestPortal.toProto() |
||||
} |
||||
if (newestPortal != null) { |
||||
builder.newer = newestPortal.toProto() |
||||
} |
||||
return builder.build() |
||||
} |
||||
|
||||
fun addOrReplacePortal(portal: Portal): Portal? { |
||||
if (portal.type != this) { |
||||
throw DeserializationException("Tried to add $portal which didn't belong to ${this}") |
||||
} |
||||
return when { |
||||
this.isEmpty -> { |
||||
this.oldestActivePortal = portal |
||||
null |
||||
} |
||||
else -> { |
||||
val replacedPortal = newestActivePortal |
||||
this.newestActivePortal = portal |
||||
replacedPortal |
||||
} |
||||
} |
||||
} |
||||
|
||||
fun loadUnpairedPortal(portal: Portal) { |
||||
if (!this.isEmpty) { |
||||
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}") |
||||
} |
||||
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") |
||||
} |
||||
if (olderPortal.type != 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}") |
||||
} |
||||
this.oldestActivePortal = olderPortal |
||||
this.newestActivePortal = newerPortal |
||||
} |
||||
|
||||
fun clear() { |
||||
oldestActivePortal = null |
||||
newestActivePortal = null |
||||
} |
||||
|
||||
override fun toString():String { |
||||
return "PortalType{mineral=$mineral, oldestActivePortal=$oldestActivePortal, newestActivePortal=$newestActivePortal}" |
||||
} |
||||
|
||||
fun removePortalWithFrame(frame: PortalFrame):Boolean { |
||||
if (oldestActivePortal?.frame == frame) { |
||||
oldestActivePortal = newestActivePortal |
||||
} else if (newestActivePortal?.frame != frame) { |
||||
return false |
||||
} |
||||
newestActivePortal = null |
||||
return true |
||||
} |
||||
} |
@ -0,0 +1,5 @@ |
||||
package net.deliciousreya.minecraftportal.model |
||||
|
||||
import java.lang.Exception |
||||
|
||||
class SerializationException (message: String? = null, cause: Throwable? = null) : Exception(message, cause) |
@ -0,0 +1,47 @@ |
||||
syntax = "proto3"; |
||||
|
||||
package net.deliciousreya.minecraftportal; |
||||
|
||||
option java_package = "net.deliciousreya.minecraftportal.proto"; |
||||
option java_outer_classname = "PortalSaveDataProtos"; |
||||
|
||||
message Location { |
||||
string world_uuid = 1; |
||||
int32 x = 2; |
||||
int32 y = 3; |
||||
int32 z = 4; |
||||
} |
||||
|
||||
message Portal { |
||||
enum Direction { |
||||
UNKNOWN_DIRECTION = 0; |
||||
NORTH = 1; |
||||
EAST = 2; |
||||
WEST = 3; |
||||
SOUTH = 4; |
||||
} |
||||
enum Mineral { |
||||
UNKNOWN_MINERAL = 0; |
||||
COAL = 1; |
||||
REDSTONE = 2; |
||||
LAPIS = 3; |
||||
GOLD = 4; |
||||
DIAMOND = 5; |
||||
EMERALD = 6; |
||||
IRON = 7; |
||||
QUARTZ = 8; |
||||
} |
||||
Location lower_left_front_corner = 1; |
||||
Direction entrance_direction = 2; |
||||
Mineral mineral = 3; |
||||
} |
||||
|
||||
message PortalPair { |
||||
Portal older = 1; |
||||
Portal newer = 2; |
||||
} |
||||
|
||||
message PortalSaveData { |
||||
repeated PortalPair paired_portals = 1; |
||||
repeated Portal unpaired_portals = 2; |
||||
} |
Loading…
Reference in new issue