introduce local player

This commit is contained in:
MihailRis 2025-01-16 05:59:43 +03:00
parent b5999fe364
commit 65fec4f4a9
16 changed files with 84 additions and 31 deletions

View File

@ -272,7 +272,7 @@ PacksManager Engine::createPacksManager(const fs::path& worldFolder) {
return manager; return manager;
} }
void Engine::setLevelConsumer(consumer<std::unique_ptr<Level>> levelConsumer) { void Engine::setLevelConsumer(OnWorldOpen levelConsumer) {
this->levelConsumer = std::move(levelConsumer); this->levelConsumer = std::move(levelConsumer);
} }
@ -446,14 +446,14 @@ void Engine::setLanguage(std::string locale) {
langs::setup(paths.getResourcesFolder(), std::move(locale), contentPacks); langs::setup(paths.getResourcesFolder(), std::move(locale), contentPacks);
} }
void Engine::onWorldOpen(std::unique_ptr<Level> level) { void Engine::onWorldOpen(std::unique_ptr<Level> level, int64_t localPlayer) {
logger.info() << "world open"; logger.info() << "world open";
levelConsumer(std::move(level)); levelConsumer(std::move(level), localPlayer);
} }
void Engine::onWorldClosed() { void Engine::onWorldClosed() {
logger.info() << "world closed"; logger.info() << "world closed";
levelConsumer(nullptr); levelConsumer(nullptr, -1);
} }
void Engine::quit() { void Engine::quit() {

View File

@ -53,6 +53,8 @@ struct CoreParameters {
std::filesystem::path scriptFile; std::filesystem::path scriptFile;
}; };
using OnWorldOpen = std::function<void(std::unique_ptr<Level>, int64_t)>;
class Engine : public util::ObjectsKeeper { class Engine : public util::ObjectsKeeper {
CoreParameters params; CoreParameters params;
EngineSettings settings; EngineSettings settings;
@ -71,7 +73,7 @@ class Engine : public util::ObjectsKeeper {
std::unique_ptr<gui::GUI> gui; std::unique_ptr<gui::GUI> gui;
PostRunnables postRunnables; PostRunnables postRunnables;
Time time; Time time;
consumer<std::unique_ptr<Level>> levelConsumer; OnWorldOpen levelConsumer;
bool quitSignal = false; bool quitSignal = false;
void loadControls(); void loadControls();
@ -134,7 +136,7 @@ public:
/// @brief Get engine resource paths controller /// @brief Get engine resource paths controller
ResPaths* getResPaths(); ResPaths* getResPaths();
void onWorldOpen(std::unique_ptr<Level> level); void onWorldOpen(std::unique_ptr<Level> level, int64_t localPlayer);
void onWorldClosed(); void onWorldClosed();
void quit(); void quit();
@ -166,7 +168,7 @@ public:
PacksManager createPacksManager(const fs::path& worldFolder); PacksManager createPacksManager(const fs::path& worldFolder);
void setLevelConsumer(consumer<std::unique_ptr<Level>> levelConsumer); void setLevelConsumer(OnWorldOpen levelConsumer);
SettingsHandler& getSettingsHandler(); SettingsHandler& getSettingsHandler();

View File

@ -15,14 +15,16 @@ Mainloop::Mainloop(Engine& engine) : engine(engine) {
void Mainloop::run() { void Mainloop::run() {
auto& time = engine.getTime(); auto& time = engine.getTime();
engine.setLevelConsumer([this](auto level) { engine.setLevelConsumer([this](auto level, int64_t localPlayer) {
if (level == nullptr) { if (level == nullptr) {
// destroy LevelScreen and run quit callbacks // destroy LevelScreen and run quit callbacks
engine.setScreen(nullptr); engine.setScreen(nullptr);
// create and go to menu screen // create and go to menu screen
engine.setScreen(std::make_shared<MenuScreen>(engine)); engine.setScreen(std::make_shared<MenuScreen>(engine));
} else { } else {
engine.setScreen(std::make_shared<LevelScreen>(engine, std::move(level))); engine.setScreen(std::make_shared<LevelScreen>(
engine, std::move(level), localPlayer
));
} }
}); });

View File

@ -30,7 +30,7 @@ void ServerMainloop::run() {
logger.info() << "nothing to do"; logger.info() << "nothing to do";
return; return;
} }
engine.setLevelConsumer([this](auto level) { engine.setLevelConsumer([this](auto level, auto) {
setLevel(std::move(level)); setLevel(std::move(level));
}); });

View File

@ -14,6 +14,7 @@
#include "graphics/render/ChunksRenderer.hpp" #include "graphics/render/ChunksRenderer.hpp"
#include "logic/scripting/scripting.hpp" #include "logic/scripting/scripting.hpp"
#include "objects/Player.hpp" #include "objects/Player.hpp"
#include "objects/Players.hpp"
#include "objects/Entities.hpp" #include "objects/Entities.hpp"
#include "objects/EntityDef.hpp" #include "objects/EntityDef.hpp"
#include "physics/Hitbox.hpp" #include "physics/Hitbox.hpp"
@ -41,6 +42,7 @@ static std::shared_ptr<Label> create_label(wstringsupplier supplier) {
// TODO: move to xml // TODO: move to xml
// TODO: move to xml finally // TODO: move to xml finally
// TODO: move to xml finally
std::shared_ptr<UINode> create_debug_panel( std::shared_ptr<UINode> create_debug_panel(
Engine& engine, Engine& engine,
Level& level, Level& level,
@ -103,6 +105,10 @@ std::shared_ptr<UINode> create_debug_panel(
return L"entities: "+std::to_wstring(level.entities->size())+L" next: "+ return L"entities: "+std::to_wstring(level.entities->size())+L" next: "+
std::to_wstring(level.entities->peekNextID()); std::to_wstring(level.entities->peekNextID());
})); }));
panel->add(create_label([&]() {
return L"players: "+std::to_wstring(level.players->size())+L" local: "+
std::to_wstring(player.getId());
}));
panel->add(create_label([&]() -> std::wstring { panel->add(create_label([&]() -> std::wstring {
const auto& vox = player.selection.vox; const auto& vox = player.selection.vox;
std::wstringstream stream; std::wstringstream stream;

View File

@ -36,9 +36,10 @@
static debug::Logger logger("level-screen"); static debug::Logger logger("level-screen");
LevelScreen::LevelScreen(Engine& engine, std::unique_ptr<Level> levelPtr) LevelScreen::LevelScreen(
: Screen(engine), postProcessing(std::make_unique<PostProcessing>()) Engine& engine, std::unique_ptr<Level> levelPtr, int64_t localPlayer
{ )
: Screen(engine), postProcessing(std::make_unique<PostProcessing>()) {
Level* level = levelPtr.get(); Level* level = levelPtr.get();
auto& settings = engine.getSettings(); auto& settings = engine.getSettings();
@ -46,7 +47,9 @@ LevelScreen::LevelScreen(Engine& engine, std::unique_ptr<Level> levelPtr)
auto menu = engine.getGUI()->getMenu(); auto menu = engine.getGUI()->getMenu();
menu->reset(); menu->reset();
auto player = level->players->get(0); auto player = level->players->get(localPlayer);
assert(player != nullptr);
controller = controller =
std::make_unique<LevelController>(&engine, std::move(levelPtr), player); std::make_unique<LevelController>(&engine, std::move(levelPtr), player);
playerController = std::make_unique<PlayerController>( playerController = std::make_unique<PlayerController>(
@ -173,6 +176,7 @@ void LevelScreen::update(float delta) {
updateHotkeys(); updateHotkeys();
} }
auto level = controller->getLevel();
auto player = playerController->getPlayer(); auto player = playerController->getPlayer();
auto camera = player->currentCamera; auto camera = player->currentCamera;
@ -189,7 +193,6 @@ void LevelScreen::update(float delta) {
camera->dir, camera->dir,
glm::vec3(0, 1, 0) glm::vec3(0, 1, 0)
); );
auto level = controller->getLevel();
const auto& settings = engine.getSettings(); const auto& settings = engine.getSettings();
if (!hud->isPause()) { if (!hud->isPause()) {

View File

@ -34,7 +34,9 @@ class LevelScreen : public Screen {
void initializeContent(); void initializeContent();
void initializePack(ContentPackRuntime* pack); void initializePack(ContentPackRuntime* pack);
public: public:
LevelScreen(Engine& engine, std::unique_ptr<Level> level); LevelScreen(
Engine& engine, std::unique_ptr<Level> level, int64_t localPlayer
);
~LevelScreen(); ~LevelScreen();
void update(float delta) override; void update(float delta) override;

View File

@ -92,7 +92,7 @@ bool ChunksController::loadVisible(const Player& player, uint padding) const {
} }
const auto& chunk = chunks.getChunks()[nearZ * sizeX + nearX]; const auto& chunk = chunks.getChunks()[nearZ * sizeX + nearX];
if (chunk != nullptr || !assigned) { if (chunk != nullptr || !assigned || !player.isLoadingChunks()) {
return false; return false;
} }
int offsetX = chunks.getOffsetX(); int offsetX = chunks.getOffsetX();
@ -101,7 +101,9 @@ bool ChunksController::loadVisible(const Player& player, uint padding) const {
return true; return true;
} }
bool ChunksController::buildLights(const Player& player, const std::shared_ptr<Chunk>& chunk) const { bool ChunksController::buildLights(
const Player& player, const std::shared_ptr<Chunk>& chunk
) const {
int surrounding = 0; int surrounding = 0;
for (int oz = -1; oz <= 1; oz++) { for (int oz = -1; oz <= 1; oz++) {
for (int ox = -1; ox <= 1; ox++) { for (int ox = -1; ox <= 1; ox++) {

View File

@ -143,7 +143,9 @@ static bool load_world_content(Engine& engine, const fs::path& folder) {
} }
static void load_world( static void load_world(
Engine& engine, const std::shared_ptr<WorldFiles>& worldFiles Engine& engine,
const std::shared_ptr<WorldFiles>& worldFiles,
int64_t localPlayer
) { ) {
try { try {
auto content = engine.getContent(); auto content = engine.getContent();
@ -151,7 +153,7 @@ static void load_world(
auto& settings = engine.getSettings(); auto& settings = engine.getSettings();
auto level = World::load(worldFiles, settings, *content, packs); auto level = World::load(worldFiles, settings, *content, packs);
engine.onWorldOpen(std::move(level)); engine.onWorldOpen(std::move(level), localPlayer);
} catch (const world_load_error& error) { } catch (const world_load_error& error) {
guiutil::alert( guiutil::alert(
engine, engine,
@ -233,7 +235,7 @@ void EngineController::openWorld(const std::string& name, bool confirmConvert) {
} }
return; return;
} }
load_world(engine, std::move(worldFiles)); load_world(engine, std::move(worldFiles), localPlayer);
} }
inline uint64_t str2seed(const std::string& seedstr) { inline uint64_t str2seed(const std::string& seedstr) {
@ -279,9 +281,13 @@ void EngineController::createWorld(
engine.getContentPacks() engine.getContentPacks()
); );
if (!engine.isHeadless()) { if (!engine.isHeadless()) {
level->players->create(); level->players->create(localPlayer);
} }
engine.onWorldOpen(std::move(level)); engine.onWorldOpen(std::move(level), localPlayer);
}
void EngineController::setLocalPlayer(int64_t player) {
localPlayer = player;
} }
void EngineController::reopenWorld(World* world) { void EngineController::reopenWorld(World* world) {

View File

@ -12,6 +12,7 @@ class LevelController;
class EngineController { class EngineController {
Engine& engine; Engine& engine;
int64_t localPlayer = -1;
void onMissingContent(const std::shared_ptr<ContentReport>& report); void onMissingContent(const std::shared_ptr<ContentReport>& report);
public: public:
EngineController(Engine& engine); EngineController(Engine& engine);
@ -37,5 +38,7 @@ public:
const std::string& generatorID const std::string& generatorID
); );
void setLocalPlayer(int64_t player);
void reopenWorld(World* world); void reopenWorld(World* world);
}; };

View File

@ -50,6 +50,10 @@ LevelController::LevelController(
do { do {
confirmed = 0; confirmed = 0;
for (const auto& [_, player] : *level->players) { for (const auto& [_, player] : *level->players) {
if (!player->isLoadingChunks()) {
confirmed++;
continue;
}
glm::vec3 position = player->getPosition(); glm::vec3 position = player->getPosition();
player->chunks->configure( player->chunks->configure(
std::floor(position.x), std::floor(position.z), 1 std::floor(position.x), std::floor(position.z), 1
@ -69,6 +73,7 @@ void LevelController::update(float delta, bool pause) {
if (player->isSuspended()) { if (player->isSuspended()) {
continue; continue;
} }
player->updateEntity();
glm::vec3 position = player->getPosition(); glm::vec3 position = player->getPosition();
player->chunks->configure( player->chunks->configure(
position.x, position.x,

View File

@ -305,7 +305,6 @@ void PlayerController::resetKeyboard() {
} }
void PlayerController::updatePlayer(float delta) { void PlayerController::updatePlayer(float delta) {
player.updateEntity();
player.updateInput(input, delta); player.updateInput(input, delta);
} }

View File

@ -55,10 +55,15 @@ static int l_new_world(lua::State* L) {
auto name = lua::require_string(L, 1); auto name = lua::require_string(L, 1);
auto seed = lua::require_string(L, 2); auto seed = lua::require_string(L, 2);
auto generator = lua::require_string(L, 3); auto generator = lua::require_string(L, 3);
int64_t localPlayer = 0;
if (lua::gettop(L) >= 4) {
localPlayer = lua::tointeger(L, 4);
}
if (level != nullptr) { if (level != nullptr) {
throw std::runtime_error("world must be closed before"); throw std::runtime_error("world must be closed before");
} }
auto controller = engine->getController(); auto controller = engine->getController();
controller->setLocalPlayer(localPlayer);
controller->createWorld(name, seed, generator); controller->createWorld(name, seed, generator);
return 0; return 0;
} }
@ -71,6 +76,7 @@ static int l_open_world(lua::State* L) {
throw std::runtime_error("world must be closed before"); throw std::runtime_error("world must be closed before");
} }
auto controller = engine->getController(); auto controller = engine->getController();
controller->setLocalPlayer(0);
controller->openWorld(name, false); controller->openWorld(name, false);
return 0; return 0;
} }

View File

@ -52,6 +52,7 @@ static int l_set_vel(lua::State* L) {
auto x = lua::tonumber(L, 2); auto x = lua::tonumber(L, 2);
auto y = lua::tonumber(L, 3); auto y = lua::tonumber(L, 3);
auto z = lua::tonumber(L, 4); auto z = lua::tonumber(L, 4);
if (auto hitbox = player->getHitbox()) { if (auto hitbox = player->getHitbox()) {
hitbox->velocity = glm::vec3(x, y, z); hitbox->velocity = glm::vec3(x, y, z);
} }
@ -272,15 +273,19 @@ static int l_set_name(lua::State* L) {
} }
static int l_create(lua::State* L) { static int l_create(lua::State* L) {
auto player = level->players->create(); int64_t playerId = Players::NONE;
if (lua::isstring(L, 1)) { if (lua::gettop(L) >= 2) {
player->setName(lua::require_string(L, 1)); playerId = lua::tointeger(L, 2);
} }
auto player = level->players->create(playerId);
player->setName(lua::require_string(L, 1));
return lua::pushinteger(L, player->getId()); return lua::pushinteger(L, player->getId());
} }
static int l_delete(lua::State* L) { static int l_delete(lua::State* L) {
level->players->remove(lua::tointeger(L, 1)); auto id = lua::tointeger(L, 1);
level->players->suspend(id);
level->players->remove(id);
return 0; return 0;
} }

View File

@ -20,10 +20,19 @@ Player* Players::get(int64_t id) const {
return found->second.get(); return found->second.get();
} }
Player* Players::create() { Player* Players::create(int64_t id) {
int64_t& nextPlayerID = level.getWorld()->getInfo().nextPlayerId;
if (id == NONE) {
id = nextPlayerID++;
} else {
if (auto player = get(id)) {
return player;
}
nextPlayerID = std::max(id + 1, nextPlayerID);
}
auto playerPtr = std::make_unique<Player>( auto playerPtr = std::make_unique<Player>(
level, level,
level.getWorld()->getInfo().nextPlayerId++, id,
"", "",
glm::vec3(0, DEF_PLAYER_Y, 0), glm::vec3(0, DEF_PLAYER_Y, 0),
DEF_PLAYER_SPEED, DEF_PLAYER_SPEED,

View File

@ -14,6 +14,9 @@ class Level;
class Player; class Player;
class Players : public Serializable { class Players : public Serializable {
public:
static inline int64_t NONE = -1;
private:
Level& level; Level& level;
std::unordered_map<int64_t, std::unique_ptr<Player>> players; std::unordered_map<int64_t, std::unique_ptr<Player>> players;
@ -23,7 +26,7 @@ public:
Player* get(int64_t id) const; Player* get(int64_t id) const;
Player* create(); Player* create(int64_t id=NONE);
void suspend(int64_t id); void suspend(int64_t id);