This commit is contained in:
Crypto City 2020-03-17 00:01:09 +00:00
parent 96c251c9ab
commit 2882f6bc80
46 changed files with 1262 additions and 36 deletions

View File

@ -12,6 +12,11 @@ TBLayout: axis: y, distribution-position: "left top", distribution: "available"
TBScrollContainer: adapt-content: 1
TBLayout: axis x, distribution: "available"
TBLayout: axis: y, distribution: "available"
lp: width: 380
TBTextField: text: "Badges"
TBSelectList: id: "badges", gravity: "all", scroll-mode: "auto"
TBEditField: id: "badges-search", placeholder: "search", type: "search", gravity: "left right"
TBLayout: axis: y, distribution: "available"
lp: width: 280
TBTextField: text: "Building activity"

View File

@ -44,4 +44,4 @@ TBTabContainer
TBEditField: id: "discoveries-search", gravity: "left right", placeholder: "search", type: "search"
TBLayout: axis: y, distribution-position: "left top", distribution: "gravity"
TBTextField: text: "Nothing here yet"
TBSelectList: id: "badges", gravity: "all"

View File

@ -39,6 +39,7 @@
#include "cc/cc_game_events.h"
#include "cc/cc_special_events.h"
#include "cc/cc_custom_item.h"
#include "cc/cc_badge.h"
#include "cryptonote_basic/blobdatatype.h"
#include "cryptonote_basic/cryptonote_basic.h"
#include "cryptonote_basic/difficulty.h"
@ -159,6 +160,7 @@ struct cc_account_data_t
uint64_t balance;
std::map<uint32_t, uint32_t> item_balances;
std::vector<uint32_t> flags;
std::map<uint32_t, uint8_t> badges;
std::string name;
bool ignore;
};
@ -1857,6 +1859,7 @@ public:
virtual void set_cc_account_item_balances(uint32_t id, const std::map<uint32_t, uint32_t> &item_balances) = 0;
virtual void add_cc_account_flag(uint32_t id, uint32_t flag_id) = 0;
virtual void remove_cc_account_flag(uint32_t id, uint32_t flag_id) = 0;
virtual void set_cc_account_badges(uint32_t id, const std::map<uint32_t, uint8_t> &badges) = 0;
virtual void set_cc_account_name(uint32_t id, const std::string &name) = 0;
virtual void set_cc_account_ignore(uint32_t id, bool ignore) = 0;
virtual bool for_all_cc_accounts(std::function<bool(const cc_account_data_t&)>) const = 0;
@ -1926,6 +1929,11 @@ public:
virtual void set_cc_custom_item_ignore(uint32_t id, bool ignore) = 0;
virtual bool for_all_cc_custom_items(std::function<bool(const cc::cc_custom_item_t &cid)> f) const = 0;
virtual uint32_t allocate_new_cc_event_badge(const std::string &name, const std::string &desc) = 0;
virtual void delete_cc_event_badge(uint32_t id) = 0;
virtual bool get_cc_event_badge_data(uint32_t id, cc::cc_badge_data_t &cid) const = 0;
virtual bool for_all_cc_event_badges(std::function<bool(const cc::cc_badge_data_t &cid)> f) const = 0;
// CC non virtual helpers, calls the virtual ones
bool does_cc_account_exist(uint32_t id) const;
bool does_cc_city_exist(uint32_t id) const;

View File

@ -305,6 +305,7 @@ namespace
* cc_discoveries id {discovery metadata}
* cc_special_events city {special event metadata}
* cc_custom_items id {item metadata}
* cc_event_badges id {badge metadata}
*
* Note: where the data items are of uniform size, DUPFIXED tables have
* been used to save space. In most of these cases, a dummy "zerokval"
@ -352,6 +353,7 @@ const char* const LMDB_CC_NAMES = "cc_names";
const char* const LMDB_CC_DISCOVERIES = "cc_discoveries";
const char* const LMDB_CC_SPECIAL_EVENTS = "cc_special_events";
const char* const LMDB_CC_CUSTOM_ITEMS = "cc_custom_items";
const char* const LMDB_CC_EVENT_BADGES = "cc_event_badges";
const char* const LMDB_PROPERTIES = "properties";
@ -474,6 +476,7 @@ typedef struct mdb_cc_account_data
uint64_t balance;
uint32_t n_item_balances;
uint32_t n_flags;
uint32_t n_badges;
bool ignore;
char name[MAX_CC_NAME_LENGTH];
} mdb_cc_account_data;
@ -579,6 +582,12 @@ typedef struct mdb_cc_custom_item_data_t
char secondary_description[MAX_CC_ITEM_DESCRIPTION_LENGTH];
} mdb_cc_custom_item_data_t;
typedef struct mdb_cc_event_badge_data_t
{
char name[MAX_CC_NAME_LENGTH];
char desc[MAX_CC_ITEM_DESCRIPTION_LENGTH];
} mdb_cc_event_badge_data_t;
std::atomic<uint64_t> mdb_txn_safe::num_active_txns{0};
std::atomic_flag mdb_txn_safe::creation_gate = ATOMIC_FLAG_INIT;
@ -1664,6 +1673,7 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags)
lmdb_db_open(txn, LMDB_CC_DISCOVERIES, MDB_INTEGERKEY | MDB_CREATE, m_cc_discoveries, "Failed to open db handle for m_cc_discoveries");
lmdb_db_open(txn, LMDB_CC_SPECIAL_EVENTS, MDB_INTEGERKEY | MDB_CREATE, m_cc_special_events, "Failed to open db handle for m_cc_special_events");
lmdb_db_open(txn, LMDB_CC_CUSTOM_ITEMS, MDB_INTEGERKEY | MDB_CREATE, m_cc_custom_items, "Failed to open db handle for m_cc_custom_items");
lmdb_db_open(txn, LMDB_CC_EVENT_BADGES, MDB_INTEGERKEY | MDB_CREATE, m_cc_event_badges, "Failed to open db handle for m_cc_event_badges");
lmdb_db_open(txn, LMDB_PROPERTIES, MDB_CREATE, m_properties, "Failed to open db handle for m_properties");
@ -1698,6 +1708,7 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags)
mdb_set_compare(txn, m_cc_discoveries, compare_uint32);
mdb_set_compare(txn, m_cc_special_events, compare_uint32);
mdb_set_compare(txn, m_cc_custom_items, compare_uint32);
mdb_set_compare(txn, m_cc_event_badges, compare_uint32);
if (!(mdb_flags & MDB_RDONLY))
{
@ -1898,6 +1909,8 @@ void BlockchainLMDB::reset()
throw0(DB_ERROR(lmdb_error("Failed to drop m_cc_special_events: ", result).c_str()));
if (auto result = mdb_drop(txn, m_cc_custom_items, 0))
throw0(DB_ERROR(lmdb_error("Failed to drop m_cc_custom_items: ", result).c_str()));
if (auto result = mdb_drop(txn, m_cc_event_badges, 0))
throw0(DB_ERROR(lmdb_error("Failed to drop m_cc_event_badges: ", result).c_str()));
// init with current version
MDB_val_str(k, "version");
@ -4619,12 +4632,13 @@ void BlockchainLMDB::drop_alt_blocks()
TXN_POSTFIX_SUCCESS();
}
static bool read_account_variable_size_data(const mdb_cc_account_data *ad, size_t bytes, std::map<uint32_t, uint32_t> &item_balances, std::vector<uint32_t> &flags)
static bool read_account_variable_size_data(const mdb_cc_account_data *ad, size_t bytes, std::map<uint32_t, uint32_t> &item_balances, std::vector<uint32_t> &flags, std::map<uint32_t, uint8_t> &badges)
{
item_balances.clear();
flags.clear();
badges.clear();
if (bytes < sizeof(mdb_cc_account_data) + (2 * sizeof(uint32_t)) * ad->n_item_balances + sizeof(uint32_t) * ad->n_flags)
if (bytes < sizeof(mdb_cc_account_data) + (2 * sizeof(uint32_t)) * ad->n_item_balances + sizeof(uint32_t) * ad->n_flags + (sizeof(uint32_t) * 2) * ad->n_badges)
return false;
// variable size data
@ -4650,18 +4664,32 @@ static bool read_account_variable_size_data(const mdb_cc_account_data *ad, size_
flags[i] = *ptr++;
}
// read badges
for (uint32_t i = 0; i < ad->n_badges; ++i)
{
const unsigned idx = *ptr++;
if (badges.find(idx) != badges.end())
MWARNING("Two entries for badges[" << idx << "]");
const unsigned level = *ptr++;
if (level > NUM_BADGE_LEVELS)
MWARNING("entry has invalid level for badges[" << idx << "]");
else if (level > 0)
badges[idx] = level;
}
return true;
}
static void write_account_variable_size_data(MDB_val &v, mdb_cc_account_data &ad, const std::map<uint32_t, uint32_t> &item_balances, std::vector<uint32_t> flags)
static void write_account_variable_size_data(MDB_val &v, mdb_cc_account_data &ad, const std::map<uint32_t, uint32_t> &item_balances, std::vector<uint32_t> flags, const std::map<uint32_t, uint8_t> &badges)
{
ad.n_item_balances = item_balances.size();
for (const auto &e: item_balances)
if (e.second == 0)
--ad.n_item_balances;
ad.n_flags = flags.size();
ad.n_badges = badges.size();
v.mv_size = sizeof(mdb_cc_account_data) + (2 * sizeof(uint32_t)) * ad.n_item_balances + sizeof(uint32_t) * ad.n_flags;
v.mv_size = sizeof(mdb_cc_account_data) + (2 * sizeof(uint32_t)) * ad.n_item_balances + sizeof(uint32_t) * ad.n_flags + (sizeof(uint32_t) * 2) * ad.n_badges;
v.mv_data = malloc(v.mv_size);
memcpy(v.mv_data, &ad, sizeof(mdb_cc_account_data));
@ -4683,6 +4711,14 @@ static void write_account_variable_size_data(MDB_val &v, mdb_cc_account_data &ad
{
*ptr++ = flags[i];
}
// write badges
for (const auto &e: badges)
{
*ptr++ = e.first;
*ptr++ = e.second;
}
if ((const uint8_t*)ptr - (const uint8_t*)v.mv_data != (ptrdiff_t)v.mv_size)
{
free(v.mv_data);
@ -4732,6 +4768,7 @@ uint32_t BlockchainLMDB::allocate_new_cc_account(const crypto::public_key &publi
ad.balance = 0;
ad.n_item_balances = 0;
ad.n_flags = 0;
ad.n_badges = 0;
ad.ignore = false;
memset(ad.name, 0, sizeof(ad.name));
@ -4869,7 +4906,7 @@ bool BlockchainLMDB::get_cc_account_data(uint32_t id, cc_account_data_t &data) c
const size_t namelen = NUL ? NUL - (const char*)ad->name : MAX_CC_NAME_LENGTH;
data.name.assign(ad->name, namelen);
if (!read_account_variable_size_data(ad, v.mv_size, data.item_balances, data.flags))
if (!read_account_variable_size_data(ad, v.mv_size, data.item_balances, data.flags, data.badges))
throw0(DB_ERROR("Failed to read account variable size data"));
TXN_POSTFIX_RDONLY();
@ -4904,10 +4941,11 @@ void BlockchainLMDB::set_cc_account_balance(uint32_t id, uint64_t balance)
std::map<uint32_t, uint32_t> item_balances;
std::vector<uint32_t> flags;
if (!read_account_variable_size_data((const mdb_cc_account_data*)v.mv_data, v.mv_size, item_balances, flags))
std::map<uint32_t, uint8_t> badges;
if (!read_account_variable_size_data((const mdb_cc_account_data*)v.mv_data, v.mv_size, item_balances, flags, badges))
throw0(DB_ERROR("Failed to read account variable size data"));
write_account_variable_size_data(v, ad, item_balances, flags);
write_account_variable_size_data(v, ad, item_balances, flags, badges);
result = mdb_cursor_put(m_cur_cc_accounts, &k, &v, 0);
if (v.mv_data) free(v.mv_data);
@ -4936,12 +4974,13 @@ void BlockchainLMDB::add_cc_account_flag(uint32_t id, uint32_t flag_id)
std::map<uint32_t, uint32_t> item_balances;
std::vector<uint32_t> flags;
if (!read_account_variable_size_data((const mdb_cc_account_data*)v.mv_data, v.mv_size, item_balances, flags))
std::map<uint32_t, uint8_t> badges;
if (!read_account_variable_size_data((const mdb_cc_account_data*)v.mv_data, v.mv_size, item_balances, flags, badges))
throw0(DB_ERROR("Failed to read account variable size data"));
flags.push_back(flag_id);
write_account_variable_size_data(v, ad, item_balances, flags);
write_account_variable_size_data(v, ad, item_balances, flags, badges);
result = mdb_cursor_put(m_cur_cc_accounts, &k, &v, 0);
if (v.mv_data) free(v.mv_data);
@ -4970,7 +5009,8 @@ void BlockchainLMDB::remove_cc_account_flag(uint32_t id, uint32_t flag_id)
std::map<uint32_t, uint32_t> item_balances;
std::vector<uint32_t> flags;
if (!read_account_variable_size_data((const mdb_cc_account_data*)v.mv_data, v.mv_size, item_balances, flags))
std::map<uint32_t, uint8_t> badges;
if (!read_account_variable_size_data((const mdb_cc_account_data*)v.mv_data, v.mv_size, item_balances, flags, badges))
throw0(DB_ERROR("Failed to read account variable size data"));
bool found = false;
@ -4986,7 +5026,7 @@ void BlockchainLMDB::remove_cc_account_flag(uint32_t id, uint32_t flag_id)
if (!found)
throw0(DB_ERROR("Flag to remove not found"));
write_account_variable_size_data(v, ad, item_balances, flags);
write_account_variable_size_data(v, ad, item_balances, flags, badges);
result = mdb_cursor_put(m_cur_cc_accounts, &k, &v, 0);
if (v.mv_data) free(v.mv_data);
@ -5015,10 +5055,44 @@ void BlockchainLMDB::set_cc_account_item_balances(uint32_t id, const std::map<ui
std::map<uint32_t, uint32_t> old_item_balances;
std::vector<uint32_t> flags;
if (!read_account_variable_size_data((mdb_cc_account_data*)v.mv_data, v.mv_size, old_item_balances, flags))
std::map<uint32_t, uint8_t> badges;
if (!read_account_variable_size_data((mdb_cc_account_data*)v.mv_data, v.mv_size, old_item_balances, flags, badges))
throw0(DB_ERROR("Failed to read account variable size data"));
write_account_variable_size_data(v, ad, item_balances, flags);
write_account_variable_size_data(v, ad, item_balances, flags, badges);
result = mdb_cursor_put(m_cur_cc_accounts, &k, &v, 0);
free(v.mv_data);
if (result)
throw0(DB_ERROR(lmdb_error("Failed to add account data to db transaction: ", result).c_str()));
}
void BlockchainLMDB::set_cc_account_badges(uint32_t id, const std::map<uint32_t, uint8_t> &badges)
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
mdb_txn_cursors *m_cursors = &m_wcursors;
CURSOR(cc_accounts)
// find account id
MDB_val_set(k, id);
MDB_val v;
int result = mdb_cursor_get(m_cur_cc_accounts, &k, &v, MDB_SET);
if (result)
throw0(DB_ERROR(lmdb_error("Account " + std::to_string(id) + " not found: ", result).c_str()));
if (v.mv_size < sizeof(mdb_cc_account_data))
throw0(DB_ERROR("Unexpected account data size"));
mdb_cc_account_data ad = *(mdb_cc_account_data*)v.mv_data;
std::map<uint32_t, uint32_t> item_balances;
std::vector<uint32_t> flags;
std::map<uint32_t, uint8_t> old_badges;
if (!read_account_variable_size_data((mdb_cc_account_data*)v.mv_data, v.mv_size, item_balances, flags, old_badges))
throw0(DB_ERROR("Failed to read account variable size data"));
write_account_variable_size_data(v, ad, item_balances, flags, badges);
result = mdb_cursor_put(m_cur_cc_accounts, &k, &v, 0);
free(v.mv_data);
@ -5079,10 +5153,11 @@ void BlockchainLMDB::set_cc_account_ignore(uint32_t id, bool ignore)
std::map<uint32_t, uint32_t> item_balances;
std::vector<uint32_t> flags;
if (!read_account_variable_size_data((const mdb_cc_account_data*)v.mv_data, v.mv_size, item_balances, flags))
std::map<uint32_t, uint8_t> badges;
if (!read_account_variable_size_data((const mdb_cc_account_data*)v.mv_data, v.mv_size, item_balances, flags, badges))
throw0(DB_ERROR("Failed to read account variable size data"));
write_account_variable_size_data(v, ad, item_balances, flags);
write_account_variable_size_data(v, ad, item_balances, flags, badges);
result = mdb_cursor_put(m_cur_cc_accounts, &k, &v, 0);
if (v.mv_data) free(v.mv_data);
@ -5123,7 +5198,7 @@ bool BlockchainLMDB::for_all_cc_accounts(std::function<bool(const cc_account_dat
data.balance = ad.balance;
data.ignore = ad.ignore;
if (!read_account_variable_size_data((mdb_cc_account_data*)v.mv_data, v.mv_size, data.item_balances, data.flags))
if (!read_account_variable_size_data((mdb_cc_account_data*)v.mv_data, v.mv_size, data.item_balances, data.flags, data.badges))
throw0(DB_ERROR("Failed to read account variable size data"));
const char *NUL = (const char*)memchr(ad.name, 0, MAX_CC_NAME_LENGTH);
@ -7087,6 +7162,166 @@ bool BlockchainLMDB::for_all_cc_custom_items(std::function<bool(const cc::cc_cus
return ret;
}
uint32_t BlockchainLMDB::allocate_new_cc_event_badge(const std::string &name, const std::string &desc)
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
mdb_txn_cursors *m_cursors = &m_wcursors;
if (name.size() > MAX_CC_NAME_LENGTH)
throw0(DB_ERROR("Name is too long"));
if (desc.size() > MAX_CC_ITEM_DESCRIPTION_LENGTH)
throw0(DB_ERROR("Description is too long"));
CURSOR(cc_event_badges)
uint32_t badge_id = cc::BADGE_FIRST_EVENT;
int result = 0;
// find first free badge id
MDB_val k;
MDB_val v;
MDB_cursor_op op = MDB_FIRST;
while (1)
{
result = mdb_cursor_get(m_cur_cc_event_badges, &k, &v, op);
op = MDB_NEXT;
if (result == MDB_NOTFOUND)
break;
if (result)
throw0(DB_ERROR(lmdb_error("Failed to enumerate event badge data: ", result).c_str()));
if (v.mv_size < sizeof(mdb_cc_event_badge_data_t))
throw0(DB_ERROR("Unexpected event badge size"));
uint32_t k_id = *(const uint32_t*)k.mv_data;
if (k_id > badge_id)
break;
++badge_id;
if (badge_id > cc::BADGE_LAST_EVENT)
throw0(DB_ERROR("No event badge ID available"));
}
MINFO("Badge ID " << badge_id << " is available");
mdb_cc_event_badge_data_t ebd;
memset(ebd.name, 0, sizeof(ebd.name));
memcpy(ebd.name, name.data(), name.size());
memset(ebd.desc, 0, sizeof(ebd.desc));
memcpy(ebd.desc, desc.data(), desc.size());
k.mv_data = (void*)&badge_id;
k.mv_size = sizeof(badge_id);
v.mv_data = (void*)&ebd;
v.mv_size = sizeof(ebd);
result = mdb_cursor_put(m_cur_cc_event_badges, &k, &v, 0);
if (result)
throw0(DB_ERROR(lmdb_error("Failed to add event badge data to db transaction: ", result).c_str()));
return badge_id;
}
void BlockchainLMDB::delete_cc_event_badge(uint32_t id)
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
mdb_txn_cursors *m_cursors = &m_wcursors;
CURSOR(cc_event_badges)
// find badge id
MDB_val_set(k, id);
MDB_val v;
int result = mdb_cursor_get(m_cur_cc_event_badges, &k, &v, MDB_SET);
if (result)
throw0(DB_ERROR(lmdb_error("Event badge " + std::to_string(id) + " not found: ", result).c_str()));
if (v.mv_size < sizeof(mdb_cc_event_badge_data_t))
throw0(DB_ERROR("Unexpected event badge data size"));
result = mdb_cursor_del(m_cur_cc_event_badges, 0);
if (result)
throw0(DB_ERROR(lmdb_error("Error deleting badge " + std::to_string(id) + ": ", result).c_str()));
}
bool BlockchainLMDB::get_cc_event_badge_data(uint32_t id, cc::cc_badge_data_t &bd) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
TXN_PREFIX_RDONLY();
RCURSOR(cc_event_badges);
MDB_val_set(k, id);
MDB_val v;
int result = mdb_cursor_get(m_cur_cc_event_badges, &k, &v, MDB_SET);
if (result == MDB_NOTFOUND)
return false;
if (result)
throw0(DB_ERROR(lmdb_error("Error attempting to retrieve event badge data: ", result).c_str()));
if (v.mv_size < sizeof(mdb_cc_event_badge_data_t))
throw0(DB_ERROR("Unexpected event badge data size"));
const mdb_cc_event_badge_data_t *badge_data = (const mdb_cc_event_badge_data_t *)v.mv_data;
bd.id = id;
const char *NUL = (const char*)memchr(badge_data->name, 0, MAX_CC_NAME_LENGTH);
const size_t namelen = NUL ? NUL - (const char*)badge_data->name : MAX_CC_NAME_LENGTH;
bd.name.assign(badge_data->name, namelen);
NUL = (const char*)memchr(badge_data->desc, 0, MAX_CC_ITEM_DESCRIPTION_LENGTH);
const size_t description_len = NUL ? NUL - (const char*)badge_data->desc : MAX_CC_ITEM_DESCRIPTION_LENGTH;
bd.desc.assign(badge_data->desc, description_len);
TXN_POSTFIX_RDONLY();
return true;
}
bool BlockchainLMDB::for_all_cc_event_badges(std::function<bool(const cc::cc_badge_data_t &bd)> f) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
TXN_PREFIX_RDONLY();
RCURSOR(cc_event_badges);
bool ret = true;
MDB_val k, v;
MDB_cursor_op op = MDB_FIRST;
while (1)
{
int result = mdb_cursor_get(m_cur_cc_event_badges, &k, &v, op);
if (result == MDB_NOTFOUND)
return true;
if (result)
throw0(DB_ERROR(lmdb_error("Error attempting to retrieve event badge data: ", result).c_str()));
if (v.mv_size < sizeof(mdb_cc_event_badge_data_t))
throw0(DB_ERROR("Unexpected event badge data size"));
op = MDB_NEXT;
const uint32_t &id = *(const uint32_t*)k.mv_data;
const mdb_cc_event_badge_data_t &badge_data = *(const mdb_cc_event_badge_data_t *)v.mv_data;
cc::cc_badge_data_t bd;
const char *NUL = (const char*)memchr(badge_data.name, 0, MAX_CC_NAME_LENGTH);
const size_t namelen = NUL ? NUL - (const char*)badge_data.name : MAX_CC_NAME_LENGTH;
bd.name.assign(badge_data.name, namelen);
NUL = (const char*)memchr(badge_data.desc, 0, MAX_CC_ITEM_DESCRIPTION_LENGTH);
const size_t description_len = NUL ? NUL - (const char*)badge_data.desc : MAX_CC_ITEM_DESCRIPTION_LENGTH;
bd.desc.assign(badge_data.desc, description_len);
if (!f(bd))
{
ret = false;
break;
}
}
TXN_POSTFIX_RDONLY();
return ret;
}
uint64_t BlockchainLMDB::get_database_size() const
{
uint64_t size = 0;

View File

@ -87,6 +87,7 @@ typedef struct mdb_txn_cursors
MDB_cursor *m_txc_cc_discoveries;
MDB_cursor *m_txc_cc_special_events;
MDB_cursor *m_txc_cc_custom_items;
MDB_cursor *m_txc_cc_event_badges;
} mdb_txn_cursors;
#define m_cur_blocks m_cursors->m_txc_blocks
@ -121,6 +122,7 @@ typedef struct mdb_txn_cursors
#define m_cur_cc_discoveries m_cursors->m_txc_cc_discoveries
#define m_cur_cc_special_events m_cursors->m_txc_cc_special_events
#define m_cur_cc_custom_items m_cursors->m_txc_cc_custom_items
#define m_cur_cc_event_badges m_cursors->m_txc_cc_event_badges
typedef struct mdb_rflags
{
@ -157,6 +159,7 @@ typedef struct mdb_rflags
bool m_rf_cc_discoveries;
bool m_rf_cc_special_events;
bool m_rf_cc_custom_items;
bool m_rf_cc_event_badges;
} mdb_rflags;
typedef struct mdb_threadinfo
@ -475,6 +478,7 @@ private:
bool does_cc_account_exist(uint32_t id) const;
void set_cc_account_balance(uint32_t id, uint64_t balance);
void set_cc_account_item_balances(uint32_t id, const std::map<uint32_t, uint32_t> &item_balances);
void set_cc_account_badges(uint32_t id, const std::map<uint32_t, uint8_t> &badges);
void set_cc_account_name(uint32_t id, const std::string &name);
void set_cc_account_ignore(uint32_t id, bool ignore);
void add_cc_account_flag(uint32_t id, uint32_t flag_id);
@ -546,6 +550,11 @@ private:
void set_cc_custom_item_ignore(uint32_t id, bool ignore);
bool for_all_cc_custom_items(std::function<bool(const cc::cc_custom_item_t &cid)> f) const;
uint32_t allocate_new_cc_event_badge(const std::string &name, const std::string &desc);
void delete_cc_event_badge(uint32_t id);
bool get_cc_event_badge_data(uint32_t id, cc::cc_badge_data_t &cid) const;
bool for_all_cc_event_badges(std::function<bool(const cc::cc_badge_data_t &cid)> f) const;
// fix up anything that may be wrong due to past bugs
virtual void fixup();
@ -613,6 +622,7 @@ private:
MDB_dbi m_cc_discoveries;
MDB_dbi m_cc_special_events;
MDB_dbi m_cc_custom_items;
MDB_dbi m_cc_event_badges;
mutable uint64_t m_cum_size; // used in batch size estimation
mutable unsigned int m_cum_count;

View File

@ -175,6 +175,7 @@ public:
virtual void set_cc_account_item_balances(uint32_t id, const std::map<uint32_t, uint32_t> &item_balances) {}
virtual void add_cc_account_flag(uint32_t id, uint32_t flag_id) {}
virtual void remove_cc_account_flag(uint32_t id, uint32_t flag_id) {}
virtual void set_cc_account_badges(uint32_t id, const std::map<uint32_t, uint8_t> &badges) {}
virtual void set_cc_account_name(uint32_t id, const std::string &name) {}
virtual void set_cc_account_ignore(uint32_t id, bool ignore) {}
virtual bool for_all_cc_accounts(std::function<bool(const cc_account_data_t&)>) const { return true; }
@ -244,6 +245,11 @@ public:
virtual void set_cc_custom_item_ignore(uint32_t id, bool ignore) {}
virtual bool for_all_cc_custom_items(std::function<bool(const cc::cc_custom_item_t &cid)> f) const { return true; }
virtual uint32_t allocate_new_cc_event_badge(const std::string &name, const std::string &desc) { return 0; }
virtual void delete_cc_event_badge(uint32_t id) {}
virtual bool get_cc_event_badge_data(uint32_t id, cc::cc_badge_data_t &cid) const { return false; }
virtual bool for_all_cc_event_badges(std::function<bool(const cc::cc_badge_data_t &cid)> f) const { return false; }
private:
uint32_t n_accounts;
};

View File

@ -41,6 +41,7 @@ set(cc_sources
cc_command_handler_give.cpp
cc_command_handler_ignore.cpp
cc_command_handler_match.cpp
cc_command_handler_new_event_badge.cpp
cc_command_handler_new_item.cpp
cc_command_handler_none.cpp
cc_command_handler_rename.cpp
@ -48,6 +49,7 @@ set(cc_sources
cc_command_handler_research.cpp
cc_command_handler_trade.cpp
cc_command_handler_transfer.cpp
cc_badge.cpp
cc_discoveries.cpp
cc_game_update.cpp
cc_influence.cpp
@ -72,6 +74,7 @@ set(cc_headers
cc_command_handler_give.h
cc_command_handler_ignore.h
cc_command_handler_match.h
cc_command_handler_new_event_badge.h
cc_command_handler_new_item.h
cc_command_handler_none.h
cc_command_handler_rename.h
@ -79,6 +82,7 @@ set(cc_headers
cc_command_handler_research.h
cc_command_handler_trade.h
cc_command_handler_transfer.h
cc_badge.h
cc_discoveries.h
cc_game_update.h
cc_influence.h

View File

@ -51,6 +51,7 @@
#include "cc_command_handler_give.h"
#include "cc_command_handler_ignore.h"
#include "cc_command_handler_match.h"
#include "cc_command_handler_new_event_badge.h"
#include "cc_command_handler_new_item.h"
#include "cc_command_handler_none.h"
#include "cc_command_handler_rename.h"
@ -1611,6 +1612,7 @@ static cc_command_handler &get_cc_command(const cryptonote::cc_command_t &cmd)
cc_command_handler &operator()(const cryptonote::cc_command_give_t &cmd) const { return cc_command_handler_give::instance; }
cc_command_handler &operator()(const cryptonote::cc_command_ignore_t &cmd) const { return cc_command_handler_ignore::instance; }
cc_command_handler &operator()(const cryptonote::cc_command_match_t &cmd) const { return cc_command_handler_match::instance; }
cc_command_handler &operator()(const cryptonote::cc_command_new_event_badge_t &cmd) const { return cc_command_handler_new_event_badge::instance; }
cc_command_handler &operator()(const cryptonote::cc_command_new_item_t &cmd) const { return cc_command_handler_new_item::instance; }
cc_command_handler &operator()(const cryptonote::cc_command_none_t &cmd) const { return cc_command_handler_none::instance; }
cc_command_handler &operator()(const cryptonote::cc_command_rename_t &cmd) const { return cc_command_handler_rename::instance; }

66
src/cc/cc_badge.cpp Normal file
View File

@ -0,0 +1,66 @@
#include "blockchain_db/blockchain_db.h"
#include "sqrtint.h"
#include "cc_badge.h"
static const struct
{
const char *name;
const char *desc;
} predefined_badges_data[cc::NUM_PREDEFINED_BADGES] = {
{}, // none
{
"Builder",
"Max number of buildings",
},
{
"Experimenter",
"Max number of building types",
},
{
"Hoarder",
"Number of blocks in inventory",
},
{
"Steadfast",
"Overall size of military buildings",
},
{
"Cultured",
"Overall size of cultural buildings",
},
};
namespace cc
{
bool get_badge_data(const cryptonote::BlockchainDB &db, cc_badge_t badge, cc_badge_data_t &data)
{
if (badge < BADGE_FIRST || badge >= NUM_BADGES)
return false;
// predefined
if (badge < NUM_PREDEFINED_BADGES)
{
data.id = badge;
data.name = predefined_badges_data[badge].name;
data.desc = predefined_badges_data[badge].desc;
return true;
}
// event
if (!db.get_cc_event_badge_data(badge, data))
return false;
return true;
}
std::pair<uint32_t, uint32_t> get_badge_score(const std::vector<uint32_t> badges)
{
if (badges.size() != NUM_BADGE_LEVELS)
return std::make_pair(0, 0);
uint32_t score = badges[0] + badges[1] * 2 + badges[2] * 5 + badges[3] * 10 + badges[4] * 25;
uint32_t level = sqrtint(score);
return std::make_pair(score, level);
}
}

44
src/cc/cc_badge.h Normal file
View File

@ -0,0 +1,44 @@
#pragma once
namespace cryptonote
{
class BlockchainDB;
}
namespace cc
{
#define NUM_BADGE_LEVELS 5
enum cc_badge_t
{
BADGE_NONE = 0,
BADGE_FIRST = 1,
BADGE_BUILDER = BADGE_FIRST,
BADGE_EXPERIMENTER,
BADGE_HOARDER,
BADGE_STEADFAST,
BADGE_CULTURED,
BADGE_LAST = 4096 - 1,
NUM_PREDEFINED_BADGES,
BADGE_FIRST_EVENT = NUM_PREDEFINED_BADGES,
BADGE_LAST_EVENT = 4096 + 4096 - 1,
NUM_BADGES
};
struct cc_badge_data_t
{
uint32_t id;
std::string name;
std::string desc;
};
bool get_badge_data(const cryptonote::BlockchainDB &db, cc_badge_t badge, cc_badge_data_t &data);
std::pair<uint32_t, uint32_t> get_badge_score(const std::vector<uint32_t> badges);
}

View File

@ -207,6 +207,24 @@ bool cc_command_handler_game_update::execute(cryptonote::BlockchainDB &db, const
if (!execute_city(db, game.cities[i]))
return false;
}
for (const auto &adj: game.badges)
{
cryptonote::cc_account_data_t data;
if (!db.get_cc_account_data(adj.account, data))
{
MERROR("Failed to get account " << adj.account << " data");
return false;
}
data.badges[adj.badge] += adj.delta_level;
if (data.badges[adj.badge] == 0 || data.badges[adj.badge] > NUM_BADGE_LEVELS)
{
MERROR("Badge level out of range: " << data.badges[adj.badge]);
return false;
}
db.set_cc_account_badges(adj.account, data.badges);
}
db.add_cc_events(db.height() - 1, last_events);
return true;
}
@ -308,6 +326,25 @@ bool cc_command_handler_game_update::revert(cryptonote::BlockchainDB &db, const
db.remove_cc_events(db.height() - 1);
for (const auto &adj: game.badges)
{
cryptonote::cc_account_data_t data;
if (!db.get_cc_account_data(adj.account, data))
{
MERROR("Failed to get account " << adj.account << " data");
return false;
}
if (data.badges[adj.badge] < adj.delta_level)
{
MERROR("Badge level out of range: " << data.badges[adj.badge] << ", adj " << (int)adj.delta_level);
return false;
}
data.badges[adj.badge] -= adj.delta_level;
if (data.badges[adj.badge] == 0)
data.badges.erase(adj.badge);
db.set_cc_account_badges(adj.account, data.badges);
}
for (size_t i = 0; i < game.cities.size(); ++i)
{
const cryptonote::cc_command_game_update_t::city_t &city = game.cities[game.cities.size() - 1 - i];

View File

@ -0,0 +1,110 @@
// Copyright (c) 2019, Crypto City
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "blockchain_db/blockchain_db.h"
#include "cc/cc.h"
#include "cc_command_handler_new_event_badge.h"
namespace cc
{
cc_command_handler_new_event_badge cc_command_handler_new_event_badge::instance;
void cc_command_handler_new_event_badge::get_in_out(const cryptonote::cc_command_t &cmd, uint64_t &cc_in, uint64_t &cc_out) const
{
cc_in = 0;
cc_out = 0;
}
uint64_t cc_command_handler_new_event_badge::get_cost(const cryptonote::cc_command_t &cmd) const
{
return 0;
}
bool cc_command_handler_new_event_badge::check(const cryptonote::BlockchainDB &db, const cryptonote::cc_command_t &cmd, cryptonote::tx_verification_context &tvc) const
{
const cryptonote::cc_command_new_event_badge_t &new_event_badge = boost::get<cryptonote::cc_command_new_event_badge_t>(cmd);
std::string error;
uint32_t type, id;
CHECK_COMMAND_SET(new_event_badge.name.size() <= MAX_CC_NAME_LENGTH, tvc.m_cc_too_large, "Name is too long");
CHECK_COMMAND_SET(!db.is_cc_name_used(new_event_badge.name, type, id), tvc.m_cc_conflict, "Name already taken");
CHECK_COMMAND_SET(new_event_badge.description.size() <= MAX_CC_ITEM_DESCRIPTION_LENGTH, tvc.m_cc_too_large, "Description is too long");
CHECK_COMMAND_SET(cc::validate_item_name(new_event_badge.name, error), tvc.m_cc_forbidden_character, error);
for (const auto &e: new_event_badge.instances)
{
CHECK_COMMAND_SET(e.level > 0 && e.level <= NUM_BADGE_LEVELS, tvc.m_cc_out_of_range, "Level out of range");
}
return true;
}
bool cc_command_handler_new_event_badge::execute(cryptonote::BlockchainDB &db, const cryptonote::cc_command_t &cmd) const
{
const cryptonote::cc_command_new_event_badge_t &new_event_badge = boost::get<cryptonote::cc_command_new_event_badge_t>(cmd);
const uint32_t id = db.allocate_new_cc_event_badge(new_event_badge.name, new_event_badge.description);
CHECK_AND_ASSERT_MES(id >= BADGE_FIRST_EVENT && id <= BADGE_LAST_EVENT, false, "Badge creation failed");
for (const auto &e: new_event_badge.instances)
{
cryptonote::cc_account_data_t data;
CHECK_AND_ASSERT_MES(db.get_cc_account_data(e.account_id, data), false, "Failed to get account data");
data.badges[id] = e.level;
db.set_cc_account_badges(e.account_id, data.badges);
}
db.add_cc_name(new_event_badge.name, NAME_TYPE_EVENT_BADGE, id);
return true;
}
bool cc_command_handler_new_event_badge::revert(cryptonote::BlockchainDB &db, const cryptonote::cc_command_t &cmd) const
{
const cryptonote::cc_command_new_event_badge_t &new_event_badge = boost::get<cryptonote::cc_command_new_event_badge_t>(cmd);
uint32_t type, id;
CHECK_AND_ASSERT_MES(db.is_cc_name_used(new_event_badge.name, type, id), false, "Badge not found");
CHECK_AND_ASSERT_MES(type == NAME_TYPE_EVENT_BADGE, false, "Name is not registered to a badge");
for (const auto &e: new_event_badge.instances)
{
cryptonote::cc_account_data_t data;
CHECK_AND_ASSERT_MES(db.get_cc_account_data(e.account_id, data), false, "Failed to get account data");
CHECK_AND_ASSERT_MES(data.badges.find(id) != data.badges.end(), false, "Player does not have the expected badge");
CHECK_AND_ASSERT_MES(data.badges[id] == e.level, false, "Player does not have the expected badge level");
data.badges.erase(id);
db.set_cc_account_badges(e.account_id, data.badges);
}
db.delete_cc_event_badge(id);
db.remove_cc_name(new_event_badge.name);
return true;
}
}

View File

@ -0,0 +1,48 @@
// Copyright (c) 2019, Crypto City
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#pragma once
#include "cc_command_handler.h"
namespace cc
{
class cc_command_handler_new_event_badge: public cc_command_handler
{
public:
virtual void get_in_out(const cryptonote::cc_command_t &cmd, uint64_t &cc_in, uint64_t &cc_out) const;
virtual uint64_t get_cost(const cryptonote::cc_command_t &cmd) const;
virtual bool check(const cryptonote::BlockchainDB &db, const cryptonote::cc_command_t &cmd, cryptonote::tx_verification_context &tvc) const;
virtual bool execute(cryptonote::BlockchainDB &db, const cryptonote::cc_command_t &cmd) const;
virtual bool revert(cryptonote::BlockchainDB &db, const cryptonote::cc_command_t &cmd) const;
static cc_command_handler_new_event_badge instance;
};
}

View File

@ -93,6 +93,7 @@
#define NAME_TYPE_PLAYER 1
#define NAME_TYPE_CUSTOM_ITEM 2
#define NAME_TYPE_EVENT_BADGE 3
enum BuildingRole
{

View File

@ -45,6 +45,7 @@
#include "cc_discoveries.h"
#include "cc_game_events.h"
#include "cc_special_events.h"
#include "cc_badge.h"
#include "cc_game_update.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
@ -197,6 +198,26 @@ static void pick_point_border(uint32_t &x, uint32_t &y, uint32_t x0, uint32_t y0
}
}
static void award_badge(const cryptonote::BlockchainDB &db, cc_command_game_update_t &cg, cc::game_update_events_t &events, const cryptonote::cc_account_data_t &ad, cc::cc_badge_t badge, uint64_t value, const uint64_t thresholds[NUM_BADGE_LEVELS])
{
for (uint8_t level = NUM_BADGE_LEVELS; level > 0; --level)
{
if (value >= thresholds[level - 1])
{
const auto it = ad.badges.find(badge);
uint8_t cur = it == ad.badges.end() ? 0 : it->second;
if (level > cur)
{
cc::cc_badge_data_t bd;
cc::get_badge_data(db, badge, bd);
events.add(ad.id, 0) << "Awarded badge '" << bd.name << "' level " << (unsigned)level;
cg.badges.push_back({ad.id, badge, (uint8_t)(level - cur)});
}
break;
}
}
}
namespace cc
{
@ -1032,6 +1053,65 @@ static void add_cities(const BlockchainDB &db, cc_command_game_update_t &cg, gam
id = e.first.first;
id2 = e.first.second;
}
// badges
std::map<uint32_t, cc_account_data_t> account_data;
std::map<uint32_t, cc_flag_data_t> flag_data;
CHECK_AND_ASSERT_THROW_MES(db.for_all_cc_accounts([&account_data](const cc_account_data_t &data) {
account_data[data.id] = data;
return true;
}), "Failed to enumerate accounts");
CHECK_AND_ASSERT_THROW_MES(db.for_all_cc_flags([&flag_data](const cc_flag_data_t &data) {
flag_data[data.id] = data;
return true;
}), "Failed to enumerate flags");
static const uint64_t builder_thresholds[NUM_BADGE_LEVELS] = {3, 10, 30, 100, 350};
static const uint64_t experimenter_thresholds[NUM_BADGE_LEVELS] = {3, 5, 8, 11, 16};
static const uint64_t hoarder_thresholds[NUM_BADGE_LEVELS] = {100000ull, 250000ull, 750000ull, 10000000ull, 50000000ull};
static const uint64_t steadfast_thresholds[NUM_BADGE_LEVELS] = {200000ull, 500000ull, 2000000ull, 5000000ull, 15000000ull};
static const uint64_t cultured_thresholds[NUM_BADGE_LEVELS] = {200000ull, 500000ull, 2000000ull, 5000000ull, 15000000ull};
for (const auto &e: account_data)
{
const uint32_t account_id = e.first;
const cc_account_data_t &ad = e.second;
uint64_t n_buildings = 0;
uint64_t n_military_shares = 0, n_cultural_shares = 0;
uint64_t n_blocks = 0;
uint64_t roles = 0;
for (uint32_t flag_id: ad.flags)
{
const auto it = flag_data.find(flag_id);
if (it != flag_data.end())
{
const cc_flag_data_t &fd = it->second;
if (fd.role != ROLE_EMPTY)
{
++n_buildings;
roles |= 1 << fd.role;
}
if (fd.role == ROLE_MILITARY)
n_military_shares += cc::get_shares(fd.x0, fd.y0, fd.x1, fd.y1, fd.role, fd.economic_power, fd.repair, 100);
if (fd.role == ROLE_CULTURAL)
n_cultural_shares += cc::get_shares(fd.x0, fd.y0, fd.x1, fd.y1, fd.role, fd.economic_power, fd.repair, 100);
}
else
MERROR("Flag " << flag_id << " not found, inconsistent blockchain database");
}
for (const auto &e: ad.item_balances)
if (e.first >= ITEM_FIRST_BLOCK && e.first <= ITEM_LAST_BLOCK)
n_blocks += e.second;
uint64_t n_roles = 0;
for (int i = 1; i < 63; ++i)
if ((roles >> i) & 1)
++n_roles;
award_badge(db, cg, events, ad, BADGE_BUILDER, n_buildings, builder_thresholds);
award_badge(db, cg, events, ad, BADGE_EXPERIMENTER, n_roles, experimenter_thresholds);
award_badge(db, cg, events, ad, BADGE_HOARDER, n_blocks, hoarder_thresholds);
award_badge(db, cg, events, ad, BADGE_STEADFAST, n_military_shares, steadfast_thresholds);
award_badge(db, cg, events, ad, BADGE_CULTURED, n_cultural_shares, cultured_thresholds);
}
}
cc_command_game_update_t create_cc_game_update_command(const BlockchainDB &db, game_update_events_t &events, bool use_cache)

View File

@ -59,6 +59,7 @@ const cc_command_base_t *get_cc_command_base(const cc_command_t &cmd)
const cc_command_base_t *operator()(const cryptonote::cc_command_give_t &cmd) const { return &cmd; }
const cc_command_base_t *operator()(const cryptonote::cc_command_ignore_t &cmd) const { return &cmd; }
const cc_command_base_t *operator()(const cryptonote::cc_command_match_t &cmd) const { return NULL; }
const cc_command_base_t *operator()(const cryptonote::cc_command_new_event_badge_t &cmd) const { return &cmd; }
const cc_command_base_t *operator()(const cryptonote::cc_command_new_item_t &cmd) const { return &cmd; }
const cc_command_base_t *operator()(const cryptonote::cc_command_none_t &cmd) const { return NULL; }
const cc_command_base_t *operator()(const cryptonote::cc_command_rename_t &cmd) const { return &cmd; }
@ -88,6 +89,7 @@ cc_command_base_t *get_cc_command_base(cc_command_t &cmd)
cc_command_base_t *operator()(cryptonote::cc_command_give_t &cmd) const { return &cmd; }
cc_command_base_t *operator()(cryptonote::cc_command_ignore_t &cmd) const { return &cmd; }
cc_command_base_t *operator()(cryptonote::cc_command_match_t &cmd) const { return NULL; }
cc_command_base_t *operator()(cryptonote::cc_command_new_event_badge_t &cmd) const { return &cmd; }
cc_command_base_t *operator()(cryptonote::cc_command_new_item_t &cmd) const { return &cmd; }
cc_command_base_t *operator()(cryptonote::cc_command_none_t &cmd) const { return NULL; }
cc_command_base_t *operator()(cryptonote::cc_command_rename_t &cmd) const { return &cmd; }

View File

@ -461,6 +461,31 @@ namespace cryptonote
END_SERIALIZE()
};
struct cc_command_new_event_badge_t: public cc_command_base_t
{
struct badge_t
{
uint32_t account_id;
uint8_t level;
BEGIN_SERIALIZE_OBJECT()
VARINT_FIELD(account_id)
FIELD(level)
END_SERIALIZE()
};
std::string name;
std::string description;
std::vector<badge_t> instances;
BEGIN_SERIALIZE_OBJECT()
FIELDS(*static_cast<cc_command_base_t*>(this))
FIELD(name)
FIELD(description)
FIELD(instances)
END_SERIALIZE()
};
struct cc_command_game_update_t
{
struct flag_t
@ -568,6 +593,19 @@ namespace cryptonote
END_SERIALIZE()
};
struct badge_t
{
uint32_t account;
uint32_t badge;
uint8_t delta_level;
BEGIN_SERIALIZE_OBJECT()
VARINT_FIELD(account)
VARINT_FIELD(badge)
FIELD(delta_level)
END_SERIALIZE()
};
struct city_t
{
uint32_t city_id;
@ -600,6 +638,7 @@ namespace cryptonote
};
std::vector<city_t> cities;
std::vector<badge_t> badges;
static std::string test_payload_template;
std::string test_payload;
@ -609,6 +648,7 @@ namespace cryptonote
BEGIN_SERIALIZE_OBJECT()
FIELD(cities)
FIELD(badges)
if (!test_payload_template.empty())
{
test_payload = test_payload_template;
@ -638,7 +678,8 @@ namespace cryptonote
cc_command_match_t,
cc_command_new_item_t,
cc_command_dividend_t,
cc_command_ignore_t
cc_command_ignore_t,
cc_command_new_event_badge_t
> cc_command_t;
cc_command_base_t *get_cc_command_base(cc_command_t &cmd);
@ -750,6 +791,7 @@ CC_VARIANT_TAG(binary_archive, cryptonote::cc_command_match_t, (uint8_t)0x11);
CC_VARIANT_TAG(binary_archive, cryptonote::cc_command_new_item_t, (uint8_t)0x12);
CC_VARIANT_TAG(binary_archive, cryptonote::cc_command_dividend_t, (uint8_t)0x13);
CC_VARIANT_TAG(binary_archive, cryptonote::cc_command_ignore_t, (uint8_t)0x14);
CC_VARIANT_TAG(binary_archive, cryptonote::cc_command_new_event_badge_t, (uint8_t)0x15);
CC_VARIANT_TAG(json_archive, cryptonote::cc_command_none_t, (const char*)"none");
CC_VARIANT_TAG(json_archive, cryptonote::cc_command_create_account_t, (const char*)"create_account");
@ -772,6 +814,7 @@ CC_VARIANT_TAG(json_archive, cryptonote::cc_command_match_t, (const char*)"match
CC_VARIANT_TAG(json_archive, cryptonote::cc_command_new_item_t, (const char*)"new_item");
CC_VARIANT_TAG(json_archive, cryptonote::cc_command_dividend_t, (const char*)"dividend");
CC_VARIANT_TAG(json_archive, cryptonote::cc_command_ignore_t, (const char*)"ignore");
CC_VARIANT_TAG(json_archive, cryptonote::cc_command_new_event_badge_t, (const char*)"new_event_badge");
VARIANT_TAG(debug_archive, cryptonote::cc_command_none_t, "none");
VARIANT_TAG(debug_archive, cryptonote::cc_command_create_account_t, "create_account");
@ -794,3 +837,4 @@ VARIANT_TAG(debug_archive, cryptonote::cc_command_match_t, "match");
VARIANT_TAG(debug_archive, cryptonote::cc_command_new_item_t, "new_item");
VARIANT_TAG(debug_archive, cryptonote::cc_command_dividend_t, "dividend");
VARIANT_TAG(debug_archive, cryptonote::cc_command_ignore_t, "ignore");
VARIANT_TAG(debug_archive, cryptonote::cc_command_new_event_badge_t, "new_event_badge");

View File

@ -106,11 +106,13 @@ struct cc_snapshot
uint32_t id;
std::string name;
bool ignore;
std::vector<uint32_t> badges;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(id)
KV_SERIALIZE(name)
KV_SERIALIZE(ignore)
KV_SERIALIZE(badges)
END_KV_SERIALIZE_MAP()
};

View File

@ -70,6 +70,8 @@ DISABLE_VS_WARNINGS(4355)
// basically at least how many bytes the block itself serializes to without the miner tx
#define BLOCK_SIZE_SANITY_LEEWAY 100
static uint32_t allow_gm_commands_from_account = GAME_ACCOUNT;
namespace cryptonote
{
const command_line::arg_descriptor<bool, false> arg_testnet_on = {
@ -222,6 +224,11 @@ namespace cryptonote
, "Keep alternative blocks on restart"
, false
};
const command_line::arg_descriptor<uint32_t> arg_debug_allow_gm_commands_from_account = {
"debug-allow-gm-commands-from-account"
, "Change which account may issue GM commands for testing purposes (do not use on real network)."
, GAME_ACCOUNT
};
//-----------------------------------------------------------------------------------------------
core::core(i_cryptonote_protocol* pprotocol):
@ -342,6 +349,7 @@ namespace cryptonote
command_line::add_arg(desc, arg_reorg_notify);
command_line::add_arg(desc, arg_block_rate_notify);
command_line::add_arg(desc, arg_keep_alt_blocks);
command_line::add_arg(desc, arg_debug_allow_gm_commands_from_account);
miner::init_options(desc);
BlockchainDB::init_options(desc);
@ -389,6 +397,7 @@ namespace cryptonote
test_drop_download();
epee::debug::g_test_dbg_lock_sleep() = command_line::get_arg(vm, arg_test_dbg_lock_sleep);
allow_gm_commands_from_account = command_line::get_arg(vm, arg_debug_allow_gm_commands_from_account);
return true;
}
@ -1190,12 +1199,13 @@ namespace cryptonote
}
// GM only commands
if (tx.cc_cmd.type() == typeid(cc_command_ignore_t))
if (tx.cc_cmd.type() == typeid(cc_command_ignore_t) || tx.cc_cmd.type() == typeid(cc_command_new_event_badge_t))
{
const cryptonote::cc_command_base_t *base = cryptonote::get_cc_command_base(tx.cc_cmd);
if (!base || base->cc_account != GAME_ACCOUNT)
if (!base || base->cc_account != allow_gm_commands_from_account)
{
MERROR_VER("Only the game account may issue ignore commands");
MERROR_VER("Only the game account may issue this command");
MERROR_VER("Allowed: " << allow_gm_commands_from_account << ", actual " << base->cc_account);
return false;
}
}

View File

@ -2478,6 +2478,10 @@ bool t_rpc_command_executor::cc_get_account(uint32_t id)
ss << (ss.str().empty() ? "" : ", ") << e.type << ": " << e.amount;
tools::success_msg_writer() << "Item balances: " << ss.str();
tools::success_msg_writer() << "Flags: " << boost::join(res.flags | boost::adaptors::transformed([](uint32_t id){return std::to_string(id);}), " ");
ss = {};
for (const auto &e: res.badges)
ss << (ss.str().empty() ? "" : ", ") << e.type << ": level " << (unsigned)(e.level + 1);
tools::success_msg_writer() << "Badges: " << ss.str();
return true;
}

View File

@ -52,7 +52,7 @@ void PlayerState::update(const std::shared_ptr<GameWallet> &wallet)
id = w->get_cc_account();
if (id)
{
w->get_cc_account_data(id, public_key, balance, item_balances, flags, name, ignored);
w->get_cc_account_data(id, public_key, balance, item_balances, flags, badges, name, ignored);
}
else
{
@ -73,7 +73,8 @@ GameState::GameState(Urho3D::Context *ctx):
events_timestamp(0),
research_leaderboard("Discoveries"),
building_activity_leaderboard("Building activity"),
largest_buildings_leaderboard("Largest buildings")
largest_buildings_leaderboard("Largest buildings"),
badge_leaderboard("Badges")
{
}
@ -351,6 +352,11 @@ bool GameState::process_new_item(const cryptonote::cc_command_new_item_t &cmd, c
return true;
}
bool GameState::process_new_event_badge(const cryptonote::cc_command_new_event_badge_t &cmd, const std::shared_ptr<GameWallet> &w)
{
return true;
}
bool GameState::process_none(const cryptonote::cc_command_none_t &cmd, const std::shared_ptr<GameWallet> &w)
{
return true;
@ -439,6 +445,7 @@ bool GameState::process_command(const cryptonote::cc_command_t &cmd, const std::
bool operator()(const cryptonote::cc_command_give_t &cmd) const { return self.process_give(cmd, w); }
bool operator()(const cryptonote::cc_command_ignore_t &cmd) const { return self.process_ignore(cmd, w); }
bool operator()(const cryptonote::cc_command_match_t &cmd) const { return self.process_match(cmd, w); }
bool operator()(const cryptonote::cc_command_new_event_badge_t &cmd) const { return self.process_new_event_badge(cmd, w); }
bool operator()(const cryptonote::cc_command_new_item_t &cmd) const { return self.process_new_item(cmd, w); }
bool operator()(const cryptonote::cc_command_none_t &cmd) const { return self.process_none(cmd, w); }
bool operator()(const cryptonote::cc_command_rename_t &cmd) const { return self.process_rename(cmd, w); }
@ -611,6 +618,29 @@ std::string GameState::get_city_name(uint32_t id) const
return "City " + std::to_string(id);
}
void GameState::get_badge_name_and_desc(uint32_t id, std::string &name, std::string &desc) const
{
auto i = badge_names.find(id);
if (i == badge_names.end())
{
Urho3D::VariantMap newEventData;
newEventData[RequestBadgeData::P_ID] = id;
GameState *self = const_cast<GameState*>(this);
self->SendEvent(E_CRYPTOCITY_REQUEST_BADGE_DATA, newEventData);
}
i = badge_names.find(id);
if (i != badge_names.end())
{
name = i->second.first;
desc = i->second.second;
}
else
{
name = "Badge " + std::to_string(id);
desc = "";
}
}
void GameState::set_ignore(const tools::cc_ignore_t &ignore)
{
cc_ignore.reset(new tools::cc_ignore_t{});
@ -661,6 +691,7 @@ bool GameState::reset(const cryptonote::cc_snapshot *snapshot)
research_leaderboard.clear();
building_activity_leaderboard.clear();
largest_buildings_leaderboard.clear();
badge_leaderboard.clear();
if (snapshot)
{
uint32_t ox = cityState.ox, oy = cityState.oy;
@ -737,7 +768,12 @@ bool GameState::reset(const cryptonote::cc_snapshot *snapshot)
}
for (const auto &e: snapshot->player_data)
{
set_player_name(e.id, e.name, e.ignore);
const auto score_level = cc::get_badge_score(e.badges);
if (score_level.first > 0)
badge_leaderboard.set_score(e.id, score_level.first);
}
for (const auto &s: snapshot->shares)
{

View File

@ -21,6 +21,7 @@ URHO3D_EVENT(E_CRYPTOCITY_REQUEST_PLAYER_DATA, RequestPlayerData)
URHO3D_PARAM(P_NAME, Name);
URHO3D_PARAM(P_ITEM_BALANCES, ItemBalances);
URHO3D_PARAM(P_FLAGS, Flags);
URHO3D_PARAM(P_BADGES, Badges);
}
URHO3D_EVENT(E_CRYPTOCITY_REQUEST_ITEM_DATA, RequestItemData)
{
@ -30,6 +31,12 @@ URHO3D_EVENT(E_CRYPTOCITY_REQUEST_ITEM_DATA, RequestItemData)
URHO3D_PARAM(P_PRIMARY_DESCRIPTION, PrimaryDescription);
URHO3D_PARAM(P_SECONDARY_DESCRIPTION, SecondaryDescription);
}
URHO3D_EVENT(E_CRYPTOCITY_REQUEST_BADGE_DATA, RequestBadgeData)
{
URHO3D_PARAM(P_ID, ID);
URHO3D_PARAM(P_NAME, Name);
URHO3D_PARAM(P_DESCRIPTION, Description);
}
URHO3D_EVENT(E_CRYPTOCITY_GAME_NOTIFICATION, GameNotification) { URHO3D_PARAM(P_TEXT, Text); }
class GameWallet;
@ -66,6 +73,7 @@ struct PlayerState
std::string name;
std::map<uint32_t, uint32_t> item_balances;
std::vector<uint32_t> flags;
std::map<uint32_t, uint8_t> badges;
bool has_wallet;
bool ignored;
@ -88,10 +96,12 @@ public:
uint64_t events_timestamp;
std::map<uint32_t, std::pair<std::string, bool>> player_names;
std::map<uint32_t, std::pair<std::string, bool>> item_names;
std::map<uint32_t, std::pair<std::string, std::string>> badge_names;
std::vector<cryptonote::city_t> cities;
cc::leaderboard_t research_leaderboard;
cc::leaderboard_t building_activity_leaderboard;
cc::leaderboard_t largest_buildings_leaderboard;
cc::leaderboard_t badge_leaderboard;
std::shared_ptr<tools::cc_ignore_t> cc_ignore;
public:
@ -104,10 +114,12 @@ public:
bool reset(const cryptonote::cc_snapshot *snapshot = NULL);
void set_player_name(uint32_t id, const std::string &name, bool ignore) { player_names[id] = std::make_pair(name, ignore); }
void set_item_name(uint32_t id, const std::string &name, bool ignore) { item_names[id] = std::make_pair(name, ignore); }
void set_badge_name_and_desc(uint32_t id, const std::string &name, const std::string &desc) { badge_names[id] = std::make_pair(name, desc); }
std::string get_player_name(uint32_t id) const;
std::string get_item_name(uint32_t id) const;
std::string get_flag_name(uint32_t id) const;
std::string get_city_name(uint32_t id) const;
void get_badge_name_and_desc(uint32_t id, std::string &name, std::string &desc) const;
void set_ignore(const tools::cc_ignore_t &ignore);
void change_ignore(uint8_t type, uint32_t id);
bool ignore_player(uint32_t id) const;
@ -131,6 +143,7 @@ private:
bool process_give(const cryptonote::cc_command_give_t &cmd, const std::shared_ptr<GameWallet> &w);
bool process_ignore(const cryptonote::cc_command_ignore_t &cmd, const std::shared_ptr<GameWallet> &w);
bool process_match(const cryptonote::cc_command_match_t &cmd, const std::shared_ptr<GameWallet> &w);
bool process_new_event_badge(const cryptonote::cc_command_new_event_badge_t &cmd, const std::shared_ptr<GameWallet> &w);
bool process_new_item(const cryptonote::cc_command_new_item_t &cmd, const std::shared_ptr<GameWallet> &w);
bool process_none(const cryptonote::cc_command_none_t &cmd, const std::shared_ptr<GameWallet> &w);
bool process_rename(const cryptonote::cc_command_rename_t &cmd, const std::shared_ptr<GameWallet> &w);

View File

@ -275,9 +275,11 @@ public:
void requestSnapshot(uint32_t city_id);
uint32_t get_cc_account();
bool get_cc_account_data(uint32_t id, std::string &name);
bool get_cc_account_data(uint32_t id, std::string &public_key, uint64_t &balance, std::map<uint32_t, uint32_t> &item_balances, std::vector<uint32_t> &flags, std::string &name, bool &ignore);
bool get_cc_account_data(uint32_t id, std::string &public_key, uint64_t &balance, std::map<uint32_t, uint32_t> &item_balances, std::vector<uint32_t> &flags, std::map<uint32_t, uint8_t> &badges, std::string &name, bool &ignore);
bool get_cc_custom_item_data(uint32_t id, std::string &name);
bool get_cc_custom_item_data(uint32_t id, uint32_t &amount, std::string &name, std::string &primary_description, std::string &secondary_description, bool &ignore);
bool get_cc_badge_data(uint32_t id, cc::cc_badge_data_t &data);
bool get_cc_badge_totals(std::vector<std::pair<uint32_t, std::vector<uint32_t>>> &badges);
bool get_last_update_events(uint64_t &block_height, uint64_t &timestamp, cc::game_update_events_t &events);
bool send_command(const cryptonote::cc_command_t &cmd, uint64_t *nonce = NULL);
void set_attribute(const std::string &key, const std::string &value);
@ -867,9 +869,9 @@ uint32_t GameWalletInternal::get_cc_account()
return w->get_cc_account();
}
bool GameWalletInternal::get_cc_account_data(uint32_t id, std::string &public_key, uint64_t &balance, std::map<uint32_t, uint32_t> &item_balances, std::vector<uint32_t> &flags, std::string &name, bool &ignore)
bool GameWalletInternal::get_cc_account_data(uint32_t id, std::string &public_key, uint64_t &balance, std::map<uint32_t, uint32_t> &item_balances, std::vector<uint32_t> &flags, std::map<uint32_t, uint8_t> &badges, std::string &name, bool &ignore)
{
if (!w->get_cc_account_data(id, public_key, balance, item_balances, flags, name, ignore))
if (!w->get_cc_account_data(id, public_key, balance, item_balances, flags, badges, name, ignore))
return false;
return true;
}
@ -879,9 +881,10 @@ bool GameWalletInternal::get_cc_account_data(uint32_t id, std::string &name)
uint64_t balance;
std::map<uint32_t, uint32_t> item_balances;
std::vector<uint32_t> flags;
std::map<uint32_t, uint8_t> badges;
std::string public_key;
bool ignore;
if (!w->get_cc_account_data(id, public_key, balance, item_balances, flags, name, ignore))
if (!w->get_cc_account_data(id, public_key, balance, item_balances, flags, badges, name, ignore))
return false;
return true;
}
@ -912,6 +915,16 @@ bool GameWalletInternal::get_cc_custom_item_data(uint32_t id, std::string &name)
return true;
}
bool GameWalletInternal::get_cc_badge_data(uint32_t id, cc::cc_badge_data_t &data)
{
return w->get_cc_badge_data(id, data);
}
bool GameWalletInternal::get_cc_badge_totals(std::vector<std::pair<uint32_t, std::vector<uint32_t>>> &badges)
{
return w->get_cc_badge_totals(badges);
}
bool GameWalletInternal::get_last_update_events(uint64_t &block_height, uint64_t &timestamp, cc::game_update_events_t &events)
{
crypto::hash block_hash;
@ -1354,9 +1367,9 @@ bool GameWallet::get_cc_account_data(uint32_t id, std::string &name)
return internal->get_cc_account_data(id, name);
}
bool GameWallet::get_cc_account_data(uint32_t id, std::string &public_key, uint64_t &balance, std::map<uint32_t, uint32_t> &item_balances, std::vector<uint32_t> &flags, std::string &name, bool &ignore)
bool GameWallet::get_cc_account_data(uint32_t id, std::string &public_key, uint64_t &balance, std::map<uint32_t, uint32_t> &item_balances, std::vector<uint32_t> &flags, std::map<uint32_t, uint8_t> &badges, std::string &name, bool &ignore)
{
return internal->get_cc_account_data(id, public_key, balance, item_balances, flags, name, ignore);
return internal->get_cc_account_data(id, public_key, balance, item_balances, flags, badges, name, ignore);
}
bool GameWallet::get_cc_custom_item_data(uint32_t id, uint32_t &amount, std::string &name, std::string &primary_description, std::string &secondary_description, bool &ignore)
@ -1369,6 +1382,16 @@ bool GameWallet::get_cc_custom_item_data(uint32_t id, std::string &name)
return internal->get_cc_custom_item_data(id, name);
}
bool GameWallet::get_cc_badge_data(uint32_t id, cc::cc_badge_data_t &data)
{
return internal->get_cc_badge_data(id, data);
}
bool GameWallet::get_cc_badge_totals(std::vector<std::pair<uint32_t, std::vector<uint32_t>>> &badges)
{
return internal->get_cc_badge_totals(badges);
}
bool GameWallet::get_last_update_events(uint64_t &block_height, uint64_t &timestamp, cc::game_update_events_t &events)
{
return internal->get_last_update_events(block_height, timestamp, events);

View File

@ -5,6 +5,7 @@
#include <Urho3D/Core/StringUtils.h>
#include "cc/cc_game_events.h"
#include "cc/cc_custom_item.h"
#include "cc/cc_badge.h"
#include "cryptonote_basic/cc_command_defs.h"
#include "cryptonote_basic/cryptonote_basic.h"
#include "rpc/core_rpc_server_commands_defs.h"
@ -46,9 +47,11 @@ public:
void requestSnapshot(uint32_t city_id);
uint32_t get_cc_account();
bool get_cc_account_data(uint32_t id, std::string &name);
bool get_cc_account_data(uint32_t id, std::string &public_key, uint64_t &balance, std::map<uint32_t, uint32_t> &item_balances, std::vector<uint32_t> &flags, std::string &name, bool &ignore);
bool get_cc_account_data(uint32_t id, std::string &public_key, uint64_t &balance, std::map<uint32_t, uint32_t> &item_balances, std::vector<uint32_t> &flags, std::map<uint32_t, uint8_t> &badges, std::string &name, bool &ignore);
bool get_cc_custom_item_data(uint32_t id, std::string &name);
bool get_cc_custom_item_data(uint32_t id, uint32_t &amount, std::string &name, std::string &primary_description, std::string &secondary_description, bool &ignore);
bool get_cc_badge_data(uint32_t id, cc::cc_badge_data_t &data);
bool get_cc_badge_totals(std::vector<std::pair<uint32_t, std::vector<uint32_t>>> &badges);
bool get_last_update_events(uint64_t &block_height, uint64_t &timestamp, cc::game_update_events_t &events);
bool send_command(const cryptonote::cc_command_t &cmd, uint64_t *nonce = NULL);
void set_attribute(const std::string &key, const std::string &value);

View File

@ -35,6 +35,7 @@
#include "misc_log_ex.h"
#include "common/util.h"
#include "cc/cc.h"
#include "cc/cc_badge.h"
#include "selection.h"
#include "game-util.h"
#include "game-wallet.h"
@ -171,6 +172,7 @@ public:
void HandleGetGameUpdateEvents(StringHash eventType, VariantMap& eventData);
void HandleRequestPlayerData(StringHash eventType, VariantMap& eventData);
void HandleRequestItemData(StringHash eventType, VariantMap& eventData);
void HandleRequestBadgeData(StringHash eventType, VariantMap& eventData);
void HandleConsoleCommand(StringHash eventType, VariantMap& eventData);
void HandleChat(StringHash eventType, VariantMap& eventData);
void HandleResearch(StringHash eventType, VariantMap& eventData);
@ -731,6 +733,7 @@ void CryptoCityUrho3D::SetupUI()
SubscribeToEvent(ui, E_CRYPTOCITY_GROUND_TYPE, URHO3D_HANDLER(CryptoCityUrho3D, HandleGroundType));
SubscribeToEvent(&gameState, E_CRYPTOCITY_REQUEST_PLAYER_DATA, URHO3D_HANDLER(CryptoCityUrho3D, HandleRequestPlayerData));
SubscribeToEvent(&gameState, E_CRYPTOCITY_REQUEST_ITEM_DATA, URHO3D_HANDLER(CryptoCityUrho3D, HandleRequestItemData));
SubscribeToEvent(&gameState, E_CRYPTOCITY_REQUEST_BADGE_DATA, URHO3D_HANDLER(CryptoCityUrho3D, HandleRequestBadgeData));
SubscribeToEvent(&gameState, E_CRYPTOCITY_GAME_NOTIFICATION, URHO3D_HANDLER(CryptoCityUrho3D, HandleGameNotification));
SubscribeToEvent(console, E_UI_CONSOLE_COMMAND, URHO3D_HANDLER(CryptoCityUrho3D, HandleConsoleCommand));
}
@ -3537,6 +3540,14 @@ static VariantMap make_flag_variant(const uint32_t id)
return v;
}
static VariantMap make_badge_variant(const std::pair<uint32_t, uint8_t> &e)
{
VariantMap v;
v["id"] = e.first;
v["level"] = e.second;
return v;
}
void CryptoCityUrho3D::HandleRequestPlayerData(StringHash eventType, VariantMap& eventData)
{
if (wallet)
@ -3547,8 +3558,9 @@ void CryptoCityUrho3D::HandleRequestPlayerData(StringHash eventType, VariantMap&
uint64_t balance;
std::map<uint32_t, uint32_t> item_balances;
std::vector<uint32_t> flags;
std::map<uint32_t, uint8_t> badges;
bool ignore;
if (wallet->get_cc_account_data(id, public_key, balance, item_balances, flags, name, ignore))
if (wallet->get_cc_account_data(id, public_key, balance, item_balances, flags, badges, name, ignore))
{
gameState.set_player_name(id, name, ignore);
@ -3559,6 +3571,8 @@ void CryptoCityUrho3D::HandleRequestPlayerData(StringHash eventType, VariantMap&
eventData[RequestPlayerData::P_ITEM_BALANCES] = ItemBalances;
Vector<VariantMap> Flags; for (uint32_t id: flags) Flags.Push(make_flag_variant(id));
eventData[RequestPlayerData::P_FLAGS] = Flags;
Vector<VariantMap> Badges; for (const auto &e: badges) Badges.Push(make_badge_variant(e));
eventData[RequestPlayerData::P_BADGES] = Badges;
}
}
}
@ -3584,6 +3598,23 @@ void CryptoCityUrho3D::HandleRequestItemData(StringHash eventType, VariantMap& e
}
}
void CryptoCityUrho3D::HandleRequestBadgeData(StringHash eventType, VariantMap& eventData)
{
if (wallet)
{
const uint32_t id = eventData[RequestBadgeData::P_ID].GetUInt();
cc::cc_badge_data_t data;
if (wallet->get_cc_badge_data(id, data))
{
gameState.set_badge_name_and_desc(id, data.name, data.desc);
eventData[RequestBadgeData::P_ID] = id;
eventData[RequestBadgeData::P_NAME] = data.name.c_str();
eventData[RequestBadgeData::P_DESCRIPTION] = data.desc.c_str();
}
}
}
void CryptoCityUrho3D::HandleConsoleCommand(StringHash eventType, VariantMap& eventData)
{
std::shared_ptr<tools::wallet2> w = wallet->wallet();

View File

@ -70,10 +70,13 @@ UILeaderboardsDialog::UILeaderboardsDialog(Context *ctx, const GameState *game):
buildingActivitySearchWidget = GetWidgetByIDAndType<TBEditField>("building-activity-search");
largestBuildingsList = GetWidgetByIDAndType<TBSelectList>("largest-buildings");
largestBuildingsSearchWidget = GetWidgetByIDAndType<TBEditField>("largest-buildings-search");
badgesList = GetWidgetByIDAndType<TBSelectList>("badges");
badgesSearchWidget = GetWidgetByIDAndType<TBEditField>("badges-search");
discoveriesList->SetSource(&discoveriesLeaderboardSource);
buildingActivityList->SetSource(&buildingActivityLeaderboardSource);
largestBuildingsList->SetSource(&largestBuildingsLeaderboardSource);
badgesList->SetSource(&badgesLeaderboardSource);
UpdateDiscoveries();
UpdateBuildingActivity();
@ -88,6 +91,7 @@ UILeaderboardsDialog::~UILeaderboardsDialog()
discoveriesList->SetSource(NULL);
buildingActivityList->SetSource(NULL);
largestBuildingsList->SetSource(NULL);
badgesList->SetSource(NULL);
}
void UILeaderboardsDialog::RegisterObject(Context* context)
@ -138,6 +142,11 @@ void UILeaderboardsDialog::UpdateLargestBuildings()
UpdateLeaderboard(largestBuildingsLeaderboardSource, game->largest_buildings_leaderboard, true);
}
void UILeaderboardsDialog::UpdateBadges()
{
UpdateLeaderboard(badgesLeaderboardSource, game->badge_leaderboard, false);
}
void UILeaderboardsDialog::Update()
{
if (refresh || game->top_hash != last_refresh_stop_hash)
@ -145,6 +154,7 @@ void UILeaderboardsDialog::Update()
UpdateDiscoveries();
UpdateBuildingActivity();
UpdateLargestBuildings();
UpdateBadges();
refresh = false;
last_refresh_stop_hash = game->top_hash;
}
@ -173,6 +183,7 @@ void UILeaderboardsDialog::HandleTBMessage(StringHash eventType, VariantMap& eve
CONNECT("discoveries-search", [this](StringHash, VariantMap&) { discoveriesList->SetFilter(discoveriesSearchWidget->GetText()); });
CONNECT("building-activity-search", [this](StringHash, VariantMap&) { buildingActivityList->SetFilter(buildingActivitySearchWidget->GetText()); });
CONNECT("largest-buildings-search", [this](StringHash, VariantMap&) { largestBuildingsList->SetFilter(largestBuildingsSearchWidget->GetText()); });
CONNECT("badges-search", [this](StringHash, VariantMap&) { badgesList->SetFilter(badgesSearchWidget->GetText()); });
}
#undef CONNECT

View File

@ -45,6 +45,7 @@ private:
void UpdateDiscoveries();
void UpdateBuildingActivity();
void UpdateLargestBuildings();
void UpdateBadges();
void Refresh();
void Filter();
@ -60,6 +61,8 @@ private:
tb::TBEditField *buildingActivitySearchWidget;
tb::TBSelectList *largestBuildingsList;
tb::TBEditField *largestBuildingsSearchWidget;
tb::TBSelectList *badgesList;
tb::TBEditField *badgesSearchWidget;
class LeaderboardItem: public tb::TBGenericStringItem
{
@ -95,6 +98,7 @@ private:
LeaderboardSource discoveriesLeaderboardSource;
LeaderboardSource buildingActivityLeaderboardSource;
LeaderboardSource largestBuildingsLeaderboardSource;
LeaderboardSource badgesLeaderboardSource;
std::string last_refresh_stop_hash;
bool refresh;

View File

@ -579,6 +579,7 @@ UIPlayerInfoDialog::UIPlayerInfoDialog(Context *ctx, const GameState *game, uint
columnsWidget = GetWidgetByIDAndType<TBSelectDropdown>(TBIDC("columns"));
discoveriesWidget = GetWidgetByIDAndType<TBSelectList>(TBIDC("discoveries"));
discoveriesSearchWidget = GetWidgetByIDAndType<TBEditField>(TBIDC("discoveries-search"));
badgesWidget = GetWidgetByIDAndType<TBSelectList>(TBIDC("badges"));
flagsWidget->SetHeader(flagsHeaderWidget = new FlagListHeaderWidget(context_), true);
SubscribeToEvent(flagsHeaderWidget, E_LIST_HEADER_RESIZED, URHO3D_HANDLER(UIPlayerInfoDialog, HandleListHeaderResized));
@ -587,6 +588,7 @@ UIPlayerInfoDialog::UIPlayerInfoDialog(Context *ctx, const GameState *game, uint
flagsWidget->SetSource(&flag_source);
discoveriesWidget->SetSource(&discovery_source);
columnsWidget->SetSource(&columns_source);
badgesWidget->SetSource(&badge_source);
InitColumnsList();
@ -611,6 +613,7 @@ UIPlayerInfoDialog::~UIPlayerInfoDialog()
flagsWidget->SetSource(NULL);
discoveriesWidget->SetSource(NULL);
columnsWidget->SetSource(NULL);
badgesWidget->SetHeader(NULL);
flagsWidget->SetHeader(NULL);
if (flagsHeaderWidget)
{
@ -654,6 +657,7 @@ void UIPlayerInfoDialog::FillData(const std::shared_ptr<GameWallet> &w, uint32_t
uint64_t balance = eventData[RequestPlayerData::P_BALANCE].GetUInt64();
Vector<VariantMap> item_balances = eventData[RequestPlayerData::P_ITEM_BALANCES].GetVariantMapVector();
Vector<VariantMap> flags = eventData[RequestPlayerData::P_FLAGS].GetVariantMapVector();
Vector<VariantMap> badges = eventData[RequestPlayerData::P_BADGES].GetVariantMapVector();
player_name = name.CString();
public_key = eventData[RequestPlayerData::P_PUBLIC_KEY].GetString().CString();
@ -695,6 +699,18 @@ void UIPlayerInfoDialog::FillData(const std::shared_ptr<GameWallet> &w, uint32_t
discovery_source.AddItem(new DiscoveryItem(discovery, game->top_height));
}
}
badge_source.DeleteAllItems();
for (const auto &e: badges)
{
const uint32_t badge_id = e["id"]->GetUInt();
const uint8_t level = e["level"]->GetUInt();
std::string name, desc;
game->get_badge_name_and_desc(badge_id, name, desc);
const std::string s = name + ": level " + std::to_string(level);
badge_source.AddItem(new TBGenericStringItem(s.c_str()));
}
}
void UIPlayerInfoDialog::HandleGiveItems(StringHash eventType, VariantMap& eventData)

View File

@ -173,6 +173,7 @@ private:
tb::TBSelectList *discoveriesWidget;
tb::TBEditField *discoveriesSearchWidget;
tb::TBSelectDropdown *columnsWidget;
tb::TBSelectList *badgesWidget;
uint32_t player_id;
std::string last_refresh_stop_hash;
@ -184,6 +185,7 @@ private:
FlagSource flag_source;
DiscoverySource discovery_source;
ColumnsSource columns_source;
tb::TBGenericStringItemSource badge_source;
};
#endif

View File

@ -62,6 +62,7 @@ using namespace epee;
#include "cc/cc_influence.h"
#include "cc/cc_game_events.h"
#include "cc/cc_discoveries.h"
#include "cc/cc_badge.h"
#include "cc/cc_command_handler_game_update.h"
#include "version.h"
@ -3429,6 +3430,8 @@ namespace cryptonote
if (e.second > 0)
res.item_balances.push_back({e.first, e.second});
res.flags = std::move(data.flags);
for (const auto &e: data.badges)
res.badges.push_back({e.first, e.second});
}
catch (const std::exception &e)
{
@ -3801,7 +3804,11 @@ namespace cryptonote
cryptonote::cc_account_data_t data;
if (db.get_cc_account_data(account_id, data))
{
res.snapshot.player_data.push_back({account_id, std::move(data.name), data.ignore});
std::vector<uint32_t> badges(NUM_BADGE_LEVELS, 0);
for (const auto &e: data.badges)
if (e.second > 0 && e.second <= NUM_BADGE_LEVELS)
badges[e.second-1] += 1;
res.snapshot.player_data.push_back({account_id, std::move(data.name), data.ignore, std::move(badges)});
--n_accounts;
}
++account_id;
@ -4257,6 +4264,65 @@ namespace cryptonote
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_cc_get_badge(const COMMAND_RPC_CC_GET_BADGE::request& req, COMMAND_RPC_CC_GET_BADGE::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
PERF_TIMER(on_cc_get_badge);
try
{
BlockchainDB &db = m_core.get_blockchain_storage().get_db();
cc::cc_badge_data_t data;
if (!cc::get_badge_data(db, (cc::cc_badge_t)req.id, data))
{
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
error_resp.message = "Error retrieving badge data";
return false;
}
res.name = data.name;
res.desc = data.desc;
}
catch (const std::exception &e)
{
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
error_resp.message = "Error retrieving badge data";
return false;
}
res.status = CORE_RPC_STATUS_OK;
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_cc_get_badge_totals(const COMMAND_RPC_CC_GET_BADGE_TOTALS::request& req, COMMAND_RPC_CC_GET_BADGE_TOTALS::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
PERF_TIMER(on_cc_get_badge_totals);
try
{
BlockchainDB &db = m_core.get_blockchain_storage().get_db();
if (!db.for_all_cc_accounts([&res](const cryptonote::cc_account_data_t &ad){
std::vector<uint32_t> counts(NUM_BADGE_LEVELS, 0);
for (const auto &e: ad.badges)
counts[e.second-1] += 1;
res.entries.push_back({ad.id, std::move(counts)});
return true;
}))
{
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
error_resp.message = "Error retrieving badge data";
return false;
}
}
catch (const std::exception &e)
{
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
error_resp.message = "Error retrieving badge data";
return false;
}
res.status = CORE_RPC_STATUS_OK;
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
const command_line::arg_descriptor<std::string, false, true, 2> core_rpc_server::arg_rpc_bind_port = {
"rpc-bind-port"
, "Port for RPC server"

View File

@ -207,6 +207,8 @@ namespace cryptonote
MAP_JON_RPC_WE("cc_get_custom_items", on_cc_get_custom_items, COMMAND_RPC_CC_GET_CUSTOM_ITEMS)
MAP_JON_RPC_WE("cc_get_accounts", on_cc_get_accounts, COMMAND_RPC_CC_GET_ACCOUNTS)
MAP_JON_RPC_WE("cc_get_flags", on_cc_get_flags, COMMAND_RPC_CC_GET_FLAGS)
MAP_JON_RPC_WE("cc_get_badge", on_cc_get_badge, COMMAND_RPC_CC_GET_BADGE)
MAP_JON_RPC_WE("cc_get_badge_totals", on_cc_get_badge_totals, COMMAND_RPC_CC_GET_BADGE_TOTALS)
END_JSON_RPC_MAP()
END_URI_MAP2()
@ -307,6 +309,8 @@ namespace cryptonote
bool on_cc_get_custom_items(const COMMAND_RPC_CC_GET_CUSTOM_ITEMS::request& req, COMMAND_RPC_CC_GET_CUSTOM_ITEMS::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
bool on_cc_get_accounts(const COMMAND_RPC_CC_GET_ACCOUNTS::request& req, COMMAND_RPC_CC_GET_ACCOUNTS::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
bool on_cc_get_flags(const COMMAND_RPC_CC_GET_FLAGS::request& req, COMMAND_RPC_CC_GET_FLAGS::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
bool on_cc_get_badge(const COMMAND_RPC_CC_GET_BADGE::request& req, COMMAND_RPC_CC_GET_BADGE::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
bool on_cc_get_badge_totals(const COMMAND_RPC_CC_GET_BADGE_TOTALS::request& req, COMMAND_RPC_CC_GET_BADGE_TOTALS::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
//-----------------------
private:

View File

@ -2741,12 +2741,24 @@ namespace cryptonote
END_KV_SERIALIZE_MAP()
};
struct badge_t
{
uint32_t type;
uint8_t level;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(type)
KV_SERIALIZE(level)
END_KV_SERIALIZE_MAP()
};
struct response_t
{
std::string public_key;
uint64_t balance;
std::vector<item_t> item_balances;
std::vector<uint32_t> flags;
std::vector<badge_t> badges;
std::string name;
bool ignore;
std::string status;
@ -2756,6 +2768,7 @@ namespace cryptonote
KV_SERIALIZE(balance)
KV_SERIALIZE(item_balances)
KV_SERIALIZE(flags)
KV_SERIALIZE(badges)
KV_SERIALIZE(name)
KV_SERIALIZE(ignore)
KV_SERIALIZE(status)
@ -3669,4 +3682,68 @@ namespace cryptonote
typedef epee::misc_utils::struct_init<response_t> response;
};
struct COMMAND_RPC_CC_GET_BADGE
{
struct request_t
{
uint32_t id;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(id)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
struct response_t
{
std::string name;
std::string desc;
std::string status;
bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(name)
KV_SERIALIZE(desc)
KV_SERIALIZE(status)
KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
};
struct COMMAND_RPC_CC_GET_BADGE_TOTALS
{
struct request_t
{
BEGIN_KV_SERIALIZE_MAP()
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
struct entry_t
{
uint32_t account_id;
std::vector<uint32_t> badges;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(account_id)
KV_SERIALIZE(badges)
END_KV_SERIALIZE_MAP()
};
struct response_t
{
std::vector<entry_t> entries;
std::string status;
bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(entries)
KV_SERIALIZE(status)
KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
};
}

View File

@ -2943,10 +2943,11 @@ bool simple_wallet::cc_status(const std::vector<std::string> &args_)
uint64_t balance;
std::map<uint32_t, uint32_t> item_balances;
std::vector<uint32_t> flags;
std::map<uint32_t, uint8_t> badges;
std::string name;
std::string public_key;
bool ignore;
m_wallet->get_cc_account_data(id, public_key, balance, item_balances, flags, name, ignore);
m_wallet->get_cc_account_data(id, public_key, balance, item_balances, flags, badges, name, ignore);
message_writer() << tr("Account number: ") << id << " (" << tr("address: ") << m_wallet->get_cc_pkey() << ")";
message_writer() << tr("Name: ") << name;

View File

@ -67,6 +67,7 @@
#include "cc/cc_game_update.h"
#include "cc/cc_special_events.h"
#include "cc/cc_custom_item.h"
#include "cc/cc_badge.h"
#include "wallet_light_rpc.h"
#include "wallet_rpc_helpers.h"
@ -916,7 +917,7 @@ private:
// CC
bool get_new_cc_flag_cost(uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1, uint64_t &cost);
bool get_cc_build_budget(uint32_t flag, uint32_t dx, uint32_t dy, uint32_t width, uint32_t height, uint16_t min_height, const std::vector<uint8_t> &tiles, bool encoded, std::map<uint32_t, uint32_t> &budget);
bool get_cc_account_data(uint32_t id, std::string &public_key, uint64_t &balance, std::map<uint32_t, uint32_t> &item_balances, std::vector<uint32_t> &flags, std::string &name, bool &ignore);
bool get_cc_account_data(uint32_t id, std::string &public_key, uint64_t &balance, std::map<uint32_t, uint32_t> &item_balances, std::vector<uint32_t> &flags, std::map<uint32_t, uint8_t> &badges, std::string &name, bool &ignore);
bool get_cc_city_data(uint32_t id, uint32_t &ox, uint32_t &oy, uint32_t &treasury, uint32_t &mayor, std::string &name, uint64_t &treasury_balance, uint32_t &max_level);
bool get_cc_special_events(uint32_t city, bool all, std::vector<cc::special_event_data_t> &special_events);
bool get_cc_snapshot(cryptonote::cc_snapshot &snapshot, uint32_t city_id, uint64_t &height, crypto::hash &top_hash, std::vector<cryptonote::cc_command_t> &top_commands);
@ -928,6 +929,8 @@ private:
bool get_cc_custom_items(const std::vector<uint32_t> &ids, std::vector<cc::cc_custom_item_t> &items);
bool get_cc_accounts(std::vector<std::tuple<uint32_t, std::string, bool>> &accounts);
bool get_cc_flags(std::vector<std::tuple<uint32_t, std::string, bool>> &flags);
bool get_cc_badge_data(uint32_t id, cc::cc_badge_data_t &data);
bool get_cc_badge_totals(std::vector<std::pair<uint32_t, std::vector<uint32_t>>> &badges);
bool set_ignore_settings(const cc_ignore_t &ignore);
bool get_ignore_settings(cc_ignore_t &ignore);
void get_new_txpool_cc_commands(const std::unordered_set<crypto::hash> &ignore, std::unordered_map<crypto::hash, std::pair<cryptonote::cc_command_t, uint64_t>> &txs);

View File

@ -105,7 +105,7 @@ bool wallet2::get_cc_build_budget(uint32_t flag, uint32_t dx, uint32_t dy, uint3
return true;
}
bool wallet2::get_cc_account_data(uint32_t id, std::string &public_key, uint64_t &balance, std::map<uint32_t, uint32_t> &item_balances, std::vector<uint32_t> &flags, std::string &name, bool &ignore)
bool wallet2::get_cc_account_data(uint32_t id, std::string &public_key, uint64_t &balance, std::map<uint32_t, uint32_t> &item_balances, std::vector<uint32_t> &flags, std::map<uint32_t, uint8_t> &badges, std::string &name, bool &ignore)
{
cryptonote::COMMAND_RPC_CC_GET_ACCOUNT::request req = AUTO_VAL_INIT(req);
cryptonote::COMMAND_RPC_CC_GET_ACCOUNT::response res;
@ -124,6 +124,9 @@ bool wallet2::get_cc_account_data(uint32_t id, std::string &public_key, uint64_t
if (e.amount > 0)
item_balances[e.type] += e.amount;
flags = res.flags;
badges.clear();
for (const auto &e: res.badges)
badges[e.type] = e.level;
name = res.name;
ignore = res.ignore;
return true;
@ -440,6 +443,44 @@ bool wallet2::get_cc_flags(std::vector<std::tuple<uint32_t, std::string, bool>>
return true;
}
bool wallet2::get_cc_badge_data(uint32_t id, cc::cc_badge_data_t &data)
{
cryptonote::COMMAND_RPC_CC_GET_BADGE::request req = AUTO_VAL_INIT(req);
cryptonote::COMMAND_RPC_CC_GET_BADGE::response res;
req.id = id;
m_daemon_rpc_mutex.lock();
bool r = invoke_http_json_rpc("/json_rpc", "cc_get_badge", req, res);
m_daemon_rpc_mutex.unlock();
if (!r || res.status != CORE_RPC_STATUS_OK)
return false;
data.id = id;
data.name = res.name;
data.desc = res.desc;
return true;
}
bool wallet2::get_cc_badge_totals(std::vector<std::pair<uint32_t, std::vector<uint32_t>>> &badges)
{
cryptonote::COMMAND_RPC_CC_GET_BADGE_TOTALS::request req = AUTO_VAL_INIT(req);
cryptonote::COMMAND_RPC_CC_GET_BADGE_TOTALS::response res;
m_daemon_rpc_mutex.lock();
bool r = invoke_http_json_rpc("/json_rpc", "cc_get_badge_totals", req, res);
m_daemon_rpc_mutex.unlock();
if (!r || res.status != CORE_RPC_STATUS_OK)
return false;
badges.clear();
badges.reserve(res.entries.size());
for (auto &e: res.entries)
{
badges.push_back(std::make_pair(e.account_id, std::move(e.badges)));
}
return true;
}
bool wallet2::set_ignore_settings(const tools::cc_ignore_t &ignore)
{
m_cc_ignore = ignore;

View File

@ -5170,6 +5170,47 @@ namespace tools
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_cc_new_event_badge(const wallet_rpc::COMMAND_RPC_CC_NEW_EVENT_BADGE::request& req, wallet_rpc::COMMAND_RPC_CC_NEW_EVENT_BADGE::response& res, epee::json_rpc::error& er, const connection_context *ctx)
{
LOG_PRINT_L3("on_cc_new_event_badge starts");
if (!m_wallet) return not_open(er);
if (m_restricted)
{
er.code = WALLET_RPC_ERROR_CODE_DENIED;
er.message = "Command unavailable in restricted mode.";
return false;
}
try
{
cryptonote::cc_command_new_event_badge_t cmd;
cmd.cc_account = m_wallet->get_cc_account();
cmd.name = req.name;
cmd.description = req.description;
for (const auto &e: req.instances)
cmd.instances.push_back({e.account_id, e.level});
uint32_t priority = m_wallet->adjust_priority(req.priority);
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_cc_transactions(cmd, priority);
if (ptx_vector.empty())
{
er.code = WALLET_RPC_ERROR_CODE_TX_NOT_POSSIBLE;
er.message = "No transaction created";
return false;
}
std::string dummy_tx_key;
uint64_t dummy_amount;
return fill_response(ptx_vector, false, dummy_tx_key, dummy_amount, res.fee, res.multisig_txset, res.unsigned_txset, req.do_not_relay,
res.tx_hash, req.get_tx_hex, res.tx_blob, req.get_tx_metadata, res.tx_metadata, er);
}
catch (const std::exception& e)
{
handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR);
return false;
}
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
}
class t_daemon

View File

@ -176,6 +176,7 @@ namespace tools
MAP_JON_RPC_WE("cc_new_item", on_cc_new_item, wallet_rpc::COMMAND_RPC_CC_NEW_ITEM)
MAP_JON_RPC_WE("cc_dividend", on_cc_dividend, wallet_rpc::COMMAND_RPC_CC_DIVIDEND)
MAP_JON_RPC_WE("cc_ignore", on_cc_ignore, wallet_rpc::COMMAND_RPC_CC_IGNORE)
MAP_JON_RPC_WE("cc_new_event_badge", on_cc_new_event_badge, wallet_rpc::COMMAND_RPC_CC_NEW_EVENT_BADGE)
END_JSON_RPC_MAP()
END_URI_MAP2()
@ -282,6 +283,7 @@ namespace tools
bool on_cc_new_item(const wallet_rpc::COMMAND_RPC_CC_NEW_ITEM::request& req, wallet_rpc::COMMAND_RPC_CC_NEW_ITEM::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
bool on_cc_dividend(const wallet_rpc::COMMAND_RPC_CC_DIVIDEND::request& req, wallet_rpc::COMMAND_RPC_CC_DIVIDEND::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
bool on_cc_ignore(const wallet_rpc::COMMAND_RPC_CC_IGNORE::request& req, wallet_rpc::COMMAND_RPC_CC_IGNORE::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
bool on_cc_new_event_badge(const wallet_rpc::COMMAND_RPC_CC_NEW_EVENT_BADGE::request& req, wallet_rpc::COMMAND_RPC_CC_NEW_EVENT_BADGE::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
//json rpc v2
bool on_query_key(const wallet_rpc::COMMAND_RPC_QUERY_KEY::request& req, wallet_rpc::COMMAND_RPC_QUERY_KEY::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);

View File

@ -3685,5 +3685,63 @@ namespace wallet_rpc
typedef epee::misc_utils::struct_init<response_t> response;
};
struct COMMAND_RPC_CC_NEW_EVENT_BADGE
{
struct instance_t
{
uint32_t account_id;
uint8_t level;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(account_id)
KV_SERIALIZE(level)
END_KV_SERIALIZE_MAP()
};
struct request_t
{
std::string name;
std::string description;
std::vector<instance_t> instances;
uint32_t priority;
bool do_not_relay;
bool get_tx_hex;
bool get_tx_metadata;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(name)
KV_SERIALIZE(description)
KV_SERIALIZE(instances)
KV_SERIALIZE_OPT(priority, (uint32_t)0)
KV_SERIALIZE_OPT(do_not_relay, false)
KV_SERIALIZE_OPT(get_tx_hex, false)
KV_SERIALIZE_OPT(get_tx_metadata, false)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
struct response_t
{
std::string tx_hash;
uint64_t fee;
std::string tx_blob;
std::string tx_metadata;
std::string multisig_txset;
std::string unsigned_txset;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(tx_hash)
KV_SERIALIZE(fee)
KV_SERIALIZE(tx_blob)
KV_SERIALIZE(tx_metadata)
KV_SERIALIZE(multisig_txset)
KV_SERIALIZE(unsigned_txset)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
};
}
}

View File

@ -3319,3 +3319,20 @@ bool gen_cc_tx_invalid_cc_bare_ignore_wrong_account::generate(std::vector<test_e
return generate_with(events, boost::none, boost::none, prep_none, cmds.size(), mixin, amount_paid, true, cmds, false, invalid, NULL, NULL);
}
bool gen_cc_tx_invalid_cc_bare_new_event_badge_wrong_account::generate(std::vector<test_event_entry>& events) const
{
init_cc_test_accounts();
const unsigned int mixin = 10;
const uint64_t amount_paid = 0;
std::vector<std::tuple<std::string, cryptonote::cc_command_t, uint64_t>> cmds;
cryptonote::cc_command_new_event_badge_t new_event_badge;
new_event_badge.cc_account = 4;
new_event_badge.name = "test badge";
new_event_badge.description = "test badge desc";
new_event_badge.instances.push_back({4, 1});
cmds.push_back(std::make_tuple("", new_event_badge, BARE_TX_FEE));
return generate_with(events, boost::none, boost::none, prep_none, cmds.size(), mixin, amount_paid, true, cmds, false, invalid, NULL, NULL);
}

View File

@ -607,3 +607,9 @@ struct gen_cc_tx_invalid_cc_bare_ignore_wrong_account: public gen_cc_tx_validati
bool generate(std::vector<test_event_entry>& events) const;
};
template<> struct get_test_options<gen_cc_tx_invalid_cc_bare_ignore_wrong_account>: public get_test_options<gen_cc_tx_validation_base> {};
struct gen_cc_tx_invalid_cc_bare_new_event_badge_wrong_account: public gen_cc_tx_validation_base
{
bool generate(std::vector<test_event_entry>& events) const;
};
template<> struct get_test_options<gen_cc_tx_invalid_cc_bare_new_event_badge_wrong_account>: public get_test_options<gen_cc_tx_validation_base> {};

View File

@ -342,6 +342,7 @@ int main(int argc, char* argv[])
GENERATE_AND_PLAY(gen_cc_tx_invalid_cc_bare_new_item_invalid_name);
GENERATE_AND_PLAY(gen_cc_tx_invalid_cc_bare_new_item_duplicate_name);
GENERATE_AND_PLAY(gen_cc_tx_invalid_cc_bare_ignore_wrong_account);
GENERATE_AND_PLAY(gen_cc_tx_invalid_cc_bare_new_event_badge_wrong_account);
el::Level level = (failed_tests.empty() ? el::Level::Info : el::Level::Error);
if (!list_tests)

View File

@ -1614,6 +1614,12 @@ class CCTest():
state['discoveries'] = res
res = daemon.cc_get_custom_items()
state['custom_items'] = res
for i in range(16):
try:
res = daemon.cc_get_badge(i)
state['badge_' + str(i)] = res
except:
pass
return state
def get_diff(self, state0, state1):
@ -1743,6 +1749,9 @@ class CCTest():
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_dividend(custom_item_id, 0, 100))
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_dividend(custom_item_id, ITEM_STONE, 16))
# new event badge
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_new_event_badge("Test badge for testing revert", "Event badge desc", [{"account_id": 4, "level": 2}]))
def test_distance_from_generator(self):
daemon = Daemon()

View File

@ -39,7 +39,7 @@ N_WALLETS = 4
WALLET_DIRECTORY = builddir + "/functional-tests-directory"
DIFFICULTY = 10
monerod_base = [builddir + "/bin/townforged", "--regtest", "--fixed-difficulty", str(DIFFICULTY), "--offline", "--no-igd", "--p2p-bind-port", "monerod_p2p_port", "--rpc-bind-port", "monerod_rpc_port", "--zmq-rpc-bind-port", "monerod_zmq_port", "--non-interactive", "--disable-dns-checkpoints", "--check-updates", "disabled", "--rpc-ssl", "disabled", "--log-level", "1"]
monerod_base = [builddir + "/bin/townforged", "--regtest", "--fixed-difficulty", str(DIFFICULTY), "--offline", "--no-igd", "--p2p-bind-port", "monerod_p2p_port", "--rpc-bind-port", "monerod_rpc_port", "--zmq-rpc-bind-port", "monerod_zmq_port", "--non-interactive", "--disable-dns-checkpoints", "--check-updates", "disabled", "--rpc-ssl", "disabled", "--log-level", "1", "--debug-allow-gm-commands-from-account", "7"]
monerod_extra = [
[],
["--rpc-payment-address", "CC1MM9BNc8w9fXr3hMfuj4zAcW2uwkRXmL8JmC8kusgfaxoKAzc3dWJvP3wV6q8sCR6PDUTu2u2c3vK4Pekw1A2urHw4KFzeZ2n", "--rpc-payment-difficulty", str(DIFFICULTY), "--rpc-payment-credits", "5000", "--data-dir", builddir + "/functional-tests-directory/townforged1"],

View File

@ -2475,6 +2475,10 @@ TEST(cc, type_tags)
ASSERT_EQ(get_cc_tag<uint8_t>(cmd), 0x12);
cmd = cryptonote::cc_command_dividend_t();
ASSERT_EQ(get_cc_tag<uint8_t>(cmd), 0x13);
cmd = cryptonote::cc_command_ignore_t();
ASSERT_EQ(get_cc_tag<uint8_t>(cmd), 0x14);
cmd = cryptonote::cc_command_new_event_badge_t();
ASSERT_EQ(get_cc_tag<uint8_t>(cmd), 0x15);
}
TEST(cc, staff)

View File

@ -880,3 +880,25 @@ class Daemon(object):
'id': '0'
}
return self.rpc.send_json_rpc_request(cc_get_custom_items)
def cc_get_badge(self, id):
cc_get_badge = {
'method': 'cc_get_badge',
'params': {
'id': id,
},
'jsonrpc': '2.0',
'id': '0'
}
return self.rpc.send_json_rpc_request(cc_get_badge)
def cc_get_badge_totals(self, id):
cc_get_badge_totals = {
'method': 'cc_get_badge_totals',
'params': {
'id': id,
},
'jsonrpc': '2.0',
'id': '0'
}
return self.rpc.send_json_rpc_request(cc_get_badge_totals)

View File

@ -1451,3 +1451,20 @@ class Wallet(object):
'id': '0'
}
return self.rpc.send_json_rpc_request(cc_ignore)
def cc_new_event_badge(self, name, description, instances, priority = 0, do_not_relay = False, get_tx_hex = False, get_tx_metadata = False):
cc_new_event_badge = {
'method': 'cc_new_event_badge',
'params': {
'name': name,
'description': description,
'instances': instances,
'priority': priority,
'do_not_relay': do_not_relay,
'get_tx_hex': get_tx_hex,
'get_tx_metadata': get_tx_metadata,
},
'jsonrpc': '2.0',
'id': '0'
}
return self.rpc.send_json_rpc_request(cc_new_event_badge)