 the guns and the hull integrity you can upgrade, progression means a more robust whaling boat, a diving bell to go and explore sunken wrecks, and perhaps a hefty ram for some up-close-and-personal action.
Kenway's story meanders a fair bit, and some of the mission structuring gets a little bit wayward if you've gone off on your own and done a whole bunch of stuff without being told how to do that. It's nice that Ubisoft let you go off and do your own thing relatively early on, but then when the explanatory story mission comes around, things get a little clunky. The narrative becomes a little unstuck towards the end, but the closing scenes are some of the finest this series has seen. McDevitt has a talent for touching finales (his story for Revelations was the highlight of that game), and that's certainly evidenced here. It good to see that the story also avoids pantomime pirates, instead producing real characters with moral depth and some nuance to their motivations. Edward begins as a man dedicated only to himself and his crew, and it's interesting to see how the Templar-Assassin feud envelopes him as the game progresses.
There are a few gripes. I've already mentioned the combat, which seems to have deteriorated in quality since Ezio, to be honest, but also worthy of note is Ubisoft's insistence on retaining eavesdropping missions. They're awful, clunky, and we needed to be rid of them a long time ago. The same can be said of those exposition dump walk-and-talks. They've never been anything more than tedious, and they still disrupt and frustrate the flow of things. Visually, the current-gen versions look great thanks to the scalable opportunities provided by working with next-gen hardware, but accept nothing less than the PS4 version if you're out for the definitive version of the game. The improved resolution and hefty power bring the level of artistic detail to life in a manner that just isn't possible on current-gen systems, and the lighting effects are utterly delightful.
Assassin's Creed II and Brotherhood are by far my favourite games in the series, but Black Flag gives them a serious run for their money. But then, this is what happens when you create a magnificently detailed, interesting world and fill it with lots of little things to do that have meaningful impacts upon the game going forward. It's the level of cohesion that has kept me coming back for more each and every evening. As a fan of Assassin's Creed, as a fan of the stories surrounding the Golden Age of Piracy, as a fan of Sid Meier's Pirates!, I'd hoped that Black Flag would deliver from the moment the whisper of pirates first escaped Ubi Montreal's vaults. I'm so enormously happy to say that it does.
Pros
- Huge, enormously detailed world
- Filled to the brim with things to do, see, kill, and collect
- Stealth is back in a big way
- Naval sandbox is fantastic
- Freeform assassinations YAY!
- The cohesion and progression make for a truly rewarding experience
Cons
- Combat seems to be worse than before
- Eavesdropping missions are still awful
- Multiplayer not undergone any significant changes
The Short Version:.
import os
import logging
import pickle as pk
import importlib
import torch

from dataloader import get_dataset, get_dataloader
from util.vocoder import get_vocoder
from util.mytorch import save_checkpoint, load_checkpoint

logger = logging.getLogger(__name__)

class BaseAgent():
    def __init__(self, config, args):
        self.device = 'cuda' if torch.cuda.is_available() else 'cpu'
        self.vocoder = get_vocoder(device=self.device)
        self.mel2wav = self.vocoder.mel2wav

    @staticmethod
    def build_model(build_config, mode, device):
        _build_model = importlib.import_module(f'model.{build_config.model_name}').build_model
        model_state, step_fn = _build_model(build_config, device=device, mode=mode)
        return model_state, step_fn

    @staticmethod
    def gen_data(ckpt_path, flag, dataset_config, dataloader_config, njobs):
        ckpt_dir = os.path.join(ckpt_path, '')
        ckpt_dir_flag = os.path.join(ckpt_dir, flag)
        prefix = os.path.basename(os.path.dirname(dataset_config.indexes_path))
        train_pkl = os.path.join(ckpt_dir, f'{prefix}_train.pkl')
        dev_pkl = os.path.join(ckpt_dir, f'{prefix}_dev.pkl')
        os.makedirs(ckpt_dir, exist_ok=True)
        with open(os.path.join(ckpt_dir, 'dirtype'), 'w') as f:
            f.write('ckpt_dir')
        os.makedirs(ckpt_dir_flag, exist_ok=True)
        with open(os.path.join(ckpt_dir_flag, 'dirtype'), 'w') as f:
            f.write('ckpt_dir_flag')
        file_handler = logging.FileHandler(os.path.join(ckpt_dir, 'train.log'))
        logging.getLogger().addHandler(file_handler)
        if os.path.exists(train_pkl):
            logger.info(f'=> load train, dev data from {ckpt_dir}')
            train_data = pk.load(open(train_pkl, 'rb'))
            dev_data = pk.load(open(dev_pkl, 'rb'))
            train_set = get_dataset(dset='train', dataset_config=dataset_config, njobs=njobs, metadata=train_data)
            dev_set = get_dataset(dset='dev', dataset_config=dataset_config, njobs=njobs, metadata=dev_data)
        else:
            train_set = get_dataset(dset='train', dataset_config=dataset_config, njobs=njobs)
            dev_set = get_dataset(dset='dev', dataset_config=dataset_config, njobs=njobs)
            pk.dump(train_set.data, open(train_pkl, 'wb'))
            pk.dump(dev_set.data, open(dev_pkl, 'wb'))
        train_loader = get_dataloader(dset='train', dataloader_config=dataloader_config, dataset=train_set)
        dev_loader = get_dataloader(dset='dev', dataloader_config=dataloader_config, dataset=dev_set)
        
        return ckpt_dir_flag, train_set, dev_set, train_loader, dev_loader

    @staticmethod
    def load_data(ckpt_path, dataset_config, dataloader_config, njobs):
        if os.path.isdir(ckpt_path):
            d = os.path.join(ckpt_path, '')
            with open(os.path.join(d, 'dirtype'), 'r') as f:
                dirtype = f.read().strip()
            if dirtype == 'ckpt_dir':
                logger.warn(f'The ckpt_path is {ckpt_path}, the flag is not specified.')
                logger.warn(f'Use "default" flag.')
                ckpt_dir = d
                flag = 'default'
                ckpt_dir_flag = os.path.join(ckpt_dir, flag)
                ckpt_path = ckpt_dir_flag
            elif dirtype == 'ckpt_dir_flag':
                ckpt_dir_flag = os.path.dirname(d)
                ckpt_dir = os.path.dirname(ckpt_dir_flag)
                flag = os.path.basename(ckpt_dir_flag)
            else:
                raise NotImplementedError(f'Wrong dirtype: {dirtype} from {d}.')
        else:
            ckpt_dir_flag = os.path.dirname(ckpt_path)
            ckpt_dir = os.path.dirname(ckpt_dir_flag)
            flag = os.path.basename(ckpt_dir_flag)

        file_handler = logging.FileHandler(os.path.join(ckpt_dir, 'train.log'))
        logging.getLogger().addHandler(file_handler)
        logger.info(f'=> load train, dev data from