Overview
Hytale's camera system is controlled server-side via packets. The server sendsServerCameraSettings to clients, which then apply the camera configuration.
1// Architecture2ServerCameraSettings (created server-side)3 ↓4SetServerCamera packet5 ↓6Client applies the settingsBasic Usage
Sending Camera Settings
1import com.hypixel.hytale.protocol.packets.camera.SetServerCamera;2import com.hypixel.hytale.protocol.ClientCameraView;3import com.hypixel.hytale.protocol.ServerCameraSettings;45// Create settings6ServerCameraSettings settings = new ServerCameraSettings();7settings.distance = 15.0f;89// Send to player10player.getPacketHandler().writeNoCache(11 new SetServerCamera(ClientCameraView.Custom, true, settings)12);Camera View Types
| view type | description |
|---|---|
| ClientCameraView.Custom | Custom camera settings |
| ClientCameraView.FirstPerson | First person view |
| ClientCameraView.ThirdPerson | Vanilla third person |
Reset to Vanilla
1// Reset to vanilla third person2player.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 & offset7 public float distance;8 public float speedModifier;9 public Position positionOffset; // Offset from attached entity10 public Direction rotationOffset; // Rotation offset11 12 // Attachment13 public AttachedToType attachedToType; // None, LocalPlayer, EntityId14 public int attachedToEntityId; // Network ID of entity to attach to15 public boolean eyeOffset;16 17 // Position18 public PositionType positionType; // Custom or attached19 public Position position; // For Custom position20 public PositionDistanceOffsetType positionDistanceOffsetType;21 22 // Rotation23 public RotationType rotationType; // Custom or AttachedToPlusOffset24 public Direction rotation; // yaw, pitch, roll (in radians!)25 26 // Controls27 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 // Input35 public MouseInputType mouseInputType;36 public MouseInputTargetType mouseInputTargetType;37 38 // Movement39 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 constructor takes (yaw, pitch, roll), NOT (pitch, yaw, roll)!1// CORRECT2new Direction(yaw, pitch, roll)34// Fields are: yaw, pitch, roll5public 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/entity2ServerCameraSettings settings = new ServerCameraSettings();3settings.attachedToType = AttachedToType.EntityId;4settings.attachedToEntityId = entity.getNetworkId(); // Get from spawned entity5settings.isFirstPerson = false; // false = you can see your character6settings.displayCursor = false;7settings.positionOffset = new Position(0, 1.5f, 0); // Camera height above entity89player.getPacketHandler().writeNoCache(10 new SetServerCamera(ClientCameraView.Custom, true, settings)11);AttachedToType Options
| value | behavior |
|---|---|
| AttachedToType.None | Camera at fixed position (use positionType = Custom) |
| AttachedToType.LocalPlayer | Camera follows the player |
| AttachedToType.EntityId | Camera follows entity with attachedToEntityId |
isFirstPerson = true, your character becomes invisible. Set it to false if you want to see yourself from the camera.Rotation Control
RotationType Options
| value | behavior |
|---|---|
| RotationType.Custom | Use rotation field for camera direction |
| RotationType.AttachedToPlusOffset | Follow entity rotation + rotationOffset |
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 position2double camX = ..., camY = ..., camZ = ...;34// Target position (e.g., player)5Vector3d targetPos = player.getTransform().getPosition();6double targetY = targetPos.getY() + 1.0; // Eye height78// Direction vector: camera -> target9double dx = targetPos.getX() - camX;10double dy = targetY - camY;11double dz = targetPos.getZ() - camZ;1213// Convert to yaw/pitch (radians)14float yaw = (float) (Math.atan2(dx, dz) + Math.PI); // +PI to face target15float pitch = (float) Math.atan2(dy, Math.sqrt(dx * dx + dz * dz));1617// Apply to camera18settings.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/sec2double 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 frequency4double 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;34double 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;78// Also shake the rotation slightly9float 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:
| rule | why |
|---|---|
| Capture player position ONCE at start | Avoid 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 > 50ms | Prevents backlog accumulation |
| Use ConcurrentHashMap for state | Thread safety between scheduler and world |
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
positionType = PositionType.Custom with absolute coordinates often causes client crashes. Attach the camera to an entity instead.LerpSpeed Breaks Camera
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
Too slow (50ms): Visible stuttering, not smooth.
8ms (~125 FPS): Sweet spot for smooth motion without overloading.
Enums Reference
RotationType
| value | behavior |
|---|---|
| RotationType.Custom | Use rotation field directly |
| RotationType.AttachedToPlusOffset | Follow entity rotation (buggy) |
MouseInputType
| value | behavior |
|---|---|
| MouseInputType.LookAtTarget | Mouse controls direction (FPS-like) |
| MouseInputType.LookAtPlane | Mouse points on a plane (RTS-like) |
| MouseInputType.LookAtTargetEntity | Locked on an entity |
| MouseInputType.LookAtTargetBlock | Locked on a block |
AttachedToType
| value | behavior |
|---|---|
| AttachedToType.None | Fixed position camera |
| AttachedToType.LocalPlayer | Follow player |
| AttachedToType.EntityId | Follow entity by network ID |
API Summary
Required Imports
1// Camera2import 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;910// NPC for camera entity11import com.hypixel.hytale.server.npc.NPCPlugin;12import com.hypixel.hytale.server.npc.entities.NPCEntity;13import com.hypixel.hytale.server.core.entity.Frozen;1415// Math16import com.hypixel.hytale.math.vector.Vector3d;17import com.hypixel.hytale.math.vector.Vector3f;Best Practices
| do | don't |
|---|---|
| Attach camera to entity | Use PositionType.Custom |
| Calculate rotation manually | Use AttachedToPlusOffset |
| Update at 8ms for smooth motion | Update at 1ms (backlog) or 50ms (choppy) |
| Capture player position once | Poll position every frame |
| Use tick counter for timing | Use System.currentTimeMillis() |
| Skip frames on lag spikes | Process all queued frames |
| Freeze camera NPC | Let NPC move on its own |