def __init__(self, send_actions, check_action, draft=0, action_wait=0.26, timeout=1, **kwargs): super(DotaTestEnvironment, self).__init__(option('dota.path', guess_path()), True, draft=draft) self.options.game_mode = int(DOTA_GameMode.DOTA_GAMEMODE_AP) self.options.ticks_per_observation = 4 self.options.host_timescale = 2 self.err = None self.action_sent = False self.check_action = check_action self.send_actions = send_actions self.action_checked = False self.kwargs = kwargs self.timeout = 0 self.timeout_deadline = timeout self.action_wait = action_wait
def gym_main(): import sys from luafun.utils.options import option sys.stderr = sys.stdout p = option('dota.path', guess_path()) main(p)
def __init__(self, path=option('dota.path', None), dedicated=True, draft=0, config=None): self.paths = DotaPaths(path) self.options = DotaOptions(dedicated=dedicated, draft=draft) self.args = None self.process = None self.reply_count = defaultdict(int) self.manager = None self.state = None self.dire_state_process = None self.radiant_state_process = None self.dire_state_delta_queue = None self.radiant_state_delta_queue = None self.ipc_recv_process = None self.ipc_recv_queue = None self.config = config self.http_server = None self.http_rpc_send = None self.http_rpc_recv = None self.heroes = None self.uid = StateHolder() self.ready = False self.pending_ready = True self.bot_count = 10 self.stats = Stats() self.players = {TEAM_RADIANT: 0, TEAM_DIRE: 0} self.dire_bots = [] self.rad_bots = [] self.dire_perf = None self.rad_perf = None self.dire_perf_prev = None self.rad_perf_prev = None self.perf = ProcessingStates(0, 0, 0, 0, 0, 0, 0, 0) self.extractor = Extractor() self.replay = SaveReplay('replay.txt') log.debug(f'Main Process: {os.getpid()}') self._bots = [] # IPC config to configure bots self.ipc_config = { 'draft_start_wait': 10, 'draft_pick_wait': 1, } ipc_send(self.paths.ipc_config_handle, self.ipc_config, StateHolder())
def __init__(self, path=option('dota.path', None), dedicated=True, draft=0, stitcher=None, reward=None, _config=None): super(Dota2Env, self).__init__(path, dedicated, draft, config=_config) # For debugging only # self.radiant_message = open(self.paths.bot_file('out_radiant.txt'), 'w') # self.dire_message = open(self.paths.bot_file('out_dire.txt'), 'w') self._action_space = action_space() # Function to stich state together if stitcher is None: stitcher = Stitcher self.sticher_factory = stitcher self.dire_stitcher = stitcher(faction=TEAM_DIRE) self.radiant_stitcher = stitcher(faction=TEAM_RADIANT) # Reward function if reward is None: reward = Reward() self.reward = reward # Draft tracker for the drafting AI self.draft_tracker = DraftTracker() self.radiant_stitcher.draft = self.draft_tracker.draft self.dire_stitcher.draft = self.draft_tracker.draft self.has_next = 0 self.step_start = None self.step_end = 0 self.cnt = 0 self.avg = 0
class OpenDotaAPI(WebAPI): URL = 'https://api.opendota.com/api/{method}' KEY = option('opendota.api', None) def __init__(self): super(OpenDotaAPI, self).__init__('opendota') now = datetime.datetime.now() day_count = calendar.monthrange(now.year, now.month)[1] # 50000 per month self.max_api_call_day = 50000 // day_count # 60 calls per minute self.wait_time = 2 def explore(self, sql): params = { 'sql': sql, 'key': self.KEY, } url = self.URL.format(method='explorer') response = requests.get(url, params=params) self.handle_errors(response) self.limit() data = response.json() rows = data.get('rows') if rows is not None: return rows return data def get_player(self, player_id): """ >>> OpenDotaAPI().get_player(81280209) { "tracked_until": "1621953083", "leaderboard_rank": null, "solo_competitive_rank": null, "profile": { "account_id": 81280209, "personaname": "Sétepenrê", "name": null, "plus": false, "cheese": 0, "steamid": "76561198041545937", "avatar": "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/e6/e68a0b9be84eafb21eadd5fa73a32c995fc7991b.jpg", "avatarmedium": "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/e6/e68a0b9be84eafb21eadd5fa73a32c995fc7991b_medium.jpg", "avatarfull": "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/e6/e68a0b9be84eafb21eadd5fa73a32c995fc7991b_full.jpg", "profileurl": "https://steamcommunity.com/id/setepenre/", "last_login": "******", "loccountrycode": null, "is_contributor": false }, "rank_tier": 24, "competitive_rank": null, "mmr_estimate": { "estimate": 2223 } } """ params = { 'key': self.KEY, } url = self.URL.format(method='players') + f'/{player_id}' response = requests.get(url, params=params) self.handle_errors(response) self.limit() return response.json() def get_all_pick_draft(self, count, offset, version="7.28"): """Does not work, opendota does not save pick order for public matches only pro matches""" mode = int(DOTA_GameMode.DOTA_GAMEMODE_ALL_DRAFT) start7_28 = 1608249726 start7_29 = 1617981499 # Game mode in open dota is not correct # matches.game_mode = {mode} AND query = f""" SELECT public_matches.match_id, public_matches.radiant_win, match_patch.patch, public_matches.avg_rank_tier, public_matches.num_rank_tier, picks_bans.is_pick, picks_bans.hero_id, picks_bans.team, picks_bans.ord FROM public_matches, picks_bans INNER JOIN match_patch USING(match_id) INNER JOIN picks_bans USING(match_id) WHERE public_matches.start_time >= {start7_28} AND public_matches.start_time <= {start7_29} AND match_patch.patch = '{version}' LIMIT {count} """ if offset is not None: query = f'{query} OFFSET {offset}' query = f'{query};' return self.explore(query) def get_all_pick_draft_match_id(self, count, offset): """Does not work, opendota does not save pick order for public matches only pro matches""" mode = int(DOTA_GameMode.DOTA_GAMEMODE_ALL_DRAFT) start7_28 = 1608249726 start7_29 = 1617981499 # Game mode in open dota is not correct # matches.game_mode = {mode} AND query = f""" SELECT * FROM public_matches WHERE public_matches.start_time >= {start7_28} AND public_matches.start_time <= {start7_29} AND public_matches.game_mode = 22 LIMIT {count} """ if offset is not None: query = f'{query} OFFSET {offset}' query = f'{query};' return self.explore(query) def get_captains_mode_matches(self, count, offset, version="7.28", mode=2): """To make sure your query is fast you should use a time constrain so the DB can focus on the partition that matters """ query = f""" SELECT matches.match_id, matches.radiant_win, matches.picks_bans, match_patch.patch FROM matches INNER JOIN match_patch USING(match_id) WHERE matches.human_players = 10 AND matches.game_mode = {mode} AND matches.picks_bans IS NOT NULL LIMIT {count} """ if offset is not None: query = f'{query} OFFSET {offset}' query = f'{query};' return self.explore(query)
from collections import defaultdict import json import logging from luafun.utils.options import option log = logging.getLogger(__name__) EXTRACT_ENABLED = option('extract', False, bool) REPLAY_ENABLED = option('replay', True, bool) class SaveReplay: """Save Proto messages we receive to replay the match for debugging purposes""" def __init__(self, filename): self.store = open(filename, 'w') def save(self, radiant, dire): if not REPLAY_ENABLED: return radiant.pop('perf', None) dire.pop('perf', None) self.store.write(f'RAD, {json.dumps(radiant)}\nDIRE, {json.dumps(dire)}\n') def close(self): self.store.close()
def connect(self): port = option('debug.port', 8080, int) host = "127.0.0.1" self.sock = socket.create_server((host, port)) log.debug(f'Listening to {host}:{port}')
from dataclasses import dataclass import json import time from typing import List import zipfile import os import gzip import datetime import requests from luafun.utils.options import option from luafun.game.game import DOTA_GameMode from luafun.steamapi.api import WebAPI, ServerError, LimitExceeded # set export LUAFUN_STEAM_API=XXXX STEAM_API_KEY = option('steam.api', None) DOTA_ID = 570 DOTA_PRIVATE_BETA = 816 DOTA_BETA_TEST = 205790 @dataclass class MatchHistory_Match_Player: account_id: int player_slot: int hero_id: int def is_dire(self): return (self.player_slot & 0b10000000) >> 7 def position(self):
def main(config=None): """This simply runs the environment until the game finishes, default to RandomActor (actions are random) It means bots will not do anything game winning, if drafting is enabled nothing will be drafted """ parser = ArgumentParser() parser.add_argument('--draft', action='store_true', default=False, help='Enable bot drafting') parser.add_argument('--mode', type=str, default='allpick_nobans', help='Game mode') parser.add_argument('--path', type=str, default=option('dota.path', None), help='Custom Dota2 game location') parser.add_argument('--render', action='store_true', default=False, help='Render the game on screen') parser.add_argument('--speed', type=float, default=4, help='Speed multiplier') parser.add_argument('--interactive', action='store_true', default=False, help='Make a human create the lobby') # --model socket://192.163.0.102:8080 parser.add_argument( '--model', type=str, default='random', help='Model name factory, defaults to a random action sampler') # --trainer socket://192.163.0.103:8081 parser.add_argument('--trainer', type=str, default='random', help='') args = parser.parse_args() game = dota2_environment(args.mode, args.path, config=config) if game is None: return # logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.DEBUG) game.options.dedicated = not args.render game.options.interactive = args.interactive game.options.host_timescale = args.speed game.options.draft = int(args.draft) obs_size = game.observation_space train = TrainEngine(args.trainer, args.model, (obs_size, 10, 16)) model = InferenceEngine(args.model, train) with game: # Initialize Drafter & Encoders if game.options.draft: model.init_draft() # --- state, reward, done, info = game.initial() # Draft here if enabled while game.running: if game.options.draft: pass break game.wait_end_draft() model.close_draft() model.init_play(game) uid = game.options.game_id # Play the game while game.running: # start issuing orders here action, logprob, filter = model.action(uid, state) # select an action to perform state, reward, done, info = game.step(action) # push the new observation train.push(uid, state, reward, done, info, action, logprob, filter) if train.ready(): train.train() if state is None: break if game.cnt > 0 and game.cnt % 100 == 0: print( f'Step time {game.avg / game.cnt:.4f} Reward {reward[0]}') print('Game Finished') print('Done')