From b1a46d0f0da4fd3adc9b4b5393b5ed1fa77fd55e Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Mon, 11 May 2015 01:21:27 -0700 Subject: [PATCH] Converted TaskManager --- .../src/mineplex/core/task/Task.java | 13 ++ .../src/mineplex/core/task/TaskClient.java | 9 +- .../src/mineplex/core/task/TaskManager.java | 122 ++++++++++++++---- .../core/task/repository/TaskRepository.java | 77 +++++++++-- .../Mineplex.Hub/src/mineplex/hub/Hub.java | 2 +- .../mineplex/hub/modules/ParkourManager.java | 15 ++- .../hub/tutorial/TutorialManager.java | 18 ++- .../src/mineplex/serverdata/Utility.java | 4 +- .../nautilus/game/arcade/ArcadeManager.java | 2 +- .../managers/GameAchievementManager.java | 14 +- Website/LOCWebsite.suo | Bin 474624 -> 474624 bytes 11 files changed, 218 insertions(+), 58 deletions(-) create mode 100644 Plugins/Mineplex.Core/src/mineplex/core/task/Task.java diff --git a/Plugins/Mineplex.Core/src/mineplex/core/task/Task.java b/Plugins/Mineplex.Core/src/mineplex/core/task/Task.java new file mode 100644 index 000000000..de88ecb84 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/task/Task.java @@ -0,0 +1,13 @@ +package mineplex.core.task; + +public class Task +{ + public int Id; + public String Name; + + public Task(int id, String name) + { + Id = id; + Name = name; + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/task/TaskClient.java b/Plugins/Mineplex.Core/src/mineplex/core/task/TaskClient.java index 44b1ce88b..22f565d58 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/task/TaskClient.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/task/TaskClient.java @@ -5,17 +5,10 @@ import java.util.List; public class TaskClient { - public String Name; public List TasksCompleted; - public TaskClient(String name) + public TaskClient() { - Name = name; TasksCompleted = new ArrayList(); } - - public String toString() - { - return Name + " Tasks: {" + TasksCompleted.toString() + "}"; - } } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/task/TaskManager.java b/Plugins/Mineplex.Core/src/mineplex/core/task/TaskManager.java index 297409df4..75f7bbe52 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/task/TaskManager.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/task/TaskManager.java @@ -1,42 +1,88 @@ package mineplex.core.task; -import org.bukkit.craftbukkit.libs.com.google.gson.Gson; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; +import java.util.UUID; + +import org.bukkit.Bukkit; import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; import org.bukkit.plugin.java.JavaPlugin; -import mineplex.core.MiniClientPlugin; -import mineplex.core.account.event.ClientWebResponseEvent; +import mineplex.core.MiniDbClientPlugin; +import mineplex.core.account.CoreClientManager; +import mineplex.core.common.util.Callback; +import mineplex.core.common.util.NautHashMap; import mineplex.core.task.repository.TaskRepository; -import mineplex.core.task.repository.TaskToken; -public class TaskManager extends MiniClientPlugin +public class TaskManager extends MiniDbClientPlugin { + private static Object _taskLock = new Object(); private TaskRepository _repository; - public TaskManager(JavaPlugin plugin, String webServerAddress) + private NautHashMap _tasks = new NautHashMap(); + + public TaskManager(JavaPlugin plugin, CoreClientManager clientManager, String webServerAddress) { - super("Task Manager", plugin); + super("Task Manager", plugin, clientManager); - _repository = new TaskRepository(webServerAddress); + _repository = new TaskRepository(plugin); + updateTasks(); } + private void updateTasks() + { + List tasks = _repository.retrieveTasks(); + + synchronized (_taskLock) + { + for (Task task : tasks) + { + _tasks.put(task.Name, task.Id); + } + } + } + @Override protected TaskClient AddPlayer(String playerName) { - return new TaskClient(playerName); + return new TaskClient(); } - @EventHandler - public void OnClientWebResponse(ClientWebResponseEvent event) + public void addTaskForOfflinePlayer(final Callback callback, final UUID uuid, final String task) { - TaskToken token = new Gson().fromJson(event.GetResponse(), TaskToken.class); - TaskClient client = new TaskClient(token.Name); - - if (token.TasksCompleted != null) - client.TasksCompleted = token.TasksCompleted; - - Set(token.Name, client); + Bukkit.getServer().getScheduler().runTaskAsynchronously(getPlugin(), new Runnable() + { + public void run() + { + synchronized (_taskLock) + { + if (!_tasks.containsKey(task)) + { + _repository.addTask(task); + System.out.println("TaskManager Adding Task : " + task); + } + } + + updateTasks(); + + synchronized (_taskLock) + { + final boolean success = _repository.addAccountTask(ClientManager.getCachedClientAccountId(uuid), _tasks.get(task)); + + if (callback != null) + { + Bukkit.getServer().getScheduler().runTask(getPlugin(), new Runnable() + { + public void run() + { + callback.run(success); + } + }); + } + } + } + }); } public boolean hasCompletedTask(Player player, String taskName) @@ -44,11 +90,41 @@ public class TaskManager extends MiniClientPlugin return Get(player.getName()).TasksCompleted.contains(taskName); } - public void completedTask(Player player, String taskName) + public void completedTask(final Callback callback, final Player player, final String taskName) { - TaskClient client = Get(player.getName()); - client.TasksCompleted.add(taskName); + Get(player.getName()).TasksCompleted.add(taskName); - _repository.AddTask(client.Name, taskName); + addTaskForOfflinePlayer(new Callback() + { + public void run(Boolean success) + { + if (!success) + { + System.out.println("Add task FAILED for " + player.getName()); + + if (_tasks.containsKey(taskName)) + { + Get(player.getName()).TasksCompleted.remove(taskName); + } + } + + if (callback != null) + { + callback.run(success); + } + } + }, player.getUniqueId(), taskName); + } + + @Override + public void processLoginResultSet(String playerName, ResultSet resultSet) throws SQLException + { + Set(playerName, _repository.loadClientInformation(resultSet)); + } + + @Override + public String getQuery(int accountId, String uuid, String name) + { + return "SELECT taskId FROM accountTasks WHERE accountId = '" + accountId + "';"; } } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/task/repository/TaskRepository.java b/Plugins/Mineplex.Core/src/mineplex/core/task/repository/TaskRepository.java index 0d79ba3f0..82d7d6d22 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/task/repository/TaskRepository.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/task/repository/TaskRepository.java @@ -1,22 +1,79 @@ package mineplex.core.task.repository; -import mineplex.core.server.remotecall.AsyncJsonWebCall; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; -public class TaskRepository +import org.bukkit.plugin.java.JavaPlugin; + +import mineplex.core.database.DBPool; +import mineplex.core.database.RepositoryBase; +import mineplex.core.database.ResultSetCallable; +import mineplex.core.database.column.ColumnInt; +import mineplex.core.database.column.ColumnVarChar; +import mineplex.core.task.Task; +import mineplex.core.task.TaskClient; + +public class TaskRepository extends RepositoryBase { - private String _webAddress; + private static String ADD_ACCOUNT_TASK = "INSERT INTO accountTasks (accountId, taskId) VALUES (?, ?);"; - public TaskRepository(String webServerAddress) + private static String ADD_TASK = "INSERT INTO tasks (name) VALUES (?);"; + private static String RETRIEVE_TASKS = "SELECT id, name FROM tasks;"; + + public TaskRepository(JavaPlugin plugin) { - _webAddress = webServerAddress; + super(plugin, DBPool.ACCOUNT); } - public void AddTask(String name, String newTask) + @Override + protected void initialize() { - UpdateTaskToken token = new UpdateTaskToken(); - token.Name = name; - token.NewTaskCompleted = newTask; + } + + @Override + protected void update() + { + } + + public boolean addAccountTask(int accountId, int taskId) + { + return executeUpdate(ADD_ACCOUNT_TASK, new ColumnInt("accountId", accountId), new ColumnInt("taskId", taskId)) > 0; + } + + public TaskClient loadClientInformation(ResultSet resultSet) throws SQLException + { + final TaskClient taskClient = new TaskClient(); + + while (resultSet.next()) + { + taskClient.TasksCompleted.add(resultSet.getString(1)); + } - new AsyncJsonWebCall(_webAddress + "PlayerAccount/AddTask").Execute(token); + return taskClient; + } + + public List retrieveTasks() + { + final List tasks = new ArrayList(); + + executeQuery(RETRIEVE_TASKS, new ResultSetCallable() + { + public void processResultSet(ResultSet resultSet) throws SQLException + { + while (resultSet.next()) + { + tasks.add(new Task(resultSet.getInt(1), resultSet.getString(2))); + } + } + }); + + return tasks; + } + + public void addTask(String task) + { + executeUpdate(ADD_TASK, new ColumnVarChar("name", 100, task)); } } diff --git a/Plugins/Mineplex.Hub/src/mineplex/hub/Hub.java b/Plugins/Mineplex.Hub/src/mineplex/hub/Hub.java index 7e4dc80e3..2e655c5a9 100644 --- a/Plugins/Mineplex.Hub/src/mineplex/hub/Hub.java +++ b/Plugins/Mineplex.Hub/src/mineplex/hub/Hub.java @@ -118,7 +118,7 @@ public class Hub extends JavaPlugin implements IRelation PartyManager partyManager = new PartyManager(this, portal, clientManager, preferenceManager); - HubManager hubManager = new HubManager(this, blockRestore, clientManager, donationManager, new ConditionManager(this), disguiseManager, new TaskManager(this, webServerAddress), portal, partyManager, preferenceManager, petManager, pollManager, statsManager, achievementManager, new HologramManager(this)); + HubManager hubManager = new HubManager(this, blockRestore, clientManager, donationManager, new ConditionManager(this), disguiseManager, new TaskManager(this, clientManager, webServerAddress), portal, partyManager, preferenceManager, petManager, pollManager, statsManager, achievementManager, new HologramManager(this)); QueueManager queueManager = new QueueManager(this, clientManager, donationManager, new EloManager(this, clientManager), partyManager); diff --git a/Plugins/Mineplex.Hub/src/mineplex/hub/modules/ParkourManager.java b/Plugins/Mineplex.Hub/src/mineplex/hub/modules/ParkourManager.java index 49d3d603e..b63561b50 100644 --- a/Plugins/Mineplex.Hub/src/mineplex/hub/modules/ParkourManager.java +++ b/Plugins/Mineplex.Hub/src/mineplex/hub/modules/ParkourManager.java @@ -390,18 +390,25 @@ public class ParkourManager extends MiniPlugin { final ParkourData fData = data; - _donationManager.RewardGems(new Callback() + _taskManager.completedTask(new Callback() { public void run(Boolean completed) { - UtilPlayer.message(player, F.main("Parkour", "You received " + F.elem(C.cGreen + fData.Gems + " Gems") + ".")); + _donationManager.RewardGems(new Callback() + { + public void run(Boolean completed) + { + UtilPlayer.message(player, F.main("Parkour", "You received " + F.elem(C.cGreen + fData.Gems + " Gems") + ".")); - _taskManager.completedTask(player, fData.Name); + //Sound + player.playSound(player.getLocation(), Sound.LEVEL_UP, 2f, 1.5f); + } + }, "Parkour " + fData.Name, player.getName(), player.getUniqueId(), fData.Gems); //Sound player.playSound(player.getLocation(), Sound.LEVEL_UP, 2f, 1.5f); } - }, "Parkour " + data.Name, player.getName(), player.getUniqueId(), data.Gems); + }, player, fData.Name); } } } diff --git a/Plugins/Mineplex.Hub/src/mineplex/hub/tutorial/TutorialManager.java b/Plugins/Mineplex.Hub/src/mineplex/hub/tutorial/TutorialManager.java index d48dc2be4..733bf058b 100644 --- a/Plugins/Mineplex.Hub/src/mineplex/hub/tutorial/TutorialManager.java +++ b/Plugins/Mineplex.Hub/src/mineplex/hub/tutorial/TutorialManager.java @@ -129,16 +129,22 @@ public class TutorialManager extends MiniPlugin //Gems if (!_taskManager.hasCompletedTask(player, tut.GetTask())) { - _donationManager.RewardGems(new Callback() + _taskManager.completedTask(new Callback() { public void run(Boolean completed) { - UtilPlayer.message(player, F.main("Tutorial", "You received " + F.elem(C.cGreen + tut.GetGems() + " Gems") + ".")); - _taskManager.completedTask(player, tut.GetTask()); - //Sound - player.playSound(player.getLocation(), Sound.LEVEL_UP, 2f, 1.5f); + _donationManager.RewardGems(new Callback() + { + public void run(Boolean completed) + { + UtilPlayer.message(player, F.main("Tutorial", "You received " + F.elem(C.cGreen + tut.GetGems() + " Gems") + ".")); + + //Sound + player.playSound(player.getLocation(), Sound.LEVEL_UP, 2f, 1.5f); + } + }, "Tutorial " + tut.GetTutName(), player.getName(), player.getUniqueId(), tut.GetGems()); } - }, "Tutorial " + tut.GetTutName(), player.getName(), player.getUniqueId(), tut.GetGems()); + }, player, tut.GetTask()); } } } diff --git a/Plugins/Mineplex.ServerData/src/mineplex/serverdata/Utility.java b/Plugins/Mineplex.ServerData/src/mineplex/serverdata/Utility.java index b848f99cd..bb64b0b2e 100644 --- a/Plugins/Mineplex.ServerData/src/mineplex/serverdata/Utility.java +++ b/Plugins/Mineplex.ServerData/src/mineplex/serverdata/Utility.java @@ -112,7 +112,9 @@ public class Utility */ public static JedisPool generatePool(ConnectionData connData) { - return new JedisPool(new JedisPoolConfig(), connData.getHost(), connData.getPort()); + JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); + jedisPoolConfig.setMaxWaitMillis(10); + return new JedisPool(jedisPoolConfig, connData.getHost(), connData.getPort()); } /** diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/ArcadeManager.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/ArcadeManager.java index 8c69eddb5..632552f4a 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/ArcadeManager.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/ArcadeManager.java @@ -252,7 +252,7 @@ public class ArcadeManager extends MiniPlugin implements IRelation _partyManager = new PartyManager(plugin, portal, _clientManager, preferences); _statsManager = new StatsManager(plugin, clientManager); - _taskManager = new TaskManager(plugin, webAddress); + _taskManager = new TaskManager(plugin, clientManager, webAddress); _achievementManager = new AchievementManager(_statsManager, clientManager, donationManager); _inventoryManager = inventoryManager; _cosmeticManager = cosmeticManager; diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/GameAchievementManager.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/GameAchievementManager.java index 6e1b295da..9997234f9 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/GameAchievementManager.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/GameAchievementManager.java @@ -106,14 +106,20 @@ public class GameAchievementManager implements Listener " " + F.elem(C.cGreen + C.Bold + "+" + type.getGemReward() + " Gems")); player.playSound(player.getLocation(), Sound.LEVEL_UP, 1f, 1f); - - Manager.GetDonation().RewardGems(new Callback() + + Manager.GetTaskManager().completedTask(new Callback() { public void run(Boolean completed) { - Manager.GetTaskManager().completedTask(player, type.getName()); + Manager.GetDonation().RewardGems(new Callback() + { + public void run(Boolean completed) + { + + } + }, type.getName(), player.getName(), player.getUniqueId(), type.getGemReward()); } - }, type.getName(), player.getName(), player.getUniqueId(), type.getGemReward()); + }, player, type.getName()); } else { diff --git a/Website/LOCWebsite.suo b/Website/LOCWebsite.suo index 2b103f237324a6eaa86dfcf9c60f6b65c8c18b4b..082599a5290fc00d2b32583da99071c4353f3f2e 100644 GIT binary patch delta 12904 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 delta 12844 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 I-edLu0zwrrKL7v#