Compare commits

...

3 Commits

12 changed files with 373 additions and 60 deletions

View File

@ -14,6 +14,7 @@ import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.NbtOps import net.minecraft.nbt.NbtOps
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.network.chat.ComponentSerialization import net.minecraft.network.chat.ComponentSerialization
import net.minecraft.server.level.ServerLevel
import net.minecraft.util.RandomSource import net.minecraft.util.RandomSource
import net.minecraft.world.Containers import net.minecraft.world.Containers
import net.minecraft.world.InteractionResult import net.minecraft.world.InteractionResult
@ -259,15 +260,11 @@ open class MatteryBlock(properties: Properties = DEFAULT_PROPERTIES) : Block(pro
newBlockState: BlockState, newBlockState: BlockState,
movedByPiston: Boolean movedByPiston: Boolean
) { ) {
if (!oldBlockState.`is`(newBlockState.block) && !level.isClientSide) { if (!oldBlockState.`is`(newBlockState.block) && level is ServerLevel) {
val blockentity = level.getBlockEntity(blockPos) val blockentity = level.getBlockEntity(blockPos)
if (blockentity is MatteryBlockEntity) { if (blockentity is MatteryBlockEntity) {
blockentity.beforeDroppingItems(oldBlockState, level, blockPos, newBlockState, movedByPiston) blockentity.dropItems(oldBlockState, level, blockPos, newBlockState, movedByPiston)
for (container in blockentity.droppableContainers)
Containers.dropContents(level, blockPos, container)
level.updateNeighbourForOutputSignal(blockPos, this) level.updateNeighbourForOutputSignal(blockPos, this)
} }
} }

View File

@ -0,0 +1,26 @@
package ru.dbotthepony.mc.otm.block.decorative
import net.minecraft.core.BlockPos
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.block.EntityBlock
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.storage.loot.LootParams
import net.minecraft.world.level.storage.loot.parameters.LootContextParams
import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock
import ru.dbotthepony.mc.otm.block.entity.decorative.BreakableContainerBlockEntity
class BreakableContainerBlock(properties: Properties) : RotatableMatteryBlock(properties), EntityBlock {
override fun newBlockEntity(pos: BlockPos, state: BlockState): BlockEntity {
return BreakableContainerBlockEntity(pos, state)
}
override fun getDrops(state: BlockState, params: LootParams.Builder): MutableList<ItemStack> {
val entity = params.getOptionalParameter(LootContextParams.BLOCK_ENTITY)
if (entity is BreakableContainerBlockEntity)
return entity.loot.getItems(params, state)
return super.getDrops(state, params)
}
}

View File

@ -17,6 +17,7 @@ import net.minecraft.nbt.CompoundTag
import net.minecraft.server.level.ServerLevel import net.minecraft.server.level.ServerLevel
import net.minecraft.server.level.ServerPlayer import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.Container import net.minecraft.world.Container
import net.minecraft.world.Containers
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
import net.minecraft.world.level.ChunkPos import net.minecraft.world.level.ChunkPos
import net.minecraft.world.level.Level import net.minecraft.world.level.Level
@ -70,7 +71,7 @@ import kotlin.collections.ArrayList
/** /**
* Absolute barebone (lol) block entity class in Overdrive that Matters, providing bare minimum (lulmao, minecraft engine) functionality * Absolute barebone (lol) block entity class in Overdrive that Matters, providing bare minimum (lulmao, minecraft engine) functionality
*/ */
abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: BlockPos, p_155230_: BlockState) : BlockEntity(p_155228_, p_155229_, p_155230_), INeighbourChangeListener { abstract class MatteryBlockEntity(type: BlockEntityType<*>, pos: BlockPos, state: BlockState) : BlockEntity(type, pos, state), INeighbourChangeListener {
private val sidelessCaps = Reference2ObjectOpenHashMap<BlockCapability<*, *>, Any>() private val sidelessCaps = Reference2ObjectOpenHashMap<BlockCapability<*, *>, Any>()
private val sidedCaps = Array(RelativeSide.entries.size) { private val sidedCaps = Array(RelativeSide.entries.size) {
Reference2ObjectOpenHashMap<BlockCapability<*, *>, ControllableCapability<*>>() Reference2ObjectOpenHashMap<BlockCapability<*, *>, ControllableCapability<*>>()
@ -121,7 +122,11 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
_neighbourChangeListeners.add(listener) _neighbourChangeListeners.add(listener)
} }
open fun beforeDroppingItems(oldBlockState: BlockState, level: Level, blockPos: BlockPos, newBlockState: BlockState, movedByPiston: Boolean) {} open fun dropItems(oldBlockState: BlockState, level: ServerLevel, blockPos: BlockPos, newBlockState: BlockState, movedByPiston: Boolean) {
for (container in droppableContainers)
Containers.dropContents(level, blockPos, container)
}
open fun beforeDestroyedByPlayer(level: Level, blockPos: BlockPos, blockState: BlockState, player: Player) {} open fun beforeDestroyedByPlayer(level: Level, blockPos: BlockPos, blockState: BlockState, player: Player) {}
open fun tick() { open fun tick() {

View File

@ -0,0 +1,23 @@
package ru.dbotthepony.mc.otm.block.entity.decorative
import net.minecraft.core.BlockPos
import net.minecraft.core.HolderLookup
import net.minecraft.nbt.CompoundTag
import net.minecraft.world.level.block.state.BlockState
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
import ru.dbotthepony.mc.otm.core.util.BlockLootTableHolder
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
class BreakableContainerBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryBlockEntity(MBlockEntities.BREAKABLE, blockPos, blockState) {
val loot = BlockLootTableHolder(::markDirtyFast)
override fun saveLevel(nbt: CompoundTag, registry: HolderLookup.Provider) {
super.saveLevel(nbt, registry)
loot.save(nbt, registry)
}
override fun loadAdditional(nbt: CompoundTag, registry: HolderLookup.Provider) {
super.loadAdditional(nbt, registry)
loot.load(nbt, registry)
}
}

View File

@ -1,18 +1,11 @@
package ru.dbotthepony.mc.otm.block.entity.decorative package ru.dbotthepony.mc.otm.block.entity.decorative
import net.minecraft.advancements.CriteriaTriggers
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.core.HolderLookup import net.minecraft.core.HolderLookup
import net.minecraft.core.registries.Registries
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.Tag
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.resources.ResourceKey
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerLevel import net.minecraft.server.level.ServerLevel
import net.minecraft.server.level.ServerPlayer
import net.minecraft.sounds.SoundSource import net.minecraft.sounds.SoundSource
import net.minecraft.world.Containers
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
@ -21,18 +14,14 @@ import net.minecraft.world.level.Level
import net.minecraft.world.level.block.Block 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.minecraft.world.level.gameevent.GameEvent import net.minecraft.world.level.gameevent.GameEvent
import net.minecraft.world.level.storage.loot.LootParams
import net.minecraft.world.level.storage.loot.LootTable
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets
import net.minecraft.world.level.storage.loot.parameters.LootContextParams
import net.minecraft.world.phys.Vec3
import net.neoforged.neoforge.capabilities.Capabilities import net.neoforged.neoforge.capabilities.Capabilities
import ru.dbotthepony.mc.otm.block.decorative.CargoCrateBlock import ru.dbotthepony.mc.otm.block.decorative.CargoCrateBlock
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.HandlerFilter
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.otmRandom import ru.dbotthepony.mc.otm.core.otmRandom
import ru.dbotthepony.mc.otm.core.util.BlockLootTableHolder
import ru.dbotthepony.mc.otm.menu.decorative.CargoCrateMenu import ru.dbotthepony.mc.otm.menu.decorative.CargoCrateMenu
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
import ru.dbotthepony.mc.otm.registry.game.MSoundEvents import ru.dbotthepony.mc.otm.registry.game.MSoundEvents
@ -47,24 +36,30 @@ class CargoCrateBlockEntity(
val handler = container.handler(object : HandlerFilter { val handler = container.handler(object : HandlerFilter {
override fun canInsert(slot: Int, stack: ItemStack): Boolean { override fun canInsert(slot: Int, stack: ItemStack): Boolean {
return lootTable == null return loot.lootTable == null
} }
override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean { override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean {
return lootTable == null return loot.lootTable == null
} }
}) })
override fun beforeDroppingItems(oldBlockState: BlockState, level: Level, blockPos: BlockPos, newBlockState: BlockState, movedByPiston: Boolean) { override fun dropItems(
oldBlockState: BlockState,
level: ServerLevel,
blockPos: BlockPos,
newBlockState: BlockState,
movedByPiston: Boolean
) {
unpackLootTable() unpackLootTable()
super.dropItems(oldBlockState, level, blockPos, newBlockState, movedByPiston)
} }
override fun beforeDestroyedByPlayer(level: Level, blockPos: BlockPos, blockState: BlockState, player: Player) { override fun beforeDestroyedByPlayer(level: Level, blockPos: BlockPos, blockState: BlockState, player: Player) {
unpackLootTable(player) unpackLootTable(player)
} }
var lootTable: ResourceKey<LootTable>? = null val loot = BlockLootTableHolder(::markDirtyFast)
var lootTableSeed: Long? = null
fun onPlayerOpen() { fun onPlayerOpen() {
val level = level val level = level
@ -92,52 +87,24 @@ class CargoCrateBlockEntity(
override fun saveLevel(nbt: CompoundTag, registry: HolderLookup.Provider) { override fun saveLevel(nbt: CompoundTag, registry: HolderLookup.Provider) {
super.saveLevel(nbt, registry) super.saveLevel(nbt, registry)
loot.save(nbt, registry)
if (lootTable != null) {
nbt.putString(LOOT_TABLE_KEY, lootTable!!.location().toString())
nbt.putLong(LOOT_TABLE_SEED_KEY, lootTableSeed ?: 0L)
}
} }
override fun loadAdditional(nbt: CompoundTag, registry: HolderLookup.Provider) { override fun loadAdditional(nbt: CompoundTag, registry: HolderLookup.Provider) {
super.loadAdditional(nbt, registry) super.loadAdditional(nbt, registry)
loot.load(nbt, registry)
if (nbt.contains(LOOT_TABLE_KEY, Tag.TAG_STRING.toInt())) {
lootTable = ResourceLocation.tryParse(nbt.getString(LOOT_TABLE_KEY))?.let { ResourceKey.create(Registries.LOOT_TABLE, it) }
lootTableSeed = if (nbt.contains(LOOT_TABLE_SEED_KEY, Tag.TAG_LONG.toInt())) nbt.getLong(LOOT_TABLE_SEED_KEY) else 0L
}
} }
fun unpackLootTable(ply: Player? = null) { private fun unpackLootTable(ply: Player? = null) {
val lootTable = lootTable ?: return loot.fill(level as? ServerLevel ?: return, blockPos, container, ply = ply, blockEntity = this)
val lootTableSeed = lootTableSeed ?: 0L loot.clear()
val server = level?.server ?: return
val loot = server.reloadableRegistries().getLootTable(lootTable)
if (ply is ServerPlayer) {
CriteriaTriggers.GENERATE_LOOT.trigger(ply, lootTable)
}
this.lootTable = null
this.lootTableSeed = null
val params = LootParams.Builder(level as ServerLevel)
.withParameter(LootContextParams.ORIGIN, Vec3.atCenterOf(this.worldPosition))
if (ply != null) {
params.withLuck(ply.luck).withParameter(LootContextParams.THIS_ENTITY, ply)
}
Containers.dropContents(level as ServerLevel, blockPos, container)
loot.fill(container, params.create(LootContextParamSets.CHEST), lootTableSeed)
} }
override val defaultDisplayName: Component override val defaultDisplayName: Component
get() = MACHINE_NAME get() = MACHINE_NAME
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu? { override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu? {
if (lootTable != null && ply.isSpectator) if (loot.lootTable != null && ply.isSpectator)
return null return null
unpackLootTable(ply) unpackLootTable(ply)

View File

@ -10,6 +10,7 @@ import com.google.common.collect.ImmutableSet
import com.google.gson.JsonElement 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.ints.IntList
import it.unimi.dsi.fastutil.objects.ObjectComparators import it.unimi.dsi.fastutil.objects.ObjectComparators
import net.minecraft.Util import net.minecraft.Util
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
@ -199,6 +200,15 @@ fun IntArray.shuffle(random: RandomSource): IntArray {
return this return this
} }
fun <L : IntList> L.shuffle(random: RandomSource): L {
for (i in lastIndex downTo 1) {
val j = random.nextInt(i + 1)
set(j, set(i, getInt(j)))
}
return this
}
fun <T, L : MutableList<T>> L.shuffle(random: RandomSource): L { fun <T, L : MutableList<T>> L.shuffle(random: RandomSource): L {
Util.shuffle(this, random) Util.shuffle(this, random)
return this return this

View File

@ -0,0 +1,132 @@
package ru.dbotthepony.mc.otm.core.util
import net.minecraft.advancements.CriteriaTriggers
import net.minecraft.core.BlockPos
import net.minecraft.core.HolderLookup
import net.minecraft.core.registries.Registries
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.Tag
import net.minecraft.resources.ResourceKey
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerLevel
import net.minecraft.server.level.ServerPlayer
import net.minecraft.util.RandomSource
import net.minecraft.world.Container
import net.minecraft.world.Containers
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.storage.loot.LootParams
import net.minecraft.world.level.storage.loot.LootTable
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets
import net.minecraft.world.level.storage.loot.parameters.LootContextParams
import net.minecraft.world.phys.Vec3
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity.Companion.LOOT_TABLE_KEY
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity.Companion.LOOT_TABLE_SEED_KEY
import ru.dbotthepony.mc.otm.core.getBlockEntityNow
import ru.dbotthepony.mc.otm.core.otmRandom
class BlockLootTableHolder(private val listener: Runnable = Runnable { }) {
private var ignoreListener = false
var lootTable: ResourceKey<LootTable>? = null
set(value) {
if (field != value) {
field = value
if (!ignoreListener) listener.run()
}
}
var lootTableSeed: Long? = null
set(value) {
if (field != value) {
field = value
if (!ignoreListener) listener.run()
}
}
fun save(nbt: CompoundTag, registry: HolderLookup.Provider) {
try {
ignoreListener = true
if (lootTable != null) {
nbt.putString(LOOT_TABLE_KEY, lootTable!!.location().toString())
if (lootTableSeed != null)
nbt.putLong(LOOT_TABLE_SEED_KEY, lootTableSeed!!)
}
} finally {
ignoreListener = false
}
}
fun load(nbt: CompoundTag, registry: HolderLookup.Provider) {
try {
ignoreListener = true
if (nbt.contains(LOOT_TABLE_KEY, Tag.TAG_STRING.toInt())) {
lootTable = ResourceLocation.tryParse(nbt.getString(LOOT_TABLE_KEY))?.let { ResourceKey.create(Registries.LOOT_TABLE, it) }
lootTableSeed = if (nbt.contains(LOOT_TABLE_SEED_KEY, Tag.TAG_LONG.toInt())) nbt.getLong(LOOT_TABLE_SEED_KEY) else null
}
} finally {
ignoreListener = false
}
}
fun lookup(level: ServerLevel): LootTable {
val lootTable = lootTable ?: return LootTable.EMPTY
return level.server.reloadableRegistries().getLootTable(lootTable)
}
private fun selectRandom(overrideSeed: Long?, fallback: RandomSource): RandomSource {
val lootTableSeed = overrideSeed ?: lootTableSeed
return if (lootTableSeed == null) fallback else GJRAND64RandomSource(lootTableSeed)
}
fun getItems(params: LootParams, level: ServerLevel, overrideSeed: Long? = null, rounds: Int = 1): MutableList<ItemStack> {
return lookup(level).getRandomItems(params, selectRandom(overrideSeed, level.otmRandom), rounds)
}
fun getItems(params: LootParams.Builder, blockState: BlockState, overrideSeed: Long? = null, rounds: Int = 1): MutableList<ItemStack> {
val level = params.level
val create = params.withParameter(LootContextParams.BLOCK_STATE, blockState).create(LootContextParamSets.BLOCK)
return getItems(create, level, overrideSeed, rounds)
}
fun fill(level: ServerLevel, blockPos: BlockPos, container: Container, ply: Player? = null, blockEntity: BlockEntity? = level.getBlockEntityNow(blockPos), overrideSeed: Long? = null, dropContents: Boolean = true, rounds: Int = 1) {
if (rounds == 0)
return
else if (rounds < 0)
throw IllegalArgumentException("Negative amount of rounds: $rounds")
val lootTable = lootTable ?: return
val server = level.server
val loot = server.reloadableRegistries().getLootTable(lootTable)
if (ply is ServerPlayer)
CriteriaTriggers.GENERATE_LOOT.trigger(ply, lootTable)
val params = LootParams.Builder(level)
.withParameter(LootContextParams.ORIGIN, Vec3.atCenterOf(blockPos))
if (ply != null) {
params
.withLuck(ply.luck)
.withParameter(LootContextParams.THIS_ENTITY, ply)
}
if (blockEntity != null)
params.withParameter(LootContextParams.BLOCK_ENTITY, blockEntity)
if (dropContents)
Containers.dropContents(level, blockPos, container)
loot.fill(params.create(LootContextParamSets.CHEST), selectRandom(overrideSeed, level.otmRandom), container, rounds)
}
fun clear() {
lootTable = null
lootTableSeed = null
}
}

View File

@ -0,0 +1,132 @@
package ru.dbotthepony.mc.otm.core.util
import it.unimi.dsi.fastutil.ints.IntArrayList
import net.minecraft.util.Mth
import net.minecraft.util.RandomSource
import net.minecraft.world.Container
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.storage.loot.LootParams
import net.minecraft.world.level.storage.loot.LootTable
import org.apache.logging.log4j.LogManager
import ru.dbotthepony.mc.otm.container.get
import ru.dbotthepony.mc.otm.container.set
import ru.dbotthepony.mc.otm.core.isNotEmpty
import ru.dbotthepony.mc.otm.core.shuffle
import java.util.stream.Collectors
import java.util.stream.IntStream
import kotlin.math.min
private val LOGGER = LogManager.getLogger()
private class Bucket {
val items = ArrayList<ItemStack>()
var last = 0
fun add(item: ItemStack) {
if (item.isEmpty) return
for (i in last until items.size) {
val existing = items[i]
var available = existing.maxStackSize - existing.count
if (available > 0 && ItemStack.isSameItemSameComponents(existing, item)) {
val diff = min(available, item.count)
existing.grow(diff)
item.shrink(diff)
available -= diff
if (available == 0 && i == last)
last++
if (item.isEmpty)
return
}
}
if (item.isNotEmpty) {
items.add(item)
}
}
}
private fun recombine(lists: Collection<Collection<ItemStack>>): MutableList<ItemStack> {
val result = HashMap<Item, Bucket>()
for (list in lists)
for (item in list)
result.computeIfAbsent(item.item) { Bucket() }.add(item)
return result.values
.stream()
.flatMap { it.items.stream() }
.collect(Collectors.toCollection(::ArrayList))
}
fun LootTable.getRandomItems(params: LootParams, random: RandomSource, rounds: Int = 1): MutableList<ItemStack> {
if (rounds == 0) {
return ArrayList()
} else if (rounds == 1) {
return getRandomItems(params, random)
} else {
return recombine(IntStream.range(0, rounds).mapToObj { getRandomItems(params, random) }.toList())
}
}
private fun shuffle(items: MutableList<ItemStack>, emptySlotCount: Int, random: RandomSource) {
val pool = ArrayList<ItemStack>(items)
items.clear()
while (items.size + pool.size < emptySlotCount && pool.isNotEmpty()) {
val select = pool.removeAt(random.nextInt(pool.size))
val maxStackSize = select.maxStackSize
if (maxStackSize == 1 || select.count == 1) {
items.add(select)
} else {
val split = select.split(Mth.nextInt(random, 1, select.count / 2))
if (split.count > 1 && random.nextBoolean())
pool.add(split)
else
items.add(split)
if (select.count > 1 && random.nextBoolean())
pool.add(select)
else
items.add(select)
}
}
items.addAll(pool)
items.shuffle(random)
}
fun LootTable.fill(params: LootParams, random: RandomSource, container: Container, rounds: Int = 1) {
val emptySlots = IntArrayList()
for (i in 0 until container.containerSize)
if (container[i].isEmpty)
emptySlots.add(i)
emptySlots.shuffle(random)
if (emptySlots.isEmpty) {
LOGGER.warn("Tried to fill container with no empty slots")
return
}
val items = getRandomItems(params, random, rounds)
shuffle(items, emptySlots.size, random)
val slotItr = emptySlots.iterator()
val itemItr = items.iterator()
while (slotItr.hasNext() && itemItr.hasNext()) {
container[slotItr.nextInt()] = itemItr.next()
}
if (itemItr.hasNext()) {
LOGGER.warn("Tried to overfill a container")
}
}

View File

@ -341,6 +341,8 @@ object MNames {
const val TRITANIUM_DOOR = "tritanium_door" const val TRITANIUM_DOOR = "tritanium_door"
const val TRITANIUM_TRAPDOOR = "tritanium_trapdoor" const val TRITANIUM_TRAPDOOR = "tritanium_trapdoor"
const val TRITANIUM_PRESSURE_PLATE = "tritanium_pressure_plate" const val TRITANIUM_PRESSURE_PLATE = "tritanium_pressure_plate"
const val SMALL_CAPSULE = "small_capsule"
} }
object StatNames { object StatNames {

View File

@ -12,6 +12,7 @@ import ru.dbotthepony.mc.otm.block.entity.tech.*
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.blackhole.BlackHoleGeneratorBlockEntity import ru.dbotthepony.mc.otm.block.entity.blackhole.BlackHoleGeneratorBlockEntity
import ru.dbotthepony.mc.otm.block.entity.cable.SimpleEnergyCableBlockEntity import ru.dbotthepony.mc.otm.block.entity.cable.SimpleEnergyCableBlockEntity
import ru.dbotthepony.mc.otm.block.entity.decorative.BreakableContainerBlockEntity
import ru.dbotthepony.mc.otm.block.entity.decorative.CargoCrateBlockEntity import ru.dbotthepony.mc.otm.block.entity.decorative.CargoCrateBlockEntity
import ru.dbotthepony.mc.otm.block.entity.decorative.DevChestBlockEntity import ru.dbotthepony.mc.otm.block.entity.decorative.DevChestBlockEntity
import ru.dbotthepony.mc.otm.block.entity.decorative.FluidTankBlockEntity import ru.dbotthepony.mc.otm.block.entity.decorative.FluidTankBlockEntity
@ -118,6 +119,12 @@ object MBlockEntities {
val HOLO_SIGN: BlockEntityType<HoloSignBlockEntity> by registry.register(MNames.HOLO_SIGN) { BlockEntityType.Builder.of(::HoloSignBlockEntity, MBlocks.HOLO_SIGN).build(null) } val HOLO_SIGN: BlockEntityType<HoloSignBlockEntity> by registry.register(MNames.HOLO_SIGN) { BlockEntityType.Builder.of(::HoloSignBlockEntity, MBlocks.HOLO_SIGN).build(null) }
val BREAKABLE: BlockEntityType<BreakableContainerBlockEntity> by registry.register("breakable") {
val blocks = ArrayList<Block>()
blocks.add(MBlocks.SMALL_CAPSULE)
BlockEntityType.Builder.of(::BreakableContainerBlockEntity, *blocks.toTypedArray()).build(null)
}
internal fun register(bus: IEventBus) { internal fun register(bus: IEventBus) {
registry.register(bus) registry.register(bus)
bus.addListener(this::registerClient) bus.addListener(this::registerClient)

View File

@ -37,6 +37,7 @@ import ru.dbotthepony.mc.otm.block.MultiblockTestBlock
import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock
import ru.dbotthepony.mc.otm.block.StorageCableBlock import ru.dbotthepony.mc.otm.block.StorageCableBlock
import ru.dbotthepony.mc.otm.block.addSimpleDescription import ru.dbotthepony.mc.otm.block.addSimpleDescription
import ru.dbotthepony.mc.otm.block.decorative.BreakableContainerBlock
import ru.dbotthepony.mc.otm.block.decorative.DevChestBlock import ru.dbotthepony.mc.otm.block.decorative.DevChestBlock
import ru.dbotthepony.mc.otm.block.decorative.EngineBlock import ru.dbotthepony.mc.otm.block.decorative.EngineBlock
import ru.dbotthepony.mc.otm.block.decorative.FluidTankBlock import ru.dbotthepony.mc.otm.block.decorative.FluidTankBlock
@ -434,6 +435,15 @@ object MBlocks {
val MULTIBLOCK_TEST by registry.register("multiblock_test") { MultiblockTestBlock() } val MULTIBLOCK_TEST by registry.register("multiblock_test") { MultiblockTestBlock() }
val SMALL_CAPSULE by registry.register(MNames.SMALL_CAPSULE) {
BreakableContainerBlock(
BlockBehaviour.Properties.of()
.mapColor(MapColor.COLOR_GRAY)
.destroyTime(0f)
.explosionResistance(1.5f)
)
}
init { init {
MRegistry.registerBlocks(registry) MRegistry.registerBlocks(registry)
} }

View File

@ -680,6 +680,8 @@ object MItems {
val CONFIGURATOR: Item by registry.register(MNames.CONFIGURATOR) { ConfiguratorItem() } val CONFIGURATOR: Item by registry.register(MNames.CONFIGURATOR) { ConfiguratorItem() }
val SMALL_CAPSULE by registry.register(MNames.SMALL_CAPSULE) { BlockItem(MBlocks.SMALL_CAPSULE, DEFAULT_PROPERTIES) }
init { init {
MRegistry.registerItems(registry) MRegistry.registerItems(registry)
} }