|
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