javamongodbbukkitbungeecord

Mongo Database profile sync on bungeecord player transfer


I have several instances of Spigot running across a bungeecord server. I have a plugin that does custom profile management across every server. This profile management plugin reads and writes to a Mongo database. All the code works just fine and I am not here for code.

However, my issue is this. When a player transfers from one server to another, the data isn't synced (wrote to the database) before the profile is loaded again on the destination server which results in old data being loaded. Because of this peoples stats and economy aren't being reflected correctly. Now if they login, switch to a minigame server, play a game, then earn coins, and they quit the server (logout) then stats will be reflected correctly on next login.

The profile manager loads profile content on a PlayerJoinEvent and data is written (saved) on PlayerQuitEvent and the PlayerKickEvent.

What is the best way to combat this issue? Can someone please point me in the right direction?

EDIT: electroniccat said on the official Spigot IRC that the player starts connection to a destination server before being disconnected from the previous server. Since this does make sense, what is the best way to work around this?


Solution

  • I would suggest adding a status variable to your player profiles in MongoDB.

    Then, using a bungee plugin or alike to detect when a player begins swapping a server; set the status to saving.

    And when your are saving your player data on PlayerQuitEvent, set the status to saved.

    Then, when a player is logging in, on PlayerJoin ensure the status is saved. If it is not, add a timer that waits a few seconds (I'd suggest actually doing loading on AsyncPlayerPreLoginEvent, this way the login is delayed and they won't be walking around with an empty profile) -- and ensure the timer continues trying (perhaps max 3 times) until status is saved. If 3 attempts pass and it is still not saved, kick the player / prevent the login (although this should not happen). Make sure there is enough delay between attempts.

    I'm not sure why you're having this issue as I have used Mongo for a bungee server before and never had this issue with player profiles.

    An alternative option is to do the profile caching via redis, keep it updated via save intervals and on leave. Or pub/sub or plugin messaging, send profile data to the bungee instance and let it handle saving profiles.

    Make sure you are setting your status to saving right after a player logins in and their profile is loaded. Otherwise this data will not be pushed in time to be read because the join event is fired before the quit on bungee. (Maybe using a Boolean rather than 'saving' / 'saved' would be better as well)

    Timeline:

    (status 1 = saved, status 0 = waiting save)

    Initial join to bungee: load profile, after profile is loaded set status: 0

    Switching server: AsyncPlayerPreLoginEvent on target server fires: check if profile loaded (if status=1), if so set status: 0. This will likely not be the case on first attempt so have a timer every ~20-40 ticks to re-attempt

    PlayerQuitEvent on origin server fires: update status: 1, save profile to mongo with same update. This will then allow the AsyncPlayerPreLoginEvent on the target server to load the profile.

    I would suggest using caching via redis as it works well with mongo and would make this situation a lot easier to deal with especially in terms of load times.