diff --git a/.gitignore b/.gitignore index 567609b1234a9b8806c5a05da6c866e480aa148d..0023a727e767c45c3521dc3f0e2ed635bb81f1ff 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ build/ +.idea +venv +.vs diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index af8acc8fe3a1bb8d928457d258d895e3aef51331..49f5cb9f08e4a01e87d1a91540b18293a1a90d41 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -19,4 +19,3 @@ pages: - public only: - master - - Doc diff --git a/docs/.gitignore b/docs/.gitignore index 105f812a5862ebf713d87bb2b570654541f0b195..267169afdf7084bd04be62a6e0d70f8598c2f970 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -1,2 +1,4 @@ _autosummary/ _build/ +venv +.idea diff --git a/docs/idareplayobserver.rst b/docs/idareplayobserver.rst index c9a3b93085422fc7e1fc6656824e3c8a5701df6e..8d34f274cccc955fb370770ea0ef63b9ff8e2154 100644 --- a/docs/idareplayobserver.rst +++ b/docs/idareplayobserver.rst @@ -9,7 +9,7 @@ IDAReplayObserver .. method:: IDAReplayObserver.on_game_start(self) - This method is called when a replay has stared, when you inherit it you have to + 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`). @@ -25,6 +25,14 @@ IDAReplayObserver call the parent's on_game_start method in order to make it work (see :ref:`replays`). + .. method:: IDAReplayObserver.on_unit_created(self) + + This method is called when the an unit is created, that includes when an unit leaves a refinery. + + .. method:: IDAReplayObserver.on_unit_destroyed(self) + + This unit is called when a unit is destroyed. + Methods: .. method:: IDAReplayObserver.get_all_units(self) -> List[library.ReplayUnit] diff --git a/docs/replays.rst b/docs/replays.rst index be0b533bb32ec860c1d825713010534d76f834f6..0ca0179f6011a90ef1c6b52b4e86baa30f73e20d 100644 --- a/docs/replays.rst +++ b/docs/replays.rst @@ -68,7 +68,7 @@ if the information you want could be collected with SC2Reader. ReplayObserver -------------- -This is the second technique it is much like using a bot but whit the difference +This is the second technique it is much like using a bot but with the difference that no action can be preform just observations. diff --git a/python-api-src/lib_replay_unit.cpp b/python-api-src/lib_replay_unit.cpp index 7a70770dffa7c1738104f451276f1b6f9aaaf3bb..63197f20a344ae22df680e8ffee70d7396aeba29 100644 --- a/python-api-src/lib_replay_unit.cpp +++ b/python-api-src/lib_replay_unit.cpp @@ -28,9 +28,8 @@ void define_replay_unit(py::module & m) .def_property_readonly("is_valid", &ReplayUnit::isValid) .def_property_readonly("is_training", &ReplayUnit::isTraining) .def_property_readonly("is_blip", &ReplayUnit::isBlip) - // Has target and target crashes if the target died in the same frame - //.def_property_readonly("target", &ReplayUnit::getTarget) - //.def_property_readonly("has_target", &ReplayUnit::hasTarget) + .def_property_readonly("target", &ReplayUnit::getTarget) + .def_property_readonly("has_target", &ReplayUnit::hasTarget) .def_property_readonly("max_hit_points", &ReplayUnit::getMaxHitPoints) .def_property_readonly("progress", &ReplayUnit::getProgress) .def_property_readonly("current_ability_id", &ReplayUnit::getCurrentAbilityID, "The AbilityID of currently used ability") diff --git a/python-api-src/library.cpp b/python-api-src/library.cpp index 0206f191b3998d9a31e31c8924e9bd72fe9623c1..023e554c8cb770a4629c15787693b08d5a6f40a9 100644 --- a/python-api-src/library.cpp +++ b/python-api-src/library.cpp @@ -136,8 +136,20 @@ PYBIND11_MODULE(library, m) .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) ; + + + 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"); py::enum_<sc2::Difficulty>(m, "Difficulty") diff --git a/python-api-src/library.h b/python-api-src/library.h index 89118af074c70399f6cb23c63fe5689775567451..3f9114d0685218dec0f51e838031976f622c5709 100644 --- a/python-api-src/library.h +++ b/python-api-src/library.h @@ -95,6 +95,27 @@ public: ); } + 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 diff --git a/src/IDAReplayObserver.cpp b/src/IDAReplayObserver.cpp index 491818b304e4f7a34990d04f5047504fcd13db20..0af4993668ed4d0af267e7949f6f82c06a78bd1c 100644 --- a/src/IDAReplayObserver.cpp +++ b/src/IDAReplayObserver.cpp @@ -1,12 +1,17 @@ #include "IDAReplayObserver.h" #include "Util.h" +#include <pybind11/pybind11.h> + void IDAReplayObserver::setUnits() { m_allUnits.clear(); + m_allUnitsID.clear(); for (auto & unit : Observation()->GetUnits()) { - m_allUnits.push_back(ReplayUnit(unit, *this)); + ReplayUnit replayUnit = ReplayUnit(unit, *this); + m_allUnits.push_back(replayUnit); + m_allUnitsID.insert(replayUnit.getID()); } } @@ -32,18 +37,44 @@ void IDAReplayObserver::OnGameEnd() void IDAReplayObserver::OnUnitDestroyed(const sc2::Unit* unit) { ReplayUnit unitInformation = ReplayUnit(unit, *this); - OnUnitInfomationDestroyed(&unitInformation); + OnReplayUnitDestroyed(&unitInformation); +} + +void IDAReplayObserver::OnReplayUnitDestroyed(const ReplayUnit *) +{ + +} + +void IDAReplayObserver::OnUnitCreated(const sc2::Unit * unit) +{ + ReplayUnit unitInformation = ReplayUnit(unit, *this); + OnReplayUnitCreated(&unitInformation); +} + +void IDAReplayObserver::OnReplayUnitCreated(const ReplayUnit *) +{ } -void IDAReplayObserver::OnUnitInfomationDestroyed(const ReplayUnit *) +void IDAReplayObserver::OnBuildingConstructionComplete(const sc2::Unit *unit) { + ReplayUnit unitInformation = ReplayUnit(unit, *this); + OnReplayUnitCreated(&unitInformation); } + ReplayUnit IDAReplayObserver::GetUnit(const CCUnitID tag) const -{ - return ReplayUnit(Observation()->GetUnit(tag), *(IDAReplayObserver *)this); +{ + + return ReplayUnit(Observation()->GetUnit(tag), *(IDAReplayObserver *)this); + +} + +bool IDAReplayObserver::UnitExists(const CCUnitID tag) const +{ + return m_allUnitsID.find(tag) != m_allUnitsID.end(); + } @@ -57,19 +88,19 @@ const std::vector<ReplayUnit>& IDAReplayObserver::GetAllUnits() const return m_allUnits; } -CCRace IDAReplayObserver::GetPlayerRace(int player) const +CCRace IDAReplayObserver::GetPlayerRace(int player) +{ + return ReplayControl()->GetReplayInfo().players[player].race; +} + +std::string IDAReplayObserver::GetReplayPath() { - auto playerID = Observation()->GetPlayerID(); - for (auto & playerInfo : Observation()->GetGameInfo().player_info) - { - if (playerInfo.player_id == playerID) - { - return playerInfo.race_actual; - } - } + return ReplayControl()->GetReplayInfo().replay_path; +} - BOT_ASSERT(false, "Failed to find the player's race!"); - return sc2::Race::Random; +sc2::GameResult IDAReplayObserver::GetResultForPlayer(int player) +{ + return ReplayControl()->GetReplayInfo().players[player].game_result; } diff --git a/src/IDAReplayObserver.h b/src/IDAReplayObserver.h index d340fb1affc2a83a1544fafe31b64e297377c5d1..83bba966a4ec21cb79b4c75a92731e3c31f019bc 100644 --- a/src/IDAReplayObserver.h +++ b/src/IDAReplayObserver.h @@ -12,6 +12,7 @@ class IDAReplayObserver : public sc2::ReplayObserver { void setUnits(); std::vector<ReplayUnit> m_allUnits; + std::set<CCUnitID> m_allUnitsID; public: IDAReplayObserver(); @@ -20,12 +21,18 @@ public: void OnStep() override; void OnGameEnd() override; void OnUnitDestroyed(const sc2::Unit*) override; - void OnUnitInfomationDestroyed(const ReplayUnit*); + virtual void OnReplayUnitDestroyed(const ReplayUnit*); + void OnUnitCreated(const sc2::Unit*); + virtual void OnReplayUnitCreated(const ReplayUnit*); + void OnBuildingConstructionComplete(const sc2::Unit*); ReplayUnit GetUnit(const CCUnitID tag) const; + bool UnitExists(const CCUnitID tag) const; const std::vector<ReplayUnit> & GetAllUnits() const; - CCRace GetPlayerRace(int player) const; + CCRace GetPlayerRace(int player); + std::string GetReplayPath(); + sc2::GameResult GetResultForPlayer(int player); }; diff --git a/src/ReplayUnit.cpp b/src/ReplayUnit.cpp index 1bab9381607394099b2d292bc4c6281db9da854f..5b6298054ac1b692f2a505336980b4f0d00146c1 100644 --- a/src/ReplayUnit.cpp +++ b/src/ReplayUnit.cpp @@ -22,23 +22,16 @@ ReplayUnit::ReplayUnit(const sc2::Unit * unit, IDAReplayObserver & replayObserve bool ReplayUnit::hasTarget() const { BOT_ASSERT(isValid(), "Unit is not valid"); - std::cout << "HAS TARGET" << std::endl; if (getUnitPtr()->orders.size() > 0) { if (getUnitPtr()->orders[0].target_unit_tag != NULL) { CCUnitID t_id = getUnitPtr()->orders[0].target_unit_tag; - //The tag is for somereason a null tag - if (t_id == sc2::NullTag) { - return false; + // IDAReplayObserver checks if the unit with this tag still exists + if (m_replayObserver->UnitExists(t_id)){ + // IDAReplayObserver finds the unit with this tag, and returns true if valid + return m_replayObserver->GetUnit(t_id).isValid(); } - std::cout << "1MID HAS TARGET" << std::endl; - std::cout << "2MID HAS TARGET" << std::endl; - std::cout << "valid" << m_replayObserver->GetUnit(t_id).getType() << std::endl; - std::cout << "AFTER" << std::endl; - // IDABot finds the unit with this tag, and returns true if valid - return m_replayObserver->GetUnit(t_id).isValid(); } } - std::cout << "END HAS TARGET" << std::endl; return false; } @@ -52,18 +45,12 @@ ReplayUnit ReplayUnit::getTarget() const if (getUnitPtr()->orders.size() > 0) { // t_id is set to the unit tag of the target CCUnitID t_id = getUnitPtr()->orders[0].target_unit_tag; - //The tag is for somereason a null tag - if (t_id == sc2::NullTag) { - - std::cout << "nullTAG" << std::endl; - std::cout << "type " << sc2::UnitTypeToName(m_unit->unit_type) <<"pos " << getPosition().x << " x y "<< getPosition().y << ", id " << getID() << "player " << getPlayer() << std::endl; - std::cout << getUnitPtr()->orders.size() << std::endl; - return *this; + // Checks if the tag is a null tag or the unit have been removed + if (t_id != sc2::NullTag && m_replayObserver->UnitExists(t_id)){ + // IDAReplayObserver finds the unit with this tag + return m_replayObserver->GetUnit(t_id); } - // IDAReplayObserver finds the unit with this tag - return m_replayObserver->GetUnit(t_id); } - ReplayUnit this_unit = ReplayUnit(m_unit, *m_replayObserver); return this_unit; }