25 std::shared_ptr<ServerboundContainerClickPacket> click_window_packet = std::make_shared<ServerboundContainerClickPacket>();
27 click_window_packet->SetContainerId(
static_cast<unsigned char>(container_id));
28 click_window_packet->SetSlotNum(slot_id);
29 click_window_packet->SetButtonNum(button_num);
30#if PROTOCOL_VERSION < 775
31 click_window_packet->SetClickType(click_type);
33 click_window_packet->SetContainerInput(click_type);
37 int transaction_id = inventory_manager->SendInventoryTransaction(click_window_packet);
40#if PROTOCOL_VERSION < 755
41 auto start = std::chrono::steady_clock::now();
44 if (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start).count() >= 10000)
46 LOG_WARNING(
"Something went wrong trying to click slot (Timeout).");
49 TransactionState transaction_state = inventory_manager->GetTransactionState(container_id, transaction_id);
50 if (transaction_state == TransactionState::Accepted)
55 else if (transaction_state == TransactionState::Refused)
68 constexpr std::array variable_names = {
69 "ClickSlotInContainer.container_id",
70 "ClickSlotInContainer.slot_id",
71 "ClickSlotInContainer.click_type",
72 "ClickSlotInContainer.button_num"
78 blackboard.
Set<
short>(variable_names[0], container_id);
79 blackboard.
Set<
short>(variable_names[1], slot_id);
80 blackboard.
Set<
int>(variable_names[2], click_type);
81 blackboard.
Set<
char>(variable_names[3], button_num);
88 constexpr std::array variable_names = {
89 "ClickSlotInContainer.container_id",
90 "ClickSlotInContainer.slot_id",
91 "ClickSlotInContainer.click_type",
92 "ClickSlotInContainer.button_num"
98 const short container_id = blackboard.
Get<
short>(variable_names[0]);
99 const short slot_id = blackboard.
Get<
short>(variable_names[1]);
100 const int click_type = blackboard.
Get<
int>(variable_names[2]);
101 const char button_num = blackboard.
Get<
char>(variable_names[3]);
109 if (first_slot == second_slot)
124 LOG_WARNING(
"Failed to swap items (second click)");
140 constexpr std::array variable_names = {
141 "SwapItemsInContainer.container_id",
142 "SwapItemsInContainer.first_slot",
143 "SwapItemsInContainer.second_slot"
148 blackboard.
Set<
short>(variable_names[0], container_id);
149 blackboard.
Set<
short>(variable_names[1], first_slot);
150 blackboard.
Set<
short>(variable_names[2], second_slot);
157 constexpr std::array variable_names = {
158 "SwapItemsInContainer.container_id",
159 "SwapItemsInContainer.first_slot",
160 "SwapItemsInContainer.second_slot"
166 const short container_id = blackboard.
Get<
short>(variable_names[0]);
167 const short first_slot = blackboard.
Get<
short>(variable_names[1]);
168 const short second_slot = blackboard.
Get<
short>(variable_names[2]);
182 if (num_to_keep == 0)
190 while (item_count > num_to_keep)
205 constexpr std::array variable_names = {
206 "DropItemsFromContainer.container_id",
207 "DropItemsFromContainer.slot_id",
208 "DropItemsFromContainer.num_to_keep"
213 blackboard.
Set<
short>(variable_names[0], container_id);
214 blackboard.
Set<
short>(variable_names[1], slot_id);
215 blackboard.
Set<
short>(variable_names[2], num_to_keep);
222 constexpr std::array variable_names = {
223 "DropItemsFromContainer.container_id",
224 "DropItemsFromContainer.slot_id",
225 "DropItemsFromContainer.num_to_keep"
231 const short container_id = blackboard.
Get<
short>(variable_names[0]);
232 const short slot_id = blackboard.
Get<
short>(variable_names[1]);
235 const short num_to_keep = blackboard.
Get<
short>(variable_names[2], 0);
246 LOG_WARNING(
"Failed to put one item in slot (first click)");
253 LOG_WARNING(
"Failed to put one item in slot (second click)");
260 LOG_WARNING(
"Failed to put one item in slot (third click)");
269 constexpr std::array variable_names = {
270 "PutOneItemInContainerSlot.container_id",
271 "PutOneItemInContainerSlot.source_slot",
272 "PutOneItemInContainerSlot.destination_slot"
277 blackboard.
Set<
short>(variable_names[0], container_id);
278 blackboard.
Set<
short>(variable_names[1], source_slot);
279 blackboard.
Set<
short>(variable_names[2], destination_slot);
286 constexpr std::array variable_names = {
287 "PutOneItemInContainerSlot.container_id",
288 "PutOneItemInContainerSlot.source_slot",
289 "PutOneItemInContainerSlot.destination_slot"
295 const short container_id = blackboard.
Get<
short>(variable_names[0]);
296 const short source_slot = blackboard.
Get<
short>(variable_names[1]);
297 const short destination_slot = blackboard.
Get<
short>(variable_names[2]);
305 if (index < 0 || index > 8)
307 LOG_WARNING(
"Index out of range (0 - 8) when trying to change selected hotbar slot");
312 inventory_manager->SetIndexHotbarSelected(index);
319 constexpr std::array variable_names = {
320 "SelectHotbarSlot.index"
325 blackboard.
Set<
short>(variable_names[0], index);
332 constexpr std::array variable_names = {
333 "SelectHotbarSlot.index"
339 const short index = blackboard.
Get<
short>(variable_names[0]);
349 short inventory_correct_slot_index = -1;
354 const Slot current_selected = hand ==
Hand::Off ? inventory_manager->GetOffHand() : inventory_manager->GetHotbarSelected();
355 if (!current_selected.
IsEmptySlot() && current_selected.GetItemId() == item_id)
366 const Slot s = inventory_manager->GetPlayerInventory()->GetSlot(i);
376 const auto slots = inventory_manager->GetPlayerInventory()->GetLockedSlots();
377 for (
const auto& [
id, slot] : *slots)
381 && !slot.IsEmptySlot()
382 && slot.GetItemId() == item_id)
384 inventory_correct_slot_index = id;
391 if (inventory_correct_slot_index == -1)
402 constexpr std::array variable_names = {
403 "SetItemIdInHand.item_name",
404 "SetItemIdInHand.hand"
409 blackboard.
Set<
ItemId>(variable_names[0], item_id);
410 blackboard.
Set<
Hand>(variable_names[1], hand);
417 constexpr std::array variable_names = {
418 "SetItemIdInHand.item_name",
419 "SetItemIdInHand.hand"
433 constexpr std::array variable_names = {
434 "SetItemInHand.item_name",
440 blackboard.
Set<std::string>(variable_names[0], item_name);
441 blackboard.
Set<
Hand>(variable_names[1], hand);
450 constexpr std::array variable_names = {
451 "SetItemInHand.item_name",
458 const std::string& item_name = blackboard.
Get<std::string>(variable_names[0]);
467 Status PlaceBlockImpl(
BehaviourClient& client,
const std::string& item_name,
const Position& pos, std::optional<PlayerDiggingFace> face,
const bool wait_confirmation,
const bool allow_midair_placing,
const bool allow_pathfinding)
469 std::shared_ptr<World> world = client.
GetWorld();
473 std::shared_ptr<LocalPlayer> local_player = entity_manager->GetLocalPlayer();
488 const std::vector<Position> neighbour_offsets({
494 bool midair_placing =
true;
496 if (!face.has_value())
498 if (allow_midair_placing)
504 std::vector<PlayerDiggingFace> premium_face_candidates;
505 premium_face_candidates.reserve(6);
506 std::vector<PlayerDiggingFace> second_choice_face_candidates;
507 second_choice_face_candidates.reserve(6);
508 for (
int face_idx = 0; face_idx < 6; face_idx++)
510 const Blockstate* neighbour_block = world->GetBlock(pos + neighbour_offsets[face_idx]);
512 if (neighbour_block !=
nullptr && !neighbour_block->
IsAir() && !neighbour_block->
IsFluid())
514 (neighbour_block->
IsSolid() ? premium_face_candidates : second_choice_face_candidates).push_back(
static_cast<PlayerDiggingFace>(face_idx));
517 if (premium_face_candidates.size() + second_choice_face_candidates.size() == 0)
519 LOG_WARNING(
"Can't place a block in midair at " << pos);
522 std::vector<PlayerDiggingFace>& face_candidates = (premium_face_candidates.size() > 0 ? premium_face_candidates : second_choice_face_candidates);
523 const Vector3<double> player_orientation = local_player->GetFrontVector();
527 Vector3<double> a_offset = neighbour_offsets[static_cast<int>(a)];
528 Vector3<double> b_offset = neighbour_offsets[static_cast<int>(b)];
529 return player_orientation.dot(a_offset) > player_orientation.dot(b_offset);
534 face = face_candidates.front();
539 const Blockstate* block = world->GetBlock(pos);
541 if (block !=
nullptr && !block->
IsAir() && !block->
IsFluid())
546 const Blockstate* neighbour_block = world->GetBlock(pos + neighbour_offsets[
static_cast<int>(face.value())]);
547 midair_placing = neighbour_block ==
nullptr || neighbour_block->
IsAir();
549 if (!allow_midair_placing && midair_placing)
551 LOG_WARNING(
"Can't place a block in midair at " << pos);
562 const int num_item_in_hand = inventory_manager->GetPlayerInventory()->GetSlot(
Window::INVENTORY_HOTBAR_START + inventory_manager->GetIndexHotbarSelected()).GetItemCount();
565 const Position placing_pos = (allow_midair_placing && midair_placing) ? pos : (pos + neighbour_offsets[
static_cast<int>(face.value())]);
567 std::shared_ptr<ServerboundUseItemOnPacket> place_block_packet = std::make_shared<ServerboundUseItemOnPacket>();
569 place_block_packet->SetDirection(
static_cast<int>(face.value()));
570 switch (face.value())
573 place_block_packet->SetCursorPositionX(0.5f);
574 place_block_packet->SetCursorPositionY(0.0f);
575 place_block_packet->SetCursorPositionZ(0.5f);
578 place_block_packet->SetCursorPositionX(0.5f);
579 place_block_packet->SetCursorPositionY(1.0f);
580 place_block_packet->SetCursorPositionZ(0.5f);
583 place_block_packet->SetCursorPositionX(0.5f);
584 place_block_packet->SetCursorPositionY(0.5f);
585 place_block_packet->SetCursorPositionZ(0.0f);
588 place_block_packet->SetCursorPositionX(0.5f);
589 place_block_packet->SetCursorPositionY(0.5f);
590 place_block_packet->SetCursorPositionZ(1.0f);
593 place_block_packet->SetCursorPositionX(1.0f);
594 place_block_packet->SetCursorPositionY(0.5f);
595 place_block_packet->SetCursorPositionZ(0.5f);
598 place_block_packet->SetCursorPositionX(0.0f);
599 place_block_packet->SetCursorPositionY(0.5f);
600 place_block_packet->SetCursorPositionZ(0.5f);
605#if PROTOCOL_VERSION > 452
606 place_block_packet->SetInside(
false);
608 place_block_packet->SetHand(
static_cast<int>(
Hand::Right));
609#if PROTOCOL_VERSION > 758
610 place_block_packet->SetSequence(world->GetNextWorldInteractionSequenceId());
615 network_manager->Send(place_block_packet);
617#if PROTOCOL_VERSION < 777
618 std::shared_ptr<ServerboundSwingPacket> swing = std::make_shared<ServerboundSwingPacket>();
620 network_manager->Send(swing);
623 if (!wait_confirmation)
628 bool is_block_ok =
false;
629 bool is_slot_ok =
true;
630 auto start = std::chrono::steady_clock::now();
632 while (!is_block_ok || !is_slot_ok)
634 if (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start).count() >= 60.0 * ms_per_tick)
636 LOG_WARNING(
'[' << network_manager->GetMyName() <<
"] "
637 <<
"Something went wrong waiting block placement confirmation at " << pos <<
" (Timeout). "
638 <<
"Block ok: " << is_block_ok <<
" Slot ok: " << is_slot_ok
644 const Blockstate* block = world->GetBlock(pos);
646 if (block !=
nullptr && block->
GetName() == item_name)
653 const int new_num_item_in_hand = inventory_manager->GetPlayerInventory()->GetSlot(
Window::INVENTORY_HOTBAR_START + inventory_manager->GetIndexHotbarSelected()).GetItemCount();
654 is_slot_ok = new_num_item_in_hand == num_item_in_hand - 1;
657 if (is_block_ok && is_slot_ok)
668 Status PlaceBlock(
BehaviourClient& client,
const std::string& item_name,
const Position& pos, std::optional<PlayerDiggingFace> face,
const bool wait_confirmation,
const bool allow_midair_placing,
const bool allow_pathfinding)
670 constexpr std::array variable_names = {
671 "PlaceBlock.item_name",
674 "PlaceBlock.wait_confirmation",
675 "PlaceBlock.allow_midair_placing",
676 "PlaceBlock.allow_pathfinding",
681 blackboard.
Set<std::string>(variable_names[0], item_name);
683 blackboard.
Set<std::optional<PlayerDiggingFace>>(variable_names[2], face);
684 blackboard.
Set<
bool>(variable_names[3], wait_confirmation);
685 blackboard.
Set<
bool>(variable_names[4], allow_midair_placing);
686 blackboard.
Set<
bool>(variable_names[5], allow_pathfinding);
688 return PlaceBlockImpl(client, item_name, pos, face, wait_confirmation, allow_midair_placing, allow_pathfinding);
693 constexpr std::array variable_names = {
694 "PlaceBlock.item_name",
697 "PlaceBlock.wait_confirmation",
698 "PlaceBlock.allow_midair_placing",
699 "PlaceBlock.allow_pathfinding",
705 const std::string& item_name = blackboard.
Get<std::string>(variable_names[0]);
709 const std::optional<PlayerDiggingFace> face = blackboard.
Get<std::optional<PlayerDiggingFace>>(variable_names[2],
PlayerDiggingFace::Up);
710 const bool wait_confirmation = blackboard.
Get<
bool>(variable_names[3],
false);
711 const bool allow_midair_placing = blackboard.
Get<
bool>(variable_names[4],
false);
712 const bool allow_pathfinding = blackboard.
Get<
bool>(variable_names[5],
true);
715 return PlaceBlockImpl(client, item_name, pos, face, wait_confirmation, allow_midair_placing, allow_pathfinding);
729 const char current_stack_size = inventory_manager->GetOffHand().GetItemCount();
730 std::shared_ptr<ServerboundUseItemPacket> use_item_packet = std::make_shared<ServerboundUseItemPacket>();
731 use_item_packet->SetHand(
static_cast<int>(
Hand::Left));
732#if PROTOCOL_VERSION > 758
733 use_item_packet->SetSequence(client.
GetWorld()->GetNextWorldInteractionSequenceId());
735 network_manager->Send(use_item_packet);
737 if (!wait_confirmation)
742 auto start = std::chrono::steady_clock::now();
744 while (inventory_manager->GetOffHand().GetItemCount() == current_stack_size)
746 if (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start).count() >= 60.0 * ms_per_tick)
748 LOG_WARNING(
"Something went wrong trying to eat (Timeout).");
759 constexpr std::array variable_names = {
761 "Eat.wait_confirmation"
766 blackboard.
Set<std::string>(variable_names[0], food_name);
767 blackboard.
Set<
bool>(variable_names[1], wait_confirmation);
769 return EatImpl(client, food_name, wait_confirmation);
774 constexpr std::array variable_names = {
776 "Eat.wait_confirmation"
782 const std::string& food_name = blackboard.
Get<std::string>(variable_names[0]);
785 const bool wait_confirmation = blackboard.
Get<
bool>(variable_names[1],
false);
788 return EatImpl(client, food_name, wait_confirmation);
803 auto start = std::chrono::steady_clock::now();
804 while (inventory_manager->GetFirstOpenedWindowId() == -1)
806 if (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start).count() >= 3000)
808 LOG_WARNING(
"Something went wrong trying to open container (Timeout).");
819 constexpr std::array variable_names = {
832 constexpr std::array variable_names = {
851 std::shared_ptr<ServerboundContainerClosePacket> close_container_packet = std::make_shared<ServerboundContainerClosePacket>();
852 short true_container_id = container_id;
853 if (true_container_id < 0)
855 true_container_id = inventory_manager->GetFirstOpenedWindowId();
857 close_container_packet->SetContainerId(
static_cast<unsigned char>(true_container_id));
858 network_manager->Send(close_container_packet);
862 inventory_manager->EraseInventory(true_container_id);
869 constexpr std::array variable_names = {
870 "CloseContainer.container_id"
875 blackboard.
Set<
short>(variable_names[0], container_id);
882 constexpr std::array variable_names = {
883 "CloseContainer.container_id"
889 const short container_id = blackboard.
Get<
short>(variable_names[0], -1);
900 std::stringstream output;
902 output <<
"Cursor --> " << inventory_manager->GetCursor().Serialize().Dump() <<
"\n";
903 auto slots = inventory_manager->GetPlayerInventory()->GetLockedSlots();
904 for (
const auto& [
id, slot] : *slots)
906 output <<
id <<
" --> " << slot.Serialize().Dump() <<
"\n";
909 LOG(output.str(), level);
915 constexpr std::array variable_names = {
916 "LogInventoryContent.level"
921 blackboard.
Set<
LogLevel>(variable_names[0], level);
928 constexpr std::array variable_names = {
929 "LogInventoryContent.level"
941#if PROTOCOL_VERSION > 451
948 auto start = std::chrono::steady_clock::now();
949 size_t num_trades = 0;
952 if (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start).count() > 5000)
954 LOG_WARNING(
"Something went wrong waiting trade opening (Timeout).");
958 num_trades = inventory_manager->GetAvailableMerchantOffers().size();
960 }
while (num_trades <= 0 || inventory_manager->GetFirstOpenedWindowId() == -1);
962 const short container_id = inventory_manager->GetFirstOpenedWindowId();
963 std::shared_ptr<Window> trading_container = inventory_manager->GetWindow(container_id);
965 if (trading_container ==
nullptr)
967 LOG_WARNING(
"Something went wrong during trade (window closed).");
971 int trade_index = trade_id;
972 bool has_trade_second_item =
false;
973 const std::vector<ProtocolCraft::MerchantOffer> trades = inventory_manager->GetAvailableMerchantOffers();
978 for (
int i = 0; i < trades.size(); ++i)
980 if ((buy && trades[i].GetOutputItem().GetItemId() == item_id)
981 || (!buy && trades[i].GetInputItem1().GetItemId() == item_id))
984 has_trade_second_item = trades[i].GetInputItem2().has_value();
990 if (trade_index == -1)
997 if (trades[trade_index].GetNumberOfTradesUses() >= trades[trade_index].GetMaximumNumberOfTradeUses())
1006 std::shared_ptr<ServerboundSelectTradePacket> select_trade_packet = std::make_shared<ServerboundSelectTradePacket>();
1007 select_trade_packet->SetItem(trade_index);
1009 network_manager->Send(select_trade_packet);
1011 start = std::chrono::steady_clock::now();
1013 bool correct_items =
false;
1016 if (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start).count() > 5000)
1018 LOG_WARNING(
"Something went wrong waiting trade selection (Timeout). Maybe an item was missing?");
1022 correct_items = (buy && trading_container->GetSlot(2).GetItemId() == item_id) ||
1023 (!buy && !trading_container->GetSlot(2).IsEmptySlot()
1024 && (trading_container->GetSlot(0).GetItemId() == item_id || trading_container->GetSlot(1).GetItemId() == item_id));
1026 }
while (!correct_items);
1029 std::vector<short> empty_slots(has_trade_second_item ? 3 : 2);
1030 int empty_slots_index = 0;
1032 auto slots = trading_container->GetLockedSlots();
1033 for (
const auto& [
id, slot] : *slots)
1035 if (id < trading_container->GetFirstPlayerInventorySlot())
1040 if (slot.IsEmptySlot())
1042 empty_slots[empty_slots_index] = id;
1043 empty_slots_index++;
1044 if (empty_slots_index == empty_slots.size())
1051 if (empty_slots_index == 0)
1053 LOG_WARNING(
"No free space in inventory for trading to happen.");
1056 else if (empty_slots_index < empty_slots.size())
1058 LOG_WARNING(
"Not enough free space in inventory for trading. Input items may be lost");
1062 const Slot input_slot_1 = trading_container->GetSlot(0);
1063 const Slot input_slot_2 = trading_container->GetSlot(1);
1068 LOG_WARNING(
"Failed to swap output slot during trading attempt");
1073 start = std::chrono::steady_clock::now();
1076 if (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start).count() > 5000)
1078 LOG_WARNING(
"Something went wrong waiting trade input update (Timeout).");
1082 if ((input_slot_1.
IsEmptySlot() || input_slot_1.GetItemCount() != trading_container->GetSlot(0).GetItemCount()) &&
1083 (input_slot_2.
IsEmptySlot() || input_slot_2.GetItemCount() != trading_container->GetSlot(1).GetItemCount()))
1091 for (
int i = 0; i < empty_slots_index - 1; ++i)
1095 LOG_WARNING(
"Failed to swap slots " << i <<
" after trading attempt");
1102 inventory_manager->IncrementMerchantOfferUse(trade_index);
1109 constexpr std::array variable_names = {
1117 blackboard.
Set<
int>(variable_names[0], item_id);
1118 blackboard.
Set<
bool>(variable_names[1], buy);
1119 blackboard.
Set<
int>(variable_names[2], trade_id);
1121 return TradeImpl(client, item_id, buy, trade_id);
1126 constexpr std::array variable_names = {
1135 const int item_id = blackboard.
Get<
int>(variable_names[0]);
1136 const bool buy = blackboard.
Get<
bool>(variable_names[1]);
1139 const int trade_id = blackboard.
Get<
int>(variable_names[2], -1);
1141 return TradeImpl(client, item_id, buy, trade_id);
1155 return TradeImpl(client, item_id, buy, trade_id);
1160 constexpr std::array variable_names = {
1161 "TradeName.item_name",
1163 "TradeName.trade_id"
1168 blackboard.
Set<std::string>(variable_names[0], item_name);
1169 blackboard.
Set<
bool>(variable_names[1], buy);
1170 blackboard.
Set<
int>(variable_names[2], trade_id);
1177 constexpr std::array variable_names = {
1178 "TradeName.item_name",
1180 "TradeName.trade_id"
1186 const std::string& item_name = blackboard.
Get<std::string>(variable_names[0]);
1187 const bool buy = blackboard.
Get<
bool>(variable_names[1]);
1190 const int trade_id = blackboard.
Get<
int>(variable_names[2], -1);
1205 bool use_inventory_craft =
false;
1206 if (!allow_inventory_craft)
1208 use_inventory_craft =
false;
1216 for (
int y = 0; y < 3; ++y)
1218 for (
int x = 0; x < 3; ++x)
1221#if PROTOCOL_VERSION < 350
1222 if (inputs[y][x].first != -1 && inputs[y][x] != air_id)
1224 if (inputs[y][x] != -1 && inputs[y][x] != air_id)
1227 min_x = std::min(x, min_x);
1228 max_x = std::max(x, max_x);
1229 min_y = std::min(y, min_y);
1230 max_y = std::max(y, max_y);
1235 use_inventory_craft = (max_x - min_x) < 2 && (max_y - min_y) < 2;
1238 int crafting_container_id = -1;
1240 if (!use_inventory_craft)
1242 auto start = std::chrono::steady_clock::now();
1245 if (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start).count() > 5000)
1247 LOG_WARNING(
"Something went wrong waiting craft opening (Timeout).");
1250 crafting_container_id = inventory_manager->GetFirstOpenedWindowId();
1252 }
while (crafting_container_id == -1);
1259 std::shared_ptr<Window> crafting_container = inventory_manager->GetWindow(crafting_container_id);
1261 if (crafting_container ==
nullptr)
1263 LOG_WARNING(
"Something went wrong during craft (window closed).");
1267 Slot output_slot_before;
1271 for (
int y = min_y; y < max_y + 1; ++y)
1273 for (
int x = min_x; x < max_x + 1; ++x)
1275 const int destination_slot = use_inventory_craft ? (1 + x - min_x + (y - min_y) * 2) : (1 + x + 3 * y);
1278#if PROTOCOL_VERSION < 350
1279 if (inputs[y][x].first == -1 || inputs[y][x] == air_id)
1281 if (inputs[y][x] == -1 || inputs[y][x] == air_id)
1289 output_slot_before = crafting_container->GetSlot(0);
1291 int source_slot = -1;
1292 int source_quantity = -1;
1295 auto slots = crafting_container->GetLockedSlots();
1296 for (
const auto& [
id, slot] : *slots)
1298 if (id < crafting_container->GetFirstPlayerInventorySlot())
1302#if PROTOCOL_VERSION < 350
1303 if (slot.GetBlockId() == inputs[y][x].first && slot.GetItemDamage() == inputs[y][x].second)
1305 if (slot.GetItemId() == inputs[y][x])
1309 source_quantity = slot.GetItemCount();
1315 if (source_slot == -1)
1335 if (source_quantity > 1)
1348 auto start = std::chrono::steady_clock::now();
1351 if (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start).count() > 5000)
1353 LOG_WARNING(
"Something went wrong waiting craft output update (Timeout).");
1356 if (!crafting_container->GetSlot(0).SameItem(output_slot_before))
1366 LOG_WARNING(
"Error trying to click on output during crafting");
1371 int destination_slot = -999;
1373 auto slots = crafting_container->GetLockedSlots();
1374 for (
const auto& [
id, slot] : *slots)
1382 if (slot.IsEmptySlot() ||
1383 (inventory_manager->GetCursor().GetItemId() == slot.GetItemId() &&
1387 destination_slot = id;
1393 if (destination_slot == -999)
1395 LOG_INFO(
"No available space for crafted item, will be thrown out");
1400 LOG_WARNING(
"Error trying to put back output during crafting");
1409 constexpr std::array variable_names = {
1411 "Craft.allow_inventory_craft"
1416 blackboard.
Set<std::array<std::array<ItemId, 3>, 3>>(variable_names[0], inputs);
1417 blackboard.
Set<
bool>(variable_names[1], allow_inventory_craft);
1419 return CraftImpl(client, inputs, allow_inventory_craft);
1424 constexpr std::array variable_names = {
1426 "Craft.allow_inventory_craft"
1432 const std::array<std::array<ItemId, 3>, 3>& inputs = blackboard.
Get<std::array<std::array<ItemId, 3>, 3>>(variable_names[0]);
1435 const bool allow_inventory_craft = blackboard.
Get<
bool>(variable_names[1],
true);
1437 return CraftImpl(client, inputs, allow_inventory_craft);
1444 std::array<std::array<ItemId, 3>, 3> inputs_ids;
1445 for (
size_t i = 0; i < 3; ++i)
1447 for (
size_t j = 0; j < 3; ++j)
1449#if PROTOCOL_VERSION < 350
1450 inputs_ids[i][j] = inputs[i][j] ==
"" ? std::pair<int, unsigned char>{ -1, 0 } : assets_manager.
GetItemID(inputs[i][j]);
1452 inputs_ids[i][j] = inputs[i][j] ==
"" ? -1 : assets_manager.
GetItemID(inputs[i][j]);
1456 return CraftImpl(client, inputs_ids, allow_inventory_craft);
1461 constexpr std::array variable_names = {
1462 "CraftNamed.inputs",
1463 "CraftNamed.allow_inventory_craft"
1468 blackboard.
Set<std::array<std::array<std::string, 3>, 3>>(variable_names[0], inputs);
1469 blackboard.
Set<
bool>(variable_names[1], allow_inventory_craft);
1476 constexpr std::array variable_names = {
1477 "CraftNamed.inputs",
1478 "CraftNamed.allow_inventory_craft"
1484 const std::array<std::array<std::string, 3>, 3>& inputs = blackboard.
Get<std::array<std::array<std::string, 3>, 3>>(variable_names[0]);
1487 const bool allow_inventory_craft = blackboard.
Get<
bool>(variable_names[1],
true);
1497 int quantity_sum = 0;
1499 auto slots = inventory_manager->GetPlayerInventory()->GetLockedSlots();
1500 for (
const auto& [
id, slot] : *slots)
1507 if (!slot.IsEmptySlot() && item_id == slot.GetItemId())
1509 quantity_sum += slot.GetItemCount();
1512 if (quantity_sum >= quantity)
1524 constexpr std::array variable_names = {
1525 "HasItemIdInInventory.item_id",
1526 "HasItemIdInInventory.quantity"
1530 blackboard.
Set<
ItemId>(variable_names[0], item_id);
1531 blackboard.
Set<
int>(variable_names[1], quantity);
1538 constexpr std::array variable_names = {
1539 "HasItemIdInInventory.item_id",
1540 "HasItemIdInInventory.quantity"
1549 const int quantity = blackboard.
Get<
int>(variable_names[1], 1);
1556 constexpr std::array variable_names = {
1557 "HasItemInInventory.item_name",
1558 "HasItemInInventory.quantity"
1562 blackboard.
Set<std::string>(variable_names[0], item_name);
1563 blackboard.
Set<
int>(variable_names[1], quantity);
1572 constexpr std::array variable_names = {
1573 "HasItemInInventory.item_name",
1574 "HasItemInInventory.quantity"
1580 const std::string& item_name = blackboard.
Get<std::string>(variable_names[0]);
1583 const int quantity = blackboard.
Get<
int>(variable_names[1], 1);
1592 std::shared_ptr<Window> player_inventory = inventory_manager->GetPlayerInventory();
1596 short src_index = -1;
1597 short dst_index = -1;
1600 const Slot dst_slot = player_inventory->GetSlot(i);
1609 if (available_space == 0)
1616 const Slot src_slot = player_inventory->GetSlot(j);
1619 && src_slot.GetItemCount() <= available_space)
1626 if (src_index != -1)
1634 if (src_index == -1 && dst_index == -1)
1642 LOG_WARNING(
"Error trying to pick up slot during inventory sorting");
1648 LOG_WARNING(
"Error trying to put down slot during inventory sorting");
#define LOG_WARNING(osstream)
#define LOG_INFO(osstream)
#define LOG(osstream, level)
const std::unordered_map< ItemId, std::unique_ptr< Item > > & Items() const
static AssetsManager & getInstance()
ItemId GetItemID(const std::string &item_name) const
A ManagersClient extended with a blackboard that can store any kind of data and a virtual Yield funct...
Blackboard & GetBlackboard()
A map wrapper to store arbitrary data.
void Set(const std::string &key, const T &value)
Set map entry at key to value.
const T & Get(const std::string &key)
Get the map value at key, casting it to T.
const std::string & GetName() const
std::shared_ptr< NetworkManager > GetNetworkManager() const
std::shared_ptr< EntityManager > GetEntityManager() const
std::shared_ptr< PhysicsManager > GetPhysicsManager() const
std::shared_ptr< InventoryManager > GetInventoryManager() const
std::shared_ptr< World > GetWorld() const
static constexpr short INVENTORY_HOTBAR_START
static constexpr short INVENTORY_STORAGE_START
static constexpr short PLAYER_INVENTORY_INDEX
static constexpr short INVENTORY_OFFHAND_INDEX
bool SameItem(const Slot &s) const
Status CraftNamedImpl(BehaviourClient &client, const std::array< std::array< std::string, 3 >, 3 > &inputs, const bool allow_inventory_craft)
Status SelectHotbarSlotImpl(BehaviourClient &client, const short index)
Status OpenContainerImpl(BehaviourClient &client, const Position &pos)
Status PutOneItemInContainerSlot(BehaviourClient &client, const short container_id, const short source_slot, const short destination_slot)
Take one item from source_slot, and put it on destination_slot.
Status ClickSlotInContainerImpl(BehaviourClient &client, const short container_id, const short slot_id, const int click_type, const char button_num)
Status HasItemInInventoryBlackboard(BehaviourClient &client)
Same thing as HasItemInInventory, but reads its parameters from the blackboard.
Status Craft(BehaviourClient &client, const std::array< std::array< ItemId, 3 >, 3 > &inputs, const bool allow_inventory_craft=true)
Put item in a crafting container and click on the output, storing it in the inventory.
Status TradeNameBlackboard(BehaviourClient &client)
Same thing as TradeName, but reads its parameters from the blackboard.
Status HasItemIdInInventory(BehaviourClient &client, const ItemId item_id, const int quantity=1)
Check if item_id is present in inventory.
Status TradeBlackboard(BehaviourClient &client)
Same thing as Trade, but reads its parameters from the blackboard.
Status SetItemIdInHandBlackboard(BehaviourClient &client)
Same thing as SetItemIdInHand, but reads its parameters from the blackboard.
Status DropItemsFromContainer(BehaviourClient &client, const short container_id, const short slot_id, const short num_to_keep=0)
Drop item out of inventory.
Status EatBlackboard(BehaviourClient &client)
Same thing as Eat, but reads its parameters from the blackboard.
Status CloseContainer(BehaviourClient &client, const short container_id=-1)
Close an opened container.
Status SetItemInHandBlackboard(BehaviourClient &client)
Same thing as SetItemInHand, but reads its parameters from the blackboard.
Status GoTo(BehaviourClient &client, const Position &goal, const int dist_tolerance=0, const int min_end_dist=0, const int min_end_dist_xz=0, const bool allow_jump=true, const bool sprint=true, const float speed_factor=1.0f)
Find a path to a block position and navigate to it.
Status HasItemInInventory(BehaviourClient &client, const std::string &item_name, const int quantity=1)
Check if item_name is present in inventory.
Status PlaceBlockImpl(BehaviourClient &client, const std::string &item_name, const Position &pos, std::optional< PlayerDiggingFace > face, const bool wait_confirmation, const bool allow_midair_placing, const bool allow_pathfinding)
Status LogInventoryContent(BehaviourClient &client, const LogLevel level=LogLevel::Info)
Log all the inventory content at given log level.
Status SwapItemsInContainer(BehaviourClient &client, const short container_id, const short first_slot, const short second_slot)
Swap two slots in a given container.
Status SelectHotbarSlotBlackboard(BehaviourClient &client)
Same thing as SelectHotbarSlot, but reads its parameters from the blackboard.
Status CraftNamed(BehaviourClient &client, const std::array< std::array< std::string, 3 >, 3 > &inputs, const bool allow_inventory_craft=true)
Put item in a crafting container and click on the output, storing it in the inventory.
Status SetItemInHandImpl(BehaviourClient &client, const ItemId item_id, const Hand hand)
Status CraftBlackboard(BehaviourClient &client)
Same thing as Craft, but reads its parameters from the blackboard.
Status ClickSlotInContainerBlackboard(BehaviourClient &client)
Same thing as ClickSlotInContainer, but reads its parameters from the blackboard.
Status HasItemIdInInventoryBlackboard(BehaviourClient &client)
Same thing as HasItemIdInInventory, but reads its parameters from the blackboard.
Status PutOneItemInContainerSlotBlackboard(BehaviourClient &client)
Same thing as PutOneItemInContainerSlot, but reads its parameters from the blackboard.
Status LookAt(BehaviourClient &client, const Vector3< double > &target, const bool set_pitch=true, const bool sync_to_server=true)
Turn the camera to look at a given target and send the new rotation to the server.
Status InteractWithBlock(BehaviourClient &client, const Position &pos, const PlayerDiggingFace face=PlayerDiggingFace::Up, const bool animation=true)
Interact (right click) with the block at the given location.
Status PlaceBlock(BehaviourClient &client, const std::string &item_name, const Position &pos, std::optional< PlayerDiggingFace > face=std::nullopt, const bool wait_confirmation=false, const bool allow_midair_placing=false, const bool allow_pathfinding=true)
Try to place the item at given pos.
Status SortInventory(BehaviourClient &client)
Clean the inventory stacking same items together.
Status HasItemInInventoryImpl(BehaviourClient &client, const ItemId item_id, const int quantity)
Status DropItemsFromContainerImpl(BehaviourClient &client, const short container_id, const short slot_id, const short num_to_keep)
Status TradeImpl(BehaviourClient &client, const int item_id, const bool buy, const int trade_id)
Status SetItemInHand(BehaviourClient &client, const std::string &item_name, const Hand hand=Hand::Right)
Try to set a given item in the given hand.
Status CraftImpl(BehaviourClient &client, const std::array< std::array< ItemId, 3 >, 3 > &inputs, const bool allow_inventory_craft)
Status CloseContainerImpl(BehaviourClient &client, const short container_id)
Status OpenContainer(BehaviourClient &client, const Position &pos)
Open a container at a given position.
Status SelectHotbarSlot(BehaviourClient &client, const short index)
Sets the current selected hotbar slot.
Status Eat(BehaviourClient &client, const std::string &food_name, const bool wait_confirmation=true)
Search for food item in the inventory and eat it.
Status ClickSlotInContainer(BehaviourClient &client, const short container_id, const short slot_id, const int click_type, const char button_num)
Perform a click action on a container.
Status DropItemsFromContainerBlackboard(BehaviourClient &client)
Same thing as DropItemsFromContainer, but reads its parameters from the blackboard.
Status LogInventoryContentBlackboard(BehaviourClient &client)
Same thing as LogInventoryContent, but reads its parameters from the blackboard.
Status PlaceBlockBlackboard(BehaviourClient &client)
Same thing as PlaceBlock, but reads its parameters from the blackboard.
Status CloseContainerBlackboard(BehaviourClient &client)
Same thing as CloseContainer, but reads its parameters from the blackboard.
Status LogInventoryContentImpl(BehaviourClient &client, const LogLevel level)
Status OpenContainerBlackboard(BehaviourClient &client)
Same thing as OpenContainer, but reads its parameters from the blackboard.
Status EatImpl(BehaviourClient &client, const std::string &food_name, const bool wait_confirmation)
Status SwapItemsInContainerBlackboard(BehaviourClient &client)
Same thing as SwapItemsInContainer, but reads its parameters from the blackboard.
Status Trade(BehaviourClient &client, const int item_id, const bool buy, const int trade_id=-1)
Buy or sell an item, assuming a trading window is currently opened.
Status TradeNameImpl(BehaviourClient &client, const std::string &item_name, const bool buy, const int trade_id)
Status SwapItemsInContainerImpl(BehaviourClient &client, const short container_id, const short first_slot, const short second_slot)
Status TradeName(BehaviourClient &client, const std::string &item_name, const bool buy, const int trade_id=-1)
Buy or sell an item, assuming a trading window is currently opened.
Status SetItemIdInHand(BehaviourClient &client, const ItemId item_id, const Hand hand=Hand::Right)
Try to set a given item in the given hand.
Status CraftNamedBlackboard(BehaviourClient &client)
Same thing as CraftNamed, but reads its parameters from the blackboard.
Status PutOneItemInContainerSlotImpl(BehaviourClient &client, const short container_id, const short source_slot, const short destination_slot)
double SqrDist(const Vector3 &v) const
ProtocolCraft::NetworkPosition ToNetworkPosition() const