C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using Facepunch;
using Network;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using ProtoBuf;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text.RegularExpressions;
using UnityEngine;
//Added group-based recycling quality (defaults to 0.5 - native)
//Added group-based recycling rates (defaults to 5s - native)
namespace Oxide.Plugins
{
[Info ( "PortableRecycler", "Raul-Sorin Sorban", "1.1.1" )]
[Description ( "A system that provides portable recyclers for players." )]
public class PortableRecycler : RustPlugin
{
public static PortableRecycler Instance { get; set; }
public Dictionary<ulong, Recycler> Recyclers { get; set; } = new Dictionary<ulong, Recycler> ();
public Dictionary<ulong, float> CooledDownPlayers { get; set; } = new Dictionary<ulong, float> ();
public Recycler GetRecycler ( BasePlayer player )
{
if ( player == null ) return null;
foreach ( var x in Recyclers )
{
if ( x.Key == player.userID )
{
var recycler = x.Value;
if ( recycler != null )
{
recycler.transform.position = GetPosition ( player );
recycler.SendNetworkUpdateImmediate ();
recycler.UpdateNetworkGroup ();
ApplySettings ( recycler, player );
}
return recycler;
}
}
return null;
}
public static T Get<T> ( string type, string property, object instance )
{
return ( T )typeof ( RootConfig ).GetNestedType ( type ).GetProperty ( property ).GetValue ( instance );
}
public Recycler SetRecycler ( BasePlayer player, Recycler recycler )
{
if ( Recyclers.ContainsKey ( player.userID ) )
Recyclers [ player.userID ] = recycler;
else Recyclers.Add ( player.userID, recycler );
return recycler;
}
public bool CanOpenRecycler ( BasePlayer player, out string reason )
{
reason = null;
if ( IsCooledDown ( player, false ) )
{
reason = string.Format ( Config.Phrases.CooledDown, GetCooldownSecondsLeft ( player ).ToString ( "0" ) );
return false;
}
if ( !Config.Rules.CanUseRecyclerWhileBuildingBlocked && !player.CanBuild () )
{
reason = Config.Phrases.BuildingBlocked;
return false;
}
if ( NoEscape != null )
{
if ( !Config.Rules.CanUseRecyclerWhileCombatBlocked && NoEscape.Call<bool> ( "IsCombatBlocked", player ) )
{
reason = Config.Phrases.CombatBlocked;
return false;
}
if ( !Config.Rules.CanUseRecyclerWhileRaidBlocked && NoEscape.Call<bool> ( "IsRaidBlocked", player ) )
{
reason = Config.Phrases.RaidBlocked;
return false;
}
}
return true;
}
public bool HasLockerContents ( BasePlayer player )
{
var locker = GetRecycler ( player );
if ( locker == null ) return false;
return locker.inventory.itemList.Count > 0;
}
public bool IsCooledDown ( BasePlayer player, bool coolDownPlayer = true )
{
foreach ( var group in Config.GroupCooldowns )
{
if ( permission.UserHasGroup ( player.UserIDString, group.Key ) )
{
if ( CooledDownPlayers.ContainsKey ( player.userID ) )
{
if ( Time.realtimeSinceStartup - CooledDownPlayers [ player.userID ] > group.Value )
{
if ( coolDownPlayer )
{
CooledDownPlayers [ player.userID ] = Time.realtimeSinceStartup;
return true;
}
else
{
CooledDownPlayers.Remove ( player.userID );
return false;
}
}
else
{
return true;
}
}
else if ( coolDownPlayer )
{
CooledDownPlayers.Add ( player.userID, Time.realtimeSinceStartup );
return true;
}
}
}
return false;
}
public float GetCooldownSecondsLeft ( BasePlayer player )
{
if ( IsCooledDown ( player, false ) )
{
foreach ( var group in Config.GroupCooldowns )
{
if ( permission.UserHasGroup ( player.UserIDString, group.Key ) )
{
return group.Value - ( Time.realtimeSinceStartup - CooledDownPlayers [ player.userID ] );
}
}
}
return 0f;
}
public float GetRate ( BasePlayer player )
{
foreach ( var group in Config.GroupRate )
{
if ( permission.UserHasGroup ( player.UserIDString, group.Key ) )
{
return group.Value;
}
}
return 5f;
}
public float GetQuality ( BasePlayer player )
{
foreach ( var group in Config.GroupQuality )
{
if ( permission.UserHasGroup ( player.UserIDString, group.Key ) )
{
return group.Value;
}
}
return 0.5f;
}
public void ApplySettings ( Recycler recycler, BasePlayer player )
{
recycler.recycleEfficiency = GetQuality ( player );
}
public const string RecyclerPrefab = "assets/bundled/prefabs/static/recycler_static.prefab";
public const string OpenEffect = "assets/prefabs/deployable/locker/effects/locker-deploy.prefab";
#region Permissions
public const string UsePerm = "portablerecycler.use";
public void InstallPermissions ()
{
permission.RegisterPermission ( UsePerm, this );
}
private bool HasPermission ( BasePlayer player, string perm, bool quiet = false )
{
if ( !permission.UserHasPermission ( player.UserIDString, perm ) )
{
if ( !quiet ) Print ( $"You need to have the \"{perm}\" permission.", player );
return false;
}
return true;
}
#endregion
#region Hooks
private void OnServerInitialized ()
{
Instance = this;
Loaded ();
InstallPermissions ();
InstallCommands ();
RefreshPlugins ();
}
private void Loaded ()
{
if ( Instance == null ) return;
if ( ConfigFile == null ) ConfigFile = new Core.Configuration.DynamicConfigFile ( $"{Manager.ConfigPath}{Path.DirectorySeparatorChar}{Name}.json" );
if ( DataFile == null ) DataFile = Interface.Oxide.DataFileSystem.GetFile ( $"{Name}_data" );
if ( !ConfigFile.Exists () )
{
Config = new RootConfig ();
ConfigFile.WriteObject ( Config );
}
else
{
try
{
Config = ConfigFile.ReadObject<RootConfig> ();
}
catch ( Exception exception )
{
Puts ( $"Broken configuration: {exception.Message}" );
}
}
if ( Config != null )
{
var updated = false;
if ( Config.GroupCooldowns == null )
{
Config.GroupCooldowns = new Dictionary<string, float> ();
Config.GroupCooldowns.Add ( "default", 60f );
updated = true;
}
if ( Config.GroupRate == null )
{
Config.GroupRate = new Dictionary<string, float> ();
Config.GroupRate.Add ( "default", 5 );
updated = true;
}
if ( Config.GroupQuality == null )
{
Config.GroupQuality = new Dictionary<string, float> ();
Config.GroupQuality.Add ( "default", 0.5f );
updated = true;
}
if ( updated )
{
ConfigFile.WriteObject ( Config ?? ( Config = new RootConfig () ) );
}
}
}
private void Unload ()
{
foreach ( var locker in Recyclers )
{
if ( locker.Value == null || locker.Value.IsDestroyed ) continue;
var player = BasePlayer.FindByID ( locker.Key );
if ( player != null ) DropUtil.DropItems ( locker.Value.inventory, player.eyes.transform.position );
locker.Value?.Kill ();
}
Recyclers.Clear ();
}
private void OnPluginLoaded ( Plugin name )
{
RefreshPlugins ();
}
private void OnPluginUnloaded ( Plugin name )
{
RefreshPlugins ();
}
private object OnEntityVisibilityCheck ( BaseEntity ent, BasePlayer player, uint id, string debugName, float maximumDistance )
{
var recycler = ent as Recycler;
if ( recycler == null ) return null;
if ( Recyclers.ContainsKey ( player.userID ) && Recyclers [ player.userID ] == ent )
{
return true;
}
return null;
}
private object OnEntityDistanceCheck ( BaseEntity ent, BasePlayer player, uint id, string debugName, float maximumDistance )
{
var recycler = ent as Recycler;
if ( recycler == null ) return null;
if ( Recyclers.ContainsKey ( player.userID ) && Recyclers [ player.userID ] == ent )
{
return true;
}
return null;
}
private object CanLootPlayer ( BasePlayer looted, BasePlayer looter )
{
var recycler = GetRecycler ( looter );
if ( recycler != null && looter.inventory.loot.containers.Count > 0 && recycler.inventory == looter.inventory.loot.containers [ 0 ] )
{
return true;
}
return null;
}
private object OnLootEntityEnd ( BasePlayer player, Recycler recycler )
{
if ( recycler == GetRecycler ( player ) )
{
DropUtil.DropItems ( recycler.inventory, player.eyes.transform.position );
// recycler.Kill ();
}
return null;
}
object OnRecyclerToggle ( Recycler recycler, BasePlayer player )
{
if ( recycler == GetRecycler ( player ) )
{
if ( recycler.IsOn () )
{
recycler.StopRecycling ();
Effect.server.Run ( recycler.stopSound.resourcePath, player, 0u, Vector3.zero, Vector3.zero );
}
else if ( !recycler.IsOn () )
{
foreach ( Item item in recycler.inventory.itemList )
{
item.CollectedForCrafting ( player );
}
var rate = GetRate ( player );
recycler.InvokeRepeating ( recycler.RecycleThink, rate, rate );
Effect.server.Run ( recycler.startSound.resourcePath, player, 0u, Vector3.zero, Vector3.zero );
recycler.SetFlag ( BaseEntity.Flags.On, b: true );
}
recycler.SendNetworkUpdateImmediate ();
return false;
}
return null;
}
private void OnServerSave ()
{
if ( Instance == null ) return;
ConfigFile.WriteObject ( Config ?? ( Config = new RootConfig () ) );
}
#endregion
#region Plugins
private Plugin NoEscape;
#endregion
#region Helpers
public void Print ( object message, BasePlayer player = null )
{
if ( player == null ) ConsoleNetwork.BroadcastToAllClients ( "chat.add", 2, Config.ChatIconSteamId, $"<color=orange>{Config.Prefix}</color>: {message}" );
else player.SendConsoleCommand ( "chat.add", 2, Config.ChatIconSteamId, $"<color=orange>{Config.Prefix}</color> (OY): {message}" );
}
public float Scale ( float oldValue, float oldMin, float oldMax, float newMin, float newMax )
{
var num = oldMax - oldMin;
var num2 = newMax - newMin;
return ( oldValue - oldMin ) * num2 / num + newMin;
}
public string Join ( string [] array, string separator, string lastSeparator = null )
{
if ( string.IsNullOrEmpty ( lastSeparator ) )
{
lastSeparator = separator;
}
if ( array.Length == 0 )
{
return string.Empty;
}
if ( array.Length == 1 )
{
return array [ 0 ];
}
var list = Pool.GetList<string> ();
for ( int i = 0; i < array.Length - 1; i++ )
{
list.Add ( array [ i ] );
}
var value = string.Join ( separator, list.ToArray () );
Pool.FreeList ( ref list );
return value + $"{lastSeparator}{array [ array.Length - 1 ]}";
}
public void SendEffectTo ( string effect, BasePlayer player )
{
if ( player == null ) return;
var effectInstance = new Effect ();
effectInstance.Init ( Effect.Type.Generic, player, 0, Vector3.up, Vector3.zero );
effectInstance.pooledstringid = StringPool.Get ( effect );
NetWrite write = Net.sv.StartWrite();
write.PacketID ( Message.Type.Effect );
effectInstance.WriteToStream ( write );
write.Send ( new SendInfo ( player.net.connection ) );
effectInstance.Clear ();
}
public Vector3 GetPosition ( BasePlayer player )
{
var position = player.transform.position;
return new Vector3 ( position.x, position.y - 50f, position.z );
}
public Recycler CreateRecycler ( BasePlayer forPlayer )
{
var recycler = GameManager.server.CreateEntity ( RecyclerPrefab, GetPosition ( forPlayer ), Quaternion.identity ) as Recycler;
recycler.skinID = 8008132;
recycler.OwnerID = forPlayer.userID;
recycler.Spawn ();
ProcessRecycler ( recycler );
return recycler;
}
public void ProcessRecycler ( Recycler recycler )
{
if ( recycler == null ) return;
UnityEngine.Object.DestroyImmediate ( recycler.GetComponent<DestroyOnGroundMissing> () );
UnityEngine.Object.DestroyImmediate ( recycler.GetComponent<GroundWatch> () );
recycler.GetComponent<DecayEntity> ().decay = null;
}
public void StartLooting ( BasePlayer player, Recycler recycler )
{
if ( Config.PlayOpenEffect ) SendEffectTo ( OpenEffect, player );
timer.In ( 0.2f, () =>
{
player.inventory.loot.StartLootingEntity ( recycler, false );
player.inventory.loot.AddContainer ( recycler.inventory );
player.inventory.loot.PositionChecks = false;
player.inventory.loot.SendImmediate ();
player.ClientRPCPlayer ( null, player, "RPC_OpenLootPanel", recycler.panelName );
} );
IsCooledDown ( player );
}
public void EnsureEntityToPlayer ( BasePlayer player, BaseEntity player2 )
{
var connection = player.Connection;
if ( connection == null ) return;
++connection.validate.entityUpdates;
var saveInfo = new BaseNetworkable.SaveInfo () { forConnection = connection, forDisk = false };
NetWrite write = Net.sv.StartWrite();
write.PacketID ( Network.Message.Type.Entities );
write.UInt32 ( connection.validate.entityUpdates );
player2.ToStreamForNetwork ( ( Stream )write, saveInfo );
write.Send ( new SendInfo ( connection ) );
}
public void RefreshPlugins ()
{
if ( NoEscape == null || !NoEscape.IsLoaded ) NoEscape = plugins.Find ( nameof ( NoEscape ) );
}
#endregion
#region Methods
public void InstallCommands ()
{
cmd.AddChatCommand ( Config.OpenCommand, this, ( player, command, args ) => OpenRecycler ( player, args ) );
cmd.AddConsoleCommand ( Config.OpenCommand, this, ( arg ) => { OpenRecycler ( arg.Player (), arg.Args ); return true; } );
}
public void OpenRecycler ( BasePlayer player, string [] args )
{
if ( player == null || !HasPermission ( player, UsePerm ) ) return;
var reason = string.Empty;
if ( !CanOpenRecycler ( player, out reason ) )
{
Print ( reason, player );
return;
}
var recycler = GetRecycler ( player );
if ( recycler == null ) recycler = SetRecycler ( player, CreateRecycler ( player ) );
EnsureEntityToPlayer ( player, recycler );
StartLooting ( player, recycler );
}
#endregion
#region Config
public Core.Configuration.DynamicConfigFile ConfigFile { get; set; }
public Core.Configuration.DynamicConfigFile DataFile { get; set; }
public new RootConfig Config { get; set; } = new RootConfig ();
public class RootConfig
{
public string Prefix { get; set; } = "Portable Recycler";
public string OpenCommand { get; set; } = "recycler";
public bool PlayOpenEffect { get; set; } = true;
public ulong ChatIconSteamId { get; set; } = 0UL;
public RuleSettings Rules { get; set; } = new RuleSettings ();
public PhraseSettings Phrases { get; set; } = new PhraseSettings ();
public Dictionary<string, float> GroupCooldowns { get; set; }
public Dictionary<string, float> GroupRate { get; set; }
public Dictionary<string, float> GroupQuality { get; set; }
public class RuleSettings
{
public bool CanUseRecyclerWhileBuildingBlocked { get; set; } = true;
public bool CanUseRecyclerWhileCombatBlocked { get; set; } = true;
public bool CanUseRecyclerWhileRaidBlocked { get; set; } = true;
}
public class PhraseSettings
{
public string CooledDown { get; set; } = "You're in cooldown.\n<size=12><color=orange>{0}</color> seconds left.</size>";
public string BuildingBlocked { get; set; } = "You're building-blocked.";
public string CombatBlocked { get; set; } = "You're combat-blocked.";
public string RaidBlocked { get; set; } = "You're raid-blocked.";
public string CloseClear { get; set; } = "Your <color=orange>Portable Recycler</color> emptied as you cannot store items inside of it.";
}
}
#endregion
}
}
///Скачано с дискорд сервера The Rust Bay & Rust Edit [PRO+] Cooperative
///https://notes.xxi2.com/ms8mr