From 4263ae5febbf38c30e51e3cb790c077f3035a4d4 Mon Sep 17 00:00:00 2001 From: MrQuentinet <32539717+mrquentin@users.noreply.github.com> Date: Fri, 28 Nov 2025 22:43:32 -0500 Subject: [PATCH 01/28] OMG it works ! Still missing a lot of features but at least it works --- .../api/capability/ISoulContainer.java | 15 +---- .../api/data/souls/SoulNetwork.java | 42 ++++++++++++++ .../api/data/souls/SoulNetworkSavedData.java | 57 +++++++++++++++++++ .../trait/NotifiableSoulContainer.java | 52 +++++++---------- .../common/data/CosmicMachines.java | 27 +++++---- .../multiblock/part/SoulHatchPartMachine.java | 30 ++++------ .../forge/ForgeCommonEventListener.java | 9 --- .../gtbridge/CosmicCoreRecipes.java | 10 ++++ 8 files changed, 154 insertions(+), 88 deletions(-) create mode 100644 src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java create mode 100644 src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetworkSavedData.java diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/capability/ISoulContainer.java b/src/main/java/com/ghostipedia/cosmiccore/api/capability/ISoulContainer.java index 472f01c68..facaad4a8 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/capability/ISoulContainer.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/capability/ISoulContainer.java @@ -1,22 +1,11 @@ package com.ghostipedia.cosmiccore.api.capability; -import wayoftime.bloodmagic.core.data.SoulNetwork; +import com.ghostipedia.cosmiccore.api.data.souls.SoulNetwork; import java.util.UUID; public interface ISoulContainer { - - /** - * @return the UUID of the player associated to the container's network - */ - UUID getOwner(); - - /** - * @param playerUUID: the player to whom we attach the container - */ - void setOwner(UUID playerUUID); - - /** + /** * @return the soul network attached to the container */ SoulNetwork getSoulNetwork(); diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java b/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java new file mode 100644 index 000000000..6166fbb96 --- /dev/null +++ b/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java @@ -0,0 +1,42 @@ +package com.ghostipedia.cosmiccore.api.data.souls; + +import lombok.Getter; +import net.minecraft.nbt.CompoundTag; +import net.minecraftforge.common.util.INBTSerializable; + +import java.util.UUID; + +public class SoulNetwork implements INBTSerializable { + + @Getter + private int tier = 0, currentSouls = 0; + + public SoulNetwork() {} + + public int add(int amount, int max) { + int oldSouls = this.currentSouls; + if (oldSouls >= max) return 0; + else { + int newSouls = Math.min(max, oldSouls + amount); + this.currentSouls = newSouls; + return newSouls - oldSouls; + } + } + + public int syphon(int amount) { + if (this.currentSouls >= amount) { + this.currentSouls -= amount; + return amount; + } else return 0; + } + + @Override + public CompoundTag serializeNBT() { + return null; + } + + @Override + public void deserializeNBT(CompoundTag compoundTag) {} + + +} diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetworkSavedData.java b/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetworkSavedData.java new file mode 100644 index 000000000..74eb2ed3f --- /dev/null +++ b/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetworkSavedData.java @@ -0,0 +1,57 @@ +package com.ghostipedia.cosmiccore.api.data.souls; + +import com.ghostipedia.cosmiccore.CosmicCore; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.saveddata.SavedData; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.UUID; + +public class SoulNetworkSavedData extends SavedData { + + private static final String DATA_NAME = CosmicCore.MOD_ID + "_soul_network_data"; + private static final String SOUL_NETWORK_MAPPING = "soul_network_mapping"; + private static final String SOUL_NETWORK_UUID = "soul_network_uuid"; + private static final String SOUL_NETWORK_DATA = "soul_network_data"; + + public static final HashMap SoulNetworkMapping = new HashMap<>(20, 0.9f); + + public static SoulNetworkSavedData getOrCreate(ServerLevel serverLevel) { + return serverLevel.getDataStorage().computeIfAbsent(SoulNetworkSavedData::new, SoulNetworkSavedData::new, DATA_NAME); + } + + public static SoulNetwork getSoulNetwork(UUID owner) { + return SoulNetworkMapping.computeIfAbsent(owner, id -> new SoulNetwork()); + } + + private SoulNetworkSavedData() {} + + private SoulNetworkSavedData(CompoundTag nbt) { + var list = nbt.getList(SOUL_NETWORK_MAPPING, CompoundTag.TAG_COMPOUND); + for (Tag tag : list) { + if (tag instanceof CompoundTag compoundTag) { + var uuid = UUID.fromString(compoundTag.getString(SOUL_NETWORK_UUID)); + var data = new SoulNetwork(); + data.deserializeNBT(compoundTag.getCompound(SOUL_NETWORK_DATA)); + SoulNetworkMapping.put(uuid, data); + } + } + } + + @Override + public @NotNull CompoundTag save(@NotNull CompoundTag compoundTag) { + var soulNetworkDataList = new ListTag(); + for (var entry : SoulNetworkMapping.entrySet()) { + var tag = new CompoundTag(); + tag.putString(SOUL_NETWORK_UUID, entry.getKey().toString()); + tag.put(SOUL_NETWORK_DATA, entry.getValue().serializeNBT()); + soulNetworkDataList.add(tag); + } + compoundTag.put(SOUL_NETWORK_MAPPING, soulNetworkDataList); + return compoundTag; + } +} diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java b/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java index 4383432dd..329b6883a 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java @@ -3,6 +3,8 @@ import com.ghostipedia.cosmiccore.api.capability.ISoulContainer; import com.ghostipedia.cosmiccore.api.capability.recipe.SoulRecipeCapability; +import com.ghostipedia.cosmiccore.api.data.souls.SoulNetwork; +import com.ghostipedia.cosmiccore.api.data.souls.SoulNetworkSavedData; import com.gregtechceu.gtceu.api.capability.recipe.IO; import com.gregtechceu.gtceu.api.capability.recipe.RecipeCapability; import com.gregtechceu.gtceu.api.machine.ConditionalSubscriptionHandler; @@ -10,14 +12,12 @@ import com.gregtechceu.gtceu.api.machine.trait.NotifiableRecipeHandlerTrait; import com.gregtechceu.gtceu.api.recipe.GTRecipe; +import com.gregtechceu.gtceu.common.machine.owner.FTBOwner; import com.lowdragmc.lowdraglib.syncdata.annotation.DescSynced; import com.lowdragmc.lowdraglib.syncdata.annotation.Persisted; import com.lowdragmc.lowdraglib.syncdata.field.ManagedFieldHolder; import lombok.Getter; -import wayoftime.bloodmagic.core.data.SoulNetwork; -import wayoftime.bloodmagic.core.data.SoulTicket; -import wayoftime.bloodmagic.util.helper.NetworkHelper; import java.util.Collections; import java.util.List; @@ -32,11 +32,6 @@ public class NotifiableSoulContainer extends NotifiableRecipeHandlerTrait owner != null); + // TODO: simplify to remove conditional that is not needed + conditionalSubscriptionHandler = new ConditionalSubscriptionHandler(machine, this::querySoulNetwork, () -> true); } private void querySoulNetwork() { @@ -63,7 +58,7 @@ private void querySoulNetwork() { var network = this.getSoulNetwork(); if (network == null) return; - var essence = network.getCurrentEssence(); + var essence = network.getCurrentSouls(); if (this.currentEssence == essence) return; this.currentEssence = essence; @@ -71,23 +66,17 @@ private void querySoulNetwork() { } @Override - public List handleRecipeInner(IO io, GTRecipe recipe, List left, - boolean simulate) { + public List handleRecipeInner(IO io, GTRecipe recipe, List left, boolean simulate) { ISoulContainer container = this; - if (container.getOwner() == null) return null; int lifeEssence = left.stream().reduce(0, Integer::sum); if (io == IO.IN) { - var canOutput = Math.min(this.maxConsumption, container.getSoulNetwork().getCurrentEssence()); - if (!simulate) lifeEssence = container.getSoulNetwork().syphon( - SoulTicket.block(this.machine.getLevel(), this.machine.getPos(), Math.min(canOutput, lifeEssence)), - false); + var canOutput = Math.min(this.maxConsumption, container.getSoulNetwork().getCurrentSouls()); + if (!simulate) lifeEssence = container.getSoulNetwork().syphon(Math.min(canOutput, lifeEssence)); lifeEssence = lifeEssence - canOutput; } else if (io == IO.OUT) { - var canInput = this.maxCapacity - container.getSoulNetwork().getCurrentEssence(); - if (!simulate) lifeEssence = container.getSoulNetwork().add( - SoulTicket.block(this.machine.getLevel(), this.machine.getPos(), Math.min(canInput, lifeEssence)), - this.maxCapacity); + var canInput = this.maxCapacity - container.getSoulNetwork().getCurrentSouls(); + if (!simulate) lifeEssence = container.getSoulNetwork().add(Math.min(canInput, lifeEssence), this.maxCapacity); lifeEssence = lifeEssence - canInput; } @@ -96,14 +85,12 @@ public List handleRecipeInner(IO io, GTRecipe recipe, List lef @Override public List getContents() { - if (this.owner == null) return Collections.emptyList(); - return List.of(this.getSoulNetwork().getCurrentEssence()); + return List.of(this.getSoulNetwork().getCurrentSouls()); } @Override public double getTotalContentAmount() { - if (this.owner == null) return 0; - return this.getSoulNetwork().getCurrentEssence(); + return this.getSoulNetwork().getCurrentSouls(); } @Override @@ -118,18 +105,17 @@ public ManagedFieldHolder getFieldHolder() { @Override public SoulNetwork getSoulNetwork() { - return NetworkHelper.getSoulNetwork(this.owner); + return SoulNetworkSavedData.getSoulNetwork(getOwner()); } - @Override - public int getSize() { - return 1; + public UUID getOwner() { + var team = ((FTBOwner) this.machine.getOwner()).getPlayerTeam(this.machine.getOwnerUUID()); + return team != null ? team.getTeamId() : this.machine.getOwnerUUID(); } @Override - public void setOwner(UUID owner) { - this.owner = owner; - conditionalSubscriptionHandler.updateSubscription(); + public int getSize() { + return 1; } @Override diff --git a/src/main/java/com/ghostipedia/cosmiccore/common/data/CosmicMachines.java b/src/main/java/com/ghostipedia/cosmiccore/common/data/CosmicMachines.java index 9fd012dcc..4dad4b200 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/common/data/CosmicMachines.java +++ b/src/main/java/com/ghostipedia/cosmiccore/common/data/CosmicMachines.java @@ -49,6 +49,7 @@ import com.gregtechceu.gtceu.common.machine.multiblock.electric.PowerSubstationMachine; import com.gregtechceu.gtceu.common.machine.multiblock.part.EnergyHatchPartMachine; import com.gregtechceu.gtceu.common.machine.multiblock.part.FluidHatchPartMachine; +import com.gregtechceu.gtceu.common.machine.multiblock.primitive.PrimitiveWorkableMachine; import com.gregtechceu.gtceu.config.ConfigHolder; import com.gregtechceu.gtceu.utils.FormattingUtil; @@ -386,20 +387,18 @@ public class CosmicMachines { GTValues.tiersBetween(ULV, HV)); // Enable If needed Inside of Dev - // public static final MultiblockMachineDefinition SOUL_TESTER = REGISTRATE.multiblock("soul_tester", - // PrimitiveWorkableMachine::new) - // .rotationState(RotationState.NON_Y_AXIS) - // .recipeType(CosmicCoreRecipeTypes.SOUL_TESTER_RECIPES) - // .appearanceBlock(GTBlocks.CASING_PRIMITIVE_BRICKS) - // .pattern(definition -> FactoryBlockPattern.start() - // .aisle("S", "C", "I") - // .where("C", controller(blocks(definition.getBlock()))) - // .where("S", abilities(CosmicPartAbility.IMPORT_SOUL).or(abilities(CosmicPartAbility.EXPORT_SOUL))) - // .where("I", abilities(PartAbility.EXPORT_ITEMS).or(abilities(PartAbility.IMPORT_ITEMS))) - // .build()) - // .workableCasingModel(GTCEu.id("block/casings/solid/machine_casing_inert_ptfe"), - // GTCEu.id("block/multiblock/coke_oven")) - // .register(); + public static final MultiblockMachineDefinition SOUL_TESTER = REGISTRATE.multiblock("soul_tester", PrimitiveWorkableMachine::new) + .rotationState(RotationState.NON_Y_AXIS) + .recipeType(CosmicRecipeTypes.SOUL_TESTER_RECIPES) + .appearanceBlock(GTBlocks.CASING_PRIMITIVE_BRICKS) + .pattern(definition -> FactoryBlockPattern.start() + .aisle("S", "C", "I") + .where("C", controller(blocks(definition.getBlock()))) + .where("S", abilities(CosmicPartAbility.IMPORT_SOUL).or(abilities(CosmicPartAbility.EXPORT_SOUL))) + .where("I", abilities(PartAbility.EXPORT_ITEMS).or(abilities(PartAbility.IMPORT_ITEMS))) + .build()) + .workableCasingModel(GTCEu.id("block/casings/solid/machine_casing_inert_ptfe"), GTCEu.id("block/multiblock/coke_oven")) + .register(); /* * public static final MultiblockMachineDefinition EMBER_TESTER = REGISTRATE.multiblock("ember_tester", * PrimitiveWorkableMachine::new) diff --git a/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java b/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java index 78a497a32..23bf5fc7c 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java +++ b/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java @@ -47,21 +47,17 @@ public Widget createUIWidget() { group.addWidget(new LabelWidget(8, 8, Component.translatable("gui.cosmiccore.soul_hatch.label." + (this.io == IO.IN ? "import" : "export")))); - if (soulContainer.getOwner() == null) { - group.addWidget( - new LabelWidget(8, 18, I18n.get("gui.cosmiccore.soul_hatch.no_network")).setClientSideWidget()); - } else { - group.addWidget( - new LabelWidget(8, 18, - () -> I18n.get("gui.cosmiccore.soul_hatch.owner", - PlayerHelper.getUsernameFromUUID(this.soulContainer.getOwner()))) - .setClientSideWidget()); - group.addWidget( - new LabelWidget(8, 28, - () -> I18n.get("gui.cosmiccore.soul_hatch.lp", - FormattingUtil.formatNumbers(soulContainer.getCurrentEssence()))) - .setClientSideWidget()); - } + // TODO: Get and display proper player/team Name +// group.addWidget( +// new LabelWidget(8, 18, +// () -> I18n.get("gui.cosmiccore.soul_hatch.owner", +// PlayerHelper.getUsernameFromUUID(this.soulContainer.getOwner()))) +// .setClientSideWidget()); + group.addWidget( + new LabelWidget(8, 28, + () -> I18n.get("gui.cosmiccore.soul_hatch.lp", + FormattingUtil.formatNumbers(soulContainer.getCurrentEssence()))) + .setClientSideWidget()); group.setBackground(GuiTextures.BACKGROUND_INVERSE); return group; @@ -99,10 +95,6 @@ public static int getMaxConsumption(int tier) { }; } - public void attachSoulNetwork(Player player) { - this.soulContainer.setOwner(player.getUUID()); - } - @Override public ManagedFieldHolder getFieldHolder() { return MANAGED_FIELD_HOLDER; diff --git a/src/main/java/com/ghostipedia/cosmiccore/forge/ForgeCommonEventListener.java b/src/main/java/com/ghostipedia/cosmiccore/forge/ForgeCommonEventListener.java index d8c44a483..ba5354974 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/forge/ForgeCommonEventListener.java +++ b/src/main/java/com/ghostipedia/cosmiccore/forge/ForgeCommonEventListener.java @@ -45,15 +45,6 @@ @Mod.EventBusSubscriber(modid = CosmicCore.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE) public class ForgeCommonEventListener { - @SubscribeEvent - public static void entityPlacementEventHandler(BlockEvent.EntityPlaceEvent event) { - if (event.getPlacedBlock().getBlock() instanceof MetaMachineBlock block && - block.getMachine(event.getLevel(), event.getPos()) instanceof SoulHatchPartMachine soulHatch && - event.getEntity() instanceof Player player) { - soulHatch.attachSoulNetwork(player); - } - } - @SubscribeEvent public static void onPlayerTick(final TickEvent.PlayerTickEvent event) { if (event.phase != TickEvent.Phase.END) { diff --git a/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java b/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java index 137167033..bdc8a8199 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java +++ b/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java @@ -1,10 +1,13 @@ package com.ghostipedia.cosmiccore.gtbridge; +import com.ghostipedia.cosmiccore.api.capability.CosmicCapabilities; +import com.ghostipedia.cosmiccore.api.capability.recipe.CosmicRecipeCapabilities; import com.ghostipedia.cosmiccore.common.machine.multiblock.multi.logic.LarvaMachine; import com.gregtechceu.gtceu.api.GTValues; import net.minecraft.data.recipes.FinishedRecipe; +import net.minecraft.world.item.Items; import java.util.function.Consumer; @@ -29,6 +32,7 @@ public static void init(Consumer provider) { .save(provider); LarvaMachine.generateTargettingChipRecipes(provider); + /* * EMBER_TESTER_RECIPES.recipeBuilder("test") * .input(CosmicRecipeCapabilities.EMBER, 100d) @@ -36,6 +40,12 @@ public static void init(Consumer provider) { * .save(provider); */ + SOUL_TESTER_RECIPES.recipeBuilder("generate_soul") + .notConsumable(Items.DIRT) + .output(CosmicRecipeCapabilities.SOUL, 10) + .duration(20) + .save(provider); + // GROVE_RECIPES.recipeBuilder("dirt_movement") // .input(SoulRecipeCapability.CAP, 100) // .notConsumable(CosmicItems.DONK) From 06d7ca78dab11b8151e45de0a692aa32b11e6f8f Mon Sep 17 00:00:00 2001 From: MrQuentinet <32539717+mrquentin@users.noreply.github.com> Date: Wed, 3 Dec 2025 22:31:35 -0500 Subject: [PATCH 02/28] Multiple Soul types need to add display of the soul amount in order to see if it works ! --- .../ghostipedia/cosmiccore/CosmicCore.java | 4 +- .../recipe/SoulRecipeCapability.java | 99 +++++++++---- .../api/capability/souls/SoulType.java | 42 ++++++ .../api/codec/CosmicCodecUtils.java | 6 + .../api/data/souls/SoulNetwork.java | 59 ++++++-- .../trait/NotifiableSoulContainer.java | 134 +++++++----------- .../recipe/content/SerializerSoulStack.java | 45 ++++++ .../api/recipe/ingredient/SoulIngredient.java | 40 ++++++ .../api/recipe/ingredient/SoulStack.java | 41 ++++++ .../api/recipe/lookup/MapSoulIngredient.java | 27 ++-- .../common/data/CosmicMachines.java | 3 - .../multiblock/part/SoulHatchPartMachine.java | 28 +--- .../gtbridge/CosmicCoreRecipes.java | 6 +- 13 files changed, 367 insertions(+), 167 deletions(-) create mode 100644 src/main/java/com/ghostipedia/cosmiccore/api/capability/souls/SoulType.java create mode 100644 src/main/java/com/ghostipedia/cosmiccore/api/codec/CosmicCodecUtils.java create mode 100644 src/main/java/com/ghostipedia/cosmiccore/api/recipe/content/SerializerSoulStack.java create mode 100644 src/main/java/com/ghostipedia/cosmiccore/api/recipe/ingredient/SoulIngredient.java create mode 100644 src/main/java/com/ghostipedia/cosmiccore/api/recipe/ingredient/SoulStack.java diff --git a/src/main/java/com/ghostipedia/cosmiccore/CosmicCore.java b/src/main/java/com/ghostipedia/cosmiccore/CosmicCore.java index b7795432f..f1a5e388c 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/CosmicCore.java +++ b/src/main/java/com/ghostipedia/cosmiccore/CosmicCore.java @@ -3,6 +3,7 @@ import com.ghostipedia.cosmiccore.api.capability.CosmicCapabilities; import com.ghostipedia.cosmiccore.api.item.LinkedTerminalBehavior; import com.ghostipedia.cosmiccore.api.pattern.CosmicPredicates; +import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulIngredient; import com.ghostipedia.cosmiccore.api.recipe.lookup.MapEmberIngredient; import com.ghostipedia.cosmiccore.api.recipe.lookup.MapSoulIngredient; import com.ghostipedia.cosmiccore.api.registries.CosmicRegistration; @@ -32,6 +33,7 @@ import com.lowdragmc.lowdraglib.Platform; import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.crafting.Ingredient; import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; @@ -104,7 +106,7 @@ public void modifyExistingMaterials(PostMaterialEvent event) { @SubscribeEvent public void commonSetup(FMLCommonSetupEvent event) { event.enqueueWork(() -> { - MapIngredientTypeManager.registerMapIngredient(Integer.class, MapSoulIngredient::convertToMapIngredient); + MapIngredientTypeManager.registerMapIngredient(SoulIngredient.class, MapSoulIngredient::from); MapIngredientTypeManager.registerMapIngredient(Double.class, MapEmberIngredient::convertToMapIngredient); GridLinkables.register(CosmicItems.LINKED_TERMINAL, LinkedTerminalBehavior.handler); CCoreNetwork.init(); diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/capability/recipe/SoulRecipeCapability.java b/src/main/java/com/ghostipedia/cosmiccore/api/capability/recipe/SoulRecipeCapability.java index 076f0b279..228607494 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/capability/recipe/SoulRecipeCapability.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/capability/recipe/SoulRecipeCapability.java @@ -1,71 +1,108 @@ package com.ghostipedia.cosmiccore.api.capability.recipe; -import com.ghostipedia.cosmiccore.api.recipe.lookup.MapSoulIngredient; +import com.ghostipedia.cosmiccore.api.capability.souls.SoulType; +import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulIngredient; +import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulStack; import com.gregtechceu.gtceu.api.capability.recipe.RecipeCapability; import com.gregtechceu.gtceu.api.recipe.GTRecipe; import com.gregtechceu.gtceu.api.recipe.content.Content; import com.gregtechceu.gtceu.api.recipe.content.ContentModifier; -import com.gregtechceu.gtceu.api.recipe.content.SerializerInteger; -import com.gregtechceu.gtceu.api.recipe.lookup.ingredient.AbstractMapIngredient; +import com.gregtechceu.gtceu.api.recipe.content.IContentSerializer; -import com.lowdragmc.lowdraglib.gui.widget.LabelWidget; import com.lowdragmc.lowdraglib.gui.widget.WidgetGroup; -import com.lowdragmc.lowdraglib.utils.LocalizationUtils; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import com.mojang.serialization.Codec; import org.apache.commons.lang3.mutable.MutableInt; -import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; import java.util.Collection; import java.util.List; -public class SoulRecipeCapability extends RecipeCapability { + +public class SoulRecipeCapability extends RecipeCapability { public final static SoulRecipeCapability CAP = new SoulRecipeCapability(); protected SoulRecipeCapability() { - super("soul", 0x5E2129FF, true, 10, SerializerInteger.INSTANCE); + super("soul", 0x5E2129FF, true, 10, SerializerSoulIngredient.INSTANCE); } @Override - public Integer copyInner(Integer content) { - return content; + public boolean isRecipeSearchFilter() { + return true; } + //TODO: try to remove @Override - public Integer copyWithModifier(Integer content, ContentModifier modifier) { - return modifier.apply(content); + public SoulIngredient copyInner(SoulIngredient content) { + return super.copyInner(content); } @Override - public @Nullable List getDefaultMapIngredient(Object ingredient) { - List ingredients = new ObjectArrayList<>(1); - if (ingredient instanceof Integer essence) ingredients.add(new MapSoulIngredient(essence)); - return ingredients; + public SoulIngredient copyWithModifier(SoulIngredient content, ContentModifier modifier) { + var modifiedStack = content.stack().withAmount(modifier.apply(content.stack().amount())); + return SoulIngredient.of(modifiedStack); } @Override public List compressIngredients(Collection ingredients) { - // TODO: Figure out what it needs to do - return super.compressIngredients(ingredients); - } - - @Override - public boolean isRecipeSearchFilter() { - return true; + List list = new ArrayList<>(ingredients.size()); + for (Object item : ingredients) { + if (item instanceof SoulIngredient soul) { + var isEqual = false; + for (Object obj : list) { + if (obj instanceof SoulIngredient soulIngredient && soul.equals(soulIngredient)) { + isEqual = true; + break; + } + } + if (isEqual) continue; + list.add(item); + } + } + return list; } @Override public void addXEIInfo(WidgetGroup group, int xOffset, GTRecipe recipe, List contents, boolean perTick, boolean isInput, MutableInt yOffset) { - int soul = contents.stream().map(Content::getContent).mapToInt(SoulRecipeCapability.CAP::of).sum(); - if (isInput) { - group.addWidget(new LabelWidget(3 - xOffset, yOffset.addAndGet(10), - LocalizationUtils.format("cosmiccore.recipe.soul_in", soul))); - } else { - group.addWidget(new LabelWidget(3 - xOffset, yOffset.addAndGet(10), - LocalizationUtils.format("cosmiccore.recipe.soul_out", soul))); + //TODO: ADD XEI info +// String type = contents.stream().map(Content::getContent).map(SoulRecipeCapability.CAP::of).map(SoulStack::type).map(SoulType::getSerializedName).findFirst().orElse(""); +// long soul = contents.stream().map(Content::getContent).map(SoulRecipeCapability.CAP::of).mapToLong(SoulStack::amount).sum(); +// if (isInput) { +// group.addWidget(new LabelWidget(3 - xOffset, yOffset.addAndGet(10), +// LocalizationUtils.format("cosmiccore.recipe." + type + "_soul_in", soul))); +// } else { +// group.addWidget(new LabelWidget(3 - xOffset, yOffset.addAndGet(10), +// LocalizationUtils.format("cosmiccore.recipe." + type + "_soul_out", soul))); +// } + } + + private static class SerializerSoulIngredient implements IContentSerializer { + + public static SerializerSoulIngredient INSTANCE = new SerializerSoulIngredient(); + + @Override + public SoulIngredient of(Object o) { + if (o instanceof SoulStack stack) return SoulIngredient.of(stack); + else if (o instanceof SoulIngredient ingredient) return ingredient; + return SoulIngredient.of(new SoulStack(SoulType.Impure, 0)); + } + + @Override + public SoulIngredient defaultValue() { + return SoulIngredient.of(new SoulStack(SoulType.Impure, 0)); + } + + @Override + public Class contentClass() { + return SoulIngredient.class; + } + + @Override + public Codec codec() { + return SoulIngredient.CODEC; } } } diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/capability/souls/SoulType.java b/src/main/java/com/ghostipedia/cosmiccore/api/capability/souls/SoulType.java new file mode 100644 index 000000000..b8aec80dd --- /dev/null +++ b/src/main/java/com/ghostipedia/cosmiccore/api/capability/souls/SoulType.java @@ -0,0 +1,42 @@ +package com.ghostipedia.cosmiccore.api.capability.souls; + +import com.mojang.serialization.Codec; +import net.minecraft.util.StringRepresentable; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +public enum SoulType implements StringRepresentable { + Impure("Impure"), + Rusted("Rusted"), + Proud("Proud"), + Greedy("Greedy"), + Envious("Envious"), + Gluttonous("Gluttonous"), + Wrathful("Wrathful"), + Slothful("Slothful"), + Temporal("Temporal"); + + private final String name; + + SoulType(String name) { + this.name = name; + } + + + @Override + public @NotNull String getSerializedName() { + return this.name; + } + + public static final Codec CODEC = StringRepresentable.fromEnum(SoulType::values); + + private static final Map BY_NAME = Arrays.stream(values()).collect(Collectors.toMap(SoulType::getSerializedName, Function.identity())); + + public static SoulType byName(String name) { + return BY_NAME.get(name); + } +} diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/codec/CosmicCodecUtils.java b/src/main/java/com/ghostipedia/cosmiccore/api/codec/CosmicCodecUtils.java new file mode 100644 index 000000000..22fa96c67 --- /dev/null +++ b/src/main/java/com/ghostipedia/cosmiccore/api/codec/CosmicCodecUtils.java @@ -0,0 +1,6 @@ +package com.ghostipedia.cosmiccore.api.codec; + +import com.mojang.serialization.Codec; + +public class CosmicCodecUtils { +} diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java b/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java index 6166fbb96..774c296d0 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java @@ -1,9 +1,15 @@ package com.ghostipedia.cosmiccore.api.data.souls; +import com.ghostipedia.cosmiccore.api.capability.souls.SoulType; +import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulIngredient; +import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulStack; import lombok.Getter; import net.minecraft.nbt.CompoundTag; import net.minecraftforge.common.util.INBTSerializable; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.UUID; public class SoulNetwork implements INBTSerializable { @@ -11,23 +17,46 @@ public class SoulNetwork implements INBTSerializable { @Getter private int tier = 0, currentSouls = 0; + private Map contents = new HashMap<>(); + public SoulNetwork() {} - public int add(int amount, int max) { - int oldSouls = this.currentSouls; - if (oldSouls >= max) return 0; - else { - int newSouls = Math.min(max, oldSouls + amount); - this.currentSouls = newSouls; - return newSouls - oldSouls; - } + public SoulStack add(SoulStack stack, int throughput, boolean simulate) { + int currentAmount = this.contents.getOrDefault(stack.type(), 0); + + int amountToAdd = Math.min(stack.amount(), throughput); // Respect throughput + amountToAdd = Math.min(amountToAdd, getSize() - currentAmount); // Respect network capacity + + if (!simulate) this.contents.put(stack.type(), currentAmount + amountToAdd); + + return stack.withAmount(amountToAdd); + } + + public SoulStack syphon(SoulStack stack, boolean simulate) { + var currentSoulContent = this.contents.getOrDefault(stack.type(), 0); + int amountToSyphon = Math.min(stack.amount(), currentSoulContent); + + if (!simulate && amountToSyphon > 0) this.contents.put(stack.type(), currentSoulContent - amountToSyphon); + + return stack.withAmount(amountToSyphon); + } + + public List getContents() { + return contents.entrySet().stream() + .map(kvp -> new SoulStack(kvp.getKey(), kvp.getValue())) + .toList(); } - public int syphon(int amount) { - if (this.currentSouls >= amount) { - this.currentSouls -= amount; - return amount; - } else return 0; + public int getSize() { + return switch (tier) { + case 0 -> 1_000; + case 1 -> 100_000; + case 3 -> 1_000_000; + case 4 -> 10_000_000; + case 5 -> 100_000_000; + case 6 -> 1_000_000_000; + default -> Integer.MAX_VALUE; + }; } @Override @@ -36,7 +65,7 @@ public CompoundTag serializeNBT() { } @Override - public void deserializeNBT(CompoundTag compoundTag) {} - + public void deserializeNBT(CompoundTag compoundTag) { + } } diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java b/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java index 329b6883a..fefc1497b 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java @@ -1,126 +1,96 @@ package com.ghostipedia.cosmiccore.api.machine.trait; -import com.ghostipedia.cosmiccore.api.capability.ISoulContainer; -import com.ghostipedia.cosmiccore.api.capability.recipe.SoulRecipeCapability; - +import com.ghostipedia.cosmiccore.api.capability.recipe.CosmicRecipeCapabilities; import com.ghostipedia.cosmiccore.api.data.souls.SoulNetwork; import com.ghostipedia.cosmiccore.api.data.souls.SoulNetworkSavedData; +import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulIngredient; +import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulStack; import com.gregtechceu.gtceu.api.capability.recipe.IO; import com.gregtechceu.gtceu.api.capability.recipe.RecipeCapability; -import com.gregtechceu.gtceu.api.machine.ConditionalSubscriptionHandler; import com.gregtechceu.gtceu.api.machine.MetaMachine; import com.gregtechceu.gtceu.api.machine.trait.NotifiableRecipeHandlerTrait; import com.gregtechceu.gtceu.api.recipe.GTRecipe; - import com.gregtechceu.gtceu.common.machine.owner.FTBOwner; -import com.lowdragmc.lowdraglib.syncdata.annotation.DescSynced; -import com.lowdragmc.lowdraglib.syncdata.annotation.Persisted; -import com.lowdragmc.lowdraglib.syncdata.field.ManagedFieldHolder; - import lombok.Getter; +import org.jetbrains.annotations.NotNull; -import java.util.Collections; +import java.util.ArrayList; import java.util.List; import java.util.UUID; -public class NotifiableSoulContainer extends NotifiableRecipeHandlerTrait implements ISoulContainer { - - public static final ManagedFieldHolder MANAGED_FIELD_HOLDER = new ManagedFieldHolder(NotifiableSoulContainer.class, - NotifiableRecipeHandlerTrait.MANAGED_FIELD_HOLDER); - @Getter - private final IO handlerIO; - private final ConditionalSubscriptionHandler conditionalSubscriptionHandler; +public class NotifiableSoulContainer extends NotifiableRecipeHandlerTrait { @Getter - @DescSynced - private int currentEssence; - - @Persisted - private int maxCapacity; + public final IO handlerIO; - @Persisted - private int maxConsumption; + private final int throughput; - public NotifiableSoulContainer(MetaMachine machine, IO io, int maxCapacity, int maxConsumption) { + public NotifiableSoulContainer(MetaMachine machine, IO io, int throughput) { super(machine); this.handlerIO = io; - this.currentEssence = -1; - this.maxCapacity = maxCapacity; - this.maxConsumption = maxConsumption; - // TODO: simplify to remove conditional that is not needed - conditionalSubscriptionHandler = new ConditionalSubscriptionHandler(machine, this::querySoulNetwork, () -> true); + this.throughput = throughput; } - private void querySoulNetwork() { - if (this.machine.getOffsetTimer() % 20 != 0) return; - - var network = this.getSoulNetwork(); - if (network == null) return; - - var essence = network.getCurrentSouls(); - if (this.currentEssence == essence) return; - - this.currentEssence = essence; - this.notifyListeners(); - } - - @Override - public List handleRecipeInner(IO io, GTRecipe recipe, List left, boolean simulate) { - ISoulContainer container = this; - - int lifeEssence = left.stream().reduce(0, Integer::sum); - if (io == IO.IN) { - var canOutput = Math.min(this.maxConsumption, container.getSoulNetwork().getCurrentSouls()); - if (!simulate) lifeEssence = container.getSoulNetwork().syphon(Math.min(canOutput, lifeEssence)); - lifeEssence = lifeEssence - canOutput; - } else if (io == IO.OUT) { - var canInput = this.maxCapacity - container.getSoulNetwork().getCurrentSouls(); - if (!simulate) lifeEssence = container.getSoulNetwork().add(Math.min(canInput, lifeEssence), this.maxCapacity); - lifeEssence = lifeEssence - canInput; - } - - return lifeEssence <= 0 ? null : Collections.singletonList(lifeEssence); + private SoulNetwork getSoulNetwork() { + return SoulNetworkSavedData.getSoulNetwork(getOwner()); } - @Override - public List getContents() { - return List.of(this.getSoulNetwork().getCurrentSouls()); + private UUID getOwner() { + var team = ((FTBOwner) this.machine.getOwner()).getPlayerTeam(this.machine.getOwnerUUID()); + return team != null ? team.getTeamId() : this.machine.getOwnerUUID(); } @Override - public double getTotalContentAmount() { - return this.getSoulNetwork().getCurrentSouls(); - } + public List handleRecipeInner(IO io, GTRecipe recipe, List left, boolean simulate) { + if (io != handlerIO) return left; + if (io != IO.IN && io != IO.OUT) return left.isEmpty() ? null : left; + + var network = getSoulNetwork(); + List result = new ArrayList<>(); + + for (SoulIngredient ingredient : left) { + SoulStack requiredStack = ingredient.stack(); + if (requiredStack.isEmpty()) continue; + + if (io == IO.IN) { + SoulStack consumedStack = network.syphon(requiredStack, simulate); + if (consumedStack.amount() < requiredStack.amount()){ + result.add(SoulIngredient.of(requiredStack.withAmount(requiredStack.amount() - consumedStack.amount()))); + } + } else { + SoulStack remainder = network.add(requiredStack, throughput, simulate); + if (remainder.amount() > 0) { + result.add(SoulIngredient.of(remainder)); + } + } + } - @Override - public RecipeCapability getCapability() { - return SoulRecipeCapability.CAP; + return List.of(); } @Override - public ManagedFieldHolder getFieldHolder() { - return MANAGED_FIELD_HOLDER; + public @NotNull List getContents() { + return getSoulNetwork().getContents().stream() + .map(SoulIngredient::new) + .map(Object.class::cast) + .toList(); } @Override - public SoulNetwork getSoulNetwork() { - return SoulNetworkSavedData.getSoulNetwork(getOwner()); - } - - public UUID getOwner() { - var team = ((FTBOwner) this.machine.getOwner()).getPlayerTeam(this.machine.getOwnerUUID()); - return team != null ? team.getTeamId() : this.machine.getOwnerUUID(); + public int getSize() { + return getSoulNetwork().getContents().size(); } @Override - public int getSize() { - return 1; + public double getTotalContentAmount() { + return getSoulNetwork().getContents().stream() + .mapToInt(SoulStack::amount) + .sum(); } @Override - public void onMachineLoad() { - super.onMachineLoad(); - conditionalSubscriptionHandler.initialize(this.machine.getLevel()); + public RecipeCapability getCapability() { + return CosmicRecipeCapabilities.SOUL; } } diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/recipe/content/SerializerSoulStack.java b/src/main/java/com/ghostipedia/cosmiccore/api/recipe/content/SerializerSoulStack.java new file mode 100644 index 000000000..dcc30a69b --- /dev/null +++ b/src/main/java/com/ghostipedia/cosmiccore/api/recipe/content/SerializerSoulStack.java @@ -0,0 +1,45 @@ +package com.ghostipedia.cosmiccore.api.recipe.content; + +import com.ghostipedia.cosmiccore.api.capability.souls.SoulType; +import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulStack; +import com.gregtechceu.gtceu.api.recipe.content.IContentSerializer; +import com.mojang.serialization.Codec; +import net.minecraft.network.FriendlyByteBuf; + +public class SerializerSoulStack implements IContentSerializer { + + public static SerializerSoulStack INSTANCE = new SerializerSoulStack(); + + private SerializerSoulStack() {} + + @Override + public void toNetwork(FriendlyByteBuf buf, SoulStack content) { + content.toNetwork(buf); + } + + @Override + public SoulStack fromNetwork(FriendlyByteBuf buf) { + return SoulStack.fromNetwork(buf); + } + + @Override + public SoulStack of(Object o) { + if (o instanceof SoulStack stack) return stack; + else return SoulStack.EMPTY; + } + + @Override + public SoulStack defaultValue() { + return SoulStack.EMPTY; + } + + @Override + public Class contentClass() { + return SoulStack.class; + } + + @Override + public Codec codec() { + return SoulStack.CODEC; + } +} diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/recipe/ingredient/SoulIngredient.java b/src/main/java/com/ghostipedia/cosmiccore/api/recipe/ingredient/SoulIngredient.java new file mode 100644 index 000000000..33b010ec8 --- /dev/null +++ b/src/main/java/com/ghostipedia/cosmiccore/api/recipe/ingredient/SoulIngredient.java @@ -0,0 +1,40 @@ +package com.ghostipedia.cosmiccore.api.recipe.ingredient; + + +import com.ghostipedia.cosmiccore.api.capability.souls.SoulType; +import com.mojang.serialization.Codec; +import org.jetbrains.annotations.NotNull; + +import java.util.function.Predicate; + +public record SoulIngredient(SoulStack stack) implements Predicate { + + public static final Codec CODEC = SoulStack.CODEC.xmap(SoulIngredient::new, SoulIngredient::stack); + + public static SoulIngredient of(final SoulStack stack) { + return new SoulIngredient(stack); + } + + public static SoulIngredient of(SoulType soulType, int amount) { + return new SoulIngredient(new SoulStack(soulType, amount)); + } + + @Override + public boolean test(SoulStack soulStack) { + return this.stack.type() == soulStack.type() + && this.stack.amount() <= soulStack.amount(); + } + + @Override + public @NotNull String toString() { + return "SoulIngredient{stack=" + stack + "}"; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof SoulIngredient other)) { + return false; + } + return stack.equals(other.stack); + } +} diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/recipe/ingredient/SoulStack.java b/src/main/java/com/ghostipedia/cosmiccore/api/recipe/ingredient/SoulStack.java new file mode 100644 index 000000000..c63715c69 --- /dev/null +++ b/src/main/java/com/ghostipedia/cosmiccore/api/recipe/ingredient/SoulStack.java @@ -0,0 +1,41 @@ +package com.ghostipedia.cosmiccore.api.recipe.ingredient; + +import com.ghostipedia.cosmiccore.api.capability.souls.SoulType; +import com.google.common.base.Preconditions; +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import lombok.With; +import net.minecraft.network.FriendlyByteBuf; + +@With +public record SoulStack(SoulType type, int amount) { + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + SoulType.CODEC.fieldOf("type").forGetter(SoulStack::type), + Codec.INT.fieldOf("amount").forGetter(SoulStack::amount) + ).apply(instance, SoulStack::new)); + + public static final SoulStack EMPTY = new SoulStack(SoulType.Impure, 0); + + public boolean isEmpty() { + return this.amount <= 0; + } + + public SoulStack add(int amount) { + Preconditions.checkArgument(this.amount + amount >= 0, "Resulting amount must be non-negative"); + return new SoulStack(this.type, this.amount + amount); + } + + public SoulStack sum(SoulStack a, SoulStack b) { + Preconditions.checkArgument(a.type == b.type, "SoulStack types don't match"); + return a.add(b.amount); + } + + public void toNetwork(FriendlyByteBuf buf) { + buf.writeEnum(this.type); + buf.writeVarInt(this.amount); + } + + public static SoulStack fromNetwork(FriendlyByteBuf buf) { + return new SoulStack(buf.readEnum(SoulType.class), buf.readVarInt()); + } +} diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/recipe/lookup/MapSoulIngredient.java b/src/main/java/com/ghostipedia/cosmiccore/api/recipe/lookup/MapSoulIngredient.java index 2ab62d0f4..eb14168ab 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/recipe/lookup/MapSoulIngredient.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/recipe/lookup/MapSoulIngredient.java @@ -1,34 +1,37 @@ package com.ghostipedia.cosmiccore.api.recipe.lookup; +import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulIngredient; +import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulStack; import com.gregtechceu.gtceu.api.recipe.lookup.ingredient.AbstractMapIngredient; -import java.util.Collections; import java.util.List; public class MapSoulIngredient extends AbstractMapIngredient { - public final Integer souls; + public final SoulStack stack; - public MapSoulIngredient(Integer souls) { - this.souls = souls; + public MapSoulIngredient(SoulStack stack) { + this.stack = stack; } @Override protected int hash() { - return MapSoulIngredient.class.hashCode(); + return 0; } @Override - public boolean equals(Object obj) { - return obj instanceof MapSoulIngredient; + public boolean equals(Object o) { + if (!(o instanceof MapSoulIngredient other)) return false; + return stack.equals(other.stack); } - @Override - public String toString() { - return "MapSoulIngredient{" + "souls=" + souls + '}'; + public static List from(SoulIngredient soulIngredient) { + SoulStack stack = soulIngredient.stack(); + return List.of(new MapSoulIngredient(stack)); } - public static List convertToMapIngredient(Integer essence) { - return Collections.singletonList(new MapSoulIngredient(essence)); + @Override + public String toString() { + return "MapSoulIngredient{stack=" + stack + "}"; } } diff --git a/src/main/java/com/ghostipedia/cosmiccore/common/data/CosmicMachines.java b/src/main/java/com/ghostipedia/cosmiccore/common/data/CosmicMachines.java index 4dad4b200..b484b49aa 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/common/data/CosmicMachines.java +++ b/src/main/java/com/ghostipedia/cosmiccore/common/data/CosmicMachines.java @@ -489,9 +489,6 @@ private static MachineDefinition[] registerSoulHatch(String name, String display if (io == IO.IN) tooltip.add(Component.translatable("tooltip.cosmiccore.soul_hatch.input", SoulHatchPartMachine.getMaxConsumption(tier))); - else - tooltip.add(Component.translatable("tooltip.cosmiccore.soul_hatch.output", - SoulHatchPartMachine.getMaxCapacity(tier))); }).register(), tiers); } diff --git a/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java b/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java index 23bf5fc7c..7fb162bfa 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java +++ b/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java @@ -36,7 +36,7 @@ public class SoulHatchPartMachine extends TieredIOPartMachine { public SoulHatchPartMachine(IMachineBlockEntity holder, int tier, IO io) { super(holder, tier, io); - this.soulContainer = new NotifiableSoulContainer(this, io, getMaxCapacity(tier), getMaxConsumption(tier)); + this.soulContainer = new NotifiableSoulContainer(this, io, getMaxConsumption(tier)); } @Override @@ -53,32 +53,16 @@ public Widget createUIWidget() { // () -> I18n.get("gui.cosmiccore.soul_hatch.owner", // PlayerHelper.getUsernameFromUUID(this.soulContainer.getOwner()))) // .setClientSideWidget()); - group.addWidget( - new LabelWidget(8, 28, - () -> I18n.get("gui.cosmiccore.soul_hatch.lp", - FormattingUtil.formatNumbers(soulContainer.getCurrentEssence()))) - .setClientSideWidget()); +// group.addWidget( +// new LabelWidget(8, 28, +// () -> I18n.get("gui.cosmiccore.soul_hatch.lp", +// FormattingUtil.formatNumbers(soulContainer.getCurrentEssence()))) +// .setClientSideWidget()); group.setBackground(GuiTextures.BACKGROUND_INVERSE); return group; } - public static int getMaxCapacity(int tier) { - return switch (tier) { - case GTValues.IV -> 5000000; - case GTValues.LuV -> 10000000; - case GTValues.ZPM -> 20000000; - case GTValues.UV -> 30000000; - case GTValues.UHV -> 50000000; - case GTValues.UEV -> 100000000; - case GTValues.UIV -> 250000000; - case GTValues.UXV -> 500000000; - case GTValues.OpV -> 1000000000; - case GTValues.MAX -> Integer.MAX_VALUE; - default -> 0; - }; - } - public static int getMaxConsumption(int tier) { return switch (tier) { case GTValues.IV -> 10000; diff --git a/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java b/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java index bdc8a8199..96df70358 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java +++ b/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java @@ -2,6 +2,9 @@ import com.ghostipedia.cosmiccore.api.capability.CosmicCapabilities; import com.ghostipedia.cosmiccore.api.capability.recipe.CosmicRecipeCapabilities; +import com.ghostipedia.cosmiccore.api.capability.souls.SoulType; +import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulIngredient; +import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulStack; import com.ghostipedia.cosmiccore.common.machine.multiblock.multi.logic.LarvaMachine; import com.gregtechceu.gtceu.api.GTValues; @@ -42,7 +45,8 @@ public static void init(Consumer provider) { SOUL_TESTER_RECIPES.recipeBuilder("generate_soul") .notConsumable(Items.DIRT) - .output(CosmicRecipeCapabilities.SOUL, 10) + .output(CosmicRecipeCapabilities.SOUL, SoulIngredient.of(SoulType.Impure, 10)) + .output(CosmicRecipeCapabilities.SOUL, SoulIngredient.of(SoulType.Temporal, 10)) .duration(20) .save(provider); From d85a9e1c6f8ca4e375f1d88b350b8d47989052d4 Mon Sep 17 00:00:00 2001 From: MrQuentinet <32539717+mrquentin@users.noreply.github.com> Date: Thu, 4 Dec 2025 20:54:56 -0500 Subject: [PATCH 03/28] it works !! --- .../api/data/souls/SoulNetwork.java | 47 +++++++++++++++---- .../trait/NotifiableSoulContainer.java | 9 ++-- .../gtbridge/CosmicCoreRecipes.java | 2 +- 3 files changed, 42 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java b/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java index 774c296d0..75aaa19b8 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java @@ -1,33 +1,37 @@ package com.ghostipedia.cosmiccore.api.data.souls; import com.ghostipedia.cosmiccore.api.capability.souls.SoulType; -import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulIngredient; import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulStack; import lombok.Getter; import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; import net.minecraftforge.common.util.INBTSerializable; -import java.util.HashMap; +import java.util.concurrent.ConcurrentHashMap; import java.util.List; import java.util.Map; -import java.util.UUID; public class SoulNetwork implements INBTSerializable { @Getter - private int tier = 0, currentSouls = 0; + private int tier = 0; - private Map contents = new HashMap<>(); + private final Map contents = new ConcurrentHashMap<>(); public SoulNetwork() {} public SoulStack add(SoulStack stack, int throughput, boolean simulate) { int currentAmount = this.contents.getOrDefault(stack.type(), 0); + int totalAmount = this.contents.values().stream().mapToInt(Integer::intValue).sum(); int amountToAdd = Math.min(stack.amount(), throughput); // Respect throughput - amountToAdd = Math.min(amountToAdd, getSize() - currentAmount); // Respect network capacity + amountToAdd = Math.min(amountToAdd, getSize() - totalAmount); // Respect network capacity + amountToAdd = Math.max(0, amountToAdd); // Ensure we don't add a negative amount - if (!simulate) this.contents.put(stack.type(), currentAmount + amountToAdd); + if (!simulate && amountToAdd > 0) this.contents.put(stack.type(), currentAmount + amountToAdd); + + System.out.println(this); return stack.withAmount(amountToAdd); } @@ -51,7 +55,7 @@ public int getSize() { return switch (tier) { case 0 -> 1_000; case 1 -> 100_000; - case 3 -> 1_000_000; + case 2 -> 1_000_000; case 4 -> 10_000_000; case 5 -> 100_000_000; case 6 -> 1_000_000_000; @@ -59,13 +63,36 @@ public int getSize() { }; } + @Override + public String toString() { + return "SoulNetwork{" + + "tier=" + tier + + ", contents=" + contents + '}'; + } + @Override public CompoundTag serializeNBT() { - return null; + var tag = new CompoundTag(); + tag.putInt("tier", this.tier); + var listTag = new ListTag(); + this.contents.forEach((soulType, amount) -> { + var contentTag = new CompoundTag(); + contentTag.putString("type", soulType.getSerializedName()); + contentTag.putInt("amount", amount); + listTag.add(contentTag); + }); + tag.put("contents", listTag); + return tag; } @Override public void deserializeNBT(CompoundTag compoundTag) { - + this.tier = compoundTag.getInt("tier"); + this.contents.clear(); + ListTag listTag = compoundTag.getList("contents", Tag.TAG_COMPOUND); + for (Tag t : listTag) { + var contentTag = (CompoundTag) t; + this.contents.put(SoulType.byName(contentTag.getString("type")), contentTag.getInt("amount")); + } } } diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java b/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java index fefc1497b..609b49993 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java @@ -59,14 +59,13 @@ public List handleRecipeInner(IO io, GTRecipe recipe, List 0) { - result.add(SoulIngredient.of(remainder)); - } + SoulStack canInput = network.add(requiredStack, throughput, simulate); + SoulStack reminder = requiredStack.withAmount(requiredStack.amount() - canInput.amount()); + if (reminder.amount() > 0) result.add(SoulIngredient.of(reminder)); } } - return List.of(); + return result.isEmpty() ? null : result; } @Override diff --git a/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java b/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java index 96df70358..31192b8ea 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java +++ b/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java @@ -46,7 +46,7 @@ public static void init(Consumer provider) { SOUL_TESTER_RECIPES.recipeBuilder("generate_soul") .notConsumable(Items.DIRT) .output(CosmicRecipeCapabilities.SOUL, SoulIngredient.of(SoulType.Impure, 10)) - .output(CosmicRecipeCapabilities.SOUL, SoulIngredient.of(SoulType.Temporal, 10)) + .output(CosmicRecipeCapabilities.SOUL, SoulIngredient.of(SoulType.Temporal, 50)) .duration(20) .save(provider); From c4a5461b83cc2104762845e17cc54e784ba69006 Mon Sep 17 00:00:00 2001 From: MrQuentinet <32539717+mrquentin@users.noreply.github.com> Date: Sat, 6 Dec 2025 13:32:50 -0500 Subject: [PATCH 04/28] Add reader item --- .../api/data/souls/SoulNetwork.java | 12 ++--- .../cosmiccore/common/data/CosmicItems.java | 9 ++++ .../common/item/SoulNetworkReaderItem.java | 45 +++++++++++++++++++ 3 files changed, 60 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/ghostipedia/cosmiccore/common/item/SoulNetworkReaderItem.java diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java b/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java index 75aaa19b8..c122186ef 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java @@ -53,12 +53,12 @@ public List getContents() { public int getSize() { return switch (tier) { - case 0 -> 1_000; - case 1 -> 100_000; - case 2 -> 1_000_000; - case 4 -> 10_000_000; - case 5 -> 100_000_000; - case 6 -> 1_000_000_000; + case 0 -> 10_000; + case 1 -> 50_000; + case 2 -> 150_000; + case 4 -> 1_000_000; + case 5 -> 10_000_000; + case 6 -> 100_000_000; default -> Integer.MAX_VALUE; }; } diff --git a/src/main/java/com/ghostipedia/cosmiccore/common/data/CosmicItems.java b/src/main/java/com/ghostipedia/cosmiccore/common/data/CosmicItems.java index 992dc5035..b5e52bd9d 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/common/data/CosmicItems.java +++ b/src/main/java/com/ghostipedia/cosmiccore/common/data/CosmicItems.java @@ -10,6 +10,7 @@ import com.ghostipedia.cosmiccore.common.item.AsteroidItem; import com.ghostipedia.cosmiccore.common.item.AsteroidTargetingChipItem; import com.ghostipedia.cosmiccore.common.item.CosmicScytheItem; +import com.ghostipedia.cosmiccore.common.item.SoulNetworkReaderItem; import com.ghostipedia.cosmiccore.common.item.armor.ChestSanguineWarptechSuite; import com.ghostipedia.cosmiccore.common.item.armor.HelmetSanguineWarptechSuite; import com.ghostipedia.cosmiccore.common.item.armor.SanguineWarptechSuite; @@ -101,6 +102,14 @@ public class CosmicItems { "cosmiccore"); // Modules + public static final ItemEntry SOUL_READER = REGISTRATE + .item("soul_reader", SoulNetworkReaderItem::new) + .lang("Soul Network Reader") + .properties(p -> p.stacksTo(1)) + .tag() + .defaultModel() + .register(); + public static final ItemEntry ETHERIC_SPIRIT_ITEM = REGISTRATE .item("etheric_spirit", (properties -> new SpiritShardItem(properties, CosmicItems.ETHERIC_SPIRIT))) .lang("Etheric Spirit") diff --git a/src/main/java/com/ghostipedia/cosmiccore/common/item/SoulNetworkReaderItem.java b/src/main/java/com/ghostipedia/cosmiccore/common/item/SoulNetworkReaderItem.java new file mode 100644 index 000000000..9f7c459eb --- /dev/null +++ b/src/main/java/com/ghostipedia/cosmiccore/common/item/SoulNetworkReaderItem.java @@ -0,0 +1,45 @@ +package com.ghostipedia.cosmiccore.common.item; + +import com.ghostipedia.cosmiccore.api.data.souls.SoulNetwork; +import com.ghostipedia.cosmiccore.api.data.souls.SoulNetworkSavedData; +import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulStack; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; + +import java.util.List; + +public class SoulNetworkReaderItem extends Item { + + public SoulNetworkReaderItem(Properties properties) { + super(properties); + } + + @Override + public InteractionResultHolder use(Level level, Player player, InteractionHand hand) { + if (!level.isClientSide() && player instanceof ServerPlayer serverPlayer) { + //TODO: get team or player uuid + SoulNetwork soulNetwork = SoulNetworkSavedData.getSoulNetwork(player.getUUID()); + List contents = soulNetwork.getContents(); + + player.sendSystemMessage(Component.literal("--- Soul Network Contents ---").withStyle(ChatFormatting.GOLD)); + + if (contents.isEmpty()) { + player.sendSystemMessage(Component.literal("Network is empty.").withStyle(ChatFormatting.GRAY)); + } else { + for (SoulStack stack : contents) { + Component message = Component.literal(String.format("%s: %,d", stack.type().getSerializedName(), stack.amount())) + .withStyle(ChatFormatting.AQUA); + player.sendSystemMessage(message); + } + } + } + return InteractionResultHolder.success(player.getItemInHand(hand)); + } +} From 01f5a63f02fff188c10fa0b6a13bfac1c1f32726 Mon Sep 17 00:00:00 2001 From: MrQuentinet <32539717+mrquentin@users.noreply.github.com> Date: Sat, 3 Jan 2026 15:31:13 -0500 Subject: [PATCH 05/28] WIP --- .../assets/cosmiccore/lang/en_us.json | 9 ++++ .../api/capability/souls/SoulType.java | 43 ++++++++++++++----- .../common/data/CosmicMachines.java | 6 +-- .../common/item/SoulNetworkReaderItem.java | 9 +--- 4 files changed, 47 insertions(+), 20 deletions(-) diff --git a/src/generated/resources/assets/cosmiccore/lang/en_us.json b/src/generated/resources/assets/cosmiccore/lang/en_us.json index 726190536..d65b89044 100644 --- a/src/generated/resources/assets/cosmiccore/lang/en_us.json +++ b/src/generated/resources/assets/cosmiccore/lang/en_us.json @@ -484,6 +484,15 @@ "cosmic.gui.wireless.energy.player": "§aPlayer:§a %s", "cosmic.gui.wireless.energy.stored": "§eStorage §b%s §f%s/%s", "cosmic.gui.wireless.energy.team": "§aTeam:§a %s", + "cosmiccore.gui.soul.impure.name": "Impure", + "cosmiccore.gui.soul.rusted.name": "Rusted", + "cosmiccore.gui.soul.proud.name": "Proud", + "cosmiccore.gui.soul.greedy.name": "Greedy", + "cosmiccore.gui.soul.envious.name": "Envious", + "cosmiccore.gui.soul.gluttonous.name": "Gluttonous", + "cosmiccore.gui.soul.wrathful.name": "Wrathful", + "cosmiccore.gui.soul.slothful.name": "Slothful", + "cosmiccore.gui.soul.temporal.name": "Temporal", "cosmic.multiblock.capacitor.buffered": "§7Buffered: %s §7EU", "cosmic.multiblock.capacitor.duplicate.multiblock.1": "This multiblock is a duplicate", "cosmic.multiblock.capacitor.duplicate.multiblock.2": "Only one can exist", diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/capability/souls/SoulType.java b/src/main/java/com/ghostipedia/cosmiccore/api/capability/souls/SoulType.java index b8aec80dd..f0ac1c9ab 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/capability/souls/SoulType.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/capability/souls/SoulType.java @@ -1,7 +1,12 @@ package com.ghostipedia.cosmiccore.api.capability.souls; import com.mojang.serialization.Codec; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.network.chat.Style; import net.minecraft.util.StringRepresentable; +import net.minecraftforge.client.event.RenderTooltipEvent; import org.jetbrains.annotations.NotNull; import java.util.Arrays; @@ -10,20 +15,23 @@ import java.util.stream.Collectors; public enum SoulType implements StringRepresentable { - Impure("Impure"), - Rusted("Rusted"), - Proud("Proud"), - Greedy("Greedy"), - Envious("Envious"), - Gluttonous("Gluttonous"), - Wrathful("Wrathful"), - Slothful("Slothful"), - Temporal("Temporal"); + Impure("impure", ChatFormatting.DARK_GRAY), + Rusted("rusted", ChatFormatting.GRAY), + Proud("proud", ChatFormatting.DARK_PURPLE), + Greedy("greedy", ChatFormatting.YELLOW), + Envious("envious", ChatFormatting.GREEN), + Gluttonous("gluttonous", ChatFormatting.GOLD), + Wrathful("wrathful", ChatFormatting.RED), + Slothful("slothful", ChatFormatting.AQUA), + Temporal("temporal", ChatFormatting.DARK_AQUA); + private final String name; + private final ChatFormatting color; - SoulType(String name) { + SoulType(String name, ChatFormatting color) { this.name = name; + this.color = color; } @@ -39,4 +47,19 @@ public enum SoulType implements StringRepresentable { public static SoulType byName(String name) { return BY_NAME.get(name); } + + public Component toComponent(int amount) { + return toComponent(amount, true); + } + + public Component toComponent(int amount, boolean formatted) { + MutableComponent nameComp = Component.translatable("cosmiccore.gui.soul." + name + ".name"); + MutableComponent amountComp = Component.literal(" : " + amount).withStyle(Style.EMPTY); + if (formatted) { + nameComp = nameComp.withStyle(ChatFormatting.BOLD, this.color); + amountComp = amountComp.withStyle(ChatFormatting.RESET); + } + + return nameComp.append(amountComp); + } } diff --git a/src/main/java/com/ghostipedia/cosmiccore/common/data/CosmicMachines.java b/src/main/java/com/ghostipedia/cosmiccore/common/data/CosmicMachines.java index b484b49aa..d0746e561 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/common/data/CosmicMachines.java +++ b/src/main/java/com/ghostipedia/cosmiccore/common/data/CosmicMachines.java @@ -72,7 +72,6 @@ import static com.ghostipedia.cosmiccore.common.machine.multiblock.electric.hpca.HPCAMachine.*; import static com.ghostipedia.cosmiccore.gtbridge.CosmicRecipeTypes.BIO_LAB; import static com.gregtechceu.gtceu.api.GTValues.*; -import static com.gregtechceu.gtceu.api.capability.recipe.IO.IN; import static com.gregtechceu.gtceu.api.capability.recipe.IO.OUT; import static com.gregtechceu.gtceu.api.machine.property.GTMachineModelProperties.*; import static com.gregtechceu.gtceu.api.pattern.Predicates.*; @@ -85,7 +84,6 @@ import static com.gregtechceu.gtceu.common.data.GTRecipeTypes.CENTRIFUGE_RECIPES; import static com.gregtechceu.gtceu.common.data.GTRecipeTypes.DUMMY_RECIPES; import static com.gregtechceu.gtceu.common.data.machines.GTMachineUtils.*; -import static com.gregtechceu.gtceu.common.data.machines.GTMachineUtils.registerTieredMachines; import static com.gregtechceu.gtceu.common.data.machines.GTMultiMachines.FUSION_REACTOR; import static com.gregtechceu.gtceu.common.data.models.GTMachineModels.*; @@ -397,8 +395,10 @@ public class CosmicMachines { .where("S", abilities(CosmicPartAbility.IMPORT_SOUL).or(abilities(CosmicPartAbility.EXPORT_SOUL))) .where("I", abilities(PartAbility.EXPORT_ITEMS).or(abilities(PartAbility.IMPORT_ITEMS))) .build()) - .workableCasingModel(GTCEu.id("block/casings/solid/machine_casing_inert_ptfe"), GTCEu.id("block/multiblock/coke_oven")) + .workableCasingModel(GTCEu.id("block/casings/solid/machine_casing_inert_ptfe"), + GTCEu.id("block/multiblock/coke_oven")) .register(); + /* * public static final MultiblockMachineDefinition EMBER_TESTER = REGISTRATE.multiblock("ember_tester", * PrimitiveWorkableMachine::new) diff --git a/src/main/java/com/ghostipedia/cosmiccore/common/item/SoulNetworkReaderItem.java b/src/main/java/com/ghostipedia/cosmiccore/common/item/SoulNetworkReaderItem.java index 9f7c459eb..dd6cee455 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/common/item/SoulNetworkReaderItem.java +++ b/src/main/java/com/ghostipedia/cosmiccore/common/item/SoulNetworkReaderItem.java @@ -28,16 +28,11 @@ public InteractionResultHolder use(Level level, Player player, Intera SoulNetwork soulNetwork = SoulNetworkSavedData.getSoulNetwork(player.getUUID()); List contents = soulNetwork.getContents(); - player.sendSystemMessage(Component.literal("--- Soul Network Contents ---").withStyle(ChatFormatting.GOLD)); - if (contents.isEmpty()) { player.sendSystemMessage(Component.literal("Network is empty.").withStyle(ChatFormatting.GRAY)); } else { - for (SoulStack stack : contents) { - Component message = Component.literal(String.format("%s: %,d", stack.type().getSerializedName(), stack.amount())) - .withStyle(ChatFormatting.AQUA); - player.sendSystemMessage(message); - } + player.sendSystemMessage(Component.literal("--- Soul Network Contents ---").withStyle(ChatFormatting.GOLD)); + for (SoulStack stack : contents) player.sendSystemMessage(stack.type().toComponent(stack.amount())); } } return InteractionResultHolder.success(player.getItemInHand(hand)); From b4469fd8db2b02e2ecbdcec01ad521ffe72e05ea Mon Sep 17 00:00:00 2001 From: MrQuentinet <32539717+mrquentin@users.noreply.github.com> Date: Sat, 17 Jan 2026 16:22:17 -0500 Subject: [PATCH 06/28] kubejs soul output works input not yet ! --- .../cosmiccore/blockstates/soul_tester.json | 76 +++++++++++++++ .../cosmiccore/blockstates/star_ladder.json | 71 +------------- .../assets/cosmiccore/lang/en_ud.json | 2 + .../assets/cosmiccore/lang/en_us.json | 11 +-- .../models/block/machine/soul_tester.json | 90 ++++++++++++++++++ .../cosmiccore/models/item/soul_reader.json | 6 ++ .../cosmiccore/models/item/soul_tester.json | 3 + .../kjs/CosmicCoreKubeJSPlugin.java | 2 + .../kjs/recipe/CosmicCoreRecipeSchema.java | 10 +- .../components/CosmicRecipeComponent.java | 45 ++++++++- .../cosmiccore/textures/item/soul_reader.png | Bin 0 -> 269 bytes 11 files changed, 228 insertions(+), 88 deletions(-) create mode 100644 src/generated/resources/assets/cosmiccore/blockstates/soul_tester.json create mode 100644 src/generated/resources/assets/cosmiccore/models/block/machine/soul_tester.json create mode 100644 src/generated/resources/assets/cosmiccore/models/item/soul_reader.json create mode 100644 src/generated/resources/assets/cosmiccore/models/item/soul_tester.json create mode 100644 src/main/resources/assets/cosmiccore/textures/item/soul_reader.png diff --git a/src/generated/resources/assets/cosmiccore/blockstates/soul_tester.json b/src/generated/resources/assets/cosmiccore/blockstates/soul_tester.json new file mode 100644 index 000000000..48ee0184a --- /dev/null +++ b/src/generated/resources/assets/cosmiccore/blockstates/soul_tester.json @@ -0,0 +1,76 @@ +{ + "variants": { + "facing=east,upwards_facing=east": { + "gtceu:z": 270, + "model": "cosmiccore:block/machine/soul_tester", + "y": 90 + }, + "facing=east,upwards_facing=north": { + "model": "cosmiccore:block/machine/soul_tester", + "y": 90 + }, + "facing=east,upwards_facing=south": { + "gtceu:z": 180, + "model": "cosmiccore:block/machine/soul_tester", + "y": 90 + }, + "facing=east,upwards_facing=west": { + "gtceu:z": 90, + "model": "cosmiccore:block/machine/soul_tester", + "y": 90 + }, + "facing=north,upwards_facing=east": { + "gtceu:z": 270, + "model": "cosmiccore:block/machine/soul_tester" + }, + "facing=north,upwards_facing=north": { + "model": "cosmiccore:block/machine/soul_tester" + }, + "facing=north,upwards_facing=south": { + "gtceu:z": 180, + "model": "cosmiccore:block/machine/soul_tester" + }, + "facing=north,upwards_facing=west": { + "gtceu:z": 90, + "model": "cosmiccore:block/machine/soul_tester" + }, + "facing=south,upwards_facing=east": { + "gtceu:z": 270, + "model": "cosmiccore:block/machine/soul_tester", + "y": 180 + }, + "facing=south,upwards_facing=north": { + "model": "cosmiccore:block/machine/soul_tester", + "y": 180 + }, + "facing=south,upwards_facing=south": { + "gtceu:z": 180, + "model": "cosmiccore:block/machine/soul_tester", + "y": 180 + }, + "facing=south,upwards_facing=west": { + "gtceu:z": 90, + "model": "cosmiccore:block/machine/soul_tester", + "y": 180 + }, + "facing=west,upwards_facing=east": { + "gtceu:z": 270, + "model": "cosmiccore:block/machine/soul_tester", + "y": 270 + }, + "facing=west,upwards_facing=north": { + "model": "cosmiccore:block/machine/soul_tester", + "y": 270 + }, + "facing=west,upwards_facing=south": { + "gtceu:z": 180, + "model": "cosmiccore:block/machine/soul_tester", + "y": 270 + }, + "facing=west,upwards_facing=west": { + "gtceu:z": 90, + "model": "cosmiccore:block/machine/soul_tester", + "y": 270 + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/cosmiccore/blockstates/star_ladder.json b/src/generated/resources/assets/cosmiccore/blockstates/star_ladder.json index ad9a7da96..e1e4793e5 100644 --- a/src/generated/resources/assets/cosmiccore/blockstates/star_ladder.json +++ b/src/generated/resources/assets/cosmiccore/blockstates/star_ladder.json @@ -1,76 +1,7 @@ { "variants": { - "facing=east,upwards_facing=east": { - "gtceu:z": 270, - "model": "cosmiccore:block/machine/star_ladder", - "y": 90 - }, - "facing=east,upwards_facing=north": { - "model": "cosmiccore:block/machine/star_ladder", - "y": 90 - }, - "facing=east,upwards_facing=south": { - "gtceu:z": 180, - "model": "cosmiccore:block/machine/star_ladder", - "y": 90 - }, - "facing=east,upwards_facing=west": { - "gtceu:z": 90, - "model": "cosmiccore:block/machine/star_ladder", - "y": 90 - }, - "facing=north,upwards_facing=east": { - "gtceu:z": 270, + "": { "model": "cosmiccore:block/machine/star_ladder" - }, - "facing=north,upwards_facing=north": { - "model": "cosmiccore:block/machine/star_ladder" - }, - "facing=north,upwards_facing=south": { - "gtceu:z": 180, - "model": "cosmiccore:block/machine/star_ladder" - }, - "facing=north,upwards_facing=west": { - "gtceu:z": 90, - "model": "cosmiccore:block/machine/star_ladder" - }, - "facing=south,upwards_facing=east": { - "gtceu:z": 270, - "model": "cosmiccore:block/machine/star_ladder", - "y": 180 - }, - "facing=south,upwards_facing=north": { - "model": "cosmiccore:block/machine/star_ladder", - "y": 180 - }, - "facing=south,upwards_facing=south": { - "gtceu:z": 180, - "model": "cosmiccore:block/machine/star_ladder", - "y": 180 - }, - "facing=south,upwards_facing=west": { - "gtceu:z": 90, - "model": "cosmiccore:block/machine/star_ladder", - "y": 180 - }, - "facing=west,upwards_facing=east": { - "gtceu:z": 270, - "model": "cosmiccore:block/machine/star_ladder", - "y": 270 - }, - "facing=west,upwards_facing=north": { - "model": "cosmiccore:block/machine/star_ladder", - "y": 270 - }, - "facing=west,upwards_facing=south": { - "gtceu:z": 180, - "model": "cosmiccore:block/machine/star_ladder", - "y": 270 - }, - "facing=west,upwards_facing=west": { - "gtceu:z": 90, - "model": "cosmiccore:block/machine/star_ladder", - "y": 270 } } } \ No newline at end of file diff --git a/src/generated/resources/assets/cosmiccore/lang/en_ud.json b/src/generated/resources/assets/cosmiccore/lang/en_ud.json index 72cf8a47d..b8032c73a 100644 --- a/src/generated/resources/assets/cosmiccore/lang/en_ud.json +++ b/src/generated/resources/assets/cosmiccore/lang/en_ud.json @@ -265,6 +265,7 @@ "block.cosmiccore.sensor_hatch": "ɥɔʇɐH ɹosuǝS", "block.cosmiccore.shimmering_neutronium_coil_block": "ʞɔoןᗺ ןıoƆ ɯnıuoɹʇnǝN buıɹǝɯɯıɥS", "block.cosmiccore.soul_stained_steel_aluminium_plated_casing": "buısɐƆ pǝʇɐןԀ ɯnıuıɯnןⱯ ןǝǝʇS pǝuıɐʇS ןnoS", + "block.cosmiccore.soul_tester": "ɹǝʇsǝ⟘ ןnoS", "block.cosmiccore.spirit_crucible": "ǝןqıɔnɹƆ ʇıɹıdS", "block.cosmiccore.star_ladder": "ɹǝppɐꞀ ɹɐʇS", "block.cosmiccore.steam_caster": "ɹǝʇsɐƆ ɯɐǝʇS", @@ -981,6 +982,7 @@ "item.cosmiccore.seraphon": "]uoɥdɐɹǝS[ - uouıɯnꞀ", "item.cosmiccore.shard_of_perpetuity": "ʎʇınʇǝdɹǝԀ ɟo pɹɐɥS", "item.cosmiccore.somatic_processing_assembly": "pɹɐoᗺ ʎןqɯǝssⱯ buıssǝɔoɹdoʇɐɯoS", + "item.cosmiccore.soul_reader": "ɹǝpɐǝᴚ ʞɹoʍʇǝN ןnoS", "item.cosmiccore.sov_blood_orb": "qɹO pooןᗺ ubıǝɹǝʌoS", "item.cosmiccore.space_advanced_nanomuscle_chestplate": "ǝʇɐןdʇsǝɥƆ ǝʇınS ǝɔɐdS ™ǝןɔsnWouɐN pǝɔuɐʌpⱯ", "item.cosmiccore.space_advanced_quarktech_chestplate": "ǝʇɐןdʇsǝɥƆ ǝʇınS ǝɔɐdS ™ɥɔǝ⟘ʞɹɐnὉ pǝɔuɐʌpⱯ", diff --git a/src/generated/resources/assets/cosmiccore/lang/en_us.json b/src/generated/resources/assets/cosmiccore/lang/en_us.json index d65b89044..a3d2ea474 100644 --- a/src/generated/resources/assets/cosmiccore/lang/en_us.json +++ b/src/generated/resources/assets/cosmiccore/lang/en_us.json @@ -265,6 +265,7 @@ "block.cosmiccore.sensor_hatch": "Sensor Hatch", "block.cosmiccore.shimmering_neutronium_coil_block": "Shimmering Neutronium Coil Block", "block.cosmiccore.soul_stained_steel_aluminium_plated_casing": "Soul Stained Steel Aluminium Plated Casing", + "block.cosmiccore.soul_tester": "Soul Tester", "block.cosmiccore.spirit_crucible": "Spirit Crucible", "block.cosmiccore.star_ladder": "Star Ladder", "block.cosmiccore.steam_caster": "Steam Caster", @@ -484,15 +485,6 @@ "cosmic.gui.wireless.energy.player": "§aPlayer:§a %s", "cosmic.gui.wireless.energy.stored": "§eStorage §b%s §f%s/%s", "cosmic.gui.wireless.energy.team": "§aTeam:§a %s", - "cosmiccore.gui.soul.impure.name": "Impure", - "cosmiccore.gui.soul.rusted.name": "Rusted", - "cosmiccore.gui.soul.proud.name": "Proud", - "cosmiccore.gui.soul.greedy.name": "Greedy", - "cosmiccore.gui.soul.envious.name": "Envious", - "cosmiccore.gui.soul.gluttonous.name": "Gluttonous", - "cosmiccore.gui.soul.wrathful.name": "Wrathful", - "cosmiccore.gui.soul.slothful.name": "Slothful", - "cosmiccore.gui.soul.temporal.name": "Temporal", "cosmic.multiblock.capacitor.buffered": "§7Buffered: %s §7EU", "cosmic.multiblock.capacitor.duplicate.multiblock.1": "This multiblock is a duplicate", "cosmic.multiblock.capacitor.duplicate.multiblock.2": "Only one can exist", @@ -990,6 +982,7 @@ "item.cosmiccore.seraphon": "Luminon - [Seraphon]", "item.cosmiccore.shard_of_perpetuity": "Shard of Perpetuity", "item.cosmiccore.somatic_processing_assembly": "Somatoprocessing Assembly Board", + "item.cosmiccore.soul_reader": "Soul Network Reader", "item.cosmiccore.sov_blood_orb": "Sovereign Blood Orb", "item.cosmiccore.space_advanced_nanomuscle_chestplate": "Advanced NanoMuscle™ Space Suite Chestplate", "item.cosmiccore.space_advanced_quarktech_chestplate": "Advanced QuarkTech™ Space Suite Chestplate", diff --git a/src/generated/resources/assets/cosmiccore/models/block/machine/soul_tester.json b/src/generated/resources/assets/cosmiccore/models/block/machine/soul_tester.json new file mode 100644 index 000000000..af218192d --- /dev/null +++ b/src/generated/resources/assets/cosmiccore/models/block/machine/soul_tester.json @@ -0,0 +1,90 @@ +{ + "parent": "minecraft:block/block", + "loader": "gtceu:machine", + "machine": "cosmiccore:soul_tester", + "texture_overrides": { + "all": "gtceu:block/casings/solid/machine_casing_inert_ptfe" + }, + "variants": { + "is_formed=false,recipe_logic_status=idle": { + "model": { + "parent": "gtceu:block/machine/template/cube_all/sided", + "textures": { + "all": "gtceu:block/casings/solid/machine_casing_inert_ptfe", + "overlay_front": "gtceu:block/multiblock/coke_oven/overlay_front", + "overlay_front_emissive": "gtceu:block/multiblock/coke_oven/overlay_front_emissive" + } + } + }, + "is_formed=false,recipe_logic_status=suspend": { + "model": { + "parent": "gtceu:block/machine/template/cube_all/sided", + "textures": { + "all": "gtceu:block/casings/solid/machine_casing_inert_ptfe", + "overlay_front": "gtceu:block/multiblock/coke_oven/overlay_front", + "overlay_front_emissive": "gtceu:block/multiblock/coke_oven/overlay_front_emissive" + } + } + }, + "is_formed=false,recipe_logic_status=waiting": { + "model": { + "parent": "gtceu:block/machine/template/cube_all/sided", + "textures": { + "all": "gtceu:block/casings/solid/machine_casing_inert_ptfe", + "overlay_front": "gtceu:block/multiblock/coke_oven/overlay_front_active", + "overlay_front_emissive": "gtceu:block/multiblock/coke_oven/overlay_front_active_emissive" + } + } + }, + "is_formed=false,recipe_logic_status=working": { + "model": { + "parent": "gtceu:block/machine/template/cube_all/sided", + "textures": { + "all": "gtceu:block/casings/solid/machine_casing_inert_ptfe", + "overlay_front": "gtceu:block/multiblock/coke_oven/overlay_front_active", + "overlay_front_emissive": "gtceu:block/multiblock/coke_oven/overlay_front_active_emissive" + } + } + }, + "is_formed=true,recipe_logic_status=idle": { + "model": { + "parent": "gtceu:block/machine/template/cube_all/sided", + "textures": { + "all": "gtceu:block/casings/solid/machine_casing_inert_ptfe", + "overlay_front": "gtceu:block/multiblock/coke_oven/overlay_front", + "overlay_front_emissive": "gtceu:block/multiblock/coke_oven/overlay_front_emissive" + } + } + }, + "is_formed=true,recipe_logic_status=suspend": { + "model": { + "parent": "gtceu:block/machine/template/cube_all/sided", + "textures": { + "all": "gtceu:block/casings/solid/machine_casing_inert_ptfe", + "overlay_front": "gtceu:block/multiblock/coke_oven/overlay_front", + "overlay_front_emissive": "gtceu:block/multiblock/coke_oven/overlay_front_emissive" + } + } + }, + "is_formed=true,recipe_logic_status=waiting": { + "model": { + "parent": "gtceu:block/machine/template/cube_all/sided", + "textures": { + "all": "gtceu:block/casings/solid/machine_casing_inert_ptfe", + "overlay_front": "gtceu:block/multiblock/coke_oven/overlay_front_active", + "overlay_front_emissive": "gtceu:block/multiblock/coke_oven/overlay_front_active_emissive" + } + } + }, + "is_formed=true,recipe_logic_status=working": { + "model": { + "parent": "gtceu:block/machine/template/cube_all/sided", + "textures": { + "all": "gtceu:block/casings/solid/machine_casing_inert_ptfe", + "overlay_front": "gtceu:block/multiblock/coke_oven/overlay_front_active", + "overlay_front_emissive": "gtceu:block/multiblock/coke_oven/overlay_front_active_emissive" + } + } + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/cosmiccore/models/item/soul_reader.json b/src/generated/resources/assets/cosmiccore/models/item/soul_reader.json new file mode 100644 index 000000000..28c03ad37 --- /dev/null +++ b/src/generated/resources/assets/cosmiccore/models/item/soul_reader.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "cosmiccore:item/soul_reader" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/cosmiccore/models/item/soul_tester.json b/src/generated/resources/assets/cosmiccore/models/item/soul_tester.json new file mode 100644 index 000000000..29eddc535 --- /dev/null +++ b/src/generated/resources/assets/cosmiccore/models/item/soul_tester.json @@ -0,0 +1,3 @@ +{ + "parent": "cosmiccore:block/machine/soul_tester" +} \ No newline at end of file diff --git a/src/main/java/com/ghostipedia/cosmiccore/integration/kjs/CosmicCoreKubeJSPlugin.java b/src/main/java/com/ghostipedia/cosmiccore/integration/kjs/CosmicCoreKubeJSPlugin.java index 875e2b221..4ebe0fd54 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/integration/kjs/CosmicCoreKubeJSPlugin.java +++ b/src/main/java/com/ghostipedia/cosmiccore/integration/kjs/CosmicCoreKubeJSPlugin.java @@ -1,6 +1,7 @@ package com.ghostipedia.cosmiccore.integration.kjs; import com.ghostipedia.cosmiccore.CosmicCore; +import com.ghostipedia.cosmiccore.api.capability.souls.SoulType; import com.ghostipedia.cosmiccore.common.data.CosmicBlocks; import com.ghostipedia.cosmiccore.common.data.CosmicItems; import com.ghostipedia.cosmiccore.common.data.CosmicMachines; @@ -63,6 +64,7 @@ public void registerBindings(BindingsEvent event) { event.add("CosmicMachines", CosmicMachines.class); event.add("CosmicItems", CosmicItems.class); event.add("CosmicRecipeTypes", CosmicRecipeTypes.class); + event.add("CosmicSoulTypes", SoulType.class); event.add("CosmicCore", CosmicCore.class); } diff --git a/src/main/java/com/ghostipedia/cosmiccore/integration/kjs/recipe/CosmicCoreRecipeSchema.java b/src/main/java/com/ghostipedia/cosmiccore/integration/kjs/recipe/CosmicCoreRecipeSchema.java index b6eb267c2..4e34ba7aa 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/integration/kjs/recipe/CosmicCoreRecipeSchema.java +++ b/src/main/java/com/ghostipedia/cosmiccore/integration/kjs/recipe/CosmicCoreRecipeSchema.java @@ -3,6 +3,8 @@ import com.ghostipedia.cosmiccore.api.capability.recipe.EmberRecipeCapability; import com.ghostipedia.cosmiccore.api.capability.recipe.SoulRecipeCapability; import com.ghostipedia.cosmiccore.api.capability.recipe.SterileRecipeCapability; +import com.ghostipedia.cosmiccore.api.capability.souls.SoulType; +import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulIngredient; import com.ghostipedia.cosmiccore.common.recipe.condition.TitanCondition; import com.gregtechceu.gtceu.integration.kjs.recipe.GTRecipeSchema; @@ -19,12 +21,12 @@ public interface CosmicCoreRecipeSchema { @Accessors(chain = true, fluent = true) class CosmicRecipeJS extends GTRecipeSchema.GTRecipeJS { - public GTRecipeSchema.GTRecipeJS soulInput(int souls) { - return this.input(SoulRecipeCapability.CAP, souls); + public GTRecipeSchema.GTRecipeJS soulInput(SoulType type, int souls) { + return this.input(SoulRecipeCapability.CAP, SoulIngredient.of(type, souls)); } - public GTRecipeSchema.GTRecipeJS soulOutput(int souls) { - return this.output(SoulRecipeCapability.CAP, souls); + public GTRecipeSchema.GTRecipeJS soulOutput(SoulType type, int souls) { + return this.output(SoulRecipeCapability.CAP, SoulIngredient.of(type, souls)); } public GTRecipeSchema.GTRecipeJS titanTier(int tier) { diff --git a/src/main/java/com/ghostipedia/cosmiccore/integration/kjs/recipe/components/CosmicRecipeComponent.java b/src/main/java/com/ghostipedia/cosmiccore/integration/kjs/recipe/components/CosmicRecipeComponent.java index 22bbcbd2f..908f2ed64 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/integration/kjs/recipe/components/CosmicRecipeComponent.java +++ b/src/main/java/com/ghostipedia/cosmiccore/integration/kjs/recipe/components/CosmicRecipeComponent.java @@ -3,21 +3,56 @@ import com.ghostipedia.cosmiccore.api.capability.recipe.EmberRecipeCapability; import com.ghostipedia.cosmiccore.api.capability.recipe.SoulRecipeCapability; +import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulIngredient; +import com.google.gson.JsonElement; import com.gregtechceu.gtceu.integration.kjs.recipe.components.ContentJS; +import com.mojang.serialization.JsonOps; +import dev.latvian.mods.kubejs.recipe.RecipeJS; import dev.latvian.mods.kubejs.recipe.component.NumberComponent; +import dev.latvian.mods.kubejs.recipe.component.RecipeComponent; +import dev.latvian.mods.rhino.Wrapper; public class CosmicRecipeComponent { - public static final ContentJS SOUL_IN = new ContentJS<>(NumberComponent.ANY_INT, SoulRecipeCapability.CAP, - false); - public static final ContentJS SOUL_OUT = new ContentJS<>(NumberComponent.ANY_INT, SoulRecipeCapability.CAP, - true); - public static final ContentJS EMBER_IN = new ContentJS<>(NumberComponent.ANY_DOUBLE, EmberRecipeCapability.CAP, false); public static final ContentJS EMBER_OUT = new ContentJS<>(NumberComponent.ANY_DOUBLE, EmberRecipeCapability.CAP, true); + + public static final RecipeComponent SOUL_STACK = new RecipeComponent<>() { + + @Override + public Class componentClass() { + return SoulIngredient.class; + } + + @Override + public String componentType() { + return "soul_stack"; + } + + @Override + public JsonElement write(RecipeJS recipeJS, SoulIngredient soulIngredient) { + return SoulIngredient.CODEC.encodeStart(JsonOps.INSTANCE, soulIngredient).result().orElse(null); + } + + @Override + public SoulIngredient read(RecipeJS recipeJS, Object o) { + if (o instanceof Wrapper w) o = w.unwrap(); + + if (o instanceof SoulIngredient soulIngredient) { + return soulIngredient; + } else { + return null; + } + } + }; + + public static final ContentJS SOUL_IN = new ContentJS<>(SOUL_STACK, SoulRecipeCapability.CAP, + false); + public static final ContentJS SOUL_OUT = new ContentJS<>(SOUL_STACK, SoulRecipeCapability.CAP, + true); } diff --git a/src/main/resources/assets/cosmiccore/textures/item/soul_reader.png b/src/main/resources/assets/cosmiccore/textures/item/soul_reader.png new file mode 100644 index 0000000000000000000000000000000000000000..b900d2016df8fd3c4c06c9b16d3ccbcd890cad65 GIT binary patch literal 269 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFhtGXS2rmyU%Rer z;-sw;r24Xjqm$FhVx@G9O$9{7$_}tO097-V1o;IsI6S+N2IRzhx;TbZ+)8#}onx%{ zW!2P1X$O=3OOV literal 0 HcmV?d00001 From d0d12a03a7a2971a26923577fbb9d1057648f2b8 Mon Sep 17 00:00:00 2001 From: MrQuentinet <32539717+mrquentin@users.noreply.github.com> Date: Sat, 17 Jan 2026 16:29:25 -0500 Subject: [PATCH 07/28] Add missing soul types --- .../cosmiccore/api/capability/souls/SoulType.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/capability/souls/SoulType.java b/src/main/java/com/ghostipedia/cosmiccore/api/capability/souls/SoulType.java index f0ac1c9ab..7ba02efc7 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/capability/souls/SoulType.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/capability/souls/SoulType.java @@ -15,10 +15,11 @@ import java.util.stream.Collectors; public enum SoulType implements StringRepresentable { - Impure("impure", ChatFormatting.DARK_GRAY), - Rusted("rusted", ChatFormatting.GRAY), + Raw("raw", ChatFormatting.DARK_RED), + Refined("refined", ChatFormatting.GRAY), Proud("proud", ChatFormatting.DARK_PURPLE), Greedy("greedy", ChatFormatting.YELLOW), + Lustful("lustful", ChatFormatting.LIGHT_PURPLE), Envious("envious", ChatFormatting.GREEN), Gluttonous("gluttonous", ChatFormatting.GOLD), Wrathful("wrathful", ChatFormatting.RED), From 6a54e39b63d4fb9bc9d667f3db6252959c83e4cd Mon Sep 17 00:00:00 2001 From: MrQuentinet <32539717+mrquentin@users.noreply.github.com> Date: Mon, 19 Jan 2026 14:12:04 -0500 Subject: [PATCH 08/28] Add more kjs integration --- .../api/capability/recipe/SoulRecipeCapability.java | 4 ++-- .../cosmiccore/api/recipe/ingredient/SoulStack.java | 2 +- .../ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java | 2 +- .../kjs/recipe/components/CosmicRecipeComponent.java | 2 ++ 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/capability/recipe/SoulRecipeCapability.java b/src/main/java/com/ghostipedia/cosmiccore/api/capability/recipe/SoulRecipeCapability.java index 228607494..669cf5923 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/capability/recipe/SoulRecipeCapability.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/capability/recipe/SoulRecipeCapability.java @@ -87,12 +87,12 @@ private static class SerializerSoulIngredient implements IContentSerializer provider) { SOUL_TESTER_RECIPES.recipeBuilder("generate_soul") .notConsumable(Items.DIRT) - .output(CosmicRecipeCapabilities.SOUL, SoulIngredient.of(SoulType.Impure, 10)) + .output(CosmicRecipeCapabilities.SOUL, SoulIngredient.of(SoulType.Raw, 10)) .output(CosmicRecipeCapabilities.SOUL, SoulIngredient.of(SoulType.Temporal, 50)) .duration(20) .save(provider); diff --git a/src/main/java/com/ghostipedia/cosmiccore/integration/kjs/recipe/components/CosmicRecipeComponent.java b/src/main/java/com/ghostipedia/cosmiccore/integration/kjs/recipe/components/CosmicRecipeComponent.java index 908f2ed64..73c07cb2e 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/integration/kjs/recipe/components/CosmicRecipeComponent.java +++ b/src/main/java/com/ghostipedia/cosmiccore/integration/kjs/recipe/components/CosmicRecipeComponent.java @@ -46,6 +46,8 @@ public SoulIngredient read(RecipeJS recipeJS, Object o) { if (o instanceof SoulIngredient soulIngredient) { return soulIngredient; } else { + System.out.println("Shit we have a problem !"); + System.out.println("object type: " + o.getClass().descriptorString()); return null; } } From 7f7343c3112299820e80ae7447ae3b14be6930ce Mon Sep 17 00:00:00 2001 From: MrQuentinet <32539717+mrquentin@users.noreply.github.com> Date: Fri, 28 Nov 2025 22:43:32 -0500 Subject: [PATCH 09/28] OMG it works ! Still missing a lot of features but at least it works --- .../api/capability/ISoulContainer.java | 15 +---- .../api/data/souls/SoulNetwork.java | 42 ++++++++++++++ .../api/data/souls/SoulNetworkSavedData.java | 57 +++++++++++++++++++ .../trait/NotifiableSoulContainer.java | 52 +++++++---------- .../common/data/CosmicMachines.java | 27 +++++---- .../multiblock/part/SoulHatchPartMachine.java | 30 ++++------ .../forge/ForgeCommonEventListener.java | 9 --- .../gtbridge/CosmicCoreRecipes.java | 10 ++++ 8 files changed, 154 insertions(+), 88 deletions(-) create mode 100644 src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java create mode 100644 src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetworkSavedData.java diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/capability/ISoulContainer.java b/src/main/java/com/ghostipedia/cosmiccore/api/capability/ISoulContainer.java index 472f01c68..facaad4a8 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/capability/ISoulContainer.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/capability/ISoulContainer.java @@ -1,22 +1,11 @@ package com.ghostipedia.cosmiccore.api.capability; -import wayoftime.bloodmagic.core.data.SoulNetwork; +import com.ghostipedia.cosmiccore.api.data.souls.SoulNetwork; import java.util.UUID; public interface ISoulContainer { - - /** - * @return the UUID of the player associated to the container's network - */ - UUID getOwner(); - - /** - * @param playerUUID: the player to whom we attach the container - */ - void setOwner(UUID playerUUID); - - /** + /** * @return the soul network attached to the container */ SoulNetwork getSoulNetwork(); diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java b/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java new file mode 100644 index 000000000..6166fbb96 --- /dev/null +++ b/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java @@ -0,0 +1,42 @@ +package com.ghostipedia.cosmiccore.api.data.souls; + +import lombok.Getter; +import net.minecraft.nbt.CompoundTag; +import net.minecraftforge.common.util.INBTSerializable; + +import java.util.UUID; + +public class SoulNetwork implements INBTSerializable { + + @Getter + private int tier = 0, currentSouls = 0; + + public SoulNetwork() {} + + public int add(int amount, int max) { + int oldSouls = this.currentSouls; + if (oldSouls >= max) return 0; + else { + int newSouls = Math.min(max, oldSouls + amount); + this.currentSouls = newSouls; + return newSouls - oldSouls; + } + } + + public int syphon(int amount) { + if (this.currentSouls >= amount) { + this.currentSouls -= amount; + return amount; + } else return 0; + } + + @Override + public CompoundTag serializeNBT() { + return null; + } + + @Override + public void deserializeNBT(CompoundTag compoundTag) {} + + +} diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetworkSavedData.java b/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetworkSavedData.java new file mode 100644 index 000000000..74eb2ed3f --- /dev/null +++ b/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetworkSavedData.java @@ -0,0 +1,57 @@ +package com.ghostipedia.cosmiccore.api.data.souls; + +import com.ghostipedia.cosmiccore.CosmicCore; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.saveddata.SavedData; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.UUID; + +public class SoulNetworkSavedData extends SavedData { + + private static final String DATA_NAME = CosmicCore.MOD_ID + "_soul_network_data"; + private static final String SOUL_NETWORK_MAPPING = "soul_network_mapping"; + private static final String SOUL_NETWORK_UUID = "soul_network_uuid"; + private static final String SOUL_NETWORK_DATA = "soul_network_data"; + + public static final HashMap SoulNetworkMapping = new HashMap<>(20, 0.9f); + + public static SoulNetworkSavedData getOrCreate(ServerLevel serverLevel) { + return serverLevel.getDataStorage().computeIfAbsent(SoulNetworkSavedData::new, SoulNetworkSavedData::new, DATA_NAME); + } + + public static SoulNetwork getSoulNetwork(UUID owner) { + return SoulNetworkMapping.computeIfAbsent(owner, id -> new SoulNetwork()); + } + + private SoulNetworkSavedData() {} + + private SoulNetworkSavedData(CompoundTag nbt) { + var list = nbt.getList(SOUL_NETWORK_MAPPING, CompoundTag.TAG_COMPOUND); + for (Tag tag : list) { + if (tag instanceof CompoundTag compoundTag) { + var uuid = UUID.fromString(compoundTag.getString(SOUL_NETWORK_UUID)); + var data = new SoulNetwork(); + data.deserializeNBT(compoundTag.getCompound(SOUL_NETWORK_DATA)); + SoulNetworkMapping.put(uuid, data); + } + } + } + + @Override + public @NotNull CompoundTag save(@NotNull CompoundTag compoundTag) { + var soulNetworkDataList = new ListTag(); + for (var entry : SoulNetworkMapping.entrySet()) { + var tag = new CompoundTag(); + tag.putString(SOUL_NETWORK_UUID, entry.getKey().toString()); + tag.put(SOUL_NETWORK_DATA, entry.getValue().serializeNBT()); + soulNetworkDataList.add(tag); + } + compoundTag.put(SOUL_NETWORK_MAPPING, soulNetworkDataList); + return compoundTag; + } +} diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java b/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java index 4383432dd..329b6883a 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java @@ -3,6 +3,8 @@ import com.ghostipedia.cosmiccore.api.capability.ISoulContainer; import com.ghostipedia.cosmiccore.api.capability.recipe.SoulRecipeCapability; +import com.ghostipedia.cosmiccore.api.data.souls.SoulNetwork; +import com.ghostipedia.cosmiccore.api.data.souls.SoulNetworkSavedData; import com.gregtechceu.gtceu.api.capability.recipe.IO; import com.gregtechceu.gtceu.api.capability.recipe.RecipeCapability; import com.gregtechceu.gtceu.api.machine.ConditionalSubscriptionHandler; @@ -10,14 +12,12 @@ import com.gregtechceu.gtceu.api.machine.trait.NotifiableRecipeHandlerTrait; import com.gregtechceu.gtceu.api.recipe.GTRecipe; +import com.gregtechceu.gtceu.common.machine.owner.FTBOwner; import com.lowdragmc.lowdraglib.syncdata.annotation.DescSynced; import com.lowdragmc.lowdraglib.syncdata.annotation.Persisted; import com.lowdragmc.lowdraglib.syncdata.field.ManagedFieldHolder; import lombok.Getter; -import wayoftime.bloodmagic.core.data.SoulNetwork; -import wayoftime.bloodmagic.core.data.SoulTicket; -import wayoftime.bloodmagic.util.helper.NetworkHelper; import java.util.Collections; import java.util.List; @@ -32,11 +32,6 @@ public class NotifiableSoulContainer extends NotifiableRecipeHandlerTrait owner != null); + // TODO: simplify to remove conditional that is not needed + conditionalSubscriptionHandler = new ConditionalSubscriptionHandler(machine, this::querySoulNetwork, () -> true); } private void querySoulNetwork() { @@ -63,7 +58,7 @@ private void querySoulNetwork() { var network = this.getSoulNetwork(); if (network == null) return; - var essence = network.getCurrentEssence(); + var essence = network.getCurrentSouls(); if (this.currentEssence == essence) return; this.currentEssence = essence; @@ -71,23 +66,17 @@ private void querySoulNetwork() { } @Override - public List handleRecipeInner(IO io, GTRecipe recipe, List left, - boolean simulate) { + public List handleRecipeInner(IO io, GTRecipe recipe, List left, boolean simulate) { ISoulContainer container = this; - if (container.getOwner() == null) return null; int lifeEssence = left.stream().reduce(0, Integer::sum); if (io == IO.IN) { - var canOutput = Math.min(this.maxConsumption, container.getSoulNetwork().getCurrentEssence()); - if (!simulate) lifeEssence = container.getSoulNetwork().syphon( - SoulTicket.block(this.machine.getLevel(), this.machine.getPos(), Math.min(canOutput, lifeEssence)), - false); + var canOutput = Math.min(this.maxConsumption, container.getSoulNetwork().getCurrentSouls()); + if (!simulate) lifeEssence = container.getSoulNetwork().syphon(Math.min(canOutput, lifeEssence)); lifeEssence = lifeEssence - canOutput; } else if (io == IO.OUT) { - var canInput = this.maxCapacity - container.getSoulNetwork().getCurrentEssence(); - if (!simulate) lifeEssence = container.getSoulNetwork().add( - SoulTicket.block(this.machine.getLevel(), this.machine.getPos(), Math.min(canInput, lifeEssence)), - this.maxCapacity); + var canInput = this.maxCapacity - container.getSoulNetwork().getCurrentSouls(); + if (!simulate) lifeEssence = container.getSoulNetwork().add(Math.min(canInput, lifeEssence), this.maxCapacity); lifeEssence = lifeEssence - canInput; } @@ -96,14 +85,12 @@ public List handleRecipeInner(IO io, GTRecipe recipe, List lef @Override public List getContents() { - if (this.owner == null) return Collections.emptyList(); - return List.of(this.getSoulNetwork().getCurrentEssence()); + return List.of(this.getSoulNetwork().getCurrentSouls()); } @Override public double getTotalContentAmount() { - if (this.owner == null) return 0; - return this.getSoulNetwork().getCurrentEssence(); + return this.getSoulNetwork().getCurrentSouls(); } @Override @@ -118,18 +105,17 @@ public ManagedFieldHolder getFieldHolder() { @Override public SoulNetwork getSoulNetwork() { - return NetworkHelper.getSoulNetwork(this.owner); + return SoulNetworkSavedData.getSoulNetwork(getOwner()); } - @Override - public int getSize() { - return 1; + public UUID getOwner() { + var team = ((FTBOwner) this.machine.getOwner()).getPlayerTeam(this.machine.getOwnerUUID()); + return team != null ? team.getTeamId() : this.machine.getOwnerUUID(); } @Override - public void setOwner(UUID owner) { - this.owner = owner; - conditionalSubscriptionHandler.updateSubscription(); + public int getSize() { + return 1; } @Override diff --git a/src/main/java/com/ghostipedia/cosmiccore/common/data/CosmicMachines.java b/src/main/java/com/ghostipedia/cosmiccore/common/data/CosmicMachines.java index 7a7da3c30..ccb87176f 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/common/data/CosmicMachines.java +++ b/src/main/java/com/ghostipedia/cosmiccore/common/data/CosmicMachines.java @@ -49,6 +49,7 @@ import com.gregtechceu.gtceu.common.machine.multiblock.electric.PowerSubstationMachine; import com.gregtechceu.gtceu.common.machine.multiblock.part.EnergyHatchPartMachine; import com.gregtechceu.gtceu.common.machine.multiblock.part.FluidHatchPartMachine; +import com.gregtechceu.gtceu.common.machine.multiblock.primitive.PrimitiveWorkableMachine; import com.gregtechceu.gtceu.config.ConfigHolder; import com.gregtechceu.gtceu.utils.FormattingUtil; @@ -386,20 +387,18 @@ public class CosmicMachines { GTValues.tiersBetween(ULV, HV)); // Enable If needed Inside of Dev - // public static final MultiblockMachineDefinition SOUL_TESTER = REGISTRATE.multiblock("soul_tester", - // PrimitiveWorkableMachine::new) - // .rotationState(RotationState.NON_Y_AXIS) - // .recipeType(CosmicCoreRecipeTypes.SOUL_TESTER_RECIPES) - // .appearanceBlock(GTBlocks.CASING_PRIMITIVE_BRICKS) - // .pattern(definition -> FactoryBlockPattern.start() - // .aisle("S", "C", "I") - // .where("C", controller(blocks(definition.getBlock()))) - // .where("S", abilities(CosmicPartAbility.IMPORT_SOUL).or(abilities(CosmicPartAbility.EXPORT_SOUL))) - // .where("I", abilities(PartAbility.EXPORT_ITEMS).or(abilities(PartAbility.IMPORT_ITEMS))) - // .build()) - // .workableCasingModel(GTCEu.id("block/casings/solid/machine_casing_inert_ptfe"), - // GTCEu.id("block/multiblock/coke_oven")) - // .register(); + public static final MultiblockMachineDefinition SOUL_TESTER = REGISTRATE.multiblock("soul_tester", PrimitiveWorkableMachine::new) + .rotationState(RotationState.NON_Y_AXIS) + .recipeType(CosmicRecipeTypes.SOUL_TESTER_RECIPES) + .appearanceBlock(GTBlocks.CASING_PRIMITIVE_BRICKS) + .pattern(definition -> FactoryBlockPattern.start() + .aisle("S", "C", "I") + .where("C", controller(blocks(definition.getBlock()))) + .where("S", abilities(CosmicPartAbility.IMPORT_SOUL).or(abilities(CosmicPartAbility.EXPORT_SOUL))) + .where("I", abilities(PartAbility.EXPORT_ITEMS).or(abilities(PartAbility.IMPORT_ITEMS))) + .build()) + .workableCasingModel(GTCEu.id("block/casings/solid/machine_casing_inert_ptfe"), GTCEu.id("block/multiblock/coke_oven")) + .register(); /* * public static final MultiblockMachineDefinition EMBER_TESTER = REGISTRATE.multiblock("ember_tester", * PrimitiveWorkableMachine::new) diff --git a/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java b/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java index 78a497a32..23bf5fc7c 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java +++ b/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java @@ -47,21 +47,17 @@ public Widget createUIWidget() { group.addWidget(new LabelWidget(8, 8, Component.translatable("gui.cosmiccore.soul_hatch.label." + (this.io == IO.IN ? "import" : "export")))); - if (soulContainer.getOwner() == null) { - group.addWidget( - new LabelWidget(8, 18, I18n.get("gui.cosmiccore.soul_hatch.no_network")).setClientSideWidget()); - } else { - group.addWidget( - new LabelWidget(8, 18, - () -> I18n.get("gui.cosmiccore.soul_hatch.owner", - PlayerHelper.getUsernameFromUUID(this.soulContainer.getOwner()))) - .setClientSideWidget()); - group.addWidget( - new LabelWidget(8, 28, - () -> I18n.get("gui.cosmiccore.soul_hatch.lp", - FormattingUtil.formatNumbers(soulContainer.getCurrentEssence()))) - .setClientSideWidget()); - } + // TODO: Get and display proper player/team Name +// group.addWidget( +// new LabelWidget(8, 18, +// () -> I18n.get("gui.cosmiccore.soul_hatch.owner", +// PlayerHelper.getUsernameFromUUID(this.soulContainer.getOwner()))) +// .setClientSideWidget()); + group.addWidget( + new LabelWidget(8, 28, + () -> I18n.get("gui.cosmiccore.soul_hatch.lp", + FormattingUtil.formatNumbers(soulContainer.getCurrentEssence()))) + .setClientSideWidget()); group.setBackground(GuiTextures.BACKGROUND_INVERSE); return group; @@ -99,10 +95,6 @@ public static int getMaxConsumption(int tier) { }; } - public void attachSoulNetwork(Player player) { - this.soulContainer.setOwner(player.getUUID()); - } - @Override public ManagedFieldHolder getFieldHolder() { return MANAGED_FIELD_HOLDER; diff --git a/src/main/java/com/ghostipedia/cosmiccore/forge/ForgeCommonEventListener.java b/src/main/java/com/ghostipedia/cosmiccore/forge/ForgeCommonEventListener.java index a0c34ac8e..cea660ba6 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/forge/ForgeCommonEventListener.java +++ b/src/main/java/com/ghostipedia/cosmiccore/forge/ForgeCommonEventListener.java @@ -53,15 +53,6 @@ @Mod.EventBusSubscriber(modid = CosmicCore.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE) public class ForgeCommonEventListener { - @SubscribeEvent - public static void entityPlacementEventHandler(BlockEvent.EntityPlaceEvent event) { - if (event.getPlacedBlock().getBlock() instanceof MetaMachineBlock block && - block.getMachine(event.getLevel(), event.getPos()) instanceof SoulHatchPartMachine soulHatch && - event.getEntity() instanceof Player player) { - soulHatch.attachSoulNetwork(player); - } - } - @SubscribeEvent public static void onPlayerTick(final TickEvent.PlayerTickEvent event) { if (event.phase != TickEvent.Phase.END) { diff --git a/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java b/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java index 137167033..bdc8a8199 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java +++ b/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java @@ -1,10 +1,13 @@ package com.ghostipedia.cosmiccore.gtbridge; +import com.ghostipedia.cosmiccore.api.capability.CosmicCapabilities; +import com.ghostipedia.cosmiccore.api.capability.recipe.CosmicRecipeCapabilities; import com.ghostipedia.cosmiccore.common.machine.multiblock.multi.logic.LarvaMachine; import com.gregtechceu.gtceu.api.GTValues; import net.minecraft.data.recipes.FinishedRecipe; +import net.minecraft.world.item.Items; import java.util.function.Consumer; @@ -29,6 +32,7 @@ public static void init(Consumer provider) { .save(provider); LarvaMachine.generateTargettingChipRecipes(provider); + /* * EMBER_TESTER_RECIPES.recipeBuilder("test") * .input(CosmicRecipeCapabilities.EMBER, 100d) @@ -36,6 +40,12 @@ public static void init(Consumer provider) { * .save(provider); */ + SOUL_TESTER_RECIPES.recipeBuilder("generate_soul") + .notConsumable(Items.DIRT) + .output(CosmicRecipeCapabilities.SOUL, 10) + .duration(20) + .save(provider); + // GROVE_RECIPES.recipeBuilder("dirt_movement") // .input(SoulRecipeCapability.CAP, 100) // .notConsumable(CosmicItems.DONK) From eca9e8235204d76964baeb19c5274a18b2406d5e Mon Sep 17 00:00:00 2001 From: MrQuentinet <32539717+mrquentin@users.noreply.github.com> Date: Wed, 3 Dec 2025 22:31:35 -0500 Subject: [PATCH 10/28] Multiple Soul types need to add display of the soul amount in order to see if it works ! --- .../ghostipedia/cosmiccore/CosmicCore.java | 4 +- .../recipe/SoulRecipeCapability.java | 99 +++++++++---- .../api/capability/souls/SoulType.java | 42 ++++++ .../api/codec/CosmicCodecUtils.java | 6 + .../api/data/souls/SoulNetwork.java | 59 ++++++-- .../trait/NotifiableSoulContainer.java | 134 +++++++----------- .../recipe/content/SerializerSoulStack.java | 45 ++++++ .../api/recipe/ingredient/SoulIngredient.java | 40 ++++++ .../api/recipe/ingredient/SoulStack.java | 41 ++++++ .../api/recipe/lookup/MapSoulIngredient.java | 27 ++-- .../common/data/CosmicMachines.java | 3 - .../multiblock/part/SoulHatchPartMachine.java | 28 +--- .../gtbridge/CosmicCoreRecipes.java | 6 +- 13 files changed, 367 insertions(+), 167 deletions(-) create mode 100644 src/main/java/com/ghostipedia/cosmiccore/api/capability/souls/SoulType.java create mode 100644 src/main/java/com/ghostipedia/cosmiccore/api/codec/CosmicCodecUtils.java create mode 100644 src/main/java/com/ghostipedia/cosmiccore/api/recipe/content/SerializerSoulStack.java create mode 100644 src/main/java/com/ghostipedia/cosmiccore/api/recipe/ingredient/SoulIngredient.java create mode 100644 src/main/java/com/ghostipedia/cosmiccore/api/recipe/ingredient/SoulStack.java diff --git a/src/main/java/com/ghostipedia/cosmiccore/CosmicCore.java b/src/main/java/com/ghostipedia/cosmiccore/CosmicCore.java index 1f80f134a..b994a3657 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/CosmicCore.java +++ b/src/main/java/com/ghostipedia/cosmiccore/CosmicCore.java @@ -3,6 +3,7 @@ import com.ghostipedia.cosmiccore.api.capability.CosmicCapabilities; import com.ghostipedia.cosmiccore.api.item.LinkedTerminalBehavior; import com.ghostipedia.cosmiccore.api.pattern.CosmicPredicates; +import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulIngredient; import com.ghostipedia.cosmiccore.api.recipe.lookup.MapEmberIngredient; import com.ghostipedia.cosmiccore.api.recipe.lookup.MapSoulIngredient; import com.ghostipedia.cosmiccore.api.registries.CosmicRegistration; @@ -37,6 +38,7 @@ import com.lowdragmc.lowdraglib.Platform; import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.crafting.Ingredient; import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; @@ -111,7 +113,7 @@ public void modifyExistingMaterials(PostMaterialEvent event) { @SubscribeEvent public void commonSetup(FMLCommonSetupEvent event) { event.enqueueWork(() -> { - MapIngredientTypeManager.registerMapIngredient(Integer.class, MapSoulIngredient::convertToMapIngredient); + MapIngredientTypeManager.registerMapIngredient(SoulIngredient.class, MapSoulIngredient::from); MapIngredientTypeManager.registerMapIngredient(Double.class, MapEmberIngredient::convertToMapIngredient); GridLinkables.register(CosmicItems.LINKED_TERMINAL, LinkedTerminalBehavior.handler); CCoreNetwork.init(); diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/capability/recipe/SoulRecipeCapability.java b/src/main/java/com/ghostipedia/cosmiccore/api/capability/recipe/SoulRecipeCapability.java index 076f0b279..228607494 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/capability/recipe/SoulRecipeCapability.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/capability/recipe/SoulRecipeCapability.java @@ -1,71 +1,108 @@ package com.ghostipedia.cosmiccore.api.capability.recipe; -import com.ghostipedia.cosmiccore.api.recipe.lookup.MapSoulIngredient; +import com.ghostipedia.cosmiccore.api.capability.souls.SoulType; +import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulIngredient; +import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulStack; import com.gregtechceu.gtceu.api.capability.recipe.RecipeCapability; import com.gregtechceu.gtceu.api.recipe.GTRecipe; import com.gregtechceu.gtceu.api.recipe.content.Content; import com.gregtechceu.gtceu.api.recipe.content.ContentModifier; -import com.gregtechceu.gtceu.api.recipe.content.SerializerInteger; -import com.gregtechceu.gtceu.api.recipe.lookup.ingredient.AbstractMapIngredient; +import com.gregtechceu.gtceu.api.recipe.content.IContentSerializer; -import com.lowdragmc.lowdraglib.gui.widget.LabelWidget; import com.lowdragmc.lowdraglib.gui.widget.WidgetGroup; -import com.lowdragmc.lowdraglib.utils.LocalizationUtils; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import com.mojang.serialization.Codec; import org.apache.commons.lang3.mutable.MutableInt; -import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; import java.util.Collection; import java.util.List; -public class SoulRecipeCapability extends RecipeCapability { + +public class SoulRecipeCapability extends RecipeCapability { public final static SoulRecipeCapability CAP = new SoulRecipeCapability(); protected SoulRecipeCapability() { - super("soul", 0x5E2129FF, true, 10, SerializerInteger.INSTANCE); + super("soul", 0x5E2129FF, true, 10, SerializerSoulIngredient.INSTANCE); } @Override - public Integer copyInner(Integer content) { - return content; + public boolean isRecipeSearchFilter() { + return true; } + //TODO: try to remove @Override - public Integer copyWithModifier(Integer content, ContentModifier modifier) { - return modifier.apply(content); + public SoulIngredient copyInner(SoulIngredient content) { + return super.copyInner(content); } @Override - public @Nullable List getDefaultMapIngredient(Object ingredient) { - List ingredients = new ObjectArrayList<>(1); - if (ingredient instanceof Integer essence) ingredients.add(new MapSoulIngredient(essence)); - return ingredients; + public SoulIngredient copyWithModifier(SoulIngredient content, ContentModifier modifier) { + var modifiedStack = content.stack().withAmount(modifier.apply(content.stack().amount())); + return SoulIngredient.of(modifiedStack); } @Override public List compressIngredients(Collection ingredients) { - // TODO: Figure out what it needs to do - return super.compressIngredients(ingredients); - } - - @Override - public boolean isRecipeSearchFilter() { - return true; + List list = new ArrayList<>(ingredients.size()); + for (Object item : ingredients) { + if (item instanceof SoulIngredient soul) { + var isEqual = false; + for (Object obj : list) { + if (obj instanceof SoulIngredient soulIngredient && soul.equals(soulIngredient)) { + isEqual = true; + break; + } + } + if (isEqual) continue; + list.add(item); + } + } + return list; } @Override public void addXEIInfo(WidgetGroup group, int xOffset, GTRecipe recipe, List contents, boolean perTick, boolean isInput, MutableInt yOffset) { - int soul = contents.stream().map(Content::getContent).mapToInt(SoulRecipeCapability.CAP::of).sum(); - if (isInput) { - group.addWidget(new LabelWidget(3 - xOffset, yOffset.addAndGet(10), - LocalizationUtils.format("cosmiccore.recipe.soul_in", soul))); - } else { - group.addWidget(new LabelWidget(3 - xOffset, yOffset.addAndGet(10), - LocalizationUtils.format("cosmiccore.recipe.soul_out", soul))); + //TODO: ADD XEI info +// String type = contents.stream().map(Content::getContent).map(SoulRecipeCapability.CAP::of).map(SoulStack::type).map(SoulType::getSerializedName).findFirst().orElse(""); +// long soul = contents.stream().map(Content::getContent).map(SoulRecipeCapability.CAP::of).mapToLong(SoulStack::amount).sum(); +// if (isInput) { +// group.addWidget(new LabelWidget(3 - xOffset, yOffset.addAndGet(10), +// LocalizationUtils.format("cosmiccore.recipe." + type + "_soul_in", soul))); +// } else { +// group.addWidget(new LabelWidget(3 - xOffset, yOffset.addAndGet(10), +// LocalizationUtils.format("cosmiccore.recipe." + type + "_soul_out", soul))); +// } + } + + private static class SerializerSoulIngredient implements IContentSerializer { + + public static SerializerSoulIngredient INSTANCE = new SerializerSoulIngredient(); + + @Override + public SoulIngredient of(Object o) { + if (o instanceof SoulStack stack) return SoulIngredient.of(stack); + else if (o instanceof SoulIngredient ingredient) return ingredient; + return SoulIngredient.of(new SoulStack(SoulType.Impure, 0)); + } + + @Override + public SoulIngredient defaultValue() { + return SoulIngredient.of(new SoulStack(SoulType.Impure, 0)); + } + + @Override + public Class contentClass() { + return SoulIngredient.class; + } + + @Override + public Codec codec() { + return SoulIngredient.CODEC; } } } diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/capability/souls/SoulType.java b/src/main/java/com/ghostipedia/cosmiccore/api/capability/souls/SoulType.java new file mode 100644 index 000000000..b8aec80dd --- /dev/null +++ b/src/main/java/com/ghostipedia/cosmiccore/api/capability/souls/SoulType.java @@ -0,0 +1,42 @@ +package com.ghostipedia.cosmiccore.api.capability.souls; + +import com.mojang.serialization.Codec; +import net.minecraft.util.StringRepresentable; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +public enum SoulType implements StringRepresentable { + Impure("Impure"), + Rusted("Rusted"), + Proud("Proud"), + Greedy("Greedy"), + Envious("Envious"), + Gluttonous("Gluttonous"), + Wrathful("Wrathful"), + Slothful("Slothful"), + Temporal("Temporal"); + + private final String name; + + SoulType(String name) { + this.name = name; + } + + + @Override + public @NotNull String getSerializedName() { + return this.name; + } + + public static final Codec CODEC = StringRepresentable.fromEnum(SoulType::values); + + private static final Map BY_NAME = Arrays.stream(values()).collect(Collectors.toMap(SoulType::getSerializedName, Function.identity())); + + public static SoulType byName(String name) { + return BY_NAME.get(name); + } +} diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/codec/CosmicCodecUtils.java b/src/main/java/com/ghostipedia/cosmiccore/api/codec/CosmicCodecUtils.java new file mode 100644 index 000000000..22fa96c67 --- /dev/null +++ b/src/main/java/com/ghostipedia/cosmiccore/api/codec/CosmicCodecUtils.java @@ -0,0 +1,6 @@ +package com.ghostipedia.cosmiccore.api.codec; + +import com.mojang.serialization.Codec; + +public class CosmicCodecUtils { +} diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java b/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java index 6166fbb96..774c296d0 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java @@ -1,9 +1,15 @@ package com.ghostipedia.cosmiccore.api.data.souls; +import com.ghostipedia.cosmiccore.api.capability.souls.SoulType; +import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulIngredient; +import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulStack; import lombok.Getter; import net.minecraft.nbt.CompoundTag; import net.minecraftforge.common.util.INBTSerializable; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.UUID; public class SoulNetwork implements INBTSerializable { @@ -11,23 +17,46 @@ public class SoulNetwork implements INBTSerializable { @Getter private int tier = 0, currentSouls = 0; + private Map contents = new HashMap<>(); + public SoulNetwork() {} - public int add(int amount, int max) { - int oldSouls = this.currentSouls; - if (oldSouls >= max) return 0; - else { - int newSouls = Math.min(max, oldSouls + amount); - this.currentSouls = newSouls; - return newSouls - oldSouls; - } + public SoulStack add(SoulStack stack, int throughput, boolean simulate) { + int currentAmount = this.contents.getOrDefault(stack.type(), 0); + + int amountToAdd = Math.min(stack.amount(), throughput); // Respect throughput + amountToAdd = Math.min(amountToAdd, getSize() - currentAmount); // Respect network capacity + + if (!simulate) this.contents.put(stack.type(), currentAmount + amountToAdd); + + return stack.withAmount(amountToAdd); + } + + public SoulStack syphon(SoulStack stack, boolean simulate) { + var currentSoulContent = this.contents.getOrDefault(stack.type(), 0); + int amountToSyphon = Math.min(stack.amount(), currentSoulContent); + + if (!simulate && amountToSyphon > 0) this.contents.put(stack.type(), currentSoulContent - amountToSyphon); + + return stack.withAmount(amountToSyphon); + } + + public List getContents() { + return contents.entrySet().stream() + .map(kvp -> new SoulStack(kvp.getKey(), kvp.getValue())) + .toList(); } - public int syphon(int amount) { - if (this.currentSouls >= amount) { - this.currentSouls -= amount; - return amount; - } else return 0; + public int getSize() { + return switch (tier) { + case 0 -> 1_000; + case 1 -> 100_000; + case 3 -> 1_000_000; + case 4 -> 10_000_000; + case 5 -> 100_000_000; + case 6 -> 1_000_000_000; + default -> Integer.MAX_VALUE; + }; } @Override @@ -36,7 +65,7 @@ public CompoundTag serializeNBT() { } @Override - public void deserializeNBT(CompoundTag compoundTag) {} - + public void deserializeNBT(CompoundTag compoundTag) { + } } diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java b/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java index 329b6883a..fefc1497b 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java @@ -1,126 +1,96 @@ package com.ghostipedia.cosmiccore.api.machine.trait; -import com.ghostipedia.cosmiccore.api.capability.ISoulContainer; -import com.ghostipedia.cosmiccore.api.capability.recipe.SoulRecipeCapability; - +import com.ghostipedia.cosmiccore.api.capability.recipe.CosmicRecipeCapabilities; import com.ghostipedia.cosmiccore.api.data.souls.SoulNetwork; import com.ghostipedia.cosmiccore.api.data.souls.SoulNetworkSavedData; +import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulIngredient; +import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulStack; import com.gregtechceu.gtceu.api.capability.recipe.IO; import com.gregtechceu.gtceu.api.capability.recipe.RecipeCapability; -import com.gregtechceu.gtceu.api.machine.ConditionalSubscriptionHandler; import com.gregtechceu.gtceu.api.machine.MetaMachine; import com.gregtechceu.gtceu.api.machine.trait.NotifiableRecipeHandlerTrait; import com.gregtechceu.gtceu.api.recipe.GTRecipe; - import com.gregtechceu.gtceu.common.machine.owner.FTBOwner; -import com.lowdragmc.lowdraglib.syncdata.annotation.DescSynced; -import com.lowdragmc.lowdraglib.syncdata.annotation.Persisted; -import com.lowdragmc.lowdraglib.syncdata.field.ManagedFieldHolder; - import lombok.Getter; +import org.jetbrains.annotations.NotNull; -import java.util.Collections; +import java.util.ArrayList; import java.util.List; import java.util.UUID; -public class NotifiableSoulContainer extends NotifiableRecipeHandlerTrait implements ISoulContainer { - - public static final ManagedFieldHolder MANAGED_FIELD_HOLDER = new ManagedFieldHolder(NotifiableSoulContainer.class, - NotifiableRecipeHandlerTrait.MANAGED_FIELD_HOLDER); - @Getter - private final IO handlerIO; - private final ConditionalSubscriptionHandler conditionalSubscriptionHandler; +public class NotifiableSoulContainer extends NotifiableRecipeHandlerTrait { @Getter - @DescSynced - private int currentEssence; - - @Persisted - private int maxCapacity; + public final IO handlerIO; - @Persisted - private int maxConsumption; + private final int throughput; - public NotifiableSoulContainer(MetaMachine machine, IO io, int maxCapacity, int maxConsumption) { + public NotifiableSoulContainer(MetaMachine machine, IO io, int throughput) { super(machine); this.handlerIO = io; - this.currentEssence = -1; - this.maxCapacity = maxCapacity; - this.maxConsumption = maxConsumption; - // TODO: simplify to remove conditional that is not needed - conditionalSubscriptionHandler = new ConditionalSubscriptionHandler(machine, this::querySoulNetwork, () -> true); + this.throughput = throughput; } - private void querySoulNetwork() { - if (this.machine.getOffsetTimer() % 20 != 0) return; - - var network = this.getSoulNetwork(); - if (network == null) return; - - var essence = network.getCurrentSouls(); - if (this.currentEssence == essence) return; - - this.currentEssence = essence; - this.notifyListeners(); - } - - @Override - public List handleRecipeInner(IO io, GTRecipe recipe, List left, boolean simulate) { - ISoulContainer container = this; - - int lifeEssence = left.stream().reduce(0, Integer::sum); - if (io == IO.IN) { - var canOutput = Math.min(this.maxConsumption, container.getSoulNetwork().getCurrentSouls()); - if (!simulate) lifeEssence = container.getSoulNetwork().syphon(Math.min(canOutput, lifeEssence)); - lifeEssence = lifeEssence - canOutput; - } else if (io == IO.OUT) { - var canInput = this.maxCapacity - container.getSoulNetwork().getCurrentSouls(); - if (!simulate) lifeEssence = container.getSoulNetwork().add(Math.min(canInput, lifeEssence), this.maxCapacity); - lifeEssence = lifeEssence - canInput; - } - - return lifeEssence <= 0 ? null : Collections.singletonList(lifeEssence); + private SoulNetwork getSoulNetwork() { + return SoulNetworkSavedData.getSoulNetwork(getOwner()); } - @Override - public List getContents() { - return List.of(this.getSoulNetwork().getCurrentSouls()); + private UUID getOwner() { + var team = ((FTBOwner) this.machine.getOwner()).getPlayerTeam(this.machine.getOwnerUUID()); + return team != null ? team.getTeamId() : this.machine.getOwnerUUID(); } @Override - public double getTotalContentAmount() { - return this.getSoulNetwork().getCurrentSouls(); - } + public List handleRecipeInner(IO io, GTRecipe recipe, List left, boolean simulate) { + if (io != handlerIO) return left; + if (io != IO.IN && io != IO.OUT) return left.isEmpty() ? null : left; + + var network = getSoulNetwork(); + List result = new ArrayList<>(); + + for (SoulIngredient ingredient : left) { + SoulStack requiredStack = ingredient.stack(); + if (requiredStack.isEmpty()) continue; + + if (io == IO.IN) { + SoulStack consumedStack = network.syphon(requiredStack, simulate); + if (consumedStack.amount() < requiredStack.amount()){ + result.add(SoulIngredient.of(requiredStack.withAmount(requiredStack.amount() - consumedStack.amount()))); + } + } else { + SoulStack remainder = network.add(requiredStack, throughput, simulate); + if (remainder.amount() > 0) { + result.add(SoulIngredient.of(remainder)); + } + } + } - @Override - public RecipeCapability getCapability() { - return SoulRecipeCapability.CAP; + return List.of(); } @Override - public ManagedFieldHolder getFieldHolder() { - return MANAGED_FIELD_HOLDER; + public @NotNull List getContents() { + return getSoulNetwork().getContents().stream() + .map(SoulIngredient::new) + .map(Object.class::cast) + .toList(); } @Override - public SoulNetwork getSoulNetwork() { - return SoulNetworkSavedData.getSoulNetwork(getOwner()); - } - - public UUID getOwner() { - var team = ((FTBOwner) this.machine.getOwner()).getPlayerTeam(this.machine.getOwnerUUID()); - return team != null ? team.getTeamId() : this.machine.getOwnerUUID(); + public int getSize() { + return getSoulNetwork().getContents().size(); } @Override - public int getSize() { - return 1; + public double getTotalContentAmount() { + return getSoulNetwork().getContents().stream() + .mapToInt(SoulStack::amount) + .sum(); } @Override - public void onMachineLoad() { - super.onMachineLoad(); - conditionalSubscriptionHandler.initialize(this.machine.getLevel()); + public RecipeCapability getCapability() { + return CosmicRecipeCapabilities.SOUL; } } diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/recipe/content/SerializerSoulStack.java b/src/main/java/com/ghostipedia/cosmiccore/api/recipe/content/SerializerSoulStack.java new file mode 100644 index 000000000..dcc30a69b --- /dev/null +++ b/src/main/java/com/ghostipedia/cosmiccore/api/recipe/content/SerializerSoulStack.java @@ -0,0 +1,45 @@ +package com.ghostipedia.cosmiccore.api.recipe.content; + +import com.ghostipedia.cosmiccore.api.capability.souls.SoulType; +import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulStack; +import com.gregtechceu.gtceu.api.recipe.content.IContentSerializer; +import com.mojang.serialization.Codec; +import net.minecraft.network.FriendlyByteBuf; + +public class SerializerSoulStack implements IContentSerializer { + + public static SerializerSoulStack INSTANCE = new SerializerSoulStack(); + + private SerializerSoulStack() {} + + @Override + public void toNetwork(FriendlyByteBuf buf, SoulStack content) { + content.toNetwork(buf); + } + + @Override + public SoulStack fromNetwork(FriendlyByteBuf buf) { + return SoulStack.fromNetwork(buf); + } + + @Override + public SoulStack of(Object o) { + if (o instanceof SoulStack stack) return stack; + else return SoulStack.EMPTY; + } + + @Override + public SoulStack defaultValue() { + return SoulStack.EMPTY; + } + + @Override + public Class contentClass() { + return SoulStack.class; + } + + @Override + public Codec codec() { + return SoulStack.CODEC; + } +} diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/recipe/ingredient/SoulIngredient.java b/src/main/java/com/ghostipedia/cosmiccore/api/recipe/ingredient/SoulIngredient.java new file mode 100644 index 000000000..33b010ec8 --- /dev/null +++ b/src/main/java/com/ghostipedia/cosmiccore/api/recipe/ingredient/SoulIngredient.java @@ -0,0 +1,40 @@ +package com.ghostipedia.cosmiccore.api.recipe.ingredient; + + +import com.ghostipedia.cosmiccore.api.capability.souls.SoulType; +import com.mojang.serialization.Codec; +import org.jetbrains.annotations.NotNull; + +import java.util.function.Predicate; + +public record SoulIngredient(SoulStack stack) implements Predicate { + + public static final Codec CODEC = SoulStack.CODEC.xmap(SoulIngredient::new, SoulIngredient::stack); + + public static SoulIngredient of(final SoulStack stack) { + return new SoulIngredient(stack); + } + + public static SoulIngredient of(SoulType soulType, int amount) { + return new SoulIngredient(new SoulStack(soulType, amount)); + } + + @Override + public boolean test(SoulStack soulStack) { + return this.stack.type() == soulStack.type() + && this.stack.amount() <= soulStack.amount(); + } + + @Override + public @NotNull String toString() { + return "SoulIngredient{stack=" + stack + "}"; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof SoulIngredient other)) { + return false; + } + return stack.equals(other.stack); + } +} diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/recipe/ingredient/SoulStack.java b/src/main/java/com/ghostipedia/cosmiccore/api/recipe/ingredient/SoulStack.java new file mode 100644 index 000000000..c63715c69 --- /dev/null +++ b/src/main/java/com/ghostipedia/cosmiccore/api/recipe/ingredient/SoulStack.java @@ -0,0 +1,41 @@ +package com.ghostipedia.cosmiccore.api.recipe.ingredient; + +import com.ghostipedia.cosmiccore.api.capability.souls.SoulType; +import com.google.common.base.Preconditions; +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import lombok.With; +import net.minecraft.network.FriendlyByteBuf; + +@With +public record SoulStack(SoulType type, int amount) { + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + SoulType.CODEC.fieldOf("type").forGetter(SoulStack::type), + Codec.INT.fieldOf("amount").forGetter(SoulStack::amount) + ).apply(instance, SoulStack::new)); + + public static final SoulStack EMPTY = new SoulStack(SoulType.Impure, 0); + + public boolean isEmpty() { + return this.amount <= 0; + } + + public SoulStack add(int amount) { + Preconditions.checkArgument(this.amount + amount >= 0, "Resulting amount must be non-negative"); + return new SoulStack(this.type, this.amount + amount); + } + + public SoulStack sum(SoulStack a, SoulStack b) { + Preconditions.checkArgument(a.type == b.type, "SoulStack types don't match"); + return a.add(b.amount); + } + + public void toNetwork(FriendlyByteBuf buf) { + buf.writeEnum(this.type); + buf.writeVarInt(this.amount); + } + + public static SoulStack fromNetwork(FriendlyByteBuf buf) { + return new SoulStack(buf.readEnum(SoulType.class), buf.readVarInt()); + } +} diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/recipe/lookup/MapSoulIngredient.java b/src/main/java/com/ghostipedia/cosmiccore/api/recipe/lookup/MapSoulIngredient.java index 2ab62d0f4..eb14168ab 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/recipe/lookup/MapSoulIngredient.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/recipe/lookup/MapSoulIngredient.java @@ -1,34 +1,37 @@ package com.ghostipedia.cosmiccore.api.recipe.lookup; +import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulIngredient; +import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulStack; import com.gregtechceu.gtceu.api.recipe.lookup.ingredient.AbstractMapIngredient; -import java.util.Collections; import java.util.List; public class MapSoulIngredient extends AbstractMapIngredient { - public final Integer souls; + public final SoulStack stack; - public MapSoulIngredient(Integer souls) { - this.souls = souls; + public MapSoulIngredient(SoulStack stack) { + this.stack = stack; } @Override protected int hash() { - return MapSoulIngredient.class.hashCode(); + return 0; } @Override - public boolean equals(Object obj) { - return obj instanceof MapSoulIngredient; + public boolean equals(Object o) { + if (!(o instanceof MapSoulIngredient other)) return false; + return stack.equals(other.stack); } - @Override - public String toString() { - return "MapSoulIngredient{" + "souls=" + souls + '}'; + public static List from(SoulIngredient soulIngredient) { + SoulStack stack = soulIngredient.stack(); + return List.of(new MapSoulIngredient(stack)); } - public static List convertToMapIngredient(Integer essence) { - return Collections.singletonList(new MapSoulIngredient(essence)); + @Override + public String toString() { + return "MapSoulIngredient{stack=" + stack + "}"; } } diff --git a/src/main/java/com/ghostipedia/cosmiccore/common/data/CosmicMachines.java b/src/main/java/com/ghostipedia/cosmiccore/common/data/CosmicMachines.java index ccb87176f..f0b68d6ec 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/common/data/CosmicMachines.java +++ b/src/main/java/com/ghostipedia/cosmiccore/common/data/CosmicMachines.java @@ -489,9 +489,6 @@ private static MachineDefinition[] registerSoulHatch(String name, String display if (io == IO.IN) tooltip.add(Component.translatable("tooltip.cosmiccore.soul_hatch.input", SoulHatchPartMachine.getMaxConsumption(tier))); - else - tooltip.add(Component.translatable("tooltip.cosmiccore.soul_hatch.output", - SoulHatchPartMachine.getMaxCapacity(tier))); }).register(), tiers); } diff --git a/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java b/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java index 23bf5fc7c..7fb162bfa 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java +++ b/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java @@ -36,7 +36,7 @@ public class SoulHatchPartMachine extends TieredIOPartMachine { public SoulHatchPartMachine(IMachineBlockEntity holder, int tier, IO io) { super(holder, tier, io); - this.soulContainer = new NotifiableSoulContainer(this, io, getMaxCapacity(tier), getMaxConsumption(tier)); + this.soulContainer = new NotifiableSoulContainer(this, io, getMaxConsumption(tier)); } @Override @@ -53,32 +53,16 @@ public Widget createUIWidget() { // () -> I18n.get("gui.cosmiccore.soul_hatch.owner", // PlayerHelper.getUsernameFromUUID(this.soulContainer.getOwner()))) // .setClientSideWidget()); - group.addWidget( - new LabelWidget(8, 28, - () -> I18n.get("gui.cosmiccore.soul_hatch.lp", - FormattingUtil.formatNumbers(soulContainer.getCurrentEssence()))) - .setClientSideWidget()); +// group.addWidget( +// new LabelWidget(8, 28, +// () -> I18n.get("gui.cosmiccore.soul_hatch.lp", +// FormattingUtil.formatNumbers(soulContainer.getCurrentEssence()))) +// .setClientSideWidget()); group.setBackground(GuiTextures.BACKGROUND_INVERSE); return group; } - public static int getMaxCapacity(int tier) { - return switch (tier) { - case GTValues.IV -> 5000000; - case GTValues.LuV -> 10000000; - case GTValues.ZPM -> 20000000; - case GTValues.UV -> 30000000; - case GTValues.UHV -> 50000000; - case GTValues.UEV -> 100000000; - case GTValues.UIV -> 250000000; - case GTValues.UXV -> 500000000; - case GTValues.OpV -> 1000000000; - case GTValues.MAX -> Integer.MAX_VALUE; - default -> 0; - }; - } - public static int getMaxConsumption(int tier) { return switch (tier) { case GTValues.IV -> 10000; diff --git a/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java b/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java index bdc8a8199..96df70358 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java +++ b/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java @@ -2,6 +2,9 @@ import com.ghostipedia.cosmiccore.api.capability.CosmicCapabilities; import com.ghostipedia.cosmiccore.api.capability.recipe.CosmicRecipeCapabilities; +import com.ghostipedia.cosmiccore.api.capability.souls.SoulType; +import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulIngredient; +import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulStack; import com.ghostipedia.cosmiccore.common.machine.multiblock.multi.logic.LarvaMachine; import com.gregtechceu.gtceu.api.GTValues; @@ -42,7 +45,8 @@ public static void init(Consumer provider) { SOUL_TESTER_RECIPES.recipeBuilder("generate_soul") .notConsumable(Items.DIRT) - .output(CosmicRecipeCapabilities.SOUL, 10) + .output(CosmicRecipeCapabilities.SOUL, SoulIngredient.of(SoulType.Impure, 10)) + .output(CosmicRecipeCapabilities.SOUL, SoulIngredient.of(SoulType.Temporal, 10)) .duration(20) .save(provider); From 5beb5d4d05fe3f3f982b969d99652d38d8ae4469 Mon Sep 17 00:00:00 2001 From: MrQuentinet <32539717+mrquentin@users.noreply.github.com> Date: Thu, 4 Dec 2025 20:54:56 -0500 Subject: [PATCH 11/28] it works !! --- .../api/data/souls/SoulNetwork.java | 47 +++++++++++++++---- .../trait/NotifiableSoulContainer.java | 9 ++-- .../gtbridge/CosmicCoreRecipes.java | 2 +- 3 files changed, 42 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java b/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java index 774c296d0..75aaa19b8 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java @@ -1,33 +1,37 @@ package com.ghostipedia.cosmiccore.api.data.souls; import com.ghostipedia.cosmiccore.api.capability.souls.SoulType; -import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulIngredient; import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulStack; import lombok.Getter; import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; import net.minecraftforge.common.util.INBTSerializable; -import java.util.HashMap; +import java.util.concurrent.ConcurrentHashMap; import java.util.List; import java.util.Map; -import java.util.UUID; public class SoulNetwork implements INBTSerializable { @Getter - private int tier = 0, currentSouls = 0; + private int tier = 0; - private Map contents = new HashMap<>(); + private final Map contents = new ConcurrentHashMap<>(); public SoulNetwork() {} public SoulStack add(SoulStack stack, int throughput, boolean simulate) { int currentAmount = this.contents.getOrDefault(stack.type(), 0); + int totalAmount = this.contents.values().stream().mapToInt(Integer::intValue).sum(); int amountToAdd = Math.min(stack.amount(), throughput); // Respect throughput - amountToAdd = Math.min(amountToAdd, getSize() - currentAmount); // Respect network capacity + amountToAdd = Math.min(amountToAdd, getSize() - totalAmount); // Respect network capacity + amountToAdd = Math.max(0, amountToAdd); // Ensure we don't add a negative amount - if (!simulate) this.contents.put(stack.type(), currentAmount + amountToAdd); + if (!simulate && amountToAdd > 0) this.contents.put(stack.type(), currentAmount + amountToAdd); + + System.out.println(this); return stack.withAmount(amountToAdd); } @@ -51,7 +55,7 @@ public int getSize() { return switch (tier) { case 0 -> 1_000; case 1 -> 100_000; - case 3 -> 1_000_000; + case 2 -> 1_000_000; case 4 -> 10_000_000; case 5 -> 100_000_000; case 6 -> 1_000_000_000; @@ -59,13 +63,36 @@ public int getSize() { }; } + @Override + public String toString() { + return "SoulNetwork{" + + "tier=" + tier + + ", contents=" + contents + '}'; + } + @Override public CompoundTag serializeNBT() { - return null; + var tag = new CompoundTag(); + tag.putInt("tier", this.tier); + var listTag = new ListTag(); + this.contents.forEach((soulType, amount) -> { + var contentTag = new CompoundTag(); + contentTag.putString("type", soulType.getSerializedName()); + contentTag.putInt("amount", amount); + listTag.add(contentTag); + }); + tag.put("contents", listTag); + return tag; } @Override public void deserializeNBT(CompoundTag compoundTag) { - + this.tier = compoundTag.getInt("tier"); + this.contents.clear(); + ListTag listTag = compoundTag.getList("contents", Tag.TAG_COMPOUND); + for (Tag t : listTag) { + var contentTag = (CompoundTag) t; + this.contents.put(SoulType.byName(contentTag.getString("type")), contentTag.getInt("amount")); + } } } diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java b/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java index fefc1497b..609b49993 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java @@ -59,14 +59,13 @@ public List handleRecipeInner(IO io, GTRecipe recipe, List 0) { - result.add(SoulIngredient.of(remainder)); - } + SoulStack canInput = network.add(requiredStack, throughput, simulate); + SoulStack reminder = requiredStack.withAmount(requiredStack.amount() - canInput.amount()); + if (reminder.amount() > 0) result.add(SoulIngredient.of(reminder)); } } - return List.of(); + return result.isEmpty() ? null : result; } @Override diff --git a/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java b/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java index 96df70358..31192b8ea 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java +++ b/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java @@ -46,7 +46,7 @@ public static void init(Consumer provider) { SOUL_TESTER_RECIPES.recipeBuilder("generate_soul") .notConsumable(Items.DIRT) .output(CosmicRecipeCapabilities.SOUL, SoulIngredient.of(SoulType.Impure, 10)) - .output(CosmicRecipeCapabilities.SOUL, SoulIngredient.of(SoulType.Temporal, 10)) + .output(CosmicRecipeCapabilities.SOUL, SoulIngredient.of(SoulType.Temporal, 50)) .duration(20) .save(provider); From b5d0ae27fd96b5d44c5e19a024bc4bb3ef90f9f8 Mon Sep 17 00:00:00 2001 From: MrQuentinet <32539717+mrquentin@users.noreply.github.com> Date: Sat, 6 Dec 2025 13:32:50 -0500 Subject: [PATCH 12/28] Add reader item --- .../api/data/souls/SoulNetwork.java | 12 ++--- .../cosmiccore/common/data/CosmicItems.java | 9 ++++ .../common/item/SoulNetworkReaderItem.java | 45 +++++++++++++++++++ 3 files changed, 60 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/ghostipedia/cosmiccore/common/item/SoulNetworkReaderItem.java diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java b/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java index 75aaa19b8..c122186ef 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java @@ -53,12 +53,12 @@ public List getContents() { public int getSize() { return switch (tier) { - case 0 -> 1_000; - case 1 -> 100_000; - case 2 -> 1_000_000; - case 4 -> 10_000_000; - case 5 -> 100_000_000; - case 6 -> 1_000_000_000; + case 0 -> 10_000; + case 1 -> 50_000; + case 2 -> 150_000; + case 4 -> 1_000_000; + case 5 -> 10_000_000; + case 6 -> 100_000_000; default -> Integer.MAX_VALUE; }; } diff --git a/src/main/java/com/ghostipedia/cosmiccore/common/data/CosmicItems.java b/src/main/java/com/ghostipedia/cosmiccore/common/data/CosmicItems.java index e6638ccac..4fe32a7eb 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/common/data/CosmicItems.java +++ b/src/main/java/com/ghostipedia/cosmiccore/common/data/CosmicItems.java @@ -11,6 +11,7 @@ import com.ghostipedia.cosmiccore.common.item.AsteroidTargetingChipItem; import com.ghostipedia.cosmiccore.common.item.CosmicScytheItem; import com.ghostipedia.cosmiccore.common.item.OxygenTankItem; +import com.ghostipedia.cosmiccore.common.item.SoulNetworkReaderItem; import com.ghostipedia.cosmiccore.common.item.armor.ChestSanguineWarptechSuite; import com.ghostipedia.cosmiccore.common.item.armor.HelmetSanguineWarptechSuite; import com.ghostipedia.cosmiccore.common.item.armor.SanguineWarptechSuite; @@ -105,6 +106,14 @@ public class CosmicItems { "cosmiccore"); // Modules + public static final ItemEntry SOUL_READER = REGISTRATE + .item("soul_reader", SoulNetworkReaderItem::new) + .lang("Soul Network Reader") + .properties(p -> p.stacksTo(1)) + .tag() + .defaultModel() + .register(); + public static final ItemEntry ETHERIC_SPIRIT_ITEM = REGISTRATE .item("etheric_spirit", (properties -> new SpiritShardItem(properties, CosmicItems.ETHERIC_SPIRIT))) .lang("Etheric Spirit") diff --git a/src/main/java/com/ghostipedia/cosmiccore/common/item/SoulNetworkReaderItem.java b/src/main/java/com/ghostipedia/cosmiccore/common/item/SoulNetworkReaderItem.java new file mode 100644 index 000000000..9f7c459eb --- /dev/null +++ b/src/main/java/com/ghostipedia/cosmiccore/common/item/SoulNetworkReaderItem.java @@ -0,0 +1,45 @@ +package com.ghostipedia.cosmiccore.common.item; + +import com.ghostipedia.cosmiccore.api.data.souls.SoulNetwork; +import com.ghostipedia.cosmiccore.api.data.souls.SoulNetworkSavedData; +import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulStack; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; + +import java.util.List; + +public class SoulNetworkReaderItem extends Item { + + public SoulNetworkReaderItem(Properties properties) { + super(properties); + } + + @Override + public InteractionResultHolder use(Level level, Player player, InteractionHand hand) { + if (!level.isClientSide() && player instanceof ServerPlayer serverPlayer) { + //TODO: get team or player uuid + SoulNetwork soulNetwork = SoulNetworkSavedData.getSoulNetwork(player.getUUID()); + List contents = soulNetwork.getContents(); + + player.sendSystemMessage(Component.literal("--- Soul Network Contents ---").withStyle(ChatFormatting.GOLD)); + + if (contents.isEmpty()) { + player.sendSystemMessage(Component.literal("Network is empty.").withStyle(ChatFormatting.GRAY)); + } else { + for (SoulStack stack : contents) { + Component message = Component.literal(String.format("%s: %,d", stack.type().getSerializedName(), stack.amount())) + .withStyle(ChatFormatting.AQUA); + player.sendSystemMessage(message); + } + } + } + return InteractionResultHolder.success(player.getItemInHand(hand)); + } +} From 6d1972704692e8f978fc8969b435617ee20c77e3 Mon Sep 17 00:00:00 2001 From: MrQuentinet <32539717+mrquentin@users.noreply.github.com> Date: Sat, 3 Jan 2026 15:31:13 -0500 Subject: [PATCH 13/28] WIP --- .../assets/cosmiccore/lang/en_us.json | 9 ++++ .../api/capability/souls/SoulType.java | 43 ++++++++++++++----- .../common/data/CosmicMachines.java | 6 +-- .../common/item/SoulNetworkReaderItem.java | 9 +--- 4 files changed, 47 insertions(+), 20 deletions(-) diff --git a/src/generated/resources/assets/cosmiccore/lang/en_us.json b/src/generated/resources/assets/cosmiccore/lang/en_us.json index b3bb2689a..257dac0a1 100644 --- a/src/generated/resources/assets/cosmiccore/lang/en_us.json +++ b/src/generated/resources/assets/cosmiccore/lang/en_us.json @@ -491,6 +491,15 @@ "cosmic.gui.wireless.energy.player": "§aPlayer:§a %s", "cosmic.gui.wireless.energy.stored": "§eStorage §b%s §f%s/%s", "cosmic.gui.wireless.energy.team": "§aTeam:§a %s", + "cosmiccore.gui.soul.impure.name": "Impure", + "cosmiccore.gui.soul.rusted.name": "Rusted", + "cosmiccore.gui.soul.proud.name": "Proud", + "cosmiccore.gui.soul.greedy.name": "Greedy", + "cosmiccore.gui.soul.envious.name": "Envious", + "cosmiccore.gui.soul.gluttonous.name": "Gluttonous", + "cosmiccore.gui.soul.wrathful.name": "Wrathful", + "cosmiccore.gui.soul.slothful.name": "Slothful", + "cosmiccore.gui.soul.temporal.name": "Temporal", "cosmic.multiblock.capacitor.buffered": "§7Buffered: %s §7EU", "cosmic.multiblock.capacitor.duplicate.multiblock.1": "This multiblock is a duplicate", "cosmic.multiblock.capacitor.duplicate.multiblock.2": "Only one can exist", diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/capability/souls/SoulType.java b/src/main/java/com/ghostipedia/cosmiccore/api/capability/souls/SoulType.java index b8aec80dd..f0ac1c9ab 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/capability/souls/SoulType.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/capability/souls/SoulType.java @@ -1,7 +1,12 @@ package com.ghostipedia.cosmiccore.api.capability.souls; import com.mojang.serialization.Codec; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.network.chat.Style; import net.minecraft.util.StringRepresentable; +import net.minecraftforge.client.event.RenderTooltipEvent; import org.jetbrains.annotations.NotNull; import java.util.Arrays; @@ -10,20 +15,23 @@ import java.util.stream.Collectors; public enum SoulType implements StringRepresentable { - Impure("Impure"), - Rusted("Rusted"), - Proud("Proud"), - Greedy("Greedy"), - Envious("Envious"), - Gluttonous("Gluttonous"), - Wrathful("Wrathful"), - Slothful("Slothful"), - Temporal("Temporal"); + Impure("impure", ChatFormatting.DARK_GRAY), + Rusted("rusted", ChatFormatting.GRAY), + Proud("proud", ChatFormatting.DARK_PURPLE), + Greedy("greedy", ChatFormatting.YELLOW), + Envious("envious", ChatFormatting.GREEN), + Gluttonous("gluttonous", ChatFormatting.GOLD), + Wrathful("wrathful", ChatFormatting.RED), + Slothful("slothful", ChatFormatting.AQUA), + Temporal("temporal", ChatFormatting.DARK_AQUA); + private final String name; + private final ChatFormatting color; - SoulType(String name) { + SoulType(String name, ChatFormatting color) { this.name = name; + this.color = color; } @@ -39,4 +47,19 @@ public enum SoulType implements StringRepresentable { public static SoulType byName(String name) { return BY_NAME.get(name); } + + public Component toComponent(int amount) { + return toComponent(amount, true); + } + + public Component toComponent(int amount, boolean formatted) { + MutableComponent nameComp = Component.translatable("cosmiccore.gui.soul." + name + ".name"); + MutableComponent amountComp = Component.literal(" : " + amount).withStyle(Style.EMPTY); + if (formatted) { + nameComp = nameComp.withStyle(ChatFormatting.BOLD, this.color); + amountComp = amountComp.withStyle(ChatFormatting.RESET); + } + + return nameComp.append(amountComp); + } } diff --git a/src/main/java/com/ghostipedia/cosmiccore/common/data/CosmicMachines.java b/src/main/java/com/ghostipedia/cosmiccore/common/data/CosmicMachines.java index f0b68d6ec..bcb455d2a 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/common/data/CosmicMachines.java +++ b/src/main/java/com/ghostipedia/cosmiccore/common/data/CosmicMachines.java @@ -72,7 +72,6 @@ import static com.ghostipedia.cosmiccore.common.machine.multiblock.electric.hpca.HPCAMachine.*; import static com.ghostipedia.cosmiccore.gtbridge.CosmicRecipeTypes.BIO_LAB; import static com.gregtechceu.gtceu.api.GTValues.*; -import static com.gregtechceu.gtceu.api.capability.recipe.IO.IN; import static com.gregtechceu.gtceu.api.capability.recipe.IO.OUT; import static com.gregtechceu.gtceu.api.machine.property.GTMachineModelProperties.*; import static com.gregtechceu.gtceu.api.pattern.Predicates.*; @@ -85,7 +84,6 @@ import static com.gregtechceu.gtceu.common.data.GTRecipeTypes.CENTRIFUGE_RECIPES; import static com.gregtechceu.gtceu.common.data.GTRecipeTypes.DUMMY_RECIPES; import static com.gregtechceu.gtceu.common.data.machines.GTMachineUtils.*; -import static com.gregtechceu.gtceu.common.data.machines.GTMachineUtils.registerTieredMachines; import static com.gregtechceu.gtceu.common.data.machines.GTMultiMachines.FUSION_REACTOR; import static com.gregtechceu.gtceu.common.data.models.GTMachineModels.*; @@ -397,8 +395,10 @@ public class CosmicMachines { .where("S", abilities(CosmicPartAbility.IMPORT_SOUL).or(abilities(CosmicPartAbility.EXPORT_SOUL))) .where("I", abilities(PartAbility.EXPORT_ITEMS).or(abilities(PartAbility.IMPORT_ITEMS))) .build()) - .workableCasingModel(GTCEu.id("block/casings/solid/machine_casing_inert_ptfe"), GTCEu.id("block/multiblock/coke_oven")) + .workableCasingModel(GTCEu.id("block/casings/solid/machine_casing_inert_ptfe"), + GTCEu.id("block/multiblock/coke_oven")) .register(); + /* * public static final MultiblockMachineDefinition EMBER_TESTER = REGISTRATE.multiblock("ember_tester", * PrimitiveWorkableMachine::new) diff --git a/src/main/java/com/ghostipedia/cosmiccore/common/item/SoulNetworkReaderItem.java b/src/main/java/com/ghostipedia/cosmiccore/common/item/SoulNetworkReaderItem.java index 9f7c459eb..dd6cee455 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/common/item/SoulNetworkReaderItem.java +++ b/src/main/java/com/ghostipedia/cosmiccore/common/item/SoulNetworkReaderItem.java @@ -28,16 +28,11 @@ public InteractionResultHolder use(Level level, Player player, Intera SoulNetwork soulNetwork = SoulNetworkSavedData.getSoulNetwork(player.getUUID()); List contents = soulNetwork.getContents(); - player.sendSystemMessage(Component.literal("--- Soul Network Contents ---").withStyle(ChatFormatting.GOLD)); - if (contents.isEmpty()) { player.sendSystemMessage(Component.literal("Network is empty.").withStyle(ChatFormatting.GRAY)); } else { - for (SoulStack stack : contents) { - Component message = Component.literal(String.format("%s: %,d", stack.type().getSerializedName(), stack.amount())) - .withStyle(ChatFormatting.AQUA); - player.sendSystemMessage(message); - } + player.sendSystemMessage(Component.literal("--- Soul Network Contents ---").withStyle(ChatFormatting.GOLD)); + for (SoulStack stack : contents) player.sendSystemMessage(stack.type().toComponent(stack.amount())); } } return InteractionResultHolder.success(player.getItemInHand(hand)); From c9e7d8059e87b3f3270314c79dd6da0c177f58ef Mon Sep 17 00:00:00 2001 From: MrQuentinet <32539717+mrquentin@users.noreply.github.com> Date: Sat, 17 Jan 2026 16:22:17 -0500 Subject: [PATCH 14/28] kubejs soul output works input not yet ! --- .../cosmiccore/blockstates/soul_tester.json | 76 +++++++++++++++ .../cosmiccore/blockstates/star_ladder.json | 71 +------------- .../assets/cosmiccore/lang/en_ud.json | 2 + .../assets/cosmiccore/lang/en_us.json | 11 +-- .../models/block/machine/soul_tester.json | 90 ++++++++++++++++++ .../cosmiccore/models/item/soul_reader.json | 6 ++ .../cosmiccore/models/item/soul_tester.json | 3 + .../kjs/CosmicCoreKubeJSPlugin.java | 2 + .../kjs/recipe/CosmicCoreRecipeSchema.java | 10 +- .../components/CosmicRecipeComponent.java | 45 ++++++++- .../cosmiccore/textures/item/soul_reader.png | Bin 0 -> 269 bytes 11 files changed, 228 insertions(+), 88 deletions(-) create mode 100644 src/generated/resources/assets/cosmiccore/blockstates/soul_tester.json create mode 100644 src/generated/resources/assets/cosmiccore/models/block/machine/soul_tester.json create mode 100644 src/generated/resources/assets/cosmiccore/models/item/soul_reader.json create mode 100644 src/generated/resources/assets/cosmiccore/models/item/soul_tester.json create mode 100644 src/main/resources/assets/cosmiccore/textures/item/soul_reader.png diff --git a/src/generated/resources/assets/cosmiccore/blockstates/soul_tester.json b/src/generated/resources/assets/cosmiccore/blockstates/soul_tester.json new file mode 100644 index 000000000..48ee0184a --- /dev/null +++ b/src/generated/resources/assets/cosmiccore/blockstates/soul_tester.json @@ -0,0 +1,76 @@ +{ + "variants": { + "facing=east,upwards_facing=east": { + "gtceu:z": 270, + "model": "cosmiccore:block/machine/soul_tester", + "y": 90 + }, + "facing=east,upwards_facing=north": { + "model": "cosmiccore:block/machine/soul_tester", + "y": 90 + }, + "facing=east,upwards_facing=south": { + "gtceu:z": 180, + "model": "cosmiccore:block/machine/soul_tester", + "y": 90 + }, + "facing=east,upwards_facing=west": { + "gtceu:z": 90, + "model": "cosmiccore:block/machine/soul_tester", + "y": 90 + }, + "facing=north,upwards_facing=east": { + "gtceu:z": 270, + "model": "cosmiccore:block/machine/soul_tester" + }, + "facing=north,upwards_facing=north": { + "model": "cosmiccore:block/machine/soul_tester" + }, + "facing=north,upwards_facing=south": { + "gtceu:z": 180, + "model": "cosmiccore:block/machine/soul_tester" + }, + "facing=north,upwards_facing=west": { + "gtceu:z": 90, + "model": "cosmiccore:block/machine/soul_tester" + }, + "facing=south,upwards_facing=east": { + "gtceu:z": 270, + "model": "cosmiccore:block/machine/soul_tester", + "y": 180 + }, + "facing=south,upwards_facing=north": { + "model": "cosmiccore:block/machine/soul_tester", + "y": 180 + }, + "facing=south,upwards_facing=south": { + "gtceu:z": 180, + "model": "cosmiccore:block/machine/soul_tester", + "y": 180 + }, + "facing=south,upwards_facing=west": { + "gtceu:z": 90, + "model": "cosmiccore:block/machine/soul_tester", + "y": 180 + }, + "facing=west,upwards_facing=east": { + "gtceu:z": 270, + "model": "cosmiccore:block/machine/soul_tester", + "y": 270 + }, + "facing=west,upwards_facing=north": { + "model": "cosmiccore:block/machine/soul_tester", + "y": 270 + }, + "facing=west,upwards_facing=south": { + "gtceu:z": 180, + "model": "cosmiccore:block/machine/soul_tester", + "y": 270 + }, + "facing=west,upwards_facing=west": { + "gtceu:z": 90, + "model": "cosmiccore:block/machine/soul_tester", + "y": 270 + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/cosmiccore/blockstates/star_ladder.json b/src/generated/resources/assets/cosmiccore/blockstates/star_ladder.json index ad9a7da96..e1e4793e5 100644 --- a/src/generated/resources/assets/cosmiccore/blockstates/star_ladder.json +++ b/src/generated/resources/assets/cosmiccore/blockstates/star_ladder.json @@ -1,76 +1,7 @@ { "variants": { - "facing=east,upwards_facing=east": { - "gtceu:z": 270, - "model": "cosmiccore:block/machine/star_ladder", - "y": 90 - }, - "facing=east,upwards_facing=north": { - "model": "cosmiccore:block/machine/star_ladder", - "y": 90 - }, - "facing=east,upwards_facing=south": { - "gtceu:z": 180, - "model": "cosmiccore:block/machine/star_ladder", - "y": 90 - }, - "facing=east,upwards_facing=west": { - "gtceu:z": 90, - "model": "cosmiccore:block/machine/star_ladder", - "y": 90 - }, - "facing=north,upwards_facing=east": { - "gtceu:z": 270, + "": { "model": "cosmiccore:block/machine/star_ladder" - }, - "facing=north,upwards_facing=north": { - "model": "cosmiccore:block/machine/star_ladder" - }, - "facing=north,upwards_facing=south": { - "gtceu:z": 180, - "model": "cosmiccore:block/machine/star_ladder" - }, - "facing=north,upwards_facing=west": { - "gtceu:z": 90, - "model": "cosmiccore:block/machine/star_ladder" - }, - "facing=south,upwards_facing=east": { - "gtceu:z": 270, - "model": "cosmiccore:block/machine/star_ladder", - "y": 180 - }, - "facing=south,upwards_facing=north": { - "model": "cosmiccore:block/machine/star_ladder", - "y": 180 - }, - "facing=south,upwards_facing=south": { - "gtceu:z": 180, - "model": "cosmiccore:block/machine/star_ladder", - "y": 180 - }, - "facing=south,upwards_facing=west": { - "gtceu:z": 90, - "model": "cosmiccore:block/machine/star_ladder", - "y": 180 - }, - "facing=west,upwards_facing=east": { - "gtceu:z": 270, - "model": "cosmiccore:block/machine/star_ladder", - "y": 270 - }, - "facing=west,upwards_facing=north": { - "model": "cosmiccore:block/machine/star_ladder", - "y": 270 - }, - "facing=west,upwards_facing=south": { - "gtceu:z": 180, - "model": "cosmiccore:block/machine/star_ladder", - "y": 270 - }, - "facing=west,upwards_facing=west": { - "gtceu:z": 90, - "model": "cosmiccore:block/machine/star_ladder", - "y": 270 } } } \ No newline at end of file diff --git a/src/generated/resources/assets/cosmiccore/lang/en_ud.json b/src/generated/resources/assets/cosmiccore/lang/en_ud.json index 99b63e4bd..fcb5a18a8 100644 --- a/src/generated/resources/assets/cosmiccore/lang/en_ud.json +++ b/src/generated/resources/assets/cosmiccore/lang/en_ud.json @@ -270,6 +270,7 @@ "block.cosmiccore.somarust_casing": "buısɐƆ ʇsnɹɐɯoS", "block.cosmiccore.soul_muted_casing": "buısɐƆ pǝʇnW ןnoS", "block.cosmiccore.soul_stained_steel_aluminium_plated_casing": "buısɐƆ pǝʇɐןԀ ɯnıuıɯnןⱯ ןǝǝʇS pǝuıɐʇS ןnoS", + "block.cosmiccore.soul_tester": "ɹǝʇsǝ⟘ ןnoS", "block.cosmiccore.spirit_crucible": "ǝןqıɔnɹƆ ʇıɹıdS", "block.cosmiccore.star_ladder": "ɹǝppɐꞀ ɹɐʇS", "block.cosmiccore.steam_caster": "ɹǝʇsɐƆ ɯɐǝʇS", @@ -1313,6 +1314,7 @@ "item.cosmiccore.simple_rebreather": "ɹǝɥʇɐǝɹqǝᴚ ǝןdɯıS", "item.cosmiccore.simple_rebreather.tooltip": "˙sʇuǝɯuoɹıʌuǝ ㄥ§ɹıⱯ uıɥ⟘q§ uı uıɐɹp uǝbʎxo sǝɔnpǝᴚㄥ§", "item.cosmiccore.somatic_processing_assembly": "pɹɐoᗺ ʎןqɯǝssⱯ buıssǝɔoɹdoʇɐɯoS", + "item.cosmiccore.soul_reader": "ɹǝpɐǝᴚ ʞɹoʍʇǝN ןnoS", "item.cosmiccore.sov_blood_orb": "qɹO pooןᗺ ubıǝɹǝʌoS", "item.cosmiccore.space_advanced_nanomuscle_chestplate": "ǝʇɐןdʇsǝɥƆ ǝʇınS ǝɔɐdS ™ǝןɔsnWouɐN pǝɔuɐʌpⱯ", "item.cosmiccore.space_advanced_quarktech_chestplate": "ǝʇɐןdʇsǝɥƆ ǝʇınS ǝɔɐdS ™ɥɔǝ⟘ʞɹɐnὉ pǝɔuɐʌpⱯ", diff --git a/src/generated/resources/assets/cosmiccore/lang/en_us.json b/src/generated/resources/assets/cosmiccore/lang/en_us.json index 257dac0a1..1cfb1cbae 100644 --- a/src/generated/resources/assets/cosmiccore/lang/en_us.json +++ b/src/generated/resources/assets/cosmiccore/lang/en_us.json @@ -270,6 +270,7 @@ "block.cosmiccore.somarust_casing": "Somarust Casing", "block.cosmiccore.soul_muted_casing": "Soul Muted Casing", "block.cosmiccore.soul_stained_steel_aluminium_plated_casing": "Soul Stained Steel Aluminium Plated Casing", + "block.cosmiccore.soul_tester": "Soul Tester", "block.cosmiccore.spirit_crucible": "Spirit Crucible", "block.cosmiccore.star_ladder": "Star Ladder", "block.cosmiccore.steam_caster": "Steam Caster", @@ -491,15 +492,6 @@ "cosmic.gui.wireless.energy.player": "§aPlayer:§a %s", "cosmic.gui.wireless.energy.stored": "§eStorage §b%s §f%s/%s", "cosmic.gui.wireless.energy.team": "§aTeam:§a %s", - "cosmiccore.gui.soul.impure.name": "Impure", - "cosmiccore.gui.soul.rusted.name": "Rusted", - "cosmiccore.gui.soul.proud.name": "Proud", - "cosmiccore.gui.soul.greedy.name": "Greedy", - "cosmiccore.gui.soul.envious.name": "Envious", - "cosmiccore.gui.soul.gluttonous.name": "Gluttonous", - "cosmiccore.gui.soul.wrathful.name": "Wrathful", - "cosmiccore.gui.soul.slothful.name": "Slothful", - "cosmiccore.gui.soul.temporal.name": "Temporal", "cosmic.multiblock.capacitor.buffered": "§7Buffered: %s §7EU", "cosmic.multiblock.capacitor.duplicate.multiblock.1": "This multiblock is a duplicate", "cosmic.multiblock.capacitor.duplicate.multiblock.2": "Only one can exist", @@ -1322,6 +1314,7 @@ "item.cosmiccore.simple_rebreather": "Simple Rebreather", "item.cosmiccore.simple_rebreather.tooltip": "§7Reduces oxygen drain in §bThin Air§7 environments.", "item.cosmiccore.somatic_processing_assembly": "Somatoprocessing Assembly Board", + "item.cosmiccore.soul_reader": "Soul Network Reader", "item.cosmiccore.sov_blood_orb": "Sovereign Blood Orb", "item.cosmiccore.space_advanced_nanomuscle_chestplate": "Advanced NanoMuscle™ Space Suite Chestplate", "item.cosmiccore.space_advanced_quarktech_chestplate": "Advanced QuarkTech™ Space Suite Chestplate", diff --git a/src/generated/resources/assets/cosmiccore/models/block/machine/soul_tester.json b/src/generated/resources/assets/cosmiccore/models/block/machine/soul_tester.json new file mode 100644 index 000000000..af218192d --- /dev/null +++ b/src/generated/resources/assets/cosmiccore/models/block/machine/soul_tester.json @@ -0,0 +1,90 @@ +{ + "parent": "minecraft:block/block", + "loader": "gtceu:machine", + "machine": "cosmiccore:soul_tester", + "texture_overrides": { + "all": "gtceu:block/casings/solid/machine_casing_inert_ptfe" + }, + "variants": { + "is_formed=false,recipe_logic_status=idle": { + "model": { + "parent": "gtceu:block/machine/template/cube_all/sided", + "textures": { + "all": "gtceu:block/casings/solid/machine_casing_inert_ptfe", + "overlay_front": "gtceu:block/multiblock/coke_oven/overlay_front", + "overlay_front_emissive": "gtceu:block/multiblock/coke_oven/overlay_front_emissive" + } + } + }, + "is_formed=false,recipe_logic_status=suspend": { + "model": { + "parent": "gtceu:block/machine/template/cube_all/sided", + "textures": { + "all": "gtceu:block/casings/solid/machine_casing_inert_ptfe", + "overlay_front": "gtceu:block/multiblock/coke_oven/overlay_front", + "overlay_front_emissive": "gtceu:block/multiblock/coke_oven/overlay_front_emissive" + } + } + }, + "is_formed=false,recipe_logic_status=waiting": { + "model": { + "parent": "gtceu:block/machine/template/cube_all/sided", + "textures": { + "all": "gtceu:block/casings/solid/machine_casing_inert_ptfe", + "overlay_front": "gtceu:block/multiblock/coke_oven/overlay_front_active", + "overlay_front_emissive": "gtceu:block/multiblock/coke_oven/overlay_front_active_emissive" + } + } + }, + "is_formed=false,recipe_logic_status=working": { + "model": { + "parent": "gtceu:block/machine/template/cube_all/sided", + "textures": { + "all": "gtceu:block/casings/solid/machine_casing_inert_ptfe", + "overlay_front": "gtceu:block/multiblock/coke_oven/overlay_front_active", + "overlay_front_emissive": "gtceu:block/multiblock/coke_oven/overlay_front_active_emissive" + } + } + }, + "is_formed=true,recipe_logic_status=idle": { + "model": { + "parent": "gtceu:block/machine/template/cube_all/sided", + "textures": { + "all": "gtceu:block/casings/solid/machine_casing_inert_ptfe", + "overlay_front": "gtceu:block/multiblock/coke_oven/overlay_front", + "overlay_front_emissive": "gtceu:block/multiblock/coke_oven/overlay_front_emissive" + } + } + }, + "is_formed=true,recipe_logic_status=suspend": { + "model": { + "parent": "gtceu:block/machine/template/cube_all/sided", + "textures": { + "all": "gtceu:block/casings/solid/machine_casing_inert_ptfe", + "overlay_front": "gtceu:block/multiblock/coke_oven/overlay_front", + "overlay_front_emissive": "gtceu:block/multiblock/coke_oven/overlay_front_emissive" + } + } + }, + "is_formed=true,recipe_logic_status=waiting": { + "model": { + "parent": "gtceu:block/machine/template/cube_all/sided", + "textures": { + "all": "gtceu:block/casings/solid/machine_casing_inert_ptfe", + "overlay_front": "gtceu:block/multiblock/coke_oven/overlay_front_active", + "overlay_front_emissive": "gtceu:block/multiblock/coke_oven/overlay_front_active_emissive" + } + } + }, + "is_formed=true,recipe_logic_status=working": { + "model": { + "parent": "gtceu:block/machine/template/cube_all/sided", + "textures": { + "all": "gtceu:block/casings/solid/machine_casing_inert_ptfe", + "overlay_front": "gtceu:block/multiblock/coke_oven/overlay_front_active", + "overlay_front_emissive": "gtceu:block/multiblock/coke_oven/overlay_front_active_emissive" + } + } + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/cosmiccore/models/item/soul_reader.json b/src/generated/resources/assets/cosmiccore/models/item/soul_reader.json new file mode 100644 index 000000000..28c03ad37 --- /dev/null +++ b/src/generated/resources/assets/cosmiccore/models/item/soul_reader.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "cosmiccore:item/soul_reader" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/cosmiccore/models/item/soul_tester.json b/src/generated/resources/assets/cosmiccore/models/item/soul_tester.json new file mode 100644 index 000000000..29eddc535 --- /dev/null +++ b/src/generated/resources/assets/cosmiccore/models/item/soul_tester.json @@ -0,0 +1,3 @@ +{ + "parent": "cosmiccore:block/machine/soul_tester" +} \ No newline at end of file diff --git a/src/main/java/com/ghostipedia/cosmiccore/integration/kjs/CosmicCoreKubeJSPlugin.java b/src/main/java/com/ghostipedia/cosmiccore/integration/kjs/CosmicCoreKubeJSPlugin.java index 875e2b221..4ebe0fd54 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/integration/kjs/CosmicCoreKubeJSPlugin.java +++ b/src/main/java/com/ghostipedia/cosmiccore/integration/kjs/CosmicCoreKubeJSPlugin.java @@ -1,6 +1,7 @@ package com.ghostipedia.cosmiccore.integration.kjs; import com.ghostipedia.cosmiccore.CosmicCore; +import com.ghostipedia.cosmiccore.api.capability.souls.SoulType; import com.ghostipedia.cosmiccore.common.data.CosmicBlocks; import com.ghostipedia.cosmiccore.common.data.CosmicItems; import com.ghostipedia.cosmiccore.common.data.CosmicMachines; @@ -63,6 +64,7 @@ public void registerBindings(BindingsEvent event) { event.add("CosmicMachines", CosmicMachines.class); event.add("CosmicItems", CosmicItems.class); event.add("CosmicRecipeTypes", CosmicRecipeTypes.class); + event.add("CosmicSoulTypes", SoulType.class); event.add("CosmicCore", CosmicCore.class); } diff --git a/src/main/java/com/ghostipedia/cosmiccore/integration/kjs/recipe/CosmicCoreRecipeSchema.java b/src/main/java/com/ghostipedia/cosmiccore/integration/kjs/recipe/CosmicCoreRecipeSchema.java index b6eb267c2..4e34ba7aa 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/integration/kjs/recipe/CosmicCoreRecipeSchema.java +++ b/src/main/java/com/ghostipedia/cosmiccore/integration/kjs/recipe/CosmicCoreRecipeSchema.java @@ -3,6 +3,8 @@ import com.ghostipedia.cosmiccore.api.capability.recipe.EmberRecipeCapability; import com.ghostipedia.cosmiccore.api.capability.recipe.SoulRecipeCapability; import com.ghostipedia.cosmiccore.api.capability.recipe.SterileRecipeCapability; +import com.ghostipedia.cosmiccore.api.capability.souls.SoulType; +import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulIngredient; import com.ghostipedia.cosmiccore.common.recipe.condition.TitanCondition; import com.gregtechceu.gtceu.integration.kjs.recipe.GTRecipeSchema; @@ -19,12 +21,12 @@ public interface CosmicCoreRecipeSchema { @Accessors(chain = true, fluent = true) class CosmicRecipeJS extends GTRecipeSchema.GTRecipeJS { - public GTRecipeSchema.GTRecipeJS soulInput(int souls) { - return this.input(SoulRecipeCapability.CAP, souls); + public GTRecipeSchema.GTRecipeJS soulInput(SoulType type, int souls) { + return this.input(SoulRecipeCapability.CAP, SoulIngredient.of(type, souls)); } - public GTRecipeSchema.GTRecipeJS soulOutput(int souls) { - return this.output(SoulRecipeCapability.CAP, souls); + public GTRecipeSchema.GTRecipeJS soulOutput(SoulType type, int souls) { + return this.output(SoulRecipeCapability.CAP, SoulIngredient.of(type, souls)); } public GTRecipeSchema.GTRecipeJS titanTier(int tier) { diff --git a/src/main/java/com/ghostipedia/cosmiccore/integration/kjs/recipe/components/CosmicRecipeComponent.java b/src/main/java/com/ghostipedia/cosmiccore/integration/kjs/recipe/components/CosmicRecipeComponent.java index 22bbcbd2f..908f2ed64 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/integration/kjs/recipe/components/CosmicRecipeComponent.java +++ b/src/main/java/com/ghostipedia/cosmiccore/integration/kjs/recipe/components/CosmicRecipeComponent.java @@ -3,21 +3,56 @@ import com.ghostipedia.cosmiccore.api.capability.recipe.EmberRecipeCapability; import com.ghostipedia.cosmiccore.api.capability.recipe.SoulRecipeCapability; +import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulIngredient; +import com.google.gson.JsonElement; import com.gregtechceu.gtceu.integration.kjs.recipe.components.ContentJS; +import com.mojang.serialization.JsonOps; +import dev.latvian.mods.kubejs.recipe.RecipeJS; import dev.latvian.mods.kubejs.recipe.component.NumberComponent; +import dev.latvian.mods.kubejs.recipe.component.RecipeComponent; +import dev.latvian.mods.rhino.Wrapper; public class CosmicRecipeComponent { - public static final ContentJS SOUL_IN = new ContentJS<>(NumberComponent.ANY_INT, SoulRecipeCapability.CAP, - false); - public static final ContentJS SOUL_OUT = new ContentJS<>(NumberComponent.ANY_INT, SoulRecipeCapability.CAP, - true); - public static final ContentJS EMBER_IN = new ContentJS<>(NumberComponent.ANY_DOUBLE, EmberRecipeCapability.CAP, false); public static final ContentJS EMBER_OUT = new ContentJS<>(NumberComponent.ANY_DOUBLE, EmberRecipeCapability.CAP, true); + + public static final RecipeComponent SOUL_STACK = new RecipeComponent<>() { + + @Override + public Class componentClass() { + return SoulIngredient.class; + } + + @Override + public String componentType() { + return "soul_stack"; + } + + @Override + public JsonElement write(RecipeJS recipeJS, SoulIngredient soulIngredient) { + return SoulIngredient.CODEC.encodeStart(JsonOps.INSTANCE, soulIngredient).result().orElse(null); + } + + @Override + public SoulIngredient read(RecipeJS recipeJS, Object o) { + if (o instanceof Wrapper w) o = w.unwrap(); + + if (o instanceof SoulIngredient soulIngredient) { + return soulIngredient; + } else { + return null; + } + } + }; + + public static final ContentJS SOUL_IN = new ContentJS<>(SOUL_STACK, SoulRecipeCapability.CAP, + false); + public static final ContentJS SOUL_OUT = new ContentJS<>(SOUL_STACK, SoulRecipeCapability.CAP, + true); } diff --git a/src/main/resources/assets/cosmiccore/textures/item/soul_reader.png b/src/main/resources/assets/cosmiccore/textures/item/soul_reader.png new file mode 100644 index 0000000000000000000000000000000000000000..b900d2016df8fd3c4c06c9b16d3ccbcd890cad65 GIT binary patch literal 269 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFhtGXS2rmyU%Rer z;-sw;r24Xjqm$FhVx@G9O$9{7$_}tO097-V1o;IsI6S+N2IRzhx;TbZ+)8#}onx%{ zW!2P1X$O=3OOV literal 0 HcmV?d00001 From 629d1374ca66daceee7e81dc0a347078e25bfae4 Mon Sep 17 00:00:00 2001 From: MrQuentinet <32539717+mrquentin@users.noreply.github.com> Date: Sat, 17 Jan 2026 16:29:25 -0500 Subject: [PATCH 15/28] Add missing soul types --- .../cosmiccore/api/capability/souls/SoulType.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/capability/souls/SoulType.java b/src/main/java/com/ghostipedia/cosmiccore/api/capability/souls/SoulType.java index f0ac1c9ab..7ba02efc7 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/capability/souls/SoulType.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/capability/souls/SoulType.java @@ -15,10 +15,11 @@ import java.util.stream.Collectors; public enum SoulType implements StringRepresentable { - Impure("impure", ChatFormatting.DARK_GRAY), - Rusted("rusted", ChatFormatting.GRAY), + Raw("raw", ChatFormatting.DARK_RED), + Refined("refined", ChatFormatting.GRAY), Proud("proud", ChatFormatting.DARK_PURPLE), Greedy("greedy", ChatFormatting.YELLOW), + Lustful("lustful", ChatFormatting.LIGHT_PURPLE), Envious("envious", ChatFormatting.GREEN), Gluttonous("gluttonous", ChatFormatting.GOLD), Wrathful("wrathful", ChatFormatting.RED), From 924d96fdd953da9236dfd839819ea316110e3649 Mon Sep 17 00:00:00 2001 From: MrQuentinet <32539717+mrquentin@users.noreply.github.com> Date: Mon, 19 Jan 2026 14:12:04 -0500 Subject: [PATCH 16/28] Add more kjs integration --- .../api/capability/recipe/SoulRecipeCapability.java | 4 ++-- .../cosmiccore/api/recipe/ingredient/SoulStack.java | 2 +- .../ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java | 2 +- .../kjs/recipe/components/CosmicRecipeComponent.java | 2 ++ 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/capability/recipe/SoulRecipeCapability.java b/src/main/java/com/ghostipedia/cosmiccore/api/capability/recipe/SoulRecipeCapability.java index 228607494..669cf5923 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/capability/recipe/SoulRecipeCapability.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/capability/recipe/SoulRecipeCapability.java @@ -87,12 +87,12 @@ private static class SerializerSoulIngredient implements IContentSerializer provider) { SOUL_TESTER_RECIPES.recipeBuilder("generate_soul") .notConsumable(Items.DIRT) - .output(CosmicRecipeCapabilities.SOUL, SoulIngredient.of(SoulType.Impure, 10)) + .output(CosmicRecipeCapabilities.SOUL, SoulIngredient.of(SoulType.Raw, 10)) .output(CosmicRecipeCapabilities.SOUL, SoulIngredient.of(SoulType.Temporal, 50)) .duration(20) .save(provider); diff --git a/src/main/java/com/ghostipedia/cosmiccore/integration/kjs/recipe/components/CosmicRecipeComponent.java b/src/main/java/com/ghostipedia/cosmiccore/integration/kjs/recipe/components/CosmicRecipeComponent.java index 908f2ed64..73c07cb2e 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/integration/kjs/recipe/components/CosmicRecipeComponent.java +++ b/src/main/java/com/ghostipedia/cosmiccore/integration/kjs/recipe/components/CosmicRecipeComponent.java @@ -46,6 +46,8 @@ public SoulIngredient read(RecipeJS recipeJS, Object o) { if (o instanceof SoulIngredient soulIngredient) { return soulIngredient; } else { + System.out.println("Shit we have a problem !"); + System.out.println("object type: " + o.getClass().descriptorString()); return null; } } From 3797a799e1555264f0f51d7ec32e3a19bb51cedd Mon Sep 17 00:00:00 2001 From: MrQuentinet <32539717+mrquentin@users.noreply.github.com> Date: Mon, 19 Jan 2026 14:21:56 -0500 Subject: [PATCH 17/28] Add another test recipe --- .../ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java b/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java index 0985e873b..6951774a1 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java +++ b/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java @@ -50,6 +50,12 @@ public static void init(Consumer provider) { .duration(20) .save(provider); + SOUL_TESTER_RECIPES.recipeBuilder("generate_soul") + .input(CosmicRecipeCapabilities.SOUL, SoulIngredient.of(SoulType.Raw, 10)) + .outputItems(ingot, Steel) + .duration(20) + .save(provider); + // GROVE_RECIPES.recipeBuilder("dirt_movement") // .input(SoulRecipeCapability.CAP, 100) // .notConsumable(CosmicItems.DONK) From 82a5ff91a1de88cd23e7705c9896cfb08253906c Mon Sep 17 00:00:00 2001 From: MrQuentinet <32539717+mrquentin@users.noreply.github.com> Date: Mon, 19 Jan 2026 15:37:16 -0500 Subject: [PATCH 18/28] fix recipe soul consumption and add lang --- .../assets/cosmiccore/lang/en_us.json | 32 ++++++++++++++++++- .../recipe/SoulRecipeCapability.java | 22 +++++++------ .../api/capability/souls/SoulType.java | 2 +- .../api/recipe/lookup/MapSoulIngredient.java | 2 +- .../gtbridge/CosmicCoreRecipes.java | 3 +- 5 files changed, 47 insertions(+), 14 deletions(-) diff --git a/src/generated/resources/assets/cosmiccore/lang/en_us.json b/src/generated/resources/assets/cosmiccore/lang/en_us.json index 1cfb1cbae..fbf1b5dd5 100644 --- a/src/generated/resources/assets/cosmiccore/lang/en_us.json +++ b/src/generated/resources/assets/cosmiccore/lang/en_us.json @@ -1896,5 +1896,35 @@ "tooltip.cosmiccore.thermia_hatch_limit": "§cTemp. Limit: %sK", "tooltip.gt_scythe.energy": "Energy: %s / %s EU", "tooltip.gt_scythe.no_energy": "§cNot enough energy.", - "tooltip.gt_scythe.per_hit": "Cost: %s EU / hit" + "tooltip.gt_scythe.per_hit": "Cost: %s EU / hit", + "recipe.cosmiccore.raw_soul_in": "Consumes: %s Raw souls", + "recipe.cosmiccore.refined_soul_in": "Consumes: %s Refined souls", + "recipe.cosmiccore.proud_soul_in": "Consumes: %s Proud souls", + "recipe.cosmiccore.greedy_soul_in": "Consumes: %s Greedy souls", + "recipe.cosmiccore.lustful_soul_in": "Consumes: %s Lustful souls", + "recipe.cosmiccore.envious_soul_in": "Consumes: %s Envious souls", + "recipe.cosmiccore.gluttonous_soul_in": "Consumes: %s Gluttonous souls", + "recipe.cosmiccore.wrathful_soul_in": "Consumes: %s Wrathful souls", + "recipe.cosmiccore.slothful_soul_in": "Consumes: %s Slothful souls", + "recipe.cosmiccore.temporal_soul_in": "Consumes: %s Temporal souls", + "recipe.cosmiccore.raw_soul_out": "Produces: %s Raw souls", + "recipe.cosmiccore.refined_soul_out": "Produces: %s Refined souls", + "recipe.cosmiccore.proud_soul_out": "Produces: %s Proud souls", + "recipe.cosmiccore.greedy_soul_out": "Produces: %s Greedy souls", + "recipe.cosmiccore.lustful_soul_out": "Produces: %s Lustful souls", + "recipe.cosmiccore.envious_soul_out": "Produces: %s Envious souls", + "recipe.cosmiccore.gluttonous_soul_out": "Produces: %s Gluttonous souls", + "recipe.cosmiccore.wrathful_soul_out": "Produces: %s Wrathful souls", + "recipe.cosmiccore.slothful_soul_out": "Produces: %s Slothful souls", + "recipe.cosmiccore.temporal_soul_out": "Produces: %s Temporal souls", + "gui.cosmiccore.soul.raw.name": "Raw souls", + "gui.cosmiccore.soul.refined.name": "Refined souls", + "gui.cosmiccore.soul.proud.name": "Proud souls", + "gui.cosmiccore.soul.greedy.name": "Greedy souls", + "gui.cosmiccore.soul.lustful.name": "Lustful souls", + "gui.cosmiccore.soul.envious.name": "Envious souls", + "gui.cosmiccore.soul.gluttonous.name": "Gluttonous souls", + "gui.cosmiccore.soul.wrathful.name": "Wrathful souls", + "gui.cosmiccore.soul.slothful.name": "Slothful souls", + "gui.cosmiccore.soul.temporal.name": "Temporal souls" } \ No newline at end of file diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/capability/recipe/SoulRecipeCapability.java b/src/main/java/com/ghostipedia/cosmiccore/api/capability/recipe/SoulRecipeCapability.java index 669cf5923..e84e46e07 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/capability/recipe/SoulRecipeCapability.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/capability/recipe/SoulRecipeCapability.java @@ -10,8 +10,10 @@ import com.gregtechceu.gtceu.api.recipe.content.ContentModifier; import com.gregtechceu.gtceu.api.recipe.content.IContentSerializer; +import com.lowdragmc.lowdraglib.gui.widget.LabelWidget; import com.lowdragmc.lowdraglib.gui.widget.WidgetGroup; +import com.lowdragmc.lowdraglib.utils.LocalizationUtils; import com.mojang.serialization.Codec; import org.apache.commons.lang3.mutable.MutableInt; @@ -67,16 +69,16 @@ public List compressIngredients(Collection ingredients) { @Override public void addXEIInfo(WidgetGroup group, int xOffset, GTRecipe recipe, List contents, boolean perTick, boolean isInput, MutableInt yOffset) { - //TODO: ADD XEI info -// String type = contents.stream().map(Content::getContent).map(SoulRecipeCapability.CAP::of).map(SoulStack::type).map(SoulType::getSerializedName).findFirst().orElse(""); -// long soul = contents.stream().map(Content::getContent).map(SoulRecipeCapability.CAP::of).mapToLong(SoulStack::amount).sum(); -// if (isInput) { -// group.addWidget(new LabelWidget(3 - xOffset, yOffset.addAndGet(10), -// LocalizationUtils.format("cosmiccore.recipe." + type + "_soul_in", soul))); -// } else { -// group.addWidget(new LabelWidget(3 - xOffset, yOffset.addAndGet(10), -// LocalizationUtils.format("cosmiccore.recipe." + type + "_soul_out", soul))); -// } + + String type = contents.stream().map(Content::getContent).map(SoulRecipeCapability.CAP::of).map(SoulIngredient::stack).map(SoulStack::type).map(SoulType::getSerializedName).findFirst().orElse(""); + long soul = contents.stream().map(Content::getContent).map(SoulRecipeCapability.CAP::of).map(SoulIngredient::stack).mapToLong(SoulStack::amount).sum(); + if (isInput) { + group.addWidget(new LabelWidget(3 - xOffset, yOffset.addAndGet(10), + LocalizationUtils.format("recipe.cosmiccore." + type + "_soul_in", soul))); + } else { + group.addWidget(new LabelWidget(3 - xOffset, yOffset.addAndGet(10), + LocalizationUtils.format("recipe.cosmiccore." + type + "_soul_out", soul))); + } } private static class SerializerSoulIngredient implements IContentSerializer { diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/capability/souls/SoulType.java b/src/main/java/com/ghostipedia/cosmiccore/api/capability/souls/SoulType.java index 7ba02efc7..554b6030f 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/capability/souls/SoulType.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/capability/souls/SoulType.java @@ -54,7 +54,7 @@ public Component toComponent(int amount) { } public Component toComponent(int amount, boolean formatted) { - MutableComponent nameComp = Component.translatable("cosmiccore.gui.soul." + name + ".name"); + MutableComponent nameComp = Component.translatable("gui.cosmiccore.soul." + name + ".name"); MutableComponent amountComp = Component.literal(" : " + amount).withStyle(Style.EMPTY); if (formatted) { nameComp = nameComp.withStyle(ChatFormatting.BOLD, this.color); diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/recipe/lookup/MapSoulIngredient.java b/src/main/java/com/ghostipedia/cosmiccore/api/recipe/lookup/MapSoulIngredient.java index eb14168ab..991bb36b9 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/recipe/lookup/MapSoulIngredient.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/recipe/lookup/MapSoulIngredient.java @@ -22,7 +22,7 @@ protected int hash() { @Override public boolean equals(Object o) { if (!(o instanceof MapSoulIngredient other)) return false; - return stack.equals(other.stack); + return stack.type().equals(other.stack.type()); } public static List from(SoulIngredient soulIngredient) { diff --git a/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java b/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java index 6951774a1..91a49d774 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java +++ b/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java @@ -50,7 +50,8 @@ public static void init(Consumer provider) { .duration(20) .save(provider); - SOUL_TESTER_RECIPES.recipeBuilder("generate_soul") + SOUL_TESTER_RECIPES.recipeBuilder("generate_soul_2") + .inputItems(Items.DIRT) .input(CosmicRecipeCapabilities.SOUL, SoulIngredient.of(SoulType.Raw, 10)) .outputItems(ingot, Steel) .duration(20) From 0a9b658f63b1144f5f5c092eea669f08f63d503f Mon Sep 17 00:00:00 2001 From: MrQuentinet <32539717+mrquentin@users.noreply.github.com> Date: Mon, 19 Jan 2026 15:56:18 -0500 Subject: [PATCH 19/28] fixed saved data --- .../api/data/souls/SoulNetwork.java | 14 ++++++++-- .../api/data/souls/SoulNetworkSavedData.java | 27 +++++++++++++------ .../trait/NotifiableSoulContainer.java | 6 ++++- .../common/item/SoulNetworkReaderItem.java | 3 ++- 4 files changed, 38 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java b/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java index c122186ef..3af272702 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java @@ -3,6 +3,7 @@ import com.ghostipedia.cosmiccore.api.capability.souls.SoulType; import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulStack; import lombok.Getter; +import lombok.Setter; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.Tag; @@ -17,6 +18,9 @@ public class SoulNetwork implements INBTSerializable { @Getter private int tier = 0; + @Setter + private Runnable dirtyCallback; + private final Map contents = new ConcurrentHashMap<>(); public SoulNetwork() {} @@ -29,7 +33,10 @@ public SoulStack add(SoulStack stack, int throughput, boolean simulate) { amountToAdd = Math.min(amountToAdd, getSize() - totalAmount); // Respect network capacity amountToAdd = Math.max(0, amountToAdd); // Ensure we don't add a negative amount - if (!simulate && amountToAdd > 0) this.contents.put(stack.type(), currentAmount + amountToAdd); + if (!simulate && amountToAdd > 0) { + this.contents.put(stack.type(), currentAmount + amountToAdd); + if (dirtyCallback != null) dirtyCallback.run(); + } System.out.println(this); @@ -40,7 +47,10 @@ public SoulStack syphon(SoulStack stack, boolean simulate) { var currentSoulContent = this.contents.getOrDefault(stack.type(), 0); int amountToSyphon = Math.min(stack.amount(), currentSoulContent); - if (!simulate && amountToSyphon > 0) this.contents.put(stack.type(), currentSoulContent - amountToSyphon); + if (!simulate && amountToSyphon > 0) { + this.contents.put(stack.type(), currentSoulContent - amountToSyphon); + if (dirtyCallback != null) dirtyCallback.run(); + } return stack.withAmount(amountToSyphon); } diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetworkSavedData.java b/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetworkSavedData.java index 74eb2ed3f..d20917e83 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetworkSavedData.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetworkSavedData.java @@ -12,32 +12,43 @@ import java.util.UUID; public class SoulNetworkSavedData extends SavedData { - + private static final String DATA_NAME = CosmicCore.MOD_ID + "_soul_network_data"; private static final String SOUL_NETWORK_MAPPING = "soul_network_mapping"; private static final String SOUL_NETWORK_UUID = "soul_network_uuid"; private static final String SOUL_NETWORK_DATA = "soul_network_data"; - public static final HashMap SoulNetworkMapping = new HashMap<>(20, 0.9f); + private final HashMap soulNetworkMapping = new HashMap<>(20, 0.9f); public static SoulNetworkSavedData getOrCreate(ServerLevel serverLevel) { return serverLevel.getDataStorage().computeIfAbsent(SoulNetworkSavedData::new, SoulNetworkSavedData::new, DATA_NAME); } - public static SoulNetwork getSoulNetwork(UUID owner) { - return SoulNetworkMapping.computeIfAbsent(owner, id -> new SoulNetwork()); + public static SoulNetwork getSoulNetwork(ServerLevel level, UUID owner) { + SoulNetworkSavedData savedData = getOrCreate(level); + return savedData.getNetwork(owner); + } + + public SoulNetwork getNetwork(UUID owner) { + return soulNetworkMapping.computeIfAbsent(owner, id -> { + SoulNetwork network = new SoulNetwork(); + network.setDirtyCallback(this::setDirty); + setDirty(); + return network; + }); } - private SoulNetworkSavedData() {} + public SoulNetworkSavedData() {} - private SoulNetworkSavedData(CompoundTag nbt) { + public SoulNetworkSavedData(CompoundTag nbt) { var list = nbt.getList(SOUL_NETWORK_MAPPING, CompoundTag.TAG_COMPOUND); for (Tag tag : list) { if (tag instanceof CompoundTag compoundTag) { var uuid = UUID.fromString(compoundTag.getString(SOUL_NETWORK_UUID)); var data = new SoulNetwork(); data.deserializeNBT(compoundTag.getCompound(SOUL_NETWORK_DATA)); - SoulNetworkMapping.put(uuid, data); + data.setDirtyCallback(this::setDirty); + soulNetworkMapping.put(uuid, data); } } } @@ -45,7 +56,7 @@ private SoulNetworkSavedData(CompoundTag nbt) { @Override public @NotNull CompoundTag save(@NotNull CompoundTag compoundTag) { var soulNetworkDataList = new ListTag(); - for (var entry : SoulNetworkMapping.entrySet()) { + for (var entry : soulNetworkMapping.entrySet()) { var tag = new CompoundTag(); tag.putString(SOUL_NETWORK_UUID, entry.getKey().toString()); tag.put(SOUL_NETWORK_DATA, entry.getValue().serializeNBT()); diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java b/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java index 609b49993..2d986fffa 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java @@ -12,6 +12,7 @@ import com.gregtechceu.gtceu.api.recipe.GTRecipe; import com.gregtechceu.gtceu.common.machine.owner.FTBOwner; import lombok.Getter; +import net.minecraft.server.level.ServerLevel; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -33,7 +34,10 @@ public NotifiableSoulContainer(MetaMachine machine, IO io, int throughput) { } private SoulNetwork getSoulNetwork() { - return SoulNetworkSavedData.getSoulNetwork(getOwner()); + if (this.machine.getLevel() instanceof ServerLevel serverLevel) { + return SoulNetworkSavedData.getSoulNetwork(serverLevel, getOwner()); + } + return new SoulNetwork(); } private UUID getOwner() { diff --git a/src/main/java/com/ghostipedia/cosmiccore/common/item/SoulNetworkReaderItem.java b/src/main/java/com/ghostipedia/cosmiccore/common/item/SoulNetworkReaderItem.java index dd6cee455..826a7924c 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/common/item/SoulNetworkReaderItem.java +++ b/src/main/java/com/ghostipedia/cosmiccore/common/item/SoulNetworkReaderItem.java @@ -5,6 +5,7 @@ import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulStack; import net.minecraft.ChatFormatting; import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResultHolder; @@ -25,7 +26,7 @@ public SoulNetworkReaderItem(Properties properties) { public InteractionResultHolder use(Level level, Player player, InteractionHand hand) { if (!level.isClientSide() && player instanceof ServerPlayer serverPlayer) { //TODO: get team or player uuid - SoulNetwork soulNetwork = SoulNetworkSavedData.getSoulNetwork(player.getUUID()); + SoulNetwork soulNetwork = SoulNetworkSavedData.getSoulNetwork((ServerLevel) level, player.getUUID()); List contents = soulNetwork.getContents(); if (contents.isEmpty()) { From b552c48ea6f70e701a21d7219a1d2ac55764820f Mon Sep 17 00:00:00 2001 From: MrQuentinet <32539717+mrquentin@users.noreply.github.com> Date: Mon, 19 Jan 2026 16:14:48 -0500 Subject: [PATCH 20/28] start adding command --- .../common/commands/SoulCommand.java | 64 +++++++++++++++++++ .../common/item/SoulNetworkReaderItem.java | 1 - 2 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/ghostipedia/cosmiccore/common/commands/SoulCommand.java diff --git a/src/main/java/com/ghostipedia/cosmiccore/common/commands/SoulCommand.java b/src/main/java/com/ghostipedia/cosmiccore/common/commands/SoulCommand.java new file mode 100644 index 000000000..938676649 --- /dev/null +++ b/src/main/java/com/ghostipedia/cosmiccore/common/commands/SoulCommand.java @@ -0,0 +1,64 @@ +package com.ghostipedia.cosmiccore.common.commands; + +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import dev.ftb.mods.ftbteams.api.FTBTeamsAPI; +import dev.ftb.mods.ftbteams.api.Team; +import dev.ftb.mods.ftbteams.data.TeamArgument; +import net.minecraft.commands.CommandBuildContext; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.arguments.EntityArgument; +import net.minecraft.server.level.ServerPlayer; + +import java.util.function.BiFunction; + +import static net.minecraft.commands.Commands.*; + +public class SoulCommand { + + public static void register(CommandDispatcher dispatcher, CommandBuildContext buildContext) { + dispatcher.register( + literal("wireless") + .then(soulLiteral("info", LEVEL_ALL, SoulCommand::displayPlayerInfo, SoulCommand::displayTeamInfo)) + ); + } + + private static LiteralArgumentBuilder soulLiteral(String name, int permissionLevel, + BiFunction, ServerPlayer, Integer> playerCommand, + BiFunction, Team, Integer> teamCommand) { + return literal(name) + .requires(source -> source.hasPermission(permissionLevel)) + .then(literal("player").then(argument("player", EntityArgument.player()) + .executes(ctx -> playerCommand.apply(ctx, EntityArgument.getPlayer(ctx, "player"))))) + .then(literal("team").then(argument("team", TeamArgument.create()) + .executes(ctx -> teamCommand.apply(ctx, TeamArgument.get(ctx, "team"))))) + .executes(ctx -> sourceCommand(ctx, playerCommand, teamCommand)); + } + + private static int sourceCommand(CommandContext context, + BiFunction, ServerPlayer, Integer> playerCommand, + BiFunction, Team, Integer> teamCommand) { + var owner = getPlayerOrTeam(context.getSource().getPlayer()); + if (owner instanceof ServerPlayer player) return playerCommand.apply(context, player); + else if (owner instanceof Team team) return teamCommand.apply(context, team); + else return -1; + } + + private static Object getPlayerOrTeam(ServerPlayer player) { + var team = FTBTeamsAPI.api().getManager().getTeamForPlayer(player); + return (team.isPresent() && !team.get().isPlayerTeam()) ? team.get() : player; + } + + // #################################### + // Display Info + // #################################### + + private static int displayPlayerInfo(CommandContext context, ServerPlayer player) { + return 1; + } + + private static int displayTeamInfo(CommandContext context, Team team) { + return 1; + } +} diff --git a/src/main/java/com/ghostipedia/cosmiccore/common/item/SoulNetworkReaderItem.java b/src/main/java/com/ghostipedia/cosmiccore/common/item/SoulNetworkReaderItem.java index 826a7924c..0eec0b2ae 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/common/item/SoulNetworkReaderItem.java +++ b/src/main/java/com/ghostipedia/cosmiccore/common/item/SoulNetworkReaderItem.java @@ -25,7 +25,6 @@ public SoulNetworkReaderItem(Properties properties) { @Override public InteractionResultHolder use(Level level, Player player, InteractionHand hand) { if (!level.isClientSide() && player instanceof ServerPlayer serverPlayer) { - //TODO: get team or player uuid SoulNetwork soulNetwork = SoulNetworkSavedData.getSoulNetwork((ServerLevel) level, player.getUUID()); List contents = soulNetwork.getContents(); From 82ba582e993d6bc0b7c48f48c5e8d1e8234e53bd Mon Sep 17 00:00:00 2001 From: MrQuentinet <32539717+mrquentin@users.noreply.github.com> Date: Mon, 19 Jan 2026 16:26:35 -0500 Subject: [PATCH 21/28] Add validation that there is no second hatch in the multiblock --- .../api/capability/recipe/SoulRecipeCapability.java | 2 +- .../machine/multiblock/part/SoulHatchPartMachine.java | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/capability/recipe/SoulRecipeCapability.java b/src/main/java/com/ghostipedia/cosmiccore/api/capability/recipe/SoulRecipeCapability.java index e84e46e07..30c6f6daf 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/capability/recipe/SoulRecipeCapability.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/capability/recipe/SoulRecipeCapability.java @@ -54,7 +54,7 @@ public List compressIngredients(Collection ingredients) { if (item instanceof SoulIngredient soul) { var isEqual = false; for (Object obj : list) { - if (obj instanceof SoulIngredient soulIngredient && soul.equals(soulIngredient)) { + if (obj instanceof SoulIngredient soulIngredient && soul.stack().type().equals(soulIngredient.stack().type())) { isEqual = true; break; } diff --git a/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java b/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java index 7fb162bfa..2f556a331 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java +++ b/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java @@ -6,6 +6,7 @@ import com.gregtechceu.gtceu.api.capability.recipe.IO; import com.gregtechceu.gtceu.api.gui.GuiTextures; import com.gregtechceu.gtceu.api.machine.IMachineBlockEntity; +import com.gregtechceu.gtceu.api.machine.feature.multiblock.IMultiController; import com.gregtechceu.gtceu.api.machine.multiblock.part.TieredIOPartMachine; import com.gregtechceu.gtceu.utils.FormattingUtil; @@ -39,6 +40,15 @@ public SoulHatchPartMachine(IMachineBlockEntity holder, int tier, IO io) { this.soulContainer = new NotifiableSoulContainer(this, io, getMaxConsumption(tier)); } + @Override + public void addedToController(IMultiController controller) { + super.addedToController(controller); + boolean hasDuplicate = controller.getParts().stream() + .filter(part -> part != this) + .anyMatch(part -> part instanceof SoulHatchPartMachine soulHatch && soulHatch.io == this.io); + if (hasDuplicate) controller.onStructureInvalid(); + } + @Override public Widget createUIWidget() { var group = new WidgetGroup(0, 0, 128, 63); From 0d9162a04986b4ba5b060b1dac32b7ad3130b80d Mon Sep 17 00:00:00 2001 From: MrQuentinet <32539717+mrquentin@users.noreply.github.com> Date: Mon, 19 Jan 2026 22:05:01 -0500 Subject: [PATCH 22/28] Add admin command to manipulate soul network --- .../assets/cosmiccore/lang/en_us.json | 9 +- .../ghostipedia/cosmiccore/CosmicCore.java | 4 + .../api/data/souls/SoulNetwork.java | 12 +++ .../common/commands/SoulCommand.java | 89 ++++++++++++------- .../commands/WirelessEnergyCommand.java | 2 +- .../commands/argument/SoulTypeArgument.java | 57 ++++++++++++ .../common/item/SoulNetworkReaderItem.java | 23 +++-- .../multiblock/part/SoulHatchPartMachine.java | 15 ++-- .../forge/ForgeCommonEventListener.java | 2 + 9 files changed, 160 insertions(+), 53 deletions(-) create mode 100644 src/main/java/com/ghostipedia/cosmiccore/common/commands/argument/SoulTypeArgument.java diff --git a/src/generated/resources/assets/cosmiccore/lang/en_us.json b/src/generated/resources/assets/cosmiccore/lang/en_us.json index fbf1b5dd5..f8b0a87ac 100644 --- a/src/generated/resources/assets/cosmiccore/lang/en_us.json +++ b/src/generated/resources/assets/cosmiccore/lang/en_us.json @@ -1926,5 +1926,12 @@ "gui.cosmiccore.soul.gluttonous.name": "Gluttonous souls", "gui.cosmiccore.soul.wrathful.name": "Wrathful souls", "gui.cosmiccore.soul.slothful.name": "Slothful souls", - "gui.cosmiccore.soul.temporal.name": "Temporal souls" + "gui.cosmiccore.soul.temporal.name": "Temporal souls", + "gui.cosmiccore.soul.empty_network": "Network is empty", + "gui.cosmiccore.soul.network_contents": "--- Network Contents ---", + "gui.cosmiccore.soul.reset": "Soul network has been reset", + "gui.cosmiccore.soul.add": "Added %s %s souls to the network", + "gui.cosmiccore.soul.remove": "removed %s %s souls to the network", + "gui.cosmiccore.soul.capacity": "Capacity: %s souls", + "gui.cosmiccore.soul.set_tier": "the network is now tier %s" } \ No newline at end of file diff --git a/src/main/java/com/ghostipedia/cosmiccore/CosmicCore.java b/src/main/java/com/ghostipedia/cosmiccore/CosmicCore.java index b994a3657..3767cbff4 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/CosmicCore.java +++ b/src/main/java/com/ghostipedia/cosmiccore/CosmicCore.java @@ -10,6 +10,7 @@ import com.ghostipedia.cosmiccore.client.CosmicCoreClient; import com.ghostipedia.cosmiccore.common.airControl.OxygenItemCap; import com.ghostipedia.cosmiccore.common.airControl.OxygenRules; +import com.ghostipedia.cosmiccore.common.commands.argument.SoulTypeArgument; import com.ghostipedia.cosmiccore.common.data.*; import com.ghostipedia.cosmiccore.common.data.materials.CosmicMaterialSet; import com.ghostipedia.cosmiccore.common.data.materials.CosmicMaterials; @@ -37,6 +38,8 @@ import com.lowdragmc.lowdraglib.Platform; +import net.minecraft.commands.synchronization.ArgumentTypeInfos; +import net.minecraft.commands.synchronization.SingletonArgumentInfo; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.crafting.Ingredient; import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent; @@ -119,6 +122,7 @@ public void commonSetup(FMLCommonSetupEvent event) { CCoreNetwork.init(); OxygenRules.registerAirRanges(); DimensionMobScaling.registerScaling(); + ArgumentTypeInfos.registerByClass(SoulTypeArgument.class, SingletonArgumentInfo.contextFree(SoulTypeArgument::soulType)); }); } diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java b/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java index 3af272702..746e33f0a 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java @@ -27,6 +27,8 @@ public SoulNetwork() {} public SoulStack add(SoulStack stack, int throughput, boolean simulate) { int currentAmount = this.contents.getOrDefault(stack.type(), 0); + + // TODO check with ghosti if we should do a total volume or a volume per type int totalAmount = this.contents.values().stream().mapToInt(Integer::intValue).sum(); int amountToAdd = Math.min(stack.amount(), throughput); // Respect throughput @@ -55,12 +57,22 @@ public SoulStack syphon(SoulStack stack, boolean simulate) { return stack.withAmount(amountToSyphon); } + public void reset() { + this.contents.clear(); + if (dirtyCallback != null) dirtyCallback.run(); + } + public List getContents() { return contents.entrySet().stream() .map(kvp -> new SoulStack(kvp.getKey(), kvp.getValue())) .toList(); } + public void setTier(int tier) { + this.tier = tier; + if (dirtyCallback != null) dirtyCallback.run(); + } + public int getSize() { return switch (tier) { case 0 -> 10_000; diff --git a/src/main/java/com/ghostipedia/cosmiccore/common/commands/SoulCommand.java b/src/main/java/com/ghostipedia/cosmiccore/common/commands/SoulCommand.java index 938676649..d0228a3d1 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/common/commands/SoulCommand.java +++ b/src/main/java/com/ghostipedia/cosmiccore/common/commands/SoulCommand.java @@ -1,17 +1,20 @@ package com.ghostipedia.cosmiccore.common.commands; +import com.ghostipedia.cosmiccore.api.capability.souls.SoulType; +import com.ghostipedia.cosmiccore.api.data.souls.SoulNetworkSavedData; +import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulStack; +import com.ghostipedia.cosmiccore.common.commands.argument.SoulTypeArgument; +import com.ghostipedia.cosmiccore.common.item.SoulNetworkReaderItem; import com.mojang.brigadier.CommandDispatcher; -import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.arguments.IntegerArgumentType; import com.mojang.brigadier.context.CommandContext; -import dev.ftb.mods.ftbteams.api.FTBTeamsAPI; -import dev.ftb.mods.ftbteams.api.Team; import dev.ftb.mods.ftbteams.data.TeamArgument; import net.minecraft.commands.CommandBuildContext; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.arguments.EntityArgument; -import net.minecraft.server.level.ServerPlayer; +import net.minecraft.network.chat.Component; -import java.util.function.BiFunction; +import java.util.UUID; import static net.minecraft.commands.Commands.*; @@ -19,46 +22,66 @@ public class SoulCommand { public static void register(CommandDispatcher dispatcher, CommandBuildContext buildContext) { dispatcher.register( - literal("wireless") - .then(soulLiteral("info", LEVEL_ALL, SoulCommand::displayPlayerInfo, SoulCommand::displayTeamInfo)) + literal("soul") + .requires(source -> source.hasPermission(LEVEL_ADMINS)) + .then(literal("player") + .then(argument("player", EntityArgument.player()) + .then(literal("info").executes(ctx -> displayInfo(ctx, EntityArgument.getPlayer(ctx, "player").getUUID()))) + .then(literal("reset").executes(ctx -> resetNetwork(ctx, EntityArgument.getPlayer(ctx, "player").getUUID()))) + .then(literal("set-tier").then(argument("tier", IntegerArgumentType.integer(0, 6)) + .executes(ctx -> setTier(ctx, EntityArgument.getPlayer(ctx, "player").getUUID(), IntegerArgumentType.getInteger(ctx, "tier"))))) + .then(literal("add").then(argument("type", SoulTypeArgument.soulType()).then(argument("amount", IntegerArgumentType.integer()) + .executes(ctx -> addSouls(ctx, EntityArgument.getPlayer(ctx, "player").getUUID(), SoulTypeArgument.get(ctx, "type"), IntegerArgumentType.getInteger(ctx, "amount")))))) + .then(literal("syphon").then(argument("type", SoulTypeArgument.soulType()).then(argument("amount", IntegerArgumentType.integer()) + .executes(ctx -> syphon(ctx, EntityArgument.getPlayer(ctx, "player").getUUID(), SoulTypeArgument.get(ctx, "type"), IntegerArgumentType.getInteger(ctx, "amount")))))) + ) + ) + .then(literal("team") + .then(argument("team", TeamArgument.create()) + .then(literal("info").executes(ctx -> displayInfo(ctx, TeamArgument.get(ctx, "team").getTeamId()))) + .then(literal("reset").executes(ctx -> resetNetwork(ctx, TeamArgument.get(ctx, "team").getTeamId()))) + .then(literal("set-tier").then(argument("tier", IntegerArgumentType.integer(0, 6)) + .executes(ctx -> setTier(ctx, TeamArgument.get(ctx, "team").getTeamId(), IntegerArgumentType.getInteger(ctx, "tier"))))) + .then(literal("add").then(argument("type", SoulTypeArgument.soulType()).then(argument("amount", IntegerArgumentType.integer()) + .executes(ctx -> addSouls(ctx, TeamArgument.get(ctx, "team").getTeamId(), SoulTypeArgument.get(ctx, "type"), IntegerArgumentType.getInteger(ctx, "amount")))))) + .then(literal("syphon").then(argument("type", SoulTypeArgument.soulType()).then(argument("amount", IntegerArgumentType.integer()) + .executes(ctx -> syphon(ctx, TeamArgument.get(ctx, "team").getTeamId(), SoulTypeArgument.get(ctx, "type"), IntegerArgumentType.getInteger(ctx, "amount")))))) + ) + ) ); } - private static LiteralArgumentBuilder soulLiteral(String name, int permissionLevel, - BiFunction, ServerPlayer, Integer> playerCommand, - BiFunction, Team, Integer> teamCommand) { - return literal(name) - .requires(source -> source.hasPermission(permissionLevel)) - .then(literal("player").then(argument("player", EntityArgument.player()) - .executes(ctx -> playerCommand.apply(ctx, EntityArgument.getPlayer(ctx, "player"))))) - .then(literal("team").then(argument("team", TeamArgument.create()) - .executes(ctx -> teamCommand.apply(ctx, TeamArgument.get(ctx, "team"))))) - .executes(ctx -> sourceCommand(ctx, playerCommand, teamCommand)); + private static int displayInfo(CommandContext context, UUID owner) { + var network = SoulNetworkSavedData.getSoulNetwork(context.getSource().getLevel(), owner); + context.getSource().sendSuccess(() ->SoulNetworkReaderItem.displaySoulNetworkInfo(network), false); + return 1; } - private static int sourceCommand(CommandContext context, - BiFunction, ServerPlayer, Integer> playerCommand, - BiFunction, Team, Integer> teamCommand) { - var owner = getPlayerOrTeam(context.getSource().getPlayer()); - if (owner instanceof ServerPlayer player) return playerCommand.apply(context, player); - else if (owner instanceof Team team) return teamCommand.apply(context, team); - else return -1; + private static int setTier(CommandContext context, UUID owner, int tier) { + var network = SoulNetworkSavedData.getSoulNetwork(context.getSource().getLevel(), owner); + network.setTier(tier); + context.getSource().sendSuccess(() ->Component.translatable("gui.cosmiccore.soul.set_tier", tier), false); + return 1; } - private static Object getPlayerOrTeam(ServerPlayer player) { - var team = FTBTeamsAPI.api().getManager().getTeamForPlayer(player); - return (team.isPresent() && !team.get().isPlayerTeam()) ? team.get() : player; + private static int resetNetwork(CommandContext context, UUID owner) { + var network = SoulNetworkSavedData.getSoulNetwork(context.getSource().getLevel(), owner); + network.reset(); + context.getSource().sendSuccess(() -> Component.translatable("gui.cosmiccore.soul.reset"), false); + return 1; } - // #################################### - // Display Info - // #################################### - - private static int displayPlayerInfo(CommandContext context, ServerPlayer player) { + private static int addSouls(CommandContext context, UUID owner, SoulType type, int amount) { + var network = SoulNetworkSavedData.getSoulNetwork(context.getSource().getLevel(), owner); + network.add(new SoulStack(type, amount), Integer.MAX_VALUE, false); + context.getSource().sendSuccess(() -> Component.translatable("gui.cosmiccore.soul.add", amount, type.getSerializedName()), false); return 1; } - private static int displayTeamInfo(CommandContext context, Team team) { + private static int syphon(CommandContext context, UUID owner, SoulType type, int amount) { + var network = SoulNetworkSavedData.getSoulNetwork(context.getSource().getLevel(), owner); + network.syphon(new SoulStack(type, amount), false); + context.getSource().sendSuccess(() -> Component.translatable("gui.cosmiccore.soul.remove", amount, type.getSerializedName()), false); return 1; } } diff --git a/src/main/java/com/ghostipedia/cosmiccore/common/commands/WirelessEnergyCommand.java b/src/main/java/com/ghostipedia/cosmiccore/common/commands/WirelessEnergyCommand.java index 409379eec..95fac2d73 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/common/commands/WirelessEnergyCommand.java +++ b/src/main/java/com/ghostipedia/cosmiccore/common/commands/WirelessEnergyCommand.java @@ -98,7 +98,7 @@ private static int displayTeamInfo(CommandContext context, T private static Component generateInfoMessage(ServerLevel serverLevel, UUID owner, Component ownerName) { var wirelessData = WirelessEnergySavedData.getOrCreate(serverLevel); - var message = Component.translatable("cosmic.command.wireless.energy.header", ownerName).append("\n") + var message = Component.translatable("cosmic.command.wireless.energy.header", ownerName).append("\n") .append(Component.translatable("cosmic.command.wireless.energy.capacity", FormattingUtil.formatNumbers(wirelessData.getEnergyCapacity(owner)))) .append("\n") diff --git a/src/main/java/com/ghostipedia/cosmiccore/common/commands/argument/SoulTypeArgument.java b/src/main/java/com/ghostipedia/cosmiccore/common/commands/argument/SoulTypeArgument.java new file mode 100644 index 000000000..6f3272829 --- /dev/null +++ b/src/main/java/com/ghostipedia/cosmiccore/common/commands/argument/SoulTypeArgument.java @@ -0,0 +1,57 @@ +package com.ghostipedia.cosmiccore.common.commands.argument; + +import com.ghostipedia.cosmiccore.api.capability.souls.SoulType; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.network.chat.Component; + +import java.util.Arrays; +import java.util.Collection; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; + +public class SoulTypeArgument implements ArgumentType { + + private static final Collection EXAMPLES = Arrays.stream(SoulType.values()) + .map(SoulType::getSerializedName) + .collect(Collectors.toList()); + + public static final DynamicCommandExceptionType ERROR_INVALID_VALUE = new DynamicCommandExceptionType( + (object) -> Component.translatable("argument.enum.invalid", object) + ); + + public static SoulTypeArgument soulType() { + return new SoulTypeArgument(); + } + + public static SoulType get(CommandContext context, String name) { + return context.getArgument(name, SoulType.class); + } + + @Override + public SoulType parse(StringReader reader) throws CommandSyntaxException { + String s = reader.readUnquotedString(); + SoulType soulType = SoulType.byName(s); + if (soulType == null) { + throw ERROR_INVALID_VALUE.create(s); + } + return soulType; + } + + @Override + public CompletableFuture listSuggestions(CommandContext context, SuggestionsBuilder builder) { + return SharedSuggestionProvider.suggest(EXAMPLES, builder); + } + + @Override + public Collection getExamples() { + return EXAMPLES; + } +} diff --git a/src/main/java/com/ghostipedia/cosmiccore/common/item/SoulNetworkReaderItem.java b/src/main/java/com/ghostipedia/cosmiccore/common/item/SoulNetworkReaderItem.java index 0eec0b2ae..a382247ee 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/common/item/SoulNetworkReaderItem.java +++ b/src/main/java/com/ghostipedia/cosmiccore/common/item/SoulNetworkReaderItem.java @@ -26,15 +26,22 @@ public SoulNetworkReaderItem(Properties properties) { public InteractionResultHolder use(Level level, Player player, InteractionHand hand) { if (!level.isClientSide() && player instanceof ServerPlayer serverPlayer) { SoulNetwork soulNetwork = SoulNetworkSavedData.getSoulNetwork((ServerLevel) level, player.getUUID()); - List contents = soulNetwork.getContents(); - - if (contents.isEmpty()) { - player.sendSystemMessage(Component.literal("Network is empty.").withStyle(ChatFormatting.GRAY)); - } else { - player.sendSystemMessage(Component.literal("--- Soul Network Contents ---").withStyle(ChatFormatting.GOLD)); - for (SoulStack stack : contents) player.sendSystemMessage(stack.type().toComponent(stack.amount())); - } + player.sendSystemMessage(displaySoulNetworkInfo(soulNetwork)); } return InteractionResultHolder.success(player.getItemInHand(hand)); } + + public static Component displaySoulNetworkInfo(SoulNetwork network) { + var message = Component.empty(); + List contents = network.getContents(); + if (contents.isEmpty()) { + message.append(Component.translatable("gui.cosmiccore.soul.empty_network").withStyle(ChatFormatting.GRAY)); + } else { + message.append(Component.translatable("gui.cosmiccore.soul.network_contents").withStyle(ChatFormatting.GOLD)).append("\n"); + message.append(Component.translatable("gui.cosmiccore.soul.capacity", network.getSize()).withStyle(ChatFormatting.GRAY)); + for (SoulStack stack : contents) message.append("\n").append(stack.type().toComponent(stack.amount())); + } + return message; + } + } diff --git a/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java b/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java index 2f556a331..35bc17279 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java +++ b/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java @@ -58,16 +58,11 @@ public Widget createUIWidget() { Component.translatable("gui.cosmiccore.soul_hatch.label." + (this.io == IO.IN ? "import" : "export")))); // TODO: Get and display proper player/team Name -// group.addWidget( -// new LabelWidget(8, 18, -// () -> I18n.get("gui.cosmiccore.soul_hatch.owner", -// PlayerHelper.getUsernameFromUUID(this.soulContainer.getOwner()))) -// .setClientSideWidget()); -// group.addWidget( -// new LabelWidget(8, 28, -// () -> I18n.get("gui.cosmiccore.soul_hatch.lp", -// FormattingUtil.formatNumbers(soulContainer.getCurrentEssence()))) -// .setClientSideWidget()); + group.addWidget( + new LabelWidget(8, 18, + () -> I18n.get("gui.cosmiccore.soul_hatch.owner", + PlayerHelper.getUsernameFromUUID(this.soulContainer.getMachine().getOwnerUUID()))) + .setClientSideWidget()); group.setBackground(GuiTextures.BACKGROUND_INVERSE); return group; diff --git a/src/main/java/com/ghostipedia/cosmiccore/forge/ForgeCommonEventListener.java b/src/main/java/com/ghostipedia/cosmiccore/forge/ForgeCommonEventListener.java index cea660ba6..d2f13c026 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/forge/ForgeCommonEventListener.java +++ b/src/main/java/com/ghostipedia/cosmiccore/forge/ForgeCommonEventListener.java @@ -2,6 +2,7 @@ import com.ghostipedia.cosmiccore.CosmicCore; import com.ghostipedia.cosmiccore.CosmicUtils; +import com.ghostipedia.cosmiccore.common.commands.SoulCommand; import com.ghostipedia.cosmiccore.common.commands.WirelessEnergyCommand; import com.ghostipedia.cosmiccore.common.data.CosmicItems; import com.ghostipedia.cosmiccore.common.data.CosmicMachines; @@ -120,6 +121,7 @@ public static void onPlayerDeath(LivingDeathEvent event) { @SubscribeEvent public static void registerCommand(RegisterCommandsEvent event) { WirelessEnergyCommand.register(event.getDispatcher(), event.getBuildContext()); + SoulCommand.register(event.getDispatcher(), event.getBuildContext()); ReflectionCommand.register(event.getDispatcher()); ReflectionCommands.register(event.getDispatcher()); } From 600a6d0d4b372ed411de6d2283d1c25e875cd384 Mon Sep 17 00:00:00 2001 From: MrQuentinet <32539717+mrquentin@users.noreply.github.com> Date: Fri, 23 Jan 2026 23:44:28 -0500 Subject: [PATCH 23/28] Add parallel Logic --- .../recipe/SoulRecipeCapability.java | 71 ++++++++++++++++++- .../trait/NotifiableSoulContainer.java | 1 + 2 files changed, 69 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/capability/recipe/SoulRecipeCapability.java b/src/main/java/com/ghostipedia/cosmiccore/api/capability/recipe/SoulRecipeCapability.java index 30c6f6daf..eabfa8842 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/capability/recipe/SoulRecipeCapability.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/capability/recipe/SoulRecipeCapability.java @@ -1,9 +1,12 @@ package com.ghostipedia.cosmiccore.api.capability.recipe; import com.ghostipedia.cosmiccore.api.capability.souls.SoulType; +import com.ghostipedia.cosmiccore.api.machine.trait.NotifiableSoulContainer; import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulIngredient; import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulStack; +import com.gregtechceu.gtceu.api.capability.recipe.IO; +import com.gregtechceu.gtceu.api.capability.recipe.IRecipeCapabilityHolder; import com.gregtechceu.gtceu.api.capability.recipe.RecipeCapability; import com.gregtechceu.gtceu.api.recipe.GTRecipe; import com.gregtechceu.gtceu.api.recipe.content.Content; @@ -17,9 +20,8 @@ import com.mojang.serialization.Codec; import org.apache.commons.lang3.mutable.MutableInt; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; +import java.util.*; +import java.util.stream.Collectors; public class SoulRecipeCapability extends RecipeCapability { @@ -66,6 +68,69 @@ public List compressIngredients(Collection ingredients) { return list; } + /// Get the total available input of each soul type. + /// The value is the sum of the available amount in each hatch. + /// The available amount is the minimum between the contained souls and the available throughput. + private static Map getInputContents(IRecipeCapabilityHolder holder) { + var handlerLists = holder.getCapabilitiesForIO(IO.IN); + if (handlerLists.isEmpty()) return new HashMap<>(); + + + var totalThroughput = 0; + var totalSouls = new HashMap(); + + for (var handlerList : handlerLists) { + if (!handlerList.hasCapability(SoulRecipeCapability.CAP)) continue; + var soulHandlers = handlerList.getCapability(SoulRecipeCapability.CAP); + for (var handler : soulHandlers) { + var soulHandler = (NotifiableSoulContainer) handler; + totalThroughput += soulHandler.getThroughput(); + for (var content : soulHandler.getContents()) { + if (content instanceof SoulIngredient soulIngredient) { + totalSouls.put(soulIngredient.stack().type(), soulIngredient.stack().amount()); + } else throw new IllegalArgumentException("Invalid content type"); + } + } + } + + final int finalTotalThroughput = totalThroughput; + return totalSouls.entrySet().stream() + .collect(Collectors.toMap( + Map.Entry::getKey, + entry -> Math.min(entry.getValue(), finalTotalThroughput) + )); + } + + + @Override + public int getMaxParallelByInput(IRecipeCapabilityHolder holder, GTRecipe recipe, int limit, boolean tick) { + if (!holder.hasCapabilityProxies()) return 0; + + var inputs = (tick ? recipe.tickInputs : recipe.inputs).get(this); + if (inputs == null || inputs.isEmpty()) return 0; + + var totalInputs = getInputContents(holder); + + var parallelMap = inputs.stream() + .map(content -> (SoulIngredient) content.getContent()) + .collect(Collectors.toMap( + ingredient -> ingredient.stack().type(), + ingredient -> { + int available = totalInputs.getOrDefault(ingredient.stack().type(), 0); + int required = ingredient.stack().amount(); + return required == 0 ? Integer.MAX_VALUE : available / required; + }, + Math::min + )); + + int maxParallel = parallelMap.values().stream() + .mapToInt(Integer::intValue) + .min() + .orElse(0); + + return Math.min(limit, maxParallel); + } + @Override public void addXEIInfo(WidgetGroup group, int xOffset, GTRecipe recipe, List contents, boolean perTick, boolean isInput, MutableInt yOffset) { diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java b/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java index 2d986fffa..0cfc625b6 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java @@ -25,6 +25,7 @@ public class NotifiableSoulContainer extends NotifiableRecipeHandlerTrait Date: Sat, 24 Jan 2026 00:00:31 -0500 Subject: [PATCH 24/28] remove tier in soul network --- .../api/data/souls/SoulNetwork.java | 33 ++--------------- .../trait/NotifiableSoulContainer.java | 8 +++-- .../common/commands/SoulCommand.java | 13 +------ .../common/item/SoulNetworkReaderItem.java | 1 - .../multiblock/part/SoulHatchPartMachine.java | 36 +++++++++++++------ 5 files changed, 36 insertions(+), 55 deletions(-) diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java b/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java index 746e33f0a..c30f74c6e 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java @@ -15,9 +15,6 @@ public class SoulNetwork implements INBTSerializable { - @Getter - private int tier = 0; - @Setter private Runnable dirtyCallback; @@ -25,14 +22,11 @@ public class SoulNetwork implements INBTSerializable { public SoulNetwork() {} - public SoulStack add(SoulStack stack, int throughput, boolean simulate) { + public SoulStack add(SoulStack stack, int throughput, int capacity, boolean simulate) { int currentAmount = this.contents.getOrDefault(stack.type(), 0); - // TODO check with ghosti if we should do a total volume or a volume per type - int totalAmount = this.contents.values().stream().mapToInt(Integer::intValue).sum(); - int amountToAdd = Math.min(stack.amount(), throughput); // Respect throughput - amountToAdd = Math.min(amountToAdd, getSize() - totalAmount); // Respect network capacity + amountToAdd = Math.min(amountToAdd, capacity - this.contents.get(stack.type())); // Respect network capacity amountToAdd = Math.max(0, amountToAdd); // Ensure we don't add a negative amount if (!simulate && amountToAdd > 0) { @@ -68,34 +62,14 @@ public List getContents() { .toList(); } - public void setTier(int tier) { - this.tier = tier; - if (dirtyCallback != null) dirtyCallback.run(); - } - - public int getSize() { - return switch (tier) { - case 0 -> 10_000; - case 1 -> 50_000; - case 2 -> 150_000; - case 4 -> 1_000_000; - case 5 -> 10_000_000; - case 6 -> 100_000_000; - default -> Integer.MAX_VALUE; - }; - } - @Override public String toString() { - return "SoulNetwork{" + - "tier=" + tier + - ", contents=" + contents + '}'; + return "SoulNetwork{contents=" + contents + '}'; } @Override public CompoundTag serializeNBT() { var tag = new CompoundTag(); - tag.putInt("tier", this.tier); var listTag = new ListTag(); this.contents.forEach((soulType, amount) -> { var contentTag = new CompoundTag(); @@ -109,7 +83,6 @@ public CompoundTag serializeNBT() { @Override public void deserializeNBT(CompoundTag compoundTag) { - this.tier = compoundTag.getInt("tier"); this.contents.clear(); ListTag listTag = compoundTag.getList("contents", Tag.TAG_COMPOUND); for (Tag t : listTag) { diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java b/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java index 0cfc625b6..2d767ea93 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java @@ -28,10 +28,14 @@ public class NotifiableSoulContainer extends NotifiableRecipeHandlerTrait handleRecipeInner(IO io, GTRecipe recipe, List 0) result.add(SoulIngredient.of(reminder)); } diff --git a/src/main/java/com/ghostipedia/cosmiccore/common/commands/SoulCommand.java b/src/main/java/com/ghostipedia/cosmiccore/common/commands/SoulCommand.java index d0228a3d1..538ae0930 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/common/commands/SoulCommand.java +++ b/src/main/java/com/ghostipedia/cosmiccore/common/commands/SoulCommand.java @@ -28,8 +28,6 @@ public static void register(CommandDispatcher dispatcher, Co .then(argument("player", EntityArgument.player()) .then(literal("info").executes(ctx -> displayInfo(ctx, EntityArgument.getPlayer(ctx, "player").getUUID()))) .then(literal("reset").executes(ctx -> resetNetwork(ctx, EntityArgument.getPlayer(ctx, "player").getUUID()))) - .then(literal("set-tier").then(argument("tier", IntegerArgumentType.integer(0, 6)) - .executes(ctx -> setTier(ctx, EntityArgument.getPlayer(ctx, "player").getUUID(), IntegerArgumentType.getInteger(ctx, "tier"))))) .then(literal("add").then(argument("type", SoulTypeArgument.soulType()).then(argument("amount", IntegerArgumentType.integer()) .executes(ctx -> addSouls(ctx, EntityArgument.getPlayer(ctx, "player").getUUID(), SoulTypeArgument.get(ctx, "type"), IntegerArgumentType.getInteger(ctx, "amount")))))) .then(literal("syphon").then(argument("type", SoulTypeArgument.soulType()).then(argument("amount", IntegerArgumentType.integer()) @@ -40,8 +38,6 @@ public static void register(CommandDispatcher dispatcher, Co .then(argument("team", TeamArgument.create()) .then(literal("info").executes(ctx -> displayInfo(ctx, TeamArgument.get(ctx, "team").getTeamId()))) .then(literal("reset").executes(ctx -> resetNetwork(ctx, TeamArgument.get(ctx, "team").getTeamId()))) - .then(literal("set-tier").then(argument("tier", IntegerArgumentType.integer(0, 6)) - .executes(ctx -> setTier(ctx, TeamArgument.get(ctx, "team").getTeamId(), IntegerArgumentType.getInteger(ctx, "tier"))))) .then(literal("add").then(argument("type", SoulTypeArgument.soulType()).then(argument("amount", IntegerArgumentType.integer()) .executes(ctx -> addSouls(ctx, TeamArgument.get(ctx, "team").getTeamId(), SoulTypeArgument.get(ctx, "type"), IntegerArgumentType.getInteger(ctx, "amount")))))) .then(literal("syphon").then(argument("type", SoulTypeArgument.soulType()).then(argument("amount", IntegerArgumentType.integer()) @@ -57,13 +53,6 @@ private static int displayInfo(CommandContext context, UUID return 1; } - private static int setTier(CommandContext context, UUID owner, int tier) { - var network = SoulNetworkSavedData.getSoulNetwork(context.getSource().getLevel(), owner); - network.setTier(tier); - context.getSource().sendSuccess(() ->Component.translatable("gui.cosmiccore.soul.set_tier", tier), false); - return 1; - } - private static int resetNetwork(CommandContext context, UUID owner) { var network = SoulNetworkSavedData.getSoulNetwork(context.getSource().getLevel(), owner); network.reset(); @@ -73,7 +62,7 @@ private static int resetNetwork(CommandContext context, UUID private static int addSouls(CommandContext context, UUID owner, SoulType type, int amount) { var network = SoulNetworkSavedData.getSoulNetwork(context.getSource().getLevel(), owner); - network.add(new SoulStack(type, amount), Integer.MAX_VALUE, false); + network.add(new SoulStack(type, amount), Integer.MAX_VALUE, Integer.MAX_VALUE, false); context.getSource().sendSuccess(() -> Component.translatable("gui.cosmiccore.soul.add", amount, type.getSerializedName()), false); return 1; } diff --git a/src/main/java/com/ghostipedia/cosmiccore/common/item/SoulNetworkReaderItem.java b/src/main/java/com/ghostipedia/cosmiccore/common/item/SoulNetworkReaderItem.java index a382247ee..746529835 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/common/item/SoulNetworkReaderItem.java +++ b/src/main/java/com/ghostipedia/cosmiccore/common/item/SoulNetworkReaderItem.java @@ -38,7 +38,6 @@ public static Component displaySoulNetworkInfo(SoulNetwork network) { message.append(Component.translatable("gui.cosmiccore.soul.empty_network").withStyle(ChatFormatting.GRAY)); } else { message.append(Component.translatable("gui.cosmiccore.soul.network_contents").withStyle(ChatFormatting.GOLD)).append("\n"); - message.append(Component.translatable("gui.cosmiccore.soul.capacity", network.getSize()).withStyle(ChatFormatting.GRAY)); for (SoulStack stack : contents) message.append("\n").append(stack.type().toComponent(stack.amount())); } return message; diff --git a/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java b/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java index 35bc17279..c780c1086 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java +++ b/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java @@ -37,7 +37,7 @@ public class SoulHatchPartMachine extends TieredIOPartMachine { public SoulHatchPartMachine(IMachineBlockEntity holder, int tier, IO io) { super(holder, tier, io); - this.soulContainer = new NotifiableSoulContainer(this, io, getMaxConsumption(tier)); + this.soulContainer = new NotifiableSoulContainer(this, io, getMaxConsumption(tier), getMaxCapacity(tier)); } @Override @@ -70,15 +70,31 @@ public Widget createUIWidget() { public static int getMaxConsumption(int tier) { return switch (tier) { - case GTValues.IV -> 10000; - case GTValues.LuV -> 50000; - case GTValues.ZPM -> 5000000; - case GTValues.UV -> 10000000; - case GTValues.UHV -> 25000000; - case GTValues.UEV -> 50000000; - case GTValues.UIV -> 125000000; - case GTValues.UXV -> 250000000; - case GTValues.OpV -> 500000000; + case GTValues.IV -> 10_000; + case GTValues.LuV -> 50_000; + case GTValues.ZPM -> 5_000_000; + case GTValues.UV -> 10_000_000; + case GTValues.UHV -> 25_000_000; + case GTValues.UEV -> 50_000_000; + case GTValues.UIV -> 125_000_000; + case GTValues.UXV -> 250_000_000; + case GTValues.OpV -> 500_000_000; + case GTValues.MAX -> Integer.MAX_VALUE; + default -> 0; + }; + } + + public static int getMaxCapacity(int tier) { + return switch (tier) { + case GTValues.IV -> 1_000_000; + case GTValues.LuV -> 10_000_000; + case GTValues.ZPM -> 50_000_000; + case GTValues.UV -> 100_000_000; + case GTValues.UHV -> 250_000_000; + case GTValues.UEV -> 500_000_000; + case GTValues.UIV -> 1_000_000_000; + case GTValues.UXV -> 1_500_000_000; + case GTValues.OpV -> 2_000_000_000; case GTValues.MAX -> Integer.MAX_VALUE; default -> 0; }; From 260eb2d819ac1324aa73196f31468e584be3c9ee Mon Sep 17 00:00:00 2001 From: MrQuentinet <32539717+mrquentin@users.noreply.github.com> Date: Mon, 26 Jan 2026 10:55:12 -0500 Subject: [PATCH 25/28] fix EMI broken --- .../common/machine/multiblock/part/SoulHatchPartMachine.java | 2 ++ .../com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java b/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java index c780c1086..c9c28ce21 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java +++ b/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java @@ -15,6 +15,7 @@ import com.lowdragmc.lowdraglib.syncdata.annotation.Persisted; import com.lowdragmc.lowdraglib.syncdata.field.ManagedFieldHolder; +import com.lowdragmc.lowdraglib.utils.DummyWorld; import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.client.resources.language.I18n; import net.minecraft.network.chat.Component; @@ -42,6 +43,7 @@ public SoulHatchPartMachine(IMachineBlockEntity holder, int tier, IO io) { @Override public void addedToController(IMultiController controller) { + if (getLevel() instanceof DummyWorld) return; super.addedToController(controller); boolean hasDuplicate = controller.getParts().stream() .filter(part -> part != this) diff --git a/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java b/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java index d07fc5883..7fd3120b8 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java +++ b/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java @@ -119,7 +119,6 @@ public static void init(Consumer provider) { .save(provider); SOUL_TESTER_RECIPES.recipeBuilder("generate_soul_2") - .inputItems(Items.DIRT) .input(CosmicRecipeCapabilities.SOUL, SoulIngredient.of(SoulType.Raw, 10)) .outputItems(ingot, Steel) .duration(20) From e00850a7a8913d3aae61a85805c6ca0875974562 Mon Sep 17 00:00:00 2001 From: MrQuentinet <32539717+mrquentin@users.noreply.github.com> Date: Mon, 26 Jan 2026 11:40:25 -0500 Subject: [PATCH 26/28] fix souls add issue --- .../com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java b/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java index c30f74c6e..f5d01f5be 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java @@ -26,7 +26,7 @@ public SoulStack add(SoulStack stack, int throughput, int capacity, boolean simu int currentAmount = this.contents.getOrDefault(stack.type(), 0); int amountToAdd = Math.min(stack.amount(), throughput); // Respect throughput - amountToAdd = Math.min(amountToAdd, capacity - this.contents.get(stack.type())); // Respect network capacity + amountToAdd = Math.min(amountToAdd, capacity - currentAmount); // Respect network capacity amountToAdd = Math.max(0, amountToAdd); // Ensure we don't add a negative amount if (!simulate && amountToAdd > 0) { From 43db920a9264c3f6b042f55f12a8d73f50b29842 Mon Sep 17 00:00:00 2001 From: MrQuentinet <32539717+mrquentin@users.noreply.github.com> Date: Mon, 26 Jan 2026 12:20:12 -0500 Subject: [PATCH 27/28] This stupid code is what breaks the recipes --- .../multiblock/part/SoulHatchPartMachine.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java b/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java index c9c28ce21..cb29797c4 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java +++ b/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java @@ -41,15 +41,15 @@ public SoulHatchPartMachine(IMachineBlockEntity holder, int tier, IO io) { this.soulContainer = new NotifiableSoulContainer(this, io, getMaxConsumption(tier), getMaxCapacity(tier)); } - @Override - public void addedToController(IMultiController controller) { - if (getLevel() instanceof DummyWorld) return; - super.addedToController(controller); - boolean hasDuplicate = controller.getParts().stream() - .filter(part -> part != this) - .anyMatch(part -> part instanceof SoulHatchPartMachine soulHatch && soulHatch.io == this.io); - if (hasDuplicate) controller.onStructureInvalid(); - } +// @Override +// public void addedToController(IMultiController controller) { +// if (getLevel() instanceof DummyWorld) return; +// super.addedToController(controller); +// boolean hasDuplicate = controller.getParts().stream() +// .filter(part -> part != this) +// .anyMatch(part -> part instanceof SoulHatchPartMachine soulHatch && soulHatch.io == this.io); +// if (hasDuplicate) controller.onStructureInvalid(); +// } @Override public Widget createUIWidget() { From 60e3d630926b448867fc902cffd62633f3ec71e5 Mon Sep 17 00:00:00 2001 From: jurrejelle Date: Mon, 26 Jan 2026 19:05:26 +0100 Subject: [PATCH 28/28] Spotless + scheduele invalidate on next tick --- .../ghostipedia/cosmiccore/CosmicCore.java | 4 +- .../api/capability/ISoulContainer.java | 5 +- .../recipe/SoulRecipeCapability.java | 30 ++++--- .../api/capability/souls/SoulType.java | 10 +-- .../api/codec/CosmicCodecUtils.java | 5 +- .../api/data/souls/SoulNetwork.java | 11 +-- .../api/data/souls/SoulNetworkSavedData.java | 7 +- .../trait/NotifiableSoulContainer.java | 11 ++- .../recipe/content/SerializerSoulStack.java | 8 +- .../api/recipe/ingredient/SoulIngredient.java | 7 +- .../api/recipe/ingredient/SoulStack.java | 8 +- .../api/recipe/lookup/MapSoulIngredient.java | 1 + .../common/commands/SoulCommand.java | 79 ++++++++++++------- .../commands/WirelessEnergyCommand.java | 2 +- .../commands/argument/SoulTypeArgument.java | 11 +-- .../common/data/CosmicMachines.java | 27 ++++--- .../common/item/SoulNetworkReaderItem.java | 6 +- .../multiblock/part/SoulHatchPartMachine.java | 37 +++++---- .../forge/ForgeCommonEventListener.java | 3 - .../gtbridge/CosmicCoreRecipes.java | 3 +- .../components/CosmicRecipeComponent.java | 6 +- 21 files changed, 155 insertions(+), 126 deletions(-) diff --git a/src/main/java/com/ghostipedia/cosmiccore/CosmicCore.java b/src/main/java/com/ghostipedia/cosmiccore/CosmicCore.java index 3767cbff4..43dc7782f 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/CosmicCore.java +++ b/src/main/java/com/ghostipedia/cosmiccore/CosmicCore.java @@ -41,7 +41,6 @@ import net.minecraft.commands.synchronization.ArgumentTypeInfos; import net.minecraft.commands.synchronization.SingletonArgumentInfo; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.item.crafting.Ingredient; import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; @@ -122,7 +121,8 @@ public void commonSetup(FMLCommonSetupEvent event) { CCoreNetwork.init(); OxygenRules.registerAirRanges(); DimensionMobScaling.registerScaling(); - ArgumentTypeInfos.registerByClass(SoulTypeArgument.class, SingletonArgumentInfo.contextFree(SoulTypeArgument::soulType)); + ArgumentTypeInfos.registerByClass(SoulTypeArgument.class, + SingletonArgumentInfo.contextFree(SoulTypeArgument::soulType)); }); } diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/capability/ISoulContainer.java b/src/main/java/com/ghostipedia/cosmiccore/api/capability/ISoulContainer.java index facaad4a8..5c058b663 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/capability/ISoulContainer.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/capability/ISoulContainer.java @@ -2,10 +2,9 @@ import com.ghostipedia.cosmiccore.api.data.souls.SoulNetwork; -import java.util.UUID; - public interface ISoulContainer { - /** + + /** * @return the soul network attached to the container */ SoulNetwork getSoulNetwork(); diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/capability/recipe/SoulRecipeCapability.java b/src/main/java/com/ghostipedia/cosmiccore/api/capability/recipe/SoulRecipeCapability.java index eabfa8842..47b3534e7 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/capability/recipe/SoulRecipeCapability.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/capability/recipe/SoulRecipeCapability.java @@ -15,15 +15,14 @@ import com.lowdragmc.lowdraglib.gui.widget.LabelWidget; import com.lowdragmc.lowdraglib.gui.widget.WidgetGroup; - import com.lowdragmc.lowdraglib.utils.LocalizationUtils; + import com.mojang.serialization.Codec; import org.apache.commons.lang3.mutable.MutableInt; import java.util.*; import java.util.stream.Collectors; - public class SoulRecipeCapability extends RecipeCapability { public final static SoulRecipeCapability CAP = new SoulRecipeCapability(); @@ -37,7 +36,7 @@ public boolean isRecipeSearchFilter() { return true; } - //TODO: try to remove + // TODO: try to remove @Override public SoulIngredient copyInner(SoulIngredient content) { return super.copyInner(content); @@ -56,7 +55,8 @@ public List compressIngredients(Collection ingredients) { if (item instanceof SoulIngredient soul) { var isEqual = false; for (Object obj : list) { - if (obj instanceof SoulIngredient soulIngredient && soul.stack().type().equals(soulIngredient.stack().type())) { + if (obj instanceof SoulIngredient soulIngredient && + soul.stack().type().equals(soulIngredient.stack().type())) { isEqual = true; break; } @@ -74,11 +74,10 @@ public List compressIngredients(Collection ingredients) { private static Map getInputContents(IRecipeCapabilityHolder holder) { var handlerLists = holder.getCapabilitiesForIO(IO.IN); if (handlerLists.isEmpty()) return new HashMap<>(); - - + var totalThroughput = 0; var totalSouls = new HashMap(); - + for (var handlerList : handlerLists) { if (!handlerList.hasCapability(SoulRecipeCapability.CAP)) continue; var soulHandlers = handlerList.getCapability(SoulRecipeCapability.CAP); @@ -97,11 +96,9 @@ private static Map getInputContents(IRecipeCapabilityHolder h return totalSouls.entrySet().stream() .collect(Collectors.toMap( Map.Entry::getKey, - entry -> Math.min(entry.getValue(), finalTotalThroughput) - )); + entry -> Math.min(entry.getValue(), finalTotalThroughput))); } - @Override public int getMaxParallelByInput(IRecipeCapabilityHolder holder, GTRecipe recipe, int limit, boolean tick) { if (!holder.hasCapabilityProxies()) return 0; @@ -120,8 +117,7 @@ public int getMaxParallelByInput(IRecipeCapabilityHolder holder, GTRecipe recipe int required = ingredient.stack().amount(); return required == 0 ? Integer.MAX_VALUE : available / required; }, - Math::min - )); + Math::min)); int maxParallel = parallelMap.values().stream() .mapToInt(Integer::intValue) @@ -134,9 +130,11 @@ public int getMaxParallelByInput(IRecipeCapabilityHolder holder, GTRecipe recipe @Override public void addXEIInfo(WidgetGroup group, int xOffset, GTRecipe recipe, List contents, boolean perTick, boolean isInput, MutableInt yOffset) { - - String type = contents.stream().map(Content::getContent).map(SoulRecipeCapability.CAP::of).map(SoulIngredient::stack).map(SoulStack::type).map(SoulType::getSerializedName).findFirst().orElse(""); - long soul = contents.stream().map(Content::getContent).map(SoulRecipeCapability.CAP::of).map(SoulIngredient::stack).mapToLong(SoulStack::amount).sum(); + String type = contents.stream().map(Content::getContent).map(SoulRecipeCapability.CAP::of) + .map(SoulIngredient::stack).map(SoulStack::type).map(SoulType::getSerializedName).findFirst() + .orElse(""); + long soul = contents.stream().map(Content::getContent).map(SoulRecipeCapability.CAP::of) + .map(SoulIngredient::stack).mapToLong(SoulStack::amount).sum(); if (isInput) { group.addWidget(new LabelWidget(3 - xOffset, yOffset.addAndGet(10), LocalizationUtils.format("recipe.cosmiccore." + type + "_soul_in", soul))); @@ -153,7 +151,7 @@ private static class SerializerSoulIngredient implements IContentSerializer CODEC = StringRepresentable.fromEnum(SoulType::values); - private static final Map BY_NAME = Arrays.stream(values()).collect(Collectors.toMap(SoulType::getSerializedName, Function.identity())); + private static final Map BY_NAME = Arrays.stream(values()) + .collect(Collectors.toMap(SoulType::getSerializedName, Function.identity())); public static SoulType byName(String name) { return BY_NAME.get(name); diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/codec/CosmicCodecUtils.java b/src/main/java/com/ghostipedia/cosmiccore/api/codec/CosmicCodecUtils.java index 22fa96c67..fa965ca71 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/codec/CosmicCodecUtils.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/codec/CosmicCodecUtils.java @@ -1,6 +1,3 @@ package com.ghostipedia.cosmiccore.api.codec; -import com.mojang.serialization.Codec; - -public class CosmicCodecUtils { -} +public class CosmicCodecUtils {} diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java b/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java index f5d01f5be..4c8227b44 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetwork.java @@ -2,16 +2,17 @@ import com.ghostipedia.cosmiccore.api.capability.souls.SoulType; import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulStack; -import lombok.Getter; -import lombok.Setter; + import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.Tag; import net.minecraftforge.common.util.INBTSerializable; -import java.util.concurrent.ConcurrentHashMap; +import lombok.Setter; + import java.util.List; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; public class SoulNetwork implements INBTSerializable { @@ -58,8 +59,8 @@ public void reset() { public List getContents() { return contents.entrySet().stream() - .map(kvp -> new SoulStack(kvp.getKey(), kvp.getValue())) - .toList(); + .map(kvp -> new SoulStack(kvp.getKey(), kvp.getValue())) + .toList(); } @Override diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetworkSavedData.java b/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetworkSavedData.java index d20917e83..8dd5a6feb 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetworkSavedData.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/data/souls/SoulNetworkSavedData.java @@ -1,18 +1,20 @@ package com.ghostipedia.cosmiccore.api.data.souls; import com.ghostipedia.cosmiccore.CosmicCore; + import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.Tag; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.saveddata.SavedData; + import org.jetbrains.annotations.NotNull; import java.util.HashMap; import java.util.UUID; public class SoulNetworkSavedData extends SavedData { - + private static final String DATA_NAME = CosmicCore.MOD_ID + "_soul_network_data"; private static final String SOUL_NETWORK_MAPPING = "soul_network_mapping"; private static final String SOUL_NETWORK_UUID = "soul_network_uuid"; @@ -21,7 +23,8 @@ public class SoulNetworkSavedData extends SavedData { private final HashMap soulNetworkMapping = new HashMap<>(20, 0.9f); public static SoulNetworkSavedData getOrCreate(ServerLevel serverLevel) { - return serverLevel.getDataStorage().computeIfAbsent(SoulNetworkSavedData::new, SoulNetworkSavedData::new, DATA_NAME); + return serverLevel.getDataStorage().computeIfAbsent(SoulNetworkSavedData::new, SoulNetworkSavedData::new, + DATA_NAME); } public static SoulNetwork getSoulNetwork(ServerLevel level, UUID owner) { diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java b/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java index 2d767ea93..36bcef060 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/machine/trait/NotifiableSoulContainer.java @@ -5,21 +5,23 @@ import com.ghostipedia.cosmiccore.api.data.souls.SoulNetworkSavedData; import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulIngredient; import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulStack; + import com.gregtechceu.gtceu.api.capability.recipe.IO; import com.gregtechceu.gtceu.api.capability.recipe.RecipeCapability; import com.gregtechceu.gtceu.api.machine.MetaMachine; import com.gregtechceu.gtceu.api.machine.trait.NotifiableRecipeHandlerTrait; import com.gregtechceu.gtceu.api.recipe.GTRecipe; import com.gregtechceu.gtceu.common.machine.owner.FTBOwner; -import lombok.Getter; + import net.minecraft.server.level.ServerLevel; + +import lombok.Getter; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; import java.util.UUID; - public class NotifiableSoulContainer extends NotifiableRecipeHandlerTrait { @Getter @@ -64,8 +66,9 @@ public List handleRecipeInner(IO io, GTRecipe recipe, List { public static SerializerSoulStack INSTANCE = new SerializerSoulStack(); - private SerializerSoulStack() {} + private SerializerSoulStack() {} @Override public void toNetwork(FriendlyByteBuf buf, SoulStack content) { diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/recipe/ingredient/SoulIngredient.java b/src/main/java/com/ghostipedia/cosmiccore/api/recipe/ingredient/SoulIngredient.java index 33b010ec8..f10639c85 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/recipe/ingredient/SoulIngredient.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/recipe/ingredient/SoulIngredient.java @@ -1,7 +1,7 @@ package com.ghostipedia.cosmiccore.api.recipe.ingredient; - import com.ghostipedia.cosmiccore.api.capability.souls.SoulType; + import com.mojang.serialization.Codec; import org.jetbrains.annotations.NotNull; @@ -21,8 +21,7 @@ public static SoulIngredient of(SoulType soulType, int amount) { @Override public boolean test(SoulStack soulStack) { - return this.stack.type() == soulStack.type() - && this.stack.amount() <= soulStack.amount(); + return this.stack.type() == soulStack.type() && this.stack.amount() <= soulStack.amount(); } @Override @@ -33,7 +32,7 @@ public boolean test(SoulStack soulStack) { @Override public boolean equals(Object obj) { if (!(obj instanceof SoulIngredient other)) { - return false; + return false; } return stack.equals(other.stack); } diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/recipe/ingredient/SoulStack.java b/src/main/java/com/ghostipedia/cosmiccore/api/recipe/ingredient/SoulStack.java index 265d83245..528e250c7 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/recipe/ingredient/SoulStack.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/recipe/ingredient/SoulStack.java @@ -1,18 +1,20 @@ package com.ghostipedia.cosmiccore.api.recipe.ingredient; import com.ghostipedia.cosmiccore.api.capability.souls.SoulType; + +import net.minecraft.network.FriendlyByteBuf; + import com.google.common.base.Preconditions; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; import lombok.With; -import net.minecraft.network.FriendlyByteBuf; @With public record SoulStack(SoulType type, int amount) { + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( SoulType.CODEC.fieldOf("type").forGetter(SoulStack::type), - Codec.INT.fieldOf("amount").forGetter(SoulStack::amount) - ).apply(instance, SoulStack::new)); + Codec.INT.fieldOf("amount").forGetter(SoulStack::amount)).apply(instance, SoulStack::new)); public static final SoulStack EMPTY = new SoulStack(SoulType.Raw, 0); diff --git a/src/main/java/com/ghostipedia/cosmiccore/api/recipe/lookup/MapSoulIngredient.java b/src/main/java/com/ghostipedia/cosmiccore/api/recipe/lookup/MapSoulIngredient.java index 991bb36b9..fdcb9792b 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/api/recipe/lookup/MapSoulIngredient.java +++ b/src/main/java/com/ghostipedia/cosmiccore/api/recipe/lookup/MapSoulIngredient.java @@ -2,6 +2,7 @@ import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulIngredient; import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulStack; + import com.gregtechceu.gtceu.api.recipe.lookup.ingredient.AbstractMapIngredient; import java.util.List; diff --git a/src/main/java/com/ghostipedia/cosmiccore/common/commands/SoulCommand.java b/src/main/java/com/ghostipedia/cosmiccore/common/commands/SoulCommand.java index 538ae0930..dab0039a8 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/common/commands/SoulCommand.java +++ b/src/main/java/com/ghostipedia/cosmiccore/common/commands/SoulCommand.java @@ -5,15 +5,17 @@ import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulStack; import com.ghostipedia.cosmiccore.common.commands.argument.SoulTypeArgument; import com.ghostipedia.cosmiccore.common.item.SoulNetworkReaderItem; -import com.mojang.brigadier.CommandDispatcher; -import com.mojang.brigadier.arguments.IntegerArgumentType; -import com.mojang.brigadier.context.CommandContext; -import dev.ftb.mods.ftbteams.data.TeamArgument; + import net.minecraft.commands.CommandBuildContext; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.arguments.EntityArgument; import net.minecraft.network.chat.Component; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.IntegerArgumentType; +import com.mojang.brigadier.context.CommandContext; +import dev.ftb.mods.ftbteams.data.TeamArgument; + import java.util.UUID; import static net.minecraft.commands.Commands.*; @@ -22,34 +24,49 @@ public class SoulCommand { public static void register(CommandDispatcher dispatcher, CommandBuildContext buildContext) { dispatcher.register( - literal("soul") - .requires(source -> source.hasPermission(LEVEL_ADMINS)) - .then(literal("player") - .then(argument("player", EntityArgument.player()) - .then(literal("info").executes(ctx -> displayInfo(ctx, EntityArgument.getPlayer(ctx, "player").getUUID()))) - .then(literal("reset").executes(ctx -> resetNetwork(ctx, EntityArgument.getPlayer(ctx, "player").getUUID()))) - .then(literal("add").then(argument("type", SoulTypeArgument.soulType()).then(argument("amount", IntegerArgumentType.integer()) - .executes(ctx -> addSouls(ctx, EntityArgument.getPlayer(ctx, "player").getUUID(), SoulTypeArgument.get(ctx, "type"), IntegerArgumentType.getInteger(ctx, "amount")))))) - .then(literal("syphon").then(argument("type", SoulTypeArgument.soulType()).then(argument("amount", IntegerArgumentType.integer()) - .executes(ctx -> syphon(ctx, EntityArgument.getPlayer(ctx, "player").getUUID(), SoulTypeArgument.get(ctx, "type"), IntegerArgumentType.getInteger(ctx, "amount")))))) - ) - ) - .then(literal("team") - .then(argument("team", TeamArgument.create()) - .then(literal("info").executes(ctx -> displayInfo(ctx, TeamArgument.get(ctx, "team").getTeamId()))) - .then(literal("reset").executes(ctx -> resetNetwork(ctx, TeamArgument.get(ctx, "team").getTeamId()))) - .then(literal("add").then(argument("type", SoulTypeArgument.soulType()).then(argument("amount", IntegerArgumentType.integer()) - .executes(ctx -> addSouls(ctx, TeamArgument.get(ctx, "team").getTeamId(), SoulTypeArgument.get(ctx, "type"), IntegerArgumentType.getInteger(ctx, "amount")))))) - .then(literal("syphon").then(argument("type", SoulTypeArgument.soulType()).then(argument("amount", IntegerArgumentType.integer()) - .executes(ctx -> syphon(ctx, TeamArgument.get(ctx, "team").getTeamId(), SoulTypeArgument.get(ctx, "type"), IntegerArgumentType.getInteger(ctx, "amount")))))) - ) - ) - ); + literal("soul") + .requires(source -> source.hasPermission(LEVEL_ADMINS)) + .then(literal("player") + .then(argument("player", EntityArgument.player()) + .then(literal("info").executes(ctx -> displayInfo(ctx, + EntityArgument.getPlayer(ctx, "player").getUUID()))) + .then(literal("reset").executes(ctx -> resetNetwork(ctx, + EntityArgument.getPlayer(ctx, "player").getUUID()))) + .then(literal("add").then(argument("type", SoulTypeArgument.soulType()) + .then(argument("amount", IntegerArgumentType.integer()) + .executes(ctx -> addSouls(ctx, + EntityArgument.getPlayer(ctx, "player").getUUID(), + SoulTypeArgument.get(ctx, "type"), + IntegerArgumentType.getInteger(ctx, "amount")))))) + .then(literal("syphon").then(argument("type", SoulTypeArgument.soulType()) + .then(argument("amount", IntegerArgumentType.integer()) + .executes(ctx -> syphon(ctx, + EntityArgument.getPlayer(ctx, "player").getUUID(), + SoulTypeArgument.get(ctx, "type"), + IntegerArgumentType.getInteger(ctx, "amount")))))))) + .then(literal("team") + .then(argument("team", TeamArgument.create()) + .then(literal("info").executes( + ctx -> displayInfo(ctx, TeamArgument.get(ctx, "team").getTeamId()))) + .then(literal("reset").executes( + ctx -> resetNetwork(ctx, TeamArgument.get(ctx, "team").getTeamId()))) + .then(literal("add").then(argument("type", SoulTypeArgument.soulType()) + .then(argument("amount", IntegerArgumentType.integer()) + .executes(ctx -> addSouls(ctx, + TeamArgument.get(ctx, "team").getTeamId(), + SoulTypeArgument.get(ctx, "type"), + IntegerArgumentType.getInteger(ctx, "amount")))))) + .then(literal("syphon").then(argument("type", SoulTypeArgument.soulType()) + .then(argument("amount", IntegerArgumentType.integer()) + .executes(ctx -> syphon(ctx, + TeamArgument.get(ctx, "team").getTeamId(), + SoulTypeArgument.get(ctx, "type"), + IntegerArgumentType.getInteger(ctx, "amount"))))))))); } private static int displayInfo(CommandContext context, UUID owner) { var network = SoulNetworkSavedData.getSoulNetwork(context.getSource().getLevel(), owner); - context.getSource().sendSuccess(() ->SoulNetworkReaderItem.displaySoulNetworkInfo(network), false); + context.getSource().sendSuccess(() -> SoulNetworkReaderItem.displaySoulNetworkInfo(network), false); return 1; } @@ -63,14 +80,16 @@ private static int resetNetwork(CommandContext context, UUID private static int addSouls(CommandContext context, UUID owner, SoulType type, int amount) { var network = SoulNetworkSavedData.getSoulNetwork(context.getSource().getLevel(), owner); network.add(new SoulStack(type, amount), Integer.MAX_VALUE, Integer.MAX_VALUE, false); - context.getSource().sendSuccess(() -> Component.translatable("gui.cosmiccore.soul.add", amount, type.getSerializedName()), false); + context.getSource().sendSuccess( + () -> Component.translatable("gui.cosmiccore.soul.add", amount, type.getSerializedName()), false); return 1; } private static int syphon(CommandContext context, UUID owner, SoulType type, int amount) { var network = SoulNetworkSavedData.getSoulNetwork(context.getSource().getLevel(), owner); network.syphon(new SoulStack(type, amount), false); - context.getSource().sendSuccess(() -> Component.translatable("gui.cosmiccore.soul.remove", amount, type.getSerializedName()), false); + context.getSource().sendSuccess( + () -> Component.translatable("gui.cosmiccore.soul.remove", amount, type.getSerializedName()), false); return 1; } } diff --git a/src/main/java/com/ghostipedia/cosmiccore/common/commands/WirelessEnergyCommand.java b/src/main/java/com/ghostipedia/cosmiccore/common/commands/WirelessEnergyCommand.java index 95fac2d73..409379eec 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/common/commands/WirelessEnergyCommand.java +++ b/src/main/java/com/ghostipedia/cosmiccore/common/commands/WirelessEnergyCommand.java @@ -98,7 +98,7 @@ private static int displayTeamInfo(CommandContext context, T private static Component generateInfoMessage(ServerLevel serverLevel, UUID owner, Component ownerName) { var wirelessData = WirelessEnergySavedData.getOrCreate(serverLevel); - var message = Component.translatable("cosmic.command.wireless.energy.header", ownerName).append("\n") + var message = Component.translatable("cosmic.command.wireless.energy.header", ownerName).append("\n") .append(Component.translatable("cosmic.command.wireless.energy.capacity", FormattingUtil.formatNumbers(wirelessData.getEnergyCapacity(owner)))) .append("\n") diff --git a/src/main/java/com/ghostipedia/cosmiccore/common/commands/argument/SoulTypeArgument.java b/src/main/java/com/ghostipedia/cosmiccore/common/commands/argument/SoulTypeArgument.java index 6f3272829..c4b02e0f9 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/common/commands/argument/SoulTypeArgument.java +++ b/src/main/java/com/ghostipedia/cosmiccore/common/commands/argument/SoulTypeArgument.java @@ -1,6 +1,11 @@ package com.ghostipedia.cosmiccore.common.commands.argument; import com.ghostipedia.cosmiccore.api.capability.souls.SoulType; + +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.network.chat.Component; + import com.mojang.brigadier.StringReader; import com.mojang.brigadier.arguments.ArgumentType; import com.mojang.brigadier.context.CommandContext; @@ -8,9 +13,6 @@ import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; import com.mojang.brigadier.suggestion.Suggestions; import com.mojang.brigadier.suggestion.SuggestionsBuilder; -import net.minecraft.commands.CommandSourceStack; -import net.minecraft.commands.SharedSuggestionProvider; -import net.minecraft.network.chat.Component; import java.util.Arrays; import java.util.Collection; @@ -24,8 +26,7 @@ public class SoulTypeArgument implements ArgumentType { .collect(Collectors.toList()); public static final DynamicCommandExceptionType ERROR_INVALID_VALUE = new DynamicCommandExceptionType( - (object) -> Component.translatable("argument.enum.invalid", object) - ); + (object) -> Component.translatable("argument.enum.invalid", object)); public static SoulTypeArgument soulType() { return new SoulTypeArgument(); diff --git a/src/main/java/com/ghostipedia/cosmiccore/common/data/CosmicMachines.java b/src/main/java/com/ghostipedia/cosmiccore/common/data/CosmicMachines.java index b5e85a987..9edc89ed8 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/common/data/CosmicMachines.java +++ b/src/main/java/com/ghostipedia/cosmiccore/common/data/CosmicMachines.java @@ -385,19 +385,20 @@ public class CosmicMachines { GTValues.tiersBetween(ULV, HV)); // Enable If needed Inside of Dev - public static final MultiblockMachineDefinition SOUL_TESTER = REGISTRATE.multiblock("soul_tester", PrimitiveWorkableMachine::new) - .rotationState(RotationState.NON_Y_AXIS) - .recipeType(CosmicRecipeTypes.SOUL_TESTER_RECIPES) - .appearanceBlock(GTBlocks.CASING_PRIMITIVE_BRICKS) - .pattern(definition -> FactoryBlockPattern.start() - .aisle("S", "C", "I") - .where("C", controller(blocks(definition.getBlock()))) - .where("S", abilities(CosmicPartAbility.IMPORT_SOUL).or(abilities(CosmicPartAbility.EXPORT_SOUL))) - .where("I", abilities(PartAbility.EXPORT_ITEMS).or(abilities(PartAbility.IMPORT_ITEMS))) - .build()) - .workableCasingModel(GTCEu.id("block/casings/solid/machine_casing_inert_ptfe"), - GTCEu.id("block/multiblock/coke_oven")) - .register(); + public static final MultiblockMachineDefinition SOUL_TESTER = REGISTRATE + .multiblock("soul_tester", PrimitiveWorkableMachine::new) + .rotationState(RotationState.NON_Y_AXIS) + .recipeType(CosmicRecipeTypes.SOUL_TESTER_RECIPES) + .appearanceBlock(GTBlocks.CASING_PRIMITIVE_BRICKS) + .pattern(definition -> FactoryBlockPattern.start() + .aisle("S", "S", "C", "I", "I") + .where("C", controller(blocks(definition.getBlock()))) + .where("S", abilities(CosmicPartAbility.IMPORT_SOUL).or(abilities(CosmicPartAbility.EXPORT_SOUL))) + .where("I", abilities(PartAbility.EXPORT_ITEMS).or(abilities(PartAbility.IMPORT_ITEMS))) + .build()) + .workableCasingModel(GTCEu.id("block/casings/solid/machine_casing_inert_ptfe"), + GTCEu.id("block/multiblock/coke_oven")) + .register(); /* * public static final MultiblockMachineDefinition EMBER_TESTER = REGISTRATE.multiblock("ember_tester", diff --git a/src/main/java/com/ghostipedia/cosmiccore/common/item/SoulNetworkReaderItem.java b/src/main/java/com/ghostipedia/cosmiccore/common/item/SoulNetworkReaderItem.java index 746529835..34b317c96 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/common/item/SoulNetworkReaderItem.java +++ b/src/main/java/com/ghostipedia/cosmiccore/common/item/SoulNetworkReaderItem.java @@ -3,6 +3,7 @@ import com.ghostipedia.cosmiccore.api.data.souls.SoulNetwork; import com.ghostipedia.cosmiccore.api.data.souls.SoulNetworkSavedData; import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulStack; + import net.minecraft.ChatFormatting; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; @@ -37,10 +38,11 @@ public static Component displaySoulNetworkInfo(SoulNetwork network) { if (contents.isEmpty()) { message.append(Component.translatable("gui.cosmiccore.soul.empty_network").withStyle(ChatFormatting.GRAY)); } else { - message.append(Component.translatable("gui.cosmiccore.soul.network_contents").withStyle(ChatFormatting.GOLD)).append("\n"); + message.append( + Component.translatable("gui.cosmiccore.soul.network_contents").withStyle(ChatFormatting.GOLD)) + .append("\n"); for (SoulStack stack : contents) message.append("\n").append(stack.type().toComponent(stack.amount())); } return message; } - } diff --git a/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java b/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java index cb29797c4..dca224da2 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java +++ b/src/main/java/com/ghostipedia/cosmiccore/common/machine/multiblock/part/SoulHatchPartMachine.java @@ -8,18 +8,16 @@ import com.gregtechceu.gtceu.api.machine.IMachineBlockEntity; import com.gregtechceu.gtceu.api.machine.feature.multiblock.IMultiController; import com.gregtechceu.gtceu.api.machine.multiblock.part.TieredIOPartMachine; -import com.gregtechceu.gtceu.utils.FormattingUtil; import com.lowdragmc.lowdraglib.gui.widget.*; import com.lowdragmc.lowdraglib.syncdata.annotation.DescSynced; import com.lowdragmc.lowdraglib.syncdata.annotation.Persisted; import com.lowdragmc.lowdraglib.syncdata.field.ManagedFieldHolder; -import com.lowdragmc.lowdraglib.utils.DummyWorld; import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.client.resources.language.I18n; import net.minecraft.network.chat.Component; -import net.minecraft.world.entity.player.Player; +import net.minecraft.server.TickTask; import wayoftime.bloodmagic.util.helper.PlayerHelper; @@ -41,15 +39,22 @@ public SoulHatchPartMachine(IMachineBlockEntity holder, int tier, IO io) { this.soulContainer = new NotifiableSoulContainer(this, io, getMaxConsumption(tier), getMaxCapacity(tier)); } -// @Override -// public void addedToController(IMultiController controller) { -// if (getLevel() instanceof DummyWorld) return; -// super.addedToController(controller); -// boolean hasDuplicate = controller.getParts().stream() -// .filter(part -> part != this) -// .anyMatch(part -> part instanceof SoulHatchPartMachine soulHatch && soulHatch.io == this.io); -// if (hasDuplicate) controller.onStructureInvalid(); -// } + @Override + public void addedToController(IMultiController controller) { + super.addedToController(controller); + controller.self().getLevel().getServer().tell(new TickTask(0, this::invalidateIfDuplicate)); + } + + private void invalidateIfDuplicate() { + for (var controller : getControllers()) { + for (var part : controller.getParts()) { + if (part == this) continue; + if (part instanceof SoulHatchPartMachine soulHatch && soulHatch.io == this.io) { + controller.onStructureInvalid(); + } + } + } + } @Override public Widget createUIWidget() { @@ -72,10 +77,10 @@ public Widget createUIWidget() { public static int getMaxConsumption(int tier) { return switch (tier) { - case GTValues.IV -> 10_000; + case GTValues.IV -> 10_000; case GTValues.LuV -> 50_000; case GTValues.ZPM -> 5_000_000; - case GTValues.UV -> 10_000_000; + case GTValues.UV -> 10_000_000; case GTValues.UHV -> 25_000_000; case GTValues.UEV -> 50_000_000; case GTValues.UIV -> 125_000_000; @@ -88,10 +93,10 @@ public static int getMaxConsumption(int tier) { public static int getMaxCapacity(int tier) { return switch (tier) { - case GTValues.IV -> 1_000_000; + case GTValues.IV -> 1_000_000; case GTValues.LuV -> 10_000_000; case GTValues.ZPM -> 50_000_000; - case GTValues.UV -> 100_000_000; + case GTValues.UV -> 100_000_000; case GTValues.UHV -> 250_000_000; case GTValues.UEV -> 500_000_000; case GTValues.UIV -> 1_000_000_000; diff --git a/src/main/java/com/ghostipedia/cosmiccore/forge/ForgeCommonEventListener.java b/src/main/java/com/ghostipedia/cosmiccore/forge/ForgeCommonEventListener.java index 6b66848ff..5ca4505b6 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/forge/ForgeCommonEventListener.java +++ b/src/main/java/com/ghostipedia/cosmiccore/forge/ForgeCommonEventListener.java @@ -13,14 +13,12 @@ import com.ghostipedia.cosmiccore.common.machine.multiblock.multi.SteamAssembler; import com.ghostipedia.cosmiccore.common.machine.multiblock.multi.SteamCaster; import com.ghostipedia.cosmiccore.common.machine.multiblock.multi.SteamMixer; -import com.ghostipedia.cosmiccore.common.machine.multiblock.part.SoulHatchPartMachine; import com.ghostipedia.cosmiccore.common.reflection.ReflectionCommand; import com.ghostipedia.cosmiccore.common.reflection.ReflectionCommands; import com.ghostipedia.cosmiccore.mixin.accessor.LivingEntityAccessor; import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.api.GTValues; -import com.gregtechceu.gtceu.api.block.MetaMachineBlock; import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; import com.gregtechceu.gtceu.api.item.armor.ArmorComponentItem; import com.gregtechceu.gtceu.api.machine.MachineDefinition; @@ -43,7 +41,6 @@ import net.minecraftforge.event.entity.living.LivingEquipmentChangeEvent; import net.minecraftforge.event.entity.living.LivingEvent; import net.minecraftforge.event.entity.living.LivingFallEvent; -import net.minecraftforge.event.level.BlockEvent; import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; diff --git a/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java b/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java index 7fd3120b8..5e1aa602f 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java +++ b/src/main/java/com/ghostipedia/cosmiccore/gtbridge/CosmicCoreRecipes.java @@ -1,10 +1,8 @@ package com.ghostipedia.cosmiccore.gtbridge; -import com.ghostipedia.cosmiccore.api.capability.CosmicCapabilities; import com.ghostipedia.cosmiccore.api.capability.recipe.CosmicRecipeCapabilities; import com.ghostipedia.cosmiccore.api.capability.souls.SoulType; import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulIngredient; -import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulStack; import com.ghostipedia.cosmiccore.common.machine.multiblock.multi.logic.LarvaMachine; import com.ghostipedia.cosmiccore.common.recipe.condition.LinkedPartnerCondition; import com.ghostipedia.cosmiccore.common.recipe.condition.LinkedPartnerDimensionCondition; @@ -119,6 +117,7 @@ public static void init(Consumer provider) { .save(provider); SOUL_TESTER_RECIPES.recipeBuilder("generate_soul_2") + .notConsumable(Items.STONE) .input(CosmicRecipeCapabilities.SOUL, SoulIngredient.of(SoulType.Raw, 10)) .outputItems(ingot, Steel) .duration(20) diff --git a/src/main/java/com/ghostipedia/cosmiccore/integration/kjs/recipe/components/CosmicRecipeComponent.java b/src/main/java/com/ghostipedia/cosmiccore/integration/kjs/recipe/components/CosmicRecipeComponent.java index 73c07cb2e..b0ad4c814 100644 --- a/src/main/java/com/ghostipedia/cosmiccore/integration/kjs/recipe/components/CosmicRecipeComponent.java +++ b/src/main/java/com/ghostipedia/cosmiccore/integration/kjs/recipe/components/CosmicRecipeComponent.java @@ -2,11 +2,11 @@ import com.ghostipedia.cosmiccore.api.capability.recipe.EmberRecipeCapability; import com.ghostipedia.cosmiccore.api.capability.recipe.SoulRecipeCapability; - import com.ghostipedia.cosmiccore.api.recipe.ingredient.SoulIngredient; -import com.google.gson.JsonElement; + import com.gregtechceu.gtceu.integration.kjs.recipe.components.ContentJS; +import com.google.gson.JsonElement; import com.mojang.serialization.JsonOps; import dev.latvian.mods.kubejs.recipe.RecipeJS; import dev.latvian.mods.kubejs.recipe.component.NumberComponent; @@ -43,7 +43,7 @@ public JsonElement write(RecipeJS recipeJS, SoulIngredient soulIngredient) { public SoulIngredient read(RecipeJS recipeJS, Object o) { if (o instanceof Wrapper w) o = w.unwrap(); - if (o instanceof SoulIngredient soulIngredient) { + if (o instanceof SoulIngredient soulIngredient) { return soulIngredient; } else { System.out.println("Shit we have a problem !");