This commit is contained in:
GearShocky 2022-09-03 17:43:26 +06:00
commit 00b8e546b0
195 changed files with 3833 additions and 3285 deletions

View File

@ -14,7 +14,7 @@ import net.minecraftforge.fml.common.Mod
import net.minecraftforge.data.event.GatherDataEvent
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.block.*
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState
import ru.dbotthepony.mc.otm.block.entity.WorkerState
import ru.dbotthepony.mc.otm.block.matter.MatterBottlerBlock
import ru.dbotthepony.mc.otm.block.matter.PatternStorageBlock
import ru.dbotthepony.mc.otm.block.storage.DriveViewerBlock
@ -30,7 +30,7 @@ import ru.dbotthepony.mc.otm.datagen.models.BlockMatteryModelProvider
import ru.dbotthepony.mc.otm.datagen.recipes.MatteryRecipeProvider
import ru.dbotthepony.mc.otm.datagen.recipes.has
import ru.dbotthepony.mc.otm.registry.*
import ru.dbotthepony.mc.otm.*
import ru.dbotthepony.mc.otm.core.registryName
import ru.dbotthepony.mc.otm.datagen.lang.MatteryLanguageProvider
import ru.dbotthepony.mc.otm.datagen.loot.addLootModifiers
import ru.dbotthepony.mc.otm.datagen.recipes.addCraftingTableRecipes

View File

@ -7,12 +7,12 @@ import net.minecraftforge.client.model.generators.BlockStateProvider
import net.minecraftforge.client.model.generators.ConfiguredModel
import net.minecraftforge.data.event.GatherDataEvent
import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState
import ru.dbotthepony.mc.otm.block.entity.WorkerState
import ru.dbotthepony.mc.otm.datagen.DataGen
import ru.dbotthepony.mc.otm.datagen.getValueNullable
import ru.dbotthepony.mc.otm.datagen.toXRotBlockstate
import ru.dbotthepony.mc.otm.datagen.toYRotBlockstate
import ru.dbotthepony.mc.otm.registryName
import ru.dbotthepony.mc.otm.core.registryName
typealias AdvancedBlockStateFunction = (BlockState, ConfiguredModel.Builder<*>, String) -> String?
private data class AdvancedBlockStateEntry(val block: Block, val func: AdvancedBlockStateFunction)

View File

@ -6,7 +6,7 @@ import net.minecraftforge.client.model.generators.ItemModelProvider
import net.minecraftforge.data.event.GatherDataEvent
import org.apache.logging.log4j.LogManager
import ru.dbotthepony.mc.otm.datagen.DataGen
import ru.dbotthepony.mc.otm.registryName
import ru.dbotthepony.mc.otm.core.registryName
private data class SimpleItemModel(val item: String, val path: ResourceLocation) {
val traceback = IllegalArgumentException("Failed to register model")

View File

@ -53,6 +53,10 @@ private fun misc(provider: MatteryLanguageProvider) {
gui("exosuit.already_activated", "You already have exosuit following you")
gui("power_supplier.active_nodes", "Currently demanding nodes: %s")
misc("battery.single_use", "Single use battery, can not be recharged.")
misc("exosuit.granted1", "As you keep pressing fingerprint reader, you are getting hurt in finger.")
misc("exosuit.granted2", "After you raise your finger, fingerprint reader glows very bright.")
misc("exosuit.granted3", "Then, fingerprint reader fades, leaving faint trace not of your finger, but of your very soul.")
@ -128,6 +132,9 @@ private fun misc(provider: MatteryLanguageProvider) {
misc("item.power.normal.storage", "Stored energy: %s / %s")
misc("item.power.normal.throughput", "Max I/O %s / %s")
misc("item.power.output_only", "Max output %s")
misc("item.power.input_only", "Max input %s")
misc("item.pattern.stored", "Stored patterns: %s / %s")
misc("item.pattern.infinite.stored", "Stored patterns %s")
misc("item.pattern.line", "%s [%s%%]")
@ -377,6 +384,9 @@ private fun items(provider: MatteryLanguageProvider) {
add(MItems.TRITANIUM_ORE_CLUMP, "Raw Tritanium")
add(MItems.PATTERN_DRIVE_NORMAL, "Pattern Drive")
add(MItems.PATTERN_DRIVE_CREATIVE, "Creative Pattern Drive")
add(MItems.ZPM_BATTERY, "Zero Point Module")
add(MItems.ZPM_BATTERY, "description", "Can be found in hands of those who travel between dimensions, if they ever reached different reality of origin of these constructs...")
}
}

View File

@ -39,11 +39,12 @@ fun addLootModifiers(it: LootModifiers) {
ItemStack(MItems.PILL_ANDROID, 1) to 0.5
))
it.add("end_city_pill", LootTableBasicAppender(
it.add("end_city_modifications", LootTableBasicAppender(
arrayOf(LootTableIdCondition.Builder(ResourceLocation("chests/end_city_treasure")).build()),
ItemStack(MItems.PILL_ANDROID, 1) to 0.1,
ItemStack(MItems.PILL_HUMANE, 1) to 0.3,
ItemStack(MItems.PILL_OBLIVION, 1) to 0.5,
ItemStack(MItems.ZPM_BATTERY, 1) to 0.005,
))
it.add("shipwreck_supply_pill", LootTableBasicAppender(

View File

@ -9,7 +9,8 @@ import net.minecraft.core.Direction
import net.minecraft.resources.ResourceLocation
import net.minecraftforge.client.model.generators.ModelBuilder
import net.minecraftforge.common.data.ExistingFileHelper
import ru.dbotthepony.mc.otm.set
import ru.dbotthepony.mc.otm.container.set
import ru.dbotthepony.mc.otm.core.set
data class TextureSize(val width: Float, val height: Float) {
constructor(arr: JsonArray) : this(arr[0].asFloat, arr[1].asFloat)

View File

@ -8,7 +8,7 @@ import net.minecraft.world.level.block.Block
import net.minecraftforge.client.model.generators.ModelProvider
import net.minecraftforge.data.event.GatherDataEvent
import ru.dbotthepony.mc.otm.datagen.DataGen
import ru.dbotthepony.mc.otm.registryName
import ru.dbotthepony.mc.otm.core.registryName
private typealias Callback = (MatteryModelProvider) -> Unit

View File

@ -4,8 +4,6 @@ import net.minecraft.data.recipes.FinishedRecipe
import net.minecraft.data.recipes.ShapedRecipeBuilder
import net.minecraft.data.recipes.ShapelessRecipeBuilder
import net.minecraft.resources.ResourceLocation
import net.minecraft.tags.TagKey
import net.minecraft.world.item.Item
import net.minecraft.world.item.Items
import net.minecraft.world.item.crafting.Ingredient
import net.minecraftforge.common.Tags
@ -15,7 +13,7 @@ import ru.dbotthepony.mc.otm.registry.MBlocks
import ru.dbotthepony.mc.otm.registry.MItemTags
import ru.dbotthepony.mc.otm.registry.MItems
import ru.dbotthepony.mc.otm.registry.MRegistry
import ru.dbotthepony.mc.otm.registryName
import ru.dbotthepony.mc.otm.core.registryName
import java.util.function.Consumer
fun addCraftingTableRecipes(consumer: Consumer<FinishedRecipe>) {
@ -55,6 +53,22 @@ fun addCraftingTableRecipes(consumer: Consumer<FinishedRecipe>) {
.build(consumer)
}
MatteryRecipe(MBlocks.PLATE_PRESS)
.row(MItems.ELECTRIC_PARTS, MItems.ENERGY_BUS, MItems.ELECTRIC_PARTS)
.row(MItemTags.INGOT_TRITANIUM, Items.BLAST_FURNACE, MItemTags.INGOT_TRITANIUM)
.row(MItemTags.PISTONS, MItemTags.INGOT_TRITANIUM, MItemTags.PISTONS)
.unlockedBy(MItemTags.INGOT_TRITANIUM)
.unlockedBy(MItems.ELECTRIC_PARTS)
.build(consumer)
MatteryRecipe(MBlocks.PLATE_PRESS)
.rowB(MItemTags.BASIC_CIRCUIT)
.row(MItemTags.PLATE_TRITANIUM, MItems.MACHINE_FRAME, MItemTags.PLATE_TRITANIUM)
.rowAC(MItemTags.PISTONS, MItemTags.PISTONS)
.unlockedBy(MItemTags.INGOT_TRITANIUM)
.unlockedBy(MItems.ELECTRIC_PARTS)
.build(consumer, "advanced")
MatteryRecipe(MBlocks.TRITANIUM_STRIPED_BLOCK, 24)
.rowB(MItemTags.PLATE_TRITANIUM)
.row(MItemTags.PLATE_TRITANIUM, COBBLESTONE, MItemTags.PLATE_TRITANIUM)

View File

@ -11,7 +11,7 @@ import net.minecraft.world.item.Item
import net.minecraft.world.item.crafting.Ingredient
import net.minecraft.world.level.ItemLike
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.registryName
import ru.dbotthepony.mc.otm.core.registryName
import java.util.function.Consumer
private interface RecipeCell {

View File

@ -7,7 +7,8 @@ import net.minecraft.resources.ResourceLocation
import net.minecraft.world.item.crafting.RecipeSerializer
import ru.dbotthepony.mc.otm.recipe.PlatePressRecipe
import ru.dbotthepony.mc.otm.recipe.PlatePressRecipeFactory
import ru.dbotthepony.mc.otm.set
import ru.dbotthepony.mc.otm.container.set
import ru.dbotthepony.mc.otm.core.set
class PlatePressFinishedRecipe(private val recipe: PlatePressRecipe) : FinishedRecipe {
override fun serializeRecipeData(it: JsonObject) {

View File

@ -2,8 +2,10 @@ package ru.dbotthepony.mc.otm;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.eventbus.api.EventPriority;
import net.minecraftforge.fml.ModList;
@ -15,15 +17,15 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import ru.dbotthepony.mc.otm.block.entity.blackhole.ExplosionQueue;
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability;
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
import ru.dbotthepony.mc.otm.capability.drive.DrivePool;
import ru.dbotthepony.mc.otm.client.ClientEventHandler;
import ru.dbotthepony.mc.otm.client.MatteryGUI;
import ru.dbotthepony.mc.otm.client.EventHandlerKt;
import ru.dbotthepony.mc.otm.client.model.GravitationStabilizerModel;
import ru.dbotthepony.mc.otm.client.model.TritaniumArmorModel;
import ru.dbotthepony.mc.otm.compat.mekanism.QIOKt;
import ru.dbotthepony.mc.otm.compat.mekanism.TooltipsKt;
import ru.dbotthepony.mc.otm.core.ImpreciseFraction;
import ru.dbotthepony.mc.otm.item.QuantumBatteryItem;
import ru.dbotthepony.mc.otm.item.weapon.AbstractWeaponItem;
import ru.dbotthepony.mc.otm.item.PortableCondensationDriveItem;
import ru.dbotthepony.mc.otm.matter.MatterDataKt;
@ -33,6 +35,8 @@ import ru.dbotthepony.mc.otm.registry.*;
import ru.dbotthepony.mc.otm.storage.*;
import ru.dbotthepony.mc.otm.worldgen.OreGen;
import static net.minecraftforge.common.MinecraftForge.EVENT_BUS;
import javax.annotation.ParametersAreNonnullByDefault;
// The value here should match an entry in the META-INF/mods.toml file
@ -76,49 +80,78 @@ public final class OverdriveThatMatters {
INSTANCE = this;
MRegistry.INSTANCE.initialize(FMLJavaModLoadingContext.get());
var modBus = FMLJavaModLoadingContext.get().getModEventBus();
FMLJavaModLoadingContext.get().getModEventBus().addListener(EventPriority.HIGHEST, this::setup);
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::setupClient);
MRegistry.INSTANCE.initialize(modBus);
MinecraftForge.EVENT_BUS.register(this);
MinecraftForge.EVENT_BUS.register(GlobalEventHandlerKt.class);
MinecraftForge.EVENT_BUS.register(MatteryPlayerCapability.Companion);
MinecraftForge.EVENT_BUS.register(MatterRegistryKt.class);
MinecraftForge.EVENT_BUS.register(MatterDataKt.class);
MinecraftForge.EVENT_BUS.register(ExplosionQueue.Companion);
MinecraftForge.EVENT_BUS.register(AbstractWeaponItem.Companion);
FMLJavaModLoadingContext.get().getModEventBus().register(MatteryCapability.class);
FMLJavaModLoadingContext.get().getModEventBus().register(MRecipes.class);
MinecraftForge.EVENT_BUS.register(DrivePool.INSTANCE);
MinecraftForge.EVENT_BUS.register(PortableCondensationDriveItem.Companion);
FMLJavaModLoadingContext.get().getModEventBus().addListener(MatteryPlayerCapability::registerEffects);
modBus.addListener(EventPriority.HIGHEST, this::setup);
modBus.addListener(EventPriority.NORMAL, this::setupClient);
}
private void setup(final FMLCommonSetupEvent event) {
EVENT_BUS.addListener(EventPriority.LOWEST, DrivePool.INSTANCE::onServerPostTick);
EVENT_BUS.addListener(EventPriority.HIGHEST, DrivePool.INSTANCE::serverStopEvent);
EVENT_BUS.addListener(EventPriority.HIGHEST, DrivePool.INSTANCE::serverStartEvent);
EVENT_BUS.addListener(EventPriority.NORMAL, DrivePool.INSTANCE::onWorldSave);
EVENT_BUS.addListener(EventPriority.HIGHEST, GlobalEventHandlerKt::onServerStopped);
EVENT_BUS.addListener(EventPriority.HIGHEST, GlobalEventHandlerKt::onServerStopping);
EVENT_BUS.addListener(EventPriority.HIGHEST, GlobalEventHandlerKt::onServerStarting);
EVENT_BUS.addListener(EventPriority.LOWEST, GlobalEventHandlerKt::onWorldTick);
EVENT_BUS.addListener(EventPriority.LOWEST, GlobalEventHandlerKt::onServerTick);
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryPlayerCapability.Companion::onLivingTick);
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryPlayerCapability.Companion::onHurtEvent);
EVENT_BUS.addGenericListener(Entity.class, EventPriority.NORMAL, MatteryPlayerCapability.Companion::onAttachCapabilityEvent);
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryPlayerCapability.Companion::onPlayerChangeDimensionEvent);
EVENT_BUS.addListener(EventPriority.LOWEST, MatteryPlayerCapability.Companion::onPlayerDeath);
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryPlayerCapability.Companion::onPlayerCloneEvent);
EVENT_BUS.addListener(EventPriority.LOW, MatteryPlayerCapability.Companion::onPickupEvent);
EVENT_BUS.addListener(EventPriority.LOW, MatterDataKt::serverStartData);
EVENT_BUS.addListener(EventPriority.NORMAL, MatterRegistryKt::onPlayerJoin);
EVENT_BUS.addListener(EventPriority.NORMAL, ExplosionQueue.Companion::onWorldTick);
EVENT_BUS.addListener(EventPriority.NORMAL, AbstractWeaponItem.Companion::tick);
EVENT_BUS.addListener(EventPriority.NORMAL, QuantumBatteryItem.Companion::tick);
EVENT_BUS.addListener(EventPriority.LOWEST, PortableCondensationDriveItem.Companion::onPickupEvent);
MatteryPlayerCapability.Companion.registerEffects(event);
MatteryPlayerNetworkChannel.INSTANCE.register();
MenuNetworkChannel.INSTANCE.register();
WeaponNetworkChannel.INSTANCE.register();
RegistryNetworkChannel.INSTANCE.register();
WorldNetworkChannel.INSTANCE.register();
GenericNetworkChannel.INSTANCE.register();
ITEM_STORAGE = StorageRegistry.register(ItemStackWrapper.class, ItemStackWrapper.EMPTY, new ImpreciseFraction("3.125"));
if (ModList.get().isLoaded("mekanism")) {
MinecraftForge.EVENT_BUS.register(QIOKt.class);
MinecraftForge.EVENT_BUS.register(TooltipsKt.class);
EVENT_BUS.addGenericListener(BlockEntity.class, EventPriority.NORMAL, QIOKt::attachCapabilities);
}
OreGen.INSTANCE.register();
}
private void setupClient(final FMLClientSetupEvent event) {
MinecraftForge.EVENT_BUS.register(MatteryGUI.INSTANCE);
MinecraftForge.EVENT_BUS.register(EventHandlerKt.class);
EVENT_BUS.addListener(EventPriority.NORMAL, MatterRegistryKt::tooltipEvent);
EVENT_BUS.addListener(EventPriority.NORMAL, AbstractWeaponItem.Companion::playerRenderHook);
EVENT_BUS.addListener(EventPriority.NORMAL, AbstractWeaponItem.Companion::fovHook);
EVENT_BUS.addListener(EventPriority.NORMAL, AbstractWeaponItem.Companion::clickHook);
EVENT_BUS.addListener(EventPriority.NORMAL, AbstractWeaponItem.Companion::renderViewModel);
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryGUI.INSTANCE::onScreenRender);
EVENT_BUS.addListener(EventPriority.LOWEST, MatteryGUI.INSTANCE::onOpenGUIEvent);
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryGUI.INSTANCE::onRenderGuiEvent);
EVENT_BUS.addListener(EventPriority.HIGH, MatteryGUI.INSTANCE::onLayerRenderEvent);
EVENT_BUS.addListener(EventPriority.NORMAL, ClientEventHandler.INSTANCE::inputEvent);
EVENT_BUS.addListener(EventPriority.NORMAL, ClientEventHandler.INSTANCE::screenOpen);
if (ModList.get().isLoaded("mekanism")) {
EVENT_BUS.addListener(EventPriority.NORMAL, TooltipsKt::tooltipEvent);
}
event.enqueueWork(GlobalEventHandlerKt::recordClientThread);

View File

@ -5,7 +5,7 @@ import net.minecraftforge.common.capabilities.*;
import org.jetbrains.annotations.NotNull;
import ru.dbotthepony.mc.otm.capability.drive.IMatteryDrive;
import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler;
import ru.dbotthepony.mc.otm.capability.matter.IMatterTaskProvider;
import ru.dbotthepony.mc.otm.capability.matter.IReplicationTaskProvider;
import ru.dbotthepony.mc.otm.capability.matter.IPatternStorage;
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode;
import ru.dbotthepony.mc.otm.graph.storage.IStorageGraphNode;
@ -36,7 +36,7 @@ public class MatteryCapability {
@Nonnull
@NotNull
public static final Capability<IMatterTaskProvider> TASK = CapabilityManager.get(new CapabilityToken<>() {});
public static final Capability<IReplicationTaskProvider> TASK = CapabilityManager.get(new CapabilityToken<>() {});
@Nonnull
@NotNull
@ -49,16 +49,4 @@ public class MatteryCapability {
@Nonnull
@NotNull
public static final Capability<IStrictEnergyHandler> MEKANISM_ENERGY = CapabilityManager.get(new CapabilityToken<>() {});
@SuppressWarnings("unused")
public static void register(final RegisterCapabilitiesEvent event) {
event.register(IMatteryEnergyStorage.class);
event.register(MatteryPlayerCapability.class);
event.register(IMatterHandler.class);
event.register(IPatternStorage.class);
event.register(IMatterTaskProvider.class);
event.register(IMatteryDrive.class);
event.register(IStorageGraphNode.class);
event.register(IMatterGraphNode.class);
}
}

View File

@ -1,147 +0,0 @@
package ru.dbotthepony.mc.otm.capability.matter;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.registries.ForgeRegistry;
import net.minecraftforge.registries.RegistryManager;
import ru.dbotthepony.mc.otm.UnOverengineeringKt;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.Objects;
import java.util.UUID;
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public record MatterTask(UUID id, @Nullable UUID pattern, Item item, int in_progress, int finished, int required) {
public MatterTask(UUID id, @Nullable UUID pattern, Item item, int in_progress, int finished, int required) {
this.id = id;
this.pattern = pattern;
this.item = item;
this.in_progress = Math.max(0, in_progress);
this.finished = Math.max(0, finished);
this.required = Math.max(0, required);
}
@Override
public int hashCode() {
return id.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof MatterTask obj1)
return obj1.id.equals(id);
return false;
}
public ItemStack stack() {
return new ItemStack(item, 1);
}
public ItemStack stack(int amount) {
return new ItemStack(item, amount);
}
public int total() {
return in_progress + finished + required;
}
public MatterTask shrinkRequired(int amount) {
return new MatterTask(id, pattern, item, in_progress + amount, finished, required - amount);
}
public MatterTask shrinkInProgress(int amount) {
return new MatterTask(id, pattern, item, in_progress - amount, finished + amount, required);
}
public CompoundTag serializeNBT() {
CompoundTag tag = new CompoundTag();
tag.putLong("id_l", id.getLeastSignificantBits());
tag.putLong("id_u", id.getMostSignificantBits());
if (pattern != null) {
tag.putLong("pattern_l", pattern.getLeastSignificantBits());
tag.putLong("pattern_u", pattern.getMostSignificantBits());
}
tag.putString("item", Objects.requireNonNull(UnOverengineeringKt.getRegistryName(item)).toString());
tag.putInt("in_progress", in_progress);
tag.putInt("finished", finished);
tag.putInt("required", required);
return tag;
}
@Nullable
public static MatterTask deserializeNBT(@Nullable Tag nbt) {
if (nbt == null)
return null;
if (nbt instanceof CompoundTag tag) {
Item get_item = ForgeRegistries.ITEMS.getValue(new ResourceLocation(tag.getString("item")));
if (get_item != null && get_item != Items.AIR) {
long a = tag.getLong("pattern_u");
long b = tag.getLong("pattern_l");
UUID pattern = a != 0 && b != 0 ? new UUID(a, b) : null;
return new MatterTask(
new UUID(tag.getLong("id_u"), tag.getLong("id_l")),
pattern,
get_item,
tag.getInt("in_progress"),
tag.getInt("finished"),
tag.getInt("required")
);
}
}
return null;
}
public void write(FriendlyByteBuf buffer) {
buffer.writeLong(id.getMostSignificantBits());
buffer.writeLong(id.getLeastSignificantBits());
if (pattern != null) {
buffer.writeBoolean(true);
buffer.writeLong(pattern.getMostSignificantBits());
buffer.writeLong(pattern.getLeastSignificantBits());
} else {
buffer.writeBoolean(false);
}
buffer.writeInt(((ForgeRegistry<Item>) ForgeRegistries.ITEMS).getID(item));
buffer.writeInt(in_progress);
buffer.writeInt(finished);
buffer.writeInt(required);
}
@Nullable
public static MatterTask read(FriendlyByteBuf buffer) {
var id = new UUID(buffer.readLong(), buffer.readLong());
var pattern = buffer.readBoolean() ? new UUID(buffer.readLong(), buffer.readLong()) : null;
var item = ((ForgeRegistry<Item>) ForgeRegistries.ITEMS).getValue(buffer.readInt());
if (item == null)
return null;
var in_progress = buffer.readInt();
var finished = buffer.readInt();
var required = buffer.readInt();
return new MatterTask(id, pattern, item, in_progress, finished, required);
}
}

View File

@ -1,95 +0,0 @@
package ru.dbotthepony.mc.otm.capability.matter;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.registries.ForgeRegistry;
import net.minecraftforge.registries.RegistryManager;
import ru.dbotthepony.mc.otm.UnOverengineeringKt;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Objects;
import java.util.UUID;
public record PatternState(@Nonnull UUID id, @Nonnull Item item, double research) {
public PatternState(@Nonnull UUID id, @Nonnull Item item, double research) {
this.id = id;
this.item = item;
this.research = Math.max(0, Math.min(1, research));
}
@Override
public boolean equals(Object state) {
if (state instanceof PatternState state1)
return state1.id.equals(id);
return false;
}
public ItemStack stack() {
return new ItemStack(item, 1);
}
@Override
public int hashCode() {
return id.hashCode();
}
public CompoundTag serializeNBT() {
var tag = new CompoundTag();
tag.putLong("id_m", id.getMostSignificantBits());
tag.putLong("id_l", id.getLeastSignificantBits());
tag.putString("item", Objects.requireNonNull(UnOverengineeringKt.getRegistryName(item)).toString());
tag.putDouble("research_percent", research);
return tag;
}
@Nullable
public static PatternState deserializeNBT(Tag nbt) {
if (nbt instanceof CompoundTag tag) {
var item = ForgeRegistries.ITEMS.getValue(new ResourceLocation(tag.getString("item")));
if (item == null)
return null;
var id = new UUID(tag.getLong("id_m"), tag.getLong("id_l"));
var research_percent = tag.getDouble("research_percent");
return new PatternState(id, item, research_percent);
}
return null;
}
public void write(FriendlyByteBuf buffer) {
buffer.writeLong(id.getMostSignificantBits());
buffer.writeLong(id.getLeastSignificantBits());
buffer.writeInt(((ForgeRegistry<Item>) ForgeRegistries.ITEMS).getID(item));
buffer.writeDouble(research);
}
@Nullable
public static PatternState read(FriendlyByteBuf buffer) {
long ida = buffer.readLong();
long idb = buffer.readLong();
int item = buffer.readInt();
double percent = buffer.readDouble();
Item get_item = ((ForgeRegistry<Item>) ForgeRegistries.ITEMS).getValue(item);
if (get_item == null)
return null;
return new PatternState(new UUID(ida, idb), get_item, percent);
}
}

View File

@ -1,401 +0,0 @@
package ru.dbotthepony.mc.otm.client.screen;
import net.minecraft.ChatFormatting;
import net.minecraft.client.gui.components.EditBox;
import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.item.ItemStack;
import ru.dbotthepony.mc.otm.capability.matter.MatterTask;
import ru.dbotthepony.mc.otm.capability.matter.PatternState;
import ru.dbotthepony.mc.otm.menu.MatterPanelMenu;
import ru.dbotthepony.mc.otm.menu.ReplicationRequestPacket;
import ru.dbotthepony.mc.otm.network.MenuNetworkChannel;
import ru.dbotthepony.mc.otm.client.screen.panels.*;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import static ru.dbotthepony.mc.otm.UnOverengineeringKt.TextComponent;
import static ru.dbotthepony.mc.otm.UnOverengineeringKt.TranslatableComponent;
public class MatterPanelScreen extends MatteryScreen<MatterPanelMenu> {
private static final int MODAL_WIDTH = 213;
private static final int MODAL_HEIGHT = 110;
public MatterPanelScreen(MatterPanelMenu p_97741_, Inventory p_97742_, Component p_97743_) {
super(p_97741_, p_97742_, p_97743_);
imageWidth = 176;
imageHeight = 187;
titleLabelY = 5;
}
public static final int GRID_WIDTH = 8;
public static final int GRID_HEIGHT = 9;
private final ArrayList<AbstractSlotPanel> pattern_slots = new ArrayList<>();
private final ArrayList<AbstractSlotPanel> task_slots = new ArrayList<>();
@Nullable
@Override
protected FramePanel makeMainFrame() {
float width = GRID_WIDTH * AbstractSlotPanel.SIZE + ScrollBarConstants.WIDTH + FramePanel.PADDING * 2 + 8;
float height = GRID_HEIGHT * AbstractSlotPanel.SIZE + FramePanel.PADDING_TOP + FramePanel.PADDING;
var scroll_panel = new ContinuousScrollBarPanel(this, null, 0, 0, 0);
var frame = new FramePanel(this, null, 0, 0, width, height, getTitle()) {
@Override
protected boolean mouseScrolledInner(double x, double y, double scroll) {
return scroll_panel.mouseScrolledInner(x, y, scroll);
}
};
var patterns_tab = frame.addTab(FramePanel.Position.TOP, () -> {
for (var slot : pattern_slots) {
slot.setVisible(true);
}
}, () -> {
for (var slot : pattern_slots) {
slot.setVisible(false);
}
});
var tasks_tab = frame.addTab(FramePanel.Position.TOP, () -> {
for (var slot : task_slots) {
slot.setVisible(true);
}
}, () -> {
for (var slot : task_slots) {
slot.setVisible(false);
}
});
scroll_panel.setParent(frame);
scroll_panel.setDock(Dock.RIGHT);
scroll_panel.setupRowMultiplier(() -> {
if (tasks_tab.isActive()) {
return menu.getTasks().size() / GRID_WIDTH;
}
return menu.getPatterns().size() / GRID_WIDTH;
});
var grid = new GridPanel(this, frame, 0, 0, GRID_WIDTH * AbstractSlotPanel.SIZE, 0, GRID_WIDTH, GRID_HEIGHT) {
@Override
protected boolean mouseScrolledInner(double x, double y, double scroll) {
return scroll_panel.mouseScrolledInner(x, y, scroll);
}
};
grid.setDock(Dock.LEFT);
grid.setDockMargin(4, 0, 0, 0);
for (int i = 0; i < GRID_WIDTH * GRID_HEIGHT; i++) {
int slot = i;
pattern_slots.add(new AbstractSlotPanel(this, grid, 0, 0) {
@Nonnull
@Override
protected ItemStack getItemStack() {
var slot1 = slot + scroll_panel.getScroll(menu.getPatterns().size() / GRID_WIDTH) * GRID_WIDTH;
if (slot1 >= menu.getPatterns().size()) {
return ItemStack.EMPTY;
}
return menu.getPatterns().get(slot1).stack();
}
@Nonnull
@Override
protected List<Component> getItemStackTooltip(@Nonnull ItemStack stack) {
var slot1 = slot + scroll_panel.getScroll(menu.getPatterns().size() / GRID_WIDTH) * GRID_WIDTH;
if (slot1 >= menu.getPatterns().size()) {
return List.of();
}
return getPatternTooltip(super.getItemStackTooltip(stack), menu.getPatterns().get(slot1));
}
@Override
protected boolean mouseScrolledInner(double x, double y, double scroll) {
return scroll_panel.mouseScrolledInner(x, y, scroll);
}
@Override
protected boolean mouseClickedInner(double x, double y, int flag) {
if (slot >= menu.getPatterns().size()) {
return true;
}
openPattern(menu.getPatterns().get(slot));
return true;
}
});
task_slots.add(new AbstractSlotPanel(this, grid, 0, 0) {
@Nonnull
@Override
protected ItemStack getItemStack() {
var slot1 = slot + scroll_panel.getScroll(menu.getTasks().size() / GRID_WIDTH) * GRID_WIDTH;
if (slot1 >= menu.getTasks().size()) {
return ItemStack.EMPTY;
}
var task = menu.getTasks().get(slot1);
return task.stack(Math.max(task.required(), 1));
}
@Nonnull
@Override
protected List<Component> getItemStackTooltip(@Nonnull ItemStack stack) {
var slot1 = slot + scroll_panel.getScroll(menu.getTasks().size() / GRID_WIDTH) * GRID_WIDTH;
if (slot1 >= menu.getTasks().size()) {
return List.of();
}
return getTaskTooltip(super.getItemStackTooltip(stack), menu.getTasks().get(slot1));
}
@Override
protected boolean mouseScrolledInner(double x, double y, double scroll) {
return scroll_panel.mouseScrolledInner(x, y, scroll);
}
@Override
protected boolean mouseClickedInner(double x, double y, int flag) {
if (slot >= menu.getTasks().size()) {
return true;
}
openTask(menu.getTasks().get(slot));
return true;
}
});
}
for (var slot : task_slots) {
slot.setVisible(false);
}
return frame;
}
private List<Component> getTaskTooltip(List<Component> input, MatterTask task) {
input.add(TranslatableComponent("otm.gui.matter_task.total", task.total()).withStyle(ChatFormatting.GRAY));
input.add(TranslatableComponent("otm.gui.matter_task.required", task.required()).withStyle(ChatFormatting.GRAY));
input.add(TranslatableComponent("otm.gui.matter_task.in_progress", task.in_progress()).withStyle(ChatFormatting.GRAY));
input.add(TranslatableComponent("otm.gui.matter_task.finished", task.finished()).withStyle(ChatFormatting.GRAY));
return input;
}
private List<Component> getPatternTooltip(List<Component> input, PatternState pattern) {
input.add(TranslatableComponent("otm.item.pattern.research", String.format("%.2f", pattern.research() * 100d)).withStyle(ChatFormatting.AQUA));
return input;
}
private void openTask(MatterTask task) {
var task_frame = new FramePanel(this, null, 0, 0, 170, 40, TranslatableComponent("otm.container.matter_panel.task")) {
@Override
public void tick() {
super.tick();
if (!menu.getTasks().contains(task)) {
remove();
}
}
};
var slot = new AbstractSlotPanel(this, task_frame, 0, 0) {
@Nonnull
@Override
protected ItemStack getItemStack() {
var task1_index = menu.getTasks().indexOf(task);
if (task1_index != -1) {
var task1 = menu.getTasks().get(task1_index);
return task1.stack(Math.max(task1.required(), 1));
}
return ItemStack.EMPTY;
}
@Nonnull
@Override
protected List<Component> getItemStackTooltip(@Nonnull ItemStack stack) {
var task1_index = menu.getTasks().indexOf(task);
List<Component> get_list = super.getItemStackTooltip(stack);
if (task1_index != -1) {
getTaskTooltip(get_list, menu.getTasks().get(task1_index));
}
return get_list;
}
};
slot.setDock(Dock.LEFT);
var button = new ButtonPanel(this, task_frame, 0, 0, 40, 20, TranslatableComponent("otm.container.matter_panel.close"));
button.setDock(Dock.RIGHT);
button.setDockMargin(2, 0, 0, 0);
button.bind(task_frame::remove);
button = new ButtonPanel(this, task_frame, 0, 0, 80, 20, TranslatableComponent("otm.container.matter_panel.cancel_task"));
button.setDock(Dock.RIGHT);
button.setDockMargin(2, 0, 0, 0);
button.bind(() -> {
menu.requestTaskCancel(task.id());
task_frame.remove();
});
task_frame.toScreenCenter();
addPanel(task_frame);
}
private void openPattern(PatternState state) {
var pattern_frame = new FramePanel(this, null, 0, 0, MODAL_WIDTH, MODAL_HEIGHT, TranslatableComponent("otm.container.matter_panel.label")){
@Override
public void tick() {
super.tick();
if (!menu.getPatterns().contains(state)) {
remove();
}
}
};
var row_1 = new EditablePanel(this, pattern_frame);
var row_2 = new EditablePanel(this, pattern_frame);
var row_3 = new EditablePanel(this, pattern_frame);
var row_4 = new EditablePanel(this, pattern_frame);
row_1.setDock(Dock.TOP);
row_2.setDock(Dock.TOP);
row_3.setDock(Dock.TOP);
row_4.setDock(Dock.TOP);
row_1.setHeight(20);
row_2.setHeight(20);
row_3.setHeight(20);
row_4.setHeight(20);
row_1.setDockMargin(0, 2, 0, 0);
row_2.setDockMargin(0, 2, 0, 0);
row_3.setDockMargin(0, 2, 0, 0);
row_4.setDockMargin(0, 2, 0, 0);
var slot = new AbstractSlotPanel(this, row_2, 0, 0) {
@Nonnull
@Override
protected ItemStack getItemStack() {
return new ItemStack(state.item(), 1);
}
@Nonnull
@Override
protected List<Component> getItemStackTooltip(@Nonnull ItemStack stack) {
return getPatternTooltip(super.getItemStackTooltip(stack), state);
}
};
var input_amount = new EditBoxPanel(this, row_2, 0, 0, 10, 20, TextComponent("Input amount")) {
@Override
protected void configureNew(@Nonnull EditBox widget, boolean recreation) {
super.configureNew(widget, recreation);
widget.setMaxLength(6);
if (!recreation) {
widget.setValue("1");
}
}
private void increase(int amount) {
int value = 1;
try {
value = Integer.parseInt(getOrCreateWidget().getValue());
} catch (Exception ignored) {
}
if (value == 1 && amount > 0)
getOrCreateWidget().setValue(Integer.toString(amount));
else
getOrCreateWidget().setValue(Integer.toString(Math.max(1, Math.min(99999, value + amount))));
}
};
var button = new ButtonPanel(this, row_1, 0, 0, 40, 20, TranslatableComponent("otm.container.matter_panel.increase_by", 8));
button.bind(() -> input_amount.increase(8));
button.setDock(Dock.RIGHT);
button.setDockMargin(2, 0, 0, 0);
button = new ButtonPanel(this, row_1, 0, 0, 40, 20, TranslatableComponent("otm.container.matter_panel.increase_by", 64));
button.setDock(Dock.RIGHT);
button.bind(() -> input_amount.increase(64));
button.setDockMargin(2, 0, 0, 0);
button = new ButtonPanel(this, row_1, 0, 0, 40, 20, TranslatableComponent("otm.container.matter_panel.increase_by", 256));
button.setDock(Dock.RIGHT);
button.bind(() -> input_amount.increase(256));
button.setDockMargin(2, 0, 0, 0);
slot.setDock(Dock.LEFT);
slot.setDockMargin(0, 0, 4, 0);
input_amount.setDock(Dock.FILL);
button = new ButtonPanel(this, row_3, 0, 0, 40, 20, TranslatableComponent("otm.container.matter_panel.decrease_by", 8));
button.bind(() -> input_amount.increase(-8));
button.setDock(Dock.RIGHT);
button.setDockMargin(2, 0, 0, 0);
button = new ButtonPanel(this, row_3, 0, 0, 40, 20, TranslatableComponent("otm.container.matter_panel.decrease_by", 64));
button.setDock(Dock.RIGHT);
button.bind(() -> input_amount.increase(-64));
button.setDockMargin(2, 0, 0, 0);
button = new ButtonPanel(this, row_3, 0, 0, 40, 20, TranslatableComponent("otm.container.matter_panel.decrease_by", 256));
button.setDock(Dock.RIGHT);
button.bind(() -> input_amount.increase(-256));
button.setDockMargin(2, 0, 0, 0);
button = new ButtonPanel(this, row_4, 0, 0, 40, 20, TranslatableComponent("otm.container.matter_panel.cancel"));
button.setDock(Dock.RIGHT);
button.bind(pattern_frame::remove);
button.setDockMargin(2, 0, 0, 0);
button = new ButtonPanel(this, row_4, 0, 0, 82, 20, TranslatableComponent("otm.container.matter_panel.send"));
button.setDock(Dock.RIGHT);
button.bind(() -> {
int value = 1;
try {
value = Integer.parseInt(input_amount.getOrCreateWidget().getValue());
} catch (Exception ignored) {
}
MenuNetworkChannel.INSTANCE.sendToServer(new ReplicationRequestPacket(state, value));
pattern_frame.remove();
});
button.setDockMargin(2, 0, 0, 0);
addPanel(pattern_frame);
pattern_frame.toScreenCenter();
popup(pattern_frame);
}
}

View File

@ -4,6 +4,7 @@ import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.crafting.Recipe;
import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.item.crafting.RecipeType;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;
@ -35,8 +36,8 @@ public class MRecipes {
typesRegistry.register(MNames.PLATE_PRESS, () -> PLATE_PRESS);
}
public static void register() {
registry.register(FMLJavaModLoadingContext.get().getModEventBus());
typesRegistry.register(FMLJavaModLoadingContext.get().getModEventBus());
public static void register(IEventBus bus) {
registry.register(bus);
typesRegistry.register(bus);
}
}

View File

@ -1,213 +0,0 @@
@file:Suppress("unused")
package ru.dbotthepony.mc.otm
import com.google.common.collect.ImmutableList
import com.google.gson.JsonElement
import com.google.gson.JsonObject
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.core.Vec3i
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.LongArrayTag
import net.minecraft.nbt.Tag
import net.minecraft.world.Container
import net.minecraft.world.entity.Entity
import net.minecraft.world.item.ItemStack
import net.minecraft.world.phys.Vec3
import net.minecraftforge.common.util.LazyOptional
import net.minecraftforge.items.IItemHandler
import java.util.*
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
operator fun Direction.unaryMinus(): Direction = this.opposite
operator fun Vec3i.unaryMinus(): Vec3i = Vec3i(-x, -y, -z)
operator fun BlockPos.unaryMinus(): BlockPos = BlockPos(-x, -y, -z)
operator fun CompoundTag.set(index: String, value: Tag) = put(index, value)
operator fun CompoundTag.set(index: String, value: Int) = putInt(index, value)
operator fun CompoundTag.set(index: String, value: Byte) = putByte(index, value)
operator fun CompoundTag.set(index: String, value: Short) = putShort(index, value)
operator fun CompoundTag.set(index: String, value: Long) = putLong(index, value)
operator fun CompoundTag.set(index: String, value: Float) = putFloat(index, value)
operator fun CompoundTag.set(index: String, value: Double) = putDouble(index, value)
operator fun CompoundTag.set(index: String, value: String) = putString(index, value)
operator fun CompoundTag.set(index: String, value: Boolean) = putBoolean(index, value)
operator fun CompoundTag.set(index: String, value: ByteArray) = putByteArray(index, value)
operator fun CompoundTag.set(index: String, value: IntArray) = putIntArray(index, value)
operator fun CompoundTag.set(index: String, value: LongArray) = putLongArray(index, value)
@JvmInline
value class CompoundTagInt(val tag: CompoundTag) : ReadWriteProperty<Any, Int> {
override fun getValue(thisRef: Any, property: KProperty<*>) = tag.getInt(property.name)
override fun setValue(thisRef: Any, property: KProperty<*>, value: Int) = tag.putInt(property.name, value)
}
@JvmInline
value class CompoundTagLong(val tag: CompoundTag) : ReadWriteProperty<Any, Long> {
override fun getValue(thisRef: Any, property: KProperty<*>) = tag.getLong(property.name)
override fun setValue(thisRef: Any, property: KProperty<*>, value: Long) = tag.putLong(property.name, value)
}
@JvmInline
value class CompoundTagByte(val tag: CompoundTag) : ReadWriteProperty<Any, Byte> {
override fun getValue(thisRef: Any, property: KProperty<*>) = tag.getByte(property.name)
override fun setValue(thisRef: Any, property: KProperty<*>, value: Byte) = tag.putByte(property.name, value)
}
@JvmInline
value class CompoundTagShort(val tag: CompoundTag) : ReadWriteProperty<Any, Short> {
override fun getValue(thisRef: Any, property: KProperty<*>) = tag.getShort(property.name)
override fun setValue(thisRef: Any, property: KProperty<*>, value: Short) = tag.putShort(property.name, value)
}
@JvmInline
value class CompoundTagFloat(val tag: CompoundTag) : ReadWriteProperty<Any, Float> {
override fun getValue(thisRef: Any, property: KProperty<*>) = tag.getFloat(property.name)
override fun setValue(thisRef: Any, property: KProperty<*>, value: Float) = tag.putFloat(property.name, value)
}
@JvmInline
value class CompoundTagBoolean(val tag: CompoundTag) : ReadWriteProperty<Any, Boolean> {
override fun getValue(thisRef: Any, property: KProperty<*>) = tag.getBoolean(property.name)
override fun setValue(thisRef: Any, property: KProperty<*>, value: Boolean) = tag.putBoolean(property.name, value)
}
@JvmInline
value class CompoundTagDouble(val tag: CompoundTag) : ReadWriteProperty<Any, Double> {
override fun getValue(thisRef: Any, property: KProperty<*>) = tag.getDouble(property.name)
override fun setValue(thisRef: Any, property: KProperty<*>, value: Double) = tag.putDouble(property.name, value)
}
@JvmInline
value class CompoundTagString(val tag: CompoundTag) : ReadWriteProperty<Any, String> {
override fun getValue(thisRef: Any, property: KProperty<*>): String = tag.getString(property.name)
override fun setValue(thisRef: Any, property: KProperty<*>, value: String) = tag.putString(property.name, value)
}
val EMPTY_UUID = UUID(0L, 0L)
@JvmInline
value class CompoundTagUUID(val tag: CompoundTag) : ReadWriteProperty<Any, UUID> {
override fun getValue(thisRef: Any, property: KProperty<*>) = (tag.get(property.name) as LongArrayTag?)?.asLongArray?.let { UUID(it[0], it[1]) } ?: EMPTY_UUID
override fun setValue(thisRef: Any, property: KProperty<*>, value: UUID) = tag.putLongArray(property.name, longArrayOf(value.mostSignificantBits, value.leastSignificantBits))
}
val CompoundTag.ints get() = CompoundTagInt(this)
val CompoundTag.longs get() = CompoundTagLong(this)
val CompoundTag.bytes get() = CompoundTagByte(this)
val CompoundTag.shorts get() = CompoundTagShort(this)
val CompoundTag.floats get() = CompoundTagFloat(this)
val CompoundTag.doubles get() = CompoundTagDouble(this)
val CompoundTag.booleans get() = CompoundTagBoolean(this)
val CompoundTag.strings get() = CompoundTagString(this)
val CompoundTag.uuids get() = CompoundTagUUID(this)
operator fun Container.set(index: Int, value: ItemStack) = setItem(index, value)
operator fun Container.get(index: Int): ItemStack = getItem(index)
operator fun IItemHandler.get(index: Int): ItemStack = getStackInSlot(index)
operator fun JsonObject.set(s: String, value: JsonElement) = add(s, value)
inline fun CompoundTag.ifHas(s: String, consumer: (Tag) -> Unit) {
val tag = get(s)
if (tag != null) {
consumer(tag)
}
}
inline fun CompoundTag.ifHas(s: String, type: Byte, consumer: (Tag) -> Unit) {
val tag = get(s)
if (tag != null && tag.id == type) {
consumer(tag)
}
}
inline fun <reified T : Tag> CompoundTag.ifHas(s: String, type: Class<T>, consumer: (T) -> Unit) {
val tag = get(s)
if (tag != null && tag::class.java === type) {
consumer(tag as T)
}
}
fun <T> LazyOptional<T>.orNull(): T? {
if (!isPresent) {
return null
}
return resolve().orElse(null)
}
fun <T> LazyOptional<T>.orThrow(): T {
if (!isPresent) {
throw IllegalStateException("Capability was expected to be not null")
}
return resolve().orElse(null) ?: throw IllegalStateException("Capability was expected to be not null")
}
inline fun <T> LazyOptional<T>.ifPresentK(lambda: (T) -> Unit) {
if (isPresent) {
val value = resolve().orElse(null) ?: throw IllegalStateException("Capability was expected to be not null")
lambda.invoke(value)
}
}
val ItemStack.tagNotNull: CompoundTag get() = orCreateTag
inline var Entity.position: Vec3
get() = position()
set(value) { setPos(value) }
inline val <reified T : Enum<T>> T.next: T get() {
val values = enumValues<T>()
val next = (ordinal + 1) % values.size
return values[next]
}
inline val <reified T : Enum<T>> T.prev: T get() {
val values = enumValues<T>()
var next = ordinal - 1
if (next < 0) {
next = values.size - 1
}
return values[next]
}
fun <T : Enum<T>> T.next(values: Array<out T>): T {
val next = (ordinal + 1) % values.size
return values[next]
}
fun <T : Enum<T>> T.prev(values: Array<out T>): T {
var next = ordinal - 1
if (next < 0) {
next = values.size - 1
}
return values[next]
}
inline fun <T> ImmutableList(size: Int, initializer: (index: Int) -> T): ImmutableList<T> {
require(size >= 0) { "Invalid list size $size" }
return when (size) {
0 -> ImmutableList.of()
1 -> ImmutableList.of(initializer(0))
else -> ImmutableList.Builder<T>().let {
for (i in 0 until size) {
it.add(initializer(i))
}
it.build()
}
}
}

View File

@ -118,6 +118,8 @@ private var _server: MinecraftServer? = null
private var _serverThread: Thread? = null
private var _clientThread: Thread? = null
val isClient: Boolean get() = _clientThread !== null
fun recordClientThread() {
if (_clientThread != null) {
throw IllegalStateException("Already have client channel")
@ -127,13 +129,13 @@ fun recordClientThread() {
}
fun runIfClient(lambda: () -> Unit) {
if (_clientThread !== null) {
if (isClient) {
lambda.invoke()
}
}
fun <V> runIfClient(value: V, lambda: () -> V): V {
if (_clientThread !== null) {
if (isClient) {
return lambda.invoke()
}
@ -178,7 +180,6 @@ interface IConditionalTickable : ITickable {
val canTick: Boolean
}
@SubscribeEvent(priority = EventPriority.LOWEST)
fun onServerTick(event: ServerTickEvent) {
if (event.phase === TickEvent.Phase.START) {
preServerTickTimers.tick()
@ -253,7 +254,6 @@ fun addPostServerTickerOnce(ticker: ITickable) {
postServerTickOnce.add(ticker)
}
@SubscribeEvent(priority = EventPriority.LOWEST)
fun onWorldTick(event: LevelTickEvent) {
if (event.phase === TickEvent.Phase.START) {
val it = preWorldTick[event.level]
@ -353,7 +353,6 @@ private fun clear() {
postWorldTickOnce.clear()
}
@SubscribeEvent(priority = EventPriority.HIGHEST)
fun onServerStarting(event: ServerAboutToStartEvent) {
clear()
SERVER_IS_DYING = false
@ -361,13 +360,11 @@ fun onServerStarting(event: ServerAboutToStartEvent) {
_serverThread = Thread.currentThread()
}
@SubscribeEvent(priority = EventPriority.HIGHEST)
fun onServerStopping(event: ServerStoppingEvent) {
clear()
SERVER_IS_DYING = true
}
@SubscribeEvent(priority = EventPriority.HIGHEST)
fun onServerStopped(event: ServerStoppedEvent) {
if (!SERVER_IS_DYING) {
LOGGER.fatal("ServerStoppingEvent did not fire. If server has crashed this is normal. However, if server finished it's work 'gracefully' this is a bug.")

View File

@ -4,9 +4,10 @@ import net.minecraft.nbt.CompoundTag
import net.minecraftforge.common.util.INBTSerializable
import net.minecraftforge.event.entity.living.LivingHurtEvent
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.readNbt
import ru.dbotthepony.mc.otm.set
import ru.dbotthepony.mc.otm.writeNbt
import ru.dbotthepony.mc.otm.core.readNbt
import ru.dbotthepony.mc.otm.container.set
import ru.dbotthepony.mc.otm.core.set
import ru.dbotthepony.mc.otm.core.writeNbt
import java.io.InputStream
import java.io.OutputStream

View File

@ -5,7 +5,7 @@ import net.minecraft.network.chat.ComponentContents
import net.minecraft.network.chat.MutableComponent
import net.minecraft.network.chat.contents.TranslatableContents
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.getKeyNullable
import ru.dbotthepony.mc.otm.core.getKeyNullable
import ru.dbotthepony.mc.otm.registry.MRegistry
open class AndroidFeatureType<T : AndroidFeature> {

View File

@ -7,9 +7,10 @@ import net.minecraft.world.item.ItemStack
import net.minecraftforge.common.util.INBTSerializable
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.client.render.SkinElement
import ru.dbotthepony.mc.otm.readNbt
import ru.dbotthepony.mc.otm.set
import ru.dbotthepony.mc.otm.writeNbt
import ru.dbotthepony.mc.otm.core.readNbt
import ru.dbotthepony.mc.otm.container.set
import ru.dbotthepony.mc.otm.core.set
import ru.dbotthepony.mc.otm.core.writeNbt
import java.io.InputStream
import java.io.OutputStream

View File

@ -6,9 +6,10 @@ import net.minecraft.ChatFormatting
import net.minecraft.network.chat.Component
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.item.ItemStack
import ru.dbotthepony.mc.otm.TranslatableComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.client.render.SkinElement
import ru.dbotthepony.mc.otm.container.iterator
import ru.dbotthepony.mc.otm.core.nonEmpty
import ru.dbotthepony.mc.otm.registry.MRegistry
import kotlin.collections.ArrayList
@ -260,7 +261,7 @@ class AndroidResearchBuilder(
for (item in items) {
var required = item.count
val iterator = capability.ply.inventory.iterator()
val iterator = capability.ply.inventory.iterator().nonEmpty()
for (invItem in iterator) {
if (ItemStack.isSameItemSameTags(invItem, item)) {
@ -335,7 +336,8 @@ class AndroidResearchBuilder(
}
if (experience != 0) {
builder.add(TranslatableComponent("otm.android_station.research.xp_cost", experience).withStyle(
builder.add(
TranslatableComponent("otm.android_station.research.xp_cost", experience).withStyle(
if (capability.ply.experienceLevel >= experience)
ChatFormatting.DARK_GREEN
else
@ -346,7 +348,8 @@ class AndroidResearchBuilder(
for (value in this.type.flatPrerequisites) {
val instance = capability.getResearch(value)
builder.add(TranslatableComponent("android_research.status.requires", instance.screenTooltipHeader).withStyle(
builder.add(
TranslatableComponent("android_research.status.requires", instance.screenTooltipHeader).withStyle(
if (instance.isResearched)
ChatFormatting.DARK_GREEN
else

View File

@ -6,9 +6,9 @@ import net.minecraft.network.chat.Component
import net.minecraft.network.chat.ComponentContents
import net.minecraft.network.chat.MutableComponent
import net.minecraft.network.chat.contents.TranslatableContents
import ru.dbotthepony.mc.otm.TranslatableComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.getKeyNullable
import ru.dbotthepony.mc.otm.core.getKeyNullable
import ru.dbotthepony.mc.otm.registry.MRegistry
import java.util.*
import kotlin.collections.HashSet

View File

@ -9,7 +9,8 @@ import ru.dbotthepony.mc.otm.capability.extractEnergyInnerExact
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.registry.AndroidFeatures
import ru.dbotthepony.mc.otm.registry.StatNames
import ru.dbotthepony.mc.otm.set
import ru.dbotthepony.mc.otm.container.set
import ru.dbotthepony.mc.otm.core.set
import kotlin.math.roundToInt
class NanobotsArmor(android: MatteryPlayerCapability) : AndroidFeature(AndroidFeatures.NANOBOTS_ARMOR, android) {

View File

@ -8,7 +8,8 @@ import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.registry.AndroidFeatures
import ru.dbotthepony.mc.otm.registry.StatNames
import ru.dbotthepony.mc.otm.set
import ru.dbotthepony.mc.otm.container.set
import ru.dbotthepony.mc.otm.core.set
import kotlin.math.roundToInt
class NanobotsRegeneration(android: MatteryPlayerCapability) : AndroidFeature(AndroidFeatures.NANOBOTS_REGENERATION, android) {

View File

@ -16,7 +16,7 @@ import net.minecraft.world.phys.shapes.CollisionContext
import net.minecraft.world.phys.shapes.VoxelShape
import ru.dbotthepony.mc.otm.block.entity.AndroidStationBlockEntity
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.orNull
import ru.dbotthepony.mc.otm.core.orNull
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.shapes.BlockShapes

View File

@ -15,7 +15,7 @@ import net.minecraft.world.phys.shapes.CollisionContext
import net.minecraft.world.phys.shapes.VoxelShape
import ru.dbotthepony.mc.otm.addPreWorldTickerOnce
import ru.dbotthepony.mc.otm.block.entity.ChemicalGeneratorBlockEntity
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState
import ru.dbotthepony.mc.otm.block.entity.WorkerState
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.shapes.BlockShapes

View File

@ -25,7 +25,7 @@ import net.minecraft.world.phys.shapes.VoxelShape
import ru.dbotthepony.mc.otm.addPreWorldTickerOnce
import ru.dbotthepony.mc.otm.block.entity.GravitationStabilizerBlockEntity
import ru.dbotthepony.mc.otm.block.entity.blackhole.BlackHoleBlockEntity
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState
import ru.dbotthepony.mc.otm.block.entity.WorkerState
import ru.dbotthepony.mc.otm.core.plus
import ru.dbotthepony.mc.otm.core.times
import ru.dbotthepony.mc.otm.registry.MBlockEntities

View File

@ -14,7 +14,7 @@ import net.minecraft.world.level.block.state.StateDefinition
import net.minecraft.world.phys.shapes.CollisionContext
import net.minecraft.world.phys.shapes.VoxelShape
import ru.dbotthepony.mc.otm.block.entity.PlatePressBlockEntity
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState
import ru.dbotthepony.mc.otm.block.entity.WorkerState
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.shapes.BlockShapes

View File

@ -9,7 +9,7 @@ import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.phys.AABB
import ru.dbotthepony.mc.otm.TranslatableComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.core.ImpreciseFraction

View File

@ -22,7 +22,7 @@ import ru.dbotthepony.mc.otm.block.BatteryBankBlock
import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock
import ru.dbotthepony.mc.otm.capability.*
import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.core.*
import ru.dbotthepony.mc.otm.menu.BatteryBankMenu
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import javax.annotation.ParametersAreNonnullByDefault

View File

@ -12,13 +12,13 @@ import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.capabilities.Capability
import net.minecraftforge.common.capabilities.ForgeCapabilities
import net.minecraftforge.common.util.LazyOptional
import ru.dbotthepony.mc.otm.TranslatableComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.block.CargoCrateBlock
import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.ifHas
import ru.dbotthepony.mc.otm.menu.CargoCrateMenu
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.set
import ru.dbotthepony.mc.otm.container.set
import ru.dbotthepony.mc.otm.core.set
class CargoCrateBlockEntity(
p_155229_: BlockPos,

View File

@ -19,11 +19,9 @@ import net.minecraftforge.common.util.LazyOptional
import net.minecraftforge.energy.IEnergyStorage
import ru.dbotthepony.mc.otm.*
import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState
import ru.dbotthepony.mc.otm.capability.*
import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.core.plus
import ru.dbotthepony.mc.otm.core.*
import ru.dbotthepony.mc.otm.menu.ChemicalGeneratorMenu
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import java.lang.ref.WeakReference

View File

@ -25,7 +25,7 @@ import ru.dbotthepony.mc.otm.*
import ru.dbotthepony.mc.otm.block.EnergyCounterBlock
import ru.dbotthepony.mc.otm.capability.*
import ru.dbotthepony.mc.otm.compat.mekanism.MatteryToMekanismEnergyWrapper
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.core.*
import ru.dbotthepony.mc.otm.menu.EnergyCounterMenu
import ru.dbotthepony.mc.otm.network.MatteryPacket
import ru.dbotthepony.mc.otm.network.WorldNetworkChannel

View File

@ -9,12 +9,11 @@ import net.minecraft.world.level.Level
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.phys.AABB
import ru.dbotthepony.mc.otm.TranslatableComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.block.BlockGravitationStabilizer
import ru.dbotthepony.mc.otm.block.BlockGravitationStabilizerLens
import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock
import ru.dbotthepony.mc.otm.block.entity.blackhole.BlackHoleBlockEntity
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState
import ru.dbotthepony.mc.otm.core.plus
import ru.dbotthepony.mc.otm.core.times
import ru.dbotthepony.mc.otm.registry.MBlockEntities

View File

@ -23,8 +23,9 @@ import net.minecraft.network.chat.Component
import net.minecraft.world.level.Level
import net.minecraftforge.common.capabilities.Capability
import ru.dbotthepony.mc.otm.addPreWorldTickerOnce
import ru.dbotthepony.mc.otm.ifHas
import ru.dbotthepony.mc.otm.set
import ru.dbotthepony.mc.otm.core.ifHas
import ru.dbotthepony.mc.otm.container.set
import ru.dbotthepony.mc.otm.core.set
abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: BlockPos, p_155230_: BlockState) : BlockEntity(p_155228_, p_155229_, p_155230_), MenuProvider {
var customDisplayName: Component? = null

View File

@ -8,13 +8,13 @@ import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.capabilities.Capability
import net.minecraftforge.common.capabilities.ForgeCapabilities
import net.minecraftforge.common.util.LazyOptional
import net.minecraftforge.energy.CapabilityEnergy
import ru.dbotthepony.mc.otm.capability.*
import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.ifHas
import ru.dbotthepony.mc.otm.ifPresentK
import ru.dbotthepony.mc.otm.set
import ru.dbotthepony.mc.otm.core.ifHas
import ru.dbotthepony.mc.otm.core.ifPresentK
import ru.dbotthepony.mc.otm.container.set
import ru.dbotthepony.mc.otm.core.set
abstract class MatteryPoweredBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: BlockPos, p_155230_: BlockState) : MatteryBlockEntity(p_155228_, p_155229_, p_155230_) {
abstract val energy: BlockEnergyStorageImpl

View File

@ -0,0 +1,342 @@
package ru.dbotthepony.mc.otm.block.entity
import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.core.BlockPos
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.nbt.CompoundTag
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.block.Block
import ru.dbotthepony.mc.otm.core.*
import ru.dbotthepony.mc.otm.core.map
private fun isReason(status: Any?, reason: Any) = status == null || status == reason
abstract class MatteryWorkerBlockEntity<JobType : MatteryWorkerBlockEntity.Job>(
type: BlockEntityType<*>,
blockPos: BlockPos,
blockState: BlockState,
val jobDeserializer: (tag: CompoundTag) -> JobType?
) : MatteryPoweredBlockEntity(type, blockPos, blockState) {
open class Job(
open val ticks: Double,
open val powerUsage: ImpreciseFraction = ImpreciseFraction.ZERO
) {
constructor(
tag: CompoundTag
) : this(tag.getDouble("ticks"), tag.getImpreciseFraction("power"))
open fun serializeNBT(): CompoundTag {
return CompoundTag().also {
it["ticks"] = ticks
it["power"] = powerUsage
}
}
}
@Suppress("LeakingThis")
open class ItemJob : Job {
open val itemStack: ItemStack
constructor(
itemStack: ItemStack,
ticks: Double,
power: ImpreciseFraction = ImpreciseFraction.ZERO
) : super(ticks, power) {
this.itemStack = itemStack
}
constructor(
tag: CompoundTag
) : super(tag) {
this.itemStack = (tag["item"] as? CompoundTag)?.let { ItemStack.of(it) } ?: ItemStack.EMPTY
}
override fun serializeNBT(): CompoundTag {
return super.serializeNBT().also {
it["item"] = itemStack.serializeNBT()
}
}
}
enum class IdleReason {
ITEM,
POWER,
MATTER,
/**
* Observing external factor, such as waiting for matter/item network tasks
*/
OBSERVING
}
data class Status(val success: Boolean, val throttleTicks: Int = 0, val idleReason: IdleReason? = null) {
companion object {
val SUCCESS = Status(true)
val FAILURE = Status(false)
val FAILURE_ITEM = Status(false, 20, IdleReason.ITEM)
val FAILURE_MATTER = Status(false, 20, IdleReason.MATTER)
val FAILURE_WAIT = Status(false, 100)
val FAILURE_WAIT_FAST = Status(false, 20)
}
}
var workTicks = 0.0
protected set
var throttleTicks = 0
protected set
var currentJob: JobType? = null
protected set
/**
* Can be whatever you want, but [IdleReason] certainly contains all cases
*/
var idleReason: Any? = null
private set
var isIdling = false
protected set
val isUnableToProcess: Boolean get() = throttleTicks > 0
val workProgress: Float
get() {
val currentJob = currentJob ?: return 0.0f
return (workTicks / currentJob.ticks).coerceAtMost(1.0).toFloat()
}
override fun saveAdditional(nbt: CompoundTag) {
super.saveAdditional(nbt)
nbt["work_ticks"] = workTicks
currentJob?.let { nbt["job"] = it.serializeNBT() }
}
override fun load(nbt: CompoundTag) {
super.load(nbt)
workTicks = nbt.getDouble("work_ticks")
currentJob = nbt.map("job", jobDeserializer::invoke)
if (currentJob == null)
workTicks = 0.0
}
override fun setChanged() {
super.setChanged()
isIdling = false
}
override fun setChangedLight() {
super.setChangedLight()
isIdling = false
}
protected fun powerLevelUpdated() {
super.setChangedLight()
if (isReason(idleReason, IdleReason.POWER)) {
isIdling = false
throttleTicks = 0
}
}
protected fun itemContainerUpdated() {
super.setChanged()
if (isReason(idleReason, IdleReason.ITEM)) {
isIdling = false
throttleTicks = 0
}
}
protected fun matterLevelUpdated() {
super.setChangedLight()
if (isReason(idleReason, IdleReason.MATTER)) {
isIdling = false
throttleTicks = 0
}
}
/**
* Called whenever reaching desired amount of ticks at job
*/
protected abstract fun onJobFinish(job: JobType): Status
/**
* [Pair.second] is reason why job can't be performed
*
* If not null, it is written to [idleReason]
*/
protected abstract fun computeNextJob(): Pair<JobType?, Any?>
protected open fun onWorkTick(requiredPower: ImpreciseFraction, extractedPower: ImpreciseFraction, ticksAdvanced: Double): Status {
return Status.SUCCESS
}
private var idleTicksAnim = 0
private var workingTicksAnim = 0
private var errorTicksAnim = 0
override fun redstoneStatusUpdated(new_blocked: Boolean, old_blocked: Boolean) {
super.redstoneStatusUpdated(new_blocked, old_blocked)
isIdling = new_blocked
}
protected fun workerLoop() {
if (errorTicksAnim > 20 && blockState.hasProperty(WorkerState.WORKER_STATE) && blockState.getValue(WorkerState.WORKER_STATE) != WorkerState.ERROR) {
level?.setBlock(blockPos, blockState.setValue(WorkerState.WORKER_STATE, WorkerState.ERROR), Block.UPDATE_CLIENTS)
}
if (throttleTicks > 0) {
workingTicksAnim = 0
idleTicksAnim = 0
throttleTicks--
errorTicksAnim++
if (throttleTicks > 0)
return
else
isIdling = false
}
if (isIdling) {
workingTicksAnim = 0
errorTicksAnim = 0
idleTicksAnim++
if (idleTicksAnim > 20 && blockState.hasProperty(WorkerState.WORKER_STATE) && blockState.getValue(
WorkerState.WORKER_STATE
) != WorkerState.IDLE
) {
level?.setBlock(blockPos, blockState.setValue(WorkerState.WORKER_STATE, WorkerState.IDLE), Block.UPDATE_CLIENTS)
}
return
}
var availableTicks = 1.0
while (!isIdling && weakGreaterThan(availableTicks, 0.0)) {
if (isBlockedByRedstone) {
isIdling = true
break
}
var currentJob = currentJob
if (currentJob == null) {
if (isBlockedByRedstone) {
isIdling = true
break
}
val (job, reason) = computeNextJob()
if (job == null) {
idleReason = reason
isIdling = reason != null
workingTicksAnim = 0
break
}
this.currentJob = job
currentJob = job
}
if (!currentJob.powerUsage.isZero && energy.batteryLevel.isZero) {
idleReason = IdleReason.POWER
isIdling = true
idleTicksAnim++
if (idleTicksAnim > 20 && blockState.hasProperty(WorkerState.WORKER_STATE) && blockState.getValue(
WorkerState.WORKER_STATE
) != WorkerState.IDLE
) {
level?.setBlock(blockPos, blockState.setValue(WorkerState.WORKER_STATE, WorkerState.IDLE), Block.UPDATE_CLIENTS)
}
break
}
idleTicksAnim = 0
if (weakLessThan(workTicks, currentJob.ticks)) {
val ticksLeft = currentJob.ticks - workTicks
val ticksAdvanced: Double
var requiredPower: ImpreciseFraction? = null
var extractedPower: ImpreciseFraction? = null
if (currentJob.powerUsage.isZero) {
ticksAdvanced = availableTicks.coerceAtMost(ticksLeft)
} else {
requiredPower = currentJob.powerUsage * ticksLeft.coerceAtMost(availableTicks)
extractedPower = energy.extractEnergyInner(requiredPower, true)
ticksAdvanced = (extractedPower / requiredPower).toDouble().coerceAtMost(ticksLeft).coerceAtMost(availableTicks)
}
if (weakEqualDoubles(ticksAdvanced, 0.0)) {
break
}
val status = onWorkTick(requiredPower ?: ImpreciseFraction.ZERO, extractedPower ?: ImpreciseFraction.ZERO, ticksAdvanced)
if (!status.success) {
throttleTicks += status.throttleTicks
if (status.idleReason != null) {
idleReason = status.idleReason
isIdling = true
}
break
}
workingTicksAnim++
errorTicksAnim = 0
workTicks += ticksAdvanced
availableTicks -= ticksAdvanced
if (extractedPower != null) {
energy.extractEnergyInner(extractedPower, false)
}
continue
}
val status = onJobFinish(currentJob)
if (status.success) {
this.currentJob = null
workTicks = 0.0
errorTicksAnim = 0
} else {
throttleTicks += status.throttleTicks
if (status.idleReason != null) {
idleReason = status.idleReason
isIdling = true
}
errorTicksAnim++
}
}
if (workingTicksAnim > 20 &&
errorTicksAnim == 0 &&
blockState.hasProperty(WorkerState.WORKER_STATE) &&
blockState.getValue(WorkerState.WORKER_STATE) != WorkerState.WORKING
)
{
level?.setBlock(blockPos, blockState.setValue(WorkerState.WORKER_STATE, WorkerState.WORKING), Block.UPDATE_CLIENTS)
}
}
fun basicTicker() {
batteryChargeLoop()
workerLoop()
}
}

View File

@ -1,5 +1,6 @@
package ru.dbotthepony.mc.otm.block.entity
import com.google.common.collect.Streams
import javax.annotation.ParametersAreNonnullByDefault
import net.minecraft.core.BlockPos
import net.minecraft.world.level.block.state.BlockState
@ -9,7 +10,6 @@ import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.block.matter.PatternStorageBlock
import net.minecraft.nbt.CompoundTag
import net.minecraftforge.common.util.LazyOptional
import net.minecraftforge.items.CapabilityItemHandler
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu
@ -21,15 +21,19 @@ import net.minecraft.server.level.ServerLevel
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.Block
import net.minecraftforge.common.capabilities.Capability
import ru.dbotthepony.mc.otm.TranslatableComponent
import net.minecraftforge.common.capabilities.ForgeCapabilities
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.capability.matter.*
import ru.dbotthepony.mc.otm.container.forEachCapability
import ru.dbotthepony.mc.otm.core.iterator
import ru.dbotthepony.mc.otm.graph.Graph6Node
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode
import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph
import ru.dbotthepony.mc.otm.ifHas
import ru.dbotthepony.mc.otm.core.ifHas
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.set
import ru.dbotthepony.mc.otm.core.set
import java.util.ArrayList
import java.util.stream.Stream
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
@ -48,13 +52,13 @@ class PatternStorageBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
if (grid != null && !ItemStack.isSameItemSameTags(new, old)) {
if (!old.isEmpty) {
old.getCapability(MatteryCapability.PATTERN).ifPresent { cap: IPatternStorage ->
cap.storedPatterns.forEach { state: PatternState? -> grid.onPatternRemoved(state!!) }
cap.storedPatterns.forEach { grid.onPatternRemoved(it) }
}
}
if (!new.isEmpty) {
new.getCapability(MatteryCapability.PATTERN).ifPresent { cap: IPatternStorage ->
cap.storedPatterns.forEach { state: PatternState? -> grid.onPatternAdded(state!!) }
cap.storedPatterns.forEach { grid.onPatternAdded(it) }
}
}
@ -130,9 +134,9 @@ class PatternStorageBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
override fun <T> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
if (valid) {
if (cap === MatteryCapability.PATTERN) return resolverPatterns.cast()
if (cap === MatteryCapability.MATTER_NODE) return resolverNode.cast()
if (cap === CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) return resolverItem.get().cast()
if (cap == MatteryCapability.PATTERN) return resolverPatterns.cast()
if (cap == MatteryCapability.MATTER_NODE) return resolverNode.cast()
if (cap == ForgeCapabilities.ITEM_HANDLER) return resolverItem.get().cast()
}
return super.getCapability(cap, side)
@ -145,16 +149,20 @@ class PatternStorageBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
return PatternStorageMenu(containerID, inventory, this)
}
override val storedPatterns: Collection<PatternState> get() {
val list = ArrayList<PatternState>()
patterns.consumeCapability(MatteryCapability.PATTERN) { capability: IPatternStorage -> list.addAll(capability.storedPatterns) }
return list
override val storedPatterns: Stream<out IPatternState> get() {
val streams = ArrayList<Stream<out IPatternState>>()
for (provider in patterns.iterator(MatteryCapability.PATTERN)) {
streams.add(provider.second.storedPatterns)
}
return Streams.concat(*streams.toTypedArray())
}
override val capacity: Int get() {
var stored = 0L
for (pattern in patterns.capabilityIterator(MatteryCapability.PATTERN))
for ((_, pattern) in patterns.iterator(MatteryCapability.PATTERN))
stored += pattern.capacity.toLong()
return if (stored > Int.MAX_VALUE) Int.MAX_VALUE else stored.toInt()
@ -163,7 +171,7 @@ class PatternStorageBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
override val stored: Int get() {
var stored = 0L
for (pattern in patterns.capabilityIterator(MatteryCapability.PATTERN))
for ((_, pattern) in patterns.iterator(MatteryCapability.PATTERN))
stored += pattern.stored.toLong()
return if (stored > Int.MAX_VALUE) Int.MAX_VALUE else stored.toInt()
@ -174,9 +182,9 @@ class PatternStorageBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
matterNode.destroy(::MatterNetworkGraph)
}
override fun insertPattern(pattern: PatternState, only_update: Boolean, simulate: Boolean): PatternInsertStatus {
for (storage in patterns.capabilityIterator(MatteryCapability.PATTERN)) {
val status = storage.insertPattern(pattern, only_update, simulate)
override fun insertPattern(pattern: IPatternState, onlyUpdate: Boolean, simulate: Boolean): PatternInsertStatus {
for (pair in patterns.iterator(MatteryCapability.PATTERN)) {
val status = pair.second.insertPattern(pattern, onlyUpdate, simulate)
if (!status.isFailed) {
if (!simulate) {

View File

@ -10,12 +10,9 @@ import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.capabilities.Capability
import net.minecraftforge.common.capabilities.ForgeCapabilities
import net.minecraftforge.common.util.LazyOptional
import net.minecraftforge.items.CapabilityItemHandler
import ru.dbotthepony.mc.otm.TranslatableComponent
import ru.dbotthepony.mc.otm.block.entity.worker.MatteryWorkerBlockEntity
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerJob
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerJobStatus
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.capability.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.container.MatteryContainerFilter
@ -23,9 +20,13 @@ import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.menu.PlatePressMenu
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.registry.MRecipes
import ru.dbotthepony.mc.otm.set
import ru.dbotthepony.mc.otm.container.set
import ru.dbotthepony.mc.otm.core.set
class PlatePressBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryWorkerBlockEntity(MBlockEntities.PLATE_PRESS, p_155229_, p_155230_) {
class PlatePressBlockEntity(
p_155229_: BlockPos,
p_155230_: BlockState
) : MatteryWorkerBlockEntity<MatteryWorkerBlockEntity.ItemJob>(MBlockEntities.PLATE_PRESS, p_155229_, p_155230_, ::ItemJob) {
val container = MatteryContainer(this::setChangedLight, 2)
override val energy = WorkerEnergyStorage(this::setChangedLight)
@ -50,7 +51,7 @@ class PlatePressBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Matter
}
override fun <T> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
if (cap === CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
if (cap == ForgeCapabilities.ITEM_HANDLER)
return itemHandler.get().cast()
return super.getCapability(cap, side)
@ -73,32 +74,24 @@ class PlatePressBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Matter
return PlatePressMenu(containerID, inventory, this)
}
override fun onJobFinish(job: WorkerJob): WorkerJobStatus {
val resultTag = job.data["result"] as? CompoundTag ?: return WorkerJobStatus()
val result = ItemStack.of(resultTag)
override fun onJobFinish(job: ItemJob): Status {
if (job.itemStack.isEmpty)
return Status.SUCCESS
if (result.isEmpty)
return WorkerJobStatus()
if (!container.fullyAddItem(job.itemStack, start = SLOT_OUTPUT, end = SLOT_OUTPUT))
return Status.FAILURE_ITEM
if (!container.fullyAddItem(result, start = SLOT_OUTPUT, end = SLOT_OUTPUT)) {
return WorkerJobStatus(false, 20)
}
return WorkerJobStatus()
return Status.SUCCESS
}
override fun computeNextJob(): WorkerJob? {
val level = level ?: return null
val recipe = level.recipeManager.getRecipeFor(MRecipes.PLATE_PRESS, container, level).orElse(null) ?: return null
override fun computeNextJob(): Pair<ItemJob?, IdleReason?> {
if (energy.batteryLevel.isZero) {
return null to IdleReason.POWER
}
val copy = container[SLOT_INPUT].copy()
val recipe = level?.recipeManager?.getRecipeFor(MRecipes.PLATE_PRESS, container, level!!)?.orElse(null) ?: return null to IdleReason.ITEM
container[SLOT_INPUT].shrink(1)
container.setChanged(SLOT_INPUT)
copy.count = 1
return WorkerJob(copy, recipe.workTime.toDouble(), BASELINE_CONSUMPTION, CompoundTag().also {
it["result"] = recipe.resultItem.serializeNBT()
})
return ItemJob(recipe.resultItem, recipe.workTime.toDouble(), BASELINE_CONSUMPTION) to null
}
companion object {

View File

@ -1,7 +1,7 @@
package ru.dbotthepony.mc.otm.block.entity
import net.minecraft.network.chat.Component
import ru.dbotthepony.mc.otm.TranslatableComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
enum class RedstoneSetting(val label: Component, val description: Component) {
IGNORED(TranslatableComponent("otm.gui.redstone.ignored"), TranslatableComponent("otm.gui.redstone.ignored.description")),

View File

@ -0,0 +1,21 @@
package ru.dbotthepony.mc.otm.block.entity
import net.minecraft.util.StringRepresentable
import net.minecraft.world.level.block.state.properties.EnumProperty
enum class WorkerState : StringRepresentable {
IDLE,
WORKING,
ERROR;
companion object {
@JvmField
val WORKER_STATE: EnumProperty<WorkerState> = EnumProperty.create("worker", WorkerState::class.java)
@JvmField
val SEMI_WORKER_STATE: EnumProperty<WorkerState> = EnumProperty.create("worker", WorkerState::class.java, IDLE, WORKING)
}
override fun getSerializedName(): String {
return if (this == IDLE) "idle" else if (this == WORKING) "working" else "error"
}
}

View File

@ -31,7 +31,8 @@ import ru.dbotthepony.mc.otm.matter.getMatterValue
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.registry.MItems
import ru.dbotthepony.mc.otm.registry.MRegistry
import ru.dbotthepony.mc.otm.set
import ru.dbotthepony.mc.otm.container.set
import ru.dbotthepony.mc.otm.core.set
import kotlin.math.roundToInt
import kotlin.math.sqrt

View File

@ -23,7 +23,6 @@ import ru.dbotthepony.mc.otm.block.BlockExplosionDebugger
import ru.dbotthepony.mc.otm.core.*
import ru.dbotthepony.mc.otm.core.Vector
import ru.dbotthepony.mc.otm.registry.MRegistry
import ru.dbotthepony.mc.otm.set
import java.util.*
import kotlin.collections.ArrayList
import kotlin.collections.HashMap

View File

@ -15,25 +15,22 @@ import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.capabilities.Capability
import net.minecraftforge.common.util.LazyOptional
import net.minecraftforge.items.CapabilityItemHandler
import ru.dbotthepony.mc.otm.TranslatableComponent
import ru.dbotthepony.mc.otm.block.matter.MatterBottlerBlock
import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState
import ru.dbotthepony.mc.otm.block.entity.WorkerState
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler
import ru.dbotthepony.mc.otm.capability.matter.MatterDirection
import ru.dbotthepony.mc.otm.capability.matter.MatterHandlerImpl
import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.graph.Graph6Node
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode
import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph
import ru.dbotthepony.mc.otm.ifHas
import ru.dbotthepony.mc.otm.menu.MatterBottlerMenu
import ru.dbotthepony.mc.otm.orNull
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.set
import ru.dbotthepony.mc.otm.container.set
import ru.dbotthepony.mc.otm.core.*
class MatterBottlerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
MatteryPoweredBlockEntity(MBlockEntities.MATTER_BOTTLER, p_155229_, p_155230_), IMatterGraphNode {

View File

@ -15,7 +15,7 @@ import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.capabilities.Capability
import net.minecraftforge.common.util.LazyOptional
import ru.dbotthepony.mc.otm.TranslatableComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.block.BatteryBankBlock
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
import ru.dbotthepony.mc.otm.capability.MatteryCapability
@ -28,7 +28,8 @@ import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode
import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph
import ru.dbotthepony.mc.otm.menu.MatterCapacitorBankMenu
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.set
import ru.dbotthepony.mc.otm.container.set
import ru.dbotthepony.mc.otm.core.set
import javax.annotation.ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault

View File

@ -12,24 +12,22 @@ import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.capabilities.Capability
import net.minecraftforge.common.capabilities.ForgeCapabilities
import net.minecraftforge.common.util.LazyOptional
import net.minecraftforge.items.CapabilityItemHandler
import net.minecraftforge.items.IItemHandler
import ru.dbotthepony.mc.otm.TranslatableComponent
import ru.dbotthepony.mc.otm.block.entity.worker.MatteryWorkerBlockEntity
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerJob
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerJobStatus
import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler
import ru.dbotthepony.mc.otm.capability.matter.MatterDirection
import ru.dbotthepony.mc.otm.capability.matter.MatterHandlerImpl
import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.container.MatteryContainerFilter
import ru.dbotthepony.mc.otm.container.set
import ru.dbotthepony.mc.otm.core.*
import ru.dbotthepony.mc.otm.graph.Graph6Node
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode
import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph
import ru.dbotthepony.mc.otm.ifHas
import ru.dbotthepony.mc.otm.item.MatterDustItem
import ru.dbotthepony.mc.otm.matter.baselineComplexityDecomposeTicks
import ru.dbotthepony.mc.otm.matter.canDecompose
@ -37,7 +35,6 @@ import ru.dbotthepony.mc.otm.matter.getMatterValue
import ru.dbotthepony.mc.otm.menu.MatterDecomposerMenu
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.registry.MItems
import ru.dbotthepony.mc.otm.set
fun moveMatterAsDustIntoContainer(_matterValue: ImpreciseFraction, container: MatteryContainer, OUTPUT_DUST_MAIN: Int, OUTPUT_DUST_STACKING: Int): ImpreciseFraction {
var matterValue = _matterValue
@ -93,7 +90,29 @@ fun moveMatterAsDustIntoContainer(_matterValue: ImpreciseFraction, container: Ma
}
class MatterDecomposerBlockEntity(pos: BlockPos, state: BlockState)
: MatteryWorkerBlockEntity(MBlockEntities.MATTER_DECOMPOSER, pos, state), IMatterGraphNode {
: MatteryWorkerBlockEntity<MatterDecomposerBlockEntity.DecomposerJob>(MBlockEntities.MATTER_DECOMPOSER, pos, state, ::DecomposerJob), IMatterGraphNode {
class DecomposerJob : Job {
val toDust: Boolean
var matterValue: ImpreciseFraction
constructor(tag: CompoundTag) : super(tag) {
toDust = tag.getBoolean("to_dust")
matterValue = tag.getImpreciseFraction("value")
}
constructor(toDust: Boolean, matterValue: ImpreciseFraction, ticks: Double) : super(ticks, BASE_CONSUMPTION) {
this.toDust = toDust
this.matterValue = matterValue
}
override fun serializeNBT(): CompoundTag {
return super.serializeNBT().also {
it["to_dust"] = toDust
it["value"] = matterValue
}
}
}
override val energy = WorkerEnergyStorage(this, ENERGY_STORAGE, MAX_IO)
private var valid = true
@ -110,13 +129,18 @@ class MatterDecomposerBlockEntity(pos: BlockPos, state: BlockState)
private var resolverNode = LazyOptional.of { this }
// вход, выход
@JvmField
val container = MatteryContainer(this::setChangedLight, 3)
private val itemHandler = LazyOptional.of<IItemHandler> {
container.handler(
{ slot: Int, stack: ItemStack -> slot == INPUT_SLOT && canDecompose(stack) },
{ slot: Int, _: Int, _: ItemStack -> slot != INPUT_SLOT })
container.handler(object : MatteryContainerFilter {
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
return slot == INPUT_SLOT && canDecompose(stack)
}
override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean {
return slot != INPUT_SLOT
}
})
}
override val defaultDisplayName: Component
@ -156,39 +180,35 @@ class MatterDecomposerBlockEntity(pos: BlockPos, state: BlockState)
override fun <T> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
if (valid) {
if (cap === MatteryCapability.MATTER) return resolverMatter.cast()
if (cap === MatteryCapability.MATTER_NODE) return resolverNode.cast()
if (cap === CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) return itemHandler.cast()
if (cap == MatteryCapability.MATTER) return resolverMatter.cast()
if (cap == MatteryCapability.MATTER_NODE) return resolverNode.cast()
if (cap == ForgeCapabilities.ITEM_HANDLER) return itemHandler.cast()
}
return super.getCapability(cap, side)
}
override fun onJobFinish(job: WorkerJob): WorkerJobStatus {
var matterValue = ImpreciseFraction.deserializeNBT(job.data["value"])
override fun onJobFinish(job: DecomposerJob): Status {
if (job.toDust) {
job.matterValue = moveMatterAsDustIntoContainer(job.matterValue, container, OUTPUT_DUST_MAIN, OUTPUT_DUST_STACKING)
if (job.data.getBoolean("to_dust")) {
matterValue = moveMatterAsDustIntoContainer(matterValue, container, OUTPUT_DUST_MAIN, OUTPUT_DUST_STACKING)
if (!matterValue.isZero) {
job.data["value"] = matterValue.serializeNBT()
return WorkerJobStatus(20)
if (!job.matterValue.isZero) {
return Status.FAILURE_WAIT_FAST
}
return WorkerJobStatus()
return Status.SUCCESS
}
matterValue -= matter.receiveMatterInner(matterValue, false)
job.matterValue -= matter.receiveMatterInner(job.matterValue, false)
if (matterValue.isPositive) {
job.data["value"] = matterValue.serializeNBT()
return WorkerJobStatus(false, 20)
if (job.matterValue.isPositive) {
return Status.FAILURE_MATTER
}
return WorkerJobStatus()
return Status.SUCCESS
}
override fun computeNextJob(): WorkerJob? {
override fun computeNextJob(): Pair<DecomposerJob?, IdleReason?> {
val stack = container[INPUT_SLOT]
if (!stack.isEmpty) {
@ -197,19 +217,13 @@ class MatterDecomposerBlockEntity(pos: BlockPos, state: BlockState)
if (canDecompose(copy)) {
val matter = getMatterValue(copy)
stack.count--
if (!matter.isZero) {
stack.count--
return WorkerJob(copy, matter.complexity * baselineComplexityDecomposeTicks, BASE_CONSUMPTION, CompoundTag().also {
it["to_dust"] = (level?.random?.nextDouble() ?: 1.0) <= 0.2
it["value"] = matter.value.serializeNBT()
})
}
return DecomposerJob((level?.random?.nextDouble() ?: 1.0) <= 0.2, matter.value, matter.complexity * baselineComplexityDecomposeTicks) to null
}
}
return null
return null to IdleReason.ITEM
}
override fun setRemoved() {

View File

@ -3,7 +3,6 @@ package ru.dbotthepony.mc.otm.block.entity.matter
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.world.level.block.state.BlockState
import ru.dbotthepony.mc.otm.capability.matter.IMatterTaskProvider
import ru.dbotthepony.mc.otm.menu.MatterPanelMenu
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player
@ -12,10 +11,6 @@ import net.minecraftforge.common.util.LazyOptional
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import java.util.HashMap
import java.util.UUID
import ru.dbotthepony.mc.otm.capability.matter.MatterTask
import java.util.stream.Collectors
import ru.dbotthepony.mc.otm.capability.matter.MatterTaskAllocation
import ru.dbotthepony.mc.otm.capability.matter.PatternState
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag
import net.minecraft.nbt.Tag
@ -23,17 +18,18 @@ import net.minecraft.network.chat.Component
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.level.Level
import net.minecraftforge.common.capabilities.Capability
import ru.dbotthepony.mc.otm.TranslatableComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
import ru.dbotthepony.mc.otm.capability.matter.*
import ru.dbotthepony.mc.otm.graph.Graph6Node
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode
import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import java.util.ArrayList
import java.util.List
import java.util.stream.Stream
class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
MatteryBlockEntity(MBlockEntities.MATTER_PANEL, p_155229_, p_155230_), IMatterGraphNode, IMatterTaskProvider {
MatteryBlockEntity(MBlockEntities.MATTER_PANEL, p_155229_, p_155230_), IMatterGraphNode, IReplicationTaskProvider {
private val listeners = ArrayList<MatterPanelMenu>()
override val matterNode = Graph6Node<IMatterGraphNode>(this)
@ -88,61 +84,59 @@ class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
matterNode.destroy(::MatterNetworkGraph)
}
override fun getTaskHandler(): IMatterTaskProvider? {
override fun getTaskHandler(): IReplicationTaskProvider {
return this
}
private val _tasks = HashMap<UUID, MatterTask>()
private val _tasks = HashMap<UUID, ReplicationTask>()
override val tasks: Collection<MatterTask> get() {
return _tasks.values.stream().filter { task: MatterTask? -> task!!.required() > 0 }.collect(Collectors.toList()) as Collection<MatterTask>
override val replicationTasks: Stream<ReplicationTask> get() {
return _tasks.values.stream().filter { it.required > 0 }
}
override val allTasks: Collection<MatterTask> get() {
return List.copyOf(_tasks.values) as Collection<MatterTask>
override val allReplicationTasks: Stream<ReplicationTask> get() {
return _tasks.values.stream()
}
override fun allocateTask(simulate: Boolean): MatterTaskAllocation? {
override fun allocateTask(simulate: Boolean): ReplicationTaskAllocation? {
val graph = matterNode.graph as MatterNetworkGraph? ?: return null
for ((key, task) in _tasks) {
if (task.required > 0) {
val getPattern = graph.getPattern(task.pattern!!)
val pattern = task.patternId?.let(graph::getPattern) ?: continue
if (getPattern != null) {
if (!simulate) {
val new = task.shrinkRequired(1)
_tasks[key] = new
listeners.forEach { menu: MatterPanelMenu -> menu.taskUpdated(new) }
graph.onMatterTaskUpdated(new, task)
setChanged()
}
return MatterTaskAllocation(task, getPattern)
if (!simulate) {
val new = task.allocate()
_tasks[key] = new
listeners.forEach { it.taskUpdated(new) }
graph.onMatterTaskUpdated(new, task)
setChanged()
}
return ReplicationTaskAllocation(task, pattern)
}
}
return null
}
override fun notifyTaskCompletion(task: MatterTask): Boolean {
var localTask = _tasks[task.id] ?: return false
override fun notifyTaskCompletion(taskId: UUID): Boolean {
var localTask = _tasks[taskId] ?: return false
val oldTask = localTask
localTask = localTask.shrinkInProgress(1)
localTask = localTask.finish()
val graph = matterNode.graph as MatterNetworkGraph?
// Задача полностью выполнена
if (localTask.required <= 0 && localTask.in_progress <= 0) {
_tasks.remove(task.id)
graph?.onMatterTaskCreated(task)
listeners.forEach { menu: MatterPanelMenu -> menu.taskRemoved(localTask) }
if (localTask.required <= 0 && localTask.inProgress <= 0) {
_tasks.remove(taskId)
graph?.onMatterTaskFinished(localTask)
listeners.forEach { it.taskRemoved(localTask) }
} else {
// Задача обновлена
_tasks[task.id()] = localTask
_tasks[taskId] = localTask
graph?.onMatterTaskUpdated(localTask, oldTask)
listeners.forEach { menu: MatterPanelMenu -> menu.taskUpdated(localTask) }
listeners.forEach { it.taskUpdated(localTask) }
}
setChanged()
@ -155,7 +149,7 @@ class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
val list = ListTag()
for (task in _tasks.values) {
list.add(task!!.serializeNBT())
list.add(task.serializeNBT())
}
nbt.put("tasks", list)
@ -167,16 +161,16 @@ class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
val list = nbt.getList("tasks", Tag.TAG_COMPOUND.toInt())
for (tag in list) {
val task = MatterTask.deserializeNBT(tag)
val task = ReplicationTask.deserializeNBT(tag)
if (task != null) {
_tasks[task.id()] = task
_tasks[task.id] = task
}
}
}
override fun getTask(id: UUID): MatterTask? {
return _tasks[id]
override fun getTask(id: UUID): ReplicationTask? {
return _tasks[id]?.asImmutable()
}
fun removeTask(id: UUID) {
@ -185,19 +179,17 @@ class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
(matterNode.graph as MatterNetworkGraph?)?.onMatterTaskRemoved(task)
listeners.forEach { menu: MatterPanelMenu -> menu.taskRemoved(task) }
listeners.forEach { it.taskRemoved(task) }
setChanged()
}
fun removeTask(state: PatternState) = removeTask(state.id)
fun addTask(state: PatternState, how_much: Int): MatterTask {
val task = MatterTask(UUID.randomUUID(), state.id, state.item, 0, 0, how_much)
_tasks[task.id()] = task
fun addTask(state: IPatternState, count: Int): IReplicationTask<*> {
val task = ReplicationTask(UUID.randomUUID(), state.id, state.item, 0, 0, count)
_tasks[task.id] = task
(matterNode.graph as MatterNetworkGraph?)?.onMatterTaskCreated(task)
listeners.forEach { menu: MatterPanelMenu -> menu.taskUpdated(task) }
listeners.forEach { it.taskUpdated(task) }
setChanged()
return task

View File

@ -12,13 +12,10 @@ import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.capabilities.Capability
import net.minecraftforge.common.capabilities.ForgeCapabilities
import net.minecraftforge.common.util.LazyOptional
import net.minecraftforge.items.CapabilityItemHandler
import ru.dbotthepony.mc.otm.TranslatableComponent
import ru.dbotthepony.mc.otm.block.entity.worker.MatteryWorkerBlockEntity
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerJob
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerJobStatus
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerTickContext
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler
@ -30,26 +27,27 @@ import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.graph.Graph6Node
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode
import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph
import ru.dbotthepony.mc.otm.ifHas
import ru.dbotthepony.mc.otm.item.MatterDustItem
import ru.dbotthepony.mc.otm.core.map
import ru.dbotthepony.mc.otm.menu.MatterRecyclerMenu
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.set
import ru.dbotthepony.mc.otm.container.set
import ru.dbotthepony.mc.otm.core.set
class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState)
: MatteryWorkerBlockEntity(MBlockEntities.MATTER_RECYCLER, blockPos, blockState), IMatterGraphNode {
: MatteryWorkerBlockEntity<MatteryWorkerBlockEntity.Job>(MBlockEntities.MATTER_RECYCLER, blockPos, blockState, ::Job), IMatterGraphNode {
val matter = MatterHandlerImpl(
this::setChangedLight,
this::matterLevelUpdated,
MatterDirection.EXTRACT,
STORAGE
)
val container = MatteryContainer(this::setChangedLight, 1)
val container = MatteryContainer(this::itemContainerUpdated, 1)
override val matterNode = Graph6Node<IMatterGraphNode>(this)
private var resolverNode = LazyOptional.of { this }
private var valid = true
override val energy = WorkerEnergyStorage(this, MAX_POWER)
override val energy = WorkerEnergyStorage(this::powerLevelUpdated, MAX_POWER)
override fun getMatterHandler(): IMatterHandler {
return matter
@ -99,7 +97,7 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState)
override fun load(nbt: CompoundTag) {
super.load(nbt)
nbt.ifHas("matter", CompoundTag::class.java, matter::deserializeNBT)
nbt.map("matter", matter::deserializeNBT)
container.deserializeNBT(nbt["container"])
}
@ -107,15 +105,12 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState)
if (!valid)
return super.getCapability(cap, side)
if (cap === CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) {
return itemHandler.get().cast()
} else if (cap === MatteryCapability.MATTER) {
return matter.get().cast()
} else if (cap === MatteryCapability.MATTER_NODE) {
return resolverNode.cast()
return when (cap) {
ForgeCapabilities.ITEM_HANDLER -> itemHandler.get().cast()
MatteryCapability.MATTER -> matter.get().cast()
MatteryCapability.MATTER_NODE -> resolverNode.cast()
else -> super.getCapability(cap, side)
}
return super.getCapability(cap, side)
}
override val defaultDisplayName: Component
@ -125,41 +120,39 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState)
return MatterRecyclerMenu(containerID, inventory, this)
}
override fun onJobFinish(job: WorkerJob): WorkerJobStatus {
override fun onJobFinish(job: Job): Status {
// вся логика в onWorkTick
return WorkerJobStatus()
return Status.SUCCESS
}
override fun computeNextJob(): WorkerJob? {
override fun computeNextJob(): Pair<Job?, IdleReason?> {
if (matter.missingMatter.isZero)
return null
return null to IdleReason.ITEM
val stack = container[0]
if (stack.isEmpty || stack.item !is MatterDustItem) {
return null
return null to IdleReason.ITEM
}
val copy = stack.copy()
copy.count = 1
val dustMatter = (stack.item as MatterDustItem).getMatterValue(copy) ?: return null
val dustMatter = (stack.item as MatterDustItem).getMatterValue(stack.copy().also { it.count = 1 }) ?: return null to IdleReason.ITEM
stack.shrink(1)
return WorkerJob(copy, dustMatter.value.toDouble() * MATTER_TICKS, POWER_CONSUMPTION)
container.setChanged(0)
return Job(dustMatter.value.toDouble() * MATTER_TICKS, POWER_CONSUMPTION) to null
}
override fun onWorkTick(context: WorkerTickContext): WorkerJobStatus {
override fun onWorkTick(requiredPower: ImpreciseFraction, extractedPower: ImpreciseFraction, ticksAdvanced: Double): Status {
if ((level?.random?.nextDouble() ?: 1.0) <= 0.4)
return WorkerJobStatus()
return Status.SUCCESS
val receive = if (context.ticksAdvanced == 1.0) MATTER_PER_TICK else MATTER_PER_TICK * context.ticksAdvanced
val receive = MATTER_PER_TICK * ticksAdvanced
val received = matter.receiveMatterInner(receive, true)
if (receive != received)
return WorkerJobStatus(false, 20)
return Status.FAILURE_MATTER
matter.receiveMatterInner(receive, false)
return WorkerJobStatus()
return Status.SUCCESS
}
fun tick() {

View File

@ -8,49 +8,93 @@ import net.minecraft.server.level.ServerLevel
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.capabilities.Capability
import net.minecraftforge.common.capabilities.ForgeCapabilities
import net.minecraftforge.common.util.LazyOptional
import net.minecraftforge.items.CapabilityItemHandler
import ru.dbotthepony.mc.otm.TranslatableComponent
import ru.dbotthepony.mc.otm.block.entity.worker.MatteryWorkerBlockEntity
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerJob
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerJobStatus
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerTickContext
import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.capability.matter.*
import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.container.MatteryContainerFilterOnlyOut
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.graph.Graph6Node
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode
import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph
import ru.dbotthepony.mc.otm.ifHas
import ru.dbotthepony.mc.otm.matter.baselineComplexityReplicateTicks
import ru.dbotthepony.mc.otm.matter.getMatterValue
import ru.dbotthepony.mc.otm.menu.MatterReplicatorMenu
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.set
import ru.dbotthepony.mc.otm.container.set
import ru.dbotthepony.mc.otm.core.*
class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
MatteryWorkerBlockEntity(MBlockEntities.MATTER_REPLICATOR, p_155229_, p_155230_), IMatterGraphNode {
MatteryWorkerBlockEntity<MatterReplicatorBlockEntity.ReplicatorJob>(MBlockEntities.MATTER_REPLICATOR, p_155229_, p_155230_, {
try {
ReplicatorJob(it)
} catch(err: NoSuchElementException) {
null
}
}), IMatterGraphNode {
override val energy = WorkerEnergyStorage(this, STORAGE, MAX_IO)
class ReplicatorJob : ItemJob {
val matterPerTick: ImpreciseFraction
val task: ReplicationTask
var matterValue: ImpreciseFraction
val pattern: PatternState?
val asDust: Boolean
constructor(tag: CompoundTag) : super(tag) {
matterPerTick = tag.getImpreciseFraction("matterPerTick")
matterValue = tag.getImpreciseFraction("matterValue")
pattern = tag.map("pattern", PatternState::deserializeNBT)
asDust = tag.getBoolean("asDust")
task = tag.map("task", ReplicationTask::deserializeNBT) ?: throw NoSuchElementException("Unable to deserialize matter task")
}
constructor(
itemStack: ItemStack,
matterPerTick: ImpreciseFraction,
task: ReplicationTask,
matterValue: ImpreciseFraction,
pattern: PatternState?,
asDust: Boolean,
ticks: Double,
) : super(itemStack, ticks, BASE_CONSUMPTION) {
this.matterPerTick = matterPerTick
this.task = task
this.matterValue = matterValue
this.pattern = pattern
this.asDust = asDust
}
override fun serializeNBT(): CompoundTag {
return super.serializeNBT().also {
it["matterPerTick"] = this.matterPerTick
it["task"] = this.task.serializeNBT()
it["matterValue"] = this.matterValue
if (this.pattern != null)
it["pattern"] = this.pattern.serializeNBT()
it["asDust"] = this.asDust
}
}
}
override val energy = WorkerEnergyStorage(this::powerLevelUpdated, STORAGE, MAX_IO)
override val matterNode = Graph6Node<IMatterGraphNode>(this)
private val resolverNode = LazyOptional.of { this }
@JvmField
val matter = MatterHandlerImpl(
this::setChangedLight,
this::matterLevelUpdated,
MatterDirection.RECEIVE,
ImpreciseFraction(2)
)
// обычные запросы
@JvmField
val container = MatteryContainer(this::setChangedLight, 5)
val container = MatteryContainer(this::itemContainerUpdated, 5)
private val itemHandler = container.handler(MatteryContainerFilterOnlyOut)
override val defaultDisplayName: Component
@ -60,38 +104,42 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
return MatterReplicatorMenu(containerID, inventory, this)
}
override fun onJobFinish(job: WorkerJob): WorkerJobStatus {
if (job.data.getBoolean("as_dust")) {
val matterValue = moveMatterAsDustIntoContainer(ImpreciseFraction.deserializeNBT(job["matter"]), container, OUTPUT_DUST_MAIN, OUTPUT_DUST_STACKING)
override fun onJobFinish(job: ReplicatorJob): Status {
if (job.asDust) {
job.matterValue = moveMatterAsDustIntoContainer(job.matterValue, container, OUTPUT_DUST_MAIN, OUTPUT_DUST_STACKING)
if (!matterValue.isZero) {
job["matter"] = matterValue.serializeNBT()
return WorkerJobStatus(false, 20)
if (!job.matterValue.isZero) {
return Status.FAILURE_WAIT
}
(matterNode.graph as MatterNetworkGraph?)?.notifyTaskCompletion(MatterTask.deserializeNBT(job["task"])!!)
return WorkerJobStatus()
(matterNode.graph as MatterNetworkGraph?)?.notifyTaskCompletion(job.task.id)
return Status.SUCCESS
}
if (!container.fullyAddItem(job.stack, FIRST_ACTUAL_OUTPUT_SLOT .. LAST_ACTUAL_OUTPUT_SLOT)) {
return WorkerJobStatus(false, 20)
if (!container.fullyAddItem(job.itemStack, FIRST_ACTUAL_OUTPUT_SLOT .. LAST_ACTUAL_OUTPUT_SLOT)) {
return Status.FAILURE_ITEM
}
(matterNode.graph as MatterNetworkGraph?)?.notifyTaskCompletion(MatterTask.deserializeNBT(job["task"])!!)
return WorkerJobStatus()
(matterNode.graph as MatterNetworkGraph?)?.notifyTaskCompletion(job.task.id)
return Status.SUCCESS
}
override fun onMatterTaskCreated(task: MatterTask) {
isIdling = false
override fun onMatterTaskCreated(task: IReplicationTask<*>) {
if (idleReason == IdleReason.OBSERVING) {
isIdling = false
}
}
override fun onMatterTaskUpdated(new_state: MatterTask, old_state: MatterTask) {
isIdling = false
override fun <T : IReplicationTask<*>> onMatterTaskUpdated(newState: T, oldState: T) {
if (idleReason == IdleReason.OBSERVING) {
isIdling = false
}
}
override fun onPatternAdded(state: PatternState) {
isIdling = false
override fun onPatternAdded(state: IPatternState) {
if (idleReason == IdleReason.OBSERVING) {
isIdling = false
}
}
override fun setRemoved() {
@ -106,33 +154,35 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
MatterNetworkGraph.discoverFull(this, matterNode)
}
override fun computeNextJob(): WorkerJob? {
val graph = matterNode.graph as MatterNetworkGraph? ?: return null
val allocation = graph.allocateTask(false) ?: return null
override fun computeNextJob(): Pair<ReplicatorJob?, IdleReason?> {
if (energy.batteryLevel < BASE_CONSUMPTION) {
return null to IdleReason.POWER
}
val graph = matterNode.graph as MatterNetworkGraph? ?: return null to null
val allocation = graph.allocateTask(simulate = false) ?: return null to IdleReason.OBSERVING
val stack = allocation.task.stack(1)
val matter = getMatterValue(stack)
// ????????
if (matter.isZero) return null
if (matter.isZero) return null to null
val ticks = matter.complexity * baselineComplexityReplicateTicks
return WorkerJob(stack, ticks, BASE_CONSUMPTION, CompoundTag().also {
it["matter_per_tick"] = (matter.value / ticks).serializeNBT()
it["task"] = allocation.task.serializeNBT()
it["matter"] = matter.value.serializeNBT()
if (allocation.pattern != null)
it["pattern"] = allocation.pattern.serializeNBT()
if ((level?.random?.nextDouble() ?: 1.0) > (allocation.pattern?.research ?: 2.0))
it["as_dust"] = true
})
return ReplicatorJob(
itemStack = stack,
matterPerTick = matter.value / ticks,
task = allocation.task.asImmutable(),
matterValue = matter.value,
pattern = allocation.pattern?.asImmutable(),
asDust = (level?.random?.nextDouble() ?: 1.0) > (allocation.pattern?.researchPercent ?: 2.0),
ticks = ticks,
) to null
}
override fun onWorkTick(context: WorkerTickContext): WorkerJobStatus {
val drainPerTick = ImpreciseFraction.deserializeNBT(context.job.data["matter_per_tick"])
val graph = matterNode.graph as MatterNetworkGraph? ?: return WorkerJobStatus(false, 20)
override fun onWorkTick(requiredPower: ImpreciseFraction, extractedPower: ImpreciseFraction, ticksAdvanced: Double): Status {
val drainPerTick = currentJob!!.matterPerTick * ticksAdvanced
val graph = matterNode.graph as MatterNetworkGraph? ?: return Status.FAILURE_WAIT_FAST
if (matter.extractMatterInner(drainPerTick, true) < drainPerTick) {
// в машине недостаточно материи
@ -142,44 +192,42 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
val toExtract = drainPerTick - matter.extractMatterInner(drainPerTick, true)
val drain = graph.extractMatter(toExtract, true)
if (drain < toExtract) {
if (drain != toExtract) {
// недостаточно материи в сети
return WorkerJobStatus(false, 200)
return Status.FAILURE_MATTER
}
// достаточно материи в сети + внутри машины
matter.extractMatterInner(drainPerTick, false)
graph.extractMatter(drain, false)
return WorkerJobStatus()
return Status.SUCCESS
} else {
// в тик требуется меньше материи, чем её может хранить репликатор
// примем из сети недостающее количество бака материи, или 200 тиков репликации, что меньше
val toExtract =
matter.missingMatter.coerceAtMost(drainPerTick.times(DRAIN_MULT))
val drain = graph.extractMatter(toExtract, true)
val drain = graph.extractMatter(matter.missingMatter.coerceAtMost(drainPerTick * DRAIN_MULT), true)
if (drain.isZero) {
// в сети нет материи
return WorkerJobStatus(false, 200)
return Status.FAILURE_MATTER
}
val received = matter.receiveMatterOuter(drain, false)
graph.extractMatter(received, false)
// получили материю, проверяем возможность работы
if (matter.extractMatterInner(drainPerTick, false) >= drainPerTick) {
return WorkerJobStatus()
if (matter.extractMatterInner(drainPerTick, true) >= drainPerTick) {
matter.extractMatterInner(drainPerTick, false)
return Status.SUCCESS
} else {
// :(
return WorkerJobStatus(false, 200)
return Status.FAILURE_WAIT
}
}
}
// в машине достаточно материи
matter.extractMatterInner(drainPerTick, false)
return WorkerJobStatus()
return Status.SUCCESS
}
override fun saveAdditional(nbt: CompoundTag) {
@ -191,10 +239,7 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
override fun load(nbt: CompoundTag) {
super.load(nbt)
container.deserializeNBT(nbt["container"])
nbt.ifHas("matter", CompoundTag::class.java) {
matter.deserializeNBT(it)
}
nbt.map("matter", matter::deserializeNBT)
}
private var valid = true
@ -213,8 +258,8 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
override fun <T> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
if (valid) {
if (cap === MatteryCapability.MATTER_NODE) return resolverNode.cast()
if (cap === CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) return itemHandler.get().cast()
if (cap == MatteryCapability.MATTER_NODE) return resolverNode.cast()
if (cap == ForgeCapabilities.ITEM_HANDLER) return itemHandler.get().cast()
}
return super.getCapability(cap, side)

View File

@ -12,16 +12,16 @@ import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.capabilities.Capability
import net.minecraftforge.common.capabilities.ForgeCapabilities
import net.minecraftforge.common.util.LazyOptional
import net.minecraftforge.items.CapabilityItemHandler
import ru.dbotthepony.mc.otm.TranslatableComponent
import ru.dbotthepony.mc.otm.block.entity.worker.MatteryWorkerBlockEntity
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerJob
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerJobStatus
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.capability.matter.IPatternState
import ru.dbotthepony.mc.otm.capability.matter.PatternState
import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.container.MatteryContainerFilter
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.graph.Graph6Node
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode
@ -32,26 +32,38 @@ import ru.dbotthepony.mc.otm.registry.MBlockEntities
import java.util.*
class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
MatteryWorkerBlockEntity(MBlockEntities.MATTER_SCANNER, p_155229_, p_155230_), IMatterGraphNode {
MatteryWorkerBlockEntity<MatteryWorkerBlockEntity.ItemJob>(MBlockEntities.MATTER_SCANNER, p_155229_, p_155230_, ::ItemJob), IMatterGraphNode {
val container = MatteryContainer(this::setChanged, 1)
override val energy = WorkerEnergyStorage(this, STORAGE, MAX_IO)
private val itemHandler = container.handler(
{ _: Int, stack: ItemStack -> canDecompose(stack) },
{ _: Int, _: Int, _: ItemStack -> isIdling }
)
val container = MatteryContainer(this::itemContainerUpdated, 1)
override val energy = WorkerEnergyStorage(this::powerLevelUpdated, STORAGE, MAX_IO)
private val itemHandler = container.handler(object : MatteryContainerFilter {
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
return canDecompose(stack)
}
override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean {
return isIdling
}
})
// IMatterGraphNode
override fun onPatternAdded(state: PatternState) {
isIdling = false
override fun onPatternAdded(state: IPatternState) {
if (idleReason == IdleReason.OBSERVING) {
isIdling = false
}
}
override fun onPatternRemoved(state: PatternState) {
isIdling = false
override fun onPatternRemoved(state: IPatternState) {
if (idleReason == IdleReason.OBSERVING) {
isIdling = false
}
}
override fun onPatternUpdated(new_state: PatternState, old_state: PatternState) {
isIdling = false
override fun onPatternUpdated(newState: IPatternState, oldState: IPatternState) {
if (idleReason == IdleReason.OBSERVING) {
isIdling = false
}
}
// /IMatterGraphNode
@ -61,7 +73,7 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
override fun <T> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
if (valid) {
if (cap === CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) return itemHandler.get().cast()
if (cap == ForgeCapabilities.ITEM_HANDLER) return itemHandler.get().cast()
if (cap == MatteryCapability.MATTER_NODE) return resolverNode.cast()
}
@ -105,72 +117,71 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
super.load(nbt)
}
override fun onJobFinish(job: WorkerJob): WorkerJobStatus {
val grid = matterNode.graph as MatterNetworkGraph? ?: return WorkerJobStatus(false, 100)
override fun onJobFinish(job: ItemJob): Status {
val grid = matterNode.graph as MatterNetworkGraph? ?: return Status.FAILURE_WAIT
val stack = job.stack
if (stack.isEmpty || !hasMatterValue(stack)) return WorkerJobStatus()
val stack = job.itemStack
if (stack.isEmpty || !hasMatterValue(stack)) return Status.SUCCESS
val getState = grid.findPatterns(stack.item)
var findState: PatternState? = null
var findState: IPatternState? = null
for (state in getState) {
if (state.item() === stack.item) {
if (findState == null && state.research() < 1.0) {
findState = state
} else if (findState != null && findState.research() < state.research()) {
findState = state
}
for (state in grid.patterns.filter { it.item === stack.item }) {
if (findState == null && state.researchPercent < 1.0) {
findState = state
} else if (findState != null && findState.researchPercent < state.researchPercent) {
findState = state
}
}
val new =
if (findState != null) {
PatternState(findState.id(), stack.item, findState.research() + 0.2)
PatternState(findState.id, stack.item, findState.researchPercent + 0.2)
} else {
PatternState(UUID.randomUUID(), stack.item, 0.2)
}
if (!grid.insertPattern(new, onlyUpdate = false, simulate = false).isFailed) {
return WorkerJobStatus()
return Status.SUCCESS
} else {
return WorkerJobStatus(false, 200)
return Status.FAILURE_WAIT
}
}
override fun computeNextJob(): WorkerJob? {
val grid = matterNode.graph as MatterNetworkGraph? ?: return null
override fun computeNextJob(): Pair<ItemJob?, IdleReason?> {
if (energy.batteryLevel.isZero) {
return null to IdleReason.POWER
}
val grid = matterNode.graph as MatterNetworkGraph? ?: return null to null
val stack = container.getItem(0)
if (stack.isEmpty || !canDecompose(stack)) return null
if (stack.isEmpty || !canDecompose(stack)) return null to IdleReason.ITEM
val getState = grid.findPatterns(stack.item)
var findState: PatternState? = null
var findState: IPatternState? = null
for (state in getState) {
if (state.item === stack.item && state.research < 1.0) {
for (state in grid.patterns.filter { it.item === stack.item }) {
if (state.researchPercent < 1.0) {
findState = state
} else if (state.item === stack.item && state.research >= 1.0) {
return null
} else if (state.researchPercent >= 1.0) {
return null to IdleReason.ITEM
}
}
val new: PatternState =
val new: IPatternState =
if (findState != null) {
PatternState(findState.id, stack.item, findState.research + 0.2)
PatternState(findState.id, stack.item, findState.researchPercent + 0.2)
} else {
PatternState(UUID.randomUUID(), stack.item, 0.2)
}
if (!grid.insertPattern(new, onlyUpdate = false, simulate = true).isFailed) {
val copy = stack.copy()
copy.count = 1
val copy = stack.copy().also { it.count = 1 }
stack.shrink(1)
container.setChanged()
return WorkerJob(copy, getMatterValue(copy).complexity * baselineComplexityScanTicks, BASE_CONSUMPTION)
return ItemJob(copy, getMatterValue(copy).complexity * baselineComplexityScanTicks, BASE_CONSUMPTION) to null
}
return null
return null to IdleReason.ITEM
}
override fun setLevel(p_155231_: Level) {

View File

@ -13,16 +13,17 @@ import net.minecraft.world.level.Level
import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.capabilities.Capability
import net.minecraftforge.common.util.LazyOptional
import ru.dbotthepony.mc.otm.TranslatableComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity
import ru.dbotthepony.mc.otm.graph.storage.BasicStorageGraphNode
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.ifHas
import ru.dbotthepony.mc.otm.core.ifHas
import ru.dbotthepony.mc.otm.menu.DriveRackMenu
import ru.dbotthepony.mc.otm.set
import ru.dbotthepony.mc.otm.container.set
import ru.dbotthepony.mc.otm.core.set
import ru.dbotthepony.mc.otm.graph.storage.StorageNetworkGraph
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.storage.*

View File

@ -11,16 +11,17 @@ import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.state.BlockState
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.TranslatableComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity
import ru.dbotthepony.mc.otm.block.storage.DriveViewerBlock
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState
import ru.dbotthepony.mc.otm.block.entity.WorkerState
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.menu.DriveViewerMenu
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.set
import ru.dbotthepony.mc.otm.container.set
import ru.dbotthepony.mc.otm.core.set
import javax.annotation.ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault

View File

@ -26,26 +26,26 @@ import net.minecraftforge.common.util.INBTSerializable
import net.minecraftforge.common.util.LazyOptional
import net.minecraftforge.network.NetworkEvent
import org.apache.logging.log4j.LogManager
import ru.dbotthepony.mc.otm.TranslatableComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.get
import ru.dbotthepony.mc.otm.container.get
import ru.dbotthepony.mc.otm.graph.storage.BasicStorageGraphNode
import ru.dbotthepony.mc.otm.graph.storage.StorageNetworkGraph
import ru.dbotthepony.mc.otm.ifHas
import ru.dbotthepony.mc.otm.core.ifHas
import ru.dbotthepony.mc.otm.menu.ItemMonitorMenu
import ru.dbotthepony.mc.otm.network.MatteryPacket
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.set
import ru.dbotthepony.mc.otm.container.set
import ru.dbotthepony.mc.otm.core.set
import ru.dbotthepony.mc.otm.storage.*
import java.math.BigInteger
import java.util.*
import java.util.function.Supplier
import kotlin.collections.HashMap
import kotlin.collections.HashSet
class ItemMonitorPlayerSettings : INBTSerializable<CompoundTag>, MatteryPacket {
enum class RefillSource(val component: Component) {
@ -296,6 +296,7 @@ class ItemMonitorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
override fun stillValid(p_18946_: Player) = true
override fun getItem(p_18941_: Int): ItemStack {
require(p_18941_ == 1) { "Invalid slot ID: $p_18941_" }
return craftingRecipe?.resultItem?.copy() ?: ItemStack.EMPTY
}
@ -423,12 +424,13 @@ class ItemMonitorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
}
override fun removeItemNoUpdate(p_18951_: Int): ItemStack {
// return removeItem(p_18951_, craftingRecipe?.resultItem?.count ?: Int.MAX_VALUE)
throw UnsupportedOperationException()
}
override fun setItem(p_18944_: Int, p_18945_: ItemStack) {
throw UnsupportedOperationException()
if ((craftingRecipe != null && !craftingRecipe!!.resultItem.isEmpty) || !p_18945_.isEmpty) {
throw RuntimeException("BUG-DETECT: Tried to set crafting result slot item to something, and either we have crafting recipe which have valid result, or we are trying to set slot to non empty item: $p_18945_")
}
}
override fun setChanged() {}

View File

@ -25,10 +25,7 @@ import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.container.ItemFilter
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.core.isPositive
import ru.dbotthepony.mc.otm.core.isZero
import ru.dbotthepony.mc.otm.core.plus
import ru.dbotthepony.mc.otm.core.*
import ru.dbotthepony.mc.otm.graph.Graph6Node
import ru.dbotthepony.mc.otm.graph.GraphNodeListener
import ru.dbotthepony.mc.otm.graph.storage.BasicStorageGraphNode

View File

@ -23,8 +23,7 @@ import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock
import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity
import ru.dbotthepony.mc.otm.capability.*
import ru.dbotthepony.mc.otm.container.ItemFilter
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.core.plus
import ru.dbotthepony.mc.otm.core.*
import ru.dbotthepony.mc.otm.graph.Graph6Node
import ru.dbotthepony.mc.otm.graph.GraphNodeListener
import ru.dbotthepony.mc.otm.graph.storage.BasicStorageGraphNode

View File

@ -13,7 +13,7 @@ import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.capabilities.Capability
import net.minecraftforge.common.util.LazyOptional
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.TranslatableComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.WorkerEnergyStorage
@ -24,7 +24,8 @@ import ru.dbotthepony.mc.otm.graph.storage.StorageNetworkGraph
import ru.dbotthepony.mc.otm.menu.StoragePowerSupplierMenu
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.registry.MNames
import ru.dbotthepony.mc.otm.set
import ru.dbotthepony.mc.otm.container.set
import ru.dbotthepony.mc.otm.core.set
class StoragePowerSupplierBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.STORAGE_POWER_SUPPLIER, blockPos, blockState) {
override val defaultDisplayName: Component

View File

@ -1,261 +0,0 @@
package ru.dbotthepony.mc.otm.block.entity.worker
import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.core.BlockPos
import net.minecraft.world.level.block.state.BlockState
import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.DoubleTag
import net.minecraft.world.level.block.Block
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.core.weakGreaterOrEqual
import ru.dbotthepony.mc.otm.core.weakLessThan
import ru.dbotthepony.mc.otm.ifHas
import ru.dbotthepony.mc.otm.set
abstract class MatteryWorkerBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: BlockPos, p_155230_: BlockState) :
MatteryPoweredBlockEntity(p_155228_, p_155229_, p_155230_) {
var workTicks = 0.0
protected set
var throttleTicks = 0
protected set
var currentJob: WorkerJob? = null
protected set
// если isIdling То ничего не делать
// isIdling должна быть выставлена в true если что то изменилось, что могло создать работу
var isIdling = false
protected set
val isUnableToProcess: Boolean get() = throttleTicks > 0
val workProgress: Float
get() {
val currentJob = currentJob ?: return 0.0f
return (workTicks / currentJob.ticks).coerceAtMost(1.0).toFloat()
}
override fun saveAdditional(nbt: CompoundTag) {
super.saveAdditional(nbt)
nbt["work_ticks"] = workTicks
currentJob?.let { nbt["current_job"] = it.serializeNBT() }
}
override fun load(nbt: CompoundTag) {
super.load(nbt)
nbt.ifHas("work_ticks", DoubleTag::class.java) {
workTicks = it.asDouble
}
currentJob = WorkerJob.deserializeNBT(nbt["current_job"])
if (currentJob == null)
workTicks = 0.0
}
override fun setChanged() {
super.setChanged()
isIdling = false
}
override fun setChangedLight() {
super.setChangedLight()
isIdling = false
}
/**
* @param job current job
* @return whenever machine can finish it's job. return false if machine for whatever reason can't finish it's job,
* waiting on conditions to be met
*/
protected abstract fun onJobFinish(job: WorkerJob): WorkerJobStatus
/**
* @param context context for current job
* @return whenever machine can perform it
*/
protected open fun onWorkTick(context: WorkerTickContext): WorkerJobStatus {
return WorkerJobStatus()
}
private var idleTicksAnim = 0
private var workingTicksAnim = 0
private var errorTicksAnim = 0
override fun redstoneStatusUpdated(new_blocked: Boolean, old_blocked: Boolean) {
super.redstoneStatusUpdated(new_blocked, old_blocked)
isIdling = new_blocked
}
protected fun workerLoop() {
if (errorTicksAnim > 20 && blockState.hasProperty(WorkerState.WORKER_STATE) && blockState.getValue(WorkerState.WORKER_STATE) != WorkerState.ERROR) {
level?.setBlock(blockPos, blockState.setValue(WorkerState.WORKER_STATE, WorkerState.ERROR), Block.UPDATE_CLIENTS)
}
if (throttleTicks > 0) {
workingTicksAnim = 0
idleTicksAnim = 0
throttleTicks--
errorTicksAnim++
if (throttleTicks > 0)
return
}
if (isIdling) {
workingTicksAnim = 0
errorTicksAnim = 0
idleTicksAnim++
if (idleTicksAnim > 20 && blockState.hasProperty(WorkerState.WORKER_STATE) && blockState.getValue(WorkerState.WORKER_STATE) != WorkerState.IDLE) {
level?.setBlock(blockPos, blockState.setValue(WorkerState.WORKER_STATE, WorkerState.IDLE), Block.UPDATE_CLIENTS)
}
return
}
var currentJob = currentJob
if (currentJob == null) {
if (isBlockedByRedstone) {
isIdling = true
return
}
val input = computeNextJob()
if (input == null) {
isIdling = true
workingTicksAnim = 0
return
}
this.currentJob = input
currentJob = input
}
if (isBlockedByRedstone) {
isIdling = true
return
}
if (!currentJob.power.isZero && energy.batteryLevel.isZero) {
idleTicksAnim++
if (idleTicksAnim > 20 && blockState.hasProperty(WorkerState.WORKER_STATE) && blockState.getValue(WorkerState.WORKER_STATE) != WorkerState.IDLE) {
level?.setBlock(blockPos, blockState.setValue(WorkerState.WORKER_STATE, WorkerState.IDLE), Block.UPDATE_CLIENTS)
}
return
}
idleTicksAnim = 0
if (weakLessThan(workTicks, currentJob.ticks)) {
if (!currentJob.power.isZero) {
// сколько осталось тиков работать
val ticksLeft = currentJob.ticks - workTicks
val requiredPower: ImpreciseFraction
// запрос энергии на то количество, сколько действительно осталось работать
if (ticksLeft > 1.0) {
requiredPower = currentJob.power
} else {
requiredPower = currentJob.power * ticksLeft
}
val extractedPower = if (requiredPower.isZero) ImpreciseFraction.ZERO else energy.extractEnergyInner(requiredPower, true)
// сколько тиков мы "проработали"
// может быть меньше, чем единица, если недостаточно питания или мы завершаем работу,
// для которой осталось дробное количество тиков
val ticksAdvanced = (extractedPower / requiredPower).toDouble().coerceAtMost(ticksLeft)
val ticksAdvancedWeak = if (requiredPower.isZero) 1.0 else ticksAdvanced
val status = onWorkTick(WorkerTickContext(currentJob, requiredPower, extractedPower, ticksAdvanced))
if (!status.valid) {
throttleTicks += status.throttle
return
}
workingTicksAnim++
errorTicksAnim = 0
val updatedWorkTicks = (workTicks + ticksAdvancedWeak).coerceAtMost(currentJob.ticks)
if (weakGreaterOrEqual(updatedWorkTicks, currentJob.ticks)) {
workTicks = currentJob.ticks
energy.extractEnergyInner(extractedPower * (1.0 - (updatedWorkTicks - currentJob.ticks)), false)
val finish = onJobFinish(currentJob)
if (finish.valid) {
this.currentJob = null
workTicks = 0.0
} else {
throttleTicks += finish.throttle
}
} else {
workTicks = updatedWorkTicks
energy.extractEnergyInner(extractedPower, false)
}
} else {
val ticksLeft = (currentJob.ticks - workTicks).coerceAtMost(1.0)
val status = onWorkTick(WorkerTickContext(currentJob, ImpreciseFraction.ZERO, ImpreciseFraction.ZERO, ticksLeft))
if (!status.valid) {
throttleTicks += status.throttle
return
}
workingTicksAnim++
errorTicksAnim = 0
workTicks = (workTicks + 1.0).coerceAtMost(currentJob.ticks)
if (weakGreaterOrEqual(workTicks, currentJob.ticks)) {
val finish = onJobFinish(currentJob)
if (finish.valid) {
this.currentJob = null
workTicks = 0.0
} else {
throttleTicks += finish.throttle
}
}
}
} else {
val finish = onJobFinish(currentJob)
if (finish.valid) {
this.currentJob = null
workTicks = 0.0
errorTicksAnim = 0
} else {
throttleTicks += finish.throttle
errorTicksAnim++
}
}
if (workingTicksAnim > 20 &&
errorTicksAnim == 0 &&
blockState.hasProperty(WorkerState.WORKER_STATE) &&
blockState.getValue(WorkerState.WORKER_STATE) != WorkerState.WORKING)
{
level?.setBlock(blockPos, blockState.setValue(WorkerState.WORKER_STATE, WorkerState.WORKING), Block.UPDATE_CLIENTS)
}
}
/**
* Determine which item can be processed from input slots if idling
* @return any item in input slots. null if no work is available
*/
protected abstract fun computeNextJob(): WorkerJob?
fun basicTicker() {
batteryChargeLoop()
workerLoop()
}
}

View File

@ -1,85 +0,0 @@
package ru.dbotthepony.mc.otm.block.entity.worker
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.DoubleTag
import net.minecraft.nbt.Tag
import net.minecraft.util.StringRepresentable
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.block.state.properties.EnumProperty
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.set
@JvmRecord
data class WorkerTickContext(
val job: WorkerJob,
val requiredPower: ImpreciseFraction,
val extractedPower: ImpreciseFraction,
val ticksAdvanced: Double
)
enum class WorkerState : StringRepresentable {
IDLE,
WORKING,
ERROR;
companion object {
@JvmField
val WORKER_STATE: EnumProperty<WorkerState> = EnumProperty.create("worker", WorkerState::class.java)
@JvmField
val SEMI_WORKER_STATE: EnumProperty<WorkerState> = EnumProperty.create("worker", WorkerState::class.java, IDLE, WORKING)
}
override fun getSerializedName(): String {
return if (this == IDLE) "idle" else if (this == WORKING) "working" else "error"
}
}
@JvmRecord
data class WorkerJobStatus @JvmOverloads constructor(val valid: Boolean = true, val throttle: Int = 0) {
constructor(throttle: Int) : this(false, throttle)
}
@JvmRecord
data class WorkerJob @JvmOverloads constructor(
val stack: ItemStack,
val ticks: Double,
val power: ImpreciseFraction = ImpreciseFraction.ZERO,
val data: CompoundTag = CompoundTag()) {
fun serializeNBT(): CompoundTag {
return CompoundTag().also {
it["stack"] = stack.serializeNBT()
it["ticks"] = ticks
it["power"] = power.serializeNBT()
it["data"] = data
}
}
operator fun get(index: String) = data[index]
operator fun set(index: String, value: Tag) { data[index] = value }
operator fun set(index: String, value: Int) { data[index] = value }
operator fun set(index: String, value: Byte) { data[index] = value }
operator fun set(index: String, value: Short) { data[index] = value }
operator fun set(index: String, value: Long) { data[index] = value }
operator fun set(index: String, value: Float) { data[index] = value }
operator fun set(index: String, value: Double) { data[index] = value }
operator fun set(index: String, value: String) { data[index] = value }
operator fun set(index: String, value: Boolean) { data[index] = value }
operator fun set(index: String, value: ByteArray) { data[index] = value }
operator fun set(index: String, value: IntArray) { data[index] = value }
operator fun set(index: String, value: LongArray) { data[index] = value }
companion object {
@JvmStatic
fun deserializeNBT(tag: Tag?): WorkerJob? {
val nbt = tag as? CompoundTag ?: return null
return WorkerJob(
ItemStack.of(nbt["stack"] as? CompoundTag ?: return null),
(nbt["ticks"] as? DoubleTag ?: return null).asDouble,
ImpreciseFraction.deserializeNBT(nbt["power"]),
nbt["data"] as? CompoundTag ?: return null
)
}
}
}

View File

@ -19,7 +19,7 @@ import net.minecraft.world.level.block.state.properties.BooleanProperty
import net.minecraft.world.phys.shapes.CollisionContext
import net.minecraft.world.phys.shapes.VoxelShape
import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState
import ru.dbotthepony.mc.otm.block.entity.WorkerState
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.shapes.BlockShapes

View File

@ -17,7 +17,7 @@ import net.minecraft.world.level.block.Block
import net.minecraft.world.phys.shapes.CollisionContext
import net.minecraft.world.phys.shapes.VoxelShape
import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState
import ru.dbotthepony.mc.otm.block.entity.WorkerState
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.shapes.BlockShapes

View File

@ -15,7 +15,7 @@ import net.minecraft.world.phys.shapes.CollisionContext
import net.minecraft.world.phys.shapes.VoxelShape
import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock
import ru.dbotthepony.mc.otm.block.entity.matter.MatterRecyclerBlockEntity
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState
import ru.dbotthepony.mc.otm.block.entity.WorkerState
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.shapes.BlockShapes

View File

@ -15,7 +15,7 @@ import net.minecraft.world.phys.shapes.CollisionContext
import net.minecraft.world.phys.shapes.VoxelShape
import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock
import ru.dbotthepony.mc.otm.block.entity.matter.MatterReplicatorBlockEntity
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState
import ru.dbotthepony.mc.otm.block.entity.WorkerState
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.shapes.BlockShapes

View File

@ -15,7 +15,7 @@ import net.minecraft.world.phys.shapes.CollisionContext
import net.minecraft.world.phys.shapes.VoxelShape
import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock
import ru.dbotthepony.mc.otm.block.entity.matter.MatterScannerBlockEntity
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState
import ru.dbotthepony.mc.otm.block.entity.WorkerState
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.shapes.BlockShapes

View File

@ -17,7 +17,7 @@ import net.minecraft.world.phys.shapes.CollisionContext
import net.minecraft.world.phys.shapes.VoxelShape
import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock
import ru.dbotthepony.mc.otm.block.entity.storage.DriveViewerBlockEntity
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState
import ru.dbotthepony.mc.otm.block.entity.WorkerState
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.shapes.BlockShapes

View File

@ -22,7 +22,7 @@ import ru.dbotthepony.mc.otm.block.StorageCableBlock
import ru.dbotthepony.mc.otm.block.entity.storage.StorageBusBlockEntity
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.shapes.BlockShapes
import ru.dbotthepony.mc.otm.unaryMinus
import ru.dbotthepony.mc.otm.core.unaryMinus
class StorageBusBlock : RotatableMatteryBlock(), EntityBlock {
override val hasFreeRotation: Boolean get() = true

View File

@ -23,7 +23,7 @@ import ru.dbotthepony.mc.otm.block.entity.storage.StorageExporterBlockEntity
import ru.dbotthepony.mc.otm.block.entity.storage.StorageImporterBlockEntity
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.shapes.BlockShapes
import ru.dbotthepony.mc.otm.unaryMinus
import ru.dbotthepony.mc.otm.core.unaryMinus
class StorageImporterBlock : RotatableMatteryBlock(), EntityBlock {
override val hasFreeRotation: Boolean get() = true

View File

@ -12,12 +12,12 @@ import net.minecraftforge.common.capabilities.ForgeCapabilities
import net.minecraftforge.common.capabilities.ICapabilityProvider
import net.minecraftforge.common.util.INBTSerializable
import net.minecraftforge.common.util.LazyOptional
import net.minecraftforge.energy.CapabilityEnergy
import ru.dbotthepony.mc.otm.compat.mekanism.MatteryToMekanismEnergyWrapper
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.ifHas
import ru.dbotthepony.mc.otm.set
import ru.dbotthepony.mc.otm.tagNotNull
import ru.dbotthepony.mc.otm.core.ifHas
import ru.dbotthepony.mc.otm.container.set
import ru.dbotthepony.mc.otm.core.set
import ru.dbotthepony.mc.otm.core.tagNotNull
private enum class EnergyFlow {
INPUT, OUTPUT, BI_DIRECTIONAL
@ -47,9 +47,9 @@ sealed class ItemEnergyStorageImpl(
protected set
override var batteryLevel: ImpreciseFraction
get() = itemStack.tag?.get("energy")?.let { ImpreciseFraction.deserializeNBT(it) } ?: ImpreciseFraction.ZERO
get() = itemStack.tag?.get(NBT_KEY)?.let { ImpreciseFraction.deserializeNBT(it) } ?: ImpreciseFraction.ZERO
protected set(value) {
itemStack.tagNotNull.put("energy", value.serializeNBT())
itemStack.tagNotNull.put(NBT_KEY, value.serializeNBT())
}
override fun extractEnergyOuter(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction {
@ -127,6 +127,10 @@ sealed class ItemEnergyStorageImpl(
override fun canReceive(): Boolean {
return type != EnergyFlow.OUTPUT
}
companion object {
const val NBT_KEY = "energy"
}
}
open class EnergyConsumerItem(stack: ItemStack, maxBatteryLevel: ImpreciseFraction, maxInput: ImpreciseFraction? = null, maxOutput: ImpreciseFraction? = maxInput)

View File

@ -1,7 +1,8 @@
package ru.dbotthepony.mc.otm.capability
import net.minecraft.core.Direction
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import net.minecraftforge.common.capabilities.ForgeCapabilities
import net.minecraftforge.common.capabilities.ICapabilityProvider
import net.minecraftforge.common.util.LazyOptional
@ -9,8 +10,10 @@ import net.minecraftforge.energy.IEnergyStorage
import net.minecraftforge.fml.ModList
import ru.dbotthepony.mc.otm.compat.mekanism.getMekanismEnergySided
import ru.dbotthepony.mc.otm.compat.mekanism.mekanismEnergy
import ru.dbotthepony.mc.otm.container.iterator
import ru.dbotthepony.mc.otm.core.iterator
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.orNull
import ru.dbotthepony.mc.otm.core.orNull
val ICapabilityProvider.matteryPlayer: MatteryPlayerCapability? get() = getCapability(MatteryCapability.MATTERY_PLAYER).orNull()
@ -117,3 +120,58 @@ fun ICapabilityProvider.getMatteryEnergySided(side: Direction? = null): LazyOpti
return getCapability(MatteryCapability.ENERGY, side)
}
fun Player.extendedItemIterator(): MutableIterator<ItemStack> {
return object : MutableIterator<ItemStack> {
private val regular = this@extendedItemIterator.inventory.iterator()
private val mattery: MutableIterator<ItemStack>
private var isSecond = false
init {
val get = this@extendedItemIterator.matteryPlayer
if (get != null && get.hasExoSuit) {
mattery = get.exoSuitContainer.iterator()
} else {
mattery = object : MutableIterator<ItemStack> {
override fun hasNext(): Boolean {
return false
}
override fun next(): ItemStack {
throw UnsupportedOperationException()
}
override fun remove() {
throw UnsupportedOperationException()
}
}
}
}
override fun hasNext(): Boolean {
return regular.hasNext() || mattery.hasNext()
}
override fun next(): ItemStack {
if (isSecond) {
return mattery.next()
}
if (!regular.hasNext()) {
isSecond = true
return mattery.next()
}
return regular.next()
}
override fun remove() {
if (isSecond) {
mattery.remove()
} else {
regular.remove()
}
}
}
}

View File

@ -2,7 +2,6 @@ package ru.dbotthepony.mc.otm.capability
import it.unimi.dsi.fastutil.objects.ObjectArraySet
import net.minecraft.ChatFormatting
import net.minecraft.advancements.CriteriaTriggers
import net.minecraft.core.Direction
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag
@ -39,7 +38,7 @@ import ru.dbotthepony.mc.otm.android.AndroidFeatureType
import ru.dbotthepony.mc.otm.android.AndroidResearch
import ru.dbotthepony.mc.otm.android.AndroidResearchType
import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.core.*
import ru.dbotthepony.mc.otm.menu.ExoSuitInventoryMenu
import ru.dbotthepony.mc.otm.network.*
import ru.dbotthepony.mc.otm.registry.AndroidFeatures
@ -79,6 +78,10 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, IMatteryEn
private set(value) {
_exoSuitMenu = null
if (ply.containerMenu.slots.any { it.container == field }) {
ply.closeContainer()
}
for (i in 0 until value.containerSize.coerceAtMost(field.containerSize)) {
if (!field[i].isEmpty) {
value[i] = field[i]
@ -627,7 +630,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, IMatteryEn
shouldSendIteration = false
}
if (hasExoSuit && ply.containerMenu != exoSuitMenu) {
if (hasExoSuit && ply.containerMenu == ply.inventoryMenu) {
exoSuitMenu.broadcastChanges()
}
@ -762,10 +765,8 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, IMatteryEn
@Suppress("unused")
companion object {
@JvmField
val UNAFFECTED_EFFECTS = ObjectArraySet<MobEffect>()
@JvmStatic
fun registerEffects(event: FMLCommonSetupEvent) {
UNAFFECTED_EFFECTS.add(MobEffects.CONDUIT_POWER)
UNAFFECTED_EFFECTS.add(MobEffects.HEAL)
@ -782,7 +783,6 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, IMatteryEn
UNAFFECTED_EFFECTS.add(MobEffects.DOLPHINS_GRACE)
}
@SubscribeEvent
fun onLivingTick(event: LivingTickEvent) {
val ent = event.entity
@ -797,7 +797,6 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, IMatteryEn
}
}
@SubscribeEvent(priority = EventPriority.LOWEST)
fun onHurtEvent(event: LivingHurtEvent) {
if (event.isCanceled) {
return
@ -809,8 +808,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, IMatteryEn
const val CAPABILITY_KEY = "otm_player"
val CAPABILITY_LOCATION = ResourceLocation(OverdriveThatMatters.MOD_ID, CAPABILITY_KEY)
@SubscribeEvent
fun onAttachCapabilityEvent(event: AttachCapabilitiesEvent<Entity?>) {
fun onAttachCapabilityEvent(event: AttachCapabilitiesEvent<Entity>) {
val ent = event.`object`
if (ent is Player) {
@ -818,18 +816,12 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, IMatteryEn
}
}
@SubscribeEvent
fun onPlayerChangeDimensionEvent(event: PlayerEvent.PlayerChangedDimensionEvent) {
event.entity.getCapability(MatteryCapability.MATTERY_PLAYER)
.ifPresentK { it.invalidateNetworkState() }
}
@SubscribeEvent(priority = EventPriority.LOWEST)
fun onPlayerDeath(event: LivingDeathEvent) {
if (event.isCanceled) {
return
}
val ply = event.entity as? Player ?: return
val mattery = ply.matteryPlayer ?: return
@ -856,7 +848,6 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, IMatteryEn
}
}
@SubscribeEvent
fun onPlayerCloneEvent(event: PlayerEvent.Clone) {
val it = event.entity.matteryPlayer ?: return
@ -889,7 +880,6 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, IMatteryEn
private val itemPickupTicks = WeakHashMap<Player, WeakHashMap<ItemEntity, MutableInt>>()
@SubscribeEvent(priority = EventPriority.LOW)
fun onPickupEvent(event: EntityItemPickupEvent) {
if (event.item.owner != null && event.item.owner != event.entity.uuid && event.item.age < 200 || event.item.item.isEmpty) {
return

View File

@ -1,21 +1,14 @@
package ru.dbotthepony.mc.otm.capability.drive
import it.unimi.dsi.fastutil.longs.Long2ObjectAVLTreeMap
import it.unimi.dsi.fastutil.objects.Object2ObjectAVLTreeMap
import it.unimi.dsi.fastutil.objects.ObjectArraySet
import kotlin.jvm.JvmOverloads
import java.util.UUID
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag
import net.minecraft.nbt.LongTag
import net.minecraft.nbt.Tag
import org.apache.logging.log4j.LogManager
import ru.dbotthepony.mc.otm.core.BigInteger
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.core.isPositive
import ru.dbotthepony.mc.otm.core.serializeNBT
import ru.dbotthepony.mc.otm.ifHas
import ru.dbotthepony.mc.otm.set
import ru.dbotthepony.mc.otm.container.set
import ru.dbotthepony.mc.otm.core.*
import ru.dbotthepony.mc.otm.storage.*
import java.math.BigInteger
import java.util.ArrayList

View File

@ -36,7 +36,6 @@ import java.util.ArrayList
* 5. Mods which check items for being stack-able even with stack size of 1 gonna compare nbt tag,
* which will be performance tanking due to clause 1.
*/
@Suppress("unused")
object DrivePool {
private val LOGGER = LogManager.getLogger()
private val pool = Object2ObjectAVLTreeMap<UUID, WeakDriveReference>()
@ -130,7 +129,6 @@ object DrivePool {
}
}
@SubscribeEvent(priority = EventPriority.LOWEST)
fun onServerPostTick(event: ServerTickEvent) {
if (event.phase == TickEvent.Phase.END) {
if (exception != null) {
@ -152,7 +150,6 @@ object DrivePool {
return Thread.currentThread() === serverThread
}
@SubscribeEvent(priority = EventPriority.HIGHEST)
fun serverStartEvent(event: ServerAboutToStartEvent) {
if (thread?.isAlive == true) {
LOGGER.error("FMLServerStartedEvent fired twice.")
@ -172,7 +169,6 @@ object DrivePool {
thread = Thread(null, this::thread, "Overdrive That Matters DrivePool IO").also { it.start() }
}
@SubscribeEvent(priority = EventPriority.HIGHEST)
fun serverStopEvent(event: ServerStoppingEvent) {
val thread = thread
@ -189,7 +185,6 @@ object DrivePool {
pool.clear()
}
@SubscribeEvent
fun onWorldSave(event: LevelEvent.Save) {
writeBacklog()
}

View File

@ -6,12 +6,11 @@ import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import net.minecraftforge.registries.ForgeRegistries
import net.minecraftforge.registries.RegistryManager
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.core.BigInteger
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.core.serializeNBT
import ru.dbotthepony.mc.otm.set
import ru.dbotthepony.mc.otm.container.set
import ru.dbotthepony.mc.otm.core.set
import ru.dbotthepony.mc.otm.storage.IStorageTuple
import ru.dbotthepony.mc.otm.storage.ItemStackWrapper
import ru.dbotthepony.mc.otm.storage.StorageStackType

View File

@ -5,6 +5,7 @@ import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import java.util.*
import java.util.function.Predicate
import java.util.stream.Collectors
import java.util.stream.Stream
interface IMatterHandler {
val storedMatter: ImpreciseFraction
@ -14,6 +15,7 @@ interface IMatterHandler {
fun receiveMatterInner(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction
fun extractMatterOuter(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction
fun extractMatterInner(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction
val direction: MatterDirection
val missingMatter: ImpreciseFraction
get() = maxStoredMatter.minus(storedMatter).moreThanZero()
@ -27,42 +29,44 @@ interface IMatterHandler {
enum class MatterDirection { RECEIVE, EXTRACT, BIDIRECTIONAL }
interface IMatterTaskProvider {
interface IReplicationTaskProvider {
/**
* @return immutable collection of tasks that can be allocated by a worker
* It must return new stream each time
*/
val tasks: Collection<MatterTask>
val replicationTasks: Stream<out IReplicationTask<*>>
/**
* @return immutable collection of all stored tasks, even fully allocated by workers
* It must return new stream each time
*/
val allTasks: Collection<MatterTask>
val allReplicationTasks: Stream<out IReplicationTask<*>>
/**
* Allocates (marks as work-in-progress) a task
* by incrementing it's in_progress by 1
* and shrinking required by 1
* by incrementing it's [IReplicationTask.inProgress] by 1
* and shrinking [IReplicationTask.required] by 1
*
* If required == 0, it should not be returned by this method
* If [IReplicationTask.required] == 0, it should not be returned by this method
* @param simulate whenever to change internal state
* @return MatterTaskAllocation(task, pattern) that should be performed, or null if no work is available
*/
fun allocateTask(simulate: Boolean): MatterTaskAllocation?
fun allocateTask(simulate: Boolean): ReplicationTaskAllocation?
/**
* Notify about task completion. If this provider indeed contain this task, it should
* shrink in_progress by 1
* If in_progress == 0 and required == 0, it should discard the task
* @param task task being completed. this method should ignore tasks that are not owned by it.
* @param taskId task being completed. this method should ignore tasks that are not owned by it.
* @return whenever task indeed belong to this provider and internal state was updated
*/
fun notifyTaskCompletion(task: MatterTask): Boolean
fun notifyTaskCompletion(taskId: UUID): Boolean
/**
* @param id uuid of task
* @return MatterTask that this capability holds with this id, or null
*/
fun getTask(id: UUID): MatterTask?
fun getTask(id: UUID): IReplicationTask<*>? {
return allReplicationTasks.filter { it.id == id }.findAny().orElse(null)
}
/**
* Destroys all tasks this capability contains
@ -72,50 +76,36 @@ interface IMatterTaskProvider {
interface IPatternStorage {
/**
* @return unmodifiable collection of stored patterns
* It must return new stream each time
*/
val storedPatterns: Collection<PatternState>
val storedPatterns: Stream<out IPatternState>
fun findPatterns(item: Item): Collection<PatternState> {
return findPatterns { item2: PatternState -> item == item2.item() }
fun findPatterns(item: Item): Collection<IPatternState> {
return findPatterns { item == it.item }
}
fun findPatterns(predicate: Predicate<PatternState>?): Collection<PatternState> {
return storedPatterns.stream().filter(predicate).collect(Collectors.toList())
fun findPatterns(predicate: Predicate<IPatternState>): Collection<IPatternState> {
return storedPatterns.filter(predicate).collect(Collectors.toList())
}
fun findPattern(item: Item): PatternState? {
return findPattern { item2: PatternState -> item == item2.item() }
fun findPattern(item: Item): IPatternState? {
return storedPatterns.filter { it.item == item }.findAny().orElse(null)
}
fun findPattern(predicate: Predicate<PatternState>): PatternState? {
for (pattern in storedPatterns) {
if (predicate.test(pattern)) {
return pattern
}
}
return null
fun getPattern(id: UUID?): IPatternState? {
return storedPatterns.filter { it.id == id }.findAny().orElse(null)
}
fun getPattern(id: UUID?): PatternState? {
id ?: return null
for (pattern in storedPatterns) {
if (pattern.id == id) {
return pattern
}
}
return null
fun hasPattern(item: Item): Boolean {
return storedPatterns.filter { it.item == item }.findAny().isPresent
}
fun hasPattern(state: PatternState): Boolean {
return getPattern(state.id) != null
fun hasPattern(state: IPatternState): Boolean {
return hasPattern(state.id)
}
fun hasPattern(id: UUID?): Boolean {
return getPattern(id) != null
return storedPatterns.filter { it.id == id }.findAny().isPresent
}
val capacity: Int
@ -126,17 +116,17 @@ interface IPatternStorage {
* and if it fail, try only_update = false
*
* @param pattern pattern to be inserted or update value from
* @param only_update do not insert new pattern if this pattern's UUID is not matched
* @param onlyUpdate do not insert new pattern if this pattern's UUID is not matched
* @param simulate whenever to affect state
* @return record of status of the operation (at status() FAIL, UPDATED, INSERTED) as well as new_state and old_state
*/
fun insertPattern(pattern: PatternState, only_update: Boolean, simulate: Boolean): PatternInsertStatus
fun insertPattern(pattern: IPatternState, onlyUpdate: Boolean, simulate: Boolean): PatternInsertStatus
fun insertPattern(pattern: PatternState, simulate: Boolean): PatternInsertStatus {
fun insertPattern(pattern: IPatternState, simulate: Boolean): PatternInsertStatus {
return insertPattern(pattern, false, simulate)
}
fun updatePattern(pattern: PatternState, simulate: Boolean): PatternInsertStatus {
fun updatePattern(pattern: IPatternState, simulate: Boolean): PatternInsertStatus {
return insertPattern(pattern, true, simulate)
}
}

View File

@ -8,17 +8,17 @@ private enum class PatternInsertResult {
sealed class PatternInsertStatus(
private val status: PatternInsertResult,
val newState: PatternState?,
val oldState: PatternState?
val newState: IPatternState?,
val oldState: IPatternState?
) {
val isFailed get() = status === PatternInsertResult.FAIL
val isUpdated get() = status === PatternInsertResult.UPDATED
val isInserted get() = status === PatternInsertResult.INSERTED
val isFailed get() = status == PatternInsertResult.FAIL
val isUpdated get() = status == PatternInsertResult.UPDATED
val isInserted get() = status == PatternInsertResult.INSERTED
}
object PatternInsertFailure : PatternInsertStatus(PatternInsertResult.FAIL, null, null)
class PatternInsertUpdated(new: PatternState, old: PatternState) : PatternInsertStatus(PatternInsertResult.UPDATED, new, old)
class PatternInsertInserted(new: PatternState) : PatternInsertStatus(PatternInsertResult.INSERTED, new, null)
class PatternInsertUpdated(new: IPatternState, old: IPatternState) : PatternInsertStatus(PatternInsertResult.UPDATED, new, old)
class PatternInsertInserted(new: IPatternState) : PatternInsertStatus(PatternInsertResult.INSERTED, new, null)
@JvmRecord
data class MatterTaskAllocation(val task: MatterTask, val pattern: PatternState?)
data class ReplicationTaskAllocation(val task: IReplicationTask<*>, val pattern: IPatternState?)

View File

@ -4,7 +4,8 @@ import net.minecraft.nbt.CompoundTag
import net.minecraftforge.common.util.INBTSerializable
import net.minecraftforge.common.util.LazyOptional
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.set
import ru.dbotthepony.mc.otm.container.set
import ru.dbotthepony.mc.otm.core.set
open class MatterHandlerImpl @JvmOverloads constructor(
protected val listener: Runnable?,

View File

@ -0,0 +1,146 @@
package ru.dbotthepony.mc.otm.capability.matter
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.Tag
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import net.minecraftforge.registries.ForgeRegistries
import ru.dbotthepony.mc.otm.core.*
import java.util.*
sealed interface IPatternState {
val id: UUID
val item: Item
val researchPercent: Double
fun asMutable(): MutablePatternState
fun asImmutable() : PatternState
fun matchId(other: IPatternState): Boolean {
return other.id == id
}
fun copyAsMutable(
id: UUID = this.id,
item: Item = this.item,
researchPercent: Double = this.researchPercent,
): MutablePatternState {
return MutablePatternState(id, item, researchPercent)
}
fun copyAsImmutable(
id: UUID = this.id,
item: Item = this.item,
researchPercent: Double = this.researchPercent,
) : PatternState {
return PatternState(id, item, researchPercent)
}
fun stack(count: Int = 1): ItemStack {
return ItemStack(item, count)
}
fun serializeNBT(): CompoundTag {
return CompoundTag().also {
it["id"] = id
it["item"] = item.registryName!!.toString()
it["researchPercent"] = researchPercent
}
}
fun write(buff: FriendlyByteBuf) {
buff.writeUUID(id)
buff.writeItemType(item)
buff.writeDouble(researchPercent)
}
}
private fun deserializeNBT(nbt: Tag?, mutable: Boolean): IPatternState? {
if (nbt !is CompoundTag)
return null
if (!nbt.contains("id", "researchPercent", "item"))
return null
val id = nbt.getUUID("id")
val researchPercent = nbt.getDouble("researchPercent")
val item = ForgeRegistries.ITEMS.getValue(ResourceLocation(nbt.getString("item"))) ?: return null
if (item == Items.AIR)
return null
if (mutable) {
return MutablePatternState(id, item, researchPercent)
} else {
return PatternState(id, item, researchPercent)
}
}
private fun read(buff: FriendlyByteBuf, mutable: Boolean): IPatternState? {
val id = buff.readUUID()
val item = buff.readItemType()
val researchPercent = buff.readDouble()
item ?: return null
if (mutable) {
return MutablePatternState(id, item, researchPercent)
} else {
return PatternState(id, item, researchPercent)
}
}
data class PatternState(
override val id: UUID,
override val item: Item,
override val researchPercent: Double,
) : IPatternState {
override fun asMutable(): MutablePatternState {
return MutablePatternState(id, item, researchPercent)
}
override fun asImmutable(): PatternState {
return this
}
companion object {
fun deserializeNBT(tag: Tag?): PatternState? {
return deserializeNBT(tag, false) as PatternState?
}
fun read(buff: FriendlyByteBuf): PatternState? {
return read(buff, false) as PatternState?
}
}
}
data class MutablePatternState(
override val id: UUID,
override val item: Item,
override var researchPercent: Double,
) : IPatternState {
override fun asMutable(): MutablePatternState {
return this
}
override fun asImmutable(): PatternState {
return PatternState(id, item, researchPercent)
}
companion object {
fun deserializeNBT(tag: Tag?): MutablePatternState? {
return deserializeNBT(tag, true) as MutablePatternState?
}
fun read(buff: FriendlyByteBuf): MutablePatternState? {
return read(buff, true) as MutablePatternState?
}
}
}
fun FriendlyByteBuf.writePatternState(state: IPatternState) = state.write(this)
fun FriendlyByteBuf.readPatternState() = PatternState.read(this)
fun FriendlyByteBuf.readMutablePatternState() = MutablePatternState.read(this)

View File

@ -0,0 +1,210 @@
package ru.dbotthepony.mc.otm.capability.matter
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.Tag
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import net.minecraftforge.registries.ForgeRegistries
import ru.dbotthepony.mc.otm.core.readItemType
import ru.dbotthepony.mc.otm.core.registryName
import ru.dbotthepony.mc.otm.core.set
import ru.dbotthepony.mc.otm.core.writeItemType
import java.util.UUID
sealed interface IReplicationTask<S : IReplicationTask<S>> {
val id: UUID
val patternId: UUID?
val item: Item
val inProgress: Int
val finished: Int
val required: Int
fun asMutable(): MutableReplicationTask
fun asImmutable(): ReplicationTask
val total get() = inProgress + finished + required
fun copyAsMutable(
id: UUID = this.id,
patternId: UUID? = this.patternId,
item: Item = this.item,
inProgress: Int = this.inProgress,
finished: Int = this.finished,
required: Int = this.required,
): MutableReplicationTask {
return MutableReplicationTask(id, patternId, item, inProgress, finished, required)
}
fun copyAsImmutable(
id: UUID = this.id,
patternId: UUID? = this.patternId,
item: Item = this.item,
inProgress: Int = this.inProgress,
finished: Int = this.finished,
required: Int = this.required,
): ReplicationTask {
return ReplicationTask(id, patternId, item, inProgress, finished, required)
}
fun matchId(other: IReplicationTask<*>): Boolean {
return other.id == id
}
fun stack(count: Int = 1): ItemStack {
return ItemStack(item, count)
}
fun allocate(amount: Int = 1): S
fun finish(amount: Int = 1): S
fun serializeNBT(): CompoundTag {
return CompoundTag().also {
it["id"] = id
if (patternId != null)
it["patternId"] = patternId!!
it["item"] = item.registryName!!.toString()
it["inProgress"] = inProgress
it["finished"] = finished
it["required"] = required
}
}
fun write(buff: FriendlyByteBuf) {
buff.writeUUID(id)
buff.writeBoolean(patternId != null)
patternId?.let(buff::writeUUID)
buff.writeItemType(item)
buff.writeInt(inProgress)
buff.writeInt(finished)
buff.writeInt(required)
}
}
private fun deserializeNBT(nbt: Tag?, mutable: Boolean): IReplicationTask<*>? {
if (nbt !is CompoundTag)
return null
if (!nbt.contains("id") || !nbt.contains("inProgress") || !nbt.contains("finished") || !nbt.contains("required") || !nbt.contains("item"))
return null
val item = ForgeRegistries.ITEMS.getValue(ResourceLocation(nbt.getString("item"))) ?: return null
if (item == Items.AIR)
return null
val id = nbt.getUUID("id")
val patternId = if (nbt.contains("patternId")) nbt.getUUID("patternId") else null
val inProgress = nbt.getInt("inProgress")
val finished = nbt.getInt("finished")
val required = nbt.getInt("required")
if (mutable) {
return MutableReplicationTask(id, patternId, item, inProgress, finished, required)
} else {
return ReplicationTask(id, patternId, item, inProgress, finished, required)
}
}
private fun read(buff: FriendlyByteBuf, mutable: Boolean): IReplicationTask<*>? {
val id = buff.readUUID()
val patternId: UUID? = if (buff.readBoolean()) buff.readUUID() else null
val item = buff.readItemType()
val inProgress = buff.readInt()
val finished = buff.readInt()
val required = buff.readInt()
item ?: return null
if (mutable) {
return MutableReplicationTask(id, patternId, item, inProgress, finished, required)
} else {
return ReplicationTask(id, patternId, item, inProgress, finished, required)
}
}
data class ReplicationTask(
override val id: UUID,
override val patternId: UUID?,
override val item: Item,
override val inProgress: Int,
override val finished: Int,
override val required: Int
) : IReplicationTask<ReplicationTask> {
override fun asMutable(): MutableReplicationTask {
return MutableReplicationTask(id, patternId, item, inProgress, finished, required)
}
override fun asImmutable(): ReplicationTask {
return this
}
override fun allocate(amount: Int): ReplicationTask {
return ReplicationTask(id, patternId, item, inProgress + amount, finished, required - amount)
}
override fun finish(amount: Int): ReplicationTask {
return ReplicationTask(id, patternId, item, inProgress - amount, finished + amount, required)
}
companion object {
fun deserializeNBT(nbt: Tag?): ReplicationTask? {
return deserializeNBT(nbt, false) as ReplicationTask?
}
fun read(buff: FriendlyByteBuf): ReplicationTask? {
return read(buff, false) as ReplicationTask?
}
}
}
data class MutableReplicationTask(
override val id: UUID,
override val patternId: UUID?,
override val item: Item,
override var inProgress: Int,
override var finished: Int,
override var required: Int
) : IReplicationTask<MutableReplicationTask> {
override fun asMutable(): MutableReplicationTask {
return this
}
override fun asImmutable(): ReplicationTask {
return ReplicationTask(id, patternId, item, inProgress, finished, required)
}
override fun allocate(amount: Int): MutableReplicationTask {
inProgress += amount
finished -= amount
return this
}
override fun finish(amount: Int): MutableReplicationTask {
finished += amount
inProgress -= amount
return this
}
companion object {
fun deserializeNBT(nbt: Tag?): MutableReplicationTask? {
return deserializeNBT(nbt, true) as MutableReplicationTask?
}
fun read(buff: FriendlyByteBuf): MutableReplicationTask? {
return read(buff, true) as MutableReplicationTask?
}
}
}
fun FriendlyByteBuf.writeReplicationTask(task: IReplicationTask<*>) = task.write(this)
fun FriendlyByteBuf.readReplicationTask() = ReplicationTask.read(this)
fun FriendlyByteBuf.readMutableReplicationTask() = MutableReplicationTask.read(this)

View File

@ -0,0 +1,53 @@
package ru.dbotthepony.mc.otm.client
import net.minecraft.client.gui.screens.inventory.InventoryScreen
import net.minecraftforge.client.event.MovementInputUpdateEvent
import net.minecraftforge.client.event.ScreenEvent
import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.client.screen.ExoSuitInventoryScreen
import ru.dbotthepony.mc.otm.registry.AndroidFeatures
object ClientEventHandler {
fun inputEvent(event: MovementInputUpdateEvent) {
val ply = event.entity
val input = event.input
val cap = ply.matteryPlayer ?: return
if (cap.hasFeature(AndroidFeatures.AIR_BAGS))
return
if (ply.abilities.mayfly) {
cap.lastJumpTicks = 14
} else {
if (ply.isInWater) {
if (ply.isOnGround) {
cap.lastJumpTicks = 14
}
if (ply.isSwimming) {
ply.isSwimming = false
}
if (cap.lastJumpTicks <= 0) {
input.jumping = false
input.up = false
} else {
cap.lastJumpTicks--
}
}
}
}
fun screenOpen(event: ScreenEvent.Opening) {
if (minecraft.player?.isCreative == true) {
return
}
val player = minecraft.player?.matteryPlayer ?: return
if (player.hasExoSuit && event.newScreen is InventoryScreen) {
event.newScreen = ExoSuitInventoryScreen(player.exoSuitMenu)
}
}
}

View File

@ -1,56 +0,0 @@
package ru.dbotthepony.mc.otm.client
import net.minecraft.client.gui.screens.inventory.InventoryScreen
import net.minecraftforge.client.event.MovementInputUpdateEvent
import net.minecraftforge.client.event.ScreenEvent
import net.minecraftforge.eventbus.api.SubscribeEvent
import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.client.screen.ExoSuitInventoryScreen
import ru.dbotthepony.mc.otm.registry.AndroidFeatures
@SubscribeEvent
@Suppress("unused")
fun inputEvent(event: MovementInputUpdateEvent) {
val ply = event.entity
val input = event.input
val cap = ply.matteryPlayer ?: return
if (cap.hasFeature(AndroidFeatures.AIR_BAGS))
return
if (ply.abilities.mayfly) {
cap.lastJumpTicks = 14
} else {
if (ply.isInWater) {
if (ply.isOnGround) {
cap.lastJumpTicks = 14
}
if (ply.isSwimming) {
ply.isSwimming = false
}
if (cap.lastJumpTicks <= 0) {
input.jumping = false
input.up = false
} else {
cap.lastJumpTicks--
}
}
}
}
@SubscribeEvent
@Suppress("unused")
fun screenOpen(event: ScreenEvent.Opening) {
if (minecraft.player?.isCreative == true) {
return
}
val player = minecraft.player?.matteryPlayer ?: return
if (player.hasExoSuit && event.newScreen is InventoryScreen) {
event.newScreen = ExoSuitInventoryScreen(player.exoSuitMenu)
}
}

View File

@ -2,6 +2,12 @@ package ru.dbotthepony.mc.otm.client
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.Font
import net.minecraft.client.resources.sounds.SimpleSoundInstance
import net.minecraft.sounds.SoundEvents
inline val minecraft: Minecraft get() = Minecraft.getInstance()
inline val font: Font get() = minecraft.font
fun playGuiClickSound() {
minecraft.soundManager.play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0f))
}

View File

@ -18,14 +18,13 @@ import net.minecraftforge.client.gui.overlay.GuiOverlayManager
import net.minecraftforge.eventbus.api.EventPriority
import net.minecraftforge.eventbus.api.SubscribeEvent
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.TextComponent
import ru.dbotthepony.mc.otm.TranslatableComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.client.render.*
import ru.dbotthepony.mc.otm.core.RGBAColor
import ru.dbotthepony.mc.otm.ifPresentK
import ru.dbotthepony.mc.otm.core.ifPresentK
import java.util.*
object MatteryGUI {
@ -40,8 +39,6 @@ object MatteryGUI {
private val button_shaker = Random()
@SubscribeEvent
@Suppress("unused")
fun onScreenRender(event: ScreenEvent.Render.Pre) {
if (knownButtonScreen != null && knownButton == null) {
for (widget in knownButtonScreen!!.renderables) {
@ -88,8 +85,6 @@ object MatteryGUI {
}
}
@SubscribeEvent(priority = EventPriority.LOWEST)
@Suppress("unused")
fun onOpenGUIEvent(event: ScreenEvent.Opening) {
knownButtonX = -1
knownButtonY = -1
@ -199,14 +194,10 @@ object MatteryGUI {
popScissorRect()
}
@SubscribeEvent
@Suppress("unused")
fun onRenderGuiEvent(event: RenderGuiEvent.Post) {
showIteration(event)
}
@SubscribeEvent(priority = EventPriority.HIGH)
@Suppress("unused")
fun onLayerRenderEvent(event: RenderGuiOverlayEvent.Pre) {
if (event.overlay != FOOD_LEVEL_ELEMENT && event.overlay != AIR_LEVEL_ELEMENT) {
return

View File

@ -11,7 +11,7 @@ import net.minecraft.client.renderer.blockentity.BlockEntityRenderer
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider
import net.minecraft.world.phys.Vec3
import org.lwjgl.opengl.GL30
import ru.dbotthepony.mc.otm.TranslatableComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.block.entity.GravitationStabilizerBlockEntity
import ru.dbotthepony.mc.otm.block.entity.blackhole.BlackHoleBlockEntity
import ru.dbotthepony.mc.otm.capability.matteryPlayer

View File

@ -6,7 +6,7 @@ import net.minecraft.client.renderer.MultiBufferSource
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider
import net.minecraft.core.Direction
import ru.dbotthepony.mc.otm.TranslatableComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.block.EnergyCounterBlock
import ru.dbotthepony.mc.otm.block.entity.EnergyCounterBlockEntity
import ru.dbotthepony.mc.otm.client.render.*

View File

@ -10,12 +10,12 @@ import net.minecraft.client.renderer.blockentity.BlockEntityRenderer
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider
import net.minecraft.client.renderer.texture.OverlayTexture
import net.minecraft.core.Direction
import ru.dbotthepony.mc.otm.TranslatableComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.block.BlackHoleBlock
import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock
import ru.dbotthepony.mc.otm.block.entity.GravitationStabilizerBlockEntity
import ru.dbotthepony.mc.otm.block.entity.blackhole.BlackHoleBlockEntity
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState
import ru.dbotthepony.mc.otm.block.entity.WorkerState
import ru.dbotthepony.mc.otm.client.render.*
import ru.dbotthepony.mc.otm.core.*
import kotlin.math.PI

View File

@ -7,16 +7,14 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap
import it.unimi.dsi.fastutil.ints.Int2ObjectFunction
import net.minecraft.ChatFormatting
import net.minecraft.client.Minecraft
import net.minecraft.client.resources.sounds.SimpleSoundInstance
import net.minecraft.network.chat.Component
import net.minecraft.sounds.SoundEvents
import net.minecraft.world.entity.player.Inventory
import ru.dbotthepony.mc.otm.TranslatableComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.android.AndroidResearch
import ru.dbotthepony.mc.otm.android.AndroidResearchType
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.client.playGuiClickSound
import ru.dbotthepony.mc.otm.client.render.Widgets18
import ru.dbotthepony.mc.otm.client.render.drawColor
import ru.dbotthepony.mc.otm.client.render.drawLine
@ -24,7 +22,7 @@ import ru.dbotthepony.mc.otm.client.render.drawRect
import ru.dbotthepony.mc.otm.client.screen.panels.*
import ru.dbotthepony.mc.otm.client.screen.widget.WidePowerGaugePanel
import ru.dbotthepony.mc.otm.core.RGBAColor
import ru.dbotthepony.mc.otm.ifPresentK
import ru.dbotthepony.mc.otm.core.ifPresentK
import ru.dbotthepony.mc.otm.menu.AndroidStationMenu
import ru.dbotthepony.mc.otm.network.MatteryPlayerNetworkChannel
import ru.dbotthepony.mc.otm.network.AndroidResearchRequestPacket
@ -383,7 +381,7 @@ private class AndroidResearchButton(
MatteryPlayerNetworkChannel.sendToServer(AndroidResearchRequestPacket(node.type))
}
minecraft.soundManager.play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0f))
playGuiClickSound()
}
return true
@ -479,6 +477,7 @@ class AndroidStationScreen constructor(p_97741_: AndroidStationMenu, p_97742_: I
override fun mouseClickedInner(x: Double, y: Double, button: Int): Boolean {
if (isPreview) {
playGuiClickSound()
openResearchTree()
return true
}

View File

@ -2,9 +2,8 @@ package ru.dbotthepony.mc.otm.client.screen
import net.minecraft.network.chat.Component
import net.minecraft.world.entity.player.Inventory
import ru.dbotthepony.mc.otm.TranslatableComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.client.screen.panels.*
import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.WidePowerGaugePanel
import ru.dbotthepony.mc.otm.menu.ChemicalGeneratorMenu

View File

@ -4,9 +4,10 @@ import com.mojang.blaze3d.vertex.PoseStack
import net.minecraft.network.chat.Component
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.item.ItemStack
import ru.dbotthepony.mc.otm.TranslatableComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.client.screen.panels.*
import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel
import ru.dbotthepony.mc.otm.core.maxScrollDivision
import ru.dbotthepony.mc.otm.item.PortableCondensationDriveItem
import ru.dbotthepony.mc.otm.menu.DriveViewerMenu
@ -51,15 +52,15 @@ class DriveViewerScreen(menu: DriveViewerMenu, inventory: Inventory, title: Comp
val grid = GridPanel(this, frame, 28f, 16f, GRID_WIDTH * 18f, GRID_HEIGHT * 18f, GRID_WIDTH, GRID_HEIGHT)
val scrollBar = ContinuousScrollBarPanel(this, frame, 192f, 14f, 92f)
scrollBar.setupRowMultiplier { menu.networkedItemView.itemCount / GRID_WIDTH }
val scrollBar = DiscreteScrollBarPanel(this, frame, { maxScrollDivision(menu.networkedItemView.itemCount, GRID_WIDTH) }, { _, _, _ -> }, 192f, 14f, 92f)
views.add(grid)
views.add(scrollBar)
for (i in 0 until GRID_WIDTH * GRID_HEIGHT) {
object : AbstractSlotPanel(this@DriveViewerScreen, grid, 0f, 0f) {
override fun getItemStack(): ItemStack {
val index = i + scrollBar.getScroll(menu.networkedItemView.sortedView.size / GRID_WIDTH)
val index = i + scrollBar.scroll * GRID_WIDTH
return menu.networkedItemView.sortedView.getOrNull(index)?.stack?.item ?: ItemStack.EMPTY
}
@ -68,7 +69,7 @@ class DriveViewerScreen(menu: DriveViewerMenu, inventory: Inventory, title: Comp
}
override fun mouseClickedInner(x: Double, y: Double, button: Int): Boolean {
val index = i + scrollBar.getScroll(GRID_WIDTH)
val index = i + scrollBar.scroll * GRID_WIDTH
menu.networkedItemView.mouseClick(index, button)
return true
}
@ -81,7 +82,7 @@ class DriveViewerScreen(menu: DriveViewerMenu, inventory: Inventory, title: Comp
override fun getItemStackTooltip(stack: ItemStack): List<Component> {
return super.getItemStackTooltip(stack).also {
it as MutableList<Component>
val index = i + scrollBar.getScroll(menu.networkedItemView.sortedView.size / GRID_WIDTH)
val index = i + scrollBar.scroll * GRID_WIDTH
val realStack = menu.networkedItemView.sortedView.getOrNull(index)!!.stack
it.add(TranslatableComponent("otm.gui.item_amount", realStack.count.toString()))
}

View File

@ -2,7 +2,7 @@ package ru.dbotthepony.mc.otm.client.screen
import net.minecraft.network.chat.Component
import net.minecraft.world.entity.player.Inventory
import ru.dbotthepony.mc.otm.TranslatableComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.client.screen.panels.*
import ru.dbotthepony.mc.otm.core.formatPower
import ru.dbotthepony.mc.otm.menu.EnergyCounterMenu

View File

@ -3,9 +3,8 @@ package ru.dbotthepony.mc.otm.client.screen
import com.mojang.blaze3d.vertex.PoseStack
import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap
import it.unimi.dsi.fastutil.ints.Int2ObjectFunction
import net.minecraft.client.gui.screens.inventory.InventoryScreen
import net.minecraft.world.inventory.Slot
import ru.dbotthepony.mc.otm.TranslatableComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.client.render.element
import ru.dbotthepony.mc.otm.client.screen.panels.*
import ru.dbotthepony.mc.otm.menu.ExoSuitInventoryMenu
@ -13,36 +12,6 @@ import ru.dbotthepony.mc.otm.network.ExoSuitMenuOpen
import ru.dbotthepony.mc.otm.network.MatteryPlayerNetworkChannel
class ExoSuitInventoryScreen(menu: ExoSuitInventoryMenu) : MatteryScreen<ExoSuitInventoryMenu>(menu, TranslatableComponent("otm.gui.exosuit")) {
private val slotRows = Int2ObjectAVLTreeMap<EditablePanel>()
private fun getSlotsRow(index: Int): EditablePanel {
return slotRows.computeIfAbsent(index, Int2ObjectFunction {
val canvas = object : EditablePanel(this@ExoSuitInventoryScreen, null, width = AbstractSlotPanel.SIZE * 9f, height = AbstractSlotPanel.SIZE) {
override fun mouseScrolledInner(x: Double, y: Double, scroll: Double): Boolean {
return false
}
}
val offset = it * 9
if (menu.combinedInventorySlots.size <= offset) {
return@Int2ObjectFunction canvas
}
for (i in 0 .. (8).coerceAtMost(menu.combinedInventorySlots.size - offset - 1)) {
val slot = object : SlotPanel<Slot>(this@ExoSuitInventoryScreen, canvas, menu.combinedInventorySlots[offset + i]) {
override fun mouseScrolledInner(x: Double, y: Double, scroll: Double): Boolean {
return false
}
}
slot.dock = Dock.LEFT
}
return@Int2ObjectFunction canvas
})
}
override fun makeMainFrame(): FramePanel {
val frame = FramePanel(this, width = 200f, height = 180f, title = this.title)
@ -53,16 +22,16 @@ class ExoSuitInventoryScreen(menu: ExoSuitInventoryMenu) : MatteryScreen<ExoSuit
var mainInventoryLine: EditablePanel? = null
val scrollPanel = DiscreteScrollBarPanel(this, null, maxScroll = { ((menu.combinedInventorySlots.size - 27) + 8) / 9 },
val scrollPanel = DiscreteScrollBarPanel(this, null, maxScroll = { ((menu.playerCombinedInventorySlots.size - 27) + 8) / 9 },
scrollCallback = {
_, old, new ->
for (i in old .. old + 2) {
getSlotsRow(i).visible = false
getInventorySlotsRow(i).visible = false
}
for (i in new .. new + 2) {
val row = getSlotsRow(i)
val row = getInventorySlotsRow(i)
row.visible = true
row.y = (i - new) * AbstractSlotPanel.SIZE
row.parent = mainInventoryLine
@ -83,7 +52,7 @@ class ExoSuitInventoryScreen(menu: ExoSuitInventoryMenu) : MatteryScreen<ExoSuit
mainInventoryLine.dock = Dock.BOTTOM
for (slot in menu.hotbarSlots) {
for (slot in menu.playerHotbarSlots) {
val panel = SlotPanel(this, toolbeltLine, slot)
panel.dock = Dock.LEFT
}
@ -92,7 +61,7 @@ class ExoSuitInventoryScreen(menu: ExoSuitInventoryMenu) : MatteryScreen<ExoSuit
offhand.dock = Dock.RIGHT
for (i in scrollPanel.scroll .. scrollPanel.scroll + 2) {
getSlotsRow(i).also {
getInventorySlotsRow(i).also {
it.parent = mainInventoryLine
it.y = AbstractSlotPanel.SIZE * (i - scrollPanel.scroll)
}

View File

@ -8,13 +8,14 @@ import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import org.lwjgl.opengl.GL11
import ru.dbotthepony.mc.otm.TranslatableComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.block.entity.storage.ItemMonitorPlayerSettings
import ru.dbotthepony.mc.otm.client.render.UVWindingOrder
import ru.dbotthepony.mc.otm.client.render.Widgets8
import ru.dbotthepony.mc.otm.client.screen.panels.*
import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel
import ru.dbotthepony.mc.otm.core.equalDownDivision
import ru.dbotthepony.mc.otm.client.screen.widget.TallHorizontalPowerGaugePanel
import ru.dbotthepony.mc.otm.core.maxScrollDivision
import ru.dbotthepony.mc.otm.core.formatReadableNumber
import ru.dbotthepony.mc.otm.core.formatSiComponent
import ru.dbotthepony.mc.otm.menu.ItemMonitorMenu
@ -24,7 +25,7 @@ class ItemMonitorScreen(menu: ItemMonitorMenu, inventory: Inventory, title: Comp
MatteryScreen<ItemMonitorMenu>(menu, inventory, title) {
override fun makeMainFrame(): FramePanel {
val frame = FramePanel(this@ItemMonitorScreen, null, 0f, 0f, FRAME_WIDTH, FRAME_HEIGHT, getTitle())
val frame = FramePanel(this@ItemMonitorScreen, null, 0f, 0f, 1f, 1f, getTitle())
val topPanel = EditablePanel(this, frame)
topPanel.height = ITEM_GRID_HEIGHT * 18f
@ -35,11 +36,13 @@ class ItemMonitorScreen(menu: ItemMonitorMenu, inventory: Inventory, title: Comp
bottomPanel.dock = Dock.TOP
bottomPanel.setDockMargin(top = 6f)
frame.height = topPanel.height + bottomPanel.height + frame.dockPadding.top + frame.dockPadding.bottom + 6f
frame.height = topPanel.height + bottomPanel.height + frame.dockPadding.top + frame.dockPadding.bottom + 26f
frame.width = 178f + frame.dockPadding.left + frame.dockPadding.right
val viewScrollBar = ContinuousScrollBarPanel(this, topPanel, 28f + ITEM_GRID_WIDTH * 18f + 2f, 16f, ITEM_GRID_HEIGHT * 18f)
viewScrollBar.setupRowMultiplier { equalDownDivision(menu.networkedItemView.itemCount, ITEM_GRID_WIDTH) }
val viewScrollBar = DiscreteScrollBarPanel(this, topPanel,
{ maxScrollDivision(menu.networkedItemView.itemCount, ITEM_GRID_WIDTH) },
{ _, _, _ -> },
28f + ITEM_GRID_WIDTH * 18f + 2f, 16f, ITEM_GRID_HEIGHT * 18f)
viewScrollBar.dock = Dock.RIGHT
viewScrollBar.setDockMargin(left = 2f)
@ -49,7 +52,7 @@ class ItemMonitorScreen(menu: ItemMonitorMenu, inventory: Inventory, title: Comp
for (i in 0 until ITEM_GRID_WIDTH * ITEM_GRID_HEIGHT) {
object : AbstractSlotPanel(this@ItemMonitorScreen, gridPanel) {
private val index get() = i + viewScrollBar.getScroll(equalDownDivision(menu.networkedItemView.itemCount, ITEM_GRID_WIDTH)) * ITEM_GRID_WIDTH
private val index get() = i + viewScrollBar.scroll * ITEM_GRID_WIDTH
override fun getItemStack(): ItemStack {
return menu.networkedItemView.sortedView.getOrNull(index)?.stack?.item ?: ItemStack.EMPTY
@ -116,7 +119,7 @@ class ItemMonitorScreen(menu: ItemMonitorMenu, inventory: Inventory, title: Comp
arrowAndButtons.dock = Dock.LEFT
arrowAndButtons.setDockMargin(left = 4f)
val arrowLineTop = EditablePanel(this, arrowAndButtons, y = 0f, height = 8f, width = arrowAndButtons.width)
EditablePanel(this, arrowAndButtons, y = 0f, height = 8f, width = arrowAndButtons.width)
val arrowLine = EditablePanel(this, arrowAndButtons, y = 38f, height = 8f, width = arrowAndButtons.width)
@ -168,7 +171,7 @@ class ItemMonitorScreen(menu: ItemMonitorMenu, inventory: Inventory, title: Comp
craftingHistory.dock = Dock.LEFT
craftingHistory.setDockMargin(left = 4f)
val craftingHistoryScroll = ContinuousScrollBarPanel(this, bottomPanel, 0f, 0f, 0f)
val craftingHistoryScroll = DiscreteScrollBarPanel(this, bottomPanel, { 0 }, { _, _, _ -> })
craftingHistoryScroll.dock = Dock.LEFT
craftingHistoryScroll.setDockMargin(left = 2f)
@ -184,13 +187,23 @@ class ItemMonitorScreen(menu: ItemMonitorMenu, inventory: Inventory, title: Comp
}
}
val bottomStrip = EditablePanel(this, frame, height = AbstractSlotPanel.SIZE)
bottomStrip.dock = Dock.BOTTOM
BatterySlotPanel(this, bottomStrip, menu.batterySlot).also {
it.dock = Dock.LEFT
it.dockRight = 3f
}
TallHorizontalPowerGaugePanel(this, bottomStrip, menu.powerWidget).also {
it.dock = Dock.FILL
it.dockResize = DockResizeMode.NONE
}
return frame
}
companion object {
const val FRAME_WIDTH = 240f
const val FRAME_HEIGHT = 210f
const val ITEM_GRID_WIDTH = 9
const val ITEM_GRID_HEIGHT = 5

View File

@ -2,7 +2,7 @@ package ru.dbotthepony.mc.otm.client.screen
import net.minecraft.network.chat.Component
import net.minecraft.world.entity.player.Inventory
import ru.dbotthepony.mc.otm.TranslatableComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.client.screen.panels.*
import ru.dbotthepony.mc.otm.client.screen.widget.MatterGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel

View File

@ -0,0 +1,295 @@
package ru.dbotthepony.mc.otm.client.screen
import net.minecraft.ChatFormatting
import net.minecraft.client.gui.components.EditBox
import net.minecraft.network.chat.Component
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.item.ItemStack
import ru.dbotthepony.mc.otm.capability.matter.IPatternState
import ru.dbotthepony.mc.otm.capability.matter.IReplicationTask
import ru.dbotthepony.mc.otm.capability.matter.PatternState
import ru.dbotthepony.mc.otm.client.screen.panels.*
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.maxScrollDivision
import ru.dbotthepony.mc.otm.menu.MatterPanelMenu
import ru.dbotthepony.mc.otm.menu.ReplicationRequestPacket
import ru.dbotthepony.mc.otm.network.MenuNetworkChannel
class MatterPanelScreen(
menu: MatterPanelMenu,
inventory: Inventory,
title: Component
) : MatteryScreen<MatterPanelMenu>(menu, inventory, title) {
override fun makeMainFrame(): FramePanel {
var isPatternView = true
val frame = FramePanel.padded(this, null, GRID_WIDTH * AbstractSlotPanel.SIZE + ScrollBarConstants.WIDTH + 4f, GRID_HEIGHT * AbstractSlotPanel.SIZE, title)
val scrollBar = DiscreteScrollBarPanel(this, frame, {
if (isPatternView) {
maxScrollDivision(menu.patterns.size, GRID_WIDTH)
} else {
maxScrollDivision(menu.tasks.size, GRID_WIDTH)
}
}, { _, _, _ -> })
scrollBar.dock = Dock.RIGHT
frame.addTab(FramePanel.Position.TOP, open = { isPatternView = true })
frame.addTab(FramePanel.Position.TOP, open = { isPatternView = false })
val canvas = object : EditablePanel(this@MatterPanelScreen, frame, width = GRID_WIDTH * AbstractSlotPanel.SIZE) {
init {
dock = Dock.LEFT
}
override fun mouseScrolledInner(x: Double, y: Double, scroll: Double): Boolean {
return scrollBar.mouseScrolledInner(x, y, scroll)
}
}
for (row in 0 until GRID_HEIGHT) {
val rowCanvas = object : EditablePanel(this@MatterPanelScreen, canvas, height = AbstractSlotPanel.SIZE) {
init {
dock = Dock.TOP
}
override fun mouseScrolledInner(x: Double, y: Double, scroll: Double): Boolean {
return false
}
}
for (i in 0 until GRID_WIDTH) {
object : AbstractSlotPanel(this@MatterPanelScreen, rowCanvas) {
init {
dock = Dock.LEFT
}
private val index: Int get() = (scrollBar.scroll + row) * GRID_WIDTH + i
override fun getItemStack(): ItemStack {
if (isPatternView) {
return menu.patterns.getOrNull(index)?.stack() ?: ItemStack.EMPTY
} else {
return menu.tasks.getOrNull(index)?.let { it.stack(it.required + it.inProgress) } ?: ItemStack.EMPTY
}
}
override fun getItemStackTooltip(stack: ItemStack): List<Component> {
val list = super.getItemStackTooltip(stack).toMutableList()
if (isPatternView) {
menu.patterns.getOrNull(index)?.let {
list.add(TranslatableComponent(
"otm.item.pattern.research",
String.format("%.2f", it.researchPercent * 100.0)
).withStyle(ChatFormatting.AQUA)) }
} else {
menu.tasks.getOrNull(index)?.let {
list.add(TranslatableComponent("otm.gui.matter_task.total", it.total).withStyle(ChatFormatting.GRAY))
list.add(TranslatableComponent("otm.gui.matter_task.required", it.required).withStyle(ChatFormatting.GRAY))
list.add(TranslatableComponent("otm.gui.matter_task.in_progress", it.inProgress).withStyle(ChatFormatting.GRAY))
list.add(TranslatableComponent("otm.gui.matter_task.finished", it.finished).withStyle(ChatFormatting.GRAY))
}
}
return list
}
override fun mouseClickedInner(x: Double, y: Double, button: Int): Boolean {
if (isPatternView) {
menu.patterns.getOrNull(index)?.let(this@MatterPanelScreen::openPattern)
} else {
menu.tasks.getOrNull(index)?.let(this@MatterPanelScreen::openTask)
}
return true
}
override fun mouseScrolledInner(x: Double, y: Double, scroll: Double): Boolean {
return false
}
}
}
}
return frame
}
private fun openTask(task: IReplicationTask<*>) {
val frame = FramePanel.padded(this, null, 170f, 20f, TranslatableComponent("otm.container.matter_panel.task"))
object : AbstractSlotPanel(this@MatterPanelScreen, frame) {
init {
dock = Dock.LEFT
}
override fun getItemStack(): ItemStack {
return menu.tasks.firstOrNull { it.id == task.id }?.let { it.stack((it.required + it.inProgress).coerceAtLeast(1)) } ?: task.stack((task.required + task.inProgress).coerceAtLeast(1))
}
override fun tick() {
super.tick()
if (!menu.tasks.any { it.id == task.id }) {
frame.remove()
}
}
}
ButtonPanel(this@MatterPanelScreen, frame, width = 40f, label = TranslatableComponent("otm.container.matter_panel.close"), onPress = frame::remove).also {
it.dock = Dock.RIGHT
it.dockLeft = 2f
}
ButtonPanel(this@MatterPanelScreen, frame, width = 80f, label = TranslatableComponent("otm.container.matter_panel.cancel_task"), onPress = {
menu.requestTaskCancel(task.id)
frame.remove()
}).also {
it.dock = Dock.RIGHT
it.dockLeft = 2f
}
addPanel(frame)
popup(frame)
frame.toScreenCenter()
}
private fun openPattern(pattern: IPatternState) {
val frame = FramePanel.padded(this, null, 213f, (ButtonPanel.HEIGHT + 3f) * 4f, TranslatableComponent("otm.container.matter_panel.task"))
val rowTop = EditablePanel(this, frame, height = ButtonPanel.HEIGHT)
val rowInput = EditablePanel(this, frame, height = ButtonPanel.HEIGHT)
val rowBottom = EditablePanel(this, frame, height = ButtonPanel.HEIGHT)
val rowControls = EditablePanel(this, frame, height = ButtonPanel.HEIGHT)
rowTop.dock = Dock.TOP
rowTop.dockTop = 3f
rowInput.dock = Dock.TOP
rowInput.dockTop = 3f
rowBottom.dock = Dock.TOP
rowBottom.dockTop = 3f
rowControls.dock = Dock.TOP
rowControls.dockTop = 3f
object : AbstractSlotPanel(this@MatterPanelScreen, rowInput) {
init {
dock = Dock.LEFT
dockRight = 2f
}
override fun getItemStack(): ItemStack {
return pattern.stack()
}
override fun getItemStackTooltip(stack: ItemStack): List<Component> {
return super.getItemStackTooltip(stack).toMutableList().also {
it.add(TranslatableComponent(
"otm.item.pattern.research",
String.format("%.2f", pattern.researchPercent * 100.0)
).withStyle(ChatFormatting.AQUA))
}
}
override fun tick() {
super.tick()
if (!menu.patterns.any { it.id == pattern.id }) {
frame.remove()
}
}
}
val input = object : EditBoxPanel(this@MatterPanelScreen, rowInput) {
init {
dock = Dock.FILL
}
override fun configureNew(widget: EditBox, recreation: Boolean) {
super.configureNew(widget, recreation)
widget.setMaxLength(6)
if (!recreation) {
widget.value = "1"
}
}
fun increase(amount: Int) {
var value = 1
try {
value = getOrCreateWidget().value.toInt()
} catch (_: NumberFormatException) {
}
if (value == 1 && amount > 0)
getOrCreateWidget().value = amount.toString()
else
getOrCreateWidget().value = 1.coerceAtLeast(99999.coerceAtMost(value + amount)).toString()
}
fun send() {
var value = 1
try {
value = getOrCreateWidget().value.toInt()
} catch (_: NumberFormatException) {
}
MenuNetworkChannel.sendToServer(ReplicationRequestPacket(pattern.id, value))
frame.remove()
}
}
ButtonPanel(this, rowTop, width = 40f, label = TranslatableComponent("otm.container.matter_panel.increase_by", 8), onPress = { input.increase(8) }).also {
it.dock = Dock.RIGHT
it.dockLeft = 2f
}
ButtonPanel(this, rowTop, width = 40f, label = TranslatableComponent("otm.container.matter_panel.increase_by", 64), onPress = { input.increase(64) }).also {
it.dock = Dock.RIGHT
it.dockLeft = 2f
}
ButtonPanel(this, rowTop, width = 40f, label = TranslatableComponent("otm.container.matter_panel.increase_by", 256), onPress = { input.increase(256) }).also {
it.dock = Dock.RIGHT
it.dockLeft = 2f
}
ButtonPanel(this, rowBottom, width = 40f, label = TranslatableComponent("otm.container.matter_panel.decrease_by", 8), onPress = { input.increase(-8) }).also {
it.dock = Dock.RIGHT
it.dockLeft = 2f
}
ButtonPanel(this, rowBottom, width = 40f, label = TranslatableComponent("otm.container.matter_panel.decrease_by", 64), onPress = { input.increase(-64) }).also {
it.dock = Dock.RIGHT
it.dockLeft = 2f
}
ButtonPanel(this, rowBottom, width = 40f, label = TranslatableComponent("otm.container.matter_panel.decrease_by", 256), onPress = { input.increase(-256) }).also {
it.dock = Dock.RIGHT
it.dockLeft = 2f
}
ButtonPanel(this, rowControls, width = 40f, label = TranslatableComponent("otm.container.matter_panel.cancel"), onPress = frame::remove).also {
it.dock = Dock.RIGHT
it.dockLeft = 2f
}
ButtonPanel(this, rowControls, width = 82f, label = TranslatableComponent("otm.container.matter_panel.send"), onPress = input::send).also {
it.dock = Dock.RIGHT
it.dockLeft = 2f
}
addPanel(frame)
popup(frame)
frame.toScreenCenter()
}
companion object {
const val GRID_HEIGHT = 8
const val GRID_WIDTH = 9
}
}

View File

@ -2,6 +2,8 @@ package ru.dbotthepony.mc.otm.client.screen
import com.mojang.blaze3d.systems.RenderSystem
import com.mojang.blaze3d.vertex.PoseStack
import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap
import it.unimi.dsi.fastutil.ints.Int2ObjectFunction
import net.minecraft.ChatFormatting
import net.minecraft.client.gui.Font
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen
@ -14,9 +16,8 @@ import net.minecraftforge.client.event.ContainerScreenEvent.Render.Foreground
import net.minecraftforge.common.MinecraftForge
import org.lwjgl.opengl.GL11
import org.lwjgl.opengl.GL13
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel
import ru.dbotthepony.mc.otm.client.screen.panels.SlotPanel
import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.client.screen.panels.*
import ru.dbotthepony.mc.otm.menu.MatteryMenu
/**
@ -50,16 +51,108 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
val quickCraftingType get() = quickCraftingType
val isQuickCrafting get() = isQuickCrafting
private val inventorySlotsRows = Int2ObjectAVLTreeMap<EditablePanel>()
init {
if (menu.playerInventorySlots.isNotEmpty() && menu.autoCreateInventoryFrame) {
inventoryFrame = FramePanel(this, null, 0f, 0f, INVENTORY_FRAME_WIDTH, INVENTORY_FRAME_HEIGHT, inventory.displayName).also(this::addPanel)
if (menu.playerExoSuitSlots.isEmpty()) {
inventoryFrame = FramePanel(this, null, 0f, 0f, INVENTORY_FRAME_WIDTH, INVENTORY_FRAME_HEIGHT, inventory.displayName).also(this::addPanel)
for (slot in menu.playerInventorySlots) {
SlotPanel(this, inventoryFrame, slot, slot.x.toFloat(), slot.y.toFloat())
val hotbarStrip = EditablePanel(this, inventoryFrame, height = AbstractSlotPanel.SIZE)
hotbarStrip.dock = Dock.BOTTOM
for (slot in menu.playerHotbarSlots) {
SlotPanel(this, hotbarStrip, slot).also { it.dock = Dock.LEFT }
}
for (i in 0 .. 2) {
getInventorySlotsRow(i).also {
it.parent = inventoryFrame
it.y = i * AbstractSlotPanel.SIZE
}
}
} else {
inventoryFrame = FramePanel(this, null, 0f, 0f, INVENTORY_FRAME_WIDTH_EXTENDED, INVENTORY_FRAME_HEIGHT, inventory.displayName).also(this::addPanel)
var slotListCanvas: EditablePanel? = null
val scrollbar = DiscreteScrollBarPanel(this, inventoryFrame, { ((menu.playerCombinedInventorySlots.size - 27) + 8) / 9 }, {
_, old, new ->
for (i in old .. old + 2) {
getInventorySlotsRow(i).visible = false
}
for (i in new .. new + 2) {
getInventorySlotsRow(i).also {
it.visible = true
it.parent = slotListCanvas
it.y = (i - new) * AbstractSlotPanel.SIZE
}
}
menu.ply.matteryPlayer?.exoSuitMenu?.lastScroll = new
})
slotListCanvas = object : EditablePanel(this@MatteryScreen, inventoryFrame, height = AbstractSlotPanel.SIZE * 3f) {
override fun mouseScrolledInner(x: Double, y: Double, scroll: Double): Boolean {
scrollbar.mouseScrolledInner(x, y, scroll)
return true
}
}
slotListCanvas.dock = Dock.TOP
val hotbarStrip = EditablePanel(this, inventoryFrame, height = AbstractSlotPanel.SIZE)
hotbarStrip.dock = Dock.BOTTOM
for (slot in menu.playerHotbarSlots) {
SlotPanel(this, hotbarStrip, slot).also { it.dock = Dock.LEFT }
}
scrollbar.parent = slotListCanvas
scrollbar.dock = Dock.RIGHT
scrollbar.scroll = menu.ply.matteryPlayer?.exoSuitMenu?.lastScroll ?: 0
for (i in scrollbar.scroll .. scrollbar.scroll + 2) {
getInventorySlotsRow(i).also {
it.parent = slotListCanvas
it.y = (i - scrollbar.scroll) * AbstractSlotPanel.SIZE
}
}
}
}
}
protected fun getInventorySlotsRow(index: Int): EditablePanel {
return inventorySlotsRows.computeIfAbsent(index, Int2ObjectFunction {
val canvas = object : EditablePanel(this@MatteryScreen, null, width = AbstractSlotPanel.SIZE * 9f, height = AbstractSlotPanel.SIZE) {
override fun mouseScrolledInner(x: Double, y: Double, scroll: Double): Boolean {
return false
}
}
val offset = it * 9
if (menu.playerCombinedInventorySlots.size <= offset) {
return@Int2ObjectFunction canvas
}
for (i in 0 .. (8).coerceAtMost(menu.playerCombinedInventorySlots.size - offset - 1)) {
val slot = object : SlotPanel<Slot>(this@MatteryScreen, canvas, menu.playerCombinedInventorySlots[offset + i]) {
override fun mouseScrolledInner(x: Double, y: Double, scroll: Double): Boolean {
return false
}
}
slot.dock = Dock.LEFT
}
return@Int2ObjectFunction canvas
})
}
override fun init() {
super.init()
@ -102,7 +195,7 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
require(indexOf != -1) { "No such panel $panel" }
if (indexOf == panels.size - 1) {
if (indexOf == 0) {
return
}
@ -354,10 +447,13 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
}
companion object {
const val DEFAULT_FRAME_WIDTH = 18f * 9f + 16f
const val DEFAULT_FRAME_WIDTH = AbstractSlotPanel.SIZE * 9f + 16f
const val DEFAULT_FRAME_HEIGHT = 100f
const val INVENTORY_FRAME_WIDTH = DEFAULT_FRAME_WIDTH
const val INVENTORY_FRAME_HEIGHT = 3f * 18f + 18f + 24f
const val INVENTORY_FRAME_WIDTH_EXTENDED = DEFAULT_FRAME_WIDTH + ScrollBarConstants.WIDTH + 2f
const val INVENTORY_FRAME_HEIGHT = 3f * AbstractSlotPanel.SIZE + AbstractSlotPanel.SIZE + 24f
const val GAUGE_TOP_WITH_SLOT = 17f
const val GAUGE_TOP_WITHOUT_SLOT = 26f
const val SLOT_TOP_UNDER_GAUGE = 70f

View File

@ -2,9 +2,8 @@ package ru.dbotthepony.mc.otm.client.screen
import net.minecraft.network.chat.Component
import net.minecraft.world.entity.player.Inventory
import ru.dbotthepony.mc.otm.TranslatableComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.client.screen.panels.*
import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.WidePowerGaugePanel
import ru.dbotthepony.mc.otm.menu.StorageBusMenu

View File

@ -2,9 +2,8 @@ package ru.dbotthepony.mc.otm.client.screen
import net.minecraft.network.chat.Component
import net.minecraft.world.entity.player.Inventory
import ru.dbotthepony.mc.otm.TranslatableComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.client.screen.panels.*
import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.WidePowerGaugePanel
import ru.dbotthepony.mc.otm.menu.StorageExporterMenu

View File

@ -2,9 +2,8 @@ package ru.dbotthepony.mc.otm.client.screen
import net.minecraft.network.chat.Component
import net.minecraft.world.entity.player.Inventory
import ru.dbotthepony.mc.otm.TranslatableComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.client.screen.panels.*
import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.WidePowerGaugePanel
import ru.dbotthepony.mc.otm.menu.StorageImporterMenu

View File

@ -2,10 +2,9 @@ package ru.dbotthepony.mc.otm.client.screen
import net.minecraft.network.chat.Component
import net.minecraft.world.entity.player.Inventory
import ru.dbotthepony.mc.otm.TranslatableComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.client.screen.panels.*
import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.WidePowerGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.HorizontalPowerGaugePanel
import ru.dbotthepony.mc.otm.core.formatPower
import ru.dbotthepony.mc.otm.menu.StoragePowerSupplierMenu
@ -13,12 +12,32 @@ import ru.dbotthepony.mc.otm.menu.StoragePowerSupplierMenu
class StoragePowerSupplierScreen(menu: StoragePowerSupplierMenu, inventory: Inventory, title: Component) :
MatteryScreen<StoragePowerSupplierMenu>(menu, inventory, title) {
override fun makeMainFrame(): FramePanel {
val frame = super.makeMainFrame()!!
val frame = FramePanel(this, width = 200f, height = 60f, title)
WidePowerGaugePanel(this, frame, menu.powerWidget, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT)
BatterySlotPanel(this, frame, menu.batterySlot, LEFT_MARGIN, SLOT_TOP_UNDER_GAUGE)
HorizontalPowerGaugePanel(this, frame, menu.powerWidget).also {
it.dock = Dock.BOTTOM
it.dockResize = DockResizeMode.NONE
}
val topStrip = EditablePanel(this, frame, height = AbstractSlotPanel.SIZE)
topStrip.dock = Dock.TOP
topStrip.dockTop = 3f
BatterySlotPanel(this, topStrip, menu.batterySlot).also {
it.dock = Dock.LEFT
it.dockRight = 3f
}
val labels = EditablePanel(this, topStrip)
labels.dock = Dock.FILL
object : Label(this@StoragePowerSupplierScreen, labels) {
init {
dock = Dock.TOP
}
object : Label(this@StoragePowerSupplierScreen, frame, 28f, 17f, width = 140f) {
override fun tick() {
super.tick()
@ -29,6 +48,21 @@ class StoragePowerSupplierScreen(menu: StoragePowerSupplierMenu, inventory: Inve
}
}
object : Label(this@StoragePowerSupplierScreen, labels) {
init {
dock = Dock.TOP
}
override fun tick() {
super.tick()
text = TranslatableComponent(
"otm.gui.power_supplier.active_nodes",
menu.activeNodes
)
}
}
return frame
}
}

View File

@ -23,9 +23,8 @@ abstract class AbstractSlotPanel @JvmOverloads constructor(
) : EditablePanel(
screen, parent, x, y, width, height
) {
protected open fun renderSlotBackground(stack: PoseStack, mouse_x: Float, mouse_y: Float, flag: Float) {
RenderSystem.setShaderTexture(0, WidgetLocation.WIDGETS)
drawTexturedRectAuto(stack, 0f, 0f, 18f, 18f, 0f, 96f, 256f, 256f)
protected open fun renderSlotBackground(stack: PoseStack, mouseX: Float, mouseY: Float, partialTick: Float) {
SLOT_BACKGROUND.render(stack, width = width, height = height)
}
protected open fun renderRegular(stack: PoseStack, itemstack: ItemStack, count_override: String? = null) {
@ -119,10 +118,9 @@ abstract class AbstractSlotPanel @JvmOverloads constructor(
}
companion object {
@JvmField
val SLOT_HIGHLIGHT = RGBAColor(255, 255, 255, 100)
@JvmField
val SLOT_HIGHLIGHT_DRAG = RGBAColor(200, 200, 200, 150)
const val SIZE = 18f
val SLOT_BACKGROUND = WidgetLocation.WIDGETS.element(0f, 0f, SIZE, SIZE)
}
}
}

View File

@ -5,15 +5,13 @@ import com.mojang.blaze3d.vertex.PoseStack
import net.minecraft.ChatFormatting
import net.minecraft.client.gui.components.Button
import net.minecraft.client.gui.components.Button.OnPress
import net.minecraft.client.resources.sounds.SimpleSoundInstance
import net.minecraft.network.chat.Component
import net.minecraft.sounds.SoundEvents
import ru.dbotthepony.mc.otm.TextComponent
import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.client.playGuiClickSound
import ru.dbotthepony.mc.otm.core.TextComponent
import ru.dbotthepony.mc.otm.client.render.*
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
import ru.dbotthepony.mc.otm.next
import ru.dbotthepony.mc.otm.prev
import ru.dbotthepony.mc.otm.core.next
import ru.dbotthepony.mc.otm.core.prev
import java.util.*
import kotlin.collections.ArrayList
import kotlin.reflect.KMutableProperty0
@ -24,10 +22,22 @@ open class ButtonPanel(
x: Float = 0f,
y: Float = 0f,
width: Float = 40f,
height: Float = 20f,
height: Float = HEIGHT,
label: Component
) : MinecraftWidgetPanel<Button>(screen, parent, x, y, width, height) {
constructor(screen: MatteryScreen<*>, parent: EditablePanel?, label: Component) : this(screen, parent, x = 0f, label = label)
constructor(
screen: MatteryScreen<*>,
parent: EditablePanel?,
x: Float = 0f,
y: Float = 0f,
width: Float = 40f,
height: Float = HEIGHT,
label: Component,
onPress: Runnable
) : this(screen, parent, x, y, width, height, label) {
this.callback = onPress
}
var label = label
set(value) {
@ -55,6 +65,10 @@ open class ButtonPanel(
protected open fun onPress() {
callback?.run()
}
companion object {
const val HEIGHT = 20f
}
}
@Suppress("PropertyName")
@ -105,7 +119,7 @@ abstract class SquareButtonPanel(
override fun mouseClickedInner(x: Double, y: Double, button: Int): Boolean {
if (!isDisabled) {
if (!pressed) {
minecraft.soundManager.play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0f))
playGuiClickSound()
}
pressed = true

Some files were not shown because too many files have changed in this diff Show More