From 5220337843eab9f2a38d2518a1f22126d27940d4 Mon Sep 17 00:00:00 2001 From: Benjamin-eecs Date: Fri, 17 Jun 2022 17:14:21 +0800 Subject: [PATCH 01/28] feat(gfootball): init third_party --- third_party/gfootball/BUILD | 0 third_party/gfootball/gfootball.BUILD | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 third_party/gfootball/BUILD create mode 100644 third_party/gfootball/gfootball.BUILD diff --git a/third_party/gfootball/BUILD b/third_party/gfootball/BUILD new file mode 100644 index 00000000..e69de29b diff --git a/third_party/gfootball/gfootball.BUILD b/third_party/gfootball/gfootball.BUILD new file mode 100644 index 00000000..36f1d112 --- /dev/null +++ b/third_party/gfootball/gfootball.BUILD @@ -0,0 +1,18 @@ +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "mujoco_lib", + srcs = glob(["lib/*"]), + hdrs = glob(["include/mujoco/*.h"]), + includes = [ + "include", + "include/mujoco", + ], + linkopts = ["-Wl,-rpath,'$$ORIGIN'"], + linkstatic = 0, +) + +filegroup( + name = "mujoco_so", + srcs = ["lib/libmujoco.so.2.2.0"], +) From 8c5d04f62fea2326185e4ea4e6d1bf5ebbc5a07d Mon Sep 17 00:00:00 2001 From: kfq2002 <95134838+kfq2002@users.noreply.github.com> Date: Sat, 23 Jul 2022 00:03:40 +0800 Subject: [PATCH 02/28] Add files via upload --- football.h | 325 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 325 insertions(+) create mode 100644 football.h diff --git a/football.h b/football.h new file mode 100644 index 00000000..324bc025 --- /dev/null +++ b/football.h @@ -0,0 +1,325 @@ +#include "envpool/core/async_envpool.h" +#include "envpool/core/env.h" +#include +#include +#include +#include +#include +#include +#include +#include +// env-specific definition of config and state/action spec + +class FootballEnvFns { + public: + char* cwd[256]; + getcwd(cwd, 256); + std::string cwd_string = cwd; + cwd_string.append("/dump") + static decltype(auto) DefaultConfig() { + return MakeDict("action_set"_.Bind(std::string("default")), + "custom_display_stats"_.Bind(0), + "display_game_stats"_.Bind(true), + "dump_full_episodes"_.Bind(false), + "dump_scores"_.Bind(false), + "players"_.Bind(std::vector{"agent:left_players=1"}), + "level"_.Bind(std::string("11_vs_11_stochastic")), + "physics_steps_per_frame"_.Bind(10), + "render_resolution_x"_.Bind(1280), + "real_time"_.Bind(false), + "tracesdir"_.Bind(cwd_string), + "video_format"_.Bind(std::string("avi")), + "video_quality_level"_.Bind(0), + "write_video"_.Bind(false), + "render_resolution_y"_.Bind(0.5625 * 1280) + ); + } + + template + static decltype(auto) StateSpec(const Config& conf) { + return MakeDict("obs"_.Bind( + Spec({72, 96, 16}, {0, 255}))); + } + template + static decltype(auto) ActionSpec(const Config& conf) { + // the last argument in Spec is for the range definition + return MakeDict("action"_.Bind(Spec({-1}, {0, 18}))); + } +}; +// this line will concat common config and common state/action spec +using FootballEnvSpec = EnvSpec; + +class CoreAction{ + public: + std::string backend_action_; + std::string name_; + bool sticky_ = false; + bool directional_ = false; + + CoreAction(std::string backend_action, std::string name, bool sticky, bool directional): + backend_action_(backend_action), + name_(name), + sticky_(sticky), + directional_(directional){} + + bool is_in_actionset(const Spec& spec) { + std::string action_set_name = spec.config["action_set"]; + if (action_set_name == "default") { + return !(std::find(action_set_dict_default.begin(), action_set_dict_default.end(), *this) == action_set_dict_default.end()); + } + else if (action_set_name == "v2") { + return !(std::find(action_set_dict_v2.begin(), action_set_dict_v2.end(), *this) == action_set_dict_v2.end()); + } + else { + return !(std::find(action_set_dict_full.begin(), action_set_dict_full.end(), *this) == action_set_dict_full.end()); + } + } +} + +class DumpConfig{ + public: + int max_count_ = 1; + int steps_before_ = 100; + int steps_after_ = 0; + int min_frequency_ = 10; + ObservationProcessor active_dump = NULL; + clock_t last_dump_time = clock() - 2 * min_frequency_; + DumpConfig(int max_count, int steps_before, int steps_after, int min_frequency) : + max_count_(max_count), steps_before_(steps_before), steps_after_(steps_after){} + +} +class ObservationState{ + public: + std::maptrace_; + std::vectoradditional_frames; + std::vectordebugs; + ObservationState(std::maptrace):trace_(trace){} + +} +class ObservationProcessor{ + public: + float ball_takeover_epsilon = 0.03; + float ball_lost_epsilon = 0.05; + int frame = 0; + Spec spec_self; + std::dequetrace; + nullptr_t state = NULL; + std::map dump_config; + Spec& spec_self; + + ObservationProcessor(const Spec& spec){ + spec_self = spec; + int max_count, steps_before = 100, steps_after = 1, min_frequency = 600; + if(spec.config["dump_socre"]){ + max_count = 100000; + } + else{ + max_count = 0; + } + dump_config.insert(pair("score", DumpConfig(max_count, steps_before, steps_after, min_frequency))); + dump_config.insert(pair("lost_score", DumpConfig(max_count, steps_before, steps_after, min_frequency))); + steps_after = 10000; + steps_before = 0; + min_frequency = 10; + if(spec.config["dump_full_episodes"]){ + max_count = 100000; + } + else{ + max_count = 0; + } + dump_config.insert(pair("episode_done", DumpConfig(max_count, steps_before, steps_after, min_frequency))); + max_count = 1; + steps_before = 100; + steps_after = 0; + min_frequency = 10; + dump_config.insert(pair("shutdown", DumpConfig(max_count, steps_before, steps_after, min_frequency))); + this->clear_state(); + } + void clear_state(); + void reset(); + int len(); + void add_frame(int frame); + void upstate(std::dequetrace_); + + std::vector pending_dumps(); +} + +void ObservationProcessor::clear_state(){ + this->frame = 0; + this->state = NULL; + this->trace.clear(); +} +void ObservationProcessor::reset(){ + this->clear_state(); +} +int ObservationProcessor::len(){ + return(this->trace.size()); +} +void ObservationProcessor::add_frame(int frame){ + if (this->trace.size() > 0 && this->spec_self.config["write_video"]){ + this->trace.back().add_frame(frame); + for(int i = 0; i < this->pending_dumps().size; i++){ + this->pending_dumps()[i].add_frame(frame); + } + } +} +void ObservationProcessor::upstate(std::maptrace){ + this->frame += 1; + int frame = trace["frame"]; + if(this->spec_self.config["write_video"] == false && trace["observation"] == "frame"){ + std::mapno_video_trace = trace; + no_video_trace["observation"] = trace["observation"]; + no_video_trace.erase("observation"); + no_video_trace.erase("frame"); + + } +} +std::vector ObservationProcessor::pending_dumps(){ + std::vectordumps; + std::map::iterator iter; + for(iter = this->dump_config.begin(); iter != _map.end(); iter++) { + if(iter->second.active_dump != NULL){ + dumps.push_back(iter->second.active_dump); + } + } + return(dumps); +} + +action_idle = CoreAction(e_BackendAction.idle, "idle", false, false); +action_builtin_ai = CoreAction(e_BackendAction.builtin_ai, "builtin_ai", false, false); +action_left = CoreAction( + e_BackendAction.left, "left", true, true); +action_top_left = CoreAction( + e_BackendAction.top_left, "top_left", true, true); +action_top = CoreAction( + e_BackendAction.top, "top", true, true); +action_top_right = CoreAction( + e_BackendAction.top_right, "top_right", true, true); +action_right = CoreAction( + e_BackendAction.right, "right", true, true); +action_bottom_right = CoreAction( + e_BackendAction.bottom_right, "bottom_right", true, true); +action_bottom = CoreAction( + e_BackendAction.bottom, "bottom", true, true); +action_bottom_left = CoreAction( + e_BackendAction.bottom_left, "bottom_left", true, true); +action_long_pass = CoreAction(e_BackendAction.long_pass, "long_pass", false, false); +action_high_pass = CoreAction(e_BackendAction.high_pass, "high_pass", false, false); +action_short_pass = CoreAction(e_BackendAction.short_pass, "short_pass", false, false); +action_shot = CoreAction(e_BackendAction.shot, "shot", false, false); +action_keeper_rush = CoreAction( + e_BackendAction.keeper_rush, "keeper_rush", true, false); +action_sliding = CoreAction(e_BackendAction.sliding, "sliding", false, false); +action_pressure = CoreAction( + e_BackendAction.pressure, "pressure", true, false); +action_team_pressure = CoreAction( + e_BackendAction.team_pressure, "team_pressure", true, false); +action_switch = CoreAction(e_BackendAction.switch, "switch", false, false); +action_sprint = CoreAction(e_BackendAction.sprint, "sprint", true, false); +action_dribble = CoreAction( + e_BackendAction.dribble, "dribble", true, false); +action_release_direction = CoreAction( + e_BackendAction.release_direction, "release_direction", true, false); +action_release_long_pass = CoreAction(e_BackendAction.release_long_pass, + "release_long_pass", false, false); +action_release_high_pass = CoreAction(e_BackendAction.release_high_pass, + "release_high_pass", false, false); +action_release_short_pass = CoreAction(e_BackendAction.release_short_pass, + "release_short_pass", false, false); +action_release_shot = CoreAction(e_BackendAction.release_shot, "release_shot", false, false); +action_release_keeper_rush = CoreAction(e_BackendAction.release_keeper_rush, + "release_keeper_rush", false, false); +action_release_sliding = CoreAction(e_BackendAction.release_sliding, + "release_sliding", false, false); +action_release_pressure = CoreAction(e_BackendAction.release_pressure, + "release_pressure", false, false); +action_release_team_pressure = CoreAction(e_BackendAction.release_team_pressure, + "release_team_pressure", false, false); +action_release_switch = CoreAction(e_BackendAction.release_switch, + "release_switch", false, false); +action_release_sprint = CoreAction(e_BackendAction.release_sprint, + "release_sprint", false, false); +action_release_dribble = CoreAction(e_BackendAction.release_dribble, + "release_dribble", false, false); + +std::vector action_set_dict_default = {action_idle, action_left, action_top_left, action_top, + action_top_right, action_right, action_bottom_right, + action_bottom, action_bottom_left, action_long_pass, + action_high_pass, action_short_pass, action_shot, + action_sprint, action_release_direction, action_release_sprint, + action_sliding, action_dribble, action_release_dribble}; +std::vector action_set_dict_v2 = {action_idle, action_left, action_top_left, action_top, + action_top_right, action_right, action_bottom_right, + action_bottom, action_bottom_left, action_long_pass, + action_high_pass, action_short_pass, action_shot, + action_sprint, action_release_direction, action_release_sprint, + action_sliding, action_dribble, action_release_dribble, action_builtin_ai}; +std::vector action_set_dict_full = {action_idle, action_left, action_top_left, action_top, + action_top_right, action_right, action_bottom_right, + action_bottom, action_bottom_left, action_long_pass, + action_high_pass, action_short_pass, action_shot, + action_keeper_rush, action_sliding, action_pressure, + action_team_pressure, action_switch, action_sprint, + action_dribble, action_release_direction, + action_release_long_pass, action_release_high_pass, + action_release_short_pass, action_release_shot, + action_release_keeper_rush, action_release_sliding, + action_release_pressure, action_release_team_pressure, + action_release_switch, action_release_sprint, + action_release_dribble, action_builtin_ai}; +class FootballEnv : public Env { + protected: + const std::map player_config; + player_config.insert(pair("index", 0)); + const int agent_index = -1; + const int agent_left_position = -1; + const int agent_right_position = -1; + + std::string env_name_, representation_, rewards_, logdir_; + bool stacked_, write_goal_dumps_, write_full_episode_dumps_, render_, write_video_; + int dump_frequency_, number_of_left_players_agent_controls_, number_of_right_players_agent_controls_; + std::tuple channel_dimensions_; + std::map other_config_option_; + void* extra_players_; + + public: + FootballEnv(const Spec& spec, int env_id) + : Env(spec, env_id), + env_name_(spec.config["env_name"_]), + representation_(spec.config["representation"_]), + rewards_(spec.config["rewards"_]), + logdir_(spec.config["logdir"_]), + stacked_(spec.config["stacked"_]), + write_goal_dumps_(spec.config["write_goal_dumps"_]), + write_full_episode_dumps_(spec.config["write_full_episode_dumps"_]), + render_(spec.config["render"_]), + write_video_(spec.config["write_video"_]), + dump_frequency_(spec.config["dump_frequency"_]), + number_of_left_players_agent_controls_(spec.config["number_of_left_players_agent_controls"_]), + number_of_right_players_agent_controls_(spec.config["number_of_right_players_agent_controls"]), + channel_dimensions_(spec.config["channel_dimensions"_]), + other_config_option_(spec.config["other_config_option"_]), + extra_players_(spec.config["extra_players"_]){} + + void reset() override { + clock_t episode_start = clock(); + std::string action_set_name = spec.config["action_set"]; + std::vector action_set; + if(action_set_name = "default"){ + action_set = action_set_dict_default; + } + else if(action_set_name = "v2"){ + action_set = action_set_dict_v2; + } + else{ + action_set = action_set_dict_full; + } + + } + + void step(const Action& action) override { + + } + private: + +} From 46d1081a081c0b5842b6e17819e131cac9cde82f Mon Sep 17 00:00:00 2001 From: kfq2002 <95134838+kfq2002@users.noreply.github.com> Date: Tue, 26 Jul 2022 23:40:07 +0800 Subject: [PATCH 03/28] Add files via upload --- football.h | 5799 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 5503 insertions(+), 296 deletions(-) diff --git a/football.h b/football.h index 324bc025..c5b1ee30 100644 --- a/football.h +++ b/football.h @@ -1,325 +1,5532 @@ -#include "envpool/core/async_envpool.h" -#include "envpool/core/env.h" +#ifndef _GAME_ENV +#define _GAME_ENV + +#define DO_VALIDATION ; +#define X_FIELD_SCALE 54.4 +#define Y_FIELD_SCALE -83.6 +#define Z_FIELD_SCALE 1 +#define MAX_PLAYERS 11 +#define CHECK(a) assert(a); + + #include -#include #include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include -// env-specific definition of config and state/action spec +#include +#include +#include +#include -class FootballEnvFns { - public: - char* cwd[256]; - getcwd(cwd, 256); - std::string cwd_string = cwd; - cwd_string.append("/dump") - static decltype(auto) DefaultConfig() { - return MakeDict("action_set"_.Bind(std::string("default")), - "custom_display_stats"_.Bind(0), - "display_game_stats"_.Bind(true), - "dump_full_episodes"_.Bind(false), - "dump_scores"_.Bind(false), - "players"_.Bind(std::vector{"agent:left_players=1"}), - "level"_.Bind(std::string("11_vs_11_stochastic")), - "physics_steps_per_frame"_.Bind(10), - "render_resolution_x"_.Bind(1280), - "real_time"_.Bind(false), - "tracesdir"_.Bind(cwd_string), - "video_format"_.Bind(std::string("avi")), - "video_quality_level"_.Bind(0), - "write_video"_.Bind(false), - "render_resolution_y"_.Bind(0.5625 * 1280) - ); - } - - template - static decltype(auto) StateSpec(const Config& conf) { - return MakeDict("obs"_.Bind( - Spec({72, 96, 16}, {0, 255}))); - } - template - static decltype(auto) ActionSpec(const Config& conf) { - // the last argument in Spec is for the range definition - return MakeDict("action"_.Bind(Spec({-1}, {0, 18}))); +#if !defined(BOOST_NO_IOSTREAM) +#if !defined(BOOST_NO_IOSFWD) +#endif +#endif +#define SHARED_PTR boost::shared_ptr +#define WEAK_PTR boost::weak_ptr + +constexpr real pi = 3.1415926535897932384626433832795028841972f; // last decimal rounded ;) +const float FORMATION_Y_SCALE = -2.36f; +const unsigned int ballPredictionSize_ms = 3000; +const unsigned int cachedPredictions = 100; +const unsigned int ballHistorySize = 401; +const float idleVelocity = 0.0f; +const float dribbleVelocity = 3.5f; +const float walkVelocity = 5.0f; +const float sprintVelocity = 8.0f; + +const float animSprintVelocity = 7.0f; + +const float idleDribbleSwitch = 1.8f; +const float dribbleWalkSwitch = 4.2f; +const float walkSprintSwitch = 6.0f; + +typedef std::vector StringVector; +typedef std::string screenshoot; +typedef float real; +typedef std::vector vector_Planes; +typedef std::map map_Properties; +typedef intrusive_ptr NodeMap[body_part_max]; +typedef std::vector MovementHistory; + +real clamp(const real value, const real min, const real max) { + DO_VALIDATION; + assert(max >= min); + if (min > value) return min; + if (max < value) return max; + return value; +} + +void Log(e_LogType logType, std::string className, std::string methodName, std::string message); +void intrusive_ptr_add_ref(RefCounted *p); +void intrusive_ptr_release(RefCounted *p); +float EnumToFloatVelocity(e_Velocity velocity) { DO_VALIDATION; + switch (velocity) { DO_VALIDATION; + case e_Velocity_Idle: + return idleVelocity; + break; + case e_Velocity_Dribble: + return dribbleVelocity; + break; + case e_Velocity_Walk: + return walkVelocity; + break; + case e_Velocity_Sprint: + return sprintVelocity; + break; } + return 0; +} + +struct Position { + Position(float x = 0.0, float y = 0.0, float z = 0.0, bool env_coords = false) { + if (env_coords) { + value[0] = X_FIELD_SCALE * x; + value[1] = Y_FIELD_SCALE * y; + value[2] = Z_FIELD_SCALE * z; + } + else { + value[0] = x; + value[1] = y; + value[2] = z; + } + } + Position(const Position& other) { + value[0] = other.value[0]; + value[1] = other.value[1]; + value[2] = other.value[2]; + } + Position& operator=(float* position) { + value[0] = position[0]; + value[1] = position[1]; + value[2] = position[2]; + return *this; + } + bool operator == (const Position& f) const { + return value[0] == f.value[0] && + value[1] == f.value[1] && + value[2] == f.value[2]; + } + float env_coord(int index) const; + std::string debug(); +private: + float value[3]; }; -// this line will concat common config and common state/action spec -using FootballEnvSpec = EnvSpec; -class CoreAction{ - public: - std::string backend_action_; - std::string name_; - bool sticky_ = false; - bool directional_ = false; +enum e_SystemType { + e_SystemType_None = 0, + e_SystemType_Graphics = 1, + e_SystemType_Physics = 2, + e_SystemType_Audio = 3, + e_SystemType_UserStart = 4 +}; - CoreAction(std::string backend_action, std::string name, bool sticky, bool directional): - backend_action_(backend_action), - name_(name), - sticky_(sticky), - directional_(directional){} +enum e_ObjectType { + e_ObjectType_Camera = 1, + e_ObjectType_Image2D = 2, + e_ObjectType_Geometry = 3, + e_ObjectType_Skybox = 4, + e_ObjectType_Light = 5, + e_ObjectType_UserStart = 7 + }; - bool is_in_actionset(const Spec& spec) { - std::string action_set_name = spec.config["action_set"]; - if (action_set_name == "default") { - return !(std::find(action_set_dict_default.begin(), action_set_dict_default.end(), *this) == action_set_dict_default.end()); - } - else if (action_set_name == "v2") { - return !(std::find(action_set_dict_v2.begin(), action_set_dict_v2.end(), *this) == action_set_dict_v2.end()); - } - else { - return !(std::find(action_set_dict_full.begin(), action_set_dict_full.end(), *this) == action_set_dict_full.end()); +enum e_SceneType { + e_SceneType_Scene2D = 1, + e_SceneType_Scene3D = 2 +}; + +enum e_PlayerRole { + e_PlayerRole_GK, + e_PlayerRole_CB, + e_PlayerRole_LB, + e_PlayerRole_RB, + e_PlayerRole_DM, + e_PlayerRole_CM, + e_PlayerRole_LM, + e_PlayerRole_RM, + e_PlayerRole_AM, + e_PlayerRole_CF, +}; + +enum e_CullingMode { + e_CullingMode_Off, + e_CullingMode_Front, + e_CullingMode_Back + }; + +enum e_Velocity { + e_Velocity_Idle, + e_Velocity_Dribble, + e_Velocity_Walk, + e_Velocity_Sprint +}; + +enum e_StrictMovement { + e_StrictMovement_False, + e_StrictMovement_True, + e_StrictMovement_Dynamic +}; + +enum e_DefString { + e_DefString_Empty = 0, + e_DefString_OutgoingSpecialState = 1, + e_DefString_IncomingSpecialState = 2, + e_DefString_SpecialVar1 = 3, + e_DefString_SpecialVar2 = 4, + e_DefString_Type = 5, + e_DefString_Trap = 6, + e_DefString_Deflect = 7, + e_DefString_Interfere = 8, + e_DefString_Trip = 9, + e_DefString_ShortPass = 10, + e_DefString_LongPass = 11, + e_DefString_Shot = 12, + e_DefString_Sliding = 13, + e_DefString_Movement = 14, + e_DefString_Special = 15, + e_DefString_BallControl = 16, + e_DefString_HighPass = 17, + e_DefString_Catch = 18, + e_DefString_OutgoingRetainState = 19, + e_DefString_IncomingRetainState = 20, + e_DefString_Size = 21 +}; + +enum BodyPart { + middle, + neck, + left_thigh, + right_thigh, + left_knee, + right_knee, + left_ankle, + right_ankle, + left_shoulder, + right_shoulder, + left_elbow, + right_elbow, + body, + player, + body_part_max + }; + +enum e_FunctionType { + e_FunctionType_None, + e_FunctionType_Movement, + e_FunctionType_BallControl, + e_FunctionType_Trap, + e_FunctionType_ShortPass, + e_FunctionType_LongPass, + e_FunctionType_HighPass, + e_FunctionType_Header, + e_FunctionType_Shot, + e_FunctionType_Deflect, + e_FunctionType_Catch, + e_FunctionType_Interfere, + e_FunctionType_Trip, + e_FunctionType_Sliding, + e_FunctionType_Special +}; + +enum e_BlendingMode { + e_BlendingMode_Off, + e_BlendingMode_On + }; + +enum e_BlendingFunction { + e_BlendingFunction_Zero, + e_BlendingFunction_One +}; + +enum PlayerStat { + physical_balance, + physical_reaction, + physical_acceleration, + physical_velocity, + physical_stamina, + physical_agility, + physical_shotpower, + technical_standingtackle, + technical_slidingtackle, + technical_ballcontrol, + technical_dribble, + technical_shortpass, + technical_highpass, + technical_header, + technical_shot, + technical_volley, + mental_calmness, + mental_workrate, + mental_resilience, + mental_defensivepositioning, + mental_offensivepositioning, + mental_vision, + player_stat_max +}; + +enum e_DepthFunction { + e_DepthFunction_Never, + e_DepthFunction_Equal, + e_DepthFunction_Greater, + e_DepthFunction_Less, + e_DepthFunction_GreaterOrEqual, + e_DepthFunction_LessOrEqual, + e_DepthFunction_NotEqual, + e_DepthFunction_Always +}; + +enum e_TextureMode { + e_TextureMode_Off, + e_TextureMode_2D +}; + +enum e_InternalPixelFormat { +// e_InternalPixelFormat_RGB, + e_InternalPixelFormat_RGB8, + e_InternalPixelFormat_SRGB8, + e_InternalPixelFormat_RGB16, +// e_InternalPixelFormat_RGBA, + e_InternalPixelFormat_RGBA8, + e_InternalPixelFormat_SRGBA8, + e_InternalPixelFormat_RGBA16, + e_InternalPixelFormat_RGBA16F, + e_InternalPixelFormat_RGBA32F, + + e_InternalPixelFormat_RGBA4, + e_InternalPixelFormat_RGB5_A1, + e_InternalPixelFormat_DepthComponent, + e_InternalPixelFormat_DepthComponent16, + e_InternalPixelFormat_DepthComponent24, + e_InternalPixelFormat_DepthComponent32, + e_InternalPixelFormat_DepthComponent32F, + e_InternalPixelFormat_StencilIndex8 + }; + +enum e_GameMode { + e_GameMode_Normal, + e_GameMode_KickOff, + e_GameMode_GoalKick, + e_GameMode_FreeKick, + e_GameMode_Corner, + e_GameMode_ThrowIn, + e_GameMode_Penalty, +}; + +enum e_TextType { + e_TextType_Default, + e_TextType_DefaultOutline, + e_TextType_Caption, + e_TextType_Title, + e_TextType_ToolTip + }; + +enum e_OfficialType { + e_OfficialType_Referee, + e_OfficialType_Linesman +}; + +enum e_DecorationType { + e_DecorationType_Dark1, + e_DecorationType_Dark2, + e_DecorationType_Bright1, + e_DecorationType_Bright2, + e_DecorationType_Toggled + }; + +enum e_TouchType { + e_TouchType_Intentional_Kicked, // goalies can't touch this + e_TouchType_Intentional_Nonkicked, // headers and such + e_TouchType_Accidental, // collisions + e_TouchType_None, + e_TouchType_SIZE +}; + +enum e_LogType { + e_Warning, + e_Error, + e_FatalError + }; + +enum e_InterruptAnim { + e_InterruptAnim_None, + e_InterruptAnim_Switch, + e_InterruptAnim_Sliding, + e_InterruptAnim_Bump, + e_InterruptAnim_Trip, + e_InterruptAnim_Cheat, + e_InterruptAnim_Cancel, + e_InterruptAnim_ReQueue +}; + +enum e_LocalMode { + e_LocalMode_Relative, + e_LocalMode_Absolute + }; + +enum e_SpatialDataType { + e_SpatialDataType_Position, + e_SpatialDataType_Rotation, + e_SpatialDataType_Both +}; + +enum e_Foot { + e_Foot_Left, + e_Foot_Right + }; + +enum e_PlayerColor { + e_PlayerColor_Blue, + e_PlayerColor_Green, + e_PlayerColor_Red, + e_PlayerColor_Yellow, + e_PlayerColor_Purple, + e_PlayerColor_Default +}; + +enum e_ButtonFunction { + e_ButtonFunction_LongPass, + e_ButtonFunction_HighPass, + e_ButtonFunction_ShortPass, + e_ButtonFunction_Shot, + e_ButtonFunction_KeeperRush, + e_ButtonFunction_Sliding, + e_ButtonFunction_Pressure, + e_ButtonFunction_TeamPressure, + e_ButtonFunction_Switch, + e_ButtonFunction_Sprint, + e_ButtonFunction_Dribble, + e_ButtonFunction_Size +}; + +enum e_MatchPhase { + e_MatchPhase_PreMatch, + e_MatchPhase_1stHalf, + e_MatchPhase_2ndHalf, +}; + +enum e_PixelFormat { + e_PixelFormat_Alpha, + e_PixelFormat_RGB, + e_PixelFormat_RGBA, + e_PixelFormat_DepthComponent, + e_PixelFormat_Luminance + }; + +enum e_ViewRenderTarget { + e_ViewRenderTarget_Texture, + e_ViewRenderTarget_Context + }; + +enum e_TargetAttachment { + e_TargetAttachment_None, + e_TargetAttachment_Front, + e_TargetAttachment_Back, + e_TargetAttachment_Depth, // can not be used with drawbuffers + e_TargetAttachment_Stencil, // can not be used with drawbuffers + e_TargetAttachment_Color0, + e_TargetAttachment_Color1, + e_TargetAttachment_Color2, + e_TargetAttachment_Color3 + }; + +enum e_DecayType { + e_DecayType_Constant, + e_DecayType_Variable +}; + +enum e_MagnetType { + e_MagnetType_Attract, + e_MagnetType_Repel +}; + +struct PlayerInfo { + PlayerInfo() { } + PlayerInfo(const PlayerInfo& f) { + player_position = f.player_position; + player_direction = f.player_direction; + has_card = f.has_card; + is_active = f.is_active; + tired_factor = f.tired_factor; + role = f.role; + designated_player = f.designated_player; + } + bool operator == (const PlayerInfo& f) const { + return player_position == f.player_position && + player_direction == f.player_direction && + has_card == f.has_card && + is_active == f.is_active && + tired_factor == f.tired_factor && + role == f.role && + designated_player == f.designated_player; + } + Position player_position; + Position player_direction; + bool has_card = false; + bool is_active = true; + bool designated_player = false; + float tired_factor = 0.0f; + e_PlayerRole role = e_PlayerRole_GK; +}; + +struct ControllerInfo { + ControllerInfo() {} + ControllerInfo(int controller_player) : controlled_player(controlled_player) {} + bool operator == (const ControllerInfo& f)const { + return controlled_player == f.controlled_player; + } + int controlled_player = -1; +}; + +struct sharedInfo { + Position ball_position; + Position ball_direction; + Position ball_rotation; + std::vector left_team; + std::vector right_team; + std::vector left_controllers; + std::vector right_controllers; + int left_goals, right_goals; + e_GameMode game_mode; + bool is_in_play = false; + int ball_owned_team = 0; + int ball_owned_player = 0; + int step = 0; +}; + +class radian { +public: + radian() {DO_VALIDATION;} + radian(float r) : _angle(r) {DO_VALIDATION;} + std::ostream& operator<<(std::ostream& os) { + os << _angle << " " << _rotated; + return os; + } + radian &operator+=(radian r) { DO_VALIDATION; + _angle += r._angle; + _rotated ^= r._rotated; + return *this; + } + radian &operator-=(radian r){ + _angle -= r._angle; + _rotated ^= r._rotated; + return *this; + } + radian &operator/=(radian r) { DO_VALIDATION; + *this = radian(real(*this) / real(r)); + return *this; + } + radian &operator*=(radian r) { DO_VALIDATION; + *this = radian(real(*this) * real(r)); + return *this; + } + operator real() const { + if (_rotated) { DO_VALIDATION; + return _angle - pi; + } + return _angle; + } + void Mirror() { DO_VALIDATION; + _rotated = !_rotated; + } +private: + float _angle = 0.0f; + bool _rotated = false; +}; + +class Matrix4 { + + public: + Matrix4(); + Matrix4(const real values[16]); + virtual ~Matrix4(); + + // ----- operator overloading + void operator = (const Matrix3 &mat3); + Matrix4 operator * (const Matrix4 &multiplier) const; + bool operator == (const Matrix4 &mat); + bool operator != (const Matrix4 &mat); + + // ----- mathematics + Matrix4 GetInverse() const; + void Transpose(); + Matrix4 GetTransposed() const; + void SetTranslation(const Vector3 &trans); + Vector3 GetTranslation() const; + void Translate(const Vector3 &trans); + Matrix4 GetTranslated(const Vector3 &trans); + void SetScale(const Vector3 &scale); + Vector3 GetScale() const; + void Construct(const Vector3 &position, const Vector3 &scale, const Quaternion &rotation); + void ConstructInverse(const Vector3 &position, const Vector3 &scale, const Quaternion &rotation); + void MultiplyVec4(float x, float y, float z, float w, float &rx, float &ry, float &rz, float &rw); + void ConstructProjection(float fov, float aspect, float zNear, float zFar); + void ConstructOrtho(float left, float right, float bottom, float top, float zNear, float zFar); + + real elements[16]; + + protected: + + private: + +}; + +class Matrix3 { + + public: + Matrix3(); + Matrix3(real values[9]); + Matrix3(real v1, real v2, real v3, real v4, real v5, real v6, real v7, real v8, real v9); + Matrix3(const Matrix3 &mat3); + Matrix3(const Matrix4 &mat4); + virtual ~Matrix3(); + + // ----- operator overloading + void operator = (const Matrix4 &mat4); + Matrix3 operator * (const Matrix3 &multiplier) const; + Vector3 operator * (const Vector3 &multiplier) const; + + // ----- mathematics + void Transpose(); + + static const Matrix3 ZERO; + static const Matrix3 IDENTITY; + real elements[9]; + + protected: + + private: + +}; + +class Quaternion{ +public: + inline Quaternion(){ + elements[0] = 0; + elements[1] = 0; + elements[2] = 0; + elements[3] = 1; + } + Quaternion(real x, real y, real z, real w); + Quaternion(real values[4]); + void Set(real x, real y, real z, real w); + void Set(const Quaternion &quat); + void Set(const Matrix3 &mat); + bool operator != (const Quaternion &fac) const; + const Quaternion operator * (float scale) const; + Vector3 operator * (const Vector3 &fac) const; + void operator = (const Vector3 &vec); + Quaternion operator * (const Quaternion &fac) const; + Quaternion operator + (const Quaternion &q2) const; + Quaternion operator - (const Quaternion &q2) const; + Quaternion operator - () const; + + Quaternion GetInverse() const; + void ConstructMatrix(Matrix3 &rotation) const; + void GetAngles(real &X, real &Y, real &Z) const; + void SetAngles(real X, real Y, real Z); + void GetAngleAxis(radian &rfangle, Vector3 &rkaxis) const; + void SetAngleAxis(const radian &rfangle, const Vector3 &rkaxis); + void conjugate(); + Quaternion conjugate_get() const; + void scale(const real fac); + real GetMagnitude() const; + void Normalize(); + Quaternion GetNormalized() const; + float GetDotProduct(const Quaternion &subject) const; + Quaternion GetLerped(float bias, const Quaternion &to) const; // bias > 1 can extrapolate small angles in a hacky, incorrect way *edit: is that so? i'm not so sure + Quaternion GetSlerped(float bias, const Quaternion &to) const; + Quaternion GetRotationTo(const Quaternion &to) const; + Quaternion GetRotationMultipliedBy(float factor) const; + radian GetRotationAngle(const Quaternion &to) const { + return 2.0f * std::acos(clamp(this->GetDotProduct(to), -1.0f, 1.0f)); + } + float MakeSameNeighborhood(const Quaternion &src); // returns dot product as added bonus! ;) + real elements[4]; +}; + +class Vector3 { +public: + Vector3(); + Vector3(const Vector3 &src) { + coords[0] = src.coords[0]; + coords[1] = src.coords[1]; + coords[2] = src.coords[2]; + } + Vector3(real xyz); + Vector3(real x, real y, real z); + void Mirror() { coords[0] = -coords[0]; coords[1] = -coords[1]; } + void Set(real xyz); + void Set(real x, real y, real z); + void Set(const Vector3 &vec); + float GetEnvCoord(int index) const; + void SetEnvCoord(int index, float value); + bool operator == (const Vector3 &vector) const; + bool operator != (const Vector3 &vector) const; + void operator = (const Quaternion &quat); + void operator = (const real src); + void operator = (const Vector3 &src); + Vector3 operator * (const real scalar) const; + Vector3 operator * (const Vector3 &scalar) const; + Vector3 &operator *= (const real scalar); + Vector3 &operator *= (const Vector3 &scalar); + Vector3 &operator *= (const Matrix3 &mat); + Vector3 &operator *= (const Matrix4 &mat); + Vector3 operator / (const real scalar) const; + Vector3 operator / (const Vector3 &scalar) const; + Vector3 &operator /= (const Vector3 &scalar); + Vector3 &operator += (const real scalar); + Vector3 &operator += (const Vector3 &scalar); + Vector3 &operator -= (const Vector3 &scalar); + Vector3 operator + (const Vector3 &vec) const; + const Vector3 &operator + () const; + Vector3 operator + (const real value) const; + Vector3 operator - (const Vector3 &vec) const; + Vector3 operator - () const; + Vector3 operator - (const real value) const; + bool operator < (const Vector3 &vector) const; + Vector3 GetCrossProduct(const Vector3 &fac) const; + real GetDotProduct(const Vector3 &fac) const; + void ConstructMatrix(Matrix3 &mat) const; + void FastNormalize(); + void Normalize(const Vector3 &ifNull); + void Normalize(); + void NormalizeTo(float length); + void NormalizeMax(float length); + Vector3 GetNormalized(const Vector3 &ifNull) const; + Vector3 GetNormalized() const; + Vector3 GetNormalizedTo(float length) const; + Vector3 GetNormalizedMax(float length) const; + real GetDistance(const Vector3 &fac) const; + real GetLength() const; + real GetSquaredLength() const; + radian GetAngle2D() const; + radian GetAngle2D(const Vector3 &test) const; + void Rotate(const Quaternion &quat); + void Rotate2D(const radian angle); + Vector3 GetRotated2D(const radian angle) const; + Vector3 Get2D() const; + bool Compare(const Vector3 &test) const; + Vector3 GetAbsolute() const; + Vector3 EnforceMaximumDeviation(const Vector3 &deviant, float maxDeviation) const; + Vector3 GetClamped2D(const Vector3 &v1, const Vector3 &v2) const; + void Extrapolate(const Vector3 &direction, unsigned long time); + real coords[3]; +}; + +class RefCounted { + + public: + RefCounted(); + virtual ~RefCounted(); + + RefCounted(const RefCounted &src); + RefCounted& operator=(const RefCounted &src); + + unsigned long GetRefCount(); + + protected: + + private: + volatile long refCount = 0; + friend void intrusive_ptr_add_ref(RefCounted *p); + friend void intrusive_ptr_release(RefCounted *p); + + }; + +class Observer : public RefCounted { + + public: + Observer(); + virtual ~Observer(); + + void SetSubjectPtr(void *subjectPtr); + + protected: + void *subjectPtr; + + }; + +class Interpreter : public Observer { + + public: + virtual e_SystemType GetSystemType() const = 0; + virtual void OnSynchronize() { DO_VALIDATION; + Log(e_FatalError, "Interpreter", "OnSynchronize", "OnSynchronize not written yet for this object! N00B!"); } - } + + protected: + +}; + +template class intrusive_ptr +{ +private: + + typedef intrusive_ptr this_type; + +public: + + typedef T element_type; + + BOOST_CONSTEXPR intrusive_ptr() BOOST_SP_NOEXCEPT : px( 0 ) + { + } + + intrusive_ptr( T * p, bool add_ref = true ): px( p ) + { + if( px != 0 && add_ref ) intrusive_ptr_add_ref( px ); + } + +#if !defined(BOOST_NO_MEMBER_TEMPLATES) || defined(BOOST_MSVC6_MEMBER_TEMPLATES) + + template +#if !defined( BOOST_SP_NO_SP_CONVERTIBLE ) + + intrusive_ptr( intrusive_ptr const & rhs, typename boost::detail::sp_enable_if_convertible::type = boost::detail::sp_empty() ) + +#else + + intrusive_ptr( intrusive_ptr const & rhs ) + +#endif + : px( rhs.get() ) + { + if( px != 0 ) intrusive_ptr_add_ref( px ); + } + +#endif + + intrusive_ptr(intrusive_ptr const & rhs): px( rhs.px ) + { + if( px != 0 ) intrusive_ptr_add_ref( px ); + } + + ~intrusive_ptr() + { + if( px != 0 ) intrusive_ptr_release( px ); + } + +#if !defined(BOOST_NO_MEMBER_TEMPLATES) || defined(BOOST_MSVC6_MEMBER_TEMPLATES) + + template intrusive_ptr & operator=(intrusive_ptr const & rhs) + { + this_type(rhs).swap(*this); + return *this; + } + +#endif + +// Move support + +#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) + + intrusive_ptr(intrusive_ptr && rhs) BOOST_SP_NOEXCEPT : px( rhs.px ) + { + rhs.px = 0; + } + + intrusive_ptr & operator=(intrusive_ptr && rhs) BOOST_SP_NOEXCEPT + { + this_type( static_cast< intrusive_ptr && >( rhs ) ).swap(*this); + return *this; + } + + template friend class intrusive_ptr; + + template +#if !defined( BOOST_SP_NO_SP_CONVERTIBLE ) + + intrusive_ptr(intrusive_ptr && rhs, typename boost::detail::sp_enable_if_convertible::type = boost::detail::sp_empty()) + +#else + + intrusive_ptr(intrusive_ptr && rhs) + +#endif + : px( rhs.px ) + { + rhs.px = 0; + } + + template + intrusive_ptr & operator=(intrusive_ptr && rhs) BOOST_SP_NOEXCEPT + { + this_type( static_cast< intrusive_ptr && >( rhs ) ).swap(*this); + return *this; + } + +#endif + + intrusive_ptr & operator=(intrusive_ptr const & rhs) + { + this_type(rhs).swap(*this); + return *this; + } + + intrusive_ptr & operator=(T * rhs) + { + this_type(rhs).swap(*this); + return *this; + } + + void reset() + { + this_type().swap( *this ); + } + + void reset( T * rhs ) + { + this_type( rhs ).swap( *this ); + } + + void reset( T * rhs, bool add_ref ) + { + this_type( rhs, add_ref ).swap( *this ); + } + + T * get() const BOOST_SP_NOEXCEPT + { + return px; + } + + T * detach() BOOST_SP_NOEXCEPT + { + T * ret = px; + px = 0; + return ret; + } + + T & operator*() const BOOST_SP_NOEXCEPT_WITH_ASSERT + { + BOOST_ASSERT( px != 0 ); + return *px; + } + + T * operator->() const BOOST_SP_NOEXCEPT_WITH_ASSERT + { + BOOST_ASSERT( px != 0 ); + return px; + } + +// implicit conversion to "bool" +#include + + void swap(intrusive_ptr & rhs) BOOST_SP_NOEXCEPT + { + T * tmp = px; + px = rhs.px; + rhs.px = tmp; + } + +private: + + T * px; +}; + +template inline bool operator==(intrusive_ptr const & a, intrusive_ptr const & b) BOOST_SP_NOEXCEPT +{ + return a.get() == b.get(); } -class DumpConfig{ - public: - int max_count_ = 1; - int steps_before_ = 100; - int steps_after_ = 0; - int min_frequency_ = 10; - ObservationProcessor active_dump = NULL; - clock_t last_dump_time = clock() - 2 * min_frequency_; - DumpConfig(int max_count, int steps_before, int steps_after, int min_frequency) : - max_count_(max_count), steps_before_(steps_before), steps_after_(steps_after){} +template inline bool operator!=(intrusive_ptr const & a, intrusive_ptr const & b) BOOST_SP_NOEXCEPT +{ + return a.get() != b.get(); +} +template inline bool operator==(intrusive_ptr const & a, U * b) BOOST_SP_NOEXCEPT +{ + return a.get() == b; } -class ObservationState{ - public: - std::maptrace_; - std::vectoradditional_frames; - std::vectordebugs; - ObservationState(std::maptrace):trace_(trace){} - + +template inline bool operator!=(intrusive_ptr const & a, U * b) BOOST_SP_NOEXCEPT +{ + return a.get() != b; } -class ObservationProcessor{ - public: - float ball_takeover_epsilon = 0.03; - float ball_lost_epsilon = 0.05; - int frame = 0; - Spec spec_self; - std::dequetrace; - nullptr_t state = NULL; - std::map dump_config; - Spec& spec_self; - - ObservationProcessor(const Spec& spec){ - spec_self = spec; - int max_count, steps_before = 100, steps_after = 1, min_frequency = 600; - if(spec.config["dump_socre"]){ - max_count = 100000; - } - else{ - max_count = 0; - } - dump_config.insert(pair("score", DumpConfig(max_count, steps_before, steps_after, min_frequency))); - dump_config.insert(pair("lost_score", DumpConfig(max_count, steps_before, steps_after, min_frequency))); - steps_after = 10000; - steps_before = 0; - min_frequency = 10; - if(spec.config["dump_full_episodes"]){ - max_count = 100000; - } - else{ - max_count = 0; - } - dump_config.insert(pair("episode_done", DumpConfig(max_count, steps_before, steps_after, min_frequency))); - max_count = 1; - steps_before = 100; - steps_after = 0; - min_frequency = 10; - dump_config.insert(pair("shutdown", DumpConfig(max_count, steps_before, steps_after, min_frequency))); - this->clear_state(); - } - void clear_state(); - void reset(); - int len(); - void add_frame(int frame); - void upstate(std::dequetrace_); - - std::vector pending_dumps(); + +template inline bool operator==(T * a, intrusive_ptr const & b) BOOST_SP_NOEXCEPT +{ + return a == b.get(); } -void ObservationProcessor::clear_state(){ - this->frame = 0; - this->state = NULL; - this->trace.clear(); +template inline bool operator!=(T * a, intrusive_ptr const & b) BOOST_SP_NOEXCEPT +{ + return a != b.get(); } -void ObservationProcessor::reset(){ - this->clear_state(); + +#if __GNUC__ == 2 && __GNUC_MINOR__ <= 96 + +// Resolve the ambiguity between our op!= and the one in rel_ops + +template inline bool operator!=(intrusive_ptr const & a, intrusive_ptr const & b) BOOST_SP_NOEXCEPT +{ + return a.get() != b.get(); } -int ObservationProcessor::len(){ - return(this->trace.size()); + +#endif + +#if !defined( BOOST_NO_CXX11_NULLPTR ) + +template inline bool operator==( intrusive_ptr const & p, boost::detail::sp_nullptr_t ) BOOST_SP_NOEXCEPT +{ + return p.get() == 0; } -void ObservationProcessor::add_frame(int frame){ - if (this->trace.size() > 0 && this->spec_self.config["write_video"]){ - this->trace.back().add_frame(frame); - for(int i = 0; i < this->pending_dumps().size; i++){ - this->pending_dumps()[i].add_frame(frame); - } - } + +template inline bool operator==( boost::detail::sp_nullptr_t, intrusive_ptr const & p ) BOOST_SP_NOEXCEPT +{ + return p.get() == 0; } -void ObservationProcessor::upstate(std::maptrace){ - this->frame += 1; - int frame = trace["frame"]; - if(this->spec_self.config["write_video"] == false && trace["observation"] == "frame"){ - std::mapno_video_trace = trace; - no_video_trace["observation"] = trace["observation"]; - no_video_trace.erase("observation"); - no_video_trace.erase("frame"); - } +template inline bool operator!=( intrusive_ptr const & p, boost::detail::sp_nullptr_t ) BOOST_SP_NOEXCEPT +{ + return p.get() != 0; } -std::vector ObservationProcessor::pending_dumps(){ - std::vectordumps; - std::map::iterator iter; - for(iter = this->dump_config.begin(); iter != _map.end(); iter++) { - if(iter->second.active_dump != NULL){ - dumps.push_back(iter->second.active_dump); - } - } - return(dumps); + +template inline bool operator!=( boost::detail::sp_nullptr_t, intrusive_ptr const & p ) BOOST_SP_NOEXCEPT +{ + return p.get() != 0; } -action_idle = CoreAction(e_BackendAction.idle, "idle", false, false); -action_builtin_ai = CoreAction(e_BackendAction.builtin_ai, "builtin_ai", false, false); -action_left = CoreAction( - e_BackendAction.left, "left", true, true); -action_top_left = CoreAction( - e_BackendAction.top_left, "top_left", true, true); -action_top = CoreAction( - e_BackendAction.top, "top", true, true); -action_top_right = CoreAction( - e_BackendAction.top_right, "top_right", true, true); -action_right = CoreAction( - e_BackendAction.right, "right", true, true); -action_bottom_right = CoreAction( - e_BackendAction.bottom_right, "bottom_right", true, true); -action_bottom = CoreAction( - e_BackendAction.bottom, "bottom", true, true); -action_bottom_left = CoreAction( - e_BackendAction.bottom_left, "bottom_left", true, true); -action_long_pass = CoreAction(e_BackendAction.long_pass, "long_pass", false, false); -action_high_pass = CoreAction(e_BackendAction.high_pass, "high_pass", false, false); -action_short_pass = CoreAction(e_BackendAction.short_pass, "short_pass", false, false); -action_shot = CoreAction(e_BackendAction.shot, "shot", false, false); -action_keeper_rush = CoreAction( - e_BackendAction.keeper_rush, "keeper_rush", true, false); -action_sliding = CoreAction(e_BackendAction.sliding, "sliding", false, false); -action_pressure = CoreAction( - e_BackendAction.pressure, "pressure", true, false); -action_team_pressure = CoreAction( - e_BackendAction.team_pressure, "team_pressure", true, false); -action_switch = CoreAction(e_BackendAction.switch, "switch", false, false); -action_sprint = CoreAction(e_BackendAction.sprint, "sprint", true, false); -action_dribble = CoreAction( - e_BackendAction.dribble, "dribble", true, false); -action_release_direction = CoreAction( - e_BackendAction.release_direction, "release_direction", true, false); -action_release_long_pass = CoreAction(e_BackendAction.release_long_pass, - "release_long_pass", false, false); -action_release_high_pass = CoreAction(e_BackendAction.release_high_pass, - "release_high_pass", false, false); -action_release_short_pass = CoreAction(e_BackendAction.release_short_pass, - "release_short_pass", false, false); -action_release_shot = CoreAction(e_BackendAction.release_shot, "release_shot", false, false); -action_release_keeper_rush = CoreAction(e_BackendAction.release_keeper_rush, - "release_keeper_rush", false, false); -action_release_sliding = CoreAction(e_BackendAction.release_sliding, - "release_sliding", false, false); -action_release_pressure = CoreAction(e_BackendAction.release_pressure, - "release_pressure", false, false); -action_release_team_pressure = CoreAction(e_BackendAction.release_team_pressure, - "release_team_pressure", false, false); -action_release_switch = CoreAction(e_BackendAction.release_switch, - "release_switch", false, false); -action_release_sprint = CoreAction(e_BackendAction.release_sprint, - "release_sprint", false, false); -action_release_dribble = CoreAction(e_BackendAction.release_dribble, - "release_dribble", false, false); - -std::vector action_set_dict_default = {action_idle, action_left, action_top_left, action_top, - action_top_right, action_right, action_bottom_right, - action_bottom, action_bottom_left, action_long_pass, - action_high_pass, action_short_pass, action_shot, - action_sprint, action_release_direction, action_release_sprint, - action_sliding, action_dribble, action_release_dribble}; -std::vector action_set_dict_v2 = {action_idle, action_left, action_top_left, action_top, - action_top_right, action_right, action_bottom_right, - action_bottom, action_bottom_left, action_long_pass, - action_high_pass, action_short_pass, action_shot, - action_sprint, action_release_direction, action_release_sprint, - action_sliding, action_dribble, action_release_dribble, action_builtin_ai}; -std::vector action_set_dict_full = {action_idle, action_left, action_top_left, action_top, - action_top_right, action_right, action_bottom_right, - action_bottom, action_bottom_left, action_long_pass, - action_high_pass, action_short_pass, action_shot, - action_keeper_rush, action_sliding, action_pressure, - action_team_pressure, action_switch, action_sprint, - action_dribble, action_release_direction, - action_release_long_pass, action_release_high_pass, - action_release_short_pass, action_release_shot, - action_release_keeper_rush, action_release_sliding, - action_release_pressure, action_release_team_pressure, - action_release_switch, action_release_sprint, - action_release_dribble, action_builtin_ai}; -class FootballEnv : public Env { - protected: - const std::map player_config; - player_config.insert(pair("index", 0)); - const int agent_index = -1; - const int agent_left_position = -1; - const int agent_right_position = -1; - - std::string env_name_, representation_, rewards_, logdir_; - bool stacked_, write_goal_dumps_, write_full_episode_dumps_, render_, write_video_; - int dump_frequency_, number_of_left_players_agent_controls_, number_of_right_players_agent_controls_; - std::tuple channel_dimensions_; - std::map other_config_option_; - void* extra_players_; +#endif - public: - FootballEnv(const Spec& spec, int env_id) - : Env(spec, env_id), - env_name_(spec.config["env_name"_]), - representation_(spec.config["representation"_]), - rewards_(spec.config["rewards"_]), - logdir_(spec.config["logdir"_]), - stacked_(spec.config["stacked"_]), - write_goal_dumps_(spec.config["write_goal_dumps"_]), - write_full_episode_dumps_(spec.config["write_full_episode_dumps"_]), - render_(spec.config["render"_]), - write_video_(spec.config["write_video"_]), - dump_frequency_(spec.config["dump_frequency"_]), - number_of_left_players_agent_controls_(spec.config["number_of_left_players_agent_controls"_]), - number_of_right_players_agent_controls_(spec.config["number_of_right_players_agent_controls"]), - channel_dimensions_(spec.config["channel_dimensions"_]), - other_config_option_(spec.config["other_config_option"_]), - extra_players_(spec.config["extra_players"_]){} - - void reset() override { - clock_t episode_start = clock(); - std::string action_set_name = spec.config["action_set"]; - std::vector action_set; - if(action_set_name = "default"){ - action_set = action_set_dict_default; - } - else if(action_set_name = "v2"){ - action_set = action_set_dict_v2; - } - else{ - action_set = action_set_dict_full; - } - - } +template inline bool operator<(intrusive_ptr const & a, intrusive_ptr const & b) BOOST_SP_NOEXCEPT +{ + return std::less()(a.get(), b.get()); +} - void step(const Action& action) override { - - } - private: +template void swap(intrusive_ptr & lhs, intrusive_ptr & rhs) BOOST_SP_NOEXCEPT +{ + lhs.swap(rhs); +} + +// mem_fn support + +template T * get_pointer(intrusive_ptr const & p) BOOST_SP_NOEXCEPT +{ + return p.get(); +} + +// pointer casts + +template intrusive_ptr static_pointer_cast(intrusive_ptr const & p) +{ + return static_cast(p.get()); +} +template intrusive_ptr const_pointer_cast(intrusive_ptr const & p) +{ + return const_cast(p.get()); } + +template intrusive_ptr dynamic_pointer_cast(intrusive_ptr const & p) +{ + return dynamic_cast(p.get()); +} + +#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) + +template intrusive_ptr static_pointer_cast( intrusive_ptr && p ) BOOST_SP_NOEXCEPT +{ + return intrusive_ptr( static_cast( p.detach() ), false ); +} + +template intrusive_ptr const_pointer_cast( intrusive_ptr && p ) BOOST_SP_NOEXCEPT +{ + return intrusive_ptr( const_cast( p.detach() ), false ); +} + +template intrusive_ptr dynamic_pointer_cast( intrusive_ptr && p ) BOOST_SP_NOEXCEPT +{ + T * p2 = dynamic_cast( p.get() ); + + intrusive_ptr r( p2, false ); + + if( p2 ) p.detach(); + + return r; +} + +#endif // defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) + +#if !defined(BOOST_NO_IOSTREAM) + +#if defined(BOOST_NO_TEMPLATED_IOSTREAMS) || ( defined(__GNUC__) && (__GNUC__ < 3) ) + +template std::ostream & operator<< (std::ostream & os, intrusive_ptr const & p) +{ + os << p.get(); + return os; +} + +#else + +// in STLport's no-iostreams mode no iostream symbols can be used +#ifndef _STLP_NO_IOSTREAMS + +# if defined(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_MSVC, < 1300 && __SGI_STL_PORT) +// MSVC6 has problems finding std::basic_ostream through the using declaration in namespace _STL +using std::basic_ostream; +template basic_ostream & operator<< (basic_ostream & os, intrusive_ptr const & p) +# else +template std::basic_ostream & operator<< (std::basic_ostream & os, intrusive_ptr const & p) +# endif +{ + os << p.get(); + return os; +} + +#endif // _STLP_NO_IOSTREAMS + +#endif // __GNUC__ < 3 + +#endif // !defined(BOOST_NO_IOSTREAM) + +template< class T > struct hash; + +template< class T > std::size_t hash_value( intrusive_ptr const & p ) BOOST_SP_NOEXCEPT +{ + return boost::hash< T* >()( p.get() ); +} + +#if !defined(BOOST_NO_CXX11_HDR_FUNCTIONAL) + +namespace std +{ + +template struct hash< ::intrusive_ptr > +{ + std::size_t operator()( ::intrusive_ptr const & p ) const BOOST_SP_NOEXCEPT + { + return std::hash< T* >()( p.get() ); + } +}; + +} // namespace std + +#endif // #if !defined(BOOST_NO_CXX11_HDR_FUNCTIONAL) +#endif // #ifndef BOOST_SMART_PTR_INTRUSIVE_PTR_HPP_INCLUDED + +struct MustUpdateSpatialData { + bool haveTo = false; + bool wihfi = true; + e_SystemType excludeSystem; +}; + +template +class Subject { + + public: + Subject() { DO_VALIDATION; + } + + virtual ~Subject() { DO_VALIDATION; + observers.clear(); + } + + virtual void Attach(intrusive_ptr observer, void *thisPtr = 0) { DO_VALIDATION; + + observer->SetSubjectPtr(thisPtr); + + observers.push_back(observer); + } + + virtual void Detach(intrusive_ptr observer) { DO_VALIDATION; + typename std::vector >::iterator o_iter = observers.begin(); + while (o_iter != observers.end()) { DO_VALIDATION; + if ((*o_iter).get() == observer.get()) { DO_VALIDATION; + (*o_iter).reset(); + o_iter = observers.erase(o_iter); + } else { + o_iter++; + } + } + } + + virtual void DetachAll() { DO_VALIDATION; + typename std::vector >::iterator o_iter = observers.begin(); + while (o_iter != observers.end()) { DO_VALIDATION; + (*o_iter).reset(); + o_iter = observers.erase(o_iter); + } + } + + protected: + std::vector > observers; + + }; + +class Plane { + // vector 0 = a position on the plane + // vector 1 = plane normal + + public: + Plane(); + Plane(const Vector3 vec1, const Vector3 vec2); + ~Plane(); + + void Set(const Vector3 &pos, const Vector3 &dir); + void SetVertex(unsigned char pos, const Vector3 &vec); + const Vector3 &GetVertex(unsigned char pos) const; + + void CalculateDeterminant() const; + real GetDeterminant() const; + + protected: + Vector3 vertices[2]; + mutable real determinant; + mutable bool _dirty_determinant = false; + + private: + + }; + +class AABB { + + public: + AABB(); + AABB(const AABB &src); + virtual ~AABB(); + + AABB operator += (const AABB &add); + AABB operator + (const Vector3 &vec) const; + AABB operator * (const Quaternion &rot) const; + + void Reset(); + + void SetMinXYZ(const Vector3 &min); + void SetMaxXYZ(const Vector3 &max); + + real GetRadius() const; + void GetCenter(Vector3 ¢er) const; + bool Intersects(const Vector3 ¢er, const real radius) const; + bool Intersects(const vector_Planes &planes) const; + bool Intersects(const AABB &src) const; + + void MakeDirty() { DO_VALIDATION; radius_needupdate = true; center_needupdate = true; } + Vector3 minxyz; + Vector3 maxxyz; + mutable real radius = 0.0f; + mutable Vector3 center; + + protected: + mutable bool radius_needupdate = false; + mutable bool center_needupdate = false; + + }; + + + +class Spatial : public RefCounted { + + public: + Spatial(const std::string &name); + virtual ~Spatial(); + + Spatial(const Spatial &src); + + virtual void Exit() = 0; + + void SetLocalMode(e_LocalMode localMode); + e_LocalMode GetLocalMode(); + + void SetName(const std::string &name); + virtual const std::string GetName() const; + + void SetParent(Node *parent); + + void SetPosition(const Vector3 &newPosition, bool updateSpatialData = true); + Vector3 GetPosition() const; + + virtual void SetRotation(const Quaternion &newRotation, bool updateSpatialData = true); + virtual Quaternion GetRotation() const; + + virtual void SetScale(const Vector3 &newScale); + virtual Vector3 GetScale() const; + + virtual Vector3 GetDerivedPosition() const; + virtual Quaternion GetDerivedRotation() const; + virtual Vector3 GetDerivedScale() const; + + virtual void RecursiveUpdateSpatialData(e_SpatialDataType spatialDataType, e_SystemType excludeSystem = e_SystemType_None) = 0; + + virtual void InvalidateBoundingVolume(); + virtual void InvalidateSpatialData(); + + virtual AABB GetAABB() const; + + protected: + std::string name; + + Node *parent; + + Vector3 position; + Quaternion rotation; + Vector3 scale; + + // cache + mutable bool _dirty_DerivedPosition = false; + mutable bool _dirty_DerivedRotation = false; + mutable bool _dirty_DerivedScale = false; + mutable Vector3 _cache_DerivedPosition; + mutable Quaternion _cache_DerivedRotation; + mutable Vector3 _cache_DerivedScale; + + e_LocalMode localMode; + + mutable AABBCache aabb; + + }; + +struct AABBCache { + bool dirty = false; + AABB aabb; +}; + +class Node : public Spatial { + + public: + Node(const std::string &name); + Node(const Node &source, const std::string &postfix, boost::shared_ptr scene3D); + virtual ~Node(); + + virtual void Exit(); + + void AddNode(intrusive_ptr node); + void DeleteNode(intrusive_ptr node); + void GetNodes(std::vector > &gatherNodes, + bool recurse = false) const; + + void AddObject(intrusive_ptr object); + intrusive_ptr GetObject(const std::string &name); + void DeleteObject(intrusive_ptr object, + bool exitObject = true); + + void GetObjects(std::list > &gatherObjects, + bool recurse = true, int depth = 0) const; + + void GetObjects(std::deque < intrusive_ptr > &gatherObjects, const vector_Planes &bounding, bool recurse = true, int depth = 0) const; + void ProcessState(EnvState* state); + + template + inline void GetObjects(e_ObjectType targetObjectType, std::list < intrusive_ptr > &gatherObjects, bool recurse = true, int depth = 0) const { + //objects.Lock(); + int objectsSize = objects.size(); + for (int i = 0; i < objectsSize; i++) { DO_VALIDATION; + if (objects[i]->GetObjectType() == targetObjectType) { DO_VALIDATION; + gatherObjects.push_back(boost::static_pointer_cast(objects[i])); + } + } + + if (recurse) { DO_VALIDATION; + int nodesSize = nodes.size(); + for (int i = 0; i < nodesSize; i++) { DO_VALIDATION; + nodes[i]->GetObjects(targetObjectType, gatherObjects, recurse, depth + 1); + } + } + } + + template + inline void GetObjects(e_ObjectType targetObjectType, std::deque < intrusive_ptr > &gatherObjects, const vector_Planes &bounding, bool recurse = true, int depth = 0) const { + int objectsSize = objects.size(); + for (int i = 0; i < objectsSize; i++) { DO_VALIDATION; + if (objects[i]->GetObjectType() == targetObjectType) { DO_VALIDATION; + if (objects[i]->GetAABB().Intersects(bounding)) gatherObjects.push_back(boost::static_pointer_cast(objects[i])); + } + } + + if (recurse) { DO_VALIDATION; + int nodesSize = nodes.size(); + for (int i = 0; i < nodesSize; i++) { DO_VALIDATION; + if (nodes[i]->GetAABB().Intersects(bounding)) nodes[i]->GetObjects(targetObjectType, gatherObjects, bounding, recurse, depth + 1); + } + } + } + + void PokeObjects(e_ObjectType targetObjectType, e_SystemType targetSystem); + + virtual AABB GetAABB() const; + + virtual void RecursiveUpdateSpatialData(e_SpatialDataType spatialDataType, e_SystemType excludeSystem = e_SystemType_None); + + protected: + mutable std::vector < intrusive_ptr > nodes; + mutable std::vector < intrusive_ptr > objects; + }; + +class Properties { + + public: + Properties(); + Properties(std::vector> values); + virtual ~Properties(); + + bool Exists(const std::string &name) const; + + void Set(const std::string &name, const std::string &value); + void SetInt(const std::string &name, int value); + void Set(const std::string &name, real value); + void SetBool(const std::string &name, bool value); + const std::string &Get( + const std::string &name, + const std::string &defaultValue = "") const; + bool GetBool(const std::string &name, bool defaultValue = false) const; + real GetReal(const std::string &name, real defaultValue = 0) const; + int GetInt(const std::string &name, int defaultValue = 0) const; + void AddProperties(const Properties *userprops); + void AddProperties(const Properties &userprops); + const map_Properties *GetProperties() const; + void ProcessState(EnvState* state); + + protected: + map_Properties properties; + }; + +class Object : public Subject, public Spatial { + + public: + Object(std::string name, e_ObjectType objectType); + virtual ~Object(); + + Object(const Object &src); + + virtual void Exit(); // ATOMIC + + virtual e_ObjectType GetObjectType(); + + virtual bool IsEnabled() { DO_VALIDATION; return enabled; } + virtual void Enable() { DO_VALIDATION; enabled = true; } + virtual void Disable() { DO_VALIDATION; enabled = false; } + + virtual const Properties &GetProperties() const; + virtual bool PropertyExists(const char *property) const; + virtual const std::string &GetProperty(const char *property) const; + + virtual void SetProperties(Properties properties); + virtual void SetProperty(const char *name, const char *value); + + virtual bool RequestPropertyExists(const char *property) const; + virtual std::string GetRequestProperty(const char *property) const; + virtual void AddRequestProperty(const char *property); + virtual void SetRequestProperty(const char *property, const char *value); + + virtual void Synchronize(); + virtual void Poke(e_SystemType targetSystemType); + + virtual void RecursiveUpdateSpatialData(e_SpatialDataType spatialDataType, e_SystemType excludeSystem = e_SystemType_None); + + MustUpdateSpatialData updateSpatialDataAfterPoke; + + virtual intrusive_ptr GetInterpreter(e_SystemType targetSystemType); + + virtual void SetPokePriority(int prio) { DO_VALIDATION; pokePriority = prio; } + virtual int GetPokePriority() const { return pokePriority; } + + // set these before creating system objects + + Properties properties; + + + + protected: + e_ObjectType objectType; + + mutable int pokePriority; + + // request these to be set by observing objects + mutable Properties requestProperties; + + bool enabled = false; + + }; + +class ISystemObject { + public: + virtual ~ISystemObject() { DO_VALIDATION;}; + + virtual intrusive_ptr GetInterpreter(e_ObjectType objectType) = 0; + + protected: + +}; + +class ISceneInterpreter : public Interpreter { + + public: + virtual void OnLoad() = 0; + virtual void OnUnload() = 0; + + virtual ISystemObject *CreateSystemObject(Object* object) = 0; + + protected: + +}; + +class GraphicsScene { + + public: + GraphicsScene(GraphicsSystem *graphicsSystem); + virtual ~GraphicsScene(); + + virtual GraphicsSystem *GetGraphicsSystem(); + + virtual ISystemObject *CreateSystemObject(Object* object); + + virtual intrusive_ptr GetInterpreter(e_SceneType sceneType); + + protected: + GraphicsSystem *graphicsSystem; +}; + +class IScene : public Subject { + + public: + virtual void Init() = 0; + virtual void Exit() = 0; // ATOMIC + + virtual void CreateSystemObjects(intrusive_ptr object) = 0; + + virtual void PokeObjects(e_ObjectType targetObjectType, e_SystemType targetSystemType) = 0; + virtual bool SupportedObjectType(e_ObjectType objectType) const = 0; + + protected: + + }; + +template +class Resource : public RefCounted { + + public: + Resource(std::string identString) : resource(0), identString(identString) { DO_VALIDATION; + resource = new T(); + } + + virtual ~Resource() { DO_VALIDATION; + delete resource; + resource = 0; + } + + Resource(const Resource &src, const std::string &identString) : identString(identString) { DO_VALIDATION; + this->resource = new T(*src.resource); + } + + + + T *GetResource() { DO_VALIDATION; + return resource; + } + + std::string GetIdentString() { DO_VALIDATION; + return identString; + } + + T *resource; + + protected: + const std::string identString; + + }; + +struct SDL_Surface; + +class Surface { + + public: + Surface(); + virtual ~Surface(); + Surface(const Surface &src); + + SDL_Surface *GetData(); + void SetData(SDL_Surface *surface); + + void Resize(int x, int y); // 0 == dependent on other coord + + protected: + SDL_Surface *surface; + + }; + +struct Material { + intrusive_ptr < Resource > diffuseTexture; + intrusive_ptr < Resource > normalTexture; + intrusive_ptr < Resource > specularTexture; + intrusive_ptr < Resource > illuminationTexture; + float shininess = 0.0f; + float specular_amount = 0.0f; + Vector3 self_illumination; + }; + +struct MaterializedTriangleMesh { + Material material; + + float *vertices; // was: triangleMesh + int verticesDataSize = 0; // was: triangleMeshSize + + /* contents: + float vertices[verticesDataSize * 3]; + float normals[verticesDataSize * 3]; + float texturevertices[verticesDataSize * 3]; + float tangents[verticesDataSize * 3]; + float bitangents[verticesDataSize * 3]; + */ + + std::vector indices; + }; + +class GeometryData { + + public: + GeometryData(); + virtual ~GeometryData(); + GeometryData(const GeometryData &src); + + + void AddTriangleMesh(Material material, float *vertices, + int verticesDataSize, + std::vector indices); + std::vector < MaterializedTriangleMesh > GetTriangleMeshes(); + std::vector < MaterializedTriangleMesh > &GetTriangleMeshesRef(); + void SetDynamic(bool dynamic) { DO_VALIDATION; isDynamic = dynamic; } + bool IsDynamic() { DO_VALIDATION; return isDynamic; } + + AABB GetAABB() const; + + protected: + bool isDynamic = false; + std::vector < MaterializedTriangleMesh > triangleMeshes; + + mutable AABBCache aabb; + + }; + +class Geometry : public Object { + + public: + Geometry(std::string name, e_ObjectType objectType = e_ObjectType_Geometry); + Geometry(const Geometry &src, const std::string &postfix); + virtual ~Geometry(); + + virtual void Exit(); + + void SetGeometryData(intrusive_ptr < Resource > geometryData); + intrusive_ptr < Resource > GetGeometryData(); + + void OnUpdateGeometryData(bool updateMaterials = true); + + virtual void Poke(e_SystemType targetSystemType); + + void RecursiveUpdateSpatialData(e_SpatialDataType spatialDataType, e_SystemType excludeSystem = e_SystemType_None); + + virtual AABB GetAABB() const; + + protected: + intrusive_ptr < Resource > geometryData; + + }; + +enum e_LightType { + e_LightType_Directional, + e_LightType_Point + }; + +class Light : public Object { + + public: + Light(std::string name); + virtual ~Light(); + + virtual void Exit(); + + virtual void SetColor(const Vector3 &color); + virtual Vector3 GetColor() const; + + virtual void SetRadius(float radius); + virtual float GetRadius() const; + + virtual void SetType(e_LightType lightType); + virtual e_LightType GetType() const; + + virtual void SetShadow(bool shadow); + virtual bool GetShadow() const; + + virtual void UpdateValues(); + + virtual void EnqueueShadowMap(intrusive_ptr camera, std::deque < intrusive_ptr > visibleGeometry); + virtual void Poke(e_SystemType targetSystemType); + + virtual void RecursiveUpdateSpatialData(e_SpatialDataType spatialDataType, e_SystemType excludeSystem = e_SystemType_None); + + virtual AABB GetAABB() const; + + protected: + Vector3 color; + float radius = 0.0f; + e_LightType lightType; + bool shadow = false; + + }; + +class Skybox : public Geometry { + + public: + Skybox(std::string name); + virtual ~Skybox(); + + protected: + + }; + +class Camera : public Object { + + public: + Camera(std::string name); + virtual ~Camera(); + + virtual void Init(); + virtual void Exit(); + + virtual void SetFOV(float fov); + virtual float GetFOV() const { return fov; } + virtual void SetCapping(float nearCap, float farCap); + virtual void GetCapping(float &nearCap, float &farCap) const { nearCap = this->nearCap; farCap = this->farCap; } + + + virtual void EnqueueView(std::deque > &visibleGeometry, std::deque < intrusive_ptr > &visibleLights, std::deque < intrusive_ptr > &skyboxes); + virtual void Poke(e_SystemType targetSystemType); + + virtual void RecursiveUpdateSpatialData(e_SpatialDataType spatialDataType, e_SystemType excludeSystem = e_SystemType_None); + + protected: + float fov = 0.0f; + float nearCap = 0.0f; + float farCap = 0.0f; + + }; + +class GraphicsTask { + + public: + GraphicsTask(GraphicsSystem *system); + ~GraphicsTask(); + void Render(bool swap_buffer); + protected: + bool Execute(intrusive_ptr camera); + void EnqueueShadowMap(intrusive_ptr camera, intrusive_ptr light); + + GraphicsSystem *graphicsSystem; + }; + +struct Shader { + std::string name; + unsigned int programID = 0; + unsigned int vertexShaderID = 0; + unsigned int fragmentShaderID = 0; + }; + +class Texture { + + public: + Texture(); + virtual ~Texture(); + + void SetRenderer3D(Renderer3D *renderer3D); + + void DeleteTexture(); + int CreateTexture(e_InternalPixelFormat internalPixelFormat, e_PixelFormat pixelFormat, int width, int height, bool alpha, bool repeat, bool mipmaps, bool filter, bool compareDepth = false); + void ResizeTexture(SDL_Surface *image, e_InternalPixelFormat internalPixelFormat, e_PixelFormat pixelFormat, bool alpha, bool mipmaps); + void UpdateTexture(SDL_Surface *image, bool alpha, bool mipmaps); + + int GetID(); + + void GetSize(int &width, int &height) const { width = this->width; height = this->height; } + + protected: + int textureID = 0; + Renderer3D *renderer3D; + int width, height; + + }; + +struct Overlay2DQueueEntry { + intrusive_ptr < Resource > texture; + int position[2]; + int size[2]; + }; + +struct LightQueueEntry { + bool hasShadow = false; + Matrix4 lightProjectionMatrix; + Matrix4 lightViewMatrix; + intrusive_ptr < Resource > shadowMapTexture; + Vector3 position; + int type = 0; // 0 == directional, 1 == point + Vector3 color; + float radius = 0.0f; + bool shadow = false; + AABB aabb; + }; + +struct View { + e_ViewRenderTarget target; + int targetTexID = 0; + int x, y, width, height; + + int gBufferID = 0; + int gBuffer_DepthTexID = 0; + int gBuffer_AlbedoTexID = 0; + int gBuffer_NormalTexID = 0; + int gBuffer_AuxTexID = 0; + + int accumBufferID = 0; + int accumBuffer_AccumTexID = 0; + int accumBuffer_ModifierTexID = 0; + }; + +struct VertexBufferID { + VertexBufferID() { DO_VALIDATION; + bufferID = -1; + } + int bufferID = 0; // -1 if uninitialized + unsigned int vertexArrayID = 0; + unsigned int elementArrayID = 0; +}; + +struct Renderer3DMaterial { + intrusive_ptr < Resource > diffuseTexture; + intrusive_ptr < Resource > normalTexture; + intrusive_ptr < Resource > specularTexture; + intrusive_ptr < Resource > illuminationTexture; + float shininess = 0.0f; + float specular_amount = 0.0f; + Vector3 self_illumination; + }; + +struct VertexBufferIndex { + int startIndex = 0; + int size = 0; + Renderer3DMaterial material; + }; + +class VertexBuffer { + + public: + VertexBuffer(); + virtual ~VertexBuffer(); + + void SetTriangleMesh(const std::vector& vertices, unsigned int verticesDataSize, std::vector indices); + void TriangleMeshWasUpdatedExternally(unsigned int verticesDataSize, std::vector indices); + VertexBufferID CreateOrUpdateVertexBuffer(Renderer3D *renderer3D, bool dynamicBuffer); + + float* GetTriangleMesh(); + + int GetVaoID(); + + int GetVerticesDataSize(); + + protected: + std::vector vertices; + int verticesDataSize = 0; + std::vector indices; + VertexBufferID vertexBufferID; + int vertexCount = 0; + Renderer3D *renderer3D; + bool dynamicBuffer = false; + + bool sizeChanged = false; + + }; + +struct VertexBufferQueueEntry { + std::list* vertexBufferIndices; + intrusive_ptr < Resource > vertexBuffer; + AABB aabb; + Vector3 position; + Quaternion rotation; + + }; + +enum e_VertexBufferUsage { + e_VertexBufferUsage_StreamDraw, + e_VertexBufferUsage_StreamRead, + e_VertexBufferUsage_StreamCopy, + e_VertexBufferUsage_StaticDraw, + e_VertexBufferUsage_StaticRead, + e_VertexBufferUsage_StaticCopy, + e_VertexBufferUsage_DynamicDraw, + e_VertexBufferUsage_DynamicRead, + e_VertexBufferUsage_DynamicCopy + }; + +enum e_RenderMode { + e_RenderMode_GeometryOnly, + e_RenderMode_Diffuse, + e_RenderMode_Full + }; + +class Renderer3D { + + public: + virtual ~Renderer3D() { DO_VALIDATION;}; + virtual void SetContext() = 0; + virtual void DisableContext() = 0; + virtual const screenshoot& GetScreen() = 0; + + virtual void SwapBuffers() = 0; + + virtual void SetMatrix(const std::string &shaderUniformName, const Matrix4 &matrix) = 0; + + virtual void RenderOverlay2D(const std::vector &overlay2DQueue) = 0; + virtual void RenderOverlay2D() = 0; + virtual void RenderLights(std::deque &lightQueue, const Matrix4 &projectionMatrix, const Matrix4 &viewMatrix) = 0; + + + // --- new & improved + + // init & exit + virtual bool CreateContext(int width, int height, int bpp, bool fullscreen) = 0; + virtual void Exit() = 0; + + virtual int CreateView(float x_percent, float y_percent, float width_percent, float height_percent) = 0; + virtual View &GetView(int viewID) = 0; + virtual void DeleteView(int viewID) = 0; + + // general + virtual void SetCullingMode(e_CullingMode cullingMode) = 0; + virtual void SetBlendingMode(e_BlendingMode blendingMode) = 0; + virtual void SetDepthFunction(e_DepthFunction depthFunction) = 0; + virtual void SetDepthTesting(bool OnOff) = 0; + virtual void SetDepthMask(bool OnOff) = 0; + virtual void SetBlendingFunction(e_BlendingFunction blendingFunction1, e_BlendingFunction blendingFunction2) = 0; + virtual void SetTextureMode(e_TextureMode textureMode) = 0; + virtual void SetColor(const Vector3 &color, float alpha) = 0; + virtual void SetColorMask(bool r, bool g, bool b, bool alpha) = 0; + + virtual void ClearBuffer(const Vector3 &color, bool clearDepth, bool clearColor) = 0; + + virtual Matrix4 CreatePerspectiveMatrix(float aspectRatio, float nearCap = -1, float farCap = -1) = 0; + virtual Matrix4 CreateOrthoMatrix(float left, float right, float bottom, float top, float nearCap = -1, float farCap = -1) = 0; + + // vertex buffers + virtual VertexBufferID CreateVertexBuffer(float *vertices, unsigned int verticesDataSize, const std::vector& indices, e_VertexBufferUsage usage) = 0; + virtual void UpdateVertexBuffer(VertexBufferID vertexBufferID, float *vertices, unsigned int verticesDataSize) = 0; + virtual void DeleteVertexBuffer(VertexBufferID vertexBufferID) = 0; + virtual void RenderVertexBuffer(const std::deque &vertexBufferQueue, e_RenderMode renderMode = e_RenderMode_Full) = 0; + + // lights + virtual void SetLight(const Vector3 &position, const Vector3 &color, float radius) = 0; + + // textures + virtual int CreateTexture(e_InternalPixelFormat internalPixelFormat, e_PixelFormat pixelFormat, int width, int height, bool alpha = false, bool repeat = true, bool mipmaps = true, bool filter = true, bool multisample = false, bool compareDepth = false) = 0; + virtual void ResizeTexture(int textureID, SDL_Surface *source, e_InternalPixelFormat internalPixelFormat, e_PixelFormat pixelFormat, bool alpha = false, bool mipmaps = true) = 0; + virtual void UpdateTexture(int textureID, SDL_Surface *source, bool alpha = false, bool mipmaps = true) = 0; + virtual void DeleteTexture(int textureID) = 0; + virtual void CopyFrameBufferToTexture(int textureID, int width, int height) = 0; + virtual void BindTexture(int textureID) = 0; + virtual void SetTextureUnit(int textureUnit) = 0; + virtual void SetClientTextureUnit(int textureUnit) = 0; + + // frame buffer + virtual int CreateFrameBuffer() = 0; + virtual void DeleteFrameBuffer(int fbID) = 0; + virtual void BindFrameBuffer(int fbID) = 0; + virtual void SetFrameBufferRenderBuffer(e_TargetAttachment targetAttachment, int rbID) = 0; + virtual void SetFrameBufferTexture2D(e_TargetAttachment targetAttachment, int texID) = 0; + virtual bool CheckFrameBufferStatus() = 0; + virtual void SetFramebufferGammaCorrection(bool onOff) = 0; + + // render targets + virtual void SetRenderTargets(std::vector targetAttachments) = 0; + + // utility + virtual void SetFOV(float angle) = 0; + virtual void PushAttribute(int attr) = 0; + virtual void PopAttribute() = 0; + virtual void SetViewport(int x, int y, int width, int height) = 0; + virtual void GetContextSize(int &width, int &height, int &bpp) = 0; + + // shaders + virtual void LoadShader(const std::string &name, const std::string &filename) = 0; + virtual void UseShader(const std::string &name) = 0; + virtual void SetUniformInt(const std::string &shaderName, const std::string &varName, int value) = 0; + virtual void SetUniformFloat(const std::string &shaderName, const std::string &varName, float value) = 0; + virtual void SetUniformFloat2(const std::string &shaderName, const std::string &varName, float value1, float value2) = 0; + virtual void SetUniformFloat3(const std::string &shaderName, const std::string &varName, float value1, float value2, float value3) = 0; + virtual void SetUniformFloat3Array(const std::string &shaderName, const std::string &varName, int count, float *values) = 0; + virtual void SetUniformMatrix4(const std::string &shaderName, const std::string &varName, const Matrix4 &mat) = 0; + + protected: + std::map shaders; + std::map::iterator currentShader; + std::vector views; + + }; + +class Command : public RefCounted { + + public: + Command(); + virtual ~Command(); + bool Handle(void *caller = NULL); + + protected: + virtual bool Execute() = 0; + }; + +template > +class MessageQueue { + + public: + MessageQueue() { DO_VALIDATION;} + virtual ~MessageQueue() { DO_VALIDATION;} + + inline void PushMessage(T message, bool notify = true) { DO_VALIDATION; + queue.push_back(message); + if (notify) NotifyWaiting(); + } + + inline void NotifyWaiting() { DO_VALIDATION; + messageNotification.notify_one(); + } + + inline T GetMessage(bool &MsgAvail) { DO_VALIDATION; + T message; + if (queue.size() > 0) { DO_VALIDATION; + message = *queue.begin(); + queue.pop_front(); + MsgAvail = true; + } else { + MsgAvail = false; + } + return message; + } + + protected: + std::list < T > queue; + boost::condition messageNotification; + + }; + +class GraphicsSystem { + + public: + GraphicsSystem(); + virtual ~GraphicsSystem(); + + virtual void Initialize(bool render, int width_, int height_); + virtual void Exit(); + void SetContext(); + void DisableContext(); + const screenshoot& GetScreen(); + + e_SystemType GetSystemType() const; + + GraphicsScene *Create2DScene(boost::shared_ptr scene); + GraphicsScene *Create3DScene(boost::shared_ptr scene); + + GraphicsTask *GetTask(); + virtual Renderer3D *GetRenderer3D(); + + MessageQueue &GetOverlay2DQueue(); + + Vector3 GetContextSize() { DO_VALIDATION; return Vector3(width, height, bpp); } + + virtual std::string GetName() const { return "graphics"; } + + protected: + const e_SystemType systemType = e_SystemType_Graphics; + + Renderer3D *renderer3DTask = 0; + + GraphicsTask *task = 0; + + MessageQueue overlay2DQueue; + + int width = 0, height = 0, bpp = 0; + + }; + +class Scene : public IScene { + + public: + Scene(); + virtual ~Scene(); + + virtual void Init() = 0; // ATOMIC + virtual void Exit(); // ATOMIC + + virtual void CreateSystemObjects(intrusive_ptr object); + virtual bool SupportedObjectType(e_ObjectType objectType) const; + + protected: + std::vector supportedObjectTypes; + }; + +typedef std::vector < intrusive_ptr > vector_Objects; +class Scene2D : public Scene { + + public: + Scene2D(int width, int height); + virtual ~Scene2D(); + + virtual void Init(); + virtual void Exit(); // ATOMIC + + void AddObject(intrusive_ptr object); + void DeleteObject(intrusive_ptr object); + + void PokeObjects(e_ObjectType targetObjectType, + e_SystemType targetSystemType); + + void GetContextSize(int &width, int &height, int &bpp); + + protected: + vector_Objects objects; + + const int width, height, bpp; + + }; + +class Image2D : public Object { + + public: + Image2D(std::string name); + virtual ~Image2D(); + + virtual void Exit(); + + void SetImage(intrusive_ptr < Resource > image); + intrusive_ptr < Resource > GetImage(); + + void SetPosition(int x, int y); + virtual void SetPosition(const Vector3 &newPosition, bool updateSpatialData = true); + virtual Vector3 GetPosition() const; + Vector3 GetSize() const; + void DrawRectangle(int x, int y, int w, int h, const Vector3 &color, + int alpha = 255); + void Resize(int w, int h); + + virtual void Poke(e_SystemType targetSystemType); + + void OnChange(); + + protected: + int position[2]; + int size[2]; + intrusive_ptr < Resource > image; + + }; + +class Gui2View { + + public: + Gui2View(Gui2WindowManager *windowManager, const std::string &name, float x_percent, float y_percent, float width_percent, float height_percent); + virtual ~Gui2View(); + + virtual void Exit(); + + virtual void UpdateImagePosition(); + virtual void UpdateImageVisibility(); + virtual void AddView(Gui2View *view); + virtual void RemoveView(Gui2View *view); + virtual void SetParent(Gui2View *view); + virtual Gui2View *GetParent(); + virtual void SetPosition(float x_percent, float y_percent); + virtual void GetSize(float &width_percent, float &height_percent) const; + virtual void GetPosition(float &x_percent, float &y_percent) const; + virtual void GetDerivedPosition(float &x_percent, float &y_percent) const; + virtual void CenterPosition(); + virtual void GetImages(std::vector < intrusive_ptr > &target); + + virtual void Redraw() { DO_VALIDATION;} + + bool IsFocussed(); + void SetFocus(); + virtual void OnGainFocus() { DO_VALIDATION; if (!children.empty()) children.at(0)->SetFocus(); } + virtual void OnLoseFocus() { DO_VALIDATION;} + virtual void SetInFocusPath(bool onOff) { DO_VALIDATION; + isInFocusPath = onOff; + if (parent) parent->SetInFocusPath(onOff); + } + + virtual bool IsVisible() { DO_VALIDATION; if (isVisible) { DO_VALIDATION; if (parent) return parent->IsVisible(); else return true; } else return false; } + virtual bool IsSelectable() { DO_VALIDATION; return isSelectable; } + virtual bool IsOverlay() { DO_VALIDATION; return isOverlay; } + + virtual void Show(); + virtual void ShowAllChildren(); + virtual void Hide(); + + void SetRecursiveZPriority(int prio); + virtual void SetZPriority(int prio); + + protected: + Gui2WindowManager *windowManager; + std::string name; + Gui2View *parent; + + std::vector children; + bool exit_called = false; + + float x_percent = 0.0f; + float y_percent = 0.0f; + float width_percent = 0.0f; + float height_percent = 0.0f; + + bool isVisible = false; + bool isSelectable = false; + bool isInFocusPath = false; + bool isOverlay = false; + }; + +class Gui2Root : public Gui2View { + + public: + Gui2Root(Gui2WindowManager *windowManager, const std::string &name, float x_percent, float y_percent, float width_percent, float height_percent); + virtual ~Gui2Root(); + + protected: + + }; + +class Gui2Style { + + public: + Gui2Style(); + virtual ~Gui2Style(); + + void SetFont(e_TextType textType, TTF_Font *font); + void SetColor(e_DecorationType decorationType, const Vector3 &color); + + TTF_Font *GetFont(e_TextType textType) const; + Vector3 GetColor(e_DecorationType decorationType) const; + + protected: + std::map fonts; + std::map colors; + + }; + +class Gui2Frame : public Gui2View { + + public: + Gui2Frame(Gui2WindowManager *windowManager, const std::string &name, float x_percent, float y_percent, float width_percent, float height_percent, bool background = false); + virtual ~Gui2Frame(); + + protected: + + }; + +struct Gui2PageData { + int pageID = 0; + }; + +class Gui2Page : public Gui2Frame { + + public: + Gui2Page(Gui2WindowManager *windowManager, const Gui2PageData &pageData); + virtual ~Gui2Page(); + protected: + Gui2PageData pageData; + + }; + +class Gui2PageFactory { + + public: + Gui2PageFactory(); + virtual ~Gui2PageFactory(); + + virtual void SetWindowManager(Gui2WindowManager *wm); + + virtual Gui2Page *CreatePage(int pageID, void *data = 0); + virtual Gui2Page *CreatePage(const Gui2PageData &pageData) = 0; + + protected: + Gui2WindowManager *windowManager; + }; + +class Gui2PagePath { + + public: + Gui2PagePath() { DO_VALIDATION;}; + virtual ~Gui2PagePath() { DO_VALIDATION; Clear(); }; + + bool Empty() { DO_VALIDATION; return path.empty(); } + void Push(const Gui2PageData &pageData, + Gui2Page *mostRecentlyCreatedPage) { DO_VALIDATION; + CHECK(!this->mostRecentlyCreatedPage); + path.push_back(pageData); + this->mostRecentlyCreatedPage = mostRecentlyCreatedPage; + } + void Pop() { DO_VALIDATION; + path.pop_back(); + } + Gui2PageData GetLast() { DO_VALIDATION; + return path.back(); + } + void Clear() { DO_VALIDATION; + DeleteCurrent(); + path.clear(); + } + Gui2Page* GetMostRecentlyCreatedPage() { DO_VALIDATION; + return mostRecentlyCreatedPage; + } + void DeleteCurrent() { DO_VALIDATION; + if (mostRecentlyCreatedPage) { DO_VALIDATION; + mostRecentlyCreatedPage->Exit(); + delete mostRecentlyCreatedPage; + mostRecentlyCreatedPage = nullptr; + } + } + protected: + std::vector path; + Gui2Page *mostRecentlyCreatedPage = nullptr; + }; + +class Gui2WindowManager { + + public: + Gui2WindowManager(boost::shared_ptr scene2D, float aspectRatio, float margin); + virtual ~Gui2WindowManager(); + + void Exit(); + + Gui2Root *GetRoot() { DO_VALIDATION; return root; } + void SetFocus(Gui2View *view); + + void GetCoordinates(float x_percent, float y_percent, float width_percent, + float height_percent, int &x, int &y, int &width, + int &height) const; + float GetWidthPercent(int pixels); + float GetHeightPercent(int pixels); + intrusive_ptr CreateImage2D(const std::string &name, int width, int height, bool sceneRegister = false); + void UpdateImagePosition(Gui2View *view) const; + void RemoveImage(intrusive_ptr image) const; + + void SetTimeStep_ms(unsigned long timeStep_ms) { DO_VALIDATION; + this->timeStep_ms = timeStep_ms; + }; + + bool IsFocussed(Gui2View *view) { DO_VALIDATION; if (focus == view) return true; else return false; } + + Gui2Style *GetStyle() { DO_VALIDATION; return style; } + + void Show(Gui2View *view); + void Hide(Gui2View *view); + + float GetAspectRatio() const { return aspectRatio; } + + void SetPageFactory(Gui2PageFactory *factory) { DO_VALIDATION; pageFactory = factory; factory->SetWindowManager(this); } + Gui2PageFactory *GetPageFactory() { DO_VALIDATION; return pageFactory; } + Gui2PagePath *GetPagePath() { DO_VALIDATION; return pagePath; } + + protected: + boost::shared_ptr scene2D; + float aspectRatio = 0.0f; + float margin = 0.0f; + float effectiveW = 0.0f; + float effectiveH = 0.0f; + + intrusive_ptr blackoutBackground; + + Gui2Root *root; + Gui2View *focus; + unsigned long timeStep_ms = 0; + + Gui2Style *style; + + Gui2PageFactory *pageFactory; + Gui2PagePath *pagePath; + + }; + +class Gui2Task { + + public: + Gui2Task(boost::shared_ptr scene2D, float aspectRatio, float margin); + ~Gui2Task(); + Gui2WindowManager *GetWindowManager() { DO_VALIDATION; return this->windowManager; } + protected: + Gui2WindowManager *windowManager; + }; + +class Gui2Image : public Gui2View { + + public: + Gui2Image(Gui2WindowManager *windowManager, const std::string &name, float x_percent, float y_percent, float width_percent, float height_percent); + virtual ~Gui2Image(); + + virtual void GetImages(std::vector < intrusive_ptr > &target); + + void LoadImage(const std::string &filename); + virtual void Redraw(); + + protected: + intrusive_ptr image; + intrusive_ptr imageSource; + + }; + +struct SideSelection { + int controllerID = 0; + Gui2Image *controllerImage; + int side = 0; // -1, 0, 1 +}; + +struct TeamTactics { + Properties userProperties; +}; + + +std::string real_to_str(real r) { + DO_VALIDATION; + std::string r_str; + char r_c[32]; + snprintf(r_c, 32, "%f", r); + r_str.assign(r_c); + return r_str; +} +class PlayerProperties { + public: + PlayerProperties() { DO_VALIDATION; + for (int x = 0; x < player_stat_max; x++) { DO_VALIDATION; + data[x] = 1.0f; + } + } + void Set(PlayerStat name, real value) { DO_VALIDATION; + data[name] = atof(real_to_str(value).c_str()); + } + real GetReal(PlayerStat name) const { + return data[name]; + } + + private: + real data[player_stat_max]; +}; + +class PlayerData { + + public: + PlayerData(int playerDatabaseID, bool left_team); + PlayerData(); + virtual ~PlayerData(); + std::string GetLastName() const { return lastName; } + inline float GetStat(PlayerStat name) const { return stats.GetReal(name); } + float get_physical_velocity() const { return physical_velocity; } + + int GetSkinColor() const { return skinColor; } + + std::string GetHairStyle() const { return hairStyle; } + void SetHairStyle(const std::string& style) { DO_VALIDATION; hairStyle = style; } + + std::string GetHairColor() const { return hairColor; } + float GetHeight() const { return height; } + + private: + void UpdateValues(); + float physical_velocity = 0.0; + protected: + PlayerProperties stats; + + int skinColor = 0; + std::string hairStyle; + std::string hairColor; + float height = 0.0f; + std::string firstName; + std::string lastName; +}; + +class TeamData { + + public: + TeamData(int teamDatabaseID, const std::vector& f); + ~TeamData(); + + std::string GetName() const { return name; } + std::string GetShortName() const { return shortName; } + std::string GetLogoUrl() const { return logo_url; } + std::string GetKitUrl() const { return kit_url; } + Vector3 GetColor1() const { return color1; } + Vector3 GetColor2() const { return color2; } + + const TeamTactics &GetTactics() const { return tactics; } + + FormationEntry GetFormationEntry(int num) const; + void SetFormationEntry(int num, FormationEntry entry); + + // vector index# is entry in formation[index#] + int GetPlayerNum() const { return playerData.size(); } + PlayerData *GetPlayerData(int num) const { return playerData.at(num); } + + protected: + std::string name; + std::string shortName; + std::string logo_url; + std::string kit_url; + Vector3 color1, color2; + + TeamTactics tactics; + + std::vector formation; + std::vector playerData; + +}; + +class MatchData { + + public: + MatchData(); + TeamData& GetTeamData(int id) { DO_VALIDATION; return teamData[id]; } + int GetGoalCount(int id) { DO_VALIDATION; return goalCount[id]; } + void SetGoalCount(int id, int amount) { DO_VALIDATION; goalCount[id] = amount; } + void AddPossessionTime(int teamID, unsigned long time); + float GetPossessionFactor_60seconds() { DO_VALIDATION; + return possession60seconds / 60.0f; + } // REMEMBER THESE ARE IRL INGAME SECONDS (because, I guess the tactics + // should be based on irl possession time instead of gametime? not sure + // yet, think about this) + void ProcessState(EnvState* state, int first_team); + protected: + TeamData teamData[2]; + + int goalCount[2]; + + float possession60seconds; // -60 to 60 for possession of team 1 / 2 respectively + +}; + +struct QueuedFixture { + QueuedFixture() { DO_VALIDATION; + team1KitNum = 1; + team2KitNum = 2; + matchData = 0; + } + std::vector sides; // queued match fixture + int team1KitNum, team2KitNum; + MatchData *matchData; +}; + +class MenuTask : public Gui2Task { + + public: + MenuTask(float aspectRatio, float margin, TTF_Font *defaultFont, TTF_Font *defaultOutlineFont, const Properties* config); + virtual ~MenuTask(); + + void SetControllerSetup(const std::vector &sides) { DO_VALIDATION; queuedFixture.sides = sides; } + const std::vector GetControllerSetup() { DO_VALIDATION; + return queuedFixture.sides; + } + int GetTeamKitNum(int teamID) { DO_VALIDATION; if (teamID == 0) return queuedFixture.team1KitNum; else return queuedFixture.team2KitNum; } + void SetMatchData(MatchData *matchData) { DO_VALIDATION; queuedFixture.matchData = matchData; } + MatchData *GetMatchData() { DO_VALIDATION; return queuedFixture.matchData; } // hint: this lock is useless, since we are returning the pointer and not a copy + + protected: + QueuedFixture queuedFixture; + +}; + +class Scene3D : public Scene { + + public: + Scene3D(); + virtual ~Scene3D(); + + virtual void Init(); + virtual void Exit(); // ATOMIC + + void AddNode(intrusive_ptr node); + void DeleteNode(intrusive_ptr node); + + void GetObjects(std::deque < intrusive_ptr > &gatherObjects, const vector_Planes &bounding) const { + hierarchyRoot->GetObjects(gatherObjects, bounding, true, 0); + } + + template + void GetObjects(e_ObjectType targetObjectType, std::list < intrusive_ptr > &gatherObjects) const { + if (!SupportedObjectType(targetObjectType)) { DO_VALIDATION; + Log(e_Error, "Scene3D", "GetObjects", "targetObjectType " + int_to_str(targetObjectType) + " is not supported by this scene"); + return; + } + + hierarchyRoot->GetObjects(targetObjectType, gatherObjects, true, 0); + } + + template + void GetObjects(e_ObjectType targetObjectType, std::deque < intrusive_ptr > &gatherObjects, const vector_Planes &bounding) const { + if (!SupportedObjectType(targetObjectType)) { DO_VALIDATION; + Log(e_Error, "Scene3D", "GetObjects", "targetObjectType " + int_to_str(targetObjectType) + " is not supported by this scene"); + return; + } + + hierarchyRoot->GetObjects(targetObjectType, gatherObjects, bounding, true, 0); + } + + void PokeObjects(e_ObjectType targetObjectType, e_SystemType targetSystemType); + + protected: + intrusive_ptr hierarchyRoot; + + }; + +class ObjectFactory { + + public: + ObjectFactory(); + virtual ~ObjectFactory(); + + intrusive_ptr CopyObject(intrusive_ptr source, std::string postfix = "_copy"); + }; + +template < typename T > +class Loader { + + public: + virtual void Load(std::string filename, intrusive_ptr < Resource > resource) = 0; + + protected: + + }; + +template +class ResourceManager { + + public: + ResourceManager() { DO_VALIDATION;}; + + ~ResourceManager() { DO_VALIDATION; + + resources.clear(); + + loaders.clear(); + }; + + void RegisterLoader(const std::string &extension, Loader *loader) { DO_VALIDATION; + //printf("registering loader for extension %s\n", extension.c_str()); + loaders.insert(std::make_pair(extension, loader)); + } + + intrusive_ptr < Resource > Fetch(const std::string &filename, bool load = true, bool useExisting = true) { DO_VALIDATION; + bool foo = false; + return Fetch(filename, load, foo, useExisting); + } + + intrusive_ptr< Resource > Fetch(const std::string &filename, bool load, bool &alreadyThere, bool useExisting) { DO_VALIDATION; + std::string adaptedFilename = get_file_name(filename); + + // resource already loaded? + + bool success = false; + intrusive_ptr < Resource > foundResource; + + if (useExisting) { DO_VALIDATION; + foundResource = Find(adaptedFilename, success); + } + + if (success) { DO_VALIDATION; + // resource is already there! w00t, that'll win us some cycles + // (or user wants a new copy) + + alreadyThere = true; + + return foundResource; + } + + else { + + // create resource + + alreadyThere = false; + intrusive_ptr < Resource > resource(new Resource(adaptedFilename)); + + // try to load + + if (load) { DO_VALIDATION; + std::string extension = get_file_extension(filename); + std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); + typename std::map < std::string, Loader* >::iterator iter = loaders.find(extension); + if (iter != loaders.end()) { DO_VALIDATION; + (*iter).second->Load(filename, resource); + } else { + Log(e_FatalError, "ResourceManager<>", "Load", "There is no loader for " + filename); + } + } + Register(resource); + return resource; + } + } + + intrusive_ptr < Resource > FetchCopy(const std::string &filename, const std::string &newName, bool &alreadyThere) { DO_VALIDATION; + intrusive_ptr < Resource > resourceCopy; + if (resources.find(newName) != resources.end()) { DO_VALIDATION; + //Log(e_Warning, "ResourceManager", "FetchCopy", "Duplicate key '" + newName + "' - returning existing resource instead of copy (maybe just use Fetch() instead?)"); + resourceCopy = Fetch(newName, false, true); + } else { + intrusive_ptr < Resource > resource = Fetch(filename, true, alreadyThere, true); + + resourceCopy = intrusive_ptr < Resource >(new Resource(*resource, newName)); + + Register(resourceCopy); + } + + return resourceCopy; + } + + void RemoveUnused() { DO_VALIDATION; + // periodically execute this cleanup code somewhere + // currently invoked from scheduler, could be a user task? + // as if it were a service.. + // would be slower, but somewhat cooler :p + + // cleanup + + + + typename std::map < std::string, intrusive_ptr< Resource > >::iterator resIter = resources.begin(); + while (resIter != resources.end()) { DO_VALIDATION; + if (resIter->second->GetRefCount() == 1) { DO_VALIDATION; + //printf("removing unused %s resource '%s'\n", typeDescription.c_str(), resIter->second->GetIdentString().c_str()); + resources.erase(resIter++); + } else { + ++resIter; + } + } + + + } + + void Remove(const std::string &identString) { DO_VALIDATION; + + auto iter = resources.find(identString); + if (iter != resources.end()) { DO_VALIDATION; + resources.erase(iter); + } + + } + + protected: + + intrusive_ptr < Resource > Find(const std::string &identString, bool &success) { DO_VALIDATION; + + typename std::map < std::string, intrusive_ptr< Resource > >::iterator resIter = resources.find(identString); + if (resIter != resources.end()) { DO_VALIDATION; + success = true; + intrusive_ptr < Resource > resource = (*resIter).second; + + return resource; + } else { + success = false; + + return intrusive_ptr < Resource >(); + } + } + + void Register(intrusive_ptr < Resource > resource) { DO_VALIDATION; + + + + //printf("registering %s\n", resource->GetIdentString().c_str()); + if (resources.find(resource->GetIdentString()) != resources.end()) { DO_VALIDATION; + Remove(resource->GetIdentString()); + if (resources.find(resource->GetIdentString()) != resources.end()) { DO_VALIDATION; + Log(e_FatalError, "ResourceManager", "Register", "Duplicate key '" + resource->GetIdentString() + "'"); + } + } + resources.insert(std::make_pair(resource->GetIdentString(), resource)); + } + + std::map < std::string, Loader* > loaders; + + std::map < std::string, intrusive_ptr < Resource > > resources; + + private: + + }; + +struct s_treeentry { + std::string name; + std::vector values; + + s_tree *subtree; + + s_treeentry() { DO_VALIDATION; + subtree = NULL; + } + + ~s_treeentry(); + }; + +struct s_tree { + std::vector entries; + + ~s_tree() { DO_VALIDATION; + for (int i = 0; i < (signed int)entries.size(); i++) { DO_VALIDATION; + delete entries[i]; + } + entries.clear(); + } + }; + +struct s_Material { + std::string maps[4]; + std::string shininess; + std::string specular_amount; + Vector3 self_illumination; + }; + +class ASELoader : public Loader { + + public: + ASELoader(); + virtual ~ASELoader(); + + // ----- encapsulating load function + virtual void Load(std::string filename, intrusive_ptr < Resource > resource); + + // ----- interpreter for the .ase treedata + void Build(const s_tree *data, intrusive_ptr < Resource > resource); + + // ----- per-object interpreters + void BuildTriangleMesh(const s_tree *data, intrusive_ptr < Resource > resource, std::vector materialList); + + protected: + + int triangleCount = 0; + + }; + +class ImageLoader : public Loader { + + public: + ImageLoader(); + virtual ~ImageLoader(); + + virtual void Load(std::string filename, intrusive_ptr < Resource > resource); + + protected: + + }; + +struct BiasedOffset { + Quaternion orientation; + float bias = 0.0f; // 0 .. 1 + void ProcessState(EnvState* state) { DO_VALIDATION; + state->process(orientation); + state->process(bias); + } + }; + +struct BiasedOffsets { + public: + BiasedOffsets() { DO_VALIDATION; + } + BiasedOffsets(const BiasedOffsets &obj) { DO_VALIDATION; + for (int x = 0; x < body_part_max; x++) { DO_VALIDATION; + elements[x] = obj.elements[x]; + } + } + void clear() { DO_VALIDATION; + } + inline BiasedOffset& operator[](BodyPart part) { DO_VALIDATION; + return elements[part]; + } + void ProcessState(EnvState* state) { DO_VALIDATION; + for (auto& el : elements) { DO_VALIDATION; + el.ProcessState(state); + } + } + private: + BiasedOffset elements[body_part_max]; + }; + +struct KeyFrame { + Quaternion orientation; + Vector3 position; + bool operator<(const KeyFrame& a) const { + return position < a.position; + } + }; + +struct KeyFrames { + std::vector> d; + void clear() { DO_VALIDATION; + d.clear(); + } + KeyFrame* getFrame(int frame) { DO_VALIDATION; + for (auto& i : d) { DO_VALIDATION; + if (i.first == frame) { DO_VALIDATION; + return &i.second; + } + } + return nullptr; + } + void addFrame(const std::pair& frame) { DO_VALIDATION; + d.push_back(frame); + std::sort(d.begin(), d.end()); + } + }; + +class AnimationExtension { + + public: + AnimationExtension(Animation *parent) : parent(parent) { DO_VALIDATION;}; + virtual ~AnimationExtension() { DO_VALIDATION; parent = 0; }; + + virtual void Shift(int fromFrame, int offset) = 0; + virtual void Rotate2D(radian angle) = 0; + virtual void Mirror() = 0; + + virtual bool GetKeyFrame(int frame, Quaternion &orientation, Vector3 &position, float &power) const = 0; + virtual void SetKeyFrame(int frame, const Quaternion &orientation, const Vector3 &position = Vector3(0, 0, 0), float power = 1.0) = 0; + virtual void DeleteKeyFrame(int frame) = 0; + + virtual void Load(std::vector &tokenizedLine) = 0; + virtual void Save(FILE *file) = 0; + + protected: + Animation *parent; + + }; + +class VariableCache { + public: + std::string get(const std::string& key) const { + auto iter = values.find(key); + if (iter != values.end()) { DO_VALIDATION; + return iter->second; + } else { + return ""; + } + } + void set(const std::string& key, const std::string& value) { DO_VALIDATION; + values[key] = value; + if (key == "idlelevel") { DO_VALIDATION; + _idlelevel = atof(value.c_str()); + } else if (key == "quadrant_id") { DO_VALIDATION; + _quadrant_id = atoi(value.c_str()); + } else if (key == "specialvar1") { DO_VALIDATION; + _specialvar1 = atof(value.c_str()); + } else if (key == "specialvar2") { DO_VALIDATION; + _specialvar2 = atof(value.c_str()); + } else if (key == "lastditch") { DO_VALIDATION; + _lastditch = value.compare("true") == 0; + } else if (key == "baseanim") { DO_VALIDATION; + _baseanim = value.compare("true") == 0; + } else if (key == "outgoing_special_state") { DO_VALIDATION; + _outgoing_special_state = value; + } else if (key == "incoming_retain_state") { DO_VALIDATION; + _incoming_retain_state = value; + } else if (key == "incoming_special_state") { DO_VALIDATION; + _incoming_special_state = value; + } + } + + void set_specialvar1(float v) { DO_VALIDATION; + _specialvar1 = v; + } + + void set_specialvar2(float v) { DO_VALIDATION; + _specialvar2 = v; + } + + void mirror() { DO_VALIDATION; + for (auto varIter : values) { DO_VALIDATION; + mirror(varIter.second); + } + mirror(_outgoing_special_state); + mirror(_incoming_retain_state); + mirror(_incoming_special_state); + } + + inline float idlelevel() const { return _idlelevel; } + inline int quadrant_id() const { return _quadrant_id; } + inline float specialvar1() const { return _specialvar1; } + inline float specialvar2() const { return _specialvar2; } + inline bool lastditch() const { return _lastditch; } + inline bool baseanim() const { return _baseanim; } + inline const std::string& outgoing_special_state() const { return _outgoing_special_state; } + inline const std::string& incoming_retain_state() const { return _incoming_retain_state; } + inline const std::string& incoming_special_state() const { return _incoming_special_state; } + + private: + void mirror(std::string& varData) { DO_VALIDATION; + if (varData.substr(0, 4) == "left") { DO_VALIDATION; + varData = varData.replace(0, 4, "right"); + } else if (varData.substr(0, 5) == "right") { DO_VALIDATION; + varData = varData.replace(0, 5, "left"); + } + } + + float _idlelevel = 0; + int _quadrant_id = 0; + float _specialvar1 = 0; + float _specialvar2 = 0; + bool _lastditch = false; + bool _baseanim = false; + std::string _outgoing_special_state; + std::string _incoming_retain_state; + std::string _incoming_special_state; + std::map values; + }; + +struct MovementHistoryEntry { + Vector3 position; + Quaternion orientation; + int timeDiff_ms = 0; + BodyPart nodeName; + void ProcessState(EnvState* state) { DO_VALIDATION; + state->process(position); + state->process(orientation); + state->process(timeDiff_ms); + state->process(nodeName); + } + }; + +struct NodeAnimation { + BodyPart nodeName; + KeyFrames animation; // frame, angles + }; + +typedef std::multimap map_XMLTree; + +struct XMLTree { + std::string value; + map_XMLTree children; + }; + +static BiasedOffsets emptyOffsets; + +class Animation { + + public: + Animation(); + Animation(const Animation &src); // attention! this does not deep copy extensions! + virtual ~Animation(); + + void DirtyCache(); // hee hee + + int GetFrameCount() const; + int GetEffectiveFrameCount() const { return GetFrameCount() - 1; } + + bool GetKeyFrame(BodyPart nodeName, int frame, Quaternion &orientation, Vector3 &position) const; + void SetKeyFrame(BodyPart nodeName, int frame, + const Quaternion &orientation, + const Vector3 &position = Vector3(0, 0, 0)); + void GetInterpolatedValues(const KeyFrames &animation, + int frame, Quaternion &orientation, + Vector3 &position) const; + void ConvertToStartFacingForwardIfIdle(); + void Apply(const NodeMap& nodeMap, + int frame, int timeOffset_ms = 0, bool smooth = true, + float smoothFactor = 1.0f, + /*const boost::shared_ptr previousAnimation, int + smoothFrames, */ + const Vector3 &basePos = Vector3(0), radian baseRot = 0, + BiasedOffsets &offsets = emptyOffsets, + MovementHistory *movementHistory = 0, int timeDiff_ms = 10, + bool noPos = false, bool updateSpatial = true); + + // returns end position - start position + Vector3 GetTranslation() const; + Vector3 GetIncomingMovement() const; + float GetIncomingVelocity() const; + Vector3 GetOutgoingMovement() const; + Vector3 GetOutgoingDirection() const; + Vector3 GetIncomingBodyDirection() const; + Vector3 GetOutgoingBodyDirection() const; + float GetOutgoingVelocity() const; + radian GetOutgoingAngle() const; + radian GetIncomingBodyAngle() const; + radian GetOutgoingBodyAngle() const; + e_Foot GetCurrentFoot() const { return currentFoot; } + e_Foot GetOutgoingFoot() const; + + void Reset(); + void LoadData(std::vector < std::vector > &file); + void Load(const std::string &filename); + void Mirror(); + std::string GetName() const; + void SetName(const std::string &name) { DO_VALIDATION; this->name = name; } + + void AddExtension(const std::string &name, boost::shared_ptr extension); + boost::shared_ptr GetExtension(const std::string &name); + + const std::string GetVariable(const char *name) const; + const VariableCache& GetVariableCache() const { + return variableCache; + } + void SetVariable(const std::string &name, const std::string &value); + e_DefString GetAnimType() const { return cache_AnimType; } + + std::vector &GetNodeAnimations() { DO_VALIDATION; + return nodeAnimations; + } + mutable float order_float = 0; + void ProcessState(EnvState* state); + + protected: + std::vector nodeAnimations; + int frameCount = 0; + std::string name; + + std::map < std::string, boost::shared_ptr > extensions; + + boost::shared_ptr customData; + VariableCache variableCache; + + // this hack only applies to humanoids + // it's which foot is moving first in this anim + e_Foot currentFoot; + + mutable bool cache_translation_dirty = false; + mutable Vector3 cache_translation; + mutable bool cache_incomingMovement_dirty = false; + mutable Vector3 cache_incomingMovement; + mutable bool cache_incomingVelocity_dirty = false; + mutable float cache_incomingVelocity = 0.0f; + mutable bool cache_outgoingDirection_dirty = false; + mutable Vector3 cache_outgoingDirection; + mutable bool cache_outgoingMovement_dirty = false; + mutable Vector3 cache_outgoingMovement; + mutable bool cache_rangedOutgoingMovement_dirty = false; + mutable Vector3 cache_rangedOutgoingMovement; + mutable bool cache_outgoingVelocity_dirty = false; + mutable float cache_outgoingVelocity = 0.0f; + mutable bool cache_angle_dirty = false; + mutable radian cache_angle; + mutable bool cache_incomingBodyAngle_dirty = false; + mutable radian cache_incomingBodyAngle; + mutable bool cache_outgoingBodyAngle_dirty = false; + mutable radian cache_outgoingBodyAngle; + mutable bool cache_incomingBodyDirection_dirty = false; + mutable Vector3 cache_incomingBodyDirection; + mutable bool cache_outgoingBodyDirection_dirty = false; + mutable Vector3 cache_outgoingBodyDirection; + e_DefString cache_AnimType; + }; + +typedef std::vector DataSet; + +struct CrudeSelectionQuery { + CrudeSelectionQuery() { DO_VALIDATION; + byFunctionType = false; + byFoot = false; foot = e_Foot_Left; + heedForcedFoot = false; strongFoot = e_Foot_Right; + bySide = false; + allowLastDitchAnims = false; + byIncomingVelocity = false; incomingVelocity_Strict = false; incomingVelocity_NoDribbleToIdle = false; incomingVelocity_NoDribbleToSprint = false; incomingVelocity_ForceLinearity = false; + byOutgoingVelocity = false; + byPickupBall = false; pickupBall = true; + byIncomingBodyDirection = false; incomingBodyDirection_Strict = false; incomingBodyDirection_ForceLinearity = false; + byIncomingBallDirection = false; + byOutgoingBallDirection = false; + byTripType = false; + } + + bool byFunctionType = false; + e_FunctionType functionType; + + bool byFoot = false; + e_Foot foot; + + bool heedForcedFoot = false; + e_Foot strongFoot; + + bool bySide = false; + Vector3 lookAtVecRel; + + bool allowLastDitchAnims = false; + + bool byIncomingVelocity = false; + bool incomingVelocity_Strict = false; // if true, allow no difference in velocity + bool incomingVelocity_NoDribbleToIdle = false; + bool incomingVelocity_NoDribbleToSprint = false; + bool incomingVelocity_ForceLinearity = false; + e_Velocity incomingVelocity; + + bool byOutgoingVelocity = false; + e_Velocity outgoingVelocity; + + bool byPickupBall = false; + bool pickupBall = false; + + bool byIncomingBodyDirection = false; + Vector3 incomingBodyDirection; + bool incomingBodyDirection_Strict = false; + bool incomingBodyDirection_ForceLinearity = false; + + bool byIncomingBallDirection = false; + Vector3 incomingBallDirection; + + bool byOutgoingBallDirection = false; + Vector3 outgoingBallDirection; + + bool byTripType = false; + int tripType = 0; + + VariableCache properties; +}; + +struct Quadrant { + int id = 0; + Vector3 position; + e_Velocity velocity; + radian angle; + void ProcessState(EnvState* state) { + state->process(id); + state->process(position); + state->process(velocity); + state->process(angle); + } +}; + +class AnimCollection { + + public: + // scene3D for debugging pilon + AnimCollection(); + virtual ~AnimCollection(); + + void Clear(); + void Load(); + + const std::vector < Animation* > &GetAnimations() const; + + void CrudeSelection(DataSet &dataSet, const CrudeSelectionQuery &query); + + inline Animation* GetAnim(int index) { DO_VALIDATION; + return animations.at(index); + } + + inline const Quadrant &GetQuadrant(int id) { DO_VALIDATION; + return quadrants.at(id); + } + + int GetQuadrantID(Animation *animation, const Vector3 &movement, radian angle) const; + + void ProcessState(EnvState* state); + + protected: + + void _PrepareAnim(Animation *animation, intrusive_ptr playerNode, const std::list < intrusive_ptr > &bodyParts, const NodeMap &nodeMap, bool convertAngledDribbleToWalk = false); + + bool _CheckFunctionType(e_DefString functionType, e_FunctionType queryFunctionType) const; + + std::vector animations; + std::vector quadrants; + + radian maxIncomingBallDirectionDeviation; + radian maxOutgoingBallDirectionDeviation; + +}; + +struct BallSpatialInfo { + BallSpatialInfo(const Vector3 &momentum, const Quaternion &rotation_ms) { DO_VALIDATION; + this->momentum = momentum; + this->rotation_ms = rotation_ms; + } + Vector3 momentum; + Quaternion rotation_ms; +}; + +class Ball { + + public: + Ball(Match *match); + virtual ~Ball(); + + void Mirror(); + intrusive_ptr GetBallGeom() { DO_VALIDATION; return ball; } + + inline Vector3 Predict(int predictTime_ms) const { + int index = predictTime_ms; + if (index >= ballPredictionSize_ms) index = ballPredictionSize_ms - 10; + index = index / 10; + if (index < 0) index = 0; + return predictions[index]; + } + + void GetPredictionArray(std::vector &target); + Vector3 GetMovement(); + Vector3 GetRotation(); + void Touch(const Vector3 &target); + void SetPosition(const Vector3 &target); + void SetMomentum(const Vector3 &target); + void SetRotation(real x, real y, real z, float bias = 1.0); // radians per second for each axis + BallSpatialInfo CalculatePrediction(); // returns momentum in 10ms + + bool BallTouchesNet() { DO_VALIDATION; return ballTouchesNet; } + Vector3 GetAveragePosition(unsigned int duration_ms) const; + + void Process(); + void Put(); + + void ResetSituation(const Vector3 &focusPos); + void ProcessState(EnvState *state); + private: + intrusive_ptr ballNode; + intrusive_ptr ball; + Vector3 momentum; + Quaternion rotation_ms; + + Vector3 predictions[ballPredictionSize_ms / 10 + cachedPredictions + 1]; + int valid_predictions = 0; + Quaternion orientPrediction; + + std::list ballPosHistory; + + Vector3 positionBuffer; + Quaternion orientationBuffer; + + Match *match; + + bool ballTouchesNet = false; + +}; + +class AIControlledKeyboard { + + public: + AIControlledKeyboard(e_PlayerColor color); + bool GetButton(e_ButtonFunction buttonFunction); + void ResetNotSticky(); + void SetButton(e_ButtonFunction buttonFunction, bool state); + bool GetPreviousButtonState(e_ButtonFunction buttonFunction); + Vector3 GetDirection(); + Vector3 GetOriginalDirection(); + + // Methods for remote controlling. + void SetDirection(const Vector3& new_direction); + bool Disabled() { return disabled_;} + void SetDisabled(bool disabled); + void Reset(); + void ProcessState(EnvState* state); + void Mirror(float mirror); + e_PlayerColor GetPlayerColor() const { return playerColor; } + + private: + Vector3 direction_; + float mirror = 1.0f; + bool disabled_ = false; + bool buttons_pressed_[e_ButtonFunction_Size]; + const e_PlayerColor playerColor; +}; + +struct TouchInfo { + Vector3 inputDirection; + float inputPower = 0; + + float autoDirectionBias = 0; + float autoPowerBias = 0; + + Vector3 desiredDirection; // inputdirection after pass function + float desiredPower = 0; + Player *targetPlayer = 0; // null == do not use + Player *forcedTargetPlayer = 0; // null == do not use + void ProcessState(EnvState* state) { DO_VALIDATION; + state->process(inputDirection); + state->process(inputPower); + state->process(autoDirectionBias); + state->process(autoPowerBias); + state->process(desiredDirection); + state->process(desiredPower); + state->process(targetPlayer); + state->process(forcedTargetPlayer); + } +}; + +struct PlayerCommand { + + /* specialVar1: + + 1: happy celebration + 2: inverse celebration (feeling bad) + 3: referee showing card + */ + + PlayerCommand() { DO_VALIDATION; + desiredFunctionType = e_FunctionType_Movement; + useDesiredMovement = false; + desiredVelocityFloat = idleVelocity; + strictMovement = e_StrictMovement_Dynamic; + useDesiredLookAt = false; + useTripType = false; + useDesiredTripDirection = false; + onlyDeflectAnimsThatPickupBall = false; + tripType = 1; + useSpecialVar1 = false; + specialVar1 = 0; + useSpecialVar2 = false; + specialVar2 = 0; + modifier = 0; + } + + e_FunctionType desiredFunctionType; + + bool useDesiredMovement; + Vector3 desiredDirection; + e_StrictMovement strictMovement; + + float desiredVelocityFloat; + + bool useDesiredLookAt; + Vector3 desiredLookAt; // absolute 'look at' position on pitch + + bool useTouchInfo = false; + TouchInfo touchInfo; + + bool onlyDeflectAnimsThatPickupBall; + + bool useTripType; + int tripType; // only applicable for trip anims + + bool useDesiredTripDirection; + Vector3 desiredTripDirection; + + bool useSpecialVar1; + int specialVar1; + bool useSpecialVar2; + int specialVar2; + + int modifier; + void ProcessState(EnvState* state) { DO_VALIDATION; + state->process(desiredFunctionType); + state->process(useDesiredMovement); + state->process(desiredDirection); + state->process(strictMovement); + state->process(desiredVelocityFloat); + state->process(useDesiredLookAt); + state->process(desiredLookAt); + state->process(useTouchInfo); + touchInfo.ProcessState(state); + state->process(onlyDeflectAnimsThatPickupBall); + state->process(useTripType); + state->process(tripType); + state->process(useDesiredTripDirection); + state->process(desiredTripDirection); + state->process(useSpecialVar1); + state->process(specialVar1); + state->process(useSpecialVar2); + state->process(specialVar2); + state->process(modifier); + } +}; + +typedef std::vector PlayerCommandQueue; +class IController { + + public: + IController(Match *match) : match(match) { DO_VALIDATION;}; + virtual ~IController() { DO_VALIDATION;}; + + virtual void RequestCommand(PlayerCommandQueue &commandQueue) = 0; + virtual void Process() { DO_VALIDATION;}; + virtual Vector3 GetDirection() = 0; + virtual void ProcessState(EnvState* state) = 0; + virtual float GetFloatVelocity() = 0; + virtual void SetPlayer(PlayerBase *player); + + // for convenience + PlayerBase *GetPlayer() { DO_VALIDATION; return player; } + Match *GetMatch() { DO_VALIDATION; return match; } + + virtual int GetReactionTime_ms(); + + virtual void Reset() = 0; + + protected: + PlayerBase *player = 0; + Match *match; +}; + +struct PlayerImage { + Vector3 position; + Vector3 directionVec; + Vector3 movement; + Player *player; + e_Velocity velocity = e_Velocity_Idle; + e_PlayerRole role; + void ProcessState(EnvState* state) { DO_VALIDATION; + state->process(position); + state->process(directionVec); + state->process(movement); + state->process(player); + state->process(velocity); + state->process(role); + } + void Mirror() { DO_VALIDATION; + position.Mirror(); + directionVec.Mirror(); + movement.Mirror(); + } +}; + +struct PlayerImagePosition { + PlayerImagePosition(const Vector3& position, const Vector3& movement, e_PlayerRole player_role) : position(position), movement(movement), player_role(player_role) { DO_VALIDATION;} + Vector3 position; + Vector3 movement; + e_PlayerRole player_role; +}; + +class MentalImage { + public: + MentalImage() { DO_VALIDATION;} + MentalImage(Match *match); + void Mirror(bool team_0, bool team_1, bool ball); + PlayerImage GetPlayerImage(PlayerBase* player) const; + std::vector GetTeamPlayerImages(int teamID) const; + void UpdateBallPredictions(); + Vector3 GetBallPrediction(int time_ms) const; + int GetTimeStampNeg_ms() const; + void ProcessState(EnvState* state, Match* match); + + std::vector players; + std::vector ballPredictions; + unsigned int timeStamp_ms = 0; + float maxDistanceDeviation = 2.5f; + float maxMovementDeviation = walkVelocity; + bool ballPredictions_mirrored = false; + private: + Match *match = nullptr; +}; + +class PlayerController : public IController { + + public: + PlayerController(Match *match); + virtual ~PlayerController() { DO_VALIDATION;}; + + virtual void Process(); + + virtual void SetPlayer(PlayerBase *player); + Player *CastPlayer(); + Team *GetTeam() { DO_VALIDATION; return team; } + Team *GetOppTeam() { DO_VALIDATION; return oppTeam; } + + const MentalImage *GetMentalImage(); + + virtual int GetReactionTime_ms(); + + float GetLastSwitchBias(); + + float GetFadingTeamPossessionAmount() { DO_VALIDATION; return fadingTeamPossessionAmount; } + + void AddDefensiveComponent(Vector3 &desiredPosition, float bias, Player* forcedOpp = 0); + Vector3 GetDefendPosition(Player *opp, float distance = 0.0f); + + virtual void Reset(); + void ProcessPlayerController(EnvState *state); + + protected: + float OppBetweenBallAndMeDot(); + float CouldWinABallDuelLikeliness(); + virtual void _Preprocess(); + virtual void _SetInput(const Vector3 &inputDirection, float inputVelocityFloat) { DO_VALIDATION; this->inputDirection = inputDirection; this->inputVelocityFloat = inputVelocityFloat; } + virtual void _KeeperDeflectCommand(PlayerCommandQueue &commandQueue, bool onlyPickupAnims = false); + virtual void _SetPieceCommand(PlayerCommandQueue &commandQueue); + virtual void _BallControlCommand(PlayerCommandQueue &commandQueue, bool idleTurnToOpponentGoal = false, bool knockOn = false, bool stickyRunDirection = false, bool keepCurrentBodyDirection = false); + virtual void _TrapCommand(PlayerCommandQueue &commandQueue, bool idleTurnToOpponentGoal = false, bool knockOn = false); + virtual void _InterfereCommand(PlayerCommandQueue &commandQueue, bool byAnyMeans = false); + virtual void _SlidingCommand(PlayerCommandQueue &commandQueue); + virtual void _MovementCommand(PlayerCommandQueue &commandQueue, bool forceMagnet = false, bool extraHaste = false); + + Vector3 inputDirection; + float inputVelocityFloat = 0.0f; + + Player *_oppPlayer = nullptr; + float _timeNeeded_ms = 0; + int _mentalImageTime; + + void _CalculateSituation(); + + // only really useful for human gamers, after switching player + unsigned long lastSwitchTime_ms = 0; + unsigned int lastSwitchTimeDuration_ms = 0; + + Team *team = nullptr; + Team *oppTeam = nullptr; + + bool hasPossession = false; + bool hasUniquePossession = false; + bool teamHasPossession = false; + bool teamHasUniquePossession = false; + bool oppTeamHasPossession = false; + bool oppTeamHasUniquePossession = false; + bool hasBestPossession = false; + bool teamHasBestPossession = false; + float possessionAmount = 0.0f; + float teamPossessionAmount = 0.0f; + float fadingTeamPossessionAmount = 0.0f; + int oppTimeNeededToGetToBall = 0; + bool hasBestChanceOfPossession = false; +}; + +class HumanController : public PlayerController { + + public: + HumanController(Match *match = nullptr, AIControlledKeyboard *hid = nullptr); + virtual ~HumanController(); + + virtual void SetPlayer(PlayerBase *player); + bool Disabled() const { + return hid->Disabled(); + } + + virtual void RequestCommand(PlayerCommandQueue &commandQueue); + virtual void Process(); + virtual Vector3 GetDirection(); + virtual float GetFloatVelocity(); + + void PreProcess(Match *match, AIControlledKeyboard *hid) { + this->match = match; + this->hid = hid; + } + + void ProcessState(EnvState* state) { DO_VALIDATION; + ProcessPlayerController(state); + hid->ProcessState(state); + state->process(actionMode); + state->process(actionButton); + state->process(actionBufferTime_ms); + state->process(gauge_ms); + state->process(previousDirection); + state->process(steadyDirection); + state->process(lastSteadyDirectionSnapshotTime_ms); + } + virtual int GetReactionTime_ms(); + + AIControlledKeyboard *GetHIDevice() { return hid; } + + int GetActionMode() { DO_VALIDATION; return actionMode; } + + virtual void Reset(); + + protected: + + void _GetHidInput(Vector3 &rawInputDirection, float &rawInputVelocityFloat); + + AIControlledKeyboard *hid; + + // set when a contextual button (example: pass/defend button) is pressed + // once this is set and the button stays pressed, it stays the same + // 0: undefined, 1: off-the-ball button active, 2: on-the-ball button active/action queued + int actionMode = 0; + + e_ButtonFunction actionButton; + int actionBufferTime_ms = 0; + int gauge_ms = 0; + + // stuff to keep track of analog stick (or keys even) so that we can use a direction once it's been pointed in for a while, instead of directly + Vector3 previousDirection; + Vector3 steadyDirection; + int lastSteadyDirectionSnapshotTime_ms = 0; + float mirror = 1.0; +}; + +class HumanGamer { + + public: + HumanGamer(Team *team, AIControlledKeyboard *hid); + HumanGamer() {} + HumanGamer(const HumanGamer&) = delete; + void operator=(const HumanGamer&) = delete; + ~HumanGamer(); + + Player *GetSelectedPlayer() const { + return selectedPlayer; + } + void SetSelectedPlayer(Player* player); + AIControlledKeyboard *GetHIDevice() { DO_VALIDATION; return hid; } + HumanController* GetHumanController() { DO_VALIDATION; return &controller; } + void ProcessState(EnvState *state); + + protected: + Team *team = nullptr; + AIControlledKeyboard *hid = nullptr; + HumanController controller; + Player *selectedPlayer = nullptr; +}; + +struct TacticalOpponentInfo { + Player *player; + float dangerFactor = 0.0f; + void ProcessState(EnvState* state) { DO_VALIDATION; + state->process(player); + state->process(dangerFactor); + } +}; + +class TeamAIController { + + public: + TeamAIController(Team *team); + virtual ~TeamAIController(); + + void Process(); + + Vector3 GetAdaptedFormationPosition(Player *player, bool useDynamicFormationPosition = true); + void CalculateDynamicRoles(); + float CalculateMarkingQuality(Player *player, Player *opp); + void CalculateManMarking(); + void ApplyOffsideTrap(Vector3 &position) const; + float GetOffsideTrapX() const { return offsideTrapX; } + void PrepareSetPiece(e_GameMode setPiece, Team* other_team, + int kickoffTakerTeamId, int takerTeamID); + Player *GetPieceTaker() { DO_VALIDATION; return taker; } + e_GameMode GetSetPieceType() { DO_VALIDATION; return setPieceType; } + void ApplyAttackingRun(Player *manualPlayer = 0); + void ApplyTeamPressure(); + void ApplyKeeperRush(); + void CalculateSituation(); + + void UpdateTactics(); + + unsigned long GetEndApplyAttackingRun_ms() { DO_VALIDATION; return endApplyAttackingRun_ms; } + Player *GetAttackingRunPlayer() { DO_VALIDATION; return attackingRunPlayer; } + + unsigned long GetEndApplyTeamPressure_ms() { DO_VALIDATION; return endApplyTeamPressure_ms; } + Player *GetTeamPressurePlayer() { DO_VALIDATION; return teamPressurePlayer; } + + Player *GetForwardSupportPlayer() { DO_VALIDATION; return forwardSupportPlayer; } + + unsigned long GetEndApplyKeeperRush_ms() { DO_VALIDATION; return endApplyKeeperRush_ms; } + + const std::vector &GetTacticalOpponentInfo() { DO_VALIDATION; return tacticalOpponentInfo; } + + void Reset(); + void ProcessState(EnvState* state); + + protected: + + Match *match; + Team *team; + Player *taker; + e_GameMode setPieceType; + + Properties baseTeamTactics; + Properties teamTacticsModMultipliers; + Properties liveTeamTactics; + + float offensivenessBias = 0.0f; + + bool teamHasPossession = false; + bool teamHasUniquePossession = false; + bool oppTeamHasPossession = false; + bool oppTeamHasUniquePossession = false; + bool teamHasBestPossession = false; + float teamPossessionAmount = 0.0f; + float fadingTeamPossessionAmount = 0.0f; + int timeNeededToGetToBall = 0; + int oppTimeNeededToGetToBall = 0; + + float depth = 0.0f; + float width = 0.0f; + + float offsideTrapX = 0.0f; + + unsigned long endApplyAttackingRun_ms = 0; + Player *attackingRunPlayer; + unsigned long endApplyTeamPressure_ms = 0; + Player *teamPressurePlayer; + unsigned long endApplyKeeperRush_ms = 0; + + Player *forwardSupportPlayer; // sort of like the attacking run player, but more for a forward offset for a player close to the action, to support the player in possession + + std::vector tacticalOpponentInfo; + +}; + +class Team { + + public: + Team(int id, Match *match, TeamData *teamData, float aiDifficulty); + void Mirror(); + bool isMirrored() { DO_VALIDATION; + return mirrored; + } + bool onOriginalSide() { DO_VALIDATION; + return id == 0 ? (side == -1) : (side == 1); + } + + virtual ~Team(); + + void Exit(); + + void InitPlayers(intrusive_ptr fullbodyNode, + std::map &colorCoords); + + Match *GetMatch() { DO_VALIDATION; return match; } + TeamAIController *GetController() { DO_VALIDATION; return teamController; } + intrusive_ptr GetSceneNode() { DO_VALIDATION; return teamNode; } + + int GetID() const { return id; } + inline signed int GetDynamicSide() { DO_VALIDATION; + return side; + } + inline signed int GetStaticSide() { DO_VALIDATION; + return id == 0 ? -1 : 1; + } + const TeamData *GetTeamData() { DO_VALIDATION; return teamData; } + + FormationEntry GetFormationEntry(void* player); + void SetFormationEntry(Player* player, FormationEntry entry); + float GetAiDifficulty() const { return aiDifficulty; } + const std::vector &GetAllPlayers() { return players; } + void GetAllPlayers(std::vector &allPlayers) { DO_VALIDATION; + allPlayers.insert(allPlayers.end(), players.begin(), players.end()); + } + void GetActivePlayers(std::vector &activePlayers); + int GetActivePlayersCount() const; + Player *MainSelectedPlayer() { return mainSelectedPlayer; } + + unsigned int GetHumanGamerCount() { + int count = 0; + for (auto& g: humanGamers) { DO_VALIDATION; + if (!g->GetHumanController()->Disabled()) { + count++; + } + } + return count; + } + void GetHumanControllers(std::vector& v) { + for (auto& g: humanGamers) { DO_VALIDATION; + v.push_back(g.get()); + } + } + void AddHumanGamers(const std::vector& controllers); + void DeleteHumanGamers(); + e_PlayerColor GetPlayerColor(PlayerBase* player); + int HumanControlledToBallDistance(); + + bool HasPossession() const; + bool HasUniquePossession() const; + int GetTimeNeededToGetToBall_ms() const; + Player *GetDesignatedTeamPossessionPlayer() { DO_VALIDATION; + return designatedTeamPossessionPlayer; + } + void UpdateDesignatedTeamPossessionPlayer(); + Player *GetBestPossessionPlayer(); + float GetTeamPossessionAmount() const; + float GetFadingTeamPossessionAmount() const; + void SetFadingTeamPossessionAmount(float value); + + void SetLastTouchPlayer( + Player *player, e_TouchType touchType = e_TouchType_Intentional_Kicked); + Player *GetLastTouchPlayer() const { return lastTouchPlayer; } + float GetLastTouchBias(int decay_ms, unsigned long time_ms = 0) { DO_VALIDATION; + return lastTouchPlayer + ? lastTouchPlayer->GetLastTouchBias(decay_ms, time_ms) + : 0; + } + + void ResetSituation(const Vector3 &focusPos); + + void HumanGamersSelectAnyone(); + void SetOpponent(Team* opponent) { DO_VALIDATION; this->opponent = opponent; } + Team* Opponent() { DO_VALIDATION; return opponent; } + void SelectPlayer(Player *player); + void DeselectPlayer(Player *player); + + void RelaxFatigue(float howMuch); + + void Process(); + void PreparePutBuffers(); + void FetchPutBuffers(); + void Put(bool mirror); + void Put2D(bool mirror); + void Hide2D(); + + void UpdatePossessionStats(); + void UpdateSwitch(); + void ProcessState(EnvState* state); + + Player *GetGoalie(); + + protected: + const int id; + Match *match; + Team *opponent = 0; + TeamData *teamData; + const float aiDifficulty; + + bool hasPossession = false; + int timeNeededToGetToBall_ms = 0; + Player *designatedTeamPossessionPlayer = 0; + + float teamPossessionAmount = 0.0f; + float fadingTeamPossessionAmount = 0.0f; + + TeamAIController *teamController; + + std::vector players; + + intrusive_ptr teamNode; + intrusive_ptr playerNode; + + std::vector> humanGamers; + + // humanGamers index whose turn it is + // begin() == due next + std::list switchPriority; + Player *lastTouchPlayer = nullptr; + Player *mainSelectedPlayer = nullptr; + + intrusive_ptr < Resource > kit; + int side = -1; + bool mirrored = false; +}; + +struct RefereeBuffer { + // Referee has pending action to execute. + bool active = false; + e_GameMode desiredSetPiece; + signed int teamID = 0; + Team* setpiece_team = 0; + unsigned long stopTime = 0; + unsigned long prepareTime = 0; + unsigned long startTime = 0; + Vector3 restartPos; + Player *taker; + bool endPhase = false; + void ProcessState(EnvState* state); +}; + +struct Foul { + Player *foulPlayer = 0; + Player *foulVictim = 0; + int foulType = 0; // 0: nothing, 1: foul, 2: yellow, 3: red + bool advantage = false; + unsigned long foulTime = 0; + Vector3 foulPosition; + bool hasBeenProcessed = false; + void ProcessState(EnvState* state); +}; + +class Referee { + + public: + Referee(Match *match, bool animations); + virtual ~Referee(); + + void Process(); + + void PrepareSetPiece(e_GameMode setPiece); + + const RefereeBuffer &GetBuffer() { DO_VALIDATION; return buffer; }; + + void AlterSetPiecePrepareTime(unsigned long newTime_ms); + + void BallTouched(); + void TripNotice(Player *tripee, Player *tripper, int tackleType); // 1 == standing tackle resulting in little trip, 2 == standing tackle resulting in fall, 3 == sliding tackle + bool CheckFoul(); + + Player *GetCurrentFoulPlayer() { DO_VALIDATION; return foul.foulPlayer; } + int GetCurrentFoulType() { DO_VALIDATION; return foul.foulType; } + void ProcessState(EnvState* state); + + protected: + Match *match; + + RefereeBuffer buffer; + + int afterSetPieceRelaxTime_ms = 0; // throw-ins cause immediate new throw-ins, because ball is still outside the lines at the moment of throwing ;) + + // Players on offside position at the time of the last ball touch. + std::vector offsidePlayers; + + Foul foul; + const bool animations; +}; + +struct RotationSmuggle { + RotationSmuggle() { DO_VALIDATION; + begin = 0; + end = 0; + } + void operator = (const float &value) { DO_VALIDATION; + begin = value; + end = value; + } + radian begin; + radian end; + void ProcessState(EnvState* state) { DO_VALIDATION; + state->process(begin); + state->process(end); + } +}; + +struct Anim { + Animation *anim = 0; + signed int id = 0; + int frameNum = 0; + e_FunctionType functionType = e_FunctionType_None; + e_InterruptAnim originatingInterrupt = e_InterruptAnim_None; + Vector3 actionSmuggle; + Vector3 actionSmuggleOffset; + Vector3 actionSmuggleSustain; + Vector3 actionSmuggleSustainOffset; + Vector3 movementSmuggle; + Vector3 movementSmuggleOffset; + RotationSmuggle rotationSmuggle; + radian rotationSmuggleOffset = 0; + signed int touchFrame = -1; + Vector3 touchPos; + Vector3 incomingMovement; + Vector3 outgoingMovement; + Vector3 positionOffset; + PlayerCommand originatingCommand; + std::vector positions; + void ProcessState(EnvState* state) { DO_VALIDATION; + state->process(anim); + state->process(id); + state->process(frameNum); + state->process(functionType); + state->process(originatingInterrupt); + state->process(actionSmuggle); + state->process(actionSmuggleOffset); + state->process(actionSmuggleSustain); + state->process(actionSmuggleSustainOffset); + state->process(movementSmuggle); + state->process(movementSmuggleOffset); + rotationSmuggle.ProcessState(state); + state->process(rotationSmuggleOffset); + state->process(touchFrame); + state->process(touchPos); + state->process(incomingMovement); + state->process(outgoingMovement); + state->process(positionOffset); + originatingCommand.ProcessState(state); + state->process(positions); + } +}; + +struct FloatArray { + float *data; + int size = 0; +}; + +struct WeightedBone { + int jointID = 0; + float weight = 0.0f; +}; + +struct WeightedVertex { + int vertexID = 0; + std::vector bones; +}; + +struct HJoint { + intrusive_ptr node; + Vector3 position; + Quaternion orientation; + Vector3 origPos; +}; + +struct RotationSmuggle { + RotationSmuggle() { DO_VALIDATION; + begin = 0; + end = 0; + } + void operator = (const float &value) { DO_VALIDATION; + begin = value; + end = value; + } + radian begin; + radian end; + void ProcessState(EnvState* state) { DO_VALIDATION; + state->process(begin); + state->process(end); + } +}; + +struct AnimApplyBuffer { + AnimApplyBuffer() { DO_VALIDATION; + frameNum = 0; + smooth = true; + smoothFactor = 0.5f; + noPos = false; + orientation = 0; + } + AnimApplyBuffer(const AnimApplyBuffer &src) { DO_VALIDATION; + anim = src.anim; + frameNum = src.frameNum; + smooth = src.smooth; + smoothFactor = src.smoothFactor; + noPos = src.noPos; + position = src.position; + orientation = src.orientation; + offsets = src.offsets; + } + void ProcessState(EnvState* state) { DO_VALIDATION; + state->process(anim); + state->process(frameNum); + state->process(smooth); + state->process(smoothFactor); + state->process(noPos); + state->process(position); + state->process(orientation); + offsets.ProcessState(state); + } + Animation *anim = 0; + int frameNum = 0; + bool smooth = false; + float smoothFactor = 0.0f; + bool noPos = false; + Vector3 position; + radian orientation; + BiasedOffsets offsets; +}; + +struct SpatialState { + Vector3 position; + radian angle; + Vector3 directionVec; // for efficiency, vector version of angle + e_Velocity enumVelocity; + float floatVelocity = 0.0f; // for efficiency, float version + + Vector3 actualMovement; + Vector3 physicsMovement; // ignores effects like positionoffset + Vector3 animMovement; + Vector3 movement; // one of the above (default) + Vector3 actionSmuggleMovement; + Vector3 movementSmuggleMovement; + Vector3 positionOffsetMovement; + + radian bodyAngle; + Vector3 bodyDirectionVec; // for efficiency, vector version of bodyAngle + radian relBodyAngleNonquantized; + radian relBodyAngle; + Vector3 relBodyDirectionVec; // for efficiency, vector version of relBodyAngle + Vector3 relBodyDirectionVecNonquantized; + e_Foot foot; + + void Mirror() { DO_VALIDATION; + position.Mirror(); + actualMovement.Mirror(); + physicsMovement.Mirror(); + animMovement.Mirror(); + movement.Mirror(); + actionSmuggleMovement.Mirror(); + movementSmuggleMovement.Mirror(); + positionOffsetMovement.Mirror(); + } + + void ProcessState(EnvState* state) { DO_VALIDATION; + state->process(position); + state->process(angle); + state->process(directionVec); + state->process(enumVelocity); + state->process(floatVelocity); + state->process(actualMovement); + state->process(physicsMovement); + state->process(animMovement); + state->process(movement); + state->process(actionSmuggleMovement); + state->process(movementSmuggleMovement); + state->process(positionOffsetMovement); + state->process(bodyAngle); + state->process(bodyDirectionVec); + state->process(relBodyAngleNonquantized); + state->process(relBodyAngle); + state->process(relBodyDirectionVec); + state->process(relBodyDirectionVecNonquantized); + state->process(foot); + } +}; + +class HumanoidBase { + + public: + HumanoidBase(PlayerBase *player, Match *match, intrusive_ptr humanoidSourceNode, intrusive_ptr fullbodySourceNode, std::map &colorCoords, boost::shared_ptr animCollection, intrusive_ptr fullbodyTargetNode, intrusive_ptr < Resource > kit); + virtual ~HumanoidBase(); + void Mirror(); + + void PrepareFullbodyModel(std::map &colorCoords); + void UpdateFullbodyNodes(bool mirror); + void UpdateFullbodyModel(bool updateSrc = false); + + virtual void Process(); + void PreparePutBuffers(); + void FetchPutBuffers(); + void Put(bool mirror); + + virtual void CalculateGeomOffsets(); + void SetOffset(BodyPart body_part, float bias, const Quaternion &orientation, bool isRelative = false); + + inline int GetFrameNum() { DO_VALIDATION; return currentAnim.frameNum; } + inline int GetFrameCount() { DO_VALIDATION; return currentAnim.anim->GetFrameCount(); } + + inline Vector3 GetPosition() const { return spatialState.position; } + inline Vector3 GetDirectionVec() const { return spatialState.directionVec; } + inline Vector3 GetBodyDirectionVec() const { + return spatialState.bodyDirectionVec; + } + inline radian GetRelBodyAngle() const { return spatialState.relBodyAngle; } + inline e_Velocity GetEnumVelocity() const { return spatialState.enumVelocity; } + inline e_FunctionType GetCurrentFunctionType() const { return currentAnim.functionType; } + inline e_FunctionType GetPreviousFunctionType() const { return previousAnim_functionType; } + inline Vector3 GetMovement() const { return spatialState.movement; } + + Vector3 GetGeomPosition() { DO_VALIDATION; return humanoidNode->GetPosition(); } + + int GetIdleMovementAnimID(); + void ResetPosition(const Vector3 &newPos, const Vector3 &focusPos); + void OffsetPosition(const Vector3 &offset); + void TripMe(const Vector3 &tripVector, int tripType); + + intrusive_ptr GetHumanoidNode() { DO_VALIDATION; return humanoidNode; } + intrusive_ptr GetFullbodyNode() { DO_VALIDATION; return fullbodyNode; } + + virtual float GetDecayingPositionOffsetLength() const { return decayingPositionOffset.GetLength(); } + virtual float GetDecayingDifficultyFactor() const { return decayingDifficultyFactor; } + + const Anim *GetCurrentAnim() { DO_VALIDATION; return ¤tAnim; } + + const NodeMap &GetNodeMap() { DO_VALIDATION; return nodeMap; } + + void Hide() { DO_VALIDATION; fullbodyNode->SetPosition(Vector3(1000, 1000, -1000)); hairStyle->SetPosition(Vector3(1000, 1000, -1000)); } // hax ;) + + void SetKit(intrusive_ptr < Resource > newKit); + + virtual void ResetSituation(const Vector3 &focusPos); + void ProcessState(EnvState* state); + + protected: + bool _HighOrBouncyBall() const; + void _KeepBestDirectionAnims(DataSet& dataset, const PlayerCommand &command, bool strict = true, radian allowedAngle = 0, int allowedVelocitySteps = 0, int forcedQuadrantID = -1); // ALERT: set sorting predicates before calling this function. strict kinda overrules the allowedstuff + void _KeepBestBodyDirectionAnims(DataSet& dataset, const PlayerCommand &command, bool strict = true, radian allowedAngle = 0); // ALERT: set sorting predicates before calling this function. strict kinda overrules the allowedstuff + virtual bool SelectAnim(const PlayerCommand &command, e_InterruptAnim localInterruptAnim, bool preferPassAndShot = false); // returns false on no applicable anim found + void CalculatePredictedSituation(Vector3 &predictedPos, radian &predictedAngle); + Vector3 CalculateOutgoingMovement(const std::vector &positions) const; + + void CalculateSpatialState(); // realtime properties, based on 'physics' + void CalculateFactualSpatialState(); // realtime properties, based on anim. usable at last frame of anim. more riggid than above function + + void AddTripCommandToQueue(PlayerCommandQueue &commandQueue, const Vector3 &tripVector, int tripType); + PlayerCommand GetTripCommand(const Vector3 &tripVector, int tripType); + PlayerCommand GetBasicMovementCommand(const Vector3 &desiredDirection, float velocityFloat); + + void SetFootSimilarityPredicate(e_Foot desiredFoot) const; + bool CompareFootSimilarity(e_Foot foot, int animIndex1, int animIndex2) const; + void SetIncomingVelocitySimilarityPredicate(e_Velocity velocity) const; + bool CompareIncomingVelocitySimilarity(int animIndex1, int animIndex2) const; + void SetMovementSimilarityPredicate(const Vector3 &relDesiredDirection, e_Velocity desiredVelocity) const; + float GetMovementSimilarity(int animIndex, const Vector3 &relDesiredDirection, e_Velocity desiredVelocity, float corneringBias) const; + bool CompareMovementSimilarity(int animIndex1, int animIndex2) const; + bool CompareByOrderFloat(int animIndex1, int animIndex2) const; + void SetIncomingBodyDirectionSimilarityPredicate( + const Vector3 &relIncomingBodyDirection) const; + bool CompareIncomingBodyDirectionSimilarity(int animIndex1, int animIndex2) const; + void SetBodyDirectionSimilarityPredicate(const Vector3 &lookAt) const; + real DirectionSimilarityRating(int animIndex) const; + bool CompareBodyDirectionSimilarity(int animIndex1, int animIndex2) const; + void SetTripDirectionSimilarityPredicate(const Vector3 &relDesiredTripDirection) const; + bool CompareTripDirectionSimilarity(int animIndex1, int animIndex2) const; + bool CompareBaseanimSimilarity(int animIndex1, int animIndex2) const; + bool CompareCatchOrDeflect(int animIndex1, int animIndex2) const; + void SetIdlePredicate(float desiredValue) const; + bool CompareIdleVariable(int animIndex1, int animIndex2) const; + bool ComparePriorityVariable(int animIndex1, int animIndex2) const; + + Vector3 CalculatePhysicsVector(Animation *anim, bool useDesiredMovement, + const Vector3 &desiredMovement, + bool useDesiredBodyDirection, + const Vector3 &desiredBodyDirectionRel, + std::vector &positions_ret, + radian &rotationOffset_ret) const; + + Vector3 ForceIntoAllowedBodyDirectionVec(const Vector3 &src) const; + radian ForceIntoAllowedBodyDirectionAngle(radian angle) const; // for making small differences irrelevant while sorting + Vector3 ForceIntoPreferredDirectionVec(const Vector3 &src) const; + radian ForceIntoPreferredDirectionAngle(radian angle) const; + + // Seems to be used for rendering only, updated in + // UpdateFullbodyModel / UpdateFullBodyNodes, Hide() method changes + // position, so maybe Hide needs to change, otherwise collision detection + // analysis hidden players? + intrusive_ptr fullbodyNode; + // Modified in PrepareFullBodyModel, not changed later. + std::vector uniqueFullbodyMesh; + // Modified in PrepareFullBodyModel, not changed later. + std::vector < std::vector > weightedVerticesVec; + // Modified in PrepareFullBodyModel, not changed later. + unsigned int fullbodySubgeomCount = 0; + // Used only for memory releasing. + std::vector uniqueIndicesVec; + // Updated in UpdateFullbodyModel / UpdateFullBodyNodes, + // snapshot not needed. References nodes point to humanoidNode. + std::vector joints; + // Used only for memory management. + intrusive_ptr fullbodyTargetNode; + // Used for ball collision detection. Seems to be the one to snapshot. + intrusive_ptr humanoidNode; + // Updated in UpdateFullbodyNodes, no need to snapshot. + intrusive_ptr hairStyle; + // Initiated in the constructor, no need to snapshot. + std::string kitDiffuseTextureIdentString = "kit_template.png"; + + Match *match; + PlayerBase *player; + // Shared between all players, no need to snapshot. + boost::shared_ptr anims; + // Pointers from elements in humanoidNode to Nodes. + NodeMap nodeMap; + // Seems to contain current animation context. + AnimApplyBuffer animApplyBuffer; + + BiasedOffsets offsets; + + Anim currentAnim; + int previousAnim_frameNum; + e_FunctionType previousAnim_functionType = e_FunctionType_None; + + // position/rotation offsets at the start of currentAnim + Vector3 startPos; + radian startAngle; + + // position/rotation offsets at the end of currentAnim + Vector3 nextStartPos; + radian nextStartAngle; + + // realtime info + SpatialState spatialState; + + Vector3 previousPosition2D; + + e_InterruptAnim interruptAnim; + int reQueueDelayFrames = 0; + int tripType = 0; + Vector3 tripDirection; + + Vector3 decayingPositionOffset; + float decayingDifficultyFactor = 0.0f; + + // for comparing dataset entries (needed by std::list::sort) + mutable e_Foot predicate_DesiredFoot; + mutable e_Velocity predicate_IncomingVelocity; + mutable Vector3 predicate_RelDesiredDirection; + mutable Vector3 predicate_DesiredDirection; + mutable float predicate_CorneringBias = 0.0f; + mutable e_Velocity predicate_DesiredVelocity; + mutable Vector3 predicate_RelIncomingBodyDirection; + mutable Vector3 predicate_LookAt; + mutable Vector3 predicate_RelDesiredTripDirection; + mutable Vector3 predicate_RelDesiredBallDirection; + mutable float predicate_idle = 0.0f; + + // Should be dynamically retrieved from match, don't cache. + int mentalImageTime = 0; + + const float zMultiplier; + MovementHistory movementHistory; + bool mirrored = false; +}; + +struct ForceSpot { + Vector3 origin; + e_MagnetType magnetType; + e_DecayType decayType; + float exp = 1.0f; + float power = 0.0f; + float scale = 0.0f; // scaled #meters until effect is almost decimated +}; + +class RefereeController : public IController { + + public: + RefereeController(Match *match); + virtual ~RefereeController(); + + PlayerOfficial *CastPlayer(); + + void GetForceField(std::vector &forceField); + + virtual void RequestCommand(PlayerCommandQueue &commandQueue); + virtual void Process(); + virtual void ProcessState(EnvState* state) { DO_VALIDATION; + } + virtual Vector3 GetDirection(); + virtual float GetFloatVelocity(); + + virtual int GetReactionTime_ms(); + + virtual void Reset(); +}; + +class PlayerOfficial : public PlayerBase { + + public: + PlayerOfficial(e_OfficialType officialType, Match *match, PlayerData *playerData); + virtual ~PlayerOfficial(); + + HumanoidBase *CastHumanoid(); + RefereeController *CastController(); + + e_OfficialType GetOfficialType() { DO_VALIDATION; return officialType; } + + virtual void Activate(intrusive_ptr humanoidSourceNode, intrusive_ptr fullbodySourceNode, std::map &colorCoords, intrusive_ptr < Resource > kit, boost::shared_ptr animCollection, bool lazyPlayer); + virtual void Deactivate(); + + virtual void Process(); + virtual void FetchPutBuffers(); + + protected: + e_OfficialType officialType; + +}; + +class Officials { + + public: + Officials(Match *match, intrusive_ptr fullbodySourceNode, std::map &colorCoords, intrusive_ptr < Resource > kit, boost::shared_ptr animCollection); + ~Officials(); + void Mirror(); + + void GetPlayers(std::vector &players); + PlayerOfficial *GetReferee() { DO_VALIDATION; return referee; } + + void Process(); + void FetchPutBuffers(); + void Put(bool mirror); + + intrusive_ptr GetYellowCardGeom() { DO_VALIDATION; return yellowCard; } + intrusive_ptr GetRedCardGeom() { DO_VALIDATION; return redCard; } + void ProcessState(EnvState* state); + + protected: + Match *match; + + PlayerOfficial *referee; + PlayerOfficial *linesmen[2]; + PlayerData *playerData; + + intrusive_ptr yellowCard; + intrusive_ptr redCard; + +}; + +struct SharedInfo { + Position ball_position; + Position ball_direction; + Position ball_rotation; + std::vector left_team; + std::vector right_team; + std::vector left_controllers; + std::vector right_controllers; + int left_goals, right_goals; + e_GameMode game_mode; + bool is_in_play = false; + int ball_owned_team = 0; + int ball_owned_player = 0; + int step = 0; +}; + +class Gui2Caption : public Gui2View { + + public: + Gui2Caption(Gui2WindowManager *windowManager, const std::string &name, float x_percent, float y_percent, float width_percent, float height_percent, const std::string &caption); + virtual ~Gui2Caption(); + + virtual void GetImages(std::vector < intrusive_ptr > &target); + + void SetColor(const Vector3 &color); + void SetOutlineColor(const Vector3 &outlineColor); + void SetTransparency(float trans); + + virtual void Redraw(); + + void SetCaption(const std::string &newCaption); + + float GetTextWidthPercent() { DO_VALIDATION; return textWidth_percent; } + + protected: + intrusive_ptr image; + + std::string caption; + Vector3 color; + Vector3 outlineColor; + float transparency = 0.0f; + float textWidth_percent = 0.0f; + int renderedTextHeightPix = 0; + + }; + +class Gui2ScoreBoard : public Gui2View { + + public: + Gui2ScoreBoard(Gui2WindowManager *windowManager, Match *match); + virtual ~Gui2ScoreBoard(); + + void GetImages(std::vector < intrusive_ptr > &target); + + virtual void Redraw(); + + void SetTimeStr(const std::string &timeStr); + void SetGoalCount(int teamID, int goalCount); + + protected: + intrusive_ptr image; + Gui2Caption *timeCaption; + Gui2Caption *teamNameCaption[2]; + Gui2Caption *goalCountCaption[2]; + Gui2Image *leagueLogo; + Gui2Image *teamLogo[2]; +}; + +class Gui2Radar : public Gui2View { + + public: + Gui2Radar(Gui2WindowManager *windowManager, const std::string &name, float x_percent, float y_percent, float width_percent, float height_percent, Match *match, const Vector3 &color1_1, const Vector3 &color1_2, const Vector3 &color2_1, const Vector3 &color2_2); + virtual ~Gui2Radar(); + + void ReloadAvatars(int teamID, unsigned int playerCount); + + virtual void Process(); + void Put(); + + protected: + Gui2Image *bg; + std::vector team1avatars; + std::vector team2avatars; + Gui2Image* ball; + + Match *match; + + Vector3 color1_1, color1_2, color2_1, color2_2; + + }; + +template class ValueHistory { + + public: + ValueHistory(unsigned int maxTime_ms = 10000) : maxTime_ms(maxTime_ms) { DO_VALIDATION;} + virtual ~ValueHistory() { DO_VALIDATION;} + + void Insert(const T &value) { DO_VALIDATION; + values.push_back(value); + if (values.size() > maxTime_ms / 10) values.pop_front(); + } + + T GetAverage(unsigned int time_ms) const { + T total = 0; + unsigned int count = 0; + if (!values.empty()) { DO_VALIDATION; + typename std::list::const_iterator iter = values.end(); + iter--; + while (count <= time_ms / 10) { DO_VALIDATION; + total += (*iter); + count++; + if (iter == values.begin()) break; else iter--; + } + } + if (count > 0) total /= (float)count; + return total; + } + + void Clear() { DO_VALIDATION; + values.clear(); + } + void ProcessState(EnvState *state) { DO_VALIDATION; + state->process(maxTime_ms); + state->process(values); + } + + protected: + unsigned int maxTime_ms = 0; + std::list values; + + }; + +struct PlayerBounce { + Player *opp; + float force = 0.0f; +}; + +class Match { + + public: + Match(MatchData *matchData, const std::vector &controllers, bool init_animation); + virtual ~Match(); + + void Exit(); + void Mirror(bool team_0, bool team_1, bool ball); + + void SetRandomSunParams(); + void RandomizeAdboards(intrusive_ptr stadiumNode); + void UpdateControllerSetup(); + void SpamMessage(const std::string &msg, int time_ms = 3000); + int GetScore(int teamID) { DO_VALIDATION; return matchData->GetGoalCount(teamID); } + Ball *GetBall() { DO_VALIDATION; return ball; } + Team *GetTeam(int teamID) { DO_VALIDATION; return teams[teamID]; } + void GetActiveTeamPlayers(int teamID, std::vector &players); + void GetOfficialPlayers(std::vector &players); + boost::shared_ptr GetAnimCollection(); + + MentalImage* GetMentalImage(int history_ms); + void UpdateLatestMentalImageBallPredictions(); + + void ResetSituation(const Vector3 &focusPos); + + void SetMatchPhase(e_MatchPhase newMatchPhase); + e_MatchPhase GetMatchPhase() const { return matchPhase; } + + void StartPlay() { DO_VALIDATION; inPlay = true; } + void StopPlay() { DO_VALIDATION; inPlay = false; } + bool IsInPlay() const { return inPlay; } + + void StartSetPiece() { DO_VALIDATION; inSetPiece = true; } + void StopSetPiece() { DO_VALIDATION; inSetPiece = false; } + bool IsInSetPiece() const { return inSetPiece; } + Referee *GetReferee() { DO_VALIDATION; return referee; } + Officials *GetOfficials() { DO_VALIDATION; return officials; } + + void SetGoalScored(bool onOff) { DO_VALIDATION; if (onOff == false) ballIsInGoal = false; goalScored = onOff; } + bool IsGoalScored() const { return goalScored; } + Team* GetLastGoalTeam() const { return lastGoalTeam; } + void SetLastTouchTeamID(int id, e_TouchType touchType = e_TouchType_Intentional_Kicked) { DO_VALIDATION; lastTouchTeamIDs[touchType] = id; lastTouchTeamID = id; referee->BallTouched(); } + int GetLastTouchTeamID(e_TouchType touchType) const { return lastTouchTeamIDs[touchType]; } + int GetLastTouchTeamID() const { return lastTouchTeamID; } + Team *GetLastTouchTeam() { DO_VALIDATION; + if (lastTouchTeamID != -1) + return teams[lastTouchTeamID]; + else + return teams[first_team]; + } + Player *GetLastTouchPlayer() { DO_VALIDATION; + if (GetLastTouchTeam()) + return GetLastTouchTeam()->GetLastTouchPlayer(); + else + return 0; + } + float GetLastTouchBias(int decay_ms, unsigned long time_ms = 0) { DO_VALIDATION; if (GetLastTouchTeam()) return GetLastTouchTeam()->GetLastTouchBias(decay_ms, time_ms); else return 0; } + bool IsBallInGoal() const { return ballIsInGoal; } + + Team* GetBestPossessionTeam(); + + Player *GetDesignatedPossessionPlayer() { DO_VALIDATION; return designatedPossessionPlayer; } + Player *GetBallRetainer() { DO_VALIDATION; return ballRetainer; } + void SetBallRetainer(Player *retainer) { DO_VALIDATION; + ballRetainer = retainer; + } + + float GetAveragePossessionSide(int time_ms) const { return possessionSideHistory.GetAverage(time_ms); } + + unsigned long GetMatchTime_ms() const { return matchTime_ms; } + unsigned long GetActualTime_ms() const { return actualTime_ms; } + void BumpActualTime_ms(unsigned long time); + void UpdateIngameCamera(); + + + intrusive_ptr GetCamera() { DO_VALIDATION; return camera; } + void GetTeamState(SharedInfo *state, std::map& controller_mapping, int team_id); + void GetState(SharedInfo* state); + void ProcessState(EnvState* state); + bool Process(); + void UpdateCamera(); + void PreparePutBuffers(); + void FetchPutBuffers(); + void Put(); + + intrusive_ptr GetDynamicNode(); + + void FollowCamera(Quaternion &orientation, Quaternion &nodeOrientation, Vector3 &position, float &FOV, const Vector3 &targetPosition, float zoom); + + void SetAutoUpdateIngameCamera(bool autoUpdate = true) { DO_VALIDATION; if (autoUpdate != autoUpdateIngameCamera) { DO_VALIDATION; camPos.clear(); autoUpdateIngameCamera = autoUpdate; } } + + int GetReplaySize_ms(); + + MatchData* GetMatchData() { DO_VALIDATION; return matchData; } + + float GetMatchDurationFactor() const { return matchDurationFactor; } + bool GetUseMagnet() const { return _useMagnet; } + + const std::vector &GetAnimPositionCache(Animation *anim) const; + + void UploadGoalNetting(); + + int FirstTeam() { DO_VALIDATION; return first_team; } + int SecondTeam() { DO_VALIDATION; return second_team; } + bool isBallMirrored() { DO_VALIDATION; return ball_mirrored; } + + private: + bool CheckForGoal(signed int side, const Vector3& previousBallPos); + + void CalculateBestPossessionTeamID(); + void CheckHumanoidCollisions(); + void CheckHumanoidCollision(Player *p1, Player *p2, std::vector &p1Bounce, std::vector &p2Bounce); + void CheckBallCollisions(); + + void PrepareGoalNetting(); + void UpdateGoalNetting(bool ballTouchesNet = false); + + MatchData *matchData; + Team *teams[2]; + int first_team = 0; + int second_team = 1; + bool ball_mirrored = false; + + Officials *officials; + + intrusive_ptr dynamicNode; + + intrusive_ptr cameraNode; + intrusive_ptr camera; + intrusive_ptr sunNode; + + intrusive_ptr stadiumNode; + + const std::vector &controllers; + + Ball *ball = nullptr; + + std::vector mentalImages; // [index] == index * 10 ms ago ([0] == now) + + Gui2ScoreBoard *scoreboard; + Gui2Radar *radar; + Gui2Caption *messageCaption; + unsigned long messageCaptionRemoveTime_ms = 0; + unsigned long matchTime_ms = 0; + unsigned long actualTime_ms = 0; + unsigned long goalScoredTimer = 0; + + e_MatchPhase matchPhase = e_MatchPhase_PreMatch; // 0 - first half; 1 - second half; 2 - 1st extra time; 3 - 2nd extra time; 4 - penalties + bool inPlay = false; + bool inSetPiece = false; // Whether game is in special mode (corner etc...) + bool goalScored = false; // true after goal scored, false again after next match state change + bool ballIsInGoal = false; + Team* lastGoalTeam = 0; + Player *lastGoalScorer; + int lastTouchTeamIDs[e_TouchType_SIZE]; + int lastTouchTeamID = 0; + Team* bestPossessionTeam = 0; + Player *designatedPossessionPlayer; + Player *ballRetainer; + + ValueHistory possessionSideHistory; + + bool autoUpdateIngameCamera = false; + + // camera + Quaternion cameraOrientation; + Quaternion cameraNodeOrientation; + Vector3 cameraNodePosition; + float cameraFOV = 0.0f; + float cameraNearCap = 0.0f; + float cameraFarCap = 0.0f; + + unsigned int lastBodyBallCollisionTime_ms = 0; + + std::deque camPos; + + Referee *referee; + + boost::shared_ptr menuTask; + + boost::shared_ptr scene3D; + + bool resetNetting = false; + bool nettingHasChanged = false; + + const float matchDurationFactor = 0.0f; + + std::vector nettingMeshesSrc[2]; + std::vector nettingMeshes[2]; + // Whether to use magnet logic (that automatically pushes active player + // towards the ball). + const bool _useMagnet; +}; + +class PlayerBase { + + public: + PlayerBase(Match *match, PlayerData *playerData); + virtual ~PlayerBase(); + void Mirror(); + + inline int GetStableID() const { return stable_id; } + inline const PlayerData* GetPlayerData() { DO_VALIDATION; return playerData; } + + inline bool IsActive() { DO_VALIDATION; return isActive; } + + // get ready for some action + virtual void Activate(intrusive_ptr humanoidSourceNode, intrusive_ptr fullbodySourceNode, std::map &colorCoords, intrusive_ptr < Resource > kit, boost::shared_ptr animCollection, bool lazyPlayer) = 0; + // go back to bench/take a shower + virtual void Deactivate(); + + void ResetPosition(const Vector3 &newPos, const Vector3 &focusPos) { DO_VALIDATION; humanoid->ResetPosition(newPos, focusPos); } + void OffsetPosition(const Vector3 &offset) { DO_VALIDATION; humanoid->OffsetPosition(offset); } + + inline int GetFrameNum() { DO_VALIDATION; return humanoid->GetFrameNum(); } + inline int GetFrameCount() { DO_VALIDATION; return humanoid->GetFrameCount(); } + + inline Vector3 GetPosition() const { return humanoid->GetPosition(); } + inline Vector3 GetGeomPosition() const { return humanoid->GetGeomPosition(); } + inline Vector3 GetDirectionVec() const { return humanoid->GetDirectionVec(); } + inline Vector3 GetBodyDirectionVec() const { return humanoid->GetBodyDirectionVec(); } + inline Vector3 GetMovement() const { return humanoid->GetMovement(); } + inline radian GetRelBodyAngle() const { + return humanoid->GetRelBodyAngle(); + } + inline e_Velocity GetEnumVelocity() const { return humanoid->GetEnumVelocity(); } + inline float GetFloatVelocity() const { return EnumToFloatVelocity(humanoid->GetEnumVelocity()); } + inline e_FunctionType GetCurrentFunctionType() const { return humanoid->GetCurrentFunctionType(); } + inline e_FunctionType GetPreviousFunctionType() const { return humanoid->GetPreviousFunctionType(); } + + void TripMe(const Vector3 &tripVector, int tripType) { DO_VALIDATION; humanoid->TripMe(tripVector, tripType); } + + void RequestCommand(PlayerCommandQueue &commandQueue); + IController *GetController(); + void SetExternalController(HumanGamer *externalController); + HumanController *ExternalController(); + bool ExternalControllerActive(); + + intrusive_ptr GetHumanoidNode() { DO_VALIDATION; return humanoid->GetHumanoidNode(); } + intrusive_ptr GetFullbodyNode() { DO_VALIDATION; return humanoid->GetFullbodyNode(); } + + float GetDecayingPositionOffsetLength() { DO_VALIDATION; return humanoid->GetDecayingPositionOffsetLength(); } + + virtual void Process(); + virtual void PreparePutBuffers(); + virtual void FetchPutBuffers(); + void Put(bool mirror); + + void UpdateFullbodyModel() { DO_VALIDATION; humanoid->UpdateFullbodyModel(); } + + virtual float GetStat(PlayerStat name) const; + float GetVelocityMultiplier() const; + float GetMaxVelocity() const; + + const Anim *GetCurrentAnim() { DO_VALIDATION; return humanoid->GetCurrentAnim(); } + + void SetLastTouchTime_ms(unsigned long touchTime_ms) { DO_VALIDATION; this->lastTouchTime_ms = touchTime_ms; } + unsigned long GetLastTouchTime_ms() { DO_VALIDATION; return lastTouchTime_ms; } + void SetLastTouchType(e_TouchType touchType) { DO_VALIDATION; this->lastTouchType = touchType; } + e_TouchType GetLastTouchType() { DO_VALIDATION; return lastTouchType; } + float GetLastTouchBias(int decay_ms, unsigned long time_ms = 0); + + const NodeMap &GetNodeMap() { DO_VALIDATION; return humanoid->GetNodeMap(); } + + float GetFatigueFactorInv() const { return fatigueFactorInv; } + void RelaxFatigue(float howMuch) { DO_VALIDATION; + fatigueFactorInv += howMuch; + fatigueFactorInv = clamp(fatigueFactorInv, 0.01f, 1.0f); + } + + virtual void ResetSituation(const Vector3 &focusPos); + + void ProcessStateBase(EnvState* state); + + protected: + Match *match; + + const PlayerData* const playerData; + const int stable_id = 0; + + std::unique_ptr humanoid; + std::unique_ptr controller; + HumanGamer *externalController = 0; + + bool isActive = false; + + unsigned long lastTouchTime_ms = 0; + e_TouchType lastTouchType; + + float fatigueFactorInv = 0.0f; + + std::vector positionHistoryPerSecond; // resets too (on ResetSituation() calls) + +}; + +class Humanoid : public HumanoidBase { + + public: + Humanoid(Player *player, intrusive_ptr humanoidSourceNode, intrusive_ptr fullbodySourceNode, std::map &colorCoords, boost::shared_ptr animCollection, intrusive_ptr fullbodyTargetNode, intrusive_ptr < Resource > kit); + virtual ~Humanoid(); + + Player *CastPlayer() const; + + virtual void Process(); + + virtual void CalculateGeomOffsets(); + + bool TouchPending() { DO_VALIDATION; return (currentAnim.frameNum < currentAnim.touchFrame) ? true : false; } + bool TouchAnim() { DO_VALIDATION; return (currentAnim.touchFrame != -1) ? true : false; } + Vector3 GetTouchPos() { DO_VALIDATION; return currentAnim.touchPos; } + int GetTouchFrame() { DO_VALIDATION; return currentAnim.touchFrame; } + int GetCurrentFrame() { DO_VALIDATION; return currentAnim.frameNum; } + + void SelectRetainAnim(); + + virtual void ResetSituation(const Vector3 &focusPos); + + protected: + virtual bool SelectAnim(const PlayerCommand &command, e_InterruptAnim localInterruptAnim, bool preferPassAndShot = false); // returns false on no applicable anim found + bool NeedTouch(int animID, const PlayerCommand &command); + float GetBodyBallDistanceAdvantage( + const Animation *anim, e_FunctionType functionType, + const Vector3 &animTouchMovement, const Vector3 &touchMovement, + const Vector3 &incomingMovement, const Vector3 &outgoingMovement, + radian outgoingAngle, + /*const Vector3 &animBallToBall2D, */ const Vector3 &bodyPos, + const Vector3 &FFO, const Vector3 &animBallPos2D, + const Vector3 &actualBallPos2D, const Vector3 &ballMovement2D, + float radiusFactor, float radiusCheatDistance, float decayPow, + bool debug = false) const; + signed int GetBestCheatableAnimID(const DataSet &sortedDataSet, bool useDesiredMovement, const Vector3 &desiredDirection, float desiredVelocityFloat, bool useDesiredBodyDirection, const Vector3 &desiredBodyDirectionRel, std::vector &positions_ret, int &animTouchFrame_ret, float &radiusOffset_ret, Vector3 &touchPos_ret, Vector3 &fullActionSmuggle_ret, Vector3 &actionSmuggle_ret, radian &rotationSmuggle_ret, e_InterruptAnim localInterruptAnim, bool preferPassAndShot = false) const; + Vector3 CalculateMovementSmuggle(const Vector3 &desiredDirection, float desiredVelocityFloat); + Vector3 GetBestPossibleTouch(const Vector3 &desiredTouch, e_FunctionType functionType); + + Team *team; +}; + +class DefaultDefenseStrategy { + public: + void RequestInput(ElizaController *controller, const MentalImage *mentalImage, Vector3 &direction, float &velocity); +}; + +class DefaultMidfieldStrategy { + + public: + void RequestInput(ElizaController *controller, const MentalImage *mentalImage, Vector3 &direction, float &velocity); +}; + +class DefaultOffenseStrategy { + + public: + void RequestInput(ElizaController *controller, const MentalImage *mentalImage, Vector3 &direction, float &velocity); + + protected: + +}; + +class GoalieDefaultStrategy { + public: + void RequestInput(ElizaController *controller, const MentalImage *mentalImage, Vector3 &direction, float &velocity); + void CalculateIfBallIsBoundForGoal(ElizaController *controller, const MentalImage *mentalImage); + bool IsBallBoundForGoal() const { return ballBoundForGoal; } + void ProcessState(EnvState* state); + + protected: + bool ballBoundForGoal = false; + float ballBoundForGoal_ycoord = 0.0f; +}; + +class ElizaController : public PlayerController { + + public: + ElizaController(Match *match, bool lazyPlayer); + virtual ~ElizaController(); + + virtual void RequestCommand(PlayerCommandQueue &commandQueue); + virtual void Process(); + virtual Vector3 GetDirection(); + virtual float GetFloatVelocity(); + + float GetLazyVelocity(float desiredVelocityFloat); + Vector3 GetSupportPosition_ForceField(const MentalImage *mentalImage, + const Vector3 &basePosition, + bool makeRun = false); + + virtual void Reset(); + virtual void ProcessState(EnvState* state); + + protected: + void GetOnTheBallCommands(std::vector &commandQueue, Vector3 &rawInputDirection, float &rawInputVelocity); + + void _AddPass(std::vector &commandQueue, Player *target, e_FunctionType passType); + void _AddPanicPass(std::vector &commandQueue); + float _GetPassingOdds(Player *targetPlayer, e_FunctionType passType, const std::vector &opponentPlayerImages, float ballVelocityMultiplier = 1.0f); + float _GetPassingOdds(const Vector3 &target, e_FunctionType passType, const std::vector &opponentPlayerImages, float ballVelocityMultiplier = 1.0f); + void _AddCelebration(std::vector &commandQueue); + + DefaultDefenseStrategy defenseStrategy; + DefaultMidfieldStrategy midfieldStrategy; + DefaultOffenseStrategy offenseStrategy; + GoalieDefaultStrategy goalieStrategy; + + Vector3 lastDesiredDirection; + float lastDesiredVelocity = 0.0f; + const bool lazyPlayer = false; +}; + +struct TacticalPlayerSituation { + float forwardSpaceRating = 0.0f; + float toGoalSpaceRating = 0.0f; + float spaceRating = 0.0f; + float forwardRating = 0.0f; + void ProcessState(EnvState* state) { DO_VALIDATION; + state->process(forwardSpaceRating); + state->process(toGoalSpaceRating); + state->process(spaceRating); + state->process(forwardRating); + } +}; + +class Player : public PlayerBase { + + public: + Player(Team *team, PlayerData *playerData); + virtual ~Player(); + + Humanoid *CastHumanoid(); + ElizaController *CastController(); + + int GetTeamID() const; + Team *GetTeam(); + Vector3 GetPitchPosition(); + + // get ready for some action + virtual void Activate(intrusive_ptr humanoidSourceNode, intrusive_ptr fullbodySourceNode, std::map &colorCoords, intrusive_ptr < Resource > kit, boost::shared_ptr animCollection, bool lazyPlayer); + // go back to bench/take a shower + virtual void Deactivate(); + + bool TouchPending() { DO_VALIDATION; return CastHumanoid()->TouchPending(); } + bool TouchAnim() { DO_VALIDATION; return CastHumanoid()->TouchAnim(); } + Vector3 GetTouchPos() { DO_VALIDATION; return CastHumanoid()->GetTouchPos(); } + int GetTouchFrame() { DO_VALIDATION; return CastHumanoid()->GetTouchFrame(); } + int GetCurrentFrame() { DO_VALIDATION; return CastHumanoid()->GetCurrentFrame(); } + + void SelectRetainAnim() { DO_VALIDATION; CastHumanoid()->SelectRetainAnim(); } + + inline e_FunctionType GetCurrentFunctionType() { DO_VALIDATION; return CastHumanoid()->GetCurrentFunctionType(); } + FormationEntry GetFormationEntry(); + inline void SetDynamicFormationEntry(FormationEntry entry) { DO_VALIDATION; dynamicFormationEntry = entry; } + inline FormationEntry GetDynamicFormationEntry() { DO_VALIDATION; return dynamicFormationEntry; } + inline void SetManMarking(Player* player) { DO_VALIDATION; manMarking = player; } + inline Player* GetManMarking() { DO_VALIDATION; return manMarking; } + + bool HasPossession() const; + bool HasBestPossession() const; + bool HasUniquePossession() const; + inline int GetPossessionDuration_ms() const { return possessionDuration_ms; } + inline int GetTimeNeededToGetToBall_ms() const { return timeNeededToGetToBall_ms; } + inline int GetTimeNeededToGetToBall_optimistic_ms() const { return timeNeededToGetToBall_optimistic_ms; } + inline int GetTimeNeededToGetToBall_previous_ms() const { return timeNeededToGetToBall_previous_ms; } + void SetDesiredTimeToBall_ms(int ms) { DO_VALIDATION; desiredTimeToBall_ms = ms; } + int GetDesiredTimeToBall_ms() const { return clamp(desiredTimeToBall_ms, timeNeededToGetToBall_ms, 1000000.0f); } + bool AllowLastDitch(bool includingPossessionAmount = true) const; + + void TriggerControlledBallCollision() { DO_VALIDATION; triggerControlledBallCollision = true; } + bool IsControlledBallCollisionTriggered() { DO_VALIDATION; return triggerControlledBallCollision; } + void ResetControlledBallCollisionTrigger() { DO_VALIDATION; triggerControlledBallCollision = false; } + + float GetAverageVelocity(float timePeriod_sec); // is reset on ResetSituation() calls + + void UpdatePossessionStats(); + + float GetClosestOpponentDistance() const; + + const TacticalPlayerSituation &GetTacticalSituation() { DO_VALIDATION; return tacticalSituation; } + + virtual void Process(); + virtual void PreparePutBuffers(); + virtual void FetchPutBuffers(); + void Put2D(bool mirror); + void Hide2D(); + + void GiveYellowCard(unsigned long giveTime_ms) { DO_VALIDATION; cards++; cardEffectiveTime_ms = giveTime_ms; } + void GiveRedCard(unsigned long giveTime_ms) { DO_VALIDATION; + cards += 3; + cardEffectiveTime_ms = giveTime_ms; + } + + bool HasCards() { DO_VALIDATION; + return cards > 0; + } + + void SendOff(); + + float GetStaminaStat() const; + virtual float GetStat(PlayerStat name) const; + + virtual void ResetSituation(const Vector3 &focusPos); + + void ProcessState(EnvState* state); + protected: + void _CalculateTacticalSituation(); + + Team *team = nullptr; + + Player* manMarking = 0; + + FormationEntry dynamicFormationEntry; + + bool hasPossession = false; + bool hasBestPossession = false; + bool hasUniquePossession = false; + int possessionDuration_ms = 0; + unsigned int timeNeededToGetToBall_ms = 1000; + unsigned int timeNeededToGetToBall_optimistic_ms = 1000; + unsigned int timeNeededToGetToBall_previous_ms = 1000; + + bool triggerControlledBallCollision = false; + + TacticalPlayerSituation tacticalSituation; + + bool buf_nameCaptionShowCondition = false; + Vector3 buf_playerColor; + + Gui2Caption *nameCaption = nullptr; + + int desiredTimeToBall_ms = 0; + int cards = 0; // 1 == 1 yellow; 2 == 2 yellow; 3 == 1 red; 4 == 1 yellow, 1 red + + unsigned long cardEffectiveTime_ms = 0; + +}; + +class GameTask { + + public: + GameTask(); + ~GameTask(); + + void StartMatch(bool init_animation); + bool StopMatch(); + + void ProcessPhase(); + void PrepareRender(); + + Match *GetMatch() { DO_VALIDATION; return match.get(); } + + protected: + std::unique_ptr match; + boost::shared_ptr scene3D; +}; + +class GameContext { + public: + GameContext() : rng(BaseGenerator(), Distribution()), rng_non_deterministic(BaseGenerator(), Distribution()) { } + GraphicsSystem graphicsSystem; + boost::shared_ptr gameTask; + boost::shared_ptr menuTask; + boost::shared_ptr scene2D; + boost::shared_ptr scene3D; + intrusive_ptr fullbodyNode; + intrusive_ptr goalsNode; + intrusive_ptr stadiumRender; + intrusive_ptr stadiumNoRender; + Properties *config = nullptr; + std::string font; + TTF_Font *defaultFont = nullptr; + TTF_Font *defaultOutlineFont = nullptr; + + std::vector controllers; + ObjectFactory object_factory; + ResourceManager geometry_manager; + ResourceManager surface_manager; + ResourceManager texture_manager; + ResourceManager vertices_manager; + ASELoader aseLoader; + ImageLoader imageLoader; + + typedef boost::mt19937 BaseGenerator; + typedef boost::uniform_real Distribution; + typedef boost::variate_generator Generator; + Generator rng; + + // Two random number generators are needed. One (deterministic when running + // in deterministic mode) to be used in places which generate deterministic + // game state. Second one is used in places which are optional and don't + // affect observations (like position of the sun). + Generator rng_non_deterministic; + bool already_loaded = false; + int playerCount = 0; + int stablePlayerCount = 0; + BiasedOffsets emptyOffsets; + boost::shared_ptr anims; + std::map> animPositionCache; + std::map colorCoords; + int step = 0; + int tracker_disabled = 1; + long tracker_pos = 0; + void ProcessState(EnvState* state); +}; + +class EnvState { + public: + EnvState(GameEnv* game_env, const std::string& state, const std::string reference = ""); + const ScenarioConfig* getConfig() { return scenario_config; } + const GameContext* getContext() { return context; } + void process(std::string &value); + void process(Animation* &value); + template void process(std::vector& collection) { + int size = collection.size(); + process(size); + collection.resize(size); + for (auto& el : collection) { + process(el); + } + } + template void process(std::list& collection) { + int size = collection.size(); + process(size); + collection.resize(size); + for (auto& el : collection) { + process(el); + } + } + void process(Player*& value); + void process(HumanGamer*& value); + void process(AIControlledKeyboard*& value); + void process(Team*& value); + bool isFailure() { + return failure; + } + bool enabled() { + return this->disable_cnt == 0; + } + void setValidate(bool validate) { + this->disable_cnt += validate ? -1 : 1; + } + void setCrash(bool crash) { + this->crash = crash; + } + bool Load() { return load; } + int getpos() { + return pos; + } + bool eos(); + template void process(T& obj) { + if (load) { + if (pos + sizeof(T) > state.size()) { + Log(blunted::e_FatalError, "EnvState", "state", "state is invalid"); + } + memcpy(&obj, &state[pos], sizeof(T)); + pos += sizeof(T); + } else { + state.resize(pos + sizeof(T)); + memcpy(&state[pos], &obj, sizeof(T)); + if (!failure && disable_cnt == 0 && !reference.empty() && (*(T*) &state[pos]) != (*(T*) &reference[pos])) { + failure = true; + std::cout << "Position: " << pos << std::endl; + std::cout << "Type: " << typeid(obj).name() << std::endl; + std::cout << "Value: " << obj << std::endl; + std::cout << "Reference: " << (*(T*) &reference[pos]) << std::endl; + if (crash) { + Log(blunted::e_FatalError, "EnvState", "state", "Reference mismatch"); + } else { + print_stacktrace(); + } + } + pos += sizeof(T); + if (pos > 10000000) { + Log(blunted::e_FatalError, "EnvState", "state", "state is too big"); + } + } + } + void SetPlayers(const std::vector& players); + void SetHumanControllers(const std::vector& controllers); + void SetControllers(const std::vector& controllers); + void SetAnimations(const std::vector& animations); + void SetTeams(Team* team0, Team* team1); + const std::string& GetState(); + protected: + bool failure = false; + bool stack = true; + bool load = false; + char disable_cnt = 0; + bool crash = false; + std::vector players; + std::vector animations; + std::vector teams; + std::vector human_controllers; + std::vector controllers; + std::string state; + std::string reference; + int pos = 0; + ScenarioConfig* scenario_config; + GameContext* context; + private: + void process(void** collection, int size, void*& element); +}; + +struct FormationEntry { + FormationEntry() { DO_VALIDATION;} + // Constructor accepts environment coordinates. + FormationEntry(float x, float y, e_PlayerRole role, bool lazy, + bool controllable) + : position(x, y * FORMATION_Y_SCALE, 0), + start_position(x, y * FORMATION_Y_SCALE, 0), + role(role), + lazy(lazy), + controllable(controllable) { + DO_VALIDATION; + } + bool operator == (const FormationEntry& f) const { + return role == f.role && + lazy == f.lazy && + position == f.position && + controllable == f.controllable; + } + Vector3 position_env() { DO_VALIDATION; + return Vector3(position.coords[0], + position.coords[1] / FORMATION_Y_SCALE, + position.coords[2]); + } + void ProcessState(EnvState* state) { DO_VALIDATION; + state->process(role); + state->process(position); + state->process(start_position); + state->process(lazy); + state->process(controllable); + } + Vector3 position; // adapted to player role (combination of databasePosition and hardcoded role position) + Vector3 start_position; + e_PlayerRole role = e_PlayerRole_GK; + bool lazy = false; // Computer doesn't perform any actions for lazy player. + // Can be controlled by the player? + bool controllable = true; +}; + +struct ScenarioConfig{ +public: + static SHARED_PTR make() { + return SHARED_PTR(new ScenarioConfig()); + } + bool DynamicPlayerSelection() { + ComputeCache(); + return cached_dynamic_player_selection; + } + int ControllableLeftPlayers() { + ComputeCache(); + return cached_controllable_left_players; + } + int ControllableRightPlayers() { + ComputeCache(); + return cached_controllable_right_players; + } + bool LeftTeamOwnsBall() { DO_VALIDATION; + float leftDistance = 1000000; + float rightDistance = 1000000; + for (auto& player : left_team) { DO_VALIDATION; + leftDistance = std::min(leftDistance, + (player.start_position - ball_position).GetLength()); + } + for (auto& player : right_team) { DO_VALIDATION; + rightDistance = std::min(rightDistance, + (player.start_position - ball_position).GetLength()); + } + return leftDistance < rightDistance; + } + void ProcessStateConstant(EnvState* state) { + cache_computed = false; + state->process(ball_position); + int size = left_team.size(); + state->process(size); + left_team.resize(size); + size = right_team.size(); + state->process(size); + right_team.resize(size); + state->process(left_agents); + state->process(right_agents); + state->process(use_magnet); + state->process(offsides); + state->process(left_team_difficulty); + state->process(right_team_difficulty); + state->process(deterministic); + state->process(end_episode_on_score); + state->process(end_episode_on_possession_change); + state->process(end_episode_on_out_of_play); + state->process(game_duration); + state->process(second_half); + state->process(control_all_players); + } + void ProcessState(EnvState* state) { + cache_computed = false; + state->process(real_time); + state->process(game_engine_random_seed); + state->process(reverse_team_processing); + for (auto& p : left_team) { + p.ProcessState(state); + } + for (auto& p : right_team) { + p.ProcessState(state); + } + } + Vector3 ball_position; + std::vector left_team; + std::vector right_team; + int left_agents = 1; + int right_agents = 0; + bool use_magnet = true; + bool offsides = true; + bool real_time = false; + unsigned int game_engine_random_seed = 42; + bool reverse_team_processing = false; + float left_team_difficulty = 1.0; + float right_team_difficulty = 0.6; + bool deterministic = false; + bool end_episode_on_score = false; + bool end_episode_on_possession_change = false; + bool end_episode_on_out_of_play = false; + int game_duration = 3000; + bool control_all_players = false; + int second_half = 999999999; + ScenarioConfig() { } +private: + void ComputeCache() { + if(cache_computed){ + return; + } + cached_controllable_left_players = 0; + cached_controllable_right_players = 0; + for(auto& p : left_team){ + if(p.controllable){ + cached_controllable_left_players++; + } + } + for (auto& p : right_team) { + if (p.controllable) { + cached_controllable_right_players++; + } + } + cached_dynamic_player_selection = + !((cached_controllable_left_players == left_agents || left_agents == 0) && + (cached_controllable_right_players == right_agents || right_agents == 0)); + cache_computed = true; + } + int cached_controllable_left_players = -1; + int cached_controllable_right_players = -1; + bool cached_dynamic_player_selection = false; + bool cache_computed = false; +}; + +class GameConfig { + public: + static SHARED_PTR make() { + return SHARED_PTR(new GameConfig()); + } + // Is rendering enabled. + bool render = false; + // Directory with textures and other resources. + std::string data_dir; + // How many physics animation steps are done per single environment step. + int physics_steps_per_frame = 10; + int render_resolution_x = 1280; + int render_resolution_y = 720; + std::string updatePath(const std::string& path) { +#ifdef WIN32 + boost::filesystem::path boost_path(path); + if (boost_path.is_absolute()) { + return path; + } + boost::filesystem::path data_dir_boost(data_dir); + data_dir_boost /= boost_path; + return data_dir_boost.string(); +#else + if (path[0] == '/') { + return path; + } + return data_dir + '/' + path; +#endif + } + void ProcessState(EnvState* state) { + state->process(data_dir); + state->process(physics_steps_per_frame); + state->process(render_resolution_x); + state->process(render_resolution_y); + } + private: + GameConfig() { } + friend GameEnv; +}; + +enum GameState { + game_created, + game_initiated, + game_running, + game_done +}; + +Tracker* GetTracker(); +GameEnv* GetGame(); +GameContext& GetContext(); +class Tracker { + public: + void setup(long start, long end) { + this->start = start; + this->end = end; + GetContext().tracker_disabled = 0; + GetContext().tracker_pos = 0; + } + void setDisabled(bool disabled) { + GetContext().tracker_disabled += disabled ? 1 : -1; + } + bool enabled() { + return GetContext().tracker_disabled == 0; + } + inline void verify(int line, const char* file) { + if (GetContext().tracker_disabled) return; + GetContext().tracker_pos++; + if (GetContext().tracker_pos < start || GetContext().tracker_pos > end) return; + std::unique_lock lock(mtx); + std::string trace; + if (waiting_game == nullptr) { + if (GetContext().tracker_pos % 10000 == 0) { + std::cout << "Validating: " << GetContext().tracker_pos << std::endl; + } + waiting_stack_trace = trace; + waiting_game = GetGame(); + waiting_line = line; + waiting_file = file; + cv.wait(lock); + return; + } + GetContext().tracker_disabled++; + verify_snapshot(GetContext().tracker_pos, line, file, trace); + GetContext().tracker_disabled--; + waiting_game = nullptr; + cv.notify_one(); + } + private: + void verify_snapshot(long pos, int line, const char* file, const std::string& trace); + // Tweak start and end to verify that line numbers match for + // each call in the verification range (2 bytes / call). + long start = 0LL; + long end = 1000000000LL; + bool verify_stack_trace = true; + std::mutex mtx; + std::condition_variable cv; + GameEnv* waiting_game = nullptr; + int waiting_line; + const char* waiting_file; + std::string waiting_stack_trace; +}; + +struct GameEnv { + GameEnv() {DO_VALIDATION}; + void start_game(); + sharedInfo get_info(); + screenshoot get_frame(); + + bool sticky_action_state(int action, bool left_team, int player); + void action(int action, bool left_team, int player); + void reset(ScenarioConfig& game_config, bool init_animation); + void render(bool swap_buffer = true); + std::string get_state(const std::string& pickle); + std::string set_state(const std::string& state); + void tracker_setup(long start, long end) { GetTracker()->setup(start, end); } + void step(); + void ProcessState(EnvState* state); + ScenarioConfig& config(); +private: + void setConfig(ScenarioConfig& scenario_config); + void do_step(int count); + void getObservations(); + AIControlledKeyboard* keyboard_ = nullptr; + bool disable_graphics_ = false; + int last_step_rendered_frames_ = 1; +public: + ScenarioConfig scenario_config; + GameConfig game_config; + GameContext* context = nullptr; + GameState state = game_created; + int waiting_for_game_count = 0; +}; From 61e50a1f17f0ea378ddbb04e9b769ea60d6639ed Mon Sep 17 00:00:00 2001 From: kfq2002 <95134838+kfq2002@users.noreply.github.com> Date: Wed, 3 Aug 2022 17:36:28 +0800 Subject: [PATCH 04/28] Add files via upload --- envpool/gfootball/BUILD | 52 ++ envpool/gfootball/__init__.py | 29 + envpool/gfootball/config.h | 31 ++ envpool/gfootball/football_action_set.h | 56 ++ envpool/gfootball/football_env.h | 412 ++++++++++++++ envpool/gfootball/football_env_test.cc | 0 envpool/gfootball/football_envpool.cc | 21 + .../football_observation_processor.py | 524 ++++++++++++++++++ envpool/gfootball/registration.py | 9 + 9 files changed, 1134 insertions(+) create mode 100644 envpool/gfootball/BUILD create mode 100644 envpool/gfootball/__init__.py create mode 100644 envpool/gfootball/config.h create mode 100644 envpool/gfootball/football_action_set.h create mode 100644 envpool/gfootball/football_env.h create mode 100644 envpool/gfootball/football_env_test.cc create mode 100644 envpool/gfootball/football_envpool.cc create mode 100644 envpool/gfootball/football_observation_processor.py create mode 100644 envpool/gfootball/registration.py diff --git a/envpool/gfootball/BUILD b/envpool/gfootball/BUILD new file mode 100644 index 00000000..486473b6 --- /dev/null +++ b/envpool/gfootball/BUILD @@ -0,0 +1,52 @@ +load("@pip_requirements//:requirements.bzl", "requirement") +load("@pybind11_bazel//:build_defs.bzl", "pybind_extension") + +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "football_env", + hdrs = ["football_env.h"], + deps = [ + "//envpool/core:async_envpool", + "@gfootball_engine//:game_env", + "config.h", + "football_action_set.h", + ], +) + + +pybind_extension( + name = "football_envpool", + srcs = [ + "football_envpool.cc", + ], + deps = [ + "football_env", + "//envpool/core:py_envpool", + ], +) + +py_library( + name = "football", + srcs = ["__init__.py"], + deps = ["//envpool/python:api"] +) + +py_library( + name = "football_observation_processor", + srcs = ["football_observation_processor.py"], + deps = [ + requirement("numpy"), + requirement("collections"), + requirement("datetime"), + requirement("os"), + requirement("shutil"), + requirement("tempfile"), + requirement("timeit"), + requirement("traceback"), + requirement("absl"), + requirement("gfootball"), + requirement("six"), + ], +) + diff --git a/envpool/gfootball/__init__.py b/envpool/gfootball/__init__.py new file mode 100644 index 00000000..b0d20d64 --- /dev/null +++ b/envpool/gfootball/__init__.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 +# Copyright 2021 Garena Online Private Limited +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Football env in EnvPool.""" + +from envpool.python.api import py_env + +from .football_envpool import _FootballEnvPool, _FootballEnvSpec + +FootballEnvSpec, FootballDMEnvPool, FootballGymEnvPool = py_env( + _FootballEnvSpec, _FootballEnvPool +) + +__all__ = [ + "FootballEnvSpec", + "FootballDMEnvPool", + "FootballGymEnvPool", +] diff --git a/envpool/gfootball/config.h b/envpool/gfootball/config.h new file mode 100644 index 00000000..402a580f --- /dev/null +++ b/envpool/gfootball/config.h @@ -0,0 +1,31 @@ +#include +#include +#include +#include "game_env.hpp" + +class Config{ + public: + std::string action_set = "default"; + std::string custom_display_stats = ""; + bool display_game_stats = true; + bool dump_full_episodes = false; + bool dump_scores = false; + std::vectorplayers = {"agent:left_players=1"}; + std::string level = "11_vs_11_stochastic"; + int physics_steps_per_frame = 10; + float render_resolution_x = 1280; + float render_resolution_y = 0.5625 * render_resolution_x; + bool real_time = false; + std::string tracesdir_pre = getcwd(NULL, 0); + std::string tracesdir = tracesdir_pre + "/dump"; + std::string video_format = "avi"; + int video_quality_level = 0; + bool write_video = false; + int episode_number = 0; + Config(); + void NewScenario(int inc = 1){ + this->episode_number += inc; + ScenarioConfig scenario_config; + }; + +}; \ No newline at end of file diff --git a/envpool/gfootball/football_action_set.h b/envpool/gfootball/football_action_set.h new file mode 100644 index 00000000..b411456f --- /dev/null +++ b/envpool/gfootball/football_action_set.h @@ -0,0 +1,56 @@ +#include +#include "config.h" +#include "game_env.hpp" + +class CoreAction{ + public: + CoreAction(Action action, std::string name, bool sticky = false, bool directional = false){ + this->action_ = action; + this->name_ = name; + this->sticky_ = sticky; + this->directional_ = directional; + } + bool is_in_actionset(Config config){ + }; + Action action_; + std::string name_; + bool sticky_; + bool directional_; +}; + +bool T = true; +bool F = false; + +CoreAction action_idle(Action::game_idle, "idle"); +CoreAction action_builtin_ai(Action::game_builtin_ai, "builtin_ai"); +CoreAction action_left(Action::game_left, "left", T, T); +CoreAction action_top_left(Action::game_top_left, "top_left", T, T); +CoreAction action_top(Action::game_top, "top", T, T); +CoreAction action_top_right(Action::game_top_right, "top_right", T, T); +CoreAction action_right(Action::game_right, "right", T, T); +CoreAction action_bottom_right(Action::game_bottom_right, "bottom_right", T, T); +CoreAction action_bottom(Action::game_bottom, "bottom", T, T); +CoreAction action_bottom_left(Action::game_bottom_left, "bottom_left", T, T); +CoreAction action_long_pass(Action::game_long_pass, "long_pass"); +CoreAction action_high_pass(Action::game_high_pass, "high_pass"); +CoreAction action_short_pass(Action::game_short_pass, "short_pass"); +CoreAction action_shot(Action::game_shot, "shot"); +CoreAction action_keeper_rush(Action::game_keeper_rush, "keeper_rush", T); +CoreAction action_sliding(Action::game_sliding, "sliding"); +CoreAction action_pressure(Action::game_pressure, "pressure", T); +CoreAction action_team_pressure(Action::game_team_pressure, "team_pressure", T); +CoreAction action_switch(Action::game_switch, "switch"); +CoreAction action_sprint(Action::game_sprint, "sprint", T); +CoreAction action_dribble(Action::game_dribble, "dribble", T); +CoreAction action_release_direction(Action::game_release_direction, "release_direction", F, T); +CoreAction action_release_long_pass(Action::game_release_long_pass, "release_long_pass"); +CoreAction action_release_high_pass(Action::game_release_high_pass, "release_high_pass"); +CoreAction action_release_short_pass(Action::game_release_short_pass, "release_short_pass"); +CoreAction action_release_shot(Action::game_release_shot, "release_shot"); +CoreAction action_release_keeper_rush(Action::game_release_keeper_rush, "release_keeper_rush"); +CoreAction action_release_sliding(Action::game_release_sliding, "release_sliding"); +CoreAction action_release_pressure(Action::game_release_pressure, "release_pressure"); +CoreAction action_release_team_pressure(Action::game_release_team_pressure, "release_team_pressure"); +CoreAction action_release_switch(Action::game_release_switch, "release_switch"); +CoreAction action_release_sprint(Action::game_release_sprint, "release_sprint"); +CoreAction action_release_dribble(Action::game_release_dribble, "release_dribble"); \ No newline at end of file diff --git a/envpool/gfootball/football_env.h b/envpool/gfootball/football_env.h new file mode 100644 index 00000000..958c2eb1 --- /dev/null +++ b/envpool/gfootball/football_env.h @@ -0,0 +1,412 @@ +#include +#include +#include "game_env.hpp" +#include "config.h" +#include "football_action_set.h" +#include "envpool/core/async_envpool.h" +#include "envpool/utils/image_process.h" +#include "envpool/core/env.h" + +namespace football{ + +class FootballEnvFns { + public: + std::string tracesdir_pre = getcwd(NULL, 0); + std::string tracesdir = tracesdir_pre + "/dump"; + static decltype(auto) DefaultConfig(){ + return MakeDict( + "action_set"_.Bind(std::string("default")), "custom_display_stats"_.Bind(std::vector{}), "display_game_stats"._Bind(true), + "dump_full_episodes"_.Bind(false), "dump_scores"_.Bind(false), "players"._Bind(std::vector{"agent:left_players=1"}), + "level"_.Bind(std::string("11_vs_11_stochastic")), "physics_steps_per_frame"_.Bind(10), "render_resolution_x"_.Bind(1280), + "render_resolution_y"_.Bind(1280 * 0.5625), "real_time"_.Bind(false), "tracesdir"_.Bind(tracesdir), "video_format"_.Bind(std::string("avi")), + "video_quality_level"_.Bind(0), "write_video"_.Bind(false) + ); + } + template + static decltype(auto) StateSpec(const Config& conf) { + return MakeDict( + "obs"_.Bind(Spec({-1, 72, 96}, {0, 255}), + "info:episode_reward"_.Bind(Spec({})), + "info:score"_.Bind(Spec({2})), + "info:steps"_.Bind(Spec({})), + "info:FPS"_.Bind(Spec({})), + "info:gameFPS"_.Bind(Spec({})) + ) + ); + } + template + static decltype(auto) ActionSpec(const Config& conf) { + return MakeDict( + "action"_.Bind(Spec({-1}, {0, 32})) + ); + } +}; + +using FootballEnvSpec = EnvSpec; + +struct FootballEnvState{ + int previous_score_diff = 0; + int previous_game_mode = -1; + int prev_ball_owned_team = -1; +}; + +class FootballEnv : public Env { + protected: + int previous_score_diff = 0; + int previous_game_mode = -1; + int prev_ball_owned_team = -1; + + public: + std::string action_set_name; + std::string custom_display_stats; + bool display_game_stats; + bool dump_full_episodes; + bool dump_scores; + std::vectorplayers; + std::string level; + bool real_time;; + std::string tracesdir; + std::string video_format; + int video_quality_level; + bool write_video; + int episode_number = 0; + ScenarioConfig scenario_config; + GameContext* context = nullptr; + GameConfig game_config; + GameState state = game_created; + int waiting_for_game_count = 0; + GameEnv env_; + int physics_steps_per_frame; + int render_resolution_x; + int render_resolution_y; + FootballEnvState state; + int steps_time = 0; + int step_count = 0; + int _step = 0; + clock_t episode_start = clock(); + std::vector action_set; + float cumulative_reward = 0; + using Observation = decltype(MakeDict( + "left_team"._Bind(std::vector(22)), "left_team_roles"_.Bind(std::vector(11)), "left_team_direction"._Bind(std::vector(22)), + "left_team_tired_factor"._Bind(std::vector(11)), "left_team_yellow_card"._Bind(std::vector(11)), "left_team_active"._Bind(std::vector{0}), + "left_team_designated_player"._Bind(3), "right_team"._Bind(std::vector(22)), "right_team_roles"._Bind(std::vector(11)), + "right_team_direction"._Bind(std::vector(22)), "right_team_tired_factor"._Bind(std::vector(11)), "right_team_yellow_card"._Bind(std::vector(11)), + "right_team_active"._Bind(std::vector{0}), "right_team_designated_player"._Bind(0), "ball"._Bind(std::vector{0 , 0 , 0}), + "ball_direction"._Bind(std::vector(3)), "ball_rotation"._Bind(std::vector(3)), "ball_owned_team"._Bind(0), + "ball_owned_player"._Bind(7), "left_agent_controlled_player"._Bind(std::vector{4}), "right_agent_controlled_player"._Bind(std::vector{6}), + "game_mode"._Bind(0), "left_agent_sticky_actions"._Bind(std::vector(2)), "right_agent_sticky_actions"._Bind(std::vector(2)), + "score"._Bind(std::vector{3, 5}), "steps_left"._Bind(45) + )); + Observation observation; + + FootballEnv(const Spec& spec, int env_id) : Env(spec, env_id), + env_(GameEnv::GameEnv()), + action_set_name(spec.config["action_set"]), + physics_steps_per_frame(spec.config["physics_steps_per_frame"]), + render_resolution_x(spec.config["render_resolution_x"]), + render_resolution_y(spec.config["render_resolution_y"]), + custom_display_stats(spec.config["custom_display_stats"]), + display_game_stats(spec.config["display_game_stats"]), + dump_full_episodes(spec.config["dump_full_episodes"]), + dump_scores(spec.config["dump_scores"]), + players(spec.config["players"]), + level(spec.config["level"]), + real_time(spec.config["real_time"]), + tracesdir(spec.config["tracesdir"]), + video_format(spec.config["video_format"]), + video_quality_level(spec.config["video_quality_level"]), + write_video(spec.config["write_video"]) + {}; + + + + void Step(std::vectoraction){ + step_count += 1; + int action_index = 0; + std::vector controlled_players; + for(int left_team = 1; left_team > 0; left_team++){ + auto agents = env_.config().left_agents; + for(int j = 0; j < agents; j++){ + auto player_action_index = action[action_index]; + CoreAction player_action = action_idle; + switch (player_action_index) + { + case 0: + player_action = action_idle; + break; + case 1: + player_action = action_left; + break; + case 2: + player_action = action_top_left; + break; + case 3: + player_action = action_top; + break; + case 4: + player_action = action_top_right; + break; + case 5: + player_action = action_right; + break; + case 6: + player_action = action_bottom_right; + break; + case 7: + player_action = action_bottom; + break; + case 8: + player_action = action_bottom_left; + break; + case 9: + player_action = action_long_pass; + break; + case 10: + player_action = action_high_pass; + break; + case 11: + player_action = action_short_pass; + break; + case 12: + player_action = action_shot; + break; + case 13: + player_action = action_keeper_rush; + break; + case 14: + player_action = action_sliding; + break; + case 15: + player_action = action_pressure; + break; + case 16: + player_action = action_team_pressure; + break; + case 17: + player_action = action_switch; + break; + case 18: + player_action = action_sprint; + break; + case 19: + player_action = action_dribble; + break; + case 20: + player_action = action_release_direction; + break; + case 21: + player_action = action_release_long_pass; + break; + case 22: + player_action = action_release_high_pass; + break; + case 23: + player_action = action_release_short_pass; + break; + case 24: + player_action = action_release_shot; + break; + case 25: + player_action = action_release_keeper_rush; + break; + case 26: + player_action = action_release_sliding; + break; + case 27: + player_action = action_release_pressure; + break; + case 28: + player_action = action_release_team_pressure; + break; + case 29: + player_action = action_release_switch; + break; + case 30: + player_action = action_release_sprint; + break; + case 31: + player_action = action_release_dribble; + break; + case 32: + player_action = action_builtin_ai; + break; + default: 0; + break; + } + if(env_.waiting_for_game_count == 20){ + player_action = action_short_pass; + } + else if(env_.waiting_for_game_count > 20){ + player_action = action_idle; + if(left_team == 0){ + controlled_players = observation["left_agent_controlled_player"]; + } + else{ + controlled_players = observation["right_agent_controlled_player"]; + } + if (observation["ball_owned_team"] != -1 && controlled_players[j] == observation["ball_owned_player"] && ~(left_team ^ observation["ball_owned_team"])){ + if(bool(env_.waiting_for_game_count < 30) != bool(left_team)){ + player_action = action_left; + } + else{ + player_action = action_right; + } + } + } + action_index += 1; + env_.action(player_action.action_, bool(left_team), j); + } + } + while(true){ + clock_t enter_time = clock(); + env_.step(); + steps_time += clock() - enter_time; + if (retrieve_observation()){ + break; + } + } + + if(env_.config().end_episode_on_score){ + if(observation["score"][0] > 0 || observation["score"][1] > 0){ + env_.state = GameState::game_done; + } + } + + if(env_.config().end_episode_on_out_of_play && observation["game_mode"] != int(e_GameMode::e_GameMode_Normal) && previous_game_mode == int(e_GameMode::e_GameMode_Normal)){ + env_.state = GameState::game_done; + } + previous_game_mode = observation["game_mode"]; + + if(env_.config().end_episode_on_possession_change && + observation["ball_owned_team"] != -1 && + prev_ball_owned_team != -1 && + observation["ball_owned_team"] != prev_ball_owned_team){ + env_.state = GameState::game_done; + } + if(observation["ball_owned_team"] != -1){ + prev_ball_owned_team = observation["ball_owned_team"]; + } + + int score_diff = observation["score"][0] - observation["score"][1]; + int reward = score_diff - previous_score_diff; + previous_score_diff = score_diff; + if(reward == 1){ + + } + if(observation["game_mode"] != int(e_GameMode::e_GameMode_Normal)){ + env_.waiting_for_game_count += 1; + } + else{ + env_.waiting_for_game_count = 0; + } + if(_step >= env_.config().game_duration){ + env_.state = GameState::game_done; + } + + bool episode_done = env_.state == GameState::game_done; + clock_t end_time = clock(); + cumulative_reward += reward; + if(episode_done){ + float fps = step_count / (end_time - episode_start); + float game_fps = step_count / steps_time; + } + }; + + void setConfig(ScenarioConfig& game_config) { + DO_VALIDATION; + scenario_config.ball_position.coords[0] = scenario_config.ball_position.coords[0] * X_FIELD_SCALE; + scenario_config.ball_position.coords[1] = scenario_config.ball_position.coords[1] * Y_FIELD_SCALE; + std::vector setup = GetMenuTask()->GetControllerSetup(); + CHECK(setup.size() == 2 * MAX_PLAYERS); + int controller = 0; + for (int x = 0; x < scenario_config.left_agents; x++) { + DO_VALIDATION; + setup[controller++].side = -1; + } + while (controller < MAX_PLAYERS) { + DO_VALIDATION; + setup[controller++].side = 0; + } + for (int x = 0; x < scenario_config.right_agents; x++) { + DO_VALIDATION; + setup[controller++].side = 1; + } + while (controller < 2 * MAX_PLAYERS) { + DO_VALIDATION; + setup[controller++].side = 0; + } + this->scenario_config = scenario_config; + GetMenuTask()->SetControllerSetup(setup); + }; + + void reset_game(bool animations, int inc) { + env_.game_config.physics_steps_per_frame = this->physics_steps_per_frame; + env_.game_config.render_resolution_x = this->render_resolution_x; + env_.game_config.render_resolution_y = this->render_resolution_y; + this->config.NewScenario(inc); + if(env_.state == GameState::game_created){ + env_.start_game(); + } + env_.state = GameState::game_running; + auto scenario_config_ = ScenarioConfig::make(); + env_.reset(*scenario_config_, animations); + }; + + void Reset (int inc = 1) { + episode_start = clock(); + action_set = get_action_set(this->config); + cumulative_reward = 0; + step_count = 0; + reset_game(env_.game_config.render, inc); + } + + bool retrieve_observation(){ + auto info = env_.get_info(); + return info.is_in_play; + } + + std::vector get_action_set(Config config){ + std::vector action_set; + if(config.action_set == "default"){ + action_set = {action_idle, action_left, action_top_left, action_top, + action_top_right, action_right, action_bottom_right, + action_bottom, action_bottom_left, action_long_pass, + action_high_pass, action_short_pass, action_shot, + action_sprint, action_release_direction, action_release_sprint, + action_sliding, action_dribble, action_release_dribble}; + } + else if(config.action_set == "v2"){ + action_set = { + action_idle, action_left, action_top_left, action_top, + action_top_right, action_right, action_bottom_right, + action_bottom, action_bottom_left, action_long_pass, + action_high_pass, action_short_pass, action_shot, + action_sprint, action_release_direction, action_release_sprint, + action_sliding, action_dribble, action_release_dribble, action_builtin_ai + }; + } + else if(config.action_set == "full"){ + action_set = { + action_idle, action_left, action_top_left, action_top, + action_top_right, action_right, action_bottom_right, + action_bottom, action_bottom_left, action_long_pass, + action_high_pass, action_short_pass, action_shot, + action_sprint, action_release_direction, action_release_sprint, + action_sliding, action_dribble, action_release_dribble, action_builtin_ai, + action_keeper_rush, action_pressure, + action_team_pressure, action_switch, + action_release_long_pass, action_release_high_pass, + action_release_short_pass, action_release_shot, + action_release_keeper_rush, action_release_sliding, + action_release_pressure, action_release_team_pressure, + action_release_switch, + }; + } + return action_set; + } + +}; + +} + +using FootballEnvPool = AsyncEnvPool; \ No newline at end of file diff --git a/envpool/gfootball/football_env_test.cc b/envpool/gfootball/football_env_test.cc new file mode 100644 index 00000000..e69de29b diff --git a/envpool/gfootball/football_envpool.cc b/envpool/gfootball/football_envpool.cc new file mode 100644 index 00000000..22c7a209 --- /dev/null +++ b/envpool/gfootball/football_envpool.cc @@ -0,0 +1,21 @@ +// Copyright 2021 Garena Online Private Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "envpool/gfootball/football_env.h" +#include "envpool/core/py_envpool.h" + +using FootballEnvSpec = PyEnvSpec; +using FootballEnvPool = PyEnvPool; + +PYBIND11_MODULE(football_envpool, m) { REGISTER(m, FootballEnvSpec, FootballEnvPool) } diff --git a/envpool/gfootball/football_observation_processor.py b/envpool/gfootball/football_observation_processor.py new file mode 100644 index 00000000..3d7625fc --- /dev/null +++ b/envpool/gfootball/football_observation_processor.py @@ -0,0 +1,524 @@ +# coding=utf-8 +# Copyright 2019 Google LLC +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +"""Observation processor, providing multiple support methods for analyzing observations.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import collections +import datetime +import os +import shutil +import tempfile +import timeit +import traceback + +from absl import logging +from gfootball.env import constants as const +from gfootball.env import football_action_set +from gfootball.scenarios import e_PlayerRole_GK +import numpy as np +from six.moves import range +from six.moves import zip +import six.moves.cPickle + +# How many past frames are kept around for the dumps to make use of them. +PAST_STEPS_TRACE_SIZE = 100 + +WRITE_FILES = True + +try: + import cv2 +except ImportError: + import cv2 + + +class DumpConfig(object): + + def __init__(self, + max_count=1, + steps_before=PAST_STEPS_TRACE_SIZE, + steps_after=0, + min_frequency=10): + self._steps_before = steps_before + self._steps_after = steps_after + self._max_count = max_count + # Make sure self._last_dump_time < timeit.default_timer() - min_frequency + # holds upon startup. + self._last_dump_time = timeit.default_timer() - 2 * min_frequency + self._active_dump = None + self._min_frequency = min_frequency + + +class TextWriter(object): + + def __init__(self, frame, x, y=0, field_coords=False, color=(255, 255, 255)): + self._frame = frame + if field_coords: + x = 400 * (x + 1) - 10 + y = 695 * (y + 0.43) + self._pos_x = int(x) + self._pos_y = int(y) + 20 + self._color = color + self._font = cv2.FONT_HERSHEY_SIMPLEX + self._lineType = 2 + self._arrow_types = ('top', 'top_right', 'right', 'bottom_right', 'bottom', + 'bottom_left', 'left', 'top_left') + + def write(self, text, scale_factor=1, color=None): + textPos = (self._pos_x, self._pos_y) + fontScale = 0.8 * scale_factor + cv2.putText(self._frame, text, textPos, self._font, fontScale, color or self._color, + self._lineType) + self._pos_y += int(25 * scale_factor) + + def write_table(self, data, widths, scale_factor=1, offset=0): + # data is a list of rows. Each row is a list of strings. + fontScale = 0.5 * scale_factor + init_x = self._pos_x + for row in data: + assert (len(row) == len(widths)) + self._pos_x += offset + for col, cell in enumerate(row): + color = self._color + if isinstance(cell, tuple): + assert (len(cell) == 2) + (text, color) = cell + else: + assert (isinstance(cell, str)) + text = cell + + if text in self._arrow_types: + self.write_arrow(text, scale_factor=scale_factor) + else: + textPos = (self._pos_x, self._pos_y) + cv2.putText(self._frame, text, textPos, self._font, fontScale, color, + self._lineType) + self._pos_x += widths[col] + self._pos_x = init_x + self._pos_y += int(20 * scale_factor) + self._pos_x = init_x + + def write_arrow(self, arrow_type, scale_factor=1): + assert (arrow_type in self._arrow_types) + thickness = 1 + arrow_offsets = { + 'top': (12, 0, 12, -16), + 'top_right': (4, -4, 16, -16), + 'right': (0, -10, 20, -10), + 'bottom_right': (4, -16, 16, -4), + 'bottom': (10, -16, 10, 0), + 'bottom_left': (12, -12, 0, 0), + 'left': (20, -10, 0, -10), + 'top_left': (16, -4, 4, -16) + } + (s_x, s_y, e_x, + e_y) = tuple(int(v * scale_factor) for v in arrow_offsets[arrow_type]) + start_point = (self._pos_x + s_x, self._pos_y + s_y) + end_point = (self._pos_x + e_x, self._pos_y + e_y) + image = cv2.arrowedLine(self._frame, start_point, end_point, self._color, + thickness) + + +def write_players_state(writer, players_info): + table_text = [["PLAYER", "SPRINT", "DRIBBLE", "DIRECTION", "ACTION"]] + widths = [65, 65, 70, 85, 85] + + # Sort the players according to the order they appear in observations + for _, player_info in sorted(players_info.items()): + table_text.append([ + (player_info['id'], player_info['color']), + str(player_info.get("sprint", "-")), + str(player_info.get("dribble", "-")), + player_info.get("DIRECTION", "O"), + player_info.get("ACTION", "-")]) + writer.write_table(table_text, widths, scale_factor=1.0, offset=10) + + +def get_frame(trace): + if 'frame' in trace._trace['observation']: + return trace._trace['observation']['frame'] + frame = np.uint8(np.zeros((600, 800, 3))) + corner1 = (0, 0) + corner2 = (799, 0) + corner3 = (799, 599) + corner4 = (0, 599) + line_color = (0, 255, 255) + cv2.line(frame, corner1, corner2, line_color) + cv2.line(frame, corner2, corner3, line_color) + cv2.line(frame, corner3, corner4, line_color) + cv2.line(frame, corner4, corner1, line_color) + cv2.line(frame, (399, 0), (399, 799), line_color) + writer = TextWriter( + frame, + trace['ball'][0], + trace['ball'][1], + field_coords=True, + color=(248, 244, 236)) + writer.write('B') + for player_idx, player_coord in enumerate(trace['left_team']): + writer = TextWriter( + frame, + player_coord[0], + player_coord[1], + field_coords=True, + color=(238, 68, 47)) + letter = str(player_idx) + if trace['left_team_roles'][player_idx] == e_PlayerRole_GK: + letter = 'G' + writer.write(letter) + for player_idx, player_coord in enumerate(trace['right_team']): + writer = TextWriter( + frame, + player_coord[0], + player_coord[1], + field_coords=True, + color=(99, 172, 190)) + letter = str(player_idx) + if trace['right_team_roles'][player_idx] == e_PlayerRole_GK: + letter = 'G' + writer.write(letter) + return frame + + +def softmax(x): + return np.exp(x) / np.sum(np.exp(x), axis=0) + + +class ActiveDump(object): + + def __init__(self, + name, + finish_step, + config): + self._name = name + self._finish_step = finish_step + self._config = config + self._video_fd = None + self._video_tmp = None + self._video_writer = None + self._frame_dim = None + self._step_cnt = 0 + self._dump_file = None + if config['write_video']: + video_format = config['video_format'] + assert video_format in ['avi', 'webm'] + self._video_suffix = '.%s' % video_format + self._video_fd, self._video_tmp = tempfile.mkstemp( + suffix=self._video_suffix) + self._frame_dim = ( + config['render_resolution_x'], config['render_resolution_y']) + if config['video_quality_level'] not in [1, 2]: + # Reduce resolution to (800, 450). + self._frame_dim = min(self._frame_dim, (800, 450)) + if video_format == 'avi': + if config['video_quality_level'] == 2: + fcc = cv2.VideoWriter_fourcc('p', 'n', 'g', ' ') + elif config['video_quality_level'] == 1: + fcc = cv2.VideoWriter_fourcc(*'MJPG') + else: + fcc = cv2.VideoWriter_fourcc(*'XVID') + else: + fcc = cv2.VideoWriter_fourcc(*'vp80') + + self._video_writer = cv2.VideoWriter( + self._video_tmp, fcc, + const.PHYSICS_STEPS_PER_SECOND / config['physics_steps_per_frame'], + self._frame_dim) + if WRITE_FILES: + self._dump_file = open(name + '.dump', 'wb') + + def __del__(self): + self.finalize() + + def add_frame(self, frame): + if self._video_writer: + frame = frame[..., ::-1] + frame = cv2.resize(frame, self._frame_dim, interpolation=cv2.INTER_AREA) + self._video_writer.write(frame) + + def add_step(self, o): + # Write video if requested. + if self._video_writer: + frame = get_frame(o) + frame = frame[..., ::-1] + frame = cv2.resize(frame, self._frame_dim, interpolation=cv2.INTER_AREA) + writer = TextWriter(frame, self._frame_dim[0] - 300) + if self._config['custom_display_stats']: + for line in self._config['custom_display_stats']: + writer.write(line) + if self._config['display_game_stats']: + writer.write('SCORE: %d - %d' % (o['score'][0], o['score'][1])) + if o['ball_owned_team'] == 0: + player = 'G' if o['left_team_roles'][ + o['ball_owned_player']] == e_PlayerRole_GK else o[ + 'ball_owned_player'] + writer.write('BALL OWNED: %s' % player, color=(47, 68, 238)) + elif o['ball_owned_team'] == 1: + player = 'G' if o['right_team_roles'][ + o['ball_owned_player']] == e_PlayerRole_GK else o[ + 'ball_owned_player'] + writer.write('BALL OWNED: %s' % player, color=(190, 172, 99)) + else: + writer.write('BALL OWNED: ---') + writer = TextWriter(frame, 0) + writer.write('STEP: %d' % self._step_cnt) + sticky_actions = football_action_set.get_sticky_actions(self._config) + + players_info = {} + for team in ['left', 'right']: + player_info = {} + sticky_actions_field = '%s_agent_sticky_actions' % team + for player in range(len(o[sticky_actions_field])): + assert len(sticky_actions) == len(o[sticky_actions_field][player]) + player_idx = o['%s_agent_controlled_player' % team][player] + player_info = {} + player_info['color'] = ( + 47, 68, 238) if team == 'left' else (190, 172, 99) + player_info['id'] = 'G' if o[ + '%s_team_roles' % + team][player_idx] == e_PlayerRole_GK else str(player_idx) + active_direction = None + for i in range(len(sticky_actions)): + if sticky_actions[i]._directional: + if o[sticky_actions_field][player][i]: + active_direction = sticky_actions[i] + else: + player_info[sticky_actions[i]._name] = \ + o[sticky_actions_field][player][i] + + # Info about direction + player_info['DIRECTION'] = \ + 'O' if active_direction is None else active_direction._name + if 'action' in o._trace['debug']: + # Info about action + player_info['ACTION'] = \ + o['action'][len(players_info)]._name + players_info[(team, player_idx)] = player_info + + write_players_state(writer, players_info) + + if 'baseline' in o._trace['debug']: + writer.write('BASELINE: %.5f' % o._trace['debug']['baseline']) + if 'logits' in o._trace['debug']: + probs = softmax(o._trace['debug']['logits']) + action_set = football_action_set.get_action_set(self._config) + for action, prob in zip(action_set, probs): + writer.write('%s: %.5f' % (action.name, prob), scale_factor=0.5) + for d in o._debugs: + writer.write(d) + self._video_writer.write(frame) + # Write the dump. + temp_frame = None + if 'frame' in o._trace['observation']: + temp_frame = o._trace['observation']['frame'] + del o._trace['observation']['frame'] + + # Add config to the first frame for our replay tools to use. + if self._step_cnt == 0: + o['debug']['config'] = self._config.get_dictionary() + + six.moves.cPickle.dump(o._trace, self._dump_file) + if temp_frame is not None: + o._trace['observation']['frame'] = temp_frame + self._step_cnt += 1 + + def finalize(self): + dump_info = {} + if self._video_writer: + self._video_writer.release() + self._video_writer = None + os.close(self._video_fd) + try: + # For some reason sometimes the file is missing, so the code fails. + if WRITE_FILES: + shutil.move(self._video_tmp, self._name + self._video_suffix) + dump_info['video'] = '%s%s' % (self._name, self._video_suffix) + logging.info('Video written to %s%s', self._name, self._video_suffix) + except: + logging.error(traceback.format_exc()) + if self._dump_file: + self._dump_file.close() + self._dump_file = None + if self._step_cnt == 0: + logging.warning('No data to write to the dump.') + else: + dump_info['dump'] = '%s.dump' % self._name + logging.info('Dump written to %s.dump', self._name) + return dump_info + + +class ObservationState(object): + + def __init__(self, trace): + # Observations + self._trace = trace + self._additional_frames = [] + self._debugs = [] + + def __getitem__(self, key): + if key in self._trace: + return self._trace[key] + if key in self._trace['observation']: + return self._trace['observation'][key] + return self._trace['debug'][key] + + def __contains__(self, key): + if key in self._trace: + return True + if key in self._trace['observation']: + return True + return key in self._trace['debug'] + + def _distance(self, o1, o2): + # We add 'z' dimension if not present, as ball has 3 dimensions, while + # players have only 2. + if len(o1) == 2: + o1 = np.array([o1[0], o1[1], 0]) + if len(o2) == 2: + o2 = np.array([o2[0], o2[1], 0]) + return np.linalg.norm(o1 - o2) + + def add_debug(self, text): + self._debugs.append(text) + + def add_frame(self, frame): + self._additional_frames.append(frame) + + +class ObservationProcessor(object): + + def __init__(self, config): + # Const. configuration + self._ball_takeover_epsilon = 0.03 + self._ball_lost_epsilon = 0.05 + self._frame = 0 + self._dump_config = {} + self._dump_config['score'] = DumpConfig( + steps_before=PAST_STEPS_TRACE_SIZE, + max_count=(100000 if config['dump_scores'] else 0), + min_frequency=600, + steps_after=1) + self._dump_config['lost_score'] = DumpConfig( + steps_before=PAST_STEPS_TRACE_SIZE, + max_count=(100000 if config['dump_scores'] else 0), + min_frequency=600, + steps_after=1) + self._dump_config['episode_done'] = DumpConfig( + steps_before=0, + # Record entire episode. + steps_after=10000, + max_count=(100000 if config['dump_full_episodes'] else 0)) + self._dump_config['shutdown'] = DumpConfig(steps_before=PAST_STEPS_TRACE_SIZE) + self._dump_directory = None + self._config = config + self.clear_state() + + def clear_state(self): + self._frame = 0 + self._state = None + self._trace = collections.deque([], PAST_STEPS_TRACE_SIZE) + + def reset(self): + self.clear_state() + + def len(self): + return len(self._trace) + + def __getitem__(self, key): + return self._trace[key] + + def add_frame(self, frame): + if len(self._trace) > 0 and self._config['write_video']: + self._trace[-1].add_frame(frame) + for dump in self.pending_dumps(): + dump.add_frame(frame) + + def update(self, trace): + self._frame += 1 + frame = trace.get('frame', None) + if not self._config['write_video'] and 'frame' in trace['observation']: + # Don't record frame in the trace if we don't write video to save memory. + no_video_trace = trace + no_video_trace['observation'] = trace['observation'].copy() + del no_video_trace['observation']['frame'] + self._state = ObservationState(no_video_trace) + frame = None + else: + self._state = ObservationState(trace) + self._trace.append(self._state) + for dump in self.pending_dumps(): + dump.add_step(self._state) + + def get_last_frame(self): + if not self._state: + return [] + return get_frame(self._state) + + def write_dump(self, name): + if not name in self._dump_config: + self._dump_config[name] = DumpConfig() + config = self._dump_config[name] + if config._active_dump: + logging.debug('Dump "%s": already pending', name) + return + if config._max_count <= 0: + logging.debug('Dump "%s": count limit reached / disabled', name) + return + if config._last_dump_time > timeit.default_timer() - config._min_frequency: + logging.debug('Dump "%s": too frequent', name) + return + config._max_count -= 1 + config._last_dump_time = timeit.default_timer() + if self._dump_directory is None: + self._dump_directory = self._config['tracesdir'] + if WRITE_FILES: + if not os.path.exists(self._dump_directory): + os.makedirs(self._dump_directory) + dump_name = '{2}{3}{0}_{1}'.format(name, + datetime.datetime.now().strftime('%Y%m%d-%H%M%S%f'), + self._dump_directory, os.sep) + config._active_dump = ActiveDump(dump_name, + self._frame + config._steps_after, self._config) + for step in list(self._trace)[-config._steps_before:]: + config._active_dump.add_step(step) + for frame in step._additional_frames: + config._active_dump.add_frame(frame) + if config._steps_after == 0: + # Synchronously finalize dump, so that crash dump is recorded. + config._active_dump.finalize() + config._active_dump = None + return dump_name + + def pending_dumps(self): + dumps = [] + for config in self._dump_config.values(): + if config._active_dump: + dumps.append(config._active_dump) + return dumps + + def process_pending_dumps(self, episode_done=False): + dumps = [] + for name in self._dump_config: + config = self._dump_config[name] + if config._active_dump and ( + episode_done or config._active_dump._finish_step <= self._frame): + dump_info = config._active_dump.finalize() + dump_info['name'] = name + dumps.append(dump_info) + config._active_dump = None + return dumps diff --git a/envpool/gfootball/registration.py b/envpool/gfootball/registration.py new file mode 100644 index 00000000..5ec2c9fc --- /dev/null +++ b/envpool/gfootball/registration.py @@ -0,0 +1,9 @@ +from envpool.registration import register + +register( + task_id = "football", + import_path = "envpool.gfootball", + spec_cls = "FootballEnvSpec", + dm_cls = "FootballDMEnvpool", + gym_cls = "FootballGymEnvpool", +) \ No newline at end of file From 7b389758175afe5f3844787c5cf531c8843b093a Mon Sep 17 00:00:00 2001 From: kfq2002 <95134838+kfq2002@users.noreply.github.com> Date: Wed, 3 Aug 2022 17:37:26 +0800 Subject: [PATCH 05/28] Add files via upload --- third_party/gfootball/gfootball.BUILD | 47 +++++++++++++++++---------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/third_party/gfootball/gfootball.BUILD b/third_party/gfootball/gfootball.BUILD index 36f1d112..6f41599c 100644 --- a/third_party/gfootball/gfootball.BUILD +++ b/third_party/gfootball/gfootball.BUILD @@ -1,18 +1,29 @@ -package(default_visibility = ["//visibility:public"]) - -cc_library( - name = "mujoco_lib", - srcs = glob(["lib/*"]), - hdrs = glob(["include/mujoco/*.h"]), - includes = [ - "include", - "include/mujoco", - ], - linkopts = ["-Wl,-rpath,'$$ORIGIN'"], - linkstatic = 0, -) - -filegroup( - name = "mujoco_so", - srcs = ["lib/libmujoco.so.2.2.0"], -) +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "game_env", + hdrs = ["third_party/gfootball_engine/src/game_env.hpp"], + srcs = glob(["third_party/gfootball_engine/src/**/*.h", + "third_party/gfootball_engine/src/**/*.hpp", + "third_party/gfootball_engine/src/**/*.c", + "third_party/gfootball_engine/src/**/*.cpp", + ]), + includes = [ + "third_party/gfootball_engine/src", + "third_party/gfootball_engine/src/ai", + "third_party/gfootball_engine/src/base", + "third_party/gfootball_engine/src/cmake", + "third_party/gfootball_engine/src/data", + "third_party/gfootball_engine/src/hid", + "third_party/gfootball_engine/src/loaders", + "third_party/gfootball_engine/src/managers", + "third_party/gfootball_engine/src/menu", + "third_party/gfootball_engine/src/misc", + "third_party/gfootball_engine/src/onthepitch", + "third_party/gfootball_engine/src/scene", + "third_party/gfootball_engine/src/systems", + "third_party/gfootball_engine/src/types", + "third_party/gfootball_engine/src/utils", + ], +) + From 50040c3d76b89b74a8dd86e028ee2121dac707e6 Mon Sep 17 00:00:00 2001 From: kfq2002 <95134838+kfq2002@users.noreply.github.com> Date: Wed, 3 Aug 2022 17:41:57 +0800 Subject: [PATCH 06/28] Update workspace0.bzl --- envpool/workspace0.bzl | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/envpool/workspace0.bzl b/envpool/workspace0.bzl index 67223a8d..38e55185 100644 --- a/envpool/workspace0.bzl +++ b/envpool/workspace0.bzl @@ -387,6 +387,16 @@ def workspace(): "https://ml.cs.tsinghua.edu.cn/~jiayi/envpool/erenon/bazel_clang_tidy/783aa523aafb4a6798a538c61e700b6ed27975a7.zip", ], ) + + maybe( + http_archive, + name = "football", + sha256 = "", + urls = [ + "https://files.pythonhosted.org/packages/98/63/b111538b5db47b8081d8ca82280fadaa145fbd31aa249f49675a01abb8eb/gfootball-2.10.2.tar.gz" + ], + build_file = "//third_party/gfootball:gfootball.BUILD", + ) maybe( cuda_configure, From 2bb4690f9bd5785a531f6d1f0b69da74abea2a6d Mon Sep 17 00:00:00 2001 From: kfq2002 <95134838+kfq2002@users.noreply.github.com> Date: Wed, 3 Aug 2022 17:43:00 +0800 Subject: [PATCH 07/28] Update entry.py --- envpool/entry.py | 1 + 1 file changed, 1 insertion(+) diff --git a/envpool/entry.py b/envpool/entry.py index f21e93ca..453c6d00 100644 --- a/envpool/entry.py +++ b/envpool/entry.py @@ -20,3 +20,4 @@ import envpool.mujoco.gym.registration # noqa: F401 import envpool.toy_text.registration # noqa: F401 import envpool.vizdoom.registration # noqa: F401 +import envpool.gfootball.registration From d6f5c78f9b4652dd425229274018b287115840d9 Mon Sep 17 00:00:00 2001 From: kfq2002 <95134838+kfq2002@users.noreply.github.com> Date: Wed, 10 Aug 2022 21:45:50 +0800 Subject: [PATCH 08/28] Update BUILD --- envpool/gfootball/BUILD | 52 ++++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/envpool/gfootball/BUILD b/envpool/gfootball/BUILD index 486473b6..414b6a0f 100644 --- a/envpool/gfootball/BUILD +++ b/envpool/gfootball/BUILD @@ -9,11 +9,27 @@ cc_library( deps = [ "//envpool/core:async_envpool", "@gfootball_engine//:game_env", - "config.h", - "football_action_set.h", + "//envpool/football:config", + "//envpool/football:football_action_set", ], ) +cc_library( + name = "config", + hdrs = ["config.h"], + deps = [ + "@gfootball_engine//:game_env", + ], +) + +cc_library( + name = "football_action_set", + hdrs = ["football_action_set.h"], + deps = [ + "//envpool/football:config", + "@gfootball_engine//:game_env", + ], +) pybind_extension( name = "football_envpool", @@ -21,7 +37,7 @@ pybind_extension( "football_envpool.cc", ], deps = [ - "football_env", + "//envpool/football:football_env", "//envpool/core:py_envpool", ], ) @@ -32,21 +48,25 @@ py_library( deps = ["//envpool/python:api"] ) -py_library( - name = "football_observation_processor", - srcs = ["football_observation_processor.py"], +py_test( + name = "football_envpool_test", + size = "enormous", + srcs = ["football_envpool_test.py"], deps = [ + ":football", requirement("numpy"), - requirement("collections"), - requirement("datetime"), - requirement("os"), - requirement("shutil"), - requirement("tempfile"), - requirement("timeit"), - requirement("traceback"), - requirement("absl"), - requirement("gfootball"), - requirement("six"), + requirement("jax"), + requirement("absl-py"), + ], +) + +cc_test( + name = "football_env_test", + size = "enormous", + srcs = ["football_env_test.cc"], + deps = [ + ":football_env", + "@com_google_googletest//:gtest_main", ], ) From 99703687e6150b2ce30710f9270e4cb1fdfce690 Mon Sep 17 00:00:00 2001 From: kfq2002 <95134838+kfq2002@users.noreply.github.com> Date: Wed, 10 Aug 2022 21:46:19 +0800 Subject: [PATCH 09/28] Delete football_observation_processor.py --- .../football_observation_processor.py | 524 ------------------ 1 file changed, 524 deletions(-) delete mode 100644 envpool/gfootball/football_observation_processor.py diff --git a/envpool/gfootball/football_observation_processor.py b/envpool/gfootball/football_observation_processor.py deleted file mode 100644 index 3d7625fc..00000000 --- a/envpool/gfootball/football_observation_processor.py +++ /dev/null @@ -1,524 +0,0 @@ -# coding=utf-8 -# Copyright 2019 Google LLC -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - - -"""Observation processor, providing multiple support methods for analyzing observations.""" - -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import collections -import datetime -import os -import shutil -import tempfile -import timeit -import traceback - -from absl import logging -from gfootball.env import constants as const -from gfootball.env import football_action_set -from gfootball.scenarios import e_PlayerRole_GK -import numpy as np -from six.moves import range -from six.moves import zip -import six.moves.cPickle - -# How many past frames are kept around for the dumps to make use of them. -PAST_STEPS_TRACE_SIZE = 100 - -WRITE_FILES = True - -try: - import cv2 -except ImportError: - import cv2 - - -class DumpConfig(object): - - def __init__(self, - max_count=1, - steps_before=PAST_STEPS_TRACE_SIZE, - steps_after=0, - min_frequency=10): - self._steps_before = steps_before - self._steps_after = steps_after - self._max_count = max_count - # Make sure self._last_dump_time < timeit.default_timer() - min_frequency - # holds upon startup. - self._last_dump_time = timeit.default_timer() - 2 * min_frequency - self._active_dump = None - self._min_frequency = min_frequency - - -class TextWriter(object): - - def __init__(self, frame, x, y=0, field_coords=False, color=(255, 255, 255)): - self._frame = frame - if field_coords: - x = 400 * (x + 1) - 10 - y = 695 * (y + 0.43) - self._pos_x = int(x) - self._pos_y = int(y) + 20 - self._color = color - self._font = cv2.FONT_HERSHEY_SIMPLEX - self._lineType = 2 - self._arrow_types = ('top', 'top_right', 'right', 'bottom_right', 'bottom', - 'bottom_left', 'left', 'top_left') - - def write(self, text, scale_factor=1, color=None): - textPos = (self._pos_x, self._pos_y) - fontScale = 0.8 * scale_factor - cv2.putText(self._frame, text, textPos, self._font, fontScale, color or self._color, - self._lineType) - self._pos_y += int(25 * scale_factor) - - def write_table(self, data, widths, scale_factor=1, offset=0): - # data is a list of rows. Each row is a list of strings. - fontScale = 0.5 * scale_factor - init_x = self._pos_x - for row in data: - assert (len(row) == len(widths)) - self._pos_x += offset - for col, cell in enumerate(row): - color = self._color - if isinstance(cell, tuple): - assert (len(cell) == 2) - (text, color) = cell - else: - assert (isinstance(cell, str)) - text = cell - - if text in self._arrow_types: - self.write_arrow(text, scale_factor=scale_factor) - else: - textPos = (self._pos_x, self._pos_y) - cv2.putText(self._frame, text, textPos, self._font, fontScale, color, - self._lineType) - self._pos_x += widths[col] - self._pos_x = init_x - self._pos_y += int(20 * scale_factor) - self._pos_x = init_x - - def write_arrow(self, arrow_type, scale_factor=1): - assert (arrow_type in self._arrow_types) - thickness = 1 - arrow_offsets = { - 'top': (12, 0, 12, -16), - 'top_right': (4, -4, 16, -16), - 'right': (0, -10, 20, -10), - 'bottom_right': (4, -16, 16, -4), - 'bottom': (10, -16, 10, 0), - 'bottom_left': (12, -12, 0, 0), - 'left': (20, -10, 0, -10), - 'top_left': (16, -4, 4, -16) - } - (s_x, s_y, e_x, - e_y) = tuple(int(v * scale_factor) for v in arrow_offsets[arrow_type]) - start_point = (self._pos_x + s_x, self._pos_y + s_y) - end_point = (self._pos_x + e_x, self._pos_y + e_y) - image = cv2.arrowedLine(self._frame, start_point, end_point, self._color, - thickness) - - -def write_players_state(writer, players_info): - table_text = [["PLAYER", "SPRINT", "DRIBBLE", "DIRECTION", "ACTION"]] - widths = [65, 65, 70, 85, 85] - - # Sort the players according to the order they appear in observations - for _, player_info in sorted(players_info.items()): - table_text.append([ - (player_info['id'], player_info['color']), - str(player_info.get("sprint", "-")), - str(player_info.get("dribble", "-")), - player_info.get("DIRECTION", "O"), - player_info.get("ACTION", "-")]) - writer.write_table(table_text, widths, scale_factor=1.0, offset=10) - - -def get_frame(trace): - if 'frame' in trace._trace['observation']: - return trace._trace['observation']['frame'] - frame = np.uint8(np.zeros((600, 800, 3))) - corner1 = (0, 0) - corner2 = (799, 0) - corner3 = (799, 599) - corner4 = (0, 599) - line_color = (0, 255, 255) - cv2.line(frame, corner1, corner2, line_color) - cv2.line(frame, corner2, corner3, line_color) - cv2.line(frame, corner3, corner4, line_color) - cv2.line(frame, corner4, corner1, line_color) - cv2.line(frame, (399, 0), (399, 799), line_color) - writer = TextWriter( - frame, - trace['ball'][0], - trace['ball'][1], - field_coords=True, - color=(248, 244, 236)) - writer.write('B') - for player_idx, player_coord in enumerate(trace['left_team']): - writer = TextWriter( - frame, - player_coord[0], - player_coord[1], - field_coords=True, - color=(238, 68, 47)) - letter = str(player_idx) - if trace['left_team_roles'][player_idx] == e_PlayerRole_GK: - letter = 'G' - writer.write(letter) - for player_idx, player_coord in enumerate(trace['right_team']): - writer = TextWriter( - frame, - player_coord[0], - player_coord[1], - field_coords=True, - color=(99, 172, 190)) - letter = str(player_idx) - if trace['right_team_roles'][player_idx] == e_PlayerRole_GK: - letter = 'G' - writer.write(letter) - return frame - - -def softmax(x): - return np.exp(x) / np.sum(np.exp(x), axis=0) - - -class ActiveDump(object): - - def __init__(self, - name, - finish_step, - config): - self._name = name - self._finish_step = finish_step - self._config = config - self._video_fd = None - self._video_tmp = None - self._video_writer = None - self._frame_dim = None - self._step_cnt = 0 - self._dump_file = None - if config['write_video']: - video_format = config['video_format'] - assert video_format in ['avi', 'webm'] - self._video_suffix = '.%s' % video_format - self._video_fd, self._video_tmp = tempfile.mkstemp( - suffix=self._video_suffix) - self._frame_dim = ( - config['render_resolution_x'], config['render_resolution_y']) - if config['video_quality_level'] not in [1, 2]: - # Reduce resolution to (800, 450). - self._frame_dim = min(self._frame_dim, (800, 450)) - if video_format == 'avi': - if config['video_quality_level'] == 2: - fcc = cv2.VideoWriter_fourcc('p', 'n', 'g', ' ') - elif config['video_quality_level'] == 1: - fcc = cv2.VideoWriter_fourcc(*'MJPG') - else: - fcc = cv2.VideoWriter_fourcc(*'XVID') - else: - fcc = cv2.VideoWriter_fourcc(*'vp80') - - self._video_writer = cv2.VideoWriter( - self._video_tmp, fcc, - const.PHYSICS_STEPS_PER_SECOND / config['physics_steps_per_frame'], - self._frame_dim) - if WRITE_FILES: - self._dump_file = open(name + '.dump', 'wb') - - def __del__(self): - self.finalize() - - def add_frame(self, frame): - if self._video_writer: - frame = frame[..., ::-1] - frame = cv2.resize(frame, self._frame_dim, interpolation=cv2.INTER_AREA) - self._video_writer.write(frame) - - def add_step(self, o): - # Write video if requested. - if self._video_writer: - frame = get_frame(o) - frame = frame[..., ::-1] - frame = cv2.resize(frame, self._frame_dim, interpolation=cv2.INTER_AREA) - writer = TextWriter(frame, self._frame_dim[0] - 300) - if self._config['custom_display_stats']: - for line in self._config['custom_display_stats']: - writer.write(line) - if self._config['display_game_stats']: - writer.write('SCORE: %d - %d' % (o['score'][0], o['score'][1])) - if o['ball_owned_team'] == 0: - player = 'G' if o['left_team_roles'][ - o['ball_owned_player']] == e_PlayerRole_GK else o[ - 'ball_owned_player'] - writer.write('BALL OWNED: %s' % player, color=(47, 68, 238)) - elif o['ball_owned_team'] == 1: - player = 'G' if o['right_team_roles'][ - o['ball_owned_player']] == e_PlayerRole_GK else o[ - 'ball_owned_player'] - writer.write('BALL OWNED: %s' % player, color=(190, 172, 99)) - else: - writer.write('BALL OWNED: ---') - writer = TextWriter(frame, 0) - writer.write('STEP: %d' % self._step_cnt) - sticky_actions = football_action_set.get_sticky_actions(self._config) - - players_info = {} - for team in ['left', 'right']: - player_info = {} - sticky_actions_field = '%s_agent_sticky_actions' % team - for player in range(len(o[sticky_actions_field])): - assert len(sticky_actions) == len(o[sticky_actions_field][player]) - player_idx = o['%s_agent_controlled_player' % team][player] - player_info = {} - player_info['color'] = ( - 47, 68, 238) if team == 'left' else (190, 172, 99) - player_info['id'] = 'G' if o[ - '%s_team_roles' % - team][player_idx] == e_PlayerRole_GK else str(player_idx) - active_direction = None - for i in range(len(sticky_actions)): - if sticky_actions[i]._directional: - if o[sticky_actions_field][player][i]: - active_direction = sticky_actions[i] - else: - player_info[sticky_actions[i]._name] = \ - o[sticky_actions_field][player][i] - - # Info about direction - player_info['DIRECTION'] = \ - 'O' if active_direction is None else active_direction._name - if 'action' in o._trace['debug']: - # Info about action - player_info['ACTION'] = \ - o['action'][len(players_info)]._name - players_info[(team, player_idx)] = player_info - - write_players_state(writer, players_info) - - if 'baseline' in o._trace['debug']: - writer.write('BASELINE: %.5f' % o._trace['debug']['baseline']) - if 'logits' in o._trace['debug']: - probs = softmax(o._trace['debug']['logits']) - action_set = football_action_set.get_action_set(self._config) - for action, prob in zip(action_set, probs): - writer.write('%s: %.5f' % (action.name, prob), scale_factor=0.5) - for d in o._debugs: - writer.write(d) - self._video_writer.write(frame) - # Write the dump. - temp_frame = None - if 'frame' in o._trace['observation']: - temp_frame = o._trace['observation']['frame'] - del o._trace['observation']['frame'] - - # Add config to the first frame for our replay tools to use. - if self._step_cnt == 0: - o['debug']['config'] = self._config.get_dictionary() - - six.moves.cPickle.dump(o._trace, self._dump_file) - if temp_frame is not None: - o._trace['observation']['frame'] = temp_frame - self._step_cnt += 1 - - def finalize(self): - dump_info = {} - if self._video_writer: - self._video_writer.release() - self._video_writer = None - os.close(self._video_fd) - try: - # For some reason sometimes the file is missing, so the code fails. - if WRITE_FILES: - shutil.move(self._video_tmp, self._name + self._video_suffix) - dump_info['video'] = '%s%s' % (self._name, self._video_suffix) - logging.info('Video written to %s%s', self._name, self._video_suffix) - except: - logging.error(traceback.format_exc()) - if self._dump_file: - self._dump_file.close() - self._dump_file = None - if self._step_cnt == 0: - logging.warning('No data to write to the dump.') - else: - dump_info['dump'] = '%s.dump' % self._name - logging.info('Dump written to %s.dump', self._name) - return dump_info - - -class ObservationState(object): - - def __init__(self, trace): - # Observations - self._trace = trace - self._additional_frames = [] - self._debugs = [] - - def __getitem__(self, key): - if key in self._trace: - return self._trace[key] - if key in self._trace['observation']: - return self._trace['observation'][key] - return self._trace['debug'][key] - - def __contains__(self, key): - if key in self._trace: - return True - if key in self._trace['observation']: - return True - return key in self._trace['debug'] - - def _distance(self, o1, o2): - # We add 'z' dimension if not present, as ball has 3 dimensions, while - # players have only 2. - if len(o1) == 2: - o1 = np.array([o1[0], o1[1], 0]) - if len(o2) == 2: - o2 = np.array([o2[0], o2[1], 0]) - return np.linalg.norm(o1 - o2) - - def add_debug(self, text): - self._debugs.append(text) - - def add_frame(self, frame): - self._additional_frames.append(frame) - - -class ObservationProcessor(object): - - def __init__(self, config): - # Const. configuration - self._ball_takeover_epsilon = 0.03 - self._ball_lost_epsilon = 0.05 - self._frame = 0 - self._dump_config = {} - self._dump_config['score'] = DumpConfig( - steps_before=PAST_STEPS_TRACE_SIZE, - max_count=(100000 if config['dump_scores'] else 0), - min_frequency=600, - steps_after=1) - self._dump_config['lost_score'] = DumpConfig( - steps_before=PAST_STEPS_TRACE_SIZE, - max_count=(100000 if config['dump_scores'] else 0), - min_frequency=600, - steps_after=1) - self._dump_config['episode_done'] = DumpConfig( - steps_before=0, - # Record entire episode. - steps_after=10000, - max_count=(100000 if config['dump_full_episodes'] else 0)) - self._dump_config['shutdown'] = DumpConfig(steps_before=PAST_STEPS_TRACE_SIZE) - self._dump_directory = None - self._config = config - self.clear_state() - - def clear_state(self): - self._frame = 0 - self._state = None - self._trace = collections.deque([], PAST_STEPS_TRACE_SIZE) - - def reset(self): - self.clear_state() - - def len(self): - return len(self._trace) - - def __getitem__(self, key): - return self._trace[key] - - def add_frame(self, frame): - if len(self._trace) > 0 and self._config['write_video']: - self._trace[-1].add_frame(frame) - for dump in self.pending_dumps(): - dump.add_frame(frame) - - def update(self, trace): - self._frame += 1 - frame = trace.get('frame', None) - if not self._config['write_video'] and 'frame' in trace['observation']: - # Don't record frame in the trace if we don't write video to save memory. - no_video_trace = trace - no_video_trace['observation'] = trace['observation'].copy() - del no_video_trace['observation']['frame'] - self._state = ObservationState(no_video_trace) - frame = None - else: - self._state = ObservationState(trace) - self._trace.append(self._state) - for dump in self.pending_dumps(): - dump.add_step(self._state) - - def get_last_frame(self): - if not self._state: - return [] - return get_frame(self._state) - - def write_dump(self, name): - if not name in self._dump_config: - self._dump_config[name] = DumpConfig() - config = self._dump_config[name] - if config._active_dump: - logging.debug('Dump "%s": already pending', name) - return - if config._max_count <= 0: - logging.debug('Dump "%s": count limit reached / disabled', name) - return - if config._last_dump_time > timeit.default_timer() - config._min_frequency: - logging.debug('Dump "%s": too frequent', name) - return - config._max_count -= 1 - config._last_dump_time = timeit.default_timer() - if self._dump_directory is None: - self._dump_directory = self._config['tracesdir'] - if WRITE_FILES: - if not os.path.exists(self._dump_directory): - os.makedirs(self._dump_directory) - dump_name = '{2}{3}{0}_{1}'.format(name, - datetime.datetime.now().strftime('%Y%m%d-%H%M%S%f'), - self._dump_directory, os.sep) - config._active_dump = ActiveDump(dump_name, - self._frame + config._steps_after, self._config) - for step in list(self._trace)[-config._steps_before:]: - config._active_dump.add_step(step) - for frame in step._additional_frames: - config._active_dump.add_frame(frame) - if config._steps_after == 0: - # Synchronously finalize dump, so that crash dump is recorded. - config._active_dump.finalize() - config._active_dump = None - return dump_name - - def pending_dumps(self): - dumps = [] - for config in self._dump_config.values(): - if config._active_dump: - dumps.append(config._active_dump) - return dumps - - def process_pending_dumps(self, episode_done=False): - dumps = [] - for name in self._dump_config: - config = self._dump_config[name] - if config._active_dump and ( - episode_done or config._active_dump._finish_step <= self._frame): - dump_info = config._active_dump.finalize() - dump_info['name'] = name - dumps.append(dump_info) - config._active_dump = None - return dumps From 8eeeb627434f95a8e5db7d7e3b4bef8430d045c4 Mon Sep 17 00:00:00 2001 From: kfq2002 <95134838+kfq2002@users.noreply.github.com> Date: Wed, 10 Aug 2022 21:52:14 +0800 Subject: [PATCH 10/28] Update football_env.h --- envpool/gfootball/football_env.h | 41 ++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/envpool/gfootball/football_env.h b/envpool/gfootball/football_env.h index 958c2eb1..641bcee6 100644 --- a/envpool/gfootball/football_env.h +++ b/envpool/gfootball/football_env.h @@ -1,22 +1,23 @@ #include -#include +#include +#include #include "game_env.hpp" #include "config.h" #include "football_action_set.h" #include "envpool/core/async_envpool.h" -#include "envpool/utils/image_process.h" #include "envpool/core/env.h" namespace football{ class FootballEnvFns { public: - std::string tracesdir_pre = getcwd(NULL, 0); - std::string tracesdir = tracesdir_pre + "/dump"; + static char *tracesdir_pre_char; + static std::string tracesdir_pre; + static std::string tracesdir; static decltype(auto) DefaultConfig(){ return MakeDict( - "action_set"_.Bind(std::string("default")), "custom_display_stats"_.Bind(std::vector{}), "display_game_stats"._Bind(true), - "dump_full_episodes"_.Bind(false), "dump_scores"_.Bind(false), "players"._Bind(std::vector{"agent:left_players=1"}), + "action_set"_.Bind(std::string("default")), "custom_display_stats"_.Bind(std::vector{}), "display_game_stats"_.Bind(true), + "dump_full_episodes"_.Bind(false), "dump_scores"_.Bind(false), "players"_.Bind(std::vector{"agent:left_players=1"}), "level"_.Bind(std::string("11_vs_11_stochastic")), "physics_steps_per_frame"_.Bind(10), "render_resolution_x"_.Bind(1280), "render_resolution_y"_.Bind(1280 * 0.5625), "real_time"_.Bind(false), "tracesdir"_.Bind(tracesdir), "video_format"_.Bind(std::string("avi")), "video_quality_level"_.Bind(0), "write_video"_.Bind(false) @@ -25,7 +26,7 @@ class FootballEnvFns { template static decltype(auto) StateSpec(const Config& conf) { return MakeDict( - "obs"_.Bind(Spec({-1, 72, 96}, {0, 255}), + "obs"_.Bind(Spec({-1, 72, 96, 16}, {0, 255}), "info:episode_reward"_.Bind(Spec({})), "info:score"_.Bind(Spec({2})), "info:steps"_.Bind(Spec({})), @@ -40,6 +41,11 @@ class FootballEnvFns { "action"_.Bind(Spec({-1}, {0, 32})) ); } + FootballEnvFns(){ + tracesdir_pre_char = getcwd(NULL, 0); + tracesdir_pre = tracesdir_pre_char; + tracesdir = tracesdir_pre + "/dump"; + } }; using FootballEnvSpec = EnvSpec; @@ -87,15 +93,15 @@ class FootballEnv : public Env { std::vector action_set; float cumulative_reward = 0; using Observation = decltype(MakeDict( - "left_team"._Bind(std::vector(22)), "left_team_roles"_.Bind(std::vector(11)), "left_team_direction"._Bind(std::vector(22)), - "left_team_tired_factor"._Bind(std::vector(11)), "left_team_yellow_card"._Bind(std::vector(11)), "left_team_active"._Bind(std::vector{0}), - "left_team_designated_player"._Bind(3), "right_team"._Bind(std::vector(22)), "right_team_roles"._Bind(std::vector(11)), - "right_team_direction"._Bind(std::vector(22)), "right_team_tired_factor"._Bind(std::vector(11)), "right_team_yellow_card"._Bind(std::vector(11)), - "right_team_active"._Bind(std::vector{0}), "right_team_designated_player"._Bind(0), "ball"._Bind(std::vector{0 , 0 , 0}), - "ball_direction"._Bind(std::vector(3)), "ball_rotation"._Bind(std::vector(3)), "ball_owned_team"._Bind(0), - "ball_owned_player"._Bind(7), "left_agent_controlled_player"._Bind(std::vector{4}), "right_agent_controlled_player"._Bind(std::vector{6}), - "game_mode"._Bind(0), "left_agent_sticky_actions"._Bind(std::vector(2)), "right_agent_sticky_actions"._Bind(std::vector(2)), - "score"._Bind(std::vector{3, 5}), "steps_left"._Bind(45) + "left_team"_.Bind(std::vector(22)), "left_team_roles"_.Bind(std::vector(11)), "left_team_direction"_.Bind(std::vector(22)), + "left_team_tired_factor"_.Bind(std::vector(11)), "left_team_yellow_card"_.Bind(std::vector(11)), "left_team_active"_.Bind(std::vector{0}), + "left_team_designated_player"_.Bind(3), "right_team"_.Bind(std::vector(22)), "right_team_roles"_.Bind(std::vector(11)), + "right_team_direction"_.Bind(std::vector(22)), "right_team_tired_factor"_.Bind(std::vector(11)), "right_team_yellow_card"_.Bind(std::vector(11)), + "right_team_active"_.Bind(std::vector{0}), "right_team_designated_player"_.Bind(0), "ball"_.Bind(std::vector{0 , 0 , 0}), + "ball_direction"_.Bind(std::vector(3)), "ball_rotation"_.Bind(std::vector(3)), "ball_owned_team"_.Bind(0), + "ball_owned_player"_.Bind(7), "left_agent_controlled_player"_.Bind(std::vector{4}), "right_agent_controlled_player"_.Bind(std::vector{6}), + "game_mode"_.Bind(0), "left_agent_sticky_actions"_.Bind(std::vector(2)), "right_agent_sticky_actions"_.Bind(std::vector(2)), + "score"_.Bind(std::vector{3, 5}), "steps_left"_.Bind(45) )); Observation observation; @@ -407,6 +413,5 @@ class FootballEnv : public Env { }; +using FootballEnvPool = AsyncEnvPool; } - -using FootballEnvPool = AsyncEnvPool; \ No newline at end of file From e63a8faf74d560ad733e0f10d332fecd9bd8eb44 Mon Sep 17 00:00:00 2001 From: kfq2002 <95134838+kfq2002@users.noreply.github.com> Date: Wed, 10 Aug 2022 21:53:38 +0800 Subject: [PATCH 11/28] Update config.h --- envpool/gfootball/config.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/envpool/gfootball/config.h b/envpool/gfootball/config.h index 402a580f..9b52cff4 100644 --- a/envpool/gfootball/config.h +++ b/envpool/gfootball/config.h @@ -1,6 +1,7 @@ #include #include -#include +#include +#include #include "game_env.hpp" class Config{ @@ -16,7 +17,8 @@ class Config{ float render_resolution_x = 1280; float render_resolution_y = 0.5625 * render_resolution_x; bool real_time = false; - std::string tracesdir_pre = getcwd(NULL, 0); + char* tracesdir_pre_char = getcwd(NULL, 0); + std::string tracesdir_pre = tracesdir_pre_char; std::string tracesdir = tracesdir_pre + "/dump"; std::string video_format = "avi"; int video_quality_level = 0; @@ -28,4 +30,4 @@ class Config{ ScenarioConfig scenario_config; }; -}; \ No newline at end of file +}; From cfa09efde81334b3d0b74e3f3056e26c0229aff5 Mon Sep 17 00:00:00 2001 From: kfq2002 <95134838+kfq2002@users.noreply.github.com> Date: Wed, 10 Aug 2022 21:54:40 +0800 Subject: [PATCH 12/28] Update football_env_test.cc --- envpool/gfootball/football_env_test.cc | 39 ++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/envpool/gfootball/football_env_test.cc b/envpool/gfootball/football_env_test.cc index e69de29b..9660f660 100644 --- a/envpool/gfootball/football_env_test.cc +++ b/envpool/gfootball/football_env_test.cc @@ -0,0 +1,39 @@ +// Copyright 2021 Garena Online Private Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "envpool/football/football_env.h" + +#include +#include + +#include + +using FootballState = football::FootballEnv::State; +using FootballAction = football::FootballEnv::Action; +auto config = football::FootballEnvSpec::kDefaultConfig; +std::size_t batch = 4; +int num_envs = 4; +config["num_envs"_] = batch; +config["batch_size"_] = batch; +config["seed"_] = 0; +int total_iter = 10000; +football::FootballEnvSpec spec(config); +football::FootballEnvPool envpool(spec); +Array all_env_ids(Spec({num_envs})); +for (int i = 0; i < num_envs; ++i) { + all_env_ids[i] = i; +} +envpool.Reset(all_env_ids); +auto state_vec = envpool.Recv(); +FootballState state(&state_vec); From 1e3941da3f68b62c6926991b3885c20e44a01c73 Mon Sep 17 00:00:00 2001 From: kfq2002 <95134838+kfq2002@users.noreply.github.com> Date: Wed, 10 Aug 2022 21:55:36 +0800 Subject: [PATCH 13/28] Create football_envpool_test.py --- envpool/gfootball/football_envpool_test.py | 71 ++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 envpool/gfootball/football_envpool_test.py diff --git a/envpool/gfootball/football_envpool_test.py b/envpool/gfootball/football_envpool_test.py new file mode 100644 index 00000000..ad62f435 --- /dev/null +++ b/envpool/gfootball/football_envpool_test.py @@ -0,0 +1,71 @@ +"""Unit tests for football check.""" + +from random import random +from typing import Any +from typing import no_type_check + +import numpy as np +import time +from absl.testing import absltest +from absl import logging +from envpool.football.football_envpool import _FootballEnvSpec, _FootballEnvPool + +from envpool.football import ( + FootballEnvSpec, + FootballEnvPool, +) + +class _FootballTest(absltest.TestCase): + + def test_reset_life(self) -> None: + np.random.seed(0) + env = FootballEnvPool( + FootballEnvSpec( + FootballEnvSpec.gen_config(task="football", num_envs=1, episodic_life=True) + ) + ) + action_num = env.action_space.n + env.reset() + info = env.step(np.array([0]))[-1] + for _ in range(10000): + _, _, done, info = env.step(np.random.randint(0, action_num, 1)) + if info["lives"][0] == 0: + break + else: + self.assertFalse(info["terminated"][0]) + _, _, next_done, next_info = env.step( + np.random.randint(0, action_num, 1) + ) + if done[0] and next_info["lives"][0] > 0: + self.assertTrue(info["terminated"][0]) + self.assertFalse(done[0]) + self.assertFalse(info["terminated"][0]) + while not done[0]: + self.assertFalse(info["terminated"][0]) + _, _, done, info = env.step(np.random.randint(0, action_num, 1)) + _, _, next_done, next_info = env.step( + np.random.randint(0, action_num, 1) + ) + self.assertTrue(next_info["lives"][0] > 0) + self.assertTrue(info["terminated"][0]) + + def observation_space_check(self) -> None: + obs0 = (72, 96, 16) + env = FootballEnvPool(FootballEnvSpec(FootballEnvSpec.gen_config())) + obs1 = env.observation_space + np.testing.assert_allclose(obs0, obs1) + + def run_check(self) -> None: + env = FootballEnvPool(FootballEnvSpec(FootballEnvSpec.gen_config())) + for i in range(10): + np.random.seed(i) + env.action_space.seed(i) + env.reset() + done = False + while not done: + a = env.action_space.sample() + obs, reward, done, _ = env.step(a) + print(obs, reward, done) + +if __name__ == "__main__": + absltest.main() From ba87f41a5ef8dcd7864a7450afd554f1d47a79e1 Mon Sep 17 00:00:00 2001 From: kfq2002 <95134838+kfq2002@users.noreply.github.com> Date: Wed, 10 Aug 2022 21:56:35 +0800 Subject: [PATCH 14/28] Update registration.py --- envpool/gfootball/registration.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/envpool/gfootball/registration.py b/envpool/gfootball/registration.py index 5ec2c9fc..0ffbe081 100644 --- a/envpool/gfootball/registration.py +++ b/envpool/gfootball/registration.py @@ -4,6 +4,5 @@ task_id = "football", import_path = "envpool.gfootball", spec_cls = "FootballEnvSpec", - dm_cls = "FootballDMEnvpool", - gym_cls = "FootballGymEnvpool", -) \ No newline at end of file + env_cls = "FootballEnvpool", +) From 8e957e4df8dfbc8759502f95df34b7425af7b2c0 Mon Sep 17 00:00:00 2001 From: kfq2002 <95134838+kfq2002@users.noreply.github.com> Date: Wed, 10 Aug 2022 21:58:23 +0800 Subject: [PATCH 15/28] Update registration.py --- envpool/gfootball/registration.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/envpool/gfootball/registration.py b/envpool/gfootball/registration.py index 0ffbe081..b41b7454 100644 --- a/envpool/gfootball/registration.py +++ b/envpool/gfootball/registration.py @@ -4,5 +4,6 @@ task_id = "football", import_path = "envpool.gfootball", spec_cls = "FootballEnvSpec", - env_cls = "FootballEnvpool", + dm_cls = "FootballDMEnvpool", + gym_cls = "FootballGymEnvpool", ) From 7592e911e057264663eea13c483ed2e9b188b477 Mon Sep 17 00:00:00 2001 From: kfq2002 <95134838+kfq2002@users.noreply.github.com> Date: Wed, 10 Aug 2022 21:59:44 +0800 Subject: [PATCH 16/28] Update BUILD --- envpool/BUILD | 2 ++ 1 file changed, 2 insertions(+) diff --git a/envpool/BUILD b/envpool/BUILD index cb901f28..130ae254 100644 --- a/envpool/BUILD +++ b/envpool/BUILD @@ -23,6 +23,7 @@ py_library( "//envpool/mujoco:mujoco_gym_registration", "//envpool/toy_text:toy_text_registration", "//envpool/vizdoom:vizdoom_registration", + "//envpool/football:football_registration", ], ) @@ -35,6 +36,7 @@ py_library( "//envpool/atari", "//envpool/box2d", "//envpool/classic_control", + "//envpool/football", "//envpool/mujoco:mujoco_dmc", "//envpool/mujoco:mujoco_gym", "//envpool/python", From 05191ff8258240afb5d5f353b086c754ea03a6c0 Mon Sep 17 00:00:00 2001 From: kfq2002 <95134838+kfq2002@users.noreply.github.com> Date: Wed, 10 Aug 2022 22:00:04 +0800 Subject: [PATCH 17/28] Update entry.py --- envpool/entry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/envpool/entry.py b/envpool/entry.py index 453c6d00..3f20b690 100644 --- a/envpool/entry.py +++ b/envpool/entry.py @@ -20,4 +20,4 @@ import envpool.mujoco.gym.registration # noqa: F401 import envpool.toy_text.registration # noqa: F401 import envpool.vizdoom.registration # noqa: F401 -import envpool.gfootball.registration +import envpool.football.registration From 54ada45655538ac60e48aa3f69f49ecdbd45084b Mon Sep 17 00:00:00 2001 From: kfq2002 <95134838+kfq2002@users.noreply.github.com> Date: Wed, 10 Aug 2022 22:01:33 +0800 Subject: [PATCH 18/28] Update workspace0.bzl --- envpool/workspace0.bzl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/envpool/workspace0.bzl b/envpool/workspace0.bzl index 731aeeea..3d59207d 100644 --- a/envpool/workspace0.bzl +++ b/envpool/workspace0.bzl @@ -390,12 +390,12 @@ def workspace(): maybe( http_archive, - name = "football", - sha256 = "", + name = "gfootball_engine", + sha256 = "1b0fdcfa78b7fadc3730585ee7f0f412ba825c27e422b2b85ea0cf7ba57800b6", urls = [ "https://files.pythonhosted.org/packages/98/63/b111538b5db47b8081d8ca82280fadaa145fbd31aa249f49675a01abb8eb/gfootball-2.10.2.tar.gz" ], - build_file = "//third_party/gfootball:gfootball.BUILD", + build_file = "//third_party/football:football.BUILD", ) maybe( From c3e1e0f038ecce4c9cdcfea6b7718a47685c302e Mon Sep 17 00:00:00 2001 From: kfq2002 <95134838+kfq2002@users.noreply.github.com> Date: Fri, 19 Aug 2022 11:21:32 +0800 Subject: [PATCH 19/28] Update BUILD --- envpool/gfootball/BUILD | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/envpool/gfootball/BUILD b/envpool/gfootball/BUILD index 414b6a0f..7c26224c 100644 --- a/envpool/gfootball/BUILD +++ b/envpool/gfootball/BUILD @@ -45,7 +45,16 @@ pybind_extension( py_library( name = "football", srcs = ["__init__.py"], - deps = ["//envpool/python:api"] + data = [":football_envpool.so"], + deps = ["//envpool/python:api"], +) + +py_library( + name = "football_registration", + srcs = ["registration.py"], + deps = [ + "//envpool:registration", + ], ) py_test( From 3d7b359ce15c1d6b895c57d330cf0b94fec864dc Mon Sep 17 00:00:00 2001 From: kfq2002 <95134838+kfq2002@users.noreply.github.com> Date: Fri, 19 Aug 2022 11:22:34 +0800 Subject: [PATCH 20/28] Update config.h --- envpool/gfootball/config.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/envpool/gfootball/config.h b/envpool/gfootball/config.h index 9b52cff4..a808918f 100644 --- a/envpool/gfootball/config.h +++ b/envpool/gfootball/config.h @@ -1,3 +1,6 @@ +#ifndef ENVPOOL_FOOTBALL_CONFIG_H_ +#define ENVPOOL_FOOTBALL_CONFIG_H_ + #include #include #include @@ -27,7 +30,9 @@ class Config{ Config(); void NewScenario(int inc = 1){ this->episode_number += inc; - ScenarioConfig scenario_config; + auto scenario_config = ScenarioConfig::make(); }; }; + +#endif // ENVPOOL_FOOTBALL_CONFIG_H_ From 4fdd1cd4d80607a85183023dbc59f83f705b7baf Mon Sep 17 00:00:00 2001 From: kfq2002 <95134838+kfq2002@users.noreply.github.com> Date: Fri, 19 Aug 2022 11:23:25 +0800 Subject: [PATCH 21/28] Update football_action_set.h --- envpool/gfootball/football_action_set.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/envpool/gfootball/football_action_set.h b/envpool/gfootball/football_action_set.h index b411456f..b7abcad1 100644 --- a/envpool/gfootball/football_action_set.h +++ b/envpool/gfootball/football_action_set.h @@ -1,3 +1,6 @@ +#ifndef ENVPOOL_FOOTBALL_ACTION_SET_H_ +#define ENVPOOL_FOOTBALL_ACTION_SET_H_ + #include #include "config.h" #include "game_env.hpp" @@ -53,4 +56,6 @@ CoreAction action_release_pressure(Action::game_release_pressure, "release_press CoreAction action_release_team_pressure(Action::game_release_team_pressure, "release_team_pressure"); CoreAction action_release_switch(Action::game_release_switch, "release_switch"); CoreAction action_release_sprint(Action::game_release_sprint, "release_sprint"); -CoreAction action_release_dribble(Action::game_release_dribble, "release_dribble"); \ No newline at end of file +CoreAction action_release_dribble(Action::game_release_dribble, "release_dribble"); + +#endif //ENVPOOL_FOOTBALL_ACTION_SET_H_ From a9ced8daede51d3c582a9dd556dcf9c20bf237e4 Mon Sep 17 00:00:00 2001 From: kfq2002 <95134838+kfq2002@users.noreply.github.com> Date: Fri, 19 Aug 2022 11:37:47 +0800 Subject: [PATCH 22/28] Update football_env.h --- envpool/gfootball/football_env.h | 158 ++++++++++++++++++------------- 1 file changed, 92 insertions(+), 66 deletions(-) diff --git a/envpool/gfootball/football_env.h b/envpool/gfootball/football_env.h index 641bcee6..cb91118a 100644 --- a/envpool/gfootball/football_env.h +++ b/envpool/gfootball/football_env.h @@ -1,3 +1,6 @@ +#ifndef ENVPOOL_FOOTBALL_ENV_H_ +#define ENVPOOL_FOOTBALL_ENV_H_ + #include #include #include @@ -11,15 +14,17 @@ namespace football{ class FootballEnvFns { public: - static char *tracesdir_pre_char; - static std::string tracesdir_pre; - static std::string tracesdir; + //static char *tracesdir_pre_char; + //static std::string tracesdir_pre; + //static std::string tracesdir; static decltype(auto) DefaultConfig(){ return MakeDict( "action_set"_.Bind(std::string("default")), "custom_display_stats"_.Bind(std::vector{}), "display_game_stats"_.Bind(true), "dump_full_episodes"_.Bind(false), "dump_scores"_.Bind(false), "players"_.Bind(std::vector{"agent:left_players=1"}), "level"_.Bind(std::string("11_vs_11_stochastic")), "physics_steps_per_frame"_.Bind(10), "render_resolution_x"_.Bind(1280), - "render_resolution_y"_.Bind(1280 * 0.5625), "real_time"_.Bind(false), "tracesdir"_.Bind(tracesdir), "video_format"_.Bind(std::string("avi")), + "render_resolution_y"_.Bind(1280 * 0.5625), "real_time"_.Bind(false), + //"tracesdir"_.Bind(tracesdir), + "video_format"_.Bind(std::string("avi")), "video_quality_level"_.Bind(0), "write_video"_.Bind(false) ); } @@ -42,14 +47,45 @@ class FootballEnvFns { ); } FootballEnvFns(){ - tracesdir_pre_char = getcwd(NULL, 0); - tracesdir_pre = tracesdir_pre_char; - tracesdir = tracesdir_pre + "/dump"; + //tracesdir_pre_char = getcwd(NULL, 0); + //tracesdir_pre = tracesdir_pre_char; + //tracesdir = tracesdir_pre + "/dump"; } }; using FootballEnvSpec = EnvSpec; +struct observation{ + int num_players = 11; + std::vector left_agent_controlled_player = std::vector(1); + std::vector right_agent_controlled_player = std::vector(1); + std::vector left_team = std::vector(num_players * 2); + std::vector left_team_roles = std::vector(num_players); + std::vector left_team_direction = std::vector(num_players * 2); + std::vector left_team_tired_factor = std::vector(num_players); + std::vector left_team_yellow_card = std::vector(num_players); + std::vector left_team_active = std::vector(1); + int left_team_designated_player = 0; + std::vector right_team = std::vector(num_players * 2); + std::vector right_team_roles = std::vector(num_players); + std::vector right_team_direction = std::vector(num_players * 2); + std::vector right_team_tired_factor = std::vector(num_players); + std::vector right_team_yellow_card = std::vector(num_players); + std::vector right_team_active = std::vector(1); + int right_team_designated_player = 0; + std::vector ball = {0, 0, 0}; + std::vector ball_direction = std::vector(3); + std::vector ball_rotation = std::vector(3); + int ball_owned_team = 0; + int ball_owned_player = 0; + int game_mode = 0; + std::vector left_agent_sticky_actions = std::vector(num_players); + std::vector right_agent_sticky_actions = std::vector(num_players); + std::vector score = std::vector(2); + int steps_left = 0; + observation(){}; +}; + struct FootballEnvState{ int previous_score_diff = 0; int previous_game_mode = -1; @@ -63,77 +99,65 @@ class FootballEnv : public Env { int prev_ball_owned_team = -1; public: - std::string action_set_name; - std::string custom_display_stats; - bool display_game_stats; - bool dump_full_episodes; - bool dump_scores; - std::vectorplayers; - std::string level; - bool real_time;; - std::string tracesdir; - std::string video_format; - int video_quality_level; - bool write_video; + std::string action_set_name_; + std::string custom_display_stats_; + bool display_game_stats_; + bool dump_full_episodes_; + bool dump_scores_; + std::vectorplayers_; + std::string level_; + bool real_time_; + //std::string tracesdir_; + std::string video_format_; + int video_quality_level_; + bool write_video_; int episode_number = 0; - ScenarioConfig scenario_config; + boost::shared_ptr scenario_config = ScenarioConfig::make(); GameContext* context = nullptr; - GameConfig game_config; + boost::shared_ptr game_config = GameConfig::make(); GameState state = game_created; int waiting_for_game_count = 0; GameEnv env_; - int physics_steps_per_frame; - int render_resolution_x; - int render_resolution_y; - FootballEnvState state; + int physics_steps_per_frame_; + int render_resolution_x_; + int render_resolution_y_; int steps_time = 0; int step_count = 0; int _step = 0; clock_t episode_start = clock(); std::vector action_set; float cumulative_reward = 0; - using Observation = decltype(MakeDict( - "left_team"_.Bind(std::vector(22)), "left_team_roles"_.Bind(std::vector(11)), "left_team_direction"_.Bind(std::vector(22)), - "left_team_tired_factor"_.Bind(std::vector(11)), "left_team_yellow_card"_.Bind(std::vector(11)), "left_team_active"_.Bind(std::vector{0}), - "left_team_designated_player"_.Bind(3), "right_team"_.Bind(std::vector(22)), "right_team_roles"_.Bind(std::vector(11)), - "right_team_direction"_.Bind(std::vector(22)), "right_team_tired_factor"_.Bind(std::vector(11)), "right_team_yellow_card"_.Bind(std::vector(11)), - "right_team_active"_.Bind(std::vector{0}), "right_team_designated_player"_.Bind(0), "ball"_.Bind(std::vector{0 , 0 , 0}), - "ball_direction"_.Bind(std::vector(3)), "ball_rotation"_.Bind(std::vector(3)), "ball_owned_team"_.Bind(0), - "ball_owned_player"_.Bind(7), "left_agent_controlled_player"_.Bind(std::vector{4}), "right_agent_controlled_player"_.Bind(std::vector{6}), - "game_mode"_.Bind(0), "left_agent_sticky_actions"_.Bind(std::vector(2)), "right_agent_sticky_actions"_.Bind(std::vector(2)), - "score"_.Bind(std::vector{3, 5}), "steps_left"_.Bind(45) - )); - Observation observation; FootballEnv(const Spec& spec, int env_id) : Env(spec, env_id), env_(GameEnv::GameEnv()), - action_set_name(spec.config["action_set"]), - physics_steps_per_frame(spec.config["physics_steps_per_frame"]), - render_resolution_x(spec.config["render_resolution_x"]), - render_resolution_y(spec.config["render_resolution_y"]), - custom_display_stats(spec.config["custom_display_stats"]), - display_game_stats(spec.config["display_game_stats"]), - dump_full_episodes(spec.config["dump_full_episodes"]), - dump_scores(spec.config["dump_scores"]), - players(spec.config["players"]), - level(spec.config["level"]), - real_time(spec.config["real_time"]), - tracesdir(spec.config["tracesdir"]), - video_format(spec.config["video_format"]), - video_quality_level(spec.config["video_quality_level"]), - write_video(spec.config["write_video"]) + action_set_name(spec.config["action_set"_]), + physics_steps_per_frame(spec.config["physics_steps_per_frame"_]), + render_resolution_x(spec.config["render_resolution_x"_]), + render_resolution_y(spec.config["render_resolution_y"_]), + custom_display_stats(spec.config["custom_display_stats"_]), + display_game_stats(spec.config["display_game_stats"_]), + dump_full_episodes(spec.config["dump_full_episodes"_]), + dump_scores(spec.config["dump_scores"_]), + players(spec.config["players"_]), + level(spec.config["level"_]), + real_time(spec.config["real_time"_]), + //tracesdir(spec.config["tracesdir"_]), + video_format(spec.config["video_format"_]), + video_quality_level(spec.config["video_quality_level"_]), + write_video(spec.config["write_video"_]) {}; - void Step(std::vectoraction){ + void Step(const Action& action){ + observation obs; step_count += 1; int action_index = 0; std::vector controlled_players; for(int left_team = 1; left_team > 0; left_team++){ auto agents = env_.config().left_agents; for(int j = 0; j < agents; j++){ - auto player_action_index = action[action_index]; + auto player_action_index = action["action"_][action_index]; CoreAction player_action = action_idle; switch (player_action_index) { @@ -245,12 +269,12 @@ class FootballEnv : public Env { else if(env_.waiting_for_game_count > 20){ player_action = action_idle; if(left_team == 0){ - controlled_players = observation["left_agent_controlled_player"]; + controlled_players = obs.left_agent_controlled_player; } else{ - controlled_players = observation["right_agent_controlled_player"]; + controlled_players = obs.right_agent_controlled_player; } - if (observation["ball_owned_team"] != -1 && controlled_players[j] == observation["ball_owned_player"] && ~(left_team ^ observation["ball_owned_team"])){ + if (obs.ball_owned_team != -1 && controlled_players[j] == obs.ball_owned_player && !(left_team ^ obs.ball_owned_team)){ if(bool(env_.waiting_for_game_count < 30) != bool(left_team)){ player_action = action_left; } @@ -273,33 +297,33 @@ class FootballEnv : public Env { } if(env_.config().end_episode_on_score){ - if(observation["score"][0] > 0 || observation["score"][1] > 0){ + if(obs.score[0] > 0 || obs.score[1] > 0){ env_.state = GameState::game_done; } } - if(env_.config().end_episode_on_out_of_play && observation["game_mode"] != int(e_GameMode::e_GameMode_Normal) && previous_game_mode == int(e_GameMode::e_GameMode_Normal)){ + if(env_.config().end_episode_on_out_of_play && obs.game_mode != int(e_GameMode::e_GameMode_Normal) && previous_game_mode == int(e_GameMode::e_GameMode_Normal)){ env_.state = GameState::game_done; } - previous_game_mode = observation["game_mode"]; + previous_game_mode = obs.game_mode; if(env_.config().end_episode_on_possession_change && - observation["ball_owned_team"] != -1 && + obs.ball_owned_team != -1 && prev_ball_owned_team != -1 && - observation["ball_owned_team"] != prev_ball_owned_team){ + obs.ball_owned_team != prev_ball_owned_team){ env_.state = GameState::game_done; } - if(observation["ball_owned_team"] != -1){ - prev_ball_owned_team = observation["ball_owned_team"]; + if(obs.ball_owned_team != -1){ + prev_ball_owned_team = obs.ball_owned_team; } - int score_diff = observation["score"][0] - observation["score"][1]; + int score_diff = obs.score[0] - obs.score[1]; int reward = score_diff - previous_score_diff; previous_score_diff = score_diff; if(reward == 1){ } - if(observation["game_mode"] != int(e_GameMode::e_GameMode_Normal)){ + if(obs.game_mode != int(e_GameMode::e_GameMode_Normal)){ env_.waiting_for_game_count += 1; } else{ @@ -415,3 +439,5 @@ class FootballEnv : public Env { using FootballEnvPool = AsyncEnvPool; } + +#endif //#ifndef ENVPOOL_FOOTBALL_ENV_H_ From 1a357cb8d685731a9ab78b4dc2f7f98c1f9429f8 Mon Sep 17 00:00:00 2001 From: kfq2002 <95134838+kfq2002@users.noreply.github.com> Date: Fri, 19 Aug 2022 11:43:20 +0800 Subject: [PATCH 23/28] Update football_env_test.cc --- envpool/gfootball/football_env_test.cc | 32 ++++++++++++++------------ 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/envpool/gfootball/football_env_test.cc b/envpool/gfootball/football_env_test.cc index 9660f660..5ab833f0 100644 --- a/envpool/gfootball/football_env_test.cc +++ b/envpool/gfootball/football_env_test.cc @@ -21,19 +21,21 @@ using FootballState = football::FootballEnv::State; using FootballAction = football::FootballEnv::Action; -auto config = football::FootballEnvSpec::kDefaultConfig; -std::size_t batch = 4; -int num_envs = 4; -config["num_envs"_] = batch; -config["batch_size"_] = batch; -config["seed"_] = 0; -int total_iter = 10000; -football::FootballEnvSpec spec(config); -football::FootballEnvPool envpool(spec); -Array all_env_ids(Spec({num_envs})); -for (int i = 0; i < num_envs; ++i) { - all_env_ids[i] = i; +int main(int argc, char** argv){ + auto config = football::FootballEnvSpec::kDefaultConfig; + int batch = 4; + int num_envs = 4; + config["num_envs"_] = batch; + config["batch_size"_] = batch; + config["seed"_] = 0; + int total_iter = 10000; + football::FootballEnvSpec spec(config); + football::FootballEnvPool envpool(spec); + Array all_env_ids(Spec({num_envs})); + for (int i = 0; i < num_envs; ++i) { + all_env_ids[i] = i; + } + envpool.Reset(all_env_ids); + auto state_vec = envpool.Recv(); + FootballState state(&state_vec); } -envpool.Reset(all_env_ids); -auto state_vec = envpool.Recv(); -FootballState state(&state_vec); From bc364750c7b74aa03405f5abef44304a79d7283f Mon Sep 17 00:00:00 2001 From: kfq2002 <95134838+kfq2002@users.noreply.github.com> Date: Fri, 19 Aug 2022 15:22:49 +0800 Subject: [PATCH 24/28] Update config.h --- envpool/gfootball/config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/envpool/gfootball/config.h b/envpool/gfootball/config.h index a808918f..c6bec683 100644 --- a/envpool/gfootball/config.h +++ b/envpool/gfootball/config.h @@ -27,7 +27,7 @@ class Config{ int video_quality_level = 0; bool write_video = false; int episode_number = 0; - Config(); + Config(){ }; void NewScenario(int inc = 1){ this->episode_number += inc; auto scenario_config = ScenarioConfig::make(); From a9b72a154877aae3ab2661d20e8f37bda1f324a2 Mon Sep 17 00:00:00 2001 From: kfq2002 <95134838+kfq2002@users.noreply.github.com> Date: Fri, 19 Aug 2022 15:24:38 +0800 Subject: [PATCH 25/28] Update football_env.h --- envpool/gfootball/football_env.h | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/envpool/gfootball/football_env.h b/envpool/gfootball/football_env.h index cb91118a..c6935aec 100644 --- a/envpool/gfootball/football_env.h +++ b/envpool/gfootball/football_env.h @@ -148,14 +148,13 @@ class FootballEnv : public Env { {}; - void Step(const Action& action){ observation obs; step_count += 1; int action_index = 0; std::vector controlled_players; for(int left_team = 1; left_team > 0; left_team++){ - auto agents = env_.config().left_agents; + auto agents = env_.scenario_config.left_agents; for(int j = 0; j < agents; j++){ auto player_action_index = action["action"_][action_index]; CoreAction player_action = action_idle; @@ -296,18 +295,18 @@ class FootballEnv : public Env { } } - if(env_.config().end_episode_on_score){ + if(env_.scenario_config.end_episode_on_score){ if(obs.score[0] > 0 || obs.score[1] > 0){ env_.state = GameState::game_done; } } - if(env_.config().end_episode_on_out_of_play && obs.game_mode != int(e_GameMode::e_GameMode_Normal) && previous_game_mode == int(e_GameMode::e_GameMode_Normal)){ + if(env_.scenario_config.end_episode_on_out_of_play && obs.game_mode != int(e_GameMode::e_GameMode_Normal) && previous_game_mode == int(e_GameMode::e_GameMode_Normal)){ env_.state = GameState::game_done; } previous_game_mode = obs.game_mode; - if(env_.config().end_episode_on_possession_change && + if(env_.scenario_config.end_episode_on_possession_change && obs.ball_owned_team != -1 && prev_ball_owned_team != -1 && obs.ball_owned_team != prev_ball_owned_team){ @@ -329,7 +328,7 @@ class FootballEnv : public Env { else{ env_.waiting_for_game_count = 0; } - if(_step >= env_.config().game_duration){ + if(_step >= env_.scenario_config.game_duration){ env_.state = GameState::game_done; } From 8d78de3dd73b493b0d513a04b9d3836735567ebd Mon Sep 17 00:00:00 2001 From: kfq2002 Date: Thu, 1 Sep 2022 07:37:00 +0000 Subject: [PATCH 26/28] 0901 --- envpool/{gfootball => football}/BUILD | 0 envpool/{gfootball => football}/__init__.py | 0 envpool/{gfootball => football}/config.h | 0 .../football_action_set.h | 0 envpool/football/football_env.h | 834 ++++++++++++++++++ .../football_env_test.cc | 0 .../football_envpool.cc | 0 .../football_envpool_test.py | 0 .../{gfootball => football}/registration.py | 0 envpool/gfootball/football_env.h | 442 ---------- 10 files changed, 834 insertions(+), 442 deletions(-) rename envpool/{gfootball => football}/BUILD (100%) rename envpool/{gfootball => football}/__init__.py (100%) rename envpool/{gfootball => football}/config.h (100%) rename envpool/{gfootball => football}/football_action_set.h (100%) create mode 100644 envpool/football/football_env.h rename envpool/{gfootball => football}/football_env_test.cc (100%) rename envpool/{gfootball => football}/football_envpool.cc (100%) rename envpool/{gfootball => football}/football_envpool_test.py (100%) rename envpool/{gfootball => football}/registration.py (100%) delete mode 100644 envpool/gfootball/football_env.h diff --git a/envpool/gfootball/BUILD b/envpool/football/BUILD similarity index 100% rename from envpool/gfootball/BUILD rename to envpool/football/BUILD diff --git a/envpool/gfootball/__init__.py b/envpool/football/__init__.py similarity index 100% rename from envpool/gfootball/__init__.py rename to envpool/football/__init__.py diff --git a/envpool/gfootball/config.h b/envpool/football/config.h similarity index 100% rename from envpool/gfootball/config.h rename to envpool/football/config.h diff --git a/envpool/gfootball/football_action_set.h b/envpool/football/football_action_set.h similarity index 100% rename from envpool/gfootball/football_action_set.h rename to envpool/football/football_action_set.h diff --git a/envpool/football/football_env.h b/envpool/football/football_env.h new file mode 100644 index 00000000..64842999 --- /dev/null +++ b/envpool/football/football_env.h @@ -0,0 +1,834 @@ +#ifndef ENVPOOL_FOOTBALL_ENV_H_ +#define ENVPOOL_FOOTBALL_ENV_H_ +#include +#include +#include +#include +#include "game_env.hpp" +#include "config.h" +#include "football_action_set.h" +#include "envpool/core/async_envpool.h" +#include "envpool/core/env.h" +#include "player.h" + +int SMM_WIDTH = 96; +int SMM_HEIGHT = 72; +float MINIMAP_NORM_X_MIN = -1.0; +float MINIMAP_NORM_X_MAX = 1.0; +float MINIMAP_NORM_Y_MIN = -1.0 / 2.25; +float MINIMAP_NORM_Y_MAX = 1.0 / 2.25; +int _MARKER_VALUE = 255; + +class FootballEnvCore; +class FootballEnvFns; +class PreFootballEnv; + +std::vectorSMM_LAYERS = {"left_team", "right_team", "ball", "active"}; + +namespace football{ + +class FootballEnvFns { + public: + //static char *tracesdir_pre_char; + //static std::string tracesdir_pre; + //static std::string tracesdir; + static decltype(auto) DefaultConfig(){ + return MakeDict( + "env_name"_.Bind(std::string("")), + "stacked"_.Bind(false), + "representation"_.Bind(std::string("extracted")), + "rewards"_.Bind(std::string("scoring")), + "write_goal_dumps"_.Bind(false), + "write_full_episode_dumps"_.Bind(false), + "render"_.Bind(false), + "write_video"_.Bind(false), + "dump_frequency"_.Bind(1), + "extra_players"_.Bind(0), + "number_of_left_players_agent_controls"_.Bind(1), + "number_of_right_players_agent_controls"_.Bind(0), + "channel_dimensions"_.Bind(std::vector{SMM_WIDTH, SMM_HEIGHT}) + ); + } + + template + static decltype(auto) StateSpec(const Config& conf) { + if(conf["representation"_] == "extracted" && conf["stacked"_] == false){ + return MakeDict( + "obs"_.Bind(Spec({72, 96, 4}, {0, 255})), + "info:episode_reward"_.Bind(Spec({})), + "info:score"_.Bind(Spec({2})), + "info:steps"_.Bind(Spec({})), + "info:FPS"_.Bind(Spec({})), + "info:gameFPS"_.Bind(Spec({})) + ); + } + else if(conf["representation"_] == "extracted" && conf["stacked"_] == true){ + return MakeDict( + "obs"_.Bind(Spec({72, 96, 16}, {0, 255})), + "info:episode_reward"_.Bind(Spec({})), + "info:score"_.Bind(Spec({2})), + "info:steps"_.Bind(Spec({})), + "info:FPS"_.Bind(Spec({})), + "info:gameFPS"_.Bind(Spec({})) + ); + } + else if(conf["representation"_] == "pixels" && conf["stacked"_] == false){ + return MakeDict( + "obs"_.Bind(Spec({72, 96, 3}, {0, 255})), + "info:episode_reward"_.Bind(Spec({})), + "info:score"_.Bind(Spec({2})), + "info:steps"_.Bind(Spec({})), + "info:FPS"_.Bind(Spec({})), + "info:gameFPS"_.Bind(Spec({})) + ); + } + else if(conf["representation"_] == "pixels" && conf["stacked"_] == true){ + return MakeDict( + "obs"_.Bind(Spec({72, 96, 12}, {0, 255})), + "info:episode_reward"_.Bind(Spec({})), + "info:score"_.Bind(Spec({2})), + "info:steps"_.Bind(Spec({})), + "info:FPS"_.Bind(Spec({})), + "info:gameFPS"_.Bind(Spec({})) + ); + } + else if(conf["representation"_] == "pixels_gray" && conf["stacked"_] == false){ + return MakeDict( + "obs"_.Bind(Spec({72, 96, 1}, {0, 255})), + "info:episode_reward"_.Bind(Spec({})), + "info:score"_.Bind(Spec({2})), + "info:steps"_.Bind(Spec({})), + "info:FPS"_.Bind(Spec({})), + "info:gameFPS"_.Bind(Spec({})) + ); + } + else if(conf["representation"_] == "pixels_gray" && conf["stacked"_] == true){ + return MakeDict( + "obs"_.Bind(Spec({72, 96, 4}, {0, 255})), + "info:episode_reward"_.Bind(Spec({})), + "info:score"_.Bind(Spec({2})), + "info:steps"_.Bind(Spec({})), + "info:FPS"_.Bind(Spec({})), + "info:gameFPS"_.Bind(Spec({})) + ); + } + else if(conf["representation"_] == "simple115" || conf["representation"_] == "simple115v2"){ + return MakeDict( + "obs"_.Bind(Spec({115})), + "info:episode_reward"_.Bind(Spec({})), + "info:score"_.Bind(Spec({2})), + "info:steps"_.Bind(Spec({})), + "info:FPS"_.Bind(Spec({})), + "info:gameFPS"_.Bind(Spec({})) + ); + } + } + template + static decltype(auto) ActionSpec(const Config& conf) { + Config_football c; + int num_actions = get_action_set(c).size(); + int number_of_players_agent_controls = conf.number_of_left_players_agent_controls + conf.number_of_right_players_agent_controls + conf.extra_players; + if(number_of_players_agent_controls > 1){ + return MakeDict( + "action"_.Bind(Spec({number_of_players_agent_controls}, {0, num_actions})) + ); + } + return MakeDict( + "action"_.Bind(Spec({}, {0, num_actions})) + ); + } + + FootballEnvFns(){ + } +}; + +using FootballEnvSpec = EnvSpec; + +struct Observation{ + std::vector ball = {0, 0, 0}; + std::vector ball_direction = std::vector(3); + std::vector ball_rotation = std::vector(3); + int ball_owned_team = 0; + int ball_owned_player = 0; + int game_mode = 0; + + std::vector > left_team = std::vector >(11, std::vector(2)); + std::vector left_team_roles = std::vector(11); + std::vector > left_team_direction = std::vector >(11, std::vector(2)); + std::vector left_team_tired_factor = std::vector(11); + std::vector left_team_yellow_card = std::vector(11); + std::vector left_team_active = std::vector(11); + int left_team_designated_player = 0; + + std::vector > right_team = std::vector >(11, std::vector(2)); + std::vector right_team_roles = std::vector(11); + std::vector > right_team_direction = std::vector >(11, std::vector(2)); + std::vector right_team_tired_factor = std::vector(11); + std::vector right_team_yellow_card = std::vector(11); + std::vector right_team_active = std::vector(11); + int right_team_designated_player = 0; + + std::vector left_agent_controlled_player = std::vector(1); + std::vector right_agent_controlled_player = std::vector(0); + std::vector > left_agent_sticky_actions = std::vector >(1, std::vector(10)); + std::vector > right_agent_sticky_actions = std::vector >(1, std::vector(10)); + std::vector score = std::vector(2); + int steps_left = 0; + Observation(){}; +}; + +struct ConvertObservations : Observation{ + int designated = 0; + int active = -1; + std::vectorsticky_actions = {}; +}; + +struct FootballEnvState{ + int previous_score_diff = 0; + int previous_game_mode = -1; + int prev_ball_owned_team = -1; + FootballEnvState(){}; +}; + +class FootballEnvCore{ + public: + Config_football _config; + Observation _observation; + std::vector _sticky_actions; + std::vector _action_set = {}; + clock_t _episode_start = 0; + clock_t _steps_time = 0; + bool _use_rendering_engine; + int _cumulative_reward = 0; + int _step_count = 0; + int _step = 0; + int reward = 0; + float _fps = 0; + float _game_fps = 0; + bool _episode_done = false; + FootballEnvState _state = FootballEnvState(); + GameEnv _env; + FootballEnvCore(Config_football config){ + _config = config; + _sticky_actions = get_sticky_actions(config); + _use_rendering_engine = false; + _env = _get_new_env(); + reset(0); + + } + GameEnv _get_new_env(){ + auto env = GameEnv(); + env.game_config.physics_steps_per_frame = _config.physics_steps_per_frame; + env.game_config.render_resolution_x = _config.render_resolution_x; + env.game_config.render_resolution_y = _config.render_resolution_y; + return env; + } + + bool reset(int inc = 1){ + _episode_start = clock(); + _action_set = get_action_set(_config); + _cumulative_reward = 0; + _step_count = 0; + _reset(_env.game_config.render, inc); + if(!_retrieve_observation()){ + _env.step(); + } + return true; + } + + void _reset(bool animations, int inc) { + if(_env.state == GameState::game_created){ + _env.start_game(); + } + _env.state = GameState::game_running; + auto scenario_config = ScenarioConfig::make(); + _env.reset(*scenario_config, animations); + }; + + bool _retrieve_observation(){ + int i = 0; + auto info = _env.get_info(); + _observation.ball = {info.ball_position.value[0], info.ball_position.value[1], info.ball_position.value[2]}; + _observation.ball_direction = {info.ball_direction.value[0], info.ball_direction.value[1], info.ball_direction.value[2]}; + _observation.ball_rotation = {info.ball_rotation.value[0], info.ball_rotation.value[1], info.ball_rotation.value[2]}; + int left_players_num = info.left_team.size(); + int right_players_num = info.right_team.size(); + std::vector >left_team(left_players_num, std::vector(2)); + std::vector >right_team(right_players_num, std::vector(2)); + std::vectortemp; + std::vector >left_team_direction(left_players_num, std::vector(2)); + std::vector >right_team_direction(right_players_num, std::vector(2)); + std::vectorleft_team_tired_factor; + std::vectorright_team_tired_factor; + std::vectorleft_team_active; + std::vectorright_team_active; + std::vectorleft_team_yellow_card; + std::vectorright_team_yellow_card; + std::vectorleft_team_roles; + std::vectorright_team_roles; + int left_designated_player = -1; + int right_designated_player = -1; + int left_team_designated_player; + int right_team_designated_player; + for(i = 0; i < left_players_num; i++){ + temp.push_back(info.left_team[i].player_position.value[0]); + temp.push_back(info.left_team[i].player_position.value[1]); + left_team.push_back(temp); + temp.clear(); + temp.push_back(info.left_team[i].player_direction.value[0]); + temp.push_back(info.left_team[i].player_direction.value[1]); + left_team_direction.push_back(temp); + temp.clear(); + left_team_tired_factor.push_back(info.left_team[i].tired_factor); + left_team_active.push_back(info.left_team[i].is_active); + left_team_yellow_card.push_back(info.left_team[i].has_card); + left_team_roles.push_back(info.left_team[i].role); + if(info.left_team[i].designated_player){ + left_designated_player = i; + } + } + left_team_designated_player = left_designated_player; + _observation.left_team.resize(left_players_num); + _observation.left_team_direction.resize(left_players_num); + _observation.left_team_tired_factor.resize(left_players_num); + _observation.left_team_active.resize(left_players_num); + _observation.left_team_yellow_card.resize(left_players_num); + _observation.left_team_roles.resize(left_players_num); + _observation.left_team = left_team; + _observation.left_team_direction = left_team_direction; + _observation.left_team_tired_factor = left_team_tired_factor; + _observation.left_team_active = left_team_active; + _observation.left_team_yellow_card = left_team_yellow_card; + _observation.left_team_roles = left_team_roles; + _observation.left_team_designated_player = left_team_designated_player; + + for(i = 0; i < right_players_num; i++){ + temp.push_back(info.right_team[i].player_position.value[0]); + temp.push_back(info.right_team[i].player_position.value[1]); + right_team.push_back(temp); + temp.clear(); + temp.push_back(info.right_team[i].player_direction.value[0]); + temp.push_back(info.right_team[i].player_direction.value[1]); + right_team_direction.push_back(temp); + temp.clear(); + right_team_tired_factor.push_back(info.right_team[i].tired_factor); + right_team_active.push_back(info.right_team[i].is_active); + right_team_yellow_card.push_back(info.right_team[i].has_card); + right_team_roles.push_back(info.right_team[i].role); + if(info.right_team[i].designated_player){ + right_designated_player = i; + } + } + right_team_designated_player = right_designated_player; + + _observation.right_team.resize(right_players_num); + _observation.right_team_direction.resize(right_players_num); + _observation.right_team_tired_factor.resize(right_players_num); + _observation.right_team_active.resize(right_players_num); + _observation.right_team_yellow_card.resize(right_players_num); + _observation.right_team_roles.resize(right_players_num); + _observation.right_team = right_team; + _observation.right_team_direction = right_team_direction; + _observation.right_team_tired_factor = right_team_tired_factor; + _observation.right_team_active = right_team_active; + _observation.right_team_yellow_card = right_team_yellow_card; + _observation.right_team_roles = right_team_roles; + _observation.right_team_designated_player = right_team_designated_player; + + std::vectorleft_agent_controlled_player; + std::vector >left_agent_sticky_actions; + for(i = 0; i < _env.config().left_agents; i++){ + left_agent_controlled_player.push_back(info.left_controllers[i].controlled_player); + left_agent_sticky_actions.push_back(sticky_actions_state(true, i)); + } + std::vectorright_agent_controlled_player; + std::vector >right_agent_sticky_actions; + for(i = 0; i < _env.config().right_agents; i++){ + right_agent_controlled_player.push_back(info.right_controllers[i].controlled_player); + right_agent_sticky_actions.push_back(sticky_actions_state(false, i)); + } + _observation.left_agent_controlled_player.resize(left_agent_controlled_player.size()); + _observation.left_agent_controlled_player = left_agent_controlled_player; + _observation.right_agent_controlled_player.resize(right_agent_controlled_player.size()); + _observation.right_agent_controlled_player = right_agent_controlled_player; + _observation.left_agent_sticky_actions.resize(left_agent_sticky_actions.size()); + for(int sticky_index = 0; sticky_index < left_agent_sticky_actions.size(); sticky_index++){ + _observation.left_agent_sticky_actions[sticky_index].resize(left_agent_sticky_actions[sticky_index].size()); + } + _observation.left_agent_sticky_actions = left_agent_sticky_actions; + _observation.left_agent_sticky_actions.resize(left_agent_sticky_actions.size()); + for(int sticky_index = 0; sticky_index < right_agent_sticky_actions.size(); sticky_index++){ + _observation.right_agent_sticky_actions[sticky_index].resize(right_agent_sticky_actions[sticky_index].size()); + } + _observation.right_agent_sticky_actions = right_agent_sticky_actions; + _observation.game_mode = int(info.game_mode); + _observation.score = {info.left_goals, info.right_goals}; + _observation.ball_owned_team = info.ball_owned_team; + _observation.ball_owned_player = info.ball_owned_player; + _observation.steps_left = _env.config().game_duration - info.step; + _step = info.step; + return info.is_in_play; + } + + std::vectorsticky_actions_state(bool left_team, int player_id){ + std::vectorresult; + for(int a = 0; a < _sticky_actions.size(); a++){ + result.push_back(int(_env.sticky_actions_state(_sticky_actions[a]._backend_action, left_team, player_id))); + } + return result; + } + + void step(std::vector action){ + std::vectoraction_set; + for(int a = 0; a < action.size(); a++){ + action_set.push_back(named_action_from_action_set(_action_set, action[a])); + } + _step_count += 1; + int action_index = 0; + for(int left_team = 1; left_team >= 0; left_team--){ + int agents = 1; + if(left_team == 1){ + agents = _env.config().left_agents; + } + else{ + agents = _env.config().right_agents; + } + for(int i = 0; i < agents; i++){ + CoreAction player_action = action_set[action_index]; + if(_env.waiting_for_game_count == 20){ + player_action = action_short_pass; + } + else if(_env.waiting_for_game_count > 20){ + player_action = action_idle; + std::vectorcontrolled_players; + if(left_team == 1){ + controlled_players = _observation.left_agent_controlled_player; + } + else{ + controlled_players = _observation.right_agent_controlled_player; + } + if(_observation.ball_owned_team != -1 && _observation.ball_owned_team ^ left_team && controlled_players[i] == _observation.ball_owned_player){ + if((_env.waiting_for_game_count < 30) != left_team){ + player_action = action_left; + } + else{ + player_action = action_right; + } + } + } + action_index += 1; + _env.action(player_action._backend_action, left_team, i); + } + } + while(true){ + clock_t enter_time = clock(); + _env.step(); + _steps_time += clock() - enter_time; + if(_retrieve_observation()){ + break; + } + } + + if(_env.config().end_episode_on_score){ + if(_observation.score[0] > 0 || _observation.score[1] > 0){ + _env.state = GameState::game_done; + } + } + + if(_env.config().end_episode_on_out_of_play && _observation.game_mode != int(e_GameMode::e_GameMode_Normal) && _state.previous_game_mode == int(e_GameMode::e_GameMode_Normal)){ + _env.state = GameState::game_done; + } + _state.previous_game_mode = _observation.game_mode; + + if(_env.config().end_episode_on_possession_change && _observation.ball_owned_team != -1 && _state.prev_ball_owned_team != -1 && _observation.ball_owned_team != _state.prev_ball_owned_team){ + _env.state = GameState::game_done; + } + + if(_observation.ball_owned_team != -1){ + _state.prev_ball_owned_team = _observation.ball_owned_team; + } + + int score_diff = _observation.score[0] - _observation.score[1]; + reward = score_diff - _state.previous_score_diff; + _state.previous_score_diff = score_diff; + if(_observation.game_mode != int(e_GameMode::e_GameMode_Normal)){ + _env.waiting_for_game_count += 1; + } + else{ + _env.waiting_for_game_count = 0; + } + if(_step >= _env.config().game_duration){ + _env.state = GameState::game_done; + } + + _episode_done = _env.state == GameState::game_done; + clock_t end_time = clock(); + _cumulative_reward += reward; + if(_episode_done){ + _fps = _step_count / (end_time - _episode_start); + _game_fps = _step_count / _steps_time; + } + } + + Observation observation(){ + return _observation; + } +}; + +class PreFootballEnv{ + public: + Config_football _config; + PlayerFootball _agent; + int _agent_index = -1; + int _agent_left_position = -1; + int _agent_right_position = -1; + int player_index = 0; + std::vector _players; + FootballEnvCore _env = FootballEnvCore(_config); + int _num_actions = get_action_set(_config).size(); + PreFootballEnv(Config_football cfg){ + _config = cfg; + _players = _construct_players(cfg.players, player_index); + } + std::vector _construct_players(std::vector definitions, int player_config){ + std::vector result; + int left_position = 0; + int right_position = 0; + auto player = PlayerFootball(definitions, _config); + result.push_back(player); + player_config += 1; + _agent = player; + _agent_index = player.num_controlled_players(); + _agent_left_position = left_position; + _agent_right_position = right_position; + left_position += player.num_controlled_left_players(); + right_position += player.num_controlled_right_players(); + return result; + } + std::vector _convert_observations(Observation original, PlayerFootball player, int left_player_position, int right_player_position){ + std::vector observations; + Observation adopted; + adopted = original; + std::string prefix = "left"; + int position = left_player_position; + ConvertObservations o; + for(int x = 0; x < player.num_controlled_left_players(); x++){ + o.ball = adopted.ball; + o.ball_direction = adopted.ball_direction; + o.ball_rotation = adopted.ball_rotation; + o.ball_owned_team = adopted.ball_owned_team; + o.ball_owned_player = adopted.ball_owned_player; + o.left_team = adopted.left_team; + o.left_team_direction = adopted.left_team_direction; + o.left_team_tired_factor = adopted.left_team_tired_factor; + o.left_team_yellow_card = adopted.left_team_yellow_card; + o.left_team_active = adopted.left_team_active; + o.left_team_roles = adopted.left_team_roles; + o.right_team = adopted.right_team; + o.right_team_direction = adopted.right_team_direction; + o.right_team_tired_factor = adopted.right_team_tired_factor; + o.right_team_yellow_card = adopted.right_team_yellow_card; + o.right_team_active = adopted.right_team_active; + o.right_team_roles = adopted.right_team_roles; + o.score = adopted.score; + o.steps_left = adopted.steps_left; + o.game_mode = adopted.game_mode; + o.designated = adopted.left_team_designated_player; + if(position + x >= adopted.left_agent_controlled_player.size()){ + o.active = -1; + o.sticky_actions = {}; + } + else{ + o.active = adopted.left_agent_controlled_player[position + x]; + o.sticky_actions = adopted.left_agent_sticky_actions[position + x]; + } + observations.push_back(o); + } + return observations; + + } + std::vector_get_actions(){ + Observation obs = this->_env.observation(); + std::vectoractions; + int left_player_position = 0; + int right_player_position = 0; + for(int i = 0; i < _players.size(); i++){ + auto adopted_obs = _convert_observations(obs, _players[i], left_player_position, right_player_position); + left_player_position += _players[i].num_controlled_left_players(); + right_player_position += _players[i].num_controlled_right_players(); + auto a = _players[i].take_action(); + int j = 0; + for(j = 0; j < _players[i].num_controlled_left_players(); j++){ + actions.push_back(a[j]); + } + for(; j < _players[i].num_controlled_left_players() + _players[i].num_controlled_right_players()){ + actions.push_back(a[j]); + } + } + return actions; + } + void reset(){ + _env.reset(); + } + void step(std::vectoraction){ + _env.step(_get_actions()); + } + + std::vectorobservation(){ + return _convert_observations(_env.observation(), _agent, _agent_left_position, _agent_right_position); + } + std::vector > > >observation_smm(std::vectorobs, std::vectorchannel_dimensions){ + std::vector > > >frame(obs.size(), std::vector > >(channel_dimensions[1], std::vector >(channel_dimensions[0], std::vector(SMM_LAYERS.size(), 0)))); + for(int i = 0; i < obs.size(); i++){ + for(int j = 0; j < SMM_LAYERS.size(); j++){ + if(SMM_LAYERS[j] == "active"){ + if(obs[i].active == -1){ + continue; + } + std::vectorleft_team_active(2); + left_team_active = obs[i].left_team[obs[i].active]; + int x = int((left_team_active[0] - MINIMAP_NORM_X_MIN) / (MINIMAP_NORM_X_MAX - MINIMAP_NORM_X_MIN) * frame[0][0].size()); + int y = int((left_team_active[1] - MINIMAP_NORM_Y_MIN) / (MINIMAP_NORM_Y_MAX - MINIMAP_NORM_Y_MIN) * frame[0].size()); + x = std::max(0, std::min(int(frame[0][0].size() - 1), x)); + y = std::max(0, std::min(int(frame[0].size() - 1), y)); + frame[i][y][x][j] = _MARKER_VALUE; + } + else if(SMM_LAYERS[j] == "left_team"){ + std::vectorleft_team(obs[i].left_team.size() * obs[i].left_team[0].size()); + for(int m = 0; m < obs[i].left_team.size(); m++){ + for(int n = 0; n < obs[i].left_team[0].size(); n++){ + left_team[m * obs[i].left_team[0].size() + n] = obs[i].left_team[m][n]; + } + } + for(int p = 0; p < (left_team.size() / 2); p++){ + int x = int((left_team[p * 2] - MINIMAP_NORM_X_MIN) / (MINIMAP_NORM_X_MAX - MINIMAP_NORM_X_MIN) * frame[0][0].size()); + int y = int((left_team[p * 2 + 1] - MINIMAP_NORM_Y_MIN) / (MINIMAP_NORM_Y_MAX - MINIMAP_NORM_Y_MIN) * frame[0].size()); + x = std::max(0, std::min(int(frame[0][0].size() - 1), x)); + y = std::max(0, std::min(int(frame[0].size() - 1), y)); + frame[i][y][x][j] = _MARKER_VALUE; + } + } + else if(SMM_LAYERS[j] == "right_team"){ + std::vectorright_team(obs[i].right_team.size() * obs[i].right_team[0].size()); + for(int m = 0; m < obs[i].right_team.size(); m++){ + for(int n = 0; n < obs[i].right_team[0].size(); n++){ + right_team[m * obs[i].right_team[0].size() + n] = obs[i].right_team[m][n]; + } + } + for(int p = 0; p < (right_team.size() / 2); p++){ + int x = int((right_team[p * 2] - MINIMAP_NORM_X_MIN) / (MINIMAP_NORM_X_MAX - MINIMAP_NORM_X_MIN) * frame[0][0].size()); + int y = int((right_team[p * 2 + 1] - MINIMAP_NORM_Y_MIN) / (MINIMAP_NORM_Y_MAX - MINIMAP_NORM_Y_MIN) * frame[0].size()); + x = std::max(0, std::min(int(frame[0][0].size() - 1), x)); + y = std::max(0, std::min(int(frame[0].size() - 1), y)); + frame[i][y][x][j] = _MARKER_VALUE; + } + } + else if(SMM_LAYERS[j] == "ball"){ + for(int p = 0; p < (obs[i].ball.size() / 2); p++){ + int x = int((obs[i].ball[p * 2] - MINIMAP_NORM_X_MIN) / (MINIMAP_NORM_X_MAX - MINIMAP_NORM_X_MIN) * frame[0][0].size()); + int y = int((obs[i].ball[p * 2 + 1] - MINIMAP_NORM_Y_MIN) / (MINIMAP_NORM_Y_MAX - MINIMAP_NORM_Y_MIN) * frame[0].size()); + x = std::max(0, std::min(int(frame[0][0].size() - 1), x)); + y = std::max(0, std::min(int(frame[0].size() - 1), y)); + frame[i][y][x][j] = _MARKER_VALUE; + } + } + } + } + return frame; + } + std::vector > >observation_smm_single_agent(std::vector > > >obs){ + return obs[0]; + } + std::vector >observation_simple115state(std::vectorobs, bool fixed_positions){ + std::vector >final_obs; + std::vectoro; + for(int i = 0; i < obs.size(); i++){ + if(fixed_positions){ + for(int j = 0; j < 4; j++){ + if(j == 0){ + o.insert(o.end(), do_flatten(obs[i].left_team).begin(), do_flatten(obs[i].left_team).end()); + } + else if(j == 1){ + o.insert(o.end(), do_flatten(obs[i].left_team_direction).begin(), do_flatten(obs[i].left_team_direction).end()); + } + else if(j == 2){ + o.insert(o.end(), do_flatten(obs[i].right_team).begin(), do_flatten(obs[i].right_team).end()); + } + else if(j == 3){ + o.insert(o.end(), do_flatten(obs[i].right_team_direction).begin(), do_flatten(obs[i].right_team_direction).end()); + } + if(o.size() < (j + 1) * 22){ + std::vectorzero(((j + 1) * 22 - o.size()), -1); + o.insert(o.end(), zero.begin(), zero.end()); + } + } + } + else{ + o.insert(o.end(), do_flatten(obs[i].left_team).begin(), do_flatten(obs[i].left_team).end()); + o.insert(o.end(), do_flatten(obs[i].left_team_direction).begin(), do_flatten(obs[i].left_team_direction).end()); + o.insert(o.end(), do_flatten(obs[i].right_team).begin(), do_flatten(obs[i].right_team).end()); + o.insert(o.end(), do_flatten(obs[i].right_team_direction).begin(), do_flatten(obs[i].right_team_direction).end()); + } + + if(o.size() < 88){ + std::vectorzero((88 - o.size()), -1); + } + o.insert(o.end(), obs[i].ball.begin(), obs[i].ball.end()); + o.insert(o.end(), obs[i].ball_direction.begin(), obs[i].ball_direction.end()); + std::vector_ball_owned_team; + if(obs[i].ball_owned_team == -1){ + _ball_owned_team = {1, 0, 0}; + } + else if(obs[i].ball_owned_team == 0){ + _ball_owned_team = {0, 1, 0}; + } + else if(obs[i].ball_owned_team == 1){ + _ball_owned_team = {0, 0, 1}; + } + o.insert(o.end(), _ball_owned_team.begin(), _ball_owned_team.end()); + std::vectoractive(11, 0); + if(obs[i].active != -1){ + active[obs[i].active] = 1; + } + o.insert(o.end(), active.begin(), active.end()); + std::vectorgame_mode(7, 0); + game_mode[obs[i].game_mode] = 1; + o.insert(o.end(), game_mode.begin(), game_mode.end()); + final_obs.push_back(o); + } + return final_obs; + } + std::vectorobservation_simple115state_single_agent(std::vector >obs){ + return obs[0]; + } + + std::vectordo_flatten(std::vector >obj){ + std::vectorresult; + int x = obj.size(); + int y = obj[0].size(); + for(int i = 0; i < x; i++){ + for(int j = 0; j < y; j++){ + result[i * y + j] = obj[i][j]; + } + } + return result; + } + +}; + +class FootballEnv : public Env { + public: + Config_football config; + std::string env_name_, representation_, rewards_, logdir_; + bool stacked_, write_goal_dumps_, write_full_episode_dumps_, render_, write_video_; + int dump_frequency_, extra_players_, number_of_left_players_agent_controls_, number_of_right_players_agent_controls_; + std::vectorchannel_dimensions_; + bool done_; + PreFootballEnv env; + FootballEnv(const Spec& spec, int env_id) : Env(spec, env_id), + env_name_(spec.config["env_name"_]), + stacked_(spec.config["stacked"_]), + representation_(spec.config["representation"_]), + rewards_(spec.config["rewards"_]), + write_goal_dumps_(spec.config["write_goal_dumps"_]), + write_full_episode_dumps_(spec.config["write_full_episode_dumps"_]), + render_(spec.config["render"_]), + write_video_(spec.config["write_video"_]), + dump_frequency_(spec.config["dump_frequency"_]), + logdir_(spec.config["logdir"_]), + extra_players_(spec.config["extra_players"_]), + number_of_left_players_agent_controls_(spec.config["number_of_left_players_agent_controls"_]), + number_of_right_players_agent_controls_(spec.config["number_of_right_players_agent_controls"_]), + channel_dimensions_(spec.config["channel_dimensions"_]) + { + config.level = env_name_; + std::vector players = {number_of_left_players_agent_controls_, number_of_right_players_agent_controls_}; + if(extra_players_ != 0){ + players.push_back(extra_players_); + } + config.dump_full_episodes = write_full_episode_dumps_; + config.dump_scores = write_goal_dumps_; + config.players = players; + config.tracesdir = logdir_; + config.write_video = write_video_; + env = PreFootballEnv(config); + } + + void Reset() override{ + env.reset(); + std::vector > >_observation_smm_single_agent = env.observation_smm_single_agent(env.observation_smm(env.observation(), channel_dimensions_)); + std::vector_observation_simple115state_single_agent = env.observation_simple115state_single_agent(env.observation_simple115state(env.observation(), false)); + std::vector_observation_simple115v2state_single_agent = env.observation_simple115state_single_agent(env.observation_simple115state(env.observation(), true)); + if(representation_ == "extracted" && stacked_ == false){ + WriteState_smm_single(_observation_smm_single_agent, 0, {0, 0}, 0, 0, 0); + } + else if(representation_ == "simple115"){ + WriteState_simple115_single(_observation_simple115state_single_agent, 0, {0, 0}, 0, 0, 0); + } + else if(representation_ == "simple115v2"){ + WriteState_simple115_single(_observation_simple115v2state_single_agent, 0, {0, 0}, 0, 0, 0); + } + } + + void Step(const Action& action) override { + std::vectoract_set = {}; + if(number_of_left_players_agent_controls_ + number_of_right_players_agent_controls_ <= 1){ + int act = action["action"_]; + act_set.push_back(act); + } + else{ + std::vectoract = action["action"_]; + act_set.resize(act.size()); + act_set = act; + } + env.step(act_set); + std::vector > >_observation_smm_single_agent = env.observation_smm_single_agent(env.observation_smm(env.observation(), channel_dimensions_)); + std::vector_observation_simple115state_single_agent = env.observation_simple115state_single_agent(env.observation_simple115state(env.observation(), false)); + std::vector_observation_simple115v2state_single_agent = env.observation_simple115state_single_agent(env.observation_simple115state(env.observation(), true)); + if(representation_ == "extracted" && stacked_ == false){ + WriteState_smm_single(_observation_smm_single_agent, env._env._cumulative_reward, env._env._observation.score, env._env._step_count, env._env._fps, env._env._game_fps); + } + else if(representation_ == "simple115"){ + WriteState_simple115_single(_observation_simple115state_single_agent, env._env._cumulative_reward, env._env._observation.score, env._env._step_count, env._env._fps, env._env._game_fps); + } + else if(representation_ == "simple115v2"){ + WriteState_simple115_single(_observation_simple115v2state_single_agent, env._env._cumulative_reward, env._env._observation.score, env._env._step_count, env._env._fps, env._env._game_fps); + } + }; + + private: + void WriteState_smm_single(std::vector > >obs, float episode_reward, std::vectorscore, int steps, float fps, float game_fps) { + State state = Allocate(); + for(int i = 0; i < channel_dimensions_[1]; i++){ + for(int j = 0; j < channel_dimensions_[0]; j++){ + for(int k = 0; k < 4; k++){ + state["obs"_][i][j][k] = obs[i][j][k]; + } + } + } + state["info:episode_reward"_] = episode_reward; + state["info:score"_][0] = score[0]; + state["info:score"_][1] = score[1]; + state["info:steps"_] = steps; + state["info:fps"_] = fps; + state["info:game_fps"_] = game_fps; + } + void WriteState_simple115_single(std::vectorobs, float episode_reward, std::vectorscore, int steps, float fps, float game_fps){ + State state = Allocate(); + for(int i = 0; i < 115; i++){ + state["obs"_][i] = obs[i]; + } + state["info:episode_reward"_] = episode_reward; + state["info:score"_][0] = score[0]; + state["info:score"_][1] = score[1]; + state["info:steps"_] = steps; + state["info:fps"_] = fps; + state["info:game_fps"_] = game_fps; + } +}; + +using FootballEnvPool = AsyncEnvPool; + +} + +#endif //#ifndef ENVPOOL_FOOTBALL_ENV_H_ \ No newline at end of file diff --git a/envpool/gfootball/football_env_test.cc b/envpool/football/football_env_test.cc similarity index 100% rename from envpool/gfootball/football_env_test.cc rename to envpool/football/football_env_test.cc diff --git a/envpool/gfootball/football_envpool.cc b/envpool/football/football_envpool.cc similarity index 100% rename from envpool/gfootball/football_envpool.cc rename to envpool/football/football_envpool.cc diff --git a/envpool/gfootball/football_envpool_test.py b/envpool/football/football_envpool_test.py similarity index 100% rename from envpool/gfootball/football_envpool_test.py rename to envpool/football/football_envpool_test.py diff --git a/envpool/gfootball/registration.py b/envpool/football/registration.py similarity index 100% rename from envpool/gfootball/registration.py rename to envpool/football/registration.py diff --git a/envpool/gfootball/football_env.h b/envpool/gfootball/football_env.h deleted file mode 100644 index c6935aec..00000000 --- a/envpool/gfootball/football_env.h +++ /dev/null @@ -1,442 +0,0 @@ -#ifndef ENVPOOL_FOOTBALL_ENV_H_ -#define ENVPOOL_FOOTBALL_ENV_H_ - -#include -#include -#include -#include "game_env.hpp" -#include "config.h" -#include "football_action_set.h" -#include "envpool/core/async_envpool.h" -#include "envpool/core/env.h" - -namespace football{ - -class FootballEnvFns { - public: - //static char *tracesdir_pre_char; - //static std::string tracesdir_pre; - //static std::string tracesdir; - static decltype(auto) DefaultConfig(){ - return MakeDict( - "action_set"_.Bind(std::string("default")), "custom_display_stats"_.Bind(std::vector{}), "display_game_stats"_.Bind(true), - "dump_full_episodes"_.Bind(false), "dump_scores"_.Bind(false), "players"_.Bind(std::vector{"agent:left_players=1"}), - "level"_.Bind(std::string("11_vs_11_stochastic")), "physics_steps_per_frame"_.Bind(10), "render_resolution_x"_.Bind(1280), - "render_resolution_y"_.Bind(1280 * 0.5625), "real_time"_.Bind(false), - //"tracesdir"_.Bind(tracesdir), - "video_format"_.Bind(std::string("avi")), - "video_quality_level"_.Bind(0), "write_video"_.Bind(false) - ); - } - template - static decltype(auto) StateSpec(const Config& conf) { - return MakeDict( - "obs"_.Bind(Spec({-1, 72, 96, 16}, {0, 255}), - "info:episode_reward"_.Bind(Spec({})), - "info:score"_.Bind(Spec({2})), - "info:steps"_.Bind(Spec({})), - "info:FPS"_.Bind(Spec({})), - "info:gameFPS"_.Bind(Spec({})) - ) - ); - } - template - static decltype(auto) ActionSpec(const Config& conf) { - return MakeDict( - "action"_.Bind(Spec({-1}, {0, 32})) - ); - } - FootballEnvFns(){ - //tracesdir_pre_char = getcwd(NULL, 0); - //tracesdir_pre = tracesdir_pre_char; - //tracesdir = tracesdir_pre + "/dump"; - } -}; - -using FootballEnvSpec = EnvSpec; - -struct observation{ - int num_players = 11; - std::vector left_agent_controlled_player = std::vector(1); - std::vector right_agent_controlled_player = std::vector(1); - std::vector left_team = std::vector(num_players * 2); - std::vector left_team_roles = std::vector(num_players); - std::vector left_team_direction = std::vector(num_players * 2); - std::vector left_team_tired_factor = std::vector(num_players); - std::vector left_team_yellow_card = std::vector(num_players); - std::vector left_team_active = std::vector(1); - int left_team_designated_player = 0; - std::vector right_team = std::vector(num_players * 2); - std::vector right_team_roles = std::vector(num_players); - std::vector right_team_direction = std::vector(num_players * 2); - std::vector right_team_tired_factor = std::vector(num_players); - std::vector right_team_yellow_card = std::vector(num_players); - std::vector right_team_active = std::vector(1); - int right_team_designated_player = 0; - std::vector ball = {0, 0, 0}; - std::vector ball_direction = std::vector(3); - std::vector ball_rotation = std::vector(3); - int ball_owned_team = 0; - int ball_owned_player = 0; - int game_mode = 0; - std::vector left_agent_sticky_actions = std::vector(num_players); - std::vector right_agent_sticky_actions = std::vector(num_players); - std::vector score = std::vector(2); - int steps_left = 0; - observation(){}; -}; - -struct FootballEnvState{ - int previous_score_diff = 0; - int previous_game_mode = -1; - int prev_ball_owned_team = -1; -}; - -class FootballEnv : public Env { - protected: - int previous_score_diff = 0; - int previous_game_mode = -1; - int prev_ball_owned_team = -1; - - public: - std::string action_set_name_; - std::string custom_display_stats_; - bool display_game_stats_; - bool dump_full_episodes_; - bool dump_scores_; - std::vectorplayers_; - std::string level_; - bool real_time_; - //std::string tracesdir_; - std::string video_format_; - int video_quality_level_; - bool write_video_; - int episode_number = 0; - boost::shared_ptr scenario_config = ScenarioConfig::make(); - GameContext* context = nullptr; - boost::shared_ptr game_config = GameConfig::make(); - GameState state = game_created; - int waiting_for_game_count = 0; - GameEnv env_; - int physics_steps_per_frame_; - int render_resolution_x_; - int render_resolution_y_; - int steps_time = 0; - int step_count = 0; - int _step = 0; - clock_t episode_start = clock(); - std::vector action_set; - float cumulative_reward = 0; - - FootballEnv(const Spec& spec, int env_id) : Env(spec, env_id), - env_(GameEnv::GameEnv()), - action_set_name(spec.config["action_set"_]), - physics_steps_per_frame(spec.config["physics_steps_per_frame"_]), - render_resolution_x(spec.config["render_resolution_x"_]), - render_resolution_y(spec.config["render_resolution_y"_]), - custom_display_stats(spec.config["custom_display_stats"_]), - display_game_stats(spec.config["display_game_stats"_]), - dump_full_episodes(spec.config["dump_full_episodes"_]), - dump_scores(spec.config["dump_scores"_]), - players(spec.config["players"_]), - level(spec.config["level"_]), - real_time(spec.config["real_time"_]), - //tracesdir(spec.config["tracesdir"_]), - video_format(spec.config["video_format"_]), - video_quality_level(spec.config["video_quality_level"_]), - write_video(spec.config["write_video"_]) - {}; - - - void Step(const Action& action){ - observation obs; - step_count += 1; - int action_index = 0; - std::vector controlled_players; - for(int left_team = 1; left_team > 0; left_team++){ - auto agents = env_.scenario_config.left_agents; - for(int j = 0; j < agents; j++){ - auto player_action_index = action["action"_][action_index]; - CoreAction player_action = action_idle; - switch (player_action_index) - { - case 0: - player_action = action_idle; - break; - case 1: - player_action = action_left; - break; - case 2: - player_action = action_top_left; - break; - case 3: - player_action = action_top; - break; - case 4: - player_action = action_top_right; - break; - case 5: - player_action = action_right; - break; - case 6: - player_action = action_bottom_right; - break; - case 7: - player_action = action_bottom; - break; - case 8: - player_action = action_bottom_left; - break; - case 9: - player_action = action_long_pass; - break; - case 10: - player_action = action_high_pass; - break; - case 11: - player_action = action_short_pass; - break; - case 12: - player_action = action_shot; - break; - case 13: - player_action = action_keeper_rush; - break; - case 14: - player_action = action_sliding; - break; - case 15: - player_action = action_pressure; - break; - case 16: - player_action = action_team_pressure; - break; - case 17: - player_action = action_switch; - break; - case 18: - player_action = action_sprint; - break; - case 19: - player_action = action_dribble; - break; - case 20: - player_action = action_release_direction; - break; - case 21: - player_action = action_release_long_pass; - break; - case 22: - player_action = action_release_high_pass; - break; - case 23: - player_action = action_release_short_pass; - break; - case 24: - player_action = action_release_shot; - break; - case 25: - player_action = action_release_keeper_rush; - break; - case 26: - player_action = action_release_sliding; - break; - case 27: - player_action = action_release_pressure; - break; - case 28: - player_action = action_release_team_pressure; - break; - case 29: - player_action = action_release_switch; - break; - case 30: - player_action = action_release_sprint; - break; - case 31: - player_action = action_release_dribble; - break; - case 32: - player_action = action_builtin_ai; - break; - default: 0; - break; - } - if(env_.waiting_for_game_count == 20){ - player_action = action_short_pass; - } - else if(env_.waiting_for_game_count > 20){ - player_action = action_idle; - if(left_team == 0){ - controlled_players = obs.left_agent_controlled_player; - } - else{ - controlled_players = obs.right_agent_controlled_player; - } - if (obs.ball_owned_team != -1 && controlled_players[j] == obs.ball_owned_player && !(left_team ^ obs.ball_owned_team)){ - if(bool(env_.waiting_for_game_count < 30) != bool(left_team)){ - player_action = action_left; - } - else{ - player_action = action_right; - } - } - } - action_index += 1; - env_.action(player_action.action_, bool(left_team), j); - } - } - while(true){ - clock_t enter_time = clock(); - env_.step(); - steps_time += clock() - enter_time; - if (retrieve_observation()){ - break; - } - } - - if(env_.scenario_config.end_episode_on_score){ - if(obs.score[0] > 0 || obs.score[1] > 0){ - env_.state = GameState::game_done; - } - } - - if(env_.scenario_config.end_episode_on_out_of_play && obs.game_mode != int(e_GameMode::e_GameMode_Normal) && previous_game_mode == int(e_GameMode::e_GameMode_Normal)){ - env_.state = GameState::game_done; - } - previous_game_mode = obs.game_mode; - - if(env_.scenario_config.end_episode_on_possession_change && - obs.ball_owned_team != -1 && - prev_ball_owned_team != -1 && - obs.ball_owned_team != prev_ball_owned_team){ - env_.state = GameState::game_done; - } - if(obs.ball_owned_team != -1){ - prev_ball_owned_team = obs.ball_owned_team; - } - - int score_diff = obs.score[0] - obs.score[1]; - int reward = score_diff - previous_score_diff; - previous_score_diff = score_diff; - if(reward == 1){ - - } - if(obs.game_mode != int(e_GameMode::e_GameMode_Normal)){ - env_.waiting_for_game_count += 1; - } - else{ - env_.waiting_for_game_count = 0; - } - if(_step >= env_.scenario_config.game_duration){ - env_.state = GameState::game_done; - } - - bool episode_done = env_.state == GameState::game_done; - clock_t end_time = clock(); - cumulative_reward += reward; - if(episode_done){ - float fps = step_count / (end_time - episode_start); - float game_fps = step_count / steps_time; - } - }; - - void setConfig(ScenarioConfig& game_config) { - DO_VALIDATION; - scenario_config.ball_position.coords[0] = scenario_config.ball_position.coords[0] * X_FIELD_SCALE; - scenario_config.ball_position.coords[1] = scenario_config.ball_position.coords[1] * Y_FIELD_SCALE; - std::vector setup = GetMenuTask()->GetControllerSetup(); - CHECK(setup.size() == 2 * MAX_PLAYERS); - int controller = 0; - for (int x = 0; x < scenario_config.left_agents; x++) { - DO_VALIDATION; - setup[controller++].side = -1; - } - while (controller < MAX_PLAYERS) { - DO_VALIDATION; - setup[controller++].side = 0; - } - for (int x = 0; x < scenario_config.right_agents; x++) { - DO_VALIDATION; - setup[controller++].side = 1; - } - while (controller < 2 * MAX_PLAYERS) { - DO_VALIDATION; - setup[controller++].side = 0; - } - this->scenario_config = scenario_config; - GetMenuTask()->SetControllerSetup(setup); - }; - - void reset_game(bool animations, int inc) { - env_.game_config.physics_steps_per_frame = this->physics_steps_per_frame; - env_.game_config.render_resolution_x = this->render_resolution_x; - env_.game_config.render_resolution_y = this->render_resolution_y; - this->config.NewScenario(inc); - if(env_.state == GameState::game_created){ - env_.start_game(); - } - env_.state = GameState::game_running; - auto scenario_config_ = ScenarioConfig::make(); - env_.reset(*scenario_config_, animations); - }; - - void Reset (int inc = 1) { - episode_start = clock(); - action_set = get_action_set(this->config); - cumulative_reward = 0; - step_count = 0; - reset_game(env_.game_config.render, inc); - } - - bool retrieve_observation(){ - auto info = env_.get_info(); - return info.is_in_play; - } - - std::vector get_action_set(Config config){ - std::vector action_set; - if(config.action_set == "default"){ - action_set = {action_idle, action_left, action_top_left, action_top, - action_top_right, action_right, action_bottom_right, - action_bottom, action_bottom_left, action_long_pass, - action_high_pass, action_short_pass, action_shot, - action_sprint, action_release_direction, action_release_sprint, - action_sliding, action_dribble, action_release_dribble}; - } - else if(config.action_set == "v2"){ - action_set = { - action_idle, action_left, action_top_left, action_top, - action_top_right, action_right, action_bottom_right, - action_bottom, action_bottom_left, action_long_pass, - action_high_pass, action_short_pass, action_shot, - action_sprint, action_release_direction, action_release_sprint, - action_sliding, action_dribble, action_release_dribble, action_builtin_ai - }; - } - else if(config.action_set == "full"){ - action_set = { - action_idle, action_left, action_top_left, action_top, - action_top_right, action_right, action_bottom_right, - action_bottom, action_bottom_left, action_long_pass, - action_high_pass, action_short_pass, action_shot, - action_sprint, action_release_direction, action_release_sprint, - action_sliding, action_dribble, action_release_dribble, action_builtin_ai, - action_keeper_rush, action_pressure, - action_team_pressure, action_switch, - action_release_long_pass, action_release_high_pass, - action_release_short_pass, action_release_shot, - action_release_keeper_rush, action_release_sliding, - action_release_pressure, action_release_team_pressure, - action_release_switch, - }; - } - return action_set; - } - -}; - -using FootballEnvPool = AsyncEnvPool; -} - -#endif //#ifndef ENVPOOL_FOOTBALL_ENV_H_ From f3c7c7ce0e048c93bdbc2a35ba489cd191cf46e1 Mon Sep 17 00:00:00 2001 From: kfq2002 Date: Thu, 1 Sep 2022 07:48:27 +0000 Subject: [PATCH 27/28] 2022/09/01 --- envpool/football/config.h | 16 +++++- envpool/football/football_action_set.h | 76 +++++++++++++++++++++++--- envpool/football/player.h | 43 +++++++++++++++ envpool/workspace0.bzl | 64 ++++++++++++++++++++++ 4 files changed, 187 insertions(+), 12 deletions(-) create mode 100644 envpool/football/player.h diff --git a/envpool/football/config.h b/envpool/football/config.h index c6bec683..876aee49 100644 --- a/envpool/football/config.h +++ b/envpool/football/config.h @@ -7,7 +7,7 @@ #include #include "game_env.hpp" -class Config{ +class Config_football{ public: std::string action_set = "default"; std::string custom_display_stats = ""; @@ -27,12 +27,22 @@ class Config{ int video_quality_level = 0; bool write_video = false; int episode_number = 0; - Config(){ }; + Config_football(){ }; void NewScenario(int inc = 1){ this->episode_number += inc; auto scenario_config = ScenarioConfig::make(); }; - + int number_of_left_players = players[0]; + int number_of_right_players = players[1]; + int number_of_players_agent_controls(); }; +int Config_football::number_of_players_agent_controls(){ + int sum = 0; + for(int i = 0; i < this->players.size(); i++){ + sum += players[i]; + } + return sum; +} + #endif // ENVPOOL_FOOTBALL_CONFIG_H_ diff --git a/envpool/football/football_action_set.h b/envpool/football/football_action_set.h index b7abcad1..d2bc12f2 100644 --- a/envpool/football/football_action_set.h +++ b/envpool/football/football_action_set.h @@ -8,17 +8,17 @@ class CoreAction{ public: CoreAction(Action action, std::string name, bool sticky = false, bool directional = false){ - this->action_ = action; - this->name_ = name; - this->sticky_ = sticky; - this->directional_ = directional; + _backend_action = backend_action; + _name = name; + _sticky = sticky; + _directional = directional; } - bool is_in_actionset(Config config){ + bool is_in_actionset(Config_football config){ }; - Action action_; - std::string name_; - bool sticky_; - bool directional_; + Action _backend_action; + std::string _name; + bool _sticky; + bool _directional; }; bool T = true; @@ -58,4 +58,62 @@ CoreAction action_release_switch(Action::game_release_switch, "release_switch"); CoreAction action_release_sprint(Action::game_release_sprint, "release_sprint"); CoreAction action_release_dribble(Action::game_release_dribble, "release_dribble"); +std::vector get_action_set(Config_football cfg){ + std::vector action_set; + if(cfg.action_set == "default"){ + action_set = { + action_idle, action_left, action_top_left, action_top, + action_top_right, action_right, action_bottom_right, + action_bottom, action_bottom_left, action_long_pass, + action_high_pass, action_short_pass, action_shot, + action_sprint, action_release_direction, action_release_sprint, + action_sliding, action_dribble, action_release_dribble + }; + } + else if(cfg.action_set == "v2"){ + action_set = { + action_idle, action_left, action_top_left, action_top, + action_top_right, action_right, action_bottom_right, + action_bottom, action_bottom_left, action_long_pass, + action_high_pass, action_short_pass, action_shot, + action_sprint, action_release_direction, action_release_sprint, + action_sliding, action_dribble, action_release_dribble, action_builtin_ai + }; + } + else if(cfg.action_set == "full"){ + action_set = { + action_idle, action_left, action_top_left, action_top, + action_top_right, action_right, action_bottom_right, + action_bottom, action_bottom_left, action_long_pass, + action_high_pass, action_short_pass, action_shot, + action_sprint, action_release_direction, action_release_sprint, + action_sliding, action_dribble, action_release_dribble, action_builtin_ai, + action_keeper_rush, action_pressure, + action_team_pressure, action_switch, + action_release_long_pass, action_release_high_pass, + action_release_short_pass, action_release_shot, + action_release_keeper_rush, action_release_sliding, + action_release_pressure, action_release_team_pressure, + action_release_switch + }; + } + return action_set; +} + +std::vector get_sticky_actions(Config_football cfg){ + std::vector sticky_actions; + std::vector action_set; + action_set = get_action_set(cfg); + for(int i = 0; i < action_set.size(); i++){ + if(action_set[i]._sticky){ + sticky_actions.push_back(action_set[i]); + } + } + return sticky_actions; +} + +CoreAction named_action_from_action_set(std::vector action_set, int action){ + return action_set[action]; +} + #endif //ENVPOOL_FOOTBALL_ACTION_SET_H_ diff --git a/envpool/football/player.h b/envpool/football/player.h new file mode 100644 index 00000000..ee8ec8d0 --- /dev/null +++ b/envpool/football/player.h @@ -0,0 +1,43 @@ +#ifndef ENVPOOL_FOOTBALL_PLAYER_H_ +#define ENVPOOL_FOOTBALL_PLAYER_H_ + +#include +#include +#include +#include "config.h" + +class PlayerFootball{ + private: + int _num_left_controlled_players = 1; + int _num_right_controlled_players = 0; + bool _can_play_right = false; + std::vector _action = {}; + public: + PlayerFootball(){}; + PlayerFootball(std::vector player_config, Config_football env_config){ + if(player_config.size() >= 2){ + _num_left_controlled_players = player_config[0]; + _num_right_controlled_players = player_config[1]; + } + } + int num_controlled_left_players(){ + return _num_left_controlled_players; + } + int num_controlled_right_players(){ + return _num_right_controlled_players; + } + int num_controlled_players(){ + return (_num_left_controlled_players + _num_right_controlled_players); + } + bool can_play_right(){ + return _can_play_right; + } + void set_action(std::vectoraction){ + _action = action; + } + std::vectortake_action(){ + return _action; + } +}; + +#endif \ No newline at end of file diff --git a/envpool/workspace0.bzl b/envpool/workspace0.bzl index 3d59207d..14230935 100644 --- a/envpool/workspace0.bzl +++ b/envpool/workspace0.bzl @@ -396,8 +396,72 @@ def workspace(): "https://files.pythonhosted.org/packages/98/63/b111538b5db47b8081d8ca82280fadaa145fbd31aa249f49675a01abb8eb/gfootball-2.10.2.tar.gz" ], build_file = "//third_party/football:football.BUILD", + strip_prefix = "gfootball-2.10.2", ) + maybe( + http_archive, + name = "sdl", + urls = ["https://github.com/libsdl-org/SDL/archive/refs/heads/main.zip"], + build_file = "//third_party/sdl:sdl.BUILD", + ) + + maybe( + http_archive, + name = "sdl2_ttf", + urls = [ + "https://github.com/libsdl-org/SDL_ttf/archive/refs/heads/main.zip" + ], + sha256 = "ba680c595f971046920fda5f16d6501e945f21d53854075d88dd6f75bd83beec", + build_file = "//third_party/sdl2_ttf:sdl2_ttf.BUILD", + ) + + maybe( + http_archive, + name = "ft2build", + sha256 = "e0b8460820ee9048720dc5932b0433ed3e08d6537bec075c290a2d3184534919", + urls = [ + "https://github.com/LuaDist/freetype/archive/refs/heads/master.zip" + ], + build_file = "//third_party/freetype:freetype.BUILD", + ) + + maybe( + http_archive, + name = "egl", + sha256 = "72bccd67ff05479b74246df3cb499610410b9f7fe8cb5214ca7f9bf31b37f499", + urls = [ + "https://github.com/McNopper/EGL/archive/refs/heads/master.zip", + ], + build_file = "//third_party/egl:egl.BUILD", + ) + + maybe( + http_archive, + name = "gl", + sha256 = "2700383d4de2455f06114fbaf872684f15529d4bdc5cdea69b5fb0e9aa7763f1", + urls = [ + "https://sourceforge.net/projects/glew/files/glew/2.1.0/glew-2.1.0.zip", + ], + build_file = "//third_party/gl:gl.BUILD", + strip_prefix = "glew-2.1.0", + ) + + maybe( + http_archive, + name = "sdl2_gfx", + sha256 = "83980d159f96e35813f8c1699a648de701585c7061f54319021d3534e48f3a3e", + urls = [ + "https://github.com/RobLoach/sdl2_gfx/archive/refs/heads/master.zip" + ], + build_file = "//third_party/sdl2_gfx:sdl2_gfx.BUILD", + ) + + maybe( + cuda_configure, + name = "cuda", + ) + maybe( cuda_configure, name = "cuda", From 8a81a94f176adefb5f5b3ac8a5f39cca1278c1d5 Mon Sep 17 00:00:00 2001 From: kfq2002 Date: Fri, 2 Sep 2022 03:06:22 +0000 Subject: [PATCH 28/28] 0902 --- envpool/football/football_env.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/envpool/football/football_env.h b/envpool/football/football_env.h index 64842999..7b581b0f 100644 --- a/envpool/football/football_env.h +++ b/envpool/football/football_env.h @@ -29,9 +29,6 @@ namespace football{ class FootballEnvFns { public: - //static char *tracesdir_pre_char; - //static std::string tracesdir_pre; - //static std::string tracesdir; static decltype(auto) DefaultConfig(){ return MakeDict( "env_name"_.Bind(std::string("")), @@ -43,6 +40,7 @@ class FootballEnvFns { "render"_.Bind(false), "write_video"_.Bind(false), "dump_frequency"_.Bind(1), + "logdir"_.Bind(std::string("")), "extra_players"_.Bind(0), "number_of_left_players_agent_controls"_.Bind(1), "number_of_right_players_agent_controls"_.Bind(0), @@ -127,7 +125,7 @@ class FootballEnvFns { static decltype(auto) ActionSpec(const Config& conf) { Config_football c; int num_actions = get_action_set(c).size(); - int number_of_players_agent_controls = conf.number_of_left_players_agent_controls + conf.number_of_right_players_agent_controls + conf.extra_players; + int number_of_players_agent_controls = conf["number_of_left_players_agent_controls"_] + conf["number_of_right_players_agent_controls"_] + conf["extra_players"_]; if(number_of_players_agent_controls > 1){ return MakeDict( "action"_.Bind(Spec({number_of_players_agent_controls}, {0, num_actions})) @@ -373,7 +371,7 @@ class FootballEnvCore{ std::vectorsticky_actions_state(bool left_team, int player_id){ std::vectorresult; for(int a = 0; a < _sticky_actions.size(); a++){ - result.push_back(int(_env.sticky_actions_state(_sticky_actions[a]._backend_action, left_team, player_id))); + result.push_back(int(_env.sticky_action_state(_sticky_actions[a]._backend_action, left_team, player_id))); } return result; } @@ -486,6 +484,9 @@ class PreFootballEnv{ std::vector _players; FootballEnvCore _env = FootballEnvCore(_config); int _num_actions = get_action_set(_config).size(); + PreFootballEnv(){ + _players = _construct_players(_config.players, player_index); + } PreFootballEnv(Config_football cfg){ _config = cfg; _players = _construct_players(cfg.players, player_index); @@ -561,7 +562,7 @@ class PreFootballEnv{ for(j = 0; j < _players[i].num_controlled_left_players(); j++){ actions.push_back(a[j]); } - for(; j < _players[i].num_controlled_left_players() + _players[i].num_controlled_right_players()){ + for(; j < _players[i].num_controlled_left_players() + _players[i].num_controlled_right_players(); j++){ actions.push_back(a[j]); } }