Better menu data networking
This commit is contained in:
parent
34f6d8e3aa
commit
da583324b9
@ -46,6 +46,10 @@ sourceSets {
|
||||
}
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
val jupiter_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,
|
||||
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.registry.MBlockEntities
|
||||
import java.lang.ref.WeakReference
|
||||
import java.util.*
|
||||
import java.util.function.Supplier
|
||||
|
||||
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_) {
|
||||
var passed = ImpreciseFraction.ZERO
|
||||
internal set
|
||||
|
||||
private val history = Array(10 * 20) { ImpreciseFraction.ZERO }
|
||||
var historyTick = 0
|
||||
internal set
|
||||
internal var historyTick = 0
|
||||
|
||||
fun size() = history.size
|
||||
operator fun get(i: Int) = history[i]
|
||||
@ -88,6 +87,15 @@ class BlockEntityEnergyCounter(p_155229_: BlockPos, p_155230_: BlockState) : Blo
|
||||
var lastTick = ImpreciseFraction.ZERO
|
||||
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> {
|
||||
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
|
||||
|
||||
if (it is IMatteryEnergyStorage) {
|
||||
diff = it.extractEnergyOuter(howMuch, simulate)
|
||||
val ioLimit = ioLimit
|
||||
|
||||
if (ioLimit != null) {
|
||||
if (it is IMatteryEnergyStorage) {
|
||||
diff = it.extractEnergyOuter(howMuch.min(ioLimit), simulate)
|
||||
} else {
|
||||
diff = ImpreciseFraction(it.extractEnergy(howMuch.min(ioLimit), simulate))
|
||||
}
|
||||
} 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) {
|
||||
@ -214,10 +232,20 @@ class BlockEntityEnergyCounter(p_155229_: BlockPos, p_155230_: BlockState) : Blo
|
||||
|
||||
val diff: ImpreciseFraction
|
||||
|
||||
if (it is IMatteryEnergyStorage) {
|
||||
diff = it.receiveEnergyOuter(howMuch, simulate)
|
||||
val ioLimit = ioLimit
|
||||
|
||||
if (ioLimit != null) {
|
||||
if (it is IMatteryEnergyStorage) {
|
||||
diff = it.receiveEnergyOuter(howMuch.min(ioLimit), simulate)
|
||||
} else {
|
||||
diff = ImpreciseFraction(it.receiveEnergy(howMuch.min(ioLimit), simulate))
|
||||
}
|
||||
} 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) {
|
||||
|
@ -42,7 +42,7 @@ class MenuChemicalGenerator @JvmOverloads constructor(id: Int, inv: Inventory, t
|
||||
addSlot(fuelSlot)
|
||||
addSlot(batterySlot)
|
||||
addSlot(residueSlot)
|
||||
addDataSlots(burnTime)
|
||||
addDataContainer(burnTime)
|
||||
addInventorySlots()
|
||||
}
|
||||
|
||||
|
@ -36,10 +36,10 @@ class MenuEnergyCounter @JvmOverloads constructor(
|
||||
}
|
||||
}
|
||||
|
||||
addDataSlots(passed)
|
||||
addDataSlots(average)
|
||||
addDataSlots(last20Ticks)
|
||||
addDataSlots(lastTick)
|
||||
addDataContainer(passed)
|
||||
addDataContainer(average)
|
||||
addDataContainer(last20Ticks)
|
||||
addDataContainer(lastTick)
|
||||
addDataSlots(inputDirection)
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,15 @@
|
||||
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.Player
|
||||
import net.minecraft.world.inventory.*
|
||||
import net.minecraft.world.item.ItemStack
|
||||
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.network.MatteryNetworking
|
||||
import java.util.function.Consumer
|
||||
|
||||
@JvmRecord
|
||||
@ -25,6 +29,7 @@ abstract class MatteryMenu protected @JvmOverloads constructor(
|
||||
|
||||
@JvmField
|
||||
val inventorySlots = ArrayList<MatterySlot>()
|
||||
val multiByteContainers = ArrayList<MultiByteDataContainer>()
|
||||
|
||||
@JvmField
|
||||
protected val lockedInventorySlots: MutableSet<Int> = HashSet()
|
||||
@ -57,6 +62,22 @@ abstract class MatteryMenu protected @JvmOverloads constructor(
|
||||
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
|
||||
protected var inventorySlotIndexStart = 0
|
||||
|
||||
@ -108,11 +129,20 @@ abstract class MatteryMenu protected @JvmOverloads constructor(
|
||||
inventorySlotIndexEnd = last!!.index
|
||||
}
|
||||
|
||||
private val pdistributor = PacketDistributor.PLAYER.with { ply as ServerPlayer }
|
||||
|
||||
override fun broadcastChanges() {
|
||||
for (widget in matteryWidgets) {
|
||||
widget.updateServer()
|
||||
}
|
||||
|
||||
for (data in multiByteContainers) {
|
||||
if (data.dirty) {
|
||||
data.dirty = false
|
||||
MatteryNetworking.CHANNEL.send(pdistributor, data.makePacket())
|
||||
}
|
||||
}
|
||||
|
||||
super.broadcastChanges()
|
||||
}
|
||||
|
||||
@ -121,6 +151,10 @@ abstract class MatteryMenu protected @JvmOverloads constructor(
|
||||
widget.updateServer()
|
||||
}
|
||||
|
||||
for (data in multiByteContainers) {
|
||||
MatteryNetworking.CHANNEL.send(pdistributor, data.makePacket())
|
||||
}
|
||||
|
||||
super.broadcastFullState()
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package ru.dbotthepony.mc.otm.menu.data
|
||||
|
||||
import net.minecraft.world.inventory.ContainerData
|
||||
import java.util.*
|
||||
|
||||
class EnumDataContainer<T : Enum<T>>(val enum: Class<T>) : ContainerData {
|
||||
val buffer = intArrayOf(0)
|
||||
@ -28,3 +29,19 @@ class EnumDataContainer<T : Enum<T>>(val enum: Class<T>) : ContainerData {
|
||||
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 java.util.zip.CRC32
|
||||
|
||||
class FractionDataContainer : ContainerData {
|
||||
class FractionDataContainer : ComplexDataContainer<Fraction>(128) {
|
||||
companion object {
|
||||
// CRC32 + Данные
|
||||
const val NETWORK_PAYLOAD_SIZE = 64 + 2
|
||||
private val LOGGER = LogManager.getLogger()
|
||||
}
|
||||
|
||||
private var _value: Fraction? = Fraction.ZERO
|
||||
private var _value2: Fraction? = Fraction.ZERO
|
||||
|
||||
fun hasComputedValue(): Boolean {
|
||||
return _value != null
|
||||
}
|
||||
|
||||
private var _value = Fraction.ZERO
|
||||
private var mute = false
|
||||
|
||||
var value: Fraction
|
||||
get() {
|
||||
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!!
|
||||
}
|
||||
override var value: Fraction
|
||||
get() = _value
|
||||
set(value) {
|
||||
if (_value == value)
|
||||
return
|
||||
|
||||
_value = value
|
||||
|
||||
val _value = _value
|
||||
if (_value == null) {
|
||||
buffer.fill(0)
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
val bytes = ByteArray(128) {0}
|
||||
_value.toByteArray().copyInto(bytes)
|
||||
|
||||
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)
|
||||
buffer.array().fill(0)
|
||||
value.toByteArray().copyInto(buffer.position(0).array())
|
||||
dirty = true
|
||||
} catch(err: Throwable) {
|
||||
if (!mute) {
|
||||
LOGGER.error("Unable to serialize value $value for network transportation", err)
|
||||
mute = true
|
||||
}
|
||||
|
||||
buffer.fill(0)
|
||||
buffer.array().fill(0)
|
||||
}
|
||||
}
|
||||
|
||||
val buffer = ShortArray(NETWORK_PAYLOAD_SIZE)
|
||||
|
||||
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
|
||||
override fun construct() {
|
||||
_value = Fraction.fromByteArray(buffer.array())
|
||||
}
|
||||
}
|
||||
|
||||
class ImpreciseFractionDataContainer : ContainerData {
|
||||
class ImpreciseFractionDataContainer : ComplexDataContainer<ImpreciseFraction>(128) {
|
||||
companion object {
|
||||
// CRC32 + Данные
|
||||
const val NETWORK_PAYLOAD_SIZE = 64 + 2
|
||||
private val LOGGER = LogManager.getLogger()
|
||||
}
|
||||
|
||||
private var _value: ImpreciseFraction? = ImpreciseFraction.ZERO
|
||||
private var _value2: ImpreciseFraction? = ImpreciseFraction.ZERO
|
||||
|
||||
fun hasComputedValue(): Boolean {
|
||||
return _value != null
|
||||
}
|
||||
|
||||
private var _value = ImpreciseFraction.ZERO
|
||||
private var mute = false
|
||||
|
||||
var value: ImpreciseFraction
|
||||
get() {
|
||||
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!!
|
||||
}
|
||||
override var value: ImpreciseFraction
|
||||
get() = _value
|
||||
set(value) {
|
||||
if (_value == value)
|
||||
return
|
||||
|
||||
_value = value
|
||||
|
||||
val _value = _value
|
||||
if (_value == null) {
|
||||
buffer.fill(0)
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
val bytes = ByteArray(128) {0}
|
||||
_value.toByteArray().copyInto(bytes)
|
||||
|
||||
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)
|
||||
buffer.array().fill(0)
|
||||
value.toByteArray().copyInto(buffer.position(0).array())
|
||||
dirty = true
|
||||
} catch(err: Throwable) {
|
||||
if (!mute) {
|
||||
LOGGER.error("Unable to serialize value $value for network transportation", err)
|
||||
mute = true
|
||||
}
|
||||
|
||||
buffer.fill(0)
|
||||
buffer.array().fill(0)
|
||||
}
|
||||
}
|
||||
|
||||
val buffer = ShortArray(NETWORK_PAYLOAD_SIZE)
|
||||
|
||||
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
|
||||
override fun construct() {
|
||||
_value = ImpreciseFraction.fromByteArray(buffer.array())
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
val buffer = intArrayOf(0, 0)
|
||||
|
||||
class IntDataContainer : MultiByteDataContainer(4) {
|
||||
var value: Int
|
||||
get() {
|
||||
return buffer[0] or (buffer[1] shl 16)
|
||||
return buffer.position(0).int
|
||||
}
|
||||
set(value) {
|
||||
buffer[0] = value and 0xFFFF
|
||||
buffer[1] = value ushr 16
|
||||
buffer.position(0).putInt(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 2
|
||||
}
|
||||
}
|
||||
|
||||
class LongDataContainer : ContainerData {
|
||||
val buffer = intArrayOf(0, 0, 0, 0)
|
||||
class FloatDataContainer : MultiByteDataContainer(4) {
|
||||
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
|
||||
get() {
|
||||
val a = buffer[0].toLong()
|
||||
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)
|
||||
return buffer.position(0).long
|
||||
}
|
||||
set(value) {
|
||||
buffer[0] = (value and 0xFFFF).toInt()
|
||||
buffer[1] = ((value ushr 16) and 0xFFFF).toInt()
|
||||
buffer[2] = ((value ushr 32) and 0xFFFF).toInt()
|
||||
buffer[3] = ((value ushr 48) and 0xFFFF).toInt()
|
||||
buffer.position(0).putLong(value)
|
||||
dirty = true
|
||||
}
|
||||
}
|
||||
|
||||
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 ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
|
||||
import ru.dbotthepony.mc.otm.menu.MatteryMenu
|
||||
import ru.dbotthepony.mc.otm.menu.data.MultiByteDataContainer
|
||||
import java.util.function.Consumer
|
||||
|
||||
abstract class AbstractWidget constructor(
|
||||
@ -15,4 +16,8 @@ abstract class AbstractWidget constructor(
|
||||
protected fun addDataSlots(slots: ContainerData) {
|
||||
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")
|
||||
class LevelGaugeWidget(menu: MatteryMenu) : AbstractWidget(menu) {
|
||||
@JvmField var level = { ImpreciseFraction.ONE}
|
||||
@JvmField var maxLevel = {ImpreciseFraction.ONE}
|
||||
var level = { ImpreciseFraction.ONE}
|
||||
var maxLevel = {ImpreciseFraction.ONE}
|
||||
|
||||
@JvmField val levelContainer = ImpreciseFractionDataContainer()
|
||||
@JvmField val maxLevelContainer = ImpreciseFractionDataContainer()
|
||||
val levelContainer = ImpreciseFractionDataContainer()
|
||||
val maxLevelContainer = ImpreciseFractionDataContainer()
|
||||
|
||||
constructor(
|
||||
menu: MatteryMenu,
|
||||
@ -57,8 +57,8 @@ class LevelGaugeWidget(menu: MatteryMenu) : AbstractWidget(menu) {
|
||||
}
|
||||
|
||||
init {
|
||||
addDataSlots(levelContainer)
|
||||
addDataSlots(maxLevelContainer)
|
||||
addDataContainer(levelContainer)
|
||||
addDataContainer(maxLevelContainer)
|
||||
}
|
||||
|
||||
override fun updateServer() {
|
||||
|
@ -6,10 +6,10 @@ import ru.dbotthepony.mc.otm.menu.data.ShortDataContainer
|
||||
|
||||
@Suppress("unused")
|
||||
class ProgressGaugeWidget(menu: MatteryMenu) : AbstractWidget(menu) {
|
||||
@JvmField var progress = {0f}
|
||||
@JvmField var stuck = {false}
|
||||
@JvmField val progressContainer = ShortDataContainer()
|
||||
@JvmField val stuckContainer = BooleanDataContainer()
|
||||
var progress = {0f}
|
||||
var stuck = {false}
|
||||
val progressContainer = ShortDataContainer()
|
||||
val stuckContainer = BooleanDataContainer()
|
||||
|
||||
init {
|
||||
addDataSlots(progressContainer)
|
||||
|
@ -15,17 +15,13 @@ object NetworkingTests {
|
||||
var frac = Fraction(18, 4)
|
||||
|
||||
container.value = frac
|
||||
container[1] = container[1]
|
||||
assert(!container.hasComputedValue())
|
||||
|
||||
container.handle(container.makePacket())
|
||||
assert(container.value.compareTo(frac) == 0) { "${container.value} != $frac" }
|
||||
|
||||
frac = Fraction(2_000_000, 1)
|
||||
|
||||
container.value = frac
|
||||
container[1] = container[1]
|
||||
assert(!container.hasComputedValue())
|
||||
|
||||
container.handle(container.makePacket())
|
||||
assert(container.value.compareTo(frac) == 0) { "${container.value} != $frac" }
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user