Harden slot switching against stale saves

This commit is contained in:
Kam committed 2025-10-12 20:38:02 -04:00
1 parent 460a1c5ef9
commit 45cae9b064
1 file changed
+24 -7
@@ -518,9 +518,12 @@ public class ProfileController implements IProfileHandler {
if (EventHooks.onProfileChange(handler, scriptPlayer, profile, newSlotId, prevSlot, false))
return ProfileOperation.error(MSG_CANCELLED);
// Persist the outgoing slot using its original id. Previously we relied on
// profile.currentSlotId inside saveSlotData, but scripts firing during the
// transition could change the active slot before the save completed and
// overwrite the destination slot with stale data.
saveSlotData(profile.player, profile, prevSlot);
profile.currentSlotId = newSlotId;
loadSlotData(profile.player);
loadSlotData(profile.player, profile, newSlotId);
EventHooks.onProfileChange(handler, scriptPlayer, profile, newSlotId, prevSlot, true);
} else {
@@ -651,11 +654,11 @@ public class ProfileController implements IProfileHandler {
saveSlotData(player, profile, profile.getCurrentSlotId());
}
public void loadSlotData(EntityPlayer player) {
if (player == null || !activeProfiles.containsKey(player.getUniqueID()))
private void loadSlotData(EntityPlayer player, Profile profile, int slotId) {
if (player == null || profile == null)
return;
Profile profile = activeProfiles.get(player.getUniqueID());
ISlot slot = profile.getSlots().get(profile.getCurrentSlotId());
ISlot slot = profile.getSlots().get(slotId);
if (slot == null)
return;
@@ -671,14 +674,28 @@ public class ProfileController implements IProfileHandler {
profileData.save(player);
}
// Only flip the active slot after the player's live data matches the
// requested slot. This way, any additional saveSlotData() calls triggered by
// scripts during the load can't persist stale information to the new slot.
profile.currentSlotId = slotId;
PlayerData pdata = PlayerData.get(player);
pdata.profileSlot = profile.getCurrentSlotId();
pdata.profileSlot = slotId;
pdata.save();
if (ConfigMain.AttributesEnabled)
AttributeController.getTracker(player).recalcAttributes(player);
}
public void loadSlotData(EntityPlayer player) {
if (player == null || !activeProfiles.containsKey(player.getUniqueID()))
return;
Profile profile = activeProfiles.get(player.getUniqueID());
// Delay flipping profile.currentSlotId until after the data for the target slot
// has been restored to the player so other saves observe consistent state.
loadSlotData(player, profile, profile.getCurrentSlotId());
}
public List<ProfileInfoEntry> getProfileInfo(EntityPlayer player, int slotId) {
List<ProfileInfoEntry> infoList = new ArrayList<>();
Profile profile = getProfile(player);