+ Invalidate();
+}
+
+glm::vec3 PlayerController::ControlForce(const Entity &e, const EntityState &s) const {
+ if (!iszero(move_dir)) {
+ // scale input by max velocity, apply yaw, and transform to world space
+ return TargetVelocity(glm::vec3(glm::vec4(rotateY(move_dir * e.MaxVelocity(), s.yaw), 0.0f) * transpose(e.Transform())), s, 5.0f);
+ } else {
+ // target velocity of 0 is the same as halt
+ return Halt(s, 5.0f);
+ }
+}
+
+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 {