C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
// Reference: 0Harmony
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using UnityEngine;
using Harmony;
using System.Reflection.Emit;
using Oxide.Plugins.CustomizableWeaponsExtensions;
namespace Oxide.Plugins {
[Info("Customizable Weapons", "0xF [dsc.gg/0xf-plugins]", "1.5.9")]
public class CustomizableWeapons : RustPlugin {
#region Consts
public const ItemContainer.Flag NoSortify = (ItemContainer.Flag)(8192) | (ItemContainer.Flag)(16384);
#endregion
#region Variables
private static CustomizableWeapons Plugin;
private static HarmonyInstance _harmony;
#endregion
#region PluginReference
[PluginReference]
private Plugin RustTranslationAPI;
#endregion
#region Permissions
const string giveCommandPerm = "customizableweapons.give";
const string iconShowPerm = "customizableweapons.icon.show";
const string iconHidePerm = "customizableweapons.icon.hide";
#endregion
#region Harmony
private static class CommonPatches {
internal static bool Item_Load(Item __instance, ProtoBuf.Item load) {
if (__instance.skin != load.skinid) {
KeyValuePair<string, CustomItem> customItem;
if (Plugin.TryGetCustomItem(__instance.info.shortname, load.skinid, out customItem)) {
__instance.SetUniqueShortname(customItem.Key);
if (customItem.Value.SkinId != load.skinid) load.skinid = customItem.Value.SkinId;
}
}
return true;
}
internal static void Item_Save(Item __instance, ref ProtoBuf.Item __result) {
if (!SaveRestore.IsSaving && Plugin.IsWeapon(__instance) && __result.streamerName != null && __result.streamerName.StartsWith("\n")) {
ItemContainer container = __instance.parent;
if (container != null) {
BasePlayer player = container.playerOwner;
if (player != null && !player.IsNpc && !player.inventory.loot.IsLooting()) __result.name = __result.streamerName;
}
}
}
}
private static class CreateItemPatches {
internal static DynamicMethod __originalCreateMethod;
internal static bool FindItemDefinitionPrefix(string shortName, ref ItemDefinition __result) {
if (shortName == null || shortName == string.Empty) return true;
if (Plugin == null) return true;
CustomItem customItem;
if (Plugin.TryGetCustomItemByKey(shortName, out customItem)) {
ItemDefinition original;
if (!ItemManager.itemDictionaryByName.TryGetValue(customItem.Shortname, out original)) return true;
__result = new ItemDefinition() {
shortname = shortName, itemid = original.itemid, category = (ItemCategory.Favourite & ItemCategory.Weapon)
}
;
return false;
}
return true;
}
internal static bool CreateByNamePrefix(string strName, int iAmount, ulong skin, ref Item __result) {
if (strName == null || strName == string.Empty) return true;
if (Plugin == null) return true;
CustomItem customItem;
if (Plugin.TryGetCustomItemByKey(strName, out customItem)) {
ItemDefinition original;
if (!ItemManager.itemDictionaryByName.TryGetValue(customItem.Shortname, out original)) return true;
__result = ItemManager.Create(new ItemDefinition() {
shortname = strName, itemid = original.itemid, category = (ItemCategory.Favourite & ItemCategory.Weapon)
}
, iAmount, skin);
return false;
}
return true;
}
internal static bool CreatePrefix(ref ItemDefinition template, int iAmount, ref ulong skin, ref Item __result) {
CustomItem customItem = null;
if (template.category == ItemCategory.Weapon && skin != 0) {
KeyValuePair<string, CustomItem> customItemPair;
if (Plugin.TryGetCustomItem(template.shortname, skin, out customItemPair)) {
template = new ItemDefinition() {
shortname = customItemPair.Key, category = (ItemCategory.Favourite & ItemCategory.Weapon)
}
;
skin = customItemPair.Value.SkinId;
customItem = customItemPair.Value;
}
}
if (template.category != (ItemCategory.Favourite & ItemCategory.Weapon)) return true;
if (Plugin == null) return true;
if (Plugin.TryGetCustomItemByKey(template.shortname, out customItem)) {
var uniqueShortname = template.shortname;
template = ItemManager.FindItemDefinition(customItem.Shortname);
var result = (Item)__originalCreateMethod.Invoke(null, new object[] {
template, iAmount, skin
}
);
result.SetUniqueShortname(uniqueShortname);
__result = result;
return false;
}
return true;
}
}
#endregion
#region Hooks
private void Init() {
Plugin = this;
permission.RegisterPermission(giveCommandPerm, this);
permission.RegisterPermission(iconShowPerm, this);
permission.RegisterPermission(iconHidePerm, this);
}
private void OnServerInitialized() {
LoadIcon();
LoadConfig();
if (config.GlobalSettings.GiveOptions.Attachments == null) config.GlobalSettings.GiveOptions.Attachments = ItemManager.itemDictionaryByName.Keys.Where(shortname => shortname.StartsWith("weapon.mod")).ToDictionary(x => x, x => false);
config.DataItems.Initialize(this);
SaveConfig();
LoadLang();
List<WeaponData> weaponDatas = new List<WeaponData>();
weaponDatas.AddRange(config.DataItems.Default.Values);
foreach (var list in config.DataItems.Permissions) weaponDatas.AddRange(list.Value.Values);
weaponDatas.AddRange(config.DataItems.Custom.Values);
foreach (var _wd in weaponDatas) {
if (_wd.DamageTypes == null) continue;
if (_wd.DamageTypeList == null) _wd.DamageTypeList = new Dictionary<string, Rust.DamageTypeList>();
foreach (var ammo_pair in _wd.DamageTypes) {
if (!_wd.DamageTypeList.ContainsKey(ammo_pair.Key)) _wd.DamageTypeList[ammo_pair.Key] = new Rust.DamageTypeList();
for (int i = 0; i < DamageTypes.Count; i++) {
Rust.DamageType type = DamageTypes[i];
string DamageTypeName = DamageTypeNames.Values.ElementAt(i);
if (_wd.DamageTypes[ammo_pair.Key].ContainsKey(DamageTypeName)) _wd.DamageTypeList[ammo_pair.Key].Add(type, _wd.DamageTypes[ammo_pair.Key][DamageTypeName]);
}
;
}
}
foreach (var perm in config.DataItems.Permissions) permission.RegisterPermission($"customizableweapons.{perm.Key}", this);
if (_harmony == null) _harmony = HarmonyInstance.Create($"{this.Name}@{this.Author}");
CreateItemPatches.__originalCreateMethod = _harmony.Patch(AccessTools.Method(typeof(ItemManager), "Create"));
_harmony.Patch(AccessTools.Method(typeof(ItemManager), "Create"), new HarmonyMethod(typeof(CreateItemPatches), "CreatePrefix"));
_harmony.Patch(AccessTools.Method(typeof(ItemManager), "CreateByName"), new HarmonyMethod(typeof(CreateItemPatches), "CreateByNamePrefix"));
_harmony.Patch(AccessTools.Method(typeof(ItemManager), "CreateByPartialName"), new HarmonyMethod(typeof(CreateItemPatches), "CreateByNamePrefix"));
_harmony.Patch(AccessTools.Method(typeof(ItemManager), "FindItemDefinition", new Type[] {
typeof(string)
}
), new HarmonyMethod(typeof(CreateItemPatches), "FindItemDefinitionPrefix"));
_harmony.Patch(AccessTools.Method(typeof(Item), "Load"), new HarmonyMethod(typeof(CommonPatches), "Item_Load"));
_harmony.Patch(AccessTools.Method(typeof(Item), "Save"), postfix : new HarmonyMethod(typeof(CommonPatches), "Item_Save"));
BasePlayer.activePlayerList.ToList().ForEach(player => AddUiIcon(player));
}
private void OnUserPermissionGranted(string playerId, string perm) {
if (perm != iconShowPerm && perm != iconHidePerm) return;
BasePlayer player = BasePlayer.Find(playerId);
if (player == null) return;
OnPermissionsChanged(player);
}
private void OnUserPermissionRevoked(string playerId, string perm) {
if (perm != iconShowPerm && perm != iconHidePerm) return;
BasePlayer player = BasePlayer.Find(playerId);
if (player == null) return;
OnPermissionsChanged(player);
}
private void OnGroupPermissionGranted(string groupName, string perm) {
if (perm != iconShowPerm && perm != iconHidePerm) return;
BasePlayer.activePlayerList.ToList().ForEach(p => OnPermissionsChanged(p));
}
private void OnGroupPermissionRevoked(string groupName, string perm) {
if (perm != iconShowPerm && perm != iconHidePerm) return;
BasePlayer.activePlayerList.ToList().ForEach(p => OnPermissionsChanged(p));
}
private object OnWeaponReload(BaseProjectile weapon, BasePlayer player) {
Item item = weapon.GetCachedItem();
if (item == null) return null;
WeaponData weaponData;
if (TryGetWeaponData(player, item, out weaponData)) {
if (weaponData.FastReload) {
if (weapon.TryReloadMagazine(player.inventory, -1)) {
weapon.SetHeld(false);
weapon.SendChildrenNetworkUpdateImmediate();
timer.Once(0.2f, () => {
if (player.GetActiveItem().uid == weapon.ownerItemUID) weapon.SetHeld(true);
}
);
return false;
}
}
}
return null;
}
void OnMagazineReload(BaseProjectile weapon, IAmmoContainer ammoSource, BasePlayer owner) {
SetupMagizineCapacity(weapon);
}
private object OnWeaponModChange(BaseProjectile weapon, BasePlayer player) {
if (weapon == null) return null;
var currentCapacity = weapon.primaryMagazine.capacity;
SetupMagizineCapacity(weapon);
if (!config.GlobalSettings.DisableUnload) {
if (currentCapacity == weapon.primaryMagazine.capacity) return false;
if (weapon.primaryMagazine.contents > 0 && weapon.primaryMagazine.contents > weapon.primaryMagazine.capacity) {
Item item = weapon.GetItem();
if (item != null && player != null) weapon.UnloadAmmo(item, player);
}
}
return false;
}
void OnImpactEffectCreate(HitInfo info) {
AttackEntity weapon = info.Weapon;
if (weapon != null) {
CustomItem customItem;
string uniqueShortname = weapon.GetCachedItem()?.GetUniqueShortname();
if (uniqueShortname != null && TryGetCustomItemByKey(uniqueShortname, out customItem)) {
BaseEntity hitEntity = info.HitEntity;
if (hitEntity.IsValid()) {
if (customItem.EffectsEntity.ElecticBalls > 0) for (int i = 0; i < customItem.EffectsEntity.ElecticBalls; i++) Effect.server.Run("assets/prefabs/locks/keypad/effects/lock.code.shock.prefab", info.HitPositionWorld + UnityEngine.Random.insideUnitSphere * 1.5f);
}
else {
if (customItem.EffectsGround.ElecticBall) Effect.server.Run("assets/prefabs/locks/keypad/effects/lock.code.shock.prefab", info.HitPositionWorld);
}
}
}
}
object OnItemSplit(Item __item, int split_Amount) {
var uniqueShortname = __item.GetUniqueShortname();
if (uniqueShortname == null || !HasCustomItemWithKey(uniqueShortname)) return null;
global : : Item item = global : : ItemManager.CreateByItemID(__item.info.itemid, 1, 0UL);
item.amount = split_Amount;
item.skin = __item.skin;
item.name = __item.name;
item.SetUniqueShortname(uniqueShortname);
__item.MarkDirty();
return item;
}
object CanStackItem(Item item, Item targetItem) {
if (item.GetUniqueShortname() != targetItem.GetUniqueShortname()) return false;
return null;
}
object CanCombineDroppedItem(DroppedItem item, DroppedItem targetItem) {
if (item.item.GetUniqueShortname() != targetItem.item.GetUniqueShortname()) return false;
return null;
}
void UpdateItemName(Item item) {
if (item == null) return;
NextTick(() => {
string uniqueShortname = item.GetUniqueShortname();
CustomItem customItem;
if (uniqueShortname != null && TryGetCustomItemByKey(uniqueShortname, out customItem)) {
var nameLangKey = $"{uniqueShortname}:Name";
var itemName = GetMessage(nameLangKey, item.GetOwnerPlayer()?.UserIDString);
if (itemName == nameLangKey) itemName = customItem.Name;
SetName(item, customItem, itemName);
if (customItem.SkinId != 0) item.skin = customItem.SkinId;
item.MarkDirty();
}
else {
WeaponData weaponData;
if (TryGetWeaponData(item.GetOwnerPlayer(), item, out weaponData)) {
SetName(item, weaponData);
item.MarkDirty();
}
}
}
);
}
private void OnItemAddedToContainer(ItemContainer container, Item item) {
if (!container.HasFlag(ItemContainer.Flag.IsPlayer)) return;
if (container.playerOwner?.inventory?.loot?.IsLooting() != false) return;
if (!IsWeapon(item)) return;
UpdateItemName(item);
NextTick(() => {
SetupMagizineCapacity(item.GetHeldEntity() as BaseProjectile);
}
);
}
private void OnRocketLaunched(BasePlayer player, BaseEntity entity) {
var explosion = entity?.GetComponent<TimedExplosive>();
if (explosion == null) return;
Item item = player.GetActiveItem();
if (item == null) return;
UpdateHitDamage(explosion.damageTypes, item, player);
}
private void OnExplosiveThrown(BasePlayer player, BaseEntity entity) {
var explosion = entity?.GetComponent<TimedExplosive>();
if (explosion == null) return;
Item item = player.GetActiveItem();
if (item == null) return;
UpdateHitDamage(explosion.damageTypes, item, player);
}
private void OnExplosiveDropped(BasePlayer player, BaseEntity entity) {
var explosion = entity?.GetComponent<TimedExplosive>();
if (explosion == null) return;
Item item = player.GetActiveItem();
if (item == null) return;
UpdateHitDamage(explosion.damageTypes, item, player);
}
void OnEntityTakeDamage(BaseCombatEntity victim, HitInfo info) {
BasePlayer initiator = info.Initiator as BasePlayer;
if (initiator == null) return;
if (info.Weapon == null) {
Item activeItem = initiator.GetActiveItem();
if (activeItem != null) {
AttackEntity attackHeldEntity = activeItem.GetHeldEntity() as AttackEntity;
if (info.WeaponPrefab != null && attackHeldEntity != null && attackHeldEntity.PrefabName != info.WeaponPrefab.PrefabName) return;
info.Weapon = attackHeldEntity;
}
}
if (info.Weapon == null) return;
var item = info.Weapon.GetCachedItem();
if (item == null) return;
var ammoType = string.Empty;
if (info.Weapon is BaseProjectile) ammoType = (info.Weapon as BaseProjectile).primaryMagazine.ammoType.shortname;
if (info.Weapon is ThrownWeapon) ammoType = "throw";
if (info.Weapon is FlameThrower) ammoType = "ammo.lowgrade";
if (!string.IsNullOrEmpty(ammoType)) {
var coef = info.damageTypes.Total() / DefaultDamageWeapons[item.info.shortname][ammoType].Total();
UpdateHitDamage(info, initiator, coef);
}
else UpdateHitDamage(info, initiator);
if (info.HitEntity as DecayEntity) {
if (info.damageTypes.Has(Rust.DamageType.Cold)) info.damageTypes.Scale(Rust.DamageType.Cold, 0f);
if (info.damageTypes.Has(Rust.DamageType.Poison)) info.damageTypes.Scale(Rust.DamageType.Poison, 0f);
if (info.damageTypes.Has(Rust.DamageType.Bleeding)) info.damageTypes.Scale(Rust.DamageType.Bleeding, 0f);
if (info.damageTypes.Has(Rust.DamageType.Hunger)) info.damageTypes.Scale(Rust.DamageType.Hunger, 0f);
if (info.damageTypes.Has(Rust.DamageType.Thirst)) info.damageTypes.Scale(Rust.DamageType.Thirst, 0f);
if (info.damageTypes.Has(Rust.DamageType.Suicide)) info.damageTypes.Scale(Rust.DamageType.Suicide, 0f);
if (info.damageTypes.Has(Rust.DamageType.ElectricShock)) info.damageTypes.Scale(Rust.DamageType.ElectricShock, 0f);
if (info.damageTypes.Has(Rust.DamageType.Drowned)) info.damageTypes.Scale(Rust.DamageType.Drowned, 0f);
if (info.damageTypes.Has(Rust.DamageType.Fall)) info.damageTypes.Scale(Rust.DamageType.Fall, 0f);
if (info.damageTypes.Has(Rust.DamageType.Heat)) info.damageTypes.Scale(Rust.DamageType.Heat, 0f);
}
//Effects
BasePlayer victimPlayer = victim.ToPlayer();
if (victimPlayer && TryGetWeaponData(initiator as BasePlayer, item, out WeaponData weaponData)) {
var effects = weaponData.EffectsEntity;
if (!effects.RadPoison.Equals(0)) {
float rad = effects.RadPoison * victimPlayer.RadiationExposureFraction();
if (rad > 0) victimPlayer.metabolism.radiation_poison.value = Mathf.Clamp(victimPlayer.metabolism.radiation_poison.value + rad, victimPlayer.metabolism.radiation_poison.min, effects.ValuesSettings.MaxRadPoison);
}
if (!effects.Bleeding.Equals(0)) victimPlayer.metabolism.bleeding.value = Mathf.Clamp(victimPlayer.metabolism.bleeding.value + effects.Bleeding, victimPlayer.metabolism.bleeding.min, effects.ValuesSettings.MaxBleading);
if (!effects.Temperature.Equals(0)) {
float temperature = effects.Temperature;
if (temperature < 0) {
var ColdExposureFraction = (1f - Mathf.Clamp(victimPlayer.baseProtection.amounts[(int)Rust.DamageType.ColdExposure], 0f, 1f));
temperature *= ColdExposureFraction;
}
if (temperature != 0) victimPlayer.metabolism.temperature.value = Mathf.Clamp(victimPlayer.metabolism.temperature.value + temperature, effects.ValuesSettings.MinTemperature, effects.ValuesSettings.MaxTemperature);
}
if (!effects.Hunger.Equals(0)) victimPlayer.metabolism.calories.Subtract(effects.Hunger);
if (!effects.Thirst.Equals(0)) victimPlayer.metabolism.hydration.Subtract(effects.Thirst);
if (!effects.Wetness.Equals(0)) victimPlayer.metabolism.wetness.value = Mathf.Clamp(victimPlayer.metabolism.wetness.value + effects.Wetness, victimPlayer.metabolism.wetness.min, effects.ValuesSettings.MaxWetness);
}
}
private void OnLoseCondition(Item item, ref float amount) {
if (!IsWeapon(item)) return;
BasePlayer owner = item.GetOwnerPlayer();
if (owner == null) return;
WeaponData weaponData;
if (TryGetWeaponData(owner, item, out weaponData)) {
if (weaponData.Unbreakable) amount = 0f;
if (item._maxCondition == item.info.condition.max && weaponData.Durability != item.info.condition.max) {
float percentCondition = (item._condition / item._maxCondition);
item._maxCondition = weaponData.Durability;
item._condition = weaponData.Durability * percentCondition;
item.MarkDirty();
}
}
}
private void OnPlayerRespawned(BasePlayer player) => AddUiIcon(player);
private void OnPlayerConnected(BasePlayer player) => AddUiIcon(player);
private void OnPlayerLootEnd(PlayerLoot playerLoot) {
var player = (BasePlayer)playerLoot.baseEntity;
if (playerLoot.entitySource == RelationshipManager.ServerInstance) {
DestroyUI(player);
playerLoot.containers.Where(c => c.entityOwner == RelationshipManager.ServerInstance && c.capacity == 0).ToList().ForEach(c => c.Kill());
}
}
void OnLootEntity(BasePlayer player, BaseEntity entity) {
NextTick(() => {
foreach (var item in player.inventory.AllItems()) {
item.MarkDirty();
}
}
);
}
void OnLootEntityEnd(BasePlayer player, BaseCombatEntity entity) {
NextTick(() => {
foreach (var item in player.inventory.AllItems()) {
item.MarkDirty();
}
}
);
}
void OnAmmoSwitch(BaseProjectile baseProjectile, BasePlayer owner) {
UpdateItemName(baseProjectile.GetCachedItem());
}
void Unload() {
_harmony.UnpatchAll($"{this.Name}@{this.Author}");
BasePlayer.allPlayerList.ToList().ForEach(player => {
DestroyUI(player);
DestroyIcon(player);
}
);
}
#endregion
#region Commands
[ConsoleCommand("cw.reload")]
private void ConsoleCommandReload(ConsoleSystem.Arg arg) {
if (arg.Player() != null) {
if (!arg.Player().IsAdmin) {
SendReply(arg, "This command is only allowed to administrators");
return;
}
}
Server.Command($"o.reload {Name}");
if (arg.Player() != null) {
SendReply(arg, "Items successfully reloaded!");
return;
}
Puts("Items successfully reloaded");
}
[ConsoleCommand("cw.create")]
private void ConsoleCommandCreate(ConsoleSystem.Arg arg) {
if (arg.Player() != null) {
if (!arg.Player().IsAdmin) {
SendReply(arg, "This command is only allowed to administrators");
return;
}
}
if (arg.Args.IsNullOrEmpty() || arg.Args?.Count() != 2) {
if (arg.Player() != null) {
SendReply(arg, "Usage: cw.create <new unique shortname> <shortname>");
return;
}
PrintWarning("Usage: cw.create <new unique shortname> <shortname>");
return;
}
var name = arg.Args[0];
if (name.Contains(" ")) {
if(arg.Player() != null) {
SendReply(arg, "No spaces are allowed in the unique shortname!");
return;
}
PrintError("No spaces are allowed in the unique shortname!");
return;
}
var shortname = arg.Args[1];
if (config.DataItems.CustomFs.ExistsDatafile(name)) {
if (arg.Player() != null) {
SendReply(arg, "A file with this name already exists, delete it or create it under another name.");
return;
}
PrintWarning("A file with this name already exists, delete it or create it under another name.");
return;
}
if (!config.DataItems.Default.ContainsKey(shortname)) {
if (arg.Player() != null) {
SendReply(arg, $"The shortname '{shortname}' is not suitable, try another one, you can find available shortnames in the 'Default' folder");
return;
}
PrintWarning($"The shortname '{shortname}' is not suitable, try another one, you can find available shortnames in the 'Default' folder");
return;
}
var defaultItem = config.DataItems.Default[shortname];
CustomItem newItem = new CustomItem() {
Shortname = shortname, SkinId = 0, Name = name, Description = "", Unbreakable = defaultItem.Unbreakable, Durability = defaultItem.Durability, MagazineCapacity = defaultItem.MagazineCapacity, DamageTypes = defaultItem.DamageTypes, DamageTypeList = defaultItem.DamageTypeList
}
;
config.DataItems.CustomFs.WriteObject<CustomItem>(name, newItem);
config.DataItems.Custom[name] = newItem;
if (arg.Player() != null) {
SendReply(arg, $"Custom item with name '{name}' added!");
return;
}
Puts($"Custom item with name '{name}' added!");
}
[ConsoleCommand("cw.give")]
private void ConsoleCommandGive(ConsoleSystem.Arg arg) {
string nickname = "SERVER";
BasePlayer player = arg.Player();
if (player != null) {
if (!player.IsAdmin && !permission.UserHasPermission(player.UserIDString, giveCommandPerm)) {
arg.ReplyWith("You don't have permission to use this command.");
return;
}
nickname = player.displayName;
}
if (arg.Args.IsNullOrEmpty() || arg.Args?.Count() > 2 || arg.Args?.Count() < 1) {
if (player != null) {
arg.ReplyWith("Usage: cw.give <steamid/nickname> <custom item name>");
return;
}
PrintWarning("Usage: cw.give <steamid/nickname> <custom item name>");
return;
}
BasePlayer playerToGive = arg.Player();
if (arg.Args?.Count() == 2) {
playerToGive = BasePlayer.Find(arg.Args[0]);
if (playerToGive == null) {
if (player != null) {
arg.ReplyWith($"Player '{arg.Args[0]}' is offline or not exists.");
return;
}
PrintError($"Player '{arg.Args[0]}' is offline or not exists.");
return;
}
}
string uniqueShortname = arg.Args?.Last();
CustomItem customItem;
if (TryGetCustomItemByKey(uniqueShortname, out customItem)) {
Item itemToGive = ItemManager.CreateByName(uniqueShortname, 1, customItem.SkinId);
var nameLangKey = $"{uniqueShortname}:Name";
var itemName = GetMessage(nameLangKey, playerToGive.UserIDString);
if (itemName == nameLangKey) itemName = customItem.Name;
if (itemToGive.contents != null) {
foreach (var shortname in config.GlobalSettings.GiveOptions.Attachments.Where(pair => pair.Value).Select(x => x.Key)) {
Item item = ItemManager.CreateByName(shortname, 1, 0UL);
if (!item.MoveToContainer(itemToGive.contents, -1, true, false, null, true)) item.Remove(0f);
}
}
var heldEntity = itemToGive.GetHeldEntity();
if (heldEntity is BaseProjectile) {
BaseProjectile weapon = (heldEntity as BaseProjectile);
weapon.primaryMagazine.capacity = customItem.MagazineCapacity;
weapon.primaryMagazine.definition.builtInSize = customItem.MagazineCapacity;
weapon.primaryMagazine.contents = customItem.MagazineCapacity;
}
if (heldEntity is ThrownWeapon && itemToGive.MaxStackable() > 1) itemToGive.amount = 100;
if (!playerToGive.inventory.GiveItem(itemToGive)) {
itemToGive.Remove(0f);
arg.ReplyWith("Couldn't give item (inventory full?)");
PrintWarning($"{nickname}[{(player == null ? "0" : player.UserIDString)}] failed to give a custom item [{uniqueShortname}] to player {playerToGive.displayName}[{(player == null ? "0" : playerToGive.UserIDString)}]!");
return;
}
SetName(itemToGive, customItem, itemName);
itemToGive.skin = customItem.SkinId;
itemToGive.MarkDirty();
heldEntity.skinID = customItem.SkinId;
heldEntity.SendNetworkUpdate();
if (arg.Player() != null) arg.ReplyWith($"Item [{uniqueShortname}] added to {playerToGive.displayName}'s inventory!");
PrintWarning($"{nickname}[{(player == null ? "0" : player.UserIDString)}] gave {playerToGive.displayName}[{(playerToGive == null ? "0" : playerToGive.UserIDString)}] custom item [{uniqueShortname}]!");
}
else {
if (arg.Player() != null) {
arg.ReplyWith($"Item with name \"{uniqueShortname}\" was not found!");
return;
}
PrintError($"Item with name \"{uniqueShortname}\" was not found!");
}
}
#endregion
#region Classes
public class CustomItem : WeaponData {
public class UISettings {
[JsonProperty(PropertyName = "Name Color (or use <color></color> in name)")]
public string NameColor {
get;
set;
}
= "1 1 1 1";
[JsonProperty(PropertyName = "Frame Color")]
public string FrameColor {
get;
set;
}
= "0.94 0.75 0.15 1";
}
[JsonProperty(PropertyName = "Name")]
public string Name {
get;
set;
}
= "";
[JsonProperty(PropertyName = "Description")]
public string Description {
get;
set;
}
= "";
[JsonProperty(PropertyName = "SkinId")]
public ulong SkinId {
get;
set;
}
= 0;
[JsonProperty(PropertyName = "SkinId to recognize (MUST BE UNIQUE)")]
public ulong RecognizeSkinId {
get;
set;
}
= (ulong)UnityEngine.Random.Range(1000, 10000000);
//[JsonProperty(PropertyName = "Permission for use")]
//public string Permission { get; set; } = string.Empty;
[JsonProperty(PropertyName = "UI Settings")]
public UISettings UiSettings {
get;
set;
}
= new UISettings();
}
public class WeaponData {
public class EffectsEntitySettings {
public class __ValuesSettings {
[JsonProperty(PropertyName = "Max Radiation Poison")]
public float MaxRadPoison {
get;
set;
}
= 500;
[JsonProperty(PropertyName = "Max Bleading")]
public float MaxBleading {
get;
set;
}
= 100;
[JsonProperty(PropertyName = "Min Temperature")]
public float MinTemperature {
get;
set;
}
= -100;
[JsonProperty(PropertyName = "Max Temperature")]
public float MaxTemperature {
get;
set;
}
= 100;
[JsonProperty(PropertyName = "Max Wetness")]
public float MaxWetness {
get;
set;
}
= 100;
}
[JsonProperty(PropertyName = "Maximum and minimum values in the accumulation")]
public __ValuesSettings ValuesSettings {
get;
set;
}
= new __ValuesSettings();
[JsonProperty(PropertyName = "Radiation Poison")]
public float RadPoison {
get;
set;
}
[JsonProperty(PropertyName = "Bleading")]
public float Bleeding {
get;
set;
}
[JsonProperty(PropertyName = "Temperature")]
public float Temperature {
get;
set;
}
[JsonProperty(PropertyName = "Hunger")]
public float Hunger {
get;
set;
}
[JsonProperty(PropertyName = "Thirst")]
public float Thirst {
get;
set;
}
[JsonProperty(PropertyName = "Wetness")]
public float Wetness {
get;
set;
}
[JsonProperty(PropertyName = "Number of electric balls (recommended to 10)")]
public int ElecticBalls {
get;
set;
}
}
public class EffectsGroundSettings {
[JsonProperty(PropertyName = "Electric Ball")]
public bool ElecticBall {
get;
set;
}
}
[JsonProperty(PropertyName = "Shortname")]
public string Shortname {
get;
set;
}
[JsonProperty(PropertyName = "Unbreakable", NullValueHandling = NullValueHandling.Ignore)]
public bool Unbreakable {
get;
set;
}
[JsonProperty(PropertyName = "Durability", DefaultValueHandling = DefaultValueHandling.Ignore)]
public float Durability {
get;
set;
}
[JsonProperty(PropertyName = "Fast Reload")]
public bool FastReload {
get;
set;
}
= false;
[JsonProperty(PropertyName = "Magazine Capacity", DefaultValueHandling = DefaultValueHandling.Ignore)]
public int MagazineCapacity {
get;
set;
}
[JsonProperty(PropertyName = "Effects when hit")]
public EffectsEntitySettings EffectsEntity {
get;
set;
}
= new EffectsEntitySettings();
[JsonProperty(PropertyName = "Effects when hit the ground")]
public EffectsGroundSettings EffectsGround {
get;
set;
}
= new EffectsGroundSettings();
[JsonProperty(PropertyName = "Base damage by type & ammo", NullValueHandling = NullValueHandling.Ignore)]
public Dictionary<string, Dictionary<string, float>> DamageTypes {
get;
set;
}
[JsonIgnore]
public Dictionary<string, Rust.DamageTypeList> DamageTypeList {
get;
set;
}
= new Dictionary<string, Rust.DamageTypeList>();
}
#endregion
#region Fields
private static List<Rust.DamageType> DamageTypesExсeptions = new List<Rust.DamageType>() {
Rust.DamageType.Generic, Rust.DamageType.LAST, Rust.DamageType.Decay, Rust.DamageType.RadiationExposure, Rust.DamageType.ColdExposure, Rust.DamageType.Fun_Water, Rust.DamageType.Suicide, Rust.DamageType.Fall,
}
;
private static List<Rust.DamageType> DamageTypes = Enum.GetValues(typeof(Rust.DamageType)).Cast<Rust.DamageType>().Where(type => !DamageTypesExсeptions.Contains(type)).ToList();
private static Dictionary<Rust.DamageType, string> DamageTypeNames = DamageTypes.ToDictionary(type => type, type => Enum.GetName(typeof(Rust.DamageType), type));
private static Dictionary<string, Dictionary<string, Rust.DamageTypeList>> DefaultDamageWeapons = new Dictionary<string, Dictionary<string, Rust.DamageTypeList>>();
#endregion
#region Methods
private void SetName(Item item, WeaponData weaponData, string itemName = null) {
if (item == null || weaponData == null) return;
item.name = itemName;
item.streamerName = null;
if (!config.ItemSelectInfo) return;
BasePlayer owner = item.GetOwnerPlayer();
Dictionary<string, string> translation = null;
if (RustTranslationAPI != null && (itemName == null || itemName == string.Empty)) translation = RustTranslationAPI.Call<Dictionary<string, string>>("GetTranslations", lang.GetLanguage(owner?.UserIDString));
if (itemName == null || itemName == string.Empty) {
if (translation == null || !translation.TryGetValue($"{item.info.shortname}", out itemName)) itemName = item.info.displayName.translated;
}
Rust.DamageTypeList damageTypeListToRender = null;
BaseEntity heldEntity = item.GetHeldEntity();
if (heldEntity != null) {
BaseProjectile baseProjectile = heldEntity as BaseProjectile;
if (baseProjectile != null && baseProjectile.primaryMagazine != null) {
ItemDefinition ammoDef = baseProjectile.primaryMagazine.ammoType;
if (ammoDef != null) {
weaponData.DamageTypeList.TryGetValue(ammoDef.shortname, out damageTypeListToRender);
}
}
}
if (damageTypeListToRender == null && weaponData.DamageTypeList.Count > 0) damageTypeListToRender = weaponData.DamageTypeList.First().Value;
if (damageTypeListToRender == null) return;
Dictionary<string, float> FieldsForRender = DamageTypes.ToDictionary(x => GetMessage(DamageTypeNames[x], owner?.UserIDString), x => damageTypeListToRender.Get(x));
FieldsForRender = FieldsForRender.Where(i => i.Value != 0f).ToDictionary(i => i.Key, i => i.Value);
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append(string.Concat(Enumerable.Repeat("\n", FieldsForRender.Count * 2 + 8)));
stringBuilder.Append($"\n{itemName}");
stringBuilder.Append("\n\t\t\t\t\t\t\t\t\t\t\t\t" + GetMessage(LangKeys.ItemInfoPanelHeader, owner?.UserIDString));
foreach (var pair in FieldsForRender) {
string keyWithoutRichtext = Regex.Replace(pair.Key, "<.*?>", String.Empty);
stringBuilder.Append("\n\t\t\t\t\t\t\t\t\t\t\t\t ");
stringBuilder.Append(" " + keyWithoutRichtext);
stringBuilder.Append("\n\t\t\t\t\t\t\t\t\t\t\t\t\t ");
stringBuilder.Append(pair.Value);
}
stringBuilder.Append("\n\n\t\t\t\t\t\t\t\t\t\t\t\t" + GetMessage(LangKeys.CharacteristicsPanelHeader, owner?.UserIDString));
stringBuilder.Append("\n\t\t\t\t\t\t\t\t\t\t\t\t " + GetMessage(LangKeys.MagazineCapacity, owner?.UserIDString));
stringBuilder.Append("\n\t\t\t\t\t\t\t\t\t\t\t\t\t " + weaponData.MagazineCapacity);
stringBuilder.Append("\n\t\t\t\t\t\t\t\t\t\t\t\t " + GetMessage(LangKeys.MaxDurability, owner?.UserIDString));
stringBuilder.Append("\n\t\t\t\t\t\t\t\t\t\t\t\t\t " + weaponData.Durability);
stringBuilder.Append("\n\t\t\t\t\t\t\t\t\t\t\t\t " + GetMessage(LangKeys.Unbreakable, owner?.UserIDString));
stringBuilder.Append("\n\t\t\t\t\t\t\t\t\t\t\t\t\t " + (weaponData.Unbreakable ? GetMessage(LangKeys.Yes, owner?.UserIDString) : GetMessage(LangKeys.No, owner?.UserIDString)));
item.streamerName = stringBuilder.ToString();
item.MarkDirty();
}
private bool TryGetCustomItem(Item item, out KeyValuePair<string, CustomItem> customItemPair) => TryGetCustomItem(item.info.shortname, item.skin, item.GetUniqueShortname(), out customItemPair);
private bool TryGetCustomItem(string shortname, ulong skinid, out KeyValuePair<string, CustomItem> customItemPair) => TryGetCustomItem(shortname, skinid, null, out customItemPair);
private bool TryGetCustomItem(string shortname, ulong skinid, string uniqueShortname, out KeyValuePair<string, CustomItem> customItemPair) {
try {
customItemPair = config.DataItems.Custom.First(c => ((uniqueShortname != null && uniqueShortname.Length > 0 && c.Key == uniqueShortname) || (c.Value.Shortname == shortname && skinid != 0 && c.Value.RecognizeSkinId == skinid)));
return true;
}
catch {
customItemPair = default(KeyValuePair<string, CustomItem>);
return false;
}
}
private bool HasCustomItemWithKey(string key) {
return config.DataItems.Custom.ContainsKey(key);
}
private bool TryGetCustomItemByKey(string key, out CustomItem customItem) {
if (key == null || config?.DataItems?.Custom == null) {
customItem = null;
return false;
}
return config.DataItems.Custom.TryGetValue(key, out customItem);
}
private bool TryGetWeaponData(BasePlayer player, Item item, out WeaponData weaponData) => TryGetWeaponData(player, item.info.shortname, item.skin, item.GetUniqueShortname(), out weaponData);
private bool TryGetWeaponData(BasePlayer player, string shortname, ulong skinid, out WeaponData weaponData) => TryGetWeaponData(player, shortname, skinid, null, out weaponData);
private bool TryGetWeaponData(BasePlayer player, string shortname, ulong skinid, string text, out WeaponData weaponData) {
KeyValuePair<string, CustomItem> customItemPair;
if (TryGetCustomItem(shortname, skinid, text, out customItemPair)) {
weaponData = customItemPair.Value;
return true;
}
else return TryGetDefaultWeaponData(player, shortname, skinid, out weaponData);
}
private bool TryGetDefaultWeaponData(BasePlayer player, Item item, out WeaponData weaponData) => TryGetDefaultWeaponData(player, item.info.shortname, item.skin, out weaponData);
private bool TryGetDefaultWeaponData(BasePlayer player, string shortname, ulong skinid, out WeaponData weaponData) {
try {
if (!config.DataItems.Default.TryGetValue(shortname, out weaponData)) return false;
if (player != null) {
foreach (var perm in config.DataItems.Permissions) {
WeaponData tempWd = null;
if (perm.Value.TryGetValue(shortname, out tempWd) && permission.UserHasPermission(player.UserIDString, $"customizableweapons.{perm.Key}")) {
weaponData = tempWd;
break;
}
}
}
return weaponData != null;
}
catch {
weaponData = default(WeaponData);
return false;
}
}
private bool IsWeapon(Item item) {
var heldEntity = item.GetHeldEntity();
return heldEntity is BaseProjectile || heldEntity is BaseMelee || heldEntity is ThrownWeapon || heldEntity is FlameThrower;
}
private void UpdateHitDamage(HitInfo info, BaseEntity entity, float scale = 1f) {
if (info.Weapon is BaseProjectile) {
var shootableWeapon = info.Weapon as BaseProjectile;
var item = shootableWeapon.GetCachedItem();
if (item == null) return;
var ammotypeShortname = shootableWeapon.primaryMagazine.ammoType.shortname;
if (ammotypeShortname == null) return;
WeaponData weaponData = null;
if (TryGetWeaponData(entity.ToPlayer(), item, out weaponData)) {
Rust.DamageTypeList damageTypeList = null;
if (!weaponData.DamageTypeList.TryGetValue(ammotypeShortname, out damageTypeList)) {
PrintWarning($"There is no damage list in the item configuration (Shortname: {weaponData.Shortname})");
return;
}
for (int i = 0; i < damageTypeList.types.Length; i++) {
Console.WriteLine($"{info.damageTypes.types
// ... [Code preview truncated due to length. Full source in attached file] ...