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 4038 additions and 722 deletions
IDAReplayObserver
=================
.. class:: commandcenter.IDAReplayObserver
This is a class for following a replay.
Inherited methods:
.. method:: on_game_start(self)
This method is called when a replay has started, when you inherit it you have to
call the parent's on_game_start method in order to make it work (see
:ref:`replays`).
.. method:: on_step(self)
This method is called on every tick of the replay, when you inherit it you
have to call the parent's on_step method in order to make it work (see
:ref:`replays`).
.. method:: on_game_end(self)
This method is called when the replay has ended, when you inherit it you have to
call the parent's on_game_start method in order to make it work (see
:ref:`replays`).
.. method:: on_unit_created(self)
This method is called when the an unit is created, that includes when an unit leaves a refinery. This only works if replay perspective is not set to 0.
.. method:: on_unit_destroyed(self)
This unit is called when a unit is destroyed.
Methods:
.. method:: get_all_units(self) -> List[commandcenter.ReplayUnit]
Retrieves a list of all visible units.
.. method:: get_player_race(self, player_id) -> commandcenter.Race
Returns the player's race.
.. toctree::
......@@ -7,6 +7,8 @@ for Starcraft II.
If you are looking on how to get started, take a look at :ref:`Getting started
<gettingstarted>`.
If you want to make changes to either this documentation or the library itself, please read the :ref:`Contributors guide <contributing>`.
If you are looking for something specific, you can either check the
:ref:`modindex` or use the search feature on the left.
......@@ -17,20 +19,25 @@ Table of contents
-----------------
.. toctree::
:maxdepth: 3
:maxdepth: 2
gettingstarted
perception
PyCommandCenter<_autosummary/commandcenter>
Coordinator<_autosummary/commandcenter.Coordinator>
helpers
idabot
unit
types
coordinates
constants
replays
idareplayobserver
replayunit
.. autosummary::
:toctree: _autosummary
:hidden:
library
library.Coordinator
commandcenter
commandcenter.Coordinator
.. _replays:
Replays
=======
This page will describe two different techniques for handling replays. The
first technique parses the information saved in the replay file. The second
uses the information in the replay file to actually replay the game. The
different techniques have certain advantages and disadvantages. The main
one is that the reader is a lot faster while replaying the game provides
a lot more information.
SC2Reader
---------
SC2Reader_ is a library that can be used to implement the first technique.
Here is a short example that uses SC2Reader to extract the build order.
.. _SC2Reader: https://github.com/ggtracker/sc2reader
.. code-block:: python
import sc2reader
import json
from sc2reader.factories import SC2Factory
# The path to the replays
PATH = "../Replays"
def main():
# Creates a generator of all the replays in the dictionary
replays = sc2reader.load_replays(PATH, load_level=3)
games = []
# Loops through every relay
for replay in replays:
building_order = []
if is_terran_vs_terran(replay):
# Loops through every event
for event in replay.events:
# Check if the event is that a building is crated
if type(event) == sc2reader.events.tracker.UnitInitEvent:
if event.unit.name not in building_order:
building_order.append(event.unit.name)
games.append(building_order)
return games
def is_terran_vs_terran(replay):
try:
return sc2reader.constants.LOCALIZED_RACES[replay.players[0].play_race] == "Terran" \
and sc2reader.constants.LOCALIZED_RACES[replay.players[1].play_race] == "Terran"
except(KeyError):
return False
if __name__ == '__main__':
games = main()
text = json.dumps(games)
print("Res: " + text)
SC2Reader has good documation_ that also describe what information
could be found. `What is in a Replay`_ and Events_ gives a good idea
if the information you want could be collected with SC2Reader.
.. _documation: https://sc2reader.readthedocs.io/en/latest/index.html
.. _What is in a Replay: https://sc2reader.readthedocs.io/en/latest/articles/whatsinareplay.html
.. _Events: https://sc2reader.readthedocs.io/en/latest/events/index.html
ReplayObserver
--------------
This is the second technique it is much like using a bot but with the difference
that no action can be preform just observations.
.. code-block:: python
from commandcenter import *
class MyObserver(ReplayObserver):
def __init__(self):
ReplayObserver.__init__(self)
def on_game_start(self):
ReplayObserver.on_game_start(self)
def on_step(self):
ReplayObserver.on_step(self)
def main():
coordinator = Coordinator(r"D:/StarCraft II/Versions/Base<version>/SC2_x64.exe")
if coordinator.load_replay_list("D:/Replays/"):
observer = MyObserver()
coordinator.add_replay_observer(observer)
while coordinator.update():
pass
else:
print("No replays found")
if __name__ == "__main__":
main()
.. toctree::
ReplayUnit
==========
.. autoclass:: commandcenter.ReplayUnit
Properties:
.. autoattribute:: buffs
.. autoattribute:: build_percentage
.. autoattribute:: energy
.. autoattribute:: facing
.. autoattribute:: hit_points
.. autoattribute:: max_hit_points
.. autoattribute:: id
.. autoattribute:: is_alive
.. autoattribute:: is_blip
.. autoattribute:: is_being_constructed
.. autoattribute:: is_burrowed
.. autoattribute:: is_cloaked
.. autoattribute:: is_completed
.. autoattribute:: is_flying
.. autoattribute:: is_idle
.. autoattribute:: is_powered
.. autoattribute:: is_training
.. autoattribute:: is_valid
.. autoattribute:: ReplayUnit.player
.. autoattribute:: position
.. autoattribute:: current_ability_id
.. autoattribute:: progress
.. autoattribute:: radius
.. autoattribute:: shields
.. autoattribute:: tile_position
.. autoattribute:: unit_type
.. autoattribute:: weapon_cooldown
.. autoattribute:: is_carrying_minerals
.. toctree::
\ No newline at end of file
Types
=====
For a full list of all unit types see the enum :class:`library.UNIT_TYPEID`.
For more information about a certain unit type, the wrapper class
:class:`library.UnitType` can be used.
For a full list of all unit types see the enum :class:`commandcenter.UNIT_TYPEID`.
For more information about a certain unit type, the wrapper class :class:`commandcenter.UnitType` can be used.
For a full list of all abilities and upgrades, see :class:`library.ABILITY_ID`
and :class:`library.UPGRADE_ID` respectively. Note that these does not have any
For a full list of all abilities and upgrades, see :class:`commandcenter.ABILITY_ID`, :class:`commandcenter.UPGRADE_ID` and :class:`commandcenter.EFFECT_ID` respectively. Note that these does not have any
wrapper classes for them.
If any of the ID's doesn't respond with the game. Before contacting the labassistent, check the game version and the compatibility through Liquipedia. Some ID's might be left after a patch and is not available in the game anymore.
UnitType
--------
As explained above, this class is a wrapper around the class
:class:`library.UNIT_TYPEID`.
.. autoclass:: library.UnitType
.. autoclass:: commandcenter.UnitType
:members:
:undoc-members:
:special-members: __init__
UNIT_TYPEID
-----------
.. autoclass:: library.UNIT_TYPEID
:members:
:undoc-members:
.. dropdown:: UNIT_TYPEID Enum (click to expand)
.. autoclass:: commandcenter.UNIT_TYPEID
:members:
:undoc-members:
ABILITY_ID
----------
.. autoclass:: library.ABILITY_ID
:members:
:undoc-members:
.. dropdown:: ABILITY_ID Enum (click to expand)
.. autoclass:: commandcenter.ABILITY_ID
:members:
:undoc-members:
UPGRADE_ID
----------
.. autoclass:: library.UPGRADE_ID
:members:
:undoc-members:
.. dropdown:: UPGRADE_ID Enum (click to expand)
.. autoclass:: commandcenter.UPGRADE_ID
:members:
:undoc-members:
EFFECT_ID
----------
EffectID is for things like ravager bile, or fungal or even a scan.
.. dropdown:: EFFECT_ID Enum (click to expand)
.. autoclass:: commandcenter.EFFECT_ID
:members:
:undoc-members:
.. toctree::
Unit
====
.. class:: library.Unit
.. autoclass:: commandcenter.Unit
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:`library.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:`library.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.
Properties:
.. autoattribute:: buffs
.. autoattribute:: build_percentage
.. autoattribute:: energy
.. autoattribute:: facing
.. autoattribute:: has_target
.. autoattribute:: hit_points
.. autoattribute:: max_hit_points
.. autoattribute:: max_shields
.. autoattribute:: max_energy
.. autoattribute:: id
.. autoattribute:: is_alive
.. autoattribute:: is_blip
.. autoattribute:: is_being_constructed
.. autoattribute:: is_burrowed
.. autoattribute:: is_cloaked
.. autoattribute:: is_completed
.. autoattribute:: is_constructing
.. autoattribute:: is_flying
.. autoattribute:: is_idle
.. autoattribute:: is_powered
.. autoattribute:: is_training
.. autoattribute:: is_valid
.. attribute:: Unit.player
Returns the constant corresponding to player which this unit belongs to.
See :ref:`playerconstants` for more information.
.. autoattribute:: player
.. autoattribute:: position
.. autoattribute:: current_ability_id
.. autoattribute:: progress
.. autoattribute:: progression_list
.. autoattribute:: radius
.. autoattribute:: shields
.. autoattribute:: tile_position
.. autoattribute:: unit_type
.. autoattribute:: weapon_cooldown
.. autoattribute:: is_carrying_minerals
.. autoattribute:: is_carrying_gas
.. autoattribute:: target
.. autoattribute:: gas_left_in_refinery
.. autoattribute:: minerals_left_in_mineralfield
.. autoattribute:: owner
Methods:
.. automethod:: ability
.. automethod:: is_constructing
.. automethod:: stop
.. automethod:: attack_unit
.. automethod:: attack_move
.. method:: Unit.move(self, point)
Move the unit to the given point, the point being an instance of either
:class:`library.Point2D` or :class:`library.Point2DI`.
.. automethod:: Unit.move(self, point)
.. automethod:: right_click
.. automethod:: repair
.. automethod:: build
......@@ -62,4 +59,9 @@ Unit
.. automethod:: train
.. automethod:: research
.. automethod:: morph
.. automethod:: hold_position
.. automethod:: patrol
.. automethod:: stop_dance
.. toctree::
\ No newline at end of file
Subproject commit f8bbf67bb3284bdf8f82544b464f4692f4f451ce
Subproject commit ed07e49236d937fd4ae98d0b0cb58a962cd269a6
Subproject commit 35ff42b56e9d34d9a944266eb25f2c899dbdfed7
Subproject commit d9ba0a33d6ce9d233c2a4ee988360c188fbe9dbf
Subproject commit c92eaf8d8cee8bda4a19f95d81b43d65f23174a9
# Installing PyCommandCenter in PyCharm
Start of by download the library from the [PyCommandCenter repository](https://gitlab.ida.liu.se/starcraft-api/pycommandcenter/tags).
Place the library in your repository.
Add the library to the Python path in Python by:
1. File->Settings->Project: (project name)->Project Interpreter
2. Select the cog in the upper right corner and select "Show All"
3. In the new window that opens select the icon which shows a few folders connected with lines
4. In the new window press the plus icon and select the path of your repository (should be where you placed the library)
5. Restart PyCharm with File->Invalidate Caches/Restart->Invalidate and Restart
include_directories(SYSTEM
${PROJECT_SOURCE_DIR}/lib/s2client-api/include
${PROJECT_SOURCE_DIR}/lib/s2client-api/contrib/protobuf/src
${PROJECT_BINARY_DIR}/lib/s2client-api/generated
${PROJECT_SOURCE_DIR}/lib/cpp-sc2/include
${PROJECT_SOURCE_DIR}/lib/cpp-sc2/contrib/protobuf/src
${PROJECT_BINARY_DIR}/lib/cpp-sc2/generated
${PROJECT_SOURCE_DIR}/lib/json/include
)
......@@ -10,14 +10,14 @@ file(GLOB BOT_SOURCES "../src/*.cpp" "../src/*.h" "../src/*.hpp")
file(GLOB LIBRARY_SOURCES "*.cpp" "*.h")
link_directories(${PROJECT_BINARY_DIR}/s2client-api/bin)
link_directories(${PROJECT_BINARY_DIR}/cpp-sc2/bin)
# Enable compilation of the SC2 version of the bot code
# TODO: Remove all remaining BW code
add_definitions(-DSC2API)
# Create the executable.
pybind11_add_module(library library.cpp library.h ${BOT_SOURCES} ${LIBRARY_SOURCES})
target_link_libraries(library PRIVATE
pybind11_add_module(commandcenter library.cpp library.h ${BOT_SOURCES} ${LIBRARY_SOURCES})
target_link_libraries(commandcenter PRIVATE
sc2api sc2lib sc2utils sc2protocol libprotobuf
)
......@@ -5,22 +5,27 @@ namespace py = pybind11;
void define_base_location(py::module & m)
{
py::class_<BaseLocation>(m, "BaseLocation")
.def_property_readonly("geysers", &BaseLocation::getGeysers)
.def_property_readonly("minerals", &BaseLocation::getMinerals)
.def_property_readonly("mineral_fields", &BaseLocation::getMinerals, "Alias for minerals in order to differentiate from harvested minerals")
.def_property_readonly("is_start_location", &BaseLocation::isStartLocation)
.def_property_readonly("depot_position", &BaseLocation::getDepotPosition)
.def_property_readonly("position", &BaseLocation::getPosition)
.def_property_readonly("geysers", &BaseLocation::getGeysers, "List of geysers at base location (List of units).")
.def_property_readonly("minerals", &BaseLocation::getMinerals, "List of mineral fields at base location (List of unit). Also returns the empty mineral fields.")
.def("is_start_location", &BaseLocation::isStartLocation, "True if the base location is a start location, False otherwise.")
.def_property_readonly("depot_position", &BaseLocation::getDepotPosition, "A suitable position for building a town hall (Command Center, Hatchery or Nexus), defined as a :class:`library.Point2DI`.")
.def_property_readonly("position", &BaseLocation::getPosition, "The position of the center of the BaseLocation, defined as a :class:`commandcenter.Point2D`.")
.def("get_ground_distance", py::overload_cast<const CCPosition &>(&BaseLocation::getGroundDistance, py::const_))
.def("get_ground_distance", py::overload_cast<const CCTilePosition &>(&BaseLocation::getGroundDistance, py::const_))
.def("is_occupied_by_player", &BaseLocation::isOccupiedByPlayer)
.def("is_player_start_location", &BaseLocation::isPlayerStartLocation)
.def("contains_position", &BaseLocation::containsPosition);
.def("get_ground_distance", py::overload_cast<const CCTilePosition &>(&BaseLocation::getGroundDistance, py::const_), "Returns the ground distance between the provided position and the base location. Note that this uses a BFS approach and may overshoot a bit.")
.def("is_occupied_by_player", &BaseLocation::isOccupiedByPlayer, "player constant"_a, "If the baselocation is occupied by the provided player. See :ref:`playerconstants` for more information.")
.def("is_player_start_location", &BaseLocation::isPlayerStartLocation, "player_constant"_a, "If the baselocation is the start location of the provided player. See :ref:`playerconstants` for more information.")
.def("contains_position", &BaseLocation::containsPosition, "If the baselocation contains the provided :class:`commandcenter.Point2D` position.")
.doc() = R"(
Represents a base location on the map. A base location is a location on the map where a player can build a base. It contains information about the resources available at the location, the position of the location, and other information.
)";
py::class_<BaseLocationManager>(m, "BaseLocationManager")
.def_property_readonly("base_locations", &BaseLocationManager::getBaseLocations, py::return_value_policy::reference)
.def_property_readonly("starting_base_locations", &BaseLocationManager::getStartingBaseLocations, py::return_value_policy::reference)
.def("get_occupied_base_locations", &BaseLocationManager::getOccupiedBaseLocations, py::return_value_policy::reference, "player_constant"_a)
.def("get_player_starting_base_location", &BaseLocationManager::getPlayerStartingBaseLocation, py::return_value_policy::copy, "player_constant"_a)
.def("get_next_expansion", &BaseLocationManager::getNextExpansion, py::return_value_policy::copy, "player_constant"_a);
.def_property_readonly("base_locations", &BaseLocationManager::getBaseLocations, py::return_value_policy::reference, "A list of all :class:`commandcenter.BaseLocation` on the current map.")
.def_property_readonly("starting_base_locations", &BaseLocationManager::getStartingBaseLocations, py::return_value_policy::reference, "A list of all :class:`commandcenter.BaseLocation` on the current map which a player started at, indexed by Player constant(see :ref:`playerconstants`).")
.def("get_occupied_base_locations", &BaseLocationManager::getOccupiedBaseLocations, py::return_value_policy::reference, "player_constant"_a, "Returns a list of all :class:`commandcenter.BaseLocation` that are occupied by the provided :ref:`playerconstants`.")
.def("get_player_starting_base_location", &BaseLocationManager::getPlayerStartingBaseLocation, py::return_value_policy::copy, "player_constant"_a, "Returns the :class:`commandcenter.BaseLocation` that provided :ref:`playerconstants` started at.")
.def("get_next_expansion", &BaseLocationManager::getNextExpansion, py::return_value_policy::copy, "player_constant"_a, "Returns the :class:`commandcenter.BaseLocation` that is closest to the startlocation of provided :ref:`playerconstants` that is possible to expand to.")
.doc() = R"(
As the name implies this class helps you manage the base locations on the map.
)";
}
\ No newline at end of file
......@@ -5,11 +5,16 @@ namespace py = pybind11;
void define_building_placer(py::module & m)
{
py::class_<BuildingPlacer>(m, "BuildingPlacer")
.def("can_build_here", &BuildingPlacer::canBuildHere, "x"_a, "y"_a, "unit_type"_a)
.def("can_build_here_with_spaces", &BuildingPlacer::canBuildHereWithSpace, "x"_a, "y"_a, "unit_type"_a, "build_distance"_a)
.def("get_build_location_near", &BuildingPlacer::getBuildLocationNear, "point2di"_a, "unit_type"_a, "build_distance"_a)
.def("reserve_tiles", &BuildingPlacer::reserveTiles, "x"_a, "y"_a, "width"_a, "height"_a)
.def("free_tiles", &BuildingPlacer::freeTiles, "x"_a, "y"_a, "width"_a, "height"_a);
// TODO: Update this method to find refinery positions outside the first base
//.def("get_refinery_position", &BuildingPlacer::getRefineryPosition);
.def("can_build_here", &BuildingPlacer::canBuildHere, "x"_a, "y"_a, "unit_type"_a, "Returns if the provided unit_type it possible to be built at the location. Note: This function uses the width and height of the unit_type and this is not correct for add-ons. So to check addons please use can_build_here_with_size with a hardcoded size instead.")
.def("can_build_here_with_size", &BuildingPlacer::canBuildHereWithSize, "x"_a, "y"_a, "width"_a, "height"_a, "Checks if it is possible to build something with the provided width and height at the provided coordinates. Note: False if the it overlaps with a base location.")
.def("can_build_here_with_spaces", &BuildingPlacer::canBuildHereWithSpace, "Creates a square with the help of x, y, distance_to_building and the size of the unit_type. Good approach if we plan to later construct an add-on. Note: Does not reserve those extra tiles given by distance_to_building for the future. Note: This function uses the width and height of the unit_type and this is not correct for add-ons. So to check add-ons use can_build_here_with_size with a hardcoded size instead.", "x"_a, "y"_a, "unit_type"_a, "distance_to_building"_a)
.def("get_build_location_near", &BuildingPlacer::getBuildLocationNear, "The search_count represents how many building we should check (nearby buildings, instead of i < size, we can switch size to search_count). distance_to_building is the distance to the closest building.", "point2di"_a, "unit_type"_a, "distance_to_building"_a = 2, "search_count"_a = 1000)
.def("reserve_tiles", &BuildingPlacer::reserveTiles, "Reserves tiles, which makes it impossible to build at the position given by x and y.", "x"_a, "y"_a, "width"_a, "height"_a)
.def("free_tiles", &BuildingPlacer::freeTiles,"Free the tile (x, y) from reservation.", "x"_a, "y"_a, "width"_a, "height"_a)
.doc() = R"(
This class is useful for placing all buildings, except refineries and town halls (Command Centers, Hacheries and Nexus).
If you want to place a town hall, take a look at attribute `depot_location` of :class:`commandcenter.BaseLocation`.
If you want to place a refinery, take a look at attribute `geysers` of :class:`commandcenter.BaseLocation` and the method build_target of :class:`commandcenter.Unit`.
)";
}
\ No newline at end of file
......@@ -20,4 +20,7 @@ void define_color(py::module & m)
color.attr("PURPLE") = sc2::Colors::Purple;
color.attr("BLACK") = sc2::Colors::Black;
color.attr("GRAY") = sc2::Colors::Gray;
color.doc() = R"(
Represents a color in RGB format. The color is represented by three integers, each ranging from 0 to 255. The color can be created by providing the red, green and blue values. The class also contains some predefined colors.
)";
}
\ No newline at end of file
......@@ -10,38 +10,64 @@ void define_map_tools(py::module & m)
.def("get_distance", py::overload_cast<const CCPosition &>(&DistanceMap::getDistance, py::const_), "position"_a)
.def("get_sorted_tiles", &DistanceMap::getSortedTiles)
.def("get_start_tile", &DistanceMap::getStartTile)
.def("draw", &DistanceMap::draw, "bot"_a);
.def("draw", &DistanceMap::draw, "bot"_a)
.doc() = R"(
This class is used to calculate the distance between two points on the map.
The distance is calculated using a BFS algorithm. Keep in mind that it can overshoot the distance a bit.
)";
const CCColor white{ 255, 255, 255 };
py::class_<MapTools>(m, "MapTools")
.def_property_readonly("width", &MapTools::width, "The width of the map")
.def_property_readonly("height", &MapTools::height, "The height of the map")
.def_property_readonly("width", &MapTools::width, "The width of the map.")
.def_property_readonly("height", &MapTools::height, "The height of the map.")
.def_property_readonly("map_name", &MapTools::name, "The name of the map.")
//.def("terrainHeight", &MapTools::terrainHeight, py::const_)
.def("draw_line", py::overload_cast<const CCPosition &, const CCPosition &, const CCColor &>(&MapTools::drawLine, py::const_), py::arg("start"), py::arg("stop"), py::arg("color") = sc2::Colors::White)
.def("draw_box", py::overload_cast<const CCPosition &, const CCPosition &, const CCColor &>(&MapTools::drawBox, py::const_), py::arg("top_left"), py::arg("bottom_right"), py::arg("color") = sc2::Colors::White)
.def("draw_circle", py::overload_cast<const CCPosition &, CCPositionType, const CCColor &>(&MapTools::drawCircle, py::const_), py::arg("center"), py::arg("radius"), py::arg("color") = sc2::Colors::White)
.def("terrainHeight", &MapTools::terrainHeightFromCoord, "x"_a, "y"_a)
.def("draw_line", py::overload_cast<const CCPosition &, const CCPosition &, const CCColor &>(&MapTools::drawLine, py::const_), py::arg("start"), py::arg("stop"), py::arg("color") = sc2::Colors::White, "Draws a line with the given color between to two points.")
.def("draw_tile", py::overload_cast<const CCTilePosition &, const CCColor &>(&MapTools::drawTile, py::const_), py::arg("tile"), py::arg("color") = sc2::Colors::White, "Draws an outline with the given color to the given tile.")
.def("draw_box", py::overload_cast<const CCPosition &, const CCPosition &, const CCColor &>(&MapTools::drawBox, py::const_), py::arg("top_left"), py::arg("bottom_right"), py::arg("color") = sc2::Colors::White, "Draws a box with the given color from the top left corner to the botom right.")
.def("draw_circle", py::overload_cast<const CCPosition &, CCPositionType, const CCColor &>(&MapTools::drawCircle, py::const_), py::arg("center"), py::arg("radius"), py::arg("color") = sc2::Colors::White, "Draws a circle with the given color with the provided point as center and the float as radius.")
.def("draw_resource_sphere", &MapTools::drawResourceSphere, py::arg("center"), py::arg("radius"), py::arg("color") = sc2::Colors::White, "Draws a 3D sphere with the given color with the provided point as center and the float as radius.")
.def("draw_text", &MapTools::drawText, "position"_a, "text"_a, "color"_a = sc2::Colors::White)
.def("draw_text_screen", &MapTools::drawTextScreen, "percentage_x"_a, "percentage_y"_a, "text"_a, "color"_a = sc2::Colors::White)
.def("is_valid_tile", py::overload_cast<int, int>(&MapTools::isValidTile, py::const_), "x"_a, "y"_a)
.def("is_valid_tile", py::overload_cast<const CCTilePosition &>(&MapTools::isValidTile, py::const_), "point_2di"_a)
.def("is_valid_position", py::overload_cast<const CCPosition &>(&MapTools::isValidPosition, py::const_), "point_2d"_a)
.def("is_valid_tile", py::overload_cast<int, int>(&MapTools::isValidTile, py::const_), "x"_a, "y"_a, "Checks whether the position is valid for the map.")
.def("is_valid_tile", py::overload_cast<const CCTilePosition &>(&MapTools::isValidTile, py::const_), "point_2di"_a, "Checks whether the tile is valid for the map.")
.def("is_valid_position", py::overload_cast<const CCPosition &>(&MapTools::isValidPosition, py::const_), "point_2d"_a, "Checks whether the position is valid for the map.")
.def("is_powered", &MapTools::isPowered, "x"_a, "y"_a)
.def("is_explored", py::overload_cast<int, int>(&MapTools::isExplored, py::const_), "x"_a, "y"_a)
.def("is_explored", py::overload_cast<const CCPosition &>(&MapTools::isExplored, py::const_), "point2d"_a)
.def("is_explored", py::overload_cast<const CCTilePosition &>(&MapTools::isExplored, py::const_), "point2di"_a)
.def("is_connected", py::overload_cast<int, int, int, int>(&MapTools::isConnected, py::const_), "x1"_a, "y1"_a, "x2"_a, "y2"_a)
.def("is_connected", py::overload_cast<const CCTilePosition &, const CCTilePosition &>(&MapTools::isConnected, py::const_), "from"_a, "too"_a)
.def("is_connected", py::overload_cast<const CCPosition &, const CCPosition &>(&MapTools::isConnected, py::const_), "from"_a, "too"_a)
.def("is_walkable", py::overload_cast<int, int>(&MapTools::isWalkable, py::const_), "x"_a, "y"_a)
.def("is_walkable", py::overload_cast<const CCTilePosition &>(&MapTools::isWalkable, py::const_), "point2di"_a)
.def("is_buildable", py::overload_cast<int, int>(&MapTools::isBuildable, py::const_), "x"_a, "y"_a)
.def("is_buildable", py::overload_cast<const CCTilePosition &>(&MapTools::isBuildable, py::const_), "point2di"_a)
.def("is_visible", &MapTools::isVisible, "x"_a, "y"_a)
.def("can_build_type_at_position", &MapTools::canBuildTypeAtPosition, "x"_a, "y"_a, "unit_type"_a)
.def("is_depot_buildable_tile", &MapTools::isDepotBuildableTile, "x"_a, "y"_a)
.def("get_ground_distance", &MapTools::getGroundDistance, "from"_a, "to"_a)
.def("is_explored", py::overload_cast<int, int>(&MapTools::isExplored, py::const_), "x"_a, "y"_a, "Returns whether the coordinates has been explored or not.")
.def("is_explored", py::overload_cast<const CCPosition &>(&MapTools::isExplored, py::const_), "point2d"_a, "Returns whether the coordinate has been explored or not.")
.def("is_explored", py::overload_cast<const CCTilePosition &>(&MapTools::isExplored, py::const_), "point2di"_a, "Returns whether the tile has been explored or not.")
.def("is_connected", py::overload_cast<int, int, int, int>(&MapTools::isConnected, py::const_), "x1"_a, "y1"_a, "x2"_a, "y2"_a, "Returns whether the coordinates are connected.")
.def("is_connected", py::overload_cast<const CCTilePosition &, const CCTilePosition &>(&MapTools::isConnected, py::const_), "from"_a, "to"_a, "Returns whether the tiles are connected.")
.def("is_connected", py::overload_cast<const CCPosition &, const CCPosition &>(&MapTools::isConnected, py::const_), "from"_a, "to"_a, "Returns whether the positions are of two connected tiles.")
.def("is_walkable", py::overload_cast<int, int>(&MapTools::isWalkable, py::const_), "x"_a, "y"_a, "Returns whether the coordinates is walkable.")
.def("is_walkable", py::overload_cast<const CCTilePosition &>(&MapTools::isWalkable, py::const_), "point2di"_a, "Returns whether the tile is walkable.")
.def("is_buildable", py::overload_cast<int, int>(&MapTools::isBuildable, py::const_), "x"_a, "y"_a, "Returns whether it is possible to build at the provided coordinate.")
.def("is_buildable", py::overload_cast<const CCTilePosition &>(&MapTools::isBuildable, py::const_), "point2di"_a, "Returns whether it is possible to build on tile.")
.def("is_visible", &MapTools::isVisible, "x"_a, "y"_a, "Returns whether the location identified by the coordinates is visible.")
.def("can_build_type_at_position", &MapTools::canBuildTypeAtPosition, "x"_a, "y"_a, "unit_type"_a, "Returns whether it is possible to build the provided unittype at the location.")
.def("is_depot_buildable_tile", &MapTools::isDepotBuildableTile, "x"_a, "y"_a, "Returns whether it is possbile to build a depot at the position.")
.def("get_ground_distance", &MapTools::getGroundDistance, "Returns the ground distance between the two points. Note that this uses a BFS approach and may overshoot a bit. The function will also do the calculations with integers resulting in that sometimes when close to a wall it might return -1 even though a path is available.", "from"_a, "to"_a)
.def("get_distance_map", py::overload_cast<const CCTilePosition &>(&MapTools::getDistanceMap, py::const_), "point2di"_a)
.def("get_distance_map", py::overload_cast<const CCPosition &>(&MapTools::getDistanceMap, py::const_), "point2d"_a)
.def("get_closest_tiles_to", &MapTools::getClosestTilesTo, "Returns a list of positions, where the first position is the closest and the last is the furthest", "point2di"_a)
.def("get_least_recently_seen_tile", &MapTools::getLeastRecentlySeenTile);
.def("get_closest_tiles_to", &MapTools::getClosestTilesTo, "Returns a list of positions, where the first position is the closest and the last is the farthest.", "point2di"_a)
.def("get_least_recently_seen_tile", &MapTools::getLeastRecentlySeenTile, "Returns the tile for which the most time has passed since it was last visible.")
.doc() = R"(
This class contains two types of methods:
* Methods for drawing information to the screen
* Methods for extracting information about the map
First, let us look at the method concerning drawing information to the
screen. Methods with the suffix ``_screen`` takes percentages of the
screens height and width, i.e. values between 0 and 1. Methods without
this suffix uses the same coordinate system as the game, i.e. world
coordinates.
The top three methods below takes in a Point2D, but it's possible to
send in x and y as floats instead of Point2D.
There is also methods which are useful for extracting information about the
game map.
)";
}
\ No newline at end of file
......@@ -9,6 +9,9 @@ void define_point(py::module & m)
py::class_<sc2::Point2D>(m, "Point2D", py::dynamic_attr())
.def(py::init<float, float>())
.def(py::init())
.def(py::init([](const sc2::Point2DI & p) {
return sc2::Point2D(p.x, p.y);
}))
.def_readwrite("x", &sc2::Point2D::x)
.def_readwrite("y", &sc2::Point2D::y)
.def(py::self += py::self)
......@@ -16,7 +19,7 @@ void define_point(py::module & m)
.def(py::self *= float())
.def(py::self /= float())
// These does not compile, but it is not a good idea to compare floats with floats anyway
//.def(py::self == py::self)
.def(py::self == py::self) // compiles now and this one is needed for __hash__. Outdated comment??
//.def(py::self != py::self)
.def(py::self + py::self)
.def(py::self - py::self)
......@@ -24,6 +27,14 @@ void define_point(py::module & m)
.def(float() * py::self)
.def(py::self / float())
.def(float() / py::self)
.def("__eq__",
[](const sc2::Point2D & p1, const sc2::Point2D & p2) {
return (p1.x == p2.x && p1.y == p2.y);
})
.def("__hash__",
[](const sc2::Point2D & p) {
return py::make_tuple(p.x, p.y).attr("__hash__")();
})
.def("__repr__",
[](const sc2::Point2D & p) {
return "<Point2D: (" + std::to_string(p.x) + ", " + std::to_string(p.y) + ")>";
......@@ -35,10 +46,18 @@ void define_point(py::module & m)
py::class_<sc2::Point2DI>(m, "Point2DI", py::dynamic_attr())
.def(py::init<int, int>())
.def(py::init())
.def(py::init([](const sc2::Point2D & p) {
return sc2::Point2DI(p);
}))
.def_readwrite("x", &sc2::Point2DI::x)
.def_readwrite("y", &sc2::Point2DI::y)
.def(py::self == py::self)
.def(py::self != py::self)
.def("__hash__",
[](const sc2::Point2DI & p) {
return py::make_tuple(p.x, p.y).attr("__hash__")();
})
.def("__repr__",
[](const sc2::Point2DI & p) {
return "<Point2DI: (" + std::to_string(p.x) + ", " + std::to_string(p.y) + ")>";
......
#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.
......@@ -6,25 +6,37 @@ void define_tech_tree(py::module & m)
{
py::class_<TypeData>(m, "TypeData")
.def_readonly("race", &TypeData::race)
.def_readonly("mineral_cost", &TypeData::mineralCost, "mineral cost of the item")
.def_readonly("gas_cost", &TypeData::gasCost, "gas cost of the item")
.def_readonly("supply_cost", &TypeData::supplyCost, "supply cost of the item")
.def_readonly("build_time", &TypeData::buildTime, "build time of the item")
.def_readonly("is_unit", &TypeData::isUnit)
.def_readonly("is_building", &TypeData::isBuilding)
.def_readonly("is_worker", &TypeData::isWorker)
.def_readonly("is_refinery", &TypeData::isRefinery)
.def_readonly("is_supply_provider", &TypeData::isSupplyProvider)
.def_readonly("is_resource_depot", &TypeData::isResourceDepot)
.def_readonly("is_addon", &TypeData::isAddon)
.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, "any of these units can build the item")
.def_readonly("required_units", &TypeData::requiredUnits, "owning ONE of these is required to make")
.def_readonly("required_upgrades", &TypeData::requiredUpgrades, "having ALL of these is required to make")
.def_readonly("required_addons", &TypeData::requiredAddons, "a unit of this type must be present next to the producer");
.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_));
}
\ No newline at end of file
.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.
)";
}