mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-28 10:01:58 +00:00
## About The Pull Request the verb is achievements-admin-panel ## Why It's Good For The Game tells the admin what to actually type ## Changelog 🆑 spellcheck: fixed a typo in the admin message about achievements cleanup /🆑
137 lines
4.8 KiB
Plaintext
137 lines
4.8 KiB
Plaintext
SUBSYSTEM_DEF(achievements)
|
|
name = "Achievements"
|
|
flags = SS_NO_FIRE
|
|
var/achievements_enabled = FALSE
|
|
|
|
///List of achievements
|
|
var/list/datum/award/achievement/achievements = list()
|
|
///The achievement with the highest amount of players that have unlocked it.
|
|
var/datum/award/achievement/most_unlocked_achievement
|
|
///List of scores
|
|
var/list/datum/award/score/scores = list()
|
|
///List of all awards
|
|
var/list/datum/award/awards = list()
|
|
|
|
/datum/controller/subsystem/achievements/Initialize()
|
|
if(!SSdbcore.Connect())
|
|
return SS_INIT_NO_NEED
|
|
achievements_enabled = TRUE
|
|
|
|
var/list/achievements_by_db_id = list()
|
|
for(var/datum/award/achievement/achievement as anything in subtypesof(/datum/award/achievement))
|
|
if(!initial(achievement.database_id)) // abstract type
|
|
continue
|
|
var/datum/award/achievement/instance = new achievement
|
|
achievements[achievement] = instance
|
|
awards[achievement] = instance
|
|
achievements_by_db_id[instance.database_id] = instance
|
|
|
|
for(var/datum/award/score/score as anything in subtypesof(/datum/award/score))
|
|
if(!initial(score.database_id)) // abstract type
|
|
continue
|
|
var/instance = new score
|
|
scores[score] = instance
|
|
awards[score] = instance
|
|
|
|
update_metadata()
|
|
|
|
/**
|
|
* Count how many (unlocked) achievements are in the achievements database
|
|
* then store that amount in the times_achieved variable for each achievement.
|
|
*
|
|
* Thanks to Jordie for the query.
|
|
*/
|
|
var/datum/db_query/query = SSdbcore.NewQuery(
|
|
"SELECT a.achievement_key, COUNT(a.achievement_key) AS count FROM achievements a \
|
|
JOIN achievement_metadata m ON a.achievement_key = m.achievement_key AND m.achievement_type = 'achievement' \
|
|
GROUP BY a.achievement_key ORDER BY count DESC"
|
|
)
|
|
if(query.Execute(async = TRUE))
|
|
while(query.NextRow())
|
|
var/id = query.item[1]
|
|
var/datum/award/achievement/instance = id ? achievements_by_db_id[id] : null
|
|
if(isnull(instance)) // removed achievement
|
|
continue
|
|
instance.times_achieved = query.item[2]
|
|
// the results are ordered in descending orders, so the first in the list should be the most unlocked one.
|
|
if(!most_unlocked_achievement)
|
|
most_unlocked_achievement = instance
|
|
qdel(query)
|
|
|
|
for(var/client/C in GLOB.clients)
|
|
if(!C.persistent_client.achievements.initialized)
|
|
C.persistent_client.achievements.InitializeData()
|
|
|
|
return SS_INIT_SUCCESS
|
|
|
|
/datum/controller/subsystem/achievements/Shutdown()
|
|
save_achievements_to_db()
|
|
|
|
/datum/controller/subsystem/achievements/proc/save_achievements_to_db()
|
|
var/list/cheevos_to_save = list()
|
|
for(var/ckey in GLOB.persistent_clients_by_ckey)
|
|
var/datum/persistent_client/PD = GLOB.persistent_clients_by_ckey[ckey]
|
|
if(!PD || !PD.achievements)
|
|
continue
|
|
cheevos_to_save += PD.achievements.get_changed_data()
|
|
|
|
if(!length(cheevos_to_save))
|
|
return
|
|
SSdbcore.MassInsert(format_table_name("achievements"), cheevos_to_save, duplicate_key = TRUE)
|
|
SEND_SIGNAL(src, COMSIG_ACHIEVEMENTS_SAVED_TO_DB)
|
|
|
|
//Update the metadata if any are behind
|
|
/datum/controller/subsystem/achievements/proc/update_metadata()
|
|
var/list/current_metadata = list()
|
|
//select metadata here
|
|
var/datum/db_query/Q = SSdbcore.NewQuery("SELECT achievement_key,achievement_version FROM [format_table_name("achievement_metadata")]")
|
|
if(!Q.Execute(async = TRUE))
|
|
qdel(Q)
|
|
return
|
|
else
|
|
while(Q.NextRow())
|
|
current_metadata[Q.item[1]] = text2num(Q.item[2])
|
|
qdel(Q)
|
|
|
|
var/list/to_update = list()
|
|
for(var/T in awards)
|
|
var/datum/award/A = awards[T]
|
|
if(!current_metadata[A.database_id] || current_metadata[A.database_id] < A.achievement_version)
|
|
to_update += list(A.get_metadata_row())
|
|
|
|
if(to_update.len)
|
|
SSdbcore.MassInsert(format_table_name("achievement_metadata"),to_update,duplicate_key = TRUE)
|
|
|
|
var/list/orphaned_keys = get_orphaned_keys(FALSE)
|
|
if(orphaned_keys.len)
|
|
message_admins("Achievement metadata found without matching achievement, use Achievements-Admin-Panel verb to cleanup if necessary")
|
|
|
|
/// returns list of metadata keys and versions in db with no matching achievement datum, either deleted achievements, or from server with code ahead of us.
|
|
/datum/controller/subsystem/achievements/proc/get_orphaned_keys(include_archived = TRUE)
|
|
. = list()
|
|
var/list/current_metadata = list()
|
|
// Fetch all keys from the db
|
|
var/datum/db_query/Q = SSdbcore.NewQuery("SELECT achievement_key,achievement_version FROM [format_table_name("achievement_metadata")]")
|
|
if(!Q.Execute(async = TRUE))
|
|
qdel(Q)
|
|
return
|
|
else
|
|
while(Q.NextRow())
|
|
current_metadata[Q.item[1]] = Q.item[2]
|
|
qdel(Q)
|
|
|
|
var/list/achievements_by_db_id = list()
|
|
for(var/datum/award/award as anything in subtypesof(/datum/award))
|
|
if(!initial(award.database_id)) // abstract type
|
|
continue
|
|
achievements_by_db_id[award.database_id] = TRUE
|
|
|
|
for(var/key in current_metadata)
|
|
if(achievements_by_db_id[key])
|
|
continue
|
|
if(!include_archived && current_metadata[key] == ACHIEVEMENT_ARCHIVED_VERSION)
|
|
continue
|
|
.[key] = current_metadata[key]
|
|
|
|
|