diff options
| author | msg-programs <msgdoesstuff@gmail.com> | 2023-10-31 21:03:42 +0100 |
|---|---|---|
| committer | msg-programs <msgdoesstuff@gmail.com> | 2023-10-31 21:03:42 +0100 |
| commit | d560c4611e603fa9e72ff6842bc14518d7bdbd63 (patch) | |
| tree | 36eb1e24443bc9d9fbba51e14f12e5aacfac935c /src/main/java/de/hysky/skyblocker/skyblock/dungeon | |
| parent | 1df4ef827d8a2e2fcc3767c1f5bf961f16b7fa19 (diff) | |
| parent | 5bb91104d3275283d7479f0b35c1b18be470d632 (diff) | |
| download | Skyblocker-d560c4611e603fa9e72ff6842bc14518d7bdbd63.tar.gz Skyblocker-d560c4611e603fa9e72ff6842bc14518d7bdbd63.tar.bz2 Skyblocker-d560c4611e603fa9e72ff6842bc14518d7bdbd63.zip | |
Merge branch 'master' of https://github.com/SkyblockerMod/Skyblocker into cleanup-2
# Conflicts:
# src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java
# src/main/java/de/hysky/skyblocker/utils/Http.java
# src/main/java/de/hysky/skyblocker/utils/render/title/TitleContainerConfigScreen.java
Pull changes from upstream master
Diffstat (limited to 'src/main/java/de/hysky/skyblocker/skyblock/dungeon')
10 files changed, 614 insertions, 96 deletions
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/CreeperBeams.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/CreeperBeams.java index 6369291b..689788e1 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/CreeperBeams.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/CreeperBeams.java @@ -237,12 +237,12 @@ public class CreeperBeams { // render either in a color if not created or faintly green if created public void render(WorldRenderContext wrc, float[] color) { if (toDo) { - RenderHelper.renderOutline(wrc, outlineOne, color, 3); - RenderHelper.renderOutline(wrc, outlineTwo, color, 3); + RenderHelper.renderOutline(wrc, outlineOne, color, 3, false); + RenderHelper.renderOutline(wrc, outlineTwo, color, 3, false); RenderHelper.renderLinesFromPoints(wrc, line, color, 1, 2); } else { - RenderHelper.renderOutline(wrc, outlineOne, LIME_COLOR_COMPONENTS, 1); - RenderHelper.renderOutline(wrc, outlineTwo, LIME_COLOR_COMPONENTS, 1); + RenderHelper.renderOutline(wrc, outlineOne, LIME_COLOR_COMPONENTS, 1, false); + RenderHelper.renderOutline(wrc, outlineTwo, LIME_COLOR_COMPONENTS, 1, false); RenderHelper.renderLinesFromPoints(wrc, line, LIME_COLOR_COMPONENTS, 0.75f, 1); } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonBlaze.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonBlaze.java index cfb16b4d..f49a2f2e 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonBlaze.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonBlaze.java @@ -128,11 +128,11 @@ public class DungeonBlaze { */ private static void renderBlazeOutline(ArmorStandEntity blaze, ArmorStandEntity nextBlaze, WorldRenderContext wrc) { Box blazeBox = blaze.getBoundingBox().expand(0.3, 0.9, 0.3).offset(0, -1.1, 0); - RenderHelper.renderOutline(wrc, blazeBox, GREEN_COLOR_COMPONENTS, 5f); + RenderHelper.renderOutline(wrc, blazeBox, GREEN_COLOR_COMPONENTS, 5f, false); if (nextBlaze != null && nextBlaze.isAlive() && nextBlaze != blaze) { Box nextBlazeBox = nextBlaze.getBoundingBox().expand(0.3, 0.9, 0.3).offset(0, -1.1, 0); - RenderHelper.renderOutline(wrc, nextBlazeBox, WHITE_COLOR_COMPONENTS, 5f); + RenderHelper.renderOutline(wrc, nextBlazeBox, WHITE_COLOR_COMPONENTS, 5f, false); Vec3d blazeCenter = blazeBox.getCenter(); Vec3d nextBlazeCenter = nextBlazeBox.getCenter(); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonChestProfit.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonChestProfit.java index 4e6a5240..1e889af3 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonChestProfit.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonChestProfit.java @@ -4,7 +4,8 @@ import com.google.gson.JsonObject; import de.hysky.skyblocker.config.SkyblockerConfig; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.mixin.accessor.ScreenAccessor; -import de.hysky.skyblocker.skyblock.item.PriceInfoTooltip; +import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip; +import de.hysky.skyblocker.skyblock.item.tooltip.TooltipInfoType; import de.hysky.skyblocker.utils.Utils; import it.unimi.dsi.fastutil.ints.IntBooleanPair; import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents; @@ -54,7 +55,7 @@ public class DungeonChestProfit { if (!stack.isEmpty()) { String name = stack.getName().getString(); - String id = PriceInfoTooltip.getInternalNameFromNBT(stack, false); + String id = ItemTooltip.getInternalNameFromNBT(stack, false); //Regular item price if (id != null) { @@ -128,8 +129,8 @@ public class DungeonChestProfit { * was based on complete data. */ private static IntBooleanPair getItemPrice(String id) { - JsonObject bazaarPrices = PriceInfoTooltip.getBazaarPrices(); - JsonObject lbinPrices = PriceInfoTooltip.getLBINPrices(); + JsonObject bazaarPrices = TooltipInfoType.BAZAAR.getData(); + JsonObject lbinPrices = TooltipInfoType.LOWEST_BINS.getData(); if (bazaarPrices == null || lbinPrices == null) return IntBooleanPair.of(0, false); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMapConfigScreen.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMapConfigScreen.java index 69018cd4..c198238b 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMapConfigScreen.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMapConfigScreen.java @@ -57,6 +57,7 @@ public class DungeonMapConfigScreen extends Screen { SkyblockerConfigManager.get().locations.dungeons.mapX = hudX; SkyblockerConfigManager.get().locations.dungeons.mapY = hudY; SkyblockerConfigManager.save(); + this.client.setScreen(parent); } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/TicTacToe.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/TicTacToe.java index 2d56c8a0..7f249e7d 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/TicTacToe.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/TicTacToe.java @@ -127,7 +127,7 @@ public class TicTacToe { private static void solutionRenderer(WorldRenderContext context) { try { if (SkyblockerConfigManager.get().locations.dungeons.solveTicTacToe && nextBestMoveToMake != null) { - RenderHelper.renderOutline(context, nextBestMoveToMake, RED_COLOR_COMPONENTS, 5); + RenderHelper.renderOutline(context, nextBestMoveToMake, RED_COLOR_COMPONENTS, 5, false); } } catch (Exception e) { LOGGER.error("[Skyblocker Tic Tac Toe] Encountered an exception while rendering the tic tac toe solution!", e); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonMapUtils.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonMapUtils.java index 259cc3f3..73d4a452 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonMapUtils.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonMapUtils.java @@ -7,7 +7,6 @@ import net.minecraft.block.MapColor; import net.minecraft.item.map.MapIcon; import net.minecraft.item.map.MapState; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3i; import org.jetbrains.annotations.NotNull; @@ -173,7 +172,7 @@ public class DungeonMapUtils { @NotNull public static Vector2ic getPhysicalRoomPos(double x, double z) { Vector2i physicalPos = new Vector2i(x + 8.5, z + 8.5, RoundingMode.TRUNCATE); - return physicalPos.sub(MathHelper.floorMod(physicalPos.x(), 32), MathHelper.floorMod(physicalPos.y(), 32)).sub(8, 8); + return physicalPos.sub(Math.floorMod(physicalPos.x(), 32), Math.floorMod(physicalPos.y(), 32)).sub(8, 8); } public static Vector2ic[] getPhysicalPosFromMap(Vector2ic mapEntrancePos, int mapRoomSize, Vector2ic physicalEntrancePos, Vector2ic... mapPositions) { diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java index c2358689..eda08cf6 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java @@ -1,5 +1,7 @@ package de.hysky.skyblocker.skyblock.dungeon.secrets; +import com.google.common.collect.HashBasedTable; +import com.google.common.collect.Table; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -7,15 +9,19 @@ import com.mojang.brigadier.Command; import com.mojang.brigadier.arguments.IntegerArgumentType; import com.mojang.brigadier.builder.ArgumentBuilder; import com.mojang.brigadier.builder.RequiredArgumentBuilder; -import it.unimi.dsi.fastutil.objects.Object2ByteMap; -import it.unimi.dsi.fastutil.objects.Object2ByteOpenHashMap; -import it.unimi.dsi.fastutil.objects.ObjectIntPair; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.serialization.JsonOps; import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.utils.Constants; import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.scheduler.Scheduler; +import it.unimi.dsi.fastutil.objects.Object2ByteMap; +import it.unimi.dsi.fastutil.objects.Object2ByteOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectIntPair; import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; @@ -23,6 +29,9 @@ import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; import net.fabricmc.fabric.api.event.player.UseBlockCallback; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.command.argument.BlockPosArgumentType; +import net.minecraft.command.argument.PosArgument; +import net.minecraft.command.argument.TextArgumentType; import net.minecraft.entity.ItemEntity; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.mob.AmbientEntity; @@ -32,11 +41,15 @@ import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.item.map.MapState; import net.minecraft.resource.Resource; +import net.minecraft.server.command.ServerCommandSource; import net.minecraft.text.Text; import net.minecraft.util.ActionResult; import net.minecraft.util.Identifier; import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.hit.HitResult; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.Vec3i; import net.minecraft.world.World; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; @@ -46,10 +59,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.BufferedReader; +import java.io.BufferedWriter; import java.io.IOException; import java.io.ObjectInputStream; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.*; import java.util.concurrent.CompletableFuture; +import java.util.stream.Stream; import java.util.zip.InflaterInputStream; import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.argument; @@ -58,6 +75,7 @@ import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.lit public class DungeonSecrets { protected static final Logger LOGGER = LoggerFactory.getLogger(DungeonSecrets.class); private static final String DUNGEONS_PATH = "dungeons"; + private static final Path CUSTOM_WAYPOINTS_DIR = SkyblockerMod.CONFIG_DIR.resolve("custom_secret_waypoints.json"); /** * Maps the block identifier string to a custom numeric block id used in dungeon rooms data. * @@ -97,6 +115,10 @@ public class DungeonSecrets { private static final Map<Vector2ic, Room> rooms = new HashMap<>(); private static final Map<String, JsonElement> roomsJson = new HashMap<>(); private static final Map<String, JsonElement> waypointsJson = new HashMap<>(); + /** + * The map of dungeon room names to custom waypoints relative to the room. + */ + private static final Table<String, BlockPos, SecretWaypoint> customWaypoints = HashBasedTable.create(); @Nullable private static CompletableFuture<Void> roomsLoaded; /** @@ -119,6 +141,10 @@ public class DungeonSecrets { return roomsLoaded != null && roomsLoaded.isDone(); } + public static Stream<Room> getRoomsStream() { + return rooms.values().stream(); + } + @SuppressWarnings("unused") public static JsonObject getRoomMetadata(String room) { return roomsJson.get(room).getAsJsonObject(); @@ -129,6 +155,38 @@ public class DungeonSecrets { } /** + * @see #customWaypoints + */ + public static Map<BlockPos, SecretWaypoint> getCustomWaypoints(String room) { + return customWaypoints.row(room); + } + + /** + * @see #customWaypoints + */ + @SuppressWarnings("UnusedReturnValue") + public static SecretWaypoint addCustomWaypoint(String room, SecretWaypoint waypoint) { + return customWaypoints.put(room, waypoint.pos, waypoint); + } + + /** + * @see #customWaypoints + */ + public static void addCustomWaypoints(String room, Collection<SecretWaypoint> waypoints) { + for (SecretWaypoint waypoint : waypoints) { + addCustomWaypoint(room, waypoint); + } + } + + /** + * @see #customWaypoints + */ + @Nullable + public static SecretWaypoint removeCustomWaypoint(String room, BlockPos pos) { + return customWaypoints.remove(room, pos); + } + + /** * Loads the dungeon secrets asynchronously from {@code /assets/skyblocker/dungeons}. * Use {@link #isRoomsLoaded()} to check for completion of loading. */ @@ -138,9 +196,10 @@ public class DungeonSecrets { } // Execute with MinecraftClient as executor since we need to wait for MinecraftClient#resourceManager to be set CompletableFuture.runAsync(DungeonSecrets::load, MinecraftClient.getInstance()).exceptionally(e -> { - LOGGER.error("[Skyblocker] Failed to load dungeon secrets", e); + LOGGER.error("[Skyblocker Dungeon Secrets] Failed to load dungeon secrets", e); return null; }); + ClientLifecycleEvents.CLIENT_STOPPING.register(DungeonSecrets::saveCustomWaypoints); Scheduler.INSTANCE.scheduleCyclic(DungeonSecrets::update, 10); WorldRenderEvents.AFTER_TRANSLUCENT.register(DungeonSecrets::render); ClientReceiveMessageEvents.GAME.register(DungeonSecrets::onChatMessage); @@ -148,7 +207,14 @@ public class DungeonSecrets { UseBlockCallback.EVENT.register((player, world, hand, hitResult) -> onUseBlock(world, hitResult)); ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> dispatcher.register(literal(SkyblockerMod.NAMESPACE).then(literal("dungeons").then(literal("secrets") .then(literal("markAsFound").then(markSecretsCommand(true))) - .then(literal("markAsMissing").then(markSecretsCommand(false))))))); + .then(literal("markAsMissing").then(markSecretsCommand(false))) + .then(literal("getRelativePos").executes(DungeonSecrets::getRelativePos)) + .then(literal("getRelativeTargetPos").executes(DungeonSecrets::getRelativeTargetPos)) + .then(literal("addWaypoint").then(addCustomWaypointCommand(false))) + .then(literal("addWaypointRelatively").then(addCustomWaypointCommand(true))) + .then(literal("removeWaypoint").then(removeCustomWaypointCommand(false))) + .then(literal("removeWaypointRelatively").then(removeCustomWaypointCommand(true))) + )))); ClientPlayConnectionEvents.JOIN.register(((handler, sender, client) -> reset())); } @@ -158,7 +224,7 @@ public class DungeonSecrets { for (Map.Entry<Identifier, Resource> resourceEntry : MinecraftClient.getInstance().getResourceManager().findResources(DUNGEONS_PATH, id -> id.getPath().endsWith(".skeleton")).entrySet()) { String[] path = resourceEntry.getKey().getPath().split("/"); if (path.length != 4) { - LOGGER.error("[Skyblocker] Failed to load dungeon secrets, invalid resource identifier {}", resourceEntry.getKey()); + LOGGER.error("[Skyblocker Dungeon Secrets] Failed to load dungeon secrets, invalid resource identifier {}", resourceEntry.getKey()); break; } String dungeon = path[1]; @@ -171,9 +237,9 @@ public class DungeonSecrets { synchronized (roomsMap) { roomsMap.put(room, rooms); } - LOGGER.debug("[Skyblocker] Loaded dungeon secrets dungeon {} room shape {} room {}", dungeon, roomShape, room); + LOGGER.debug("[Skyblocker Dungeon Secrets] Loaded dungeon secrets dungeon {} room shape {} room {}", dungeon, roomShape, room); }).exceptionally(e -> { - LOGGER.error("[Skyblocker] Failed to load dungeon secrets dungeon {} room shape {} room {}", dungeon, roomShape, room, e); + LOGGER.error("[Skyblocker Dungeon Secrets] Failed to load dungeon secrets dungeon {} room shape {} room {}", dungeon, roomShape, room, e); return null; })); } @@ -181,16 +247,39 @@ public class DungeonSecrets { try (BufferedReader roomsReader = MinecraftClient.getInstance().getResourceManager().openAsReader(new Identifier(SkyblockerMod.NAMESPACE, "dungeons/dungeonrooms.json")); BufferedReader waypointsReader = MinecraftClient.getInstance().getResourceManager().openAsReader(new Identifier(SkyblockerMod.NAMESPACE, "dungeons/secretlocations.json"))) { loadJson(roomsReader, roomsJson); loadJson(waypointsReader, waypointsJson); - LOGGER.debug("[Skyblocker] Loaded dungeon secrets json"); + LOGGER.debug("[Skyblocker Dungeon Secrets] Loaded dungeon secret waypoints json"); + } catch (Exception e) { + LOGGER.error("[Skyblocker Dungeon Secrets] Failed to load dungeon secret waypoints json", e); + } + })); + dungeonFutures.add(CompletableFuture.runAsync(() -> { + try (BufferedReader customWaypointsReader = Files.newBufferedReader(CUSTOM_WAYPOINTS_DIR)) { + SkyblockerMod.GSON.fromJson(customWaypointsReader, JsonObject.class).asMap().forEach((room, waypointsJson) -> + addCustomWaypoints(room, SecretWaypoint.LIST_CODEC.parse(JsonOps.INSTANCE, waypointsJson).resultOrPartial(LOGGER::error).orElseThrow()) + ); + LOGGER.debug("[Skyblocker Dungeon Secrets] Loaded custom dungeon secret waypoints"); } catch (Exception e) { - LOGGER.error("[Skyblocker] Failed to load dungeon secrets json", e); + LOGGER.error("[Skyblocker Dungeon Secrets] Failed to load custom dungeon secret waypoints", e); } })); - roomsLoaded = CompletableFuture.allOf(dungeonFutures.toArray(CompletableFuture[]::new)).thenRun(() -> LOGGER.info("[Skyblocker] Loaded dungeon secrets for {} dungeon(s), {} room shapes, and {} rooms total in {} ms", ROOMS_DATA.size(), ROOMS_DATA.values().stream().mapToInt(Map::size).sum(), ROOMS_DATA.values().stream().map(Map::values).flatMap(Collection::stream).mapToInt(Map::size).sum(), System.currentTimeMillis() - startTime)).exceptionally(e -> { - LOGGER.error("[Skyblocker] Failed to load dungeon secrets", e); + roomsLoaded = CompletableFuture.allOf(dungeonFutures.toArray(CompletableFuture[]::new)).thenRun(() -> LOGGER.info("[Skyblocker Dungeon Secrets] Loaded dungeon secrets for {} dungeon(s), {} room shapes, {} rooms, and {} custom secret waypoints total in {} ms", ROOMS_DATA.size(), ROOMS_DATA.values().stream().mapToInt(Map::size).sum(), ROOMS_DATA.values().stream().map(Map::values).flatMap(Collection::stream).mapToInt(Map::size).sum(), customWaypoints.size(), System.currentTimeMillis() - startTime)).exceptionally(e -> { + LOGGER.error("[Skyblocker Dungeon Secrets] Failed to load dungeon secrets", e); return null; }); - LOGGER.info("[Skyblocker] Started loading dungeon secrets in (blocked main thread for) {} ms", System.currentTimeMillis() - startTime); + LOGGER.info("[Skyblocker Dungeon Secrets] Started loading dungeon secrets in (blocked main thread for) {} ms", System.currentTimeMillis() - startTime); + } + + private static void saveCustomWaypoints(MinecraftClient client) { + try (BufferedWriter writer = Files.newBufferedWriter(CUSTOM_WAYPOINTS_DIR)) { + JsonObject customWaypointsJson = new JsonObject(); + customWaypoints.rowMap().forEach((room, waypoints) -> + customWaypointsJson.add(room, SecretWaypoint.LIST_CODEC.encodeStart(JsonOps.INSTANCE, new ArrayList<>(waypoints.values())).resultOrPartial(LOGGER::error).orElseThrow()) + ); + SkyblockerMod.GSON.toJson(customWaypointsJson, writer); + LOGGER.info("[Skyblocker Dungeon Secrets] Saved custom dungeon secret waypoints"); + } catch (Exception e) { + LOGGER.error("[Skyblocker Dungeon Secrets] Failed to save custom dungeon secret waypoints", e); + } } private static int[] readRoom(Resource resource) throws RuntimeException { @@ -203,25 +292,110 @@ public class DungeonSecrets { /** * Loads the json from the given {@link BufferedReader} into the given {@link Map}. + * * @param reader the reader to read the json from - * @param map the map to load into + * @param map the map to load into */ private static void loadJson(BufferedReader reader, Map<String, JsonElement> map) { SkyblockerMod.GSON.fromJson(reader, JsonObject.class).asMap().forEach((room, jsonElement) -> map.put(room.toLowerCase().replaceAll(" ", "-"), jsonElement)); } private static ArgumentBuilder<FabricClientCommandSource, RequiredArgumentBuilder<FabricClientCommandSource, Integer>> markSecretsCommand(boolean found) { - return argument("secret", IntegerArgumentType.integer()).executes(context -> { - int secretIndex = IntegerArgumentType.getInteger(context, "secret"); + return argument("secretIndex", IntegerArgumentType.integer()).executes(context -> { + int secretIndex = IntegerArgumentType.getInteger(context, "secretIndex"); if (markSecrets(secretIndex, found)) { - context.getSource().sendFeedback(Text.translatable(found ? "skyblocker.dungeons.secrets.markSecretFound" : "skyblocker.dungeons.secrets.markSecretMissing", secretIndex)); + context.getSource().sendFeedback(Constants.PREFIX.get().append(Text.translatable(found ? "skyblocker.dungeons.secrets.markSecretFound" : "skyblocker.dungeons.secrets.markSecretMissing", secretIndex))); } else { - context.getSource().sendError(Text.translatable(found ? "skyblocker.dungeons.secrets.markSecretFoundUnable" : "skyblocker.dungeons.secrets.markSecretMissingUnable", secretIndex)); + context.getSource().sendError(Constants.PREFIX.get().append(Text.translatable(found ? "skyblocker.dungeons.secrets.markSecretFoundUnable" : "skyblocker.dungeons.secrets.markSecretMissingUnable", secretIndex))); } return Command.SINGLE_SUCCESS; }); } + private static int getRelativePos(CommandContext<FabricClientCommandSource> context) { + return getRelativePos(context.getSource(), context.getSource().getPlayer().getBlockPos()); + } + + private static int getRelativeTargetPos(CommandContext<FabricClientCommandSource> context) { + if (MinecraftClient.getInstance().crosshairTarget instanceof BlockHitResult blockHitResult && blockHitResult.getType() == HitResult.Type.BLOCK) { + return getRelativePos(context.getSource(), blockHitResult.getBlockPos()); + } else { + context.getSource().sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.noTarget"))); + } + return Command.SINGLE_SUCCESS; + } + + private static int getRelativePos(FabricClientCommandSource source, BlockPos pos) { + Room room = getRoomAtPhysical(pos); + if (isRoomMatched(room)) { + BlockPos relativePos = currentRoom.actualToRelative(pos); + source.sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.posMessage", currentRoom.getName(), relativePos.getX(), relativePos.getY(), relativePos.getZ()))); + } else { + source.sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.notMatched"))); + } + return Command.SINGLE_SUCCESS; + } + + private static ArgumentBuilder<FabricClientCommandSource, RequiredArgumentBuilder<FabricClientCommandSource, PosArgument>> addCustomWaypointCommand(boolean relative) { + return argument("pos", BlockPosArgumentType.blockPos()) + .then(argument("secretIndex", IntegerArgumentType.integer()) + .then(argument("category", SecretWaypoint.Category.CategoryArgumentType.category()) + .then(argument("name", TextArgumentType.text()).executes(context -> { + // TODO Less hacky way with custom ClientBlockPosArgumentType + BlockPos pos = context.getArgument("pos", PosArgument.class).toAbsoluteBlockPos(new ServerCommandSource(null, context.getSource().getPosition(), context.getSource().getRotation(), null, 0, null, null, null, null)); + return relative ? addCustomWaypointRelative(context, pos) : addCustomWaypoint(context, pos); + })) + ) + ); + } + + private static int addCustomWaypoint(CommandContext<FabricClientCommandSource> context, BlockPos pos) { + Room room = getRoomAtPhysical(pos); + if (isRoomMatched(room)) { + room.addCustomWaypoint(context, room.actualToRelative(pos)); + } else { + context.getSource().sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.notMatched"))); + } + return Command.SINGLE_SUCCESS; + } + + private static int addCustomWaypointRelative(CommandContext<FabricClientCommandSource> context, BlockPos pos) { + if (isCurrentRoomMatched()) { + currentRoom.addCustomWaypoint(context, pos); + } else { + context.getSource().sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.notMatched"))); + } + return Command.SINGLE_SUCCESS; + } + + private static ArgumentBuilder<FabricClientCommandSource, RequiredArgumentBuilder<FabricClientCommandSource, PosArgument>> removeCustomWaypointCommand(boolean relative) { + return argument("pos", BlockPosArgumentType.blockPos()) + .executes(context -> { + // TODO Less hacky way with custom ClientBlockPosArgumentType + BlockPos pos = context.getArgument("pos", PosArgument.class).toAbsoluteBlockPos(new ServerCommandSource(null, context.getSource().getPosition(), context.getSource().getRotation(), null, 0, null, null, null, null)); + return relative ? removeCustomWaypointRelative(context, pos) : removeCustomWaypoint(context, pos); + }); + } + + private static int removeCustomWaypoint(CommandContext<FabricClientCommandSource> context, BlockPos pos) { + Room room = getRoomAtPhysical(pos); + if (isRoomMatched(room)) { + room.removeCustomWaypoint(context, room.actualToRelative(pos)); + } else { + context.getSource().sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.notMatched"))); + } + return Command.SINGLE_SUCCESS; + } + + private static int removeCustomWaypointRelative(CommandContext<FabricClientCommandSource> context, BlockPos pos) { + if (isCurrentRoomMatched()) { + currentRoom.removeCustomWaypoint(context, pos); + } else { + context.getSource().sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.notMatched"))); + } + return Command.SINGLE_SUCCESS; + } + /** * Updates the dungeon. The general idea is similar to the Dungeon Rooms Mod. * <p></p> @@ -282,7 +456,7 @@ public class DungeonSecrets { } mapEntrancePos = mapEntrancePosAndSize.left(); mapRoomSize = mapEntrancePosAndSize.rightInt(); - LOGGER.info("[Skyblocker] Started dungeon with map room size {}, map entrance pos {}, player pos {}, and physical entrance pos {}", mapRoomSize, mapEntrancePos, client.player.getPos(), physicalEntrancePos); + LOGGER.info("[Skyblocker Dungeon Secrets] Started dungeon with map room size {}, map entrance pos {}, player pos {}, and physical entrance pos {}", mapRoomSize, mapEntrancePos, client.player.getPos(), physicalEntrancePos); } Vector2ic physicalPos = DungeonMapUtils.getPhysicalRoomPos(client.player.getPos()); @@ -320,7 +494,7 @@ public class DungeonSecrets { } return newRoom; } catch (IllegalArgumentException e) { - LOGGER.error("[Skyblocker] Failed to create room", e); + LOGGER.error("[Skyblocker Dungeon Secrets] Failed to create room", e); } return null; } @@ -339,9 +513,16 @@ public class DungeonSecrets { * Used to detect when all secrets in a room are found. */ private static void onChatMessage(Text text, boolean overlay) { + String message = text.getString(); + if (overlay && isCurrentRoomMatched()) { - currentRoom.onChatMessage(text.getString()); + currentRoom.onChatMessage(message); } + + if (message.equals("[BOSS] Bonzo: Gratz for making it this far, but I'm basically unbeatable.") || message.equals("[BOSS] Scarf: This is where the journey ends for you, Adventurers.") + || message.equals("[BOSS] The Professor: I was burdened with terrible news recently...") || message.equals("[BOSS] Thorn: Welcome Adventurers! I am Thorn, the Spirit! And host of the Vegan Trials!") + || message.equals("[BOSS] Livid: Welcome, you've arrived right on time. I am Livid, the Master of Shadows.") || message.equals("[BOSS] Sadan: So you made it all the way here... Now you wish to defy me? Sadan?!") + || message.equals("[BOSS] Maxor: WELL! WELL! WELL! LOOK WHO'S HERE!")) reset(); } /** @@ -410,6 +591,19 @@ public class DungeonSecrets { } /** + * Gets the room at the given physical position. + * + * @param pos the physical position + * @return the room at the given physical position, or null if there is no room at the given physical position + * @see #rooms + * @see DungeonMapUtils#getPhysicalRoomPos(Vec3i) + */ + @Nullable + private static Room getRoomAtPhysical(Vec3i pos) { + return rooms.get(DungeonMapUtils.getPhysicalRoomPos(pos)); + } + + /** * Calls {@link #isRoomMatched(Room)} on {@link #currentRoom}. * * @return {@code true} if {@link #currentRoom} is not null and {@link #isRoomMatched(Room)} @@ -439,7 +633,7 @@ public class DungeonSecrets { } /** - * Resets fields when leaving a dungeon. + * Resets fields when leaving a dungeon or entering boss. */ private static void reset() { mapEntrancePos = null; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java index dd7dc91e..ecfcf496 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java @@ -1,14 +1,17 @@ package de.hysky.skyblocker.skyblock.dungeon.secrets; import com.google.common.collect.HashBasedTable; -import com.google.common.collect.ImmutableTable; import com.google.common.collect.Table; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import com.mojang.brigadier.arguments.IntegerArgumentType; +import com.mojang.brigadier.context.CommandContext; +import de.hysky.skyblocker.utils.Constants; +import de.hysky.skyblocker.utils.scheduler.Scheduler; import it.unimi.dsi.fastutil.ints.IntRBTreeSet; import it.unimi.dsi.fastutil.ints.IntSortedSet; import it.unimi.dsi.fastutil.ints.IntSortedSets; -import de.hysky.skyblocker.utils.scheduler.Scheduler; +import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; import net.fabricmc.fabric.api.util.TriState; import net.minecraft.block.BlockState; @@ -21,13 +24,14 @@ import net.minecraft.entity.ItemEntity; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.mob.AmbientEntity; import net.minecraft.registry.Registries; +import net.minecraft.text.Text; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; import org.apache.commons.lang3.tuple.MutableTriple; import org.apache.commons.lang3.tuple.Triple; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.joml.Vector2i; import org.joml.Vector2ic; @@ -72,6 +76,9 @@ public class Room { */ private TriState matched = TriState.DEFAULT; private Table<Integer, BlockPos, SecretWaypoint> secretWaypoints; + private String name; + private Direction direction; + private Vector2ic physicalCornerPos; public Room(@NotNull Type type, @NotNull Vector2ic... physicalPositions) { this.type = type; @@ -92,6 +99,13 @@ public class Room { return matched == TriState.TRUE; } + /** + * Not null if {@link #isMatched()}. + */ + public String getName() { + return name; + } + @Override public String toString() { return "Room{type=" + type + ", shape=" + shape + ", matched=" + matched + ", segments=" + Arrays.toString(segments.toArray()) + "}"; @@ -145,6 +159,79 @@ public class Room { } /** + * @see #addCustomWaypoint(int, SecretWaypoint.Category, Text, BlockPos) + */ + protected void addCustomWaypoint(CommandContext<FabricClientCommandSource> context, BlockPos pos) { + int secretIndex = IntegerArgumentType.getInteger(context, "secretIndex"); + SecretWaypoint.Category category = SecretWaypoint.Category.CategoryArgumentType.getCategory(context, "category"); + Text waypointName = context.getArgument("name", Text.class); + addCustomWaypoint(secretIndex, category, waypointName, pos); + context.getSource().sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.customWaypointAdded", pos.getX(), pos.getY(), pos.getZ(), name, secretIndex, category, waypointName))); + } + + /** + * Adds a custom waypoint relative to this room to {@link DungeonSecrets#customWaypoints} and all existing instances of this r |
