Compute block shapes in background, reduces mod startup time to 1/3 of original

This commit is contained in:
DBotThePony 2024-01-05 23:50:10 +07:00
parent 808f152cc3
commit 9be5ca359d
Signed by: DBot
GPG Key ID: DCC23B5715498507
12 changed files with 117 additions and 52 deletions

View File

@ -55,8 +55,8 @@ abstract class CableBlock(properties: Properties) : MatteryBlock(properties) {
) )
} }
protected fun generateShapes(halfCoreSize: Double): ImmutableMap<BlockState, VoxelShape> { protected fun generateShapes(halfCoreSize: Double): Map<BlockState, VoxelShape> {
return getShapeForEachState { getShapeFor(it, halfCoreSize) } return getShapeForEachStateMattery { getShapeFor(it, halfCoreSize) }
} }
@Suppress("OVERRIDE_DEPRECATION") @Suppress("OVERRIDE_DEPRECATION")

View File

@ -5,6 +5,7 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
import it.unimi.dsi.fastutil.objects.ObjectIterators import it.unimi.dsi.fastutil.objects.ObjectIterators
import net.minecraft.ChatFormatting import net.minecraft.ChatFormatting
import net.minecraft.Util
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.core.Direction import net.minecraft.core.Direction
import net.minecraft.core.particles.DustParticleOptions import net.minecraft.core.particles.DustParticleOptions
@ -32,41 +33,40 @@ import ru.dbotthepony.mc.otm.block.entity.IRedstoneControlled
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity 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.client.isShiftDown
import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.core.ITooltippable import ru.dbotthepony.mc.otm.core.ITooltippable
import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.addAll
import ru.dbotthepony.mc.otm.core.addDescriptionFunctions import ru.dbotthepony.mc.otm.core.addDescriptionFunctions
import ru.dbotthepony.mc.otm.core.addDescriptionLines import ru.dbotthepony.mc.otm.core.asSupplier
import ru.dbotthepony.mc.otm.core.collect.SupplierMap
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.component1 import ru.dbotthepony.mc.otm.core.math.component1
import ru.dbotthepony.mc.otm.core.math.component2 import ru.dbotthepony.mc.otm.core.math.component2
import ru.dbotthepony.mc.otm.core.math.component3 import ru.dbotthepony.mc.otm.core.math.component3
import ru.dbotthepony.mc.otm.core.stream
import ru.dbotthepony.mc.otm.core.tagNotNull import ru.dbotthepony.mc.otm.core.tagNotNull
import ru.dbotthepony.mc.otm.once import ru.dbotthepony.mc.otm.once
import java.util.stream.Stream import java.util.concurrent.Callable
import java.util.function.Function
import java.util.function.Supplier
fun Block.getShapeForEachState(properties: List<Property<*>>, fn: (BlockState) -> VoxelShape): Map<BlockState, VoxelShape> { fun Block.getShapeForEachState(properties: List<Property<*>>, fn: (BlockState) -> VoxelShape): Map<BlockState, VoxelShape> {
val builder = ImmutableMap.Builder<BlockState, VoxelShape>() val builder = Object2ObjectArrayMap<BlockState, Supplier<VoxelShape>>()
if (properties.isEmpty()) { if (properties.isEmpty()) {
val shape = fn(stateDefinition.possibleStates.first()) val shape = fn(stateDefinition.possibleStates.first())
for (state in stateDefinition.possibleStates) { for (state in stateDefinition.possibleStates) {
builder.put(state, shape) builder.put(state, Supplier { shape })
} }
} else { } else {
val cache = Object2ObjectArrayMap<List<Any>, VoxelShape>() val cache = Object2ObjectArrayMap<List<Any>, Supplier<VoxelShape>>()
for (state in stateDefinition.possibleStates) { for (state in stateDefinition.possibleStates) {
builder.put(state, cache.computeIfAbsent(properties.map { state[it] }, Object2ObjectFunction { fn(state) })) builder.put(state, cache.computeIfAbsent(properties.map { state[it] }, Object2ObjectFunction { Util.backgroundExecutor().submit(Callable { fn(state) }).asSupplier() }))
} }
} }
return builder.build() return SupplierMap(builder)
} }
fun Block.getShapeForEachState(property: Property<*>, fn: (BlockState) -> VoxelShape): Map<BlockState, VoxelShape> { fun Block.getShapeForEachState(property: Property<*>, fn: (BlockState) -> VoxelShape): Map<BlockState, VoxelShape> {
@ -107,6 +107,15 @@ open class MatteryBlock(properties: Properties = DEFAULT_PROPERTIES) : Block(pro
super.setPlacedBy(level, blockPos, blockState, entity, itemStack) super.setPlacedBy(level, blockPos, blockState, entity, itemStack)
} }
@Deprecated("Use OTM specific one", level = DeprecationLevel.ERROR, replaceWith = ReplaceWith("this.getShapeForEachStateMattery"))
override fun getShapeForEachState(mapper: Function<BlockState, VoxelShape>): ImmutableMap<BlockState, VoxelShape> {
return super.getShapeForEachState(mapper)
}
fun getShapeForEachStateMattery(mapper: (BlockState) -> VoxelShape): Map<BlockState, VoxelShape> {
return getShapeForEachState(ArrayList(stateDefinition.properties), mapper)
}
@Suppress("OVERRIDE_DEPRECATION") @Suppress("OVERRIDE_DEPRECATION")
override fun use( override fun use(
blockState: BlockState, blockState: BlockState,

View File

@ -33,7 +33,7 @@ class EngineBlock : RotatableMatteryBlock(Properties.of().mapColor(MapColor.COLO
return BlockRotationFreedom.DIRECTIONAL return BlockRotationFreedom.DIRECTIONAL
} }
private val shapes = getShapeForEachState { BlockShapes.ENGINE.rotateFromNorth(it[rotationProperty]).computeShape() } private val shapes = getShapeForEachStateMattery { BlockShapes.ENGINE.rotateFromNorth(it[rotationProperty]).computeShape() }
override fun getShape( override fun getShape(
p_60555_: BlockState, p_60555_: BlockState,

View File

@ -22,7 +22,7 @@ class HoloSignBlock : RotatableMatteryBlock(DEFAULT_MACHINE_PROPERTIES), EntityB
return HoloSignBlockEntity(p_153215_, p_153216_) return HoloSignBlockEntity(p_153215_, p_153216_)
} }
private val shapes = getShapeForEachState { BlockShapes.HOLO_SIGN.rotateFromNorth(it[rotationProperty]).computeShape() } private val shapes = getShapeForEachStateMattery { BlockShapes.HOLO_SIGN.rotateFromNorth(it[rotationProperty]).computeShape() }
override fun getShape( override fun getShape(
pState: BlockState, pState: BlockState,

View File

@ -23,12 +23,12 @@ class MatterPanelBlock(val color: DyeColor?) : RotatableMatteryBlock(DEFAULT_MAC
return MatterPanelBlockEntity(blockPos, blockState) return MatterPanelBlockEntity(blockPos, blockState)
} }
private val shapes: ImmutableMap<BlockState, VoxelShape> private val shapes: Map<BlockState, VoxelShape>
init { init {
registerDefaultState(getStateDefinition().any().setValue(BlockRotationFreedom.DIRECTIONAL.property, BlockRotation.SOUTH)) registerDefaultState(getStateDefinition().any().setValue(BlockRotationFreedom.DIRECTIONAL.property, BlockRotation.SOUTH))
shapes = getShapeForEachState { shapes = getShapeForEachStateMattery {
when (it[BlockRotationFreedom.DIRECTIONAL.property].front) { when (it[BlockRotationFreedom.DIRECTIONAL.property].front) {
Direction.NORTH -> Shapes.box( Direction.NORTH -> Shapes.box(
0.0, 0.0,

View File

@ -22,6 +22,7 @@ import ru.dbotthepony.mc.otm.block.CableBlock
import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock
import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity
import ru.dbotthepony.mc.otm.block.entity.storage.StorageBusBlockEntity import ru.dbotthepony.mc.otm.block.entity.storage.StorageBusBlockEntity
import ru.dbotthepony.mc.otm.block.getShapeForEachState
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.core.get import ru.dbotthepony.mc.otm.core.get
import ru.dbotthepony.mc.otm.core.math.BlockRotation import ru.dbotthepony.mc.otm.core.math.BlockRotation
@ -88,7 +89,7 @@ class StorageBusBlock : RotatableMatteryBlock(DEFAULT_MACHINE_PROPERTIES), Entit
return BlockEntityTicker { _, _, _, tile -> if (tile is StorageBusBlockEntity) tile.tick() } return BlockEntityTicker { _, _, _, tile -> if (tile is StorageBusBlockEntity) tile.tick() }
} }
private val shapes = getShapeForEachState { private val shapes = getShapeForEachStateMattery {
Shapes.joinUnoptimized(CableBlock.getShapeFor(it, 0.185), BlockShapes.STORAGE_BUS.rotateFromNorth(it[rotationProperty]).computeShape(), BooleanOp.OR) Shapes.joinUnoptimized(CableBlock.getShapeFor(it, 0.185), BlockShapes.STORAGE_BUS.rotateFromNorth(it[rotationProperty]).computeShape(), BooleanOp.OR)
} }

View File

@ -89,7 +89,7 @@ class StorageImporterBlock : RotatableMatteryBlock(DEFAULT_MACHINE_PROPERTIES),
MatteryPoweredBlockEntity.appendHoverText(itemStack, blockAccessor, components, tooltipType) MatteryPoweredBlockEntity.appendHoverText(itemStack, blockAccessor, components, tooltipType)
} }
private val shapes = getShapeForEachState { private val shapes = getShapeForEachStateMattery {
Shapes.joinUnoptimized(CableBlock.getShapeFor(it, 0.185), BlockShapes.STORAGE_IMPORTER.rotateFromNorth(it[rotationProperty]).computeShape(), BooleanOp.OR) Shapes.joinUnoptimized(CableBlock.getShapeFor(it, 0.185), BlockShapes.STORAGE_IMPORTER.rotateFromNorth(it[rotationProperty]).computeShape(), BooleanOp.OR)
} }
@ -162,7 +162,7 @@ class StorageExporterBlock : RotatableMatteryBlock(DEFAULT_MACHINE_PROPERTIES),
return super.getStateForPlacement(context)?.setValue(BlockRotationFreedom.DIRECTIONAL.property, BlockRotation.of(-context.clickedFace)) return super.getStateForPlacement(context)?.setValue(BlockRotationFreedom.DIRECTIONAL.property, BlockRotation.of(-context.clickedFace))
} }
private val shapes = getShapeForEachState { private val shapes = getShapeForEachStateMattery {
Shapes.joinUnoptimized(CableBlock.getShapeFor(it, 0.185), BlockShapes.STORAGE_EXPORTER.rotateFromNorth(it[rotationProperty]).computeShape(), BooleanOp.OR) Shapes.joinUnoptimized(CableBlock.getShapeFor(it, 0.185), BlockShapes.STORAGE_EXPORTER.rotateFromNorth(it[rotationProperty]).computeShape(), BooleanOp.OR)
} }

View File

@ -1,5 +1,7 @@
package ru.dbotthepony.mc.otm.block.tech package ru.dbotthepony.mc.otm.block.tech
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
import net.minecraft.Util
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.core.Direction import net.minecraft.core.Direction
import net.minecraft.world.item.context.BlockPlaceContext import net.minecraft.world.item.context.BlockPlaceContext
@ -15,12 +17,14 @@ import net.minecraft.world.level.block.state.StateDefinition
import net.minecraft.world.level.block.state.properties.EnumProperty import net.minecraft.world.level.block.state.properties.EnumProperty
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.SERVER_IS_LIVE
import ru.dbotthepony.mc.otm.block.MatteryBlock import ru.dbotthepony.mc.otm.block.MatteryBlock
import ru.dbotthepony.mc.otm.block.entity.tech.EnergyCounterBlockEntity import ru.dbotthepony.mc.otm.block.entity.tech.EnergyCounterBlockEntity
import ru.dbotthepony.mc.otm.once import ru.dbotthepony.mc.otm.core.asSupplier
import ru.dbotthepony.mc.otm.core.collect.SupplierMap
import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.shapes.BlockShapes import ru.dbotthepony.mc.otm.shapes.BlockShapes
import java.util.concurrent.Callable
import java.util.function.Supplier
class EnergyCounterBlock : MatteryBlock(DEFAULT_MACHINE_PROPERTIES), EntityBlock { class EnergyCounterBlock : MatteryBlock(DEFAULT_MACHINE_PROPERTIES), EntityBlock {
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity { override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity {
@ -63,9 +67,11 @@ class EnergyCounterBlock : MatteryBlock(DEFAULT_MACHINE_PROPERTIES), EntityBlock
p_49915_.add(INPUT_DIRECTION, IF_DIRECTION) p_49915_.add(INPUT_DIRECTION, IF_DIRECTION)
} }
private val SHAPES = HashMap<BlockState, VoxelShape>() private val shapes: Map<BlockState, VoxelShape>
init { init {
val shapes = Object2ObjectOpenHashMap<BlockState, Supplier<VoxelShape>>()
for (state in stateDefinition.possibleStates) { for (state in stateDefinition.possibleStates) {
val input: Direction = state.getValue(INPUT_DIRECTION) val input: Direction = state.getValue(INPUT_DIRECTION)
val iface: Direction = state.getValue(IF_DIRECTION) val iface: Direction = state.getValue(IF_DIRECTION)
@ -101,8 +107,10 @@ class EnergyCounterBlock : MatteryBlock(DEFAULT_MACHINE_PROPERTIES), EntityBlock
} }
} }
SHAPES[state] = shape.computeShape() shapes[state] = Util.backgroundExecutor().submit(Callable { shape.computeShape() }).asSupplier()
} }
this.shapes = SupplierMap(shapes)
} }
override fun getShape( override fun getShape(
@ -111,7 +119,7 @@ class EnergyCounterBlock : MatteryBlock(DEFAULT_MACHINE_PROPERTIES), EntityBlock
p_60557_: BlockPos, p_60557_: BlockPos,
p_60558_: CollisionContext p_60558_: CollisionContext
): VoxelShape { ): VoxelShape {
return SHAPES[blockState] ?: super.getShape(blockState, p_60556_, p_60557_, p_60558_) return shapes[blockState] ?: super.getShape(blockState, p_60556_, p_60557_, p_60558_)
} }
companion object { companion object {

View File

@ -28,11 +28,13 @@ import ru.dbotthepony.mc.otm.block.addSimpleDescription
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.blackhole.BlackHoleBlockEntity import ru.dbotthepony.mc.otm.block.entity.blackhole.BlackHoleBlockEntity
import ru.dbotthepony.mc.otm.block.entity.WorkerState import ru.dbotthepony.mc.otm.block.entity.WorkerState
import ru.dbotthepony.mc.otm.core.collect.SupplierList
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.plus 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.core.needsNoPowerDescription import ru.dbotthepony.mc.otm.core.needsNoPowerDescription
import ru.dbotthepony.mc.otm.core.runInBackground
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
import ru.dbotthepony.mc.otm.registry.MBlocks import ru.dbotthepony.mc.otm.registry.MBlocks
@ -140,7 +142,7 @@ class BlockGravitationStabilizer : RotatableMatteryBlock(props), EntityBlock {
p_60557_: BlockPos, p_60557_: BlockPos,
p_60558_: CollisionContext p_60558_: CollisionContext
): VoxelShape { ): VoxelShape {
return SHAPES[p_60555_[BlockRotationFreedom.DIRECTIONAL].ordinal] return shapes[p_60555_[BlockRotationFreedom.DIRECTIONAL].ordinal]
} }
init { init {
@ -151,13 +153,13 @@ class BlockGravitationStabilizer : RotatableMatteryBlock(props), EntityBlock {
} }
companion object { companion object {
private val SHAPES = arrayOf( private val shapes = SupplierList.ofFuture(
BlockShapes.GRAVITATION_STABILIZER.rotateAroundX(PI / 2).computeShape(), runInBackground { BlockShapes.GRAVITATION_STABILIZER.rotateAroundX(PI / 2).computeShape() },
BlockShapes.GRAVITATION_STABILIZER.rotateAroundX(-PI / 2).computeShape(), runInBackground { BlockShapes.GRAVITATION_STABILIZER.rotateAroundX(-PI / 2).computeShape() },
BlockShapes.GRAVITATION_STABILIZER.computeShape(), runInBackground { BlockShapes.GRAVITATION_STABILIZER.computeShape() },
BlockShapes.GRAVITATION_STABILIZER.rotateFromSouth(Direction.NORTH).computeShape(), runInBackground { BlockShapes.GRAVITATION_STABILIZER.rotateFromSouth(Direction.NORTH).computeShape() },
BlockShapes.GRAVITATION_STABILIZER.rotateFromSouth(Direction.WEST).computeShape(), runInBackground { BlockShapes.GRAVITATION_STABILIZER.rotateFromSouth(Direction.WEST).computeShape() },
BlockShapes.GRAVITATION_STABILIZER.rotateFromSouth(Direction.EAST).computeShape() runInBackground { BlockShapes.GRAVITATION_STABILIZER.rotateFromSouth(Direction.EAST).computeShape() },
) )
fun getBoundingBlock(level: Level, blockState: BlockState, blockPos: BlockPos): BlockState { fun getBoundingBlock(level: Level, blockState: BlockState, blockPos: BlockPos): BlockState {
@ -206,7 +208,7 @@ class BlockGravitationStabilizerLens : RotatableMatteryBlock(props) {
p_60557_: BlockPos, p_60557_: BlockPos,
p_60558_: CollisionContext p_60558_: CollisionContext
): VoxelShape { ): VoxelShape {
return SHAPES[p_60555_[BlockRotationFreedom.DIRECTIONAL].front.ordinal] return shapes[p_60555_[BlockRotationFreedom.DIRECTIONAL].front.ordinal]
} }
companion object { companion object {
@ -218,13 +220,13 @@ class BlockGravitationStabilizerLens : RotatableMatteryBlock(props) {
return blockPos + blockState.getValue(BlockRotationFreedom.DIRECTIONAL.property).front.opposite.normal return blockPos + blockState.getValue(BlockRotationFreedom.DIRECTIONAL.property).front.opposite.normal
} }
private val SHAPES = arrayOf( private val shapes = SupplierList.ofFuture(
BlockShapes.GRAVITATION_STABILIZER_LENS.rotateAroundX(PI / 2).computeShape(), runInBackground { BlockShapes.GRAVITATION_STABILIZER_LENS.rotateAroundX(PI / 2).computeShape() },
BlockShapes.GRAVITATION_STABILIZER_LENS.rotateAroundX(-PI / 2).computeShape(), runInBackground { BlockShapes.GRAVITATION_STABILIZER_LENS.rotateAroundX(-PI / 2).computeShape() },
BlockShapes.GRAVITATION_STABILIZER_LENS.computeShape(), runInBackground { BlockShapes.GRAVITATION_STABILIZER_LENS.computeShape() },
BlockShapes.GRAVITATION_STABILIZER_LENS.rotateFromSouth(Direction.NORTH).computeShape(), runInBackground { BlockShapes.GRAVITATION_STABILIZER_LENS.rotateFromSouth(Direction.NORTH).computeShape() },
BlockShapes.GRAVITATION_STABILIZER_LENS.rotateFromSouth(Direction.WEST).computeShape(), runInBackground { BlockShapes.GRAVITATION_STABILIZER_LENS.rotateFromSouth(Direction.WEST).computeShape() },
BlockShapes.GRAVITATION_STABILIZER_LENS.rotateFromSouth(Direction.EAST).computeShape() runInBackground { BlockShapes.GRAVITATION_STABILIZER_LENS.rotateFromSouth(Direction.EAST).computeShape() },
) )
} }
} }

View File

@ -11,6 +11,7 @@ import com.google.gson.JsonElement
import com.google.gson.JsonObject import com.google.gson.JsonObject
import com.google.gson.JsonPrimitive import com.google.gson.JsonPrimitive
import it.unimi.dsi.fastutil.objects.ObjectComparators import it.unimi.dsi.fastutil.objects.ObjectComparators
import net.minecraft.Util
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.NbtAccounter import net.minecraft.nbt.NbtAccounter
@ -52,6 +53,8 @@ import java.math.BigInteger
import java.util.Arrays import java.util.Arrays
import java.util.Spliterators import java.util.Spliterators
import java.util.UUID import java.util.UUID
import java.util.concurrent.Callable
import java.util.concurrent.Future
import java.util.function.Consumer import java.util.function.Consumer
import java.util.function.Supplier import java.util.function.Supplier
import java.util.stream.Stream import java.util.stream.Stream
@ -86,6 +89,14 @@ fun <V> Map<*, V>.asSupplierArray(): Array<Supplier<V>> {
return result as Array<Supplier<V>> return result as Array<Supplier<V>>
} }
fun <V> Future<V>.asSupplier(): Supplier<V> {
return Supplier { get() }
}
fun <V> runInBackground(block: Callable<V>): Future<V> {
return Util.backgroundExecutor().submit(block)
}
operator fun IItemHandler.get(index: Int): ItemStack = getStackInSlot(index) operator fun IItemHandler.get(index: Int): ItemStack = getStackInSlot(index)
operator fun JsonObject.set(s: String, value: JsonElement) = add(s, value) operator fun JsonObject.set(s: String, value: JsonElement) = add(s, value)

View File

@ -1,5 +1,7 @@
package ru.dbotthepony.mc.otm.core.collect package ru.dbotthepony.mc.otm.core.collect
import ru.dbotthepony.mc.otm.core.stream
import java.util.concurrent.Future
import java.util.function.Supplier import java.util.function.Supplier
import java.util.stream.Stream import java.util.stream.Stream
@ -12,7 +14,7 @@ class SupplierList<T> : AbstractList<T> {
} }
constructor(getters: Stream<Supplier<T>>) : super() { constructor(getters: Stream<Supplier<T>>) : super() {
this.getters = getters.toArray(::arrayOfNulls) this.getters = getters.toArray { arrayOfNulls<Supplier<T>>(it) }
} }
constructor(vararg getters: Supplier<T>) : super() { constructor(vararg getters: Supplier<T>) : super() {
@ -29,4 +31,14 @@ class SupplierList<T> : AbstractList<T> {
override fun get(index: Int): T { override fun get(index: Int): T {
return getters[index].get() return getters[index].get()
} }
companion object {
fun <T> ofLazy(vararg values: Lazy<T>): SupplierList<T> {
return SupplierList(values.stream().map { Supplier { it.value } })
}
fun <T> ofFuture(vararg values: Future<T>): SupplierList<T> {
return SupplierList(values.stream().map { Supplier { it.get() } })
}
}
} }

View File

@ -1,31 +1,53 @@
package ru.dbotthepony.mc.otm.core.collect package ru.dbotthepony.mc.otm.core.collect
import com.google.common.collect.ImmutableMap
import com.google.common.collect.ImmutableSet import com.google.common.collect.ImmutableSet
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
import ru.dbotthepony.mc.otm.core.stream
import java.util.function.Supplier import java.util.function.Supplier
import java.util.stream.Stream import java.util.stream.Stream
class SupplierMap<K, T> : AbstractMap<K, T> { class SupplierMap<K, T>(values: Stream<Pair<K, Supplier<T>>>) : Map<K, T> {
private val backing = Object2ObjectOpenHashMap<K, Supplier<T>>()
override val entries: Set<Map.Entry<K, T>> override val entries: Set<Map.Entry<K, T>>
override val keys: Set<K>
get() = backing.keys
override val size: Int
get() = entries.size
override val values: Collection<T>
constructor(vararg mValues: Pair<K, Supplier<T>>) : super() { init {
entries = ImmutableSet.copyOf(mValues.map { Entry(it.first, it.second) }) values.forEach {
backing[it.first] = it.second
}
entries = ImmutableSet.copyOf(backing.entries.map { Entry(it.key, it.value) })
this.values = SupplierList(backing.values)
} }
constructor(mValues: Collection<Pair<K, Supplier<T>>>) : super() { override fun containsKey(key: K): Boolean {
entries = ImmutableSet.copyOf(mValues.map { Entry(it.first, it.second) }) return key in keys
} }
constructor(mValues: Stream<Pair<K, Supplier<T>>>) : super() { override fun containsValue(value: T): Boolean {
entries = mValues.map { Entry(it.first, it.second) }.collect(ImmutableSet.toImmutableSet()) return value in values
} }
constructor(mValues: Map<K, () -> T>) : super() { override fun get(key: K): T? {
entries = ImmutableSet.copyOf(mValues.map { Entry(it.key, it.value) }) return backing[key]?.get()
} }
override fun isEmpty(): Boolean {
return entries.isEmpty()
}
constructor(vararg mValues: Pair<K, Supplier<T>>) : this((mValues as Array<Pair<K, Supplier<T>>>).stream())
constructor(mValues: Collection<Pair<K, Supplier<T>>>) : this(mValues.stream())
constructor(mValues: Map<K, Supplier<T>>) : this(mValues.entries.stream().map { it.key to it.value })
private inner class Entry( private inner class Entry(
override val key: K, override val key: K,
private val getter: Supplier<T> val getter: Supplier<T>
) : Map.Entry<K, T> { ) : Map.Entry<K, T> {
override val value: T override val value: T
get() = getter.get() get() = getter.get()