Fixing event ordering bug

The events logs is populating with existing move events after the user joins a game session, but they are in the wrong order. The most recent events should be rendered at the bottom of the events log component, but they are at the top. I decide to simply sort the events on the client before they are added to the Alpine store as event messages. The id property for event objects are numeric with the newest event ids being larger than older ones.

// …

export default function createSetGameEventsLog({ store }) {
  return (events) => {
    const messages = events
      .sort((a, b) => a.id - b.id)
      .map(convertGameEventToMessage)
      .filter((message) => message !== null)

    store.eventsLog.set(messages)
  }
}

Updating events log every round

When a round ends, any new game events are sent to the frontend client with the new round information. I update the LiveView event handler that receives this payload to append messages for new game events to the Alpine data store. The UI component is already hooked up to render based on this data store, so all move events are now being displayed in the events log component as the game progresses.

Better event message formatting for own moves

The last item I had on my list for move events is to change the displayed message for the user’s own player character movements. Currently, all move event messages show the name of the player and from which direction they moved. Instead of an event message like “Player123 arrived from the east.”, a user’s own movement should render a message like “You arrived from the east.”

My initial though is to create a separate event to differentiate between movement of another player and the movement of the current player. This change would be fairly small to implement on the backend, but it would require sending more context to the formatter functions that convert game event structs into serializable maps for the frontend to use. Adding a new parameter for this function that is responsible for converting arbitrary event structs to maps could be adding bloat to the function signature that is only used by this single event type.

I’m rethinking my decision to remove player ids from the game event payload since that would be an easy way on the frontend to handle checking if the movement was made by the current player. I add back the player_id to the game event objects in the server event payloads sent to the front end. Eventually, I can remove the player_name from these game events and create a lookup map on the frontend to derive the name from the player ids, but I’ll leave names as-is for now.

On the frontend, I pass the current player’s id to the functions responsible for converting game event objects to event message objects. With this change, the conversion function can determine if the current player was the source of the move event and set the appropriate message text for the context.

// …

function convertPCEnteredHex(event, playerId) {
  const mover = playerId === event.playerId ? 'You' : event.pcName
  const direction = convertCoordToDirection(event.from)

  return {
    eventId: event.id,
    round: event.round,
    text: `${mover} arrived from the ${direction}.`,
  }
}

Now, the event messages are displaying text specific to the current user. I’m going back to review the logic for which players have visibility to the move events since there are some cases I’ve changed my mind on. With a few more tweaks I’m hoping I’ll be done with move events and can move on to more interesting mechanics.