Skip to content
Snippets Groups Projects
Commit 70768e2b authored by David Bergström's avatar David Bergström
Browse files

Merge branch 'master' into 'master'

Uppdaterat API

See merge request starcraft-ai-course/pycommandcenter!7
parents 32cfd745 06370875
No related branches found
No related tags found
No related merge requests found
Showing with 3827 additions and 609 deletions
......@@ -8,7 +8,7 @@ pages:
- mkdir build
- cd build
- cmake ..
- make -j $(nproc) library
- make library
- cd ../docs
- make html
- cd ..
......
[submodule "lib/pybind11"]
path = lib/pybind11
url = https://github.com/pybind/pybind11
[submodule "lib/s2client-api"]
path = lib/s2client-api
url = https://github.com/Blizzard/s2client-api.git
[submodule "lib/cpp-sc2"]
path = lib/cpp-sc2
url = https://github.com/cpp-sc2/cpp-sc2.git
[submodule "lib/sc2-gamedata"]
path = lib/sc2-gamedata
url = https://github.com/noorus/sc2-gamedata.git
[submodule "lib/json"]
path = lib/json
url = https://github.com/nlohmann/json.git
[submodule "lib/sc2-techtree"]
path = lib/sc2-techtree
url = https://github.com/BurnySc2/sc2-techtree.git
......@@ -14,7 +14,7 @@ set(BUILD_API_EXAMPLES OFF CACHE INTERNAL "" FORCE)
set(BUILD_API_TESTS OFF CACHE INTERNAL "" FORCE)
add_subdirectory(lib/pybind11)
add_subdirectory(lib/s2client-api)
add_subdirectory(lib/cpp-sc2)
add_subdirectory(src)
add_subdirectory(python-api-src)
......
# Extending the API
This is a guide for extending the API and adding more functionality to the courses TDDE25 and TDDD92.
If a function already exist but you can't use it in python, check and see if it's exist in the library files (pybind).
1. Create a declaration of your function in the header file.
2. Create a definition of your function in the source file.
3. Depending on which object you decided to extend, you should also add this function to the library file. The library is the pybind, making it possible to use your function in python.
4. Update the documentation. There are instructions on how you build and test the documentation.
Example:
We want to add function to unit, returning a bool depending on if it's holding a mineral. We have discovered a function in the SC2 API containing this information (sc2_client.ccp). This is a helper function, it doesn't belong to any object.
1. In unit.h: ```bool isCarryingMinerals() const;```
2. In unit.cpp: ```bool Unit::isCarryingMinerals() const
{
return sc2::IsCarryingMinerals(*m_unit);
}```
We can access m_unit in the unit file and with sc2::Function() we can access any function in the blizzard API that doesn't belong to any object. The same goes for any object, for example sc2::Point3D makes us able to access the Point3D object.
3. In lib_unit.cpp: ```.def_property_readonly("is_carrying_minerals", &Unit::isCarryingMinerals)```
4. In the folder named docs we update the documentation. In this case, we update the file unit.rst.
Common problems:
1. The return in python is a memory address:
Make sure that it returns a correct type.
2. The compiler complains about files I have not even touched:
Make sure that the startUp is library and you have release x64. If you just added a new function in pybind, check it.
......@@ -12,7 +12,9 @@
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
# Two paths here to work on both Windows and Linux
import sys,os
sys.path.append(os.path.join(os.getcwd(), "..", "build", "python-api-src", "Release"))
sys.path.append(os.path.join(os.getcwd(), "..", "build", "python-api-src"))
# -- Project information -----------------------------------------------------
......
......@@ -25,6 +25,13 @@ Difficulty
:members:
:undoc-members:
AIBuild
-------
.. autoclass:: library.AIBuild
:members:
:undoc-members:
Race
----
......
......@@ -127,6 +127,14 @@ However, your bot might will probably be able to play the game faster. If you
remove or comment out this line the game will run as fast as possible, only
waiting for your bot to return from `on_step`.
If you want to train your agent on certain type of bots. For example, If we
want the opponent to focus on air strategy. You can add the
following line to the bot.
.. code-block:: python
participant_2 = create_computer(Race.Random, Difficulty.Easy, AIBuild.Air)
We can also play two bots against each other by changing the row:
.. code-block:: python
......
......@@ -62,6 +62,9 @@ BaseLocation
.. autoattribute:: geysers
.. automethod:: get_ground_distance
This function uses BFS and moves in a vertical and horizontal position. Because of this,
the distance might overshoot compared to calculating it with Pythagoras' theorem.
.. automethod:: is_occupied_by_player
......@@ -81,8 +84,13 @@ TechTree
This class has some invalid information by default, this can be corrected by
placing the file `techtree.json` in the working directory. The
`techtree.json` files are available here_, select the lastest version. A
recent file is included in the `template repository`_.
`techtree.json` files are available here_, select the lastest version.
A techtree for SC2 version >=4.10 is now available (not fully tested yet),
this can be found under the folder data in this link_.
A recent file is included in the `template repository`_.
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.
.. method:: get_data(argument) -> library.TypeData
......@@ -90,6 +98,7 @@ TechTree
an instance of the class :class:`library.CCUpgrade`, depending on what
information is wanted.
.. _link: https://github.com/BurnySc2/sc2-techtree
.. _here: https://github.com/noorus/sc2-gamedata
.. _`template repository`: https://gitlab.liu.se/starcraft-ai-course/sc2-python-bot
......@@ -100,6 +109,7 @@ TypeData
:members:
:undoc-members:
.. TODO: Types for all fields would be nice, is required_units List[UnitType] or List[UNIT_TYPEID]?
MapTools
......@@ -120,8 +130,12 @@ MapTools
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.
.. automethod:: draw_box
.. automethod:: draw_circle
.. automethod:: draw_resource_sphere
.. automethod:: draw_line
.. automethod:: draw_text
.. automethod:: draw_text_screen
......
......@@ -59,6 +59,39 @@ IDABot
Sends the string 'message' to the game chat
.. method:: IDABot.has_creep(self, Point2D) -> Boolean
Returns if the position has a creep
.. method:: IDABot.move_camera(self, Point2DI)
Move the camera to the position
.. method:: IDABot.ability_for_upgrade(self, UpgradeID)
Ability that researches this upgrade
Example: If we send in UPGRADE_ID.BANSHEECLOAK, it will return
ABILITY_ID.RESEARCH_BANSHEECLOAKINGFIELD. In this case,
the unit of scv has the ability for this. You can then use the
unit.ability(AbilityID) on the scv for creating the upgrade.
.. method:: IDABot.upgrade_mineral_cost(self, UpgradeID)
Mineral cost of researching the upgrade
.. method:: IDABot.upgrade_gas_cost(self, UpgradeID)
Vespene/gas cost of researching the upgrade
.. method:: IDABot.upgrade_research_time(self, UpgradeID)
Time in GameLoops to research this upgrade
.. method:: IDABot.effect_radius(self, EffectID)
Size of the circle the effect impacts
Attributes:
.. autoattribute:: minerals
......@@ -70,3 +103,91 @@ IDABot
.. autoattribute:: max_supply
.. autoattribute:: current_frame
Debug
-----
When developing AI-methods or when simply having a problem.
The debug-methods are a great tool for speeding up the process.
.. method:: IDABot.debug_create_unit(self, UnitTypeID, Point2D, Player Constant, Int)
This method creates the nr (INT) of units on the position :class:`library.Point2D`, the unit
belongs to the Player Constant
.. method:: IDABot.debug_kill_unit(self, Unit)
Kills the :class:`library.Unit`
.. method:: IDABot.debug_show_map(self)
Make the entire map visible
.. method:: IDABot.debug_fast_build(self)
Set the build time in game to 1
.. method:: IDABot.debug_enemy_control(self)
Gives the player full control over the enemy
.. method:: IDABot.debug_fast_build(self)
Set the build time in game to 1
.. method:: IDABot.debug_ignore_food(self)
Ignore food in game
.. method:: IDABot.debug_ignore_resource_cost(self)
Ignore the resource cost in game. Everything cost 0 resources
.. method:: IDABot.debug_give_all_resources(self)
Set the mineral and vespene gas to 5000
.. method:: IDABot.debug_god_mode(self)
Give yourself god mode in the game
.. method:: IDABot.debug_ignore_mineral(self)
Ignore the mineral cost in the game
.. method:: IDABot.debug_no_cooldowns(self)
Deactivate cooldowns (Basically setting them to 0)
.. method:: IDABot.debug_give_all_tech(self)
Give yourself all tech
.. method:: IDABot.debug_give_all_upgrades(self)
Give yourself all upgrades
.. method:: IDABot.debug_set_score(self, Float)
Set the player score in game
.. method:: IDABot.debug_end_game(self, Boolean)
End the game, if the Boolean is True then victory.
If False, defeat.
.. method:: IDABot.debug_set_energy(self, Float, Unit)
Set the amount (Float) of energy to the :class:`library.Unit`
The maximum depends on the unit maxenergy.
Note: This is not in percent of the unit energy.
Same goes for life and shields.
.. method:: IDABot.debug_set_life(self, Float, Unit)
Set the amount (Float) of life to the unit
.. method:: IDABot.debug_set_shields(self, Float, Unit)
Set the amount (Float) of shield to the unit
......@@ -6,9 +6,13 @@ For more information about a certain unit type, the wrapper class
:class:`library.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
, :class:`library.UPGRADE_ID` and :class:`library.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
--------
......@@ -40,3 +44,12 @@ UPGRADE_ID
.. autoclass:: library.UPGRADE_ID
:members:
:undoc-members:
EFFECT_ID
----------
EffectID is for things like ravager bile, or fungal or even a scan.
.. autoclass:: library.EFFECT_ID
:members:
:undoc-members:
......@@ -32,11 +32,14 @@ Unit
.. autoattribute:: hit_points
.. autoattribute:: max_hit_points
Returns the max health
.. autoattribute:: max_shields
.. autoattribute:: max_energy
.. autoattribute:: id
.. autoattribute:: is_alive
.. autoattribute:: is_blip
Returns true if unit is a "blip" - a ping on the map.
Returns true if unit is a "blip" - a ping on the map
.. autoattribute:: is_being_constructed
......@@ -56,7 +59,7 @@ Unit
.. attribute:: Unit.player
Returns the constant corresponding to player which this unit belongs to.
See :ref:`playerconstants` for more information.
See :ref:`playerconstants` for more information
.. autoattribute:: position
.. autoattribute:: current_ability_id
......@@ -77,19 +80,36 @@ Unit
Returns if this unit is currently holding minerals
.. autoattribute:: is_carrying_gas
Returns if this unit is currently holding gas
.. attribute:: Unit.target
Returns target if unit has one, otherwise will fail the assertion (make sure not to call this unless certain that the unit has a target!).
Returns target if unit has one, otherwise will fail the assertion (make sure not to call this unless certain that the unit has a target!)
.. autoattribute:: gas_left_in_refinery
This is used on the geyser.
Returns the amount of gas left in refinery
.. autoattribute:: minerals_left_in_mineralfield
Returns the amount of minerals left in mineralfield
.. autoattribute:: owner
Returns the Player ID, the owner of the unit
Methods:
.. automethod:: ability
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).
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)
.. method:: Unit.is_constructing(self, unit_type: library.UnitType)
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:`library.UnitType`.
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:`library.UnitType`
.. automethod:: stop
.. automethod:: attack_unit
......@@ -107,7 +127,7 @@ Unit
.. automethod:: morph
.. method:: Unit.has_target
Returns True if the target has a valid target and False otherwise.
Returns True if the target has a valid target and False otherwise
.. automethod:: hold_position
.. automethod:: stop_dance
......
Subproject commit f8bbf67bb3284bdf8f82544b464f4692f4f451ce
Subproject commit d9ba0a33d6ce9d233c2a4ee988360c188fbe9dbf
Subproject commit c92eaf8d8cee8bda4a19f95d81b43d65f23174a9
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,7 +10,7 @@ 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
......
......@@ -6,8 +6,8 @@ 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 = 2, "search_count"_a = 1000)
.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);
.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 later gonna make a addon to the building.", "x"_a, "y"_a, "unit_type"_a, "distance_to_building"_a)
.def("get_build_location_near", &BuildingPlacer::getBuildLocationNear, "The search_count is 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, "It's possible to reserve 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);
}
\ No newline at end of file
......@@ -20,6 +20,7 @@ void define_map_tools(py::module & m)
.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("draw_resource_sphere", &MapTools::drawResourceSphere, py::arg("center"), py::arg("radius"), py::arg("color") = sc2::Colors::White)
.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)
......
Source diff could not be displayed: it is too large. Options to address this: view the blob.
......@@ -20,9 +20,9 @@ void define_tech_tree(py::module & m)
.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("required_units", &TypeData::requiredUnits, "owning ONE of these is required to make -> List[UnitType]")
.def_readonly("required_upgrades", &TypeData::requiredUpgrades, "having ALL of these is required to make -> List[UPGRADE_ID]")
.def_readonly("required_addons", &TypeData::requiredAddons, "a unit of this type must be present next to the producer -> List[UnitType]");
py::class_<TechTree>(m, "TechTree")
.def("get_data", py::overload_cast<const UnitType &>(&TechTree::getData, py::const_))
......
......@@ -35,6 +35,12 @@ void define_unit(py::module & m)
.def_property_readonly("facing", &Unit::getFacing)
.def_property_readonly("radius", &Unit::getRadius)
.def_property_readonly("is_carrying_minerals", &Unit::isCarryingMinerals)
.def_property_readonly("is_carrying_gas", &Unit::isCarryingGas)
.def_property_readonly("gas_left_in_refinery", &Unit::gasLeftInGeyser)
.def_property_readonly("minerals_left_in_mineralfield", &Unit::mineralsLeftInMineralfield)
.def_property_readonly("owner", &Unit::getOwner)
.def_property_readonly("max_shields", &Unit::maxShields)
.def_property_readonly("max_energy", &Unit::maxEnergy)
.def("hold_position", &Unit::holdPosition)
.def("patrol", py::overload_cast<const CCPosition &>(&Unit::patrol, py::const_))
.def("stop_dance", &Unit::stopDance)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment