diff --git a/LICENSE b/LICENSE
index 5102ff96..c4e8ca16 100644
--- a/LICENSE
+++ b/LICENSE
@@ -6,12 +6,12 @@ Things can you CANNOT do:
 - Issue a refund on PayPal without our explicit permission, as this is a digital good.
 - Redistribute, sell or give an official/modified version of the plugin (with or without any type of counterpart) to anyone else.
 - Modify and compile the project source code to bypass an anti-piracy protection.
-- Download, compile, decompile or use the plugin on a production server without purchasing a license.
+- Download, compile, decompile or use the plugin on any server without purchasing a license.
 
 Things can you CAN do when purchasing the plugin:
 - Download and decompile the plugin file.
 - Fork and modify the project source code to meet your production server's needs.
-- Use it on ONE production server or network (= proxy-connected servers) at a time.
+- Use it on ONE production server or network (= proxy-connected servers) and one private test server at a time.
 
 You may propose a merge request, under the terms that you grant full rights to us using any pushed code.
 
diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/MMOCore.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/MMOCore.java
index 103362ea..d1ec3e6e 100644
--- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/MMOCore.java
+++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/MMOCore.java
@@ -275,25 +275,12 @@ public class MMOCore extends JavaPlugin {
     @Override
     public void onDisable() {
 
-        // Executes all the pending asynchronous task (like saving the playerData)
-        Bukkit.getScheduler().getPendingTasks().forEach(worker -> {
-            if (worker.getOwner().equals(this)) {
-                ((Runnable) worker).run();
-            }
-        });
-
-        // Save player data
-        for (PlayerData data : PlayerData.getAll())
-            if (data.isSynchronized()) {
-                data.close();
-                dataProvider.getDataManager().getDataHandler().saveData(data, true);
-            }
-
         // Save guild info
         for (Guild guild : dataProvider.getGuildManager().getAll())
             dataProvider.getGuildManager().save(guild);
 
         // Close MySQL data provider (memory leaks)
+        playerDataManager.saveAll(false);
         playerDataManager.getDataHandler().close();
 
         // Reset active blocks
diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/load/DefaultMMOLoader.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/load/DefaultMMOLoader.java
index 6be9b448..677dac71 100644
--- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/load/DefaultMMOLoader.java
+++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/load/DefaultMMOLoader.java
@@ -119,6 +119,12 @@ public class DefaultMMOLoader extends MMOLoader {
         if (config.getKey().equals("permission"))
             return new PermissionCondition(config);
 
+        if (config.getKey().equals("weather"))
+            return new WeatherCondition(config);
+
+        if (config.getKey().equals("time"))
+            return new TimeCondition(config);
+
         return null;
     }
 
diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/command/rpg/admin/ExportDataTreeNode.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/command/rpg/admin/ExportDataTreeNode.java
index 250962cd..f5b36328 100644
--- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/command/rpg/admin/ExportDataTreeNode.java
+++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/command/rpg/admin/ExportDataTreeNode.java
@@ -92,7 +92,7 @@ public class ExportDataTreeNode extends CommandTreeNode {
                         MMOCore.plugin.dataProvider.getDataManager().getDataHandler().loadData(offlinePlayerData);
 
                         // Player data is loaded, now it gets saved through SQL
-                        sqlHandler.saveData(offlinePlayerData, true);
+                        sqlHandler.saveData(offlinePlayerData, false);
                     } catch (RuntimeException exception) {
                         errorCount++;
                         exception.printStackTrace();
diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/loot/chest/condition/TimeCondition.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/loot/chest/condition/TimeCondition.java
new file mode 100644
index 00000000..1e0fc82e
--- /dev/null
+++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/loot/chest/condition/TimeCondition.java
@@ -0,0 +1,37 @@
+package net.Indyuce.mmocore.loot.chest.condition;
+
+import io.lumine.mythic.lib.api.MMOLineConfig;
+import org.apache.commons.lang.Validate;
+import org.bukkit.entity.Player;
+
+public class TimeCondition extends Condition {
+
+    private final int min;
+    private final int max;
+
+    public TimeCondition(MMOLineConfig config) {
+        super(config);
+
+        Validate.isTrue(config.contains("min"));
+        Validate.isTrue(config.contains("max"));
+
+        min = config.getInt("min");
+        max = config.getInt("max");
+    }
+
+    @Override
+    public boolean isMet(ConditionInstance entity) {
+        if (entity.getEntity() instanceof Player player) {
+            long time = player.getWorld().getTime();
+
+            if (min < max) {
+                return time > min && time < max;
+            } else {
+                // Allows for wrapping times, such as min=20000 max=6000
+                return time > min || time < max;
+            }
+        }
+
+        return false;
+    }
+}
diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/loot/chest/condition/WeatherCondition.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/loot/chest/condition/WeatherCondition.java
new file mode 100644
index 00000000..37285a1f
--- /dev/null
+++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/loot/chest/condition/WeatherCondition.java
@@ -0,0 +1,34 @@
+package net.Indyuce.mmocore.loot.chest.condition;
+
+import io.lumine.mythic.lib.api.MMOLineConfig;
+import org.apache.commons.lang.Validate;
+import org.bukkit.entity.Player;
+
+public class WeatherCondition extends Condition {
+
+    private final String condition;
+
+    public WeatherCondition(MMOLineConfig config) {
+        super(config);
+
+        Validate.isTrue(config.contains("condition"));
+
+        condition = config.getString("condition");
+    }
+
+    @Override
+    public boolean isMet(ConditionInstance entity) {
+        if (entity.getEntity() instanceof Player player) {
+            boolean isClear = player.getWorld().isClearWeather();
+            boolean hasStorm = player.getWorld().hasStorm();
+
+            if (condition.equalsIgnoreCase("clear")) {
+                return isClear;
+            } else if (condition.equalsIgnoreCase("stormy")) {
+                return hasStorm;
+            }
+        }
+
+        return false;
+    }
+}
diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/skill/cast/listener/KeyCombos.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/skill/cast/listener/KeyCombos.java
index 2028f842..e05758e4 100644
--- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/skill/cast/listener/KeyCombos.java
+++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/skill/cast/listener/KeyCombos.java
@@ -71,7 +71,7 @@ public class KeyCombos implements SkillCastingListener {
     public void whenPressingKey(PlayerKeyPressEvent event) {
         PlayerData playerData = event.getData();
         Player player = playerData.getPlayer();
-        if(player.getGameMode()== GameMode.CREATIVE&&!MMOCore.plugin.configManager.canCreativeCast)
+        if (player.getGameMode() == GameMode.CREATIVE && !MMOCore.plugin.configManager.canCreativeCast)
             return;
 
         // Start combo when there is an initializer key
@@ -82,9 +82,9 @@ public class KeyCombos implements SkillCastingListener {
                 if (event.getPressed().shouldCancelEvent()) event.setCancelled(true);
 
                 // Start combo
-                if (playerData.setSkillCasting(new CustomSkillCastingInstance(playerData))) {
-                    if (beginComboSound != null) beginComboSound.playTo(player);
-                }
+                if (playerData.setSkillCasting(new CustomSkillCastingInstance(playerData)) && beginComboSound != null)
+                    beginComboSound.playTo(player);
+
             }
             return;
         }
@@ -99,10 +99,8 @@ public class KeyCombos implements SkillCastingListener {
             final @NotNull ComboMap comboMap = Objects.requireNonNullElse(playerData.getProfess().getComboMap(), this.comboMap);
             if (comboMap.isComboStart(event.getPressed())) {
                 casting = new CustomSkillCastingInstance(playerData);
-                if (!playerData.setSkillCasting(casting)) {
-                    return;
-                }
-                if (beginComboSound != null) beginComboSound.playTo(player);
+                if (playerData.setSkillCasting(new CustomSkillCastingInstance(playerData)) && beginComboSound != null)
+                    beginComboSound.playTo(player);
             }
         }