C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using Newtonsoft.Json;
using Oxide.Core.Libraries;
using Oxide.Core.Libraries.Covalence;
using Tebex.Adapters;
using Tebex.API;
using Tebex.Triage;
namespace Oxide.Plugins
{
[Info("Tebex", "Tebex", "2.0.8")]
[Description("Official support for the Tebex server monetization platform")]
public class Tebex : CovalencePlugin
{
private static TebexOxideAdapter _adapter;
private Dictionary<string, DateTime> _lastNoteGiven = new Dictionary<string, DateTime>();
public static string GetPluginVersion()
{
return "2.0.8";
}
private void Init()
{
// Setup our API and adapter
_adapter = new TebexOxideAdapter(this);
TebexApi.Instance.InitAdapter(_adapter);
BaseTebexAdapter.PluginConfig = Config.ReadObject<BaseTebexAdapter.TebexConfig>();
if (!Config.Exists())
{
//Creates new config file
LoadConfig();
}
// Register permissions
permission.RegisterPermission("tebex.secret", this);
permission.RegisterPermission("tebex.sendlink", this);
permission.RegisterPermission("tebex.forcecheck", this);
permission.RegisterPermission("tebex.refresh", this);
permission.RegisterPermission("tebex.report", this);
permission.RegisterPermission("tebex.ban", this);
permission.RegisterPermission("tebex.lookup", this);
permission.RegisterPermission("tebex.debug", this);
// Register user permissions
permission.RegisterPermission("tebex.info", this);
permission.RegisterPermission("tebex.categories", this);
permission.RegisterPermission("tebex.packages", this);
permission.RegisterPermission("tebex.checkout", this);
// Check if auto reporting is disabled and show a warning if so.if (!BaseTebexAdapter.PluginConfig.AutoReportingEnabled)
{
_adapter.LogWarning("Auto reporting issues to Tebex is disabled.");
_adapter.LogWarning("To enable, please set 'AutoReportingEnabled' to 'true' in config/Tebex.json");
}
// Check if secret key has been set.If so, get store information and place in cache
if (BaseTebexAdapter.PluginConfig.SecretKey != "your-secret-key-here")
{
// No-op, just to place info in the cache for any future triage events
_adapter.FetchStoreInfo((info => { }));
return;
}
_adapter.LogInfo("Tebex detected a new configuration file.");
_adapter.LogInfo("Use tebex:secret <secret> to add your store's secret key.");
_adapter.LogInfo("Alternatively, add the secret key to 'Tebex.json' and reload the plugin.");
}
public WebRequests WebRequests()
{
return webrequest;
}
public IPlayerManager PlayerManager()
{
return players;
}
public PluginTimers PluginTimers()
{
return timer;
}
public IServer Server()
{
return server;
}
public string GetGame()
{
return game;
}
public void Warn(string message)
{
LogWarning("{0}", message);
}
public void Error(string message)
{
LogError("{0}", message);
}
public void Info(string info)
{
Puts("{0}", info);
}
private void OnUserConnected(IPlayer player)
{
// Check for default config and inform the admin that configuration is waiting.if (player.IsAdmin && BaseTebexAdapter.PluginConfig.SecretKey == "your-secret-key-here")
{
player.Command("chat.add", 0, player.Id,
"Tebex is not configured.Use tebex:secret <secret> from the F1 menu to add your key.");
player.Command("chat.add", 0, player.Id, "Get your secret key by logging in at:");
player.Command("chat.add", 0, player.Id, "https://tebex.io/");
}
_adapter.LogDebug($"Player login event: {player.Id}@{player.Address}");
_adapter.OnUserConnected(player.Id, player.Address);
}
#if RUST // VIP notes are enabled on Rust only
void OnLootEntity(BasePlayer player, BaseEntity entity)
{
if (!BaseTebexAdapter.PluginConfig.VipNotesEnabled)
{
return;
}
// If the user configured no VIP codes, skip.if (BaseTebexAdapter.PluginConfig.VipCodes.Count == 0)
{
return;
}
// Check if we have a target loot crate by prefab name
string prefabName = entity?.ShortPrefabName;
if (string.IsNullOrEmpty(prefabName) || (prefabName != "crate_normal_2" &&
prefabName != "crate_normal_2_food" &&
prefabName != "crate_normal_2_tools"))
{
return;
}
// Ensure the player was provided
string userID = player?.UserIDString;
if (string.IsNullOrEmpty(userID))
{
return;
}
// If the player is already in a VIP group, they won't receive a VIP note
if (BaseTebexAdapter.PluginConfig.VipGroups.Any(group => permission.UserHasGroup(userID, group)))
{
return;
}
// Make sure we haven't spawned a note too recently for the user.if (_lastNoteGiven.TryGetValue(userID, out DateTime lastGivenTime) &&
(DateTime.Now - lastGivenTime).Seconds < BaseTebexAdapter.PluginConfig.NoteCooldown)
{
return;
}
// Spawn chance check
if (Oxide.Core.Random.Range(0.0f, 1.0f) > BaseTebexAdapter.PluginConfig.NoteSpawnChance)
{
return;
}
// Create the note
Item item = ItemManager.CreateByName("note", 1, 0UL);
if (item == null)
{
return;
}
List<string> messages = BaseTebexAdapter.PluginConfig.NoteMessages["en"];
string message = messages[Oxide.Core.Random.Range(0, messages.Count)];
string vipCode = BaseTebexAdapter.PluginConfig.VipCodes[Oxide.Core.Random.Range(0, BaseTebexAdapter.PluginConfig.VipCodes.Count)];
var info = BaseTebexAdapter.Cache.Instance.Get("information").Value as TebexApi.TebexStoreInfo;
if (info != null)
{
item.text = string.Format(message, player.displayName, info.AccountInfo.Domain, vipCode);
item.MarkDirty();
player.GiveItem(item, BaseEntity.GiveItemReason.Generic);
_lastNoteGiven[userID] = DateTime.Now;
}
else
{
_adapter.LogDebug("Store information not present in cache when trying to spawn VIP note!");
}
}
#endif
private void OnServerShutdown()
{
// Make sure join queue is always empties on shutdown
_adapter.ProcessJoinQueue();
}
private void PrintCategories(IPlayer player, List<TebexApi.Category> categories)
{
// Index counter for selecting displayed items
var categoryIndex = 1;
var packIndex = 1;
// Line separator for category response
_adapter.ReplyPlayer(player, "---------------------------------");
// Sort categories in order and display
var orderedCategories = categories.OrderBy(category => category.Order).ToList();
for (int i = 0; i < categories.Count; i++)
{
var listing = orderedCategories[i];
_adapter.ReplyPlayer(player, $"[C{categoryIndex}] {listing.Name}");
categoryIndex++;
// Show packages for the category in order from API
if (listing.Packages.Count > 0)
{
var packages = listing.Packages.OrderBy(category => category.Order).ToList();
_adapter.ReplyPlayer(player, $"Packages");
foreach (var package in packages)
{
// Add additional flair on sales
if (package.Sale != null && package.Sale.Active)
{
_adapter.ReplyPlayer(player,
$"-> [P{packIndex}] {package.Name} {package.Price - package.Sale.Discount} (SALE {package.Sale.Discount} off)");
}
else
{
_adapter.ReplyPlayer(player, $"-> [P{packIndex}] {package.Name} {package.Price}");
}
packIndex++;
}
}
// At the end of each category add a line separator
_adapter.ReplyPlayer(player, "---------------------------------");
}
}
private static void PrintPackages(IPlayer player, List<TebexApi.Package> packages)
{
// Index counter for selecting displayed items
var packIndex = 1;
_adapter.ReplyPlayer(player, "---------------------------------");
_adapter.ReplyPlayer(player, " PACKAGES AVAILABLE ");
_adapter.ReplyPlayer(player, "---------------------------------");
// Sort categories in order and display
var orderedPackages = packages.OrderBy(package => package.Order).ToList();
for (var i = 0; i < packages.Count; i++)
{
var package = orderedPackages[i];
// Add additional flair on sales
_adapter.ReplyPlayer(player, $"[P{packIndex}] {package.Name}");
_adapter.ReplyPlayer(player, $"Category: {package.Category.Name}");
_adapter.ReplyPlayer(player, $"Description: {package.Description}");
if (package.Sale != null && package.Sale.Active)
{
_adapter.ReplyPlayer(player,
$"Original Price: {package.Price} {package.GetFriendlyPayFrequency()} SALE: {package.Sale.Discount} OFF!");
}
else
{
_adapter.ReplyPlayer(player, $"Price: {package.Price} {package.GetFriendlyPayFrequency()}");
}
_adapter.ReplyPlayer(player,
$"Purchase with 'tebex.checkout P{packIndex}' or 'tebex.checkout {package.Id}'");
_adapter.ReplyPlayer(player, "--------------------------------");
packIndex++;
}
}
protected override void LoadDefaultConfig()
{
Config.WriteObject(GetDefaultConfig(), true);
}
private BaseTebexAdapter.TebexConfig GetDefaultConfig()
{
return new BaseTebexAdapter.TebexConfig();
}
[Command("tebex.secret", "tebex:secret")]
private void TebexSecretCommand(IPlayer player, string command, string[] args)
{
// Secret can only be ran as the admin
if (!player.HasPermission("tebex.secret"))
{
_adapter.ReplyPlayer(player, "You do not have permission to run this command.");
_adapter.ReplyPlayer(player, "If you are an admin, grant permission to use `tebex.secret`");
return;
}
if (args.Length != 1)
{
_adapter.ReplyPlayer(player, "Invalid syntax.Usage: \"tebex.secret <secret>\"");
return;
}
_adapter.ReplyPlayer(player, "Setting your secret key...");
BaseTebexAdapter.PluginConfig.SecretKey = args[0];
Config.WriteObject(BaseTebexAdapter.PluginConfig);
// Reset store info so that we don't fetch from the cache
BaseTebexAdapter.Cache.Instance.Remove("information");
// Any failure to set secret key is logged to console automatically
_adapter.FetchStoreInfo(info =>
{
_adapter.ReplyPlayer(player, $"Successfully set your secret key.");
_adapter.ReplyPlayer(player,
$"Store set as: {info.ServerInfo.Name} for the web store {info.AccountInfo.Name}");
});
}
[Command("tebex.info", "tebex:info", "tebex.information", "tebex:information")]
private void TebexInfoCommand(IPlayer player, string command, string[] args)
{
if (!player.HasPermission(command))
{
_adapter.ReplyPlayer(player, "You do not have permission to run that command.");
return;
}
_adapter.ReplyPlayer(player, "Getting store information...");
_adapter.FetchStoreInfo(info =>
{
_adapter.ReplyPlayer(player, "Information for this server:");
_adapter.ReplyPlayer(player, $"{info.ServerInfo.Name} for webstore {info.AccountInfo.Name}");
_adapter.ReplyPlayer(player, $"Server prices are in {info.AccountInfo.Currency.Iso4217}");
_adapter.ReplyPlayer(player, $"Webstore domain {info.AccountInfo.Domain}");
});
}
[Command("tebex.checkout", "tebex:checkout")]
private void TebexCheckoutCommand(IPlayer player, string command, string[] args)
{
if (!player.HasPermission(command))
{
_adapter.ReplyPlayer(player, "You do not have permission to run that command.");
return;
}
if (player.IsServer)
{
_adapter.ReplyPlayer(player,
$"{command} cannot be executed via server.Use tebex:sendlink <username> <packageId> to specify a target player.");
return;
}
// Only argument will be the package ID of the item in question
if (args.Length != 1)
{
_adapter.ReplyPlayer(player, "Invalid syntax: Usage \"tebex.checkout <packageId>\"");
return;
}
// Lookup the package by provided input and respond with the checkout URL
var package = _adapter.GetPackageByShortCodeOrId(args[0].Trim());
if (package == null)
{
_adapter.ReplyPlayer(player, "A package with that ID was not found.");
return;
}
_adapter.ReplyPlayer(player, "Creating your checkout URL...");
_adapter.CreateCheckoutUrl(player.Name, package, checkoutUrl =>
{
player.Command("chat.add", 0, player.Id, "Please visit the following URL to complete your purchase:");
player.Command("chat.add", 0, player.Id, $"{checkoutUrl.Url}");
}, error => { _adapter.ReplyPlayer(player, $"{error.ErrorMessage}"); });
}
[Command("tebex.help", "tebex:help")]
private void TebexHelpCommand(IPlayer player, string command, string[] args)
{
_adapter.ReplyPlayer(player, "Tebex Commands Available:");
if (player.IsAdmin) //Always show help to admins regardless of perms, for new server owners
{
_adapter.ReplyPlayer(player, "-- Administrator Commands --");
_adapter.ReplyPlayer(player, "tebex.secret <secretKey> - Sets your server's secret key.");
_adapter.ReplyPlayer(player, "tebex.debug <on/off> - Enables or disables debug logging.");
_adapter.ReplyPlayer(player,
"tebex.sendlink <player> <packId> - Sends a purchase link to the provided player.");
_adapter.ReplyPlayer(player,
"tebex.forcecheck - Forces the command queue to check for any pending purchases.");
_adapter.ReplyPlayer(player,
"tebex.refresh - Refreshes store information, packages, categories, etc.");
_adapter.ReplyPlayer(player,
"tebex.report - Generates a report for the Tebex support team.");
_adapter.ReplyPlayer(player,
"tebex.ban <playerId> - Bans a player from using your Tebex store.");
_adapter.ReplyPlayer(player,
"tebex.lookup <playerId> - Looks up store statistics for the given player.");
}
_adapter.ReplyPlayer(player, "-- User Commands --");
_adapter.ReplyPlayer(player,
"tebex.info - Get information about this server's store.");
_adapter.ReplyPlayer(player,
"tebex.categories - Shows all item categories available on the store.");
_adapter.ReplyPlayer(player,
"tebex.packages <opt:categoryId> - Shows all item packages available in the store or provided category.");
_adapter.ReplyPlayer(player,
"tebex.checkout <packId> - Creates a checkout link for an item.Visit to purchase.");
}
[Command("tebex.debug", "tebex:debug")]
private void TebexDebugCommand(IPlayer player, string command, string[] args)
{
if (!player.HasPermission(command))
{
_adapter.ReplyPlayer(player, "You do not have permission to run that command.");
return;
}
if (args.Length != 1)
{
_adapter.ReplyPlayer(player, "Usage: tebex.debug <on/off>");
return;
}
if (args[0].Equals("on"))
{
BaseTebexAdapter.PluginConfig.DebugMode = true;
Config.WriteObject(BaseTebexAdapter.PluginConfig);
_adapter.ReplyPlayer(player, "Debug mode is enabled.");
}
else if (args[0].Equals("off"))
{
BaseTebexAdapter.PluginConfig.DebugMode = false;
Config.WriteObject(BaseTebexAdapter.PluginConfig);
_adapter.ReplyPlayer(player, "Debug mode is disabled.");
}
else
{
_adapter.ReplyPlayer(player, "Usage: tebex.debug <on/off>");
}
}
[Command("tebex.forcecheck", "tebex:forcecheck")]
private void TebexForceCheckCommand(IPlayer player, string command, string[] args)
{
if (!player.HasPermission(command))
{
_adapter.ReplyPlayer(player, "You do not have permission to run that command.");
return;
}
_adapter.RefreshStoreInformation(true);
_adapter.ProcessCommandQueue(true);
_adapter.ProcessJoinQueue(true);
_adapter.DeleteExecutedCommands(true);
}
[Command("tebex.refresh", "tebex:refresh")]
private void TebexRefreshCommand(IPlayer player, string command, string[] args)
{
if (!player.HasPermission(command))
{
_adapter.ReplyPlayer(player, "You do not have permission to run that command.");
return;
}
_adapter.ReplyPlayer(player, "Refreshing listings...");
BaseTebexAdapter.Cache.Instance.Remove("packages");
BaseTebexAdapter.Cache.Instance.Remove("categories");
_adapter.RefreshListings((code, body) =>
{
if (BaseTebexAdapter.Cache.Instance.HasValid("packages") &&
BaseTebexAdapter.Cache.Instance.HasValid("categories"))
{
var packs = (List<TebexApi.Package>)BaseTebexAdapter.Cache.Instance.Get("packages").Value;
var categories = (List<TebexApi.Category>)BaseTebexAdapter.Cache.Instance.Get("categories").Value;
_adapter.ReplyPlayer(player,
$"Fetched {packs.Count} packages out of {categories.Count} categories");
}
});
}
[Command("tebex.report", "tebex:report")]
private void TebexReportCommand(IPlayer player, string command, string[] args)
{
if (!player.HasPermission(command))
{
_adapter.ReplyPlayer(player, "You do not have permission to run that command.");
return;
}
if (args.Length == 0) // require /confirm to send
{
_adapter.ReplyPlayer(player,
"Please run `tebex.report confirm 'Your description here'` to submit your report.The following information will be sent to Tebex: ");
_adapter.ReplyPlayer(player, "- Your game version, store id, and server IP.");
_adapter.ReplyPlayer(player, "- Your username and IP address.");
_adapter.ReplyPlayer(player, "- Please include a short description of the issue you were facing.");
}
if (args.Length == 2 && args[0] == "confirm")
{
_adapter.ReplyPlayer(player, "Sending your report to Tebex...");
var triageEvent = new TebexTriage.ReportedTriageEvent();
triageEvent.GameId = $"{game} {server.Version}|{server.Protocol}";
triageEvent.FrameworkId = "Oxide";
triageEvent.PluginVersion = GetPluginVersion();
triageEvent.ServerIp = server.Address.ToString();
triageEvent.ErrorMessage = "Player Report: " + args[1];
triageEvent.Trace = "";
triageEvent.Metadata = new Dictionary<string, string>()
{
};
triageEvent.Username = player.Name + "/" + player.Id;
triageEvent.UserIp = player.Address;
_adapter.ReportManualTriageEvent(triageEvent,
(code, body) => { _adapter.ReplyPlayer(player, "Your report has been sent.Thank you!"); },
(code, body) =>
{
_adapter.ReplyPlayer(player,
"An error occurred while submitting your report.Please contact our support team directly.");
_adapter.ReplyPlayer(player, "Error: " + body);
});
return;
}
_adapter.ReplyPlayer(player, $"Usage: tebex.report <confirm> '<message>'");
}
[Command("tebex.ban", "tebex:ban")]
private void TebexBanCommand(IPlayer commandRunner, string command, string[] args)
{
if (!commandRunner.HasPermission("tebex.ban"))
{
_adapter.ReplyPlayer(commandRunner, $"{command} can only be used by administrators.");
return;
}
if (args.Length < 2)
{
_adapter.ReplyPlayer(commandRunner, $"Usage: tebex.ban <playerName> <reason>");
return;
}
var player = players.FindPlayer(args[0].Trim());
if (player == null)
{
_adapter.ReplyPlayer(commandRunner, $"Could not find that player on the server.");
return;
}
var reason = string.Join(" ", args.Skip(1));
_adapter.ReplyPlayer(commandRunner, $"Processing ban for player {player.Name} with reason '{reason}'");
_adapter.BanPlayer(player.Name, player.Address, reason,
(code, body) => { _adapter.ReplyPlayer(commandRunner, "Player banned successfully."); },
error => { _adapter.ReplyPlayer(commandRunner, $"Could not ban player.{error.ErrorMessage}"); });
}
[Command("tebex.unban", "tebex:unban")]
private void TebexUnbanCommand(IPlayer commandRunner, string command, string[] args)
{
if (!commandRunner.IsAdmin)
{
_adapter.ReplyPlayer(commandRunner, $"{command} can only be used by administrators.");
return;
}
_adapter.ReplyPlayer(commandRunner, $"You must unban players via your webstore.");
}
[Command("tebex.categories", "tebex:categories", "tebex.listings", "tebex:listings")]
private void TebexCategoriesCommand(IPlayer player, string command, string[] args)
{
if (!player.HasPermission(command))
{
_adapter.ReplyPlayer(player, "You do not have permission to run that command.");
return;
}
_adapter.GetCategories(categories => { PrintCategories(player, categories); });
}
[Command("tebex.packages", "tebex:packages")]
private void TebexPackagesCommand(IPlayer player, string command, string[] args)
{
if (!player.HasPermission(command))
{
_adapter.ReplyPlayer(player, "You do not have permission to run that command.");
return;
}
_adapter.GetPackages(packages => { PrintPackages(player, packages); });
}
[Command("tebex.lookup", "tebex:lookup")]
private void TebexLookupCommand(IPlayer player, string command, string[] args)
{
if (!player.HasPermission(command))
{
_adapter.ReplyPlayer(player, "You do not have permission to run that command.");
return;
}
if (args.Length != 1)
{
_adapter.ReplyPlayer(player, $"Usage: tebex.lookup <playerId/playerUsername>");
return;
}
// Try to find the given player
var target = players.FindPlayer(args[0]);
if (target == null)
{
_adapter.ReplyPlayer(player, $"Could not find a player matching the name or id {args[0]}.");
return;
}
_adapter.GetUser(target.Id, (code, body) =>
{
var response = JsonConvert.DeserializeObject<TebexApi.UserInfoResponse>(body);
_adapter.ReplyPlayer(player, $"Username: {response.Player.Username}");
_adapter.ReplyPlayer(player, $"Id: {response.Player.Id}");
_adapter.ReplyPlayer(player, $"Payments Total: ${response.Payments.Sum(payment => payment.Price)}");
_adapter.ReplyPlayer(player, $"Chargeback Rate: {response.ChargebackRate}%");
_adapter.ReplyPlayer(player, $"Bans Total: {response.BanCount}");
_adapter.ReplyPlayer(player, $"Payments: {response.Payments.Count}");
}, error => { _adapter.ReplyPlayer(player, error.ErrorMessage); });
}
[Command("tebex.sendlink", "tebex:sendlink")]
private void TebexSendLinkCommand(IPlayer commandRunner, string command, string[] args)
{
if (!commandRunner.HasPermission("tebex.sendlink"))
{
_adapter.ReplyPlayer(commandRunner, "You must be an administrator to run this command.");
return;
}
if (args.Length != 2)
{
_adapter.ReplyPlayer(commandRunner, "Usage: tebex.sendlink <username> <packageId>");
return;
}
var username = args[0].Trim();
var package = _adapter.GetPackageByShortCodeOrId(args[1].Trim());
if (package == null)
{
_adapter.ReplyPlayer(commandRunner, "A package with that ID was not found.");
return;
}
_adapter.ReplyPlayer(commandRunner,
$"Creating checkout URL with package '{package.Name}'|{package.Id} for player {username}");
var player = players.FindPlayer(username);
if (player == null)
{
_adapter.ReplyPlayer(commandRunner, $"Couldn't find that player on the server.");
return;
}
_adapter.CreateCheckoutUrl(player.Name, package, checkoutUrl =>
{
player.Command("chat.add", 0, player.Id, "Please visit the following URL to complete your purchase:");
player.Command("chat.add", 0, player.Id, $"{checkoutUrl.Url}");
}, error => { _adapter.ReplyPlayer(player, $"{error.ErrorMessage}"); });
}
}
}