Freecam
Freecam copied to clipboard
"Initial Perspective" config option
As requested in #16, I've added an option to select from one of the following initial camera perspectives:
- "Inside" this option retains the current behavior.
- "First Person" this option shifts the camera 0.3 blocks forward, to be just in front of the player's eyes.
- "Third Person" this option replicates F5 mode, moving the camera 4 blocks behind the player.
- "Mirror" this option replicates mirrored F5 mode, moving the camera 4 blocks in front of the player and inverting the camera.
Default is set to "Third Person" as this felt the most intuitive option during testing, but let me know if you'd rather something different and I can amend the commit.
Most of the backed logic comes from net.minecraft.client.render.Camera
, which has been cleaned up and ported into a new util class PositionRotationUtil
. Let me know if there's anything you'd like named/formatted differently or if you'd rather a different approach be taken somewhere.
https://user-images.githubusercontent.com/5046562/168478005-f961f7cf-6e6d-4992-989c-ba0b08841c78.mov
https://user-images.githubusercontent.com/5046562/168478356-ba94f2ae-80a0-4438-ad72-8863f5fe83ac.mov
https://user-images.githubusercontent.com/5046562/168478145-3baa1d31-a1fe-4fe5-8b98-ffcb821383ab.mov
https://user-images.githubusercontent.com/5046562/168478222-a615f646-4123-45e7-ad21-6a2d8ad15df3.mov
https://user-images.githubusercontent.com/5046562/168478285-b20c59d7-8b34-40a6-a1bc-fbe08a73389b.mov
Fixes #16
Thanks again for your help. Looks great for the most part. I did notice a couple problems, though:
- If first person is used while the players pitch is between 33 and 90, the freecam entity still spawns inside the players head.
- (The main reason I was putting off
#16
) Using third person with a wall behind you will cause the freecam entity to spawn inside a block. This isn't a big issue most of the time, however if the player has noClip disabled, they will get stuck.
If you can solve these issues, I'll merge the pr.
A couple smaller changes:
- I'd prefer 'Inside' be left as the default setting, so as to not confuse people who are unaware of the new feature.
- The new setting should be moved under 'Flight Mode' just to keep settings of the same type together. (I think it looks better)
I'll try and have a look at those issues through the week 👍
Had a quick look at the noclip issue this evening.
A simple ray-trace won't work, since it will find the first conflicting pixel and then place the camera on the edge of that block. This means the camera's collision box is half in the block. It also doesn't take account of the camera's feet or head colliding with adjacent blocks:
double distance = 4.0;
Vec3d targetPosition = util.getRelativePosition(-distance, 0, 0);
// Raytrace from entity to target
distance = unobstructedDistance(entity, targetPosition);
System.out.printf("Distance %.1f - desired %.1f\n", distance, 4.0);
util.moveForward(-distance);
An alternative approach is to ray-trace manually, re-position the camera on each iteration and check for collisions... Not the cleanest approach for sure:
PositionRotationUtil util = new PositionRotationUtil(entity);
this.setPosition(util.getPosition());
// Loop from 0 to 4 in 0.1 increments.
// Check for collision at each increment
for (double d = 0; d <= 4.0; d += 0.1) {
Vec3d position = util.getRelativePosition(-d, 0, 0);
Vec3d oldPos = this.getPos();
// Test if the camera will collide with the new position
this.setPosition(position);
if (!MC.world.isSpaceEmpty(this)) {
System.out.printf("FreeCam collides with block at %.1f %.1f %.1f\n", position.getX(), position.getY(), position.getZ());
this.setPosition(oldPos);
break; // End loop
}
}
Incidentally this doesn't seem to work properly when the player is "swimming" under a trapdoor or similar.
Hopefully I'll get time to look at this properly and come up with a
The 1st person issue seems to be just a case of tuning the moveForward distance. 0.3 is just a bit too tight, 0.4 seems to work better, looks fairly normal until around pitch 70 where the camera starts clipping through the player's body/legs.
While I was playing around, I realized that the camera having a full standing-player collision box could be a bit awkward with noclip disabled. It's especially janky when the player is crouching or "swimming" in a tunnel and then enters freecam. In this scenario the "changing pose" animation plays, since the FreeCamera is standing up. (It plays again when exiting Freecam).
Maybe we should permanently set the pose to EntityPose.SWIMMING
or manually set the EntityDimensions
somewhere? We'd have to manually match up the camera's eye height with the player's of course... Something like player.getEyePos().subtract(0, this.getEyeHeight(this.getPose()), 0)
perhaps... This probably needs its own issue, but I'm off to bed for now.
Not sure I'll have time to finish looking into ray-tracing to avoid no-clip collision issues. Perhaps alternatively the "perspective" config option could somehow depend on the "noclip" config option? Or we warn the user when they set both options? Edit: fixed in follow up PR #69
This is a separate issue, but I also noticed that disabling noclip can open a can-of-worms when the player is in different poses, because the swimming and crouching poses have smaller collision boxes than the (default) standing pose. Wondering if we should be making the camera entity always 0.8 blocks tall to allow them to fit in any position the player may be? Edit: fixed in PR #68