A lot of refactoring related to block entities, capability helpers and save helpers
This commit is contained in:
parent
370aca1e6a
commit
0ee5673ea9
@ -26,7 +26,7 @@ import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets
|
|||||||
import net.minecraft.world.level.storage.loot.predicates.LootItemBlockStatePropertyCondition
|
import net.minecraft.world.level.storage.loot.predicates.LootItemBlockStatePropertyCondition
|
||||||
import net.minecraft.world.level.storage.loot.providers.nbt.ContextNbtProvider
|
import net.minecraft.world.level.storage.loot.providers.nbt.ContextNbtProvider
|
||||||
import net.minecraft.world.level.storage.loot.providers.number.ConstantValue
|
import net.minecraft.world.level.storage.loot.providers.number.ConstantValue
|
||||||
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity
|
||||||
|
|
||||||
data class NbtCopy(val source: String, val destination: String, val strategy: CopyNbtFunction.MergeStrategy = CopyNbtFunction.MergeStrategy.REPLACE)
|
data class NbtCopy(val source: String, val destination: String, val strategy: CopyNbtFunction.MergeStrategy = CopyNbtFunction.MergeStrategy.REPLACE)
|
||||||
@ -36,13 +36,13 @@ fun TileNbtCopy(source: String, strategy: CopyNbtFunction.MergeStrategy = CopyNb
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val basicTags = arrayOf(
|
private val basicTags = arrayOf(
|
||||||
TileNbtCopy(MatteryBlockEntity.REDSTONE_CONTROL_KEY),
|
TileNbtCopy(MatteryDeviceBlockEntity.REDSTONE_CONTROL_KEY),
|
||||||
)
|
)
|
||||||
|
|
||||||
private val poweredTags = arrayOf(
|
private val poweredTags = arrayOf(
|
||||||
*basicTags,
|
*basicTags,
|
||||||
TileNbtCopy(MatteryBlockEntity.ENERGY_KEY),
|
TileNbtCopy(MatteryDeviceBlockEntity.ENERGY_KEY),
|
||||||
TileNbtCopy(MatteryBlockEntity.BATTERY_KEY),
|
TileNbtCopy(MatteryDeviceBlockEntity.BATTERY_KEY),
|
||||||
)
|
)
|
||||||
|
|
||||||
private val workerTags = arrayOf(
|
private val workerTags = arrayOf(
|
||||||
@ -53,7 +53,7 @@ private val workerTags = arrayOf(
|
|||||||
|
|
||||||
private val poweredMatterWorker = arrayOf(
|
private val poweredMatterWorker = arrayOf(
|
||||||
*workerTags,
|
*workerTags,
|
||||||
TileNbtCopy(MatteryBlockEntity.MATTER_STORAGE_KEY),
|
TileNbtCopy(MatteryDeviceBlockEntity.MATTER_STORAGE_KEY),
|
||||||
)
|
)
|
||||||
|
|
||||||
class LootTables(generator: DataGenerator) : LootTableProvider(generator.packOutput, setOf() /* because we don't fucking validate you fuck */, listOf() /* because we attach everything after class is constructed duh */) {
|
class LootTables(generator: DataGenerator) : LootTableProvider(generator.packOutput, setOf() /* because we don't fucking validate you fuck */, listOf() /* because we attach everything after class is constructed duh */) {
|
||||||
|
@ -8,9 +8,9 @@ import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets
|
|||||||
import net.minecraft.world.level.storage.loot.predicates.ExplosionCondition
|
import net.minecraft.world.level.storage.loot.predicates.ExplosionCondition
|
||||||
import ru.dbotthepony.mc.otm.block.entity.tech.ChemicalGeneratorBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.tech.ChemicalGeneratorBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.block.entity.tech.EnergyCounterBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.tech.EnergyCounterBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity.Companion.ENERGY_KEY
|
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity.Companion.ENERGY_KEY
|
||||||
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity.Companion.MATTER_STORAGE_KEY
|
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity.Companion.MATTER_STORAGE_KEY
|
||||||
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity.Companion.REDSTONE_CONTROL_KEY
|
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity.Companion.REDSTONE_CONTROL_KEY
|
||||||
import ru.dbotthepony.mc.otm.block.entity.decorative.HoloSignBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.decorative.HoloSignBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.block.entity.matter.MatterBottlerBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.matter.MatterBottlerBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.block.entity.storage.AbstractStorageImportExport.Companion.FILTER_KEY
|
import ru.dbotthepony.mc.otm.block.entity.storage.AbstractStorageImportExport.Companion.FILTER_KEY
|
||||||
|
@ -17,7 +17,7 @@ import org.apache.logging.log4j.LogManager;
|
|||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import ru.dbotthepony.mc.otm.android.AndroidResearchManager;
|
import ru.dbotthepony.mc.otm.android.AndroidResearchManager;
|
||||||
import ru.dbotthepony.mc.otm.android.feature.EnderTeleporterFeature;
|
import ru.dbotthepony.mc.otm.android.feature.EnderTeleporterFeature;
|
||||||
import ru.dbotthepony.mc.otm.block.entity.SynchronizedBlockEntity;
|
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity;
|
||||||
import ru.dbotthepony.mc.otm.block.entity.blackhole.ExplosionQueue;
|
import ru.dbotthepony.mc.otm.block.entity.blackhole.ExplosionQueue;
|
||||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
|
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
|
||||||
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability;
|
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability;
|
||||||
@ -170,12 +170,12 @@ public final class OverdriveThatMatters {
|
|||||||
EVENT_BUS.addListener(EventPriority.NORMAL, MatterManager.INSTANCE::onDataPackSync);
|
EVENT_BUS.addListener(EventPriority.NORMAL, MatterManager.INSTANCE::onDataPackSync);
|
||||||
EVENT_BUS.addListener(EventPriority.NORMAL, MatterManager.INSTANCE::addCommands);
|
EVENT_BUS.addListener(EventPriority.NORMAL, MatterManager.INSTANCE::addCommands);
|
||||||
|
|
||||||
EVENT_BUS.addListener(EventPriority.NORMAL, SynchronizedBlockEntity.Companion::onServerStopping);
|
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryBlockEntity.Companion::onServerStopping);
|
||||||
EVENT_BUS.addListener(EventPriority.NORMAL, SynchronizedBlockEntity.Companion::onLevelUnload);
|
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryBlockEntity.Companion::onLevelUnload);
|
||||||
EVENT_BUS.addListener(EventPriority.NORMAL, SynchronizedBlockEntity.Companion::onWatch);
|
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryBlockEntity.Companion::onWatch);
|
||||||
EVENT_BUS.addListener(EventPriority.NORMAL, SynchronizedBlockEntity.Companion::onForget);
|
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryBlockEntity.Companion::onForget);
|
||||||
EVENT_BUS.addListener(EventPriority.NORMAL, SynchronizedBlockEntity.Companion::playerDisconnected);
|
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryBlockEntity.Companion::playerDisconnected);
|
||||||
EVENT_BUS.addListener(EventPriority.LOWEST, SynchronizedBlockEntity.Companion::postLevelTick);
|
EVENT_BUS.addListener(EventPriority.LOWEST, MatteryBlockEntity.Companion::postLevelTick);
|
||||||
|
|
||||||
EVENT_BUS.addListener(EventPriority.NORMAL, EnderTeleporterFeature.Companion::onEntityDeath);
|
EVENT_BUS.addListener(EventPriority.NORMAL, EnderTeleporterFeature.Companion::onEntityDeath);
|
||||||
EVENT_BUS.addListener(EventPriority.HIGH, ItemTritaniumArmor.Companion::onHurt);
|
EVENT_BUS.addListener(EventPriority.HIGH, ItemTritaniumArmor.Companion::onHurt);
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
package ru.dbotthepony.mc.otm.capability;
|
package ru.dbotthepony.mc.otm.capability;
|
||||||
|
|
||||||
import mekanism.api.energy.IStrictEnergyHandler;
|
import mekanism.api.energy.IStrictEnergyHandler;
|
||||||
import net.minecraftforge.common.capabilities.*;
|
import net.minecraftforge.common.capabilities.CapabilityManager;
|
||||||
|
import net.minecraftforge.common.capabilities.Capability;
|
||||||
|
import net.minecraftforge.common.capabilities.CapabilityToken;
|
||||||
|
import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import ru.dbotthepony.mc.otm.capability.drive.IMatteryDrive;
|
import ru.dbotthepony.mc.otm.capability.drive.IMatteryDrive;
|
||||||
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage;
|
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage;
|
||||||
|
@ -23,8 +23,8 @@ import net.minecraft.world.level.material.Material
|
|||||||
import net.minecraft.world.level.material.MaterialColor
|
import net.minecraft.world.level.material.MaterialColor
|
||||||
import net.minecraft.world.phys.BlockHitResult
|
import net.minecraft.world.phys.BlockHitResult
|
||||||
import net.minecraft.world.phys.shapes.VoxelShape
|
import net.minecraft.world.phys.shapes.VoxelShape
|
||||||
import ru.dbotthepony.mc.otm.block.entity.IRedstoneControlProvider
|
import ru.dbotthepony.mc.otm.block.entity.IRedstoneControlled
|
||||||
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.block.entity.WorkerState
|
import ru.dbotthepony.mc.otm.block.entity.WorkerState
|
||||||
import ru.dbotthepony.mc.otm.core.get
|
import ru.dbotthepony.mc.otm.core.get
|
||||||
import ru.dbotthepony.mc.otm.core.math.BlockRotationFreedom
|
import ru.dbotthepony.mc.otm.core.math.BlockRotationFreedom
|
||||||
@ -69,7 +69,7 @@ abstract class MatteryBlock @JvmOverloads constructor(
|
|||||||
if (this is EntityBlock && itemStack.hasCustomHoverName() && !level.isClientSide) {
|
if (this is EntityBlock && itemStack.hasCustomHoverName() && !level.isClientSide) {
|
||||||
val tile = level.getBlockEntity(blockPos)
|
val tile = level.getBlockEntity(blockPos)
|
||||||
|
|
||||||
if (tile is MatteryBlockEntity)
|
if (tile is MatteryDeviceBlockEntity)
|
||||||
tile.customDisplayName = itemStack.displayName
|
tile.customDisplayName = itemStack.displayName
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,7 +172,7 @@ abstract class MatteryBlock @JvmOverloads constructor(
|
|||||||
if (this is EntityBlock && !level.isClientSide) {
|
if (this is EntityBlock && !level.isClientSide) {
|
||||||
val tile = level.getBlockEntity(pos)
|
val tile = level.getBlockEntity(pos)
|
||||||
|
|
||||||
if (tile is IRedstoneControlProvider)
|
if (tile is IRedstoneControlled)
|
||||||
tile.redstoneControl.redstoneSignal = level.getBestNeighborSignal(pos)
|
tile.redstoneControl.redstoneSignal = level.getBestNeighborSignal(pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,43 +1,404 @@
|
|||||||
package ru.dbotthepony.mc.otm.block.entity
|
package ru.dbotthepony.mc.otm.block.entity
|
||||||
|
|
||||||
import net.minecraft.world.level.block.entity.BlockEntityType
|
import it.unimi.dsi.fastutil.longs.Long2ObjectFunction
|
||||||
import net.minecraft.core.BlockPos
|
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap
|
||||||
import net.minecraft.world.level.block.state.BlockState
|
import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap
|
||||||
import net.minecraft.world.MenuProvider
|
import it.unimi.dsi.fastutil.objects.ReferenceArraySet
|
||||||
import java.lang.Runnable
|
|
||||||
import net.minecraft.server.level.ServerLevel
|
|
||||||
import net.minecraft.client.multiplayer.ClientLevel
|
import net.minecraft.client.multiplayer.ClientLevel
|
||||||
|
import net.minecraft.core.BlockPos
|
||||||
|
import net.minecraft.core.Direction
|
||||||
import net.minecraft.core.SectionPos
|
import net.minecraft.core.SectionPos
|
||||||
import net.minecraft.world.entity.player.Inventory
|
|
||||||
import net.minecraft.world.entity.player.Player
|
|
||||||
import net.minecraft.world.inventory.AbstractContainerMenu
|
|
||||||
import net.minecraft.nbt.CompoundTag
|
import net.minecraft.nbt.CompoundTag
|
||||||
import net.minecraft.nbt.StringTag
|
import net.minecraft.nbt.Tag
|
||||||
import net.minecraft.network.chat.Component
|
import net.minecraft.server.level.ServerLevel
|
||||||
|
import net.minecraft.server.level.ServerPlayer
|
||||||
|
import net.minecraft.world.level.ChunkPos
|
||||||
import net.minecraft.world.level.Level
|
import net.minecraft.world.level.Level
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntityType
|
||||||
import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity
|
import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.core.TextComponent
|
import net.minecraft.world.level.block.state.BlockState
|
||||||
import ru.dbotthepony.mc.otm.core.nbt.ifHas
|
import net.minecraftforge.common.capabilities.Capability
|
||||||
|
import net.minecraftforge.common.capabilities.ForgeCapabilities
|
||||||
|
import net.minecraftforge.common.util.INBTSerializable
|
||||||
|
import net.minecraftforge.common.util.LazyOptional
|
||||||
|
import net.minecraftforge.event.TickEvent
|
||||||
|
import net.minecraftforge.event.TickEvent.LevelTickEvent
|
||||||
|
import net.minecraftforge.event.entity.player.PlayerEvent
|
||||||
|
import net.minecraftforge.event.level.ChunkWatchEvent
|
||||||
|
import net.minecraftforge.event.level.LevelEvent
|
||||||
|
import net.minecraftforge.event.server.ServerStoppingEvent
|
||||||
|
import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock
|
||||||
|
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
||||||
|
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
|
||||||
|
import ru.dbotthepony.mc.otm.core.forValidRefs
|
||||||
|
import ru.dbotthepony.mc.otm.core.get
|
||||||
|
import ru.dbotthepony.mc.otm.core.math.BlockRotation
|
||||||
|
import ru.dbotthepony.mc.otm.core.math.RelativeSide
|
||||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||||
|
import ru.dbotthepony.mc.otm.network.BlockEntitySyncPacket
|
||||||
|
import ru.dbotthepony.mc.otm.network.FieldSynchronizer
|
||||||
|
import ru.dbotthepony.mc.otm.network.WorldNetworkChannel
|
||||||
import ru.dbotthepony.mc.otm.oncePre
|
import ru.dbotthepony.mc.otm.oncePre
|
||||||
|
import ru.dbotthepony.mc.otm.onceServer
|
||||||
|
import java.lang.ref.WeakReference
|
||||||
|
import java.util.WeakHashMap
|
||||||
|
import kotlin.properties.ReadWriteProperty
|
||||||
|
import kotlin.reflect.KMutableProperty0
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
import kotlin.reflect.KProperty0
|
||||||
|
|
||||||
abstract class MatteryBlockEntity(
|
/**
|
||||||
p_155228_: BlockEntityType<*>,
|
* Absolute barebone block entity class in Overdrive that Matters, providing bare minimum functionality
|
||||||
p_155229_: BlockPos,
|
*/
|
||||||
p_155230_: BlockState
|
abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: BlockPos, p_155230_: BlockState) : BlockEntity(p_155228_, p_155229_, p_155230_) {
|
||||||
) : SynchronizedBlockEntity(p_155228_, p_155229_, p_155230_), MenuProvider, IRedstoneControlProvider {
|
private var isSynchronizing = false
|
||||||
var customDisplayName: Component? = null
|
|
||||||
override val redstoneControl: AbstractRedstoneControl = RedstoneControl { new, old ->
|
/**
|
||||||
if (new != old)
|
* "shortcut" for getting [BlockRotation]
|
||||||
redstoneStatusUpdated(new, old)
|
*
|
||||||
else
|
* if block has no rotation, returns [BlockRotation.NORTH]
|
||||||
setChangedLight()
|
*/
|
||||||
|
open val blockRotation: BlockRotation get() {
|
||||||
|
return blockState[(blockState.block as? RotatableMatteryBlock ?: return BlockRotation.NORTH).rotationProperty]
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open val defaultDisplayName: Component
|
// Capabilities
|
||||||
get() = level?.getBlockState(blockPos)?.block?.name ?: TextComponent("null at $blockPos")
|
|
||||||
|
|
||||||
abstract override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu?
|
private val caps = Reference2ObjectArrayMap<Capability<*>, CapInstance<*, *>>()
|
||||||
|
|
||||||
|
fun <T : Any> getCapInstance(index: Capability<in T>): CapInstance<T, *>? {
|
||||||
|
return caps[index] as CapInstance<T, *>?
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun <T : IMatteryEnergyStorage> energy(capability: T): StaticCap<T> {
|
||||||
|
return StaticCap(MatteryCapability.ENERGY, "energy", capability).alias(ForgeCapabilities.ENERGY)
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract inner class CapInstance<T : Any, S : CapInstance<T, S>>(type: Capability<in T>, val name: String) : INBTSerializable<CompoundTag> {
|
||||||
|
private val types = ReferenceArraySet<Capability<in T>>()
|
||||||
|
protected var valid = true
|
||||||
|
abstract val capability: T
|
||||||
|
|
||||||
|
protected var optional by object : ReadWriteProperty<Any?, LazyOptional<T>> {
|
||||||
|
private var value: LazyOptional<T>? = null
|
||||||
|
|
||||||
|
override fun getValue(thisRef: Any?, property: KProperty<*>): LazyOptional<T> {
|
||||||
|
if (value == null)
|
||||||
|
value = if (valid) LazyOptional.of { capability } else LazyOptional.empty()
|
||||||
|
|
||||||
|
return value!!
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setValue(thisRef: Any?, property: KProperty<*>, value: LazyOptional<T>) {
|
||||||
|
this.value = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
check(!caps.values.any { it.name == name }) { "Already has capability with name $name!" }
|
||||||
|
check(!caps.containsKey(type)) { "Already has capability with type $type!" }
|
||||||
|
caps[type] = this
|
||||||
|
types.add(type)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun alias(type: Capability<in T>): S {
|
||||||
|
if (type !in types) {
|
||||||
|
check(!caps.containsKey(type)) { "Already has capability with type $type!" }
|
||||||
|
caps[type] = this
|
||||||
|
types.add(type)
|
||||||
|
}
|
||||||
|
|
||||||
|
return this as S
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "${this@MatteryBlockEntity} at $blockPos CapInstance[name = $name, capability = $capability]"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun serializeNBT(): CompoundTag {
|
||||||
|
return CompoundTag().also {
|
||||||
|
var sides = 0
|
||||||
|
|
||||||
|
for (i in 0 .. 5)
|
||||||
|
if (exposedSides[i].first)
|
||||||
|
sides = sides.or(1 shl (i + 1))
|
||||||
|
|
||||||
|
it["sides"] = sides.toShort()
|
||||||
|
|
||||||
|
if (capability is INBTSerializable<*>)
|
||||||
|
it["capability"] = (capability as INBTSerializable<Tag>).serializeNBT()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun deserializeNBT(nbt: CompoundTag) {
|
||||||
|
var sides = 0
|
||||||
|
|
||||||
|
if (nbt.contains("sides")) {
|
||||||
|
sides = nbt.getInt("sides")
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i in 0 .. 5) {
|
||||||
|
val isExposed = sides and (1 shl (1 + i)) == 1
|
||||||
|
|
||||||
|
if (isExposed && valid) {
|
||||||
|
exposedSides[i] = true to LazyOptional.of { capability }
|
||||||
|
} else {
|
||||||
|
exposedSides[i] = isExposed to LazyOptional.empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val tag = nbt["capability"]
|
||||||
|
|
||||||
|
if (tag != null && capability is INBTSerializable<*>) {
|
||||||
|
// will throw classcastexception if serialized type is wrong
|
||||||
|
(capability as INBTSerializable<Tag>).deserializeNBT(tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected val exposedSides = Array<Pair<Boolean, LazyOptional<T>>>(6) { true to LazyOptional.of { capability } }
|
||||||
|
|
||||||
|
fun exposeAt(side: RelativeSide): S {
|
||||||
|
if (!exposedSides[side.ordinal].first) {
|
||||||
|
if (valid) {
|
||||||
|
setChanged()
|
||||||
|
exposedSides[side.ordinal] = true to LazyOptional.of { capability }
|
||||||
|
} else {
|
||||||
|
exposedSides[side.ordinal] = true to LazyOptional.empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this as S
|
||||||
|
}
|
||||||
|
|
||||||
|
fun closeAt(side: RelativeSide): S {
|
||||||
|
if (exposedSides[side.ordinal].first) {
|
||||||
|
exposedSides[side.ordinal].second.invalidate()
|
||||||
|
exposedSides[side.ordinal] = false to LazyOptional.empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
return this as S
|
||||||
|
}
|
||||||
|
|
||||||
|
fun closeAll(): S {
|
||||||
|
for (side in RelativeSide.values())
|
||||||
|
closeAt(side)
|
||||||
|
|
||||||
|
return this as S
|
||||||
|
}
|
||||||
|
|
||||||
|
fun exposeAll(): S {
|
||||||
|
for (side in RelativeSide.values())
|
||||||
|
exposeAt(side)
|
||||||
|
|
||||||
|
return this as S
|
||||||
|
}
|
||||||
|
|
||||||
|
fun exposeFront() = exposeAt(RelativeSide.FRONT)
|
||||||
|
fun exposeBack() = exposeAt(RelativeSide.BACK)
|
||||||
|
fun exposeLeft() = exposeAt(RelativeSide.LEFT)
|
||||||
|
fun exposeRight() = exposeAt(RelativeSide.RIGHT)
|
||||||
|
fun exposeTop() = exposeAt(RelativeSide.TOP)
|
||||||
|
fun exposeBottom() = exposeAt(RelativeSide.BOTTOM)
|
||||||
|
|
||||||
|
fun closeFront() = closeAt(RelativeSide.FRONT)
|
||||||
|
fun closeBack() = closeAt(RelativeSide.BACK)
|
||||||
|
fun closeLeft() = closeAt(RelativeSide.LEFT)
|
||||||
|
fun closeRight() = closeAt(RelativeSide.RIGHT)
|
||||||
|
fun closeTop() = closeAt(RelativeSide.TOP)
|
||||||
|
fun closeBottom() = closeAt(RelativeSide.BOTTOM)
|
||||||
|
|
||||||
|
fun isExposedAt(side: RelativeSide): Boolean {
|
||||||
|
return exposedSides[side.ordinal].first
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isExposedAt(side: Direction): Boolean {
|
||||||
|
return isExposedAt(blockRotation.dir2Side(side))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun get(side: Direction? = null): LazyOptional<T> {
|
||||||
|
if (!valid) {
|
||||||
|
return LazyOptional.empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (side == null) {
|
||||||
|
return optional
|
||||||
|
} else {
|
||||||
|
return exposedSides[blockRotation.dir2Side(side).ordinal].second
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun invalidate() {
|
||||||
|
if (valid) {
|
||||||
|
for ((_, v) in exposedSides)
|
||||||
|
v.invalidate()
|
||||||
|
|
||||||
|
optional.invalidate()
|
||||||
|
valid = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun revive() {
|
||||||
|
if (!valid) {
|
||||||
|
for ((i, pair) in exposedSides.withIndex())
|
||||||
|
if (pair.first)
|
||||||
|
exposedSides[i] = true to LazyOptional.of { capability }
|
||||||
|
|
||||||
|
optional = LazyOptional.of { capability }
|
||||||
|
valid = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class StaticCap<T : Any>(type: Capability<in T>, name: String, override val capability: T) : CapInstance<T, StaticCap<T>>(type, name)
|
||||||
|
|
||||||
|
inner class DynamicCap<T : Any>(type: Capability<in T>, name: String, capability: T) : CapInstance<T, DynamicCap<T>>(type, name) {
|
||||||
|
override var capability: T = capability
|
||||||
|
private set(value) {
|
||||||
|
field = value
|
||||||
|
|
||||||
|
if (valid) {
|
||||||
|
val old = ArrayList<LazyOptional<T>>(7)
|
||||||
|
old.add(optional)
|
||||||
|
val new = LazyOptional.of { value }
|
||||||
|
optional = new
|
||||||
|
|
||||||
|
for ((i, pair) in exposedSides.withIndex()) {
|
||||||
|
if (pair.first) {
|
||||||
|
old.add(pair.second)
|
||||||
|
exposedSides[i] = true to LazyOptional.of { value }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
old.forEach(LazyOptional<T>::invalidate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// /Capabilities
|
||||||
|
|
||||||
|
override fun <T> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
|
||||||
|
return caps[cap]?.get(side)?.cast() ?: super.getCapability(cap, side)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun invalidateCaps() {
|
||||||
|
super.invalidateCaps()
|
||||||
|
|
||||||
|
for (cap in caps.values)
|
||||||
|
cap.invalidate()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun reviveCaps() {
|
||||||
|
super.reviveCaps()
|
||||||
|
|
||||||
|
for (cap in caps.values)
|
||||||
|
cap.revive()
|
||||||
|
}
|
||||||
|
|
||||||
|
private data class Savetable0<T : Tag, V : Any>(val type: Class<T>, val property: KProperty0<V>, val name: String, val serialize: (V) -> T, val deserialize: (V, T) -> Unit)
|
||||||
|
private data class Savetable1<T : Tag, V : Any>(val type: Class<T>, val property: KMutableProperty0<V>, val name: String, val serialize: (V) -> T, val deserialize: (T) -> V)
|
||||||
|
|
||||||
|
private val savetables0 = ArrayList<Savetable0<*, *>>()
|
||||||
|
private val savetables1 = ArrayList<Savetable1<*, *>>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save and load object state
|
||||||
|
*/
|
||||||
|
protected fun <T : Tag, V : Any> savetable(type: Class<T>, property: KProperty0<V>, name: String = property.name, serialize: (V) -> T, deserialize: (V, T?) -> Unit) {
|
||||||
|
check(!savetables0.any { it.name == name }) { "Already has save field with name $name" }
|
||||||
|
check(!savetables1.any { it.name == name }) { "Already has save field with name $name" }
|
||||||
|
savetables0.add(Savetable0(type, property, name, serialize, deserialize))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save and load value
|
||||||
|
*/
|
||||||
|
protected fun <T : Tag, V : Any> savetable(type: Class<T>, property: KMutableProperty0<V>, name: String = property.name, serialize: (V) -> T, deserialize: (T?) -> V) {
|
||||||
|
check(!savetables0.any { it.name == name }) { "Already has save field with name $name" }
|
||||||
|
check(!savetables1.any { it.name == name }) { "Already has save field with name $name" }
|
||||||
|
savetables1.add(Savetable1(type, property, name, serialize, deserialize))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save and load object state
|
||||||
|
*/
|
||||||
|
protected fun <T : Tag, V : INBTSerializable<T?>> savetable(type: Class<T>, property: KProperty0<V>, name: String = property.name) {
|
||||||
|
savetable(type, property, name, { it.serializeNBT()!! }, { self, it -> self.deserializeNBT(it) })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save and load object state
|
||||||
|
*/
|
||||||
|
protected inline fun <reified T : Tag, V : INBTSerializable<T?>> savetable(property: KProperty0<V>, name: String = property.name) {
|
||||||
|
savetable(T::class.java, property, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save and load object state
|
||||||
|
*/
|
||||||
|
protected inline fun <reified T : Tag, V : Any> savetable(property: KProperty0<V>, name: String = property.name, noinline serialize: (V) -> T, noinline deserialize: (V, T?) -> Unit) {
|
||||||
|
savetable(T::class.java, property, name, serialize, deserialize)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save and load value
|
||||||
|
*/
|
||||||
|
protected inline fun <reified T : Tag, V : Any> savetable(property: KMutableProperty0<V>, name: String = property.name, noinline serialize: (V) -> T, noinline deserialize: (T?) -> V) {
|
||||||
|
savetable(T::class.java, property, name, serialize, deserialize)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun saveAdditional(nbt: CompoundTag) {
|
||||||
|
super.saveAdditional(nbt)
|
||||||
|
|
||||||
|
if (caps.isNotEmpty()) {
|
||||||
|
nbt["Capabilities"] = CompoundTag().also {
|
||||||
|
for (cap in caps.values) {
|
||||||
|
it[cap.name] = cap.serializeNBT()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (data in savetables0) {
|
||||||
|
nbt[data.name] = (data.serialize as (Any) -> Tag).invoke(data.property.get())
|
||||||
|
}
|
||||||
|
|
||||||
|
for (data in savetables1) {
|
||||||
|
nbt[data.name] = (data.serialize as (Any) -> Tag).invoke(data.property.get())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun load(nbt: CompoundTag) {
|
||||||
|
super.load(nbt)
|
||||||
|
|
||||||
|
if (nbt.contains("Capabilities")) {
|
||||||
|
@Suppress("name_shadowing")
|
||||||
|
val nbt = nbt.getCompound("Capabilities")
|
||||||
|
|
||||||
|
for (cap in caps.values) {
|
||||||
|
if (nbt.contains(cap.name)) {
|
||||||
|
cap.deserializeNBT(nbt.getCompound(cap.name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (data in savetables0) {
|
||||||
|
val value = nbt[data.name]
|
||||||
|
|
||||||
|
if (value != null && data.type.isAssignableFrom(value.javaClass)) {
|
||||||
|
(data.deserialize as (Any, Tag) -> Unit).invoke(data.property.get(), value)
|
||||||
|
} else if (value != null) {
|
||||||
|
throw ClassCastException("Expected ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (data in savetables1) {
|
||||||
|
val value = nbt[data.name]
|
||||||
|
|
||||||
|
if (value != null && data.type.isAssignableFrom(value.javaClass)) {
|
||||||
|
(data.property as KMutableProperty0<Any>).set((data.deserialize as (Tag) -> Any).invoke(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected fun tickOnce(func: Runnable) {
|
protected fun tickOnce(func: Runnable) {
|
||||||
level?.oncePre { if (!isRemoved) func.run() }
|
level?.oncePre { if (!isRemoved) func.run() }
|
||||||
@ -66,32 +427,6 @@ abstract class MatteryBlockEntity(
|
|||||||
level.oncePre { if (!isRemoved) func.invoke(level) }
|
level.oncePre { if (!isRemoved) func.invoke(level) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getDisplayName(): Component {
|
|
||||||
return customDisplayName ?: defaultDisplayName
|
|
||||||
}
|
|
||||||
|
|
||||||
protected open fun redstoneStatusUpdated(newBlocked: Boolean, oldBlocked: Boolean) {}
|
|
||||||
|
|
||||||
override fun saveAdditional(nbt: CompoundTag) {
|
|
||||||
super.saveAdditional(nbt)
|
|
||||||
|
|
||||||
val customDisplayName = customDisplayName
|
|
||||||
if (customDisplayName != null)
|
|
||||||
nbt.putString("Name", Component.Serializer.toJson(customDisplayName))
|
|
||||||
|
|
||||||
nbt[REDSTONE_CONTROL_KEY] = redstoneControl.serializeNBT()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun load(nbt: CompoundTag) {
|
|
||||||
super.load(nbt)
|
|
||||||
|
|
||||||
nbt.ifHas("Name", StringTag::class.java) {
|
|
||||||
customDisplayName = Component.Serializer.fromJson(it.asString)
|
|
||||||
}
|
|
||||||
|
|
||||||
redstoneControl.deserializeNBT(nbt[REDSTONE_CONTROL_KEY] as? CompoundTag)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Just to mark chunk unsaved
|
// Just to mark chunk unsaved
|
||||||
open fun setChangedLight() {
|
open fun setChangedLight() {
|
||||||
val level = level
|
val level = level
|
||||||
@ -102,6 +437,255 @@ abstract class MatteryBlockEntity(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val synchronizer = FieldSynchronizer {
|
||||||
|
if (isSynchronizing)
|
||||||
|
return@FieldSynchronizer
|
||||||
|
|
||||||
|
if (!isRemoved && level?.isClientSide == false && (_subCache == null || (_subCache ?: throw ConcurrentModificationException()).players.isNotEmpty())) {
|
||||||
|
onceServer {
|
||||||
|
synchronizeToPlayers(true)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
markSynchronizerClean()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun markSynchronizerClean() {
|
||||||
|
synchronizer.markClean()
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
synchronizer.defaultEndpoint.markUnused()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setLevel(p_155231_: Level) {
|
||||||
|
super.setLevel(p_155231_)
|
||||||
|
unsubscribe()
|
||||||
|
_subCache = null
|
||||||
|
|
||||||
|
if (!p_155231_.isClientSide) {
|
||||||
|
subscribe()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setRemoved() {
|
||||||
|
super.setRemoved()
|
||||||
|
unsubscribe()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clearRemoved() {
|
||||||
|
super.clearRemoved()
|
||||||
|
|
||||||
|
if (level?.isClientSide == false) {
|
||||||
|
subscribe()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var _subCache: ChunkSubscribers? = null
|
||||||
|
|
||||||
|
private fun unsubscribe() {
|
||||||
|
val subCache = _subCache ?: return
|
||||||
|
|
||||||
|
if (subCache.unsubscribe(this)) {
|
||||||
|
val level = subCache.level.get()
|
||||||
|
|
||||||
|
if (level != null) {
|
||||||
|
playerMap.get(level)?.remove(subCache.chunkPos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lastSubscriptionChangeset = -1
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun subscribe(): ChunkSubscribers {
|
||||||
|
val level = level
|
||||||
|
check(level is ServerLevel) { "Invalid realm" }
|
||||||
|
unsubscribe()
|
||||||
|
|
||||||
|
val subs = playerMap
|
||||||
|
.computeIfAbsent(level) { Long2ObjectOpenHashMap() }
|
||||||
|
.computeIfAbsent(ChunkPos(blockPos).toLong(), Long2ObjectFunction { ChunkSubscribers(level = WeakReference(level), chunkPos = ChunkPos(blockPos).toLong()) })
|
||||||
|
|
||||||
|
subs.subscribe(this)
|
||||||
|
_subCache = subs
|
||||||
|
return subs
|
||||||
|
}
|
||||||
|
|
||||||
|
private val subscription get() = _subCache ?: subscribe()
|
||||||
|
private var lastSubscriptionChangeset = -1
|
||||||
|
|
||||||
|
fun synchronizeToPlayers() {
|
||||||
|
synchronizeToPlayers(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun synchronizeToPlayers(calledBySynchronizer: Boolean) {
|
||||||
|
isSynchronizing = true
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (synchronizer.isEmpty || isRemoved) {
|
||||||
|
if (calledBySynchronizer) synchronizer.markClean()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
check(level is ServerLevel) { "Invalid realm or Level is null" }
|
||||||
|
|
||||||
|
synchronizer.observe()
|
||||||
|
|
||||||
|
val subscription = subscription
|
||||||
|
|
||||||
|
if (subscription.players.isEmpty() || lastSubscriptionChangeset == subscription.changeset && !synchronizer.hasChanges) {
|
||||||
|
if (calledBySynchronizer) synchronizer.markClean()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
lastSubscriptionChangeset = subscription.changeset
|
||||||
|
|
||||||
|
for (player in subscription.players) {
|
||||||
|
val payload = synchronizer.computeEndpointFor(player).collectNetworkPayload()
|
||||||
|
|
||||||
|
if (payload != null) {
|
||||||
|
WorldNetworkChannel.send(player, BlockEntitySyncPacket(blockPos, payload.array, payload.length))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronizer.markClean()
|
||||||
|
} finally {
|
||||||
|
isSynchronizing = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private data class ChunkSubscribers(
|
||||||
|
val blockEntities: ArrayList<WeakReference<MatteryBlockEntity>> = ArrayList(0),
|
||||||
|
val players: ArrayList<ServerPlayer> = ArrayList(1),
|
||||||
|
val observingBlockEntities: ArrayList<WeakReference<MatteryBlockEntity>> = ArrayList(0),
|
||||||
|
val level: WeakReference<ServerLevel>,
|
||||||
|
val chunkPos: Long,
|
||||||
|
var changeset: Int = 0
|
||||||
|
) {
|
||||||
|
fun cleanUpBlocks() {
|
||||||
|
val listIterator = blockEntities.listIterator()
|
||||||
|
|
||||||
|
for (block in listIterator) {
|
||||||
|
if (block.get() == null) {
|
||||||
|
listIterator.remove()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val hasObservers: Boolean get() {
|
||||||
|
val listIterator = blockEntities.listIterator()
|
||||||
|
|
||||||
|
for (value in listIterator) {
|
||||||
|
val ref = value.get()
|
||||||
|
|
||||||
|
if (ref == null) {
|
||||||
|
listIterator.remove()
|
||||||
|
} else if (ref.synchronizer.hasObservers) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun subscribe(blockEntity: MatteryBlockEntity) {
|
||||||
|
val iterator = blockEntities.listIterator()
|
||||||
|
|
||||||
|
for (value in iterator) {
|
||||||
|
val ref = value.get()
|
||||||
|
|
||||||
|
if (ref === blockEntity) {
|
||||||
|
return
|
||||||
|
} else if (ref == null) {
|
||||||
|
iterator.remove()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val bref = WeakReference(blockEntity)
|
||||||
|
blockEntities.add(bref)
|
||||||
|
changeset++
|
||||||
|
|
||||||
|
onceServer {
|
||||||
|
blockEntity.synchronizeToPlayers()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blockEntity.synchronizer.hasObservers) {
|
||||||
|
observingBlockEntities.add(bref)
|
||||||
|
val listing = tickingMap.computeIfAbsent(level.get() ?: throw NullPointerException("Level got GCd!")) { ArrayList(1) }
|
||||||
|
val tickerIterator = listing.listIterator()
|
||||||
|
|
||||||
|
for (value in tickerIterator) {
|
||||||
|
val ref = value.get()
|
||||||
|
|
||||||
|
if (ref === this) {
|
||||||
|
return
|
||||||
|
} else if (ref == null) {
|
||||||
|
tickerIterator.remove()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
listing.add(WeakReference(this))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun unsubscribe(blockEntity: MatteryBlockEntity): Boolean {
|
||||||
|
val listIterator = blockEntities.listIterator()
|
||||||
|
|
||||||
|
for (value in listIterator) {
|
||||||
|
if (value.get() === blockEntity) {
|
||||||
|
listIterator.remove()
|
||||||
|
changeset++
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blockEntity.synchronizer.hasObservers) {
|
||||||
|
val tickerIterator = observingBlockEntities.listIterator()
|
||||||
|
|
||||||
|
for (value in tickerIterator) {
|
||||||
|
val ref = value.get()
|
||||||
|
|
||||||
|
if (ref === blockEntity) {
|
||||||
|
tickerIterator.remove()
|
||||||
|
break
|
||||||
|
} else if (ref == null) {
|
||||||
|
tickerIterator.remove()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (players.isNotEmpty()) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanUpBlocks()
|
||||||
|
return blockEntities.isEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
val isEmpty: Boolean get() {
|
||||||
|
if (players.isNotEmpty()) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanUpBlocks()
|
||||||
|
return blockEntities.isEmpty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Why track player-tracked chunks?
|
||||||
|
*
|
||||||
|
* because minecraft itself doesn't track them, well,
|
||||||
|
* in "section partitioning" way.
|
||||||
|
*
|
||||||
|
* just look at [net.minecraft.server.level.PlayerMap]
|
||||||
|
*
|
||||||
|
* the [net.minecraft.server.level.PlayerMap.getPlayers] straight ignores chunk position
|
||||||
|
* and just fetches all players
|
||||||
|
*
|
||||||
|
* even if they did not ignore that argument, you still have to fetch player *list* though
|
||||||
|
* [net.minecraft.server.level.ChunkMap.getPlayers], which is not something we want
|
||||||
|
*/
|
||||||
companion object {
|
companion object {
|
||||||
const val REDSTONE_CONTROL_KEY = "redstoneControl"
|
const val REDSTONE_CONTROL_KEY = "redstoneControl"
|
||||||
const val INVENTORY_KEY = "container"
|
const val INVENTORY_KEY = "container"
|
||||||
@ -110,5 +694,105 @@ abstract class MatteryBlockEntity(
|
|||||||
const val BATTERY_KEY = "batteryInventory"
|
const val BATTERY_KEY = "batteryInventory"
|
||||||
const val LOOT_TABLE_KEY = RandomizableContainerBlockEntity.LOOT_TABLE_TAG
|
const val LOOT_TABLE_KEY = RandomizableContainerBlockEntity.LOOT_TABLE_TAG
|
||||||
const val LOOT_TABLE_SEED_KEY = RandomizableContainerBlockEntity.LOOT_TABLE_SEED_TAG
|
const val LOOT_TABLE_SEED_KEY = RandomizableContainerBlockEntity.LOOT_TABLE_SEED_TAG
|
||||||
|
|
||||||
|
private val playerMap = WeakHashMap<ServerLevel, Long2ObjectOpenHashMap<ChunkSubscribers>>()
|
||||||
|
private val tickingMap = WeakHashMap<ServerLevel, ArrayList<WeakReference<ChunkSubscribers>>>()
|
||||||
|
|
||||||
|
fun onLevelUnload(event: LevelEvent.Unload) {
|
||||||
|
val level = event.level as? ServerLevel ?: return
|
||||||
|
playerMap.remove(level)
|
||||||
|
tickingMap.remove(level)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onServerStopping(event: ServerStoppingEvent) {
|
||||||
|
playerMap.clear()
|
||||||
|
tickingMap.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun postLevelTick(event: LevelTickEvent) {
|
||||||
|
if (event.phase == TickEvent.Phase.END) {
|
||||||
|
val level = event.level as? ServerLevel ?: return
|
||||||
|
val listing = tickingMap[level] ?: return
|
||||||
|
val listIterator = listing.listIterator()
|
||||||
|
var hitAnyObservers = false
|
||||||
|
|
||||||
|
for (value in listIterator) {
|
||||||
|
val ref = value.get()
|
||||||
|
|
||||||
|
if (ref == null) {
|
||||||
|
listIterator.remove()
|
||||||
|
} else if (ref.players.isNotEmpty()) {
|
||||||
|
var hitObservers = false
|
||||||
|
|
||||||
|
ref.observingBlockEntities.forValidRefs {
|
||||||
|
hitObservers = true
|
||||||
|
hitAnyObservers = true
|
||||||
|
it.synchronizeToPlayers()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hitObservers) {
|
||||||
|
listIterator.remove()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hitAnyObservers) {
|
||||||
|
tickingMap.remove(level)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onWatch(event: ChunkWatchEvent.Watch) {
|
||||||
|
playerMap
|
||||||
|
.computeIfAbsent(event.level) { Long2ObjectOpenHashMap() }
|
||||||
|
.computeIfAbsent(event.pos.toLong(), Long2ObjectFunction { ChunkSubscribers(level = WeakReference(event.level), chunkPos = event.pos.toLong()) })
|
||||||
|
.let {
|
||||||
|
val (blocks, players) = it
|
||||||
|
|
||||||
|
if (event.player !in players) {
|
||||||
|
players.add(event.player)
|
||||||
|
it.changeset++
|
||||||
|
|
||||||
|
onceServer(10) {
|
||||||
|
if (!event.player.hasDisconnected() && event.player in players) {
|
||||||
|
blocks.forValidRefs {
|
||||||
|
it.synchronizeToPlayers(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onForget(event: ChunkWatchEvent.UnWatch) {
|
||||||
|
val subs = playerMap.get(event.level)?.get(event.pos.toLong()) ?: return
|
||||||
|
|
||||||
|
if (subs.players.remove(event.player)) {
|
||||||
|
if (subs.isEmpty) {
|
||||||
|
playerMap.get(event.level)?.remove(event.pos.toLong())
|
||||||
|
} else {
|
||||||
|
subs.changeset++
|
||||||
|
subs.blockEntities.forValidRefs {
|
||||||
|
it.synchronizer.removeEndpointFor(event.player)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun playerDisconnected(event: PlayerEvent.PlayerLoggedOutEvent) {
|
||||||
|
for (tree in playerMap.values) {
|
||||||
|
val iterator = tree.iterator()
|
||||||
|
|
||||||
|
for (entry in iterator) {
|
||||||
|
if (entry.value.players.remove(event.entity)) {
|
||||||
|
entry.value.changeset++
|
||||||
|
|
||||||
|
if (entry.value.isEmpty) {
|
||||||
|
iterator.remove()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,64 @@
|
|||||||
|
package ru.dbotthepony.mc.otm.block.entity
|
||||||
|
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntityType
|
||||||
|
import net.minecraft.core.BlockPos
|
||||||
|
import net.minecraft.world.level.block.state.BlockState
|
||||||
|
import net.minecraft.world.MenuProvider
|
||||||
|
import java.lang.Runnable
|
||||||
|
import net.minecraft.server.level.ServerLevel
|
||||||
|
import net.minecraft.client.multiplayer.ClientLevel
|
||||||
|
import net.minecraft.core.SectionPos
|
||||||
|
import net.minecraft.world.entity.player.Inventory
|
||||||
|
import net.minecraft.world.entity.player.Player
|
||||||
|
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||||
|
import net.minecraft.nbt.CompoundTag
|
||||||
|
import net.minecraft.network.chat.Component
|
||||||
|
import net.minecraft.world.level.Level
|
||||||
|
import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity
|
||||||
|
import ru.dbotthepony.mc.otm.core.TextComponent
|
||||||
|
import ru.dbotthepony.mc.otm.core.nbt.getJson
|
||||||
|
import ru.dbotthepony.mc.otm.core.nbt.putJson
|
||||||
|
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||||
|
import ru.dbotthepony.mc.otm.oncePre
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Device block entity base, implementing [MenuProvider] and [IRedstoneControlled], and also tracks custom display name
|
||||||
|
*/
|
||||||
|
abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blockPos: BlockPos, blockState: BlockState)
|
||||||
|
: MatteryBlockEntity(blockEntityType, blockPos, blockState), MenuProvider, IRedstoneControlled {
|
||||||
|
var customDisplayName: Component? = null
|
||||||
|
|
||||||
|
override val redstoneControl: AbstractRedstoneControl = RedstoneControl { new, old ->
|
||||||
|
setChangedLight()
|
||||||
|
|
||||||
|
if (new != old)
|
||||||
|
redstoneStatusUpdated(new, old)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open val defaultDisplayName: Component
|
||||||
|
get() = level?.getBlockState(blockPos)?.block?.name ?: TextComponent("null at $blockPos")
|
||||||
|
|
||||||
|
abstract override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu?
|
||||||
|
|
||||||
|
override fun getDisplayName(): Component {
|
||||||
|
return customDisplayName ?: defaultDisplayName
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun redstoneStatusUpdated(newBlocked: Boolean, oldBlocked: Boolean) {}
|
||||||
|
|
||||||
|
override fun saveAdditional(nbt: CompoundTag) {
|
||||||
|
super.saveAdditional(nbt)
|
||||||
|
|
||||||
|
if (customDisplayName != null)
|
||||||
|
nbt.putJson("Name", Component.Serializer.toJsonTree(customDisplayName!!))
|
||||||
|
|
||||||
|
nbt[REDSTONE_CONTROL_KEY] = redstoneControl.serializeNBT()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun load(nbt: CompoundTag) {
|
||||||
|
super.load(nbt)
|
||||||
|
|
||||||
|
customDisplayName = nbt.getJson("Name")?.let(Component.Serializer::fromJson)
|
||||||
|
redstoneControl.deserializeNBT(nbt[REDSTONE_CONTROL_KEY] as? CompoundTag)
|
||||||
|
}
|
||||||
|
}
|
@ -25,7 +25,7 @@ import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
|||||||
import ru.dbotthepony.mc.otm.core.nbt.map
|
import ru.dbotthepony.mc.otm.core.nbt.map
|
||||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||||
|
|
||||||
abstract class MatteryPoweredBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: BlockPos, p_155230_: BlockState) : MatteryBlockEntity(p_155228_, p_155229_, p_155230_) {
|
abstract class MatteryPoweredBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: BlockPos, p_155230_: BlockState) : MatteryDeviceBlockEntity(p_155228_, p_155229_, p_155230_) {
|
||||||
abstract val energy: BlockEnergyStorageImpl?
|
abstract val energy: BlockEnergyStorageImpl?
|
||||||
private var valid = true
|
private var valid = true
|
||||||
val batteryContainer = MatteryContainer(this::setChangedLight, 1)
|
val batteryContainer = MatteryContainer(this::setChangedLight, 1)
|
||||||
|
@ -6,7 +6,7 @@ import ru.dbotthepony.mc.otm.core.nbt.getEnum
|
|||||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||||
import ru.dbotthepony.mc.otm.network.FieldSynchronizer
|
import ru.dbotthepony.mc.otm.network.FieldSynchronizer
|
||||||
|
|
||||||
interface IRedstoneControlProvider {
|
interface IRedstoneControlled {
|
||||||
val redstoneControl: AbstractRedstoneControl
|
val redstoneControl: AbstractRedstoneControl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,380 +0,0 @@
|
|||||||
package ru.dbotthepony.mc.otm.block.entity
|
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectFunction
|
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap
|
|
||||||
import net.minecraft.core.BlockPos
|
|
||||||
import net.minecraft.server.level.ServerLevel
|
|
||||||
import net.minecraft.server.level.ServerPlayer
|
|
||||||
import net.minecraft.world.level.ChunkPos
|
|
||||||
import net.minecraft.world.level.Level
|
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity
|
|
||||||
import net.minecraft.world.level.block.entity.BlockEntityType
|
|
||||||
import net.minecraft.world.level.block.state.BlockState
|
|
||||||
import net.minecraftforge.event.TickEvent
|
|
||||||
import net.minecraftforge.event.TickEvent.LevelTickEvent
|
|
||||||
import net.minecraftforge.event.entity.player.PlayerEvent
|
|
||||||
import net.minecraftforge.event.level.ChunkWatchEvent
|
|
||||||
import net.minecraftforge.event.level.LevelEvent
|
|
||||||
import net.minecraftforge.event.server.ServerStoppingEvent
|
|
||||||
import ru.dbotthepony.mc.otm.core.forValidRefs
|
|
||||||
import ru.dbotthepony.mc.otm.network.BlockEntitySyncPacket
|
|
||||||
import ru.dbotthepony.mc.otm.network.FieldSynchronizer
|
|
||||||
import ru.dbotthepony.mc.otm.network.WorldNetworkChannel
|
|
||||||
import ru.dbotthepony.mc.otm.onceServer
|
|
||||||
import java.lang.ref.WeakReference
|
|
||||||
import java.util.WeakHashMap
|
|
||||||
|
|
||||||
abstract class SynchronizedBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: BlockPos, p_155230_: BlockState) : BlockEntity(p_155228_, p_155229_, p_155230_) {
|
|
||||||
private var isSynchronizing = false
|
|
||||||
|
|
||||||
val synchronizer = FieldSynchronizer {
|
|
||||||
if (isSynchronizing)
|
|
||||||
return@FieldSynchronizer
|
|
||||||
|
|
||||||
if (!isRemoved && level?.isClientSide == false && (_subCache == null || (_subCache ?: throw ConcurrentModificationException()).players.isNotEmpty())) {
|
|
||||||
onceServer {
|
|
||||||
synchronizeToPlayers(true)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
markSynchronizerClean()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun markSynchronizerClean() {
|
|
||||||
synchronizer.markClean()
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
synchronizer.defaultEndpoint.markUnused()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setLevel(p_155231_: Level) {
|
|
||||||
super.setLevel(p_155231_)
|
|
||||||
unsubscribe()
|
|
||||||
_subCache = null
|
|
||||||
|
|
||||||
if (!p_155231_.isClientSide) {
|
|
||||||
subscribe()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setRemoved() {
|
|
||||||
super.setRemoved()
|
|
||||||
unsubscribe()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun clearRemoved() {
|
|
||||||
super.clearRemoved()
|
|
||||||
|
|
||||||
if (level?.isClientSide == false) {
|
|
||||||
subscribe()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var _subCache: ChunkSubscribers? = null
|
|
||||||
|
|
||||||
private fun unsubscribe() {
|
|
||||||
val subCache = _subCache ?: return
|
|
||||||
|
|
||||||
if (subCache.unsubscribe(this)) {
|
|
||||||
val level = subCache.level.get()
|
|
||||||
|
|
||||||
if (level != null) {
|
|
||||||
playerMap.get(level)?.remove(subCache.chunkPos)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lastSubscriptionChangeset = -1
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun subscribe(): ChunkSubscribers {
|
|
||||||
val level = level
|
|
||||||
check(level is ServerLevel) { "Invalid realm" }
|
|
||||||
unsubscribe()
|
|
||||||
|
|
||||||
val subs = playerMap
|
|
||||||
.computeIfAbsent(level) { Long2ObjectOpenHashMap() }
|
|
||||||
.computeIfAbsent(ChunkPos(blockPos).toLong(), Long2ObjectFunction { ChunkSubscribers(level = WeakReference(level), chunkPos = ChunkPos(blockPos).toLong()) })
|
|
||||||
|
|
||||||
subs.subscribe(this)
|
|
||||||
_subCache = subs
|
|
||||||
return subs
|
|
||||||
}
|
|
||||||
|
|
||||||
private val subscription get() = _subCache ?: subscribe()
|
|
||||||
private var lastSubscriptionChangeset = -1
|
|
||||||
|
|
||||||
fun synchronizeToPlayers() {
|
|
||||||
synchronizeToPlayers(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
protected fun synchronizeToPlayers(calledBySynchronizer: Boolean) {
|
|
||||||
isSynchronizing = true
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (synchronizer.isEmpty || isRemoved) {
|
|
||||||
if (calledBySynchronizer) synchronizer.markClean()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
check(level is ServerLevel) { "Invalid realm or Level is null" }
|
|
||||||
|
|
||||||
synchronizer.observe()
|
|
||||||
|
|
||||||
val subscription = subscription
|
|
||||||
|
|
||||||
if (subscription.players.isEmpty() || lastSubscriptionChangeset == subscription.changeset && !synchronizer.hasChanges) {
|
|
||||||
if (calledBySynchronizer) synchronizer.markClean()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
lastSubscriptionChangeset = subscription.changeset
|
|
||||||
|
|
||||||
for (player in subscription.players) {
|
|
||||||
val payload = synchronizer.computeEndpointFor(player).collectNetworkPayload()
|
|
||||||
|
|
||||||
if (payload != null) {
|
|
||||||
WorldNetworkChannel.send(player, BlockEntitySyncPacket(blockPos, payload.array, payload.length))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronizer.markClean()
|
|
||||||
} finally {
|
|
||||||
isSynchronizing = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private data class ChunkSubscribers(
|
|
||||||
val blockEntities: ArrayList<WeakReference<SynchronizedBlockEntity>> = ArrayList(0),
|
|
||||||
val players: ArrayList<ServerPlayer> = ArrayList(1),
|
|
||||||
val observingBlockEntities: ArrayList<WeakReference<SynchronizedBlockEntity>> = ArrayList(0),
|
|
||||||
val level: WeakReference<ServerLevel>,
|
|
||||||
val chunkPos: Long,
|
|
||||||
var changeset: Int = 0
|
|
||||||
) {
|
|
||||||
fun cleanUpBlocks() {
|
|
||||||
val listIterator = blockEntities.listIterator()
|
|
||||||
|
|
||||||
for (block in listIterator) {
|
|
||||||
if (block.get() == null) {
|
|
||||||
listIterator.remove()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val hasObservers: Boolean get() {
|
|
||||||
val listIterator = blockEntities.listIterator()
|
|
||||||
|
|
||||||
for (value in listIterator) {
|
|
||||||
val ref = value.get()
|
|
||||||
|
|
||||||
if (ref == null) {
|
|
||||||
listIterator.remove()
|
|
||||||
} else if (ref.synchronizer.hasObservers) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
fun subscribe(blockEntity: SynchronizedBlockEntity) {
|
|
||||||
val iterator = blockEntities.listIterator()
|
|
||||||
|
|
||||||
for (value in iterator) {
|
|
||||||
val ref = value.get()
|
|
||||||
|
|
||||||
if (ref === blockEntity) {
|
|
||||||
return
|
|
||||||
} else if (ref == null) {
|
|
||||||
iterator.remove()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val bref = WeakReference(blockEntity)
|
|
||||||
blockEntities.add(bref)
|
|
||||||
changeset++
|
|
||||||
|
|
||||||
onceServer {
|
|
||||||
blockEntity.synchronizeToPlayers()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (blockEntity.synchronizer.hasObservers) {
|
|
||||||
observingBlockEntities.add(bref)
|
|
||||||
val listing = tickingMap.computeIfAbsent(level.get() ?: throw NullPointerException("Level got GCd!")) { ArrayList(1) }
|
|
||||||
val tickerIterator = listing.listIterator()
|
|
||||||
|
|
||||||
for (value in tickerIterator) {
|
|
||||||
val ref = value.get()
|
|
||||||
|
|
||||||
if (ref === this) {
|
|
||||||
return
|
|
||||||
} else if (ref == null) {
|
|
||||||
tickerIterator.remove()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
listing.add(WeakReference(this))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun unsubscribe(blockEntity: SynchronizedBlockEntity): Boolean {
|
|
||||||
val listIterator = blockEntities.listIterator()
|
|
||||||
|
|
||||||
for (value in listIterator) {
|
|
||||||
if (value.get() === blockEntity) {
|
|
||||||
listIterator.remove()
|
|
||||||
changeset++
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (blockEntity.synchronizer.hasObservers) {
|
|
||||||
val tickerIterator = observingBlockEntities.listIterator()
|
|
||||||
|
|
||||||
for (value in tickerIterator) {
|
|
||||||
val ref = value.get()
|
|
||||||
|
|
||||||
if (ref === blockEntity) {
|
|
||||||
tickerIterator.remove()
|
|
||||||
break
|
|
||||||
} else if (ref == null) {
|
|
||||||
tickerIterator.remove()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (players.isNotEmpty()) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanUpBlocks()
|
|
||||||
return blockEntities.isEmpty()
|
|
||||||
}
|
|
||||||
|
|
||||||
val isEmpty: Boolean get() {
|
|
||||||
if (players.isNotEmpty()) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanUpBlocks()
|
|
||||||
return blockEntities.isEmpty()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Why track player-tracked chunks?
|
|
||||||
*
|
|
||||||
* because minecraft itself doesn't track them, well,
|
|
||||||
* in "section partitioning" way.
|
|
||||||
*
|
|
||||||
* just look at [net.minecraft.server.level.PlayerMap]
|
|
||||||
*
|
|
||||||
* the [net.minecraft.server.level.PlayerMap.getPlayers] straight ignores chunk position
|
|
||||||
* and just fetches all players
|
|
||||||
*
|
|
||||||
* even if they did not ignore that argument, you still have to fetch player *list* though
|
|
||||||
* [net.minecraft.server.level.ChunkMap.getPlayers], which is not something we want
|
|
||||||
*/
|
|
||||||
companion object {
|
|
||||||
private val playerMap = WeakHashMap<ServerLevel, Long2ObjectOpenHashMap<ChunkSubscribers>>()
|
|
||||||
private val tickingMap = WeakHashMap<ServerLevel, ArrayList<WeakReference<ChunkSubscribers>>>()
|
|
||||||
|
|
||||||
fun onLevelUnload(event: LevelEvent.Unload) {
|
|
||||||
val level = event.level as? ServerLevel ?: return
|
|
||||||
playerMap.remove(level)
|
|
||||||
tickingMap.remove(level)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onServerStopping(event: ServerStoppingEvent) {
|
|
||||||
playerMap.clear()
|
|
||||||
tickingMap.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun postLevelTick(event: LevelTickEvent) {
|
|
||||||
if (event.phase == TickEvent.Phase.END) {
|
|
||||||
val level = event.level as? ServerLevel ?: return
|
|
||||||
val listing = tickingMap[level] ?: return
|
|
||||||
val listIterator = listing.listIterator()
|
|
||||||
var hitAnyObservers = false
|
|
||||||
|
|
||||||
for (value in listIterator) {
|
|
||||||
val ref = value.get()
|
|
||||||
|
|
||||||
if (ref == null) {
|
|
||||||
listIterator.remove()
|
|
||||||
} else if (ref.players.isNotEmpty()) {
|
|
||||||
var hitObservers = false
|
|
||||||
|
|
||||||
ref.observingBlockEntities.forValidRefs {
|
|
||||||
hitObservers = true
|
|
||||||
hitAnyObservers = true
|
|
||||||
it.synchronizeToPlayers()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hitObservers) {
|
|
||||||
listIterator.remove()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hitAnyObservers) {
|
|
||||||
tickingMap.remove(level)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onWatch(event: ChunkWatchEvent.Watch) {
|
|
||||||
playerMap
|
|
||||||
.computeIfAbsent(event.level) { Long2ObjectOpenHashMap() }
|
|
||||||
.computeIfAbsent(event.pos.toLong(), Long2ObjectFunction { ChunkSubscribers(level = WeakReference(event.level), chunkPos = event.pos.toLong()) })
|
|
||||||
.let {
|
|
||||||
val (blocks, players) = it
|
|
||||||
|
|
||||||
if (event.player !in players) {
|
|
||||||
players.add(event.player)
|
|
||||||
it.changeset++
|
|
||||||
|
|
||||||
onceServer(10) {
|
|
||||||
if (!event.player.hasDisconnected() && event.player in players) {
|
|
||||||
blocks.forValidRefs {
|
|
||||||
it.synchronizeToPlayers(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onForget(event: ChunkWatchEvent.UnWatch) {
|
|
||||||
val subs = playerMap.get(event.level)?.get(event.pos.toLong()) ?: return
|
|
||||||
|
|
||||||
if (subs.players.remove(event.player)) {
|
|
||||||
if (subs.isEmpty) {
|
|
||||||
playerMap.get(event.level)?.remove(event.pos.toLong())
|
|
||||||
} else {
|
|
||||||
subs.changeset++
|
|
||||||
subs.blockEntities.forValidRefs {
|
|
||||||
it.synchronizer.removeEndpointFor(event.player)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun playerDisconnected(event: PlayerEvent.PlayerLoggedOutEvent) {
|
|
||||||
for (tree in playerMap.values) {
|
|
||||||
val iterator = tree.iterator()
|
|
||||||
|
|
||||||
for (entry in iterator) {
|
|
||||||
if (entry.value.players.remove(event.entity)) {
|
|
||||||
entry.value.changeset++
|
|
||||||
|
|
||||||
if (entry.value.isEmpty) {
|
|
||||||
iterator.remove()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -19,7 +19,7 @@ import net.minecraft.world.phys.AABB
|
|||||||
import net.minecraft.world.phys.Vec3
|
import net.minecraft.world.phys.Vec3
|
||||||
import ru.dbotthepony.mc.otm.block.BlackHoleBlock
|
import ru.dbotthepony.mc.otm.block.BlackHoleBlock
|
||||||
import ru.dbotthepony.mc.otm.block.entity.tech.GravitationStabilizerBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.tech.GravitationStabilizerBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.block.entity.SynchronizedBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.block.entity.blackhole.ExplosionQueue.Companion.queueForLevel
|
import ru.dbotthepony.mc.otm.block.entity.blackhole.ExplosionQueue.Companion.queueForLevel
|
||||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||||
import ru.dbotthepony.mc.otm.core.math.plus
|
import ru.dbotthepony.mc.otm.core.math.plus
|
||||||
@ -36,7 +36,7 @@ import kotlin.math.pow
|
|||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
import kotlin.math.sqrt
|
import kotlin.math.sqrt
|
||||||
|
|
||||||
class BlackHoleBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : SynchronizedBlockEntity(MBlockEntities.BLACK_HOLE, p_155229_, p_155230_) {
|
class BlackHoleBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryBlockEntity(MBlockEntities.BLACK_HOLE, p_155229_, p_155230_) {
|
||||||
var mass by synchronizer.fraction(BASELINE_MASS, setter = setter@{ mass, field, setByRemote ->
|
var mass by synchronizer.fraction(BASELINE_MASS, setter = setter@{ mass, field, setByRemote ->
|
||||||
if (mass <= Decimal.ZERO) {
|
if (mass <= Decimal.ZERO) {
|
||||||
collapse()
|
collapse()
|
||||||
|
@ -30,7 +30,7 @@ import net.minecraftforge.common.capabilities.ForgeCapabilities
|
|||||||
import net.minecraftforge.common.util.LazyOptional
|
import net.minecraftforge.common.util.LazyOptional
|
||||||
import ru.dbotthepony.mc.otm.block.decorative.CargoCrateBlock
|
import ru.dbotthepony.mc.otm.block.decorative.CargoCrateBlock
|
||||||
import ru.dbotthepony.mc.otm.block.IDroppableContainer
|
import ru.dbotthepony.mc.otm.block.IDroppableContainer
|
||||||
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryContainerHooks
|
import ru.dbotthepony.mc.otm.container.MatteryContainerHooks
|
||||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||||
@ -43,7 +43,7 @@ import ru.dbotthepony.mc.otm.registry.MSoundEvents
|
|||||||
class CargoCrateBlockEntity(
|
class CargoCrateBlockEntity(
|
||||||
p_155229_: BlockPos,
|
p_155229_: BlockPos,
|
||||||
p_155230_: BlockState
|
p_155230_: BlockState
|
||||||
) : MatteryBlockEntity(MBlockEntities.CARGO_CRATE, p_155229_, p_155230_), IDroppableContainer {
|
) : MatteryDeviceBlockEntity(MBlockEntities.CARGO_CRATE, p_155229_, p_155230_), IDroppableContainer {
|
||||||
val container = MatteryContainer(this::setChanged, CAPACITY)
|
val container = MatteryContainer(this::setChanged, CAPACITY)
|
||||||
private var interactingPlayers = 0
|
private var interactingPlayers = 0
|
||||||
val handler = container.handler(object : MatteryContainerHooks {
|
val handler = container.handler(object : MatteryContainerHooks {
|
||||||
|
@ -8,15 +8,15 @@ import net.minecraft.world.entity.player.Inventory
|
|||||||
import net.minecraft.world.entity.player.Player
|
import net.minecraft.world.entity.player.Player
|
||||||
import net.minecraft.world.inventory.AbstractContainerMenu
|
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||||
import net.minecraft.world.level.block.state.BlockState
|
import net.minecraft.world.level.block.state.BlockState
|
||||||
import ru.dbotthepony.mc.otm.block.entity.IRedstoneControlProvider
|
import ru.dbotthepony.mc.otm.block.entity.IRedstoneControlled
|
||||||
import ru.dbotthepony.mc.otm.block.entity.SynchronizedBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.block.entity.SynchronizedRedstoneControl
|
import ru.dbotthepony.mc.otm.block.entity.SynchronizedRedstoneControl
|
||||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||||
import ru.dbotthepony.mc.otm.menu.decorative.HoloSignMenu
|
import ru.dbotthepony.mc.otm.menu.decorative.HoloSignMenu
|
||||||
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
||||||
import ru.dbotthepony.mc.otm.registry.MBlocks
|
import ru.dbotthepony.mc.otm.registry.MBlocks
|
||||||
|
|
||||||
class HoloSignBlockEntity(blockPos: BlockPos, blockState: BlockState) : SynchronizedBlockEntity(MBlockEntities.HOLO_SIGN, blockPos, blockState), MenuProvider, IRedstoneControlProvider {
|
class HoloSignBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryBlockEntity(MBlockEntities.HOLO_SIGN, blockPos, blockState), MenuProvider, IRedstoneControlled {
|
||||||
override val redstoneControl = SynchronizedRedstoneControl(synchronizer) { _, _ -> setChanged() }
|
override val redstoneControl = SynchronizedRedstoneControl(synchronizer) { _, _ -> setChanged() }
|
||||||
|
|
||||||
var text by synchronizer.string("", name = "text", setter = { value, access, remote ->
|
var text by synchronizer.string("", name = "text", setter = { value, access, remote ->
|
||||||
|
@ -11,14 +11,12 @@ import net.minecraft.world.entity.player.Player
|
|||||||
import net.minecraft.world.inventory.AbstractContainerMenu
|
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
import net.minecraft.world.level.Level
|
import net.minecraft.world.level.Level
|
||||||
import net.minecraft.world.level.block.Block
|
|
||||||
import net.minecraft.world.level.block.state.BlockState
|
import net.minecraft.world.level.block.state.BlockState
|
||||||
import net.minecraftforge.common.capabilities.Capability
|
import net.minecraftforge.common.capabilities.Capability
|
||||||
import net.minecraftforge.common.util.LazyOptional
|
import net.minecraftforge.common.util.LazyOptional
|
||||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||||
import ru.dbotthepony.mc.otm.block.tech.BatteryBankBlock
|
|
||||||
import ru.dbotthepony.mc.otm.block.IDroppableContainer
|
import ru.dbotthepony.mc.otm.block.IDroppableContainer
|
||||||
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.block.entity.tech.BatteryBankBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.tech.BatteryBankBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.capability.FlowDirection
|
import ru.dbotthepony.mc.otm.capability.FlowDirection
|
||||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
||||||
@ -35,7 +33,7 @@ import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
|||||||
import ru.dbotthepony.mc.otm.core.nbt.map
|
import ru.dbotthepony.mc.otm.core.nbt.map
|
||||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||||
|
|
||||||
class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryBlockEntity(MBlockEntities.MATTER_CAPACITOR_BANK, p_155229_, p_155230_), IMatterGraphNode, IMatterStorage, IDroppableContainer {
|
class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.MATTER_CAPACITOR_BANK, p_155229_, p_155230_), IMatterGraphNode, IMatterStorage, IDroppableContainer {
|
||||||
var gaugeLevel by synchronizer.float()
|
var gaugeLevel by synchronizer.float()
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ import net.minecraft.server.level.ServerLevel
|
|||||||
import net.minecraft.world.level.Level
|
import net.minecraft.world.level.Level
|
||||||
import net.minecraftforge.common.capabilities.Capability
|
import net.minecraftforge.common.capabilities.Capability
|
||||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||||
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.capability.matter.*
|
import ru.dbotthepony.mc.otm.capability.matter.*
|
||||||
import ru.dbotthepony.mc.otm.graph.Graph6Node
|
import ru.dbotthepony.mc.otm.graph.Graph6Node
|
||||||
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode
|
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode
|
||||||
@ -29,7 +29,7 @@ import java.util.ArrayList
|
|||||||
import java.util.stream.Stream
|
import java.util.stream.Stream
|
||||||
|
|
||||||
class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
|
class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
|
||||||
MatteryBlockEntity(MBlockEntities.MATTER_PANEL, p_155229_, p_155230_), IMatterGraphNode, IReplicationTaskProvider {
|
MatteryDeviceBlockEntity(MBlockEntities.MATTER_PANEL, p_155229_, p_155230_), IMatterGraphNode, IReplicationTaskProvider {
|
||||||
|
|
||||||
private val listeners = ArrayList<MatterPanelMenu>()
|
private val listeners = ArrayList<MatterPanelMenu>()
|
||||||
override val matterNode = Graph6Node<IMatterGraphNode>(this)
|
override val matterNode = Graph6Node<IMatterGraphNode>(this)
|
||||||
|
@ -24,7 +24,7 @@ import net.minecraft.world.level.block.Block
|
|||||||
import net.minecraftforge.common.capabilities.Capability
|
import net.minecraftforge.common.capabilities.Capability
|
||||||
import net.minecraftforge.common.capabilities.ForgeCapabilities
|
import net.minecraftforge.common.capabilities.ForgeCapabilities
|
||||||
import ru.dbotthepony.mc.otm.block.IDroppableContainer
|
import ru.dbotthepony.mc.otm.block.IDroppableContainer
|
||||||
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||||
import ru.dbotthepony.mc.otm.capability.matter.*
|
import ru.dbotthepony.mc.otm.capability.matter.*
|
||||||
import ru.dbotthepony.mc.otm.core.collect.iterator
|
import ru.dbotthepony.mc.otm.core.collect.iterator
|
||||||
@ -40,7 +40,7 @@ import java.util.stream.Stream
|
|||||||
@MethodsReturnNonnullByDefault
|
@MethodsReturnNonnullByDefault
|
||||||
@ParametersAreNonnullByDefault
|
@ParametersAreNonnullByDefault
|
||||||
class PatternStorageBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
|
class PatternStorageBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
|
||||||
MatteryBlockEntity(MBlockEntities.PATTERN_STORAGE, p_155229_, p_155230_), IMatterGraphNode, IPatternStorage, IDroppableContainer {
|
MatteryDeviceBlockEntity(MBlockEntities.PATTERN_STORAGE, p_155229_, p_155230_), IMatterGraphNode, IPatternStorage, IDroppableContainer {
|
||||||
|
|
||||||
override val matterNode = Graph6Node<IMatterGraphNode>(this)
|
override val matterNode = Graph6Node<IMatterGraphNode>(this)
|
||||||
private val resolverPatterns = LazyOptional.of { this }
|
private val resolverPatterns = LazyOptional.of { this }
|
||||||
|
@ -10,17 +10,14 @@ import net.minecraft.world.entity.player.Player
|
|||||||
import net.minecraft.world.inventory.AbstractContainerMenu
|
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
import net.minecraft.world.level.Level
|
import net.minecraft.world.level.Level
|
||||||
import net.minecraft.world.level.block.Block
|
|
||||||
import net.minecraft.world.level.block.state.BlockState
|
import net.minecraft.world.level.block.state.BlockState
|
||||||
import net.minecraftforge.common.capabilities.Capability
|
import net.minecraftforge.common.capabilities.Capability
|
||||||
import net.minecraftforge.common.capabilities.ForgeCapabilities
|
import net.minecraftforge.common.capabilities.ForgeCapabilities
|
||||||
import net.minecraftforge.common.util.LazyOptional
|
import net.minecraftforge.common.util.LazyOptional
|
||||||
import net.minecraftforge.energy.IEnergyStorage
|
import net.minecraftforge.energy.IEnergyStorage
|
||||||
import org.apache.logging.log4j.LogManager
|
import org.apache.logging.log4j.LogManager
|
||||||
import ru.dbotthepony.mc.otm.block.tech.BatteryBankBlock
|
|
||||||
import ru.dbotthepony.mc.otm.block.IDroppableContainer
|
import ru.dbotthepony.mc.otm.block.IDroppableContainer
|
||||||
import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock
|
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
|
|
||||||
import ru.dbotthepony.mc.otm.capability.*
|
import ru.dbotthepony.mc.otm.capability.*
|
||||||
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
|
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
|
||||||
import ru.dbotthepony.mc.otm.compat.mekanism.Mattery2MekanismEnergyWrapper
|
import ru.dbotthepony.mc.otm.compat.mekanism.Mattery2MekanismEnergyWrapper
|
||||||
@ -29,14 +26,12 @@ import ru.dbotthepony.mc.otm.container.MatteryContainerHooks
|
|||||||
import ru.dbotthepony.mc.otm.core.*
|
import ru.dbotthepony.mc.otm.core.*
|
||||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||||
import ru.dbotthepony.mc.otm.core.math.facingOne
|
import ru.dbotthepony.mc.otm.core.math.facingOne
|
||||||
import ru.dbotthepony.mc.otm.core.math.rotationOne
|
|
||||||
import ru.dbotthepony.mc.otm.core.math.unaryMinus
|
|
||||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||||
import ru.dbotthepony.mc.otm.core.util.BESubscribeList
|
import ru.dbotthepony.mc.otm.core.util.BESubscribeList
|
||||||
import ru.dbotthepony.mc.otm.menu.tech.BatteryBankMenu
|
import ru.dbotthepony.mc.otm.menu.tech.BatteryBankMenu
|
||||||
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
||||||
|
|
||||||
class BatteryBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryBlockEntity(MBlockEntities.BATTERY_BANK, p_155229_, p_155230_), IDroppableContainer {
|
class BatteryBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.BATTERY_BANK, p_155229_, p_155230_), IDroppableContainer {
|
||||||
var gaugeLevel by synchronizer.float()
|
var gaugeLevel by synchronizer.float()
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
@ -19,8 +19,7 @@ import net.minecraftforge.common.capabilities.ForgeCapabilities
|
|||||||
import net.minecraftforge.common.util.LazyOptional
|
import net.minecraftforge.common.util.LazyOptional
|
||||||
import net.minecraftforge.energy.IEnergyStorage
|
import net.minecraftforge.energy.IEnergyStorage
|
||||||
import ru.dbotthepony.mc.otm.block.IDroppableContainer
|
import ru.dbotthepony.mc.otm.block.IDroppableContainer
|
||||||
import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock
|
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
|
|
||||||
import ru.dbotthepony.mc.otm.block.entity.WorkerState
|
import ru.dbotthepony.mc.otm.block.entity.WorkerState
|
||||||
import ru.dbotthepony.mc.otm.capability.*
|
import ru.dbotthepony.mc.otm.capability.*
|
||||||
import ru.dbotthepony.mc.otm.capability.energy.GeneratorEnergyStorage
|
import ru.dbotthepony.mc.otm.capability.energy.GeneratorEnergyStorage
|
||||||
@ -39,7 +38,7 @@ import ru.dbotthepony.mc.otm.core.nbt.map
|
|||||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||||
import ru.dbotthepony.mc.otm.core.util.BESubscribeList
|
import ru.dbotthepony.mc.otm.core.util.BESubscribeList
|
||||||
|
|
||||||
class ChemicalGeneratorBlockEntity(pos: BlockPos, state: BlockState) : MatteryBlockEntity(MBlockEntities.CHEMICAL_GENERATOR, pos, state), IDroppableContainer {
|
class ChemicalGeneratorBlockEntity(pos: BlockPos, state: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.CHEMICAL_GENERATOR, pos, state), IDroppableContainer {
|
||||||
override val defaultDisplayName: Component
|
override val defaultDisplayName: Component
|
||||||
get() = MACHINE_NAME
|
get() = MACHINE_NAME
|
||||||
|
|
||||||
|
@ -1,25 +1,17 @@
|
|||||||
package ru.dbotthepony.mc.otm.block.entity.tech
|
package ru.dbotthepony.mc.otm.block.entity.tech
|
||||||
|
|
||||||
import net.minecraft.core.BlockPos
|
import net.minecraft.core.BlockPos
|
||||||
import net.minecraft.core.Direction
|
|
||||||
import net.minecraft.nbt.CompoundTag
|
|
||||||
import net.minecraft.network.chat.Component
|
|
||||||
import net.minecraft.world.Container
|
|
||||||
import net.minecraft.world.entity.player.Inventory
|
import net.minecraft.world.entity.player.Inventory
|
||||||
import net.minecraft.world.entity.player.Player
|
import net.minecraft.world.entity.player.Player
|
||||||
import net.minecraft.world.inventory.AbstractContainerMenu
|
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
import net.minecraft.world.item.Items
|
import net.minecraft.world.item.Items
|
||||||
import net.minecraft.world.level.block.state.BlockState
|
import net.minecraft.world.level.block.state.BlockState
|
||||||
import net.minecraftforge.common.capabilities.Capability
|
|
||||||
import net.minecraftforge.common.capabilities.ForgeCapabilities
|
import net.minecraftforge.common.capabilities.ForgeCapabilities
|
||||||
import net.minecraftforge.common.util.LazyOptional
|
|
||||||
import ru.dbotthepony.mc.otm.block.IDroppableContainer
|
import ru.dbotthepony.mc.otm.block.IDroppableContainer
|
||||||
import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryContainerHooks
|
import ru.dbotthepony.mc.otm.container.MatteryContainerHooks
|
||||||
import ru.dbotthepony.mc.otm.core.nbt.map
|
|
||||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
|
||||||
import ru.dbotthepony.mc.otm.menu.tech.CobblerMenu
|
import ru.dbotthepony.mc.otm.menu.tech.CobblerMenu
|
||||||
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
||||||
|
|
||||||
@ -31,37 +23,15 @@ class CobblerBlockEntity(blockPos: BlockPos, blockState: BlockState)
|
|||||||
|
|
||||||
override val energy = null
|
override val energy = null
|
||||||
override val droppableContainer = MatteryContainer(this::itemContainerUpdated, CONTAINER_SIZE)
|
override val droppableContainer = MatteryContainer(this::itemContainerUpdated, CONTAINER_SIZE)
|
||||||
val handler = droppableContainer.handler(object : MatteryContainerHooks {
|
|
||||||
|
val handler = StaticCap(ForgeCapabilities.ITEM_HANDLER, INVENTORY_KEY, droppableContainer.handler(object : MatteryContainerHooks {
|
||||||
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
|
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
})
|
}))
|
||||||
|
|
||||||
override fun <T> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
|
init {
|
||||||
if (cap === ForgeCapabilities.ITEM_HANDLER)
|
savetable(::droppableContainer, INVENTORY_KEY)
|
||||||
return handler.get().cast()
|
|
||||||
|
|
||||||
return super.getCapability(cap, side)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun invalidateCaps() {
|
|
||||||
super.invalidateCaps()
|
|
||||||
handler.invalidate()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun reviveCaps() {
|
|
||||||
super.reviveCaps()
|
|
||||||
handler.revive()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun saveAdditional(nbt: CompoundTag) {
|
|
||||||
super.saveAdditional(nbt)
|
|
||||||
nbt[INVENTORY_KEY] = droppableContainer.serializeNBT()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun load(nbt: CompoundTag) {
|
|
||||||
super.load(nbt)
|
|
||||||
nbt.map(INVENTORY_KEY, droppableContainer::deserializeNBT)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onJobFinish(job: ItemJob): Status {
|
override fun onJobFinish(job: ItemJob): Status {
|
||||||
|
@ -16,7 +16,7 @@ import net.minecraftforge.common.capabilities.ForgeCapabilities
|
|||||||
import net.minecraftforge.common.util.LazyOptional
|
import net.minecraftforge.common.util.LazyOptional
|
||||||
import net.minecraftforge.energy.IEnergyStorage
|
import net.minecraftforge.energy.IEnergyStorage
|
||||||
import ru.dbotthepony.mc.otm.block.tech.EnergyCounterBlock
|
import ru.dbotthepony.mc.otm.block.tech.EnergyCounterBlock
|
||||||
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.capability.*
|
import ru.dbotthepony.mc.otm.capability.*
|
||||||
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
|
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
|
||||||
import ru.dbotthepony.mc.otm.compat.mekanism.Mattery2MekanismEnergyWrapper
|
import ru.dbotthepony.mc.otm.compat.mekanism.Mattery2MekanismEnergyWrapper
|
||||||
@ -33,7 +33,7 @@ import ru.dbotthepony.mc.otm.menu.tech.EnergyCounterMenu
|
|||||||
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryBlockEntity(MBlockEntities.ENERGY_COUNTER, p_155229_, p_155230_) {
|
class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.ENERGY_COUNTER, p_155229_, p_155230_) {
|
||||||
var passed by synchronizer.fraction()
|
var passed by synchronizer.fraction()
|
||||||
|
|
||||||
private val history = Array(10 * 20) { Decimal.ZERO }
|
private val history = Array(10 * 20) { Decimal.ZERO }
|
||||||
|
@ -14,7 +14,7 @@ import net.minecraftforge.common.capabilities.Capability
|
|||||||
import net.minecraftforge.common.capabilities.ForgeCapabilities
|
import net.minecraftforge.common.capabilities.ForgeCapabilities
|
||||||
import net.minecraftforge.common.util.LazyOptional
|
import net.minecraftforge.common.util.LazyOptional
|
||||||
import ru.dbotthepony.mc.otm.block.IDroppableContainer
|
import ru.dbotthepony.mc.otm.block.IDroppableContainer
|
||||||
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.capability.FlowDirection
|
import ru.dbotthepony.mc.otm.capability.FlowDirection
|
||||||
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
|
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
|
||||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
||||||
@ -33,7 +33,7 @@ import ru.dbotthepony.mc.otm.menu.tech.EnergyServoMenu
|
|||||||
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
||||||
import ru.dbotthepony.mc.otm.registry.MBlocks
|
import ru.dbotthepony.mc.otm.registry.MBlocks
|
||||||
|
|
||||||
class EnergyServoBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryBlockEntity(MBlockEntities.ENERGY_SERVO, blockPos, blockState), IDroppableContainer {
|
class EnergyServoBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.ENERGY_SERVO, blockPos, blockState), IDroppableContainer {
|
||||||
override val defaultDisplayName: Component
|
override val defaultDisplayName: Component
|
||||||
get() = MBlocks.ENERGY_SERVO.name
|
get() = MBlocks.ENERGY_SERVO.name
|
||||||
|
|
||||||
|
@ -11,8 +11,7 @@ import net.minecraft.world.level.block.state.BlockState
|
|||||||
import net.minecraft.world.phys.AABB
|
import net.minecraft.world.phys.AABB
|
||||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||||
import ru.dbotthepony.mc.otm.block.tech.BlockGravitationStabilizerLens
|
import ru.dbotthepony.mc.otm.block.tech.BlockGravitationStabilizerLens
|
||||||
import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock
|
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
|
|
||||||
import ru.dbotthepony.mc.otm.block.entity.WorkerState
|
import ru.dbotthepony.mc.otm.block.entity.WorkerState
|
||||||
import ru.dbotthepony.mc.otm.block.entity.blackhole.BlackHoleBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.blackhole.BlackHoleBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.block.tech.BlockGravitationStabilizer
|
import ru.dbotthepony.mc.otm.block.tech.BlockGravitationStabilizer
|
||||||
@ -21,7 +20,7 @@ import ru.dbotthepony.mc.otm.core.math.plus
|
|||||||
import ru.dbotthepony.mc.otm.core.math.times
|
import ru.dbotthepony.mc.otm.core.math.times
|
||||||
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
||||||
|
|
||||||
class GravitationStabilizerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryBlockEntity(
|
class GravitationStabilizerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryDeviceBlockEntity(
|
||||||
MBlockEntities.GRAVITATION_STABILIZER, p_155229_, p_155230_) {
|
MBlockEntities.GRAVITATION_STABILIZER, p_155229_, p_155230_) {
|
||||||
|
|
||||||
override val defaultDisplayName: Component
|
override val defaultDisplayName: Component
|
||||||
|
@ -2,7 +2,6 @@ package ru.dbotthepony.mc.otm.block.tech
|
|||||||
|
|
||||||
import net.minecraft.ChatFormatting
|
import net.minecraft.ChatFormatting
|
||||||
import net.minecraft.core.BlockPos
|
import net.minecraft.core.BlockPos
|
||||||
import net.minecraft.core.Direction
|
|
||||||
import net.minecraft.nbt.CompoundTag
|
import net.minecraft.nbt.CompoundTag
|
||||||
import net.minecraft.network.chat.Component
|
import net.minecraft.network.chat.Component
|
||||||
import net.minecraft.world.item.BlockItem
|
import net.minecraft.world.item.BlockItem
|
||||||
@ -20,8 +19,9 @@ import net.minecraft.world.level.block.state.StateDefinition
|
|||||||
import net.minecraft.world.phys.shapes.CollisionContext
|
import net.minecraft.world.phys.shapes.CollisionContext
|
||||||
import net.minecraft.world.phys.shapes.VoxelShape
|
import net.minecraft.world.phys.shapes.VoxelShape
|
||||||
import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock
|
import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock
|
||||||
import ru.dbotthepony.mc.otm.block.entity.tech.ChemicalGeneratorBlockEntity
|
|
||||||
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
|
||||||
|
import ru.dbotthepony.mc.otm.block.entity.tech.ChemicalGeneratorBlockEntity
|
||||||
|
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.block.entity.WorkerState
|
import ru.dbotthepony.mc.otm.block.entity.WorkerState
|
||||||
import ru.dbotthepony.mc.otm.block.getShapeForEachState
|
import ru.dbotthepony.mc.otm.block.getShapeForEachState
|
||||||
import ru.dbotthepony.mc.otm.capability.energy.GeneratorEnergyStorage
|
import ru.dbotthepony.mc.otm.capability.energy.GeneratorEnergyStorage
|
||||||
@ -29,7 +29,6 @@ import ru.dbotthepony.mc.otm.capability.energy.ItemEnergyStorageImpl
|
|||||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||||
import ru.dbotthepony.mc.otm.core.get
|
import ru.dbotthepony.mc.otm.core.get
|
||||||
import ru.dbotthepony.mc.otm.core.math.facingOne
|
|
||||||
import ru.dbotthepony.mc.otm.core.nbt.map
|
import ru.dbotthepony.mc.otm.core.nbt.map
|
||||||
import ru.dbotthepony.mc.otm.oncePre
|
import ru.dbotthepony.mc.otm.oncePre
|
||||||
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
||||||
|
@ -13,9 +13,10 @@ import net.minecraft.world.level.block.entity.BlockEntity
|
|||||||
import net.minecraftforge.common.ForgeConfigSpec
|
import net.minecraftforge.common.ForgeConfigSpec
|
||||||
import net.minecraftforge.common.util.INBTSerializable
|
import net.minecraftforge.common.util.INBTSerializable
|
||||||
import net.minecraftforge.common.util.LazyOptional
|
import net.minecraftforge.common.util.LazyOptional
|
||||||
|
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.config.ConciseBalanceValues
|
import ru.dbotthepony.mc.otm.config.ConciseBalanceValues
|
||||||
import ru.dbotthepony.mc.otm.config.VerboseBalanceValues
|
import ru.dbotthepony.mc.otm.config.VerboseBalanceValues
|
||||||
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.capability.FlowDirection
|
import ru.dbotthepony.mc.otm.capability.FlowDirection
|
||||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||||
import ru.dbotthepony.mc.otm.core.math.defineDecimal
|
import ru.dbotthepony.mc.otm.core.math.defineDecimal
|
||||||
|
@ -10,10 +10,8 @@ import net.minecraft.core.Direction
|
|||||||
import net.minecraft.resources.ResourceLocation
|
import net.minecraft.resources.ResourceLocation
|
||||||
import net.minecraft.world.level.levelgen.XoroshiroRandomSource
|
import net.minecraft.world.level.levelgen.XoroshiroRandomSource
|
||||||
import net.minecraftforge.client.event.ModelEvent
|
import net.minecraftforge.client.event.ModelEvent
|
||||||
import org.joml.AxisAngle4f
|
|
||||||
import org.joml.Quaternionf
|
|
||||||
import ru.dbotthepony.mc.otm.OverdriveThatMatters
|
import ru.dbotthepony.mc.otm.OverdriveThatMatters
|
||||||
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.block.entity.matter.MatterCapacitorBankBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.matter.MatterCapacitorBankBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.block.entity.tech.BatteryBankBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.tech.BatteryBankBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.client.minecraft
|
import ru.dbotthepony.mc.otm.client.minecraft
|
||||||
@ -24,7 +22,6 @@ import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel
|
|||||||
import ru.dbotthepony.mc.otm.core.ImmutableList
|
import ru.dbotthepony.mc.otm.core.ImmutableList
|
||||||
import ru.dbotthepony.mc.otm.core.get
|
import ru.dbotthepony.mc.otm.core.get
|
||||||
import ru.dbotthepony.mc.otm.core.math.BlockRotationFreedom
|
import ru.dbotthepony.mc.otm.core.math.BlockRotationFreedom
|
||||||
import ru.dbotthepony.mc.otm.core.math.PIf
|
|
||||||
import ru.dbotthepony.mc.otm.core.math.facingOne
|
import ru.dbotthepony.mc.otm.core.math.facingOne
|
||||||
import ru.dbotthepony.mc.otm.core.math.rotate
|
import ru.dbotthepony.mc.otm.core.math.rotate
|
||||||
import ru.dbotthepony.mc.otm.core.math.rotateY
|
import ru.dbotthepony.mc.otm.core.math.rotateY
|
||||||
@ -32,7 +29,7 @@ import ru.dbotthepony.mc.otm.nanoTime
|
|||||||
import java.util.function.Supplier
|
import java.util.function.Supplier
|
||||||
import kotlin.math.PI
|
import kotlin.math.PI
|
||||||
|
|
||||||
abstract class BankRenderer<T : MatteryBlockEntity>(private val context: BlockEntityRendererProvider.Context) : BlockEntityRenderer<T> {
|
abstract class BankRenderer<T : MatteryDeviceBlockEntity>(private val context: BlockEntityRendererProvider.Context) : BlockEntityRenderer<T> {
|
||||||
protected abstract fun gaugeLevel(entity: T): Float
|
protected abstract fun gaugeLevel(entity: T): Float
|
||||||
protected abstract val texture: AbstractMatterySprite
|
protected abstract val texture: AbstractMatterySprite
|
||||||
protected abstract val models: List<BakedModel>
|
protected abstract val models: List<BakedModel>
|
||||||
|
@ -9,12 +9,13 @@ import net.minecraft.world.Container
|
|||||||
import kotlin.jvm.JvmOverloads
|
import kotlin.jvm.JvmOverloads
|
||||||
import net.minecraft.world.entity.player.Player
|
import net.minecraft.world.entity.player.Player
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity
|
import net.minecraft.world.level.block.entity.BlockEntity
|
||||||
|
import net.minecraftforge.common.util.INBTSerializable
|
||||||
import ru.dbotthepony.mc.otm.core.nbt.ifHas
|
import ru.dbotthepony.mc.otm.core.nbt.ifHas
|
||||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@Suppress("UNUSED")
|
@Suppress("UNUSED")
|
||||||
open class MatteryContainer(val watcher: Runnable, private val size: Int) : Container, Iterable<ItemStack> {
|
open class MatteryContainer(val watcher: Runnable, private val size: Int) : Container, Iterable<ItemStack>, INBTSerializable<Tag?> {
|
||||||
constructor(watcher: BlockEntity, size: Int) : this(watcher::setChanged, size)
|
constructor(watcher: BlockEntity, size: Int) : this(watcher::setChanged, size)
|
||||||
constructor(size: Int) : this({}, size)
|
constructor(size: Int) : this({}, size)
|
||||||
|
|
||||||
@ -107,7 +108,7 @@ open class MatteryContainer(val watcher: Runnable, private val size: Int) : Cont
|
|||||||
setChanged()
|
setChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun deserializeNBT(tag: Tag?) {
|
override fun deserializeNBT(tag: Tag?) {
|
||||||
when (tag) {
|
when (tag) {
|
||||||
is CompoundTag -> deserializeNBT(tag)
|
is CompoundTag -> deserializeNBT(tag)
|
||||||
is ListTag -> deserializeNBT(tag)
|
is ListTag -> deserializeNBT(tag)
|
||||||
@ -122,7 +123,7 @@ open class MatteryContainer(val watcher: Runnable, private val size: Int) : Cont
|
|||||||
if (ignoreChangeNotifications == 0) watcher.run()
|
if (ignoreChangeNotifications == 0) watcher.run()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun serializeNBT(): ListTag {
|
override fun serializeNBT(): ListTag {
|
||||||
return ListTag().also {
|
return ListTag().also {
|
||||||
for ((i, item) in slots.withIndex()) {
|
for ((i, item) in slots.withIndex()) {
|
||||||
if (!item.isEmpty) {
|
if (!item.isEmpty) {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package ru.dbotthepony.mc.otm.core.math
|
package ru.dbotthepony.mc.otm.core.math
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMap
|
||||||
import net.minecraft.core.BlockPos
|
import net.minecraft.core.BlockPos
|
||||||
import net.minecraft.core.Direction
|
import net.minecraft.core.Direction
|
||||||
import net.minecraft.core.Vec3i
|
import net.minecraft.core.Vec3i
|
||||||
@ -8,6 +9,7 @@ import net.minecraft.world.level.block.Rotation
|
|||||||
import net.minecraftforge.common.capabilities.Capability
|
import net.minecraftforge.common.capabilities.Capability
|
||||||
import net.minecraftforge.common.capabilities.ICapabilityProvider
|
import net.minecraftforge.common.capabilities.ICapabilityProvider
|
||||||
import net.minecraftforge.common.util.LazyOptional
|
import net.minecraftforge.common.util.LazyOptional
|
||||||
|
import java.util.Collections
|
||||||
import java.util.EnumMap
|
import java.util.EnumMap
|
||||||
|
|
||||||
internal inline val Direction.blockRotation
|
internal inline val Direction.blockRotation
|
||||||
@ -25,6 +27,10 @@ operator fun BlockPos.plus(other: BlockRotation): BlockPos {
|
|||||||
return this + other.normal
|
return this + other.normal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class RelativeSide {
|
||||||
|
FRONT, BACK, LEFT, RIGHT, TOP, BOTTOM
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents unique block orientation in space, by providing [front] and [top] directions
|
* Represents unique block orientation in space, by providing [front] and [top] directions
|
||||||
*
|
*
|
||||||
@ -83,6 +89,36 @@ enum class BlockRotation(
|
|||||||
val bottom: Direction = top.opposite
|
val bottom: Direction = top.opposite
|
||||||
val back: Direction = front.opposite
|
val back: Direction = front.opposite
|
||||||
|
|
||||||
|
private val _dir2Side = EnumMap<Direction, RelativeSide>(Direction::class.java)
|
||||||
|
private val _side2Dir = EnumMap<RelativeSide, Direction>(RelativeSide::class.java)
|
||||||
|
|
||||||
|
val dir2Side: Map<Direction, RelativeSide> = Collections.unmodifiableMap(_dir2Side)
|
||||||
|
val side2Dir: Map<RelativeSide, Direction> = Collections.unmodifiableMap(_side2Dir)
|
||||||
|
|
||||||
|
init {
|
||||||
|
_side2Dir[RelativeSide.FRONT] = front
|
||||||
|
_side2Dir[RelativeSide.BACK] = back
|
||||||
|
_side2Dir[RelativeSide.LEFT] = left
|
||||||
|
_side2Dir[RelativeSide.RIGHT] = right
|
||||||
|
_side2Dir[RelativeSide.TOP] = top
|
||||||
|
_side2Dir[RelativeSide.BOTTOM] = bottom
|
||||||
|
|
||||||
|
_dir2Side[front] = RelativeSide.FRONT
|
||||||
|
_dir2Side[back] = RelativeSide.BACK
|
||||||
|
_dir2Side[left] = RelativeSide.LEFT
|
||||||
|
_dir2Side[right] = RelativeSide.RIGHT
|
||||||
|
_dir2Side[top] = RelativeSide.TOP
|
||||||
|
_dir2Side[bottom] = RelativeSide.BOTTOM
|
||||||
|
}
|
||||||
|
|
||||||
|
fun dir2Side(direction: Direction): RelativeSide {
|
||||||
|
return _dir2Side[direction]!!
|
||||||
|
}
|
||||||
|
|
||||||
|
fun side2Dir(side: RelativeSide): Direction {
|
||||||
|
return _side2Dir[side]!!
|
||||||
|
}
|
||||||
|
|
||||||
operator fun component1() = front
|
operator fun component1() = front
|
||||||
operator fun component2() = top
|
operator fun component2() = top
|
||||||
operator fun component3() = left
|
operator fun component3() = left
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package ru.dbotthepony.mc.otm.core.nbt
|
package ru.dbotthepony.mc.otm.core.nbt
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement
|
||||||
|
import it.unimi.dsi.fastutil.io.FastByteArrayInputStream
|
||||||
|
import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream
|
||||||
import net.minecraft.nbt.ByteArrayTag
|
import net.minecraft.nbt.ByteArrayTag
|
||||||
import net.minecraft.nbt.ByteTag
|
import net.minecraft.nbt.ByteTag
|
||||||
import net.minecraft.nbt.CompoundTag
|
import net.minecraft.nbt.CompoundTag
|
||||||
@ -10,11 +13,14 @@ import net.minecraft.nbt.IntTag
|
|||||||
import net.minecraft.nbt.ListTag
|
import net.minecraft.nbt.ListTag
|
||||||
import net.minecraft.nbt.LongArrayTag
|
import net.minecraft.nbt.LongArrayTag
|
||||||
import net.minecraft.nbt.LongTag
|
import net.minecraft.nbt.LongTag
|
||||||
|
import net.minecraft.nbt.NbtAccounter
|
||||||
import net.minecraft.nbt.NbtUtils
|
import net.minecraft.nbt.NbtUtils
|
||||||
import net.minecraft.nbt.ShortTag
|
import net.minecraft.nbt.ShortTag
|
||||||
import net.minecraft.nbt.StringTag
|
import net.minecraft.nbt.StringTag
|
||||||
import net.minecraft.nbt.Tag
|
import net.minecraft.nbt.Tag
|
||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
|
import ru.dbotthepony.mc.otm.core.util.readJson
|
||||||
|
import ru.dbotthepony.mc.otm.core.util.writeJson
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
operator fun CompoundTag.set(index: String, value: Tag) = put(index, value)
|
operator fun CompoundTag.set(index: String, value: Tag) = put(index, value)
|
||||||
@ -132,3 +138,18 @@ fun CompoundTag.getUUIDSafe(key: String): UUID? {
|
|||||||
val value = this[key] as? IntArrayTag ?: return null
|
val value = this[key] as? IntArrayTag ?: return null
|
||||||
return NbtUtils.loadUUID(value)
|
return NbtUtils.loadUUID(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun CompoundTag.putJson(key: String, json: JsonElement) {
|
||||||
|
val bytes = FastByteArrayOutputStream()
|
||||||
|
bytes.writeJson(json)
|
||||||
|
putByteArray(key, bytes.array.copyOfRange(0, bytes.length))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun CompoundTag.getJson(key: String, sizeLimit: NbtAccounter = NbtAccounter.UNLIMITED): JsonElement? {
|
||||||
|
val bytes = getByteArray(key)
|
||||||
|
|
||||||
|
if (bytes.isEmpty())
|
||||||
|
return null
|
||||||
|
|
||||||
|
return FastByteArrayInputStream(bytes).readJson(sizeLimit)
|
||||||
|
}
|
||||||
|
@ -7,7 +7,7 @@ import net.minecraftforge.network.NetworkDirection
|
|||||||
import net.minecraftforge.network.NetworkEvent
|
import net.minecraftforge.network.NetworkEvent
|
||||||
import org.apache.logging.log4j.LogManager
|
import org.apache.logging.log4j.LogManager
|
||||||
import ru.dbotthepony.mc.otm.android.feature.ItemEntityDataPacket
|
import ru.dbotthepony.mc.otm.android.feature.ItemEntityDataPacket
|
||||||
import ru.dbotthepony.mc.otm.block.entity.SynchronizedBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.client.minecraft
|
import ru.dbotthepony.mc.otm.client.minecraft
|
||||||
import java.util.function.Supplier
|
import java.util.function.Supplier
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ class BlockEntitySyncPacket(val position: BlockPos, val buffer: ByteArray, val v
|
|||||||
|
|
||||||
context.enqueueWork {
|
context.enqueueWork {
|
||||||
val level = minecraft.player?.level ?: return@enqueueWork
|
val level = minecraft.player?.level ?: return@enqueueWork
|
||||||
val blockEntity = level.getBlockEntity(position) as? SynchronizedBlockEntity ?: return@enqueueWork
|
val blockEntity = level.getBlockEntity(position) as? MatteryBlockEntity ?: return@enqueueWork
|
||||||
|
|
||||||
try {
|
try {
|
||||||
blockEntity.synchronizer.read(FastByteArrayInputStream(buffer, 0, validBytes))
|
blockEntity.synchronizer.read(FastByteArrayInputStream(buffer, 0, validBytes))
|
||||||
|
Loading…
Reference in New Issue
Block a user