Condensation drive test

This commit is contained in:
DBotThePony 2021-08-25 22:53:17 +07:00
parent d7a62f6d3c
commit e7e12bed8c
Signed by: DBot
GPG Key ID: DCC23B5715498507
9 changed files with 715 additions and 4 deletions

View File

@ -15,8 +15,10 @@ import org.apache.logging.log4j.Logger;
import ru.dbotthepony.mc.otm.capability.AndroidCapability; import ru.dbotthepony.mc.otm.capability.AndroidCapability;
import ru.dbotthepony.mc.otm.capability.AndroidCapabilityPlayer; import ru.dbotthepony.mc.otm.capability.AndroidCapabilityPlayer;
import ru.dbotthepony.mc.otm.capability.MatteryCapability; import ru.dbotthepony.mc.otm.capability.MatteryCapability;
import ru.dbotthepony.mc.otm.capability.drive.DrivePool;
import ru.dbotthepony.mc.otm.client.AndroidGui; import ru.dbotthepony.mc.otm.client.AndroidGui;
import ru.dbotthepony.mc.otm.client.EventHandler; import ru.dbotthepony.mc.otm.client.EventHandler;
import ru.dbotthepony.mc.otm.item.ItemPortableCondensationDrive;
import ru.dbotthepony.mc.otm.matter.MatterGrid; import ru.dbotthepony.mc.otm.matter.MatterGrid;
import ru.dbotthepony.mc.otm.matter.MatterRegistry; import ru.dbotthepony.mc.otm.matter.MatterRegistry;
import ru.dbotthepony.mc.otm.network.MatteryNetworking; import ru.dbotthepony.mc.otm.network.MatteryNetworking;
@ -58,6 +60,9 @@ public class OverdriveThatMatters {
FMLJavaModLoadingContext.get().getModEventBus().register(Registry.AndroidResearch.class); FMLJavaModLoadingContext.get().getModEventBus().register(Registry.AndroidResearch.class);
FMLJavaModLoadingContext.get().getModEventBus().register(Registry.Stats.class); FMLJavaModLoadingContext.get().getModEventBus().register(Registry.Stats.class);
MinecraftForge.EVENT_BUS.register(DrivePool.class);
MinecraftForge.EVENT_BUS.register(ItemPortableCondensationDrive.class);
FMLJavaModLoadingContext.get().getModEventBus().addListener(AndroidCapability::registerEffects); FMLJavaModLoadingContext.get().getModEventBus().addListener(AndroidCapability::registerEffects);
// LOGGER.info("Registered event handlers"); // LOGGER.info("Registered event handlers");

View File

@ -29,10 +29,7 @@ import ru.dbotthepony.mc.otm.android.feature.AndroidNanobotsRegeneration;
import ru.dbotthepony.mc.otm.block.*; import ru.dbotthepony.mc.otm.block.*;
import ru.dbotthepony.mc.otm.block.entity.*; import ru.dbotthepony.mc.otm.block.entity.*;
import ru.dbotthepony.mc.otm.android.AndroidFeatureType; import ru.dbotthepony.mc.otm.android.AndroidFeatureType;
import ru.dbotthepony.mc.otm.item.ItemBattery; import ru.dbotthepony.mc.otm.item.*;
import ru.dbotthepony.mc.otm.item.ItemMatterCapacitor;
import ru.dbotthepony.mc.otm.item.ItemPatternStorage;
import ru.dbotthepony.mc.otm.item.ItemPill;
import ru.dbotthepony.mc.otm.menu.*; import ru.dbotthepony.mc.otm.menu.*;
import ru.dbotthepony.mc.otm.screen.*; import ru.dbotthepony.mc.otm.screen.*;
@ -113,6 +110,8 @@ public class Registry {
public static final ResourceLocation NUTRIENT_PASTE = new ResourceLocation(OverdriveThatMatters.MOD_ID, "nutrient_paste"); public static final ResourceLocation NUTRIENT_PASTE = new ResourceLocation(OverdriveThatMatters.MOD_ID, "nutrient_paste");
public static final ResourceLocation PORTABLE_CONDENSATION_DRIVE = new ResourceLocation(OverdriveThatMatters.MOD_ID, "portable_condensation_drive");
// android features and research // android features and research
public static final ResourceLocation AIR_BAGS = new ResourceLocation(OverdriveThatMatters.MOD_ID, "air_bags"); public static final ResourceLocation AIR_BAGS = new ResourceLocation(OverdriveThatMatters.MOD_ID, "air_bags");
@ -234,6 +233,8 @@ public class Registry {
public static final ItemPatternStorage PATTERN_DRIVE_NORMAL = new ItemPatternStorage(4); public static final ItemPatternStorage PATTERN_DRIVE_NORMAL = new ItemPatternStorage(4);
public static final ItemPatternStorage PATTERN_DRIVE_CREATIVE = new ItemPatternStorage(); public static final ItemPatternStorage PATTERN_DRIVE_CREATIVE = new ItemPatternStorage();
public static final ItemPortableCondensationDrive PORTABLE_CONDENSATION_DRIVE = new ItemPortableCondensationDrive();
public static final Item NUTRIENT_PASTE = new Item(new Item.Properties().stacksTo(64).food(new FoodProperties.Builder().meat().nutrition(8).saturationMod(0.9F).build()).tab(OverdriveThatMatters.CREATIVE_TAB)); public static final Item NUTRIENT_PASTE = new Item(new Item.Properties().stacksTo(64).food(new FoodProperties.Builder().meat().nutrition(8).saturationMod(0.9F).build()).tab(OverdriveThatMatters.CREATIVE_TAB));
static { static {
@ -262,6 +263,7 @@ public class Registry {
PATTERN_DRIVE_NORMAL.setRegistryName(Names.PATTERN_DRIVE_NORMAL); PATTERN_DRIVE_NORMAL.setRegistryName(Names.PATTERN_DRIVE_NORMAL);
PATTERN_DRIVE_CREATIVE.setRegistryName(Names.PATTERN_DRIVE_CREATIVE); PATTERN_DRIVE_CREATIVE.setRegistryName(Names.PATTERN_DRIVE_CREATIVE);
PORTABLE_CONDENSATION_DRIVE.setRegistryName(Names.PORTABLE_CONDENSATION_DRIVE);
NUTRIENT_PASTE.setRegistryName(Names.NUTRIENT_PASTE); NUTRIENT_PASTE.setRegistryName(Names.NUTRIENT_PASTE);
} }
@ -293,6 +295,7 @@ public class Registry {
event.getRegistry().register(PATTERN_DRIVE_NORMAL); event.getRegistry().register(PATTERN_DRIVE_NORMAL);
event.getRegistry().register(PATTERN_DRIVE_CREATIVE); event.getRegistry().register(PATTERN_DRIVE_CREATIVE);
event.getRegistry().register(PORTABLE_CONDENSATION_DRIVE);
event.getRegistry().register(NUTRIENT_PASTE); event.getRegistry().register(NUTRIENT_PASTE);

View File

@ -4,6 +4,7 @@ import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.CapabilityInject; import net.minecraftforge.common.capabilities.CapabilityInject;
import net.minecraftforge.common.capabilities.CapabilityManager; import net.minecraftforge.common.capabilities.CapabilityManager;
import net.minecraftforge.energy.IEnergyStorage; import net.minecraftforge.energy.IEnergyStorage;
import ru.dbotthepony.mc.otm.capability.drive.IMatteryDrive;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.MathContext; import java.math.MathContext;
@ -28,6 +29,9 @@ public class MatteryCapability {
@CapabilityInject(IMatterTaskProvider.class) @CapabilityInject(IMatterTaskProvider.class)
public static Capability<IMatterTaskProvider> TASK = null; public static Capability<IMatterTaskProvider> TASK = null;
@CapabilityInject(IMatteryDrive.class)
public static Capability<IMatteryDrive> DRIVE = null;
public static void register() { public static void register() {
CapabilityManager.INSTANCE.register(IAndroidCapability.class); CapabilityManager.INSTANCE.register(IAndroidCapability.class);
CapabilityManager.INSTANCE.register(IMatteryEnergyStorage.class); CapabilityManager.INSTANCE.register(IMatteryEnergyStorage.class);
@ -35,6 +39,7 @@ public class MatteryCapability {
CapabilityManager.INSTANCE.register(IPatternStorage.class); CapabilityManager.INSTANCE.register(IPatternStorage.class);
CapabilityManager.INSTANCE.register(IMatterGridCell.class); CapabilityManager.INSTANCE.register(IMatterGridCell.class);
CapabilityManager.INSTANCE.register(IMatterTaskProvider.class); CapabilityManager.INSTANCE.register(IMatterTaskProvider.class);
CapabilityManager.INSTANCE.register(IMatteryDrive.class);
} }
public static final MathContext ROUND_RULES = new MathContext(32, RoundingMode.HALF_DOWN); public static final MathContext ROUND_RULES = new MathContext(32, RoundingMode.HALF_DOWN);

View File

@ -0,0 +1,267 @@
package ru.dbotthepony.mc.otm.capability.drive;
import net.minecraft.CrashReport;
import net.minecraft.ReportedException;
import net.minecraft.Util;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtIo;
import net.minecraft.server.MinecraftServer;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fmlserverevents.FMLServerStartedEvent;
import net.minecraftforge.fmlserverevents.FMLServerStoppingEvent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import ru.dbotthepony.mc.otm.OverdriveThatMatters;
import javax.annotation.Nullable;
import java.io.File;
import java.lang.reflect.Array;
import java.security.Provider;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.locks.LockSupport;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* Let me answer everyone's questions about:
*
* Why?
*
* There are several reasons:
* 0. This data can get very large very quickly, even when playing singleplayer (and much quicker and bigger when hosting a dedicated server)
* 1. This data can not be stored inside ItemStack.ForgeCaps due to it's size
* 2. This data can not be stored inside unshared (server only) nbt tag because, again, mods prone to use and interact with
* it wrong, causing loss of stored data or mods exposing full content of a drive inside their own tag (which cause very real "NBT size too large"
* network kicks, often locking players out of server
* 3. net.minecraft.world.level.saveddata.SaveData is for storing everything inside one dat file, which
* is performance tanking, because we have to write *entire* NBT on each save, not the data of Drive which got changed
*/
public class DrivePool {
private static final Logger LOGGER = LogManager.getLogger();
public static class Entry {
public final UUID id;
public final IMatteryDrive drive;
public long last_access = System.currentTimeMillis();
public long soft_sync_on = last_access + 8_000; // soft sync in 4 seconds
public long hard_sync_on = last_access + 30_000; // hard sync in 4 seconds
Entry(UUID id, IMatteryDrive drive) {
this.id = id;
this.drive = drive;
}
@Nullable
public CompoundTag sync(boolean force) {
if (!drive.isDirty()) {
soft_sync_on = System.currentTimeMillis() + 8_000;
hard_sync_on = System.currentTimeMillis() + 30_000;
next_save = Math.min(next_save, soft_sync_on);
return null;
}
if (force || hard_sync_on <= System.currentTimeMillis() || soft_sync_on <= System.currentTimeMillis()) {
var tag = drive.serializeNBT();
drive.markClean();
soft_sync_on = System.currentTimeMillis() + 8_000;
hard_sync_on = System.currentTimeMillis() + 30_000;
next_save = Math.min(next_save, soft_sync_on);
last_access = System.currentTimeMillis();
return tag;
}
return null;
}
public IMatteryDrive access() {
last_access = System.currentTimeMillis();
soft_sync_on = last_access + 8_000;
next_save = Math.min(hard_sync_on, Math.min(next_save, soft_sync_on));
return drive;
}
}
private static HashMap<UUID, Entry> pool = new HashMap<>();
private static Thread thread;
private static boolean stopping = false;
private static ReportedException exception;
public static final String DATA_PATH = "data/otm_drives";
private static long next_save = Long.MAX_VALUE;
public static <T extends IMatteryDrive> T get(UUID id, Function<CompoundTag, T> factory_stored, Supplier<T> factory_empty) {
var get = pool.get(id);
if (get != null) {
return (T) get.access();
}
var file = new File(base_directory, id.toString() + ".dat");
if (file.exists()) {
try {
var factorize = factory_stored.apply(NbtIo.readCompressed(file));
pool.put(id, new Entry(id, factorize));
return factorize;
} catch(Throwable error) {
var report = new CrashReport("Reading OTM Drive from disk", error);
var category = report.addCategory("Corrupt drive");
category.setDetail("UUID", id);
throw new ReportedException(report);
}
}
var factorize = factory_empty.get();
pool.put(id, new Entry(id, factorize));
return factorize;
}
public static void put(UUID id, IMatteryDrive drive) {
pool.put(id, new Entry(id, drive));
}
private record BacklogLine(UUID file, CompoundTag tag, IMatteryDrive drive) {
@Override
public boolean equals(Object obj) {
return obj instanceof BacklogLine line && line.file.equals(file);
}
}
private static List<BacklogLine> backlog = new ArrayList<>();
private static File base_directory;
private static void thread(MinecraftServer server) {
while (true) {
LockSupport.park();
if (stopping) {
return;
}
try {
sync();
} catch (ReportedException error) {
exception = error;
return;
}
}
}
@SubscribeEvent
public static void onServerPostTick(TickEvent.ServerTickEvent event) {
if (event.phase == TickEvent.Phase.END) {
if (exception != null) {
throw exception;
}
//if (next_save < System.currentTimeMillis()) {
writeBacklog(true);
//}
}
}
@SubscribeEvent
public static void serverStartEvent(FMLServerStartedEvent event) {
if (thread != null && thread.isAlive()) {
LOGGER.error("Attempting to start another DrivePool I/O thread when already running one!");
return;
}
pool.clear();
final var server = event.getServer();
base_directory = new File(server.storageSource.getWorldDir().toFile(), DATA_PATH);
base_directory.mkdirs();
thread = new Thread(null, () -> DrivePool.thread(server), "Overdrive That Matters DrivePool I/O");
thread.start();
}
@SubscribeEvent
public static void serverStopEvent(FMLServerStoppingEvent event) {
if (thread != null && thread.isAlive()) {
stopping = true;
LockSupport.unpark(thread);
}
writeBacklog(true);
sync();
pool.clear();
}
public static void writeBacklog(boolean force) {
var sync_required = false;
ArrayList<UUID> remove_keys = null;
for (var entry : pool.entrySet()) {
var tag = entry.getValue().sync(force);
if (tag != null) {
LOGGER.info("Syncing {}", entry.getKey());
var index = backlog.indexOf(entry.getKey());
if (index != -1) {
backlog.set(index, new BacklogLine(entry.getKey(), tag, entry.getValue().drive));
} else {
backlog.add(new BacklogLine(entry.getKey(), tag, entry.getValue().drive));
}
sync_required = true;
} else if (entry.getValue().last_access < System.currentTimeMillis() - 600_000) {
// no access or changes in 600 seconds - unload
if (remove_keys == null)
remove_keys = new ArrayList<>();
remove_keys.add(entry.getKey());
}
}
if (remove_keys != null) {
for (var key : remove_keys) {
pool.remove(key);
}
}
if (sync_required) {
LockSupport.unpark(thread);
}
if (pool.size() == 0) {
next_save = Long.MAX_VALUE;
}
}
public static void sync() {
var copy = backlog;
backlog = new ArrayList<>();
for (var entry : copy) {
try {
var file = new File(base_directory, entry.file.toString() + ".dat");
LOGGER.info("Writing {}", entry.file);
NbtIo.writeCompressed(entry.tag, file);
} catch(Throwable error) {
var report = new CrashReport("Syncing OTM Drives state to disk", error);
var category = report.addCategory("Corrupt drive");
category.setDetail("UUID", entry.file.toString());
category.setDetail("Stored item count", entry.drive.getStoredCount());
category.setDetail("Capacity", entry.drive.getCapacity());
if (entry.drive instanceof MatteryDrive drive) {
category.setDetail("Amount of different stacks", drive.different_stacks);
category.setDetail("Max amount of different stacks", drive.max_different_stacks);
}
throw new ReportedException(report);
}
}
}
}

View File

@ -0,0 +1,50 @@
package ru.dbotthepony.mc.otm.capability.drive;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.common.util.INBTSerializable;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
import java.util.UUID;
import java.util.function.Predicate;
public interface IMatteryDrive {
List<StoredStack> getItems();
boolean isDirty();
void markDirty();
void markClean();
/**
* @param item
* @return all items belonging to passed class
*/
@Nonnull
List<StoredStack> findItems(@Nonnull Item item);
/**
* @param stack
* @return all items that match this itemstack
*/
@Nonnull
List<StoredStack> findItems(@Nonnull ItemStack stack);
@Nullable
StoredStack getItem(@Nonnull UUID id);
int getStoredCount();
int getCapacity();
@Nonnull
ItemStack insertItem(@Nonnull ItemStack item, boolean simulate);
@Nonnull
ItemStack extractItem(@Nonnull UUID id, int amount, boolean simulate);
// not extending INBTSerializable to avoid serializing it as forgecaps
CompoundTag serializeNBT();
void deserializeNBT(CompoundTag nbt);
}

View File

@ -0,0 +1,277 @@
package ru.dbotthepony.mc.otm.capability.drive;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
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.RegistryManager;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
public class MatteryDrive implements IMatteryDrive {
protected final HashMap<Item, List<StoredStack>> items = new HashMap<>();
protected final HashMap<UUID, StoredStack> items_uuid = new HashMap<>();
protected boolean dirty = false;
protected int different_stacks = 0;
protected int stored = 0;
protected int max_different_stacks;
protected int capacity;
public MatteryDrive(int capacity, int max_different_stacks) {
this.capacity = capacity;
this.max_different_stacks = max_different_stacks;
}
public MatteryDrive(int capacity) {
this(capacity, 0xFFFF);
}
@Override
public List<StoredStack> getItems() {
int amount = 0;
for (var list : items.values()) {
amount += list.size();
}
var output = new ArrayList<StoredStack>(amount);
int i = 0;
for (var list : items.values()) {
for (var stack : list) {
output.set(i, stack);
i++;
}
}
return output;
}
@Override
public boolean isDirty() {
return dirty;
}
@Override
public void markDirty() {
dirty = true;
}
@Override
public void markClean() {
dirty = false;
}
@Override
public int getStoredCount() {
return stored;
}
@Override
public int getCapacity() {
return capacity;
}
@Override
@Nonnull
public List<StoredStack> findItems(@Nonnull Item item) {
var list = items.get(item);
if (list != null)
return List.copyOf(list);
return List.of();
}
@Override
@Nonnull
public List<StoredStack> findItems(@Nonnull ItemStack stack) {
var list = items.get(stack.getItem());
if (list == null)
return List.of();
var amount = 0;
for (var _stack : list) {
if (ItemStack.tagMatches(_stack.stack(), stack)) {
amount++;
}
}
var build_list = new ArrayList<StoredStack>(amount);
for (var _stack : list) {
if (ItemStack.tagMatches(_stack.stack(), stack)) {
build_list.add(_stack);
}
}
return build_list;
}
@Nullable
@Override
public StoredStack getItem(@Nonnull UUID id) {
return items_uuid.get(id);
}
@Nonnull
@Override
public ItemStack insertItem(@Nonnull ItemStack item, boolean simulate) {
int max_insert = Math.min(getCapacity() - getStoredCount(), item.getCount());
if (max_insert <= 0)
return item;
var listing = items.computeIfAbsent(item.getItem(), (key) -> new ArrayList<>());
for (var state : listing) {
if (ItemStack.tagMatches(state.stack(), item)) {
if (!simulate) {
state.stack().grow(max_insert);
stored += max_insert;
markDirty();
}
var copy_item = item.copy();
copy_item.shrink(max_insert);
return copy_item;
}
}
if (different_stacks >= max_different_stacks) {
return item;
}
if (!simulate) {
different_stacks++;
var copy = item.copy();
copy.setCount(max_insert);
var state = new StoredStack(copy, UUID.randomUUID());
listing.add(state);
items_uuid.put(state.id(), state);
markDirty();
}
var copy_item = item.copy();
copy_item.shrink(max_insert);
return copy_item;
}
@Nonnull
@Override
public ItemStack extractItem(@Nonnull UUID id, int amount, boolean simulate) {
var get = items_uuid.get(id);
if (get == null)
return ItemStack.EMPTY;
var extract = Math.min(amount, get.stack().getCount());
if (extract <= 0)
return ItemStack.EMPTY;
if (!simulate) {
if (extract == get.stack().getCount()) {
var listing = items.get(get.stack().getItem());
listing.remove(get);
}
get.stack().shrink(extract);
markDirty();
}
var copy = get.stack().copy();
copy.setCount(extract);
return copy;
}
@Override
public CompoundTag serializeNBT() {
final var compound = new CompoundTag();
compound.putInt("capacity", capacity);
compound.putInt("max_different_stacks", max_different_stacks);
var list_items = new ListTag();
compound.put("items", list_items);
for (var entry : items.entrySet()) {
var item = Objects.requireNonNull(entry.getKey().getRegistryName(), "Missing registry name for stored Item").toString();
var entry_compound = new CompoundTag();
entry_compound.putString("id", item);
var stack_list = new ListTag();
entry_compound.put("list", stack_list);
for (var stack : entry.getValue()) {
var stack_nbt = new CompoundTag();
stack_list.add(stack_nbt);
stack_nbt.putInt("count", stack.stack().getCount());
stack_nbt.putLongArray("uuid", new long[] { stack.id().getMostSignificantBits(), stack.id().getLeastSignificantBits() });
if (stack.stack().getTag() != null) {
stack_nbt.put("data", stack.stack().getTag());
}
}
list_items.add(entry_compound);
}
return compound;
}
@Override
public void deserializeNBT(CompoundTag nbt) {
items.clear();
items_uuid.clear();
stored = 0;
different_stacks = 0;
capacity = nbt.getInt("capacity");
max_different_stacks = nbt.getInt("max_different_stacks");
var list_items = nbt.getList("items", Tag.TAG_COMPOUND);
var registry = RegistryManager.ACTIVE.getRegistry(Item.class);
for (var _entry : list_items) {
if (_entry instanceof CompoundTag entry) {
var item = registry.getValue(new ResourceLocation(entry.getString("id")));
if (item != null && item != Items.AIR) {
var map_list = items.computeIfAbsent(item, (key) -> new ArrayList<>());
var stack_list = entry.getList("list", Tag.TAG_COMPOUND);
for (var _stack : stack_list) {
if (_stack instanceof CompoundTag stack) {
var count = stack.getInt("count");
var _uuid = stack.getLongArray("uuid");
var data = stack.get("data");
var itemstack = new ItemStack(item, count);
if (data != null) {
itemstack.setTag((CompoundTag) data);
}
stored += count;
different_stacks += 1;
var state = new StoredStack(itemstack, new UUID(_uuid[0], _uuid[1]));
map_list.add(state);
items_uuid.put(state.id(), state);
}
}
}
}
}
}
}

View File

@ -0,0 +1,8 @@
package ru.dbotthepony.mc.otm.capability.drive;
import net.minecraft.world.item.ItemStack;
import java.util.UUID;
public record StoredStack(ItemStack stack, UUID id) {
}

View File

@ -0,0 +1,95 @@
package ru.dbotthepony.mc.otm.item;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.event.entity.player.EntityItemPickupEvent;
import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import ru.dbotthepony.mc.otm.OverdriveThatMatters;
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
import ru.dbotthepony.mc.otm.capability.drive.DrivePool;
import ru.dbotthepony.mc.otm.capability.drive.IMatteryDrive;
import ru.dbotthepony.mc.otm.capability.drive.MatteryDrive;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.UUID;
public class ItemPortableCondensationDrive extends Item {
public ItemPortableCondensationDrive() {
super(new Properties().stacksTo(1).tab(OverdriveThatMatters.CREATIVE_TAB));
}
@SubscribeEvent
public static void onPickupEvent(EntityItemPickupEvent event) {
for (var stack : event.getPlayer().getInventory().items) {
if (stack.getItem() instanceof ItemPortableCondensationDrive) {
var cap = stack.getCapability(MatteryCapability.DRIVE).resolve().get();
var remaining = cap.insertItem(event.getItem().getItem(), false);
if (remaining.getCount() == event.getItem().getItem().getCount()) {
continue;
}
event.setCanceled(true);
if (remaining.getCount() > 0) {
event.getItem().getItem().setCount(remaining.getCount());
} else {
event.getItem().discard();
return;
}
}
}
}
private static class DriveCapability implements ICapabilityProvider {
private UUID uuid;
private final ItemStack stack;
private final LazyOptional<IMatteryDrive> resolver = LazyOptional.of(() -> {
return DrivePool.get(uuid, (tag) -> {
var drive = new MatteryDrive(4000);
drive.deserializeNBT(tag);
return drive;
}, () -> new MatteryDrive(4000));
});
DriveCapability(ItemStack stack) {
this.stack = stack;
}
@Nonnull
@Override
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
if (cap == MatteryCapability.DRIVE) {
if (uuid == null) {
var get_value = stack.getOrCreateTag().getLongArray("uuid");
if (get_value.length == 2) {
uuid = new UUID(get_value[0], get_value[1]);
} else {
uuid = UUID.randomUUID();
stack.getOrCreateTag().putLongArray("uuid", new long[] { uuid.getMostSignificantBits(), uuid.getLeastSignificantBits() });
}
}
return resolver.cast();
}
return LazyOptional.empty();
}
}
@Nullable
@Override
public ICapabilityProvider initCapabilities(ItemStack stack, @Nullable CompoundTag nbt) {
return new DriveCapability(stack);
}
}

View File

@ -1,5 +1,6 @@
# Make Screen.title be public and easily modifiable # Make Screen.title be public and easily modifiable
public-f net.minecraft.client.gui.screens.Screen f_96539_ # title public-f net.minecraft.client.gui.screens.Screen f_96539_ # title
public net.minecraft.server.MinecraftServer f_129744_ # storageSource
# for accessing and setting from MatteryScreen class # for accessing and setting from MatteryScreen class
# protected net.minecraft.client.gui.screens.inventory.AbstractContainerScreen f_97724_ # lastQuickMoved # protected net.minecraft.client.gui.screens.inventory.AbstractContainerScreen f_97724_ # lastQuickMoved