diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/async_locator/SetNameFunctionMixin.java b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/async_locator/SetNameFunctionMixin.java new file mode 100644 index 00000000..9f215c86 --- /dev/null +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/async_locator/SetNameFunctionMixin.java @@ -0,0 +1,26 @@ +package org.embeddedt.modernfix.forge.mixin.perf.async_locator; + +import net.minecraft.network.chat.Component; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.storage.loot.functions.SetNameFunction; +import org.embeddedt.modernfix.forge.structure.logic.CommonLogic; +import org.embeddedt.modernfix.forge.structure.logic.ExplorationMapFunctionLogic; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(SetNameFunction.class) +public class SetNameFunctionMixin { + @Redirect( + method = "run", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/item/ItemStack;setHoverName(Lnet/minecraft/network/chat/Component;)Lnet/minecraft/world/item/ItemStack;" + ) + ) + public ItemStack deferSetName(ItemStack stack, Component name) { + if (CommonLogic.isEmptyPendingMap(stack)) + ExplorationMapFunctionLogic.cacheName(stack, name); + return stack; + } +} diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/async_locator/SlotMixin.java b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/async_locator/SlotMixin.java new file mode 100644 index 00000000..4e6f8b66 --- /dev/null +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/async_locator/SlotMixin.java @@ -0,0 +1,28 @@ +package org.embeddedt.modernfix.forge.mixin.perf.async_locator; + +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.Slot; +import net.minecraft.world.item.ItemStack; +import org.embeddedt.modernfix.forge.structure.logic.CommonLogic; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(Slot.class) +public abstract class SlotMixin { + @Shadow + public abstract ItemStack getItem(); + + @Inject( + method = "mayPickup", + at = @At(value = "HEAD"), + cancellable = true + ) + public void preventPickupOfPendingExplorationMap(Player player, CallbackInfoReturnable cir) { + if (CommonLogic.isEmptyPendingMap(getItem())) { + cir.setReturnValue(false); + } + } +} diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/structure/logic/CommonLogic.java b/forge/src/main/java/org/embeddedt/modernfix/forge/structure/logic/CommonLogic.java index 84a2460f..96915589 100644 --- a/forge/src/main/java/org/embeddedt/modernfix/forge/structure/logic/CommonLogic.java +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/structure/logic/CommonLogic.java @@ -1,6 +1,8 @@ package org.embeddedt.modernfix.forge.structure.logic; import net.minecraft.core.BlockPos; +import net.minecraft.nbt.ByteTag; +import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.inventory.AbstractContainerMenu; @@ -15,6 +17,9 @@ import net.minecraft.world.level.saveddata.maps.MapItemSavedData; import org.embeddedt.modernfix.forge.mixin.perf.async_locator.MapItemAccess; public class CommonLogic { + private static final String MAP_HOVER_NAME_KEY = "menu.working"; + private static final String KEY_LOCATING = "asynclocator.locating"; + private CommonLogic() {} /** @@ -24,10 +29,23 @@ public class CommonLogic { */ public static ItemStack createEmptyMap() { ItemStack stack = new ItemStack(Items.FILLED_MAP); - stack.setHoverName(new TranslatableComponent("asynclocator.map.locating")); + stack.setHoverName(new TranslatableComponent(MAP_HOVER_NAME_KEY)); + stack.addTagElement(KEY_LOCATING, ByteTag.ONE); return stack; } + /** + * Returns true if the stack is an empty FILLED_MAP item with the hover tooltip name stating that it's locating a + * feature. + * + * @param stack The stack to check. + * @return True if the stack is an empty FILLED_MAP awaiting to be populated with location data. + */ + @SuppressWarnings("DataFlowIssue") + public static boolean isEmptyPendingMap(ItemStack stack) { + return stack.getItem() == Items.FILLED_MAP && stack.hasTag() && stack.getTag().contains(KEY_LOCATING); + } + /** * Updates the map stack with all the given data. * @@ -44,7 +62,7 @@ public class CommonLogic { int scale, MapDecoration.Type destinationType ) { - updateMap(mapStack, level, pos, scale, destinationType, null); + updateMap(mapStack, level, pos, scale, destinationType, (Component)null); } /** @@ -64,6 +82,27 @@ public class CommonLogic { int scale, MapDecoration.Type destinationType, String displayName + ) { + updateMap(mapStack, level, pos, scale, destinationType, new TranslatableComponent(displayName)); + } + + /** + * Updates the map stack with all the given data. + * + * @param mapStack The map ItemStack to update + * @param level The ServerLevel + * @param pos The feature position + * @param scale The map scale + * @param destinationType The map feature type + * @param displayName The hover tooltip display name of the ItemStack + */ + public static void updateMap( + ItemStack mapStack, + ServerLevel level, + BlockPos pos, + int scale, + MapDecoration.Type destinationType, + Component displayName ) { MapItemAccess.callCreateAndStoreSavedData( mapStack, level, pos.getX(), pos.getZ(), scale, true, true, level.dimension() @@ -71,7 +110,8 @@ public class CommonLogic { MapItem.renderBiomePreviewMap(level, mapStack); MapItemSavedData.addTargetDecoration(mapStack, pos, "+", destinationType); if (displayName != null) - mapStack.setHoverName(new TranslatableComponent(displayName)); + mapStack.setHoverName(displayName); + mapStack.removeTagKey(KEY_LOCATING); } /** diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/structure/logic/ExplorationMapFunctionLogic.java b/forge/src/main/java/org/embeddedt/modernfix/forge/structure/logic/ExplorationMapFunctionLogic.java index 136c8b54..50fe7198 100644 --- a/forge/src/main/java/org/embeddedt/modernfix/forge/structure/logic/ExplorationMapFunctionLogic.java +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/structure/logic/ExplorationMapFunctionLogic.java @@ -1,7 +1,11 @@ package org.embeddedt.modernfix.forge.structure.logic; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; import com.google.common.collect.ImmutableSet; import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; @@ -15,13 +19,29 @@ import net.minecraftforge.items.IItemHandlerModifiable; import org.embeddedt.modernfix.ModernFix; import org.embeddedt.modernfix.forge.structure.AsyncLocator; +import java.util.Locale; +import java.util.concurrent.TimeUnit; import java.util.function.BiConsumer; // TODO: Need to test this public class ExplorationMapFunctionLogic { + // I'd like to think that structure locating shouldn't take *this* long + private static final Cache MAP_NAME_CACHE = + CacheBuilder.newBuilder().expireAfterWrite(5, TimeUnit.MINUTES).build(); + private static final int MAX_STACK_SIZE = 64; private ExplorationMapFunctionLogic() {} + public static void cacheName(ItemStack stack, Component name) { + MAP_NAME_CACHE.put(stack, name); + } + + public static Component getCachedName(ItemStack stack) { + Component name = MAP_NAME_CACHE.getIfPresent(stack); + MAP_NAME_CACHE.invalidate(stack); + return name; + } + public static void invalidateMap(ItemStack mapStack, ServerLevel level, BlockPos pos) { handleUpdateMapInChest(mapStack, level, pos, (handler, slot) -> { if (handler instanceof IItemHandlerModifiable) { @@ -39,9 +59,10 @@ public class ExplorationMapFunctionLogic { BlockPos pos, int scale, MapDecoration.Type destinationType, - BlockPos invPos + BlockPos invPos, + Component displayName ) { - CommonLogic.updateMap(mapStack, level, pos, scale, destinationType); + CommonLogic.updateMap(mapStack, level, pos, scale, destinationType, displayName); // Shouldn't need to set the stack in its slot again, as we're modifying the same instance handleUpdateMapInChest(mapStack, level, invPos, (handler, slot) -> {}); } @@ -84,12 +105,17 @@ public class ExplorationMapFunctionLogic { BlockPos pos, int scale, MapDecoration.Type destinationType, + StructureFeature destination, BlockPos invPos ) { if (pos == null) { invalidateMap(mapStack, level, invPos); } else { - updateMap(mapStack, level, pos, scale, destinationType, invPos); + Component displayName = getCachedName(mapStack); + if(displayName == null) { + displayName = new TranslatableComponent("filled_map." + destination.getFeatureName().toLowerCase(Locale.ROOT)); + } + updateMap(mapStack, level, pos, scale, destinationType, invPos, displayName); } } @@ -104,7 +130,7 @@ public class ExplorationMapFunctionLogic { ) { ItemStack mapStack = CommonLogic.createEmptyMap(); AsyncLocator.locateLevel(level, ImmutableSet.of(destination), blockPos, searchRadius, skipKnownStructures) - .thenOnServerThread(pos -> handleLocationFound(mapStack, level, pos, scale, destinationType, blockPos)); + .thenOnServerThread(pos -> handleLocationFound(mapStack, level, pos, scale, destinationType, destination, blockPos)); return mapStack; } }