Earthcomputer / clientcommands

Adds useful client-side commands
Other
1.04k stars 116 forks source link

Add a "force" option to /cenchant to have it always crack a new player seed even if the current enchantment seed can do the requested enchant. #631

Open AJMansfield opened 6 months ago

AJMansfield commented 6 months ago

When performing a large number of enchantments, it's useful to be able to use each manipulated enchantment as also the "dummy enchantment" that buffers another manipulated enchantment seed for the next enchantment after it.

In some cases though, /cenchant will "discover" that the currently-buffered enchantment seed already has the requested enchantments and won't manipulate the next seed after it. This makes it impossible to chain together enchanting two of the same item, and makes other cases like doing both a chestplate and leggings or both a diamond tool and the book needed to get Efficiency V, somewhat unpredictable and frustrating.

To be clear: enchantment chaining does already usually work for dissimilar items, especially when enchanting items that have a much wider range of possible enchantments. And the exp savings are significant: it only takes 168 exp for each additional Level 30 item after the first when chained, instead of the 218 exp required if doing separate dummy enchants for each. Especially in the early game with slow farms like skeleton spawners, that 50 exp difference amounts to significant time savings.

What I want is some type of config toggle or parameter that will force /cenchant crack another player seed that'll buffer into an appropriate enchantment seed -- even if it already has an enchantment seed buffered that can do the requested enchantment.


For context sake, here's a more explicit description of enchantment chaining technique, along with an explanation of the underlying theory for why it works in the working cases and why it doesn't in the non-working cases.

Here's a scenario where the command lets me chain enchants the way I want to be able to generally:

Goal:

  • Diamond Helmet with Protection IV, Respiration III, Aqua Affinity, and Unbreaking III
  • Diamond Sword with Sharpness V, Fire Aspect II, and Unbreaking III

Procedure:

  • Gain 17 exp.
    • This raises the player from Level 0 to Level 1.
  • /ccrackrng
    • Player Seed Cracker throws items and determines player seed.
  • /cenchant diamond_helmet with protection 4 with respiration 3 with aqua_affinity 1 with unbreaking 3
    • Enchantment Cracker throws items and prompts to do a dummy enchantment.
  • Enchant a book in slot 1.
    • This buffers the helmet enchantment seed.
    • This drops the player from Level 1 to Level 0.
    • Enchantment Cracker prompts to indicate: 15 bookshelves, slot 3.
  • Adjust the torches on the bookshelves to expose the table to 15 bookshelves.
  • Gain 825 exp.
    • This raises the player from Level 0 to Level 30.
    • Player RNG Maintenance prompts the need to crack the seed again due to collecting exp orbs.
  • /ccrackrng
    • Player Seed Cracker throws items and determines player seed.
  • /cenchant diamond_sword with sharpness 5 with fire_aspect 2 with unbreaking 3
    • Enchantment Cracker throws items and prompts to do a dummy enchantment.
  • Enchant a diamond helmet in slot 3.
    • This obtains the desired enchanted helmet.
    • This buffers the sword enchantment seed.
    • This drops the player from Level 30 to Level 27.
    • Enchantment Cracker prompts to indicate: 15 bookshelves, slot 3.
  • Gain 168 exp.
    • This raises the player from Level 27 to Level 30.
  • Enchant a diamond sword in slot 3.
    • This obtains the desired enchanted sword.

Total EXP Needed: 1010

Here's a scenario where the command does not allow chaining enchants the way I want to, but would allow it if there were this sort of "force" config or parameter:

Goal:

  • 2x Diamond Helmet with Protection IV, Respiration III, Aqua Affinity, and Unbreaking III

Procedure:

  • Gain 17 exp.
    • This raises the player from Level 0 to Level 1.
  • /ccrackrng
    • Player Seed Cracker throws items and determines player seed.
  • /cenchant diamond_helmet with protection 4 with respiration 3 with aqua_affinity 1 with unbreaking 3
    • Enchantment Cracker throws items and prompts to do a dummy enchantment.
  • Enchant a book in slot 1.
    • This buffers the first helmet enchantment seed.
    • This drops the player from Level 1 to Level 0.
    • Enchantment Cracker prompts to indicate: 15 bookshelves, slot 3.
  • Adjust the torches on the bookshelves to expose the table to 15 bookshelves.
  • Gain 825 exp.
    • This raises the player from Level 0 to Level 30.
    • Player RNG Maintenance prompts the need to crack the seed again due to collecting exp orbs.
  • /ccrackrng
    • Player Seed Cracker throws items and determines player seed.
  • /cenchant diamond_helmet with protection 4 with respiration 3 with aqua_affinity 1 with unbreaking 3
    • Enchantment Cracker does not throw any items and indicates that no dummy enchantment is needed.
    • Enchantment Cracker prompts to indicates: 15 bookshelves, slot 3.
    • This is the step that needs the "force" option to function as expected.
  • Enchant a diamond helmet in slot 3.
    • This obtains the first enchanted helmet.
    • The player seed was not manipulated by the last step, so this only buffers a random enchantment seed.
    • Now a new enchantment sequence with a dummy enchant is required.
  • Not know that this output means chaining won't work.
  • Gain 168 exp.
  • Enchant a diamond helmet in slot 3.
  • Pawn off the Blast Protection III Thorns II diamond helmet to someone else on the server.
  • Make another diamond helmet to try again.
  • /ccrackrng
    • Player Seed Cracker throws items and determines player seed.
  • /cenchant diamond_helmet with protection 4 with respiration 3 with aqua_affinity 1 with unbreaking 3
    • Enchantment Cracker throws items and prompts to do a dummy enchantment.
  • Enchant a book in slot 1.
    • This buffers the second helmet enchantment seed.
    • This drops the player from Level 27 to Level 26.
    • Enchantment Cracker prompts to indicate: 15 bookshelves, slot 3.
  • Gain 218 exp.
    • This raises the player from Level 26 to Level 30.
  • Enchant a diamond helmet in slot 3.
    • This obtains the second enchanted helmet.

Total EXP Needed: 1228 1060

Earthcomputer commented 6 months ago

So basically what you want is a --chain option (I think "force" is too vague), which would force the cracker to search for solutions with a minimum of 1 item throw?

AJMansfield commented 6 months ago

So basically what you want is a --chain option (I think "force" is too vague), which would force the cracker to search for solutions with a minimum of 1 item throw?

That's a much better name for it, I'd fully support calling it --chain.

Conceptually though, this isn't actually about the number of throws, but the fact that the enchantment seed cracker won't try to set up a favorable future enchantment seed if it judges the current enchantment seed to already be favorable.

That current behavior is certainly a good, user-friendly default: optimistically checking if the current seed is already favorable makes low-level enchants much simpler to get (i.e. ones you just need the right bookshelf count for), and it prevents players from being misled by the prompts if they run the command a second time.

But when chaining, whatever the current seed is it's already reserved for a different item -- and the cracker just needs to skip that optimistic check and set up a favorable next seed regardless.

AJMansfield commented 6 months ago

I've looking through the code a bit, and I suspect that the way to avoid this optimistic check would be to make a change here:

https://github.com/Earthcomputer/clientcommands/blob/fabric/src/main/java/net/earthcomputer/clientcommands/features/EnchantmentCracker.java#L340

for (int i = Configs.enchCrackState == CrackState.CRACKED ? ManipulateResult.NO_DUMMY : 0;

Where for chaining enchants, that loop needs to always start from 0 regardless of the crack state, instead of sometimes starting from ManipulateResult.NO_DUMMY (i.e. -1).

If I had build tooling set up to test it I would -- but I'm not familiar enough with this codebase to know how to implement the glue parts of the change (argument parsing and passing that information from the command handler to the enchantment cracker, etc).

I'd be happy to write documentation for the --chain option if/when it's added, but I don't think I'm likely to have the time to figure out the other technical details to be able to submit a PR in any particularly near future.