New Matter registry, with better balance and "complexity" support

This commit is contained in:
DBotThePony 2022-01-29 17:38:25 +07:00
parent 154e3679df
commit da5aa346fb
Signed by: DBot
GPG Key ID: DCC23B5715498507
15 changed files with 1053 additions and 702 deletions

View File

@ -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();
}
}

View File

@ -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<Item, ImpreciseFraction> INITIAL_ITEMS = new HashMap<>();
public static final Map<Item, ImpreciseFraction> 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<ItemStackWrapper>) 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<Item, ArrayList<Recipe<?>>> usages = new HashMap<>();
private static final HashMap<Item, ArrayList<Recipe<?>>> results = new HashMap<>();
private static final HashMap<Item, Integer> seen_items = new HashMap<>();
private static final HashMap<Item, Item> seen_items_child = new HashMap<>();
private static boolean solve_occured = false;
private static final Set<Item> 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<? extends Recipe<?>> recipe_type) {
for (Recipe<?> recipe : recipe_type) {
ItemStack result = recipe.getResultItem();
if (result.isEmpty())
continue;
ArrayList<Recipe<?>> 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<Recipe<?>> 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<Map.Entry<Item, Integer>> required_resolve = new ArrayList<>(seen_items.entrySet());
required_resolve.sort((a, b) -> Integer.compare(0, a.getValue().compareTo(b.getValue())));
for (Map.Entry<Item, Integer> 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));
}
}
}
}

View File

@ -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<Item, ImpreciseFraction> list) {
public void write(FriendlyByteBuf buffer) {
buffer.writeInt(list.size());
var registry = (ForgeRegistry<Item>) 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<Item>) RegistryManager.ACTIVE.getRegistry(Item.class);
var map = new HashMap<Item, ImpreciseFraction>();
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<NetworkEvent.Context> context) {
context.get().setPacketHandled(true);
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> this::playClient);
}
}

View File

@ -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)
);

View File

@ -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<IItemHandler> {
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)
}
}
}

View File

@ -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)
}
}

View File

@ -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

View File

@ -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
}
}
}

View File

@ -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())
}

View File

@ -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<Item>()
private val seenRecipes = ArrayDeque<Recipe<*>>()
private val LOGGER = LogManager.getLogger()
private val mappedOutputs = HashMap<Item, ArrayList<Recipe<*>>>()
private val mappedInputs = HashMap<Item, ArrayList<Recipe<*>>>()
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<Item>, 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<Recipe<*>>) {
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)
}

View File

@ -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<Item, MatterTuple>()
private val derivedEntries = HashMap<Item, MatterTuple>()
/**
* 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<Item, MatterTuple> 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<out Item, MatterTuple>) {
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<Item, MatterTuple> 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<out Item, MatterTuple>) {
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<ItemStackWrapper>).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<MatterTuple> {
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<NetworkEvent.Context>) {
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<NetworkEvent.Context>) {
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<Item, MatterTuple>) {
fun play(context: Supplier<NetworkEvent.Context>) {
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<Item, MatterTuple>()
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<NetworkEvent.Context>) {
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)
}
}
}

View File

@ -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_)
}
}

View File

@ -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_)
}
}

View File

@ -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<Ingredient> {
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<*>>(), RecipeSerializer<PlatePressRecipe> {
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<RecipeSerializer<*>>(), 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<RecipeSerializer<*>>(), 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)
}

View File

@ -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",