15 min

Camera System

Control the camera from the server using ServerCameraSettings and packets. Create cinematic, third-person, orbit cameras and custom camera modes.

Overview

Hytale's camera system is controlled server-side via packets. The server sendsServerCameraSettings to clients, which then apply the camera configuration.

1// Architecture
2ServerCameraSettings (created server-side)
3
4SetServerCamera packet
5
6Client applies the settings
server-side only
The server controls the camera via packets, not directly. All camera changes must go through the packet system.

Basic Usage

Sending Camera Settings

1import com.hypixel.hytale.protocol.packets.camera.SetServerCamera;
2import com.hypixel.hytale.protocol.ClientCameraView;
3import com.hypixel.hytale.protocol.ServerCameraSettings;
4
5// Create settings
6ServerCameraSettings settings = new ServerCameraSettings();
7settings.distance = 15.0f;
8
9// Send to player
10player.getPacketHandler().writeNoCache(
11 new SetServerCamera(ClientCameraView.Custom, true, settings)
12);

Camera View Types

view typedescription
ClientCameraView.CustomCustom camera settings
ClientCameraView.FirstPersonFirst person view
ClientCameraView.ThirdPersonVanilla third person

Reset to Vanilla

1// Reset to vanilla third person
2player.getPacketHandler().writeNoCache(
3 new SetServerCamera(ClientCameraView.ThirdPerson, false, null)
4);

ServerCameraSettings Fields

All Available Fields

1public class ServerCameraSettings {
2 // Lerp (smoothing)
3 public float positionLerpSpeed;
4 public float rotationLerpSpeed;
5
6 // Distance & offset
7 public float distance;
8 public float speedModifier;
9 public Position positionOffset; // Offset from attached entity
10 public Direction rotationOffset; // Rotation offset
11
12 // Attachment
13 public AttachedToType attachedToType; // None, LocalPlayer, EntityId
14 public int attachedToEntityId; // Network ID of entity to attach to
15 public boolean eyeOffset;
16
17 // Position
18 public PositionType positionType; // Custom or attached
19 public Position position; // For Custom position
20 public PositionDistanceOffsetType positionDistanceOffsetType;
21
22 // Rotation
23 public RotationType rotationType; // Custom or AttachedToPlusOffset
24 public Direction rotation; // yaw, pitch, roll (in radians!)
25
26 // Controls
27 public boolean allowPitchControls;
28 public boolean displayCursor;
29 public boolean displayReticle;
30 public boolean sendMouseMotion;
31 public boolean skipCharacterPhysics;
32 public boolean isFirstPerson;
33
34 // Input
35 public MouseInputType mouseInputType;
36 public MouseInputTargetType mouseInputTargetType;
37
38 // Movement
39 public MovementForceRotationType movementForceRotationType;
40 public Direction movementForceRotation;
41 public CanMoveType canMoveType;
42 public ApplyMovementType applyMovementType;
43 public Vector3f movementMultiplier;
44 public ApplyLookType applyLookType;
45 public Vector2f lookMultiplier;
46 public Vector3f planeNormal;
47}

Direction Constructor

direction order
The Direction constructor takes (yaw, pitch, roll), NOT (pitch, yaw, roll)!
1// CORRECT
2new Direction(yaw, pitch, roll)
3
4// Fields are: yaw, pitch, roll
5public float yaw;
6public float pitch;
7public float roll;

Attaching Camera to Entity

You can attach the camera to any entity using its network ID. This is useful for cinematic cameras, spectator modes, or orbit cameras.

1// Attach camera to an NPC/entity
2ServerCameraSettings settings = new ServerCameraSettings();
3settings.attachedToType = AttachedToType.EntityId;
4settings.attachedToEntityId = entity.getNetworkId(); // Get from spawned entity
5settings.isFirstPerson = false; // false = you can see your character
6settings.displayCursor = false;
7settings.positionOffset = new Position(0, 1.5f, 0); // Camera height above entity
8
9player.getPacketHandler().writeNoCache(
10 new SetServerCamera(ClientCameraView.Custom, true, settings)
11);

AttachedToType Options

valuebehavior
AttachedToType.NoneCamera at fixed position (use positionType = Custom)
AttachedToType.LocalPlayerCamera follows the player
AttachedToType.EntityIdCamera follows entity with attachedToEntityId
isfirstperson
When isFirstPerson = true, your character becomes invisible. Set it to false if you want to see yourself from the camera.

Rotation Control

RotationType Options

valuebehavior
RotationType.CustomUse rotation field for camera direction
RotationType.AttachedToPlusOffsetFollow entity rotation + rotationOffset
attachedtoplusoffset bug
RotationType.AttachedToPlusOffset often causes issues (camera pointing at sky). Use RotationType.Custom with calculated rotation instead.

Calculate Look-At Rotation

To make the camera look at a target, calculate yaw and pitch from the direction vector:

1// Camera position
2double camX = ..., camY = ..., camZ = ...;
3
4// Target position (e.g., player)
5Vector3d targetPos = player.getTransform().getPosition();
6double targetY = targetPos.getY() + 1.0; // Eye height
7
8// Direction vector: camera -> target
9double dx = targetPos.getX() - camX;
10double dy = targetY - camY;
11double dz = targetPos.getZ() - camZ;
12
13// Convert to yaw/pitch (radians)
14float yaw = (float) (Math.atan2(dx, dz) + Math.PI); // +PI to face target
15float pitch = (float) Math.atan2(dy, Math.sqrt(dx * dx + dz * dz));
16
17// Apply to camera
18settings.rotationType = RotationType.Custom;
19settings.rotation = new Direction(yaw, pitch, 0);

Cinematic Animations

For smooth cinematic cameras, use a tick-based animation system with an NPC as the camera anchor. Here are some example animation patterns:

Orbit Animation

Classic orbit around the player:

1float angle = elapsed * speed; // speed in radians/sec
2double x = center.getX() + Math.sin(angle) * radius;
3double z = center.getZ() + Math.cos(angle) * radius;
4double y = center.getY() + height;

Figure-8 Animation

Horizontal figure-8 pattern using Lissajous curve:

1float t = elapsed * speed;
2double x = center.getX() + Math.sin(t) * size;
3double z = center.getZ() + Math.sin(t * 2) * size * 0.5; // Double frequency
4double y = center.getY() + height + Math.sin(t * 2) * 0.5;

Camera Shake

Action-style camera shake using multiple sine waves:

1float frequency = 15.0f;
2float intensity = 0.15f;
3
4double shakeX = Math.sin(elapsed * frequency) * intensity;
5double shakeY = Math.cos(elapsed * frequency * 1.3) * intensity * 0.5;
6double shakeZ = Math.sin(elapsed * frequency * 0.7) * intensity;
7
8// Also shake the rotation slightly
9float shakeYaw = (float) (Math.sin(elapsed * frequency * 2) * 0.02);
10float shakePitch = (float) (Math.cos(elapsed * frequency * 2.5) * 0.01);

Smooth Animation Tips

For butter-smooth cinematics, follow these critical rules:

rulewhy
Capture player position ONCE at startAvoid jitter from position polling
Use tick counter, not System.currentTimeMillis()Prevents jumps during alt-tab/lag
Update at 8ms intervals (~125 FPS)Sweet spot for smooth motion
Skip frames if delta > 50msPrevents backlog accumulation
Use ConcurrentHashMap for stateThread safety between scheduler and world
why capture position once?
Polling player.getTransform().getPosition() every frame introduces micro-jitter because the server position has tiny variations even when the player is standing still. By capturing once at the start, the animation math is 100% deterministic.

Common Gotchas

PositionType.Custom Crashes

avoid custom position
Using positionType = PositionType.Custom with absolute coordinates often causes client crashes. Attach the camera to an entity instead.

LerpSpeed Breaks Camera

avoid lerpspeed with custom rotation
Setting positionLerpSpeed or rotationLerpSpeed when usingRotationType.Custom causes erratic camera behavior (pointing at sky, jittering). Omit these fields for continuous rotation updates.

Entity Rotation Not Synced

Changing an entity's rotation via teleportRotation() does NOT sync to the client for camera purposes. Calculate and send rotation manually.

Update Rate Sweet Spot

8ms is optimal
Too fast (1ms): Scheduler can't keep up, creates backlog and latency.
Too slow (50ms): Visible stuttering, not smooth.
8ms (~125 FPS): Sweet spot for smooth motion without overloading.

Enums Reference

RotationType

valuebehavior
RotationType.CustomUse rotation field directly
RotationType.AttachedToPlusOffsetFollow entity rotation (buggy)

MouseInputType

valuebehavior
MouseInputType.LookAtTargetMouse controls direction (FPS-like)
MouseInputType.LookAtPlaneMouse points on a plane (RTS-like)
MouseInputType.LookAtTargetEntityLocked on an entity
MouseInputType.LookAtTargetBlockLocked on a block

AttachedToType

valuebehavior
AttachedToType.NoneFixed position camera
AttachedToType.LocalPlayerFollow player
AttachedToType.EntityIdFollow entity by network ID

API Summary

Required Imports

1// Camera
2import com.hypixel.hytale.protocol.ServerCameraSettings;
3import com.hypixel.hytale.protocol.packets.camera.SetServerCamera;
4import com.hypixel.hytale.protocol.ClientCameraView;
5import com.hypixel.hytale.protocol.Direction;
6import com.hypixel.hytale.protocol.Position;
7import com.hypixel.hytale.protocol.AttachedToType;
8import com.hypixel.hytale.protocol.RotationType;
9
10// NPC for camera entity
11import com.hypixel.hytale.server.npc.NPCPlugin;
12import com.hypixel.hytale.server.npc.entities.NPCEntity;
13import com.hypixel.hytale.server.core.entity.Frozen;
14
15// Math
16import com.hypixel.hytale.math.vector.Vector3d;
17import com.hypixel.hytale.math.vector.Vector3f;

Best Practices

dodon't
Attach camera to entityUse PositionType.Custom
Calculate rotation manuallyUse AttachedToPlusOffset
Update at 8ms for smooth motionUpdate at 1ms (backlog) or 50ms (choppy)
Capture player position oncePoll position every frame
Use tick counter for timingUse System.currentTimeMillis()
Skip frames on lag spikesProcess all queued frames
Freeze camera NPCLet NPC move on its own