diff --git a/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpAcceptCommand.java b/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpAcceptCommand.java index 19c98ad6a..370318545 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpAcceptCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpAcceptCommand.java @@ -49,6 +49,7 @@ public class PtpAcceptCommand implements CommandExecutor { } if (mcMMO.p.getGeneralConfig().getPTPCommandWorldPermissions()) { + // TODO TECH CHECK - running operations on teleporting player and target player without the proper thread World targetWorld = target.getWorld(); World playerWorld = player.getWorld(); @@ -64,6 +65,7 @@ public class PtpAcceptCommand implements CommandExecutor { } } + // TODO TECH CHECK - running operations on teleporting player and target player without the proper thread PtpCommand.handleTeleportWarmup(target, player); return true; } diff --git a/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpCommand.java b/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpCommand.java index 48276c723..fea76961c 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpCommand.java @@ -228,6 +228,7 @@ public class PtpCommand implements TabExecutor { return true; } + // TODO TECH CHECK - running operations on teleporting player and target player without the proper thread protected static void handleTeleportWarmup(Player teleportingPlayer, Player targetPlayer) { if(UserManager.getPlayer(targetPlayer) == null) { @@ -250,9 +251,11 @@ public class PtpCommand implements TabExecutor { if (warmup > 0) { teleportingPlayer.sendMessage(LocaleLoader.getString("Teleport.Commencing", warmup)); + // TODO TECH CHECK - running operations on teleporting player and target player without the proper thread mcMMO.p.getFoliaLib().getImpl().runAtEntityLater(teleportingPlayer, new TeleportationWarmup(mcMMOPlayer, mcMMOTarget), 20 * warmup); } else { + // TODO TECH CHECK - running operations on teleporting player and target player without the proper thread EventUtils.handlePartyTeleportEvent(teleportingPlayer, targetPlayer); } } diff --git a/src/main/java/com/gmail/nossr50/commands/player/McrankCommand.java b/src/main/java/com/gmail/nossr50/commands/player/McrankCommand.java index dcfcdcdbe..66e14e877 100644 --- a/src/main/java/com/gmail/nossr50/commands/player/McrankCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/player/McrankCommand.java @@ -106,12 +106,13 @@ public class McrankCommand implements TabExecutor { } mcMMOPlayer.actualizeDatabaseATS(); + + // Assumes sender is player + boolean useBoard = mcMMO.p.getGeneralConfig().getScoreboardsEnabled() && (sender instanceof Player) && (mcMMO.p.getGeneralConfig().getRankUseBoard()); + boolean useChat = !useBoard || mcMMO.p.getGeneralConfig().getRankUseChat(); + mcMMO.p.getFoliaLib().getImpl().runAsync(new McrankCommandAsyncTask(playerName, sender, useBoard, useChat)); } - boolean useBoard = mcMMO.p.getGeneralConfig().getScoreboardsEnabled() && (sender instanceof Player) && (mcMMO.p.getGeneralConfig().getRankUseBoard()); - boolean useChat = !useBoard || mcMMO.p.getGeneralConfig().getRankUseChat(); - - mcMMO.p.getFoliaLib().getImpl().runAsync(new McrankCommandAsyncTask(playerName, sender, useBoard, useChat)); } private long getCDSeconds(McMMOPlayer mcMMOPlayer, long cooldownMillis) { diff --git a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java index 34eaa2113..ca42284ef 100644 --- a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java @@ -242,7 +242,7 @@ public class EntityListener implements Listener { entity.setMetadata(MetadataConstants.METADATA_KEY_TRAVELING_BLOCK, MetadataConstants.MCMMO_METADATA_VALUE); TravelingBlockMetaCleanup metaCleanupTask = new TravelingBlockMetaCleanup(entity, pluginRef); - mcMMO.p.getFoliaLib().getImpl().runAtEntityTimer(entity, metaCleanupTask, 20, 20*60); //6000 ticks is 5 minutes + mcMMO.p.getFoliaLib().getImpl().runAtEntityTimer(entity, metaCleanupTask, 20, 20*60); // 20*60 ticks is 1 minute } else if (isTracked) { BlockUtils.setUnnaturalBlock(block); diff --git a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java index a63b7650e..781f73781 100644 --- a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java @@ -589,7 +589,7 @@ public class PlayerListener implements Listener { Player player = event.getPlayer(); //Delay loading for 3 seconds in case the player has a save task running, its hacky but it should do the trick - mcMMO.p.getFoliaLib().getImpl().runLaterAsync(new PlayerProfileLoadingTask(player), 60); + mcMMO.p.getFoliaLib().getImpl().runLaterAsync(new PlayerProfileLoadingTask(player), 3*20); if (mcMMO.p.getGeneralConfig().getMOTDEnabled() && Permissions.motd(player)) { Motd.displayAll(player); diff --git a/src/main/java/com/gmail/nossr50/listeners/WorldListener.java b/src/main/java/com/gmail/nossr50/listeners/WorldListener.java index 4c24930c6..e31da44bd 100644 --- a/src/main/java/com/gmail/nossr50/listeners/WorldListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/WorldListener.java @@ -11,6 +11,8 @@ import org.bukkit.event.world.ChunkUnloadEvent; import org.bukkit.event.world.StructureGrowEvent; import org.bukkit.event.world.WorldUnloadEvent; +import java.util.List; + public class WorldListener implements Listener { private final mcMMO plugin; @@ -29,9 +31,16 @@ public class WorldListener implements Listener { if(WorldBlacklist.isWorldBlacklisted(event.getWorld())) return; - // Using 50 ms later as I do not know of a way to run one tick later (safely) - plugin.getFoliaLib().getImpl().runLater(() -> { - for (BlockState blockState : event.getBlocks()) { + // Under Folia, any two loaded and adjacent chunks will be in the same ticking region. To avoid scheduling many + // tasks, we will use this assumption. + // Therefore, we will schedule the task such that all blocks in the event are handled from the ticking region of + // the first block in the event. + // Without folia, this will run on the main tick. + List blocks = event.getBlocks(); + BlockState referenceBlock = blocks.get(0); + plugin.getFoliaLib().getImpl().runAtLocationLater(referenceBlock.getLocation(), () -> { + for (BlockState blockState : blocks) { + // The HashChunkManager is thread-safe, we can safely call it from a non-single-threaded environment mcMMO.getPlaceStore().setFalse(blockState); } }, 1); diff --git a/src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandAsyncTask.java b/src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandAsyncTask.java index 2897b4388..9917b50af 100644 --- a/src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandAsyncTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandAsyncTask.java @@ -32,7 +32,18 @@ public class McrankCommandAsyncTask extends CancellableRunnable { public void run() { Map skills = mcMMO.getDatabaseManager().readRank(playerName); - mcMMO.p.getFoliaLib().getImpl().runNextTick(new McrankCommandDisplayTask(skills, sender, playerName, useBoard, useChat)); + // If the sender is a player, actions on the player will be taken. Under folia, this needs to run on the + // entity's scheduler. + if (sender instanceof Player player) { + mcMMO.p.getFoliaLib().getImpl().runAtEntityLater( + player, + new McrankCommandDisplayTask(skills, player, playerName, useBoard, useChat), + 1 + ); + } else { + McrankCommandDisplayTask task = new McrankCommandDisplayTask(skills, sender, playerName, useBoard, useChat); + mcMMO.p.getFoliaLib().getImpl().runNextTick(task); + } } } diff --git a/src/main/java/com/gmail/nossr50/runnables/database/DatabaseConversionTask.java b/src/main/java/com/gmail/nossr50/runnables/database/DatabaseConversionTask.java index 4e59a01fb..ccfc4084e 100644 --- a/src/main/java/com/gmail/nossr50/runnables/database/DatabaseConversionTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/database/DatabaseConversionTask.java @@ -21,6 +21,6 @@ public class DatabaseConversionTask extends CancellableRunnable { public void run() { sourceDatabase.convertUsers(mcMMO.getDatabaseManager()); - mcMMO.p.getFoliaLib().getImpl().runNextTick(t -> sender.sendMessage(message)); + mcMMO.p.getFoliaLib().getImpl().runLaterAsync(t -> sender.sendMessage(message), 1); } } diff --git a/src/main/java/com/gmail/nossr50/runnables/player/PlayerProfileLoadingTask.java b/src/main/java/com/gmail/nossr50/runnables/player/PlayerProfileLoadingTask.java index 6cd865055..f34639e1e 100644 --- a/src/main/java/com/gmail/nossr50/runnables/player/PlayerProfileLoadingTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/player/PlayerProfileLoadingTask.java @@ -37,7 +37,7 @@ public class PlayerProfileLoadingTask extends CancellableRunnable { } // Quit if they logged out - if (!player.isOnline()) { + if (!player.isOnline()) { // TODO TECH CHECK - is thread safe? We are running this async LogUtils.debug(mcMMO.p.getLogger(), "Aborting profile loading recovery for " + player.getName() + " - player logged out"); return; } diff --git a/src/main/java/com/gmail/nossr50/runnables/skills/DelayedCropReplant.java b/src/main/java/com/gmail/nossr50/runnables/skills/DelayedCropReplant.java index 927e9a3f8..6fa3b0bbc 100644 --- a/src/main/java/com/gmail/nossr50/runnables/skills/DelayedCropReplant.java +++ b/src/main/java/com/gmail/nossr50/runnables/skills/DelayedCropReplant.java @@ -54,7 +54,10 @@ public class DelayedCropReplant extends CancellableRunnable { PlantAnchorType plantAnchorType = PlantAnchorType.NORMAL; //Remove the metadata marking the block as recently replanted - mcMMO.p.getFoliaLib().getImpl().runAtLocationLater(blockBreakEvent.getBlock().getLocation(), new markPlantAsOld(blockBreakEvent.getBlock().getLocation()), 10); + mcMMO.p.getFoliaLib().getImpl().runAtLocationLater( + blockBreakEvent.getBlock().getLocation(), + new markPlantAsOld(blockBreakEvent.getBlock().getLocation()), + 10); if(blockBreakEvent.isCancelled()) { wasImmaturePlant = true; @@ -101,7 +104,10 @@ public class DelayedCropReplant extends CancellableRunnable { //Play an effect ParticleEffectUtils.playGreenThumbEffect(cropLocation); - mcMMO.p.getFoliaLib().getImpl().runAtLocationLater(newState.getLocation(), new PhysicsBlockUpdate(newState.getBlock(), cropFace, plantAnchorType), 1); + mcMMO.p.getFoliaLib().getImpl().runAtLocationLater( + newState.getLocation(), + new PhysicsBlockUpdate(newState.getBlock(), cropFace, plantAnchorType), + 1); } } diff --git a/src/main/java/com/gmail/nossr50/skills/alchemy/AlchemyPotionBrewer.java b/src/main/java/com/gmail/nossr50/skills/alchemy/AlchemyPotionBrewer.java index 2a11b0159..b753c668f 100644 --- a/src/main/java/com/gmail/nossr50/skills/alchemy/AlchemyPotionBrewer.java +++ b/src/main/java/com/gmail/nossr50/skills/alchemy/AlchemyPotionBrewer.java @@ -259,6 +259,7 @@ public final class AlchemyPotionBrewer { } public static void scheduleCheck(Player player, BrewingStand brewingStand) { + // TODO TECH CHECK - should be runAtLocation? We are using block data AND player data. Must resolve correctly mcMMO.p.getFoliaLib().getImpl().runAtEntity(player, new AlchemyBrewCheckTask(player, brewingStand)); } diff --git a/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java b/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java index e5fb8e0c4..3ff60f76a 100644 --- a/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java +++ b/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java @@ -130,8 +130,11 @@ public class HerbalismManager extends SkillManager { if(blockState.getType().toString().equalsIgnoreCase("sweet_berry_bush")) { if(blockState.getBlockData() instanceof Ageable ageable) { - if(ageable.getAge() <= 1) { - applyXpGain(xpReward, XPGainReason.PVE, XPGainSource.SELF); + if (ageable.getAge() <= 1) { + // Is using Player properties, run this on the Player's Scheduler if under Folia + mcMMO.p.getFoliaLib().getImpl().runAtEntity( + mmoPlayer.getPlayer(), + (task) -> applyXpGain(xpReward, XPGainReason.PVE, XPGainSource.SELF)); } } } @@ -310,7 +313,8 @@ public class HerbalismManager extends SkillManager { DelayedHerbalismXPCheckTask delayedHerbalismXPCheckTask = new DelayedHerbalismXPCheckTask(mmoPlayer, delayedChorusBlocks); //Large delay because the tree takes a while to break - mcMMO.p.getFoliaLib().getImpl().runAtEntity(mmoPlayer.getPlayer(), delayedHerbalismXPCheckTask); //Calculate Chorus XP + Bonus Drops 1 tick later + Location referenceLocation = delayedChorusBlocks.get(0).getBlockRef().getLocation(); + mcMMO.p.getFoliaLib().getImpl().runAtLocationLater(referenceLocation, delayedHerbalismXPCheckTask, 1); //Calculate Chorus XP + Bonus Drops 1 tick later } } @@ -741,7 +745,10 @@ public class HerbalismManager extends SkillManager { */ private void startReplantTask(int desiredCropAge, BlockBreakEvent blockBreakEvent, BlockState cropState, boolean isImmature) { //Mark the plant as recently replanted to avoid accidental breakage - mcMMO.p.getFoliaLib().getImpl().runAtLocationLater(blockBreakEvent.getBlock().getLocation(), new DelayedCropReplant(blockBreakEvent, cropState, desiredCropAge, isImmature), 2 * Misc.TICK_CONVERSION_FACTOR); + mcMMO.p.getFoliaLib().getImpl().runAtLocationLater( + blockBreakEvent.getBlock().getLocation(), + new DelayedCropReplant(blockBreakEvent, cropState, desiredCropAge, isImmature), + 2 * Misc.TICK_CONVERSION_FACTOR); blockBreakEvent.getBlock().setMetadata(MetadataConstants.METADATA_KEY_REPLANT, new RecentlyReplantedCropMeta(mcMMO.p, true)); } diff --git a/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java b/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java index 030104d4f..94c9aebb9 100644 --- a/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java +++ b/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java @@ -130,7 +130,10 @@ public class MiningManager extends SkillManager { mmoPlayer.setAbilityDATS(SuperAbilityType.BLAST_MINING, System.currentTimeMillis()); mmoPlayer.setAbilityInformed(SuperAbilityType.BLAST_MINING, false); - mcMMO.p.getFoliaLib().getImpl().runAtEntityLater(mmoPlayer.getPlayer(), new AbilityCooldownTask(mmoPlayer, SuperAbilityType.BLAST_MINING), (long) SuperAbilityType.BLAST_MINING.getCooldown() * Misc.TICK_CONVERSION_FACTOR); + mcMMO.p.getFoliaLib().getImpl().runAtEntityLater( + mmoPlayer.getPlayer(), + new AbilityCooldownTask(mmoPlayer, SuperAbilityType.BLAST_MINING), + (long) SuperAbilityType.BLAST_MINING.getCooldown() * Misc.TICK_CONVERSION_FACTOR); } /** diff --git a/src/main/java/com/gmail/nossr50/util/EventUtils.java b/src/main/java/com/gmail/nossr50/util/EventUtils.java index 3e5035b40..333335e45 100644 --- a/src/main/java/com/gmail/nossr50/util/EventUtils.java +++ b/src/main/java/com/gmail/nossr50/util/EventUtils.java @@ -354,12 +354,14 @@ public final class EventUtils { return !damageEvent.isCancelled() && !fakeBlockBreakEvent.isCancelled(); } + // TODO TECH CHECK - running operations on teleporting player and target player without the proper thread public static void handlePartyTeleportEvent(Player teleportingPlayer, Player targetPlayer) { McMMOPlayer mcMMOPlayer = UserManager.getPlayer(teleportingPlayer); if(mcMMOPlayer == null) return; + // TODO TECH CHECK - running operations on teleporting player and target player without the proper thread McMMOPartyTeleportEvent event = new McMMOPartyTeleportEvent(teleportingPlayer, targetPlayer, mcMMOPlayer.getParty().getName()); mcMMO.p.getServer().getPluginManager().callEvent(event); @@ -367,7 +369,7 @@ public final class EventUtils { return; } -// teleportingPlayer.teleport(targetPlayer); + // TODO TECH CHECK - getting location of target from another thread mcMMO.p.getFoliaLib().getImpl().teleportAsync(teleportingPlayer, targetPlayer.getLocation()); teleportingPlayer.sendMessage(LocaleLoader.getString("Party.Teleport.Player", targetPlayer.getName())); diff --git a/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java b/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java index 1237ce086..be45b3ee0 100644 --- a/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java +++ b/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java @@ -131,7 +131,8 @@ public class ScoreboardWrapper { if (cooldownTask == null) { // Repeat every 5 seconds. // Cancels once all cooldowns are done, using stopCooldownUpdating(). - cooldownTask = mcMMO.p.getFoliaLib().getImpl().runAtEntityTimer(player, new ScoreboardCooldownTask(), 5 * Misc.TICK_CONVERSION_FACTOR, 5 * Misc.TICK_CONVERSION_FACTOR); + cooldownTask = mcMMO.p.getFoliaLib().getImpl().runAtEntityTimer(player, new ScoreboardCooldownTask(), + 5 * Misc.TICK_CONVERSION_FACTOR, 5 * Misc.TICK_CONVERSION_FACTOR); } } diff --git a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java index 5f4c51ac5..85068f195 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java @@ -981,6 +981,6 @@ public final class CombatUtils { * @param entity the projectile */ public static void delayArrowMetaCleanup(@NotNull Projectile entity) { - mcMMO.p.getFoliaLib().getImpl().runLater(() -> cleanupArrowMetadata(entity), 20*60); + mcMMO.p.getFoliaLib().getImpl().runAtEntityLater(entity, () -> cleanupArrowMetadata(entity), 20*60); } } diff --git a/src/main/java/com/gmail/nossr50/util/skills/RankUtils.java b/src/main/java/com/gmail/nossr50/util/skills/RankUtils.java index ae2f842ad..a9b7317e8 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/RankUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/RankUtils.java @@ -48,7 +48,9 @@ public class RankUtils { { SkillUnlockNotificationTask skillUnlockNotificationTask = new SkillUnlockNotificationTask(mcMMOPlayer, subSkillType, newLevel); - mcMMO.p.getFoliaLib().getImpl().runAtEntityLater(mcMMOPlayer.getPlayer(), skillUnlockNotificationTask, (count * 100L)); + long tickDelay = count * 100L; // Delay for this skill's notification + if (tickDelay == 0) tickDelay = 1; // Ensure delay always > 0 + mcMMO.p.getFoliaLib().getImpl().runAtEntityLater(mcMMOPlayer.getPlayer(), skillUnlockNotificationTask, tickDelay); count++; }