diff --git a/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java b/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java index d6fed7fa2..6e27e0c54 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java +++ b/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java @@ -10,13 +10,10 @@ import net.minecraftforge.event.server.ServerAboutToStartEvent; import net.minecraftforge.event.server.ServerStoppingEvent; import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.InterModComms; import net.minecraftforge.fml.LogicalSide; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; -import net.minecraftforge.fml.event.lifecycle.InterModEnqueueEvent; -import net.minecraftforge.fml.event.lifecycle.InterModProcessEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -29,10 +26,10 @@ import ru.dbotthepony.mc.otm.client.AndroidGui; import ru.dbotthepony.mc.otm.client.EventHandler; import ru.dbotthepony.mc.otm.client.model.GravitationStabilizerModel; import ru.dbotthepony.mc.otm.client.model.TritaniumArmorModel; -import ru.dbotthepony.mc.otm.core.Fraction; import ru.dbotthepony.mc.otm.core.ImpreciseFraction; import ru.dbotthepony.mc.otm.item.ItemPortableCondensationDrive; -import ru.dbotthepony.mc.otm.matter.MatterRegistry; +import ru.dbotthepony.mc.otm.matter.MatterDataKt; +import ru.dbotthepony.mc.otm.matter.MatterRegistryKt; import ru.dbotthepony.mc.otm.network.MatteryNetworking; import ru.dbotthepony.mc.otm.storage.ItemStackWrapper; import ru.dbotthepony.mc.otm.storage.StorageObjectRegistry; @@ -43,7 +40,6 @@ import java.util.ArrayList; import java.util.WeakHashMap; import java.util.function.Consumer; import java.util.function.Supplier; -import java.util.stream.Collectors; // The value here should match an entry in the META-INF/mods.toml file @Mod(OverdriveThatMatters.MOD_ID) @@ -139,7 +135,8 @@ public class OverdriveThatMatters { MinecraftForge.EVENT_BUS.register(this); MinecraftForge.EVENT_BUS.register(AndroidCapabilityPlayer.Companion); MinecraftForge.EVENT_BUS.register(AndroidCapability.Companion); - MinecraftForge.EVENT_BUS.register(MatterRegistry.class); + MinecraftForge.EVENT_BUS.register(MatterRegistryKt.class); + MinecraftForge.EVENT_BUS.register(MatterDataKt.class); MinecraftForge.EVENT_BUS.register(ExplosionQueue.Companion); FMLJavaModLoadingContext.get().getModEventBus().register(MatteryCapability.class); @@ -170,12 +167,7 @@ public class OverdriveThatMatters { MatteryNetworking.register(); // LOGGER.info("Registered network"); - MatterRegistry.registerInitialItems(); - ITEM_STORAGE = StorageObjectRegistry.register(ItemStackWrapper.class, ItemStackWrapper.EMPTY, new ImpreciseFraction("3.125")); - - TritaniumArmorModel.register(); - GravitationStabilizerModel.register(); } private void setupClient(final FMLClientSetupEvent event) { @@ -183,5 +175,8 @@ public class OverdriveThatMatters { MinecraftForge.EVENT_BUS.register(ANDROID_GUI); MinecraftForge.EVENT_BUS.register(AndroidGui.class); MinecraftForge.EVENT_BUS.register(EventHandler.class); + + TritaniumArmorModel.register(); + GravitationStabilizerModel.register(); } } diff --git a/src/main/java/ru/dbotthepony/mc/otm/matter/MatterRegistry.java b/src/main/java/ru/dbotthepony/mc/otm/matter/MatterRegistry.java deleted file mode 100644 index 0baf42759..000000000 --- a/src/main/java/ru/dbotthepony/mc/otm/matter/MatterRegistry.java +++ /dev/null @@ -1,573 +0,0 @@ -package ru.dbotthepony.mc.otm.matter; - -import com.mojang.blaze3d.platform.InputConstants; -import net.minecraft.ChatFormatting; -import net.minecraft.client.Minecraft; -import net.minecraft.server.dedicated.DedicatedServer; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; -import net.minecraft.world.item.crafting.Ingredient; -import net.minecraft.world.item.crafting.Recipe; -import net.minecraft.world.item.crafting.RecipeType; -import net.minecraftforge.event.entity.player.ItemTooltipEvent; -import net.minecraftforge.event.entity.player.PlayerEvent; -import net.minecraftforge.event.server.ServerStartedEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.network.PacketDistributor; -import ru.dbotthepony.mc.otm.OverdriveThatMatters; -import ru.dbotthepony.mc.otm.capability.MatteryCapability; -import ru.dbotthepony.mc.otm.capability.drive.IMatteryDrive; -import ru.dbotthepony.mc.otm.core.Fraction; -import ru.dbotthepony.mc.otm.core.ImpreciseFraction; -import ru.dbotthepony.mc.otm.menu.FormattingHelper; -import ru.dbotthepony.mc.otm.network.MatterRegistryPacket; -import ru.dbotthepony.mc.otm.network.MatteryNetworking; -import ru.dbotthepony.mc.otm.storage.ItemStackWrapper; - -import javax.annotation.Nullable; -import java.math.MathContext; -import java.util.*; - -public class MatterRegistry { - public static final Map INITIAL_ITEMS = new HashMap<>(); - public static final Map ITEMS = new HashMap<>(); - - public static ImpreciseFraction getMatterValue(Item item) { - return ITEMS.getOrDefault(item, INITIAL_ITEMS.getOrDefault(item, ImpreciseFraction.ZERO)); - } - - public static boolean hasMatterValue(Item item) { - return ITEMS.containsKey(item) || INITIAL_ITEMS.containsKey(item); - } - - public static boolean hasMatterValue(ItemStack item) { - if (item.getCapability(MatteryCapability.DRIVE).isPresent() || item.getCapability(MatteryCapability.MATTER).isPresent()) - return true; - - return hasMatterValue(item.getItem()); - } - - public static boolean canDecompose(ItemStack stack) { - if (stack.getCapability(MatteryCapability.DRIVE).isPresent() && stack.getCapability(MatteryCapability.DRIVE).resolve().get().getStoredCount().compareTo(ImpreciseFraction.ZERO) > 0) - return false; - - if (stack.getCapability(MatteryCapability.MATTER).isPresent() && stack.getCapability(MatteryCapability.MATTER).resolve().get().getStoredMatter().compareTo(ImpreciseFraction.ZERO) > 0) - return false; - - return hasMatterValue(stack.getItem()); - } - - private static ImpreciseFraction getMatterValue(ItemStack stack, int level) { - if (level >= 100) { - return ImpreciseFraction.ZERO; - } - - Item item = stack.getItem(); - var matter = getMatterValue(item); - - if (item.isDamageable(stack)) { - matter = matter.times(ImpreciseFraction.ONE.minus(new ImpreciseFraction(item.getDamage(stack)).div(new ImpreciseFraction(item.getMaxDamage(stack))))); - } - - var cap1 = stack.getCapability(MatteryCapability.DRIVE).resolve(); - var cap2 = stack.getCapability(MatteryCapability.MATTER).resolve(); - - if (cap1.isPresent() && cap1.get().storageIdentity() == ItemStackWrapper.class) { - for (var stored : ((IMatteryDrive) cap1.get()).getStacks()) { - matter = matter.plus(getMatterValue(stored.stack().stack(), level + 1)); - } - } - - if (cap2.isPresent()) { - matter = matter.plus(cap2.get().getStoredMatter()); - } - - return matter; - } - - public static ImpreciseFraction getMatterValue(ItemStack stack) { - return getMatterValue(stack, 0); - } - - public static void registerInitialItems() { - // basic things - INITIAL_ITEMS.put(Items.DIRT, new ImpreciseFraction("0.0013")); - INITIAL_ITEMS.put(Items.DIRT_PATH, new ImpreciseFraction("0.0013")); - INITIAL_ITEMS.put(Items.GRASS_BLOCK, new ImpreciseFraction("0.0016")); - - INITIAL_ITEMS.put(Items.POINTED_DRIPSTONE, new ImpreciseFraction("0.0007")); - - INITIAL_ITEMS.put(Items.STONE, new ImpreciseFraction("0.001")); - INITIAL_ITEMS.put(Items.COBBLESTONE, new ImpreciseFraction("0.001")); - INITIAL_ITEMS.put(Items.MOSSY_COBBLESTONE, new ImpreciseFraction("0.001")); - INITIAL_ITEMS.put(Items.NETHERRACK, new ImpreciseFraction("0.00027")); - INITIAL_ITEMS.put(Items.GRANITE, new ImpreciseFraction("0.0011")); - INITIAL_ITEMS.put(Items.DIORITE, new ImpreciseFraction("0.0013")); - INITIAL_ITEMS.put(Items.ANDESITE, new ImpreciseFraction("0.0012")); - INITIAL_ITEMS.put(Items.BASALT, new ImpreciseFraction("0.0013")); - - INITIAL_ITEMS.put(Items.SOUL_SAND, new ImpreciseFraction("0.00087")); - INITIAL_ITEMS.put(Items.SOUL_SOIL, new ImpreciseFraction("0.00087")); - - INITIAL_ITEMS.put(Items.ICE, new ImpreciseFraction("0.0002")); - - INITIAL_ITEMS.put(Items.GRAVEL, new ImpreciseFraction("0.001")); - INITIAL_ITEMS.put(Items.FLINT, new ImpreciseFraction("0.001")); - - INITIAL_ITEMS.put(Items.SAND, new ImpreciseFraction("0.0005")); - INITIAL_ITEMS.put(Items.RED_SAND, new ImpreciseFraction("0.0005")); - - INITIAL_ITEMS.put(Items.TUFF, new ImpreciseFraction("0.0007")); - INITIAL_ITEMS.put(Items.DEEPSLATE, new ImpreciseFraction("0.0014")); - INITIAL_ITEMS.put(Items.COBBLED_DEEPSLATE, new ImpreciseFraction("0.0014")); - - INITIAL_ITEMS.put(Items.BLACKSTONE, new ImpreciseFraction("0.0015")); - - INITIAL_ITEMS.put(Items.INFESTED_STONE, new ImpreciseFraction("0.063")); - INITIAL_ITEMS.put(Items.INFESTED_COBBLESTONE, new ImpreciseFraction("0.063")); - INITIAL_ITEMS.put(Items.INFESTED_STONE_BRICKS, new ImpreciseFraction("0.063")); - INITIAL_ITEMS.put(Items.INFESTED_MOSSY_STONE_BRICKS, new ImpreciseFraction("0.063")); - INITIAL_ITEMS.put(Items.INFESTED_CRACKED_STONE_BRICKS, new ImpreciseFraction("0.063")); - INITIAL_ITEMS.put(Items.INFESTED_CHISELED_STONE_BRICKS, new ImpreciseFraction("0.063")); - INITIAL_ITEMS.put(Items.INFESTED_DEEPSLATE, new ImpreciseFraction("0.067")); - - // affected by luck enchantment, thus can be duped - // INITIAL_ITEMS.put(Items.GILDED_BLACKSTONE, new ImpreciseFraction("0.037")); - INITIAL_ITEMS.put(Items.GILDED_BLACKSTONE, new ImpreciseFraction("0.34")); - - // assuming it is very light since it is floating - INITIAL_ITEMS.put(Items.END_STONE, new ImpreciseFraction("0.0004")); - - INITIAL_ITEMS.put(Items.OBSIDIAN, new ImpreciseFraction("0.038")); - - // metallic / chemical things - INITIAL_ITEMS.put(Items.COAL, new ImpreciseFraction("0.005")); - INITIAL_ITEMS.put(Items.LAPIS_LAZULI, new ImpreciseFraction("0.0042")); - INITIAL_ITEMS.put(Items.REDSTONE, new ImpreciseFraction("0.004")); - INITIAL_ITEMS.put(Items.CHARCOAL, new ImpreciseFraction("0.005")); - INITIAL_ITEMS.put(Items.DIAMOND, new ImpreciseFraction("0.5")); - INITIAL_ITEMS.put(Items.EMERALD, new ImpreciseFraction("0.46")); - INITIAL_ITEMS.put(Items.IRON_INGOT, new ImpreciseFraction("0.03")); - INITIAL_ITEMS.put(Items.COPPER_INGOT, new ImpreciseFraction("0.014")); - INITIAL_ITEMS.put(Items.GOLD_INGOT, new ImpreciseFraction("0.32")); - INITIAL_ITEMS.put(Items.NETHERITE_SCRAP, new ImpreciseFraction("1.2")); - INITIAL_ITEMS.put(Items.QUARTZ, new ImpreciseFraction("0.008")); - INITIAL_ITEMS.put(Items.GLOWSTONE_DUST, new ImpreciseFraction("0.007")); - INITIAL_ITEMS.put(Items.AMETHYST_SHARD, new ImpreciseFraction("0.034")); - - // living things - INITIAL_ITEMS.put(Items.MOSS_BLOCK, new ImpreciseFraction("0.0012")); - - INITIAL_ITEMS.put(Items.OAK_LOG, new ImpreciseFraction("0.005")); - INITIAL_ITEMS.put(Items.SPRUCE_LOG, new ImpreciseFraction("0.005")); - INITIAL_ITEMS.put(Items.BIRCH_LOG, new ImpreciseFraction("0.005")); - INITIAL_ITEMS.put(Items.JUNGLE_LOG, new ImpreciseFraction("0.005")); - INITIAL_ITEMS.put(Items.ACACIA_LOG, new ImpreciseFraction("0.005")); - INITIAL_ITEMS.put(Items.DARK_OAK_LOG, new ImpreciseFraction("0.005")); - - INITIAL_ITEMS.put(Items.BAMBOO, new ImpreciseFraction("0.00085")); - - INITIAL_ITEMS.put(Items.CRIMSON_PLANKS, new ImpreciseFraction("0.003")); - INITIAL_ITEMS.put(Items.WARPED_PLANKS, new ImpreciseFraction("0.003")); - - INITIAL_ITEMS.put(Items.STRIPPED_OAK_LOG, new ImpreciseFraction("0.005")); - INITIAL_ITEMS.put(Items.STRIPPED_SPRUCE_LOG, new ImpreciseFraction("0.005")); - INITIAL_ITEMS.put(Items.STRIPPED_BIRCH_LOG, new ImpreciseFraction("0.005")); - INITIAL_ITEMS.put(Items.STRIPPED_JUNGLE_LOG, new ImpreciseFraction("0.005")); - INITIAL_ITEMS.put(Items.STRIPPED_ACACIA_LOG, new ImpreciseFraction("0.005")); - INITIAL_ITEMS.put(Items.STRIPPED_DARK_OAK_LOG, new ImpreciseFraction("0.005")); - - INITIAL_ITEMS.put(Items.CACTUS, new ImpreciseFraction("0.0039")); - INITIAL_ITEMS.put(Items.PUMPKIN, new ImpreciseFraction("0.005")); - INITIAL_ITEMS.put(Items.MELON, new ImpreciseFraction("0.005")); - - // flowers! - final ImpreciseFraction flower_value = new ImpreciseFraction("0.0031"); - INITIAL_ITEMS.put(Items.DANDELION, flower_value); - INITIAL_ITEMS.put(Items.POPPY, flower_value); - INITIAL_ITEMS.put(Items.BLUE_ORCHID, flower_value); - INITIAL_ITEMS.put(Items.ALLIUM, flower_value); - INITIAL_ITEMS.put(Items.AZURE_BLUET, flower_value); - INITIAL_ITEMS.put(Items.RED_TULIP, flower_value); - INITIAL_ITEMS.put(Items.ORANGE_TULIP, flower_value); - INITIAL_ITEMS.put(Items.WHITE_TULIP, flower_value); - INITIAL_ITEMS.put(Items.PINK_TULIP, flower_value); - INITIAL_ITEMS.put(Items.OXEYE_DAISY, flower_value); - INITIAL_ITEMS.put(Items.CORNFLOWER, flower_value); - INITIAL_ITEMS.put(Items.LILY_OF_THE_VALLEY, flower_value); - - final ImpreciseFraction big_flower_value = new ImpreciseFraction("0.0042"); - INITIAL_ITEMS.put(Items.SUNFLOWER, big_flower_value); - INITIAL_ITEMS.put(Items.LILAC, big_flower_value); - INITIAL_ITEMS.put(Items.ROSE_BUSH, big_flower_value); - INITIAL_ITEMS.put(Items.PEONY, big_flower_value); - - INITIAL_ITEMS.put(Items.SPORE_BLOSSOM, new ImpreciseFraction("0.0067")); - INITIAL_ITEMS.put(Items.BROWN_MUSHROOM, new ImpreciseFraction("0.0034")); - INITIAL_ITEMS.put(Items.RED_MUSHROOM, new ImpreciseFraction("0.0034")); - INITIAL_ITEMS.put(Items.CRIMSON_FUNGUS, new ImpreciseFraction("0.004")); - INITIAL_ITEMS.put(Items.WARPED_FUNGUS, new ImpreciseFraction("0.004")); - - // grass - final ImpreciseFraction grass_value = new ImpreciseFraction("0.0024"); - INITIAL_ITEMS.put(Items.CRIMSON_ROOTS, grass_value); - INITIAL_ITEMS.put(Items.WARPED_ROOTS, grass_value); - INITIAL_ITEMS.put(Items.NETHER_SPROUTS, new ImpreciseFraction("0.002")); - INITIAL_ITEMS.put(Items.WEEPING_VINES, grass_value); - INITIAL_ITEMS.put(Items.TWISTING_VINES, grass_value); - INITIAL_ITEMS.put(Items.HANGING_ROOTS, grass_value); - INITIAL_ITEMS.put(Items.TALL_GRASS, new ImpreciseFraction("0.0035")); - INITIAL_ITEMS.put(Items.LARGE_FERN, new ImpreciseFraction("0.0035")); - INITIAL_ITEMS.put(Items.GRASS, grass_value); - INITIAL_ITEMS.put(Items.VINE, grass_value); - INITIAL_ITEMS.put(Items.LILY_PAD, grass_value); - INITIAL_ITEMS.put(Items.BIG_DRIPLEAF, grass_value); - INITIAL_ITEMS.put(Items.SMALL_DRIPLEAF, grass_value); - INITIAL_ITEMS.put(Items.SEA_PICKLE, grass_value); - INITIAL_ITEMS.put(Items.SEAGRASS, grass_value); - INITIAL_ITEMS.put(Items.FERN, grass_value); - INITIAL_ITEMS.put(Items.DEAD_BUSH, new ImpreciseFraction("0.0017")); - INITIAL_ITEMS.put(Items.GLOW_LICHEN, new ImpreciseFraction("0.0026")); - INITIAL_ITEMS.put(Items.AZALEA, new ImpreciseFraction("0.0018")); - INITIAL_ITEMS.put(Items.FLOWERING_AZALEA, grass_value); - - // living plant (not very blocky) things - // saplings - INITIAL_ITEMS.put(Items.OAK_SAPLING, new ImpreciseFraction("0.0035")); - INITIAL_ITEMS.put(Items.SPRUCE_SAPLING, new ImpreciseFraction("0.0045")); - INITIAL_ITEMS.put(Items.BIRCH_SAPLING, new ImpreciseFraction("0.0035")); - INITIAL_ITEMS.put(Items.JUNGLE_SAPLING, new ImpreciseFraction("0.0048")); - INITIAL_ITEMS.put(Items.ACACIA_SAPLING, new ImpreciseFraction("0.0033")); - INITIAL_ITEMS.put(Items.DARK_OAK_SAPLING, new ImpreciseFraction("0.005")); - - INITIAL_ITEMS.put(Items.WHEAT_SEEDS, new ImpreciseFraction("0.0007")); - INITIAL_ITEMS.put(Items.BEETROOT_SEEDS, new ImpreciseFraction("0.0007")); - // INITIAL_ITEMS.put(Items.MELON_SEEDS, new ImpreciseFraction("0.0013")); - INITIAL_ITEMS.put(Items.WHEAT, new ImpreciseFraction("0.0016")); - INITIAL_ITEMS.put(Items.NETHER_WART, new ImpreciseFraction("0.0017")); - INITIAL_ITEMS.put(Items.CARROT, new ImpreciseFraction("0.0019")); - INITIAL_ITEMS.put(Items.POTATO, new ImpreciseFraction("0.0021")); - INITIAL_ITEMS.put(Items.BEETROOT, new ImpreciseFraction("0.0021")); - INITIAL_ITEMS.put(Items.MELON_SLICE, new ImpreciseFraction("0.0008")); - - INITIAL_ITEMS.put(Items.COCOA_BEANS, new ImpreciseFraction("0.00035")); - INITIAL_ITEMS.put(Items.HONEYCOMB, new ImpreciseFraction("0.0014")); - INITIAL_ITEMS.put(Items.SUGAR_CANE, new ImpreciseFraction("0.004")); - INITIAL_ITEMS.put(Items.APPLE, new ImpreciseFraction("0.0061")); - INITIAL_ITEMS.put(Items.SWEET_BERRIES, new ImpreciseFraction("0.0035")); - INITIAL_ITEMS.put(Items.GLOW_BERRIES, new ImpreciseFraction("0.0041")); - INITIAL_ITEMS.put(Items.KELP, new ImpreciseFraction("0.0009")); - - // living animal things - INITIAL_ITEMS.put(Items.STRING, new ImpreciseFraction("0.0006")); - INITIAL_ITEMS.put(Items.COBWEB, new ImpreciseFraction("0.0006")); - INITIAL_ITEMS.put(Items.INK_SAC, new ImpreciseFraction("0.0009")); - INITIAL_ITEMS.put(Items.SPIDER_EYE, new ImpreciseFraction("0.001")); - INITIAL_ITEMS.put(Items.FEATHER, new ImpreciseFraction("0.0007")); - INITIAL_ITEMS.put(Items.GUNPOWDER, new ImpreciseFraction("0.003")); - INITIAL_ITEMS.put(Items.LEATHER, new ImpreciseFraction("0.0065")); - INITIAL_ITEMS.put(Items.BONE, new ImpreciseFraction("0.004")); - INITIAL_ITEMS.put(Items.ENDER_PEARL, new ImpreciseFraction("0.041")); - INITIAL_ITEMS.put(Items.GHAST_TEAR, new ImpreciseFraction("0.023")); - INITIAL_ITEMS.put(Items.BLAZE_ROD, new ImpreciseFraction("0.02")); - INITIAL_ITEMS.put(Items.SLIME_BALL, new ImpreciseFraction("0.0015")); - INITIAL_ITEMS.put(Items.EGG, new ImpreciseFraction("0.0011")); - - INITIAL_ITEMS.put(Items.PORKCHOP, new ImpreciseFraction("0.0047")); - INITIAL_ITEMS.put(Items.BEEF, new ImpreciseFraction("0.0047")); - INITIAL_ITEMS.put(Items.MUTTON, new ImpreciseFraction("0.004")); - - INITIAL_ITEMS.put(Items.PUFFERFISH, new ImpreciseFraction("0.013")); - INITIAL_ITEMS.put(Items.COD, new ImpreciseFraction("0.013")); - INITIAL_ITEMS.put(Items.SALMON, new ImpreciseFraction("0.013")); - INITIAL_ITEMS.put(Items.TROPICAL_FISH, new ImpreciseFraction("0.013")); - - // building items - INITIAL_ITEMS.put(Items.CLAY_BALL, new ImpreciseFraction("0.0006")); - INITIAL_ITEMS.put(Items.SNOWBALL, new ImpreciseFraction("0.00041")); - - // loot - INITIAL_ITEMS.put(Items.TOTEM_OF_UNDYING, new ImpreciseFraction("1.47")); - INITIAL_ITEMS.put(Items.TRIDENT, new ImpreciseFraction("1.35")); - - /* - INITIAL_ITEMS.put(Items.WHITE_WOOL, new ImpreciseFraction("0.004")); - INITIAL_ITEMS.put(Items.ORANGE_WOOL, new ImpreciseFraction("0.004")); - INITIAL_ITEMS.put(Items.MAGENTA_WOOL, new ImpreciseFraction("0.004")); - INITIAL_ITEMS.put(Items.LIGHT_BLUE_WOOL, new ImpreciseFraction("0.004")); - INITIAL_ITEMS.put(Items.YELLOW_WOOL, new ImpreciseFraction("0.004")); - INITIAL_ITEMS.put(Items.LIME_WOOL, new ImpreciseFraction("0.004")); - INITIAL_ITEMS.put(Items.PINK_WOOL, new ImpreciseFraction("0.004")); - INITIAL_ITEMS.put(Items.GRAY_WOOL, new ImpreciseFraction("0.004")); - INITIAL_ITEMS.put(Items.LIGHT_GRAY_WOOL, new ImpreciseFraction("0.004")); - INITIAL_ITEMS.put(Items.CYAN_WOOL, new ImpreciseFraction("0.004")); - INITIAL_ITEMS.put(Items.PURPLE_WOOL, new ImpreciseFraction("0.004")); - INITIAL_ITEMS.put(Items.BLUE_WOOL, new ImpreciseFraction("0.004")); - INITIAL_ITEMS.put(Items.BROWN_WOOL, new ImpreciseFraction("0.004")); - INITIAL_ITEMS.put(Items.GREEN_WOOL, new ImpreciseFraction("0.004")); - INITIAL_ITEMS.put(Items.RED_WOOL, new ImpreciseFraction("0.004")); - INITIAL_ITEMS.put(Items.BLACK_WOOL, new ImpreciseFraction("0.004")); - */ - - // INITIAL_ITEMS.put(Items.CRIMSON_LOG, new ImpreciseFraction("0.005")); - // INITIAL_ITEMS.put(Items.WARPED_LOG, new ImpreciseFraction("0.005")); - } - - private static void registerPostItem(Item item, Item base, ImpreciseFraction multiplier) { - ImpreciseFraction value = getMatterValue(base); - - if (!value.equals(Fraction.ZERO)) { - ITEMS.put(item, value.times(multiplier)); - } - } - - public static void registerPostItems() { - registerPostItem(Items.CHIPPED_ANVIL, Items.ANVIL, new ImpreciseFraction("0.8")); - registerPostItem(Items.DAMAGED_ANVIL, Items.ANVIL, new ImpreciseFraction("0.5")); - } - - private static final HashMap>> usages = new HashMap<>(); - private static final HashMap>> results = new HashMap<>(); - private static final HashMap seen_items = new HashMap<>(); - private static final HashMap seen_items_child = new HashMap<>(); - - private static boolean solve_occured = false; - private static final Set defered_items = new HashSet<>(); - - private static int stack_index = 0; - private static final Item[] scan_stack = new Item[1000]; - - @Nullable - private static ImpreciseFraction determineValue(Item item) { - ImpreciseFraction _get = ITEMS.get(item); - - if (_get != null) { - return _get; - } - - _get = INITIAL_ITEMS.get(item); - - if (_get != null) { - return _get; - } - - if (defered_items.contains(item)) { - return null; - } - - for (Item value : scan_stack) { - if (value == null) - break; - - if (value == item) { - // defer, we hit an recursive recipe - defered_items.add(item); - return null; - } - } - - if (seen_items.containsKey(item)) { - // OverdriveThatMatters.LOGGER.debug("Already seen: {}", item); - seen_items.put(item, seen_items.get(item) + 1); - - if (seen_items_child.containsKey(item)) { - for (Item child : seen_items_child.values()) { - seen_items.put(child, seen_items.get(child) + 1); - } - } - - return ImpreciseFraction.ZERO; - } - - seen_items.put(item, 0); - - if (!results.containsKey(item)) { - return ImpreciseFraction.ZERO; - } - - scan_stack[stack_index] = item; - stack_index++; - - boolean defer_occured = false; - - ImpreciseFraction smallest_possible_total = null; - - for (Recipe recipe : results.get(item)) { - ItemStack self = recipe.getResultItem(); - ImpreciseFraction recipe_summ = ImpreciseFraction.ZERO; - - boolean this_defered = false; - - for (Ingredient ingredient : recipe.getIngredients()) { - ItemStack[] items = ingredient.getItems(); - - ImpreciseFraction smallest_possible = null; - - for (ItemStack stack : items) { - if (!stack.isEmpty()) { - ImpreciseFraction determine = determineValue(stack.getItem()); - - // if we hit an recursive recipe, defer it - if (determine != null) { - if (determine.isZero()) { - // farewell - OverdriveThatMatters.LOGGER.debug("Cannot determine matter value for {} because value of {} is unknown", item, stack.getItem()); - seen_items_child.put(item, stack.getItem()); - scan_stack[stack_index] = null; - stack_index--; - return ImpreciseFraction.ZERO; - } - - if (smallest_possible == null || smallest_possible.compareTo(determine) > 0) - smallest_possible = determine; - } else { - OverdriveThatMatters.LOGGER.debug("Matter value for {} happened to be defered in calculations because {} is defered", item, stack.getItem()); - defer_occured = true; - this_defered = true; - smallest_possible = null; - break; - } - } - } - - if (this_defered) - break; - - if (smallest_possible != null) { - recipe_summ = recipe_summ.plus(smallest_possible); - } - } - - if (this_defered) - continue; - - recipe_summ = recipe_summ.div(self.getCount()); - - if (smallest_possible_total == null || smallest_possible_total.compareTo(recipe_summ) > 0) - smallest_possible_total = recipe_summ; - } - - if (smallest_possible_total != null) { - // ez - ITEMS.put(item, smallest_possible_total); - scan_stack[stack_index] = null; - stack_index--; - solve_occured = true; - return smallest_possible_total; - } - - if (defer_occured) { - defered_items.add(item); - scan_stack[stack_index] = null; - stack_index--; - OverdriveThatMatters.LOGGER.debug("Matter value for {} is defered completely until next iteration", item); - return null; - } - - scan_stack[stack_index] = null; - stack_index--; - return ImpreciseFraction.ZERO; - } - - private static void flood(List> recipe_type) { - for (Recipe recipe : recipe_type) { - ItemStack result = recipe.getResultItem(); - - if (result.isEmpty()) - continue; - - ArrayList> results_get = results.computeIfAbsent(result.getItem(), k -> new ArrayList<>()); - - if (results_get.contains(recipe)) - return; - - results_get.add(recipe); - - for (Ingredient ingredient : recipe.getIngredients()) { - ItemStack[] items = ingredient.getItems(); - - for (ItemStack stack : items) { - if (!stack.isEmpty()) { - ArrayList> usages_get = usages.computeIfAbsent(stack.getItem(), k -> new ArrayList<>()); - - if (!usages_get.contains(recipe)) { - usages_get.add(recipe); - } - } - } - } - } - } - - private static boolean should_network = false; - - @SubscribeEvent - public static void onClientLogin(PlayerEvent.PlayerLoggedInEvent event) { - if (!should_network) - return; - - MatteryNetworking.CHANNEL.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) event.getPlayer()), new MatterRegistryPacket(ITEMS)); - } - - @SubscribeEvent - public static void onServerStarted(ServerStartedEvent event) { - should_network = event.getServer() instanceof DedicatedServer; - - ITEMS.clear(); - usages.clear(); - results.clear(); - defered_items.clear(); - seen_items.clear(); - seen_items_child.clear(); - - // scan for recipes and build linked tables - flood(event.getServer().getRecipeManager().getAllRecipesFor(RecipeType.CRAFTING)); - flood(event.getServer().getRecipeManager().getAllRecipesFor(RecipeType.SMELTING)); - flood(event.getServer().getRecipeManager().getAllRecipesFor(RecipeType.STONECUTTING)); - flood(event.getServer().getRecipeManager().getAllRecipesFor(RecipeType.SMITHING)); - - // expand the recipe tree and find references - // just scan entire known tree - solve_occured = true; - - for (int i = 0; i < 100 && solve_occured; i++) - for (Item item : results.keySet()) { - seen_items.clear(); - seen_items_child.clear(); - defered_items.clear(); - determineValue(item); - } - - // clean up garbage - usages.clear(); - results.clear(); - defered_items.clear(); - - ArrayList> required_resolve = new ArrayList<>(seen_items.entrySet()); - required_resolve.sort((a, b) -> Integer.compare(0, a.getValue().compareTo(b.getValue()))); - - for (Map.Entry entry : required_resolve) { - if (entry.getValue() > 0) { - OverdriveThatMatters.LOGGER.debug("Resolving matter value of {} will unlock {} subcalls (reason: {})", entry.getKey(), entry.getValue(), seen_items_child.getOrDefault(entry.getKey(), Items.AIR)); - } - } - - seen_items.clear(); - seen_items_child.clear(); - - registerPostItems(); - } - - @SubscribeEvent - public static void attachItemStackTextEvent(ItemTooltipEvent event) { - if (InputConstants.isKeyDown(Minecraft.getInstance().getWindow().getWindow(), 340) || InputConstants.isKeyDown(Minecraft.getInstance().getWindow().getWindow(), 344)) { - ImpreciseFraction matter_value = getMatterValue(event.getItemStack()); - - if (!matter_value.isZero()) { - event.getToolTip().add(FormattingHelper.formatMatterValue(matter_value).withStyle(ChatFormatting.AQUA)); - } - } - } -} diff --git a/src/main/java/ru/dbotthepony/mc/otm/network/MatterRegistryPacket.java b/src/main/java/ru/dbotthepony/mc/otm/network/MatterRegistryPacket.java deleted file mode 100644 index 8c5ff967e..000000000 --- a/src/main/java/ru/dbotthepony/mc/otm/network/MatterRegistryPacket.java +++ /dev/null @@ -1,53 +0,0 @@ -package ru.dbotthepony.mc.otm.network; - -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.world.item.Item; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.DistExecutor; -import net.minecraftforge.network.NetworkEvent; -import net.minecraftforge.registries.ForgeRegistry; -import net.minecraftforge.registries.RegistryManager; -import ru.dbotthepony.mc.otm.core.Fraction; -import ru.dbotthepony.mc.otm.core.ImpreciseFraction; -import ru.dbotthepony.mc.otm.matter.MatterRegistry; - -import java.math.BigDecimal; -import java.util.HashMap; -import java.util.Map; -import java.util.function.Supplier; - -public record MatterRegistryPacket(Map list) { - public void write(FriendlyByteBuf buffer) { - buffer.writeInt(list.size()); - var registry = (ForgeRegistry) RegistryManager.ACTIVE.getRegistry(Item.class); - - for (var entry : list.entrySet()) { - buffer.writeInt(registry.getID(entry.getKey())); - entry.getValue().write(buffer); - } - } - - public static MatterRegistryPacket read(FriendlyByteBuf buffer) { - var size = buffer.readInt(); - var registry = (ForgeRegistry) RegistryManager.ACTIVE.getRegistry(Item.class); - - var map = new HashMap(); - - for (int i = 0; i < size; i++) { - map.put(registry.getValue(buffer.readInt()), ImpreciseFraction.read(buffer)); - } - - return new MatterRegistryPacket(map); - } - - public void playClient() { - MatterRegistry.ITEMS.clear(); - MatterRegistry.ITEMS.putAll(list); - } - - public void play(Supplier context) { - context.get().setPacketHandled(true); - - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> this::playClient); - } -} diff --git a/src/main/java/ru/dbotthepony/mc/otm/network/MatteryNetworking.java b/src/main/java/ru/dbotthepony/mc/otm/network/MatteryNetworking.java index b7fcd4421..e8ea8688e 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/network/MatteryNetworking.java +++ b/src/main/java/ru/dbotthepony/mc/otm/network/MatteryNetworking.java @@ -8,6 +8,10 @@ import net.minecraftforge.network.PacketDistributor; import net.minecraftforge.network.simple.SimpleChannel; import ru.dbotthepony.mc.otm.OverdriveThatMatters; import ru.dbotthepony.mc.otm.block.entity.EnergyCounterPacket; +import ru.dbotthepony.mc.otm.matter.RegistryPacketClear; +import ru.dbotthepony.mc.otm.matter.RegistryPacketFullUpdate; +import ru.dbotthepony.mc.otm.matter.RegistryPacketRemove; +import ru.dbotthepony.mc.otm.matter.RegistryPacketUpdate; import ru.dbotthepony.mc.otm.menu.MenuDriveViewer; import ru.dbotthepony.mc.otm.menu.data.*; import ru.dbotthepony.mc.otm.network.android.*; @@ -117,10 +121,37 @@ public class MatteryNetworking { CHANNEL.registerMessage( next_network_id++, - MatterRegistryPacket.class, - MatterRegistryPacket::write, - MatterRegistryPacket::read, - MatterRegistryPacket::play, + RegistryPacketClear.class, + RegistryPacketClear::write, + RegistryPacketClear.Companion::read, + RegistryPacketClear::play, + Optional.of(NetworkDirection.PLAY_TO_CLIENT) + ); + + CHANNEL.registerMessage( + next_network_id++, + RegistryPacketUpdate.class, + RegistryPacketUpdate::write, + RegistryPacketUpdate.Companion::read, + RegistryPacketUpdate::play, + Optional.of(NetworkDirection.PLAY_TO_CLIENT) + ); + + CHANNEL.registerMessage( + next_network_id++, + RegistryPacketFullUpdate.class, + RegistryPacketFullUpdate::write, + RegistryPacketFullUpdate.Companion::read, + RegistryPacketFullUpdate::play, + Optional.of(NetworkDirection.PLAY_TO_CLIENT) + ); + + CHANNEL.registerMessage( + next_network_id++, + RegistryPacketRemove.class, + RegistryPacketRemove::write, + RegistryPacketRemove.Companion::read, + RegistryPacketRemove::play, Optional.of(NetworkDirection.PLAY_TO_CLIENT) ); diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatterDecomposer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatterDecomposer.kt index 362af67a3..08e74df42 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatterDecomposer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatterDecomposer.kt @@ -25,13 +25,14 @@ import ru.dbotthepony.mc.otm.capability.MatteryMachineEnergyStorage import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler import ru.dbotthepony.mc.otm.capability.matter.MatterHandlerCapability import ru.dbotthepony.mc.otm.container.MatteryContainer -import ru.dbotthepony.mc.otm.core.Fraction import ru.dbotthepony.mc.otm.core.ImpreciseFraction import ru.dbotthepony.mc.otm.graph.Graph6Node import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph import ru.dbotthepony.mc.otm.ifHas -import ru.dbotthepony.mc.otm.matter.MatterRegistry +import ru.dbotthepony.mc.otm.matter.baselineComplexityDecomposeTicks +import ru.dbotthepony.mc.otm.matter.canDecompose +import ru.dbotthepony.mc.otm.matter.getMatterValue import ru.dbotthepony.mc.otm.menu.MenuMatterDecomposer import ru.dbotthepony.mc.otm.set @@ -67,8 +68,8 @@ class BlockEntityMatterDecomposer(pos: BlockPos, state: BlockState) private val itemHandler = LazyOptional.of { itemContainer.handler( - { slot: Int, stack: ItemStack? -> slot == 0 && MatterRegistry.canDecompose(stack) }, - { slot: Int, amount: Int, stack: ItemStack? -> slot == 1 }) + { slot: Int, stack: ItemStack -> slot == 0 && canDecompose(stack) }, + { slot: Int, amount: Int, stack: ItemStack -> slot == 1 }) } override fun getDefaultDisplayName(): Component { @@ -118,7 +119,7 @@ class BlockEntityMatterDecomposer(pos: BlockPos, state: BlockState) } override fun onJobFinish(job: MachineJob): MachineJobStatus { - matter.receiveMatterInner(MatterRegistry.getMatterValue(job.stack()), false) + matter.receiveMatterInner(getMatterValue(job.stack()).value, false) return MachineJobStatus() } @@ -129,12 +130,12 @@ class BlockEntityMatterDecomposer(pos: BlockPos, state: BlockState) val copy = stack.copy() copy.count = 1 - if (MatterRegistry.canDecompose(copy)) { - val value = MatterRegistry.getMatterValue(copy) + if (canDecompose(copy)) { + val matter = getMatterValue(copy) - if (!value.isZero && matter.canReceiveAll(value)) { + if (!matter.isZero && this.matter.canReceiveAll(matter.value)) { stack.shrink(1) - return MachineJob(copy, value.toDouble() * 12500.0, BASE_CONSUMPTION) + return MachineJob(copy, matter.complexity * baselineComplexityDecomposeTicks, BASE_CONSUMPTION) } } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatterReplicator.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatterReplicator.kt index 500c290e0..e00ad3b6b 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatterReplicator.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatterReplicator.kt @@ -28,13 +28,13 @@ import ru.dbotthepony.mc.otm.capability.matter.MatterHandlerCapability import ru.dbotthepony.mc.otm.capability.matter.MatterTask import ru.dbotthepony.mc.otm.capability.matter.PatternState import ru.dbotthepony.mc.otm.container.MatteryContainer -import ru.dbotthepony.mc.otm.core.Fraction import ru.dbotthepony.mc.otm.core.ImpreciseFraction import ru.dbotthepony.mc.otm.graph.Graph6Node import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph import ru.dbotthepony.mc.otm.ifHas -import ru.dbotthepony.mc.otm.matter.MatterRegistry +import ru.dbotthepony.mc.otm.matter.baselineComplexityReplicateTicks +import ru.dbotthepony.mc.otm.matter.getMatterValue import ru.dbotthepony.mc.otm.menu.MatterReplicatorMenu import ru.dbotthepony.mc.otm.set import javax.annotation.ParametersAreNonnullByDefault @@ -105,20 +105,25 @@ class BlockEntityMatterReplicator(p_155229_: BlockPos, p_155230_: BlockState) : val graph = node.graph as MatterNetworkGraph? ?: return null val allocation = graph.allocateTask(false) ?: return null val stack = allocation.task().stack(1) + val matter = getMatterValue(stack) // ???????? - if (!MatterRegistry.hasMatterValue(stack)) return null - val job = MachineJob(stack, MatterRegistry.getMatterValue(stack).toDouble() * TICKS_PER_MTU, BASE_CONSUMPTION) + if (matter.isZero) return null - job.data["task"] = allocation.task.serializeNBT() - if (allocation.pattern != null) job.data["pattern"] = allocation.pattern!!.serializeNBT() + val ticks = matter.complexity * baselineComplexityReplicateTicks - return job + return MachineJob(stack, ticks, BASE_CONSUMPTION, CompoundTag().also { + it["matter_per_tick"] = (matter.value / ticks).serializeNBT() + it["task"] = allocation.task.serializeNBT() + + if (allocation.pattern != null) + it["pattern"] = allocation.pattern!!.serializeNBT() + }) } override fun onWorkTick(context: WorkTickContext): MachineJobStatus { - val drainPerTick = MTU_PER_TICK_BD.times(context.workSpeed()) - val graph = node.graph as? MatterNetworkGraph ?: return MachineJobStatus(false, 20) + val drainPerTick = ImpreciseFraction.deserializeNBT(context.job.data["matter_per_tick"]) + val graph = node.graph as MatterNetworkGraph? ?: return MachineJobStatus(false, 20) if (matter.extractMatterInner(drainPerTick, true) < drainPerTick) { // в машине недостаточно материи @@ -219,10 +224,6 @@ class BlockEntityMatterReplicator(p_155229_: BlockPos, p_155230_: BlockState) : companion object { private val NAME = TranslatableComponent("block.overdrive_that_matters.matter_replicator") private val BASE_CONSUMPTION = ImpreciseFraction(400) - private const val TICKS_PER_MTU = 20000.0 - private val TICKS_PER_MTU_BD = ImpreciseFraction(20000) - private const val MTU_PER_TICK = 1.0 / 20000.0 - private val MTU_PER_TICK_BD = ImpreciseFraction.ONE.div(TICKS_PER_MTU_BD) private val DRAIN_MULT = ImpreciseFraction(200) } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatterScanner.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatterScanner.kt index 249ec842f..ee17b4972 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatterScanner.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatterScanner.kt @@ -24,12 +24,11 @@ import ru.dbotthepony.mc.otm.capability.MatteryMachineEnergyStorage import ru.dbotthepony.mc.otm.capability.matter.PatternInsertStatus import ru.dbotthepony.mc.otm.capability.matter.PatternState import ru.dbotthepony.mc.otm.container.MatteryContainer -import ru.dbotthepony.mc.otm.core.Fraction import ru.dbotthepony.mc.otm.core.ImpreciseFraction import ru.dbotthepony.mc.otm.graph.Graph6Node import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph -import ru.dbotthepony.mc.otm.matter.MatterRegistry +import ru.dbotthepony.mc.otm.matter.* import ru.dbotthepony.mc.otm.menu.MenuMatterScanner import java.util.* @@ -39,8 +38,8 @@ class BlockEntityMatterScanner(p_155229_: BlockPos, p_155230_: BlockState) : val input_slot = MatteryContainer(this::setChanged, 1) private val inputHandler = input_slot.handler( - { slot: Int, stack: ItemStack? -> MatterRegistry.canDecompose(stack) }, - { slot: Int, amount: Int, stack: ItemStack? -> isIdling } + { _: Int, stack: ItemStack -> canDecompose(stack) }, + { _: Int, _: Int, _: ItemStack -> isIdling } ) // IMatterGraphNode @@ -117,29 +116,29 @@ class BlockEntityMatterScanner(p_155229_: BlockPos, p_155230_: BlockState) : val grid = matterNode.graph as MatterNetworkGraph? ?: return MachineJobStatus(false, 100) val stack = job.stack() - if (stack.isEmpty || !MatterRegistry.hasMatterValue(stack)) return MachineJobStatus() + if (stack.isEmpty || !hasMatterValue(stack)) return MachineJobStatus() - val get_state = grid.findPatterns(stack.item) - var find_state: PatternState? = null + val getState = grid.findPatterns(stack.item) + var findState: PatternState? = null - for (state in get_state) { + for (state in getState) { if (state.item() === stack.item) { - if (find_state == null && state.research_percent() < 1.0) { - find_state = state - } else if (find_state != null && find_state.research_percent() < state.research_percent()) { - find_state = state + if (findState == null && state.research_percent() < 1.0) { + findState = state + } else if (findState != null && findState.research_percent() < state.research_percent()) { + findState = state } } } val new_state = - if (find_state != null) { - PatternState(find_state.id(), stack.item, find_state.research_percent() + 0.2) + if (findState != null) { + PatternState(findState.id(), stack.item, findState.research_percent() + 0.2) } else { PatternState(UUID.randomUUID(), stack.item, 0.2) } - if (grid.insertPattern(new_state, false, false).status != PatternInsertStatus.Status.FAIL) { + if (grid.insertPattern(new_state, onlyUpdate = false, simulate = false).status != PatternInsertStatus.Status.FAIL) { return MachineJobStatus() } else { return MachineJobStatus(false, 200) @@ -150,7 +149,7 @@ class BlockEntityMatterScanner(p_155229_: BlockPos, p_155230_: BlockState) : val grid = matterNode.graph as MatterNetworkGraph? ?: return null val stack = input_slot.getItem(0) - if (stack.isEmpty || !MatterRegistry.canDecompose(stack)) return null + if (stack.isEmpty || !canDecompose(stack)) return null val getState = grid.findPatterns(stack.item) var findState: PatternState? = null @@ -175,7 +174,7 @@ class BlockEntityMatterScanner(p_155229_: BlockPos, p_155230_: BlockState) : copy.count = 1 stack.shrink(1) input_slot.setChanged() - return MachineJob(copy, MatterRegistry.getMatterValue(copy).toDouble() * 35000.0, BASE_CONSUMPTION) + return MachineJob(copy, getMatterValue(copy).complexity * baselineComplexityScanTicks, BASE_CONSUMPTION) } return null diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/blackhole/BlockEntityBlackHole.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/blackhole/BlockEntityBlackHole.kt index 222e332a3..38d064266 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/blackhole/BlockEntityBlackHole.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/blackhole/BlockEntityBlackHole.kt @@ -25,10 +25,9 @@ import ru.dbotthepony.mc.otm.Registry import ru.dbotthepony.mc.otm.block.BlockBlackHole import ru.dbotthepony.mc.otm.block.entity.BlockEntityGravitationStabilizer import ru.dbotthepony.mc.otm.block.entity.blackhole.ExplosionQueue.Companion.queueForLevel -import ru.dbotthepony.mc.otm.core.Fraction import ru.dbotthepony.mc.otm.core.ImpreciseFraction import ru.dbotthepony.mc.otm.core.plus -import ru.dbotthepony.mc.otm.matter.MatterRegistry +import ru.dbotthepony.mc.otm.matter.getMatterValue import ru.dbotthepony.mc.otm.set import kotlin.math.roundToInt import kotlin.math.sqrt @@ -279,10 +278,10 @@ class BlockEntityBlackHole(p_155229_: BlockPos, p_155230_: BlockState) : BlockEn if (item.item.item === Registry.Items.GRAVITATIONAL_DISRUPTOR) { collapse() } else { - val mass = MatterRegistry.getMatterValue(item.item) + val mass = getMatterValue(item.item) - if (mass > ImpreciseFraction.ZERO) - this.mass += mass * item.item.count + if (!mass.isZero) + this.mass += mass.value * item.item.count } } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/ImpreciseFraction.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/ImpreciseFraction.kt index 5d65c2f50..3e90ac153 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/ImpreciseFraction.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/ImpreciseFraction.kt @@ -10,7 +10,8 @@ import java.math.MathContext import java.nio.ByteBuffer import kotlin.math.absoluteValue -private fun isZero(value: BigInteger) = value == BigInteger.ZERO +//private fun isZero(value: BigInteger) = value == BigInteger.ZERO +private fun isZero(value: BigInteger) = value.signum() == 0 private fun unsignedInt(value: Byte): Int { return value.toInt() and 0xFF @@ -162,15 +163,27 @@ class ImpreciseFraction @JvmOverloads constructor(whole: BigInteger, decimal: Do if (bZero && dZero) { if (isZero(a) || isZero(c)) - return this + return ZERO return ImpreciseFraction(a * c) + } else if (isZero(a) && isZero(c)) { + if (bZero || dZero) + return ZERO + + return ImpreciseFraction(0, decimal * other.decimal) } else if (bZero) { val d = other.decimal * MEANINGFUL_BITS_DOUBLE val dL = d.toLong() val adInflated = a * BigInteger.valueOf(dL) val ad = adInflated.divideAndRemainder(MEANINGFUL_BITS_BI) + if (isZero(c)) { + return ImpreciseFraction( + ad[0], + ad[1].toDouble() / MEANINGFUL_BITS_DOUBLE + ) + } + return ImpreciseFraction( a * c + ad[0], ad[1].toDouble() / MEANINGFUL_BITS_DOUBLE @@ -181,9 +194,16 @@ class ImpreciseFraction @JvmOverloads constructor(whole: BigInteger, decimal: Do val bcInflated = c * BigInteger.valueOf(bL) val bc = bcInflated.divideAndRemainder(MEANINGFUL_BITS_BI) + if (isZero(a)) { + return ImpreciseFraction( + bc[0], + bc[1].toDouble() / MEANINGFUL_BITS_DOUBLE + ) + } + return ImpreciseFraction( a * c + bc[0], - bc[1].toDouble() / b + bc[1].toDouble() / MEANINGFUL_BITS_DOUBLE ) } @@ -209,8 +229,11 @@ class ImpreciseFraction @JvmOverloads constructor(whole: BigInteger, decimal: Do if (isZero && other.isZero) return this - if (isZero(whole) && isZero(other.whole)) - return ImpreciseFraction(BigInteger.ZERO, decimal / other.decimal) + if (!isZero && other.isZero) + throw ArithmeticException("Divide by zero") + + //if (isZero(whole) && isZero(other.whole)) + // return ImpreciseFraction(BigInteger.ZERO, decimal / other.decimal) val a = toBigDecmial() val b = other.toBigDecmial() @@ -218,7 +241,7 @@ class ImpreciseFraction @JvmOverloads constructor(whole: BigInteger, decimal: Do val bD = b.toDouble() - if (bD.isInfinite()) { + if (bD.isInfinite() || bD == 0.0 || bD == -0.0) { return ImpreciseFraction(div[0].toBigInteger()) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/matter/MatterData.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/matter/MatterData.kt new file mode 100644 index 000000000..8351efcdb --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/matter/MatterData.kt @@ -0,0 +1,499 @@ +package ru.dbotthepony.mc.otm.matter + +import net.minecraft.tags.ItemTags +import net.minecraft.tags.Tag +import net.minecraft.world.item.Item +import net.minecraft.world.item.Items +import net.minecraft.world.item.crafting.Recipe +import net.minecraft.world.item.crafting.RecipeType +import net.minecraftforge.event.server.ServerStartedEvent +import net.minecraftforge.eventbus.api.SubscribeEvent +import org.apache.logging.log4j.LogManager +import ru.dbotthepony.mc.otm.Registry +import ru.dbotthepony.mc.otm.core.ImpreciseFraction + +/** + * baselineComplexityReplicateTicks * complexity = replicate ticks + * baselineComplexityDecomposeTicks * complexity = decompose ticks + */ +const val baselineComplexityReplicateTicks = 2000.0 +const val baselineComplexityDecomposeTicks = 400.0 +const val baselineComplexityScanTicks = 12000.0 + +@JvmField val BASELINE = ImpreciseFraction(0.001) +@JvmField val DIRT = BASELINE +@JvmField val STONY = BASELINE * 0.92 + +@JvmField val IRON = BASELINE * 60 +@JvmField val COPPER = BASELINE * 36 +@JvmField val GOLD = IRON * 2.5 +@JvmField val LAPIS = IRON * 1.15 +@JvmField val REDSTONE = IRON * 1.4 +@JvmField val DIAMOND = GOLD * 4 +@JvmField val EMERALD = DIAMOND +@JvmField val QUARTZ = IRON * 0.97 +@JvmField val COAL = DIAMOND * 0.08 +@JvmField val TRITANIUM = IRON * 1.95 + +@JvmField val WATER = BASELINE * 0.3 + +@JvmField val AMETHYST = EMERALD * 0.44 + +@JvmField val NETHER_STAR = ImpreciseFraction(40) + +@JvmField val MUSIC_DISC = BASELINE * 200 + +@JvmField val SOUL_SAND = BASELINE * 6.66666666 +@JvmField val GLOWSTONE_DUST = GOLD * 0.44 + REDSTONE * 0.7 + +@JvmField val SEEDS = BASELINE * 1.8 +@JvmField val PLANTS = BASELINE * 4.6 +@JvmField val GRASS = PLANTS * 0.65 + +@JvmField val SIMPLE_ORGANICS = BASELINE * 9 +@JvmField val STRINGS = SIMPLE_ORGANICS * 0.8 +@JvmField val FEATHERS = SIMPLE_ORGANICS * 1.2 +@JvmField val BONES = SIMPLE_ORGANICS * 1.8 + +@JvmField val ADVANCED_ORGANICS = SIMPLE_ORGANICS * 4.2 + +@JvmField val PRISMARINE = IRON * 0.44 + +@JvmField val LOGS = BASELINE * 4 +@JvmField val STRIPPED_LOGS = LOGS * 0.91 +@JvmField val PLANKS = LOGS * 6 + +// трава? +@JvmField val CORALS = ADVANCED_ORGANICS * 0.83 +@JvmField val DEAD_CORALS = CORALS * 0.91 + +private val seenItems = ArrayDeque() +private val seenRecipes = ArrayDeque>() +private val LOGGER = LogManager.getLogger() +private val mappedOutputs = HashMap>>() +private val mappedInputs = HashMap>>() + +private fun defaultComplexity(value: ImpreciseFraction): Double { + return value.toDouble() +} + +private fun make(item: Item, value: ImpreciseFraction, complexity: Double = defaultComplexity(value)) { + rootEntriesAccess[item] = MatterTuple(value, complexity) +} + +private fun derive(from: Item, to: Item, multValue: ImpreciseFraction = ImpreciseFraction.ONE, multComplexity: Double = 1.0) { + val getValue = getMatterValueNullable(from) + + if (getValue != null) { + derivedEntriesAccess[to] = MatterTuple(getValue.value * multValue, getValue.complexity * multComplexity) + } +} + +private fun derive(from: Item, to: Item, multValue: Double, multComplexity: Double = 1.0) = derive(from, to, ImpreciseFraction(multValue), multComplexity) + +private fun deriveIfMissing(from: Item, to: Item, multValue: ImpreciseFraction = ImpreciseFraction.ONE, multComplexity: Double = 1.0) { + if (getMatterValueNullable(to) != null) + return + + val getValue = getMatterValueNullable(from) + + if (getValue != null) { + derivedEntriesAccess[to] = MatterTuple(getValue.value * multValue, getValue.complexity * multComplexity) + } +} + +private fun deriveIfMissing(from: Item, to: Item, multValue: Double, multComplexity: Double = 1.0) = deriveIfMissing(from, to, ImpreciseFraction(multValue), multComplexity) + +private fun make(tag: Tag, value: ImpreciseFraction, complexity: Double = defaultComplexity(value)) { + for (item in tag.values) { + make(item, value, complexity) + } +} + +private fun logResolutionError(text: String) { + LOGGER.error("... Item chain: " + seenItems.joinToString(" -> ")) + // LOGGER.error("Recipe chain: " + seenRecipes.joinToString(" -> ")) + LOGGER.error(text) +} + +private enum class ResultType { + RESOLVED, + RECURSION, + UNKNOWN_VALUE +} + +private data class Result(val type: ResultType = ResultType.UNKNOWN_VALUE, val tuple: MatterTuple? = null) + +@SubscribeEvent +@Suppress("unused") +fun serverStartData(event: ServerStartedEvent) { + rootEntriesAccess.clear() + derivedEntriesAccess.clear() + mappedOutputs.clear() + mappedInputs.clear() + + building = true + registerRoots() + + floodRecipeCategory(event.server.recipeManager.getAllRecipesFor(RecipeType.SMELTING)) + floodRecipeCategory(event.server.recipeManager.getAllRecipesFor(RecipeType.BLASTING)) + floodRecipeCategory(event.server.recipeManager.getAllRecipesFor(RecipeType.SMOKING)) + floodRecipeCategory(event.server.recipeManager.getAllRecipesFor(RecipeType.STONECUTTING)) + floodRecipeCategory(event.server.recipeManager.getAllRecipesFor(Registry.Recipes.PLATE_PRESS)) + floodRecipeCategory(event.server.recipeManager.getAllRecipesFor(RecipeType.CRAFTING)) + + for (item in mappedInputs.keys) { + determineMatterValue(item) + } + + for (item in mappedOutputs.keys) { + determineMatterValue(item) + } + + registerDerived() + building = false +} + +private fun floodRecipeCategory(list: Collection>) { + for (recipe in list) { + val result = recipe.resultItem + + if (!result.isEmpty) { + mappedOutputs.computeIfAbsent(result.item) {ArrayList()}.add(recipe) + + for (inputI in recipe.ingredients) { + for (stack in inputI.items) { + if (!stack.isEmpty) { + mappedInputs.computeIfAbsent(stack.item) {ArrayList()}.add(recipe) + } + } + } + } + } +} + +private fun determineMatterValue(item: Item): Result { + val rootEntry = getMatterValueNullable(item) + + if (rootEntry != null) + return Result(ResultType.RESOLVED, rootEntry) + + val recipes = mappedOutputs[item] ?: return Result(ResultType.UNKNOWN_VALUE) + + if (seenItems.contains(item)) { + // logResolutionError("Already seen this item: $item") + return Result(ResultType.RECURSION) + } + + seenItems.addLast(item) + var minimal: MatterTuple? = null + var anyRecursion = false + + for (recipe in recipes) { + if (seenRecipes.contains(recipe)) { + logResolutionError("Already seen this recipe: $recipe") + continue + } + + seenRecipes.addLast(recipe) + var sum = MatterTuple.ZERO + var recursiveRecipe = false + var once = false + + for (ingredient in recipe.ingredients) { + var minIngredient: MatterTuple? = null + var recursive = false + + for (stack in ingredient.items) { + val getStackTuple = determineMatterValue(stack.item) + + if (getStackTuple.type == ResultType.UNKNOWN_VALUE) { + logResolutionError("Failed to resolve $item value because ${stack.item} is unknown") + seenItems.removeLast() + seenRecipes.removeLast() + return getStackTuple + } else if (getStackTuple.type == ResultType.RESOLVED) { + if (minIngredient == null || minIngredient > getStackTuple.tuple!!) + minIngredient = getStackTuple.tuple + } else { + recursive = true + } + } + + //if (minIngredient == null) { + // if (recursive) { + // recursiveRecipe = true + // break + // } + + // logResolutionError("Failed to resolve $item value because $ingredient is empty (${ingredient.items.joinToString(", ")})???") + // seenItems.removeLast() + // seenRecipes.removeLast() + // return Result(ResultType.UNKNOWN_VALUE) + //} + + if (recursive) { + recursiveRecipe = true + } + + if (minIngredient != null) { + sum += minIngredient + once = true + } + } + + seenRecipes.removeLast() + + if (recursiveRecipe) { + anyRecursion = true + // logResolutionError("$recipe is anything but recursion?") + // continue + } + + if (!once) { + if (recursiveRecipe) { + //logResolutionError("Escaping resolution of $item early because $recipe is recursive") + //seenItems.removeLast() + //return Result(ResultType.RECURSION) + continue + } + + logResolutionError("Failed to resolve $item because $recipe is unresolvable") + seenItems.removeLast() + return Result(ResultType.UNKNOWN_VALUE) + } + + sum = MatterTuple(sum.value / recipe.resultItem.count, sum.complexity / recipe.resultItem.count) + + if (minimal == null || minimal > sum) { + minimal = sum + } + } + + seenItems.removeLast() + + if (minimal != null) { + derivedEntriesAccess[item] = minimal + return Result(ResultType.RESOLVED, minimal) + } + + if (anyRecursion) { + logResolutionError("Failed to resolve $item because hit recursive recipes") + return Result(ResultType.RECURSION) + } + + logResolutionError("Failed to resolve $item because no appropriate recipes were found") + return Result() +} + +private fun registerRoots() { + make(Items.STONE, STONY) + make(Items.COBBLESTONE, STONY) + make(Items.GRAVEL, STONY) + make(Items.TUFF, STONY * 1.17) + make(Items.CALCITE, STONY * 1.17) + make(Items.SAND, STONY) + make(Items.RED_SAND, STONY) + make(Items.FLINT, STONY) + make(Items.NETHERRACK, STONY * 0.7) + make(Items.SOUL_SAND, SOUL_SAND) + make(Items.SOUL_SOIL, SOUL_SAND) + make(Items.DEEPSLATE, STONY * 1.15) + make(Items.COBBLED_DEEPSLATE, STONY * 1.15) + make(Items.BLACKSTONE, STONY * 1.21) + make(Items.OBSIDIAN, STONY * 3.5) + + make(Items.INFESTED_COBBLESTONE, STONY + ADVANCED_ORGANICS * 3.6) + make(Items.MOSSY_COBBLESTONE, STONY + GRASS * 0.6) + + make(Items.SNOWBALL, WATER / 4) + + make(ItemTags.PLANKS, PLANKS) + + make(ItemTags.LOGS, LOGS) + + make(ItemTags.SAPLINGS, PLANTS * 2.6) + + make(Items.STRIPPED_OAK_LOG, STRIPPED_LOGS) + make(Items.STRIPPED_SPRUCE_LOG, STRIPPED_LOGS) + make(Items.STRIPPED_BIRCH_LOG, STRIPPED_LOGS) + make(Items.STRIPPED_JUNGLE_LOG, STRIPPED_LOGS) + make(Items.STRIPPED_ACACIA_LOG, STRIPPED_LOGS) + make(Items.STRIPPED_DARK_OAK_LOG, STRIPPED_LOGS) + make(Items.STRIPPED_CRIMSON_STEM, STRIPPED_LOGS) + make(Items.STRIPPED_WARPED_STEM, STRIPPED_LOGS) + make(Items.STRIPPED_OAK_WOOD, STRIPPED_LOGS) + make(Items.STRIPPED_SPRUCE_WOOD, STRIPPED_LOGS) + make(Items.STRIPPED_BIRCH_WOOD, STRIPPED_LOGS) + make(Items.STRIPPED_JUNGLE_WOOD, STRIPPED_LOGS) + make(Items.STRIPPED_ACACIA_WOOD, STRIPPED_LOGS) + make(Items.STRIPPED_DARK_OAK_WOOD, STRIPPED_LOGS) + make(Items.STRIPPED_CRIMSON_HYPHAE, STRIPPED_LOGS) + make(Items.STRIPPED_WARPED_HYPHAE, STRIPPED_LOGS) + + make(Items.DIRT, DIRT) + make(Items.DIRT_PATH, DIRT) + make(Items.GRASS_BLOCK, DIRT * 1.1) + make(Items.PODZOL, DIRT * 1.15) + + make(Items.COAL, COAL) + make(Items.QUARTZ, QUARTZ) + make(Items.AMETHYST_SHARD, AMETHYST) + make(Items.DIAMOND, DIAMOND) + make(Items.IRON_INGOT, IRON) + make(Registry.Items.TRITANIUM_INGOT, TRITANIUM) + make(Items.COPPER_INGOT, COPPER) + make(Items.LAPIS_LAZULI, LAPIS) + make(Items.REDSTONE, REDSTONE) + make(Items.GOLD_INGOT, GOLD) + make(Items.EMERALD, EMERALD) + make(Items.NETHER_STAR, NETHER_STAR) + make(Items.GLOWSTONE_DUST, GLOWSTONE_DUST) + + make(Items.GUNPOWDER, BASELINE * 2.4) + make(Items.CLAY_BALL, BASELINE * 1.9) + make(Items.PRISMARINE_CRYSTALS, PRISMARINE * 1.3) + make(Items.PRISMARINE_SHARD, PRISMARINE) + + make(Items.WHEAT, PLANTS) + make(Items.BEETROOT, PLANTS * 1.1) + make(Items.NETHER_WART, PLANTS * 2.4) + make(Items.WHEAT_SEEDS, SEEDS) + make(Items.MELON_SEEDS, SEEDS * 1.1) + make(Items.PUMPKIN_SEEDS, SEEDS * 0.9) + make(Items.BEETROOT_SEEDS, SEEDS * 1.26) + make(Items.SUGAR, PLANTS * 0.75) + make(Items.SUGAR_CANE, PLANTS * 1.55) + make(Items.BAMBOO, PLANTS * 1.45) + make(Items.CACTUS, PLANTS * 1.8) + make(Items.VINE, PLANTS * 0.9) + make(Items.GLOW_LICHEN, PLANTS * 1.35) + make(Items.LILY_PAD, PLANTS) + make(Items.SPORE_BLOSSOM, PLANTS * 1.4) + make(Items.CHORUS_FRUIT, PLANTS * 1.55) + make(Items.CHORUS_PLANT, PLANTS * 1.55) + make(Items.CHORUS_FLOWER, PLANTS * 1.55) + + make(Items.SUNFLOWER, PLANTS * 1.5) + make(Items.LILAC, PLANTS * 1.5) + make(Items.ROSE_BUSH, PLANTS * 1.5) + make(Items.PEONY, PLANTS * 1.5) + make(Items.DANDELION, PLANTS * 1.24) + make(Items.POPPY, PLANTS * 1.24) + make(Items.BLUE_ORCHID, PLANTS * 1.24) + make(Items.ALLIUM, PLANTS * 1.24) + make(Items.AZURE_BLUET, PLANTS * 1.24) + make(Items.RED_TULIP, PLANTS * 1.24) + make(Items.ORANGE_TULIP, PLANTS * 1.24) + make(Items.WHITE_TULIP, PLANTS * 1.24) + make(Items.PINK_TULIP, PLANTS * 1.24) + make(Items.OXEYE_DAISY, PLANTS * 1.24) + make(Items.CORNFLOWER, PLANTS * 1.24) + make(Items.LILY_OF_THE_VALLEY, PLANTS * 1.24) + + make(Items.WITHER_ROSE, PLANTS * 2.35) + + make(Items.BROWN_MUSHROOM, PLANTS) + make(Items.RED_MUSHROOM, PLANTS) + make(Items.COCOA_BEANS, PLANTS * 1.4) + make(Items.CRIMSON_FUNGUS, PLANTS * 1.161) + make(Items.WARPED_FUNGUS, PLANTS * 1.161) + make(Items.CRIMSON_ROOTS, GRASS * 1.161) + make(Items.WARPED_ROOTS, GRASS * 1.161) + make(Items.NETHER_SPROUTS, GRASS * 0.8) + make(Items.WEEPING_VINES, GRASS * 1.161) + make(Items.TWISTING_VINES, GRASS * 1.261) + make(Items.DEAD_BUSH, GRASS * 0.64) + + make(Items.TALL_GRASS, GRASS * 1.7) + make(Items.GRASS, GRASS) + make(Items.FERN, GRASS * 1.02) + make(Items.LARGE_FERN, GRASS * 1.91) + make(Items.SEAGRASS, GRASS * 0.94) + + make(Items.KELP, PLANTS * 0.94) + make(Items.MOSS_BLOCK, PLANTS * 1.4) + make(Items.HANGING_ROOTS, PLANTS * 0.8) + make(Items.BIG_DRIPLEAF, PLANTS * 1.15) + make(Items.SMALL_DRIPLEAF, PLANTS * 1.1) + make(Items.AZALEA, PLANTS * 1.3) + make(Items.FLOWERING_AZALEA, PLANTS * 1.4) + make(Items.FLOWERING_AZALEA_LEAVES, PLANTS * 1.5) + + make(Items.BONE, BONES) + make(Items.STRING, STRINGS) + make(Items.FEATHER, FEATHERS) + + make(Items.PORKCHOP, ADVANCED_ORGANICS * 0.65) + make(Items.BEEF, ADVANCED_ORGANICS * 0.65) + make(Items.LEATHER, ADVANCED_ORGANICS * 0.7) + make(Items.EGG, ADVANCED_ORGANICS * 0.75) + make(Items.HONEYCOMB, ADVANCED_ORGANICS * 1.15) + make(Items.BLAZE_ROD, ADVANCED_ORGANICS * 2.3) + make(Items.ENDER_PEARL, ADVANCED_ORGANICS * 6.5) + + make(Items.SLIME_BALL, SIMPLE_ORGANICS * 1.7) + make(Items.INK_SAC, SIMPLE_ORGANICS * 1.4) + make(Items.GLOW_INK_SAC, SIMPLE_ORGANICS * 2.1) + make(Items.NAUTILUS_SHELL, SIMPLE_ORGANICS * 2.3) + make(Items.HEART_OF_THE_SEA, SIMPLE_ORGANICS * 4) + + make(Items.MUSIC_DISC_13, MUSIC_DISC) + make(Items.MUSIC_DISC_CAT, MUSIC_DISC) + make(Items.MUSIC_DISC_BLOCKS, MUSIC_DISC) + make(Items.MUSIC_DISC_CHIRP, MUSIC_DISC) + make(Items.MUSIC_DISC_FAR, MUSIC_DISC) + make(Items.MUSIC_DISC_MALL, MUSIC_DISC) + make(Items.MUSIC_DISC_MELLOHI, MUSIC_DISC) + make(Items.MUSIC_DISC_STAL, MUSIC_DISC) + make(Items.MUSIC_DISC_STRAD, MUSIC_DISC) + make(Items.MUSIC_DISC_WARD, MUSIC_DISC) + make(Items.MUSIC_DISC_11, MUSIC_DISC) + make(Items.MUSIC_DISC_WAIT, MUSIC_DISC) + make(Items.MUSIC_DISC_OTHERSIDE, MUSIC_DISC) + make(Items.MUSIC_DISC_PIGSTEP, MUSIC_DISC) + + make(Items.TUBE_CORAL, CORALS) + make(Items.BRAIN_CORAL, CORALS) + make(Items.BUBBLE_CORAL, CORALS) + make(Items.FIRE_CORAL, CORALS) + make(Items.HORN_CORAL, CORALS) + + make(Items.SEA_PICKLE, CORALS * 1.27) + + make(Items.DEAD_BRAIN_CORAL, DEAD_CORALS) + make(Items.DEAD_BUBBLE_CORAL, DEAD_CORALS) + make(Items.DEAD_FIRE_CORAL, DEAD_CORALS) + make(Items.DEAD_HORN_CORAL, DEAD_CORALS) + make(Items.DEAD_TUBE_CORAL, DEAD_CORALS) + + derive(Items.IRON_INGOT, Items.IRON_NUGGET, 1.0 / 9.0, 1.0 / 9.0) + derive(Items.GOLD_INGOT, Items.GOLD_NUGGET, 1.0 / 9.0, 1.0 / 9.0) +} + +private fun registerDerived() { + deriveIfMissing(Items.BROWN_MUSHROOM, Items.BROWN_MUSHROOM_BLOCK) + deriveIfMissing(Items.RED_MUSHROOM, Items.RED_MUSHROOM_BLOCK) + deriveIfMissing(Items.COBWEB, Items.STRING) + deriveIfMissing(Items.FARMLAND, Items.DIRT) + + derive(Items.ANVIL, Items.CHIPPED_ANVIL, 0.75, 0.85) + derive(Items.ANVIL, Items.DAMAGED_ANVIL, 0.6, 0.78) + + derive(Items.WHITE_CONCRETE_POWDER, Items.WHITE_CONCRETE) + derive(Items.ORANGE_CONCRETE_POWDER, Items.ORANGE_CONCRETE) + derive(Items.MAGENTA_CONCRETE_POWDER, Items.MAGENTA_CONCRETE) + derive(Items.LIGHT_BLUE_CONCRETE_POWDER, Items.LIGHT_BLUE_CONCRETE) + derive(Items.YELLOW_CONCRETE_POWDER, Items.YELLOW_CONCRETE) + derive(Items.LIME_CONCRETE_POWDER, Items.LIME_CONCRETE) + derive(Items.PINK_CONCRETE_POWDER, Items.PINK_CONCRETE) + derive(Items.GRAY_CONCRETE_POWDER, Items.GRAY_CONCRETE) + derive(Items.LIGHT_GRAY_CONCRETE_POWDER, Items.LIGHT_GRAY_CONCRETE) + derive(Items.CYAN_CONCRETE_POWDER, Items.CYAN_CONCRETE) + derive(Items.PURPLE_CONCRETE_POWDER, Items.PURPLE_CONCRETE) + derive(Items.BLUE_CONCRETE_POWDER, Items.BLUE_CONCRETE) + derive(Items.BROWN_CONCRETE_POWDER, Items.BROWN_CONCRETE) + derive(Items.GREEN_CONCRETE_POWDER, Items.GREEN_CONCRETE) + derive(Items.RED_CONCRETE_POWDER, Items.RED_CONCRETE) + derive(Items.BLACK_CONCRETE_POWDER, Items.BLACK_CONCRETE) +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/matter/MatterRegistry.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/matter/MatterRegistry.kt new file mode 100644 index 000000000..3a9d1e2b8 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/matter/MatterRegistry.kt @@ -0,0 +1,416 @@ +package ru.dbotthepony.mc.otm.matter + +import com.mojang.blaze3d.platform.InputConstants +import net.minecraft.ChatFormatting +import net.minecraft.client.Minecraft +import net.minecraft.network.FriendlyByteBuf +import net.minecraft.network.chat.TranslatableComponent +import net.minecraft.server.dedicated.DedicatedServer +import net.minecraft.world.item.Item +import net.minecraft.world.item.ItemStack +import net.minecraftforge.event.entity.player.ItemTooltipEvent +import net.minecraftforge.event.entity.player.PlayerEvent +import net.minecraftforge.event.server.ServerStartedEvent +import net.minecraftforge.event.server.ServerStoppingEvent +import net.minecraftforge.eventbus.api.SubscribeEvent +import net.minecraftforge.network.NetworkEvent +import net.minecraftforge.network.PacketDistributor +import org.lwjgl.glfw.GLFW +import ru.dbotthepony.mc.otm.capability.MatteryCapability +import ru.dbotthepony.mc.otm.capability.drive.IMatteryDrive +import ru.dbotthepony.mc.otm.core.ImpreciseFraction +import ru.dbotthepony.mc.otm.core.readImpreciseFraction +import ru.dbotthepony.mc.otm.core.writeImpreciseFraction +import ru.dbotthepony.mc.otm.menu.FormattingHelper +import ru.dbotthepony.mc.otm.network.MatteryNetworking +import ru.dbotthepony.mc.otm.orNull +import ru.dbotthepony.mc.otm.storage.ItemStackWrapper +import java.util.function.Supplier + +internal var building = false + +interface MatterTuplePredicate { + fun accept(item: Item): MatterTuple? +} + +private val rootEntries = HashMap() +private val derivedEntries = HashMap() + +/** + * Nothing prevents you from writing to this map. + * This derived class is designed solely to network YOUR changes to players online in real-time. + * + * If you use MapEntry#setValue, it is your fault this map go out of sync with clients. + */ +@JvmField +val rootEntriesAccess = object : MutableMap by rootEntries { + override fun put(key: Item, value: MatterTuple): MatterTuple? { + MatteryNetworking.CHANNEL.send(PacketDistributor.ALL.noArg(), RegistryPacketUpdate(MatterRegistryType.ROOT, key, value)) + return rootEntries.put(key, value) + } + + override fun putAll(from: Map) { + rootEntries.putAll(from) + + if (!building) { + val distr = PacketDistributor.ALL.noArg() + + for ((key, value) in from) { + MatteryNetworking.CHANNEL.send(distr, RegistryPacketUpdate(MatterRegistryType.ROOT, key, value)) + } + } + } + + override fun remove(key: Item): MatterTuple? { + val value = rootEntries.remove(key) + + if (!building && value != null) + MatteryNetworking.CHANNEL.send(PacketDistributor.ALL.noArg(), RegistryPacketRemove(MatterRegistryType.ROOT, key)) + + return value + } + + override fun clear() { + rootEntries.clear() + + if (!building && server != null) { + MatteryNetworking.CHANNEL.send(PacketDistributor.ALL.noArg(), RegistryPacketClear.ROOT) + } + } +} + +/** + * Nothing prevents you from writing to this map. + * This derived class is designed solely to network YOUR changes to players online in real-time. + * + * If you use MapEntry#setValue, it is your fault this map go out of sync with clients. + */ +@JvmField +val derivedEntriesAccess = object : MutableMap by derivedEntries { + override fun put(key: Item, value: MatterTuple): MatterTuple? { + MatteryNetworking.CHANNEL.send(PacketDistributor.ALL.noArg(), RegistryPacketUpdate(MatterRegistryType.DERIVED, key, value)) + return derivedEntries.put(key, value) + } + + override fun putAll(from: Map) { + derivedEntries.putAll(from) + + if (!building) { + val distr = PacketDistributor.ALL.noArg() + + for ((key, value) in from) { + MatteryNetworking.CHANNEL.send(distr, RegistryPacketUpdate(MatterRegistryType.DERIVED, key, value)) + } + } + } + + override fun remove(key: Item): MatterTuple? { + val value = derivedEntries.remove(key) + + if (!building && value != null) + MatteryNetworking.CHANNEL.send(PacketDistributor.ALL.noArg(), RegistryPacketRemove(MatterRegistryType.DERIVED, key)) + + return value + } + + override fun clear() { + derivedEntries.clear() + + if (!building && server != null) { + MatteryNetworking.CHANNEL.send(PacketDistributor.ALL.noArg(), RegistryPacketClear.DERIVED) + } + } +} + +fun getMatterValue(item: Item): MatterTuple { + return rootEntries[item] ?: derivedEntries[item] ?: MatterTuple.ZERO +} + +fun getMatterValueNullable(item: Item): MatterTuple? { + return rootEntries[item] ?: derivedEntries[item] +} + +fun hasMatterValue(item: Item): Boolean { + return !getMatterValue(item).isZero +} + +fun hasMatterValue(stack: ItemStack): Boolean { + return !getMatterValue(stack).isZero +} + +fun canDecompose(item: Item): Boolean { + return hasMatterValue(item) +} + +fun canDecompose(stack: ItemStack): Boolean { + return canDecompose(stack.item) && + (stack.getCapability(MatteryCapability.MATTER).orNull()?.storedMatter ?: ImpreciseFraction.ZERO).isZero && + (stack.getCapability(MatteryCapability.DRIVE).orNull()?.storedCount ?: ImpreciseFraction.ZERO).isZero +} + +private const val MAX_NESTING = 100 + +private fun getMatterValue(stack: ItemStack, level: Int): MatterTuple { + if (level >= MAX_NESTING) { + return MatterTuple.ZERO + } + + var matter = getMatterValue(stack.item) + + if (matter.isZero) + return matter + + if (stack.isDamageableItem) { + val severity = stack.damageValue.toDouble() / stack.maxDamage.toDouble() + matter = MatterTuple(matter.value * severity, matter.complexity * (1.0 - severity / 2)) + } + + val matterCap = stack.getCapability(MatteryCapability.MATTER).orNull() + + if (matterCap != null) { + matter = MatterTuple(matter.value + matterCap.storedMatter, matter.complexity) + } + + val drive = stack.getCapability(MatteryCapability.DRIVE).orNull() + + if (drive != null && drive.storageIdentity() === ItemStackWrapper.javaClass) { + for (item in (drive as IMatteryDrive).getStacks()) { + val tuple = getMatterValue(item.stack.stack, level + 1) + + if (!tuple.isZero) { + matter += tuple + } + } + } + + return matter +} + +/** + * Возвращает массу предмета БЕЗ учёта размера стопки + */ +fun getMatterValue(stack: ItemStack): MatterTuple { + return getMatterValue(stack, 0) +} + +private var server: DedicatedServer? = null + +@SubscribeEvent +@Suppress("unused") +fun onPlayerJoin(event: PlayerEvent.PlayerLoggedInEvent) { + if (server != null) { + MatteryNetworking.CHANNEL.send(PacketDistributor.ALL.noArg(), RegistryPacketFullUpdate(MatterRegistryType.ROOT, rootEntries)) + MatteryNetworking.CHANNEL.send(PacketDistributor.ALL.noArg(), RegistryPacketFullUpdate(MatterRegistryType.DERIVED, derivedEntries)) + } +} + +@SubscribeEvent +@Suppress("unused") +fun serverStartRegistry(event: ServerStartedEvent) { + server = event.server as? DedicatedServer +} + +@SubscribeEvent +@Suppress("unused") +fun serverStopRegistry(event: ServerStoppingEvent) { + server = null +} + +@SubscribeEvent +@Suppress("unused") +fun tooltipEvent(event: ItemTooltipEvent) { + val window = Minecraft.getInstance().window.window + + if (InputConstants.isKeyDown(window, GLFW.GLFW_KEY_LEFT_SHIFT) || InputConstants.isKeyDown(window, GLFW.GLFW_KEY_RIGHT_SHIFT)) { + val matter = getMatterValue(event.itemStack) + + if (!matter.isZero) { + event.toolTip.add( + TranslatableComponent("otm.gui.matter.format_and_complexity", + FormattingHelper.formatMatterValue(matter.value), + "%.3f".format(matter.complexity) + ).withStyle(ChatFormatting.AQUA)) + } + } +} + +data class MatterTuple(val value: ImpreciseFraction, val complexity: Double): Comparable { + operator fun plus(other: MatterTuple) = MatterTuple(value + other.value, complexity + other.complexity) + operator fun minus(other: MatterTuple) = MatterTuple(value - other.value, complexity - other.complexity) + + override operator fun compareTo(other: MatterTuple): Int { + if (compareValues(other) != 0) { + return compareComplexity(other) + } + + return 0 + } + + fun compareValues(other: MatterTuple) = value.compareTo(other.value) + fun compareComplexity(other: MatterTuple): Int { + if (complexity == other.complexity) + return 0 + + return if (complexity < other.complexity) -1 else 1 + } + + fun write(buff: FriendlyByteBuf) { + buff.writeImpreciseFraction(value) + buff.writeDouble(complexity) + } + + val isZero get() = value.isZero + + companion object { + @JvmField val ZERO = MatterTuple(ImpreciseFraction.ZERO, 0.0) + + fun read(buff: FriendlyByteBuf): MatterTuple { + return MatterTuple(buff.readImpreciseFraction(), buff.readDouble()) + } + } +} + +internal enum class MatterRegistryType {ROOT, DERIVED} + +internal class RegistryPacketUpdate(val type: MatterRegistryType, val item: Item, val tuple: MatterTuple) { + fun play(context: Supplier) { + context.get().packetHandled = true + + when (type) { + MatterRegistryType.ROOT -> { + synchronized(rootEntries) { + rootEntries[item] = tuple + } + } + + MatterRegistryType.DERIVED -> { + synchronized(derivedEntries) { + derivedEntries[item] = tuple + } + } + } + } + + fun write(buff: FriendlyByteBuf) { + buff.writeEnum(type) + buff.writeRegistryId(item) + tuple.write(buff) + } + + companion object { + fun read(buff: FriendlyByteBuf): RegistryPacketUpdate { + return RegistryPacketUpdate(buff.readEnum(MatterRegistryType::class.java), buff.readRegistryIdSafe(Item::class.java), MatterTuple.read(buff)) + } + } +} + +internal class RegistryPacketRemove(val type: MatterRegistryType, val item: Item) { + fun play(context: Supplier) { + context.get().packetHandled = true + + when (type) { + MatterRegistryType.ROOT -> { + synchronized(rootEntries) { + rootEntries.remove(item) + } + } + + MatterRegistryType.DERIVED -> { + synchronized(derivedEntries) { + derivedEntries.remove(item) + } + } + } + } + + fun write(buff: FriendlyByteBuf) { + buff.writeEnum(type) + buff.writeRegistryId(item) + } + + companion object { + fun read(buff: FriendlyByteBuf): RegistryPacketRemove { + return RegistryPacketRemove(buff.readEnum(MatterRegistryType::class.java), buff.readRegistryIdSafe(Item::class.java)) + } + } +} + +internal class RegistryPacketFullUpdate(val type: MatterRegistryType, val map: Map) { + fun play(context: Supplier) { + context.get().packetHandled = true + + when (type) { + MatterRegistryType.ROOT -> { + synchronized(rootEntries) { + rootEntries.clear() + rootEntries.putAll(map) + } + } + + MatterRegistryType.DERIVED -> { + synchronized(derivedEntries) { + derivedEntries.clear() + derivedEntries.putAll(map) + } + } + } + } + + fun write(buff: FriendlyByteBuf) { + buff.writeEnum(type) + buff.writeInt(map.size) + + for ((key, value) in map) { + buff.writeRegistryId(key) + value.write(buff) + } + } + + companion object { + fun read(buff: FriendlyByteBuf): RegistryPacketFullUpdate { + val map = HashMap() + val type = buff.readEnum(MatterRegistryType::class.java) + + val size = buff.readInt() + + for (i in 0 until size) { + map[buff.readRegistryId()] = MatterTuple.read(buff) + } + + return RegistryPacketFullUpdate(type, map) + } + } +} + +internal enum class RegistryPacketClear(val type: MatterRegistryType) { + ROOT(MatterRegistryType.ROOT), + DERIVED(MatterRegistryType.DERIVED); + + fun play(context: Supplier) { + context.get().packetHandled = true + + when (type) { + MatterRegistryType.ROOT -> { + synchronized(rootEntries) { + rootEntries.clear() + } + } + + MatterRegistryType.DERIVED -> { + synchronized(derivedEntries) { + derivedEntries.clear() + } + } + } + } + + fun write(buff: FriendlyByteBuf) { + buff.writeEnum(type) + } + + companion object { + fun read(buff: FriendlyByteBuf): RegistryPacketClear { + return buff.readEnum(RegistryPacketClear::class.java) + } + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MenuMatterDecomposer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MenuMatterDecomposer.kt index 656e5746a..414d7b2bb 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MenuMatterDecomposer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MenuMatterDecomposer.kt @@ -8,8 +8,8 @@ import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget import net.minecraft.world.SimpleContainer import net.minecraft.world.item.ItemStack import ru.dbotthepony.mc.otm.Registry -import ru.dbotthepony.mc.otm.matter.MatterRegistry import ru.dbotthepony.mc.otm.capability.MatteryCapability +import ru.dbotthepony.mc.otm.matter.canDecompose import ru.dbotthepony.mc.otm.orNull class MenuMatterDecomposer @JvmOverloads constructor( @@ -28,7 +28,7 @@ class MenuMatterDecomposer @JvmOverloads constructor( // Вход input = object : MatterySlot(container, 0, 61, 36) { override fun mayPlace(p_40231_: ItemStack): Boolean { - return MatterRegistry.canDecompose(p_40231_) + return canDecompose(p_40231_) } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MenuMatterScanner.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MenuMatterScanner.kt index abc086544..8061a0595 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MenuMatterScanner.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MenuMatterScanner.kt @@ -8,9 +8,8 @@ import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget import net.minecraft.world.SimpleContainer import net.minecraft.world.item.ItemStack import ru.dbotthepony.mc.otm.Registry -import ru.dbotthepony.mc.otm.core.Fraction import ru.dbotthepony.mc.otm.core.ImpreciseFraction -import ru.dbotthepony.mc.otm.matter.MatterRegistry +import ru.dbotthepony.mc.otm.matter.canDecompose import java.math.BigInteger class MenuMatterScanner @JvmOverloads constructor( @@ -29,7 +28,7 @@ class MenuMatterScanner @JvmOverloads constructor( input = object : MatterySlot(container, 0, 64, 38) { override fun mayPlace(p_40231_: ItemStack): Boolean { - return MatterRegistry.canDecompose(p_40231_) + return canDecompose(p_40231_) } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/recipe/PlatePressRecipe.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/recipe/PlatePressRecipe.kt index b9bf1c77a..03f33c9a2 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/recipe/PlatePressRecipe.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/recipe/PlatePressRecipe.kt @@ -2,6 +2,7 @@ package ru.dbotthepony.mc.otm.recipe import com.google.gson.JsonObject import com.google.gson.JsonPrimitive +import net.minecraft.core.NonNullList import net.minecraft.network.FriendlyByteBuf import net.minecraft.resources.ResourceLocation import net.minecraft.world.Container @@ -34,11 +35,22 @@ class PlatePressRecipe( private var outputStack: ItemStack? = null + override fun getIngredients(): NonNullList { + if (input.isEmpty || output.isEmpty) + return super.getIngredients() + + return NonNullList.of(null, input) + } + + override fun isIncomplete(): Boolean { + return input.isEmpty || output.isEmpty + } + override fun assemble(p_44001_: Container): ItemStack = resultItem.copy() override fun canCraftInDimensions(p_43999_: Int, p_44000_: Int) = true override fun getResultItem(): ItemStack { if (outputStack == null) { - if (output.isEmpty) { + if (output.isEmpty || input.isEmpty) { outputStack = ItemStack.EMPTY } else { val items = output.items @@ -70,6 +82,7 @@ class PlatePressRecipe( } object PlatePressRecipeFactory : ForgeRegistryEntry>(), RecipeSerializer { + private val EMPTY = PlatePressRecipe(ResourceLocation(OverdriveThatMatters.MOD_ID, "empty"), Ingredient.EMPTY, Ingredient.EMPTY, 1) private val LOGGER = LogManager.getLogger() init { @@ -81,9 +94,9 @@ object PlatePressRecipeFactory : ForgeRegistryEntry>(), Reci Ingredient.fromJson(obj["input"] ?: throw IllegalStateException("Recipe $loc has no input field defined")) } catch (err: Throwable) { if (err.message?.lowercase()?.contains("unknown item tag") == true) { - LOGGER.warn("Ignoring recipe Input of $loc deserialization error") + LOGGER.warn("Ignoring recipe Input of $loc deserialization error, defaulting to empty recipe") LOGGER.warn(err) - Ingredient.of() + return EMPTY } else { throw IllegalStateException("Input of $loc is malformed", err) } @@ -93,9 +106,9 @@ object PlatePressRecipeFactory : ForgeRegistryEntry>(), Reci Ingredient.fromJson(obj["result"] ?: throw IllegalStateException("Recipe $loc has no result field defined")) } catch (err: Throwable) { if (err.message?.lowercase()?.contains("unknown item tag") == true) { - LOGGER.warn("Ignoring recipe Output of $loc deserialization error") + LOGGER.warn("Ignoring recipe Output of $loc deserialization error, defaulting to empty recipe") LOGGER.warn(err) - Ingredient.of() + return EMPTY } else { throw IllegalStateException("Result of $loc is malformed", err) } diff --git a/src/main/resources/assets/overdrive_that_matters/lang/en_us.json b/src/main/resources/assets/overdrive_that_matters/lang/en_us.json index 77aa69d9c..fa140917e 100644 --- a/src/main/resources/assets/overdrive_that_matters/lang/en_us.json +++ b/src/main/resources/assets/overdrive_that_matters/lang/en_us.json @@ -28,6 +28,7 @@ "otm.gui.matter.percentage_level": "Matter level: %s%%", "otm.gui.matter.format": "Matter: %s", + "otm.gui.matter.format_and_complexity": "%s / Complexity: %s", "otm.gui.matter.name": "MtU", "otm.gui.android_research": "Research Tree",