Beispiel #1
0
def create_collections_categories_graph(db: StandardDatabase) -> None:
    if db.has_graph(GRAPH_COLLECTIONS_CATEGORIES):
        return

    graph = db.create_graph(GRAPH_COLLECTIONS_CATEGORIES)
    # Language -> Collections
    graph.create_edge_definition(
        edge_collection=EDGE_COLLECTION_LANGUAGE_HAS_COLLECTIONS,
        from_vertex_collections=[COLLECTION_LANGUAGES],
        to_vertex_collections=[COLLECTION_MENU_COLLECTIONS],
    )
    # Collection -> Categories
    graph.create_edge_definition(
        edge_collection=EDGE_COLLECTION_COLLECTION_HAS_CATEGORIES,
        from_vertex_collections=[COLLECTION_MENU_COLLECTIONS],
        to_vertex_collections=[COLLECTION_MENU_CATEGORIES],
    )
    # Category -> Files
    graph.create_edge_definition(
        edge_collection=EDGE_COLLECTION_CATEGORY_HAS_FILES,
        from_vertex_collections=[COLLECTION_MENU_CATEGORIES],
        to_vertex_collections=[COLLECTION_FILES],
    )
Beispiel #2
0
def create(db: StandardDatabase, game: Game, creator=None):
    """
    save a game to the database
    :param db: connection
    :param game: target
    :param creator: creator of the game
    """
    logger.info(f'create called for {game.title}')
    if not db.has_collection('games'):
        logger.info(f'games collection does not exist, creating it.')
        db.create_collection('games')
    db_games = db.collection('games')
    if db_games.find({'key': game.title}):
        logger.warning(f'{game.title} already in metadata')
        raise GameStateException(f'{game.title} already in metadata')
    if db.has_graph(game.title):
        logger.warning(f'{game.title} already defined')
        raise GameStateException(f'{game.title} already defined')
    if not nx.is_directed_acyclic_graph(game.graph):
        logger.warning(f'{game.title} is not acyclic')
        raise GameStateException(f'{game.title} is not acyclic')
    if not game.start_is_set():
        logger.warning(f'{game.title} has no starting point')
        raise GameStateException(f'{game.title} has no starting point')
    db_game_graph = db.create_graph(f'game_{game.title}')
    if not db_game_graph.has_vertex_collection('waypoints'):
        logger.info(f'waypoints vertex collection does not exist, creating it.')
        db_game_graph.create_vertex_collection('waypoints')
    path = db_game_graph.create_edge_definition(
        edge_collection='path',
        from_vertex_collections=['waypoints'],
        to_vertex_collections=['waypoints']
    )
    # add all game nodes
    for waypoint_vertex in set(game.start.all_path_nodes()):
        logger.debug(f'inserting waypoint vertex {repr(waypoint_vertex)}')
        db_game_graph.insert_vertex('waypoints', json.dumps(waypoint_vertex, cls=MarugotoEncoder))

    # tasks as documents
    if not db.has_collection('tasks'):
        logger.info(f'tasks collection does not exist, creating it.')
        db.create_collection('tasks')
    tasks = db.collection('tasks')

    # dialogs metadata
    if not db.has_collection('dialogs'):
        logger.info(f'dialogs does not exist, creating it.')
        db.create_collection('dialogs')
    db_dialogs = db.collection('dialogs')

    # npc dialog metadata
    if not db.has_collection('npcs'):
        logger.info(f'npcs collection does not exist, creating it.')
        db.create_collection('npcs')
    db_npcs = db.collection('npcs')

    for npc in game.npcs:
        if db_npcs.find({'_key': f'{game.title}-{npc.first_name}-{npc.last_name}'}):
            logger.warning(f'dialog {game.title}-{npc.first_name}-{npc.last_name} already in metadata')
            raise GameStateException(f'dialog {game.title}-{npc.first_name}-{npc.last_name} already in metadata')
        logger.debug(f'inserting npc {game.title}-{npc.first_name}-{npc.last_name} with dialog {npc.dialog.id.hex}')
        db_npcs.insert({
            '_key': f'{game.title}-{npc.first_name}-{npc.last_name}',
            'game': f'game_{game.title}',
            'first_name': npc.first_name,
            'last_name': npc.last_name,
            'salutation': npc.salutation,
            'mail': npc.mail,
            'image': base64.encodebytes(npc.image) if npc.image else None,
            'dialog': npc.dialog.id.hex
        })

        if db_dialogs.find({'_key': npc.dialog.id.hex}):
            logger.warning(f'dialog {npc.dialog.id} already in metadata')
            raise GameStateException(f'dialog {npc.dialog.id} already in metadata')
        if db.has_graph(f'dialog_{npc.dialog.id.hex}'):
            logger.warning(f'dialog {npc.dialog.id} already defined')
            raise GameStateException(f'dialog {npc.dialog.id} already defined')
        if not nx.is_directed_acyclic_graph(npc.dialog.graph):
            logger.warning(f'dialog {npc.dialog.id} is not acyclic')
            raise GameStateException(f'dialog {npc.dialog.id} is not acyclic')
        if not npc.dialog.start_is_set():
            logger.warning(f'dialog {npc.dialog.id} has no starting point')
            raise GameStateException(f'dialog {npc.dialog.id} has no starting point')
        db_dialog_graph = db.create_graph(f'dialog_{npc.dialog.id.hex}')
        if not db_dialog_graph.has_vertex_collection('interactions'):
            logger.debug(f'interaction vertex collection does not exist, creating it.')
            db_dialog_graph.create_vertex_collection('interactions')
        conversation = db_dialog_graph.create_edge_definition(
            edge_collection='conversation',
            from_vertex_collections=['interactions'],
            to_vertex_collections=['interactions']
        )
        # add all dialog nodes
        for interaction_vertex in set(npc.dialog.start.all_path_nodes()):
            logger.debug(f'inserting interaction vertex {repr(interaction_vertex)}')
            db_dialog_graph.insert_vertex('interactions', json.dumps(interaction_vertex, cls=MarugotoEncoder))

        dia_visited = {}

        def dialog_traversal(s, i):
            """
            Walk through the game path from a starting source
            :param s: starting waypoint for traversal
            :param i: dict containing identified steps
            """
            for successor in npc.dialog.graph.successors(s):
                logger.debug(f'successor {repr(successor)} for {repr(s)}')
                if s not in i.keys():
                    logger.debug(f'{repr(s)} is new, adding it')
                    i[s] = []
                if successor not in i[s]:
                    if successor.task:
                        logger.debug(f'{repr(successor)} has {repr(successor.task)}, adding to tasks')
                        task_dump = json.loads(json.dumps(successor.task, cls=MarugotoEncoder))
                        task_dump['_key'] = successor.task.id.hex
                        task_dump['for'] = successor.id.hex
                        if not tasks.find(task_dump):
                            tasks.insert(json.dumps(task_dump))
                    logger.debug(f'inserting interaction edge {repr(s)} to {repr(successor)}')
                    conversation.insert({
                        '_key': f'{s.id.hex}-{successor.id.hex}',
                        '_from': f'interactions/{s.id.hex}',
                        '_to': f'interactions/{successor.id.hex}'
                    })
                    dia_visited[s].append(successor)
                    dialog_traversal(successor, i)

        logger.debug(f'traversing dialog graph for {npc.first_name} {npc.last_name}')
        dialog_traversal(npc.dialog.start, dia_visited)
        logger.debug(f'inserting dialog {npc.dialog.id.hex}')
        db_dialogs.insert({
            '_key': npc.dialog.id.hex,
            'start': npc.dialog.start.id.hex
        })

    wp_visited = {}

    def game_traversal(s, i):
        """
        Walk through the game path from a starting source
        :param s: starting waypoint for traversal
        :param i: dict containing identified steps
        """
        for successor in game.graph.successors(s):
            logger.debug(f'successor {repr(successor)} for {repr(s)}')
            if s not in i.keys():
                logger.debug(f'{repr(s)} is new, adding it.')
                i[s] = []
            if successor not in i[s]:
                for task in successor.tasks:
                    logger.debug(f'{repr(successor)} has {repr(task)}, adding to tasks')
                    task_dump = json.loads(json.dumps(task, cls=MarugotoEncoder))
                    task_dump['_key'] = task.id.hex
                    task_dump['for'] = successor.id.hex
                    if not tasks.find(task_dump):
                        tasks.insert(json.dumps(task_dump))
                logger.debug(f'waypoint interaction edge {repr(s)} to {repr(successor)}')
                weight = game.graph.edges[s, successor]['weight'] if 'weight' in game.graph.edges[s, successor] and game.graph.edges[s, successor]['weight'] else None
                path.insert({
                    '_key': f'{s.id.hex}-{successor.id.hex}',
                    '_from': f'waypoints/{s.id.hex}',
                    '_to': f'waypoints/{successor.id.hex}',
                    'weight': weight
                })
                wp_visited[s].append(successor)
                game_traversal(successor, i)

    logger.debug(f'traversing game graph for {game.title}')
    game_traversal(game.start, wp_visited)
    logger.debug(f'inserting game {game.title}')
    db_games.insert({
        '_key': game.title,
        'start': game.start.id.hex,
        'image': base64.encodebytes(game.image) if game.image else None,
        'creator': creator
    })