C#:
using System;
using System.Collections.Generic;
using UnityEngine;
using Oxide.Core;
using Oxide.Core.Configuration;
using System.Linq;
using Newtonsoft.Json;
namespace Oxide.Plugins
{
[Info("RoadCopters", "ProxyAssistant", "1.1.5")]
[Description("Спавнит миникоптеры на дорогах и по команде с настройкой через конфиг")]
class RoadCopters : RustPlugin
{
private Configuration config;
private List<ulong> spawnedCopters = new List<ulong>();
private const string MinicopterPrefab = "assets/content/vehicles/minicopter/minicopter.entity.prefab";
private const string FuelShortname = "lowgradefuel";
#region Configuration
private class Configuration
{
[JsonProperty("Настройки спавна на дорогах")]
public RoadSettings Road = new RoadSettings();
[JsonProperty("Настройки команды /mc")]
public CommandSettings Command = new CommandSettings();
[JsonProperty("Общие настройки")]
public GeneralSettings General = new GeneralSettings();
public class RoadSettings
{
[JsonProperty("Включить автоматический спавн на дорогах")]
public bool Enabled = true;
[JsonProperty("Шанс спавна в точке проверки (0-100)")]
public float SpawnChance = 15f;
[JsonProperty("Дистанция между точками проверки дорог (метры)")]
public int CheckDistance = 40;
[JsonProperty("Количество топлива в дорожных коптерах")]
public int RoadFuelAmount = 0;
}
public class CommandSettings
{
[JsonProperty("Количество топлива при спавне командой")]
public int CommandFuelAmount = 100;
[JsonProperty("Право (permission) для использования команды")]
public string Permission = "roadcopters.admin";
}
public class GeneralSettings
{
[JsonProperty("Удалять дорожные коптеры при выгрузке плагина")]
public bool CleanupOnUnload = true;
}
}
protected override void LoadConfig()
{
base.LoadConfig();
try {
config = Config.ReadObject<Configuration>();
if (config == null) LoadDefaultConfig();
} catch {
LoadDefaultConfig();
}
SaveConfig();
}
protected override void LoadDefaultConfig() => config = new Configuration();
protected override void SaveConfig() => Config.WriteObject(config);
#endregion
#region Localization
protected override void LoadDefaultMessages()
{
lang.RegisterMessages(new Dictionary<string, string>
{
["NoPermission"] = "У вас нет прав на использование этой команды.",
["Spawned"] = "Миникоптер заспавнен и заправлен на {0} топлива!",
["RoadSpawnFinished"] = "Спавн завершен. На дорогах размещено {0} миникоптеров."
}, this);
}
private string Msg(string key, string id = null) => lang.GetMessage(key, this, id);
#endregion
void Init() => permission.RegisterPermission(config.Command.Permission, this);
void OnServerInitialized()
{
if (config.Road.Enabled)
SpawnCoptersOnRoads();
}
void Unload()
{
if (config.General.CleanupOnUnload)
{
foreach (var netId in spawnedCopters)
{
var entity = BaseNetworkable.serverEntities.Find(new NetworkableId(netId)) as BaseEntity;
if (entity != null && !entity.IsDestroyed)
entity.Kill();
}
}
}
[ChatCommand("mc")]
void CmdSpawnMinicopter(BasePlayer player, string command, string[] args)
{
if (!permission.UserHasPermission(player.UserIDString, config.Command.Permission))
{
SendReply(player, Msg("NoPermission", player.UserIDString));
return;
}
Vector3 spawnPos = player.transform.position + player.eyes.HeadForward() * 3f;
spawnPos.y = player.transform.position.y + 1.5f;
BaseEntity entity = GameManager.server.CreateEntity(MinicopterPrefab, spawnPos, Quaternion.Euler(0, player.transform.rotation.eulerAngles.y, 0));
if (entity == null) return;
entity.Spawn();
AddFuel(entity as Minicopter, config.Command.CommandFuelAmount);
SendReply(player, string.Format(Msg("Spawned", player.UserIDString), config.Command.CommandFuelAmount));
}
private void SpawnCoptersOnRoads()
{
int count = 0;
if (TerrainMeta.Path?.Roads == null) return;
foreach (var road in TerrainMeta.Path.Roads)
{
for (int i = 0; i < road.Path.Points.Length; i += config.Road.CheckDistance)
{
if (UnityEngine.Random.Range(0f, 100f) > config.Road.SpawnChance) continue;
Vector3 pos = road.Path.Points[i];
pos.y = TerrainMeta.HeightMap.GetHeight(pos) + 0.5f;
if (CanSpawnAt(pos))
{
BaseEntity entity = GameManager.server.CreateEntity(MinicopterPrefab, pos, Quaternion.Euler(0, UnityEngine.Random.Range(0f, 360f), 0));
if (entity != null)
{
entity.Spawn();
AddFuel(entity as Minicopter, config.Road.RoadFuelAmount);
spawnedCopters.Add(entity.net.ID.Value);
count++;
}
}
}
}
Puts(string.Format(Msg("RoadSpawnFinished"), count));
}
private bool CanSpawnAt(Vector3 pos)
{
int mask = LayerMask.GetMask("Construction", "Deployed", "Default", "World", "Tree");
return !Physics.CheckSphere(pos, 5f, mask);
}
private void AddFuel(Minicopter copter, int amount)
{
if (copter == null || amount <= 0) return;
// Используем базовый класс StorageContainer, который доступен всегда.
// У миникоптера бак — это единственный дочерний контейнер.
StorageContainer fuelContainer = copter.GetComponentInChildren<StorageContainer>();
if (fuelContainer != null && fuelContainer.inventory != null)
{
Item fuelItem = ItemManager.CreateByName(FuelShortname, amount);
if (fuelItem != null)
{
if (!fuelItem.MoveToContainer(fuelContainer.inventory))
fuelItem.Remove();
}
}
}
}
}