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;
}
void Engine::setLevelConsumer(consumer<std::unique_ptr<Level>> levelConsumer) {
void Engine::setLevelConsumer(OnWorldOpen levelConsumer) {
this->levelConsumer = std::move(levelConsumer);
}
@ -446,14 +446,14 @@ void Engine::setLanguage(std::string locale) {
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";
levelConsumer(std::move(level));
levelConsumer(std::move(level), localPlayer);
}
void Engine::onWorldClosed() {
logger.info() << "world closed";
levelConsumer(nullptr);
levelConsumer(nullptr, -1);
}
void Engine::quit() {

View File

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

View File

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

View File

@ -14,6 +14,7 @@
#include "graphics/render/ChunksRenderer.hpp"
#include "logic/scripting/scripting.hpp"
#include "objects/Player.hpp"
#include "objects/Players.hpp"
#include "objects/Entities.hpp"
#include "objects/EntityDef.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 finally
// TODO: move to xml finally
std::shared_ptr<UINode> create_debug_panel(
Engine& engine,
Level& level,
@ -103,6 +105,10 @@ std::shared_ptr<UINode> create_debug_panel(
return L"entities: "+std::to_wstring(level.entities->size())+L" next: "+
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 {
const auto& vox = player.selection.vox;
std::wstringstream stream;

View File

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

View File

@ -34,7 +34,9 @@ class LevelScreen : public Screen {
void initializeContent();
void initializePack(ContentPackRuntime* pack);
public:
LevelScreen(Engine& engine, std::unique_ptr<Level> level);
LevelScreen(
Engine& engine, std::unique_ptr<Level> level, int64_t localPlayer
);
~LevelScreen();
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];
if (chunk != nullptr || !assigned) {
if (chunk != nullptr || !assigned || !player.isLoadingChunks()) {
return false;
}
int offsetX = chunks.getOffsetX();
@ -101,7 +101,9 @@ bool ChunksController::loadVisible(const Player& player, uint padding) const {
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;
for (int oz = -1; oz <= 1; oz++) {
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(
Engine& engine, const std::shared_ptr<WorldFiles>& worldFiles
Engine& engine,
const std::shared_ptr<WorldFiles>& worldFiles,
int64_t localPlayer
) {
try {
auto content = engine.getContent();
@ -151,7 +153,7 @@ static void load_world(
auto& settings = engine.getSettings();
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) {
guiutil::alert(
engine,
@ -233,7 +235,7 @@ void EngineController::openWorld(const std::string& name, bool confirmConvert) {
}
return;
}
load_world(engine, std::move(worldFiles));
load_world(engine, std::move(worldFiles), localPlayer);
}
inline uint64_t str2seed(const std::string& seedstr) {
@ -279,9 +281,13 @@ void EngineController::createWorld(
engine.getContentPacks()
);
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) {

View File

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

View File

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

View File

@ -305,7 +305,6 @@ void PlayerController::resetKeyboard() {
}
void PlayerController::updatePlayer(float delta) {
player.updateEntity();
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 seed = lua::require_string(L, 2);
auto generator = lua::require_string(L, 3);
int64_t localPlayer = 0;
if (lua::gettop(L) >= 4) {
localPlayer = lua::tointeger(L, 4);
}
if (level != nullptr) {
throw std::runtime_error("world must be closed before");
}
auto controller = engine->getController();
controller->setLocalPlayer(localPlayer);
controller->createWorld(name, seed, generator);
return 0;
}
@ -71,6 +76,7 @@ static int l_open_world(lua::State* L) {
throw std::runtime_error("world must be closed before");
}
auto controller = engine->getController();
controller->setLocalPlayer(0);
controller->openWorld(name, false);
return 0;
}

View File

@ -52,6 +52,7 @@ static int l_set_vel(lua::State* L) {
auto x = lua::tonumber(L, 2);
auto y = lua::tonumber(L, 3);
auto z = lua::tonumber(L, 4);
if (auto hitbox = player->getHitbox()) {
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) {
auto player = level->players->create();
if (lua::isstring(L, 1)) {
player->setName(lua::require_string(L, 1));
int64_t playerId = Players::NONE;
if (lua::gettop(L) >= 2) {
playerId = lua::tointeger(L, 2);
}
auto player = level->players->create(playerId);
player->setName(lua::require_string(L, 1));
return lua::pushinteger(L, player->getId());
}
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;
}

View File

@ -20,10 +20,19 @@ Player* Players::get(int64_t id) const {
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>(
level,
level.getWorld()->getInfo().nextPlayerId++,
id,
"",
glm::vec3(0, DEF_PLAYER_Y, 0),
DEF_PLAYER_SPEED,

View File

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