Skip to content
Snippets Groups Projects
Commit 2e26f140 authored by David Warnquist's avatar David Warnquist
Browse files

Fix: segfault guards. also some cleanup and comments.

parent ffeec525
No related branches found
No related tags found
No related merge requests found
......@@ -8,7 +8,6 @@ void define_unittype(py::module & m)
.def(py::init([](const sc2::UnitTypeID & type, IDABot & bot) {
return UnitType(type, bot, bot);
}))
.def(py::self == py::self)
.def_property_readonly("unit_typeid", [](UnitType & unit_type) { return static_cast<sc2::UNIT_TYPEID>(unit_type.getAPIUnitType()); })
.def_property_readonly("name", &UnitType::getName, "The name of the unit as a sting.")
.def_property_readonly("race", &UnitType::getRace, "The race the unit belongs to.")
......@@ -51,8 +50,13 @@ void define_unittype(py::module & m)
.def("__hash__", [](const UnitType & unit_type) { return std::hash<CCUnitID>{}(unit_type.getAPIUnitType()); })
.def(py::self == py::self)
.def("__repr__", [](const UnitType & unit_type) { return "<UnitType: '" + unit_type.getName() + "'>"; })
.def("is", &UnitType::is)
.def("__lt__", &UnitType::operator<, py::is_operator())
.def("__eq__", &UnitType::operator==, py::is_operator())
.doc() = R"(
Wrapper for :class:`library.UNIT_TYPEID`. Represents a type of unit in the game.
NOTE: A lot of functions utilize checks that require the game to be running.
Therefore if you get an unexpected segmentation fault, it is likely due to the game not being in a running state.
)";
// Not implemented in CommandCenter
......
......@@ -11,9 +11,9 @@ UnitType::UnitType()
UnitType::UnitType(const sc2::UnitTypeID & type, sc2::Client & client)
: m_client(&client)
, m_type(type)
, m_bot(nullptr)
, m_observer(nullptr)
, m_type(type)
{
......@@ -21,18 +21,18 @@ UnitType::UnitType(const sc2::UnitTypeID & type, sc2::Client & client)
UnitType::UnitType(const sc2::UnitTypeID & type, sc2::Client & client, IDABot & bot)
: m_client(&client)
, m_type(type)
, m_bot(&bot)
, m_observer(nullptr)
, m_type(type)
{
}
UnitType::UnitType(const sc2::UnitTypeID & type, sc2::Client & client, IDAReplayObserver & observer)
: m_client(&client)
, m_type(type)
, m_observer(&observer)
, m_bot(nullptr)
, m_observer(&observer)
, m_type(type)
{
......@@ -70,7 +70,13 @@ std::string UnitType::getName() const
CCRace UnitType::getRace() const
{
return m_client->Observation()->GetUnitTypeData()[m_type].race;
auto UTData = m_client->Observation()->GetUnitTypeData();
if (UTData.empty()) // Check to hopefully avoid segfaults
{
BOT_ASSERT(false, "Failed, try with game running!");
return CCRace::Random;
}
return UTData[m_type].race;
}
bool UnitType::isCombatUnit() const
......@@ -225,7 +231,13 @@ bool UnitType::isWorker() const
bool UnitType::canAttackGound() const
{
#ifdef SC2API
auto & weapons = m_client->Observation()->GetUnitTypeData()[m_type].weapons;
auto UTData = m_client->Observation()->GetUnitTypeData();
if (UTData.empty()) // Check to hopefully avoid segfaults
{
BOT_ASSERT(false, "Failed, try with game running!");
return false;
}
auto & weapons = UTData[m_type].weapons;
if (weapons.empty())
{
......@@ -249,7 +261,14 @@ bool UnitType::canAttackGound() const
bool UnitType::canAttackAir() const
{
#ifdef SC2API
auto & weapons = m_client->Observation()->GetUnitTypeData()[m_type].weapons;
auto UTData = m_client->Observation()->GetUnitTypeData();
if (UTData.empty()) // Check to hopefully avoid segfaults
{
BOT_ASSERT(false, "Failed, try with game running!");
return false;
}
auto & weapons = UTData[m_type].weapons;
if (weapons.empty())
{
......@@ -273,7 +292,13 @@ bool UnitType::canAttackAir() const
CCPositionType UnitType::getAttackRange() const
{
#ifdef SC2API
auto & weapons = m_client->Observation()->GetUnitTypeData()[m_type].weapons;
auto UTData = m_client->Observation()->GetUnitTypeData();
if (UTData.empty()) // Check to hopefully avoid segfaults
{
BOT_ASSERT(false, "Failed, try with game running!");
return 0.0f;
}
auto & weapons = UTData[m_type].weapons;
if (weapons.empty())
{
......@@ -299,8 +324,13 @@ CCPositionType UnitType::getAttackRange() const
float UnitType::getAttackDamage() const
{
#ifdef SC2API
auto & weapons = m_client->Observation()->GetUnitTypeData()[m_type].weapons;
auto UTData = m_client->Observation()->GetUnitTypeData();
if (UTData.empty()) // Check to hopefully avoid segfaults
{
BOT_ASSERT(false, "Failed, try with game running!");
return 0.0f;
}
auto & weapons = UTData[m_type].weapons;
if (weapons.empty())
{
return 0.0f;
......@@ -329,13 +359,20 @@ int UnitType::tileWidth() const
if (isMineral()) { return 2; }
if (isGeyser()) { return 3; }
else {
if (m_bot != nullptr)
auto UTData = m_client->Observation()->GetAbilityData();
if (UTData.empty()) // Check to hopefully avoid segfaults
{
BOT_ASSERT(false, "Failed, try with game running!");
return -1;
}
else if (m_bot != nullptr)
{
return (int)(2 * m_client->Observation()->GetAbilityData()[m_bot->Data(*this).buildAbility].footprint_radius);
return (int)(2 * UTData[m_bot->Data(*this).buildAbility].footprint_radius);
}
else if (m_observer != nullptr)
{
return (int)(2 * m_client->Observation()->GetAbilityData()[m_observer->Data(*this).buildAbility].footprint_radius);
return (int)(2 * UTData[m_observer->Data(*this).buildAbility].footprint_radius);
}
else
{
......@@ -353,13 +390,20 @@ int UnitType::tileHeight() const
if (isMineral()) { return 1; }
if (isGeyser()) { return 3; }
else {
if (m_bot != nullptr)
auto UTData = m_client->Observation()->GetAbilityData();
if (UTData.empty()) // Check to hopefully avoid segfaults
{
BOT_ASSERT(false, "Failed, try with game running!");
return -1;
}
else if (m_bot != nullptr)
{
return (int)(2 * m_client->Observation()->GetAbilityData()[m_bot->Data(*this).buildAbility].footprint_radius);
return (int)(2 * UTData[m_bot->Data(*this).buildAbility].footprint_radius);
}
else if (m_observer != nullptr)
{
return (int)(2 * m_client->Observation()->GetAbilityData()[m_observer->Data(*this).buildAbility].footprint_radius);
return (int)(2 * UTData[m_observer->Data(*this).buildAbility].footprint_radius);
}
else
{
......@@ -417,7 +461,14 @@ bool UnitType::isBuilding() const
int UnitType::supplyProvided() const
{
#ifdef SC2API
return (int)m_client->Observation()->GetUnitTypeData()[m_type].food_provided;
auto UTData = m_client->Observation()->GetUnitTypeData();
if (UTData.empty()) // Check to hopefully avoid segfaults
{
BOT_ASSERT(false, "Failed, try with game running!");
return -1;
}
return (int)UTData[m_type].food_provided;
#else
return m_type.supplyProvided();
#endif
......@@ -426,7 +477,14 @@ int UnitType::supplyProvided() const
int UnitType::supplyRequired() const
{
#ifdef SC2API
return (int)m_client->Observation()->GetUnitTypeData()[m_type].food_required;
auto UTData = m_client->Observation()->GetUnitTypeData();
if (UTData.empty()) // Check to hopefully avoid segfaults
{
BOT_ASSERT(false, "Failed, try with game running!");
return -1;
}
return (int)UTData[m_type].food_required;
#else
return m_type.supplyRequired();
#endif
......@@ -435,7 +493,13 @@ int UnitType::supplyRequired() const
int UnitType::mineralPrice() const
{
#ifdef SC2API
return (int)m_client->Observation()->GetUnitTypeData()[m_type].mineral_cost;
auto UTData = m_client->Observation()->GetUnitTypeData();
if (UTData.empty()) // Check to hopefully avoid segfaults
{
BOT_ASSERT(false, "Failed, try with game running!");
return -1;
}
return (int)UTData[m_type].mineral_cost;
#else
return m_type.mineralPrice();
#endif
......@@ -444,7 +508,13 @@ int UnitType::mineralPrice() const
int UnitType::gasPrice() const
{
#ifdef SC2API
return (int)m_client->Observation()->GetUnitTypeData()[m_type].vespene_cost;
auto UTData = m_client->Observation()->GetUnitTypeData();
if (UTData.empty()) // Check to hopefully avoid segfaults
{
BOT_ASSERT(false, "Failed, try with game running!");
return -1;
}
return (int)UTData[m_type].vespene_cost;
#else
return m_type.gasPrice();
#endif
......@@ -536,30 +606,66 @@ bool UnitType::isMorphedBuilding() const
int UnitType::getMovementSpeed() const
{
return m_client->Observation()->GetUnitTypeData()[m_type].movement_speed;
auto UTData = m_client->Observation()->GetUnitTypeData();
if (UTData.empty()) // Check to hopefully avoid segfaults
{
BOT_ASSERT(false, "Failed, try with game running!");
return -1;
}
return UTData[m_type].movement_speed;
}
int UnitType::getSightRange() const
{
return m_client->Observation()->GetUnitTypeData()[m_type].sight_range;
auto UTData = m_client->Observation()->GetUnitTypeData();
if (UTData.empty()) // Check to hopefully avoid segfaults
{
BOT_ASSERT(false, "Failed, try with game running!");
return -1;
}
return UTData[m_type].sight_range;
}
UnitTypeID UnitType::getRequiredStructure() const
{
return m_client->Observation()->GetUnitTypeData()[m_type].tech_requirement;
auto UTData = m_client->Observation()->GetUnitTypeData();
if (UTData.empty()) // Check to hopefully avoid segfaults
{
BOT_ASSERT(false, "Failed, try with game running!");
return UnitTypeID();
}
return UTData[m_type].tech_requirement;
}
std::vector<sc2::UnitTypeID> UnitType::getEquivalentUnits() const
{
return m_client->Observation()->GetUnitTypeData()[m_type].tech_alias;
auto UTData = m_client->Observation()->GetUnitTypeData();
if (UTData.empty()) // Check to hopefully avoid segfaults
{
BOT_ASSERT(false, "Failed, try with game running!");
return std::vector<sc2::UnitTypeID>();
}
return UTData[m_type].tech_alias;
}
bool UnitType::requiredAttached() const
{
return m_client->Observation()->GetUnitTypeData()[m_type].require_attached;
auto UTData = m_client->Observation()->GetUnitTypeData();
if (UTData.empty()) // Check to hopefully avoid segfaults
{
BOT_ASSERT(false, "Failed, try with game running!");
return false;
}
return UTData[m_type].require_attached;
}
float UnitType::getBuildTime() const
{
return m_client->Observation()->GetUnitTypeData()[m_type].build_time;
auto UTData = m_client->Observation()->GetUnitTypeData();
if (UTData.empty()) // Check to hopefully avoid segfaults
{
BOT_ASSERT(false, "Failed, try with game running!");
return -1;
}
return UTData[m_type].build_time;
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment