C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Plugins;
using System;
using System.Collections.Generic;
using Oxide.Core.Libraries.Covalence;
using System.Linq;
using UnityEngine;
/* ChangeLog:
- Updated: For May 4th Rust update changes
*/
namespace Oxide.Plugins
{
[Info("Personal Marketplace", "ZEODE", "1.2.3")]
[Description("Deploy, craft, pickup and use personal drone marketplaces.")]
public class PersonalMarketplace: CovalencePlugin
{
#region Instance refs
[PluginReference] Plugin Friends, Clans, WaterBases;
#endregion
#region Consts
private static PersonalMarketplace Instance;
private const ulong itemSkinID = 2859284352;
private const string placeableItem = "mailbox";
private const string itemName = "Marketplace";
private const string vendingName = "Market Vending Machine";
private const string marketPrefab = "assets/prefabs/misc/marketplace/marketplace.prefab";
private const string marketTerminal = "assets/prefabs/misc/marketplace/marketterminal.prefab";
private const string vendingPrefab = "assets/prefabs/deployable/vendingmachine/vendingmachine.deployed.prefab";
private const string errorSound = "assets/prefabs/locks/keypad/effects/lock.code.denied.prefab";
private const string successSound = "assets/prefabs/locks/keypad/effects/lock.code.updated.prefab";
private const string breakSound = "assets/bundled/prefabs/fx/item_break.prefab";
private const string permAdmin = "personalmarketplace.admin";
private const string permDeploy = "personalmarketplace.deploy";
private const string permPickup = "personalmarketplace.pickup";
private const string permCraft = "personalmarketplace.craft";
private const float lookDistance = 5f;
private const float ceilingDistance = 100f;
#endregion Consts
#region Oxide Hooks
private void Init()
{
permission.RegisterPermission(permAdmin, this);
permission.RegisterPermission(permDeploy, this);
permission.RegisterPermission(permPickup, this);
permission.RegisterPermission(permCraft, this);
try
{
storedData = Interface.Oxide.DataFileSystem.ReadObject<StoredData>(Name);
if (storedData == null)
{
Puts("Data is null.Creating blank data file...");
storedData = new StoredData();
SaveData();
}
}
catch (Exception ex)
{
if (ex is JsonSerializationException || ex is NullReferenceException || ex is JsonReaderException)
{
Puts("Data file invalid.Creating blank data file...");
storedData = new StoredData();
SaveData();
return;
}
throw;
}
}
private void OnServerInitialized(bool initial)
{
Instance = this;
bool doSave = false;
foreach (var key in storedData.MarketData.Keys.ToList())
{
var market = BaseNetworkable.serverEntities.Find(new NetworkableId(key)) as Marketplace;
if (market == null)
{
Puts($"INFO: Missing/Destroyed Marketplace with ID {key}, data entry removed.");
storedData.MarketData.Remove(key);
doSave = true;
continue;
}
if (config.deploy.addVending)
{
var vending = storedData.MarketData[key].Vending;
if (vending == null)
continue;
int count = 1;
for (int i = 0; i < vending.Count; i++)
{
var machine = BaseNetworkable.serverEntities.Find(new NetworkableId(vending[i].NetID)) as VendingMachine;
if (machine != null)
{
if (!storedData.MarketData[key].Vending[i].Name.Contains(vendingName))
{
storedData.MarketData[key].Vending[i].Name = $"{vendingName} {count}";
doSave = true;
}
machine._name = storedData.MarketData[key].Vending[i].Name;
count++;
}
}
}
}
if (doSave) SaveData();
NextTick(()=> SetupMarketplaces());
}
private void Unload()
{
foreach (var obj in UnityEngine.Object.FindObjectsOfType(typeof(MarketplaceComponent)).ToList())
{
if (obj != null)
UnityEngine.Object.Destroy(obj);
}
Instance = null;
SaveData();
}
private void OnNewSave()
{
PrintWarning("Server wipe detected, clearing all player data.");
storedData = new StoredData();
SaveData();
}
private void OnEntityBuilt(Planner plan, GameObject go)
{
if (go == null || plan.GetOwnerPlayer() == null)
{
return;
}
var player = plan?.GetOwnerPlayer();
var entity = go?.ToBaseEntity();
if (player == null || entity == null)
{
return;
}
if (IsMarketplace(entity.skinID))
{
float condition = config.pickup.initialCondition;
var item = plan.GetItem();
if (item != null)
{
condition = item.maxCondition;
}
if (!permission.UserHasPermission(player.UserIDString, permDeploy))
{
KillGive(player, entity, condition, "Permission");
return;
}
if (config.deploy.privDeploy && !IsAuthorized(player, entity))
{
KillGive(player, entity, condition, "BuildPriv");
return;
}
if (!config.deploy.deployMultiple)
{
foreach (var key in storedData.MarketData.Keys)
{
if (storedData.MarketData[key].OwnerID == player.userID)
{
KillGive(player, entity, condition, "NoMultiples");
return;
}
}
}
if (config.deploy.onFoundation && !OnFoundation(entity))
{
KillGive(player, entity, condition, "OnFoundation");
return;
}
if (IsNearWorldCollider(entity))
{
KillGive(player, entity, condition, "RoomToDeploy");
return;
}
if (InBuilding(entity))
{
KillGive(player, entity, condition, "InsideBuilding");
return;
}
var marketplace = GameManager.server.CreateEntity(marketPrefab, entity.transform.position, entity.transform.rotation) as BaseEntity;
if (marketplace == null) return;
marketplace.transform.forward = player.transform.position - marketplace.transform.position;
marketplace.transform.rotation = Quaternion.Euler(entity.transform.rotation.eulerAngles.x, marketplace.transform.rotation.eulerAngles.y, entity.transform.rotation.eulerAngles.z);
marketplace.skinID = itemSkinID;
marketplace.OwnerID = player.userID;
marketplace.creatorEntity = player;
marketplace.Spawn();
marketplace.gameObject.AddComponent<MarketplaceComponent>();
NextTick(() =>
{
entity.Kill();
});
foreach (var child in marketplace.children)
{
child.skinID = itemSkinID;
child.OwnerID = player.userID;
child.creatorEntity = player;
}
if (config.deploy.addVending)
{
AddVendingMachines(player, marketplace, condition);
Message(player, "HitToRotate");
}
else
{
AddPlayerData(player.userID, player.displayName, marketplace.net.ID.Value, condition, new List<Vending>());
}
}
}
private object CanStackItem(Item item, Item targetItem)
{
if (item.skin == itemSkinID && targetItem.skin == itemSkinID)
{
return false;
}
return null;
}
private object CanCombineDroppedItem(DroppedItem item, DroppedItem targetItem)
{
return CanStackItem(item.item, targetItem.item);
}
ItemContainer.CanAcceptResult? CanAcceptItem(ItemContainer container, Item item, int targetPos)
{
if (!IsMarketplace(item.skin))
{
return null;
}
BasePlayer player = item.GetOwnerPlayer();
var entity = container.entityOwner;
if (entity is RepairBench)
{
if (config.options.showTips)
player.ShowToast(GameTip.Styles.Blue_Long, lang.GetMessage("NoRepair", this));
return ItemContainer.CanAcceptResult.CannotAccept;
}
else if (entity is Recycler)
{
if (config.options.showTips)
player.ShowToast(GameTip.Styles.Blue_Long, lang.GetMessage("NoRecycle", this));
return ItemContainer.CanAcceptResult.CannotAccept;
}
return null;
}
private void OnHammerHit(BasePlayer player, HitInfo info)
{
BaseEntity entity = info?.HitEntity as BaseEntity;
if (entity == null)
return;
if (!IsMarketplace(entity.skinID))
{
if (entity._name == null)
return;
if (!entity._name.Contains(vendingName))
return;
}
if (entity.name == vendingPrefab && config.deploy.addVending)
{
if (config.deploy.vendingAuth && !IsAuthorized(player, entity))
{
PlaySound(errorSound, player);
Message(player, "BuildPriv");
return;
}
else if (config.options.useFriends || config.options.useClans || config.options.useTeams)
{
if (!IsFriend(player.userID, entity.OwnerID))
{
PlaySound(errorSound, player);
Message(player, "OwnerTeamRotate");
return;
}
}
else if (entity.OwnerID != player.userID)
{
PlaySound(errorSound, player);
Message(player, "OwnerRotate");
return;
}
entity.transform.rotation = Quaternion.LookRotation(-entity.transform.forward, entity.transform.up);
entity.SendNetworkUpdateImmediate();
return;
}
else if (entity.name == marketTerminal)
{
var marketplace = entity?.GetParentEntity();
if (marketplace == null)
{
return;
}
if (!config.pickup.canPickup)
{
PlaySound(errorSound, player);
Message(player, "NoPickup");
return;
}
else if (!permission.UserHasPermission(player.UserIDString, permPickup))
{
PlaySound(errorSound, player);
Message(player, "Permission");
return;
}
else if (config.pickup.privPickup && !IsAuthorized(player, marketplace))
{
PlaySound(errorSound, player);
Message(player, "BuildPriv");
return;
}
else if (config.options.useFriends || config.options.useClans || config.options.useTeams)
{
if (!IsFriend(player.userID, marketplace.OwnerID))
{
PlaySound(errorSound, player);
Message(player, "OwnerTeam");
return;
}
}
if (config.deploy.addVending && !IsVendingEmpty(player, marketplace))
{
PlaySound(errorSound, player);
Message(player, "VendingNotEmpty");
return;
}
PickupMarketplace(player, marketplace);
}
}
private object OnEntityTakeDamage(VendingMachine entity, HitInfo info)
{
if (entity?._name == null)
return null;
if (config.deploy.addVending && config.deploy.blockVendingDamage)
{
if (entity._name.Contains(vendingName))
return true;
}
return null;
}
#endregion
#region Main
private void SetupMarketplaces()
{
foreach (var marketplace in UnityEngine.Object.FindObjectsOfType<Marketplace>())
{
if (IsMarketplace(marketplace.skinID))
{
if (!marketplace.GetComponent<MarketplaceComponent>())
marketplace.gameObject.AddComponent<MarketplaceComponent>();
// Check data file for missing marketplace data and replace it if needed
if (!storedData.MarketData.ContainsKey(marketplace.net.ID.Value))
{
IPlayer iplayer = players.FindPlayerById(marketplace.OwnerID.ToString());
if (iplayer != null)
{
List<Vending> vending = new List<Vending>();
if (config.deploy.addVending)
{
var layerMask = LayerMask.GetMask("Deployed");
var center = marketplace.transform.position + new Vector3(0, 1f, 0);
Vector3 halfExtents = new Vector3(4f, 4.7f, 4.7f);
Collider[] hitColliders = Physics.OverlapBox(center, halfExtents, Quaternion.identity, layerMask, QueryTriggerInteraction.UseGlobal);
if (hitColliders.Length != 0)
{
int count = 1;
for (int i = 0; i < hitColliders.Length; i++)
{
var hitEntity = hitColliders[i].GetComponentInParent<BaseEntity>();
if (hitEntity == null) continue;
if (hitEntity.name.Contains("vendingmachine"))
{
if (!hitEntity._name.Contains(vendingName))
hitEntity._name = $"{vendingName} {count}";
vending.Add(new Vending { Name = hitEntity._name, NetID = hitEntity.net.ID.Value });
if (count == 4) break;
count++;
continue;
}
}
}
if (vending == null) vending = new List<Vending>();
AddPlayerData(Convert.ToUInt64(iplayer.Id), iplayer.Name, marketplace.net.ID.Value, 100, vending);
}
else
{
AddPlayerData(Convert.ToUInt64(iplayer.Id), iplayer.Name, marketplace.net.ID.Value, 100, new List<Vending>());
}
}
}
}
}
}
private void GiveMarketplace(BasePlayer player, string type, float condition = -1)
{
var mpItem = CreatePlaceableItem();
if (mpItem != null && player != null)
{
if (condition == -1)
{
mpItem.maxCondition = config.pickup.initialCondition;
}
mpItem.maxCondition = condition;
if (type == "pickup")
{
if (condition <= 0)
{
mpItem.maxCondition = condition;
mpItem.condition = 0;
Message(player.IPlayer, "ItemBroken");
PlaySound(breakSound, player);
}
Message(player.IPlayer, "Pickup");
player.GiveItem(mpItem);
return;
}
else if (type == "refund")
{
player.GiveItem(mpItem);
return;
}
else if (type == "receive")
{
player.GiveItem(mpItem);
Message(player.IPlayer, "Receive");
return;
}
else if (type == "craft")
{
player.GiveItem(mpItem);
Message(player.IPlayer, "Crafted");
return;
}
}
}
private void PickupMarketplace(BasePlayer player, BaseEntity market)
{
if (player == null || market == null)
{
return;
}
ulong marketId = market.net.ID.Value;
float condition = 0;
List<Vending> vending = new List<Vending>();
if (storedData.MarketData.ContainsKey(marketId))
{
condition = storedData.MarketData[marketId].Condition;
vending = storedData.MarketData[marketId].Vending;
}
if (vending == null)
return;
if (config.deploy.addVending)
{
foreach (var vend in vending)
{
var machine = BaseNetworkable.serverEntities.Find(new NetworkableId(vend.NetID));
if (machine != null)
{
NextTick(() => {
if (machine != null || !machine.IsDestroyed)
machine.Kill();
});
}
}
}
NextTick(() => {
if (!market.IsDestroyed)
market.Kill();
});
if (config.pickup.loseCondition)
condition = condition - config.pickup.pickupPenalty;
RemovePlayerData(marketId);
GiveMarketplace(player, "pickup", condition);
}
private void AddVendingMachines(BasePlayer player, BaseEntity marketplace, float condition)
{
var position = marketplace.transform.position;
List<Vending> vending = new List<Vending>();
var vend1 = GameManager.server.CreateEntity(vendingPrefab, position) as VendingMachine;
if (vend1 == null) return;
vend1.OwnerID = player.userID;
vend1._name = vendingName + " 1";
vend1.creatorEntity = player;
vend1.dropsLoot = config.deploy.dropVendingLoot;
vend1.transform.localPosition = new Vector3(4.76f, 0.64f, 0.73f);
vend1.transform.localRotation = new Quaternion(0.0f, 1.0f, 0.0f, 1.0f);
DestroyGroundWatch(vend1);
vend1.SetFlag(BaseEntity.Flags.Reserved1, true, true, true);
vend1.SetParent(marketplace, false, false);
vend1.Spawn();
vend1.SetParent(null, true, true);
vending.Add(new Vending { Name = vend1._name, NetID = vend1.net.ID.Value });
var vend2 = GameManager.server.CreateEntity(vendingPrefab, position) as VendingMachine;
if (vend2 == null) return;
vend2.OwnerID = player.userID;
vend2._name = vendingName + " 2";
vend2.creatorEntity = player;
vend2.dropsLoot = config.deploy.dropVendingLoot;
vend2.transform.localPosition = new Vector3(4.76f, 0.64f, -0.73f);
vend2.transform.localRotation = new Quaternion(0.0f, 1.0f, 0.0f, 1.0f);
DestroyGroundWatch(vend2);
vend2.SetFlag(BaseEntity.Flags.Reserved1, true, true, true);
vend2.SetParent(marketplace, false, false);
vend2.Spawn();
vend2.SetParent(null, true, true);
vending.Add(new Vending { Name = vend2._name, NetID = vend2.net.ID.Value });
var vend3 = GameManager.server.CreateEntity(vendingPrefab, position) as VendingMachine;
if (vend3 == null) return;
vend3.enableSaving = true;
vend3.OwnerID = player.userID;
vend3._name = vendingName + " 3";
vend3.creatorEntity = player;
vend3.dropsLoot = config.deploy.dropVendingLoot;
vend3.transform.localPosition = new Vector3(-4.76f, 0.64f, 0.73f);
vend3.transform.localRotation = new Quaternion(0.0f, -1.0f, 0.0f, 1.0f);
DestroyGroundWatch(vend3);
vend3.SetFlag(BaseEntity.Flags.Reserved1, true, true, true);
vend3.SetParent(marketplace, false, false);
vend3.Spawn();
vend3.SetParent(null, true, true);
vending.Add(new Vending { Name = vend3._name, NetID = vend3.net.ID.Value });
var vend4 = GameManager.server.CreateEntity(vendingPrefab, position) as VendingMachine;
if (vend4 == null) return;
vend4.enableSaving = true;
vend4.OwnerID = player.userID;
vend4._name = vendingName + " 4";
vend4.creatorEntity = player;
vend4.dropsLoot = config.deploy.dropVendingLoot;
vend4.transform.localPosition = new Vector3(-4.76f, 0.64f, -0.73f);
vend4.transform.localRotation = new Quaternion(0.0f, -1.0f, 0.0f, 1.0f);
DestroyGroundWatch(vend4);
vend4.SetFlag(BaseEntity.Flags.Reserved1, true, true, true);
vend4.SetParent(marketplace, false, false); // Parent to marketplace temporarily (stop parent entity errors)
vend4.Spawn();
vend4.SetParent(null, true, true); // Unparent from marketplace but keep world position (stop parent entity errors)
vending.Add(new Vending { Name = vend4._name, NetID = vend4.net.ID.Value });
AddPlayerData(player.userID, player.displayName, marketplace.net.ID.Value, condition, vending);
}
#endregion
#region Helpers
private void DestroyGroundWatch(BaseEntity entity)
{
UnityEngine.Object.DestroyImmediate(entity.GetComponent<GroundWatch>());
UnityEngine.Object.DestroyImmediate(entity.GetComponent<DestroyOnGroundMissing>());
}
// Method for other plugins related to storage boxes or Marketplaces to check whether a entity is a
// Personal Marketplace item or not and handle accordingly, to avoid conflicts (such as Chest Stacks).object MarketplaceCheck(ulong skinId) => (skinId == itemSkinID) ? true : (object)null;
private bool IsVendingEmpty(BasePlayer player, BaseEntity marketplace)
{
foreach (var key in storedData.MarketData.Keys)
{
if (key == marketplace.net.ID.Value)
{
var vending = storedData.MarketData[key].Vending;
if (vending == null)
return true;
foreach (var vend in vending)
{
var machine = BaseNetworkable.serverEntities.Find(new NetworkableId(vend.NetID)) as VendingMachine;
if (machine != null)
{
if (!machine.IsInventoryEmpty())
return false;
}
}
break;
}
}
return true;
}
private bool OnFoundation(BaseEntity entity)
{
RaycastHit hit;
var heightOffset = new Vector3(0, 0.5f, 0);
var mpPosition = entity.transform.position;
if (Physics.Raycast(mpPosition + heightOffset, Vector3.down, out hit, 0.6f, LayerMask.GetMask("Terrain", "Construction")) && hit.GetEntity().IsValid())
{
if (hit.GetEntity().name.Contains("foundation"))
return true;
}
return false;
}
private bool InBuilding(BaseEntity entity)
{
var layerMask = LayerMask.GetMask("Construction");
var center = entity.transform.position + new Vector3(0, ((ceilingDistance / 2) + 0.1f), 0);
Vector3 halfExtents = new Vector3(14, ceilingDistance, 8) / 2;
Collider[] hitColliders = Physics.OverlapBox(center, halfExtents, Quaternion.identity, layerMask, QueryTriggerInteraction.UseGlobal);
if (hitColliders.Length != 0)
{
for (int i = 0; i < hitColliders.Length; i++)
{
var hitEntity = hitColliders[i].GetComponentInParent<BaseEntity>();
if (hitEntity == null || hitEntity == entity)
continue;
return true;
}
}
return false;
}
private bool IsNearWorldCollider(BaseEntity entity)
{
var layerMask = LayerMask.GetMask("Deployed", "Construction", "Terrain", "Tree");
var center = entity.transform.position + new Vector3(0, 4.1f, 0);
Vector3 halfExtents = new Vector3(14, 8, 8) / 2;
Collider[] hitColliders = Physics.OverlapBox(center, halfExtents, Quaternion.identity, layerMask, QueryTriggerInteraction.UseGlobal);
if (hitColliders.Length != 0)
{
for (int i = 0; i < hitColliders.Length; i++)
{
var hitEntity = hitColliders[i].GetComponentInParent<BaseEntity>();
if (hitEntity == null || hitEntity == entity)
continue;
return true;
}
}
return false;
}
private Item CreatePlaceableItem()
{
var mpItem = ItemManager.CreateByName(placeableItem, 1, itemSkinID);
if (mpItem != null)
mpItem.name = itemName;
return mpItem;
}
public void KillGive(BasePlayer player, BaseEntity entity, float condition, string messageKey)
{
if (entity.IsValid() == true && !entity.IsDestroyed)
{
NextTick(() => {
entity.Kill();
});
}
GiveMarketplace(player, "refund", condition);
Message(player, messageKey);
}
private void DropDestroyed(Vector3 position, float condition)
{
var mpItem = CreatePlaceableItem();
mpItem.maxCondition = condition;
if (config.destroy.dropCondition)
mpItem.maxCondition = condition - config.pickup.pickupPenalty;
mpItem?.Drop(position, Vector3.down);
}
private void PlaySound(string sound, BasePlayer player)
{
if (player == null)
return;
if (config.options.enableSounds)
{
if (!player.IPlayer.IsServer)
{
Effect.server.Run(sound, player.transform.position);
return;
}
}
}
private bool IsMarketplace(ulong skinId)
{
if (skinId == null || skinId == 0)
return false;
if (skinId == itemSkinID)
return true;
return false;
}
private bool IsAuthorized(BasePlayer player, BaseEntity block)
{
if (block.GetBuildingPrivilege()?.IsAuthed(player) == true)
return true;
return false;
}
private bool IsFriend(ulong playerId, ulong targetId)
{
if (playerId == null || targetId == null)
return false;
if (playerId == targetId)
return true;
if (Clans)
{
var result = Clans?.Call("IsMemberOrAlly", playerId, targetId);
if (result != null && Convert.ToBoolean(result))
return true;
}
if (Friends)
{
var result = Friends?.Call("AreFriends", playerId, targetId);
if (result != null && Convert.ToBoolean(result))
return true;
}
RelationshipManager.PlayerTeam team;
RelationshipManager.ServerInstance.playerToTeam.TryGetValue(playerId, out team);
if (team == null)
return false;
if (team.members.Contains(targetId))
return true;
return false;
}
private object RaycastAll<T>(Ray ray) where T : BaseEntity
{
var hits = Physics.RaycastAll(ray);
GamePhysics.Sort(hits);
var distance = lookDistance;
object target = false;
foreach (var hit in hits)
{
var ent = hit.GetEntity();
if (ent is T && hit.distance < distance)
{
target = ent;
break;
}
}
return target;
}
private IPlayer FindPlayer(string nameOrIdOrIp)
{
foreach (var activePlayer in covalence.Players.Connected)
{
if (activePlayer.Id == nameOrIdOrIp)
return activePlayer;
if (activePlayer.Name.Contains(nameOrIdOrIp))
return activePlayer;
if (activePlayer.Name.ToLower().Contains(nameOrIdOrIp.ToLower()))
return activePlayer;
if (activePlayer.Address == nameOrIdOrIp)
return activePlayer;
}
return null;
}
#endregion
#region Commands
[Command("marketplace.give")]
private void ChatGiveCmd(IPlayer player, string command, string[] args)
{
var self = player.Object as BasePlayer;
if (self == null && !player.IsServer) return;
if (!player.HasPermission(permAdmin))
{
Message(player, "Permission");
PlaySound(errorSound, self);
return;
}
else if (args.Length < 1 && player.IsServer)
{
Message(player, "ConsoleUsage");
return;
}
else if (args.Length < 1 && player.IsConnected)
{
GiveMarketplace(self, "receive", config.pickup.initialCondition);
PlaySound(successSound, self);
return;
}
var t = FindPlayer(args[0]);
var target = t.Object as BasePlayer;
if (target == null)
{
Message(player, "PlayerNotFound", args[0]);
PlaySound(errorSound, self);
return;
}
GiveMarketplace(target, "receive", config.pickup.initialCondition);
PlaySound(successSound, self);
Message(player, "PlayerGiven", target);
}
[Command("marketplace.craft")]
private void CraftCmd(IPlayer player, string command, string[] args)
{
if (player.IsServer)
{
Message(player, "InGameOnly");
return;
}
var self = player.Object as BasePlayer;
if (self == null) return;
if (!config.craft.craftTrue)
{
Message(player, "NoCraft");
PlaySound(errorSound, self);
return;
}
else if (config.craft.craftTrue && !player.HasPermission(permCraft))
{
Message(player, "Permission");
PlaySound(errorSound, self);
return;
}
var required = new Dictionary<string, int>();
foreach (var component in config.craft.cost)
{
ItemDefinition compDefinition = ItemManager.FindItemDefinition(component.Key);
if (self.inventory.GetAmount(compDefinition.itemid) < component.Value)
{
if (!required.ContainsKey(component.Key))
{
required.Add(component.Key, 0);
}
required[component.Key] += component.Value;
}
}
if (required.Count == 0)
{
foreach (var item in config.craft.cost)
{
ItemDefinition itemDefinition = ItemManager.FindItemDefinition(item.Key);
self.inventory.Take(null, itemDefinition.itemid, item.Value);
}
GiveMarketplace(self, "craft", config.pickup.initialCondition);
PlaySound(successSound, self);
return;
}
else
{
string list = String.Empty;
foreach (var item in required)
{
list = list + ($" + {item.Key} x {item.Value}\n");
}
Message(player, "CraftCost", list);
PlaySound(errorSound, self);
}
}
[Command("marketplace.pickup")]
private void PickupCmd(IPlayer player, string command, string[] args)
{
var self = player.Object as BasePlayer;
if (self == null && !player.IsServer) return;
if (player.IsServer)
{
Message(player, "InGameOnly");
return;
}
else if (!config.pickup.canPickup)
{
Message(player, "NoPickup");
PlaySound(errorSound, self);
return;
}
else if (!player.HasPermission(permPickup))
{
Message(player, "Permission");
PlaySound(errorSound, self);
return;
}
else if (args.Length > 1)
{
Message(player, "PickupUse");
return;
}
var entity = RaycastAll<BaseEntity>(self.eyes.HeadRay()) as BaseEntity;
if (entity == null)
{
Message(player, "NullEnt");
PlaySound(errorSound, self);
return;
}
else if (entity.name == marketTerminal)
{
entity = entity.GetParentEntity();
}
else if (!IsMarketplace(entity.skinID))
{
Message(player, "NotMarket");
PlaySound(errorSound, self);
return;
}
else if (config.pickup.privPickup && !IsAuthorized(self, entity))
{
Message(player, "BuildPriv");
PlaySound(errorSound, self);
return;
}
else if (config.options.useFriends || config.options.useClans || config.options.useTeams)
{
if (!IsFriend(self.userID, entity.OwnerID))
{
Message(player, "OwnerTeam");
PlaySound(errorSound, self);
return;
}
}
if (config.deploy.addVending && !IsVendingEmpty(self, entity))
{
PlaySound(errorSound, self);
Message(player, "VendingNotEmpty");
return;
}
PickupMarketplace(self, entity);
}
[Command("marketplace.clear")]
void ClearData(IPlayer player, string command, string[] args)
{
var self = player.Object as BasePlayer;
if (self == null && !player.IsServer) return;
if (!player.HasPermission(permAdmin))
{
Message(player, "Permission");
PlaySound(errorSound, self);
return;
}
else if (args?.Length > 1 && player.IsConnected)
{
Message(player, "ClearUsage");
PlaySound(errorSound, self);
return;
}
else if (args?.Length < 1)
{
storedData.MarketData.Clear();
SaveData();
Message(player, "DataCleared");
PlaySound(successSound, self);
return;
}
else if (args?.Length == 1)
{
var ownerId = args[0];
bool success = false;
var keys = storedData.MarketData.Keys.ToArray();
foreach (var key in keys)
{
if (storedData.MarketData[key].OwnerID.ToString() == ownerId)
{
storedData.MarketData.Remove(key);
success = true;
}
}
if (success)
{
SaveData();
Message(player, "UserCleared", ownerId);
PlaySound(successSound, self);
return;
}
Message(player, "NoPlayerData", ownerId);
PlaySound(errorSound, self);
}
}
#endregion
#region Mono
private class MarketplaceComponent : MonoBehaviour
{
public BaseEntity marketplace;
public BasePlayer player;
public ulong marketId;
public Vector3 position;
void Awake()
{
marketplace = gameObject.GetComponent<Marketplace>();
marketplace.SendNetworkUpdateImmediate();
marketplace.UpdateNetworkGroup();
player = marketplace.creatorEntity as BasePlayer;
marketId = marketplace.net.ID.Value;
position = marketplace.transform.position;
if (marketplace == null)
DestroyImmediate(this);
if (config.destroy.floorCheck)
InvokeRepeating(nameof(GroundCheck), 3f, 3f);
}
void GroundCheck()
{
RaycastHit hit;
var mpPosition = position + new Vector3(0, 0.5f, 0);
Physics.Raycast(mpPosition, Vector3.down, out hit, 5f, LayerMask.GetMask("Terrain", "Construction", "Default"));
if (hit.distance > 0.6f)
GroundMissing();
}
void GroundMissing()
{
if (!storedData.MarketData.ContainsKey(marketplace.net.ID.Value))
return;
var condition = storedData.MarketData[marketId].Condition;
var vending = storedData.MarketData[marketId].Vending;
if (config.deploy.addVending && vending != null)
{
foreach (var vend in vending)
{
var machine = BaseNetworkable.serverEntities.Find(new NetworkableId(vend.NetID));
Instance.NextTick(() => {
if (!machine.IsDestroyed)
machine.Kill();
});
}
}
marketplace.Kill();
Instance.RemovePlayerData(marketId);
if (config.destroy.dropItem)
{
Instance.DropDestroyed(position, condition);
}
if (config.options.enableSounds)
{
Instance.PlaySound(breakSound, player);
}
}
void OnDestroy()
{
CancelInvoke(nameof(GroundCheck));
}
}
#endregion Mono
#region Language
protected override void LoadDefaultMessages()
{
lang.RegisterMessages(new Dictionary<string, string>
{
["Pickup"] = "You picked up a Marketplace!",
["Receive"] = "You received a Marketplace!",
["Crafted"] = "You crafted a Marketplace!",
["PlayerGiven"] = "{0} received a Marketplace!",
["ItemBroken"] = "Your Marketplace has broken and is not repariable!",
["Permission"] = "You do not have permission to do that!",
["BuildPriv"] = "You need building privilege to do that!",
["NoCraft"] = "Marketplace crafting is disabled!",
["NoPickup"] = "Marketplace pickup is disabled!",
["PickupUse"] = "Hit a terminal with a hammer or type: /marketplace.pickup while looking at it.",
["OwnerTeam"] = "Only the owner or their allies can pickup this Marketplace!",
["CraftCost"] = "Not enough resources to craft:\n{0}",
["NullEnt"] = "No marketplace near, try standing closer.",
["PlayerNotFound"] = "Can't find a player with the name/SteamID: {0}",
["NoPlayerData"] = "Can't find a player with the SteamID: {0}",
["NoMultiples"] = "You may only deploy one marketplace at any time!",
["OnFoundation"] = "Marketplaces must be placed on foundations!",
["InsideBuilding"] = "Marketplaces must have a clear line of sight to the sky!",
["RoomToDeploy"] = "There is not room to deploy a marketplace here!",
["NotMarket"] = "You are not looking at a marketplace!",
["ClearUsage"] = "Usage:\n - /marketplace.clear to clear ALL players data\n - /marketplace.clear <Steam64Id> to clear data for that player",
["DataCleared"] = "ALL Marketplace data cleared!",
["UserCleared"] = "Marketplace data cleared for: {0}",
["NoRepair"] = "You cannot repair a Marketplace!",
["NoRecycle"] = "You cannot recycle a Marketplace!",
["ConsoleUsage"] = "Error: Please specify a player name or SteamID!",
["InGameOnly"] = "Error: This command is only for use in game!",
["VendingNotEmpty"] = "One or more vending machines are not empty!",
["HitToRotate"] = "Hit marketplace vending machines with a hammer to rotate",
["OwnerTeamRotate"] = "Only the owner or their allies can rotate this vending machine",
["OwnerRotate"] = "Only the owner can rotate this vending machine"
}, this, "en");
}
private string GetLang(string messageKey, string playerID, params object[] args)
{
return string.Format(lang.GetMessage(messageKey, this, playerID), args);
}
public void Message(IPlayer player, string messageKey, params object[] args)
{
if (player == null) return;
var message = string.Format(GetLang(messageKey, player.Id, args));
if (config.options.useChatPrefix)
player.Reply(config.options.chatPrefix + message);
else
player.Reply(message);
BasePlayer basePlayer = player.Object as BasePlayer;
if (config.options.showTips)
basePlayer.ShowToast(GameTip.Styles.Blue_Long, message, args.ToString());
}
private void Message(BasePlayer player, string messageKey, params object[] args)
{
if (player == null) return;
var message = string.Format(GetLang(messageKey, player.UserIDString, args));
if (config.options.useChatPrefix)
player.ChatMessage(config.options.chatPrefix + message);
else
player.ChatMessage(message);
if (config.options.showTips)
player.ShowToast(GameTip.Styles.Blue_Long, message, args.ToString());
}
#endregion Language
#region Stored Data
private static StoredData storedData;
private class StoredData
{
public Dictionary<ulong, MarketplaceData> MarketData = new Dictionary<ulong, MarketplaceData>();
}
private class MarketplaceData
{
public string PlayerName;
public ulong OwnerID;
public float Condition;
public List<Vending> Vending = new List<Vending>();
}
private class Vending
{
public string Name;
public ulong NetID;
}
private void AddPlayerData(ulong playerId, string playerName, ulong marketId, float condition, List<Vending> vending)
{
if(!storedData.MarketData.ContainsKey(marketId))
{
storedData.MarketData.Add(marketId, new MarketplaceData());
storedData.MarketData[marketId].PlayerName = playerName;
storedData.MarketData[marketId].OwnerID = playerId;
storedData.MarketData[marketId].Condition = condition;
storedData.MarketData[marketId].Vending = vending;
SaveData();
}
}
private void RemovePlayerData(ulong marketId)
{
if (storedData.MarketData.ContainsKey(marketId))
{
storedData.Market
// ... [Code preview truncated due to length. Full source in attached file] ...