implement player ticks in headless mode & prevent on_player_tick call if player chunk does not exists

This commit is contained in:
MihailRis 2024-12-18 23:31:26 +03:00
parent 8e7dfe3e0b
commit 1cd85b6f77
9 changed files with 70 additions and 41 deletions

View File

@ -19,14 +19,13 @@
#include "objects/Player.hpp"
#include "objects/Players.hpp"
BlocksController::BlocksController(const Level& level, Lighting* lighting, uint padding)
BlocksController::BlocksController(const Level& level, Lighting* lighting)
: level(level),
chunks(*level.chunks),
lighting(lighting),
randTickClock(20, 3),
blocksTickClock(20, 1),
worldTickClock(20, 1),
padding(padding) {
worldTickClock(20, 1) {
}
void BlocksController::updateSides(int x, int y, int z) {
@ -120,9 +119,9 @@ void BlocksController::updateBlock(int x, int y, int z) {
}
}
void BlocksController::update(float delta) {
void BlocksController::update(float delta, uint padding) {
if (randTickClock.update(delta)) {
randomTick(randTickClock.getPart(), randTickClock.getParts());
randomTick(randTickClock.getPart(), randTickClock.getParts(), padding);
}
if (blocksTickClock.update(delta)) {
onBlocksTick(blocksTickClock.getPart(), blocksTickClock.getParts());
@ -169,7 +168,7 @@ void BlocksController::randomTick(
}
}
void BlocksController::randomTick(int tickid, int parts) {
void BlocksController::randomTick(int tickid, int parts, uint padding) {
auto indices = level.content->getIndices();
std::set<uint64_t> chunksIterated;

View File

@ -31,11 +31,10 @@ class BlocksController {
util::Clock randTickClock;
util::Clock blocksTickClock;
util::Clock worldTickClock;
uint padding;
FastRandom random {};
std::vector<on_block_interaction> blockInteractionCallbacks;
public:
BlocksController(const Level& level, Lighting* lighting, uint padding);
BlocksController(const Level& level, Lighting* lighting);
void updateSides(int x, int y, int z);
void updateSides(int x, int y, int z, int w, int h, int d);
@ -46,11 +45,11 @@ public:
Player* player, const Block& def, blockstate state, int x, int y, int z
);
void update(float delta);
void update(float delta, uint padding);
void randomTick(
const Chunk& chunk, int segments, const ContentIndices* indices
);
void randomTick(int tickid, int parts);
void randomTick(int tickid, int parts, uint padding);
void onBlocksTick(int tickid, int parts);
int64_t createBlockInventory(int x, int y, int z);
void bindInventory(int64_t invid, int x, int y, int z);

View File

@ -1,8 +1,6 @@
#include "ChunksController.hpp"
#include <limits.h>
#include <iostream>
#include <memory>
#include "content/Content.hpp"
@ -23,9 +21,8 @@
const uint MAX_WORK_PER_FRAME = 128;
const uint MIN_SURROUNDING = 9;
ChunksController::ChunksController(Level& level, uint padding)
ChunksController::ChunksController(Level& level)
: level(level),
padding(padding),
generator(std::make_unique<WorldGenerator>(
level.content->generators.require(level.getWorld()->getGenerator()),
level.content,
@ -35,7 +32,7 @@ ChunksController::ChunksController(Level& level, uint padding)
ChunksController::~ChunksController() = default;
void ChunksController::update(
int64_t maxDuration, int loadDistance, Player& player
int64_t maxDuration, int loadDistance, uint padding, Player& player
) const {
const auto& position = player.getPosition();
int centerX = floordiv<CHUNK_W>(position.x);
@ -47,7 +44,7 @@ void ChunksController::update(
for (uint i = 0; i < MAX_WORK_PER_FRAME; i++) {
timeutil::Timer timer;
if (loadVisible(player)) {
if (loadVisible(player, padding)) {
int64_t mcs = timer.stop();
if (mcstotal + mcs < maxDuration * 1000) {
mcstotal += mcs;
@ -58,7 +55,7 @@ void ChunksController::update(
}
}
bool ChunksController::loadVisible(const Player& player) const {
bool ChunksController::loadVisible(const Player& player, uint padding) const {
const auto& chunks = *player.chunks;
int sizeX = chunks.getWidth();
int sizeY = chunks.getHeight();

View File

@ -15,21 +15,22 @@ class WorldGenerator;
class ChunksController {
private:
Level& level;
uint padding;
std::unique_ptr<WorldGenerator> generator;
/// @brief Process one chunk: load it or calculate lights for it
bool loadVisible(const Player& player) const;
bool loadVisible(const Player& player, uint padding) const;
bool buildLights(const Player& player, const std::shared_ptr<Chunk>& chunk) const;
void createChunk(const Player& player, int x, int y) const;
public:
std::unique_ptr<Lighting> lighting;
ChunksController(Level& level, uint padding);
ChunksController(Level& level);
~ChunksController();
/// @param maxDuration milliseconds reserved for chunks loading
void update(int64_t maxDuration, int loadDistance, Player& player) const;
void update(
int64_t maxDuration, int loadDistance, uint padding, Player& player
) const;
const WorldGenerator* getGenerator() const {
return generator.get();

View File

@ -24,25 +24,41 @@ LevelController::LevelController(
)
: settings(engine->getSettings()),
level(std::move(levelPtr)),
chunks(std::make_unique<ChunksController>(
*level, settings.chunks.padding.get()
)) {
chunks(std::make_unique<ChunksController>(*level)),
playerTickClock(20, 3) {
if (clientPlayer) {
chunks->lighting = std::make_unique<Lighting>(
level->content, clientPlayer->chunks.get()
);
}
blocks = std::make_unique<BlocksController>(
*level,
chunks ? chunks->lighting.get() : nullptr,
settings.chunks.padding.get()
*level, chunks ? chunks->lighting.get() : nullptr
);
scripting::on_world_load(this);
// TODO: do something to players added later
int confirmed;
do {
confirmed = 0;
for (const auto& [_, player] : *level->players) {
glm::vec3 position = player->getPosition();
player->chunks->configure(
std::floor(position.x), std::floor(position.z), 1
);
chunks->update(16, 1, 0, *player);
if (player->chunks->get(
std::floor(position.x),
std::floor(position.y),
std::floor(position.z)
)) {
confirmed++;
}
}
} while (confirmed < level->players->size());
}
void LevelController::update(float delta, bool pause) {
for (const auto& [uid, player] : *level->players) {
for (const auto& [_, player] : *level->players) {
glm::vec3 position = player->getPosition();
player->chunks->configure(
position.x,
@ -52,14 +68,33 @@ void LevelController::update(float delta, bool pause) {
chunks->update(
settings.chunks.loadSpeed.get(),
settings.chunks.loadDistance.get(),
settings.chunks.padding.get(),
*player
);
}
if (!pause) {
// update all objects that needed
blocks->update(delta);
blocks->update(delta, settings.chunks.padding.get());
level->entities->updatePhysics(delta);
level->entities->update(delta);
for (const auto& [_, player] : *level->players) {
if (playerTickClock.update(delta)) {
if (player->getId() % playerTickClock.getParts() ==
playerTickClock.getPart()) {
const auto& position = player->getPosition();
if (!player->chunks->get(
std::floor(position.x),
std::floor(position.y),
std::floor(position.z)
)){
scripting::on_player_tick(
player.get(), playerTickClock.getTickRate()
);
}
}
}
}
}
level->entities->clean();
}

View File

@ -4,6 +4,7 @@
#include "BlocksController.hpp"
#include "ChunksController.hpp"
#include "util/Clock.hpp"
class Engine;
class Level;
@ -17,6 +18,8 @@ class LevelController {
// Sub-controllers
std::unique_ptr<BlocksController> blocks;
std::unique_ptr<ChunksController> chunks;
util::Clock playerTickClock;
public:
LevelController(Engine* engine, std::unique_ptr<Level> level, Player* clientPlayer);

View File

@ -202,8 +202,7 @@ PlayerController::PlayerController(
level(level),
player(player),
camControl(player, settings.camera),
blocksController(blocksController),
playerTickClock(20, 3) {
blocksController(blocksController) {
}
void PlayerController::onFootstep(const Hitbox& hitbox) {
@ -256,13 +255,6 @@ void PlayerController::update(float delta, bool input) {
resetKeyboard();
}
updatePlayer(delta);
if (playerTickClock.update(delta)) {
if (player->getId() % playerTickClock.getParts() ==
playerTickClock.getPart()) {
scripting::on_player_tick(player, playerTickClock.getTickRate());
}
}
}
void PlayerController::postUpdate(float delta, bool input, bool pause) {

View File

@ -54,9 +54,8 @@ class PlayerController {
PlayerInput input {};
CameraControl camControl;
BlocksController* blocksController;
util::Clock playerTickClock;
float interactionTimer = 0.0f;
void updateKeyboard();
void resetKeyboard();
void updatePlayer(float delta);

View File

@ -36,4 +36,8 @@ public:
auto end() const {
return players.end();
}
size_t size() const {
return players.size();
}
};