Skip to content

Commit 7a82007

Browse files
committed
Handle creative mode item throw throttling, improve help messages
1 parent 5b5fe3c commit 7a82007

File tree

14 files changed

+105
-77
lines changed

14 files changed

+105
-77
lines changed

src/main/java/net/earthcomputer/clientcommands/features/CCrackRng.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,8 @@ protected void onSuccess() {
4848
}
4949

5050
@Override
51-
protected void onFailedToThrowItem() {
52-
Minecraft.getInstance().gui.getChat().addMessage(Component.translatable("itemCrack.notEnoughItems").withStyle(ChatFormatting.RED));
53-
EnchantmentCracker.LOGGER.info("Unable to use rng SeedCracker |not enough items|");
51+
protected void onFailedToThrowItem(PlayerRandCracker.ThrowItemsResult throwItemsResult) {
52+
super.onFailedToThrowItem(throwItemsResult);
5453
Configs.playerCrackState = PlayerRandCracker.CrackState.UNCRACKED;
5554
currentTaskName = null;
5655
}

src/main/java/net/earthcomputer/clientcommands/features/ChorusManipulation.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,8 @@ public static boolean onEat(Vec3 pos, int particleCount, int itemUseTimeLeft) {
125125
return false;
126126
}
127127
}, Configs.getMaxChorusItemThrows());
128-
if (!throwItemsState.getType().isSuccess()) {
129-
sendError(throwItemsState.getMessage());
128+
if (!throwItemsState.isSuccess()) {
129+
throwItemsState.sendErrorMessage();
130130
Minecraft.getInstance().gui.setOverlayMessage(
131131
Component.translatable("chorusManip.landing.failed").withStyle(ChatFormatting.RED), false);
132132
return false;

src/main/java/net/earthcomputer/clientcommands/features/PlayerRandCracker.java

Lines changed: 77 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
import net.earthcomputer.clientcommands.interfaces.ICreativeSlot;
1010
import net.minecraft.ChatFormatting;
1111
import net.minecraft.client.Minecraft;
12+
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
13+
import net.minecraft.client.gui.screens.inventory.CreativeModeInventoryScreen;
14+
import net.minecraft.client.multiplayer.MultiPlayerGameMode;
1215
import net.minecraft.client.player.LocalPlayer;
1316
import net.minecraft.core.component.DataComponents;
1417
import net.minecraft.network.chat.Component;
@@ -38,6 +41,7 @@
3841
import java.util.OptionalLong;
3942
import java.util.Random;
4043
import java.util.concurrent.atomic.AtomicLong;
44+
import java.util.function.Function;
4145
import java.util.function.Predicate;
4246
import java.util.stream.Collectors;
4347

@@ -326,20 +330,24 @@ public static void onItemDamage(int amount, LivingEntity holder, ItemStack stack
326330
}
327331

328332
if (Configs.infiniteTools && Configs.playerCrackState.knowsSeed()) {
329-
int unbreakingLevel_f = unbreakingLevel;
330-
Runnable action = () -> throwItemsUntil(rand -> {
331-
for (int i = 0; i < amount; i++) {
332-
Equippable equippableComponent = stack.get(DataComponents.EQUIPPABLE);
333-
boolean isArmor = equippableComponent != null && equippableComponent.damageOnHurt();
334-
if (isArmor && rand.nextFloat() < 0.6) {
335-
return false;
336-
}
337-
if (rand.nextInt(unbreakingLevel_f + 1) == 0) {
338-
return false;
333+
Runnable action = () -> {
334+
ThrowItemsResult result = throwItemsUntil(rand -> {
335+
for (int i = 0; i < amount; i++) {
336+
Equippable equippableComponent = stack.get(DataComponents.EQUIPPABLE);
337+
boolean isArmor = equippableComponent != null && equippableComponent.damageOnHurt();
338+
if (isArmor && rand.nextFloat() < 0.6) {
339+
return false;
340+
}
341+
if (rand.nextInt(unbreakingLevel + 1) == 0) {
342+
return false;
343+
}
339344
}
345+
return true;
346+
}, 64);
347+
if (!result.isSuccess()) {
348+
result.sendErrorMessage();
340349
}
341-
return true;
342-
}, 64);
350+
};
343351
if (isPredictingBlockBreaking) {
344352
postBlockBreakPredictAction = action;
345353
} else {
@@ -403,26 +411,45 @@ public static ThrowItemsResult throwItemsUntil(Predicate<Random> condition, int
403411
return new ThrowItemsResult(ThrowItemsResult.Type.NOT_POSSIBLE, itemsNeeded);
404412
}
405413
for (int i = 0; i < itemsNeeded; i++) {
406-
if (!throwItem()) {
407-
return new ThrowItemsResult(ThrowItemsResult.Type.NOT_ENOUGH_ITEMS, i, itemsNeeded);
414+
ThrowItemsResult result = throwItem();
415+
if (!result.isSuccess()) {
416+
return result;
408417
}
409418
}
410419

411420
return new ThrowItemsResult(ThrowItemsResult.Type.SUCCESS);
412421
}
413422

414-
public static boolean throwItem() {
415-
LocalPlayer player = Minecraft.getInstance().player;
423+
public static ThrowItemsResult throwItem() {
424+
Minecraft mc = Minecraft.getInstance();
425+
LocalPlayer player = mc.player;
426+
MultiPlayerGameMode interactionManager = mc.gameMode;
427+
assert player != null && interactionManager != null;
428+
429+
boolean isInContainer = mc.screen instanceof AbstractContainerScreen && !(mc.screen instanceof CreativeModeInventoryScreen);
430+
boolean useCreativeThrow = player.hasInfiniteMaterials() && !isInContainer;
431+
if (useCreativeThrow) {
432+
// the client throttle is set a bit below the server throttle so we shouldn't get a desync here
433+
if (!player.canDropItems()) {
434+
return new ThrowItemsResult(ThrowItemsResult.Type.THROTTLED);
435+
}
436+
437+
expectedThrows++;
438+
ItemStack stackToDrop = new ItemStack(Items.COBBLESTONE);
439+
player.drop(stackToDrop, true);
440+
interactionManager.handleCreativeModeItemDrop(stackToDrop);
441+
return new ThrowItemsResult(ThrowItemsResult.Type.SUCCESS);
442+
}
416443

417444
Slot matchingSlot = getBestItemThrowSlot(player.containerMenu.slots);
418445
if (matchingSlot == null) {
419-
return false;
446+
return new ThrowItemsResult(ThrowItemsResult.Type.NOT_ENOUGH_ITEMS);
420447
}
421448
expectedThrows++;
422-
Minecraft.getInstance().gameMode.handleInventoryMouseClick(player.containerMenu.containerId,
449+
interactionManager.handleInventoryMouseClick(player.containerMenu.containerId,
423450
matchingSlot.index, 0, ClickType.THROW, player);
424451

425-
return true;
452+
return new ThrowItemsResult(ThrowItemsResult.Type.SUCCESS);
426453
}
427454

428455
public static void unthrowItem() {
@@ -453,7 +480,6 @@ public static Slot getBestItemThrowSlot(List<Slot> slots) {
453480
if (itemCounts.isEmpty()) {
454481
return null;
455482
}
456-
//noinspection OptionalGetWithoutIsPresent
457483
Item preferredItem = itemCounts.keySet().stream().max(Comparator.comparingInt(Item::getDefaultMaxStackSize).thenComparing(itemCounts::get)).get();
458484
//noinspection OptionalGetWithoutIsPresent
459485
return slots.stream().filter(slot -> slot.getItem().getItem() == preferredItem).findFirst().get();
@@ -488,47 +514,59 @@ public static OptionalLong getSeed(Random rand) {
488514

489515
public static class ThrowItemsResult {
490516
private final Type type;
491-
private final MutableComponent message;
517+
private final Object[] messageArgs;
492518

493-
public ThrowItemsResult(Type type, Object... args) {
519+
public ThrowItemsResult(Type type, Object... messageArgs) {
494520
this.type = type;
495-
this.message = Component.translatable(type.getTranslationKey(), args);
521+
this.messageArgs = messageArgs;
522+
}
523+
524+
public boolean isSuccess() {
525+
return type.success;
496526
}
497527

498528
public Type getType() {
499529
return type;
500530
}
501531

502-
public MutableComponent getMessage() {
503-
return message;
532+
public void sendErrorMessage() {
533+
for (MutableComponent message : type.messageCreator.apply(messageArgs)) {
534+
ClientCommandHelper.sendFeedback(message);
535+
}
504536
}
505537

506538
public enum Type {
507-
NOT_ENOUGH_ITEMS(false, "playerManip.notEnoughItems"),
539+
NOT_ENOUGH_ITEMS(false, args -> List.of(
540+
Component.translatable("playerManip.notEnoughItems", args).withStyle(ChatFormatting.RED),
541+
Component.translatable("playerManip.notEnoughItems.help").withStyle(ChatFormatting.AQUA)
542+
)),
508543
NOT_POSSIBLE(false, "playerManip.throwError"),
509-
UNKNOWN_SEED(false, "playerManip.uncracked"),
510-
SUCCESS(true, null),
544+
THROTTLED(false, args -> List.of(
545+
Component.translatable("playerManip.throttled", args).withStyle(ChatFormatting.RED),
546+
Component.translatable("playerManip.throttled.help").withStyle(ChatFormatting.AQUA)
547+
)),
548+
UNKNOWN_SEED(false, args -> List.of(Component.translatable("playerManip.uncracked")
549+
.append(" ")
550+
.append(ClientCommandHelper.getCommandTextComponent("commands.client.crack", "/ccrackrng"))
551+
.withStyle(ChatFormatting.RED))),
552+
SUCCESS(true, (Function<Object[], List<MutableComponent>>) null),
511553
;
512554

513555
private final boolean success;
514-
private final String translationKey;
556+
private final Function<Object[], List<MutableComponent>> messageCreator;
515557

516-
Type(boolean success, String translationKey) {
517-
this.success = success;
518-
this.translationKey = translationKey;
558+
Type(boolean success, @Translatable String translationKey) {
559+
this(success, args -> List.of(Component.translatable(translationKey, args).withStyle(ChatFormatting.RED)));
519560
}
520561

521-
public boolean isSuccess() {
522-
return success;
523-
}
524-
525-
public String getTranslationKey() {
526-
return translationKey;
562+
Type(boolean success, Function<Object[], List<MutableComponent>> messageCreator) {
563+
this.success = success;
564+
this.messageCreator = messageCreator;
527565
}
528566
}
529567
}
530568

531-
public static enum CrackState implements StringRepresentable {
569+
public enum CrackState implements StringRepresentable {
532570
UNCRACKED("uncracked"),
533571
CRACKED("cracked", true),
534572
ENCH_CRACKING_1("ench_cracking_1"),

src/main/java/net/earthcomputer/clientcommands/task/ItemThrowTask.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import org.slf4j.Logger;
1313

1414
import java.lang.ref.WeakReference;
15+
import java.util.EnumSet;
1516
import java.util.Set;
1617

1718
public class ItemThrowTask extends SimpleTask {
@@ -36,6 +37,7 @@ public class ItemThrowTask extends SimpleTask {
3637
private float itemThrowsAllowedThisTick;
3738
private boolean waitingFence = false;
3839
private boolean failed = false;
40+
private final Set<PlayerRandCracker.ThrowItemsResult.Type> errorTypesHappened = EnumSet.noneOf(PlayerRandCracker.ThrowItemsResult.Type.class);
3941

4042
public ItemThrowTask(int itemsToThrow) {
4143
this(itemsToThrow, 0);
@@ -57,13 +59,14 @@ protected void onTick() {
5759

5860
while (((flags & FLAG_URGENT) != 0 || itemThrowsAllowedThisTick >= 1) && sentItemThrows < totalItemsToThrow) {
5961
itemThrowsAllowedThisTick--;
60-
if (!PlayerRandCracker.throwItem()) {
62+
PlayerRandCracker.ThrowItemsResult throwItemsResult = PlayerRandCracker.throwItem();
63+
if (!throwItemsResult.isSuccess()) {
64+
onFailedToThrowItem(throwItemsResult);
6165
if ((flags & FLAG_WAIT_FOR_ITEMS) != 0) {
6266
return;
6367
}
6468
failed = true;
6569
_break();
66-
onFailedToThrowItem();
6770
return;
6871
}
6972
onItemThrown(++sentItemThrows, totalItemsToThrow);
@@ -102,7 +105,12 @@ public Set<Object> getMutexKeys() {
102105
return MUTEX_KEYS;
103106
}
104107

105-
protected void onFailedToThrowItem() {
108+
protected void onFailedToThrowItem(PlayerRandCracker.ThrowItemsResult throwItemsResult) {
109+
if (throwItemsResult.getType() != PlayerRandCracker.ThrowItemsResult.Type.NOT_ENOUGH_ITEMS || (flags & FLAG_WAIT_FOR_ITEMS) == 0) {
110+
if (errorTypesHappened.add(throwItemsResult.getType())) {
111+
throwItemsResult.sendErrorMessage();
112+
}
113+
}
106114
}
107115

108116
protected void onSuccess() {

src/main/resources/assets/clientcommands/lang/de_de.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -282,9 +282,7 @@
282282
"enchCrack.xpSeed.many": "Anzahl der möglichen XP-Seeds: %s",
283283
"enchCrack.xpSeed.one": "XP-Seed: %s",
284284

285-
"itemCrack.notEnoughItems": "Kann RNG-SeedCracker nicht benutzen: Nicht genug Gegenstände in der Hand des Spielers",
286-
287-
"playerManip.notEnoughItems": "Nicht genug Gegenstände (%s von %s), um Seed zu manipulieren",
285+
"playerManip.notEnoughItems": "Nicht genug Gegenstände, um Seed zu manipulieren",
288286
"playerManip.reset": "Starte Spieler-RNG-Manipulation neu. Grund: %s",
289287
"playerManip.reset.advancement": "Fortschritt erzielt",
290288
"playerManip.reset.amethystChime": "Auf einen Amethystkristall gestiegen",

src/main/resources/assets/clientcommands/lang/en_us.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -345,13 +345,12 @@
345345
"enchCrack.xpSeed.many": "Possible XP seeds: %s",
346346
"enchCrack.xpSeed.one": "XP Seed: %s",
347347

348-
"itemCrack.notEnoughItems": "Unable to use RNG SeedCracker: Not Enough Items in Player Hand",
349-
350348
"minesweeperGame.minesLeft": "Mines Left: %s",
351349
"minesweeperGame.timePlayed": "Time Played: %ss",
352350
"minesweeperGame.title": "Minesweeper",
353351

354-
"playerManip.notEnoughItems": "Not enough items(%s of %s) to manipulate seed",
352+
"playerManip.notEnoughItems": "Not enough items to manipulate seed",
353+
"playerManip.notEnoughItems.help": "Help: put some more items in your inventory",
355354
"playerManip.reset": "Restarting player RNG manipulation. Reason: %s",
356355
"playerManip.reset.advancement": "Gained Advancement",
357356
"playerManip.reset.amethystChime": "Walked on Amethyst Crystals",
@@ -392,9 +391,11 @@
392391
"playerManip.state.manipulating_enchantments": "Manipulating Enchantments",
393392
"playerManip.state.uncracked": "Uncracked",
394393
"playerManip.state.waiting_dummy_enchant": "Waiting for Dummy Enchantment",
394+
"playerManip.throttled": "Hit the creative mode item throw throttle limit",
395+
"playerManip.throttled.help": "Help: try changing to survival mode",
395396
"playerManip.throwError": "Condition not possible or would require more than %s item throws",
396397
"playerManip.toolBreakWarning": "Warning: tool has %s durability left",
397-
"playerManip.uncracked": "Player-Seed needs to be cracked",
398+
"playerManip.uncracked": "Player seed needs to be cracked",
398399

399400
"snakeGame.score": "Score: %s",
400401
"snakeGame.title": "Snake",

src/main/resources/assets/clientcommands/lang/id_id.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -266,9 +266,7 @@
266266
"enchCrack.xpSeed.many": "Kemungkinan benih XP: %s",
267267
"enchCrack.xpSeed.one": "Benih XP: %s",
268268

269-
"itemCrack.notEnoughItems": "Tidak bisa menggunakkan SeedCracker RNG: Tidak cukup benda di Tangan Pemain",
270-
271-
"playerManip.notEnoughItems": "Tidak cukup item(%s dari %s) untuk memanipulasi seed",
269+
"playerManip.notEnoughItems": "Tidak cukup item untuk memanipulasi seed",
272270
"playerManip.reset": "Manipulasi pemain RNG telah di reset. Alasan: %s",
273271
"playerManip.reset.advancement": "Mendapatkan Advancement",
274272
"playerManip.reset.amethystChime": "Jalan di Gugus Kecubung",

src/main/resources/assets/clientcommands/lang/ja_jp.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -266,9 +266,7 @@
266266
"enchCrack.xpSeed.many": "可能性のあるXPシード: %s",
267267
"enchCrack.xpSeed.one": "XPシード: %s",
268268

269-
"itemCrack.notEnoughItems": "RNGシードクラッカの使用に失敗しました: 十分なアイテムがありません",
270-
271-
"playerManip.notEnoughItems": "シードを操作するためのアイテムが不足しています (%s 分の %s)",
269+
"playerManip.notEnoughItems": "シードを操作するためのアイテムが不足しています",
272270
"playerManip.reset": "RNG操作を再度開始しています、 理由は次のとおりです: %s",
273271
"playerManip.reset.advancement": "進捗の達成",
274272
"playerManip.reset.amethystChime": "アメジストのクリスタルのを上を歩きました",

src/main/resources/assets/clientcommands/lang/nl_nl.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,7 @@
112112
"enchCrack.xpSeed.many": "Mogelijke XP seeds: %s",
113113
"enchCrack.xpSeed.one": "XP Seed: %s",
114114

115-
"itemCrack.notEnoughItems": "RNG SeedCracker kan niet worden gebruikt: niet genoeg items in spelershand",
116-
117-
"playerManip.notEnoughItems": "Niet genoeg items(%s van %s) om seed te manipuleren",
115+
"playerManip.notEnoughItems": "Niet genoeg items om seed te manipuleren",
118116
"playerManip.reset": "Speler RNG manipulatie aan het herstarten. Reden: %s",
119117
"playerManip.reset.advancement": "Prestatie Behaald",
120118
"playerManip.reset.anvil": "Aambeeld Gebruikt",

src/main/resources/assets/clientcommands/lang/pl_pl.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -194,9 +194,7 @@
194194
"enchCrack.xpSeed.many": "Liczba możliwych ziarn XP: %s",
195195
"enchCrack.xpSeed.one": "Ziarno XP: %s",
196196

197-
"itemCrack.notEnoughItems": "Nie można użyć RNG SeedCracker: niewystarczająca ilość przedmiotów w ekwipunku",
198-
199-
"playerManip.notEnoughItems": "Nie wystarczająca ilość przedmiotów (%s of %s) by manipulować ziarnem",
197+
"playerManip.notEnoughItems": "Nie wystarczająca ilość przedmiotów by manipulować ziarnem",
200198
"playerManip.reset": "Resetowanie manipulacji RNG. Powód: %s",
201199
"playerManip.reset.advancement": "Zdobyto osiągnięcie",
202200
"playerManip.reset.anvil": "Użyto kowadła",

0 commit comments

Comments
 (0)