From ec8d3777deb53a5679d9ae4a3301a9d197b5e894 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Bergstr=C3=B6m?= <davbe125@student.liu.se> Date: Tue, 26 Jun 2018 16:18:45 +0200 Subject: [PATCH] Add enough Python API to make it possible to mine minerals --- python-api-src/lib_sc2_typeenums.cpp | 2 +- python-api-src/lib_unit.cpp | 41 ++++++++++++++++++++++++++ python-api-src/lib_unittype.cpp | 43 ++++++++++++++++++++++++++++ python-api-src/lib_util.cpp | 12 ++++++++ python-api-src/library.cpp | 8 +++++- python-api-src/library.h | 6 +++- src/Common.h | 4 ++- 7 files changed, 112 insertions(+), 4 deletions(-) create mode 100644 python-api-src/lib_unit.cpp create mode 100644 python-api-src/lib_unittype.cpp create mode 100644 python-api-src/lib_util.cpp diff --git a/python-api-src/lib_sc2_typeenums.cpp b/python-api-src/lib_sc2_typeenums.cpp index 21b0c09..3715131 100644 --- a/python-api-src/lib_sc2_typeenums.cpp +++ b/python-api-src/lib_sc2_typeenums.cpp @@ -4,7 +4,7 @@ namespace py = pybind11; // This file is brought to you by VIM, phew. -void define_pyteenums(py::module & m) +void define_typeenums(py::module & m) { py::enum_<sc2::UNIT_TYPEID>(m, "UNIT_TYPEID") .value("INVALID", sc2::UNIT_TYPEID::INVALID) diff --git a/python-api-src/lib_unit.cpp b/python-api-src/lib_unit.cpp new file mode 100644 index 0000000..c3b71e1 --- /dev/null +++ b/python-api-src/lib_unit.cpp @@ -0,0 +1,41 @@ +#include "library.h" + +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("attackUnit", &Unit::attackUnit) + .def("attackMove", &Unit::attackMove) + .def("move", py::overload_cast<const CCPosition &>(&Unit::move, py::const_)) + .def("move", py::overload_cast<const CCTilePosition &>(&Unit::move, py::const_)) + .def("rightClick", &Unit::rightClick) + .def("repair", &Unit::repair) + .def("build", &Unit::build) + .def("buildTarget", &Unit::buildTarget) + .def("train", &Unit::train) + .def("morph", &Unit::morph) + .def("__repr__", [](const Unit & unit) { return "<Unit of type: '" + unit.getType().getName() + "'>"; }); +} diff --git a/python-api-src/lib_unittype.cpp b/python-api-src/lib_unittype.cpp new file mode 100644 index 0000000..0586d1b --- /dev/null +++ b/python-api-src/lib_unittype.cpp @@ -0,0 +1,43 @@ +#include "library.h" + +namespace py = pybind11; + +void define_unittype(py::module & m) +{ + py::class_<UnitType>(m, "UnitType") + .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) + // 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() + "'>"; }); + + // Not implemented in CommandCenter + //.def("whatBuilds", &UnitType::whatBuilds); +} \ No newline at end of file diff --git a/python-api-src/lib_util.cpp b/python-api-src/lib_util.cpp new file mode 100644 index 0000000..116975c --- /dev/null +++ b/python-api-src/lib_util.cpp @@ -0,0 +1,12 @@ +#include "library.h" + +namespace py = pybind11; + +void define_util(py::module & mod) +{ + py::module m = mod.def_submodule("util"); + + 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)); +} \ No newline at end of file diff --git a/python-api-src/library.cpp b/python-api-src/library.cpp index 1185755..08add75 100644 --- a/python-api-src/library.cpp +++ b/python-api-src/library.cpp @@ -4,7 +4,12 @@ namespace py = pybind11; PYBIND11_MODULE(library, m) { - m.doc() = "pybind11 example plugin"; + m.doc() = "Python API for playing Starcraft II"; + + define_typeenums(m); + define_unit(m); + define_unittype(m); + define_util(m); py::class_<Coordinator>(m, "Coordinator") .def(py::init()) @@ -28,6 +33,7 @@ PYBIND11_MODULE(library, m) .def("OnGameStart", &IDABot::OnGameStart) .def("OnStep", &IDABot::OnStep) .def("OnStep_UpdateIDABot", &IDABot::OnStep_UpdateIDABot) + .def("GetAllUnits", &IDABot::GetAllUnits) .def("GetMyUnits", &IDABot::GetMyUnits); py::class_<sc2::PlayerSetup>(m, "PlayerSetup"); diff --git a/python-api-src/library.h b/python-api-src/library.h index c8bdb79..14223b3 100644 --- a/python-api-src/library.h +++ b/python-api-src/library.h @@ -5,6 +5,7 @@ #include "../src/IDABot.h" #include <iostream> #include <pybind11/stl.h> /* Automatic conversion from std::vector to Python lists */ +#include <pybind11/operators.h> /* Convenient operator support */ // Wrapper class since the initialization uses pure argc/argv and these cannot be wrapped into Python correctly class Coordinator : public sc2::Coordinator @@ -49,4 +50,7 @@ public: } }; -void define_typeenums(pybind11::module & m); \ No newline at end of file +void define_typeenums(pybind11::module & m); +void define_unit(pybind11::module & m); +void define_unittype(pybind11::module &m); +void define_util(pybind11::module &m); \ No newline at end of file diff --git a/src/Common.h b/src/Common.h index dec31ff..fa45feb 100644 --- a/src/Common.h +++ b/src/Common.h @@ -10,7 +10,8 @@ #include <string> #include <array> -// Somewhere in the dependency graph someone defines a macro max, which ruins everything +// Somewhere in the dependency graph someone defines a macro called max, +// which breaks all calls to std::limits::max #define NOMINMAX #include <sc2api/sc2_api.h> @@ -25,6 +26,7 @@ typedef float CCHealth; typedef float CCPositionType; typedef size_t CCPlayer; + namespace Players { enum {Self = 0u, Enemy = 1u, Neutral = 2u, Ally = 3u, Size = 4u, None = 5u}; -- GitLab