Merge branch '1.20.2' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into 1.20.1
This commit is contained in:
commit
0b7e54b4ef
@ -0,0 +1,24 @@
|
||||
package ru.dbotthepony.mc.otm.mixin;
|
||||
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import ru.dbotthepony.mc.otm.core.MultiblockKt;
|
||||
|
||||
// because i know
|
||||
// someone
|
||||
// somewhere
|
||||
// will try to break the system
|
||||
// either on purpose or accidentally because of other mod
|
||||
@Mixin(BlockEntity.class)
|
||||
public abstract class BlockEntityMixin {
|
||||
@Inject(
|
||||
at = @At("TAIL"),
|
||||
method = "setRemoved()V"
|
||||
)
|
||||
public void setRemovedListener(CallbackInfo ci) {
|
||||
MultiblockKt.onBlockEntityInvalidated((BlockEntity) (Object) this);
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package ru.dbotthepony.mc.otm.mixin;
|
||||
|
||||
import net.minecraft.client.resources.SplashManager;
|
||||
import net.minecraft.server.packs.resources.ResourceManager;
|
||||
import net.minecraft.util.profiling.ProfilerFiller;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mixin(SplashManager.class)
|
||||
public abstract class SplashManagerMixin {
|
||||
@Shadow
|
||||
public List<String> splashes;
|
||||
|
||||
@Inject(
|
||||
at = @At("TAIL"),
|
||||
method = "apply(Ljava/util/List;Lnet/minecraft/server/packs/resources/ResourceManager;Lnet/minecraft/util/profiling/ProfilerFiller;)V"
|
||||
)
|
||||
public void otmSplashes(List<String> splashes, ResourceManager p_118879_, ProfilerFiller p_118880_, CallbackInfo ci) {
|
||||
this.splashes.add("42 is the answer!");
|
||||
this.splashes.add("Now with matter!");
|
||||
this.splashes.add("Now with four dimensions!");
|
||||
this.splashes.add("Now with more ways to slice Creepers!");
|
||||
this.splashes.add("Batteries not included!");
|
||||
this.splashes.add("As it was 13 nanoseconds ago!");
|
||||
this.splashes.add("Smart AI is smart enough to fail Turing test!");
|
||||
this.splashes.add("Neural computing!");
|
||||
this.splashes.add("Swimming through quantum field!");
|
||||
this.splashes.add("For biological and digital alike!");
|
||||
this.splashes.add("Digital is the next form of Biological!");
|
||||
|
||||
this.splashes.add("Also try Starbound!");
|
||||
this.splashes.add("Also try No Man's Sky!");
|
||||
this.splashes.add("Also try Factorio!");
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package ru.dbotthepony.mc.otm.block
|
||||
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.EntityBlock
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.entity.BlockEntityTicker
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import ru.dbotthepony.mc.otm.block.entity.MultiblockTestBlockEntity
|
||||
|
||||
class MultiblockTestBlock : MatteryBlock(), EntityBlock {
|
||||
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity {
|
||||
return MultiblockTestBlockEntity(blockPos, blockState)
|
||||
}
|
||||
|
||||
override fun <T : BlockEntity?> getTicker(level: Level, blockState: BlockState, blockEntityType: BlockEntityType<T>): BlockEntityTicker<T>? {
|
||||
if (level.isClientSide)
|
||||
return null
|
||||
|
||||
return BlockEntityTicker { _, _, _, tile -> if (tile is MultiblockTestBlockEntity) tile.tick() }
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
package ru.dbotthepony.mc.otm.block.entity
|
||||
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.tags.BlockTags
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.entity.FurnaceBlockEntity
|
||||
import net.minecraft.world.level.block.entity.HopperBlockEntity
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import ru.dbotthepony.mc.otm.core.multiblockConfiguration
|
||||
import ru.dbotthepony.mc.otm.core.multiblockEntity
|
||||
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
||||
import ru.dbotthepony.mc.otm.registry.MBlocks
|
||||
|
||||
class MultiblockTestBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryBlockEntity(MBlockEntities.MULTIBLOCK_TEST, blockPos, blockState) {
|
||||
val config = CONFIG.create(blockPos)
|
||||
|
||||
override fun tick() {
|
||||
super.tick()
|
||||
|
||||
if (config.update(level!!)) {
|
||||
println("It matches!")
|
||||
println("hopper block entities: ${config.blockEntities(HOPPERS)}")
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val HOPPERS = multiblockEntity<HopperBlockEntity>()
|
||||
private val FURNACES = multiblockEntity<FurnaceBlockEntity>()
|
||||
|
||||
val CONFIG = multiblockConfiguration {
|
||||
block(MBlocks.MULTIBLOCK_TEST)
|
||||
|
||||
and {
|
||||
top {
|
||||
or {
|
||||
block(Blocks.HOPPER)
|
||||
block(Blocks.CHEST)
|
||||
block(BlockTags.PLANKS)
|
||||
}
|
||||
|
||||
tag(HOPPERS)
|
||||
}
|
||||
|
||||
left(Blocks.FURNACE) {
|
||||
tag(FURNACES)
|
||||
|
||||
top {
|
||||
or {
|
||||
block(Blocks.HOPPER)
|
||||
block(Blocks.CHEST)
|
||||
block(BlockTags.PLANKS)
|
||||
}
|
||||
|
||||
tag(HOPPERS)
|
||||
}
|
||||
}
|
||||
|
||||
right(Blocks.FURNACE) {
|
||||
tag(FURNACES)
|
||||
|
||||
top {
|
||||
or {
|
||||
block(Blocks.HOPPER)
|
||||
block(Blocks.CHEST)
|
||||
block(BlockTags.PLANKS)
|
||||
}
|
||||
|
||||
tag(HOPPERS)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -66,7 +66,7 @@ class PainterBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDe
|
||||
}
|
||||
|
||||
override fun fill(resource: FluidStack, action: IFluidHandler.FluidAction): Int {
|
||||
if (resource.isEmpty || resource.fluid != Fluids.WATER || waterStored() >= MAX_WATER_STORAGE) return 0
|
||||
if (resource.amount <= 0 || resource.fluid != Fluids.WATER || waterStored() >= MAX_WATER_STORAGE) return 0
|
||||
val diff = ((waterStored().toLong() + resource.amount.toLong()).coerceAtMost(MAX_WATER_STORAGE.toLong()) - waterStored().toLong()).toInt()
|
||||
if (action.simulate() || diff == 0) return diff
|
||||
dyeStored[null] = waterStored() + diff
|
||||
|
@ -143,8 +143,8 @@ sealed class AbstractPoweredFurnaceBlockEntity<P : AbstractCookingRecipe, S : Ma
|
||||
return JobContainer.success(
|
||||
ItemJob(
|
||||
recipe.getResultItem(level.registryAccess()).copyWithCount(toProcess),
|
||||
recipe.workTime * MachinesConfig.PLATE_PRESS.workTimeMultiplier,
|
||||
MachinesConfig.PLATE_PRESS.energyConsumption * toProcess,
|
||||
recipe.workTime * config.workTimeMultiplier,
|
||||
config.energyConsumption * toProcess,
|
||||
experience = recipe.experience.sample(level.random) * toProcess))
|
||||
}
|
||||
}
|
||||
|
@ -157,8 +157,8 @@ object Widgets18 {
|
||||
}
|
||||
}
|
||||
|
||||
val LEFT_CONTROLS = SideControls()
|
||||
val RIGHT_CONTROLS = SideControls()
|
||||
val LEFT_CONTROLS = SideControls()
|
||||
val TOP_CONTROLS = SideControls()
|
||||
val BOTTOM_CONTROLS = SideControls()
|
||||
val FRONT_CONTROLS = SideControls()
|
||||
|
@ -16,6 +16,7 @@ import net.minecraft.world.item.ItemStack
|
||||
import ru.dbotthepony.mc.otm.container.util.IContainerSlot
|
||||
import ru.dbotthepony.mc.otm.container.util.containerSlot
|
||||
import ru.dbotthepony.mc.otm.container.util.iterator
|
||||
import ru.dbotthepony.mc.otm.container.util.slotIterator
|
||||
import ru.dbotthepony.mc.otm.core.collect.concatIterators
|
||||
import ru.dbotthepony.mc.otm.core.collect.filter
|
||||
import ru.dbotthepony.mc.otm.core.collect.flatMap
|
||||
@ -154,6 +155,9 @@ class CombinedContainer(containers: Stream<Pair<Container, Iterable<Int>>>) : IM
|
||||
}
|
||||
|
||||
override fun iterator(nonEmpty: Boolean): Iterator<ItemStack> {
|
||||
if (notFullCoverage.isEmpty())
|
||||
return fullCoverage.iterator().flatMap { it.iterator(nonEmpty) }
|
||||
|
||||
return concatIterators(
|
||||
fullCoverage.iterator().flatMap { it.iterator(nonEmpty) },
|
||||
notFullCoverage.values.iterator().flatMap { it.iterator() }.map { it.item }.let { if (nonEmpty) it.filter { it.isNotEmpty } else it }
|
||||
|
@ -66,6 +66,44 @@ interface ISubscriptable<V> {
|
||||
}
|
||||
}
|
||||
|
||||
interface IUnitSubscripable : ISubscriptable<Unit> {
|
||||
fun addListener(listener: Runnable): ISubscriptable.L
|
||||
|
||||
override fun addListener(listener: Consumer<Unit>): ISubscriptable.L {
|
||||
return addListener(Runnable { listener.accept(Unit) })
|
||||
}
|
||||
|
||||
class Impl : IUnitSubscripable, Runnable {
|
||||
private inner class L(val callback: Runnable) : ISubscriptable.L {
|
||||
private var isRemoved = false
|
||||
|
||||
init {
|
||||
subscribers.add(this)
|
||||
}
|
||||
|
||||
override fun remove() {
|
||||
if (!isRemoved) {
|
||||
isRemoved = true
|
||||
queue.add(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val subscribers = ReferenceLinkedOpenHashSet<L>(0)
|
||||
private val queue = ReferenceArraySet<L>(0)
|
||||
|
||||
override fun addListener(listener: Runnable): ISubscriptable.L {
|
||||
return L(listener)
|
||||
}
|
||||
|
||||
override fun run() {
|
||||
queue.forEach { subscribers.remove(it) }
|
||||
queue.clear()
|
||||
subscribers.forEach { it.callback.run() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface IFloatSubcripable : ISubscriptable<Float> {
|
||||
@Deprecated("Use type specific listener")
|
||||
override fun addListener(listener: Consumer<Float>): ISubscriptable.L {
|
||||
|
681
src/main/kotlin/ru/dbotthepony/mc/otm/core/Multiblock.kt
Normal file
681
src/main/kotlin/ru/dbotthepony/mc/otm/core/Multiblock.kt
Normal file
@ -0,0 +1,681 @@
|
||||
package ru.dbotthepony.mc.otm.core
|
||||
|
||||
import com.google.common.collect.ImmutableList
|
||||
import com.google.common.collect.ImmutableSet
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArraySet
|
||||
import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.core.Vec3i
|
||||
import net.minecraft.tags.TagKey
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.LevelAccessor
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.block.Rotation
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import ru.dbotthepony.mc.otm.core.collect.WeakHashSet
|
||||
import ru.dbotthepony.mc.otm.core.collect.collect
|
||||
import ru.dbotthepony.mc.otm.core.collect.map
|
||||
import ru.dbotthepony.mc.otm.core.math.RelativeSide
|
||||
import ru.dbotthepony.mc.otm.core.math.plus
|
||||
import java.util.Collections
|
||||
import java.util.WeakHashMap
|
||||
import java.util.function.Predicate
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
private val blockEntityListeners = WeakHashMap<Level, WeakHashMap<BlockEntity, WeakHashSet<Multiblock>>>()
|
||||
|
||||
fun onBlockEntityInvalidated(blockEntity: BlockEntity) {
|
||||
blockEntityListeners[blockEntity.level]?.get(blockEntity)?.forEach { it.blockEntityRemoved(blockEntity) }
|
||||
blockEntityListeners[blockEntity.level]?.remove(blockEntity)
|
||||
}
|
||||
|
||||
fun interface BlockPredicate {
|
||||
fun test(pos: BlockPos, access: LevelAccessor): Boolean
|
||||
|
||||
fun and(other: BlockPredicate): BlockPredicate {
|
||||
return BlockPredicate { pos, access -> test(pos, access) && other.test(pos, access) }
|
||||
}
|
||||
|
||||
fun or(other: BlockPredicate): BlockPredicate {
|
||||
return BlockPredicate { pos, access -> test(pos, access) || other.test(pos, access) }
|
||||
}
|
||||
|
||||
fun offset(offset: BlockPos): Positioned {
|
||||
return Positioned(offset, this)
|
||||
}
|
||||
|
||||
fun offset(offset: Vec3i): Positioned {
|
||||
return offset(BlockPos(offset))
|
||||
}
|
||||
|
||||
data class Positioned(val offset: BlockPos, val parent: BlockPredicate) : BlockPredicate {
|
||||
override fun test(pos: BlockPos, access: LevelAccessor): Boolean {
|
||||
return parent.test(offset + pos, access)
|
||||
}
|
||||
|
||||
override fun offset(offset: BlockPos): Positioned {
|
||||
return Positioned(this.offset + offset, parent)
|
||||
}
|
||||
}
|
||||
|
||||
data class And(val nodes: ImmutableSet<BlockPredicate>) : BlockPredicate {
|
||||
constructor(vararg nodes: BlockPredicate) : this(ImmutableSet.copyOf(nodes))
|
||||
constructor(nodes: Set<BlockPredicate>) : this(ImmutableSet.copyOf(nodes))
|
||||
|
||||
override fun test(pos: BlockPos, access: LevelAccessor): Boolean {
|
||||
return nodes.all { it.test(pos, access) }
|
||||
}
|
||||
}
|
||||
|
||||
data class Or(val nodes: ImmutableSet<BlockPredicate>) : BlockPredicate {
|
||||
constructor(vararg nodes: BlockPredicate) : this(ImmutableSet.copyOf(nodes))
|
||||
constructor(nodes: Set<BlockPredicate>) : this(ImmutableSet.copyOf(nodes))
|
||||
|
||||
override fun test(pos: BlockPos, access: LevelAccessor): Boolean {
|
||||
return nodes.any { it.test(pos, access) }
|
||||
}
|
||||
}
|
||||
|
||||
object Air : BlockPredicate {
|
||||
override fun test(pos: BlockPos, access: LevelAccessor): Boolean {
|
||||
return access.isEmptyBlock(pos)
|
||||
}
|
||||
}
|
||||
|
||||
object NotAir : BlockPredicate {
|
||||
override fun test(pos: BlockPos, access: LevelAccessor): Boolean {
|
||||
return !access.isEmptyBlock(pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline fun multiblockConfiguration(configurator: MultiblockBuilder.Node.() -> Unit): MultiblockFactory {
|
||||
val builder = MultiblockBuilder()
|
||||
configurator.invoke(builder.root())
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
inline fun <reified T : BlockEntity> multiblockEntity(): MultiblockBuilder.EntityTag<T> {
|
||||
return MultiblockBuilder.EntityTag(T::class)
|
||||
}
|
||||
|
||||
class MultiblockBuilder {
|
||||
private val nodes = Object2ObjectOpenHashMap<BlockPos, Node>()
|
||||
|
||||
// not data classes to allow having multiple tags with same target
|
||||
class EntityTag<T : BlockEntity>(val clazz: KClass<T>) : Predicate<BlockEntity> {
|
||||
override fun test(t: BlockEntity): Boolean {
|
||||
return clazz.isInstance(t)
|
||||
}
|
||||
}
|
||||
|
||||
enum class Strategy {
|
||||
OR, AND
|
||||
}
|
||||
|
||||
@Suppress("unchecked_cast")
|
||||
abstract class BlockPredicates<T : BlockPredicates<T>> {
|
||||
val predicates = ObjectArraySet<BlockPredicate>()
|
||||
val children = ObjectArraySet<BlockPredicates<*>>()
|
||||
|
||||
val blockStateTags = ObjectArraySet<Any>()
|
||||
val blockTags = ObjectArraySet<Any>()
|
||||
val blockEntityTags = ObjectArraySet<EntityTag<*>>()
|
||||
|
||||
fun tagBlockState(value: Any): T {
|
||||
blockStateTags.add(value)
|
||||
return this as T
|
||||
}
|
||||
|
||||
fun tagBlock(value: Any): T {
|
||||
blockTags.add(value)
|
||||
return this as T
|
||||
}
|
||||
|
||||
fun tag(value: EntityTag<*>): T {
|
||||
blockEntityTags.add(value)
|
||||
return this as T
|
||||
}
|
||||
|
||||
fun clear(): T {
|
||||
predicates.clear()
|
||||
return this as T
|
||||
}
|
||||
|
||||
fun predicate(predicate: BlockPredicate): T {
|
||||
predicates.add(predicate)
|
||||
return this as T
|
||||
}
|
||||
|
||||
fun block(block: Block): T {
|
||||
predicates.add { pos, access -> access.getBlockState(pos).`is`(block) }
|
||||
return this as T
|
||||
}
|
||||
|
||||
fun block(block: TagKey<Block>): T {
|
||||
predicates.add { pos, access -> access.getBlockState(pos).`is`(block) }
|
||||
return this as T
|
||||
}
|
||||
|
||||
fun air(): T {
|
||||
predicate(BlockPredicate.Air)
|
||||
return this as T
|
||||
}
|
||||
|
||||
fun block(state: BlockState): T {
|
||||
predicates.add { pos, access -> access.getBlockState(pos) == state }
|
||||
return this as T
|
||||
}
|
||||
|
||||
fun and(): And<T> {
|
||||
return And(this as T)
|
||||
}
|
||||
|
||||
fun or(): Or<T> {
|
||||
return Or(this as T)
|
||||
}
|
||||
|
||||
fun and(configurator: And<T>.() -> Unit): And<T> {
|
||||
return And(this as T).also(configurator)
|
||||
}
|
||||
|
||||
fun or(configurator: Or<T>.() -> Unit): Or<T> {
|
||||
return Or(this as T).also(configurator)
|
||||
}
|
||||
|
||||
protected fun build(pos: BlockPos): MultiblockFactory.Part {
|
||||
return MultiblockFactory.Part(
|
||||
pos, strategy, ImmutableList.copyOf(predicates),
|
||||
children.stream().map { it.build(pos) }.collect(ImmutableList.toImmutableList()),
|
||||
ImmutableSet.copyOf(blockStateTags),
|
||||
ImmutableSet.copyOf(blockTags),
|
||||
ImmutableSet.copyOf(blockEntityTags),
|
||||
)
|
||||
}
|
||||
|
||||
abstract val strategy: Strategy
|
||||
}
|
||||
|
||||
class And<P : BlockPredicates<P>>(val parent: P) : BlockPredicates<And<P>>() {
|
||||
init {
|
||||
parent.children.add(this)
|
||||
}
|
||||
|
||||
fun end() = parent
|
||||
|
||||
override val strategy: Strategy
|
||||
get() = Strategy.AND
|
||||
}
|
||||
|
||||
class Or<P : BlockPredicates<P>>(val parent: P) : BlockPredicates<Or<P>>() {
|
||||
init {
|
||||
parent.children.add(this)
|
||||
}
|
||||
|
||||
fun end() = parent
|
||||
|
||||
override val strategy: Strategy
|
||||
get() = Strategy.OR
|
||||
}
|
||||
|
||||
/**
|
||||
* Behaves as if being [Or] node
|
||||
*/
|
||||
inner class Node(val pos: BlockPos) : BlockPredicates<Node>() {
|
||||
init {
|
||||
check(nodes.put(pos, this) == null) { "Trying to create new node at $pos while already having one" }
|
||||
}
|
||||
|
||||
fun relative(diff: Vec3i): Node {
|
||||
return node(pos + diff)
|
||||
}
|
||||
|
||||
fun relative(dir: Direction): Node {
|
||||
return relative(dir.normal)
|
||||
}
|
||||
|
||||
fun relative(dir: RelativeSide): Node {
|
||||
return relative(dir.default)
|
||||
}
|
||||
|
||||
fun front() = relative(RelativeSide.FRONT)
|
||||
fun back() = relative(RelativeSide.BACK)
|
||||
fun left() = relative(RelativeSide.LEFT)
|
||||
fun right() = relative(RelativeSide.RIGHT)
|
||||
fun top() = relative(RelativeSide.TOP)
|
||||
fun bottom() = relative(RelativeSide.BOTTOM)
|
||||
|
||||
fun front(block: Block) = relative(RelativeSide.FRONT).also { it.block(block) }
|
||||
fun back(block: Block) = relative(RelativeSide.BACK).also { it.block(block) }
|
||||
fun left(block: Block) = relative(RelativeSide.LEFT).also { it.block(block) }
|
||||
fun right(block: Block) = relative(RelativeSide.RIGHT).also { it.block(block) }
|
||||
fun top(block: Block) = relative(RelativeSide.TOP).also { it.block(block) }
|
||||
fun bottom(block: Block) = relative(RelativeSide.BOTTOM).also { it.block(block) }
|
||||
|
||||
fun front(block: BlockState) = relative(RelativeSide.FRONT).also { it.block(block) }
|
||||
fun back(block: BlockState) = relative(RelativeSide.BACK).also { it.block(block) }
|
||||
fun left(block: BlockState) = relative(RelativeSide.LEFT).also { it.block(block) }
|
||||
fun right(block: BlockState) = relative(RelativeSide.RIGHT).also { it.block(block) }
|
||||
fun top(block: BlockState) = relative(RelativeSide.TOP).also { it.block(block) }
|
||||
fun bottom(block: BlockState) = relative(RelativeSide.BOTTOM).also { it.block(block) }
|
||||
|
||||
fun front(predicate: BlockPredicate) = relative(RelativeSide.FRONT).also { it.predicate(predicate) }
|
||||
fun back(predicate: BlockPredicate) = relative(RelativeSide.BACK).also { it.predicate(predicate) }
|
||||
fun left(predicate: BlockPredicate) = relative(RelativeSide.LEFT).also { it.predicate(predicate) }
|
||||
fun right(predicate: BlockPredicate) = relative(RelativeSide.RIGHT).also { it.predicate(predicate) }
|
||||
fun top(predicate: BlockPredicate) = relative(RelativeSide.TOP).also { it.predicate(predicate) }
|
||||
fun bottom(predicate: BlockPredicate) = relative(RelativeSide.BOTTOM).also { it.predicate(predicate) }
|
||||
|
||||
fun front(configurator: Node.() -> Unit) = relative(RelativeSide.FRONT).also(configurator)
|
||||
fun back(configurator: Node.() -> Unit) = relative(RelativeSide.BACK).also(configurator)
|
||||
fun left(configurator: Node.() -> Unit) = relative(RelativeSide.LEFT).also(configurator)
|
||||
fun right(configurator: Node.() -> Unit) = relative(RelativeSide.RIGHT).also(configurator)
|
||||
fun top(configurator: Node.() -> Unit) = relative(RelativeSide.TOP).also(configurator)
|
||||
fun bottom(configurator: Node.() -> Unit) = relative(RelativeSide.BOTTOM).also(configurator)
|
||||
|
||||
fun front(block: Block, configurator: Node.() -> Unit) = relative(RelativeSide.FRONT).also { it.block(block) }.also(configurator)
|
||||
fun back(block: Block, configurator: Node.() -> Unit) = relative(RelativeSide.BACK).also { it.block(block) }.also(configurator)
|
||||
fun left(block: Block, configurator: Node.() -> Unit) = relative(RelativeSide.LEFT).also { it.block(block) }.also(configurator)
|
||||
fun right(block: Block, configurator: Node.() -> Unit) = relative(RelativeSide.RIGHT).also { it.block(block) }.also(configurator)
|
||||
fun top(block: Block, configurator: Node.() -> Unit) = relative(RelativeSide.TOP).also { it.block(block) }.also(configurator)
|
||||
fun bottom(block: Block, configurator: Node.() -> Unit) = relative(RelativeSide.BOTTOM).also { it.block(block) }.also(configurator)
|
||||
|
||||
fun front(block: BlockState, configurator: Node.() -> Unit) = relative(RelativeSide.FRONT).also { it.block(block) }.also(configurator)
|
||||
fun back(block: BlockState, configurator: Node.() -> Unit) = relative(RelativeSide.BACK).also { it.block(block) }.also(configurator)
|
||||
fun left(block: BlockState, configurator: Node.() -> Unit) = relative(RelativeSide.LEFT).also { it.block(block) }.also(configurator)
|
||||
fun right(block: BlockState, configurator: Node.() -> Unit) = relative(RelativeSide.RIGHT).also { it.block(block) }.also(configurator)
|
||||
fun top(block: BlockState, configurator: Node.() -> Unit) = relative(RelativeSide.TOP).also { it.block(block) }.also(configurator)
|
||||
fun bottom(block: BlockState, configurator: Node.() -> Unit) = relative(RelativeSide.BOTTOM).also { it.block(block) }.also(configurator)
|
||||
|
||||
fun front(predicate: BlockPredicate, configurator: Node.() -> Unit) = relative(RelativeSide.FRONT).also { it.predicate(predicate) }.also(configurator)
|
||||
fun back(predicate: BlockPredicate, configurator: Node.() -> Unit) = relative(RelativeSide.BACK).also { it.predicate(predicate) }.also(configurator)
|
||||
fun left(predicate: BlockPredicate, configurator: Node.() -> Unit) = relative(RelativeSide.LEFT).also { it.predicate(predicate) }.also(configurator)
|
||||
fun right(predicate: BlockPredicate, configurator: Node.() -> Unit) = relative(RelativeSide.RIGHT).also { it.predicate(predicate) }.also(configurator)
|
||||
fun top(predicate: BlockPredicate, configurator: Node.() -> Unit) = relative(RelativeSide.TOP).also { it.predicate(predicate) }.also(configurator)
|
||||
fun bottom(predicate: BlockPredicate, configurator: Node.() -> Unit) = relative(RelativeSide.BOTTOM).also { it.predicate(predicate) }.also(configurator)
|
||||
|
||||
fun build(): MultiblockFactory.Part {
|
||||
return build(pos)
|
||||
}
|
||||
|
||||
override var strategy: Strategy = Strategy.OR
|
||||
}
|
||||
|
||||
fun node(at: BlockPos): Node {
|
||||
return nodes[at] ?: Node(at)
|
||||
}
|
||||
|
||||
fun root() = node(BlockPos.ZERO)
|
||||
fun root(configurator: Node.() -> Unit) = node(BlockPos.ZERO).also(configurator)
|
||||
|
||||
fun copy(): MultiblockBuilder {
|
||||
val copied = MultiblockBuilder()
|
||||
|
||||
for ((k, v) in nodes) {
|
||||
val node = copied.Node(k)
|
||||
copied.nodes[k] = node
|
||||
node.predicates.addAll(v.predicates)
|
||||
}
|
||||
|
||||
return copied
|
||||
}
|
||||
|
||||
fun build(): MultiblockFactory {
|
||||
return MultiblockFactory(nodes.values.iterator().map { it.build() }.collect(ImmutableSet.toImmutableSet()))
|
||||
}
|
||||
}
|
||||
|
||||
class MultiblockFactory(val north: ImmutableSet<Part>) {
|
||||
data class Part(
|
||||
val pos: BlockPos,
|
||||
val strategy: MultiblockBuilder.Strategy,
|
||||
val predicate: ImmutableList<BlockPredicate>,
|
||||
val children: ImmutableList<Part>,
|
||||
val blockStateTags: ImmutableSet<Any>,
|
||||
val blockTags: ImmutableSet<Any>,
|
||||
val blockEntityTags: ImmutableSet<MultiblockBuilder.EntityTag<*>>,
|
||||
)
|
||||
|
||||
fun create(pos: BlockPos): Multiblock {
|
||||
return Multiblock(
|
||||
pos,
|
||||
north,
|
||||
south,
|
||||
west,
|
||||
east,
|
||||
)
|
||||
}
|
||||
|
||||
val south: ImmutableSet<Part> = north.iterator().map { it.copy(pos = it.pos.rotate(Rotation.CLOCKWISE_180)) }.collect(ImmutableSet.toImmutableSet())
|
||||
val west: ImmutableSet<Part> = north.iterator().map { it.copy(pos = it.pos.rotate(Rotation.COUNTERCLOCKWISE_90)) }.collect(ImmutableSet.toImmutableSet())
|
||||
val east: ImmutableSet<Part> = north.iterator().map { it.copy(pos = it.pos.rotate(Rotation.CLOCKWISE_90)) }.collect(ImmutableSet.toImmutableSet())
|
||||
}
|
||||
|
||||
class Multiblock(
|
||||
pos: BlockPos,
|
||||
north: Collection<MultiblockFactory.Part>,
|
||||
south: Collection<MultiblockFactory.Part>,
|
||||
west: Collection<MultiblockFactory.Part>,
|
||||
east: Collection<MultiblockFactory.Part>,
|
||||
) {
|
||||
var isValid = false
|
||||
private set
|
||||
|
||||
private val configurations = ArrayList<Config>()
|
||||
|
||||
private inner class BEList<T : BlockEntity>(val tag: MultiblockBuilder.EntityTag<T>) {
|
||||
val list = ArrayList<T>()
|
||||
val set = ObjectArraySet<T>()
|
||||
val setView: Set<T> = Collections.unmodifiableSet(set)
|
||||
|
||||
fun add(blockEntity: BlockEntity) {
|
||||
if (tag.test(blockEntity)) {
|
||||
if (set.add(blockEntity as T)) {
|
||||
blockEntityListeners
|
||||
.computeIfAbsent(blockEntity.level) { WeakHashMap() }
|
||||
.computeIfAbsent(blockEntity) { WeakHashSet() }
|
||||
.add(this@Multiblock)
|
||||
}
|
||||
|
||||
list.add(blockEntity)
|
||||
}
|
||||
}
|
||||
|
||||
fun remove(blockEntity: BlockEntity) {
|
||||
if (tag.test(blockEntity)) {
|
||||
check(list.remove(blockEntity as T)) { "Unable to remove $blockEntity from tag $tag" }
|
||||
|
||||
if (blockEntity !in list) {
|
||||
set.remove(blockEntity)
|
||||
|
||||
val getSet = blockEntityListeners[blockEntity.level]?.get(blockEntity)
|
||||
|
||||
if (getSet != null) {
|
||||
getSet.remove(this@Multiblock)
|
||||
|
||||
if (getSet.isEmpty()) {
|
||||
blockEntityListeners[blockEntity.level]?.remove(blockEntity)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun blockEntityRemoved(blockEntity: BlockEntity): Boolean {
|
||||
if (blockEntity in list) {
|
||||
while (list.remove(blockEntity)) {}
|
||||
set.remove(blockEntity)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
set.forEach {
|
||||
val getSet = checkNotNull(blockEntityListeners[it.level]) { "Consistency check failed: No subscriber lists for level ${it.level}" }.get(it)
|
||||
checkNotNull(getSet) { "Consistency check failed: No subscriber list for $it" }
|
||||
check(getSet.remove(this@Multiblock)) { "Consistency check failed: Can't remove ${this@Multiblock} from $it subscriber list" }
|
||||
|
||||
if (getSet.isEmpty()) {
|
||||
blockEntityListeners[it.level]?.remove(it)
|
||||
}
|
||||
}
|
||||
|
||||
list.clear()
|
||||
set.clear()
|
||||
}
|
||||
}
|
||||
|
||||
private inner class Config(val pos: BlockPos, parts: Collection<MultiblockFactory.Part>) {
|
||||
private inner class Part(val pos: BlockPos, val prototype: MultiblockFactory.Part) {
|
||||
private var blockEntity: BlockEntity? = null
|
||||
private var blockState: BlockState? = null
|
||||
private val assignedBlockEntityLists = ArrayList<BEList<*>>(prototype.blockEntityTags.size)
|
||||
private val assignedBlockStateLists = ArrayList<Reference2IntOpenHashMap<BlockState>>()
|
||||
private val assignedBlockLists = ArrayList<Object2IntOpenHashMap<Block>>()
|
||||
private val children: ImmutableList<Part> = prototype.children.stream().map { Part(pos, it) }.collect(ImmutableList.toImmutableList())
|
||||
|
||||
init {
|
||||
prototype.blockEntityTags.forEach {
|
||||
assignedBlockEntityLists.add(tag2BlockEntity.computeIfAbsent(it, Object2ObjectFunction { _ -> BEList(it as MultiblockBuilder.EntityTag<BlockEntity>).also { blockEntityLists.add(it) } }))
|
||||
}
|
||||
|
||||
prototype.blockStateTags.forEach {
|
||||
assignedBlockStateLists.add(tag2BlockState.computeIfAbsent(it, Object2ObjectFunction { Reference2IntOpenHashMap<BlockState>().also { blockStateLists.add(it) } }))
|
||||
}
|
||||
|
||||
prototype.blockTags.forEach {
|
||||
assignedBlockLists.add(tag2Block.computeIfAbsent(it, Object2ObjectFunction { Object2IntOpenHashMap<Block>().also { blockLists.add(it) } }))
|
||||
}
|
||||
}
|
||||
|
||||
private var lastSuccessfulPathPredicate = -1
|
||||
private var lastSuccessfulPathChildren = -1
|
||||
|
||||
fun test(levelAccessor: LevelAccessor): Boolean {
|
||||
val test = when (prototype.strategy) {
|
||||
MultiblockBuilder.Strategy.OR -> {
|
||||
var status = true
|
||||
|
||||
if (prototype.predicate.isNotEmpty()) {
|
||||
if (lastSuccessfulPathPredicate != -1 && !prototype.predicate[lastSuccessfulPathPredicate].test(pos, levelAccessor)) {
|
||||
lastSuccessfulPathPredicate = -1
|
||||
}
|
||||
|
||||
if (lastSuccessfulPathPredicate == -1) {
|
||||
lastSuccessfulPathPredicate = prototype.predicate.indexOfFirst { it.test(pos, levelAccessor) }
|
||||
status = lastSuccessfulPathPredicate != -1
|
||||
}
|
||||
}
|
||||
|
||||
if (status && children.isNotEmpty()) {
|
||||
if (lastSuccessfulPathChildren != -1 && !children[lastSuccessfulPathChildren].test(levelAccessor)) {
|
||||
lastSuccessfulPathChildren = -1
|
||||
}
|
||||
|
||||
if (lastSuccessfulPathChildren == -1) {
|
||||
lastSuccessfulPathChildren = children.indexOfFirst { it.test(levelAccessor) }
|
||||
status = lastSuccessfulPathChildren != -1
|
||||
}
|
||||
}
|
||||
|
||||
status
|
||||
}
|
||||
|
||||
MultiblockBuilder.Strategy.AND -> prototype.predicate.all { it.test(pos, levelAccessor) } && children.all { it.test(levelAccessor) }
|
||||
}
|
||||
|
||||
if (test) {
|
||||
if (assignedBlockEntityLists.isNotEmpty()) {
|
||||
val be1 = blockEntity
|
||||
val be2 = levelAccessor.getBlockEntity(pos)
|
||||
|
||||
if (be1 != be2) {
|
||||
if (be1 != null) {
|
||||
assignedBlockEntityLists.forEach { it.remove(be1) }
|
||||
}
|
||||
|
||||
if (be2 != null) {
|
||||
assignedBlockEntityLists.forEach { it.add(be2) }
|
||||
}
|
||||
|
||||
blockEntity = be2
|
||||
}
|
||||
}
|
||||
|
||||
if (assignedBlockStateLists.isNotEmpty() || assignedBlockLists.isNotEmpty()) {
|
||||
val state = levelAccessor.getBlockState(pos)
|
||||
val old = blockState
|
||||
|
||||
if (state != old) {
|
||||
if (old != null) {
|
||||
assignedBlockStateLists.forEach {
|
||||
it[old] = it.getInt(old) - 1
|
||||
check(it.getInt(old) >= 0) { "Consistency check failed: Counter for block state $old turned negative" }
|
||||
}
|
||||
|
||||
assignedBlockLists.forEach {
|
||||
it[old.block] = it.getInt(old.block) - 1
|
||||
check(it.getInt(old.block) >= 0) { "Consistency check failed: Counter for block ${old.block.registryName} turned negative" }
|
||||
}
|
||||
}
|
||||
|
||||
assignedBlockStateLists.forEach {
|
||||
it[state] = it.getInt(state) + 1
|
||||
}
|
||||
|
||||
assignedBlockLists.forEach {
|
||||
it[state.block] = it.getInt(state.block) + 1
|
||||
}
|
||||
|
||||
blockState = state
|
||||
}
|
||||
}
|
||||
} else {
|
||||
clearFull()
|
||||
}
|
||||
|
||||
return test
|
||||
}
|
||||
|
||||
private fun clearFull() {
|
||||
val blockEntity = blockEntity
|
||||
|
||||
if (blockEntity != null) {
|
||||
assignedBlockEntityLists.forEach { it.remove(blockEntity) }
|
||||
}
|
||||
|
||||
val blockState = blockState
|
||||
|
||||
if (blockState != null) {
|
||||
assignedBlockStateLists.forEach {
|
||||
it[blockState] = it.getInt(blockState) - 1
|
||||
check(it.getInt(blockState) >= 0) { "Consistency check failed: Counter for block state $blockState turned negative" }
|
||||
}
|
||||
|
||||
assignedBlockLists.forEach {
|
||||
it[blockState.block] = it.getInt(blockState.block) - 1
|
||||
check(it.getInt(blockState.block) >= 0) { "Consistency check failed: Counter for block ${blockState.block.registryName} turned negative" }
|
||||
}
|
||||
}
|
||||
|
||||
this.blockEntity = null
|
||||
this.blockState = null
|
||||
|
||||
lastSuccessfulPathPredicate = -1
|
||||
lastSuccessfulPathChildren = -1
|
||||
|
||||
// avoid allocating iterator when empty
|
||||
if (children.isNotEmpty())
|
||||
children.forEach { it.clearFull() }
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
blockEntity = null
|
||||
blockState = null
|
||||
|
||||
lastSuccessfulPathPredicate = -1
|
||||
lastSuccessfulPathChildren = -1
|
||||
|
||||
children.forEach { it.clear() }
|
||||
}
|
||||
}
|
||||
|
||||
private val tag2BlockEntity = Object2ObjectOpenHashMap<MultiblockBuilder.EntityTag<*>, BEList<*>>()
|
||||
private val tag2BlockState = Object2ObjectOpenHashMap<Any, Reference2IntOpenHashMap<BlockState>>()
|
||||
private val tag2Block = Object2ObjectOpenHashMap<Any, Object2IntOpenHashMap<Block>>()
|
||||
|
||||
private val blockEntityLists = ArrayList<BEList<*>>()
|
||||
private val blockStateLists = ArrayList<Reference2IntOpenHashMap<BlockState>>()
|
||||
private val blockLists = ArrayList<Object2IntOpenHashMap<Block>>()
|
||||
|
||||
private val parts: ImmutableSet<Part> = parts.stream().map { Part(it.pos + pos, it) }.collect(ImmutableSet.toImmutableSet())
|
||||
|
||||
fun clear() {
|
||||
blockEntityLists.forEach { it.clear() }
|
||||
blockStateLists.forEach { it.clear() }
|
||||
blockLists.forEach { it.clear() }
|
||||
parts.forEach { it.clear() }
|
||||
}
|
||||
|
||||
fun update(levelAccessor: LevelAccessor): Boolean {
|
||||
var valid = true
|
||||
|
||||
for (part in parts) {
|
||||
valid = part.test(levelAccessor)
|
||||
if (!valid) break
|
||||
}
|
||||
|
||||
if (!valid)
|
||||
clear()
|
||||
|
||||
return valid
|
||||
}
|
||||
|
||||
fun <T : BlockEntity> blockEntities(tag: MultiblockBuilder.EntityTag<T>): Set<T> {
|
||||
return (tag2BlockEntity[tag]?.setView ?: setOf()) as Set<T>
|
||||
}
|
||||
|
||||
fun blockEntityRemoved(blockEntity: BlockEntity): Boolean {
|
||||
var any = false
|
||||
|
||||
blockEntityLists.forEach {
|
||||
any = it.blockEntityRemoved(blockEntity) || any
|
||||
}
|
||||
|
||||
return any
|
||||
}
|
||||
}
|
||||
|
||||
private val north = Config(pos, north).also { configurations.add(it) }
|
||||
private val south = Config(pos, south).also { configurations.add(it) }
|
||||
private val west = Config(pos, west).also { configurations.add(it) }
|
||||
private val east = Config(pos, east).also { configurations.add(it) }
|
||||
|
||||
private var activeConfig: Config? = null
|
||||
|
||||
fun <T : BlockEntity> blockEntities(tag: MultiblockBuilder.EntityTag<T>): Set<T> {
|
||||
if (!isValid) return emptySet()
|
||||
return activeConfig?.blockEntities(tag) ?: setOf()
|
||||
}
|
||||
|
||||
fun blockEntityRemoved(blockEntity: BlockEntity) {
|
||||
activeConfig?.blockEntityRemoved(blockEntity)
|
||||
}
|
||||
|
||||
fun update(levelAccessor: LevelAccessor): Boolean {
|
||||
val activeConfig = activeConfig
|
||||
|
||||
if (activeConfig != null && activeConfig.update(levelAccessor)) {
|
||||
return true
|
||||
} else if (activeConfig != null) {
|
||||
for (config in configurations) {
|
||||
if (config !== activeConfig && config.update(levelAccessor)) {
|
||||
this.activeConfig = config
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
this.activeConfig = null
|
||||
this.isValid = false
|
||||
return false
|
||||
} else {
|
||||
for (config in configurations) {
|
||||
if (config.update(levelAccessor)) {
|
||||
this.activeConfig = config
|
||||
this.isValid = true
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
package ru.dbotthepony.mc.otm.core.math
|
||||
|
||||
import com.google.common.collect.ImmutableMap
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.core.Vec3i
|
||||
@ -27,8 +26,8 @@ operator fun BlockPos.plus(other: BlockRotation): BlockPos {
|
||||
return this + other.normal
|
||||
}
|
||||
|
||||
enum class RelativeSide {
|
||||
FRONT, BACK, LEFT, RIGHT, TOP, BOTTOM
|
||||
enum class RelativeSide(val default: Direction) {
|
||||
FRONT(Direction.NORTH), BACK(Direction.SOUTH), LEFT(Direction.WEST), RIGHT(Direction.EAST), TOP(Direction.UP), BOTTOM(Direction.DOWN)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -44,6 +44,10 @@ object MBlockEntities {
|
||||
return registry.register(name) { BlockEntityType.Builder.of(factory, *blocks.map { it.get() }.toTypedArray()).build(null) }
|
||||
}
|
||||
|
||||
private fun <T : BlockEntity> register(name: String, factory: BlockEntityType.BlockEntitySupplier<T>, blocks: Supplier<Block>): MDeferredRegister<*>.Entry<BlockEntityType<T>> {
|
||||
return registry.register(name) { BlockEntityType.Builder.of(factory, blocks.get()).build(null) }
|
||||
}
|
||||
|
||||
private fun <T : BlockEntity> register(name: String, factory: BlockEntityType.BlockEntitySupplier<T>, blocks: Map<*, Block>): MDeferredRegister<*>.Entry<BlockEntityType<T>> {
|
||||
return registry.register(name) { BlockEntityType.Builder.of(factory, *blocks.values.toTypedArray()).build(null) }
|
||||
}
|
||||
@ -87,6 +91,8 @@ object MBlockEntities {
|
||||
val POWERED_BLAST_FURNACE by register(MNames.POWERED_BLAST_FURNACE, ::PoweredBlastFurnaceBlockEntity, MBlocks.POWERED_BLAST_FURNACE)
|
||||
val POWERED_SMOKER by register(MNames.POWERED_SMOKER, ::PoweredSmokerBlockEntity, MBlocks.POWERED_SMOKER)
|
||||
|
||||
val MULTIBLOCK_TEST by register("multiblock_test", ::MultiblockTestBlockEntity, MBlocks::MULTIBLOCK_TEST)
|
||||
|
||||
val ENERGY_CABLES: Map<CablesConfig.E, BlockEntityType<*>> = SupplierMap(CablesConfig.E.entries.map { conf ->
|
||||
var selfFeed: Supplier<BlockEntityType<*>> = Supplier { TODO() }
|
||||
selfFeed = register("${conf.name.lowercase()}_energy_cable", { a, b -> SimpleEnergyCableBlockEntity(selfFeed.get(), a, b, conf) }) as Supplier<BlockEntityType<*>>
|
||||
|
@ -27,6 +27,7 @@ import ru.dbotthepony.mc.otm.block.BlockSphereDebugger
|
||||
import ru.dbotthepony.mc.otm.block.EnergyCableBlock
|
||||
import ru.dbotthepony.mc.otm.block.MatterCableBlock
|
||||
import ru.dbotthepony.mc.otm.block.MatteryBlock
|
||||
import ru.dbotthepony.mc.otm.block.MultiblockTestBlock
|
||||
import ru.dbotthepony.mc.otm.block.StorageCableBlock
|
||||
import ru.dbotthepony.mc.otm.block.addSimpleDescription
|
||||
import ru.dbotthepony.mc.otm.block.decorative.DevChestBlock
|
||||
@ -228,7 +229,7 @@ object MBlocks {
|
||||
.sound(SoundType.BASALT)
|
||||
.requiresCorrectToolForDrops()
|
||||
.explosionResistance(80f)
|
||||
.strength(4f)
|
||||
.destroyTime(2.5f)
|
||||
) }
|
||||
|
||||
val TRITANIUM_STRIPED_STAIRS: Block by registry.register(MNames.TRITANIUM_STRIPED_STAIRS) { StairBlock(
|
||||
@ -250,9 +251,11 @@ object MBlocks {
|
||||
.sound(SoundType.BASALT)
|
||||
.requiresCorrectToolForDrops()
|
||||
.explosionResistance(40f)
|
||||
.strength(3f)
|
||||
.destroyTime(1.5f)
|
||||
) }
|
||||
|
||||
val MULTIBLOCK_TEST by registry.register("multiblock_test") { MultiblockTestBlock() }
|
||||
|
||||
init {
|
||||
MRegistry.registerBlocks(registry)
|
||||
}
|
||||
|
@ -160,6 +160,7 @@ object MItems {
|
||||
|
||||
val DEBUG_EXPLOSION_SMALL: Item by registry.register(MNames.DEBUG_EXPLOSION_SMALL) { BlockItem(MBlocks.DEBUG_EXPLOSION_SMALL, Item.Properties().stacksTo(64)) }
|
||||
val DEBUG_SPHERE_POINTS: Item by registry.register(MNames.DEBUG_SPHERE_POINTS) { BlockItem(MBlocks.DEBUG_SPHERE_POINTS, Item.Properties().stacksTo(64)) }
|
||||
val MULTIBLOCK_TEST by registry.register("multiblock_test") { BlockItem(MBlocks.MULTIBLOCK_TEST, Properties().stacksTo(64)) }
|
||||
|
||||
val TRITANIUM_ANVIL: List<BlockItem>
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
"minVersion": "0.8",
|
||||
"refmap": "overdrive_that_matters.refmap.json",
|
||||
"mixins": [
|
||||
"BlockEntityMixin",
|
||||
"EnchantmentHelperMixin",
|
||||
"FoodDataMixin",
|
||||
"MixinPatchProjectileFinder",
|
||||
@ -22,6 +23,7 @@
|
||||
],
|
||||
"client": [
|
||||
"MixinGameRenderer",
|
||||
"MixinMinecraft"
|
||||
"MixinMinecraft",
|
||||
"SplashManagerMixin"
|
||||
]
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user