More storage work and fixes

This commit is contained in:
DBotThePony 2022-05-14 16:45:00 +07:00
parent 42c0c49782
commit af172dafe8
Signed by: DBot
GPG Key ID: DCC23B5715498507
9 changed files with 212 additions and 203 deletions

View File

@ -1,54 +0,0 @@
package ru.dbotthepony.mc.otm.menu.data;
import net.minecraft.client.Minecraft;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.network.NetworkEvent;
import java.util.function.Supplier;
public record StackAddPacket(int id, int stack_id, ItemStack stack) {
public void write(FriendlyByteBuf buffer) {
buffer.writeInt(id);
buffer.writeInt(stack_id);
buffer.writeRegistryId(stack.getItem());
buffer.writeInt(stack.getCount());
buffer.writeBoolean(stack.getTag() != null);
if (stack.getTag() != null)
buffer.writeNbt(stack.getShareTag());
}
public static StackAddPacket read(FriendlyByteBuf buffer) {
var id = buffer.readInt();
var stack = buffer.readInt();
var item = buffer.readRegistryIdSafe(Item.class);
var count = buffer.readInt();
var state = new ItemStack(item, count);
if (buffer.readBoolean())
state.readShareTag(buffer.readNbt());
return new StackAddPacket(id, stack, state);
}
public void play(Supplier<NetworkEvent.Context> context) {
context.get().setPacketHandled(true);
context.get().enqueueWork(() -> {
var get = Minecraft.getInstance().player.containerMenu instanceof INetworkedItemViewSupplier supplier && Minecraft.getInstance().player.containerMenu.containerId == id ? supplier.getNetworkedItemView() : null;
if (get == null) {
throw new IllegalStateException("No such item tracker with id " + id);
}
if (get.state.containsKey(stack_id)) {
throw new IllegalStateException("Item tracker " + id + " already has stack with id of " + stack_id);
}
get.state.put(stack_id, new NetworkedItemView.NetworkedItem(stack_id, stack));
get.clearCache();
});
}
}

View File

@ -1,43 +0,0 @@
package ru.dbotthepony.mc.otm.menu.data;
import net.minecraft.client.Minecraft;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraftforge.network.NetworkEvent;
import java.util.function.Supplier;
public record StackChangePacket(int id, int stack_id, int new_count) {
public void write(FriendlyByteBuf buffer) {
buffer.writeInt(id);
buffer.writeInt(stack_id);
buffer.writeInt(new_count);
}
public static StackChangePacket read(FriendlyByteBuf buffer) {
var id = buffer.readInt();
var stack_id = buffer.readInt();
var new_count = buffer.readInt();
return new StackChangePacket(id, stack_id, new_count);
}
public void play(Supplier<NetworkEvent.Context> context) {
context.get().setPacketHandled(true);
context.get().enqueueWork(() -> {
var get = Minecraft.getInstance().player.containerMenu instanceof INetworkedItemViewSupplier supplier && Minecraft.getInstance().player.containerMenu.containerId == id ? supplier.getNetworkedItemView() : null;
if (get == null) {
throw new IllegalStateException("No such item tracker with id " + id);
}
var get_state = get.state.get(stack_id);
if (get_state == null) {
throw new IllegalStateException("Item tracker " + id + " has no stack with id of " + stack_id);
}
get_state.stack().setCount(new_count);
get.clearCache();
});
}
}

View File

@ -1,40 +0,0 @@
package ru.dbotthepony.mc.otm.menu.data;
import net.minecraft.client.Minecraft;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraftforge.network.NetworkEvent;
import java.util.function.Supplier;
public record StackRemovePacket(int id, int stack_id) {
public void write(FriendlyByteBuf buffer) {
buffer.writeInt(id);
buffer.writeInt(stack_id);
}
public static StackRemovePacket read(FriendlyByteBuf buffer) {
var id = buffer.readInt();
var stack_id = buffer.readInt();
return new StackRemovePacket(id, stack_id);
}
public void play(Supplier<NetworkEvent.Context> context) {
context.get().setPacketHandled(true);
context.get().enqueueWork(() -> {
var get = Minecraft.getInstance().player.containerMenu instanceof INetworkedItemViewSupplier supplier && Minecraft.getInstance().player.containerMenu.containerId == id ? supplier.getNetworkedItemView() : null;
if (get == null) {
throw new IllegalStateException("No such item tracker with id " + id);
}
var get_state = get.state.remove(stack_id);
if (get_state == null) {
throw new IllegalStateException("Item tracker " + id + " has no stack with id of " + stack_id);
}
get.clearCache();
});
}
}

View File

@ -191,7 +191,7 @@ public class MatteryNetworking {
next_network_id++,
StackAddPacket.class,
StackAddPacket::write,
StackAddPacket::read,
StackAddPacket.Companion::read,
StackAddPacket::play,
Optional.of(NetworkDirection.PLAY_TO_CLIENT)
);
@ -200,7 +200,7 @@ public class MatteryNetworking {
next_network_id++,
StackChangePacket.class,
StackChangePacket::write,
StackChangePacket::read,
StackChangePacket.Companion::read,
StackChangePacket::play,
Optional.of(NetworkDirection.PLAY_TO_CLIENT)
);
@ -209,7 +209,7 @@ public class MatteryNetworking {
next_network_id++,
StackRemovePacket.class,
StackRemovePacket::write,
StackRemovePacket::read,
StackRemovePacket.Companion::read,
StackRemovePacket::play,
Optional.of(NetworkDirection.PLAY_TO_CLIENT)
);

View File

@ -5,6 +5,7 @@ import net.minecraft.resources.ResourceLocation
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import net.minecraftforge.registries.ForgeRegistries
import net.minecraftforge.registries.RegistryManager
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
@ -45,13 +46,13 @@ class ItemMatteryDrive : AbstractMatteryDrive<ItemStackWrapper>, IItemMatteryDri
}
override fun deserializeStack(tag: CompoundTag): ItemStackWrapper? {
val item = RegistryManager.ACTIVE.getRegistry(Item::class.java).getValue(ResourceLocation(tag.getString("item")))
val item = ForgeRegistries.ITEMS.getValue(ResourceLocation(tag.getString("item")))
if (item != null && item !== Items.AIR) {
val count = tag.getInt("count")
val itemstack = ItemStack(item, count)
itemstack.tag = tag["data"] as? CompoundTag?
return ItemStackWrapper(itemstack)
val count = ImpreciseFraction.deserializeNBT(tag["count"])
val itemstack = ItemStack(item, 1)
itemstack.tag = tag["data"] as? CompoundTag
return ItemStackWrapper(itemstack, copy = false).also { it.count = count }
}
return null

View File

@ -61,12 +61,8 @@ class DriveViewerScreen(menu: DriveViewerMenu, inventory: Inventory, title: Comp
for (i in 0 until GRID_WIDTH * GRID_HEIGHT) {
object : AbstractSlotPanel(this@DriveViewerScreen, grid, 0f, 0f) {
override fun getItemStack(): ItemStack {
val index = i + scroll_bar.getScroll(menu.view.getItems().size / GRID_WIDTH)
val list = menu.view.getItems()
return if (index >= list.size) {
ItemStack.EMPTY
} else list[index].stack
val index = i + scroll_bar.getScroll(menu.view.sortedView.size / GRID_WIDTH)
return menu.view.sortedView.getOrNull(index)?.stack ?: ItemStack.EMPTY
}
override fun mouseScrolledInner(mouse_x: Double, mouse_y: Double, scroll: Double): Boolean {

View File

@ -25,8 +25,7 @@ class ItemMonitorScreen(menu: ItemMonitorMenu, inventory: Inventory, title: Comp
object : AbstractSlotPanel(this@ItemMonitorScreen, gridPanel) {
override fun getItemStack(): ItemStack {
val index = i + scrollBar.getScroll(menu.view.getItemCount() / GRID_WIDTH)
val list = menu.view.getItems()
return if (index >= list.size) ItemStack.EMPTY else list[index].stack
return menu.view.sortedView.getOrNull(index)?.stack ?: ItemStack.EMPTY
}
override fun mouseScrolledInner(mouse_x: Double, mouse_y: Double, scroll: Double): Boolean {

View File

@ -27,9 +27,9 @@ class DriveViewerMenu @JvmOverloads constructor(
) : MatteryPoweredMenu(
MMenus.DRIVE_VIEWER, containerID, inventory, tile
), INetworkedItemViewSupplier {
@JvmField val view: NetworkedItemView
val view: NetworkedItemView
private val powered: PoweredVirtualComponent<ItemStackWrapper>?
@JvmField val driveSlot: MatterySlot
val driveSlot: MatterySlot
private var lastDrive: IMatteryDrive<ItemStackWrapper>? = null
override fun getNetworkedItemView() = view

View File

@ -1,12 +1,17 @@
package ru.dbotthepony.mc.otm.menu.data
import com.mojang.blaze3d.platform.InputConstants
import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.screens.Screen
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.ClickAction
import net.minecraft.world.inventory.ClickType
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraftforge.network.NetworkEvent
import net.minecraftforge.network.PacketDistributor
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.menu.MatteryMenu
@ -17,29 +22,185 @@ import ru.dbotthepony.mc.otm.storage.IStorageListener
import ru.dbotthepony.mc.otm.storage.IStorageView
import ru.dbotthepony.mc.otm.storage.ItemStackWrapper
import java.util.*
import java.util.function.Supplier
/**
* Creates a virtual, slotless container for Player's interaction with.
*/
open class NetworkedItemView(val ply: Player, val menu: MatteryMenu, val remote: Boolean) : IStorageListener<ItemStackWrapper> {
@JvmRecord
data class NetworkedItem @JvmOverloads constructor(val id: Int, val stack: ItemStack, val upstreamId: UUID? = null)
class StackAddPacket(val id: Int, val stack_id: Int, val stack: ItemStack) {
fun write(buffer: FriendlyByteBuf) {
buffer.writeInt(id)
buffer.writeInt(stack_id)
buffer.writeRegistryId(stack.item)
buffer.writeInt(stack.count)
buffer.writeBoolean(stack.shareTag != null)
@JvmField protected var next_stack_id = 0
@JvmField val state = HashMap<Int, NetworkedItem>()
@JvmField protected val upstream_state = HashMap<UUID, NetworkedItem>()
@JvmField protected val backlog = ArrayList<Any>()
operator fun get(id: Int): NetworkedItem? {
return state[id]
if (stack.tag != null) buffer.writeNbt(stack.shareTag)
}
private var cachedView: List<NetworkedItem>? = null
@JvmField protected var provider: IStorageComponent<ItemStackWrapper>? = null
fun play(context: Supplier<NetworkEvent.Context>) {
context.get().packetHandled = true
context.get().enqueueWork {
val get = Minecraft.getInstance().player?.containerMenu ?: return@enqueueWork
if (get.containerId != id)
return@enqueueWork
val view = (get as? INetworkedItemViewSupplier)?.networkedItemView ?: throw IllegalStateException("No such item tracker with id $id")
if (view.localState.containsKey(stack_id)) {
throw IllegalStateException("Item tracker $id already has stack with id of $stack_id")
}
val state = NetworkedItemView.NetworkedItem(stack_id, stack)
view.localState[stack_id] = state
/*val iterator = view.sortedView.iterator().withIndex()
var lastCompare = 0
var hit = false
while (iterator.hasNext()) {
val (i, existing) = iterator.next()
val cmp = view.sorter.compare(existing.stack, stack)
if (cmp != lastCompare && lastCompare != 0) {
hit = true
view.sortedView.add(i, state)
} else if (cmp != lastCompare) {
lastCompare = cmp
}
}
if (!hit) {*/
view.sortedView.add(state)
//}
view.resort()
}
}
companion object {
fun read(buffer: FriendlyByteBuf): StackAddPacket {
val id = buffer.readInt()
val stack = buffer.readInt()
val item = buffer.readRegistryIdSafe(Item::class.java)
val count = buffer.readInt()
val state = ItemStack(item, count)
if (buffer.readBoolean()) state.readShareTag(buffer.readNbt())
return StackAddPacket(id, stack, state)
}
}
}
class StackChangePacket(val id: Int, val stackID: Int, val newCount: Int) {
fun write(buffer: FriendlyByteBuf) {
buffer.writeInt(id)
buffer.writeInt(stackID)
buffer.writeInt(newCount)
}
fun play(context: Supplier<NetworkEvent.Context>) {
context.get().packetHandled = true
context.get().enqueueWork {
val get = Minecraft.getInstance().player?.containerMenu ?: return@enqueueWork
if (get.containerId != id)
return@enqueueWork
val view = (get as? INetworkedItemViewSupplier)?.networkedItemView ?: throw IllegalStateException("No such item tracker with id $id")
val state = view.localState[stackID] ?: throw IllegalStateException("No such stack with id $stackID in $view")
state.stack.count = newCount
view.resort()
}
}
companion object {
fun read(buffer: FriendlyByteBuf): StackChangePacket {
val id = buffer.readInt()
val stackID = buffer.readInt()
val newCount = buffer.readInt()
return StackChangePacket(id, stackID, newCount)
}
}
}
class StackRemovePacket(val id: Int, val stackID: Int) {
fun write(buffer: FriendlyByteBuf) {
buffer.writeInt(id)
buffer.writeInt(stackID)
}
fun play(context: Supplier<NetworkEvent.Context>) {
context.get().packetHandled = true
context.get().enqueueWork {
val get = Minecraft.getInstance().player?.containerMenu ?: return@enqueueWork
if (get.containerId != id)
return@enqueueWork
val view = (get as? INetworkedItemViewSupplier)?.networkedItemView ?: throw IllegalStateException("No such item tracker with id $id")
val obj = view.localState.remove(stackID) ?: throw IllegalStateException("No such stack with id $stackID in $view")
view.sortedView.remove(obj)
view.resort()
}
}
companion object {
fun read(buffer: FriendlyByteBuf): StackRemovePacket {
val id = buffer.readInt()
val stackID = buffer.readInt()
return StackRemovePacket(id, stackID)
}
}
}
/**
* Creates a virtual, slotless container for Player to interaction with.
*/
open class NetworkedItemView(val ply: Player, val menu: MatteryMenu, val remote: Boolean) : IStorageListener<ItemStackWrapper> {
data class NetworkedItem constructor(val id: Int, val stack: ItemStack, val upstreamId: UUID? = null)
protected var nextStackID = 0
// this (how client see and interact with)
val localState = Int2ObjectAVLTreeMap<NetworkedItem>()
val sortedView = LinkedList<NetworkedItem>()
var sorter: Comparator<ItemStack> = NAME_SORTER
companion object {
val NAME_SORTER = Comparator<ItemStack> { o1, o2 ->
val cmp = o1.displayName.string.compareTo(o2.displayName.string)
if (cmp != 0)
return@Comparator cmp
return@Comparator o1.item.registryName.toString().compareTo(o2.item.registryName.toString())
}
val COUNT_SORTER = Comparator<ItemStack> { o1, o2 ->
val cmp = o1.count.compareTo(o2.count)
if (cmp != 0)
return@Comparator cmp
return@Comparator o1.item.registryName.toString().compareTo(o2.item.registryName.toString())
}
}
fun resort() {
sortedView.sortWith { a, b ->
return@sortWith sorter.compare(a.stack, b.stack)
}
}
// parent (e.g. VirtualComponent)
protected val upstreamState = HashMap<UUID, NetworkedItem>()
protected val networkBacklog = ArrayList<Any>()
operator fun get(id: Int): NetworkedItem? = localState[id]
protected var provider: IStorageComponent<ItemStackWrapper>? = null
fun mouseClick(index: Int, mouse_click_type: Int) {
val list = getItems()
val list = sortedView
val action =
if (mouse_click_type == InputConstants.MOUSE_BUTTON_LEFT) ClickAction.PRIMARY else ClickAction.SECONDARY
@ -65,16 +226,8 @@ open class NetworkedItemView(val ply: Player, val menu: MatteryMenu, val remote:
provider?.removeListenerAuto(this)
}
fun clearCache() {
cachedView = null
}
fun getItems(): List<NetworkedItem> {
return if (cachedView != null) cachedView!! else java.util.List.copyOf(state.values).also { cachedView = it }
}
fun getItemCount(): Int {
return state.values.size
return localState.values.size
}
override fun addStack(stack: ItemStackWrapper, id: UUID, provider: IStorageView<ItemStackWrapper>) = addObject(stack.stack, id)
@ -82,60 +235,57 @@ open class NetworkedItemView(val ply: Player, val menu: MatteryMenu, val remote:
protected fun network(fn: () -> Any) {
if (!remote) {
backlog.add(fn())
networkBacklog.add(fn())
}
}
override fun removeStack(stack: ItemStackWrapper, id: UUID) {
val get = upstream_state[id] ?: throw IllegalStateException("Unknown ItemStack with upstream id $id!")
upstream_state.remove(id)
state.remove(get.id)
val get = upstreamState[id] ?: throw IllegalStateException("Unknown ItemStack with upstream id $id!")
upstreamState.remove(id)
localState.remove(get.id)
network { StackRemovePacket(menu.containerId, get.id) }
clearCache()
}
fun addObject(stack: ItemStack, id_upstream: UUID) {
check(!upstream_state.containsKey(id_upstream)) { "Already tracking ItemStack with upstream id $id_upstream!" }
check(!upstreamState.containsKey(id_upstream)) { "Already tracking ItemStack with upstream id $id_upstream!" }
val state = NetworkedItem(next_stack_id++, stack.copy(), id_upstream)
val state = NetworkedItem(nextStackID++, stack.copy(), id_upstream)
this.state[state.id] = state
upstream_state[id_upstream] = state
this.localState[state.id] = state
upstreamState[id_upstream] = state
network { StackAddPacket(menu.containerId, state.id, stack) }
clearCache()
}
fun changeObject(id_upstream: UUID, new_count: Int) {
val get = upstream_state[id_upstream] ?: throw IllegalStateException("Unknown ItemStack with upstream id $id_upstream!")
val get = upstreamState[id_upstream] ?: throw IllegalStateException("Unknown ItemStack with upstream id $id_upstream!")
get.stack.count = new_count
network { StackChangePacket(menu.containerId, get.id, new_count) }
clearCache()
}
fun clear() {
clearCache()
upstream_state.clear()
state.clear()
sortedView.clear()
upstreamState.clear()
localState.clear()
if (!remote) {
backlog.clear()
backlog.add(ClearPacket(menu.containerId))
networkBacklog.clear()
networkBacklog.add(ClearPacket(menu.containerId))
}
}
fun network() {
check(!remote) { "Not a server" }
val consumer = PacketDistributor.PLAYER.with { ply as ServerPlayer }
for (packet in backlog) MatteryNetworking.CHANNEL.send(consumer, packet)
backlog.clear()
for (packet in networkBacklog) MatteryNetworking.CHANNEL.send(consumer, packet)
networkBacklog.clear()
}
fun playerInteract(packet: InteractPacket) {
val provider = provider ?: return
val click = packet.click()
val action = packet.action()
val stack_id = packet.stack_id()
val click = packet.click
val action = packet.action
val stack_id = packet.stack_id
if (click == ClickType.CLONE) {
if (stack_id < 0 || !ply.abilities.instabuild) return