Exemple #1
0
def entity_picked(context, entity):
    """An entity was picked with the mouse click.

    :param context: The game context.
    :type context: :class:`context.Context`

    :param entity: The entity picked
    :type entity: :class:`game.entities.entity.Entity`
    """
    send_event(EntityPick(entity))
Exemple #2
0
def entity_picked(context, entity):
    """An entity was picked with the mouse click.

    :param context: The game context.
    :type context: :class:`context.Context`

    :param entity: The entity picked
    :type entity: :class:`game.entities.entity.Entity`
    """
    send_event(EntityPick(entity))
Exemple #3
0
def handle_key_press(evt):
    """Handles the B key pressed event.

    Toggles the building game mode.

    :param evt: The key press event.
    :type evt: :class:`core.events.KeyPressEvent`
    """
    context = evt.context
    if evt.key == sdl.SDLK_b:
        send_event(GameModeToggle(context.GameMode.building))
Exemple #4
0
def handle_key_press(evt):
    """Handles the B key pressed event.

    Toggles the building game mode.

    :param evt: The key press event.
    :type evt: :class:`core.events.KeyPressEvent`
    """
    context = evt.context
    if evt.key == sdl.SDLK_b:
        send_event(GameModeToggle(context.GameMode.building))
def handle_actor_idle(gs_mgr):
    """Handles entities in idle state and fires ActorIdle event for them.

    :param gs_mgr: the gs_mgr
    :type gs_mgr: dict
    """
    for srv_id, entity in gamestate_entities(gs_mgr):
        # Update the position of every idle entity
        if entity.get(MF.action_type, ActionType.idle) == ActionType.idle:
            x, y = entity[MF.x_pos], entity[MF.y_pos]
            evt = ActorIdle(srv_id, x, y)
            send_event(evt)
Exemple #6
0
def handle_actor_idle(gs_mgr):
    """Handles entities in idle state and fires ActorIdle event for them.

    :param gs_mgr: the gs_mgr
    :type gs_mgr: dict
    """
    for srv_id, entity in gamestate_entities(gs_mgr):
        # Update the position of every idle entity
        if entity.get(MF.action_type, ActionType.idle) == ActionType.idle:
            x, y = entity[MF.x_pos], entity[MF.y_pos]
            evt = ActorIdle(srv_id, x, y)
            send_event(evt)
def handle_character_start_building(gs_mgr):
    """Handles building entities and fires CharacterBuildingStart event for them.

    :param gs_mgr: the gs_mgr
    :type gs_mgr: dict
    """
    n, o = gs_mgr.get(2)
    o = o or {}
    new, old = n[MF.entities], o.get(MF.entities, {})
    for e_id, entity in new.items():
        if entity[MF.action_type] in {ActionType.build, ActionType.repair}:
            if e_id not in old or old[e_id][MF.action_type] not in {ActionType.build, ActionType.repair}:
                send_event(CharacterBuildingStart(e_id))
Exemple #8
0
    def handle_joined(self, msg):
        """Handles player joins.

        Instantiates player entities and adds them to the game.

        :param msg: the message to be processed
        :type msg: :class:`message.Message`
        """
        character_name = as_utf8(msg.data[MF.name])
        srv_id = msg.data[MF.id]
        if srv_id != self.context.player_id:
            self.context.players_name_map[srv_id] = character_name
            send_event(CharacterJoin(srv_id, character_name))
Exemple #9
0
    def handle_joined(self, msg):
        """Handles player joins.

        Instantiates player entities and adds them to the game.

        :param msg: the message to be processed
        :type msg: :class:`message.Message`
        """
        character_name = as_utf8(msg.data[MF.name])
        srv_id = msg.data[MF.id]
        if srv_id != self.context.player_id:
            self.context.players_name_map[srv_id] = character_name
            send_event(CharacterJoin(srv_id, character_name))
def handle_time(gs_mgr):
    """Handles time change and sends time update event.

    :param gs_mgr: The gamestate manager.
    :type gs_mgr: :class:`game.gamestate.GameStateManager`
    """
    new, old = gs_mgr.get(2)
    if old:
        prev_total_minutes = old.get(MF.time, 0)
        total_minutes = new.get(MF.time, 0)
        h, m = int(total_minutes / 60), total_minutes % 60
        prev_m = prev_total_minutes % 60
        if m != prev_m:
            send_event(TimeUpdate(h, m))
Exemple #11
0
def handle_time(gs_mgr):
    """Handles time change and sends time update event.

    :param gs_mgr: The gamestate manager.
    :type gs_mgr: :class:`game.gamestate.GameStateManager`
    """
    new, old = gs_mgr.get(2)
    if old:
        prev_total_minutes = old.get(MF.time, 0)
        total_minutes = new.get(MF.time, 0)
        h, m = int(total_minutes / 60), total_minutes % 60
        prev_m = prev_total_minutes % 60
        if m != prev_m:
            send_event(TimeUpdate(h, m))
def handle_actor_disappear(gs_mgr):
    """Check for disappeared entities and send the appropriate events.

    Check if there are new entities that were not in the previous gamestate.

    :param gs_mgr: the gs_mgr
    :type gs_mgr: dict
    """
    n, o = gs_mgr.get(2)
    o = o or {}
    new, old = n[MF.entities], o.get(MF.entities, {})
    old_entities = set(old) - set(new)
    for ent in old_entities:
        evt = ActorDisappear(ent, old[ent][MF.entity_type])
        send_event(evt)
Exemple #13
0
    def handle_leave(self, msg):
        """Handles the leave message.

        :param msg: the message to be processed
        :type msg: :class:`message.Message`
        """
        srv_id = msg.data[MF.id]
        reason = msg.data[MF.reason]
        if not self.context.player_id or srv_id == self.context.player_id:
            LOG.info('Local player disconnected')
            self.exit = True
        else:
            LOG.info('Player "{}" disconnected'.format(srv_id))
            name = self.context.players_name_map.pop(srv_id)
            send_event(CharacterLeave(srv_id, name, reason))
Exemple #14
0
def handle_object_spawn(gs_mgr):
    """Check for new static objects and place them on the scene.

    :param gs_mgr: the gs_mgr
    :type gs_mgr: :class:`dict`
    """
    n, o = gs_mgr.get(2)
    o = o or {}
    new, old = n[MF.objects], o.get(MF.objects, {})
    for o_id, obj in new.items():
        if o_id not in old:
            obj_type = obj[MF.object_type]
            pos = obj[MF.x_pos], obj[MF.y_pos]
            operated_by = obj[MF.operated_by]
            send_event(ObjectSpawn(o_id, obj_type, pos, operated_by))
Exemple #15
0
    def handle_leave(self, msg):
        """Handles the leave message.

        :param msg: the message to be processed
        :type msg: :class:`message.Message`
        """
        srv_id = msg.data[MF.id]
        reason = msg.data[MF.reason]
        if not self.context.player_id or srv_id == self.context.player_id:
            LOG.info('Local player disconnected')
            self.exit = True
        else:
            LOG.info('Player "{}" disconnected'.format(srv_id))
            name = self.context.players_name_map.pop(srv_id)
            send_event(CharacterLeave(srv_id, name, reason))
Exemple #16
0
def handle_actor_disappear(gs_mgr):
    """Check for disappeared entities and send the appropriate events.

    Check if there are new entities that were not in the previous gamestate.

    :param gs_mgr: the gs_mgr
    :type gs_mgr: dict
    """
    n, o = gs_mgr.get(2)
    o = o or {}
    new, old = n[MF.entities], o.get(MF.entities, {})
    old_entities = set(old) - set(new)
    for ent in old_entities:
        evt = ActorDisappear(ent, old[ent][MF.entity_type])
        send_event(evt)
Exemple #17
0
def handle_character_start_building(gs_mgr):
    """Handles building entities and fires CharacterBuildingStart event for them.

    :param gs_mgr: the gs_mgr
    :type gs_mgr: dict
    """
    n, o = gs_mgr.get(2)
    o = o or {}
    new, old = n[MF.entities], o.get(MF.entities, {})
    for e_id, entity in new.items():
        if entity[MF.action_type] in {ActionType.build, ActionType.repair}:
            if e_id not in old or old[e_id][MF.action_type] not in {
                    ActionType.build, ActionType.repair
            }:
                send_event(CharacterBuildingStart(e_id))
def handle_object_spawn(gs_mgr):
    """Check for new static objects and place them on the scene.

    :param gs_mgr: the gs_mgr
    :type gs_mgr: :class:`dict`
    """
    n, o = gs_mgr.get(2)
    o = o or {}
    new, old = n[MF.objects], o.get(MF.objects, {})
    for o_id, obj in new.items():
        if o_id not in old:
            obj_type = obj[MF.object_type]
            pos = obj[MF.x_pos], obj[MF.y_pos]
            operated_by = obj[MF.operated_by]
            send_event(ObjectSpawn(o_id, obj_type, pos, operated_by))
Exemple #19
0
def handle_actor_action_change(gs_mgr):
    new, old = gs_mgr.get(2)
    if not old:
        return

    new_entities = new.get(MF.entities, {})
    old_entities = old.get(MF.entities, {})
    for srv_id, entity in old_entities.items():
        if srv_id in new_entities:
            old_action = entity[MF.action_type]
            new_action = new_entities[srv_id][MF.action_type]
            if old_action != new_action:
                actor_type = ActorType(entity[MF.entity_type])
                send_event(
                    ActorActionChange(srv_id, actor_type, old_action,
                                      new_action))
Exemple #20
0
def handle_actor_health(gs_mgr):
    """Check for entity health changes and send the appropriate event.

    :param gs_mgr: the gs_mgr
    :type gs_mgr: :class:`dict`
    """
    n, o = gs_mgr.get(2)
    o = o or {}
    new, old = n[MF.entities], o.get(MF.entities, {})
    for e_id, entities in new.items():
        if e_id in old:
            new_hp = entities[MF.cur_hp]
            old_hp = old[e_id][MF.cur_hp]
            hp_changed = new_hp != old_hp
            actor_type = ActorType(entities[MF.entity_type])
            if hp_changed:
                send_event(ActorStatusChange(e_id, actor_type, old_hp, new_hp))
def handle_actor_health(gs_mgr):
    """Check for entity health changes and send the appropriate event.

    :param gs_mgr: the gs_mgr
    :type gs_mgr: :class:`dict`
    """
    n, o = gs_mgr.get(2)
    o = o or {}
    new, old = n[MF.entities], o.get(MF.entities, {})
    for e_id, entities in new.items():
        if e_id in old:
            new_hp = entities[MF.cur_hp]
            old_hp = old[e_id][MF.cur_hp]
            hp_changed = new_hp != old_hp
            actor_type = ActorType(entities[MF.entity_type])
            if hp_changed:
                send_event(ActorStatusChange(e_id, actor_type, old_hp, new_hp))
def handle_actor_spawn(gs_mgr):
    """Check for new entities and send the appropriate events.

    Check if there are new entities that were not in the previous gamestate.

    :param gs_mgr: the gs_mgr
    :type gs_mgr: dict
    """
    n, o = gs_mgr.get(2)
    o = o or {}
    new, old = n[MF.entities], o.get(MF.entities, {})
    new_entities = set(new) - set(old)
    for ent in new_entities:
        data = new[ent]
        actor_type = ActorType(data[MF.entity_type])
        cur_hp = data[MF.cur_hp]
        evt = ActorSpawn(ent, actor_type, cur_hp)
        send_event(evt)
def handle_actor_action_change(gs_mgr):
    new, old = gs_mgr.get(2)
    if not old:
        return

    new_entities = new.get(MF.entities, {})
    old_entities = old.get(MF.entities, {})
    for srv_id, entity in old_entities.items():
        if srv_id in new_entities:
            old_action = entity[MF.action_type]
            new_action = new_entities[srv_id][MF.action_type]
            if old_action != new_action:
                actor_type = ActorType(entity[MF.entity_type])
                send_event(ActorActionChange(
                    srv_id,
                    actor_type,
                    old_action,
                    new_action))
def handle_building_health(gs_mgr):
    """Check for building health/satatus changes and send the appropriate event.

    :param gs_mgr: the gs_mgr
    :type gs_mgr: :class:`dict`
    """
    n, o = gs_mgr.get(2)
    o = o or {}
    new, old = n[MF.buildings], o.get(MF.buildings, {})
    for b_id, building in new.items():
        if b_id in old:
            new_hp = building[MF.cur_hp]
            old_hp = old[b_id][MF.cur_hp]
            hp_changed = new_hp != old_hp
            status_changed = building[MF.completed] == old[b_id][MF.completed]
            if hp_changed or status_changed:
                send_event(BuildingStatusChange(
                    b_id, old_hp, new_hp, building[MF.completed]))
Exemple #25
0
def handle_actor_spawn(gs_mgr):
    """Check for new entities and send the appropriate events.

    Check if there are new entities that were not in the previous gamestate.

    :param gs_mgr: the gs_mgr
    :type gs_mgr: dict
    """
    n, o = gs_mgr.get(2)
    o = o or {}
    new, old = n[MF.entities], o.get(MF.entities, {})
    new_entities = set(new) - set(old)
    for ent in new_entities:
        data = new[ent]
        actor_type = ActorType(data[MF.entity_type])
        cur_hp = data[MF.cur_hp]
        evt = ActorSpawn(ent, actor_type, cur_hp)
        send_event(evt)
Exemple #26
0
def handle_building_health(gs_mgr):
    """Check for building health/satatus changes and send the appropriate event.

    :param gs_mgr: the gs_mgr
    :type gs_mgr: :class:`dict`
    """
    n, o = gs_mgr.get(2)
    o = o or {}
    new, old = n[MF.buildings], o.get(MF.buildings, {})
    for b_id, building in new.items():
        if b_id in old:
            new_hp = building[MF.cur_hp]
            old_hp = old[b_id][MF.cur_hp]
            hp_changed = new_hp != old_hp
            status_changed = building[MF.completed] == old[b_id][MF.completed]
            if hp_changed or status_changed:
                send_event(
                    BuildingStatusChange(b_id, old_hp, new_hp,
                                         building[MF.completed]))
Exemple #27
0
def start_build_action(context, position):
    """Start a build action to the defined position.

    NOTE: the game context has all the information required.

    :param context: The game context.
    :type context: :class:`context.Context`

    :param position: The position in world ccoordinates
    :type position: :class:`tuple`
    """
    building_type = context.building_type
    msg = Message(MessageType.build, {
        MessageField.building_type: building_type,
        MessageField.x_pos: position[0],
        MessageField.y_pos: position[1],
    })

    context.msg_queue.append(msg)
    send_event(GameModeToggle(context.GameMode.building))
Exemple #28
0
def handle_buildings(selected, buildings, event):
    """Generic function for building spawning/disappearing handling.

    :param selected: The ids of the building to be handled.
    :type selected: :class:`set`

    :param buildings: The mapping of all the buildings in the gamestate.
    :type buildings: :class:`dict`

    :param event: The event class to be used
    :type event: :class:`type`
    """
    for building in selected:
        data = buildings[building]
        b_type = BuildingType(data[MF.building_type])
        pos = data[MF.x_pos], data[MF.y_pos]
        cur_hp = data[MF.cur_hp]
        completed = data[MF.completed]
        evt = event(building, b_type, pos, cur_hp, completed)
        send_event(evt)
def handle_buildings(selected, buildings, event):
    """Generic function for building spawning/disappearing handling.

    :param selected: The ids of the building to be handled.
    :type selected: :class:`set`

    :param buildings: The mapping of all the buildings in the gamestate.
    :type buildings: :class:`dict`

    :param event: The event class to be used
    :type event: :class:`type`
    """
    for building in selected:
        data = buildings[building]
        b_type = BuildingType(data[MF.building_type])
        pos = data[MF.x_pos], data[MF.y_pos]
        cur_hp = data[MF.cur_hp]
        completed = data[MF.completed]
        evt = event(building, b_type, pos, cur_hp, completed)
        send_event(evt)
Exemple #30
0
def start_build_action(context, position):
    """Start a build action to the defined position.

    NOTE: the game context has all the information required.

    :param context: The game context.
    :type context: :class:`context.Context`

    :param position: The position in world coordinates
    :type position: :class:`tuple`
    """
    building_type = context.building_type
    msg = Message(
        MessageType.build, {
            MessageField.building_type: building_type,
            MessageField.x_pos: position[0],
            MessageField.y_pos: position[1],
        })

    context.msg_queue.append(msg)
    send_event(GameModeToggle(context.GameMode.building))
Exemple #31
0
    def process_input(self):
        """Process buffered input and dispatch resulting events."""
        events = sdl_ext.get_events()
        for evt in events:
            if evt.type in {sdl.SDL_KEYUP}:
                key_event = evt.key
                send_event(KeyPressEvent(key_event.keysym.sym))

            elif evt.type in {sdl.SDL_MOUSEMOTION}:
                mouse_motion = evt.motion
                send_event(MouseMoveEvent(mouse_motion.x, mouse_motion.y))

            elif evt.type in {sdl.SDL_MOUSEBUTTONDOWN, sdl.SDL_MOUSEBUTTONUP}:
                mouse_event = evt.button

                if mouse_event.button == sdl.SDL_BUTTON_LEFT:
                    button = MouseClickEvent.Button.left
                elif mouse_event.button == sdl.SDL_BUTTON_RIGHT:
                    button = MouseClickEvent.Button.right
                else:
                    button = MouseClickEvent.Button.unknown

                if evt.type == sdl.SDL_MOUSEBUTTONDOWN:
                    state = MouseClickEvent.State.down
                else:
                    state = MouseClickEvent.State.up

                send_event(MouseClickEvent(
                    mouse_event.x,
                    mouse_event.y,
                    button,
                    state))
Exemple #32
0
    def process_input(self):
        """Process buffered input and dispatch resulting events."""
        events = sdl_ext.get_events()
        for evt in events:
            if evt.type in {sdl.SDL_KEYUP}:
                key_event = evt.key
                send_event(KeyPressEvent(key_event.keysym.sym))

            elif evt.type in {sdl.SDL_MOUSEMOTION}:
                mouse_motion = evt.motion
                send_event(MouseMoveEvent(mouse_motion.x, mouse_motion.y))

            elif evt.type in {sdl.SDL_MOUSEBUTTONDOWN, sdl.SDL_MOUSEBUTTONUP}:
                mouse_event = evt.button

                if mouse_event.button == sdl.SDL_BUTTON_LEFT:
                    button = MouseClickEvent.Button.left
                elif mouse_event.button == sdl.SDL_BUTTON_RIGHT:
                    button = MouseClickEvent.Button.right
                else:
                    button = MouseClickEvent.Button.unknown

                if evt.type == sdl.SDL_MOUSEBUTTONDOWN:
                    state = MouseClickEvent.State.down
                else:
                    state = MouseClickEvent.State.up

                send_event(
                    MouseClickEvent(mouse_event.x, mouse_event.y, button,
                                    state))
def handle_actor_move(gs_mgr):
    """Handles moving entities and fires ActorMove event for them.

    :param gs_mgr: the gs_mgr
    :type gs_mgr: dict
    """
    new, old = gs_mgr.get(2)
    if not old:
        return
    new_entities = new.get(MF.entities, {})
    old_entities = old.get(MF.entities, {})
    for srv_id, entity in old_entities.items():
        if entity[MF.action_type] == ActionType.move and srv_id in new_entities:
            action = entity[MF.action]
            position = entity[MF.x_pos], entity[MF.y_pos]
            new_entity = new_entities[srv_id]
            new_position = new_entity[MF.x_pos], new_entity[MF.y_pos]
            send_event(ActorMove(
                srv_id,
                position=position,
                path=[new_position],
                speed=action[MF.speed]))
Exemple #34
0
def show_building_template(evt):
    """In case we are in a gamemode different from the default one shows the
    building template otherwise destroys it.
    """
    context = evt.context

    if evt.mode == context.GameMode.building:
        # Check if the player has the proper type and toggle the game mode.
        if context.character_type == ActorType.engineer:
            prev, cur = context.toggle_game_mode(evt.mode)
            send_event(GameModeChange(prev, cur))

    if context.game_mode == context.GameMode.building:
        # TODO: Remove the hardcoded building type with a dynamic one
        building_type = BuildingType.barricade.value
        entities = context.res_mgr.get('/entities')
        resource = context.res_mgr.get(
            entities.data['buildings_map'].get(
                BuildingType(building_type).name,
                '/prefabs/buildings/barricade'
            )
        )

        matrix, scale_factor = context.matrix, context.scale_factor
        building_template = BuildingTemplate(
            resource, matrix, scale_factor, context.scene.root)

        context.building_type = building_type
        context.building_template = building_template
        context.entities[building_template.e_id] = building_template
        x, y = context.input_mgr.mouse_position
        place_building_template(context, x, y)

    elif context.building_template is not None:
        # Reset the building-mode related context while exiting building mode
        context.building_type = 0
        bt, context.building_template = context.building_template, None
        del context.entities[bt.e_id]
        bt.destroy()
def show_building_template(evt):
    """In case we are in a gamemode different from the default one shows the
    building template otherwise destroys it.
    """
    context = evt.context

    if evt.mode == context.GameMode.building:
        # Check if the player has the proper type and toggle the game mode.
        if context.character_type == ActorType.engineer:
            prev, cur = context.toggle_game_mode(evt.mode)
            send_event(GameModeChange(prev, cur))

    if context.game_mode == context.GameMode.building:
        # TODO: Remove the hardcoded building type with a dynamic one
        building_type = BuildingType.barricade.value
        entities = context.res_mgr.get('/entities')
        resource = context.res_mgr.get(
            entities.data['buildings_map'].get(
                BuildingType(building_type).name,
                '/prefabs/buildings/barricade'
            )
        )

        matrix, scale_factor = context.matrix, context.scale_factor
        building_template = BuildingTemplate(
            resource, context.scene, matrix, scale_factor)

        context.building_type = building_type
        context.building_template = building_template
        context.entities[building_template.e_id] = building_template
        x, y = context.input_mgr.mouse_position
        place_building_template(context, x, y)

    elif context.building_template is not None:
        # Reset the building-mode related context while exiting building mode
        context.building_type = 0
        bt, context.building_template = context.building_template, None
        del context.entities[bt.e_id]
        bt.remove()
Exemple #36
0
def handle_actor_move(gs_mgr):
    """Handles moving entities and fires ActorMove event for them.

    :param gs_mgr: the gs_mgr
    :type gs_mgr: dict
    """
    new, old = gs_mgr.get(2)
    if not old:
        return
    new_entities = new.get(MF.entities, {})
    old_entities = old.get(MF.entities, {})
    for srv_id, entity in old_entities.items():
        if entity[
                MF.action_type] == ActionType.move and srv_id in new_entities:
            action = entity[MF.action]
            position = entity[MF.x_pos], entity[MF.y_pos]
            new_entity = new_entities[srv_id]
            new_position = new_entity[MF.x_pos], new_entity[MF.y_pos]
            send_event(
                ActorMove(srv_id,
                          position=position,
                          path=[new_position],
                          speed=action[MF.speed]))
Exemple #37
0
    def handle_stay(self, msg):
        """Handles stay response from server.

        Assigns the client a server provided id, which uniquely identifies the
        controlled player entity.

        :param msg: the message to be processed
        :type msg: :class:`message.Message`
        """
        srv_id = msg.data[MF.id]
        self.context.player_id = srv_id
        self.context.players_name_map[srv_id] = msg.data[MF.id]
        LOG.info('Joined the party with name "{}" and  ID {}'.format(
            self.context.character_name, self.context.player_id))

        # Send the proper events for the joined local player
        send_event(
            PlayerJoin(self.context.player_id, self.context.character_name))

        for srv_id, name in msg.data[MF.players].items():
            if srv_id != self.context.player_id:
                self.context.players_name_map[srv_id] = name
                send_event(CharacterJoin(srv_id, as_utf8(name)))
Exemple #38
0
    def handle_stay(self, msg):
        """Handles stay response from server.

        Assigns the client a server provided id, which uniquely identifies the
        controlled player entity.

        :param msg: the message to be processed
        :type msg: :class:`message.Message`
        """
        srv_id = msg.data[MF.id]
        self.context.player_id = srv_id
        self.context.players_name_map[srv_id] = msg.data[MF.id]
        LOG.info('Joined the party with name "{}" and  ID {}'.format(
            self.context.character_name, self.context.player_id))

        # Send the proper events for the joined local player
        send_event(PlayerJoin(
            self.context.player_id, self.context.character_name))

        for srv_id, name in msg.data[MF.players].items():
            if srv_id != self.context.player_id:
                self.context.players_name_map[srv_id] = name
                send_event(CharacterJoin(srv_id, as_utf8(name)))
Exemple #39
0
    def __call__(self, pipeline_id, state, errors=None, stats=None):  #noqa
        logging.info('Status %s: %s (errors#=%d, stats=%r)', pipeline_id,
                     state,
                     len(errors) if errors is not None else 0, stats)
        now = datetime.datetime.now()
        registry = self.registry

        if pipeline_id.startswith('./'):
            pipeline_id = pipeline_id[2:]

        errors = errors
        if state in ('SUCCESS', 'FAILED'):
            event = 'finish'
        else:
            event = 'progress'
        success = state == 'SUCCESS'
        log = []
        stats = stats if stats is not None else {}

        pipeline_status = STATE_PENDING if event == 'queue' else STATE_RUNNING
        if event == 'finish':
            if success:
                pipeline_status = STATE_SUCCESS
            else:
                pipeline_status = STATE_FAILED

        doc = dict(status=pipeline_status,
                   errors=errors,
                   stats=stats,
                   log=log,
                   updated_at=now)
        if registry.update_pipeline(pipeline_id, doc):
            pipeline = registry.get_pipeline(pipeline_id)
            flow_id = registry.get_flow_id(pipeline_id)
            flow_status = registry.check_flow_status(flow_id)

            if pipeline_status == STATE_FAILED:
                update_dependants(flow_id, pipeline_id, registry)

            doc = dict(
                status=flow_status,
                updated_at=now,
            )
            if errors:
                doc['errors'] = errors
            if stats:
                doc['stats'] = stats
            if log:
                doc['logs'] = log

            rev = registry.get_revision_by_revision_id(flow_id)
            pipelines = rev.get('pipelines')
            if pipelines is None:
                pipelines = {}

            pipeline_state = {
                STATE_PENDING: 'QUEUED',
                STATE_RUNNING: 'INPROGRESS',
                STATE_SUCCESS: 'SUCCEEDED',
                STATE_FAILED: 'FAILED',
            }[pipeline_status]

            pipelines[pipeline_id] = dict(
                title=pipeline.get('title'),
                status=pipeline_state,
                stats=stats,
                error_log=errors,
            )
            doc['pipelines'] = pipelines
            revision = registry.update_revision(flow_id, doc)
            dataset = registry.get_dataset(revision['dataset_id'])
            if (flow_status != STATE_PENDING) and (flow_status !=
                                                   STATE_RUNNING):
                registry.delete_pipelines(flow_id)
                findability = \
                    flow_status == STATE_SUCCESS and \
                    dataset['spec']['meta']['findability'] == 'published'
                findability = 'published' if findability else 'private'
                events.send_event(
                    'flow',  # Source of the event
                    event,  # What happened
                    'OK' if flow_status == STATE_SUCCESS else
                    'FAIL',  # Success indication
                    findability,  # one of "published/private/internal":
                    dataset['owner'],  # Actor
                    dataset_getter(dataset['spec']),  # Dataset in question
                    dataset['spec']['meta']['owner'],  # Owner of the dataset
                    dataset['spec']['meta']
                    ['ownerid'],  # Ownerid of the dataset
                    flow_id,  # Related flow id
                    pipeline_id,  # Related pipeline id
                    {
                        'flow-id': flow_id,
                        'errors': errors,
                    }  # Other payload
                )
            if flow_status == STATE_FAILED:
                statuspage.on_incident(
                    'Pipelines Failed for %s' %
                    dataset['spec']['meta']['dataset'],
                    dataset['spec']['meta']['owner'], errors)

            no_succesful_revision = registry.get_revision(
                revision['dataset_id'], 'successful') is None

            if flow_status == STATE_SUCCESS or no_succesful_revision:
                descriptor: dict = get_descriptor(flow_id)
                if descriptor is not None:
                    if no_succesful_revision and descriptor['datahub'].get(
                            'findability') == 'published':
                        descriptor['datahub']['findability'] = 'unlisted'
                    send_dataset(descriptor.get('id'), descriptor.get('name'),
                                 descriptor.get('title'),
                                 descriptor.get('description'),
                                 descriptor.get('datahub'), descriptor,
                                 dataset.get('certified') or False)

            return {'status': flow_status, 'id': flow_id, 'errors': errors}
        else:
            return {
                'status': None,
                'id': None,
                'errors': ['pipeline not found']
            }