diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7f875fc0..47025343 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,8 +1,11 @@ name: Java CI - Build Release on: - release: - types: [ published ] + push: + tags: + - 'v[0-9]+\.[0-9]+\.[0-9]+' + - 'v[0-9]+\.[0-9]+\.[0-9]+-[a-z]+' + - 'v[0-9]+\.[0-9]+\.[0-9]+-[a-z]+\.[0-9]+' jobs: build: diff --git a/CHANGELOG.md b/CHANGELOG.md index 92d9ecd5..7bea6d32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,29 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2001.3.2] + +### Added +* The waypoint manager screen has had a facelift + * No longer a full-screen GUI + * Added a delete button alongside the visibility toggle button on the manager screen +* Added waypoint sharing; there is now a "Share" option on the context menus for waypoints on the large map, and in the waypoint manager screen +* Player icon on the large map screen is now combined with a pointer indicating the player's facing direction +* Added new entity tag: `ftbchunks:entity_mob_griefing_blacklist` + * Prevents mob griefing by any entities in this tag if mob griefing protection is enabled in team settings + * Note: only works on Forge at this time (Fabric remains limited to Endermen only) +* Info text lines under the minimap are now highly configurable + * Configure with the "Minimap Info" book icon on the left of the large map screen + * Entries can be enabled/disabled/reordered/configured + * Added new real time, game time and FPS lines in addition to existing zone/biome/player-pos/debug lines + +### Fixed +* Fixed the `/ftbchunks waypoint add` command only working for loaded chunks +* Fixed block/item/entity tags not being detected +* If the minimap is being displayed in top-right of screen (the default), then any potion effect icons are moved to the left of the minimap to avoid overlap +* Possible fix for occasional problem where some regions just don't render on the map or minimap + * Can't be sure, the problem is very hard to reproduce + ## [2001.3.1] ### Fixed diff --git a/build.gradle b/build.gradle index 905a342a..1847f182 100644 --- a/build.gradle +++ b/build.gradle @@ -3,6 +3,8 @@ plugins { id "dev.architectury.loom" version "1.4-SNAPSHOT" apply false } +apply from: 'https://raw.githubusercontent.com/FTBTeam/mods-meta/main/gradle/changelog.gradle' + architectury { minecraft = rootProject.minecraft_version } @@ -24,7 +26,6 @@ allprojects { apply plugin: "java" apply plugin: "architectury-plugin" apply plugin: "maven-publish" - apply from: "https://raw.githubusercontent.com/FTBTeam/mods-meta/main/gradle/git-md-changelog.gradle" version = project.mod_version group = project.maven_group diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/FTBChunksCommands.java b/common/src/main/java/dev/ftb/mods/ftbchunks/FTBChunksCommands.java index fa69fe9d..882b1038 100644 --- a/common/src/main/java/dev/ftb/mods/ftbchunks/FTBChunksCommands.java +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/FTBChunksCommands.java @@ -1,6 +1,7 @@ package dev.ftb.mods.ftbchunks; import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.BoolArgumentType; import com.mojang.brigadier.arguments.IntegerArgumentType; import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.builder.RequiredArgumentBuilder; @@ -37,6 +38,7 @@ import net.minecraft.commands.arguments.coordinates.ColumnPosArgument; import net.minecraft.commands.arguments.coordinates.Coordinates; import net.minecraft.core.BlockPos; +import net.minecraft.core.GlobalPos; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; @@ -188,9 +190,25 @@ public static void registerCommands(CommandDispatcher dispat .then(Commands.literal("add") .then(Commands.argument("name", StringArgumentType.string()) .then(Commands.argument("position", BlockPosArgument.blockPos()) - .executes(context -> addWaypoint(context.getSource(), StringArgumentType.getString(context, "name"), BlockPosArgument.getLoadedBlockPos(context, "position"))) + .executes(context -> addWaypoint(context.getSource(), StringArgumentType.getString(context, "name"), BlockPosArgument.getBlockPos(context, "position"))) .then(Commands.argument("color", ColorArgument.color()) - .executes(context -> addWaypoint(context.getSource(), StringArgumentType.getString(context, "name"), BlockPosArgument.getLoadedBlockPos(context, "position"), ColorArgument.getColor(context, "color"))) + .executes(context -> addWaypoint(context.getSource(), StringArgumentType.getString(context, "name"), context.getSource().getLevel(), BlockPosArgument.getBlockPos(context, "position"), ColorArgument.getColor(context, "color"))) + ) + ) + ) + ) + .then(Commands.literal("add-dim") + .then(Commands.argument("name", StringArgumentType.string()) + .then(Commands.argument("position", BlockPosArgument.blockPos()) + .executes(context -> addWaypoint(context.getSource(), StringArgumentType.getString(context, "name"), BlockPosArgument.getBlockPos(context, "position"))) + .then(Commands.argument("dimension", DimensionArgument.dimension()) + .executes(context -> addWaypoint(context.getSource(), StringArgumentType.getString(context, "name"), DimensionArgument.getDimension(context, "dimension"), BlockPosArgument.getBlockPos(context, "position"))) + .then(Commands.argument("color", ColorArgument.color()) + .executes(context -> addWaypoint(context.getSource(), StringArgumentType.getString(context, "name"), DimensionArgument.getDimension(context, "dimension"), BlockPosArgument.getBlockPos(context, "position"), ColorArgument.getColor(context, "color"))) + .then(Commands.argument("gui", BoolArgumentType.bool()) + .executes(context -> addWaypoint(context.getSource(), StringArgumentType.getString(context, "name"), DimensionArgument.getDimension(context, "dimension"), BlockPosArgument.getBlockPos(context, "position"), ColorArgument.getColor(context, "color"), BoolArgumentType.getBool(context, "gui"))) + ) + ) ) ) ) @@ -201,17 +219,26 @@ public static void registerCommands(CommandDispatcher dispat dispatcher.register(Commands.literal("chunks").redirect(command)); } - private static int addWaypoint(CommandSourceStack source, String name, BlockPos position, ChatFormatting color) throws CommandSyntaxException { + private static int addWaypoint(CommandSourceStack source, String name, ServerLevel level, BlockPos position, ChatFormatting color, boolean useGui) throws CommandSyntaxException { if (color.getColor() != null) { ServerPlayer player = source.getPlayerOrException(); - new AddWaypointPacket(name, position, color.getColor()).sendTo(player); + new AddWaypointPacket(name, GlobalPos.of(level.dimension(), position), color.getColor(), useGui).sendTo(player); } return 1; } + private static int addWaypoint(CommandSourceStack source, String name, ServerLevel level, BlockPos position, ChatFormatting color) throws CommandSyntaxException { + return addWaypoint(source, name, level ,position, color, false); + } + private static int addWaypoint(CommandSourceStack source, String name, BlockPos position) throws CommandSyntaxException { int idx = source.getPlayerOrException().getRandom().nextInt(ChatFormatting.values().length); - return addWaypoint(source, name, position, ChatFormatting.values()[idx]); + return addWaypoint(source, name, source.getLevel(), position, ChatFormatting.values()[idx], false); + } + + private static int addWaypoint(CommandSourceStack source, String name, ServerLevel level, BlockPos position) throws CommandSyntaxException { + int idx = source.getPlayerOrException().getRandom().nextInt(ChatFormatting.values().length); + return addWaypoint(source, name, level ,position, ChatFormatting.values()[idx], false); } private static int bypassProtection(CommandSourceStack source) throws CommandSyntaxException { diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/FTBChunksWorldConfig.java b/common/src/main/java/dev/ftb/mods/ftbchunks/FTBChunksWorldConfig.java index ef639b11..5f7bc216 100644 --- a/common/src/main/java/dev/ftb/mods/ftbchunks/FTBChunksWorldConfig.java +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/FTBChunksWorldConfig.java @@ -42,6 +42,11 @@ public interface FTBChunksWorldConfig { BooleanValue LOCATION_MODE_OVERRIDE = CONFIG.addBoolean("location_mode_override", false).comment("If true, \"Location Visibility\" team settings are ignored, and all players can see each other anywhere on the map."); IntValue MAX_PREVENTED_LOG_AGE = CONFIG.addInt("max_prevented_log_age", 7, 1, Integer.MAX_VALUE).comment("Maximum time in days to keep logs of prevented fakeplayer access to a team's claims."); + SNBTConfig WAYPOINT_SHARING = CONFIG.addGroup("waypoint_sharing"); + BooleanValue WAYPOINT_SHARING_SERVER = WAYPOINT_SHARING.addBoolean("waypoint_sharing_server", true).comment("Allow players to share waypoints with the entire server."); + BooleanValue WAYPOINT_SHARING_PARTY = WAYPOINT_SHARING.addBoolean("waypoint_sharing_party", true).comment("Allow players to share waypoints with their party."); + BooleanValue WAYPOINT_SHARING_PLAYERS = WAYPOINT_SHARING.addBoolean("waypoint_sharing_players", true).comment("Allow players to share waypoints with other players."); + static int getMaxClaimedChunks(ChunkTeamData playerData, ServerPlayer player) { if (player != null) { return PermissionsHelper.getMaxClaimedChunks(player, MAX_CLAIMED_CHUNKS.get()) + playerData.getExtraClaimChunks(); diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/api/ClaimResult.java b/common/src/main/java/dev/ftb/mods/ftbchunks/api/ClaimResult.java index a2a5a1e3..681acc56 100644 --- a/common/src/main/java/dev/ftb/mods/ftbchunks/api/ClaimResult.java +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/api/ClaimResult.java @@ -72,7 +72,7 @@ enum StandardProblem implements ClaimResult { NOT_LOADED("not_loaded"), ; - public static final NameMap NAME_MAP = NameMap.of(NOT_OWNER, values()).create(); + public static final NameMap NAME_MAP = NameMap.of(NOT_OWNER, values()).baseNameKey("ftbchunks.standard_problem").create(); private final String resultName; diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/api/FTBChunksTags.java b/common/src/main/java/dev/ftb/mods/ftbchunks/api/FTBChunksTags.java index 796e1722..62798bf2 100644 --- a/common/src/main/java/dev/ftb/mods/ftbchunks/api/FTBChunksTags.java +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/api/FTBChunksTags.java @@ -28,5 +28,7 @@ public static class Entities { = TagKey.create(Registries.ENTITY_TYPE, new ResourceLocation(FTBChunks.MOD_ID, "entity_interact_whitelist")); public static final TagKey> NONLIVING_ENTITY_ATTACK_WHITELIST_TAG = TagKey.create(Registries.ENTITY_TYPE, new ResourceLocation(FTBChunks.MOD_ID, "nonliving_entity_attack_whitelist")); + public static final TagKey> ENTITY_MOB_GRIEFING_BLACKLIST_TAG + = TagKey.create(Registries.ENTITY_TYPE, FTBChunksAPI.rl("entity_mob_griefing_blacklist")); } } diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/api/client/FTBChunksClientAPI.java b/common/src/main/java/dev/ftb/mods/ftbchunks/api/client/FTBChunksClientAPI.java index 82c74cbb..c4137afe 100644 --- a/common/src/main/java/dev/ftb/mods/ftbchunks/api/client/FTBChunksClientAPI.java +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/api/client/FTBChunksClientAPI.java @@ -1,5 +1,7 @@ package dev.ftb.mods.ftbchunks.api.client; +import com.google.common.collect.ImmutableList; +import dev.ftb.mods.ftbchunks.api.client.minimap.MinimapInfoComponent; import dev.ftb.mods.ftbchunks.api.client.waypoint.WaypointManager; import net.minecraft.resources.ResourceKey; import net.minecraft.world.level.Level; @@ -27,4 +29,33 @@ public interface FTBChunksClientAPI { * entities...) */ void requestMinimapIconRefresh(); + + /** + * Register a custom minimap info component {@link MinimapInfoComponent} to be rendered on the minimap. + * + * This should be called during mod initialization as this list will be finalized once Minecraft has "started" + * per the client lifecycle events + * + * @param component the component to register + */ + void registerMinimapComponent(MinimapInfoComponent component); + + + /** + * @param component the component to check if it is enabled + * @return is the component enabled and will render under the minimap + */ + boolean isMinimapComponentEnabled(MinimapInfoComponent component); + + /** + * Enable or disable a specific minimap component for rendering under the minimap + * @param component the component to enable or disable to that shoul + * @param enabled the state to set the component to + */ + void setMinimapComponentEnabled(MinimapInfoComponent component, boolean enabled); + + /** + * Provides an immutable list of all registered minimap components. + */ + ImmutableList getMinimapComponents(); } diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/api/client/minimap/MinimapContext.java b/common/src/main/java/dev/ftb/mods/ftbchunks/api/client/minimap/MinimapContext.java new file mode 100644 index 00000000..eb396db4 --- /dev/null +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/api/client/minimap/MinimapContext.java @@ -0,0 +1,33 @@ +package dev.ftb.mods.ftbchunks.api.client.minimap; + +import dev.ftb.mods.ftbchunks.client.map.MapDimension; +import dev.ftb.mods.ftblibrary.math.XZ; +import net.minecraft.client.Minecraft; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.world.phys.Vec3; + +import java.util.Map; + +/** + * Minimal context for Minimap Info Components + * + * @param minecraft The Minecraft instance (Helper) + * @param player The client player + * @param mapDimension The dimension of the players location + * @param mapChunksPos The chunk for the players location + * @param playerPos the players pos + * @param infoSettings raw settings for this component + */ +public record MinimapContext( + Minecraft minecraft, + LocalPlayer player, + MapDimension mapDimension, + XZ mapChunksPos, + Vec3 playerPos, + Map infoSettings +) { + + public String getSetting(MinimapInfoComponent infoComponent) { + return infoSettings.getOrDefault(infoComponent.id().toString(), ""); + } +} \ No newline at end of file diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/api/client/minimap/MinimapInfoComponent.java b/common/src/main/java/dev/ftb/mods/ftbchunks/api/client/minimap/MinimapInfoComponent.java new file mode 100644 index 00000000..9216dd74 --- /dev/null +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/api/client/minimap/MinimapInfoComponent.java @@ -0,0 +1,90 @@ +package dev.ftb.mods.ftbchunks.api.client.minimap; + +import dev.ftb.mods.ftbchunks.client.FTBChunksClientConfig; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; + +import java.util.Set; + +/** + * An entry point for developers to create custom minimap info components. + */ +public interface MinimapInfoComponent { + /** + * The ID of this component. + */ + ResourceLocation id(); + + /** + * Render your component here, the {@link com.mojang.blaze3d.vertex.PoseStack} will already be scaled and + * translated to the correct position (centered by default). We do not provide an X and Y position as + * 0, 0 is the center of the correct location. Use 0, 0 as the center of the component and {@link #height(MinimapContext)} + * to allocate the correct height for the component. + * + * @param context The minimap context + * @param graphics The graphics object see {@link GuiGraphics} + * @param font The font object + */ + void render(MinimapContext context, GuiGraphics graphics, Font font); + + /** + * Set of Info {@link TranslatedOption} that are used to configure options for rendering the waypoint + * this is exposed in the right click action of Minimap Info GUI + * @return the set of {@link TranslatedOption}. + */ + default Set getConfigComponents() { + return Set.of(); + } + + /** + * The height of the component is used to allocate the correct space for the component. Failure to return the correct + * height will result in the component overlapping with other components. + * + * @param context The minimap context + * @return The height of the component + */ + default int height(MinimapContext context) { + return computeLineHeight(context.minecraft(), 1) + 1; + } + + /** + * Checked on each render frame to determine if the height for the component should be allocated + */ + default boolean shouldRender(MinimapContext context) { + return true; + } + + /** + * Helper method to compute the height of a text component whilst taking into account the font scale + */ + default int computeLineHeight(Minecraft minecraft, int lines) { + final float fontScale = FTBChunksClientConfig.MINIMAP_FONT_SCALE.get().floatValue(); + return (int) ((minecraft.font.lineHeight + 2) * lines * fontScale); + } + + /** + * Helper method to draw centered text without the faff of calculating the width of the text + */ + default void drawCenteredText(Font font, GuiGraphics graphics, Component text, int y) { + int textWidth = font.width(text.getVisualOrderText()); + graphics.drawString(font, text, -textWidth / 2, y, 0xFFFFFFFF, true); + } + + + /** + * @return display name render in the Minimap Info Settings GUI + */ + default Component displayName() { + return Component.translatable("minimap.info." + id().getNamespace() + "." + id().getPath() + ".title"); + } + + /** + * @return hover texted displayed render in the Minimap Info Settings GUI + */ + default Component description() { + return Component.translatable("minimap.info." + id().getNamespace() + "." + id().getPath() + ".description"); + } +} \ No newline at end of file diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/api/client/minimap/TranslatedOption.java b/common/src/main/java/dev/ftb/mods/ftbchunks/api/client/minimap/TranslatedOption.java new file mode 100644 index 00000000..a8bd6c15 --- /dev/null +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/api/client/minimap/TranslatedOption.java @@ -0,0 +1,12 @@ +package dev.ftb.mods.ftbchunks.api.client.minimap; + +public record TranslatedOption( + String optionName, + String translationKey +) { + + public static TranslatedOption of(String optionName) { + String translatedKey = optionName.toLowerCase().replaceAll("[^a-z0-9]", "_"); + return new TranslatedOption(optionName, "minimap.option." + translatedKey); + } +} \ No newline at end of file diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/client/FTBChunksClient.java b/common/src/main/java/dev/ftb/mods/ftbchunks/client/FTBChunksClient.java index 687202d6..d853f490 100644 --- a/common/src/main/java/dev/ftb/mods/ftbchunks/client/FTBChunksClient.java +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/client/FTBChunksClient.java @@ -12,30 +12,30 @@ import dev.architectury.event.events.client.*; import dev.architectury.hooks.client.screen.ScreenAccess; import dev.architectury.injectables.annotations.ExpectPlatform; +import dev.architectury.platform.Platform; import dev.architectury.registry.ReloadListenerRegistry; import dev.architectury.registry.client.keymappings.KeyMappingRegistry; import dev.ftb.mods.ftbchunks.ColorMapLoader; import dev.ftb.mods.ftbchunks.FTBChunks; import dev.ftb.mods.ftbchunks.FTBChunksWorldConfig; import dev.ftb.mods.ftbchunks.api.FTBChunksAPI; +import dev.ftb.mods.ftbchunks.api.client.FTBChunksClientAPI; import dev.ftb.mods.ftbchunks.api.client.event.MapIconEvent; import dev.ftb.mods.ftbchunks.api.client.icon.MapIcon; import dev.ftb.mods.ftbchunks.api.client.icon.MapType; import dev.ftb.mods.ftbchunks.api.client.icon.WaypointIcon; +import dev.ftb.mods.ftbchunks.api.client.minimap.MinimapContext; +import dev.ftb.mods.ftbchunks.api.client.minimap.MinimapInfoComponent; import dev.ftb.mods.ftbchunks.api.client.waypoint.Waypoint; -import dev.ftb.mods.ftbchunks.client.gui.AddWaypointOverlay; -import dev.ftb.mods.ftbchunks.client.gui.ChunkScreen; -import dev.ftb.mods.ftbchunks.client.gui.LargeMapScreen; -import dev.ftb.mods.ftbchunks.client.gui.WaypointEditorScreen; +import dev.ftb.mods.ftbchunks.client.gui.*; import dev.ftb.mods.ftbchunks.client.map.*; import dev.ftb.mods.ftbchunks.client.map.color.ColorUtils; import dev.ftb.mods.ftbchunks.client.mapicon.*; +import dev.ftb.mods.ftbchunks.client.minimap.components.*; import dev.ftb.mods.ftbchunks.net.PartialPackets; import dev.ftb.mods.ftbchunks.net.SendGeneralDataPacket.GeneralChunkData; import dev.ftb.mods.ftblibrary.config.ColorConfig; import dev.ftb.mods.ftblibrary.config.StringConfig; -import dev.ftb.mods.ftblibrary.config.ui.EditConfigFromStringScreen; -import dev.ftb.mods.ftblibrary.config.ui.EditStringConfigOverlay; import dev.ftb.mods.ftblibrary.icon.Color4I; import dev.ftb.mods.ftblibrary.icon.FaceIcon; import dev.ftb.mods.ftblibrary.icon.Icon; @@ -47,7 +47,6 @@ import dev.ftb.mods.ftblibrary.ui.GuiHelper; import dev.ftb.mods.ftblibrary.ui.Theme; import dev.ftb.mods.ftblibrary.ui.input.Key; -import dev.ftb.mods.ftblibrary.util.StringUtils; import dev.ftb.mods.ftblibrary.util.client.ClientUtils; import dev.ftb.mods.ftbteams.api.event.ClientTeamPropertiesChangedEvent; import dev.ftb.mods.ftbteams.api.event.TeamEvent; @@ -66,7 +65,6 @@ import net.minecraft.client.renderer.GameRenderer; import net.minecraft.core.BlockPos; import net.minecraft.core.GlobalPos; -import net.minecraft.core.Holder; import net.minecraft.core.SectionPos; import net.minecraft.network.chat.ClickEvent; import net.minecraft.network.chat.Component; @@ -79,14 +77,12 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.PackType; import net.minecraft.server.packs.resources.ResourceProvider; -import net.minecraft.util.FormattedCharSequence; import net.minecraft.util.Mth; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.MobCategory; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; -import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkStatus; @@ -99,6 +95,8 @@ import org.lwjgl.opengl.GL11; import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; import static dev.ftb.mods.ftbchunks.net.SendChunkPacket.SingleChunk; @@ -121,6 +119,7 @@ public enum FTBChunksClient { }; public KeyMapping openMapKey; + public KeyMapping toggleMinimapKey; public KeyMapping openClaimManagerKey; public KeyMapping zoomInKey; public KeyMapping zoomOutKey; @@ -149,8 +148,12 @@ public enum FTBChunksClient { private Matrix4f worldMatrix; private Vec3 cameraPos; + private final List sortedComponents = new LinkedList<>(); + // kludge to move potion effects left to avoid rendering over/under minimap in top right of screen + private static double vanillaEffectsOffsetX; - public void init() { + + public void init() { if (Minecraft.getInstance() == null) { return; } @@ -172,9 +175,24 @@ public void init() { TeamEvent.CLIENT_PROPERTIES_CHANGED.register(this::teamPropertiesChanged); MapIconEvent.LARGE_MAP.register(this::mapIcons); MapIconEvent.MINIMAP.register(this::mapIcons); -// RefreshMinimapIconsEvent.EVENT.register(this::refreshMinimapIcons); ClientReloadShadersEvent.EVENT.register(this::reloadShaders); registerPlatform(); + + // Register minimap components + FTBChunksClientAPI clientApi = FTBChunksAPI.clientApi(); + clientApi.registerMinimapComponent(new PlayerPosInfoComponent()); + clientApi.registerMinimapComponent(new ZoneInfoComponent()); + clientApi.registerMinimapComponent(new BiomeComponent()); + clientApi.registerMinimapComponent(new GameTimeComponent()); + clientApi.registerMinimapComponent(new RealTimeComponent()); + clientApi.registerMinimapComponent(new FPSComponent()); + clientApi.registerMinimapComponent(new DebugComponent()); + + ClientLifecycleEvent.CLIENT_STARTED.register(this::clientStarted); + } + + private void clientStarted(Minecraft minecraft) { + this.setupComponents(); } private void registerKeys() { @@ -182,6 +200,10 @@ private void registerKeys() { openMapKey = new KeyMapping("key.ftbchunks.map", InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_M, "key.categories.ftbchunks"); KeyMappingRegistry.register(openMapKey); + // Keybinding to open Large map screen + toggleMinimapKey = new KeyMapping("key.ftbchunks.toggle_minimap", InputConstants.Type.KEYSYM, -1, "key.categories.ftbchunks"); + KeyMappingRegistry.register(toggleMinimapKey); + // Keybinding to open claim manager screen openClaimManagerKey = new KeyMapping("key.ftbchunks.claim_manager", InputConstants.Type.KEYSYM, -1, "key.categories.ftbchunks"); KeyMappingRegistry.register(openClaimManagerKey); @@ -229,7 +251,7 @@ public void scheduleMinimapUpdate() { } public void handlePlayerLogin(UUID serverId, SNBTCompoundTag config) { - FTBChunks.LOGGER.info("Loading FTB Chunks client data from world " + serverId); + FTBChunks.LOGGER.info("Loading FTB Chunks client data from world {}", serverId); FTBChunksWorldConfig.CONFIG.read(config); MapManager.startUp(serverId); scheduleMinimapUpdate(); @@ -339,17 +361,12 @@ public EventResult keyPressed(Minecraft client, int keyCode, int scanCode, int a return EventResult.pass(); } if (doesKeybindMatch(openMapKey, keyCode, scanCode, modifiers)) { - if (Screen.hasControlDown()) { - SNBTCompoundTag tag = new SNBTCompoundTag(); - tag.putBoolean(FTBChunksClientConfig.MINIMAP_ENABLED.key, !FTBChunksClientConfig.MINIMAP_ENABLED.get()); - FTBChunksClientConfig.MINIMAP_ENABLED.read(tag); - FTBChunksClientConfig.saveConfig(); - } else if (FTBChunksClientConfig.DEBUG_INFO.get() && Screen.hasAltDown()) { - ClientTaskQueue.dumpTaskInfo(); - } else { - openGui(); - return EventResult.interruptTrue(); - } + openGui(); + return EventResult.interruptTrue(); + } else if (doesKeybindMatch(toggleMinimapKey, keyCode, scanCode, modifiers)) { + FTBChunksClientConfig.MINIMAP_ENABLED.set(!FTBChunksClientConfig.MINIMAP_ENABLED.get()); + FTBChunksClientConfig.saveConfig(); + return EventResult.interruptTrue(); } else if (doesKeybindMatch(openClaimManagerKey, keyCode, scanCode, modifiers)) { ChunkScreen.openChunkScreen(); return EventResult.interruptTrue(); @@ -361,13 +378,15 @@ public EventResult keyPressed(Minecraft client, int keyCode, int scanCode, int a return addQuickWaypoint(); } else if (doesKeybindMatch(waypointManagerKey, keyCode, scanCode, modifiers)) { new WaypointEditorScreen().openGui(); + return EventResult.interruptTrue(); } return EventResult.pass(); } public EventResult keyPressed(Minecraft client, Screen screen, int keyCode, int scanCode, int modifiers) { - if (doesKeybindMatch(openMapKey, keyCode, scanCode, modifiers)) { + if (doesKeybindMatch(openMapKey, keyCode, scanCode, modifiers) && Platform.isFabric()) { + // platform specific behaviour :( why? ¯\_(ツ)_/¯ LargeMapScreen gui = ClientUtils.getCurrentGuiAs(LargeMapScreen.class); if (gui != null && !gui.anyModalPanelOpen()) { gui.closeGui(false); @@ -539,6 +558,13 @@ public void renderHud(GuiGraphics graphics, float tickDelta) { y -= minimapPosition.posY > 1 ? offsetY : -offsetY; } + // a bit of a kludge here: vanilla renders active mobeffects in the top-right; move the minimap down if necessary to avoid them + if (!mc.player.getActiveEffects().isEmpty() && y <= 50 && x + size > scaledWidth - 50) { + vanillaEffectsOffsetX = -(scaledWidth - x) - 5; + } else { + vanillaEffectsOffsetX = 0; + } + float border = 0F; int alpha = FTBChunksClientConfig.MINIMAP_VISIBILITY.get(); @@ -677,23 +703,28 @@ public void renderHud(GuiGraphics graphics, float tickDelta) { poseStack.popPose(); } - List textList = buildMinimapTextData(mc, playerX, playerY, playerZ, dim); - if (!textList.isEmpty()) { - float fontScale = FTBChunksClientConfig.MINIMAP_FONT_SCALE.get().floatValue(); - float textHeight = (mc.font.lineHeight + 2) * textList.size() * fontScale; - // draw text below minimap if there's room, above otherwise - float yOff = y + size + textHeight >= scaledHeight ? -textHeight : size + 2f; + // The minimap info text + var context = new MinimapContext(mc, mc.player, dim, XZ.of(currentPlayerChunkX, currentPlayerChunkZ), new Vec3(playerX, playerY, playerZ), FTBChunksClientConfig.MINIMAP_SETTINGS.get()); + var fontScale = FTBChunksClientConfig.MINIMAP_FONT_SCALE.get().floatValue(); + + int yOffset = 0; + for (MinimapInfoComponent component : sortedComponents) { + if (!component.shouldRender(context)) { + continue; + } + + var height = component.height(context); + var isBottom = y + size + height >= scaledHeight; + var yOff = isBottom ? (-height - yOffset) : (size + 2f + yOffset); poseStack.pushPose(); poseStack.translate(x + halfSizeD, y + yOff, 0D); poseStack.scale(fontScale, fontScale, 1F); - for (int i = 0; i < textList.size(); i++) { - FormattedCharSequence text = textList.get(i).getVisualOrderText(); - int textWidth = mc.font.width(text); - graphics.drawString(mc.font, text, -textWidth / 2, i * (mc.font.lineHeight + 2), 0xFFFFFFFF, true); - } + component.render(context, graphics, mc.font); poseStack.popPose(); + + yOffset += height; } RenderSystem.enableDepthTest(); @@ -724,43 +755,6 @@ private void drawMinimapCompassPoints(float minimapRotation, int size, double ha } } - private List buildMinimapTextData(Minecraft mc, double playerX, double playerY, double playerZ, MapDimension dim) { - List res = new ArrayList<>(); - - if (FTBChunksClientConfig.MINIMAP_ZONE.get()) { - MapRegionData data = dim.getRegion(XZ.regionFromChunk(currentPlayerChunkX, currentPlayerChunkZ)).getData(); - if (data != null) { - data.getChunk(XZ.of(currentPlayerChunkX, currentPlayerChunkZ)).getTeam() - .ifPresent(team -> res.add(team.getColoredName())); - } - } - - if (FTBChunksClientConfig.MINIMAP_XYZ.get()) { - res.add(Component.literal(Mth.floor(playerX) + " " + Mth.floor(playerY) + " " + Mth.floor(playerZ))); - } - - if (FTBChunksClientConfig.MINIMAP_BIOME.get()) { - Holder biome = mc.level.getBiome(mc.player.blockPosition()); - biome.unwrapKey().ifPresent(e -> - res.add(Component.translatable("biome." + e.location().getNamespace() + "." + e.location().getPath())) - ); - } - - if (FTBChunksClientConfig.DEBUG_INFO.get()) { - XZ playerXZ = XZ.regionFromChunk(currentPlayerChunkX, currentPlayerChunkZ); - long memory = MapManager.getInstance().map(MapManager::estimateMemoryUsage).orElse(0L); - res.add(Component.literal("TQ: " + ClientTaskQueue.queueSize()).withStyle(ChatFormatting.GRAY)); - res.add(Component.literal("Rgn: " + playerXZ).withStyle(ChatFormatting.GRAY)); - res.add(Component.literal("Mem: ~" + StringUtils.formatDouble00(memory / 1024D / 1024D) + " MB").withStyle(ChatFormatting.GRAY)); - res.add(Component.literal("Updates: " + renderedDebugCount).withStyle(ChatFormatting.GRAY)); - if (ChunkUpdateTask.getDebugLastTime() > 0L) { - res.add(Component.literal(String.format("Last: %,d ns", ChunkUpdateTask.getDebugLastTime())).withStyle(ChatFormatting.GRAY)); - } - } - - return res; - } - private void drawInWorldIcons(Minecraft mc, GuiGraphics graphics, float tickDelta, double playerX, double playerY, double playerZ, int scaledWidth, int scaledHeight) { GuiHelper.setupDrawing(); float ww2 = scaledWidth / 2F; @@ -1044,6 +1038,7 @@ private void mapIcons(MapIconEvent event) { if (!event.getMapType().isMinimap()) { event.add(new EntityMapIcon(mc.player, FaceIcon.getFace(mc.player.getGameProfile()))); + event.add(new PointerIcon()); } } @@ -1162,25 +1157,79 @@ public int getMinimapTextureId() { return minimapTextureId; } - public static Waypoint addWaypoint(Player player, String name, BlockPos position, int color) { - return FTBChunksAPI.clientApi().getWaypointManager(player.level().dimension()).map(mgr -> { - Waypoint wp = mgr.addWaypointAt(position, name); + public static Waypoint addWaypoint(String name, GlobalPos globalPos, int color) { + return FTBChunksAPI.clientApi().getWaypointManager(globalPos.dimension()).map(mgr -> { + Waypoint wp = mgr.addWaypointAt(globalPos.pos(), name); wp.setColor(color); return wp; }).orElse(null); } - private static class WaypointAddScreen extends BaseScreen { + public void setupComponents() { + this.sortedComponents.clear(); + this.computeOrderedComponents(); + } + + /** + * Handles the headache of sorting logic + */ + private void computeOrderedComponents() { + Map componentMap = FTBChunksAPI.clientApi().getMinimapComponents().stream() + .collect(Collectors.toMap(MinimapInfoComponent::id, Function.identity())); + + List order = FTBChunksClientConfig.MINIMAP_INFO_ORDER.get() + .stream() + .map(ResourceLocation::new) + .collect(Collectors.toList()); + + // Adds any missing components to the end of the list + boolean save = false; + for (ResourceLocation location : componentMap.keySet()) { + if (!order.contains(location)) { + order.add(location); + save = true; + } + } + + if (save) { + FTBChunksClientConfig.MINIMAP_INFO_ORDER.set(order.stream().map(ResourceLocation::toString).collect(Collectors.toList())); + FTBChunksClientConfig.saveConfig(); + } + + for (ResourceLocation id : order) { + MinimapInfoComponent minimapInfoComponent = componentMap.get(id); + if (minimapInfoComponent != null && FTBChunksAPI.clientApi().isMinimapComponentEnabled(minimapInfoComponent)) { + sortedComponents.add(minimapInfoComponent); + } + } + } + + // See GuiMixin + // This moves the vanilla potion effects rendering to the left of the minimap if it's in the top-right + public static double getVanillaEffectsOffsetX() { + return vanillaEffectsOffsetX; + } + + public int getRenderedDebugCount() { + return renderedDebugCount; + } + + public static class WaypointAddScreen extends BaseScreen { private final StringConfig name; - private final Player player; + private final GlobalPos waypointLocation; - public WaypointAddScreen(StringConfig name, Player player) { + public WaypointAddScreen(StringConfig name, GlobalPos waypointLocation) { super(); this.name = name; - this.player = player; + this.waypointLocation = waypointLocation; this.setHeight(35); } + public WaypointAddScreen(StringConfig name, Player player) { + this(name, GlobalPos.of(player.level().dimension(), player.blockPosition())); + } + + @Override public void drawBackground(GuiGraphics graphics, Theme theme, int x, int y, int w, int h) { } @@ -1191,7 +1240,7 @@ public void addWidgets() { col.setValue(Color4I.hsb(MathUtils.RAND.nextFloat(), 1F, 1F)); AddWaypointOverlay overlay = new AddWaypointOverlay(this, name, col, set -> { if (set && !name.getValue().isEmpty()) { - Waypoint wp = addWaypoint(player, name.getValue(), player.blockPosition(), col.getValue().rgba()); + Waypoint wp = addWaypoint(name.getValue(), waypointLocation, col.getValue().rgba()); Minecraft.getInstance().player.displayClientMessage( Component.translatable("ftbchunks.waypoint_added", Component.literal(wp.getName()).withStyle(ChatFormatting.YELLOW) diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/client/FTBChunksClientAPIImpl.java b/common/src/main/java/dev/ftb/mods/ftbchunks/client/FTBChunksClientAPIImpl.java index 47d6e148..bc2fc188 100644 --- a/common/src/main/java/dev/ftb/mods/ftbchunks/client/FTBChunksClientAPIImpl.java +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/client/FTBChunksClientAPIImpl.java @@ -1,15 +1,21 @@ package dev.ftb.mods.ftbchunks.client; +import com.google.common.collect.ImmutableList; import dev.ftb.mods.ftbchunks.api.client.FTBChunksClientAPI; +import dev.ftb.mods.ftbchunks.api.client.minimap.MinimapInfoComponent; import dev.ftb.mods.ftbchunks.api.client.waypoint.WaypointManager; import dev.ftb.mods.ftbchunks.client.map.MapDimension; import dev.ftb.mods.ftbchunks.client.map.MapManager; import net.minecraft.resources.ResourceKey; import net.minecraft.world.level.Level; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; public class FTBChunksClientAPIImpl implements FTBChunksClientAPI { + private static final List minimapComponents = new ArrayList<>(); + @Override public Optional getWaypointManager() { return MapDimension.getCurrent().flatMap(d -> Optional.ofNullable(d.getWaypointManager())); @@ -24,4 +30,34 @@ public Optional getWaypointManager(ResourceKey dimension public void requestMinimapIconRefresh() { FTBChunksClient.INSTANCE.refreshMinimapIcons(); } + + @Override + public void registerMinimapComponent(MinimapInfoComponent component) { + if (minimapComponents.contains(component)) { + throw new IllegalStateException("Minimap component %s already registered".formatted(component.id())); + } + + minimapComponents.add(component); + } + + @Override + public boolean isMinimapComponentEnabled(MinimapInfoComponent component) { + return !FTBChunksClientConfig.MINIMAP_INFO_HIDDEN.get().contains(component.id().toString()); + } + + @Override + public void setMinimapComponentEnabled(MinimapInfoComponent component, boolean enabled) { + if (enabled) { + FTBChunksClientConfig.MINIMAP_INFO_HIDDEN.get().remove(component.id().toString()); + } else { + FTBChunksClientConfig.MINIMAP_INFO_HIDDEN.get().add(component.id().toString()); + } + FTBChunksClientConfig.saveConfig(); + FTBChunksClient.INSTANCE.setupComponents(); + } + + @Override + public ImmutableList getMinimapComponents() { + return ImmutableList.copyOf(minimapComponents); + } } diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/client/FTBChunksClientConfig.java b/common/src/main/java/dev/ftb/mods/ftbchunks/client/FTBChunksClientConfig.java index 2d820667..bc9dedab 100644 --- a/common/src/main/java/dev/ftb/mods/ftbchunks/client/FTBChunksClientConfig.java +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/client/FTBChunksClientConfig.java @@ -6,13 +6,20 @@ import dev.ftb.mods.ftbchunks.client.map.BiomeBlendMode; import dev.ftb.mods.ftbchunks.client.map.MapManager; import dev.ftb.mods.ftbchunks.client.map.MapMode; +import dev.ftb.mods.ftbchunks.client.minimap.components.*; import dev.ftb.mods.ftbchunks.net.ServerConfigRequestPacket; import dev.ftb.mods.ftblibrary.config.ConfigGroup; +import dev.ftb.mods.ftblibrary.config.StringMapValue; import dev.ftb.mods.ftblibrary.config.ui.EditConfigScreen; import dev.ftb.mods.ftblibrary.snbt.SNBTCompoundTag; import dev.ftb.mods.ftblibrary.snbt.config.*; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.Screen; +import net.minecraft.resources.ResourceLocation; + +import java.util.Collections; +import java.util.List; +import java.util.stream.Stream; import static dev.ftb.mods.ftblibrary.snbt.config.ConfigUtil.LOCAL_DIR; import static dev.ftb.mods.ftblibrary.snbt.config.ConfigUtil.loadDefaulted; @@ -59,17 +66,17 @@ public interface FTBChunksClientConfig { BooleanValue MINIMAP_ENTITIES = MINIMAP.addBoolean("entities", true).comment("Show entities on minimap"); BooleanValue MINIMAP_ENTITY_HEADS = MINIMAP.addBoolean("entity_heads", true).comment("Show entity heads on minimap"); BooleanValue MINIMAP_LARGE_ENTITIES = MINIMAP.addBoolean("large_entities", false).comment("Entities in minimap will be larger"); - BooleanValue MINIMAP_XYZ = MINIMAP.addBoolean("xyz", true).comment("Show XYZ under minimap"); - BooleanValue MINIMAP_BIOME = MINIMAP.addBoolean("biome", true).comment("Show biome under minimap"); EnumValue MINIMAP_BLUR_MODE = MINIMAP.addEnum("blur_mode", MinimapBlurMode.NAME_MAP).comment("Blurs minimap"); BooleanValue MINIMAP_COMPASS = MINIMAP.addBoolean("compass", true).comment("Adds NWSE compass inside minimap"); IntValue MINIMAP_VISIBILITY = MINIMAP.addInt("visibility", 255, 0, 255).comment("Minimap visibility"); - BooleanValue MINIMAP_ZONE = MINIMAP.addBoolean("zone", true).comment("Show zone (claimed chunk or wilderness) under minimap"); IntValue MINIMAP_OFFSET_X = MINIMAP.addInt("position_offset_x", 0).comment("Changes the maps X offset from it's origin point. When on the Left, the map will be pushed out from the left, then from the right when on the right."); IntValue MINIMAP_OFFSET_Y = MINIMAP.addInt("position_offset_y", 0).comment("Changes the maps X offset from it's origin point. When on the Left, the map will be pushed out from the left, then from the right when on the right."); EnumValue MINIMAP_POSITION_OFFSET_CONDITION = MINIMAP.addEnum("position_offset_condition", MinimapPosition.MinimapOffsetConditional.NAME_MAP).comment("Applied a conditional check to the offset. When set to anything other that None, the offset will apply only to the selected minimap position.", "When set to none and the maps offset is greater than 0, the offset will apply to all directions"); BooleanValue SQUARE_MINIMAP = MINIMAP.addBoolean("square", false).comment("Draw a square minimap instead of a circular one"); BooleanValue MINIMAP_PROPORTIONAL = MINIMAP.addBoolean("proportional", true).comment("Size minimap proportional to screen width (and scale)"); + StringListValue MINIMAP_INFO_ORDER = MINIMAP.addStringList("info_order", Stream.of(PlayerPosInfoComponent.ID, BiomeComponent.ID, ZoneInfoComponent.ID, FPSComponent.ID, GameTimeComponent.ID, RealTimeComponent.ID, DebugComponent.ID).map(ResourceLocation::toString).toList()).comment("Info displayed under minimap"); + StringListValue MINIMAP_INFO_HIDDEN = MINIMAP.addStringList("info_hidden", List.of(DebugComponent.ID.toString())).comment("Info hidden under minimap"); + StringMapValue MINIMAP_SETTINGS = MINIMAP.add(new StringMapValue(MINIMAP, "info_settings", Collections.emptyMap())).comment("Settings for minimap info components"); SNBTConfig ADVANCED = CONFIG.addGroup("advanced", 3); BooleanValue DEBUG_INFO = ADVANCED.addBoolean("debug_info", false).comment("Enables debug info"); @@ -124,4 +131,5 @@ static void openServerSettings(Screen screen) { static void saveConfig() { CONFIG.save(Platform.getGameFolder().resolve("local/ftbchunks/client-config.snbt")); } + } diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/client/gui/ChunkScreen.java b/common/src/main/java/dev/ftb/mods/ftbchunks/client/gui/ChunkScreen.java index f1710d69..7a285510 100644 --- a/common/src/main/java/dev/ftb/mods/ftbchunks/client/gui/ChunkScreen.java +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/client/gui/ChunkScreen.java @@ -5,6 +5,7 @@ import dev.ftb.mods.ftbchunks.FTBChunks; import dev.ftb.mods.ftbchunks.FTBChunksWorldConfig; import dev.ftb.mods.ftbchunks.api.ClaimResult; +import dev.ftb.mods.ftbchunks.api.client.icon.MapType; import dev.ftb.mods.ftbchunks.client.FTBChunksClient; import dev.ftb.mods.ftbchunks.client.map.MapChunk; import dev.ftb.mods.ftbchunks.client.map.MapDimension; @@ -158,6 +159,7 @@ public void drawBackground(GuiGraphics graphics, Theme theme, int x, int y, int double hx = sx + FTBChunks.TILE_SIZE * FTBChunks.TILE_OFFSET + MathUtils.mod(player.getX(), 16D); double hy = sy + FTBChunks.TILE_SIZE * FTBChunks.TILE_OFFSET + MathUtils.mod(player.getZ(), 16D); + new PointerIcon().draw(MapType.LARGE_MAP, graphics, (int) (hx - 4D), (int) (hy - 4D), 8, 8, false, 255); FaceIcon.getFace(player.getGameProfile()).draw(graphics, (int) (hx - 4D), (int) (hy - 4D), 8, 8); List list = FTBChunksClient.INSTANCE.getChunkSummary(); diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/client/gui/LargeMapScreen.java b/common/src/main/java/dev/ftb/mods/ftbchunks/client/gui/LargeMapScreen.java index 8bd90a04..b8bf187d 100644 --- a/common/src/main/java/dev/ftb/mods/ftbchunks/client/gui/LargeMapScreen.java +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/client/gui/LargeMapScreen.java @@ -2,6 +2,7 @@ import com.mojang.blaze3d.platform.InputConstants; import com.mojang.blaze3d.vertex.PoseStack; +import dev.architectury.platform.Platform; import dev.ftb.mods.ftbchunks.FTBChunks; import dev.ftb.mods.ftbchunks.client.FTBChunksClient; import dev.ftb.mods.ftbchunks.client.FTBChunksClientConfig; @@ -59,6 +60,7 @@ public class LargeMapScreen extends BaseScreen { private Button settingsButton; private Button serverSettingsButton; private Button clearDeathpointsButton; + private Button infoSortScreen; private boolean needIconRefresh; private final int minZoom; @@ -140,7 +142,8 @@ public void addWidgets() { (b, m) -> new WaypointEditorScreen().openGui(), tooltip)); add(infoButton = new SimpleButton(this, Component.translatable("ftbchunks.gui.large_map_info"), Icons.INFO, (b, m) -> new MapKeyReferenceScreen().openGui())); - + add(infoSortScreen = new SimpleTooltipButton(this, Component.translatable("ftbchunks.gui.sort_minimap_info"), Icons.BOOK, + (b, m) -> new MinimapInfoSortScreen().openGui(), tooltip)); add(clearDeathpointsButton = new ClearDeathPointButton(this)); /* @@ -193,7 +196,8 @@ public void alignWidgets() { claimChunksButton.setPosAndSize(1, 1, 16, 16); waypointManagerButton.setPosAndSize(1, 19, 16, 16); infoButton.setPosAndSize(1, 37, 16, 16); - clearDeathpointsButton.setPosAndSize(1, 55, 16, 16); + infoSortScreen.setPosAndSize(1, 55, 16, 16); + clearDeathpointsButton.setPosAndSize(1, 73, 16, 16); dimensionButton.setPosAndSize(1, height - 36, 16, 16); settingsButton.setPosAndSize(1, height - 18, 16, 16); @@ -275,6 +279,10 @@ public boolean keyPressed(Key key) { return true; } else if (FTBChunksClient.doesKeybindMatch(FTBChunksClient.INSTANCE.waypointManagerKey, key)) { waypointManagerButton.onClicked(MouseButton.LEFT); + } else if (FTBChunksClient.doesKeybindMatch(FTBChunksClient.INSTANCE.openMapKey, key) && Platform.isForge()) { + // platform specific behaviour :( why? ¯\_(ツ)_/¯ + closeGui(false); + return true; } return false; diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/client/gui/MinimapInfoSortScreen.java b/common/src/main/java/dev/ftb/mods/ftbchunks/client/gui/MinimapInfoSortScreen.java new file mode 100644 index 00000000..4e62d018 --- /dev/null +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/client/gui/MinimapInfoSortScreen.java @@ -0,0 +1,263 @@ +package dev.ftb.mods.ftbchunks.client.gui; + +import dev.ftb.mods.ftbchunks.api.FTBChunksAPI; +import dev.ftb.mods.ftbchunks.api.client.minimap.MinimapInfoComponent; +import dev.ftb.mods.ftbchunks.api.client.minimap.TranslatedOption; +import dev.ftb.mods.ftbchunks.client.FTBChunksClient; +import dev.ftb.mods.ftbchunks.client.FTBChunksClientConfig; +import dev.ftb.mods.ftblibrary.icon.Color4I; +import dev.ftb.mods.ftblibrary.icon.Icon; +import dev.ftb.mods.ftblibrary.icon.Icons; +import dev.ftb.mods.ftblibrary.ui.*; +import dev.ftb.mods.ftblibrary.ui.misc.AbstractThreePanelScreen; +import dev.ftb.mods.ftblibrary.util.TooltipList; +import dev.ftb.mods.ftblibrary.util.client.ClientTextComponentUtils; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; + +import java.util.*; + +public class MinimapInfoSortScreen extends AbstractThreePanelScreen { + + private List infoSortList = new LinkedList<>(); + + public MinimapInfoSortScreen() { + super(); + setHeight(200); + setWidth(200); + FTBChunksClientConfig.MINIMAP_INFO_ORDER.get().forEach(s -> infoSortList.add(new ResourceLocation(s))); + showBottomPanel(false); + } + + @Override + protected void doCancel() { + + } + + @Override + protected void doAccept() { + + } + + @Override + protected int getTopPanelHeight() { + return 22; + } + + @Override + protected MinimapInfoSortEntry createMainPanel() { + return new MinimapInfoSortEntry(this); + } + + @Override + protected Panel createTopPanel() { + return new CustomTopPanel(); + } + + protected class CustomTopPanel extends TopPanel { + private final TextField titleLabel = new TextField(this); + + @Override + public void addWidgets() { + titleLabel.setText(Component.translatable("ftbchunks.gui.sort_minimap_info")); + titleLabel.addFlags(Theme.CENTERED_V); + add(titleLabel); + } + + @Override + public void alignWidgets() { + titleLabel.setPosAndSize(4, 0, titleLabel.width, height); + } + } + + public class MinimapInfoSortEntry extends Panel { + + private final Map entryMap = new HashMap<>(); + + public MinimapInfoSortEntry(Panel panel) { + super(panel); + for (MinimapInfoComponent minimapComponent : FTBChunksAPI.clientApi().getMinimapComponents()) { + entryMap.put(minimapComponent.id(), new InfoEntry(minimapComponent, MinimapInfoSortEntry.this)); + } + } + + @Override + public void addWidgets() { + addAll(entryMap.values()); + } + + @Override + public void alignWidgets() { + int height = 0; + for (ResourceLocation id : infoSortList) { + InfoEntry infoEntry = entryMap.get(id); + if (infoEntry != null) { + infoEntry.setPosAndSize(0, height, width, 24); + infoEntry.alignWidgets(); + height += 24; + } + } + } + } + + public class InfoEntry extends Panel { + + private final Button down; + private final Button up; + private final SimpleButton hideButton; + private final TextField field; + private final MinimapInfoComponent infoComponent; + private final SimpleButton configButton; + + public InfoEntry(MinimapInfoComponent infoComponent, Panel panel) { + super(panel); + hideButton = ToggleVisibilityButton.create(this, !isComponentDisabled(infoComponent), (enabled) -> setComponentEnabled(infoComponent, enabled)); + down = new SortScreenButton(InfoEntry.this, Component.translatable("ftbchunks.gui.move_up"), Icons.UP, (widget, button) -> move(false, isShiftKeyDown())); + up = new SortScreenButton(InfoEntry.this, Component.translatable("ftbchunks.gui.move_down"), Icons.DOWN, (widget, button) -> move(true, isShiftKeyDown())); + configButton = new SimpleButton(InfoEntry.this, Component.translatable("gui.settings"), Icons.SETTINGS, (widget, button) -> { + List items = new ArrayList<>(); + for (TranslatedOption translatedOption : infoComponent.getConfigComponents()) { + ContextMenuItem item = new ContextMenuItem(Component.translatable(translatedOption.translationKey()), isTranslatedOptionEnabled(infoComponent, translatedOption) ? Icons.ACCEPT : Icons.REMOVE_GRAY, (button1) -> setTranslatedOptionEnabled(infoComponent, translatedOption)); + items.add(item); + } + openContextMenu(items); + playClickSound(); + }) { + @Override + public void drawIcon(GuiGraphics graphics, Theme theme, int x, int y, int w, int h) { + super.drawIcon(graphics, theme, x, y, 12, 12); + } + }; + field = new TextField(InfoEntry.this) { + @Override + public void addMouseOverText(TooltipList list) { + list.add(infoComponent.description()); + } + }; + this.infoComponent = infoComponent; + } + + + @Override + public void addWidgets() { + int listIndex = infoSortList.indexOf(infoComponent.id()); + if (listIndex != 0) { + add(down); + } + if (listIndex != infoSortList.size() - 1) { + add(up); + } + add(hideButton); + add(field); + if(!infoComponent.getConfigComponents().isEmpty()) { + add(configButton); + } + } + + @Override + public void alignWidgets() { + down.setPosAndSize(6, height / 6 + 1, 6, 8); + up.setPosAndSize(6, height / 6 + 11, 6, 8); + hideButton.setPosAndSize(width - 18, height / 6, 12, 12); + field.setPosAndSize(16, 8, width - 37, height); + if(!infoComponent.getConfigComponents().isEmpty()) { + configButton.setPos(width - 18 - 14, height / 6 + 2); + } + field.setText(ClientTextComponentUtils.ellipsize(getTheme().getFont(), infoComponent.displayName(), hideButton.getPosX() - 14 - 5).getString()); + } + + @Override + public void draw(GuiGraphics graphics, Theme theme, int x, int y, int w, int h) { + theme.drawWidget(graphics, x, y, w, h, getWidgetType()); + if (isMouseOver()) { + Color4I.WHITE.withAlpha(33).draw(graphics, x, y, w, h); + } + super.draw(graphics, theme, x, y, w, h); + } + + /** + * moves the current MiniMapInfoComponent in our ordered list and saves the new order for rendering + * @param forward true if the current value `down` the list and false if `up` the list + * @param end true if the current value is the last value in the list and false if it is not + */ + private void move(boolean forward, boolean end) { + List list = new LinkedList<>(infoSortList); + if (end) { + if (forward) { + list.remove(infoComponent.id()); + list.add(infoComponent.id()); + } else { + list.remove(infoComponent.id()); + list.add(0, infoComponent.id()); + } + } else { + int index = list.indexOf(infoComponent.id()); + if (index == -1) { + return; + } + if (forward) { + if (index == list.size() - 1) { + return; + } + list.remove(index); + list.add(index + 1, infoComponent.id()); + } else { + if (index == 0) { + return; + } + list.remove(index); + list.add(index - 1, infoComponent.id()); + } + } + infoSortList = list; + saveConfig(); + parent.refreshWidgets(); + } + } + + public static class SortScreenButton extends SimpleButton { + + public SortScreenButton(Panel panel, Component text, Icon icon, Callback c) { + super(panel, text, icon, c); + } + + @Override + public void drawIcon(GuiGraphics graphics, Theme theme, int x, int y, int w, int h) { + super.drawIcon(graphics, theme, x - 1, y - 2, 6, 8); + } + } + + + private void saveConfig() { + List list = new LinkedList<>(); + infoSortList.forEach(resourceLocation -> list.add(resourceLocation.toString())); + FTBChunksClientConfig.MINIMAP_INFO_ORDER.set(list); + FTBChunksClientConfig.saveConfig(); + FTBChunksClient.INSTANCE.setupComponents(); + } + + private boolean isComponentDisabled(MinimapInfoComponent component) { + return !FTBChunksAPI.clientApi().isMinimapComponentEnabled(component); + } + + private void setComponentEnabled(MinimapInfoComponent component, boolean enabled) { + FTBChunksAPI.clientApi().setMinimapComponentEnabled(component, enabled); + } + + private boolean isTranslatedOptionEnabled(MinimapInfoComponent component, TranslatedOption option) { + Map stringStringMap = FTBChunksClientConfig.MINIMAP_SETTINGS.get(); + if (!stringStringMap.containsKey(component.id().toString())) { + stringStringMap.put(component.id().toString(), option.optionName()); + } + return stringStringMap.get(component.id().toString()).equals(option.optionName()); + } + + private void setTranslatedOptionEnabled(MinimapInfoComponent component, TranslatedOption option) { + Map stringStringMap = FTBChunksClientConfig.MINIMAP_SETTINGS.get(); + stringStringMap.put(component.id().toString(), option.optionName()); + FTBChunksClientConfig.MINIMAP_SETTINGS.set(stringStringMap); + FTBChunksClientConfig.saveConfig(); + } + +} diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/client/gui/PointerIcon.java b/common/src/main/java/dev/ftb/mods/ftbchunks/client/gui/PointerIcon.java new file mode 100644 index 00000000..37c89e14 --- /dev/null +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/client/gui/PointerIcon.java @@ -0,0 +1,46 @@ +package dev.ftb.mods.ftbchunks.client.gui; + +import com.mojang.math.Axis; +import dev.ftb.mods.ftbchunks.api.FTBChunksAPI; +import dev.ftb.mods.ftbchunks.api.client.icon.MapIcon; +import dev.ftb.mods.ftbchunks.api.client.icon.MapType; +import dev.ftb.mods.ftblibrary.icon.Icon; +import dev.ftb.mods.ftblibrary.ui.BaseScreen; +import dev.ftb.mods.ftblibrary.ui.input.Key; +import dev.ftb.mods.ftblibrary.ui.input.MouseButton; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.phys.Vec3; + +public class PointerIcon implements MapIcon { + + private static final Icon POINTER = Icon.getIcon(FTBChunksAPI.rl("textures/player.png")); + + @Override + public Vec3 getPos(float partialTick) { + Player player = Minecraft.getInstance().player; + return partialTick >= 1F ? player.position() : player.getPosition(partialTick); + } + + @Override + public boolean onMousePressed(BaseScreen screen, MouseButton button) { + return false; + } + + @Override + public boolean onKeyPressed(BaseScreen screen, Key key) { + return false; + } + + @Override + public void draw(MapType mapType, GuiGraphics graphics, int x, int y, int w, int h, boolean outsideVisibleArea, int iconAlpha) { + Player player = Minecraft.getInstance().player; + graphics.pose().pushPose(); + graphics.pose().translate(x + w / 2f, y + h / 2f, 0F); + graphics.pose().scale(2f, 2f, 2f); + graphics.pose().mulPose(Axis.ZP.rotationDegrees(player.getYRot() + 180F)); + POINTER.draw(graphics, - w / 2, -h / 2, w, h); + graphics.pose().popPose(); + } +} diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/client/gui/ToggleVisibilityButton.java b/common/src/main/java/dev/ftb/mods/ftbchunks/client/gui/ToggleVisibilityButton.java new file mode 100644 index 00000000..7a3e9571 --- /dev/null +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/client/gui/ToggleVisibilityButton.java @@ -0,0 +1,47 @@ +package dev.ftb.mods.ftbchunks.client.gui; + +import dev.ftb.mods.ftblibrary.icon.Icons; +import dev.ftb.mods.ftblibrary.ui.Panel; +import dev.ftb.mods.ftblibrary.ui.SimpleButton; +import dev.ftb.mods.ftblibrary.ui.Theme; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.network.chat.Component; + +import java.util.function.Consumer; + +public class ToggleVisibilityButton extends SimpleButton { + + private static final Component TOGGLE_ON = Component.translatable("ftbchunks.gui.toggle_visibility_on"); + private static final Component TOGGLE_OFF = Component.translatable("ftbchunks.gui.toggle_visibility_off"); + + private boolean visible; + + private ToggleVisibilityButton(Panel panel, boolean defaultState, Callback c) { + super(panel, Component.empty(), defaultState ? Icons.ACCEPT : Icons.REMOVE_GRAY, c); + visible = defaultState; + } + + public static ToggleVisibilityButton create(Panel panel, boolean defaultState, Consumer newState) { + return new ToggleVisibilityButton(panel, defaultState, (widget, button) -> { + ToggleVisibilityButton visibilityButton = (ToggleVisibilityButton) widget; + visibilityButton.visible = !visibilityButton.visible; + widget.setIcon(visibilityButton.visible ? Icons.ACCEPT : Icons.REMOVE_GRAY); + newState.accept(visibilityButton.visible); + }); + } + + public boolean isVisible() { + return visible; + } + + @Override + public Component getTitle() { + return visible ? TOGGLE_ON : TOGGLE_OFF; + } + + + @Override + public void drawIcon(GuiGraphics graphics, Theme theme, int x, int y, int w, int h) { + super.drawIcon(graphics, theme, x, y, width, height); + } +} diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/client/gui/WaypointEditorScreen.java b/common/src/main/java/dev/ftb/mods/ftbchunks/client/gui/WaypointEditorScreen.java index 41c09735..a4780b3a 100644 --- a/common/src/main/java/dev/ftb/mods/ftbchunks/client/gui/WaypointEditorScreen.java +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/client/gui/WaypointEditorScreen.java @@ -1,6 +1,5 @@ package dev.ftb.mods.ftbchunks.client.gui; -import com.mojang.blaze3d.systems.RenderSystem; import dev.ftb.mods.ftbchunks.client.map.MapManager; import dev.ftb.mods.ftbchunks.client.map.WaypointImpl; import dev.ftb.mods.ftbchunks.net.TeleportFromMapPacket; @@ -9,216 +8,165 @@ import dev.ftb.mods.ftblibrary.icon.Color4I; import dev.ftb.mods.ftblibrary.icon.Icon; import dev.ftb.mods.ftblibrary.icon.Icons; -import dev.ftb.mods.ftblibrary.icon.ImageIcon; -import dev.ftb.mods.ftblibrary.ui.Button; -import dev.ftb.mods.ftblibrary.ui.Panel; -import dev.ftb.mods.ftblibrary.ui.TextField; +import dev.ftb.mods.ftblibrary.icon.ItemIcon; import dev.ftb.mods.ftblibrary.ui.*; import dev.ftb.mods.ftblibrary.ui.input.Key; import dev.ftb.mods.ftblibrary.ui.input.MouseButton; +import dev.ftb.mods.ftblibrary.ui.misc.AbstractButtonListScreen; +import dev.ftb.mods.ftblibrary.util.TextComponentUtils; import dev.ftb.mods.ftblibrary.util.TooltipList; +import dev.ftb.mods.ftblibrary.util.client.ClientTextComponentUtils; import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.BlockPos; +import net.minecraft.commands.Commands; import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.HoverEvent; import net.minecraft.network.chat.Style; +import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.Level; +import org.lwjgl.glfw.GLFW; -import java.awt.*; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import java.util.Objects; +import java.util.*; -public class WaypointEditorScreen extends BaseScreen { - public static final Color4I COLOR_BACKGROUND = Color4I.rgba(0x99333333); - private static final Icon PEARL_ICON = ImageIcon.getIcon(new ResourceLocation("minecraft", "textures/item/ender_pearl.png")); +import static dev.ftb.mods.ftblibrary.util.TextComponentUtils.hotkeyTooltip; - public static final Theme THEME = new Theme() { - @Override - public void drawScrollBarBackground(GuiGraphics graphics, int x, int y, int w, int h, WidgetType type) { - Color4I.BLACK.withAlpha(70).draw(graphics, x, y, w, h); - } - - @Override - public void drawScrollBar(GuiGraphics graphics, int x, int y, int w, int h, WidgetType type, boolean vertical) { - getContentColor(WidgetType.NORMAL).withAlpha(100).withBorder(Color4I.GRAY.withAlpha(100), false).draw(graphics, x, y, w, h); - } - }; - - private static final Component TITLE = Component.translatable("ftbchunks.gui.waypoints").withStyle(ChatFormatting.BOLD); - - private final Panel waypointPanel; - private final PanelScrollBar scrollbar; - private final List rows; +public class WaypointEditorScreen extends AbstractButtonListScreen { + private final Map, Boolean> collapsed = new HashMap<>(); + private final Map, List> waypoints = new HashMap<>(); private final Button buttonCollapseAll, buttonExpandAll; - private int maxWidth; public WaypointEditorScreen() { - waypointPanel = new WaypointPanel(this); - scrollbar = new PanelScrollBar(this, waypointPanel) { - @Override - public void drawBackground(GuiGraphics graphics, Theme theme, int x, int y, int w, int h) { - if (getMaxValue() > parent.height) { - super.drawBackground(graphics, theme, x, y, w, h); - } - } - }; - rows = new ArrayList<>(); - - buttonCollapseAll = new ExpanderButton(this, false); - buttonExpandAll = new ExpanderButton(this, true); + showBottomPanel(false); + showCloseButton(true); - for (DimWayPoints entry : collectWaypoints()) { - rows.add(new VerticalSpaceWidget(waypointPanel,4)); - - boolean thisDimension = Minecraft.getInstance().level.dimension().location().equals(entry.levelKey); - GroupButton groupButton = new GroupButton(waypointPanel, Component.literal(entry.levelKey.toString()).withStyle(ChatFormatting.YELLOW), !thisDimension); - rows.add(groupButton); - - for (WaypointImpl wp : entry.waypoints) { - rows.add(new RowPanel(waypointPanel, groupButton, wp)); - } + for (Map.Entry, List> resourceKeyListEntry : collectWaypoints().entrySet()) { + collapsed.put(resourceKeyListEntry.getKey(), false); + waypoints.put(resourceKeyListEntry.getKey(), new ArrayList<>(resourceKeyListEntry.getValue())); } - } - - private List collectWaypoints() { - List res = new ArrayList<>(); - - Player player = Objects.requireNonNull(Minecraft.getInstance().player); - MapManager manager = MapManager.getInstance().orElseThrow(); - manager.getDimensions().values().stream() - .filter(dim -> !dim.getWaypointManager().isEmpty()) - .sorted((dim1, dim2) -> { - // put vanilla dimensions first - ResourceLocation dim1id = dim1.dimension.location(); - ResourceLocation dim2id = dim2.dimension.location(); - if (dim1id.getNamespace().equals("minecraft") && !dim2id.getNamespace().equals("minecraft")) { - return -1; - } - int i = dim1id.getNamespace().compareTo(dim2id.getNamespace()); - return i == 0 ? dim1id.getPath().compareTo(dim2id.getPath()) : i; - }) - .forEach(dim -> res.add(new DimWayPoints(dim.dimension.location(), dim.getWaypointManager().stream() - .sorted(Comparator.comparingDouble(wp -> wp.getDistanceSq(player))) - .toList())) - ); - return res; + buttonExpandAll = new SimpleButton(topPanel, List.of(Component.translatable("gui.expand_all"), hotkeyTooltip("="), hotkeyTooltip("+")), Icons.UP, + (widget, button) -> toggleAll(false)); + buttonCollapseAll = new SimpleButton(topPanel, List.of(Component.translatable("gui.collapse_all"), hotkeyTooltip("-")), Icons.DOWN, + (widget, button) -> toggleAll(true)); } - @Override - public boolean onInit() { - boolean r = setFullscreen(); - maxWidth = Math.min(maxWidth, getGui().width / 2); - return r; + private void toggleAll(boolean collapsed) { + this.collapsed.keySet().forEach(levelResourceKey -> this.collapsed.put(levelResourceKey, collapsed)); + scrollBar.setValue(0); + getGui().refreshWidgets(); } @Override - public void addWidgets() { - add(waypointPanel); - add(scrollbar); - - add(buttonCollapseAll); - add(buttonExpandAll); + protected void doCancel() { } @Override - public void alignWidgets() { - waypointPanel.setPosAndSize(0, 20, width, height - 20); - waypointPanel.alignWidgets(); - scrollbar.setPosAndSize(width - 16, 20, 16, height - 20); - buttonExpandAll.setPos(width - 18, 2); - buttonCollapseAll.setPos(width - 38, 2); + protected void doAccept() { } @Override - public Theme getTheme() { - return super.getTheme(); + public boolean onInit() { + setWidth(220); + setHeight(getScreen().getGuiScaledHeight() * 4 / 5); + return true; } @Override - public Component getTitle() { - return TITLE; + protected int getTopPanelHeight() { + return 22; } @Override - public void drawBackground(GuiGraphics graphics, Theme theme, int x, int y, int w, int h) { - COLOR_BACKGROUND.draw(graphics, 0, 0, w, 20); - theme.drawString(graphics, getTitle(), 6, 6, Theme.SHADOW); + protected Panel createTopPanel() { + return new CustomTopPanel(); } @Override - public boolean keyPressed(Key key) { - if (key.esc() && getContextMenu().isPresent()) { - closeContextMenu(); - return true; - } - return super.keyPressed(key); + public void addButtons(Panel panel) { + waypoints.forEach((key, value) -> { + boolean startCollapsed = collapsed.get(key); + GroupButton groupButton = new GroupButton(panel, key, startCollapsed, value); + panel.add(groupButton); + if (!startCollapsed) { + panel.addAll(groupButton.collectPanels()); + } + }); } - private class WaypointPanel extends Panel { - public WaypointPanel(Panel panel) { - super(panel); - } + protected class CustomTopPanel extends TopPanel { + private final TextField titleLabel = new TextField(this); @Override public void addWidgets() { - maxWidth = 0; - for (var row : rows) { - if (!(row instanceof RowPanel rowPanel) || !rowPanel.groupButton.collapsed && !rowPanel.deleted) { - add(row); - if (row instanceof RowPanel rp) maxWidth = Math.max(maxWidth, getTheme().getStringWidth(rp.wp.getName())); - } + titleLabel.setText(Component.translatable("ftbchunks.gui.waypoints")); + titleLabel.addFlags(Theme.CENTERED_V); + add(titleLabel); + + if (waypoints.size() > 1) { + add(buttonExpandAll); + add(buttonCollapseAll); } - maxWidth = Math.min(maxWidth, getGui().width / 2); } @Override public void alignWidgets() { - align(WidgetLayout.VERTICAL); - int sbWidth = scrollbar.getMaxValue() > 0 ? 16 : 0; - scrollbar.setWidth(sbWidth); - widgets.forEach(w -> { - int prevWidth = w.width; - w.setWidth(width - sbWidth); - if (w.width != prevWidth && w instanceof Panel p) p.alignWidgets(); - }); + titleLabel.setPosAndSize(4, 0, titleLabel.width, height); + if (waypoints.size() > 1) { + buttonExpandAll.setPos(width - 18, 2); + buttonCollapseAll.setPos(width - 38, 2); + } } } - private static class GroupButton extends Button { - private boolean collapsed; + private class GroupButton extends Button { private final Component titleText; + private final List rowPanels; + private final ResourceKey dim; - public GroupButton(Panel panel, Component titleText, boolean startCollapsed) { + public GroupButton(Panel panel, ResourceKey dim, boolean startCollapsed, List waypoints) { super(panel); - this.titleText = titleText; + + this.dim = dim; + this.titleText = TextComponentUtils.translatedDimension(dim).copy() + .withStyle(style -> style.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.literal(dim.location().toString())))); setCollapsed(startCollapsed); + this.rowPanels = new ArrayList<>(); + for (WaypointImpl waypoint : waypoints) { + rowPanels.add(new RowPanel(panel, waypoint)); + } + } + + public List collectPanels() { + return isCollapsed() ? List.of() : List.copyOf(rowPanels); } @Override public void onClicked(MouseButton button) { - setCollapsed(!collapsed); - getGui().refreshWidgets(); + setCollapsed(!isCollapsed()); + parent.refreshWidgets(); + refreshWidgets(); + playClickSound(); + } + + public boolean isCollapsed() { + return collapsed.get(dim); } - void setCollapsed(boolean collapsed) { - this.collapsed = collapsed; - setTitle(Component.literal(collapsed ? "[>] " : "[v] ").withStyle(collapsed ? ChatFormatting.RED : ChatFormatting.GREEN).append(titleText)); + public void setCollapsed(boolean collapsed) { + WaypointEditorScreen.this.collapsed.put(dim, collapsed); + boolean isCollapsed = isCollapsed(); + setTitle(Component.literal(isCollapsed ? "▶ " : "▼ ").withStyle(isCollapsed ? ChatFormatting.RED : ChatFormatting.GREEN).append(titleText)); } @Override public void draw(GuiGraphics graphics, Theme theme, int x, int y, int w, int h) { - COLOR_BACKGROUND.draw(graphics, x, y, w, h); - theme.drawString(graphics, getTitle(), x + 3, y + 1 + (h - theme.getFontHeight()) / 2); - RenderSystem.setShaderColor(1F, 1F, 1F, 1F); - - Color4I.GRAY.withAlpha(80).draw(graphics, 0, y, width, 1); - Color4I.GRAY.withAlpha(80).draw(graphics, 0, y, 1, height); + theme.drawWidget(graphics, x, y, w, h, getWidgetType()); + theme.drawString(graphics, getTitle(), x + 3, y + 3); if (isMouseOver()) { Color4I.WHITE.withAlpha(33).draw(graphics, x, y, w, h); } @@ -226,43 +174,71 @@ public void draw(GuiGraphics graphics, Theme theme, int x, int y, int w, int h) @Override public void addMouseOverText(TooltipList list) { + list.add(Component.literal(dim.location().toString())); } } private class RowPanel extends Panel { - private final GroupButton groupButton; + private static final Component DELETE = Component.translatable("ftbchunks.gui.delete"); + private static final Component QUICK_DELETE = Component.translatable("ftbchunks.gui.quick_delete"); + private final WaypointImpl wp; - private boolean deleted = false; + private TextField nameField; + private TextField distField; + private SimpleButton hideButton; + private SimpleButton deleteButton; - public RowPanel(Panel panel, GroupButton groupButton, WaypointImpl wp) { + public RowPanel(Panel panel, WaypointImpl wp) { super(panel); - this.groupButton = groupButton; + this.wp = wp; setHeight(18); } @Override public void addWidgets() { - add(new SimpleButton(this, Component.empty(), wp.isHidden() ? Icons.REMOVE_GRAY : Icons.ACCEPT, (w, mb) -> { - wp.setHidden(!wp.isHidden()); - w.setIcon(wp.isHidden() ? Icons.REMOVE_GRAY : Icons.ACCEPT); - })); + add(hideButton = ToggleVisibilityButton.create(this, !wp.isHidden(), hidden -> wp.setHidden(!hidden))); - add(new TextField(this).setMaxWidth(maxWidth).setTrim().setText(wp.getName()).setColor(Color4I.rgb(wp.getColor())).addFlags(Theme.SHADOW)); + add(nameField = new TextField(this).setTrim().setColor(Color4I.rgb(wp.getColor())).addFlags(Theme.SHADOW)); LocalPlayer player = Minecraft.getInstance().player; String distStr = player.level().dimension().equals(wp.getDimension()) ? String.format("%.1fm", Math.sqrt(wp.getDistanceSq(player))) : ""; - add(new TextField(this).setText(distStr).setColor(Color4I.GRAY)); + add(distField = new TextField(this).setText(distStr).setColor(Color4I.WHITE)); + add(deleteButton = new SimpleButton(this, DELETE, Icons.BIN, (w, mb) -> deleteWaypoint(!isShiftKeyDown())) { + @Override + public Component getTitle() { + return isShiftKeyDown() ? QUICK_DELETE : DELETE; + } + + @Override + public void drawIcon(GuiGraphics graphics, Theme theme, int x, int y, int w, int h) { + super.drawIcon(graphics, theme, x, y, 12, 12); + } + }); } @Override public void alignWidgets() { - if (widgets.size() == 3) { + } + + @Override + public void setWidth(int newWidth) { + super.setWidth(newWidth); + + if (newWidth > 0) { + int farRight = newWidth - 8; + int yOff = (this.height - getTheme().getFontHeight()) / 2 + 1; - widgets.get(0).setPos(10, 1); - widgets.get(1).setPos(30, yOff); - widgets.get(2).setPos(maxWidth + 40, yOff); + + hideButton.setPosAndSize(farRight - 8 - 16, 1, 12, 12); + deleteButton.setPosAndSize(farRight - 8, 1, 12, 12); + + distField.setPos(hideButton.getPosX() - 5 - distField.width, yOff); + + nameField.setPos(5, yOff); + nameField.setText(ClientTextComponentUtils.ellipsize(getTheme().getFont(), Component.literal(wp.getName()),distField.getPosX() - 5).getString()); + nameField.setHeight(getTheme().getFontHeight() + 2); } } @@ -284,6 +260,8 @@ public boolean mousePressed(MouseButton button) { list.add(makeTitleMenuItem()); list.add(ContextMenuItem.SEPARATOR); + WaypointShareMenu.makeShareMenu(Minecraft.getInstance().player, wp).ifPresent(list::add); + list.add(new ContextMenuItem(Component.translatable("gui.rename"), Icons.CHAT, btn -> { StringConfig config = new StringConfig(); config.setDefaultValue(""); @@ -310,29 +288,45 @@ public boolean mousePressed(MouseButton button) { }); })); } - if (Minecraft.getInstance().player.hasPermissions(2)) { // permissions are checked again on server! - list.add(new ContextMenuItem(Component.translatable("ftbchunks.gui.teleport"), PEARL_ICON, btn -> { - BlockPos pos = wp.getPos().above(); - new TeleportFromMapPacket(pos, false, wp.getDimension()).sendToServer(); + if (Minecraft.getInstance().player.hasPermissions(Commands.LEVEL_GAMEMASTERS)) { // permissions are checked again on server! + list.add(new ContextMenuItem(Component.translatable("ftbchunks.gui.teleport"), ItemIcon.getItemIcon(Items.ENDER_PEARL), btn -> { + new TeleportFromMapPacket(wp.getPos().above(), false, wp.getDimension()).sendToServer(); closeGui(false); })); } - list.add(new ContextMenuItem(Component.translatable("gui.remove"), Icons.REMOVE, btn -> { - getGui().openYesNo(Component.translatable("ftbchunks.gui.delete_waypoint", Component.literal(wp.getName()) - .withStyle(Style.EMPTY.withColor(wp.getColor()))), Component.empty(), () -> { - wp.removeFromManager(); - deleted = true; - getGui().refreshWidgets(); - }); - }) - ); + list.add(new ContextMenuItem(Component.translatable("gui.remove"), Icons.REMOVE, btn -> deleteWaypoint(true))); getGui().openContextMenu(list); return true; } return super.mousePressed(button); } - + + @Override + public boolean keyPressed(Key key) { + if (key.is(GLFW.GLFW_KEY_DELETE)) { + deleteWaypoint(!isShiftKeyDown()); + return true; + } else { + return super.keyPressed(key); + } + } + + private void deleteWaypoint(boolean gui) { + if (gui) { + getGui().openYesNo(Component.translatable("ftbchunks.gui.delete_waypoint", Component.literal(wp.getName()) + .withStyle(Style.EMPTY.withColor(wp.getColor()))), Component.empty(), () -> { + wp.removeFromManager(); + WaypointEditorScreen.this.waypoints.get(wp.getDimension()).remove(wp); + getGui().refreshWidgets(); + }); + } else { + wp.removeFromManager(); + WaypointEditorScreen.this.waypoints.get(wp.getDimension()).remove(wp); + getGui().refreshWidgets(); + } + } + private ContextMenuItem makeTitleMenuItem() { return new ContextMenuItem(Component.literal(wp.getName()), Icon.empty(), null) { @Override @@ -343,16 +337,28 @@ public Icon getIcon() { } } - private class ExpanderButton extends SimpleButton { - public ExpanderButton(Panel panel, boolean expand) { - super(panel, Component.translatable(expand ? "gui.expand_all" : "gui.collapse_all"), expand ? Icons.DOWN : Icons.UP, (btn, mb) -> { - rows.stream().filter(w -> w instanceof GroupButton).map(w -> (GroupButton) w).forEach(g -> g.setCollapsed(!expand)); - scrollbar.setValue(0); - btn.getGui().refreshWidgets(); - }); - } - } + private static Map, List> collectWaypoints() { + Map, List> res = new HashMap<>(); - private record DimWayPoints(ResourceLocation levelKey, List waypoints) { + Player player = Objects.requireNonNull(Minecraft.getInstance().player); + MapManager manager = MapManager.getInstance().orElseThrow(); + manager.getDimensions().values().stream() + .filter(dim -> !dim.getWaypointManager().isEmpty()) + .sorted((dim1, dim2) -> { + // put vanilla dimensions first + ResourceLocation dim1id = dim1.dimension.location(); + ResourceLocation dim2id = dim2.dimension.location(); + if (dim1id.getNamespace().equals("minecraft") && !dim2id.getNamespace().equals("minecraft")) { + return -1; + } + int i = dim1id.getNamespace().compareTo(dim2id.getNamespace()); + return i == 0 ? dim1id.getPath().compareTo(dim2id.getPath()) : i; + }) + .forEach(dim -> res.put(dim.dimension, dim.getWaypointManager().stream() + .sorted(Comparator.comparingDouble(wp -> wp.getDistanceSq(player))) + .toList()) + ); + + return res; } } diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/client/gui/WaypointShareMenu.java b/common/src/main/java/dev/ftb/mods/ftbchunks/client/gui/WaypointShareMenu.java new file mode 100644 index 00000000..c16008d4 --- /dev/null +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/client/gui/WaypointShareMenu.java @@ -0,0 +1,94 @@ +package dev.ftb.mods.ftbchunks.client.gui; + +import com.mojang.authlib.GameProfile; +import dev.ftb.mods.ftbchunks.FTBChunksWorldConfig; +import dev.ftb.mods.ftbchunks.api.client.waypoint.Waypoint; +import dev.ftb.mods.ftbchunks.net.ShareWaypointPacket; +import dev.ftb.mods.ftblibrary.icon.FaceIcon; +import dev.ftb.mods.ftblibrary.icon.Icons; +import dev.ftb.mods.ftblibrary.ui.ContextMenuItem; +import dev.ftb.mods.ftblibrary.ui.NordButton; +import dev.ftb.mods.ftblibrary.ui.Panel; +import dev.ftb.mods.ftblibrary.ui.input.MouseButton; +import dev.ftb.mods.ftblibrary.ui.misc.AbstractButtonListScreen; +import dev.ftb.mods.ftblibrary.ui.misc.SimpleToast; +import dev.ftb.mods.ftbteams.api.FTBTeamsAPI; +import dev.ftb.mods.ftbteams.api.client.KnownClientPlayer; +import net.minecraft.ChatFormatting; +import net.minecraft.core.GlobalPos; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Player; + +import java.util.*; + +public class WaypointShareMenu { + public static Optional makeShareMenu(Player sharingPlayer, Waypoint waypoint) { + List items = new ArrayList<>(); + + if (FTBChunksWorldConfig.WAYPOINT_SHARING_SERVER.get()) { + items.add(new ContextMenuItem(Component.translatable("ftbchunks.waypoint.share.server"), Icons.BEACON, + b -> shareWaypoint(waypoint, ShareWaypointPacket.ShareType.SERVER, List.of()))); + } + if (FTBChunksWorldConfig.WAYPOINT_SHARING_PARTY.get()) { + items.add(new ContextMenuItem(Component.translatable("ftbchunks.waypoint.share.party"), Icons.BELL, + b -> shareWaypoint(waypoint, ShareWaypointPacket.ShareType.PARTY, List.of()))); + } + if (FTBChunksWorldConfig.WAYPOINT_SHARING_PLAYERS.get()) { + items.add(new ContextMenuItem(Component.translatable("ftbchunks.waypoint.share.player"), Icons.PLAYER, b -> { + Collection knownClientPlayers = FTBTeamsAPI.api().getClientManager().knownClientPlayers(); + List list = knownClientPlayers.stream() + .filter(KnownClientPlayer::online) + .filter(p -> !p.id().equals(sharingPlayer.getGameProfile().getId())) + .map(KnownClientPlayer::profile).toList(); + List selectedProfiles = new ArrayList<>(); + new AbstractButtonListScreen() { + @Override + protected void doCancel() { + closeGui(); + } + + @Override + protected void doAccept() { + List toShare = selectedProfiles.stream().map(GameProfile::getId).toList(); + if (!toShare.isEmpty()) { + shareWaypoint(waypoint, ShareWaypointPacket.ShareType.PLAYER, toShare); + } + closeGui(); + } + + @Override + public void addButtons(Panel panel) { + for (GameProfile gameProfile : list) { + Component unchecked = (Component.literal("☐ ")).append(gameProfile.getName()); + Component checked = (Component.literal("☑ ").withStyle(ChatFormatting.GREEN)).append(gameProfile.getName()); + NordButton widget = new NordButton(panel, unchecked, FaceIcon.getFace(gameProfile)) { + @Override + public void onClicked(MouseButton button) { + if (selectedProfiles.contains(gameProfile)) { + selectedProfiles.remove(gameProfile); + title = unchecked; + } else { + selectedProfiles.add(gameProfile); + title = checked; + } + playClickSound(); + } + }; + panel.add(widget); + } + } + }.openGui(); + })); + } + + return items.isEmpty() ? + Optional.empty() : + Optional.of(ContextMenuItem.subMenu(Component.translatable("ftbchunks.waypoint.share"), Icons.INFO, items)); + } + + private static void shareWaypoint(Waypoint waypoint, ShareWaypointPacket.ShareType type, List targets) { + GlobalPos waypointPos = GlobalPos.of(waypoint.getDimension(), waypoint.getPos()); + new ShareWaypointPacket(waypoint.getName(), waypointPos, type, targets).sendToServer(); + SimpleToast.info(Component.translatable("ftbchunks.waypoint.shared_by_you", waypoint.getName()), Component.empty()); + } +} diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/client/map/MapMode.java b/common/src/main/java/dev/ftb/mods/ftbchunks/client/map/MapMode.java index dd619de0..c10fb150 100644 --- a/common/src/main/java/dev/ftb/mods/ftbchunks/client/map/MapMode.java +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/client/map/MapMode.java @@ -9,5 +9,6 @@ public enum MapMode { BLOCKS, LIGHT_SOURCES; - public static final NameMap NAME_MAP = NameMap.of(NONE, values()).create(); + public static final NameMap NAME_MAP = NameMap.of(NONE, values()).baseNameKey("ftbchunks.map_mode").create(); + } diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/client/map/MapRegion.java b/common/src/main/java/dev/ftb/mods/ftbchunks/client/map/MapRegion.java index 392704c3..44eb6a9b 100644 --- a/common/src/main/java/dev/ftb/mods/ftbchunks/client/map/MapRegion.java +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/client/map/MapRegion.java @@ -202,13 +202,13 @@ public void runMapTask() throws Exception { public void setRenderedMapImageRGBA(int x, int z, int col) { synchronized (dimension.getManager().lock) { - renderedMapImage.setPixelRGBA(x, z, col); + getRenderedMapImage().setPixelRGBA(x, z, col); } } private void uploadRenderedMapImage() { synchronized (dimension.getManager().lock) { - renderedMapImage.upload(0, 0, 0, false); + getRenderedMapImage().upload(0, 0, 0, false); } } diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/client/mapicon/WaypointMapIcon.java b/common/src/main/java/dev/ftb/mods/ftbchunks/client/mapicon/WaypointMapIcon.java index 865f25c3..4574166b 100644 --- a/common/src/main/java/dev/ftb/mods/ftbchunks/client/mapicon/WaypointMapIcon.java +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/client/mapicon/WaypointMapIcon.java @@ -4,28 +4,28 @@ import dev.ftb.mods.ftbchunks.api.client.icon.MapType; import dev.ftb.mods.ftbchunks.api.client.icon.WaypointIcon; import dev.ftb.mods.ftbchunks.client.gui.LargeMapScreen; +import dev.ftb.mods.ftbchunks.client.gui.WaypointShareMenu; import dev.ftb.mods.ftbchunks.client.map.WaypointImpl; +import dev.ftb.mods.ftbchunks.net.TeleportFromMapPacket; import dev.ftb.mods.ftblibrary.config.ColorConfig; import dev.ftb.mods.ftblibrary.config.StringConfig; -import dev.ftb.mods.ftblibrary.icon.Color4I; -import dev.ftb.mods.ftblibrary.icon.Icon; -import dev.ftb.mods.ftblibrary.icon.Icons; -import dev.ftb.mods.ftblibrary.icon.ImageIcon; +import dev.ftb.mods.ftblibrary.icon.*; import dev.ftb.mods.ftblibrary.math.MathUtils; import dev.ftb.mods.ftblibrary.ui.BaseScreen; import dev.ftb.mods.ftblibrary.ui.ColorSelectorPanel; import dev.ftb.mods.ftblibrary.ui.ContextMenuItem; -import dev.ftb.mods.ftblibrary.ui.Widget; import dev.ftb.mods.ftblibrary.ui.input.Key; import dev.ftb.mods.ftblibrary.ui.input.MouseButton; import dev.ftb.mods.ftblibrary.util.TooltipList; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.commands.Commands; import net.minecraft.network.chat.Component; import net.minecraft.util.Mth; +import net.minecraft.world.item.Items; import org.lwjgl.glfw.GLFW; -import java.awt.*; import java.util.ArrayList; import java.util.List; @@ -98,6 +98,10 @@ private void openWPContextMenu(LargeMapScreen screen) { contextMenu.add(makeTitleMenuItem()); contextMenu.add(ContextMenuItem.SEPARATOR); + LocalPlayer player = Minecraft.getInstance().player; + + WaypointShareMenu.makeShareMenu(player, waypoint).ifPresent(contextMenu::add); + contextMenu.add(new ContextMenuItem(Component.translatable("gui.rename"), Icons.CHAT, b -> { StringConfig config = new StringConfig(); config.setValue(waypoint.getName()); @@ -129,6 +133,13 @@ private void openWPContextMenu(LargeMapScreen screen) { screen.refreshWidgets(); })); + if (player.hasPermissions(Commands.LEVEL_GAMEMASTERS)) { + contextMenu.add(new ContextMenuItem(Component.translatable("ftbchunks.gui.teleport"), ItemIcon.getItemIcon(Items.ENDER_PEARL), b -> { + new TeleportFromMapPacket(waypoint.getPos().above(), false, waypoint.getDimension()).sendToServer(); + screen.closeGui(false); + })); + } + contextMenu.add(new ContextMenuItem(Component.translatable("gui.remove"), Icons.REMOVE, b -> { waypoint.removeFromManager(); screen.refreshIcons(); diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/client/minimap/components/BiomeComponent.java b/common/src/main/java/dev/ftb/mods/ftbchunks/client/minimap/components/BiomeComponent.java new file mode 100644 index 00000000..9bd452a9 --- /dev/null +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/client/minimap/components/BiomeComponent.java @@ -0,0 +1,40 @@ +package dev.ftb.mods.ftbchunks.client.minimap.components; + +import dev.ftb.mods.ftbchunks.api.FTBChunksAPI; +import dev.ftb.mods.ftbchunks.api.client.minimap.MinimapContext; +import dev.ftb.mods.ftbchunks.api.client.minimap.MinimapInfoComponent; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.core.Holder; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.biome.Biome; + +public class BiomeComponent implements MinimapInfoComponent { + + public static final ResourceLocation ID = FTBChunksAPI.rl("biome"); + + private ResourceKey biomeKey; + + @Override + public ResourceLocation id() { + return ID; + } + + @Override + public void render(MinimapContext context, GuiGraphics graphics, Font font) { + drawCenteredText(context.minecraft().font, graphics, Component.translatable("biome." + biomeKey.location().getNamespace() + "." + biomeKey.location().getPath()), 0); + } + + @Override + public boolean shouldRender(MinimapContext context) { + Holder biome = context.minecraft().level.getBiome(context.minecraft().player.blockPosition()); + if (biome.unwrapKey().isPresent()) { + biomeKey = biome.unwrapKey().get(); + return true; + } + + return false; + } +} diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/client/minimap/components/DebugComponent.java b/common/src/main/java/dev/ftb/mods/ftbchunks/client/minimap/components/DebugComponent.java new file mode 100644 index 00000000..31f9e57d --- /dev/null +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/client/minimap/components/DebugComponent.java @@ -0,0 +1,59 @@ +package dev.ftb.mods.ftbchunks.client.minimap.components; + +import dev.ftb.mods.ftbchunks.api.FTBChunksAPI; +import dev.ftb.mods.ftbchunks.api.client.minimap.MinimapContext; +import dev.ftb.mods.ftbchunks.api.client.minimap.MinimapInfoComponent; +import dev.ftb.mods.ftbchunks.client.ClientTaskQueue; +import dev.ftb.mods.ftbchunks.client.FTBChunksClient; +import dev.ftb.mods.ftbchunks.client.map.ChunkUpdateTask; +import dev.ftb.mods.ftbchunks.client.map.MapManager; +import dev.ftb.mods.ftblibrary.math.XZ; +import dev.ftb.mods.ftblibrary.util.StringUtils; +import net.minecraft.ChatFormatting; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; + +import java.util.ArrayList; +import java.util.List; + +public class DebugComponent implements MinimapInfoComponent { + + public static final ResourceLocation ID = FTBChunksAPI.rl("debug"); + + public DebugComponent() { + super(); + } + + @Override + public ResourceLocation id() { + return ID; + } + + @Override + public void render(MinimapContext context, GuiGraphics graphics, Font font) { + List components = new ArrayList<>(); + long memory = MapManager.getInstance().map(MapManager::estimateMemoryUsage).orElse(0L); + components.add(Component.literal("TQ: " + ClientTaskQueue.queueSize()).withStyle(ChatFormatting.GRAY)); + components.add(Component.literal("Rgn: " + XZ.of(context.mapChunksPos().x(), context.mapChunksPos().z())).withStyle(ChatFormatting.GRAY)); + components.add(Component.literal("Mem: ~" + StringUtils.formatDouble00(memory / 1024D / 1024D) + " MB").withStyle(ChatFormatting.GRAY)); + components.add(Component.literal("Updates: " + FTBChunksClient.INSTANCE.getRenderedDebugCount()).withStyle(ChatFormatting.GRAY)); + if(ChunkUpdateTask.getDebugLastTime() > 0L) { + components.add(Component.literal(String.format("Last: %,d ns", ChunkUpdateTask.getDebugLastTime())).withStyle(ChatFormatting.GRAY)); + } + + int y = 0; + int lineHeight = computeLineHeight(context.minecraft(), 1) + font.lineHeight + 1; + for (Component component : components) { + drawCenteredText(context.minecraft().font, graphics, component, y); + y += lineHeight; + } + } + + @Override + public int height(MinimapContext context) { + return computeLineHeight(context.minecraft(), 5) + 1; + } + +} diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/client/minimap/components/FPSComponent.java b/common/src/main/java/dev/ftb/mods/ftbchunks/client/minimap/components/FPSComponent.java new file mode 100644 index 00000000..69d578a8 --- /dev/null +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/client/minimap/components/FPSComponent.java @@ -0,0 +1,30 @@ +package dev.ftb.mods.ftbchunks.client.minimap.components; + +import dev.ftb.mods.ftbchunks.api.FTBChunksAPI; +import dev.ftb.mods.ftbchunks.api.client.minimap.MinimapContext; +import dev.ftb.mods.ftbchunks.api.client.minimap.MinimapInfoComponent; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; + +public class FPSComponent implements MinimapInfoComponent { + + public static final ResourceLocation ID = FTBChunksAPI.rl("fps"); + + public FPSComponent() { + super(); + } + + @Override + public ResourceLocation id() { + return ID; + } + + @Override + public void render(MinimapContext context, GuiGraphics graphics, Font font) { + drawCenteredText(context.minecraft().font, graphics, Component.translatable("ftbchunks.fps", Minecraft.getInstance().getFps()), 0); + } + +} diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/client/minimap/components/GameTimeComponent.java b/common/src/main/java/dev/ftb/mods/ftbchunks/client/minimap/components/GameTimeComponent.java new file mode 100644 index 00000000..7ec64856 --- /dev/null +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/client/minimap/components/GameTimeComponent.java @@ -0,0 +1,69 @@ +package dev.ftb.mods.ftbchunks.client.minimap.components; + +import dev.ftb.mods.ftbchunks.api.FTBChunksAPI; +import dev.ftb.mods.ftbchunks.api.client.minimap.MinimapContext; +import dev.ftb.mods.ftbchunks.api.client.minimap.MinimapInfoComponent; +import dev.ftb.mods.ftbchunks.api.client.minimap.TranslatedOption; +import dev.ftb.mods.ftblibrary.config.NameMap; +import dev.ftb.mods.ftblibrary.icon.Icon; +import dev.ftb.mods.ftblibrary.icon.ItemIcon; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Items; + +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; + +public class GameTimeComponent implements MinimapInfoComponent { + + public static final ResourceLocation ID = FTBChunksAPI.rl("game_time"); + private static final Icon CLOCK_ICON = ItemIcon.getItemIcon(Items.CLOCK); + + @Override + public ResourceLocation id() { + return ID; + } + + @Override + public void render(MinimapContext context, GuiGraphics graphics, Font font) { + String setting = context.getSetting(this); + if (setting.equals(ClockedTimeMode.CLOCK.name())) { + CLOCK_ICON.draw(graphics, -8, 0, 16, 16); + return; + } + + Minecraft minecraft = context.minecraft(); + + long time = minecraft.level.getDayTime() % 24000L; + int hours = (int) (time / 1000L); + int minutes = (int) ((time % 1000L) * 60L / 1000L); + drawCenteredText(minecraft.font, graphics, Component.literal(RealTimeComponent.createTimeString(hours + 6, minutes, setting.equals(ClockedTimeMode.TWENTY_FOUR.name()))), 0); + } + + + @Override + public int height(MinimapContext context) { + String setting = context.getSetting(this); + return !setting.equals(ClockedTimeMode.CLOCK.name()) ? MinimapInfoComponent.super.height(context) : 10; + } + + @Override + public Set getConfigComponents() { + return Arrays.stream(ClockedTimeMode.values()) + .map(value -> new TranslatedOption(value.name(), "ftbchunks.time_mode." + ClockedTimeMode.NAME_MAP.getName(value))) + .collect(Collectors.toSet()); + } + + public enum ClockedTimeMode { + TWENTY_FOUR, + TWELVE, + CLOCK; + + public static final NameMap NAME_MAP = NameMap.of(TWENTY_FOUR, values()).baseNameKey("ftbchunks.time_mode").create(); + } + +} diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/client/minimap/components/PlayerPosInfoComponent.java b/common/src/main/java/dev/ftb/mods/ftbchunks/client/minimap/components/PlayerPosInfoComponent.java new file mode 100644 index 00000000..90ad210a --- /dev/null +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/client/minimap/components/PlayerPosInfoComponent.java @@ -0,0 +1,27 @@ +package dev.ftb.mods.ftbchunks.client.minimap.components; + +import dev.ftb.mods.ftbchunks.api.FTBChunksAPI; +import dev.ftb.mods.ftbchunks.api.client.minimap.MinimapContext; +import dev.ftb.mods.ftbchunks.api.client.minimap.MinimapInfoComponent; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; + +public class PlayerPosInfoComponent implements MinimapInfoComponent { + + public static final ResourceLocation ID = FTBChunksAPI.rl("player_pos"); + + @Override + public ResourceLocation id() { + return ID; + } + + @Override + public void render(MinimapContext context, GuiGraphics graphics, Font font) { + var text = Component.literal(Mth.floor(context.playerPos().x()) + " " + Mth.floor(context.playerPos().y()) + " " + Mth.floor(context.playerPos().z())); + drawCenteredText(font, graphics, text, 0); + } + +} diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/client/minimap/components/RealTimeComponent.java b/common/src/main/java/dev/ftb/mods/ftbchunks/client/minimap/components/RealTimeComponent.java new file mode 100644 index 00000000..80434e9e --- /dev/null +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/client/minimap/components/RealTimeComponent.java @@ -0,0 +1,64 @@ +package dev.ftb.mods.ftbchunks.client.minimap.components; + +import dev.ftb.mods.ftbchunks.api.FTBChunksAPI; +import dev.ftb.mods.ftbchunks.api.client.minimap.MinimapContext; +import dev.ftb.mods.ftbchunks.api.client.minimap.MinimapInfoComponent; +import dev.ftb.mods.ftbchunks.api.client.minimap.TranslatedOption; +import dev.ftb.mods.ftblibrary.config.NameMap; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; + +import java.time.LocalDateTime; +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; + +public class RealTimeComponent implements MinimapInfoComponent { + + public static final ResourceLocation ID = FTBChunksAPI.rl("real_time"); + + @Override + public ResourceLocation id() { + return ID; + } + + @Override + public void render(MinimapContext context, GuiGraphics graphics, Font font) { + String setting = context.getSetting(this); + LocalDateTime now = LocalDateTime.now(); + int hours = now.getHour(); + int minutes = now.getMinute(); + drawCenteredText(font, graphics, Component.literal(createTimeString(hours, minutes, setting.equals(TimeMode.TWENTY_FOUR.name()))), 0); + } + + @Override + public Set getConfigComponents() { + return Arrays.stream(TimeMode.values()) + .map(value -> new TranslatedOption(value.name(),"ftbchunks.time_mode." + TimeMode.NAME_MAP.getName(value))) + .collect(Collectors.toSet()); + } + + static String createTimeString(int hours, int minutes, boolean twentyFourHourClock) { + if (twentyFourHourClock) { + return String.format("%02d:%02d", hours, minutes); + } + + String ampm = hours >= 12 ? "PM" : "AM"; + if (hours == 0) { + hours = 12; + } else if (hours > 12) { + hours -= 12; + } + + return String.format("%2d:%02d %s", hours, minutes, ampm); + } + + public enum TimeMode { + TWENTY_FOUR, + TWELVE; + + public static final NameMap NAME_MAP = NameMap.of(TWENTY_FOUR, values()).baseNameKey("ftbchunks.time_mode").create(); + } +} diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/client/minimap/components/ZoneInfoComponent.java b/common/src/main/java/dev/ftb/mods/ftbchunks/client/minimap/components/ZoneInfoComponent.java new file mode 100644 index 00000000..c8191535 --- /dev/null +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/client/minimap/components/ZoneInfoComponent.java @@ -0,0 +1,75 @@ +package dev.ftb.mods.ftbchunks.client.minimap.components; + +import dev.ftb.mods.ftbchunks.api.FTBChunksAPI; +import dev.ftb.mods.ftbchunks.api.client.minimap.MinimapContext; +import dev.ftb.mods.ftbchunks.api.client.minimap.MinimapInfoComponent; +import dev.ftb.mods.ftbchunks.api.client.minimap.TranslatedOption; +import dev.ftb.mods.ftblibrary.config.NameMap; +import dev.ftb.mods.ftblibrary.math.XZ; +import dev.ftb.mods.ftbteams.api.Team; +import net.minecraft.ChatFormatting; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; + +import java.util.Arrays; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +public class ZoneInfoComponent implements MinimapInfoComponent { + public static final ResourceLocation ID = FTBChunksAPI.rl("zone"); + public static final Component WILDNESS = Component.translatable("wilderness").withStyle(s -> s.withColor(ChatFormatting.DARK_GREEN).withItalic(true)); + + private Team team; + + @Override + public ResourceLocation id() { + return ID; + } + + @Override + public void render(MinimapContext context, GuiGraphics graphics, Font font) { + String setting = context.getSetting(this); + + if (team != null) { + drawCenteredText(context.minecraft().font, graphics, team.getColoredName(), 0); + } else if (setting.equals(ShowWilderness.SHOW_WILDERNESS.name())) { + drawCenteredText(context.minecraft().font, graphics, WILDNESS, 0); + } + } + + @Override + public boolean shouldRender(MinimapContext context) { + var data = context.mapDimension().getRegion(XZ.regionFromChunk(context.mapChunksPos().x(), context.mapChunksPos().z())).getData(); + + team = null; + if (data != null) { + Optional foundTeam = data.getChunk(XZ.of(context.mapChunksPos().x(), context.mapChunksPos().z())).getTeam(); + if (foundTeam.isPresent()) { + team = foundTeam.get(); + return true; + } + } + + String setting = context.getSetting(this); + return !setting.isEmpty() && !setting.equals(ShowWilderness.JUST_CLAIMED.name()); + } + + + @Override + public Set getConfigComponents() { + return Arrays.stream(ShowWilderness.values()) + .map(value -> new TranslatedOption(value.name(), "ftbchunks.show_wilderness." + ShowWilderness.NAME_MAP.getName(value))) + .collect(Collectors.toSet()); + } + + public enum ShowWilderness { + JUST_CLAIMED, + SHOW_WILDERNESS; + + public static final NameMap NAME_MAP = NameMap.of(SHOW_WILDERNESS, values()).baseNameKey("ftbchunks.show_wilderness").create(); + } + +} diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/core/mixin/GuiMixin.java b/common/src/main/java/dev/ftb/mods/ftbchunks/core/mixin/GuiMixin.java new file mode 100644 index 00000000..4846bb28 --- /dev/null +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/core/mixin/GuiMixin.java @@ -0,0 +1,23 @@ +package dev.ftb.mods.ftbchunks.core.mixin; + +import dev.ftb.mods.ftbchunks.client.FTBChunksClient; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.GuiGraphics; +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; + +@Mixin(Gui.class) +public abstract class GuiMixin { + @Inject(method = "renderEffects", at = @At("HEAD")) + public void onRenderEffectsEnter(GuiGraphics guiGraphics, CallbackInfo info) { + guiGraphics.pose().pushPose(); + guiGraphics.pose().translate(FTBChunksClient.getVanillaEffectsOffsetX(), 0, 0); + } + + @Inject(method = "renderEffects", at = @At("RETURN")) + public void onRenderEffectsReturn(GuiGraphics guiGraphics, CallbackInfo info) { + guiGraphics.pose().popPose(); + } +} diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/data/AllyMode.java b/common/src/main/java/dev/ftb/mods/ftbchunks/data/AllyMode.java index 67164266..ab96d72f 100644 --- a/common/src/main/java/dev/ftb/mods/ftbchunks/data/AllyMode.java +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/data/AllyMode.java @@ -7,5 +7,5 @@ public enum AllyMode { FORCED_ALL, FORCED_NONE; - public static final NameMap NAME_MAP = NameMap.of(DEFAULT, values()).create(); + public static final NameMap NAME_MAP = NameMap.of(DEFAULT, values()).baseNameKey("ftbchunks.ally_mode").create(); } \ No newline at end of file diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/data/ForceLoadMode.java b/common/src/main/java/dev/ftb/mods/ftbchunks/data/ForceLoadMode.java index 6c2b98a7..4f06688c 100644 --- a/common/src/main/java/dev/ftb/mods/ftbchunks/data/ForceLoadMode.java +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/data/ForceLoadMode.java @@ -7,5 +7,5 @@ public enum ForceLoadMode { ALWAYS, NEVER; - public static final NameMap NAME_MAP = NameMap.of(DEFAULT, values()).create(); + public static final NameMap NAME_MAP = NameMap.of(DEFAULT, values()).baseNameKey("ftbchunks.force_load_mode").create(); } diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/data/PartyLimitMode.java b/common/src/main/java/dev/ftb/mods/ftbchunks/data/PartyLimitMode.java index 94078112..e97e7a76 100644 --- a/common/src/main/java/dev/ftb/mods/ftbchunks/data/PartyLimitMode.java +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/data/PartyLimitMode.java @@ -8,5 +8,5 @@ public enum PartyLimitMode { SUM, AVERAGE; - public static final NameMap NAME_MAP = NameMap.of(LARGEST, values()).create(); + public static final NameMap NAME_MAP = NameMap.of(LARGEST, values()).baseNameKey("ftbchunks.party_limit_mode").create(); } diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/data/PvPMode.java b/common/src/main/java/dev/ftb/mods/ftbchunks/data/PvPMode.java index 71258e85..cf743c9e 100644 --- a/common/src/main/java/dev/ftb/mods/ftbchunks/data/PvPMode.java +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/data/PvPMode.java @@ -8,5 +8,5 @@ public enum PvPMode { PER_TEAM, ; - public static final NameMap NAME_MAP = NameMap.of(ALWAYS, values()).create(); + public static final NameMap NAME_MAP = NameMap.of(ALWAYS, values()).baseNameKey("ftbchunks.pvp_mode").create(); } diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/net/AddWaypointPacket.java b/common/src/main/java/dev/ftb/mods/ftbchunks/net/AddWaypointPacket.java index 147e79a5..4b48d41d 100644 --- a/common/src/main/java/dev/ftb/mods/ftbchunks/net/AddWaypointPacket.java +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/net/AddWaypointPacket.java @@ -4,24 +4,28 @@ import dev.architectury.networking.simple.BaseS2CMessage; import dev.architectury.networking.simple.MessageType; import dev.ftb.mods.ftbchunks.client.FTBChunksClient; -import net.minecraft.core.BlockPos; +import dev.ftb.mods.ftblibrary.config.StringConfig; +import net.minecraft.core.GlobalPos; import net.minecraft.network.FriendlyByteBuf; public class AddWaypointPacket extends BaseS2CMessage { private final String name; - private final BlockPos position; + private final GlobalPos position; private final int color; + private final boolean useGui; - public AddWaypointPacket(String name, BlockPos position, int color) { + public AddWaypointPacket(String name, GlobalPos position, int color, boolean useGui) { this.name = name; this.position = position; this.color = color; + this.useGui = useGui; } public AddWaypointPacket(FriendlyByteBuf buf) { name = buf.readUtf(); - position = buf.readBlockPos(); + position = buf.readGlobalPos(); color = buf.readInt(); + useGui = buf.readBoolean(); } @Override @@ -32,12 +36,21 @@ public MessageType getType() { @Override public void write(FriendlyByteBuf buf) { buf.writeUtf(name); - buf.writeBlockPos(position); + buf.writeGlobalPos(position); buf.writeInt(color); + buf.writeBoolean(useGui); } @Override public void handle(NetworkManager.PacketContext context) { - FTBChunksClient.addWaypoint(context.getPlayer(), name, position, color); + context.queue(() -> { + if(useGui) { + StringConfig configName = new StringConfig(); + configName.setValue(name); + new FTBChunksClient.WaypointAddScreen(configName, position).openGui(); + }else { + FTBChunksClient.addWaypoint(name, position, color); + } + }); } } diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/net/FTBChunksNet.java b/common/src/main/java/dev/ftb/mods/ftbchunks/net/FTBChunksNet.java index 0990fc8b..416edfe5 100644 --- a/common/src/main/java/dev/ftb/mods/ftbchunks/net/FTBChunksNet.java +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/net/FTBChunksNet.java @@ -8,6 +8,7 @@ public interface FTBChunksNet { SimpleNetworkManager MAIN = SimpleNetworkManager.create(FTBChunks.MOD_ID); MessageType REQUEST_MAP_DATA = MAIN.registerC2S("request_map_data", RequestMapDataPacket::new); + MessageType SHARE_WAYPOINT = MAIN.registerC2S("share_waypoint", ShareWaypointPacket::new); MessageType SEND_ALL_CHUNKS = MAIN.registerS2C("send_all_chunks", SendManyChunksPacket::new); MessageType LOGIN_DATA = MAIN.registerS2C("login_data", LoginDataPacket::new); MessageType REQUEST_CHUNK_CHANGE = MAIN.registerC2S("request_chunk_change", RequestChunkChangePacket::new); diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/net/ShareWaypointPacket.java b/common/src/main/java/dev/ftb/mods/ftbchunks/net/ShareWaypointPacket.java new file mode 100644 index 00000000..d93ee7d0 --- /dev/null +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/net/ShareWaypointPacket.java @@ -0,0 +1,103 @@ +package dev.ftb.mods.ftbchunks.net; + +import dev.architectury.networking.NetworkManager; +import dev.architectury.networking.simple.BaseC2SMessage; +import dev.architectury.networking.simple.MessageType; +import dev.ftb.mods.ftbteams.api.FTBTeamsAPI; +import dev.ftb.mods.ftbteams.api.Team; +import net.minecraft.ChatFormatting; +import net.minecraft.core.GlobalPos; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.chat.*; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.players.PlayerList; + +import java.util.*; + +public class ShareWaypointPacket extends BaseC2SMessage { + + private final String name; + private final GlobalPos globalPos; + private final ShareType shareType; + private final List targets; + + public ShareWaypointPacket(String name, GlobalPos globalPos, ShareType shareType, List targets) { + this.name = name; + this.globalPos = globalPos; + this.shareType = shareType; + this.targets = targets; + } + + public ShareWaypointPacket(FriendlyByteBuf buf) { + name = buf.readUtf(); + globalPos = buf.readGlobalPos(); + shareType = buf.readEnum(ShareType.class); + int size = buf.readInt(); + List targets = new ArrayList<>(); + for (int i = 0; i < size; i++) { + targets.add(buf.readUUID()); + } + this.targets = targets; + } + + @Override + public MessageType getType() { + return FTBChunksNet.SHARE_WAYPOINT; + } + + @Override + public void write(FriendlyByteBuf buf) { + buf.writeUtf(name); + buf.writeGlobalPos(globalPos); + buf.writeEnum(shareType); + buf.writeInt(targets.size()); + for (UUID target : targets) { + buf.writeUUID(target); + } + } + + @Override + public void handle(NetworkManager.PacketContext context) { + context.queue(() -> { + ServerPlayer serverPlayer = (ServerPlayer) context.getPlayer(); + PlayerList playerList = serverPlayer.getServer().getPlayerList(); + ChatType.Bound bound2 = ChatType.bind(ChatType.CHAT, serverPlayer).withTargetName(serverPlayer.getDisplayName()); + List playersToSend = switch (shareType) { + case SERVER -> playerList.getPlayers(); + case PARTY -> { + Optional teamForPlayer = FTBTeamsAPI.api().getManager().getTeamForPlayer(serverPlayer); + if (teamForPlayer.isPresent()) { + Team team = teamForPlayer.get(); + yield team.getMembers().stream().map(playerList::getPlayer) + .filter(Objects::nonNull).toList(); + } else { + yield List.of(serverPlayer); + } + } + case PLAYER -> targets.stream().map(playerList::getPlayer) + .filter(Objects::nonNull).toList(); + }; + for (ServerPlayer playerListPlayer : playersToSend) { + String cords = globalPos.pos().getX() + " " + globalPos.pos().getY() + " " + globalPos.pos().getZ(); + + String dim = globalPos.dimension().location().toString(); + Component waypointText = Component.literal(name) + .withStyle(style -> style + .withColor(ChatFormatting.AQUA) + .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.literal(dim + " " + cords)))); + + playerListPlayer.sendChatMessage(OutgoingChatMessage.create(PlayerChatMessage.system("") + .withUnsignedContent(Component.translatable("ftbchunks.waypoint.shared", waypointText) + .withStyle(style -> + style.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/ftbchunks waypoint add-dim " + name + " " + cords + " " + dim + " white true"))))), false, bound2); + } + }); + } + + public enum ShareType { + SERVER, + PARTY, + PLAYER; + + } +} diff --git a/common/src/main/resources/assets/ftbchunks/lang/en_us.json b/common/src/main/resources/assets/ftbchunks/lang/en_us.json index b31e0e65..d055a9c5 100644 --- a/common/src/main/resources/assets/ftbchunks/lang/en_us.json +++ b/common/src/main/resources/assets/ftbchunks/lang/en_us.json @@ -87,6 +87,7 @@ "key.ftbchunks.minimap.zoomOut": "Zoom Out Minimap", "key.ftbchunks.add_waypoint": "Quick Add Waypoint", "key.ftbchunks.waypoint_manager": "Waypoint Manager", + "key.ftbchunks.toggle_minimap": "Toggle Minimap", "wilderness": "Wilderness", "ftbchunks.no_server_mod": "FTB Chunks requires mod on server!", "ftbchunks.already_claimed": "Chunk is already claimed by %s", @@ -115,6 +116,8 @@ "ftbchunks.gui.large_map_info.text": "Mouse\nLeft Button;Click/Drag to move map view\nRight Button;Context Menu\nMouse Wheel;Rotate to zoom\n\nKeys\nSpace;Center view on player\nC;Open chunk claim screen\nT;Teleport to point (op required)\nS;Open settings screen\nCtrl + S;Open server settings screen (op required)\nF3+G;Toggle Chunk Grid", "ftbchunks.gui.chunk_info": "Chunk Claiming Reference", "ftbchunks.gui.chunk_info.text": "Claiming\nLeft Button;Drag to claim an area\nRight Button;Drag to unclaim an area\n\nForceloading\nShift + Left Button;Drag to forceload an area\nShift + Right Button;Drag to unforceload an area\nMouse Wheel;Rotate on forceloaded chunk to adjust auto-expiry\n\nMisc\nTab;Hold to hide chunk grid\nAlt;Hold to show absolute chunk claim/force times", + "ftbchunks.gui.delete": "Delete", + "ftbchunks.gui.quick_delete": "Quick Delete", "ftbteamsconfig.ftbchunks": "FTB Chunks Properties", "ftbteamsconfig.ftbchunks.allow_fake_players": "Allow All Fake Players", "ftbteamsconfig.ftbchunks.allow_fake_players.tooltip": "Treat ALL fake players as allies of the team.\nWARNING: Setting this to true could allow hostile players to access your claims via any fake player. Set this to false if you're unsure.", @@ -198,5 +201,67 @@ "ftbchunks.need_to_claim_chunk": "You need to claim this chunk to interact with blocks here!", "ftbchunks.label.show": "Show", "ftbchunks.label.hide": "Hide", - "ftbchunks.message.no_pvp": "PvP combat is disabled here" + "ftbchunks.message.no_pvp": "PvP combat is disabled here", + "ftbchunks.game_time": "Game Time: %s", + "ftbchunks.real_time": "Real Time: %s", + "ftbchunks.fps": "FPS: %d", + "ftbchunks.minimap.show_game_time": "Show Game Time", + "ftbchunks.minimap.show_fps": "Show FPS", + "ftbchunks.minimap.show_real_time": "Show Real Time", + "ftbchunks.waypoint.shared": "Has shared waypoint '%s' with you! Click to add", + "ftbchunks.waypoint.shared_by_you": "You shared waypoint '%s' !", + "ftbchunks.waypoint.share": "Share", + "ftbchunks.waypoint.share.server": "Server", + "ftbchunks.waypoint.share.party": "Party", + "ftbchunks.waypoint.share.player": "Player", + "ftbchunks.waypoint_sharing": "Waypoint Sharing", + "ftbchunks.waypoint_sharing.waypoint_sharing_party": "Allow Sharing waypoints with Party", + "ftbchunks.waypoint_sharing.waypoint_sharing_server": "Allow Sharing waypoints with Server", + "ftbchunks.waypoint_sharing.waypoint_sharing_players": "Allow Sharing waypoints with Players", + "ftbchunks.map_mode.none": "None", + "ftbchunks.map_mode.night": "Night", + "ftbchunks.map_mode.topography": "Topography", + "ftbchunks.map_mode.blocks": "Blocks", + "ftbchunks.map_mode.light_sources": "Light Sources", + "ftbchunks.ally_mode.default": "Default", + "ftbchunks.ally_mode.forced_all": "Forced All", + "ftbchunks.ally_mode.forced_none": "Forced None", + "ftbchunks.pvp_mode.always": "Always", + "ftbchunks.pvp_mode.never": "Never", + "ftbchunks.pvp_mode.per_team": "Per Team", + "ftbchunks.party_limit_mode.largest": "Largest", + "ftbchunks.party_limit_mode.owner": "Owner", + "ftbchunks.party_limit_mode.sum": "Sum", + "ftbchunks.party_limit_mode.average": "Average", + "ftbchunks.force_load_mode.default": "Default", + "ftbchunks.force_load_mode.never": "Never", + "ftbchunks.force_load_mode.always": "Always", + "ftbchunks.time_mode.twenty_four": "Twenty Four", + "ftbchunks.time_mode.twelve": "Twelve", + "ftbchunks.time_mode.clock": "Clock", + "ftbchunks.gui.move_up": "Move Up", + "ftbchunks.gui.move_down": "Move Down", + "minimap.info.ftbchunks.biome.title": "Biome", + "minimap.info.ftbchunks.biome.description": "Render Biome", + "minimap.info.ftbchunks.fps.title": "FPS", + "minimap.info.ftbchunks.fps.description": "Render FPS", + "minimap.info.ftbchunks.game_time.title": "Game Time", + "minimap.info.ftbchunks.game_time.description": "Render Game Time", + "minimap.info.ftbchunks.debug.title": "Debug", + "minimap.info.ftbchunks.debug.description": "Render Debug", + "minimap.info.ftbchunks.player_pos.title": "Player Pos", + "minimap.info.ftbchunks.player_pos.description": "Render Player Pos", + "minimap.info.ftbchunks.real_time.title": "Real Time", + "minimap.info.ftbchunks.real_time.description": "Render Real Time", + "minimap.info.ftbchunks.zone.title": "Zone", + "minimap.info.ftbchunks.zone.description": "Render Zone", + "ftbchunks.gui.toggle_visibility_off": "Toggle Visibility - Off", + "ftbchunks.gui.toggle_visibility_on": "Toggle Visibility - On", + "ftbchunks.gui.sort_minimap_info": "Minimap Info Settings", + "ftbchunks.minimap.info_hidden": "Hidden Minimap Info", + "ftbchunks.minimap.info_order": "Minimap info order", + "ftbchunks.show_wilderness.show_wilderness": "Show Wilderness", + "ftbchunks.show_wilderness.just_claimed": "Show only Claimed Chunks", + "tag.item.ftbchunks.right_click_blacklist": "Right Click Blacklist", + "tag.item.ftbchunks.right_click_whitelist": "Right Click Whitelist" } \ No newline at end of file diff --git a/common/src/main/resources/data/ftbchunks/tags/entity_types/entity_mob_griefing_blacklist.json b/common/src/main/resources/data/ftbchunks/tags/entity_types/entity_mob_griefing_blacklist.json new file mode 100644 index 00000000..264d2016 --- /dev/null +++ b/common/src/main/resources/data/ftbchunks/tags/entity_types/entity_mob_griefing_blacklist.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "minecraft:enderman" + ] +} \ No newline at end of file diff --git a/common/src/main/resources/ftbchunks-common.mixins.json b/common/src/main/resources/ftbchunks-common.mixins.json index 17f7a135..8476067b 100644 --- a/common/src/main/resources/ftbchunks-common.mixins.json +++ b/common/src/main/resources/ftbchunks-common.mixins.json @@ -10,7 +10,8 @@ "UtilMixin" ], "client": [ - "ClientPacketListenerMixin" + "ClientPacketListenerMixin", + "GuiMixin" ], "injectors": { "defaultRequire": 1 diff --git a/forge/src/main/java/dev/ftb/mods/ftbchunks/forge/FTBChunksForge.java b/forge/src/main/java/dev/ftb/mods/ftbchunks/forge/FTBChunksForge.java index 5e72a538..e4b79512 100644 --- a/forge/src/main/java/dev/ftb/mods/ftbchunks/forge/FTBChunksForge.java +++ b/forge/src/main/java/dev/ftb/mods/ftbchunks/forge/FTBChunksForge.java @@ -2,6 +2,7 @@ import dev.architectury.platform.forge.EventBuses; import dev.ftb.mods.ftbchunks.FTBChunks; +import dev.ftb.mods.ftbchunks.api.FTBChunksTags; import dev.ftb.mods.ftbchunks.api.Protection; import dev.ftb.mods.ftbchunks.data.ClaimedChunkImpl; import dev.ftb.mods.ftbchunks.data.ClaimedChunkManagerImpl; @@ -49,9 +50,10 @@ private void entityInteractSpecific(PlayerInteractEvent.EntityInteractSpecific e private void mobGriefing(EntityMobGriefingEvent event) { // we could do this for all mob griefing but that's arguably OP (could trivialize wither fights, for example) - // enderman block stealing is the most common annoyance, and this also has parity with the fabric support + // expose this as a tag so pack makers can change to what they want (default tag with only enderman) + // due to current limitations on fabric this tag will only work on NeoForge, while fabric only supports enderman // Note: explicit check for server-side needed due to Optifine brain-damage - if (event.getEntity() instanceof EnderMan && !event.getEntity().level().isClientSide()) { + if (event.getEntity().getType().is(FTBChunksTags.Entities.ENTITY_MOB_GRIEFING_BLACKLIST_TAG) && !event.getEntity().level().isClientSide()) { ClaimedChunkImpl cc = ClaimedChunkManagerImpl.getInstance().getChunk(new ChunkDimPos(event.getEntity())); if (cc != null && !cc.allowMobGriefing()) { diff --git a/gradle.properties b/gradle.properties index 90e3bce3..8eaf231f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,7 +5,7 @@ org.gradle.daemon=false mod_id=ftbchunks archives_base_name=ftb-chunks maven_group=dev.ftb.mods -mod_version=2001.3.1 +mod_version=2001.3.2 mod_author=FTB Team minecraft_version=1.20.1 @@ -14,7 +14,7 @@ architectury_version=9.1.12 fabric_loader_version=0.14.21 fabric_api_version=0.83.1+1.20.1 -ftb_library_version=2001.2.0 +ftb_library_version=2001.2.4 ftb_teams_version=2001.3.0 curseforge_id_forge=314906