Создание плагина для Rust, который позволяет ограничить использование больших и маленьких грядок, требует знания языка программирования, на котором написаны плагины для сервера Rust. Большинство плагинов для Rust серверов пишутся на языке C# с использованием Oxide или uMod платформы, которая позволяет легко интегрировать сторонний код.
### Шаг 1: Установка uMod (ранее Oxide)
Прежде всего, убедитесь, что у вас установлен uMod на вашем сервере Rust. Это необходимо для работы плагинов.
### Шаг 2: Создание плагина
Для создания такого плагина, вам понадобится базовое знание C#. Вот примерный код плагина, который ограничивает количество грядок:
C#:
using Oxide.Core.Plugins;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Garden Beds Limit", "YourName", "1.0.0")]
[Description("Limits the number of large and small garden beds a player can place.")]
public class GardenBedsLimit : RustPlugin
{
private const string SmallGardenBedPrefab = "assets/prefabs/deployable/small planter box/small_planter_box.deployed.prefab";
private const string LargeGardenBedPrefab = "assets/prefabs/deployable/planter box/planter.large.deployed.prefab";
private const int MaxSmallGardenBeds = 10; // Максимальное количество маленьких грядок
private const int MaxLargeGardenBeds = 5; // Максимальное количество больших грядок
void OnEntityBuilt(Planner planner, GameObject go)
{
BasePlayer player = planner.GetOwnerPlayer();
if (player == null) return;
if (go.name.Equals(SmallGardenBedPrefab))
{
if (CountDeployed(player, SmallGardenBedPrefab) > MaxSmallGardenBeds)
{
player.ChatMessage($"You cannot place more than {MaxSmallGardenBeds} small garden beds.");
go.GetComponent<BaseEntity>().Kill();
}
}
else if (go.name.Equals(LargeGardenBedPrefab))
{
if (CountDeployed(player, LargeGardenBedPrefab) > MaxLargeGardenBeds)
{
player.ChatMessage($"You cannot place more than {MaxLargeGardenBeds} large garden beds.");
go.GetComponent<BaseEntity>().Kill();
}
}
}
private int CountDeployed(BasePlayer player, string prefabName)
{
int count = 0;
foreach (var entity in BaseNetworkable.serverEntities)
{
var baseEntity = entity as BaseEntity;
if (baseEntity != null && baseEntity.OwnerID == player.userID && baseEntity.PrefabName == prefabName)
{
count++;
}
}
return count;
}
}
}
Этот код является базовым примером и может потребовать доработок в зависимости от ваших конкретных требований и версии uMod. Он ограничивает количество маленьких и больших грядок, которые игрок может разместить, с немедленным удалением объекта, если лимит превышен.
### Шаг 3: Компиляция и установка плагина
- Сохраните код в файл с расширением
.cs
(например, GardenBedsLimit.cs
). - Загрузите этот файл в папку
oxide/plugins
на вашем сервере Rust. - Перезапустите сервер или используйте команду
oxide.reload
для загрузки нового плагина.
Не забудьте протестировать работу плагина после установки, чтобы убедиться, что все функционирует как задумано.
дополни плагин что бы можно было использовать все оружие а не только луки
using System;
using System.Collections.Generic;
using System.Linq;
using Rust;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Advanced Arrows", "Ryan", "2.1.3")]
[Description("Allows players with permission to use custom arrow types")]
class AdvancedArrows : RustPlugin
{
#region Declaration
private readonly Dictionary<ulong, ActiveArrow> ActiveArrows = new Dictionary<ulong, ActiveArrow>();
private ConfigFile configFile;
private readonly System.Random rnd = new System.Random();
private enum ArrowType
{
Wind,
Fire,
Explosive,
Knockdown,
Narco,
Poison,
None
}
#endregion
#region Config
private class ConfigFile
{
public Dictionary<ArrowType, Arrow> Arrows;
public ExplosionSettings ExplosionSettings;
public static ConfigFile DefaultConfig()
{
return new ConfigFile
{
Arrows = new Dictionary<ArrowType, Arrow>()
{
{ ArrowType.Wind, new Arrow() },
{ ArrowType.Fire, new Arrow() },
{ ArrowType.Explosive, new Arrow() },
{ ArrowType.Knockdown, new Arrow() },
{ ArrowType.Narco, new Arrow() },
{ ArrowType.Poison, new Arrow() },
},
ExplosionSettings = new ExplosionSettings()
};
}
}
protected override void LoadDefaultConfig()
{
PrintWarning("Generating default configuration file...");
configFile = ConfigFile.DefaultConfig();
}
protected override void LoadConfig()
{
base.LoadConfig();
configFile = Config.ReadObject<ConfigFile>();
}
protected override void SaveConfig() => Config.WriteObject(configFile);
#endregion
#region Lang
private new void LoadDefaultMessages()
{
lang.RegisterMessages(new Dictionary<string, string>
{
["Cmd_Types"] = "<color=orange>ARROW TYPES</color> \n{0}",
["Cmd_Switched"] = "You've switched your arrow type to '<color=orange>{0}</color>', you have <color=orange>{1}</color> uses until it's automatically deactivated.",
["Cmd_Disabled"] = "You've sucessfully <color=orange>disabled</color> your active arrow",
["Cmd_NoPerm"] = "You don't have permission to use arrow '<color=orange>{0}</color>'",
["Cmd_Price"] = "(<color=orange>{0}</color>x {1})",
["Cmd_Active"] = "<color=orange>Active Arrow</color>: {0}",
["Arrow_Disabled"] = "Your arrow has been automatically disabled",
["Error_NotSelected"] = "Your bow isn't drawn, you must select am arrow using '<color=orange>/arrow</color>'.",
["Error_InvalidEnt"] = "Your arrow didn't hit anything",
["Error_NotPlayer"] = "You can't hit an entity with arrow type '<color=orange>{0}</color>'.",
["Hit_Wind"] = "You hit <color=orange>{0}</color> with a <color=orange>Wind</color> arrow!",
["Hit_Fire"] = "You used a <color=orange>Fire</color> arrow! (<color=orange>{0}</color> HP remaining)",
["Hit_Explosive"] = "You used a <color=orange>Explosive</color> arrow! (<color=orange>{0}</color> HP remaining)",
["Hit_Knockdown"] = "You knocked <color=orange>{0}</color> out, choose his fate!",
["Hit_Narco"] = "You've sent <color=orange>{0}</color> to sleep, act quick before they wake up again!",
["Hit_Poison"] = "You've sucessfully poisoned <color=orange>{0}</color> (<color=orange>{1}</color> HP remaining)",
["Damaged_Poison"] = "You've been poisoned by an poisoned arrow, there's no cure!",
["Resources_Needed"] = "You need <color=orange>{0}</color>x <color=orange>{1}</color> to use that arrow",
["Resources_Spent"] = "The arrow you just used costed <color=orange>{0}</color>x <color=orange>{1}</color>"
}, this);
}
#endregion
#region Classes
private class ExplosionSettings
{
public float ExplosiveDamage;
public float ExplosionRadius;
public ExplosionSettings()
{
ExplosiveDamage = 50f;
ExplosionRadius = 10f;
}
}
private class Price
{
public bool Enabled;
public string ItemShortname;
public int ItemAmount;
public Price()
{
Enabled = true;
ItemShortname = "metal.refined";
ItemAmount = 30;
}
}
private class Arrow
{
public Price ArrowPrice;
public string Permission;
public int Uses;
public Arrow()
{
ArrowPrice = new Price();
Permission = "able";
Uses = 1;
}
}
private class ActiveArrow
{
public int Uses;
public ArrowType ArrowType;
public ActiveArrow()
{
}
public ActiveArrow(ArrowType type)
{
Uses = 0;
ArrowType = type;
}
}
#endregion
#region Methods
private bool IsPlayerArrow(ArrowType type)
{
switch (type)
{
case ArrowType.Explosive:
return false;
case ArrowType.Fire:
return false;
default:
return true;
}
}
private bool CanUseArrow(BasePlayer player, ArrowType type, BaseCombatEntity combatEntity, out Item outItem)
{
if (IsPlayerArrow(type) && combatEntity.ToPlayer() == null)
{
PrintToChat(player, Lang("Error_NotPlayer", player.UserIDString, type));
outItem = null;
return false;
}
var typeConfig = configFile.Arrows[type];
if (!typeConfig.ArrowPrice.Enabled)
{
outItem = null;
return true;
}
if (player.inventory.FindItemByItemID(typeConfig.ArrowPrice.ItemShortname) == null)
{
PrintToChat(player, Lang("Resources_Needed", player.UserIDString, typeConfig.ArrowPrice.ItemAmount,
ItemManager.CreateByPartialName(typeConfig.ArrowPrice.ItemShortname).info.displayName.english) ?? "<color=red>ITEM NOT FOUND</color>");
ActiveArrows.Remove(player.userID);
outItem = null;
return false;
}
var item = player.inventory.FindItemByItemID(typeConfig.ArrowPrice.ItemShortname);
var amount = player.inventory.GetAmount(item.info.itemid);
if (amount >= typeConfig.ArrowPrice.ItemAmount)
{
outItem = ItemManager.CreateByName(typeConfig.ArrowPrice.ItemShortname, typeConfig.ArrowPrice.ItemAmount) ?? ItemManager.CreateByName("metal.refined", 30);
return true;
}
outItem = null;
var neededAmount = typeConfig.ArrowPrice.ItemAmount - amount;
PrintToChat(player, Lang("Resources_Needed", player.UserIDString, neededAmount, item.info.displayName.english));
return false;
}
private void TakeItems(BasePlayer player, Item item)
{
player.inventory.Take(player.inventory.FindItemsByItemID(item.info.itemid), item.info.itemid, item.amount);
PrintToChat(player, Lang("Resources_Spent", player.UserIDString, item.amount, item.info.displayName.english));
}
private void FireArrow(Vector3 targetPos)
{
var entity = GameManager.server.CreateEntity("assets/bundled/prefabs/fireball.prefab", targetPos);
Effect.server.Run("assets/prefabs/weapons/satchelcharge/effects/satchel-charge-explosion.prefab", targetPos);
entity.Spawn();
}
private void ExplosiveArrow(Vector3 targetPos, BaseCombatEntity combatEnt)
{
Effect.server.Run("assets/prefabs/npc/patrol helicopter/effects/rocket_explosion.prefab", targetPos);
var vicinityEnts = new List<BaseCombatEntity>();
var damage = configFile.ExplosionSettings.ExplosiveDamage;
Vis.Entities(targetPos, configFile.ExplosionSettings.ExplosionRadius, vicinityEnts);
foreach (var vicinityEnt in vicinityEnts)
{
var scaledDamage = damage - Vector3.Distance(targetPos, vicinityEnt.transform.position) * 2;
vicinityEnt.Hurt(scaledDamage, DamageType.Explosion);
}
}
private bool CanActivateArrow(BasePlayer player, ArrowType type)
{
var typeConfig = configFile.Arrows[type];
if (!permission.UserHasPermission(player.UserIDString, Name + "." + typeConfig.Permission))
{
PrintToChat(player, Lang("Cmd_NoPerm", player.UserIDString, type));
return false;
}
return true;
}
private void DealWithArrow(BasePlayer player, ActiveArrow arrow)
{
if (!CanActivateArrow(player, arrow.ArrowType))
return;
if (!ActiveArrows.ContainsKey(player.userID))
ActiveArrows.Add(player.userID, arrow);
else
ActiveArrows[player.userID] = arrow;
PrintToChat(player, Lang("Cmd_Switched", player.UserIDString, arrow.ArrowType, configFile.Arrows[arrow.ArrowType].Uses));
}
private void DealWithRemoval(BasePlayer player)
{
ActiveArrows[player.userID].Uses++;
if (ActiveArrows[player.userID].Uses >= configFile.Arrows[ActiveArrows[player.userID].ArrowType].Uses)
{
PrintToChat(player, Lang("Arrow_Disabled", player.UserIDString));
ActiveArrows.Remove(player.userID);
}
}
private string Lang(string key, string id = null, params object[] args) => string.Format(lang.GetMessage(key, this, id), args);
private string GetHelpMsg(BasePlayer player)
{
var msgList = new List<string>();
var msg = "";
foreach (var type in Enum.GetValues(typeof(ArrowType)).Cast<ArrowType>())
{
if(type.Equals(ArrowType.None)) continue;
var configType = configFile.Arrows[type];
msgList.Add(type + " " + (configType.ArrowPrice.Enabled ? Lang("Cmd_Price", player.UserIDString, configType.ArrowPrice.ItemAmount,
ItemManager.CreateByPartialName(configType.ArrowPrice.ItemShortname).info.displayName.english ?? "<color=red>ITEM NOT FOUND</color>") : ""));
}
msg = "\t" + string.Join("\n\t", msgList.ToArray());
if (ActiveArrows.ContainsKey(player.userID))
msg += "\n" + Lang("Cmd_Active", player.UserIDString, ActiveArrows[player.userID].ArrowType);
return msg;
}
#endregion
#region Hooks
private void Init()
{
foreach (var arrow in configFile.Arrows)
{
if (!permission.PermissionExists(Name + "." + arrow.Value.Permission, this))
permission.RegisterPermission(Name + "." + arrow.Value.Permission, this);
}
}
private void OnPlayerAttack(BasePlayer attacker, HitInfo hitInfo)
{
if (hitInfo == null || attacker == null || hitInfo.WeaponPrefab == null || hitInfo.Weapon == null)
return;
if (hitInfo.WeaponPrefab.ToString().Contains("hunting") || hitInfo.Weapon.name.Contains("bow") && attacker.IsAdmin)
{
var hitEntity = hitInfo.HitEntity as BaseCombatEntity;
if (hitEntity != null)
{
ActiveArrow arrow;
if (ActiveArrows.TryGetValue(attacker.userID, out arrow))
{
Item foundItem;
switch (arrow.ArrowType)
{
case ArrowType.Wind:
{
if (!CanUseArrow(attacker, arrow.ArrowType, hitEntity, out foundItem))
return;
TakeItems(attacker, foundItem);
var windPlayer = hitEntity.ToPlayer();
windPlayer.MovePosition(windPlayer.transform.position + new Vector3(1, rnd.Next(5, 11), 1));
timer.Repeat(0.1f, 30, () => windPlayer.violationLevel = 0);
PrintToChat(attacker, Lang("Hit_Wind", attacker.UserIDString, windPlayer.name));
DealWithRemoval(attacker);
return;
}
case ArrowType.Fire:
{
if (!CanUseArrow(attacker, arrow.ArrowType, hitEntity, out foundItem))
return;
TakeItems(attacker, foundItem);
NextTick(() =>
{
FireArrow(hitInfo.HitPositionWorld);
PrintToChat(attacker, Lang("Hit_Fire", attacker.UserIDString, Math.Round(hitEntity.Health(), 1)));
});
DealWithRemoval(attacker);
return;
}
case ArrowType.Explosive:
{
if (!CanUseArrow(attacker, arrow.ArrowType, hitEntity, out foundItem))
return;
TakeItems(attacker, foundItem);
NextTick(() =>
{
ExplosiveArrow(hitInfo.HitPositionWorld, hitEntity);
PrintToChat(attacker, Lang("Hit_Explosive", attacker.UserIDString, Math.Round(hitEntity.Health(), 1)));
});
DealWithRemoval(attacker);
return;
}
case ArrowType.Knockdown:
{
if (!CanUseArrow(attacker, arrow.ArrowType, hitEntity, out foundItem))
return;
TakeItems(attacker, foundItem);
var knockdownPlayer = hitEntity.ToPlayer();
NextTick(() => PrintToChat(attacker, Lang("Hit_Knockdown", attacker.UserIDString, knockdownPlayer.name, Math.Round(knockdownPlayer.health, 1))));
knockdownPlayer.BecomeWounded();
DealWithRemoval(attacker);
return;
}
case ArrowType.Narco:
{
if (!CanUseArrow(attacker, arrow.ArrowType, hitEntity, out foundItem))
return;
TakeItems(attacker, foundItem);
var narcoPlayer = hitEntity.ToPlayer();
NextTick(() => PrintToChat(attacker, Lang("Hit_Narco", attacker.UserIDString, narcoPlayer.name, Math.Round(narcoPlayer.health, 1))));
narcoPlayer.StartSleeping();
DealWithRemoval(attacker);
return;
}
case ArrowType.Poison:
{
if (!CanUseArrow(attacker, arrow.ArrowType, hitEntity, out foundItem))
return;
TakeItems(attacker, foundItem);
var poisonPlayer = hitEntity.ToPlayer();
NextTick(() => PrintToChat(attacker, Lang("Hit_Poison", attacker.UserIDString, poisonPlayer.name, Math.Round(poisonPlayer.Health(), 1))));
PrintToChat(poisonPlayer, Lang("Damaged_Poison", poisonPlayer.UserIDString));
poisonPlayer.metabolism.poison.value = 30;
DealWithRemoval(attacker);
return;
}
}
}
else
{
if (ActiveArrows.ContainsKey(attacker.userID))
ActiveArrows.Remove(attacker.userID);
}
}
}
}
[ChatCommand("arrow")]
private void ArrowCommand(BasePlayer player, string command, string[] args)
{
if (args.Length >= 1)
{
switch (args[0].ToLower())
{
case "wind":
DealWithArrow(player, new ActiveArrow(ArrowType.Wind));
return;
case "fire":
DealWithArrow(player, new ActiveArrow(ArrowType.Fire));
return;
case "explosive":
DealWithArrow(player, new ActiveArrow(ArrowType.Explosive));
return;
case "knockdown":
DealWithArrow(player, new ActiveArrow(ArrowType.Knockdown));
return;
case "narco":
DealWithArrow(player, new ActiveArrow(ArrowType.Narco));
return;
case "poison":
DealWithArrow(player, new ActiveArrow(ArrowType.Poison));
return;
case "none":
if (!ActiveArrows.ContainsKey(player.userID))
goto default;
ActiveArrows[player.userID] = new ActiveArrow(ArrowType.None);
PrintToChat(player, Lang("Cmd_Disabled", player.UserIDString, ArrowType.None));
return;
default:
PrintToChat(player, Lang("Cmd_Types", player.UserIDString, GetHelpMsg(player)));
return;
}
}
PrintToChat(player, Lang("Cmd_Types", player.UserIDString, GetHelpMsg(player)));
}
#endregion
}
}