Here is a simple reward system. The reward has a few types and the data will be the amount of currency given or the badge code given. When a player is given a reward, it will be added to the dictionary and processed when the check method has been called. The reward logs keep hold of what players have received what rewards, the key is the players id, and the value (i.e. a list of integers) is the rewards they have been given.
All rewards are loaded from the database into _rewards
so we know the details of them when processing (such as what reward type, how much, etc). It just seems better to load and cache them than call to the DB when processing a players rewards to get the information.
internal class RewardHandler { private readonly ConcurrentDictionary<int, Reward> _rewards; private readonly ConcurrentDictionary<int, List<int>> _rewardLogs; public RewardHandler() { _rewards = new ConcurrentDictionary<int, Reward>(); _rewardLogs = new ConcurrentDictionary<int, List<int>>(); } public void Load() { if (_rewards.Count > 0) { _rewards.Clear(); } if (_rewardLogs.Count > 0) { _rewardLogs.Clear(); } using (var dbConnection = Program.Server.DatabaseHandler.Connection) { dbConnection.SetQuery("SELECT * FROM `server_rewards` WHERE enabled = '1'"); using (var reader = dbConnection.ExecuteReader()) { var reward = new Reward( reader.GetDouble("reward_start"), reader.GetDouble("reward_end"), reader.GetString("reward_type"), reader.GetString("reward_data"), reader.GetString("message") ); if (!_rewards.TryAdd(reader.GetInt32("id"), reward)) { // TODO: Log a message? } } dbConnection.SetQuery("SELECT * FROM `server_reward_logs`"); using (var reader = dbConnection.ExecuteReader()) { var userId = reader.GetInt32("user_id"); var rewardId = reader.GetInt32("reward_id"); if (!_rewardLogs.ContainsKey(userId)) _rewardLogs.TryAdd(userId, new List<int>()); if (!_rewardLogs[userId].Contains(rewardId)) _rewardLogs[userId].Add(rewardId); } } } public bool PlayerHasReward(int userId, int rewardId) { return _rewardLogs.ContainsKey(userId) && _rewardLogs[userId].Contains(rewardId); } public void CreateLog(int userId, int rewardId) { if (!_rewardLogs.ContainsKey(userId)) { _rewardLogs.TryAdd(userId, new List<int>()); } if (!_rewardLogs[userId].Contains(rewardId)) { _rewardLogs[userId].Add(rewardId); } using (var dbConnection = Program.Server.DatabaseHandler.Connection) { dbConnection.SetQuery("INSERT INTO `server_reward_logs` (`user_id`, `reward_id`) VALUES (@userId, @rewardId)"); dbConnection.AppendParameter("userId", userId); dbConnection.AppendParameter("rewardId", rewardId); dbConnection.ExecuteNonQuery(); } } public void CheckRewardsForPlayer(Player player) { if (player == null) { return; } foreach (var reward in _rewards) { if (PlayerHasReward(player.Id, reward.Key)) { continue; } if (!reward.Value.IsActive()) { continue; } switch (reward.Value.Type) { case RewardType.Badge: player.GetBadgeComponent().GiveBadgeIfNotGot(reward.Value.Data, true); break; case RewardType.Credits: player.Credits += reward.Value.Data.ToInt(); player.SendPacket(new CreditBalanceComposer(player.Credits)); break; case RewardType.Duckets: player.Duckets += reward.Value.Data.ToInt(); player.SendPacket(new HabboActivityPointNotificationComposer(player.Duckets, reward.Value.Data.ToInt())); break; case RewardType.Diamonds: player.Diamonds += reward.Value.Data.ToInt(); player.SendPacket(new HabboActivityPointNotificationComposer(player.Diamonds, reward.Value.Data.ToInt(), 5)); break; } var message = reward.Value.Message; if (string.IsNullOrEmpty(message)) { player.SendNotification(message); } CreateLog(player.Id, reward.Key); } } }
internal class Reward { public double Start; public double End; public RewardType Type; public string Data; public string Message; public Reward(double start, double end, RewardType type, string data, string message) { Start = start; End = end; Type = type; Data = data; Message = message; } public bool IsActive() { var unixNow = UnixTimestamp.GetNow(); return unixNow >= Start && unixNow <= End; } }