using System; using System.Collections.Generic; using System.Globalization; using Newtonsoft.Json; using Oxide.Core; using UnityEngine; using Oxide.Core.Database; namespace Oxide.Plugins { [Info("CustomAdventCalendar", "ThePitereq", "2.0.1")] public class CustomAdventCalendar : RustPlugin { private Core.MySql.Libraries.MySql sqlLibrary = Interface.Oxide.GetLibrary(); private Connection sqlConnection; private List blockedRedeem = new List(); private void OnServerInitialized() { config = Config.ReadObject(); Config.WriteObject(config); if (config.useSql) { sqlConnection = sqlLibrary.OpenDb(config.sqlConfig.ip, config.sqlConfig.port, config.sqlConfig.dbName, config.sqlConfig.username, config.sqlConfig.password, this); Sql sqlCommand1 = Sql.Builder.Append("CREATE TABLE IF NOT EXISTS redeemedRewards_user ( `id` int(11) NOT NULL AUTO_INCREMENT, `userid` VARCHAR(17) NOT NULL, `date` VARCHAR(16) NOT NULL, `hour` VARCHAR(16) NOT NULL, `count` int(3) NOT NULL, PRIMARY KEY (id) );"); sqlLibrary.Insert(sqlCommand1, sqlConnection); if (config.rewardMethod) { Sql sqlCommand2 = Sql.Builder.Append("CREATE TABLE IF NOT EXISTS redeemedRewards_daily ( `userid` VARCHAR(17) NOT NULL, `dayCount` int(3) NOT NULL );"); sqlLibrary.Insert(sqlCommand2, sqlConnection); } string today = DateTime.Now.ToShortDateString(); Sql sqlCommand3 = Sql.Builder.Append($"DELETE FROM redeemedRewards_user WHERE date NOT LIKE '{today}';"); sqlLibrary.Delete(sqlCommand3, sqlConnection); } else LoadData(); if (!config.rewardMethod && config.rewards.Count <= 30) { PrintWarning($"You've set less rewards than 31 ({config.rewards.Count}) and plugin will not work correctly in last days of the month! Add rewards for remaining days and load plugin again!"); Server.Command($"oxide.unload {this.Name}"); } } private void Unload() { if (!config.useSql) SaveData(); else sqlLibrary.CloseDb(sqlConnection); } private bool CanBeAwardedAdventGift(AdventCalendar calendar, BasePlayer player) { if (blockedRedeem.Contains(player.userID)) return false; blockedRedeem.Add(player.userID); timer.Once(5, () => blockedRedeem.Remove(player.userID)); return true; } private object OnAdventGiftAward(AdventCalendar calendar, BasePlayer player) { string today = DateTime.Now.ToShortDateString(); string now = DateTime.Now.ToString("dd/MM/yyyy HH:mm"); if (config.useSql) { int dayReward = -10; if (config.rewardMethod) { bool redeemed = false; Sql sqlCommand1 = Sql.Builder.Append($"SELECT userId,dayCount FROM redeemedRewards_daily WHERE userId='{player.userID}';"); sqlLibrary.Query(sqlCommand1, sqlConnection, list1 => { if (list1 == null) return; else if (list1.Count == 0) { sqlCommand1 = Sql.Builder.Append($"INSERT INTO redeemedRewards_daily (userId,dayCount) VALUES ('{player.userID}',-1);"); sqlLibrary.Insert(sqlCommand1, sqlConnection); dayReward = -1; } else dayReward = Convert.ToInt32(list1[0]["dayCount"]); Sql sqlCommand2 = Sql.Builder.Append($"SELECT userId,date,hour,count FROM redeemedRewards_user WHERE date='{today}' AND userId='{player.UserIDString}';"); int todayUses = 0; sqlLibrary.Query(sqlCommand2, sqlConnection, list2 => { bool increased = false; if (list2 == null) return; else if (list2.Count == 0) { sqlCommand2 = Sql.Builder.Append($"INSERT INTO redeemedRewards_user (userId,date,hour,count) VALUES ('{player.userID}','{today}','{now}',0);"); sqlLibrary.Insert(sqlCommand2, sqlConnection); } else { todayUses = (int)list2[0]["count"]; if (todayUses == 0) { dayReward++; increased = true; } if ((int)list2[0]["count"] >= config.rewards[dayReward].maxDaily) { player.SendConsoleCommand("gametip.showtoast", 1, Lang("MaxDailyReached", player.UserIDString)); redeemed = true; return; } DateTime lastUsage = DateTime.ParseExact((string)list2[0]["hour"], "dd/MM/yyyy HH:mm", CultureInfo.InvariantCulture); double minDifference = DateTime.Now.Subtract(lastUsage).TotalMinutes; if (minDifference < config.rewards[dayReward].cooldown) { string time = Math.Ceiling(config.rewards[dayReward].cooldown - minDifference).ToString("0"); player.SendConsoleCommand("gametip.showtoast", 1, Lang("RedeemCooldown", player.UserIDString, time)); redeemed = true; return; } } if (todayUses == 0 && !increased) dayReward++; sqlCommand2 = Sql.Builder.Append($"UPDATE redeemedRewards_user SET count={todayUses + 1},hour='{now}' WHERE date='{today}' AND userId='{player.UserIDString}';"); sqlLibrary.Insert(sqlCommand2, sqlConnection); if (todayUses == 0) { sqlCommand2 = Sql.Builder.Append($"UPDATE redeemedRewards_daily SET dayCount={dayReward} WHERE userId='{player.UserIDString}';"); sqlLibrary.Insert(sqlCommand2, sqlConnection); } RewardPlayer(player, dayReward, todayUses + 1, config.rewards[dayReward].maxDaily); }); if (redeemed) return; }); if (redeemed) return false; } else { dayReward = DateTime.Now.Day - 1; Sql sqlCommand2 = Sql.Builder.Append($"SELECT userId,date,hour,count FROM redeemedRewards_user WHERE date='{today}' AND userId='{player.UserIDString}';"); bool redeemed = false; int todayUses = 0; sqlLibrary.Query(sqlCommand2, sqlConnection, list => { if (list == null) return; else if (list.Count == 0) { sqlCommand2 = Sql.Builder.Append($"INSERT INTO redeemedRewards_user (userId,date,hour,count) VALUES ('{player.userID}','{today}','{now}',0);"); sqlLibrary.Insert(sqlCommand2, sqlConnection); } else { todayUses = (int)list[0]["count"]; if ((int)list[0]["count"] >= config.rewards[dayReward].maxDaily) { player.SendConsoleCommand("gametip.showtoast", 1, Lang("MaxDailyReached", player.UserIDString)); redeemed = true; return; } DateTime lastUsage = DateTime.ParseExact((string)list[0]["hour"], "dd/MM/yyyy HH:mm", CultureInfo.InvariantCulture); double minDifference = DateTime.Now.Subtract(lastUsage).TotalMinutes; if (minDifference < config.rewards[dayReward].cooldown) { string time = Math.Ceiling(config.rewards[dayReward].cooldown - minDifference).ToString("0"); player.SendConsoleCommand("gametip.showtoast", 1, Lang("RedeemCooldown", player.UserIDString, time)); redeemed = true; return; } } sqlCommand2 = Sql.Builder.Append($"UPDATE redeemedRewards_user SET count={todayUses + 1} WHERE date='{today}' AND userId='{player.UserIDString}';"); sqlLibrary.Insert(sqlCommand2, sqlConnection); if (config.rewardMethod && todayUses == 0) { sqlCommand2 = Sql.Builder.Append($"UPDATE redeemedRewards_daily SET dayCount={dayReward + 1} WHERE userId='{player.UserIDString}';"); sqlLibrary.Insert(sqlCommand2, sqlConnection); } RewardPlayer(player, dayReward, todayUses + 1, config.rewards[dayReward].maxDaily); }); if (redeemed) return false; } } else { data.userData.TryAdd(today, new Dictionary()); bool firstUse = false; if (!data.userData[today].ContainsKey(player.userID)) { firstUse = true; data.userData[today].Add(player.userID, new UserData() { lastUsed = now, timesUsed = 1 }); if (config.rewardMethod) { if (data.redeemCounter.ContainsKey(player.userID)) data.redeemCounter[player.userID]++; else data.redeemCounter.Add(player.userID, 0); } } int dayReward = config.rewardMethod ? data.redeemCounter[player.userID] : DateTime.Now.Day - 1; if (dayReward >= config.rewards.Count) dayReward = config.rewards.Count - 1; if (!firstUse) { if (data.userData[today][player.userID].timesUsed >= config.rewards[dayReward].maxDaily) { player.SendConsoleCommand("gametip.showtoast", 1, Lang("MaxDailyReached", player.UserIDString)); return false; } DateTime lastUsage = DateTime.ParseExact(data.userData[today][player.userID].lastUsed, "dd/MM/yyyy HH:mm", CultureInfo.InvariantCulture); double minDifference = DateTime.Now.Subtract(lastUsage).TotalMinutes; if (minDifference < config.rewards[dayReward].cooldown) { string time = Math.Ceiling(config.rewards[dayReward].cooldown - minDifference).ToString("0"); player.SendConsoleCommand("gametip.showtoast", 1, Lang("RedeemCooldown", player.UserIDString, time)); return false; } data.userData[today][player.userID].timesUsed++; data.userData[today][player.userID].lastUsed = now; } RewardPlayer(player, dayReward, data.userData[today][player.userID].timesUsed, config.rewards[dayReward].maxDaily); } return false; } private void RewardPlayer(BasePlayer player, int dayReward, int timesUsed, int maxDaily) { int rolledReward = Core.Random.Range(0, config.rewards[dayReward].itemRewards.Count); foreach (var item in config.rewards[dayReward].itemRewards[rolledReward]) { if (item.command != string.Empty) Server.Command(item.command.Replace("{userId}", player.UserIDString).Replace("{userName}", player.displayName)); if (item.shortname != string.Empty) { Item itemReward = ItemManager.CreateByName(item.shortname, Core.Random.Range(item.minAmount, item.maxAmount), item.skin); if (itemReward == null) { Puts($"ERROR! Item {item.shortname} is not valid item!"); continue; } itemReward.name = item.displayName; player.SendConsoleCommand("note.inv", itemReward.info.itemid, itemReward.amount, item.displayName == string.Empty ? itemReward.info.displayName.english : itemReward.name); if (!itemReward.MoveToContainer(player.inventory.containerMain)) itemReward.Drop(player.eyes.transform.position, Vector3.zero); } } if (config.consoleLogs) Puts($"Player {player.displayName} ({player.userID}) redeemed an reward no. {dayReward}!"); if (timesUsed != maxDaily) player.SendConsoleCommand("gametip.showtoast", 0, Lang("RewardRedeemedNext", player.UserIDString, config.rewards[dayReward].cooldown)); else player.SendConsoleCommand("gametip.showtoast", 0, Lang("RewardRedeemed", player.UserIDString)); Effect.server.Run("assets/prefabs/misc/easter/painted eggs/effects/gold_open.prefab", player.eyes.position); } protected override void LoadDefaultMessages() { lang.RegisterMessages(new Dictionary { ["MaxDailyReached"] = "You've reached daily limit of rewards!", ["RedeemCooldown"] = "Daily reward on cooldown!\nYou need to wait {0} minutes...", ["RewardRedeemedNext"] = "Enjoy your reward!\nYou can redeem it again in {0} minutes!", ["RewardRedeemed"] = "Enjoy your reward!\nCome back tommorow for more!", }, this); } private string Lang(string key, string id = null, params object[] args) => string.Format(lang.GetMessage(key, this, id), args); private PluginConfig config; protected override void LoadDefaultConfig() { Config.WriteObject(config = new PluginConfig() { rewards = new List() { new RewardConfig() { itemRewards = new List>() { new List() { new ItemConfig() { shortname = "metal.fragments", minAmount = 10000, maxAmount = 10000, }, new ItemConfig() { shortname = "wood", minAmount = 15000, maxAmount = 15000, } }, new List() { new ItemConfig() { shortname = "stones", minAmount = 10000, maxAmount = 10000, }, new ItemConfig() { shortname = "sulfur", minAmount = 10000, maxAmount = 15000, } } } }, new RewardConfig() { maxDaily = 1, cooldown = 0, itemRewards = new List>() { new List() { new ItemConfig() { command = "oxide.grant user {userId} permission.here" }, new ItemConfig() { command = "say Player {userName} redeemed an reward!" } } } }, new RewardConfig() { maxDaily = 1, cooldown = 0, itemRewards = new List>() { new List() { new ItemConfig() { shortname = "box.repair.bench", skin = 2795785961, displayName = "Recycler" } } } } } }, true); } private class PluginConfig { [JsonProperty("Count Rewards Per Player (true) or Count Rewards Per Day of Month (false)")] public bool rewardMethod = true; [JsonProperty("Enable Console Logs")] public bool consoleLogs = true; [JsonProperty("Use SQL Database")] public bool useSql = false; [JsonProperty("SQL Credentials")] public SqlConfig sqlConfig = new SqlConfig(); [JsonProperty("Reward List")] public List rewards = new List(); } private class SqlConfig { [JsonProperty("IP")] public string ip = "127.0.0.1"; [JsonProperty("Port")] public int port = 3306; [JsonProperty("Database Name")] public string dbName = "CustomAdventCalendarPro"; [JsonProperty("Username")] public string username = "admin"; [JsonProperty("Password")] public string password = "YourSuperSecretPassword"; } private class RewardConfig { [JsonProperty("Max Daily Redeems")] public int maxDaily = 1; [JsonProperty("Cooldown (in minutes, works only if Max Daily Redeems more than 1)")] public int cooldown = 360; [JsonProperty("Item Rewards")] public List> itemRewards = new List>(); } private class ItemConfig { [JsonProperty("Command (Ignored if empty)")] public string command = string.Empty; [JsonProperty("Shortname")] public string shortname = string.Empty; [JsonProperty("Minimum Amount")] public int minAmount = 1; [JsonProperty("Maximum Amount")] public int maxAmount = 1; [JsonProperty("Skin")] public ulong skin = 0; [JsonProperty("Display Name")] public string displayName = string.Empty; } private static PluginData data; private class PluginData { [JsonProperty("Daily User Data")] public Dictionary> userData = new Dictionary>(); [JsonProperty("Reward Redeemed Counter")] public Dictionary redeemCounter = new Dictionary(); } private class UserData { [JsonProperty("Last Used")] public string lastUsed = string.Empty; [JsonProperty("Times Used")] public int timesUsed = 0; } private void LoadData() { data = Interface.Oxide.DataFileSystem.ReadObject(this.Name); timer.Every(Core.Random.Range(500, 700), SaveData); } private void SaveData() => Interface.Oxide.DataFileSystem.WriteObject(this.Name, data); } }