C#:
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using Rust;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("GFVoter", "www.gamesfinder.net", "1.0.2")]
class GFVoter : RustPlugin
{
#region Classes
internal class ItemData
{
public string Shortname;
public int Amount;
public ulong SkinID;
public Item Get() => ItemManager.CreateByName(Shortname, Amount, SkinID);
}
internal struct Reward
{
[JsonProperty("Display name for chat (if empty - use key or item name)")]
public string DisplayName;
public int NeedPoints;
public RewardType Type;
public ItemData Item;
[JsonProperty("Command (%STEAMID% - player user id)")]
public string Command;
}
internal class PlayerData
{
public string DisplayName = "undefined";
public int Points;
[JsonIgnore]
public int RequestCooldown;
public bool IsOnCooldown() => RequestCooldown - CurrentTime() > 0;
public void SetRequestCooldown(int seconds) => RequestCooldown = CurrentTime() + seconds;
}
#endregion
#region Fields
internal enum RewardType : byte
{
Item = 0,
Command = 1
}
private const string PERM_ADMIN = "gfvoter.admin";
private static readonly DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0);
private static int CurrentTime() => (int)DateTime.UtcNow.Subtract(epoch).TotalSeconds;
private Dictionary<ulong, PlayerData> _players = new();
#endregion
#region Hooks
private void OnServerInitialized()
{
LoadData();
permission.RegisterPermission(PERM_ADMIN, this);
foreach (var x in BasePlayer.activePlayerList)
{
OnPlayerConnected(x);
}
foreach (var x in cfg.CommandsClaim)
cmd.AddChatCommand(x, this, nameof(cmdClaimReward));
foreach (var x in cfg.CommandsClaimPoint)
cmd.AddChatCommand(x, this, nameof(cmdClaimPoint));
foreach (var x in cfg.CommandsCheck)
cmd.AddChatCommand(x, this, nameof(cmdRewardList));
foreach (var cmdCheckPoint in cfg.CommandsCheckPoints)
cmd.AddChatCommand(cmdCheckPoint, this, nameof(cmdCheckPoints));
StartReminderTimer(); // Start the reminder timer
}
private void Unload() => SaveData();
private void OnServerSave() => SaveData();
private void OnPlayerConnected(BasePlayer player)
{
if (!_players.ContainsKey(player.userID))
_players.Add(player.userID, new PlayerData());
_players[player.userID].DisplayName = player.displayName;
}
#endregion
#region Methods
private List<BasePlayer> FindPlayer(string s)
{
List<BasePlayer> players = new List<BasePlayer>();
foreach (var x in BasePlayer.activePlayerList.Where(x => x.UserIDString == s || x.displayName.Contains(s, CompareOptions.IgnoreCase)))
players.Add(x);
return players;
}
private void SendVoteRequest(ulong userid, Action<int> callback)
{
webrequest.Enqueue($"https://www.gamesfinder.net/api/vote?key={cfg.APIKey}&steamid={userid}", "", (code, response) =>
{
callback?.Invoke(int.Parse(response));
}, this);
}
private void SendVoteClaim(ulong userid)
{
webrequest.Enqueue($"https://www.gamesfinder.net/api/vote?mode=claim&key={cfg.APIKey}&steamid={userid}", "", (code, response) =>
{
}, this);
}
private void GiveReward(BasePlayer player, Reward reward)
{
switch (reward.Type)
{
case RewardType.Command:
Server.Command(reward.Command.Replace("%STEAMID%", player.UserIDString));
break;
case RewardType.Item:
GiveItem(player, reward.Item.Get());
break;
default:
throw new ArgumentException("Unknown RewardType");
}
}
private void GiveItem(BasePlayer player, Item item)
{
if (!player.inventory.containerMain.IsFull())
{
item.MoveToContainer(player.inventory.containerMain);
return;
}
if (!player.inventory.containerBelt.IsFull())
{
item.MoveToContainer(player.inventory.containerBelt);
return;
}
item.Drop(player.GetDropPosition(), player.GetDropVelocity());
}
private void SendToDiscord(ulong userid, string message)
{
string res = @"{
""embeds"": [
{
""color"": 4321431,
""author"": {
""name"": ""GFVoter""
},
""description"": ""{message}""
}
]
}".Replace("{message}", message);
webrequest.Enqueue(cfg.Webhook, res, (code, response) =>
{
}, this, Core.Libraries.RequestMethod.POST, new Dictionary<string, string>() { { "Content-Type", "application/json" } }, 5000);
}
private void StartReminderTimer()
{
timer.Repeat(cfg.ReminderIntervalMinutes * 60f, 0, () =>
{
foreach (var player in BasePlayer.activePlayerList)
{
player.ChatMessage(cfg.ReminderMessage);
}
});
}
#endregion
#region Commands
[ConsoleCommand("gfvote")]
private void cmdGivePointsConsole(ConsoleSystem.Arg arg) => cmdGivePoints(arg.Player(), "", arg.Args);
[ChatCommand("gfvote")]
private void cmdGivePoints(BasePlayer player, string command, string[] args)
{
if (player != null && !player.IPlayer.HasPermission(PERM_ADMIN))
return;
if (args.IsNullOrEmpty())
{
if (player == null)
PrintWarning($"/gfvote 'points' 'playername'");
else
player.ChatMessage($"/gfvote 'points' 'playername'");
return;
}
if (!int.TryParse(args[0], out var points))
{
if (player == null)
PrintWarning($"Not correct number of points '{args[0]}'");
else
player.ChatMessage($"Not correct number of points '{args[0]}'");
return;
}
var players = FindPlayer(args[1]);
if (players.IsNullOrEmpty())
{
if (player == null)
PrintWarning($"Player {args[1]} not found");
else
player.ChatMessage($"Player {args[1]} not found");
return;
}
if (players.Count > 1)
{
if (player == null)
PrintWarning($"Many players: " + string.Join(", ", players.Select(x => x.displayName)));
else
player.ChatMessage($"Many players: " + string.Join(", ", players.Select(x => x.displayName)));
return;
}
var p = players.First();
_players[p.userID].Points += points;
if (player == null)
PrintWarning($"Added {points} points for {p.displayName}");
else
player.ChatMessage($"Added {points} points for {p.displayName}");
}
private void cmdCheckPoints(BasePlayer player, string command, string[] args)
{
if (!_players.ContainsKey(player.userID))
{
player.ChatMessage("You have no points.");
return;
}
var points = _players[player.userID].Points;
player.ChatMessage($"You currently have {points} point(s).");
}
private void cmdClaimReward(BasePlayer player, string command, string[] args)
{
if (args.IsNullOrEmpty())
{
player.ChatMessage($"Usage: /{command} 'reward id'");
return;
}
string key = args[0];
if (!cfg.Rewards.ContainsKey(key))
{
player.ChatMessage($"Reward '{key}' doesnt exists!");
return;
}
var reward = cfg.Rewards[key];
if (_players[player.userID].Points < reward.NeedPoints)
{
player.ChatMessage($"You need {reward.NeedPoints - _players[player.userID].Points} more points!");
return;
}
_players[player.userID].Points -= reward.NeedPoints;
GiveReward(player, reward);
player.ChatMessage($"You <color=green>succesfully</color> claimed reward '{key}'!");
if (cfg.UseDiscordClaim)
SendToDiscord(player.userID, $"Player **{_players[player.userID].DisplayName}({player.userID})** claim reward **{key}**!");
}
private void cmdRewardList(BasePlayer player)
{
StringBuilder sb = new StringBuilder();
sb.Append("<b>Rewards List:</b>\n");
foreach (var x in cfg.Rewards.OrderBy(x => x.Value.NeedPoints))
{
var reward = x.Value;
sb.Append($"<color={(_players[player.userID].Points >= reward.NeedPoints ? "green" : "red")}>{x.Key} ({reward.NeedPoints}p)</color>" + " -> ");
if (string.IsNullOrEmpty(reward.DisplayName))
{
if (reward.Type == RewardType.Item)
{
sb.Append($"x{reward.Item.Amount} {reward.Item.Get().info.displayName.english}\n");
}
else
{
sb.Append($"{x.Key}\n");
}
}
else
{
sb.Append($"{reward.DisplayName}\n");
}
}
player.ChatMessage(sb.ToString());
}
private void cmdClaimPoint(BasePlayer player)
{
if (!_players.ContainsKey(player.userID))
_players.Add(player.userID, new PlayerData
{
DisplayName = player.displayName
});
var data = _players[player.userID];
if (!data.IsOnCooldown())
{
SendVoteRequest(player.userID, (code) =>
{
if (code == 1)
{
if (cfg.UseDiscordAtVote)
SendToDiscord(player.userID, $"Player **{data.DisplayName}({player.userID})** voted!");
SendVoteClaim(player.userID);
data.Points++;
player.ChatMessage("You claimed 1 point!");
data.SetRequestCooldown(3600);
}
else if (code == 2)
{
data.SetRequestCooldown(3600);
player.ChatMessage("You already claimed point!");
}
else if (code == 0)
{
data.SetRequestCooldown(10);
player.ChatMessage("Vote us server");
}
});
}
else
{
player.ChatMessage($"You are on cooldown. Please, wait {data.RequestCooldown - CurrentTime()} seconds.");
}
}
#endregion
#region Config
private ConfigData cfg;
public class ConfigData
{
[JsonProperty("Use discord webhook at vote")]
public bool UseDiscordAtVote;
[JsonProperty("Use discord webhook at claim")]
public bool UseDiscordClaim;
[JsonProperty("Discord webhook")]
public string Webhook;
[JsonProperty("Chat command to claim reward point")]
public List<string> CommandsClaimPoint;
[JsonProperty("Chat command for check rewards")]
public List<string> CommandsCheck;
[JsonProperty("Chat command for get reward")]
public List<string> CommandsClaim;
[JsonProperty("Chat commands for checking points")]
public List<string> CommandsCheckPoints;
[JsonProperty("GamesFinder API")]
public string APIKey;
[JsonProperty("Rewards")]
public Dictionary<string, Reward> Rewards;
[JsonProperty("Reminder message")]
public string ReminderMessage;
[JsonProperty("Reminder interval minutes")]
public int ReminderIntervalMinutes;
}
protected override void LoadDefaultConfig()
{
var config = new ConfigData
{
UseDiscordAtVote = false,
UseDiscordClaim = false,
Webhook = "Your webhook",
CommandsClaimPoint = new List<string> { "claimpoint", "clp" },
CommandsCheck = new List<string> { "rewardlist", "rl" },
CommandsClaim = new List<string> { "claimreward", "cr" },
CommandsCheckPoints = new List<string> { "checkpoints", "checkp" },
APIKey = "Your api key",
Rewards = new Dictionary<string, Reward>
{
["wood"] = new Reward
{
NeedPoints = 1,
Type = RewardType.Item,
Item = new ItemData
{
Shortname = "wood",
Amount = 1000,
SkinID = 0
},
Command = null
},
["sr"] = new Reward
{
DisplayName = "x10 ServerRewards",
NeedPoints = 2,
Type = RewardType.Command,
Item = null,
Command = "sr add %STEAMID% 10"
},
["economics"] = new Reward
{
DisplayName = "x50 Economics",
NeedPoints = 3,
Type = RewardType.Command,
Item = null,
Command = "deposit %STEAMID% 50"
},
["group"] = new Reward
{
DisplayName = "x1 Group 'Member'",
NeedPoints = 10,
Type = RewardType.Command,
Item = null,
Command = "oxide.grant user %STEAMID% (Permission)"
}
},
ReminderMessage = "Hey! Don't forget to vote for our server on gamesfinder.net and claim your points.",
ReminderIntervalMinutes = 15
};
SaveConfig(config);
}
protected override void LoadConfig()
{
base.LoadConfig();
cfg = Config.ReadObject<ConfigData>();
SaveConfig(cfg); // Ensure any new defaults are written back to the config file
}
private void SaveConfig(object config)
{
Config.WriteObject(config, true);
}
#endregion
#region Data
private void SaveData()
{
Interface.Oxide.DataFileSystem.WriteObject($"{Title}/players", _players);
}
void LoadData()
{
_players = Interface.Oxide?.DataFileSystem?.ReadObject<Dictionary<ulong, PlayerData>>($"{Title}/players") ?? new Dictionary<ulong, PlayerData>();
}
#endregion
}
}