From 3a2380330ada2a2c57e18c1bdf24aed9be2ed996 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Mon, 18 May 2026 20:53:13 +0200 Subject: [PATCH 01/96] Add HandledScreenMixin to render custom button for inventory interactions --- .../ucutils/mixin/HandledScreenMixin.java | 89 +++++++++++++++++++ src/main/resources/ucutils.mixins.json | 1 + 2 files changed, 90 insertions(+) create mode 100644 src/main/java/de/rettichlp/ucutils/mixin/HandledScreenMixin.java diff --git a/src/main/java/de/rettichlp/ucutils/mixin/HandledScreenMixin.java b/src/main/java/de/rettichlp/ucutils/mixin/HandledScreenMixin.java new file mode 100644 index 00000000..11dd15d8 --- /dev/null +++ b/src/main/java/de/rettichlp/ucutils/mixin/HandledScreenMixin.java @@ -0,0 +1,89 @@ +package de.rettichlp.ucutils.mixin; + +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.screen.ingame.HandledScreen; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.component.type.LoreComponent; +import net.minecraft.screen.GenericContainerScreenHandler; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.screen.slot.Slot; +import net.minecraft.text.Text; +import org.jetbrains.annotations.NotNull; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.regex.Matcher; + +import static de.rettichlp.ucutils.UCUtils.commandService; +import static java.lang.Integer.parseInt; +import static java.util.regex.Pattern.compile; +import static net.minecraft.component.DataComponentTypes.LORE; +import static net.minecraft.text.Text.literal; + +@Mixin(HandledScreen.class) +public abstract class HandledScreenMixin extends Screen { + + @Shadow + protected int backgroundWidth; + + @Shadow + protected int backgroundHeight; + + protected HandledScreenMixin(Text title) { + super(title); + } + + @Inject(method = "render", at = @At("TAIL")) + private void ucutils$renderTail(DrawContext context, int mouseX, int mouseY, float deltaTicks, CallbackInfo ci) { + HandledScreen self = (HandledScreen) (Object) this; + ScreenHandler screenHandler = self.getScreenHandler(); + + String title = self.getTitle().getString(); + + switch (screenHandler) { + case GenericContainerScreenHandler genericContainerScreenHandler -> { + switch (title) { + case "ʟᴀɢᴇʀ" -> { + int ingredient1StoredAmount = getStoredAmount(genericContainerScreenHandler, 11); + int ingredient2StoredAmount = getStoredAmount(genericContainerScreenHandler, 13); + int ingredient3StoredAmount = getStoredAmount(genericContainerScreenHandler, 15); + + int x = (this.width - this.backgroundWidth) / 2; + int y = (this.height - this.backgroundHeight) / 2; + int buttonX = x + this.backgroundWidth + 4; + + // render button right to the inventory + ButtonWidget buttonWidget = new ButtonWidget.Builder(literal("➤"), button -> commandService.sendCommand("f Lager: " + ingredient1StoredAmount + "x Wirkstoff " + ingredient2StoredAmount + "x Trägerstoff " + ingredient3StoredAmount + "x Zusatzstoff")) + .dimensions(buttonX, y, 20, 20) + .build(); + + buttonWidget.render(context, mouseX, mouseY, deltaTicks); + + addDrawableChild(buttonWidget); + } + } + } + case null, default -> { + } + } + } + + @Unique + private int getStoredAmount(@NotNull ScreenHandler screenHandler, int slotId) { + Slot slot = screenHandler.slots.get(slotId); + LoreComponent loreComponent = slot.getStack().get(LORE); + + if (loreComponent == null) { + return 0; + } + + String amountString = loreComponent.lines().get(1).getString(); + Matcher matcher = compile("\\d+").matcher(amountString); + return matcher.find() ? parseInt(matcher.group()) : 0; + } +} diff --git a/src/main/resources/ucutils.mixins.json b/src/main/resources/ucutils.mixins.json index 98728688..cc051e11 100644 --- a/src/main/resources/ucutils.mixins.json +++ b/src/main/resources/ucutils.mixins.json @@ -19,6 +19,7 @@ "ClientPlayNetworkHandlerMixin", "DialogScreenMixin", "GameMenuScreenMixin", + "HandledScreenMixin", "InGameHudMixin", "MinecraftClientMixin", "PlayerEntityRendererMixin", From 1480efabb1b0ff70866761e43ddff77d0eb1bc5e Mon Sep 17 00:00:00 2001 From: RettichLP Date: Mon, 18 May 2026 21:10:55 +0200 Subject: [PATCH 02/96] Update README to document new EMS inventory button functionality for faction chat --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 449b701e..7eb88162 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,7 @@ reibungsloser und angenehmer gestalten. - Eine Plantage kann durch einen Rechtsklick mit einem Wassereimer oder Dünger direkt gewässert beziehungsweise gedüngt werden - Der Rettungsdienst kann durch einen Rechtsklick auf eine bewusstlose Person diese wiederbeleben - Mit `/fbank einzahlen ` kann das Eingabe GUI des Servers übersprungen werden +- Für den Rettungsdienst gibt es im Herstellungs-Inventar für Medikamente einen Button, um die benötigte Anzahl an Stoffen in den Fraktionschat zu senden ### Jobs From c849fbcc27434166e3e11af0443c0939e8274291 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Tue, 19 May 2026 21:19:05 +0200 Subject: [PATCH 03/96] Remove house ban functionality and related code --- .../de/rettichlp/ucutils/common/Storage.java | 6 -- .../configuration/options/NameTagOptions.java | 1 - .../screens/options/NameTagOptionsScreen.java | 7 --- .../ucutils/common/models/HousebanEntry.java | 16 ----- .../listener/impl/faction/MedicListener.java | 63 ------------------- .../rettichlp/ucutils/mixin/EntityMixin.java | 14 ----- .../mixin/PlayerEntityRendererMixin.java | 8 --- .../resources/assets/ucutils/lang/de_de.json | 2 - .../resources/assets/ucutils/lang/en_gb.json | 2 - .../resources/assets/ucutils/lang/en_us.json | 2 - 10 files changed, 121 deletions(-) delete mode 100644 src/main/java/de/rettichlp/ucutils/common/models/HousebanEntry.java diff --git a/src/main/java/de/rettichlp/ucutils/common/Storage.java b/src/main/java/de/rettichlp/ucutils/common/Storage.java index 246743a4..90cf2a91 100644 --- a/src/main/java/de/rettichlp/ucutils/common/Storage.java +++ b/src/main/java/de/rettichlp/ucutils/common/Storage.java @@ -9,7 +9,6 @@ import de.rettichlp.ucutils.common.models.Faction; import de.rettichlp.ucutils.common.models.FactionEntry; import de.rettichlp.ucutils.common.models.FactionMember; -import de.rettichlp.ucutils.common.models.HousebanEntry; import de.rettichlp.ucutils.common.models.Ingredient; import de.rettichlp.ucutils.common.models.Job; import de.rettichlp.ucutils.common.models.PlantEntry; @@ -68,9 +67,6 @@ public class Storage { @Getter private final Set factionEntries = new HashSet<>(); - @Getter - private final List housebanEntries = new ArrayList<>(); - @Getter private final Map> inventory = new HashMap<>(); @@ -171,8 +167,6 @@ public void print() { LOGGER.info("dealers[{}]: {}", this.dealers.size(), this.dealers); // factionEntries this.factionEntries.forEach(factionEntry -> LOGGER.info("factionEntries[{}:{}]: {}", factionEntry.faction(), factionEntry.members().size(), factionEntry.members())); - // housebanEntries - LOGGER.info("housebanEntries[{}]: {}", this.housebanEntries.size(), this.housebanEntries); // inventory this.inventory.forEach((ingredient, ingredientMap) -> LOGGER.info("inventory[{}:{}]: {}", ingredient, ingredientMap.size(), ingredientMap)); // medicBandageCooldowns diff --git a/src/main/java/de/rettichlp/ucutils/common/configuration/options/NameTagOptions.java b/src/main/java/de/rettichlp/ucutils/common/configuration/options/NameTagOptions.java index c99e62bd..3e13068f 100644 --- a/src/main/java/de/rettichlp/ucutils/common/configuration/options/NameTagOptions.java +++ b/src/main/java/de/rettichlp/ucutils/common/configuration/options/NameTagOptions.java @@ -11,7 +11,6 @@ public class NameTagOptions { private boolean aDuty = true; private boolean afk = true; - private boolean houseBan = true; private boolean outlaw = true; private boolean medicalInformation = true; } diff --git a/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/NameTagOptionsScreen.java b/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/NameTagOptionsScreen.java index a504cbc7..41bf4e2d 100644 --- a/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/NameTagOptionsScreen.java +++ b/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/NameTagOptionsScreen.java @@ -18,8 +18,6 @@ public class NameTagOptionsScreen extends OptionsScreen { private static final Text NAMETAG_A_DUTY_TOOLTIP = translatable("ucutils.options.nametag.a_duty.tooltip"); private static final Text NAMETAG_AFK_NAME = translatable("ucutils.options.nametag.afk.name"); private static final Text NAMETAG_AFK_TOOLTIP = translatable("ucutils.options.nametag.afk.tooltip"); - private static final Text NAMETAG_HOUSE_BAN_NAME = translatable("ucutils.options.nametag.house_ban.name"); - private static final Text NAMETAG_HOUSE_BAN_TOOLTIP = translatable("ucutils.options.nametag.house_ban.tooltip"); private static final Text NAMETAG_OUTLAW_NAME = translatable("ucutils.options.nametag.outlaw.name"); private static final Text NAMETAG_OUTLAW_TOOLTIP = translatable("ucutils.options.nametag.outlaw.tooltip"); private static final Text NAMETAG_MEDICAL_INFORMATION_NAME = translatable("ucutils.options.nametag.medical_information.name"); @@ -47,11 +45,6 @@ public void initBody() { toggleButton2.setTooltip(Tooltip.of(NAMETAG_AFK_TOOLTIP)); gridWidgetAdder.add(toggleButton2); - ToggleButtonWidget toggleButton3 = new ToggleButtonWidget(NAMETAG_HOUSE_BAN_NAME, nameTagOptions::houseBan, nameTagOptions.houseBan()); - toggleButton3.setWidth(150); - toggleButton3.setTooltip(Tooltip.of(NAMETAG_HOUSE_BAN_TOOLTIP)); - gridWidgetAdder.add(toggleButton3); - ToggleButtonWidget toggleButton4 = new ToggleButtonWidget(NAMETAG_OUTLAW_NAME, nameTagOptions::outlaw, nameTagOptions.outlaw()); toggleButton4.setWidth(150); toggleButton4.setTooltip(Tooltip.of(NAMETAG_OUTLAW_TOOLTIP)); diff --git a/src/main/java/de/rettichlp/ucutils/common/models/HousebanEntry.java b/src/main/java/de/rettichlp/ucutils/common/models/HousebanEntry.java deleted file mode 100644 index 2639b4d5..00000000 --- a/src/main/java/de/rettichlp/ucutils/common/models/HousebanEntry.java +++ /dev/null @@ -1,16 +0,0 @@ -package de.rettichlp.ucutils.common.models; - -import lombok.AllArgsConstructor; -import lombok.Data; - -import java.time.LocalDateTime; -import java.util.List; - -@Data -@AllArgsConstructor -public class HousebanEntry { - - private String playerName; - private List reasons; - private LocalDateTime unbanDateTime; -} diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/faction/MedicListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/faction/MedicListener.java index 44330438..c8bc7a6e 100644 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/faction/MedicListener.java +++ b/src/main/java/de/rettichlp/ucutils/listener/impl/faction/MedicListener.java @@ -2,16 +2,12 @@ import de.rettichlp.ucutils.common.models.Countdown; import de.rettichlp.ucutils.common.models.Faction; -import de.rettichlp.ucutils.common.models.HousebanEntry; import de.rettichlp.ucutils.common.registry.UCUtilsListener; import de.rettichlp.ucutils.listener.IMessageReceiveListener; import net.minecraft.text.MutableText; import net.minecraft.text.Text; -import org.jetbrains.annotations.NotNull; import java.time.Duration; -import java.time.LocalDateTime; -import java.util.regex.MatchResult; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -23,11 +19,8 @@ import static de.rettichlp.ucutils.UCUtils.utilService; import static de.rettichlp.ucutils.common.models.Sound.FIRE; import static de.rettichlp.ucutils.common.services.CommandService.COMMAND_COOLDOWN_MILLIS; -import static java.lang.Integer.parseInt; import static java.time.Duration.ofMinutes; import static java.time.LocalDateTime.now; -import static java.util.Arrays.asList; -import static java.util.Collections.singletonList; import static java.util.Optional.ofNullable; import static java.util.regex.Pattern.compile; import static net.minecraft.text.Text.of; @@ -44,10 +37,6 @@ public class MedicListener implements IMessageReceiveListener { private static final Pattern MEDIC_PILL_PATTERN = compile("^\\[Medic] Doktor (?:\\[UC])?(?[a-zA-Z0-9_]+) hat dir Schmerzpillen verabreicht\\.$"); private static final Pattern MEDIC_PILL_GIVE_PATTERN = compile("^\\[Medic] Du hast (?:\\[UC])?(?[a-zA-Z0-9_]+) Schmerzpillen verabreicht\\.$"); private static final Pattern MEDIC_REVIVE_START_PATTERN = compile("^Du beginnst mit der Wiederbelebung von (?:\\[UC])?(?[a-zA-Z0-9_]+)\\.\\.\\.$"); - private static final Pattern HOUSEBAN_HEADER_PATTERN = compile("^=== Hausverbote \\(\\d+\\) ===$"); - private static final Pattern HOUSEBAN_ENTRY_PATTERN = compile("^» (?:\\[UC])?(?[a-zA-Z0-9_]+) ➲ (?.+) ➲ \\d+d \\((?\\d+)\\.(?\\d+)\\.(?\\d+) (?\\d+):(?\\d+)\\)$"); - private static final Pattern HOUSEBAN_ADD_PATTERN = compile("^\\[HV] » (?:\\[UC])?(?[a-zA-Z0-9_]+) hat (?:\\[UC])?(?[a-zA-Z0-9_]+)s Hausverbot gegeben\\. » (?.+) » \\d+d \\((?\\d+)\\.(?\\d+)\\.(?\\d+) (?\\d+):(?\\d+)\\)$"); - private static final Pattern HOUSEBAN_REMOVE_PATTERN = compile("^\\[HV] » (?:\\[UC])?(?[a-zA-Z0-9_]+) hat (?:\\[UC])?(?[a-zA-Z0-9_]+)s Hausverbot aufgehoben\\.$"); private static final Pattern FIRST_AID_PATTERN = compile("^\\[Erste-Hilfe] (?:\\[UC])?(?[a-zA-Z0-9_]+) hat dir ein Erste-Hilfe-Schein für 14 Tage ausgestellt\\.$"); private static final Pattern FIRST_AID_LICENCES_PATTERN = compile("^- Erste-Hilfe-Schein: Vorhanden$"); private static final Pattern LABOR_TRANSPORT_STARTED_PATTERN = compile("^\\[ʟᴀʙᴏʀ] Transport gestartet: (?\\d+) ᴋɪsᴛᴇɴ mit (?\\d+) (?.+)$"); @@ -87,43 +76,6 @@ public boolean onMessageReceive(Text text, String message) { return true; } - Matcher housebanHeaderMatcher = HOUSEBAN_HEADER_PATTERN.matcher(message); - if (housebanHeaderMatcher.find()) { - storage.getHousebanEntries().clear(); - return commandService.showCommandOutputMessage("hausverbot"); - } - - Matcher housebanEntryMatcher = HOUSEBAN_ENTRY_PATTERN.matcher(message); - if (housebanEntryMatcher.find()) { - HousebanEntry housebanEntry = getHousebanEntry(housebanEntryMatcher); - storage.getHousebanEntries().add(housebanEntry); - return commandService.showCommandOutputMessage("hausverbot"); - } - - Matcher housebanAddMatcher = HOUSEBAN_ADD_PATTERN.matcher(message); - if (housebanAddMatcher.find()) { - String playerName = housebanAddMatcher.group("playerName"); - String reason = housebanAddMatcher.group("reason"); - int expireDateDay = parseInt(housebanAddMatcher.group("expireDateDay")); - int expireDateMonth = parseInt(housebanAddMatcher.group("expireDateMonth")); - int expireDateYear = parseInt(housebanAddMatcher.group("expireDateYear")); - int expireTimeHour = parseInt(housebanAddMatcher.group("expireTimeHour")); - int expireTimeMinute = parseInt(housebanAddMatcher.group("expireTimeMinute")); - - storage.getHousebanEntries().removeIf(housebanEntry -> housebanEntry.getPlayerName().equals(playerName)); - LocalDateTime unbanDateTime = LocalDateTime.of(expireDateYear, expireDateMonth, expireDateDay, expireTimeHour, expireTimeMinute); - HousebanEntry housebanEntry = new HousebanEntry(playerName, singletonList(reason), unbanDateTime); - storage.getHousebanEntries().add(housebanEntry); - return true; - } - - Matcher housebanRemoveMatcher = HOUSEBAN_REMOVE_PATTERN.matcher(message); - if (housebanRemoveMatcher.find()) { - String playerName = housebanRemoveMatcher.group("playerName"); - storage.getHousebanEntries().removeIf(housebanEntry -> housebanEntry.getPlayerName().equals(playerName)); - return true; - } - Matcher firstAidMatcher = FIRST_AID_PATTERN.matcher(message); if (firstAidMatcher.find()) { configuration.setFirstAidLicenseExpireDateTime(now().plusDays(14)); @@ -157,19 +109,4 @@ public boolean onMessageReceive(Text text, String message) { return true; } - - private @NotNull HousebanEntry getHousebanEntry(@NotNull MatchResult housebanEntryMatcher) { - String playerName = housebanEntryMatcher.group("playerName"); - String reasonsRaw = housebanEntryMatcher.group("reasons"); - int expireDateDay = parseInt(housebanEntryMatcher.group("expireDateDay")); - int expireDateMonth = parseInt(housebanEntryMatcher.group("expireDateMonth")); - int expireDateYear = parseInt(housebanEntryMatcher.group("expireDateYear")); - int expireTimeHour = parseInt(housebanEntryMatcher.group("expireTimeHour")); - int expireTimeMinute = parseInt(housebanEntryMatcher.group("expireTimeMinute")); - - String[] reasons = reasonsRaw.split(" \\+ "); - - LocalDateTime unbanDateTime = LocalDateTime.of(expireDateYear, expireDateMonth, expireDateDay, expireTimeHour, expireTimeMinute); - return new HousebanEntry(playerName, asList(reasons), unbanDateTime); - } } diff --git a/src/main/java/de/rettichlp/ucutils/mixin/EntityMixin.java b/src/main/java/de/rettichlp/ucutils/mixin/EntityMixin.java index 8bc08543..c2c8fa50 100644 --- a/src/main/java/de/rettichlp/ucutils/mixin/EntityMixin.java +++ b/src/main/java/de/rettichlp/ucutils/mixin/EntityMixin.java @@ -4,7 +4,6 @@ import de.rettichlp.ucutils.common.models.BlacklistEntry; import de.rettichlp.ucutils.common.models.ContractEntry; import de.rettichlp.ucutils.common.models.Faction; -import de.rettichlp.ucutils.common.models.HousebanEntry; import de.rettichlp.ucutils.common.models.WantedEntry; import de.rettichlp.ucutils.listener.callback.PlayerEnterVehicleCallback; import net.minecraft.client.network.ClientPlayerEntity; @@ -144,19 +143,6 @@ private MutableText getEnrichedDisplayName(String targetName) { newTargetDisplayNameColor = RED; } - // houseban - Optional optionalTargetHousebanEntry = storage.getHousebanEntries().stream() - .filter(housebanEntry -> housebanEntry.getPlayerName().equals(targetName)) - .filter(housebanEntry -> housebanEntry.getUnbanDateTime().isAfter(now())) - .findAny(); - - if (optionalTargetHousebanEntry.isPresent() && nameTagOptions.houseBan()) { - newTargetDisplayNamePrefix = empty() - .append(of("[").copy().formatted(DARK_GRAY)) - .append(of("HV").copy().formatted(DARK_RED)) - .append(of("]").copy().formatted(DARK_GRAY)); - } - // wanted Optional optionalTargetWantedEntry = storage.getWantedEntries().stream() .filter(wantedEntry -> wantedEntry.getPlayerName().equals(targetName)) diff --git a/src/main/java/de/rettichlp/ucutils/mixin/PlayerEntityRendererMixin.java b/src/main/java/de/rettichlp/ucutils/mixin/PlayerEntityRendererMixin.java index 3567c55d..9f49172d 100644 --- a/src/main/java/de/rettichlp/ucutils/mixin/PlayerEntityRendererMixin.java +++ b/src/main/java/de/rettichlp/ucutils/mixin/PlayerEntityRendererMixin.java @@ -18,7 +18,6 @@ import static de.rettichlp.ucutils.UCUtils.storage; import static de.rettichlp.ucutils.common.services.NameTagService.AFK_TAG; import static de.rettichlp.ucutils.common.services.NameTagService.A_DUTY_TAG; -import static de.rettichlp.ucutils.common.services.NameTagService.HOUSE_BAN_TAG; @Mixin(PlayerEntityRenderer.class) public abstract class PlayerEntityRendererMixin { @@ -67,12 +66,5 @@ public abstract class PlayerEntityRendererMixin { orderedRenderCommandQueue.submitLabel(matrixStack, playerEntityRenderState.nameLabelPos, 0, AFK_TAG, !playerEntityRenderState.sneaking, playerEntityRenderState.light, playerEntityRenderState.squaredDistanceToCamera, cameraRenderState); return; } - - // handle houseban tag - boolean hasHouseBan = storage.getHousebanEntries().stream().anyMatch(housebanEntry -> housebanEntry.getPlayerName().equals(playerName)); - if (configuration.getOptions().nameTag().houseBan() && hasHouseBan) { - matrixStack.translate(0.0F, medicInformationPresent ? 0.8F : 2.6, 0.0F); - orderedRenderCommandQueue.submitLabel(matrixStack, playerEntityRenderState.nameLabelPos, 0, HOUSE_BAN_TAG, !playerEntityRenderState.sneaking, playerEntityRenderState.light, playerEntityRenderState.squaredDistanceToCamera, cameraRenderState); - } } } diff --git a/src/main/resources/assets/ucutils/lang/de_de.json b/src/main/resources/assets/ucutils/lang/de_de.json index 7a0b1810..d1ce27b4 100644 --- a/src/main/resources/assets/ucutils/lang/de_de.json +++ b/src/main/resources/assets/ucutils/lang/de_de.json @@ -68,8 +68,6 @@ "ucutils.options.nametag.a_duty.tooltip": "Zeigt eine Information an über dem Namen von Spielern, die im Admin-Dienst sind", "ucutils.options.nametag.afk.name": "AFK", "ucutils.options.nametag.afk.tooltip": "Zeigt eine Information an über dem Namen von Spielern, die AFK sind", - "ucutils.options.nametag.house_ban.name": "Hausverbot", - "ucutils.options.nametag.house_ban.tooltip": "Zeigt eine Information über dem Namen von Spielern an, die ein Hausverbot haben", "ucutils.options.nametag.outlaw.name": "Vogelfrei", "ucutils.options.nametag.outlaw.tooltip": "Zeigt eine Information über dem Namen von Spielern an, die Vogelfrei sind", "ucutils.options.nametag.medical_information.name": "Information für Ärzte", diff --git a/src/main/resources/assets/ucutils/lang/en_gb.json b/src/main/resources/assets/ucutils/lang/en_gb.json index 92dcf151..32248696 100644 --- a/src/main/resources/assets/ucutils/lang/en_gb.json +++ b/src/main/resources/assets/ucutils/lang/en_gb.json @@ -68,8 +68,6 @@ "ucutils.options.nametag.a_duty.tooltip": "Shows an information above the players name of players in admin duty", "ucutils.options.nametag.afk.name": "AFK", "ucutils.options.nametag.afk.tooltip": "Shows an information above the players name of afk players", - "ucutils.options.nametag.house_ban.name": "House ban", - "ucutils.options.nametag.house_ban.tooltip": "Shows an information above the players name of players with a house ban", "ucutils.options.nametag.outlaw.name": "Outlaw", "ucutils.options.nametag.outlaw.tooltip": "Shows an information above the players name of outlaw players", "ucutils.options.nametag.medical_information.name": "Medical information", diff --git a/src/main/resources/assets/ucutils/lang/en_us.json b/src/main/resources/assets/ucutils/lang/en_us.json index 92dcf151..32248696 100644 --- a/src/main/resources/assets/ucutils/lang/en_us.json +++ b/src/main/resources/assets/ucutils/lang/en_us.json @@ -68,8 +68,6 @@ "ucutils.options.nametag.a_duty.tooltip": "Shows an information above the players name of players in admin duty", "ucutils.options.nametag.afk.name": "AFK", "ucutils.options.nametag.afk.tooltip": "Shows an information above the players name of afk players", - "ucutils.options.nametag.house_ban.name": "House ban", - "ucutils.options.nametag.house_ban.tooltip": "Shows an information above the players name of players with a house ban", "ucutils.options.nametag.outlaw.name": "Outlaw", "ucutils.options.nametag.outlaw.tooltip": "Shows an information above the players name of outlaw players", "ucutils.options.nametag.medical_information.name": "Medical information", From 59d9d26f6568c76c232d6fb3a67f8062fce5ab1d Mon Sep 17 00:00:00 2001 From: RettichLP Date: Tue, 19 May 2026 21:24:08 +0200 Subject: [PATCH 04/96] Remove blacklist and outlaw functionality and related code --- .../de/rettichlp/ucutils/common/Storage.java | 12 ---- .../configuration/options/NameTagOptions.java | 1 - .../screens/options/NameTagOptionsScreen.java | 15 ++--- .../ucutils/common/models/BlacklistEntry.java | 14 ----- .../common/models/BlacklistReason.java | 14 ----- .../impl/faction/BlacklistListener.java | 63 ------------------- .../rettichlp/ucutils/mixin/EntityMixin.java | 20 ------ .../ucutils/mixin/PlayerListHudMixin.java | 10 --- .../resources/assets/ucutils/lang/de_de.json | 2 - .../resources/assets/ucutils/lang/en_gb.json | 2 - .../resources/assets/ucutils/lang/en_us.json | 2 - 11 files changed, 4 insertions(+), 151 deletions(-) delete mode 100644 src/main/java/de/rettichlp/ucutils/common/models/BlacklistEntry.java delete mode 100644 src/main/java/de/rettichlp/ucutils/common/models/BlacklistReason.java delete mode 100644 src/main/java/de/rettichlp/ucutils/listener/impl/faction/BlacklistListener.java diff --git a/src/main/java/de/rettichlp/ucutils/common/Storage.java b/src/main/java/de/rettichlp/ucutils/common/Storage.java index 90cf2a91..4feeb82b 100644 --- a/src/main/java/de/rettichlp/ucutils/common/Storage.java +++ b/src/main/java/de/rettichlp/ucutils/common/Storage.java @@ -1,8 +1,6 @@ package de.rettichlp.ucutils.common; import de.rettichlp.ucutils.common.models.BlackMarket; -import de.rettichlp.ucutils.common.models.BlacklistEntry; -import de.rettichlp.ucutils.common.models.BlacklistReason; import de.rettichlp.ucutils.common.models.ContractEntry; import de.rettichlp.ucutils.common.models.Countdown; import de.rettichlp.ucutils.common.models.Dealer; @@ -46,12 +44,6 @@ public class Storage { @Getter private final List activeShutdowns = new ArrayList<>(); - @Getter - private final List blacklistEntries = new ArrayList<>(); - - @Getter - private final Map> blacklistReasons = new HashMap<>(); - @Getter private final List blackMarkets = new ArrayList<>(); @@ -153,10 +145,6 @@ public class Storage { public void print() { //activeShutdowns LOGGER.info("activeShutdowns[{}]: {}", this.activeShutdowns.size(), this.activeShutdowns); - // blacklistEntries - LOGGER.info("blacklistEntries[{}]: {}", this.blacklistEntries.size(), this.blacklistEntries); - // blacklistReasons - this.blacklistReasons.forEach((faction, blacklistReasons) -> LOGGER.info("blacklistReasons[{}:{}]: {}", faction, blacklistReasons.size(), blacklistReasons)); // blackMarkets LOGGER.info("blackMarkets[{}]: {}", this.blackMarkets.size(), this.blackMarkets); // contractEntries diff --git a/src/main/java/de/rettichlp/ucutils/common/configuration/options/NameTagOptions.java b/src/main/java/de/rettichlp/ucutils/common/configuration/options/NameTagOptions.java index 3e13068f..266d28b6 100644 --- a/src/main/java/de/rettichlp/ucutils/common/configuration/options/NameTagOptions.java +++ b/src/main/java/de/rettichlp/ucutils/common/configuration/options/NameTagOptions.java @@ -11,6 +11,5 @@ public class NameTagOptions { private boolean aDuty = true; private boolean afk = true; - private boolean outlaw = true; private boolean medicalInformation = true; } diff --git a/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/NameTagOptionsScreen.java b/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/NameTagOptionsScreen.java index 41bf4e2d..c29f14d4 100644 --- a/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/NameTagOptionsScreen.java +++ b/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/NameTagOptionsScreen.java @@ -18,8 +18,6 @@ public class NameTagOptionsScreen extends OptionsScreen { private static final Text NAMETAG_A_DUTY_TOOLTIP = translatable("ucutils.options.nametag.a_duty.tooltip"); private static final Text NAMETAG_AFK_NAME = translatable("ucutils.options.nametag.afk.name"); private static final Text NAMETAG_AFK_TOOLTIP = translatable("ucutils.options.nametag.afk.tooltip"); - private static final Text NAMETAG_OUTLAW_NAME = translatable("ucutils.options.nametag.outlaw.name"); - private static final Text NAMETAG_OUTLAW_TOOLTIP = translatable("ucutils.options.nametag.outlaw.tooltip"); private static final Text NAMETAG_MEDICAL_INFORMATION_NAME = translatable("ucutils.options.nametag.medical_information.name"); private static final Text NAMETAG_MEDICAL_INFORMATION_TOOLTIP = translatable("ucutils.options.nametag.medical_information.tooltip"); @@ -45,15 +43,10 @@ public void initBody() { toggleButton2.setTooltip(Tooltip.of(NAMETAG_AFK_TOOLTIP)); gridWidgetAdder.add(toggleButton2); - ToggleButtonWidget toggleButton4 = new ToggleButtonWidget(NAMETAG_OUTLAW_NAME, nameTagOptions::outlaw, nameTagOptions.outlaw()); - toggleButton4.setWidth(150); - toggleButton4.setTooltip(Tooltip.of(NAMETAG_OUTLAW_TOOLTIP)); - gridWidgetAdder.add(toggleButton4); - - ToggleButtonWidget toggleButton5 = new ToggleButtonWidget(NAMETAG_MEDICAL_INFORMATION_NAME, nameTagOptions::medicalInformation, nameTagOptions.medicalInformation()); - toggleButton5.setWidth(150); - toggleButton5.setTooltip(Tooltip.of(NAMETAG_MEDICAL_INFORMATION_TOOLTIP)); - gridWidgetAdder.add(toggleButton5); + ToggleButtonWidget toggleButton3 = new ToggleButtonWidget(NAMETAG_MEDICAL_INFORMATION_NAME, nameTagOptions::medicalInformation, nameTagOptions.medicalInformation()); + toggleButton3.setWidth(150); + toggleButton3.setTooltip(Tooltip.of(NAMETAG_MEDICAL_INFORMATION_TOOLTIP)); + gridWidgetAdder.add(toggleButton3); gridWidget.refreshPositions(); gridWidget.forEachChild(this::addDrawableChild); diff --git a/src/main/java/de/rettichlp/ucutils/common/models/BlacklistEntry.java b/src/main/java/de/rettichlp/ucutils/common/models/BlacklistEntry.java deleted file mode 100644 index 7de0f763..00000000 --- a/src/main/java/de/rettichlp/ucutils/common/models/BlacklistEntry.java +++ /dev/null @@ -1,14 +0,0 @@ -package de.rettichlp.ucutils.common.models; - -import lombok.Getter; - -@Getter -public class BlacklistEntry extends BlacklistReason { - - private final String playerName; - - public BlacklistEntry(String playerName, String reason, boolean outlaw, int kills, int price) { - super(reason, outlaw, kills, price); - this.playerName = playerName; - } -} diff --git a/src/main/java/de/rettichlp/ucutils/common/models/BlacklistReason.java b/src/main/java/de/rettichlp/ucutils/common/models/BlacklistReason.java deleted file mode 100644 index c871d5f2..00000000 --- a/src/main/java/de/rettichlp/ucutils/common/models/BlacklistReason.java +++ /dev/null @@ -1,14 +0,0 @@ -package de.rettichlp.ucutils.common.models; - -import lombok.AllArgsConstructor; -import lombok.Data; - -@Data -@AllArgsConstructor -public class BlacklistReason { - - private final String reason; - private final boolean outlaw; - private int kills; - private int price; -} diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/faction/BlacklistListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/faction/BlacklistListener.java deleted file mode 100644 index 906046f7..00000000 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/faction/BlacklistListener.java +++ /dev/null @@ -1,63 +0,0 @@ -package de.rettichlp.ucutils.listener.impl.faction; - -import de.rettichlp.ucutils.common.models.BlacklistEntry; -import de.rettichlp.ucutils.common.registry.UCUtilsListener; -import de.rettichlp.ucutils.listener.IMessageReceiveListener; -import net.minecraft.text.Text; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import static de.rettichlp.ucutils.UCUtils.commandService; -import static de.rettichlp.ucutils.UCUtils.storage; -import static de.rettichlp.ucutils.UCUtils.utilService; -import static de.rettichlp.ucutils.common.services.CommandService.COMMAND_COOLDOWN_MILLIS; -import static java.lang.Integer.parseInt; -import static java.util.regex.Pattern.compile; - -@UCUtilsListener -public class BlacklistListener implements IMessageReceiveListener { - - private static final Pattern BLACKLIST_HEADER_PATTERN = compile("^==== Blacklist .+ ====$"); - private static final Pattern BLACKLIST_ENTRY_PATTERN = compile("^» (?:\\[UC])?(?[a-zA-Z0-9_]+) \\| (?.+) \\| (?.+) \\| (?\\d+) Kills \\| (?\\d+)\\$(| \\(AFK\\))$"); - private static final Pattern BLACKLIST_ENTRY_ADD = compile("^\\[Blacklist] (?:\\[UC])?(?[a-zA-Z0-9_]+) wurde von (?:\\[UC])?(?[a-zA-Z0-9_]+) auf die Blacklist gesetzt!$"); - private static final Pattern BLACKLIST_ENTRY_REMOVE = compile("^\\[Blacklist] (?:\\[UC])?(?[a-zA-Z0-9_]+) wurde von (?:\\[UC])?(?[a-zA-Z0-9_]+) von der Blacklist gelöscht!$"); - - @Override - public boolean onMessageReceive(Text text, String message) { - Matcher blacklistHeaderMatcher = BLACKLIST_HEADER_PATTERN.matcher(message); - if (blacklistHeaderMatcher.find()) { - storage.getBlacklistEntries().clear(); - return commandService.showCommandOutputMessage("blacklist"); - } - - Matcher blacklistEntryMatcher = BLACKLIST_ENTRY_PATTERN.matcher(message); - if (blacklistEntryMatcher.find()) { - String playerName = blacklistEntryMatcher.group("playerName"); - String reason = blacklistEntryMatcher.group("reason"); - boolean outlaw = reason.toLowerCase().contains("(vf)") || reason.toLowerCase().contains("(vogelfrei)"); - int kills = parseInt(blacklistEntryMatcher.group("kills")); - int price = parseInt(blacklistEntryMatcher.group("price")); - - BlacklistEntry blacklistEntry = new BlacklistEntry(playerName, reason, outlaw, kills, price); - storage.getBlacklistEntries().add(blacklistEntry); - return commandService.showCommandOutputMessage("blacklist"); - } - - Matcher blacklistEntryAddMatcher = BLACKLIST_ENTRY_ADD.matcher(message); - if (blacklistEntryAddMatcher.find()) { - // show all entries to sync - utilService.delayedAction(() -> commandService.sendCommandWithHiddenOutput("blacklist"), COMMAND_COOLDOWN_MILLIS); - return true; - } - - Matcher blacklistEntryRemoveMatcher = BLACKLIST_ENTRY_REMOVE.matcher(message); - if (blacklistEntryRemoveMatcher.find()) { - String targetName = blacklistEntryRemoveMatcher.group("targetName"); - storage.getBlacklistEntries().removeIf(blacklistEntry -> blacklistEntry.getPlayerName().equals(targetName)); - return true; - } - - return true; - } -} diff --git a/src/main/java/de/rettichlp/ucutils/mixin/EntityMixin.java b/src/main/java/de/rettichlp/ucutils/mixin/EntityMixin.java index c2c8fa50..d832c855 100644 --- a/src/main/java/de/rettichlp/ucutils/mixin/EntityMixin.java +++ b/src/main/java/de/rettichlp/ucutils/mixin/EntityMixin.java @@ -1,7 +1,6 @@ package de.rettichlp.ucutils.mixin; import de.rettichlp.ucutils.common.configuration.options.NameTagOptions; -import de.rettichlp.ucutils.common.models.BlacklistEntry; import de.rettichlp.ucutils.common.models.ContractEntry; import de.rettichlp.ucutils.common.models.Faction; import de.rettichlp.ucutils.common.models.WantedEntry; @@ -30,14 +29,10 @@ import static de.rettichlp.ucutils.UCUtils.player; import static de.rettichlp.ucutils.UCUtils.storage; import static de.rettichlp.ucutils.common.models.Color.WHITE; -import static java.time.LocalDateTime.now; import static net.minecraft.item.Items.SKELETON_SKULL; import static net.minecraft.item.Items.WITHER_SKELETON_SKULL; import static net.minecraft.text.Text.empty; import static net.minecraft.text.Text.literal; -import static net.minecraft.text.Text.of; -import static net.minecraft.util.Formatting.DARK_GRAY; -import static net.minecraft.util.Formatting.DARK_RED; import static net.minecraft.util.Formatting.GRAY; import static net.minecraft.util.Formatting.RED; @@ -119,21 +114,6 @@ private MutableText getEnrichedDisplayName(String targetName) { // highlight factions newTargetDisplayNameColor = WHITE.getFormatting(); - // blacklist - Optional optionalTargetBlacklistEntry = storage.getBlacklistEntries().stream() - .filter(blacklistEntry -> blacklistEntry.getPlayerName().equals(targetName)) - .findAny(); - - if (optionalTargetBlacklistEntry.isPresent() && nameTagOptions.outlaw()) { - newTargetDisplayNameColor = RED; - newTargetDisplayNamePrefix = optionalTargetBlacklistEntry.get().isOutlaw() - ? empty() - .append(of("[").copy().formatted(DARK_GRAY)) - .append(of("V").copy().formatted(DARK_RED)) - .append(of("]").copy().formatted(DARK_GRAY)) - : empty(); - } - // contract Optional optionalTargetContractEntry = storage.getContractEntries().stream() .filter(contractEntry -> contractEntry.getPlayerName().equals(targetName)) diff --git a/src/main/java/de/rettichlp/ucutils/mixin/PlayerListHudMixin.java b/src/main/java/de/rettichlp/ucutils/mixin/PlayerListHudMixin.java index 348b091f..1c972763 100644 --- a/src/main/java/de/rettichlp/ucutils/mixin/PlayerListHudMixin.java +++ b/src/main/java/de/rettichlp/ucutils/mixin/PlayerListHudMixin.java @@ -1,6 +1,5 @@ package de.rettichlp.ucutils.mixin; -import de.rettichlp.ucutils.common.models.BlacklistEntry; import net.minecraft.client.gui.hud.PlayerListHud; import net.minecraft.client.network.PlayerListEntry; import net.minecraft.text.MutableText; @@ -11,13 +10,10 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import java.util.Optional; - import static de.rettichlp.ucutils.UCUtils.storage; import static net.minecraft.text.Text.literal; import static net.minecraft.util.Formatting.BOLD; import static net.minecraft.util.Formatting.RED; -import static net.minecraft.util.Formatting.WHITE; @Mixin(PlayerListHud.class) public abstract class PlayerListHudMixin { @@ -36,14 +32,8 @@ public abstract class PlayerListHudMixin { boolean isWanted = storage.getWantedEntries().stream() .anyMatch(wantedEntry -> wantedEntry.getPlayerName().equals(playerName)); - Optional optionalBlacklistEntry = storage.getBlacklistEntries().stream() - .filter(be -> be.getPlayerName().equals(playerName)) - .findFirst(); - if (isWanted) { text = literal(" 🔍").formatted(RED, BOLD); - } else if (optionalBlacklistEntry.isPresent()) { - text = literal(" 💀").formatted(optionalBlacklistEntry.get().isOutlaw() ? RED : WHITE, BOLD); } if (text != null) { diff --git a/src/main/resources/assets/ucutils/lang/de_de.json b/src/main/resources/assets/ucutils/lang/de_de.json index d1ce27b4..d1425d2d 100644 --- a/src/main/resources/assets/ucutils/lang/de_de.json +++ b/src/main/resources/assets/ucutils/lang/de_de.json @@ -68,8 +68,6 @@ "ucutils.options.nametag.a_duty.tooltip": "Zeigt eine Information an über dem Namen von Spielern, die im Admin-Dienst sind", "ucutils.options.nametag.afk.name": "AFK", "ucutils.options.nametag.afk.tooltip": "Zeigt eine Information an über dem Namen von Spielern, die AFK sind", - "ucutils.options.nametag.outlaw.name": "Vogelfrei", - "ucutils.options.nametag.outlaw.tooltip": "Zeigt eine Information über dem Namen von Spielern an, die Vogelfrei sind", "ucutils.options.nametag.medical_information.name": "Information für Ärzte", "ucutils.options.nametag.medical_information.tooltip": "Zeigt die restliche Wirkungsdauer von Bandagen und Schmerzpillen unter dem Spielernamen an", "ucutils.options.notifications.join_quit.name": "Beitreten und Verlassen", diff --git a/src/main/resources/assets/ucutils/lang/en_gb.json b/src/main/resources/assets/ucutils/lang/en_gb.json index 32248696..8cd1b733 100644 --- a/src/main/resources/assets/ucutils/lang/en_gb.json +++ b/src/main/resources/assets/ucutils/lang/en_gb.json @@ -68,8 +68,6 @@ "ucutils.options.nametag.a_duty.tooltip": "Shows an information above the players name of players in admin duty", "ucutils.options.nametag.afk.name": "AFK", "ucutils.options.nametag.afk.tooltip": "Shows an information above the players name of afk players", - "ucutils.options.nametag.outlaw.name": "Outlaw", - "ucutils.options.nametag.outlaw.tooltip": "Shows an information above the players name of outlaw players", "ucutils.options.nametag.medical_information.name": "Medical information", "ucutils.options.nametag.medical_information.tooltip": "Shows the cooldown of bandages and pills below the players name", "ucutils.options.notifications.join_quit.name": "Join and Quit", diff --git a/src/main/resources/assets/ucutils/lang/en_us.json b/src/main/resources/assets/ucutils/lang/en_us.json index 32248696..8cd1b733 100644 --- a/src/main/resources/assets/ucutils/lang/en_us.json +++ b/src/main/resources/assets/ucutils/lang/en_us.json @@ -68,8 +68,6 @@ "ucutils.options.nametag.a_duty.tooltip": "Shows an information above the players name of players in admin duty", "ucutils.options.nametag.afk.name": "AFK", "ucutils.options.nametag.afk.tooltip": "Shows an information above the players name of afk players", - "ucutils.options.nametag.outlaw.name": "Outlaw", - "ucutils.options.nametag.outlaw.tooltip": "Shows an information above the players name of outlaw players", "ucutils.options.nametag.medical_information.name": "Medical information", "ucutils.options.nametag.medical_information.tooltip": "Shows the cooldown of bandages and pills below the players name", "ucutils.options.notifications.join_quit.name": "Join and Quit", From 5e0f330a48f9bcbfe5ed676208390ed8d3303718 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Tue, 19 May 2026 21:40:27 +0200 Subject: [PATCH 05/96] Remove contract functionality and related code --- .../de/rettichlp/ucutils/common/Storage.java | 6 --- .../ucutils/common/models/ContractEntry.java | 12 ------ .../impl/faction/ContractListener.java | 38 ------------------- .../rettichlp/ucutils/mixin/EntityMixin.java | 10 ----- 4 files changed, 66 deletions(-) delete mode 100644 src/main/java/de/rettichlp/ucutils/common/models/ContractEntry.java diff --git a/src/main/java/de/rettichlp/ucutils/common/Storage.java b/src/main/java/de/rettichlp/ucutils/common/Storage.java index 4feeb82b..2ef66648 100644 --- a/src/main/java/de/rettichlp/ucutils/common/Storage.java +++ b/src/main/java/de/rettichlp/ucutils/common/Storage.java @@ -1,7 +1,6 @@ package de.rettichlp.ucutils.common; import de.rettichlp.ucutils.common.models.BlackMarket; -import de.rettichlp.ucutils.common.models.ContractEntry; import de.rettichlp.ucutils.common.models.Countdown; import de.rettichlp.ucutils.common.models.Dealer; import de.rettichlp.ucutils.common.models.Faction; @@ -47,9 +46,6 @@ public class Storage { @Getter private final List blackMarkets = new ArrayList<>(); - @Getter - private final List contractEntries = new ArrayList<>(); - @Getter private final List countdowns = new ArrayList<>(); @@ -147,8 +143,6 @@ public void print() { LOGGER.info("activeShutdowns[{}]: {}", this.activeShutdowns.size(), this.activeShutdowns); // blackMarkets LOGGER.info("blackMarkets[{}]: {}", this.blackMarkets.size(), this.blackMarkets); - // contractEntries - LOGGER.info("contractEntries[{}]: {}", this.contractEntries.size(), this.contractEntries); // countdowns LOGGER.info("countdowns[{}]: {}", this.countdowns.size(), this.countdowns); // dealers diff --git a/src/main/java/de/rettichlp/ucutils/common/models/ContractEntry.java b/src/main/java/de/rettichlp/ucutils/common/models/ContractEntry.java deleted file mode 100644 index 77dd3cc9..00000000 --- a/src/main/java/de/rettichlp/ucutils/common/models/ContractEntry.java +++ /dev/null @@ -1,12 +0,0 @@ -package de.rettichlp.ucutils.common.models; - -import lombok.AllArgsConstructor; -import lombok.Data; - -@Data -@AllArgsConstructor -public class ContractEntry { - - private String playerName; - private int price; -} diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/faction/ContractListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/faction/ContractListener.java index 6413652c..cd778a7c 100644 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/faction/ContractListener.java +++ b/src/main/java/de/rettichlp/ucutils/listener/impl/faction/ContractListener.java @@ -1,6 +1,5 @@ package de.rettichlp.ucutils.listener.impl.faction; -import de.rettichlp.ucutils.common.models.ContractEntry; import de.rettichlp.ucutils.common.registry.UCUtilsListener; import de.rettichlp.ucutils.listener.IMessageReceiveListener; import net.minecraft.text.Text; @@ -8,48 +7,21 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import static de.rettichlp.ucutils.UCUtils.commandService; import static de.rettichlp.ucutils.UCUtils.configuration; -import static de.rettichlp.ucutils.UCUtils.storage; -import static de.rettichlp.ucutils.UCUtils.utilService; import static de.rettichlp.ucutils.common.models.Sound.CONTRACT_FULFILLED; import static de.rettichlp.ucutils.common.models.Sound.CONTRACT_SET; -import static de.rettichlp.ucutils.common.services.CommandService.COMMAND_COOLDOWN_MILLIS; -import static java.lang.Integer.parseInt; import static java.util.regex.Pattern.compile; @UCUtilsListener public class ContractListener implements IMessageReceiveListener { - private static final Pattern CONTRACT_HEADER_PATTERN = compile("^\\[Contracts] Kopfgelder:$"); - private static final Pattern CONTRACT_ENTRY_PATTERN = compile("^- (?:\\[UC])?(?[a-zA-Z0-9_]+) \\[(?\\d+)\\$](?: \\(AFK\\))?$"); private static final Pattern CONTRACT_ADD_PATTERN = compile("^\\[Contract] Es wurde ein Kopfgeld auf (?:\\[UC])?(?[a-zA-Z0-9_]+) \\((?\\d+)\\$\\) ausgesetzt\\.$"); - private static final Pattern CONTRACT_REMOVE_PATTERN = compile("^\\[Contract] (?:\\[UC])?(?[a-zA-Z0-9_]+) hat (?:\\[UC])?(?[a-zA-Z0-9_]+) von der Contract Liste gelöscht\\. \\[-(?\\d+)\\$]$"); private static final Pattern CONTRACT_KILL_PATTERN = compile("^\\[Contract] (?:\\[UC])?(?[a-zA-Z0-9_]+) hat (?:\\[UC])?(?[a-zA-Z0-9_]+) getötet\\. Kopfgeld: (?\\d+)\\$$"); @Override public boolean onMessageReceive(Text text, String message) { - Matcher contractHeaderMatcher = CONTRACT_HEADER_PATTERN.matcher(message); - if (contractHeaderMatcher.find()) { - storage.getContractEntries().clear(); - return commandService.showCommandOutputMessage("contractlist"); - } - - Matcher contractEntryMatcher = CONTRACT_ENTRY_PATTERN.matcher(message); - if (contractEntryMatcher.find()) { - String playerName = contractEntryMatcher.group("playerName"); - int price = parseInt(contractEntryMatcher.group("price")); - - ContractEntry contractEntry = new ContractEntry(playerName, price); - storage.getContractEntries().add(contractEntry); - return commandService.showCommandOutputMessage("contractlist"); - } - Matcher contractAddMatcher = CONTRACT_ADD_PATTERN.matcher(message); if (contractAddMatcher.find()) { - // show all entries to sync - utilService.delayedAction(() -> commandService.sendCommandWithHiddenOutput("contractlist"), COMMAND_COOLDOWN_MILLIS); - if (configuration.getOptions().sound().contractSet()) { CONTRACT_SET.play(); } @@ -57,18 +29,8 @@ public boolean onMessageReceive(Text text, String message) { return true; } - Matcher contractRemoveMatcher = CONTRACT_REMOVE_PATTERN.matcher(message); - if (contractRemoveMatcher.find()) { - String targetName = contractRemoveMatcher.group("targetName"); - storage.getContractEntries().removeIf(contractEntry -> contractEntry.getPlayerName().equals(targetName)); - return true; - } - Matcher contractKillMatcher = CONTRACT_KILL_PATTERN.matcher(message); if (contractKillMatcher.find()) { - String targetName = contractKillMatcher.group("targetName"); - storage.getContractEntries().removeIf(contractEntry -> contractEntry.getPlayerName().equals(targetName)); - if (configuration.getOptions().sound().contractFulfilled()) { CONTRACT_FULFILLED.play(); } diff --git a/src/main/java/de/rettichlp/ucutils/mixin/EntityMixin.java b/src/main/java/de/rettichlp/ucutils/mixin/EntityMixin.java index d832c855..dca2b2df 100644 --- a/src/main/java/de/rettichlp/ucutils/mixin/EntityMixin.java +++ b/src/main/java/de/rettichlp/ucutils/mixin/EntityMixin.java @@ -1,7 +1,6 @@ package de.rettichlp.ucutils.mixin; import de.rettichlp.ucutils.common.configuration.options.NameTagOptions; -import de.rettichlp.ucutils.common.models.ContractEntry; import de.rettichlp.ucutils.common.models.Faction; import de.rettichlp.ucutils.common.models.WantedEntry; import de.rettichlp.ucutils.listener.callback.PlayerEnterVehicleCallback; @@ -114,15 +113,6 @@ private MutableText getEnrichedDisplayName(String targetName) { // highlight factions newTargetDisplayNameColor = WHITE.getFormatting(); - // contract - Optional optionalTargetContractEntry = storage.getContractEntries().stream() - .filter(contractEntry -> contractEntry.getPlayerName().equals(targetName)) - .findAny(); - - if (optionalTargetContractEntry.isPresent()) { - newTargetDisplayNameColor = RED; - } - // wanted Optional optionalTargetWantedEntry = storage.getWantedEntries().stream() .filter(wantedEntry -> wantedEntry.getPlayerName().equals(targetName)) From 3c433f7972f16897ca7d88b6e3e440b4d5a14d9a Mon Sep 17 00:00:00 2001 From: RettichLP Date: Tue, 19 May 2026 21:49:43 +0200 Subject: [PATCH 06/96] Remove reinforcement functionality and related code --- .../de/rettichlp/ucutils/common/Storage.java | 13 ----------- .../ucutils/common/models/Reinforcement.java | 23 ------------------- 2 files changed, 36 deletions(-) delete mode 100644 src/main/java/de/rettichlp/ucutils/common/models/Reinforcement.java diff --git a/src/main/java/de/rettichlp/ucutils/common/Storage.java b/src/main/java/de/rettichlp/ucutils/common/Storage.java index 2ef66648..c543b210 100644 --- a/src/main/java/de/rettichlp/ucutils/common/Storage.java +++ b/src/main/java/de/rettichlp/ucutils/common/Storage.java @@ -10,7 +10,6 @@ import de.rettichlp.ucutils.common.models.Job; import de.rettichlp.ucutils.common.models.PlantEntry; import de.rettichlp.ucutils.common.models.Purity; -import de.rettichlp.ucutils.common.models.Reinforcement; import de.rettichlp.ucutils.common.models.ShutdownReason; import de.rettichlp.ucutils.common.models.TeamResponse; import de.rettichlp.ucutils.common.models.WantedEntry; @@ -70,9 +69,6 @@ public class Storage { @Getter private final Map playerFactionCache = new HashMap<>(); - @Getter - private final List reinforcements = new ArrayList<>(); - @Getter private final Map retrievedNumbers = new HashMap<>(); @@ -157,8 +153,6 @@ public void print() { LOGGER.info("medicPillCooldowns[{}]: {}", this.medicPillCooldowns.size(), this.medicPillCooldowns); // playerFactionCache LOGGER.info("playerFactionCache[{}]: {}", this.playerFactionCache.size(), this.playerFactionCache); - // reinforcements - LOGGER.info("reinforcements[{}]: {}", this.reinforcements.size(), this.reinforcements); // retrievedNumbers LOGGER.info("retrievedNumbers[{}]: {}", this.retrievedNumbers.size(), this.retrievedNumbers); // wantedEntries @@ -212,13 +206,6 @@ public Optional getFactionMember(String playerName) { .findFirst(); } - public void trackReinforcement(Reinforcement reinforcement) { - // remove all previous reinforcements of the same sender - this.reinforcements.removeIf(r -> r.getSenderPlayerName().equals(reinforcement.getSenderPlayerName())); - // add new reinforcement - this.reinforcements.add(reinforcement); - } - @Getter @AllArgsConstructor public enum ToggledChat { diff --git a/src/main/java/de/rettichlp/ucutils/common/models/Reinforcement.java b/src/main/java/de/rettichlp/ucutils/common/models/Reinforcement.java deleted file mode 100644 index 1c36abb8..00000000 --- a/src/main/java/de/rettichlp/ucutils/common/models/Reinforcement.java +++ /dev/null @@ -1,23 +0,0 @@ -package de.rettichlp.ucutils.common.models; - -import lombok.Data; -import net.minecraft.util.math.BlockPos; - -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; - -import static java.time.LocalDateTime.now; - -@Data -public class Reinforcement { - - private final LocalDateTime createdAt = now(); - private final List acceptedPlayerNames = new ArrayList<>(); - private final String type; - private final String senderPlayerName; - private final String naviPoint; - private final String distance; - private BlockPos blockPos; - private boolean addedAsActivity; -} From d90dcef2a6f315b3fdd12ef478874daa19b170da Mon Sep 17 00:00:00 2001 From: RettichLP Date: Tue, 19 May 2026 21:52:49 +0200 Subject: [PATCH 07/96] Remove remaining references to deprecated faction functionalities --- .../de/rettichlp/ucutils/common/services/SyncService.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/java/de/rettichlp/ucutils/common/services/SyncService.java b/src/main/java/de/rettichlp/ucutils/common/services/SyncService.java index 8462f7f6..7488bdd0 100644 --- a/src/main/java/de/rettichlp/ucutils/common/services/SyncService.java +++ b/src/main/java/de/rettichlp/ucutils/common/services/SyncService.java @@ -73,12 +73,7 @@ public void syncFactionSpecificData() { Faction faction = storage.getFaction(player.getStringifiedName()); switch (faction) { case FBI, POLIZEI -> commandService.sendCommandWithHiddenOutput("wanteds"); - case MERCENARY -> commandService.sendCommandWithHiddenOutput("contractlist"); - case RETTUNGSDIENST -> commandService.sendCommandWithHiddenOutput("hausverbot"); default -> { - if (faction.isBadFaction()) { - commandService.sendCommandWithHiddenOutput("blacklist"); - } } } } From dc68aa0fea4585774e20033ab57bbef0c0c61946 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Tue, 19 May 2026 21:55:49 +0200 Subject: [PATCH 08/96] Remove unused NameTagOptions reference and update README to clarify faction-related features --- README.md | 3 +-- src/main/java/de/rettichlp/ucutils/mixin/EntityMixin.java | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 7eb88162..cda92bc7 100644 --- a/README.md +++ b/README.md @@ -35,8 +35,7 @@ reibungsloser und angenehmer gestalten. ### Fraktionen - Für bewusstlose Spieler wird hinter dem Spielernamen ein Symbol angezeigt, um die dazugehörige Fraktion zu erkennen -- Sollte ein Spieler Contract, auf der Blacklist stehen, Hausverbot oder Wanted-Punkte haben, wird der Name dementsprechend eingefärbt - und in der Spielerliste angezeigt +- Sollte ein Spieler Wanted-Punkte haben, wird der Name der Leiche dementsprechend eingefärbt - Das Design der Reinforcements ist so überarbeitet, dass diese besser auffallen - Für das FBI, die Polizei und den Rettungsdienst gibt es einen Timer, der die Dauer der Bombe anzeigt - Mit einem Rechtsklick auf ein Fraktionstor (nicht Fraktionstür) wird dieses automatisch geöffnet oder geschlossen diff --git a/src/main/java/de/rettichlp/ucutils/mixin/EntityMixin.java b/src/main/java/de/rettichlp/ucutils/mixin/EntityMixin.java index dca2b2df..4e41c228 100644 --- a/src/main/java/de/rettichlp/ucutils/mixin/EntityMixin.java +++ b/src/main/java/de/rettichlp/ucutils/mixin/EntityMixin.java @@ -102,7 +102,6 @@ public abstract class EntityMixin { @Unique private MutableText getEnrichedDisplayName(String targetName) { - NameTagOptions nameTagOptions = configuration.getOptions().nameTag(); Faction targetFaction = storage.getCachedFaction(targetName); Text newTargetDisplayNamePrefix = empty(); From 57802adcb6090e4fbdafe0c9b7a2a28a451b153f Mon Sep 17 00:00:00 2001 From: RettichLP Date: Tue, 19 May 2026 22:15:50 +0200 Subject: [PATCH 09/96] Add functionality to track join timestamp and suppress initial notifications --- src/main/java/de/rettichlp/ucutils/UCUtils.java | 2 ++ src/main/java/de/rettichlp/ucutils/common/Storage.java | 6 ++++++ .../ucutils/mixin/ClientPlayNetworkHandlerMixin.java | 7 +++++++ 3 files changed, 15 insertions(+) diff --git a/src/main/java/de/rettichlp/ucutils/UCUtils.java b/src/main/java/de/rettichlp/ucutils/UCUtils.java index 064fbe6f..6f9b0832 100644 --- a/src/main/java/de/rettichlp/ucutils/UCUtils.java +++ b/src/main/java/de/rettichlp/ucutils/UCUtils.java @@ -21,6 +21,7 @@ import org.slf4j.LoggerFactory; import static java.lang.Boolean.getBoolean; +import static java.lang.System.currentTimeMillis; import static java.util.Objects.isNull; public class UCUtils implements ModInitializer { @@ -68,6 +69,7 @@ public void onInitialize() { boolean isUnicaCity = isUnicaCity(handler); storage.setUnicaCity(isUnicaCity); + storage.setJoinTimestamp(currentTimeMillis()); if (isUnicaCity) { client.execute(() -> { this.registry.registerListeners(); diff --git a/src/main/java/de/rettichlp/ucutils/common/Storage.java b/src/main/java/de/rettichlp/ucutils/common/Storage.java index c543b210..2d51d9f3 100644 --- a/src/main/java/de/rettichlp/ucutils/common/Storage.java +++ b/src/main/java/de/rettichlp/ucutils/common/Storage.java @@ -100,6 +100,10 @@ public class Storage { @Setter private double hydration = -1.0; + @Getter + @Setter + private long joinTimestamp = 0; + @Getter @Setter private int lastReceivedSmsNumber = -1; @@ -169,6 +173,8 @@ public void print() { LOGGER.info("fBankDepositReason: {}", this.fBankDepositReason); // hydration LOGGER.info("hydration: {}", this.hydration); + // joinTimestamp + LOGGER.info("joinTimestamp: {}", this.joinTimestamp); // lastReceivedSmsNumber LOGGER.info("lastReceivedSmsNumber: {}", this.lastReceivedSmsNumber); // minecartEntityToHighlight diff --git a/src/main/java/de/rettichlp/ucutils/mixin/ClientPlayNetworkHandlerMixin.java b/src/main/java/de/rettichlp/ucutils/mixin/ClientPlayNetworkHandlerMixin.java index 19e85849..9189ede6 100644 --- a/src/main/java/de/rettichlp/ucutils/mixin/ClientPlayNetworkHandlerMixin.java +++ b/src/main/java/de/rettichlp/ucutils/mixin/ClientPlayNetworkHandlerMixin.java @@ -24,6 +24,7 @@ import static de.rettichlp.ucutils.UCUtils.notificationService; import static de.rettichlp.ucutils.UCUtils.storage; import static java.awt.Color.WHITE; +import static java.lang.System.currentTimeMillis; import static net.minecraft.text.Text.empty; import static net.minecraft.text.Text.literal; import static net.minecraft.text.Text.translatable; @@ -104,6 +105,12 @@ public abstract class ClientPlayNetworkHandlerMixin { EnrichedGameProfile enrichedGameProfile = new EnrichedGameProfile(profile, currentDisplayName, currentDisplayName); this.enrichedGameProfiles.removeIf(egp -> egp.getProfile().id().equals(profileId)); this.enrichedGameProfiles.add(enrichedGameProfile); + + // if the client joined the server few moments ago, hide notifications due to initial sync of player list + if (currentTimeMillis() - storage.getJoinTimestamp() < 1000) { + return; + } + sendChangeNotification(enrichedGameProfile, "ucutils.notification.player_join"); } case UPDATE_DISPLAY_NAME -> { From 98ac55bd10d73c2e1e18ecd3a91f4095e3c158b3 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Tue, 19 May 2026 22:27:21 +0200 Subject: [PATCH 10/96] Update release workflow to include dynamic mod version passing and remove version check --- .github/workflows/release.yml | 14 +++----------- gradle.properties | 2 +- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5ec5d165..76f1305f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -28,15 +28,6 @@ jobs: with: fetch-depth: 0 - - name: Check version in gradle.properties - run: | - MOD_VERSION=$(grep "^mod_version=" gradle.properties | cut -d'=' -f2) - echo "Found mod version: $MOD_VERSION" - if [ "$MOD_VERSION" != "${{ inputs.version }}" ]; then - echo "Version mismatch! gradle.properties=$MOD_VERSION input=${{ inputs.version }}" - exit 1 - fi - - name: Set up JDK uses: actions/setup-java@v5 with: @@ -48,7 +39,7 @@ jobs: run: chmod +x ./gradlew - name: Build with Gradle - run: ./gradlew build --full-stacktrace + run: ./gradlew build --full-stacktrace -Pmod_version=${{ inputs.version }} - name: Upload artifacts uses: actions/upload-artifact@v7 @@ -65,4 +56,5 @@ jobs: --target main \ --repo="$GITHUB_REPOSITORY" \ --title="$tag" \ - --generate-notes + --generate-notes \ + build/libs/*.jar diff --git a/gradle.properties b/gradle.properties index a4a78fc0..ad4392be 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,7 +13,7 @@ loader_version=0.19.2 loom_version=1.16.2 # Mod Properties -mod_version=2.7.1 +mod_version=0.0.0 maven_group=de.rettichlp # Dependencies From 3703d1b80e427d4aa8df89a3e9cc793e3546dc18 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Wed, 20 May 2026 10:38:53 +0200 Subject: [PATCH 11/96] Enable car features only for non-premium players --- src/main/java/de/rettichlp/ucutils/common/Storage.java | 6 ++++++ .../de/rettichlp/ucutils/listener/impl/CarListener.java | 8 ++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/rettichlp/ucutils/common/Storage.java b/src/main/java/de/rettichlp/ucutils/common/Storage.java index 2d51d9f3..253cfebc 100644 --- a/src/main/java/de/rettichlp/ucutils/common/Storage.java +++ b/src/main/java/de/rettichlp/ucutils/common/Storage.java @@ -116,6 +116,10 @@ public class Storage { @Setter private int moneyAtmAmount = 0; + @Getter + @Setter + private boolean premium = false; + @Getter @Setter private TeamResponse team; @@ -181,6 +185,8 @@ public void print() { LOGGER.info("minecartEntityToHighlight: {}", this.minecartEntityToHighlight); // moneyAtmAmount LOGGER.info("moneyAtmAmount: {}", this.moneyAtmAmount); + // premium + LOGGER.info("premium: {}", this.premium); // team LOGGER.info("team: {}", this.team); // toggledChat diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/CarListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/CarListener.java index 5f83a8b6..e1ca94f3 100644 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/CarListener.java +++ b/src/main/java/de/rettichlp/ucutils/listener/impl/CarListener.java @@ -52,13 +52,13 @@ public void onEnterVehicle(Entity vehicle) { storage.setMinecartEntityToHighlight(null); - if (configuration.getOptions().car().automatedStart()) { + if (configuration.getOptions().car().automatedStart() && !storage.isPremium()) { // start the car with a small delay to ensure the player is fully in the vehicle utilService.delayedAction(() -> commandService.sendCommand("car start"), 500); } // lock the car after 1 second and the small delay if not already locked - if (!storage.isCarLocked() && configuration.getOptions().car().automatedLock()) { + if (!storage.isCarLocked() && configuration.getOptions().car().automatedLock() && !storage.isPremium()) { utilService.delayedAction(() -> commandService.sendCommand("car lock"), 1500); } } @@ -69,7 +69,7 @@ public void onEntityRender(WorldRenderContext context) { VertexConsumerProvider vertexConsumers = context.consumers(); ClientWorld world = MinecraftClient.getInstance().world; - if (world != null && configuration.getOptions().car().highlight()) { + if (world != null && configuration.getOptions().car().highlight() && !storage.isPremium()) { ofNullable(storage.getMinecartEntityToHighlight()) .map(minecartEntity -> world.getEntityById(minecartEntity.getId())) .ifPresent(minecartEntity -> renderService.renderTextAboveEntity(matrices, vertexConsumers, minecartEntity, Text.of("🚗").copy().formatted(AQUA), 0.05F)); @@ -117,7 +117,7 @@ public void onScreenOpen(Screen screen, int scaledWidth, int scaledHeight) { switch (titleString) { case "ᴄᴀʀᴄᴏɴᴛʀᴏʟ" -> { - if (configuration.getOptions().car().fastLock()) { + if (configuration.getOptions().car().fastLock() && !storage.isPremium()) { interactionManager.clickSlot(genericContainerScreen.getScreenHandler().syncId, 0, 0, PICKUP, player); } } From 33cead19e96eb389f4f66b819b3b65d12d3adcb3 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Wed, 20 May 2026 10:41:25 +0200 Subject: [PATCH 12/96] Add handling for premium account status in chat messages --- .../rettichlp/ucutils/listener/impl/PlayerListener.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/PlayerListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/PlayerListener.java index 9c7acee6..377384ea 100644 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/PlayerListener.java +++ b/src/main/java/de/rettichlp/ucutils/listener/impl/PlayerListener.java @@ -59,6 +59,9 @@ public class PlayerListener implements IAbsorptionGetListener, IMessageReceiveLi // pray private static final Pattern PRAY_START_PATTERN = compile("^\\[Kirche] Du fängst an für (?:\\[UC])?(?[a-zA-Z0-9_]+) zu beten\\.$"); + // premium + private static final Pattern PREMIUM_PATTERN = compile("^\\[Premium] Dein Premium Account ist noch .+ aktiv\\.$"); + // requests private static final Pattern ACCEPT_PATTERN = compile("^\\[Deal] (?:\\[UC])?(?[a-zA-Z0-9_]+) hat den Deal angenommen\\.$"); private static final Pattern DECLINE_PATTERN = compile("^\\[Deal] (?:\\[UC])?(?[a-zA-Z0-9_]+) hat das Angebot abgelehnt\\.$"); @@ -149,6 +152,12 @@ public boolean onMessageReceive(Text text, String message) { return true; } + Matcher premiumMatcher = PREMIUM_PATTERN.matcher(message); + if (premiumMatcher.find()) { + storage.setPremium(true); + return true; + } + Matcher acceptMatcher = ACCEPT_PATTERN.matcher(message); Matcher declineMatcher = DECLINE_PATTERN.matcher(message); if (acceptMatcher.find() || declineMatcher.find()) { From bd8651ce473fd0f793da438e06f875c6881a9819 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Wed, 20 May 2026 10:44:54 +0200 Subject: [PATCH 13/96] Add premium info message to car options screen and update translations --- .../common/gui/screens/options/CarOptionsScreen.java | 7 +++++++ src/main/resources/assets/ucutils/lang/de_de.json | 1 + src/main/resources/assets/ucutils/lang/en_gb.json | 1 + src/main/resources/assets/ucutils/lang/en_us.json | 1 + 4 files changed, 10 insertions(+) diff --git a/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/CarOptionsScreen.java b/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/CarOptionsScreen.java index 39fcc0fa..a57e91f5 100644 --- a/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/CarOptionsScreen.java +++ b/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/CarOptionsScreen.java @@ -3,6 +3,7 @@ import de.rettichlp.ucutils.common.gui.screens.OptionsScreen; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.widget.DirectionalLayoutWidget; +import net.minecraft.client.gui.widget.MultilineTextWidget; import net.minecraft.client.gui.widget.Positioner; import net.minecraft.client.gui.widget.TextWidget; import net.minecraft.text.Text; @@ -11,12 +12,14 @@ import static net.minecraft.client.gui.widget.DirectionalLayoutWidget.horizontal; import static net.minecraft.client.gui.widget.DirectionalLayoutWidget.vertical; import static net.minecraft.text.Text.translatable; +import static net.minecraft.util.Formatting.GOLD; public class CarOptionsScreen extends OptionsScreen { private static final Text TEXT_CAR = translatable("ucutils.options.text.car"); private static final Text TEXT_GENERAL = translatable("ucutils.options.text.general"); private static final Text TEXT_AUTOMATION = translatable("ucutils.options.text.automation"); + private static final Text CAR_PREMIUM_INFO = translatable("ucutils.options.car.premium_info"); private static final Text CAR_GENERAL_FAST_FIND_NAME = translatable("ucutils.options.car.general.fast_find.name"); private static final Text CAR_GENERAL_FAST_FIND_TOOLTIP = translatable("ucutils.options.car.general.fast_find.tooltip"); private static final Text CAR_GENERAL_FAST_LOCK_NAME = translatable("ucutils.options.car.general.fast_lock.name"); @@ -38,6 +41,10 @@ public CarOptionsScreen(Screen parent) { public void initBody() { DirectionalLayoutWidget directionalLayoutWidget = this.layout.addBody(vertical().spacing(4)); + MultilineTextWidget multilineTextWidget = directionalLayoutWidget.add(new MultilineTextWidget(CAR_PREMIUM_INFO.copy().formatted(GOLD), this.textRenderer), Positioner::alignHorizontalCenter); + multilineTextWidget.setMaxWidth(308); + multilineTextWidget.setCentered(true); + directionalLayoutWidget.add(new TextWidget(TEXT_GENERAL, this.textRenderer), Positioner::alignHorizontalCenter); DirectionalLayoutWidget directionalLayoutWidget1 = directionalLayoutWidget.add(horizontal().spacing(8)); diff --git a/src/main/resources/assets/ucutils/lang/de_de.json b/src/main/resources/assets/ucutils/lang/de_de.json index d1425d2d..47779bf3 100644 --- a/src/main/resources/assets/ucutils/lang/de_de.json +++ b/src/main/resources/assets/ucutils/lang/de_de.json @@ -52,6 +52,7 @@ "ucutils.options.text.sounds": "Sounds", "ucutils.options.text.notifications": "Benachrichtigungen", + "ucutils.options.car.premium_info": "Diese Einstellungen sind nur ohne Premium relevant. Für Premium Spieler können diese Einstellungen auf UnicaCity mit '/settings' getätigt werden.", "ucutils.options.car.general.fast_find.name": "Instant finden", "ucutils.options.car.general.fast_find.tooltip": "Findet das Auto sofort, wenn '/car find' ausgeführt wird", "ucutils.options.car.general.fast_lock.name": "Instant abschließen", diff --git a/src/main/resources/assets/ucutils/lang/en_gb.json b/src/main/resources/assets/ucutils/lang/en_gb.json index 8cd1b733..2022920d 100644 --- a/src/main/resources/assets/ucutils/lang/en_gb.json +++ b/src/main/resources/assets/ucutils/lang/en_gb.json @@ -52,6 +52,7 @@ "ucutils.options.text.sounds": "Sounds", "ucutils.options.text.notifications": "Notifications", + "ucutils.options.car.premium_info": "These settings are only relevant if you do not have Premium. For Premium players, these settings can be configured on UnicaCity using '/settings'.", "ucutils.options.car.general.fast_find.name": "Fast find", "ucutils.options.car.general.fast_find.tooltip": "Finds your car immediately when execution '/car find'", "ucutils.options.car.general.fast_lock.name": "Fast lock", diff --git a/src/main/resources/assets/ucutils/lang/en_us.json b/src/main/resources/assets/ucutils/lang/en_us.json index 8cd1b733..2022920d 100644 --- a/src/main/resources/assets/ucutils/lang/en_us.json +++ b/src/main/resources/assets/ucutils/lang/en_us.json @@ -52,6 +52,7 @@ "ucutils.options.text.sounds": "Sounds", "ucutils.options.text.notifications": "Notifications", + "ucutils.options.car.premium_info": "These settings are only relevant if you do not have Premium. For Premium players, these settings can be configured on UnicaCity using '/settings'.", "ucutils.options.car.general.fast_find.name": "Fast find", "ucutils.options.car.general.fast_find.tooltip": "Finds your car immediately when execution '/car find'", "ucutils.options.car.general.fast_lock.name": "Fast lock", From 8f9a46a3d72093f72219bd174ba011adab1c2905 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Wed, 20 May 2026 11:11:55 +0200 Subject: [PATCH 14/96] Make minecart interaction cancellable and consume action result --- .../java/de/rettichlp/ucutils/mixin/MinecartEntityMixin.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/rettichlp/ucutils/mixin/MinecartEntityMixin.java b/src/main/java/de/rettichlp/ucutils/mixin/MinecartEntityMixin.java index b887fbc1..47a43c29 100644 --- a/src/main/java/de/rettichlp/ucutils/mixin/MinecartEntityMixin.java +++ b/src/main/java/de/rettichlp/ucutils/mixin/MinecartEntityMixin.java @@ -15,6 +15,7 @@ import static de.rettichlp.ucutils.UCUtils.configuration; import static de.rettichlp.ucutils.UCUtils.storage; import static java.lang.System.currentTimeMillis; +import static net.minecraft.util.ActionResult.CONSUME; @Mixin(MinecartEntity.class) public abstract class MinecartEntityMixin { @@ -22,7 +23,7 @@ public abstract class MinecartEntityMixin { @Unique private long lastClick = 0; - @Inject(method = "interact", at = @At("HEAD")) + @Inject(method = "interact", at = @At("HEAD"), cancellable = true) private void ucutils$interactHead(PlayerEntity player, Hand hand, CallbackInfoReturnable cir) { if (!storage.isUnicaCity()) { return; @@ -32,6 +33,7 @@ public abstract class MinecartEntityMixin { if (configuration.getOptions().car().automatedCheckKfz() && entity instanceof MinecartEntity && player.isSneaking() && currentTimeMillis() - this.lastClick > 1000) { commandService.sendCommand("checkkfz"); this.lastClick = currentTimeMillis(); + cir.setReturnValue(CONSUME); } } } From 0b0963652ce2456d3a8a62ed4e4715b45e547e68 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Wed, 20 May 2026 11:46:58 +0200 Subject: [PATCH 15/96] Remove plant management functionality and related code --- .../de/rettichlp/ucutils/common/Storage.java | 4 - .../ucutils/common/models/PlantEntry.java | 17 --- .../listener/impl/faction/PlantListener.java | 143 +----------------- 3 files changed, 4 insertions(+), 160 deletions(-) delete mode 100644 src/main/java/de/rettichlp/ucutils/common/models/PlantEntry.java diff --git a/src/main/java/de/rettichlp/ucutils/common/Storage.java b/src/main/java/de/rettichlp/ucutils/common/Storage.java index 253cfebc..bd7112c7 100644 --- a/src/main/java/de/rettichlp/ucutils/common/Storage.java +++ b/src/main/java/de/rettichlp/ucutils/common/Storage.java @@ -8,7 +8,6 @@ import de.rettichlp.ucutils.common.models.FactionMember; import de.rettichlp.ucutils.common.models.Ingredient; import de.rettichlp.ucutils.common.models.Job; -import de.rettichlp.ucutils.common.models.PlantEntry; import de.rettichlp.ucutils.common.models.Purity; import de.rettichlp.ucutils.common.models.ShutdownReason; import de.rettichlp.ucutils.common.models.TeamResponse; @@ -63,9 +62,6 @@ public class Storage { @Getter private final Map medicPillCooldowns = new HashMap<>(); - @Getter - private final List plantEntries = new ArrayList<>(); - @Getter private final Map playerFactionCache = new HashMap<>(); diff --git a/src/main/java/de/rettichlp/ucutils/common/models/PlantEntry.java b/src/main/java/de/rettichlp/ucutils/common/models/PlantEntry.java deleted file mode 100644 index db0a6c80..00000000 --- a/src/main/java/de/rettichlp/ucutils/common/models/PlantEntry.java +++ /dev/null @@ -1,17 +0,0 @@ -package de.rettichlp.ucutils.common.models; - -import lombok.Data; -import lombok.RequiredArgsConstructor; -import net.minecraft.util.math.BlockPos; - -import java.time.LocalDateTime; - -@Data -@RequiredArgsConstructor -public class PlantEntry { - - private final BlockPos blockPos; - private final LocalDateTime plantedAt; - private LocalDateTime lastWateredAt; - private LocalDateTime lastFertilizedAt; -} diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/faction/PlantListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/faction/PlantListener.java index b7ca5645..2e2445ee 100644 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/faction/PlantListener.java +++ b/src/main/java/de/rettichlp/ucutils/listener/impl/faction/PlantListener.java @@ -1,43 +1,22 @@ package de.rettichlp.ucutils.listener.impl.faction; -import de.rettichlp.ucutils.common.models.PlantEntry; import de.rettichlp.ucutils.common.registry.UCUtilsListener; import de.rettichlp.ucutils.listener.IBlockRightClickListener; -import de.rettichlp.ucutils.listener.IEntityRenderListener; -import de.rettichlp.ucutils.listener.IMessageReceiveListener; import de.rettichlp.ucutils.listener.IScreenOpenListener; -import net.fabricmc.fabric.api.client.rendering.v1.world.WorldRenderContext; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.ingame.HopperScreen; import net.minecraft.client.network.ClientPlayerInteractionManager; -import net.minecraft.client.render.VertexConsumerProvider; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.client.world.ClientWorld; import net.minecraft.item.ItemStack; -import net.minecraft.text.Text; -import net.minecraft.util.Formatting; import net.minecraft.util.Hand; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; - -import java.time.Duration; -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +import org.jetbrains.annotations.NotNull; import static de.rettichlp.ucutils.UCUtils.commandService; import static de.rettichlp.ucutils.UCUtils.messageService; import static de.rettichlp.ucutils.UCUtils.player; -import static de.rettichlp.ucutils.UCUtils.renderService; -import static de.rettichlp.ucutils.UCUtils.storage; -import static java.time.Duration.between; -import static java.time.LocalDateTime.now; -import static java.util.Objects.nonNull; -import static java.util.regex.Pattern.compile; import static net.minecraft.block.Blocks.FERN; import static net.minecraft.block.Blocks.PODZOL; import static net.minecraft.entity.EquipmentSlot.MAINHAND; @@ -45,28 +24,14 @@ import static net.minecraft.item.Items.BONE_MEAL; import static net.minecraft.item.Items.WATER_BUCKET; import static net.minecraft.screen.slot.SlotActionType.PICKUP; -import static net.minecraft.text.Text.empty; -import static net.minecraft.text.Text.of; -import static net.minecraft.util.Formatting.AQUA; -import static net.minecraft.util.Formatting.BLUE; -import static net.minecraft.util.Formatting.GOLD; -import static net.minecraft.util.Formatting.GRAY; -import static net.minecraft.util.Formatting.GREEN; -import static net.minecraft.util.Formatting.RED; @UCUtilsListener -public class PlantListener implements IBlockRightClickListener, IEntityRenderListener, IMessageReceiveListener, IScreenOpenListener { +public class PlantListener implements IBlockRightClickListener, IScreenOpenListener { private static final String PLANT_TEXT = "Plantage"; - private static final Pattern PLANT_PLANT_PATTERN = compile("^\\[Plantage] (?:\\[UC])?(?[a-zA-Z0-9_]+) hat eine (Kräuter|Pulver)-Plantage gelegt\\. \\[\\d+/10]$"); - private static final Pattern PLANT_WATER_PATTERN = compile("^\\[Plantage] Eine (Kräuter|Pulver)-Plantage wurde von (?:\\[UC])?(?[a-zA-Z0-9_]+) gewässert\\.$"); - private static final Pattern PLANT_FERTILIZE_PATTERN = compile("^\\[Plantage] Eine (Kräuter|Pulver)-Plantage wurde von (?:\\[UC])?(?[a-zA-Z0-9_]+) gedüngt\\.$"); - - private static final int PLANT_WATERING_INTERVAL_MINUTES = 40; - private static final int PLANT_FERTILIZING_INTERVAL_MINUTES = 45; @Override - public void onBlockRightClick(World world, Hand hand, BlockHitResult hitResult) { + public void onBlockRightClick(@NotNull World world, Hand hand, @NotNull BlockHitResult hitResult) { BlockPos blockPos = hitResult.getBlockPos(); boolean targetBlockIsPlant = world.getBlockState(blockPos).getBlock().equals(FERN) && world.getBlockState(blockPos.down()).getBlock().equals(PODZOL); @@ -90,96 +55,6 @@ public void onBlockRightClick(World world, Hand hand, BlockHitResult hitResult) commandService.sendCommand("plant"); } - @Override - public void onEntityRender(WorldRenderContext context) { - MatrixStack matrices = context.matrices(); - VertexConsumerProvider vertexConsumers = context.consumers(); - ClientWorld world = MinecraftClient.getInstance().world; - - if (nonNull(matrices) && nonNull(vertexConsumers) && nonNull(world)) { - // create a copy to avoid ConcurrentModificationException - new ArrayList<>(storage.getPlantEntries()).forEach(plantEntry -> { - Vec3d centerBlockPos = plantEntry.getBlockPos().toCenterPos(); - double x = centerBlockPos.x; - double y = centerBlockPos.y; - double z = centerBlockPos.z; - - // only render if the player is nearby - if (!player.getBlockPos().isWithinDistance(plantEntry.getBlockPos(), 15)) { - return; - } - - Text waterText; - LocalDateTime lastWateredAt = plantEntry.getLastWateredAt(); - if (nonNull(lastWateredAt)) { - LocalDateTime nextWateringAt = lastWateredAt.plusMinutes(PLANT_WATERING_INTERVAL_MINUTES); - Duration durationUntilNextWatering = between(now(), nextWateringAt); - long millis = durationUntilNextWatering.toMillis(); - - waterText = empty() - .append(of("🫗").copy().formatted(BLUE)).append(" ") - .append(of(messageService.millisToFriendlyString(millis)).copy().formatted(getTextColor(millis))); - } else { - waterText = of("↓").copy().formatted(AQUA); - } - - Text fertilizeText; - LocalDateTime lastFertilizedAt = plantEntry.getLastFertilizedAt(); - if (nonNull(lastFertilizedAt)) { - LocalDateTime nextFertilizingAt = lastFertilizedAt.plusMinutes(PLANT_FERTILIZING_INTERVAL_MINUTES); - Duration durationUntilNextFertilizing = between(now(), nextFertilizingAt); - long millis = durationUntilNextFertilizing.toMillis(); - - fertilizeText = empty() - .append(of("🫘").copy().formatted(GOLD)).append(" ") - .append(of(messageService.millisToFriendlyString(millis)).copy().formatted(getTextColor(millis))); - } else { - fertilizeText = of("↓").copy().formatted(AQUA); - } - - renderService.renderTextAt(matrices, vertexConsumers, x, y + 0.75, z, waterText, 0.015f); - renderService.renderTextAt(matrices, vertexConsumers, x, y + 0.6, z, fertilizeText, 0.015f); - }); - } - } - - @Override - public boolean onMessageReceive(Text text, String message) { - Matcher plantPlantMatcher = PLANT_PLANT_PATTERN.matcher(message); - if (plantPlantMatcher.find() && player.getGameProfile().name().equals(plantPlantMatcher.group("playerName"))) { - BlockPos blockPos = player.getBlockPos(); - - PlantEntry plantEntry = new PlantEntry(blockPos, now()); - storage.getPlantEntries().add(plantEntry); - - return true; - } - - Matcher plantFertilizeMatcher = PLANT_FERTILIZE_PATTERN.matcher(message); - if (plantFertilizeMatcher.find()) { - BlockPos blockPos = player.getBlockPos(); - - storage.getPlantEntries().stream() - .filter(plantEntry -> plantEntry.getBlockPos().equals(blockPos)) - .findAny().ifPresent(plantEntry -> plantEntry.setLastFertilizedAt(now())); - - return true; - } - - Matcher plantWaterMatcher = PLANT_WATER_PATTERN.matcher(message); - if (plantWaterMatcher.find()) { - BlockPos blockPos = player.getBlockPos(); - - storage.getPlantEntries().stream() - .filter(plantEntry -> plantEntry.getBlockPos().equals(blockPos)) - .findAny().ifPresent(plantEntry -> plantEntry.setLastWateredAt(now())); - - return true; - } - - return true; - } - @Override public void onScreenOpen(Screen screen, int scaledWidth, int scaledHeight) { ClientPlayerInteractionManager interactionManager = MinecraftClient.getInstance().interactionManager; @@ -188,7 +63,7 @@ public void onScreenOpen(Screen screen, int scaledWidth, int scaledHeight) { ItemStack mainHandStack = player.getEquippedStack(MAINHAND); int syncId = hopperScreen.getScreenHandler().syncId; - // // https://i.imgur.com/b8INthP.png + // https://i.imgur.com/b8INthP.png if (mainHandStack.isOf(WATER_BUCKET)) { interactionManager.clickSlot(syncId, 4, 0, PICKUP, player); } else if (mainHandStack.isOf(BONE_MEAL)) { @@ -196,14 +71,4 @@ public void onScreenOpen(Screen screen, int scaledWidth, int scaledHeight) { } } } - - private Formatting getTextColor(long millis) { - if (millis < 0) { - return RED; - } else if (millis <= 3 * 60 * 1000) { - return GREEN; - } else { - return GRAY; - } - } } From f0804e0e716b1e77c361afa9a9e2fd7ba140beaf Mon Sep 17 00:00:00 2001 From: RettichLP Date: Wed, 20 May 2026 11:53:06 +0200 Subject: [PATCH 16/96] Remove Ingredient model and migrate functionality to InventoryItem --- .../command/faction/DBankDropAllCommand.java | 14 +++--- .../command/faction/SellDrugAllCommand.java | 14 +++--- .../de/rettichlp/ucutils/common/Storage.java | 6 +-- .../ucutils/common/models/Ingredient.java | 43 ------------------- .../ucutils/common/models/InventoryItem.java | 30 ++++++++++--- .../listener/impl/InventoryListener.java | 36 ++++++++-------- 6 files changed, 59 insertions(+), 84 deletions(-) delete mode 100644 src/main/java/de/rettichlp/ucutils/common/models/Ingredient.java diff --git a/src/main/java/de/rettichlp/ucutils/command/faction/DBankDropAllCommand.java b/src/main/java/de/rettichlp/ucutils/command/faction/DBankDropAllCommand.java index 90af90cf..37ae0df5 100644 --- a/src/main/java/de/rettichlp/ucutils/command/faction/DBankDropAllCommand.java +++ b/src/main/java/de/rettichlp/ucutils/command/faction/DBankDropAllCommand.java @@ -1,7 +1,7 @@ package de.rettichlp.ucutils.command.faction; import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import de.rettichlp.ucutils.common.models.Ingredient; +import de.rettichlp.ucutils.common.models.InventoryItem; import de.rettichlp.ucutils.common.registry.CommandBase; import de.rettichlp.ucutils.common.registry.UCUtilsCommand; import de.rettichlp.ucutils.listener.impl.InventoryListener; @@ -14,7 +14,7 @@ import static de.rettichlp.ucutils.UCUtils.commandService; import static de.rettichlp.ucutils.UCUtils.storage; import static de.rettichlp.ucutils.UCUtils.utilService; -import static de.rettichlp.ucutils.common.models.Ingredient.POWDER; +import static de.rettichlp.ucutils.common.models.InventoryItem.POWDER; @UCUtilsCommand(label = "dbankdropall", aliases = "dda") public class DBankDropAllCommand extends CommandBase { @@ -32,16 +32,16 @@ public LiteralArgumentBuilder execute(@NotNull Litera List commandQueue = new ArrayList<>(); storage.getInventory().entrySet().stream() - .filter(ingredientMapEntry -> ingredientMapEntry.getKey().isDrugBankDropable()) - .forEach(ingredientMapEntry -> { - Ingredient ingredient = ingredientMapEntry.getKey(); + .filter(ingredientMapEntry -> ingredientMapEntry.getKey().isDrugBankItem()) + .forEach(inventoryItemMapEntry -> { + InventoryItem inventoryItem = inventoryItemMapEntry.getKey(); - ingredientMapEntry.getValue().entrySet().stream() + inventoryItemMapEntry.getValue().entrySet().stream() .filter(purityIntegerEntry -> purityIntegerEntry.getValue() > 0) .forEach(purityIntegerEntry -> { int purityNumber = purityIntegerEntry.getKey().ordinal(); Integer amount = purityIntegerEntry.getValue(); - commandQueue.add("dbank drop " + ingredient.getDisplayName() + " " + amount + " " + purityNumber); + commandQueue.add("dbank drop " + inventoryItem.getDisplayName() + " " + amount + " " + purityNumber); }); }); diff --git a/src/main/java/de/rettichlp/ucutils/command/faction/SellDrugAllCommand.java b/src/main/java/de/rettichlp/ucutils/command/faction/SellDrugAllCommand.java index 0dbfc588..a58603a9 100644 --- a/src/main/java/de/rettichlp/ucutils/command/faction/SellDrugAllCommand.java +++ b/src/main/java/de/rettichlp/ucutils/command/faction/SellDrugAllCommand.java @@ -2,7 +2,7 @@ import com.mojang.authlib.GameProfile; import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import de.rettichlp.ucutils.common.models.Ingredient; +import de.rettichlp.ucutils.common.models.InventoryItem; import de.rettichlp.ucutils.common.registry.CommandBase; import de.rettichlp.ucutils.common.registry.UCUtilsCommand; import de.rettichlp.ucutils.listener.impl.InventoryListener; @@ -19,7 +19,7 @@ import static de.rettichlp.ucutils.UCUtils.networkHandler; import static de.rettichlp.ucutils.UCUtils.storage; import static de.rettichlp.ucutils.UCUtils.utilService; -import static de.rettichlp.ucutils.common.models.Ingredient.POWDER; +import static de.rettichlp.ucutils.common.models.InventoryItem.POWDER; import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.argument; import static net.minecraft.command.CommandSource.suggestMatching; @@ -49,16 +49,16 @@ public LiteralArgumentBuilder execute(@NotNull Litera List commandQueue = new ArrayList<>(); storage.getInventory().entrySet().stream() - .filter(ingredientMapEntry -> ingredientMapEntry.getKey().isDrugBankDropable()) - .forEach(ingredientMapEntry -> { - Ingredient ingredient = ingredientMapEntry.getKey(); + .filter(inventoryItemMapEntry -> inventoryItemMapEntry.getKey().isDrugBankItem()) + .forEach(inventoryItemMapEntry -> { + InventoryItem inventoryItem = inventoryItemMapEntry.getKey(); - ingredientMapEntry.getValue().entrySet().stream() + inventoryItemMapEntry.getValue().entrySet().stream() .filter(purityIntegerEntry -> purityIntegerEntry.getValue() > 0) .forEach(purityIntegerEntry -> { int purityNumber = purityIntegerEntry.getKey().ordinal(); Integer amount = purityIntegerEntry.getValue(); - commandQueue.add("selldrug " + targetName + " " + ingredient.getDisplayName() + " " + purityNumber + " " + amount + " " + 0); + commandQueue.add("selldrug " + targetName + " " + inventoryItem.getDisplayName() + " " + purityNumber + " " + amount + " " + 0); }); }); diff --git a/src/main/java/de/rettichlp/ucutils/common/Storage.java b/src/main/java/de/rettichlp/ucutils/common/Storage.java index bd7112c7..5e0cc47f 100644 --- a/src/main/java/de/rettichlp/ucutils/common/Storage.java +++ b/src/main/java/de/rettichlp/ucutils/common/Storage.java @@ -6,7 +6,7 @@ import de.rettichlp.ucutils.common.models.Faction; import de.rettichlp.ucutils.common.models.FactionEntry; import de.rettichlp.ucutils.common.models.FactionMember; -import de.rettichlp.ucutils.common.models.Ingredient; +import de.rettichlp.ucutils.common.models.InventoryItem; import de.rettichlp.ucutils.common.models.Job; import de.rettichlp.ucutils.common.models.Purity; import de.rettichlp.ucutils.common.models.ShutdownReason; @@ -54,7 +54,7 @@ public class Storage { private final Set factionEntries = new HashSet<>(); @Getter - private final Map> inventory = new HashMap<>(); + private final Map> inventory = new HashMap<>(); @Getter private final Map medicBandageCooldowns = new HashMap<>(); @@ -150,7 +150,7 @@ public void print() { // factionEntries this.factionEntries.forEach(factionEntry -> LOGGER.info("factionEntries[{}:{}]: {}", factionEntry.faction(), factionEntry.members().size(), factionEntry.members())); // inventory - this.inventory.forEach((ingredient, ingredientMap) -> LOGGER.info("inventory[{}:{}]: {}", ingredient, ingredientMap.size(), ingredientMap)); + this.inventory.forEach((inventoryItem, inventoryItemMap) -> LOGGER.info("inventory[{}:{}]: {}", inventoryItem, inventoryItemMap.size(), inventoryItemMap)); // medicBandageCooldowns LOGGER.info("medicBandageCooldowns[{}]: {}", this.medicBandageCooldowns.size(), this.medicBandageCooldowns); // medicPillCooldowns diff --git a/src/main/java/de/rettichlp/ucutils/common/models/Ingredient.java b/src/main/java/de/rettichlp/ucutils/common/models/Ingredient.java deleted file mode 100644 index a22fe3fd..00000000 --- a/src/main/java/de/rettichlp/ucutils/common/models/Ingredient.java +++ /dev/null @@ -1,43 +0,0 @@ -package de.rettichlp.ucutils.common.models; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NonNull; - -import java.util.Optional; - -import static java.util.Arrays.stream; - -@Getter -@AllArgsConstructor -public enum Ingredient { - - POWDER("Pulver", true, true), - HERBS("Kräuter", true, true), - MEDICINAL_HERBS("Medizinische Kräuter"), - CRYSTALS("Kristalle", true, true), - SURPRISE_BAG("Wundertüte", false, true), - COUGH_SYRUP("Hustensaft"), - PAINKILLERS("Schmerzmittel"), - ANTIBIOTICS("Antibiotika"), - MASK("Maske"), - IRON("Eisen"), - GUNPOWDER("Schwarzpulver"), - KEVLAR_FIBERS("Kevlarfasern"); - - private final String displayName; - private final boolean purity; - private final boolean drugBankDropable; - - Ingredient(String displayName) { - this.displayName = displayName; - this.purity = false; - this.drugBankDropable = false; - } - - public static @NonNull Optional fromDisplayName(String displayName) { - return stream(values()) - .filter(ingredient -> ingredient.getDisplayName().equals(displayName)) - .findFirst(); - } -} diff --git a/src/main/java/de/rettichlp/ucutils/common/models/InventoryItem.java b/src/main/java/de/rettichlp/ucutils/common/models/InventoryItem.java index 406fbf2e..b08ca9b8 100644 --- a/src/main/java/de/rettichlp/ucutils/common/models/InventoryItem.java +++ b/src/main/java/de/rettichlp/ucutils/common/models/InventoryItem.java @@ -2,6 +2,11 @@ import lombok.AllArgsConstructor; import lombok.Getter; +import lombok.NonNull; + +import java.util.Optional; + +import static java.util.Arrays.stream; @Getter @AllArgsConstructor @@ -9,20 +14,33 @@ public enum InventoryItem { // drugs POWDER("Pulver", true), + MEDICINAL_HERBS("Medizinische Kräuter"), HERBS("Kräuter", true), CRYSTALS("Kristalle", true), GRAB_BAG("Wundertüte", true), // medical - COUGH_SYRUP("Hustensaft", false), - PAINKILLERS("Schmerzmittel", false), - ANTIBIOTICS("Antibiotika", false), + COUGH_SYRUP("Hustensaft"), + PAINKILLERS("Schmerzmittel"), + ANTIBIOTICS("Antibiotika"), // other - MASK("Maske", false), - GUN_POWDER("Schwarzpulver", false), - IRON("Eisen", false); + MASK("Maske"), + IRON("Eisen"), + GUN_POWDER("Schwarzpulver"), + KEVLAR_FIBERS("Kevlarfasern"); private final String displayName; private final boolean drugBankItem; + + InventoryItem(String displayName) { + this.displayName = displayName; + this.drugBankItem = false; + } + + public static @NonNull Optional fromDisplayName(String displayName) { + return stream(values()) + .filter(inventoryItem -> inventoryItem.getDisplayName().equals(displayName)) + .findFirst(); + } } diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/InventoryListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/InventoryListener.java index 12d99267..13eba124 100644 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/InventoryListener.java +++ b/src/main/java/de/rettichlp/ucutils/listener/impl/InventoryListener.java @@ -1,6 +1,6 @@ package de.rettichlp.ucutils.listener.impl; -import de.rettichlp.ucutils.common.models.Ingredient; +import de.rettichlp.ucutils.common.models.InventoryItem; import de.rettichlp.ucutils.common.models.Purity; import de.rettichlp.ucutils.common.registry.UCUtilsListener; import de.rettichlp.ucutils.listener.IScreenOpenListener; @@ -24,18 +24,18 @@ import static de.rettichlp.ucutils.UCUtils.player; import static de.rettichlp.ucutils.UCUtils.storage; import static de.rettichlp.ucutils.UCUtils.utilService; -import static de.rettichlp.ucutils.common.models.Ingredient.ANTIBIOTICS; -import static de.rettichlp.ucutils.common.models.Ingredient.COUGH_SYRUP; -import static de.rettichlp.ucutils.common.models.Ingredient.CRYSTALS; -import static de.rettichlp.ucutils.common.models.Ingredient.GUNPOWDER; -import static de.rettichlp.ucutils.common.models.Ingredient.HERBS; -import static de.rettichlp.ucutils.common.models.Ingredient.IRON; -import static de.rettichlp.ucutils.common.models.Ingredient.KEVLAR_FIBERS; -import static de.rettichlp.ucutils.common.models.Ingredient.MASK; -import static de.rettichlp.ucutils.common.models.Ingredient.MEDICINAL_HERBS; -import static de.rettichlp.ucutils.common.models.Ingredient.PAINKILLERS; -import static de.rettichlp.ucutils.common.models.Ingredient.SURPRISE_BAG; -import static de.rettichlp.ucutils.common.models.Ingredient.fromDisplayName; +import static de.rettichlp.ucutils.common.models.InventoryItem.ANTIBIOTICS; +import static de.rettichlp.ucutils.common.models.InventoryItem.COUGH_SYRUP; +import static de.rettichlp.ucutils.common.models.InventoryItem.CRYSTALS; +import static de.rettichlp.ucutils.common.models.InventoryItem.GRAB_BAG; +import static de.rettichlp.ucutils.common.models.InventoryItem.GUN_POWDER; +import static de.rettichlp.ucutils.common.models.InventoryItem.HERBS; +import static de.rettichlp.ucutils.common.models.InventoryItem.IRON; +import static de.rettichlp.ucutils.common.models.InventoryItem.KEVLAR_FIBERS; +import static de.rettichlp.ucutils.common.models.InventoryItem.MASK; +import static de.rettichlp.ucutils.common.models.InventoryItem.MEDICINAL_HERBS; +import static de.rettichlp.ucutils.common.models.InventoryItem.PAINKILLERS; +import static de.rettichlp.ucutils.common.models.InventoryItem.fromDisplayName; import static de.rettichlp.ucutils.common.models.Purity.BEST; import static java.lang.Integer.parseInt; import static java.util.regex.Pattern.compile; @@ -45,7 +45,7 @@ @UCUtilsListener public class InventoryListener implements IScreenOpenListener { - public static Ingredient inventorySyncStep = null; + public static InventoryItem inventorySyncStep = null; @Override public void onScreenOpen(Screen screen, int scaledWidth, int scaledHeight) { @@ -91,7 +91,7 @@ public void onScreenOpen(Screen screen, int scaledWidth, int scaledHeight) { ItemStack surpriseBagItemStack = genericContainerScreenHandler.slots.get(4).getStack(); int surpriseBagAmount = getAmount(surpriseBagItemStack, 0); - storage.getInventory().put(SURPRISE_BAG, Map.of(BEST, surpriseBagAmount)); + storage.getInventory().put(GRAB_BAG, Map.of(BEST, surpriseBagAmount)); ItemStack coughSyrupItemStack = genericContainerScreenHandler.slots.get(9).getStack(); int coughSyrupAmount = getAmount(coughSyrupItemStack, 0); @@ -115,7 +115,7 @@ public void onScreenOpen(Screen screen, int scaledWidth, int scaledHeight) { ItemStack gunpowderItemStack = genericContainerScreenHandler.slots.get(20).getStack(); int gunpowderAmount = getAmount(gunpowderItemStack, 0); - storage.getInventory().put(GUNPOWDER, Map.of(BEST, gunpowderAmount)); + storage.getInventory().put(GUN_POWDER, Map.of(BEST, gunpowderAmount)); ItemStack kevlarFibersItemStack = genericContainerScreenHandler.slots.get(21).getStack(); int kevlarFibersAmount = getAmount(kevlarFibersItemStack, 0); @@ -129,7 +129,7 @@ public void onScreenOpen(Screen screen, int scaledWidth, int scaledHeight) { } if (screenHandler instanceof HopperScreenHandler hopperScreenHandler) { - utilService.delayedAction(() -> fromDisplayName(title).ifPresent(ingredient -> { + utilService.delayedAction(() -> fromDisplayName(title).ifPresent(inventoryItem -> { Map purityAmounts = new HashMap<>(); DefaultedList slots = hopperScreenHandler.slots; @@ -139,7 +139,7 @@ public void onScreenOpen(Screen screen, int scaledWidth, int scaledHeight) { purityAmounts.put(Purity.values()[i], amount); } - storage.getInventory().put(ingredient, purityAmounts); + storage.getInventory().put(inventoryItem, purityAmounts); switch (inventorySyncStep) { case POWDER -> { inventorySyncStep = HERBS; From 0ff342f5a3db062bd506af46c0418a7eb02373cc Mon Sep 17 00:00:00 2001 From: RettichLP Date: Wed, 20 May 2026 11:57:32 +0200 Subject: [PATCH 17/96] Remove absorption handling and related listener functionality --- .../ucutils/common/registry/Registry.java | 15 --------------- .../ucutils/listener/IAbsorptionGetListener.java | 6 ------ .../ucutils/listener/impl/PlayerListener.java | 8 +------- 3 files changed, 1 insertion(+), 28 deletions(-) delete mode 100644 src/main/java/de/rettichlp/ucutils/listener/IAbsorptionGetListener.java diff --git a/src/main/java/de/rettichlp/ucutils/common/registry/Registry.java b/src/main/java/de/rettichlp/ucutils/common/registry/Registry.java index ef379c50..3353b99e 100644 --- a/src/main/java/de/rettichlp/ucutils/common/registry/Registry.java +++ b/src/main/java/de/rettichlp/ucutils/common/registry/Registry.java @@ -3,7 +3,6 @@ import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import de.rettichlp.ucutils.common.models.Sound; -import de.rettichlp.ucutils.listener.IAbsorptionGetListener; import de.rettichlp.ucutils.listener.IBlockRightClickListener; import de.rettichlp.ucutils.listener.ICommandSendListener; import de.rettichlp.ucutils.listener.IEnterVehicleListener; @@ -41,11 +40,9 @@ import static de.rettichlp.ucutils.UCUtils.storage; import static java.util.Collections.emptySet; import static java.util.Objects.isNull; -import static java.util.Optional.ofNullable; import static java.util.stream.Collectors.toSet; import static java.util.stream.StreamSupport.stream; import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal; -import static net.minecraft.entity.effect.StatusEffects.ABSORPTION; import static net.minecraft.registry.Registries.SOUND_EVENT; import static net.minecraft.registry.Registry.register; import static net.minecraft.util.ActionResult.PASS; @@ -60,7 +57,6 @@ public class Registry { private boolean initialized = false; private BlockPos lastPlayerPos = null; - private boolean lastAbsorptionState = false; public void registerSounds() { for (Sound value : Sound.values()) { @@ -149,17 +145,6 @@ public void registerListeners() { getListenersImplementing(IMoveListener.class).forEach(iMoveListener -> iMoveListener.onMove(blockPos)); } - // handle absorption - boolean hasAbsorption = ofNullable(player) - .map(clientPlayerEntity -> clientPlayerEntity.hasStatusEffect(ABSORPTION)) - .orElse(false); - - if (!this.lastAbsorptionState && hasAbsorption) { - getListenersImplementing(IAbsorptionGetListener.class).forEach(IAbsorptionGetListener::onAbsorptionGet); - } - - this.lastAbsorptionState = hasAbsorption; - // handle key press KeyBinding swapHandsKey = MinecraftClient.getInstance().options.swapHandsKey; if (swapHandsKey.isPressed()) { diff --git a/src/main/java/de/rettichlp/ucutils/listener/IAbsorptionGetListener.java b/src/main/java/de/rettichlp/ucutils/listener/IAbsorptionGetListener.java deleted file mode 100644 index 558cba50..00000000 --- a/src/main/java/de/rettichlp/ucutils/listener/IAbsorptionGetListener.java +++ /dev/null @@ -1,6 +0,0 @@ -package de.rettichlp.ucutils.listener; - -public interface IAbsorptionGetListener extends IUCUtilsListener { - - void onAbsorptionGet(); -} diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/PlayerListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/PlayerListener.java index 377384ea..f5378f4e 100644 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/PlayerListener.java +++ b/src/main/java/de/rettichlp/ucutils/listener/impl/PlayerListener.java @@ -2,7 +2,6 @@ import de.rettichlp.ucutils.common.models.Countdown; import de.rettichlp.ucutils.common.registry.UCUtilsListener; -import de.rettichlp.ucutils.listener.IAbsorptionGetListener; import de.rettichlp.ucutils.listener.IMessageReceiveListener; import de.rettichlp.ucutils.listener.ITickListener; import net.minecraft.network.ClientConnection; @@ -36,7 +35,7 @@ import static net.minecraft.util.Formatting.RED; @UCUtilsListener -public class PlayerListener implements IAbsorptionGetListener, IMessageReceiveListener, ITickListener { +public class PlayerListener implements IMessageReceiveListener, ITickListener { private static final String SHUTDOWN_TIMEOUT = "5"; private static final int PRAY_DELAY_IN_SECONDS = 30; @@ -66,11 +65,6 @@ public class PlayerListener implements IAbsorptionGetListener, IMessageReceiveLi private static final Pattern ACCEPT_PATTERN = compile("^\\[Deal] (?:\\[UC])?(?[a-zA-Z0-9_]+) hat den Deal angenommen\\.$"); private static final Pattern DECLINE_PATTERN = compile("^\\[Deal] (?:\\[UC])?(?[a-zA-Z0-9_]+) hat das Angebot abgelehnt\\.$"); - @Override - public void onAbsorptionGet() { - storage.getCountdowns().add(new Countdown("Absorption", ofMinutes(3))); - } - @Override public boolean onMessageReceive(Text text, String message) { Matcher deadAReviveMatcher = DEAD_AREVIVE_PATTERN.matcher(message); From 576274c9d022e3ddd86f1f56ca89a5c438f08da3 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Wed, 20 May 2026 12:00:14 +0200 Subject: [PATCH 18/96] Update README to remove cooldown display for absorption --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cda92bc7..2f9213f6 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ reibungsloser und angenehmer gestalten. gültigen Command umgewandelt - Als Business-Besitzer wird in der Business-Info ein Button angezeigt, um die Einnahmen direkt abzubuchen - Wirft man eine Glasflasche in der Nähe eines Shops weg, wird diese als Pfand abgegeben -- Es wird angezeigt wie lang der Cooldown für Bandagen, Schmerzpillen und Absorption ist +- Es wird angezeigt wie lang der Cooldown für Bandagen und Schmerzpillen ist - Es werden Sounds abgespielt für Notrufe, Bomben, Feuer, Staatsbankraub und weitere Situationen - Über der Hungerleiste wird der Durst angezeigt - Mit einem Rechtsklick, während man schleicht, kann man bewusstlosen Personen Erste-Hilfe geben From 52c7f935ba45180d0163b200bcb8b00a3c08cfe7 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Wed, 20 May 2026 12:05:40 +0200 Subject: [PATCH 19/96] Remove first-aid license management and related code --- .../common/configuration/Configuration.java | 4 ---- .../listener/impl/faction/MedicListener.java | 24 ------------------- 2 files changed, 28 deletions(-) diff --git a/src/main/java/de/rettichlp/ucutils/common/configuration/Configuration.java b/src/main/java/de/rettichlp/ucutils/common/configuration/Configuration.java index 2cf94054..dc1e6e60 100644 --- a/src/main/java/de/rettichlp/ucutils/common/configuration/Configuration.java +++ b/src/main/java/de/rettichlp/ucutils/common/configuration/Configuration.java @@ -4,14 +4,12 @@ import de.rettichlp.ucutils.listener.impl.EventListener; import lombok.Data; import net.fabricmc.loader.api.FabricLoader; -import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.IOException; import java.io.Reader; import java.io.Writer; import java.nio.file.Path; -import java.time.LocalDateTime; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -37,8 +35,6 @@ public class Configuration { private int minutesSinceLastPayDay = 0; private int predictedPayDaySalary = 0; private int predictedPayDayExp = 0; - @Nullable - private LocalDateTime firstAidLicenseExpireDateTime = null; private Set halloweenClickedDoors = new HashSet<>(); public void addMinutesSinceLastPayDay(int minutes) { diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/faction/MedicListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/faction/MedicListener.java index c8bc7a6e..6ed5cf36 100644 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/faction/MedicListener.java +++ b/src/main/java/de/rettichlp/ucutils/listener/impl/faction/MedicListener.java @@ -4,7 +4,6 @@ import de.rettichlp.ucutils.common.models.Faction; import de.rettichlp.ucutils.common.registry.UCUtilsListener; import de.rettichlp.ucutils.listener.IMessageReceiveListener; -import net.minecraft.text.MutableText; import net.minecraft.text.Text; import java.time.Duration; @@ -13,7 +12,6 @@ import static de.rettichlp.ucutils.UCUtils.commandService; import static de.rettichlp.ucutils.UCUtils.configuration; -import static de.rettichlp.ucutils.UCUtils.messageService; import static de.rettichlp.ucutils.UCUtils.player; import static de.rettichlp.ucutils.UCUtils.storage; import static de.rettichlp.ucutils.UCUtils.utilService; @@ -21,10 +19,7 @@ import static de.rettichlp.ucutils.common.services.CommandService.COMMAND_COOLDOWN_MILLIS; import static java.time.Duration.ofMinutes; import static java.time.LocalDateTime.now; -import static java.util.Optional.ofNullable; import static java.util.regex.Pattern.compile; -import static net.minecraft.text.Text.of; -import static net.minecraft.util.Formatting.AQUA; @UCUtilsListener public class MedicListener implements IMessageReceiveListener { @@ -37,8 +32,6 @@ public class MedicListener implements IMessageReceiveListener { private static final Pattern MEDIC_PILL_PATTERN = compile("^\\[Medic] Doktor (?:\\[UC])?(?[a-zA-Z0-9_]+) hat dir Schmerzpillen verabreicht\\.$"); private static final Pattern MEDIC_PILL_GIVE_PATTERN = compile("^\\[Medic] Du hast (?:\\[UC])?(?[a-zA-Z0-9_]+) Schmerzpillen verabreicht\\.$"); private static final Pattern MEDIC_REVIVE_START_PATTERN = compile("^Du beginnst mit der Wiederbelebung von (?:\\[UC])?(?[a-zA-Z0-9_]+)\\.\\.\\.$"); - private static final Pattern FIRST_AID_PATTERN = compile("^\\[Erste-Hilfe] (?:\\[UC])?(?[a-zA-Z0-9_]+) hat dir ein Erste-Hilfe-Schein für 14 Tage ausgestellt\\.$"); - private static final Pattern FIRST_AID_LICENCES_PATTERN = compile("^- Erste-Hilfe-Schein: Vorhanden$"); private static final Pattern LABOR_TRANSPORT_STARTED_PATTERN = compile("^\\[ʟᴀʙᴏʀ] Transport gestartet: (?\\d+) ᴋɪsᴛᴇɴ mit (?\\d+) (?.+)$"); private static final Pattern FIRE_START_PATTERN = compile("^News: Es wurde ein Feuer bei .+ gemeldet!$"); @@ -76,23 +69,6 @@ public boolean onMessageReceive(Text text, String message) { return true; } - Matcher firstAidMatcher = FIRST_AID_PATTERN.matcher(message); - if (firstAidMatcher.find()) { - configuration.setFirstAidLicenseExpireDateTime(now().plusDays(14)); - return true; - } - - Matcher firstAidLicencesMatcher = FIRST_AID_LICENCES_PATTERN.matcher(message); - if (firstAidLicencesMatcher.find()) { - MutableText overwriteText = text.copy().append(" ") - .append(of("bis " + ofNullable(configuration.getFirstAidLicenseExpireDateTime()) - .map(messageService::dateTimeToFriendlyString) - .orElse("Unbekannt")).copy().formatted(AQUA)); - - player.sendMessage(overwriteText, false); - return false; // hide message - } - Matcher laborTransportStartedMatcher = LABOR_TRANSPORT_STARTED_PATTERN.matcher(message); if (laborTransportStartedMatcher.find()) { Duration duration = ofMinutes(5).plusSeconds(56); // please don't ask why it is like this From 71ecb3e851a1c5e825b5ea03b28d40f55101bc1e Mon Sep 17 00:00:00 2001 From: RettichLP Date: Wed, 20 May 2026 17:02:06 +0200 Subject: [PATCH 20/96] Remove personal use features and related code --- .../command/faction/PersonalUseCommand.java | 93 ------------ .../common/configuration/options/Options.java | 5 - .../screens/options/MainOptionsScreen.java | 2 - .../options/PersonalUseOptionsScreen.java | 135 ------------------ .../common/models/PersonalUseEntry.java | 13 -- .../resources/assets/ucutils/lang/de_de.json | 3 - .../resources/assets/ucutils/lang/en_gb.json | 3 - .../resources/assets/ucutils/lang/en_us.json | 3 - 8 files changed, 257 deletions(-) delete mode 100644 src/main/java/de/rettichlp/ucutils/command/faction/PersonalUseCommand.java delete mode 100644 src/main/java/de/rettichlp/ucutils/common/gui/screens/options/PersonalUseOptionsScreen.java delete mode 100644 src/main/java/de/rettichlp/ucutils/common/models/PersonalUseEntry.java diff --git a/src/main/java/de/rettichlp/ucutils/command/faction/PersonalUseCommand.java b/src/main/java/de/rettichlp/ucutils/command/faction/PersonalUseCommand.java deleted file mode 100644 index b9bb0e5b..00000000 --- a/src/main/java/de/rettichlp/ucutils/command/faction/PersonalUseCommand.java +++ /dev/null @@ -1,93 +0,0 @@ -package de.rettichlp.ucutils.command.faction; - -import com.mojang.authlib.GameProfile; -import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import de.rettichlp.ucutils.common.registry.CommandBase; -import de.rettichlp.ucutils.common.registry.UCUtilsCommand; -import de.rettichlp.ucutils.listener.IMessageReceiveListener; -import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; -import net.minecraft.client.network.PlayerListEntry; -import net.minecraft.text.Text; -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Pattern; - -import static com.mojang.brigadier.arguments.StringArgumentType.getString; -import static com.mojang.brigadier.arguments.StringArgumentType.word; -import static de.rettichlp.ucutils.UCUtils.commandService; -import static de.rettichlp.ucutils.UCUtils.configuration; -import static de.rettichlp.ucutils.UCUtils.messageService; -import static de.rettichlp.ucutils.UCUtils.networkHandler; -import static de.rettichlp.ucutils.UCUtils.utilService; -import static java.lang.String.valueOf; -import static java.util.regex.Pattern.compile; -import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.argument; -import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal; -import static net.minecraft.command.CommandSource.suggestMatching; - -@UCUtilsCommand(label = "eigenbedarf") -public class PersonalUseCommand extends CommandBase implements IMessageReceiveListener { - - private static final Pattern DEAL_ACCEPTED = compile("^\\[Deal] (?:\\[UC])?(?[a-zA-Z0-9_]+) hat den Deal angenommen\\.$"); - private static final Pattern DEAL_DECLINED = compile("^(?:\\[UC])?(?[a-zA-Z0-9_]+) hat das Angebot abgelehnt\\.$"); - - private List commands = new ArrayList<>(); - - @Override - public LiteralArgumentBuilder execute(@NotNull LiteralArgumentBuilder node) { - return node - .then(literal("give") - .then(argument("player", word()) - .suggests((context, builder) -> { - List list = networkHandler.getPlayerList().stream() - .map(PlayerListEntry::getProfile) - .map(GameProfile::name) - .toList(); - return suggestMatching(list, builder); - }) - .executes(context -> { - String targetPlayer = getString(context, "player"); - this.commands = new ArrayList<>(createCommands("selldrug " + targetPlayer + " %name% %amount% %purity% 0")); - removeAndExecuteFirst(); - return 1; - }))) - .executes(context -> { - commandService.sendCommands(createCommands("dbank get %name% %amount% %purity%"), 1000); - return 1; - }); - } - - @Override - public boolean onMessageReceive(Text text, String message) { - if (DEAL_ACCEPTED.matcher(message).find() || DEAL_DECLINED.matcher(message).find()) { - utilService.delayedAction(this::removeAndExecuteFirst, 500); - } - - return true; - } - - private @NotNull List createCommands(String commandTemplate) { - List commandStrings = configuration.getOptions().personalUse().stream() - .filter(personalUseEntry -> personalUseEntry.getAmount() > 0) - .map(personalUseEntry -> commandTemplate - .replace("%name%", personalUseEntry.getInventoryItem().getDisplayName()) - .replace("%amount%", valueOf(personalUseEntry.getAmount())) - .replace("%purity%", valueOf(personalUseEntry.getPurity().ordinal()))) - .toList(); - - if (commandStrings.isEmpty()) { - messageService.sendModMessage("Du hast keinen Eigenbedarf gesetzt.", false); - } - - return commandStrings; - } - - private void removeAndExecuteFirst() { - if (!this.commands.isEmpty()) { - String firstCommandString = this.commands.removeFirst(); - commandService.sendCommand(firstCommandString); - } - } -} diff --git a/src/main/java/de/rettichlp/ucutils/common/configuration/options/Options.java b/src/main/java/de/rettichlp/ucutils/common/configuration/options/Options.java index 5a5d34ca..d21e7031 100644 --- a/src/main/java/de/rettichlp/ucutils/common/configuration/options/Options.java +++ b/src/main/java/de/rettichlp/ucutils/common/configuration/options/Options.java @@ -2,7 +2,6 @@ import de.rettichlp.ucutils.common.gui.screens.components.CyclingButtonEntry; import de.rettichlp.ucutils.common.models.Color; -import de.rettichlp.ucutils.common.models.PersonalUseEntry; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; @@ -12,9 +11,6 @@ import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.List; - import static de.rettichlp.ucutils.common.configuration.options.Options.AtmInformationType.NONE; import static de.rettichlp.ucutils.common.configuration.options.Options.ReinforcementType.UNICACITYADDON; import static net.minecraft.text.Text.empty; @@ -31,7 +27,6 @@ public class Options { private final NameTagOptions nameTag = new NameTagOptions(); - private final List personalUse = new ArrayList<>(); private final CarOptions car = new CarOptions(); private final SoundOptions sound = new SoundOptions(); private final NotificationOptions notification = new NotificationOptions(); diff --git a/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/MainOptionsScreen.java b/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/MainOptionsScreen.java index 0aa7596f..d98dab10 100644 --- a/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/MainOptionsScreen.java +++ b/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/MainOptionsScreen.java @@ -22,7 +22,6 @@ public class MainOptionsScreen extends OptionsScreen { private static final Text TEXT_SOUNDS = translatable("ucutils.options.text.sounds"); private static final Text TEXT_WIDGETS = translatable("ucutils.options.text.widgets"); private static final Text TEXT_NOTIFICATIONS = translatable("ucutils.options.text.notifications"); - private static final Text TEXT_PERSONAL_USE = translatable("ucutils.options.text.personal_use"); private static final Text HYDRATION_NAME = translatable("ucutils.options.hydration.name"); private static final Text HYDRATION_TOOLTIP = translatable("ucutils.options.hydration.tooltip"); private static final Text BANK_INFORMATION_NAME = translatable("ucutils.options.atm_information.name"); @@ -57,7 +56,6 @@ public void initBody() { renderService.addCyclingButton(directionalLayoutWidget4, BANK_INFORMATION_NAME, Options.AtmInformationType.values(), Options.AtmInformationType::getDisplayName, Options::atmInformationType, Options::atmInformationType, 150); DirectionalLayoutWidget directionalLayoutWidget5 = directionalLayoutWidget.add(horizontal().spacing(8)); - renderService.addButton(directionalLayoutWidget5, TEXT_PERSONAL_USE, button -> this.client.setScreen(new PersonalUseOptionsScreen(this)), 150); renderService.addToggleButton(directionalLayoutWidget5, ENRICHED_KARMA_NAME, ENRICHED_KARMA_TOOLTIP, Options::showEnrichedKarma, Options::showEnrichedKarma, 150); directionalLayoutWidget.forEachChild(this::addDrawableChild); diff --git a/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/PersonalUseOptionsScreen.java b/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/PersonalUseOptionsScreen.java deleted file mode 100644 index e3852ce0..00000000 --- a/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/PersonalUseOptionsScreen.java +++ /dev/null @@ -1,135 +0,0 @@ -package de.rettichlp.ucutils.common.gui.screens.options; - -import de.rettichlp.ucutils.common.gui.screens.OptionsScreen; -import de.rettichlp.ucutils.common.models.InventoryItem; -import de.rettichlp.ucutils.common.models.PersonalUseEntry; -import de.rettichlp.ucutils.common.models.Purity; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.widget.DirectionalLayoutWidget; -import net.minecraft.client.gui.widget.EmptyWidget; -import net.minecraft.client.gui.widget.Positioner; -import net.minecraft.client.gui.widget.TextFieldWidget; -import net.minecraft.client.gui.widget.TextWidget; -import net.minecraft.text.Text; -import org.jetbrains.annotations.NotNull; - -import java.util.List; - -import static de.rettichlp.ucutils.UCUtils.LOGGER; -import static de.rettichlp.ucutils.UCUtils.configuration; -import static de.rettichlp.ucutils.UCUtils.renderService; -import static java.lang.Integer.parseInt; -import static java.lang.String.valueOf; -import static java.util.Arrays.stream; -import static net.minecraft.client.gui.widget.DirectionalLayoutWidget.horizontal; -import static net.minecraft.client.gui.widget.DirectionalLayoutWidget.vertical; -import static net.minecraft.text.Text.empty; -import static net.minecraft.text.Text.of; -import static net.minecraft.text.Text.translatable; - -public class PersonalUseOptionsScreen extends OptionsScreen { - - private static final Text TEXT_PERSONAL_USE = translatable("ucutils.options.text.personal_use"); - private static final Text TEXT_PURITY = translatable("ucutils.options.text.purity"); - private static final Text TEXT_AMOUNT = translatable("ucutils.options.text.amount"); - - public PersonalUseOptionsScreen(Screen parent) { - super(parent, TEXT_PERSONAL_USE); - } - - @Override - public void initBody() { - DirectionalLayoutWidget directionalLayoutWidget = this.layout.addBody(vertical().spacing(4)); - - DirectionalLayoutWidget directionalLayoutWidget1 = directionalLayoutWidget.add(horizontal().spacing(8)); - - EmptyWidget widget = new EmptyWidget(100, 0); - directionalLayoutWidget1.add(widget); - - TextWidget widget1 = new TextWidget(TEXT_PURITY, this.textRenderer); - widget1.setWidth(96); - directionalLayoutWidget1.add(widget1, positioner -> positioner.alignVerticalCenter().alignHorizontalCenter()); - - TextWidget widget2 = new TextWidget(TEXT_AMOUNT, this.textRenderer); - widget2.setWidth(96); - directionalLayoutWidget1.add(widget2, positioner -> positioner.alignVerticalCenter().alignHorizontalCenter()); - - stream(InventoryItem.values()) - .filter(InventoryItem::isDrugBankItem) - .forEach(inventoryItem -> directionalLayoutWidget.add(personalUseRow(inventoryItem))); - - directionalLayoutWidget.forEachChild(this::addDrawableChild); - } - - private @NotNull DirectionalLayoutWidget personalUseRow(@NotNull InventoryItem inventoryItem) { - PersonalUseEntry personalUseEntry = configuration.getOptions().personalUse().stream() - .filter(oue -> oue.getInventoryItem() == inventoryItem) - .findFirst() - .orElseGet(() -> new PersonalUseEntry(inventoryItem)); - - DirectionalLayoutWidget directionalLayoutWidget = horizontal().spacing(8); - - // text - TextWidget widget = new TextWidget(translatable("ucutils.inventory." + inventoryItem.name().toLowerCase()), this.textRenderer); - widget.setWidth(100); - // FIXME widget.alignLeft(); - directionalLayoutWidget.add(widget, Positioner::alignVerticalCenter); - - // purity input - renderService.addCyclingButton(directionalLayoutWidget, TEXT_PURITY, Purity.values(), Purity::getDisplayName, (options, value) -> updatePersonalUseEntry(personalUseEntry, value), options -> personalUseEntry.getPurity(), 96); - - // amount input - DirectionalLayoutWidget widget2 = personalUseInput(personalUseEntry); - directionalLayoutWidget.add(widget2); - - return directionalLayoutWidget; - } - - private @NotNull DirectionalLayoutWidget personalUseInput(@NotNull PersonalUseEntry personalUseEntry) { - DirectionalLayoutWidget directionalLayoutWidget = horizontal(); - - TextFieldWidget widget = new TextFieldWidget(this.textRenderer, 40, 20, empty()); - widget.setWidth(80); - widget.setChangedListener(value -> updatePersonalUseEntry(personalUseEntry, value)); - widget.setEditable(true); - widget.setPlaceholder(of(valueOf(personalUseEntry.getAmount()))); - - TextWidget widget1 = new TextWidget(of(" g"), this.textRenderer); - widget1.setWidth(16); - // FIXME widget1.alignLeft(); - - directionalLayoutWidget.add(widget); - directionalLayoutWidget.add(widget1, Positioner::alignVerticalCenter); - - return directionalLayoutWidget; - } - - private void updatePersonalUseEntry(@NotNull PersonalUseEntry personalUseEntry, Purity newPurity) { - personalUseEntry.setPurity(newPurity); - List personalUseEntries = configuration.getOptions().personalUse(); - personalUseEntries.removeIf(pue -> pue.getInventoryItem() == personalUseEntry.getInventoryItem()); - personalUseEntries.add(personalUseEntry); - } - - private void updatePersonalUseEntry(@NotNull PersonalUseEntry personalUseEntry, String newAmount) { - int parsedInt; - - try { - parsedInt = parseInt(newAmount); - } catch (NumberFormatException e) { - LOGGER.warn("Could not parse personal use amount: {}", newAmount); - parsedInt = -1; - } - - // skip config edit if the amount did not change or is negative - if (parsedInt == personalUseEntry.getAmount() || parsedInt < 0) { - LOGGER.info("Skipping personal use config edit, amount did not change or is negative (newAmount: {}, currentAmount: {})", parsedInt, personalUseEntry.getAmount()); - return; - } - - personalUseEntry.setAmount(parsedInt); - List personalUseEntries = configuration.getOptions().personalUse(); - personalUseEntries.removeIf(pue -> pue.getInventoryItem() == personalUseEntry.getInventoryItem()); - personalUseEntries.add(personalUseEntry); - } -} diff --git a/src/main/java/de/rettichlp/ucutils/common/models/PersonalUseEntry.java b/src/main/java/de/rettichlp/ucutils/common/models/PersonalUseEntry.java deleted file mode 100644 index 10af3db2..00000000 --- a/src/main/java/de/rettichlp/ucutils/common/models/PersonalUseEntry.java +++ /dev/null @@ -1,13 +0,0 @@ -package de.rettichlp.ucutils.common.models; - -import lombok.Data; - -import static de.rettichlp.ucutils.common.models.Purity.BEST; - -@Data -public class PersonalUseEntry { - - private final InventoryItem inventoryItem; - private Purity purity = BEST; - private int amount = 0; -} diff --git a/src/main/resources/assets/ucutils/lang/de_de.json b/src/main/resources/assets/ucutils/lang/de_de.json index 47779bf3..edc3ec51 100644 --- a/src/main/resources/assets/ucutils/lang/de_de.json +++ b/src/main/resources/assets/ucutils/lang/de_de.json @@ -38,16 +38,13 @@ "ucutils.notification.player_enter_report": "%s ist jetzt im Report", "ucutils.notification.player_leave_report": "%s ist nicht mehr im Report", - "ucutils.options.text.amount": "Menge", "ucutils.options.text.automation": "Automatisierung", "ucutils.options.text.chat": "Chat", "ucutils.options.text.car": "Auto", "ucutils.options.text.faction": "Fraktion", "ucutils.options.text.general": "Allgemein", "ucutils.options.text.nametag": "Nametag", - "ucutils.options.text.personal_use": "Eigenbedarf", "ucutils.options.text.position": "Position", - "ucutils.options.text.purity": "Reinheit", "ucutils.options.text.widgets": "Widgets", "ucutils.options.text.sounds": "Sounds", "ucutils.options.text.notifications": "Benachrichtigungen", diff --git a/src/main/resources/assets/ucutils/lang/en_gb.json b/src/main/resources/assets/ucutils/lang/en_gb.json index 2022920d..a638179f 100644 --- a/src/main/resources/assets/ucutils/lang/en_gb.json +++ b/src/main/resources/assets/ucutils/lang/en_gb.json @@ -38,16 +38,13 @@ "ucutils.notification.player_enter_report": "%s is now in a report", "ucutils.notification.player_leave_report": "%s is no longer in a report", - "ucutils.options.text.amount": "Amount", "ucutils.options.text.automation": "Automation", "ucutils.options.text.chat": "Chat", "ucutils.options.text.car": "Car", "ucutils.options.text.faction": "Faction", "ucutils.options.text.general": "General", "ucutils.options.text.nametag": "Nametag", - "ucutils.options.text.personal_use": "Personal use", "ucutils.options.text.position": "Position", - "ucutils.options.text.purity": "Purity", "ucutils.options.text.widgets": "Widgets", "ucutils.options.text.sounds": "Sounds", "ucutils.options.text.notifications": "Notifications", diff --git a/src/main/resources/assets/ucutils/lang/en_us.json b/src/main/resources/assets/ucutils/lang/en_us.json index 2022920d..a638179f 100644 --- a/src/main/resources/assets/ucutils/lang/en_us.json +++ b/src/main/resources/assets/ucutils/lang/en_us.json @@ -38,16 +38,13 @@ "ucutils.notification.player_enter_report": "%s is now in a report", "ucutils.notification.player_leave_report": "%s is no longer in a report", - "ucutils.options.text.amount": "Amount", "ucutils.options.text.automation": "Automation", "ucutils.options.text.chat": "Chat", "ucutils.options.text.car": "Car", "ucutils.options.text.faction": "Faction", "ucutils.options.text.general": "General", "ucutils.options.text.nametag": "Nametag", - "ucutils.options.text.personal_use": "Personal use", "ucutils.options.text.position": "Position", - "ucutils.options.text.purity": "Purity", "ucutils.options.text.widgets": "Widgets", "ucutils.options.text.sounds": "Sounds", "ucutils.options.text.notifications": "Notifications", From 98ceabb43cbb851fdcce3c298d81f58adc10390a Mon Sep 17 00:00:00 2001 From: RettichLP Date: Wed, 20 May 2026 17:04:26 +0200 Subject: [PATCH 21/96] Remove inventory-related translations for powders, herbs, crystals, and grab bags --- src/main/resources/assets/ucutils/lang/de_de.json | 5 ----- src/main/resources/assets/ucutils/lang/en_gb.json | 5 ----- src/main/resources/assets/ucutils/lang/en_us.json | 5 ----- 3 files changed, 15 deletions(-) diff --git a/src/main/resources/assets/ucutils/lang/de_de.json b/src/main/resources/assets/ucutils/lang/de_de.json index edc3ec51..ebabddf1 100644 --- a/src/main/resources/assets/ucutils/lang/de_de.json +++ b/src/main/resources/assets/ucutils/lang/de_de.json @@ -16,11 +16,6 @@ "ucutils.color.yellow": "Gelb", "ucutils.color.white": "Weiß", - "ucutils.inventory.powder": "Pulver", - "ucutils.inventory.herbs": "Kräuter", - "ucutils.inventory.crystals": "Kristalle", - "ucutils.inventory.grab_bag": "Wundertüte", - "ucutils.notification.error.api": "Fehler bei der API Abfrage (%s)", "ucutils.notification.error.configuration": "Konfiguration konnte nicht geladen werden", "ucutils.notification.info.new_version": "Neue UCUtils Version verfügbar", diff --git a/src/main/resources/assets/ucutils/lang/en_gb.json b/src/main/resources/assets/ucutils/lang/en_gb.json index a638179f..bba176f9 100644 --- a/src/main/resources/assets/ucutils/lang/en_gb.json +++ b/src/main/resources/assets/ucutils/lang/en_gb.json @@ -16,11 +16,6 @@ "ucutils.color.yellow": "Yellow", "ucutils.color.white": "White", - "ucutils.inventory.powder": "Powder", - "ucutils.inventory.herbs": "Herbs", - "ucutils.inventory.crystals": "Crystals", - "ucutils.inventory.grab_bag": "Grab bag", - "ucutils.notification.error.api": "API request error (%s)", "ucutils.notification.error.configuration": "Configuration could not be loaded", "ucutils.notification.info.new_version": "New UCUtils version available", diff --git a/src/main/resources/assets/ucutils/lang/en_us.json b/src/main/resources/assets/ucutils/lang/en_us.json index a638179f..bba176f9 100644 --- a/src/main/resources/assets/ucutils/lang/en_us.json +++ b/src/main/resources/assets/ucutils/lang/en_us.json @@ -16,11 +16,6 @@ "ucutils.color.yellow": "Yellow", "ucutils.color.white": "White", - "ucutils.inventory.powder": "Powder", - "ucutils.inventory.herbs": "Herbs", - "ucutils.inventory.crystals": "Crystals", - "ucutils.inventory.grab_bag": "Grab bag", - "ucutils.notification.error.api": "API request error (%s)", "ucutils.notification.error.configuration": "Configuration could not be loaded", "ucutils.notification.info.new_version": "New UCUtils version available", From d00481a3da48c07426104b24bd1eaba08398e463 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Wed, 20 May 2026 17:07:34 +0200 Subject: [PATCH 22/96] Remove unused imports in EntityMixin to clean up code --- src/main/java/de/rettichlp/ucutils/mixin/EntityMixin.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/de/rettichlp/ucutils/mixin/EntityMixin.java b/src/main/java/de/rettichlp/ucutils/mixin/EntityMixin.java index 4e41c228..f0465a80 100644 --- a/src/main/java/de/rettichlp/ucutils/mixin/EntityMixin.java +++ b/src/main/java/de/rettichlp/ucutils/mixin/EntityMixin.java @@ -1,6 +1,5 @@ package de.rettichlp.ucutils.mixin; -import de.rettichlp.ucutils.common.configuration.options.NameTagOptions; import de.rettichlp.ucutils.common.models.Faction; import de.rettichlp.ucutils.common.models.WantedEntry; import de.rettichlp.ucutils.listener.callback.PlayerEnterVehicleCallback; @@ -23,7 +22,6 @@ import java.util.Optional; -import static de.rettichlp.ucutils.UCUtils.configuration; import static de.rettichlp.ucutils.UCUtils.nameTagService; import static de.rettichlp.ucutils.UCUtils.player; import static de.rettichlp.ucutils.UCUtils.storage; @@ -33,7 +31,6 @@ import static net.minecraft.text.Text.empty; import static net.minecraft.text.Text.literal; import static net.minecraft.util.Formatting.GRAY; -import static net.minecraft.util.Formatting.RED; @Mixin(Entity.class) public abstract class EntityMixin { From d23204e7cf5e765d919364f6d9d53428c1698444 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Wed, 20 May 2026 18:54:56 +0200 Subject: [PATCH 23/96] Clear FBank deposit reason after sending custom click action packet --- src/main/java/de/rettichlp/ucutils/mixin/DialogScreenMixin.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/de/rettichlp/ucutils/mixin/DialogScreenMixin.java b/src/main/java/de/rettichlp/ucutils/mixin/DialogScreenMixin.java index de1ff763..1d1a0f10 100644 --- a/src/main/java/de/rettichlp/ucutils/mixin/DialogScreenMixin.java +++ b/src/main/java/de/rettichlp/ucutils/mixin/DialogScreenMixin.java @@ -59,6 +59,7 @@ public abstract class DialogScreenMixin { MinecraftClient client = MinecraftClient.getInstance(); client.getNetworkHandler().sendPacket(customClickActionC2SPacket); + storage.setFBankDepositReason(""); client.setScreen(null); } } From 378f796600ad0df73270e0226d006cc62dc0323e Mon Sep 17 00:00:00 2001 From: RettichLP Date: Wed, 20 May 2026 23:56:21 +0200 Subject: [PATCH 24/96] Remove mobile-related commands (ACall, ASMS, Reply) and associated code --- .../ucutils/command/mobile/ACallCommand.java | 53 ------------------ .../ucutils/command/mobile/ASMSCommand.java | 56 ------------------- .../ucutils/command/mobile/ReplyCommand.java | 38 ------------- .../de/rettichlp/ucutils/common/Storage.java | 11 ---- .../common/services/CommandService.java | 11 ---- .../ucutils/listener/impl/MobileListener.java | 23 -------- 6 files changed, 192 deletions(-) delete mode 100644 src/main/java/de/rettichlp/ucutils/command/mobile/ACallCommand.java delete mode 100644 src/main/java/de/rettichlp/ucutils/command/mobile/ASMSCommand.java delete mode 100644 src/main/java/de/rettichlp/ucutils/command/mobile/ReplyCommand.java diff --git a/src/main/java/de/rettichlp/ucutils/command/mobile/ACallCommand.java b/src/main/java/de/rettichlp/ucutils/command/mobile/ACallCommand.java deleted file mode 100644 index 71596968..00000000 --- a/src/main/java/de/rettichlp/ucutils/command/mobile/ACallCommand.java +++ /dev/null @@ -1,53 +0,0 @@ -package de.rettichlp.ucutils.command.mobile; - -import com.mojang.authlib.GameProfile; -import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import de.rettichlp.ucutils.common.registry.CommandBase; -import de.rettichlp.ucutils.common.registry.UCUtilsCommand; -import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; -import net.minecraft.client.network.PlayerListEntry; -import org.jetbrains.annotations.NotNull; - -import java.util.List; - -import static com.mojang.brigadier.arguments.StringArgumentType.getString; -import static com.mojang.brigadier.arguments.StringArgumentType.word; -import static de.rettichlp.ucutils.UCUtils.commandService; -import static de.rettichlp.ucutils.UCUtils.networkHandler; -import static de.rettichlp.ucutils.UCUtils.storage; -import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.argument; -import static net.minecraft.command.CommandSource.suggestMatching; - -@UCUtilsCommand(label = "acall") -public class ACallCommand extends CommandBase { - - @Override - public LiteralArgumentBuilder execute(@NotNull LiteralArgumentBuilder node) { - return node - .then(argument("player", word()) - .suggests((context, builder) -> { - List list = networkHandler.getPlayerList().stream() - .map(PlayerListEntry::getProfile) - .map(GameProfile::name) - .toList(); - return suggestMatching(list, builder); - }) - .executes(context -> { - String playerName = getString(context, "player"); - - boolean numberAlreadyRetrieved = storage.getRetrievedNumbers().containsKey(playerName); - if (numberAlreadyRetrieved) { - int number = storage.getRetrievedNumbers().get(playerName); - call(number); - } else { - commandService.retrieveNumberAndRun(playerName, this::call); - } - - return 1; - })); - } - - private void call(int number) { - commandService.sendCommand("call " + number); - } -} diff --git a/src/main/java/de/rettichlp/ucutils/command/mobile/ASMSCommand.java b/src/main/java/de/rettichlp/ucutils/command/mobile/ASMSCommand.java deleted file mode 100644 index 316a629f..00000000 --- a/src/main/java/de/rettichlp/ucutils/command/mobile/ASMSCommand.java +++ /dev/null @@ -1,56 +0,0 @@ -package de.rettichlp.ucutils.command.mobile; - -import com.mojang.authlib.GameProfile; -import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import de.rettichlp.ucutils.common.registry.CommandBase; -import de.rettichlp.ucutils.common.registry.UCUtilsCommand; -import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; -import net.minecraft.client.network.PlayerListEntry; -import org.jetbrains.annotations.NotNull; - -import java.util.List; - -import static com.mojang.brigadier.arguments.StringArgumentType.getString; -import static com.mojang.brigadier.arguments.StringArgumentType.greedyString; -import static com.mojang.brigadier.arguments.StringArgumentType.word; -import static de.rettichlp.ucutils.UCUtils.commandService; -import static de.rettichlp.ucutils.UCUtils.networkHandler; -import static de.rettichlp.ucutils.UCUtils.storage; -import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.argument; -import static net.minecraft.command.CommandSource.suggestMatching; - -@UCUtilsCommand(label = "asms") -public class ASMSCommand extends CommandBase { - - @Override - public LiteralArgumentBuilder execute(@NotNull LiteralArgumentBuilder node) { - return node - .then(argument("player", word()) - .suggests((context, builder) -> { - List list = networkHandler.getPlayerList().stream() - .map(PlayerListEntry::getProfile) - .map(GameProfile::name) - .toList(); - return suggestMatching(list, builder); - }) - .then(argument("message", greedyString()) - .executes(context -> { - String playerName = getString(context, "player"); - String message = getString(context, "message"); - - boolean numberAlreadyRetrieved = storage.getRetrievedNumbers().containsKey(playerName); - if (numberAlreadyRetrieved) { - int number = storage.getRetrievedNumbers().get(playerName); - sms(number, message); - } else { - commandService.retrieveNumberAndRun(playerName, number -> sms(number, message)); - } - - return 1; - }))); - } - - private void sms(int number, String message) { - commandService.sendCommand("sms " + number + " " + message); - } -} diff --git a/src/main/java/de/rettichlp/ucutils/command/mobile/ReplyCommand.java b/src/main/java/de/rettichlp/ucutils/command/mobile/ReplyCommand.java deleted file mode 100644 index 06383c74..00000000 --- a/src/main/java/de/rettichlp/ucutils/command/mobile/ReplyCommand.java +++ /dev/null @@ -1,38 +0,0 @@ -package de.rettichlp.ucutils.command.mobile; - -import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import de.rettichlp.ucutils.common.registry.CommandBase; -import de.rettichlp.ucutils.common.registry.UCUtilsCommand; -import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; -import org.jetbrains.annotations.NotNull; - -import static com.mojang.brigadier.arguments.StringArgumentType.getString; -import static com.mojang.brigadier.arguments.StringArgumentType.greedyString; -import static de.rettichlp.ucutils.UCUtils.commandService; -import static de.rettichlp.ucutils.UCUtils.messageService; -import static de.rettichlp.ucutils.UCUtils.storage; -import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.argument; - -@UCUtilsCommand(label = "reply", aliases = "r") -public class ReplyCommand extends CommandBase { - - @Override - public LiteralArgumentBuilder execute(@NotNull LiteralArgumentBuilder node) { - return node - .then(argument("message", greedyString()) - .executes(context -> { - String message = getString(context, "message"); - - int lastReceivedSmsNumber = storage.getLastReceivedSmsNumber(); - - if (lastReceivedSmsNumber < 0) { - messageService.sendModMessage("Kein SMS-Empfänger gefunden.", false); - return 1; - } - - commandService.sendCommand("sms " + lastReceivedSmsNumber + " " + message); - - return 1; - })); - } -} diff --git a/src/main/java/de/rettichlp/ucutils/common/Storage.java b/src/main/java/de/rettichlp/ucutils/common/Storage.java index 5e0cc47f..f96efd57 100644 --- a/src/main/java/de/rettichlp/ucutils/common/Storage.java +++ b/src/main/java/de/rettichlp/ucutils/common/Storage.java @@ -65,9 +65,6 @@ public class Storage { @Getter private final Map playerFactionCache = new HashMap<>(); - @Getter - private final Map retrievedNumbers = new HashMap<>(); - @Getter private final List wantedEntries = new ArrayList<>(); @@ -100,10 +97,6 @@ public class Storage { @Setter private long joinTimestamp = 0; - @Getter - @Setter - private int lastReceivedSmsNumber = -1; - @Getter @Setter private MinecartEntity minecartEntityToHighlight; @@ -157,8 +150,6 @@ public void print() { LOGGER.info("medicPillCooldowns[{}]: {}", this.medicPillCooldowns.size(), this.medicPillCooldowns); // playerFactionCache LOGGER.info("playerFactionCache[{}]: {}", this.playerFactionCache.size(), this.playerFactionCache); - // retrievedNumbers - LOGGER.info("retrievedNumbers[{}]: {}", this.retrievedNumbers.size(), this.retrievedNumbers); // wantedEntries LOGGER.info("wantedEntries[{}]: {}", this.wantedEntries.size(), this.wantedEntries); // activeServices @@ -175,8 +166,6 @@ public void print() { LOGGER.info("hydration: {}", this.hydration); // joinTimestamp LOGGER.info("joinTimestamp: {}", this.joinTimestamp); - // lastReceivedSmsNumber - LOGGER.info("lastReceivedSmsNumber: {}", this.lastReceivedSmsNumber); // minecartEntityToHighlight LOGGER.info("minecartEntityToHighlight: {}", this.minecartEntityToHighlight); // moneyAtmAmount diff --git a/src/main/java/de/rettichlp/ucutils/common/services/CommandService.java b/src/main/java/de/rettichlp/ucutils/common/services/CommandService.java index 7dedc38e..a6a00ca4 100644 --- a/src/main/java/de/rettichlp/ucutils/common/services/CommandService.java +++ b/src/main/java/de/rettichlp/ucutils/common/services/CommandService.java @@ -9,19 +9,15 @@ import java.util.Map; import java.util.Timer; import java.util.TimerTask; -import java.util.function.Consumer; import static de.rettichlp.ucutils.UCUtils.LOGGER; -import static de.rettichlp.ucutils.UCUtils.messageService; import static de.rettichlp.ucutils.UCUtils.nameTagService; import static de.rettichlp.ucutils.UCUtils.networkHandler; import static de.rettichlp.ucutils.UCUtils.player; import static de.rettichlp.ucutils.UCUtils.storage; -import static de.rettichlp.ucutils.UCUtils.utilService; import static java.lang.Boolean.getBoolean; import static java.lang.System.currentTimeMillis; import static java.util.Objects.nonNull; -import static java.util.Optional.ofNullable; public class CommandService { @@ -90,11 +86,4 @@ public boolean showCommandOutputMessage(String command) { public boolean isSuperUser() { return nonNull(player) && (UUID_RETTICHLP.equals(player.getUuidAsString()) || getBoolean("fabric.development")); } - - public void retrieveNumberAndRun(String playerName, Consumer runWithNumber) { - sendCommand("nummer " + playerName); - - utilService.delayedAction(() -> ofNullable(storage.getRetrievedNumbers().get(playerName)) - .ifPresentOrElse(runWithNumber, () -> messageService.sendModMessage("Die Nummer von " + playerName + " konnte nicht abgerufen werden.", false)), COMMAND_COOLDOWN_MILLIS); - } } diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/MobileListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/MobileListener.java index 0aa8baec..6551c205 100644 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/MobileListener.java +++ b/src/main/java/de/rettichlp/ucutils/listener/impl/MobileListener.java @@ -8,40 +8,17 @@ import java.util.regex.Pattern; import static de.rettichlp.ucutils.UCUtils.commandService; -import static de.rettichlp.ucutils.UCUtils.storage; import static de.rettichlp.ucutils.UCUtils.utilService; import static de.rettichlp.ucutils.common.services.CommandService.COMMAND_COOLDOWN_MILLIS; -import static java.lang.Integer.parseInt; import static java.util.regex.Pattern.compile; @UCUtilsListener public class MobileListener implements IMessageReceiveListener { - private static final Pattern MOBILE_NUMBER_PATTERN = compile("^Nummer von (?:\\[UC])?(?[a-zA-Z0-9_]+): (?\\d+)$"); - private static final Pattern MOBILE_SMS_RECEIVE_PATTERN = compile("^Dein Handy klingelt! Eine Nachricht von (?:\\[UC])?(?[a-zA-Z0-9_]+) \\((?\\d+)\\)\\.$"); private static final Pattern MOBILE_OFF_PATTERN = compile("^Dein Handy ist ausgeschaltet\\.$"); @Override public boolean onMessageReceive(Text text, String message) { - Matcher mobileNumberMatcher = MOBILE_NUMBER_PATTERN.matcher(message); - if (mobileNumberMatcher.find()) { - String playerName = mobileNumberMatcher.group("playerName"); - int number = parseInt(mobileNumberMatcher.group("number")); - storage.getRetrievedNumbers().put(playerName, number); - return true; - } - - Matcher mobileSmsReceiveMatcher = MOBILE_SMS_RECEIVE_PATTERN.matcher(message); - if (mobileSmsReceiveMatcher.find()) { - String playerName = mobileSmsReceiveMatcher.group("playerName"); - int number = parseInt(mobileSmsReceiveMatcher.group("number")); - - storage.getRetrievedNumbers().put(playerName, number); - storage.setLastReceivedSmsNumber(number); - - return true; - } - Matcher mobileOffMatcher = MOBILE_OFF_PATTERN.matcher(message); if (mobileOffMatcher.find()) { utilService.delayedAction(() -> commandService.sendCommand("togglephone"), COMMAND_COOLDOWN_MILLIS); From b1422a19074db629ab8e33cbf7c53177ccfc261b Mon Sep 17 00:00:00 2001 From: RettichLP Date: Thu, 21 May 2026 00:10:57 +0200 Subject: [PATCH 25/96] Remove admin duty tag and related code --- .../rettichlp/ucutils/common/services/NameTagService.java | 6 ------ .../ucutils/mixin/PlayerEntityRendererMixin.java | 8 -------- 2 files changed, 14 deletions(-) diff --git a/src/main/java/de/rettichlp/ucutils/common/services/NameTagService.java b/src/main/java/de/rettichlp/ucutils/common/services/NameTagService.java index b29936f4..462fe6c7 100644 --- a/src/main/java/de/rettichlp/ucutils/common/services/NameTagService.java +++ b/src/main/java/de/rettichlp/ucutils/common/services/NameTagService.java @@ -29,14 +29,8 @@ public class NameTagService { - public static final MutableText A_DUTY_TAG = empty() - .append(literal("ᴀ").formatted(BLUE, BOLD)) - .append(literal("ᴅᴜᴛʏ").formatted(RED, BOLD)); - public static final MutableText AFK_TAG = literal("ᴀꜰᴋ").formatted(GOLD, BOLD); - public static final MutableText HOUSE_BAN_TAG = literal("Hᴀᴜѕᴠᴇʀʙᴏᴛ").formatted(RED, BOLD); - private static final MutableText A_DUTY_PREFIX = empty() .append(literal("[").formatted(DARK_GRAY)) .append(literal("UC").formatted(BLUE)) diff --git a/src/main/java/de/rettichlp/ucutils/mixin/PlayerEntityRendererMixin.java b/src/main/java/de/rettichlp/ucutils/mixin/PlayerEntityRendererMixin.java index 9f49172d..0359660b 100644 --- a/src/main/java/de/rettichlp/ucutils/mixin/PlayerEntityRendererMixin.java +++ b/src/main/java/de/rettichlp/ucutils/mixin/PlayerEntityRendererMixin.java @@ -17,7 +17,6 @@ import static de.rettichlp.ucutils.UCUtils.nameTagService; import static de.rettichlp.ucutils.UCUtils.storage; import static de.rettichlp.ucutils.common.services.NameTagService.AFK_TAG; -import static de.rettichlp.ucutils.common.services.NameTagService.A_DUTY_TAG; @Mixin(PlayerEntityRenderer.class) public abstract class PlayerEntityRendererMixin { @@ -53,13 +52,6 @@ public abstract class PlayerEntityRendererMixin { orderedRenderCommandQueue.submitLabel(matrixStack, playerEntityRenderState.nameLabelPos, 0, medicInformation, !playerEntityRenderState.sneaking, playerEntityRenderState.light, playerEntityRenderState.squaredDistanceToCamera, cameraRenderState); } - // handle admin duty tag - if (configuration.getOptions().nameTag().aDuty() && nameTagService.isADuty(playerName)) { - matrixStack.translate(0.0F, medicInformationPresent ? 0.8F : 2.6, 0.0F); - orderedRenderCommandQueue.submitLabel(matrixStack, playerEntityRenderState.nameLabelPos, 0, A_DUTY_TAG, !playerEntityRenderState.sneaking, playerEntityRenderState.light, playerEntityRenderState.squaredDistanceToCamera, cameraRenderState); - return; - } - // handle afk tag if (configuration.getOptions().nameTag().afk() && nameTagService.isAfk(playerName)) { matrixStack.translate(0.0F, medicInformationPresent ? 0.8F : 2.6, 0.0F); From cc5df2f65c2ff1a1c59e367eb1f9d22b77ef0e35 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Thu, 21 May 2026 00:16:34 +0200 Subject: [PATCH 26/96] Update README to refine AFK display description --- README.md | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 2f9213f6..f4d50cc2 100644 --- a/README.md +++ b/README.md @@ -12,21 +12,25 @@ reibungsloser und angenehmer gestalten. gültigen Command umgewandelt - Als Business-Besitzer wird in der Business-Info ein Button angezeigt, um die Einnahmen direkt abzubuchen - Wirft man eine Glasflasche in der Nähe eines Shops weg, wird diese als Pfand abgegeben -- Es wird angezeigt wie lang der Cooldown für Bandagen und Schmerzpillen ist +- Es wird angezeigt, wie lang der Cooldown für Bandagen und Schmerzpillen ist - Es werden Sounds abgespielt für Notrufe, Bomben, Feuer, Staatsbankraub und weitere Situationen - Über der Hungerleiste wird der Durst angezeigt - Mit einem Rechtsklick, während man schleicht, kann man bewusstlosen Personen Erste-Hilfe geben -- Über dem Spielernamen wird eine Information angezeigt, wenn ein Spieler AFK oder im A-Duty ist +- Über den Spielernamen wird AFK angezeigt, wenn der Spieler AFK ist - Für Teammitglieder wird eine Warnung angezeigt, wenn sie sich im Admindienst befinden und eine Waffe in der Hand haben -- Hinter der Nachricht, dass sich das Karma geändert hat, wird angezeigt, wie viel Karma man insgesamt besitzt und wann ein Spieler despawnen sollte (falls das Karma durch einen Kill geändert wurde) +- Hinter der Nachricht, dass sich das Karma geändert hat, wird angezeigt, wie viel Karma man insgesamt besitzt und wann ein Spieler + despawnen sollte (falls das Karma durch einen Kill geändert wurde) - Bei der Mieterübersicht wird angezeigt wie lang ein Mieter offline ist und ein Button um diesen zu kündigen - Beim Beten wird nach 15 Sekunden automatisch der zweite Befehl ausgeführt -- Es gibt Benachrichtigungen, wenn ein Spieler den Server betritt oder verlässt, einen Report betritt oder verlässt, den Baumodus betritt oder verlässt und den Admindienst betritt oder verlässt +- Es gibt Benachrichtigungen, wenn ein Spieler den Server betritt oder verlässt, einen Report betritt oder verlässt, den Baumodus + betritt oder verlässt und den Admindienst betritt oder verlässt ### Auto - Beim Suchen seines Fahrzeugs (`/car find`) wird automatisch das erste Fahrzeug ausgewählt - Werden die Koordinaten eines Autos angezeigt, wird automatisch eine Navigation zu diesen gestartet + +Folgende Funktionen sind nur für Spieler ohne Premium-Rang verfügbar, da Spieler mit Premium diese Funktion vom Server aus können: - Das Auf-/Abschließen eines Fahrzeuges wurde teilweise automatisiert (automatisches Klicken des Items im Inventar) - Beim Rechtsklick auf das eigene Fahrzeug wird automatisch `/car lock` ausgeführt - Steigt man in ein Fahrzeug ein, wird dieses automatisch gestartet und abgeschlossen @@ -46,7 +50,8 @@ reibungsloser und angenehmer gestalten. - Eine Plantage kann durch einen Rechtsklick mit einem Wassereimer oder Dünger direkt gewässert beziehungsweise gedüngt werden - Der Rettungsdienst kann durch einen Rechtsklick auf eine bewusstlose Person diese wiederbeleben - Mit `/fbank einzahlen ` kann das Eingabe GUI des Servers übersprungen werden -- Für den Rettungsdienst gibt es im Herstellungs-Inventar für Medikamente einen Button, um die benötigte Anzahl an Stoffen in den Fraktionschat zu senden +- Für den Rettungsdienst gibt es im Herstellungs-Inventar für Medikamente einen Button, um die benötigte Anzahl an Stoffen in den + Fraktionschat zu senden ### Jobs @@ -102,11 +107,3 @@ reibungsloser und angenehmer gestalten. |------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `/einzahlen ()` | Zahlt das gesamte Bargeld in den ATM in der Nähe ein | | `/adropmoney` | Bucht für den Geldtransport-Job so viel Geld vom Konto ab, sodass das Geld vom Geldtransport-Job in den ATM eingezahlt werden kann und bucht das Geld anschließend zurück auf das Konto | - -**Handy** - -| Befehl | Beschreibung | -|-----------------------------------|--------------------------------------------------------------------------| -| `/acall ` | Ermöglicht das Anrufen mittels Spielername statt der Nummer | -| `/asms ` | Ermöglicht das Schreiben einer SMS mittels Spielername statt der Nummer | -| `/reply ` | Antwortet direkt auf eine SMS | From 989cfd6a3b7792f456375510f4f6e2f8bdc6c9ff Mon Sep 17 00:00:00 2001 From: RettichLP Date: Thu, 21 May 2026 00:32:21 +0200 Subject: [PATCH 27/96] Pathfinding: Remove ItemButtonWidget and TableHeaderTextWidget classes --- .../screens/components/ItemButtonWidget.java | 32 ------- .../components/TableHeaderTextWidget.java | 88 ------------------- 2 files changed, 120 deletions(-) delete mode 100644 src/main/java/de/rettichlp/ucutils/common/gui/screens/components/ItemButtonWidget.java delete mode 100644 src/main/java/de/rettichlp/ucutils/common/gui/screens/components/TableHeaderTextWidget.java diff --git a/src/main/java/de/rettichlp/ucutils/common/gui/screens/components/ItemButtonWidget.java b/src/main/java/de/rettichlp/ucutils/common/gui/screens/components/ItemButtonWidget.java deleted file mode 100644 index 4beef24b..00000000 --- a/src/main/java/de/rettichlp/ucutils/common/gui/screens/components/ItemButtonWidget.java +++ /dev/null @@ -1,32 +0,0 @@ -package de.rettichlp.ucutils.common.gui.screens.components; - -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.tooltip.Tooltip; -import net.minecraft.client.gui.widget.ButtonWidget; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.text.Text; - -import static net.minecraft.text.Text.translatable; - -public class ItemButtonWidget extends ButtonWidget { - - private final Item item; - - public ItemButtonWidget(String key, Item item, PressAction onPress) { - super(0, 0, 20, 20, Text.empty(), onPress, DEFAULT_NARRATION_SUPPLIER); - this.item = item; - setTooltip(Tooltip.of(translatable(key))); - } - - @Override - protected void renderWidget(DrawContext context, int mouseX, int mouseY, float delta) { - super.renderWidget(context, mouseX, mouseY, delta); - - int x = getX() + (getWidth() / 2) - 8; - int y = getY() + (getHeight() / 2) - 8; - - ItemStack stack = new ItemStack(this.item); - context.drawItem(stack, x, y); - } -} diff --git a/src/main/java/de/rettichlp/ucutils/common/gui/screens/components/TableHeaderTextWidget.java b/src/main/java/de/rettichlp/ucutils/common/gui/screens/components/TableHeaderTextWidget.java deleted file mode 100644 index 04d6ff54..00000000 --- a/src/main/java/de/rettichlp/ucutils/common/gui/screens/components/TableHeaderTextWidget.java +++ /dev/null @@ -1,88 +0,0 @@ -package de.rettichlp.ucutils.common.gui.screens.components; - -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.font.TextRenderer; -import net.minecraft.client.gui.Click; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder; -import net.minecraft.client.gui.widget.ClickableWidget; -import net.minecraft.text.Text; -import org.jetbrains.annotations.NotNull; - -import java.util.Comparator; -import java.util.function.Consumer; - -import static de.rettichlp.ucutils.common.gui.screens.components.TableHeaderTextWidget.SortingDirection.ASCENDING; -import static de.rettichlp.ucutils.common.gui.screens.components.TableHeaderTextWidget.SortingDirection.DESCENDING; -import static de.rettichlp.ucutils.common.gui.screens.components.TableHeaderTextWidget.SortingDirection.NONE; -import static net.minecraft.text.Text.empty; -import static net.minecraft.text.Text.of; -import static net.minecraft.util.Formatting.AQUA; - -public class TableHeaderTextWidget extends ClickableWidget { - - private static final TextRenderer TEXT_RENDERER = MinecraftClient.getInstance().textRenderer; - - private final Text text; - private final Consumer onChange; - private SortingDirection sortingDirection; - - public TableHeaderTextWidget(Text text, Consumer onChange, SortingDirection initialSortingDirection) { - super(0, 0, TEXT_RENDERER.getWidth(text), TEXT_RENDERER.fontHeight, empty()); - this.text = text; - this.onChange = onChange; - this.sortingDirection = initialSortingDirection; - } - - @Override - protected void renderWidget(@NotNull DrawContext context, int mouseX, int mouseY, float delta) { - Text modifiedText = getModifiedText(); - int textWidth = TEXT_RENDERER.getWidth(modifiedText); - context.drawText(TEXT_RENDERER, modifiedText, getX() + (getWidth() - textWidth) / 2, getY(), 0xFFFFFFFF, false); - } - - @Override - public boolean mouseClicked(Click click, boolean doubled) { - boolean mouseClicked = super.mouseClicked(click, doubled); - - if (click.button() != 0 || !isMouseOver(click.x(), click.y())) { - return mouseClicked; - } - - this.sortingDirection = switch (this.sortingDirection) { - case NONE -> ASCENDING; - case ASCENDING -> DESCENDING; - case DESCENDING -> NONE; - }; - - this.onChange.accept(this.sortingDirection); - - return mouseClicked; - } - - @Override - protected void appendClickableNarrations(NarrationMessageBuilder builder) { - - } - - private Text getModifiedText() { - String arrow = switch (this.sortingDirection) { - case ASCENDING -> " ↓"; - case DESCENDING -> " ↑"; - default -> ""; - }; - - return this.text.copy().append(of(arrow).copy().formatted(AQUA)); - } - - public enum SortingDirection { - - NONE, - ASCENDING, - DESCENDING; - - public Comparator apply(Comparator comparator) { - return this == DESCENDING ? comparator.reversed() : comparator; - } - } -} From 6f10c40d25d59eb6af2d8ae7fb20cf36d032759b Mon Sep 17 00:00:00 2001 From: RettichLP Date: Thu, 21 May 2026 00:34:06 +0200 Subject: [PATCH 28/96] Pathfinding: Remove IEntityRightClickListener and IKeyPressListener interfaces and related code --- .../ucutils/common/registry/Registry.java | 19 ------------------- .../listener/IEntityRightClickListener.java | 11 ----------- .../ucutils/listener/IKeyPressListener.java | 6 ------ 3 files changed, 36 deletions(-) delete mode 100644 src/main/java/de/rettichlp/ucutils/listener/IEntityRightClickListener.java delete mode 100644 src/main/java/de/rettichlp/ucutils/listener/IKeyPressListener.java diff --git a/src/main/java/de/rettichlp/ucutils/common/registry/Registry.java b/src/main/java/de/rettichlp/ucutils/common/registry/Registry.java index 3353b99e..dfa51a60 100644 --- a/src/main/java/de/rettichlp/ucutils/common/registry/Registry.java +++ b/src/main/java/de/rettichlp/ucutils/common/registry/Registry.java @@ -7,9 +7,7 @@ import de.rettichlp.ucutils.listener.ICommandSendListener; import de.rettichlp.ucutils.listener.IEnterVehicleListener; import de.rettichlp.ucutils.listener.IEntityRenderListener; -import de.rettichlp.ucutils.listener.IEntityRightClickListener; import de.rettichlp.ucutils.listener.IHudRenderListener; -import de.rettichlp.ucutils.listener.IKeyPressListener; import de.rettichlp.ucutils.listener.IMessageReceiveListener; import de.rettichlp.ucutils.listener.IMessageSendListener; import de.rettichlp.ucutils.listener.IMoveListener; @@ -26,9 +24,6 @@ import net.fabricmc.fabric.api.client.rendering.v1.world.WorldRenderEvents; import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents; import net.fabricmc.fabric.api.event.player.UseBlockCallback; -import net.fabricmc.fabric.api.event.player.UseEntityCallback; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.option.KeyBinding; import net.minecraft.util.math.BlockPos; import org.jetbrains.annotations.NotNull; @@ -144,12 +139,6 @@ public void registerListeners() { this.lastPlayerPos = blockPos; getListenersImplementing(IMoveListener.class).forEach(iMoveListener -> iMoveListener.onMove(blockPos)); } - - // handle key press - KeyBinding swapHandsKey = MinecraftClient.getInstance().options.swapHandsKey; - if (swapHandsKey.isPressed()) { - getListenersImplementing(IKeyPressListener.class).forEach(IKeyPressListener::onSwapHandsKeyPress); - } }); HudRenderCallback.EVENT.register((drawContext, tickCounter) -> getListenersImplementing(IHudRenderListener.class).forEach(iHudRenderListener -> iHudRenderListener.onHudRender(drawContext, tickCounter))); @@ -166,14 +155,6 @@ public void registerListeners() { return PASS; }); - UseEntityCallback.EVENT.register((player, world, hand, entity, hitResult) -> { - if (hand != OFF_HAND && world.isClient()) { - getListenersImplementing(IEntityRightClickListener.class).forEach(iEntityRightClickListener -> iEntityRightClickListener.onEntityRightClick(world, hand, entity, hitResult)); - } - - return PASS; - }); - WorldRenderEvents.AFTER_ENTITIES.register(context -> getListenersImplementing(IEntityRenderListener.class).forEach(iEntityRenderListener -> iEntityRenderListener.onEntityRender(context))); // prevent multiple registrations of listeners diff --git a/src/main/java/de/rettichlp/ucutils/listener/IEntityRightClickListener.java b/src/main/java/de/rettichlp/ucutils/listener/IEntityRightClickListener.java deleted file mode 100644 index ccc0ac9d..00000000 --- a/src/main/java/de/rettichlp/ucutils/listener/IEntityRightClickListener.java +++ /dev/null @@ -1,11 +0,0 @@ -package de.rettichlp.ucutils.listener; - -import net.minecraft.entity.Entity; -import net.minecraft.util.Hand; -import net.minecraft.util.hit.EntityHitResult; -import net.minecraft.world.World; - -public interface IEntityRightClickListener extends IUCUtilsListener { - - void onEntityRightClick(World world, Hand hand, Entity entity, EntityHitResult hitResult); -} diff --git a/src/main/java/de/rettichlp/ucutils/listener/IKeyPressListener.java b/src/main/java/de/rettichlp/ucutils/listener/IKeyPressListener.java deleted file mode 100644 index 4badaba5..00000000 --- a/src/main/java/de/rettichlp/ucutils/listener/IKeyPressListener.java +++ /dev/null @@ -1,6 +0,0 @@ -package de.rettichlp.ucutils.listener; - -public interface IKeyPressListener extends IUCUtilsListener { - - void onSwapHandsKeyPress(); -} From ad215778d32eb2a2f227e9ca340e7449b76430a8 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Thu, 21 May 2026 00:36:43 +0200 Subject: [PATCH 29/96] Remove `/mi` and `/mia` commands and related code --- README.md | 2 - .../rettichlp/ucutils/command/MiCommand.java | 45 ------------------- .../rettichlp/ucutils/command/MiaCommand.java | 45 ------------------- 3 files changed, 92 deletions(-) delete mode 100644 src/main/java/de/rettichlp/ucutils/command/MiCommand.java delete mode 100644 src/main/java/de/rettichlp/ucutils/command/MiaCommand.java diff --git a/README.md b/README.md index f4d50cc2..2bcb383d 100644 --- a/README.md +++ b/README.md @@ -78,8 +78,6 @@ Folgende Funktionen sind nur für Spieler ohne Premium-Rang verfügbar, da Spiel | Befehl | Beschreibung | |-----------------------------------|-----------------------------------------------------------------------------------------------------------------| | `/ucutils ()` | Zeigt nützliche Status-Informationen über das Projekt an oder startet eine Synchronisierung | -| `/mi` | Alias für `/memberinfo` | -| `/mia` | Alias für `/memberinfoall` | | `/screenshot` | Erstellt einen Screenshot in einer bestimmten Kategorie | | `/shutdown ` | Aktiviert das automatische Herunterfahren des PCs nachdem man nicht mehr auf dem Friedhof oder im Gefängnis ist | | `/selldrugall` `/sda` | Verkauft alle illegalen Drogen für 0$ an den angegebenen Spieler (Pulver, Kräuter, Kristalle und Wundertüten) | diff --git a/src/main/java/de/rettichlp/ucutils/command/MiCommand.java b/src/main/java/de/rettichlp/ucutils/command/MiCommand.java deleted file mode 100644 index 9b93ce2c..00000000 --- a/src/main/java/de/rettichlp/ucutils/command/MiCommand.java +++ /dev/null @@ -1,45 +0,0 @@ -package de.rettichlp.ucutils.command; - -import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import de.rettichlp.ucutils.common.models.Faction; -import de.rettichlp.ucutils.common.registry.CommandBase; -import de.rettichlp.ucutils.common.registry.UCUtilsCommand; -import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; -import org.jetbrains.annotations.NotNull; - -import static com.mojang.brigadier.arguments.StringArgumentType.getString; -import static com.mojang.brigadier.arguments.StringArgumentType.greedyString; -import static de.rettichlp.ucutils.UCUtils.commandService; -import static de.rettichlp.ucutils.UCUtils.messageService; -import static de.rettichlp.ucutils.UCUtils.player; -import static de.rettichlp.ucutils.UCUtils.storage; -import static de.rettichlp.ucutils.common.models.Faction.fromDisplayName; -import static java.util.Arrays.stream; -import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.argument; -import static net.minecraft.command.CommandSource.suggestMatching; - -@UCUtilsCommand(label = "mi") -public class MiCommand extends CommandBase { - - @Override - public LiteralArgumentBuilder execute(@NotNull LiteralArgumentBuilder node) { - return node - .then(argument("faction", greedyString()) - .suggests((context, builder) -> suggestMatching(stream(Faction.values()) - .map(Faction::getDisplayName), builder)) - .executes(context -> { - String input = getString(context, "faction"); - fromDisplayName(input).ifPresentOrElse(faction -> commandService.sendCommand("memberinfo " + faction.getDisplayName()), - () -> messageService.sendModMessage("Die Fraktion " + input + " konnte nicht gefunden werden.", false)); - - return 1; - }) - ) - .executes(context -> { - String playerName = player.getGameProfile().name(); - Faction faction = storage.getFaction(playerName); - commandService.sendCommand("memberinfo " + faction.getDisplayName()); - return 1; - }); - } -} diff --git a/src/main/java/de/rettichlp/ucutils/command/MiaCommand.java b/src/main/java/de/rettichlp/ucutils/command/MiaCommand.java deleted file mode 100644 index dc8f4441..00000000 --- a/src/main/java/de/rettichlp/ucutils/command/MiaCommand.java +++ /dev/null @@ -1,45 +0,0 @@ -package de.rettichlp.ucutils.command; - -import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import de.rettichlp.ucutils.common.models.Faction; -import de.rettichlp.ucutils.common.registry.CommandBase; -import de.rettichlp.ucutils.common.registry.UCUtilsCommand; -import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; -import org.jetbrains.annotations.NotNull; - -import static com.mojang.brigadier.arguments.StringArgumentType.getString; -import static com.mojang.brigadier.arguments.StringArgumentType.greedyString; -import static de.rettichlp.ucutils.UCUtils.commandService; -import static de.rettichlp.ucutils.UCUtils.messageService; -import static de.rettichlp.ucutils.UCUtils.player; -import static de.rettichlp.ucutils.UCUtils.storage; -import static de.rettichlp.ucutils.common.models.Faction.fromDisplayName; -import static java.util.Arrays.stream; -import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.argument; -import static net.minecraft.command.CommandSource.suggestMatching; - -@UCUtilsCommand(label = "mia") -public class MiaCommand extends CommandBase { - - @Override - public LiteralArgumentBuilder execute(@NotNull LiteralArgumentBuilder node) { - return node - .then(argument("faction", greedyString()) - .suggests((context, builder) -> suggestMatching(stream(Faction.values()) - .map(Faction::getDisplayName), builder)) - .executes(context -> { - String input = getString(context, "faction"); - fromDisplayName(input).ifPresentOrElse(faction -> commandService.sendCommand("memberinfoall " + faction.getDisplayName()), - () -> messageService.sendModMessage("Die Fraktion " + input + " konnte nicht gefunden werden.", false)); - - return 1; - }) - ) - .executes(context -> { - String playerName = player.getGameProfile().name(); - Faction faction = storage.getFaction(playerName); - commandService.sendCommand("memberinfoall " + faction.getDisplayName()); - return 1; - }); - } -} From f57b5d558661b6058b474e0d98c27382e93e1726 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Thu, 21 May 2026 00:36:57 +0200 Subject: [PATCH 30/96] Remove `/dbankdropall` (`/dda`) command and related code --- README.md | 2 - .../command/faction/DBankDropAllCommand.java | 54 ------------------- 2 files changed, 56 deletions(-) delete mode 100644 src/main/java/de/rettichlp/ucutils/command/faction/DBankDropAllCommand.java diff --git a/README.md b/README.md index 2bcb383d..9e275fdb 100644 --- a/README.md +++ b/README.md @@ -94,10 +94,8 @@ Folgende Funktionen sind nur für Spieler ohne Premium-Rang verfügbar, da Spiel | Befehl | Beschreibung | |------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------| -| `/eigenbedarf` | Nimmt eine eingestellte Menge an Drogen aus der Drogenbank einer Fraktion oder gibt diese an einen Spieler | | `/schwarzmarkt` | Zeigt alle Schwarzmärkte an einschließlich des Zeitpunkts des letzten Besuchs des Ortes und einer Markierung ob sich der Schwarzmarkt dort befand | | `/dealer` | Zeigt alle Dealer an einschließlich des Zeitpunkts des letzten Besuchs des Ortes und einer Markierung ob sich der Dealer dort befand | -| `/dbankdropall` `/dda` | Legt alle Drogen in die Drogenbank der Fraktion (Pulver, Kräuter, Kristalle und Wundertüten) | **Geld** diff --git a/src/main/java/de/rettichlp/ucutils/command/faction/DBankDropAllCommand.java b/src/main/java/de/rettichlp/ucutils/command/faction/DBankDropAllCommand.java deleted file mode 100644 index 37ae0df5..00000000 --- a/src/main/java/de/rettichlp/ucutils/command/faction/DBankDropAllCommand.java +++ /dev/null @@ -1,54 +0,0 @@ -package de.rettichlp.ucutils.command.faction; - -import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import de.rettichlp.ucutils.common.models.InventoryItem; -import de.rettichlp.ucutils.common.registry.CommandBase; -import de.rettichlp.ucutils.common.registry.UCUtilsCommand; -import de.rettichlp.ucutils.listener.impl.InventoryListener; -import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.List; - -import static de.rettichlp.ucutils.UCUtils.commandService; -import static de.rettichlp.ucutils.UCUtils.storage; -import static de.rettichlp.ucutils.UCUtils.utilService; -import static de.rettichlp.ucutils.common.models.InventoryItem.POWDER; - -@UCUtilsCommand(label = "dbankdropall", aliases = "dda") -public class DBankDropAllCommand extends CommandBase { - - @Override - public LiteralArgumentBuilder execute(@NotNull LiteralArgumentBuilder node) { - return node - .executes(context -> { - // sync inventory - InventoryListener.inventorySyncStep = POWDER; - commandService.sendCommand("inv"); - - utilService.delayedAction(() -> { - // handle - List commandQueue = new ArrayList<>(); - - storage.getInventory().entrySet().stream() - .filter(ingredientMapEntry -> ingredientMapEntry.getKey().isDrugBankItem()) - .forEach(inventoryItemMapEntry -> { - InventoryItem inventoryItem = inventoryItemMapEntry.getKey(); - - inventoryItemMapEntry.getValue().entrySet().stream() - .filter(purityIntegerEntry -> purityIntegerEntry.getValue() > 0) - .forEach(purityIntegerEntry -> { - int purityNumber = purityIntegerEntry.getKey().ordinal(); - Integer amount = purityIntegerEntry.getValue(); - commandQueue.add("dbank drop " + inventoryItem.getDisplayName() + " " + amount + " " + purityNumber); - }); - }); - - commandService.sendCommands(commandQueue, 1000); - }, 2500); - - return 1; - }); - } -} From 30f7c34c5fac2ef4378eea0ffad7a5d5f199630e Mon Sep 17 00:00:00 2001 From: RettichLP Date: Thu, 21 May 2026 00:37:50 +0200 Subject: [PATCH 31/96] Remove `/notvisitedhouses` command --- .../command/NotVisitedHousesCommand.java | 48 ------------------- 1 file changed, 48 deletions(-) delete mode 100644 src/main/java/de/rettichlp/ucutils/command/NotVisitedHousesCommand.java diff --git a/src/main/java/de/rettichlp/ucutils/command/NotVisitedHousesCommand.java b/src/main/java/de/rettichlp/ucutils/command/NotVisitedHousesCommand.java deleted file mode 100644 index 20a33b3d..00000000 --- a/src/main/java/de/rettichlp/ucutils/command/NotVisitedHousesCommand.java +++ /dev/null @@ -1,48 +0,0 @@ -package de.rettichlp.ucutils.command; - -import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import de.rettichlp.ucutils.common.registry.CommandBase; -import de.rettichlp.ucutils.common.registry.UCUtilsCommand; -import de.rettichlp.ucutils.listener.impl.EventListener; -import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import static de.rettichlp.ucutils.UCUtils.configuration; -import static de.rettichlp.ucutils.UCUtils.messageService; -import static de.rettichlp.ucutils.UCUtils.player; -import static net.minecraft.text.Text.empty; -import static net.minecraft.text.Text.of; - -@UCUtilsCommand(label = "notvisitedhouses") -public class NotVisitedHousesCommand extends CommandBase { - - @Override - public LiteralArgumentBuilder execute(@NotNull LiteralArgumentBuilder node) { - return node - .executes(context -> { - List doorNumbersVisited = configuration.getHalloweenClickedDoors().stream() - .map(EventListener.HalloweenDoor::getDoorNumber) - .toList(); - - Collection doorNumbersNotVisited = new ArrayList<>(); - for (int i = 1; i <= 828; i++) { - if (!doorNumbersVisited.contains(i)) { - doorNumbersNotVisited.add(i); - } - } - - player.sendMessage(empty(), false); - - messageService.sendModMessage("Noch nicht besuchte Häuser:", false); - doorNumbersNotVisited.forEach(integer -> messageService.sendModMessage(of("Haus " + integer), false)); - - player.sendMessage(empty(), false); - - return 1; - }); - } -} From 8195caa4752c2aa1460a1e00a2436c88d1bff375 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Thu, 21 May 2026 10:21:19 +0200 Subject: [PATCH 32/96] Remove IHudRenderListener from MajorEventListener and related bomb timer logic --- .../ucutils/listener/impl/EventListener.java | 57 --------------- .../impl/faction/MajorEventListener.java | 72 ++----------------- 2 files changed, 4 insertions(+), 125 deletions(-) delete mode 100644 src/main/java/de/rettichlp/ucutils/listener/impl/EventListener.java diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/EventListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/EventListener.java deleted file mode 100644 index 986591ba..00000000 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/EventListener.java +++ /dev/null @@ -1,57 +0,0 @@ -package de.rettichlp.ucutils.listener.impl; - -import de.rettichlp.ucutils.common.registry.UCUtilsListener; -import de.rettichlp.ucutils.listener.IMessageReceiveListener; -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import net.minecraft.text.Text; - -import java.time.LocalDateTime; -import java.util.Set; -import java.util.function.Predicate; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import static de.rettichlp.ucutils.UCUtils.configuration; -import static java.lang.Integer.parseInt; -import static java.time.LocalDateTime.now; -import static java.util.regex.Pattern.compile; - -@UCUtilsListener -public class EventListener implements IMessageReceiveListener { - - private static final Pattern HALLOWEEN_DOOR_VISITED_PATTERN = compile("^\\[Halloween] Du hast bei Haus (?\\d+) geklingelt\\.$"); - - private static final Predicate HALLOWEEN_DOOR_REMOVE_PREDICATE = halloweenDoor -> { - LocalDateTime now = now(); - LocalDateTime today4am = now.withHour(4).withMinute(0).withSecond(0).withNano(0); - LocalDateTime timestamp = halloweenDoor.getTimestamp(); - return now.isAfter(today4am) - ? timestamp.isBefore(today4am) - : timestamp.isBefore(today4am.minusDays(1)); - }; - - @Override - public boolean onMessageReceive(Text text, String message) { - Matcher halloweenDoorVisitedMatcher = HALLOWEEN_DOOR_VISITED_PATTERN.matcher(message); - if (halloweenDoorVisitedMatcher.find()) { - int doorNumber = parseInt(halloweenDoorVisitedMatcher.group("number")); - HalloweenDoor halloweenDoor = new HalloweenDoor(doorNumber); - - Set halloweenClickedDoors = configuration.getHalloweenClickedDoors(); - halloweenClickedDoors.removeIf(HALLOWEEN_DOOR_REMOVE_PREDICATE); - halloweenClickedDoors.add(halloweenDoor); - return true; - } - - return true; - } - - @Getter - @RequiredArgsConstructor - public static class HalloweenDoor { - - private final LocalDateTime timestamp = now(); - private final int doorNumber; - } -} diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/faction/MajorEventListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/faction/MajorEventListener.java index 1e5a7f48..53a5968e 100644 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/faction/MajorEventListener.java +++ b/src/main/java/de/rettichlp/ucutils/listener/impl/faction/MajorEventListener.java @@ -2,15 +2,9 @@ import de.rettichlp.ucutils.common.models.Faction; import de.rettichlp.ucutils.common.registry.UCUtilsListener; -import de.rettichlp.ucutils.listener.IHudRenderListener; import de.rettichlp.ucutils.listener.IMessageReceiveListener; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.font.TextRenderer; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.render.RenderTickCounter; import net.minecraft.text.Text; -import java.time.LocalDateTime; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -19,28 +13,13 @@ import static de.rettichlp.ucutils.UCUtils.storage; import static de.rettichlp.ucutils.common.models.Sound.BANK_ROBBERY; import static de.rettichlp.ucutils.common.models.Sound.BOMB_SOUND; -import static java.lang.String.format; -import static java.time.Duration.between; -import static java.time.LocalDateTime.now; -import static java.util.Objects.isNull; -import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.regex.Pattern.compile; -import static net.minecraft.text.Text.empty; -import static net.minecraft.text.Text.literal; -import static net.minecraft.util.Formatting.BOLD; -import static net.minecraft.util.Formatting.GOLD; -import static net.minecraft.util.Formatting.GRAY; -import static net.minecraft.util.Formatting.RED; @UCUtilsListener -public class MajorEventListener implements IMessageReceiveListener, IHudRenderListener { +public class MajorEventListener implements IMessageReceiveListener { private static final Pattern BANK_ROBBERY_PATTERN = compile("^News: Es wurde ein Raub in der Staatsbank gemeldet!$"); private static final Pattern BOMB_FOUND_PATTERN = compile("^News: ACHTUNG! Es wurde eine Bombe in der Nähe von (?.+) gefunden!$"); - private static final Pattern BOMB_STOP_PATTERN = compile("^News: Die Bombe konnte (erfolgreich|nicht) entschärft werden!"); - - private LocalDateTime bombPlantedTime = null; - private String bombLocationString = ""; @Override public boolean onMessageReceive(Text text, String message) { @@ -49,58 +28,15 @@ public boolean onMessageReceive(Text text, String message) { Matcher bankRobberyMatcher = BANK_ROBBERY_PATTERN.matcher(message); if (bankRobberyMatcher.find() && configuration.getOptions().sound().bankRobbery().verify(playerFaction)) { BANK_ROBBERY.play(); - } - - Matcher bombFoundMatcher = BOMB_FOUND_PATTERN.matcher(message); - if (bombFoundMatcher.find()) { - this.bombPlantedTime = now(); - this.bombLocationString = bombFoundMatcher.group("location"); - - if (configuration.getOptions().sound().bomb().verify(playerFaction)) { - BOMB_SOUND.play(); - } - return true; } - Matcher bombStopMatcher = BOMB_STOP_PATTERN.matcher(message); - if (bombStopMatcher.find()) { - this.bombPlantedTime = null; - this.bombLocationString = ""; + Matcher bombFoundMatcher = BOMB_FOUND_PATTERN.matcher(message); + if (bombFoundMatcher.find() && configuration.getOptions().sound().bomb().verify(playerFaction)) { + BOMB_SOUND.play(); return true; } return true; } - - @Override - public void onHudRender(DrawContext drawContext, RenderTickCounter renderTickCounter) { - if (isNull(this.bombPlantedTime)) { - return; - } - - long elapsedTimeInMillis = between(this.bombPlantedTime, now()).toMillis(); - long minutes = MILLISECONDS.toMinutes(elapsedTimeInMillis); - long seconds = MILLISECONDS.toSeconds(elapsedTimeInMillis) % 60; - - if (minutes >= 20) { - this.bombPlantedTime = null; - } - - Text timerText = empty() - .append(literal("Bombe").formatted(RED)) - .append(literal(":").formatted(GRAY)).append(" ") - .append(literal(this.bombLocationString).formatted(GOLD)).append(" ") - .append(literal("|").formatted(GRAY)).append(" ") - .append(literal(format("%02d:%02d", minutes, seconds)).formatted(RED, BOLD)); - - MinecraftClient client = MinecraftClient.getInstance(); - TextRenderer textRenderer = client.textRenderer; - - int textWidth = textRenderer.getWidth(timerText); - int x = (client.getWindow().getScaledWidth() - textWidth) / 2; - int y = 15; - - drawContext.drawTextWithShadow(textRenderer, timerText, x, y, 0xFFFFFFFF); - } } From 901e77b9fcc8e6fc0b74278769daddcba9f71644 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Thu, 21 May 2026 10:23:55 +0200 Subject: [PATCH 33/96] Remove halloweenClickedDoors field and related unused imports --- .../rettichlp/ucutils/common/configuration/Configuration.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/de/rettichlp/ucutils/common/configuration/Configuration.java b/src/main/java/de/rettichlp/ucutils/common/configuration/Configuration.java index dc1e6e60..b2286888 100644 --- a/src/main/java/de/rettichlp/ucutils/common/configuration/Configuration.java +++ b/src/main/java/de/rettichlp/ucutils/common/configuration/Configuration.java @@ -1,7 +1,6 @@ package de.rettichlp.ucutils.common.configuration; import de.rettichlp.ucutils.common.configuration.options.Options; -import de.rettichlp.ucutils.listener.impl.EventListener; import lombok.Data; import net.fabricmc.loader.api.FabricLoader; @@ -11,9 +10,7 @@ import java.io.Writer; import java.nio.file.Path; import java.util.HashMap; -import java.util.HashSet; import java.util.Map; -import java.util.Set; import static de.rettichlp.ucutils.UCUtils.LOGGER; import static de.rettichlp.ucutils.UCUtils.api; @@ -35,7 +32,6 @@ public class Configuration { private int minutesSinceLastPayDay = 0; private int predictedPayDaySalary = 0; private int predictedPayDayExp = 0; - private Set halloweenClickedDoors = new HashSet<>(); public void addMinutesSinceLastPayDay(int minutes) { this.minutesSinceLastPayDay += minutes; From 74d4fbdfb247531c633c1c08d31658ac48a226cd Mon Sep 17 00:00:00 2001 From: RettichLP Date: Thu, 21 May 2026 11:11:53 +0200 Subject: [PATCH 34/96] Remove MajorEventListener and ContractListener and merge sound handling logic into SoundTriggerListener --- ...istener.java => SoundTriggerListener.java} | 28 +++++++++++- .../impl/faction/ContractListener.java | 43 ------------------- .../listener/impl/faction/MedicListener.java | 12 ------ 3 files changed, 26 insertions(+), 57 deletions(-) rename src/main/java/de/rettichlp/ucutils/listener/impl/{faction/MajorEventListener.java => SoundTriggerListener.java} (50%) delete mode 100644 src/main/java/de/rettichlp/ucutils/listener/impl/faction/ContractListener.java diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/faction/MajorEventListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/SoundTriggerListener.java similarity index 50% rename from src/main/java/de/rettichlp/ucutils/listener/impl/faction/MajorEventListener.java rename to src/main/java/de/rettichlp/ucutils/listener/impl/SoundTriggerListener.java index 53a5968e..d435e368 100644 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/faction/MajorEventListener.java +++ b/src/main/java/de/rettichlp/ucutils/listener/impl/SoundTriggerListener.java @@ -1,4 +1,4 @@ -package de.rettichlp.ucutils.listener.impl.faction; +package de.rettichlp.ucutils.listener.impl; import de.rettichlp.ucutils.common.models.Faction; import de.rettichlp.ucutils.common.registry.UCUtilsListener; @@ -13,13 +13,19 @@ import static de.rettichlp.ucutils.UCUtils.storage; import static de.rettichlp.ucutils.common.models.Sound.BANK_ROBBERY; import static de.rettichlp.ucutils.common.models.Sound.BOMB_SOUND; +import static de.rettichlp.ucutils.common.models.Sound.CONTRACT_FULFILLED; +import static de.rettichlp.ucutils.common.models.Sound.CONTRACT_SET; +import static de.rettichlp.ucutils.common.models.Sound.FIRE; import static java.util.regex.Pattern.compile; @UCUtilsListener -public class MajorEventListener implements IMessageReceiveListener { +public class SoundTriggerListener implements IMessageReceiveListener { private static final Pattern BANK_ROBBERY_PATTERN = compile("^News: Es wurde ein Raub in der Staatsbank gemeldet!$"); private static final Pattern BOMB_FOUND_PATTERN = compile("^News: ACHTUNG! Es wurde eine Bombe in der Nähe von (?.+) gefunden!$"); + private static final Pattern CONTRACT_ADD_PATTERN = compile("^\\[Contract] Es wurde ein Kopfgeld auf (?:\\[UC])?(?[a-zA-Z0-9_]+) \\((?\\d+)\\$\\) ausgesetzt\\.$"); + private static final Pattern CONTRACT_KILL_PATTERN = compile("^\\[Contract] (?:\\[UC])?(?[a-zA-Z0-9_]+) hat (?:\\[UC])?(?[a-zA-Z0-9_]+) getötet\\. Kopfgeld: (?\\d+)\\$$"); + private static final Pattern FIRE_START_PATTERN = compile("^News: Es wurde ein Feuer bei .+ gemeldet!$"); @Override public boolean onMessageReceive(Text text, String message) { @@ -37,6 +43,24 @@ public boolean onMessageReceive(Text text, String message) { return true; } + Matcher contractAddMatcher = CONTRACT_ADD_PATTERN.matcher(message); + if (contractAddMatcher.find() && configuration.getOptions().sound().contractSet()) { + CONTRACT_SET.play(); + return true; + } + + Matcher contractKillMatcher = CONTRACT_KILL_PATTERN.matcher(message); + if (contractKillMatcher.find() && configuration.getOptions().sound().contractFulfilled()) { + CONTRACT_FULFILLED.play(); + return true; + } + + Matcher fireStartMatcher = FIRE_START_PATTERN.matcher(message); + if (fireStartMatcher.find() && configuration.getOptions().sound().fire().verify(playerFaction)) { + FIRE.play(); + return true; + } + return true; } } diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/faction/ContractListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/faction/ContractListener.java deleted file mode 100644 index cd778a7c..00000000 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/faction/ContractListener.java +++ /dev/null @@ -1,43 +0,0 @@ -package de.rettichlp.ucutils.listener.impl.faction; - -import de.rettichlp.ucutils.common.registry.UCUtilsListener; -import de.rettichlp.ucutils.listener.IMessageReceiveListener; -import net.minecraft.text.Text; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import static de.rettichlp.ucutils.UCUtils.configuration; -import static de.rettichlp.ucutils.common.models.Sound.CONTRACT_FULFILLED; -import static de.rettichlp.ucutils.common.models.Sound.CONTRACT_SET; -import static java.util.regex.Pattern.compile; - -@UCUtilsListener -public class ContractListener implements IMessageReceiveListener { - - private static final Pattern CONTRACT_ADD_PATTERN = compile("^\\[Contract] Es wurde ein Kopfgeld auf (?:\\[UC])?(?[a-zA-Z0-9_]+) \\((?\\d+)\\$\\) ausgesetzt\\.$"); - private static final Pattern CONTRACT_KILL_PATTERN = compile("^\\[Contract] (?:\\[UC])?(?[a-zA-Z0-9_]+) hat (?:\\[UC])?(?[a-zA-Z0-9_]+) getötet\\. Kopfgeld: (?\\d+)\\$$"); - - @Override - public boolean onMessageReceive(Text text, String message) { - Matcher contractAddMatcher = CONTRACT_ADD_PATTERN.matcher(message); - if (contractAddMatcher.find()) { - if (configuration.getOptions().sound().contractSet()) { - CONTRACT_SET.play(); - } - - return true; - } - - Matcher contractKillMatcher = CONTRACT_KILL_PATTERN.matcher(message); - if (contractKillMatcher.find()) { - if (configuration.getOptions().sound().contractFulfilled()) { - CONTRACT_FULFILLED.play(); - } - - return true; - } - - return true; - } -} diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/faction/MedicListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/faction/MedicListener.java index 6ed5cf36..716d3338 100644 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/faction/MedicListener.java +++ b/src/main/java/de/rettichlp/ucutils/listener/impl/faction/MedicListener.java @@ -1,7 +1,6 @@ package de.rettichlp.ucutils.listener.impl.faction; import de.rettichlp.ucutils.common.models.Countdown; -import de.rettichlp.ucutils.common.models.Faction; import de.rettichlp.ucutils.common.registry.UCUtilsListener; import de.rettichlp.ucutils.listener.IMessageReceiveListener; import net.minecraft.text.Text; @@ -11,11 +10,8 @@ import java.util.regex.Pattern; import static de.rettichlp.ucutils.UCUtils.commandService; -import static de.rettichlp.ucutils.UCUtils.configuration; -import static de.rettichlp.ucutils.UCUtils.player; import static de.rettichlp.ucutils.UCUtils.storage; import static de.rettichlp.ucutils.UCUtils.utilService; -import static de.rettichlp.ucutils.common.models.Sound.FIRE; import static de.rettichlp.ucutils.common.services.CommandService.COMMAND_COOLDOWN_MILLIS; import static java.time.Duration.ofMinutes; import static java.time.LocalDateTime.now; @@ -33,7 +29,6 @@ public class MedicListener implements IMessageReceiveListener { private static final Pattern MEDIC_PILL_GIVE_PATTERN = compile("^\\[Medic] Du hast (?:\\[UC])?(?[a-zA-Z0-9_]+) Schmerzpillen verabreicht\\.$"); private static final Pattern MEDIC_REVIVE_START_PATTERN = compile("^Du beginnst mit der Wiederbelebung von (?:\\[UC])?(?[a-zA-Z0-9_]+)\\.\\.\\.$"); private static final Pattern LABOR_TRANSPORT_STARTED_PATTERN = compile("^\\[ʟᴀʙᴏʀ] Transport gestartet: (?\\d+) ᴋɪsᴛᴇɴ mit (?\\d+) (?.+)$"); - private static final Pattern FIRE_START_PATTERN = compile("^News: Es wurde ein Feuer bei .+ gemeldet!$"); @Override public boolean onMessageReceive(Text text, String message) { @@ -76,13 +71,6 @@ public boolean onMessageReceive(Text text, String message) { return true; } - Faction playerFaction = storage.getFaction(player.getGameProfile().name()); - Matcher fireStartMatcher = FIRE_START_PATTERN.matcher(message); - if (fireStartMatcher.find() && configuration.getOptions().sound().fire().verify(playerFaction)) { - FIRE.play(); - return true; - } - return true; } } From bb8716cfc0f8407a5b3f036962c90b997c894f8d Mon Sep 17 00:00:00 2001 From: RettichLP Date: Thu, 21 May 2026 14:47:00 +0200 Subject: [PATCH 35/96] Add zero checks before rendering and adding buttonWidget --- .../de/rettichlp/ucutils/mixin/HandledScreenMixin.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/rettichlp/ucutils/mixin/HandledScreenMixin.java b/src/main/java/de/rettichlp/ucutils/mixin/HandledScreenMixin.java index 11dd15d8..8a9c9002 100644 --- a/src/main/java/de/rettichlp/ucutils/mixin/HandledScreenMixin.java +++ b/src/main/java/de/rettichlp/ucutils/mixin/HandledScreenMixin.java @@ -62,9 +62,10 @@ protected HandledScreenMixin(Text title) { .dimensions(buttonX, y, 20, 20) .build(); - buttonWidget.render(context, mouseX, mouseY, deltaTicks); - - addDrawableChild(buttonWidget); + if (ingredient1StoredAmount != 0 && ingredient2StoredAmount != 0 && ingredient3StoredAmount != 0) { + buttonWidget.render(context, mouseX, mouseY, deltaTicks); + addDrawableChild(buttonWidget); + } } } } From 94648ebde3df7b44cc49c58ce289f4530f7e9854 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Thu, 21 May 2026 14:47:43 +0200 Subject: [PATCH 36/96] Adjust buttonX positioning in HandledScreenMixin --- .../java/de/rettichlp/ucutils/mixin/HandledScreenMixin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/rettichlp/ucutils/mixin/HandledScreenMixin.java b/src/main/java/de/rettichlp/ucutils/mixin/HandledScreenMixin.java index 8a9c9002..b557e18e 100644 --- a/src/main/java/de/rettichlp/ucutils/mixin/HandledScreenMixin.java +++ b/src/main/java/de/rettichlp/ucutils/mixin/HandledScreenMixin.java @@ -55,7 +55,7 @@ protected HandledScreenMixin(Text title) { int x = (this.width - this.backgroundWidth) / 2; int y = (this.height - this.backgroundHeight) / 2; - int buttonX = x + this.backgroundWidth + 4; + int buttonX = x + this.backgroundWidth + 2; // render button right to the inventory ButtonWidget buttonWidget = new ButtonWidget.Builder(literal("➤"), button -> commandService.sendCommand("f Lager: " + ingredient1StoredAmount + "x Wirkstoff " + ingredient2StoredAmount + "x Trägerstoff " + ingredient3StoredAmount + "x Zusatzstoff")) From 96768b44458b1d484da68fa2143d95f796d4db78 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Thu, 21 May 2026 16:37:02 +0200 Subject: [PATCH 37/96] Refactor MedicListener to handle storage ingredient share and accept patterns; update message formatting and button command in HandledScreenMixin --- .../listener/impl/faction/MedicListener.java | 109 ++++++++++++++++++ .../ucutils/mixin/HandledScreenMixin.java | 2 +- 2 files changed, 110 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/faction/MedicListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/faction/MedicListener.java index 716d3338..9daa4772 100644 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/faction/MedicListener.java +++ b/src/main/java/de/rettichlp/ucutils/listener/impl/faction/MedicListener.java @@ -3,19 +3,39 @@ import de.rettichlp.ucutils.common.models.Countdown; import de.rettichlp.ucutils.common.registry.UCUtilsListener; import de.rettichlp.ucutils.listener.IMessageReceiveListener; +import net.minecraft.text.ClickEvent; +import net.minecraft.text.HoverEvent; +import net.minecraft.text.MutableText; import net.minecraft.text.Text; +import net.minecraft.util.Formatting; +import java.awt.Color; import java.time.Duration; 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 de.rettichlp.ucutils.UCUtils.storage; import static de.rettichlp.ucutils.UCUtils.utilService; import static de.rettichlp.ucutils.common.services.CommandService.COMMAND_COOLDOWN_MILLIS; +import static java.lang.Integer.parseInt; +import static java.lang.String.valueOf; import static java.time.Duration.ofMinutes; import static java.time.LocalDateTime.now; import static java.util.regex.Pattern.compile; +import static net.minecraft.screen.ScreenTexts.LINE_BREAK; +import static net.minecraft.text.Text.empty; +import static net.minecraft.text.Text.literal; +import static net.minecraft.util.Formatting.BOLD; +import static net.minecraft.util.Formatting.DARK_AQUA; +import static net.minecraft.util.Formatting.DARK_GRAY; +import static net.minecraft.util.Formatting.DARK_GREEN; +import static net.minecraft.util.Formatting.GOLD; +import static net.minecraft.util.Formatting.GRAY; +import static net.minecraft.util.Formatting.GREEN; +import static net.minecraft.util.Formatting.RED; +import static net.minecraft.util.Formatting.YELLOW; @UCUtilsListener public class MedicListener implements IMessageReceiveListener { @@ -29,6 +49,15 @@ public class MedicListener implements IMessageReceiveListener { private static final Pattern MEDIC_PILL_GIVE_PATTERN = compile("^\\[Medic] Du hast (?:\\[UC])?(?[a-zA-Z0-9_]+) Schmerzpillen verabreicht\\.$"); private static final Pattern MEDIC_REVIVE_START_PATTERN = compile("^Du beginnst mit der Wiederbelebung von (?:\\[UC])?(?[a-zA-Z0-9_]+)\\.\\.\\.$"); private static final Pattern LABOR_TRANSPORT_STARTED_PATTERN = compile("^\\[ʟᴀʙᴏʀ] Transport gestartet: (?\\d+) ᴋɪsᴛᴇɴ mit (?\\d+) (?.+)$"); + private static final Pattern STORAGE_INGREDIENT_SHARE_PATTERN = compile("^.+ (?:\\[UC])?(?[a-zA-Z0-9_]+): (?\\d+)x Wirkstoff \\| (?\\d+)x Trägerstoff \\| (?\\d+)x Zusatzstoff$"); + private static final Pattern STORAGE_INGREDIENT_ACCEPT_PATTERN = compile("^.+ (?:\\[UC])?(?[a-zA-Z0-9_]+): Ich nehme (?Wirkstoff|Trägerstoff|Zusatzstoff)! \\(geschätzt: (?\\d+) → (?\\d+)\\)$"); + + private static final MutableText STORAGE_TEXT = empty() + .append(literal("ʟ").withColor(Color.decode("#AA0000").getRGB())) + .append(literal("ᴀ").withColor(Color.decode("#BF1515").getRGB())) + .append(literal("ʙ").withColor(Color.decode("#D52B2B").getRGB())) + .append(literal("ᴏ").withColor(Color.decode("#EA4040").getRGB())) + .append(literal("ʀ").withColor(Color.decode("#FF5555").getRGB())); @Override public boolean onMessageReceive(Text text, String message) { @@ -71,6 +100,86 @@ public boolean onMessageReceive(Text text, String message) { return true; } + Matcher storageIngredientShareMatcher = STORAGE_INGREDIENT_SHARE_PATTERN.matcher(message); + if (storageIngredientShareMatcher.find()) { + String playerName = storageIngredientShareMatcher.group("playerName"); + int ingredient1 = parseInt(storageIngredientShareMatcher.group("ingredient1")); + int ingredient2 = parseInt(storageIngredientShareMatcher.group("ingredient2")); + int ingredient3 = parseInt(storageIngredientShareMatcher.group("ingredient3")); + + MutableText storageText = empty() + .append(LINE_BREAK) + .append(literal("[").formatted(DARK_GRAY)) + .append(STORAGE_TEXT) + .append(literal("] ").formatted(DARK_GRAY)) + .append(literal("Aktueller Bestand (geteilt von " + playerName + ")").formatted(GRAY)) + .append(literal(":").formatted(DARK_GRAY)) + .append(LINE_BREAK) + .append(getIngredientText("Wirkstoff", ingredient1)) + .append(LINE_BREAK) + .append(getIngredientText("Trägerstoff", ingredient2)) + .append(LINE_BREAK) + .append(getIngredientText("Zusatzstoff", ingredient3)) + .append(LINE_BREAK); + + player.sendMessage(storageText, false); + return false; + } + + Matcher storageIngredientAcceptMatcher = STORAGE_INGREDIENT_ACCEPT_PATTERN.matcher(message); + if (storageIngredientAcceptMatcher.find()) { + String playerName = storageIngredientAcceptMatcher.group("playerName"); + String ingredient = storageIngredientAcceptMatcher.group("ingredient"); + int amountBefore = parseInt(storageIngredientAcceptMatcher.group("amountBefore")); + int amountAfter = parseInt(storageIngredientAcceptMatcher.group("amountAfter")); + + MutableText storageText = empty() + .append(literal("[").formatted(DARK_GRAY)) + .append(STORAGE_TEXT) + .append(literal("] ").formatted(DARK_GRAY)) + .append(literal(playerName).formatted(RED)) + .append(literal(" übernimmt ").formatted(GRAY)) + .append(literal(ingredient).formatted(RED)) + .append(literal(":").formatted(DARK_GRAY)) + .append(LINE_BREAK) + .append(literal(" > ").formatted(DARK_GRAY)) + .append(literal("Erwartete Menge nach Transport").formatted(GRAY)) + .append(literal(": ").formatted(DARK_GRAY)) + .append(literal(amountBefore + " → ").formatted(GRAY)) + .append(literal(valueOf(amountAfter)).formatted(getColor(amountAfter), BOLD)); + + player.sendMessage(storageText, false); + return false; + } + return true; } + + private MutableText getIngredientText(String ingredient, int amount) { + return empty() + .append(literal(" > ").formatted(DARK_GRAY)) + .append(literal("[").formatted(DARK_GRAY)) + .append(literal("Ich übernehme!").styled(style -> style + .withFormatting(DARK_AQUA) + .withHoverEvent(new HoverEvent.ShowText(literal("Klicke um bescheid zu sagen, dass Du den Transport übernimmst"))) + .withClickEvent(new ClickEvent.RunCommand("/f Ich nehme " + ingredient + "! (geschätzt: " + amount + " → " + (amount + 20) + ")")))) + .append(literal("] ").formatted(DARK_GRAY)) + .append(literal(ingredient).formatted(GRAY)) + .append(literal(": ").formatted(DARK_GRAY)) + .append(literal(valueOf(amount)).formatted(getColor(amount), BOLD)); + } + + private Formatting getColor(int amount) { + if (amount >= 80) { + return DARK_GREEN; + } else if (amount >= 60) { + return GREEN; + } else if (amount >= 40) { + return YELLOW; + } else if (amount >= 20) { + return GOLD; + } else { + return RED; + } + } } diff --git a/src/main/java/de/rettichlp/ucutils/mixin/HandledScreenMixin.java b/src/main/java/de/rettichlp/ucutils/mixin/HandledScreenMixin.java index b557e18e..60ca2292 100644 --- a/src/main/java/de/rettichlp/ucutils/mixin/HandledScreenMixin.java +++ b/src/main/java/de/rettichlp/ucutils/mixin/HandledScreenMixin.java @@ -58,7 +58,7 @@ protected HandledScreenMixin(Text title) { int buttonX = x + this.backgroundWidth + 2; // render button right to the inventory - ButtonWidget buttonWidget = new ButtonWidget.Builder(literal("➤"), button -> commandService.sendCommand("f Lager: " + ingredient1StoredAmount + "x Wirkstoff " + ingredient2StoredAmount + "x Trägerstoff " + ingredient3StoredAmount + "x Zusatzstoff")) + ButtonWidget buttonWidget = new ButtonWidget.Builder(literal("➤"), button -> commandService.sendCommand("f " + ingredient1StoredAmount + "x Wirkstoff | " + ingredient2StoredAmount + "x Trägerstoff | " + ingredient3StoredAmount + "x Zusatzstoff")) .dimensions(buttonX, y, 20, 20) .build(); From 9f85a1395c2b5ead7d8e25ab847f5d4727187d04 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Thu, 21 May 2026 17:32:54 +0200 Subject: [PATCH 38/96] Refactor EconomyListener to simplify ATM command setup logic --- .../ucutils/listener/impl/EconomyListener.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/EconomyListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/EconomyListener.java index 1d984295..0f0ee2b4 100644 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/EconomyListener.java +++ b/src/main/java/de/rettichlp/ucutils/listener/impl/EconomyListener.java @@ -76,12 +76,15 @@ public boolean onMessageReceive(Text text, String message) { int amount = parseInt(bankStatementMatcher.group("amount")); configuration.setMoneyBankAmount(amount); - List commands = switch (configuration.getOptions().atmInformationType()) { - case NONE -> emptyList(); - case F_BANK -> List.of("fbank"); - case G_BANK -> List.of("gruppierungkasse"); - case BOTH -> List.of("fbank", "gruppierungkasse"); - }; + List commands = new ArrayList<>(); + commands.add("atminfo"); + + switch (configuration.getOptions().atmInformationType()) { + case NONE -> {} + case F_BANK -> commands.add("fbank"); + case G_BANK -> commands.add("gruppierungkasse"); + case BOTH -> commands.addAll(List.of("fbank", "gruppierungkasse")); + } commandService.sendCommands(commands); From 3de65ddacf58b655a9d855ba4c3f801c3cf4bf9a Mon Sep 17 00:00:00 2001 From: RettichLP Date: Thu, 21 May 2026 17:34:04 +0200 Subject: [PATCH 39/96] Clean up imports in EconomyListener --- .../de/rettichlp/ucutils/listener/impl/EconomyListener.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/EconomyListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/EconomyListener.java index 0f0ee2b4..b8707dea 100644 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/EconomyListener.java +++ b/src/main/java/de/rettichlp/ucutils/listener/impl/EconomyListener.java @@ -7,6 +7,7 @@ import net.minecraft.text.MutableText; import net.minecraft.text.Text; +import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -20,7 +21,6 @@ import static java.lang.Integer.parseInt; import static java.lang.Math.max; import static java.lang.System.currentTimeMillis; -import static java.util.Collections.emptyList; import static java.util.Optional.ofNullable; import static java.util.regex.Pattern.compile; import static net.minecraft.text.Text.of; @@ -80,7 +80,8 @@ public boolean onMessageReceive(Text text, String message) { commands.add("atminfo"); switch (configuration.getOptions().atmInformationType()) { - case NONE -> {} + case NONE -> { + } case F_BANK -> commands.add("fbank"); case G_BANK -> commands.add("gruppierungkasse"); case BOTH -> commands.addAll(List.of("fbank", "gruppierungkasse")); From fb2e30b4274660bb8c109e8aa4960444862b1e45 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Thu, 21 May 2026 18:02:29 +0200 Subject: [PATCH 40/96] Simplify MedicListener message formatting and adjust logic for displaying ingredient details --- .../listener/impl/faction/MedicListener.java | 32 +++++++++---------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/faction/MedicListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/faction/MedicListener.java index 9daa4772..3e839209 100644 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/faction/MedicListener.java +++ b/src/main/java/de/rettichlp/ucutils/listener/impl/faction/MedicListener.java @@ -24,7 +24,6 @@ import static java.time.Duration.ofMinutes; import static java.time.LocalDateTime.now; import static java.util.regex.Pattern.compile; -import static net.minecraft.screen.ScreenTexts.LINE_BREAK; import static net.minecraft.text.Text.empty; import static net.minecraft.text.Text.literal; import static net.minecraft.util.Formatting.BOLD; @@ -107,22 +106,22 @@ public boolean onMessageReceive(Text text, String message) { int ingredient2 = parseInt(storageIngredientShareMatcher.group("ingredient2")); int ingredient3 = parseInt(storageIngredientShareMatcher.group("ingredient3")); + player.sendMessage(empty(), false); + MutableText storageText = empty() - .append(LINE_BREAK) .append(literal("[").formatted(DARK_GRAY)) .append(STORAGE_TEXT) .append(literal("] ").formatted(DARK_GRAY)) .append(literal("Aktueller Bestand (geteilt von " + playerName + ")").formatted(GRAY)) - .append(literal(":").formatted(DARK_GRAY)) - .append(LINE_BREAK) - .append(getIngredientText("Wirkstoff", ingredient1)) - .append(LINE_BREAK) - .append(getIngredientText("Trägerstoff", ingredient2)) - .append(LINE_BREAK) - .append(getIngredientText("Zusatzstoff", ingredient3)) - .append(LINE_BREAK); + .append(literal(":").formatted(DARK_GRAY)); player.sendMessage(storageText, false); + + player.sendMessage(getIngredientText("Wirkstoff", ingredient1), false); + player.sendMessage(getIngredientText("Trägerstoff", ingredient2), false); + player.sendMessage(getIngredientText("Zusatzstoff", ingredient3), false); + + player.sendMessage(empty(), false); return false; } @@ -133,22 +132,21 @@ public boolean onMessageReceive(Text text, String message) { int amountBefore = parseInt(storageIngredientAcceptMatcher.group("amountBefore")); int amountAfter = parseInt(storageIngredientAcceptMatcher.group("amountAfter")); - MutableText storageText = empty() + player.sendMessage(empty() .append(literal("[").formatted(DARK_GRAY)) .append(STORAGE_TEXT) .append(literal("] ").formatted(DARK_GRAY)) .append(literal(playerName).formatted(RED)) .append(literal(" übernimmt ").formatted(GRAY)) .append(literal(ingredient).formatted(RED)) - .append(literal(":").formatted(DARK_GRAY)) - .append(LINE_BREAK) + .append(literal(":").formatted(DARK_GRAY)), false); + + player.sendMessage(empty() .append(literal(" > ").formatted(DARK_GRAY)) - .append(literal("Erwartete Menge nach Transport").formatted(GRAY)) + .append(literal("Geschätzte Menge nach Transport").formatted(GRAY)) .append(literal(": ").formatted(DARK_GRAY)) .append(literal(amountBefore + " → ").formatted(GRAY)) - .append(literal(valueOf(amountAfter)).formatted(getColor(amountAfter), BOLD)); - - player.sendMessage(storageText, false); + .append(literal(valueOf(amountAfter)).formatted(getColor(amountAfter), BOLD)), false); return false; } From 8e023a5c3012ad3bbe99957a796bca1108f819cf Mon Sep 17 00:00:00 2001 From: RettichLP Date: Thu, 21 May 2026 10:32:17 +0200 Subject: [PATCH 41/96] Remove `/selldrugall` (`/sda`) command and associated classes and logic --- .../command/faction/SellDrugAllCommand.java | 71 ------- .../de/rettichlp/ucutils/common/Storage.java | 7 - .../ucutils/common/models/InventoryItem.java | 46 ----- .../ucutils/common/models/Purity.java | 30 --- .../listener/impl/InventoryListener.java | 173 ------------------ 5 files changed, 327 deletions(-) delete mode 100644 src/main/java/de/rettichlp/ucutils/command/faction/SellDrugAllCommand.java delete mode 100644 src/main/java/de/rettichlp/ucutils/common/models/InventoryItem.java delete mode 100644 src/main/java/de/rettichlp/ucutils/common/models/Purity.java delete mode 100644 src/main/java/de/rettichlp/ucutils/listener/impl/InventoryListener.java diff --git a/src/main/java/de/rettichlp/ucutils/command/faction/SellDrugAllCommand.java b/src/main/java/de/rettichlp/ucutils/command/faction/SellDrugAllCommand.java deleted file mode 100644 index a58603a9..00000000 --- a/src/main/java/de/rettichlp/ucutils/command/faction/SellDrugAllCommand.java +++ /dev/null @@ -1,71 +0,0 @@ -package de.rettichlp.ucutils.command.faction; - -import com.mojang.authlib.GameProfile; -import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import de.rettichlp.ucutils.common.models.InventoryItem; -import de.rettichlp.ucutils.common.registry.CommandBase; -import de.rettichlp.ucutils.common.registry.UCUtilsCommand; -import de.rettichlp.ucutils.listener.impl.InventoryListener; -import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; -import net.minecraft.client.network.PlayerListEntry; -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.List; - -import static com.mojang.brigadier.arguments.StringArgumentType.getString; -import static com.mojang.brigadier.arguments.StringArgumentType.word; -import static de.rettichlp.ucutils.UCUtils.commandService; -import static de.rettichlp.ucutils.UCUtils.networkHandler; -import static de.rettichlp.ucutils.UCUtils.storage; -import static de.rettichlp.ucutils.UCUtils.utilService; -import static de.rettichlp.ucutils.common.models.InventoryItem.POWDER; -import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.argument; -import static net.minecraft.command.CommandSource.suggestMatching; - -@UCUtilsCommand(label = "selldrugall", aliases = "sda") -public class SellDrugAllCommand extends CommandBase { - - @Override - public LiteralArgumentBuilder execute(@NotNull LiteralArgumentBuilder node) { - return node - .then(argument("player", word()) - .suggests((context, builder) -> { - List list = networkHandler.getPlayerList().stream() - .map(PlayerListEntry::getProfile) - .map(GameProfile::name) - .toList(); - return suggestMatching(list, builder); - }) - .executes(context -> { - // sync inventory - InventoryListener.inventorySyncStep = POWDER; - commandService.sendCommand("inv"); - - String targetName = getString(context, "player"); - - utilService.delayedAction(() -> { - // handle - List commandQueue = new ArrayList<>(); - - storage.getInventory().entrySet().stream() - .filter(inventoryItemMapEntry -> inventoryItemMapEntry.getKey().isDrugBankItem()) - .forEach(inventoryItemMapEntry -> { - InventoryItem inventoryItem = inventoryItemMapEntry.getKey(); - - inventoryItemMapEntry.getValue().entrySet().stream() - .filter(purityIntegerEntry -> purityIntegerEntry.getValue() > 0) - .forEach(purityIntegerEntry -> { - int purityNumber = purityIntegerEntry.getKey().ordinal(); - Integer amount = purityIntegerEntry.getValue(); - commandQueue.add("selldrug " + targetName + " " + inventoryItem.getDisplayName() + " " + purityNumber + " " + amount + " " + 0); - }); - }); - - commandService.sendCommandsWithAwaitingResponse(commandQueue); - }, 2500); - - return 1; - })); - } -} diff --git a/src/main/java/de/rettichlp/ucutils/common/Storage.java b/src/main/java/de/rettichlp/ucutils/common/Storage.java index f96efd57..40ba14a8 100644 --- a/src/main/java/de/rettichlp/ucutils/common/Storage.java +++ b/src/main/java/de/rettichlp/ucutils/common/Storage.java @@ -6,9 +6,7 @@ import de.rettichlp.ucutils.common.models.Faction; import de.rettichlp.ucutils.common.models.FactionEntry; import de.rettichlp.ucutils.common.models.FactionMember; -import de.rettichlp.ucutils.common.models.InventoryItem; import de.rettichlp.ucutils.common.models.Job; -import de.rettichlp.ucutils.common.models.Purity; import de.rettichlp.ucutils.common.models.ShutdownReason; import de.rettichlp.ucutils.common.models.TeamResponse; import de.rettichlp.ucutils.common.models.WantedEntry; @@ -53,9 +51,6 @@ public class Storage { @Getter private final Set factionEntries = new HashSet<>(); - @Getter - private final Map> inventory = new HashMap<>(); - @Getter private final Map medicBandageCooldowns = new HashMap<>(); @@ -142,8 +137,6 @@ public void print() { LOGGER.info("dealers[{}]: {}", this.dealers.size(), this.dealers); // factionEntries this.factionEntries.forEach(factionEntry -> LOGGER.info("factionEntries[{}:{}]: {}", factionEntry.faction(), factionEntry.members().size(), factionEntry.members())); - // inventory - this.inventory.forEach((inventoryItem, inventoryItemMap) -> LOGGER.info("inventory[{}:{}]: {}", inventoryItem, inventoryItemMap.size(), inventoryItemMap)); // medicBandageCooldowns LOGGER.info("medicBandageCooldowns[{}]: {}", this.medicBandageCooldowns.size(), this.medicBandageCooldowns); // medicPillCooldowns diff --git a/src/main/java/de/rettichlp/ucutils/common/models/InventoryItem.java b/src/main/java/de/rettichlp/ucutils/common/models/InventoryItem.java deleted file mode 100644 index b08ca9b8..00000000 --- a/src/main/java/de/rettichlp/ucutils/common/models/InventoryItem.java +++ /dev/null @@ -1,46 +0,0 @@ -package de.rettichlp.ucutils.common.models; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NonNull; - -import java.util.Optional; - -import static java.util.Arrays.stream; - -@Getter -@AllArgsConstructor -public enum InventoryItem { - - // drugs - POWDER("Pulver", true), - MEDICINAL_HERBS("Medizinische Kräuter"), - HERBS("Kräuter", true), - CRYSTALS("Kristalle", true), - GRAB_BAG("Wundertüte", true), - - // medical - COUGH_SYRUP("Hustensaft"), - PAINKILLERS("Schmerzmittel"), - ANTIBIOTICS("Antibiotika"), - - // other - MASK("Maske"), - IRON("Eisen"), - GUN_POWDER("Schwarzpulver"), - KEVLAR_FIBERS("Kevlarfasern"); - - private final String displayName; - private final boolean drugBankItem; - - InventoryItem(String displayName) { - this.displayName = displayName; - this.drugBankItem = false; - } - - public static @NonNull Optional fromDisplayName(String displayName) { - return stream(values()) - .filter(inventoryItem -> inventoryItem.getDisplayName().equals(displayName)) - .findFirst(); - } -} diff --git a/src/main/java/de/rettichlp/ucutils/common/models/Purity.java b/src/main/java/de/rettichlp/ucutils/common/models/Purity.java deleted file mode 100644 index c9f611b1..00000000 --- a/src/main/java/de/rettichlp/ucutils/common/models/Purity.java +++ /dev/null @@ -1,30 +0,0 @@ -package de.rettichlp.ucutils.common.models; - -import de.rettichlp.ucutils.common.gui.screens.components.CyclingButtonEntry; -import lombok.AllArgsConstructor; -import lombok.Getter; -import net.minecraft.client.gui.tooltip.Tooltip; -import net.minecraft.text.Text; - -import static net.minecraft.text.Text.translatable; -import static net.minecraft.util.Formatting.DARK_GREEN; -import static net.minecraft.util.Formatting.GREEN; -import static net.minecraft.util.Formatting.RED; -import static net.minecraft.util.Formatting.YELLOW; - -@Getter -@AllArgsConstructor -public enum Purity implements CyclingButtonEntry { - - BEST(translatable("ucutils.purity.best").formatted(DARK_GREEN)), - GOOD(translatable("ucutils.purity.good").formatted(GREEN)), - MEDIUM(translatable("ucutils.purity.medium").formatted(YELLOW)), - BAD(translatable("ucutils.purity.bad").formatted(RED)); - - private final Text displayName; - - @Override - public Tooltip getTooltip() { - return Tooltip.of(this.displayName); - } -} diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/InventoryListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/InventoryListener.java deleted file mode 100644 index 13eba124..00000000 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/InventoryListener.java +++ /dev/null @@ -1,173 +0,0 @@ -package de.rettichlp.ucutils.listener.impl; - -import de.rettichlp.ucutils.common.models.InventoryItem; -import de.rettichlp.ucutils.common.models.Purity; -import de.rettichlp.ucutils.common.registry.UCUtilsListener; -import de.rettichlp.ucutils.listener.IScreenOpenListener; -import lombok.NonNull; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.screen.ingame.HandledScreen; -import net.minecraft.client.network.ClientPlayerInteractionManager; -import net.minecraft.component.type.LoreComponent; -import net.minecraft.item.ItemStack; -import net.minecraft.screen.GenericContainerScreenHandler; -import net.minecraft.screen.HopperScreenHandler; -import net.minecraft.screen.ScreenHandler; -import net.minecraft.screen.slot.Slot; -import net.minecraft.util.collection.DefaultedList; - -import java.util.HashMap; -import java.util.Map; -import java.util.regex.Matcher; - -import static de.rettichlp.ucutils.UCUtils.player; -import static de.rettichlp.ucutils.UCUtils.storage; -import static de.rettichlp.ucutils.UCUtils.utilService; -import static de.rettichlp.ucutils.common.models.InventoryItem.ANTIBIOTICS; -import static de.rettichlp.ucutils.common.models.InventoryItem.COUGH_SYRUP; -import static de.rettichlp.ucutils.common.models.InventoryItem.CRYSTALS; -import static de.rettichlp.ucutils.common.models.InventoryItem.GRAB_BAG; -import static de.rettichlp.ucutils.common.models.InventoryItem.GUN_POWDER; -import static de.rettichlp.ucutils.common.models.InventoryItem.HERBS; -import static de.rettichlp.ucutils.common.models.InventoryItem.IRON; -import static de.rettichlp.ucutils.common.models.InventoryItem.KEVLAR_FIBERS; -import static de.rettichlp.ucutils.common.models.InventoryItem.MASK; -import static de.rettichlp.ucutils.common.models.InventoryItem.MEDICINAL_HERBS; -import static de.rettichlp.ucutils.common.models.InventoryItem.PAINKILLERS; -import static de.rettichlp.ucutils.common.models.InventoryItem.fromDisplayName; -import static de.rettichlp.ucutils.common.models.Purity.BEST; -import static java.lang.Integer.parseInt; -import static java.util.regex.Pattern.compile; -import static net.minecraft.component.DataComponentTypes.LORE; -import static net.minecraft.screen.slot.SlotActionType.PICKUP; - -@UCUtilsListener -public class InventoryListener implements IScreenOpenListener { - - public static InventoryItem inventorySyncStep = null; - - @Override - public void onScreenOpen(Screen screen, int scaledWidth, int scaledHeight) { - if (!(screen instanceof HandledScreen handledScreen)) { - return; - } - - String title = handledScreen.getTitle().getString(); - ClientPlayerInteractionManager interactionManager = MinecraftClient.getInstance().interactionManager; - - if (inventorySyncStep == null || interactionManager == null) { - return; - } - - ScreenHandler screenHandler = handledScreen.getScreenHandler(); - - if (screenHandler instanceof GenericContainerScreenHandler genericContainerScreenHandler) { - if (!title.equals("Inventar")) { - return; - } - - utilService.delayedAction(() -> { - switch (inventorySyncStep) { - case POWDER -> { - interactionManager.clickSlot(genericContainerScreenHandler.syncId, 0, 0, PICKUP, player); - return; - } - case HERBS -> { - interactionManager.clickSlot(genericContainerScreenHandler.syncId, 1, 0, PICKUP, player); - return; - } - case CRYSTALS -> { - interactionManager.clickSlot(genericContainerScreenHandler.syncId, 3, 0, PICKUP, player); - return; - } - default -> { - } - } - - ItemStack medicinalHerbsItemStack = genericContainerScreenHandler.slots.get(2).getStack(); - int medicinalHerbsAmount = getAmount(medicinalHerbsItemStack, 0); - storage.getInventory().put(MEDICINAL_HERBS, Map.of(BEST, medicinalHerbsAmount)); - - ItemStack surpriseBagItemStack = genericContainerScreenHandler.slots.get(4).getStack(); - int surpriseBagAmount = getAmount(surpriseBagItemStack, 0); - storage.getInventory().put(GRAB_BAG, Map.of(BEST, surpriseBagAmount)); - - ItemStack coughSyrupItemStack = genericContainerScreenHandler.slots.get(9).getStack(); - int coughSyrupAmount = getAmount(coughSyrupItemStack, 0); - storage.getInventory().put(COUGH_SYRUP, Map.of(BEST, coughSyrupAmount)); - - ItemStack painkillersItemStack = genericContainerScreenHandler.slots.get(10).getStack(); - int painkillersAmount = getAmount(painkillersItemStack, 0); - storage.getInventory().put(PAINKILLERS, Map.of(BEST, painkillersAmount)); - - ItemStack antibioticsItemStack = genericContainerScreenHandler.slots.get(11).getStack(); - int antibioticsAmount = getAmount(antibioticsItemStack, 0); - storage.getInventory().put(ANTIBIOTICS, Map.of(BEST, antibioticsAmount)); - - ItemStack maskItemStack = genericContainerScreenHandler.slots.get(18).getStack(); - int maskAmount = getAmount(maskItemStack, 0); - storage.getInventory().put(MASK, Map.of(BEST, maskAmount)); - - ItemStack ironItemStack = genericContainerScreenHandler.slots.get(19).getStack(); - int ironAmount = getAmount(ironItemStack, 0); - storage.getInventory().put(IRON, Map.of(BEST, ironAmount)); - - ItemStack gunpowderItemStack = genericContainerScreenHandler.slots.get(20).getStack(); - int gunpowderAmount = getAmount(gunpowderItemStack, 0); - storage.getInventory().put(GUN_POWDER, Map.of(BEST, gunpowderAmount)); - - ItemStack kevlarFibersItemStack = genericContainerScreenHandler.slots.get(21).getStack(); - int kevlarFibersAmount = getAmount(kevlarFibersItemStack, 0); - storage.getInventory().put(KEVLAR_FIBERS, Map.of(BEST, kevlarFibersAmount)); - - inventorySyncStep = null; - player.closeScreen(); - }, 250); - - return; - } - - if (screenHandler instanceof HopperScreenHandler hopperScreenHandler) { - utilService.delayedAction(() -> fromDisplayName(title).ifPresent(inventoryItem -> { - Map purityAmounts = new HashMap<>(); - - DefaultedList slots = hopperScreenHandler.slots; - for (int i = 0; i < 4; i++) { - ItemStack itemStack = slots.get(i).getStack(); - int amount = getAmount(itemStack, 2); - purityAmounts.put(Purity.values()[i], amount); - } - - storage.getInventory().put(inventoryItem, purityAmounts); - switch (inventorySyncStep) { - case POWDER -> { - inventorySyncStep = HERBS; - interactionManager.clickSlot(hopperScreenHandler.syncId, 4, 0, PICKUP, player); - } - case HERBS -> { - inventorySyncStep = CRYSTALS; - interactionManager.clickSlot(hopperScreenHandler.syncId, 4, 0, PICKUP, player); - } - case CRYSTALS -> { - inventorySyncStep = MEDICINAL_HERBS; - interactionManager.clickSlot(hopperScreenHandler.syncId, 4, 0, PICKUP, player); - } - default -> inventorySyncStep = null; - } - }), 250); - } - } - - private int getAmount(@NonNull ItemStack itemStack, int loreLineIndex) { - LoreComponent loreComponent = itemStack.get(LORE); - - if (loreComponent == null) { - return 0; - } - - String amountString = loreComponent.lines().get(loreLineIndex).getString(); - Matcher matcher = compile("\\d+").matcher(amountString); - return matcher.find() ? parseInt(matcher.group()) : 0; - } -} From 0499b9ebab2ed7335104832a17f2cbf7ed3fc484 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Thu, 21 May 2026 18:09:51 +0200 Subject: [PATCH 42/96] Remove unused translation keys for purity levels --- src/main/resources/assets/ucutils/lang/de_de.json | 12 ------------ src/main/resources/assets/ucutils/lang/en_gb.json | 12 ------------ src/main/resources/assets/ucutils/lang/en_us.json | 12 ------------ 3 files changed, 36 deletions(-) diff --git a/src/main/resources/assets/ucutils/lang/de_de.json b/src/main/resources/assets/ucutils/lang/de_de.json index ebabddf1..c298f585 100644 --- a/src/main/resources/assets/ucutils/lang/de_de.json +++ b/src/main/resources/assets/ucutils/lang/de_de.json @@ -113,18 +113,6 @@ "ucutils.options.widgets.service_count.options.name": "Notrufe", "ucutils.options.widgets.service_count.options.tooltip": "Zeigt an wie viele Notrufe gerade offen sind", - "ucutils.purity.best": "Höchste", - "ucutils.purity.good": "Gute", - "ucutils.purity.medium": "Mittlere", - "ucutils.purity.bad": "Schlechte", - - "ucutils.screen.data_usage_confirmation.message": "UCUtils kommuniziert mit einem externen Server. Dies ist notwendig, damit einige Funktionen richtig arbeiten. Mit dem Klick auf Zustimmen stimmst du der Datennutzung zu.", - "ucutils.screen.faction.button.activity.name": "Aktivitäten", - "ucutils.screen.faction.button.equip.name": "Equip", - "ucutils.screen.faction.button.blacklist.name": "Blacklist Gründe", - "ucutils.screen.faction.blacklist.header.reason": "Grund", - "ucutils.screen.faction.blacklist.header.price": "Preis", - "ucutils.screen.faction.blacklist.header.kills": "Tode", "ucutils.screen.shutdown_abort.button.name": "Herunterfahren abbrechen", "ucutils.select_state.always.name": "Immer", diff --git a/src/main/resources/assets/ucutils/lang/en_gb.json b/src/main/resources/assets/ucutils/lang/en_gb.json index bba176f9..1675e91d 100644 --- a/src/main/resources/assets/ucutils/lang/en_gb.json +++ b/src/main/resources/assets/ucutils/lang/en_gb.json @@ -113,18 +113,6 @@ "ucutils.options.widgets.service_count.options.name": "Service Count", "ucutils.options.widgets.service_count.options.tooltip": "Shows the number of active services", - "ucutils.purity.best": "Best", - "ucutils.purity.good": "Good", - "ucutils.purity.medium": "Medium", - "ucutils.purity.bad": "Bad", - - "ucutils.screen.data_usage_confirmation.message": "UCUtils sends and receives data from an external server. This is required for certain features to function properly. By clicking Agree, you agree to this data usage.", - "ucutils.screen.faction.button.activity.name": "Activities", - "ucutils.screen.faction.button.equip.name": "Equip", - "ucutils.screen.faction.button.blacklist.name": "Blacklist reasons", - "ucutils.screen.faction.blacklist.header.reason": "Reason", - "ucutils.screen.faction.blacklist.header.price": "Price", - "ucutils.screen.faction.blacklist.header.kills": "Kills", "ucutils.screen.shutdown_abort.button.name": "Abort shutdown", "ucutils.select_state.always.name": "Always", diff --git a/src/main/resources/assets/ucutils/lang/en_us.json b/src/main/resources/assets/ucutils/lang/en_us.json index bba176f9..1675e91d 100644 --- a/src/main/resources/assets/ucutils/lang/en_us.json +++ b/src/main/resources/assets/ucutils/lang/en_us.json @@ -113,18 +113,6 @@ "ucutils.options.widgets.service_count.options.name": "Service Count", "ucutils.options.widgets.service_count.options.tooltip": "Shows the number of active services", - "ucutils.purity.best": "Best", - "ucutils.purity.good": "Good", - "ucutils.purity.medium": "Medium", - "ucutils.purity.bad": "Bad", - - "ucutils.screen.data_usage_confirmation.message": "UCUtils sends and receives data from an external server. This is required for certain features to function properly. By clicking Agree, you agree to this data usage.", - "ucutils.screen.faction.button.activity.name": "Activities", - "ucutils.screen.faction.button.equip.name": "Equip", - "ucutils.screen.faction.button.blacklist.name": "Blacklist reasons", - "ucutils.screen.faction.blacklist.header.reason": "Reason", - "ucutils.screen.faction.blacklist.header.price": "Price", - "ucutils.screen.faction.blacklist.header.kills": "Kills", "ucutils.screen.shutdown_abort.button.name": "Abort shutdown", "ucutils.select_state.always.name": "Always", From 2c2986bd6d2f0760208b5e2071462b6cc413f66d Mon Sep 17 00:00:00 2001 From: RettichLP Date: Fri, 22 May 2026 01:58:50 +0200 Subject: [PATCH 43/96] Remove unused INaviSpotReachedListener implementation and related logic in EmergencyServiceListener --- .../faction/EmergencyServiceListener.java | 40 +------------------ 1 file changed, 1 insertion(+), 39 deletions(-) diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/faction/EmergencyServiceListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/faction/EmergencyServiceListener.java index 72d7bd6e..99517535 100644 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/faction/EmergencyServiceListener.java +++ b/src/main/java/de/rettichlp/ucutils/listener/impl/faction/EmergencyServiceListener.java @@ -2,15 +2,12 @@ import de.rettichlp.ucutils.common.registry.UCUtilsListener; import de.rettichlp.ucutils.listener.IMessageReceiveListener; -import de.rettichlp.ucutils.listener.INaviSpotReachedListener; import net.minecraft.text.Text; import java.util.regex.Matcher; import java.util.regex.Pattern; -import static de.rettichlp.ucutils.UCUtils.commandService; import static de.rettichlp.ucutils.UCUtils.configuration; -import static de.rettichlp.ucutils.UCUtils.player; import static de.rettichlp.ucutils.UCUtils.storage; import static de.rettichlp.ucutils.common.models.Sound.SERVICE; import static java.lang.Integer.parseInt; @@ -18,19 +15,15 @@ import static java.util.regex.Pattern.compile; @UCUtilsListener -public class EmergencyServiceListener implements IMessageReceiveListener, INaviSpotReachedListener { +public class EmergencyServiceListener implements IMessageReceiveListener { private static final Pattern SERVICE_PATTERN = compile("Ein Notruf von (?:\\[UC])?(?[a-zA-Z0-9_]+) \\((?\\d+)\\): \"(?.+)\""); private static final Pattern SERVICE_ACCEPTED_PATTERN = compile("^(?:HQ: )?(?:\\[UC])?(?[a-zA-Z0-9_]+) hat den Notruf von (?:\\[UC])?(?[a-zA-Z0-9_]+) angenommen\\. \\((?\\d+)m entfernt\\)$"); private static final Pattern SERVICE_REQUEUED_PATTERN = compile("^(?:\\[UC])?(?[a-zA-Z0-9_]+) hat den Notruf von (?:\\[UC])?(?[a-zA-Z0-9_]+) \\((?\\d+)\\) wieder geöffnet\\.$"); - private static final Pattern SERVICE_DONE_PATTERN = compile("^Du hast den Service von (?:\\[UC])?(?[a-zA-Z0-9_]+) als 'Erledigt' markiert!$"); private static final Pattern SERVICE_ABORTED_PATTERN = compile("^Der Service von (?:\\[UC])?(?[a-zA-Z0-9_]+) wurde abgebrochen\\.$"); private static final Pattern SERVICE_DELETED_PATTERN = compile("^Der Notruf von (?:\\[UC])?(?[a-zA-Z0-9_]+) wurde von (?:\\[UC])?(?[a-zA-Z0-9_]+) gelöscht\\.$"); private static final Pattern SERVICE_COUNT_PATTERN = compile("^Offene Notrufe \\((?\\d+)\\):"); private static final Pattern SERVICE_NONE_PATTERN = compile("^Fehler: Es ist kein Service offen\\.$"); - private static final Pattern SERVICE_NONE_FOR_PLAYER_PATTERN = compile("^Fehler: Es wurde kein Service von dir akzeptiert\\.$"); - - private boolean activeService = false; @Override public boolean onMessageReceive(Text text, String message) { @@ -48,30 +41,12 @@ public boolean onMessageReceive(Text text, String message) { Matcher serviceAcceptedMatcher = SERVICE_ACCEPTED_PATTERN.matcher(message); if (serviceAcceptedMatcher.find()) { storage.setActiveServices(max(0, storage.getActiveServices() - 1)); - - String playerName = serviceAcceptedMatcher.group("playerName"); - if (playerName.equals(player.getGameProfile().name())) { - this.activeService = true; - } - return true; } Matcher serviceRequeuedMatcher = SERVICE_REQUEUED_PATTERN.matcher(message); if (serviceRequeuedMatcher.find()) { storage.setActiveServices(storage.getActiveServices() + 1); - - String playerName = serviceRequeuedMatcher.group("playerName"); - if (playerName.equals(player.getGameProfile().name())) { - this.activeService = false; - } - - return true; - } - - Matcher serviceDoneMatcher = SERVICE_DONE_PATTERN.matcher(message); - if (serviceDoneMatcher.find()) { - this.activeService = false; return true; } @@ -100,19 +75,6 @@ public boolean onMessageReceive(Text text, String message) { return true; } - Matcher serviceNoneForPlayerMatcher = SERVICE_NONE_FOR_PLAYER_PATTERN.matcher(message); - if (serviceNoneForPlayerMatcher.find()) { - this.activeService = false; - return true; - } - return true; } - - @Override - public void onNaviSpotReached() { - if (this.activeService) { - commandService.sendCommand("doneservice"); - } - } } From f2e5788f37d168d2d589f808c32bbe3cf10e402e Mon Sep 17 00:00:00 2001 From: RettichLP Date: Fri, 22 May 2026 03:07:29 +0200 Subject: [PATCH 44/96] Remove PlantListener and IBlockRightClickListener classes and related logic --- .../listener/IBlockRightClickListener.java | 10 --- .../listener/impl/faction/PlantListener.java | 74 ------------------- 2 files changed, 84 deletions(-) delete mode 100644 src/main/java/de/rettichlp/ucutils/listener/IBlockRightClickListener.java delete mode 100644 src/main/java/de/rettichlp/ucutils/listener/impl/faction/PlantListener.java diff --git a/src/main/java/de/rettichlp/ucutils/listener/IBlockRightClickListener.java b/src/main/java/de/rettichlp/ucutils/listener/IBlockRightClickListener.java deleted file mode 100644 index c5487c68..00000000 --- a/src/main/java/de/rettichlp/ucutils/listener/IBlockRightClickListener.java +++ /dev/null @@ -1,10 +0,0 @@ -package de.rettichlp.ucutils.listener; - -import net.minecraft.util.Hand; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.world.World; - -public interface IBlockRightClickListener extends IUCUtilsListener { - - void onBlockRightClick(World world, Hand hand, BlockHitResult hitResult); -} diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/faction/PlantListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/faction/PlantListener.java deleted file mode 100644 index 2e2445ee..00000000 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/faction/PlantListener.java +++ /dev/null @@ -1,74 +0,0 @@ -package de.rettichlp.ucutils.listener.impl.faction; - -import de.rettichlp.ucutils.common.registry.UCUtilsListener; -import de.rettichlp.ucutils.listener.IBlockRightClickListener; -import de.rettichlp.ucutils.listener.IScreenOpenListener; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.screen.ingame.HopperScreen; -import net.minecraft.client.network.ClientPlayerInteractionManager; -import net.minecraft.item.ItemStack; -import net.minecraft.util.Hand; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; -import org.jetbrains.annotations.NotNull; - -import static de.rettichlp.ucutils.UCUtils.commandService; -import static de.rettichlp.ucutils.UCUtils.messageService; -import static de.rettichlp.ucutils.UCUtils.player; -import static net.minecraft.block.Blocks.FERN; -import static net.minecraft.block.Blocks.PODZOL; -import static net.minecraft.entity.EquipmentSlot.MAINHAND; -import static net.minecraft.item.Items.BEETROOT_SEEDS; -import static net.minecraft.item.Items.BONE_MEAL; -import static net.minecraft.item.Items.WATER_BUCKET; -import static net.minecraft.screen.slot.SlotActionType.PICKUP; - -@UCUtilsListener -public class PlantListener implements IBlockRightClickListener, IScreenOpenListener { - - private static final String PLANT_TEXT = "Plantage"; - - @Override - public void onBlockRightClick(@NotNull World world, Hand hand, @NotNull BlockHitResult hitResult) { - BlockPos blockPos = hitResult.getBlockPos(); - - boolean targetBlockIsPlant = world.getBlockState(blockPos).getBlock().equals(FERN) && world.getBlockState(blockPos.down()).getBlock().equals(PODZOL); - if (!targetBlockIsPlant) { - // check for plant placing - ItemStack mainHandStack = player.getEquippedStack(MAINHAND); - - if (player.isSneaking() && (mainHandStack.isOf(BEETROOT_SEEDS))) { - commandService.sendCommand("plant plant"); - } - - return; - } - - boolean isStandingOnPlant = player.getBlockPos().equals(blockPos); - if (!isStandingOnPlant) { - messageService.sendModMessage("Du musst auf der Plantage stehen, um sie via UCUtils zu verwalten.", false); - return; - } - - commandService.sendCommand("plant"); - } - - @Override - public void onScreenOpen(Screen screen, int scaledWidth, int scaledHeight) { - ClientPlayerInteractionManager interactionManager = MinecraftClient.getInstance().interactionManager; - - if (interactionManager != null && screen instanceof HopperScreen hopperScreen && PLANT_TEXT.equals(hopperScreen.getTitle().getString())) { - ItemStack mainHandStack = player.getEquippedStack(MAINHAND); - - int syncId = hopperScreen.getScreenHandler().syncId; - // https://i.imgur.com/b8INthP.png - if (mainHandStack.isOf(WATER_BUCKET)) { - interactionManager.clickSlot(syncId, 4, 0, PICKUP, player); - } else if (mainHandStack.isOf(BONE_MEAL)) { - interactionManager.clickSlot(syncId, 3, 0, PICKUP, player); - } - } - } -} From 62c207c169d5e2c334825a2ab9d160c4ab0975b3 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Fri, 22 May 2026 03:08:00 +0200 Subject: [PATCH 45/96] Replace `LOGGER` and `networkHandler` with `commandService`; remove praying logic and unused imports/constants in mixins and listeners --- .../ucutils/listener/impl/PlayerListener.java | 11 ----------- .../ucutils/mixin/ClientPlayerEntityMixin.java | 6 ++---- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/PlayerListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/PlayerListener.java index f5378f4e..80b7f074 100644 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/PlayerListener.java +++ b/src/main/java/de/rettichlp/ucutils/listener/impl/PlayerListener.java @@ -19,7 +19,6 @@ import static de.rettichlp.ucutils.UCUtils.nameTagService; import static de.rettichlp.ucutils.UCUtils.player; import static de.rettichlp.ucutils.UCUtils.storage; -import static de.rettichlp.ucutils.UCUtils.utilService; import static de.rettichlp.ucutils.common.models.ShutdownReason.CEMETERY; import static de.rettichlp.ucutils.common.models.ShutdownReason.JAIL; import static java.lang.Double.parseDouble; @@ -38,7 +37,6 @@ public class PlayerListener implements IMessageReceiveListener, ITickListener { private static final String SHUTDOWN_TIMEOUT = "5"; - private static final int PRAY_DELAY_IN_SECONDS = 30; // dead private static final Pattern DEAD_PATTERN = compile("^Du bist nun für (?\\d+) Minuten auf dem Friedhof\\.$"); @@ -55,9 +53,6 @@ public class PlayerListener implements IMessageReceiveListener, ITickListener { private static final Pattern JAIL_PATTERN = compile("^\\[Gefängnis] Du bist nun für (?\\d+) Minuten im Gefängnis\\.$"); private static final Pattern JAIL_UNJAIL_PATTERN = compile("^\\[Gefängnis] Du bist nun wieder frei!$"); - // pray - private static final Pattern PRAY_START_PATTERN = compile("^\\[Kirche] Du fängst an für (?:\\[UC])?(?[a-zA-Z0-9_]+) zu beten\\.$"); - // premium private static final Pattern PREMIUM_PATTERN = compile("^\\[Premium] Dein Premium Account ist noch .+ aktiv\\.$"); @@ -140,12 +135,6 @@ public boolean onMessageReceive(Text text, String message) { return true; } - Matcher prayStartMatcher = PRAY_START_PATTERN.matcher(message); - if (prayStartMatcher.find()) { - utilService.delayedAction(() -> commandService.sendCommand("beten"), PRAY_DELAY_IN_SECONDS * 1000L); - return true; - } - Matcher premiumMatcher = PREMIUM_PATTERN.matcher(message); if (premiumMatcher.find()) { storage.setPremium(true); diff --git a/src/main/java/de/rettichlp/ucutils/mixin/ClientPlayerEntityMixin.java b/src/main/java/de/rettichlp/ucutils/mixin/ClientPlayerEntityMixin.java index c48a2ea9..cb7891a2 100644 --- a/src/main/java/de/rettichlp/ucutils/mixin/ClientPlayerEntityMixin.java +++ b/src/main/java/de/rettichlp/ucutils/mixin/ClientPlayerEntityMixin.java @@ -10,8 +10,7 @@ import java.util.List; -import static de.rettichlp.ucutils.UCUtils.LOGGER; -import static de.rettichlp.ucutils.UCUtils.networkHandler; +import static de.rettichlp.ucutils.UCUtils.commandService; import static de.rettichlp.ucutils.UCUtils.player; import static de.rettichlp.ucutils.UCUtils.storage; import static net.minecraft.item.Items.GLASS_BOTTLE; @@ -36,8 +35,7 @@ public abstract class ClientPlayerEntityMixin { cir.setReturnValue(null); // execute command - LOGGER.info("UCUtils executing command: sell pfand"); - networkHandler.sendChatCommand("sell pfand"); + commandService.sendCommand("sell pfand"); } } From ca55887a6c1578199e3dc1d351f9a4029a141f0b Mon Sep 17 00:00:00 2001 From: RettichLP Date: Fri, 22 May 2026 03:08:49 +0200 Subject: [PATCH 46/96] Remove planting and watering logic from README documentation --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 9e275fdb..d2492029 100644 --- a/README.md +++ b/README.md @@ -46,8 +46,6 @@ Folgende Funktionen sind nur für Spieler ohne Premium-Rang verfügbar, da Spiel - Für den Rettungsdienst wird der Cooldown von Bandagen und Schmerzpillen unter dem Spielernamen angezeigt - Wenn man den Navi-Punkt eines Notrufs erreicht, wird der Notruf automatisch als erledigt markiert - Der Fraktionschat kann individuell eingefärbt werden -- Eine Plantage kann direkt durch gleichzeitiges Schleichen und Klicken mit einem Samen in der Hand gelegt werden -- Eine Plantage kann durch einen Rechtsklick mit einem Wassereimer oder Dünger direkt gewässert beziehungsweise gedüngt werden - Der Rettungsdienst kann durch einen Rechtsklick auf eine bewusstlose Person diese wiederbeleben - Mit `/fbank einzahlen ` kann das Eingabe GUI des Servers übersprungen werden - Für den Rettungsdienst gibt es im Herstellungs-Inventar für Medikamente einen Button, um die benötigte Anzahl an Stoffen in den From 0e6007f81e360a371948fe83c42015fe07d6af3b Mon Sep 17 00:00:00 2001 From: RettichLP Date: Fri, 22 May 2026 03:11:40 +0200 Subject: [PATCH 47/96] Remove UseBlockCallback event and related IBlockRightClickListener logic --- .../rettichlp/ucutils/common/registry/Registry.java | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/main/java/de/rettichlp/ucutils/common/registry/Registry.java b/src/main/java/de/rettichlp/ucutils/common/registry/Registry.java index dfa51a60..bf0ed2a0 100644 --- a/src/main/java/de/rettichlp/ucutils/common/registry/Registry.java +++ b/src/main/java/de/rettichlp/ucutils/common/registry/Registry.java @@ -3,7 +3,6 @@ import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import de.rettichlp.ucutils.common.models.Sound; -import de.rettichlp.ucutils.listener.IBlockRightClickListener; import de.rettichlp.ucutils.listener.ICommandSendListener; import de.rettichlp.ucutils.listener.IEnterVehicleListener; import de.rettichlp.ucutils.listener.IEntityRenderListener; @@ -23,7 +22,6 @@ import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback; import net.fabricmc.fabric.api.client.rendering.v1.world.WorldRenderEvents; import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents; -import net.fabricmc.fabric.api.event.player.UseBlockCallback; import net.minecraft.util.math.BlockPos; import org.jetbrains.annotations.NotNull; @@ -40,8 +38,6 @@ import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal; import static net.minecraft.registry.Registries.SOUND_EVENT; import static net.minecraft.registry.Registry.register; -import static net.minecraft.util.ActionResult.PASS; -import static net.minecraft.util.Hand.OFF_HAND; import static org.atteo.classindex.ClassIndex.getAnnotated; public class Registry { @@ -147,14 +143,6 @@ public void registerListeners() { ScreenEvents.AFTER_INIT.register((client, screen, scaledWidth, scaledHeight) -> getListenersImplementing(IScreenOpenListener.class).forEach(iScreenOpenListener -> iScreenOpenListener.onScreenOpen(screen, scaledWidth, scaledHeight))); - UseBlockCallback.EVENT.register((player, world, hand, hitResult) -> { - if (hand != OFF_HAND && world.isClient()) { - getListenersImplementing(IBlockRightClickListener.class).forEach(iBlockRightClickListener -> iBlockRightClickListener.onBlockRightClick(world, hand, hitResult)); - } - - return PASS; - }); - WorldRenderEvents.AFTER_ENTITIES.register(context -> getListenersImplementing(IEntityRenderListener.class).forEach(iEntityRenderListener -> iEntityRenderListener.onEntityRender(context))); // prevent multiple registrations of listeners From 3442d0d3dd9131010cc91754b150c15993fcafae Mon Sep 17 00:00:00 2001 From: RettichLP Date: Fri, 22 May 2026 03:13:44 +0200 Subject: [PATCH 48/96] Remove FactionDoorListener and related door interaction logic --- .../impl/faction/FactionDoorListener.java | 46 ------------------- 1 file changed, 46 deletions(-) delete mode 100644 src/main/java/de/rettichlp/ucutils/listener/impl/faction/FactionDoorListener.java diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/faction/FactionDoorListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/faction/FactionDoorListener.java deleted file mode 100644 index b702cf75..00000000 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/faction/FactionDoorListener.java +++ /dev/null @@ -1,46 +0,0 @@ -package de.rettichlp.ucutils.listener.impl.faction; - -import de.rettichlp.ucutils.common.models.Faction; -import de.rettichlp.ucutils.common.registry.UCUtilsListener; -import de.rettichlp.ucutils.listener.IBlockRightClickListener; -import net.minecraft.util.Hand; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; - -import java.util.Map; -import java.util.Set; - -import static de.rettichlp.ucutils.UCUtils.commandService; -import static de.rettichlp.ucutils.UCUtils.player; -import static de.rettichlp.ucutils.UCUtils.storage; -import static de.rettichlp.ucutils.common.models.Faction.FBI; -import static de.rettichlp.ucutils.common.models.Faction.KERZAKOV_FAMILIE; -import static de.rettichlp.ucutils.common.models.Faction.WESTSIDE_BALLAS; -import static java.util.Collections.emptySet; -import static net.minecraft.util.Hand.MAIN_HAND; - -@UCUtilsListener -public class FactionDoorListener implements IBlockRightClickListener { - - private static final Map> FACTION_DOOR_POSITIONS = Map.of( - FBI, Set.of(new BlockPos(879, 62, -87)), - KERZAKOV_FAMILIE, Set.of(new BlockPos(936, 69, 191), new BlockPos(936, 69, 174)), - WESTSIDE_BALLAS, Set.of(new BlockPos(-166, 68, 205))); - private static final int DISTANCE = 4; - - @Override - public void onBlockRightClick(World world, Hand hand, BlockHitResult hitResult) { - if (!player.getStackInHand(MAIN_HAND).isEmpty()) { - return; - } - - Faction faction = storage.getFaction(player.getGameProfile().name()); - Set factionDoorPositions = FACTION_DOOR_POSITIONS.getOrDefault(faction, emptySet()); - - factionDoorPositions.stream() - .filter(blockPos -> blockPos.isWithinDistance(hitResult.getBlockPos(), DISTANCE)) - .findAny() - .ifPresent(blockPos -> commandService.sendCommand("fdoor")); - } -} From 8ab05088d18fd8e16946f04a1c33b2f77fbd2baf Mon Sep 17 00:00:00 2001 From: RettichLP Date: Fri, 22 May 2026 03:15:07 +0200 Subject: [PATCH 49/96] Remove FactionDoor interaction documentation from README --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index d2492029..23715a79 100644 --- a/README.md +++ b/README.md @@ -42,9 +42,7 @@ Folgende Funktionen sind nur für Spieler ohne Premium-Rang verfügbar, da Spiel - Sollte ein Spieler Wanted-Punkte haben, wird der Name der Leiche dementsprechend eingefärbt - Das Design der Reinforcements ist so überarbeitet, dass diese besser auffallen - Für das FBI, die Polizei und den Rettungsdienst gibt es einen Timer, der die Dauer der Bombe anzeigt -- Mit einem Rechtsklick auf ein Fraktionstor (nicht Fraktionstür) wird dieses automatisch geöffnet oder geschlossen - Für den Rettungsdienst wird der Cooldown von Bandagen und Schmerzpillen unter dem Spielernamen angezeigt -- Wenn man den Navi-Punkt eines Notrufs erreicht, wird der Notruf automatisch als erledigt markiert - Der Fraktionschat kann individuell eingefärbt werden - Der Rettungsdienst kann durch einen Rechtsklick auf eine bewusstlose Person diese wiederbeleben - Mit `/fbank einzahlen ` kann das Eingabe GUI des Servers übersprungen werden From 42e135092cfcfc7a89eba8208d43b60ef35f16f8 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Fri, 22 May 2026 03:17:32 +0200 Subject: [PATCH 50/96] Remove `MinecraftClientMixin` and related item interaction logic --- .../ucutils/mixin/MinecraftClientMixin.java | 75 ------------------- src/main/resources/ucutils.mixins.json | 1 - 2 files changed, 76 deletions(-) delete mode 100644 src/main/java/de/rettichlp/ucutils/mixin/MinecraftClientMixin.java diff --git a/src/main/java/de/rettichlp/ucutils/mixin/MinecraftClientMixin.java b/src/main/java/de/rettichlp/ucutils/mixin/MinecraftClientMixin.java deleted file mode 100644 index fa1bb70a..00000000 --- a/src/main/java/de/rettichlp/ucutils/mixin/MinecraftClientMixin.java +++ /dev/null @@ -1,75 +0,0 @@ -package de.rettichlp.ucutils.mixin; - -import com.mojang.brigadier.Message; -import lombok.NonNull; -import net.minecraft.client.MinecraftClient; -import net.minecraft.entity.ItemEntity; -import net.minecraft.text.Text; -import net.minecraft.util.hit.EntityHitResult; -import net.minecraft.util.math.Box; -import net.minecraft.util.math.Vec3d; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import static de.rettichlp.ucutils.UCUtils.commandService; -import static de.rettichlp.ucutils.UCUtils.player; -import static de.rettichlp.ucutils.UCUtils.storage; -import static de.rettichlp.ucutils.common.models.Faction.RETTUNGSDIENST; -import static net.minecraft.entity.projectile.ProjectileUtil.raycast; - -@Mixin(MinecraftClient.class) -public abstract class MinecraftClientMixin { - - @Unique - private static final int DISTANCE = 3; - - @Inject(method = "handleInputEvents", at = @At("HEAD")) - private void ucutils$handleInputEventsHead(CallbackInfo ci) { - if (!storage.isUnicaCity()) { - return; - } - - MinecraftClient client = MinecraftClient.getInstance(); - - if (client.options.useKey.wasPressed()) { - float partialTick = client.getRenderTickCounter().getTickProgress(true); - - Vec3d from = player.getCameraPosVec(partialTick); - - Vec3d direction = player.getRotationVec(partialTick); - Vec3d to = from.add(direction.multiply(DISTANCE)); - - Box box = player.getBoundingBox() - .stretch(direction.multiply(DISTANCE)) - .expand(1.0); - - EntityHitResult result = raycast(player, from, to, box, e -> e instanceof ItemEntity, DISTANCE * DISTANCE); - - if (result == null || !(result.getEntity() instanceof ItemEntity itemEntity) || !itemEntity.hasCustomName()) { - return; - } - - Text customName = itemEntity.getCustomName(); - assert customName != null; - String playerName = revertEnrichment(customName); - - if (player.isSneaking()) { - commandService.sendCommand("erstehilfe " + playerName); - } else if (storage.getFaction(player.getStringifiedName()) == RETTUNGSDIENST) { - commandService.sendCommand("revive " + playerName); - } - } - } - - @Unique - private String revertEnrichment(@NonNull Message text) { - String string = text.getString(); - String[] strings = string.split(" "); - - // if name contains faction information, the last index is faction information - return string.contains("⌜") ? strings[strings.length - 2] : strings[strings.length - 1]; - } -} diff --git a/src/main/resources/ucutils.mixins.json b/src/main/resources/ucutils.mixins.json index cc051e11..86151a0f 100644 --- a/src/main/resources/ucutils.mixins.json +++ b/src/main/resources/ucutils.mixins.json @@ -21,7 +21,6 @@ "GameMenuScreenMixin", "HandledScreenMixin", "InGameHudMixin", - "MinecraftClientMixin", "PlayerEntityRendererMixin", "PlayerListHudMixin" ] From f41741cb3595ceca481bfbe6c6b937094c966da9 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Fri, 22 May 2026 03:19:02 +0200 Subject: [PATCH 51/96] Remove first aid and revival logic from README documentation --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 23715a79..5bd4bced 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,6 @@ reibungsloser und angenehmer gestalten. - Es wird angezeigt, wie lang der Cooldown für Bandagen und Schmerzpillen ist - Es werden Sounds abgespielt für Notrufe, Bomben, Feuer, Staatsbankraub und weitere Situationen - Über der Hungerleiste wird der Durst angezeigt -- Mit einem Rechtsklick, während man schleicht, kann man bewusstlosen Personen Erste-Hilfe geben - Über den Spielernamen wird AFK angezeigt, wenn der Spieler AFK ist - Für Teammitglieder wird eine Warnung angezeigt, wenn sie sich im Admindienst befinden und eine Waffe in der Hand haben - Hinter der Nachricht, dass sich das Karma geändert hat, wird angezeigt, wie viel Karma man insgesamt besitzt und wann ein Spieler @@ -44,7 +43,6 @@ Folgende Funktionen sind nur für Spieler ohne Premium-Rang verfügbar, da Spiel - Für das FBI, die Polizei und den Rettungsdienst gibt es einen Timer, der die Dauer der Bombe anzeigt - Für den Rettungsdienst wird der Cooldown von Bandagen und Schmerzpillen unter dem Spielernamen angezeigt - Der Fraktionschat kann individuell eingefärbt werden -- Der Rettungsdienst kann durch einen Rechtsklick auf eine bewusstlose Person diese wiederbeleben - Mit `/fbank einzahlen ` kann das Eingabe GUI des Servers übersprungen werden - Für den Rettungsdienst gibt es im Herstellungs-Inventar für Medikamente einen Button, um die benötigte Anzahl an Stoffen in den Fraktionschat zu senden From 1f8c55da59cd8a39675a33874255b61b19679240 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Fri, 22 May 2026 03:27:14 +0200 Subject: [PATCH 52/96] Remove IMoveListener implementation and related black market and dealer tracking logic --- .../impl/faction/FactionListener.java | 65 +------------------ 1 file changed, 1 insertion(+), 64 deletions(-) diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/faction/FactionListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/faction/FactionListener.java index ff712ebe..762d49bd 100644 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/faction/FactionListener.java +++ b/src/main/java/de/rettichlp/ucutils/listener/impl/faction/FactionListener.java @@ -1,38 +1,27 @@ package de.rettichlp.ucutils.listener.impl.faction; import de.rettichlp.ucutils.common.Storage; -import de.rettichlp.ucutils.common.models.BlackMarket; -import de.rettichlp.ucutils.common.models.Dealer; import de.rettichlp.ucutils.common.models.FactionMember; import de.rettichlp.ucutils.common.registry.UCUtilsListener; import de.rettichlp.ucutils.listener.IMessageReceiveListener; import de.rettichlp.ucutils.listener.IMessageSendListener; -import de.rettichlp.ucutils.listener.IMoveListener; import lombok.NonNull; import net.minecraft.client.MinecraftClient; -import net.minecraft.entity.passive.VillagerEntity; import net.minecraft.text.Text; import net.minecraft.text.TextColor; import net.minecraft.util.Formatting; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Box; import java.util.List; import java.util.Optional; -import java.util.function.Predicate; import java.util.regex.Matcher; import java.util.regex.Pattern; -import static de.rettichlp.ucutils.UCUtils.LOGGER; import static de.rettichlp.ucutils.UCUtils.commandService; import static de.rettichlp.ucutils.UCUtils.configuration; import static de.rettichlp.ucutils.UCUtils.player; import static de.rettichlp.ucutils.UCUtils.storage; import static de.rettichlp.ucutils.common.Storage.ToggledChat.NONE; import static de.rettichlp.ucutils.common.configuration.options.Options.ReinforcementType.UNICACITYADDON; -import static java.lang.System.currentTimeMillis; -import static java.time.LocalDateTime.now; -import static java.util.Arrays.stream; import static java.util.Optional.ofNullable; import static java.util.regex.Pattern.compile; import static net.minecraft.text.Text.empty; @@ -46,7 +35,7 @@ import static net.minecraft.util.Formatting.RED; @UCUtilsListener -public class FactionListener implements IMessageReceiveListener, IMessageSendListener, IMoveListener { +public class FactionListener implements IMessageReceiveListener, IMessageSendListener { private static final Pattern REINFORCEMENT_PATTERN = compile("^(?:(?.+)! )?(?.+) (?:\\[UC])?(?[a-zA-Z0-9_]+) benötigt Unterstützung in der Nähe von (?.+)! \\((?\\d+) Meter entfernt\\)$"); private static final Pattern REINFORCEMENT_BUTTON_PATTERN = compile("^ §7» §cRoute anzeigen §7\\| §cUnterwegs$"); @@ -71,8 +60,6 @@ public class FactionListener implements IMessageReceiveListener, IMessageSendLis .append(of(distance + "m").copy().formatted(DARK_AQUA)) .append(of(")").copy().formatted(GRAY)); - private long lastBlackMarketAndDealerCheck = 0; - @Override public boolean onMessageReceive(Text text, String message) { Matcher reinforcementMatcher = REINFORCEMENT_PATTERN.matcher(message); @@ -173,56 +160,6 @@ public boolean onMessageSend(String message) { return true; } - @Override - public void onMove(BlockPos blockPos) { - // mark the black market spot as visited if within 60 blocks - if (currentTimeMillis() - this.lastBlackMarketAndDealerCheck >= 3000) { // every 3 seconds to reduce performance impact - this.lastBlackMarketAndDealerCheck = currentTimeMillis(); - - stream(BlackMarket.Type.values()) - .filter(type -> type.getBlockPos().isWithinDistance(blockPos, 60)) - .forEach(type -> { - // remove old type association if exists - storage.getBlackMarkets().removeIf(blackMarket -> blackMarket.getType() == type); - - // check if black market was found there - Box box = player.getBoundingBox().expand(60); - Predicate isBlackMarket = villagerEntity -> ofNullable(villagerEntity.getCustomName()) - .map(text -> text.getString().contains("Schwarzmarkt")) - .orElse(false); - - assert MinecraftClient.getInstance().world != null; // cannot be null at this point - boolean found = !MinecraftClient.getInstance().world.getEntitiesByClass(VillagerEntity.class, box, isBlackMarket).isEmpty(); - - // add new black market entry - BlackMarket blackMarket = new BlackMarket(type, now(), found); - storage.getBlackMarkets().add(blackMarket); - LOGGER.info("Marked black market spot as visited: {}", type); - }); - - stream(Dealer.Type.values()) - .filter(type -> type.getBlockPos().isWithinDistance(blockPos, 60)) - .forEach(type -> { - // remove old type association if exists - storage.getDealers().removeIf(dealer -> dealer.getType() == type); - - // check if black market was found there - Box box = player.getBoundingBox().expand(60); - Predicate isBlackMarket = villagerEntity -> ofNullable(villagerEntity.getCustomName()) - .map(text -> text.getString().contains("Dealer")) - .orElse(false); - - assert MinecraftClient.getInstance().world != null; // cannot be null at this point - boolean found = !MinecraftClient.getInstance().world.getEntitiesByClass(VillagerEntity.class, box, isBlackMarket).isEmpty(); - - // add new black market entry - Dealer dealer = new Dealer(type, now(), found); - storage.getDealers().add(dealer); - LOGGER.info("Marked dealer spot as visited: {}", type); - }); - } - } - private boolean messageMatchesColor(@NonNull List siblings, Formatting primaryFormatting, Formatting secondaryFormatting) { TextColor primaryFormattingCurrent = siblings.get(0).getStyle().getColor(); TextColor secondaryFormattingCurrent = siblings.get(2).getStyle().getColor(); From fa6e356f97bd3134d7b8aaf0dc425ea09ebc8b26 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Fri, 22 May 2026 03:27:40 +0200 Subject: [PATCH 53/96] Remove IMoveListener and related player movement tracking logic --- .../ucutils/common/registry/Registry.java | 17 +---------------- .../ucutils/listener/IMoveListener.java | 8 -------- .../ucutils/listener/impl/job/JobListener.java | 15 +-------------- 3 files changed, 2 insertions(+), 38 deletions(-) delete mode 100644 src/main/java/de/rettichlp/ucutils/listener/IMoveListener.java diff --git a/src/main/java/de/rettichlp/ucutils/common/registry/Registry.java b/src/main/java/de/rettichlp/ucutils/common/registry/Registry.java index bf0ed2a0..2fa30f69 100644 --- a/src/main/java/de/rettichlp/ucutils/common/registry/Registry.java +++ b/src/main/java/de/rettichlp/ucutils/common/registry/Registry.java @@ -9,7 +9,6 @@ import de.rettichlp.ucutils.listener.IHudRenderListener; import de.rettichlp.ucutils.listener.IMessageReceiveListener; import de.rettichlp.ucutils.listener.IMessageSendListener; -import de.rettichlp.ucutils.listener.IMoveListener; import de.rettichlp.ucutils.listener.INaviSpotReachedListener; import de.rettichlp.ucutils.listener.IScreenOpenListener; import de.rettichlp.ucutils.listener.ITickListener; @@ -22,17 +21,14 @@ import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback; import net.fabricmc.fabric.api.client.rendering.v1.world.WorldRenderEvents; import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents; -import net.minecraft.util.math.BlockPos; import org.jetbrains.annotations.NotNull; import java.util.Objects; import java.util.Set; import static de.rettichlp.ucutils.UCUtils.LOGGER; -import static de.rettichlp.ucutils.UCUtils.player; import static de.rettichlp.ucutils.UCUtils.storage; import static java.util.Collections.emptySet; -import static java.util.Objects.isNull; import static java.util.stream.Collectors.toSet; import static java.util.stream.StreamSupport.stream; import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal; @@ -47,7 +43,6 @@ public class Registry { private final Set listenerInstances = getListenerInstances(); private boolean initialized = false; - private BlockPos lastPlayerPos = null; public void registerSounds() { for (Sound value : Sound.values()) { @@ -125,17 +120,7 @@ public void registerListeners() { return executeCommand; }); - ClientTickEvents.END_CLIENT_TICK.register((server) -> { - // handle tick - getListenersImplementing(ITickListener.class).forEach(ITickListener::onTick); - - // handle on move - BlockPos blockPos = player.getBlockPos(); - if (isNull(this.lastPlayerPos) || !this.lastPlayerPos.equals(blockPos)) { - this.lastPlayerPos = blockPos; - getListenersImplementing(IMoveListener.class).forEach(iMoveListener -> iMoveListener.onMove(blockPos)); - } - }); + ClientTickEvents.END_CLIENT_TICK.register((server) -> getListenersImplementing(ITickListener.class).forEach(ITickListener::onTick)); HudRenderCallback.EVENT.register((drawContext, tickCounter) -> getListenersImplementing(IHudRenderListener.class).forEach(iHudRenderListener -> iHudRenderListener.onHudRender(drawContext, tickCounter))); diff --git a/src/main/java/de/rettichlp/ucutils/listener/IMoveListener.java b/src/main/java/de/rettichlp/ucutils/listener/IMoveListener.java deleted file mode 100644 index 8777bb08..00000000 --- a/src/main/java/de/rettichlp/ucutils/listener/IMoveListener.java +++ /dev/null @@ -1,8 +0,0 @@ -package de.rettichlp.ucutils.listener; - -import net.minecraft.util.math.BlockPos; - -public interface IMoveListener extends IUCUtilsListener { - - void onMove(BlockPos blockPos); -} diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/job/JobListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/job/JobListener.java index c4610d1f..dac213bb 100644 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/job/JobListener.java +++ b/src/main/java/de/rettichlp/ucutils/listener/impl/job/JobListener.java @@ -4,7 +4,6 @@ import de.rettichlp.ucutils.common.models.Job; import de.rettichlp.ucutils.common.registry.UCUtilsListener; import de.rettichlp.ucutils.listener.IMessageReceiveListener; -import de.rettichlp.ucutils.listener.IMoveListener; import de.rettichlp.ucutils.listener.INaviSpotReachedListener; import net.minecraft.text.Text; import net.minecraft.util.math.BlockPos; @@ -20,7 +19,6 @@ import static de.rettichlp.ucutils.UCUtils.utilService; import static de.rettichlp.ucutils.common.models.Job.PIZZA_DELIVERY; import static de.rettichlp.ucutils.common.models.Job.TOBACCO_PLANTATION; -import static de.rettichlp.ucutils.common.models.Job.URANIUM_TRANSPORT; import static java.lang.Integer.parseInt; import static java.time.Duration.between; import static java.time.LocalDateTime.now; @@ -30,7 +28,7 @@ import static java.util.regex.Pattern.compile; @UCUtilsListener -public class JobListener implements IMessageReceiveListener, IMoveListener, INaviSpotReachedListener { +public class JobListener implements IMessageReceiveListener, INaviSpotReachedListener { private static final String MINING_BOOSTER_COUNTDOWN_TITLE = "Mining XP-Booster"; private static final Pattern TRANSPORT_DELIVER_PATTERN = compile("^\\[Transport] Du hast (eine Holz Lieferung|eine Kiste|eine Waffenkiste|ein Weizen Paket|eine Schwarzpulverkiste) abgeliefert( bei .+)?\\.$"); @@ -89,17 +87,6 @@ public boolean onMessageReceive(Text text, String message) { return true; } - @Override - public void onMove(BlockPos blockPos) { - if (isNull(storage.getCurrentJob())) { - return; - } - - if (storage.getCurrentJob() == URANIUM_TRANSPORT && player.getBlockPos().isWithinDistance(new BlockPos(1132, 68, 396), 2)) { - commandService.sendCommand("dropuran"); - } - } - @Override public void onNaviSpotReached() { if (isNull(storage.getCurrentJob())) { From cc7443a4fce730b20d5b442ee80524761e5346d7 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Fri, 22 May 2026 03:28:43 +0200 Subject: [PATCH 54/96] Remove faction commands documentation from README --- README.md | 7 ------- 1 file changed, 7 deletions(-) diff --git a/README.md b/README.md index 23715a79..8273bd0e 100644 --- a/README.md +++ b/README.md @@ -86,13 +86,6 @@ Folgende Funktionen sind nur für Spieler ohne Premium-Rang verfügbar, da Spiel | `/dd` | Aktiviert und deaktiviert das dauerhafte Schreiben im D-Chat ohne den `/d` Befehl jedes Mal eingeben zu müssen | | `/ww` | Aktiviert und deaktiviert das dauerhafte Flüstern ohne den `/w` Befehl jedes Mal eingeben zu müssen | -**Fraktionen** - -| Befehl | Beschreibung | -|------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------| -| `/schwarzmarkt` | Zeigt alle Schwarzmärkte an einschließlich des Zeitpunkts des letzten Besuchs des Ortes und einer Markierung ob sich der Schwarzmarkt dort befand | -| `/dealer` | Zeigt alle Dealer an einschließlich des Zeitpunkts des letzten Besuchs des Ortes und einer Markierung ob sich der Dealer dort befand | - **Geld** | Befehl | Beschreibung | From 46948578ff2a6307f74884e38c266efd93cbab66 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Fri, 22 May 2026 03:33:45 +0200 Subject: [PATCH 55/96] Remove `/einzahlen` (DepositCommand) and associated ATM handling logic --- .../ucutils/command/money/DepositCommand.java | 97 ------------------- .../de/rettichlp/ucutils/common/Storage.java | 6 -- .../listener/impl/EconomyListener.java | 8 -- 3 files changed, 111 deletions(-) delete mode 100644 src/main/java/de/rettichlp/ucutils/command/money/DepositCommand.java diff --git a/src/main/java/de/rettichlp/ucutils/command/money/DepositCommand.java b/src/main/java/de/rettichlp/ucutils/command/money/DepositCommand.java deleted file mode 100644 index 88273447..00000000 --- a/src/main/java/de/rettichlp/ucutils/command/money/DepositCommand.java +++ /dev/null @@ -1,97 +0,0 @@ -package de.rettichlp.ucutils.command.money; - -import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import de.rettichlp.ucutils.common.registry.CommandBase; -import de.rettichlp.ucutils.common.registry.UCUtilsCommand; -import de.rettichlp.ucutils.common.registry.UCUtilsListener; -import de.rettichlp.ucutils.listener.IMessageReceiveListener; -import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; -import net.minecraft.text.Text; -import org.jetbrains.annotations.NotNull; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import static de.rettichlp.ucutils.UCUtils.commandService; -import static de.rettichlp.ucutils.UCUtils.messageService; -import static de.rettichlp.ucutils.UCUtils.utilService; -import static de.rettichlp.ucutils.common.services.CommandService.COMMAND_COOLDOWN_MILLIS; -import static java.lang.Integer.parseInt; -import static java.util.regex.Pattern.compile; -import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal; - -@UCUtilsCommand(label = "einzahlen") -@UCUtilsListener -public class DepositCommand extends CommandBase implements IMessageReceiveListener { - - private static final Pattern PLAYER_MONEY_AMOUNT_PATTERN = compile("- Geld: (?\\d+)\\$"); - private static final Pattern ATM_MONEY_AMOUNT_PATTERN = compile("^ATM (?\\d+): (?\\d+)\\$/(?\\d+)\\$$"); - - private static int money = 0; - private static int atmMoneyAvailable = -1; - - @Override - public LiteralArgumentBuilder execute(@NotNull LiteralArgumentBuilder node) { - return node - .then(literal("force") - .executes(context -> { - commandService.sendCommand("stats"); - - utilService.delayedAction(() -> { - if (money <= 0) { - messageService.sendModMessage("Du hast kein Geld zum Einzahlen.", false); - return; - } - - commandService.sendCommand("bank einzahlen " + money); - messageService.sendModMessage("Nutze \"force\" bitte nur in Notfällen um zu vermeiden dass AMTs überfüllt werden und Geld dadurch \"verloren\" geht.", false); - }, COMMAND_COOLDOWN_MILLIS); - - return 1; - }) - ) - .executes(context -> { - commandService.sendCommand("stats"); - utilService.delayedAction(() -> commandService.sendCommandWithHiddenOutput("atminfo"), COMMAND_COOLDOWN_MILLIS); - - utilService.delayedAction(() -> { - if (money <= 0) { - messageService.sendModMessage("Du hast kein Geld zum Einzahlen.", false); - return; - } - - if (atmMoneyAvailable == 0) { - messageService.sendModMessage("Der ATM ist voll.", false); - messageService.sendModMessage("Nutze einen anderen ATM oder '/einzahlen force' um dennoch Geld in diesen ATM zu legen.", false); - } else if (atmMoneyAvailable > 0 && money > atmMoneyAvailable) { - commandService.sendCommand("bank einzahlen " + atmMoneyAvailable); - messageService.sendModMessage("Der ATM ist voll. Es wurden nur " + atmMoneyAvailable + "$ eingezahlt.", false); - messageService.sendModMessage("Nutze einen anderen ATM oder '/einzahlen force' um dennoch Geld in diesen ATM zu legen.", false); - } else { - commandService.sendCommand("bank einzahlen " + money); - } - }, COMMAND_COOLDOWN_MILLIS * 2); - - return 1; - }); - } - - @Override - public boolean onMessageReceive(Text text, String message) { - Matcher playerMoneyAmountMatcher = PLAYER_MONEY_AMOUNT_PATTERN.matcher(message); - if (playerMoneyAmountMatcher.find()) { - money = parseInt(playerMoneyAmountMatcher.group("moneyAmount")); - return true; - } - - Matcher atmMoneyAmountMatcher = ATM_MONEY_AMOUNT_PATTERN.matcher(message); - if (atmMoneyAmountMatcher.find()) { - int amountCurrent = parseInt(atmMoneyAmountMatcher.group("amountCurrent")); - int amountMax = parseInt(atmMoneyAmountMatcher.group("amountMax")); - atmMoneyAvailable = amountMax - amountCurrent; - return commandService.showCommandOutputMessage("atminfo"); - } - - return true; - } -} diff --git a/src/main/java/de/rettichlp/ucutils/common/Storage.java b/src/main/java/de/rettichlp/ucutils/common/Storage.java index 40ba14a8..a70ef756 100644 --- a/src/main/java/de/rettichlp/ucutils/common/Storage.java +++ b/src/main/java/de/rettichlp/ucutils/common/Storage.java @@ -96,10 +96,6 @@ public class Storage { @Setter private MinecartEntity minecartEntityToHighlight; - @Getter - @Setter - private int moneyAtmAmount = 0; - @Getter @Setter private boolean premium = false; @@ -161,8 +157,6 @@ public void print() { LOGGER.info("joinTimestamp: {}", this.joinTimestamp); // minecartEntityToHighlight LOGGER.info("minecartEntityToHighlight: {}", this.minecartEntityToHighlight); - // moneyAtmAmount - LOGGER.info("moneyAtmAmount: {}", this.moneyAtmAmount); // premium LOGGER.info("premium: {}", this.premium); // team diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/EconomyListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/EconomyListener.java index b8707dea..a4b5fb00 100644 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/EconomyListener.java +++ b/src/main/java/de/rettichlp/ucutils/listener/impl/EconomyListener.java @@ -58,7 +58,6 @@ public class EconomyListener implements IMessageReceiveListener { private static final Pattern PAYDAY_COUNTDOWN_PATTERN = compile("^Info: Du hast in 3 Minuten deinen PayDay$"); // other - private static final Pattern ATM_MONEY_AMOUNT_PATTERN = compile("ATM \\d+: (?\\d+)\\$/100000\\$"); private static final Pattern BUSINESS_CASH_PATTERN = compile("^Kasse: (\\d+)\\$$"); private static final Pattern EXP_PATTERN = compile("(?[+-]\\d+) Exp!( \\(x(?\\d)\\))?"); private static final Pattern LOTTO_WIN_PATTERN = compile("^\\[Lotto] Du hast im Lotto gewonnen! \\((?\\d+)\\$\\)$"); @@ -253,13 +252,6 @@ public boolean onMessageReceive(Text text, String message) { return true; } - Matcher moneyAtmAmountMatcher = ATM_MONEY_AMOUNT_PATTERN.matcher(message); - if (moneyAtmAmountMatcher.find()) { - int moneyAtmAmount = parseInt(moneyAtmAmountMatcher.group("moneyAtmAmount")); - storage.setMoneyAtmAmount(moneyAtmAmount); - return true; - } - Matcher businessCashMatcher = BUSINESS_CASH_PATTERN.matcher(message); if (businessCashMatcher.find()) { String amountString = businessCashMatcher.group(1); From 166d564744ee0d082a343015efa92cc512a7086a Mon Sep 17 00:00:00 2001 From: RettichLP Date: Fri, 22 May 2026 03:34:04 +0200 Subject: [PATCH 56/96] Remove `/einzahlen` command documentation from README --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 23715a79..bd00cfff 100644 --- a/README.md +++ b/README.md @@ -97,5 +97,4 @@ Folgende Funktionen sind nur für Spieler ohne Premium-Rang verfügbar, da Spiel | Befehl | Beschreibung | |------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `/einzahlen ()` | Zahlt das gesamte Bargeld in den ATM in der Nähe ein | | `/adropmoney` | Bucht für den Geldtransport-Job so viel Geld vom Konto ab, sodass das Geld vom Geldtransport-Job in den ATM eingezahlt werden kann und bucht das Geld anschließend zurück auf das Konto | From 0163c3914bc2bab5a08efa079bb87dee2ca7a574 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Fri, 22 May 2026 11:51:42 +0200 Subject: [PATCH 57/96] Remove `PlayerEnterVehicleCallback` and `IEnterVehicleListener`; refactor vehicle interaction logic in `EntityMixin` --- .../ucutils/common/registry/Registry.java | 4 --- .../listener/IEnterVehicleListener.java | 8 ------ .../callback/PlayerEnterVehicleCallback.java | 17 ------------ .../ucutils/listener/impl/CarListener.java | 27 +------------------ .../rettichlp/ucutils/mixin/EntityMixin.java | 18 ++++++++++--- 5 files changed, 16 insertions(+), 58 deletions(-) delete mode 100644 src/main/java/de/rettichlp/ucutils/listener/IEnterVehicleListener.java delete mode 100644 src/main/java/de/rettichlp/ucutils/listener/callback/PlayerEnterVehicleCallback.java diff --git a/src/main/java/de/rettichlp/ucutils/common/registry/Registry.java b/src/main/java/de/rettichlp/ucutils/common/registry/Registry.java index bf0ed2a0..97a3a502 100644 --- a/src/main/java/de/rettichlp/ucutils/common/registry/Registry.java +++ b/src/main/java/de/rettichlp/ucutils/common/registry/Registry.java @@ -4,7 +4,6 @@ import com.mojang.brigadier.builder.LiteralArgumentBuilder; import de.rettichlp.ucutils.common.models.Sound; import de.rettichlp.ucutils.listener.ICommandSendListener; -import de.rettichlp.ucutils.listener.IEnterVehicleListener; import de.rettichlp.ucutils.listener.IEntityRenderListener; import de.rettichlp.ucutils.listener.IHudRenderListener; import de.rettichlp.ucutils.listener.IMessageReceiveListener; @@ -14,7 +13,6 @@ import de.rettichlp.ucutils.listener.IScreenOpenListener; import de.rettichlp.ucutils.listener.ITickListener; import de.rettichlp.ucutils.listener.IUCUtilsListener; -import de.rettichlp.ucutils.listener.callback.PlayerEnterVehicleCallback; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents; @@ -139,8 +137,6 @@ public void registerListeners() { HudRenderCallback.EVENT.register((drawContext, tickCounter) -> getListenersImplementing(IHudRenderListener.class).forEach(iHudRenderListener -> iHudRenderListener.onHudRender(drawContext, tickCounter))); - PlayerEnterVehicleCallback.EVENT.register(vehicle -> getListenersImplementing(IEnterVehicleListener.class).forEach(iEnterVehicleListener -> iEnterVehicleListener.onEnterVehicle(vehicle))); - ScreenEvents.AFTER_INIT.register((client, screen, scaledWidth, scaledHeight) -> getListenersImplementing(IScreenOpenListener.class).forEach(iScreenOpenListener -> iScreenOpenListener.onScreenOpen(screen, scaledWidth, scaledHeight))); WorldRenderEvents.AFTER_ENTITIES.register(context -> getListenersImplementing(IEntityRenderListener.class).forEach(iEntityRenderListener -> iEntityRenderListener.onEntityRender(context))); diff --git a/src/main/java/de/rettichlp/ucutils/listener/IEnterVehicleListener.java b/src/main/java/de/rettichlp/ucutils/listener/IEnterVehicleListener.java deleted file mode 100644 index 70e82649..00000000 --- a/src/main/java/de/rettichlp/ucutils/listener/IEnterVehicleListener.java +++ /dev/null @@ -1,8 +0,0 @@ -package de.rettichlp.ucutils.listener; - -import net.minecraft.entity.Entity; - -public interface IEnterVehicleListener extends IUCUtilsListener { - - void onEnterVehicle(Entity vehicle); -} diff --git a/src/main/java/de/rettichlp/ucutils/listener/callback/PlayerEnterVehicleCallback.java b/src/main/java/de/rettichlp/ucutils/listener/callback/PlayerEnterVehicleCallback.java deleted file mode 100644 index 5978084d..00000000 --- a/src/main/java/de/rettichlp/ucutils/listener/callback/PlayerEnterVehicleCallback.java +++ /dev/null @@ -1,17 +0,0 @@ -package de.rettichlp.ucutils.listener.callback; - -import net.fabricmc.fabric.api.event.Event; -import net.minecraft.entity.Entity; - -import static net.fabricmc.fabric.api.event.EventFactory.createArrayBacked; - -public interface PlayerEnterVehicleCallback { - - Event EVENT = createArrayBacked(PlayerEnterVehicleCallback.class, listeners -> vehicle -> { - for (PlayerEnterVehicleCallback listener : listeners) { - listener.onEnter(vehicle); - } - }); - - void onEnter(Entity vehicle); -} diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/CarListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/CarListener.java index e1ca94f3..07ff5f52 100644 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/CarListener.java +++ b/src/main/java/de/rettichlp/ucutils/listener/impl/CarListener.java @@ -1,7 +1,6 @@ package de.rettichlp.ucutils.listener.impl; import de.rettichlp.ucutils.common.registry.UCUtilsListener; -import de.rettichlp.ucutils.listener.IEnterVehicleListener; import de.rettichlp.ucutils.listener.IEntityRenderListener; import de.rettichlp.ucutils.listener.IMessageReceiveListener; import de.rettichlp.ucutils.listener.IScreenOpenListener; @@ -13,8 +12,6 @@ import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.world.ClientWorld; -import net.minecraft.entity.Entity; -import net.minecraft.entity.vehicle.MinecartEntity; import net.minecraft.text.Text; import java.util.regex.Matcher; @@ -26,7 +23,6 @@ import static de.rettichlp.ucutils.UCUtils.player; import static de.rettichlp.ucutils.UCUtils.renderService; import static de.rettichlp.ucutils.UCUtils.storage; -import static de.rettichlp.ucutils.UCUtils.utilService; import static java.lang.Integer.parseInt; import static java.util.Objects.nonNull; import static java.util.Optional.ofNullable; @@ -35,34 +31,13 @@ import static net.minecraft.util.Formatting.AQUA; @UCUtilsListener -public class CarListener - implements IEnterVehicleListener, IEntityRenderListener, IMessageReceiveListener, IScreenOpenListener { +public class CarListener implements IEntityRenderListener, IMessageReceiveListener, IScreenOpenListener { private static final Pattern CAR_UNLOCK_PATTERN = compile("^\\[Car] Du hast deinen .+ aufgeschlossen\\.$"); private static final Pattern CAR_LOCK_PATTERN = compile("^\\[Car] Du hast deinen .+ abgeschlossen\\.$"); private static final Pattern CAR_LOCKED_OWN_PATTERN = compile("^\\[Car] Dein Fahrzeug ist abgeschlossen\\.$"); private static final Pattern CAR_FIND_PATTERN = compile("^\\[Car] Das Fahrzeug befindet sich bei » X: (?-?\\d+) \\| Y: (?-?\\d+) \\| Z: (?-?\\d+)$"); - @Override - public void onEnterVehicle(Entity vehicle) { - // the entity is a car - if (!(vehicle instanceof MinecartEntity)) { - return; - } - - storage.setMinecartEntityToHighlight(null); - - if (configuration.getOptions().car().automatedStart() && !storage.isPremium()) { - // start the car with a small delay to ensure the player is fully in the vehicle - utilService.delayedAction(() -> commandService.sendCommand("car start"), 500); - } - - // lock the car after 1 second and the small delay if not already locked - if (!storage.isCarLocked() && configuration.getOptions().car().automatedLock() && !storage.isPremium()) { - utilService.delayedAction(() -> commandService.sendCommand("car lock"), 1500); - } - } - @Override public void onEntityRender(WorldRenderContext context) { MatrixStack matrices = context.matrices(); diff --git a/src/main/java/de/rettichlp/ucutils/mixin/EntityMixin.java b/src/main/java/de/rettichlp/ucutils/mixin/EntityMixin.java index f0465a80..3944e797 100644 --- a/src/main/java/de/rettichlp/ucutils/mixin/EntityMixin.java +++ b/src/main/java/de/rettichlp/ucutils/mixin/EntityMixin.java @@ -2,7 +2,6 @@ import de.rettichlp.ucutils.common.models.Faction; import de.rettichlp.ucutils.common.models.WantedEntry; -import de.rettichlp.ucutils.listener.callback.PlayerEnterVehicleCallback; import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.entity.Entity; import net.minecraft.entity.ItemEntity; @@ -22,9 +21,12 @@ import java.util.Optional; +import static de.rettichlp.ucutils.UCUtils.commandService; +import static de.rettichlp.ucutils.UCUtils.configuration; import static de.rettichlp.ucutils.UCUtils.nameTagService; import static de.rettichlp.ucutils.UCUtils.player; import static de.rettichlp.ucutils.UCUtils.storage; +import static de.rettichlp.ucutils.UCUtils.utilService; import static de.rettichlp.ucutils.common.models.Color.WHITE; import static net.minecraft.item.Items.SKELETON_SKULL; import static net.minecraft.item.Items.WITHER_SKELETON_SKULL; @@ -50,8 +52,18 @@ public abstract class EntityMixin { } UniquelyIdentifiable self = (Entity) (Object) this; - if (self.getUuid().equals(player.getUuid())) { - PlayerEnterVehicleCallback.EVENT.invoker().onEnter(vehicle); + if (self.getUuid().equals(player.getUuid()) && vehicle instanceof MinecartEntity) { + storage.setMinecartEntityToHighlight(null); + + if (configuration.getOptions().car().automatedStart() && !storage.isPremium()) { + // start the car with a small delay to ensure the player is fully in the vehicle + utilService.delayedAction(() -> commandService.sendCommand("car start"), 500); + } + + // lock the car after 1 second and the small delay if not already locked + if (!storage.isCarLocked() && configuration.getOptions().car().automatedLock() && !storage.isPremium()) { + utilService.delayedAction(() -> commandService.sendCommand("car lock"), 1500); + } } } From 3a3fd7193e9a9cea5141999476716ece833c3a84 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Fri, 22 May 2026 14:24:31 +0200 Subject: [PATCH 58/96] Remove `KarmaListener` and enriched karma handling logic --- .../common/configuration/options/Options.java | 1 - .../screens/options/MainOptionsScreen.java | 5 -- .../ucutils/listener/impl/KarmaListener.java | 86 ------------------- .../resources/assets/ucutils/lang/de_de.json | 2 - .../resources/assets/ucutils/lang/en_gb.json | 2 - .../resources/assets/ucutils/lang/en_us.json | 2 - 6 files changed, 98 deletions(-) delete mode 100644 src/main/java/de/rettichlp/ucutils/listener/impl/KarmaListener.java diff --git a/src/main/java/de/rettichlp/ucutils/common/configuration/options/Options.java b/src/main/java/de/rettichlp/ucutils/common/configuration/options/Options.java index d21e7031..ee6ebefb 100644 --- a/src/main/java/de/rettichlp/ucutils/common/configuration/options/Options.java +++ b/src/main/java/de/rettichlp/ucutils/common/configuration/options/Options.java @@ -35,7 +35,6 @@ public class Options { private AtmInformationType atmInformationType = NONE; private boolean showHydration = true; private boolean checkUnicacityServer = true; - private boolean showEnrichedKarma = true; private boolean changeFactionChatColor = false; private Color factionChatColorPrimary = Color.BLUE; private Color factionChatColorSecondary = Color.DARK_AQUA; diff --git a/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/MainOptionsScreen.java b/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/MainOptionsScreen.java index d98dab10..7f130f36 100644 --- a/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/MainOptionsScreen.java +++ b/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/MainOptionsScreen.java @@ -25,8 +25,6 @@ public class MainOptionsScreen extends OptionsScreen { private static final Text HYDRATION_NAME = translatable("ucutils.options.hydration.name"); private static final Text HYDRATION_TOOLTIP = translatable("ucutils.options.hydration.tooltip"); private static final Text BANK_INFORMATION_NAME = translatable("ucutils.options.atm_information.name"); - private static final Text ENRICHED_KARMA_NAME = translatable("ucutils.options.enriched_karma.name"); - private static final Text ENRICHED_KARMA_TOOLTIP = translatable("ucutils.options.enriched_karma.tooltip"); public MainOptionsScreen() { super(new GameMenuScreen(true)); @@ -55,9 +53,6 @@ public void initBody() { renderService.addToggleButton(directionalLayoutWidget4, HYDRATION_NAME, HYDRATION_TOOLTIP, Options::showHydration, Options::showHydration, 150); renderService.addCyclingButton(directionalLayoutWidget4, BANK_INFORMATION_NAME, Options.AtmInformationType.values(), Options.AtmInformationType::getDisplayName, Options::atmInformationType, Options::atmInformationType, 150); - DirectionalLayoutWidget directionalLayoutWidget5 = directionalLayoutWidget.add(horizontal().spacing(8)); - renderService.addToggleButton(directionalLayoutWidget5, ENRICHED_KARMA_NAME, ENRICHED_KARMA_TOOLTIP, Options::showEnrichedKarma, Options::showEnrichedKarma, 150); - directionalLayoutWidget.forEachChild(this::addDrawableChild); } } diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/KarmaListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/KarmaListener.java deleted file mode 100644 index 2d47f376..00000000 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/KarmaListener.java +++ /dev/null @@ -1,86 +0,0 @@ -package de.rettichlp.ucutils.listener.impl; - -import de.rettichlp.ucutils.common.registry.UCUtilsListener; -import de.rettichlp.ucutils.listener.IMessageReceiveListener; -import net.minecraft.text.MutableText; -import net.minecraft.text.Text; - -import java.time.LocalTime; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import static de.rettichlp.ucutils.UCUtils.commandService; -import static de.rettichlp.ucutils.UCUtils.configuration; -import static de.rettichlp.ucutils.UCUtils.player; -import static de.rettichlp.ucutils.common.services.MessageService.TIME_FORMAT; -import static java.lang.Integer.parseInt; -import static java.lang.String.valueOf; -import static java.time.LocalTime.now; -import static java.util.regex.Pattern.compile; -import static net.minecraft.text.Text.empty; -import static net.minecraft.text.Text.literal; -import static net.minecraft.util.Formatting.AQUA; -import static net.minecraft.util.Formatting.BLUE; -import static net.minecraft.util.Formatting.DARK_GRAY; - -@UCUtilsListener -public class KarmaListener implements IMessageReceiveListener { - - private static final Pattern KARMA_CHANGED_PATTERN = compile("^\\[Karma] (?[+-]\\d+) Karma\\.$"); - private static final Pattern KARMA_PATTERN = compile("^\\[Karma] Du hast ein Karma von (?[+-]\\d+)\\.$"); - - private int lastKarmaChange = 0; - - @Override - public boolean onMessageReceive(Text text, String message) { - Matcher karmaChangedMatcher = KARMA_CHANGED_PATTERN.matcher(message); - if (karmaChangedMatcher.find()) { - boolean showEnrichedKarma = configuration.getOptions().showEnrichedKarma(); - if (!showEnrichedKarma) { - return true; - } - - // show enriched karma message - this.lastKarmaChange = parseInt(karmaChangedMatcher.group("amount")); - commandService.sendCommandWithAfkCheck("karma"); - return false; - } - - Matcher karmaMatcher = KARMA_PATTERN.matcher(message); - if (karmaMatcher.find()) { - // show default message if no karma was changed - if (this.lastKarmaChange == 0) { - return true; - } - - int currentKarma = parseInt(karmaMatcher.group("amount")); - - MutableText enrichedKarmaMessage = empty() - .append(literal("[").formatted(DARK_GRAY)) - .append(literal("Karma").formatted(BLUE)) - .append(literal("] ").formatted(DARK_GRAY)) - .append(literal((this.lastKarmaChange > 0 ? "+" : "") + this.lastKarmaChange + " ").formatted(AQUA)) - .append(literal("Karma ").formatted(AQUA)) - .append(literal("(").formatted(DARK_GRAY)) - .append(literal(valueOf(currentKarma)).formatted(AQUA)) - .append(literal("/").formatted(DARK_GRAY)) - .append(literal("100").formatted(AQUA)) - .append(literal(")").formatted(DARK_GRAY)); - - // add despawn time if available - if (this.lastKarmaChange < 0) { - LocalTime despawnTime = now().plusMinutes(5); - enrichedKarmaMessage - .append(literal(" (").formatted(DARK_GRAY)) - .append(literal(TIME_FORMAT.format(despawnTime)).formatted(AQUA)) - .append(literal(")").formatted(DARK_GRAY)); - } - - player.sendMessage(enrichedKarmaMessage, false); - this.lastKarmaChange = 0; - return false; - } - - return true; - } -} \ No newline at end of file diff --git a/src/main/resources/assets/ucutils/lang/de_de.json b/src/main/resources/assets/ucutils/lang/de_de.json index c298f585..bce2ae80 100644 --- a/src/main/resources/assets/ucutils/lang/de_de.json +++ b/src/main/resources/assets/ucutils/lang/de_de.json @@ -85,8 +85,6 @@ "ucutils.options.hydration.tooltip": "Zeigt deinen Durst über der Hungeranzeige an", "ucutils.options.check_unicacity_server.name": "UnicaCity Check", "ucutils.options.check_unicacity_server.tooltip": "Überprüft ob du auf UnicaCity spielst. Wenn aktiviert sind bestimmte Funktionen nur auf UnicaCity aktiviert um Probleme mit anderen Servern zu vermeiden.", - "ucutils.options.enriched_karma.name": "Erweiterte Karma Nachricht", - "ucutils.options.enriched_karma.tooltip": "Zeigt zusätzliche Informationen in der Karma Nachricht an, wie die Gesamt-Karma-Menge oder die Zeit wenn ein Spieler despawnen sollte bei einem Kill", "ucutils.options.faction_chat_color.name": "Farbe des Fraktionschats", "ucutils.options.faction_chat_color.tooltip": "Ändert die Farbe des Fraktionschats", "ucutils.options.faction_chat_color_primary.name": "Primäre Farbe des Fraktionschats", diff --git a/src/main/resources/assets/ucutils/lang/en_gb.json b/src/main/resources/assets/ucutils/lang/en_gb.json index 1675e91d..66110ad5 100644 --- a/src/main/resources/assets/ucutils/lang/en_gb.json +++ b/src/main/resources/assets/ucutils/lang/en_gb.json @@ -85,8 +85,6 @@ "ucutils.options.hydration.tooltip": "Displays your hydration above your hunger bar", "ucutils.options.check_unicacity_server.name": "Check for UnicaCity", "ucutils.options.check_unicacity_server.tooltip": "Checks if you are playing on the UnicaCity server. If enabled, certain features will only be available on the UnicaCity server to prevent issues on other servers.", - "ucutils.options.enriched_karma.name": "Enriched karma message", - "ucutils.options.enriched_karma.tooltip": "Populates the karma message with additional information such as the current overall karma amount and the time until a player despawns in case of a kill", "ucutils.options.faction_chat_color.name": "Faction chat color", "ucutils.options.faction_chat_color.tooltip": "Changes the color of the faction chat", "ucutils.options.faction_chat_color_primary.name": "Faction chat primary color", diff --git a/src/main/resources/assets/ucutils/lang/en_us.json b/src/main/resources/assets/ucutils/lang/en_us.json index 1675e91d..66110ad5 100644 --- a/src/main/resources/assets/ucutils/lang/en_us.json +++ b/src/main/resources/assets/ucutils/lang/en_us.json @@ -85,8 +85,6 @@ "ucutils.options.hydration.tooltip": "Displays your hydration above your hunger bar", "ucutils.options.check_unicacity_server.name": "Check for UnicaCity", "ucutils.options.check_unicacity_server.tooltip": "Checks if you are playing on the UnicaCity server. If enabled, certain features will only be available on the UnicaCity server to prevent issues on other servers.", - "ucutils.options.enriched_karma.name": "Enriched karma message", - "ucutils.options.enriched_karma.tooltip": "Populates the karma message with additional information such as the current overall karma amount and the time until a player despawns in case of a kill", "ucutils.options.faction_chat_color.name": "Faction chat color", "ucutils.options.faction_chat_color.tooltip": "Changes the color of the faction chat", "ucutils.options.faction_chat_color_primary.name": "Faction chat primary color", From 8babfe48524d068ce772c164813cca164bdc859a Mon Sep 17 00:00:00 2001 From: RettichLP Date: Fri, 22 May 2026 14:33:42 +0200 Subject: [PATCH 59/96] Remove karma display details from README documentation --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index c01fa826..b77dc79d 100644 --- a/README.md +++ b/README.md @@ -17,8 +17,6 @@ reibungsloser und angenehmer gestalten. - Über der Hungerleiste wird der Durst angezeigt - Über den Spielernamen wird AFK angezeigt, wenn der Spieler AFK ist - Für Teammitglieder wird eine Warnung angezeigt, wenn sie sich im Admindienst befinden und eine Waffe in der Hand haben -- Hinter der Nachricht, dass sich das Karma geändert hat, wird angezeigt, wie viel Karma man insgesamt besitzt und wann ein Spieler - despawnen sollte (falls das Karma durch einen Kill geändert wurde) - Bei der Mieterübersicht wird angezeigt wie lang ein Mieter offline ist und ein Button um diesen zu kündigen - Beim Beten wird nach 15 Sekunden automatisch der zweite Befehl ausgeführt - Es gibt Benachrichtigungen, wenn ein Spieler den Server betritt oder verlässt, einen Report betritt oder verlässt, den Baumodus @@ -74,7 +72,6 @@ Folgende Funktionen sind nur für Spieler ohne Premium-Rang verfügbar, da Spiel | `/ucutils ()` | Zeigt nützliche Status-Informationen über das Projekt an oder startet eine Synchronisierung | | `/screenshot` | Erstellt einen Screenshot in einer bestimmten Kategorie | | `/shutdown ` | Aktiviert das automatische Herunterfahren des PCs nachdem man nicht mehr auf dem Friedhof oder im Gefängnis ist | -| `/selldrugall` `/sda` | Verkauft alle illegalen Drogen für 0$ an den angegebenen Spieler (Pulver, Kräuter, Kristalle und Wundertüten) | **Chat** From ebebc07fad846f4ea0850cf0975367d8b522c794 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Fri, 22 May 2026 18:15:31 +0200 Subject: [PATCH 60/96] Reintroduce black market and dealer tracking logic via ClientPlayNetworkHandlerMixin --- .../de/rettichlp/ucutils/common/Storage.java | 9 ++++ .../mixin/ClientPlayNetworkHandlerMixin.java | 52 +++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/src/main/java/de/rettichlp/ucutils/common/Storage.java b/src/main/java/de/rettichlp/ucutils/common/Storage.java index 40ba14a8..e2ec055a 100644 --- a/src/main/java/de/rettichlp/ucutils/common/Storage.java +++ b/src/main/java/de/rettichlp/ucutils/common/Storage.java @@ -15,6 +15,7 @@ import lombok.Setter; import net.minecraft.entity.vehicle.MinecartEntity; import net.minecraft.text.Text; +import net.minecraft.util.math.Vec3d; import org.jetbrains.annotations.Nullable; import java.time.LocalDateTime; @@ -67,6 +68,10 @@ public class Storage { @Setter private int activeServices = 0; + @Getter + @Setter + private Vec3d blackMarketPosition; + @Getter @Setter private boolean carLocked = true; @@ -80,6 +85,10 @@ public class Storage { @Setter private boolean dead = false; + @Getter + @Setter + private Vec3d dealerPosition; + @Getter @Setter private String fBankDepositReason = ""; diff --git a/src/main/java/de/rettichlp/ucutils/mixin/ClientPlayNetworkHandlerMixin.java b/src/main/java/de/rettichlp/ucutils/mixin/ClientPlayNetworkHandlerMixin.java index 9189ede6..22bb7fd7 100644 --- a/src/main/java/de/rettichlp/ucutils/mixin/ClientPlayNetworkHandlerMixin.java +++ b/src/main/java/de/rettichlp/ucutils/mixin/ClientPlayNetworkHandlerMixin.java @@ -4,12 +4,18 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.NonNull; +import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientPlayNetworkHandler; import net.minecraft.client.network.PlayerListEntry; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.entity.Entity; +import net.minecraft.entity.passive.VillagerEntity; +import net.minecraft.network.packet.s2c.play.EntityTrackerUpdateS2CPacket; import net.minecraft.network.packet.s2c.play.PlayerListS2CPacket; import net.minecraft.network.packet.s2c.play.PlayerRemoveS2CPacket; import net.minecraft.text.MutableText; import net.minecraft.text.Text; +import net.minecraft.util.math.Vec3d; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; @@ -22,15 +28,21 @@ import static de.rettichlp.ucutils.UCUtils.configuration; import static de.rettichlp.ucutils.UCUtils.notificationService; +import static de.rettichlp.ucutils.UCUtils.player; import static de.rettichlp.ucutils.UCUtils.storage; import static java.awt.Color.WHITE; import static java.lang.System.currentTimeMillis; +import static java.util.Objects.requireNonNull; import static net.minecraft.text.Text.empty; import static net.minecraft.text.Text.literal; import static net.minecraft.text.Text.translatable; import static net.minecraft.util.Formatting.BLUE; +import static net.minecraft.util.Formatting.BOLD; import static net.minecraft.util.Formatting.DARK_GRAY; +import static net.minecraft.util.Formatting.DARK_RED; import static net.minecraft.util.Formatting.GOLD; +import static net.minecraft.util.Formatting.GRAY; +import static net.minecraft.util.Formatting.RED; import static net.minecraft.util.Formatting.YELLOW; import static org.spongepowered.asm.mixin.injection.At.Shift.AFTER; @@ -58,6 +70,46 @@ public abstract class ClientPlayNetworkHandlerMixin { @Unique private final Collection enrichedGameProfiles = new HashSet<>(); + @Inject(method = "onEntityTrackerUpdate", at = @At("TAIL")) + private void onEntityTrackerUpdate(EntityTrackerUpdateS2CPacket packet, CallbackInfo ci) { + if (!storage.isUnicaCity()) { + return; + } + + ClientWorld world = MinecraftClient.getInstance().world; + if (world == null) { + return; + } + + Entity entity = world.getEntityById(packet.id()); + if (!(entity instanceof VillagerEntity villager) || !villager.hasCustomName()) { + return; + } + + String customNameString = requireNonNull(villager.getCustomName()).getString(); + Vec3d entityPos = villager.getEntityPos(); + switch (customNameString) { + case "Dealer" -> { + storage.setBlackMarketPosition(entityPos); + player.sendMessage(empty() + .append(literal("[").formatted(DARK_GRAY)) + .append(literal("Dealer").formatted(RED)) + .append(literal("] ").formatted(DARK_GRAY)) + .append(literal("Der Dealer ist in der Nähe ").formatted(GRAY)) + .append(literal("⯐").formatted(DARK_RED, BOLD)), false); + } + case "Schwarzmarkt" -> { + storage.setDealerPosition(entityPos); + player.sendMessage(empty() + .append(literal("[").formatted(DARK_GRAY)) + .append(literal("Schwarzmarkt").formatted(RED)) + .append(literal("] ").formatted(DARK_GRAY)) + .append(literal("Der Schwarzmarkt ist in der Nähe ").formatted(GRAY)) + .append(literal("⯐").formatted(DARK_RED, BOLD)), false); + } + } + } + @Inject(method = "onPlayerRemove", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/NetworkThreadUtils;forceMainThread(Lnet/minecraft/network/packet/Packet;Lnet/minecraft/network/listener/PacketListener;Lnet/minecraft/network/PacketApplyBatcher;)V", From 3569635878518d613ecfecaa6efb637a2c51c093 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Fri, 22 May 2026 18:19:19 +0200 Subject: [PATCH 61/96] Simplify dealer and black market proximity messages by removing icons and bold formatting --- .../ucutils/mixin/ClientPlayNetworkHandlerMixin.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/java/de/rettichlp/ucutils/mixin/ClientPlayNetworkHandlerMixin.java b/src/main/java/de/rettichlp/ucutils/mixin/ClientPlayNetworkHandlerMixin.java index 22bb7fd7..e1c06d32 100644 --- a/src/main/java/de/rettichlp/ucutils/mixin/ClientPlayNetworkHandlerMixin.java +++ b/src/main/java/de/rettichlp/ucutils/mixin/ClientPlayNetworkHandlerMixin.java @@ -37,9 +37,7 @@ import static net.minecraft.text.Text.literal; import static net.minecraft.text.Text.translatable; import static net.minecraft.util.Formatting.BLUE; -import static net.minecraft.util.Formatting.BOLD; import static net.minecraft.util.Formatting.DARK_GRAY; -import static net.minecraft.util.Formatting.DARK_RED; import static net.minecraft.util.Formatting.GOLD; import static net.minecraft.util.Formatting.GRAY; import static net.minecraft.util.Formatting.RED; @@ -95,8 +93,7 @@ private void onEntityTrackerUpdate(EntityTrackerUpdateS2CPacket packet, Callback .append(literal("[").formatted(DARK_GRAY)) .append(literal("Dealer").formatted(RED)) .append(literal("] ").formatted(DARK_GRAY)) - .append(literal("Der Dealer ist in der Nähe ").formatted(GRAY)) - .append(literal("⯐").formatted(DARK_RED, BOLD)), false); + .append(literal("Der Dealer ist in der Nähe!").formatted(GRAY)), false); } case "Schwarzmarkt" -> { storage.setDealerPosition(entityPos); @@ -104,8 +101,7 @@ private void onEntityTrackerUpdate(EntityTrackerUpdateS2CPacket packet, Callback .append(literal("[").formatted(DARK_GRAY)) .append(literal("Schwarzmarkt").formatted(RED)) .append(literal("] ").formatted(DARK_GRAY)) - .append(literal("Der Schwarzmarkt ist in der Nähe ").formatted(GRAY)) - .append(literal("⯐").formatted(DARK_RED, BOLD)), false); + .append(literal("Der Schwarzmarkt ist in der Nähe!").formatted(GRAY)), false); } } } From daa4612971c8b02346dbbbf5f6a7313805164e46 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Fri, 22 May 2026 19:47:06 +0200 Subject: [PATCH 62/96] Remove BlackMarket and Dealer commands and models --- .../{faction => }/ScreenshotCommand.java | 2 +- .../command/faction/BlackMarketCommand.java | 36 ------- .../command/faction/DealerCommand.java | 36 ------- .../de/rettichlp/ucutils/common/Storage.java | 29 ++---- .../ucutils/common/models/BlackMarket.java | 97 ------------------- .../ucutils/common/models/Dealer.java | 95 ------------------ 6 files changed, 7 insertions(+), 288 deletions(-) rename src/main/java/de/rettichlp/ucutils/command/{faction => }/ScreenshotCommand.java (98%) delete mode 100644 src/main/java/de/rettichlp/ucutils/command/faction/BlackMarketCommand.java delete mode 100644 src/main/java/de/rettichlp/ucutils/command/faction/DealerCommand.java delete mode 100644 src/main/java/de/rettichlp/ucutils/common/models/BlackMarket.java delete mode 100644 src/main/java/de/rettichlp/ucutils/common/models/Dealer.java diff --git a/src/main/java/de/rettichlp/ucutils/command/faction/ScreenshotCommand.java b/src/main/java/de/rettichlp/ucutils/command/ScreenshotCommand.java similarity index 98% rename from src/main/java/de/rettichlp/ucutils/command/faction/ScreenshotCommand.java rename to src/main/java/de/rettichlp/ucutils/command/ScreenshotCommand.java index c21598a2..c67eabfa 100644 --- a/src/main/java/de/rettichlp/ucutils/command/faction/ScreenshotCommand.java +++ b/src/main/java/de/rettichlp/ucutils/command/ScreenshotCommand.java @@ -1,4 +1,4 @@ -package de.rettichlp.ucutils.command.faction; +package de.rettichlp.ucutils.command; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import de.rettichlp.ucutils.common.models.ScreenshotType; diff --git a/src/main/java/de/rettichlp/ucutils/command/faction/BlackMarketCommand.java b/src/main/java/de/rettichlp/ucutils/command/faction/BlackMarketCommand.java deleted file mode 100644 index 5e2d19d9..00000000 --- a/src/main/java/de/rettichlp/ucutils/command/faction/BlackMarketCommand.java +++ /dev/null @@ -1,36 +0,0 @@ -package de.rettichlp.ucutils.command.faction; - -import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import de.rettichlp.ucutils.common.registry.CommandBase; -import de.rettichlp.ucutils.common.registry.UCUtilsCommand; -import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; -import org.jetbrains.annotations.NotNull; - -import static de.rettichlp.ucutils.UCUtils.commandService; -import static de.rettichlp.ucutils.UCUtils.messageService; -import static de.rettichlp.ucutils.UCUtils.player; -import static de.rettichlp.ucutils.UCUtils.storage; -import static java.util.Comparator.comparingDouble; -import static net.minecraft.text.Text.empty; - -@UCUtilsCommand(label = "blackmarket", aliases = "schwarzmarkt") -public class BlackMarketCommand extends CommandBase { - - @Override - public LiteralArgumentBuilder execute(@NotNull LiteralArgumentBuilder node) { - return node - .requires(fabricClientCommandSource -> storage.getFaction(player.getStringifiedName()).isBadFaction() || commandService.isSuperUser()) - .executes(context -> { - player.sendMessage(empty(), false); - - messageService.sendModMessage("Schwarzmarkt Orte:", false); - storage.getBlackMarkets().stream() - .sorted(comparingDouble(value -> value.getType().getBlockPos().getSquaredDistance(player.getBlockPos()))) - .forEach(blackMarket -> messageService.sendModMessage(blackMarket.getText(), false)); - - player.sendMessage(empty(), false); - - return 1; - }); - } -} diff --git a/src/main/java/de/rettichlp/ucutils/command/faction/DealerCommand.java b/src/main/java/de/rettichlp/ucutils/command/faction/DealerCommand.java deleted file mode 100644 index bb351d9e..00000000 --- a/src/main/java/de/rettichlp/ucutils/command/faction/DealerCommand.java +++ /dev/null @@ -1,36 +0,0 @@ -package de.rettichlp.ucutils.command.faction; - -import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import de.rettichlp.ucutils.common.registry.CommandBase; -import de.rettichlp.ucutils.common.registry.UCUtilsCommand; -import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; -import org.jetbrains.annotations.NotNull; - -import static de.rettichlp.ucutils.UCUtils.commandService; -import static de.rettichlp.ucutils.UCUtils.messageService; -import static de.rettichlp.ucutils.UCUtils.player; -import static de.rettichlp.ucutils.UCUtils.storage; -import static java.util.Comparator.comparingDouble; -import static net.minecraft.text.Text.empty; - -@UCUtilsCommand(label = "dealer") -public class DealerCommand extends CommandBase { - - @Override - public LiteralArgumentBuilder execute(@NotNull LiteralArgumentBuilder node) { - return node - .requires(fabricClientCommandSource -> storage.getFaction(player.getStringifiedName()).isBadFaction() || commandService.isSuperUser()) - .executes(context -> { - player.sendMessage(empty(), false); - - messageService.sendModMessage("Dealer Orte:", false); - storage.getDealers().stream() - .sorted(comparingDouble(value -> value.getType().getBlockPos().getSquaredDistance(player.getBlockPos()))) - .forEach(dealer -> messageService.sendModMessage(dealer.getText(), false)); - - player.sendMessage(empty(), false); - - return 1; - }); - } -} diff --git a/src/main/java/de/rettichlp/ucutils/common/Storage.java b/src/main/java/de/rettichlp/ucutils/common/Storage.java index e2ec055a..d2b5c5b1 100644 --- a/src/main/java/de/rettichlp/ucutils/common/Storage.java +++ b/src/main/java/de/rettichlp/ucutils/common/Storage.java @@ -1,8 +1,6 @@ package de.rettichlp.ucutils.common; -import de.rettichlp.ucutils.common.models.BlackMarket; import de.rettichlp.ucutils.common.models.Countdown; -import de.rettichlp.ucutils.common.models.Dealer; import de.rettichlp.ucutils.common.models.Faction; import de.rettichlp.ucutils.common.models.FactionEntry; import de.rettichlp.ucutils.common.models.FactionMember; @@ -31,7 +29,6 @@ import static de.rettichlp.ucutils.UCUtils.storage; import static de.rettichlp.ucutils.common.Storage.ToggledChat.NONE; import static de.rettichlp.ucutils.common.models.Faction.NULL; -import static java.util.Arrays.stream; import static java.util.Optional.ofNullable; import static net.minecraft.text.Text.translatable; @@ -40,15 +37,9 @@ public class Storage { @Getter private final List activeShutdowns = new ArrayList<>(); - @Getter - private final List blackMarkets = new ArrayList<>(); - @Getter private final List countdowns = new ArrayList<>(); - @Getter - private final List dealers = new ArrayList<>(); - @Getter private final Set factionEntries = new HashSet<>(); @@ -70,6 +61,7 @@ public class Storage { @Getter @Setter + @Nullable private Vec3d blackMarketPosition; @Getter @@ -87,6 +79,7 @@ public class Storage { @Getter @Setter + @Nullable private Vec3d dealerPosition; @Getter @@ -125,25 +118,15 @@ public class Storage { @Setter private boolean unicaCity = false; - { - this.blackMarkets.addAll(stream(BlackMarket.Type.values()) - .map(type -> new BlackMarket(type, null, false)) - .toList()); - - this.dealers.addAll(stream(Dealer.Type.values()) - .map(type -> new Dealer(type, null, false)) - .toList()); - } - public void print() { //activeShutdowns LOGGER.info("activeShutdowns[{}]: {}", this.activeShutdowns.size(), this.activeShutdowns); - // blackMarkets - LOGGER.info("blackMarkets[{}]: {}", this.blackMarkets.size(), this.blackMarkets); + // blackMarketPosition + LOGGER.info("blackMarketPosition: {}", this.blackMarketPosition); // countdowns LOGGER.info("countdowns[{}]: {}", this.countdowns.size(), this.countdowns); - // dealers - LOGGER.info("dealers[{}]: {}", this.dealers.size(), this.dealers); + // dealerPosition + LOGGER.info("dealerPosition: {}", this.dealerPosition); // factionEntries this.factionEntries.forEach(factionEntry -> LOGGER.info("factionEntries[{}:{}]: {}", factionEntry.faction(), factionEntry.members().size(), factionEntry.members())); // medicBandageCooldowns diff --git a/src/main/java/de/rettichlp/ucutils/common/models/BlackMarket.java b/src/main/java/de/rettichlp/ucutils/common/models/BlackMarket.java deleted file mode 100644 index 38907fe7..00000000 --- a/src/main/java/de/rettichlp/ucutils/common/models/BlackMarket.java +++ /dev/null @@ -1,97 +0,0 @@ -package de.rettichlp.ucutils.common.models; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import net.minecraft.text.ClickEvent; -import net.minecraft.text.HoverEvent; -import net.minecraft.text.Text; -import net.minecraft.util.math.BlockPos; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.time.Duration; -import java.time.LocalDateTime; - -import static java.time.LocalDateTime.now; -import static java.util.Objects.isNull; -import static net.minecraft.text.Text.empty; -import static net.minecraft.text.Text.of; -import static net.minecraft.util.Formatting.DARK_GRAY; -import static net.minecraft.util.Formatting.DARK_GREEN; -import static net.minecraft.util.Formatting.GOLD; -import static net.minecraft.util.Formatting.GRAY; -import static net.minecraft.util.Formatting.GREEN; -import static net.minecraft.util.Formatting.RED; -import static net.minecraft.util.Formatting.YELLOW; - -@Getter -@AllArgsConstructor -public class BlackMarket { - - private final Type type; - @Nullable - private final LocalDateTime visitedAt; - private boolean found; // whether the black market was found or not - - public Text getText() { - return empty() - .styled(style -> style - .withHoverEvent(new HoverEvent.ShowText(of("Klicke, um die Navigation zu starten").copy().formatted(GOLD))) - .withClickEvent(new ClickEvent.RunCommand(this.type.getNavigationCommand()))) - .append(of(this.type.getDisplayName())).append(" ") - .append(of("(").copy().formatted(DARK_GRAY)) - .append(of("Besucht:").copy().formatted(GRAY)).append(" ") - .append(getLastVisitedText()) - .append(of(")").copy().formatted(DARK_GRAY)) - .append(this.found ? of(" ←").copy().formatted(GREEN) : empty()); - } - - private Text getLastVisitedText() { - if (isNull(this.visitedAt)) { - return of("Nie").copy().formatted(GRAY); - } - - Duration duration = Duration.between(this.visitedAt, now()); - long minutes = duration.toMinutes(); - - if (minutes >= 60) { - return of("vor über einer Stunde").copy().formatted(RED); - } - - if (minutes == 0) { - return of("Jetzt").copy().formatted(DARK_GREEN); - } - - return of("vor " + minutes + (minutes == 1 ? " Minute" : " Minuten")).copy().formatted(YELLOW); - } - - @Getter - @AllArgsConstructor - public enum Type { - - JAIL("Gefängnis", -777, 64, 143), - PANEL_BUILDING("Plattenbau", 470, 69, 424), - AIRPORT("Flughafen", -292, 69, 636), - SH_PARK("Park an der Stadthalle", 58, 70, 355), - FARM("Farm", 427, 82, 512), - CINEMA("Kino", 770, 68, 331), - CHURCH("Wohnwagen an der Kirche", -304, 71, -206), - SUBWAY_MEXICAN("U-Bahn (Mexikanisches Kartell)", -94, 51, -34); - - private final String displayName; - private final int x; - private final int y; - private final int z; - - @Contract(pure = true) - public @NotNull String getNavigationCommand() { - return "/navi " + this.x + "/" + this.y + "/" + this.z; - } - - @Contract(value = " -> new", pure = true) - public @NotNull BlockPos getBlockPos() { - return new BlockPos(this.x, this.y, this.z); - } - } -} diff --git a/src/main/java/de/rettichlp/ucutils/common/models/Dealer.java b/src/main/java/de/rettichlp/ucutils/common/models/Dealer.java deleted file mode 100644 index 77ca9000..00000000 --- a/src/main/java/de/rettichlp/ucutils/common/models/Dealer.java +++ /dev/null @@ -1,95 +0,0 @@ -package de.rettichlp.ucutils.common.models; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import net.minecraft.text.ClickEvent; -import net.minecraft.text.HoverEvent; -import net.minecraft.text.Text; -import net.minecraft.util.math.BlockPos; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.time.Duration; -import java.time.LocalDateTime; - -import static java.time.LocalDateTime.now; -import static java.util.Objects.isNull; -import static net.minecraft.text.Text.empty; -import static net.minecraft.text.Text.of; -import static net.minecraft.util.Formatting.DARK_GRAY; -import static net.minecraft.util.Formatting.DARK_GREEN; -import static net.minecraft.util.Formatting.GOLD; -import static net.minecraft.util.Formatting.GRAY; -import static net.minecraft.util.Formatting.GREEN; -import static net.minecraft.util.Formatting.RED; -import static net.minecraft.util.Formatting.YELLOW; - -@Getter -@AllArgsConstructor -public class Dealer { - - private final Type type; - @Nullable - private final LocalDateTime visitedAt; - private boolean found; // whether the dealer was found or not - - public Text getText() { - return empty() - .styled(style -> style - .withHoverEvent(new HoverEvent.ShowText(of("Klicke, um die Navigation zu starten").copy().formatted(GOLD))) - .withClickEvent(new ClickEvent.RunCommand(this.type.getNavigationCommand()))) - .append(of(this.type.getDisplayName())).append(" ") - .append(of("(").copy().formatted(DARK_GRAY)) - .append(of("Besucht:").copy().formatted(GRAY)).append(" ") - .append(getLastVisitedText()) - .append(of(")").copy().formatted(DARK_GRAY)) - .append(this.found ? of(" ←").copy().formatted(GREEN) : empty()); - } - - private Text getLastVisitedText() { - if (isNull(this.visitedAt)) { - return of("Nie").copy().formatted(GRAY); - } - - Duration duration = Duration.between(this.visitedAt, now()); - long minutes = duration.toMinutes(); - - if (minutes >= 60) { - return of("vor über einer Stunde").copy().formatted(RED); - } - - if (minutes == 0) { - return of("Jetzt").copy().formatted(DARK_GREEN); - } - - return of("vor " + minutes + (minutes == 1 ? " Minute" : " Minuten")).copy().formatted(YELLOW); - } - - @Getter - @AllArgsConstructor - public enum Type { - - PAPER_COMPANY("Papierfabrik", -37, 70, -279), - HARBOR("Hafen", -417, 69, 185), - MEXICAN("Wohnwagen (Mex)", -381, 69, -198), - WINE_MAKER("Winzer", -2, 88, 598), - ALTSTADT("Altstadt", 0, 0, 0), - AIRPORT("Flughafen", -93, 64, 924); - - private final String displayName; - private final int x; - private final int y; - private final int z; - - @Contract(pure = true) - public @NotNull String getNavigationCommand() { - return "/navi " + this.x + "/" + this.y + "/" + this.z; - } - - @Contract(value = " -> new", pure = true) - public @NotNull BlockPos getBlockPos() { - return new BlockPos(this.x, this.y, this.z); - } - } -} From 67fb71c4bb3d850d1742e21a15391d6ffb619bab Mon Sep 17 00:00:00 2001 From: RettichLP Date: Fri, 22 May 2026 20:39:42 +0200 Subject: [PATCH 63/96] Add BadFactionListener to handle black market dealer entry detection and proximity checks --- .../impl/faction/BadFactionListener.java | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 src/main/java/de/rettichlp/ucutils/listener/impl/faction/BadFactionListener.java diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/faction/BadFactionListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/faction/BadFactionListener.java new file mode 100644 index 00000000..260bf97a --- /dev/null +++ b/src/main/java/de/rettichlp/ucutils/listener/impl/faction/BadFactionListener.java @@ -0,0 +1,59 @@ +package de.rettichlp.ucutils.listener.impl.faction; + +import de.rettichlp.ucutils.common.registry.UCUtilsListener; +import de.rettichlp.ucutils.listener.IMessageReceiveListener; +import net.minecraft.text.ClickEvent; +import net.minecraft.text.MutableText; +import net.minecraft.text.Text; +import net.minecraft.util.math.Vec3d; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static de.rettichlp.ucutils.UCUtils.player; +import static de.rettichlp.ucutils.UCUtils.storage; +import static java.lang.Integer.parseInt; +import static java.util.regex.Pattern.compile; +import static net.minecraft.text.Text.literal; +import static net.minecraft.util.Formatting.BOLD; +import static net.minecraft.util.Formatting.DARK_RED; + +@UCUtilsListener +public class BadFactionListener implements IMessageReceiveListener { + + private static final Pattern BLACK_MARKET_DEALER_ENTRY_PATTERN = compile("^» (?.+) – (gerade eben|vor \\d+ min|vor \\d+ std) {2}\\[Navi]$"); + + @Override + public boolean onMessageReceive(Text text, String message) { + Matcher blackMarketDealerEntryMatcher = BLACK_MARKET_DEALER_ENTRY_PATTERN.matcher(message); + if (blackMarketDealerEntryMatcher.find()) { + Vec3d blackMarketPosition = storage.getBlackMarketPosition(); + Vec3d dealerPosition = storage.getDealerPosition(); + + // extract location from message + Text last = text.getSiblings().getLast(); + ClickEvent clickEvent = last.getStyle().getClickEvent(); + if (!(clickEvent instanceof ClickEvent.RunCommand(String command))) { + return true; + } + + String[] locationPieces = command.replace("/navi ", "").split("/"); + + if (locationPieces.length != 3) { + return true; + } + + Vec3d extractedPosition = new Vec3d(parseInt(locationPieces[0]), parseInt(locationPieces[1]), parseInt(locationPieces[2])); + + if ((blackMarketPosition != null && extractedPosition.distanceTo(blackMarketPosition) < 5) || (dealerPosition != null && extractedPosition.distanceTo(dealerPosition) < 5)) { + MutableText text1 = text.copy().append(literal(" ⯐").formatted(DARK_RED, BOLD)); + player.sendMessage(text1, false); + return false; + } + + return true; + } + + return true; + } +} From 88f2da7543c9690be4710d352b0f24e9c1bb7d23 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Fri, 22 May 2026 20:41:14 +0200 Subject: [PATCH 64/96] Update README to include dealer and black market location information in the overview --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 8273bd0e..f2817088 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,7 @@ Folgende Funktionen sind nur für Spieler ohne Premium-Rang verfügbar, da Spiel - Mit `/fbank einzahlen ` kann das Eingabe GUI des Servers übersprungen werden - Für den Rettungsdienst gibt es im Herstellungs-Inventar für Medikamente einen Button, um die benötigte Anzahl an Stoffen in den Fraktionschat zu senden +- Für den Dealer und Schwarzmarkt wird (in der Übersicht) angezeigt, an welchem Ort der Händler gefunden wurde ### Jobs From b4e89092f62330dd7a0e5e99ad02ffab858ec246 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Sat, 23 May 2026 03:21:24 +0200 Subject: [PATCH 65/96] Remove `IScreenOpenListener` and associated logic; refactor screen handling in `HandledScreenMixin` --- .../ucutils/common/registry/Registry.java | 4 -- .../ucutils/listener/IScreenOpenListener.java | 8 ---- .../ucutils/listener/impl/CarListener.java | 37 +------------------ .../ucutils/mixin/HandledScreenMixin.java | 27 ++++++++++++++ 4 files changed, 28 insertions(+), 48 deletions(-) delete mode 100644 src/main/java/de/rettichlp/ucutils/listener/IScreenOpenListener.java diff --git a/src/main/java/de/rettichlp/ucutils/common/registry/Registry.java b/src/main/java/de/rettichlp/ucutils/common/registry/Registry.java index 04a8f628..a330914c 100644 --- a/src/main/java/de/rettichlp/ucutils/common/registry/Registry.java +++ b/src/main/java/de/rettichlp/ucutils/common/registry/Registry.java @@ -9,7 +9,6 @@ import de.rettichlp.ucutils.listener.IMessageReceiveListener; import de.rettichlp.ucutils.listener.IMessageSendListener; import de.rettichlp.ucutils.listener.INaviSpotReachedListener; -import de.rettichlp.ucutils.listener.IScreenOpenListener; import de.rettichlp.ucutils.listener.ITickListener; import de.rettichlp.ucutils.listener.IUCUtilsListener; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; @@ -18,7 +17,6 @@ import net.fabricmc.fabric.api.client.message.v1.ClientSendMessageEvents; import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback; import net.fabricmc.fabric.api.client.rendering.v1.world.WorldRenderEvents; -import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents; import org.jetbrains.annotations.NotNull; import java.util.Objects; @@ -122,8 +120,6 @@ public void registerListeners() { HudRenderCallback.EVENT.register((drawContext, tickCounter) -> getListenersImplementing(IHudRenderListener.class).forEach(iHudRenderListener -> iHudRenderListener.onHudRender(drawContext, tickCounter))); - ScreenEvents.AFTER_INIT.register((client, screen, scaledWidth, scaledHeight) -> getListenersImplementing(IScreenOpenListener.class).forEach(iScreenOpenListener -> iScreenOpenListener.onScreenOpen(screen, scaledWidth, scaledHeight))); - WorldRenderEvents.AFTER_ENTITIES.register(context -> getListenersImplementing(IEntityRenderListener.class).forEach(iEntityRenderListener -> iEntityRenderListener.onEntityRender(context))); // prevent multiple registrations of listeners diff --git a/src/main/java/de/rettichlp/ucutils/listener/IScreenOpenListener.java b/src/main/java/de/rettichlp/ucutils/listener/IScreenOpenListener.java deleted file mode 100644 index 0a501bcf..00000000 --- a/src/main/java/de/rettichlp/ucutils/listener/IScreenOpenListener.java +++ /dev/null @@ -1,8 +0,0 @@ -package de.rettichlp.ucutils.listener; - -import net.minecraft.client.gui.screen.Screen; - -public interface IScreenOpenListener extends IUCUtilsListener { - - void onScreenOpen(Screen screen, int scaledWidth, int scaledHeight); -} diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/CarListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/CarListener.java index 07ff5f52..9a85f595 100644 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/CarListener.java +++ b/src/main/java/de/rettichlp/ucutils/listener/impl/CarListener.java @@ -3,12 +3,8 @@ import de.rettichlp.ucutils.common.registry.UCUtilsListener; import de.rettichlp.ucutils.listener.IEntityRenderListener; import de.rettichlp.ucutils.listener.IMessageReceiveListener; -import de.rettichlp.ucutils.listener.IScreenOpenListener; import net.fabricmc.fabric.api.client.rendering.v1.world.WorldRenderContext; import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.screen.ingame.GenericContainerScreen; -import net.minecraft.client.network.ClientPlayerInteractionManager; import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.world.ClientWorld; @@ -17,21 +13,17 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import static de.rettichlp.ucutils.UCUtils.LOGGER; import static de.rettichlp.ucutils.UCUtils.commandService; import static de.rettichlp.ucutils.UCUtils.configuration; -import static de.rettichlp.ucutils.UCUtils.player; import static de.rettichlp.ucutils.UCUtils.renderService; import static de.rettichlp.ucutils.UCUtils.storage; import static java.lang.Integer.parseInt; -import static java.util.Objects.nonNull; import static java.util.Optional.ofNullable; import static java.util.regex.Pattern.compile; -import static net.minecraft.screen.slot.SlotActionType.PICKUP; import static net.minecraft.util.Formatting.AQUA; @UCUtilsListener -public class CarListener implements IEntityRenderListener, IMessageReceiveListener, IScreenOpenListener { +public class CarListener implements IEntityRenderListener, IMessageReceiveListener { private static final Pattern CAR_UNLOCK_PATTERN = compile("^\\[Car] Du hast deinen .+ aufgeschlossen\\.$"); private static final Pattern CAR_LOCK_PATTERN = compile("^\\[Car] Du hast deinen .+ abgeschlossen\\.$"); @@ -82,31 +74,4 @@ public boolean onMessageReceive(Text text, String message) { return true; } - - @Override - public void onScreenOpen(Screen screen, int scaledWidth, int scaledHeight) { - ClientPlayerInteractionManager interactionManager = MinecraftClient.getInstance().interactionManager; - - if (nonNull(interactionManager) && screen instanceof GenericContainerScreen genericContainerScreen) { - String titleString = genericContainerScreen.getTitle().getString(); - - switch (titleString) { - case "ᴄᴀʀᴄᴏɴᴛʀᴏʟ" -> { - if (configuration.getOptions().car().fastLock() && !storage.isPremium()) { - interactionManager.clickSlot(genericContainerScreen.getScreenHandler().syncId, 0, 0, PICKUP, player); - } - } - case "Fahrzeuge" -> { - if (configuration.getOptions().car().fastFind()) { - interactionManager.clickSlot(genericContainerScreen.getScreenHandler().syncId, 0, 0, PICKUP, player); - } - } - default -> { - if (commandService.isSuperUser()) { - LOGGER.info("Screen opened: {}", titleString); - } - } - } - } - } } diff --git a/src/main/java/de/rettichlp/ucutils/mixin/HandledScreenMixin.java b/src/main/java/de/rettichlp/ucutils/mixin/HandledScreenMixin.java index 60ca2292..84ec6c40 100644 --- a/src/main/java/de/rettichlp/ucutils/mixin/HandledScreenMixin.java +++ b/src/main/java/de/rettichlp/ucutils/mixin/HandledScreenMixin.java @@ -1,9 +1,11 @@ package de.rettichlp.ucutils.mixin; +import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.ingame.HandledScreen; import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.network.ClientPlayerInteractionManager; import net.minecraft.component.type.LoreComponent; import net.minecraft.screen.GenericContainerScreenHandler; import net.minecraft.screen.ScreenHandler; @@ -19,10 +21,15 @@ import java.util.regex.Matcher; +import static de.rettichlp.ucutils.UCUtils.LOGGER; import static de.rettichlp.ucutils.UCUtils.commandService; +import static de.rettichlp.ucutils.UCUtils.configuration; +import static de.rettichlp.ucutils.UCUtils.player; +import static de.rettichlp.ucutils.UCUtils.storage; import static java.lang.Integer.parseInt; import static java.util.regex.Pattern.compile; import static net.minecraft.component.DataComponentTypes.LORE; +import static net.minecraft.screen.slot.SlotActionType.PICKUP; import static net.minecraft.text.Text.literal; @Mixin(HandledScreen.class) @@ -42,6 +49,11 @@ protected HandledScreenMixin(Text title) { private void ucutils$renderTail(DrawContext context, int mouseX, int mouseY, float deltaTicks, CallbackInfo ci) { HandledScreen self = (HandledScreen) (Object) this; ScreenHandler screenHandler = self.getScreenHandler(); + ClientPlayerInteractionManager interactionManager = MinecraftClient.getInstance().interactionManager; + + if (interactionManager == null) { + return; + } String title = self.getTitle().getString(); @@ -67,6 +79,21 @@ protected HandledScreenMixin(Text title) { addDrawableChild(buttonWidget); } } + case "ᴄᴀʀᴄᴏɴᴛʀᴏʟ" -> { + if (configuration.getOptions().car().fastLock() && !storage.isPremium()) { + interactionManager.clickSlot(genericContainerScreenHandler.syncId, 0, 0, PICKUP, player); + } + } + case "Fahrzeuge" -> { + if (configuration.getOptions().car().fastFind()) { + interactionManager.clickSlot(genericContainerScreenHandler.syncId, 0, 0, PICKUP, player); + } + } + default -> { + if (commandService.isSuperUser()) { + LOGGER.info("Screen opened: {}", title); + } + } } } case null, default -> { From 15b7a08df9bd49aa22afeb20b9c2502eca601096 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Sat, 23 May 2026 03:22:10 +0200 Subject: [PATCH 66/96] Pathfinding: clean up README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d3fd3e78..1295d544 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ reibungsloser und angenehmer gestalten. - Sollte ein Command mit einem Großbuchstaben eingegeben werden (z. B. `/Afk` statt `/afk`) wird dieser Command automatisch zu einem gültigen Command umgewandelt +- Statt `/navi Haus:` kann `/navi ` genutzt werden - Als Business-Besitzer wird in der Business-Info ein Button angezeigt, um die Einnahmen direkt abzubuchen - Wirft man eine Glasflasche in der Nähe eines Shops weg, wird diese als Pfand abgegeben - Es wird angezeigt, wie lang der Cooldown für Bandagen und Schmerzpillen ist @@ -54,7 +55,6 @@ Folgende Funktionen sind nur für Spieler ohne Premium-Rang verfügbar, da Spiel - Der Müllmann-Job gibt am Ende den gesammelten Müll automatisch ab, ohne dass der `/dropwaste` Command ausgeführt werden muss - 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 -- Bei der Abgabe von Uran am Atomkraftwerk muss man nicht mehr aus dem Auto aussteigen - Aktive Mining XP-Booster werden angezeigt ### Widgets From d9062a797ac6113c317d4f23a385919fbf32368a Mon Sep 17 00:00:00 2001 From: RettichLP Date: Sun, 24 May 2026 20:00:31 +0200 Subject: [PATCH 67/96] Refactor PayDay notification logic: remove redundant checks in `Configuration` and centralize handling in `EconomyListener` Co-authored-by: AI --- .../common/configuration/Configuration.java | 16 -------------- .../listener/impl/EconomyListener.java | 22 ++++++++++++++----- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/src/main/java/de/rettichlp/ucutils/common/configuration/Configuration.java b/src/main/java/de/rettichlp/ucutils/common/configuration/Configuration.java index b2286888..1cd7db8f 100644 --- a/src/main/java/de/rettichlp/ucutils/common/configuration/Configuration.java +++ b/src/main/java/de/rettichlp/ucutils/common/configuration/Configuration.java @@ -14,9 +14,6 @@ import static de.rettichlp.ucutils.UCUtils.LOGGER; import static de.rettichlp.ucutils.UCUtils.api; -import static de.rettichlp.ucutils.UCUtils.configuration; -import static de.rettichlp.ucutils.UCUtils.messageService; -import static de.rettichlp.ucutils.UCUtils.notificationService; import static java.nio.file.Files.newBufferedReader; import static java.nio.file.Files.newBufferedWriter; @@ -39,19 +36,6 @@ public void addMinutesSinceLastPayDay(int minutes) { if (this.minutesSinceLastPayDay % 10 == 0) { new Thread(this::saveToFile).start(); // asynchronously save every active 10 minutes } - - if (configuration.getMoneyBankAmount() > 100000) { - switch (this.minutesSinceLastPayDay) { - case 50 -> { - messageService.sendModMessage("Du hast in 10 Minuten PayDay und über 100000$ auf der Bank!", false); - notificationService.notificationSound(1); - } - case 55 -> { - messageService.sendModMessage("Du hast in 5 Minuten PayDay und über 100000$ auf der Bank!", false); - notificationService.notificationSound(2); - } - } - } } public void addPredictedPayDaySalary(int salary) { diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/EconomyListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/EconomyListener.java index a4b5fb00..1d925e21 100644 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/EconomyListener.java +++ b/src/main/java/de/rettichlp/ucutils/listener/impl/EconomyListener.java @@ -18,6 +18,7 @@ import static de.rettichlp.ucutils.UCUtils.notificationService; import static de.rettichlp.ucutils.UCUtils.player; import static de.rettichlp.ucutils.UCUtils.storage; +import static de.rettichlp.ucutils.UCUtils.utilService; import static java.lang.Integer.parseInt; import static java.lang.Math.max; import static java.lang.System.currentTimeMillis; @@ -55,7 +56,7 @@ public class EconomyListener implements IMessageReceiveListener { private static final Pattern PAYDAY_TIME_PATTERN = compile("^- Zeit seit PayDay: (?\\d+)/60 Minuten$"); private static final Pattern PAYDAY_SALARY_PATTERN = compile("^\\[PayDay] Du bekommst dein Gehalt von (?\\d+)\\$ am PayDay ausgezahlt\\.$"); private static final Pattern PAYDAY_MINE_SALARY_PATTERN = compile("^\\[PayDay] Du bekommst deine Mine Einnahmen von (?\\d+)\\$ am PayDay ausgezahlt\\.$"); - private static final Pattern PAYDAY_COUNTDOWN_PATTERN = compile("^Info: Du hast in 3 Minuten deinen PayDay$"); + private static final Pattern PAYDAY_COUNTDOWN_PATTERN = compile("^Info: Du hast in (?\\d+) Minuten? deinen PayDay$"); // other private static final Pattern BUSINESS_CASH_PATTERN = compile("^Kasse: (\\d+)\\$$"); @@ -242,12 +243,21 @@ public boolean onMessageReceive(Text text, String message) { Matcher paydayCountdownMatcher = PAYDAY_COUNTDOWN_PATTERN.matcher(message); if (paydayCountdownMatcher.find()) { - configuration.setMinutesSinceLastPayDay(57); + int minutes = parseInt(paydayCountdownMatcher.group("minutes")); + int minutesSinceLastPayDay = 60 - minutes; + configuration.setMinutesSinceLastPayDay(minutesSinceLastPayDay); - if (configuration.getMoneyBankAmount() > 100000) { - messageService.sendModMessage("Du hast über 100000$ auf der Bank!", false); - notificationService.notificationSound(3); - } + utilService.delayedAction(() -> { + if (configuration.getMoneyBankAmount() > 100000) { + messageService.sendModMessage("Du hast über 100000$ auf der Bank!", false); + + switch (minutes) { + case 10 -> notificationService.notificationSound(1); + case 5 -> notificationService.notificationSound(2); + case 3, 2, 1 -> notificationService.notificationSound(3); + } + } + }, 50); return true; } From 91ad7ccf26529bb59d654fe3754a2829ee1b3e89 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Thu, 28 May 2026 09:55:28 +0200 Subject: [PATCH 68/96] Remove `ADropMoneyCommand` and associated money dropping logic --- .../command/money/ADropMoneyCommand.java | 64 ------------------- 1 file changed, 64 deletions(-) delete mode 100644 src/main/java/de/rettichlp/ucutils/command/money/ADropMoneyCommand.java diff --git a/src/main/java/de/rettichlp/ucutils/command/money/ADropMoneyCommand.java b/src/main/java/de/rettichlp/ucutils/command/money/ADropMoneyCommand.java deleted file mode 100644 index 256b0357..00000000 --- a/src/main/java/de/rettichlp/ucutils/command/money/ADropMoneyCommand.java +++ /dev/null @@ -1,64 +0,0 @@ -package de.rettichlp.ucutils.command.money; - -import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import de.rettichlp.ucutils.common.registry.CommandBase; -import de.rettichlp.ucutils.common.registry.UCUtilsCommand; -import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; -import net.minecraft.scoreboard.ReadableScoreboardScore; -import net.minecraft.scoreboard.Scoreboard; -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -import static de.rettichlp.ucutils.UCUtils.commandService; -import static de.rettichlp.ucutils.UCUtils.configuration; -import static de.rettichlp.ucutils.UCUtils.messageService; -import static de.rettichlp.ucutils.UCUtils.player; -import static java.lang.Math.min; -import static java.util.Optional.ofNullable; -import static net.minecraft.scoreboard.ScoreHolder.fromName; -import static net.minecraft.scoreboard.ScoreboardDisplaySlot.SIDEBAR; - -@UCUtilsCommand(label = "adropmoney") -public class ADropMoneyCommand extends CommandBase { - - @Override - public LiteralArgumentBuilder execute(@NotNull LiteralArgumentBuilder node) { - return node - .executes(context -> { - Scoreboard scoreboard = player.getEntityWorld().getScoreboard(); - - Optional optionalReadableScoreboardScore = ofNullable(scoreboard.getObjectiveForSlot(SIDEBAR)) - .map(scoreboardObjective -> scoreboard.getScore(fromName("§9Geld§8:"), scoreboardObjective)); - - if (optionalReadableScoreboardScore.isEmpty()) { - messageService.sendModMessage("Der Geldtransport-Job wird nicht ausgeführt.", false); - return 1; - } - - List scheduledCommands = getScheduledCommands(optionalReadableScoreboardScore); - - commandService.sendCommands(scheduledCommands); - - return 1; - }); - } - - private @NotNull List getScheduledCommands(@NotNull Optional optionalReadableScoreboardScore) { - ReadableScoreboardScore readableScoreboardScore = optionalReadableScoreboardScore.get(); - int moneyToDrop = readableScoreboardScore.getScore(); - - List scheduledCommands = new ArrayList<>(); - - while (moneyToDrop > 0) { - int moneyCanDrop = min(moneyToDrop, configuration.getMoneyBankAmount()); - scheduledCommands.add("bank abbuchen " + moneyCanDrop); - scheduledCommands.add("dropmoney"); - scheduledCommands.add("bank einzahlen " + moneyCanDrop); - moneyToDrop -= moneyCanDrop; - } - return scheduledCommands; - } -} From a6b0f87d1fe79b1212ba3e3be819c5d954a1173b Mon Sep 17 00:00:00 2001 From: RettichLP Date: Thu, 28 May 2026 09:56:04 +0200 Subject: [PATCH 69/96] Remove outdated `/adropmoney` command details from README --- README.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/README.md b/README.md index 1295d544..d7cb4435 100644 --- a/README.md +++ b/README.md @@ -81,9 +81,3 @@ Folgende Funktionen sind nur für Spieler ohne Premium-Rang verfügbar, da Spiel | `/ff` | Aktiviert und deaktiviert das dauerhafte Schreiben im F-Chat ohne den `/f` Befehl jedes Mal eingeben zu müssen | | `/dd` | Aktiviert und deaktiviert das dauerhafte Schreiben im D-Chat ohne den `/d` Befehl jedes Mal eingeben zu müssen | | `/ww` | Aktiviert und deaktiviert das dauerhafte Flüstern ohne den `/w` Befehl jedes Mal eingeben zu müssen | - -**Geld** - -| Befehl | Beschreibung | -|------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `/adropmoney` | Bucht für den Geldtransport-Job so viel Geld vom Konto ab, sodass das Geld vom Geldtransport-Job in den ATM eingezahlt werden kann und bucht das Geld anschließend zurück auf das Konto | From 70d8113a1cd3ea7a5b54fff6f8bdd7e60ac12e1f Mon Sep 17 00:00:00 2001 From: RettichLP Date: Thu, 28 May 2026 12:16:10 +0200 Subject: [PATCH 70/96] Rename FisherListener to DeepSeaFisherListener and update related logic and patterns --- .../impl/job/DeepSeaFisherListener.java | 138 ++++++++++++++++++ .../listener/impl/job/FisherListener.java | 138 ------------------ 2 files changed, 138 insertions(+), 138 deletions(-) create mode 100644 src/main/java/de/rettichlp/ucutils/listener/impl/job/DeepSeaFisherListener.java delete mode 100644 src/main/java/de/rettichlp/ucutils/listener/impl/job/FisherListener.java diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/job/DeepSeaFisherListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/job/DeepSeaFisherListener.java new file mode 100644 index 00000000..c520b8e8 --- /dev/null +++ b/src/main/java/de/rettichlp/ucutils/listener/impl/job/DeepSeaFisherListener.java @@ -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 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 nearestNextFisherJobSpot = getNearestFisherJobSpot(getNotVisitedFisherJobSpots()); + nearestNextFisherJobSpot.ifPresent(DeepSeaFisherJobSpot::startNavigation); + } + + private @NotNull Optional getNearestFisherJobSpot(@NotNull Collection 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 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); + } + } +} diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/job/FisherListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/job/FisherListener.java deleted file mode 100644 index e4c211bc..00000000 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/job/FisherListener.java +++ /dev/null @@ -1,138 +0,0 @@ -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 FisherListener implements IMessageReceiveListener, INaviSpotReachedListener { - - private static final Pattern FISHER_START = compile("^\\[Fischer] Mit /findschwarm kannst du dir den nächsten Fischschwarm anzeigen lassen\\.$"); - private static final Pattern FISHER_SPOT_FOUND_PATTERN = compile("^\\[Fischer] Du hast einen Fischschwarm gefunden!$"); - private static final Pattern FISHER_SPOT_LOST_PATTERN = compile("^\\[Fischer] Du hast dich dem Fischschwarm zu weit entfernt\\.$"); - private static final Pattern FISHER_CATCH_SUCCESS = compile("^\\[Fischer] Du hast \\d+kg frischen Fisch gefangen! \\(\\d+kg\\)$"); - private static final Pattern FISHER_CATCH_FAILURE = compile("^\\[Fischer] Du hast das Fischernetz verloren\\.\\.\\.$"); - private static final int NET_AMOUNT = 5; - - private Collection visitedFisherJobSpots = new ArrayList<>(); - private boolean onFisherSpot = false; - private boolean canCatchFish = true; - - @Override - public boolean onMessageReceive(Text text, String message) { - Matcher fisherStartMatcher = FISHER_START.matcher(message); - if (fisherStartMatcher.find()) { - this.visitedFisherJobSpots = new ArrayList<>(); - FisherJobSpot.SPOT_1.startNavigation(); - return true; - } - - Matcher fisherSpotFoundMatcher = FISHER_SPOT_FOUND_PATTERN.matcher(message); - if (fisherSpotFoundMatcher.find()) { - commandService.sendCommand("stoproute"); - this.onFisherSpot = true; - - if (this.canCatchFish) { - startFishing(); - } - - return true; - } - - Matcher fisherSpotLostMatcher = FISHER_SPOT_LOST_PATTERN.matcher(message); - if (fisherSpotLostMatcher.find()) { - this.onFisherSpot = false; - return true; - } - - Matcher fisherCatchSuccessMatcher = FISHER_CATCH_SUCCESS.matcher(message); - Matcher fisherCatchFailureMatcher = FISHER_CATCH_FAILURE.matcher(message); - if (fisherCatchSuccessMatcher.find() || fisherCatchFailureMatcher.find()) { - this.canCatchFish = true; - - // if already on the next fishing spot, start fishing again - if (this.onFisherSpot) { - startFishing(); - } - } - - return true; - } - - @Override - public void onNaviSpotReached() { - if (this.visitedFisherJobSpots.size() == NET_AMOUNT) { - this.visitedFisherJobSpots = new ArrayList<>(); - commandService.sendCommand("dropfish"); - } - } - - private void startFishing() { - this.onFisherSpot = false; - this.canCatchFish = false; - commandService.sendCommand("catchfish"); - - // add the current spot to visited spots - getNearestFisherJobSpot(getNotVisitedFisherJobSpots()).ifPresent(this.visitedFisherJobSpots::add); - - if (this.visitedFisherJobSpots.size() == NET_AMOUNT) { - return; - } - - // get nearest next spot and start navigation - Optional nearestNextFisherJobSpot = getNearestFisherJobSpot(getNotVisitedFisherJobSpots()); - nearestNextFisherJobSpot.ifPresent(FisherJobSpot::startNavigation); - } - - private @NotNull Optional getNearestFisherJobSpot(@NotNull Collection fisherJobSpots) { - return fisherJobSpots.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 getNotVisitedFisherJobSpots() { - return stream(FisherJobSpot.values()) - .filter(fisherJobSpot -> !this.visitedFisherJobSpots.contains(fisherJobSpot)) - .toList(); - } - - @Getter - @AllArgsConstructor - private enum FisherJobSpot { - - 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); - } - } -} From 51f3e9d06f910fbe20c5060c0a6d916f8917a8e0 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Thu, 28 May 2026 12:29:13 +0200 Subject: [PATCH 71/96] Add AnglerListener to handle anti-bot fishing captcha detection and interaction logic --- .../de/rettichlp/ucutils/common/Storage.java | 8 ++ .../listener/impl/job/AnglerListener.java | 87 +++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 src/main/java/de/rettichlp/ucutils/listener/impl/job/AnglerListener.java diff --git a/src/main/java/de/rettichlp/ucutils/common/Storage.java b/src/main/java/de/rettichlp/ucutils/common/Storage.java index 492152b5..b9b9ce3e 100644 --- a/src/main/java/de/rettichlp/ucutils/common/Storage.java +++ b/src/main/java/de/rettichlp/ucutils/common/Storage.java @@ -16,6 +16,7 @@ import net.minecraft.util.math.Vec3d; import org.jetbrains.annotations.Nullable; +import java.awt.image.BufferedImage; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.HashMap; @@ -64,6 +65,11 @@ public class Storage { @Nullable private Vec3d blackMarketPosition; + @Getter + @Setter + @Nullable + private BufferedImage captchaMapImage; + @Getter @Setter private boolean carLocked = true; @@ -119,6 +125,8 @@ public void print() { LOGGER.info("activeShutdowns[{}]: {}", this.activeShutdowns.size(), this.activeShutdowns); // blackMarketPosition LOGGER.info("blackMarketPosition: {}", this.blackMarketPosition); + // captchaMapImage + LOGGER.info("captchaMapImage: {}", this.captchaMapImage); // countdowns LOGGER.info("countdowns[{}]: {}", this.countdowns.size(), this.countdowns); // dealerPosition diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/job/AnglerListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/job/AnglerListener.java new file mode 100644 index 00000000..7be28ebd --- /dev/null +++ b/src/main/java/de/rettichlp/ucutils/listener/impl/job/AnglerListener.java @@ -0,0 +1,87 @@ +package de.rettichlp.ucutils.listener.impl.job; + +import de.rettichlp.ucutils.common.registry.UCUtilsListener; +import de.rettichlp.ucutils.listener.IMessageReceiveListener; +import lombok.NonNull; +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.util.regex.Matcher; +import java.util.regex.Pattern; + +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 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.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; + } + + storage.setCaptchaMapImage(getMapImage(offHandStack)); + return true; + } + + Matcher anglerCaptchaContinuedMatcher = ANGLER_CAPTCHA_CONTINUED_PATTERN.matcher(message); + if (anglerCaptchaContinuedMatcher.find()) { + ClientPlayerInteractionManager interactionManager = client.interactionManager; + if (interactionManager == null) { + return true; + } + + interactionManager.interactItem(player, MAIN_HAND); + player.swingHand(MAIN_HAND); + return true; + } + + return true; + } + + private @Nullable BufferedImage getMapImage(@NonNull ItemStack mapItemStack) { + MapIdComponent mapId = mapItemStack.get(MAP_ID); + if (mapId == null) { + return null; + } + + MapState mapState = getMapState(mapId, 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; + } +} From e4f34b58b141a00e1dcdc90531d58ad8e58f3f96 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Thu, 28 May 2026 12:30:54 +0200 Subject: [PATCH 72/96] Update README: display fishing captcha centered and auto-cast after solving --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index d7cb4435..85cbcb84 100644 --- a/README.md +++ b/README.md @@ -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 From 32e503ec68428d6818585d5b87434da04c173b4b Mon Sep 17 00:00:00 2001 From: RettichLP Date: Thu, 28 May 2026 12:52:49 +0200 Subject: [PATCH 73/96] Refactor AnglerListener and Storage: replace `captchaMapImage` with `captchaMap` for handling map identifiers --- src/main/java/de/rettichlp/ucutils/common/Storage.java | 6 +++--- .../rettichlp/ucutils/listener/impl/job/AnglerListener.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/rettichlp/ucutils/common/Storage.java b/src/main/java/de/rettichlp/ucutils/common/Storage.java index b9b9ce3e..5d83faca 100644 --- a/src/main/java/de/rettichlp/ucutils/common/Storage.java +++ b/src/main/java/de/rettichlp/ucutils/common/Storage.java @@ -11,12 +11,12 @@ 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; import org.jetbrains.annotations.Nullable; -import java.awt.image.BufferedImage; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.HashMap; @@ -68,7 +68,7 @@ public class Storage { @Getter @Setter @Nullable - private BufferedImage captchaMapImage; + private MapIdComponent captchaMap; @Getter @Setter @@ -126,7 +126,7 @@ public void print() { // blackMarketPosition LOGGER.info("blackMarketPosition: {}", this.blackMarketPosition); // captchaMapImage - LOGGER.info("captchaMapImage: {}", this.captchaMapImage); + LOGGER.info("captchaMap: {}", this.captchaMap); // countdowns LOGGER.info("countdowns[{}]: {}", this.countdowns.size(), this.countdowns); // dealerPosition diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/job/AnglerListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/job/AnglerListener.java index 7be28ebd..88e8bbf3 100644 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/job/AnglerListener.java +++ b/src/main/java/de/rettichlp/ucutils/listener/impl/job/AnglerListener.java @@ -42,7 +42,7 @@ public boolean onMessageReceive(Text text, String message) { return true; } - storage.setCaptchaMapImage(getMapImage(offHandStack)); + storage.setCaptchaMap(offHandStack.get(MAP_ID)); return true; } From fdbc959c03cd0bff737bb3eccce5bbb40e7e5db2 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Thu, 28 May 2026 21:15:33 +0200 Subject: [PATCH 74/96] Add fishing rod check in AnglerListener to ensure proper tool is equipped during captcha handling --- .../rettichlp/ucutils/listener/impl/job/AnglerListener.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/job/AnglerListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/job/AnglerListener.java index 88e8bbf3..19385dc7 100644 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/job/AnglerListener.java +++ b/src/main/java/de/rettichlp/ucutils/listener/impl/job/AnglerListener.java @@ -23,6 +23,7 @@ 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 @@ -48,8 +49,10 @@ public boolean onMessageReceive(Text text, String message) { Matcher anglerCaptchaContinuedMatcher = ANGLER_CAPTCHA_CONTINUED_PATTERN.matcher(message); if (anglerCaptchaContinuedMatcher.find()) { + storage.setCaptchaMap(null); + ClientPlayerInteractionManager interactionManager = client.interactionManager; - if (interactionManager == null) { + if (interactionManager == null || !player.getMainHandStack().isOf(FISHING_ROD)) { return true; } From 477ebc156e41f25d071843470c7c0a3319a8cb8c Mon Sep 17 00:00:00 2001 From: RettichLP Date: Fri, 29 May 2026 22:30:21 +0200 Subject: [PATCH 75/96] Save captcha map image to file system in `AnglerListener` for render purposes --- .../listener/impl/job/AnglerListener.java | 32 +++++++++++++++---- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/job/AnglerListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/job/AnglerListener.java index 19385dc7..a8a2b70a 100644 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/job/AnglerListener.java +++ b/src/main/java/de/rettichlp/ucutils/listener/impl/job/AnglerListener.java @@ -2,7 +2,6 @@ import de.rettichlp.ucutils.common.registry.UCUtilsListener; import de.rettichlp.ucutils.listener.IMessageReceiveListener; -import lombok.NonNull; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientPlayerInteractionManager; import net.minecraft.component.type.MapIdComponent; @@ -12,13 +11,16 @@ 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; @@ -43,7 +45,11 @@ public boolean onMessageReceive(Text text, String message) { return true; } - storage.setCaptchaMap(offHandStack.get(MAP_ID)); + MapIdComponent captchaMap = offHandStack.get(MAP_ID); + storage.setCaptchaMap(captchaMap); + + saveCaptchaImage(captchaMap); + return true; } @@ -64,13 +70,25 @@ public boolean onMessageReceive(Text text, String message) { return true; } - private @Nullable BufferedImage getMapImage(@NonNull ItemStack mapItemStack) { - MapIdComponent mapId = mapItemStack.get(MAP_ID); - if (mapId == null) { - return null; + private void saveCaptchaImage(MapIdComponent captchaMap) { + BufferedImage mapImage = getMapImage(captchaMap); + if (mapImage == null) { + return; } - MapState mapState = getMapState(mapId, MinecraftClient.getInstance().world); + 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; } From d6a42873123fcfab8b68a02a386afc71ebe476df Mon Sep 17 00:00:00 2001 From: RettichLP Date: Fri, 29 May 2026 22:31:42 +0200 Subject: [PATCH 76/96] Render captcha image in front of chat window using custom texture manager --- .../ucutils/mixin/InGameHudMixin.java | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/main/java/de/rettichlp/ucutils/mixin/InGameHudMixin.java b/src/main/java/de/rettichlp/ucutils/mixin/InGameHudMixin.java index e9af07e5..50c27a29 100644 --- a/src/main/java/de/rettichlp/ucutils/mixin/InGameHudMixin.java +++ b/src/main/java/de/rettichlp/ucutils/mixin/InGameHudMixin.java @@ -1,13 +1,17 @@ package de.rettichlp.ucutils.mixin; import com.llamalad7.mixinextras.sugar.Local; +import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.hud.InGameHud; import net.minecraft.client.render.RenderTickCounter; +import net.minecraft.client.texture.NativeImage; +import net.minecraft.client.texture.NativeImageBackedTexture; import net.minecraft.entity.LivingEntity; import net.minecraft.util.Identifier; import net.minecraft.util.profiler.Profilers; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -15,6 +19,10 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import java.io.InputStream; +import java.nio.file.Path; + +import static de.rettichlp.ucutils.UCUtils.LOGGER; import static de.rettichlp.ucutils.UCUtils.MOD_ID; import static de.rettichlp.ucutils.UCUtils.configuration; import static de.rettichlp.ucutils.UCUtils.nameTagService; @@ -26,6 +34,7 @@ import static java.lang.Math.clamp; import static java.lang.Math.round; import static java.lang.System.currentTimeMillis; +import static java.nio.file.Files.newInputStream; import static net.minecraft.client.gl.RenderPipelines.GUI_TEXTURED; import static net.minecraft.item.Items.GOLDEN_HOE; import static net.minecraft.registry.tag.FluidTags.WATER; @@ -43,9 +52,40 @@ public abstract class InGameHudMixin { @Unique private static final Identifier HYDRATION_FULL_TEXTURE = Identifier.of(MOD_ID, "textures/hud/hydration_full.png"); + @Unique + private static final Identifier CAPTCHA_IDENTIFIER = Identifier.of("ucutils", "captcha"); + + @Shadow + @Final + private MinecraftClient client; + @Shadow public abstract TextRenderer getTextRenderer(); + @Inject(method = "renderChat", at = @At("TAIL")) + private void ucutils$renderChatTail(DrawContext context, RenderTickCounter tickCounter, CallbackInfo ci) { + if (storage.getCaptchaMap() == null) { + return; + } + + NativeImage nativeImage; + try (InputStream is = newInputStream(Path.of("captcha.png"))) { + nativeImage = NativeImage.read(is); + } catch (Exception e) { + LOGGER.error("Failed to read captcha image", e); + return; + } + + NativeImageBackedTexture nativeImageBackedTexture = new NativeImageBackedTexture(() -> "captcha", nativeImage); + this.client.getTextureManager().registerTexture(CAPTCHA_IDENTIFIER, nativeImageBackedTexture); + + int side = context.getScaledWindowWidth() / 4; + int x = context.getScaledWindowWidth() / 2 - side / 2; + int y = context.getScaledWindowHeight() / 4 - side / 2; + + context.drawTexture(GUI_TEXTURED, CAPTCHA_IDENTIFIER, x, y, 0, 0, side, side, side, side); + } + @Inject(method = "renderCrosshair", at = @At( value = "INVOKE", From 021967c19bd89ae3c39233fda40232cafbb1e608 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Fri, 29 May 2026 22:36:10 +0200 Subject: [PATCH 77/96] Remove custom name handling logic from `EntityMixin` --- .../rettichlp/ucutils/mixin/EntityMixin.java | 76 ------------------- 1 file changed, 76 deletions(-) diff --git a/src/main/java/de/rettichlp/ucutils/mixin/EntityMixin.java b/src/main/java/de/rettichlp/ucutils/mixin/EntityMixin.java index 3944e797..9f508ead 100644 --- a/src/main/java/de/rettichlp/ucutils/mixin/EntityMixin.java +++ b/src/main/java/de/rettichlp/ucutils/mixin/EntityMixin.java @@ -1,38 +1,21 @@ package de.rettichlp.ucutils.mixin; -import de.rettichlp.ucutils.common.models.Faction; -import de.rettichlp.ucutils.common.models.WantedEntry; import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.entity.Entity; -import net.minecraft.entity.ItemEntity; import net.minecraft.entity.vehicle.MinecartEntity; -import net.minecraft.item.ItemStack; -import net.minecraft.text.MutableText; -import net.minecraft.text.Text; -import net.minecraft.util.Formatting; import net.minecraft.world.entity.UniquelyIdentifiable; import org.jetbrains.annotations.NotNull; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import java.util.Optional; - import static de.rettichlp.ucutils.UCUtils.commandService; import static de.rettichlp.ucutils.UCUtils.configuration; -import static de.rettichlp.ucutils.UCUtils.nameTagService; import static de.rettichlp.ucutils.UCUtils.player; import static de.rettichlp.ucutils.UCUtils.storage; import static de.rettichlp.ucutils.UCUtils.utilService; -import static de.rettichlp.ucutils.common.models.Color.WHITE; -import static net.minecraft.item.Items.SKELETON_SKULL; -import static net.minecraft.item.Items.WITHER_SKELETON_SKULL; -import static net.minecraft.text.Text.empty; -import static net.minecraft.text.Text.literal; -import static net.minecraft.util.Formatting.GRAY; @Mixin(Entity.class) public abstract class EntityMixin { @@ -78,63 +61,4 @@ public abstract class EntityMixin { storage.setMinecartEntityToHighlight(minecartEntity); } } - - @Inject(method = "getCustomName", at = @At("RETURN"), cancellable = true) - private void ucutils$getDisplayNameReturn(@NotNull CallbackInfoReturnable cir) { - if (!storage.isUnicaCity()) { - return; - } - - Entity self = (Entity) (Object) this; - if (!(self instanceof ItemEntity itemEntity) || !itemEntity.hasCustomName()) { - return; - } - - ItemStack itemStack = itemEntity.getStack(); - Text returnValue = cir.getReturnValue(); - if (returnValue == null || (!itemStack.isOf(SKELETON_SKULL) && !itemStack.isOf(WITHER_SKELETON_SKULL))) { - return; - } - - String displayNameString = returnValue.getString(); - - // extract player name (✟RettichLP -> RettichLP) - String playerName = displayNameString.substring(1); - - // enrich player name with faction information (RettichLP -> RettichLP ⌜✚⌟) - MutableText enrichedDisplayName = getEnrichedDisplayName(playerName); - - cir.setReturnValue(empty() - .append(literal("✟").copy().formatted(GRAY)) - .append(enrichedDisplayName)); - } - - @Unique - private MutableText getEnrichedDisplayName(String targetName) { - Faction targetFaction = storage.getCachedFaction(targetName); - - Text newTargetDisplayNamePrefix = empty(); - Text newTargetDisplayName = literal(targetName); - Text newTargetDisplayNameSuffix = targetFaction.getNameTagSuffix(); - Formatting newTargetDisplayNameColor; - - // highlight factions - newTargetDisplayNameColor = WHITE.getFormatting(); - - // wanted - Optional optionalTargetWantedEntry = storage.getWantedEntries().stream() - .filter(wantedEntry -> wantedEntry.getPlayerName().equals(targetName)) - .findAny(); - - if (optionalTargetWantedEntry.isPresent()) { - newTargetDisplayNameColor = nameTagService.getWantedPointColor(optionalTargetWantedEntry.get().getWantedPointAmount()); - } - - return empty() - .append(newTargetDisplayNamePrefix) - .append(" ") - .append(newTargetDisplayName.copy().formatted(newTargetDisplayNameColor)) - .append(" ") - .append(newTargetDisplayNameSuffix); - } } From 717d18b9b73d996febd0907035346e8aece2c804 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Fri, 29 May 2026 22:51:26 +0200 Subject: [PATCH 78/96] Replace custom `addButton` method with direct usage of `ButtonWidget.builder` in screens and remove redundant method from `RenderService` --- .../ucutils/common/gui/screens/ShutdownScreen.java | 4 ++-- .../gui/screens/options/MainOptionsScreen.java | 13 +++++++------ .../options/WidgetOptionsPositionScreen.java | 9 +++++---- .../gui/screens/options/WidgetOptionsScreen.java | 3 ++- .../ucutils/common/services/RenderService.java | 13 ------------- 5 files changed, 16 insertions(+), 26 deletions(-) diff --git a/src/main/java/de/rettichlp/ucutils/common/gui/screens/ShutdownScreen.java b/src/main/java/de/rettichlp/ucutils/common/gui/screens/ShutdownScreen.java index b797327d..633ad200 100644 --- a/src/main/java/de/rettichlp/ucutils/common/gui/screens/ShutdownScreen.java +++ b/src/main/java/de/rettichlp/ucutils/common/gui/screens/ShutdownScreen.java @@ -1,11 +1,11 @@ package de.rettichlp.ucutils.common.gui.screens; import de.rettichlp.ucutils.common.models.ShutdownReason; +import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.gui.widget.DirectionalLayoutWidget; import net.minecraft.client.gui.widget.TextWidget; import net.minecraft.text.Text; -import static de.rettichlp.ucutils.UCUtils.renderService; import static de.rettichlp.ucutils.UCUtils.storage; import static net.minecraft.client.gui.widget.DirectionalLayoutWidget.vertical; import static net.minecraft.text.Text.empty; @@ -44,7 +44,7 @@ public void initBody() { directionalLayoutWidget.add(new TextWidget(empty() .append(of("wird das automatische Herunterfahren gestoppt.").copy().formatted(GRAY)), this.textRenderer), positioner -> positioner.marginBottom(16)); - renderService.addButton(directionalLayoutWidget, BUTTON_SHUTDOWN_ABORT_NAME, button -> close(), 150); + directionalLayoutWidget.add(ButtonWidget.builder(BUTTON_SHUTDOWN_ABORT_NAME, button -> close()).width(150).build()); directionalLayoutWidget.forEachChild(this::addDrawableChild); } diff --git a/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/MainOptionsScreen.java b/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/MainOptionsScreen.java index 7f130f36..7de6605b 100644 --- a/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/MainOptionsScreen.java +++ b/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/MainOptionsScreen.java @@ -3,6 +3,7 @@ import de.rettichlp.ucutils.common.configuration.options.Options; import de.rettichlp.ucutils.common.gui.screens.OptionsScreen; import net.minecraft.client.gui.screen.GameMenuScreen; +import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.gui.widget.DirectionalLayoutWidget; import net.minecraft.text.Text; @@ -38,16 +39,16 @@ public void initBody() { renderService.addCyclingButton(directionalLayoutWidget, REINFORCEMENT_STYLE_NAME, Options.ReinforcementType.values(), Options.ReinforcementType::getDisplayName, Options::reinforcementType, Options::reinforcementType, 308); DirectionalLayoutWidget directionalLayoutWidget1 = directionalLayoutWidget.add(horizontal().spacing(8)); - renderService.addButton(directionalLayoutWidget1, TEXT_NAMETAG, button -> this.client.setScreen(new NameTagOptionsScreen(this)), 150); - renderService.addButton(directionalLayoutWidget1, TEXT_CHAT, button -> this.client.setScreen(new ChatOptionsScreen(this)), 150); + directionalLayoutWidget1.add(ButtonWidget.builder(TEXT_NAMETAG, button -> this.client.setScreen(new NameTagOptionsScreen(this))).width(150).build()); + directionalLayoutWidget1.add(ButtonWidget.builder(TEXT_CHAT, button -> this.client.setScreen(new ChatOptionsScreen(this))).width(150).build()); DirectionalLayoutWidget directionalLayoutWidget2 = directionalLayoutWidget.add(horizontal().spacing(8)); - renderService.addButton(directionalLayoutWidget2, TEXT_CAR, button -> this.client.setScreen(new CarOptionsScreen(this)), 150); - renderService.addButton(directionalLayoutWidget2, TEXT_SOUNDS, button -> this.client.setScreen(new SoundOptionsScreen(this)), 150); + directionalLayoutWidget2.add(ButtonWidget.builder(TEXT_CAR, button -> this.client.setScreen(new CarOptionsScreen(this))).width(150).build()); + directionalLayoutWidget2.add(ButtonWidget.builder(TEXT_SOUNDS, button -> this.client.setScreen(new SoundOptionsScreen(this))).width(150).build()); DirectionalLayoutWidget directionalLayoutWidget3 = directionalLayoutWidget.add(horizontal().spacing(8)); - renderService.addButton(directionalLayoutWidget3, TEXT_WIDGETS, button -> this.client.setScreen(new WidgetOptionsScreen(this)), 150); - renderService.addButton(directionalLayoutWidget3, TEXT_NOTIFICATIONS, button -> this.client.setScreen(new NotificationOptionsScreen(this)), 150); + directionalLayoutWidget3.add(ButtonWidget.builder(TEXT_WIDGETS, button -> this.client.setScreen(new WidgetOptionsScreen(this))).width(150).build()); + directionalLayoutWidget3.add(ButtonWidget.builder(TEXT_NOTIFICATIONS, button -> this.client.setScreen(new NotificationOptionsScreen(this))).width(150).build()); DirectionalLayoutWidget directionalLayoutWidget4 = directionalLayoutWidget.add(horizontal().spacing(8)); renderService.addToggleButton(directionalLayoutWidget4, HYDRATION_NAME, HYDRATION_TOOLTIP, Options::showHydration, Options::showHydration, 150); diff --git a/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/WidgetOptionsPositionScreen.java b/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/WidgetOptionsPositionScreen.java index 7ca7a5f3..694478ae 100644 --- a/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/WidgetOptionsPositionScreen.java +++ b/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/WidgetOptionsPositionScreen.java @@ -6,6 +6,7 @@ import net.minecraft.client.gui.Click; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.gui.widget.DirectionalLayoutWidget; import net.minecraft.client.util.Window; import net.minecraft.text.Text; @@ -39,16 +40,16 @@ public WidgetOptionsPositionScreen(Screen parent) { public void initBody() { DirectionalLayoutWidget directionalLayoutWidget = this.layout.addBody(horizontal().spacing(8), positioner -> positioner.marginTop(this.client.getWindow().getScaledHeight() / 4)); - renderService.addButton(directionalLayoutWidget, DONE, button -> { + directionalLayoutWidget.add(ButtonWidget.builder(DONE, button -> { renderService.getWidgets().forEach(AbstractUCUtilsWidget::saveConfiguration); back(); - }, 150); + }).width(150).build()); - renderService.addButton(directionalLayoutWidget, CANCEL, button -> { + directionalLayoutWidget.add(ButtonWidget.builder(CANCEL, button -> { // restore configurations from the configuration file renderService.getWidgets().forEach(AbstractUCUtilsWidget::loadConfiguration); back(); - }, 150); + }).width(150).build()); directionalLayoutWidget.forEachChild(this::addDrawableChild); } diff --git a/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/WidgetOptionsScreen.java b/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/WidgetOptionsScreen.java index 4652132b..be8b47ee 100644 --- a/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/WidgetOptionsScreen.java +++ b/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/WidgetOptionsScreen.java @@ -7,6 +7,7 @@ import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.tooltip.Tooltip; +import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.gui.widget.DirectionalLayoutWidget; import net.minecraft.client.gui.widget.GridWidget; import net.minecraft.client.gui.widget.Positioner; @@ -40,7 +41,7 @@ public void initBody() { // general directionalLayoutWidget.add(new TextWidget(TEXT_GENERAL, this.textRenderer), Positioner::alignHorizontalCenter); - renderService.addButton(directionalLayoutWidget, TEXT_POSITION, button -> this.client.setScreen(new WidgetOptionsPositionScreen(this)), 308); + directionalLayoutWidget.add(ButtonWidget.builder(TEXT_POSITION, button -> this.client.setScreen(new WidgetOptionsPositionScreen(this))).width(308).build()); // general - enable status GridWidget gridWidget = directionalLayoutWidget.add(new GridWidget()); diff --git a/src/main/java/de/rettichlp/ucutils/common/services/RenderService.java b/src/main/java/de/rettichlp/ucutils/common/services/RenderService.java index 06c25dd1..23a3068c 100644 --- a/src/main/java/de/rettichlp/ucutils/common/services/RenderService.java +++ b/src/main/java/de/rettichlp/ucutils/common/services/RenderService.java @@ -9,7 +9,6 @@ import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.tooltip.Tooltip; -import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.gui.widget.CyclingButtonWidget; import net.minecraft.client.gui.widget.DirectionalLayoutWidget; import net.minecraft.client.render.Camera; @@ -103,18 +102,6 @@ public void initializeWidgets() { .collect(toCollection(LinkedHashSet::new)); } - public void addButton(@NotNull DirectionalLayoutWidget widget, - Text name, - ButtonWidget.PressAction onPress, - int width) { - ButtonWidget buttonWidget = ButtonWidget.builder(name, onPress) - .build(); - - buttonWidget.setWidth(width); - - widget.add(buttonWidget); - } - public void addCyclingButton(@NotNull DirectionalLayoutWidget widget, Text name, E[] values, From c88293cf40053f899a225deeb9a20bd148c5bd3b Mon Sep 17 00:00:00 2001 From: RettichLP Date: Fri, 29 May 2026 22:51:55 +0200 Subject: [PATCH 79/96] Adjust faction features and remove outdated details from README --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index 85cbcb84..cd76b94b 100644 --- a/README.md +++ b/README.md @@ -36,10 +36,7 @@ Folgende Funktionen sind nur für Spieler ohne Premium-Rang verfügbar, da Spiel ### Fraktionen -- Für bewusstlose Spieler wird hinter dem Spielernamen ein Symbol angezeigt, um die dazugehörige Fraktion zu erkennen -- Sollte ein Spieler Wanted-Punkte haben, wird der Name der Leiche dementsprechend eingefärbt - Das Design der Reinforcements ist so überarbeitet, dass diese besser auffallen -- Für das FBI, die Polizei und den Rettungsdienst gibt es einen Timer, der die Dauer der Bombe anzeigt - Für den Rettungsdienst wird der Cooldown von Bandagen und Schmerzpillen unter dem Spielernamen angezeigt - Der Fraktionschat kann individuell eingefärbt werden - Mit `/fbank einzahlen ` kann das Eingabe GUI des Servers übersprungen werden From 422790a4dcb72bf50416f63cf665e012b978622c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 31 May 2026 18:31:56 +0000 Subject: [PATCH 80/96] Update plugin net.fabricmc.fabric-loom-remap to v1.16.3 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index ad4392be..2c263fec 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,7 +10,7 @@ org.gradle.configuration-cache=false minecraft_version=1.21.10 yarn_mappings=1.21.10+build.3 loader_version=0.19.2 -loom_version=1.16.2 +loom_version=1.16.3 # Mod Properties mod_version=0.0.0 From 96d8c91fb4a199a06c97d804722457cf9dc0000c Mon Sep 17 00:00:00 2001 From: RettichLP Date: Fri, 22 May 2026 02:03:53 +0200 Subject: [PATCH 81/96] Add stock market buy/sell message handling in EconomyListener --- .../listener/impl/EconomyListener.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/EconomyListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/EconomyListener.java index 1d925e21..24f93fc7 100644 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/EconomyListener.java +++ b/src/main/java/de/rettichlp/ucutils/listener/impl/EconomyListener.java @@ -58,6 +58,10 @@ public class EconomyListener implements IMessageReceiveListener { private static final Pattern PAYDAY_MINE_SALARY_PATTERN = compile("^\\[PayDay] Du bekommst deine Mine Einnahmen von (?\\d+)\\$ am PayDay ausgezahlt\\.$"); private static final Pattern PAYDAY_COUNTDOWN_PATTERN = compile("^Info: Du hast in (?\\d+) Minuten? deinen PayDay$"); + // stock market + private static final Pattern STOCK_MARKET_BUY_PATTERN = compile("^\\[Aktien] Du hast (?\\d+)x (?.+) für (?\\d+)\\$ gekauft\\. \\(Gebühr: (?\\d+)\\$\\)$"); + private static final Pattern STOCK_MARKET_SELL_PATTERN = compile("^\\[Aktien] (?\\d+)x (?.+) verkauft für (?\\d+)\\$\\. \\(Gebühr: (?\\d+)\\$\\) (?[+-]\\d+)\\$ Brutto / (?[+-]\\d+)\\$ Netto$"); + // other private static final Pattern BUSINESS_CASH_PATTERN = compile("^Kasse: (\\d+)\\$$"); private static final Pattern EXP_PATTERN = compile("(?[+-]\\d+) Exp!( \\(x(?\\d)\\))?"); @@ -262,6 +266,21 @@ public boolean onMessageReceive(Text text, String message) { return true; } + Matcher stockMarketBuyMatcher = STOCK_MARKET_BUY_PATTERN.matcher(message); + if (stockMarketBuyMatcher.find()) { + int price = parseInt(stockMarketBuyMatcher.group("price")); + int fee = parseInt(stockMarketBuyMatcher.group("fee")); + configuration.setMoneyCashAmount(configuration.getMoneyCashAmount() - price - fee); + return true; + } + + Matcher stockMarketSellMatcher = STOCK_MARKET_SELL_PATTERN.matcher(message); + if (stockMarketSellMatcher.find()) { + int price = parseInt(stockMarketSellMatcher.group("price")); + configuration.setMoneyCashAmount(configuration.getMoneyCashAmount() + price); + return true; + } + Matcher businessCashMatcher = BUSINESS_CASH_PATTERN.matcher(message); if (businessCashMatcher.find()) { String amountString = businessCashMatcher.group(1); From e0ea79cf5e91e696a434920121bbf92b2849fc5a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 7 Jun 2026 16:27:01 +0000 Subject: [PATCH 82/96] Update loom_version to v1.17.1 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 2c263fec..d13560a3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,7 +10,7 @@ org.gradle.configuration-cache=false minecraft_version=1.21.10 yarn_mappings=1.21.10+build.3 loader_version=0.19.2 -loom_version=1.16.3 +loom_version=1.17.1 # Mod Properties mod_version=0.0.0 From cbbc63fde6af3202b192392284cb40865eab9efe Mon Sep 17 00:00:00 2001 From: RettichLP Date: Sun, 7 Jun 2026 20:56:41 +0200 Subject: [PATCH 83/96] Remove F-Bank deposit reason handling and related GUI bypass functionality --- README.md | 1 - .../de/rettichlp/ucutils/common/Storage.java | 6 -- .../listener/impl/CommandListener.java | 11 ---- .../ucutils/mixin/DialogScreenMixin.java | 65 ------------------- src/main/resources/ucutils.mixins.json | 1 - 5 files changed, 84 deletions(-) delete mode 100644 src/main/java/de/rettichlp/ucutils/mixin/DialogScreenMixin.java diff --git a/README.md b/README.md index cd76b94b..f8c152d0 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,6 @@ Folgende Funktionen sind nur für Spieler ohne Premium-Rang verfügbar, da Spiel - Das Design der Reinforcements ist so überarbeitet, dass diese besser auffallen - Für den Rettungsdienst wird der Cooldown von Bandagen und Schmerzpillen unter dem Spielernamen angezeigt - Der Fraktionschat kann individuell eingefärbt werden -- Mit `/fbank einzahlen ` kann das Eingabe GUI des Servers übersprungen werden - Für den Rettungsdienst gibt es im Herstellungs-Inventar für Medikamente einen Button, um die benötigte Anzahl an Stoffen in den Fraktionschat zu senden - Für den Dealer und Schwarzmarkt wird (in der Übersicht) angezeigt, an welchem Ort der Händler gefunden wurde diff --git a/src/main/java/de/rettichlp/ucutils/common/Storage.java b/src/main/java/de/rettichlp/ucutils/common/Storage.java index 5d83faca..da6b4a60 100644 --- a/src/main/java/de/rettichlp/ucutils/common/Storage.java +++ b/src/main/java/de/rettichlp/ucutils/common/Storage.java @@ -88,10 +88,6 @@ public class Storage { @Nullable private Vec3d dealerPosition; - @Getter - @Setter - private String fBankDepositReason = ""; - @Getter @Setter private double hydration = -1.0; @@ -149,8 +145,6 @@ public void print() { LOGGER.info("currentJob: {}", this.currentJob); // dead LOGGER.info("dead: {}", this.dead); - // fBankDepositReason - LOGGER.info("fBankDepositReason: {}", this.fBankDepositReason); // hydration LOGGER.info("hydration: {}", this.hydration); // joinTimestamp diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/CommandListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/CommandListener.java index 4c7a2700..aaba2e06 100644 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/CommandListener.java +++ b/src/main/java/de/rettichlp/ucutils/listener/impl/CommandListener.java @@ -9,7 +9,6 @@ import java.util.regex.Pattern; import static de.rettichlp.ucutils.UCUtils.commandService; -import static de.rettichlp.ucutils.UCUtils.storage; import static java.lang.Character.isUpperCase; import static java.util.regex.Pattern.compile; @@ -17,7 +16,6 @@ public class CommandListener implements ICommandSendListener { private static final Pattern COMMAND_NAVI_HOUSE_NUMBER_PATTERN = compile("^navi (?\\d+)$"); - private static final Pattern FACTION_BANK_DEPOSIT_WITH_REASON_PATTERN = compile("^fbank einzahlen (?\\d+) (?.+)$"); @Override public boolean onCommandSend(@NotNull String command) { @@ -45,15 +43,6 @@ public boolean onCommandSend(@NotNull String command) { return false; } - Matcher factionBankDepositWithReasonMatcher = FACTION_BANK_DEPOSIT_WITH_REASON_PATTERN.matcher(command); - if (factionBankDepositWithReasonMatcher.find()) { - String amount = factionBankDepositWithReasonMatcher.group("amount"); - String reason = factionBankDepositWithReasonMatcher.group("reason"); - storage.setFBankDepositReason(reason); - commandService.sendCommand("fbank einzahlen " + amount); - return false; - } - return true; } diff --git a/src/main/java/de/rettichlp/ucutils/mixin/DialogScreenMixin.java b/src/main/java/de/rettichlp/ucutils/mixin/DialogScreenMixin.java deleted file mode 100644 index 1d1a0f10..00000000 --- a/src/main/java/de/rettichlp/ucutils/mixin/DialogScreenMixin.java +++ /dev/null @@ -1,65 +0,0 @@ -package de.rettichlp.ucutils.mixin; - -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.screen.dialog.DialogScreen; -import net.minecraft.dialog.DialogActionButtonData; -import net.minecraft.dialog.action.DynamicCustomDialogAction; -import net.minecraft.dialog.type.Dialog; -import net.minecraft.dialog.type.MultiActionDialog; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.nbt.NbtElement; -import net.minecraft.network.packet.c2s.common.CustomClickActionC2SPacket; -import net.minecraft.util.Identifier; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import java.util.List; -import java.util.Optional; - -import static de.rettichlp.ucutils.UCUtils.storage; - -@Mixin(DialogScreen.class) -public abstract class DialogScreenMixin { - - @Shadow - @Final - private T dialog; - - @Inject(method = "init", at = @At("TAIL")) - public void ucutils$initTail(CallbackInfo ci) { - String fBankDepositReason = storage.getFBankDepositReason(); - if (fBankDepositReason.isBlank()) { - return; - } - - DialogScreen self = (DialogScreen) (Object) this; - - if (!(this.dialog instanceof MultiActionDialog multiActionDialog) || !self.getTitle().getString().equals("F-Bank Einzahlung")) { - return; - } - - List actions = multiActionDialog.actions(); - if (actions.isEmpty()) { - return; - } - - DialogActionButtonData dialogActionButtonData = actions.getFirst(); - if (dialogActionButtonData.action().isEmpty() || !(dialogActionButtonData.action().get() instanceof DynamicCustomDialogAction( - Identifier id, Optional additions - ))) { - return; - } - - additions.ifPresent(nbtCompound -> nbtCompound.putString("grund", fBankDepositReason)); - CustomClickActionC2SPacket customClickActionC2SPacket = new CustomClickActionC2SPacket(id, additions.map(nbt -> (NbtElement) nbt)); - - MinecraftClient client = MinecraftClient.getInstance(); - client.getNetworkHandler().sendPacket(customClickActionC2SPacket); - storage.setFBankDepositReason(""); - client.setScreen(null); - } -} diff --git a/src/main/resources/ucutils.mixins.json b/src/main/resources/ucutils.mixins.json index 86151a0f..a5f82e73 100644 --- a/src/main/resources/ucutils.mixins.json +++ b/src/main/resources/ucutils.mixins.json @@ -17,7 +17,6 @@ "ChatScreenMixin", "ClientPlayerEntityMixin", "ClientPlayNetworkHandlerMixin", - "DialogScreenMixin", "GameMenuScreenMixin", "HandledScreenMixin", "InGameHudMixin", From c508e778f92a6bbe373f71ff38e2ebb5ed7a51ac Mon Sep 17 00:00:00 2001 From: RettichLP Date: Sun, 7 Jun 2026 21:06:50 +0200 Subject: [PATCH 84/96] Remove "Admin duty" name tag option and related translations --- .../configuration/options/NameTagOptions.java | 1 - .../gui/screens/options/NameTagOptionsScreen.java | 15 ++++----------- src/main/resources/assets/ucutils/lang/de_de.json | 2 -- src/main/resources/assets/ucutils/lang/en_gb.json | 2 -- src/main/resources/assets/ucutils/lang/en_us.json | 2 -- 5 files changed, 4 insertions(+), 18 deletions(-) diff --git a/src/main/java/de/rettichlp/ucutils/common/configuration/options/NameTagOptions.java b/src/main/java/de/rettichlp/ucutils/common/configuration/options/NameTagOptions.java index 266d28b6..08546141 100644 --- a/src/main/java/de/rettichlp/ucutils/common/configuration/options/NameTagOptions.java +++ b/src/main/java/de/rettichlp/ucutils/common/configuration/options/NameTagOptions.java @@ -9,7 +9,6 @@ @Accessors(fluent = true) public class NameTagOptions { - private boolean aDuty = true; private boolean afk = true; private boolean medicalInformation = true; } diff --git a/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/NameTagOptionsScreen.java b/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/NameTagOptionsScreen.java index c29f14d4..bfcd5bff 100644 --- a/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/NameTagOptionsScreen.java +++ b/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/NameTagOptionsScreen.java @@ -14,8 +14,6 @@ public class NameTagOptionsScreen extends OptionsScreen { private static final Text TEXT_NAMETAG = translatable("ucutils.options.text.nametag"); - private static final Text NAMETAG_A_DUTY_NAME = translatable("ucutils.options.nametag.a_duty.name"); - private static final Text NAMETAG_A_DUTY_TOOLTIP = translatable("ucutils.options.nametag.a_duty.tooltip"); private static final Text NAMETAG_AFK_NAME = translatable("ucutils.options.nametag.afk.name"); private static final Text NAMETAG_AFK_TOOLTIP = translatable("ucutils.options.nametag.afk.tooltip"); private static final Text NAMETAG_MEDICAL_INFORMATION_NAME = translatable("ucutils.options.nametag.medical_information.name"); @@ -33,21 +31,16 @@ public void initBody() { NameTagOptions nameTagOptions = configuration.getOptions().nameTag(); - ToggleButtonWidget toggleButton1 = new ToggleButtonWidget(NAMETAG_A_DUTY_NAME, nameTagOptions::aDuty, nameTagOptions.aDuty()); + ToggleButtonWidget toggleButton1 = new ToggleButtonWidget(NAMETAG_AFK_NAME, nameTagOptions::afk, nameTagOptions.afk()); toggleButton1.setWidth(150); - toggleButton1.setTooltip(Tooltip.of(NAMETAG_A_DUTY_TOOLTIP)); + toggleButton1.setTooltip(Tooltip.of(NAMETAG_AFK_TOOLTIP)); gridWidgetAdder.add(toggleButton1); - ToggleButtonWidget toggleButton2 = new ToggleButtonWidget(NAMETAG_AFK_NAME, nameTagOptions::afk, nameTagOptions.afk()); + ToggleButtonWidget toggleButton2 = new ToggleButtonWidget(NAMETAG_MEDICAL_INFORMATION_NAME, nameTagOptions::medicalInformation, nameTagOptions.medicalInformation()); toggleButton2.setWidth(150); - toggleButton2.setTooltip(Tooltip.of(NAMETAG_AFK_TOOLTIP)); + toggleButton2.setTooltip(Tooltip.of(NAMETAG_MEDICAL_INFORMATION_TOOLTIP)); gridWidgetAdder.add(toggleButton2); - ToggleButtonWidget toggleButton3 = new ToggleButtonWidget(NAMETAG_MEDICAL_INFORMATION_NAME, nameTagOptions::medicalInformation, nameTagOptions.medicalInformation()); - toggleButton3.setWidth(150); - toggleButton3.setTooltip(Tooltip.of(NAMETAG_MEDICAL_INFORMATION_TOOLTIP)); - gridWidgetAdder.add(toggleButton3); - gridWidget.refreshPositions(); gridWidget.forEachChild(this::addDrawableChild); } diff --git a/src/main/resources/assets/ucutils/lang/de_de.json b/src/main/resources/assets/ucutils/lang/de_de.json index bce2ae80..65796045 100644 --- a/src/main/resources/assets/ucutils/lang/de_de.json +++ b/src/main/resources/assets/ucutils/lang/de_de.json @@ -57,8 +57,6 @@ "ucutils.options.car.automation.start.tooltip": "Startet das Auto automatisch, wenn du einsteigst", "ucutils.options.car.automation.check_kfz.name": "Automatisches /checkkfz", "ucutils.options.car.automation.check_kfz.tooltip": "Führt /checkkfz aus wenn du ein Auto rechtsklickst während du schleichst", - "ucutils.options.nametag.a_duty.name": "Admin-Dienst", - "ucutils.options.nametag.a_duty.tooltip": "Zeigt eine Information an über dem Namen von Spielern, die im Admin-Dienst sind", "ucutils.options.nametag.afk.name": "AFK", "ucutils.options.nametag.afk.tooltip": "Zeigt eine Information an über dem Namen von Spielern, die AFK sind", "ucutils.options.nametag.medical_information.name": "Information für Ärzte", diff --git a/src/main/resources/assets/ucutils/lang/en_gb.json b/src/main/resources/assets/ucutils/lang/en_gb.json index 66110ad5..20a6dbe9 100644 --- a/src/main/resources/assets/ucutils/lang/en_gb.json +++ b/src/main/resources/assets/ucutils/lang/en_gb.json @@ -57,8 +57,6 @@ "ucutils.options.car.automation.start.tooltip": "Starts the car automatically when you enter it", "ucutils.options.car.automation.check_kfz.name": "Automated /checkkfz", "ucutils.options.car.automation.check_kfz.tooltip": "Automatically executes /checkkfz when you right click your car while sneaking", - "ucutils.options.nametag.a_duty.name": "Admin duty", - "ucutils.options.nametag.a_duty.tooltip": "Shows an information above the players name of players in admin duty", "ucutils.options.nametag.afk.name": "AFK", "ucutils.options.nametag.afk.tooltip": "Shows an information above the players name of afk players", "ucutils.options.nametag.medical_information.name": "Medical information", diff --git a/src/main/resources/assets/ucutils/lang/en_us.json b/src/main/resources/assets/ucutils/lang/en_us.json index 66110ad5..20a6dbe9 100644 --- a/src/main/resources/assets/ucutils/lang/en_us.json +++ b/src/main/resources/assets/ucutils/lang/en_us.json @@ -57,8 +57,6 @@ "ucutils.options.car.automation.start.tooltip": "Starts the car automatically when you enter it", "ucutils.options.car.automation.check_kfz.name": "Automated /checkkfz", "ucutils.options.car.automation.check_kfz.tooltip": "Automatically executes /checkkfz when you right click your car while sneaking", - "ucutils.options.nametag.a_duty.name": "Admin duty", - "ucutils.options.nametag.a_duty.tooltip": "Shows an information above the players name of players in admin duty", "ucutils.options.nametag.afk.name": "AFK", "ucutils.options.nametag.afk.tooltip": "Shows an information above the players name of afk players", "ucutils.options.nametag.medical_information.name": "Medical information", From 5c3eb353a9a02f957470f16a55801bd26dd4ecbf Mon Sep 17 00:00:00 2001 From: RettichLP Date: Sun, 7 Jun 2026 21:08:19 +0200 Subject: [PATCH 85/96] Refactor `messageMatchesColor` method in `FactionListener` to simplify sibling size check logic --- .../ucutils/listener/impl/faction/FactionListener.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/faction/FactionListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/faction/FactionListener.java index 762d49bd..a80dd1ee 100644 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/faction/FactionListener.java +++ b/src/main/java/de/rettichlp/ucutils/listener/impl/faction/FactionListener.java @@ -118,7 +118,7 @@ public boolean onMessageReceive(Text text, String message) { // check if color already matches formatting List siblings = text.getSiblings(); - if (siblings.size() != 3 || messageMatchesColor(siblings, primaryFormatting, secondaryFormatting)) { + if (messageMatchesColor(siblings, primaryFormatting, secondaryFormatting)) { return true; } @@ -161,6 +161,10 @@ public boolean onMessageSend(String message) { } private boolean messageMatchesColor(@NonNull List siblings, Formatting primaryFormatting, Formatting secondaryFormatting) { + if (siblings.size() != 3) { + return false; + } + TextColor primaryFormattingCurrent = siblings.get(0).getStyle().getColor(); TextColor secondaryFormattingCurrent = siblings.get(2).getStyle().getColor(); return primaryFormattingCurrent == null || secondaryFormattingCurrent == null || primaryFormattingCurrent.getRgb() == primaryFormatting.getColorValue() || secondaryFormattingCurrent.getRgb() == secondaryFormatting.getColorValue(); From 90e7ffc9fdc3d1d43a83489e0b0f2d682b72f6fe Mon Sep 17 00:00:00 2001 From: RettichLP Date: Sun, 7 Jun 2026 22:00:11 +0200 Subject: [PATCH 86/96] Remove `IEntityRenderListener` and related entity render highlighting functionality --- .../ucutils/common/registry/Registry.java | 4 -- .../common/services/RenderService.java | 52 ------------------- .../listener/IEntityRenderListener.java | 8 --- .../ucutils/listener/impl/CarListener.java | 25 +-------- 4 files changed, 1 insertion(+), 88 deletions(-) delete mode 100644 src/main/java/de/rettichlp/ucutils/listener/IEntityRenderListener.java diff --git a/src/main/java/de/rettichlp/ucutils/common/registry/Registry.java b/src/main/java/de/rettichlp/ucutils/common/registry/Registry.java index a330914c..a2a853b2 100644 --- a/src/main/java/de/rettichlp/ucutils/common/registry/Registry.java +++ b/src/main/java/de/rettichlp/ucutils/common/registry/Registry.java @@ -4,7 +4,6 @@ import com.mojang.brigadier.builder.LiteralArgumentBuilder; import de.rettichlp.ucutils.common.models.Sound; import de.rettichlp.ucutils.listener.ICommandSendListener; -import de.rettichlp.ucutils.listener.IEntityRenderListener; import de.rettichlp.ucutils.listener.IHudRenderListener; import de.rettichlp.ucutils.listener.IMessageReceiveListener; import de.rettichlp.ucutils.listener.IMessageSendListener; @@ -16,7 +15,6 @@ import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents; import net.fabricmc.fabric.api.client.message.v1.ClientSendMessageEvents; import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback; -import net.fabricmc.fabric.api.client.rendering.v1.world.WorldRenderEvents; import org.jetbrains.annotations.NotNull; import java.util.Objects; @@ -120,8 +118,6 @@ public void registerListeners() { HudRenderCallback.EVENT.register((drawContext, tickCounter) -> getListenersImplementing(IHudRenderListener.class).forEach(iHudRenderListener -> iHudRenderListener.onHudRender(drawContext, tickCounter))); - WorldRenderEvents.AFTER_ENTITIES.register(context -> getListenersImplementing(IEntityRenderListener.class).forEach(iEntityRenderListener -> iEntityRenderListener.onEntityRender(context))); - // prevent multiple registrations of listeners this.initialized = true; } diff --git a/src/main/java/de/rettichlp/ucutils/common/services/RenderService.java b/src/main/java/de/rettichlp/ucutils/common/services/RenderService.java index 23a3068c..067cc9cd 100644 --- a/src/main/java/de/rettichlp/ucutils/common/services/RenderService.java +++ b/src/main/java/de/rettichlp/ucutils/common/services/RenderService.java @@ -6,15 +6,9 @@ import de.rettichlp.ucutils.common.gui.widgets.base.AbstractUCUtilsWidget; import de.rettichlp.ucutils.common.gui.widgets.base.UCUtilsWidget; import lombok.Getter; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.tooltip.Tooltip; import net.minecraft.client.gui.widget.CyclingButtonWidget; import net.minecraft.client.gui.widget.DirectionalLayoutWidget; -import net.minecraft.client.render.Camera; -import net.minecraft.client.render.VertexConsumerProvider; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.entity.Entity; import net.minecraft.text.Text; import org.jetbrains.annotations.NotNull; @@ -28,8 +22,6 @@ import static java.util.Comparator.comparing; import static java.util.stream.Collectors.toCollection; import static java.util.stream.StreamSupport.stream; -import static net.minecraft.client.font.TextRenderer.TextLayerType.SEE_THROUGH; -import static net.minecraft.util.math.RotationAxis.POSITIVE_Y; import static org.atteo.classindex.ClassIndex.getAnnotated; public class RenderService { @@ -39,50 +31,6 @@ public class RenderService { @Getter private LinkedHashSet> widgets = new LinkedHashSet<>(); - public void renderTextAboveEntity(@NotNull MatrixStack matrices, - VertexConsumerProvider vertexConsumers, - @NotNull Entity entity, - Text text, - float scale) { - renderTextAt(matrices, vertexConsumers, entity.getX(), entity.getY() + 1.35, entity.getZ(), text, scale); - } - - public void renderTextAt(@NotNull MatrixStack matrices, - VertexConsumerProvider vertexConsumers, - double x, - double y, - double z, - Text text, - float scale) { - // save the current matrix state - matrices.push(); - - Camera camera = MinecraftClient.getInstance().gameRenderer.getCamera(); - double camX = camera.getPos().x; - double camY = camera.getPos().y; - double camZ = camera.getPos().z; - - matrices.translate(x - camX, y - camY, z - camZ); - - // make the text face the camera - matrices.multiply(camera.getRotation()); - matrices.multiply(POSITIVE_Y.rotationDegrees(180.0F)); - - // scale the text down so it's not too big - matrices.scale(-scale, -scale, scale); - - TextRenderer textRenderer = MinecraftClient.getInstance().textRenderer; - - // calculate the width of the text to center it - float textWidth = -textRenderer.getWidth(text) / 2.0F; - - // render the text - textRenderer.draw(text, textWidth, 0.0F, 0xFFFFFFFF, false, matrices.peek().getPositionMatrix(), vertexConsumers, SEE_THROUGH, 0x55000000, 0xF000F0); - - // restore the previous matrix state - matrices.pop(); - } - public Color getSecondaryColor(@NotNull Color color) { return new Color(color.getRed() / 2, color.getGreen() / 2, color.getBlue() / 2, 100); } diff --git a/src/main/java/de/rettichlp/ucutils/listener/IEntityRenderListener.java b/src/main/java/de/rettichlp/ucutils/listener/IEntityRenderListener.java deleted file mode 100644 index 2538ff86..00000000 --- a/src/main/java/de/rettichlp/ucutils/listener/IEntityRenderListener.java +++ /dev/null @@ -1,8 +0,0 @@ -package de.rettichlp.ucutils.listener; - -import net.fabricmc.fabric.api.client.rendering.v1.world.WorldRenderContext; - -public interface IEntityRenderListener extends IUCUtilsListener { - - void onEntityRender(WorldRenderContext context); -} diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/CarListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/CarListener.java index 9a85f595..5551be01 100644 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/CarListener.java +++ b/src/main/java/de/rettichlp/ucutils/listener/impl/CarListener.java @@ -1,48 +1,25 @@ package de.rettichlp.ucutils.listener.impl; import de.rettichlp.ucutils.common.registry.UCUtilsListener; -import de.rettichlp.ucutils.listener.IEntityRenderListener; import de.rettichlp.ucutils.listener.IMessageReceiveListener; -import net.fabricmc.fabric.api.client.rendering.v1.world.WorldRenderContext; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.render.VertexConsumerProvider; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.client.world.ClientWorld; import net.minecraft.text.Text; import java.util.regex.Matcher; import java.util.regex.Pattern; import static de.rettichlp.ucutils.UCUtils.commandService; -import static de.rettichlp.ucutils.UCUtils.configuration; -import static de.rettichlp.ucutils.UCUtils.renderService; import static de.rettichlp.ucutils.UCUtils.storage; import static java.lang.Integer.parseInt; -import static java.util.Optional.ofNullable; import static java.util.regex.Pattern.compile; -import static net.minecraft.util.Formatting.AQUA; @UCUtilsListener -public class CarListener implements IEntityRenderListener, IMessageReceiveListener { +public class CarListener implements IMessageReceiveListener { private static final Pattern CAR_UNLOCK_PATTERN = compile("^\\[Car] Du hast deinen .+ aufgeschlossen\\.$"); private static final Pattern CAR_LOCK_PATTERN = compile("^\\[Car] Du hast deinen .+ abgeschlossen\\.$"); private static final Pattern CAR_LOCKED_OWN_PATTERN = compile("^\\[Car] Dein Fahrzeug ist abgeschlossen\\.$"); private static final Pattern CAR_FIND_PATTERN = compile("^\\[Car] Das Fahrzeug befindet sich bei » X: (?-?\\d+) \\| Y: (?-?\\d+) \\| Z: (?-?\\d+)$"); - @Override - public void onEntityRender(WorldRenderContext context) { - MatrixStack matrices = context.matrices(); - VertexConsumerProvider vertexConsumers = context.consumers(); - ClientWorld world = MinecraftClient.getInstance().world; - - if (world != null && configuration.getOptions().car().highlight() && !storage.isPremium()) { - ofNullable(storage.getMinecartEntityToHighlight()) - .map(minecartEntity -> world.getEntityById(minecartEntity.getId())) - .ifPresent(minecartEntity -> renderService.renderTextAboveEntity(matrices, vertexConsumers, minecartEntity, Text.of("🚗").copy().formatted(AQUA), 0.05F)); - } - } - @Override public boolean onMessageReceive(Text text, String message) { Matcher carUnlockMatcher = CAR_UNLOCK_PATTERN.matcher(message); From c9a9adbe592512ea7bcb566e5f59107b7b7de600 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Sun, 7 Jun 2026 22:02:43 +0200 Subject: [PATCH 87/96] Highlight targeted minecart entities in outline when rendering --- .../AbstractMinecartEntityRendererMixin.java | 23 +++++++++++++++++++ src/main/resources/ucutils.mixins.json | 1 + 2 files changed, 24 insertions(+) create mode 100644 src/main/java/de/rettichlp/ucutils/mixin/AbstractMinecartEntityRendererMixin.java diff --git a/src/main/java/de/rettichlp/ucutils/mixin/AbstractMinecartEntityRendererMixin.java b/src/main/java/de/rettichlp/ucutils/mixin/AbstractMinecartEntityRendererMixin.java new file mode 100644 index 00000000..8b555263 --- /dev/null +++ b/src/main/java/de/rettichlp/ucutils/mixin/AbstractMinecartEntityRendererMixin.java @@ -0,0 +1,23 @@ +package de.rettichlp.ucutils.mixin; + +import net.minecraft.client.render.entity.AbstractMinecartEntityRenderer; +import net.minecraft.client.render.entity.state.MinecartEntityRenderState; +import net.minecraft.entity.vehicle.AbstractMinecartEntity; +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; + +import static de.rettichlp.ucutils.UCUtils.storage; + +@Mixin(AbstractMinecartEntityRenderer.class) +public class AbstractMinecartEntityRendererMixin { + + @Inject(method = "updateRenderState(Lnet/minecraft/entity/vehicle/AbstractMinecartEntity;Lnet/minecraft/client/render/entity/state/MinecartEntityRenderState;F)V", + at = @At("TAIL")) + private void ucutils$updateRenderStateTail(T entity, S state, float tickDelta, CallbackInfo ci) { + if (storage.getMinecartEntityToHighlight() != null && storage.getMinecartEntityToHighlight().getUuid().equals(entity.getUuid())) { + state.outlineColor = 0xFFFFAA00; + } + } +} diff --git a/src/main/resources/ucutils.mixins.json b/src/main/resources/ucutils.mixins.json index a5f82e73..085e908f 100644 --- a/src/main/resources/ucutils.mixins.json +++ b/src/main/resources/ucutils.mixins.json @@ -14,6 +14,7 @@ "requireAnnotations": true }, "client": [ + "AbstractMinecartEntityRendererMixin", "ChatScreenMixin", "ClientPlayerEntityMixin", "ClientPlayNetworkHandlerMixin", From 510721e21dc651a28ad9a5786678872df49c95e4 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Sun, 7 Jun 2026 22:04:12 +0200 Subject: [PATCH 88/96] Remove unused `getCachedFaction` method from `Storage` --- src/main/java/de/rettichlp/ucutils/common/Storage.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/main/java/de/rettichlp/ucutils/common/Storage.java b/src/main/java/de/rettichlp/ucutils/common/Storage.java index da6b4a60..1851bc70 100644 --- a/src/main/java/de/rettichlp/ucutils/common/Storage.java +++ b/src/main/java/de/rettichlp/ucutils/common/Storage.java @@ -27,10 +27,8 @@ import java.util.Set; import static de.rettichlp.ucutils.UCUtils.LOGGER; -import static de.rettichlp.ucutils.UCUtils.storage; import static de.rettichlp.ucutils.common.Storage.ToggledChat.NONE; import static de.rettichlp.ucutils.common.models.Faction.NULL; -import static java.util.Optional.ofNullable; import static net.minecraft.text.Text.translatable; public class Storage { @@ -161,10 +159,6 @@ public void print() { LOGGER.info("unicaCity: {}", this.unicaCity); } - public Faction getCachedFaction(String playerName) { - return ofNullable(this.playerFactionCache.get(playerName)).orElseGet(() -> storage.getFaction(playerName)); - } - public Faction getFaction(String playerName) { Faction faction = this.factionEntries.stream() .filter(factionEntry -> factionEntry.members().stream() From 728597d4c52145286c5e635cb2e512af432b28e4 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Sun, 7 Jun 2026 22:24:50 +0200 Subject: [PATCH 89/96] Restructure car options screen and remove related translations --- .../gui/screens/options/CarOptionsScreen.java | 65 ++++++++++++------- .../AbstractMinecartEntityRendererMixin.java | 9 +++ .../resources/assets/ucutils/lang/de_de.json | 1 - .../resources/assets/ucutils/lang/en_gb.json | 1 - .../resources/assets/ucutils/lang/en_us.json | 1 - 5 files changed, 49 insertions(+), 28 deletions(-) diff --git a/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/CarOptionsScreen.java b/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/CarOptionsScreen.java index a57e91f5..fe67b22f 100644 --- a/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/CarOptionsScreen.java +++ b/src/main/java/de/rettichlp/ucutils/common/gui/screens/options/CarOptionsScreen.java @@ -1,24 +1,22 @@ package de.rettichlp.ucutils.common.gui.screens.options; +import de.rettichlp.ucutils.common.configuration.options.CarOptions; import de.rettichlp.ucutils.common.gui.screens.OptionsScreen; +import de.rettichlp.ucutils.common.gui.screens.components.ToggleButtonWidget; import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.widget.DirectionalLayoutWidget; +import net.minecraft.client.gui.tooltip.Tooltip; +import net.minecraft.client.gui.widget.GridWidget; import net.minecraft.client.gui.widget.MultilineTextWidget; -import net.minecraft.client.gui.widget.Positioner; -import net.minecraft.client.gui.widget.TextWidget; import net.minecraft.text.Text; -import static de.rettichlp.ucutils.UCUtils.renderService; -import static net.minecraft.client.gui.widget.DirectionalLayoutWidget.horizontal; -import static net.minecraft.client.gui.widget.DirectionalLayoutWidget.vertical; +import static de.rettichlp.ucutils.UCUtils.configuration; +import static net.minecraft.client.gui.widget.Positioner.create; import static net.minecraft.text.Text.translatable; import static net.minecraft.util.Formatting.GOLD; public class CarOptionsScreen extends OptionsScreen { private static final Text TEXT_CAR = translatable("ucutils.options.text.car"); - private static final Text TEXT_GENERAL = translatable("ucutils.options.text.general"); - private static final Text TEXT_AUTOMATION = translatable("ucutils.options.text.automation"); private static final Text CAR_PREMIUM_INFO = translatable("ucutils.options.car.premium_info"); private static final Text CAR_GENERAL_FAST_FIND_NAME = translatable("ucutils.options.car.general.fast_find.name"); private static final Text CAR_GENERAL_FAST_FIND_TOOLTIP = translatable("ucutils.options.car.general.fast_find.tooltip"); @@ -39,30 +37,47 @@ public CarOptionsScreen(Screen parent) { @Override public void initBody() { - DirectionalLayoutWidget directionalLayoutWidget = this.layout.addBody(vertical().spacing(4)); + GridWidget gridWidget = this.layout.addBody(new GridWidget()); + gridWidget.setColumnSpacing(8).setRowSpacing(4); + GridWidget.Adder gridWidgetAdder = gridWidget.createAdder(2); - MultilineTextWidget multilineTextWidget = directionalLayoutWidget.add(new MultilineTextWidget(CAR_PREMIUM_INFO.copy().formatted(GOLD), this.textRenderer), Positioner::alignHorizontalCenter); - multilineTextWidget.setMaxWidth(308); - multilineTextWidget.setCentered(true); + CarOptions carOptions = configuration.getOptions().car(); + + ToggleButtonWidget toggleButton1 = new ToggleButtonWidget(CAR_GENERAL_HIGHLIGHT_NAME, carOptions::highlight, carOptions.highlight()); + toggleButton1.setWidth(150); + toggleButton1.setTooltip(Tooltip.of(CAR_GENERAL_HIGHLIGHT_TOOLTIP)); + gridWidgetAdder.add(toggleButton1); - directionalLayoutWidget.add(new TextWidget(TEXT_GENERAL, this.textRenderer), Positioner::alignHorizontalCenter); + ToggleButtonWidget toggleButton2 = new ToggleButtonWidget(CAR_GENERAL_FAST_FIND_NAME, carOptions::fastFind, carOptions.fastFind()); + toggleButton2.setWidth(150); + toggleButton2.setTooltip(Tooltip.of(CAR_GENERAL_FAST_FIND_TOOLTIP)); + gridWidgetAdder.add(toggleButton2); - DirectionalLayoutWidget directionalLayoutWidget1 = directionalLayoutWidget.add(horizontal().spacing(8)); - renderService.addToggleButton(directionalLayoutWidget1, CAR_GENERAL_FAST_FIND_NAME, CAR_GENERAL_FAST_FIND_TOOLTIP, (options, value) -> options.car().fastFind(value), options -> options.car().fastFind(), 150); - renderService.addToggleButton(directionalLayoutWidget1, CAR_GENERAL_FAST_LOCK_NAME, CAR_GENERAL_FAST_LOCK_TOOLTIP, (options, value) -> options.car().fastLock(value), options -> options.car().fastLock(), 150); + ToggleButtonWidget toggleButton3 = new ToggleButtonWidget(CAR_AUTOMATION_CHECK_KFZ_NAME, carOptions::automatedCheckKfz, carOptions.automatedCheckKfz()); + toggleButton3.setWidth(150); + toggleButton3.setTooltip(Tooltip.of(CAR_AUTOMATION_CHECK_KFZ_TOOLTIP)); + gridWidgetAdder.add(toggleButton3); - DirectionalLayoutWidget directionalLayoutWidget2 = directionalLayoutWidget.add(horizontal().spacing(8)); - renderService.addToggleButton(directionalLayoutWidget2, CAR_GENERAL_HIGHLIGHT_NAME, CAR_GENERAL_HIGHLIGHT_TOOLTIP, (options, value) -> options.car().highlight(value), options -> options.car().highlight(), 150); + MultilineTextWidget multilineTextWidget = gridWidgetAdder.add(new MultilineTextWidget(CAR_PREMIUM_INFO.copy().formatted(GOLD), this.textRenderer), 2, create().alignHorizontalCenter().marginTop(16)); + multilineTextWidget.setMaxWidth(308); + multilineTextWidget.setCentered(true); - directionalLayoutWidget.add(new TextWidget(TEXT_AUTOMATION, this.textRenderer), positioner -> positioner.alignHorizontalCenter().marginTop(16)); + ToggleButtonWidget toggleButton4 = new ToggleButtonWidget(CAR_GENERAL_FAST_LOCK_NAME, carOptions::fastLock, carOptions.fastLock()); + toggleButton4.setWidth(150); + toggleButton4.setTooltip(Tooltip.of(CAR_GENERAL_FAST_LOCK_TOOLTIP)); + gridWidgetAdder.add(toggleButton4); - DirectionalLayoutWidget directionalLayoutWidget3 = directionalLayoutWidget.add(horizontal().spacing(8)); - renderService.addToggleButton(directionalLayoutWidget3, CAR_AUTOMATION_LOCK_NAME, CAR_AUTOMATION_LOCK_TOOLTIP, (options, value) -> options.car().automatedLock(value), options -> options.car().automatedLock(), 150); - renderService.addToggleButton(directionalLayoutWidget3, CAR_AUTOMATION_START_NAME, CAR_AUTOMATION_START_TOOLTIP, (options, value) -> options.car().automatedStart(value), options -> options.car().automatedStart(), 150); + ToggleButtonWidget toggleButton5 = new ToggleButtonWidget(CAR_AUTOMATION_LOCK_NAME, carOptions::automatedLock, carOptions.automatedLock()); + toggleButton5.setWidth(150); + toggleButton5.setTooltip(Tooltip.of(CAR_AUTOMATION_LOCK_TOOLTIP)); + gridWidgetAdder.add(toggleButton5); - DirectionalLayoutWidget directionalLayoutWidget4 = directionalLayoutWidget.add(horizontal().spacing(8)); - renderService.addToggleButton(directionalLayoutWidget4, CAR_AUTOMATION_CHECK_KFZ_NAME, CAR_AUTOMATION_CHECK_KFZ_TOOLTIP, (options, value) -> options.car().automatedCheckKfz(value), options -> options.car().automatedCheckKfz(), 150); + ToggleButtonWidget toggleButton6 = new ToggleButtonWidget(CAR_AUTOMATION_START_NAME, carOptions::automatedStart, carOptions.automatedStart()); + toggleButton6.setWidth(150); + toggleButton6.setTooltip(Tooltip.of(CAR_AUTOMATION_START_TOOLTIP)); + gridWidgetAdder.add(toggleButton6); - directionalLayoutWidget.forEachChild(this::addDrawableChild); + gridWidget.refreshPositions(); + gridWidget.forEachChild(this::addDrawableChild); } } diff --git a/src/main/java/de/rettichlp/ucutils/mixin/AbstractMinecartEntityRendererMixin.java b/src/main/java/de/rettichlp/ucutils/mixin/AbstractMinecartEntityRendererMixin.java index 8b555263..c68410d7 100644 --- a/src/main/java/de/rettichlp/ucutils/mixin/AbstractMinecartEntityRendererMixin.java +++ b/src/main/java/de/rettichlp/ucutils/mixin/AbstractMinecartEntityRendererMixin.java @@ -8,6 +8,7 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import static de.rettichlp.ucutils.UCUtils.configuration; import static de.rettichlp.ucutils.UCUtils.storage; @Mixin(AbstractMinecartEntityRenderer.class) @@ -16,6 +17,14 @@ public class AbstractMinecartEntityRendererMixin Date: Sun, 7 Jun 2026 21:14:28 +0000 Subject: [PATCH 90/96] Update loom_version to v1.17.2 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index d13560a3..8e8e0e2c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,7 +10,7 @@ org.gradle.configuration-cache=false minecraft_version=1.21.10 yarn_mappings=1.21.10+build.3 loader_version=0.19.2 -loom_version=1.17.1 +loom_version=1.17.2 # Mod Properties mod_version=0.0.0 From 065e1cd5b8cb7404d8d2ac813684b1fe3dd74731 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Sun, 7 Jun 2026 23:14:55 +0200 Subject: [PATCH 91/96] Simplify black market dealer entry pattern in `BadFactionListener` --- .../ucutils/listener/impl/faction/BadFactionListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/faction/BadFactionListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/faction/BadFactionListener.java index 260bf97a..7a0502cc 100644 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/faction/BadFactionListener.java +++ b/src/main/java/de/rettichlp/ucutils/listener/impl/faction/BadFactionListener.java @@ -21,7 +21,7 @@ @UCUtilsListener public class BadFactionListener implements IMessageReceiveListener { - private static final Pattern BLACK_MARKET_DEALER_ENTRY_PATTERN = compile("^» (?.+) – (gerade eben|vor \\d+ min|vor \\d+ std) {2}\\[Navi]$"); + private static final Pattern BLACK_MARKET_DEALER_ENTRY_PATTERN = compile("^» (?.+) – (gerade eben|vor \\d+ \\w+) {2}\\[Navi]$"); @Override public boolean onMessageReceive(Text text, String message) { From 6c1e3ff1d1ee7ca44eac376d3d88e6d8995c0e8c Mon Sep 17 00:00:00 2001 From: RettichLP Date: Sun, 7 Jun 2026 23:18:34 +0200 Subject: [PATCH 92/96] Add check to prevent redundant notifications for dealer positions in `ClientPlayNetworkHandlerMixin` --- .../ucutils/mixin/ClientPlayNetworkHandlerMixin.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/de/rettichlp/ucutils/mixin/ClientPlayNetworkHandlerMixin.java b/src/main/java/de/rettichlp/ucutils/mixin/ClientPlayNetworkHandlerMixin.java index e1c06d32..ee81c8d5 100644 --- a/src/main/java/de/rettichlp/ucutils/mixin/ClientPlayNetworkHandlerMixin.java +++ b/src/main/java/de/rettichlp/ucutils/mixin/ClientPlayNetworkHandlerMixin.java @@ -86,6 +86,12 @@ private void onEntityTrackerUpdate(EntityTrackerUpdateS2CPacket packet, Callback String customNameString = requireNonNull(villager.getCustomName()).getString(); Vec3d entityPos = villager.getEntityPos(); + + // already notified check + if (entityPos.equals(storage.getDealerPosition()) || entityPos.equals(storage.getBlackMarketPosition())) { + return; + } + switch (customNameString) { case "Dealer" -> { storage.setBlackMarketPosition(entityPos); From 7e811635f9e23ad8867aaa36e685ad0f2b2736cc Mon Sep 17 00:00:00 2001 From: RettichLP Date: Mon, 8 Jun 2026 00:10:49 +0200 Subject: [PATCH 93/96] Revert 'Refactor `messageMatchesColor` method in `FactionListener` to simplify sibling size check logic' --- .../ucutils/listener/impl/faction/FactionListener.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/faction/FactionListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/faction/FactionListener.java index a80dd1ee..762d49bd 100644 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/faction/FactionListener.java +++ b/src/main/java/de/rettichlp/ucutils/listener/impl/faction/FactionListener.java @@ -118,7 +118,7 @@ public boolean onMessageReceive(Text text, String message) { // check if color already matches formatting List siblings = text.getSiblings(); - if (messageMatchesColor(siblings, primaryFormatting, secondaryFormatting)) { + if (siblings.size() != 3 || messageMatchesColor(siblings, primaryFormatting, secondaryFormatting)) { return true; } @@ -161,10 +161,6 @@ public boolean onMessageSend(String message) { } private boolean messageMatchesColor(@NonNull List siblings, Formatting primaryFormatting, Formatting secondaryFormatting) { - if (siblings.size() != 3) { - return false; - } - TextColor primaryFormattingCurrent = siblings.get(0).getStyle().getColor(); TextColor secondaryFormattingCurrent = siblings.get(2).getStyle().getColor(); return primaryFormattingCurrent == null || secondaryFormattingCurrent == null || primaryFormattingCurrent.getRgb() == primaryFormatting.getColorValue() || secondaryFormattingCurrent.getRgb() == secondaryFormatting.getColorValue(); From 52a46a3c6121053c1c177c4f3e3708b7833e3d04 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Mon, 8 Jun 2026 00:10:59 +0200 Subject: [PATCH 94/96] Adjust auto features in README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f8c152d0..b6d26a35 100644 --- a/README.md +++ b/README.md @@ -25,14 +25,15 @@ reibungsloser und angenehmer gestalten. ### Auto +- Das zuletzt gefahrene Fahrzeug wird besonders hervorgehoben - Beim Suchen seines Fahrzeugs (`/car find`) wird automatisch das erste Fahrzeug ausgewählt - Werden die Koordinaten eines Autos angezeigt, wird automatisch eine Navigation zu diesen gestartet +- Wenn man schleicht und ein Auto rechtsklickt, wird `/checkkfz` ausgeführt Folgende Funktionen sind nur für Spieler ohne Premium-Rang verfügbar, da Spieler mit Premium diese Funktion vom Server aus können: - Das Auf-/Abschließen eines Fahrzeuges wurde teilweise automatisiert (automatisches Klicken des Items im Inventar) - Beim Rechtsklick auf das eigene Fahrzeug wird automatisch `/car lock` ausgeführt - Steigt man in ein Fahrzeug ein, wird dieses automatisch gestartet und abgeschlossen -- Das zuletzt gefahrene Fahrzeug wird mit einem Symbol markiert ### Fraktionen From caa908975705c4a245221153a0fea6ee0a1bd6d7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 8 Jun 2026 11:13:00 +0000 Subject: [PATCH 95/96] Update loom_version to v1.17.3 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 8e8e0e2c..77e4da71 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,7 +10,7 @@ org.gradle.configuration-cache=false minecraft_version=1.21.10 yarn_mappings=1.21.10+build.3 loader_version=0.19.2 -loom_version=1.17.2 +loom_version=1.17.3 # Mod Properties mod_version=0.0.0 From 0a0bc471694d3ea6e82635b6caa92558447e9135 Mon Sep 17 00:00:00 2001 From: RettichLP Date: Mon, 8 Jun 2026 14:54:44 +0200 Subject: [PATCH 96/96] Pathfinding: Adjust AnglerListener captcha handling and refine captcha image processing paths --- .../listener/impl/job/AnglerListener.java | 20 +++++++++---------- .../ucutils/mixin/InGameHudMixin.java | 5 +++-- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/main/java/de/rettichlp/ucutils/listener/impl/job/AnglerListener.java b/src/main/java/de/rettichlp/ucutils/listener/impl/job/AnglerListener.java index a8a2b70a..33e683c1 100644 --- a/src/main/java/de/rettichlp/ucutils/listener/impl/job/AnglerListener.java +++ b/src/main/java/de/rettichlp/ucutils/listener/impl/job/AnglerListener.java @@ -18,6 +18,7 @@ import static de.rettichlp.ucutils.UCUtils.LOGGER; import static de.rettichlp.ucutils.UCUtils.player; import static de.rettichlp.ucutils.UCUtils.storage; +import static de.rettichlp.ucutils.UCUtils.utilService; import static java.awt.image.BufferedImage.TYPE_INT_RGB; import static java.util.regex.Pattern.compile; import static javax.imageio.ImageIO.write; @@ -31,7 +32,7 @@ @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_PATTERN = compile("^Lies den Code auf der Karte in deiner Nebenhand ab und schreib ihn in den Chat\\.$"); private static final Pattern ANGLER_CAPTCHA_CONTINUED_PATTERN = compile("^Deine Combo wurde fortgesetzt! \\(\\d+\\)$"); @Override @@ -40,15 +41,14 @@ public boolean onMessageReceive(Text text, String message) { 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); + utilService.delayedAction(() -> { + ItemStack offHandStack = player.getOffHandStack(); + if (offHandStack.isOf(FILLED_MAP)) { + MapIdComponent captchaMap = offHandStack.get(MAP_ID); + storage.setCaptchaMap(captchaMap); + saveCaptchaImage(captchaMap); + } + }, 500); return true; } diff --git a/src/main/java/de/rettichlp/ucutils/mixin/InGameHudMixin.java b/src/main/java/de/rettichlp/ucutils/mixin/InGameHudMixin.java index 50c27a29..5a62d371 100644 --- a/src/main/java/de/rettichlp/ucutils/mixin/InGameHudMixin.java +++ b/src/main/java/de/rettichlp/ucutils/mixin/InGameHudMixin.java @@ -36,6 +36,7 @@ import static java.lang.System.currentTimeMillis; import static java.nio.file.Files.newInputStream; import static net.minecraft.client.gl.RenderPipelines.GUI_TEXTURED; +import static net.minecraft.client.texture.NativeImage.read; import static net.minecraft.item.Items.GOLDEN_HOE; import static net.minecraft.registry.tag.FluidTags.WATER; import static org.spongepowered.asm.mixin.injection.At.Shift.AFTER; @@ -69,8 +70,8 @@ public abstract class InGameHudMixin { } NativeImage nativeImage; - try (InputStream is = newInputStream(Path.of("captcha.png"))) { - nativeImage = NativeImage.read(is); + try (InputStream is = newInputStream(Path.of("screenshots/ucutils/captcha.png"))) { + nativeImage = read(is); } catch (Exception e) { LOGGER.error("Failed to read captcha image", e); return;