Implement a new crown currency

This commit is contained in:
AlexTheCoder 2017-05-04 18:29:38 -04:00
parent f9f2e362c4
commit 6ffd10133e
3 changed files with 358 additions and 1 deletions

View File

@ -1,9 +1,12 @@
package mineplex.core.donation;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import org.bukkit.entity.Player;
@ -15,10 +18,14 @@ import mineplex.core.MiniClientPlugin;
import mineplex.core.ReflectivelyCreateMiniPlugin;
import mineplex.core.account.CoreClient;
import mineplex.core.account.CoreClientManager;
import mineplex.core.account.ILoginProcessor;
import mineplex.core.account.event.ClientUnloadEvent;
import mineplex.core.account.event.ClientWebResponseEvent;
import mineplex.core.common.currency.GlobalCurrency;
import mineplex.core.donation.command.CrownCommand;
import mineplex.core.donation.command.GemCommand;
import mineplex.core.donation.command.ShardCommand;
import mineplex.core.donation.crown.CrownRepository;
import mineplex.core.donation.gold.GoldRepository;
import mineplex.core.donation.repository.DonationRepository;
import mineplex.core.donation.repository.token.DonorTokenWrapper;
@ -40,7 +47,10 @@ public class DonationManager extends MiniClientPlugin<Donor>
private static final Gson GSON = new Gson();
private final Map<GlobalCurrency, LinkedList<CurrencyRewardData>> _attemptUntilSuccess = new HashMap<>();
private final Map<UUID, Integer> _crownBalance = new ConcurrentHashMap<>();
private final CrownRepository _crownRepository;
private final CoreClientManager _clientManager = require(CoreClientManager.class);
private final DonationRepository _repository;
@ -52,6 +62,36 @@ public class DonationManager extends MiniClientPlugin<Donor>
_repository = new DonationRepository();
_goldRepository = new GoldRepository();
_crownRepository = new CrownRepository();
_clientManager.addStoredProcedureLoginProcessor(new ILoginProcessor()
{
@Override
public String getName()
{
return "crown-balance-loader";
}
@Override
public void processLoginResultSet(String playerName, UUID uuid, int accountId, ResultSet resultSet) throws SQLException
{
boolean hasRow = resultSet.next();
if (hasRow)
{
_crownBalance.put(uuid, resultSet.getInt(1));
}
else
{
_crownBalance.put(uuid, 0);
}
}
@Override
public String getQuery(int accountId, String uuid, String name)
{
return "SELECT crownCount FROM accountCrowns WHERE accountId=" + accountId + ";";
}
});
UtilScheduler.runEvery(UpdateType.FAST, this::processCoinAttemptQueue);
}
@ -61,6 +101,7 @@ public class DonationManager extends MiniClientPlugin<Donor>
{
addCommand(new GemCommand(this));
addCommand(new ShardCommand(this));
addCommand(new CrownCommand(this));
}
@EventHandler
@ -75,6 +116,88 @@ public class DonationManager extends MiniClientPlugin<Donor>
{
return _goldRepository;
}
public int getCrowns(Player player)
{
return getCrowns(player.getUniqueId());
}
public int getCrowns(UUID uuid)
{
return _crownBalance.computeIfAbsent(uuid, key -> 0);
}
/**
* Adds an unknown sales package to the specified {@link Player}
*
* @param callback The callback which will be called on the main thread. Possible responses are:
* {@link TransactionResponse#InsufficientFunds}, when the player does not have enough of the currency
* {@link TransactionResponse#Success}, when everything worked fine
* {@link TransactionResponse#Failed}, when an known exception occured
* {@link TransactionResponse#AlreadyOwns}, when the player already owns the package
*/
public void purchaseUnknownSalesPackageCrown(Player player, String packageName, int cost, boolean oneTimePurchase, Consumer<TransactionResponse> callback)
{
purchaseUnknownSalesPackageCrown(_clientManager.Get(player), packageName, cost, oneTimePurchase, callback);
}
/**
* Adds an unknown sales package to the specified {@link CoreClient}
*
* @param callback The callback which will be called on the main thread. Possible responses are:
* {@link TransactionResponse#InsufficientFunds}, when the player does not have enough of the currency
* {@link TransactionResponse#Success}, when everything worked fine
* {@link TransactionResponse#Failed}, when an known exception occured
* {@link TransactionResponse#AlreadyOwns}, when the player already owns the package
*/
public void purchaseUnknownSalesPackageCrown(CoreClient client, String packageName, int cost, boolean oneTimePurchase, Consumer<TransactionResponse> callback)
{
Donor donor = Get(client.getUniqueId());
if (donor != null)
{
if (oneTimePurchase && donor.ownsUnknownSalesPackage(packageName))
{
if (callback != null)
{
callback.accept(TransactionResponse.AlreadyOwns);
}
return;
}
}
_crownRepository.consumeCrowns(result ->
{
if (result == TransactionResponse.Success)
{
if (_crownBalance.containsKey(client.getUniqueId()))
{
_crownBalance.put(client.getUniqueId(), _crownBalance.get(client.getUniqueId()) - cost);
}
_repository.purchaseUnknownSalesPackage(client.getName(), packageName, GlobalCurrency.GEM, 0, response ->
{
if (response == TransactionResponse.Success)
{
if (donor != null)
{
donor.addOwnedUnknownSalesPackage(packageName);
donor.addBalance(GlobalCurrency.GEM, 0);
}
}
if (callback != null)
{
callback.accept(response);
}
});
}
else if (callback != null)
{
callback.accept(result);
}
}, client.getAccountId(), cost);
}
/**
* Adds an unknown sales package to the specified {@link Player}
@ -187,6 +310,26 @@ public class DonationManager extends MiniClientPlugin<Donor>
callback.accept(response);
});
}
public void rewardCrowns(int crowns, Player player)
{
rewardCrowns(crowns, player, null);
}
public void rewardCrowns(int crowns, Player player, Consumer<Boolean> completed)
{
_crownRepository.rewardCrowns(success ->
{
if (success)
{
_crownBalance.merge(player.getUniqueId(), crowns, Integer::sum);
}
if (completed != null)
{
completed.accept(success);
}
}, _clientManager.Get(player).getAccountId(), crowns);
}
/**
* Rewards the specified {@link Player} with {@code amount} of {@code currency} because of {@code reason}
@ -405,4 +548,10 @@ public class DonationManager extends MiniClientPlugin<Donor>
{
return _clientManager;
}
@EventHandler
public void unloadCrownBalance(ClientUnloadEvent event)
{
_crownBalance.remove(event.getUniqueId());
}
}

View File

@ -0,0 +1,91 @@
package mineplex.core.donation.command;
import org.bukkit.entity.Player;
import mineplex.core.command.CommandBase;
import mineplex.core.common.Rank;
import mineplex.core.common.util.F;
import mineplex.core.common.util.UtilPlayer;
import mineplex.core.common.util.UtilServer;
import mineplex.core.donation.DonationManager;
public class CrownCommand extends CommandBase<DonationManager>
{
public CrownCommand(DonationManager plugin)
{
super(plugin, Rank.ADMIN, "crown");
}
@Override
public void Execute(final Player caller, String[] args)
{
if (args.length < 2)
{
UtilPlayer.message(caller, F.main("Crown", "Missing Args: " + F.elem("/crown <player> <amount>")));
return;
}
String targetName = args[0];
int amount;
try
{
amount = Integer.parseInt(args[1]);
}
catch (NumberFormatException ex)
{
UtilPlayer.message(caller, F.main("Crown", "Invalid crown Amount"));
return;
}
if (targetName.equalsIgnoreCase("@a"))
{
rewardAllCrowns(caller, amount);
}
else
{
Player target = UtilPlayer.searchExact(targetName);
if (target != null)
{
rewardCrowns(caller, target, amount);
}
else
{
UtilPlayer.message(caller, F.main("Crown", "Could not find player " + F.name(targetName)));
}
}
}
private void rewardAllCrowns(Player caller, int crowns)
{
if (crowns > 1000)
{
UtilPlayer.message(caller, F.main("Crown", "You can only give everybody 1000 crowns at a time."));
return;
}
for (Player player : UtilServer.getPlayers())
{
Plugin.rewardCrowns(crowns, player);
}
UtilPlayer.message(caller, F.main("Crown", "Gave everyone " + F.elem(crowns + " crowns")));
}
private void rewardCrowns(Player caller, Player target, int crowns)
{
Plugin.rewardCrowns(crowns, target, completed ->
{
if (completed)
{
UtilPlayer.message(caller, F.main("Crown", "You gave " + F.elem(crowns + " crowns") + " to " + F.name(target.getName()) + "."));
UtilPlayer.message(target, F.main("Crown", F.name(caller.getName()) + " gave you " + F.elem(crowns + " crowns") + "."));
}
else
{
UtilPlayer.message(caller, F.main("Crown", "There was an error giving " + F.elem(crowns + " crowns") + " to " + F.name(target.getName()) + "."));
}
});
}
}

View File

@ -0,0 +1,117 @@
package mineplex.core.donation.crown;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.bukkit.Bukkit;
import mineplex.core.common.util.Callback;
import mineplex.core.common.util.UtilServer;
import mineplex.core.server.util.TransactionResponse;
import mineplex.serverdata.database.DBPool;
public class CrownRepository
{
private static final String CREATE_TABLE = "CREATE TABLE accountCrowns (accountId INT(11) NOT NULL, crownCount INT NOT NULL, PRIMARY KEY (accountId), FOREIGN KEY (accountId) REFERENCES accounts(id));";
private static final String REWARD_ACCOUNT_CROWNS = "INSERT INTO accountCrowns (accountId, crownCount) VALUES (?, ?) ON DUPLICATE KEY UPDATE crownCount=crownCount+VALUES(crownCount);";
private static final String CONSUME_ACCOUNT_CROWNS = "UPDATE accountCrowns SET crownCount=(crownCount - ?) WHERE accountId=? AND crownCount >= ?;";
private static final String SET_ACCOUNT_CROWNS = "INSERT INTO accountCrowns (accountId, crownCount) VALUES (?, ?) ON DUPLICATE KEY UPDATE crownCount=VALUES(crownCount);";
public CrownRepository() {}
public void rewardCrowns(final Callback<Boolean> callback, final int accountId, final int crowns)
{
Bukkit.getScheduler().runTaskAsynchronously(UtilServer.getPlugin(), () ->
{
try (Connection connection = DBPool.getAccount().getConnection())
{
PreparedStatement statement = connection.prepareStatement(REWARD_ACCOUNT_CROWNS);
statement.setInt(1, accountId);
statement.setInt(2, crowns);
statement.executeUpdate();
if (callback != null)
{
Bukkit.getScheduler().runTask(UtilServer.getPlugin(), () -> callback.run(true));
}
}
catch (SQLException e)
{
e.printStackTrace();
if (callback != null)
{
Bukkit.getScheduler().runTask(UtilServer.getPlugin(), () -> callback.run(false));
}
}
});
}
public void consumeCrowns(final Callback<TransactionResponse> callback, final int accountId, final int crowns)
{
Bukkit.getScheduler().runTaskAsynchronously(UtilServer.getPlugin(), () ->
{
try (Connection connection = DBPool.getAccount().getConnection())
{
String baseStmt = "INSERT INTO accountCrowns (accountId, crownCount) VALUES (" + accountId + ", 0) ON DUPLICATE KEY UPDATE crownCount=crownCount;";
PreparedStatement statement = connection.prepareStatement(baseStmt + CONSUME_ACCOUNT_CROWNS);
statement.setInt(1, crowns);
statement.setInt(2, accountId);
statement.setInt(3, crowns);
statement.execute();
statement.getMoreResults();
final TransactionResponse response = statement.getUpdateCount() > 0 ? TransactionResponse.Success : TransactionResponse.InsufficientFunds;
if (callback != null)
{
Bukkit.getScheduler().runTask(UtilServer.getPlugin(), () -> callback.run(response));
}
}
catch (SQLException e)
{
e.printStackTrace();
if (callback != null)
{
Bukkit.getScheduler().runTask(UtilServer.getPlugin(), () -> callback.run(TransactionResponse.Failed));
}
}
});
}
public void setGold(final Callback<Boolean> callback, final int accountId, final int crowns)
{
if (crowns < 0)
{
throw new IllegalArgumentException("Crowns cannot be negative");
}
Bukkit.getScheduler().runTaskAsynchronously(UtilServer.getPlugin(), () ->
{
try (Connection connection = DBPool.getAccount().getConnection())
{
PreparedStatement statement = connection.prepareStatement(SET_ACCOUNT_CROWNS);
statement.setInt(1, accountId);
statement.setInt(2, crowns);
statement.executeUpdate();
if (callback != null)
{
Bukkit.getScheduler().runTask(UtilServer.getPlugin(), () -> callback.run(true));
}
}
catch (SQLException e)
{
e.printStackTrace();
if (callback != null)
{
Bukkit.getScheduler().runTask(UtilServer.getPlugin(), () -> callback.run(false));
}
}
});
}
}