Dodge + better third person
Summary Better Third person overwrites player.input values, messing up dodge movement vector projection.
Running Environment
- Minecraft Version: every one supported
- ParCool Version: latest
- Forge Version (optional):
Detail I intend to open a PR with a fix, I'm opening this issue to discuss the idea.
What I thought we could do to fix that is to, at each tick the action/animation is being done, if better third person is active, we can adjust the dodge vector rotating it to match player's yaw. This adjustment would consist in creating a new vector considering what is left to reach the end of the previous one, but rotating it accordingly. This maybe 's enough to give a smooth dodge trajectory. As normally the time for turning is pretty low.
What do you think of this idea?
Additional Data Such as Screenshots or Crash Reports (I am happy and fix the bug more easily if you send me these)
I'm not willing to change decided direction of Dodge changes during the movements working...
Just want to know to understand exactly the problem, how does Better Third Person change player input, and how does it cause problem concretely? as an example
To exemplify it, I configured BetterThirdperson to have the slowest turning speed.
See how shoulder surfing works when turning left and right:
https://github.com/user-attachments/assets/39c26115-31e7-428e-9e1d-64a7baeda72e
Now, see what happens with BetterThirdPerson when doing the same thing:
https://github.com/user-attachments/assets/5bd5fb35-f76a-4dab-97da-d8eb28874a01
While Shoulder Surfing maintains a vanilla-friendly approach, BetterThirdPerson overwrites the input directions (and I suspect at each tick) to give that semi-circle trajectory pattern. To make things more difficult, it's not an open-source project, which imposes some legal barriers for some compatibilization strategies, such as trying to mirror its math to compensate for it.
More so, when dodging, you want to move in the direction the player inputted. With Vanilla and Shoulder Surfing, you can just look at player.input to get it. With BetterThirdPerson, this circle-pattern has a "tangent" direction approach, where the moving vector always starts with forward, and at each tick, it slightly rotates, and it looks like they do it over each tick, constantly manipulating the "player.input" properties. It really messes up actions that depends on the direction the player intended.
Now, a personal opinion: I'd rather use my free time to favor open source projects, while closed ones must be a problem for their owners, that's why I'm all for ShoulderSurfing, but I understand how the community likes BetterThirdPerson and that's why I still consider to try to find a solution to this, but I couldn't find a way to compatibilize such behavior and I don't understand why they decided for it, as it looks like a worse controlling experience.
My best idea was to change the rolling vector over ticks, letting the direction be controlled by BetterThirdPerson indirectly, but I understand this may lead to odd behaviors.
Thank you for detailed description. I understood the problem.
I also feel the approach that change the rolling vector every ticks can cause problem... but surely this way might be the best among the ways that we can.
Hmm but if we used this way, the internal process of dodge would change than the one with BetterThirdPerson. It's not a very good way...
Another option I thought was to use keyboard keys key bindings to decide movement just for better third person. I'm theory, we could know the inputted directions this way. If there aren't any or better third person is not installed we'd assume the current method.
the behavior when using gamepad would be the same as today, though, but maybe it could be further compatibilized with some internal API controlify and controllable may offer.
The problem with that approach is mainly maintainability, as you'd have two ways of detecting the same thing, while you, today, have one that works perfectly, unless when using better third person that changed vanilla input.
The last idea I had was to ask for methods that expose the vanilla player.input for the better third person maintainer. When they offer it, it finally can be compatibilized
The last way is ideally the best but actually take time and a bit troublesome to realize...
How about using Mixin? Apply mixin injection to a process of input override of Better Third Person and save the input information before it's changed.
I've not tried to apply mixin to opptional external mod so I'm not sure whether it's possible, but if I remember correctly, for example YesSteveModels should have mixin to ParCool so I think it may be possible. In fact dangerous approach. Maybe upper version limit for Better Third Person is needed.
Mixin is actually a very good idea if possible. I'll experiment on this to see if I can get it to work, but maybe the mod must be guaranteed to be installed otherwise the mixin will crash. If it's possible to do so and this crash problem happens when better third person is not installed, it'd need to be in a compatibilization mod that is only who needs it will get it
@alRex-U mixin can only be used with Minecraft classes, unfortunately. But I had an idea... I tried to create this mixin
@Mixin({MovementInputFromOptions.class})
public class MovementInputMixin {
@Inject(
method = {"tick"},
at = {@At("RETURN")}
)
public void tickHook(boolean moveSlowly, CallbackInfo ci) {
KeyRecorder.recordMovingVector((MovementInputFromOptions)(Object)this);
}
}
And I'm logging the move vectors I've captured with it:
public static void recordMovingVector(MovementInputFromOptions moving) {
Vector2f vector = moving.getMoveVector();
if (!VectorUtil.isZero(vector)) {
lastDirection = new Vector3d(vector.x, 0, vector.y).normalize();
ParCool.LOGGER.info("Input {}, {}", vector.x, vector.y);
}
}
Take a look at the logs I've gotten when pressing back:
- With Vanilla
[23:48:53] [Render thread/INFO]: Input 0.0, -1.0
[23:48:53] [Render thread/INFO]: Input 0.0, -1.0
[23:48:54] [Server thread/INFO]: Saving and pausing game...
- With Shoulder Surfing
[23:51:43] [Render thread/INFO]: Input 0.0, -1.0
[23:51:43] [Render thread/INFO]: Input 0.0, -1.0
[23:51:45] [Server thread/INFO]: Saving and pausing game...
- With better third person
[23:46:44] [Render thread/INFO]: Input -0.0, 1.0
[23:46:44] [Render thread/INFO]: Input -0.0, 1.0
[23:46:46] [Server thread/INFO]: Saving and pausing game...
I don't have any idea how the input is being changed at this moment. Still, maybe the best way to treat it is something like this, is to register the input vector before BetterThirdPerson transform it somehow.
Edit: Wow, I just got it using this target:
at = @At(
value = "FIELD",
target = "Lnet/minecraft/util/MovementInputFromOptions;shiftKeyDown:Z",
shift = At.Shift.AFTER // Execute after the field assignment
)
With better third person running, every direction could be captured correctly:
[00:16:24] [Render thread/INFO]: Input 0.0, 1.0
[00:16:25] [Render thread/INFO]: Input 0.0, -1.0
[00:16:25] [Render thread/INFO]: Input 0.0, -1.0
[00:16:36] [Render thread/INFO]: Input -1.0, 0.0
[00:16:36] [Render thread/INFO]: Input -1.0, 0.0
[00:16:37] [Render thread/INFO]: Input 1.0, 0.0
[00:16:37] [Render thread/INFO]: Input 1.0, 0.0