From 16515ecc92b9485f779458ed8fff09db6d288449 Mon Sep 17 00:00:00 2001 From: YuRaNnNzZZ Date: Wed, 9 Apr 2025 00:36:49 +0300 Subject: [PATCH 01/11] iron chests --- build.gradle.kts | 4 + .../CopperChestBlockEntityMixin.java | 16 ++++ .../CrystalChestBlockEntityMixin.java | 16 ++++ .../DiamondChestBlockEntityMixin.java | 16 ++++ .../ironchest/DirtChestBlockEntityMixin.java | 16 ++++ .../ironchest/GoldChestBlockEntityMixin.java | 16 ++++ .../ironchest/IronChestBlockEntityMixin.java | 16 ++++ .../ObsidianChestBlockEntityMixin.java | 16 ++++ .../TrappedCopperChestBlockEntityMixin.java | 16 ++++ .../TrappedCrystalChestBlockEntityMixin.java | 16 ++++ .../TrappedDiamondChestBlockEntityMixin.java | 16 ++++ .../TrappedDirtChestBlockEntityMixin.java | 16 ++++ .../TrappedGoldChestBlockEntityMixin.java | 16 ++++ .../TrappedIronChestBlockEntityMixin.java | 16 ++++ .../TrappedObsidianChestBlockEntityMixin.java | 16 ++++ .../mc/otm/OverdriveThatMatters.kt | 6 ++ .../compat/ironchest/IronChestMenuTypes.kt | 66 +++++++++++++++ .../compat/ironchest/MatteryIronChestMenu.kt | 82 +++++++++++++++++++ ...erdrive_that_matters.ironchest.mixins.json | 22 +++++ 19 files changed, 404 insertions(+) create mode 100644 src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/CopperChestBlockEntityMixin.java create mode 100644 src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/CrystalChestBlockEntityMixin.java create mode 100644 src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/DiamondChestBlockEntityMixin.java create mode 100644 src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/DirtChestBlockEntityMixin.java create mode 100644 src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/GoldChestBlockEntityMixin.java create mode 100644 src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/IronChestBlockEntityMixin.java create mode 100644 src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/ObsidianChestBlockEntityMixin.java create mode 100644 src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/TrappedCopperChestBlockEntityMixin.java create mode 100644 src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/TrappedCrystalChestBlockEntityMixin.java create mode 100644 src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/TrappedDiamondChestBlockEntityMixin.java create mode 100644 src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/TrappedDirtChestBlockEntityMixin.java create mode 100644 src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/TrappedGoldChestBlockEntityMixin.java create mode 100644 src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/TrappedIronChestBlockEntityMixin.java create mode 100644 src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/TrappedObsidianChestBlockEntityMixin.java create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/compat/ironchest/IronChestMenuTypes.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/compat/ironchest/MatteryIronChestMenu.kt create mode 100644 src/main/resources/overdrive_that_matters.ironchest.mixins.json diff --git a/build.gradle.kts b/build.gradle.kts index 70ea476a2..3e0258458 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -209,6 +209,9 @@ dependencies { // runtimeOnly("curse.maven:integrated-tunnels-251389:4344632") implementation("mekanism:Mekanism:${mc_version}-${mekanism_version}") + + implementation("curse.maven:iron-chests-228756:5491156") + implementation("curse.maven:iron-shulker-boxes-314911:5491246") } } @@ -268,6 +271,7 @@ minecraft { mixin { config("$mod_id.mixins.json") + config("$mod_id.ironchest.mixins.json") // config("$mod_id.ad_astra.mixins.json") } diff --git a/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/CopperChestBlockEntityMixin.java b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/CopperChestBlockEntityMixin.java new file mode 100644 index 000000000..49af2c026 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/CopperChestBlockEntityMixin.java @@ -0,0 +1,16 @@ +package ru.dbotthepony.mc.otm.mixin.ironchest; + +import com.progwml6.ironchest.common.block.regular.entity.CopperChestBlockEntity; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.AbstractContainerMenu; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import ru.dbotthepony.mc.otm.compat.ironchest.MatteryIronChestMenu; + +@Mixin(CopperChestBlockEntity.class) +public abstract class CopperChestBlockEntityMixin { + @Overwrite(remap = false) + public AbstractContainerMenu createMenu(int containerId, Inventory inventory) { + return MatteryIronChestMenu.copper(containerId, inventory, ((CopperChestBlockEntity)(Object) this)); + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/CrystalChestBlockEntityMixin.java b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/CrystalChestBlockEntityMixin.java new file mode 100644 index 000000000..fca710c70 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/CrystalChestBlockEntityMixin.java @@ -0,0 +1,16 @@ +package ru.dbotthepony.mc.otm.mixin.ironchest; + +import com.progwml6.ironchest.common.block.regular.entity.CrystalChestBlockEntity; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.AbstractContainerMenu; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import ru.dbotthepony.mc.otm.compat.ironchest.MatteryIronChestMenu; + +@Mixin(CrystalChestBlockEntity.class) +public abstract class CrystalChestBlockEntityMixin { + @Overwrite(remap = false) + public AbstractContainerMenu createMenu(int containerId, Inventory inventory) { + return MatteryIronChestMenu.crystal(containerId, inventory, ((CrystalChestBlockEntity)(Object) this)); + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/DiamondChestBlockEntityMixin.java b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/DiamondChestBlockEntityMixin.java new file mode 100644 index 000000000..5c9f4dea4 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/DiamondChestBlockEntityMixin.java @@ -0,0 +1,16 @@ +package ru.dbotthepony.mc.otm.mixin.ironchest; + +import com.progwml6.ironchest.common.block.regular.entity.DiamondChestBlockEntity; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.AbstractContainerMenu; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import ru.dbotthepony.mc.otm.compat.ironchest.MatteryIronChestMenu; + +@Mixin(DiamondChestBlockEntity.class) +public abstract class DiamondChestBlockEntityMixin { + @Overwrite(remap = false) + public AbstractContainerMenu createMenu(int containerId, Inventory inventory) { + return MatteryIronChestMenu.diamond(containerId, inventory, ((DiamondChestBlockEntity)(Object) this)); + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/DirtChestBlockEntityMixin.java b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/DirtChestBlockEntityMixin.java new file mode 100644 index 000000000..e828a851a --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/DirtChestBlockEntityMixin.java @@ -0,0 +1,16 @@ +package ru.dbotthepony.mc.otm.mixin.ironchest; + +import com.progwml6.ironchest.common.block.regular.entity.DirtChestBlockEntity; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.AbstractContainerMenu; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import ru.dbotthepony.mc.otm.compat.ironchest.MatteryIronChestMenu; + +@Mixin(DirtChestBlockEntity.class) +public abstract class DirtChestBlockEntityMixin { + @Overwrite(remap = false) + public AbstractContainerMenu createMenu(int containerId, Inventory inventory) { + return MatteryIronChestMenu.dirt(containerId, inventory, ((DirtChestBlockEntity)(Object) this)); + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/GoldChestBlockEntityMixin.java b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/GoldChestBlockEntityMixin.java new file mode 100644 index 000000000..f985dbebe --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/GoldChestBlockEntityMixin.java @@ -0,0 +1,16 @@ +package ru.dbotthepony.mc.otm.mixin.ironchest; + +import com.progwml6.ironchest.common.block.regular.entity.GoldChestBlockEntity; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.AbstractContainerMenu; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import ru.dbotthepony.mc.otm.compat.ironchest.MatteryIronChestMenu; + +@Mixin(GoldChestBlockEntity.class) +public abstract class GoldChestBlockEntityMixin { + @Overwrite(remap = false) + public AbstractContainerMenu createMenu(int containerId, Inventory inventory) { + return MatteryIronChestMenu.gold(containerId, inventory, ((GoldChestBlockEntity)(Object) this)); + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/IronChestBlockEntityMixin.java b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/IronChestBlockEntityMixin.java new file mode 100644 index 000000000..c95ab1dc8 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/IronChestBlockEntityMixin.java @@ -0,0 +1,16 @@ +package ru.dbotthepony.mc.otm.mixin.ironchest; + +import com.progwml6.ironchest.common.block.regular.entity.IronChestBlockEntity; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.AbstractContainerMenu; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import ru.dbotthepony.mc.otm.compat.ironchest.MatteryIronChestMenu; + +@Mixin(IronChestBlockEntity.class) +public abstract class IronChestBlockEntityMixin { + @Overwrite(remap = false) + public AbstractContainerMenu createMenu(int containerId, Inventory inventory) { + return MatteryIronChestMenu.iron(containerId, inventory, ((IronChestBlockEntity)(Object) this)); + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/ObsidianChestBlockEntityMixin.java b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/ObsidianChestBlockEntityMixin.java new file mode 100644 index 000000000..8ff85dda8 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/ObsidianChestBlockEntityMixin.java @@ -0,0 +1,16 @@ +package ru.dbotthepony.mc.otm.mixin.ironchest; + +import com.progwml6.ironchest.common.block.regular.entity.ObsidianChestBlockEntity; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.AbstractContainerMenu; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import ru.dbotthepony.mc.otm.compat.ironchest.MatteryIronChestMenu; + +@Mixin(ObsidianChestBlockEntity.class) +public abstract class ObsidianChestBlockEntityMixin { + @Overwrite(remap = false) + public AbstractContainerMenu createMenu(int containerId, Inventory inventory) { + return MatteryIronChestMenu.obdisian(containerId, inventory, ((ObsidianChestBlockEntity)(Object) this)); + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/TrappedCopperChestBlockEntityMixin.java b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/TrappedCopperChestBlockEntityMixin.java new file mode 100644 index 000000000..5f3313725 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/TrappedCopperChestBlockEntityMixin.java @@ -0,0 +1,16 @@ +package ru.dbotthepony.mc.otm.mixin.ironchest; + +import com.progwml6.ironchest.common.block.trapped.entity.TrappedCopperChestBlockEntity; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.AbstractContainerMenu; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import ru.dbotthepony.mc.otm.compat.ironchest.MatteryIronChestMenu; + +@Mixin(TrappedCopperChestBlockEntity.class) +public abstract class TrappedCopperChestBlockEntityMixin { + @Overwrite(remap = false) + public AbstractContainerMenu createMenu(int containerId, Inventory inventory) { + return MatteryIronChestMenu.copper(containerId, inventory, ((TrappedCopperChestBlockEntity)(Object) this)); + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/TrappedCrystalChestBlockEntityMixin.java b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/TrappedCrystalChestBlockEntityMixin.java new file mode 100644 index 000000000..149d6c5a9 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/TrappedCrystalChestBlockEntityMixin.java @@ -0,0 +1,16 @@ +package ru.dbotthepony.mc.otm.mixin.ironchest; + +import com.progwml6.ironchest.common.block.trapped.entity.TrappedCrystalChestBlockEntity; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.AbstractContainerMenu; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import ru.dbotthepony.mc.otm.compat.ironchest.MatteryIronChestMenu; + +@Mixin(TrappedCrystalChestBlockEntity.class) +public abstract class TrappedCrystalChestBlockEntityMixin { + @Overwrite(remap = false) + public AbstractContainerMenu createMenu(int containerId, Inventory inventory) { + return MatteryIronChestMenu.crystal(containerId, inventory, ((TrappedCrystalChestBlockEntity)(Object) this)); + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/TrappedDiamondChestBlockEntityMixin.java b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/TrappedDiamondChestBlockEntityMixin.java new file mode 100644 index 000000000..0c454f5a7 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/TrappedDiamondChestBlockEntityMixin.java @@ -0,0 +1,16 @@ +package ru.dbotthepony.mc.otm.mixin.ironchest; + +import com.progwml6.ironchest.common.block.trapped.entity.TrappedDiamondChestBlockEntity; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.AbstractContainerMenu; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import ru.dbotthepony.mc.otm.compat.ironchest.MatteryIronChestMenu; + +@Mixin(TrappedDiamondChestBlockEntity.class) +public abstract class TrappedDiamondChestBlockEntityMixin { + @Overwrite(remap = false) + public AbstractContainerMenu createMenu(int containerId, Inventory inventory) { + return MatteryIronChestMenu.diamond(containerId, inventory, ((TrappedDiamondChestBlockEntity)(Object) this)); + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/TrappedDirtChestBlockEntityMixin.java b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/TrappedDirtChestBlockEntityMixin.java new file mode 100644 index 000000000..5b8c8600b --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/TrappedDirtChestBlockEntityMixin.java @@ -0,0 +1,16 @@ +package ru.dbotthepony.mc.otm.mixin.ironchest; + +import com.progwml6.ironchest.common.block.trapped.entity.TrappedDirtChestBlockEntity; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.AbstractContainerMenu; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import ru.dbotthepony.mc.otm.compat.ironchest.MatteryIronChestMenu; + +@Mixin(TrappedDirtChestBlockEntity.class) +public abstract class TrappedDirtChestBlockEntityMixin { + @Overwrite(remap = false) + public AbstractContainerMenu createMenu(int containerId, Inventory inventory) { + return MatteryIronChestMenu.dirt(containerId, inventory, ((TrappedDirtChestBlockEntity)(Object) this)); + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/TrappedGoldChestBlockEntityMixin.java b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/TrappedGoldChestBlockEntityMixin.java new file mode 100644 index 000000000..0b52e7787 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/TrappedGoldChestBlockEntityMixin.java @@ -0,0 +1,16 @@ +package ru.dbotthepony.mc.otm.mixin.ironchest; + +import com.progwml6.ironchest.common.block.trapped.entity.TrappedGoldChestBlockEntity; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.AbstractContainerMenu; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import ru.dbotthepony.mc.otm.compat.ironchest.MatteryIronChestMenu; + +@Mixin(TrappedGoldChestBlockEntity.class) +public abstract class TrappedGoldChestBlockEntityMixin { + @Overwrite(remap = false) + public AbstractContainerMenu createMenu(int containerId, Inventory inventory) { + return MatteryIronChestMenu.gold(containerId, inventory, ((TrappedGoldChestBlockEntity)(Object) this)); + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/TrappedIronChestBlockEntityMixin.java b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/TrappedIronChestBlockEntityMixin.java new file mode 100644 index 000000000..56a5458a7 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/TrappedIronChestBlockEntityMixin.java @@ -0,0 +1,16 @@ +package ru.dbotthepony.mc.otm.mixin.ironchest; + +import com.progwml6.ironchest.common.block.trapped.entity.TrappedIronChestBlockEntity; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.AbstractContainerMenu; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import ru.dbotthepony.mc.otm.compat.ironchest.MatteryIronChestMenu; + +@Mixin(TrappedIronChestBlockEntity.class) +public abstract class TrappedIronChestBlockEntityMixin { + @Overwrite(remap = false) + public AbstractContainerMenu createMenu(int containerId, Inventory inventory) { + return MatteryIronChestMenu.iron(containerId, inventory, ((TrappedIronChestBlockEntity)(Object) this)); + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/TrappedObsidianChestBlockEntityMixin.java b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/TrappedObsidianChestBlockEntityMixin.java new file mode 100644 index 000000000..f025ab31f --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/TrappedObsidianChestBlockEntityMixin.java @@ -0,0 +1,16 @@ +package ru.dbotthepony.mc.otm.mixin.ironchest; + +import com.progwml6.ironchest.common.block.trapped.entity.TrappedObsidianChestBlockEntity; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.AbstractContainerMenu; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import ru.dbotthepony.mc.otm.compat.ironchest.MatteryIronChestMenu; + +@Mixin(TrappedObsidianChestBlockEntity.class) +public abstract class TrappedObsidianChestBlockEntityMixin { + @Overwrite(remap = false) + public AbstractContainerMenu createMenu(int containerId, Inventory inventory) { + return MatteryIronChestMenu.obdisian(containerId, inventory, ((TrappedObsidianChestBlockEntity)(Object) this)); + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/OverdriveThatMatters.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/OverdriveThatMatters.kt index 1f66d1b96..223680e49 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/OverdriveThatMatters.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/OverdriveThatMatters.kt @@ -44,6 +44,8 @@ import ru.dbotthepony.mc.otm.client.render.blockentity.BatteryBankRenderer import ru.dbotthepony.mc.otm.client.render.blockentity.MatterBatteryBankRenderer import ru.dbotthepony.mc.otm.compat.curios.isCuriosLoaded import ru.dbotthepony.mc.otm.compat.curios.onCuriosSlotModifiersUpdated +import ru.dbotthepony.mc.otm.compat.ironchest.IronChestMenuTypes +import ru.dbotthepony.mc.otm.compat.ironchest.isIronChestLoaded import ru.dbotthepony.mc.otm.compat.vanilla.MatteryChestMenu import ru.dbotthepony.mc.otm.compat.vanilla.VanillaMenuTypes import ru.dbotthepony.mc.otm.config.PlayerConfig @@ -134,6 +136,10 @@ object OverdriveThatMatters { StorageStack.register(MOD_BUS) VanillaMenuTypes.register(MOD_BUS) + if (isIronChestLoaded) { + IronChestMenuTypes.register(MOD_BUS) + } + MCreativeTabs.initialize(MOD_BUS) MOD_BUS.addListener(::registerNetworkPackets) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/ironchest/IronChestMenuTypes.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/ironchest/IronChestMenuTypes.kt new file mode 100644 index 000000000..d1894ed78 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/ironchest/IronChestMenuTypes.kt @@ -0,0 +1,66 @@ +package ru.dbotthepony.mc.otm.compat.ironchest + +import com.progwml6.ironchest.IronChests +import com.progwml6.ironchest.common.block.IronChestsTypes +import net.minecraft.core.BlockPos +import net.minecraft.core.registries.Registries +import net.minecraft.world.Container +import net.minecraft.world.flag.FeatureFlags +import net.minecraft.world.inventory.MenuType +import net.minecraft.world.level.Level +import net.minecraft.world.level.block.entity.BlockEntity +import net.minecraft.world.level.block.state.BlockState +import net.neoforged.bus.api.IEventBus +import net.neoforged.fml.ModList +import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent +import net.neoforged.neoforge.client.event.RegisterMenuScreensEvent +import ru.dbotthepony.mc.otm.OverdriveThatMatters +import ru.dbotthepony.mc.otm.capability.IQuickStackContainer +import ru.dbotthepony.mc.otm.capability.MatteryCapability +import ru.dbotthepony.mc.otm.compat.vanilla.VanillaChestScreen +import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot +import ru.dbotthepony.mc.otm.menu.makeSlots +import ru.dbotthepony.mc.otm.registry.MDeferredRegister + +val isIronChestLoaded by lazy { + ModList.get().isLoaded(IronChests.MODID) +} + +object IronChestMenuTypes { + private val registrar = MDeferredRegister(Registries.MENU, OverdriveThatMatters.MOD_ID) + + val IRON by registrar.register("ironchest_iron") { MenuType(MatteryIronChestMenu::iron, FeatureFlags.VANILLA_SET) } + val GOLD by registrar.register("ironchest_gold") { MenuType(MatteryIronChestMenu::gold, FeatureFlags.VANILLA_SET) } + val DIAMOND by registrar.register("ironchest_diamond") { MenuType(MatteryIronChestMenu::diamond, FeatureFlags.VANILLA_SET) } + val COPPER by registrar.register("ironchest_copper") { MenuType(MatteryIronChestMenu::copper, FeatureFlags.VANILLA_SET) } + val CRYSTAL by registrar.register("ironchest_crystal") { MenuType(MatteryIronChestMenu::crystal, FeatureFlags.VANILLA_SET) } + val OBSIDIAN by registrar.register("ironchest_obsidian") { MenuType(MatteryIronChestMenu::obdisian, FeatureFlags.VANILLA_SET) } + val DIRT by registrar.register("ironchest_dirt") { MenuType(MatteryIronChestMenu::dirt, FeatureFlags.VANILLA_SET) } + + private fun provider(level: Level, pos: BlockPos, state: BlockState, blockEntity: BlockEntity?, context: Void?): IQuickStackContainer? { + val container = blockEntity as? Container ?: return null + return IQuickStackContainer.Simple(makeSlots(container, ::MatteryMenuSlot)) + } + + fun registerCapabilities(event: RegisterCapabilitiesEvent) { + IronChestsTypes.entries.map { IronChestsTypes.get(it) }.forEach { + event.registerBlock(MatteryCapability.QUICK_STACK_CONTAINER, ::provider, *it.toTypedArray()) + } + } + + internal fun register(bus: IEventBus) { + registrar.register(bus) + bus.addListener(this::registerScreens) + bus.addListener(this::registerCapabilities) + } + + private fun registerScreens(event: RegisterMenuScreensEvent) { + event.register(IRON, ::VanillaChestScreen) + event.register(GOLD, ::VanillaChestScreen) + event.register(DIAMOND, ::VanillaChestScreen) + event.register(COPPER, ::VanillaChestScreen) + event.register(CRYSTAL, ::VanillaChestScreen) + event.register(OBSIDIAN, ::VanillaChestScreen) + event.register(DIRT, ::VanillaChestScreen) + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/ironchest/MatteryIronChestMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/ironchest/MatteryIronChestMenu.kt new file mode 100644 index 000000000..bc7140719 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/ironchest/MatteryIronChestMenu.kt @@ -0,0 +1,82 @@ +package ru.dbotthepony.mc.otm.compat.ironchest + +import com.progwml6.ironchest.common.block.IronChestsTypes +import net.minecraft.world.Container +import net.minecraft.world.SimpleContainer +import net.minecraft.world.entity.player.Inventory +import net.minecraft.world.inventory.MenuType +import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.Items +import ru.dbotthepony.mc.otm.compat.vanilla.AbstractVanillaChestMenu +import ru.dbotthepony.mc.otm.container.EnhancedContainer +import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot +import ru.dbotthepony.mc.otm.menu.QuickMoveInput +import ru.dbotthepony.mc.otm.menu.makeSlots + +class MatteryIronChestMenu( + type: MenuType<*>, containerId: Int, + inventory: Inventory, chestType: IronChestsTypes, + container: Container = EnhancedContainer.Simple(chestType.size), +) : AbstractVanillaChestMenu(type, containerId, inventory, container) { + override val columns = chestType.rowLength + override val rows = chestType.size / chestType.rowLength + + override val containerSlots = if (chestType == IronChestsTypes.DIRT) makeSlots(container, ::MDirtChestSlot) else makeSlots(container, ::MatteryMenuSlot) + + init { + container.startOpen(player) + addStorageSlot(containerSlots) + addInventorySlots() + } + + override val quickMoveToStorage = QuickMoveInput.create(this, playerCombinedInventorySlots, containerSlots) + override val quickMoveFromStorage = QuickMoveInput.create(this, containerSlots, playerInventorySlots, false) + + class MDirtChestSlot(container: Container, slot: Int) : MatteryMenuSlot(container, slot) { + override fun mayPlace(stack: ItemStack): Boolean = stack.isEmpty || stack.`is`(Items.DIRT) + } + + companion object { + @JvmStatic + @JvmOverloads + fun iron(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(IronChestsTypes.IRON.size), chestType: IronChestsTypes = IronChestsTypes.IRON): MatteryIronChestMenu { + return MatteryIronChestMenu(IronChestMenuTypes.IRON, containerId, inventory, chestType, container) + } + + @JvmStatic + @JvmOverloads + fun gold(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(IronChestsTypes.GOLD.size), chestType: IronChestsTypes = IronChestsTypes.GOLD): MatteryIronChestMenu { + return MatteryIronChestMenu(IronChestMenuTypes.GOLD, containerId, inventory, chestType, container) + } + + @JvmStatic + @JvmOverloads + fun diamond(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(IronChestsTypes.DIAMOND.size), chestType: IronChestsTypes = IronChestsTypes.DIAMOND): MatteryIronChestMenu { + return MatteryIronChestMenu(IronChestMenuTypes.DIAMOND, containerId, inventory, chestType, container) + } + + @JvmStatic + @JvmOverloads + fun copper(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(IronChestsTypes.COPPER.size), chestType: IronChestsTypes = IronChestsTypes.COPPER): MatteryIronChestMenu { + return MatteryIronChestMenu(IronChestMenuTypes.COPPER, containerId, inventory, chestType, container) + } + + @JvmStatic + @JvmOverloads + fun crystal(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(IronChestsTypes.CRYSTAL.size), chestType: IronChestsTypes = IronChestsTypes.CRYSTAL): MatteryIronChestMenu { + return MatteryIronChestMenu(IronChestMenuTypes.CRYSTAL, containerId, inventory, chestType, container) + } + + @JvmStatic + @JvmOverloads + fun obdisian(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(IronChestsTypes.OBSIDIAN.size), chestType: IronChestsTypes = IronChestsTypes.OBSIDIAN): MatteryIronChestMenu { + return MatteryIronChestMenu(IronChestMenuTypes.OBSIDIAN, containerId, inventory, chestType, container) + } + + @JvmStatic + @JvmOverloads + fun dirt(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(IronChestsTypes.DIRT.size), chestType: IronChestsTypes = IronChestsTypes.DIRT): MatteryIronChestMenu { + return MatteryIronChestMenu(IronChestMenuTypes.DIRT, containerId, inventory, chestType, container) + } + } +} diff --git a/src/main/resources/overdrive_that_matters.ironchest.mixins.json b/src/main/resources/overdrive_that_matters.ironchest.mixins.json new file mode 100644 index 000000000..20cb09454 --- /dev/null +++ b/src/main/resources/overdrive_that_matters.ironchest.mixins.json @@ -0,0 +1,22 @@ +{ + "required": false, + "package": "ru.dbotthepony.mc.otm.mixin.ironchest", + "compatibilityLevel": "JAVA_21", + "minVersion": "0.8", + "mixins": [ + "IronChestBlockEntityMixin", + "GoldChestBlockEntityMixin", + "DiamondChestBlockEntityMixin", + "CopperChestBlockEntityMixin", + "CrystalChestBlockEntityMixin", + "ObsidianChestBlockEntityMixin", + "DirtChestBlockEntityMixin", + "TrappedIronChestBlockEntityMixin", + "TrappedGoldChestBlockEntityMixin", + "TrappedDiamondChestBlockEntityMixin", + "TrappedCopperChestBlockEntityMixin", + "TrappedCrystalChestBlockEntityMixin", + "TrappedObsidianChestBlockEntityMixin", + "TrappedDirtChestBlockEntityMixin" + ] +} From 85950c6a903a0f55e36ec1845312839ddaa056bd Mon Sep 17 00:00:00 2001 From: YuRaNnNzZZ Date: Wed, 9 Apr 2025 03:48:10 +0300 Subject: [PATCH 02/11] =?UTF-8?q?=D1=82=D1=8B=20=D0=BA=D0=B0=D0=BA=20?= =?UTF-8?q?=D0=BC=D0=B5=D0=BD=D1=8F=20=D0=BD=D0=B0=D0=B7=D0=B2=D0=B0=D0=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mc/otm/mixin/ironchest/ObsidianChestBlockEntityMixin.java | 2 +- .../mixin/ironchest/TrappedObsidianChestBlockEntityMixin.java | 2 +- .../dbotthepony/mc/otm/compat/ironchest/IronChestMenuTypes.kt | 2 +- .../dbotthepony/mc/otm/compat/ironchest/MatteryIronChestMenu.kt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/ObsidianChestBlockEntityMixin.java b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/ObsidianChestBlockEntityMixin.java index 8ff85dda8..1e2a45aa6 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/ObsidianChestBlockEntityMixin.java +++ b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/ObsidianChestBlockEntityMixin.java @@ -11,6 +11,6 @@ import ru.dbotthepony.mc.otm.compat.ironchest.MatteryIronChestMenu; public abstract class ObsidianChestBlockEntityMixin { @Overwrite(remap = false) public AbstractContainerMenu createMenu(int containerId, Inventory inventory) { - return MatteryIronChestMenu.obdisian(containerId, inventory, ((ObsidianChestBlockEntity)(Object) this)); + return MatteryIronChestMenu.obsidian(containerId, inventory, ((ObsidianChestBlockEntity)(Object) this)); } } diff --git a/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/TrappedObsidianChestBlockEntityMixin.java b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/TrappedObsidianChestBlockEntityMixin.java index f025ab31f..49efee1f8 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/TrappedObsidianChestBlockEntityMixin.java +++ b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironchest/TrappedObsidianChestBlockEntityMixin.java @@ -11,6 +11,6 @@ import ru.dbotthepony.mc.otm.compat.ironchest.MatteryIronChestMenu; public abstract class TrappedObsidianChestBlockEntityMixin { @Overwrite(remap = false) public AbstractContainerMenu createMenu(int containerId, Inventory inventory) { - return MatteryIronChestMenu.obdisian(containerId, inventory, ((TrappedObsidianChestBlockEntity)(Object) this)); + return MatteryIronChestMenu.obsidian(containerId, inventory, ((TrappedObsidianChestBlockEntity)(Object) this)); } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/ironchest/IronChestMenuTypes.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/ironchest/IronChestMenuTypes.kt index d1894ed78..c7203ff6b 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/ironchest/IronChestMenuTypes.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/ironchest/IronChestMenuTypes.kt @@ -34,7 +34,7 @@ object IronChestMenuTypes { val DIAMOND by registrar.register("ironchest_diamond") { MenuType(MatteryIronChestMenu::diamond, FeatureFlags.VANILLA_SET) } val COPPER by registrar.register("ironchest_copper") { MenuType(MatteryIronChestMenu::copper, FeatureFlags.VANILLA_SET) } val CRYSTAL by registrar.register("ironchest_crystal") { MenuType(MatteryIronChestMenu::crystal, FeatureFlags.VANILLA_SET) } - val OBSIDIAN by registrar.register("ironchest_obsidian") { MenuType(MatteryIronChestMenu::obdisian, FeatureFlags.VANILLA_SET) } + val OBSIDIAN by registrar.register("ironchest_obsidian") { MenuType(MatteryIronChestMenu::obsidian, FeatureFlags.VANILLA_SET) } val DIRT by registrar.register("ironchest_dirt") { MenuType(MatteryIronChestMenu::dirt, FeatureFlags.VANILLA_SET) } private fun provider(level: Level, pos: BlockPos, state: BlockState, blockEntity: BlockEntity?, context: Void?): IQuickStackContainer? { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/ironchest/MatteryIronChestMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/ironchest/MatteryIronChestMenu.kt index bc7140719..bd19c9d13 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/ironchest/MatteryIronChestMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/ironchest/MatteryIronChestMenu.kt @@ -69,7 +69,7 @@ class MatteryIronChestMenu( @JvmStatic @JvmOverloads - fun obdisian(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(IronChestsTypes.OBSIDIAN.size), chestType: IronChestsTypes = IronChestsTypes.OBSIDIAN): MatteryIronChestMenu { + fun obsidian(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(IronChestsTypes.OBSIDIAN.size), chestType: IronChestsTypes = IronChestsTypes.OBSIDIAN): MatteryIronChestMenu { return MatteryIronChestMenu(IronChestMenuTypes.OBSIDIAN, containerId, inventory, chestType, container) } From cc372ed871b04db1fd1f1c2df7afcd78e51b5745 Mon Sep 17 00:00:00 2001 From: YuRaNnNzZZ Date: Wed, 9 Apr 2025 03:57:42 +0300 Subject: [PATCH 03/11] iron shulker boxes --- build.gradle.kts | 1 + .../CopperShulkerBoxBlockEntityMixin.java | 16 ++++ .../CrystalShulkerBoxBlockEntityMixin.java | 16 ++++ .../DiamondShulkerBoxBlockEntityMixin.java | 16 ++++ .../GoldShulkerBoxBlockEntityMixin.java | 16 ++++ .../IronShulkerBoxBlockEntityMixin.java | 16 ++++ .../ObsidianShulkerBoxBlockEntityMixin.java | 16 ++++ .../mc/otm/OverdriveThatMatters.kt | 6 ++ .../ironshulkerbox/IronShulkersMenuTypes.kt | 68 ++++++++++++++++ .../MatteryIronShulkerBoxMenu.kt | 77 +++++++++++++++++++ ...ve_that_matters.ironshulkerbox.mixins.json | 14 ++++ 11 files changed, 262 insertions(+) create mode 100644 src/main/java/ru/dbotthepony/mc/otm/mixin/ironshulkerbox/CopperShulkerBoxBlockEntityMixin.java create mode 100644 src/main/java/ru/dbotthepony/mc/otm/mixin/ironshulkerbox/CrystalShulkerBoxBlockEntityMixin.java create mode 100644 src/main/java/ru/dbotthepony/mc/otm/mixin/ironshulkerbox/DiamondShulkerBoxBlockEntityMixin.java create mode 100644 src/main/java/ru/dbotthepony/mc/otm/mixin/ironshulkerbox/GoldShulkerBoxBlockEntityMixin.java create mode 100644 src/main/java/ru/dbotthepony/mc/otm/mixin/ironshulkerbox/IronShulkerBoxBlockEntityMixin.java create mode 100644 src/main/java/ru/dbotthepony/mc/otm/mixin/ironshulkerbox/ObsidianShulkerBoxBlockEntityMixin.java create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/compat/ironshulkerbox/IronShulkersMenuTypes.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/compat/ironshulkerbox/MatteryIronShulkerBoxMenu.kt create mode 100644 src/main/resources/overdrive_that_matters.ironshulkerbox.mixins.json diff --git a/build.gradle.kts b/build.gradle.kts index 3e0258458..4d93835b5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -272,6 +272,7 @@ minecraft { mixin { config("$mod_id.mixins.json") config("$mod_id.ironchest.mixins.json") + config("$mod_id.ironshulkerbox.mixins.json") // config("$mod_id.ad_astra.mixins.json") } diff --git a/src/main/java/ru/dbotthepony/mc/otm/mixin/ironshulkerbox/CopperShulkerBoxBlockEntityMixin.java b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironshulkerbox/CopperShulkerBoxBlockEntityMixin.java new file mode 100644 index 000000000..c99bc8496 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironshulkerbox/CopperShulkerBoxBlockEntityMixin.java @@ -0,0 +1,16 @@ +package ru.dbotthepony.mc.otm.mixin.ironshulkerbox; + +import com.progwml6.ironshulkerbox.common.block.entity.CopperShulkerBoxBlockEntity; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.AbstractContainerMenu; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import ru.dbotthepony.mc.otm.compat.ironshulkerbox.MatteryIronShulkerBoxMenu; + +@Mixin(CopperShulkerBoxBlockEntity.class) +public abstract class CopperShulkerBoxBlockEntityMixin { + @Overwrite(remap = false) + public AbstractContainerMenu createMenu(int containerId, Inventory inventory) { + return MatteryIronShulkerBoxMenu.copper(containerId, inventory, ((CopperShulkerBoxBlockEntity)(Object) this)); + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/mixin/ironshulkerbox/CrystalShulkerBoxBlockEntityMixin.java b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironshulkerbox/CrystalShulkerBoxBlockEntityMixin.java new file mode 100644 index 000000000..c2a05b4c3 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironshulkerbox/CrystalShulkerBoxBlockEntityMixin.java @@ -0,0 +1,16 @@ +package ru.dbotthepony.mc.otm.mixin.ironshulkerbox; + +import com.progwml6.ironshulkerbox.common.block.entity.CrystalShulkerBoxBlockEntity; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.AbstractContainerMenu; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import ru.dbotthepony.mc.otm.compat.ironshulkerbox.MatteryIronShulkerBoxMenu; + +@Mixin(CrystalShulkerBoxBlockEntity.class) +public abstract class CrystalShulkerBoxBlockEntityMixin { + @Overwrite(remap = false) + public AbstractContainerMenu createMenu(int containerId, Inventory inventory) { + return MatteryIronShulkerBoxMenu.crystal(containerId, inventory, ((CrystalShulkerBoxBlockEntity)(Object) this)); + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/mixin/ironshulkerbox/DiamondShulkerBoxBlockEntityMixin.java b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironshulkerbox/DiamondShulkerBoxBlockEntityMixin.java new file mode 100644 index 000000000..6ed982d9a --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironshulkerbox/DiamondShulkerBoxBlockEntityMixin.java @@ -0,0 +1,16 @@ +package ru.dbotthepony.mc.otm.mixin.ironshulkerbox; + +import com.progwml6.ironshulkerbox.common.block.entity.DiamondShulkerBoxBlockEntity; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.AbstractContainerMenu; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import ru.dbotthepony.mc.otm.compat.ironshulkerbox.MatteryIronShulkerBoxMenu; + +@Mixin(DiamondShulkerBoxBlockEntity.class) +public abstract class DiamondShulkerBoxBlockEntityMixin { + @Overwrite(remap = false) + public AbstractContainerMenu createMenu(int containerId, Inventory inventory) { + return MatteryIronShulkerBoxMenu.diamond(containerId, inventory, ((DiamondShulkerBoxBlockEntity)(Object) this)); + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/mixin/ironshulkerbox/GoldShulkerBoxBlockEntityMixin.java b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironshulkerbox/GoldShulkerBoxBlockEntityMixin.java new file mode 100644 index 000000000..4adb75011 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironshulkerbox/GoldShulkerBoxBlockEntityMixin.java @@ -0,0 +1,16 @@ +package ru.dbotthepony.mc.otm.mixin.ironshulkerbox; + +import com.progwml6.ironshulkerbox.common.block.entity.GoldShulkerBoxBlockEntity; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.AbstractContainerMenu; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import ru.dbotthepony.mc.otm.compat.ironshulkerbox.MatteryIronShulkerBoxMenu; + +@Mixin(GoldShulkerBoxBlockEntity.class) +public abstract class GoldShulkerBoxBlockEntityMixin { + @Overwrite(remap = false) + public AbstractContainerMenu createMenu(int containerId, Inventory inventory) { + return MatteryIronShulkerBoxMenu.gold(containerId, inventory, ((GoldShulkerBoxBlockEntity)(Object) this)); + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/mixin/ironshulkerbox/IronShulkerBoxBlockEntityMixin.java b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironshulkerbox/IronShulkerBoxBlockEntityMixin.java new file mode 100644 index 000000000..bdd856532 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironshulkerbox/IronShulkerBoxBlockEntityMixin.java @@ -0,0 +1,16 @@ +package ru.dbotthepony.mc.otm.mixin.ironshulkerbox; + +import com.progwml6.ironshulkerbox.common.block.entity.IronShulkerBoxBlockEntity; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.AbstractContainerMenu; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import ru.dbotthepony.mc.otm.compat.ironshulkerbox.MatteryIronShulkerBoxMenu; + +@Mixin(IronShulkerBoxBlockEntity.class) +public abstract class IronShulkerBoxBlockEntityMixin { + @Overwrite(remap = false) + public AbstractContainerMenu createMenu(int containerId, Inventory inventory) { + return MatteryIronShulkerBoxMenu.iron(containerId, inventory, ((IronShulkerBoxBlockEntity)(Object) this)); + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/mixin/ironshulkerbox/ObsidianShulkerBoxBlockEntityMixin.java b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironshulkerbox/ObsidianShulkerBoxBlockEntityMixin.java new file mode 100644 index 000000000..6a9990a37 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/mixin/ironshulkerbox/ObsidianShulkerBoxBlockEntityMixin.java @@ -0,0 +1,16 @@ +package ru.dbotthepony.mc.otm.mixin.ironshulkerbox; + +import com.progwml6.ironshulkerbox.common.block.entity.ObsidianShulkerBoxBlockEntity; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.AbstractContainerMenu; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import ru.dbotthepony.mc.otm.compat.ironshulkerbox.MatteryIronShulkerBoxMenu; + +@Mixin(ObsidianShulkerBoxBlockEntity.class) +public abstract class ObsidianShulkerBoxBlockEntityMixin { + @Overwrite(remap = false) + public AbstractContainerMenu createMenu(int containerId, Inventory inventory) { + return MatteryIronShulkerBoxMenu.obsidian(containerId, inventory, ((ObsidianShulkerBoxBlockEntity)(Object) this)); + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/OverdriveThatMatters.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/OverdriveThatMatters.kt index 223680e49..c9fdcaad9 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/OverdriveThatMatters.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/OverdriveThatMatters.kt @@ -46,6 +46,8 @@ import ru.dbotthepony.mc.otm.compat.curios.isCuriosLoaded import ru.dbotthepony.mc.otm.compat.curios.onCuriosSlotModifiersUpdated import ru.dbotthepony.mc.otm.compat.ironchest.IronChestMenuTypes import ru.dbotthepony.mc.otm.compat.ironchest.isIronChestLoaded +import ru.dbotthepony.mc.otm.compat.ironshulkerbox.IronShulkersMenuTypes +import ru.dbotthepony.mc.otm.compat.ironshulkerbox.isIronShulkersLoaded import ru.dbotthepony.mc.otm.compat.vanilla.MatteryChestMenu import ru.dbotthepony.mc.otm.compat.vanilla.VanillaMenuTypes import ru.dbotthepony.mc.otm.config.PlayerConfig @@ -140,6 +142,10 @@ object OverdriveThatMatters { IronChestMenuTypes.register(MOD_BUS) } + if (isIronShulkersLoaded) { + IronShulkersMenuTypes.register(MOD_BUS) + } + MCreativeTabs.initialize(MOD_BUS) MOD_BUS.addListener(::registerNetworkPackets) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/ironshulkerbox/IronShulkersMenuTypes.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/ironshulkerbox/IronShulkersMenuTypes.kt new file mode 100644 index 000000000..ad49080e7 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/ironshulkerbox/IronShulkersMenuTypes.kt @@ -0,0 +1,68 @@ +package ru.dbotthepony.mc.otm.compat.ironshulkerbox + +import com.progwml6.ironshulkerbox.IronShulkerBoxes +import com.progwml6.ironshulkerbox.common.block.IronShulkerBoxesTypes +import net.minecraft.core.BlockPos +import net.minecraft.core.registries.Registries +import net.minecraft.world.Container +import net.minecraft.world.flag.FeatureFlags +import net.minecraft.world.inventory.MenuType +import net.minecraft.world.item.DyeColor +import net.minecraft.world.level.Level +import net.minecraft.world.level.block.entity.BlockEntity +import net.minecraft.world.level.block.state.BlockState +import net.neoforged.bus.api.IEventBus +import net.neoforged.fml.ModList +import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent +import net.neoforged.neoforge.client.event.RegisterMenuScreensEvent +import ru.dbotthepony.mc.otm.OverdriveThatMatters +import ru.dbotthepony.mc.otm.capability.IQuickStackContainer +import ru.dbotthepony.mc.otm.capability.MatteryCapability +import ru.dbotthepony.mc.otm.compat.ironshulkerbox.MatteryIronShulkerBoxMenu.Slot +import ru.dbotthepony.mc.otm.compat.vanilla.VanillaChestScreen +import ru.dbotthepony.mc.otm.menu.makeSlots +import ru.dbotthepony.mc.otm.registry.MDeferredRegister +import kotlin.collections.toTypedArray + +val isIronShulkersLoaded by lazy { + ModList.get().isLoaded(IronShulkerBoxes.MODID) +} + +object IronShulkersMenuTypes { + private val registrar = MDeferredRegister(Registries.MENU, OverdriveThatMatters.MOD_ID) + + val IRON by registrar.register("ironshulkerbox_iron") { MenuType(MatteryIronShulkerBoxMenu::iron, FeatureFlags.VANILLA_SET) } + val GOLD by registrar.register("ironshulkerbox_gold") { MenuType(MatteryIronShulkerBoxMenu::gold, FeatureFlags.VANILLA_SET) } + val DIAMOND by registrar.register("ironshulkerbox_diamond") { MenuType(MatteryIronShulkerBoxMenu::diamond, FeatureFlags.VANILLA_SET) } + val COPPER by registrar.register("ironshulkerbox_copper") { MenuType(MatteryIronShulkerBoxMenu::copper, FeatureFlags.VANILLA_SET) } + val CRYSTAL by registrar.register("ironshulkerbox_crystal") { MenuType(MatteryIronShulkerBoxMenu::crystal, FeatureFlags.VANILLA_SET) } + val OBSIDIAN by registrar.register("ironshulkerbox_obsidian") { MenuType(MatteryIronShulkerBoxMenu::obsidian, FeatureFlags.VANILLA_SET) } + + private fun provider(level: Level, pos: BlockPos, state: BlockState, blockEntity: BlockEntity?, context: Void?): IQuickStackContainer? { + val container = blockEntity as? Container ?: return null + return IQuickStackContainer.Simple(makeSlots(container, ::Slot)) + } + + fun registerCapabilities(event: RegisterCapabilitiesEvent) { + val colors = DyeColor.entries.toMutableList().also { it.add(0, null) } + + IronShulkerBoxesTypes.entries.forEach { type -> + event.registerBlock(MatteryCapability.QUICK_STACK_CONTAINER, ::provider, *colors.map { IronShulkerBoxesTypes.get(type, it) }.toTypedArray()) + } + } + + internal fun register(bus: IEventBus) { + registrar.register(bus) + bus.addListener(this::registerScreens) + bus.addListener(this::registerCapabilities) + } + + private fun registerScreens(event: RegisterMenuScreensEvent) { + event.register(IRON, ::VanillaChestScreen) + event.register(GOLD, ::VanillaChestScreen) + event.register(DIAMOND, ::VanillaChestScreen) + event.register(COPPER, ::VanillaChestScreen) + event.register(CRYSTAL, ::VanillaChestScreen) + event.register(OBSIDIAN, ::VanillaChestScreen) + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/ironshulkerbox/MatteryIronShulkerBoxMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/ironshulkerbox/MatteryIronShulkerBoxMenu.kt new file mode 100644 index 000000000..2f0d6e13e --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/ironshulkerbox/MatteryIronShulkerBoxMenu.kt @@ -0,0 +1,77 @@ +package ru.dbotthepony.mc.otm.compat.ironshulkerbox + +import com.progwml6.ironshulkerbox.common.block.IronShulkerBoxesTypes +import net.minecraft.world.Container +import net.minecraft.world.SimpleContainer +import net.minecraft.world.entity.player.Inventory +import net.minecraft.world.inventory.MenuType +import net.minecraft.world.item.ItemStack +import ru.dbotthepony.mc.otm.compat.vanilla.AbstractVanillaChestMenu +import ru.dbotthepony.mc.otm.container.EnhancedContainer +import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot +import ru.dbotthepony.mc.otm.menu.QuickMoveInput +import ru.dbotthepony.mc.otm.menu.makeSlots + +class MatteryIronShulkerBoxMenu( + type: MenuType<*>, containerId: Int, + inventory: Inventory, boxType: IronShulkerBoxesTypes, + container: Container = EnhancedContainer.Simple(boxType.size) +) : AbstractVanillaChestMenu(type, containerId, inventory, container) { + override val rows: Int = boxType.size / boxType.rowLength + override val columns: Int = boxType.rowLength + + override val containerSlots = makeSlots(container, ::Slot) + + init { + container.startOpen(player) + addStorageSlot(containerSlots) + addInventorySlots() + } + + override val quickMoveToStorage = QuickMoveInput.create(this, playerCombinedInventorySlots, containerSlots) + override val quickMoveFromStorage = QuickMoveInput.create(this, containerSlots, playerInventorySlots, false) + + class Slot(container: Container, slot: Int) : MatteryMenuSlot(container, slot) { + override fun mayPlace(stack: ItemStack): Boolean { + return super.mayPlace(stack) && stack.item.canFitInsideContainerItems() + } + } + + companion object { + @JvmStatic + @JvmOverloads + fun iron(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(IronShulkerBoxesTypes.IRON.size), boxType: IronShulkerBoxesTypes = IronShulkerBoxesTypes.IRON): MatteryIronShulkerBoxMenu { + return MatteryIronShulkerBoxMenu(IronShulkersMenuTypes.IRON, containerId, inventory, boxType, container) + } + + @JvmStatic + @JvmOverloads + fun gold(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(IronShulkerBoxesTypes.GOLD.size), boxType: IronShulkerBoxesTypes = IronShulkerBoxesTypes.GOLD): MatteryIronShulkerBoxMenu { + return MatteryIronShulkerBoxMenu(IronShulkersMenuTypes.GOLD, containerId, inventory, boxType, container) + } + + @JvmStatic + @JvmOverloads + fun diamond(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(IronShulkerBoxesTypes.DIAMOND.size), boxType: IronShulkerBoxesTypes = IronShulkerBoxesTypes.DIAMOND): MatteryIronShulkerBoxMenu { + return MatteryIronShulkerBoxMenu(IronShulkersMenuTypes.DIAMOND, containerId, inventory, boxType, container) + } + + @JvmStatic + @JvmOverloads + fun copper(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(IronShulkerBoxesTypes.COPPER.size), boxType: IronShulkerBoxesTypes = IronShulkerBoxesTypes.COPPER): MatteryIronShulkerBoxMenu { + return MatteryIronShulkerBoxMenu(IronShulkersMenuTypes.COPPER, containerId, inventory, boxType, container) + } + + @JvmStatic + @JvmOverloads + fun crystal(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(IronShulkerBoxesTypes.CRYSTAL.size), boxType: IronShulkerBoxesTypes = IronShulkerBoxesTypes.CRYSTAL): MatteryIronShulkerBoxMenu { + return MatteryIronShulkerBoxMenu(IronShulkersMenuTypes.CRYSTAL, containerId, inventory, boxType, container) + } + + @JvmStatic + @JvmOverloads + fun obsidian(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(IronShulkerBoxesTypes.OBSIDIAN.size), boxType: IronShulkerBoxesTypes = IronShulkerBoxesTypes.OBSIDIAN): MatteryIronShulkerBoxMenu { + return MatteryIronShulkerBoxMenu(IronShulkersMenuTypes.OBSIDIAN, containerId, inventory, boxType, container) + } + } +} diff --git a/src/main/resources/overdrive_that_matters.ironshulkerbox.mixins.json b/src/main/resources/overdrive_that_matters.ironshulkerbox.mixins.json new file mode 100644 index 000000000..12d348dc5 --- /dev/null +++ b/src/main/resources/overdrive_that_matters.ironshulkerbox.mixins.json @@ -0,0 +1,14 @@ +{ + "required": false, + "package": "ru.dbotthepony.mc.otm.mixin.ironshulkerbox", + "compatibilityLevel": "JAVA_21", + "minVersion": "0.8", + "mixins": [ + "IronShulkerBoxBlockEntityMixin", + "GoldShulkerBoxBlockEntityMixin", + "DiamondShulkerBoxBlockEntityMixin", + "CopperShulkerBoxBlockEntityMixin", + "CrystalShulkerBoxBlockEntityMixin", + "ObsidianShulkerBoxBlockEntityMixin" + ] +} From 1fc5c762245f154530330e6d14a8f8018fbb3a79 Mon Sep 17 00:00:00 2001 From: YuRaNnNzZZ Date: Wed, 9 Apr 2025 17:11:49 +0300 Subject: [PATCH 04/11] =?UTF-8?q?=D0=BD=D0=B8=D1=87=D0=B5=D0=B3=D0=BE=20?= =?UTF-8?q?=D0=BD=D0=B5=20=D0=B7=D0=B0=D0=B1=D1=8B=D0=BB=3F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/ru/dbotthepony/mc/otm/registry/MRegistry.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MRegistry.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MRegistry.kt index 5d71f2a39..bd74ee10e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MRegistry.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MRegistry.kt @@ -326,7 +326,7 @@ object MRegistry : IBlockItemRegistryAcceptor { } } - for (item in MItems.ALL_BATTERIES) { + for (item in MItems.ALL_BATTERIES.toMutableList().also { it.add(MItems.PROCEDURAL_BATTERY) }) { ItemProperties.register(item, ResourceLocation(OverdriveThatMatters.MOD_ID, "capacitor_gauge")) { stack, _, _, _ -> val energy = stack.matteryEnergy ?: return@register 1f From 5f64f5708b8f1bb46640170e3dcaa090d092b9d5 Mon Sep 17 00:00:00 2001 From: YuRaNnNzZZ Date: Wed, 9 Apr 2025 18:10:43 +0300 Subject: [PATCH 05/11] =?UTF-8?q?=D0=B4=D0=B0=D0=B2=D0=B0=D0=B9=D1=82?= =?UTF-8?q?=D0=B5=20=D0=BA=D0=BE=D1=80=D0=BE=D1=87=D0=B5=20=D1=81=D0=BA?= =?UTF-8?q?=D0=BE=D0=BF=D0=B8=D1=80=D1=83=D0=B5=D0=BC=20=D0=BC=D0=B5=D1=82?= =?UTF-8?q?=D0=BE=D0=B4=20=D0=B8=D0=B7=20=D0=B2=D0=B0=D0=BD=D0=B8=D0=BB?= =?UTF-8?q?=D0=BB=D1=8B=20=D0=BD=D0=B5=20=D0=BE=D1=81=D0=BE=D0=B1=D0=BE=20?= =?UTF-8?q?=D1=80=D0=B0=D0=B7=D0=B1=D0=B8=D1=80=D0=B0=D1=8F=D1=81=D1=8C=20?= =?UTF-8?q?=D0=B7=D0=B0=D1=87=D0=B5=D0=BC=20=D0=BE=D0=BD=20=D0=BD=D0=B0?= =?UTF-8?q?=D0=BC=20=D0=BD=D1=83=D0=B6=D0=B5=D0=BD,=20=D0=9F=D0=9E=D0=A5?= =?UTF-8?q?=D0=A3=D0=99=20=D0=A7=D0=A2=D0=9E=20=D0=90=D0=99=D0=A0=D0=9E?= =?UTF-8?q?=D0=9D=D0=A7=D0=95=D0=A1=D0=A2=D0=AB=20=D0=9D=D0=98=D0=9A=D0=9E?= =?UTF-8?q?=D0=93=D0=94=D0=90=20=D0=9D=D0=95=20=D0=91=D0=AB=D0=92=D0=90?= =?UTF-8?q?=D0=AE=D0=A2=20=D0=A1=D0=94=D0=92=D0=9E=D0=95=D0=9D=D0=9D=D0=AB?= =?UTF-8?q?=D0=95.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/META-INF/coremods.json | 3 +- .../resources/coremods/iron_chest_menus.js | 45 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/coremods/iron_chest_menus.js diff --git a/src/main/resources/META-INF/coremods.json b/src/main/resources/META-INF/coremods.json index 677dde2cf..715af5a6c 100644 --- a/src/main/resources/META-INF/coremods.json +++ b/src/main/resources/META-INF/coremods.json @@ -1,5 +1,6 @@ { "code_injector": "coremods/code_injector.js", "chest_menus": "coremods/chest_menus.js", - "limb_brush_overclock": "coremods/limb_brush_overclock.js" + "limb_brush_overclock": "coremods/limb_brush_overclock.js", + "iron_chest_menus": "coremods/iron_chest_menus.js" } \ No newline at end of file diff --git a/src/main/resources/coremods/iron_chest_menus.js b/src/main/resources/coremods/iron_chest_menus.js new file mode 100644 index 000000000..192b72f69 --- /dev/null +++ b/src/main/resources/coremods/iron_chest_menus.js @@ -0,0 +1,45 @@ + +var Opcodes = Java.type('org.objectweb.asm.Opcodes') +var MethodNode = Java.type('org.objectweb.asm.tree.MethodNode') +var VarInsnNode = Java.type('org.objectweb.asm.tree.VarInsnNode') +var MethodInsnNode = Java.type('org.objectweb.asm.tree.MethodInsnNode') +var InsnNode = Java.type('org.objectweb.asm.tree.InsnNode') +var TypeInsnNode = Java.type('org.objectweb.asm.tree.TypeInsnNode') + + +var isOwnPatches = [ + 'com.progwml6.ironchest.common.block.regular.entity.AbstractIronChestBlockEntity$1', +] + +function initializeCoreMod() { + var result = {} + + for (i in isOwnPatches) { + var clazz = isOwnPatches[i] + + result[clazz] = { + 'target': { + 'type': 'METHOD', + 'class': clazz, + 'methodName': 'isOwnContainer', + 'methodDesc': '(Lnet/minecraft/world/entity/player/Player;)Z' + }, + 'transformer': function(node) { + for (var i = 0; i < node.instructions.size(); i++) { + var instr = node.instructions.get(i) + + if ((instr.getOpcode() == Opcodes.INSTANCEOF || instr.getOpcode() == Opcodes.CHECKCAST) && instr.desc == 'com/progwml6/ironchest/common/inventory/IronChestMenu') { + instr.desc = 'ru/dbotthepony/mc/otm/compat/ironchest/MatteryIronChestMenu' + } else if (instr.getOpcode() == Opcodes.INVOKEVIRTUAL && instr.owner == 'com/progwml6/ironchest/common/inventory/IronChestMenu' && instr.name == 'getContainer') { + instr.owner = 'ru/dbotthepony/mc/otm/compat/ironchest/MatteryIronChestMenu' + instr.name = 'getContainer' + } + } + + return node + } + } + } + + return result +} From bb501e2c7e83a5e74f0831cd3b241a3c7347e263 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 10 Apr 2025 08:31:26 +0700 Subject: [PATCH 06/11] Mark "is mod loaded" as internal property, so it don't bleed into other namespaces --- .../ru/dbotthepony/mc/otm/compat/cos/CosmeticArmorCompat.kt | 2 +- .../kotlin/ru/dbotthepony/mc/otm/compat/curios/CuriosCompat.kt | 2 +- .../dbotthepony/mc/otm/compat/ironchest/IronChestMenuTypes.kt | 2 +- .../mc/otm/compat/ironshulkerbox/IronShulkersMenuTypes.kt | 2 +- .../dbotthepony/mc/otm/compat/itemborders/ItemBordersCompat.kt | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/cos/CosmeticArmorCompat.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/cos/CosmeticArmorCompat.kt index 0cb56a423..1106b0819 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/cos/CosmeticArmorCompat.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/cos/CosmeticArmorCompat.kt @@ -31,7 +31,7 @@ import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot import java.util.Collections.emptyIterator import java.util.stream.Stream -val isCosmeticArmorLoaded by lazy { +internal val isCosmeticArmorLoaded by lazy { ModList.get().isLoaded("cosmeticarmorreworked") } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/curios/CuriosCompat.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/curios/CuriosCompat.kt index d236113c1..ee2652365 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/curios/CuriosCompat.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/curios/CuriosCompat.kt @@ -35,7 +35,7 @@ import java.util.Collections.emptyIterator import java.util.stream.Stream import kotlin.collections.ArrayList -val isCuriosLoaded by lazy { +internal val isCuriosLoaded by lazy { ModList.get().isLoaded(CuriosApi.MODID) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/ironchest/IronChestMenuTypes.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/ironchest/IronChestMenuTypes.kt index c7203ff6b..ca612deee 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/ironchest/IronChestMenuTypes.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/ironchest/IronChestMenuTypes.kt @@ -22,7 +22,7 @@ import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot import ru.dbotthepony.mc.otm.menu.makeSlots import ru.dbotthepony.mc.otm.registry.MDeferredRegister -val isIronChestLoaded by lazy { +internal val isIronChestLoaded by lazy { ModList.get().isLoaded(IronChests.MODID) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/ironshulkerbox/IronShulkersMenuTypes.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/ironshulkerbox/IronShulkersMenuTypes.kt index ad49080e7..cebcc5a3f 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/ironshulkerbox/IronShulkersMenuTypes.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/ironshulkerbox/IronShulkersMenuTypes.kt @@ -24,7 +24,7 @@ import ru.dbotthepony.mc.otm.menu.makeSlots import ru.dbotthepony.mc.otm.registry.MDeferredRegister import kotlin.collections.toTypedArray -val isIronShulkersLoaded by lazy { +internal val isIronShulkersLoaded by lazy { ModList.get().isLoaded(IronShulkerBoxes.MODID) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/itemborders/ItemBordersCompat.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/itemborders/ItemBordersCompat.kt index 7464294ae..02619a2e6 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/itemborders/ItemBordersCompat.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/itemborders/ItemBordersCompat.kt @@ -5,7 +5,7 @@ import net.minecraft.world.inventory.Slot import net.neoforged.fml.ModList import ru.dbotthepony.mc.otm.client.render.MGUIGraphics -val isItemBordersLoaded by lazy { +internal val isItemBordersLoaded by lazy { ModList.get().isLoaded("itemborders") } From 389d0648b11d4798dceae16ce22da9437418b884 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 10 Apr 2025 10:12:01 +0700 Subject: [PATCH 07/11] Allow allocating indices sparsingly in IDAllocator --- .../ru/dbotthepony/mc/otm/util/IDAllocator.kt | 49 +++++++++++++------ 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/util/IDAllocator.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/util/IDAllocator.kt index 9fa5b05ff..cc197fb62 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/util/IDAllocator.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/util/IDAllocator.kt @@ -1,37 +1,58 @@ package ru.dbotthepony.mc.otm.util -import it.unimi.dsi.fastutil.ints.IntAVLTreeSet +import it.unimi.dsi.fastutil.ints.IntRBTreeSet class IDAllocator { - private var highestID = 0 - private val gaps = IntAVLTreeSet() + private var nextID = -1 + private val gaps = IntRBTreeSet() + private val sparseAllocations = IntRBTreeSet() + + private fun increaseHighestID(): Int { + while (sparseAllocations.remove(++nextID)) {} + return nextID + } fun allocate(): Int { if (gaps.isEmpty()) { - return highestID++ + return increaseHighestID() } else { return gaps.removeFirst() } } + fun allocate(id: Int): Boolean { + if (id < 0) { + return true // not handling negative IDs + } else if (id > nextID) { + sparseAllocations.add(id) + return true + } else if (id == nextID) { + increaseHighestID() + return true + } else { + return gaps.remove(id) + } + } + fun release(id: Int) { - if (id >= 0) { - throw IllegalArgumentException("Invalid ID: $id") - } else if (id >= highestID) { - throw IllegalArgumentException("Not tracking ID: $id (highest known ID is ${highestID - 1})") + if (id < 0) { + return // not handling negative IDs + } else if (sparseAllocations.remove(id)) { + return // was allocated above highest ID + } else if (id > nextID) { + throw IllegalArgumentException("Not tracking ID: $id (highest known ID is ${nextID})") } else if (id in gaps) { throw IllegalArgumentException("ID is already free: $id") - } - - if (id + 1 == highestID) { - highestID-- + } else if (id == nextID) { + nextID-- } else { - gaps.add(id) + check(gaps.add(id)) } } fun reset() { - highestID = 0 + nextID = -1 gaps.clear() + sparseAllocations.clear() } } From 1cfa2be1dddc92f8110b7b88f092c8909d974f40 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 10 Apr 2025 22:17:47 +0700 Subject: [PATCH 08/11] Make DynamicSynchableGroup implement Int2ReferenceMap what am i doing --- .../network/syncher/DynamicSynchableGroup.kt | 347 +++++++++++++++++- 1 file changed, 336 insertions(+), 11 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/network/syncher/DynamicSynchableGroup.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/network/syncher/DynamicSynchableGroup.kt index 1d2ac6625..cfa06cc6e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/network/syncher/DynamicSynchableGroup.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/network/syncher/DynamicSynchableGroup.kt @@ -1,8 +1,19 @@ package ru.dbotthepony.mc.otm.network.syncher import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap +import it.unimi.dsi.fastutil.ints.Int2ReferenceLinkedOpenHashMap +import it.unimi.dsi.fastutil.ints.Int2ReferenceMap +import it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap import it.unimi.dsi.fastutil.ints.IntArraySet +import it.unimi.dsi.fastutil.ints.IntCollection +import it.unimi.dsi.fastutil.ints.IntIterator +import it.unimi.dsi.fastutil.ints.IntSet +import it.unimi.dsi.fastutil.objects.ObjectIterator +import it.unimi.dsi.fastutil.objects.ObjectSet +import it.unimi.dsi.fastutil.objects.Reference2ObjectLinkedOpenHashMap +import it.unimi.dsi.fastutil.objects.ReferenceCollection import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet +import it.unimi.dsi.fastutil.objects.ReferenceSet import net.minecraft.network.RegistryFriendlyByteBuf import ru.dbotthepony.kommons.util.KOptional import ru.dbotthepony.mc.otm.util.IDAllocator @@ -39,7 +50,7 @@ class DynamicSynchableGroup( * first-time networking of [T] to remote */ private val writer: T.(RegistryFriendlyByteBuf) -> Unit = {}, -) : ISynchable, MutableSet { +) : ISynchable, ReferenceSet, Int2ReferenceMap { private inner class RemoteState(val listener: Runnable) : IRemoteState { private inner class RemoteSlot(val slot: Slot, fromConstructor: Boolean) : Runnable, Closeable { val remoteState = synchable(slot.value).createRemoteState(this) @@ -188,11 +199,12 @@ class DynamicSynchableGroup( } } - private data class Slot(val value: T, val id: Int) + private class Slot(val value: T, val id: Int) + private var defaultReturnValue: T? = null private val remoteStates = ArrayList() - private val value2slot = LinkedHashMap>() - private val id2slot = Int2ObjectOpenHashMap>() + private val value2slot = Reference2ObjectLinkedOpenHashMap>() + private val id2slot = Int2ReferenceLinkedOpenHashMap>() private val idAllocator = IDAllocator() override val hasRemotes: Boolean @@ -210,7 +222,7 @@ class DynamicSynchableGroup( REMOVE_ENTRY -> { val id = stream.readVarInt() val slot = checkNotNull(id2slot.remove(id)) { "No such slot with ID: $id" } - check(value2slot.remove(slot.value) == value2slot) + check(value2slot.remove(slot.value) == slot) remoteStates.forEach { it.remove(slot) } } @@ -223,7 +235,7 @@ class DynamicSynchableGroup( if (id2slot.containsKey(id)) { val slot = id2slot.remove(id)!! - check(value2slot.remove(slot.value) == value2slot) + check(value2slot.remove(slot.value) == slot) remoteStates.forEach { it.remove(slot) } } @@ -298,8 +310,8 @@ class DynamicSynchableGroup( return value2slot.isEmpty() } - override fun iterator(): MutableIterator { - return object : MutableIterator { + override fun iterator(): ObjectIterator { + return object : ObjectIterator { private val parent = value2slot.values.iterator() private var last: KOptional> = KOptional() @@ -323,11 +335,15 @@ class DynamicSynchableGroup( } } - override fun remove(element: T): Boolean { - val slot = value2slot.remove(element) ?: return false - checkNotNull(id2slot.remove(slot.id)) + private fun removeBySlot(slot: Slot) { + value2slot.remove(slot.value) + id2slot.remove(slot.id) remoteStates.forEach { it.remove(slot) } idAllocator.release(slot.id) + } + + override fun remove(element: T): Boolean { + removeBySlot(value2slot.remove(element) ?: return false) return true } @@ -351,6 +367,315 @@ class DynamicSynchableGroup( return any } + override fun put(key: Int, value: T): T? { + val slot = Slot(value, key) + val oldSlot = id2slot.put(key, slot) + + if (oldSlot?.value === value) + return value + + if (oldSlot != null) { + remoteStates.forEach { it.remove(oldSlot) } + value2slot.remove(oldSlot.value) + } else { + idAllocator.allocate(key) + } + + value2slot[value] = slot + remoteStates.forEach { it.add(slot) } + + return oldSlot?.value + } + + override fun get(key: Int): T? { + return id2slot.get(key)?.value ?: defaultReturnValue + } + + override fun containsKey(key: Int): Boolean { + return id2slot.containsKey(key) + } + + override fun defaultReturnValue(rv: T?) { + defaultReturnValue = rv + } + + override fun defaultReturnValue(): T? { + return defaultReturnValue + } + + override fun putAll(from: Map) { + from.forEach { (k, v) -> + put(k, v) + } + } + + override fun containsValue(value: T): Boolean { + return value2slot.containsKey(value) + } + + private val entrySet: ObjectSet> by lazy(LazyThreadSafetyMode.PUBLICATION) { + object : ObjectSet> { + inner class Entry(private val ikey: Int) : Int2ReferenceMap.Entry { + override val value: T + get() = id2slot[ikey]?.value ?: throw NoSuchElementException() + + override fun setValue(newValue: T): T? { + return put(ikey, newValue) + } + + override fun getIntKey(): Int { + return ikey + } + + override fun equals(other: Any?): Boolean { + return this === other || other is Int2ReferenceMap.Entry<*> && other.intKey == ikey && other.value === id2slot[ikey]?.value + } + + override fun hashCode(): Int { + return ikey * 31 + (id2slot[ikey] as Slot?).hashCode() + } + + override fun toString(): String { + return "Map.Entry[$ikey, ${id2slot[ikey]?.value}]" + } + } + + override val size: Int + get() = id2slot.size + + override fun add(element: Int2ReferenceMap.Entry): Boolean { + return put(element.intKey, element.value) != null + } + + override fun addAll(elements: Collection>): Boolean { + var any = false + elements.forEach { any = add(it) || any } + return any + } + + override fun clear() { + this@DynamicSynchableGroup.clear() + } + + override fun iterator(): ObjectIterator> { + return object : ObjectIterator> { + private val parent = id2slot.int2ReferenceEntrySet().iterator() + private var last: Slot? = null + + override fun hasNext(): Boolean { + return parent.hasNext() + } + + override fun remove() { + if (last == null) + throw NoSuchElementException() + + parent.remove() + removeBySlot(last!!) + last = null + } + + override fun next(): Int2ReferenceMap.Entry { + val value = parent.next() + last = value.value + return Entry(value.intKey) + } + } + } + + override fun remove(element: Int2ReferenceMap.Entry): Boolean { + val slot = id2slot.get(element.intKey) + + if (slot?.value === element.value) { + this@DynamicSynchableGroup.removeBySlot(slot) + return true + } + + return false + } + + override fun removeAll(elements: Collection>): Boolean { + var any = false + elements.forEach { any = remove(it) || any } + return any + } + + override fun retainAll(elements: Collection>): Boolean { + if (elements.isEmpty()) { + val isNotEmpty = id2slot.isNotEmpty() + this@DynamicSynchableGroup.clear() + return isNotEmpty + } + + var any = false + val itr = id2slot.int2ReferenceEntrySet().iterator() + + for (entry in itr) { + if (elements.none { it.intKey == entry.intKey && it.value === entry.value.value }) { + any = true + itr.remove() + removeBySlot(entry.value) + } + } + + return any + } + + override fun contains(element: Int2ReferenceMap.Entry): Boolean { + return id2slot.get(element.intKey)?.value === element.value + } + + override fun containsAll(elements: Collection>): Boolean { + return elements.all { contains(it) } + } + + override fun isEmpty(): Boolean { + return id2slot.isEmpty() + } + } + } + + override fun int2ReferenceEntrySet(): ObjectSet> { + return entrySet + } + + override val keys: IntSet by lazy(LazyThreadSafetyMode.PUBLICATION) { + object : IntSet { + override fun add(key: Int): Boolean { + throw UnsupportedOperationException() + } + + override fun addAll(c: IntCollection): Boolean { + throw UnsupportedOperationException() + } + + override fun addAll(elements: Collection): Boolean { + throw UnsupportedOperationException() + } + + override fun clear() { + this@DynamicSynchableGroup.clear() + } + + override fun iterator(): IntIterator { + return object : IntIterator { + private val parent = id2slot.keys.iterator() + private var last = -1 + private var hasLast = false + + override fun hasNext(): Boolean { + return parent.hasNext() + } + + override fun remove() { + if (!hasLast) + throw NoSuchElementException() + + hasLast = false + val slot = id2slot.get(last) + parent.remove() + removeBySlot(slot) + } + + override fun nextInt(): Int { + last = parent.nextInt() + hasLast = true + return last + } + } + } + + override fun remove(k: Int): Boolean { + removeBySlot(id2slot.get(k) ?: return false) + return true + } + + override fun removeAll(c: IntCollection): Boolean { + val itr = c.iterator() + var any = false + + while (itr.hasNext()) { + any = remove(itr.nextInt()) || any + } + + return any + } + + override fun removeAll(elements: Collection): Boolean { + val itr = elements.iterator() + var any = false + + while (itr.hasNext()) { + any = remove(itr.next()) || any + } + + return any + } + + override fun retainAll(c: IntCollection): Boolean { + val itr = id2slot.values.iterator() + var any = false + + for (slot in itr) { + if (!c.contains(slot.id)) { + itr.remove() + check(value2slot.remove(slot.value) == slot) + remoteStates.forEach { it.remove(slot) } + any = true + } + } + + return any + } + + override fun retainAll(elements: Collection): Boolean { + val itr = id2slot.values.iterator() + var any = false + + for (slot in itr) { + if (!elements.contains(slot.id)) { + itr.remove() + check(value2slot.remove(slot.value) == slot) + remoteStates.forEach { it.remove(slot) } + any = true + } + } + + return any + } + + override fun contains(key: Int): Boolean { + return id2slot.containsKey(key) + } + + override fun containsAll(c: IntCollection): Boolean { + return id2slot.keys.containsAll(c) + } + + override fun containsAll(elements: Collection): Boolean { + return id2slot.keys.containsAll(elements) + } + + override fun isEmpty(): Boolean { + return id2slot.isEmpty() + } + + override fun toArray(a: IntArray?): IntArray { + return id2slot.keys.toArray(a) + } + + override fun toIntArray(): IntArray { + return id2slot.keys.toIntArray() + } + + override val size: Int + get() = id2slot.size + } + } + + override val values: ReferenceCollection + get() = this + companion object { private const val END = 0 private const val ADD_ENTRY = 1 From 77443ee801c104a7fc7dada97685fe5f055bf85e Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 10 Apr 2025 22:29:52 +0700 Subject: [PATCH 09/11] To avoid name conflicts, move dynamic synchable group map implementation to asMap property --- .../network/syncher/DynamicSynchableGroup.kt | 586 +++++++++--------- 1 file changed, 306 insertions(+), 280 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/network/syncher/DynamicSynchableGroup.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/network/syncher/DynamicSynchableGroup.kt index cfa06cc6e..f7664893a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/network/syncher/DynamicSynchableGroup.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/network/syncher/DynamicSynchableGroup.kt @@ -50,7 +50,7 @@ class DynamicSynchableGroup( * first-time networking of [T] to remote */ private val writer: T.(RegistryFriendlyByteBuf) -> Unit = {}, -) : ISynchable, ReferenceSet, Int2ReferenceMap { +) : ISynchable, ReferenceSet { private inner class RemoteState(val listener: Runnable) : IRemoteState { private inner class RemoteSlot(val slot: Slot, fromConstructor: Boolean) : Runnable, Closeable { val remoteState = synchable(slot.value).createRemoteState(this) @@ -367,315 +367,341 @@ class DynamicSynchableGroup( return any } - override fun put(key: Int, value: T): T? { - val slot = Slot(value, key) - val oldSlot = id2slot.put(key, slot) + /** + * Representation of this synchable group as an [Int2ReferenceMap]. Changes made to [DynamicSynchableGroup] are reflected in this map + * and vice versa. Entries can be put at arbitrary keys, but negative keys should be avoided, since they are not efficiently + * networked, and hence will create a lot of network traffic if synchables with negative keys get frequently updated. + */ + val asMap: Int2ReferenceMap by lazy { + object : Int2ReferenceMap { + override fun isEmpty(): Boolean { + return this@DynamicSynchableGroup.isEmpty() + } - if (oldSlot?.value === value) - return value + override fun remove(key: Int): T? { + val slot = id2slot.remove(key) ?: return null + removeBySlot(slot) + return slot.value + } - if (oldSlot != null) { - remoteStates.forEach { it.remove(oldSlot) } - value2slot.remove(oldSlot.value) - } else { - idAllocator.allocate(key) - } - - value2slot[value] = slot - remoteStates.forEach { it.add(slot) } - - return oldSlot?.value - } - - override fun get(key: Int): T? { - return id2slot.get(key)?.value ?: defaultReturnValue - } - - override fun containsKey(key: Int): Boolean { - return id2slot.containsKey(key) - } - - override fun defaultReturnValue(rv: T?) { - defaultReturnValue = rv - } - - override fun defaultReturnValue(): T? { - return defaultReturnValue - } - - override fun putAll(from: Map) { - from.forEach { (k, v) -> - put(k, v) - } - } - - override fun containsValue(value: T): Boolean { - return value2slot.containsKey(value) - } - - private val entrySet: ObjectSet> by lazy(LazyThreadSafetyMode.PUBLICATION) { - object : ObjectSet> { - inner class Entry(private val ikey: Int) : Int2ReferenceMap.Entry { - override val value: T - get() = id2slot[ikey]?.value ?: throw NoSuchElementException() - - override fun setValue(newValue: T): T? { - return put(ikey, newValue) - } - - override fun getIntKey(): Int { - return ikey - } - - override fun equals(other: Any?): Boolean { - return this === other || other is Int2ReferenceMap.Entry<*> && other.intKey == ikey && other.value === id2slot[ikey]?.value - } - - override fun hashCode(): Int { - return ikey * 31 + (id2slot[ikey] as Slot?).hashCode() - } - - override fun toString(): String { - return "Map.Entry[$ikey, ${id2slot[ikey]?.value}]" - } + override fun getOrDefault(key: Int, defaultValue: T): T { + return super.getOrDefault(key, defaultValue) } override val size: Int - get() = id2slot.size + get() = this@DynamicSynchableGroup.size - override fun add(element: Int2ReferenceMap.Entry): Boolean { - return put(element.intKey, element.value) != null - } + override fun put(key: Int, value: T): T? { + val slot = Slot(value, key) + val oldSlot = id2slot.put(key, slot) - override fun addAll(elements: Collection>): Boolean { - var any = false - elements.forEach { any = add(it) || any } - return any - } + if (oldSlot?.value === value) + return value - override fun clear() { - this@DynamicSynchableGroup.clear() - } - - override fun iterator(): ObjectIterator> { - return object : ObjectIterator> { - private val parent = id2slot.int2ReferenceEntrySet().iterator() - private var last: Slot? = null - - override fun hasNext(): Boolean { - return parent.hasNext() - } - - override fun remove() { - if (last == null) - throw NoSuchElementException() - - parent.remove() - removeBySlot(last!!) - last = null - } - - override fun next(): Int2ReferenceMap.Entry { - val value = parent.next() - last = value.value - return Entry(value.intKey) - } - } - } - - override fun remove(element: Int2ReferenceMap.Entry): Boolean { - val slot = id2slot.get(element.intKey) - - if (slot?.value === element.value) { - this@DynamicSynchableGroup.removeBySlot(slot) - return true + if (oldSlot != null) { + remoteStates.forEach { it.remove(oldSlot) } + value2slot.remove(oldSlot.value) + } else { + idAllocator.allocate(key) } - return false + value2slot[value] = slot + remoteStates.forEach { it.add(slot) } + + return oldSlot?.value } - override fun removeAll(elements: Collection>): Boolean { - var any = false - elements.forEach { any = remove(it) || any } - return any + override fun get(key: Int): T? { + return id2slot.get(key)?.value ?: defaultReturnValue } - override fun retainAll(elements: Collection>): Boolean { - if (elements.isEmpty()) { - val isNotEmpty = id2slot.isNotEmpty() - this@DynamicSynchableGroup.clear() - return isNotEmpty - } - - var any = false - val itr = id2slot.int2ReferenceEntrySet().iterator() - - for (entry in itr) { - if (elements.none { it.intKey == entry.intKey && it.value === entry.value.value }) { - any = true - itr.remove() - removeBySlot(entry.value) - } - } - - return any - } - - override fun contains(element: Int2ReferenceMap.Entry): Boolean { - return id2slot.get(element.intKey)?.value === element.value - } - - override fun containsAll(elements: Collection>): Boolean { - return elements.all { contains(it) } - } - - override fun isEmpty(): Boolean { - return id2slot.isEmpty() - } - } - } - - override fun int2ReferenceEntrySet(): ObjectSet> { - return entrySet - } - - override val keys: IntSet by lazy(LazyThreadSafetyMode.PUBLICATION) { - object : IntSet { - override fun add(key: Int): Boolean { - throw UnsupportedOperationException() - } - - override fun addAll(c: IntCollection): Boolean { - throw UnsupportedOperationException() - } - - override fun addAll(elements: Collection): Boolean { - throw UnsupportedOperationException() - } - - override fun clear() { - this@DynamicSynchableGroup.clear() - } - - override fun iterator(): IntIterator { - return object : IntIterator { - private val parent = id2slot.keys.iterator() - private var last = -1 - private var hasLast = false - - override fun hasNext(): Boolean { - return parent.hasNext() - } - - override fun remove() { - if (!hasLast) - throw NoSuchElementException() - - hasLast = false - val slot = id2slot.get(last) - parent.remove() - removeBySlot(slot) - } - - override fun nextInt(): Int { - last = parent.nextInt() - hasLast = true - return last - } - } - } - - override fun remove(k: Int): Boolean { - removeBySlot(id2slot.get(k) ?: return false) - return true - } - - override fun removeAll(c: IntCollection): Boolean { - val itr = c.iterator() - var any = false - - while (itr.hasNext()) { - any = remove(itr.nextInt()) || any - } - - return any - } - - override fun removeAll(elements: Collection): Boolean { - val itr = elements.iterator() - var any = false - - while (itr.hasNext()) { - any = remove(itr.next()) || any - } - - return any - } - - override fun retainAll(c: IntCollection): Boolean { - val itr = id2slot.values.iterator() - var any = false - - for (slot in itr) { - if (!c.contains(slot.id)) { - itr.remove() - check(value2slot.remove(slot.value) == slot) - remoteStates.forEach { it.remove(slot) } - any = true - } - } - - return any - } - - override fun retainAll(elements: Collection): Boolean { - val itr = id2slot.values.iterator() - var any = false - - for (slot in itr) { - if (!elements.contains(slot.id)) { - itr.remove() - check(value2slot.remove(slot.value) == slot) - remoteStates.forEach { it.remove(slot) } - any = true - } - } - - return any - } - - override fun contains(key: Int): Boolean { + override fun containsKey(key: Int): Boolean { return id2slot.containsKey(key) } - override fun containsAll(c: IntCollection): Boolean { - return id2slot.keys.containsAll(c) + override fun defaultReturnValue(rv: T?) { + defaultReturnValue = rv } - override fun containsAll(elements: Collection): Boolean { - return id2slot.keys.containsAll(elements) + override fun defaultReturnValue(): T? { + return defaultReturnValue } - override fun isEmpty(): Boolean { - return id2slot.isEmpty() + override fun putAll(from: Map) { + from.forEach { (k, v) -> + put(k, v) + } } - override fun toArray(a: IntArray?): IntArray { - return id2slot.keys.toArray(a) + override fun containsValue(value: T): Boolean { + return value2slot.containsKey(value) } - override fun toIntArray(): IntArray { - return id2slot.keys.toIntArray() + private val entrySet: ObjectSet> by lazy(LazyThreadSafetyMode.PUBLICATION) { + object : ObjectSet> { + inner class Entry(private val ikey: Int) : Int2ReferenceMap.Entry { + override val value: T + get() = id2slot[ikey]?.value ?: throw NoSuchElementException() + + override fun setValue(newValue: T): T? { + return put(ikey, newValue) + } + + override fun getIntKey(): Int { + return ikey + } + + override fun equals(other: Any?): Boolean { + return this === other || other is Int2ReferenceMap.Entry<*> && other.intKey == ikey && other.value === id2slot[ikey]?.value + } + + override fun hashCode(): Int { + return ikey * 31 + (id2slot[ikey] as Slot?).hashCode() + } + + override fun toString(): String { + return "Map.Entry[$ikey, ${id2slot[ikey]?.value}]" + } + } + + override val size: Int + get() = id2slot.size + + override fun add(element: Int2ReferenceMap.Entry): Boolean { + return put(element.intKey, element.value) != null + } + + override fun addAll(elements: Collection>): Boolean { + var any = false + elements.forEach { any = add(it) || any } + return any + } + + override fun clear() { + this@DynamicSynchableGroup.clear() + } + + override fun iterator(): ObjectIterator> { + return object : ObjectIterator> { + private val parent = id2slot.int2ReferenceEntrySet().iterator() + private var last: Slot? = null + + override fun hasNext(): Boolean { + return parent.hasNext() + } + + override fun remove() { + if (last == null) + throw NoSuchElementException() + + parent.remove() + removeBySlot(last!!) + last = null + } + + override fun next(): Int2ReferenceMap.Entry { + val value = parent.next() + last = value.value + return Entry(value.intKey) + } + } + } + + override fun remove(element: Int2ReferenceMap.Entry): Boolean { + val slot = id2slot.get(element.intKey) + + if (slot?.value === element.value) { + this@DynamicSynchableGroup.removeBySlot(slot) + return true + } + + return false + } + + override fun removeAll(elements: Collection>): Boolean { + var any = false + elements.forEach { any = remove(it) || any } + return any + } + + override fun retainAll(elements: Collection>): Boolean { + if (elements.isEmpty()) { + val isNotEmpty = id2slot.isNotEmpty() + this@DynamicSynchableGroup.clear() + return isNotEmpty + } + + var any = false + val itr = id2slot.int2ReferenceEntrySet().iterator() + + for (entry in itr) { + if (elements.none { it.intKey == entry.intKey && it.value === entry.value.value }) { + any = true + itr.remove() + removeBySlot(entry.value) + } + } + + return any + } + + override fun contains(element: Int2ReferenceMap.Entry): Boolean { + return id2slot.get(element.intKey)?.value === element.value + } + + override fun containsAll(elements: Collection>): Boolean { + return elements.all { contains(it) } + } + + override fun isEmpty(): Boolean { + return id2slot.isEmpty() + } + } } - override val size: Int - get() = id2slot.size + override fun int2ReferenceEntrySet(): ObjectSet> { + return entrySet + } + + override val keys: IntSet by lazy(LazyThreadSafetyMode.PUBLICATION) { + object : IntSet { + override fun add(key: Int): Boolean { + throw UnsupportedOperationException() + } + + override fun addAll(c: IntCollection): Boolean { + throw UnsupportedOperationException() + } + + override fun addAll(elements: Collection): Boolean { + throw UnsupportedOperationException() + } + + override fun clear() { + this@DynamicSynchableGroup.clear() + } + + override fun iterator(): IntIterator { + return object : IntIterator { + private val parent = id2slot.keys.iterator() + private var last = -1 + private var hasLast = false + + override fun hasNext(): Boolean { + return parent.hasNext() + } + + override fun remove() { + if (!hasLast) + throw NoSuchElementException() + + hasLast = false + val slot = id2slot.get(last) + parent.remove() + removeBySlot(slot) + } + + override fun nextInt(): Int { + last = parent.nextInt() + hasLast = true + return last + } + } + } + + override fun remove(k: Int): Boolean { + removeBySlot(id2slot.get(k) ?: return false) + return true + } + + override fun removeAll(c: IntCollection): Boolean { + val itr = c.iterator() + var any = false + + while (itr.hasNext()) { + any = remove(itr.nextInt()) || any + } + + return any + } + + override fun removeAll(elements: Collection): Boolean { + val itr = elements.iterator() + var any = false + + while (itr.hasNext()) { + any = remove(itr.next()) || any + } + + return any + } + + override fun retainAll(c: IntCollection): Boolean { + val itr = id2slot.values.iterator() + var any = false + + for (slot in itr) { + if (!c.contains(slot.id)) { + itr.remove() + check(value2slot.remove(slot.value) == slot) + remoteStates.forEach { it.remove(slot) } + any = true + } + } + + return any + } + + override fun retainAll(elements: Collection): Boolean { + val itr = id2slot.values.iterator() + var any = false + + for (slot in itr) { + if (!elements.contains(slot.id)) { + itr.remove() + check(value2slot.remove(slot.value) == slot) + remoteStates.forEach { it.remove(slot) } + any = true + } + } + + return any + } + + override fun contains(key: Int): Boolean { + return id2slot.containsKey(key) + } + + override fun containsAll(c: IntCollection): Boolean { + return id2slot.keys.containsAll(c) + } + + override fun containsAll(elements: Collection): Boolean { + return id2slot.keys.containsAll(elements) + } + + override fun isEmpty(): Boolean { + return id2slot.isEmpty() + } + + override fun toArray(a: IntArray?): IntArray { + return id2slot.keys.toArray(a) + } + + override fun toIntArray(): IntArray { + return id2slot.keys.toIntArray() + } + + override val size: Int + get() = id2slot.size + } + } + + override val values: ReferenceCollection + get() = this@DynamicSynchableGroup } } - override val values: ReferenceCollection - get() = this - companion object { private const val END = 0 private const val ADD_ENTRY = 1 From e9a0983ab2b8622a6bf77da2a405639ec6fca303 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 11 Apr 2025 06:54:52 +0700 Subject: [PATCH 10/11] Add relative side and direction nullable codecs --- src/main/kotlin/ru/dbotthepony/mc/otm/network/StreamCodecs.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/network/StreamCodecs.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/network/StreamCodecs.kt index 62ce5522a..0402e7a67 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/network/StreamCodecs.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/network/StreamCodecs.kt @@ -39,6 +39,8 @@ object StreamCodecs { val BLOCK_TYPE = MatteryStreamCodec.Of(FriendlyByteBuf::writeBlockType, FriendlyByteBuf::readBlockType) val RELATIVE_SIDE = MatteryStreamCodec.Enum(RelativeSide::class.java) val DIRECTION = MatteryStreamCodec.Enum(Direction::class.java) + val RELATIVE_SIDE_NULLABLE = RELATIVE_SIDE.nullable() + val DIRECTION_NULLABLE = DIRECTION.nullable() val RGBA: MatteryStreamCodec = StreamCodec.of( { s, v -> s.writeFloat(v.red); s.writeFloat(v.green); s.writeFloat(v.blue); s.writeFloat(v.alpha) }, From ad71619b72ef25a8b9301f81b4790be6d05757b4 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 11 Apr 2025 08:15:55 +0700 Subject: [PATCH 11/11] Efficient "nullable" on Enum codec --- .../mc/otm/network/MatteryStreamCodec.kt | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryStreamCodec.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryStreamCodec.kt index a217ec302..c685fb861 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryStreamCodec.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryStreamCodec.kt @@ -189,6 +189,35 @@ interface MatteryStreamCodec : StreamCodec<@UnsafeVariance S, val values: List = listOf(*this.clazz.enumConstants!!) val valuesMap = values.associateBy { it.name } + private val nullable = object : MatteryStreamCodec { + override fun decode(stream: S): V? { + val value = stream.readVarInt() + + if (value == 0) { + return null + } else { + val id = value ushr 1 + return values.getOrNull(id) ?: throw NoSuchElementException("No such enum with index $id") + } + } + + override fun encode(stream: S, value: V?) { + if (value == null) { + stream.writeVarInt(0) + } else { + stream.writeVarInt(1 or (value.ordinal shl 1)) + } + } + + override fun copy(value: V?): V? { + return value + } + + override fun compare(a: V?, b: V?): Boolean { + return a === b + } + } + override fun decode(stream: S): V { val id = stream.readVarInt() return values.getOrNull(id) ?: throw NoSuchElementException("No such enum with index $id") @@ -206,6 +235,10 @@ interface MatteryStreamCodec : StreamCodec<@UnsafeVariance S, return a === b } + fun nullable(): MatteryStreamCodec { + return nullable + } + companion object { /** * FIXME: enums with abstract methods which get compiled to subclasses, whose DO NOT expose "parent's" enum constants array