[Kernel] Let XGIUserWriteAchievements unlock achievements
XGIUserWriteAchievements seems to be the main (only?) way achievements are unlocked, when used that'll now try getting the GPD from UserProfile and unlock the achievements passed to it. Dash GPD info is recalced and GPDs get written to disk whenever achievements are unlocked, letting achievements persist across instances. TODO: - "Achievement Unlocked!" UI, writing to log isn't much of an indicator :P - XamUserCreateAchievementEnumerator, needs to return XACHIEVEMENT_DETAILS structs, which also contain pointers to strings in guest memory... - Copy over more data from SPA? (need to check what data 360 copies to it) - Optimize GPD writing, atm every GPD gets rewritten even if it hasn't been changed... - Change profile folder path? Maybe allow using 360 profiles eventually? - GPD settings
This commit is contained in:
parent
2a5ab07024
commit
8368e8ce06
|
@ -17,6 +17,11 @@ namespace kernel {
|
|||
namespace xam {
|
||||
namespace apps {
|
||||
|
||||
struct X_XUSER_ACHIEVEMENT {
|
||||
xe::be<uint32_t> user_idx;
|
||||
xe::be<uint32_t> achievement_id;
|
||||
};
|
||||
|
||||
XgiApp::XgiApp(KernelState* kernel_state) : App(kernel_state, 0xFB) {}
|
||||
|
||||
// http://mb.mirage.org/bugzilla/xliveless/main.c
|
||||
|
@ -55,6 +60,32 @@ X_RESULT XgiApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr,
|
|||
uint32_t achievements_ptr = xe::load_and_swap<uint32_t>(buffer + 4);
|
||||
XELOGD("XGIUserWriteAchievements(%.8X, %.8X)", achievement_count,
|
||||
achievements_ptr);
|
||||
|
||||
auto* game_gpd = kernel_state_->user_profile()->GetTitleGpd();
|
||||
if (!game_gpd) {
|
||||
XELOGE("XGIUserWriteAchievements failed, no game GPD set?");
|
||||
return X_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
bool modified = false;
|
||||
auto* achievement =
|
||||
(X_XUSER_ACHIEVEMENT*)memory_->TranslateVirtual(achievements_ptr);
|
||||
for (uint32_t i = 0; i < achievement_count; i++) {
|
||||
util::XdbfAchievement ach;
|
||||
if (game_gpd->GetAchievement(achievement->achievement_id, &ach)) {
|
||||
if (!ach.IsUnlocked()) {
|
||||
XELOGI("Achievement Unlocked! %ws (%d gamerscore) - %ws",
|
||||
ach.label.c_str(), ach.gamerscore, ach.description.c_str());
|
||||
ach.Unlock(false);
|
||||
game_gpd->UpdateAchievement(ach);
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (modified) {
|
||||
kernel_state_->user_profile()->UpdateGpdFiles();
|
||||
}
|
||||
|
||||
return X_ERROR_SUCCESS;
|
||||
}
|
||||
case 0x000B0010: {
|
||||
|
|
Loading…
Reference in New Issue