aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/de/hysky/skyblocker
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/de/hysky/skyblocker')
-rw-r--r--src/main/java/de/hysky/skyblocker/SkyblockerMod.java3
-rw-r--r--src/main/java/de/hysky/skyblocker/SkyblockerScreen.java125
-rw-r--r--src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java2
-rw-r--r--src/main/java/de/hysky/skyblocker/config/categories/LocationsCategory.java7
-rw-r--r--src/main/java/de/hysky/skyblocker/mixin/ClientPlayNetworkHandlerMixin.java2
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/Tips.java2
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/end/EnderNodes.java138
7 files changed, 278 insertions, 1 deletions
diff --git a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java
index 485a2103..3d96cc50 100644
--- a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java
+++ b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java
@@ -21,6 +21,7 @@ import de.hysky.skyblocker.skyblock.dwarven.CrystalsHud;
import de.hysky.skyblocker.skyblock.dwarven.CrystalsLocationsManager;
import de.hysky.skyblocker.skyblock.dwarven.DwarvenHud;
import de.hysky.skyblocker.skyblock.end.BeaconHighlighter;
+import de.hysky.skyblocker.skyblock.end.EnderNodes;
import de.hysky.skyblocker.skyblock.end.TheEnd;
import de.hysky.skyblocker.skyblock.garden.FarmingHud;
import de.hysky.skyblocker.skyblock.garden.LowerSensitivity;
@@ -98,6 +99,7 @@ public class SkyblockerMod implements ClientModInitializer {
ClientTickEvents.END_CLIENT_TICK.register(this::tick);
Utils.init();
SkyblockerConfigManager.init();
+ SkyblockerScreen.initClass();
Tips.init();
NEURepoManager.init();
ImageRepoLoader.init();
@@ -110,6 +112,7 @@ public class SkyblockerMod implements ClientModInitializer {
FairySouls.init();
Relics.init();
MythologicalRitual.init();
+ EnderNodes.init();
OrderedWaypoints.init();
BackpackPreview.init();
QuickNav.init();
diff --git a/src/main/java/de/hysky/skyblocker/SkyblockerScreen.java b/src/main/java/de/hysky/skyblocker/SkyblockerScreen.java
new file mode 100644
index 00000000..ba0745ed
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/SkyblockerScreen.java
@@ -0,0 +1,125 @@
+package de.hysky.skyblocker;
+
+import de.hysky.skyblocker.config.SkyblockerConfigManager;
+import de.hysky.skyblocker.skyblock.Tips;
+import de.hysky.skyblocker.utils.scheduler.Scheduler;
+import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager;
+import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
+import net.minecraft.client.font.TextRenderer;
+import net.minecraft.client.gui.DrawContext;
+import net.minecraft.client.gui.screen.ConfirmLinkScreen;
+import net.minecraft.client.gui.screen.Screen;
+import net.minecraft.client.gui.widget.ButtonWidget;
+import net.minecraft.client.gui.widget.GridWidget;
+import net.minecraft.client.gui.widget.MultilineTextWidget;
+import net.minecraft.client.gui.widget.TextWidget;
+import net.minecraft.client.gui.widget.ThreePartsLayoutWidget;
+import net.minecraft.screen.ScreenTexts;
+import net.minecraft.text.OrderedText;
+import net.minecraft.text.StringVisitable;
+import net.minecraft.text.Text;
+import net.minecraft.util.Identifier;
+import net.minecraft.util.Language;
+
+public class SkyblockerScreen extends Screen {
+ private static final int SPACING = 8;
+ private static final int BUTTON_WIDTH = 210;
+ private static final int HALF_BUTTON_WIDTH = 101; //Same as (210 - 8) / 2
+ private static final Text TITLE = Text.literal("Skyblocker " + SkyblockerMod.VERSION);
+ private static final Identifier ICON = new Identifier(SkyblockerMod.NAMESPACE, "icon.png");
+ private static final Text CONFIGURATION_TEXT = Text.translatable("text.skyblocker.config");
+ private static final Text SOURCE_TEXT = Text.translatable("text.skyblocker.source");
+ private static final Text REPORT_BUGS_TEXT = Text.translatable("menu.reportBugs");
+ private static final Text WEBSITE_TEXT = Text.translatable("text.skyblocker.website");
+ private static final Text TRANSLATE_TEXT = Text.translatable("text.skyblocker.translate");
+ private static final Text MODRINTH_TEXT = Text.translatable("text.skyblocker.modrinth");
+ private static final Text DISCORD_TEXT = Text.translatable("text.skyblocker.discord");
+ private final ThreePartsLayoutWidget layout = new ThreePartsLayoutWidget(this);
+
+ private SkyblockerScreen() {
+ super(TITLE);
+ }
+
+ public static void initClass() {
+ ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> {
+ dispatcher.register(ClientCommandManager.literal(SkyblockerMod.NAMESPACE)
+ .executes(Scheduler.queueOpenScreenCommand(SkyblockerScreen::new)));
+ });
+ }
+
+ @Override
+ protected void init() {
+ this.layout.addHeader(new IconTextWidget(this.getTitle(), this.textRenderer, ICON));
+
+ GridWidget gridWidget = this.layout.addBody(new GridWidget()).setSpacing(SPACING);
+ gridWidget.getMainPositioner().alignHorizontalCenter();
+ GridWidget.Adder adder = gridWidget.createAdder(2);
+
+ adder.add(ButtonWidget.builder(CONFIGURATION_TEXT, button -> this.openConfig()).width(BUTTON_WIDTH).build(), 2);
+ adder.add(ButtonWidget.builder(SOURCE_TEXT, ConfirmLinkScreen.opening(this, "https://github.com/SkyblockerMod/Skyblocker")).width(HALF_BUTTON_WIDTH).build());
+ adder.add(ButtonWidget.builder(REPORT_BUGS_TEXT, ConfirmLinkScreen.opening(this, "https://github.com/SkyblockerMod/Skyblocker/issues")).width(HALF_BUTTON_WIDTH).build());
+ adder.add(ButtonWidget.builder(WEBSITE_TEXT, ConfirmLinkScreen.opening(this, "https://hysky.de/")).width(HALF_BUTTON_WIDTH).build());
+ adder.add(ButtonWidget.builder(TRANSLATE_TEXT, ConfirmLinkScreen.opening(this, "https://translate.hysky.de/")).width(HALF_BUTTON_WIDTH).build());
+ adder.add(ButtonWidget.builder(MODRINTH_TEXT, ConfirmLinkScreen.opening(this, "https://modrinth.com/mod/skyblocker-liap")).width(HALF_BUTTON_WIDTH).build());
+ adder.add(ButtonWidget.builder(DISCORD_TEXT, ConfirmLinkScreen.opening(this, "https://discord.gg/aNNJHQykck")).width(HALF_BUTTON_WIDTH).build());
+ adder.add(ButtonWidget.builder(ScreenTexts.DONE, button -> this.close()).width(BUTTON_WIDTH).build(), 2);
+
+ MultilineTextWidget tip = new MultilineTextWidget(Text.translatable("skyblocker.tips.tip", Tips.nextTipInternal()), this.textRenderer)
+ .setCentered(true)
+ .setMaxWidth((int) (this.width * 0.7));
+
+ this.layout.addFooter(tip);
+ this.layout.refreshPositions();
+ this.layout.forEachChild(this::addDrawableChild);
+ }
+
+ @Override
+ protected void initTabNavigation() {
+ this.layout.refreshPositions();
+ }
+
+ private void openConfig() {
+ this.client.setScreen(SkyblockerConfigManager.createGUI(this));
+ }
+
+ @Override
+ public void render(DrawContext context, int mouseX, int mouseY, float delta) {
+ this.renderBackground(context, mouseX, mouseY, delta);
+ super.render(context, mouseX, mouseY, delta);
+ }
+
+ private static class IconTextWidget extends TextWidget {
+ private final Identifier icon;
+
+ IconTextWidget(Text message, TextRenderer textRenderer, Identifier icon) {
+ super(message, textRenderer);
+ this.icon = icon;
+ }
+
+ @Override
+ public void renderWidget(DrawContext context, int mouseX, int mouseY, float delta) {
+ Text text = this.getMessage();
+ TextRenderer textRenderer = this.getTextRenderer();
+
+ int width = this.getWidth();
+ int textWidth = textRenderer.getWidth(text);
+ float horizontalAlignment = 0.5f; // default
+ //17 = (32 + 2) / 2 • 32 + 2 is the width of the icon + spacing between icon and text
+ int x = this.getX() + 17 + Math.round(horizontalAlignment * (float) (width - textWidth));
+ int y = this.getY() + (this.getHeight() - textRenderer.fontHeight) / 2;
+ OrderedText orderedText = textWidth > width ? this.trim(text, width) : text.asOrderedText();
+
+ int iconX = x - 34;
+ int iconY = y - 13;
+
+ context.drawTextWithShadow(textRenderer, orderedText, x, y, this.getTextColor());
+ context.drawTexture(this.icon, iconX, iconY, 0, 0, 32, 32, 32, 32);
+ }
+
+ private OrderedText trim(Text text, int width) {
+ TextRenderer textRenderer = this.getTextRenderer();
+ StringVisitable stringVisitable = textRenderer.trimToWidth(text, width - textRenderer.getWidth(ScreenTexts.ELLIPSIS));
+ return Language.getInstance().reorder(StringVisitable.concat(stringVisitable, ScreenTexts.ELLIPSIS));
+ }
+ }
+}
diff --git a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java
index 418cc4d1..bf98ac1f 100644
--- a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java
+++ b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java
@@ -1071,6 +1071,8 @@ public class SkyblockerConfig {
}
public static class TheEnd {
+ @SerialEntry
+ public boolean enableEnderNodeHelper = true;
@SerialEntry
public boolean hudEnabled = true;
diff --git a/src/main/java/de/hysky/skyblocker/config/categories/LocationsCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/LocationsCategory.java
index 67512b78..46f3067c 100644
--- a/src/main/java/de/hysky/skyblocker/config/categories/LocationsCategory.java
+++ b/src/main/java/de/hysky/skyblocker/config/categories/LocationsCategory.java
@@ -85,6 +85,13 @@ public class LocationsCategory {
.name(Text.translatable("text.autoconfig.skyblocker.option.locations.end"))
.collapsed(false)
.option(Option.<Boolean>createBuilder()
+ .name(Text.translatable("text.autoconfig.skyblocker.option.locations.end.enableEnderNodeHelper"))
+ .binding(defaults.locations.end.enableEnderNodeHelper,
+ () -> config.locations.end.enableEnderNodeHelper,
+ newValue -> config.locations.end.enableEnderNodeHelper = newValue)
+ .controller(ConfigUtils::createBooleanController)
+ .build())
+ .option(Option.<Boolean>createBuilder()
.name(Text.translatable("text.autoconfig.skyblocker.option.locations.end.hudEnabled"))
.binding(defaults.locations.end.hudEnabled,
() -> config.locations.end.hudEnabled,
diff --git a/src/main/java/de/hysky/skyblocker/mixin/ClientPlayNetworkHandlerMixin.java b/src/main/java/de/hysky/skyblocker/mixin/ClientPlayNetworkHandlerMixin.java
index 8397292b..743f949f 100644
--- a/src/main/java/de/hysky/skyblocker/mixin/ClientPlayNetworkHandlerMixin.java
+++ b/src/main/java/de/hysky/skyblocker/mixin/ClientPlayNetworkHandlerMixin.java
@@ -7,6 +7,7 @@ import de.hysky.skyblocker.skyblock.FishingHelper;
import de.hysky.skyblocker.skyblock.dungeon.DungeonScore;
import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonManager;
import de.hysky.skyblocker.skyblock.end.BeaconHighlighter;
+import de.hysky.skyblocker.skyblock.end.EnderNodes;
import de.hysky.skyblocker.skyblock.end.TheEnd;
import de.hysky.skyblocker.skyblock.waypoint.MythologicalRitual;
import de.hysky.skyblocker.utils.SlayerUtils;
@@ -91,6 +92,7 @@ public abstract class ClientPlayNetworkHandlerMixin {
@Inject(method = "onParticle", at = @At("RETURN"))
private void skyblocker$onParticle(ParticleS2CPacket packet, CallbackInfo ci) {
MythologicalRitual.onParticle(packet);
+ EnderNodes.onParticle(packet);
}
@ModifyExpressionValue(method = "onEntityStatus", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/packet/s2c/play/EntityStatusS2CPacket;getEntity(Lnet/minecraft/world/World;)Lnet/minecraft/entity/Entity;"))
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/Tips.java b/src/main/java/de/hysky/skyblocker/skyblock/Tips.java
index c483555e..513dc4b7 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/Tips.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/Tips.java
@@ -103,7 +103,7 @@ public class Tips {
.append(Text.translatable("skyblocker.tips.clickDisable").styled(style -> style.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/skyblocker tips disable"))));
}
- private static Text nextTipInternal() {
+ public static Text nextTipInternal() {
int randomInt = RANDOM.nextInt(TIPS.size());
while (randomInt == previousTipIndex) randomInt = RANDOM.nextInt(TIPS.size());
previousTipIndex = randomInt;
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/end/EnderNodes.java b/src/main/java/de/hysky/skyblocker/skyblock/end/EnderNodes.java
new file mode 100644
index 00000000..b4af7256
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/skyblock/end/EnderNodes.java
@@ -0,0 +1,138 @@
+package de.hysky.skyblocker.skyblock.end;
+
+import de.hysky.skyblocker.config.SkyblockerConfigManager;
+import de.hysky.skyblocker.utils.Utils;
+import de.hysky.skyblocker.utils.scheduler.Scheduler;
+import de.hysky.skyblocker.utils.waypoint.Waypoint;
+import it.unimi.dsi.fastutil.ints.IntIntMutablePair;
+import it.unimi.dsi.fastutil.ints.IntIntPair;
+import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
+import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;
+import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
+import net.fabricmc.fabric.api.event.player.AttackBlockCallback;
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.network.packet.s2c.play.ParticleS2CPacket;
+import net.minecraft.particle.ParticleType;
+import net.minecraft.particle.ParticleTypes;
+import net.minecraft.util.ActionResult;
+import net.minecraft.util.DyeColor;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.util.math.Direction;
+import net.minecraft.util.math.MathHelper;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class EnderNodes {
+ private static final MinecraftClient client = MinecraftClient.getInstance();
+ private static final Map<BlockPos, EnderNode> enderNodes = new HashMap<>();
+
+ public static void init() {
+ Scheduler.INSTANCE.scheduleCyclic(EnderNodes::update, 20);
+ WorldRenderEvents.AFTER_TRANSLUCENT.register(EnderNodes::render);
+ AttackBlockCallback.EVENT.register((player, world, hand, pos, direction) -> {
+ enderNodes.remove(pos);
+ return ActionResult.PASS;
+ });
+ ClientPlayConnectionEvents.JOIN.register((handler, sender, client) -> reset());
+ }
+
+ public static void onParticle(ParticleS2CPacket packet) {
+ if (!shouldProcess()) return;
+ ParticleType<?> particleType = packet.getParameters().getType();
+ if (!ParticleTypes.PORTAL.getType().equals(particleType) && !ParticleTypes.WITCH.getType().equals(particleType))
+ return;
+
+ double x = packet.getX();
+ double y = packet.getY();
+ double z = packet.getZ();
+ double xFrac = MathHelper.floorMod(x, 1);
+ double yFrac = MathHelper.floorMod(y, 1);
+ double zFrac = MathHelper.floorMod(z, 1);
+ BlockPos pos;
+ Direction direction;
+ if (yFrac == 0.25) {
+ pos = BlockPos.ofFloored(x, y - 1, z);
+ direction = Direction.UP;
+ } else if (yFrac == 0.75) {
+ pos = BlockPos.ofFloored(x, y + 1, z);
+ direction = Direction.DOWN;
+ } else if (xFrac == 0.25) {
+ pos = BlockPos.ofFloored(x - 1, y, z);
+ direction = Direction.EAST;
+ } else if (xFrac == 0.75) {
+ pos = BlockPos.ofFloored(x + 1, y, z);
+ direction = Direction.WEST;
+ } else if (zFrac == 0.25) {
+ pos = BlockPos.ofFloored(x, y, z - 1);
+ direction = Direction.SOUTH;
+ } else if (zFrac == 0.75) {
+ pos = BlockPos.ofFloored(x, y, z + 1);
+ direction = Direction.NORTH;
+ } else {
+ return;
+ }
+
+ EnderNode enderNode = enderNodes.computeIfAbsent(pos, EnderNode::new);
+ IntIntPair particles = enderNode.particles.get(direction);
+ particles.left(particles.leftInt() + 1);
+ particles.right(particles.rightInt() + 1);
+ }
+
+ private static void update() {
+ if (shouldProcess()) {
+ for (EnderNode enderNode : enderNodes.values()) {
+ enderNode.updateParticles();
+ }
+ }
+ }
+
+ private static void render(WorldRenderContext context) {
+ if (shouldProcess()) {
+ for (EnderNode enderNode : enderNodes.values()) {
+ if (enderNode.shouldRender()) {
+ enderNode.render(context);
+ }
+ }
+ }
+ }
+
+ private static boolean shouldProcess() {
+ return SkyblockerConfigManager.get().locations.end.enableEnderNodeHelper && Utils.isInTheEnd();
+ }
+
+ private static void reset() {
+ enderNodes.clear();
+ }
+
+ public static class EnderNode extends Waypoint {
+ private final Map<Direction, IntIntPair> particles = Map.of(
+ Direction.UP, new IntIntMutablePair(0, 0),
+ Direction.DOWN, new IntIntMutablePair(0, 0),
+ Direction.EAST, new IntIntMutablePair(0, 0),
+ Direction.WEST, new IntIntMutablePair(0, 0),
+ Direction.SOUTH, new IntIntMutablePair(0, 0),
+ Direction.NORTH, new IntIntMutablePair(0, 0)
+ );
+ private long lastConfirmed;
+
+ private EnderNode(BlockPos pos) {
+ super(pos, () -> SkyblockerConfigManager.get().general.waypoints.waypointType, DyeColor.CYAN.getColorComponents(), false);
+ }
+
+ private void updateParticles() {
+ long currentTimeMillis = System.currentTimeMillis();
+ if (lastConfirmed + 2000 > currentTimeMillis || client.world == null || !particles.entrySet().stream().allMatch(entry -> entry.getValue().leftInt() >= 5 && entry.getValue().rightInt() >= 5 || !client.world.getBlockState(pos.offset(entry.getKey())).isAir())) return;
+ lastConfirmed = currentTimeMillis;
+ for (Map.Entry<Direction, IntIntPair> entry : particles.entrySet()) {
+ entry.getValue().left(0);
+ entry.getValue().right(0);
+ }
+ }
+
+ @Override
+ public boolean shouldRender() {
+ return super.shouldRender() && lastConfirmed + 5000 > System.currentTimeMillis();
+ }
+ }
+}