Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • stebr364/pycommandcenter
  • starcraft-ai-course/pycommandcenter
  • eriah592/pycommandcenter
  • edvbe696/pycommandcenter
  • dawab699/pycommandcenter
  • hanja189/pycommandcenter
  • teoga849/pycommandcenter
  • musab250/pycommandcenter
  • emibr898/pycommandcenter
  • chrgu102/pycommandcenter
  • axega544/pycommandcenter
  • edvth289/pycommandcenter
  • jonbo278/py-command-center-v-2
13 results
Show changes
Showing
with 4294 additions and 737 deletions
#include "library.h"
namespace py = pybind11;
void define_replay_unit(py::module & m)
{
py::class_<ReplayUnit>(m, "ReplayUnit")
.def_property_readonly("id", &ReplayUnit::getID, "The ID of the unit.")
.def_property_readonly("unit_type", &ReplayUnit::getType, "The :class:`commandcenter.UnitType` of the unit.")
.def_property_readonly("position", &ReplayUnit::getPosition, "The :class:`commandcenter.Point2D` of the unit.")
.def_property_readonly("tile_position", &ReplayUnit::getTilePosition, "The :class:`commandcenter.Point2DI` of the unit.")
.def_property_readonly("hit_points", &ReplayUnit::getHitPoints, "The hit points of the unit.")
.def_property_readonly("shields", &ReplayUnit::getShields, "The shields of the unit.")
.def_property_readonly("energy", &ReplayUnit::getEnergy, "The energy of the unit.")
.def_property_readonly("player", &ReplayUnit::getPlayer, "Returns the constant corresponding to player which this unit belongs to. See :ref:`playerconstants` for more information.")
.def_property_readonly("build_percentage", &ReplayUnit::getBuildPercentage, "The build percentage of the unit.")
.def_property_readonly("weapon_cooldown", &ReplayUnit::getWeaponCooldown, "The weapon cooldown of the unit.")
.def_property_readonly("is_completed", &ReplayUnit::isCompleted, "Whether the unit is completed, returns build_progress >= 1.")
.def_property_readonly("is_being_constructed", &ReplayUnit::isBeingConstructed, "Whether the unit is being constructed, returns build_progress > 0.")
.def_property_readonly("is_cloaked", &ReplayUnit::isCloaked, "Whether the unit is cloaked.")
.def_property_readonly("is_flying", &ReplayUnit::isFlying, "Whether the unit is flying.")
.def_property_readonly("buffs", &ReplayUnit::buffs, "Returns a list of BuffIDs representing the buffs on the unit.")
.def_property_readonly("is_alive", &ReplayUnit::isAlive, "Whether the unit is alive.")
.def_property_readonly("is_powered", &ReplayUnit::isPowered, "Whether the unit is powered.")
.def_property_readonly("is_idle", &ReplayUnit::isIdle, "Whether the unit is idle.")
.def_property_readonly("is_burrowed", &ReplayUnit::isBurrowed, "Whether the unit is burrowed.")
.def_property_readonly("is_valid", &ReplayUnit::isValid, "Whether the unit is valid.")
.def_property_readonly("is_training", &ReplayUnit::isTraining, "Whether the unit is training.")
.def_property_readonly("is_blip", &ReplayUnit::isBlip, "Whether the unit is a blip ie a ping on the map.")
.def_property_readonly("target", &ReplayUnit::getTarget, "The target of the unit.")
.def_property_readonly("has_target", &ReplayUnit::hasTarget, "Whether the unit has a target.")
.def_property_readonly("max_hit_points", &ReplayUnit::getMaxHitPoints, "The maximum hit points of the unit.")
.def_property_readonly("progress", &ReplayUnit::getProgress, "Returns the progress of currently used ability (-1 if not using ability).")
.def_property_readonly("current_ability_id", &ReplayUnit::getCurrentAbilityID, "The AbilityID of currently used ability.")
.def_property_readonly("facing", &ReplayUnit::getFacing, "Returns the direction the unit is facing.")
.def_property_readonly("radius", &ReplayUnit::getRadius, "The radius of the unit.")
.def_property_readonly("is_carrying_minerals", &ReplayUnit::isCarryingMinerals, "Whether the unit is carrying minerals.")
.def("__hash__", [](const ReplayUnit & unit) { return std::hash<const sc2::Unit *>{}(unit.getUnitPtr()); })
.def(py::self == py::self)
.def("__repr__", [](const ReplayUnit & unit) { return "<Unit of type: '" + unit.getType().getName() + "'>"; })
.doc() = R"(
The ReplayUnit class is used to represent a unit in a replay of a game.
A ReplayUnit is a :class:`commandcenter.Unit` with some limitations.
It provides various properties and methods to access information about the unit, such as its ID, type, position, hit points, energy, and more.
It is possible to use ReplayUnit as keys in a dictionary, which might be helpful for bookkeeping.
)";
}
This diff is collapsed.
#include "library.h"
namespace py = pybind11;
void define_tech_tree(py::module & m)
{
py::class_<TypeData>(m, "TypeData")
.def_readonly("race", &TypeData::race)
.def_readonly("mineral_cost", &TypeData::mineralCost, "The mineral cost of the item.")
.def_readonly("gas_cost", &TypeData::gasCost, "The gas cost of the item.")
.def_readonly("supply_cost", &TypeData::supplyCost, "The supply cost of the item.")
.def_readonly("build_time", &TypeData::buildTime, "The build time of the item in seconds (should be 32 game updates per tick).")
.def_readonly("is_unit", &TypeData::isUnit, "Whether the item is a unit.")
.def_readonly("is_building", &TypeData::isBuilding, "Whether the item is a building.")
.def_readonly("is_worker", &TypeData::isWorker, "Whether the item is a worker.")
.def_readonly("is_refinery", &TypeData::isRefinery, "Whether the item is a refinery.")
.def_readonly("is_supply_provider", &TypeData::isSupplyProvider, "Whether the item is a supply provider.")
.def_readonly("is_resource_depot", &TypeData::isResourceDepot, "Whether the item is a resource depot.")
.def_readonly("is_addon", &TypeData::isAddon, "Whether the item is an add-on.")
.def_readonly("build_ability", &TypeData::buildAbility, "The ability that creates this item.")
.def_readonly("warp_ability", &TypeData::warpAbility, "The ability that creates this item via warp-in.")
.def_readonly("what_builds", &TypeData::whatBuilds, "The units that can build the item.")
.def_readonly("required_units", &TypeData::requiredUnits, "Owning ONE of these (List[UnitType]) is required to make the item.")
.def_readonly("required_upgrades", &TypeData::requiredUpgrades, "Having ALL of these (List[UPGRADE_ID]) is required to make the item.")
.def_readonly("required_addons", &TypeData::requiredAddons, "A unit of this type (List[UnitType]) must be present next to the producer.")
.doc() = R"(
Allows you to get information about a unit type or upgrade. This is a read-only class.
)";
py::class_<TechTree>(m, "TechTree")
.def("get_data", py::overload_cast<const UnitType &>(&TechTree::getData, py::const_))
.def("get_data", py::overload_cast<const CCUpgrade &>(&TechTree::getData, py::const_), "Argument is either an instance of the class :class:`commandcenter.UnitType` or an instance of the class :class:`commandcenter.CCUpgrade`, depending on what information is wanted.")
.def("suppress_warnings", &TechTree::setSuppressWarnings, "Suppress type and upgrade warnings." ,"b"_a)
.doc() = R"(
This class contains all information about units and what is required to
build a certain unit and what builds it. It only has one method, which is
used to look-up unit types properties.
Instead of using TechTree, it's possible to use the functions in UnitType for
structure, etc. In IDABot there is functions for getting data about upgrades.
)";
}
......@@ -5,39 +5,80 @@ namespace py = pybind11;
void define_unit(py::module & m)
{
py::class_<Unit>(m, "Unit")
.def_property_readonly("unit_type", &Unit::getType)
.def_property_readonly("position", &Unit::getPosition)
.def_property_readonly("tile_position", &Unit::getTilePosition)
.def_property_readonly("hit_points", &Unit::getHitPoints)
.def_property_readonly("shields", &Unit::getShields)
.def_property_readonly("energy", &Unit::getEnergy)
.def_property_readonly("player", &Unit::getPlayer)
.def_property_readonly("id", &Unit::getID)
.def_property_readonly("build_percentage", &Unit::getBuildPercentage)
.def_property_readonly("weapon_cooldown", &Unit::getWeaponCooldown)
.def_property_readonly("completed", &Unit::isCompleted)
.def_property_readonly("being_constructed", &Unit::isBeingConstructed)
.def_property_readonly("cloaked", &Unit::isCloaked)
.def_property_readonly("flying", &Unit::isFlying)
.def_property_readonly("alive", &Unit::isAlive)
.def_property_readonly("powered", &Unit::isPowered)
.def_property_readonly("idle", &Unit::isIdle)
.def_property_readonly("burrowed", &Unit::isBurrowed)
.def_property_readonly("valid", &Unit::isValid)
.def_property_readonly("training", &Unit::isTraining)
.def_property_readonly("constructing", &Unit::isConstructing)
.def("stop", &Unit::stop)
.def("attack_unit", &Unit::attackUnit)
.def("attack_move", &Unit::attackMove)
.def_property_readonly("unit_type", &Unit::getType, "The :class:`commandcenter.UnitType` of the unit.")
.def_property_readonly("position", &Unit::getPosition, "The :class:`commandcenter.Point2D` of the unit.")
.def_property_readonly("tile_position", &Unit::getTilePosition, "The :class:`commandcenter.Point2DI` of the unit.")
.def_property_readonly("hit_points", &Unit::getHitPoints, "Health of the unit.")
.def_property_readonly("shields", &Unit::getShields, "Shield of the unit.")
.def_property_readonly("energy", &Unit::getEnergy, "Energy of the unit.")
.def_property_readonly("player", &Unit::getPlayer, "Returns the constant corresponding to player which this unit belongs to. See :ref:`playerconstants` for more information.")
.def_property_readonly("id", &Unit::getID, "Returns an int to identify the unit. This value does not stay the same for units you lose vision of, so maybe not best idea to use as a way of keeping track of them.")
.def_property_readonly("build_percentage", &Unit::getBuildPercentage, "Gives progress under construction. Range [0.0, 1.0]. 1.0 == finished.")
.def_property_readonly("weapon_cooldown", &Unit::getWeaponCooldown, "Time remaining for a weapon on cooldown.")
.def_property_readonly("is_completed", &Unit::isCompleted, "Returns build_progress >= 1.")
.def_property_readonly("is_being_constructed", &Unit::isBeingConstructed, "Returns (build_progress > 0 and not is_completed).")
.def_property_readonly("is_cloaked", &Unit::isCloaked, "If the unit is cloaked.")
.def_property_readonly("is_flying", &Unit::isFlying, "If the unit is flying.")
.def_property_readonly("buffs", &Unit::buffs, "Returns a list buffs on this unit. Only valid for this player's units.")
.def_property_readonly("is_alive", &Unit::isAlive, "Whether the unit is alive or not.")
.def_property_readonly("is_powered", &Unit::isPowered, "Whether the unit is powered by a pylon.")
.def_property_readonly("is_idle", &Unit::isIdle, "Whether the unit has any orders.")
.def_property_readonly("is_burrowed", &Unit::isBurrowed, "Whether the unit is burrowed.")
.def_property_readonly("is_valid", &Unit::isValid, "Whether the unit is valid")
.def_property_readonly("is_training", &Unit::isTraining, "Returns True if the unit is a building and is training another unit.")
.def_property_readonly("is_blip", &Unit::isBlip, "Returns true if unit is a 'blip' - a ping on the map.")
.def_property_readonly("target", &Unit::getTarget, "Returns target unit if one exists, otherwise return itself.")
.def_property_readonly("has_target", &Unit::hasTarget, "Returns True if the target has a valid target and False otherwise.")
.def_property_readonly("max_hit_points", &Unit::getMaxHitPoints, "Returns the max health.")
.def_property_readonly("progress", &Unit::getProgress, "Returns the progress of currently used ability (-1 if not using ability).")
.def_property_readonly("progression_list", &Unit::getAllProgress, "Returns a list containing the progression on all the processes in order. Empty list if no process exists.")
.def_property_readonly("current_ability_id", &Unit::getCurrentAbilityID, "The AbilityID of currently used ability.")
.def_property_readonly("facing", &Unit::getFacing, "Direction the unit faces in radians (1 radian == 57.296 degrees).")
.def_property_readonly("radius", &Unit::getRadius, "Returns the radius of the unit.")
.def_property_readonly("is_carrying_minerals", &Unit::isCarryingMinerals, "Returns if this unit is currently holding minerals.")
.def_property_readonly("is_carrying_gas", &Unit::isCarryingGas, "Returns if this unit is currently holding gas.")
.def_property_readonly("gas_left_in_refinery", &Unit::gasLeftInGeyser, "Amount of vespene left in the the refinery.")
.def_property_readonly("minerals_left_in_mineralfield", &Unit::mineralsLeftInMineralfield, "Amount of minerals if the unit is a mineral field.")
.def_property_readonly("owner", &Unit::getOwner, "Which player owns a unit. Not same as player; 'player' originates from IDA implementation whilst 'owner' originates from StarCraft II.")
.def_property_readonly("max_shields", &Unit::maxShields, "Max shield of the unit.")
.def_property_readonly("max_energy", &Unit::maxEnergy, "Max energy of the unit.")
.def("hold_position", &Unit::holdPosition, "Unit will hold its position.")
.def("patrol", py::overload_cast<const CCPosition &>(&Unit::patrol, py::const_), "Unit will patrol back and forth from its current location to the given Point2D.")
.def("stop_dance", &Unit::stopDance, "Unit will Stop and dance.")
.def("stop", &Unit::stop, "Unit will stop.")
.def("attack_unit", &Unit::attackUnit, "Unit will attack the provided unit.")
.def("attack_move", &Unit::attackMove, "Moves to provided Point2D location. If an enemy is seen on the way it will try to attack it. Will chase after the enemy as long as it is visible.")
.def("ability", py::overload_cast<sc2::AbilityID>(&Unit::ability, py::const_))
.def("ability", py::overload_cast<sc2::AbilityID, const CCPosition &>(&Unit::ability, py::const_))
.def("ability", py::overload_cast<sc2::AbilityID, const Unit &>(&Unit::ability, py::const_), "Call an ability directly, different abilities has different targets. Some target the unit itself (no argument), target a point (Point2D as argument) and some target a Unit (instance of Unit as argument).")
.def("move", py::overload_cast<const CCPosition &>(&Unit::move, py::const_))
.def("move", py::overload_cast<const CCTilePosition &>(&Unit::move, py::const_))
.def("right_click", &Unit::rightClick)
.def("repair", &Unit::repair)
.def("build", &Unit::build)
.def("build_target", &Unit::buildTarget)
.def("train", &Unit::train)
.def("morph", &Unit::morph)
.def("__hash__", [](const Unit & unit) { return std::hash<CCUnitID>{}(unit.getID()); })
.def("move", py::overload_cast<const CCTilePosition &>(&Unit::move, py::const_), "Move the unit to the given point, the point being an instance of either :class:`commandcenter.Point2D` or :class:`commandcenter.Point2DI`.")
.def("right_click", &Unit::rightClick, "Same as right-clicking in the game, for example making workers mine minerals.")
.def("repair", &Unit::repair, "Right-clicks on the provided unit in order to repair it.")
.def("build", &Unit::build, "Build unit of type building_type at given position.", "building_type"_a, "position"_a)
.def("build_target", &Unit::buildTarget, "Build building_type on top of target Unit, useful for building refineries.", "building_type"_a, "target"_a)
.def("train", &Unit::train, "Train unit of type.", "unit_type"_a)
.def("morph", &Unit::morph, "Morph into type of unit_type.", "unit_type"_a)
.def("research", &Unit::research, "Research the given :class:`commandcenter.UPGRADE_ID`.", "upgrade_id"_a)
.def("is_constructing", &Unit::isConstructing, "unit_type"_a, "Returns true if the unit is currently constructing another unit of type `unit_type`. Note that `unit_type` needs to be an instance of :class:`commandcenter.UnitType`.")
.def("__hash__", [](const Unit & unit) { return std::hash<const sc2::Unit *>{}(unit.getUnitPtr()); })
.def(py::self == py::self)
.def("__repr__", [](const Unit & unit) { return "<Unit of type: '" + unit.getType().getName() + "'>"; });
.def("__repr__", [](const Unit & unit) { return "<Unit of type: '" + unit.getType().getName() + "'>"; })
.doc() = R"(
An instance of the class Unit represents one unit in the game. The units are
not limited to moveable units, but every entity which is not part of the
background is a unit. For example, the minerals and geysers are units as
well as all buildings.
For all possible types of units see the enum :class:`commandcenter.UNIT_TYPEID`.
Some types of objects are almost the same, for example there are many types
of mineral deposits, but all of them are mineable. This is one of the
motivations behind the :class:`commandcenter.UnitType` which aims to to make the
list of types more manageable. The UnitType can be accessed by the
:any:`Unit.unit_type` property.
It is possible to use Unit as keys in a dictionary, which might be helpful
for bookkeeping.
)" ;
}
......@@ -5,40 +5,60 @@ namespace py = pybind11;
void define_unittype(py::module & m)
{
py::class_<UnitType>(m, "UnitType")
.def(py::init<const sc2::UnitTypeID &, IDABot &>())
.def("is", &UnitType::is, "Check if UnitType is UnitTypeID")
.def(py::self == py::self)
.def_property_readonly("name", &UnitType::getName)
.def_property_readonly("race", &UnitType::getRace)
.def_property_readonly("is_valid", &UnitType::isValid)
.def_property_readonly("is_building", &UnitType::isBuilding)
.def_property_readonly("is_combat_unit", &UnitType::isCombatUnit)
.def_property_readonly("is_supply_provider", &UnitType::isSupplyProvider)
.def_property_readonly("is_resource_depot", &UnitType::isResourceDepot)
.def_property_readonly("is_refinery", &UnitType::isRefinery)
.def_property_readonly("is_detector", &UnitType::isDetector)
.def_property_readonly("is_geyser", &UnitType::isGeyser)
.def_property_readonly("is_mineral", &UnitType::isMineral)
.def_property_readonly("is_worker", &UnitType::isWorker)
.def_property_readonly("is_morphed_building", &UnitType::isMorphedBuilding)
.def(py::init([](const sc2::UnitTypeID & type, IDABot & bot) {
return UnitType(type, bot, bot);
}))
.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 string.")
.def_property_readonly("race", &UnitType::getRace, "The race the unit belongs to.")
.def_property_readonly("movement_speed", &UnitType::getMovementSpeed, "Movement speed of unit type.")
.def_property_readonly("sight_range", &UnitType::getSightRange, "Range the unit reveals vision.")
.def_property_readonly("required_structure", &UnitType::getRequiredStructure, "Structure required to build this unit. (Or any with the same tech_alias.)")
.def_property_readonly("is_valid", &UnitType::isValid, "Its a valid unit type.")
.def_property_readonly("is_building", &UnitType::isBuilding, "Is this unit type a building or not.")
.def_property_readonly("is_combat_unit", &UnitType::isCombatUnit, "The unit is not any of the following, worker, supply provider, building, larva, egg.")
.def_property_readonly("is_supply_provider", &UnitType::isSupplyProvider, "The unit provides supply.")
.def_property_readonly("is_resource_depot", &UnitType::isResourceDepot, "The unit is one of the following, hatchery, lair, hive, commandcenter, orbialtcommand, planetaryfortress, nexus.")
.def_property_readonly("is_refinery", &UnitType::isRefinery, "The unit is one of the following (depending on race), refinery, assimilator, extractor.")
.def_property_readonly("is_detector", &UnitType::isDetector, "Is this a unit type which is a detector unit.")
.def_property_readonly("is_geyser", &UnitType::isGeyser, "Is the unit type a geyser.")
.def_property_readonly("is_mineral", &UnitType::isMineral, "Is the unit type a mineralfield.")
.def_property_readonly("is_worker", &UnitType::isWorker, "Is the unit type a unit which is a worker.")
.def_property_readonly("is_morphed_building", &UnitType::isMorphedBuilding, "Has this building been morphed.")
// Not implemented in CommandCenter
//.def_property_readonly("can_attack", &UnitType::canAttack)
//.def_property_readonly("can_Move", &UnitType::canMove)
.def_property_readonly("is_addon", &UnitType::isAddon)
.def_property_readonly("attack_range", &UnitType::getAttackRange)
.def_property_readonly("tile_width", &UnitType::tileWidth)
.def_property_readonly("tile_height", &UnitType::tileHeight)
.def_property_readonly("supply_provided", &UnitType::supplyProvided)
.def_property_readonly("supply_required", &UnitType::supplyRequired)
.def_property_readonly("mineral_price", &UnitType::mineralPrice)
.def_property_readonly("gas_price", &UnitType::gasPrice)
.def_property_readonly("is_overlord", &UnitType::isOverlord)
.def_property_readonly("is_larva", &UnitType::isLarva)
.def_property_readonly("is_egg", &UnitType::isEgg)
.def_property_readonly("is_queen", &UnitType::isQueen)
.def_property_readonly("is_tank", &UnitType::isTank)
.def("__repr__", [](const UnitType & unit_type) { return "<UnitType: '" + unit_type.getName() + "'>"; });
.def_property_readonly("is_addon", &UnitType::isAddon, "Is this unit type a add-on.")
.def_property_readonly("can_attack_ground", &UnitType::canAttackGound, "True if this unit can attack ground units.")
.def_property_readonly("can_attack_air", &UnitType::canAttackAir, "True if this unit can attack air units.")
.def_property_readonly("attack_range", &UnitType::getAttackRange, "Returns the attack range of the unit type.")
.def_property_readonly("attack_damage", &UnitType::getAttackDamage, "Returns the base attack damage of the unit type.")
.def_property_readonly("tile_width", &UnitType::tileWidth, "Returns the width of the unit type.")
.def_property_readonly("tile_height", &UnitType::tileHeight, "Returns the height of the unit type.")
.def_property_readonly("supply_provided", &UnitType::supplyProvided, "Amount of supply provided by the unit type.")
.def_property_readonly("supply_required", &UnitType::supplyRequired, "Amount of supply required for the unit type.")
.def_property_readonly("mineral_price", &UnitType::mineralPrice, "Mineral price of the unit type.")
.def_property_readonly("gas_price", &UnitType::gasPrice, "Gas price of the unit type.")
.def_property_readonly("is_overlord", &UnitType::isOverlord, "Is this a ZERG_OVERLORD.")
.def_property_readonly("is_larva", &UnitType::isLarva, "is this a ZERG_LARVA.")
.def_property_readonly("is_egg", &UnitType::isEgg, "is this a ZERG_EGG.")
.def_property_readonly("is_queen", &UnitType::isQueen, "is this a ZERG_QUEEN.")
.def_property_readonly("is_tank", &UnitType::isTank, "is this a TERRAN_SIEGETANK or TERRAN_SIEGETANKSIEGED.")
.def_property_readonly("get_equivalent_units", &UnitType::getEquivalentUnits, "Units this is equivalent to in terms of satisfying tech requirements.")
.def_property_readonly("required_attached", &UnitType::requiredAttached, "Whether tech_requirement is an add-on.")
.def_property_readonly("build_time", &UnitType::getBuildTime, "How long the unit takes to build.")
.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:`commandcenter.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
//.def("whatBuilds", &UnitType::whatBuilds);
}
\ No newline at end of file
}
......@@ -7,7 +7,7 @@ void define_util(py::module & mod)
py::module m = mod.def_submodule("util");
/*
TODO:
TODO: Implement and document these functions
Maybe should be included in Point instead?
CCTilePosition GetTilePosition(const CCPosition & pos);
CCPosition GetPosition(const CCTilePosition & tile);
......@@ -22,4 +22,7 @@ void define_util(py::module & mod)
m.def("dist", py::overload_cast<const Unit &, const Unit &>(&Util::Dist));
m.def("dist", py::overload_cast<const Unit &, const CCPosition &>(&Util::Dist));
m.def("dist", py::overload_cast<const CCPosition &, const CCPosition &>(&Util::Dist));
m.doc() = R"(
The util module provides utility functions for the library.
)";
}
\ No newline at end of file
......@@ -2,63 +2,214 @@
namespace py = pybind11;
PYBIND11_MODULE(library, m)
PYBIND11_MODULE(commandcenter, m)
{
m.doc() = "Python API for playing Starcraft II";
define_typeenums(m);
define_unit(m);
define_replay_unit(m);
define_unittype(m);
define_util(m);
define_point(m);
define_base_location(m);
define_tech_tree(m);
define_color(m);
define_map_tools(m);
define_building_placer(m);
// Note: This is not sc2::Coordinator but a small wrapper class which
// overrides the constructor of sc2::Coordinator, see library.h.
py::class_<Coordinator>(m, "Coordinator")
.def(py::init())
.def("set_participants", &sc2::Coordinator::SetParticipants)
.def(py::init<std::string>())
.def("set_participants", &sc2::Coordinator::SetParticipants, "participants"_a)
.def("launch_starcraft", &sc2::Coordinator::LaunchStarcraft)
.def("start_game", &sc2::Coordinator::StartGame)
.def("update", &sc2::Coordinator::Update);
.def("start_game", &sc2::Coordinator::StartGame, "map_path"_a)
.def("connect", &sc2::Coordinator::Connect, "port"_a)
.def("update", &sc2::Coordinator::Update)
.def("all_games_ended", &sc2::Coordinator::AllGamesEnded)
.def("join_game", &sc2::Coordinator::JoinGame)
.def("set_real_time", &sc2::Coordinator::SetRealtime)
.def("load_replay_list",&sc2::Coordinator::SetReplayPath, "replay_path"_a)
.def("add_replay_observer",&sc2::Coordinator::AddReplayObserver, "replay_observer"_a)
.def("set_replay_perspective",&sc2::Coordinator::SetReplayPerspective, "perspective"_a)
.def("leave_game", &sc2::Coordinator::LeaveGame)
.doc() = R"(
The Coordinator class is a wrapper class that provides a simplified interface for managing and controlling Starcraft II games. It allows you to set up game parameters, launch the Starcraft II application, start a game on a specific map, connect to the game, update the game state, and perform various game-related actions.
Here are some key functionalities provided by the Coordinator class:
py::enum_<sc2::Race>(m, "Race")
* Initialization: The Coordinator class has multiple constructors that allow you to create an instance of the class. You can initialize it without any arguments or provide a string argument representing the path to the Starcraft II executable.
* Setting Participants: You can use the set_participants method to set the participants for the game. This method takes a list of participants as an argument, where each participant is defined by their race and other relevant information.
* Launching Starcraft II: The launch_starcraft method launches the Starcraft II application.
* Starting a Game: The start_game method starts a game on a specific map. You need to provide the path to the map as an argument.
* Connecting to the Game: The connect method allows you to connect to the game by specifying the port number.
* Updating the Game State: The update method updates the game state, including the positions and statuses of units, resources, and other game elements.
* Game Control: The all_games_ended method checks if all games have ended. The join_game method allows you to join a game. The set_real_time method sets the game to real-time mode. The leave_game method allows you to leave the current game.
These are just some of the methods provided by the Coordinator class. It serves as a central control point for managing Starcraft II games and provides an interface for interacting with the game engine.
)";
py::enum_<sc2::Race>(m, "Race", "The Race enum in the provided code represents the different races in the Starcraft II game. It is used to define the race of a player or a unit. \
In Starcraft II, each race has its own unique units, buildings, and abilities. The Race enum allows you to specify the race of a player or a unit, which can be useful for various game-related operations and strategies. \
For example, if you want to set the race of a player to Terran, you can use the Race.Terran value. Similarly, if you want to check the race of a unit, you can compare its race with the enum values.")
.value("Terran", sc2::Race::Terran)
.value("Zerg", sc2::Race::Zerg)
.value("Protoss", sc2::Race::Protoss)
.value("Random", sc2::Race::Random);
//DON'T USE .doc on enum
// Stupid anonymous enum, used as int everywhere. Best work-around I could think of.
py::module players = m.def_submodule("Players", "Constants for referring to players");
players.attr("Self") = (int) Players::Self;
players.attr("Enemy") = (int) Players::Enemy;
players.attr("Neutral") = (int) Players::Neutral;
players.attr("Ally") = (int) Players::Ally;
players.attr("Size") = (int) Players::Size; // These are probably used for
players.attr("None") = (int) Players::None; // creating arrays of fixed length??
m.attr("PLAYER_SELF") = py::int_((int) Players::Self);
m.attr("PLAYER_ENEMY") = py::int_((int) Players::Enemy);
m.attr("PLAYER_NEUTRAL") = py::int_((int) Players::Neutral);
m.attr("PLAYER_ALLY") = py::int_((int) Players::Ally);
/*
TODO: These also needs to be defined
py::class_<sc2::BuffID>(m, "BuffID")
.def(py::init<sc2::BUFF_ID>())
.doc() = R"(
The BuffID class is a wrapper class that represents the BuffID enum in the Starcraft II game. It is used to define the different buffs that can be applied to units in the game.
In Starcraft II, buffs are temporary effects that modify the behavior or attributes of units. The BuffID class allows you to specify a particular buff by its ID, which can be useful for various game-related operations and strategies.
For example, if you want to apply a specific buff to a unit, you can use the BuffID class to represent the buff and apply it to the unit. Similarly, if you want to check if a unit has a particular buff, you can compare its ID with the enum values.
)";
py::implicitly_convertible<sc2::BUFF_ID, sc2::BuffID>();
typedef SC2Type<ABILITY_ID> AbilityID;
typedef SC2Type<UPGRADE_ID> UpgradeID;
typedef SC2Type<BUFF_ID> BuffID;
*/
py::class_<sc2::UnitTypeID>(m, "UnitTypeID")
.def(py::init<sc2::UNIT_TYPEID>());
.def(py::init<sc2::UNIT_TYPEID>())
.def("__eq__", [](const sc2::UnitTypeID &value, sc2::UNIT_TYPEID &value2) { return value == value2; })
.doc() = R"(
The UnitTypeID class is a wrapper class that represents the UnitTypeID enum in the Starcraft II game. It is used to define the different types of units that exist in the game.
In Starcraft II, each unit has a unique type ID that identifies its unit type. The UnitTypeID class allows you to specify a particular unit type by its ID, which can be useful for various game-related operations and strategies.
For example, if you want to create a specific unit, you can use the UnitTypeID class to represent the unit type and create the unit. Similarly, if you want to check the type of a unit, you can compare its ID with the enum values.
)";
py::implicitly_convertible<sc2::UNIT_TYPEID, sc2::UnitTypeID>();
py::class_<sc2::UpgradeID>(m, "UpgradeID")
.def(py::init<sc2::UPGRADE_ID>())
.doc() = R"(
The UpgradeID class is a wrapper class that represents the UpgradeID enum in the Starcraft II game. It is used to define the different upgrades that can be researched in the game.
In Starcraft II, upgrades are enhancements that improve the attributes or abilities of units and buildings. The UpgradeID class allows you to specify a particular upgrade by its ID, which can be useful for various game-related operations and strategies.
For example, if you want to research a specific upgrade, you can use the UpgradeID class to represent the upgrade and research it. Similarly, if you want to check if a unit or building has a particular upgrade, you can compare its ID with the enum values.
)";
py::implicitly_convertible<sc2::UPGRADE_ID, sc2::UpgradeID>();
py::class_<sc2::EffectID>(m, "EffectID")
.def(py::init<sc2::EFFECT_ID>())
.doc() = R"(
The EffectID class is a wrapper class that represents the EffectID enum in the Starcraft II game. It is used to define the different effects that can be applied to units or abilities in the game.
In Starcraft II, effects are special abilities or attributes that modify the behavior or properties of units or abilities. The EffectID class allows you to specify a particular effect by its ID, which can be useful for various game-related operations and strategies.
For example, if you want to apply a specific effect to a unit or ability, you can use the EffectID class to represent the effect and apply it. Similarly, if you want to check if a unit or ability has a particular effect, you can compare its ID with the enum values.
)";
py::implicitly_convertible<sc2::EFFECT_ID, sc2::EffectID>();
py::class_<sc2::AbilityID>(m, "AbilityID")
.def(py::init<sc2::ABILITY_ID>())
.doc() = R"(
The AbilityID class is a wrapper class that represents the AbilityID enum in the Starcraft II game. It is used to define the different abilities that units and buildings can use in the game.
In Starcraft II, abilities are special actions or commands that units and buildings can perform. The AbilityID class allows you to specify a particular ability by its ID, which can be useful for various game-related operations and strategies.
For example, if you want to use a specific ability with a unit or building, you can use the AbilityID class to represent the ability and use it. Similarly, if you want to check if a unit or building has a particular ability, you can compare its ID with the enum values.
)";
py::implicitly_convertible<sc2::ABILITY_ID, sc2::AbilityID>();
py::implicitly_convertible<sc2::AbilityID, sc2::ABILITY_ID>();
py::class_<sc2::Agent>(m, "Agent")
.def(py::init());
// IDABot is a specialization of Agent
py::class_<IDABot, PyIDABot, sc2::Agent>(m, "IDABot")
.def(py::init())
.def("OnGameStart", &IDABot::OnGameStart)
.def("OnStep", &IDABot::OnStep)
.def("OnStep_UpdateIDABot", &IDABot::OnStep_UpdateIDABot)
.def("get_all_units", &IDABot::GetAllUnits)
.def("get_my_units", &IDABot::GetMyUnits)
.def_property_readonly("base_manager", &IDABot::Bases);
py::class_<IDABot, PyIDABot, sc2::Agent>(m, "IDABot")
.def(py::init())
.def("on_game_start", &IDABot::OnGameStart, R"(The on_game_start function is a method defined in the IDABot class. It is called when a game starts in Starcraft II.
This function is responsible for initializing the bot and performing any necessary setup before the game begins.
This can include setting up initial game state, gathering information about the map and opponents, and making any initial decisions or strategies.)")
.def("on_step", &IDABot::OnStep, R"(The on_step function in the IDABot class is a method that is called every game step (or frame) during a Starcraft II match.
This function is crucial for implementing the bot's logic that needs to be executed continuously throughout the game.
It's where the bot evaluates the current game state, makes decisions, and issues commands to units.)")
.def("on_game_end", &IDABot::OnGameEnd, R"(The on_game_end function is a method defined in the IDABot class. It is called when a game ends in Starcraft II.
This function can for example be used to save a replay and log performance information.)")
.def("send_chat", &IDABot::SendChat, "Sends the string 'message' to the game chat.", "message"_a)
.def("get_all_units", &IDABot::GetAllUnits, "Returns a list of all visible units, including minerals and geysers.")
.def("get_my_units", &IDABot::GetMyUnits, "Returns a list of all your units.")
.def("get_player_race", &IDABot::GetPlayerRace, "Returns the players race, useful if you play Race.Random.")
.def("debug_create_unit", &IDABot::DebugCreateUnit, "This method creates the nr (INT) of units on the position :class:`commandcenter.Point2D`, the unit belongs to the Player Constant.", "unit_type"_a, "p"_a, "player_id"_a = 0, "count"_a = 1)
.def("debug_kill_unit", &IDABot::DebugKillUnit, "Kill the unit from debug mode.")
.def("debug_show_map", &IDABot::DebugShowMap, "Show the entire map through debug mode.")
.def("debug_fast_build", &IDABot::DebugFastBuild, "Set build time in game to 1 through debug mode.")
.def("debug_enemy_control", &IDABot::DebugEnemyControl, "Control the enemy through debug mode.")
.def("debug_ignore_food", &IDABot::DebugIgnoreFood, "Ignore the food in game through debug mode.")
.def("debug_ignore_resource_cost", &IDABot::DebugIgnoreResourceCost, "Ignore the resource cost in game, making, everything cost zero resources through debug mode.")
.def("debug_give_all_resources", &IDABot::DebugGiveAllResources, "Set the mineral and vespene gas to 5000 through debug mode.")
.def("debug_god_mode", &IDABot::DebugGodMode, "Give the player god mode.")
.def("debug_ignore_mineral", &IDABot::DebugIgnoreMineral, "Ignore the mineral cost in game through debug mode.")
.def("debug_no_cooldowns", &IDABot::DebugNoCooldowns, "Deactive cooldowns (Basically setting them to 0) through debug mode.")
.def("debug_give_all_tech", &IDABot::DebugGiveAllTech, "Give all the tech to the player through debug mode.")
.def("debug_give_all_upgrades", &IDABot::DebugGiveAllUpgrades, "Give all the upgrades to the player through debug mode.")
.def("debug_set_score", &IDABot::DebugSetScore, "Set the Players score in game through debug mode.")
.def("debug_end_game", &IDABot::DebugEndGame, "End the game through debug mode. If the Boolean is True then victory. If False, defeat.")
.def("debug_set_energy", &IDABot::DebugSetEnergy, "Set the energy on a unit through debug mode.")
.def("debug_set_life", &IDABot::DebugSetLife, "Set the life on a unit through debug mode.")
.def("debug_set_shields", &IDABot::DebugSetShields, "Set the shields on a unit through debug mode.")
.def("get_enemy_base_location", &IDABot::GetEnemyBaseLocations, "Return the CCposition of the enemy base.")
.def("move_camera", &IDABot::CameraMove, "Move the camera to the position.", "p"_a)
.def("has_creep", &IDABot::HasCreep, "Returns true if there is creep at position p.", "p"_a)
.def("ability_for_upgrade", &IDABot::abilityForUpgrade, "Ability that researches this upgrade.", "upgrade"_a)
.def("upgrade_mineral_cost", &IDABot::UpgradeMineralCost, "Mineral cost of researching the upgrade.", "upgrade"_a)
.def("upgrade_gas_cost", &IDABot::UpgradeGasCost, "Vespene/gas cost of researching the upgrade.", "upgrade"_a)
.def("upgrade_research_time", &IDABot::UpgradeResearchTime, "Time in GameLoops to research this upgrade.", "upgrade"_a)
.def("effect_radius", &IDABot::RadiusEffect, "Size of the circle the effect impacts.", "effect"_a)
.def("save_replay", &IDABot::SaveReplay, "Saves the game as an SC2Replay. Returns whether successful.", "path"_a)
.def_property_readonly("base_location_manager", &IDABot::Bases, "An instance of the class :class:`commandcenter.BaseLocationManager`. ")
.def_property_readonly("tech_tree", &IDABot::GetTechTree, "An instance of the class :class:`commandcenter.TechTree`.")
.def_property_readonly("map_tools", &IDABot::Map, "An instance of the class :class:`commandcenter.MapTools`.")
.def_property_readonly("building_placer", &IDABot::GetBuildingPlacer, "An instance of the class :class:`commandcenter.BuildingPlacer`.")
.def_property_readonly("start_location", &IDABot::GetStartLocation, "CCPosition representing the start location, note that it is the depot position that is returned.")
.def_property_readonly("start_locations", &IDABot::GetStartLocations, "List of CCPositions representing the start locations, note that it is the depot positions and not the center positions.")
.def_property_readonly("minerals", &IDABot::GetMinerals, "How much minerals we currently have.")
.def_property_readonly("current_supply", &IDABot::GetCurrentSupply, "How much supply we are currently using.")
.def_property_readonly("max_supply", &IDABot::GetMaxSupply, "How much supply we can currently use.")
.def_property_readonly("gas", &IDABot::GetGas, "How much gas we currently have.")
.def_property_readonly("current_frame", &IDABot::GetCurrentFrame, "Which frame we are currently on.")
.def_property_readonly("score", &IDABot::GetScore, "The current score.")
.def_property_readonly("player_result", &IDABot::GetPlayerResults, "The match result for the player.")
.doc() = R"(This is a stripped-down version of a bot. It contains all available managers and basic methods.)";
// API extended summer 2020
py::class_<sc2::ReplayObserver>(m, "ReplayObserver")
.def(py::init());
py::class_<IDAReplayObserver, PyReplayObserver, sc2::ReplayObserver>(m, "IDAReplayObserver")
.def(py::init())
.def("on_game_start", &IDAReplayObserver::OnGameStart)
.def("on_step", &IDAReplayObserver::OnStep)
.def("on_game_end", &IDAReplayObserver::OnGameEnd)
.def("get_all_units", &IDAReplayObserver::GetAllUnits, "Returns a list of all units")
.def("get_player_race", &IDAReplayObserver::GetPlayerRace,"player_id"_a)
.def("get_replay_path", &IDAReplayObserver::GetReplayPath)
.def("get_result_for_player", &IDAReplayObserver::GetResultForPlayer, "player_id"_a)
.def("on_unit_destroyed", &IDAReplayObserver::OnReplayUnitDestroyed, "unit"_a)
.def("on_unit_created", &IDAReplayObserver::OnReplayUnitCreated, "unit"_a)
.def_property_readonly("tech_tree", &IDAReplayObserver::GetTechTree)
;
py::enum_<sc2::GameResult>(m, "GameResult")
.value("Win", sc2::GameResult::Win)
.value("Loss", sc2::GameResult::Loss)
.value("Tie", sc2::GameResult::Tie)
.value("Undecided", sc2::GameResult::Undecided);
py::class_<sc2::PlayerSetup>(m, "PlayerSetup");
......@@ -74,6 +225,30 @@ PYBIND11_MODULE(library, m)
.value("CheatMoney", sc2::Difficulty::CheatMoney)
.value("CheatInsane", sc2::Difficulty::CheatInsane);
m.def("create_participants", &sc2::CreateParticipant, "Create participant from agent");
m.def("create_computer", &sc2::CreateComputer, "Create participant from built-in Starcraft computer");
py::enum_<sc2::AIBuild>(m, "AIBuild")
.value("RandomBuild", sc2::AIBuild::RandomBuild)
.value("Rush", sc2::AIBuild::Rush)
.value("Timing", sc2::AIBuild::Timing)
.value("Power", sc2::AIBuild::Power)
.value("Macro", sc2::AIBuild::Macro)
.value("Air", sc2::AIBuild::Air);
m.def("create_participants", &sc2::CreateParticipant, "Create participant from bot", "race"_a, "bot"_a, "player_name"_a = "");
m.def("create_computer", &sc2::CreateComputer, "Create participant from built-in Starcraft computer", "race"_a, "difficulty"_a, "ai_build"_a = sc2::AIBuild::RandomBuild, "player_name"_a = "");
/*
py::class_<BuildDescription>(m, "BuildDescription")
.def(py::init())
.def_readwrite("producer_type", &BuildDescription::producer_type)
.def_readwrite("result_type", &BuildDescription::result_type)
.def_readwrite("ability_used", &BuildDescription::ability_used)
.def_readwrite("buildings_needed", &BuildDescription::buildings_needed)
.def_readwrite("addons_needed", &BuildDescription::addons_needed);
py::class_<TechTreeImproved>(m, "TechTreeImproved")
.def(py::init())
.def("load_data", &TechTreeImproved::LoadData)
.def("how_to_build", &TechTreeImproved::HowToBuild);
*/
}
......@@ -3,20 +3,38 @@
#include <pybind11/pybind11.h>
#include <sc2api/sc2_api.h>
#include "../src/IDABot.h"
#include "../src/IDAReplayObserver.h"
#include <iostream>
#include <pybind11/stl.h> /* Automatic conversion from std::vector to Python lists */
#include <pybind11/operators.h> /* Convenient operator support */
// Lets us use "x"_a instead of py::arg("x"), great.
using namespace pybind11::literals;
// Wrapper class since the initialization uses pure argc/argv and these cannot be wrapped into Python correctly
class Coordinator : public sc2::Coordinator
{
public:
// TODO: We might not always want default value when we run on Linux
Coordinator() : sc2::Coordinator()
{
char *argv[] = { "executable", NULL};
int argc = sizeof(argv) / sizeof(char*) - 1;
LoadSettings(argc, argv);
std::vector<std::string> arguments = { "pycommandcenter" };
CustomLoadSettings(arguments);
}
Coordinator(std::string path) : sc2::Coordinator()
{
std::vector<std::string> arguments = { "pycommandcenter", "-e", path };
CustomLoadSettings(arguments);
}
void CustomLoadSettings(std::vector<std::string> arguments)
{
std::vector<char*> argv;
for (const auto& arg : arguments)
argv.push_back((char*)arg.data());
argv.push_back(nullptr);
LoadSettings(argv.size() - 1, argv.data());
}
};
......@@ -26,35 +44,99 @@ public:
using IDABot::IDABot;
void OnGameStart() override
{
PYBIND11_OVERLOAD(
PYBIND11_OVERLOAD_NAME(
void,
IDABot,
"on_game_start",
OnGameStart
);
}
void OnStep() override
{
PYBIND11_OVERLOAD(
PYBIND11_OVERLOAD_NAME(
void,
IDABot,
"on_step",
OnStep
);
}
void OnStep_UpdateIDABot() override
{
PYBIND11_OVERLOAD(
void,
IDABot,
OnStep_UpdateIDABot
);
}
void OnGameEnd() override
{
PYBIND11_OVERLOAD_NAME(
void,
IDABot,
"on_game_end",
OnGameEnd
);
}
};
class PyReplayObserver : public IDAReplayObserver
{
public:
using IDAReplayObserver::IDAReplayObserver;
void OnGameStart() override
{
PYBIND11_OVERLOAD_NAME(
void,
IDAReplayObserver,
"on_game_start",
OnGameStart
);
}
void OnStep() override
{
PYBIND11_OVERLOAD_NAME(
void,
IDAReplayObserver,
"on_step",
OnStep
);
}
void OnGameEnd() override
{
PYBIND11_OVERLOAD_NAME(
void,
IDAReplayObserver,
"on_game_end",
OnGameEnd
);
}
void OnReplayUnitDestroyed(const ReplayUnit *unit) override
{
PYBIND11_OVERLOAD_NAME(
void,
IDAReplayObserver,
"on_unit_destroyed",
OnReplayUnitDestroyed,
unit
);
}
void OnReplayUnitCreated(const ReplayUnit *unit) override
{
PYBIND11_OVERLOAD_NAME(
void,
IDAReplayObserver,
"on_unit_created",
OnReplayUnitCreated,
unit
);
}
};
// The functions below are all defined in different .cpp files, in order
// to keep compilation snappy
void define_typeenums(pybind11::module & m);
void define_unit(pybind11::module & m);
void define_replay_unit(pybind11::module & m);
void define_unittype(pybind11::module &m);
void define_util(pybind11::module &m);
void define_point(pybind11::module &m);
void define_base_location(pybind11::module & m);
\ No newline at end of file
void define_base_location(pybind11::module & m);
void define_tech_tree(pybind11::module & m);
void define_color(pybind11::module & m);
void define_map_tools(pybind11::module & m);
void define_building_placer(pybind11::module & m);
alabaster==0.7.16
Babel==2.15.0
certifi==2024.6.2
charset-normalizer==3.3.2
docutils==0.21.2
idna==3.7
imagesize==1.4.1
Jinja2==3.1.4
MarkupSafe==2.1.5
mypy==1.10.0
mypy-extensions==1.0.0
packaging==24.1
Pygments==2.18.0
requests==2.32.3
snowballstemmer==2.2.0
Sphinx==7.3.7
sphinx_design==0.6.0
sphinxcontrib-applehelp==1.0.8
sphinxcontrib-devhelp==1.0.6
sphinxcontrib-htmlhelp==2.0.5
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==1.0.7
sphinxcontrib-serializinghtml==1.1.10
typing_extensions==4.12.2
urllib3==2.2.2
mkdir build
cd build
"C:\Program Files\CMake\bin\cmake" .. -G "Visual Studio 17 2022" -DPYTHON_EXECUTABLE:FILEPATH="C:/Program Files/Python312/python.exe"
"C:\Program Files\CMake\bin\cmake.exe" --build . --config Release --verbose
#!/bin/sh
mkdir build
cd build
"C:\Program Files\CMake\bin\cmake.exe" -G "Visual Studio 17 2022" -DPYTHON_EXECUTABLE:FILEPATH="C:/Program Files/Python312/python.exe" ..
"C:\Program Files\CMake\bin\cmake.exe" --build . --config Release --verbose
#!/bin/sh
mkdir build37
cd build37
"C:\Program Files\CMake\bin\cmake" .. -G "Visual Studio 15 Win64" -DPYTHON_EXECUTABLE:FILEPATH="C:/Program Files/Python37/python.exe"
#!/bin/sh
mkdir build38
cd build38
"C:\Program Files\CMake\bin\cmake" .. -G "Visual Studio 15 Win64" -DPYTHON_EXECUTABLE:FILEPATH="C:/Program Files/Python38/python.exe"
#!/bin/sh
mkdir build
cd build
"C:\Program Files\CMake\bin\cmake" .. -G "Visual Studio 15 Win64" -DPYTHON_EXECUTABLE:FILEPATH="C:/Program Files/Python39/python.exe"
"""
This file inserts the docs of each class and method into the pyi file for autocompletetion.
Before running make sure you have created the pyi according to the README.
You might need to change the pyi_path.
Then simply run this file.
After running all the docs should have been inserted.
Now you're done and can enjoy working autocompletion of this library.
"""
import sys
import inspect
import re
sys.path.append('build/python-api-src') #Unix
sys.path.append('build/python-api-src/Release') #Windows
import commandcenter
def update_pyi_with_docstrings(pyi_path):
"""
Update the .pyi file with docstrings from the corresponding library.
Args:
pyi_path (str): The path to the .pyi file.
Returns:
None
"""
with open(pyi_path, 'r') as file:
lines = file.readlines()
new_lines = []
known_def = {} #To keep track of docs to class methods
for i in range(len(lines)):
line = lines[i]
if line.strip().startswith('class '):
new_lines.append(line)
if not line.strip().endswith("ID:"):
class_name = re.split(r'[\(: ]', line)[1]
docstring = inspect.getdoc(getattr(commandcenter, class_name))
new_lines.append(f' """{docstring}"""\n')
for func in dir(getattr(commandcenter, class_name)):
if func.startswith("__"):
continue
func_docs = inspect.getdoc(getattr(getattr(commandcenter, class_name), func))
known_def[func] = func_docs
else:
class_name = re.split(r'[\(: ]', line)[1]
docstring = inspect.getdoc(getattr(commandcenter, class_name))
docstring = docstring.split("Members:")[0]
new_lines.append(f' """{docstring}"""\n')
elif line.strip().startswith('def '):
new_lines.append(line[:-4])
func_name = re.split(r'[\(: ]', line.strip())[1]
if func_name.startswith("__"):
new_lines.append(f' {line[-4:]}')
continue
elif func_name in known_def:
new_lines.append(f'\n """{known_def[func_name]}"""\n')
new_lines.append(f' {line[-4:]}')
continue
else:
try:
func_doc = inspect.getdoc(getattr(commandcenter, func_name))
if func_name == "create_computer" or func_name == "create_participants": #Special case with indentation
new_lines.append(f'\n """{func_doc}"""\n')
else:
new_lines.append(f'\n """{func_doc}"""\n')
new_lines.append(f' {line[-4:]}')
continue
except AttributeError:
new_lines.append(f'\n """not found"""\n')
new_lines.append(f' {line[-4:]}')
continue
else:
new_lines.append(line)
# Write the updated content back to the .pyi file
with open(pyi_path, 'w') as file:
file.writelines(new_lines)
# Path to the generated .pyi file
pyi_file_path = 'build/python-api-src/commandcenter.pyi' #Unix
#pyi_file_path = 'build/python-api-src/Release/commandcenter.pyi' #Windows
update_pyi_with_docstrings(pyi_file_path)
......@@ -131,6 +131,14 @@ void BaseLocation::setPlayerOccupying(CCPlayer player, bool occupying)
}
}
void BaseLocation::setMinerals(std::vector<Unit> & mineralFields) {
m_minerals = mineralFields;
}
void BaseLocation::setGeysers(std::vector<Unit> & geysers) {
m_geysers = geysers;
}
bool BaseLocation::isInResourceBox(int tileX, int tileY) const
{
CCPositionType px = Util::TileToPosition((float)tileX);
......@@ -202,7 +210,9 @@ void BaseLocation::draw()
{
CCPositionType radius = Util::TileToPosition(1.0f);
m_bot.Map().drawCircle(m_centerOfResources, radius, CCColor(255, 255, 0));
// Take first mineral for the Z-pos.
sc2::Point3D center_pos = sc2::Point3D(m_centerOfResources.x, m_centerOfResources.y, m_minerals[0].getUnitPtr()->pos.z);
m_bot.Map().drawResourceSphere(center_pos, radius, CCColor(255, 255, 0));
std::stringstream ss;
ss << "BaseLocation: " << m_baseID << "\n";
......@@ -237,14 +247,14 @@ void BaseLocation::draw()
//m_bot.Map().drawLine(m_left, y, m_right, y, CCColor(160, 160, 160));
}
for (auto & mineralPos : m_mineralPositions)
for (auto & mineral : m_minerals)
{
m_bot.Map().drawCircle(mineralPos, radius, CCColor(0, 128, 128));
m_bot.Map().drawResourceSphere(mineral.getUnitPtr()->pos, radius, CCColor(0, 128, 128));
}
for (auto & geyserPos : m_geyserPositions)
for (auto & geyser : m_geysers)
{
m_bot.Map().drawCircle(geyserPos, radius, CCColor(0, 255, 0));
m_bot.Map().drawResourceSphere(geyser.getUnitPtr()->pos, radius, CCColor(0, 255, 0));
}
if (m_isStartLocation)
......
......@@ -50,6 +50,8 @@ public:
bool isInResourceBox(int x, int y) const;
void setPlayerOccupying(CCPlayer player, bool occupying);
void setMinerals(std::vector<Unit> & mineralFields);
void setGeysers(std::vector<Unit> & geysers);
const std::vector<CCTilePosition> & getClosestTiles() const;
......
......@@ -138,6 +138,12 @@ void BaseLocationManager::onFrame()
{
drawBaseLocations();
// make sure that mineralfields and geysers are up to date in the different bases
for (BaseLocation & baselocation : m_baseLocationData) {
updateMinerals(baselocation);
updateGeysers(baselocation);
}
// reset the player occupation information for each location
for (auto & baseLocation : m_baseLocationData)
{
......@@ -247,6 +253,32 @@ void BaseLocationManager::onFrame()
}
void BaseLocationManager::updateMinerals(BaseLocation & baseToUpdate) {
std::vector<Unit> newMinerals;
for (Unit oldMineral : baseToUpdate.getMinerals()) {
for (auto & mineral : m_bot.GetAllUnits()) {
if (oldMineral.getPosition() == mineral.getPosition() && mineral.getType().isMineral()) {
newMinerals.push_back(mineral);
break;
}
}
}
baseToUpdate.setMinerals(newMinerals);
}
void BaseLocationManager::updateGeysers(BaseLocation & baseToUpdate) {
std::vector<Unit> newGeysers;
for (Unit oldGeyser : baseToUpdate.getGeysers()) {
for (auto & geyser : m_bot.GetAllUnits()) {
if (oldGeyser.getPosition() == geyser.getPosition() && geyser.getType().isGeyser()) {
newGeysers.push_back(geyser);
break;
}
}
}
baseToUpdate.setGeysers(newGeysers);
}
BaseLocation * BaseLocationManager::getBaseLocation(const CCPosition & pos) const
{
if (!m_bot.Map().isValidPosition(pos)) { return nullptr; }
......@@ -269,7 +301,7 @@ void BaseLocationManager::drawBaseLocations()
const BaseLocation * next_expansion = getNextExpansion(Players::Self);
CCTilePosition nextExpansionPosition = next_expansion->getDepotPosition();
m_bot.Map().drawCircle(Util::GetPosition(nextExpansionPosition), 1, CCColor(255, 0, 255));
m_bot.Map().drawResourceSphere(sc2::Point3D(Util::GetPosition(nextExpansionPosition).x, Util::GetPosition(nextExpansionPosition).y, next_expansion->getMinerals()[0].getUnitPtr()->pos.z), 1, CCColor(255, 0, 255));
m_bot.Map().drawText(Util::GetPosition(nextExpansionPosition), "Next Expansion Location", CCColor(255, 0, 255));
}
......@@ -293,7 +325,6 @@ const std::set<const BaseLocation *> & BaseLocationManager::getOccupiedBaseLocat
return m_occupiedBaseLocations.at(player);
}
const BaseLocation * BaseLocationManager::getNextExpansion(int player) const
{
const BaseLocation * homeBase = getPlayerStartingBaseLocation(player);
......
......@@ -32,4 +32,9 @@ public:
const BaseLocation * getNextExpansion(int player) const;
private:
void updateMinerals(BaseLocation & baseToUpdate);
void updateGeysers(BaseLocation & baseToUpdate);
};
#include "BuildOrder.h"
BuildOrder::BuildOrder()
{
}
BuildOrder::BuildOrder(const std::vector<MetaType> & vec)
: m_buildOrder(vec)
{
}
void BuildOrder::add(const MetaType & type)
{
m_buildOrder.push_back(type);
}
size_t BuildOrder::size() const
{
return m_buildOrder.size();
}
const MetaType & BuildOrder::operator [] (const size_t & index) const
{
return m_buildOrder[index];
}
MetaType & BuildOrder::operator [] (const size_t & index)
{
return m_buildOrder[index];
}
\ No newline at end of file