Compare commits

...

29 Commits

Author SHA1 Message Date
01d3cbf7b2
Add "Smart exchange" button to quickstack controls 2025-03-21 21:58:56 +07:00
be2011cf96
Merge branch '1.21' into new-container-api 2025-03-21 21:24:26 +07:00
ab2cc33b7a
"Smart storage exchange icon" 2025-03-21 21:24:16 +07:00
9413ae5f2b
Shrink effect list panel so it no longer overlaps "quick stack" controls 2025-03-21 21:17:50 +07:00
dc73ac7b55
Merge branch '1.21' into new-container-api 2025-03-21 21:11:30 +07:00
bfb8f0380a
Panel debug rendering 2025-03-21 21:10:46 +07:00
a6361f10f2
Final improvements to quick stack controls 2025-03-21 18:35:25 +07:00
f16b003cdf
Merge branch '1.21' into new-container-api 2025-03-21 18:18:18 +07:00
06f109575d
Fix children not getting re-sorted upon visibility changes 2025-03-21 18:18:07 +07:00
a2d9f43a2e
Fix grid panel layouts, introduce column major order 2025-03-21 18:17:50 +07:00
07e0c73479
Fixes for quick stack controls 2025-03-21 15:19:07 +07:00
2547478914
Merge branch '1.21' into new-container-api 2025-03-21 15:11:17 +07:00
7c028b1fa6
Im with stupid 2025-03-21 15:11:09 +07:00
dcff861e71
More quickstack controls 2025-03-21 14:31:59 +07:00
9be8596a5f
Merge branch '1.21' into new-container-api 2025-03-21 14:05:50 +07:00
57c6bbb795
Update cases where wrong random being used 2025-03-21 14:00:19 +07:00
29c51617b9
Merge branch '1.21' into new-container-api 2025-03-21 13:52:56 +07:00
3e92c5272d
Move panels additional types to separate file 2025-03-21 13:52:00 +07:00
f9821aa552
Use GJRAND64 in menus 2025-03-21 13:36:46 +07:00
b921658eb2
Remove randomGenerator from editable panel 2025-03-21 13:34:53 +07:00
9b27ed7fb6
Add netFloat and nextDouble helper methods to RandomSource 2025-03-21 13:33:53 +07:00
269227f6cf
Add helper methods for fast DockProperty creation 2025-03-21 12:58:13 +07:00
27834cc595
Fix wrong layout final iteration value 2025-03-21 12:23:08 +07:00
70ed0cfcba
Merge branch '1.21' into new-container-api 2025-03-21 10:46:03 +07:00
c343de6031
Parenting callbacks in panels 2025-03-21 10:45:07 +07:00
65bf4dc9d0
Merge branch '1.21' into new-container-api 2025-03-21 08:07:52 +07:00
e6c9708652
Add layout modes to grid panel 2025-03-21 08:07:43 +07:00
a48aaf52ae
Add DockProperty#all variant 2025-03-21 07:19:03 +07:00
9b384f2213
Implement sizeToContents() for GridPanel 2025-03-21 07:18:42 +07:00
25 changed files with 664 additions and 172 deletions

View File

@ -988,12 +988,14 @@ private fun androidFeatures(provider: MatteryLanguageProvider) {
private fun gui(provider: MatteryLanguageProvider) { private fun gui(provider: MatteryLanguageProvider) {
with(provider.english) { with(provider.english) {
gui("quickmove_from.restock", "Restock from storage") gui("quickmove_from.restock", "Restock from storage")
gui("quickmove_from.restock_with_move", "Full restock from storage") gui("quickmove_from.restock_with_move", "Quickstack from storage")
gui("quickmove_from.move", "Take all") gui("quickmove_from.move", "Take all")
gui("quickmove_to.restock", "Restock to storage") gui("quickmove_to.restock", "Restock to storage")
gui("quickmove_to.restock_with_move", "Full restock to storage") gui("quickmove_to.restock_with_move", "Quickstack to storage")
gui("quickmove_to.move", "Deposit all") gui("quickmove_to.move", "Deposit all")
gui("quickmove.exchange", "Smart exchange with storage")
gui("quickmove.exchange.desc", "Filtered slots get restocked, everything else gets quickstacked from Exopack")
gui("quickmove_hint", "Right click to show all variants") gui("quickmove_hint", "Right click to show all variants")

View File

@ -981,12 +981,14 @@ private fun androidFeatures(provider: MatteryLanguageProvider) {
private fun gui(provider: MatteryLanguageProvider) { private fun gui(provider: MatteryLanguageProvider) {
with(provider.russian) { with(provider.russian) {
gui("quickmove_from.restock", "Быстрое пополнение из хранилища") gui("quickmove_from.restock", "Быстрое пополнение из хранилища")
gui("quickmove_from.restock_with_move", "Быстрое перемещение из хранилища") gui("quickmove_from.restock_with_move", "Быстрое складирование из хранилища")
gui("quickmove_from.move", "Взять всё") gui("quickmove_from.move", "Взять всё")
gui("quickmove_to.restock", "Быстрое пополнение в хранилище") gui("quickmove_to.restock", "Быстрое пополнение в хранилище")
gui("quickmove_to.restock_with_move", "Быстрое перемещение в хранилище") gui("quickmove_to.restock_with_move", "Быстрое складирование в хранилище")
gui("quickmove_to.move", "Переместить всё") gui("quickmove_to.move", "Переместить всё")
gui("quickmove.exchange", "Умный обмен с хранилищем")
gui("quickmove.exchange.desc", "Слоты с фильтрами заполняются до максимума, всё остальное быстро складируется из экзопака")
gui("quickmove_hint", "Правый клик чтоб увидеть все варианты") gui("quickmove_hint", "Правый клик чтоб увидеть все варианты")

View File

@ -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,

View File

@ -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)

View File

@ -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)

View File

@ -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,

View File

@ -284,18 +284,9 @@ class ExopackInventoryScreen(menu: ExopackInventoryMenu) : MatteryScreen<Exopack
curios.x = x curios.x = x
} }
EffectListPanel(this, frame, menu.player, x - 56f, gridHeight = 6).tick() EffectListPanel(this, frame, menu.player, x - 56f, gridHeight = 4).tick()
val leftControls = DeviceControls(this, frame) QuickStackControlsPanel(this, frame, x = -19f, y = 96f + 18f)
leftControls.dockOnLeft = true
leftControls.dockTop = 96f
leftControls.addButton(ButtonPanel.square18(
this, leftControls,
icon = Widgets18.RESTOCK_WITH_MOVE_TO_STORAGE,
onPress = IntConsumer { PacketDistributor.sendToServer(QuickStackPacket(QuickMoveInput.Mode.RESTOCK_WITH_MOVE, true)) }).also {
it.tooltips.add(QuickMoveInput.Mode.RESTOCK_WITH_MOVE.textToStorage)
})
return frame return frame
} }

View File

@ -14,9 +14,13 @@ import net.minecraft.world.item.ItemStack
import net.neoforged.neoforge.client.event.ContainerScreenEvent import net.neoforged.neoforge.client.event.ContainerScreenEvent
import net.neoforged.neoforge.common.NeoForge 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.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
@ -52,6 +56,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
@ -685,7 +690,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() })

View File

@ -2,6 +2,7 @@ package ru.dbotthepony.mc.otm.client.screen.decorative
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import ru.dbotthepony.kommons.util.Either
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel
import ru.dbotthepony.mc.otm.client.screen.panels.button.DeviceControls import ru.dbotthepony.mc.otm.client.screen.panels.button.DeviceControls
@ -28,11 +29,11 @@ class CargoCrateScreen(menu: CargoCrateMenu, inventory: Inventory, title: Compon
val leftControls = DeviceControls(this, frame) val leftControls = DeviceControls(this, frame)
leftControls.dockOnLeft = true leftControls.dockOnLeft = true
leftControls.quickMoveButtons(menu.quickMoveFromStorage, QuickMoveInput.Mode.RESTOCK, true) leftControls.quickMoveButtons(menu.quickMoveFromStorage)
val leftInventoryControls = DeviceControls(this, inventoryFrame!!) val leftInventoryControls = DeviceControls(this, inventoryFrame!!)
leftInventoryControls.dockOnLeft = true leftInventoryControls.dockOnLeft = true
leftInventoryControls.quickMoveButtons(menu.quickMoveToStorage, QuickMoveInput.Mode.RESTOCK_WITH_MOVE, false) leftInventoryControls.quickMoveButtons(menu.quickMoveToStorage, menu.quickMoveFromStorage)
return frame return frame
} }

View File

@ -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 }) {

View File

@ -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()

View File

@ -62,7 +62,7 @@ open class EffectListPanel<out S : Screen> @JvmOverloads constructor(
init { init {
scroll.visible = false scroll.visible = false
//scissor = true scissor = true
} }
open inner class EffectSquare( open inner class EffectSquare(

View File

@ -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)
} }

View File

@ -0,0 +1,120 @@
package ru.dbotthepony.mc.otm.client.screen.panels
import com.mojang.blaze3d.platform.InputConstants
import net.minecraft.ChatFormatting
import net.minecraft.client.gui.screens.Screen
import net.neoforged.neoforge.network.PacketDistributor
import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.client.render.IGUIRenderable
import ru.dbotthepony.mc.otm.client.render.Widgets18
import ru.dbotthepony.mc.otm.client.screen.panels.button.ButtonPanel
import ru.dbotthepony.mc.otm.client.screen.panels.util.GridPanel
import ru.dbotthepony.mc.otm.core.TextComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.menu.QuickMoveInput
import ru.dbotthepony.mc.otm.network.QuickStackPacket
import java.util.function.IntConsumer
class QuickStackControlsPanel<out S : Screen>(
screen: S,
parent: EditablePanel<*>? = null,
x: Float = 0f,
y: Float = 0f
) : EditablePanel<S>(screen, parent, x, y, 18f, 18f) {
private val grid = GridPanel(screen, this, columns = 1, rows = 1)
private val buttons = ArrayList<EditablePanel<S>>()
init {
grid.dock = Dock.FILL
grid.layout = GridPanel.Layout.TOP_RIGHT
grid.columnMajorOrder = true
// so row with main button contains only that button (visibly)
val fill = EditablePanel(screen, grid, width = 18f, height = 18f)
fill.childrenOrder = 999
fill.visible = false
fill.dockMargin = DockProperty.bottomRight(1f)
buttons.add(fill)
}
private inner class MainButton : ButtonPanel<S>(screen, grid, width = 18f, height = 18f) {
init {
dockMargin = DockProperty.bottom(1f)
childrenOrder = -100000
tooltips.add(TranslatableComponent("otm.gui.quickmove.exchange"))
tooltips.add(TranslatableComponent("otm.gui.quickmove.exchange.desc").withStyle(ChatFormatting.GRAY))
tooltips.add(TextComponent(""))
tooltips.add(TranslatableComponent("otm.gui.quickmove_hint").withStyle(ChatFormatting.GRAY))
}
override var isDisabled: Boolean
get() = minecraft.player!!.isSpectator
set(value) {}
override val icon: IGUIRenderable
get() = Widgets18.SMART_STORAGE_EXCHANGE
override fun test(value: Int): Boolean {
return value == InputConstants.MOUSE_BUTTON_LEFT || value == InputConstants.MOUSE_BUTTON_RIGHT
}
override fun onClick(mouseButton: Int) {
if (mouseButton == InputConstants.MOUSE_BUTTON_LEFT) {
PacketDistributor.sendToServer(QuickStackPacket(QuickMoveInput.Mode.RESTOCK_WITH_MOVE, true))
PacketDistributor.sendToServer(QuickStackPacket(QuickMoveInput.Mode.RESTOCK, false))
} else {
buttons.forEach { it.visible = !it.visible }
if (buttons[0].visible) {
grid.columns = 2
grid.rows = 4
} else {
grid.columns = 1
grid.rows = 1
}
this@QuickStackControlsPanel.sizeToContents()
}
}
}
override fun mouseClickedInner(x: Double, y: Double, button: Int): Boolean {
return false
}
override fun sizeToContents() {
val oldWidth = width
super.sizeToContents()
x -= width - oldWidth
}
init {
for ((i, mode) in QuickMoveInput.Mode.entries.withIndex()) {
val button = ButtonPanel.square18(
screen, grid,
mode.iconFromStorage,
onPress = IntConsumer { PacketDistributor.sendToServer(QuickStackPacket(mode, false)) })
button.childrenOrder = 1000 + i
button.dockMargin = DockProperty.bottomRight(1f)
button.visible = false
button.tooltips.add(mode.textFromStorage)
buttons.add(button)
}
for ((i, mode) in QuickMoveInput.Mode.entries.withIndex()) {
val button = ButtonPanel.square18(
screen, grid,
mode.iconToStorage,
onPress = IntConsumer { PacketDistributor.sendToServer(QuickStackPacket(mode, true)) })
button.childrenOrder = i
button.dockMargin = DockProperty.bottom(1f)
button.visible = false
button.tooltips.add(mode.textToStorage)
buttons.add(button)
}
MainButton()
}
}

View File

@ -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())
}
}

View File

@ -6,6 +6,7 @@ import net.minecraft.network.chat.Component
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items import net.minecraft.world.item.Items
import ru.dbotthepony.kommons.util.Delegate import ru.dbotthepony.kommons.util.Delegate
import ru.dbotthepony.kommons.util.Either
import ru.dbotthepony.kommons.util.value import ru.dbotthepony.kommons.util.value
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
import ru.dbotthepony.mc.otm.block.entity.RedstoneSetting import ru.dbotthepony.mc.otm.block.entity.RedstoneSetting
@ -542,33 +543,43 @@ class DeviceControls<out S : MatteryScreen<*>>(
} }
} }
fun quickMoveButtons(buttons: Map<QuickMoveInput.Mode, QuickMoveInput>, mainMode: QuickMoveInput.Mode, isFromStorage: Boolean, unfoldableSettings: Boolean = true) { fun quickMoveButtons(
buttons: Map<QuickMoveInput.Mode, QuickMoveInput>,
fromStorage: Map<QuickMoveInput.Mode, QuickMoveInput>? = null
) {
object : FoldableButtonPanel() { object : FoldableButtonPanel() {
private val input = buttons[mainMode]!!
override fun performAction() { override fun performAction() {
input.clientInput() if (fromStorage == null) {
buttons[QuickMoveInput.Mode.MOVE]!!.clientInput()
} else {
buttons[QuickMoveInput.Mode.RESTOCK_WITH_MOVE]!!.clientInput()
fromStorage[QuickMoveInput.Mode.RESTOCK]!!.clientInput()
}
} }
override var isDisabled: Boolean override var isDisabled: Boolean
get() { return !input.input.test(minecraft.player ?: return false) } get() { return !buttons.values.first().input.test(minecraft.player ?: return false) }
set(value) {} set(value) {}
override val hasExtraButtons: Boolean override val hasExtraButtons: Boolean
get() = unfoldableSettings get() = true
override fun doMakeButtons(): List<EditablePanel<S>> { override fun doMakeButtons(): List<EditablePanel<S>> {
return buttons.entries var stream = buttons.entries
.stream() .stream()
.filter { (m, _) -> m != input.mode }
if (fromStorage == null)
stream = stream.filter { (m) -> m != QuickMoveInput.Mode.MOVE }
return stream
.map { (m, b) -> .map { (m, b) ->
square18( square18(
screen, screen,
this, this,
icon = if (isFromStorage) m.iconFromStorage else m.iconToStorage, icon = if (fromStorage == null) m.iconFromStorage else m.iconToStorage,
onPress = { b.clientInput() } onPress = { b.clientInput() }
).also { ).also {
if (isFromStorage) if (fromStorage == null)
it.tooltips.add(m.textFromStorage) it.tooltips.add(m.textFromStorage)
else else
it.tooltips.add(m.textToStorage) it.tooltips.add(m.textToStorage)
@ -578,21 +589,19 @@ class DeviceControls<out S : MatteryScreen<*>>(
} }
init { init {
if (isFromStorage) if (fromStorage == null)
tooltips.add(input.mode.textFromStorage) tooltips.add(QuickMoveInput.Mode.MOVE.textFromStorage)
else else {
tooltips.add(input.mode.textToStorage) tooltips.add(TranslatableComponent("otm.gui.quickmove.exchange"))
tooltips.add(TranslatableComponent("otm.gui.quickmove.exchange.desc").withStyle(ChatFormatting.GRAY))
if (unfoldableSettings) {
tooltips.add(TextComponent(""))
tooltips.add(TranslatableComponent("otm.gui.quickmove_hint").withStyle(ChatFormatting.GRAY))
} else {
makeButtons()
} }
tooltips.add(TextComponent(""))
tooltips.add(TranslatableComponent("otm.gui.quickmove_hint").withStyle(ChatFormatting.GRAY))
} }
override val icon: IGUIRenderable override val icon: IGUIRenderable
get() = if (isFromStorage) input.mode.iconFromStorage else input.mode.iconToStorage get() = if (fromStorage == null) QuickMoveInput.Mode.MOVE.iconFromStorage else Widgets18.SMART_STORAGE_EXCHANGE
} }
} }

View File

@ -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

View File

@ -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)
} }
} }
} }

View File

@ -2,6 +2,7 @@ package ru.dbotthepony.mc.otm.compat.vanilla
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import ru.dbotthepony.kommons.util.Either
import ru.dbotthepony.mc.otm.client.render.RenderGravity import ru.dbotthepony.mc.otm.client.render.RenderGravity
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
import ru.dbotthepony.mc.otm.client.screen.panels.Dock import ru.dbotthepony.mc.otm.client.screen.panels.Dock
@ -31,11 +32,11 @@ class VanillaChestScreen(menu: AbstractVanillaChestMenu, inventory: Inventory, t
val leftControls = DeviceControls(this, frame) val leftControls = DeviceControls(this, frame)
leftControls.dockOnLeft = true leftControls.dockOnLeft = true
leftControls.quickMoveButtons(menu.quickMoveFromStorage, QuickMoveInput.Mode.RESTOCK, true) leftControls.quickMoveButtons(menu.quickMoveFromStorage)
val leftInventoryControls = DeviceControls(this, inventoryFrame!!) val leftInventoryControls = DeviceControls(this, inventoryFrame!!)
leftInventoryControls.dockOnLeft = true leftInventoryControls.dockOnLeft = true
leftInventoryControls.quickMoveButtons(menu.quickMoveToStorage, QuickMoveInput.Mode.RESTOCK_WITH_MOVE, false) leftInventoryControls.quickMoveButtons(menu.quickMoveToStorage, menu.quickMoveFromStorage)
return frame return frame
} }

View File

@ -680,3 +680,21 @@ fun <K : Any, V> SimpleCache(size: Long, freshness: Duration): Cache<K, V> {
.expireAfterWrite(freshness) .expireAfterWrite(freshness)
.build() .build()
} }
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)
}

View File

@ -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

View File

@ -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

View File

@ -43,6 +43,7 @@ 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.entity.checkCanInteract import ru.dbotthepony.mc.otm.entity.checkCanInteract
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>()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB