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/Player.hpp"
#include "objects/Players.hpp" #include "objects/Players.hpp"
BlocksController::BlocksController(const Level& level, Lighting* lighting, uint padding) BlocksController::BlocksController(const Level& level, Lighting* lighting)
: level(level), : level(level),
chunks(*level.chunks), chunks(*level.chunks),
lighting(lighting), lighting(lighting),
randTickClock(20, 3), randTickClock(20, 3),
blocksTickClock(20, 1), blocksTickClock(20, 1),
worldTickClock(20, 1), worldTickClock(20, 1) {
padding(padding) {
} }
void BlocksController::updateSides(int x, int y, int z) { 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)) { if (randTickClock.update(delta)) {
randomTick(randTickClock.getPart(), randTickClock.getParts()); randomTick(randTickClock.getPart(), randTickClock.getParts(), padding);
} }
if (blocksTickClock.update(delta)) { if (blocksTickClock.update(delta)) {
onBlocksTick(blocksTickClock.getPart(), blocksTickClock.getParts()); 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(); auto indices = level.content->getIndices();
std::set<uint64_t> chunksIterated; std::set<uint64_t> chunksIterated;

View File

@ -31,11 +31,10 @@ class BlocksController {
util::Clock randTickClock; util::Clock randTickClock;
util::Clock blocksTickClock; util::Clock blocksTickClock;
util::Clock worldTickClock; util::Clock worldTickClock;
uint padding;
FastRandom random {}; FastRandom random {};
std::vector<on_block_interaction> blockInteractionCallbacks; std::vector<on_block_interaction> blockInteractionCallbacks;
public: 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);
void updateSides(int x, int y, int z, int w, int h, int d); 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 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( void randomTick(
const Chunk& chunk, int segments, const ContentIndices* indices 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); void onBlocksTick(int tickid, int parts);
int64_t createBlockInventory(int x, int y, int z); int64_t createBlockInventory(int x, int y, int z);
void bindInventory(int64_t invid, 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 "ChunksController.hpp"
#include <limits.h> #include <limits.h>
#include <iostream>
#include <memory> #include <memory>
#include "content/Content.hpp" #include "content/Content.hpp"
@ -23,9 +21,8 @@
const uint MAX_WORK_PER_FRAME = 128; const uint MAX_WORK_PER_FRAME = 128;
const uint MIN_SURROUNDING = 9; const uint MIN_SURROUNDING = 9;
ChunksController::ChunksController(Level& level, uint padding) ChunksController::ChunksController(Level& level)
: level(level), : level(level),
padding(padding),
generator(std::make_unique<WorldGenerator>( generator(std::make_unique<WorldGenerator>(
level.content->generators.require(level.getWorld()->getGenerator()), level.content->generators.require(level.getWorld()->getGenerator()),
level.content, level.content,
@ -35,7 +32,7 @@ ChunksController::ChunksController(Level& level, uint padding)
ChunksController::~ChunksController() = default; ChunksController::~ChunksController() = default;
void ChunksController::update( void ChunksController::update(
int64_t maxDuration, int loadDistance, Player& player int64_t maxDuration, int loadDistance, uint padding, Player& player
) const { ) const {
const auto& position = player.getPosition(); const auto& position = player.getPosition();
int centerX = floordiv<CHUNK_W>(position.x); int centerX = floordiv<CHUNK_W>(position.x);
@ -47,7 +44,7 @@ void ChunksController::update(
for (uint i = 0; i < MAX_WORK_PER_FRAME; i++) { for (uint i = 0; i < MAX_WORK_PER_FRAME; i++) {
timeutil::Timer timer; timeutil::Timer timer;
if (loadVisible(player)) { if (loadVisible(player, padding)) {
int64_t mcs = timer.stop(); int64_t mcs = timer.stop();
if (mcstotal + mcs < maxDuration * 1000) { if (mcstotal + mcs < maxDuration * 1000) {
mcstotal += mcs; 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; const auto& chunks = *player.chunks;
int sizeX = chunks.getWidth(); int sizeX = chunks.getWidth();
int sizeY = chunks.getHeight(); int sizeY = chunks.getHeight();

View File

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

View File

@ -24,25 +24,41 @@ LevelController::LevelController(
) )
: settings(engine->getSettings()), : settings(engine->getSettings()),
level(std::move(levelPtr)), level(std::move(levelPtr)),
chunks(std::make_unique<ChunksController>( chunks(std::make_unique<ChunksController>(*level)),
*level, settings.chunks.padding.get() playerTickClock(20, 3) {
)) {
if (clientPlayer) { if (clientPlayer) {
chunks->lighting = std::make_unique<Lighting>( chunks->lighting = std::make_unique<Lighting>(
level->content, clientPlayer->chunks.get() level->content, clientPlayer->chunks.get()
); );
} }
blocks = std::make_unique<BlocksController>( blocks = std::make_unique<BlocksController>(
*level, *level, chunks ? chunks->lighting.get() : nullptr
chunks ? chunks->lighting.get() : nullptr,
settings.chunks.padding.get()
); );
scripting::on_world_load(this); 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) { 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(); glm::vec3 position = player->getPosition();
player->chunks->configure( player->chunks->configure(
position.x, position.x,
@ -52,14 +68,33 @@ void LevelController::update(float delta, bool pause) {
chunks->update( chunks->update(
settings.chunks.loadSpeed.get(), settings.chunks.loadSpeed.get(),
settings.chunks.loadDistance.get(), settings.chunks.loadDistance.get(),
settings.chunks.padding.get(),
*player *player
); );
} }
if (!pause) { if (!pause) {
// update all objects that needed // update all objects that needed
blocks->update(delta); blocks->update(delta, settings.chunks.padding.get());
level->entities->updatePhysics(delta); level->entities->updatePhysics(delta);
level->entities->update(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(); level->entities->clean();
} }

View File

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

View File

@ -202,8 +202,7 @@ PlayerController::PlayerController(
level(level), level(level),
player(player), player(player),
camControl(player, settings.camera), camControl(player, settings.camera),
blocksController(blocksController), blocksController(blocksController) {
playerTickClock(20, 3) {
} }
void PlayerController::onFootstep(const Hitbox& hitbox) { void PlayerController::onFootstep(const Hitbox& hitbox) {
@ -256,13 +255,6 @@ void PlayerController::update(float delta, bool input) {
resetKeyboard(); resetKeyboard();
} }
updatePlayer(delta); 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) { void PlayerController::postUpdate(float delta, bool input, bool pause) {

View File

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

View File

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