mirror of
https://gitlab.com/phoenix-dvpmt/mmocore.git
synced 2025-11-18 06:24:17 +01:00
Fixed force-class-selection thread safety
This commit is contained in:
parent
a688ed32ed
commit
60b958f986
@ -186,7 +186,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>fr.phoenixdevt</groupId>
|
<groupId>fr.phoenixdevt</groupId>
|
||||||
<artifactId>Profile-API</artifactId>
|
<artifactId>Profile-API</artifactId>
|
||||||
<version>1.2</version>
|
<version>1.2-SNAPSHOT</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|||||||
@ -68,6 +68,7 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@ -220,9 +221,36 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
|
|||||||
this.getStats().updateStats();
|
this.getStats().updateStats();
|
||||||
PartyUtils.resolvePartyBonuses(this); // In case buffs not removed on logoff
|
PartyUtils.resolvePartyBonuses(this); // In case buffs not removed on logoff
|
||||||
|
|
||||||
|
tryForceClassSelection(); // Force class selection
|
||||||
|
|
||||||
getMMOPlayerData().getProfileSession().addOpenCallback(session -> this.onProfileSessionReady());
|
getMMOPlayerData().getProfileSession().addOpenCallback(session -> this.onProfileSessionReady());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//region Force class selection
|
||||||
|
|
||||||
|
private Runnable bufferedForcedClassSelectionCallback;
|
||||||
|
private final AtomicBoolean bufferedForcedClassSelection = new AtomicBoolean(false);
|
||||||
|
|
||||||
|
private void tryForceClassSelection() {
|
||||||
|
final var canOpen = this.bufferedForcedClassSelection.getAndSet(true);
|
||||||
|
// Useless to check if `forceClassSelect` is enabled, it must be if `canOpen` is `true`
|
||||||
|
if (canOpen) {
|
||||||
|
this.bufferedForcedClassSelectionCallback.run();
|
||||||
|
this.bufferedForcedClassSelectionCallback = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void bufferForceClassSelection(@NotNull Runnable callback) {
|
||||||
|
this.bufferedForcedClassSelectionCallback = callback;
|
||||||
|
final var canOpen = this.bufferedForcedClassSelection.getAndSet(true);
|
||||||
|
if (canOpen) {
|
||||||
|
this.bufferedForcedClassSelectionCallback.run();
|
||||||
|
this.bufferedForcedClassSelectionCallback = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
private void castOnLoginScripts() {
|
private void castOnLoginScripts() {
|
||||||
|
|
||||||
// Class Skills
|
// Class Skills
|
||||||
@ -499,7 +527,7 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @return If the item is unlocked by the player
|
* @return If the item is unlocked by the player
|
||||||
* This is used for skills that can be locked & unlocked.
|
* This is used for skills that can be locked & unlocked.
|
||||||
*/
|
*/
|
||||||
public boolean hasUnlocked(Unlockable unlockable) {
|
public boolean hasUnlocked(Unlockable unlockable) {
|
||||||
return unlockable.isUnlockedByDefault() || unlockedItems.contains(unlockable.getUnlockNamespacedKey());
|
return unlockable.isUnlockedByDefault() || unlockedItems.contains(unlockable.getUnlockNamespacedKey());
|
||||||
@ -673,7 +701,7 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
|
|||||||
/**
|
/**
|
||||||
* @param key The identifier of an exp table item.
|
* @param key The identifier of an exp table item.
|
||||||
* @return Amount of times an item has been claimed
|
* @return Amount of times an item has been claimed
|
||||||
* inside an experience table.
|
* inside an experience table.
|
||||||
*/
|
*/
|
||||||
public int getClaims(@NotNull String key) {
|
public int getClaims(@NotNull String key) {
|
||||||
return tableItemClaims.getOrDefault(key, 0);
|
return tableItemClaims.getOrDefault(key, 0);
|
||||||
@ -1138,7 +1166,7 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @return If the PlayerEnterCastingModeEvent successfully put the player
|
* @return If the PlayerEnterCastingModeEvent successfully put the player
|
||||||
* into casting mode, otherwise if the event is cancelled, returns false.
|
* into casting mode, otherwise if the event is cancelled, returns false.
|
||||||
*/
|
*/
|
||||||
public boolean setSkillCasting() {
|
public boolean setSkillCasting() {
|
||||||
Validate.isTrue(!isCasting(), "Player already in casting mode");
|
Validate.isTrue(!isCasting(), "Player already in casting mode");
|
||||||
@ -1157,7 +1185,7 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @return If player successfully left skill casting i.e the Bukkit
|
* @return If player successfully left skill casting i.e the Bukkit
|
||||||
* event has not been cancelled
|
* event has not been cancelled
|
||||||
*/
|
*/
|
||||||
public boolean leaveSkillCasting() {
|
public boolean leaveSkillCasting() {
|
||||||
return leaveSkillCasting(false);
|
return leaveSkillCasting(false);
|
||||||
@ -1166,7 +1194,7 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
|
|||||||
/**
|
/**
|
||||||
* @param skipEvent Skip firing the exit event
|
* @param skipEvent Skip firing the exit event
|
||||||
* @return If player successfully left skill casting i.e the Bukkit
|
* @return If player successfully left skill casting i.e the Bukkit
|
||||||
* event has not been cancelled
|
* event has not been cancelled
|
||||||
*/
|
*/
|
||||||
public boolean leaveSkillCasting(boolean skipEvent) {
|
public boolean leaveSkillCasting(boolean skipEvent) {
|
||||||
Validate.isTrue(isCasting(), "Player not in casting mode");
|
Validate.isTrue(isCasting(), "Player not in casting mode");
|
||||||
@ -1554,7 +1582,7 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
|
|||||||
* checks if they could potentially upgrade to one of these
|
* checks if they could potentially upgrade to one of these
|
||||||
*
|
*
|
||||||
* @return If the player can change its current class to
|
* @return If the player can change its current class to
|
||||||
* a subclass
|
* a subclass
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public boolean canChooseSubclass() {
|
public boolean canChooseSubclass() {
|
||||||
|
|||||||
@ -7,11 +7,11 @@ import fr.phoenixdevt.profiles.event.ProfileRemoveEvent;
|
|||||||
import fr.phoenixdevt.profiles.event.ProfileSelectEvent;
|
import fr.phoenixdevt.profiles.event.ProfileSelectEvent;
|
||||||
import fr.phoenixdevt.profiles.event.ProfileUnloadEvent;
|
import fr.phoenixdevt.profiles.event.ProfileUnloadEvent;
|
||||||
import io.lumine.mythic.lib.MythicLib;
|
import io.lumine.mythic.lib.MythicLib;
|
||||||
import io.lumine.mythic.lib.api.event.SynchronizedDataLoadEvent;
|
|
||||||
import io.lumine.mythic.lib.comp.profile.ProfileMode;
|
import io.lumine.mythic.lib.comp.profile.ProfileMode;
|
||||||
import io.lumine.mythic.lib.util.lang3.Validate;
|
import io.lumine.mythic.lib.util.lang3.Validate;
|
||||||
import net.Indyuce.mmocore.MMOCore;
|
import net.Indyuce.mmocore.MMOCore;
|
||||||
import net.Indyuce.mmocore.api.player.PlayerData;
|
import net.Indyuce.mmocore.api.player.PlayerData;
|
||||||
|
import net.Indyuce.mmocore.api.player.profess.ClassOption;
|
||||||
import net.Indyuce.mmocore.manager.InventoryManager;
|
import net.Indyuce.mmocore.manager.InventoryManager;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.NamespacedKey;
|
import org.bukkit.NamespacedKey;
|
||||||
@ -47,7 +47,7 @@ public class ForceClassProfileDataModule implements ProfileDataModule {
|
|||||||
@EventHandler
|
@EventHandler
|
||||||
public void onProfileCreate(ProfileCreateEvent event) {
|
public void onProfileCreate(ProfileCreateEvent event) {
|
||||||
|
|
||||||
// Proxy-based profiles
|
// Will be prompted on profile application in proxy-mode
|
||||||
if (MythicLib.plugin.getProfileMode() == ProfileMode.PROXY) {
|
if (MythicLib.plugin.getProfileMode() == ProfileMode.PROXY) {
|
||||||
event.validate(this);
|
event.validate(this);
|
||||||
return;
|
return;
|
||||||
@ -57,30 +57,14 @@ public class ForceClassProfileDataModule implements ProfileDataModule {
|
|||||||
InventoryManager.CLASS_SELECT.newInventory(playerData, () -> event.validate(this)).open();
|
InventoryManager.CLASS_SELECT.newInventory(playerData, () -> event.validate(this)).open();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Force class before profile selection once MMOCore loaded its data
|
|
||||||
*/
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onDataLoad(SynchronizedDataLoadEvent event) {
|
public void onProfileApply(ProfileSelectEvent event) {
|
||||||
if (event.getManager().getOwningPlugin().equals(MMOCore.plugin)) {
|
final var playerData = PlayerData.get(event.getPlayerData().getPlayer());
|
||||||
final PlayerData playerData = (PlayerData) event.getHolder();
|
playerData.bufferForceClassSelection(() -> {
|
||||||
|
if (playerData.getProfess().hasOption(ClassOption.DEFAULT))
|
||||||
// Proxy-based profiles
|
InventoryManager.CLASS_SELECT.newInventory(playerData, () -> event.validate(this)).open();
|
||||||
if (!event.hasProfileEvent()) {
|
else event.validate(this);
|
||||||
Validate.isTrue(MythicLib.plugin.getProfileMode() == ProfileMode.PROXY, "Listened to a data load event with no profile event attached but proxy-based profiles are disabled");
|
});
|
||||||
if (playerData.getProfess().equals(MMOCore.plugin.classManager.getDefaultClass()))
|
|
||||||
InventoryManager.CLASS_SELECT.newInventory(playerData, () -> event.getHolder().getMMOPlayerData().getProfileSession().markAsReady(this.key)).open();
|
|
||||||
else event.getHolder().getMMOPlayerData().getProfileSession().markAsReady(this.key);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final ProfileSelectEvent event1 = (ProfileSelectEvent) event.getProfileEvent();
|
|
||||||
|
|
||||||
// Validate if necessary
|
|
||||||
if (playerData.getProfess().equals(MMOCore.plugin.classManager.getDefaultClass()))
|
|
||||||
InventoryManager.CLASS_SELECT.newInventory(playerData, () -> event1.validate(this)).open();
|
|
||||||
else event1.validate(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
|
|||||||
@ -23,8 +23,9 @@ import java.util.List;
|
|||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
public class ConfigManager {
|
public class ConfigManager {
|
||||||
public boolean overrideVanillaExp, canCreativeCast, passiveSkillsNeedBinding, cobbleGeneratorXP, saveDefaultClassInfo, splitMainExp, splitProfessionExp, disableQuestBossBar,
|
public boolean overrideVanillaExp, canCreativeCast, passiveSkillsNeedBinding, cobbleGeneratorXP, saveDefaultClassInfo,
|
||||||
pvpModeEnabled, pvpModeInvulnerabilityCanDamage, forceClassSelection, enableGlobalSkillTreeGUI, enableSpecificSkillTreeGUI, waypointAutoPathCalculation, waypointLinkReciprocity;
|
splitMainExp, splitProfessionExp, disableQuestBossBar, pvpModeEnabled, pvpModeInvulnerabilityCanDamage, forceClassSelection,
|
||||||
|
enableGlobalSkillTreeGUI, enableSpecificSkillTreeGUI, waypointAutoPathCalculation, waypointLinkReciprocity;
|
||||||
public String partyChatPrefix, noSkillBoundPlaceholder;
|
public String partyChatPrefix, noSkillBoundPlaceholder;
|
||||||
public ChatColor staminaFull, staminaHalf, staminaEmpty;
|
public ChatColor staminaFull, staminaHalf, staminaEmpty;
|
||||||
public long combatLogTimer, lootChestExpireTime, lootChestPlayerCooldown, globalSkillCooldown;
|
public long combatLogTimer, lootChestExpireTime, lootChestPlayerCooldown, globalSkillCooldown;
|
||||||
|
|||||||
@ -31,7 +31,7 @@ public class MMOCoreBukkit {
|
|||||||
if (plugin.getConfig().getBoolean("vanilla-exp-redirection.enabled"))
|
if (plugin.getConfig().getBoolean("vanilla-exp-redirection.enabled"))
|
||||||
Bukkit.getPluginManager().registerEvents(new RedirectVanillaExp(plugin.getConfig().getDouble("vanilla-exp-redirection.ratio")), plugin);
|
Bukkit.getPluginManager().registerEvents(new RedirectVanillaExp(plugin.getConfig().getDouble("vanilla-exp-redirection.ratio")), plugin);
|
||||||
|
|
||||||
if (plugin.getConfig().getBoolean("force-class-selection") && MythicLib.plugin.hasProfiles())
|
if (plugin.configManager.forceClassSelection && MythicLib.plugin.hasProfiles())
|
||||||
new ForceClassProfileDataModule();
|
new ForceClassProfileDataModule();
|
||||||
|
|
||||||
Bukkit.getPluginManager().registerEvents(new WaypointsListener(), plugin);
|
Bukkit.getPluginManager().registerEvents(new WaypointsListener(), plugin);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user