|
9 | 9 | import net.earthcomputer.clientcommands.interfaces.ICreativeSlot;
|
10 | 10 | import net.minecraft.ChatFormatting;
|
11 | 11 | 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; |
12 | 15 | import net.minecraft.client.player.LocalPlayer;
|
13 | 16 | import net.minecraft.core.component.DataComponents;
|
14 | 17 | import net.minecraft.network.chat.Component;
|
|
38 | 41 | import java.util.OptionalLong;
|
39 | 42 | import java.util.Random;
|
40 | 43 | import java.util.concurrent.atomic.AtomicLong;
|
| 44 | +import java.util.function.Function; |
41 | 45 | import java.util.function.Predicate;
|
42 | 46 | import java.util.stream.Collectors;
|
43 | 47 |
|
@@ -326,20 +330,24 @@ public static void onItemDamage(int amount, LivingEntity holder, ItemStack stack
|
326 | 330 | }
|
327 | 331 |
|
328 | 332 | 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 | + } |
339 | 344 | }
|
| 345 | + return true; |
| 346 | + }, 64); |
| 347 | + if (!result.isSuccess()) { |
| 348 | + result.sendErrorMessage(); |
340 | 349 | }
|
341 |
| - return true; |
342 |
| - }, 64); |
| 350 | + }; |
343 | 351 | if (isPredictingBlockBreaking) {
|
344 | 352 | postBlockBreakPredictAction = action;
|
345 | 353 | } else {
|
@@ -403,26 +411,45 @@ public static ThrowItemsResult throwItemsUntil(Predicate<Random> condition, int
|
403 | 411 | return new ThrowItemsResult(ThrowItemsResult.Type.NOT_POSSIBLE, itemsNeeded);
|
404 | 412 | }
|
405 | 413 | 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; |
408 | 417 | }
|
409 | 418 | }
|
410 | 419 |
|
411 | 420 | return new ThrowItemsResult(ThrowItemsResult.Type.SUCCESS);
|
412 | 421 | }
|
413 | 422 |
|
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 | + } |
416 | 443 |
|
417 | 444 | Slot matchingSlot = getBestItemThrowSlot(player.containerMenu.slots);
|
418 | 445 | if (matchingSlot == null) {
|
419 |
| - return false; |
| 446 | + return new ThrowItemsResult(ThrowItemsResult.Type.NOT_ENOUGH_ITEMS); |
420 | 447 | }
|
421 | 448 | expectedThrows++;
|
422 |
| - Minecraft.getInstance().gameMode.handleInventoryMouseClick(player.containerMenu.containerId, |
| 449 | + interactionManager.handleInventoryMouseClick(player.containerMenu.containerId, |
423 | 450 | matchingSlot.index, 0, ClickType.THROW, player);
|
424 | 451 |
|
425 |
| - return true; |
| 452 | + return new ThrowItemsResult(ThrowItemsResult.Type.SUCCESS); |
426 | 453 | }
|
427 | 454 |
|
428 | 455 | public static void unthrowItem() {
|
@@ -453,7 +480,6 @@ public static Slot getBestItemThrowSlot(List<Slot> slots) {
|
453 | 480 | if (itemCounts.isEmpty()) {
|
454 | 481 | return null;
|
455 | 482 | }
|
456 |
| - //noinspection OptionalGetWithoutIsPresent |
457 | 483 | Item preferredItem = itemCounts.keySet().stream().max(Comparator.comparingInt(Item::getDefaultMaxStackSize).thenComparing(itemCounts::get)).get();
|
458 | 484 | //noinspection OptionalGetWithoutIsPresent
|
459 | 485 | return slots.stream().filter(slot -> slot.getItem().getItem() == preferredItem).findFirst().get();
|
@@ -488,47 +514,59 @@ public static OptionalLong getSeed(Random rand) {
|
488 | 514 |
|
489 | 515 | public static class ThrowItemsResult {
|
490 | 516 | private final Type type;
|
491 |
| - private final MutableComponent message; |
| 517 | + private final Object[] messageArgs; |
492 | 518 |
|
493 |
| - public ThrowItemsResult(Type type, Object... args) { |
| 519 | + public ThrowItemsResult(Type type, Object... messageArgs) { |
494 | 520 | 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; |
496 | 526 | }
|
497 | 527 |
|
498 | 528 | public Type getType() {
|
499 | 529 | return type;
|
500 | 530 | }
|
501 | 531 |
|
502 |
| - public MutableComponent getMessage() { |
503 |
| - return message; |
| 532 | + public void sendErrorMessage() { |
| 533 | + for (MutableComponent message : type.messageCreator.apply(messageArgs)) { |
| 534 | + ClientCommandHelper.sendFeedback(message); |
| 535 | + } |
504 | 536 | }
|
505 | 537 |
|
506 | 538 | 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 | + )), |
508 | 543 | 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), |
511 | 553 | ;
|
512 | 554 |
|
513 | 555 | private final boolean success;
|
514 |
| - private final String translationKey; |
| 556 | + private final Function<Object[], List<MutableComponent>> messageCreator; |
515 | 557 |
|
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))); |
519 | 560 | }
|
520 | 561 |
|
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; |
527 | 565 | }
|
528 | 566 | }
|
529 | 567 | }
|
530 | 568 |
|
531 |
| - public static enum CrackState implements StringRepresentable { |
| 569 | + public enum CrackState implements StringRepresentable { |
532 | 570 | UNCRACKED("uncracked"),
|
533 | 571 | CRACKED("cracked", true),
|
534 | 572 | ENCH_CRACKING_1("ench_cracking_1"),
|
|
0 commit comments