Skip to content

Commit

Permalink
Removed uncaching as async saving can cause race condition
Browse files Browse the repository at this point in the history
Fixed tests.
  • Loading branch information
tastybento committed Apr 19, 2020
1 parent 6e64d27 commit c463170
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 75 deletions.
126 changes: 71 additions & 55 deletions src/main/java/world/bentobox/level/Level.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import org.eclipse.jdt.annotation.Nullable;

import world.bentobox.bentobox.api.addons.Addon;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.configuration.Config;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.Database;
Expand Down Expand Up @@ -47,6 +48,13 @@ public class Level extends Addon {
private ConfigSettings settings;
private Config<ConfigSettings> configObject = new Config<>(this, ConfigSettings.class);

/**
* @param settings the settings to set
*/
public void setSettings(ConfigSettings settings) {
this.settings = settings;
}

// Database handler for level data
private Database<LevelsData> handler;

Expand Down Expand Up @@ -89,6 +97,7 @@ public long getIslandLevel(World world, @Nullable UUID targetPlayer) {
* @param targetPlayer - UUID of target player
* @return LevelsData object or null if not found
*/
@Nullable
public LevelsData getLevelsData(@NonNull UUID targetPlayer) {
// Get from database if not in cache
if (!levelsCache.containsKey(targetPlayer) && handler.objectExists(targetPlayer.toString())) {
Expand Down Expand Up @@ -182,54 +191,19 @@ public void onEnable() {
// Start the top ten and register it for clicks
topTen = new TopTen(this);
registerListener(topTen);
// Register commands for AcidIsland and BSkyBlock
// Register commands for GameModes
getPlugin().getAddonsManager().getGameModeAddons().stream()
.filter(gm -> settings.getGameModes().contains(gm.getDescription().getName()))
.filter(gm -> settings
.getGameModes()
.contains(gm
.getDescription()
.getName()))
.forEach(gm -> {
log("Level hooking into " + gm.getDescription().getName());
gm.getAdminCommand().ifPresent(adminCommand -> {
new AdminLevelCommand(this, adminCommand);
new AdminTopCommand(this, adminCommand);
});
gm.getPlayerCommand().ifPresent(playerCmd -> {
new IslandLevelCommand(this, playerCmd);
new IslandTopCommand(this, playerCmd);
new IslandValueCommand(this, playerCmd);
});
registerCommands(gm);
// Register placeholders
if (getPlugin().getPlaceholdersManager() != null) {
// Island Level
getPlugin().getPlaceholdersManager().registerPlaceholder(this,
gm.getDescription().getName().toLowerCase() + "_island_level",
user -> getLevelPresenter().getLevelString(getIslandLevel(gm.getOverWorld(), user.getUniqueId())));

// Visited Island Level
getPlugin().getPlaceholdersManager().registerPlaceholder(this,
gm.getDescription().getName().toLowerCase() + "_visited_island_level",
user -> getPlugin().getIslands().getIslandAt(user.getLocation())
.map(island -> getIslandLevel(gm.getOverWorld(), island.getOwner()))
.map(level -> getLevelPresenter().getLevelString(level))
.orElse("0"));

// Top Ten
for (int i = 1; i <= 10; i++) {
final int rank = i;
// Value
getPlugin().getPlaceholdersManager().registerPlaceholder(this,
gm.getDescription().getName().toLowerCase() + "_top_value_" + rank,
user -> {
Collection<Long> values = getTopTen().getTopTenList(gm.getOverWorld()).getTopTen().values();
return values.size() < rank ? "" : values.stream().skip(rank - 1).findFirst().map(String::valueOf).orElse("");
});

// Name
getPlugin().getPlaceholdersManager().registerPlaceholder(this,
gm.getDescription().getName().toLowerCase() + "_top_name_" + rank,
user -> {
Collection<UUID> values = getTopTen().getTopTenList(gm.getOverWorld()).getTopTen().keySet();
return values.size() < rank ? "" : getPlayers().getName(values.stream().skip(rank - 1).findFirst().orElse(null));
});
}
registerPlaceholders(gm);
}
});

Expand All @@ -242,15 +216,64 @@ public void onEnable() {
registerRequestHandler(new TopTenRequestHandler(this));

// Check if WildStackers is enabled on the server
if (Bukkit.getPluginManager().getPlugin("WildStacker") != null) {
// I only added support for counting blocks into the island level
// Someone else can PR if they want spawners added to the Leveling system :)
CalcIslandLevel.stackersEnabled = true;
} else CalcIslandLevel.stackersEnabled = false;
// I only added support for counting blocks into the island level
// Someone else can PR if they want spawners added to the Leveling system :)
CalcIslandLevel.stackersEnabled = Bukkit.getPluginManager().getPlugin("WildStacker") != null;

// Done
}

private void registerPlaceholders(GameModeAddon gm) {
// Island Level
getPlugin().getPlaceholdersManager().registerPlaceholder(this,
gm.getDescription().getName().toLowerCase() + "_island_level",
user -> getLevelPresenter().getLevelString(getIslandLevel(gm.getOverWorld(), user.getUniqueId())));

// Visited Island Level
getPlugin().getPlaceholdersManager().registerPlaceholder(this,
gm.getDescription().getName().toLowerCase() + "_visited_island_level", user -> getVisitedIslandLevel(gm, user));

// Top Ten
for (int i = 1; i <= 10; i++) {
final int rank = i;
// Value
getPlugin().getPlaceholdersManager().registerPlaceholder(this,
gm.getDescription().getName().toLowerCase() + "_top_value_" + rank,
user -> {
Collection<Long> values = getTopTen().getTopTenList(gm.getOverWorld()).getTopTen().values();
return values.size() < rank ? "" : values.stream().skip(rank - 1).findFirst().map(String::valueOf).orElse("");
});

// Name
getPlugin().getPlaceholdersManager().registerPlaceholder(this,
gm.getDescription().getName().toLowerCase() + "_top_name_" + rank,
user -> {
Collection<UUID> values = getTopTen().getTopTenList(gm.getOverWorld()).getTopTen().keySet();
return values.size() < rank ? "" : getPlayers().getName(values.stream().skip(rank - 1).findFirst().orElse(null));
});
}

}

private String getVisitedIslandLevel(GameModeAddon gm, User user) {
return getIslands().getIslandAt(user.getLocation())
.map(island -> getIslandLevel(gm.getOverWorld(), island.getOwner()))
.map(level -> getLevelPresenter().getLevelString(level))
.orElse("0");
}

private void registerCommands(GameModeAddon gm) {
gm.getAdminCommand().ifPresent(adminCommand -> {
new AdminLevelCommand(this, adminCommand);
new AdminTopCommand(this, adminCommand);
});
gm.getPlayerCommand().ifPresent(playerCmd -> {
new IslandLevelCommand(this, playerCmd);
new IslandTopCommand(this, playerCmd);
new IslandValueCommand(this, playerCmd);
});
}

/**
* Save the levels to the database
*/
Expand Down Expand Up @@ -316,13 +339,6 @@ public Database<LevelsData> getHandler() {
return handler;
}

public void uncachePlayer(@Nullable UUID uniqueId) {
if (levelsCache.containsKey(uniqueId) && levelsCache.get(uniqueId) != null) {
handler.saveObject(levelsCache.get(uniqueId));
}
levelsCache.remove(uniqueId);
}

public static Addon getInstance() {
return addon;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;

import world.bentobox.level.Level;

/**
* Listens for when players join and leave
* Listens for when players join
* @author tastybento
*
*/
Expand All @@ -36,10 +35,4 @@ public void onPlayerJoin(PlayerJoinEvent e) {
}
}

@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onPlayerQuit(PlayerQuitEvent e) {
addon.uncachePlayer(e.getPlayer().getUniqueId());
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@

/**
* @author tastybento
*
* @deprecated As of 1.9.0, for removal.
*/
@Deprecated
public class LevelPlaceholder implements PlaceholderReplacer {

private final Level addon;
Expand Down
8 changes: 6 additions & 2 deletions src/test/java/world/bentobox/level/LevelPresenterTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import world.bentobox.bentobox.managers.IslandsManager;
import world.bentobox.level.calculators.PlayerLevel;
import world.bentobox.level.config.BlockConfig;
import world.bentobox.level.config.ConfigSettings;

/**
* @author tastybento
Expand All @@ -39,7 +40,9 @@ public class LevelPresenterTest {
@Mock
private PlayerLevel pl;
@Mock
private BlockConfig settings;
private ConfigSettings settings;
@Mock
private BlockConfig blockConfig;

@Before
public void setUp() throws Exception {
Expand All @@ -60,6 +63,7 @@ public void setUp() throws Exception {

// Settings
when(addon.getSettings()).thenReturn(settings);
when(addon.getBlockConfig()).thenReturn(blockConfig);
}

/**
Expand Down Expand Up @@ -99,7 +103,7 @@ public void testGetLevelStringLong() {
*/
@Test
public void testGetLevelStringLongShorthand() {
when(settings.isShortHand()).thenReturn(true);
when(settings.isShorthand()).thenReturn(true);
LevelPresenter lp = new LevelPresenter(addon, plugin);
assertEquals("123.5M", lp.getLevelString(123456789L));
assertEquals("1.2k", lp.getLevelString(1234L));
Expand Down
25 changes: 18 additions & 7 deletions src/test/java/world/bentobox/level/LevelTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@
import world.bentobox.bentobox.managers.IslandWorldManager;
import world.bentobox.bentobox.managers.IslandsManager;
import world.bentobox.bentobox.managers.PlaceholdersManager;
import world.bentobox.level.config.BlockConfig;
import world.bentobox.level.config.ConfigSettings;
import world.bentobox.level.listeners.IslandTeamListeners;
import world.bentobox.level.listeners.JoinLeaveListener;

Expand Down Expand Up @@ -94,8 +96,6 @@ public class LevelTest {
private AddonsManager am;
@Mock
private BukkitScheduler scheduler;
@Mock
private Settings settings;

private Level addon;

Expand All @@ -113,14 +113,23 @@ public class LevelTest {

@Mock
private PluginManager pim;
@Mock
private BlockConfig blockConfig;
@Mock
private Settings pluginSettings;

@BeforeClass
public static void beforeClass() throws IOException {
// Make the addon jar
jFile = new File("addon.jar");
// Copy over config file from src folder
Path fromPath = Paths.get("src/main/resources/config.yml");
Path path = Paths.get("config.yml");
Files.copy(fromPath, path);
// Copy over block config file from src folder
fromPath = Paths.get("src/main/resources/blockconfig.yml");
path = Paths.get("blockconfig.yml");
Files.copy(fromPath, path);
try (JarOutputStream tempJarOutputStream = new JarOutputStream(new FileOutputStream(jFile))) {
//Added the new files to the jar.
try (FileInputStream fis = new FileInputStream(path.toFile())) {
Expand Down Expand Up @@ -185,6 +194,7 @@ public void setUp() throws Exception {
addon.setFile(jFile);
AddonDescription desc = new AddonDescription.Builder("bentobox", "Level", "1.3").description("test").authors("tastybento").build();
addon.setDescription(desc);
addon.setSettings(new ConfigSettings());
// Addons manager
when(plugin.getAddonsManager()).thenReturn(am);
// One game mode
Expand All @@ -205,9 +215,9 @@ public void setUp() throws Exception {
when(fm.getFlags()).thenReturn(Collections.emptyList());

// The database type has to be created one line before the thenReturn() to work!
when(plugin.getSettings()).thenReturn(settings);
DatabaseType value = DatabaseType.JSON;
when(settings.getDatabaseType()).thenReturn(value);
when(plugin.getSettings()).thenReturn(pluginSettings);
when(pluginSettings.getDatabaseType()).thenReturn(value);

// Bukkit
PowerMockito.mockStatic(Bukkit.class);
Expand Down Expand Up @@ -243,6 +253,7 @@ public void tearDown() throws Exception {
public static void cleanUp() throws Exception {
new File("addon.jar").delete();
new File("config.yml").delete();
new File("blockconfig.yml").delete();
deleteAll(new File("addons"));
}

Expand All @@ -261,7 +272,7 @@ private static void deleteAll(File file) throws IOException {
@Test
public void testOnEnable() {
addon.onEnable();
verify(plugin).logWarning("[Level] Level Addon: No such world in config.yml : acidisland_world");
verify(plugin).logWarning("[Level] Level Addon: No such world in blockconfig.yml : acidisland_world");
verify(plugin).log("[Level] Level hooking into BSkyBlock");
verify(cmd, times(3)).getAddon(); // Three commands
verify(adminCmd, times(2)).getAddon(); // Two commands
Expand Down Expand Up @@ -311,8 +322,8 @@ public void testGetLevelsDataUnknown() {
@Test
public void testGetSettings() {
addon.onEnable();
world.bentobox.level.config.BlockConfig s = addon.getSettings();
assertEquals(100, s.getDeathPenalty());
ConfigSettings s = addon.getSettings();
assertEquals(100, s.getLevelCost());
}

/**
Expand Down

0 comments on commit c463170

Please sign in to comment.