aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJude Melton-Houghton <jwmhjwmh@gmail.com>2022-11-15 10:45:12 -0500
committerGitHub <noreply@github.com>2022-11-15 16:45:12 +0100
commitcd8a7fe47298be12620cab62be8cf0816fabb095 (patch)
treed667a204294e382cdf1d08ce8a77096778fc7fdd
parent1a045da0dd7f086a6ca689620aeb0fa28a1f6ce6 (diff)
downloadminetest-cd8a7fe47298be12620cab62be8cf0816fabb095.tar.xz
Add MetaDataRef:get_keys (#12841)
-rw-r--r--doc/lua_api.txt1
-rw-r--r--games/devtest/mods/unittests/metadata.lua9
-rw-r--r--src/content/mods.cpp7
-rw-r--r--src/content/mods.h2
-rw-r--r--src/database/database-dummy.cpp11
-rw-r--r--src/database/database-dummy.h1
-rw-r--r--src/database/database-files.cpp15
-rw-r--r--src/database/database-files.h1
-rw-r--r--src/database/database-sqlite3.cpp20
-rw-r--r--src/database/database-sqlite3.h2
-rw-r--r--src/database/database.h1
-rw-r--r--src/metadata.cpp9
-rw-r--r--src/metadata.h5
-rw-r--r--src/script/lua_api/l_itemstackmeta.cpp1
-rw-r--r--src/script/lua_api/l_metadata.cpp26
-rw-r--r--src/script/lua_api/l_metadata.h3
-rw-r--r--src/script/lua_api/l_nodemeta.cpp2
-rw-r--r--src/script/lua_api/l_playermeta.cpp1
-rw-r--r--src/script/lua_api/l_storage.cpp1
-rw-r--r--src/unittest/test_modmetadatadatabase.cpp7
20 files changed, 125 insertions, 0 deletions
diff --git a/doc/lua_api.txt b/doc/lua_api.txt
index b9da89c2d..26d105db0 100644
--- a/doc/lua_api.txt
+++ b/doc/lua_api.txt
@@ -6863,6 +6863,7 @@ and [`PlayerMetaRef`].
* `get_int(key)`: Returns `0` if key not present.
* `set_float(key, value)`
* `get_float(key)`: Returns `0` if key not present.
+* `get_keys()`: returns a list of all keys in the metadata.
* `to_table()`: returns `nil` or a table with keys:
* `fields`: key-value storage
* `inventory`: `{list1 = {}, ...}}` (NodeMetaRef only)
diff --git a/games/devtest/mods/unittests/metadata.lua b/games/devtest/mods/unittests/metadata.lua
index 1ae48fcf2..2246469ed 100644
--- a/games/devtest/mods/unittests/metadata.lua
+++ b/games/devtest/mods/unittests/metadata.lua
@@ -30,6 +30,14 @@ local function test_metadata(meta)
assert(tab.fields.d == "4")
assert(tab.fields.e == "e")
+ local keys = meta:get_keys()
+ assert(table.indexof(keys, "a") > 0)
+ assert(table.indexof(keys, "b") > 0)
+ assert(table.indexof(keys, "c") > 0)
+ assert(table.indexof(keys, "d") > 0)
+ assert(table.indexof(keys, "e") > 0)
+ assert(#keys == 5)
+
assert(not meta:contains(""))
assert(meta:contains("a"))
assert(meta:contains("b"))
@@ -57,6 +65,7 @@ local function test_metadata(meta)
meta:from_table()
assert(next(meta:to_table().fields) == nil)
+ assert(#meta:get_keys() == 0)
assert(not meta:equals(compare_meta))
end
diff --git a/src/content/mods.cpp b/src/content/mods.cpp
index ef268055f..57ccaaf2e 100644
--- a/src/content/mods.cpp
+++ b/src/content/mods.cpp
@@ -247,6 +247,13 @@ const StringMap &ModMetadata::getStrings(StringMap *place) const
return *place;
}
+const std::vector<std::string> &ModMetadata::getKeys(std::vector<std::string> *place) const
+{
+ place->clear();
+ m_database->getModKeys(m_mod_name, place);
+ return *place;
+}
+
const std::string *ModMetadata::getStringRaw(const std::string &name, std::string *place) const
{
return m_database->getModEntry(m_mod_name, name, place) ? place : nullptr;
diff --git a/src/content/mods.h b/src/content/mods.h
index 0b0e26b50..a45081f57 100644
--- a/src/content/mods.h
+++ b/src/content/mods.h
@@ -127,6 +127,8 @@ public:
const StringMap &getStrings(StringMap *place) const override;
+ const std::vector<std::string> &getKeys(std::vector<std::string> *place) const override;
+
protected:
const std::string *getStringRaw(const std::string &name,
std::string *place) const override;
diff --git a/src/database/database-dummy.cpp b/src/database/database-dummy.cpp
index ee88c6684..a8daaca88 100644
--- a/src/database/database-dummy.cpp
+++ b/src/database/database-dummy.cpp
@@ -92,6 +92,17 @@ bool Database_Dummy::getModEntries(const std::string &modname, StringMap *storag
return true;
}
+bool Database_Dummy::getModKeys(const std::string &modname, std::vector<std::string> *storage)
+{
+ const auto mod_pair = m_mod_meta_database.find(modname);
+ if (mod_pair != m_mod_meta_database.cend()) {
+ storage->reserve(storage->size() + mod_pair->second.size());
+ for (const auto &pair : mod_pair->second)
+ storage->push_back(pair.first);
+ }
+ return true;
+}
+
bool Database_Dummy::getModEntry(const std::string &modname,
const std::string &key, std::string *value)
{
diff --git a/src/database/database-dummy.h b/src/database/database-dummy.h
index 86c680ef1..b77911d55 100644
--- a/src/database/database-dummy.h
+++ b/src/database/database-dummy.h
@@ -38,6 +38,7 @@ public:
void listPlayers(std::vector<std::string> &res);
bool getModEntries(const std::string &modname, StringMap *storage);
+ bool getModKeys(const std::string &modname, std::vector<std::string> *storage);
bool getModEntry(const std::string &modname,
const std::string &key, std::string *value);
bool hasModEntry(const std::string &modname, const std::string &key);
diff --git a/src/database/database-files.cpp b/src/database/database-files.cpp
index eff08de12..0b94b28f2 100644
--- a/src/database/database-files.cpp
+++ b/src/database/database-files.cpp
@@ -396,6 +396,21 @@ bool ModMetadataDatabaseFiles::getModEntries(const std::string &modname, StringM
return true;
}
+bool ModMetadataDatabaseFiles::getModKeys(const std::string &modname,
+ std::vector<std::string> *storage)
+{
+ Json::Value *meta = getOrCreateJson(modname);
+ if (!meta)
+ return false;
+
+ std::vector<std::string> keys = meta->getMemberNames();
+ storage->reserve(storage->size() + keys.size());
+ for (std::string &key : keys)
+ storage->push_back(std::move(key));
+
+ return true;
+}
+
bool ModMetadataDatabaseFiles::getModEntry(const std::string &modname,
const std::string &key, std::string *value)
{
diff --git a/src/database/database-files.h b/src/database/database-files.h
index 089e071fe..2f74cc2e1 100644
--- a/src/database/database-files.h
+++ b/src/database/database-files.h
@@ -79,6 +79,7 @@ public:
virtual ~ModMetadataDatabaseFiles() = default;
virtual bool getModEntries(const std::string &modname, StringMap *storage);
+ virtual bool getModKeys(const std::string &modname, std::vector<std::string> *storage);
virtual bool getModEntry(const std::string &modname,
const std::string &key, std::string *value);
virtual bool hasModEntry(const std::string &modname, const std::string &key);
diff --git a/src/database/database-sqlite3.cpp b/src/database/database-sqlite3.cpp
index 0406fadc8..5511a46de 100644
--- a/src/database/database-sqlite3.cpp
+++ b/src/database/database-sqlite3.cpp
@@ -775,6 +775,7 @@ ModMetadataDatabaseSQLite3::~ModMetadataDatabaseSQLite3()
FINALIZE_STATEMENT(m_stmt_set)
FINALIZE_STATEMENT(m_stmt_has)
FINALIZE_STATEMENT(m_stmt_get)
+ FINALIZE_STATEMENT(m_stmt_get_keys)
FINALIZE_STATEMENT(m_stmt_get_all)
}
@@ -796,6 +797,7 @@ void ModMetadataDatabaseSQLite3::createDatabase()
void ModMetadataDatabaseSQLite3::initStatements()
{
PREPARE_STATEMENT(get_all, "SELECT `key`, `value` FROM `entries` WHERE `modname` = ?");
+ PREPARE_STATEMENT(get_keys, "SELECT `key` FROM `entries` WHERE `modname` = ?");
PREPARE_STATEMENT(get,
"SELECT `value` FROM `entries` WHERE `modname` = ? AND `key` = ? LIMIT 1");
PREPARE_STATEMENT(has,
@@ -825,6 +827,24 @@ bool ModMetadataDatabaseSQLite3::getModEntries(const std::string &modname, Strin
return true;
}
+bool ModMetadataDatabaseSQLite3::getModKeys(const std::string &modname,
+ std::vector<std::string> *storage)
+{
+ verifyDatabase();
+
+ str_to_sqlite(m_stmt_get_keys, 1, modname);
+ while (sqlite3_step(m_stmt_get_keys) == SQLITE_ROW) {
+ const char *key_data = (const char *) sqlite3_column_blob(m_stmt_get_keys, 0);
+ size_t key_len = sqlite3_column_bytes(m_stmt_get_keys, 0);
+ storage->emplace_back(key_data, key_len);
+ }
+ sqlite3_vrfy(sqlite3_errcode(m_database), SQLITE_DONE);
+
+ sqlite3_reset(m_stmt_get_keys);
+
+ return true;
+}
+
bool ModMetadataDatabaseSQLite3::getModEntry(const std::string &modname,
const std::string &key, std::string *value)
{
diff --git a/src/database/database-sqlite3.h b/src/database/database-sqlite3.h
index 566f6cebb..20488f0f0 100644
--- a/src/database/database-sqlite3.h
+++ b/src/database/database-sqlite3.h
@@ -240,6 +240,7 @@ public:
virtual ~ModMetadataDatabaseSQLite3();
virtual bool getModEntries(const std::string &modname, StringMap *storage);
+ virtual bool getModKeys(const std::string &modname, std::vector<std::string> *storage);
virtual bool getModEntry(const std::string &modname,
const std::string &key, std::string *value);
virtual bool hasModEntry(const std::string &modname, const std::string &key);
@@ -258,6 +259,7 @@ protected:
private:
sqlite3_stmt *m_stmt_get_all = nullptr;
+ sqlite3_stmt *m_stmt_get_keys = nullptr;
sqlite3_stmt *m_stmt_get = nullptr;
sqlite3_stmt *m_stmt_has = nullptr;
sqlite3_stmt *m_stmt_set = nullptr;
diff --git a/src/database/database.h b/src/database/database.h
index 0f22deebc..bf5a3da2b 100644
--- a/src/database/database.h
+++ b/src/database/database.h
@@ -92,6 +92,7 @@ public:
virtual ~ModMetadataDatabase() = default;
virtual bool getModEntries(const std::string &modname, StringMap *storage) = 0;
+ virtual bool getModKeys(const std::string &modname, std::vector<std::string> *storage) = 0;
virtual bool hasModEntry(const std::string &modname, const std::string &key) = 0;
virtual bool getModEntry(const std::string &modname,
const std::string &key, std::string *value) = 0;
diff --git a/src/metadata.cpp b/src/metadata.cpp
index c0ae9a404..d8a41218d 100644
--- a/src/metadata.cpp
+++ b/src/metadata.cpp
@@ -108,6 +108,15 @@ const StringMap &SimpleMetadata::getStrings(StringMap *) const
return m_stringvars;
}
+const std::vector<std::string> &SimpleMetadata::getKeys(std::vector<std::string> *place) const
+{
+ place->clear();
+ place->reserve(m_stringvars.size());
+ for (const auto &pair : m_stringvars)
+ place->push_back(pair.first);
+ return *place;
+}
+
const std::string *SimpleMetadata::getStringRaw(const std::string &name, std::string *) const
{
const auto found = m_stringvars.find(name);
diff --git a/src/metadata.h b/src/metadata.h
index df61b3f7a..45a3774d2 100644
--- a/src/metadata.h
+++ b/src/metadata.h
@@ -60,6 +60,9 @@ public:
// May (not must!) put strings in `place` and return a reference to these strings.
virtual const StringMap &getStrings(StringMap *place) const = 0;
+ // May (not must!) put keys in `place` and return a reference to these keys.
+ virtual const std::vector<std::string> &getKeys(std::vector<std::string> *place) const = 0;
+
// Add support for variable names in values. Uses place like getString.
const std::string &resolveString(const std::string &str, std::string *place,
u16 recursion = 0) const;
@@ -88,6 +91,8 @@ public:
bool contains(const std::string &name) const override;
virtual bool setString(const std::string &name, const std::string &var) override;
const StringMap &getStrings(StringMap *) const override final;
+ const std::vector<std::string> &getKeys(std::vector<std::string> *place)
+ const override final;
// Simple version of getters, possible due to in-memory storage:
diff --git a/src/script/lua_api/l_itemstackmeta.cpp b/src/script/lua_api/l_itemstackmeta.cpp
index 3c0f68406..8ce9673db 100644
--- a/src/script/lua_api/l_itemstackmeta.cpp
+++ b/src/script/lua_api/l_itemstackmeta.cpp
@@ -97,6 +97,7 @@ const luaL_Reg ItemStackMetaRef::methods[] = {
luamethod(MetaDataRef, set_int),
luamethod(MetaDataRef, get_float),
luamethod(MetaDataRef, set_float),
+ luamethod(MetaDataRef, get_keys),
luamethod(MetaDataRef, to_table),
luamethod(MetaDataRef, from_table),
luamethod(MetaDataRef, equals),
diff --git a/src/script/lua_api/l_metadata.cpp b/src/script/lua_api/l_metadata.cpp
index 8388bc089..68b79331b 100644
--- a/src/script/lua_api/l_metadata.cpp
+++ b/src/script/lua_api/l_metadata.cpp
@@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "serverenvironment.h"
#include "map.h"
#include "server.h"
+#include "util/basic_macros.h"
MetaDataRef *MetaDataRef::checkAnyMetadata(lua_State *L, int narg)
{
@@ -196,6 +197,31 @@ int MetaDataRef::l_set_float(lua_State *L)
return 0;
}
+// get_keys(self)
+int MetaDataRef::l_get_keys(lua_State *L)
+{
+ MAP_LOCK_REQUIRED;
+
+ MetaDataRef *ref = checkAnyMetadata(L, 1);
+
+ IMetadata *meta = ref->getmeta(false);
+ if (meta == NULL) {
+ lua_newtable(L);
+ return 1;
+ }
+
+ std::vector<std::string> keys_;
+ const std::vector<std::string> &keys = meta->getKeys(&keys_);
+
+ int i = 0;
+ lua_createtable(L, keys.size(), 0);
+ for (const std::string &key : keys) {
+ lua_pushlstring(L, key.c_str(), key.size());
+ lua_rawseti(L, -2, ++i);
+ }
+ return 1;
+}
+
// to_table(self)
int MetaDataRef::l_to_table(lua_State *L)
{
diff --git a/src/script/lua_api/l_metadata.h b/src/script/lua_api/l_metadata.h
index 084b06c83..cae15e232 100644
--- a/src/script/lua_api/l_metadata.h
+++ b/src/script/lua_api/l_metadata.h
@@ -74,6 +74,9 @@ protected:
// set_float(self, name, var)
static int l_set_float(lua_State *L);
+ // get_keys(self)
+ static int l_get_keys(lua_State *L);
+
// to_table(self)
static int l_to_table(lua_State *L);
diff --git a/src/script/lua_api/l_nodemeta.cpp b/src/script/lua_api/l_nodemeta.cpp
index 3cfb25883..f4edc1790 100644
--- a/src/script/lua_api/l_nodemeta.cpp
+++ b/src/script/lua_api/l_nodemeta.cpp
@@ -209,6 +209,7 @@ const luaL_Reg NodeMetaRef::methodsServer[] = {
luamethod(MetaDataRef, set_int),
luamethod(MetaDataRef, get_float),
luamethod(MetaDataRef, set_float),
+ luamethod(MetaDataRef, get_keys),
luamethod(MetaDataRef, to_table),
luamethod(MetaDataRef, from_table),
luamethod(NodeMetaRef, get_inventory),
@@ -230,6 +231,7 @@ const luaL_Reg NodeMetaRef::methodsClient[] = {
luamethod(MetaDataRef, get_string),
luamethod(MetaDataRef, get_int),
luamethod(MetaDataRef, get_float),
+ luamethod(MetaDataRef, get_keys),
luamethod(MetaDataRef, to_table),
{0,0}
};
diff --git a/src/script/lua_api/l_playermeta.cpp b/src/script/lua_api/l_playermeta.cpp
index 6ccb53e1c..def65a1cc 100644
--- a/src/script/lua_api/l_playermeta.cpp
+++ b/src/script/lua_api/l_playermeta.cpp
@@ -70,6 +70,7 @@ const luaL_Reg PlayerMetaRef::methods[] = {
luamethod(MetaDataRef, set_int),
luamethod(MetaDataRef, get_float),
luamethod(MetaDataRef, set_float),
+ luamethod(MetaDataRef, get_keys),
luamethod(MetaDataRef, to_table),
luamethod(MetaDataRef, from_table),
luamethod(MetaDataRef, equals),
diff --git a/src/script/lua_api/l_storage.cpp b/src/script/lua_api/l_storage.cpp
index 4b3863ca9..e1d47ba72 100644
--- a/src/script/lua_api/l_storage.cpp
+++ b/src/script/lua_api/l_storage.cpp
@@ -74,6 +74,7 @@ const luaL_Reg StorageRef::methods[] = {
luamethod(MetaDataRef, set_int),
luamethod(MetaDataRef, get_float),
luamethod(MetaDataRef, set_float),
+ luamethod(MetaDataRef, get_keys),
luamethod(MetaDataRef, to_table),
luamethod(MetaDataRef, from_table),
luamethod(MetaDataRef, equals),
diff --git a/src/unittest/test_modmetadatadatabase.cpp b/src/unittest/test_modmetadatadatabase.cpp
index b46feb884..1a443e51b 100644
--- a/src/unittest/test_modmetadatadatabase.cpp
+++ b/src/unittest/test_modmetadatadatabase.cpp
@@ -286,8 +286,11 @@ void TestModMetadataDatabase::testRecallFail()
{
ModMetadataDatabase *mod_meta_db = mod_meta_provider->getModMetadataDatabase();
StringMap recalled;
+ std::vector<std::string> recalled_keys;
mod_meta_db->getModEntries("mod1", &recalled);
+ mod_meta_db->getModKeys("mod1", &recalled_keys);
UASSERT(recalled.empty());
+ UASSERT(recalled_keys.empty());
std::string key1_value;
UASSERT(!mod_meta_db->getModEntry("mod1", "key1", &key1_value));
UASSERT(!mod_meta_db->hasModEntry("mod1", "key1"));
@@ -303,9 +306,13 @@ void TestModMetadataDatabase::testRecall()
{
ModMetadataDatabase *mod_meta_db = mod_meta_provider->getModMetadataDatabase();
StringMap recalled;
+ std::vector<std::string> recalled_keys;
mod_meta_db->getModEntries("mod1", &recalled);
+ mod_meta_db->getModKeys("mod1", &recalled_keys);
UASSERTCMP(std::size_t, ==, recalled.size(), 1);
+ UASSERTCMP(std::size_t, ==, recalled_keys.size(), 1);
UASSERTCMP(std::string, ==, recalled["key1"], "value1");
+ UASSERTCMP(std::string, ==, recalled_keys[0], "key1");
std::string key1_value;
UASSERT(mod_meta_db->getModEntry("mod1", "key1", &key1_value));
UASSERTCMP(std::string, ==, key1_value, "value1");