aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorolim <bobq4582@gmail.com>2024-02-20 12:11:17 +0000
committerolim <bobq4582@gmail.com>2024-02-20 12:11:17 +0000
commit9a3deba1170b8ba4c5fdccc0a6df0788123ce041 (patch)
treed19d7cf6e87def4c9c724c5ca1ce672c40b782ea
parent28299e61238d90d690541e713e1c059e6ec00ed0 (diff)
parent20117e764d3a4f444efd06c846449395caac20aa (diff)
downloadSkyblocker-9a3deba1170b8ba4c5fdccc0a6df0788123ce041.tar.gz
Skyblocker-9a3deba1170b8ba4c5fdccc0a6df0788123ce041.tar.bz2
Skyblocker-9a3deba1170b8ba4c5fdccc0a6df0788123ce041.zip
Merge remote-tracking branch 'upstream/master' into chat-rules
-rw-r--r--.github/workflows/beta.yml12
-rw-r--r--.github/workflows/buildrelease.yml90
-rw-r--r--.github/workflows/webhook_translate.yml4
-rw-r--r--build.gradle60
-rw-r--r--gradle.properties3
-rw-r--r--src/main/java/de/hysky/skyblocker/SkyblockerMod.java10
-rw-r--r--src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java6
-rw-r--r--src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java14
-rw-r--r--src/main/java/de/hysky/skyblocker/mixin/ClientPlayerEntityMixin.java4
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/Kuudra.java1
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/IceFill.java170
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/Silverfish.java181
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/waterboard/Waterboard.java14
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretsTracker.java71
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dwarven/DwarvenHud.java4
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/end/BeaconHighlighter.java19
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java24
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/rift/TheRift.java5
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/searchoverlay/OverlayScreen.java (renamed from src/main/java/de/hysky/skyblocker/skyblock/searchOverlay/OverlayScreen.java)2
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/searchoverlay/SearchOverManager.java (renamed from src/main/java/de/hysky/skyblocker/skyblock/searchOverlay/SearchOverManager.java)14
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/tabhud/util/Ico.java1
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/DungeonSecretWidget.java18
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/SpidersDenServerWidget.java87
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/Http.java14
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/Location.java116
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/Utils.java80
-rw-r--r--src/main/resources/assets/skyblocker/lang/en_us.json8
-rw-r--r--src/main/resources/assets/skyblocker/tabhud/standard/spider_den.json17
-rw-r--r--src/main/resources/resourcepacks/top_aligned/assets/skyblocker/tabhud/standard/spider_den.json17
-rw-r--r--src/test/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/IceFillTest.java29
-rw-r--r--src/test/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/SilverfishTest.java40
-rw-r--r--src/test/java/de/hysky/skyblocker/skyblock/searchoverlay/SplitStringTest.java (renamed from src/test/java/de/hysky/skyblocker/skyblock/searchOverlay/SplitStringTest.java)2
32 files changed, 921 insertions, 216 deletions
diff --git a/.github/workflows/beta.yml b/.github/workflows/beta.yml
index 9f0b8490..7e444cb8 100644
--- a/.github/workflows/beta.yml
+++ b/.github/workflows/beta.yml
@@ -19,9 +19,9 @@ jobs:
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- - uses: actions/github-script@v6
+ - uses: actions/github-script@v7
with:
result-encoding: string
script: |
@@ -31,13 +31,13 @@ jobs:
fs.writeFileSync("./gradle.properties", file);
- name: Set up JDK 17
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
distribution: 'microsoft'
java-version: '17'
- name: Initialize caches
- uses: actions/cache@v3
+ uses: actions/cache@v4
with:
path: |
~/.gradle/caches
@@ -53,7 +53,7 @@ jobs:
- name: Build with Gradle
run: ./gradlew build
- - uses: actions/github-script@v6
+ - uses: actions/github-script@v7
id: fname
with:
result-encoding: string
@@ -61,7 +61,7 @@ jobs:
const fs = require("fs")
return fs.readdirSync("build/libs/").filter(e => !e.endsWith("dev.jar") && !e.endsWith("sources.jar") && e.endsWith(".jar"))[0].replace(".jar", "");
- - uses: actions/upload-artifact@v3
+ - uses: actions/upload-artifact@v4
with:
name: ${{ steps.fname.outputs.result }}
path: build/libs/
diff --git a/.github/workflows/buildrelease.yml b/.github/workflows/buildrelease.yml
index 4a15fe57..b062d079 100644
--- a/.github/workflows/buildrelease.yml
+++ b/.github/workflows/buildrelease.yml
@@ -17,9 +17,9 @@ jobs:
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Set up JDK 17
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
distribution: 'microsoft'
java-version: '17'
@@ -30,7 +30,7 @@ jobs:
- name: Build with Gradle
run: ./gradlew build
- - uses: actions/upload-artifact@v3
+ - uses: actions/upload-artifact@v4
with:
name: Artifacts
path: build/libs/
@@ -46,55 +46,29 @@ jobs:
CHANGELOGtmp="${CHANGELOGtmp//$'\n'/'%0A'}"
CHANGELOGtmp="${CHANGELOGtmp//$'\r'/'%0D'}"
- echo "::set-output name=changelog::$CHANGELOGtmp"
+ # changelog for Github release
+ echo "changelog=$CHANGELOGtmp" >> $GITHUB_OUTPUT
- echo "Changelog:\n$CHANGELOG"
+ #echo "Changelog:\n$CHANGELOG" # for debugging
changelog="${CHANGELOG}"
+ highlight_section=$(echo "$changelog" | awk '/## Highlight/{flag=1;next}/^$/{flag=0}flag')
+ highlight_section="# Highlight\n$highlight_section\n\nhttps://hysky.de/"
- # Because of the 2000 char limit in Discord shorten the changelog
-
- # Calculate the number of characters to delete
- delete_chars=$((${#changelog} + 350 - 2000 - 15))
+ # Format highlight_section with printf
+ highlight_section=$(printf "%s" "$highlight_section")
- # Check if delete_chars is greater than 0
- if [ $delete_chars -gt 0 ]; then
-
- # Extract the "What's Changed" section from the changelog
- changed_section=$(echo "$changelog" | awk '/## What'\''s Changed/{flag=1;next}/^$/{flag=0}flag')
-
- # Trim the changed_section based on the delete_chars value and remove the last line
- modified_section="${changed_section::-delete_chars}"
- modified_section=$(echo "$modified_section" | sed '$d')
-
- # Add "[...] and more" at the end of modified_section
- modified_section+="\n[...] and more"
-
- # Format modified_section with printf
- modified_section=$(printf "%s" "$modified_section")
-
- # Generate the modified_changelog by inserting modified_section after the "What's Changed" section
- modified_changelog=$(awk -v modified_section="$modified_section" '
- /^## What'\''s Changed/ { print; print modified_section; f=1; next }
- f && /^$/ { f=0 }
- !f { print }
- END { if (f) print "" }
- ' ORS='\n' <<< "$changelog")
-
- # Format the modified_changelog by removing "@" characters and enclosing URLs in "<>"
- # modified_changelog=$(echo "$modified_changelog" | sed -e 's/@//g' -e 's|https\?://[^[:space:]]*|<\0>|g')
-
- # Store the modified_changelog in the CHANGELOG variable
- CHANGELOG=$(echo -n "$modified_changelog")
- fi
+ # Store the highlight_section in the CHANGELOG variable
+ CHANGELOG=$(echo -n "$highlight_section")
CHANGELOG="${CHANGELOG//'%'/'%25'}"
CHANGELOG="${CHANGELOG//$'\n'/'%0A'}"
CHANGELOG="${CHANGELOG//$'\r'/'%0D'}"
- echo "::set-output name=changelog_discord::$CHANGELOG"
+ # changelog for rest
+ echo "changelog_highlight=$CHANGELOG" >> $GITHUB_OUTPUT
- - uses: actions/github-script@v6
+ - uses: actions/github-script@v7
id: fname
with:
result-encoding: string
@@ -110,35 +84,13 @@ jobs:
token: ${{ secrets.GH_RELEASE }}
files: build/libs/${{ steps.fname.outputs.result }}
- - name: Publish to Modrinth
- id: modrinth
+ - name: Publish using mod-publish-plugin
+ run: ./gradlew build publishMods
env:
- MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
- CHANGELOG: ${{ steps.read_changelog.outputs.changelog }}
- run: ./gradlew modrinth
-
- - name: Get version tag
- id: version_tag
- run: |
- [[ ! "$GITHUB_REF" =~ refs/tags ]] && exit
- echo "::set-output name=value::${GITHUB_REF#refs/tags/}"
-
- - name: Discord notification
- shell: bash
- run: |
- OUTPUT="
- <@&1134565945482948638>
- ## Skyblocker ${{ steps.version_tag.outputs.value }}
-
- ${{ steps.read_changelog.outputs.changelog_discord }}
-
- :inbox_tray: Download latest version on Modrinth or Github:
- <:modrinth:900697862206287882> ${{ steps.modrinth.outputs.url }}
- <:github:900697885706952725> ${{ steps.uploadrelease.outputs.url }}
-
- https://hysky.de/"
-
- curl -H "Content-Type: application/json" -d '{"content":"'"${OUTPUT//$'\n'/\\n}"'", "flags": 4}' "${{ secrets.DISCORD_WEBHOOK }}"
+ CHANGELOG: ${{ steps.read_changelog.outputs.changelog_highlight }}
+ DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
+ MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
+ CURSEFORGE_TOKEN: ${{ secrets.CURSEFORGE_TOKEN }}
- name: Trigger Modpack
shell: bash
diff --git a/.github/workflows/webhook_translate.yml b/.github/workflows/webhook_translate.yml
index c901c056..5d1208fa 100644
--- a/.github/workflows/webhook_translate.yml
+++ b/.github/workflows/webhook_translate.yml
@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
fetch-depth: 2
@@ -22,7 +22,7 @@ jobs:
with:
go-version: '1.20'
- - uses: actions/cache@v3
+ - uses: actions/cache@v4
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-pkg-mod-${{ hashFiles('go.sum') }}
diff --git a/build.gradle b/build.gradle
index b8349360..d7b37bfe 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,7 +1,7 @@
plugins {
id 'fabric-loom' version '1.5-SNAPSHOT'
id 'maven-publish'
- id 'com.modrinth.minotaur' version '2.+'
+ id "me.modmuss50.mod-publish-plugin" version "0.5.1"
}
version = "${project.mod_version}+${project.minecraft_version}"
@@ -92,13 +92,6 @@ processResources {
}
tasks.withType(JavaCompile).configureEach {
- // ensure that the encoding is set to UTF-8, no matter what the system default is
- // this fixes some edge cases with special characters not displaying correctly
- // see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html
- // If Javadoc is generated, this must be specified in that task too.
-
-
- // Minecraft 1.18 upwards uses Java 17.
it.options.release = 17
}
@@ -122,30 +115,39 @@ test {
useJUnitPlatform()
}
-modrinth {
- token = System.getenv('MODRINTH_TOKEN')
- projectId = project.modrinth_id
- versionNumber = "v${project.version}"
- versionName = "Skyblocker ${project.mod_version} for ${project.minecraft_version}"
- uploadFile = remapJar
- gameVersions = [project.minecraft_version]
- loaders = ["fabric"]
- versionType = "release"
- dependencies {
- required.project "fabric-api"
- optional.project "modmenu"
- optional.project "rei"
- optional.project "emi"
- }
+publishMods {
+ file = remapJar.archiveFile
changelog = System.getenv('CHANGELOG')
- syncBodyFrom = rootProject.file("MRREADME.md").text
-}
+ version = "v${project.version}"
+ displayName = "Skyblocker ${mod_version} for ${minecraft_version}"
+ modLoaders.add("fabric")
+ type = STABLE
+
+ modrinth {
+ accessToken = System.getenv("MODRINTH_TOKEN")
+ projectId = modrinth_id
+ minecraftVersions.add(minecraft_version)
+ announcementTitle = "<:modrinth:900697862206287882> Download from Modrinth"
+ requires("fabric-api")
+ optional("modmenu", "rei", "emi")
+ }
-tasks.modrinth.doLast {
- println "::set-output name=url::https://modrinth.com/mod/skyblocker-liap/version/$uploadInfo.id"
-}
+ curseforge {
+ accessToken = System.getenv("CURSEFORGE_TOKEN")
+ projectId = curseforge_id
+ minecraftVersions.add(minecraft_version)
+ announcementTitle = "<:curseforge:900697838453936149> Download from CurseForge"
+ projectSlug = "skyblocker"
+ requires("fabric-api")
+ optional("roughly-enough-items", "emi")
+ }
-tasks.modrinth.dependsOn(tasks.modrinthSyncBody)
+ discord {
+ webhookUrl = System.getenv("DISCORD_WEBHOOK")
+ username = "Changelog"
+ content = changelog.map { "<@&1134565945482948638>\n## Skyblocker v${mod_version}\n" + it}
+ }
+}
// configure the maven publication
publishing {
diff --git a/gradle.properties b/gradle.properties
index 8459bf8e..07340c99 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -37,4 +37,5 @@ commons_math_version = 3.6.1
mod_version = 1.17.0
maven_group = de.hysky
archives_base_name = skyblocker
-modrinth_id=y6DuFGwJ \ No newline at end of file
+modrinth_id=y6DuFGwJ
+curseforge_id=936169 \ No newline at end of file
diff --git a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java
index fc72ea3f..edd4241e 100644
--- a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java
+++ b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java
@@ -10,25 +10,23 @@ import de.hysky.skyblocker.skyblock.crimson.kuudra.Kuudra;
import de.hysky.skyblocker.skyblock.chat.ChatRulesHandler;
import de.hysky.skyblocker.skyblock.dungeon.*;
import de.hysky.skyblocker.skyblock.dungeon.partyfinder.PartyFinderScreen;
+import de.hysky.skyblocker.skyblock.dungeon.puzzle.*;
import de.hysky.skyblocker.skyblock.dungeon.puzzle.boulder.Boulder;
-import de.hysky.skyblocker.skyblock.dungeon.puzzle.CreeperBeams;
-import de.hysky.skyblocker.skyblock.dungeon.puzzle.DungeonBlaze;
-import de.hysky.skyblocker.skyblock.dungeon.puzzle.TicTacToe;
import de.hysky.skyblocker.skyblock.dungeon.puzzle.waterboard.Waterboard;
import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonManager;
import de.hysky.skyblocker.skyblock.dungeon.secrets.SecretsTracker;
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.TheEnd;
import de.hysky.skyblocker.skyblock.end.BeaconHighlighter;
+import de.hysky.skyblocker.skyblock.end.TheEnd;
import de.hysky.skyblocker.skyblock.item.*;
import de.hysky.skyblocker.skyblock.item.tooltip.BackpackPreview;
import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip;
import de.hysky.skyblocker.skyblock.itemlist.ItemRepository;
import de.hysky.skyblocker.skyblock.quicknav.QuickNav;
import de.hysky.skyblocker.skyblock.rift.TheRift;
-import de.hysky.skyblocker.skyblock.searchOverlay.SearchOverManager;
+import de.hysky.skyblocker.skyblock.searchoverlay.SearchOverManager;
import de.hysky.skyblocker.skyblock.shortcut.Shortcuts;
import de.hysky.skyblocker.skyblock.special.SpecialEffects;
import de.hysky.skyblocker.skyblock.tabhud.TabHud;
@@ -121,6 +119,8 @@ public class SkyblockerMod implements ClientModInitializer {
DungeonManager.init();
DungeonBlaze.init();
Waterboard.init();
+ Silverfish.init();
+ IceFill.init();
DungeonScore.init();
PartyFinderScreen.initClass();
ChestValue.init();
diff --git a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java
index ea1f7d43..4a1fe614 100644
--- a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java
+++ b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java
@@ -723,6 +723,12 @@ public class SkyblockerConfig {
public boolean solveBoulder = true;
@SerialEntry
+ public boolean solveIceFill = true;
+
+ @SerialEntry
+ public boolean solveSilverfish = true;
+
+ @SerialEntry
public boolean fireFreezeStaffTimer = true;
@SerialEntry
diff --git a/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java
index 5eb9a066..3ebd5d76 100644
--- a/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java
+++ b/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java
@@ -417,6 +417,20 @@ public class DungeonsCategory {
.controller(ConfigUtils::createBooleanController)
.build())
.option(Option.<Boolean>createBuilder()
+ .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.solveIceFill"))
+ .binding(defaults.locations.dungeons.solveIceFill,
+ () -> config.locations.dungeons.solveIceFill,
+ newValue -> config.locations.dungeons.solveIceFill = newValue)
+ .controller(ConfigUtils::createBooleanController)
+ .build())
+ .option(Option.<Boolean>createBuilder()
+ .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.solveSilverfish"))
+ .binding(defaults.locations.dungeons.solveSilverfish,
+ () -> config.locations.dungeons.solveSilverfish,
+ newValue -> config.locations.dungeons.solveSilverfish = newValue)
+ .controller(ConfigUtils::createBooleanController)
+ .build())
+ .option(Option.<Boolean>createBuilder()
.name(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.fireFreezeStaffTimer"))
.description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.fireFreezeStaffTimer.@Tooltip")))
.binding(defaults.locations.dungeons.fireFreezeStaffTimer,
diff --git a/src/main/java/de/hysky/skyblocker/mixin/ClientPlayerEntityMixin.java b/src/main/java/de/hysky/skyblocker/mixin/ClientPlayerEntityMixin.java
index 2a4c38a7..ceda9ed4 100644
--- a/src/main/java/de/hysky/skyblocker/mixin/ClientPlayerEntityMixin.java
+++ b/src/main/java/de/hysky/skyblocker/mixin/ClientPlayerEntityMixin.java
@@ -6,8 +6,8 @@ import de.hysky.skyblocker.skyblock.dungeon.partyfinder.PartyFinderScreen;
import de.hysky.skyblocker.skyblock.item.HotbarSlotLock;
import de.hysky.skyblocker.skyblock.item.ItemProtection;
import de.hysky.skyblocker.skyblock.rift.HealingMelonIndicator;
-import de.hysky.skyblocker.skyblock.searchOverlay.OverlayScreen;
-import de.hysky.skyblocker.skyblock.searchOverlay.SearchOverManager;
+import de.hysky.skyblocker.skyblock.searchoverlay.OverlayScreen;
+import de.hysky.skyblocker.skyblock.searchoverlay.SearchOverManager;
import de.hysky.skyblocker.utils.Utils;
import net.minecraft.block.entity.SignBlockEntity;
import net.minecraft.client.MinecraftClient;
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/Kuudra.java b/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/Kuudra.java
index 033a919d..5bc98894 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/Kuudra.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/Kuudra.java
@@ -10,7 +10,6 @@ import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
public class Kuudra {
- public static final String LOCATION = "kuudra";
static KuudraPhase phase = KuudraPhase.OTHER;
public static void init() {
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/IceFill.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/IceFill.java
new file mode 100644
index 00000000..57386674
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/IceFill.java
@@ -0,0 +1,170 @@
+package de.hysky.skyblocker.skyblock.dungeon.puzzle;
+
+import com.google.common.primitives.Booleans;
+import com.mojang.brigadier.Command;
+import de.hysky.skyblocker.SkyblockerMod;
+import de.hysky.skyblocker.config.SkyblockerConfigManager;
+import de.hysky.skyblocker.debug.Debug;
+import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonManager;
+import de.hysky.skyblocker.skyblock.dungeon.secrets.Room;
+import de.hysky.skyblocker.utils.Constants;
+import de.hysky.skyblocker.utils.render.RenderHelper;
+import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
+import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.util.DyeColor;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.util.math.Direction;
+import net.minecraft.util.math.Vec3d;
+import net.minecraft.world.World;
+import org.joml.Vector2i;
+import org.joml.Vector2ic;
+
+import java.util.*;
+import java.util.concurrent.CompletableFuture;
+
+import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal;
+
+public class IceFill extends DungeonPuzzle {
+ public static final IceFill INSTANCE = new IceFill();
+ private static final float[] RED_COLOR_COMPONENTS = DyeColor.RED.getColorComponents();
+ private static final BlockPos[] BOARD_ORIGINS = {
+ new BlockPos(16, 70, 9),
+ new BlockPos(17, 71, 16),
+ new BlockPos(18, 72, 25)
+ };
+ private CompletableFuture<Void> solve;
+ private final boolean[][][] iceFillBoards = {new boolean[3][3], new boolean[5][5], new boolean[7][7]};
+ private final List<List<Vector2ic>> iceFillPaths = List.of(new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
+
+ private IceFill() {
+ super("ice-fill", "ice-path");
+ }
+
+ public static void init() {
+ if (Debug.debugEnabled()) {
+ ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> dispatcher.register(literal(SkyblockerMod.NAMESPACE).then(literal("dungeons").then(literal("puzzle").then(literal(INSTANCE.puzzleName)
+ .then(literal("printBoard1").executes(context -> {
+ context.getSource().sendFeedback(Constants.PREFIX.get().append(boardToString(INSTANCE.iceFillBoards[0])));
+ return Command.SINGLE_SUCCESS;
+ })).then(literal("printBoard2").executes(context -> {
+ context.getSource().sendFeedback(Constants.PREFIX.get().append(boardToString(INSTANCE.iceFillBoards[1])));
+ return Command.SINGLE_SUCCESS;
+ })).then(literal("printBoard3").executes(context -> {
+ context.getSource().sendFeedback(Constants.PREFIX.get().append(boardToString(INSTANCE.iceFillBoards[2])));
+ return Command.SINGLE_SUCCESS;
+ })).then(literal("printPath1").executes(context -> {
+ context.getSource().sendFeedback(Constants.PREFIX.get().append(INSTANCE.iceFillPaths.get(0).toString()));
+ return Command.SINGLE_SUCCESS;
+ })).then(literal("printPath2").executes(context -> {
+ context.getSource().sendFeedback(Constants.PREFIX.get().append(INSTANCE.iceFillPaths.get(1).toString()));
+ return Command.SINGLE_SUCCESS;
+ })).then(literal("printPath3").executes(context -> {
+ context.getSource().sendFeedback(Constants.PREFIX.get().append(INSTANCE.iceFillPaths.get(2).toString()));
+ return Command.SINGLE_SUCCESS;
+ }))
+ )))));
+ }
+ }
+
+ private static String boardToString(boolean[][] iceFillBoard) {
+ StringBuilder sb = new StringBuilder();
+ for (boolean[] row : iceFillBoard) {
+ sb.append("\n");
+ for (boolean cell : row) {
+ sb.append(cell ? '#' : '.');
+ }
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public void tick(MinecraftClient client) {
+ if (!SkyblockerConfigManager.get().locations.dungeons.solveIceFill || client.world == null || !DungeonManager.isCurrentRoomMatched() || solve != null && !solve.isDone()) {
+ return;
+ }
+ Room room = DungeonManager.getCurrentRoom();
+
+ solve = CompletableFuture.runAsync(() -> {
+ BlockPos.Mutable pos = new BlockPos.Mutable();
+ for (int i = 0; i < 3; i++) {
+ if (updateBoard(client.world, room, iceFillBoards[i], pos.set(BOARD_ORIGINS[i]))) {
+ solve(iceFillBoards[i], iceFillPaths.get(i));
+ }
+ }
+ });
+ }
+
+ private boolean updateBoard(World world, Room room, boolean[][] iceFillBoard, BlockPos.Mutable pos) {
+ boolean boardChanged = false;
+ for (int row = 0; row < iceFillBoard.length; pos.move(iceFillBoard[row].length, 0, -1), row++) {
+ for (int col = 0; col < iceFillBoard[row].length; pos.move(Direction.WEST), col++) {
+ BlockPos actualPos = room.relativeToActual(pos);
+ boolean isBlock = !world.getBlockState(actualPos).isAir();
+ if (iceFillBoard[row][col] != isBlock) {
+ iceFillBoard[row][col] = isBlock;
+ boardChanged = true;
+ }
+ }
+ }
+ return boardChanged;
+ }
+
+ void solve(boolean[][] iceFillBoard, List<Vector2ic> iceFillPath) {
+ Vector2ic start = new Vector2i(iceFillBoard.length - 1, iceFillBoard[0].length / 2);
+ int count = iceFillBoard.length * iceFillBoard[0].length - Arrays.stream(iceFillBoard).mapToInt(Booleans::countTrue).sum();
+
+ List<Vector2ic> newPath = solveDfs(iceFillBoard, count - 1, new ArrayList<>(List.of(start)), new HashSet<>(List.of(start)));
+ if (newPath != null) {
+ iceFillPath.clear();
+ iceFillPath.addAll(newPath);
+ }
+ }
+
+ private List<Vector2ic> solveDfs(boolean[][] iceFillBoard, int count, List<Vector2ic> path, Set<Vector2ic> visited) {
+ Vector2ic pos = path.get(path.size() - 1);
+ if (count == 0) {
+ if (pos.x() == 0 && pos.y() == iceFillBoard[0].length / 2) {
+ return path;
+ } else {
+ return null;
+ }
+ }
+
+ Vector2ic[] newPosArray = {pos.add(1, 0, new Vector2i()), pos.add(-1, 0, new Vector2i()), pos.add(0, 1, new Vector2i()), pos.add(0, -1, new Vector2i())};
+ for (Vector2ic newPos : newPosArray) {
+ if (newPos.x() >= 0 && newPos.x() < iceFillBoard.length && newPos.y() >= 0 && newPos.y() < iceFillBoard[0].length && !iceFillBoard[newPos.x()][newPos.y()] && !visited.contains(newPos)) {
+ path.add(newPos);
+ visited.add(newPos);
+ List<Vector2ic> newPath = solveDfs(iceFillBoard, count - 1, path, visited);
+ if (newPath != null) {
+ return newPath;
+ }
+ path.remove(path.size() - 1);
+ visited.remove(newPos);
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public void render(WorldRenderContext context) {
+ if (!SkyblockerConfigManager.get().locations.dungeons.solveIceFill || !DungeonManager.isCurrentRoomMatched()) {
+ return;
+ }
+ Room room = DungeonManager.getCurrentRoom();
+ for (int i = 0; i < 3; i++) {
+ renderPath(context, room, iceFillPaths.get(i), BOARD_ORIGINS[i]);
+ }
+ }
+
+ private void renderPath(WorldRenderContext context, Room room, List<Vector2ic> iceFillPath, BlockPos originPos) {
+ BlockPos.Mutable pos = new BlockPos.Mutable();
+ for (int i = 0; i < iceFillPath.size() - 1; i++) {
+ Vec3d start = Vec3d.ofCenter(room.relativeToActual(pos.set(originPos).move(-iceFillPath.get(i).y(), 0, -iceFillPath.get(i).x())));
+ Vec3d end = Vec3d.ofCenter(room.relativeToActual(pos.set(originPos).move(-iceFillPath.get(i + 1).y(), 0, -iceFillPath.get(i + 1).x())));
+ RenderHelper.renderLinesFromPoints(context, new Vec3d[]{start, end}, RED_COLOR_COMPONENTS, 1f, 5f, true);
+ }
+ }
+}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/Silverfish.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/Silverfish.java
new file mode 100644
index 00000000..b5cbc8ee
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/Silverfish.java
@@ -0,0 +1,181 @@
+package de.hysky.skyblocker.skyblock.dungeon.puzzle;
+
+import com.mojang.brigadier.Command;
+import de.hysky.skyblocker.SkyblockerMod;
+import de.hysky.skyblocker.config.SkyblockerConfigManager;
+import de.hysky.skyblocker.debug.Debug;
+import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonManager;
+import de.hysky.skyblocker.skyblock.dungeon.secrets.Room;
+impor