Skip to content

Commit

Permalink
Add configurable auto-save period
Browse files Browse the repository at this point in the history
Took 1 hour 14 minutes
  • Loading branch information
Darkyenus committed Apr 4, 2020
1 parent 82232f8 commit 74bed60
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 18 deletions.
43 changes: 31 additions & 12 deletions src/main/java/com/darkyen/minecraft/DeadSouls.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ public class DeadSouls extends JavaPlugin implements Listener {
private long soulFreeAfterMs = Long.MAX_VALUE;
private long soulFadesAfterMs = Long.MAX_VALUE;

private long autoSaveMs = 0L;

private float retainedXPPercent;
private int retainedXPPerLevel;

Expand Down Expand Up @@ -131,7 +133,7 @@ public class DeadSouls extends JavaPlugin implements Listener {

@NotNull
private final HashMap<Player, PlayerSoulInfo> watchedPlayers = new HashMap<>();
private boolean soulDatabaseChanged = false;
private boolean refreshNearbySoulCache = false;

private static final double COLLECTION_DISTANCE2 = NumberConversions.square(1);

Expand All @@ -145,6 +147,7 @@ public class DeadSouls extends JavaPlugin implements Listener {
private final Random processPlayers_random = new Random();

private long processPlayers_nextFadeCheck = 0;
private long processPlayers_nextAutoSave = 0;

private void processPlayers() {
final SoulDatabase soulDatabase = this.soulDatabase;
Expand All @@ -158,22 +161,24 @@ private void processPlayers() {
if (now > processPlayers_nextFadeCheck && soulFadesAfterMs < Long.MAX_VALUE) {
final int faded = soulDatabase.removeFadedSouls(soulFadesAfterMs);
if (faded > 0) {
this.soulDatabaseChanged = true;
getLogger().log(Level.INFO, "Removed "+faded+" faded soul(s)");
this.refreshNearbySoulCache = true;
getLogger().log(Level.FINE, "Removed "+faded+" faded soul(s)");
}
processPlayers_nextFadeCheck = now + 1000 * 60;// Check every minute
processPlayers_nextFadeCheck = now + 1000 * 60 * 5;// Check every 5 minutes
}

final boolean soulDatabaseChanged = this.soulDatabaseChanged;
this.soulDatabaseChanged = false;
final boolean refreshNearbySoulCache = this.refreshNearbySoulCache;
this.refreshNearbySoulCache = false;

final boolean playCallingSounds = !soundSoulCalling.isEmpty() && volumeSoulCalling > 0f && this.processPlayers_random.nextInt(12) == 0;

boolean databaseChanged = false;

for (Map.Entry<Player, PlayerSoulInfo> entry : watchedPlayers.entrySet()) {
final Player player = entry.getKey();
final PlayerSoulInfo info = entry.getValue();

boolean searchNewSouls = soulDatabaseChanged;
boolean searchNewSouls = refreshNearbySoulCache;

// Update location
final Location playerLocation = player.getLocation(processPlayers_playerLocation);
Expand Down Expand Up @@ -267,6 +272,7 @@ private void processPlayers() {
if (!soundSoulCollectXp.isEmpty() && closestSoulLocation != null) {
player.playSound(closestSoulLocation, soundSoulCollectXp, 1f, 1f);
}
databaseChanged = true;
}

final @NotNull ItemStack[] items = closestSoul.items;
Expand All @@ -281,10 +287,12 @@ private void processPlayers() {
boolean someCollected = false;
if (overflow.size() < items.length) {
someCollected = true;
databaseChanged = true;
} else {
for (Map.Entry<Integer, ItemStack> overflowEntry : overflow.entrySet()) {
if (!items[overflowEntry.getKey()].equals(overflowEntry.getValue())) {
someCollected = true;
databaseChanged = true;
break;
}
}
Expand All @@ -298,7 +306,7 @@ private void processPlayers() {
if (closestSoul.xp <= 0 && closestSoul.items.length <= 0) {
// Soul is depleted
soulDatabase.removeSoul(closestSoul);
this.soulDatabaseChanged = true;
this.refreshNearbySoulCache = true;

// Do some fancy effect
if (closestSoulLocation != null) {
Expand All @@ -315,6 +323,16 @@ private void processPlayers() {
}
}
}

if (databaseChanged) {
soulDatabase.markDirty();
}

final long autoSaveMs = this.autoSaveMs;
if (now > processPlayers_nextAutoSave) {
processPlayers_nextAutoSave = now + autoSaveMs;
soulDatabase.autoSave();
}
}

@Override
Expand All @@ -323,6 +341,7 @@ public void onEnable() {
final Logger LOG = getLogger();
soulFreeAfterMs = parseTimeMs(config.getString("soul-free-after"), Long.MAX_VALUE, LOG);
soulFadesAfterMs = parseTimeMs(config.getString("soul-fades-after"), Long.MAX_VALUE, LOG);
autoSaveMs = parseTimeMs(config.getString("auto-save"), 0L, LOG);

{
this.retainedXPPercent = 90;
Expand Down Expand Up @@ -448,7 +467,7 @@ public void onEnable() {
}
}

soulDatabaseChanged = true;
refreshNearbySoulCache = true;

for (Player onlinePlayer : server.getOnlinePlayers()) {
watchedPlayers.put(onlinePlayer, new PlayerSoulInfo());
Expand All @@ -464,7 +483,7 @@ public void onDisable() {
try {
final int faded = soulDatabase.removeFadedSouls(soulFadesAfterMs);
if (faded > 0) {
getLogger().log(Level.INFO, "Removed "+faded+" faded soul(s)");
getLogger().log(Level.FINE, "Removed "+faded+" faded soul(s)");
}
soulDatabase.save();
} catch (Exception e) {
Expand Down Expand Up @@ -752,7 +771,7 @@ public void onPlayerDeath(PlayerDeathEvent event) {

final int soulId = soulDatabase.addSoul(owner, player.getWorld().getUID(),
soulLocation.getX(), soulLocation.getY(), soulLocation.getZ(), soulItems, soulXp);
soulDatabaseChanged = true;
refreshNearbySoulCache = true;

// Do not offer to free the soul if it will be free sooner than the player can click the button
if (owner != null && soulFreeAfterMs > 1000
Expand Down Expand Up @@ -814,7 +833,7 @@ public void onEntityDeath(EntityDeathEvent event) {

final World world = entity.getWorld();
soulDatabase.addSoul(null, world.getUID(), soulLocation.getX(), soulLocation.getY(), soulLocation.getZ(), soulItems, soulXp);
soulDatabaseChanged = true;
refreshNearbySoulCache = true;

if (!soundSoulDropped.isEmpty()) {
world.playSound(soulLocation, soundSoulDropped, SoundCategory.MASTER, 1.1f, 1.7f);
Expand Down
38 changes: 34 additions & 4 deletions src/main/java/com/darkyen/minecraft/SoulDatabase.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ public class SoulDatabase {
@NotNull
private final Path databaseFile;

private boolean dirty = false;

public SoulDatabase(@Nullable Plugin owner, @NotNull Path databaseFile) {
this.owner = owner;
this.databaseFile = databaseFile;
Expand Down Expand Up @@ -191,6 +193,7 @@ public boolean save() throws IOException {
if (failedWrites > 0) {
LOG.log(Level.WARNING, failedWrites + " soul(s) failed to save");
}
LOG.log(Level.INFO, "Saved");
return true;
}
LOG.log(Level.SEVERE, "Failed to save souls", exception);
Expand Down Expand Up @@ -219,6 +222,10 @@ public int removeFadedSouls(long soulFadesAfterMs) {
}
}

if (fadedSouls > 0) {
dirty = true;
}

return fadedSouls;
}

Expand All @@ -240,24 +247,45 @@ public int addSoul(@Nullable UUID owner, @NotNull UUID world, double x, double y
}
}
souls.insert(soul);
dirty = true;
return soulId;
}

public void markDirty() {
dirty = true;
}

public void autoSave() {
if (!dirty) {
return;
}

if (this.owner != null) {
dirty = false;
Bukkit.getScheduler().runTaskAsynchronously(this.owner, () -> {
boolean success = false;
try {
save();
if (save()) {
success = true;
}
} catch (IOException e) {
LOG.log(Level.WARNING, "Failed to save ItemStore asynchronously", e);
} finally {
if (!success) {
dirty = true;
}
}
});
} else {
LOG.log(Level.INFO, "Saving synchronously");
try {
save();
if (save()) {
dirty = false;
}
} catch (IOException e) {
LOG.log(Level.WARNING, "Failed to save ItemStore synchronously", e);
}
}

return soulId;
}

@Nullable
Expand Down Expand Up @@ -301,6 +329,7 @@ public void freeSoul(@NotNull CommandSender sender, int soulId, long soulFreeAft

if (soul.freeSoul(System.currentTimeMillis(), soulFreeAfterMs)) {
sender.sendMessage(ChatColor.AQUA+"Soul has been set free");
dirty = true;
} else {
sender.sendMessage(ChatColor.AQUA+"This soul is already free");
}
Expand All @@ -313,6 +342,7 @@ public void removeSoul(@NotNull Soul toRemove) {
LOG.log(Level.WARNING, "Soul " + toRemove + " already removed from BY-ID");
} else {
soulsById.set(i, null);
dirty = true;
}
}

Expand Down
9 changes: 8 additions & 1 deletion src/main/resources/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,11 @@ color-soul-gone: FFFF00
# Text on a button to free the soul (Set to empty to disable this functionality)
text-free-my-soul: "Free my soul"
# Text displayed as a tooltip on button to free player's soul (Set to empty to disable the tooltip)
text-free-my-soul-tooltip: "Allows other players to collect the soul immediately"
text-free-my-soul-tooltip: "Allows other players to collect the soul immediately"

# <time> How frequently should auto-save of the soul database occur (only if modified and not more frequently than once per second)
# never = saving happens only on server restart (not generally recommended, unless you are sure that your server is stable)
# otherwise = plugin will attempt to save periodically, after this time interval passes
# 0s is recommended for servers with infrequent deaths
# 1m or 5m might be sensible values for large servers
auto-save: 0s
2 changes: 1 addition & 1 deletion src/main/resources/plugin.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: DeadSouls
version: '1.3'
version: '1.4'
api-version: '1.13'
main: com.darkyen.minecraft.DeadSouls
authors: [Darkyen]
Expand Down

0 comments on commit 74bed60

Please sign in to comment.