C#:
using System;
using System.Collections.Generic;
using System.Linq;
using Oxide.Core.Plugins;
using Oxide.Core;
using UnityEngine;
using Oxide.Game.Rust.Cui;
using Rust.Ai.Gen2;
namespace Oxide.Plugins {
// To do
// Fix teleport distance abuse.
// Add API for GetMultiplier and NotifyReward
// Track user supply drops and give a different reward.PPlank
// Add permission to enable player settings UI.
// Add growables as new section.
// Consider adding rewards to all in team/clan ?
// Confirm what happens when user makes mistake in config - Reports of config file becoming null.
// Add kill reward for street signs?
// TODO - Add BossMonster and BetterNPC
// TODO
// Record IDs for barrels to prevent multiple rewards (AutoPickupBarrel plugin - Calls death hook multiple times)
// Changes in 3.2.5
// Added new vine and schizo trees.
// Fixed issue with happy hour sync after plugin reload.
//
//
//
//
//
//
[Info("RustRewards", "Steenamaroo", "3.2.5")]
[Description("Rewards players for activities using Economic, ServerRewards or Scrap")]
public class RustRewards : RustPlugin {
bool loaded = false;
[PluginReference]
Plugin Clans, Economics, Friends, GUIAnnouncements, NoEscape, ServerRewards, ZoneManager, RaidableBases, ImageLibrary;
Dictionary<ulong, Dictionary<ulong, float>> VehicleAttackers = new Dictionary<ulong, Dictionary<ulong, float>>();
private bool EventTerritory(BaseEntity entity) {
if (!RaidableBases || RaidableBases == null) return false;
return entity.OwnerID == 0 && Convert.ToBoolean(RaidableBases?.Call("EventTerritory", entity.transform.position));
}
public static RustRewards rr;
private const string AdminUIPermission = "rustrewards.adminui";
private const string HarvestPermission = "rustrewards.harvest";
private const string KillPermission = "rustrewards.kill";
private const string OpenPermission = "rustrewards.open";
private const string PickupPermission = "rustrewards.pickup";
private const string ActivityPermission = "rustrewards.activity";
private const string WelcomePermission = "rustrewards.welcome";
public enum RewardType {
Kill, Harvest, Open, Pickup, Activity, Welcome
}
public enum Currency {
None, Scrap, ServerRewards, Economics
}
;
public Currency currency = Currency.None;
int CurrentHour = 0;
int CurrentDay => (int)DateTime.UtcNow.AddHours(conf?.Settings?.General != null ? conf.Settings.General.UTCHourOffset : 0).DayOfWeek;
public bool IsNight() {
if (conf.Settings.General.UseServerDayNightHours) return TOD_Sky.Instance.IsNight;
CurrentHour = (int)TOD_Sky.Instance.Cycle.Hour;
if (conf.Settings.General.UseRealTime) CurrentHour = DateTime.UtcNow.Hour + conf.Settings.General.UTCHourOffset;
if (conf.Settings.General.NightStartHour > conf.Settings.General.DayStartHour) return CurrentHour >= conf.Settings.General.NightStartHour || CurrentHour < conf.Settings.General.DayStartHour;
else return CurrentHour >= conf.Settings.General.NightStartHour && CurrentHour < conf.Settings.General.DayStartHour;
}
public bool HappyHour() {
CurrentHour = (int)TOD_Sky.Instance.Cycle.Hour;
if (conf.Settings.General.UseRealTime) CurrentHour = DateTime.UtcNow.Hour + conf.Settings.General.UTCHourOffset;
if (conf.Settings.General.HappyHour_BeginHour > conf.Settings.General.HappyHour_EndHour) return CurrentHour > conf.Settings.General.HappyHour_BeginHour || CurrentHour < conf.Settings.General.HappyHour_EndHour;
else return CurrentHour > conf.Settings.General.HappyHour_BeginHour && CurrentHour < conf.Settings.General.HappyHour_EndHour;
}
#region ConfigPrep
public Dictionary<string, double> WeaponsList = new Dictionary<string, double>();
public Kill Kills = new Kill();
public class Kill {
public Dictionary<string, double> NPCs = new Dictionary<string, double>();
public Dictionary<string, double> Animals = new Dictionary<string, double>() {
{
"simpleshark", 0.0
}
}
;
public Dictionary<string, double> Vehicles = new Dictionary<string, double>() {
{
"patrolhelicopter", 0.0
}
, {
"bradleyapc", 0.0
}
, {
"ch47.entity", 0.0
}
, {
"ch47scientists.entity", 0.0
}
}
;
public Dictionary<string, double> MountedWeapons = new Dictionary<string, double>();
public Dictionary<string, double> Players = new Dictionary<string, double>() {
{
"Players", 0.0
}
, {
"Suicide", 0.0
}
, {
"Death", 0.0
}
, {
"Sleepers", 0.0
}
}
;
}
public Harvest Harvests = new Harvest();
List<string> OddWood = new List<string>() {
"birch_tiny_tundra", "birch_small_tundra", "birch_medium_tundra", "birch_big_tundra", "birch_large_tundra", "birch_tiny_temp", "birch_small_temp", "birch_medium_temp", "birch_big_temp", "birch_large_temp", "wood-pile", "douglas_fir_d_small", "palm_tree_short_a_entity", "palm_tree_short_b_entity", "palm_tree_short_c_entity", "palm_tree_small_a_entity", "palm_tree_small_b_entity", "palm_tree_small_c_entity", "palm_tree_med_a_entity", "palm_tree_tall_a_entity", "palm_tree_tall_b_entity",
}
;
string TreeTypes(string name) {
if (OddWood.Contains(name)) return name;
if (name.Contains("cactus-")) return "Cactus";
if (name.Contains("swamp_tree")) return "Swamp_Tree";
if (name.Contains("_sapling_")) return "Sapling";
if (name.Contains("oak_")) return "Oak";
if (name.Contains("pine_")) return "Pine";
if (name.Contains("american_beech_")) return "American_Beech";
if (name.Contains("_log_")) return "Log";
if (name.Contains("driftwood_")) return "Driftwood";
if (name.Contains("douglas_fir_")) return "Douglas_Fir";
if (name.Contains("mauritia")) return "Mauritia_Flexuosa";
if (name.Contains("trumpet")) return "Trumpet_Tree";
if (name.Contains("crepitans")) return "Hura_Crepitans";
if (name.Contains("vineswingingtree")) return "Vine_Swinging_Tree";
if (name.Contains("schizolobium")) return "Schizolobium";
return string.Empty;
}
public class Harvest {
public Dictionary<string, double> Flesh = new Dictionary<string, double>() {
}
;
public Dictionary<string, double> Ore = new Dictionary<string, double>() {
{
"stone", 0.0
}
, {
"metal", 0.0
}
, {
"sulfur", 0.0
}
,
}
;
public Dictionary<string, double> Tree = new Dictionary<string, double>() {
{
"Cactus", 0.0
}
, {
"Swamp_Tree", 0.0
}
, {
"Sapling", 0.0
}
, {
"Oak", 0.0
}
, {
"Pine", 0.0
}
, {
"American_Beech", 0.0
}
, {
"Log", 0.0
}
, {
"Driftwood", 0.0
}
, {
"Douglas_Fir", 0.0
}
, {
"Mauritia_Flexuosa", 0.0
}
, {
"Trumpet_Tree", 0.0
}
, {
"Hura_Crepitans", 0.0
}
, {
"Vine_Swinging_Tree", 0.0
}
, {
"Schizolobium", 0.0
}
}
;
/*
CACTUS
cactus-1, cactus-2, cactus-3, cactus-4, cactus-5, cactus-6, cactus-7
SWAMP TREE
swamp_tree_c, swamp_tree_f, swamp_tree_d, swamp_tree_e, swamp_tree_a, swamp_tree_b
SAPLING
pine_sapling_d, pine_sapling_e, pine_sapling_c, pine_sapling_a, pine_sapling_b, pine_sapling_a_snow, pine_sapling_b_snow, pine_sapling_d_snow, pine_sapling_e_snow, pine_sapling_c_snow
OAK
oak_b, oak_c, oak_d, oak_e, oak_f
PINE
pine_a, pine_b, pine_c, pine_d, pine_dead_snow_a, pine_dead_snow_b, pine_dead_snow_c, pine_dead_snow_d, pine_dead_snow_e, pine_dead_snow_f. pine_dead_a, pine_dead_b, pine_dead_c, pine_dead_d, pine_dead_e, pine_dead_f
AMERICAN BEECH
american_beech_a, american_beech_b, american_beech_c, american_beech_d, american_beech_e, american_beech_a_dead, american_beech_e_dead
LOG
ead_log_b, dead_log_c, dead_log_a
DRIFTWOOD
driftwood_set_3, driftwood_set_1, driftwood_set_2, driftwood_1, driftwood_2, driftwood_3driftwood_4, driftwood_5
FIR
douglas_fir_a_snow, douglas_fir_b_snow, douglas_fir_c_snow, douglas_fir_a, douglas_fir_b, douglas_fir_c, douglas_fir_d
*/
}
public Dictionary<string, double> Open = new Dictionary<string, double>();
public Dictionary<string, double> Pickup = new Dictionary<string, double>();
#endregion
const int ScrapId = -932201673;
#region SetupAndTakedown
void Init() {
permission.RegisterPermission(AdminUIPermission, this);
permission.RegisterPermission(ActivityPermission, this);
permission.RegisterPermission(HarvestPermission, this);
permission.RegisterPermission(KillPermission, this);
permission.RegisterPermission(OpenPermission, this);
permission.RegisterPermission(PickupPermission, this);
permission.RegisterPermission(WelcomePermission, this);
lang.RegisterMessages(Messages, this);
}
void OnServerSave() {
SaveConf();
SaveData();
}
bool newsave = false;
void OnNewSave(string filename) => newsave = true;
void OnServerInitialized() {
rr = this;
// Set up config information in advance.
var Weapons = ItemManager.itemList.Where(x => x.category == ItemCategory.Weapon && !x.shortname.Contains("weapon.mod"));
var AllEnts = Resources.FindObjectsOfTypeAll<BaseEntity>();
var ItemMods = Resources.FindObjectsOfTypeAll<ItemMod>();
foreach (var entry in Weapons) WeaponsList[entry.shortname] = 1.0;
foreach (var entry in ItemMods.OfType<ItemModUnwrap>().Where(x => x != null)) {
DictAdd(entry.name);
Open[entry.name] = 0.0;
}
foreach (var entry in ItemMods.OfType<ItemModMenuOption>().Where(x => x != null && x.option.name.english == "Gut")) {
DictAdd(entry.name);
Harvests.Flesh[entry.name] = 0.0;
}
List<string> Trees = new List<string>();
List<string> Exclusions = new List<string>() {
"CH47Helicopter", "CH47HelicopterAIController", "BaseArcadeMachine", "CardTable", "BaseCrane"
}
;
foreach (var e in AllEnts) {
if (e == null) continue;
if (e is TreeEntity) Trees.Add(e.ShortPrefabName);
if (e is LootContainer) {
string name = e.ShortPrefabName;
if (name.Contains("roadsign") || name.Contains("dm ") || name.Contains("test ")) continue;
if (e.PrefabName.Contains("underwater_labs")) name = "underwater_labs_" + e.ShortPrefabName;
DictAdd(name);
Open[name] = 0.0;
continue;
}
if (e is BaseNpc || e is BaseNPC2 || e is WildlifeHazard) {
if (e.ShortPrefabName.Contains("tutorial")) continue;
DictAdd(e.ShortPrefabName);
Kills.Animals[e.ShortPrefabName] = 0.0;
continue;
}
var rd = e.GetComponent<ResourceDispenser>();
if (rd != null) {
string name = e.ShortPrefabName;
if (name == "scientist_corpse" || name == "murderer_corpse") continue;
if (name == "snake.corpse") {
DictAdd("snake.entity");
Harvests.Flesh["snake.entity"] = 0.0;
continue;
}
if (e.GetComponent<ResourceDispenser>().gatherType == ResourceDispenser.GatherType.Flesh) {
DictAdd(e.ShortPrefabName);
Harvests.Flesh[e.ShortPrefabName] = 0.0;
continue;
}
}
if (e is CollectibleEntity || e is GrowableEntity) {
DictAdd(e.ShortPrefabName);
Pickup[e.ShortPrefabName] = 0.0;
continue;
}
if ((e is GunTrap || e is SamSite || e is AutoTurret || e is FlameTurret)) {
//if (e.ShortPrefabName.Contains("deployed"))
//{
DictAdd(e.ShortPrefabName);
Kills.MountedWeapons[e.ShortPrefabName] = 0.0;
continue;
//}
//else
// Puts(e.ShortPrefabName + " - ignored");
}
if (e is BaseVehicle) {
if (!Exclusions.Contains(e.GetType().ToString())) Kills.Vehicles[e.GetType().ToString()] = 0.0;
}
}
//Trees = Trees.Distinct().ToList();
//foreach (var tree in Trees)
// if (TreeTypes(tree) == string.Empty)
// Puts(tree);
// Print trees which aren't handled.
foreach (var entry in new List<string>() {
"BotReSpawn", "ZombieHorde", "OilRig", "Excavator", "CompoundScientist", "BanditTown", "MountedScientist", "JunkPileScientist", "DungeonScarecrow", "ScareCrow", "MilitaryTunnelScientist", "CargoShip", "APCScientist", "APCScientistHeavy", "HeavyScientist", "JungleScientist", "TunnelDweller", "UnderwaterDweller", "Trainyard", "Airfield", "DesertScientist", "ArcticResearchBase", "NuclearMissileSilo", "LaunchSite", "Gingerbread"
}
) {
DictAdd(entry);
Kills.NPCs[entry] = 0.0;
Harvests.Flesh[entry] = 0.0;
}
foreach (var ore in Harvests.Ore.Keys) DictAdd(ore);
foreach (var veh in Kills.Vehicles.Keys) DictAdd(veh);
//NEW
foreach (var oddwood in OddWood) Harvests.Tree[oddwood] = 0.0;
foreach (var tree in Harvests.Tree.Keys) DictAdd(tree);
//
StoreReferences();
if (!LoadConfigVariables()) {
Puts("Config file issue detected. Please delete file, or check syntax and fix.");
return;
}
RemoveUnusedAndSort();
if (conf.Settings.UI.BackgroundImage == "https://www.wallpapertip.com/wmimgs/16-169722_transparent-background-sticky-note-clipart.png") conf.Settings.UI.BackgroundImage = "https://codefling.com/uploads/monthly_2024_07/16-169722_transparent-background-sticky-note-clipart.png.63332204e329e4cd726402534f64dac7.png";
foreach (var entry in conf.Group_Multipliers) if (!permission.GroupExists(entry.Key)) permission.CreateGroup(entry.Key, entry.Key, 0);
DictAdd("simpleshark");
foreach (var entry in conf.Permission_Multipliers.Where(x => !x.Key.Contains("."))) permission.RegisterPermission(Title + "." + entry.Key, this);
//Register a permission for all perm multipliers. Dynamic - User can add/remove entries.
//Check if permissions containing dots do already exist. If not, notify user + ignore.
CheckDependencies();
cmd.AddChatCommand($"{conf.Settings.UI.MainCommandAlias}", this, "RustRewardsUI");
if (ImageLibrary) ImageLibrary?.Call("AddImage", conf.Settings.UI.BackgroundImage, "RRUiImage", 0UL);
if (newsave && conf.Settings.General.Reset_Activity_Reward_At_Wipe) foreach (var record in storedData.PlayerPrefs) record.Value.Activity_Given = false;
foreach (var player in BasePlayer.activePlayerList) OnPlayerConnected(player);
if (conf.Settings.Rewards.ActivityReward_Seconds > 0) ServerMgr.Instance.InvokeRepeating(this.CheckActivity, 1, 60);
if (conf.Settings.Multipliers.HappyHour > 1) ServerMgr.Instance.InvokeRepeating(this.CheckHappyHour, 1, 15);
PurgeOldPrefs();
SaveData();
SaveConf();
loaded = true;
}
List<string> RefKillAnimals;
List<string> RefKillMountedWeapons;
List<string> RefKillNPCs;
List<string> RefKillPlayers;
List<string> RefKillVehicles;
List<string> RefHarvestFlesh;
List<string> RefHarvestOre;
List<string> RefHarvestTree;
List<string> RefOpen;
List<string> RefPickup;
List<string> RefMultipliers;
void StoreReferences() {
RefKillAnimals = Kills.Animals.Keys.ToList();
RefKillMountedWeapons = Kills.MountedWeapons.Keys.ToList();
RefKillNPCs = Kills.NPCs.Keys.ToList();
RefKillPlayers = Kills.Players.Keys.ToList();
RefKillVehicles = Kills.Vehicles.Keys.ToList();
RefHarvestFlesh = Harvests.Flesh.Keys.ToList();
RefHarvestOre = Harvests.Ore.Keys.ToList();
RefHarvestTree = Harvests.Tree.Keys.ToList();
RefOpen = Open.Keys.ToList();
RefPickup = Pickup.Keys.ToList();
RefMultipliers = WeaponsList.Keys.ToList();
}
void RemoveUnusedAndSort() {
conf.RewardTypes.Kill.Animals = rr.Kills.Animals.Where(x => RefKillAnimals.Contains(x.Key)).OrderBy(x => x.Key).ToDictionary(val => val.Key, val => val.Value);
conf.RewardTypes.Kill.MountedWeapons = rr.Kills.MountedWeapons.Where(x => RefKillMountedWeapons.Contains(x.Key)).OrderBy(x => x.Key).ToDictionary(val => val.Key, val => val.Value);
conf.RewardTypes.Kill.NPCs = rr.Kills.NPCs.Where(x => RefKillNPCs.Contains(x.Key)).OrderBy(x => x.Key).ToDictionary(val => val.Key, val => val.Value);
conf.RewardTypes.Kill.Players = rr.Kills.Players.Where(x => RefKillPlayers.Contains(x.Key)).OrderBy(x => x.Key).ToDictionary(val => val.Key, val => val.Value);
conf.RewardTypes.Kill.Vehicles = rr.Kills.Vehicles.Where(x => RefKillVehicles.Contains(x.Key)).OrderBy(x => x.Key).ToDictionary(val => val.Key, val => val.Value);
conf.RewardTypes.Harvest.Flesh = rr.Harvests.Flesh.Where(x => RefHarvestFlesh.Contains(x.Key)).OrderBy(x => x.Key).ToDictionary(val => val.Key, val => val.Value);
conf.RewardTypes.Harvest.Ore = rr.Harvests.Ore.Where(x => RefHarvestOre.Contains(x.Key)).OrderBy(x => x.Key).ToDictionary(val => val.Key, val => val.Value);
conf.RewardTypes.Harvest.Tree = rr.Harvests.Tree.Where(x => RefHarvestTree.Contains(x.Key)).OrderBy(x => x.Key).OrderBy(x => OddWood.Contains(x.Key)).ToDictionary(val => val.Key, val => val.Value);
conf.RewardTypes.Open = rr.Open.Where(x => RefOpen.Contains(x.Key)).OrderBy(x => x.Key).ToDictionary(val => val.Key, val => val.Value);
conf.RewardTypes.Pickup = rr.Pickup.Where(x => RefPickup.Contains(x.Key)).OrderBy(x => x.Key).OrderByDescending(x => x.Key.Contains("entity")).ToDictionary(val => val.Key, val => val.Value);
conf.Weapon_Multipliers = rr.WeaponsList.Where(x => RefMultipliers.Contains(x.Key)).OrderBy(x => x.Key).ToDictionary(val => val.Key, val => val.Value);
}
void DictAdd(string name) {
if (!storedData.FriendlyNames.ContainsKey(name)) storedData.FriendlyNames.Add(name, name);
}
void PurgeOldPrefs() {
int counter = 0;
if (storedData?.PlayerPrefs == null) return;
foreach (var entry in storedData.PlayerPrefs.ToDictionary(val => val.Key, val => val.Value)) {
if ((DateTime.Now - entry.Value.LastActive).TotalDays > conf.Settings.General.Delete_Player_Prefs_After_Days) {
counter++;
storedData.PlayerPrefs.Remove(entry.Key);
}
}
if (counter > 0) PrintWarning($"Deleted {counter} player preference records, for {conf.Settings.General.Delete_Player_Prefs_After_Days} days of inactivity.");
}
void Unload() {
foreach (BasePlayer player in BasePlayer.activePlayerList) DestroyMenu(player, true, false, false);
if (conf?.Settings.Rewards.ActivityReward_Seconds > 0) ServerMgr.Instance.CancelInvoke(this.CheckActivity);
if (conf?.Settings.Multipliers.HappyHour > 1) ServerMgr.Instance.CancelInvoke(this.CheckHappyHour);
//SaveData();
}
#endregion
void CheckDependencies() {
if (conf.Settings.RewardCurrency.UseScrap) {
currency = Currency.Scrap;
PrintWarning("Using Scrap");
}
else if (conf.Settings.RewardCurrency.UseEconomics) {
currency = Currency.Economics;
PrintWarning("Using Economics");
}
else if (conf.Settings.RewardCurrency.UseServerRewards) {
currency = Currency.ServerRewards;
PrintWarning("Using Server Rewards");
}
if (conf.Settings.Allies.UseFriendsPlugin && !Friends) Puts("Friends plugin wasn't loaded. Option has been disabled.");
if (conf.Settings.Allies.UseClansPlugin && !Clans) Puts("Clans plugin wasn't loaded. Option has been disabled.");
if (conf.Settings.Plugins.UseZoneManagerPlugin && !ZoneManager) {
conf.Settings.Plugins.UseZoneManagerPlugin = false;
Puts("Zone Manager plugin wasn't loaded. Option has been disabled.");
}
if (conf.Settings.Plugins.UseGUIAnnouncementsPlugin && !GUIAnnouncements) Puts("GUI Announcements plugin wasn't loaded. Option has been disabled.");
if (conf.Settings.Plugins.UseNoEscape && !NoEscape) Puts("No Escape plugin wasn't loaded. Option has been disabled.");
}
Dictionary<ulong, int> RewardSeconds = new Dictionary<ulong, int>();
Dictionary<ulong, Vector3> LastLoc = new Dictionary<ulong, Vector3>();
void CheckActivity() {
foreach (var player in BasePlayer.activePlayerList) {
if (player?.net?.connection == null) continue;
if (conf.Settings.Rewards.Use_Permissions && !HasPerm(player.UserIDString, ActivityPermission)) continue;
var duration = (int)(Time.realtimeSinceStartup - player.net.connection.connectionTime);
if (duration - RewardSeconds[player.userID] < 0) continue;
int Rewards = (int)Mathf.Floor((duration - RewardSeconds[player.userID]) / conf.Settings.Rewards.ActivityReward_Seconds);
if (Rewards == 0) continue;
RewardSeconds[player.userID] += conf.Settings.Rewards.ActivityReward_Seconds * Rewards;
if (conf.Settings.Rewards.Activity_Reward_For_AFK || LastLoc[player.userID] != player.transform.position) {
LastLoc[player.userID] = player.transform.position;
GiveReward(player, RewardType.Activity, conf.Settings.Rewards.ActivityRewardAmount * Rewards);
}
}
}
bool first = true;
bool HappyHourRef = false;
void CheckHappyHour() {
if (HappyHour() == true) {
if (!HappyHourRef || first) {
HappyHourRef = true;
MessagePlayers("happyhourstart");
}
}
else {
if (HappyHourRef || first) {
HappyHourRef = false;
MessagePlayers("happyhourend");
}
}
first = false;
}
string Lang(string key, string id = null, params object[] args) => string.Format(lang.GetMessage(key, this, id), args);
bool HasPerm(string id, string perm) => permission.UserHasPermission(id, perm);
string CleanIP(string ipaddress) {
if (string.IsNullOrEmpty(ipaddress)) return " ";
if (!ipaddress.Contains(":") || ipaddress.LastIndexOf(":") == 0) return ipaddress;
return ipaddress.Substring(0, ipaddress.LastIndexOf(":"));
}
private void MessagePlayers(string key) {
if (conf.Settings.Plugins.UseGUIAnnouncementsPlugin && GUIAnnouncements) {
foreach (var player in BasePlayer.activePlayerList) GUIAnnouncements?.Call("CreateAnnouncement", String.Concat(Lang("Prefix", player.UserIDString), Lang(key, player.UserIDString)), conf.Settings.Announcements.GUI_Announcement_Banner_Colour, conf.Settings.Announcements.GUI_Announcement_Text_Colour, player);
}
else foreach (var player in BasePlayer.activePlayerList) Player.Reply(player, string.Format(conf.Settings.Announcements.ChatMessageFormat, Lang("Prefix", player.UserIDString), Lang(key, player.UserIDString)), "", conf.Settings.General.ChatIcon);
}
private void MessagePlayer(BasePlayer player, string msg, string prefix) {
if (player?.net?.connection == null || String.IsNullOrWhiteSpace(msg)) return;
if (!String.IsNullOrWhiteSpace(prefix)) msg = string.Format(conf.Settings.Announcements.ChatMessageFormat, prefix, msg);
if (conf.Settings.Plugins.UseGUIAnnouncementsPlugin && GUIAnnouncements) GUIAnnouncements?.Call("CreateAnnouncement", msg, conf.Settings.Announcements.GUI_Announcement_Banner_Colour, conf.Settings.Announcements.GUI_Announcement_Text_Colour, player);
else Player.Reply(player, msg, "", conf.Settings.General.ChatIcon);
}
private void NotifyReward(BasePlayer player, string msg, string prefix, bool GUI) {
if (player?.net?.connection == null || String.IsNullOrWhiteSpace(msg)) return;
if (!String.IsNullOrWhiteSpace(prefix)) msg = string.Format(conf.Settings.Announcements.ChatMessageFormat, prefix, msg);
if (GUI) GUIAnnouncements?.Call("CreateAnnouncement", msg, conf.Settings.Announcements.GUI_Announcement_Banner_Colour, conf.Settings.Announcements.GUI_Announcement_Text_Colour, player);
else Player.Reply(player, msg, "", conf.Settings.General.ChatIcon);
}
private void TakeScrap(BasePlayer player, int itemAmount) {
if (player.inventory.Take(null, ScrapId, itemAmount) > 0) player.SendConsoleCommand("note.inv", ScrapId, itemAmount * -1);
}
private object GiveScrap(BasePlayer player, int amount = 1) {
Item item = ItemManager.Create(ItemManager.FindItemDefinition(-932201673));
if (item == null) return false;
item.amount = amount;
if (player == null) {
item.Remove();
return false;
}
if (!player.inventory.GiveItem(item, player.inventory.containerMain)) {
item.Remove();
return false;
}
return true;
}
void PayPlayer(BasePlayer baseplayer, double amount) {
if (currency != Currency.Economics) amount = Math.Round(amount, 0);
if (amount == 0.0d) return;
if (currency == Currency.Scrap) {
if (amount < 0.0d) {
//Puts("Rust Rewards does not currently support taking scrap from players");
//TakeScrap(baseplayer, (int)(amount));
//// Create a scrap debt in data? Pay it off as you collect?
return;
}
else GiveScrap(baseplayer, (int)(amount));
}
// Both plugins look for a positive number to take/withdraw
else if (currency == Currency.ServerRewards) {
if (amount < 0.0d) ServerRewards?.Call("TakePoints", baseplayer.UserIDString, -1 * (int)(amount));
else ServerRewards?.Call("AddPoints", baseplayer.UserIDString, (int)(amount));
}
else {
if (amount < 0.0d) Economics?.Call("Withdraw", baseplayer.UserIDString, -1 * amount);
else Economics?.Call("Deposit", baseplayer.UserIDString, amount);
}
}
bool CheckPlayer(string playerId, double amount) {
double balance = 0.0d;
if (currency == Currency.ServerRewards) balance = (double)ServerRewards?.Call("CheckPoints", playerId);
else if (currency == Currency.Economics) balance = (double)Economics?.Call("Balance", playerId);
return !(amount.CompareTo(balance) < 0);
}
void GiveRustReward(BasePlayer player, int type, double amount, BaseEntity ent = null, string weapon = "", float distance = 0f, string name = null) => GiveReward(player, (RewardType)type, amount, ent, weapon, distance, name);
void GiveReward(BasePlayer player, RewardType type, double amount, BaseEntity ent = null, string weapon = "", float distance = 0f, string name = null) {
if (!loaded || conf == null || storedData?.PlayerPrefs == null || amount == 0 || player == null || player.IsNpc) return;
if (currency == Currency.None || (currency == Currency.ServerRewards && !ServerRewards) || (currency == Currency.Economics && !Economics)) return;
PlayerPrefs prefs = null;
if (!storedData.PlayerPrefs.TryGetValue(player.userID, out prefs)) return;
if (Interface.CallHook("OnRustReward", player, type.ToString()) != null) return;
if (name == null) name = ent?.ShortPrefabName;
double Multiplier = GetMultiplier(player, weapon, distance, ent);
amount *= Multiplier;
if (NoEscape && conf.Settings.Plugins.UseNoEscape) {
var success = NoEscape?.Call("IsBlocked", player);
if (success != null && success is bool && (bool)success) {
MessagePlayer(player, Lang("NoEscapeBlocked", player.UserIDString), Lang("Prefix", player.UserIDString));
return;
}
}
string formatted_amount = amount.ToString();
if (currency == Currency.Economics) amount = Math.Round(amount, 2);
else {
amount = Math.Round(amount, 0);
formatted_amount = string.Format("{0:#;-#;0}", amount);
}
var amt = Math.Abs(amount);
if (amt > 0 && ((amt < 0.01d && currency == Currency.Economics) || (amt < 1.0d && currency == Currency.ServerRewards))) return;
if (amt < 0 && ((amt > -0.01d && currency == Currency.Economics) || (amt > -1.0d && currency == Currency.ServerRewards))) return;
if (ent?.net?.connection != null) {
var victim = ent as BasePlayer;
if (victim != null && conf.Settings.General.TakeMoneyfromVictim) {
try {
PayPlayer(victim, -amount);
MessagePlayer(victim, Lang("VictimKilled", victim.UserIDString, victim.displayName), Lang("Prefix", victim.UserIDString));
if (conf.Settings.General.LogToFile) LogToFile(Name, $"[{DateTime.Now}] " + victim.displayName + " ( " + victim.UserIDString + " / " + CleanIP(victim.net.connection.ipaddress) + " )" + " lost " + formatted_amount + " for " + type, this);
if (conf.Settings.General.LogToConsole) Puts($"{victim.displayName} ( {victim.UserIDString} / {CleanIP(victim.net.connection.ipaddress)} ) lost {formatted_amount} for {type}");
}
catch {
MessagePlayer(player, Lang("VictimNoMoney", player.UserIDString, victim.displayName), Lang("Prefix", player.UserIDString));
}
}
}
PayPlayer(player, amount);
if (!conf.Settings.General.Disable_All_Notifications) {
if (prefs.Type != 3 && prefs.ShowReward(type)) {
if (prefs.Type == 2) {
if (amount > 0) RRRUI(player, type, $"+{amount}");
else RRRUI(player, type, $"-{amount}");
}
else //if (name != null)
NotifyReward(player, Lang(type.ToString() + (type == RewardType.Kill && amount < 0 ? "_negative" : ""), player.UserIDString, new object[] {
(amount < 1 ? amount.ToString("0.00") : amount.ToString()), GetFriendly(name, ent), Math.Round(distance, 2)
}
), Lang("Prefix", player.UserIDString), prefs.Type == 1);
}
}
if (conf.Settings.General.LogToFile) LogToFile(Name, $"[{DateTime.Now}] " + player.displayName + " ( " + player.userID + " / " + CleanIP(player.net.connection.ipaddress) + " )" + " got " + formatted_amount + " for " + type, this);
if (conf.Settings.General.LogToConsole) Puts($"{player.displayName} ( {player.UserIDString} / {CleanIP(player.net.connection.ipaddress)} got {formatted_amount} for {type}");
}
Dictionary<RewardType, string> Colours = new Dictionary<RewardType, string>() {
{
RewardType.Kill, "1 0 0 1"
}
, {
RewardType.Harvest, "0 1 0 1"
}
, {
RewardType.Open, "0 0 1 10"
}
, {
RewardType.Pickup, "1 1 0 1"
}
, {
RewardType.Activity, "0 1 1 1"
}
, {
RewardType.Welcome, "1 1 1 1"
}
}
;
void RRRUI(BasePlayer player, RewardType type, string message) {
CuiHelper.DestroyUi(player, "RRRUI");
timer.Once(1.4f, () => {
if (player != null) CuiHelper.DestroyUi(player, "RRRUI");
}
);
var prefs = Positions[storedData.PlayerPrefs[player.userID].Position];
var elements = new CuiElementContainer();
var mainName = elements.Add(new CuiPanel {
Image = {
FadeIn = 0.7f, Color = $"0.1 0.1 0.1 0"
}
, RectTransform = {
AnchorMin = prefs[0], AnchorMax = prefs[1]
}
, CursorEnabled = false
}
, "Overlay", "RRRUI");
var addy = (string)ImageLibrary?.Call("GetImage", "RRUiImage");
if (addy != null) elements.Add(new CuiElement {
Parent = mainName, Components = {
new CuiRawImageComponent {
FadeIn = 0.7f, Png = addy, Sprite = Sprite
}
, new CuiRectTransformComponent {
AnchorMin = "0.15 0.15", AnchorMax = "0.85 0.85"
}
,
}
,
}
);
elements.Add(new CuiLabel {
Text = {
FadeIn = 0.7f, Text = message, Color = Colours[type], FontSize = message.Length > 3 ? 28 : message.Length > 2 ? 34 : 38, Align = TextAnchor.MiddleCenter
}
, RectTransform = {
AnchorMin = "0 0", AnchorMax = "1 1"
}
,
}
, mainName);
CuiHelper.AddUi(player, elements);
}
string GetFriendly(string name, BaseEntity ent) {
if (ent == null && name == null) return null;
BasePlayer player = ent as BasePlayer;
if (player != null) {
if (!string.IsNullOrEmpty(player.displayName)) return player.displayName;
if (IsBotReSpawn(player) != null || player.Categorize() == "Zombie") return player.displayName;
name = GetNPCType(player);
}
if (name == null) return "No Record";
if (!storedData.FriendlyNames.ContainsKey(name)) {
Puts($"No friendly name for {ent?.GetType()} {name} - Please notify author.");
return "No Record";
}
return storedData.FriendlyNames[name];
}
public object IsBotReSpawn(BasePlayer player) {
foreach (var comp in player.GetComponents<Component>()) if (comp.ToString().Contains("BotData")) return true;
return null;
}
double GetMultiplier(BasePlayer player, string weapon, float distance, BaseEntity ent = null) {
double TimeMulti = IsNight() ? conf.Settings.Multipliers.Nighttime : conf.Settings.Multipliers.Daytime;
double RBMulti = ent != null && !ent.IsDestroyed && ent.transform != null && EventTerritory(ent) ? conf.Settings.Multipliers.RaidableBases : 1;
double DistanceMulti = conf.Settings.Multipliers.UseDynamicDistance ? 1.0f + (distance * conf.Settings.Multipliers.DynamicDistance) : Get_Distance_Multiplier(distance);
double WeaponMulti = weapon != null && conf.Weapon_Multipliers.ContainsKey(weapon) ? conf.Weapon_Multipliers[weapon] : 1;
double DayMulti = conf.WeekDay_Multipliers.ElementAt(CurrentDay).Value;
double HappyMulti = HappyHourRef ? conf.Settings.Multipliers.HappyHour : 1;
double ZoneMulti = 1;
if (ZoneManager) {
List<string> playerzones = ((string[])ZoneManager?.CallHook("GetPlayerZoneIDs", player)).ToList();
foreach (var zone in playerzones) if (zone != null && storedData.ZoneMultipliers.ContainsKey(zone)) if (storedData.ZoneMultipliers[zone] > ZoneMulti) ZoneMulti = storedData.ZoneMultipliers[zone];
}
double PermMulti = 1;
foreach (var entry in conf.Permission_Multipliers) if (HasPerm(player.UserIDString, Title + "." + entry.Key)) if (entry.Value > PermMulti) PermMulti = entry.Value;
double GroupMulti = 1;
foreach (var entry in conf.Group_Multipliers) if (permission.UserHasGroup(player.UserIDString, entry.Key)) if (entry.Value > GroupMulti) GroupMulti = entry.Value;
return ProcessMultis(new List<double>() {
TimeMulti, PermMulti, GroupMulti, DistanceMulti, WeaponMulti, DayMulti, ZoneMulti, HappyMulti, RBMulti
}
);
}
double ProcessMultis(List<double> multis) {
double multiplier = 1;
if (conf.Settings.General.Use_Highest_Multiplier_Only) return multis.Max<double>();
foreach (var multi in multis) {
if (conf.Settings.General.Add_Multipliers) {
if (multi > 1) multiplier += multi - 1;
}
else multiplier *= multi;
}
return multiplier;
}
private ulong GetMajorityAttacker(ulong id) {
if (VehicleAttackers.ContainsKey(id)) return VehicleAttackers[id].OrderByDescending(pair => pair.Value).First().Key;
return 0U;
}
#region OxideHooks
private void OnPlayerConnected(BasePlayer player) {
if (conf == null || player?.net?.connection == null) return;
if (!RewardSeconds.ContainsKey(player.userID)) RewardSeconds[player.userID] = (int)(Time.realtimeSinceStartup - player.net.connection.connectionTime);
if (!LastLoc.ContainsKey(player.userID)) LastLoc[player.userID] = player.transform.position;
if (!LastKills.ContainsKey(player.userID)) LastKills[player.userID] = new DateTime();
if (!storedData.PlayerPrefs.ContainsKey(player.userID)) {
storedData.PlayerPrefs.Add(player.userID.Get(), new PlayerPrefs() {
Type = storedData.PrefDefaults.Default_Notification_Type, Position = storedData.PrefDefaults.Position, Show_Activity = storedData.PrefDefaults.Show_Activity, Show_Harvest = storedData.PrefDefaults.Show_Harvest, Show_Kills = storedData.PrefDefaults.Show_Kills, Show_Open = storedData.PrefDefaults.Show_Open, Show_Pickup = storedData.PrefDefaults.Show_Pickup, Show_Welcome = storedData.PrefDefaults.Show_Welcome,
}
);
}
if (conf.Settings.Rewards.Use_Permissions && !HasPerm(player.UserIDString, WelcomePermission)) return;
storedData.PlayerPrefs[player.userID].LastActive = DateTime.Now;
if (conf.Settings.Rewards.WelcomeMoneyAmount > 0 && !storedData.PlayerPrefs[player.userID].Activity_Given) {
storedData.PlayerPrefs[player.userID].Activity_Given = true;
GiveReward(player, RewardType.Welcome, conf.Settings.Rewards.WelcomeMoneyAmount);
}
}
List<ulong> HarvestCoolDown = new List<ulong>();
List<ulong> BonusCoolDown = new List<ulong>();
bool CoolDownPlayer(BasePlayer player, List<ulong> list) {
if (list.Contains(player.userID)) return true;
list.Add(player.userID);
timer.Once(0.1f, () => list.Remove(player.userID));
return false;
}
void OnDispenserGather(ResourceDispenser d, BaseEntity entity, Item item) {
if (!loaded) return;
BasePlayer player = entity?.ToPlayer();
var corpse = d.GetComponent<PlayerCorpse>();
if (corpse != null) {
var id = corpse.playerSteamID;
NextTick(() => {
if (d == null && CorpseTypes.ContainsKey(id)) if (CorpseTypes[id] != null && conf.RewardTypes.Harvest.Flesh.ContainsKey(CorpseTypes[id])) GiveReward(player, RewardType.Harvest, conf.RewardTypes.Harvest.Flesh[CorpseTypes[id]], null, "", 0, CorpseTypes[id]);
//GiveReward(player, RewardType.Harvest, conf.RewardTypes.Harvest.Flesh[CorpseTypes[id]], name:CorpseTypes[id]);
}
);
return;
}
var ent = d.baseEntity;
bool Hazard = ent is WildlifeHazard;
if (ent != null) {
if (conf.Settings.General.Use_Harvesting_Cooldown && CoolDownPlayer(player, HarvestCoolDown)) return;
var name = ent.ShortPrefabName;
NextTick(() => {
if (ent.IsDestroyed && conf.RewardTypes.Harvest.Flesh.ContainsKey(name)) {
GiveReward(player, RewardType.Harvest, conf.RewardTypes.Harvest.Flesh[name], ent);
return;
}
if (ent.Health() <= 0 && d.gatherType == ResourceDispenser.GatherType.Tree) {
string tree = TreeTypes(name);
if (tree != string.Empty) GiveReward(player, RewardType.Harvest, conf.RewardTypes.Harvest.Tree[tree], ent, "", 0, tree);
return;
}
}
);
}
}
List<ulong> Bonuses = new List<ulong>();
List<string> ores = new List<string>() {
"metal", "stone", "sulfur"
}
;
void OnDispenserBonus(ResourceDispenser d, BasePlayer player, Item i) {
if (!loaded || !conf.Settings.Rewards.HarvestReward) return;
if (d == null || i?.info == null || player == null) return;
if (conf.Settings.Rewards.Use_Permissions && !HasPerm(player.UserIDString, HarvestPermission)) return;
var ent = d.GetComponent<BaseEntity>();
if (ent?.net?.ID == null || Bonuses.Contains(ent.net.ID.Value)) //metal/hqm
return;
Bonuses.Add(ent.net.ID.Value);
if (conf.Settings.General.Use_Harvesting_Cooldown && CoolDownPlayer(player, BonusCoolDown)) return;
foreach (var entry in ores) if (ent.ShortPrefabName.Contains(entry)) GiveReward(player, RewardType.Harvest, conf.RewardTypes.Harvest.Ore[entry], ent, "", 0, entry);
}
void OnGrowableGathered(GrowableEntity growable, Item item, BasePlayer player) {
if (!loaded || player == null || growable == null || !conf.Settings.Rewards.PickupReward) return;
if (growable.planter == null && conf.Settings.General.Only_Reward_Growables_From_Planters) return;
if (conf.Settings.Rewards.Use_Permissions && !HasPerm(player.UserIDString, PickupPermission)) return;
if (conf.RewardTypes.Pickup.ContainsKey(growable.ShortPrefabName)) GiveReward(player, RewardType.Pickup, conf.RewardTypes.Pickup[growable.ShortPrefabName], growable);
}
void OnCollectiblePickup(CollectibleEntity entity, BasePlayer player) {
if (!loaded || player == null || entity?.net?.ID == null || entity?.ShortPrefabName == null || !conf.Settings.Rewards.PickupReward) return;
if (conf.Settings.Rewards.Use_Permissions && !HasPerm(player.UserIDString, PickupPermission)) return;
if (UsedIDs.Contains(entity.net.ID.Value)) return;
UsedIDs.Add(entity.net.ID.Value);
if (conf.RewardTypes.Pickup.ContainsKey(entity.ShortPrefabName)) GiveReward(player, RewardType.Pickup, conf.RewardTypes.Pickup[entity.ShortPrefabName], entity);
}
List<ulong> UsedIDs = new List<ulong>();
void OnItemAction(Item item, string action, BasePlayer player) {
if (!loaded || player == null || item?.info?.name == null || !conf.Settings.Rewards.OpenReward) return;
if (conf.Settings.Rewards.Use_Permissions && !HasPerm(player.UserIDString, OpenPermission)) return;
if (conf.Settings.SkinnedItemBlackList.Contains(item.skin)) return;
if (conf.RewardTypes.Harvest.Flesh.ContainsKey(item.info.name)) if (action == "Gut") GiveReward(player, RewardType.Harvest, conf.RewardTypes.Harvest.Flesh[item.info.name], null, "", 0, item.info.name);
//GiveReward(player, RewardType.Harvest, conf.RewardTypes.Harvest.Flesh[item.info.name], name: item.info.name)
// ... [Code preview truncated due to length. Full source in attached file] ...