Skip to content

Commit

Permalink
Lobby: show own worlds
Browse files Browse the repository at this point in the history
  • Loading branch information
SmallJoker committed Feb 19, 2023
1 parent cdae68f commit 882b77d
Show file tree
Hide file tree
Showing 10 changed files with 140 additions and 51 deletions.
Binary file modified assets/textures/pack_owner.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 0 additions & 4 deletions src/client/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,6 @@ struct ClientStartData {
std::string nickname;
};

struct LobbyWorld : public WorldMeta {
blockpos_t size;
};

// Abstract for inheritance
class Client : public Environment, public GameEventHandler {
public:
Expand Down
2 changes: 1 addition & 1 deletion src/client/client_packethandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ void Client::pkt_Lobby(Packet &pkt)

std::string world_id(pkt.readStr16());

LobbyWorld world;
LobbyWorld world(world_id);
world.readCommon(pkt);
world.size.X = pkt.read<u16>();
world.size.Y = pkt.read<u16>();
Expand Down
9 changes: 9 additions & 0 deletions src/core/world.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ struct BlockUpdateHash {
};

struct WorldMeta {
WorldMeta(const std::string &id) :
id(id) {}

// For networking
void readCommon(Packet &pkt);
void writeCommon(Packet &pkt) const;
Expand Down Expand Up @@ -72,6 +75,12 @@ struct WorldMeta {
} keys[3] = {};
};

struct LobbyWorld : public WorldMeta {
LobbyWorld(const std::string &id) :
WorldMeta(id) {}

blockpos_t size;
};

class World : public IReferenceCounted {
public:
Expand Down
8 changes: 6 additions & 2 deletions src/gui/gameplay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,11 @@ void SceneGameplay::step(float dtime)

bool SceneGameplay::OnEvent(const SEvent &e)
{
if (m_blockselector->OnEvent(e))
return true;
auto element = m_gui->guienv->getFocus();
if (!element || element->getID() != ID_BoxChat) {
if (m_blockselector->OnEvent(e))
return true;
}

if (e.EventType == EET_GUI_EVENT) {
switch (e.GUIEvent.EventType) {
Expand Down Expand Up @@ -263,6 +266,7 @@ bool SceneGameplay::OnEvent(const SEvent &e)
m_ignore_keys = true;
break;
case gui::EGET_ELEMENT_FOCUS_LOST:
// !! This is not triggered when dragging & releasing the mouse
m_ignore_keys = false;
break;
default: break;
Expand Down
61 changes: 49 additions & 12 deletions src/gui/lobby.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "lobby.h"
#include "client/client.h"
#include "client/localplayer.h"
#include <IGUIButton.h>
#include <IGUIEnvironment.h>
#include <IGUIListBox.h>
Expand All @@ -9,7 +10,8 @@
enum ElementId : int {
ID_LabelLobby = 100,
ID_BtnRefresh,
ID_ListWorlds,
ID_ListPublic,
ID_ListMine,
ID_BoxWorldID,
ID_BtnJoin,
};
Expand All @@ -33,7 +35,7 @@ void SceneLobby::draw()

{
auto rect = m_gui->getRect({10, 15}, {80, 30});
m_worldlist = gui->addListBox(rect, nullptr, ID_ListWorlds, true);
m_publiclist = gui->addListBox(rect, nullptr, ID_ListPublic, true);

core::recti rect_lab(
rect.UpperLeftCorner + core::vector2di(0, -25),
Expand All @@ -49,9 +51,21 @@ void SceneLobby::draw()
m_refreshbtn = gui->addButton(rect_btn, nullptr, ID_BtnRefresh, L"Refresh");
}

{
auto rect = m_gui->getRect({10, 51}, {80, 25});
m_mylist = gui->addListBox(rect, nullptr, ID_ListMine, true);

core::recti rect_lab(
rect.UpperLeftCorner + core::vector2di(0, -25),
core::dimension2di(100, 25)
);
auto e = gui->addStaticText(L"My worlds", rect_lab);
e->setOverrideColor(Gui::COLOR_ON_BG);
}

{
// Custom world ID box
auto rect = m_gui->getRect({10, 75}, {20, -30});
auto rect = m_gui->getRect({10, 83}, {20, -30});
gui->addEditBox(L"", rect, true, nullptr, ID_BoxWorldID);

core::recti rect_lab(
Expand All @@ -61,7 +75,7 @@ void SceneLobby::draw()
auto e = gui->addStaticText(L"Custom world ID", rect_lab);
e->setOverrideColor(Gui::COLOR_ON_BG);

auto rect_btn = m_gui->getRect({32, 75}, {-100, -30});
auto rect_btn = m_gui->getRect({32, 83}, {-100, -30});
gui->addButton(rect_btn, nullptr, ID_BtnJoin, L"Join");
}

Expand Down Expand Up @@ -97,11 +111,22 @@ bool SceneLobby::OnEvent(const SEvent &e)
}
break;
case gui::EGET_LISTBOX_SELECTED_AGAIN:
if (e.GUIEvent.Caller->getID() == ID_ListWorlds) {
if (e.GUIEvent.Caller->getID() == ID_ListPublic) {
gui::IGUIListBox *list = (gui::IGUIListBox *)e.GUIEvent.Caller;

try {
world_id = m_index_to_worldid.at(list->getSelected());
world_id = m_public_index_to_worldid.at(list->getSelected());
} catch (std::exception &) {
break;
}

m_gui->joinWorld(this);
}
if (e.GUIEvent.Caller->getID() == ID_ListMine) {
gui::IGUIListBox *list = (gui::IGUIListBox *)e.GUIEvent.Caller;

try {
world_id = m_my_index_to_worldid.at(list->getSelected());
} catch (std::exception &) {
break;
}
Expand Down Expand Up @@ -134,26 +159,38 @@ void SceneLobby::updateWorldList()
return;
m_dirty_worldlist = false;

m_worldlist->clear();
m_index_to_worldid.clear();
m_publiclist->clear();
m_mylist->clear();
m_public_index_to_worldid.clear();
m_my_index_to_worldid.clear();

auto player = m_gui->getClient()->getMyPlayer();
auto worlds = m_gui->getClient()->world_list;

for (const auto &it : worlds) {
bool is_mine = player->name == it.second.owner;
auto size = it.second.size;

std::ostringstream os;
os << "[" << it.second.online << " online]";
os << " id=" << it.first;
os << " ( " << size.X << "x" << size.Y << " )";
os << " by " << it.second.owner;
if (is_mine)
os << (it.second.is_public ? " - public" : " - private");
else
os << " by " << it.second.owner;

core::stringw textw;
core::multibyteToWString(textw, os.str().c_str());
auto i = m_worldlist->addItem(textw.c_str());
m_worldlist->setItemOverrideColor(i, 0xFFFFFFFF);
auto dst = is_mine ? m_mylist : m_publiclist;

auto i = dst->addItem(textw.c_str());
dst->setItemOverrideColor(i, 0xFFFFFFFF);

m_index_to_worldid.push_back(it.first);
if (is_mine)
m_my_index_to_worldid.push_back(it.first);
else
m_public_index_to_worldid.push_back(it.first);
}

m_refreshbtn->setEnabled(true);
Expand Down
6 changes: 4 additions & 2 deletions src/gui/lobby.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ class SceneLobby : public SceneHandler {
private:
void updateWorldList();
bool m_dirty_worldlist = false;
std::vector<std::string> m_index_to_worldid;
gui::IGUIListBox *m_worldlist = nullptr;
std::vector<std::string> m_public_index_to_worldid,
m_my_index_to_worldid;
gui::IGUIListBox *m_publiclist = nullptr;
gui::IGUIListBox *m_mylist = nullptr;
gui::IGUIButton *m_refreshbtn = nullptr;
};
71 changes: 49 additions & 22 deletions src/server/database_world.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#include "database_world.h"
#include "core/packet.h"
#include "core/world.h"
#include <sqlite3.h>

DatabaseWorld::~DatabaseWorld()
Expand All @@ -24,6 +23,7 @@ bool DatabaseWorld::tryOpen(const char *filepath)
"`width` INTEGER,"
"`height` INTEGER,"
"`owner` TEXT,"
"`title` TEXT,"
"`plays` INTEGER,"
"`visibility` INTEGER,"
"`player_flags` BLOB,"
Expand All @@ -43,9 +43,13 @@ bool DatabaseWorld::tryOpen(const char *filepath)
-1, &m_stmt_read, nullptr));
good &= ok("write", sqlite3_prepare_v2(m_database,
"REPLACE INTO `worlds` "
"(`id`, `width`, `height`, `owner`, `plays`, `visibility`, `player_flags`, `data`) "
"VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
"(`id`, `width`, `height`, `owner`, `title`, `plays`, `visibility`, `player_flags`, `data`) "
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
-1, &m_stmt_write, nullptr));
good &= ok("by_player", sqlite3_prepare_v2(m_database,
"SELECT `id`, `width`, `height`, `title`, `plays`, `visibility` "
"FROM `worlds` WHERE `owner` = ?",
-1, &m_stmt_by_player, nullptr));

return good;
}
Expand All @@ -61,6 +65,7 @@ void DatabaseWorld::close()
ok("~end", sqlite3_finalize(m_stmt_end));
ok("~read", sqlite3_finalize(m_stmt_read));
ok("~write", sqlite3_finalize(m_stmt_write));
ok("~by_player", sqlite3_finalize(m_stmt_by_player));

ok("close", sqlite3_close_v2(m_database));
m_database = nullptr;
Expand All @@ -72,14 +77,6 @@ static int custom_bind_string(sqlite3_stmt *s, int col, const std::string &text)
return sqlite3_bind_text(s, col, text.c_str(), text.size(), nullptr);
}

static uint32_t stupid_worldid_hash(const std::string &id)
{
uint32_t v = 0;
for (char c : id)
v ^= (v << 3) + (uint8_t)c;
return v;
}

bool DatabaseWorld::load(World *world)
{
if (!m_database)
Expand Down Expand Up @@ -107,21 +104,22 @@ bool DatabaseWorld::load(World *world)
world->createDummy(size);

meta.owner = (const char *)sqlite3_column_text(s, 3);
meta.plays = sqlite3_column_int(s, 4);
meta.is_public = sqlite3_column_int(s, 5) == 1;
meta.title = (const char *)sqlite3_column_text(s, 4);
meta.plays = sqlite3_column_int(s, 5);
meta.is_public = sqlite3_column_int(s, 6) == 1;

{
// Player flags
const void *blob = sqlite3_column_blob(s, 6);
const size_t len = sqlite3_column_bytes(s, 6);
const void *blob = sqlite3_column_blob(s, 7);
const size_t len = sqlite3_column_bytes(s, 7);
Packet pkt((const char *)blob, len);
meta.readPlayerFlags(pkt);
}

{
// World data
const void *blob = sqlite3_column_blob(s, 7);
const size_t len = sqlite3_column_bytes(s, 7);
const void *blob = sqlite3_column_blob(s, 8);
const size_t len = sqlite3_column_bytes(s, 8);
Packet pkt((const char *)blob, len);
world->read(pkt);
}
Expand Down Expand Up @@ -151,18 +149,19 @@ bool DatabaseWorld::save(const World *world)
sqlite3_bind_int(s, 2, world->getSize().X);
sqlite3_bind_int(s, 3, world->getSize().Y);
custom_bind_string(s, 4, meta.owner);
sqlite3_bind_int(s, 5, meta.plays);
sqlite3_bind_int(s, 6, meta.is_public ? 1 : 0);
custom_bind_string(s, 5, meta.title);
sqlite3_bind_int(s, 6, meta.plays);
sqlite3_bind_int(s, 7, meta.is_public ? 1 : 0);

// IMPORTANT: slite3_bind_*(...) does NOT copy the data.
// The packets must be alive until sqlite3_step(...)
Packet p_flags;
meta.writePlayerFlags(p_flags);
sqlite3_bind_blob(s, 7, p_flags.data(), p_flags.size(), nullptr);
sqlite3_bind_blob(s, 8, p_flags.data(), p_flags.size(), nullptr);

Packet p_world;
world->write(p_world, World::Method::Plain);
sqlite3_bind_blob(s, 8, p_world.data(), p_world.size(), nullptr);
sqlite3_bind_blob(s, 9, p_world.data(), p_world.size(), nullptr);

bool good = ok("save_s", sqlite3_step(s));
ok("save_r", sqlite3_reset(s));
Expand All @@ -185,8 +184,36 @@ bool DatabaseWorld::runCustomQuery(const char *query)
return good;
}

std::vector<LobbyWorld> DatabaseWorld::getByPlayer(const std::string &name) const
{
std::vector<LobbyWorld> out;
if (!m_database)
return out;

auto s = m_stmt_by_player;
custom_bind_string(s, 1, name);

while (sqlite3_step(s) == SQLITE_ROW) {
std::string world_id = (const char *)sqlite3_column_text(s, 0);

LobbyWorld meta(world_id);
meta.size.X = sqlite3_column_int(s, 1);
meta.size.Y = sqlite3_column_int(s, 2);
meta.title = sqlite3_column_int(s, 3);
meta.owner = name;
meta.plays = sqlite3_column_int(s, 4);
meta.is_public = sqlite3_column_int(s, 5) == 1;

out.emplace_back(meta);
}

ok("byPlayer", sqlite3_errcode(m_database));
sqlite3_reset(s);
return out;
}


bool DatabaseWorld::ok(const char *where, int status)
bool DatabaseWorld::ok(const char *where, int status) const
{
if (status == SQLITE_OK || status == SQLITE_DONE)
return true;
Expand Down
10 changes: 8 additions & 2 deletions src/server/database_world.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#pragma once

class World;
#include "core/world.h" // WorldMeta
#include <vector>

struct sqlite3;
struct sqlite3_stmt;

Expand All @@ -16,8 +18,10 @@ class DatabaseWorld {

bool runCustomQuery(const char *query);

std::vector<LobbyWorld> getByPlayer(const std::string &name) const;

private:
bool ok(const char *where, int status);
bool ok(const char *where, int status) const;

sqlite3 *m_database = nullptr;

Expand All @@ -26,4 +30,6 @@ class DatabaseWorld {

sqlite3_stmt *m_stmt_read = nullptr;
sqlite3_stmt *m_stmt_write = nullptr;

sqlite3_stmt *m_stmt_by_player = nullptr;
};
Loading

0 comments on commit 882b77d

Please sign in to comment.