C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using System;
using System.Reflection;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using UnityEngine;
using Facepunch.Steamworks;
using Rust;
using Oxide.Core;
using Oxide.Core.Plugins;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace Oxide.Plugins {
[Info("SkinBox", "Fujikura", "1.9.3", ResourceId = 17)]
class SkinBox : RustPlugin {
[PluginReference]
Plugin QuickSort;
[PluginReference]
Plugin ServerRewards;
[PluginReference]
Plugin Economics;
bool skinsLoaded;
bool Changed = false;
bool _unloaded;
static SkinBox skinBox = null;
bool activeServerRewards;
bool activeEconomics;
bool activePointSystem;
Dictionary<string, List<ulong>> skinsCache = new Dictionary<string, List<ulong>>();
Dictionary<string, List<ulong>> skinsCacheLimited = new Dictionary<string, List<ulong>>();
Dictionary<string, int> approvedSkinsCount = new Dictionary<string, int>();
List<ulong> checkedPlayers = new List <ulong>();
Dictionary<string, DateTime> cooldownTimes = new Dictionary<string, DateTime>();
Dictionary<string, string> NameToItemName = new Dictionary<string, string>();
Dictionary<string, string> ItemNameToName = new Dictionary<string, string>();
Dictionary <string, object> manualAddedSkinsPre = new Dictionary <string, object>();
Dictionary <string, List<ulong>> manualAddedSkins = new Dictionary <string, List<ulong>>();
List<ulong> excludedSkins = new List<ulong>();
List<object> excludedSkinsPre = new List<object>();
Dictionary <ulong, Vector3> activeBoxUsers = new Dictionary <ulong, Vector3>();
static Dictionary<string, object> missingWorkshopNames() {
var dp = new Dictionary<string, object>();
dp.Add("rug", "Rug");
dp.Add("chair", "Chair");
dp.Add("rug.bear", "Bearskin Rug");
dp.Add("mask.bandana", "Bandana");
dp.Add("table", "Table");
dp.Add("fridge", "Fridge");
return dp;
}
string skinBoxCommand;
string permissionUse;
bool forceClientPreload;
bool forceClientAlways;
bool forceAlsoWearables;
bool showLoadedSkinCounts;
int exludedSkinsAuthLevel;
bool hideQuickSort;
float boxUseDistance;
string steamApiKey;
int accessOverrideAuthLevel;
bool enableCustomPerms;
string permCustomPlayerwearable;
string permCustomWeapon;
string permCustomDeployable;
bool useInbuiltSkins;
bool useApprovedSkins;
int approvedSkinsLimit;
bool useManualAddedSkins;
bool useWebskinsRankedByTrend;
int usedRankedByTrendDays;
Dictionary<string, object> missingSkinNames = new Dictionary<string, object>();
bool enableCooldown;
int cooldownBox;
bool cooldownOverrideAdmin;
int cooldownOverrideAuthLevel;
bool activateAfterSkinTaken;
bool enableUsageCost;
bool useServerRewards;
bool useEconomics;
int costBoxOpen;
int costWeapon;
int costPlayerwearable;
int costDeployable;
bool costExcludeAdmins;
object GetConfig(string menu, string datavalue, object defaultValue) {
var data = Config[menu] as Dictionary<string, object>;
if (data == null) {
data = new Dictionary<string, object>();
Config[menu] = data;
Changed = true;
}
object value;
if (!data.TryGetValue(datavalue, out value)) {
value = defaultValue;
data[datavalue] = value;
Changed = true;
}
return value;
}
void LoadVariables() {
useInbuiltSkins = Convert.ToBoolean(GetConfig("AvailableSkins", "useInbuiltSkins", true));
useApprovedSkins = Convert.ToBoolean(GetConfig("AvailableSkins", "useApprovedSkins", true));
approvedSkinsLimit = Convert.ToInt32(GetConfig("AvailableSkins", "approvedSkinsLimit", -1));
useManualAddedSkins = Convert.ToBoolean(GetConfig("AvailableSkins", "useManualAddedSkins", true));
useWebskinsRankedByTrend = Convert.ToBoolean(GetConfig("AvailableSkins", "useWebskinsRankedByTrend", false));
usedRankedByTrendDays = Convert.ToInt32(GetConfig("AvailableSkins", "usedRankedByTrendDays", 30));
missingSkinNames = (Dictionary<string, object>)GetConfig("AvailableSkins", "MissingSkinNames", missingWorkshopNames());
skinBoxCommand = Convert.ToString(GetConfig("Settings", "skinBoxCommand", "skinbox"));
permissionUse = Convert.ToString(GetConfig("Settings", "permissionUse", "skinbox.use"));
forceClientPreload = Convert.ToBoolean(GetConfig("Settings", "forceClientPreload", false));
forceClientAlways = Convert.ToBoolean(GetConfig("Settings", "forceClientAlways", false));
forceAlsoWearables = Convert.ToBoolean(GetConfig("Settings", "forceAlsoWearables", true));
showLoadedSkinCounts = Convert.ToBoolean(GetConfig("Settings", "showLoadedSkinCounts", true));
exludedSkinsAuthLevel = Convert.ToInt32(GetConfig("Settings", "exludedSkinsAuthLevel", 2));
accessOverrideAuthLevel = Convert.ToInt32(GetConfig("Settings", "accessOverrideAuthLevel", 2));
hideQuickSort = Convert.ToBoolean(GetConfig("Settings", "hideQuickSort", false));
boxUseDistance = Convert.ToSingle(GetConfig("Settings", "boxUseDistance", 10.0));
steamApiKey = Convert.ToString(GetConfig("Settings", "steamApiKey", ""));
enableCustomPerms = Convert.ToBoolean(GetConfig("CustomPermissions", "enableCustomPerms", false));
permCustomPlayerwearable = Convert.ToString(GetConfig("CustomPermissions", "permCustomPlayerwearable", "skinbox.playerwearable"));
permCustomWeapon= Convert.ToString(GetConfig("CustomPermissions", "permCustomWeapon", "skinbox.weapon"));
permCustomDeployable = Convert.ToString(GetConfig("CustomPermissions", "permCustomDeployable", "skinbox.deployable"));
enableCooldown = Convert.ToBoolean(GetConfig("Cooldown", "enableCooldown", false));
cooldownBox = Convert.ToInt32(GetConfig("Cooldown", "cooldownBox", 60));
cooldownOverrideAdmin = Convert.ToBoolean(GetConfig("Cooldown", "cooldownOverrideAdmin", true));
cooldownOverrideAuthLevel = Convert.ToInt32(GetConfig("Cooldown", "cooldownOverrideAuthLevel", 2));
activateAfterSkinTaken = Convert.ToBoolean(GetConfig("Cooldown", "activateAfterSkinTaken", true));
manualAddedSkinsPre = (Dictionary<string, object>)GetConfig("SkinsAdded", "SkinList", new Dictionary<string, object> {
}
);
excludedSkinsPre = (List<object>)GetConfig("SkinsExcluded", "SkinList", new List<object> {
}
);
enableUsageCost = Convert.ToBoolean(GetConfig("UsageCost", "enableUsageCost", false));
useServerRewards = Convert.ToBoolean(GetConfig("UsageCost", "useServerRewards", true));
useEconomics = Convert.ToBoolean(GetConfig("UsageCost", "useEconomics", false));
costBoxOpen = Convert.ToInt32(GetConfig("UsageCost", "costBoxOpen", 5));
costWeapon = Convert.ToInt32(GetConfig("UsageCost", "costWeapon", 30));
costPlayerwearable = Convert.ToInt32(GetConfig("UsageCost", "costPlayerwearable", 20));
costDeployable = Convert.ToInt32(GetConfig("UsageCost", "costDeployable", 10));
costExcludeAdmins = Convert.ToBoolean(GetConfig("UsageCost", "costExcludeAdmins", true));
if (!Changed) return;
SaveConfig();
Changed = false;
}
protected override void LoadDefaultConfig() {
Config.Clear();
LoadVariables();
}
void LoadDefaultMessages() {
lang.RegisterMessages(new Dictionary<string, string> {
{
"NoPermission", "You don't have permission to use the SkinBox"
}
, {
"ToNearPlayer", "The SkinBox is currently not usable at this place"
}
, {
"CooldownTime", "You need to wait {0} seconds to re-open the SkinBox again"
}
, {
"NotEnoughBalanceOpen", "You need at least '{0}' bucks to open the SkinBox"
}
, {
"NotEnoughBalanceUse", "You would need at least '{0}' bucks to skin '{1}'"
}
, {
"NotEnoughBalanceTake", "'{0}' was not skinned.You had not enough bucks"
}
,
}
, this);
}
void Loaded() {
LoadVariables();
LoadDefaultMessages();
cmd.AddChatCommand(skinBoxCommand, this, "cmdSkinBox");
if (!permission.PermissionExists(permissionUse)) permission.RegisterPermission(permissionUse, this);
if (enableCustomPerms) {
if (!permission.PermissionExists(permCustomPlayerwearable)) permission.RegisterPermission(permCustomPlayerwearable, this);
if (!permission.PermissionExists(permCustomWeapon)) permission.RegisterPermission(permCustomWeapon, this);
if (!permission.PermissionExists(permCustomDeployable)) permission.RegisterPermission(permCustomDeployable, this);
}
skinsCache = new Dictionary<string, List<ulong>>();
skinsCacheLimited = new Dictionary<string, List<ulong>>();
approvedSkinsCount = new Dictionary<string, int>();
NameToItemName = new Dictionary<string, string>();
ItemNameToName = new Dictionary<string, string>();
checkedPlayers = new List <ulong>();
activeBoxUsers = new Dictionary <ulong, Vector3>();
skinsLoaded = false;
_unloaded = false;
skinBox = this;
}
void OnServerInitialized() {
if (enableUsageCost) {
if (ServerRewards && useServerRewards) activeServerRewards = true;
if (Economics && useEconomics) activeEconomics = true;
if (activeServerRewards && activeEconomics) activeEconomics = false;
if (activeServerRewards || activeEconomics) activePointSystem = true;
}
OnServerInit();
}
void OnServerInit() {
foreach (var itemtype in Rust.Workshop.Approved.All.ToList()) {
if (itemtype.Skinnable.Name == null || itemtype.Skinnable.Name == string.Empty) continue;
if (itemtype.Skinnable.ItemName == null || itemtype.Skinnable.ItemName == string.Empty) continue;
if (!NameToItemName.ContainsKey(itemtype.Skinnable.Name.ToLower())) NameToItemName.Add(itemtype.Skinnable.Name.ToLower(), itemtype.Skinnable.ItemName.ToLower());
if (!ItemNameToName.ContainsKey(itemtype.Skinnable.ItemName.ToLower())) ItemNameToName.Add(itemtype.Skinnable.ItemName.ToLower(), itemtype.Skinnable.Name.ToLower());
}
foreach (var skin in missingSkinNames) {
var itemname = skin.Key.ToLower();
var itemDef = ItemManager.FindItemDefinition(itemname);
if (itemDef == null) continue;
var workshopname = ((string)skin.Value).ToLower();
if (!NameToItemName.ContainsKey(workshopname)) NameToItemName.Add(workshopname, itemname);
if (!ItemNameToName.ContainsKey(itemname)) ItemNameToName.Add(itemname, workshopname);
}
foreach (var manual in manualAddedSkinsPre) manualAddedSkins.Add(manual.Key.ToString(), (manual.Value as List<object>).ConvertAll(obj => Convert.ToUInt64(obj)));
excludedSkins = excludedSkinsPre.ConvertAll(obj => Convert.ToUInt64(obj));
GetItemSkins();
}
void Unload() {
_unloaded = true;
ServerMgr.Instance.StopCoroutine("GetRankedWorkshopSkins");
ServerMgr.Instance.StopCoroutine("GetAcceptedWorkshopSkins");
ServerMgr.Instance.StopCoroutine("SearchWorkshopSkin");
var objs = UnityEngine.Object.FindObjectsOfType<SkinBoxHandler>().ToList();
if (objs.Count > 0) foreach (var obj in objs) {
if (obj.looter == null) continue;
obj.looter.EndLooting();
obj.PlayerStoppedLooting(obj.looter);
GameObject.Destroy(obj);
}
}
void GetItemSkins() {
if (skinsLoaded) return;
int countInbuilt = 0;
foreach (var itemDef in ItemManager.GetItemDefinitions()) {
List<ulong> skins;
skins = new List<ulong> {
0
}
;
if (useInbuiltSkins) skins.AddRange(ItemSkinDirectory.ForItem(itemDef).Select(skin => Convert.ToUInt64(skin.id)));
skinsCache.Add(itemDef.shortname, skins);
if (skins.Count > 1) countInbuilt += (skins.Count -1);
}
if (showLoadedSkinCounts && useInbuiltSkins) {
Puts($"Loaded {countInbuilt} inbuilt skins");
Interface.CallHook("OnSkinCacheUpdate", skinsCache);
}
if (useApprovedSkins) {
int countApproved = 0;
foreach (var shopskin in Rust.Workshop.Approved.All.Where(skin => skin.Skinnable.ItemName != null)) {
if (!approvedSkinsCount.ContainsKey(shopskin.Skinnable.ItemName)) approvedSkinsCount[shopskin.Skinnable.ItemName] = 0;
if (approvedSkinsLimit > 0 && approvedSkinsCount[shopskin.Skinnable.ItemName] >= approvedSkinsLimit) {
if (!skinsCacheLimited.ContainsKey(shopskin.Skinnable.ItemName)) skinsCacheLimited[shopskin.Skinnable.ItemName] = new List<ulong>();
skinsCacheLimited[shopskin.Skinnable.ItemName].Add(shopskin.WorkshopdId);
continue;
}
if (!skinsCache.ContainsKey(shopskin.Skinnable.ItemName)) skinsCache[shopskin.Skinnable.ItemName] = new List<ulong>();
if (!skinsCache[shopskin.Skinnable.ItemName].Contains(shopskin.WorkshopdId)) {
skinsCache[shopskin.Skinnable.ItemName].Add(shopskin.WorkshopdId);
approvedSkinsCount[shopskin.Skinnable.ItemName]++;
countApproved++;
}
}
if (showLoadedSkinCounts) Puts($"Loaded {countApproved} inbuilt approved Workshop skins");
}
if (useManualAddedSkins) {
int countManual = 0;
foreach (var manualskins in manualAddedSkins) {
string shortname = manualskins.Key;
if (!ItemNameToName.ContainsKey(shortname)) continue;
string itemname = ItemNameToName[shortname];
List<ulong> fileids = manualskins.Value;
foreach (var fileid in fileids) {
if (!skinsCache[shortname].Contains(fileid)) {
skinsCache[shortname].Add(fileid);
countManual++;
}
}
}
if (showLoadedSkinCounts && countManual > 0) {
Puts($"Loaded {countManual} manual added skins");
Interface.CallHook("OnSkinCacheUpdate", skinsCache);
}
}
skinsLoaded = true;
if (useApprovedSkins) ServerMgr.Instance.StartCoroutine(GetAcceptedWorkshopSkins());
else if (useWebskinsRankedByTrend) ServerMgr.Instance.StartCoroutine(GetRankedWorkshopSkins());
}
void RunQuery(Facepunch.Steamworks.Workshop.Query query) {
FieldInfo Callback = typeof(Facepunch.Steamworks.Workshop.Query).GetField("Callback", (BindingFlags.Instance | BindingFlags.NonPublic));
FieldInfo _resultSkip = typeof(Facepunch.Steamworks.Workshop.Query).GetField("_resultSkip", (BindingFlags.Instance | BindingFlags.NonPublic));
FieldInfo _resultsRemain = typeof(Facepunch.Steamworks.Workshop.Query).GetField("_resultsRemain", (BindingFlags.Instance | BindingFlags.NonPublic));
FieldInfo _resultPage = typeof(Facepunch.Steamworks.Workshop.Query).GetField("_resultPage", (BindingFlags.Instance | BindingFlags.NonPublic));
FieldInfo _results = typeof(Facepunch.Steamworks.Workshop.Query).GetField("_results", (BindingFlags.Instance | BindingFlags.NonPublic));
MethodInfo runInternal = typeof(Facepunch.Steamworks.Workshop.Query).GetMethod("RunInternal", BindingFlags.NonPublic | BindingFlags.Instance);
bool flag = Callback.GetValue(query) != null;
if (!flag) {
int num = (query.Page - 1) * query.PerPage;
query.TotalResults = 0;
_resultSkip.SetValue(query, num % 50);
_resultsRemain.SetValue(query, query.PerPage);
_resultPage.SetValue(query, (int)Math.Floor((double)((float)num / 50f)));
_results.SetValue(query, new List<Workshop.Item>());
runInternal.Invoke(query, null);
}
}
public IEnumerator GetAcceptedWorkshopSkins(bool timed = false) {
var workshopQuery = Global.SteamServer.Workshop.CreateQuery();
workshopQuery.Page = 1;
workshopQuery.PerPage = 5000;
workshopQuery.RequireTags.Add("Version3");
workshopQuery.RequireTags.Add("Skin");
workshopQuery.RequireAllTags = true;
workshopQuery.Order = Workshop.Order.AcceptedForGameRankedByAcceptanceDate;
if (showLoadedSkinCounts && !timed) Puts($"Checking Workshop for new accepted skins");
RunQuery(workshopQuery);
yield return new WaitWhile(new System.Func<bool>(() => workshopQuery.IsRunning));
if (_unloaded) {
workshopQuery.Dispose();
workshopQuery = null;
yield return null;
}
int countQueried = 0;
foreach (var item in workshopQuery.Items) {
foreach (var tag in item.Tags.Where(t => !t.Contains("Version") && !t.Contains("Skin"))) {
if (NameToItemName.ContainsKey(tag)) {
string shortname = NameToItemName[tag];
if (skinsCacheLimited.ContainsKey(shortname) && skinsCacheLimited[shortname].Contains(item.Id)) continue;
if (!skinsCache[shortname].Contains(item.Id)) {
skinsCache[shortname].Add(item.Id);
countQueried++;
}
}
}
}
workshopQuery.Dispose();
if (showLoadedSkinCounts && countQueried > 0) {
Puts($"Loaded {countQueried} new accepted Workshop skins");
Interface.CallHook("OnSkinCacheUpdate", skinsCache);
}
else if (showLoadedSkinCounts && countQueried == 0 && !timed) Puts($"No recently accepted Workshop skins found");
if (useWebskinsRankedByTrend) ServerMgr.Instance.StartCoroutine(GetRankedWorkshopSkins());
}
public IEnumerator GetRankedWorkshopSkins() {
var workshopQuery = Global.SteamServer.Workshop.CreateQuery();
workshopQuery.Page = 1;
workshopQuery.PerPage = 50000;
workshopQuery.RequireTags.Add("Version3");
workshopQuery.RequireTags.Add("Skin");
workshopQuery.RequireAllTags = true;
workshopQuery.Order = Workshop.Order.RankedByTrend;
workshopQuery.RankedByTrendDays = usedRankedByTrendDays;
if (showLoadedSkinCounts) Puts($"Calling Workshop to fill up the SkinCache.This can take a few moments...");
RunQuery(workshopQuery);
yield return new WaitWhile(new System.Func<bool>(() => workshopQuery.IsRunning));
if (_unloaded) {
workshopQuery.Dispose();
yield break;
}
int countQueried = 0;
foreach (var item in workshopQuery.Items) {
foreach (var tag in item.Tags.Where(t => !t.Contains("Version") && !t.Contains("Skin"))) {
if (NameToItemName.ContainsKey(tag)) {
string shortname = NameToItemName[tag];
if (!skinsCache[shortname].Contains(item.Id) && skinsCache[shortname].Count < 31) {
skinsCache[shortname].Add(item.Id);
countQueried++;
}
}
}
}
workshopQuery.Dispose();
if (showLoadedSkinCounts && countQueried > 0) {
Puts($"Filled up SkinCache with {countQueried} new Workshop skins");
Interface.CallHook("OnSkinCacheUpdate", skinsCache);
}
}
[ConsoleCommand("skinbox.addexcluded")]
void consoleAddExcluded(ConsoleSystem.Arg arg) {
if (arg.Connection != null && arg.Connection.authLevel < 2) return;
if (arg.Args == null || arg.Args.Length < 1) {
SendReply(arg, "You need to type in one or more Workshop FileId's");
return;
}
List<ulong> fileIds = new List<ulong>();
for (int i = 0; i < arg.Args.Length; i++) {
ulong fileId = 0ul;
if (!ulong.TryParse(arg.Args[i], out fileId)) {
SendReply(arg, $"Ignored '{arg.Args[i]}' as of not a number");
continue;
}
else {
if (arg.Args[i].Length != 9) {
SendReply(arg, $"Ignored '{arg.Args[i]}' as of not 9-Digits");
continue;
}
fileIds.Add(fileId);
}
}
int countAdded = 0;
foreach (var fileId in fileIds) if (!excludedSkins.Contains(fileId)) {
excludedSkins.Add(fileId);
countAdded++;
}
if (countAdded > 0) {
Config["SkinsExcluded", "SkinList"] = excludedSkins;
Config.Save();
SendReply(arg, $"Added {countAdded} skins to exclusion list");
}
}
[ConsoleCommand("skinbox.removeexcluded")]
void consoleRemoveExcluded(ConsoleSystem.Arg arg) {
if (arg.Connection != null && arg.Connection.authLevel < 2) return;
if (arg.Args == null || arg.Args.Length < 1) {
SendReply(arg, "You need to type in one or more Workshop FileId's");
return;
}
List<ulong> fileIds = new List<ulong>();
for (int i = 0; i < arg.Args.Length; i++) {
ulong fileId = 0ul;
if (!ulong.TryParse(arg.Args[i], out fileId)) {
SendReply(arg, $"Ignored '{arg.Args[i]}' as of not a number");
continue;
}
else {
if (arg.Args[i].Length != 9) {
SendReply(arg, $"Ignored '{arg.Args[i]}' as of not 9-Digits");
continue;
}
fileIds.Add(fileId);
}
}
int countRemoved = 0;
foreach (var fileId in fileIds) if (excludedSkins.Contains(fileId)) {
excludedSkins.Remove(fileId);
countRemoved++;
}
if (countRemoved > 0) {
Config["SkinsExcluded", "SkinList"] = manualAddedSkins;
Config.Save();
Puts($"Removed {countRemoved} skins from exclusion");
}
}
[ConsoleCommand("skinbox.addskin")]
void consoleAddSkin(ConsoleSystem.Arg arg) {
if (arg.Connection != null && arg.Connection.authLevel < 2) return;
if (arg.Args == null || arg.Args.Length < 1) {
SendReply(arg, "You need to type in one or more Workshop FileId's");
return;
}
List<ulong> fileIds = new List<ulong>();
for (int i = 0; i < arg.Args.Length; i++) {
ulong fileId = 0ul;
if (!ulong.TryParse(arg.Args[i], out fileId)) {
SendReply(arg, $"Ignored '{arg.Args[i]}' as of not a number");
continue;
}
else {
if (arg.Args[i].Length != 9) {
SendReply(arg, $"Ignored '{arg.Args[i]}' as of not 9-Digits");
continue;
}
fileIds.Add(fileId);
}
}
ServerMgr.Instance.StartCoroutine(SearchWorkshopSkin(fileIds));
}
[ConsoleCommand("skinbox.removeskin")]
void consoleRemoveSkin(ConsoleSystem.Arg arg) {
if (arg.Connection != null && arg.Connection.authLevel < 2) return;
if (arg.Args == null || arg.Args.Length < 1) {
SendReply(arg, "You need to type in one or more Workshop FileId's");
return;
}
List<ulong> fileIds = new List<ulong>();
for (int i = 0; i < arg.Args.Length; i++) {
ulong fileId = 0ul;
if (!ulong.TryParse(arg.Args[i], out fileId)) {
SendReply(arg, $"Ignored '{arg.Args[i]}' as of not a number");
continue;
}
else {
if (arg.Args[i].Length != 9) {
SendReply(arg, $"Ignored '{arg.Args[i]}' as of not 9-Digits");
continue;
}
fileIds.Add(fileId);
}
}
bool doSave = false;
int removed = 0;
foreach (var addedSkins in manualAddedSkins) {
foreach (var fileId in fileIds) {
if (addedSkins.Value.Contains(fileId)) {
manualAddedSkins[addedSkins.Key].Remove(fileId);
skinsCache[addedSkins.Key].Remove(fileId);
removed++;
doSave = true;
}
}
}
if (doSave) {
Config["SkinsAdded", "SkinList"] = manualAddedSkins;
Config.Save();
Puts($"Removed {removed} FileId's");
}
}
public IEnumerator SearchWorkshopSkin(List<ulong> fileIds) {
var workshopQuery = Global.SteamServer.Workshop.CreateQuery();
workshopQuery.Page = 1;
workshopQuery.PerPage = 1;
workshopQuery.RequireTags.Add("Version3");
workshopQuery.FileId = new List<ulong>(fileIds);
Puts($"Calling Workshop for '{fileIds.Count}' FileId's");
RunQuery(workshopQuery);
yield return new WaitWhile(new System.Func<bool>(() => workshopQuery.IsRunning));
bool doSave = false;
foreach (var item in workshopQuery.Items) {
bool matchedAny = false;
foreach (var tag in item.Tags.Where(t => !t.Contains("Version") && !t.Contains("Skin") && !t.Contains("Weapon") && !t.Contains("Playerwearable") && !t.Contains("Deployable"))) {
if (NameToItemName.ContainsKey(tag)) {
string shortname = NameToItemName[tag];
if (manualAddedSkins.ContainsKey(shortname)) {
if (manualAddedSkins[shortname].Contains(item.Id)) {
Puts($"The FileId '{item.Id}' was already added");
matchedAny = true;
continue;
}
}
if (skinsCache.ContainsKey(shortname)) if ((skinsCache[shortname] as List<ulong>).Contains(item.Id)) {
Puts($"The FileId '{item.Id}' belongs already to the default loaded skins");
matchedAny = true;
continue;
}
if (!manualAddedSkins.ContainsKey(shortname)) manualAddedSkins.Add(shortname, new List<ulong>());
manualAddedSkins[shortname].Add(item.Id);
if (!skinsCache.ContainsKey(shortname)) skinsCache.Add(shortname, new List<ulong>());
skinsCache[shortname].Add(item.Id);
Puts($"Added '{item.Title}' to the manual skins list for '{shortname}'");
matchedAny = true;
doSave = true;
}
}
if (!matchedAny) Puts($"No matching item shortname found to assign the skin '{item.Id}'");
}
if (doSave) {
Config["SkinsAdded", "SkinList"] = manualAddedSkins;
Config.Save();
Interface.CallHook("OnSkinCacheUpdate", skinsCache);
}
workshopQuery.Dispose();
}
[ConsoleCommand("skinbox.addcollection")]
void consoleAddCollection(ConsoleSystem.Arg arg) {
if (arg.Connection != null && arg.Connection.authLevel < 2) return;
if (steamApiKey == null || steamApiKey == string.Empty) {
SendReply(arg, "This functions needs valid defined steam api-key");
return;
}
if (arg.Args == null || arg.Args.Length < 1) {
SendReply(arg, "You need to type in a valid collection id");
return;
}
ulong collId = 0;
if (!ulong.TryParse(arg.Args[0], out collId)) {
SendReply(arg, $"Collection ID not correct: '{arg.Args[0]}' is not a number");
return;
}
else {
if (arg.Args[0].Length != 9) {
SendReply(arg, $"Collection ID not correct: '{arg.Args[0]}' has not 9-Digits");
return;
}
}
var url = $"https://api.steampowered.com/ISteamRemoteStorage/GetCollectionDetails/v1/";
var body = $"?key={steamApiKey}&collectioncount=1&publishedfileids[0]={arg.Args[0]}";
try {
webrequest.EnqueuePost(url, body, (code, response) => PostCallback(code, response), this);
}
catch {
Puts("Steam webrequest failed!");
}
}
void PostCallback(int code, string response) {
if (response == null || code != 200) {
Puts("Steam webrequest failed by wrong response!");
return;
}
var col = JsonConvert.DeserializeObject<GetCollectionDetails>(response);
if (col == null || !(col is GetCollectionDetails)) {
Puts("No Collection data received!");
return;
}
if (col.response.resultcount == 0 || col.response.collectiondetails == null || col.response.collectiondetails.Count == 0 || col.response.collectiondetails[0].result != 1) {
Puts("The Steam collection could not be found!");
return;
}
List<ulong> fileIds = new List<ulong>();
foreach (var child in col.response.collectiondetails[0].children) {
try {
fileIds.Add(Convert.ToUInt64(child.publishedfileid));
}
catch {
}
}
if (fileIds.Count == 0) {
Puts("No skin numbers found.Workshop search cancelled.");
return;
}
ServerMgr.Instance.StartCoroutine(SearchWorkshopSkin(fileIds));
}
public class GetCollectionDetails {
[JsonProperty("response")]
public Response response;
public class Response {
[JsonProperty("result")]
public int result;
[JsonProperty("resultcount")]
public int resultcount;
[JsonProperty("collectiondetails")]
public List<Collectiondetail> collectiondetails;
public class Collectiondetail {
[JsonProperty("publishedfileid")]
public string publishedfileid;
[JsonProperty("result")]
public int result;
[JsonProperty("children")]
public List<Child> children;
public class Child {
[JsonProperty("publishedfileid")]
public string publishedfileid;
[JsonProperty("sortorder")]
public int sortorder;
[JsonProperty("filetype")]
public int filetype;
}
}
}
}
void OnPlayerInit(BasePlayer player) {
if (player == null) return;
if (!forceClientPreload || (checkedPlayers.Contains(player.userID) && !forceClientAlways)) return;
timer.Once(0.1f, () => InitPreload(player));
}
void InitPreload(BasePlayer player) {
ItemContainer beltInv = player.inventory.containerBelt;
ItemContainer wearInv = player.inventory.containerWear;
var wearList = new List<Item>();
if (forceAlsoWearables) {
foreach (var item in wearInv.itemList.ToList()) {
wearList.Add(item);
item.RemoveFromContainer();
}
player.inventory.SendUpdatedInventory(PlayerInventory.Type.Wear, wearInv, false);
}
beltInv.capacity++;
foreach (var skinCache in skinsCache) {
if ((skinCache.Value as List<ulong>).Count <= 1) continue;
foreach (var skin in (List<ulong>)skinCache.Value) {
if (skin == 0) continue;
Item item = ItemManager.Create(ItemManager.FindItemDefinition(skinCache.Key), 1, skin);
if (item.info.category == ItemCategory.Attire && !forceAlsoWearables) {
item.Remove(0f);
continue;
}
if (item != null) {
if (item.info.category == ItemCategory.Attire && forceAlsoWearables) {
item.MoveToContainer(wearInv);
player.inventory.SendUpdatedInventory(PlayerInventory.Type.Wear, wearInv, false);
}
else {
item.MoveToContainer(beltInv, 6, false);
player.inventory.SendUpdatedInventory(PlayerInventory.Type.Belt, beltInv, false);
}
item.RemoveFromContainer();
}
item.Remove(0f);
}
}
beltInv.capacity--;
if (forceAlsoWearables) {
foreach (var item in wearList) item.MoveToContainer(wearInv);
player.inventory.SendUpdatedInventory(PlayerInventory.Type.Wear, wearInv, false);
wearList.Clear();
}
if (!checkedPlayers.Contains(player.userID)) checkedPlayers.Add(player.userID);
ItemManager.DoRemoves();
}
[ConsoleCommand("skinbox.open")]
void consoleSkinboxOpen(ConsoleSystem.Arg arg) {
if(arg != null && arg.Connection != null && arg.Connection.player != null) {
BasePlayer player = arg.Player();
if (player.inventory.loot.IsLooting()) return;
if(!(player.IsAdmin || player.net.connection.authLevel >= accessOverrideAuthLevel) && !permission.UserHasPermission(player.UserIDString, permissionUse)) {
player.ChatMessage(lang.GetMessage("NoPermission", this, player.UserIDString));
return;
}
if (!CheckDistance(player) || !CheckOpenBalance(player)) return;
if (enableCooldown && !(cooldownOverrideAdmin && (player.IsAdmin || player.net.connection.authLevel >= cooldownOverrideAuthLevel))) {
DateTime now = DateTime.UtcNow;
DateTime time;
var key = player.UserIDString + "-box";
if (cooldownTimes.TryGetValue(key, out time)) {
if (time > now.AddSeconds(-cooldownBox)) {
player.ChatMessage(string.Format(lang.GetMessage("CooldownTime", this, player.UserIDString), (time - now.AddSeconds(-cooldownBox)).Seconds));
return;
}
}
}
OpenSkinBox(player);
}
}
void cmdSkinBox(BasePlayer player, string command, string[] args) {
if (player.inventory.loot.IsLooting()) return;
if(!(player.IsAdmin || player.net.connection.authLevel >= accessOverrideAuthLevel) && !permission.UserHasPermission(player.UserIDString, permissionUse)) {
player.ChatMessage(lang.GetMessage("NoPermission", this, player.UserIDString));
return;
}
if (!CheckDistance(player) || !CheckOpenBalance(player)) return;
if (enableCooldown && !(cooldownOverrideAdmin && (player.IsAdmin || player.net.connection.authLevel >= cooldownOverrideAuthLevel))) {
DateTime now = DateTime.UtcNow;
DateTime time;
var key = player.UserIDString + "-box";
if (cooldownTimes.TryGetValue(key, out time)) {
if (time > now.AddSeconds(-cooldownBox)) {
player.ChatMessage(string.Format(lang.GetMessage("CooldownTime", this, player.UserIDString), (time - now.AddSeconds(-cooldownBox)).Seconds));
return;
}
}
}
timer.Once(0.2f, () => {
OpenSkinBox(player);
}
);
}
Boolean CheckOpenBalance(BasePlayer player) {
if (!activePointSystem || costBoxOpen <= 0 || (player.IsAdmin && costExcludeAdmins)) return true;
object getMoney = null;
if (activeServerRewards) getMoney = ServerRewards?.Call("CheckPoints", player.userID);
if (activeEconomics) getMoney = Economics?.CallHook("GetPlayerMoney", player.userID);
int playerMoney = 0;
playerMoney = Convert.ToInt32(getMoney);
if (playerMoney < costBoxOpen) {
player.ChatMessage(string.Format(lang.GetMessage("NotEnoughBalanceOpen", this, player.UserIDString), costBoxOpen));
return false;
}
if (activeServerRewards) ServerRewards?.Call("TakePoints", player.userID, costBoxOpen);
if (activeEconomics) Economics?.CallHook("Withdraw", player.userID, Convert.ToDouble(costBoxOpen));
return true;
}
Boolean CheckSkinBalance(BasePlayer player, Item item) {
if (!activePointSystem || (player.IsAdmin && costExcludeAdmins)) return true;
object getMoney = null;
if (activeServerRewards) getMoney = ServerRewards?.Call("CheckPoints", player.userID);
if (activeEconomics) getMoney = Economics?.CallHook("GetPlayerMoney", player.userID);
int playerMoney = 0;
playerMoney = Convert.ToInt32(getMoney);
bool hasBalance = false;
int getCost = 0;
switch (item.info.category.ToString()) {
case "Weapon" : case "Tool" : if (costWeapon <= 0 || playerMoney > costWeapon) hasBalance = true;
getCost = costWeapon;
break;
case "Attire" : if (costPlayerwearable <= 0 || playerMoney > costPlayerwearable) hasBalance = true;
getCost = costPlayerwearable;
break;
case "Items" : case "Construction" : if (costDeployable <= 0 || playerMoney > costDeployable) hasBalance = true;
getCost = costDeployable;
break;
default : hasBalance = true;
break;
}
if (!hasBalance) {
player.ChatMessage(string.Format(lang.GetMessage("NotEnoughBalanceUse", this, player.UserIDString), getCost, item.info.displayName.translated));
return false;
}
return true;
}
Boolean WithdrawBalance(BasePlayer player, Item item) {
if (!activePointSystem || (player.IsAdmin && costExcludeAdmins)) return true;
int getCost = 0;
switch (item.info.category.ToString()) {
case "Weapon" : case "Tool" : getCost = costWeapon;
break;
case "Attire" : getCost = costPlayerwearable;
break;
case "Items" : case "Construction" : getCost = costDeployable;
break;
default : break;
}
bool hadMoney = false;
if (activeServerRewards && (bool)ServerRewards?.Call("TakePoints", player.userID, getCost)) hadMoney = true;
if (activeEconomics && (bool)Economics?.CallHook("Withdraw", player.userID, Convert.ToDouble(getCost))) hadMoney = true;
if (!hadMoney) {
player.ChatMessage(string.Format(lang.GetMessage("NotEnoughBalanceTake", this, player.UserIDString), item.info.displayName.translated));
return false;
}
return true;
}
sealed class SkinBoxHandler : MonoBehaviour {
public bool isCreating;
public bool isBlocked;
public bool isCleaning;
public bool isEmptied;
public int itemId;
public Item item;
public BasePlayer looter;
ItemContainer loot;
public BaseEntity entityOwner;
public ulong skinId;
void Awake() {
isCreating = false;
isBlocked = false;
isCleaning = false;
isEmptied = false;
loot = GetComponent<StorageContainer>().inventory;
entityOwner = loot.entityOwner;
}
public void PlayerStoppedLooting(BasePlayer player) {
skinBox.activeBoxUsers.Remove(player.userID);
if (!isEmptied && item != null) {
isEmptied = true;
player.GiveItem(item);
}
if (!GetComponent<BaseEntity>().IsDestroyed) GetComponent<BaseEntity>().Kill(BaseNetworkable.DestroyMode.None);
if (skinBox.enableCooldown) skinBox.cooldownTimes[player.UserIDString + "-box"] = DateTime.UtcNow;
}
void OnDestroy() {
skinBox.activeBoxUsers.Remove(looter.userID);
if (!isEmptied && item!= null) {
isEmptied = true;
looter.GiveItem(item);
}
looter.EndLooting();
}
}
Boolean CheckDistance(BasePlayer player) {
var playerPos = player.transform.position;
foreach (var id in activeBoxUsers) {
if (Vector3.Distance(playerPos, id.Value) < boxUseDistance) {
player.ChatMessage(lang.GetMessage("ToNearPlayer", this, player.UserIDString));
return false;
}
}
return true;
}
void OpenSkinBox(BasePlayer player) {
var skinBox = GameManager.server.CreateEntity("assets/prefabs/deployable/large wood storage/box.wooden.large.prefab", player.transform.position - new Vector3(UnityEngine.Random.Range(-5f, 5f), 200, UnityEngine.Random.Range(-5f, 5f)));
skinBox.UpdateNetworkGroup();
skinBox.SendNetworkUpdateImmediate();
skinBox.globalBroadcast = true;
(skinBox as BaseNetworkable).limitNetworking = true;
skinBox.Spawn();
skinBox.gameObject.AddComponent<SkinBoxHandler>().looter = player;
var container = skinBox.GetComponent<StorageContainer>();
container.inventory.capacity = 1;
container.SetFlag(BaseEntity.Flags.Open, true, false);
if (QuickSort && hideQuickSort) StartLootingEntity(player.inventory.loot, container);
else player.inventory.loot.StartLootingEntity(container, false);
player.inventory.loot.AddContainer(container.inventory);
player.inventory.loot.SendImmediate();
player.ClientRPCPlayer(null, player, "RPC_OpenLootPanel", container.panelName);
container.DecayTouch();
container.SendNetworkUpdate();
activeBoxUsers[player.userID] = player.transform.position;
}
public void StartLootingEntity(PlayerLoot loot, BaseEntity targetEntity) {
FieldInfo _PositionChecks = typeof(PlayerLoot).GetField("PositionChecks", (BindingFlags.Instance | BindingFlags.NonPublic));
MethodInfo _MarkDirty = typeof(PlayerLoot).GetMethod("MarkDirty", BindingFlags.NonPublic | BindingFlags.Instance);
loot.Clear();
if (!targetEntity) return;
_PositionChecks.SetValue(loot, false);
loot.entitySource = targetEntity;
loot.itemSource = null;
_MarkDirty.Invoke(loot, null);
}
void ClearContainer(ItemContainer container) {
while (container.itemList.Count > 0) {
var item = container.itemList[0];
item.RemoveFromContainer();
item.Remove(0f);
}
}
object CanAcceptItem(ItemContainer container, Item item) {
if (container == null || item == null || container.entityOwner == null || container.entityOwner.GetComponent<SkinBoxHandler>() == null || container.entityOwner != container.e
// ... [Code preview truncated due to length. Full source in attached file] ...