Condensation drive test
This commit is contained in:
parent
d7a62f6d3c
commit
e7e12bed8c
@ -15,8 +15,10 @@ import org.apache.logging.log4j.Logger;
|
||||
import ru.dbotthepony.mc.otm.capability.AndroidCapability;
|
||||
import ru.dbotthepony.mc.otm.capability.AndroidCapabilityPlayer;
|
||||
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.EventHandler;
|
||||
import ru.dbotthepony.mc.otm.item.ItemPortableCondensationDrive;
|
||||
import ru.dbotthepony.mc.otm.matter.MatterGrid;
|
||||
import ru.dbotthepony.mc.otm.matter.MatterRegistry;
|
||||
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.Stats.class);
|
||||
|
||||
MinecraftForge.EVENT_BUS.register(DrivePool.class);
|
||||
MinecraftForge.EVENT_BUS.register(ItemPortableCondensationDrive.class);
|
||||
|
||||
FMLJavaModLoadingContext.get().getModEventBus().addListener(AndroidCapability::registerEffects);
|
||||
|
||||
// LOGGER.info("Registered event handlers");
|
||||
|
@ -29,10 +29,7 @@ import ru.dbotthepony.mc.otm.android.feature.AndroidNanobotsRegeneration;
|
||||
import ru.dbotthepony.mc.otm.block.*;
|
||||
import ru.dbotthepony.mc.otm.block.entity.*;
|
||||
import ru.dbotthepony.mc.otm.android.AndroidFeatureType;
|
||||
import ru.dbotthepony.mc.otm.item.ItemBattery;
|
||||
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.item.*;
|
||||
import ru.dbotthepony.mc.otm.menu.*;
|
||||
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 PORTABLE_CONDENSATION_DRIVE = new ResourceLocation(OverdriveThatMatters.MOD_ID, "portable_condensation_drive");
|
||||
|
||||
// android features and research
|
||||
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_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));
|
||||
|
||||
static {
|
||||
@ -262,6 +263,7 @@ public class Registry {
|
||||
|
||||
PATTERN_DRIVE_NORMAL.setRegistryName(Names.PATTERN_DRIVE_NORMAL);
|
||||
PATTERN_DRIVE_CREATIVE.setRegistryName(Names.PATTERN_DRIVE_CREATIVE);
|
||||
PORTABLE_CONDENSATION_DRIVE.setRegistryName(Names.PORTABLE_CONDENSATION_DRIVE);
|
||||
|
||||
NUTRIENT_PASTE.setRegistryName(Names.NUTRIENT_PASTE);
|
||||
}
|
||||
@ -293,6 +295,7 @@ public class Registry {
|
||||
|
||||
event.getRegistry().register(PATTERN_DRIVE_NORMAL);
|
||||
event.getRegistry().register(PATTERN_DRIVE_CREATIVE);
|
||||
event.getRegistry().register(PORTABLE_CONDENSATION_DRIVE);
|
||||
|
||||
event.getRegistry().register(NUTRIENT_PASTE);
|
||||
|
||||
|
@ -4,6 +4,7 @@ import net.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.common.capabilities.CapabilityInject;
|
||||
import net.minecraftforge.common.capabilities.CapabilityManager;
|
||||
import net.minecraftforge.energy.IEnergyStorage;
|
||||
import ru.dbotthepony.mc.otm.capability.drive.IMatteryDrive;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
@ -28,6 +29,9 @@ public class MatteryCapability {
|
||||
@CapabilityInject(IMatterTaskProvider.class)
|
||||
public static Capability<IMatterTaskProvider> TASK = null;
|
||||
|
||||
@CapabilityInject(IMatteryDrive.class)
|
||||
public static Capability<IMatteryDrive> DRIVE = null;
|
||||
|
||||
public static void register() {
|
||||
CapabilityManager.INSTANCE.register(IAndroidCapability.class);
|
||||
CapabilityManager.INSTANCE.register(IMatteryEnergyStorage.class);
|
||||
@ -35,6 +39,7 @@ public class MatteryCapability {
|
||||
CapabilityManager.INSTANCE.register(IPatternStorage.class);
|
||||
CapabilityManager.INSTANCE.register(IMatterGridCell.class);
|
||||
CapabilityManager.INSTANCE.register(IMatterTaskProvider.class);
|
||||
CapabilityManager.INSTANCE.register(IMatteryDrive.class);
|
||||
}
|
||||
|
||||
public static final MathContext ROUND_RULES = new MathContext(32, RoundingMode.HALF_DOWN);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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) {
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
# Make Screen.title be public and easily modifiable
|
||||
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
|
||||
# protected net.minecraft.client.gui.screens.inventory.AbstractContainerScreen f_97724_ # lastQuickMoved
|
||||
|
Loading…
Reference in New Issue
Block a user