Example #1
0
    async def update(self, ctx, *args):
        """
        Updates the current character sheet, preserving all settings.
        __Valid Arguments__
        `-v` - Shows character sheet after update is complete.
        `-nocc` - Do not automatically create or update custom counters for class resources and features.
        `-noprep` - Import all known spells as prepared.
        """
        old_character: Character = await Character.from_ctx(ctx)
        url = old_character.upstream
        args = argparse(args)

        prefixes = 'dicecloud-', 'google-', 'beyond-'
        _id = url[:]
        for p in prefixes:
            if url.startswith(p):
                _id = url[len(p):]
                break
        sheet_type = old_character.sheet_type
        if sheet_type == 'dicecloud':
            parser = DicecloudParser(_id)
            loading = await ctx.send('Updating character data from Dicecloud...')
        elif sheet_type == 'google':
            parser = GoogleSheet(_id)
            loading = await ctx.send('Updating character data from Google...')
        elif sheet_type == 'beyond':
            parser = BeyondSheetParser(_id)
            loading = await ctx.send('Updating character data from Beyond...')
        else:
            return await ctx.send(f"Error: Unknown sheet type {sheet_type}.")

        try:
            character = await parser.load_character(ctx, args)
        except ExternalImportError as eep:
            return await loading.edit(content=f"Error loading character: {eep}")
        except Exception as eep:
            log.warning(f"Error importing character {old_character.upstream}")
            log.warning(traceback.format_exc())
            return await loading.edit(content=f"Error loading character: {eep}")

        character.update(old_character)
        
        # keeps an old check if the old character was active on the current server
        was_server_active = old_character.is_active_server(ctx)
        
        await character.commit(ctx)
        
        # overwrites the old_character's server active state
        # since character._active_guilds is old_character._active_guilds here
        if old_character.is_active_global():
            await character.set_active(ctx)
        if was_server_active:
            await character.set_server_active(ctx)
        
        await loading.edit(content=f"Updated and saved data for {character.name}!")
        if args.last('v'):
            await ctx.send(embed=character.get_sheet_embed())
        if sheet_type == 'beyond':
            await send_ddb_ctas(ctx, character)
    async def dicecloud(self, ctx, url: str, *, args=""):
        """Loads a character sheet from [Dicecloud](https://dicecloud.com/), resetting all settings.
        Share your character with `avrae` on Dicecloud (edit perms) for live updates.
        __Valid Arguments__
        `-cc` - Will automatically create custom counters for class resources and features."""
        if 'dicecloud.com' in url:
            url = url.split('/character/')[-1].split('/')[0]

        override = await self._confirm_overwrite(ctx, f"dicecloud-{url}")
        if not override: return await ctx.send("Character overwrite unconfirmed. Aborting.")

        loading = await ctx.send('Loading character data from Dicecloud...')
        parser = DicecloudParser(url)
        try:
            await parser.get_character()
        except Exception as eep:
            return await loading.edit(content=f"Dicecloud returned an error: {eep}")

        try:
            sheet = parser.get_sheet()
        except Exception as e:
            traceback.print_exception(type(e), e, e.__traceback__, file=sys.stderr)
            return await loading.edit(content=
                                      'Error: Invalid character sheet. Capitalization matters!\n' + str(e))

        c = Character(sheet['sheet'], f"dicecloud-{url}").initialize_consumables()
        await loading.edit(content=f'Loaded and saved data for {c.get_name()}!')

        if '-cc' in args:
            for counter in parser.get_custom_counters():
                displayType = 'bubble' if c.evaluate_cvar(counter['max']) < 6 else None
                try:
                    c.create_consumable(counter['name'], maxValue=str(counter['max']), minValue=str(counter['min']),
                                        reset=counter['reset'], displayType=displayType, live=counter['live'])
                except InvalidArgument:
                    pass

        del parser  # uh. maybe some weird instance things going on here.
        await c.commit(ctx)
        await c.set_active(ctx)
        try:
            await ctx.send(embed=c.get_sheet_embed())
        except:
            await ctx.send(
                "...something went wrong generating your character sheet. Don't worry, your character has been saved. "
                "This is usually due to an invalid image.")
Example #3
0
    async def dicecloud(self, ctx, url: str, *args):
        """Loads a character sheet from [Dicecloud](https://dicecloud.com/), resetting all settings.
        Share your character with `avrae` on Dicecloud (edit perms) for live updates.
        __Valid Arguments__
        `-cc` - Will automatically create custom counters for class resources and features."""
        if 'dicecloud.com' in url:
            url = url.split('/character/')[-1].split('/')[0]

        override = await self._confirm_overwrite(ctx, f"dicecloud-{url}")
        if not override: return await ctx.send("Character overwrite unconfirmed. Aborting.")

        loading = await ctx.send('Loading character data from Dicecloud...')
        parser = DicecloudParser(url)
        await self._load_sheet(ctx, parser, args, loading)
Example #4
0
    async def update(self, ctx, *args):
        """Updates the current character sheet, preserving all settings.
        __Valid Arguments__
        `-v` - Shows character sheet after update is complete.
        `-cc` - Updates custom counters from Dicecloud."""
        old_character: Character = await Character.from_ctx(ctx)
        url = old_character.upstream
        args = argparse(args)

        prefixes = 'dicecloud-', 'pdf-', 'google-', 'beyond-'
        _id = url[:]
        for p in prefixes:
            if url.startswith(p):
                _id = url[len(p):]
                break
        sheet_type = old_character.sheet_type
        if sheet_type == 'dicecloud':
            parser = DicecloudParser(_id)
            loading = await ctx.send(
                'Updating character data from Dicecloud...')
        elif sheet_type == 'google':
            parser = GoogleSheet(_id)
            loading = await ctx.send('Updating character data from Google...')
        elif sheet_type == 'beyond':
            parser = BeyondSheetParser(_id)
            loading = await ctx.send('Updating character data from Beyond...')
        else:
            return await ctx.send(f"Error: Unknown sheet type {sheet_type}.")

        try:
            character = await parser.load_character(str(ctx.author.id), args)
        except ExternalImportError as eep:
            return await loading.edit(content=f"Error loading character: {eep}"
                                      )
        except Exception as eep:
            log.warning(f"Error importing character {old_character.upstream}")
            log.warning(traceback.format_exc())
            return await loading.edit(content=f"Error loading character: {eep}"
                                      )

        character.update(old_character)

        await character.commit(ctx)
        await character.set_active(ctx)
        await loading.edit(
            content=f"Updated and saved data for {character.name}!")
        if args.last('v'):
            await ctx.send(embed=character.get_sheet_embed())
Example #5
0
            Avrae's google account is `[email protected]`.


        """  # noqa: E501
        url = await self._check_url(ctx, url)  # check for < >
        # Sheets in order: DDB, Dicecloud, Gsheet
        if beyond_match := DDB_URL_RE.match(url):
            loading = await ctx.send('Loading character data from Beyond...')
            prefix = 'beyond'
            url = beyond_match.group(1)
            parser = BeyondSheetParser(url)
        elif dicecloud_match := DICECLOUD_URL_RE.match(url):
            loading = await ctx.send('Loading character data from Dicecloud...')
            url = dicecloud_match.group(1)
            prefix = 'dicecloud'
            parser = DicecloudParser(url)
        else:
            try:
                url = extract_gsheet_id_from_url(url)
            except ExternalImportError:
                return await ctx.send("Sheet type did not match accepted formats.")
            loading = await ctx.send('Loading character data from Google...')
            prefix = 'google'
            parser = GoogleSheet(url)

        override = await self._confirm_overwrite(ctx, f"{prefix}-{url}")
        if not override:
            return await ctx.send("Character overwrite unconfirmed. Aborting.")

        # Load the parsed sheet
        character = await self._load_sheet(ctx, parser, args, loading)
    async def update(self, ctx, *, args=''):
        """Updates the current character sheet, preserving all settings.
        Valid Arguments: `-v` - Shows character sheet after update is complete.
        `-cc` - Updates custom counters from Dicecloud."""
        char = await Character.from_ctx(ctx)
        url = char.id
        old_character = char.character

        prefixes = 'dicecloud-', 'pdf-', 'google-', 'beyond-'
        _id = copy.copy(url)
        for p in prefixes:
            if url.startswith(p):
                _id = url[len(p):]
                break
        sheet_type = old_character.get('type', 'dicecloud')
        if sheet_type == 'dicecloud':
            parser = DicecloudParser(_id)
            loading = await ctx.send('Updating character data from Dicecloud...')
        elif sheet_type == 'google':
            try:
                parser = GoogleSheet(_id, self.gsheet_client)
            except AssertionError:
                await self.init_gsheet_client()  # attempt reconnection
                return await ctx.send("I am still connecting to Google. Try again in 15-30 seconds.")
            loading = await ctx.send('Updating character data from Google...')
        elif sheet_type == 'beyond':
            loading = await ctx.send('Updating character data from Beyond...')
            parser = BeyondSheetParser(_id)
        else:
            return await ctx.send("Error: Unknown sheet type.")
        try:
            await parser.get_character()
        except (timeout, aiohttp.ClientResponseError) as e:
            log.warning(
                f"Response error importing char:\n{''.join(traceback.format_exception(type(e), e, e.__traceback__))}")
            return await loading.edit(content=
                                      "I'm having some issues connecting to Dicecloud or Google right now. "
                                      "Please try again in a few minutes.")
        except HttpError:
            return await loading.edit(content=
                                      "Google returned an error trying to access your sheet. "
                                      "Please ensure your sheet is shared and try again in a few minutes.")
        except Exception as e:
            log.warning(
                f"Failed to import character\n{''.join(traceback.format_exception(type(e), e, e.__traceback__))}")
            return await loading.edit(content='Error: Invalid character sheet.\n' + str(e))

        try:
            if sheet_type == 'dicecloud':
                sheet = parser.get_sheet()
            elif sheet_type == 'pdf':
                sheet = parser.get_sheet()
            elif sheet_type == 'google':
                sheet = await parser.get_sheet()
            elif sheet_type == 'beyond':
                sheet = parser.get_sheet()
            else:
                return await ctx.send("Error: Unknown sheet type.")
            await loading.edit(content=
                               'Updated and saved data for {}!'.format(sheet['sheet']['stats']['name']))
        except TypeError as e:
            del parser
            log.info(f"Exception in parser.get_sheet: {e}")
            log.debug('\n'.join(traceback.format_exception(type(e), e, e.__traceback__)))
            return await loading.edit(content=
                                      'Invalid character sheet. '
                                      'If you are using a dicecloud sheet, '
                                      'make sure you have shared the sheet so that anyone with the '
                                      'link can view.')
        except Exception as e:
            del parser
            return await loading.edit(content='Error: Invalid character sheet.\n' + str(e))

        sheet = sheet['sheet']
        sheet['settings'] = old_character.get('settings', {})
        sheet['overrides'] = old_character.get('overrides', {})
        sheet['cvars'] = old_character.get('cvars', {})
        sheet['consumables'] = old_character.get('consumables', {})

        overrides = old_character.get('overrides', {})
        sheet['stats']['description'] = overrides.get('desc') or sheet.get('stats', {}).get("description",
                                                                                            "No description available.")
        sheet['stats']['image'] = overrides.get('image') or sheet.get('stats', {}).get('image', '')
        override_spells = []
        for s in overrides.get('spells', []):
            if isinstance(s, str):
                override_spells.append({'name': s, 'strict': True})
            else:
                override_spells.append(s)
        sheet['spellbook']['spells'].extend(override_spells)

        c = Character(sheet, url).initialize_consumables()

        if '-cc' in args and sheet_type == 'dicecloud':
            counters = parser.get_custom_counters()
            for counter in counters:
                displayType = 'bubble' if c.evaluate_cvar(counter['max']) < 6 else None
                try:
                    c.create_consumable(counter['name'], maxValue=str(counter['max']),
                                        minValue=str(counter['min']),
                                        reset=counter['reset'], displayType=displayType, live=counter['live'])
                except InvalidArgument:
                    pass

        # if c.get_combat_id() and not self.bot.rdb.exists(c.get_combat_id()):
        #     c.leave_combat()
        # reimplement this later

        await c.commit(ctx)
        await c.set_active(ctx)
        del parser, old_character  # pls don't freak out avrae
        if '-v' in args:
            await ctx.send(embed=c.get_sheet_embed())