Skip to content
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ Folgende Funktionen sind nur für Spieler ohne Premium-Rang verfügbar, da Spiel
- Für den Pizzalieferanten-Job wird `/getpizza` automatisch ausgeführt, bis 10 Pizzen gesammelt wurden
- Es werden Countdowns angezeigt, bis ein Job wieder ausgeführt werden kann
- Aktive Mining XP-Booster werden angezeigt
- Das Angel-Captcha wird zusätzlich in der Mitte des Bildschirms angezeigt, damit es nicht vom Chat verdeckt wird
- Nach der erfolgreichen Eingabe des Angel-Captchas wird die Angel automatisch wieder ausgeworfen

### Widgets

Expand Down
8 changes: 8 additions & 0 deletions src/main/java/de/rettichlp/ucutils/common/Storage.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import net.minecraft.component.type.MapIdComponent;
import net.minecraft.entity.vehicle.MinecartEntity;
import net.minecraft.text.Text;
import net.minecraft.util.math.Vec3d;
Expand Down Expand Up @@ -64,6 +65,11 @@ public class Storage {
@Nullable
private Vec3d blackMarketPosition;

@Getter
@Setter
@Nullable
private MapIdComponent captchaMap;

@Getter
@Setter
private boolean carLocked = true;
Expand Down Expand Up @@ -119,6 +125,8 @@ public void print() {
LOGGER.info("activeShutdowns[{}]: {}", this.activeShutdowns.size(), this.activeShutdowns);
// blackMarketPosition
LOGGER.info("blackMarketPosition: {}", this.blackMarketPosition);
// captchaMapImage
LOGGER.info("captchaMap: {}", this.captchaMap);
// countdowns
LOGGER.info("countdowns[{}]: {}", this.countdowns.size(), this.countdowns);
// dealerPosition
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package de.rettichlp.ucutils.listener.impl.job;

import de.rettichlp.ucutils.common.registry.UCUtilsListener;
import de.rettichlp.ucutils.listener.IMessageReceiveListener;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayerInteractionManager;
import net.minecraft.component.type.MapIdComponent;
import net.minecraft.item.ItemStack;
import net.minecraft.item.map.MapState;
import net.minecraft.text.Text;
import org.jetbrains.annotations.Nullable;

import java.awt.image.BufferedImage;
import java.io.File;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static de.rettichlp.ucutils.UCUtils.LOGGER;
import static de.rettichlp.ucutils.UCUtils.player;
import static de.rettichlp.ucutils.UCUtils.storage;
import static java.awt.image.BufferedImage.TYPE_INT_RGB;
import static java.util.regex.Pattern.compile;
import static javax.imageio.ImageIO.write;
import static net.minecraft.block.MapColor.getRenderColor;
import static net.minecraft.component.DataComponentTypes.MAP_ID;
import static net.minecraft.item.FilledMapItem.getMapState;
import static net.minecraft.item.Items.FILLED_MAP;
import static net.minecraft.item.Items.FISHING_ROD;
import static net.minecraft.util.Hand.MAIN_HAND;

@UCUtilsListener
public class AnglerListener implements IMessageReceiveListener {

private static final Pattern ANGLER_CAPTCHA_PATTERN = compile("^\\[AntiBot] Zufällige Überprüfung$");
private static final Pattern ANGLER_CAPTCHA_CONTINUED_PATTERN = compile("^Deine Combo wurde fortgesetzt! \\(\\d+\\)$");

@Override
public boolean onMessageReceive(Text text, String message) {
MinecraftClient client = MinecraftClient.getInstance();

Matcher anglerCaptchaMatcher = ANGLER_CAPTCHA_PATTERN.matcher(message);
if (anglerCaptchaMatcher.find()) {
ItemStack offHandStack = player.getOffHandStack();
if (!offHandStack.isOf(FILLED_MAP)) {
return true;
}

MapIdComponent captchaMap = offHandStack.get(MAP_ID);
storage.setCaptchaMap(captchaMap);

saveCaptchaImage(captchaMap);

return true;
}

Matcher anglerCaptchaContinuedMatcher = ANGLER_CAPTCHA_CONTINUED_PATTERN.matcher(message);
if (anglerCaptchaContinuedMatcher.find()) {
storage.setCaptchaMap(null);

ClientPlayerInteractionManager interactionManager = client.interactionManager;
if (interactionManager == null || !player.getMainHandStack().isOf(FISHING_ROD)) {
return true;
}

interactionManager.interactItem(player, MAIN_HAND);
player.swingHand(MAIN_HAND);
return true;
}

return true;
}

private void saveCaptchaImage(MapIdComponent captchaMap) {
BufferedImage mapImage = getMapImage(captchaMap);
if (mapImage == null) {
return;
}

File outputFile = new File("screenshots/ucutils/captcha.png");

try {
outputFile.mkdirs();
outputFile.createNewFile();
write(mapImage, "PNG", outputFile);
} catch (Exception e) {
LOGGER.error("Failed to save captcha image", e);
}
}

private @Nullable BufferedImage getMapImage(MapIdComponent mapIdComponent) {
MapState mapState = getMapState(mapIdComponent, MinecraftClient.getInstance().world);
if (mapState == null) {
return null;
}

BufferedImage mapImage = new BufferedImage(128, 128, TYPE_INT_RGB);

for (int i = 0; i < mapState.colors.length; i++) {
int x = i % 128;
int y = i / 128;

int argb = getRenderColor(mapState.colors[i]);
mapImage.setRGB(x, y, argb);
}

return mapImage;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package de.rettichlp.ucutils.listener.impl.job;

import de.rettichlp.ucutils.common.registry.UCUtilsListener;
import de.rettichlp.ucutils.listener.IMessageReceiveListener;
import de.rettichlp.ucutils.listener.INaviSpotReachedListener;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.minecraft.text.Text;
import net.minecraft.util.math.BlockPos;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static de.rettichlp.ucutils.UCUtils.commandService;
import static de.rettichlp.ucutils.UCUtils.player;
import static java.lang.Double.compare;
import static java.util.Arrays.stream;
import static java.util.regex.Pattern.compile;

@UCUtilsListener
public class DeepSeaFisherListener implements IMessageReceiveListener, INaviSpotReachedListener {

private static final Pattern DEEP_SEA_FISHER_START_PATTERN = compile("^\\[Fischer] Mit /findschwarm kannst du dir den nächsten Fischschwarm anzeigen lassen\\.$");
private static final Pattern DEEP_SEA_FISHER_SPOT_FOUND_PATTERN = compile("^\\[Fischer] Du hast einen Fischschwarm gefunden!$");
private static final Pattern DEEP_SEA_FISHER_SPOT_LOST_PATTERN = compile("^\\[Fischer] Du hast dich dem Fischschwarm zu weit entfernt\\.$");
private static final Pattern DEEP_SEA_FISHER_CATCH_SUCCESS_PATTERN = compile("^\\[Fischer] Du hast \\d+kg frischen Fisch gefangen! \\(\\d+kg\\)$");
private static final Pattern DEEP_SEA_FISHER_CATCH_FAILURE_PATTERN = compile("^\\[Fischer] Du hast das Fischernetz verloren\\.\\.\\.$");
private static final int NET_AMOUNT = 5;

private Collection<DeepSeaFisherJobSpot> visitedDeepSeaFisherJobSpots = new ArrayList<>();
private boolean onDeepSeaFisherSpot = false;
private boolean canCatchFish = true;

@Override
public boolean onMessageReceive(Text text, String message) {
Matcher deepSeaFisherStartMatcher = DEEP_SEA_FISHER_START_PATTERN.matcher(message);
if (deepSeaFisherStartMatcher.find()) {
this.visitedDeepSeaFisherJobSpots = new ArrayList<>();
DeepSeaFisherJobSpot.SPOT_1.startNavigation();
return true;
}

Matcher deepSeaFisherSpotFoundMatcher = DEEP_SEA_FISHER_SPOT_FOUND_PATTERN.matcher(message);
if (deepSeaFisherSpotFoundMatcher.find()) {
commandService.sendCommand("stoproute");
this.onDeepSeaFisherSpot = true;

if (this.canCatchFish) {
startFishing();
}

return true;
}

Matcher deepSeaFisherSpotLostMatcher = DEEP_SEA_FISHER_SPOT_LOST_PATTERN.matcher(message);
if (deepSeaFisherSpotLostMatcher.find()) {
this.onDeepSeaFisherSpot = false;
return true;
}

Matcher deepSeaFisherCatchSuccessMatcher = DEEP_SEA_FISHER_CATCH_SUCCESS_PATTERN.matcher(message);
Matcher deepSeaFisherCatchFailureMatcher = DEEP_SEA_FISHER_CATCH_FAILURE_PATTERN.matcher(message);
if (deepSeaFisherCatchSuccessMatcher.find() || deepSeaFisherCatchFailureMatcher.find()) {
this.canCatchFish = true;

// if already on the next fishing spot, start fishing again
if (this.onDeepSeaFisherSpot) {
startFishing();
}
}

return true;
}

@Override
public void onNaviSpotReached() {
if (this.visitedDeepSeaFisherJobSpots.size() == NET_AMOUNT) {
this.visitedDeepSeaFisherJobSpots = new ArrayList<>();
commandService.sendCommand("dropfish");
}
}

private void startFishing() {
this.onDeepSeaFisherSpot = false;
this.canCatchFish = false;
commandService.sendCommand("catchfish");

// add the current spot to visited spots
getNearestFisherJobSpot(getNotVisitedFisherJobSpots()).ifPresent(this.visitedDeepSeaFisherJobSpots::add);

if (this.visitedDeepSeaFisherJobSpots.size() == NET_AMOUNT) {
return;
}

// get nearest next spot and start navigation
Optional<DeepSeaFisherJobSpot> nearestNextFisherJobSpot = getNearestFisherJobSpot(getNotVisitedFisherJobSpots());
nearestNextFisherJobSpot.ifPresent(DeepSeaFisherJobSpot::startNavigation);
}

private @NotNull Optional<DeepSeaFisherJobSpot> getNearestFisherJobSpot(@NotNull Collection<DeepSeaFisherJobSpot> deepSeaFisherJobSpots) {
return deepSeaFisherJobSpots.stream()
.min((spot1, spot2) -> {
double distance1 = player.squaredDistanceTo(spot1.getPosition().getX(), spot1.getPosition().getY(), spot1.getPosition().getZ());
double distance2 = player.squaredDistanceTo(spot2.getPosition().getX(), spot2.getPosition().getY(), spot2.getPosition().getZ());
return compare(distance1, distance2);
});
}

private @NotNull @Unmodifiable List<DeepSeaFisherJobSpot> getNotVisitedFisherJobSpots() {
return stream(DeepSeaFisherJobSpot.values())
.filter(deepSeaFisherJobSpot -> !this.visitedDeepSeaFisherJobSpots.contains(deepSeaFisherJobSpot))
.toList();
}

@Getter
@AllArgsConstructor
private enum DeepSeaFisherJobSpot {

SPOT_1(new BlockPos(-571, 63, 160)),
SPOT_2(new BlockPos(-554, 63, 107)),
SPOT_3(new BlockPos(-568, 63, 50)),
SPOT_4(new BlockPos(-522, 63, 10)),
SPOT_5(new BlockPos(-521, 63, 78));

private final BlockPos position;

public void startNavigation() {
String naviCommandString = "navi " + this.position.getX() + "/" + this.position.getY() + "/" + this.position.getZ();
commandService.sendCommand(naviCommandString);
}
}
}
Loading