Synchronized maps, update save keys, exosuit inventory upgrades as items
This commit is contained in:
parent
2915ef675b
commit
e7653d559f
@ -56,10 +56,17 @@ private fun misc(provider: MatteryLanguageProvider) {
|
|||||||
|
|
||||||
gui("exosuit.already_activated", "You already have exosuit following you")
|
gui("exosuit.already_activated", "You already have exosuit following you")
|
||||||
|
|
||||||
|
gui("exosuit_upgrades.no_exosuit", "This piece of technology seems to be of no use to you.... Or is it?!")
|
||||||
|
|
||||||
|
gui("exosuit_upgrades.already_activated", "Upgrade is already active!")
|
||||||
|
gui("exosuit_upgrades.slots_upgrade", "Using this will permanently grant %s slots in ExoSuit inventory.")
|
||||||
|
|
||||||
gui("power_supplier.active_nodes", "Currently demanding nodes: %s")
|
gui("power_supplier.active_nodes", "Currently demanding nodes: %s")
|
||||||
|
|
||||||
misc("battery.single_use", "Single use battery, can not be recharged.")
|
misc("battery.single_use", "Single use battery, can not be recharged.")
|
||||||
|
|
||||||
|
misc("exosuit_upgrades.slots_upgraded", "Your exosuit has permanently gained %s slots")
|
||||||
|
|
||||||
misc("exosuit.granted1", "As you keep pressing fingerprint reader, you are getting hurt in finger.")
|
misc("exosuit.granted1", "As you keep pressing fingerprint reader, you are getting hurt in finger.")
|
||||||
misc("exosuit.granted2", "After you raise your finger, fingerprint reader glows very bright.")
|
misc("exosuit.granted2", "After you raise your finger, fingerprint reader glows very bright.")
|
||||||
misc("exosuit.granted3", "Then, fingerprint reader fades, leaving faint trace not of your finger, but of your very soul.")
|
misc("exosuit.granted3", "Then, fingerprint reader fades, leaving faint trace not of your finger, but of your very soul.")
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package ru.dbotthepony.mc.otm.capability
|
package ru.dbotthepony.mc.otm.capability
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2IntAVLTreeMap
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectArraySet
|
import it.unimi.dsi.fastutil.objects.ObjectArraySet
|
||||||
import net.minecraft.ChatFormatting
|
import net.minecraft.ChatFormatting
|
||||||
import net.minecraft.core.Direction
|
import net.minecraft.core.Direction
|
||||||
@ -64,6 +65,26 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
|
|
||||||
var hasExoSuit by synchronizer.bool()
|
var hasExoSuit by synchronizer.bool()
|
||||||
|
|
||||||
|
private val exoSuitSlotCountModifiersMap: MutableMap<UUID, Int> by synchronizer.Map(
|
||||||
|
keyCodec = UUIDValueCodec,
|
||||||
|
valueCodec = IntValueCodec,
|
||||||
|
backingMap = Object2IntAVLTreeMap(),
|
||||||
|
callback = {
|
||||||
|
this.exoSuitSlotCountModifiers.recompute()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
val exoSuitSlotCountModifiers = UUIDIntModifiersMap(observer = observer@{
|
||||||
|
if (ply !is ServerPlayer)
|
||||||
|
return@observer
|
||||||
|
|
||||||
|
if (it < 0) {
|
||||||
|
exoSuitSlotCount = 0
|
||||||
|
} else {
|
||||||
|
exoSuitSlotCount = it
|
||||||
|
}
|
||||||
|
}, backingMap = this.exoSuitSlotCountModifiersMap)
|
||||||
|
|
||||||
var exoSuitSlotCount by synchronizer.int(setter = setter@{ value, access, _ ->
|
var exoSuitSlotCount by synchronizer.int(setter = setter@{ value, access, _ ->
|
||||||
require(value >= 0) { "Invalid slot count $value" }
|
require(value >= 0) { "Invalid slot count $value" }
|
||||||
|
|
||||||
@ -334,37 +355,11 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
override fun serializeNBT(): CompoundTag {
|
override fun serializeNBT(): CompoundTag {
|
||||||
val tag = CompoundTag()
|
val tag = CompoundTag()
|
||||||
|
|
||||||
tag["androidEnergy"] = androidEnergy.serializeNBT()
|
// iteration
|
||||||
|
|
||||||
val featureList = ListTag()
|
|
||||||
|
|
||||||
for (feature in features.values) {
|
|
||||||
val featureNbt = feature.serializeNBT()
|
|
||||||
|
|
||||||
featureNbt["id"] = feature.type.registryName!!.toString()
|
|
||||||
featureList.add(featureNbt)
|
|
||||||
}
|
|
||||||
|
|
||||||
tag["features"] = featureList
|
|
||||||
|
|
||||||
tag["is_android"] = isAndroid
|
|
||||||
tag["will_become_android"] = willBecomeAndroid
|
|
||||||
|
|
||||||
val list = ListTag()
|
|
||||||
|
|
||||||
for ((type, instance) in research) {
|
|
||||||
val researchTag = instance.serializeNBT()
|
|
||||||
|
|
||||||
researchTag["id"] = type.registryName!!.toString()
|
|
||||||
list.add(researchTag)
|
|
||||||
}
|
|
||||||
|
|
||||||
tag["research"] = list
|
|
||||||
|
|
||||||
tag["iteration"] = iteration
|
tag["iteration"] = iteration
|
||||||
tag["should_send_iteration"] = shouldSendIteration
|
tag["shouldSendIteration"] = shouldSendIteration
|
||||||
|
|
||||||
tag["death_log"] = ListTag().also {
|
tag["deathLog"] = ListTag().also {
|
||||||
for ((ticks, component) in deathLog) {
|
for ((ticks, component) in deathLog) {
|
||||||
it.add(CompoundTag().also {
|
it.add(CompoundTag().also {
|
||||||
it["ticks"] = ticks
|
it["ticks"] = ticks
|
||||||
@ -373,21 +368,47 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tag["exo_suit_slot_count"] = exoSuitSlotCount
|
// exosuit
|
||||||
tag["has_exo_suit"] = hasExoSuit
|
tag["hasExoSuit"] = hasExoSuit
|
||||||
tag["exo_suit_inventory"] = exoSuitContainer.serializeNBT()
|
tag["exoSuitContainer"] = exoSuitContainer.serializeNBT()
|
||||||
tag["exo_suit_crafting_upgraded"] = isExoSuitCraftingUpgraded
|
tag["isExoSuitCraftingUpgraded"] = isExoSuitCraftingUpgraded
|
||||||
|
tag["exoSuitSlotCountModifiers"] = exoSuitSlotCountModifiers.serializeNBT()
|
||||||
|
|
||||||
|
// android
|
||||||
|
tag["androidEnergy"] = androidEnergy.serializeNBT()
|
||||||
|
|
||||||
|
tag["isAndroid"] = isAndroid
|
||||||
|
tag["willBecomeAndroid"] = willBecomeAndroid
|
||||||
|
|
||||||
|
val featureList = ListTag()
|
||||||
|
val researchList = ListTag()
|
||||||
|
|
||||||
|
for (feature in features.values) {
|
||||||
|
featureList.add(feature.serializeNBT().also {
|
||||||
|
it["id"] = feature.type.registryName!!.toString()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
for ((type, instance) in research) {
|
||||||
|
researchList.add(instance.serializeNBT().also {
|
||||||
|
it["id"] = type.registryName!!.toString()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
tag["features"] = featureList
|
||||||
|
tag["research"] = researchList
|
||||||
|
|
||||||
return tag
|
return tag
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun deserializeNBT(tag: CompoundTag) {
|
override fun deserializeNBT(tag: CompoundTag) {
|
||||||
|
// iterations
|
||||||
iteration = tag.getInt("iteration")
|
iteration = tag.getInt("iteration")
|
||||||
shouldSendIteration = tag.getBoolean("should_send_iteration")
|
shouldSendIteration = tag.getBoolean("shouldSendIteration")
|
||||||
|
|
||||||
deathLog.clear()
|
deathLog.clear()
|
||||||
|
|
||||||
for (value in tag.getCompoundList("death_log")) {
|
for (value in tag.getCompoundList("deathLog")) {
|
||||||
val component = Component.Serializer.fromJson(value.getString("component"))
|
val component = Component.Serializer.fromJson(value.getString("component"))
|
||||||
|
|
||||||
if (component != null) {
|
if (component != null) {
|
||||||
@ -395,9 +416,21 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// exosuit
|
||||||
|
hasExoSuit = tag.getBoolean("hasExoSuit")
|
||||||
|
exoSuitContainer.deserializeNBT(tag["exoSuitContainer"])
|
||||||
|
isExoSuitCraftingUpgraded = tag.getBoolean("isExoSuitCraftingUpgraded")
|
||||||
|
|
||||||
|
tag.map("exoSuitSlotCountModifiers", exoSuitSlotCountModifiers::deserializeNBT)
|
||||||
|
|
||||||
|
// android
|
||||||
|
isAndroid = tag.getBoolean("isAndroid")
|
||||||
|
willBecomeAndroid = tag.getBoolean("willBecomeAndroid")
|
||||||
|
|
||||||
tag.map("androidEnergy", androidEnergy::deserializeNBT)
|
tag.map("androidEnergy", androidEnergy::deserializeNBT)
|
||||||
|
|
||||||
features.clear()
|
features.clear()
|
||||||
|
research.clear()
|
||||||
|
|
||||||
for (featureTag in tag.getCompoundList("features")) {
|
for (featureTag in tag.getCompoundList("features")) {
|
||||||
val feature = MRegistry.ANDROID_FEATURES.getValue(ResourceLocation(featureTag.getString("id")))
|
val feature = MRegistry.ANDROID_FEATURES.getValue(ResourceLocation(featureTag.getString("id")))
|
||||||
@ -414,10 +447,6 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isAndroid = tag.getBoolean("is_android")
|
|
||||||
willBecomeAndroid = tag.getBoolean("will_become_android")
|
|
||||||
research.clear()
|
|
||||||
|
|
||||||
for (researchTag in tag.getCompoundList("research")) {
|
for (researchTag in tag.getCompoundList("research")) {
|
||||||
val research = MRegistry.ANDROID_RESEARCH.getValue(ResourceLocation(researchTag.getString("id")))
|
val research = MRegistry.ANDROID_RESEARCH.getValue(ResourceLocation(researchTag.getString("id")))
|
||||||
|
|
||||||
@ -427,11 +456,6 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
this.research[research] = instance
|
this.research[research] = instance
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hasExoSuit = tag.getBoolean("has_exo_suit")
|
|
||||||
exoSuitSlotCount = tag.getInt("exo_suit_slot_count")
|
|
||||||
exoSuitContainer.deserializeNBT(tag["exo_suit_inventory"])
|
|
||||||
isExoSuitCraftingUpgraded = tag.getBoolean("exo_suit_crafting_upgraded")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun dropBattery() {
|
fun dropBattery() {
|
||||||
|
@ -0,0 +1,96 @@
|
|||||||
|
package ru.dbotthepony.mc.otm.capability
|
||||||
|
|
||||||
|
import net.minecraft.nbt.CompoundTag
|
||||||
|
import net.minecraft.nbt.ListTag
|
||||||
|
import net.minecraft.nbt.Tag
|
||||||
|
import net.minecraftforge.common.util.INBTSerializable
|
||||||
|
import ru.dbotthepony.mc.otm.core.contains
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
class UUIDIntModifiersMap(private val observer: (Int) -> Unit, private val backingMap: MutableMap<UUID, Int> = HashMap()) : INBTSerializable<ListTag> {
|
||||||
|
var value: Int = 0
|
||||||
|
private set
|
||||||
|
|
||||||
|
fun recompute() {
|
||||||
|
var value = 0
|
||||||
|
|
||||||
|
for (mapValue in backingMap.values) {
|
||||||
|
value += mapValue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.value != value) {
|
||||||
|
this.value = value
|
||||||
|
observer.invoke(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun set(key: UUID, value: Int): Boolean {
|
||||||
|
val old = backingMap.put(key, value)
|
||||||
|
|
||||||
|
if (old == value) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
this.value += value - (old ?: 0)
|
||||||
|
observer.invoke(this.value)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun get(key: UUID): Int? {
|
||||||
|
return backingMap[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun contains(key: UUID): Boolean {
|
||||||
|
return backingMap.containsKey(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun remove(key: UUID): Boolean {
|
||||||
|
if (!backingMap.containsKey(key)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
val old = backingMap.remove(key) ?: return true
|
||||||
|
value -= old
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clear() {
|
||||||
|
backingMap.clear()
|
||||||
|
val old = this.value
|
||||||
|
this.value = 0
|
||||||
|
if (old != this.value) {
|
||||||
|
observer.invoke(this.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun serializeNBT(): ListTag {
|
||||||
|
return ListTag().also {
|
||||||
|
for ((key, value) in backingMap) {
|
||||||
|
it.add(CompoundTag().also {
|
||||||
|
it.putUUID("key", key)
|
||||||
|
it.putInt("value", value)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun deserializeNBT(nbt: ListTag) {
|
||||||
|
backingMap.clear()
|
||||||
|
val old = this.value
|
||||||
|
this.value = 0
|
||||||
|
|
||||||
|
for (value in nbt) {
|
||||||
|
value as CompoundTag
|
||||||
|
|
||||||
|
if (value.contains("key", "value")) {
|
||||||
|
val int = value.getInt("value")
|
||||||
|
backingMap.put(value.getUUID("key"), int)
|
||||||
|
this.value += int
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (old != this.value) {
|
||||||
|
observer.invoke(this.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,96 @@
|
|||||||
|
package ru.dbotthepony.mc.otm.item
|
||||||
|
|
||||||
|
import net.minecraft.ChatFormatting
|
||||||
|
import net.minecraft.network.chat.Component
|
||||||
|
import net.minecraft.server.level.ServerPlayer
|
||||||
|
import net.minecraft.world.InteractionHand
|
||||||
|
import net.minecraft.world.InteractionResultHolder
|
||||||
|
import net.minecraft.world.entity.LivingEntity
|
||||||
|
import net.minecraft.world.entity.player.Player
|
||||||
|
import net.minecraft.world.item.Item
|
||||||
|
import net.minecraft.world.item.ItemStack
|
||||||
|
import net.minecraft.world.item.Rarity
|
||||||
|
import net.minecraft.world.item.TooltipFlag
|
||||||
|
import net.minecraft.world.item.UseAnim
|
||||||
|
import net.minecraft.world.level.Level
|
||||||
|
import ru.dbotthepony.mc.otm.OverdriveThatMatters
|
||||||
|
import ru.dbotthepony.mc.otm.capability.matteryPlayer
|
||||||
|
import ru.dbotthepony.mc.otm.client.minecraft
|
||||||
|
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||||
|
import ru.dbotthepony.mc.otm.runIfClient
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
class ExoSuitSlotUpgradeItem(
|
||||||
|
val id: UUID?,
|
||||||
|
val slotCount: Int,
|
||||||
|
properties: Properties = Properties().stacksTo(64).rarity(Rarity.UNCOMMON).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB)
|
||||||
|
) : Item(properties) {
|
||||||
|
val isCreative: Boolean get() = id == null
|
||||||
|
|
||||||
|
override fun getUseDuration(p_41454_: ItemStack): Int {
|
||||||
|
return 30
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun appendHoverText(p_41421_: ItemStack, p_41422_: Level?, tooltip: MutableList<Component>, p_41424_: TooltipFlag) {
|
||||||
|
super.appendHoverText(p_41421_, p_41422_, tooltip, p_41424_)
|
||||||
|
|
||||||
|
val alreadyHasExosuit = runIfClient(true) {
|
||||||
|
minecraft.player?.matteryPlayer?.hasExoSuit == true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!alreadyHasExosuit) {
|
||||||
|
tooltip.add(TranslatableComponent("otm.gui.exosuit_upgrades.no_exosuit").withStyle(ChatFormatting.GRAY))
|
||||||
|
|
||||||
|
if (runIfClient(false) { minecraft.player?.isCreative != true }) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val alreadyHas = id != null && runIfClient(false) {
|
||||||
|
minecraft.player?.matteryPlayer?.exoSuitSlotCountModifiers?.contains(id) == true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alreadyHas) {
|
||||||
|
tooltip.add(TranslatableComponent("otm.gui.exosuit_upgrades.already_activated").withStyle(ChatFormatting.DARK_RED))
|
||||||
|
}
|
||||||
|
|
||||||
|
tooltip.add(TranslatableComponent("otm.gui.exosuit_upgrades.slots_upgrade", slotCount).withStyle(ChatFormatting.DARK_GREEN))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun use(p_41432_: Level, player: Player, hand: InteractionHand): InteractionResultHolder<ItemStack> {
|
||||||
|
val matteryPlayer = player.matteryPlayer ?: return super.use(p_41432_, player, hand)
|
||||||
|
|
||||||
|
if (matteryPlayer.hasExoSuit && (id == null || id !in matteryPlayer.exoSuitSlotCountModifiers)) {
|
||||||
|
player.startUsingItem(hand)
|
||||||
|
return InteractionResultHolder.consume(player.getItemInHand(hand))
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.use(p_41432_, player, hand)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun finishUsingItem(itemStack: ItemStack, level: Level, player: LivingEntity): ItemStack {
|
||||||
|
if (player !is Player) return super.finishUsingItem(itemStack, level, player)
|
||||||
|
val matteryPlayer = player.matteryPlayer ?: return super.finishUsingItem(itemStack, level, player)
|
||||||
|
|
||||||
|
if (!matteryPlayer.hasExoSuit || (id != null && id in matteryPlayer.exoSuitSlotCountModifiers)) {
|
||||||
|
return super.finishUsingItem(itemStack, level, player)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!player.abilities.instabuild)
|
||||||
|
itemStack.shrink(1)
|
||||||
|
|
||||||
|
if (player is ServerPlayer) {
|
||||||
|
if (id != null) {
|
||||||
|
matteryPlayer.exoSuitSlotCountModifiers[id] = slotCount
|
||||||
|
} else {
|
||||||
|
matteryPlayer.exoSuitSlotCountModifiers[UUID.randomUUID()] = slotCount
|
||||||
|
}
|
||||||
|
|
||||||
|
player.displayClientMessage(TranslatableComponent("otm.exosuit_upgrades.slots_upgraded", slotCount).withStyle(ChatFormatting.WHITE), false)
|
||||||
|
}
|
||||||
|
|
||||||
|
return itemStack
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getUseAnimation(p_41452_: ItemStack): UseAnim = UseAnim.BOW
|
||||||
|
}
|
@ -8,7 +8,10 @@ import java.io.DataOutputStream
|
|||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import kotlin.ConcurrentModificationException
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
|
import kotlin.collections.HashMap
|
||||||
|
import kotlin.properties.ReadOnlyProperty
|
||||||
import kotlin.properties.ReadWriteProperty
|
import kotlin.properties.ReadWriteProperty
|
||||||
import kotlin.reflect.KMutableProperty0
|
import kotlin.reflect.KMutableProperty0
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
@ -95,20 +98,39 @@ class EnumValueCodec<V : Enum<V>>(private val clazz: Class<out V>) : INetworkVal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed interface IField<V> : ReadWriteProperty<Any, V> {
|
sealed interface IField<V> : ReadOnlyProperty<Any, V> {
|
||||||
fun observe()
|
fun observe()
|
||||||
fun markDirty()
|
fun markDirty()
|
||||||
var value: V
|
val value: V
|
||||||
|
|
||||||
fun write(stream: DataOutputStream)
|
fun write(stream: DataOutputStream)
|
||||||
fun read(stream: DataInputStream)
|
fun read(stream: DataInputStream)
|
||||||
|
|
||||||
override fun getValue(thisRef: Any, property: KProperty<*>): V {
|
override fun getValue(thisRef: Any, property: KProperty<*>): V {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed interface IMutableField<V> : IField<V>, ReadWriteProperty<Any, V> {
|
||||||
|
override var value: V
|
||||||
|
|
||||||
override fun setValue(thisRef: Any, property: KProperty<*>, value: V) {
|
override fun setValue(thisRef: Any, property: KProperty<*>, value: V) {
|
||||||
this.value = value
|
this.value = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getValue(thisRef: Any, property: KProperty<*>): V {
|
||||||
|
return super.getValue(thisRef, property)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class MapChangeset<out K, out V>(
|
||||||
|
val action: MapAction,
|
||||||
|
val key: K?,
|
||||||
|
val value: V?
|
||||||
|
)
|
||||||
|
|
||||||
|
enum class MapAction {
|
||||||
|
CLEAR, ADD, REMOVE
|
||||||
}
|
}
|
||||||
|
|
||||||
class FieldSynchronizer {
|
class FieldSynchronizer {
|
||||||
@ -235,13 +257,29 @@ class FieldSynchronizer {
|
|||||||
return ObservedField(delegate, ItemStackValueCodec)
|
return ObservedField(delegate, ItemStackValueCodec)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <K, V> map(
|
||||||
|
keyCodec: INetworkValueCodec<K>,
|
||||||
|
valueCodec: INetworkValueCodec<V>,
|
||||||
|
callback: ((changes: Collection<MapChangeset<K, V>>) -> Unit)? = null,
|
||||||
|
backingMap: MutableMap<K, V> = HashMap(),
|
||||||
|
observingBackingMap: MutableMap<K, V>? = null,
|
||||||
|
): Map<K, V> {
|
||||||
|
return Map(
|
||||||
|
keyCodec = keyCodec,
|
||||||
|
valueCodec = valueCodec,
|
||||||
|
callback = callback,
|
||||||
|
backingMap = backingMap,
|
||||||
|
observingBackingMap = observingBackingMap
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
inner class Field<V>(
|
inner class Field<V>(
|
||||||
private var field: V,
|
private var field: V,
|
||||||
private val codec: INetworkValueCodec<V>,
|
private val codec: INetworkValueCodec<V>,
|
||||||
private val getter: FieldGetter<V>? = null,
|
private val getter: FieldGetter<V>? = null,
|
||||||
private val setter: FieldSetter<V>? = null,
|
private val setter: FieldSetter<V>? = null,
|
||||||
isObserver: Boolean = false,
|
isObserver: Boolean = false,
|
||||||
) : IField<V> {
|
) : IMutableField<V> {
|
||||||
private var remote: V = codec.copy(field)
|
private var remote: V = codec.copy(field)
|
||||||
|
|
||||||
val id = fields.size + 1
|
val id = fields.size + 1
|
||||||
@ -335,7 +373,7 @@ class FieldSynchronizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class ObservedField<V> : IField<V> {
|
inner class ObservedField<V> : IMutableField<V> {
|
||||||
private val codec: NetworkValueCodec<V>
|
private val codec: NetworkValueCodec<V>
|
||||||
private val getter: () -> V
|
private val getter: () -> V
|
||||||
private val setter: (V) -> Unit
|
private val setter: (V) -> Unit
|
||||||
@ -397,6 +435,211 @@ class FieldSynchronizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val ClearBacklogEntry = { stream: DataOutputStream -> stream.write(MapAction.CLEAR.ordinal + 1) }
|
||||||
|
private val MapActionList = MapAction.values()
|
||||||
|
private val ClearMapChangeset = MapChangeset(MapAction.CLEAR, null, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class Map<K, V>(
|
||||||
|
private val keyCodec: INetworkValueCodec<K>,
|
||||||
|
private val valueCodec: INetworkValueCodec<V>,
|
||||||
|
private val backingMap: MutableMap<K, V>,
|
||||||
|
private val observingBackingMap: MutableMap<K, V>? = null,
|
||||||
|
private val callback: ((changes: Collection<MapChangeset<K, V>>) -> Unit)? = null
|
||||||
|
) : IField<MutableMap<K, V>> {
|
||||||
|
private var isDirty = false
|
||||||
|
private var sentAllValues = false
|
||||||
|
private var isRemote = false
|
||||||
|
|
||||||
|
val id = fields.size + 1
|
||||||
|
|
||||||
|
init {
|
||||||
|
fields.add(this)
|
||||||
|
|
||||||
|
if (observingBackingMap != null)
|
||||||
|
observers.add(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val backlog = LinkedList<(DataOutputStream) -> Unit>()
|
||||||
|
|
||||||
|
override fun observe() {
|
||||||
|
if (isRemote) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val observingBackingMap = observingBackingMap
|
||||||
|
|
||||||
|
if (observingBackingMap != null) {
|
||||||
|
for ((key, value) in backingMap) {
|
||||||
|
val remoteValue = observingBackingMap[key] ?: throw ConcurrentModificationException("Backing map of $this was modified externally, or $value missed a modification")
|
||||||
|
|
||||||
|
if (!valueCodec.compare(value, remoteValue)) {
|
||||||
|
val valueCopy = valueCodec.copy(value)
|
||||||
|
|
||||||
|
backlog.add {
|
||||||
|
it.write(MapAction.ADD.ordinal + 1)
|
||||||
|
keyCodec.write(it, key)
|
||||||
|
valueCodec.write(it, valueCopy)
|
||||||
|
}
|
||||||
|
|
||||||
|
observingBackingMap[key] = valueCopy
|
||||||
|
|
||||||
|
if (!isDirty) {
|
||||||
|
dirtyFields.add(this)
|
||||||
|
isDirty = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun markDirty() {
|
||||||
|
if (isRemote) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isDirty) {
|
||||||
|
dirtyFields.add(this)
|
||||||
|
isDirty = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sentAllValues) {
|
||||||
|
for ((key, value) in backingMap) {
|
||||||
|
val valueCopy = valueCodec.copy(value)
|
||||||
|
|
||||||
|
backlog.add {
|
||||||
|
it.write(MapAction.ADD.ordinal + 1)
|
||||||
|
keyCodec.write(it, key)
|
||||||
|
valueCodec.write(it, valueCopy)
|
||||||
|
}
|
||||||
|
|
||||||
|
observingBackingMap?.put(key, valueCopy)
|
||||||
|
}
|
||||||
|
|
||||||
|
sentAllValues = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val value: MutableMap<K, V> = object : ObservedMap<K, V>(backingMap) {
|
||||||
|
override fun onClear() {
|
||||||
|
if (isRemote) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
backlog.clear()
|
||||||
|
observingBackingMap?.clear()
|
||||||
|
backlog.add(ClearBacklogEntry)
|
||||||
|
|
||||||
|
if (!isDirty) {
|
||||||
|
dirtyFields.add(this@Map)
|
||||||
|
isDirty = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onValueAdded(key: K, value: V) {
|
||||||
|
if (isRemote) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val valueCopy = valueCodec.copy(value)
|
||||||
|
|
||||||
|
backlog.add {
|
||||||
|
it.write(MapAction.ADD.ordinal + 1)
|
||||||
|
keyCodec.write(it, key)
|
||||||
|
valueCodec.write(it, valueCopy)
|
||||||
|
}
|
||||||
|
|
||||||
|
observingBackingMap?.put(key, valueCopy)
|
||||||
|
|
||||||
|
if (!isDirty) {
|
||||||
|
dirtyFields.add(this@Map)
|
||||||
|
isDirty = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onValueRemoved(key: K, value: V) {
|
||||||
|
if (isRemote) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val keyCopy = keyCodec.copy(key)
|
||||||
|
|
||||||
|
backlog.add {
|
||||||
|
it.write(MapAction.REMOVE.ordinal + 1)
|
||||||
|
keyCodec.write(it, keyCopy)
|
||||||
|
}
|
||||||
|
|
||||||
|
observingBackingMap?.remove(key)
|
||||||
|
|
||||||
|
if (!isDirty) {
|
||||||
|
dirtyFields.add(this@Map)
|
||||||
|
isDirty = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun write(stream: DataOutputStream) {
|
||||||
|
stream.write(id)
|
||||||
|
|
||||||
|
sentAllValues = false
|
||||||
|
isDirty = false
|
||||||
|
|
||||||
|
for (entry in backlog) {
|
||||||
|
entry.invoke(stream)
|
||||||
|
}
|
||||||
|
|
||||||
|
backlog.clear()
|
||||||
|
|
||||||
|
stream.write(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun read(stream: DataInputStream) {
|
||||||
|
if (!isRemote) {
|
||||||
|
isRemote = true
|
||||||
|
backlog.clear()
|
||||||
|
observingBackingMap?.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
isDirty = false
|
||||||
|
|
||||||
|
val changeset = LinkedList<MapChangeset<K, V>>()
|
||||||
|
var readAction = stream.read() - 1
|
||||||
|
|
||||||
|
while (readAction != -1) {
|
||||||
|
if (readAction >= MapActionList.size) {
|
||||||
|
throw IndexOutOfBoundsException("Unknown map action with ID $readAction")
|
||||||
|
}
|
||||||
|
|
||||||
|
when (MapActionList[readAction]) {
|
||||||
|
MapAction.CLEAR -> {
|
||||||
|
backingMap.clear()
|
||||||
|
changeset.add(ClearMapChangeset)
|
||||||
|
}
|
||||||
|
|
||||||
|
MapAction.ADD -> {
|
||||||
|
val key = keyCodec.read(stream)
|
||||||
|
val value = valueCodec.read(stream)
|
||||||
|
backingMap[key] = value
|
||||||
|
changeset.add(MapChangeset(MapAction.ADD, key, value))
|
||||||
|
}
|
||||||
|
|
||||||
|
MapAction.REMOVE -> {
|
||||||
|
val key = keyCodec.read(stream)
|
||||||
|
backingMap.remove(key)
|
||||||
|
changeset.add(MapChangeset(MapAction.REMOVE, key, null))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
readAction = stream.read() - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changeset.size != 0) {
|
||||||
|
callback?.invoke(changeset)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun invalidate() {
|
fun invalidate() {
|
||||||
for (field in fields) {
|
for (field in fields) {
|
||||||
field.markDirty()
|
field.markDirty()
|
||||||
@ -438,6 +681,10 @@ class FieldSynchronizer {
|
|||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (stream.read() != -1) {
|
||||||
|
throw IllegalStateException("Stream wasn't fully drain!")
|
||||||
|
}
|
||||||
|
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ import net.minecraftforge.registries.RegistryObject
|
|||||||
|
|
||||||
class LazyList<T>(private val getters: ImmutableList<() -> T>) : AbstractList<T>() {
|
class LazyList<T>(private val getters: ImmutableList<() -> T>) : AbstractList<T>() {
|
||||||
constructor(vararg getters: () -> T) : this(ImmutableList.copyOf(getters))
|
constructor(vararg getters: () -> T) : this(ImmutableList.copyOf(getters))
|
||||||
|
constructor(getters: List<() -> T>) : this(ImmutableList.copyOf(getters))
|
||||||
|
|
||||||
override val size: Int
|
override val size: Int
|
||||||
get() = getters.size
|
get() = getters.size
|
||||||
|
@ -14,11 +14,14 @@ import net.minecraftforge.eventbus.api.IEventBus
|
|||||||
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext
|
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext
|
||||||
import net.minecraftforge.registries.DeferredRegister
|
import net.minecraftforge.registries.DeferredRegister
|
||||||
import net.minecraftforge.registries.ForgeRegistries
|
import net.minecraftforge.registries.ForgeRegistries
|
||||||
|
import net.minecraftforge.registries.RegistryObject
|
||||||
import ru.dbotthepony.mc.otm.OverdriveThatMatters
|
import ru.dbotthepony.mc.otm.OverdriveThatMatters
|
||||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||||
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
|
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
|
||||||
import ru.dbotthepony.mc.otm.item.*
|
import ru.dbotthepony.mc.otm.item.*
|
||||||
import ru.dbotthepony.mc.otm.item.weapon.PlasmaRifleItem
|
import ru.dbotthepony.mc.otm.item.weapon.PlasmaRifleItem
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
object MItems {
|
object MItems {
|
||||||
private val DEFAULT_PROPERTIES = Item.Properties().stacksTo(64).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB)
|
private val DEFAULT_PROPERTIES = Item.Properties().stacksTo(64).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB)
|
||||||
@ -76,6 +79,39 @@ object MItems {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val EXOSUIT_PROBE: Item by registry.register(MNames.EXOSUIT_PROBE, ::ExoSuitProbeItem)
|
val EXOSUIT_PROBE: Item by registry.register(MNames.EXOSUIT_PROBE, ::ExoSuitProbeItem)
|
||||||
|
val EXOSUIT_INVENTORY_UPGRADE_CREATIVE: Item by registry.register("exosuit_inventory_upgrade_creative") { ExoSuitSlotUpgradeItem(null, 9, Item.Properties().stacksTo(64).rarity(Rarity.EPIC).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB)) }
|
||||||
|
|
||||||
|
val EXOSUIT_INVENTORY_UPGRADES: List<Item>
|
||||||
|
val EXOSUIT_INVENTORY_UPGRADES_CRAFTABLE: List<Item>
|
||||||
|
val EXOSUIT_INVENTORY_UPGRADES_UNCRAFTABLE: List<Item>
|
||||||
|
|
||||||
|
init {
|
||||||
|
val upgrades = ArrayList<() -> Item>()
|
||||||
|
val upgradesCraftable = ArrayList<() -> Item>()
|
||||||
|
val upgradesUncraftable = ArrayList<() -> Item>()
|
||||||
|
|
||||||
|
val baseSignificant = 7344348239534784L
|
||||||
|
var baseInsignificant = 848473865769484L
|
||||||
|
|
||||||
|
for (i in 1 .. 4) {
|
||||||
|
val obj = registry.register("exosuit_inventory_upgrade_$i") { ExoSuitSlotUpgradeItem(UUID(baseSignificant, baseInsignificant++), 9) }
|
||||||
|
upgrades.add(obj::get)
|
||||||
|
upgradesCraftable.add(obj::get)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i in 1 .. 16) {
|
||||||
|
val obj = registry.register("exosuit_inventory_upgrade_uncraftable_$i") { ExoSuitSlotUpgradeItem(UUID(baseSignificant, baseInsignificant++), 9 + (i / 5) * 9) }
|
||||||
|
upgrades.add(obj::get)
|
||||||
|
upgradesUncraftable.add(obj::get)
|
||||||
|
}
|
||||||
|
|
||||||
|
EXOSUIT_INVENTORY_UPGRADES = LazyList(upgrades)
|
||||||
|
EXOSUIT_INVENTORY_UPGRADES_CRAFTABLE = LazyList(upgradesCraftable)
|
||||||
|
EXOSUIT_INVENTORY_UPGRADES_UNCRAFTABLE = LazyList(upgradesUncraftable)
|
||||||
|
}
|
||||||
|
|
||||||
|
val EXOSUIT_INVENTORY_UPGRADE_BIG: Item by registry.register("exosuit_inventory_upgrade_big") { ExoSuitSlotUpgradeItem(UUID.fromString("121a17a5-533c-9ac0-ff02-03aea75ed20c"), 45, Item.Properties().stacksTo(64).rarity(Rarity.RARE).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB)) }
|
||||||
|
val EXOSUIT_INVENTORY_UPGRADE_HUGE: Item by registry.register("exosuit_inventory_upgrade_huge") { ExoSuitSlotUpgradeItem(UUID.fromString("121a17a5-533c-9ac0-ff02-03aea75ed20d"), 90, Item.Properties().stacksTo(64).rarity(Rarity.RARE).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB)) }
|
||||||
|
|
||||||
val DEBUG_EXPLOSION_SMALL: Item by registry.register(MNames.DEBUG_EXPLOSION_SMALL) { BlockItem(MBlocks.DEBUG_EXPLOSION_SMALL, DEFAULT_PROPERTIES) }
|
val DEBUG_EXPLOSION_SMALL: Item by registry.register(MNames.DEBUG_EXPLOSION_SMALL) { BlockItem(MBlocks.DEBUG_EXPLOSION_SMALL, DEFAULT_PROPERTIES) }
|
||||||
val DEBUG_SPHERE_POINTS: Item by registry.register(MNames.DEBUG_SPHERE_POINTS) { BlockItem(MBlocks.DEBUG_SPHERE_POINTS, DEFAULT_PROPERTIES) }
|
val DEBUG_SPHERE_POINTS: Item by registry.register(MNames.DEBUG_SPHERE_POINTS) { BlockItem(MBlocks.DEBUG_SPHERE_POINTS, DEFAULT_PROPERTIES) }
|
||||||
|
Loading…
Reference in New Issue
Block a user