VoxelEngine/src/objects/Player.cpp

340 lines
8.6 KiB
C++

#include "Player.hpp"
#include "../content/ContentLUT.hpp"
#include "../physics/Hitbox.hpp"
#include "../physics/PhysicsSolver.hpp"
#include "../voxels/Chunks.hpp"
#include "../world/Level.hpp"
#include "../window/Events.hpp"
#include "../window/Camera.hpp"
#include "../items/Inventory.hpp"
#include "../objects/Entities.hpp"
#include "../objects/rigging.hpp"
#include <algorithm>
#include <glm/glm.hpp>
#include <utility>
const float CROUCH_SPEED_MUL = 0.35f;
const float RUN_SPEED_MUL = 1.5f;
const float PLAYER_GROUND_DAMPING = 10.0f;
const float PLAYER_AIR_DAMPING = 7.0f;
const float FLIGHT_SPEED_MUL = 4.0f;
const float CHEAT_SPEED_MUL = 5.0f;
const float JUMP_FORCE = 8.0f;
Player::Player(Level* level, glm::vec3 position, float speed,
std::shared_ptr<Inventory> inv, entityid_t eid) :
level(level),
speed(speed),
chosenSlot(0),
position(position),
inventory(std::move(inv)),
eid(eid),
camera(level->getCamera("base:first-person")),
spCamera(level->getCamera("base:third-person-front")),
tpCamera(level->getCamera("base:third-person-back")),
currentCamera(camera)
{
camera->setFov(glm::radians(90.0f));
spCamera->setFov(glm::radians(90.0f));
tpCamera->setFov(glm::radians(90.0f));
}
Player::~Player() {
}
void Player::updateEntity() {
if (eid == 0) {
auto& def = level->content->entities.require("base:player");
eid = level->entities->spawn(def, getPosition());
} else if (auto entity = level->entities->get(eid)) {
position = entity->getTransform().pos;
} else {
// TODO: check if chunk loaded
}
}
Hitbox* Player::getHitbox() {
if (auto entity = level->entities->get(eid)) {
return &entity->getRigidbody().hitbox;
}
return nullptr;
}
void Player::updateInput(PlayerInput& input, float delta) {
auto hitbox = getHitbox();
if (hitbox == nullptr) {
return;
}
bool crouch = input.shift && hitbox->grounded && !input.sprint;
float speed = this->speed;
if (flight){
speed *= FLIGHT_SPEED_MUL;
}
if (input.cheat){
speed *= CHEAT_SPEED_MUL;
}
hitbox->crouching = crouch;
if (crouch) {
speed *= CROUCH_SPEED_MUL;
} else if (input.sprint) {
speed *= RUN_SPEED_MUL;
}
glm::vec3 dir(0,0,0);
if (input.moveForward){
dir += camera->dir;
}
if (input.moveBack){
dir -= camera->dir;
}
if (input.moveRight){
dir += camera->right;
}
if (input.moveLeft){
dir -= camera->right;
}
if (glm::length(dir) > 0.0f){
dir = glm::normalize(dir);
hitbox->velocity += dir * speed * delta * 9.0f;
}
hitbox->linearDamping = PLAYER_GROUND_DAMPING;
hitbox->verticalDamping = flight;
hitbox->gravityScale = flight ? 0.0f : 1.0f;
if (flight){
hitbox->linearDamping = PLAYER_AIR_DAMPING;
if (input.jump){
hitbox->velocity.y += speed * delta * 9;
}
if (input.shift){
hitbox->velocity.y -= speed * delta * 9;
}
}
if (!hitbox->grounded) {
hitbox->linearDamping = PLAYER_AIR_DAMPING;
}
if (input.jump && hitbox->grounded){
hitbox->velocity.y = JUMP_FORCE;
}
if ((input.flight && !noclip) ||
(input.noclip && flight == noclip)){
flight = !flight;
if (flight){
hitbox->velocity.y += 1.0f;
}
}
hitbox->type = noclip ? BodyType::KINEMATIC : BodyType::DYNAMIC;
if (input.noclip) {
noclip = !noclip;
}
input.noclip = false;
input.flight = false;
}
void Player::updateSelectedEntity() {
selectedEid = selection.entity;
}
#include "../window/Window.hpp"
void Player::postUpdate() {
auto entity = level->entities->get(eid);
if (!entity.has_value()) {
return;
}
auto& hitbox = entity->getRigidbody().hitbox;
position = hitbox.position;
if (flight && hitbox.grounded) {
flight = false;
}
if (spawnpoint.y <= 0.1) {
attemptToFindSpawnpoint();
}
auto& skeleton = entity->getSkeleton();
skeleton.visible = currentCamera != camera;
size_t bodyIndex = skeleton.config->find("body")->getIndex();
size_t headIndex = skeleton.config->find("head")->getIndex();
skeleton.pose.matrices[bodyIndex] =
glm::rotate(glm::mat4(1.0f), glm::radians(cam.x), glm::vec3(0, 1, 0));
skeleton.pose.matrices[headIndex] = glm::rotate(
glm::mat4(1.0f), glm::radians(cam.y), glm::vec3(1, 0, 0));
}
void Player::teleport(glm::vec3 position) {
this->position = position;
if (auto hitbox = getHitbox()) {
hitbox->position = position;
}
}
void Player::attemptToFindSpawnpoint() {
glm::vec3 newpos (
position.x + (rand() % 200 - 100),
rand() % 80 + 100,
position.z + (rand() % 200 - 100)
);
while (newpos.y > 0 && !level->chunks->isObstacleBlock(newpos.x, newpos.y-2, newpos.z)) {
newpos.y--;
}
voxel* headvox = level->chunks->get(newpos.x, newpos.y+1, newpos.z);
if (level->chunks->isObstacleBlock(newpos.x, newpos.y, newpos.z) ||
headvox == nullptr || headvox->id != 0) {
return;
}
spawnpoint = newpos + glm::vec3(0.5f, 0.0f, 0.5f);
teleport(spawnpoint);
}
void Player::setChosenSlot(int index) {
chosenSlot = index;
}
int Player::getChosenSlot() const {
return chosenSlot;
}
float Player::getSpeed() const {
return speed;
}
bool Player::isFlight() const {
return flight;
}
void Player::setFlight(bool flag) {
this->flight = flag;
}
bool Player::isNoclip() const {
return noclip;
}
void Player::setNoclip(bool flag) {
this->noclip = flag;
}
entityid_t Player::getEntity() const {
return eid;
}
void Player::setEntity(entityid_t eid) {
this->eid = eid;
}
entityid_t Player::getSelectedEntity() const {
return selectedEid;
}
std::shared_ptr<Inventory> Player::getInventory() const {
return inventory;
}
void Player::setSpawnPoint(glm::vec3 spawnpoint) {
this->spawnpoint = spawnpoint;
}
glm::vec3 Player::getSpawnPoint() const {
return spawnpoint;
}
std::unique_ptr<dynamic::Map> Player::serialize() const {
auto root = std::make_unique<dynamic::Map>();
auto& posarr = root->putList("position");
posarr.put(position.x);
posarr.put(position.y);
posarr.put(position.z);
auto& rotarr = root->putList("rotation");
rotarr.put(cam.x);
rotarr.put(cam.y);
rotarr.put(cam.z);
auto& sparr = root->putList("spawnpoint");
sparr.put(spawnpoint.x);
sparr.put(spawnpoint.y);
sparr.put(spawnpoint.z);
root->put("flight", flight);
root->put("noclip", noclip);
root->put("chosen-slot", chosenSlot);
root->put("entity", eid);
root->put("inventory", inventory->serialize());
auto found = std::find(
level->cameras.begin(), level->cameras.end(), currentCamera);
if (found != level->cameras.end()) {
root->put("camera", level->content->getIndices(
ResourceType::CAMERA).getName(found - level->cameras.begin()));
}
return root;
}
void Player::deserialize(dynamic::Map *src) {
auto posarr = src->list("position");
position.x = posarr->num(0);
position.y = posarr->num(1);
position.z = posarr->num(2);
camera->position = position;
auto rotarr = src->list("rotation");
cam.x = rotarr->num(0);
cam.y = rotarr->num(1);
if (rotarr->size() > 2) {
cam.z = rotarr->num(2);
}
if (src->has("spawnpoint")) {
auto sparr = src->list("spawnpoint");
setSpawnPoint(glm::vec3(
sparr->num(0),
sparr->num(1),
sparr->num(2)
));
} else {
setSpawnPoint(position);
}
src->flag("flight", flight);
src->flag("noclip", noclip);
setChosenSlot(src->get("chosen-slot", getChosenSlot()));
src->num("entity", eid);
if (auto invmap = src->map("inventory")) {
getInventory()->deserialize(invmap.get());
}
if (src->has("camera")) {
std::string name;
src->str("camera", name);
if (auto camera = level->getCamera(name)) {
currentCamera = camera;
}
}
}
void Player::convert(dynamic::Map* data, const ContentLUT* lut) {
auto players = data->list("players");
if (players) {
for (uint i = 0; i < players->size(); i++) {
auto playerData = players->map(i);
if (auto inventory = playerData->map("inventory")) {
Inventory::convert(inventory.get(), lut);
}
}
} else {
if (auto inventory = data->map("inventory")) {
Inventory::convert(inventory.get(), lut);
}
}
}