Better menu data networking
This commit is contained in:
parent
34f6d8e3aa
commit
da583324b9
@ -46,6 +46,10 @@ sourceSets {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.test {
|
||||||
|
useJUnitPlatform()
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
val jupiter_version: String by project
|
val jupiter_version: String by project
|
||||||
val kotlin_version: String by project
|
val kotlin_version: String by project
|
||||||
|
@ -1,111 +0,0 @@
|
|||||||
package ru.dbotthepony.mc.otm.menu.data;
|
|
||||||
|
|
||||||
import net.minecraft.world.inventory.ContainerData;
|
|
||||||
import org.apache.commons.lang3.ArrayUtils;
|
|
||||||
import ru.dbotthepony.mc.otm.OverdriveThatMatters;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.math.BigInteger;
|
|
||||||
|
|
||||||
public class BigDecimalDataContainer implements ContainerData {
|
|
||||||
public static final int NETWORK_PAYLOAD_SIZE = 16;
|
|
||||||
|
|
||||||
private BigDecimal value;
|
|
||||||
// working with ints
|
|
||||||
// networking as shorts
|
|
||||||
// crazy.
|
|
||||||
private final int[] buffer = new int[NETWORK_PAYLOAD_SIZE + 2];
|
|
||||||
|
|
||||||
public BigDecimal getDecimal() {
|
|
||||||
if (value != null) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] _build = new byte[NETWORK_PAYLOAD_SIZE * 2];
|
|
||||||
|
|
||||||
int build_index = 0;
|
|
||||||
|
|
||||||
// read payload
|
|
||||||
for (int i = 1; i <= NETWORK_PAYLOAD_SIZE; i++) {
|
|
||||||
_build[build_index] = (byte) ((buffer[i] & 0xFF00) >> 8);
|
|
||||||
_build[build_index + 1] = (byte) (buffer[i] & 0xFF);
|
|
||||||
|
|
||||||
build_index += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] build = new byte[_build[0] & 0xFF];
|
|
||||||
|
|
||||||
if (_build[0] != 0) {
|
|
||||||
if (build.length > _build.length - 1) {
|
|
||||||
OverdriveThatMatters.LOGGER.fatal("Tried to read {} bytes, while buffer allow only up to {} bytes to be read!", build.length, _build.length - 1);
|
|
||||||
OverdriveThatMatters.LOGGER.fatal("buffer state: {}", ArrayUtils.toString(buffer));
|
|
||||||
OverdriveThatMatters.LOGGER.fatal("decoded state: {}", ArrayUtils.toString(_build));
|
|
||||||
return value = BigDecimal.ZERO;
|
|
||||||
}
|
|
||||||
|
|
||||||
System.arraycopy(_build, 1, build, 0, build.length);
|
|
||||||
|
|
||||||
return value = new BigDecimal(new BigInteger(build), buffer[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return value = BigDecimal.ZERO;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDecimal(BigDecimal decimal) {
|
|
||||||
if (decimal.equals(value)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = decimal;
|
|
||||||
|
|
||||||
int scale = decimal.scale();
|
|
||||||
BigInteger integer = decimal.unscaledValue();
|
|
||||||
|
|
||||||
buffer[0] = scale & 0xFFFF;
|
|
||||||
buffer[1] = (scale & 0xFFFF0000) >>> 16;
|
|
||||||
byte[] _build = integer.toByteArray();
|
|
||||||
byte[] build = new byte[NETWORK_PAYLOAD_SIZE * 2];
|
|
||||||
|
|
||||||
// insert, shift by one
|
|
||||||
System.arraycopy(_build, 0, build, 1, Math.min(_build.length, NETWORK_PAYLOAD_SIZE * 4 - 1));
|
|
||||||
|
|
||||||
// tell how many bytes are in there
|
|
||||||
build[0] = (byte) _build.length;
|
|
||||||
|
|
||||||
int build_index = 0;
|
|
||||||
|
|
||||||
// write
|
|
||||||
for (int i = 1; i <= NETWORK_PAYLOAD_SIZE; i++) {
|
|
||||||
buffer[i] =
|
|
||||||
(build[build_index] & 0xFF) << 8 |
|
|
||||||
(build[build_index + 1] & 0xFF);
|
|
||||||
|
|
||||||
build_index += 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// override
|
|
||||||
protected void updateValue() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int get(int index) {
|
|
||||||
updateValue();
|
|
||||||
return buffer[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void set(int index, int _value) {
|
|
||||||
if (buffer[index] == _value)
|
|
||||||
return;
|
|
||||||
|
|
||||||
value = null;
|
|
||||||
buffer[index] = _value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getCount() {
|
|
||||||
return NETWORK_PAYLOAD_SIZE + 2;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,81 +0,0 @@
|
|||||||
package ru.dbotthepony.mc.otm.menu.data;
|
|
||||||
|
|
||||||
import net.minecraft.world.inventory.ContainerData;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public class UUIDDataContainer implements ContainerData {
|
|
||||||
public static final int NETWORK_PAYLOAD_SIZE = 8;
|
|
||||||
|
|
||||||
private UUID value;
|
|
||||||
private final int[] buffer = new int[NETWORK_PAYLOAD_SIZE];
|
|
||||||
|
|
||||||
public UUID getValue() {
|
|
||||||
if (value != null) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
long a = buffer[0];
|
|
||||||
long b = buffer[1];
|
|
||||||
long c = buffer[2];
|
|
||||||
long d = buffer[3];
|
|
||||||
|
|
||||||
long upper = a | b << 16 | c << 32 | d << 48;
|
|
||||||
|
|
||||||
a = buffer[4];
|
|
||||||
b = buffer[5];
|
|
||||||
c = buffer[6];
|
|
||||||
d = buffer[7];
|
|
||||||
|
|
||||||
long lower = a | b << 16 | c << 32 | d << 48;
|
|
||||||
|
|
||||||
return value = new UUID(upper, lower);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setValue(UUID value) {
|
|
||||||
if (value.equals(this.value)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.value = value;
|
|
||||||
|
|
||||||
long long_value = value.getMostSignificantBits();
|
|
||||||
|
|
||||||
buffer[0] = (int) ((long_value) & 0xFFFF);
|
|
||||||
buffer[1] = (int) ((long_value >>> 16) & 0xFFFF);
|
|
||||||
buffer[2] = (int) ((long_value >>> 32) & 0xFFFF);
|
|
||||||
buffer[3] = (int) ((long_value >>> 48) & 0xFFFF);
|
|
||||||
|
|
||||||
long_value = value.getLeastSignificantBits();
|
|
||||||
|
|
||||||
buffer[4] = (int) ((long_value) & 0xFFFF);
|
|
||||||
buffer[5] = (int) ((long_value >>> 16) & 0xFFFF);
|
|
||||||
buffer[6] = (int) ((long_value >>> 32) & 0xFFFF);
|
|
||||||
buffer[7] = (int) ((long_value >>> 48) & 0xFFFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
// override
|
|
||||||
protected void updateValue() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int get(int index) {
|
|
||||||
updateValue();
|
|
||||||
return buffer[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void set(int index, int _value) {
|
|
||||||
if (buffer[index] == _value)
|
|
||||||
return;
|
|
||||||
|
|
||||||
value = null;
|
|
||||||
buffer[index] = _value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getCount() {
|
|
||||||
return NETWORK_PAYLOAD_SIZE;
|
|
||||||
}
|
|
||||||
}
|
|
@ -273,5 +273,14 @@ public class MatteryNetworking {
|
|||||||
OneWayPlayerInputPacket::play,
|
OneWayPlayerInputPacket::play,
|
||||||
Optional.of(NetworkDirection.PLAY_TO_SERVER)
|
Optional.of(NetworkDirection.PLAY_TO_SERVER)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CHANNEL.registerMessage(
|
||||||
|
next_network_id++,
|
||||||
|
MultiByteDataContainerPacket.class,
|
||||||
|
MultiByteDataContainerPacket::write,
|
||||||
|
MultiByteDataContainerPacket.Companion::read,
|
||||||
|
MultiByteDataContainerPacket::play,
|
||||||
|
Optional.of(NetworkDirection.PLAY_TO_CLIENT)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ import ru.dbotthepony.mc.otm.menu.MenuEnergyCounter
|
|||||||
import ru.dbotthepony.mc.otm.network.MatteryNetworking
|
import ru.dbotthepony.mc.otm.network.MatteryNetworking
|
||||||
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
||||||
import java.lang.ref.WeakReference
|
import java.lang.ref.WeakReference
|
||||||
|
import java.util.*
|
||||||
import java.util.function.Supplier
|
import java.util.function.Supplier
|
||||||
|
|
||||||
data class EnergyCounterPacket(val pos: BlockPos, val thisTick: ImpreciseFraction, val total: ImpreciseFraction, val index: Int, val value: ImpreciseFraction) {
|
data class EnergyCounterPacket(val pos: BlockPos, val thisTick: ImpreciseFraction, val total: ImpreciseFraction, val index: Int, val value: ImpreciseFraction) {
|
||||||
@ -73,11 +74,9 @@ data class EnergyCounterPacket(val pos: BlockPos, val thisTick: ImpreciseFractio
|
|||||||
|
|
||||||
class BlockEntityEnergyCounter(p_155229_: BlockPos, p_155230_: BlockState) : BlockEntityMattery(MBlockEntities.ENERGY_COUNTER, p_155229_, p_155230_) {
|
class BlockEntityEnergyCounter(p_155229_: BlockPos, p_155230_: BlockState) : BlockEntityMattery(MBlockEntities.ENERGY_COUNTER, p_155229_, p_155230_) {
|
||||||
var passed = ImpreciseFraction.ZERO
|
var passed = ImpreciseFraction.ZERO
|
||||||
internal set
|
|
||||||
|
|
||||||
private val history = Array(10 * 20) { ImpreciseFraction.ZERO }
|
private val history = Array(10 * 20) { ImpreciseFraction.ZERO }
|
||||||
var historyTick = 0
|
internal var historyTick = 0
|
||||||
internal set
|
|
||||||
|
|
||||||
fun size() = history.size
|
fun size() = history.size
|
||||||
operator fun get(i: Int) = history[i]
|
operator fun get(i: Int) = history[i]
|
||||||
@ -88,6 +87,15 @@ class BlockEntityEnergyCounter(p_155229_: BlockPos, p_155230_: BlockState) : Blo
|
|||||||
var lastTick = ImpreciseFraction.ZERO
|
var lastTick = ImpreciseFraction.ZERO
|
||||||
internal set
|
internal set
|
||||||
|
|
||||||
|
var ioLimit: ImpreciseFraction? = null
|
||||||
|
|
||||||
|
fun resetStats() {
|
||||||
|
historyTick = 0
|
||||||
|
lastTick = ImpreciseFraction.ZERO
|
||||||
|
passed = ImpreciseFraction.ZERO
|
||||||
|
Arrays.fill(history, ImpreciseFraction.ZERO)
|
||||||
|
}
|
||||||
|
|
||||||
fun getHistory(ticks: Int): Array<ImpreciseFraction> {
|
fun getHistory(ticks: Int): Array<ImpreciseFraction> {
|
||||||
require(!(ticks < 1 || ticks >= history.size)) { "Invalid history length provided" }
|
require(!(ticks < 1 || ticks >= history.size)) { "Invalid history length provided" }
|
||||||
|
|
||||||
@ -184,10 +192,20 @@ class BlockEntityEnergyCounter(p_155229_: BlockPos, p_155230_: BlockState) : Blo
|
|||||||
|
|
||||||
val diff: ImpreciseFraction
|
val diff: ImpreciseFraction
|
||||||
|
|
||||||
if (it is IMatteryEnergyStorage) {
|
val ioLimit = ioLimit
|
||||||
diff = it.extractEnergyOuter(howMuch, simulate)
|
|
||||||
|
if (ioLimit != null) {
|
||||||
|
if (it is IMatteryEnergyStorage) {
|
||||||
|
diff = it.extractEnergyOuter(howMuch.min(ioLimit), simulate)
|
||||||
|
} else {
|
||||||
|
diff = ImpreciseFraction(it.extractEnergy(howMuch.min(ioLimit), simulate))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
diff = ImpreciseFraction(it.extractEnergy(howMuch, simulate))
|
if (it is IMatteryEnergyStorage) {
|
||||||
|
diff = it.extractEnergyOuter(howMuch, simulate)
|
||||||
|
} else {
|
||||||
|
diff = ImpreciseFraction(it.extractEnergy(howMuch, simulate))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!simulate) {
|
if (!simulate) {
|
||||||
@ -214,10 +232,20 @@ class BlockEntityEnergyCounter(p_155229_: BlockPos, p_155230_: BlockState) : Blo
|
|||||||
|
|
||||||
val diff: ImpreciseFraction
|
val diff: ImpreciseFraction
|
||||||
|
|
||||||
if (it is IMatteryEnergyStorage) {
|
val ioLimit = ioLimit
|
||||||
diff = it.receiveEnergyOuter(howMuch, simulate)
|
|
||||||
|
if (ioLimit != null) {
|
||||||
|
if (it is IMatteryEnergyStorage) {
|
||||||
|
diff = it.receiveEnergyOuter(howMuch.min(ioLimit), simulate)
|
||||||
|
} else {
|
||||||
|
diff = ImpreciseFraction(it.receiveEnergy(howMuch.min(ioLimit), simulate))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
diff = ImpreciseFraction(it.receiveEnergy(howMuch, simulate))
|
if (it is IMatteryEnergyStorage) {
|
||||||
|
diff = it.receiveEnergyOuter(howMuch, simulate)
|
||||||
|
} else {
|
||||||
|
diff = ImpreciseFraction(it.receiveEnergy(howMuch, simulate))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!simulate) {
|
if (!simulate) {
|
||||||
|
@ -42,7 +42,7 @@ class MenuChemicalGenerator @JvmOverloads constructor(id: Int, inv: Inventory, t
|
|||||||
addSlot(fuelSlot)
|
addSlot(fuelSlot)
|
||||||
addSlot(batterySlot)
|
addSlot(batterySlot)
|
||||||
addSlot(residueSlot)
|
addSlot(residueSlot)
|
||||||
addDataSlots(burnTime)
|
addDataContainer(burnTime)
|
||||||
addInventorySlots()
|
addInventorySlots()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,10 +36,10 @@ class MenuEnergyCounter @JvmOverloads constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addDataSlots(passed)
|
addDataContainer(passed)
|
||||||
addDataSlots(average)
|
addDataContainer(average)
|
||||||
addDataSlots(last20Ticks)
|
addDataContainer(last20Ticks)
|
||||||
addDataSlots(lastTick)
|
addDataContainer(lastTick)
|
||||||
addDataSlots(inputDirection)
|
addDataSlots(inputDirection)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
package ru.dbotthepony.mc.otm.menu
|
package ru.dbotthepony.mc.otm.menu
|
||||||
|
|
||||||
|
import net.minecraft.server.level.ServerPlayer
|
||||||
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.*
|
import net.minecraft.world.inventory.*
|
||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity
|
import net.minecraft.world.level.block.entity.BlockEntity
|
||||||
|
import net.minecraftforge.network.PacketDistributor
|
||||||
|
import ru.dbotthepony.mc.otm.menu.data.MultiByteDataContainer
|
||||||
import ru.dbotthepony.mc.otm.menu.widget.AbstractWidget
|
import ru.dbotthepony.mc.otm.menu.widget.AbstractWidget
|
||||||
|
import ru.dbotthepony.mc.otm.network.MatteryNetworking
|
||||||
import java.util.function.Consumer
|
import java.util.function.Consumer
|
||||||
|
|
||||||
@JvmRecord
|
@JvmRecord
|
||||||
@ -25,6 +29,7 @@ abstract class MatteryMenu protected @JvmOverloads constructor(
|
|||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
val inventorySlots = ArrayList<MatterySlot>()
|
val inventorySlots = ArrayList<MatterySlot>()
|
||||||
|
val multiByteContainers = ArrayList<MultiByteDataContainer>()
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
protected val lockedInventorySlots: MutableSet<Int> = HashSet()
|
protected val lockedInventorySlots: MutableSet<Int> = HashSet()
|
||||||
@ -57,6 +62,22 @@ abstract class MatteryMenu protected @JvmOverloads constructor(
|
|||||||
return matteryWidgets[index]
|
return matteryWidgets[index]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun addDataContainer(container: MultiByteDataContainer) {
|
||||||
|
if (multiByteContainers.contains(container))
|
||||||
|
throw IllegalStateException("Already containing $container")
|
||||||
|
|
||||||
|
multiByteContainers.add(container)
|
||||||
|
container.slotID = multiByteContainers.size - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getDataContainer(index: Int): MultiByteDataContainer? {
|
||||||
|
if (index !in 0 until multiByteContainers.size) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return multiByteContainers[index]
|
||||||
|
}
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
protected var inventorySlotIndexStart = 0
|
protected var inventorySlotIndexStart = 0
|
||||||
|
|
||||||
@ -108,11 +129,20 @@ abstract class MatteryMenu protected @JvmOverloads constructor(
|
|||||||
inventorySlotIndexEnd = last!!.index
|
inventorySlotIndexEnd = last!!.index
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val pdistributor = PacketDistributor.PLAYER.with { ply as ServerPlayer }
|
||||||
|
|
||||||
override fun broadcastChanges() {
|
override fun broadcastChanges() {
|
||||||
for (widget in matteryWidgets) {
|
for (widget in matteryWidgets) {
|
||||||
widget.updateServer()
|
widget.updateServer()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (data in multiByteContainers) {
|
||||||
|
if (data.dirty) {
|
||||||
|
data.dirty = false
|
||||||
|
MatteryNetworking.CHANNEL.send(pdistributor, data.makePacket())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
super.broadcastChanges()
|
super.broadcastChanges()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,6 +151,10 @@ abstract class MatteryMenu protected @JvmOverloads constructor(
|
|||||||
widget.updateServer()
|
widget.updateServer()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (data in multiByteContainers) {
|
||||||
|
MatteryNetworking.CHANNEL.send(pdistributor, data.makePacket())
|
||||||
|
}
|
||||||
|
|
||||||
super.broadcastFullState()
|
super.broadcastFullState()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package ru.dbotthepony.mc.otm.menu.data
|
package ru.dbotthepony.mc.otm.menu.data
|
||||||
|
|
||||||
import net.minecraft.world.inventory.ContainerData
|
import net.minecraft.world.inventory.ContainerData
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
class EnumDataContainer<T : Enum<T>>(val enum: Class<T>) : ContainerData {
|
class EnumDataContainer<T : Enum<T>>(val enum: Class<T>) : ContainerData {
|
||||||
val buffer = intArrayOf(0)
|
val buffer = intArrayOf(0)
|
||||||
@ -28,3 +29,19 @@ class EnumDataContainer<T : Enum<T>>(val enum: Class<T>) : ContainerData {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class UUIDDataContainer : ComplexDataContainer<UUID>(16) {
|
||||||
|
private var _value = UUID(0, 0)
|
||||||
|
|
||||||
|
override var value: UUID
|
||||||
|
get() = _value
|
||||||
|
set(value) {
|
||||||
|
buffer.position(0).putLong(value.mostSignificantBits).putLong(value.leastSignificantBits)
|
||||||
|
_value = value
|
||||||
|
dirty = true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun construct() {
|
||||||
|
_value = UUID(buffer.position(0).long, buffer.long)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -0,0 +1,48 @@
|
|||||||
|
package ru.dbotthepony.mc.otm.menu.data
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager
|
||||||
|
import java.math.BigDecimal
|
||||||
|
import java.math.BigInteger
|
||||||
|
|
||||||
|
class BigDecimalDataContainer(bytes: Int = 128) : ComplexDataContainer<BigDecimal>(bytes) {
|
||||||
|
companion object {
|
||||||
|
private val LOGGER = LogManager.getLogger()
|
||||||
|
}
|
||||||
|
|
||||||
|
private var _value = BigDecimal.ZERO
|
||||||
|
private var mute = false
|
||||||
|
|
||||||
|
override var value: BigDecimal
|
||||||
|
get() = _value
|
||||||
|
set(value) {
|
||||||
|
if (value == _value)
|
||||||
|
return
|
||||||
|
|
||||||
|
try {
|
||||||
|
buffer.array().fill(0)
|
||||||
|
buffer.position(0)
|
||||||
|
buffer.putInt(value.scale())
|
||||||
|
val bytes = value.unscaledValue().toByteArray()
|
||||||
|
|
||||||
|
buffer.putInt(bytes.size)
|
||||||
|
|
||||||
|
bytes.copyInto(buffer.array(), destinationOffset = 8)
|
||||||
|
|
||||||
|
dirty = true
|
||||||
|
} catch(err: Throwable) {
|
||||||
|
if (!mute) {
|
||||||
|
LOGGER.error("Unable to serialize value $value for network transportation", err)
|
||||||
|
mute = true
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.array().fill(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun construct() {
|
||||||
|
val scale = buffer.position(0).int
|
||||||
|
val length = buffer.int
|
||||||
|
val bytes = buffer.array().copyOfRange(8, 8 + length)
|
||||||
|
_value = BigDecimal(BigInteger(bytes), scale)
|
||||||
|
}
|
||||||
|
}
|
@ -7,178 +7,72 @@ import ru.dbotthepony.mc.otm.core.ImpreciseFraction
|
|||||||
import ru.dbotthepony.mc.otm.network.NetworkHelper
|
import ru.dbotthepony.mc.otm.network.NetworkHelper
|
||||||
import java.util.zip.CRC32
|
import java.util.zip.CRC32
|
||||||
|
|
||||||
class FractionDataContainer : ContainerData {
|
class FractionDataContainer : ComplexDataContainer<Fraction>(128) {
|
||||||
companion object {
|
companion object {
|
||||||
// CRC32 + Данные
|
|
||||||
const val NETWORK_PAYLOAD_SIZE = 64 + 2
|
|
||||||
private val LOGGER = LogManager.getLogger()
|
private val LOGGER = LogManager.getLogger()
|
||||||
}
|
}
|
||||||
|
|
||||||
private var _value: Fraction? = Fraction.ZERO
|
private var _value = Fraction.ZERO
|
||||||
private var _value2: Fraction? = Fraction.ZERO
|
|
||||||
|
|
||||||
fun hasComputedValue(): Boolean {
|
|
||||||
return _value != null
|
|
||||||
}
|
|
||||||
|
|
||||||
private var mute = false
|
private var mute = false
|
||||||
|
|
||||||
var value: Fraction
|
override var value: Fraction
|
||||||
get() {
|
get() = _value
|
||||||
if (_value != null)
|
|
||||||
return _value!!
|
|
||||||
|
|
||||||
val bytes = NetworkHelper.shortsToBytes(buffer, 2)
|
|
||||||
|
|
||||||
val crc = CRC32()
|
|
||||||
crc.update(bytes)
|
|
||||||
val crcValue = crc.value
|
|
||||||
|
|
||||||
val a = (crcValue and 0xFFFF).toShort()
|
|
||||||
val b = ((crcValue and 0xFFFF0000) ushr 16).toShort()
|
|
||||||
|
|
||||||
if (a == buffer[0] && b == buffer[1]) {
|
|
||||||
_value = Fraction.fromByteArray(bytes)
|
|
||||||
} else {
|
|
||||||
_value = _value2
|
|
||||||
}
|
|
||||||
|
|
||||||
return _value!!
|
|
||||||
}
|
|
||||||
set(value) {
|
set(value) {
|
||||||
|
if (_value == value)
|
||||||
|
return
|
||||||
|
|
||||||
_value = value
|
_value = value
|
||||||
|
|
||||||
val _value = _value
|
|
||||||
if (_value == null) {
|
|
||||||
buffer.fill(0)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val bytes = ByteArray(128) {0}
|
buffer.array().fill(0)
|
||||||
_value.toByteArray().copyInto(bytes)
|
value.toByteArray().copyInto(buffer.position(0).array())
|
||||||
|
dirty = true
|
||||||
val crc = CRC32()
|
|
||||||
crc.update(bytes)
|
|
||||||
val crcValue = crc.value
|
|
||||||
|
|
||||||
val a = (crcValue and 0xFFFF).toShort()
|
|
||||||
val b = ((crcValue and 0xFFFF0000) ushr 16).toShort()
|
|
||||||
buffer[0] = a
|
|
||||||
buffer[1] = b
|
|
||||||
|
|
||||||
NetworkHelper.bytesToShorts(bytes).copyInto(buffer, destinationOffset = 2)
|
|
||||||
} catch(err: Throwable) {
|
} catch(err: Throwable) {
|
||||||
if (!mute) {
|
if (!mute) {
|
||||||
LOGGER.error("Unable to serialize value $value for network transportation", err)
|
LOGGER.error("Unable to serialize value $value for network transportation", err)
|
||||||
mute = true
|
mute = true
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.fill(0)
|
buffer.array().fill(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val buffer = ShortArray(NETWORK_PAYLOAD_SIZE)
|
override fun construct() {
|
||||||
|
_value = Fraction.fromByteArray(buffer.array())
|
||||||
override operator fun get(p_39284_: Int): Int {
|
|
||||||
return buffer[p_39284_].toInt()
|
|
||||||
}
|
|
||||||
|
|
||||||
override operator fun set(p_39285_: Int, p_39286_: Int) {
|
|
||||||
buffer[p_39285_] = p_39286_.toShort()
|
|
||||||
if (_value != null) _value2 = _value
|
|
||||||
_value = null
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getCount(): Int {
|
|
||||||
return buffer.size
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ImpreciseFractionDataContainer : ContainerData {
|
class ImpreciseFractionDataContainer : ComplexDataContainer<ImpreciseFraction>(128) {
|
||||||
companion object {
|
companion object {
|
||||||
// CRC32 + Данные
|
|
||||||
const val NETWORK_PAYLOAD_SIZE = 64 + 2
|
|
||||||
private val LOGGER = LogManager.getLogger()
|
private val LOGGER = LogManager.getLogger()
|
||||||
}
|
}
|
||||||
|
|
||||||
private var _value: ImpreciseFraction? = ImpreciseFraction.ZERO
|
private var _value = ImpreciseFraction.ZERO
|
||||||
private var _value2: ImpreciseFraction? = ImpreciseFraction.ZERO
|
|
||||||
|
|
||||||
fun hasComputedValue(): Boolean {
|
|
||||||
return _value != null
|
|
||||||
}
|
|
||||||
|
|
||||||
private var mute = false
|
private var mute = false
|
||||||
|
|
||||||
var value: ImpreciseFraction
|
override var value: ImpreciseFraction
|
||||||
get() {
|
get() = _value
|
||||||
if (_value != null)
|
|
||||||
return _value!!
|
|
||||||
|
|
||||||
val bytes = NetworkHelper.shortsToBytes(buffer, 2)
|
|
||||||
|
|
||||||
val crc = CRC32()
|
|
||||||
crc.update(bytes)
|
|
||||||
val crcValue = crc.value
|
|
||||||
|
|
||||||
val a = (crcValue and 0xFFFF).toShort()
|
|
||||||
val b = ((crcValue and 0xFFFF0000) ushr 16).toShort()
|
|
||||||
|
|
||||||
if (a == buffer[0] && b == buffer[1]) {
|
|
||||||
_value = ImpreciseFraction.fromByteArray(bytes)
|
|
||||||
} else {
|
|
||||||
_value = _value2
|
|
||||||
}
|
|
||||||
|
|
||||||
return _value!!
|
|
||||||
}
|
|
||||||
set(value) {
|
set(value) {
|
||||||
|
if (_value == value)
|
||||||
|
return
|
||||||
|
|
||||||
_value = value
|
_value = value
|
||||||
|
|
||||||
val _value = _value
|
|
||||||
if (_value == null) {
|
|
||||||
buffer.fill(0)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val bytes = ByteArray(128) {0}
|
buffer.array().fill(0)
|
||||||
_value.toByteArray().copyInto(bytes)
|
value.toByteArray().copyInto(buffer.position(0).array())
|
||||||
|
dirty = true
|
||||||
val crc = CRC32()
|
|
||||||
crc.update(bytes)
|
|
||||||
val crcValue = crc.value
|
|
||||||
|
|
||||||
val a = (crcValue and 0xFFFF).toShort()
|
|
||||||
val b = ((crcValue and 0xFFFF0000) ushr 16).toShort()
|
|
||||||
buffer[0] = a
|
|
||||||
buffer[1] = b
|
|
||||||
|
|
||||||
NetworkHelper.bytesToShorts(bytes).copyInto(buffer, destinationOffset = 2)
|
|
||||||
} catch(err: Throwable) {
|
} catch(err: Throwable) {
|
||||||
if (!mute) {
|
if (!mute) {
|
||||||
LOGGER.error("Unable to serialize value $value for network transportation", err)
|
LOGGER.error("Unable to serialize value $value for network transportation", err)
|
||||||
mute = true
|
mute = true
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.fill(0)
|
buffer.array().fill(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val buffer = ShortArray(NETWORK_PAYLOAD_SIZE)
|
override fun construct() {
|
||||||
|
_value = ImpreciseFraction.fromByteArray(buffer.array())
|
||||||
override operator fun get(p_39284_: Int): Int {
|
|
||||||
return buffer[p_39284_].toInt()
|
|
||||||
}
|
|
||||||
|
|
||||||
override operator fun set(p_39285_: Int, p_39286_: Int) {
|
|
||||||
buffer[p_39285_] = p_39286_.toShort()
|
|
||||||
if (_value != null) _value2 = _value
|
|
||||||
_value = null
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getCount(): Int {
|
|
||||||
return buffer.size
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,108 @@
|
|||||||
|
package ru.dbotthepony.mc.otm.menu.data
|
||||||
|
|
||||||
|
import net.minecraft.client.Minecraft
|
||||||
|
import net.minecraft.network.FriendlyByteBuf
|
||||||
|
import net.minecraftforge.network.NetworkEvent
|
||||||
|
import ru.dbotthepony.mc.otm.menu.MatteryMenu
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
import java.util.function.Supplier
|
||||||
|
|
||||||
|
class MultiByteDataContainerPacket(val slotID: Int, val offset: Int, val payload: ByteArray) {
|
||||||
|
fun play(context: Supplier<NetworkEvent.Context>) {
|
||||||
|
context.get().packetHandled = true
|
||||||
|
(Minecraft.getInstance().player?.containerMenu as? MatteryMenu)?.getDataContainer(slotID)?.handle(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun write(buff: FriendlyByteBuf) {
|
||||||
|
buff.writeInt(slotID)
|
||||||
|
buff.writeInt(offset)
|
||||||
|
buff.writeByteArray(payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val empty = ByteArray(0)
|
||||||
|
fun empty(slotID: Int) = MultiByteDataContainerPacket(slotID, 0, empty)
|
||||||
|
|
||||||
|
fun read(buff: FriendlyByteBuf): MultiByteDataContainerPacket {
|
||||||
|
return MultiByteDataContainerPacket(buff.readInt(), buff.readInt(), buff.readByteArray())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open class MultiByteDataContainer(bytes: Int) {
|
||||||
|
init {
|
||||||
|
require(bytes >= 1) { "Buffer size of $bytes does not make any sense" }
|
||||||
|
}
|
||||||
|
|
||||||
|
protected val buffer = ByteBuffer.allocate(bytes)
|
||||||
|
var slotID = 0
|
||||||
|
var dirty = false
|
||||||
|
|
||||||
|
open fun handle(packet: MultiByteDataContainerPacket) {
|
||||||
|
if (packet.payload.isEmpty()) {
|
||||||
|
buffer.array().fill(0)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val backed = buffer.array()
|
||||||
|
|
||||||
|
for (i in 0 until packet.offset) {
|
||||||
|
backed[i] = bzero
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i in packet.payload.indices) {
|
||||||
|
backed[i + packet.offset] = packet.payload[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i in packet.payload.size + packet.offset until backed.size) {
|
||||||
|
backed[i] = bzero
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun makePacket(): MultiByteDataContainerPacket {
|
||||||
|
var firstNonZero = 0
|
||||||
|
val backed = buffer.array()
|
||||||
|
|
||||||
|
for (i in 0 until backed.size) {
|
||||||
|
if (backed[i] != bzero) {
|
||||||
|
firstNonZero = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstNonZero == 0 && backed[0] == bzero) {
|
||||||
|
return MultiByteDataContainerPacket.empty(slotID)
|
||||||
|
}
|
||||||
|
|
||||||
|
var lastNonZero = firstNonZero
|
||||||
|
|
||||||
|
for (i in firstNonZero + 1 until backed.size) {
|
||||||
|
if (backed[i] != bzero) {
|
||||||
|
lastNonZero = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val payload = ByteArray(lastNonZero - firstNonZero + 1)
|
||||||
|
var pi = 0
|
||||||
|
|
||||||
|
for (i in firstNonZero .. lastNonZero) {
|
||||||
|
payload[pi++] = backed[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
return MultiByteDataContainerPacket(slotID, firstNonZero, payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val bzero: Byte = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class ComplexDataContainer<T>(bytes: Int) : MultiByteDataContainer(bytes) {
|
||||||
|
abstract var value: T
|
||||||
|
protected abstract fun construct()
|
||||||
|
|
||||||
|
override fun handle(packet: MultiByteDataContainerPacket) {
|
||||||
|
super.handle(packet)
|
||||||
|
construct()
|
||||||
|
}
|
||||||
|
}
|
@ -62,59 +62,46 @@ class ByteDataContainer : ContainerData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class IntDataContainer : ContainerData {
|
class IntDataContainer : MultiByteDataContainer(4) {
|
||||||
val buffer = intArrayOf(0, 0)
|
|
||||||
|
|
||||||
var value: Int
|
var value: Int
|
||||||
get() {
|
get() {
|
||||||
return buffer[0] or (buffer[1] shl 16)
|
return buffer.position(0).int
|
||||||
}
|
}
|
||||||
set(value) {
|
set(value) {
|
||||||
buffer[0] = value and 0xFFFF
|
buffer.position(0).putInt(value)
|
||||||
buffer[1] = value ushr 16
|
dirty = true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun get(p_39284_: Int): Int {
|
|
||||||
return buffer[p_39284_]
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun set(p_39285_: Int, p_39286_: Int) {
|
|
||||||
buffer[p_39285_] = p_39286_
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getCount(): Int {
|
|
||||||
return 2
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class LongDataContainer : ContainerData {
|
class FloatDataContainer : MultiByteDataContainer(4) {
|
||||||
val buffer = intArrayOf(0, 0, 0, 0)
|
var value: Float
|
||||||
|
get() {
|
||||||
|
return buffer.position(0).float
|
||||||
|
}
|
||||||
|
set(value) {
|
||||||
|
buffer.position(0).putFloat(value)
|
||||||
|
dirty = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LongDataContainer : MultiByteDataContainer(8) {
|
||||||
var value: Long
|
var value: Long
|
||||||
get() {
|
get() {
|
||||||
val a = buffer[0].toLong()
|
return buffer.position(0).long
|
||||||
val b = buffer[1].toLong()
|
|
||||||
val c = buffer[2].toLong()
|
|
||||||
val d = buffer[3].toLong()
|
|
||||||
|
|
||||||
return a or (b shl 16) or (c shl 32) or (d shl 48)
|
|
||||||
}
|
}
|
||||||
set(value) {
|
set(value) {
|
||||||
buffer[0] = (value and 0xFFFF).toInt()
|
buffer.position(0).putLong(value)
|
||||||
buffer[1] = ((value ushr 16) and 0xFFFF).toInt()
|
dirty = true
|
||||||
buffer[2] = ((value ushr 32) and 0xFFFF).toInt()
|
}
|
||||||
buffer[3] = ((value ushr 48) and 0xFFFF).toInt()
|
}
|
||||||
|
|
||||||
|
class DoubleDataContainer : MultiByteDataContainer(8) {
|
||||||
|
var value: Double
|
||||||
|
get() {
|
||||||
|
return buffer.position(0).double
|
||||||
|
}
|
||||||
|
set(value) {
|
||||||
|
buffer.position(0).putDouble(value)
|
||||||
|
dirty = true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun get(p_39284_: Int): Int {
|
|
||||||
return buffer[p_39284_]
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun set(p_39285_: Int, p_39286_: Int) {
|
|
||||||
buffer[p_39285_] = p_39286_
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getCount(): Int {
|
|
||||||
return 4
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package ru.dbotthepony.mc.otm.menu.widget
|
|||||||
import net.minecraft.world.inventory.ContainerData
|
import net.minecraft.world.inventory.ContainerData
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
|
||||||
import ru.dbotthepony.mc.otm.menu.MatteryMenu
|
import ru.dbotthepony.mc.otm.menu.MatteryMenu
|
||||||
|
import ru.dbotthepony.mc.otm.menu.data.MultiByteDataContainer
|
||||||
import java.util.function.Consumer
|
import java.util.function.Consumer
|
||||||
|
|
||||||
abstract class AbstractWidget constructor(
|
abstract class AbstractWidget constructor(
|
||||||
@ -15,4 +16,8 @@ abstract class AbstractWidget constructor(
|
|||||||
protected fun addDataSlots(slots: ContainerData) {
|
protected fun addDataSlots(slots: ContainerData) {
|
||||||
menu.addDataSlots(slots)
|
menu.addDataSlots(slots)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected fun addDataContainer(slot: MultiByteDataContainer) {
|
||||||
|
menu.addDataContainer(slot)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,11 +11,11 @@ import ru.dbotthepony.mc.otm.menu.data.ImpreciseFractionDataContainer
|
|||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
class LevelGaugeWidget(menu: MatteryMenu) : AbstractWidget(menu) {
|
class LevelGaugeWidget(menu: MatteryMenu) : AbstractWidget(menu) {
|
||||||
@JvmField var level = { ImpreciseFraction.ONE}
|
var level = { ImpreciseFraction.ONE}
|
||||||
@JvmField var maxLevel = {ImpreciseFraction.ONE}
|
var maxLevel = {ImpreciseFraction.ONE}
|
||||||
|
|
||||||
@JvmField val levelContainer = ImpreciseFractionDataContainer()
|
val levelContainer = ImpreciseFractionDataContainer()
|
||||||
@JvmField val maxLevelContainer = ImpreciseFractionDataContainer()
|
val maxLevelContainer = ImpreciseFractionDataContainer()
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
menu: MatteryMenu,
|
menu: MatteryMenu,
|
||||||
@ -57,8 +57,8 @@ class LevelGaugeWidget(menu: MatteryMenu) : AbstractWidget(menu) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
addDataSlots(levelContainer)
|
addDataContainer(levelContainer)
|
||||||
addDataSlots(maxLevelContainer)
|
addDataContainer(maxLevelContainer)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateServer() {
|
override fun updateServer() {
|
||||||
|
@ -6,10 +6,10 @@ import ru.dbotthepony.mc.otm.menu.data.ShortDataContainer
|
|||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
class ProgressGaugeWidget(menu: MatteryMenu) : AbstractWidget(menu) {
|
class ProgressGaugeWidget(menu: MatteryMenu) : AbstractWidget(menu) {
|
||||||
@JvmField var progress = {0f}
|
var progress = {0f}
|
||||||
@JvmField var stuck = {false}
|
var stuck = {false}
|
||||||
@JvmField val progressContainer = ShortDataContainer()
|
val progressContainer = ShortDataContainer()
|
||||||
@JvmField val stuckContainer = BooleanDataContainer()
|
val stuckContainer = BooleanDataContainer()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
addDataSlots(progressContainer)
|
addDataSlots(progressContainer)
|
||||||
|
@ -15,17 +15,13 @@ object NetworkingTests {
|
|||||||
var frac = Fraction(18, 4)
|
var frac = Fraction(18, 4)
|
||||||
|
|
||||||
container.value = frac
|
container.value = frac
|
||||||
container[1] = container[1]
|
container.handle(container.makePacket())
|
||||||
assert(!container.hasComputedValue())
|
|
||||||
|
|
||||||
assert(container.value.compareTo(frac) == 0) { "${container.value} != $frac" }
|
assert(container.value.compareTo(frac) == 0) { "${container.value} != $frac" }
|
||||||
|
|
||||||
frac = Fraction(2_000_000, 1)
|
frac = Fraction(2_000_000, 1)
|
||||||
|
|
||||||
container.value = frac
|
container.value = frac
|
||||||
container[1] = container[1]
|
container.handle(container.makePacket())
|
||||||
assert(!container.hasComputedValue())
|
|
||||||
|
|
||||||
assert(container.value.compareTo(frac) == 0) { "${container.value} != $frac" }
|
assert(container.value.compareTo(frac) == 0) { "${container.value} != $frac" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user