C#:
using Network;
using Oxide.Core;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace Oxide.Plugins {
[Info("Trade", "https://topplugin.ru / https://discord.com/invite/5DPTsRmd3G", "1.0.3")]
public class Trade : RustPlugin {
[PluginReference]
Plugin Duel;
public Timer mytimer;
private Dictionary<BasePlayer, DateTime> Cooldowns = new Dictionary<BasePlayer, DateTime>();
private static Trade m_Instance;
private Dictionary<string, TradeController> m_Boxes = new Dictionary<string, TradeController>();
private static Dictionary<string, ShopFront> boxes = new Dictionary<string, ShopFront>();
private static Dictionary<string, List<BasePlayer>> players = new Dictionary<string, List<BasePlayer>>();
private List<ulong> tradingPlayers = new List<ulong>();
private Dictionary<BasePlayer, BasePlayer> pendings = new Dictionary<BasePlayer, BasePlayer>();
bool getCupAuth = true;
bool getCupSend = true;
bool getFly = true;
bool getSwim = true;
bool getWound = true;
int getTime = 15;
private double CooldownTrade = 60f;
public int getInt = 8;
public string Permission = "trade.use";
public bool UsePermission = false;
private void LoadDefaultConfig() {
GetConfig("Основное", "Запретить отправлять запрос в BuildingBlock", ref getCupSend);
GetConfig("Основное", "Запретить принимать запрос в BuildingBlock", ref getCupAuth);
GetConfig("Основное", "Запретить отправлять запрос в BuildingBlock", ref getCupSend);
GetConfig("Основное", "Запретить использовать трейд в полёте", ref getFly);
GetConfig("Основное", "Запретить использовать трейд в воде", ref getSwim);
GetConfig("Основное", "Запретить использовать трейд в предсмертном состоянии", ref getWound);
GetConfig("Основное", "Время ответа на предложения обмена (секунд)", ref getTime);
GetConfig("Основное", "Задержка использования трейда (Cooldown - секунд)", ref CooldownTrade);
GetConfig("Основное", "Количество активных слотов при обмене", ref getInt);
GetConfig("Основное", "Привилегия на использование команды trade", ref Permission);
GetConfig("Основное", "Разрешить использование трейда только если игрок имеет привилегию указаную в конфиге", ref UsePermission);
SaveConfig();
}
private void GetConfig<T>(string menu, string Key, ref T var) {
if (Config[menu, Key] != null) {
var = (T)Convert.ChangeType(Config[menu, Key], typeof(T));
}
Config[menu, Key] = var;
}
private void Loaded() {
m_Instance = this;
LoadDefaultConfig();
permission.RegisterPermission(Permission, this);
}
void Unload() {
foreach (var trade in m_Boxes.ToList()) {
OnTradeCanceled(trade.Value.guid);
Destroy(trade.Key);
UnityEngine.Object.Destroy(trade.Value, 0.1f);
}
}
private void OnShopCompleteTrade(ShopFront shop) {
var trade = m_Boxes.Select(p => p.Value).FirstOrDefault(p => p.shop == shop);
if (trade != null) {
SendReply(trade.player1, "<color=#ee3e61>Система обмена</color>\nTrade успешно завершён!");
SendReply(trade.player2, "<color=#ee3e61>Система обмена</color>\nTrade успешно завершён!");
Cooldowns[trade.player1] = DateTime.Now.AddSeconds(CooldownTrade);
Cooldowns[trade.player2] = DateTime.Now.AddSeconds(CooldownTrade);
timer.Once(1.0f, () => {
trade.player1.EndLooting();
trade.player2.EndLooting();
}
);
}
}
[ConsoleCommand("trade")]
void cmdTrade(ConsoleSystem.Arg arg) {
var player = arg.Player();
if (player == null || arg.Args.Length == 0) return;
var name = arg.Args[0];
CmdChatTrade(player, string.Empty, new string[] {
name
}
);
}
public BasePlayer FindOnline(string nameOrUserId) {
nameOrUserId = nameOrUserId.ToLower();
foreach (BasePlayer activePlayer in BasePlayer.activePlayerList) {
if (activePlayer.displayName.ToLower().Contains(nameOrUserId) || activePlayer.UserIDString == nameOrUserId) return activePlayer;
}
return null;
}
[ChatCommand("trade")]
void CmdChatTrade(BasePlayer player, string command, string[] args) {
if (player == null) return;
if (args.Length == 0 || args == null) {
SendReply(player, "Используйте:\n<color=#ee3e61>/trade ник игрока</color> для обмена\nЧто бы принять обмен, введите: <color=#ee3e61>/trade accept</color>\nЧто бы отказаться от обмена введите: <color=#ee3e61>/trade cancel </color>");
return;
}
if (UsePermission && !permission.UserHasPermission(player.UserIDString, Permission)) {
SendReply(player, "<color=#ee3e61>Система обмена</color>\nНедоступно, у Вас нету прав на использование трейда!");
return;
}
if (Cooldowns.ContainsKey(player)) {
double seconds = Cooldowns[player].Subtract(DateTime.Now).TotalSeconds;
if (seconds >= 0) {
SendReply(player, $"<color=#ee3e61>Система обмена</color>\nВы только недавно обменивались, подождите - <color=#ee3e61>{seconds}</color> сек.");
return;
}
}
switch (args[0]) {
default : if (!CanPlayerTrade(player)) {
return;
}
var name = args[0];
var target = FindOnline(name);
if (target == null) {
SendReply(player, $"<color=#ee3e61>Система обмена</color>\nИгрок <color=#ee3e61>{name}</color> не найден!");
return;
}
if (target == player) {
SendReply(player, "<color=#ee3e61>Система обмена</color>\nНельзя отправлять запрос самому себе!");
return;
}
if (UsePermission && !permission.UserHasPermission(target.UserIDString, Permission)) {
SendReply(player, $"<color=#ee3e61>Система обмена</color>\nНедоступно, у игрока {target.displayName} нет прав на использование трейда!");
return;
}
if (getCupSend) {
if (!player.CanBuild()) {
SendReply(player, "<color=#ee3e61>Система обмена</color>\nНедоступно, вы в зоне Building Blocked!");
return;
}
}
BasePlayer anotherTarget;
if (pendings.TryGetValue(player, out anotherTarget)) {
SendReply(player, $"<color=#ee3e61>Система обмена</color>\nНевозможно! Игрок <color=#ee3e61>{anotherTarget.displayName}</color> уже отправил вам предложение обмена!");
return;
}
pendings[target] = player;
SendReply(player, $"Предложение обмена игроку <color=#ee3e61>{target.displayName}</color> успешно отправлено, ожидайте...");
SendReply(target, $"Игрок <color=#ee3e61>{player.displayName}</color> отправил вам предложние обмена\nДля принятия обмена используйте команду <color=#ee3e61>/trade accept</color>\nЧто бы отказаться введите <color=#ee3e61>/trade cancel</color>");
mytimer = timer.Once(getTime, () => {
if (target != null && player != null && player.IsConnected && target.IsConnected && pendings.ContainsKey(target)) {
pendings.Remove(target);
pendings.Remove(player);
SendReply(player, "<color=#ee3e61>Система обмена</color>\nTrade отменён! Причина: время истекло.");
SendReply(target, "<color=#ee3e61>Система обмена</color>\nTrade отменён! Причина: вы вовремя не приняли запрос.");
}
}
);
break;
case "accept" : if (player == null) return;
if (getCupAuth) {
if (!player.CanBuild()) {
SendReply(player, "<color=#ee3e61>Система обмена</color>\nНедоступно, вы в зоне Building Blocked!");
return;
}
}
BasePlayer player2;
if (!pendings.TryGetValue(player, out player2)) {
SendReply(player, "<color=#ee3e61>Система обмена</color>\nУ вас нет входящих предложний обмена!");
return;
}
if (!CanPlayerTrade(player)) return;
pendings.Remove(player);
timer.Once(0.2f, () => OpenBox(player2, player));
break;
case "cancel" : if (player == null) return;
if (!pendings.TryGetValue(player, out player2)) {
SendReply(player, "<color=#ee3e61>Система обмена</color>\nУ вас нет входящих предложний обмена!");
return;
}
pendings.Remove(player);
if (player2?.IsConnected == true) SendReply(player2, $"<color=#ee3e61>Система обмена</color>\nTrade отменён! Причина: игрок <color=#ee3e61>{player.displayName}</color> отказался");
SendReply(player, "<color=#ee3e61>Система обмена</color>\nTrade отменен!");
break;
}
}
private void RemovePending(BasePlayer player) {
BasePlayer player2;
if (!pendings.TryGetValue(player, out player2)) return;
pendings.Remove(player);
pendings.Remove(player2);
}
void OnPlayerLootEnd(PlayerLoot inventory) {
var player = inventory.gameObject.ToBaseEntity();
if (player == null) return;
var box = m_Boxes.Select(p => p.Value).FirstOrDefault(p => p.player1 == player || p.player2 == player);
if (box != null) {
OnTradeCanceled(box.guid);
}
}
private static void DrawUI(BasePlayer a) {
CuiHelper.AddUi(a, @"[{""name"":""TradeBox_Button"",""parent"":""Overlay"",""components"":[{""type"":""UnityEngine.UI.Button"",""command"":""tradebox.button"",""color"":""1 1 1 0""},{""type"":""RectTransform"",""anchormin"":""0.65 0.1504"",""anchormax"":""0.9464 0.2455"",""offsetmin"":""0 0"",""offsetmax"":""1 1""}]},{""name"":""CuiElement"",""parent"":""Overlay"",""components"":[{""type"":""RectTransform"",""anchormin"":""0.05208334 0.09259259"",""anchormax"":""0.1041667 0.1851852"",""offsetmin"":""0 0"",""offsetmax"":""1 1""}]},{""name"":""CuiElement"",""parent"":""Overlay"",""components"":[{""type"":""RectTransform"",""anchormin"":""0.05208334 0.09259259"",""anchormax"":""0.1041667 0.1851852"",""offsetmin"":""0 0"",""offsetmax"":""1 1""}]}]");
}
private static void DestroyUI(BasePlayer a) {
CuiHelper.DestroyUi(a, "TradeBox_Button");
}
private static void cmdTradeButton(ConsoleSystem.Arg arg) {
var player = arg.Player();
if (player == null) return;
var shop = boxes.Select(p => p.Value).FirstOrDefault(p => p.customerPlayer == player || p.vendorPlayer == player);
if (shop == null) return;
if (shop.HasFlag(BaseEntity.Flags.Reserved3)) return;
if (!shop.IsTradingPlayer(player)) {
return;
}
if (shop.vendorPlayer == null || shop.customerPlayer == null) {
return;
}
if (shop.IsPlayerVendor(player)) {
if (shop.HasFlag(BaseEntity.Flags.Reserved1)) {
shop.ResetTrade();
}
else {
shop.SetFlag(BaseEntity.Flags.Reserved1, true);
shop.vendorInventory.SetLocked(true);
}
}
else if (shop.IsPlayerCustomer(player)) {
if (shop.HasFlag(BaseEntity.Flags.Reserved2)) {
shop.ResetTrade();
}
else {
shop.SetFlag(BaseEntity.Flags.Reserved2, true);
shop.customerInventory.SetLocked(true);
}
}
if (shop.HasFlag(BaseEntity.Flags.Reserved1) && shop.HasFlag(BaseEntity.Flags.Reserved2)) {
shop.SetFlag(BaseEntity.Flags.Reserved3, true);
shop.Invoke(shop.CompleteTrade, 2f);
}
}
[ConsoleCommand("tradebox.button")]
void cmdTradeButton1(ConsoleSystem.Arg a) {
cmdTradeButton(a);
}
public static string Create(BasePlayer player1, BasePlayer player2, int getInt) {
BaseEntity entity = GameManager.server.CreateEntity("assets/prefabs/building/wall.frame.shopfront/wall.frame.shopfront.metal.prefab", new Vector3(), new Quaternion(), true);
entity.transform.position = Vector3.zero;
UnityEngine.Object.Destroy(entity.GetComponent<DestroyOnGroundMissing>());
UnityEngine.Object.Destroy(entity.GetComponent<GroundWatch>());
entity.Spawn();
ShopFront shopFront = (ShopFront)entity;
shopFront.vendorInventory.capacity = getInt;
shopFront.customerInventory.capacity = getInt;
string guid = CuiHelper.GetGuid();
boxes.Add(guid, shopFront);
var reply = 1;
if (reply == 0) {
}
players[guid] = new List<BasePlayer>() {
player1, player2
}
;
if (!player1.net.subscriber.IsSubscribed(shopFront.net.group)) player1.net.subscriber.Subscribe(shopFront.net.group);
if (!player2.net.subscriber.IsSubscribed(shopFront.net.group)) player2.net.subscriber.Subscribe(shopFront.net.group);
SendEntity(player1, (BaseEntity)shopFront);
SendEntity(player2, (BaseEntity)shopFront);
SendEntity(player1, (BaseEntity)player2);
SendEntity(player2, (BaseEntity)player1);
player1.EndLooting();
player2.EndLooting();
m_Instance.timer.Once(0.1f, (Action)(() => StartLooting(guid, player1)));
m_Instance.timer.Once(0.5f, (Action)(() => StartLooting(guid, player2)));
return guid;
}
static void SendEntity(BasePlayer a, BaseEntity b) {
if (Net.sv.write.Start()) {
a.net.connection.validate.entityUpdates++;
BaseNetworkable.SaveInfo c = new BaseNetworkable.SaveInfo {
forConnection = a.net.connection, forDisk = false
}
;
Net.sv.write.PacketID(Message.Type.Entities);
Net.sv.write.UInt32(a.net.connection.validate.entityUpdates);
b.ToStreamForNetwork(Net.sv.write, c);
Net.sv.write.Send(new SendInfo(a.net.connection));
}
}
public static T AddComponent<T>(string a) where T : Component {
ShopFront b;
if (!boxes.TryGetValue(a, out b)) {
throw new InvalidOperationException($"AddBehaviour: TradeBox for {b} not Found");
}
return b.gameObject.AddComponent<T>();
}
public static void Destroy(string a) {
ShopFront b;
if (boxes.TryGetValue(a, out b)) {
if (players.ContainsKey(a)) {
players[a].ForEach(DestroyUI);
players.Remove(a);
}
boxes.Remove(a);
b.Kill();
}
}
private void OnItemSplit(Item item, int amount) {
if (item == null || item?.uid == null) return;
if (item.GetRootContainer() == null || item.GetRootContainer()?.entityOwner == null || item.GetRootContainer()?.entityOwner?.GetComponent<ShopFront>() == null) return;
var container = item.GetRootContainer().entityOwner?.GetComponent<ShopFront>();
if (container != null) if (boxes.FirstOrDefault(p => p.Value == container).Key != null) if (container.vendorInventory != null && container.customerInventory != null) if (container.vendorInventory.IsLocked() || container.customerInventory.IsLocked()) container.ResetTrade();
}
private void DropTrade(TradeController trade) {
m_Boxes.Remove(trade.guid);
tradingPlayers.Remove(trade.player1.userID);
tradingPlayers.Remove(trade.player2.userID);
Destroy(trade.guid);
UnityEngine.Object.DestroyImmediate(trade);
}
private void OpenBox(BasePlayer player1, BasePlayer player2, ulong playerid = 1) {
var guid = Create(player1, player2, getInt);
var trade = AddComponent<TradeController>(guid);
trade.Init(guid, player1, player2);
m_Boxes.Add(guid, trade);
tradingPlayers.Add(player1.userID);
tradingPlayers.Add(player2.userID);
}
private void OnTradeCanceled(string guid) {
TradeController trade;
if (m_Boxes.TryGetValue(guid, out trade)) {
if (trade.shop.customerInventory != null) {
for (int i = trade.shop.customerInventory.itemList.Count - 1;
i >= 0;
i--) {
trade.player1.GiveItem(trade.shop.customerInventory.itemList[i], BaseEntity.GiveItemReason.Generic);
}
}
if (trade.shop.vendorInventory != null) {
for (int i = trade.shop.vendorInventory.itemList.Count - 1;
i >= 0;
i--) {
trade.player2.GiveItem(trade.shop.vendorInventory.itemList[i], BaseEntity.GiveItemReason.Generic);
}
}
DropTrade(trade);
}
}
object CanMoveItem(Item item, PlayerInventory playerLoot, uint targetContainer) {
if (playerLoot == null) return null;
var cont1 = playerLoot.FindContainer(targetContainer);
if (cont1 == null) return null;
var player = playerLoot.containerMain.playerOwner;
if (player == null) return null;
if (cont1.entityOwner != null && cont1.entityOwner is ShopFront) {
var shopfront = cont1.entityOwner.GetComponent<ShopFront>();
if (shopfront != null) {
if (item.contents != null) {
item.contents.SetLocked(true);
item.MarkDirty();
}
}
if (shopfront.IsPlayerCustomer(player) && shopfront.customerInventory.uid != targetContainer) return false;
else if (shopfront.IsPlayerVendor(player) && shopfront.vendorInventory.uid != targetContainer) return false;
}
else {
if (item.contents != null && item.contents.IsLocked()) {
item.contents.SetLocked(false);
item.MarkDirty();
}
}
return null;
}
public static void StartLooting(string guid, BasePlayer player) {
ShopFront shopFront;
if (!boxes.TryGetValue(guid, out shopFront)) return;
player.inventory.loot.StartLootingEntity(shopFront, false);
player.inventory.loot.AddContainer(shopFront.vendorInventory);
player.inventory.loot.SendImmediate();
player.ClientRPCPlayer(null, player, "RPC_OpenLootPanel", shopFront.panelName);
shopFront.DecayTouch();
shopFront.SendNetworkUpdate(BasePlayer.NetworkQueue.Update);
player.inventory.loot.AddContainer(shopFront.customerInventory);
player.inventory.loot.SendImmediate();
if (shopFront.customerPlayer == null) shopFront.customerPlayer = player;
else shopFront.vendorPlayer = player;
DrawUI(player);
shopFront.ResetTrade();
shopFront.UpdatePlayers();
}
bool CanPlayerTrade(BasePlayer player) {
if (getSwim) {
if (player.IsSwimming()) {
SendReply(player, "<color=#ee3e61>Система обмена</color>\nНедоступно, вы плаваете!");
return false;
}
}
if (getCupSend && getCupAuth) {
if (!player.CanBuild()) {
SendReply(player, "<color=#ee3e61>Система обмена</color>\nНедоступно, вы в зоне Building Blocked!");
return false;
}
}
if (getFly) {
if (!player.IsOnGround() || player.IsFlying) {
SendReply(player, "<color=#ee3e61>Система обмена</color>\nНедоступно, вы левитируете!");
return false;
}
}
if (getWound) {
if (player.IsWounded()) {
SendReply(player, "<color=#ee3e61>Система обмена</color>\nНедоступно, вы в предсмертном состоянии!");
return false;
}
}
if (Cooldowns.ContainsKey(player)) {
double seconds = Cooldowns[player].Subtract(DateTime.Now).TotalSeconds;
if (seconds >= 0) {
SendReply(player, $"<color=#ee3e61>Система обмена</color>\nВы только недавно обменивались, подождите - <color=#ee3e61>{seconds}</color> сек.");
return false;
}
}
var canTrade = Interface.Call("CanTrade", player);
if (canTrade != null) {
if (canTrade is string) {
SendReply(player, Convert.ToString(canTrade));
return false;
}
SendReply(player, "<color=#ee3e61>Система обмена</color>\nНедоступно, заблокировано другим плагином!");
return false;
}
return true;
}
class TradeController : MonoBehaviour {
public string guid;
public ShopFront shop;
public BasePlayer player1, player2;
public void Init(string guid, BasePlayer player1, BasePlayer player2) {
this.guid = guid;
this.player1 = player1;
this.player2 = player2;
}
private void Awake() {
shop = GetComponent<ShopFront>();
}
}
}
}