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