CoinBombs and GemBombs now queue their amounts to prevent excessive database calls.
Removed excess account row information retrieval on web api when awarding gems/coins. Added account specific transactional locks in webapi.
This commit is contained in:
parent
ecad60eee3
commit
4254225462
@ -28,6 +28,7 @@ public class DonationManager extends MiniPlugin
|
||||
private Object _donorLock = new Object();
|
||||
|
||||
private NautHashMap<Player, NautHashMap<String, Integer>> _gemQueue = new NautHashMap<Player, NautHashMap<String, Integer>>();
|
||||
private NautHashMap<Player, NautHashMap<String, Integer>> _coinQueue = new NautHashMap<Player, NautHashMap<String, Integer>>();
|
||||
|
||||
public DonationManager(JavaPlugin plugin, String webAddress)
|
||||
{
|
||||
@ -247,4 +248,56 @@ public class DonationManager extends MiniPlugin
|
||||
}
|
||||
}, caller, name, uuid.toString(), amount);
|
||||
}
|
||||
|
||||
public void RewardCoinsLater(final String caller, final Player player, final int amount)
|
||||
{
|
||||
if (!_coinQueue.containsKey(player))
|
||||
_coinQueue.put(player, new NautHashMap<String, Integer>());
|
||||
|
||||
int totalAmount = amount;
|
||||
|
||||
if (_coinQueue.get(player).containsKey(caller))
|
||||
totalAmount += _coinQueue.get(player).get(caller);
|
||||
|
||||
_coinQueue.get(player).put(caller, totalAmount);
|
||||
|
||||
//Do Temp Change
|
||||
Donor donor = Get(player.getName());
|
||||
|
||||
if (donor != null)
|
||||
donor.addCoins(amount);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void UpdateCoinQueue(UpdateEvent event)
|
||||
{
|
||||
if (event.getType() != UpdateType.SLOWER)
|
||||
return;
|
||||
|
||||
for (Player player : _coinQueue.keySet())
|
||||
{
|
||||
String caller = null;
|
||||
int total = 0;
|
||||
|
||||
for (String curCaller : _coinQueue.get(player).keySet())
|
||||
{
|
||||
caller = curCaller;
|
||||
total += _coinQueue.get(player).get(curCaller);
|
||||
}
|
||||
|
||||
if (caller == null)
|
||||
continue;
|
||||
|
||||
//Actually Add Gems
|
||||
RewardCoins(null, caller, player.getName(), player.getUniqueId(), total, false);
|
||||
|
||||
System.out.println("Queue Added [" + player + "] with Coins [" + total + "] for [" + caller + "]");
|
||||
|
||||
//Clean
|
||||
_coinQueue.get(player).clear();
|
||||
}
|
||||
|
||||
//Clean
|
||||
_coinQueue.clear();
|
||||
}
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ public class ItemCoinBomb extends ItemGadget
|
||||
event.setCancelled(true);
|
||||
event.getItem().remove();
|
||||
|
||||
Manager.getDonationManager().RewardCoins(null, this.GetName() + " Pickup", event.getPlayer().getName(), event.getPlayer().getUniqueId(), 4);
|
||||
Manager.getDonationManager().RewardCoinsLater(GetName() + " Pickup", event.getPlayer(), 4);
|
||||
|
||||
event.getPlayer().getWorld().playSound(event.getPlayer().getLocation(), Sound.ORB_PICKUP, 1f, 2f);
|
||||
|
||||
|
@ -189,7 +189,7 @@ public class ItemGemBomb extends ItemGadget
|
||||
event.setCancelled(true);
|
||||
event.getItem().remove();
|
||||
|
||||
Manager.getDonationManager().RewardGems(null, this.GetName() + " Pickup", event.getPlayer().getName(), event.getPlayer().getUniqueId(), 4);
|
||||
Manager.getDonationManager().RewardGemsLater(GetName() + " Pickup", event.getPlayer(), 4);
|
||||
|
||||
event.getPlayer().getWorld().playSound(event.getPlayer().getLocation(), Sound.ORB_PICKUP, 1f, 2f);
|
||||
}
|
||||
|
@ -143,7 +143,7 @@ public class MorphVillager extends MorphGadget implements IThrown
|
||||
event.setCancelled(true);
|
||||
event.getItem().remove();
|
||||
|
||||
Manager.getDonationManager().RewardGems(null, this.GetName() + " Pickup", event.getPlayer().getName(), event.getPlayer().getUniqueId(), 16);
|
||||
Manager.getDonationManager().RewardGemsLater(GetName() + " Pickup", event.getPlayer(), 16);
|
||||
|
||||
event.getPlayer().getWorld().playSound(event.getPlayer().getLocation(), Sound.ORB_PICKUP, 1f, 2f);
|
||||
}
|
||||
|
@ -2,10 +2,14 @@
|
||||
{
|
||||
public class GemRewardToken
|
||||
{
|
||||
public int OriginalBalance;
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public string Source { get; set; }
|
||||
|
||||
public int Amount { get; set; }
|
||||
|
||||
public int Retries { get; set; }
|
||||
}
|
||||
}
|
@ -7,5 +7,7 @@
|
||||
public string Rank { get; set; }
|
||||
|
||||
public bool Perm { get; set; }
|
||||
|
||||
public int Retries { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
using LOC.Website.Common.Contexts;
|
||||
using System.Data.Entity.Infrastructure;
|
||||
using System.Transactions;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
public class AccountAdministrator : IAccountAdministrator
|
||||
{
|
||||
@ -23,7 +24,7 @@
|
||||
private readonly IGameServerMonitor _gameServerMonitor;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
private readonly object _transactionLock = new object();
|
||||
private static ConditionalWeakTable<string, object> _accountLocks = new ConditionalWeakTable<string, object>();
|
||||
|
||||
public AccountAdministrator(INautilusRepositoryFactory nautilusRepositoryFactory, ILogger logger)
|
||||
{
|
||||
@ -64,47 +65,66 @@
|
||||
}
|
||||
}
|
||||
|
||||
private object getAccountLock(string name)
|
||||
{
|
||||
object lockObject = null;
|
||||
|
||||
if (!_accountLocks.TryGetValue(name, out lockObject))
|
||||
{
|
||||
lockObject = new object();
|
||||
_accountLocks.Add(name, lockObject);
|
||||
}
|
||||
|
||||
return lockObject;
|
||||
}
|
||||
|
||||
public Account Login(LoginRequestToken loginToken)
|
||||
{
|
||||
using (var repository = _repositoryFactory.CreateRepository())
|
||||
lock (getAccountLock(loginToken.Name))
|
||||
{
|
||||
var account = repository.Where<Account>(x => x.Uuid == loginToken.Uuid).FirstOrDefault() ?? CreateAccount(loginToken, repository);
|
||||
account.LoadNavigationProperties(repository.Context);
|
||||
account.LastLogin = DateTime.Now.Ticks;
|
||||
|
||||
// Expire punishments
|
||||
if (account.Punishments != null)
|
||||
using (var repository = _repositoryFactory.CreateRepository())
|
||||
{
|
||||
foreach (var expiredPunishment in account.Punishments.Where(x => x.Active && (x.Duration - 0d) > 0 && TimeUtil.GetCurrentMilliseconds() > (x.Time + (x.Duration * 3600000))))
|
||||
var account = repository.Where<Account>(x => x.Uuid == loginToken.Uuid).FirstOrDefault() ?? (repository.Where<Account>(x => x.Name == loginToken.Name).FirstOrDefault() ?? CreateAccount(loginToken, repository));
|
||||
account.LoadNavigationProperties(repository.Context);
|
||||
account.LastLogin = DateTime.Now.Ticks;
|
||||
|
||||
if (String.IsNullOrEmpty(account.Uuid))
|
||||
account.Uuid = loginToken.Uuid;
|
||||
|
||||
// Expire punishments
|
||||
if (account.Punishments != null)
|
||||
{
|
||||
expiredPunishment.Active = false;
|
||||
foreach (var expiredPunishment in account.Punishments.Where(x => x.Active && (x.Duration - 0d) > 0 && TimeUtil.GetCurrentMilliseconds() > (x.Time + (x.Duration * 3600000))))
|
||||
{
|
||||
expiredPunishment.Active = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Insert UUID if not there
|
||||
if (String.IsNullOrEmpty(account.Uuid) && !String.IsNullOrEmpty(loginToken.Uuid))
|
||||
{
|
||||
account.Uuid = loginToken.Uuid;
|
||||
}
|
||||
|
||||
// Update account name if changed
|
||||
if (!String.Equals(account.Name, loginToken.Name))
|
||||
{
|
||||
account.Name = loginToken.Name;
|
||||
}
|
||||
|
||||
/*
|
||||
// Expire ranks
|
||||
if ((account.Rank.Name == "ULTRA" || account.Rank.Name == "HERO") && !account.RankPerm && DateTime.Now.CompareTo(account.RankExpire) >= 0)
|
||||
{
|
||||
account.Rank = repository.Where<Rank>(x => x.Name == "ALL").First();
|
||||
repository.Attach(account.Rank);
|
||||
}
|
||||
* */
|
||||
|
||||
repository.CommitChanges();
|
||||
|
||||
return account;
|
||||
}
|
||||
|
||||
// Insert UUID if not there
|
||||
if (String.IsNullOrEmpty(account.Uuid) && !String.IsNullOrEmpty(loginToken.Uuid))
|
||||
{
|
||||
account.Uuid = loginToken.Uuid;
|
||||
}
|
||||
|
||||
// Update account name if changed
|
||||
if (!String.Equals(account.Name, loginToken.Name))
|
||||
{
|
||||
account.Name = loginToken.Name;
|
||||
}
|
||||
|
||||
/*
|
||||
// Expire ranks
|
||||
if ((account.Rank.Name == "ULTRA" || account.Rank.Name == "HERO") && !account.RankPerm && DateTime.Now.CompareTo(account.RankExpire) >= 0)
|
||||
{
|
||||
account.Rank = repository.Where<Rank>(x => x.Name == "ALL").First();
|
||||
repository.Attach(account.Rank);
|
||||
}
|
||||
* */
|
||||
|
||||
repository.CommitChanges();
|
||||
|
||||
return account;
|
||||
}
|
||||
}
|
||||
|
||||
@ -194,31 +214,33 @@
|
||||
|
||||
public bool GemReward(GemRewardToken token)
|
||||
{
|
||||
using (var repository = _repositoryFactory.CreateRepository())
|
||||
lock (getAccountLock(token.Name))
|
||||
{
|
||||
var account = repository.Where<Account>(x => x.Name == token.Name).FirstOrDefault();
|
||||
account.LoadNavigationProperties(repository.Context);
|
||||
|
||||
if (account == null)
|
||||
return false;
|
||||
|
||||
account.Gems += token.Amount;
|
||||
|
||||
if (!token.Source.Contains("Earned") && !token.Source.Contains("Tutorial") && !token.Source.Contains("Parkour"))
|
||||
using (var repository = _repositoryFactory.CreateRepository())
|
||||
{
|
||||
var gemTransaction = new GemTransaction
|
||||
{
|
||||
Source = token.Source,
|
||||
Account = account,
|
||||
Amount = token.Amount,
|
||||
Date = (long)TimeUtil.GetCurrentMilliseconds()
|
||||
};
|
||||
var account = repository.Where<Account>(x => x.Name == token.Name).FirstOrDefault();
|
||||
|
||||
repository.Add<GemTransaction>(gemTransaction);
|
||||
if (account == null)
|
||||
return false;
|
||||
|
||||
account.Gems += token.Amount;
|
||||
|
||||
if (!token.Source.Contains("Earned") && !token.Source.Contains("Tutorial") && !token.Source.Contains("Parkour"))
|
||||
{
|
||||
var gemTransaction = new GemTransaction
|
||||
{
|
||||
Source = token.Source,
|
||||
Account = account,
|
||||
Amount = token.Amount,
|
||||
Date = (long)TimeUtil.GetCurrentMilliseconds()
|
||||
};
|
||||
|
||||
repository.Add<GemTransaction>(gemTransaction);
|
||||
}
|
||||
|
||||
repository.Edit(account);
|
||||
repository.CommitChanges();
|
||||
}
|
||||
|
||||
repository.Edit(account);
|
||||
repository.CommitChanges();
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -226,31 +248,35 @@
|
||||
|
||||
public bool CoinReward(GemRewardToken token)
|
||||
{
|
||||
using (var repository = _repositoryFactory.CreateRepository())
|
||||
lock (getAccountLock(token.Name))
|
||||
{
|
||||
var account = repository.Where<Account>(x => x.Name == token.Name).FirstOrDefault();
|
||||
account.LoadNavigationProperties(repository.Context);
|
||||
|
||||
if (account == null)
|
||||
return false;
|
||||
|
||||
account.Coins += token.Amount;
|
||||
|
||||
if (!token.Source.Contains("Earned") && !token.Source.Contains("Tutorial") && !token.Source.Contains("Parkour"))
|
||||
using (var repository = _repositoryFactory.CreateRepository())
|
||||
{
|
||||
var coinTransaction = new CoinTransaction
|
||||
var account = repository.Where<Account>(x => x.Name == token.Name).FirstOrDefault();
|
||||
|
||||
if (account == null)
|
||||
return false;
|
||||
|
||||
token.OriginalBalance = account.Coins;
|
||||
account.Coins += token.Amount;
|
||||
|
||||
if (!token.Source.Contains("Earned") && !token.Source.Contains("Tutorial") && !token.Source.Contains("Parkour"))
|
||||
{
|
||||
Source = token.Source,
|
||||
Account = account,
|
||||
Amount = token.Amount,
|
||||
Date = (long)TimeUtil.GetCurrentMilliseconds()
|
||||
};
|
||||
var coinTransaction = new CoinTransaction
|
||||
{
|
||||
Source = token.Source,
|
||||
Account = account,
|
||||
Amount = token.Amount,
|
||||
Date = (long)TimeUtil.GetCurrentMilliseconds()
|
||||
};
|
||||
|
||||
repository.Add<CoinTransaction>(coinTransaction);
|
||||
}
|
||||
|
||||
repository.Edit(account);
|
||||
repository.CommitChanges();
|
||||
|
||||
repository.Add<CoinTransaction>(coinTransaction);
|
||||
}
|
||||
|
||||
repository.Edit(account);
|
||||
repository.CommitChanges();
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -358,9 +384,9 @@
|
||||
|
||||
public string PurchaseGameSalesPackage(PurchaseToken token)
|
||||
{
|
||||
lock (_transactionLock)
|
||||
try
|
||||
{
|
||||
try
|
||||
lock (getAccountLock(token.AccountName))
|
||||
{
|
||||
using (var repository = _repositoryFactory.CreateRepository())
|
||||
{
|
||||
@ -390,7 +416,7 @@
|
||||
repository.Edit(account);
|
||||
|
||||
if (account.PvpTransactions == null)
|
||||
account.PvpTransactions = new List<GameTransaction> {accountTransaction};
|
||||
account.PvpTransactions = new List<GameTransaction> { accountTransaction };
|
||||
else
|
||||
{
|
||||
account.PvpTransactions.Add(accountTransaction);
|
||||
@ -403,10 +429,10 @@
|
||||
return TransactionResponse.Success.ToString();
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
return TransactionResponse.Failed.ToString() + ":" + exception.Message;
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
return TransactionResponse.Failed.ToString() + ":" + exception.Message;
|
||||
}
|
||||
}
|
||||
|
||||
@ -420,43 +446,46 @@
|
||||
|
||||
public void SaveCustomBuild(CustomBuildToken token)
|
||||
{
|
||||
using (var repository = _repositoryFactory.CreateRepository())
|
||||
lock (getAccountLock(token.PlayerName))
|
||||
{
|
||||
var account =
|
||||
repository.Where<Account>(x => x.Name == token.PlayerName).Include(x => x.CustomBuilds).First();
|
||||
|
||||
var customBuild =
|
||||
account.CustomBuilds.FirstOrDefault(
|
||||
x => String.Equals(x.PvpClass, token.PvpClass) && x.CustomBuildNumber == token.CustomBuildNumber);
|
||||
|
||||
if (customBuild == null)
|
||||
using (var repository = _repositoryFactory.CreateRepository())
|
||||
{
|
||||
customBuild = repository.Add(token.GetCustomBuild());
|
||||
account.CustomBuilds.Add(customBuild);
|
||||
}
|
||||
else
|
||||
{
|
||||
token.UpdateCustomBuild(customBuild);
|
||||
repository.Edit(customBuild);
|
||||
}
|
||||
var account =
|
||||
repository.Where<Account>(x => x.Name == token.PlayerName).Include(x => x.CustomBuilds).First();
|
||||
|
||||
if (customBuild.Active)
|
||||
{
|
||||
foreach (
|
||||
var otherClassBuild in
|
||||
account.CustomBuilds.Where(
|
||||
x =>
|
||||
String.Equals(x.PvpClass, token.PvpClass) && x.CustomBuildNumber != customBuild.CustomBuildNumber)
|
||||
.ToList())
|
||||
var customBuild =
|
||||
account.CustomBuilds.FirstOrDefault(
|
||||
x => String.Equals(x.PvpClass, token.PvpClass) && x.CustomBuildNumber == token.CustomBuildNumber);
|
||||
|
||||
if (customBuild == null)
|
||||
{
|
||||
otherClassBuild.Active = false;
|
||||
repository.Edit(otherClassBuild);
|
||||
customBuild = repository.Add(token.GetCustomBuild());
|
||||
account.CustomBuilds.Add(customBuild);
|
||||
}
|
||||
else
|
||||
{
|
||||
token.UpdateCustomBuild(customBuild);
|
||||
repository.Edit(customBuild);
|
||||
}
|
||||
}
|
||||
|
||||
repository.Edit(account);
|
||||
|
||||
repository.CommitChanges();
|
||||
if (customBuild.Active)
|
||||
{
|
||||
foreach (
|
||||
var otherClassBuild in
|
||||
account.CustomBuilds.Where(
|
||||
x =>
|
||||
String.Equals(x.PvpClass, token.PvpClass) && x.CustomBuildNumber != customBuild.CustomBuildNumber)
|
||||
.ToList())
|
||||
{
|
||||
otherClassBuild.Active = false;
|
||||
repository.Edit(otherClassBuild);
|
||||
}
|
||||
}
|
||||
|
||||
repository.Edit(account);
|
||||
|
||||
repository.CommitChanges();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -486,9 +515,9 @@
|
||||
|
||||
public string PurchaseUnknownSalesPackage(UnknownPurchaseToken token)
|
||||
{
|
||||
lock (_transactionLock)
|
||||
try
|
||||
{
|
||||
try
|
||||
lock (getAccountLock(token.AccountName))
|
||||
{
|
||||
using (var repository = _repositoryFactory.CreateRepository())
|
||||
{
|
||||
@ -532,16 +561,17 @@
|
||||
return TransactionResponse.Success.ToString();
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
return TransactionResponse.Failed.ToString() + ":" + exception.Message;
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
return TransactionResponse.Failed.ToString() + ":" + exception.Message;
|
||||
}
|
||||
}
|
||||
|
||||
public string UpdateRank(RankUpdateToken token)
|
||||
{
|
||||
Rank rank = null;
|
||||
var expire = DateTime.Now.AddMonths(1).AddMilliseconds(-DateTime.Now.Millisecond);
|
||||
|
||||
try
|
||||
{
|
||||
@ -559,8 +589,6 @@
|
||||
if (rank == null)
|
||||
return account.Rank.ToString();
|
||||
|
||||
var expire = DateTime.Now.AddMonths(1).AddMilliseconds(-DateTime.Now.Millisecond);
|
||||
|
||||
account.Rank = rank;
|
||||
account.RankExpire = expire;
|
||||
account.RankPerm = token.Perm;
|
||||
@ -574,7 +602,14 @@
|
||||
using (var repository = _repositoryFactory.CreateRepository())
|
||||
{
|
||||
var account = repository.Where<Account>(x => String.Equals(x.Name, token.Name)).Include(x => x.Rank).FirstOrDefault();
|
||||
_logger.Log("INFO", "ACCOUNT " + account.Name + "'s rank is " + account.Rank.Name + " " + (account.RankPerm ? "Permanently" : "Monthly") + "." + " Rank expire : " + account.RankExpire.ToString());
|
||||
|
||||
if (token.Retries >= 3)
|
||||
_logger.Log("ERROR", "Applying UpdateRank, retried 3 times and something didn't stick.");
|
||||
else if (!account.Rank.Name.Equals(token.Rank) || account.RankPerm != token.Perm || account.RankExpire != expire)
|
||||
{
|
||||
token.Retries++;
|
||||
UpdateRank(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Loading…
Reference in New Issue
Block a user