// TODO: dataファイルに時間を取り日付が変わったタイミングでカウント0
#region 更新履歴
// 1.2.0
// * コンフィグ変更
// * コンフィグ変更後に変更した値を読み込めない問題の修正
//
#endregion
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Core.Plugins;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("DeathPenalty", "babu77", "1.2.0")]
[Description("Dead players will be deprived of their property.")]
public class DeathPenalty : RustPlugin
{
[PluginReference]
private Plugin Economics, ServerRewards;//, ZoneManeger;
#region Variables
const string pName = "[DeathPenalty]:";
const string perm_use = "deathpenalty.use";
const string perm_admin = "deathpenalty.admin";
private DynamicConfigFile DATA_PLAYER_LOST_CR;//コインとRPのロスト分集計用データファイル
private Dictionary LOST_DATA;
private Dictionary DATA_CONFIG;
//List loadedTime;
#endregion
#region Classes
private class PlayerDataCR
{
public double Coins { get; set; }
public int RP { get; set; }
}
#endregion
#region Configurations
private bool Changed;
//
private double MinRateEconomics;
private double MaxRateEconomics;
private double MinRateRP;
private double MaxRateRP;
private string ReceiverSteamID;
private bool ReceiverFlag;
private bool UseEconomics;
private bool UseServerRewards;
private void LoadVariables()
{
MinRateEconomics = Convert.ToDouble(GetConfig("Config", "Min_Rate_Economics(0.00 - 1.00)", 0.01));
MaxRateEconomics = Convert.ToDouble(GetConfig("Config", "Max_Rate_Economics(0.00 - 1.00)", 0.1));
MinRateRP = Convert.ToDouble(GetConfig("Config", "Min_Rate_RP(0.00 - 1.00)", 0.01));
MaxRateRP = Convert.ToDouble(GetConfig("Config", "Max_Rate_RP(0.00 - 1.00)", 0.1));
ReceiverFlag = Convert.ToBoolean(GetConfig("Config", "Receiver", false));
ReceiverSteamID = Convert.ToString(GetConfig("Config", "Receiver_Player_steamID", "0"));
UseEconomics = Convert.ToBoolean(GetConfig("Config", "Use_Economics", false));
UseServerRewards = Convert.ToBoolean(GetConfig("Config", "Use_ServerRewards", false));
}
private object GetConfig(string menu, string dataValue, object defaultValue)
{
Dictionary data = Config[menu] as Dictionary;
if (data == null)
{
data = new Dictionary();
Config[menu] = data;
Changed = true;
}
object value;
if (!data.TryGetValue(dataValue, out value))
{
value = defaultValue;
data[dataValue] = value;
Changed = true;
}
return value;
}
private void DPLoadConfig()
{
DATA_CONFIG = Config["Config"] as Dictionary;
LoadVariables();
}
#endregion
#region OxideHook
private void Init()
{
lang.RegisterMessages(new Dictionary
{
{"NoPerm", "You don't have a permission."},
{"NoEconomics", "Can't find Economics Plugin."},
{"InternalError", "A serious error has occurred in the plugin. Please report this to the administrator." },
{"NotRun", "Plugin is not running." },
{"PlayerLostCoins", "You have lost {reduce} of your Economics balance."},
{"PlayerLostRP", "You have lost {reduce} RP."},
{"CheckBalance", "The balance you've lost so far.\n Economics: {amountEconomics}\n RP: {amountRP}" }
}, this);
}
protected override void LoadDefaultConfig()
{
Config.Clear();
LoadVariables();
}
private void Loaded()
{
permission.RegisterPermission(perm_admin, this);
permission.RegisterPermission(perm_use, this);
//コインとRPロスト分
DATA_PLAYER_LOST_CR = GetFile(nameof(DeathPenalty));
LOST_DATA = DATA_PLAYER_LOST_CR.ReadObject>();
DPLoadConfig();
//Puts($"{MinRateEconomics}, {MaxRateEconomics}, {MinRateRP}, {MaxRateRP}, {ReceiverFlag}, {ReceiverSteamID}, {UseEconomics}. {UseServerRewards}");
}
private object OnPlayerDeath(BasePlayer player, HitInfo info)
{
if(!permission.UserHasPermission(player.UserIDString, perm_use))
{
return null;
}
/** 追記 ここから **/
//BasePlayer attacker = player.lastAttacker?.ToPlayer();
/** 追記 ここまで **/
ChangeEconomicsOrRp(player);
return null;
}
private void OnServerSave()
{
SaveLostData();
}
private void OnServerShutdown() => OnServerSave();
private void Unload() => OnServerSave();
private void SaveLostData()
{
if (LOST_DATA == null) return;
DATA_PLAYER_LOST_CR.WriteObject(LOST_DATA);
}
private void OnNewSave()
{
DATA_PLAYER_LOST_CR.Clear();
}
#endregion
#region Functions
private DynamicConfigFile GetFile(string name)
{
var file = Interface.Oxide.DataFileSystem.GetFile(name);
file.Settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
file.Settings.Converters = new JsonConverter[] { new UnityVector3Converter(), new CustomComparerDictionaryCreationConverter(StringComparer.OrdinalIgnoreCase) };
return file;
}
///
/// コインとRPの変更(メイン)
///
/// プレイヤー
private void ChangeEconomicsOrRp(BasePlayer player)
{
bool checker = true;
bool _bool;
//Puts($"Economics: {UseEconomics}, Server Rewards: {UseServerRewards}");
if (UseEconomics && UseServerRewards)
{
if (Economics != null && ServerRewards != null)//正常系
{
SqueezeSelector(player);
}
else
{
SendMessage(player, lang.GetMessage("InternalError", this));
Puts("Can not find Economics and ServerRewards.");
}
}
else if(UseEconomics && !UseServerRewards)
{
if (Economics != null)//ServerRewardsなし
{
_bool = ChangeEconomics(player);
}
else
{
SendMessage(player, lang.GetMessage("InternalError", this));
Puts("Can not find Economics.");
}
}
else if (!UseEconomics && UseServerRewards)
{
Puts("OK");
if (ServerRewards != null) //Economicsなし
{
_bool = ChangeRp(player);
}
else
{
SendMessage(player, lang.GetMessage("InternalError", this));
Puts("Can not find ServerRewards.");
}
}
else
{
Puts("DeathPenalty is not active.");
}
return;
//if (Economics == null && ServerRewards == null)//全部だめ
//{
// SendMessage(player, lang.GetMessage("InternalError", this));
// Puts("Can not find Economics and ServerRewards.");
// return;
//}
//else if(Economics != null && ServerRewards == null)//ServerRewardsなし
//{
// _bool = ChangeEconomics(player);
// return;
//}
//else if (Economics == null && ServerRewards != null)//Economicsなし
//{
// _bool = ChangeRp(player);
// return;
//}
//else if (Economics != null && ServerRewards != null)//正常系
//{
// SqueezeSelector(player);
// return;
//}
//else
//{
// SendMessage(player, lang.GetMessage("InternalError", this));
// Puts("Can not find Economics and ServerRewards.");
// return;
//}
}
private void SqueezeSelector(BasePlayer player)
{
double rateRandom = (double)UnityEngine.Random.Range(0, 1.0f);
rateRandom = Math.Round(rateRandom, 1, MidpointRounding.AwayFromZero);
bool _bool;
if (0.5 <= rateRandom)
{
_bool = ChangeEconomics(player);
}
else
{
_bool = ChangeRp(player);
}
return;
}
private bool ChangeEconomics(BasePlayer player)
{
double playerCoins = (double)Economics.CallHook("Balance", player.UserIDString);
if (playerCoins == 0)
{
return true;
}
double rateRandom = UnityEngine.Random.Range(Convert.ToSingle(MinRateEconomics), Convert.ToSingle(MaxRateEconomics));
double reduce = Math.Round(playerCoins * rateRandom, 1, MidpointRounding.AwayFromZero);
object tmp_economics;
if (ReceiverFlag && ReceiverSteamID != "0")
{
tmp_economics = Economics.CallHook("Transfer", player.UserIDString, ReceiverSteamID, reduce);
}
else
{
tmp_economics = Economics.CallHook("Withdraw", player.UserIDString, reduce);
}
if (tmp_economics == null || !(tmp_economics is bool) && !(bool)tmp_economics)
{
SendMessage(player, lang.GetMessage("NotRun", this));
Puts("Plugin is not running.:Economics");
return false;
}
playerCoins = (double)Economics.CallHook("Balance", player.UserIDString);
LoggingDeathData(player, reduce, "COINS");
return true;
}
private bool ChangeRp(BasePlayer player)
{
int? NplayerRP = (int)ServerRewards?.Call("CheckPoints", player.userID);
int playerRP;
if (NplayerRP == null || NplayerRP == 0)
{
return true;
}
else
{
playerRP = Convert.ToInt32(NplayerRP);
}
double rateRandom = UnityEngine.Random.Range(Convert.ToSingle(MinRateRP), Convert.ToSingle(MaxRateRP));
int reduce = (int)Math.Round(playerRP * rateRandom, 0, MidpointRounding.AwayFromZero);
object tmp_RP;
object tmp_RP_T;
if (ReceiverFlag && ReceiverSteamID != "0")
{
tmp_RP = ServerRewards?.Call("TakePoints", player.userID, reduce);
tmp_RP_T = ServerRewards?.Call("AddPoints", Convert.ToUInt64(ReceiverSteamID), reduce);
}
else
{
tmp_RP = ServerRewards?.Call("TakePoints", player.userID, reduce);
}
if (tmp_RP == null || tmp_RP is bool && !(bool)tmp_RP)
{
SendMessage(player, lang.GetMessage("NotRun", this));
Puts("Plugin is not running.:ServerRewards");
return false;
}
playerRP = (int)ServerRewards?.Call("CheckPoints", player.userID);
LoggingDeathData(player, reduce, "RP");
return true;
}
///
/// ログ吐き出し
///
/// プレイヤー
/// 値
private void LoggingDeathData(BasePlayer player,double reduce, string type)
{
//double currentDouble;
//int currentInt;
PlayerDataCR currentPlayerData;
if (!LOST_DATA.TryGetValue(player.userID, out currentPlayerData))
{
currentPlayerData = new PlayerDataCR();
LOST_DATA.Add(player.userID, currentPlayerData);
}
if (type.Equals("COINS"))
{
Log(player + " lost " + reduce + " coins");
currentPlayerData.Coins += reduce;
SendMessage(player, lang.GetMessage("PlayerLostCoins", this).Replace("{reduce}", reduce.ToString()));
Puts(player.displayName + "[" + player.UserIDString + "] lost " + reduce + " coins.");
return;
}
if (type.Equals("RP"))
{
Log(player + " lost " + reduce + " RP");
currentPlayerData.RP += (int)reduce;
SendMessage(player, lang.GetMessage("PlayerLostRP", this).Replace("{reduce}", reduce.ToString()));
Puts(player.displayName + "[" + player.UserIDString + "] lost " + reduce + " RP.");
return;
}
LOST_DATA[player.userID] = currentPlayerData;
return;
}
#endregion
#region Commands
//[ConsoleCommand("deathpenalty.convert")]
//private void DataConvert()
//{
// Puts("Data convert START");
// DynamicConfigFile dataPlayerLostCoins;//コインロスト分集計用データファイル
// DynamicConfigFile dataPlayerLostRP;//RPロスト分集計用データファイル
// Dictionary LostCoinData;
// Dictionary LostRPData;
// //コインロスト分集計
// dataPlayerLostCoins = GetFile(nameof(DeathPenalty) + "_LostCoins");
// LostCoinData = dataPlayerLostCoins.ReadObject>();
// //RPロスト分集計
// dataPlayerLostRP = GetFile(nameof(DeathPenalty) + "_LostRP");
// LostRPData = dataPlayerLostRP.ReadObject>();
// Puts("Coins Data convert START");
// if (LostCoinData != null)
// {
// foreach (var playerOldCoinData in LostCoinData)
// {
// //Puts($"COINS OLD DATA: {playerOldCoinData.Key}:{playerOldCoinData.Value}");
// PlayerDataCR playerNewData;
// if (!LOST_DATA.TryGetValue(playerOldCoinData.Key, out playerNewData))
// {
// playerNewData = new PlayerDataCR();
// playerNewData.Coins += playerOldCoinData.Value;
// LOST_DATA.Add(playerOldCoinData.Key, playerNewData);
// }
// else
// {
// playerNewData.Coins += playerOldCoinData.Value;
// }
// LOST_DATA[playerOldCoinData.Key] = playerNewData;
// }
// }
// Puts("Coins Data convert END");
// SaveLostData();
// Puts("RP Data convert START");
// if (LostRPData != null)
// {
// foreach (var playerOldRPData in LostRPData)
// {
// PlayerDataCR playerNewData;
// //Puts($"RP OLD DATA: {playerOldRPData.Key}:{playerOldRPData.Value}");
// if (!LOST_DATA.TryGetValue(playerOldRPData.Key, out playerNewData))
// {
// playerNewData = new PlayerDataCR();
// playerNewData.RP += playerOldRPData.Value;
// LOST_DATA.Add(playerOldRPData.Key, playerNewData);
// }
// else
// {
// playerNewData.RP += playerOldRPData.Value;
// }
// LOST_DATA[playerOldRPData.Key] = playerNewData;
// }
// }
// Puts("RP Data convert END");
// SaveLostData();
// Puts("Data convert END");
//}
[ChatCommand("dp")]
private void DpCmd(BasePlayer player, string command, string[] args)
{
PlayerDataCR playerData;
if(!LOST_DATA.TryGetValue(player.userID, out playerData))
{
playerData = new PlayerDataCR();
LOST_DATA.Add(player.userID, playerData);
}
//SendMessage(player, lang.GetMessage("CPlayerLostCoins", this).Replace("{amount}", playerData.Coins.ToString()));
//SendMessage(player, lang.GetMessage("CPlayerLostRP", this).Replace("{amount}", playerData.RP.ToString()));
SendMessage(player, lang.GetMessage("CheckBalance", this).Replace("{amountEconomics}", playerData.Coins.ToString()).Replace("{amountRP}", playerData.RP.ToString()));
}
#endregion
#region Helper
private class UnityVector3Converter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var vector = (Vector3)value;
writer.WriteValue($"{vector.x} {vector.y} {vector.z}");
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.String)
{
var values = reader.Value.ToString().Trim().Split(' ');
return new Vector3(Convert.ToSingle(values[0]), Convert.ToSingle(values[1]), Convert.ToSingle(values[2]));
}
var o = JObject.Load(reader);
return new Vector3(Convert.ToSingle(o["x"]), Convert.ToSingle(o["y"]), Convert.ToSingle(o["z"]));
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(Vector3);
}
}
private class CustomComparerDictionaryCreationConverter : CustomCreationConverter
{
private readonly IEqualityComparer comparer;
public CustomComparerDictionaryCreationConverter(IEqualityComparer comparer)
{
if (comparer == null) throw new ArgumentNullException(nameof(comparer));
this.comparer = comparer;
}
public override bool CanConvert(Type objectType)
{
return HasCompatibleInterface(objectType) && HasCompatibleConstructor(objectType);
}
private static bool HasCompatibleInterface(Type objectType)
{
return objectType.GetInterfaces().Where(i => HasGenericTypeDefinition(i, typeof(IDictionary<,>))).Any(i => typeof(T).IsAssignableFrom(i.GetGenericArguments().First()));
}
private static bool HasGenericTypeDefinition(Type objectType, Type typeDefinition)
{
return objectType.IsGenericType && objectType.GetGenericTypeDefinition() == typeDefinition;
}
private static bool HasCompatibleConstructor(Type objectType)
{
return objectType.GetConstructor(new[] { typeof(IEqualityComparer) }) != null;
}
public override IDictionary Create(Type objectType)
{
return Activator.CreateInstance(objectType, comparer) as IDictionary;
}
}
void SendMessage(BasePlayer player, string message, params object[] args) => PrintToChat(player, pName + message, args);
private void Log(string text) => LogToFile("death", $"[{DateTime.Now}] {text}", this);
#endregion
}
}