+, aim_world()
+, aim_entity() {
+ player.GetEntity().SetController(*this);
+ player.GetEntity().GetSteering().SetAcceleration(5.0f);
+}
+
+PlayerController::~PlayerController() {
+ if (&player.GetEntity().GetController() == this) {
+ player.GetEntity().UnsetController();
+ }
+}
+
+void PlayerController::SetMovement(const glm::vec3 &m) noexcept {
+ if (glm::dot(m, m) > 1.0f) {
+ move_dir = glm::normalize(m);
+ } else {
+ move_dir = m;
+ }
+ Invalidate();
+}
+
+void PlayerController::TurnHead(float dp, float dy) noexcept {
+ player.GetEntity().TurnHead(dp, dy);
+}
+
+float PlayerController::GetPitch() const noexcept {
+ return player.GetEntity().Pitch();
+}
+
+float PlayerController::GetYaw() const noexcept {
+ return player.GetEntity().Yaw();
+}
+
+void PlayerController::SelectInventory(int i) noexcept {
+ player.SetInventorySlot(i);
+}
+
+int PlayerController::InventorySlot() const noexcept {
+ return player.GetInventorySlot();
+}
+
+void PlayerController::Invalidate() noexcept {
+ dirty = true;
+}
+
+void PlayerController::UpdatePlayer() noexcept {
+ if (dirty) {
+ Ray aim = player.Aim();
+ Entity &entity = player.GetEntity();
+ if (!world.Intersection(aim, entity.ChunkCoords(), aim_world)) {
+ aim_world = WorldCollision();
+ }
+ if (!world.Intersection(aim, entity, aim_entity)) {
+ aim_entity = EntityCollision();
+ }
+ if (aim_world && aim_entity) {
+ // got both, pick the closest one
+ if (aim_world.depth < aim_entity.depth) {
+ aim_entity = EntityCollision();
+ } else {
+ aim_world = WorldCollision();
+ }
+ }
+ Steering &steering = entity.GetSteering();
+ if (!iszero(move_dir)) {
+ // scale input by max velocity, apply yaw, and transform to world space
+ steering.SetTargetVelocity(glm::vec3(
+ glm::vec4(glm::rotateY(move_dir * entity.MaxVelocity(), entity.Yaw()), 0.0f)
+ * glm::transpose(entity.Transform())
+ ));
+ steering.Enable(Steering::TARGET_VELOCITY);
+ steering.Disable(Steering::HALT);
+ } else {
+ // target velocity of 0 is the same as halt
+ steering.Enable(Steering::HALT);
+ steering.Disable(Steering::TARGET_VELOCITY);
+ }
+ dirty = false;
+ }
+}
+
+
+DirectInput::DirectInput(World &world, Player &player, WorldManipulator &manip)
+: PlayerController(world, player)
+, manip(manip)
+, place_timer(0.25f)
+, remove_timer(0.25f) {