Compare commits
24 Commits
3ec685b3f5
...
e31817e482
Author | SHA1 | Date | |
---|---|---|---|
e31817e482 | |||
fdfc406ca6 | |||
16f91343d8 | |||
3902e60424 | |||
c778f192b2 | |||
22ebdbb1eb | |||
0a9e90bec6 | |||
0126d4d976 | |||
ab2cc33b7a | |||
bfb8f0380a | |||
06f109575d | |||
a2d9f43a2e | |||
7c028b1fa6 | |||
57c6bbb795 | |||
3e92c5272d | |||
f9821aa552 | |||
b921658eb2 | |||
9b27ed7fb6 | |||
269227f6cf | |||
27834cc595 | |||
c343de6031 | |||
e6c9708652 | |||
a48aaf52ae | |||
9b384f2213 |
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
@ -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() {
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
@ -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)
|
||||||
|
@ -117,7 +117,7 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState)
|
|||||||
stack.shrink(1)
|
stack.shrink(1)
|
||||||
container.setChanged(0)
|
container.setChanged(0)
|
||||||
|
|
||||||
val actualMatter = dustMatter.matter * (0.4 + level!!.otmRandom.nextDouble() * 0.6)
|
val actualMatter = dustMatter.matter
|
||||||
|
|
||||||
return JobContainer.success(
|
return JobContainer.success(
|
||||||
RecyclerJob(
|
RecyclerJob(
|
||||||
@ -134,10 +134,11 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState)
|
|||||||
|
|
||||||
if (toReceive.isZero)
|
if (toReceive.isZero)
|
||||||
return status.success()
|
return status.success()
|
||||||
|
else if (matter.receiveMatter(toReceive, true) != toReceive)
|
||||||
|
return status.noMatter()
|
||||||
|
|
||||||
val received = matter.receiveMatter(toReceive, false)
|
matter.receiveMatter(toReceive * 0.4 + level!!.otmRandom.nextDouble() * 0.6, false)
|
||||||
status.scale(received / toReceive)
|
job.totalMatter -= toReceive
|
||||||
job.totalMatter -= received
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun tick() {
|
override fun tick() {
|
||||||
|
@ -14,6 +14,8 @@ import net.minecraft.world.inventory.tooltip.TooltipComponent
|
|||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
import ru.dbotthepony.mc.otm.client.minecraft
|
import ru.dbotthepony.mc.otm.client.minecraft
|
||||||
import ru.dbotthepony.kommons.math.RGBAColor
|
import ru.dbotthepony.kommons.math.RGBAColor
|
||||||
|
import ru.dbotthepony.mc.otm.client.screen.panels.ScreenPos
|
||||||
|
import java.util.Arrays
|
||||||
import kotlin.math.PI
|
import kotlin.math.PI
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
@ -45,6 +47,73 @@ class MGUIGraphics(val parent: GuiGraphics) {
|
|||||||
drawLine(pose.last().pose(), startX, startY, endX, endY, width, z, color)
|
drawLine(pose.last().pose(), startX, startY, endX, endY, width, z, color)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun drawLine(
|
||||||
|
points: Iterable<LinePoint>,
|
||||||
|
width: Float,
|
||||||
|
color: RGBAColor = RGBAColor.WHITE
|
||||||
|
) {
|
||||||
|
drawLine(pose.last().pose(), points, width, color)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun drawLine(
|
||||||
|
points: Array<out LinePoint>,
|
||||||
|
width: Float,
|
||||||
|
color: RGBAColor = RGBAColor.WHITE
|
||||||
|
) {
|
||||||
|
drawLine(pose.last().pose(), points, width, color)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun drawLine(
|
||||||
|
width: Float,
|
||||||
|
color: RGBAColor,
|
||||||
|
vararg points: LinePoint,
|
||||||
|
) {
|
||||||
|
drawLine(pose.last().pose(), points, width, color)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun drawLine(
|
||||||
|
width: Float,
|
||||||
|
color: RGBAColor,
|
||||||
|
points: Iterable<LinePoint>,
|
||||||
|
) {
|
||||||
|
drawLine(pose.last().pose(), points, width, color)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun drawLine(
|
||||||
|
width: Float,
|
||||||
|
color: RGBAColor,
|
||||||
|
z: Float,
|
||||||
|
points: List<ScreenPos>,
|
||||||
|
) {
|
||||||
|
require(points.size >= 2) { "Degenerate point list: only ${points.size} defined" }
|
||||||
|
|
||||||
|
val result = ArrayList<LinePoint>(points.size)
|
||||||
|
|
||||||
|
for (i in 1 until points.size) {
|
||||||
|
val (x0, y0) = points[i - 1]
|
||||||
|
val (x1, y1) = points[i]
|
||||||
|
|
||||||
|
result.add(
|
||||||
|
LinePoint(
|
||||||
|
x0, y0,
|
||||||
|
x1, y1,
|
||||||
|
z
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
drawLine(pose.last().pose(), result, width, color)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun drawLine(
|
||||||
|
width: Float,
|
||||||
|
color: RGBAColor,
|
||||||
|
z: Float,
|
||||||
|
vararg points: ScreenPos,
|
||||||
|
) {
|
||||||
|
drawLine(width, color, z, Arrays.asList(*points))
|
||||||
|
}
|
||||||
|
|
||||||
fun renderRect(
|
fun renderRect(
|
||||||
x: Float,
|
x: Float,
|
||||||
y: Float,
|
y: Float,
|
||||||
|
@ -294,6 +294,65 @@ fun renderColoredSphere(pose: PoseStack, radius: Float, color: RGBAColor = RGBAC
|
|||||||
BufferUploader.drawWithShader(builder.buildOrThrow())
|
BufferUploader.drawWithShader(builder.buildOrThrow())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun uploadLineSegment(
|
||||||
|
builder: BufferBuilder,
|
||||||
|
matrix: Matrix4f,
|
||||||
|
startX: Float,
|
||||||
|
startY: Float,
|
||||||
|
endX: Float,
|
||||||
|
endY: Float,
|
||||||
|
width: Float,
|
||||||
|
z: Float,
|
||||||
|
color: RGBAColor = RGBAColor.WHITE
|
||||||
|
) {
|
||||||
|
val length = ((startX - endX).pow(2f) + (startY - endY).pow(2f)).pow(0.5f)
|
||||||
|
var angle = acos((endX - startX) / length)
|
||||||
|
|
||||||
|
if (startY > endY)
|
||||||
|
angle *= -1f
|
||||||
|
|
||||||
|
val cos = cos(angle)
|
||||||
|
val sin = sin(angle)
|
||||||
|
|
||||||
|
val y0 = -width
|
||||||
|
|
||||||
|
val y1 = width
|
||||||
|
|
||||||
|
val x2 = length
|
||||||
|
val y2 = width
|
||||||
|
|
||||||
|
val x3 = length
|
||||||
|
val y3 = -width
|
||||||
|
|
||||||
|
builder.vertex(matrix,
|
||||||
|
startX - y0 * sin,
|
||||||
|
startY + y0 * cos,
|
||||||
|
z).color(color)
|
||||||
|
|
||||||
|
builder.vertex(matrix,
|
||||||
|
startX - y1 * sin,
|
||||||
|
startY + y1 * cos,
|
||||||
|
z).color(color)
|
||||||
|
|
||||||
|
builder.vertex(matrix,
|
||||||
|
startX + x2 * cos - y2 * sin,
|
||||||
|
startY + x2 * sin + y2 * cos,
|
||||||
|
z).color(color)
|
||||||
|
|
||||||
|
builder.vertex(matrix,
|
||||||
|
startX + x3 * cos - y3 * sin,
|
||||||
|
startY + x3 * sin + y3 * cos,
|
||||||
|
z).color(color)
|
||||||
|
}
|
||||||
|
|
||||||
|
data class LinePoint(
|
||||||
|
val startX: Float,
|
||||||
|
val startY: Float,
|
||||||
|
val endX: Float,
|
||||||
|
val endY: Float,
|
||||||
|
val z: Float = 0f,
|
||||||
|
)
|
||||||
|
|
||||||
fun drawLine(
|
fun drawLine(
|
||||||
matrix: Matrix4f,
|
matrix: Matrix4f,
|
||||||
startX: Float,
|
startX: Float,
|
||||||
@ -312,46 +371,46 @@ fun drawLine(
|
|||||||
RenderSystem.depthFunc(GL_ALWAYS)
|
RenderSystem.depthFunc(GL_ALWAYS)
|
||||||
|
|
||||||
val builder = tesselator.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR)
|
val builder = tesselator.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR)
|
||||||
|
uploadLineSegment(builder, matrix, startX, startY, endX, endY, width, z, color)
|
||||||
|
BufferUploader.drawWithShader(builder.buildOrThrow())
|
||||||
|
}
|
||||||
|
|
||||||
val length = ((startX - endX).pow(2f) + (startY - endY).pow(2f)).pow(0.5f)
|
fun drawLine(
|
||||||
val angle = acos((endX - startX) / length)
|
matrix: Matrix4f,
|
||||||
|
points: Iterable<LinePoint>,
|
||||||
|
width: Float,
|
||||||
|
color: RGBAColor = RGBAColor.WHITE
|
||||||
|
) {
|
||||||
|
val itr = points.iterator()
|
||||||
|
|
||||||
val cos = cos(angle)
|
if (!itr.hasNext()) {
|
||||||
val sin = sin(angle)
|
throw IllegalArgumentException("No line points were provided")
|
||||||
|
}
|
||||||
|
|
||||||
val y0 = -width
|
RenderSystem.setShader(GameRenderer::getPositionColorShader)
|
||||||
|
RenderSystem.enableBlend()
|
||||||
|
RenderSystem.defaultBlendFunc()
|
||||||
|
|
||||||
val y1 = width
|
if (!is3DContext)
|
||||||
|
RenderSystem.depthFunc(GL_ALWAYS)
|
||||||
|
|
||||||
val x2 = length
|
val builder = tesselator.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR)
|
||||||
val y2 = width
|
|
||||||
|
|
||||||
val x3 = length
|
for ((startX, startY, endX, endY, z) in itr)
|
||||||
val y3 = -width
|
uploadLineSegment(builder, matrix, startX, startY, endX, endY, width, z, color)
|
||||||
|
|
||||||
builder.vertex(matrix,
|
|
||||||
startX - y0 * sin,
|
|
||||||
startY + y0 * cos,
|
|
||||||
z).color(color)
|
|
||||||
|
|
||||||
builder.vertex(matrix,
|
|
||||||
startX - y1 * sin,
|
|
||||||
startY + y1 * cos,
|
|
||||||
z).color(color)
|
|
||||||
|
|
||||||
builder.vertex(matrix,
|
|
||||||
startX + x2 * cos - y2 * sin,
|
|
||||||
startY + x2 * sin + y2 * cos,
|
|
||||||
z).color(color)
|
|
||||||
|
|
||||||
builder.vertex(matrix,
|
|
||||||
startX + x3 * cos - y3 * sin,
|
|
||||||
startY + x3 * sin + y3 * cos,
|
|
||||||
z).color(color)
|
|
||||||
|
|
||||||
BufferUploader.drawWithShader(builder.buildOrThrow())
|
BufferUploader.drawWithShader(builder.buildOrThrow())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun drawLine(
|
||||||
|
matrix: Matrix4f,
|
||||||
|
points: Array<out LinePoint>,
|
||||||
|
width: Float,
|
||||||
|
color: RGBAColor = RGBAColor.WHITE
|
||||||
|
) {
|
||||||
|
return drawLine(matrix, points.asIterable(), width, color)
|
||||||
|
}
|
||||||
|
|
||||||
data class ScissorRect(val xStart: Int, val yStart: Int, val xEnd: Int, val yEnd: Int, val lock: Boolean = false) {
|
data class ScissorRect(val xStart: Int, val yStart: Int, val xEnd: Int, val yEnd: Int, val lock: Boolean = false) {
|
||||||
val width: Int
|
val width: Int
|
||||||
get() = (xEnd - xStart).coerceAtLeast(0)
|
get() = (xEnd - xStart).coerceAtLeast(0)
|
||||||
|
@ -30,6 +30,7 @@ object Widgets18 {
|
|||||||
val RESTOCK_FROM_STORAGE = storageGrid.next()
|
val RESTOCK_FROM_STORAGE = storageGrid.next()
|
||||||
val RESTOCK_WITH_MOVE_TO_STORAGE = storageGrid.next()
|
val RESTOCK_WITH_MOVE_TO_STORAGE = storageGrid.next()
|
||||||
val RESTOCK_WITH_MOVE_FROM_STORAGE = storageGrid.next()
|
val RESTOCK_WITH_MOVE_FROM_STORAGE = storageGrid.next()
|
||||||
|
val SMART_STORAGE_EXCHANGE = storageGrid.next()
|
||||||
|
|
||||||
private val miscGrid = WidgetLocation.WIDGET_18.grid(4, 4)
|
private val miscGrid = WidgetLocation.WIDGET_18.grid(4, 4)
|
||||||
|
|
||||||
|
@ -20,12 +20,13 @@ import ru.dbotthepony.mc.otm.core.math.asAngle
|
|||||||
import ru.dbotthepony.mc.otm.core.math.clusterize
|
import ru.dbotthepony.mc.otm.core.math.clusterize
|
||||||
import ru.dbotthepony.mc.otm.core.util.formatPower
|
import ru.dbotthepony.mc.otm.core.util.formatPower
|
||||||
import ru.dbotthepony.mc.otm.core.math.times
|
import ru.dbotthepony.mc.otm.core.math.times
|
||||||
|
import ru.dbotthepony.mc.otm.core.util.GJRAND64RandomSource
|
||||||
import java.util.Random
|
import java.util.Random
|
||||||
import kotlin.math.PI
|
import kotlin.math.PI
|
||||||
import kotlin.math.absoluteValue
|
import kotlin.math.absoluteValue
|
||||||
|
|
||||||
class EnergyCounterRenderer(private val context: BlockEntityRendererProvider.Context) : BlockEntityRenderer<EnergyCounterBlockEntity> {
|
class EnergyCounterRenderer(private val context: BlockEntityRendererProvider.Context) : BlockEntityRenderer<EnergyCounterBlockEntity> {
|
||||||
private val random = Random()
|
private val random = GJRAND64RandomSource()
|
||||||
|
|
||||||
override fun render(
|
override fun render(
|
||||||
tile: EnergyCounterBlockEntity,
|
tile: EnergyCounterBlockEntity,
|
||||||
|
@ -17,9 +17,11 @@ import net.neoforged.neoforge.common.NeoForge
|
|||||||
import org.lwjgl.opengl.GL11
|
import org.lwjgl.opengl.GL11
|
||||||
import ru.dbotthepony.kommons.util.getValue
|
import ru.dbotthepony.kommons.util.getValue
|
||||||
import ru.dbotthepony.kommons.util.setValue
|
import ru.dbotthepony.kommons.util.setValue
|
||||||
|
import ru.dbotthepony.kommons.math.RGBAColor
|
||||||
import ru.dbotthepony.mc.otm.player.matteryPlayer
|
import ru.dbotthepony.mc.otm.player.matteryPlayer
|
||||||
import ru.dbotthepony.mc.otm.client.render.MGUIGraphics
|
import ru.dbotthepony.mc.otm.client.render.MGUIGraphics
|
||||||
import ru.dbotthepony.mc.otm.client.moveMousePosScaled
|
import ru.dbotthepony.mc.otm.client.moveMousePosScaled
|
||||||
|
import ru.dbotthepony.mc.otm.client.render.LinePoint
|
||||||
import ru.dbotthepony.mc.otm.client.render.WidgetLocation
|
import ru.dbotthepony.mc.otm.client.render.WidgetLocation
|
||||||
import ru.dbotthepony.mc.otm.client.render.Widgets18
|
import ru.dbotthepony.mc.otm.client.render.Widgets18
|
||||||
import ru.dbotthepony.mc.otm.client.render.translation
|
import ru.dbotthepony.mc.otm.client.render.translation
|
||||||
@ -55,6 +57,7 @@ import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget
|
|||||||
import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget
|
import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.CopyOnWriteArrayList
|
import java.util.concurrent.CopyOnWriteArrayList
|
||||||
|
import kotlin.collections.ArrayList
|
||||||
import kotlin.collections.List
|
import kotlin.collections.List
|
||||||
import kotlin.collections.MutableSet
|
import kotlin.collections.MutableSet
|
||||||
import kotlin.collections.isNotEmpty
|
import kotlin.collections.isNotEmpty
|
||||||
@ -690,7 +693,13 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
|
|||||||
for (panel in panelsReversed) {
|
for (panel in panelsReversed) {
|
||||||
RenderSystem.depthFunc(GL11.GL_ALWAYS)
|
RenderSystem.depthFunc(GL11.GL_ALWAYS)
|
||||||
RenderSystem.setShaderColor(1f, 1f, 1f, 1f)
|
RenderSystem.setShaderColor(1f, 1f, 1f, 1f)
|
||||||
panel.render(wrap, mouseXf, mouseYf, partialTick)
|
val segments = ArrayList<LinePoint>()
|
||||||
|
|
||||||
|
panel.render(wrap, mouseXf, mouseYf, partialTick, segments)
|
||||||
|
|
||||||
|
if (segments.isNotEmpty()) {
|
||||||
|
wrap.drawLine(0.5f, RGBAColor.GOLD, segments)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!panelsReversed.any { it.updateCursor0() })
|
if (!panelsReversed.any { it.updateCursor0() })
|
||||||
|
@ -52,7 +52,7 @@ open class DecimalHistoryChartPanel<out S : MatteryScreen<*>>(
|
|||||||
|
|
||||||
map[1f] = formatText(maximum)
|
map[1f] = formatText(maximum)
|
||||||
|
|
||||||
for (cluster in chart.asIterable().clusterize(randomGenerator)) {
|
for (cluster in chart.asIterable().clusterize(random)) {
|
||||||
val perc = (cluster.center / maximum).toFloat()
|
val perc = (cluster.center / maximum).toFloat()
|
||||||
|
|
||||||
if (map.keys.none { (it - perc).absoluteValue < 0.08f }) {
|
if (map.keys.none { (it - perc).absoluteValue < 0.08f }) {
|
||||||
|
@ -11,94 +11,31 @@ import net.minecraft.client.gui.components.events.GuiEventListener
|
|||||||
import net.minecraft.client.gui.navigation.FocusNavigationEvent
|
import net.minecraft.client.gui.navigation.FocusNavigationEvent
|
||||||
import net.minecraft.client.gui.navigation.ScreenRectangle
|
import net.minecraft.client.gui.navigation.ScreenRectangle
|
||||||
import net.minecraft.client.gui.screens.Screen
|
import net.minecraft.client.gui.screens.Screen
|
||||||
import net.minecraft.client.renderer.Rect2i
|
|
||||||
import net.minecraft.network.chat.Component
|
import net.minecraft.network.chat.Component
|
||||||
import net.minecraft.util.RandomSource
|
|
||||||
import org.apache.logging.log4j.LogManager
|
import org.apache.logging.log4j.LogManager
|
||||||
|
import ru.dbotthepony.kommons.math.RGBAColor
|
||||||
import ru.dbotthepony.mc.otm.SystemTime
|
import ru.dbotthepony.mc.otm.SystemTime
|
||||||
import ru.dbotthepony.mc.otm.client.CursorType
|
import ru.dbotthepony.mc.otm.client.CursorType
|
||||||
import ru.dbotthepony.mc.otm.client.render.MGUIGraphics
|
import ru.dbotthepony.mc.otm.client.render.MGUIGraphics
|
||||||
import ru.dbotthepony.mc.otm.client.minecraft
|
import ru.dbotthepony.mc.otm.client.minecraft
|
||||||
import ru.dbotthepony.mc.otm.client.moveMousePosScaled
|
import ru.dbotthepony.mc.otm.client.moveMousePosScaled
|
||||||
|
import ru.dbotthepony.mc.otm.client.render.LinePoint
|
||||||
import ru.dbotthepony.mc.otm.client.render.RenderGravity
|
import ru.dbotthepony.mc.otm.client.render.RenderGravity
|
||||||
import ru.dbotthepony.mc.otm.client.render.currentScissorRect
|
import ru.dbotthepony.mc.otm.client.render.currentScissorRect
|
||||||
import ru.dbotthepony.mc.otm.client.render.popScissorRect
|
import ru.dbotthepony.mc.otm.client.render.popScissorRect
|
||||||
import ru.dbotthepony.mc.otm.client.render.pushScissorRect
|
import ru.dbotthepony.mc.otm.client.render.pushScissorRect
|
||||||
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
|
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.input.QueryUserPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.input.QueryUserPanel
|
||||||
import ru.dbotthepony.mc.otm.core.RandomSource2Generator
|
|
||||||
import ru.dbotthepony.mc.otm.core.collect.concatIterators
|
import ru.dbotthepony.mc.otm.core.collect.concatIterators
|
||||||
import ru.dbotthepony.mc.otm.core.collect.flatMap
|
import ru.dbotthepony.mc.otm.core.collect.flatMap
|
||||||
|
import ru.dbotthepony.mc.otm.core.util.GJRAND64RandomSource
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.CopyOnWriteArrayList
|
import java.util.concurrent.CopyOnWriteArrayList
|
||||||
import java.util.function.Predicate
|
import java.util.function.Predicate
|
||||||
import java.util.random.RandomGenerator
|
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
data class ScreenPos(val x: Float, val y: Float)
|
|
||||||
|
|
||||||
data class DockProperty(val left: Float = 0f, val top: Float = 0f, val right: Float = 0f, val bottom: Float = 0f) {
|
|
||||||
val isEmpty get() = left == 0f && right == 0f && top == 0f && bottom == 0f
|
|
||||||
val horizontal get() = left + right
|
|
||||||
val vertical get() = top + bottom
|
|
||||||
|
|
||||||
operator fun plus(other: DockProperty): DockProperty {
|
|
||||||
return DockProperty(
|
|
||||||
left + other.left,
|
|
||||||
top + other.top,
|
|
||||||
right + other.right,
|
|
||||||
bottom + other.bottom
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
operator fun minus(other: DockProperty): DockProperty {
|
|
||||||
return DockProperty(
|
|
||||||
left - other.left,
|
|
||||||
top - other.top,
|
|
||||||
right - other.right,
|
|
||||||
bottom - other.bottom
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
operator fun plus(other: Float): DockProperty {
|
|
||||||
return DockProperty(
|
|
||||||
left + other,
|
|
||||||
top + other,
|
|
||||||
right + other,
|
|
||||||
bottom + other
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
operator fun minus(other: Float): DockProperty {
|
|
||||||
return DockProperty(
|
|
||||||
left - other,
|
|
||||||
top - other,
|
|
||||||
right - other,
|
|
||||||
bottom - other
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
val EMPTY = DockProperty()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class Dock {
|
|
||||||
NONE, LEFT, RIGHT, TOP, BOTTOM, FILL
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class DockResizeMode(val changeWidth: Boolean, val changeHeight: Boolean) {
|
|
||||||
ALL(true, true), NONE(false, false), WIDTH(true, false), HEIGHT(false, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
data class Rect2f(val x: Float, val y: Float, val width: Float, val height: Float) {
|
|
||||||
fun toIntRect(): Rect2i {
|
|
||||||
return Rect2i(x.roundToInt(), y.roundToInt(), width.roundToInt(), height.roundToInt())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
open class EditablePanel<out S : Screen>(
|
open class EditablePanel<out S : Screen>(
|
||||||
val screen: S,
|
val screen: S,
|
||||||
parent: EditablePanel<*>?,
|
parent: EditablePanel<*>?,
|
||||||
@ -175,18 +112,14 @@ open class EditablePanel<out S : Screen>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val random: RandomSource by lazy {
|
val random: GJRAND64RandomSource by lazy {
|
||||||
if (screen is MatteryScreen<*>) {
|
if (screen is MatteryScreen<*>) {
|
||||||
screen.menu.random
|
screen.menu.random
|
||||||
} else {
|
} else {
|
||||||
RandomSource.create()
|
GJRAND64RandomSource()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val randomGenerator: RandomGenerator by lazy {
|
|
||||||
RandomSource2Generator(random)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bigger values means lesser priority while docking, rendering and processing inputs.
|
* Bigger values means lesser priority while docking, rendering and processing inputs.
|
||||||
*/
|
*/
|
||||||
@ -350,11 +283,13 @@ open class EditablePanel<out S : Screen>(
|
|||||||
|
|
||||||
if (visibleChildrenParent?.contains(this) == false) {
|
if (visibleChildrenParent?.contains(this) == false) {
|
||||||
visibleChildrenParent.add(this)
|
visibleChildrenParent.add(this)
|
||||||
|
parent?.invalidateChildrenSorting()
|
||||||
parent?.layoutInvalidated = true
|
parent?.layoutInvalidated = true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (visibleChildrenParent?.contains(this) == true) {
|
if (visibleChildrenParent?.contains(this) == true) {
|
||||||
visibleChildrenParent.remove(this)
|
visibleChildrenParent.remove(this)
|
||||||
|
parent?.invalidateChildrenSorting()
|
||||||
parent?.layoutInvalidated = true
|
parent?.layoutInvalidated = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -843,6 +778,12 @@ open class EditablePanel<out S : Screen>(
|
|||||||
childrenSortingInvalidated = true
|
childrenSortingInvalidated = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected open fun onChildrenAdded(child: EditablePanel<*>) {}
|
||||||
|
protected open fun onChildrenRemoved(child: EditablePanel<*>) {}
|
||||||
|
|
||||||
|
protected open fun onParented(parent: EditablePanel<*>) {}
|
||||||
|
protected open fun onUnParented(parent: EditablePanel<*>) {}
|
||||||
|
|
||||||
private fun onParent(child: EditablePanel<*>) {
|
private fun onParent(child: EditablePanel<*>) {
|
||||||
if (childrenInternal.contains(child)) throw IllegalStateException("Already containing $child")
|
if (childrenInternal.contains(child)) throw IllegalStateException("Already containing $child")
|
||||||
childrenInternal.add(child)
|
childrenInternal.add(child)
|
||||||
@ -860,11 +801,15 @@ open class EditablePanel<out S : Screen>(
|
|||||||
else
|
else
|
||||||
updateVisibility = true
|
updateVisibility = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onChildrenAdded(child)
|
||||||
|
child.onParented(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onUnParent(child: EditablePanel<*>) {
|
private fun onUnParent(child: EditablePanel<*>) {
|
||||||
val indexOf = childrenInternal.indexOf(child)
|
val indexOf = childrenInternal.indexOf(child)
|
||||||
if (indexOf == -1) throw IllegalStateException("Already not containing $child")
|
if (indexOf == -1) throw IllegalStateException("Already not containing $child")
|
||||||
|
child.onUnParented(this)
|
||||||
childrenInternal.removeAt(indexOf)
|
childrenInternal.removeAt(indexOf)
|
||||||
invalidateChildrenSorting()
|
invalidateChildrenSorting()
|
||||||
|
|
||||||
@ -876,6 +821,8 @@ open class EditablePanel<out S : Screen>(
|
|||||||
if (child.isVisible() != isVisible()) {
|
if (child.isVisible() != isVisible()) {
|
||||||
updateVisible()
|
updateVisible()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onChildrenRemoved(child)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun sortChildren() {
|
private fun sortChildren() {
|
||||||
@ -944,12 +891,11 @@ open class EditablePanel<out S : Screen>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun render(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
|
fun render(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float, debugSegments: MutableList<LinePoint>) {
|
||||||
once = true
|
once = true
|
||||||
|
|
||||||
if (!isVisible()) {
|
if (!isVisible())
|
||||||
return
|
return
|
||||||
}
|
|
||||||
|
|
||||||
val poseStack = graphics.pose
|
val poseStack = graphics.pose
|
||||||
|
|
||||||
@ -997,12 +943,19 @@ open class EditablePanel<out S : Screen>(
|
|||||||
child.absoluteX = absoluteX + child.x + xOffset
|
child.absoluteX = absoluteX + child.x + xOffset
|
||||||
child.absoluteY = absoluteY + child.y + yOffset
|
child.absoluteY = absoluteY + child.y + yOffset
|
||||||
|
|
||||||
child.render(graphics, mouseX, mouseY, partialTick)
|
child.render(graphics, mouseX, mouseY, partialTick, debugSegments)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scissor) {
|
if (scissor) {
|
||||||
popScissorRect()
|
popScissorRect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (minecraft.entityRenderDispatcher.shouldRenderHitBoxes()) {
|
||||||
|
debugSegments.add(LinePoint(absoluteX, absoluteY, absoluteX + width, absoluteY))
|
||||||
|
debugSegments.add(LinePoint(absoluteX + width, absoluteY, absoluteX + width, absoluteY + height))
|
||||||
|
debugSegments.add(LinePoint(absoluteX + width, absoluteY + height, absoluteX, absoluteY + height))
|
||||||
|
debugSegments.add(LinePoint(absoluteX, absoluteY + height, absoluteX, absoluteY))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateCursor0(): Boolean {
|
fun updateCursor0(): Boolean {
|
||||||
@ -1508,6 +1461,7 @@ open class EditablePanel<out S : Screen>(
|
|||||||
|
|
||||||
if (old != new) {
|
if (old != new) {
|
||||||
child.visibilityChanges(new, old)
|
child.visibilityChanges(new, old)
|
||||||
|
child.invalidateChildrenSorting()
|
||||||
}
|
}
|
||||||
|
|
||||||
child.updateVisible()
|
child.updateVisible()
|
||||||
|
@ -4,6 +4,8 @@ import net.minecraft.client.gui.GuiGraphics
|
|||||||
import net.minecraft.client.gui.components.Renderable
|
import net.minecraft.client.gui.components.Renderable
|
||||||
import net.minecraft.client.gui.components.events.GuiEventListener
|
import net.minecraft.client.gui.components.events.GuiEventListener
|
||||||
import net.minecraft.client.gui.screens.Screen
|
import net.minecraft.client.gui.screens.Screen
|
||||||
|
import ru.dbotthepony.kommons.math.RGBAColor
|
||||||
|
import ru.dbotthepony.mc.otm.client.render.LinePoint
|
||||||
import ru.dbotthepony.mc.otm.client.render.MGUIGraphics
|
import ru.dbotthepony.mc.otm.client.render.MGUIGraphics
|
||||||
|
|
||||||
// before 1.19.3 Renderable was Widget
|
// before 1.19.3 Renderable was Widget
|
||||||
@ -21,11 +23,17 @@ class Panel2Widget<out S: Screen, out P : EditablePanel<S>>(
|
|||||||
val yFloat = mouseY.toFloat()
|
val yFloat = mouseY.toFloat()
|
||||||
|
|
||||||
val wrap = MGUIGraphics(graphics)
|
val wrap = MGUIGraphics(graphics)
|
||||||
|
val segments = ArrayList<LinePoint>()
|
||||||
|
|
||||||
panel.tickHovered0(xFloat, yFloat, false)
|
panel.tickHovered0(xFloat, yFloat, false)
|
||||||
panel.tickHovered1()
|
panel.tickHovered1()
|
||||||
panel.tickHovered2()
|
panel.tickHovered2()
|
||||||
panel.render(wrap, xFloat, yFloat, partialTick)
|
panel.render(wrap, xFloat, yFloat, partialTick, segments)
|
||||||
|
|
||||||
|
if (segments.isNotEmpty()) {
|
||||||
|
wrap.drawLine(0.5f, RGBAColor.GOLD, segments)
|
||||||
|
}
|
||||||
|
|
||||||
panel.renderTooltips(wrap, xFloat, yFloat, partialTick)
|
panel.renderTooltips(wrap, xFloat, yFloat, partialTick)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,115 @@
|
|||||||
|
package ru.dbotthepony.mc.otm.client.screen.panels
|
||||||
|
|
||||||
|
import net.minecraft.client.renderer.Rect2i
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
data class ScreenPos(val x: Float, val y: Float)
|
||||||
|
|
||||||
|
data class DockProperty(val left: Float = 0f, val top: Float = 0f, val right: Float = 0f, val bottom: Float = 0f) {
|
||||||
|
val isEmpty get() = left == 0f && right == 0f && top == 0f && bottom == 0f
|
||||||
|
val horizontal get() = left + right
|
||||||
|
val vertical get() = top + bottom
|
||||||
|
|
||||||
|
operator fun plus(other: DockProperty): DockProperty {
|
||||||
|
return DockProperty(
|
||||||
|
left + other.left,
|
||||||
|
top + other.top,
|
||||||
|
right + other.right,
|
||||||
|
bottom + other.bottom
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun minus(other: DockProperty): DockProperty {
|
||||||
|
return DockProperty(
|
||||||
|
left - other.left,
|
||||||
|
top - other.top,
|
||||||
|
right - other.right,
|
||||||
|
bottom - other.bottom
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun plus(other: Float): DockProperty {
|
||||||
|
return DockProperty(
|
||||||
|
left + other,
|
||||||
|
top + other,
|
||||||
|
right + other,
|
||||||
|
bottom + other
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun minus(other: Float): DockProperty {
|
||||||
|
return DockProperty(
|
||||||
|
left - other,
|
||||||
|
top - other,
|
||||||
|
right - other,
|
||||||
|
bottom - other
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val EMPTY = DockProperty()
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun all(value: Float): DockProperty {
|
||||||
|
return DockProperty(value, value, value, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
@JvmOverloads
|
||||||
|
fun topLeft(top: Float, left: Float = top): DockProperty {
|
||||||
|
return DockProperty(left = left, top = top)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun left(value: Float): DockProperty {
|
||||||
|
return DockProperty(left = value)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
@JvmOverloads
|
||||||
|
fun topRight(top: Float, right: Float = top): DockProperty {
|
||||||
|
return DockProperty(right = right, top = top)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun right(value: Float): DockProperty {
|
||||||
|
return DockProperty(right = value)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun top(value: Float): DockProperty {
|
||||||
|
return DockProperty(top = value)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
@JvmOverloads
|
||||||
|
fun bottomLeft(bottom: Float, left: Float = bottom): DockProperty {
|
||||||
|
return DockProperty(left = left, bottom = bottom)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
@JvmOverloads
|
||||||
|
fun bottomRight(bottom: Float, right: Float = bottom): DockProperty {
|
||||||
|
return DockProperty(right = right, bottom = bottom)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun bottom(value: Float): DockProperty {
|
||||||
|
return DockProperty(bottom = value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class Dock {
|
||||||
|
NONE, LEFT, RIGHT, TOP, BOTTOM, FILL
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class DockResizeMode(val changeWidth: Boolean, val changeHeight: Boolean) {
|
||||||
|
ALL(true, true), NONE(false, false), WIDTH(true, false), HEIGHT(false, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Rect2f(val x: Float, val y: Float, val width: Float, val height: Float) {
|
||||||
|
fun toIntRect(): Rect2i {
|
||||||
|
return Rect2i(x.roundToInt(), y.roundToInt(), width.roundToInt(), height.roundToInt())
|
||||||
|
}
|
||||||
|
}
|
@ -7,6 +7,9 @@ import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
|
|||||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel
|
||||||
import ru.dbotthepony.mc.otm.core.collect.filter
|
import ru.dbotthepony.mc.otm.core.collect.filter
|
||||||
import ru.dbotthepony.mc.otm.core.collect.maybe
|
import ru.dbotthepony.mc.otm.core.collect.maybe
|
||||||
|
import java.util.stream.IntStream
|
||||||
|
import java.util.stream.Stream
|
||||||
|
import kotlin.math.max
|
||||||
|
|
||||||
open class GridPanel<out S : Screen>(
|
open class GridPanel<out S : Screen>(
|
||||||
screen: S,
|
screen: S,
|
||||||
@ -20,25 +23,150 @@ open class GridPanel<out S : Screen>(
|
|||||||
) : EditablePanel<S>(screen, parent, x, y, width, height) {
|
) : EditablePanel<S>(screen, parent, x, y, width, height) {
|
||||||
var columns: Int = columns
|
var columns: Int = columns
|
||||||
set(value) {
|
set(value) {
|
||||||
field = value
|
if (field != value) {
|
||||||
invalidateLayout()
|
field = value
|
||||||
|
invalidateLayout()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var rows: Int = rows
|
var rows: Int = rows
|
||||||
set(value) {
|
set(value) {
|
||||||
field = value
|
if (field != value) {
|
||||||
invalidateLayout()
|
field = value
|
||||||
|
invalidateLayout()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var gravity: RenderGravity = RenderGravity.CENTER_CENTER
|
var gravity: RenderGravity = RenderGravity.CENTER_CENTER
|
||||||
set(value) {
|
set(value) {
|
||||||
field = value
|
if (field != value) {
|
||||||
invalidateLayout()
|
field = value
|
||||||
|
invalidateLayout()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var layout: Layout = Layout.TOP_LEFT
|
||||||
|
set(value) {
|
||||||
|
if (field != value) {
|
||||||
|
field = value
|
||||||
|
invalidateLayout()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var columnMajorOrder = false
|
||||||
|
set(value) {
|
||||||
|
if (field != value) {
|
||||||
|
field = value
|
||||||
|
invalidateLayout()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class Layout {
|
||||||
|
TOP_LEFT {
|
||||||
|
override fun get(
|
||||||
|
list: List<EditablePanel<*>>,
|
||||||
|
row: Int,
|
||||||
|
column: Int,
|
||||||
|
rows: Int,
|
||||||
|
columns: Int,
|
||||||
|
columnMajorOrder: Boolean
|
||||||
|
): EditablePanel<*>? {
|
||||||
|
if (columnMajorOrder) {
|
||||||
|
return list.getOrNull(row + column * rows)
|
||||||
|
} else {
|
||||||
|
return list.getOrNull(column + row * columns)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
TOP_RIGHT {
|
||||||
|
override fun get(
|
||||||
|
list: List<EditablePanel<*>>,
|
||||||
|
row: Int,
|
||||||
|
column: Int,
|
||||||
|
rows: Int,
|
||||||
|
columns: Int,
|
||||||
|
columnMajorOrder: Boolean
|
||||||
|
): EditablePanel<*>? {
|
||||||
|
if (columnMajorOrder) {
|
||||||
|
return list.getOrNull(row + (columns - column - 1) * rows)
|
||||||
|
} else {
|
||||||
|
return list.getOrNull((columns - column - 1) + row * columns)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
BOTTOM_LEFT {
|
||||||
|
override fun get(
|
||||||
|
list: List<EditablePanel<*>>,
|
||||||
|
row: Int,
|
||||||
|
column: Int,
|
||||||
|
rows: Int,
|
||||||
|
columns: Int,
|
||||||
|
columnMajorOrder: Boolean
|
||||||
|
): EditablePanel<*>? {
|
||||||
|
if (columnMajorOrder) {
|
||||||
|
return list.getOrNull((rows - row - 1) + column * rows)
|
||||||
|
} else {
|
||||||
|
return list.getOrNull(column + (rows - row - 1) * columns)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
BOTTOM_RIGHT {
|
||||||
|
override fun get(
|
||||||
|
list: List<EditablePanel<*>>,
|
||||||
|
row: Int,
|
||||||
|
column: Int,
|
||||||
|
rows: Int,
|
||||||
|
columns: Int,
|
||||||
|
columnMajorOrder: Boolean
|
||||||
|
): EditablePanel<*>? {
|
||||||
|
if (columnMajorOrder) {
|
||||||
|
return list.getOrNull((rows - row - 1) + (columns - column - 1) * rows)
|
||||||
|
} else {
|
||||||
|
return list.getOrNull((columns - column - 1) + (rows - row - 1) * columns)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
abstract fun get(list: List<EditablePanel<*>>, row: Int, column: Int, rows: Int, columns: Int, columnMajorOrder: Boolean): EditablePanel<*>?
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun sizeToContents() {
|
||||||
|
if (visibleChildren.isEmpty()) {
|
||||||
|
// nothing to size against
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
visibleChildren.forEach { it.sizeToContents() }
|
||||||
|
|
||||||
|
var width = 0f
|
||||||
|
var height = 0f
|
||||||
|
|
||||||
|
val children = visibleChildren.filter { it.dock == Dock.NONE }
|
||||||
|
|
||||||
|
for (row in 0 until rows) {
|
||||||
|
var maxHeight = 0f
|
||||||
|
var rowWidth = 0f
|
||||||
|
|
||||||
|
for (column in 0 until columns) {
|
||||||
|
val nextChild = layout.get(children, row, column, rows, columns, columnMajorOrder) ?: continue
|
||||||
|
rowWidth += nextChild.width + nextChild.dockMargin.horizontal
|
||||||
|
maxHeight = max(maxHeight, nextChild.height + nextChild.dockMargin.vertical)
|
||||||
|
}
|
||||||
|
|
||||||
|
height += maxHeight
|
||||||
|
width = max(width, rowWidth)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.width = width
|
||||||
|
this.height = height
|
||||||
|
}
|
||||||
|
|
||||||
override fun performLayout() {
|
override fun performLayout() {
|
||||||
super.performLayout()
|
super.performLayout()
|
||||||
var children = visibleChildren.iterator().filter { it.dock == Dock.NONE }
|
val children = visibleChildren.filter { it.dock == Dock.NONE }
|
||||||
|
|
||||||
var totalWidth = 0f
|
var totalWidth = 0f
|
||||||
var totalHeight = 0f
|
var totalHeight = 0f
|
||||||
@ -48,7 +176,7 @@ open class GridPanel<out S : Screen>(
|
|||||||
var width = 0f
|
var width = 0f
|
||||||
|
|
||||||
for (column in 0 until columns) {
|
for (column in 0 until columns) {
|
||||||
val child = children.maybe() ?: break
|
val child = layout.get(children, row, column, rows, columns, columnMajorOrder) ?: continue
|
||||||
width += child.dockedWidth
|
width += child.dockedWidth
|
||||||
maxHeight = maxHeight.coerceAtLeast(child.dockedHeight)
|
maxHeight = maxHeight.coerceAtLeast(child.dockedHeight)
|
||||||
}
|
}
|
||||||
@ -59,7 +187,6 @@ open class GridPanel<out S : Screen>(
|
|||||||
|
|
||||||
val alignX = gravity.repositionX(width, totalWidth)
|
val alignX = gravity.repositionX(width, totalWidth)
|
||||||
val alignY = gravity.repositionY(height, totalHeight)
|
val alignY = gravity.repositionY(height, totalHeight)
|
||||||
children = visibleChildren.iterator().filter { it.dock == Dock.NONE }
|
|
||||||
|
|
||||||
totalWidth = 0f
|
totalWidth = 0f
|
||||||
totalHeight = 0f
|
totalHeight = 0f
|
||||||
@ -69,7 +196,7 @@ open class GridPanel<out S : Screen>(
|
|||||||
var width = 0f
|
var width = 0f
|
||||||
|
|
||||||
for (column in 0 until columns) {
|
for (column in 0 until columns) {
|
||||||
val child = children.maybe() ?: break
|
val child = layout.get(children, row, column, rows, columns, columnMajorOrder) ?: continue
|
||||||
child.x = alignX + width
|
child.x = alignX + width
|
||||||
child.y = alignY + totalHeight
|
child.y = alignY + totalHeight
|
||||||
width += child.dockedWidth
|
width += child.dockedWidth
|
||||||
|
@ -7,6 +7,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
|
|||||||
import net.minecraft.ChatFormatting
|
import net.minecraft.ChatFormatting
|
||||||
import net.minecraft.client.Minecraft
|
import net.minecraft.client.Minecraft
|
||||||
import net.minecraft.network.chat.Component
|
import net.minecraft.network.chat.Component
|
||||||
|
import net.minecraft.util.RandomSource
|
||||||
import net.minecraft.world.entity.player.Inventory
|
import net.minecraft.world.entity.player.Inventory
|
||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
import net.neoforged.neoforge.network.PacketDistributor
|
import net.neoforged.neoforge.network.PacketDistributor
|
||||||
@ -34,6 +35,7 @@ import ru.dbotthepony.mc.otm.config.MachinesConfig
|
|||||||
import ru.dbotthepony.kommons.math.RGBAColor
|
import ru.dbotthepony.kommons.math.RGBAColor
|
||||||
import ru.dbotthepony.mc.otm.player.matteryPlayer
|
import ru.dbotthepony.mc.otm.player.matteryPlayer
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.button.BooleanButtonPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.button.BooleanButtonPanel
|
||||||
|
import ru.dbotthepony.mc.otm.core.nextFloat
|
||||||
import ru.dbotthepony.mc.otm.menu.tech.AndroidStationMenu
|
import ru.dbotthepony.mc.otm.menu.tech.AndroidStationMenu
|
||||||
import ru.dbotthepony.mc.otm.network.AndroidResearchRequestPacket
|
import ru.dbotthepony.mc.otm.network.AndroidResearchRequestPacket
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -540,14 +542,14 @@ class AndroidStationScreen(p_97741_: AndroidStationMenu, p_97742_: Inventory, p_
|
|||||||
|
|
||||||
if (isPreview && !layoutInvalidated) {
|
if (isPreview && !layoutInvalidated) {
|
||||||
if (firstTick) {
|
if (firstTick) {
|
||||||
scroller.init.invoke(this, randomGenerator)
|
scroller.init.invoke(this, random)
|
||||||
}
|
}
|
||||||
|
|
||||||
val status = scroller.scroll.invoke(this, randomGenerator)
|
val status = scroller.scroll.invoke(this, random)
|
||||||
|
|
||||||
if (!status) {
|
if (!status) {
|
||||||
scroller = PreviewScrollers.entries.let { it[random.nextInt(it.size)] }
|
scroller = PreviewScrollers.entries.let { it[random.nextInt(it.size)] }
|
||||||
scroller.init.invoke(this, randomGenerator)
|
scroller.init.invoke(this, random)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
@ -662,3 +672,21 @@ fun RandomSource.nextNormalDoubles(stddev: Double, mean: Double): DoublePair {
|
|||||||
fun RandomSource.nextNormalDouble(stddev: Double, mean: Double): Double {
|
fun RandomSource.nextNormalDouble(stddev: Double, mean: Double): Double {
|
||||||
return nextGaussian() * stddev + mean
|
return nextGaussian() * stddev + mean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun RandomSource.nextFloat(min: Float, max: Float): Float {
|
||||||
|
if (this is RandomGenerator)
|
||||||
|
return nextFloat(min, max)
|
||||||
|
|
||||||
|
require(max >= min) { "Min is bigger than max: $min vs $max" }
|
||||||
|
if (min == max) return min
|
||||||
|
return min + nextFloat() * (max - min)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun RandomSource.nextDouble(min: Double, max: Double): Double {
|
||||||
|
if (this is RandomGenerator)
|
||||||
|
return nextDouble(min, max)
|
||||||
|
|
||||||
|
require(max >= min) { "Min is bigger than max: $min vs $max" }
|
||||||
|
if (min == max) return min
|
||||||
|
return min + nextDouble() * (max - min)
|
||||||
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package ru.dbotthepony.mc.otm.core.math
|
package ru.dbotthepony.mc.otm.core.math
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList
|
||||||
|
import net.minecraft.util.RandomSource
|
||||||
import ru.dbotthepony.mc.otm.core.random
|
import ru.dbotthepony.mc.otm.core.random
|
||||||
import java.util.random.RandomGenerator
|
import java.util.random.RandomGenerator
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
@ -88,7 +89,7 @@ private class MutableCluster<V : Comparable<V>>(var center: V) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun <V : Comparable<V>> Iterable<V>.clusterize(
|
private fun <V : Comparable<V>> Iterable<V>.clusterize(
|
||||||
random: RandomGenerator,
|
random: RandomSource,
|
||||||
initialClusters: Int = 1,
|
initialClusters: Int = 1,
|
||||||
zeroBound: Boolean = false,
|
zeroBound: Boolean = false,
|
||||||
identity: V,
|
identity: V,
|
||||||
@ -202,7 +203,7 @@ private fun <V : Comparable<V>> Iterable<V>.clusterize(
|
|||||||
// TODO: could use some tweaking
|
// TODO: could use some tweaking
|
||||||
private val DECIMAL_ERROR_TOLERANCE = Decimal("0.02")
|
private val DECIMAL_ERROR_TOLERANCE = Decimal("0.02")
|
||||||
|
|
||||||
fun Iterable<Decimal>.clusterize(random: RandomGenerator, clusters: Int? = null, zeroBound: Boolean = false): List<Cluster<Decimal>> {
|
fun Iterable<Decimal>.clusterize(random: RandomSource, clusters: Int? = null, zeroBound: Boolean = false): List<Cluster<Decimal>> {
|
||||||
return clusterize(random, clusters ?: 1, zeroBound, Decimal.ZERO, Decimal::plus, Decimal::minus, Decimal::div, Decimal::absoluteValue) { min, max, error ->
|
return clusterize(random, clusters ?: 1, zeroBound, Decimal.ZERO, Decimal::plus, Decimal::minus, Decimal::div, Decimal::absoluteValue) { min, max, error ->
|
||||||
if (clusters != null)
|
if (clusters != null)
|
||||||
false
|
false
|
||||||
|
@ -0,0 +1,147 @@
|
|||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var lootTableRounds: Int? = 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!!)
|
||||||
|
|
||||||
|
if (lootTableRounds != null)
|
||||||
|
nbt.putInt("LootRounds", lootTableRounds!!)
|
||||||
|
}
|
||||||
|
} 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
|
||||||
|
lootTableRounds = if (nbt.contains("LootRounds", Tag.TAG_INT.toInt())) nbt.getInt("LootRounds") else null
|
||||||
|
|
||||||
|
if (lootTableRounds != null && lootTableRounds!! < 0)
|
||||||
|
lootTableRounds = 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? = null): MutableList<ItemStack> {
|
||||||
|
return lookup(level).getRandomItems(params, selectRandom(overrideSeed, level.otmRandom), rounds ?: lootTableRounds ?: 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getItems(params: LootParams.Builder, blockState: BlockState, overrideSeed: Long? = null, rounds: Int? = null): 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? = null) {
|
||||||
|
if (rounds == 0)
|
||||||
|
return
|
||||||
|
else if (rounds != null && 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 ?: lootTableRounds ?: 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clear() {
|
||||||
|
lootTable = null
|
||||||
|
lootTableSeed = null
|
||||||
|
}
|
||||||
|
}
|
@ -9,6 +9,7 @@ import net.minecraft.network.chat.FormattedText
|
|||||||
import net.minecraft.network.chat.MutableComponent
|
import net.minecraft.network.chat.MutableComponent
|
||||||
import net.minecraft.world.inventory.tooltip.TooltipComponent
|
import net.minecraft.world.inventory.tooltip.TooltipComponent
|
||||||
import ru.dbotthepony.kommons.math.RGBAColor
|
import ru.dbotthepony.kommons.math.RGBAColor
|
||||||
|
import ru.dbotthepony.mc.otm.THREAD_LOCAL_RANDOM
|
||||||
import ru.dbotthepony.mc.otm.client.render.ChartLevelLabels
|
import ru.dbotthepony.mc.otm.client.render.ChartLevelLabels
|
||||||
import ru.dbotthepony.mc.otm.client.render.ChartTooltipElement
|
import ru.dbotthepony.mc.otm.client.render.ChartTooltipElement
|
||||||
import ru.dbotthepony.mc.otm.config.ClientConfig
|
import ru.dbotthepony.mc.otm.config.ClientConfig
|
||||||
@ -453,10 +454,8 @@ private fun formatHistoryChart(
|
|||||||
labelNames[0f] = (-maxTransferred).formatSiComponent(suffix, decimals, formatAsReadable = verbose, bias = bias)
|
labelNames[0f] = (-maxTransferred).formatSiComponent(suffix, decimals, formatAsReadable = verbose, bias = bias)
|
||||||
labelNames[1f] = maxReceived.formatSiComponent(suffix, decimals, formatAsReadable = verbose, bias = bias)
|
labelNames[1f] = maxReceived.formatSiComponent(suffix, decimals, formatAsReadable = verbose, bias = bias)
|
||||||
|
|
||||||
val rand = java.util.Random()
|
|
||||||
|
|
||||||
if (maxTransferred.isNotZero && transferredMult > 0.2f) {
|
if (maxTransferred.isNotZero && transferredMult > 0.2f) {
|
||||||
for (cluster in widget.transferred.clusterize(rand, zeroBound = true)) {
|
for (cluster in widget.transferred.clusterize(THREAD_LOCAL_RANDOM, zeroBound = true)) {
|
||||||
val perc = (cluster.center / maxTransferred).toFloat() * transferredMult
|
val perc = (cluster.center / maxTransferred).toFloat() * transferredMult
|
||||||
|
|
||||||
if (labelNames.keys.none { (it - perc).absoluteValue < 0.08f })
|
if (labelNames.keys.none { (it - perc).absoluteValue < 0.08f })
|
||||||
@ -465,7 +464,7 @@ private fun formatHistoryChart(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (maxReceived.isNotZero && receivedMult > 0.2f) {
|
if (maxReceived.isNotZero && receivedMult > 0.2f) {
|
||||||
for (cluster in widget.received.clusterize(rand, zeroBound = true)) {
|
for (cluster in widget.received.clusterize(THREAD_LOCAL_RANDOM, zeroBound = true)) {
|
||||||
val perc = zero + (cluster.center / maxReceived).toFloat() * receivedMult
|
val perc = zero + (cluster.center / maxReceived).toFloat() * receivedMult
|
||||||
|
|
||||||
if (labelNames.keys.none { (it - perc).absoluteValue < 0.08f })
|
if (labelNames.keys.none { (it - perc).absoluteValue < 0.08f })
|
||||||
@ -473,7 +472,7 @@ private fun formatHistoryChart(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val clusters = diff.asIterable().clusterize(rand, zeroBound = true)
|
val clusters = diff.asIterable().clusterize(THREAD_LOCAL_RANDOM, zeroBound = true)
|
||||||
|
|
||||||
for (cluster in clusters) {
|
for (cluster in clusters) {
|
||||||
val perc: Float
|
val perc: Float
|
||||||
|
@ -2,15 +2,12 @@ package ru.dbotthepony.mc.otm.core.util
|
|||||||
|
|
||||||
import net.minecraft.util.Mth
|
import net.minecraft.util.Mth
|
||||||
import net.minecraft.util.RandomSource
|
import net.minecraft.util.RandomSource
|
||||||
import net.minecraft.world.level.levelgen.MarsagliaPolarGaussian
|
|
||||||
import net.minecraft.world.level.levelgen.PositionalRandomFactory
|
import net.minecraft.world.level.levelgen.PositionalRandomFactory
|
||||||
import net.minecraft.world.level.levelgen.RandomSupport
|
import net.minecraft.world.level.levelgen.RandomSupport
|
||||||
import ru.dbotthepony.kommons.random.GJRAND64Random
|
import ru.dbotthepony.kommons.random.GJRAND64Random
|
||||||
import java.lang.StringBuilder
|
import java.lang.StringBuilder
|
||||||
|
|
||||||
class GJRAND64RandomSource : GJRAND64Random, IRandomSourceGenerator {
|
class GJRAND64RandomSource : GJRAND64Random, IRandomSourceGenerator {
|
||||||
private val gaussian = MarsagliaPolarGaussian(this)
|
|
||||||
|
|
||||||
constructor() : super(RandomSupport.generateUniqueSeed(), RandomSupport.generateUniqueSeed())
|
constructor() : super(RandomSupport.generateUniqueSeed(), RandomSupport.generateUniqueSeed())
|
||||||
constructor(seed: Long) : super(seed)
|
constructor(seed: Long) : super(seed)
|
||||||
constructor(seed0: Long, seed1: Long) : super(seed0, seed1)
|
constructor(seed0: Long, seed1: Long) : super(seed0, seed1)
|
||||||
@ -19,10 +16,6 @@ class GJRAND64RandomSource : GJRAND64Random, IRandomSourceGenerator {
|
|||||||
return nextLong().ushr(32).toInt()
|
return nextLong().ushr(32).toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun nextGaussian(): Double {
|
|
||||||
return gaussian.nextGaussian()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun fork(): RandomSource {
|
override fun fork(): RandomSource {
|
||||||
return GJRAND64RandomSource(nextLong(), nextLong())
|
return GJRAND64RandomSource(nextLong(), nextLong())
|
||||||
}
|
}
|
||||||
@ -33,7 +26,6 @@ class GJRAND64RandomSource : GJRAND64Random, IRandomSourceGenerator {
|
|||||||
|
|
||||||
override fun setSeed(seed: Long) {
|
override fun setSeed(seed: Long) {
|
||||||
reinitialize(seed)
|
reinitialize(seed)
|
||||||
gaussian.reset()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Positional(private val seed0: Long, private val seed1: Long) : PositionalRandomFactory {
|
class Positional(private val seed0: Long, private val seed1: Long) : PositionalRandomFactory {
|
||||||
|
@ -26,5 +26,7 @@ interface IRandomSourceGenerator : RandomSource, RandomGenerator {
|
|||||||
return super.nextDouble()
|
return super.nextDouble()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun nextGaussian(): Double
|
override fun nextGaussian(): Double {
|
||||||
|
return super.nextGaussian()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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")
|
||||||
|
}
|
||||||
|
}
|
@ -20,6 +20,9 @@ import ru.dbotthepony.mc.otm.client.minecraft
|
|||||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||||
import ru.dbotthepony.mc.otm.core.isExplosion
|
import ru.dbotthepony.mc.otm.core.isExplosion
|
||||||
import ru.dbotthepony.mc.otm.core.isFire
|
import ru.dbotthepony.mc.otm.core.isFire
|
||||||
|
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
||||||
|
import ru.dbotthepony.mc.otm.core.nextUUID
|
||||||
|
import ru.dbotthepony.mc.otm.core.otmRandom
|
||||||
import ru.dbotthepony.mc.otm.registry.game.MItems
|
import ru.dbotthepony.mc.otm.registry.game.MItems
|
||||||
import ru.dbotthepony.mc.otm.runIfClient
|
import ru.dbotthepony.mc.otm.runIfClient
|
||||||
import ru.dbotthepony.mc.otm.triggers.ExopackSlotsExpandedTrigger
|
import ru.dbotthepony.mc.otm.triggers.ExopackSlotsExpandedTrigger
|
||||||
@ -35,7 +38,7 @@ abstract class AbstractExopackSlotUpgradeItem(properties: Properties = defaultPr
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getUseDuration(p_41454_: ItemStack, p_344979_: LivingEntity): Int {
|
override fun getUseDuration(p_41454_: ItemStack, p_344979_: LivingEntity): Int {
|
||||||
return 30
|
return 20
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun appendHoverText(
|
override fun appendHoverText(
|
||||||
@ -76,7 +79,7 @@ abstract class AbstractExopackSlotUpgradeItem(properties: Properties = defaultPr
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun use(p_41432_: Level, player: Player, hand: InteractionHand): InteractionResultHolder<ItemStack> {
|
override fun use(p_41432_: Level, player: Player, hand: InteractionHand): InteractionResultHolder<ItemStack> {
|
||||||
val matteryPlayer = player.matteryPlayer ?: return super.use(p_41432_, player, hand)
|
val matteryPlayer = player.matteryPlayer
|
||||||
|
|
||||||
val uuid = uuid(player.getItemInHand(hand))
|
val uuid = uuid(player.getItemInHand(hand))
|
||||||
|
|
||||||
@ -98,25 +101,32 @@ abstract class AbstractExopackSlotUpgradeItem(properties: Properties = defaultPr
|
|||||||
return super.finishUsingItem(itemStack, level, player)
|
return super.finishUsingItem(itemStack, level, player)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!player.abilities.instabuild)
|
var allowedUses = itemStack.count
|
||||||
itemStack.shrink(1)
|
|
||||||
|
|
||||||
if (player is ServerPlayer) {
|
while (allowedUses > 0) {
|
||||||
if (uuid != null) {
|
if (!player.abilities.instabuild)
|
||||||
if (ServerConfig.INFINITE_EXOSUIT_UPGRADES && uuid in matteryPlayer.exopackSlotModifier) {
|
itemStack.shrink(1)
|
||||||
matteryPlayer.exopackSlotModifier[UUID.randomUUID()] = slotCount
|
|
||||||
|
allowedUses--
|
||||||
|
|
||||||
|
if (player is ServerPlayer) {
|
||||||
|
if (uuid != null) {
|
||||||
|
if (ServerConfig.INFINITE_EXOSUIT_UPGRADES && uuid in matteryPlayer.exopackSlotModifier) {
|
||||||
|
matteryPlayer.exopackSlotModifier[level.otmRandom.nextUUID()] = slotCount
|
||||||
|
} else {
|
||||||
|
matteryPlayer.exopackSlotModifier[uuid] = slotCount
|
||||||
|
allowedUses = 0
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
matteryPlayer.exopackSlotModifier[uuid] = slotCount
|
matteryPlayer.exopackSlotModifier[level.otmRandom.nextUUID()] = slotCount
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
matteryPlayer.exopackSlotModifier[UUID.randomUUID()] = slotCount
|
|
||||||
}
|
|
||||||
|
|
||||||
ExopackSlotsExpandedTrigger.trigger(player, slotCount, matteryPlayer.exopackContainer.containerSize)
|
ExopackSlotsExpandedTrigger.trigger(player, slotCount, matteryPlayer.exopackContainer.containerSize)
|
||||||
player.displayClientMessage(TranslatableComponent("otm.exopack_upgrades.slots_upgraded", slotCount).withStyle(ChatFormatting.DARK_GREEN), false)
|
player.displayClientMessage(TranslatableComponent("otm.exopack_upgrades.slots_upgraded", slotCount).withStyle(ChatFormatting.DARK_GREEN), false)
|
||||||
|
|
||||||
if (this === MItems.ExopackUpgrades.INVENTORY_UPGRADE_ENDER_DRAGON) {
|
if (this === MItems.ExopackUpgrades.INVENTORY_UPGRADE_ENDER_DRAGON) {
|
||||||
MItems.ExopackUpgrades.ENDER_UPGRADE.finishUsingItem(ItemStack(MItems.ExopackUpgrades.INVENTORY_UPGRADE_ENDER_DRAGON), level, player)
|
MItems.ExopackUpgrades.ENDER_UPGRADE.finishUsingItem(ItemStack(MItems.ExopackUpgrades.INVENTORY_UPGRADE_ENDER_DRAGON), level, player)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ class ExopackUpgradeItem(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun use(p_41432_: Level, player: Player, hand: InteractionHand): InteractionResultHolder<ItemStack> {
|
override fun use(p_41432_: Level, player: Player, hand: InteractionHand): InteractionResultHolder<ItemStack> {
|
||||||
if (player.matteryPlayer?.hasExopack == true && !type.prop.get(player.matteryPlayer!!)) {
|
if (player.matteryPlayer.hasExopack && !type.prop.get(player.matteryPlayer)) {
|
||||||
player.startUsingItem(hand)
|
player.startUsingItem(hand)
|
||||||
return InteractionResultHolder.consume(player.getItemInHand(hand))
|
return InteractionResultHolder.consume(player.getItemInHand(hand))
|
||||||
}
|
}
|
||||||
@ -70,7 +70,7 @@ class ExopackUpgradeItem(
|
|||||||
|
|
||||||
override fun finishUsingItem(itemStack: ItemStack, level: Level, player: LivingEntity): ItemStack {
|
override fun finishUsingItem(itemStack: ItemStack, level: Level, player: LivingEntity): ItemStack {
|
||||||
if (player !is Player) return super.finishUsingItem(itemStack, level, player)
|
if (player !is Player) return super.finishUsingItem(itemStack, level, player)
|
||||||
val mattery = player.matteryPlayer ?: return super.finishUsingItem(itemStack, level, player)
|
val mattery = player.matteryPlayer
|
||||||
|
|
||||||
if (!mattery.hasExopack || type.prop.get(mattery)) {
|
if (!mattery.hasExopack || type.prop.get(mattery)) {
|
||||||
return super.finishUsingItem(itemStack, level, player)
|
return super.finishUsingItem(itemStack, level, player)
|
||||||
|
@ -44,6 +44,7 @@ import ru.dbotthepony.mc.otm.container.sortWithIndices
|
|||||||
import ru.dbotthepony.mc.otm.core.ResourceLocation
|
import ru.dbotthepony.mc.otm.core.ResourceLocation
|
||||||
import ru.dbotthepony.mc.otm.core.collect.ConditionalSet
|
import ru.dbotthepony.mc.otm.core.collect.ConditionalSet
|
||||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||||
|
import ru.dbotthepony.mc.otm.core.util.GJRAND64RandomSource
|
||||||
import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback
|
import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback
|
||||||
import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget
|
import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget
|
||||||
import ru.dbotthepony.mc.otm.network.MatteryStreamCodec
|
import ru.dbotthepony.mc.otm.network.MatteryStreamCodec
|
||||||
@ -81,7 +82,7 @@ abstract class MatteryMenu(
|
|||||||
val mSynchronizer = SynchableGroup()
|
val mSynchronizer = SynchableGroup()
|
||||||
val synchronizerRemote = mSynchronizer.Remote()
|
val synchronizerRemote = mSynchronizer.Remote()
|
||||||
val player: Player get() = inventory.player
|
val player: Player get() = inventory.player
|
||||||
val random: RandomSource = RandomSource.create()
|
val random = GJRAND64RandomSource()
|
||||||
|
|
||||||
private val _playerInventorySlots = ArrayList<InventorySlot>()
|
private val _playerInventorySlots = ArrayList<InventorySlot>()
|
||||||
private val _playerHotbarSlots = ArrayList<InventorySlot>()
|
private val _playerHotbarSlots = ArrayList<InventorySlot>()
|
||||||
|
@ -355,6 +355,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 {
|
||||||
|
@ -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)
|
||||||
|
@ -38,6 +38,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
|
||||||
@ -455,6 +456,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)
|
||||||
}
|
}
|
||||||
|
@ -692,6 +692,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)
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
Loading…
Reference in New Issue
Block a user