Skip to content

Commit

Permalink
Optimize stat correctors to use less threads and player schedulers; A…
Browse files Browse the repository at this point in the history
…dd EcoSkills as supported stat provider?
  • Loading branch information
ErikSzabo committed Sep 29, 2024
1 parent 7067ab0 commit 3cee880
Show file tree
Hide file tree
Showing 12 changed files with 290 additions and 137 deletions.
5 changes: 4 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ plugins {
}

group = "gg.auroramc"
version = "1.5.3"
version = "1.5.4-SNAPSHOT"

java.sourceCompatibility = JavaVersion.VERSION_21
java.targetCompatibility = JavaVersion.VERSION_21
Expand All @@ -33,6 +33,7 @@ repositories {
maven("https://mvn.lumine.io/repository/maven-public/")
maven("https://nexus.phoenixdevt.fr/repository/maven-public/")
maven("https://maven.enginehub.org/repo/")
maven("https://repo.auxilor.io/repository/maven-public/")
}

dependencies {
Expand All @@ -43,6 +44,8 @@ dependencies {
compileOnly("io.lumine:Mythic-Dist:5.6.1")
compileOnly("io.lumine:MythicLib-dist:1.6.2-SNAPSHOT")
compileOnly("com.sk89q.worldguard:worldguard-bukkit:7.0.7")
compileOnly("com.willfp:eco:6.73.0")
compileOnly("com.willfp:EcoSkills:3.59.7")

implementation("co.aikar:acf-paper:0.5.1-SNAPSHOT")

Expand Down
5 changes: 4 additions & 1 deletion src/main/java/gg/auroramc/levels/AuroraLevels.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;

import java.util.concurrent.CompletableFuture;

public class AuroraLevels extends JavaPlugin {
@Getter
private PlayerLeveler leveler;
Expand Down Expand Up @@ -74,7 +76,8 @@ public void reload() {
commandManager.reload();
leveler.reload(false);

Bukkit.getOnlinePlayers().forEach(player -> leveler.getRewardAutoCorrector().correctRewards(player));
Bukkit.getOnlinePlayers().forEach(player ->
CompletableFuture.runAsync(() -> leveler.getRewardAutoCorrector().correctRewards(player)));
}

@Override
Expand Down
1 change: 1 addition & 0 deletions src/main/java/gg/auroramc/levels/hooks/Hooks.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
@Getter
public enum Hooks {
AURA_SKILLS(AuraSkillsHook.class, "AuraSkills"),
ECO_SKILLS(AuraSkillsHook.class, "EcoSkills"),
LUCK_PERMS(LuckPermsHook.class, "LuckPerms"),
MYTHIC_MOBS(MythicHook.class, "MythicMobs"),
WORLD_GUARD(WorldguardHook.class, "WorldGuard"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,9 @@
import dev.aurelium.auraskills.api.stat.StatModifier;
import gg.auroramc.aurora.api.reward.RewardCorrector;
import gg.auroramc.levels.AuroraLevels;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;

import java.util.Map;
import java.util.concurrent.CompletableFuture;

public class AuraSkillsCorrector implements RewardCorrector {
private final AuroraLevels plugin;
Expand All @@ -21,50 +19,49 @@ public AuraSkillsCorrector(AuroraLevels plugin) {

@Override
public void correctRewards(Player player) {
CompletableFuture.runAsync(() -> {
var leveler = plugin.getLeveler();
var data = leveler.getUserData(player);
var level = data.getLevel();
var leveler = plugin.getLeveler();
var data = leveler.getUserData(player);
var level = data.getLevel();

Map<Stat, Double> statMap = Maps.newHashMap();
Map<Stat, Double> statMap = Maps.newHashMap();

// Reset all stat modifiers first
for (var stat : AuraSkillsApi.get().getGlobalRegistry().getStats()) {
statMap.put(stat, 0.0);
}
// Reset all stat modifiers first
for (var stat : AuraSkillsApi.get().getGlobalRegistry().getStats()) {
statMap.put(stat, 0.0);
}

// Gather new stat modifiers
for (int i = 1; i < level + 1; i++) {
var matcher = leveler.getLevelMatcher().getBestMatcher(i);
if (matcher == null) continue;
var formulaPlaceholders = leveler.getRewardFormulaPlaceholders(player, i);
for (var reward : matcher.computeRewards(i)) {
if (reward instanceof AuraSkillsStatReward statReward) {
statMap.merge(statReward.getStat(), statReward.getValue(formulaPlaceholders), Double::sum);
}
// Gather new stat modifiers
for (int i = 1; i < level + 1; i++) {
var matcher = leveler.getLevelMatcher().getBestMatcher(i);
if (matcher == null) continue;
var formulaPlaceholders = leveler.getRewardFormulaPlaceholders(player, i);
for (var reward : matcher.computeRewards(i)) {
if (reward instanceof AuraSkillsStatReward statReward) {
statMap.merge(statReward.getStat(), statReward.getValue(formulaPlaceholders), Double::sum);
}
}
}

// I'm not sure if it's safe to call AuraSkills apis async, so lets just run it on the main thread
Bukkit.getGlobalRegionScheduler().run(plugin, (task) -> {
// Apply the new stat modifiers
for (var entry : statMap.entrySet()) {
var statKey = AuraSkillsStatReward.getAURA_SKILLS_STAT() + entry.getKey().getId().toString();
var user = AuraSkillsApi.get().getUser(player.getUniqueId());
if (!player.isOnline()) return;

var oldModifier = user.getStatModifier(statKey);
player.getScheduler().run(plugin, (task) -> {
// Apply the new stat modifiers
for (var entry : statMap.entrySet()) {
var statKey = AuraSkillsStatReward.getAURA_SKILLS_STAT() + entry.getKey().getId().toString();
var user = AuraSkillsApi.get().getUser(player.getUniqueId());

if (oldModifier == null) {
if (entry.getValue() > 0) {
user.addStatModifier(new StatModifier(statKey, entry.getKey(), entry.getValue()));
}
} else if (entry.getValue() <= 0) {
user.removeStatModifier(statKey);
} else if (entry.getValue() != oldModifier.value()) {
var oldModifier = user.getStatModifier(statKey);

if (oldModifier == null) {
if (entry.getValue() > 0) {
user.addStatModifier(new StatModifier(statKey, entry.getKey(), entry.getValue()));
}
} else if (entry.getValue() <= 0) {
user.removeStatModifier(statKey);
} else if (entry.getValue() != oldModifier.value()) {
user.addStatModifier(new StatModifier(statKey, entry.getKey(), entry.getValue()));
}
});
});
}
}, null);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package gg.auroramc.levels.hooks.ecoskills;

import com.google.common.collect.Maps;
import com.willfp.ecoskills.api.EcoSkillsAPI;
import com.willfp.ecoskills.api.modifiers.ModifierOperation;
import com.willfp.ecoskills.api.modifiers.StatModifier;
import com.willfp.ecoskills.stats.Stats;
import gg.auroramc.aurora.api.reward.RewardCorrector;
import gg.auroramc.levels.AuroraLevels;
import org.bukkit.entity.Player;

import java.util.Map;

public class EcoSkillsCorrector implements RewardCorrector {
private final AuroraLevels plugin;

public EcoSkillsCorrector(AuroraLevels plugin) {
this.plugin = plugin;
}

@Override
public void correctRewards(Player player) {
var leveler = plugin.getLeveler();
var data = leveler.getUserData(player);
var level = data.getLevel();

Map<String, Map<ModifierOperation, Double>> statMap = Maps.newHashMap();

Stats.INSTANCE.values().forEach(stat -> {
var map = statMap.computeIfAbsent(stat.getId(), (key) -> Maps.newHashMap());
for (var operation : ModifierOperation.values()) {
map.put(operation, 0.0);
}
});

// Gather new stat modifiers
for (int i = 1; i < level + 1; i++) {
var matcher = leveler.getLevelMatcher().getBestMatcher(i);
if (matcher == null) continue;
var formulaPlaceholders = leveler.getRewardFormulaPlaceholders(player, i);
for (var reward : matcher.computeRewards(i)) {
if (reward instanceof EcoSkillsStatReward statReward && statReward.isValid()) {
statMap.computeIfAbsent(statReward.getStat().getId(), (key) -> Maps.newHashMap())
.merge(statReward.getOperation(), statReward.getValue(formulaPlaceholders), Double::sum);
}
}
}

// Apply the new stat modifiers
player.getScheduler().run(plugin, (task) -> {
for (var entry : statMap.entrySet()) {
var statType = entry.getKey();
var stat = Stats.INSTANCE.getByID(statType);
if (stat == null) continue;

for (var modifierEntry : entry.getValue().entrySet()) {
var operation = modifierEntry.getKey();
var value = modifierEntry.getValue();
var uuid = EcoSkillsStatReward.createStatModifierUUID(stat, operation);
if (value <= 0) {
EcoSkillsAPI.removeStatModifier(player, uuid);
} else {
AuroraLevels.logger().debug("Adding stat " + statType + " with value " + value + "/" + operation.name() + " to player " + player.getName());
EcoSkillsAPI.addStatModifier(player, new StatModifier(uuid, stat, value, operation));
}
}
}
}, null);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package gg.auroramc.levels.hooks.ecoskills;

import gg.auroramc.aurora.api.util.NamespacedId;
import gg.auroramc.levels.AuroraLevels;
import gg.auroramc.levels.hooks.Hook;

public class EcoSkillsHook implements Hook {
@Override
public void hook(AuroraLevels plugin) {
plugin.getLeveler().getRewardFactory()
.registerRewardType(NamespacedId.fromDefault("ecoskills_stat"), EcoSkillsStatReward.class);
plugin.getLeveler().getRewardAutoCorrector()
.registerCorrector(NamespacedId.fromDefault("ecoskills_stat"), new EcoSkillsCorrector(plugin));

AuroraLevels.logger().info("Hooked into AuraSkills for stat rewards with reward type: 'ecoskills_stat'. Auto reward corrector for stats is registered.");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package gg.auroramc.levels.hooks.ecoskills;

import com.willfp.ecoskills.api.EcoSkillsAPI;
import com.willfp.ecoskills.api.modifiers.ModifierOperation;
import com.willfp.ecoskills.api.modifiers.StatModifier;
import com.willfp.ecoskills.stats.Stat;
import com.willfp.ecoskills.stats.Stats;
import gg.auroramc.aurora.api.message.Placeholder;
import gg.auroramc.aurora.api.reward.NumberReward;
import gg.auroramc.levels.AuroraLevels;
import lombok.Getter;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;

import java.util.List;
import java.util.Locale;
import java.util.UUID;

@Getter
public class EcoSkillsStatReward extends NumberReward {
public static final String prefix = "aurora_levels/stat/";

private boolean valid = true;
private Stat stat;
private ModifierOperation operation = ModifierOperation.ADD;

private UUID createStatModifierUUID() {
return createStatModifierUUID(stat, operation);
}

public static UUID createStatModifierUUID(Stat stat, ModifierOperation operation) {
return UUID.nameUUIDFromBytes((prefix + stat.getId() + "/" + operation.name()).getBytes());
}

@Override
public void execute(Player player, long level, List<Placeholder<?>> placeholders) {
if (!valid) return;
var uuid = createStatModifierUUID();
var current = EcoSkillsAPI.getStatModifier(player, uuid);

double value = getValue(placeholders) + (current != null ? current.getModifier() : 0);

// Since the UUID is always the same this should overwrite the previous value
EcoSkillsAPI.addStatModifier(player, new StatModifier(uuid, stat, value, operation));
}

@Override
public void init(ConfigurationSection args) {
super.init(args);
var statName = args.getString("stat", "");
stat = Stats.INSTANCE.getByID(statName);
if (stat == null) {
valid = false;
AuroraLevels.logger().warning("Couldn't find EcoSkills stat: " + statName);
}

var operationName = args.getString("operation", "add").toUpperCase(Locale.ROOT);

try {
operation = ModifierOperation.valueOf(operationName);
} catch (IllegalArgumentException e) {
valid = false;
AuroraLevels.logger().warning("Couldn't find EcoSkills operation: " + operationName);
}
}

@Override
public String getDisplay(Player player, List<Placeholder<?>> placeholders) {
var display = super.getDisplay(player, placeholders);
if (!valid) return display;
return Placeholder.execute(display, Placeholder.of("{stat}", stat.getName()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
import net.luckperms.api.util.Tristate;
import org.bukkit.entity.Player;

import java.util.concurrent.CompletableFuture;

public class PermissionCorrector implements RewardCorrector {
private AuroraLevels plugin;

Expand All @@ -19,38 +17,34 @@ public PermissionCorrector(AuroraLevels plugin) {

@Override
public void correctRewards(Player player) {
CompletableFuture.runAsync(() -> {
var leveler = plugin.getLeveler();
var data = leveler.getUserData(player);
var level = data.getLevel();

for (int i = 1; i < level + 1; i++) {
var matcher = leveler.getLevelMatcher().getBestMatcher(i);
if (matcher == null) continue;
var formulaPlaceholders = leveler.getRewardFormulaPlaceholders(player, i);
for (var reward : matcher.computeRewards(i)) {
if (reward instanceof PermissionReward permissionReward) {
if (permissionReward.getPermissions() == null || permissionReward.getPermissions().isEmpty()) {
continue;
}
var leveler = plugin.getLeveler();
var data = leveler.getUserData(player);
var level = data.getLevel();

for (int i = 1; i < level + 1; i++) {
var matcher = leveler.getLevelMatcher().getBestMatcher(i);
if (matcher == null) continue;
var formulaPlaceholders = leveler.getRewardFormulaPlaceholders(player, i);
for (var reward : matcher.computeRewards(i)) {
if (reward instanceof PermissionReward permissionReward) {
if (permissionReward.getPermissions() == null || permissionReward.getPermissions().isEmpty()) {
continue;
}

var nodes = permissionReward.buildNodes(player, formulaPlaceholders);
var nodes = permissionReward.buildNodes(player, formulaPlaceholders);

LuckPermsProvider.get().getUserManager().modifyUser(player.getUniqueId(), (user) -> {
for (var node : nodes) {
var hasPermission = user.data().contains(node, NodeEqualityPredicate.EXACT);
LuckPermsProvider.get().getUserManager().modifyUser(player.getUniqueId(), (user) -> {
for (var node : nodes) {
var hasPermission = user.data().contains(node, NodeEqualityPredicate.EXACT);

if (hasPermission.equals(Tristate.UNDEFINED)) {
AuroraLevels.logger().debug("Permission " + node.getKey() + " is undefined for player " + player.getName());
user.data().add(node);
}
if (hasPermission.equals(Tristate.UNDEFINED)) {
AuroraLevels.logger().debug("Permission " + node.getKey() + " is undefined for player " + player.getName());
user.data().add(node);
}
});
}
}
});
}


}
});
}
}
}
Loading

0 comments on commit 3cee880

Please sign in to comment.