forked from townforge/townforge
buying blocks in game
This commit is contained in:
parent
43ce9e2471
commit
822d3796a1
@ -44,21 +44,44 @@ void cc_command_handler_buy_blocks::get_in_out(const cryptonote::cc_command_t &c
|
||||
uint64_t cc_command_handler_buy_blocks::get_cost(const cryptonote::cc_command_t &cmd) const
|
||||
{
|
||||
const cryptonote::cc_command_buy_blocks_t &buy_blocks = boost::get<cryptonote::cc_command_buy_blocks_t>(cmd);
|
||||
return last_resort_block_cost[buy_blocks.type] * buy_blocks.amount;
|
||||
uint64_t cost = 0;
|
||||
for (const auto &e: buy_blocks.entries)
|
||||
{
|
||||
uint64_t entry_cost = last_resort_block_cost[e.type] * e.amount;
|
||||
if (entry_cost > std::numeric_limits<uint64_t>::max() - cost)
|
||||
{
|
||||
MERROR("buy_blocks command cost overflow");
|
||||
return std::numeric_limits<uint64_t>::max();
|
||||
}
|
||||
cost += entry_cost;
|
||||
}
|
||||
return cost;
|
||||
}
|
||||
|
||||
bool cc_command_handler_buy_blocks::check(const cryptonote::BlockchainDB &db, const cryptonote::cc_command_t &cmd, uint32_t cc_account) const
|
||||
{
|
||||
const cryptonote::cc_command_buy_blocks_t &buy_blocks = boost::get<cryptonote::cc_command_buy_blocks_t>(cmd);
|
||||
CHECK_AND_ASSERT_MES(buy_blocks.type != 0, false, "Buy order for block type 0");
|
||||
CHECK_AND_ASSERT_MES(buy_blocks.amount > 0, false, "Buy order for 0 blocks");
|
||||
CHECK_AND_ASSERT_MES(last_resort_block_cost[buy_blocks.type] > 0, false, "Trying to buy unallocated block type " + std::to_string(buy_blocks.type));
|
||||
for (const auto &e: buy_blocks.entries)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(e.type != 0, false, "Buy order for block type 0");
|
||||
CHECK_AND_ASSERT_MES(e.amount > 0, false, "Buy order for 0 blocks");
|
||||
CHECK_AND_ASSERT_MES(last_resort_block_cost[e.type] > 0, false, "Trying to buy unallocated block type " + std::to_string(e.type));
|
||||
}
|
||||
bool present[256] = {false};
|
||||
for (const auto &e: buy_blocks.entries)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(!present[e.type], false, "Buy order for the same block more than once");
|
||||
present[e.type] = true;
|
||||
}
|
||||
crypto::public_key public_key;
|
||||
uint64_t balance;
|
||||
uint32_t block_balances[256];
|
||||
std::vector<uint32_t> flags;
|
||||
CHECK_AND_ASSERT_MES(db.get_cc_account_data(cc_account, public_key, balance, block_balances, flags), false, "Failed to get account data");
|
||||
CHECK_AND_ASSERT_MES(block_balances[buy_blocks.type] <= std::numeric_limits<uint32_t>::max() - buy_blocks.amount, false, "Balance would overflow");
|
||||
for (const auto &e: buy_blocks.entries)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(block_balances[e.type] <= std::numeric_limits<uint32_t>::max() - e.amount, false, "Balance would overflow");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -72,11 +95,16 @@ bool cc_command_handler_buy_blocks::execute(cryptonote::BlockchainDB &db, const
|
||||
uint32_t treasury;
|
||||
uint64_t cost;
|
||||
|
||||
cost = last_resort_block_cost[buy_blocks.type] * buy_blocks.amount;
|
||||
cost = 0;
|
||||
for (const auto &e: buy_blocks.entries)
|
||||
cost += last_resort_block_cost[e.type] * e.amount;
|
||||
|
||||
CHECK_AND_ASSERT_MES(db.get_cc_account_data(cc_account, public_key, balance, block_balances, flags), false, "Failed to get account data");
|
||||
CHECK_AND_ASSERT_MES(block_balances[buy_blocks.type] <= std::numeric_limits<uint32_t>::max() - buy_blocks.amount, false, "Balance would overflow");
|
||||
block_balances[buy_blocks.type] += buy_blocks.amount;
|
||||
for (const auto &e: buy_blocks.entries)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(block_balances[e.type] <= std::numeric_limits<uint32_t>::max() - e.amount, false, "Balance would overflow");
|
||||
block_balances[e.type] += e.amount;
|
||||
}
|
||||
db.set_cc_account_block_balances(cc_account, block_balances);
|
||||
balance -= cost;
|
||||
db.set_cc_account_balance(cc_account, balance);
|
||||
@ -99,11 +127,16 @@ bool cc_command_handler_buy_blocks::revert(cryptonote::BlockchainDB &db, const c
|
||||
uint32_t treasury;
|
||||
uint64_t cost;
|
||||
|
||||
cost = last_resort_block_cost[buy_blocks.type] * buy_blocks.amount;
|
||||
cost = 0;
|
||||
for (const auto &e: buy_blocks.entries)
|
||||
cost += last_resort_block_cost[e.type] * e.amount;
|
||||
|
||||
CHECK_AND_ASSERT_MES(db.get_cc_account_data(cc_account, public_key, balance, block_balances, flags), false, "Failed to get account data");
|
||||
CHECK_AND_ASSERT_MES(block_balances[buy_blocks.type] >= buy_blocks.amount, false, "Balance would underflow");
|
||||
block_balances[buy_blocks.type] -= buy_blocks.amount;
|
||||
for (const auto &e: buy_blocks.entries)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(block_balances[e.type] >= e.amount, false, "Balance would underflow");
|
||||
block_balances[e.type] -= e.amount;
|
||||
}
|
||||
db.set_cc_account_block_balances(cc_account, block_balances);
|
||||
|
||||
CHECK_AND_ASSERT_MES(cost <= std::numeric_limits<uint64_t>::max() - balance, false, "Balance would overflow");
|
||||
|
@ -113,12 +113,21 @@ namespace cryptonote
|
||||
|
||||
struct cc_command_buy_blocks_t
|
||||
{
|
||||
uint8_t type;
|
||||
uint32_t amount;
|
||||
struct entry_t
|
||||
{
|
||||
uint8_t type;
|
||||
uint32_t amount;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(type)
|
||||
VARINT_FIELD(amount);
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
std::vector<entry_t> entries;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(type)
|
||||
VARINT_FIELD(amount)
|
||||
FIELD(entries)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
|
@ -34,6 +34,7 @@ set(game_sources
|
||||
game-state.cc
|
||||
shadable-window.cc
|
||||
shade-button.cc
|
||||
ui-buyblocks.cc
|
||||
ui-notifier.cc
|
||||
ui-urho3d.cc)
|
||||
|
||||
@ -45,6 +46,7 @@ set(game_headers
|
||||
quadtree.h
|
||||
shadable-window.h
|
||||
shade-button.h
|
||||
ui-buyblocks.h
|
||||
ui-notifier.h
|
||||
ui-urho3d.h)
|
||||
|
||||
|
@ -31,6 +31,7 @@ void PlayerState::update(const std::shared_ptr<tools::wallet2> &w)
|
||||
else
|
||||
{
|
||||
*this = PlayerState();
|
||||
has_wallet = true;
|
||||
// continue to fill up what we can
|
||||
}
|
||||
wallet_balance = w->balance(0);
|
||||
|
@ -533,18 +533,21 @@ bool GameWalletInternal::deposit(uint64_t amount, bool confirmed)
|
||||
tools::wallet_keys_unlocker unlocker(*w, tools::password_container(password));
|
||||
uint32_t fake_outs_count = w->adjust_mixin(0);
|
||||
|
||||
std::vector<tools::wallet2::pending_tx> ptx_vector = w->create_transactions_2(dsts, boost::none, cc_dest, fake_outs_count, 0 /* unlock_time */, priority, {}, 0, {});
|
||||
if (ptx_vector.size() > 1)
|
||||
try
|
||||
{
|
||||
new MessageBox(context_, "More than one transaction is needed. CC deposit/withdrawal should be one transaction only. Consolidate your outputs first by sending to yourself.");
|
||||
return false;
|
||||
std::vector<tools::wallet2::pending_tx> ptx_vector = w->create_transactions_2(dsts, boost::none, cc_dest, fake_outs_count, 0 /* unlock_time */, priority, {}, 0, {});
|
||||
if (ptx_vector.size() > 1)
|
||||
{
|
||||
new MessageBox(context_, "More than one transaction is needed. CC deposit/withdrawal should be one transaction only. Consolidate your outputs first by sending to yourself.");
|
||||
return false;
|
||||
}
|
||||
if (ptx_vector.empty())
|
||||
{
|
||||
new MessageBox(context_, "No outputs found, or daemon is not ready");
|
||||
return false;
|
||||
}
|
||||
w->commit_tx(ptx_vector);
|
||||
}
|
||||
if (ptx_vector.empty())
|
||||
{
|
||||
new MessageBox(context_, "No outputs found, or daemon is not ready");
|
||||
return false;
|
||||
}
|
||||
try { w->commit_tx(ptx_vector); }
|
||||
catch (const std::exception &e) { new MessageBox(context_, String("Error creation transaction: ") + e.what()); return false; }
|
||||
return true;
|
||||
}
|
||||
|
@ -91,6 +91,7 @@ public:
|
||||
void HandleDeposit(StringHash eventType, VariantMap& eventData);
|
||||
void HandleWithdraw(StringHash eventType, VariantMap& eventData);
|
||||
void HandleBuy(StringHash eventType, VariantMap& eventData);
|
||||
void HandleBuyBlocks(StringHash eventType, VariantMap& eventData);
|
||||
void HandleAddBlock(StringHash eventType, VariantMap& eventData);
|
||||
void HandleRemoveBlock(StringHash eventType, VariantMap& eventData);
|
||||
void HandleApproveBuild(StringHash eventType, VariantMap& eventData);
|
||||
@ -343,6 +344,7 @@ void CryptoCityUrho3D::SetupUI()
|
||||
SubscribeToEvent(ui, E_CRYPTOCITY_DEPOSIT, URHO3D_HANDLER(CryptoCityUrho3D, HandleDeposit));
|
||||
SubscribeToEvent(ui, E_CRYPTOCITY_WITHDRAW, URHO3D_HANDLER(CryptoCityUrho3D, HandleWithdraw));
|
||||
SubscribeToEvent(ui, E_CRYPTOCITY_BUY, URHO3D_HANDLER(CryptoCityUrho3D, HandleBuy));
|
||||
SubscribeToEvent(ui, E_CRYPTOCITY_BUY_BLOCKS, URHO3D_HANDLER(CryptoCityUrho3D, HandleBuyBlocks));
|
||||
SubscribeToEvent(ui, E_CRYPTOCITY_ADD_BLOCK, URHO3D_HANDLER(CryptoCityUrho3D, HandleAddBlock));
|
||||
SubscribeToEvent(ui, E_CRYPTOCITY_REMOVE_BLOCK, URHO3D_HANDLER(CryptoCityUrho3D, HandleRemoveBlock));
|
||||
SubscribeToEvent(ui, E_CRYPTOCITY_APPROVE_BUILD, URHO3D_HANDLER(CryptoCityUrho3D, HandleApproveBuild));
|
||||
@ -841,6 +843,25 @@ void CryptoCityUrho3D::HandleBuy(StringHash eventType, VariantMap& eventData)
|
||||
wallet->send_command(cmd);
|
||||
}
|
||||
|
||||
void CryptoCityUrho3D::HandleBuyBlocks(StringHash eventType, VariantMap& eventData)
|
||||
{
|
||||
if (!wallet || !wallet->wallet())
|
||||
{
|
||||
new MessageBox(context_, "No wallet loaded - load a wallet to be able to buy blocks");
|
||||
return;
|
||||
}
|
||||
cryptonote::cc_command_buy_blocks_t cmd;
|
||||
const std::vector<std::pair<uint8_t, uint32_t>> *v = (const std::vector<std::pair<uint8_t, uint32_t>>*)eventData[BuyBlocks::P_QUANTITIES].GetVoidPtr();
|
||||
for (const auto &q: *v)
|
||||
{
|
||||
cryptonote::cc_command_buy_blocks_t::entry_t e;
|
||||
e.type = q.first;
|
||||
e.amount = q.second;
|
||||
cmd.entries.push_back(e);
|
||||
}
|
||||
wallet->send_command(cmd);
|
||||
}
|
||||
|
||||
void CryptoCityUrho3D::HandleAddBlock(StringHash eventType, VariantMap& eventData)
|
||||
{
|
||||
UnsetFocus();
|
||||
|
@ -37,16 +37,6 @@ BlockMaterial materials[256] =
|
||||
},
|
||||
{
|
||||
2,
|
||||
"water",
|
||||
64, 64, 192, 1,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
4,
|
||||
1,
|
||||
},
|
||||
{
|
||||
3,
|
||||
"wood",
|
||||
60, 40, 10, 1,
|
||||
1,
|
||||
@ -55,6 +45,16 @@ BlockMaterial materials[256] =
|
||||
1,
|
||||
4,
|
||||
},
|
||||
{
|
||||
3,
|
||||
"water",
|
||||
64, 64, 192, 1,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
4,
|
||||
1,
|
||||
},
|
||||
};
|
||||
|
||||
bool encode_single_type(uint8_t src_type, uint16_t n_src_types, uint8_t *encoded_types, uint16_t *encoded_types_len)
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define CRYPTO_CITY_TYPES_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <set>
|
||||
#include <Urho3D/Container/RefCounted.h>
|
||||
|
231
src/game/ui-buyblocks.cc
Normal file
231
src/game/ui-buyblocks.cc
Normal file
@ -0,0 +1,231 @@
|
||||
#include <limits.h>
|
||||
#include <limits>
|
||||
#include "Urho3D/Core/Context.h"
|
||||
#include "Urho3D/Resource/ResourceCache.h"
|
||||
#include "Urho3D/UI/UI.h"
|
||||
#include "Urho3D/UI/UIEvents.h"
|
||||
#include "Urho3D/UI/Window.h"
|
||||
#include "Urho3D/UI/DropDownList.h"
|
||||
#include "Urho3D/UI/LineEdit.h"
|
||||
#include "Urho3D/UI/Text.h"
|
||||
#include "Urho3D/UI/Button.h"
|
||||
#include "Urho3D/UI/MessageBox.h"
|
||||
#include "Urho3D/UI/ListView.h"
|
||||
#include "game/map.h"
|
||||
#include "ui-buyblocks.h"
|
||||
|
||||
using namespace Urho3D;
|
||||
|
||||
UIBuyBlocksDialog::UIBuyBlocksDialog(Context *ctx):
|
||||
Object(ctx)
|
||||
{
|
||||
auto root = ctx->GetSubsystem<UI>()->GetRoot();
|
||||
auto* cache = ctx->GetSubsystem<ResourceCache>();
|
||||
auto* style = cache->GetResource<XMLFile>("UI/DefaultStyle.xml");
|
||||
root->SetDefaultStyle(style);
|
||||
|
||||
window = root->CreateChild<Window>();
|
||||
window->SetName("UIBuyBlocksDialog");
|
||||
window->SetMinWidth(280);
|
||||
window->SetLayout(LM_VERTICAL, 6, IntRect(6, 6, 6, 6));
|
||||
window->SetAlignment(HA_CENTER, VA_CENTER);
|
||||
window->SetStyleAuto(style);
|
||||
|
||||
// Create Window 'titlebar' container
|
||||
auto* titleBar = new UIElement(context_);
|
||||
titleBar->SetMinSize(0, 24);
|
||||
titleBar->SetVerticalAlignment(VA_TOP);
|
||||
titleBar->SetLayoutMode(LM_HORIZONTAL);
|
||||
|
||||
// Create the Window title Text
|
||||
auto *windowTitle_ = new Text(context_);
|
||||
windowTitle_->SetName("WindowTitle");
|
||||
windowTitle_->SetText("Select blocks to buy:");
|
||||
windowTitle_->SetStyleAuto(style);
|
||||
|
||||
// Create the Window's close button
|
||||
auto* buttonClose = new Button(context_);
|
||||
buttonClose->SetName("CloseButton");
|
||||
buttonClose->SetStyle("CloseButton");
|
||||
|
||||
// Add the controls to the title bar
|
||||
titleBar->AddChild(windowTitle_);
|
||||
titleBar->AddChild(buttonClose);
|
||||
|
||||
// Add the title bar to the Window
|
||||
window->AddChild(titleBar);
|
||||
|
||||
// contents
|
||||
column = new UIElement(ctx);
|
||||
column->SetLayout(LM_VERTICAL, 6, IntRect(0, 0, 0, 0));
|
||||
column->SetStyleAuto(style);
|
||||
window->AddChild(column);
|
||||
|
||||
// + button
|
||||
UIElement *AddRowLayout = new UIElement(ctx);
|
||||
AddRowLayout->SetStyleAuto(style);
|
||||
AddRowLayout->SetLayout(LM_HORIZONTAL, 6, IntRect(0, 0, 0, 0));
|
||||
column->AddChild(AddRowLayout);
|
||||
auto* buttonAddRow = new Button(context_);
|
||||
buttonAddRow->SetName("AddRow");
|
||||
buttonAddRow->SetMinHeight(24);
|
||||
buttonAddRow->SetMinWidth(48);
|
||||
buttonAddRow->SetStyleAuto(style);
|
||||
Text *textAddRow = new Text(context_);
|
||||
textAddRow->SetText(" + ");
|
||||
textAddRow->SetAlignment(HA_CENTER, VA_CENTER);
|
||||
textAddRow->SetStyleAuto(style);
|
||||
buttonAddRow->AddChild(textAddRow);
|
||||
AddRowLayout->AddChild(buttonAddRow);
|
||||
|
||||
AddRow();
|
||||
|
||||
// OK/cancel buttons
|
||||
auto* horiz = new UIElement(context_);
|
||||
horiz->SetLayout(LM_HORIZONTAL, 6, IntRect(0, 6, 0, 0));
|
||||
window->AddChild(horiz);
|
||||
|
||||
// OK
|
||||
auto* buttonOK = new Button(context_);
|
||||
buttonOK->SetName("OK");
|
||||
buttonOK->SetMinHeight(24);
|
||||
buttonOK->SetStyleAuto(style);
|
||||
horiz->AddChild(buttonOK);
|
||||
Text *textOK = new Text(context_);
|
||||
textOK->SetText("OK");
|
||||
textOK->SetAlignment(HA_CENTER, VA_CENTER);
|
||||
textOK->SetStyleAuto(style);
|
||||
buttonOK->AddChild(textOK);
|
||||
|
||||
// Cancel
|
||||
auto* buttonCancel = new Button(context_);
|
||||
buttonCancel->SetName("Cancel");
|
||||
buttonCancel->SetMinHeight(24);
|
||||
buttonCancel->SetStyleAuto(style);
|
||||
horiz->AddChild(buttonCancel);
|
||||
Text *textCancel = new Text(context_);
|
||||
textCancel->SetText("Cancel");
|
||||
textCancel->SetAlignment(HA_CENTER, VA_CENTER);
|
||||
textCancel->SetStyleAuto(style);
|
||||
buttonCancel->AddChild(textCancel);
|
||||
|
||||
//const IntVector2 size = window->GetSize();
|
||||
window->SetPosition(0, 0);
|
||||
window->SetModal(true);
|
||||
|
||||
buttonClose->SetStyle("CloseButton");
|
||||
|
||||
SubscribeToEvent(window, E_MODALCHANGED, URHO3D_HANDLER(UIBuyBlocksDialog, HandleCancel));
|
||||
SubscribeToEvent(buttonAddRow, E_RELEASED, URHO3D_HANDLER(UIBuyBlocksDialog, HandleAddRow));
|
||||
SubscribeToEvent(buttonOK, E_RELEASED, URHO3D_HANDLER(UIBuyBlocksDialog, HandleOK));
|
||||
SubscribeToEvent(buttonCancel, E_RELEASED, URHO3D_HANDLER(UIBuyBlocksDialog, HandleCancel));
|
||||
SubscribeToEvent(buttonClose, E_RELEASED, URHO3D_HANDLER(UIBuyBlocksDialog, HandleCancel));
|
||||
|
||||
AddRef();
|
||||
}
|
||||
|
||||
UIBuyBlocksDialog::~UIBuyBlocksDialog()
|
||||
{
|
||||
if (window)
|
||||
window->Remove();
|
||||
}
|
||||
|
||||
void UIBuyBlocksDialog::RegisterObject(Context* context)
|
||||
{
|
||||
context->RegisterFactory<UIBuyBlocksDialog>();
|
||||
}
|
||||
|
||||
void UIBuyBlocksDialog::AddRow()
|
||||
{
|
||||
auto* cache = context_->GetSubsystem<ResourceCache>();
|
||||
auto* style = cache->GetResource<XMLFile>("UI/DefaultStyle.xml");
|
||||
|
||||
auto *row = new UIElement(context_);
|
||||
row->SetStyleAuto(style);
|
||||
row->SetMinHeight(20);
|
||||
row->SetLayout(LM_HORIZONTAL, 6, IntRect(0, 0, 0, 0));
|
||||
column->InsertChild(typeWidgets.size(), row);
|
||||
|
||||
SharedPtr<DropDownList> typeWidget(new DropDownList(context_));
|
||||
typeWidget->SetName("MaterialDropDown");
|
||||
typeWidget->SetResizePopup(true);
|
||||
|
||||
// fill list
|
||||
unsigned int idx = 0;
|
||||
for (int i = 1; i < 256; ++i)
|
||||
{
|
||||
const BlockMaterial &m = materials[i];
|
||||
if (!m.name)
|
||||
continue;
|
||||
types[idx++] = i;
|
||||
Text *t = new Text(context_);
|
||||
t->SetText(m.name);
|
||||
t->SetStyleAuto(style);
|
||||
typeWidget->AddItem(t);
|
||||
}
|
||||
|
||||
row->AddChild(typeWidget);
|
||||
typeWidget->SetStyleAuto(style);
|
||||
|
||||
SharedPtr<LineEdit> amountWidget(new LineEdit(context_));
|
||||
amountWidget->SetStyleAuto(style);
|
||||
amountWidget->SetText("0");
|
||||
row->AddChild(amountWidget);
|
||||
|
||||
typeWidget->SetSelection(0);
|
||||
|
||||
typeWidgets.push_back(std::move(typeWidget));
|
||||
amountWidgets.push_back(std::move(amountWidget));
|
||||
}
|
||||
|
||||
void UIBuyBlocksDialog::HandleOK(StringHash eventType, VariantMap& eventData)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint32_t>> quantities;
|
||||
|
||||
for (size_t i = 0; i < typeWidgets.size(); ++i)
|
||||
{
|
||||
unsigned sel = typeWidgets[i]->GetSelection();
|
||||
if (sel >= 256)
|
||||
{
|
||||
new MessageBox(context_, "Internal error: bad item index");
|
||||
return;
|
||||
}
|
||||
char *endptr = NULL;
|
||||
errno = 0;
|
||||
unsigned long ul = strtoul(amountWidgets[i]->GetText().CString(), &endptr, 10);
|
||||
if ((endptr && *endptr) || (ul == ULONG_MAX && errno) || ul > std::numeric_limits<uint32_t>::max())
|
||||
{
|
||||
new MessageBox(context_, "Invalid amount");
|
||||
return;
|
||||
}
|
||||
const uint8_t sel8 = types[sel];
|
||||
if (sel8 == 0 || !materials[sel8].name)
|
||||
{
|
||||
new MessageBox(context_, "Internal error: bad item");
|
||||
return;
|
||||
}
|
||||
const uint32_t amount = ul;
|
||||
quantities.push_back(std::make_pair(sel8, amount));
|
||||
}
|
||||
|
||||
VariantMap& newEventData = GetEventDataMap();
|
||||
newEventData[BuyBlocksOkayed::P_QUANTITIES] = &quantities;
|
||||
SendEvent(E_BUY_BLOCKS_OKAYED, newEventData);
|
||||
|
||||
// Self destruct
|
||||
ReleaseRef();
|
||||
}
|
||||
|
||||
void UIBuyBlocksDialog::HandleAddRow(StringHash eventType, VariantMap& eventData)
|
||||
{
|
||||
AddRow();
|
||||
}
|
||||
|
||||
void UIBuyBlocksDialog::HandleCancel(StringHash eventType, VariantMap& eventData)
|
||||
{
|
||||
VariantMap& newEventData = GetEventDataMap();
|
||||
SendEvent(E_BUY_BLOCKS_CANCELLED, newEventData);
|
||||
|
||||
// Self destruct
|
||||
ReleaseRef();
|
||||
}
|
45
src/game/ui-buyblocks.h
Normal file
45
src/game/ui-buyblocks.h
Normal file
@ -0,0 +1,45 @@
|
||||
#ifndef UI_BUY_BLOCKS_H
|
||||
#define UI_BUY_BLOCKS_H
|
||||
|
||||
#include <vector>
|
||||
#include <Urho3D/Core/Object.h>
|
||||
#include <Urho3D/Container/Str.h>
|
||||
#include <Urho3D/Container/Ptr.h>
|
||||
#include <Urho3D/Math/StringHash.h>
|
||||
|
||||
namespace Urho3D
|
||||
{
|
||||
class Context;
|
||||
class Window;
|
||||
class DropDownList;
|
||||
class LineEdit;
|
||||
}
|
||||
|
||||
URHO3D_EVENT(E_BUY_BLOCKS_OKAYED, BuyBlocksOkayed) { URHO3D_PARAM(P_QUANTITIES, Quantities); }
|
||||
URHO3D_EVENT(E_BUY_BLOCKS_CANCELLED, BuyBlocksCancelled) {}
|
||||
|
||||
class UIBuyBlocksDialog: public Urho3D::Object
|
||||
{
|
||||
URHO3D_OBJECT(UIBuyBlocksDialog, Object);
|
||||
|
||||
public:
|
||||
UIBuyBlocksDialog(Urho3D::Context *ctx);
|
||||
virtual ~UIBuyBlocksDialog() override;
|
||||
|
||||
static void RegisterObject(Urho3D::Context* context);
|
||||
|
||||
private:
|
||||
void AddRow();
|
||||
void HandleAddRow(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
|
||||
void HandleOK(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
|
||||
void HandleCancel(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
|
||||
|
||||
private:
|
||||
Urho3D::SharedPtr<Urho3D::Window> window;
|
||||
Urho3D::SharedPtr<Urho3D::UIElement> column;
|
||||
std::vector<Urho3D::SharedPtr<Urho3D::DropDownList>> typeWidgets;
|
||||
std::vector<Urho3D::SharedPtr<Urho3D::LineEdit>> amountWidgets;
|
||||
uint8_t types[256];
|
||||
};
|
||||
|
||||
#endif
|
@ -4,6 +4,7 @@
|
||||
#include <Urho3D/UI/UIEvents.h>
|
||||
#include <Urho3D/Graphics/Graphics.h>
|
||||
#include "cryptonote_basic/cryptonote_format_utils.h"
|
||||
#include "ui-buyblocks.h"
|
||||
#include "cc/cc.h"
|
||||
#include "ui-urho3d.h"
|
||||
|
||||
@ -327,12 +328,14 @@ void UIUrho3D::CreateActionsWindow()
|
||||
Button *removeBlockButton = AddButton(w, "Remove block");
|
||||
Button *approveBuildButton = AddButton(w, "Approve build");
|
||||
Button *abandonBuildButton = AddButton(w, "Abandon build");
|
||||
Button *buyBlocksButton = AddButton(w, "Buy blocks");
|
||||
|
||||
SubscribeToEvent(buyButton, E_RELEASED, URHO3D_HANDLER(UIUrho3D, HandleBuy));
|
||||
SubscribeToEvent(addBlockButton, E_RELEASED, URHO3D_HANDLER(UIUrho3D, HandleAddBlock));
|
||||
SubscribeToEvent(removeBlockButton, E_RELEASED, URHO3D_HANDLER(UIUrho3D, HandleRemoveBlock));
|
||||
SubscribeToEvent(approveBuildButton, E_RELEASED, URHO3D_HANDLER(UIUrho3D, HandleApproveBuild));
|
||||
SubscribeToEvent(abandonBuildButton, E_RELEASED, URHO3D_HANDLER(UIUrho3D, HandleAbandonBuild));
|
||||
SubscribeToEvent(buyBlocksButton, E_RELEASED, URHO3D_HANDLER(UIUrho3D, HandleBuyBlocks));
|
||||
|
||||
actionsWindow->SetPosition(0, selectionWindow->GetHeight() + playerWindow->GetHeight() + displayWindow->GetHeight());
|
||||
}
|
||||
@ -528,6 +531,14 @@ void UIUrho3D::HandleAbandonBuild(StringHash eventType, VariantMap& eventData)
|
||||
SendEvent(E_CRYPTOCITY_ABANDON_BUILD, noEventData);
|
||||
}
|
||||
|
||||
void UIUrho3D::HandleBuyBlocks(StringHash eventType, VariantMap& eventData)
|
||||
{
|
||||
auto *d = new UIBuyBlocksDialog(context_);
|
||||
SubscribeToEvent(d, E_BUY_BLOCKS_OKAYED, [this](StringHash eventType, VariantMap& eventData) {
|
||||
SendEvent(E_CRYPTOCITY_BUY_BLOCKS, eventData);
|
||||
});
|
||||
}
|
||||
|
||||
void UIUrho3D::HandleDisplayNormal(StringHash eventType, VariantMap& eventData)
|
||||
{
|
||||
VariantMap noEventData;
|
||||
|
@ -18,6 +18,7 @@ URHO3D_EVENT(E_CRYPTOCITY_LOAD_WALLET, LoadWallet) {}
|
||||
URHO3D_EVENT(E_CRYPTOCITY_DEPOSIT, Deposit) { URHO3D_PARAM(P_AMOUNT, Amount); /*, uint64_t */ }
|
||||
URHO3D_EVENT(E_CRYPTOCITY_WITHDRAW, Withdraw) { URHO3D_PARAM(P_AMOUNT, Amount); /* uint64_t */ }
|
||||
URHO3D_EVENT(E_CRYPTOCITY_BUY, Buy) {}
|
||||
URHO3D_EVENT(E_CRYPTOCITY_BUY_BLOCKS, BuyBlocks) { URHO3D_PARAM(P_QUANTITIES, Quantities); /* vector */ }
|
||||
URHO3D_EVENT(E_CRYPTOCITY_ADD_BLOCK, AddBlock) {}
|
||||
URHO3D_EVENT(E_CRYPTOCITY_REMOVE_BLOCK, RemoveBlock) {}
|
||||
URHO3D_EVENT(E_CRYPTOCITY_APPROVE_BUILD, ApproveBuild) {}
|
||||
@ -58,6 +59,7 @@ private:
|
||||
void HandleRemoveBlock(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
|
||||
void HandleApproveBuild(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
|
||||
void HandleAbandonBuild(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
|
||||
void HandleBuyBlocks(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
|
||||
void HandleDisplayNormal(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
|
||||
void HandleDisplayLand(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
|
||||
void HandleMaterialSelected(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
|
||||
|
@ -2652,8 +2652,10 @@ bool simple_wallet::cc_buy_blocks(const std::vector<std::string> &args_)
|
||||
message_writer() << tr("Price per block: ") << cryptonote::print_money(last_resort_block_cost[type]);
|
||||
|
||||
cryptonote::cc_command_buy_blocks_t cmd;
|
||||
cmd.type = type;
|
||||
cmd.amount = amount;
|
||||
cryptonote::cc_command_buy_blocks_t::entry_t e;
|
||||
e.type = type;
|
||||
e.amount = amount;
|
||||
cmd.entries.push_back(e);
|
||||
|
||||
return send_command(cmd);
|
||||
}
|
||||
|
@ -4240,8 +4240,10 @@ namespace tools
|
||||
try
|
||||
{
|
||||
cryptonote::cc_command_buy_blocks_t cmd;
|
||||
cmd.type = req.type;
|
||||
cmd.amount = req.amount;
|
||||
cryptonote::cc_command_buy_blocks_t::entry_t e;
|
||||
e.type = req.type;
|
||||
e.amount = req.amount;
|
||||
cmd.entries.push_back(e);
|
||||
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())
|
||||
|
@ -441,19 +441,21 @@ bool gen_cc_tx_validation_base::generate_with(std::vector<test_event_entry>& eve
|
||||
events.push_back(tx);
|
||||
txs_hashes.push_back(get_transaction_hash(tx));
|
||||
|
||||
cryptonote::cc_command_buy_blocks_t buy_blocks;
|
||||
for (int i = 1; i <= 2; ++i)
|
||||
{
|
||||
cryptonote::cc_command_buy_blocks_t buy_blocks;
|
||||
buy_blocks.type = i;
|
||||
buy_blocks.amount = 20 - 10 * (i-1);
|
||||
fee = BARE_TX_FEE;
|
||||
expected_balance[cc_account - 4] -= last_resort_block_cost[buy_blocks.type] * buy_blocks.amount + fee;
|
||||
expected_treasury_balance += last_resort_block_cost[buy_blocks.type] * buy_blocks.amount;
|
||||
r = construct_bare_tx(sending_account.get_keys(), cc_account, buy_blocks, fee, tx);
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction");
|
||||
events.push_back(tx);
|
||||
txs_hashes.push_back(get_transaction_hash(tx));
|
||||
cryptonote::cc_command_buy_blocks_t::entry_t e;
|
||||
e.type = i;
|
||||
e.amount = 20 - 10 * (i-1);
|
||||
buy_blocks.entries.push_back(e);
|
||||
expected_balance[cc_account - 4] -= last_resort_block_cost[e.type] * e.amount + fee;
|
||||
expected_treasury_balance += last_resort_block_cost[e.type] * e.amount;
|
||||
}
|
||||
fee = BARE_TX_FEE;
|
||||
r = construct_bare_tx(sending_account.get_keys(), cc_account, buy_blocks, fee, tx);
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction");
|
||||
events.push_back(tx);
|
||||
txs_hashes.push_back(get_transaction_hash(tx));
|
||||
|
||||
cryptonote::block blk;
|
||||
CHECK_AND_ASSERT_MES(generator.construct_block_manually(blk, blk_last, miner_account,
|
||||
@ -1337,19 +1339,23 @@ bool gen_cc_tx_valid_cc_bare_buy_blocks::generate(std::vector<test_event_entry>&
|
||||
blocks_cost = 0;
|
||||
|
||||
cryptonote::cc_command_buy_blocks_t cmd;
|
||||
cmd.type = 1;
|
||||
cmd.amount = 80;
|
||||
blocks_cost += last_resort_block_cost[cmd.type] * cmd.amount;
|
||||
cryptonote::cc_command_buy_blocks_t::entry_t e;
|
||||
e.type = 1;
|
||||
e.amount = 80;
|
||||
cmd.entries.push_back(e);
|
||||
blocks_cost += last_resort_block_cost[e.type] * e.amount;
|
||||
cmds.push_back(std::make_tuple(4, "", cmd, BARE_TX_FEE));
|
||||
|
||||
cmd.type = 2;
|
||||
cmd.amount = 180;
|
||||
blocks_cost += last_resort_block_cost[cmd.type] * cmd.amount;
|
||||
e.type = 2;
|
||||
e.amount = 180;
|
||||
cmd.entries[0] = e;
|
||||
blocks_cost += last_resort_block_cost[e.type] * e.amount;
|
||||
cmds.push_back(std::make_tuple(4, "", cmd, BARE_TX_FEE));
|
||||
|
||||
cmd.type = 1;
|
||||
cmd.amount = 40;
|
||||
blocks_cost += last_resort_block_cost[cmd.type] * cmd.amount;
|
||||
e.type = 1;
|
||||
e.amount = 40;
|
||||
cmd.entries[0] = e;
|
||||
blocks_cost += last_resort_block_cost[e.type] * e.amount;
|
||||
cmds.push_back(std::make_tuple(4, "", cmd, BARE_TX_FEE));
|
||||
|
||||
return generate_with(events, boost::none, boost::none, prep_create_accounts, cmds.size(), mixin, amount_paid, true, cmds, false, valid, NULL, NULL);
|
||||
@ -1374,8 +1380,10 @@ bool gen_cc_tx_invalid_cc_bare_buy_blocks_type_0::generate(std::vector<test_even
|
||||
std::vector<std::tuple<uint32_t, std::string, cryptonote::cc_command_t, uint64_t>> cmds;
|
||||
|
||||
cryptonote::cc_command_buy_blocks_t cmd;
|
||||
cmd.type = 0;
|
||||
cmd.amount = 1;
|
||||
cryptonote::cc_command_buy_blocks_t::entry_t e;
|
||||
e.type = 0;
|
||||
e.amount = 1;
|
||||
cmd.entries.push_back(e);
|
||||
cmds.push_back(std::make_tuple(4, "", cmd, BARE_TX_FEE));
|
||||
|
||||
return generate_with(events, boost::none, boost::none, prep_create_accounts, cmds.size(), mixin, amount_paid, true, cmds, false, invalid, NULL, NULL);
|
||||
@ -1389,8 +1397,10 @@ bool gen_cc_tx_invalid_cc_bare_buy_blocks_amount_0::generate(std::vector<test_ev
|
||||
std::vector<std::tuple<uint32_t, std::string, cryptonote::cc_command_t, uint64_t>> cmds;
|
||||
|
||||
cryptonote::cc_command_buy_blocks_t cmd;
|
||||
cmd.type = 1;
|
||||
cmd.amount = 0;
|
||||
cryptonote::cc_command_buy_blocks_t::entry_t e;
|
||||
e.type = 1;
|
||||
e.amount = 0;
|
||||
cmd.entries.push_back(e);
|
||||
cmds.push_back(std::make_tuple(4, "", cmd, BARE_TX_FEE));
|
||||
|
||||
return generate_with(events, boost::none, boost::none, prep_create_accounts, cmds.size(), mixin, amount_paid, true, cmds, false, invalid, NULL, NULL);
|
||||
@ -1404,10 +1414,49 @@ bool gen_cc_tx_invalid_cc_bare_buy_blocks_balance_overflow::generate(std::vector
|
||||
std::vector<std::tuple<uint32_t, std::string, cryptonote::cc_command_t, uint64_t>> cmds;
|
||||
|
||||
cryptonote::cc_command_buy_blocks_t cmd;
|
||||
cmd.type = 1;
|
||||
cmd.amount = 0x1fffffff;
|
||||
cryptonote::cc_command_buy_blocks_t::entry_t e;
|
||||
e.type = 1;
|
||||
e.amount = 0x1fffffff;
|
||||
cmd.entries.push_back(e);
|
||||
cmds.push_back(std::make_tuple(4, "", cmd, BARE_TX_FEE));
|
||||
|
||||
return generate_with(events, boost::none, boost::none, prep_create_accounts, cmds.size(), mixin, amount_paid, true, cmds, false, invalid, NULL, NULL);
|
||||
}
|
||||
|
||||
bool gen_cc_tx_invalid_cc_bare_buy_blocks_balance_overflow_in_aggregate::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<uint32_t, std::string, cryptonote::cc_command_t, uint64_t>> cmds;
|
||||
|
||||
cryptonote::cc_command_buy_blocks_t cmd;
|
||||
cryptonote::cc_command_buy_blocks_t::entry_t e;
|
||||
e.type = 1;
|
||||
e.amount = 30000000;
|
||||
cmd.entries.push_back(e);
|
||||
e.type = 2;
|
||||
e.amount = 30000000;
|
||||
cmd.entries.push_back(e);
|
||||
cmds.push_back(std::make_tuple(4, "", cmd, BARE_TX_FEE));
|
||||
|
||||
return generate_with(events, boost::none, boost::none, prep_create_accounts, cmds.size(), mixin, amount_paid, true, cmds, false, invalid, NULL, NULL);
|
||||
}
|
||||
|
||||
bool gen_cc_tx_invalid_cc_bare_buy_blocks_duplicate_type::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<uint32_t, std::string, cryptonote::cc_command_t, uint64_t>> cmds;
|
||||
|
||||
cryptonote::cc_command_buy_blocks_t cmd;
|
||||
cryptonote::cc_command_buy_blocks_t::entry_t e;
|
||||
e.type = 1;
|
||||
e.amount = 0x100;
|
||||
cmd.entries.push_back(e);
|
||||
cmd.entries.push_back(e);
|
||||
cmds.push_back(std::make_tuple(4, "", cmd, BARE_TX_FEE));
|
||||
|
||||
return generate_with(events, boost::none, boost::none, prep_create_accounts, cmds.size(), mixin, amount_paid, true, cmds, false, invalid, NULL, NULL);
|
||||
}
|
||||
|
@ -358,3 +358,15 @@ struct gen_cc_tx_invalid_cc_bare_buy_blocks_balance_overflow: public gen_cc_tx_v
|
||||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
};
|
||||
template<> struct get_test_options<gen_cc_tx_invalid_cc_bare_buy_blocks_balance_overflow>: public get_test_options<gen_cc_tx_validation_base> {};
|
||||
|
||||
struct gen_cc_tx_invalid_cc_bare_buy_blocks_balance_overflow_in_aggregate: 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_buy_blocks_balance_overflow_in_aggregate>: public get_test_options<gen_cc_tx_validation_base> {};
|
||||
|
||||
struct gen_cc_tx_invalid_cc_bare_buy_blocks_duplicate_type: 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_buy_blocks_duplicate_type>: public get_test_options<gen_cc_tx_validation_base> {};
|
||||
|
@ -303,6 +303,8 @@ int main(int argc, char* argv[])
|
||||
GENERATE_AND_PLAY(gen_cc_tx_invalid_cc_bare_buy_blocks_type_0);
|
||||
GENERATE_AND_PLAY(gen_cc_tx_invalid_cc_bare_buy_blocks_amount_0);
|
||||
GENERATE_AND_PLAY(gen_cc_tx_invalid_cc_bare_buy_blocks_balance_overflow);
|
||||
GENERATE_AND_PLAY(gen_cc_tx_invalid_cc_bare_buy_blocks_balance_overflow_in_aggregate);
|
||||
GENERATE_AND_PLAY(gen_cc_tx_invalid_cc_bare_buy_blocks_duplicate_type);
|
||||
|
||||
el::Level level = (failed_tests.empty() ? el::Level::Info : el::Level::Error);
|
||||
if (!list_tests)
|
||||
|
@ -457,14 +457,15 @@ TEST(cc_command, build)
|
||||
TEST(cc_command, buy_blocks)
|
||||
{
|
||||
cryptonote::cc_command_buy_blocks_t cmd;
|
||||
cmd.type = 1;
|
||||
cmd.amount = 1;
|
||||
cmd.entries.resize(1);
|
||||
cmd.entries[0].type = 1;
|
||||
cmd.entries[0].amount = 1;
|
||||
uint64_t c1 = cc::get_cc_command_cost(cmd);
|
||||
ASSERT_GT(c1, 0);
|
||||
cmd.amount = 50;
|
||||
cmd.entries[0].amount = 50;
|
||||
uint64_t c50 = cc::get_cc_command_cost(cmd);
|
||||
ASSERT_EQ(c50, 50 * c1);
|
||||
cmd.amount = std::numeric_limits<uint32_t>::max();
|
||||
cmd.entries[0].amount = std::numeric_limits<uint32_t>::max();
|
||||
uint64_t cmax32 = cc::get_cc_command_cost(cmd);
|
||||
ASSERT_EQ(cmax32, std::numeric_limits<uint32_t>::max() * c1);
|
||||
uint64_t cc_in = (uint64_t)-1, cc_out = (uint64_t)-1;
|
||||
@ -779,20 +780,21 @@ TEST(cc_command, execute_buy_blocks)
|
||||
create_account.public_key = keys.pub;
|
||||
create_account.amount = CRYPTONOTE_CC_NEW_ACCOUNT_FEE + 1000000000000;
|
||||
setup.push_back(std::make_pair(1, create_account));
|
||||
buy_blocks.entries.resize(1);
|
||||
|
||||
// good
|
||||
buy_blocks.type = 1;
|
||||
buy_blocks.amount = 1;
|
||||
buy_blocks.entries[0].type = 1;
|
||||
buy_blocks.entries[0].amount = 1;
|
||||
test_commands(true, 4, setup, buy_blocks, "valid");
|
||||
|
||||
// cannot buy block 0
|
||||
buy_blocks.type = 0;
|
||||
buy_blocks.amount = 1;
|
||||
buy_blocks.entries[0].type = 0;
|
||||
buy_blocks.entries[0].amount = 1;
|
||||
test_commands(false, 4, setup, buy_blocks, "block 0");
|
||||
|
||||
// cannot buy 0 blocks
|
||||
buy_blocks.type = 1;
|
||||
buy_blocks.amount = 0;
|
||||
buy_blocks.entries[0].type = 1;
|
||||
buy_blocks.entries[0].amount = 0;
|
||||
test_commands(false, 4, setup, buy_blocks, "0 blocks");
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user