diff --git a/dependencies.gradle b/dependencies.gradle index 3733be79..6940836e 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -122,6 +122,9 @@ dependencies { // Effortless Building (from CurseForge) compileOnly rfg.deobf("curse.maven:effortless-building-302113:2847346") // Version 2.16 + // FTB Utilities (from CurseForge) + compileOnly rfg.deobf("curse.maven:ftb-utilities-forge-237102:3157548") // Version 5.4.1.131 + // Better Questing Unofficial (from CurseForge) compileOnly rfg.deobf("curse.maven:better-questing-unofficial-629629:5183601") // Version 4.2.2 @@ -206,6 +209,11 @@ dependencies { runtimeOnly "curse.maven:effortless-building-302113:2847346" // Version 2.16 } + if (project.enable_ftb_utils.toBoolean()) { + runtimeOnly "curse.maven:ftb-library-legacy-forge-237167:2985811" // Version 5.4.7.2 + runtimeOnly "curse.maven:ftb-utilities-forge-237102:3157548" // Version 5.4.1.131 + } + if (project.enable_bqu.toBoolean()) { runtimeOnly "curse.maven:better-questing-unofficial-629629:5183601" // Version 4.2.2 } diff --git a/gradle.properties b/gradle.properties index eebd93be..d856a746 100644 --- a/gradle.properties +++ b/gradle.properties @@ -154,7 +154,9 @@ curseForgeRelations = requiredDependency:codechicken-lib-1-8;\ optionalDependency:better-questing-unofficial;\ optionalDependency:controlling;\ optionalDependency:default-world-generator-port;\ - optionalDependency:dme; + optionalDependency:dme;\ + optionalDependency:ftb-library-legacy-forge;\ + optionalDependency:ftb-utilities-forge; # This project's release type on CurseForge and/or Modrinth # Alternatively this can be set with the 'RELEASE_TYPE' environment variable. @@ -226,7 +228,7 @@ enable_chisel = false enable_ae2 = false # Whether to enable DME in runtime. Enables the DME Dat Hatch. -enable_dme = true +enable_dme = false # Whether to enable Extended Crafting in runtime. Enables Extended Crafting Blocks in DME Sim Chamber and Naq Reactors. # If this is set to false, those blocks will be set to air. @@ -257,7 +259,11 @@ enable_architecture_craft = false # Whether to enable Effortless Building in runtime. Enables the mixin which improves clarity of Reach Upgrades. # If this is set to false, the mixin will not apply. -enable_effortless_building = false +enable_effortless_building = true + +# Whether to enable FTB Utilities in runtime. Enables mixins which provide fixes relating to Ghost Items, and Effortless + FTB Utils Compat. +# If this is set to false, Effortless + FTB Utils Compat will not be applied, and the mixin will not apply. +enable_ftb_utils = true # Whether to enable BQu in runtime. Enables Labs Tier Helper. enable_bqu = false diff --git a/src/main/java/com/nomiceu/nomilabs/LabsValues.java b/src/main/java/com/nomiceu/nomilabs/LabsValues.java index e2915efd..831d9538 100644 --- a/src/main/java/com/nomiceu/nomilabs/LabsValues.java +++ b/src/main/java/com/nomiceu/nomilabs/LabsValues.java @@ -37,4 +37,5 @@ public class LabsValues { public static final String CONTROLLING_MODID = "controlling"; public static final String DEFAULT_WORLD_GEN_MODID = "defaultworldgenerator-port"; public static final String DME_MODID = "deepmoblearning"; + public static final String FTB_UTILS_MODID = "ftbutilities"; } diff --git a/src/main/java/com/nomiceu/nomilabs/NomiLabs.java b/src/main/java/com/nomiceu/nomilabs/NomiLabs.java index 4f9645f4..e06e29bf 100644 --- a/src/main/java/com/nomiceu/nomilabs/NomiLabs.java +++ b/src/main/java/com/nomiceu/nomilabs/NomiLabs.java @@ -2,6 +2,7 @@ import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fml.common.Loader; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod.EventHandler; import net.minecraftforge.fml.common.event.*; @@ -9,8 +10,11 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import com.nomiceu.nomilabs.config.LabsConfig; import com.nomiceu.nomilabs.event.ClientProxy; import com.nomiceu.nomilabs.event.CommonProxy; +import com.nomiceu.nomilabs.integration.effortlessbuilding.EffortlessEventHandler; +import com.nomiceu.nomilabs.integration.ftbutilities.event.FTBUtilsEventHandler; import com.nomiceu.nomilabs.remap.datafixer.DataFixerHandler; import com.nomiceu.nomilabs.util.LabsSide; @@ -23,12 +27,17 @@ "required-after:jei@[4.15.0,);" + "required-after:theoneprobe;" + "after:advancedrocketry;" + "after:libvulpes;" + "after:crafttweaker@[4.1.20,);" + "after:appliedenergistics2;" + "after:architecturecraft;" + "after:effortlessbuilding;" + "after:betterquesting;" + - "after:defaultworldgenerator-port;" + "after:deepmoblearning;") + "after:defaultworldgenerator-port;" + "after:deepmoblearning;" + "after:ftbutilities;") @SuppressWarnings("unused") public class NomiLabs { public static final Logger LOGGER = LogManager.getLogger(LabsValues.LABS_MODID); + @EventHandler + public void onConstruction(FMLConstructionEvent event) { + CommonProxy.onConstruction(); + } + @EventHandler public void preInit(FMLPreInitializationEvent event) { MinecraftForge.EVENT_BUS.register(this); @@ -37,6 +46,14 @@ public void preInit(FMLPreInitializationEvent event) { CommonProxy.preInit(); if (LabsSide.isClient()) ClientProxy.latePreInit(); + + if (Loader.isModLoaded(LabsValues.EFFORTLESS_MODID) && + LabsConfig.modIntegration.effortlessBuildingIntegration.enableEffortlessBuildingIntegration) + MinecraftForge.EVENT_BUS.register(EffortlessEventHandler.class); + + if (Loader.isModLoaded(LabsValues.FTB_UTILS_MODID) && + LabsConfig.modIntegration.enableFTBUtilsIntegration) + MinecraftForge.EVENT_BUS.register(FTBUtilsEventHandler.class); } @EventHandler diff --git a/src/main/java/com/nomiceu/nomilabs/config/LabsConfig.java b/src/main/java/com/nomiceu/nomilabs/config/LabsConfig.java index 6e97ad87..820fa0ed 100644 --- a/src/main/java/com/nomiceu/nomilabs/config/LabsConfig.java +++ b/src/main/java/com/nomiceu/nomilabs/config/LabsConfig.java @@ -224,9 +224,17 @@ public static class ModIntegration { @Config.Name("effortless building integration") public final EffortlessBuildingIntegration effortlessBuildingIntegration = new EffortlessBuildingIntegration(); + @Config.Comment({ + "Whether to enable FTB Utilities Integration. Makes Status Messages more consistent, translatable, and fixes issues relating to Ghost Items.", + "[default: true]" }) + @Config.LangKey("config.nomilabs.mod_integration.ftb_utils") + @Config.RequiresMcRestart + public boolean enableFTBUtilsIntegration = true; + public static class EffortlessBuildingIntegration { @Config.Comment({ "Whether to enable Effortless Building Integration, which splits the parts of reach.", + "Also fixes various Dupe and Transmutation Bugs, and fixes allowing Placing Blocks in FTB Utils Claimed Chunks.", "None of the below options work if this config is set to false.", "[default: true]" }) @Config.LangKey("config.nomilabs.mod_integration.effortlessbuilding.enable") @@ -236,61 +244,51 @@ public static class EffortlessBuildingIntegration { @Config.Comment({ "Max Reach Per Axis Without Upgrades.", "[default: 8]" }) @Config.LangKey("config.nomilabs.mod_integration.effortlessbuilding.axis.0") - @Config.RequiresMcRestart public int axisReach0 = 8; @Config.Comment({ "Max Reach Per Axis With 1 Upgrade.", "[default: 16]" }) @Config.LangKey("config.nomilabs.mod_integration.effortlessbuilding.axis.1") - @Config.RequiresMcRestart public int axisReach1 = 16; @Config.Comment({ "Max Reach Per Axis With 2 Upgrades.", "[default: 32]" }) @Config.LangKey("config.nomilabs.mod_integration.effortlessbuilding.axis.2") - @Config.RequiresMcRestart public int axisReach2 = 32; @Config.Comment({ "Max Reach Per Axis With 3 Upgrades.", "[default: 64]" }) @Config.LangKey("config.nomilabs.mod_integration.effortlessbuilding.axis.3") - @Config.RequiresMcRestart public int axisReach3 = 64; @Config.Comment({ "Max Reach Per Axis In Creative.", "[default: 2048]" }) @Config.LangKey("config.nomilabs.mod_integration.effortlessbuilding.axis.creative") - @Config.RequiresMcRestart public int axisReachCreative = 2048; @Config.Comment({ "Max Blocks Placed at Once Without Upgrades.", "[default: 256]" }) @Config.LangKey("config.nomilabs.mod_integration.effortlessbuilding.blocks.0") - @Config.RequiresMcRestart public int blocksPlaced0 = 256; @Config.Comment({ "Max Blocks Placed at Once With 1 Upgrade.", "[default: 2048]" }) @Config.LangKey("config.nomilabs.mod_integration.effortlessbuilding.blocks.1") - @Config.RequiresMcRestart public int blocksPlaced1 = 2048; @Config.Comment({ "Max Blocks Placed at Once With 2 Upgrades.", "[default: 16384]" }) @Config.LangKey("config.nomilabs.mod_integration.effortlessbuilding.blocks.2") - @Config.RequiresMcRestart public int blocksPlaced2 = 16384; @Config.Comment({ "Max Blocks Placed at Once With 3 Upgrades.", "[default: 131072]" }) @Config.LangKey("config.nomilabs.mod_integration.effortlessbuilding.blocks.3") - @Config.RequiresMcRestart public int blocksPlaced3 = 131072; @Config.Comment({ "Max Blocks Placed at Once In Creative.", "[default: 1048576]" }) @Config.LangKey("config.nomilabs.mod_integration.effortlessbuilding.blocks.creative") - @Config.RequiresMcRestart public int blocksPlacedCreative = 1048576; } diff --git a/src/main/java/com/nomiceu/nomilabs/core/LabsLateMixin.java b/src/main/java/com/nomiceu/nomilabs/core/LabsLateMixin.java index af28f9e4..209cc63e 100644 --- a/src/main/java/com/nomiceu/nomilabs/core/LabsLateMixin.java +++ b/src/main/java/com/nomiceu/nomilabs/core/LabsLateMixin.java @@ -38,7 +38,9 @@ public class LabsLateMixin implements ILateMixinLoader { new AbstractMap.SimpleImmutableEntry<>(LabsValues.CONTROLLING_MODID, true), new AbstractMap.SimpleImmutableEntry<>(LabsValues.DEFAULT_WORLD_GEN_MODID, LabsConfig.modIntegration.enableDefaultWorldGenIntegration), - new AbstractMap.SimpleImmutableEntry<>(LabsValues.DME_MODID, true)) + new AbstractMap.SimpleImmutableEntry<>(LabsValues.DME_MODID, true), + new AbstractMap.SimpleImmutableEntry<>(LabsValues.FTB_UTILS_MODID, + LabsConfig.modIntegration.enableFTBUtilsIntegration)) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); @Override diff --git a/src/main/java/com/nomiceu/nomilabs/event/CommonProxy.java b/src/main/java/com/nomiceu/nomilabs/event/CommonProxy.java index b994e11f..d234b591 100644 --- a/src/main/java/com/nomiceu/nomilabs/event/CommonProxy.java +++ b/src/main/java/com/nomiceu/nomilabs/event/CommonProxy.java @@ -37,6 +37,7 @@ import com.nomiceu.nomilabs.integration.top.TOPTooltipManager; import com.nomiceu.nomilabs.item.ItemExcitationCoil; import com.nomiceu.nomilabs.item.registry.LabsItems; +import com.nomiceu.nomilabs.network.LabsNetworkHandler; import com.nomiceu.nomilabs.recipe.HandFramingRecipe; import com.nomiceu.nomilabs.remap.LabsRemappers; import com.nomiceu.nomilabs.remap.Remapper; @@ -53,6 +54,10 @@ @SuppressWarnings("unused") public class CommonProxy { + public static void onConstruction() { + LabsNetworkHandler.onConstruction(); + } + public static void preInit() { LabsModeHelper.check(); @@ -82,6 +87,8 @@ public static void preInit() { DataFixerHandler.preInit(); FluidRegistryMixinHelper.preInit(); + + LabsNetworkHandler.preInit(); } public static void loadComplete() { diff --git a/src/main/java/com/nomiceu/nomilabs/gregtech/recipe/recipelogic/DMERecipeLogic.java b/src/main/java/com/nomiceu/nomilabs/gregtech/recipe/recipelogic/DMERecipeLogic.java index 3a35912a..e6bb8efa 100644 --- a/src/main/java/com/nomiceu/nomilabs/gregtech/recipe/recipelogic/DMERecipeLogic.java +++ b/src/main/java/com/nomiceu/nomilabs/gregtech/recipe/recipelogic/DMERecipeLogic.java @@ -33,9 +33,11 @@ protected boolean setupAndConsumeRecipeInputs(@NotNull Recipe recipe, for (var stack : list) { if (stack.getItem() == searchItem && DataModelHelper.getTier(stack) == searchTier) { DataModelHelper.setCurrentTierDataCount(stack, - Math.min(Integer.MAX_VALUE, DataModelHelper.getCurrentTierDataCount(stack) + property.getAddition())); + Math.min(Integer.MAX_VALUE, + DataModelHelper.getCurrentTierDataCount(stack) + property.getAddition())); DataModelHelper.setTotalSimulationCount(stack, - Math.min(Integer.MAX_VALUE, DataModelHelper.getTotalSimulationCount(stack) + property.getAddition())); + Math.min(Integer.MAX_VALUE, + DataModelHelper.getTotalSimulationCount(stack) + property.getAddition())); var increase = true; while (increase) { increase = DataModelHelperAccessor.tryIncreaseTier(stack); diff --git a/src/main/java/com/nomiceu/nomilabs/integration/effortlessbuilding/EffortlessEventHandler.java b/src/main/java/com/nomiceu/nomilabs/integration/effortlessbuilding/EffortlessEventHandler.java new file mode 100644 index 00000000..a8a72903 --- /dev/null +++ b/src/main/java/com/nomiceu/nomilabs/integration/effortlessbuilding/EffortlessEventHandler.java @@ -0,0 +1,37 @@ +package com.nomiceu.nomilabs.integration.effortlessbuilding; + +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.ItemBlock; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +import nl.requios.effortlessbuilding.EffortlessBuilding; +import nl.requios.effortlessbuilding.buildmode.BuildModes; +import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager; +import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; +import nl.requios.effortlessbuilding.network.RequestLookAtMessage; + +@SuppressWarnings("unused") +public class EffortlessEventHandler { + + @SubscribeEvent + public static void onPlayerInteract(PlayerInteractEvent.RightClickBlock event) { + var player = event.getEntityPlayer(); + var stack = player.getHeldItem(event.getHand()); + if (!(stack.getItem() instanceof ItemBlock itemBlock)) return; + + BuildModes.BuildModeEnum buildMode = ModeSettingsManager.getModeSettings(player).getBuildMode(); + ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player); + + if (buildMode != BuildModes.BuildModeEnum.NORMAL) { + event.setCanceled(true); + } else if (modifierSettings.doQuickReplace()) { + event.setCanceled(true); + if (!event.getWorld().isRemote && player instanceof EntityPlayerMP playerMP) { + EffortlessBuilding.packetHandler.sendTo(new RequestLookAtMessage(true), playerMP); + } + } else if (!event.getWorld().isRemote && player instanceof EntityPlayerMP playerMP) { + EffortlessBuilding.packetHandler.sendTo(new RequestLookAtMessage(false), playerMP); + } + } +} diff --git a/src/main/java/com/nomiceu/nomilabs/integration/effortlessbuilding/GenericReachUpgrade.java b/src/main/java/com/nomiceu/nomilabs/integration/effortlessbuilding/GenericReachUpgrade.java index a22b8b3e..d4746be9 100644 --- a/src/main/java/com/nomiceu/nomilabs/integration/effortlessbuilding/GenericReachUpgrade.java +++ b/src/main/java/com/nomiceu/nomilabs/integration/effortlessbuilding/GenericReachUpgrade.java @@ -2,6 +2,7 @@ import java.util.List; import java.util.Map; +import java.util.function.Supplier; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; @@ -15,26 +16,27 @@ import nl.requios.effortlessbuilding.BuildConfig; import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; +import scala.Int; public class GenericReachUpgrade { public static final int CREATIVE_LEVEL = -1; public static Map REACH_MAP = ImmutableMap.of( - -1, new ReachInfo(BuildConfig.reach.maxReachCreative, - LabsConfig.modIntegration.effortlessBuildingIntegration.axisReachCreative, - LabsConfig.modIntegration.effortlessBuildingIntegration.blocksPlacedCreative), - 0, new ReachInfo(BuildConfig.reach.maxReachLevel0, - LabsConfig.modIntegration.effortlessBuildingIntegration.axisReach0, - LabsConfig.modIntegration.effortlessBuildingIntegration.blocksPlaced0), - 1, new ReachInfo(BuildConfig.reach.maxReachLevel1, - LabsConfig.modIntegration.effortlessBuildingIntegration.axisReach1, - LabsConfig.modIntegration.effortlessBuildingIntegration.blocksPlaced1), - 2, new ReachInfo(BuildConfig.reach.maxReachLevel2, - LabsConfig.modIntegration.effortlessBuildingIntegration.axisReach2, - LabsConfig.modIntegration.effortlessBuildingIntegration.blocksPlaced2), - 3, new ReachInfo(BuildConfig.reach.maxReachLevel3, - LabsConfig.modIntegration.effortlessBuildingIntegration.axisReach3, - LabsConfig.modIntegration.effortlessBuildingIntegration.blocksPlaced3)); + -1, new ReachInfo(() -> BuildConfig.reach.maxReachCreative, + () -> LabsConfig.modIntegration.effortlessBuildingIntegration.axisReachCreative, + () -> LabsConfig.modIntegration.effortlessBuildingIntegration.blocksPlacedCreative), + 0, new ReachInfo(() -> BuildConfig.reach.maxReachLevel0, + () -> LabsConfig.modIntegration.effortlessBuildingIntegration.axisReach0, + () -> LabsConfig.modIntegration.effortlessBuildingIntegration.blocksPlaced0), + 1, new ReachInfo(() -> BuildConfig.reach.maxReachLevel1, + () -> LabsConfig.modIntegration.effortlessBuildingIntegration.axisReach1, + () -> LabsConfig.modIntegration.effortlessBuildingIntegration.blocksPlaced1), + 2, new ReachInfo(() -> BuildConfig.reach.maxReachLevel2, + () -> LabsConfig.modIntegration.effortlessBuildingIntegration.axisReach2, + () -> LabsConfig.modIntegration.effortlessBuildingIntegration.blocksPlaced2), + 3, new ReachInfo(() -> BuildConfig.reach.maxReachLevel3, + () -> LabsConfig.modIntegration.effortlessBuildingIntegration.axisReach3, + () -> LabsConfig.modIntegration.effortlessBuildingIntegration.blocksPlaced3)); // A complete overwrite so everything can be localized! public static ActionResult onItemRightClick(World world, EntityPlayer player, EnumHand hand, @@ -64,9 +66,9 @@ public static ActionResult onItemRightClick(World world, EntityPlayer EffortlessBuilding.log(player, LabsTranslate.translate("effortlessbuilding.use.reach_upgrade.success.1")); EffortlessBuilding.log(player, LabsTranslate.translate("effortlessbuilding.use.reach_upgrade.success.2", - currentReach.axis, newReach.axis)); + currentReach.getAxis(), newReach.getAxis())); EffortlessBuilding.log(player, LabsTranslate.translate("effortlessbuilding.use.reach_upgrade.success.3", - currentReach.distance, newReach.distance)); + currentReach.getDistance(), newReach.getDistance())); } player.setHeldItem(hand, ItemStack.EMPTY); @@ -84,20 +86,32 @@ public static ActionResult onItemRightClick(World world, EntityPlayer public static void addInformation(List tooltip, int level) { ReachInfo reach = REACH_MAP.get(level); tooltip.add(LabsTranslate.translate("effortlessbuilding.item.reach_upgrade.tooltip.1")); - tooltip.add(LabsTranslate.translate("effortlessbuilding.item.reach_upgrade.tooltip.2", reach.axis)); - tooltip.add(LabsTranslate.translate("effortlessbuilding.item.reach_upgrade.tooltip.3", reach.distance)); + tooltip.add(LabsTranslate.translate("effortlessbuilding.item.reach_upgrade.tooltip.2", reach.getAxis())); + tooltip.add(LabsTranslate.translate("effortlessbuilding.item.reach_upgrade.tooltip.3", reach.getDistance())); } public static class ReachInfo { + // Uses Suppliers so that we can change configs on the fly + private final Supplier distance; + private final Supplier axis; + private final Supplier maxBlocks; - public final int distance; - public final int axis; - public final int maxBlocks; - - public ReachInfo(int distance, int axis, int maxBlocks) { + public ReachInfo(Supplier distance, Supplier axis, Supplier maxBlocks) { this.distance = distance; this.axis = axis; this.maxBlocks = maxBlocks; } + + public int getDistance() { + return distance.get(); + } + + public int getAxis() { + return axis.get(); + } + + public int getMaxBlocks() { + return maxBlocks.get(); + } } } diff --git a/src/main/java/com/nomiceu/nomilabs/integration/effortlessbuilding/ImprovedInventoryHelper.java b/src/main/java/com/nomiceu/nomilabs/integration/effortlessbuilding/ImprovedInventoryHelper.java new file mode 100644 index 00000000..61ee4e32 --- /dev/null +++ b/src/main/java/com/nomiceu/nomilabs/integration/effortlessbuilding/ImprovedInventoryHelper.java @@ -0,0 +1,33 @@ +package com.nomiceu.nomilabs.integration.effortlessbuilding; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemBlock; +import net.minecraft.item.ItemStack; + +public class ImprovedInventoryHelper { + + public static ItemStack findItemStackInInventory(EntityPlayer player, IBlockState state) { + var block = state.getBlock(); + var meta = block.getMetaFromState(state); + for (ItemStack invStack : player.inventory.mainInventory) { + if (!invStack.isEmpty() && invStack.getItem() instanceof ItemBlock itemBlock && + itemBlock.getBlock().equals(block) && invStack.getMetadata() == meta) { + return invStack; + } + } + return ItemStack.EMPTY; + } + + public static ItemStack findItemStackInInventory(EntityPlayer player, ItemStack stack) { + var item = stack.getItem(); + var meta = stack.getMetadata(); + for (ItemStack invStack : player.inventory.mainInventory) { + if (!invStack.isEmpty() && invStack.getItem() instanceof ItemBlock itemBlock && itemBlock.equals(item) && + invStack.getMetadata() == meta) { + return invStack; + } + } + return ItemStack.EMPTY; + } +} diff --git a/src/main/java/com/nomiceu/nomilabs/integration/ftbutilities/CanEditChunkDataMessageHelper.java b/src/main/java/com/nomiceu/nomilabs/integration/ftbutilities/CanEditChunkDataMessageHelper.java new file mode 100644 index 00000000..198b6ca8 --- /dev/null +++ b/src/main/java/com/nomiceu/nomilabs/integration/ftbutilities/CanEditChunkDataMessageHelper.java @@ -0,0 +1,170 @@ +package com.nomiceu.nomilabs.integration.ftbutilities; + +import static com.feed_the_beast.ftbutilities.data.ClaimedChunks.instance; +import static com.nomiceu.nomilabs.integration.ftbutilities.network.CanEditChunkDataMessage.*; + +import java.lang.reflect.InvocationTargetException; +import java.util.UUID; + +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.math.MathHelper; + +import org.apache.logging.log4j.Level; +import org.jetbrains.annotations.Nullable; + +import com.feed_the_beast.ftbutilities.data.ClaimedChunk; +import com.feed_the_beast.ftbutilities.data.ClaimedChunks; +import com.nomiceu.nomilabs.NomiLabs; +import com.nomiceu.nomilabs.integration.ftbutilities.network.CanEditChunkDataMessage; +import com.nomiceu.nomilabs.network.LabsNetworkHandler; + +public class CanEditChunkDataMessageHelper { + + public static void sendMessageToAll() { + if (!ClaimedChunks.isActive()) return; + + var server = getUniverseServer(); + if (server == null) return; + + for (EntityPlayerMP player : server.getPlayerList().getPlayers()) { + sendMessage(player); + } + } + + public static void sendMessage(EntityPlayerMP player) { + // Same as dividing by 16, but faster + int chunkX = MathHelper.floor(player.posX) >> 4; + int chunkZ = MathHelper.floor(player.posZ) >> 4; + + int startX = chunkX - STORAGE_WIDTH / 2; + int startZ = chunkZ - STORAGE_WIDTH / 2; + + int dim = player.world.provider.getDimension(); + + boolean[] storage = new boolean[STORAGE_LENGTH]; + + for (int x = 0; x < STORAGE_WIDTH; x++) { + for (int z = 0; z < STORAGE_WIDTH; z++) { + storage[x * STORAGE_WIDTH + z] = !playerCanEdit(startX + x, startZ + z, dim, player); + } + } + + LabsNetworkHandler.NETWORK_HANDLER.sendTo(new CanEditChunkDataMessage(startX, startZ, storage), player); + NomiLabs.LOGGER.debug("[FTB Utils Integration] Sent CanEditChunkDataMessage to Player {} ({})", + player.getUniqueID(), player.getName()); + } + + /** + * Reflection to see whether a chunk is editable by the player. + * Equal to `getChunk(new ChunkDimPos(posX, posZ, dim)).getTeam().hasStatus(instance.universe.getPlayer(player), + * chunk.getData().getAttackEntitiesStatus())` + */ + private static boolean playerCanEdit(int posX, int posZ, int dim, EntityPlayerMP player) { + var chunk = getChunk(posX, posZ, dim); + var forgePlayer = getUniversePlayer(player); + if (chunk == null || forgePlayer == null) return true; + + try { + var getTeamMethod = chunk.getClass().getDeclaredMethod("getTeam"); + var team = getTeamMethod.invoke(chunk); + + var getDataMethod = chunk.getClass().getDeclaredMethod("getData"); + var data = getDataMethod.invoke(chunk); + + var getStatusMethod = data.getClass().getDeclaredMethod("getEditBlocksStatus"); + var status = getStatusMethod.invoke(data); + + var hasStatusMethod = team.getClass().getDeclaredMethod("hasStatus", forgePlayer.getClass(), + status.getClass()); + return (Boolean) hasStatusMethod.invoke(team, forgePlayer, status); + } catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) { + NomiLabs.LOGGER.fatal( + "[FTB Utils Integration] Failed to Check whether Player {} can edit at posX {}, posZ {}, dim {}! See Exception Below!", + player.getUniqueID(), posX, posZ, dim); + NomiLabs.LOGGER.throwing(Level.FATAL, e); + return true; + } + } + + /** + * Reflection to Grab 'ForgePlayer' From Universe. Done to not use FTBLib. (Breaks Compiling) + * Equal to `instance.universe.getPlayer(player)` + */ + @Nullable + private static Object getUniversePlayer(EntityPlayerMP player) { + var universe = getUniverse(); + if (universe == null) return null; + try { + var forgePlayerMethod = universe.getClass().getDeclaredMethod("getPlayer", UUID.class); + return forgePlayerMethod.invoke(universe, player.getUniqueID()); + } catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) { + NomiLabs.LOGGER.fatal("[FTB Utils Integration] Failed to get Universe Player! See Exception Below!"); + NomiLabs.LOGGER.throwing(Level.FATAL, e); + return null; + } + } + + /** + * Reflection to Grab Universe Server. Done to not use FTBLib. (Breaks Compiling) + * Equal to `instance.universe.server` + */ + @Nullable + private static MinecraftServer getUniverseServer() { + var universe = getUniverse(); + if (universe == null) return null; + + try { + var serverField = universe.getClass().getDeclaredField("server"); + return (MinecraftServer) serverField.get(universe); + } catch (NoSuchFieldException | IllegalAccessException e) { + NomiLabs.LOGGER.fatal("[FTB Utils Integration] Failed to get Universe Server! See Exception Below!"); + NomiLabs.LOGGER.throwing(Level.FATAL, e); + return null; + } + } + + /** + * Reflection to Grab Universe. Done to not use FTBLib. (Breaks Compiling) + * Equal to `instance.universe` + */ + @Nullable + public static Object getUniverse() { + try { + var instance = ClaimedChunks.instance; + var universeField = instance.getClass().getDeclaredField("universe"); + return universeField.get(instance); + } catch (NoSuchFieldException | IllegalAccessException e) { + NomiLabs.LOGGER.fatal("[FTB Utils Integration] Failed to get Universe! See Exception Below!"); + NomiLabs.LOGGER.throwing(Level.FATAL, e); + return null; + } + } + + /** + * Reflection to Grab Claimed Chunk. Done to not use FTBLib. (Breaks Compiling) + * Equal to `getChunk(new ChunkDimPos(posX, posZ, dim))` + */ + @Nullable + private static ClaimedChunk getChunk(int posX, int posZ, int dim) { + try { + var chunkDimPosClass = Class.forName("com.feed_the_beast.ftblib.lib.math.ChunkDimPos"); + var constructor = chunkDimPosClass.getConstructor(int.class, int.class, int.class); + Object obj = constructor.newInstance(posX, posZ, dim); + + var claimedChunksClass = Class.forName("com.feed_the_beast.ftbutilities.data.ClaimedChunks"); + var getChunkMethod = claimedChunksClass.getDeclaredMethod("getChunk", chunkDimPosClass); + + // noinspection JavaReflectionInvocation + return (ClaimedChunk) getChunkMethod.invoke(instance, chunkDimPosClass.cast(obj)); + } catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException | IllegalAccessException | + InstantiationException e) { + NomiLabs.LOGGER.fatal( + "[FTB Utils Integration] Failed to get Chunk with posX {}, posZ {}, dim {}! See Exception Below!", + posX, + posZ, dim); + NomiLabs.LOGGER.throwing(Level.FATAL, e); + return null; + } + } +} diff --git a/src/main/java/com/nomiceu/nomilabs/integration/ftbutilities/CanEditChunkHelper.java b/src/main/java/com/nomiceu/nomilabs/integration/ftbutilities/CanEditChunkHelper.java new file mode 100644 index 00000000..fdfe581f --- /dev/null +++ b/src/main/java/com/nomiceu/nomilabs/integration/ftbutilities/CanEditChunkHelper.java @@ -0,0 +1,58 @@ +package com.nomiceu.nomilabs.integration.ftbutilities; + +import java.util.Comparator; +import java.util.Map; +import java.util.stream.Collectors; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; + +import com.feed_the_beast.ftbutilities.FTBUtilitiesPermissions; +import com.feed_the_beast.ftbutilities.data.ClaimedChunks; +import com.nomiceu.nomilabs.NomiLabs; + +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; + +public class CanEditChunkHelper { + + private static final Map cannotEditChunks = new Object2ObjectOpenHashMap<>(); + + public static void clear() { + cannotEditChunks.clear(); + } + + public static void addEntries(boolean[][] entries, int startX, int startZ) { + for (int x = 0; x < entries.length; x++) { + for (int z = 0; z < entries[x].length; z++) { + cannotEditChunks.put(new ChunkPos(startX + x, startZ + z), entries[x][z]); + } + } + NomiLabs.LOGGER.debug("[FTB Utils Integration] Chunk Editing Permissions: {}", + cannotEditChunks.entrySet().stream() + .sorted(Comparator + .comparingInt((Map.Entry entry) -> entry.getKey().x) + .thenComparingInt(entry -> entry.getKey().z)) + .map((entry) -> "chunk: x: " + entry.getKey().x + ", z: " + + entry.getKey().z + " | " + entry.getValue()) + .collect(Collectors.toList())); + } + + public static boolean cannotEditChunk(EntityPlayer player, BlockPos pos, IBlockState state) { + if (player.world == null) return false; + + var chunkPos = new ChunkPos(pos); + if ((player instanceof EntityPlayerMP && ClaimedChunks.isActive()) || cannotEditChunks.isEmpty() || + !cannotEditChunks.containsKey(chunkPos)) + return ClaimedChunks.blockBlockEditing(player, pos, state); + + if (state == null) { + state = player.world.getBlockState(pos); + } + + return !FTBUtilitiesPermissions.hasBlockEditingPermission(player, state.getBlock()) && + cannotEditChunks.get(chunkPos); + } +} diff --git a/src/main/java/com/nomiceu/nomilabs/integration/ftbutilities/event/FTBUtilsEventHandler.java b/src/main/java/com/nomiceu/nomilabs/integration/ftbutilities/event/FTBUtilsEventHandler.java new file mode 100644 index 00000000..9d76700c --- /dev/null +++ b/src/main/java/com/nomiceu/nomilabs/integration/ftbutilities/event/FTBUtilsEventHandler.java @@ -0,0 +1,48 @@ +package com.nomiceu.nomilabs.integration.ftbutilities.event; + +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraftforge.event.entity.EntityEvent; +import net.minecraftforge.fml.common.eventhandler.EventPriority; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.PlayerEvent; + +import com.feed_the_beast.ftbutilities.events.chunks.ChunkModifiedEvent; +import com.nomiceu.nomilabs.integration.ftbutilities.CanEditChunkDataMessageHelper; + +@SuppressWarnings("unused") +public class FTBUtilsEventHandler { + + @SubscribeEvent(priority = EventPriority.LOWEST) + public static void onPlayerJoined(PlayerEvent.PlayerLoggedInEvent event) { + if (event.player.world.isRemote || !(event.player instanceof EntityPlayerMP mp)) return; + CanEditChunkDataMessageHelper.sendMessage(mp); + } + + @SubscribeEvent + public static void onPlayerClone(net.minecraftforge.event.entity.player.PlayerEvent.Clone event) { + if (event.getEntityPlayer().world.isRemote || !(event.getEntityPlayer() instanceof EntityPlayerMP mp)) return; + CanEditChunkDataMessageHelper.sendMessage(mp); + } + + @SubscribeEvent + public static void onPlayerChangedDimension(PlayerEvent.PlayerChangedDimensionEvent event) { + if (event.player.world.isRemote || !(event.player instanceof EntityPlayerMP mp)) return; + CanEditChunkDataMessageHelper.sendMessage(mp); + } + + @SubscribeEvent + public static void onChunkChanged(EntityEvent.EnteringChunk event) { + if (event.getEntity().world.isRemote || !(event.getEntity() instanceof EntityPlayerMP mp)) return; + CanEditChunkDataMessageHelper.sendMessage(mp); + } + + @SubscribeEvent + public static void onChunkTeamClaimed(ChunkModifiedEvent.Claimed event) { + CanEditChunkDataMessageHelper.sendMessageToAll(); + } + + @SubscribeEvent + public static void onChunkTeamUnclaimed(ChunkModifiedEvent.Unclaimed event) { + CanEditChunkDataMessageHelper.sendMessageToAll(); + } +} diff --git a/src/main/java/com/nomiceu/nomilabs/integration/ftbutilities/network/CanEditChunkDataMessage.java b/src/main/java/com/nomiceu/nomilabs/integration/ftbutilities/network/CanEditChunkDataMessage.java new file mode 100644 index 00000000..d00f9746 --- /dev/null +++ b/src/main/java/com/nomiceu/nomilabs/integration/ftbutilities/network/CanEditChunkDataMessage.java @@ -0,0 +1,105 @@ +package com.nomiceu.nomilabs.integration.ftbutilities.network; + +import java.util.Arrays; + +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; + +import com.nomiceu.nomilabs.NomiLabs; +import com.nomiceu.nomilabs.integration.ftbutilities.CanEditChunkHelper; + +import io.netty.buffer.ByteBuf; + +public class CanEditChunkDataMessage implements IMessage { + + private int startX; + private int startZ; + private int storage; + + // Should be a square number. Should be less than or equal to 31. + public static final int STORAGE_LENGTH = 25; + // Should be the sqrt of the above. Should not be divisible by 2. + public static final int STORAGE_WIDTH = 5; + + public CanEditChunkDataMessage() { + startX = 0; + startZ = 0; + storage = 0; + } + + /** + * Create a new Can Edit Chunk Data Message. + * + * @param startX X Loc of the Chunk (Not Block Pos) + * @param startZ Z Loc of the Chunk (Not Block Pos) + * @param chunkInfo Boolean list of chunk info (0, top left, 1, right of that, etc.) true = no edit allowed, false = + * edit allowed + */ + public CanEditChunkDataMessage(int startX, int startZ, boolean[] chunkInfo) { + if (chunkInfo.length != STORAGE_LENGTH) throw new RuntimeException( + "[FTB Utils Integration] Chunk Info cannot have length that is not " + STORAGE_LENGTH + "!"); + this.startX = startX; + this.startZ = startZ; + this.storage = 0; + + // Encode Boolean List into one integer. + // Using Bit Manipulation. Each storage is a bit. + for (int i = 0; i < chunkInfo.length; i++) { + if (chunkInfo[i]) storage += (int) Math.pow(2, i); + } + + NomiLabs.LOGGER.debug( + "[FTB Utils Integration] Made CanEditChunkDataMessage with Storage {} with start x {} and start z {}", + storage, startX, startZ); + } + + public boolean[][] getChunkInfo() { + // Decode Storage (More Bit Manipulation) + boolean[][] chunkInfo = new boolean[STORAGE_WIDTH][STORAGE_WIDTH]; + for (int x = 0; x < STORAGE_WIDTH; x++) { + for (int z = 0; z < STORAGE_WIDTH; z++) { + chunkInfo[x][z] = (storage & (int) Math.pow(2, x * STORAGE_WIDTH + z)) != 0; + } + } + NomiLabs.LOGGER.debug("[FTB Utils Integration] Decoded Storage: {}", Arrays.deepToString(chunkInfo)); + return chunkInfo; + } + + public int getStartX() { + return startX; + } + + public int getStartZ() { + return startZ; + } + + @Override + public void fromBytes(ByteBuf buf) { + storage = buf.readInt(); + startX = buf.readInt(); + startZ = buf.readInt(); + } + + @Override + public void toBytes(ByteBuf buf) { + buf.writeInt(storage); + buf.writeInt(startX); + buf.writeInt(startZ); + } + + public static class MessageHandler implements IMessageHandler { + + @Override + public IMessage onMessage(CanEditChunkDataMessage message, MessageContext ctx) { + if (!ctx.side.isClient()) return null; + + NomiLabs.LOGGER.debug( + "[FTB Utils Integration] Received CanEditChunkDataMessage with Storage {} with start x {} and start z {}", + message.storage, message.startX, message.startZ); + CanEditChunkHelper.clear(); + CanEditChunkHelper.addEntries(message.getChunkInfo(), message.getStartX(), message.getStartZ()); + return null; + } + } +} diff --git a/src/main/java/com/nomiceu/nomilabs/integration/ftbutilities/network/DisplayGameOverlayMessageHelper.java b/src/main/java/com/nomiceu/nomilabs/integration/ftbutilities/network/DisplayGameOverlayMessageHelper.java new file mode 100644 index 00000000..05894799 --- /dev/null +++ b/src/main/java/com/nomiceu/nomilabs/integration/ftbutilities/network/DisplayGameOverlayMessageHelper.java @@ -0,0 +1,20 @@ +package com.nomiceu.nomilabs.integration.ftbutilities.network; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.util.text.ChatType; +import net.minecraft.util.text.TextComponentTranslation; + +import com.nomiceu.nomilabs.mixinhelper.AccessibleEntityPlayerSP; + +public class DisplayGameOverlayMessageHelper { + + public static void sendMessageOrDisplay(EntityPlayer player, String key) { + if (player instanceof EntityPlayerMP) { + player.sendStatusMessage(new TextComponentTranslation(key), true); + } else if (player instanceof AccessibleEntityPlayerSP) { + ((AccessibleEntityPlayerSP) player).getGuiIngame().addChatMessage(ChatType.GAME_INFO, + new TextComponentTranslation(key)); + } + } +} diff --git a/src/main/java/com/nomiceu/nomilabs/mixin/EntityPlayerSPMixin.java b/src/main/java/com/nomiceu/nomilabs/mixin/EntityPlayerSPMixin.java new file mode 100644 index 00000000..e4e9acd4 --- /dev/null +++ b/src/main/java/com/nomiceu/nomilabs/mixin/EntityPlayerSPMixin.java @@ -0,0 +1,22 @@ +package com.nomiceu.nomilabs.mixin; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.EntityPlayerSP; +import net.minecraft.client.gui.GuiIngame; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import com.nomiceu.nomilabs.mixinhelper.AccessibleEntityPlayerSP; + +@Mixin(EntityPlayerSP.class) +public class EntityPlayerSPMixin implements AccessibleEntityPlayerSP { + + @Shadow + protected Minecraft mc; + + @Override + public GuiIngame getGuiIngame() { + return mc.ingameGUI; + } +} diff --git a/src/main/java/com/nomiceu/nomilabs/mixin/effortlessbuilding/BuildModifiersMixin.java b/src/main/java/com/nomiceu/nomilabs/mixin/effortlessbuilding/BuildModifiersMixin.java new file mode 100644 index 00000000..33bd83e2 --- /dev/null +++ b/src/main/java/com/nomiceu/nomilabs/mixin/effortlessbuilding/BuildModifiersMixin.java @@ -0,0 +1,30 @@ +package com.nomiceu.nomilabs.mixin.effortlessbuilding; + +import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import com.llamalad7.mixinextras.sugar.Local; +import com.nomiceu.nomilabs.integration.effortlessbuilding.ImprovedInventoryHelper; + +import nl.requios.effortlessbuilding.buildmodifier.BuildModifiers; + +/** + * Fixes Transmutation when Building, as Effortless isn't checking Meta. + */ +@Mixin(value = BuildModifiers.class, remap = false) +public class BuildModifiersMixin { + + @Redirect(method = "onBlockPlaced", + at = @At(value = "INVOKE", + target = "Lnl/requios/effortlessbuilding/helper/InventoryHelper;findItemStackInInventory(Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/block/Block;)Lnet/minecraft/item/ItemStack;"), + require = 1) + private static ItemStack getProperStacksInInv(EntityPlayer player, Block block, @Local IBlockState blockState) { + return ImprovedInventoryHelper.findItemStackInInventory(player, blockState); + } +} diff --git a/src/main/java/com/nomiceu/nomilabs/mixin/effortlessbuilding/EventHandlerMixin.java b/src/main/java/com/nomiceu/nomilabs/mixin/effortlessbuilding/EventHandlerMixin.java new file mode 100644 index 00000000..a606aa80 --- /dev/null +++ b/src/main/java/com/nomiceu/nomilabs/mixin/effortlessbuilding/EventHandlerMixin.java @@ -0,0 +1,25 @@ +package com.nomiceu.nomilabs.mixin.effortlessbuilding; + +import net.minecraftforge.event.world.BlockEvent; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import com.nomiceu.nomilabs.integration.effortlessbuilding.EffortlessEventHandler; + +import nl.requios.effortlessbuilding.EventHandler; + +/** + * Cancel Original Handling of Block Placed Event, Now Done in {@link EffortlessEventHandler#onPlayerInteract} + */ +@Mixin(value = EventHandler.class, remap = false) +public class EventHandlerMixin { + + @Inject(method = "onBlockPlaced", at = @At("HEAD"), cancellable = true) + @SuppressWarnings("deprecation") + private static void cancelOriginalHandling(BlockEvent.PlaceEvent event, CallbackInfo ci) { + ci.cancel(); + } +} diff --git a/src/main/java/com/nomiceu/nomilabs/mixin/effortlessbuilding/ReachHelperMixin.java b/src/main/java/com/nomiceu/nomilabs/mixin/effortlessbuilding/ReachHelperMixin.java index 0020dd47..e95e6810 100644 --- a/src/main/java/com/nomiceu/nomilabs/mixin/effortlessbuilding/ReachHelperMixin.java +++ b/src/main/java/com/nomiceu/nomilabs/mixin/effortlessbuilding/ReachHelperMixin.java @@ -21,20 +21,20 @@ public class ReachHelperMixin { @Inject(method = "getMaxBlocksPerAxis", at = @At("HEAD"), cancellable = true) private static void getNewMaxBlocksPerAxis(EntityPlayer player, CallbackInfoReturnable cir) { if (player.isCreative()) { - cir.setReturnValue(GenericReachUpgrade.REACH_MAP.get(GenericReachUpgrade.CREATIVE_LEVEL).axis); + cir.setReturnValue(GenericReachUpgrade.REACH_MAP.get(GenericReachUpgrade.CREATIVE_LEVEL).getAxis()); return; } int level = ModifierSettingsManager.getModifierSettings(player).getReachUpgrade(); - cir.setReturnValue(GenericReachUpgrade.REACH_MAP.get(level).axis); + cir.setReturnValue(GenericReachUpgrade.REACH_MAP.get(level).getAxis()); } @Inject(method = "getMaxBlocksPlacedAtOnce", at = @At("HEAD"), cancellable = true) private static void getNewMaxBlocksPlacedAtOnce(EntityPlayer player, CallbackInfoReturnable cir) { if (player.isCreative()) { - cir.setReturnValue(GenericReachUpgrade.REACH_MAP.get(GenericReachUpgrade.CREATIVE_LEVEL).maxBlocks); + cir.setReturnValue(GenericReachUpgrade.REACH_MAP.get(GenericReachUpgrade.CREATIVE_LEVEL).getMaxBlocks()); return; } int level = ModifierSettingsManager.getModifierSettings(player).getReachUpgrade(); - cir.setReturnValue(GenericReachUpgrade.REACH_MAP.get(level).maxBlocks); + cir.setReturnValue(GenericReachUpgrade.REACH_MAP.get(level).getMaxBlocks()); } } diff --git a/src/main/java/com/nomiceu/nomilabs/mixin/effortlessbuilding/RenderHandlerMixin.java b/src/main/java/com/nomiceu/nomilabs/mixin/effortlessbuilding/RenderHandlerMixin.java new file mode 100644 index 00000000..ae196431 --- /dev/null +++ b/src/main/java/com/nomiceu/nomilabs/mixin/effortlessbuilding/RenderHandlerMixin.java @@ -0,0 +1,40 @@ +package com.nomiceu.nomilabs.mixin.effortlessbuilding; + +import net.minecraft.client.Minecraft; +import net.minecraftforge.client.event.RenderGameOverlayEvent; +import net.minecraftforge.client.event.RenderWorldLastEvent; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import nl.requios.effortlessbuilding.gui.buildmode.RadialMenu; +import nl.requios.effortlessbuilding.gui.buildmodifier.ModifierSettingsGui; +import nl.requios.effortlessbuilding.render.RenderHandler; + +/** + * Fixes Shader being applied on Pause Screens, Inventory, and on the Main Menu. + */ +@Mixin(value = RenderHandler.class, remap = false) +public class RenderHandlerMixin { + + @Unique + private static boolean wasVisible = false; + + @Inject(method = "onRenderGameOverlay", at = @At("HEAD")) + private static void saveWasVisible(RenderGameOverlayEvent.Post event, CallbackInfo ci) { + wasVisible = RadialMenu.instance.isVisible(); + } + + @Inject(method = "onRender", at = @At("HEAD"), cancellable = true) + private static void cancelRenderIfNeeded(RenderWorldLastEvent event, CallbackInfo ci) { + // Cancels when game is not in focus. Does not cancel at the beginning of radial menu use (last condition), + // during, or at the end (second-last condition), or when modifier menu is open. + if ((!Minecraft.getMinecraft().inGameHasFocus) && + !(Minecraft.getMinecraft().currentScreen instanceof ModifierSettingsGui) && !wasVisible && + !RadialMenu.instance.isVisible()) + ci.cancel(); + } +} diff --git a/src/main/java/com/nomiceu/nomilabs/mixin/effortlessbuilding/SurvivalHelperMixin.java b/src/main/java/com/nomiceu/nomilabs/mixin/effortlessbuilding/SurvivalHelperMixin.java new file mode 100644 index 00000000..76b50148 --- /dev/null +++ b/src/main/java/com/nomiceu/nomilabs/mixin/effortlessbuilding/SurvivalHelperMixin.java @@ -0,0 +1,33 @@ +package com.nomiceu.nomilabs.mixin.effortlessbuilding; + +import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.fml.common.Loader; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import com.nomiceu.nomilabs.LabsValues; +import com.nomiceu.nomilabs.integration.ftbutilities.CanEditChunkHelper; + +import nl.requios.effortlessbuilding.helper.SurvivalHelper; + +@Mixin(value = SurvivalHelper.class, remap = false) +public class SurvivalHelperMixin { + + @Inject(method = "mayPlace", at = @At("HEAD"), cancellable = true) + private static void checkFTBUtilsCondition(World world, Block blockIn, IBlockState newBlockState, BlockPos pos, + boolean skipCollisionCheck, EnumFacing sidePlacedOn, Entity placer, + CallbackInfoReturnable cir) { + if (!Loader.isModLoaded(LabsValues.FTB_UTILS_MODID) || !(placer instanceof EntityPlayer player)) return; + + if (CanEditChunkHelper.cannotEditChunk(player, pos, newBlockState)) cir.setReturnValue(false); + } +} diff --git a/src/main/java/com/nomiceu/nomilabs/mixin/effortlessbuilding/UndoRedoMixin.java b/src/main/java/com/nomiceu/nomilabs/mixin/effortlessbuilding/UndoRedoMixin.java new file mode 100644 index 00000000..a0065d8f --- /dev/null +++ b/src/main/java/com/nomiceu/nomilabs/mixin/effortlessbuilding/UndoRedoMixin.java @@ -0,0 +1,48 @@ +package com.nomiceu.nomilabs.mixin.effortlessbuilding; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemBlock; +import net.minecraft.item.ItemStack; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import com.nomiceu.nomilabs.integration.effortlessbuilding.ImprovedInventoryHelper; + +import nl.requios.effortlessbuilding.buildmodifier.UndoRedo; + +/** + * Fixes a Transmutation Bug where Effortless would ignore Meta during Undo/Redo. + */ +@Mixin(value = UndoRedo.class, remap = false) +public class UndoRedoMixin { + + // Just Replace Whole Function, as it is short, and drops check uses wrong function + @Inject(method = "findItemStackInInventory", at = @At("HEAD"), cancellable = true) + private static void findProperItemStackInInventory(EntityPlayer player, IBlockState blockState, + CallbackInfoReturnable cir) { + if (blockState == null) { + cir.setReturnValue(ItemStack.EMPTY); + return; + } + var result = ImprovedInventoryHelper.findItemStackInInventory(player, blockState); + if (!result.isEmpty()) { + cir.setReturnValue(result); + return; + } + + /* Drops Check */ + Item itemDropped = blockState.getBlock().getItemDropped(blockState, player.world.rand, 10); + int metaDropped = blockState.getBlock().damageDropped(blockState); + if (itemDropped instanceof ItemBlock) { + result = ImprovedInventoryHelper.findItemStackInInventory(player, + new ItemStack(itemDropped, 1, metaDropped)); + } + // Will be empty if Previous found None + cir.setReturnValue(result); + } +} diff --git a/src/main/java/com/nomiceu/nomilabs/mixin/ftbutilities/FTBUtilitiesPlayerEventHandlerMixin.java b/src/main/java/com/nomiceu/nomilabs/mixin/ftbutilities/FTBUtilitiesPlayerEventHandlerMixin.java new file mode 100644 index 00000000..62232f98 --- /dev/null +++ b/src/main/java/com/nomiceu/nomilabs/mixin/ftbutilities/FTBUtilitiesPlayerEventHandlerMixin.java @@ -0,0 +1,161 @@ +package com.nomiceu.nomilabs.mixin.ftbutilities; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemBlock; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.ITextComponent; +import net.minecraftforge.event.entity.player.AttackEntityEvent; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import net.minecraftforge.event.world.BlockEvent; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import com.feed_the_beast.ftbutilities.handlers.FTBUtilitiesPlayerEventHandler; +import com.nomiceu.nomilabs.integration.ftbutilities.CanEditChunkHelper; +import com.nomiceu.nomilabs.integration.ftbutilities.network.DisplayGameOverlayMessageHelper; + +@Mixin(value = FTBUtilitiesPlayerEventHandler.class, remap = false) +public class FTBUtilitiesPlayerEventHandlerMixin { + + @Unique + private static boolean cancelledMainHandPlace = false; + + /* New Logic */ + + @Inject(method = "onRightClickBlock", at = @At("HEAD"), cancellable = true) + @SuppressWarnings("deprecation") + private static void handleAndCancelPlace(PlayerInteractEvent.RightClickBlock event, CallbackInfo ci) { + var stack = event.getEntityPlayer().getHeldItem(event.getHand()); + var item = stack.getItem(); + var pos = event.getPos(); + + if (event.getHand() == EnumHand.MAIN_HAND) + cancelledMainHandPlace = false; + // Off Hand is always called after main hand + else if (event.getHand() == EnumHand.OFF_HAND && cancelledMainHandPlace) { + cancelledMainHandPlace = false; + event.setCanceled(true); + ci.cancel(); + return; + } + + if (!(item instanceof ItemBlock itemBlock)) + return; + + // Offset Pos if Needed + if (event.getFace() != null && !itemBlock.getBlock().isReplaceable(event.getWorld(), pos)) + pos = pos.offset(event.getFace()); + + if (!CanEditChunkHelper.cannotEditChunk(event.getEntityPlayer(), + pos, itemBlock.getBlock().getStateFromMeta(stack.getMetadata()))) + return; + + event.setCanceled(true); + cancelledMainHandPlace = true; + + if (!event.getWorld().isRemote) + DisplayGameOverlayMessageHelper.sendMessageOrDisplay(event.getEntityPlayer(), + "ftbutilities.status.chunk.no_place_block"); + ci.cancel(); + } + + @Redirect(method = "onBlockLeftClick", + at = @At(value = "INVOKE", + target = "Lcom/feed_the_beast/ftbutilities/data/ClaimedChunks;blockBlockEditing(Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/state/IBlockState;)Z"), + require = 1) + private static boolean blockBlockEditingRedirect(EntityPlayer player, BlockPos pos, IBlockState state) { + return CanEditChunkHelper.cannotEditChunk(player, pos, state); + } + + /* Status Message Adders */ + + @Inject(method = "onEntityAttacked", at = @At("TAIL")) + private static void sendStatusEntity(AttackEntityEvent event, CallbackInfo ci) { + if (!event.isCanceled() || event.getEntityPlayer().world == null) + return; + + if (!event.getEntityPlayer().world.isRemote) { + if (event.getTarget() instanceof EntityPlayer) + DisplayGameOverlayMessageHelper.sendMessageOrDisplay(event.getEntityPlayer(), + "ftbutilities.status.server.pvp"); + else + DisplayGameOverlayMessageHelper.sendMessageOrDisplay(event.getEntityPlayer(), + "ftbutilities.status.chunk.no_attack"); + } + } + + @Inject(method = "onBlockLeftClick", at = @At("TAIL")) + private static void sendStatusBlockBreak(PlayerInteractEvent.LeftClickBlock event, CallbackInfo ci) { + if (!event.isCanceled() || event.getEntityPlayer().world == null) return; + + if (!event.getEntityPlayer().world.isRemote) + DisplayGameOverlayMessageHelper.sendMessageOrDisplay(event.getEntityPlayer(), + "ftbutilities.status.chunk.no_break_block"); + } + + @Inject(method = "onRightClickItem", + at = @At(value = "INVOKE", + target = "Lcom/feed_the_beast/ftblib/lib/util/InvUtils;forceUpdate(Lnet/minecraft/entity/player/EntityPlayer;)V", + shift = At.Shift.AFTER), + require = 1) + private static void sendStatusItemUse(PlayerInteractEvent.RightClickItem event, CallbackInfo ci) { + if (!event.getEntityPlayer().world.isRemote) + DisplayGameOverlayMessageHelper.sendMessageOrDisplay(event.getEntityPlayer(), + "ftbutilities.status.chunk.no_interact_item"); + } + + @Inject(method = "onRightClickBlock", + at = @At(value = "INVOKE", + target = "Lcom/feed_the_beast/ftblib/lib/util/InvUtils;forceUpdate(Lnet/minecraft/entity/player/EntityPlayer;)V", + shift = At.Shift.AFTER), + require = 1) + private static void sendStatusBlockInteraction(PlayerInteractEvent.RightClickBlock event, CallbackInfo ci) { + if (!event.getEntityPlayer().world.isRemote) + DisplayGameOverlayMessageHelper.sendMessageOrDisplay(event.getEntityPlayer(), + "ftbutilities.status.chunk.no_interact_block"); + } + + /* Status Message Changers */ + + @Redirect(method = "onRightClickItem", + at = @At(value = "INVOKE", + target = "Lnet/minecraft/entity/player/EntityPlayer;sendStatusMessage(Lnet/minecraft/util/text/ITextComponent;Z)V", + remap = true), + require = 1) + private static void sendTranslatableStatusMessageItem(EntityPlayer instance, ITextComponent chatComponent, + boolean actionBar) { + // World is Already Not Remote Here + DisplayGameOverlayMessageHelper.sendMessageOrDisplay(instance, "ftbutilities.status.server.item_disabled"); + } + + @Redirect(method = "onRightClickBlock", + at = @At(value = "INVOKE", + target = "Lnet/minecraft/entity/player/EntityPlayer;sendStatusMessage(Lnet/minecraft/util/text/ITextComponent;Z)V", + remap = true), + require = 1) + private static void sendTranslatableStatusMessageBlock(EntityPlayer instance, ITextComponent chatComponent, + boolean actionBar) { + // World is Already Not Remote Here + DisplayGameOverlayMessageHelper.sendMessageOrDisplay(instance, "ftbutilities.status.server.item_disabled"); + } + + /* Removals */ + + @Inject(method = "onBlockBreak", at = @At("HEAD"), cancellable = true) + private static void cancelOriginalBreakHandler(BlockEvent.BreakEvent event, CallbackInfo ci) { + ci.cancel(); + } + + @Inject(method = "onBlockPlace", at = @At("HEAD"), cancellable = true) + @SuppressWarnings("deprecation") + private static void cancelOriginalPlaceHandler(BlockEvent.PlaceEvent event, CallbackInfo ci) { + ci.cancel(); + } +} diff --git a/src/main/java/com/nomiceu/nomilabs/mixinhelper/AccessibleEntityPlayerSP.java b/src/main/java/com/nomiceu/nomilabs/mixinhelper/AccessibleEntityPlayerSP.java new file mode 100644 index 00000000..7767964f --- /dev/null +++ b/src/main/java/com/nomiceu/nomilabs/mixinhelper/AccessibleEntityPlayerSP.java @@ -0,0 +1,8 @@ +package com.nomiceu.nomilabs.mixinhelper; + +import net.minecraft.client.gui.GuiIngame; + +public interface AccessibleEntityPlayerSP { + + GuiIngame getGuiIngame(); +} diff --git a/src/main/java/com/nomiceu/nomilabs/network/LabsNetworkHandler.java b/src/main/java/com/nomiceu/nomilabs/network/LabsNetworkHandler.java new file mode 100644 index 00000000..c4ab7721 --- /dev/null +++ b/src/main/java/com/nomiceu/nomilabs/network/LabsNetworkHandler.java @@ -0,0 +1,32 @@ +package com.nomiceu.nomilabs.network; + +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; +import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper; +import net.minecraftforge.fml.relauncher.Side; + +import com.nomiceu.nomilabs.LabsValues; +import com.nomiceu.nomilabs.integration.ftbutilities.network.CanEditChunkDataMessage; + +public class LabsNetworkHandler { + + public static SimpleNetworkWrapper NETWORK_HANDLER; + private static int CURRENT_ID; + + public static void onConstruction() { + NETWORK_HANDLER = new SimpleNetworkWrapper(LabsValues.LABS_MODID); + } + + public static void preInit() { + CURRENT_ID = 0; + registerMessage(CanEditChunkDataMessage.MessageHandler.class, CanEditChunkDataMessage.class); + } + + @SuppressWarnings("SameParameterValue") + private static void registerMessage(Class> messageHandler, + Class requestMessageType) { + NETWORK_HANDLER.registerMessage(messageHandler, requestMessageType, CURRENT_ID++, Side.CLIENT); + NETWORK_HANDLER.registerMessage(messageHandler, requestMessageType, CURRENT_ID++, Side.SERVER); + } +} diff --git a/src/main/resources/assets/ftbutilities/lang/en_us.lang b/src/main/resources/assets/ftbutilities/lang/en_us.lang new file mode 100644 index 00000000..5e01a08e --- /dev/null +++ b/src/main/resources/assets/ftbutilities/lang/en_us.lang @@ -0,0 +1,7 @@ +ftbutilities.status.server.item_disabled=§cItem Disabled!§r +ftbutilities.status.server.pvp=§cYou cannot PvP Here!§r +ftbutilities.status.chunk.no_attack=§cYou cannot attack Friendly Entities in this Chunk!§r +ftbutilities.status.chunk.no_break_block=§cYou cannot break Blocks in this Chunk!§r +ftbutilities.status.chunk.no_place_block=§cYou cannot place Blocks in this Chunk!§r +ftbutilities.status.chunk.no_interact_item=§cYou cannot use that Item in this Chunk!§r +ftbutilities.status.chunk.no_interact_block=§cYou cannot interact with Blocks in this Chunk!§r \ No newline at end of file diff --git a/src/main/resources/assets/nomilabs/lang/en_us.lang b/src/main/resources/assets/nomilabs/lang/en_us.lang index 5017a547..7da9acfe 100644 --- a/src/main/resources/assets/nomilabs/lang/en_us.lang +++ b/src/main/resources/assets/nomilabs/lang/en_us.lang @@ -39,18 +39,19 @@ config.nomilabs.mod_integration.architecture_craft=Enable ArchitectureCraft Inte config.nomilabs.mod_integration.default_world_gen=Enable Default World Generator Port Integration config.nomilabs.mod_integration.ender_storage=Enable Ender Storage Integration config.nomilabs.mod_integration.ender_io=Enable Ender IO Integration +config.nomilabs.mod_integration.ftb_utils=Enable FTB Utilities Integration config.nomilabs.mod_integration.effortlessbuilding=Effortless Building Integration Settings config.nomilabs.mod_integration.effortlessbuilding.enable=Enable Effortless Building Integration config.nomilabs.mod_integration.effortlessbuilding.axis.0=Max Reach Per Axis (No Upgrades) config.nomilabs.mod_integration.effortlessbuilding.axis.1=Max Reach Per Axis (1 Upgrade) -config.nomilabs.mod_integration.effortlessbuilding.axis.2=Max Reach Per Axis (2 Upgrade) -config.nomilabs.mod_integration.effortlessbuilding.axis.3=Max Reach Per Axis (3 Upgrade) +config.nomilabs.mod_integration.effortlessbuilding.axis.2=Max Reach Per Axis (2 Upgrades) +config.nomilabs.mod_integration.effortlessbuilding.axis.3=Max Reach Per Axis (3 Upgrades) config.nomilabs.mod_integration.effortlessbuilding.axis.creative=Max Reach Per Axis (Creative) config.nomilabs.mod_integration.effortlessbuilding.blocks.0=Max Blocks Placed (No Upgrades) config.nomilabs.mod_integration.effortlessbuilding.blocks.1=Max Blocks Placed (1 Upgrade) -config.nomilabs.mod_integration.effortlessbuilding.blocks.2=Max Blocks Placed (2 Upgrade) -config.nomilabs.mod_integration.effortlessbuilding.blocks.3=Max Blocks Placed (3 Upgrade) +config.nomilabs.mod_integration.effortlessbuilding.blocks.2=Max Blocks Placed (2 Upgrades) +config.nomilabs.mod_integration.effortlessbuilding.blocks.3=Max Blocks Placed (3 Upgrades) config.nomilabs.mod_integration.effortlessbuilding.blocks.creative=Max Blocks Placed (Creative) config.nomilabs.groovy=GroovyScript Extensions and Script Helper Settings diff --git a/src/main/resources/mixins.nomilabs.effortlessbuilding.json b/src/main/resources/mixins.nomilabs.effortlessbuilding.json index 87e47bf8..43943ee0 100644 --- a/src/main/resources/mixins.nomilabs.effortlessbuilding.json +++ b/src/main/resources/mixins.nomilabs.effortlessbuilding.json @@ -5,10 +5,15 @@ "minVersion": "0.8", "compatibilityLevel": "JAVA_8", "mixins": [ + "BuildModifiersMixin", + "EventHandlerMixin", "ItemReachUpgrade1Mixin", "ItemReachUpgrade2Mixin", "ItemReachUpgrade3Mixin", - "ReachHelperMixin" + "ReachHelperMixin", + "RenderHandlerMixin", + "SurvivalHelperMixin", + "UndoRedoMixin" ], "client": [], "server": [] diff --git a/src/main/resources/mixins.nomilabs.ftbutilities.json b/src/main/resources/mixins.nomilabs.ftbutilities.json new file mode 100644 index 00000000..b66aa693 --- /dev/null +++ b/src/main/resources/mixins.nomilabs.ftbutilities.json @@ -0,0 +1,12 @@ +{ + "package": "com.nomiceu.nomilabs.mixin.ftbutilities", + "refmap": "mixins.nomilabs.refmap.json", + "target": "@env(DEFAULT)", + "minVersion": "0.8", + "compatibilityLevel": "JAVA_8", + "mixins": [ + "FTBUtilitiesPlayerEventHandlerMixin" + ], + "client": [], + "server": [] +} diff --git a/src/main/resources/mixins.nomilabs.json b/src/main/resources/mixins.nomilabs.json index cb9801e1..25d8a1fd 100644 --- a/src/main/resources/mixins.nomilabs.json +++ b/src/main/resources/mixins.nomilabs.json @@ -12,6 +12,7 @@ "WorldLoadHandler" ], "client": [ + "EntityPlayerSPMixin", "GuiKeyBindingListAccessor", "GuiKeyBindingListKeyEntryMixin", "KeyBindingAccessor",