Files
2024-04-30 22:07:50 -06:00

110 lines
4.9 KiB
C++

#pragma once
#include "TestManager.hpp"
#include <memory>
#include <stdexcept>
#include <botcraft/AI/TemplatedBehaviourClient.hpp>
#include <botcraft/AI/SimpleBehaviourClient.hpp>
#include <botcraft/Game/ManagersClient.hpp>
#include <botcraft/Game/Vector3.hpp>
#include <botcraft/Game/Entities/EntityManager.hpp>
#include <botcraft/Game/Entities/LocalPlayer.hpp>
template<class ClientType = Botcraft::ManagersClient>
std::unique_ptr<ClientType> SetupTestBot(const Botcraft::Vector3<double>& offset = { 0,0,0 }, const Botcraft::GameType gamemode = Botcraft::GameType::Survival)
{
std::string botname;
std::unique_ptr<ClientType> bot = TestManager::GetInstance().GetBot<ClientType>(botname, gamemode);
const Botcraft::Vector3<double> pos = offset + TestManager::GetInstance().GetCurrentOffset();
TestManager::GetInstance().Teleport(botname, pos);
// Wait for bot to register teleportation
std::shared_ptr<Botcraft::LocalPlayer> local_player = bot->GetLocalPlayer();
if (!Botcraft::Utilities::WaitForCondition([&]()
{
return local_player->GetPosition().SqrDist(pos) < 1.0;
}, 5000))
{
throw std::runtime_error("Timeout waiting " + botname + " to register teleportation");
}
// Wait for bot to load center and corner view_distance blocks
std::shared_ptr<Botcraft::World> world = bot->GetWorld();
const int chunk_x = static_cast<int>(std::floor(pos.x / static_cast<double>(Botcraft::CHUNK_WIDTH)));
const int chunk_z = static_cast<int>(std::floor(pos.z / static_cast<double>(Botcraft::CHUNK_WIDTH)));
// -1 because sometimes corner chunks are not sent, depending on where you are on the current chunk
const int view_distance = MinecraftServer::options.view_distance - 1;
std::vector<std::pair<int, int>> wait_loaded = {
{chunk_x * Botcraft::CHUNK_WIDTH, chunk_z * Botcraft::CHUNK_WIDTH},
{(chunk_x + view_distance) * Botcraft::CHUNK_WIDTH - 1, (chunk_z + view_distance) * Botcraft::CHUNK_WIDTH - 1},
{(chunk_x - view_distance) * Botcraft::CHUNK_WIDTH, (chunk_z + view_distance) * Botcraft::CHUNK_WIDTH - 1},
{(chunk_x + view_distance) * Botcraft::CHUNK_WIDTH - 1, (chunk_z - view_distance) * Botcraft::CHUNK_WIDTH},
{(chunk_x - view_distance) * Botcraft::CHUNK_WIDTH, (chunk_z - view_distance) * Botcraft::CHUNK_WIDTH}
};
if (!Botcraft::Utilities::WaitForCondition([&]() {
for (size_t i = 0; i < wait_loaded.size(); ++i)
{
if (!bot->GetWorld()->IsLoaded(Botcraft::Position(wait_loaded[i].first, 2, wait_loaded[i].second)))
{
return false;
}
}
return true;
}, 15000))
{
throw std::runtime_error("Timeout waiting " + botname + " to load surroundings");
}
return bot;
}
#include <botcraft/Game/AssetsManager.hpp>
#include <botcraft/Game/Inventory/InventoryManager.hpp>
#include <botcraft/Game/Inventory/Window.hpp>
template<class ClientType = Botcraft::SimpleBehaviourClient>
bool GiveItem(std::unique_ptr<ClientType>& bot, const std::string& item_name, const std::string& item_pretty_name, const int quantity = 1)
{
const std::shared_ptr<Botcraft::InventoryManager> inventory_manager = bot->GetInventoryManager();
const Botcraft::Item* item = Botcraft::AssetsManager::getInstance().GetItem(Botcraft::AssetsManager::getInstance().GetItemID(item_name));
short receiving_slot = -1;
const std::map<short, ProtocolCraft::Slot> slots = inventory_manager->GetPlayerInventory()->GetSlots();
for (short i = Botcraft::Window::INVENTORY_HOTBAR_START; i < Botcraft::Window::INVENTORY_OFFHAND_INDEX; ++i)
{
if (slots.at(i).IsEmptySlot() ||
(item->GetId() == slots.at(i).GetItemID() && item->GetStackSize() >= slots.at(i).GetItemCount() + quantity))
{
receiving_slot = i;
break;
}
}
// No slot available in the hotbar, check the main inventory
if (receiving_slot == -1)
{
for (short i = Botcraft::Window::INVENTORY_STORAGE_START; i < Botcraft::Window::INVENTORY_HOTBAR_START; ++i)
{
if (slots.at(i).IsEmptySlot())
{
receiving_slot = i;
break;
}
}
}
if (receiving_slot == -1)
{
return false;
}
const std::string& botname = bot->GetNetworkManager()->GetMyName();
MinecraftServer::GetInstance().SendLine("give " + botname + " " + item_name + " " + std::to_string(quantity));
MinecraftServer::GetInstance().WaitLine(".*?: (?:Given|Gave " + std::to_string(quantity) + ") \\[" + item_pretty_name + "\\](?: \\* " + std::to_string(quantity) + ")? to " + botname + ".*", 5000);
return Botcraft::Utilities::WaitForCondition([&]()
{
return !bot->GetInventoryManager()->GetPlayerInventory()->GetSlot(receiving_slot).IsEmptySlot();
}, 5000);
}