#The type of actions you’re storing
1 messages · Page 1 of 1 (latest)
I'm essentially just making a generic variable counter plugin our server uses - it's the simplest solution to our problem of storing custom-statistics about players without needing to come up with a storage-strategy for each statistic.
E.g.:
EASY_POT_BREWS(custom potions plugin, doesn't use default brewing stands or call default potion brewing events)EASY_POT_BREW_NAMEKILL_CUSTOM_MOBATTEND_CLASS_ABOUT_POT_NAMEDISMOUNT_BROOM
etc etc.
Essentially each player has a map of string=int with different string keys we want to track information about.
Currently we store it in a fork of a plugin called HuskSync (which we bought & with the authors permission). HuskSync syncs player data (inventory, health, advancements - only in-game stored things) across multiple BungeeCord servers.
I've forked the plugin to also store our custom variable_counter data (a map of string=int for each player).
We store it terribly in a column called variable_counter along side all their other HuskSync stored data: https://github.com/Potterverse/HuskSync/blob/master/common/src/main/java/me/william278/husksync/proxy/data/sql/MySQL.java#L45
And we "serialize" this map into a string poorly too: https://github.com/Potterverse/HuskSync/blob/master/api/src/main/java/me/william278/husksync/bukkit/data/DataSerializer.java#L28
.
Wow I just wrote a whole ass essay in response and Discord just deleted it and made the thread
I would suggest you cache the stats locally and save them on disconnect/server swap
Also
I hate that storage method
Lmao
It’s awful
which one
Where you serialize it all into one glob
oh wait do you see my msg????
i can't see it i thought discord deleted it i was just retyping it lol
Yeah it’s there
tl;dr:
- We want to store a map of
String, Integerfor each player. - The String is a custom "stat" we want to track related to our server, e.g. potions_brewed or whatever. Sometimes there are more ideal solutions to tracking these stats and we could group them as some of the keys are related - but we don't have the time.
- We currently do this through a fork of HuskSync. HuskSync is a premium resource (we paid for) and we have forked to store our
String, Integerfor each player. - This way the plugin takes care of loading the stats on join and saving them on quit for us - it uses redis messaging, etc.
- Our fork stores in HuskSync by converting the
String, Integermap into a string ofkey=value,key=valueand then storing this in an extra column with other HuskSync data: https://github.com/Potterverse/HuskSync/blob/master/common/src/main/java/me/william278/husksync/proxy/data/sql/MySQL.java#L45
This strategy isn't sustainable as we don't have the time to continually rebase on HuskSync's changes & so I'm looking at how we can make it independent.
Obviously the ideal solution is caching and loading like they do ^ (their Redis messaging system makes up for the fact that onJoin is called on the new server before onQuit on the current server - which makes loading on Join and saving on disconnect a bit more difficult in practice), but we don't have tons of time to develop/maintain the system.
So essentially just looking to take the storing of our String, Integer map about each player into a different plugin
You should make a separate table for this
well that's what I just retyped
yes ideally if we had the time to do it we'd even make related data into their own table. e.g. easy_potion_id, easy potion, year - and then for individual players we can just say easy_potion_id, number_of_times_brewed
but we don't have time so we took the low maintenance approach of instead storing easy_potion_name, number_of_times_brewed and potion_year, number_of_times_brewed
i know what the ideal solution is - but i also know we don't have time to develop it - so this is the next best (subsequently, worse) thing
I would argue you’re going to spend more time in the long run trying to make this Frankenstein storage system work than you would doing it properly in the first place
the problem with the current system is that sometimes stats reset for a reason we haven't been able to track down (using the husksync fork) - but data like inventory/etc is unaffected (as it's also saved in game and not just in maps and the table)
Can I tell you why you’re experiencing data loss?
It’s a race condition accentuated by the fact that you’re storing it all in one column
why would that lead to the entire row in the husksync DB being deleted?
The whole row is gone?
yeah
but the other data - e.g. inventory/stats isn't affected, because the server also stores them
so it's just our variablecounter data which is stored in the row and the map in the plug which is lost
even tho the entire row is deleted
Well of course inventory isn’t, totally separate system
ye but we store the inventory in the same table on the same row
Are you sure the row existed to begin with?
ye
Wait what
If the inventory isn’t lost then the row isn’t lost
If the inventory is in the row
Explain
Right
and redis messaging handles the whole onjoin being called before onquit
Sure
sometimes - with no particular reason that we've been able to find - the row is deleted
but the inventory is correct
location unaffected
health etc is correct
but variable_counter is deleted
when i say is correct
So the row isn’t deleted, the variable_counter is
i mean it loaded before the row deleted
no if you look at the table
the row is gone
not that i'm aware of
i appreciate that you're trying to help and that you're not able to validate anything of what i'm saying btw, i promise that what i'm saying is accurate to the best of my ability and i like to think im fairly competent
How do you interface with the table
oh it's all on that github
yeah im pretty sure everything that wants to interact with DB goes through that class
also yes i'm aware we're 43 commits behind HuskSync master - but that's part of the reason I'm trying to abstract this string=integer data storage into it's own plugin
just no time to maintain
How confident are you that the row exists prior to them logging in and it isn’t just them having saved minecraft player data
Since you said the stats are empty
very because if that was the case the inventory wouldn't sync between the two servers but it does
when i say stats i mean variable_counter
by being a fork of husksync we get the added benefit of loading into redis and saving onto redis and handles all the issues of onjoin and onquit order
but variablecounter data keeps resetting for players (it's related to restarts/crashes - so it's not entirely random)
our current solution is kick players from the husksync servers 45 seconds before we restart
and that's stopped the variable counter data being lost
but when it crashes, the variable counter data for online players is lost
it doesn't crash often - once every few months - but still
new row is generated
Can you consistently reproduce this
i haven't been able to get a step-by-step do this and this will cause it
if i had then i probably would've been able to fix it by now
But can you reproduce it
yea
it's related to restarts/crashes
whenever one of them happens variable_counter data could be lost
for online players*
Well that seems like you just aren’t saving it and it’s being cleared on login or something
I'm thinking that too but I swear I cleared that being a potential problem months ago
I'm double checking now to make sure my memory isn't failing me
And this is on mysql?
i can't see this happening
@granite panther what happens if their row vanishes and then they swap servers
no idea
I think I may know what your issue is
The only data being lost is your new custom addition right?
The rest is all preserved?
I suspect the Husk code is doing it intentionally and has a mechanism for caching it’s own stock data in Redis that you haven’t updated to also preserve your custom data
why would that only happen in the event of players online in restart/crash
I’m not familiar enough with the husk plugin to know exactly where that is, but that’s my suspicion as to what is happening
Because your server that has the state is going down before it has an opportunity to save it
That’s the only explanation for what’s happening
Redis msg sent with player's uuid: https://github.com/Potterverse/HuskSync/blob/master/bungeecord/src/main/java/me/william278/husksync/bungeecord/listener/BungeeEventListener.java#L40
Redis msg sent with PlayerData object: https://github.com/Potterverse/HuskSync/blob/master/bungeecord/src/main/java/me/william278/husksync/bungeecord/listener/BungeeRedisListener.java#L72
PlayerData object updated to contain my custom var:
https://github.com/Potterverse/HuskSync/blob/master/common/src/main/java/me/william278/husksync/PlayerData.java#L49
redis classes:
https://github.com/Potterverse/HuskSync/blob/master/common/src/main/java/me/william278/husksync/redis/RedisMessage.java
https://github.com/Potterverse/HuskSync/blob/master/common/src/main/java/me/william278/husksync/redis/RedisListener.java
doesn't contain word "redis":
https://github.com/Potterverse/HuskSync/blob/master/common/src/main/java/me/william278/husksync/proxy/data/DataManager.java
as much as i would love for the explanation to be that simple, it doesn't appear to be 😦
there are 100,000 possibilities here with the amount of states being managed and message being sent
this is why i just want to make the storing of String=Integer map independent, but then I either have to just suck up the potential of 100 update/select SQL statements being called a second (unlikely, but possible) or implement my own system of caching to fix handling onjoin vs onquit order