C#:
//Reference: Facepunch.Sqlite
//Reference: UnityEngine.UnityWebRequestModule
//Copyright SurvivalShop.org
using System;
using System.Linq;
using System.Text;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Globalization;
using Oxide.Core;
using Oxide.Game.Rust.Libraries;
using Oxide.Game.Rust.Cui;
using Rust;
using UnityEngine;
using UnityEngine.Networking;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Oxide.Plugins {
[Description("SurvivalShop is a plugin for server monetization")]
[Info("SurvivalShop", "SurvivalShop.org", "2.8.4")]
public class SurvivalShop : RustPlugin {
SurvivalShop Plugin;
private const string PermissionSkipQueue="survivalshop.skipqueue";
Dictionary<string, PlayerData>Players=new Dictionary<string, PlayerData>();
public class PlayerData {
public BasePlayer Player;
public string PlayerId;
public JArray Inventory;
public int InventoryCount;
public DateTime InventoryTime;
public int InventoryPage;
public int InventoryTotalPages;
public bool InventoryNoTimer;
public bool InventoryShown;
public bool InventoryShowTip;
public int InventoryShowTipCounter;
public bool InventoryMeshNotExists;
public DateTime GiveAllCooldown;
public bool GiveAllScheduled;
public Lang Language;
public bool SafeMode;
SurvivalShop SurvivalShop;
public Lang Locale {
get {
return SurvivalShop.Locale(Player);
}
}
public PlayerData(SurvivalShop shop, BasePlayer player) {
SurvivalShop=shop;
Player=player;
PlayerId=player.UserIDString;
if(PlayerId==null)PlayerId="*anonymous";
}
}
new PlayerData Player(BasePlayer player) {
PlayerData data;
if(player==null)return null;
if(!Players.TryGetValue(player.UserIDString, out data)) {
data=new PlayerData(this, player);
Players[player.UserIDString]=data;
}
return data;
}
public delegate void LockCallback();
static void ThreadLock(string state, LockCallback callback, ref bool lock_param, object lock_ref) {
ThreadLockState=state;
if(lock_param)ThreadLockCounter++;
lock(lock_ref) {
try {
lock_param=true;
callback();
}
finally {
lock_param=false;
ThreadLockState=null;
}
}
}
static string ThreadLockState;
static long ThreadLockCounter=0;
public string SiteId;
public string ApiKey;
public bool DebugEnabled;
public bool AutofuelEnabled;
public bool IgnoreStack;
public bool NoWelcomeTitle;
public string BrandName="SurvivalShop";
public string BucketIcon="assets/icons/loot.png";
public string BucketIconPos="top-left";
public bool Auto;
public bool GiveAllButton;
public bool ServerInitialized;
public Dictionary<string, List<ApiRequest>>ApiRequests;
public bool ApiRequestsLock;
public Dictionary<string, JObject>PowerupActivations;
public bool PowerupActivationsLock;
public List<ApiResponse>ApiResponses;
public bool ApiResponsesLock;
public Queue<DeliveryRequest>DeliveryQueue;
public bool DeliveryQueueLock;
public int DeliveryActiveRequests;
public DateTime DeliveryLastUse;
public bool ShopRegistered;
public string ShopServerId;
public string ShopLink;
public bool ShopServerPremium;
public string ShopHello;
public DateTime RegisterLastError;
public string RegisterLastErrorString;
public DateTime RegisterLastSuccess;
DateTime NextRegister;
DateTime NextTimeoutCheck;
public class ApiRequest {
public SurvivalShop Plugin;
public string MethodName;
public PlayerData Player;
public UnityWebRequest Request;
public DateTime StartTime;
public DateTime TimeoutTime;
public Coroutine Routine;
public static string ImageUrl="https://survivalshop.org";
public static string ApiUrl="https://api.survivalshop.org";
public Dictionary<string, object>Data;
public ApiFunc Completed;
public string RequestFor;
public bool Canceled;
public class BypassCertificate : CertificateHandler {
protected override bool ValidateCertificate(byte[]certificateData) {
return true;
}
}
System.Collections.IEnumerator ExecWait(ApiErrorHandler failed=null) {
yield return Request.SendWebRequest();
try {
ThreadLock("Api requests", ()=> {
List<ApiRequest>requests;
if(Plugin.ApiRequests.TryGetValue(RequestFor, out requests))requests.Remove(this);
}
, ref Plugin.ApiRequestsLock, Plugin.ApiRequests);
JObject response_data=null;
JToken error_code=null;
var error=Request.error;
var text=Request.downloadHandler.text;
if(error==null&&(text.Length==0||text.Length>1024*1024))error="Response is null or too large";
if(error==null) {
var data=Request.downloadHandler.text+"";
try {
response_data=JObject.Parse(Request.downloadHandler.text);
}
catch(Exception e) {
error="Failed to parse response: "+e.Message+". Data was (first 50 bytes): '"+(data.Length>50?data.Substring(0, 50) : data)+"'";
}
}
if(error==null&&response_data==null)error="Response data is null";
if(error==null&&response_data.TryGetValue("error_code", out error_code))error=response_data["error_msg"].ToString();
if(!string.IsNullOrEmpty(error)) {
try {
var handled=false;
if(failed!=null)handled=failed.Invoke(this, error);
if(Plugin.DebugEnabled||!handled)Plugin.Error("Api request {0} failed for {1}: {2}", MethodName, RequestFor, error);
}
catch(Exception e) {
Plugin.Error(e, "ApiError");
}
}
else {
Plugin.Debug("Finished request {0} for {1}: {2}", MethodName, RequestFor, Request.downloadHandler.text, Request.error);
if(!Canceled)ThreadLock("Api responses", ()=> {
Plugin.ApiResponses.Add(new ApiResponse(this, response_data, Completed, text));
}
, ref Plugin.ApiRequestsLock, Plugin.ApiResponses);
}
Request=null;
}
catch(Exception e) {
Plugin.Error("Failed to run request {0} for {1}: {2}", MethodName, RequestFor, e.Message);
}
}
public void Execute(ApiErrorHandler failed=null) {
Plugin.Debug("Started request {0} for {1}", MethodName, RequestFor);
ThreadLock("Api requests", ()=> {
List<ApiRequest>requests;
if(Plugin.ApiRequests.TryGetValue(RequestFor, out requests))requests.Add(this);
else {
requests=new List<ApiRequest>();
requests.Add(this);
Plugin.ApiRequests.Add(RequestFor, requests);
}
}
, ref Plugin.ApiRequestsLock, Plugin.ApiRequests);
var salt="salt";
var data_json=JsonConvert.SerializeObject(Data, Formatting.None);
var bytes=new SHA256CryptoServiceProvider().ComputeHash(Encoding.UTF8.GetBytes(data_json+Plugin.ApiKey+salt));
var hex=new StringBuilder(bytes.Length*2);
for(int i=0;i<bytes.Length;i++)hex.AppendFormat("{0:x2}", bytes[i]);
Data["__sign"]=hex.ToString()+":"+Plugin.SiteId+":"+salt;
var serialized_data=JsonConvert.SerializeObject(Data, Formatting.None);
Plugin.Debug("Api request data {0}", serialized_data);
Request=new UnityWebRequest(ApiUrl+"/"+MethodName, "POST");
Request.certificateHandler=new BypassCertificate();
Request.uploadHandler=new UploadHandlerRaw(Encoding.UTF8.GetBytes(serialized_data));
Request.downloadHandler=new DownloadHandlerBuffer();
Request.SetRequestHeader("Content-Type", "application/json");
Routine=Rust.Global.Runner.StartCoroutine(ExecWait(failed));
}
public void Cancel() {
Canceled=true;
Plugin.Debug("Cancelling request {0} for {1}", MethodName, RequestFor);
if(Routine!=null)Rust.Global.Runner.StopCoroutine(Routine);
Routine=null;
}
public ApiRequest(SurvivalShop shop, PlayerData player, string method_name, Dictionary<string, object>data, ApiFunc completed) {
Plugin=shop;
Player=player;
RequestFor=Player==null?"*" : Player.PlayerId;
StartTime=DateTime.Now;
TimeoutTime=StartTime.AddSeconds(30);
MethodName=method_name;
Data=data;
Completed=completed;
}
}
public class ApiResponse {
public ApiRequest Request;
public JObject Data;
public ApiFunc Completed;
public string ResponseString;
public ApiResponse(ApiRequest request, JObject data, ApiFunc completed, string response_string) {
Request=request;
Data=data;
Completed=completed;
ResponseString=response_string;
}
}
public delegate void ApiFunc(ApiResponse result);
public delegate bool ApiErrorHandler(ApiRequest request, string error);
void ApiExec(PlayerData player, string method_name, Dictionary<string, object>data, ApiFunc completed, ApiErrorHandler failed=null) {
new ApiRequest(this, player, method_name, data, completed).Execute(failed);
}
bool ApiFailed(PlayerData player, ApiRequest request, string error, bool for_draw_gui, bool gui_no_timer=false) {
if(player==null)return false;
if(!string.IsNullOrEmpty(error)&&(error.Contains("Mesh not exist", System.Globalization.CompareOptions.OrdinalIgnoreCase)||error.Contains("Клиент не найден", System.Globalization.CompareOptions.OrdinalIgnoreCase))) {
if(!for_draw_gui)ChatNotify(player, player.Locale.MeshNotExists);
else {
player.Inventory=new JArray();
player.InventoryCount=0;
player.InventoryPage=0;
player.InventoryTotalPages=1;
player.InventoryNoTimer=gui_no_timer;
player.InventoryMeshNotExists=true;
InvDraw(player, true);
}
return true;
}
ChatNotify(player, player.Locale.ApiRequestError);
return false;
}
void ApiInit() {
ApiRequests=new Dictionary<string, List<ApiRequest>>();
ApiRequestsLock=false;
ApiResponses=new List<ApiResponse>();
ApiResponsesLock=false;
PowerupActivations=new Dictionary<string, JObject>();
PowerupActivationsLock=false;
DeliveryQueue=new Queue<DeliveryRequest>();
DeliveryActiveRequests=0;
}
void ApiFrame() {
if(DateTime.Now>NextRegister&&!string.IsNullOrEmpty(SiteId)&&!string.IsNullOrEmpty(ApiKey)) {
var was_registered=ShopRegistered;
ApiExec(null, "servers.register2", new Dictionary<string, object>() {
{
"siteId", SiteId
}
, {
"serverData", new {
game="RUST", name=ConVar.Server.hostname, port=ConVar.Server.queryport, online=BasePlayer.activePlayerList.Count, maxplayers=ConVar.Server.maxplayers, pluginName="SurvivalShop", pluginVersion="2.8.4"
}
}
}
, (r)=> {
var response=r.Data["response"];
ShopRegistered=true;
ShopServerId=response["id"].ToString();
ShopServerPremium=(bool)response["premium"];
ShopLink=(string)response["shopUrl"];
ShopHello=response["hello"].ToString();
if(!was_registered)Plugin.Notify(Locale().ServerRegister, SiteId, ShopServerId);
if(!was_registered)InvStartAll();
if(response["powerups"]!=null)Plugin.PowerupsAcquire((JArray)response["powerups"]);
RegisterLastSuccess=DateTime.Now;
}
, (r, err)=> {
RegisterLastErrorString=err;
RegisterLastError=DateTime.Now;
return true;
}
);
NextRegister=DateTime.Now.AddMinutes(1);
}
if(DateTime.Now>NextTimeoutCheck) {
var now=DateTime.Now;
ThreadLock("Api requests", ()=> {
foreach(var kv in ApiRequests)for(int i=0;i<kv.Value.Count;i++) {
if(now>kv.Value[i].TimeoutTime) {
kv.Value[i].Cancel();
kv.Value.Remove(kv.Value[i]);
}
}
}
, ref Plugin.ApiRequestsLock, Plugin.ApiRequests);
NextTimeoutCheck=DateTime.Now.AddMinutes(2);
}
}
void ApiTick() {
ThreadLock("Api responses", ()=> {
if(ApiResponses.Count>0) {
for(int i=0;i<ApiResponses.Count;i++) {
try {
ApiResponses[i].Completed(ApiResponses[i]);
}
catch(Exception e) {
Error(e, "ApiResponse ("+ApiResponses[i].Request.MethodName+")"+(ApiResponses[i].Request.Player!=null?" for "+ApiResponses[i].Request.Player.PlayerId : ""));
}
}
ApiResponses.Clear();
}
}
, ref Plugin.ApiResponsesLock, Plugin.ApiResponses);
}
void ApiUnload() {
ApiRequests.Clear();
}
string SafeStringFormat(string format, object[]args=null) {
if(args==null)return format;
for(int i=0;i<args.Length;i++)format=format.Replace("{"+i+"}", args[i]==null?"null" : args[i].ToString());
return format;
}
void Notify(string format, params object[]args) {
var msg=SafeStringFormat(format, args);
LogToFile("log", msg, Plugin);
var locale=Locale();
if(locale!=null&&locale.Locale!="EN")msg=Locale().Translit(msg);
Puts(msg);
}
void Debug(string format, params object[]args) {
if(!DebugEnabled)return;
var msg=SafeStringFormat(format, args);
LogToFile("log", "DEBUG "+msg, Plugin);
var locale=Locale();
if(locale!=null&&locale.Locale!="EN")msg=Locale().Translit(msg);
Puts("Debug "+msg);
}
void Error(string format, params object[]args) {
var msg=SafeStringFormat(format, args);
LogToFile("log", "ERROR "+msg, Plugin);
LogToFile("error", "ERROR "+msg, Plugin);
var locale=Locale();
if(locale!=null&&locale.Locale!="EN")msg=Locale().Translit(msg);
PrintError(msg);
}
void Error(Exception e, string function_name, string details=null) {
var msg="In "+function_name+": "+e.Message+", callstack: "+e.StackTrace+(string.IsNullOrEmpty(details)?"." : ", details: "+details+".");
if(e.InnerException!=null)msg=msg+"Inner in "+function_name+": "+e.InnerException.Message+", callstack: "+e.InnerException.StackTrace+".";
LogToFile("log", "ERROR "+msg, Plugin);
LogToFile("error", "ERROR "+msg, Plugin);
var locale=Locale();
if(locale!=null&&locale.Locale!="EN")msg=Locale().Translit(msg);
PrintError(msg);
}
void Warning(string format, params object[]args) {
var msg=SafeStringFormat(format, args);
LogToFile("log", "WARNING "+msg, Plugin);
var locale=Locale();
if(locale!=null&&locale.Locale!="EN")msg=Locale().Translit(msg);
PrintWarning(msg);
}
void ChatNotify(BasePlayer player, string message, params object[]args) {
if(Auto)return;
player.ChatMessage("Shop: "+SafeStringFormat(message, args));
}
void ChatNotify(PlayerData player, string message, params object[]args) {
if(Auto)return;
player.Player.ChatMessage(player.Locale.Shop+": "+SafeStringFormat(message, args));
}
Lang LocaleEn;
Lang LocaleRu;
Lang LocaleCurrent;
public class Lang {
public virtual string Locale=>"EN";
public virtual string Shop=>"Shop";
public virtual string ConfigFailedToLoad=>"Failed to load config: {0}";
public virtual string InventoryFailedToShow=>"Failed to show inventory: {0} ({1})";
public virtual string InventoryFailedToTake=>"Failed to take inventory: {0} ({1})";
public virtual string InventoryFailedToTakeAll=>"Failed to take all inventory: {0} ({1})";
public virtual string Loading=>"Loading inventory data...";
public virtual string Empty=>"Empty...";
public virtual string EmptyAuthorize=>"Пусто... Sign in to check your bonuses, or gain more!";
public virtual string MySurvivalShopInventory=>"My SurvivalShop Inventory";
public virtual string Paging=>"page {0} of {1}";
public virtual string Tip=>"Tip:";
public virtual string QuickBindHelp=>"How to set up quick access: hit F1 (console), then type:";
public virtual string QuickBindHelp2=>"bind f2 chat.say /shopinvt";
public virtual string ShopNotRegistered=>"Sorry, shop is not registered";
public virtual string ShopUsage=>"Usage {0} <Page number>";
public virtual string ShopGiveUsage=>"Usage {0} <Index> [Quantity]";
public virtual string NoSuchPosition=>"Sorry, no such inventory position";
public virtual string PlayerNotFound=>"Sorry, player not found";
public virtual string SlotNotFound=>"Sorry, slot not found";
public virtual string MeshNotExists=>"Sorry, store account not found. Please log in to this server's store site and try again.";
public virtual string ApiRequestError=>"Sorry, request error occured, please try again later";
public virtual string RuntimeError=>"Sorry, runtime error occured, please try again later";
public virtual string FailedToUseInventory=>"Sorry, failed to use inventory";
public virtual string FailedToUseSlot=>"sorry, failed to use slot";
public virtual string Activate_0_1=>"Activate: {0} {1}";
public virtual string Delivered_0_1=>"Delivered: {0} {1}";
public virtual string DeliveredBackpack_0_1=>"Delivered: {0} {1} (BACKPACK)";
public virtual string Unlocked_0_1=>"Blueprint unlocked: {0} {1}";
public virtual string CountNotEnough=>"Sorry, not enough items in inventory";
public virtual string Purshase_0_for_1_=>"purshase '{0}' (x{2}) for {1} - ";
public virtual string YourCharacterMustBeConcious=>"Your character must be conscious";
public virtual string CannotActivate_0_1=>"Sorry, failed to activate {0} - {1}";
public virtual string CannotDeliver_0_1=>"Sorry, failed to deliver {0} - {1}";
public virtual string CannotUnlock_0_1=>"Sorry, failed to unlock {0} - {1}";
public virtual string ActivationError=>"activation error";
public virtual string DeliveryError=>"delivery error";
public virtual string UnlockError=>"unlock error";
public virtual string RequireMoreSlots=>"need to free up {0} inventory slots";
public virtual string ItemNotFound=>"item {0} not found";
public virtual string LocaleSetUp=>"Switched language to EN";
public virtual string LocaleFailed=>"Sorry, failed to switch language: {0}";
public virtual string SafeModeIsOn=>"Safe inventory mode is ON";
public virtual string SafeModeIsOff=>"Safe inventory mode is ON";
public virtual string SafeModeFailed=>"Sorry, failed to switch safe inventory mode";
public virtual string SetupOk=>"Shop keys written succesfully! Type survivalshop.status for detailed state information";
public virtual string Status01=>"Registered: {0} (siteId {1}), init {2}, next reg {3}";
public virtual string Status02=>"Options: debug {0}, autofuel {1}, auto {2}, api {3}, giveall {4}, ignorestack {5}";
public virtual string Status03=>"Server ID: {0}, lock '{1}' (counter {2})";
public virtual string Status04=>"Server Hello: {0}";
public virtual string Status05=>"Locale: {0}";
public virtual string Status06=>"Players: {0}";
public virtual string Status07=>"Active requests: {0}, delivery {1} {2}";
public virtual string Status08=>"Last register: {0}, last error: {1}: {2}";
public virtual string ShopSetupUsage=>"Usage {0} <SiteId> <SiteKey> [Locale]";
public virtual string ServerRegister=>"Shop registered with site {0}, server Id {1}";
public virtual string AcquiredPowerups=>"Acquired powerups: {0}";
public virtual string PowerupDelivered_for_0_1=>"Powerup delivered for {0}: {1}";
public virtual string TitleHelp=>"Take item: /give <position> [count] or /giveall [position]";
public virtual string TitleHelp2=>"Switch page: /shop <page>";
public virtual string TitleHelp3=>"Switch language: /en, /ru";
public virtual string ShopHello1=>"Welcome!\nSign in to check your bonuses, or gain more!\nThen use /shop to view your inventory\nShop site: {0}";
public virtual string ShopHello2=>"Welcome to {0}!\nSign in to check your bonuses, or gain more!\nThen use /shop to view your inventory\nShop site: {1}";
public virtual string Close=>"Close";
public virtual string BuildingBlockedHere=>"Sorry, failed to deliver: construction here is blocked";
public virtual string OptionIsNowOn=>"{0} is now ON";
public virtual string OptionIsNowOff=>"{0} is now OFF";
public virtual string OptionIsNow=>"{0} is now {1}";
public virtual string PluginNeedsRestart=>"Plugin needs to be restarted";
public virtual string InventoryRestarted=>"Inventory subsystem were restarted";
public virtual string OptionUsage=>"Usage {0} 0/1";
public virtual string TakeAll=>"Take All";
public virtual string Translit(string s) {
return s;
}
}
public class LangRu : Lang {
public override string Locale=>"RU";
public override string Shop=>"Магазин";
public override string ConfigFailedToLoad=>"Ошибка загрузки конфигурации: {0}";
public override string InventoryFailedToShow=>"Ошибка показа инвентаря: {0} ({1})";
public override string InventoryFailedToTake=>"Ошибка выдачи инвентаря: {0} ({1})";
public override string InventoryFailedToTakeAll=>"Ошибка выдачи всего инвентаря: {0} ({1})";
public override string Loading=>"Загружаем данные инвентаря...";
public override string Empty=>"Пусто...";
public override string EmptyAuthorize=>"Пусто... Авторизуйтесь на сайте, чтобы получить бонусы!";
public override string MySurvivalShopInventory=>"Мой инвентарь SurvivalShop";
public override string Paging=>"стр. {0} из {1}";
public override string Tip=>"Совет:";
public override string QuickBindHelp=>"Доступ с клавиши: нажать F1 (консоль), затем набрать:";
public override string ShopNotRegistered=>"Извините, магазин не зарегистрирован";
public override string ShopUsage=>"Формат {0} <Номер страницы>";
public override string ShopGiveUsage=>"Формат {0} <Индекс> [Количество] или /d <Индекс> [Количество]";
public override string NoSuchPosition=>"Извините, нет такой позиции в инвентаре";
public override string PlayerNotFound=>"Извините, игрок не найден";
public override string SlotNotFound=>"Извините, cлот не найден";
public override string MeshNotExists=>"Извините, счет в магазине не найден. Пожалуйста выполните вход на сайте магазина этого сервера и попробуйте снова.";
public override string ApiRequestError=>"Извините, произошла ошибка запроса, попробуйте еще раз позднее";
public override string RuntimeError=>"Извините, произошла ошибка выполнения, попробуйте еще раз позднее";
public override string FailedToUseInventory=>"Извините, не удалось использовать инвентарь";
public override string FailedToUseSlot=>"Извините, не удалось использовать слот";
public override string Activate_0_1=>"Активация: {0} {1}";
public override string Delivered_0_1=>"Выдано: {0} {1}";
public override string DeliveredBackpack_0_1=>"Выдано: {0} {1} (РЮКЗАК)";
public override string Unlocked_0_1=>"Чертеж разблокирован: {0} {1}";
public override string CountNotEnough=>"Извините, недостаточно предметов в инвентаре";
public override string Purshase_0_for_1_=>"покупка '{0}' (x{2}) для {1} - ";
public override string YourCharacterMustBeConcious=>"Ваш персонаж должен быть в сознании";
public override string CannotActivate_0_1=>"Извините, не удалось активировать {0} - {1}";
public override string CannotDeliver_0_1=>"Извините, не удалось выдать {0} - {1}";
public override string CannotUnlock_0_1=>"Извините, не удалось разблокировать {0} - {1}";
public override string ActivationError=>"ошибка при активации";
public override string DeliveryError=>"ошибка при выдаче";
public override string UnlockError=>"ошибка при разблокировке";
public override string RequireMoreSlots=>"необходимо освободить {0} слотов в инвентаре";
public override string ItemNotFound=>"предмет {0} не найден";
public override string LocaleSetUp=>"Установлен язык RU";
public override string LocaleFailed=>"Извините, не удалось установить язык: {0}";
public override string SafeModeIsOn=>"Режим безопасного инвентаря: ВКЛ";
public override string SafeModeIsOff=>"Режим безопасного инвентаря: ВЫКЛ";
public override string SafeModeFailed=>"Извините, не удалось установить режим безопасного инвентаря";
public override string SetupOk=>"Ключи прописаны успешно! Введите survivalshop.status для получения подробной информации о состоянии";
public override string Status01=>"Зарегистрирован: {0} (siteId {1}), init: {2}, next reg {3}";
public override string Status02=>"Опции: debug {0}, autofuel {1}, auto {2}, api {3}, giveall {4}, ignorestack {5}";
public override string Status03=>"ID сервера: {0} lock '{1}' (счетчик {2})";
public override string Status04=>"Приветствие сервера: {0}";
public override string Status05=>"Локализация: {0}";
public override string Status06=>"Игроки: {0}";
public override string Status07=>"Активные запросы: {0}, доставка {1} {2}";
public override string Status08=>"Регистрация: {0}, посл. ошибка: {1}: {2}";
public override string ShopSetupUsage=>"Формат {0} <SiteId> <SiteKey> [Locale]";
public override string ServerRegister=>"Магазин зарегистрирован с ID сайта {0}, ID сервера {1}";
public override string AcquiredPowerups=>"Получены бонусные товары: {0}";
public override string PowerupDelivered_for_0_1=>"Выдан бонус для {0}: {1}";
public override string TitleHelp=>"Получить предмет: /give <позиция> [кол-во] или /giveall [позиция] или /в <позиция> [кол-во] или /вв [позиция]";
public override string TitleHelp2=>"Переключить страницу: /shop <page> или /м <страница>";
public override string TitleHelp3=>"Переключить язык: /en, /ru";
public override string ShopHello1=>"Добро пожаловать!\nАвторизуйтесь на сайте, чтобы получить бонусы!\nНаберите /shop, чтобы просмотреть инвентарь\nСайт магазина: {0}";
public override string ShopHello2=>"Привет от {0}!\nАвторизуйтесь на сайте, чтобы получить бонусы!\nНаберите /shop, чтобы просмотреть инвентарь\nСайт магазина: {1}";
public override string Close=>"Закрыть";
public override string BuildingBlockedHere=>"Извините, не удалось доставить: строительство здесь заблокировано";
public override string OptionIsNowOn=>"{0} теперь ВКЛ";
public override string OptionIsNowOff=>"{0} теперь ВЫКЛ";
public override string OptionIsNow=>"{0} теперь {1}";
public override string PluginNeedsRestart=>"Требуется перезагрузка плагина";
public override string InventoryRestarted=>"Подсистема инвентарей перезапускается";
public override string OptionUsage=>"Формат {0} 0/1";
public override string TakeAll=>"Забрать Все";
static Dictionary<char, string>TranslitChars=new Dictionary<char, string>() {
{
'Є', "EH"
}
, {
'І', "I"
}
, {
'і', "i"
}
, {
'є', "eh"
}
, {
'А', "A"
}
, {
'Б', "B"
}
, {
'В', "V"
}
, {
'Г', "G"
}
, {
'Д', "D"
}
, {
'Е', "E"
}
, {
'Ё', "JO"
}
, {
'Ж', "ZH"
}
, {
'З', "Z"
}
, {
'И', "I"
}
, {
'Й', "JJ"
}
, {
'К', "K"
}
, {
'Л', "L"
}
, {
'М', "M"
}
, {
'Н', "N"
}
, {
'О', "O"
}
, {
'П', "P"
}
, {
'Р', "R"
}
, {
'С', "S"
}
, {
'Т', "T"
}
, {
'У', "U"
}
, {
'Ф', "F"
}
, {
'Х', "KH"
}
, {
'Ц', "C"
}
, {
'Ч', "CH"
}
, {
'Ш', "SH"
}
, {
'Щ', "SHH"
}
, {
'Ъ', "'"
}
, {
'Ы', "Y"
}
, {
'Ь', ""
}
, {
'Э', "EH"
}
, {
'Ю', "YU"
}
, {
'Я', "YA"
}
, {
'а', "a"
}
, {
'б', "b"
}
, {
'в', "v"
}
, {
'г', "g"
}
, {
'д', "d"
}
, {
'е', "e"
}
, {
'ё', "jo"
}
, {
'ж', "zh"
}
, {
'з', "z"
}
, {
'и', "i"
}
, {
'й', "jj"
}
, {
'к', "k"
}
, {
'л', "l"
}
, {
'м', "m"
}
, {
'н', "n"
}
, {
'о', "o"
}
, {
'п', "p"
}
, {
'р', "r"
}
, {
'с', "s"
}
, {
'т', "t"
}
, {
'у', "u"
}
, {
'ф', "f"
}
, {
'х', "kh"
}
, {
'ц', "c"
}
, {
'ч', "ch"
}
, {
'ш', "sh"
}
, {
'щ', "shh"
}
, {
'ъ', ""
}
, {
'ы', "y"
}
, {
'ь', ""
}
, {
'э', "eh"
}
, {
'ю', "yu"
}
, {
'я', "ya"
}
, {
'«', ""
}
, {
'»', ""
}
, {
'—', "_"
}
}
;
public override string Translit(string s) {
var sb=new StringBuilder();
if(!string.IsNullOrEmpty(s))for(int i=0;i<s.Length;i++)if(TranslitChars.TryGetValue(s[i], out var t))sb.Append(t);
else sb.Append(s[i]);
return sb.ToString();
}
}
void LocaleInit() {
LocaleEn=new Lang();
LocaleRu=new LangRu();
LocaleCurrent=LocaleEn;
}
Lang Locale() {
return LocaleCurrent;
}
Lang Locale(PlayerData player) {
if(player.Language==null)return Locale();
return player.Language;
}
Lang Locale(BasePlayer player) {
return Locale(Player(player));
}
void LocaleSet(PlayerData player, Lang locale) {
player.Language=locale;
ChatNotify(player, Locale(player).LocaleSetUp);
}
void LocaleUnload() {
}
class Configuration {
[JsonProperty("siteId")]
public string SiteId;
[JsonProperty("siteKey")]
public string SiteKey;
[JsonProperty("locale")]
public string Locale;
[JsonProperty("debug")]
public bool Debug=false;
[JsonProperty("auto")]
public bool Auto=false;
[JsonProperty("autofuel")]
public bool Autofuel=true;
[JsonProperty("ignoreStack")]
public bool IgnoreStack=false;
[JsonProperty("noWelcomeTitle")]
public bool NoWelcomeTitle=false;
[JsonProperty("brandName")]
public string BrandName="SurvivalShop";
[JsonProperty("bucketIcon")]
public string BucketIcon="assets/icons/loot.png";
[JsonProperty("bucketIconPos")]
public string BucketIconPos="top-left";
[JsonProperty("giveAllButton")]
public bool GiveAllButton=true;
internal void Set(string name, object value) {
if(name=="siteId")SiteId=(string)value;
if(name=="siteKey")SiteKey=(string)value;
if(name=="locale")Locale=(string)value;
if(name=="debug")Debug=(bool)value;
if(name=="auto")Auto=(bool)value;
if(name=="autofuel")Autofuel=(bool)value;
if(name=="ignoreStack")IgnoreStack=(bool)value;
if(name=="noWelcomeTitle")NoWelcomeTitle=(bool)value;
if(name=="brandName")BrandName=(string)value;
if(name=="bucketIcon")BucketIcon=(string)value;
if(name=="bucketIconPos")BucketIconPos=(string)value;
if(name=="giveAllButton")GiveAllButton=(bool)value;
}
}
protected override void LoadConfig() {
base.LoadConfig();
var config=new Configuration();
try {
config=Config.ReadObject<Configuration>();
}
catch(Exception e) {
Error(e, "LoadConfig");
}
SiteId=config.SiteId;
ApiKey=config.SiteKey;
DebugEnabled=config.Debug;
AutofuelEnabled=config.Autofuel;
IgnoreStack=config.IgnoreStack;
NoWelcomeTitle=config.NoWelcomeTitle;
BrandName=config.BrandName;
BucketIcon=config.BucketIcon;
BucketIconPos=config.BucketIconPos;
GiveAllButton=config.GiveAllButton;
LocaleCurrent=LocaleEn;
Auto=config.Auto;
var locale=config.Locale;
if(locale!=null)switch(locale.ToLower()) {
case"en" : LocaleCurrent=LocaleEn;
break;
case"ru" : LocaleCurrent=LocaleRu;
break;
}
Debug("SITE_ID: {0}", SiteId);
Debug("Auto: {0}", Auto);
NextRegister=DateTime.MinValue;
}
protected void SetupConfig(string site_id, string site_key, string locale) {
var config=new Configuration();
try {
config=Config.ReadObject<Configuration>();
}
catch(Exception e) {
Error(e, "LoadConfig");
}
config.SiteId=site_id;
config.SiteKey=site_key;
if(locale!=null)config.Locale=locale;
Config.WriteObject<Configuration>(config);
LoadConfig();
}
protected bool SetupBool(string option, string value) {
var config=new Configuration();
try {
config=Config.ReadObject<Configuration>();
}
catch(Exception e) {
Error(e, "LoadConfig");
}
int v;
bool ov;
if(int.TryParse(value, out v))ov=v==0?false : true;
else if(value=="1"||value=="on"||value=="true"||value=="yes")ov=true;
else ov=true;
config.Set(option, ov);
Config.WriteObject<Configuration>(config);
LoadConfig();
return ov;
}
protected string SetupString(string option, string value) {
var config=new Configuration();
try {
config=Config.ReadObject<Configuration>();
}
catch(Exception e) {
Error(e, "LoadConfig");
}
config.Set(option, value);
Config.WriteObject<Configuration>(config);
LoadConfig();
return value;
}
string InvName="SurvivalshopInventoryCUI";
int InventoryItemsPerPage=10;
DateTime NextTimerUpdate;
public class ItemAffixes {
SurvivalShop Plugin;
public bool IsBlueprint;
public bool IsBackpack;
public bool IsFueled;
public bool IsSuperStack;
public Modifier SlotsRequired;
static string[]BlueprintAffixes=new string[] {
"чертеж", "чертёж", "blueprint", "[ч]", "[b]"
}
;
static string[]BackpackAffixes=new string[] {
"[backpack]", "[рюкзак]"
}
;
static string[]FueledAffixes=new string[] {
"[fueled]", "[заправлено]"
}
;
static string[]SuperStackAffixes=new string[] {
"[superstack]", "[суперстак]", "[++]"
}
;
public int CheckedSlotsCount;
public class Modifier {
public double Min;
public double Max;
public double Value {
get {
var rnd=new System.Random();
return Min+(Max-Min)*rnd.NextDouble();
}
}
}
static NumberFormatInfo FloatDotNumber=new NumberFormatInfo() {
NumberDecimalSeparator=".", NumberGroupSeparator=" "
}
;
Modifier Search(string title, string mod_prefix1, string mod_prefix2, string suffix="]") {
var prefix=mod_prefix1;
var index=title.IndexOf(prefix);
if(index<0) {
prefix=mod_prefix2;
index=title.IndexOf(prefix);
if(index<0)return null;
}
var index_end=title.IndexOf(suffix, index+prefix.Length);
if(index_end<0)return null;
try {
var mod=new Modifier();
var mod_string=title.Substring(index+prefix.Length, index_end-(index+prefix.Length));
var parts=mod_string.Split(new string[] {
".."
}
, StringSplitOptions.None);
if(parts.Length==2) {
mod.Min=Convert.ToDouble(parts[0], FloatDotNumber);
mod.Max=Convert.ToDouble(parts[1], FloatDotNumber);
if(mod.Min>mod.Max) {
var m=mod.Min;
mod.Min=mod.Max;
mod.Max=m;
}
}
else {
mod.Min=Convert.ToDouble(mod_string, FloatDotNumber);
mod.Max=mod.Min;
}
Plugin.Debug("SearchModifier({0}{1}) in '{2}' - parsed {3}..{4}", prefix, suffix, title, mod.Min, mod.Max);
return mod;
}
catch(Exception e) {
Plugin.Debug("SearchModifier({0}{1}) in '{2}' - exception {3}", prefix, suffix, title, e.Message);
return null;
}
}
internal ItemAffixes(SurvivalShop plugin, string title) {
Plugin=plugin;
for(int i=0;i<BlueprintAffixes.Length;i++)if(title.Contains(BlueprintAffixes[i], System.Globalization.CompareOptions.OrdinalIgnoreCase)) {
IsBlueprint=true;
break;
}
for(int i=0;i<BackpackAffixes.Length;i++)if(title.Contains(BackpackAffixes[i], System.Globalization.CompareOptions.OrdinalIgnoreCase)) {
IsBackpack=true;
break;
}
for(int i=0;i<FueledAffixes.Length;i++)if(title.Contains(FueledAffixes[i], System.Globalization.CompareOptions.OrdinalIgnoreCase)) {
IsFueled=true;
break;
}
IsSuperStack=Plugin.IgnoreStack;
for(int i=0;i<SuperStackAffixes.Length;i++)if(title.Contains(SuperStackAffixes[i], System.Globalization.CompareOptions.OrdinalIgnoreCase)) {
IsSuperStack=true;
break;
}
SlotsRequired=Search(title, "[s+", "[с+", "]");
}
}
void InvInit() {
if(Auto)for(var i=0;i<BasePlayer.activePlayerList.Count;i++)InvDeliverAll(Player(BasePlayer.activePlayerList[i]), true);
}
void InvStart(BasePlayer player, bool welcome=true) {
if(Auto)return;
if(!NoWelcomeTitle&&welcome) {
if(string.IsNullOrEmpty(BrandName))ChatNotify(player, Player(player).Locale.ShopHello1, ShopLink);
else ChatNotify(player, Player(player).Locale.ShopHello2, BrandName, ShopLink);
}
InvLinkDraw(player);
}
void InvStartAll() {
for(var i=0;i<BasePlayer.activePlayerList.Count;i++)InvStart(BasePlayer.activeP
// ... [Code preview truncated due to length. Full source in attached file] ...