From 1375045b37903bc54168d53d396949f52bec2306 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Clod=C3=A9ric=20Mars?= Date: Tue, 24 Jan 2023 13:52:33 -0500 Subject: [PATCH] Directly using and serializing gym.spaces and their value (#116) * Directly using and serializing gym.spaces and their value * Introducing debug inspector of received observation on the web side * Take into account review --- actors/ppo.py | 57 +++-- actors/random_actor.py | 27 +- actors/simple_a2c.py | 69 ++--- actors/simple_dqn.py | 122 ++++----- actors/td3.py | 131 ++++------ actors/tutorial/tutorial_1.py | 21 +- actors/tutorial/tutorial_2.py | 40 +-- actors/tutorial/tutorial_3.py | 54 ++-- actors/tutorial/tutorial_4.py | 49 ++-- cogment_verse/processes/environment.py | 4 +- cogment_verse/processes/run.py | 4 +- cogment_verse/specs/__init__.py | 18 +- cogment_verse/specs/action_space.py | 136 ++++++++++ cogment_verse/specs/cogment.yaml | 2 + cogment_verse/specs/data.proto | 81 +----- cogment_verse/specs/environment_specs.py | 122 ++++++++- cogment_verse/specs/flatten.py | 121 --------- cogment_verse/specs/gym_spaces_adapter.py | 97 ------- cogment_verse/specs/ndarray.proto | 35 +++ cogment_verse/specs/ndarray.py | 30 --- cogment_verse/specs/ndarray_serialization.py | 120 +++++++++ cogment_verse/specs/observation_space.py | 232 +++++++++++++++++ cogment_verse/specs/sample_space.py | 78 ------ cogment_verse/specs/spaces.proto | 45 ++++ cogment_verse/specs/spaces_serialization.py | 62 +++++ cogment_verse/specs/test_sample.py | 122 --------- cogment_verse/specs/value.py | 22 -- .../web/components/build/asset-manifest.json | 15 -- .../build/static/css/main.b6c8fc15.css | 4 - .../build/static/css/main.b6c8fc15.css.map | 1 - cogment_verse/web/components/src/App.jsx | 116 --------- cogment_verse/web/utils/generate.py | 2 + cogment_verse/web/utils/npm.py | 4 +- .../web/web_app/build/asset-manifest.json | 12 +- cogment_verse/web/web_app/build/index.html | 2 +- .../build/static/css/main.116f63ff.css | 4 - .../build/static/css/main.116f63ff.css.map | 1 - .../build/static/css/main.afd381f3.css | 4 + .../build/static/css/main.afd381f3.css.map | 1 + .../web_app/build/static/js/main.343deae2.js | 3 - .../build/static/js/main.343deae2.js.map | 1 - .../web_app/build/static/js/main.f749e5c1.js | 3 + ...CENSE.txt => main.f749e5c1.js.LICENSE.txt} | 0 .../build/static/js/main.f749e5c1.js.map | 1 + cogment_verse/web/web_app/cogment.yaml | 2 + cogment_verse/web/web_app/data.proto | 81 +----- cogment_verse/web/web_app/ndarray.proto | 35 +++ cogment_verse/web/web_app/spaces.proto | 45 ++++ .../web/web_app/src/components/Inspector.jsx | 146 +++++++++++ .../src/controls/AtariPitfallControls.jsx | 63 ++--- .../src/controls/ConnectFourControls.jsx | 46 ++-- .../src/controls/GymCartPoleControls.jsx | 29 +-- .../GymLunarLanderContinuousControls.jsx | 26 +- .../src/controls/GymLunarLanderControls.jsx | 20 +- .../src/controls/GymMountainCarControls.jsx | 17 +- .../src/controls/RealTimeObserverControls.jsx | 2 +- .../web_app/src/controls/TetrisControls.jsx | 34 ++- .../controls/TurnBasedObserverControls.jsx | 4 +- cogment_verse/web/web_app/src/pages/Play.jsx | 10 +- .../web/web_app/src/utils/constants.js | 4 - .../web_app/src/utils/spaceSerialization.js | 239 ++++++++++++++++++ config/services/environment/hopper.yaml | 4 +- config/services/environment/pitfall.yaml | 3 + docs/development_setup.md | 9 +- environments/gym_adapter.py | 84 +++--- environments/gym_wrapper.py | 118 --------- environments/isaac_adapter.py | 74 +++--- environments/pettingzoo_adapter.py | 98 ++----- requirements.txt | 1 + runs/play.py | 6 +- tests/test_flatten.py | 169 ------------- tests/test_ndarray_serialization.py | 97 +++++++ tests/test_sample.py | 192 -------------- tests/test_spaces_serialization.py | 62 +++++ 74 files changed, 1922 insertions(+), 1873 deletions(-) create mode 100644 cogment_verse/specs/action_space.py delete mode 100644 cogment_verse/specs/flatten.py delete mode 100644 cogment_verse/specs/gym_spaces_adapter.py create mode 100644 cogment_verse/specs/ndarray.proto delete mode 100644 cogment_verse/specs/ndarray.py create mode 100644 cogment_verse/specs/ndarray_serialization.py create mode 100644 cogment_verse/specs/observation_space.py delete mode 100644 cogment_verse/specs/sample_space.py create mode 100644 cogment_verse/specs/spaces.proto create mode 100644 cogment_verse/specs/spaces_serialization.py delete mode 100644 cogment_verse/specs/test_sample.py delete mode 100644 cogment_verse/specs/value.py delete mode 100644 cogment_verse/web/components/build/asset-manifest.json delete mode 100644 cogment_verse/web/components/build/static/css/main.b6c8fc15.css delete mode 100644 cogment_verse/web/components/build/static/css/main.b6c8fc15.css.map delete mode 100644 cogment_verse/web/components/src/App.jsx delete mode 100644 cogment_verse/web/web_app/build/static/css/main.116f63ff.css delete mode 100644 cogment_verse/web/web_app/build/static/css/main.116f63ff.css.map create mode 100644 cogment_verse/web/web_app/build/static/css/main.afd381f3.css create mode 100644 cogment_verse/web/web_app/build/static/css/main.afd381f3.css.map delete mode 100644 cogment_verse/web/web_app/build/static/js/main.343deae2.js delete mode 100644 cogment_verse/web/web_app/build/static/js/main.343deae2.js.map create mode 100644 cogment_verse/web/web_app/build/static/js/main.f749e5c1.js rename cogment_verse/web/web_app/build/static/js/{main.343deae2.js.LICENSE.txt => main.f749e5c1.js.LICENSE.txt} (100%) create mode 100644 cogment_verse/web/web_app/build/static/js/main.f749e5c1.js.map create mode 100644 cogment_verse/web/web_app/ndarray.proto create mode 100644 cogment_verse/web/web_app/spaces.proto create mode 100644 cogment_verse/web/web_app/src/components/Inspector.jsx create mode 100644 cogment_verse/web/web_app/src/utils/spaceSerialization.js create mode 100644 config/services/environment/pitfall.yaml delete mode 100644 environments/gym_wrapper.py delete mode 100644 tests/test_flatten.py create mode 100644 tests/test_ndarray_serialization.py delete mode 100644 tests/test_sample.py create mode 100644 tests/test_spaces_serialization.py diff --git a/actors/ppo.py b/actors/ppo.py index 1fc157ca..488ef157 100644 --- a/actors/ppo.py +++ b/actors/ppo.py @@ -20,20 +20,17 @@ import numpy as np import torch from torch.distributions.normal import Normal +from gym.spaces import Box, utils from cogment_verse import Model from cogment_verse.run.run_session import RunSession from cogment_verse.run.sample_producer_worker import SampleProducerSession from cogment_verse.specs import ( - PLAYER_ACTOR_CLASS, AgentConfig, + cog_settings, EnvironmentConfig, EnvironmentSpecs, - PlayerAction, - cog_settings, - flatten, - flattened_dimensions, - unflatten, + PLAYER_ACTOR_CLASS, ) torch.multiprocessing.set_sharing_strategy("file_system") @@ -308,14 +305,15 @@ def get_actor_classes(self): async def impl(self, actor_session): # Start a session actor_session.start() + config = actor_session.config - assert config.environment_specs.num_players == 1 - assert len(config.environment_specs.action_space.properties) == 1 - assert config.environment_specs.action_space.properties[0].WhichOneof("type") == "box" - # Get observation and action space - observation_space = config.environment_specs.observation_space - action_space = config.environment_specs.action_space + environment_specs = EnvironmentSpecs.deserialize(config.environment_specs) + observation_space = environment_specs.get_observation_space() + action_space = environment_specs.get_action_space() + + assert isinstance(action_space.gym_space, Box) + assert config.environment_specs.num_players == 1 # Get model model, _, _ = await actor_session.model_registry.retrieve_version( @@ -324,9 +322,9 @@ async def impl(self, actor_session): async for event in actor_session.all_events(): if event.observation and event.type == cogment.EventType.ACTIVE: - obs_tensor = torch.tensor( - flatten(observation_space, event.observation.observation.value), dtype=self._dtype - ).view(1, -1) + observation = observation_space.deserialize(event.observation.observation) + + obs_tensor = torch.tensor(observation.flat_value, dtype=self._dtype).view(1, -1) # Normalize the observation if model.state_normalization is not None: @@ -339,11 +337,11 @@ async def impl(self, actor_session): # Get action from policy network with torch.no_grad(): dist, _ = model.policy_network(obs_tensor) - action = dist.sample().cpu().numpy()[0] + action_value = dist.sample().cpu().numpy()[0] # Send action to environment - action_value = unflatten(action_space, action) - actor_session.do_action(PlayerAction(value=action_value)) + action = action_space.create(value=action_value) + actor_session.do_action(action_space.serialize(action)) class PPOTraining: @@ -392,8 +390,8 @@ def __init__(self, environment_specs: EnvironmentSpecs, cfg: EnvironmentConfig) self.model = PPOModel( model_id="", environment_implementation=self._environment_specs.implementation, - num_input=flattened_dimensions(self._environment_specs.observation_space), - num_output=flattened_dimensions(self._environment_specs.action_space), + num_input=utils.flatdim(self._environment_specs.get_observation_space().gym_space), + num_output=utils.flatdim(self._environment_specs.get_action_space().gym_space), learning_rate=self._cfg.learning_rate, n_iter=self._cfg.num_epochs, policy_network_hidden_nodes=self._cfg.policy_network.num_hidden_nodes, @@ -404,15 +402,20 @@ def __init__(self, environment_specs: EnvironmentSpecs, cfg: EnvironmentConfig) async def trial_sample_sequences_producer_impl(self, sample_producer_session: SampleProducerSession): """Collect sample from the trial""" + + # Share with A2C + observation = [] action = [] reward = [] done = [] player_actor_params = sample_producer_session.trial_info.parameters.actors[0] + player_actor_name = player_actor_params.name - player_observation_space = player_actor_params.config.environment_specs.observation_space - player_action_space = player_actor_params.config.environment_specs.action_space + player_environment_specs = EnvironmentSpecs.deserialize(player_actor_params.config.environment_specs) + player_observation_space = player_environment_specs.get_observation_space() + player_action_space = player_environment_specs.get_action_space() async for sample in sample_producer_session.all_trial_samples(): if sample.trial_state == cogment.TrialState.ENDED: @@ -423,9 +426,10 @@ async def trial_sample_sequences_producer_impl(self, sample_producer_session: Sa actor_sample = sample.actors_data[player_actor_name] observation.append( - torch.tensor(flatten(player_observation_space, actor_sample.observation.value), dtype=self._dtype) + torch.tensor(player_observation_space.deserialize(actor_sample.observation).value, dtype=self._dtype) ) - action.append(torch.tensor(flatten(player_action_space, actor_sample.action.value), dtype=self._dtype)) + + action.append(torch.tensor(player_action_space.deserialize(actor_sample.action).value, dtype=self._dtype)) reward.append( torch.tensor(actor_sample.reward if actor_sample.reward is not None else 0, dtype=self._dtype) ) @@ -438,8 +442,9 @@ async def impl(self, run_session: RunSession) -> dict: """Train and publish model the model""" model_id = f"{run_session.run_id}_model" + assert self._environment_specs.num_players == 1 - assert len(self._environment_specs.action_space.properties) == 1 + assert isinstance(self._environment_specs.get_action_space().gym_space, Box) # Initalize model self.model.model_id = model_id @@ -462,7 +467,7 @@ def create_trial_params(trial_idx: int, iter_idx: int): implementation="actors.ppo.PPOActor", config=AgentConfig( run_id=run_session.run_id, - environment_specs=self._environment_specs, + environment_specs=self._environment_specs.serialize(), model_id=model_id, model_version=version_info["version_number"], ), diff --git a/actors/random_actor.py b/actors/random_actor.py index 56dfaefa..40c87bae 100644 --- a/actors/random_actor.py +++ b/actors/random_actor.py @@ -13,13 +13,8 @@ # limitations under the License. import cogment -import numpy as np -from cogment_verse.specs import ( - PLAYER_ACTOR_CLASS, - PlayerAction, - sample_space, -) +from cogment_verse.specs import PLAYER_ACTOR_CLASS, EnvironmentSpecs class RandomActor: @@ -33,19 +28,19 @@ async def impl(self, actor_session): actor_session.start() config = actor_session.config + environment_specs = EnvironmentSpecs.deserialize(config.environment_specs) + observation_space = environment_specs.get_observation_space() + action_space = environment_specs.get_action_space() - action_space = config.environment_specs.action_space - - rng = np.random.default_rng(config.seed if config.seed is not None else 0) + action_space.gym_space.seed(config.seed if config.seed is not None else 0) async for event in actor_session.all_events(): if event.observation and event.type == cogment.EventType.ACTIVE: - if ( - event.observation.observation.HasField("current_player") - and event.observation.observation.current_player != actor_session.name - ): + observation = observation_space.deserialize(event.observation.observation) + if observation.current_player is not None and observation.current_player != actor_session.name: # Not the turn of the agent - actor_session.do_action(PlayerAction()) + actor_session.do_action(action_space.serialize(action_space.create())) continue - [action_value] = sample_space(action_space, rng=rng, mask=event.observation.observation.action_mask) - actor_session.do_action(PlayerAction(value=action_value)) + + action = action_space.sample(mask=observation.action_mask) + actor_session.do_action(action_space.serialize(action)) diff --git a/actors/simple_a2c.py b/actors/simple_a2c.py index 7898bd3b..b7fec381 100644 --- a/actors/simple_a2c.py +++ b/actors/simple_a2c.py @@ -12,27 +12,21 @@ # See the License for the specific language governing permissions and # limitations under the License. -# pylint: disable=C0303 -# pylint: disable=W0611 -# pylint: disable=W0612 - import logging import cogment import torch +from gym.spaces import utils, Discrete + from cogment_verse import Model from cogment_verse.specs import ( - PLAYER_ACTOR_CLASS, AgentConfig, - EnvironmentConfig, - PlayerAction, - SpaceValue, cog_settings, - flatten, - flattened_dimensions, - unflatten, + EnvironmentConfig, + EnvironmentSpecs, ) +from cogment_verse.constants import PLAYER_ACTOR_CLASS torch.multiprocessing.set_sharing_strategy("file_system") @@ -132,12 +126,9 @@ async def impl(self, actor_session): config = actor_session.config - assert config.environment_specs.num_players == 1 - assert len(config.environment_specs.action_space.properties) == 1 - # assert config.environment_specs.action_space.properties[0].WhichOneof("type") == "discrete" - - observation_space = config.environment_specs.observation_space - action_space = config.environment_specs.action_space + environment_specs = EnvironmentSpecs.deserialize(config.environment_specs) + observation_space = environment_specs.get_observation_space() + action_space = environment_specs.get_action_space(seed=config.seed) model, _, _ = await actor_session.model_registry.retrieve_version( SimpleA2CModel, config.model_id, config.model_version @@ -147,22 +138,17 @@ async def impl(self, actor_session): async for event in actor_session.all_events(): if event.observation and event.type == cogment.EventType.ACTIVE: - obs_tensor = torch.tensor( - flatten(observation_space, event.observation.observation.value), dtype=self._dtype - ) - if config.environment_specs.action_space.properties[0].WhichOneof("type") == "discrete": - probs = torch.softmax(model.actor_network(obs_tensor), dim=-1) - discrete_action_tensor = torch.distributions.Categorical(probs).sample() - action_value = SpaceValue( - properties=[SpaceValue.PropertyValue(discrete=discrete_action_tensor.item())] - ) + observation = observation_space.deserialize(event.observation.observation) + if isinstance(action_space.gym_space, Discrete): + observation_tensor = torch.tensor(observation.flat_value, dtype=self._dtype) + probs = torch.softmax(model.actor_network(observation_tensor), dim=-1) + discrete_action_tensor = torch.distributions.Categorical(probs).sample() + action = action_space.create(value=discrete_action_tensor.numpy()) else: - action = torch.rand((1,) + (action_space.properties[0].box.shape[0],)) - action = action.cpu().numpy()[0] - action_value = unflatten(action_space, action) + action = action_space.sample() - actor_session.do_action(PlayerAction(value=action_value)) + actor_session.do_action(action_space.serialize(action)) class SimpleA2CTraining: @@ -195,7 +181,9 @@ async def trial_sample_sequences_producer_impl(self, sample_producer_session): player_actor_params = sample_producer_session.trial_info.parameters.actors[0] player_actor_name = player_actor_params.name - player_observation_space = player_actor_params.config.environment_specs.observation_space + player_environment_specs = EnvironmentSpecs.deserialize(player_actor_params.config.environment_specs) + player_observation_space = player_environment_specs.get_observation_space() + player_action_space = player_environment_specs.get_action_space() async for sample in sample_producer_session.all_trial_samples(): if sample.trial_state == cogment.TrialState.ENDED: @@ -206,14 +194,10 @@ async def trial_sample_sequences_producer_impl(self, sample_producer_session): actor_sample = sample.actors_data[player_actor_name] observation.append( - torch.tensor(flatten(player_observation_space, actor_sample.observation.value), dtype=self._dtype) - ) - action_value = actor_sample.action.value - action.append( - torch.tensor( - action_value.properties[0].discrete if len(action_value.properties) > 0 else 0, dtype=self._dtype - ) + torch.tensor(player_observation_space.deserialize(actor_sample.observation).value, dtype=self._dtype) ) + + action.append(torch.tensor(player_action_space.deserialize(actor_sample.action).value, dtype=self._dtype)) reward.append( torch.tensor(actor_sample.reward if actor_sample.reward is not None else 0, dtype=self._dtype) ) @@ -227,14 +211,13 @@ async def impl(self, run_session): model_id = f"{run_session.run_id}_model" assert self._environment_specs.num_players == 1 - assert len(self._environment_specs.action_space.properties) == 1 - # assert self._environment_specs.action_space.properties[0].WhichOneof("type") == "discrete" + assert isinstance(self._environment_specs.get_action_space().gym_space, Discrete) model = SimpleA2CModel( model_id, environment_implementation=self._environment_specs.implementation, - num_input=flattened_dimensions(self._environment_specs.observation_space), - num_output=flattened_dimensions(self._environment_specs.action_space), + num_input=utils.flatdim(self._environment_specs.get_observation_space().gym_space), + num_output=utils.flatdim(self._environment_specs.get_action_space().gym_space), actor_network_num_hidden_nodes=self._cfg.actor_network.num_hidden_nodes, critic_network_num_hidden_nodes=self._cfg.critic_network.num_hidden_nodes, dtype=self._dtype, @@ -285,7 +268,7 @@ async def impl(self, run_session): run_id=run_session.run_id, model_id=model_id, model_version=version_info["version_number"], - environment_specs=self._environment_specs, + environment_specs=self._environment_specs.serialize(), ), ) ], diff --git a/actors/simple_dqn.py b/actors/simple_dqn.py index f65363a5..7cfffc50 100644 --- a/actors/simple_dqn.py +++ b/actors/simple_dqn.py @@ -23,22 +23,11 @@ import cogment import torch +from gym.spaces import Discrete, utils +from cogment_verse.specs import AgentConfig, cog_settings, EnvironmentConfig, EnvironmentSpecs -from cogment_verse.specs import ( - AgentConfig, - cog_settings, - EnvironmentConfig, - flatten, - flattened_dimensions, - flatten_mask, - PLAYER_ACTOR_CLASS, - PlayerAction, - SpaceValue, - sample_space, - WEB_ACTOR_NAME, - HUMAN_ACTOR_IMPL, -) +from cogment_verse.constants import PLAYER_ACTOR_CLASS, WEB_ACTOR_NAME, HUMAN_ACTOR_IMPL from cogment_verse import Model, TorchReplayBuffer # pylint: disable=abstract-class-instantiated @@ -68,7 +57,7 @@ def __init__( dtype=torch.float, version_number=0, ): - super().__init__(model_id=model_id, version_number=version_number) + super().__init__(model_id, version_number) self._dtype = dtype self._environment_implementation = environment_implementation self._num_input = num_input @@ -142,13 +131,13 @@ async def impl(self, actor_session): config = actor_session.config - assert len(config.environment_specs.action_space.properties) == 1 - assert config.environment_specs.action_space.properties[0].WhichOneof("type") == "discrete" + rng = np.random.default_rng(config.seed if config.seed is not None else 0) - observation_space = config.environment_specs.observation_space - action_space = config.environment_specs.action_space + environment_specs = EnvironmentSpecs.deserialize(config.environment_specs) + observation_space = environment_specs.get_observation_space() + action_space = environment_specs.get_action_space(seed=rng.integers(9999)) - rng = np.random.default_rng(config.seed if config.seed is not None else 0) + assert isinstance(action_space.gym_space, Discrete) model, _, _ = await actor_session.model_registry.retrieve_version( SimpleDQNModel, config.model_id, config.model_version @@ -157,12 +146,10 @@ async def impl(self, actor_session): async for event in actor_session.all_events(): if event.observation and event.type == cogment.EventType.ACTIVE: - if ( - event.observation.observation.HasField("current_player") - and event.observation.observation.current_player != actor_session.name - ): + observation = observation_space.deserialize(event.observation.observation) + if observation.current_player is not None and observation.current_player != actor_session.name: # Not the turn of the agent - actor_session.do_action(PlayerAction()) + actor_session.do_action(action_space.serialize(action_space.create())) continue if ( @@ -175,26 +162,21 @@ async def impl(self, actor_session): ) model.network.eval() if rng.random() < model.epsilon: - [action_value] = sample_space(action_space, rng=rng, mask=event.observation.observation.action_mask) + action = action_space.sample(mask=observation.action_mask) else: - obs_tensor = torch.tensor( - flatten(observation_space, event.observation.observation.value), dtype=self._dtype - ) + obs_tensor = torch.tensor(observation.flat_value, dtype=self._dtype) action_probs = model.network(obs_tensor) - if event.observation.observation.HasField("action_mask"): - action_mask = torch.tensor( - flatten_mask(action_space, event.observation.observation.action_mask), dtype=self._dtype - ) + action_mask = observation.action_mask + if action_mask is not None: + action_mask_tensor = torch.tensor(action_mask, dtype=self._dtype) large = torch.finfo(self._dtype).max - if torch.equal(action_mask, torch.zeros_like(action_mask)): + if torch.equal(action_mask_tensor, torch.zeros_like(action_mask_tensor)): log.info("no moves are available, this shouldn't be possible") - action_probs = action_probs - large * (1 - action_mask) + action_probs = action_probs - large * (1 - action_mask_tensor) discrete_action_tensor = torch.argmax(action_probs) - action_value = SpaceValue( - properties=[SpaceValue.PropertyValue(discrete=discrete_action_tensor.item())] - ) + action = action_space.create(value=discrete_action_tensor.item()) - actor_session.do_action(PlayerAction(value=action_value)) + actor_session.do_action(action_space.serialize(action)) class SimpleDQNTraining: @@ -227,7 +209,9 @@ async def sample_producer_impl(self, sample_producer_session): player_actor_params = sample_producer_session.trial_info.parameters.actors[0] player_actor_name = player_actor_params.name - player_observation_space = player_actor_params.config.environment_specs.observation_space + player_environment_specs = EnvironmentSpecs.deserialize(player_actor_params.config.environment_specs) + player_observation_space = player_environment_specs.get_observation_space() + player_action_space = player_environment_specs.get_action_space() observation = None action = None @@ -242,7 +226,7 @@ async def sample_producer_impl(self, sample_producer_session): continue next_observation = torch.tensor( - flatten(player_observation_space, actor_sample.observation.value), dtype=self._dtype + player_observation_space.deserialize(actor_sample.observation).flat_value, dtype=self._dtype ) if observation is not None: @@ -262,10 +246,8 @@ async def sample_producer_impl(self, sample_producer_session): break observation = next_observation - action_value = actor_sample.action.value - action = torch.tensor( - action_value.properties[0].discrete if len(action_value.properties) > 0 else 0, dtype=torch.int64 - ) + action_value = player_action_space.deserialize(actor_sample.action).value + action = torch.tensor(action_value, dtype=torch.int64) reward = torch.tensor(actor_sample.reward if actor_sample.reward is not None else 0, dtype=self._dtype) total_reward += reward.item() @@ -274,8 +256,9 @@ async def impl(self, run_session): model_id = f"{run_session.run_id}_model" assert self._environment_specs.num_players == 1 - assert len(self._environment_specs.action_space.properties) == 1 - assert self._environment_specs.action_space.properties[0].WhichOneof("type") == "discrete" + action_space = self._environment_specs.get_action_space() + observation_space = self._environment_specs.get_observation_space() + assert isinstance(action_space.gym_space, Discrete) epsilon_schedule = create_linear_schedule( self._cfg.epsilon_schedule_start, @@ -286,8 +269,8 @@ async def impl(self, run_session): model = SimpleDQNModel( model_id, environment_implementation=self._environment_specs.implementation, - num_input=flattened_dimensions(self._environment_specs.observation_space), - num_output=flattened_dimensions(self._environment_specs.action_space), + num_input=utils.flatdim(observation_space.gym_space), + num_output=utils.flatdim(action_space.gym_space), num_hidden_nodes=self._cfg.value_network.num_hidden_nodes, epsilon=epsilon_schedule(0), dtype=self._dtype, @@ -311,7 +294,7 @@ async def impl(self, run_session): replay_buffer = TorchReplayBuffer( capacity=self._cfg.buffer_size, - observation_shape=(flattened_dimensions(self._environment_specs.observation_space),), + observation_shape=(utils.flatdim(observation_space.gym_space),), observation_dtype=self._dtype, action_shape=(1,), action_dtype=torch.int64, @@ -347,7 +330,7 @@ async def impl(self, run_session): model_id=model_id, model_version=-1, model_update_frequency=self._cfg.model_update_frequency, - environment_specs=self._environment_specs, + environment_specs=self._environment_specs.serialize(), ), ) ], @@ -456,14 +439,20 @@ def __init__(self, environment_specs, cfg): async def sample_producer_impl(self, sample_producer_session): players_params = { - actor_params.name: actor_params + actor_params.name: { + "params": actor_params, + "observation_space": EnvironmentSpecs.deserialize( + actor_params.config.environment_specs + ).get_observation_space(), + "action_space": EnvironmentSpecs.deserialize(actor_params.config.environment_specs).get_action_space(), + } for actor_params in sample_producer_session.trial_info.parameters.actors if actor_params.class_name == PLAYER_ACTOR_CLASS } players_partial_sample = { - actor_params.name: {"observation": None, "action": None, "reward": None, "total_reward": 0} - for actor_params in players_params.values() + player_params["params"].name: {"observation": None, "action": None, "reward": None, "total_reward": 0} + for player_params in players_params.values() } # Let's start with any player actor @@ -481,10 +470,7 @@ async def sample_producer_impl(self, sample_producer_session): current_player_sample = sample.actors_data[current_player_actor] next_observation = torch.tensor( - flatten( - current_player_params.config.environment_specs.observation_space, - current_player_sample.observation.value, - ), + current_player_params["observation_space"].deserialize(current_player_sample.observation).flat_value, dtype=self._dtype, ) @@ -509,9 +495,10 @@ async def sample_producer_impl(self, sample_producer_session): break current_player_partial_sample["observation"] = next_observation - action_value = current_player_sample.action.value + action_value = current_player_params["action_space"].deserialize(current_player_sample.action).value current_player_partial_sample["action"] = torch.tensor( - action_value.properties[0].discrete if len(action_value.properties) > 0 else 0, dtype=torch.int64 + action_value, + dtype=torch.int64, ) for player_actor in players_params.keys(): player_partial_sample = players_partial_sample[player_actor] @@ -528,8 +515,9 @@ async def impl(self, run_session): model_id = f"{run_session.run_id}_model" assert self._environment_specs.num_players == 2 - assert len(self._environment_specs.action_space.properties) == 1 - assert self._environment_specs.action_space.properties[0].WhichOneof("type") == "discrete" + action_space = self._environment_specs.get_action_space() + observation_space = self._environment_specs.get_observation_space() + assert isinstance(action_space.gym_space, Discrete) epsilon_schedule = create_linear_schedule( self._cfg.epsilon_schedule_start, @@ -540,8 +528,8 @@ async def impl(self, run_session): model = SimpleDQNModel( model_id, environment_implementation=self._environment_specs.implementation, - num_input=flattened_dimensions(self._environment_specs.observation_space), - num_output=flattened_dimensions(self._environment_specs.action_space), + num_input=utils.flatdim(observation_space.gym_space), + num_output=utils.flatdim(action_space.gym_space), num_hidden_nodes=self._cfg.value_network.num_hidden_nodes, epsilon=epsilon_schedule(0), dtype=self._dtype, @@ -565,7 +553,7 @@ async def impl(self, run_session): replay_buffer = TorchReplayBuffer( capacity=self._cfg.buffer_size, - observation_shape=(flattened_dimensions(self._environment_specs.observation_space),), + observation_shape=(utils.flatdim(observation_space.gym_space),), observation_dtype=self._dtype, action_shape=(1,), action_dtype=torch.int64, @@ -582,7 +570,7 @@ def create_actor_params(name, version_number=-1, human=False): implementation=HUMAN_ACTOR_IMPL, config=AgentConfig( run_id=run_session.run_id, - environment_specs=self._environment_specs, + environment_specs=self._environment_specs.serialize(), ), ) return cogment.ActorParameters( @@ -598,7 +586,7 @@ def create_actor_params(name, version_number=-1, human=False): model_id=model_id, model_version=version_number, model_update_frequency=self._cfg.model_update_frequency, - environment_specs=self._environment_specs, + environment_specs=self._environment_specs.serialize(), ), ) diff --git a/actors/td3.py b/actors/td3.py index b76dd8e6..b6704128 100644 --- a/actors/td3.py +++ b/actors/td3.py @@ -12,15 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -# pylint: disable=C0103 -# pylint: disable=W0613 -# pylint: disable=W0221 -# pylint: disable=W0212 -# pylint: disable=W0622 -# pylint: disable=R0402 -# pylint: disable=W0612 -# pylint: disable=W0611 -# pylint: disable=E0611 +# pylint: disable=invalid-name import logging import copy @@ -28,21 +20,12 @@ import numpy as np import cogment import torch -import torch.nn as nn +from torch import nn import torch.nn.functional as F -from cogment_verse.specs import ( - AgentConfig, - cog_settings, - EnvironmentConfig, - flatten, - flattened_dimensions, - PLAYER_ACTOR_CLASS, - PlayerAction, - SpaceValue, - sample_space, - NDArray, -) +from gym.spaces import utils, Box + +from cogment_verse.specs import AgentConfig, cog_settings, EnvironmentConfig, EnvironmentSpecs, PLAYER_ACTOR_CLASS from cogment_verse import Model, TorchReplayBuffer torch.multiprocessing.set_sharing_strategy("file_system") @@ -50,16 +33,6 @@ log = logging.getLogger(__name__) -def proto_array_from_np_array(arr): - return NDArray(shape=arr.shape, dtype=str(arr.dtype), data=arr.tobytes()) - - -def np_array_from_proto_array(arr): - # print("arr = ", arr) - dtype = arr.dtype or "int8" # default type for empty array - return np.frombuffer(arr.data, dtype=dtype).reshape(*arr.shape) - - class Actor(nn.Module): def __init__(self, state_dim, action_dim, max_action): super().__init__() @@ -130,7 +103,7 @@ def __init__( self._environment_implementation = environment_implementation self._num_input = num_input self._num_output = num_output - self._max_action = max_action + self.max_action = max_action self.time_steps = time_steps self.expl_noise = expl_noise self.random_steps = random_steps @@ -150,7 +123,7 @@ def get_model_user_data(self): "environment_implementation": self._environment_implementation, "num_input": self._num_input, "num_output": self._num_output, - "max_action": self._max_action, + "max_action": self.max_action, "expl_noise": self.expl_noise, "random_steps": self.random_steps, } @@ -214,14 +187,12 @@ async def impl(self, actor_session): actor_session.start() config = actor_session.config - # print("config = ", config) - assert config.environment_specs.num_players == 1 - assert len(config.environment_specs.action_space.properties) == 1 - assert config.environment_specs.action_space.properties[0].WhichOneof("type") == "box" + environment_specs = EnvironmentSpecs.deserialize(config.environment_specs) + observation_space = environment_specs.get_observation_space() + action_space = environment_specs.get_action_space(seed=config.seed) - observation_space = config.environment_specs.observation_space - action_space = config.environment_specs.action_space + assert isinstance(action_space.gym_space, Box) model, _, _ = await actor_session.model_registry.retrieve_version( TD3Model, config.model_id, config.model_version @@ -229,24 +200,20 @@ async def impl(self, actor_session): async for event in actor_session.all_events(): if event.observation and event.type == cogment.EventType.ACTIVE: - if model.time_steps < model.random_steps: - [action_value] = sample_space(action_space) - action_value = SpaceValue(properties=[action_value.properties[0]]) + observation = observation_space.deserialize(event.observation.observation) + if model.time_steps < model.random_steps: + action = action_space.sample() else: - obs_tensor = torch.tensor( - flatten(observation_space, event.observation.observation.value), dtype=self._dtype - ) - action_value = model.actor(obs_tensor) - action_value = action_value.cpu().detach().numpy() - action_value = action_value + np.random.normal( - 0, model._max_action * model.expl_noise, size=2 - ) # adding exploration noise + observation = torch.tensor(observation.value, dtype=self._dtype) + action = model.actor(observation) + action = action.cpu().detach().numpy() + # adding exploration noise + action = action + np.random.normal(0, model.max_action * model.expl_noise, size=2) - action_value = proto_array_from_np_array(action_value) - action_value = SpaceValue(properties=[SpaceValue.PropertyValue(box=action_value)]) + action = action_space.create(value=action) - actor_session.do_action(PlayerAction(value=action_value)) + actor_session.do_action(action_space.serialize(action)) class TD3Training: @@ -274,7 +241,9 @@ async def sample_producer_impl(self, sample_producer_session): player_actor_params = sample_producer_session.trial_info.parameters.actors[0] player_actor_name = player_actor_params.name - player_observation_space = player_actor_params.config.environment_specs.observation_space + player_environment_specs = EnvironmentSpecs.deserialize(player_actor_params.config.environment_specs) + player_observation_space = player_environment_specs.get_observation_space() + player_action_space = player_environment_specs.get_action_space() observation = None action = None @@ -288,7 +257,7 @@ async def sample_producer_impl(self, sample_producer_session): continue next_observation = torch.tensor( - flatten(player_observation_space, actor_sample.observation.value), dtype=self._dtype + player_observation_space.deserialize(actor_sample.observation).flat_value, dtype=self._dtype ) if observation is not None: @@ -308,25 +277,23 @@ async def sample_producer_impl(self, sample_producer_session): break observation = next_observation - action_value = actor_sample.action.value - action_value = np_array_from_proto_array(action_value.properties[0].box) - action = torch.tensor(action_value, dtype=torch.float) + action = torch.tensor(player_action_space.deserialize(actor_sample.action).value, dtype=self._dtype) reward = torch.tensor(actor_sample.reward if actor_sample.reward is not None else 0, dtype=self._dtype) total_reward += reward.item() async def impl(self, run_session): # Initializing a model model_id = f"{run_session.run_id}_model" + assert self._environment_specs.num_players == 1 - assert len(self._environment_specs.action_space.properties) == 1 - assert self._environment_specs.action_space.properties[0].WhichOneof("type") == "box" + assert isinstance(self._environment_specs.get_action_space().gym_space, Box) model = TD3Model( model_id, environment_implementation=self._environment_specs.implementation, - num_input=flattened_dimensions(self._environment_specs.observation_space), - num_output=flattened_dimensions(self._environment_specs.action_space), - max_action=float(self._environment_specs.action_space.properties[0].box.high[0].bound), + num_input=utils.flatdim(self._environment_specs.get_observation_space().gym_space), + num_output=utils.flatdim(self._environment_specs.get_action_space().gym_space), + max_action=float(self._environment_specs.get_action_space().gym_space.high[0]), expl_noise=float(self._cfg.expl_noise), random_steps=int(self._cfg.random_steps), time_steps=0, @@ -346,14 +313,15 @@ async def impl(self, run_session): replay_buffer = TorchReplayBuffer( capacity=self._cfg.buffer_size, - observation_shape=(flattened_dimensions(self._environment_specs.observation_space),), + observation_shape=(utils.flatdim(self._environment_specs.get_observation_space().gym_space),), observation_dtype=self._dtype, - action_shape=(flattened_dimensions(self._environment_specs.action_space),), + action_shape=(utils.flatdim(self._environment_specs.get_action_space().gym_space),), action_dtype=self._dtype, # check reward_dtype=self._dtype, seed=self._cfg.seed, ) - # start_time = time.time() + + start_time = time.time() total_reward_cum = 0 for (step_idx, _trial_id, trial_idx, sample,) in run_session.start_and_await_trials( @@ -381,7 +349,7 @@ async def impl(self, run_session): model_id=model_id, model_version=-1, model_update_frequency=self._cfg.policy_freq, - environment_specs=self._environment_specs, + environment_specs=self._environment_specs.serialize(), ), ) ], @@ -417,7 +385,7 @@ async def impl(self, run_session): -self._cfg.noise_clip, self._cfg.noise_clip ) next_action = (model.actor_target(data.next_observation) + noise).clamp( - -model._max_action, model._max_action + -model.max_action, model.max_action ) # Compute the target Q value @@ -455,21 +423,26 @@ async def impl(self, run_session): for param, target_param in zip(model.actor.parameters(), model.actor_target.parameters()): target_param.data.copy_(self._cfg.tau * param.data + (1 - self._cfg.tau) * target_param.data) + run_session.log_metrics(loss=actor_loss.item()) + # Update the version info model.total_samples += data.size() + if step_idx % 100 == 0: + run_session.log_metrics( + batch_avg_reward=data.reward.mean().item(), + ) + model.time_steps += 1 version_info = await run_session.model_registry.publish_version(model) - # if step_idx % 100 == 0: - # end_time = time.time() - # steps_per_seconds = 100 / (end_time - start_time) - # start_time = end_time - # run_session.log_metrics( - # model_version_number=version_info["version_number"], - # loss=actor_loss.item(), - # batch_avg_reward=data.reward.mean().item(), - # steps_per_seconds=steps_per_seconds, - # ) + if step_idx % 100 == 0: + end_time = time.time() + steps_per_seconds = 100 / (end_time - start_time) + start_time = end_time + run_session.log_metrics( + model_version_number=version_info["version_number"], + steps_per_seconds=steps_per_seconds, + ) version_info = await run_session.model_registry.publish_version(model, archived=True) diff --git a/actors/tutorial/tutorial_1.py b/actors/tutorial/tutorial_1.py index 549b01d8..a5f3be37 100644 --- a/actors/tutorial/tutorial_1.py +++ b/actors/tutorial/tutorial_1.py @@ -20,10 +20,9 @@ AgentConfig, cog_settings, EnvironmentConfig, + EnvironmentSpecs, HUMAN_ACTOR_IMPL, PLAYER_ACTOR_CLASS, - PlayerAction, - sample_space, TEACHER_ACTOR_CLASS, WEB_ACTOR_NAME, ) @@ -43,10 +42,13 @@ async def impl(self, actor_session): config = actor_session.config + environment_specs = EnvironmentSpecs.deserialize(config.environment_specs) + action_space = environment_specs.get_action_space(seed=config.seed) + async for event in actor_session.all_events(): if event.observation and event.type == cogment.EventType.ACTIVE: - [action_value] = sample_space(config.environment_specs.action_space) - actor_session.do_action(PlayerAction(value=action_value)) + action = action_space.sample() + actor_session.do_action(action_space.serialize(action)) class SimpleBCTraining: @@ -78,10 +80,13 @@ async def sample_producer(self, sample_producer_session): player_params = players_params[0] teacher_params = teachers_params[0] + environment_specs = EnvironmentSpecs.deserialize(player_params.config.environment_specs) + action_space = environment_specs.get_action_space() + async for sample in sample_producer_session.all_trial_samples(): - teacher_action = sample.actors_data[teacher_params.name].action + teacher_action = action_space.deserialize(sample.actors_data[teacher_params.name].action) - if teacher_action.HasField("value"): + if teacher_action.flat_value is not None: log.info(f"Got raw sample with action override from [{teacher_params.name}]") else: log.info(f"Got raw sample with action from [{player_params.name}]") @@ -103,7 +108,7 @@ def create_trial_params(trial_idx): implementation="actors.tutorial.tutorial_1.SimpleBCActor", config=AgentConfig( run_id=run_session.run_id, - environment_specs=self._environment_specs, + environment_specs=self._environment_specs.serialize(), ), ) @@ -114,7 +119,7 @@ def create_trial_params(trial_idx): implementation=HUMAN_ACTOR_IMPL, config=AgentConfig( run_id=run_session.run_id, - environment_specs=self._environment_specs, + environment_specs=self._environment_specs.serialize(), ), ) diff --git a/actors/tutorial/tutorial_2.py b/actors/tutorial/tutorial_2.py index f9b4c45b..359593fb 100644 --- a/actors/tutorial/tutorial_2.py +++ b/actors/tutorial/tutorial_2.py @@ -25,13 +25,9 @@ AgentConfig, cog_settings, EnvironmentConfig, - ############ TUTORIAL STEP 2 ############ - flatten, - ######################################### + EnvironmentSpecs, HUMAN_ACTOR_IMPL, PLAYER_ACTOR_CLASS, - PlayerAction, - sample_space, TEACHER_ACTOR_CLASS, WEB_ACTOR_NAME, ) @@ -53,10 +49,13 @@ async def impl(self, actor_session): config = actor_session.config + environment_specs = EnvironmentSpecs.deserialize(config.environment_specs) + action_space = environment_specs.get_action_space(seed=config.seed) + async for event in actor_session.all_events(): if event.observation and event.type == cogment.EventType.ACTIVE: - [action_value] = sample_space(config.environment_specs.action_space) - actor_session.do_action(PlayerAction(value=action_value)) + action = action_space.sample() + actor_session.do_action(action_space.serialize(action)) class SimpleBCTraining: @@ -91,31 +90,36 @@ async def sample_producer(self, sample_producer_session): player_params = players_params[0] teacher_params = teachers_params[0] + environment_specs = EnvironmentSpecs.deserialize(player_params.config.environment_specs) + action_space = environment_specs.get_action_space() + ############ TUTORIAL STEP 2 ############ - environment_specs = player_params.config.environment_specs + observation_space = environment_specs.get_observation_space() ######################################### async for sample in sample_producer_session.all_trial_samples(): ############ TUTORIAL STEP 2 ############ observation_tensor = torch.tensor( - flatten(environment_specs.observation_space, sample.actors_data[player_params.name].observation.value), + observation_space.deserialize(sample.actors_data[player_params.name].observation).flat_value, dtype=self._dtype, ) ######################################### - teacher_action = sample.actors_data[teacher_params.name].action + teacher_action = action_space.deserialize(sample.actors_data[teacher_params.name].action) - ############ TUTORIAL STEP 2 ############ - if teacher_action.HasField("value"): + if teacher_action.flat_value is not None: + ############ TUTORIAL STEP 2 ############ applied_action = teacher_action demonstration = True else: - applied_action = sample.actors_data[player_params.name].action + applied_action = action_space.deserialize(sample.actors_data[player_params.name].action) demonstration = False - action_tensor = torch.tensor( - flatten(environment_specs.action_space, applied_action.value), dtype=self._dtype - ) + if applied_action.flat_value is None: + # TODO figure out why we get into this situation + continue + + action_tensor = torch.tensor(applied_action.flat_value, dtype=self._dtype) sample_producer_session.produce_sample((demonstration, observation_tensor, action_tensor)) ######################################### @@ -138,7 +142,7 @@ def create_trial_params(trial_idx): ######################################### config=AgentConfig( run_id=run_session.run_id, - environment_specs=self._environment_specs, + environment_specs=self._environment_specs.serialize(), ), ) @@ -149,7 +153,7 @@ def create_trial_params(trial_idx): implementation=HUMAN_ACTOR_IMPL, config=AgentConfig( run_id=run_session.run_id, - environment_specs=self._environment_specs, + environment_specs=self._environment_specs.serialize(), ), ) diff --git a/actors/tutorial/tutorial_3.py b/actors/tutorial/tutorial_3.py index 53f4569f..30c398a7 100644 --- a/actors/tutorial/tutorial_3.py +++ b/actors/tutorial/tutorial_3.py @@ -18,23 +18,19 @@ import torch ############ TUTORIAL STEP 3 ############ +from gym.spaces import utils + from cogment_verse import Model ######################################### + from cogment_verse.specs import ( AgentConfig, cog_settings, EnvironmentConfig, - flatten, - ############ TUTORIAL STEP 3 ############ - flattened_dimensions, - ######################################### + EnvironmentSpecs, HUMAN_ACTOR_IMPL, PLAYER_ACTOR_CLASS, - PlayerAction, - ############ TUTORIAL STEP 3 ############ - SpaceValue, - ######################################### TEACHER_ACTOR_CLASS, WEB_ACTOR_NAME, ) @@ -127,7 +123,9 @@ async def impl(self, actor_session): config = actor_session.config ############ TUTORIAL STEP 3 ############ - observation_space = config.environment_specs.observation_space + environment_specs = EnvironmentSpecs.deserialize(config.environment_specs) + action_space = environment_specs.get_action_space(seed=config.seed) + observation_space = environment_specs.get_observation_space() model, _model_info, version_info = await actor_session.model_registry.retrieve_version( SimpleBCModel, config.model_id, config.model_version @@ -141,15 +139,14 @@ async def impl(self, actor_session): async for event in actor_session.all_events(): if event.observation and event.type == cogment.EventType.ACTIVE: ############ TUTORIAL STEP 3 ############ - observation_tensor = torch.tensor( - flatten(observation_space, event.observation.observation.value), dtype=self._dtype - ) + observation = observation_space.deserialize(event.observation.observation) + observation_tensor = torch.tensor(observation.flat_value, dtype=self._dtype) scores = model.policy_network(observation_tensor.view(1, -1)) probs = torch.softmax(scores, dim=-1) discrete_action_tensor = torch.distributions.Categorical(probs).sample() - action_value = SpaceValue(properties=[SpaceValue.PropertyValue(discrete=discrete_action_tensor.item())]) + action = action_space.create(value=discrete_action_tensor.item()) ########################################## - actor_session.do_action(PlayerAction(value=action_value)) + actor_session.do_action(action_space.serialize(action)) class SimpleBCTraining: @@ -185,25 +182,30 @@ async def sample_producer(self, sample_producer_session): player_params = players_params[0] teacher_params = teachers_params[0] - environment_specs = player_params.config.environment_specs + environment_specs = EnvironmentSpecs.deserialize(player_params.config.environment_specs) + action_space = environment_specs.get_action_space() + observation_space = environment_specs.get_observation_space() async for sample in sample_producer_session.all_trial_samples(): observation_tensor = torch.tensor( - flatten(environment_specs.observation_space, sample.actors_data[player_params.name].observation.value), + observation_space.deserialize(sample.actors_data[player_params.name].observation).flat_value, dtype=self._dtype, ) - teacher_action = sample.actors_data[teacher_params.name].action - if teacher_action.HasField("value"): + teacher_action = action_space.deserialize(sample.actors_data[teacher_params.name].action) + + if teacher_action.flat_value is not None: applied_action = teacher_action demonstration = True else: - applied_action = sample.actors_data[player_params.name].action + applied_action = action_space.deserialize(sample.actors_data[player_params.name].action) demonstration = False - action_tensor = torch.tensor( - flatten(environment_specs.action_space, applied_action.value), dtype=self._dtype - ) + if applied_action.flat_value is None: + # TODO figure out why we get into this situation + continue + + action_tensor = torch.tensor(applied_action.flat_value, dtype=self._dtype) sample_producer_session.produce_sample((demonstration, observation_tensor, action_tensor)) async def impl(self, run_session): @@ -216,8 +218,8 @@ async def impl(self, run_session): model = SimpleBCModel( model_id, environment_implementation=self._environment_specs.implementation, - num_input=flattened_dimensions(self._environment_specs.observation_space), - num_output=flattened_dimensions(self._environment_specs.action_space), + num_input=utils.flatdim(self._environment_specs.get_observation_space().gym_space), + num_output=utils.flatdim(self._environment_specs.get_action_space().gym_space), policy_network_num_hidden_nodes=self._cfg.policy_network.num_hidden_nodes, ) _model_info, _version_info = await run_session.model_registry.publish_initial_version(model) @@ -242,7 +244,7 @@ def create_trial_params(trial_idx): ######################################### config=AgentConfig( run_id=run_session.run_id, - environment_specs=self._environment_specs, + environment_specs=self._environment_specs.serialize(), ############ TUTORIAL STEP 3 ############ model_id=model_id, model_version=-1, @@ -257,7 +259,7 @@ def create_trial_params(trial_idx): implementation=HUMAN_ACTOR_IMPL, config=AgentConfig( run_id=run_session.run_id, - environment_specs=self._environment_specs, + environment_specs=self._environment_specs.serialize(), ), ) diff --git a/actors/tutorial/tutorial_4.py b/actors/tutorial/tutorial_4.py index b64c1ab9..9d545a35 100644 --- a/actors/tutorial/tutorial_4.py +++ b/actors/tutorial/tutorial_4.py @@ -22,17 +22,16 @@ ######################################### +from gym.spaces import utils + from cogment_verse import Model from cogment_verse.specs import ( AgentConfig, cog_settings, EnvironmentConfig, - flatten, - flattened_dimensions, + EnvironmentSpecs, HUMAN_ACTOR_IMPL, PLAYER_ACTOR_CLASS, - PlayerAction, - SpaceValue, TEACHER_ACTOR_CLASS, WEB_ACTOR_NAME, ) @@ -119,7 +118,9 @@ async def impl(self, actor_session): config = actor_session.config - observation_space = config.environment_specs.observation_space + environment_specs = EnvironmentSpecs.deserialize(config.environment_specs) + observation_space = environment_specs.get_observation_space() + action_space = environment_specs.get_action_space(seed=config.seed) model, _model_info, version_info = await actor_session.model_registry.retrieve_version( SimpleBCModel, config.model_id, config.model_version @@ -131,14 +132,13 @@ async def impl(self, actor_session): async for event in actor_session.all_events(): if event.observation and event.type == cogment.EventType.ACTIVE: - observation_tensor = torch.tensor( - flatten(observation_space, event.observation.observation.value), dtype=self._dtype - ) + observation = observation_space.deserialize(event.observation.observation) + observation_tensor = torch.tensor(observation.flat_value, dtype=self._dtype) scores = model.policy_network(observation_tensor.view(1, -1)) probs = torch.softmax(scores, dim=-1) discrete_action_tensor = torch.distributions.Categorical(probs).sample() - action_value = SpaceValue(properties=[SpaceValue.PropertyValue(discrete=discrete_action_tensor.item())]) - actor_session.do_action(PlayerAction(value=action_value)) + action = action_space.create(value=discrete_action_tensor.item()) + actor_session.do_action(action_space.serialize(action)) class SimpleBCTraining: @@ -178,25 +178,30 @@ async def sample_producer(self, sample_producer_session): player_params = players_params[0] teacher_params = teachers_params[0] - environment_specs = player_params.config.environment_specs + environment_specs = EnvironmentSpecs.deserialize(player_params.config.environment_specs) + action_space = environment_specs.get_action_space() + observation_space = environment_specs.get_observation_space() async for sample in sample_producer_session.all_trial_samples(): observation_tensor = torch.tensor( - flatten(environment_specs.observation_space, sample.actors_data[player_params.name].observation.value), + observation_space.deserialize(sample.actors_data[player_params.name].observation).flat_value, dtype=self._dtype, ) - teacher_action = sample.actors_data[teacher_params.name].action - if teacher_action.HasField("value"): + teacher_action = action_space.deserialize(sample.actors_data[teacher_params.name].action) + + if teacher_action.flat_value is not None: applied_action = teacher_action demonstration = True else: - applied_action = sample.actors_data[player_params.name].action + applied_action = action_space.deserialize(sample.actors_data[player_params.name].action) demonstration = False - action_tensor = torch.tensor( - flatten(environment_specs.action_space, applied_action.value), dtype=self._dtype - ) + if applied_action.flat_value is None: + # TODO figure out why we get into this situation + continue + + action_tensor = torch.tensor(applied_action.flat_value, dtype=self._dtype) sample_producer_session.produce_sample((demonstration, observation_tensor, action_tensor)) async def impl(self, run_session): @@ -208,8 +213,8 @@ async def impl(self, run_session): model = SimpleBCModel( model_id, environment_implementation=self._environment_specs.implementation, - num_input=flattened_dimensions(self._environment_specs.observation_space), - num_output=flattened_dimensions(self._environment_specs.action_space), + num_input=utils.flatdim(self._environment_specs.get_observation_space().gym_space), + num_output=utils.flatdim(self._environment_specs.get_action_space().gym_space), policy_network_num_hidden_nodes=self._cfg.policy_network.num_hidden_nodes, ) _model_info, _version_info = await run_session.model_registry.publish_initial_version(model) @@ -231,7 +236,7 @@ def create_trial_params(trial_idx): ######################################### config=AgentConfig( run_id=run_session.run_id, - environment_specs=self._environment_specs, + environment_specs=self._environment_specs.serialize(), model_id=model_id, model_version=-1, ), @@ -244,7 +249,7 @@ def create_trial_params(trial_idx): implementation=HUMAN_ACTOR_IMPL, config=AgentConfig( run_id=run_session.run_id, - environment_specs=self._environment_specs, + environment_specs=self._environment_specs.serialize(), ), ) diff --git a/cogment_verse/processes/environment.py b/cogment_verse/processes/environment.py index 8bfd5368..6f5b0093 100644 --- a/cogment_verse/processes/environment.py +++ b/cogment_verse/processes/environment.py @@ -38,7 +38,7 @@ def environment_main( ): # Importing 'specs' only in the subprocess (i.e. where generate has been properly executed) # pylint: disable-next=import-outside-toplevel - from cogment_verse.specs import cog_settings, save_environment_specs + from cogment_verse.specs import cog_settings environment_cls = import_class(environment_cfg.class_name) env = environment_cls(environment_cfg) @@ -46,7 +46,7 @@ def environment_main( env_implementation_name = get_implementation_name(env) # Generate the environment specs if needed. - save_environment_specs(work_dir, env_implementation_name, env.get_environment_specs()) + env.get_environment_specs().save(work_dir, env_implementation_name) async def environment_main_async(): context = cogment.Context(cog_settings=cog_settings, user_id="cogment_verse_environment") diff --git a/cogment_verse/processes/run.py b/cogment_verse/processes/run.py index f1fcb4eb..56dfaf67 100644 --- a/cogment_verse/processes/run.py +++ b/cogment_verse/processes/run.py @@ -38,7 +38,7 @@ def run_main( async def run_main_async(): # Importing 'specs' only in the subprocess (i.e. where generate has been properly executed) # pylint: disable-next=import-outside-toplevel - from cogment_verse.specs import load_environment_specs + from cogment_verse.specs import EnvironmentSpecs _run_cfg = run_cfg run_cls = import_class(_run_cfg.class_name) @@ -49,7 +49,7 @@ async def run_main_async(): enviroment_impl_name = _run_cfg.get("environment", registered_enviroment_impl_names[0]) try: - environment_specs = load_environment_specs(work_dir, enviroment_impl_name) + environment_specs = EnvironmentSpecs.load(work_dir, enviroment_impl_name) except Exception as error: raise RuntimeError(f"Unable to start run, unknown environment: '{enviroment_impl_name}'") from error diff --git a/cogment_verse/specs/__init__.py b/cogment_verse/specs/__init__.py index 0e403858..0fdaa155 100644 --- a/cogment_verse/specs/__init__.py +++ b/cogment_verse/specs/__init__.py @@ -15,13 +15,6 @@ from data_pb2 import ( # pylint: disable=import-error AgentConfig, EnvironmentConfig, - EnvironmentSpecs, - Observation, - PlayerAction, - Space, - SpaceMask, - SpaceValue, - NDArray, ) import cog_settings # pylint: disable=import-error from cogment_verse.constants import ( @@ -32,14 +25,5 @@ OBSERVER_ACTOR_CLASS, ) -from .environment_specs import save_environment_specs, load_environment_specs +from .environment_specs import EnvironmentSpecs from .encode_rendered_frame import encode_rendered_frame -from .ndarray import deserialize_ndarray, serialize_ndarray -from .sample_space import sample_space -from .flatten import flattened_dimensions, flatten, unflatten, flatten_mask -from .gym_spaces_adapter import ( - gym_action_from_action, - gym_space_from_space, - observation_from_gym_observation, - space_from_gym_space, -) diff --git a/cogment_verse/specs/action_space.py b/cogment_verse/specs/action_space.py new file mode 100644 index 00000000..b3d8369b --- /dev/null +++ b/cogment_verse/specs/action_space.py @@ -0,0 +1,136 @@ +# Copyright 2022 AI Redefined Inc. +# +# 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. + +from gym.spaces import utils + +from data_pb2 import PlayerAction, TeacherAction, ObserverAction # pylint: disable=import-error + +from .ndarray_serialization import serialize_ndarray, deserialize_ndarray + +from ..constants import TEACHER_ACTOR_CLASS, PLAYER_ACTOR_CLASS, OBSERVER_ACTOR_CLASS + +ACTOR_CLASS_ACTION_CLASS = { + TEACHER_ACTOR_CLASS: TeacherAction, + PLAYER_ACTOR_CLASS: PlayerAction, + OBSERVER_ACTOR_CLASS: ObserverAction, +} + +# pylint: disable=attribute-defined-outside-init +class Action: + """ + Cogment Verse actor action + + Properties: + flat_value: + The action value, as a flat numpy array. + value: + The action value, as a numpy array. + """ + + def __init__(self, gym_space, pb_action=None, value=None): + """ + Action constructor. + Shouldn't be called directly, prefer the factory function of ActionSpace. + """ + self._gym_space = gym_space + + if pb_action is not None: + assert value is None + self._pb_action = pb_action + return + + self._value = value + + def _compute_flat_value(self): + if hasattr(self, "_value"): + value = self._value + if value is None: + return None + return utils.flatten(self._gym_space, self._value) + + if not self._pb_action.HasField("value"): + # This happens whenever value is None + return None + + return deserialize_ndarray(self._pb_action.value) + + @property + def flat_value(self): + if not hasattr(self, "_flat_value"): + self._flat_value = self._compute_flat_value() + return self._flat_value + + def _compute_value(self): + flat_value = self.flat_value + if flat_value is None: + return None + return utils.unflatten(self._gym_space, flat_value) + + @property + def value(self): + if not hasattr(self, "_value"): + self._value = self._compute_value() + return self._value + + +class ActionSpace: + """ + Cogment Verse action space + + Properties: + gym_space: + Wrapped Gym space for the action values (cf. https://www.gymlibrary.dev/api/spaces/) + actor_class: + Class of the actor for which this space will serialize Action probobug messages + seed: + Random seed used when generating random actions + """ + + def __init__(self, gym_space, actor_class=PLAYER_ACTOR_CLASS, seed=None): + self.gym_space = gym_space + self._action_class = ACTOR_CLASS_ACTION_CLASS[actor_class] + + if seed: + self.gym_space.seed(int(seed)) + + def create(self, value=None): + """ + Create an Action + """ + return Action(self.gym_space, value=value) + + def sample(self, mask=None): + """ + Generate a random Action + """ + return Action(self.gym_space, value=self.gym_space.sample(mask=mask)) + + def serialize( + self, + action, + ): + """ + Serialize an Action to an Action protobuf message + """ + if action.value is None: + return self._action_class() + + serialized_value = serialize_ndarray(action.flat_value) + return self._action_class(value=serialized_value) + + def deserialize(self, pb_action): + """ + Deserialize an Action from an Action protobuf message + """ + return Action(self.gym_space, pb_action=pb_action) diff --git a/cogment_verse/specs/cogment.yaml b/cogment_verse/specs/cogment.yaml index dae4bda4..d86defc4 100644 --- a/cogment_verse/specs/cogment.yaml +++ b/cogment_verse/specs/cogment.yaml @@ -1,5 +1,7 @@ import: proto: + - ndarray.proto + - spaces.proto - data.proto environment: diff --git a/cogment_verse/specs/data.proto b/cogment_verse/specs/data.proto index 30d78b1a..f183f9ed 100644 --- a/cogment_verse/specs/data.proto +++ b/cogment_verse/specs/data.proto @@ -16,68 +16,15 @@ syntax = "proto3"; package cogment_verse; -message NDArray { - string dtype = 1; - repeated uint32 shape = 2; - bytes data = 3; -} - -// Space messages are used to define environments action or observation space -// Similar to gym's "dict" space -message Space { - message Discrete { - int32 num = 1; - repeated string labels = 2; // Define labels for the discrete elements in the space, overrides `num` - } - message Bound { - optional float bound = 1; // value of the bound, not set means unbounded - } - message Box { - repeated uint32 shape = 1; - repeated Bound low = 2; // independant lower bounds for each dimensions (gets reshaped) - repeated Bound high = 3; // independant upper bounds for each dimensions (gets reshaped) - } - message Property { - string key = 1; - oneof type { - Discrete discrete = 2; - Box box = 3; - } - } - repeated Property properties = 1; -} - -// SpaceValue messages are values within a Space -// `properties` are sorted in the same way than the value's Space -message SpaceValue { - message SimpleBox { - repeated float values = 1; - } - message PropertyValue { - oneof value { - int32 discrete = 1; - NDArray box = 2; - SimpleBox simple_box = 3; - } - } - repeated PropertyValue properties = 1; -} - -// SpaceMask messages are value masks within a space -// `properties` are sorted in the same way than the value's Space -message SpaceMask { - message PropertyMask { - repeated int32 discrete = 1; // The discrete actions that are valid - } - repeated PropertyMask properties = 1; -} +import "ndarray.proto"; +import "spaces.proto"; message EnvironmentSpecs { string implementation = 1; bool turn_based = 2; int32 num_players = 3; - Space observation_space = 4; - Space action_space = 5; + spaces.Space observation_space = 4; + spaces.Space action_space = 5; } message EnvironmentConfig { @@ -86,9 +33,6 @@ message EnvironmentConfig { int32 render_width = 3; uint32 seed = 4; bool flatten = 5; - - // uint32 framestack = 8; - // string mode = 10; } message HFHubModel { @@ -103,34 +47,25 @@ message AgentConfig { string model_id = 4; int32 model_version = 5; int32 model_update_frequency = 6; - // int32 actor_index = 6; // Used to figure out if an agent is the current_player in the observation space - // string device = 7; - // uint32 threads_per_worker = 8; - // HFHubModel hf_hub_model = 9; } message TrialConfig { } message Observation { - SpaceValue value = 1; + nd_array.Array value = 1; optional string current_player = 2; // active player for multi-agent turn-based environments - optional SpaceMask action_mask = 3; + optional nd_array.Array action_mask = 3; optional bytes rendered_frame = 4; repeated string overridden_players = 5; // list of players that provided an action that was overriden during the last tick - //NDArray segmentation = 6; } message PlayerAction { - SpaceValue value = 1; - // NDArray policy = 2; // optional: policy from which action was drawn - // float value = 3; // optional: value of the state from which the action was taken + nd_array.Array value = 1; } message TeacherAction { - optional SpaceValue value = 1; - // NDArray policy = 2; // optional: policy from which action was drawn - // float value = 3; // optional: value of the state from which the action was taken + optional nd_array.Array value = 1; } message ObserverAction { diff --git a/cogment_verse/specs/environment_specs.py b/cogment_verse/specs/environment_specs.py index f1ee0077..9c92995f 100644 --- a/cogment_verse/specs/environment_specs.py +++ b/cogment_verse/specs/environment_specs.py @@ -17,21 +17,121 @@ from google.protobuf.json_format import MessageToDict, ParseDict import yaml -from data_pb2 import EnvironmentSpecs # pylint: disable=import-error +from data_pb2 import EnvironmentSpecs as PbEnvironmentSpecs # pylint: disable=import-error +from .spaces_serialization import serialize_gym_space, deserialize_gym_space +from .observation_space import ObservationSpace +from .action_space import ActionSpace -def save_environment_specs(work_dir, env_name, env_specs): - specs_filename = os.path.join(work_dir, "environment_specs", f"{env_name}.yaml") - os.makedirs(os.path.dirname(specs_filename), exist_ok=True) +from ..constants import PLAYER_ACTOR_CLASS - env_specs.implementation = env_name - with open(specs_filename, "w", encoding="utf-8") as f: - yaml.safe_dump(MessageToDict(env_specs, preserving_proto_field_name=True), f) +class EnvironmentSpecs: + """ + Representation of the specification of an environment within cogment verse + Properties: + implementation: + The name of the implementation for the environment. + num_players: + Number of players supported by the environment. + turn_based: + is this environment turn based (vs real time). + """ -def load_environment_specs(work_dir, env_name): - specs_filename = os.path.join(work_dir, "environment_specs", f"{env_name}.yaml") + def __init__(self, environment_specs_pb): + """ + EnvironmentSpecs constructor. + Shouldn't be called directly, prefer the factory function such as EnvironmentSpecs.deserialize or EnvironmentSpecs.create_homogeneous. + """ + self._pb = environment_specs_pb - with open(specs_filename, "r", encoding="utf-8") as f: - return ParseDict(yaml.safe_load(f), EnvironmentSpecs()) + @property + def implementation(self): + return self._pb.implementation + + @property + def num_players(self): + return self._pb.num_players + + @property + def turn_based(self): + return self._pb.turn_based + + def get_observation_space(self, render_width=1024): + """ + Build an instance of the observation space for this environment + + Parameters: + render_width: optional + maximum width for the serialized rendered frame in observation + + NOTE: In the future we'll want to support different observation space per agent role + """ + return ObservationSpace(deserialize_gym_space(self._pb.observation_space), render_width) + + def get_action_space(self, actor_class=PLAYER_ACTOR_CLASS, seed=None): + """ + Build an instance of the action space for this environment + + Parameters: + actor_class: optional + the class of the actor for which we want to retrieve the action space. + this parameters is mostly useful when serializing actions. + seed: optional + the seed used when generating random actions + + NOTE: In the future we'll want to support different action space per agent roles + """ + return ActionSpace(deserialize_gym_space(self._pb.action_space), actor_class, seed) + + @classmethod + def create_homogeneous(cls, num_players, turn_based, observation_space, action_space): + """ + Factory function building an homogenous EnvironmentSpecs, ie with all actors having the same action and observation spaces. + """ + return cls.deserialize( + PbEnvironmentSpecs( + num_players=num_players, + turn_based=turn_based, + observation_space=serialize_gym_space(observation_space), + action_space=serialize_gym_space(action_space), + ) + ) + + def serialize(self): + """ + Serialize to a EnvironmentSpecs protobuf message + """ + return self._pb + + @classmethod + def deserialize(cls, environment_specs_pb): + """ + Factory function building an EnvironmentSpecs instance from a EnvironmentSpecs protobuf message + """ + return cls(environment_specs_pb) + + @classmethod + def load(cls, work_dir, env_name): + """ + Factory function building an EnvironmentSpecs from cogment_version work dir cache + """ + + specs_filename = os.path.join(work_dir, "environment_specs", f"{env_name}.yaml") + + with open(specs_filename, "r", encoding="utf-8") as f: + return cls.deserialize(ParseDict(yaml.safe_load(f), PbEnvironmentSpecs())) + + def save(self, work_dir, env_name): + """ + Saving to cogment_version work dir cache + """ + + specs_filename = os.path.join(work_dir, "environment_specs", f"{env_name}.yaml") + os.makedirs(os.path.dirname(specs_filename), exist_ok=True) + + self._pb.implementation = env_name + + with open(specs_filename, "w", encoding="utf-8") as f: + yaml.safe_dump(MessageToDict(self._pb, preserving_proto_field_name=True), f) diff --git a/cogment_verse/specs/flatten.py b/cogment_verse/specs/flatten.py deleted file mode 100644 index f9895acc..00000000 --- a/cogment_verse/specs/flatten.py +++ /dev/null @@ -1,121 +0,0 @@ -# Copyright 2022 AI Redefined Inc. -# -# 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. - -import numpy as np - -from data_pb2 import Space, SpaceMask, SpaceValue # pylint: disable=import-error - -from .value import create_space_values -from .ndarray import deserialize_ndarray, serialize_ndarray, create_one_hot_ndarray - - -def space_prop_flattened_dimensions(prop): - """ - Computes the number of dimensions a flattened equivalent of the given space property would have. - """ - assert isinstance(prop, Space.Property) - - if prop.WhichOneof("type") == "discrete": - return max(len(prop.discrete.labels), prop.discrete.num) - # box - if len(prop.box.shape) == 0: - return 0 - prop_dim = 1 - for dim in prop.box.shape: - prop_dim *= dim - return prop_dim - - -def flattened_dimensions(space): - """ - Computes the number of dimensions a flattened equivalent of the given space would have. - """ - assert isinstance(space, Space) - - space_dim = 0 - for prop in space.properties: - space_dim += space_prop_flattened_dimensions(prop) - - return space_dim - - -def flatten_prop(space, value, prop_idx): - assert isinstance(space, Space) - assert isinstance(value, SpaceValue) - - if prop_idx >= len(value.properties): - # If a value defines less properties than its space we make the remaining zeros - return np.zeros(space_prop_flattened_dimensions(space.properties[prop_idx])) - prop_value = value.properties[prop_idx] - value_type = prop_value.WhichOneof("value") - if value_type == "discrete": - space_prop = space.properties[prop_idx] - return create_one_hot_ndarray( - [prop_value.discrete], max(len(space_prop.discrete.labels), space_prop.discrete.num) - ) - if value_type == "box": - return deserialize_ndarray(prop_value.box).flatten() - # if value_type == "simple_box": - return np.array(prop_value.simple_box.values) - - -def flatten(space, value): - assert isinstance(space, Space) - assert isinstance(value, SpaceValue) - - return np.concatenate([flatten_prop(space, value, prop_idx) for prop_idx in range(len(space.properties))]) - - -def unflatten(space, flat_value): - assert isinstance(space, Space) - assert len(np.shape(flat_value)) == 1 - - [value] = create_space_values(space) - flat_value_idx = 0 - for prop_idx, prop in enumerate(space.properties): - flat_value_idx_end = flat_value_idx + space_prop_flattened_dimensions(prop) - flat_value_prop = flat_value[flat_value_idx:flat_value_idx_end] - if prop.WhichOneof("type") == "discrete": - # np.nonzero on a flat array returns a 1D tuple of the indices whose value is != 0 - value.properties[prop_idx].discrete = np.nonzero(flat_value_prop)[0][0] - else: - value.properties[prop_idx].box.CopyFrom(serialize_ndarray(flat_value_prop.reshape(prop.box.shape))) - - flat_value_idx = flat_value_idx_end - - return value - - -def flatten_mask_prop(space, mask, prop_idx): - assert isinstance(space, Space) - assert isinstance(mask, SpaceMask) - - space_prop = space.properties[prop_idx] - if prop_idx >= len(mask.properties): - # If a mask defines less properties than its space we make the remaining ones - return np.ones(space_prop_flattened_dimensions(space_prop)) - - value_type = space_prop.WhichOneof("type") - prop_mask = mask.properties[prop_idx] - if value_type == "discrete": - return create_one_hot_ndarray(prop_mask.discrete, max(len(space_prop.discrete.labels), space_prop.discrete.num)) - # if value_type == "box": - return np.ones(space_prop_flattened_dimensions(space_prop)) - - -def flatten_mask(space, mask): - assert isinstance(space, Space) - assert isinstance(mask, SpaceMask) - - return np.concatenate([flatten_mask_prop(space, mask, prop_idx) for prop_idx in range(len(space.properties))]) diff --git a/cogment_verse/specs/gym_spaces_adapter.py b/cogment_verse/specs/gym_spaces_adapter.py deleted file mode 100644 index 70b02d32..00000000 --- a/cogment_verse/specs/gym_spaces_adapter.py +++ /dev/null @@ -1,97 +0,0 @@ -# Copyright 2022 AI Redefined Inc. -# -# 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. - -import gym -import numpy as np - -from data_pb2 import Space, SpaceValue # pylint: disable=import-error - -from .ndarray import deserialize_ndarray, serialize_ndarray - -SPACES_BOUND_MAX = float.fromhex("0x1.fffffep+127") -SPACES_BOUND_MIN = -SPACES_BOUND_MAX - - -def gym_space_from_space(space): - gym_spaces_dict = {} - for prop in space.properties: - prop_type = prop.WhichOneof("type") - if prop_type == "discrete": - num_action = max(len(prop.discrete.labels), prop.discrete.num) - gym_spaces_dict[prop.key] = gym.spaces.Discrete(num_action) - if prop_type == "box": - gym_spaces_dict[prop.key] = gym.spaces.Box( - low=np.array([bound.bound if bound.bound is not None else -np.inf for bound in prop.box.low]), - high=np.array([bound.bound if bound.bound is not None else np.inf for bound in prop.box.high]), - shape=prop.box.shape, - ) - if len(gym_spaces_dict) == 1: - return next(iter(gym_spaces_dict.values())) - return gym.spaces.Dict(gym_spaces_dict) - - -def space_properties_from_gym_space(gym_space): - if isinstance(gym_space, gym.spaces.Box): - return [ - Space.Property( - box=Space.Box( - shape=list(gym_space.shape), - low=[ - Space.Bound(bound=v) if SPACES_BOUND_MIN < v < SPACES_BOUND_MAX else Space.Bound() - for v in gym_space.low.flat - ], - high=[ - Space.Bound(bound=v) if SPACES_BOUND_MIN < v < SPACES_BOUND_MAX else Space.Bound() - for v in gym_space.high.flat - ], - ) - ) - ] - if isinstance(gym_space, gym.spaces.Discrete): - return [Space.Property(discrete=Space.Discrete(num=gym_space.n))] - if isinstance(gym_space, gym.spaces.Dict): - properties = [] - for prop_key, gym_sub_space in gym_space.properties: - for sub_prop in space_properties_from_gym_space(gym_sub_space): - sub_prop.key = ( - f"{prop_key}.{sub_prop.key}" if sub_prop.key is not None else prop_key # pylint: disable=no-member - ) - properties.append(sub_prop) - return properties - raise RuntimeError(f"[{type(gym_space)}] is not a supported gym space type") - - -def space_from_gym_space(gym_space): - return Space(properties=space_properties_from_gym_space(gym_space)) - - -def gym_action_from_action(space, action): - if len(action.properties) == 1: - prop_value = action.properties[0] - value_type = prop_value.WhichOneof("value") - if value_type == "discrete": - return prop_value.discrete - if value_type == "box": - return deserialize_ndarray(prop_value.box) - # value_type == "simple_box" - return np.array(prop_value.simple_box.values).reshape(space.properties[0].box.shape) - raise RuntimeError(f"Not supporting spaces not having one property, got {len(action.properties)}") - - -def observation_from_gym_observation(gym_space, gym_observation): - if isinstance(gym_space, gym.spaces.Box): - return SpaceValue(properties=[SpaceValue.PropertyValue(box=serialize_ndarray(gym_observation))]) - if isinstance(gym_space, gym.spaces.Discrete): - return SpaceValue(properties=[SpaceValue.PropertyValue(discrete=gym_observation.item())]) - raise RuntimeError(f"[{type(gym_space)}] is not a supported gym space type") diff --git a/cogment_verse/specs/ndarray.proto b/cogment_verse/specs/ndarray.proto new file mode 100644 index 00000000..5008bd07 --- /dev/null +++ b/cogment_verse/specs/ndarray.proto @@ -0,0 +1,35 @@ +// Copyright 2022 AI Redefined Inc. +// +// 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. + +syntax = "proto3"; + +package cogment_verse.nd_array; + +enum DType { + DTYPE_UNKNOWN = 0; + DTYPE_FLOAT32 = 1; + DTYPE_FLOAT64 = 2; + DTYPE_INT8 = 3; + DTYPE_INT64 = 4; +} + +message Array { + DType dtype = 1; + repeated uint32 shape = 2; + bytes raw_data = 3; + bytes npy_data = 4; + repeated double double_data = 5; + repeated sint32 int32_data = 6; + repeated sint64 int64_data = 7; +} diff --git a/cogment_verse/specs/ndarray.py b/cogment_verse/specs/ndarray.py deleted file mode 100644 index d662a3cd..00000000 --- a/cogment_verse/specs/ndarray.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright 2022 AI Redefined Inc. -# -# 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. - -import numpy as np -from data_pb2 import NDArray # pylint: disable=import-error - - -def deserialize_ndarray(nd_array): - return np.frombuffer(nd_array.data, dtype=nd_array.dtype).reshape(*nd_array.shape) - - -def serialize_ndarray(nd_array): - return NDArray(shape=nd_array.shape, dtype=str(nd_array.dtype), data=nd_array.tobytes()) - - -def create_one_hot_ndarray(values, size): - nd_array = np.zeros(size) - nd_array[values] = 1 - return nd_array diff --git a/cogment_verse/specs/ndarray_serialization.py b/cogment_verse/specs/ndarray_serialization.py new file mode 100644 index 00000000..49dc6f43 --- /dev/null +++ b/cogment_verse/specs/ndarray_serialization.py @@ -0,0 +1,120 @@ +# Copyright 2022 AI Redefined Inc. +# +# 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. + +from enum import Enum +import io + +import numpy as np + +# pylint: disable=import-error +from ndarray_pb2 import ( + Array, + DTYPE_UNKNOWN, + DTYPE_FLOAT32, + DTYPE_FLOAT64, + DTYPE_INT8, + DTYPE_INT64, +) + +PB_DTYPE_FROM_DTYPE = { + "float32": DTYPE_FLOAT32, + "float64": DTYPE_FLOAT64, + "int8": DTYPE_INT8, + "int64": DTYPE_INT64, +} + +DTYPE_FROM_PB_DTYPE = { + DTYPE_FLOAT32: np.dtype("float32"), + DTYPE_FLOAT64: np.dtype("float64"), + DTYPE_INT8: np.dtype("int8"), + DTYPE_INT64: np.dtype("int64"), +} + +DOUBLE_DTYPES = frozenset(["float32", "float64"]) +INT32_DTYPES = frozenset(["int8"]) +INT64_DTYPES = frozenset(["int64"]) + + +class SerializationFormat(Enum): + RAW = 1 + NPY = 2 + STRUCTURED = 3 + + +def serialize_ndarray(nd_array, serilization_format=SerializationFormat.RAW): + str_dtype = str(nd_array.dtype) + pb_dtype = PB_DTYPE_FROM_DTYPE.get(str_dtype, DTYPE_UNKNOWN) + + # SerializationFormat.RAW + if serilization_format is SerializationFormat.RAW: + return Array( + shape=nd_array.shape, + dtype=pb_dtype, + raw_data=nd_array.tobytes(order="C"), + ) + + # SerializationFormat.NPY + if serilization_format is SerializationFormat.NPY: + buffer = io.BytesIO() + np.save(buffer, nd_array, allow_pickle=False) + return Array( + shape=nd_array.shape, + dtype=pb_dtype, + npy_data=buffer.getvalue(), + ) + + # SerializationFormat.STRUCTURED: + if str_dtype in DOUBLE_DTYPES: + return Array( + shape=nd_array.shape, + dtype=pb_dtype, + double_data=nd_array.ravel(order="C").tolist(), + ) + if str_dtype in INT32_DTYPES: + return Array( + shape=nd_array.shape, + dtype=pb_dtype, + int32_data=nd_array.ravel(order="C").tolist(), + ) + if str_dtype in INT64_DTYPES: + return Array( + shape=nd_array.shape, + dtype=pb_dtype, + int64_data=nd_array.ravel(order="C").tolist(), + ) + + raise RuntimeError(f"[{str_dtype}] is not a supported numpy dtype for serialization format [{format}]") + + +def deserialize_ndarray(pb_array): + dtype = DTYPE_FROM_PB_DTYPE.get(pb_array.dtype) + str_dtype = str(dtype) + shape = tuple(pb_array.shape) + + if len(pb_array.raw_data) > 0: + return np.frombuffer(pb_array.raw_data, dtype=dtype).reshape(shape, order="C") + + if len(pb_array.npy_data) > 0: + buffer = io.BytesIO(pb_array.npy_data) + return np.load(buffer, allow_pickle=False) + + # SerializationFormat.STRUCTURED + if str_dtype in DOUBLE_DTYPES: + return np.array(pb_array.double_data, dtype=dtype).reshape(shape, order="C") + if str_dtype in INT32_DTYPES: + return np.array(pb_array.int32_data, dtype=dtype).reshape(shape, order="C") + if str_dtype in INT64_DTYPES: + return np.array(pb_array.int64_data, dtype=dtype).reshape(shape, order="C") + + raise RuntimeError(f"[{str_dtype}] is not a supported numpy dtype for serialization format [{format}]") diff --git a/cogment_verse/specs/observation_space.py b/cogment_verse/specs/observation_space.py new file mode 100644 index 00000000..095baa28 --- /dev/null +++ b/cogment_verse/specs/observation_space.py @@ -0,0 +1,232 @@ +# Copyright 2022 AI Redefined Inc. +# +# 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. + +from gym.spaces import utils, Dict + +from data_pb2 import Observation as PbObservation # pylint: disable=import-error + +from .encode_rendered_frame import encode_rendered_frame +from .ndarray_serialization import serialize_ndarray, deserialize_ndarray + +# pylint: disable=attribute-defined-outside-init +class Observation: + """ + Cogment Verse actor observation + + Properties: + flat_value: + The observation value, as a flat numpy array. + value: + The observation value, as a numpy array. + flat_action_mask: optional + The action mask, as a flat numpy array. + action_mask: optional + The action mask. + rendered_frame: optional + Environmnent's rendered frame as a numpy array of RGB pixels + current_player: optional + Name of the current player. `None` for single player environments. + overridden_players: + List of players whose actions where overriden by a teacher actor. + """ + + def __init__( + self, + gym_space, + action_mask_gym_space, + pb_observation=None, + value=None, + action_mask=None, + rendered_frame=None, + current_player=None, + overridden_players=None, + ): + """ + Observation constructor. + Shouldn't be called directly, prefer the factory function of ObservationSpace. + """ + + self._gym_space = gym_space + self._action_mask_gym_space = action_mask_gym_space + + if pb_observation is not None: + assert value is None + assert action_mask is None + assert rendered_frame is None + assert current_player is None + assert overridden_players is None + self._pb_observation = pb_observation + return + + self._value = value + self._action_mask = action_mask + self._rendered_frame = rendered_frame + + self._pb_observation = PbObservation( + current_player=current_player, + overridden_players=overridden_players, + ) + + def _compute_flat_value(self): + if hasattr(self, "_value"): + return utils.flatten(self._gym_space, self._value) + + return deserialize_ndarray(self._pb_observation.value) + + @property + def flat_value(self): + if not hasattr(self, "_flat_value"): + self._flat_value = self._compute_flat_value() + return self._flat_value + + def _compute_value(self): + return utils.unflatten(self._gym_space, self.flat_value) + + @property + def value(self): + if not hasattr(self, "_value"): + self._value = self._compute_value() + return self._value + + def _compute_flat_action_mask(self): + if hasattr(self, "_action_mask"): + if self._action_mask is None: + return None + return utils.flatten(self._action_mask_gym_space, self._action_mask) + + if not self._pb_observation.HasField("action_mask"): + return None + + return deserialize_ndarray(self._pb_observation.action_mask) + + @property + def flat_action_mask(self): + if not hasattr(self, "_flat_action_mask"): + self._flat_action_mask = self._compute_flat_action_mask() + return self._flat_action_mask + + def _compute_action_mask(self): + flat_action_mask = self.flat_action_mask + if flat_action_mask is None: + return None + return utils.unflatten(self._action_mask_gym_space, self.flat_action_mask) + + @property + def action_mask(self): + if not hasattr(self, "_action_mask"): + self._action_mask = self._compute_action_mask() + return self._action_mask + + @property + def rendered_frame(self): + try: + return self._rendered_frame + except AttributeError as exc: + # At the moment there's no use to deserialize the rendered frame on the python side + raise NotImplementedError from exc + + @property + def current_player(self): + if not self._pb_observation.HasField("current_player"): + return None + + return self._pb_observation.current_player + + @property + def overridden_players(self): + overridden_players = self._pb_observation.overridden_players + if overridden_players is None: + return [] + return overridden_players + + +class ObservationSpace: + """ + Cogment Verse observation space + + Properties: + gym_space: + Wrapped Gym space for the observation values (cf. https://www.gymlibrary.dev/api/spaces/) + action_mask_gym_space: optional + Wrapped Gym space for the action mask (cf. https://www.gymlibrary.dev/api/spaces/) + render_width: + Maximum width for the serialized rendered frame in observations + """ + + def __init__(self, space, render_width=1024): + """ + ObservationSpace constructor. + Shouldn't be called directly, prefer the factory function of EnvironmentSpecs. + """ + if isinstance(space, Dict) and ("action_mask" in space.spaces): + # Check the observation space defines an action_mask "component" (like petting zoo does) + assert "observation" in space.spaces + assert len(space.spaces) == 2 + + self.gym_space = space.spaces["observation"] + self.action_mask_gym_space = space.spaces["action_mask"] + else: + # "Standard" observation space, no action_mask + self.gym_space = space + self.action_mask_gym_space = None + + # Other configuration + self.render_width = render_width + + def create(self, value=None, action_mask=None, rendered_frame=None, current_player=None, overridden_players=None): + """ + Create an Observation + """ + return Observation( + self.gym_space, + self.action_mask_gym_space, + value=value, + action_mask=action_mask, + rendered_frame=rendered_frame, + current_player=current_player, + overridden_players=overridden_players, + ) + + def serialize( + self, + observation, + ): + """ + Serialize an Observation to an Observation protobuf message + """ + flat_value = utils.flatten(self.gym_space, observation.value) + serialized_value = serialize_ndarray(flat_value) + + serialized_action_mask = None + if self.action_mask_gym_space is not None: + flat_action_mask = utils.flatten(self.action_mask_gym_space, observation.action_mask) + serialized_action_mask = serialize_ndarray(flat_action_mask) + + serialized_rendered_frame = None + if observation.rendered_frame is not None: + serialized_rendered_frame = encode_rendered_frame(observation.rendered_frame, self.render_width) + + return PbObservation( + value=serialized_value, + action_mask=serialized_action_mask, + rendered_frame=serialized_rendered_frame, + overridden_players=observation.overridden_players, + current_player=observation.current_player, + ) + + def deserialize(self, pb_observation): + """ + Deserialize an Observation from an Observation protobuf message + """ + return Observation(self.gym_space, self.action_mask_gym_space, pb_observation=pb_observation) diff --git a/cogment_verse/specs/sample_space.py b/cogment_verse/specs/sample_space.py deleted file mode 100644 index bc81893f..00000000 --- a/cogment_verse/specs/sample_space.py +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright 2022 AI Redefined Inc. -# -# 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. - -import numpy as np - -from .value import create_space_values -from .ndarray import serialize_ndarray - - -def sample_space(space, num_samples=1, rng=None, mask=None): - if rng is None: - rng = np.random.default_rng() - - space_values = create_space_values(space, num_samples) - - for prop_idx, prop in enumerate(space.properties): - if prop.WhichOneof("type") == "discrete": - if mask is not None and prop_idx < len(mask.properties) and len(mask.properties[prop_idx].discrete) > 0: - for space_value, sampled_value in zip( - space_values, rng.choice(a=mask.properties[prop_idx].discrete, size=num_samples) - ): - space_value.properties[prop_idx].discrete = sampled_value - continue - num_action = max(len(prop.discrete.labels), prop.discrete.num) - for space_value, sampled_value in zip(space_values, rng.integers(low=0, high=num_action, size=num_samples)): - space_value.properties[prop_idx].discrete = sampled_value - else: - shape = prop.box.shape - - high = np.array([bound.bound if bound.HasField("bound") else np.inf for bound in prop.box.high]).reshape( - shape - ) - low = np.array([bound.bound if bound.HasField("bound") else -np.inf for bound in prop.box.low]).reshape( - shape - ) - - sampled_values = np.zeros((num_samples, *shape)) - - if len(shape) == 1: - high = np.repeat(high[np.newaxis, :], num_samples, axis=0) - low = np.repeat(low[np.newaxis, :], num_samples, axis=0) - else: - high = np.repeat(high[np.newaxis, :, :], num_samples, axis=0) - low = np.repeat(low[np.newaxis, :, :], num_samples, axis=0) - - unbounded_mask = (high == np.inf) & (low == -np.inf) - sampled_values[unbounded_mask] = rng.normal(size=unbounded_mask[unbounded_mask].shape) - - low_bounded_mask = (high == np.inf) & (low != -np.inf) - sampled_values[low_bounded_mask] = ( - -rng.exponential(size=low_bounded_mask[low_bounded_mask].shape) + low[low_bounded_mask] - ) - - high_bounded_mask = (high != np.inf) & (low == -np.inf) - sampled_values[high_bounded_mask] = ( - rng.exponential(size=high_bounded_mask[high_bounded_mask].shape) + high[high_bounded_mask] - ) - - bounded_mask = (high != np.inf) & (low != -np.inf) - sampled_values[bounded_mask] = rng.uniform( - low=low[bounded_mask], high=high[bounded_mask], size=bounded_mask[bounded_mask].shape - ) - - for space_value, sampled_value in zip(space_values, sampled_values): - space_value.properties[prop_idx].box.CopyFrom(serialize_ndarray(sampled_value)) - - return space_values diff --git a/cogment_verse/specs/spaces.proto b/cogment_verse/specs/spaces.proto new file mode 100644 index 00000000..3bbd60f1 --- /dev/null +++ b/cogment_verse/specs/spaces.proto @@ -0,0 +1,45 @@ +// Copyright 2022 AI Redefined Inc. +// +// 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. + +syntax = "proto3"; + +import "ndarray.proto"; + +package cogment_verse.spaces; + +message Discrete { + int32 n = 1; + int32 start = 2; +} + +message Box { + nd_array.Array low = 2; + nd_array.Array high = 3; +} + +message Dict { + message SubSpace { + string key = 1; + Space space = 2; + } + repeated SubSpace spaces = 1; +} + +message Space { + oneof kind { + Discrete discrete = 1; + Box box = 2; + Dict dict = 3; + } +} diff --git a/cogment_verse/specs/spaces_serialization.py b/cogment_verse/specs/spaces_serialization.py new file mode 100644 index 00000000..43d44985 --- /dev/null +++ b/cogment_verse/specs/spaces_serialization.py @@ -0,0 +1,62 @@ +# Copyright 2022 AI Redefined Inc. +# +# 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. + +import gym + +from spaces_pb2 import Space, Discrete, Box, Dict # pylint: disable=import-error + +from .ndarray_serialization import deserialize_ndarray, serialize_ndarray, SerializationFormat + + +def serialize_gym_space(gym_space, serilization_format=SerializationFormat.STRUCTURED): + if isinstance(gym_space, gym.spaces.Discrete): + return Space(discrete=Discrete(n=gym_space.n, start=gym_space.start)) + + if isinstance(gym_space, gym.spaces.Box): + low = gym_space.low + high = gym_space.high + return Space( + box=Box( + low=serialize_ndarray(low, serilization_format=serilization_format), + high=serialize_ndarray(high, serilization_format=serilization_format), + ) + ) + + if isinstance(gym_space, gym.spaces.Dict): + spaces = [] + for key, gym_sub_space in gym_space.spaces.items(): + spaces.append(Dict.SubSpace(key=key, space=serialize_gym_space(gym_sub_space))) + return Space(dict=Dict(spaces=spaces)) + raise RuntimeError(f"[{type(gym_space)}] is not a supported space type") + + +def deserialize_gym_space(pb_space): + space_kind = pb_space.WhichOneof("kind") + if space_kind == "discrete": + discrete_space_pb = pb_space.discrete + return gym.spaces.Discrete(n=discrete_space_pb.n, start=discrete_space_pb.start) + if space_kind == "box": + box_space_pb = pb_space.box + low = deserialize_ndarray(box_space_pb.low) + high = deserialize_ndarray(box_space_pb.high) + return gym.spaces.Box(low=low, high=high, shape=low.shape, dtype=low.dtype) + if space_kind == "dict": + dict_space_pb = pb_space.dict + spaces = [] + for sub_space in dict_space_pb.spaces: + spaces.append((sub_space.key, deserialize_gym_space(sub_space.space))) + + return gym.spaces.Dict(spaces=spaces) + + raise RuntimeError(f"[{space_kind}] is not a supported space type") diff --git a/cogment_verse/specs/test_sample.py b/cogment_verse/specs/test_sample.py deleted file mode 100644 index 440461e3..00000000 --- a/cogment_verse/specs/test_sample.py +++ /dev/null @@ -1,122 +0,0 @@ -# Copyright 2022 AI Redefined Inc. -# -# 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. - -from cogment_verse.specs import ( - Space, - SpaceMask, - sample_space, - deserialize_ndarray, -) - - -def test_sample_discrete(): - space = Space(properties=[Space.Property(discrete=Space.Discrete(num=2))]) - - values = sample_space(space, 4) - assert len(values) == 4 - - for value in values: - assert len(value.properties) == 1 - assert value.properties[0].discrete in range(2) - - -def test_sample_discrete_named(): - space = Space(properties=[Space.Property(discrete=Space.Discrete(labels=["brake", "accelerate", "do nothing"]))]) - - values = sample_space(space, 12) - assert len(values) == 12 - - for value in values: - assert len(value.properties) == 1 - assert value.properties[0].discrete in range(3) - - -def test_sample_discrete_named_masked(): - space = Space(properties=[Space.Property(discrete=Space.Discrete(labels=["brake", "accelerate", "do nothing"]))]) - mask = SpaceMask(properties=[SpaceMask.PropertyMask(discrete=[0, 2])]) - - values = sample_space(space, 345, mask=mask) - assert len(values) == 345 - - for value in values: - assert len(value.properties) == 1 - assert value.properties[0].discrete in [0, 2] - - -def test_sample_discrete_named_and_more(): - space = Space( - properties=[Space.Property(discrete=Space.Discrete(labels=["brake", "accelerate", "do nothing"], num=12))] - ) - - values = sample_space(space, 12) - assert len(values) == 12 - - for value in values: - assert len(value.properties) == 1 - assert value.properties[0].discrete in range(12) - - -def test_sample_multiple_discrete(): - space = Space( - properties=[ - Space.Property(key="foo", discrete=Space.Discrete(labels=["brake", "accelerate", "do nothing"])), - Space.Property(key="bar", discrete=Space.Discrete(num=6)), - ] - ) - mask = SpaceMask(properties=[SpaceMask.PropertyMask(), SpaceMask.PropertyMask(discrete=[1, 4, 5])]) - - values = sample_space(space, 12, mask=mask) - assert len(values) == 12 - - for value in values: - assert len(value.properties) == 2 - assert value.properties[0].discrete in range(3) - assert value.properties[1].discrete in [1, 4, 5] - - -def test_sample_box(): - space = Space( - properties=[ - Space.Property( - box=Space.Box( - shape=[2, 3], - low=[ - Space.Bound(bound=-1), - Space.Bound(bound=-2), - Space.Bound(), - Space.Bound(bound=-4), - Space.Bound(), - Space.Bound(bound=-6), - ], - high=[ - Space.Bound(bound=1), - Space.Bound(bound=2), - Space.Bound(), - Space.Bound(), - Space.Bound(bound=5), - Space.Bound(bound=6), - ], - ) - ) - ] - ) - - values = sample_space(space, 4) - assert len(values) == 4 - - for value in values: - assert len(value.properties) == 1 - assert value.properties[0].box.shape == [2, 3] - ndarray = deserialize_ndarray(value.properties[0].box) - assert ndarray.shape == (2, 3) diff --git a/cogment_verse/specs/value.py b/cogment_verse/specs/value.py deleted file mode 100644 index 7bf904cc..00000000 --- a/cogment_verse/specs/value.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright 2022 AI Redefined Inc. -# -# 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. - -from data_pb2 import SpaceValue # pylint: disable=import-error - - -def create_space_values(space, num_values=1): - return [ - SpaceValue(properties=[SpaceValue.PropertyValue() for property_definition in space.properties]) - for idx_value in range(num_values) - ] diff --git a/cogment_verse/web/components/build/asset-manifest.json b/cogment_verse/web/components/build/asset-manifest.json deleted file mode 100644 index f797cea9..00000000 --- a/cogment_verse/web/components/build/asset-manifest.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "files": { - "main.css": "/static/css/main.b6c8fc15.css", - "main.js": "/static/js/main.33a072ac.js", - "static/js/787.90542627.chunk.js": "/static/js/787.90542627.chunk.js", - "index.html": "/index.html", - "main.b6c8fc15.css.map": "/static/css/main.b6c8fc15.css.map", - "main.33a072ac.js.map": "/static/js/main.33a072ac.js.map", - "787.90542627.chunk.js.map": "/static/js/787.90542627.chunk.js.map" - }, - "entrypoints": [ - "static/css/main.b6c8fc15.css", - "static/js/main.33a072ac.js" - ] -} \ No newline at end of file diff --git a/cogment_verse/web/components/build/static/css/main.b6c8fc15.css b/cogment_verse/web/components/build/static/css/main.b6c8fc15.css deleted file mode 100644 index 6c11223f..00000000 --- a/cogment_verse/web/components/build/static/css/main.b6c8fc15.css +++ /dev/null @@ -1,4 +0,0 @@ -/* -! tailwindcss v3.0.24 | MIT License | https://tailwindcss.com -*/*,:after,:before{border:0 solid #e5e7eb;box-sizing:border-box}:after,:before{--tw-content:""}html{-webkit-text-size-adjust:100%;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5;tab-size:4}body{line-height:inherit}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{color:inherit;font-family:inherit;font-size:100%;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#9ca3af;opacity:1}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#9ca3af;opacity:1}input::placeholder,textarea::placeholder{color:#9ca3af;opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}[hidden]{display:none}*,:after,:before{--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.static{position:static}.mx-auto{margin-left:auto;margin-right:auto}.mb-2{margin-bottom:.5rem}.block{display:block}.flex{display:flex}.aspect-square{aspect-ratio:1/1}.min-h-screen{min-height:100vh}.w-full{width:100%}.w-fit{width:-webkit-fit-content;width:-moz-fit-content;width:fit-content}.max-w-screen-md{max-width:768px}.flex-1{flex:1 1}.flex-none{flex:none}.flex-initial{flex:0 1 auto}.transform{-webkit-transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.list-inside{list-style-position:inside}.list-disc{list-style-type:disc}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-center{justify-content:center}.gap-2{gap:.5rem}.gap-1{gap:.25rem}.gap-4{gap:1rem}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.bg-indigo-600{--tw-bg-opacity:1;background-color:rgb(79 70 229/var(--tw-bg-opacity))}.bg-slate-600{--tw-bg-opacity:1;background-color:rgb(71 85 105/var(--tw-bg-opacity))}.bg-indigo-200{--tw-bg-opacity:1;background-color:rgb(199 210 254/var(--tw-bg-opacity))}.p-2{padding:.5rem}.p-5{padding:1.25rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.py-3{padding-bottom:.75rem;padding-top:.75rem}.px-10{padding-left:2.5rem;padding-right:2.5rem}.text-center{text-align:center}.text-right{text-align:right}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-base{font-size:1rem;line-height:1.5rem}.text-xs{font-size:.75rem;line-height:1rem}.text-sm{font-size:.875rem;line-height:1.25rem}.font-semibold{font-weight:600}.lowercase{text-transform:lowercase}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.ring-8{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(8px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),0 0 #0000;box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-inset{--tw-ring-inset:inset}.blur{--tw-blur:blur(8px)}.blur,.filter{-webkit-filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.duration-75{transition-duration:75ms}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;margin:0}code{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}.hover\:bg-indigo-900:hover{--tw-bg-opacity:1;background-color:rgb(49 46 129/var(--tw-bg-opacity))}.disabled\:bg-gray-400:disabled{--tw-bg-opacity:1;background-color:rgb(156 163 175/var(--tw-bg-opacity))}.disabled\:text-gray-200:disabled{--tw-text-opacity:1;color:rgb(229 231 235/var(--tw-text-opacity))}.RenderedScreen_container__9inx9{display:grid;position:relative}.RenderedScreen_canvas__Zmrsu,.RenderedScreen_overlay__fApA7{grid-area:1/-1;width:100%;z-index:0}.RenderedScreen_overlay__fApA7{align-items:center;display:flex;justify-content:center;z-index:1}:root{--dpad-bg-color:#fff;--dpad-bg-color-hover:#eee;--dpad-bg-color-active:#fff;--dpad-bg-color-disabled:#fff;--dpad-fg-color:#5217b8;--dpad-fg-color-hover:#5217b8;--dpad-fg-color-active:#ffb300;--dpad-fg-color-disabled:#bbb;--dpad-button-outer-radius:15%;--dpad-button-inner-radius:50%;--dpad-arrow-position:40%;--dpad-arrow-position-hover:35%;--dpad-arrow-base:19px;--dpad-arrow-height:13px}.DPad_dpad__ZZdxt{display:inline-block;height:200px;overflow:hidden;position:relative;width:200px}.DPad_down__EeuUg,.DPad_left__1AYHI,.DPad_right__AqUBc,.DPad_up__dOfw6{-webkit-tap-highlight-color:rgba(255,255,255,0);background:#fff;background:var(--dpad-bg-color);border-color:#5217b8;border-color:var(--dpad-fg-color);border-style:solid;border-width:1px;color:transparent;display:block;line-height:40%;padding:0;position:absolute;text-align:center}.DPad_down__EeuUg,.DPad_up__dOfw6{height:43%;width:33.3%}.DPad_left__1AYHI,.DPad_right__AqUBc{height:33%;width:43%}.DPad_up__dOfw6{border-radius:15% 15% 50% 50%;border-radius:var(--dpad-button-outer-radius) var(--dpad-button-outer-radius) var(--dpad-button-inner-radius) var(--dpad-button-inner-radius);top:0}.DPad_down__EeuUg,.DPad_up__dOfw6{left:50%;-webkit-transform:translate(-50%);transform:translate(-50%)}.DPad_down__EeuUg{border-radius:50% 50% 15% 15%;border-radius:var(--dpad-button-inner-radius) var(--dpad-button-inner-radius) var(--dpad-button-outer-radius) var(--dpad-button-outer-radius);bottom:0}.DPad_left__1AYHI{border-radius:15% 50% 50% 15%;border-radius:var(--dpad-button-outer-radius) var(--dpad-button-inner-radius) var(--dpad-button-inner-radius) var(--dpad-button-outer-radius);left:0}.DPad_left__1AYHI,.DPad_right__AqUBc{top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.DPad_right__AqUBc{border-radius:50% 15% 15% 50%;border-radius:50% var(--dpad-button-outer-radius) var(--dpad-button-outer-radius) 50%;right:0}.DPad_down__EeuUg:before,.DPad_left__1AYHI:before,.DPad_right__AqUBc:before,.DPad_up__dOfw6:before{border-radius:5px;border-style:solid;content:"";height:0;position:absolute;transition:all .25s;width:0}.DPad_up__dOfw6:before{border-color:transparent transparent #5217b8;border-color:transparent transparent var(--dpad-fg-color) transparent;border-width:0 13px 19px;border-width:0 var(--dpad-arrow-height) var(--dpad-arrow-base) var(--dpad-arrow-height);left:50%;top:40%;top:var(--dpad-arrow-position);-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%)}.DPad_down__EeuUg:before{border-color:#5217b8 transparent transparent;border-color:var(--dpad-fg-color) transparent transparent transparent;border-width:19px 13px 0;border-width:var(--dpad-arrow-base) var(--dpad-arrow-height) 0 var(--dpad-arrow-height);bottom:40%;bottom:var(--dpad-arrow-position);left:50%;-webkit-transform:translate(-50%,50%);transform:translate(-50%,50%)}.DPad_left__1AYHI:before{border-color:transparent #5217b8 transparent transparent;border-color:transparent var(--dpad-fg-color) transparent transparent;border-width:13px 19px 13px 0;border-width:var(--dpad-arrow-height) var(--dpad-arrow-base) var(--dpad-arrow-height) 0;left:40%;left:var(--dpad-arrow-position);top:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%)}.DPad_right__AqUBc:before{border-color:transparent transparent transparent #5217b8;border-color:transparent transparent transparent var(--dpad-fg-color);border-width:13px 0 13px 19px;border-width:var(--dpad-arrow-height) 0 var(--dpad-arrow-height) var(--dpad-arrow-base);right:40%;right:var(--dpad-arrow-position);top:50%;-webkit-transform:translate(50%,-50%);transform:translate(50%,-50%)}.DPad_down__EeuUg:hover,.DPad_left__1AYHI:hover,.DPad_right__AqUBc:hover,.DPad_up__dOfw6:hover{background:#eee;background:var(--dpad-bg-color-hover);border-color:#5217b8;border-color:var(--dpad-fg-color-hover)}.DPad_up__dOfw6:hover:before{border-bottom-color:#5217b8;border-bottom-color:var(--dpad-fg-color-hover);top:35%;top:var(--dpad-arrow-position-hover)}.DPad_down__EeuUg:hover:before{border-top-color:#5217b8;border-top-color:var(--dpad-fg-color-hover);bottom:35%;bottom:var(--dpad-arrow-position-hover)}.DPad_left__1AYHI:hover:before{border-right-color:#5217b8;border-right-color:var(--dpad-fg-color-hover);left:35%;left:var(--dpad-arrow-position-hover)}.DPad_right__AqUBc:hover:before{border-left-color:#5217b8;border-left-color:var(--dpad-fg-color-hover);right:35%;right:var(--dpad-arrow-position-hover)}.DPad_down__EeuUg.DPad_active__OzzXu,.DPad_down__EeuUg:active,.DPad_left__1AYHI.DPad_active__OzzXu,.DPad_left__1AYHI:active,.DPad_right__AqUBc.DPad_active__OzzXu,.DPad_right__AqUBc:active,.DPad_up__dOfw6.DPad_active__OzzXu,.DPad_up__dOfw6:active{background:#fff;background:var(--dpad-bg-color-active);border-color:#ffb300;border-color:var(--dpad-fg-color-active)}.DPad_up__dOfw6.DPad_active__OzzXu:before,.DPad_up__dOfw6:active:before{border-bottom-color:#ffb300;border-bottom-color:var(--dpad-fg-color-active)}.DPad_down__EeuUg.DPad_active__OzzXu:before,.DPad_down__EeuUg:active:before{border-top-color:#ffb300;border-top-color:var(--dpad-fg-color-active)}.DPad_left__1AYHI.DPad_active__OzzXu:before,.DPad_left__1AYHI:active:before{border-right-color:#ffb300;border-right-color:var(--dpad-fg-color-active)}.DPad_right__AqUBc.DPad_active__OzzXu:before,.DPad_right__AqUBc:active:before{border-left-color:#ffb300;border-left-color:var(--dpad-fg-color-active)}.DPad_down__EeuUg.DPad_disabled__\+IfWl,.DPad_left__1AYHI.DPad_disabled__\+IfWl,.DPad_right__AqUBc.DPad_disabled__\+IfWl,.DPad_up__dOfw6.DPad_disabled__\+IfWl{background:#fff;background:var(--dpad-bg-color-disabled);border-color:#bbb;border-color:var(--dpad-fg-color-disabled)}.DPad_up__dOfw6.DPad_disabled__\+IfWl:before{border-bottom-color:#bbb;border-bottom-color:var(--dpad-fg-color-disabled);top:40%;top:var(--dpad-arrow-position)}.DPad_down__EeuUg.DPad_disabled__\+IfWl:before{border-top-color:#bbb;border-top-color:var(--dpad-fg-color-disabled);bottom:40%;bottom:var(--dpad-arrow-position)}.DPad_left__1AYHI.DPad_disabled__\+IfWl:before{border-right-color:#bbb;border-right-color:var(--dpad-fg-color-disabled);left:40%;left:var(--dpad-arrow-position)}.DPad_right__AqUBc.DPad_disabled__\+IfWl:before{border-left-color:#bbb;border-left-color:var(--dpad-fg-color-disabled);right:40%;right:var(--dpad-arrow-position)}:root{--joystick-surface-size:200px;--joystick-stick-size:50px;--joystick-color:#5217b8;--joystick-color-active:#ffb300;--joystick-color-disabled:#bbb}.Joystick_joystick__DwFj2{align-items:center;border-color:#5217b8;border-color:var(--joystick-color);border-radius:25px;border-radius:calc(var(--joystick-stick-size)/2);border-style:solid;border-width:1px;display:flex;height:200px;height:var(--joystick-surface-size);justify-content:center;overflow:hidden;position:relative;transition:all .25s;width:200px;width:var(--joystick-surface-size)}.Joystick_joystick__DwFj2>.Joystick_stick__z5P-5{background-color:#5217b8;background-color:var(--joystick-color);border-radius:50%;height:50px;height:var(--joystick-stick-size);transition:all .25s;width:50px;width:var(--joystick-stick-size)}.Joystick_joystick__DwFj2.Joystick_active__EOXxn{border-color:#ffb300;border-color:var(--joystick-color-active)}.Joystick_joystick__DwFj2.Joystick_active__EOXxn>.Joystick_stick__z5P-5{background-color:#ffb300;background-color:var(--joystick-color-active)}.Joystick_joystick__DwFj2.Joystick_disabled__WyYwu{border-color:#bbb;border-color:var(--joystick-color-disabled)}.Joystick_joystick__DwFj2.Joystick_disabled__WyYwu>.Joystick_stick__z5P-5{background-color:#bbb;background-color:var(--joystick-color-disabled)} -/*# sourceMappingURL=main.b6c8fc15.css.map*/ \ No newline at end of file diff --git a/cogment_verse/web/components/build/static/css/main.b6c8fc15.css.map b/cogment_verse/web/components/build/static/css/main.b6c8fc15.css.map deleted file mode 100644 index 1407f751..00000000 --- a/cogment_verse/web/components/build/static/css/main.b6c8fc15.css.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"static/css/main.b6c8fc15.css","mappings":"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","sources":["index.css","components/RenderedScreen.module.css","components/DPad.module.css","components/Joystick.module.css"],"sourcesContent":["@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\nbody {\n margin: 0;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Roboto\", \"Oxygen\", \"Ubuntu\", \"Cantarell\", \"Fira Sans\",\n \"Droid Sans\", \"Helvetica Neue\", sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\ncode {\n font-family: source-code-pro, Menlo, Monaco, Consolas, \"Courier New\", monospace;\n}\n",".container {\n position: relative;\n display: grid;\n}\n\n.canvas,\n.overlay {\n grid-area: 1/-1;\n z-index: 0;\n\n width: 100%;\n}\n\n.overlay {\n z-index: 1;\n\n display: flex;\n justify-content: center;\n align-items: center;\n}\n",":root {\n --dpad-bg-color: #fff;\n --dpad-bg-color-hover: #eee;\n --dpad-bg-color-active: #fff;\n --dpad-bg-color-disabled: #fff;\n --dpad-fg-color: #5217b8;\n --dpad-fg-color-hover: #5217b8;\n --dpad-fg-color-active: #ffb300;\n --dpad-fg-color-disabled: #bbb;\n\n --dpad-button-outer-radius: 15%;\n --dpad-button-inner-radius: 50%;\n\n --dpad-arrow-position: 40%;\n --dpad-arrow-position-hover: 35%;\n --dpad-arrow-base: 19px;\n --dpad-arrow-height: 13px;\n}\n\n.dpad {\n position: relative;\n display: inline-block;\n\n width: 200px;\n height: 200px;\n\n overflow: hidden;\n}\n\n/* Buttons background */\n\n.up,\n.right,\n.down,\n.left {\n display: block;\n position: absolute;\n -webkit-tap-highlight-color: rgba(255, 255, 255, 0);\n\n line-height: 40%;\n text-align: center;\n background: var(--dpad-bg-color);\n border-color: var(--dpad-fg-color);\n border-style: solid;\n border-width: 1px;\n padding: 0px;\n color: transparent;\n}\n\n.up,\n.down {\n width: 33.3%;\n height: 43%;\n}\n\n.left,\n.right {\n width: 43%;\n height: 33%;\n}\n\n.up {\n top: 0;\n left: 50%;\n transform: translate(-50%, 0);\n border-radius: var(--dpad-button-outer-radius) var(--dpad-button-outer-radius) var(--dpad-button-inner-radius)\n var(--dpad-button-inner-radius);\n}\n\n.down {\n bottom: 0;\n left: 50%;\n transform: translate(-50%, 0);\n border-radius: var(--dpad-button-inner-radius) var(--dpad-button-inner-radius) var(--dpad-button-outer-radius)\n var(--dpad-button-outer-radius);\n}\n\n.left {\n top: 50%;\n left: 0;\n transform: translate(0, -50%);\n border-radius: var(--dpad-button-outer-radius) var(--dpad-button-inner-radius) var(--dpad-button-inner-radius)\n var(--dpad-button-outer-radius);\n}\n\n.right {\n top: 50%;\n right: 0;\n transform: translate(0, -50%);\n border-radius: 50% var(--dpad-button-outer-radius) var(--dpad-button-outer-radius) 50%;\n}\n\n/* Buttons arrows */\n.up:before,\n.right:before,\n.down:before,\n.left:before {\n content: \"\";\n position: absolute;\n width: 0;\n height: 0;\n border-radius: 5px;\n border-style: solid;\n transition: all 0.25s;\n}\n\n.up:before {\n top: var(--dpad-arrow-position);\n left: 50%;\n transform: translate(-50%, -50%);\n border-width: 0 var(--dpad-arrow-height) var(--dpad-arrow-base) var(--dpad-arrow-height);\n border-color: transparent transparent var(--dpad-fg-color) transparent;\n}\n\n.down:before {\n bottom: var(--dpad-arrow-position);\n left: 50%;\n transform: translate(-50%, 50%);\n border-width: var(--dpad-arrow-base) var(--dpad-arrow-height) 0px var(--dpad-arrow-height);\n border-color: var(--dpad-fg-color) transparent transparent transparent;\n}\n\n.left:before {\n left: var(--dpad-arrow-position);\n top: 50%;\n transform: translate(-50%, -50%);\n border-width: var(--dpad-arrow-height) var(--dpad-arrow-base) var(--dpad-arrow-height) 0;\n border-color: transparent var(--dpad-fg-color) transparent transparent;\n}\n\n.right:before {\n right: var(--dpad-arrow-position);\n top: 50%;\n transform: translate(50%, -50%);\n border-width: var(--dpad-arrow-height) 0 var(--dpad-arrow-height) var(--dpad-arrow-base);\n border-color: transparent transparent transparent var(--dpad-fg-color);\n}\n\n/* Hover */\n\n.up:hover,\n.right:hover,\n.down:hover,\n.left:hover {\n background: var(--dpad-bg-color-hover);\n border-color: var(--dpad-fg-color-hover);\n}\n\n.up:hover:before {\n top: var(--dpad-arrow-position-hover);\n border-bottom-color: var(--dpad-fg-color-hover);\n}\n\n.down:hover:before {\n bottom: var(--dpad-arrow-position-hover);\n border-top-color: var(--dpad-fg-color-hover);\n}\n\n.left:hover:before {\n left: var(--dpad-arrow-position-hover);\n border-right-color: var(--dpad-fg-color-hover);\n}\n\n.right:hover:before {\n right: var(--dpad-arrow-position-hover);\n border-left-color: var(--dpad-fg-color-hover);\n}\n\n/* Active */\n\n.up:active,\n.right:active,\n.down:active,\n.left:active,\n.up.active,\n.right.active,\n.down.active,\n.left.active {\n background: var(--dpad-bg-color-active);\n border-color: var(--dpad-fg-color-active);\n}\n\n.up:active:before,\n.up.active:before {\n border-bottom-color: var(--dpad-fg-color-active);\n}\n\n.down:active:before,\n.down.active:before {\n border-top-color: var(--dpad-fg-color-active);\n}\n\n.left:active:before,\n.left.active:before {\n border-right-color: var(--dpad-fg-color-active);\n}\n\n.right:active:before,\n.right.active:before {\n border-left-color: var(--dpad-fg-color-active);\n}\n\n/* Disabled */\n\n.up.disabled,\n.right.disabled,\n.down.disabled,\n.left.disabled {\n background: var(--dpad-bg-color-disabled);\n border-color: var(--dpad-fg-color-disabled);\n}\n\n.up.disabled:before {\n top: var(--dpad-arrow-position);\n border-bottom-color: var(--dpad-fg-color-disabled);\n}\n\n.down.disabled:before {\n bottom: var(--dpad-arrow-position);\n border-top-color: var(--dpad-fg-color-disabled);\n}\n\n.left.disabled:before {\n left: var(--dpad-arrow-position);\n border-right-color: var(--dpad-fg-color-disabled);\n}\n\n.right.disabled:before {\n right: var(--dpad-arrow-position);\n border-left-color: var(--dpad-fg-color-disabled);\n}\n",":root {\n --joystick-surface-size: 200px;\n --joystick-stick-size: 50px;\n\n --joystick-color: #5217b8;\n --joystick-color-active: #ffb300;\n --joystick-color-disabled: #bbb;\n}\n\n.joystick {\n position: relative;\n display: flex;\n justify-content: center;\n align-items: center;\n\n overflow: hidden;\n\n height: var(--joystick-surface-size);\n width: var(--joystick-surface-size);\n border-radius: calc(var(--joystick-stick-size) / 2);\n border-color: var(--joystick-color);\n border-width: 1px;\n border-style: solid;\n\n transition: all 0.25s;\n}\n\n.joystick > .stick {\n height: var(--joystick-stick-size);\n width: var(--joystick-stick-size);\n\n border-radius: 50%;\n background-color: var(--joystick-color);\n\n transition: all 0.25s;\n}\n\n.joystick.active {\n border-color: var(--joystick-color-active);\n}\n\n.joystick.active > .stick {\n background-color: var(--joystick-color-active);\n}\n\n.joystick.disabled {\n border-color: var(--joystick-color-disabled);\n}\n\n.joystick.disabled > .stick {\n background-color: var(--joystick-color-disabled);\n}\n"],"names":[],"sourceRoot":""} \ No newline at end of file diff --git a/cogment_verse/web/components/src/App.jsx b/cogment_verse/web/components/src/App.jsx deleted file mode 100644 index 934536d0..00000000 --- a/cogment_verse/web/components/src/App.jsx +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2022 AI Redefined Inc. -// -// 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. - -import { useCallback, useEffect, useRef, useState } from "react"; -import { cogSettings } from "./CogSettings"; -import { Countdown } from "./components/Countdown"; -import { useActions } from "./hooks/useActions"; -import { RenderedScreen } from "./components/RenderedScreen"; -import { Button } from "./components/Button"; -import { Controls } from "./controls/Controls"; -import { ORCHESTRATOR_WEB_ENDPOINT } from "./utils/constants"; - -function App() { - const [trialStatus, setTrialStatus] = useState("no trial started"); - const [countdown, setCountdown] = useState(false); - - const [{ trialId, runId, environment, turnBased }, setTrialInfo] = useState({}); - - const [event, joinAnyTrial, _sendAction, trialJoined, actorClass, actorConfig] = useActions( - cogSettings, - ORCHESTRATOR_WEB_ENDPOINT - ); - - const actionLock = useRef(false); - - useEffect(() => { - actionLock.current = false; - }, [event]); - - const sendAction = useCallback( - (action) => { - // use lock to ensure we send exactly one action per tick - if (actionLock.current) return; - if (_sendAction) { - _sendAction(action); - actionLock.current = true; - } - }, - [_sendAction] - ); - - useEffect(() => { - setTrialInfo((trialInfo = {}) => ({ - ...trialInfo, - environment: actorConfig?.environmentSpecs?.implementation || undefined, - turnBased: actorConfig?.environmentSpecs?.turnBased || false, - runId: actorConfig?.runId || undefined, - })); - }, [actorConfig]); - const joinTrial = useCallback(() => { - setCountdown(false); - const joinResult = joinAnyTrial(); - if (!joinResult) return; - if (!joinResult.joinPromise) return; - setTrialInfo((trialInfo = {}) => ({ - ...trialInfo, - trialId: joinResult.trialToJoin, - })); - setTrialStatus("trial joined"); - joinResult.joinPromise.then(() => { - setTrialInfo((trialInfo = {}) => ({ - ...trialInfo, - trialId: undefined, - })); - setTrialStatus("waiting to join trial"); - setCountdown(true); - }); - }, [joinAnyTrial]); - - return ( -
-
-

{environment}

-
- {runId}/{trialId} -
-
- - - ) : trialId == null ? ( - - ) : null - } - /> -
- {trialJoined ? ( - - ) : null} -
Status: {trialStatus}
-
-
- ); -} - -export default App; diff --git a/cogment_verse/web/utils/generate.py b/cogment_verse/web/utils/generate.py index 4f4950b2..e7a0ca5c 100644 --- a/cogment_verse/web/utils/generate.py +++ b/cogment_verse/web/utils/generate.py @@ -27,6 +27,8 @@ def generate(specs_filename, web_dir, force=False): cog_generate_source_files = [ specs_filename, os.path.join(os.path.dirname(specs_filename), "data.proto"), + os.path.join(os.path.dirname(specs_filename), "ndarray.proto"), + os.path.join(os.path.dirname(specs_filename), "spaces.proto"), ] # TODO make that more generic do_generate = force diff --git a/cogment_verse/web/utils/npm.py b/cogment_verse/web/utils/npm.py index dc9f7430..bf5392cb 100644 --- a/cogment_verse/web/utils/npm.py +++ b/cogment_verse/web/utils/npm.py @@ -23,7 +23,9 @@ def npm_command(args, cwd): try: - subprocess.run([NPM_BIN, *args], cwd=cwd, capture_output=True, check=True) + args = [NPM_BIN, *args] + res = subprocess.run(args, cwd=cwd, capture_output=True, check=True) + log.debug(f"Call to {args} returned {res.stdout.decode('utf-8')}") except subprocess.CalledProcessError as err: log.error( f"Error while running [{args}] in [{cwd}]\n---STDOUT---\n{err.stdout.decode('utf-8')}\n---STDERR---\n{err.stderr.decode('utf-8')}" diff --git a/cogment_verse/web/web_app/build/asset-manifest.json b/cogment_verse/web/web_app/build/asset-manifest.json index 91841da0..21175842 100644 --- a/cogment_verse/web/web_app/build/asset-manifest.json +++ b/cogment_verse/web/web_app/build/asset-manifest.json @@ -1,15 +1,15 @@ { "files": { - "main.css": "/static/css/main.116f63ff.css", - "main.js": "/static/js/main.343deae2.js", + "main.css": "/static/css/main.afd381f3.css", + "main.js": "/static/js/main.f749e5c1.js", "static/js/787.90542627.chunk.js": "/static/js/787.90542627.chunk.js", "index.html": "/index.html", - "main.116f63ff.css.map": "/static/css/main.116f63ff.css.map", - "main.343deae2.js.map": "/static/js/main.343deae2.js.map", + "main.afd381f3.css.map": "/static/css/main.afd381f3.css.map", + "main.f749e5c1.js.map": "/static/js/main.f749e5c1.js.map", "787.90542627.chunk.js.map": "/static/js/787.90542627.chunk.js.map" }, "entrypoints": [ - "static/css/main.116f63ff.css", - "static/js/main.343deae2.js" + "static/css/main.afd381f3.css", + "static/js/main.f749e5c1.js" ] } \ No newline at end of file diff --git a/cogment_verse/web/web_app/build/index.html b/cogment_verse/web/web_app/build/index.html index 8e78ad95..012e2f8c 100644 --- a/cogment_verse/web/web_app/build/index.html +++ b/cogment_verse/web/web_app/build/index.html @@ -1 +1 @@ -Cogment Verse
\ No newline at end of file +Cogment Verse
\ No newline at end of file diff --git a/cogment_verse/web/web_app/build/static/css/main.116f63ff.css b/cogment_verse/web/web_app/build/static/css/main.116f63ff.css deleted file mode 100644 index f8e2886b..00000000 --- a/cogment_verse/web/web_app/build/static/css/main.116f63ff.css +++ /dev/null @@ -1,4 +0,0 @@ -/* -! tailwindcss v3.2.4 | MIT License | https://tailwindcss.com -*/*,:after,:before{border:0 solid #e5e7eb;box-sizing:border-box}:after,:before{--tw-content:""}html{-webkit-text-size-adjust:100%;-webkit-font-feature-settings:normal;font-feature-settings:normal;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5;tab-size:4}body{line-height:inherit}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{color:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#9ca3af;opacity:1}input::placeholder,textarea::placeholder{color:#9ca3af;opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}[hidden]{display:none}*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::-webkit-backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.static{position:static}.mx-auto{margin-left:auto;margin-right:auto}.my-5{margin-bottom:1.25rem;margin-top:1.25rem}.mb-2{margin-bottom:.5rem}.mt-2{margin-top:.5rem}.mt-5{margin-top:1.25rem}.block{display:block}.flex{display:flex}.aspect-square{aspect-ratio:1/1}.min-h-screen{min-height:100vh}.w-full{width:100%}.w-fit{width:-webkit-fit-content;width:-moz-fit-content;width:fit-content}.max-w-screen-md{max-width:768px}.flex-1{flex:1 1}.flex-none{flex:none}.flex-initial{flex:0 1 auto}.grow{flex-grow:1}.transform{-webkit-transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.list-inside{list-style-position:inside}.list-disc{list-style-type:disc}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-center{justify-content:center}.gap-1{gap:.25rem}.gap-4{gap:1rem}.gap-2{gap:.5rem}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-md{border-radius:.375rem}.border-l-8{border-left-width:8px}.border-red-600{--tw-border-opacity:1;border-color:rgb(220 38 38/var(--tw-border-opacity))}.bg-indigo-600{--tw-bg-opacity:1;background-color:rgb(79 70 229/var(--tw-bg-opacity))}.bg-slate-600{--tw-bg-opacity:1;background-color:rgb(71 85 105/var(--tw-bg-opacity))}.bg-indigo-200{--tw-bg-opacity:1;background-color:rgb(199 210 254/var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-emerald-500{--tw-bg-opacity:1;background-color:rgb(16 185 129/var(--tw-bg-opacity))}.bg-red-600{--tw-bg-opacity:1;background-color:rgb(220 38 38/var(--tw-bg-opacity))}.bg-slate-100{--tw-bg-opacity:1;background-color:rgb(241 245 249/var(--tw-bg-opacity))}.p-5{padding:1.25rem}.p-2{padding:.5rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.py-3{padding-bottom:.75rem;padding-top:.75rem}.px-10{padding-left:2.5rem;padding-right:2.5rem}.text-center{text-align:center}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-base{font-size:1rem;line-height:1.5rem}.font-semibold{font-weight:600}.font-medium{font-weight:500}.lowercase{text-transform:lowercase}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.shadow-md{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color);box-shadow:0 0 #0000,0 0 #0000,var(--tw-shadow);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.ring-8{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(8px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),0 0 #0000;box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-inset{--tw-ring-inset:inset}.blur{--tw-blur:blur(8px)}.blur,.filter{-webkit-filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.duration-75{transition-duration:75ms}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;margin:0}code{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}.hover\:bg-indigo-900:hover{--tw-bg-opacity:1;background-color:rgb(49 46 129/var(--tw-bg-opacity))}.hover\:bg-emerald-800:hover{--tw-bg-opacity:1;background-color:rgb(6 95 70/var(--tw-bg-opacity))}.disabled\:bg-gray-400:disabled{--tw-bg-opacity:1;background-color:rgb(156 163 175/var(--tw-bg-opacity))}.disabled\:text-gray-200:disabled{--tw-text-opacity:1;color:rgb(229 231 235/var(--tw-text-opacity))}.RenderedScreen_container__9inx9{display:grid;position:relative}.RenderedScreen_canvas__Zmrsu,.RenderedScreen_overlay__fApA7{grid-area:1/-1;width:100%;z-index:0}.RenderedScreen_overlay__fApA7{align-items:center;display:flex;justify-content:center;z-index:1}:root{--dpad-bg-color:#fff;--dpad-bg-color-hover:#eee;--dpad-bg-color-active:#fff;--dpad-bg-color-disabled:#fff;--dpad-fg-color:#5217b8;--dpad-fg-color-hover:#5217b8;--dpad-fg-color-active:#ffb300;--dpad-fg-color-disabled:#bbb;--dpad-button-outer-radius:15%;--dpad-button-inner-radius:50%;--dpad-arrow-position:40%;--dpad-arrow-position-hover:35%;--dpad-arrow-base:19px;--dpad-arrow-height:13px}.DPad_dpad__ZZdxt{display:inline-block;height:200px;overflow:hidden;position:relative;width:200px}.DPad_down__EeuUg,.DPad_left__1AYHI,.DPad_right__AqUBc,.DPad_up__dOfw6{-webkit-tap-highlight-color:rgba(255,255,255,0);background:#fff;background:var(--dpad-bg-color);border-color:#5217b8;border-color:var(--dpad-fg-color);border-style:solid;border-width:1px;color:transparent;display:block;line-height:40%;padding:0;position:absolute;text-align:center}.DPad_down__EeuUg,.DPad_up__dOfw6{height:43%;width:33.3%}.DPad_left__1AYHI,.DPad_right__AqUBc{height:33%;width:43%}.DPad_up__dOfw6{border-radius:15% 15% 50% 50%;border-radius:var(--dpad-button-outer-radius) var(--dpad-button-outer-radius) var(--dpad-button-inner-radius) var(--dpad-button-inner-radius);top:0}.DPad_down__EeuUg,.DPad_up__dOfw6{left:50%;-webkit-transform:translate(-50%);transform:translate(-50%)}.DPad_down__EeuUg{border-radius:50% 50% 15% 15%;border-radius:var(--dpad-button-inner-radius) var(--dpad-button-inner-radius) var(--dpad-button-outer-radius) var(--dpad-button-outer-radius);bottom:0}.DPad_left__1AYHI{border-radius:15% 50% 50% 15%;border-radius:var(--dpad-button-outer-radius) var(--dpad-button-inner-radius) var(--dpad-button-inner-radius) var(--dpad-button-outer-radius);left:0}.DPad_left__1AYHI,.DPad_right__AqUBc{top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.DPad_right__AqUBc{border-radius:50% 15% 15% 50%;border-radius:50% var(--dpad-button-outer-radius) var(--dpad-button-outer-radius) 50%;right:0}.DPad_down__EeuUg:before,.DPad_left__1AYHI:before,.DPad_right__AqUBc:before,.DPad_up__dOfw6:before{border-radius:5px;border-style:solid;content:"";height:0;position:absolute;transition:all .25s;width:0}.DPad_up__dOfw6:before{border-color:transparent transparent #5217b8;border-color:transparent transparent var(--dpad-fg-color) transparent;border-width:0 13px 19px;border-width:0 var(--dpad-arrow-height) var(--dpad-arrow-base) var(--dpad-arrow-height);left:50%;top:40%;top:var(--dpad-arrow-position);-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%)}.DPad_down__EeuUg:before{border-color:#5217b8 transparent transparent;border-color:var(--dpad-fg-color) transparent transparent transparent;border-width:19px 13px 0;border-width:var(--dpad-arrow-base) var(--dpad-arrow-height) 0 var(--dpad-arrow-height);bottom:40%;bottom:var(--dpad-arrow-position);left:50%;-webkit-transform:translate(-50%,50%);transform:translate(-50%,50%)}.DPad_left__1AYHI:before{border-color:transparent #5217b8 transparent transparent;border-color:transparent var(--dpad-fg-color) transparent transparent;border-width:13px 19px 13px 0;border-width:var(--dpad-arrow-height) var(--dpad-arrow-base) var(--dpad-arrow-height) 0;left:40%;left:var(--dpad-arrow-position);top:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%)}.DPad_right__AqUBc:before{border-color:transparent transparent transparent #5217b8;border-color:transparent transparent transparent var(--dpad-fg-color);border-width:13px 0 13px 19px;border-width:var(--dpad-arrow-height) 0 var(--dpad-arrow-height) var(--dpad-arrow-base);right:40%;right:var(--dpad-arrow-position);top:50%;-webkit-transform:translate(50%,-50%);transform:translate(50%,-50%)}.DPad_down__EeuUg:hover,.DPad_left__1AYHI:hover,.DPad_right__AqUBc:hover,.DPad_up__dOfw6:hover{background:#eee;background:var(--dpad-bg-color-hover);border-color:#5217b8;border-color:var(--dpad-fg-color-hover)}.DPad_up__dOfw6:hover:before{border-bottom-color:#5217b8;border-bottom-color:var(--dpad-fg-color-hover);top:35%;top:var(--dpad-arrow-position-hover)}.DPad_down__EeuUg:hover:before{border-top-color:#5217b8;border-top-color:var(--dpad-fg-color-hover);bottom:35%;bottom:var(--dpad-arrow-position-hover)}.DPad_left__1AYHI:hover:before{border-right-color:#5217b8;border-right-color:var(--dpad-fg-color-hover);left:35%;left:var(--dpad-arrow-position-hover)}.DPad_right__AqUBc:hover:before{border-left-color:#5217b8;border-left-color:var(--dpad-fg-color-hover);right:35%;right:var(--dpad-arrow-position-hover)}.DPad_down__EeuUg.DPad_active__OzzXu,.DPad_down__EeuUg:active,.DPad_left__1AYHI.DPad_active__OzzXu,.DPad_left__1AYHI:active,.DPad_right__AqUBc.DPad_active__OzzXu,.DPad_right__AqUBc:active,.DPad_up__dOfw6.DPad_active__OzzXu,.DPad_up__dOfw6:active{background:#fff;background:var(--dpad-bg-color-active);border-color:#ffb300;border-color:var(--dpad-fg-color-active)}.DPad_up__dOfw6.DPad_active__OzzXu:before,.DPad_up__dOfw6:active:before{border-bottom-color:#ffb300;border-bottom-color:var(--dpad-fg-color-active)}.DPad_down__EeuUg.DPad_active__OzzXu:before,.DPad_down__EeuUg:active:before{border-top-color:#ffb300;border-top-color:var(--dpad-fg-color-active)}.DPad_left__1AYHI.DPad_active__OzzXu:before,.DPad_left__1AYHI:active:before{border-right-color:#ffb300;border-right-color:var(--dpad-fg-color-active)}.DPad_right__AqUBc.DPad_active__OzzXu:before,.DPad_right__AqUBc:active:before{border-left-color:#ffb300;border-left-color:var(--dpad-fg-color-active)}.DPad_down__EeuUg.DPad_disabled__\+IfWl,.DPad_left__1AYHI.DPad_disabled__\+IfWl,.DPad_right__AqUBc.DPad_disabled__\+IfWl,.DPad_up__dOfw6.DPad_disabled__\+IfWl{background:#fff;background:var(--dpad-bg-color-disabled);border-color:#bbb;border-color:var(--dpad-fg-color-disabled)}.DPad_up__dOfw6.DPad_disabled__\+IfWl:before{border-bottom-color:#bbb;border-bottom-color:var(--dpad-fg-color-disabled);top:40%;top:var(--dpad-arrow-position)}.DPad_down__EeuUg.DPad_disabled__\+IfWl:before{border-top-color:#bbb;border-top-color:var(--dpad-fg-color-disabled);bottom:40%;bottom:var(--dpad-arrow-position)}.DPad_left__1AYHI.DPad_disabled__\+IfWl:before{border-right-color:#bbb;border-right-color:var(--dpad-fg-color-disabled);left:40%;left:var(--dpad-arrow-position)}.DPad_right__AqUBc.DPad_disabled__\+IfWl:before{border-left-color:#bbb;border-left-color:var(--dpad-fg-color-disabled);right:40%;right:var(--dpad-arrow-position)}:root{--joystick-surface-size:200px;--joystick-stick-size:50px;--joystick-color:#5217b8;--joystick-color-active:#ffb300;--joystick-color-disabled:#bbb}.Joystick_joystick__DwFj2{align-items:center;border-color:#5217b8;border-color:var(--joystick-color);border-radius:25px;border-radius:calc(var(--joystick-stick-size)/2);border-style:solid;border-width:1px;display:flex;height:200px;height:var(--joystick-surface-size);justify-content:center;overflow:hidden;position:relative;transition:all .25s;width:200px;width:var(--joystick-surface-size)}.Joystick_joystick__DwFj2>.Joystick_stick__z5P-5{background-color:#5217b8;background-color:var(--joystick-color);border-radius:50%;height:50px;height:var(--joystick-stick-size);transition:all .25s;width:50px;width:var(--joystick-stick-size)}.Joystick_joystick__DwFj2.Joystick_active__EOXxn{border-color:#ffb300;border-color:var(--joystick-color-active)}.Joystick_joystick__DwFj2.Joystick_active__EOXxn>.Joystick_stick__z5P-5{background-color:#ffb300;background-color:var(--joystick-color-active)}.Joystick_joystick__DwFj2.Joystick_disabled__WyYwu{border-color:#bbb;border-color:var(--joystick-color-disabled)}.Joystick_joystick__DwFj2.Joystick_disabled__WyYwu>.Joystick_stick__z5P-5{background-color:#bbb;background-color:var(--joystick-color-disabled)} -/*# sourceMappingURL=main.116f63ff.css.map*/ \ No newline at end of file diff --git a/cogment_verse/web/web_app/build/static/css/main.116f63ff.css.map b/cogment_verse/web/web_app/build/static/css/main.116f63ff.css.map deleted file mode 100644 index dfd35f29..00000000 --- a/cogment_verse/web/web_app/build/static/css/main.116f63ff.css.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"static/css/main.116f63ff.css","mappings":"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","sources":["index.css","components/RenderedScreen.module.css","components/DPad.module.css","components/Joystick.module.css"],"sourcesContent":["@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\nbody {\n margin: 0;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Roboto\", \"Oxygen\", \"Ubuntu\", \"Cantarell\", \"Fira Sans\",\n \"Droid Sans\", \"Helvetica Neue\", sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\ncode {\n font-family: source-code-pro, Menlo, Monaco, Consolas, \"Courier New\", monospace;\n}\n",".container {\n position: relative;\n display: grid;\n}\n\n.canvas,\n.overlay {\n grid-area: 1/-1;\n z-index: 0;\n\n width: 100%;\n}\n\n.overlay {\n z-index: 1;\n\n display: flex;\n justify-content: center;\n align-items: center;\n}\n",":root {\n --dpad-bg-color: #fff;\n --dpad-bg-color-hover: #eee;\n --dpad-bg-color-active: #fff;\n --dpad-bg-color-disabled: #fff;\n --dpad-fg-color: #5217b8;\n --dpad-fg-color-hover: #5217b8;\n --dpad-fg-color-active: #ffb300;\n --dpad-fg-color-disabled: #bbb;\n\n --dpad-button-outer-radius: 15%;\n --dpad-button-inner-radius: 50%;\n\n --dpad-arrow-position: 40%;\n --dpad-arrow-position-hover: 35%;\n --dpad-arrow-base: 19px;\n --dpad-arrow-height: 13px;\n}\n\n.dpad {\n position: relative;\n display: inline-block;\n\n width: 200px;\n height: 200px;\n\n overflow: hidden;\n}\n\n/* Buttons background */\n\n.up,\n.right,\n.down,\n.left {\n display: block;\n position: absolute;\n -webkit-tap-highlight-color: rgba(255, 255, 255, 0);\n\n line-height: 40%;\n text-align: center;\n background: var(--dpad-bg-color);\n border-color: var(--dpad-fg-color);\n border-style: solid;\n border-width: 1px;\n padding: 0px;\n color: transparent;\n}\n\n.up,\n.down {\n width: 33.3%;\n height: 43%;\n}\n\n.left,\n.right {\n width: 43%;\n height: 33%;\n}\n\n.up {\n top: 0;\n left: 50%;\n transform: translate(-50%, 0);\n border-radius: var(--dpad-button-outer-radius) var(--dpad-button-outer-radius) var(--dpad-button-inner-radius)\n var(--dpad-button-inner-radius);\n}\n\n.down {\n bottom: 0;\n left: 50%;\n transform: translate(-50%, 0);\n border-radius: var(--dpad-button-inner-radius) var(--dpad-button-inner-radius) var(--dpad-button-outer-radius)\n var(--dpad-button-outer-radius);\n}\n\n.left {\n top: 50%;\n left: 0;\n transform: translate(0, -50%);\n border-radius: var(--dpad-button-outer-radius) var(--dpad-button-inner-radius) var(--dpad-button-inner-radius)\n var(--dpad-button-outer-radius);\n}\n\n.right {\n top: 50%;\n right: 0;\n transform: translate(0, -50%);\n border-radius: 50% var(--dpad-button-outer-radius) var(--dpad-button-outer-radius) 50%;\n}\n\n/* Buttons arrows */\n.up:before,\n.right:before,\n.down:before,\n.left:before {\n content: \"\";\n position: absolute;\n width: 0;\n height: 0;\n border-radius: 5px;\n border-style: solid;\n transition: all 0.25s;\n}\n\n.up:before {\n top: var(--dpad-arrow-position);\n left: 50%;\n transform: translate(-50%, -50%);\n border-width: 0 var(--dpad-arrow-height) var(--dpad-arrow-base) var(--dpad-arrow-height);\n border-color: transparent transparent var(--dpad-fg-color) transparent;\n}\n\n.down:before {\n bottom: var(--dpad-arrow-position);\n left: 50%;\n transform: translate(-50%, 50%);\n border-width: var(--dpad-arrow-base) var(--dpad-arrow-height) 0px var(--dpad-arrow-height);\n border-color: var(--dpad-fg-color) transparent transparent transparent;\n}\n\n.left:before {\n left: var(--dpad-arrow-position);\n top: 50%;\n transform: translate(-50%, -50%);\n border-width: var(--dpad-arrow-height) var(--dpad-arrow-base) var(--dpad-arrow-height) 0;\n border-color: transparent var(--dpad-fg-color) transparent transparent;\n}\n\n.right:before {\n right: var(--dpad-arrow-position);\n top: 50%;\n transform: translate(50%, -50%);\n border-width: var(--dpad-arrow-height) 0 var(--dpad-arrow-height) var(--dpad-arrow-base);\n border-color: transparent transparent transparent var(--dpad-fg-color);\n}\n\n/* Hover */\n\n.up:hover,\n.right:hover,\n.down:hover,\n.left:hover {\n background: var(--dpad-bg-color-hover);\n border-color: var(--dpad-fg-color-hover);\n}\n\n.up:hover:before {\n top: var(--dpad-arrow-position-hover);\n border-bottom-color: var(--dpad-fg-color-hover);\n}\n\n.down:hover:before {\n bottom: var(--dpad-arrow-position-hover);\n border-top-color: var(--dpad-fg-color-hover);\n}\n\n.left:hover:before {\n left: var(--dpad-arrow-position-hover);\n border-right-color: var(--dpad-fg-color-hover);\n}\n\n.right:hover:before {\n right: var(--dpad-arrow-position-hover);\n border-left-color: var(--dpad-fg-color-hover);\n}\n\n/* Active */\n\n.up:active,\n.right:active,\n.down:active,\n.left:active,\n.up.active,\n.right.active,\n.down.active,\n.left.active {\n background: var(--dpad-bg-color-active);\n border-color: var(--dpad-fg-color-active);\n}\n\n.up:active:before,\n.up.active:before {\n border-bottom-color: var(--dpad-fg-color-active);\n}\n\n.down:active:before,\n.down.active:before {\n border-top-color: var(--dpad-fg-color-active);\n}\n\n.left:active:before,\n.left.active:before {\n border-right-color: var(--dpad-fg-color-active);\n}\n\n.right:active:before,\n.right.active:before {\n border-left-color: var(--dpad-fg-color-active);\n}\n\n/* Disabled */\n\n.up.disabled,\n.right.disabled,\n.down.disabled,\n.left.disabled {\n background: var(--dpad-bg-color-disabled);\n border-color: var(--dpad-fg-color-disabled);\n}\n\n.up.disabled:before {\n top: var(--dpad-arrow-position);\n border-bottom-color: var(--dpad-fg-color-disabled);\n}\n\n.down.disabled:before {\n bottom: var(--dpad-arrow-position);\n border-top-color: var(--dpad-fg-color-disabled);\n}\n\n.left.disabled:before {\n left: var(--dpad-arrow-position);\n border-right-color: var(--dpad-fg-color-disabled);\n}\n\n.right.disabled:before {\n right: var(--dpad-arrow-position);\n border-left-color: var(--dpad-fg-color-disabled);\n}\n",":root {\n --joystick-surface-size: 200px;\n --joystick-stick-size: 50px;\n\n --joystick-color: #5217b8;\n --joystick-color-active: #ffb300;\n --joystick-color-disabled: #bbb;\n}\n\n.joystick {\n position: relative;\n display: flex;\n justify-content: center;\n align-items: center;\n\n overflow: hidden;\n\n height: var(--joystick-surface-size);\n width: var(--joystick-surface-size);\n border-radius: calc(var(--joystick-stick-size) / 2);\n border-color: var(--joystick-color);\n border-width: 1px;\n border-style: solid;\n\n transition: all 0.25s;\n}\n\n.joystick > .stick {\n height: var(--joystick-stick-size);\n width: var(--joystick-stick-size);\n\n border-radius: 50%;\n background-color: var(--joystick-color);\n\n transition: all 0.25s;\n}\n\n.joystick.active {\n border-color: var(--joystick-color-active);\n}\n\n.joystick.active > .stick {\n background-color: var(--joystick-color-active);\n}\n\n.joystick.disabled {\n border-color: var(--joystick-color-disabled);\n}\n\n.joystick.disabled > .stick {\n background-color: var(--joystick-color-disabled);\n}\n"],"names":[],"sourceRoot":""} \ No newline at end of file diff --git a/cogment_verse/web/web_app/build/static/css/main.afd381f3.css b/cogment_verse/web/web_app/build/static/css/main.afd381f3.css new file mode 100644 index 00000000..cb1565d0 --- /dev/null +++ b/cogment_verse/web/web_app/build/static/css/main.afd381f3.css @@ -0,0 +1,4 @@ +/* +! tailwindcss v3.2.4 | MIT License | https://tailwindcss.com +*/*,:after,:before{border:0 solid #e5e7eb;box-sizing:border-box}:after,:before{--tw-content:""}html{-webkit-text-size-adjust:100%;-webkit-font-feature-settings:normal;font-feature-settings:normal;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5;tab-size:4}body{line-height:inherit}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{color:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#9ca3af;opacity:1}input::placeholder,textarea::placeholder{color:#9ca3af;opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}[hidden]{display:none}*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::-webkit-backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.visible{visibility:visible}.\!visible{visibility:visible!important}.static{position:static}.absolute{position:absolute}.relative{position:relative}.inset-x-0{left:0;right:0}.top-full{top:100%}.z-10{z-index:10}.mx-auto{margin-left:auto;margin-right:auto}.my-2{margin-bottom:.5rem;margin-top:.5rem}.my-5{margin-bottom:1.25rem;margin-top:1.25rem}.ml-2{margin-left:.5rem}.mt-1{margin-top:.25rem}.mb-2{margin-bottom:.5rem}.mt-2{margin-top:.5rem}.mt-5{margin-top:1.25rem}.block{display:block}.flex{display:flex}.table{display:table}.aspect-square{aspect-ratio:1/1}.min-h-screen{min-height:100vh}.w-full{width:100%}.w-fit{width:-webkit-fit-content;width:-moz-fit-content;width:fit-content}.max-w-screen-md{max-width:768px}.flex-1{flex:1 1}.flex-none{flex:none}.flex-initial{flex:0 1 auto}.grow{flex-grow:1}.table-fixed{table-layout:fixed}.transform{-webkit-transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.list-inside{list-style-position:inside}.list-disc{list-style-type:disc}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.items-start{align-items:flex-start}.items-center{align-items:center}.items-stretch{align-items:stretch}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-4{gap:1rem}.gap-2{gap:.5rem}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-md{border-radius:.375rem}.rounded-b{border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem}.border-l-8{border-left-width:8px}.border-red-600{--tw-border-opacity:1;border-color:rgb(220 38 38/var(--tw-border-opacity))}.bg-indigo-600{--tw-bg-opacity:1;background-color:rgb(79 70 229/var(--tw-bg-opacity))}.bg-slate-600{--tw-bg-opacity:1;background-color:rgb(71 85 105/var(--tw-bg-opacity))}.bg-indigo-200{--tw-bg-opacity:1;background-color:rgb(199 210 254/var(--tw-bg-opacity))}.bg-neutral-400\/90{background-color:hsla(0,0%,64%,.9)}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-emerald-500{--tw-bg-opacity:1;background-color:rgb(16 185 129/var(--tw-bg-opacity))}.bg-red-600{--tw-bg-opacity:1;background-color:rgb(220 38 38/var(--tw-bg-opacity))}.bg-slate-100{--tw-bg-opacity:1;background-color:rgb(241 245 249/var(--tw-bg-opacity))}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-5{padding:1.25rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.py-3{padding-bottom:.75rem;padding-top:.75rem}.px-10{padding-left:2.5rem;padding-right:2.5rem}.text-center{text-align:center}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-sm{font-size:.875rem;line-height:1.25rem}.text-lg{font-size:1.125rem}.text-lg,.text-xl{line-height:1.75rem}.text-xl{font-size:1.25rem}.font-semibold{font-weight:600}.font-medium{font-weight:500}.lowercase{text-transform:lowercase}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.shadow-md{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color);box-shadow:0 0 #0000,0 0 #0000,var(--tw-shadow);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.ring-8{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(8px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),0 0 #0000;box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-inset{--tw-ring-inset:inset}.blur{--tw-blur:blur(8px)}.blur,.filter{-webkit-filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.duration-75{transition-duration:75ms}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;margin:0}code{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}.hover\:bg-indigo-900:hover{--tw-bg-opacity:1;background-color:rgb(49 46 129/var(--tw-bg-opacity))}.hover\:bg-emerald-800:hover{--tw-bg-opacity:1;background-color:rgb(6 95 70/var(--tw-bg-opacity))}.disabled\:bg-gray-400:disabled{--tw-bg-opacity:1;background-color:rgb(156 163 175/var(--tw-bg-opacity))}.disabled\:text-gray-200:disabled{--tw-text-opacity:1;color:rgb(229 231 235/var(--tw-text-opacity))}.RenderedScreen_container__9inx9{display:grid;position:relative}.RenderedScreen_canvas__Zmrsu,.RenderedScreen_overlay__fApA7{grid-area:1/-1;width:100%;z-index:0}.RenderedScreen_overlay__fApA7{align-items:center;display:flex;justify-content:center;z-index:1}:root{--dpad-bg-color:#fff;--dpad-bg-color-hover:#eee;--dpad-bg-color-active:#fff;--dpad-bg-color-disabled:#fff;--dpad-fg-color:#5217b8;--dpad-fg-color-hover:#5217b8;--dpad-fg-color-active:#ffb300;--dpad-fg-color-disabled:#bbb;--dpad-button-outer-radius:15%;--dpad-button-inner-radius:50%;--dpad-arrow-position:40%;--dpad-arrow-position-hover:35%;--dpad-arrow-base:19px;--dpad-arrow-height:13px}.DPad_dpad__ZZdxt{display:inline-block;height:200px;overflow:hidden;position:relative;width:200px}.DPad_down__EeuUg,.DPad_left__1AYHI,.DPad_right__AqUBc,.DPad_up__dOfw6{-webkit-tap-highlight-color:rgba(255,255,255,0);background:#fff;background:var(--dpad-bg-color);border-color:#5217b8;border-color:var(--dpad-fg-color);border-style:solid;border-width:1px;color:transparent;display:block;line-height:40%;padding:0;position:absolute;text-align:center}.DPad_down__EeuUg,.DPad_up__dOfw6{height:43%;width:33.3%}.DPad_left__1AYHI,.DPad_right__AqUBc{height:33%;width:43%}.DPad_up__dOfw6{border-radius:15% 15% 50% 50%;border-radius:var(--dpad-button-outer-radius) var(--dpad-button-outer-radius) var(--dpad-button-inner-radius) var(--dpad-button-inner-radius);top:0}.DPad_down__EeuUg,.DPad_up__dOfw6{left:50%;-webkit-transform:translate(-50%);transform:translate(-50%)}.DPad_down__EeuUg{border-radius:50% 50% 15% 15%;border-radius:var(--dpad-button-inner-radius) var(--dpad-button-inner-radius) var(--dpad-button-outer-radius) var(--dpad-button-outer-radius);bottom:0}.DPad_left__1AYHI{border-radius:15% 50% 50% 15%;border-radius:var(--dpad-button-outer-radius) var(--dpad-button-inner-radius) var(--dpad-button-inner-radius) var(--dpad-button-outer-radius);left:0}.DPad_left__1AYHI,.DPad_right__AqUBc{top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.DPad_right__AqUBc{border-radius:50% 15% 15% 50%;border-radius:50% var(--dpad-button-outer-radius) var(--dpad-button-outer-radius) 50%;right:0}.DPad_down__EeuUg:before,.DPad_left__1AYHI:before,.DPad_right__AqUBc:before,.DPad_up__dOfw6:before{border-radius:5px;border-style:solid;content:"";height:0;position:absolute;transition:all .25s;width:0}.DPad_up__dOfw6:before{border-color:transparent transparent #5217b8;border-color:transparent transparent var(--dpad-fg-color) transparent;border-width:0 13px 19px;border-width:0 var(--dpad-arrow-height) var(--dpad-arrow-base) var(--dpad-arrow-height);left:50%;top:40%;top:var(--dpad-arrow-position);-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%)}.DPad_down__EeuUg:before{border-color:#5217b8 transparent transparent;border-color:var(--dpad-fg-color) transparent transparent transparent;border-width:19px 13px 0;border-width:var(--dpad-arrow-base) var(--dpad-arrow-height) 0 var(--dpad-arrow-height);bottom:40%;bottom:var(--dpad-arrow-position);left:50%;-webkit-transform:translate(-50%,50%);transform:translate(-50%,50%)}.DPad_left__1AYHI:before{border-color:transparent #5217b8 transparent transparent;border-color:transparent var(--dpad-fg-color) transparent transparent;border-width:13px 19px 13px 0;border-width:var(--dpad-arrow-height) var(--dpad-arrow-base) var(--dpad-arrow-height) 0;left:40%;left:var(--dpad-arrow-position);top:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%)}.DPad_right__AqUBc:before{border-color:transparent transparent transparent #5217b8;border-color:transparent transparent transparent var(--dpad-fg-color);border-width:13px 0 13px 19px;border-width:var(--dpad-arrow-height) 0 var(--dpad-arrow-height) var(--dpad-arrow-base);right:40%;right:var(--dpad-arrow-position);top:50%;-webkit-transform:translate(50%,-50%);transform:translate(50%,-50%)}.DPad_down__EeuUg:hover,.DPad_left__1AYHI:hover,.DPad_right__AqUBc:hover,.DPad_up__dOfw6:hover{background:#eee;background:var(--dpad-bg-color-hover);border-color:#5217b8;border-color:var(--dpad-fg-color-hover)}.DPad_up__dOfw6:hover:before{border-bottom-color:#5217b8;border-bottom-color:var(--dpad-fg-color-hover);top:35%;top:var(--dpad-arrow-position-hover)}.DPad_down__EeuUg:hover:before{border-top-color:#5217b8;border-top-color:var(--dpad-fg-color-hover);bottom:35%;bottom:var(--dpad-arrow-position-hover)}.DPad_left__1AYHI:hover:before{border-right-color:#5217b8;border-right-color:var(--dpad-fg-color-hover);left:35%;left:var(--dpad-arrow-position-hover)}.DPad_right__AqUBc:hover:before{border-left-color:#5217b8;border-left-color:var(--dpad-fg-color-hover);right:35%;right:var(--dpad-arrow-position-hover)}.DPad_down__EeuUg.DPad_active__OzzXu,.DPad_down__EeuUg:active,.DPad_left__1AYHI.DPad_active__OzzXu,.DPad_left__1AYHI:active,.DPad_right__AqUBc.DPad_active__OzzXu,.DPad_right__AqUBc:active,.DPad_up__dOfw6.DPad_active__OzzXu,.DPad_up__dOfw6:active{background:#fff;background:var(--dpad-bg-color-active);border-color:#ffb300;border-color:var(--dpad-fg-color-active)}.DPad_up__dOfw6.DPad_active__OzzXu:before,.DPad_up__dOfw6:active:before{border-bottom-color:#ffb300;border-bottom-color:var(--dpad-fg-color-active)}.DPad_down__EeuUg.DPad_active__OzzXu:before,.DPad_down__EeuUg:active:before{border-top-color:#ffb300;border-top-color:var(--dpad-fg-color-active)}.DPad_left__1AYHI.DPad_active__OzzXu:before,.DPad_left__1AYHI:active:before{border-right-color:#ffb300;border-right-color:var(--dpad-fg-color-active)}.DPad_right__AqUBc.DPad_active__OzzXu:before,.DPad_right__AqUBc:active:before{border-left-color:#ffb300;border-left-color:var(--dpad-fg-color-active)}.DPad_down__EeuUg.DPad_disabled__\+IfWl,.DPad_left__1AYHI.DPad_disabled__\+IfWl,.DPad_right__AqUBc.DPad_disabled__\+IfWl,.DPad_up__dOfw6.DPad_disabled__\+IfWl{background:#fff;background:var(--dpad-bg-color-disabled);border-color:#bbb;border-color:var(--dpad-fg-color-disabled)}.DPad_up__dOfw6.DPad_disabled__\+IfWl:before{border-bottom-color:#bbb;border-bottom-color:var(--dpad-fg-color-disabled);top:40%;top:var(--dpad-arrow-position)}.DPad_down__EeuUg.DPad_disabled__\+IfWl:before{border-top-color:#bbb;border-top-color:var(--dpad-fg-color-disabled);bottom:40%;bottom:var(--dpad-arrow-position)}.DPad_left__1AYHI.DPad_disabled__\+IfWl:before{border-right-color:#bbb;border-right-color:var(--dpad-fg-color-disabled);left:40%;left:var(--dpad-arrow-position)}.DPad_right__AqUBc.DPad_disabled__\+IfWl:before{border-left-color:#bbb;border-left-color:var(--dpad-fg-color-disabled);right:40%;right:var(--dpad-arrow-position)}:root{--joystick-surface-size:200px;--joystick-stick-size:50px;--joystick-color:#5217b8;--joystick-color-active:#ffb300;--joystick-color-disabled:#bbb}.Joystick_joystick__DwFj2{align-items:center;border-color:#5217b8;border-color:var(--joystick-color);border-radius:25px;border-radius:calc(var(--joystick-stick-size)/2);border-style:solid;border-width:1px;display:flex;height:200px;height:var(--joystick-surface-size);justify-content:center;overflow:hidden;position:relative;transition:all .25s;width:200px;width:var(--joystick-surface-size)}.Joystick_joystick__DwFj2>.Joystick_stick__z5P-5{background-color:#5217b8;background-color:var(--joystick-color);border-radius:50%;height:50px;height:var(--joystick-stick-size);transition:all .25s;width:50px;width:var(--joystick-stick-size)}.Joystick_joystick__DwFj2.Joystick_active__EOXxn{border-color:#ffb300;border-color:var(--joystick-color-active)}.Joystick_joystick__DwFj2.Joystick_active__EOXxn>.Joystick_stick__z5P-5{background-color:#ffb300;background-color:var(--joystick-color-active)}.Joystick_joystick__DwFj2.Joystick_disabled__WyYwu{border-color:#bbb;border-color:var(--joystick-color-disabled)}.Joystick_joystick__DwFj2.Joystick_disabled__WyYwu>.Joystick_stick__z5P-5{background-color:#bbb;background-color:var(--joystick-color-disabled)} +/*# sourceMappingURL=main.afd381f3.css.map*/ \ No newline at end of file diff --git a/cogment_verse/web/web_app/build/static/css/main.afd381f3.css.map b/cogment_verse/web/web_app/build/static/css/main.afd381f3.css.map new file mode 100644 index 00000000..8df031a3 --- /dev/null +++ b/cogment_verse/web/web_app/build/static/css/main.afd381f3.css.map @@ -0,0 +1 @@ +{"version":3,"file":"static/css/main.afd381f3.css","mappings":"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","sources":["index.css","components/RenderedScreen.module.css","components/DPad.module.css","components/Joystick.module.css"],"sourcesContent":["@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\nbody {\n margin: 0;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Roboto\", \"Oxygen\", \"Ubuntu\", \"Cantarell\", \"Fira Sans\",\n \"Droid Sans\", \"Helvetica Neue\", sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\ncode {\n font-family: source-code-pro, Menlo, Monaco, Consolas, \"Courier New\", monospace;\n}\n",".container {\n position: relative;\n display: grid;\n}\n\n.canvas,\n.overlay {\n grid-area: 1/-1;\n z-index: 0;\n\n width: 100%;\n}\n\n.overlay {\n z-index: 1;\n\n display: flex;\n justify-content: center;\n align-items: center;\n}\n",":root {\n --dpad-bg-color: #fff;\n --dpad-bg-color-hover: #eee;\n --dpad-bg-color-active: #fff;\n --dpad-bg-color-disabled: #fff;\n --dpad-fg-color: #5217b8;\n --dpad-fg-color-hover: #5217b8;\n --dpad-fg-color-active: #ffb300;\n --dpad-fg-color-disabled: #bbb;\n\n --dpad-button-outer-radius: 15%;\n --dpad-button-inner-radius: 50%;\n\n --dpad-arrow-position: 40%;\n --dpad-arrow-position-hover: 35%;\n --dpad-arrow-base: 19px;\n --dpad-arrow-height: 13px;\n}\n\n.dpad {\n position: relative;\n display: inline-block;\n\n width: 200px;\n height: 200px;\n\n overflow: hidden;\n}\n\n/* Buttons background */\n\n.up,\n.right,\n.down,\n.left {\n display: block;\n position: absolute;\n -webkit-tap-highlight-color: rgba(255, 255, 255, 0);\n\n line-height: 40%;\n text-align: center;\n background: var(--dpad-bg-color);\n border-color: var(--dpad-fg-color);\n border-style: solid;\n border-width: 1px;\n padding: 0px;\n color: transparent;\n}\n\n.up,\n.down {\n width: 33.3%;\n height: 43%;\n}\n\n.left,\n.right {\n width: 43%;\n height: 33%;\n}\n\n.up {\n top: 0;\n left: 50%;\n transform: translate(-50%, 0);\n border-radius: var(--dpad-button-outer-radius) var(--dpad-button-outer-radius) var(--dpad-button-inner-radius)\n var(--dpad-button-inner-radius);\n}\n\n.down {\n bottom: 0;\n left: 50%;\n transform: translate(-50%, 0);\n border-radius: var(--dpad-button-inner-radius) var(--dpad-button-inner-radius) var(--dpad-button-outer-radius)\n var(--dpad-button-outer-radius);\n}\n\n.left {\n top: 50%;\n left: 0;\n transform: translate(0, -50%);\n border-radius: var(--dpad-button-outer-radius) var(--dpad-button-inner-radius) var(--dpad-button-inner-radius)\n var(--dpad-button-outer-radius);\n}\n\n.right {\n top: 50%;\n right: 0;\n transform: translate(0, -50%);\n border-radius: 50% var(--dpad-button-outer-radius) var(--dpad-button-outer-radius) 50%;\n}\n\n/* Buttons arrows */\n.up:before,\n.right:before,\n.down:before,\n.left:before {\n content: \"\";\n position: absolute;\n width: 0;\n height: 0;\n border-radius: 5px;\n border-style: solid;\n transition: all 0.25s;\n}\n\n.up:before {\n top: var(--dpad-arrow-position);\n left: 50%;\n transform: translate(-50%, -50%);\n border-width: 0 var(--dpad-arrow-height) var(--dpad-arrow-base) var(--dpad-arrow-height);\n border-color: transparent transparent var(--dpad-fg-color) transparent;\n}\n\n.down:before {\n bottom: var(--dpad-arrow-position);\n left: 50%;\n transform: translate(-50%, 50%);\n border-width: var(--dpad-arrow-base) var(--dpad-arrow-height) 0px var(--dpad-arrow-height);\n border-color: var(--dpad-fg-color) transparent transparent transparent;\n}\n\n.left:before {\n left: var(--dpad-arrow-position);\n top: 50%;\n transform: translate(-50%, -50%);\n border-width: var(--dpad-arrow-height) var(--dpad-arrow-base) var(--dpad-arrow-height) 0;\n border-color: transparent var(--dpad-fg-color) transparent transparent;\n}\n\n.right:before {\n right: var(--dpad-arrow-position);\n top: 50%;\n transform: translate(50%, -50%);\n border-width: var(--dpad-arrow-height) 0 var(--dpad-arrow-height) var(--dpad-arrow-base);\n border-color: transparent transparent transparent var(--dpad-fg-color);\n}\n\n/* Hover */\n\n.up:hover,\n.right:hover,\n.down:hover,\n.left:hover {\n background: var(--dpad-bg-color-hover);\n border-color: var(--dpad-fg-color-hover);\n}\n\n.up:hover:before {\n top: var(--dpad-arrow-position-hover);\n border-bottom-color: var(--dpad-fg-color-hover);\n}\n\n.down:hover:before {\n bottom: var(--dpad-arrow-position-hover);\n border-top-color: var(--dpad-fg-color-hover);\n}\n\n.left:hover:before {\n left: var(--dpad-arrow-position-hover);\n border-right-color: var(--dpad-fg-color-hover);\n}\n\n.right:hover:before {\n right: var(--dpad-arrow-position-hover);\n border-left-color: var(--dpad-fg-color-hover);\n}\n\n/* Active */\n\n.up:active,\n.right:active,\n.down:active,\n.left:active,\n.up.active,\n.right.active,\n.down.active,\n.left.active {\n background: var(--dpad-bg-color-active);\n border-color: var(--dpad-fg-color-active);\n}\n\n.up:active:before,\n.up.active:before {\n border-bottom-color: var(--dpad-fg-color-active);\n}\n\n.down:active:before,\n.down.active:before {\n border-top-color: var(--dpad-fg-color-active);\n}\n\n.left:active:before,\n.left.active:before {\n border-right-color: var(--dpad-fg-color-active);\n}\n\n.right:active:before,\n.right.active:before {\n border-left-color: var(--dpad-fg-color-active);\n}\n\n/* Disabled */\n\n.up.disabled,\n.right.disabled,\n.down.disabled,\n.left.disabled {\n background: var(--dpad-bg-color-disabled);\n border-color: var(--dpad-fg-color-disabled);\n}\n\n.up.disabled:before {\n top: var(--dpad-arrow-position);\n border-bottom-color: var(--dpad-fg-color-disabled);\n}\n\n.down.disabled:before {\n bottom: var(--dpad-arrow-position);\n border-top-color: var(--dpad-fg-color-disabled);\n}\n\n.left.disabled:before {\n left: var(--dpad-arrow-position);\n border-right-color: var(--dpad-fg-color-disabled);\n}\n\n.right.disabled:before {\n right: var(--dpad-arrow-position);\n border-left-color: var(--dpad-fg-color-disabled);\n}\n",":root {\n --joystick-surface-size: 200px;\n --joystick-stick-size: 50px;\n\n --joystick-color: #5217b8;\n --joystick-color-active: #ffb300;\n --joystick-color-disabled: #bbb;\n}\n\n.joystick {\n position: relative;\n display: flex;\n justify-content: center;\n align-items: center;\n\n overflow: hidden;\n\n height: var(--joystick-surface-size);\n width: var(--joystick-surface-size);\n border-radius: calc(var(--joystick-stick-size) / 2);\n border-color: var(--joystick-color);\n border-width: 1px;\n border-style: solid;\n\n transition: all 0.25s;\n}\n\n.joystick > .stick {\n height: var(--joystick-stick-size);\n width: var(--joystick-stick-size);\n\n border-radius: 50%;\n background-color: var(--joystick-color);\n\n transition: all 0.25s;\n}\n\n.joystick.active {\n border-color: var(--joystick-color-active);\n}\n\n.joystick.active > .stick {\n background-color: var(--joystick-color-active);\n}\n\n.joystick.disabled {\n border-color: var(--joystick-color-disabled);\n}\n\n.joystick.disabled > .stick {\n background-color: var(--joystick-color-disabled);\n}\n"],"names":[],"sourceRoot":""} \ No newline at end of file diff --git a/cogment_verse/web/web_app/build/static/js/main.343deae2.js b/cogment_verse/web/web_app/build/static/js/main.343deae2.js deleted file mode 100644 index 75ef704a..00000000 --- a/cogment_verse/web/web_app/build/static/js/main.343deae2.js +++ /dev/null @@ -1,3 +0,0 @@ -/*! For license information please see main.343deae2.js.LICENSE.txt */ -(function(){var __webpack_modules__={33:function(e,t,r){var n;t.CL=void 0;var o=r(358),i=function(){this.name="player",this.config=o.cogment_verse.AgentConfig,this.actionSpace=o.cogment_verse.PlayerAction,this.observationSpace=o.cogment_verse.Observation};var a=function(){this.name="teacher",this.config=o.cogment_verse.AgentConfig,this.actionSpace=o.cogment_verse.TeacherAction,this.observationSpace=o.cogment_verse.Observation};var s=function(){this.name="observer",this.config=o.cogment_verse.AgentConfig,this.actionSpace=o.cogment_verse.ObserverAction,this.observationSpace=o.cogment_verse.Observation};t.CL={messageUrlMap:(n={},n["type.googleapis.com/cogment_verse.NDArray"]=o.cogment_verse.NDArray,n["type.googleapis.com/cogment_verse.Space"]=o.cogment_verse.Space,n["type.googleapis.com/cogment_verse.Space.Discrete"]=o.cogment_verse.Space.Discrete,n["type.googleapis.com/cogment_verse.Space.Bound"]=o.cogment_verse.Space.Bound,n["type.googleapis.com/cogment_verse.Space.Box"]=o.cogment_verse.Space.Box,n["type.googleapis.com/cogment_verse.Space.Property"]=o.cogment_verse.Space.Property,n["type.googleapis.com/cogment_verse.SpaceValue"]=o.cogment_verse.SpaceValue,n["type.googleapis.com/cogment_verse.SpaceValue.SimpleBox"]=o.cogment_verse.SpaceValue.SimpleBox,n["type.googleapis.com/cogment_verse.SpaceValue.PropertyValue"]=o.cogment_verse.SpaceValue.PropertyValue,n["type.googleapis.com/cogment_verse.SpaceMask"]=o.cogment_verse.SpaceMask,n["type.googleapis.com/cogment_verse.SpaceMask.PropertyMask"]=o.cogment_verse.SpaceMask.PropertyMask,n["type.googleapis.com/cogment_verse.EnvironmentSpecs"]=o.cogment_verse.EnvironmentSpecs,n["type.googleapis.com/cogment_verse.EnvironmentConfig"]=o.cogment_verse.EnvironmentConfig,n["type.googleapis.com/cogment_verse.HFHubModel"]=o.cogment_verse.HFHubModel,n["type.googleapis.com/cogment_verse.AgentConfig"]=o.cogment_verse.AgentConfig,n["type.googleapis.com/cogment_verse.TrialConfig"]=o.cogment_verse.TrialConfig,n["type.googleapis.com/cogment_verse.Observation"]=o.cogment_verse.Observation,n["type.googleapis.com/cogment_verse.PlayerAction"]=o.cogment_verse.PlayerAction,n["type.googleapis.com/cogment_verse.TeacherAction"]=o.cogment_verse.TeacherAction,n["type.googleapis.com/cogment_verse.ObserverAction"]=o.cogment_verse.ObserverAction,n),actorClasses:{player:new i,teacher:new a,observer:new s},trial:{config:o.cogment_verse.TrialConfig},environment:{config:o.cogment_verse.EnvironmentConfig,class:{id:"env",config:o.cogment_verse.EnvironmentConfig}}}},358:function(e,t,r){var n,o,i;o=[r(886)],void 0===(i="function"===typeof(n=function(e){"use strict";var t=e.Reader,r=e.Writer,n=e.util,o=e.roots.default||(e.roots.default={});return o.cogment_verse=function(){var i={};return i.NDArray=function(){function i(e){if(this.shape=[],e)for(var t=Object.keys(e),r=0;r>>3){case 1:i.dtype=e.string();break;case 2:if(i.shape&&i.shape.length||(i.shape=[]),2===(7&a))for(var s=e.uint32()+e.pos;e.pos>>0}return null!=e.data&&("string"===typeof e.data?n.base64.decode(e.data,t.data=n.newBuffer(n.base64.length(e.data)),0):e.data.length>=0&&(t.data=e.data)),t},i.toObject=function(e,t){t||(t={});var r={};if((t.arrays||t.defaults)&&(r.shape=[]),t.defaults&&(r.dtype="",t.bytes===String?r.data="":(r.data=[],t.bytes!==Array&&(r.data=n.newBuffer(r.data)))),null!=e.dtype&&e.hasOwnProperty("dtype")&&(r.dtype=e.dtype),e.shape&&e.shape.length){r.shape=[];for(var o=0;o>>3===1?(i.properties&&i.properties.length||(i.properties=[]),i.properties.push(o.cogment_verse.Space.Property.decode(e,e.uint32()))):e.skipType(7&a)}return i},i.decodeDelimited=function(e){return e instanceof t||(e=new t(e)),this.decode(e,e.uint32())},i.verify=function(e){if("object"!==typeof e||null===e)return"object expected";if(null!=e.properties&&e.hasOwnProperty("properties")){if(!Array.isArray(e.properties))return"properties: array expected";for(var t=0;t>>3){case 1:i.num=e.int32();break;case 2:i.labels&&i.labels.length||(i.labels=[]),i.labels.push(e.string());break;default:e.skipType(7&a)}}return i},i.decodeDelimited=function(e){return e instanceof t||(e=new t(e)),this.decode(e,e.uint32())},i.verify=function(e){if("object"!==typeof e||null===e)return"object expected";if(null!=e.num&&e.hasOwnProperty("num")&&!n.isInteger(e.num))return"num: integer expected";if(null!=e.labels&&e.hasOwnProperty("labels")){if(!Array.isArray(e.labels))return"labels: array expected";for(var t=0;t>>3===1?i.bound=e.float():e.skipType(7&a)}return i},i.decodeDelimited=function(e){return e instanceof t||(e=new t(e)),this.decode(e,e.uint32())},i.verify=function(e){if("object"!==typeof e||null===e)return"object expected";var t={};return null!=e.bound&&e.hasOwnProperty("bound")&&(t._bound=1,"number"!==typeof e.bound)?"bound: number expected":null},i.fromObject=function(e){if(e instanceof o.cogment_verse.Space.Bound)return e;var t=new o.cogment_verse.Space.Bound;return null!=e.bound&&(t.bound=Number(e.bound)),t},i.toObject=function(e,t){t||(t={});var r={};return null!=e.bound&&e.hasOwnProperty("bound")&&(r.bound=t.json&&!isFinite(e.bound)?String(e.bound):e.bound,t.oneofs&&(r._bound="bound")),r},i.prototype.toJSON=function(){return this.constructor.toObject(this,e.util.toJSONOptions)},i.getTypeUrl=function(){return"type.googleapis.com/cogment_verse.Space.Bound"},i}(),i.Box=function(){function i(e){if(this.shape=[],this.low=[],this.high=[],e)for(var t=Object.keys(e),r=0;r>>3){case 1:if(i.shape&&i.shape.length||(i.shape=[]),2===(7&a))for(var s=e.uint32()+e.pos;e.pos>>0}if(e.low){if(!Array.isArray(e.low))throw TypeError(".cogment_verse.Space.Box.low: array expected");for(t.low=[],r=0;r>>3){case 1:i.key=e.string();break;case 2:i.discrete=o.cogment_verse.Space.Discrete.decode(e,e.uint32());break;case 3:i.box=o.cogment_verse.Space.Box.decode(e,e.uint32());break;default:e.skipType(7&a)}}return i},i.decodeDelimited=function(e){return e instanceof t||(e=new t(e)),this.decode(e,e.uint32())},i.verify=function(e){if("object"!==typeof e||null===e)return"object expected";var t={};if(null!=e.key&&e.hasOwnProperty("key")&&!n.isString(e.key))return"key: string expected";if(null!=e.discrete&&e.hasOwnProperty("discrete")&&(t.type=1,r=o.cogment_verse.Space.Discrete.verify(e.discrete)))return"discrete."+r;if(null!=e.box&&e.hasOwnProperty("box")){if(1===t.type)return"type: multiple values";var r;if(t.type=1,r=o.cogment_verse.Space.Box.verify(e.box))return"box."+r}return null},i.fromObject=function(e){if(e instanceof o.cogment_verse.Space.Property)return e;var t=new o.cogment_verse.Space.Property;if(null!=e.key&&(t.key=String(e.key)),null!=e.discrete){if("object"!==typeof e.discrete)throw TypeError(".cogment_verse.Space.Property.discrete: object expected");t.discrete=o.cogment_verse.Space.Discrete.fromObject(e.discrete)}if(null!=e.box){if("object"!==typeof e.box)throw TypeError(".cogment_verse.Space.Property.box: object expected");t.box=o.cogment_verse.Space.Box.fromObject(e.box)}return t},i.toObject=function(e,t){t||(t={});var r={};return t.defaults&&(r.key=""),null!=e.key&&e.hasOwnProperty("key")&&(r.key=e.key),null!=e.discrete&&e.hasOwnProperty("discrete")&&(r.discrete=o.cogment_verse.Space.Discrete.toObject(e.discrete,t),t.oneofs&&(r.type="discrete")),null!=e.box&&e.hasOwnProperty("box")&&(r.box=o.cogment_verse.Space.Box.toObject(e.box,t),t.oneofs&&(r.type="box")),r},i.prototype.toJSON=function(){return this.constructor.toObject(this,e.util.toJSONOptions)},i.getTypeUrl=function(){return"type.googleapis.com/cogment_verse.Space.Property"},i}(),i}(),i.SpaceValue=function(){function i(e){if(this.properties=[],e)for(var t=Object.keys(e),r=0;r>>3===1?(i.properties&&i.properties.length||(i.properties=[]),i.properties.push(o.cogment_verse.SpaceValue.PropertyValue.decode(e,e.uint32()))):e.skipType(7&a)}return i},i.decodeDelimited=function(e){return e instanceof t||(e=new t(e)),this.decode(e,e.uint32())},i.verify=function(e){if("object"!==typeof e||null===e)return"object expected";if(null!=e.properties&&e.hasOwnProperty("properties")){if(!Array.isArray(e.properties))return"properties: array expected";for(var t=0;t>>3===1)if(i.values&&i.values.length||(i.values=[]),2===(7&a))for(var s=e.uint32()+e.pos;e.pos>>3){case 1:i.discrete=e.int32();break;case 2:i.box=o.cogment_verse.NDArray.decode(e,e.uint32());break;case 3:i.simpleBox=o.cogment_verse.SpaceValue.SimpleBox.decode(e,e.uint32());break;default:e.skipType(7&a)}}return i},i.decodeDelimited=function(e){return e instanceof t||(e=new t(e)),this.decode(e,e.uint32())},i.verify=function(e){if("object"!==typeof e||null===e)return"object expected";var t={};if(null!=e.discrete&&e.hasOwnProperty("discrete")&&(t.value=1,!n.isInteger(e.discrete)))return"discrete: integer expected";if(null!=e.box&&e.hasOwnProperty("box")){if(1===t.value)return"value: multiple values";if(t.value=1,r=o.cogment_verse.NDArray.verify(e.box))return"box."+r}if(null!=e.simpleBox&&e.hasOwnProperty("simpleBox")){if(1===t.value)return"value: multiple values";var r;if(t.value=1,r=o.cogment_verse.SpaceValue.SimpleBox.verify(e.simpleBox))return"simpleBox."+r}return null},i.fromObject=function(e){if(e instanceof o.cogment_verse.SpaceValue.PropertyValue)return e;var t=new o.cogment_verse.SpaceValue.PropertyValue;if(null!=e.discrete&&(t.discrete=0|e.discrete),null!=e.box){if("object"!==typeof e.box)throw TypeError(".cogment_verse.SpaceValue.PropertyValue.box: object expected");t.box=o.cogment_verse.NDArray.fromObject(e.box)}if(null!=e.simpleBox){if("object"!==typeof e.simpleBox)throw TypeError(".cogment_verse.SpaceValue.PropertyValue.simpleBox: object expected");t.simpleBox=o.cogment_verse.SpaceValue.SimpleBox.fromObject(e.simpleBox)}return t},i.toObject=function(e,t){t||(t={});var r={};return null!=e.discrete&&e.hasOwnProperty("discrete")&&(r.discrete=e.discrete,t.oneofs&&(r.value="discrete")),null!=e.box&&e.hasOwnProperty("box")&&(r.box=o.cogment_verse.NDArray.toObject(e.box,t),t.oneofs&&(r.value="box")),null!=e.simpleBox&&e.hasOwnProperty("simpleBox")&&(r.simpleBox=o.cogment_verse.SpaceValue.SimpleBox.toObject(e.simpleBox,t),t.oneofs&&(r.value="simpleBox")),r},i.prototype.toJSON=function(){return this.constructor.toObject(this,e.util.toJSONOptions)},i.getTypeUrl=function(){return"type.googleapis.com/cogment_verse.SpaceValue.PropertyValue"},i}(),i}(),i.SpaceMask=function(){function i(e){if(this.properties=[],e)for(var t=Object.keys(e),r=0;r>>3===1?(i.properties&&i.properties.length||(i.properties=[]),i.properties.push(o.cogment_verse.SpaceMask.PropertyMask.decode(e,e.uint32()))):e.skipType(7&a)}return i},i.decodeDelimited=function(e){return e instanceof t||(e=new t(e)),this.decode(e,e.uint32())},i.verify=function(e){if("object"!==typeof e||null===e)return"object expected";if(null!=e.properties&&e.hasOwnProperty("properties")){if(!Array.isArray(e.properties))return"properties: array expected";for(var t=0;t>>3===1)if(i.discrete&&i.discrete.length||(i.discrete=[]),2===(7&a))for(var s=e.uint32()+e.pos;e.pos>>3){case 1:i.implementation=e.string();break;case 2:i.turnBased=e.bool();break;case 3:i.numPlayers=e.int32();break;case 4:i.observationSpace=o.cogment_verse.Space.decode(e,e.uint32());break;case 5:i.actionSpace=o.cogment_verse.Space.decode(e,e.uint32());break;default:e.skipType(7&a)}}return i},i.decodeDelimited=function(e){return e instanceof t||(e=new t(e)),this.decode(e,e.uint32())},i.verify=function(e){return"object"!==typeof e||null===e?"object expected":null!=e.implementation&&e.hasOwnProperty("implementation")&&!n.isString(e.implementation)?"implementation: string expected":null!=e.turnBased&&e.hasOwnProperty("turnBased")&&"boolean"!==typeof e.turnBased?"turnBased: boolean expected":null!=e.numPlayers&&e.hasOwnProperty("numPlayers")&&!n.isInteger(e.numPlayers)?"numPlayers: integer expected":null!=e.observationSpace&&e.hasOwnProperty("observationSpace")&&(t=o.cogment_verse.Space.verify(e.observationSpace))?"observationSpace."+t:null!=e.actionSpace&&e.hasOwnProperty("actionSpace")&&(t=o.cogment_verse.Space.verify(e.actionSpace))?"actionSpace."+t:null;var t},i.fromObject=function(e){if(e instanceof o.cogment_verse.EnvironmentSpecs)return e;var t=new o.cogment_verse.EnvironmentSpecs;if(null!=e.implementation&&(t.implementation=String(e.implementation)),null!=e.turnBased&&(t.turnBased=Boolean(e.turnBased)),null!=e.numPlayers&&(t.numPlayers=0|e.numPlayers),null!=e.observationSpace){if("object"!==typeof e.observationSpace)throw TypeError(".cogment_verse.EnvironmentSpecs.observationSpace: object expected");t.observationSpace=o.cogment_verse.Space.fromObject(e.observationSpace)}if(null!=e.actionSpace){if("object"!==typeof e.actionSpace)throw TypeError(".cogment_verse.EnvironmentSpecs.actionSpace: object expected");t.actionSpace=o.cogment_verse.Space.fromObject(e.actionSpace)}return t},i.toObject=function(e,t){t||(t={});var r={};return t.defaults&&(r.implementation="",r.turnBased=!1,r.numPlayers=0,r.observationSpace=null,r.actionSpace=null),null!=e.implementation&&e.hasOwnProperty("implementation")&&(r.implementation=e.implementation),null!=e.turnBased&&e.hasOwnProperty("turnBased")&&(r.turnBased=e.turnBased),null!=e.numPlayers&&e.hasOwnProperty("numPlayers")&&(r.numPlayers=e.numPlayers),null!=e.observationSpace&&e.hasOwnProperty("observationSpace")&&(r.observationSpace=o.cogment_verse.Space.toObject(e.observationSpace,t)),null!=e.actionSpace&&e.hasOwnProperty("actionSpace")&&(r.actionSpace=o.cogment_verse.Space.toObject(e.actionSpace,t)),r},i.prototype.toJSON=function(){return this.constructor.toObject(this,e.util.toJSONOptions)},i.getTypeUrl=function(){return"type.googleapis.com/cogment_verse.EnvironmentSpecs"},i}(),i.EnvironmentConfig=function(){function i(e){if(e)for(var t=Object.keys(e),r=0;r>>3){case 1:i.runId=e.string();break;case 2:i.render=e.bool();break;case 3:i.renderWidth=e.int32();break;case 4:i.seed=e.uint32();break;case 5:i.flatten=e.bool();break;default:e.skipType(7&a)}}return i},i.decodeDelimited=function(e){return e instanceof t||(e=new t(e)),this.decode(e,e.uint32())},i.verify=function(e){return"object"!==typeof e||null===e?"object expected":null!=e.runId&&e.hasOwnProperty("runId")&&!n.isString(e.runId)?"runId: string expected":null!=e.render&&e.hasOwnProperty("render")&&"boolean"!==typeof e.render?"render: boolean expected":null!=e.renderWidth&&e.hasOwnProperty("renderWidth")&&!n.isInteger(e.renderWidth)?"renderWidth: integer expected":null!=e.seed&&e.hasOwnProperty("seed")&&!n.isInteger(e.seed)?"seed: integer expected":null!=e.flatten&&e.hasOwnProperty("flatten")&&"boolean"!==typeof e.flatten?"flatten: boolean expected":null},i.fromObject=function(e){if(e instanceof o.cogment_verse.EnvironmentConfig)return e;var t=new o.cogment_verse.EnvironmentConfig;return null!=e.runId&&(t.runId=String(e.runId)),null!=e.render&&(t.render=Boolean(e.render)),null!=e.renderWidth&&(t.renderWidth=0|e.renderWidth),null!=e.seed&&(t.seed=e.seed>>>0),null!=e.flatten&&(t.flatten=Boolean(e.flatten)),t},i.toObject=function(e,t){t||(t={});var r={};return t.defaults&&(r.runId="",r.render=!1,r.renderWidth=0,r.seed=0,r.flatten=!1),null!=e.runId&&e.hasOwnProperty("runId")&&(r.runId=e.runId),null!=e.render&&e.hasOwnProperty("render")&&(r.render=e.render),null!=e.renderWidth&&e.hasOwnProperty("renderWidth")&&(r.renderWidth=e.renderWidth),null!=e.seed&&e.hasOwnProperty("seed")&&(r.seed=e.seed),null!=e.flatten&&e.hasOwnProperty("flatten")&&(r.flatten=e.flatten),r},i.prototype.toJSON=function(){return this.constructor.toObject(this,e.util.toJSONOptions)},i.getTypeUrl=function(){return"type.googleapis.com/cogment_verse.EnvironmentConfig"},i}(),i.HFHubModel=function(){function i(e){if(e)for(var t=Object.keys(e),r=0;r>>3){case 1:i.repoId=e.string();break;case 2:i.filename=e.string();break;default:e.skipType(7&a)}}return i},i.decodeDelimited=function(e){return e instanceof t||(e=new t(e)),this.decode(e,e.uint32())},i.verify=function(e){return"object"!==typeof e||null===e?"object expected":null!=e.repoId&&e.hasOwnProperty("repoId")&&!n.isString(e.repoId)?"repoId: string expected":null!=e.filename&&e.hasOwnProperty("filename")&&!n.isString(e.filename)?"filename: string expected":null},i.fromObject=function(e){if(e instanceof o.cogment_verse.HFHubModel)return e;var t=new o.cogment_verse.HFHubModel;return null!=e.repoId&&(t.repoId=String(e.repoId)),null!=e.filename&&(t.filename=String(e.filename)),t},i.toObject=function(e,t){t||(t={});var r={};return t.defaults&&(r.repoId="",r.filename=""),null!=e.repoId&&e.hasOwnProperty("repoId")&&(r.repoId=e.repoId),null!=e.filename&&e.hasOwnProperty("filename")&&(r.filename=e.filename),r},i.prototype.toJSON=function(){return this.constructor.toObject(this,e.util.toJSONOptions)},i.getTypeUrl=function(){return"type.googleapis.com/cogment_verse.HFHubModel"},i}(),i.AgentConfig=function(){function i(e){if(e)for(var t=Object.keys(e),r=0;r>>3){case 1:i.runId=e.string();break;case 2:i.environmentSpecs=o.cogment_verse.EnvironmentSpecs.decode(e,e.uint32());break;case 3:i.seed=e.uint32();break;case 4:i.modelId=e.string();break;case 5:i.modelVersion=e.int32();break;case 6:i.modelUpdateFrequency=e.int32();break;default:e.skipType(7&a)}}return i},i.decodeDelimited=function(e){return e instanceof t||(e=new t(e)),this.decode(e,e.uint32())},i.verify=function(e){if("object"!==typeof e||null===e)return"object expected";if(null!=e.runId&&e.hasOwnProperty("runId")&&!n.isString(e.runId))return"runId: string expected";if(null!=e.environmentSpecs&&e.hasOwnProperty("environmentSpecs")){var t=o.cogment_verse.EnvironmentSpecs.verify(e.environmentSpecs);if(t)return"environmentSpecs."+t}return null!=e.seed&&e.hasOwnProperty("seed")&&!n.isInteger(e.seed)?"seed: integer expected":null!=e.modelId&&e.hasOwnProperty("modelId")&&!n.isString(e.modelId)?"modelId: string expected":null!=e.modelVersion&&e.hasOwnProperty("modelVersion")&&!n.isInteger(e.modelVersion)?"modelVersion: integer expected":null!=e.modelUpdateFrequency&&e.hasOwnProperty("modelUpdateFrequency")&&!n.isInteger(e.modelUpdateFrequency)?"modelUpdateFrequency: integer expected":null},i.fromObject=function(e){if(e instanceof o.cogment_verse.AgentConfig)return e;var t=new o.cogment_verse.AgentConfig;if(null!=e.runId&&(t.runId=String(e.runId)),null!=e.environmentSpecs){if("object"!==typeof e.environmentSpecs)throw TypeError(".cogment_verse.AgentConfig.environmentSpecs: object expected");t.environmentSpecs=o.cogment_verse.EnvironmentSpecs.fromObject(e.environmentSpecs)}return null!=e.seed&&(t.seed=e.seed>>>0),null!=e.modelId&&(t.modelId=String(e.modelId)),null!=e.modelVersion&&(t.modelVersion=0|e.modelVersion),null!=e.modelUpdateFrequency&&(t.modelUpdateFrequency=0|e.modelUpdateFrequency),t},i.toObject=function(e,t){t||(t={});var r={};return t.defaults&&(r.runId="",r.environmentSpecs=null,r.seed=0,r.modelId="",r.modelVersion=0,r.modelUpdateFrequency=0),null!=e.runId&&e.hasOwnProperty("runId")&&(r.runId=e.runId),null!=e.environmentSpecs&&e.hasOwnProperty("environmentSpecs")&&(r.environmentSpecs=o.cogment_verse.EnvironmentSpecs.toObject(e.environmentSpecs,t)),null!=e.seed&&e.hasOwnProperty("seed")&&(r.seed=e.seed),null!=e.modelId&&e.hasOwnProperty("modelId")&&(r.modelId=e.modelId),null!=e.modelVersion&&e.hasOwnProperty("modelVersion")&&(r.modelVersion=e.modelVersion),null!=e.modelUpdateFrequency&&e.hasOwnProperty("modelUpdateFrequency")&&(r.modelUpdateFrequency=e.modelUpdateFrequency),r},i.prototype.toJSON=function(){return this.constructor.toObject(this,e.util.toJSONOptions)},i.getTypeUrl=function(){return"type.googleapis.com/cogment_verse.AgentConfig"},i}(),i.TrialConfig=function(){function n(e){if(e)for(var t=Object.keys(e),r=0;r>>3){case 1:i.value=o.cogment_verse.SpaceValue.decode(e,e.uint32());break;case 2:i.currentPlayer=e.string();break;case 3:i.actionMask=o.cogment_verse.SpaceMask.decode(e,e.uint32());break;case 4:i.renderedFrame=e.bytes();break;case 5:i.overriddenPlayers&&i.overriddenPlayers.length||(i.overriddenPlayers=[]),i.overriddenPlayers.push(e.string());break;default:e.skipType(7&a)}}return i},i.decodeDelimited=function(e){return e instanceof t||(e=new t(e)),this.decode(e,e.uint32())},i.verify=function(e){if("object"!==typeof e||null===e)return"object expected";var t,r={};if(null!=e.value&&e.hasOwnProperty("value")&&(t=o.cogment_verse.SpaceValue.verify(e.value)))return"value."+t;if(null!=e.currentPlayer&&e.hasOwnProperty("currentPlayer")&&(r._currentPlayer=1,!n.isString(e.currentPlayer)))return"currentPlayer: string expected";if(null!=e.actionMask&&e.hasOwnProperty("actionMask")&&(r._actionMask=1,t=o.cogment_verse.SpaceMask.verify(e.actionMask)))return"actionMask."+t;if(null!=e.renderedFrame&&e.hasOwnProperty("renderedFrame")&&(r._renderedFrame=1,!(e.renderedFrame&&"number"===typeof e.renderedFrame.length||n.isString(e.renderedFrame))))return"renderedFrame: buffer expected";if(null!=e.overriddenPlayers&&e.hasOwnProperty("overriddenPlayers")){if(!Array.isArray(e.overriddenPlayers))return"overriddenPlayers: array expected";for(var i=0;i=0&&(t.renderedFrame=e.renderedFrame)),e.overriddenPlayers){if(!Array.isArray(e.overriddenPlayers))throw TypeError(".cogment_verse.Observation.overriddenPlayers: array expected");t.overriddenPlayers=[];for(var r=0;r>>3===1?i.value=o.cogment_verse.SpaceValue.decode(e,e.uint32()):e.skipType(7&a)}return i},n.decodeDelimited=function(e){return e instanceof t||(e=new t(e)),this.decode(e,e.uint32())},n.verify=function(e){if("object"!==typeof e||null===e)return"object expected";if(null!=e.value&&e.hasOwnProperty("value")){var t=o.cogment_verse.SpaceValue.verify(e.value);if(t)return"value."+t}return null},n.fromObject=function(e){if(e instanceof o.cogment_verse.PlayerAction)return e;var t=new o.cogment_verse.PlayerAction;if(null!=e.value){if("object"!==typeof e.value)throw TypeError(".cogment_verse.PlayerAction.value: object expected");t.value=o.cogment_verse.SpaceValue.fromObject(e.value)}return t},n.toObject=function(e,t){t||(t={});var r={};return t.defaults&&(r.value=null),null!=e.value&&e.hasOwnProperty("value")&&(r.value=o.cogment_verse.SpaceValue.toObject(e.value,t)),r},n.prototype.toJSON=function(){return this.constructor.toObject(this,e.util.toJSONOptions)},n.getTypeUrl=function(){return"type.googleapis.com/cogment_verse.PlayerAction"},n}(),i.TeacherAction=function(){function i(e){if(e)for(var t=Object.keys(e),r=0;r>>3===1?i.value=o.cogment_verse.SpaceValue.decode(e,e.uint32()):e.skipType(7&a)}return i},i.decodeDelimited=function(e){return e instanceof t||(e=new t(e)),this.decode(e,e.uint32())},i.verify=function(e){if("object"!==typeof e||null===e)return"object expected";var t={};if(null!=e.value&&e.hasOwnProperty("value")){t._value=1;var r=o.cogment_verse.SpaceValue.verify(e.value);if(r)return"value."+r}return null},i.fromObject=function(e){if(e instanceof o.cogment_verse.TeacherAction)return e;var t=new o.cogment_verse.TeacherAction;if(null!=e.value){if("object"!==typeof e.value)throw TypeError(".cogment_verse.TeacherAction.value: object expected");t.value=o.cogment_verse.SpaceValue.fromObject(e.value)}return t},i.toObject=function(e,t){t||(t={});var r={};return null!=e.value&&e.hasOwnProperty("value")&&(r.value=o.cogment_verse.SpaceValue.toObject(e.value,t),t.oneofs&&(r._value="value")),r},i.prototype.toJSON=function(){return this.constructor.toObject(this,e.util.toJSONOptions)},i.getTypeUrl=function(){return"type.googleapis.com/cogment_verse.TeacherAction"},i}(),i.ObserverAction=function(){function n(e){if(e)for(var t=Object.keys(e),r=0;r0){var i=n.substring(0,o).trim(),a=n.substring(o+1).trim();this.append(i,a)}}},e.prototype.delete=function(e,t){var r=n.normalizeName(e);if(void 0===t)delete this.headersMap[r];else{var o=this.headersMap[r];if(o){var i=o.indexOf(t);i>=0&&o.splice(i,1),0===o.length&&delete this.headersMap[r]}}},e.prototype.append=function(e,t){var r=this,o=n.normalizeName(e);Array.isArray(this.headersMap[o])||(this.headersMap[o]=[]),Array.isArray(t)?t.forEach((function(e){r.headersMap[o].push(n.normalizeValue(e))})):this.headersMap[o].push(n.normalizeValue(t))},e.prototype.set=function(e,t){var r=n.normalizeName(e);if(Array.isArray(t)){var o=[];t.forEach((function(e){o.push(n.normalizeValue(e))})),this.headersMap[r]=o}else this.headersMap[r]=[n.normalizeValue(t)]},e.prototype.has=function(e,t){var r=this.headersMap[n.normalizeName(e)];if(!Array.isArray(r))return!1;if(void 0!==t){var o=n.normalizeValue(t);return r.indexOf(o)>=0}return!0},e.prototype.get=function(e){var t=this.headersMap[n.normalizeName(e)];return void 0!==t?t.concat():[]},e.prototype.forEach=function(e){var t=this;Object.getOwnPropertyNames(this.headersMap).forEach((function(r){e(r,t.headersMap[r])}),this)},e.prototype.toHeaders=function(){if("undefined"!=typeof Headers){var e=new Headers;return this.forEach((function(t,r){r.forEach((function(r){e.append(t,r)}))})),e}throw new Error("Headers class is not defined")},e}();t.BrowserHeaders=o},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=r(0);t.BrowserHeaders=n.BrowserHeaders},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.iterateHeaders=function(e,t){for(var r=e[Symbol.iterator](),n=r.next();!n.done;)t(n.value[0]),n=r.next()},t.iterateHeadersKeys=function(e,t){for(var r=e.keys(),n=r.next();!n.done;)t(n.value),n=r.next()}},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=r(2);t.normalizeName=function(e){if("string"!=typeof e&&(e=String(e)),/[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(e))throw new TypeError("Invalid character in header field name");return e.toLowerCase()},t.normalizeValue=function(e){return"string"!=typeof e&&(e=String(e)),e},t.getHeaderValues=function(e,t){var r=e;if(r instanceof Headers&&r.getAll)return r.getAll(t);var n=r.get(t);return n&&"string"==typeof n?[n]:n},t.getHeaderKeys=function(e){var t=e,r={},o=[];return t.keys?n.iterateHeadersKeys(t,(function(e){r[e]||(r[e]=!0,o.push(e))})):t.forEach?t.forEach((function(e,t){r[t]||(r[t]=!0,o.push(t))})):n.iterateHeaders(t,(function(e){var t=e[0];r[t]||(r[t]=!0,o.push(t))})),o},t.splitHeaderValue=function(e){var t=[];return e.split(", ").forEach((function(e){e.split(",").forEach((function(e){t.push(e)}))})),t}}]))},617:function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.ChunkParser=t.ChunkType=t.encodeASCII=t.decodeASCII=void 0;var n,o=r(65);function i(e){return 9===(t=e)||10===t||13===t||e>=32&&e<=126;var t}function a(e){for(var t=0;t!==e.length;++t)if(!i(e[t]))throw new Error("Metadata is not valid (printable) ASCII");return String.fromCharCode.apply(String,Array.prototype.slice.call(e))}function s(e){return 128==(128&e.getUint8(0))}function l(e){return e.getUint32(1,!1)}function u(e,t,r){return e.byteLength-t>=r}function c(e,t,r){if(e.slice)return e.slice(t,r);var n=e.length;void 0!==r&&(n=r);for(var o=new Uint8Array(n-t),i=0,a=t;a=0?r:i.httpStatusToCode(t);this.props.debug&&a.debug("onHeaders.code",n);var o=e.get("grpc-message")||[];if(this.props.debug&&a.debug("onHeaders.gRPCMessage",o),this.rawOnHeaders(e),n!==i.Code.OK){var s=this.decodeGRPCStatus(o[0]);this.rawOnError(n,s,e)}}},e.prototype.onTransportChunk=function(e){var t=this;if(this.closed)this.props.debug&&a.debug("grpc.onChunk received after request was closed - ignoring");else{var r=[];try{r=this.parser.parse(e)}catch(e){return this.props.debug&&a.debug("onChunk.parsing error",e,e.message),void this.rawOnError(i.Code.Internal,"parsing error: "+e.message)}r.forEach((function(e){if(e.chunkType===o.ChunkType.MESSAGE){var r=t.methodDefinition.responseType.deserializeBinary(e.data);t.rawOnMessage(r)}else e.chunkType===o.ChunkType.TRAILERS&&(t.responseHeaders?(t.responseTrailers=new n.Metadata(e.trailers),t.props.debug&&a.debug("onChunk.trailers",t.responseTrailers)):(t.responseHeaders=new n.Metadata(e.trailers),t.rawOnHeaders(t.responseHeaders)))}))}},e.prototype.onTransportEnd=function(){if(this.props.debug&&a.debug("grpc.onEnd"),this.closed)this.props.debug&&a.debug("grpc.onEnd received after request was closed - ignoring");else if(void 0!==this.responseTrailers){var e=c(this.responseTrailers);if(null!==e){var t=this.responseTrailers.get("grpc-message"),r=this.decodeGRPCStatus(t[0]);this.rawOnEnd(e,r,this.responseTrailers)}else this.rawOnError(i.Code.Internal,"Response closed without grpc-status (Trailers provided)")}else{if(void 0===this.responseHeaders)return void this.rawOnError(i.Code.Unknown,"Response closed without headers");var n=c(this.responseHeaders),o=this.responseHeaders.get("grpc-message");if(this.props.debug&&a.debug("grpc.headers only response ",n,o),null===n)return void this.rawOnEnd(i.Code.Unknown,"Response closed without grpc-status (Headers only)",this.responseHeaders);var s=this.decodeGRPCStatus(o[0]);this.rawOnEnd(n,s,this.responseHeaders)}},e.prototype.decodeGRPCStatus=function(e){if(!e)return"";try{return decodeURIComponent(e)}catch(t){return e}},e.prototype.rawOnEnd=function(e,t,r){var n=this;this.props.debug&&a.debug("rawOnEnd",e,t,r),this.completed||(this.completed=!0,this.onEndCallbacks.forEach((function(o){if(!n.closed)try{o(e,t,r)}catch(e){setTimeout((function(){throw e}),0)}})))},e.prototype.rawOnHeaders=function(e){this.props.debug&&a.debug("rawOnHeaders",e),this.completed||this.onHeadersCallbacks.forEach((function(t){try{t(e)}catch(e){setTimeout((function(){throw e}),0)}}))},e.prototype.rawOnError=function(e,t,r){var o=this;void 0===r&&(r=new n.Metadata),this.props.debug&&a.debug("rawOnError",e,t),this.completed||(this.completed=!0,this.onEndCallbacks.forEach((function(n){if(!o.closed)try{n(e,t,r)}catch(e){setTimeout((function(){throw e}),0)}})))},e.prototype.rawOnMessage=function(e){var t=this;this.props.debug&&a.debug("rawOnMessage",e.toObject()),this.completed||this.closed||this.onMessageCallbacks.forEach((function(r){if(!t.closed)try{r(e)}catch(e){setTimeout((function(){throw e}),0)}}))},e.prototype.onHeaders=function(e){this.onHeadersCallbacks.push(e)},e.prototype.onMessage=function(e){this.onMessageCallbacks.push(e)},e.prototype.onEnd=function(e){this.onEndCallbacks.push(e)},e.prototype.start=function(e){if(this.started)throw new Error("Client already started - cannot .start()");this.started=!0;var t=new n.Metadata(e||{});t.set("content-type","application/grpc-web+proto"),t.set("x-grpc-web","1"),this.transport.start(t)},e.prototype.send=function(e){if(!this.started)throw new Error("Client not started - .start() must be called before .send()");if(this.closed)throw new Error("Client already closed - cannot .send()");if(this.finishedSending)throw new Error("Client already finished sending - cannot .send()");if(!this.methodDefinition.requestStream&&this.sentFirstMessage)throw new Error("Message already sent for non-client-streaming method - cannot .send()");this.sentFirstMessage=!0;var t=l.frameRequest(e);this.transport.sendMessage(t)},e.prototype.finishSend=function(){if(!this.started)throw new Error("Client not started - .finishSend() must be called before .close()");if(this.closed)throw new Error("Client already closed - cannot .send()");if(this.finishedSending)throw new Error("Client already finished sending - cannot .finishSend()");this.finishedSending=!0,this.transport.finishSend()},e.prototype.close=function(){if(!this.started)throw new Error("Client not started - .start() must be called before .close()");if(this.closed)throw new Error("Client already closed - cannot .close()");this.closed=!0,this.props.debug&&a.debug("request.abort aborting request"),this.transport.cancel()},e}();function c(e){var t=e.get("grpc-status")||[];if(t.length>0)try{var r=t[0];return parseInt(r,10)}catch(e){return null}return null}},346:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.debug=void 0,t.debug=function(){for(var e=[],t=0;t=55296&&r<=56319){var n=e.charCodeAt(t+1);n>=56320&&n<=57343&&(r=65536+(r-55296<<10)+(n-56320))}return r}function g(e){for(var t=new Uint8Array(e.length),r=0,n=0;n1&&"="===e.charAt(t);)++r;return Math.ceil(3*e.length)/4-r};for(var n=new Array(64),o=new Array(123),i=0;i<64;)o[n[i]=i<26?i+65:i<52?i+71:i<62?i-4:i-59|43]=i++;r.encode=function(e,t,r){for(var o,i=null,a=[],s=0,l=0;t>2],o=(3&u)<<4,l=1;break;case 1:a[s++]=n[o|u>>4],o=(15&u)<<2,l=2;break;case 2:a[s++]=n[o|u>>6],a[s++]=n[63&u],l=0}s>8191&&((i||(i=[])).push(String.fromCharCode.apply(String,a)),s=0)}return l&&(a[s++]=n[o],a[s++]=61,1===l&&(a[s++]=61)),i?(s&&i.push(String.fromCharCode.apply(String,a.slice(0,s))),i.join("")):String.fromCharCode.apply(String,a.slice(0,s))};var a="invalid encoding";r.decode=function(e,t,r){for(var n,i=r,s=0,l=0;l1)break;if(void 0===(u=o[u]))throw Error(a);switch(s){case 0:n=u,s=1;break;case 1:t[r++]=n<<2|(48&u)>>4,n=u,s=2;break;case 2:t[r++]=(15&n)<<4|(60&u)>>2,n=u,s=3;break;case 3:t[r++]=(3&n)<<6|u,s=0}}if(1===s)throw Error(a);return r-i},r.test=function(e){return/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(e)}},"./node_modules/@protobufjs/eventemitter/index.js":function(e){"use strict";function t(){this._listeners={}}e.exports=t,t.prototype.on=function(e,t,r){return(this._listeners[e]||(this._listeners[e]=[])).push({fn:t,ctx:r||this}),this},t.prototype.off=function(e,t){if(void 0===e)this._listeners={};else if(void 0===t)this._listeners[e]=[];else for(var r=this._listeners[e],n=0;n0?0:2147483648,r,n);else if(isNaN(t))e(2143289344,r,n);else if(t>34028234663852886e22)e((o<<31|2139095040)>>>0,r,n);else if(t<11754943508222875e-54)e((o<<31|Math.round(t/1401298464324817e-60))>>>0,r,n);else{var i=Math.floor(Math.log(t)/Math.LN2);e((o<<31|i+127<<23|8388607&Math.round(t*Math.pow(2,-i)*8388608))>>>0,r,n)}}function a(e,t,r){var n=e(t,r),o=2*(n>>31)+1,i=n>>>23&255,a=8388607&n;return 255===i?a?NaN:o*(1/0):0===i?1401298464324817e-60*o*a:o*Math.pow(2,i-150)*(a+8388608)}e.writeFloatLE=t.bind(null,r),e.writeFloatBE=t.bind(null,n),e.readFloatLE=a.bind(null,o),e.readFloatBE=a.bind(null,i)}(),"undefined"!==typeof Float64Array?function(){var t=new Float64Array([-0]),r=new Uint8Array(t.buffer),n=128===r[7];function o(e,n,o){t[0]=e,n[o]=r[0],n[o+1]=r[1],n[o+2]=r[2],n[o+3]=r[3],n[o+4]=r[4],n[o+5]=r[5],n[o+6]=r[6],n[o+7]=r[7]}function i(e,n,o){t[0]=e,n[o]=r[7],n[o+1]=r[6],n[o+2]=r[5],n[o+3]=r[4],n[o+4]=r[3],n[o+5]=r[2],n[o+6]=r[1],n[o+7]=r[0]}function a(e,n){return r[0]=e[n],r[1]=e[n+1],r[2]=e[n+2],r[3]=e[n+3],r[4]=e[n+4],r[5]=e[n+5],r[6]=e[n+6],r[7]=e[n+7],t[0]}function s(e,n){return r[7]=e[n],r[6]=e[n+1],r[5]=e[n+2],r[4]=e[n+3],r[3]=e[n+4],r[2]=e[n+5],r[1]=e[n+6],r[0]=e[n+7],t[0]}e.writeDoubleLE=n?o:i,e.writeDoubleBE=n?i:o,e.readDoubleLE=n?a:s,e.readDoubleBE=n?s:a}():function(){function t(e,t,r,n,o,i){var a=n<0?1:0;if(a&&(n=-n),0===n)e(0,o,i+t),e(1/n>0?0:2147483648,o,i+r);else if(isNaN(n))e(0,o,i+t),e(2146959360,o,i+r);else if(n>17976931348623157e292)e(0,o,i+t),e((a<<31|2146435072)>>>0,o,i+r);else{var s;if(n<22250738585072014e-324)e((s=n/5e-324)>>>0,o,i+t),e((a<<31|s/4294967296)>>>0,o,i+r);else{var l=Math.floor(Math.log(n)/Math.LN2);1024===l&&(l=1023),e(4503599627370496*(s=n*Math.pow(2,-l))>>>0,o,i+t),e((a<<31|l+1023<<20|1048576*s&1048575)>>>0,o,i+r)}}}function a(e,t,r,n,o){var i=e(n,o+t),a=e(n,o+r),s=2*(a>>31)+1,l=a>>>20&2047,u=4294967296*(1048575&a)+i;return 2047===l?u?NaN:s*(1/0):0===l?5e-324*s*u:s*Math.pow(2,l-1075)*(u+4503599627370496)}e.writeDoubleLE=t.bind(null,r,0,4),e.writeDoubleBE=t.bind(null,n,4,0),e.readDoubleLE=a.bind(null,o,0,4),e.readDoubleBE=a.bind(null,i,4,0)}(),e}function r(e,t,r){t[r]=255&e,t[r+1]=e>>>8&255,t[r+2]=e>>>16&255,t[r+3]=e>>>24}function n(e,t,r){t[r]=e>>>24,t[r+1]=e>>>16&255,t[r+2]=e>>>8&255,t[r+3]=255&e}function o(e,t){return(e[t]|e[t+1]<<8|e[t+2]<<16|e[t+3]<<24)>>>0}function i(e,t){return(e[t]<<24|e[t+1]<<16|e[t+2]<<8|e[t+3])>>>0}e.exports=t(t)},"./node_modules/@protobufjs/inquire/index.js":function node_modulesProtobufjsInquireIndexJs(module){"use strict";function inquire(moduleName){try{var mod=eval("quire".replace(/^/,"re"))(moduleName);if(mod&&(mod.length||Object.keys(mod).length))return mod}catch(e){}return null}module.exports=inquire},"./node_modules/@protobufjs/pool/index.js":function(e){"use strict";e.exports=function(e,t,r){var n=r||8192,o=n>>>1,i=null,a=n;return function(r){if(r<1||r>o)return e(r);a+r>n&&(i=e(n),a=0);var s=t.call(i,a,a+=r);return 7&a&&(a=1+(7|a)),s}}},"./node_modules/@protobufjs/utf8/index.js":function(e,t){"use strict";var r=t;r.length=function(e){for(var t=0,r=0,n=0;n191&&n<224?i[a++]=(31&n)<<6|63&e[t++]:n>239&&n<365?(n=((7&n)<<18|(63&e[t++])<<12|(63&e[t++])<<6|63&e[t++])-65536,i[a++]=55296+(n>>10),i[a++]=56320+(1023&n)):i[a++]=(15&n)<<12|(63&e[t++])<<6|63&e[t++],a>8191&&((o||(o=[])).push(String.fromCharCode.apply(String,i)),a=0);return o?(a&&o.push(String.fromCharCode.apply(String,i.slice(0,a))),o.join("")):String.fromCharCode.apply(String,i.slice(0,a))},r.write=function(e,t,r){for(var n,o,i=r,a=0;a>6|192,t[r++]=63&n|128):55296===(64512&n)&&56320===(64512&(o=e.charCodeAt(a+1)))?(n=65536+((1023&n)<<10)+(1023&o),++a,t[r++]=n>>18|240,t[r++]=n>>12&63|128,t[r++]=n>>6&63|128,t[r++]=63&n|128):(t[r++]=n>>12|224,t[r++]=n>>6&63|128,t[r++]=63&n|128);return r-i}},"./node_modules/browser-headers/dist/browser-headers.umd.js":function(e){var t;t=function(){return function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}return r.m=e,r.c=t,r.i=function(e){return e},r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{configurable:!1,enumerable:!0,get:n})},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=1)}([function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=r(3),o=function(){function e(e,t){void 0===e&&(e={}),void 0===t&&(t={splitValues:!1});var r,o=this;this.headersMap={},e&&("undefined"!==typeof Headers&&e instanceof Headers?n.getHeaderKeys(e).forEach((function(r){n.getHeaderValues(e,r).forEach((function(e){t.splitValues?o.append(r,n.splitHeaderValue(e)):o.append(r,e)}))})):"object"===typeof(r=e)&&"object"===typeof r.headersMap&&"function"===typeof r.forEach?e.forEach((function(e,t){o.append(e,t)})):"undefined"!==typeof Map&&e instanceof Map?e.forEach((function(e,t){o.append(t,e)})):"string"===typeof e?this.appendFromString(e):"object"===typeof e&&Object.getOwnPropertyNames(e).forEach((function(t){var r=e[t];Array.isArray(r)?r.forEach((function(e){o.append(t,e)})):o.append(t,r)})))}return e.prototype.appendFromString=function(e){for(var t=e.split("\r\n"),r=0;r0){var i=n.substring(0,o).trim(),a=n.substring(o+1).trim();this.append(i,a)}}},e.prototype.delete=function(e,t){var r=n.normalizeName(e);if(void 0===t)delete this.headersMap[r];else{var o=this.headersMap[r];if(o){var i=o.indexOf(t);i>=0&&o.splice(i,1),0===o.length&&delete this.headersMap[r]}}},e.prototype.append=function(e,t){var r=this,o=n.normalizeName(e);Array.isArray(this.headersMap[o])||(this.headersMap[o]=[]),Array.isArray(t)?t.forEach((function(e){r.headersMap[o].push(n.normalizeValue(e))})):this.headersMap[o].push(n.normalizeValue(t))},e.prototype.set=function(e,t){var r=n.normalizeName(e);if(Array.isArray(t)){var o=[];t.forEach((function(e){o.push(n.normalizeValue(e))})),this.headersMap[r]=o}else this.headersMap[r]=[n.normalizeValue(t)]},e.prototype.has=function(e,t){var r=this.headersMap[n.normalizeName(e)];if(!Array.isArray(r))return!1;if(void 0!==t){var o=n.normalizeValue(t);return r.indexOf(o)>=0}return!0},e.prototype.get=function(e){var t=this.headersMap[n.normalizeName(e)];return void 0!==t?t.concat():[]},e.prototype.forEach=function(e){var t=this;Object.getOwnPropertyNames(this.headersMap).forEach((function(r){e(r,t.headersMap[r])}),this)},e.prototype.toHeaders=function(){if("undefined"!==typeof Headers){var e=new Headers;return this.forEach((function(t,r){r.forEach((function(r){e.append(t,r)}))})),e}throw new Error("Headers class is not defined")},e}();t.BrowserHeaders=o},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=r(0);t.BrowserHeaders=n.BrowserHeaders},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.iterateHeaders=function(e,t){for(var r=e[Symbol.iterator](),n=r.next();!n.done;)t(n.value[0]),n=r.next()},t.iterateHeadersKeys=function(e,t){for(var r=e.keys(),n=r.next();!n.done;)t(n.value),n=r.next()}},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=r(2);t.normalizeName=function(e){if("string"!==typeof e&&(e=String(e)),/[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(e))throw new TypeError("Invalid character in header field name");return e.toLowerCase()},t.normalizeValue=function(e){return"string"!==typeof e&&(e=String(e)),e},t.getHeaderValues=function(e,t){var r=e;if(r instanceof Headers&&r.getAll)return r.getAll(t);var n=r.get(t);return n&&"string"===typeof n?[n]:n},t.getHeaderKeys=function(e){var t=e,r={},o=[];return t.keys?n.iterateHeadersKeys(t,(function(e){r[e]||(r[e]=!0,o.push(e))})):t.forEach?t.forEach((function(e,t){r[t]||(r[t]=!0,o.push(t))})):n.iterateHeaders(t,(function(e){var t=e[0];r[t]||(r[t]=!0,o.push(t))})),o},t.splitHeaderValue=function(e){var t=[];return e.split(", ").forEach((function(e){e.split(",").forEach((function(e){t.push(e)}))})),t}}])},e.exports=t()},"./node_modules/google-protobuf/google-protobuf.js":function node_modulesGoogleProtobufGoogleProtobufJs(__unused_webpack_module,exports,__nested_webpack_require_86449__){var $jscomp=$jscomp||{};$jscomp.scope={},$jscomp.findInternal=function(e,t,r){e instanceof String&&(e=String(e));for(var n=e.length,o=0;o=n}}),"es6","es3"),$jscomp.polyfill("Array.prototype.find",(function(e){return e||function(e,t){return $jscomp.findInternal(this,e,t).v}}),"es6","es3"),$jscomp.polyfill("String.prototype.startsWith",(function(e){return e||function(e,t){var r=$jscomp.checkStringArgs(this,e,"startsWith");e+="";var n=r.length,o=e.length;t=Math.max(0,Math.min(0|t,r.length));for(var i=0;i=o}}),"es6","es3"),$jscomp.polyfill("String.prototype.repeat",(function(e){return e||function(e){var t=$jscomp.checkStringArgs(this,null,"repeat");if(0>e||1342177279>>=1)&&(t+=t);return r}}),"es6","es3");var COMPILED=!0,goog=goog||{};goog.global=this||self,goog.isDef=function(e){return void 0!==e},goog.isString=function(e){return"string"==typeof e},goog.isBoolean=function(e){return"boolean"==typeof e},goog.isNumber=function(e){return"number"==typeof e},goog.exportPath_=function(e,t,r){e=e.split("."),r=r||goog.global,e[0]in r||"undefined"==typeof r.execScript||r.execScript("var "+e[0]);for(var n;e.length&&(n=e.shift());)!e.length&&goog.isDef(t)?r[n]=t:r=r[n]&&r[n]!==Object.prototype[n]?r[n]:r[n]={}},goog.define=function(e,t){if(!COMPILED){var r=goog.global.CLOSURE_UNCOMPILED_DEFINES,n=goog.global.CLOSURE_DEFINES;r&&void 0===r.nodeType&&Object.prototype.hasOwnProperty.call(r,e)?t=r[e]:n&&void 0===n.nodeType&&Object.prototype.hasOwnProperty.call(n,e)&&(t=n[e])}return t},goog.FEATURESET_YEAR=2012,goog.DEBUG=!0,goog.LOCALE="en",goog.TRUSTED_SITE=!0,goog.STRICT_MODE_COMPATIBLE=!1,goog.DISALLOW_TEST_ONLY_CODE=COMPILED&&!goog.DEBUG,goog.ENABLE_CHROME_APP_SAFE_SCRIPT_LOADING=!1,goog.provide=function(e){if(goog.isInModuleLoader_())throw Error("goog.provide cannot be used within a module.");if(!COMPILED&&goog.isProvided_(e))throw Error('Namespace "'+e+'" already declared.');goog.constructNamespace_(e)},goog.constructNamespace_=function(e,t){if(!COMPILED){delete goog.implicitNamespaces_[e];for(var r=e;(r=r.substring(0,r.lastIndexOf(".")))&&!goog.getObjectByName(r);)goog.implicitNamespaces_[r]=!0}goog.exportPath_(e,t)},goog.getScriptNonce=function(e){return e&&e!=goog.global?goog.getScriptNonce_(e.document):(null===goog.cspNonce_&&(goog.cspNonce_=goog.getScriptNonce_(goog.global.document)),goog.cspNonce_)},goog.NONCE_PATTERN_=/^[\w+/_-]+[=]{0,2}$/,goog.cspNonce_=null,goog.getScriptNonce_=function(e){return(e=e.querySelector&&e.querySelector("script[nonce]"))&&(e=e.nonce||e.getAttribute("nonce"))&&goog.NONCE_PATTERN_.test(e)?e:""},goog.VALID_MODULE_RE_=/^[a-zA-Z_$][a-zA-Z0-9._$]*$/,goog.module=function(e){if(!goog.isString(e)||!e||-1==e.search(goog.VALID_MODULE_RE_))throw Error("Invalid module identifier");if(!goog.isInGoogModuleLoader_())throw Error("Module "+e+" has been loaded incorrectly. Note, modules cannot be loaded as normal scripts. They require some kind of pre-processing step. You're likely trying to load a module via a script tag or as a part of a concatenated bundle without rewriting the module. For more info see: https://github.com/google/closure-library/wiki/goog.module:-an-ES6-module-like-alternative-to-goog.provide.");if(goog.moduleLoaderState_.moduleName)throw Error("goog.module may only be called once per module.");if(goog.moduleLoaderState_.moduleName=e,!COMPILED){if(goog.isProvided_(e))throw Error('Namespace "'+e+'" already declared.');delete goog.implicitNamespaces_[e]}},goog.module.get=function(e){return goog.module.getInternal_(e)},goog.module.getInternal_=function(e){if(!COMPILED){if(e in goog.loadedModules_)return goog.loadedModules_[e].exports;if(!goog.implicitNamespaces_[e])return null!=(e=goog.getObjectByName(e))?e:null}return null},goog.ModuleType={ES6:"es6",GOOG:"goog"},goog.moduleLoaderState_=null,goog.isInModuleLoader_=function(){return goog.isInGoogModuleLoader_()||goog.isInEs6ModuleLoader_()},goog.isInGoogModuleLoader_=function(){return!!goog.moduleLoaderState_&&goog.moduleLoaderState_.type==goog.ModuleType.GOOG},goog.isInEs6ModuleLoader_=function(){if(goog.moduleLoaderState_&&goog.moduleLoaderState_.type==goog.ModuleType.ES6)return!0;var e=goog.global.$jscomp;return!!e&&("function"==typeof e.getCurrentModulePath&&!!e.getCurrentModulePath())},goog.module.declareLegacyNamespace=function(){if(!COMPILED&&!goog.isInGoogModuleLoader_())throw Error("goog.module.declareLegacyNamespace must be called from within a goog.module");if(!COMPILED&&!goog.moduleLoaderState_.moduleName)throw Error("goog.module must be called prior to goog.module.declareLegacyNamespace.");goog.moduleLoaderState_.declareLegacyNamespace=!0},goog.declareModuleId=function(e){if(!COMPILED){if(!goog.isInEs6ModuleLoader_())throw Error("goog.declareModuleId may only be called from within an ES6 module");if(goog.moduleLoaderState_&&goog.moduleLoaderState_.moduleName)throw Error("goog.declareModuleId may only be called once per module.");if(e in goog.loadedModules_)throw Error('Module with namespace "'+e+'" already exists.')}if(goog.moduleLoaderState_)goog.moduleLoaderState_.moduleName=e;else{var t=goog.global.$jscomp;if(!t||"function"!=typeof t.getCurrentModulePath)throw Error('Module with namespace "'+e+'" has been loaded incorrectly.');t=t.require(t.getCurrentModulePath()),goog.loadedModules_[e]={exports:t,type:goog.ModuleType.ES6,moduleId:e}}},goog.setTestOnly=function(e){if(goog.DISALLOW_TEST_ONLY_CODE)throw e=e||"",Error("Importing test-only code into non-debug environment"+(e?": "+e:"."))},goog.forwardDeclare=function(e){},COMPILED||(goog.isProvided_=function(e){return e in goog.loadedModules_||!goog.implicitNamespaces_[e]&&goog.isDefAndNotNull(goog.getObjectByName(e))},goog.implicitNamespaces_={"goog.module":!0}),goog.getObjectByName=function(e,t){e=e.split("."),t=t||goog.global;for(var r=0;r>>0),goog.uidCounter_=0,goog.getHashCode=goog.getUid,goog.removeHashCode=goog.removeUid,goog.cloneObject=function(e){var t=goog.typeOf(e);if("object"==t||"array"==t){if("function"===typeof e.clone)return e.clone();for(var r in t="array"==t?[]:{},e)t[r]=goog.cloneObject(e[r]);return t}return e},goog.bindNative_=function(e,t,r){return e.call.apply(e.bind,arguments)},goog.bindJs_=function(e,t,r){if(!e)throw Error();if(2{"use strict";class X{constructor(){if(new.target!=String)throw 1;this.x=42}}let q=Reflect.construct(X,[],String);if(q.x!=42||!(q instanceof String))throw 1;for(const a of[2,3]){if(a==2)continue;function f(z={a}){let a=0;return z.a}{function f(){return 0;}}return f()==3}})()')})),a("es7",(function(){return b("2 ** 2 == 4")})),a("es8",(function(){return b("async () => 1, true")})),a("es9",(function(){return b("({...rest} = {}), true")})),a("es_next",(function(){return!1})),{target:c,map:d}},goog.Transpiler.prototype.needsTranspile=function(e,t){if("always"==goog.TRANSPILE)return!0;if("never"==goog.TRANSPILE)return!1;if(!this.requiresTranspilation_){var r=this.createRequiresTranspilation_();this.requiresTranspilation_=r.map,this.transpilationTarget_=this.transpilationTarget_||r.target}if(e in this.requiresTranspilation_)return!!this.requiresTranspilation_[e]||!(!goog.inHtmlDocument_()||"es6"!=t||"noModule"in goog.global.document.createElement("script"));throw Error("Unknown language mode: "+e)},goog.Transpiler.prototype.transpile=function(e,t){return goog.transpile_(e,t,this.transpilationTarget_)},goog.transpiler_=new goog.Transpiler,goog.protectScriptTag_=function(e){return e.replace(/<\/(SCRIPT)/gi,"\\x3c/$1")},goog.DebugLoader_=function(){this.dependencies_={},this.idToPath_={},this.written_={},this.loadingDeps_=[],this.depsToLoad_=[],this.paused_=!1,this.factory_=new goog.DependencyFactory(goog.transpiler_),this.deferredCallbacks_={},this.deferredQueue_=[]},goog.DebugLoader_.prototype.bootstrap=function(e,t){function r(){n&&(goog.global.setTimeout(n,0),n=null)}var n=t;if(e.length){t=[];for(var o=0;o<\/script>",t.write(goog.TRUSTED_TYPES_POLICY_?goog.TRUSTED_TYPES_POLICY_.createHTML(n):n)}else{var o=t.createElement("script");o.defer=goog.Dependency.defer_,o.async=!1,o.type="text/javascript",(n=goog.getScriptNonce())&&o.setAttribute("nonce",n),goog.DebugLoader_.IS_OLD_IE_?(e.pause(),o.onreadystatechange=function(){"loaded"!=o.readyState&&"complete"!=o.readyState||(e.loaded(),e.resume())}):o.onload=function(){o.onload=null,e.loaded()},o.src=goog.TRUSTED_TYPES_POLICY_?goog.TRUSTED_TYPES_POLICY_.createScriptURL(this.path):this.path,t.head.appendChild(o)}}else goog.logToConsole_("Cannot use default debug loader outside of HTML documents."),"deps.js"==this.relativePath?(goog.logToConsole_("Consider setting CLOSURE_IMPORT_SCRIPT before loading base.js, or setting CLOSURE_NO_DEPS to true."),e.loaded()):e.pause()},goog.Es6ModuleDependency=function(e,t,r,n,o){goog.Dependency.call(this,e,t,r,n,o)},goog.inherits(goog.Es6ModuleDependency,goog.Dependency),goog.Es6ModuleDependency.prototype.load=function(e){if(goog.global.CLOSURE_IMPORT_SCRIPT)goog.global.CLOSURE_IMPORT_SCRIPT(this.path)?e.loaded():e.pause();else if(goog.inHtmlDocument_()){var t=goog.global.document,r=this;if(goog.isDocumentLoading_()){var n=function(e,r){e=r?'