Game Mods - Json + Configuration migration
- Changed the Game Mods config to a json file - Created a .ini migration for the json file - Better ANSI readability - Improved some methods
This commit is contained in:
parent
56dd6194a1
commit
f3ccab713e
@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@ -24,12 +26,12 @@ public class AnsiTarget : LogTarget
|
||||
_table = new Table().Expand().ShowFooters().ShowHeaders().Border(TableBorder.Rounded);
|
||||
|
||||
if (IncludeTimeStamps)
|
||||
_table.AddColumn("Time");
|
||||
_table.AddColumn("Time").Centered();
|
||||
_table
|
||||
.AddColumn("Level")
|
||||
.AddColumn("Logger")
|
||||
.AddColumn("Message")
|
||||
.AddColumn("Error");
|
||||
.AddColumn("Level").RightAligned()
|
||||
.AddColumn("Message").Centered()
|
||||
.AddColumn("Logger").LeftAligned()
|
||||
.AddColumn("Error").RightAligned();
|
||||
|
||||
AnsiConsole.Live(_table).StartAsync(async ctx =>
|
||||
{
|
||||
@ -101,6 +103,15 @@ public class AnsiTarget : LogTarget
|
||||
}
|
||||
|
||||
|
||||
private static Dictionary<string, string> _replacements = new ()
|
||||
{
|
||||
["["] = "[[",
|
||||
["]"] = "]]",
|
||||
["$[[/]]$"] = "[/]",
|
||||
["$[["] = "[",
|
||||
["]]$"] = "]"
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Performs a cleanup on the target.
|
||||
/// All [ becomes [[, and ] becomes ]] (for ignoring ANSI codes)
|
||||
@ -112,82 +123,58 @@ public class AnsiTarget : LogTarget
|
||||
/// </summary>
|
||||
/// <param name="x"></param>
|
||||
/// <returns></returns>
|
||||
public static string Cleanup(string x) => Beautify(x.Replace("[", "[[").Replace("]", "]]").Replace("$[[/]]$", "[/]").Replace("$[[", "[").Replace("]]$", "]"));
|
||||
|
||||
public static string Cleanup(string input)
|
||||
{
|
||||
if (string.IsNullOrEmpty(input)) return "";
|
||||
return Beautify(_replacements.Aggregate(input, (current, replacement) => current.Replace(replacement.Key, replacement.Value)));
|
||||
}
|
||||
public override void LogMessage(Logger.Level level, string logger, string message)
|
||||
{
|
||||
if (CancellationTokenSource.IsCancellationRequested)
|
||||
return;
|
||||
if (CancellationTokenSource.IsCancellationRequested) return;
|
||||
|
||||
try
|
||||
{
|
||||
if (IncludeTimeStamps)
|
||||
_table.AddRow(
|
||||
new Markup(DateTime.Now.ToString(TimeStampFormat), GetStyleByLevel(level)),
|
||||
new Markup(level.ToString(), GetStyleByLevel(level)).RightJustified(),
|
||||
new Markup(logger, GetStyleByLevel(level)).LeftJustified(),
|
||||
new Markup(Cleanup(message), GetStyleByLevel(level)).LeftJustified(),
|
||||
new Markup("", new Style(foreground: Color.Green3_1)).Centered());
|
||||
else
|
||||
_table.AddRow(
|
||||
new Markup(level.ToString()).RightJustified(),
|
||||
new Markup(logger, GetStyleByLevel(level)).LeftJustified(),
|
||||
new Markup(Cleanup(message), GetStyleByLevel(level)).LeftJustified(),
|
||||
new Markup("", new Style(foreground: Color.Green3_1)).Centered());
|
||||
AddRow(level, logger, message, "");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var regex = new Regex(@"\$\[.*?\]\$");
|
||||
var matches = regex.Matches(message);
|
||||
foreach (Match match in matches)
|
||||
{
|
||||
message = message.Replace(match.Value, "");
|
||||
}
|
||||
|
||||
if (IncludeTimeStamps)
|
||||
{
|
||||
_table.AddRow(
|
||||
new Markup(DateTime.Now.ToString(TimeStampFormat), GetStyleByLevel(level)),
|
||||
new Markup(level.ToString(), GetStyleByLevel(level)).RightJustified(),
|
||||
new Markup(logger, GetStyleByLevel(level)).LeftJustified(),
|
||||
new Markup(Cleanup(message), GetStyleByLevel(level)).LeftJustified(),
|
||||
new Markup(ex.Message, new Style(foreground: Color.Red3_1)).Centered());
|
||||
}
|
||||
else
|
||||
{
|
||||
_table.AddRow(
|
||||
new Markup(level.ToString()).RightJustified(),
|
||||
new Markup(logger, GetStyleByLevel(level)).LeftJustified(),
|
||||
new Markup(Cleanup(message), GetStyleByLevel(level)).LeftJustified(),
|
||||
new Markup(ex.Message, new Style(foreground: Color.Red3_1)).Centered());
|
||||
}
|
||||
AddRow(level, logger, Cleanup(StripMarkup(message)), ex.Message, true);
|
||||
}
|
||||
}
|
||||
|
||||
public override void LogException(Logger.Level level, string logger, string message, Exception exception)
|
||||
{
|
||||
if (CancellationTokenSource.IsCancellationRequested)
|
||||
return;
|
||||
if (CancellationTokenSource.IsCancellationRequested) return;
|
||||
|
||||
try
|
||||
{
|
||||
if (IncludeTimeStamps)
|
||||
_table.AddRow(
|
||||
new Markup(DateTime.Now.ToString(TimeStampFormat), GetStyleByLevel(level)),
|
||||
new Markup(level.ToString(), GetStyleByLevel(level)).RightJustified(),
|
||||
new Markup(logger, GetStyleByLevel(level)).LeftJustified(),
|
||||
new Markup(Cleanup(message), GetStyleByLevel(level)).LeftJustified(),
|
||||
new Markup(
|
||||
$"[underline red3_1 on white]{exception.GetType().Name}[/]\n" + Cleanup(exception.Message),
|
||||
new Style(foreground: Color.Red3_1)).Centered());
|
||||
else
|
||||
_table.AddRow(
|
||||
new Markup(level.ToString()).RightJustified(),
|
||||
new Markup(logger, GetStyleByLevel(level)).LeftJustified(),
|
||||
new Markup(message, GetStyleByLevel(level)).LeftJustified(),
|
||||
new Markup(
|
||||
$"[underline red3_1 on white]{exception.GetType().Name}[/]\n" + Cleanup(exception.Message),
|
||||
new Style(foreground: Color.Red3_1)).Centered());
|
||||
AddRow(level, logger, message, $"[underline red3_1 on white]{exception.GetType().Name}[/]\n" + Cleanup(exception.Message), exFormat: true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AddRow(level, logger, Cleanup(StripMarkup(message)), ex.Message, true);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddRow(Logger.Level level, string logger, string message, string exMessage, bool isError = false,
|
||||
bool exFormat = false)
|
||||
{
|
||||
Style messageStyle = GetStyleByLevel(level);
|
||||
Style exStyle = exFormat ? new Style(foreground: Color.Red3_1) : new Style(foreground: Color.Green3_1);
|
||||
var colTimestamp = new Markup(DateTime.Now.ToString(TimeStampFormat), messageStyle).Centered();
|
||||
var colLevel = new Markup(level.ToString(), messageStyle).RightJustified();
|
||||
var colMessage = new Markup(Cleanup(message), messageStyle).Centered();
|
||||
var colLogger = new Markup(logger, new Style(messageStyle.Foreground, messageStyle.Background, messageStyle.Decoration
|
||||
#if DEBUG
|
||||
//, link = ...
|
||||
#endif
|
||||
)).LeftJustified();
|
||||
var colError = new Markup(isError ? exMessage : "", exStyle).RightJustified();
|
||||
if (IncludeTimeStamps) _table.AddRow(colTimestamp, colLevel, colMessage, colLogger, colError);
|
||||
else _table.AddRow(colLevel, colMessage, colLogger, colError);
|
||||
}
|
||||
|
||||
private string StripMarkup(string message)
|
||||
{
|
||||
var regex = new Regex(@"\$\[.*?\]\$");
|
||||
var matches = regex.Matches(message);
|
||||
@ -196,38 +183,21 @@ public class AnsiTarget : LogTarget
|
||||
message = message.Replace(match.Value, "");
|
||||
}
|
||||
|
||||
if (IncludeTimeStamps)
|
||||
{
|
||||
_table.AddRow(
|
||||
new Markup(DateTime.Now.ToString(TimeStampFormat), GetStyleByLevel(level)),
|
||||
new Markup(level.ToString(), GetStyleByLevel(level)).RightJustified(),
|
||||
new Markup(logger, GetStyleByLevel(level)).LeftJustified(),
|
||||
new Markup(Cleanup(message), GetStyleByLevel(level)).LeftJustified(),
|
||||
new Markup(ex.Message, new Style(foreground: Color.Red3_1)).Centered());
|
||||
}
|
||||
else
|
||||
{
|
||||
_table.AddRow(
|
||||
new Markup(level.ToString()).RightJustified(),
|
||||
new Markup(logger, GetStyleByLevel(level)).LeftJustified(),
|
||||
new Markup(Cleanup(message), GetStyleByLevel(level)).LeftJustified(),
|
||||
new Markup(ex.Message, new Style(foreground: Color.Red3_1)).Centered());
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
private static Style GetStyleByLevel(Logger.Level level)
|
||||
{
|
||||
return level switch
|
||||
{
|
||||
Logger.Level.RenameAccountLog => new Style(Color.DarkSlateGray3),//
|
||||
Logger.Level.ChatMessage => new Style(Color.DarkSlateGray2),//
|
||||
Logger.Level.Debug => new Style(Color.Olive),//
|
||||
Logger.Level.MethodTrace => new Style(Color.DarkOliveGreen1_1),//
|
||||
Logger.Level.Trace => new Style(Color.BlueViolet),//
|
||||
Logger.Level.Info => new Style(Color.White),
|
||||
Logger.Level.Success => new Style(Color.Green3_1),
|
||||
Logger.Level.Warn => new Style(Color.Yellow),//
|
||||
Logger.Level.RenameAccountLog => new Style(Color.Gold1),//
|
||||
Logger.Level.ChatMessage => new Style(Color.Plum2),//
|
||||
Logger.Level.Debug => new Style(Color.Grey62),//
|
||||
Logger.Level.MethodTrace => new Style(Color.Grey74, decoration: Decoration.Dim | Decoration.Italic),//
|
||||
Logger.Level.Trace => new Style(Color.Grey82),//
|
||||
Logger.Level.Info => new Style(Color.SteelBlue),
|
||||
Logger.Level.Success => new Style(Color.DarkOliveGreen3_2),
|
||||
Logger.Level.Warn => new Style(Color.DarkOrange),//
|
||||
Logger.Level.Error => new Style(Color.IndianRed1),//
|
||||
Logger.Level.Fatal => new Style(Color.Red3_1),//
|
||||
Logger.Level.PacketDump => new Style(Color.Maroon),//
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace DiIiS_NA.Core.Logging
|
||||
{
|
||||
@ -25,7 +26,7 @@ namespace DiIiS_NA.Core.Logging
|
||||
/// Creates and returns a logger named with declaring type.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="Logger"/> instance.</returns>
|
||||
public static Logger CreateLogger()
|
||||
public static Logger CreateLogger([CallerFilePath] string filePath = "")
|
||||
{
|
||||
var frame = new StackFrame(1, false); // read stack frame.
|
||||
var name = frame.GetMethod().DeclaringType.Name; // get declaring type's name.
|
||||
@ -33,7 +34,7 @@ namespace DiIiS_NA.Core.Logging
|
||||
if (name == null) // see if we got a name.
|
||||
throw new Exception("Error getting full name for declaring type.");
|
||||
|
||||
return CreateLogger(name); // return the newly created logger.
|
||||
return CreateLogger(name, filePath); // return the newly created logger.
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -41,10 +42,10 @@ namespace DiIiS_NA.Core.Logging
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns>A <see cref="Logger"/> instance.</returns>
|
||||
public static Logger CreateLogger(string name)
|
||||
public static Logger CreateLogger(string name, [CallerFilePath] string filePath = "")
|
||||
{
|
||||
if (!Loggers.ContainsKey(name)) // see if we already have instance for the given name.
|
||||
Loggers.Add(name, new Logger(name)); // add it to dictionary of loggers.
|
||||
Loggers.Add(name, new Logger(name, filePath)); // add it to dictionary of loggers.
|
||||
|
||||
return Loggers[name]; // return the newly created logger.
|
||||
}
|
||||
|
||||
@ -13,15 +13,17 @@ namespace DiIiS_NA.Core.Logging
|
||||
public class Logger
|
||||
{
|
||||
public string Name { get; protected set; }
|
||||
public string FilePath { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// A logger base type is used to create a logger instance.
|
||||
/// E.g. ConsoleTarget, FileTarget, etc.
|
||||
/// </summary>
|
||||
/// <param name="name">Logger name</param>
|
||||
public Logger(string name)
|
||||
public Logger(string name, string filePath = null)
|
||||
{
|
||||
Name = name;
|
||||
FilePath = filePath;
|
||||
}
|
||||
|
||||
public enum Level
|
||||
|
||||
@ -79,7 +79,7 @@ namespace DiIiS_NA.Core.MPQ
|
||||
|
||||
public void Init()
|
||||
{
|
||||
Logger.Info("Loading Diablo III Assets..");
|
||||
Logger.Info("Loading Diablo III Assets...");
|
||||
DictSNOAccolade = Dicts.LoadAccolade();
|
||||
DictSNOAct = Dicts.LoadActs();
|
||||
DictSNOActor = Dicts.LoadActors();
|
||||
|
||||
@ -30,11 +30,11 @@ namespace DiIiS_NA.Core.MPQ
|
||||
var mpqFile = MPQStorage.GetMPQFile(file);
|
||||
if (mpqFile == null)
|
||||
{
|
||||
Logger.Error("Cannot find base MPQ file: {0}.", file);
|
||||
Logger.Fatal("Cannot find base MPQ file: $[white on red]${0}$[/]$.", file);
|
||||
return;
|
||||
}
|
||||
this.BaseMPQFiles.Add(mpqFile);
|
||||
Logger.Trace("Added MPQ storage: {0}.", file);
|
||||
Logger.Debug($"Added MPQ storage: $[white underline]${file}$[/]$.");
|
||||
}
|
||||
|
||||
this.PatchPattern = patchPattern;
|
||||
@ -45,7 +45,7 @@ namespace DiIiS_NA.Core.MPQ
|
||||
this.Loaded = true;
|
||||
else
|
||||
{
|
||||
Logger.Error("Required patch-chain version {0} is not satified (found version: {1}).", this.RequiredVersion, topMostMPQVersion);
|
||||
Logger.Error("Required patch-chain version {0} is not satisfied (found version: {1}).", this.RequiredVersion, topMostMPQVersion);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,18 @@
|
||||
using DiIiS_NA.Core.Logging;
|
||||
using DiIiS_NA.D3_GameServer;
|
||||
using DiIiS_NA.LoginServer.AccountsSystem;
|
||||
using DiIiS_NA.LoginServer.Battle;
|
||||
|
||||
namespace DiIiS_NA.GameServer.CommandManager;
|
||||
|
||||
[CommandGroup("game", "Game Commands", Account.UserLevels.Admin, inGameOnly: false)]
|
||||
public class GameCommand : CommandGroup
|
||||
{
|
||||
private static readonly Logger Logger = LogManager.CreateLogger();
|
||||
[Command("reload-mods", "Reload all game mods file.", Account.UserLevels.Admin, inGameOnly: false)]
|
||||
public void ReloadMods(string[] @params, BattleClient invokerClient)
|
||||
{
|
||||
GameModsConfig.ReloadSettings();
|
||||
invokerClient.SendServerWhisper("Game mods updated successfully!");
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,5 @@
|
||||
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Hireling;
|
||||
using System;
|
||||
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Hireling;
|
||||
using DiIiS_NA.LoginServer.AccountsSystem;
|
||||
using DiIiS_NA.LoginServer.Battle;
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@ using DiIiS_NA.GameServer.GSSystem.AISystem.Brains;
|
||||
using DiIiS_NA.GameServer.MessageSystem;
|
||||
using DiIiS_NA.Core.Logging;
|
||||
using DiIiS_NA.Core.MPQ.FileFormats;
|
||||
using DiIiS_NA.D3_GameServer;
|
||||
|
||||
namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations
|
||||
{
|
||||
@ -73,9 +74,9 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations
|
||||
//this.Attributes[GameAttribute.Immune_To_Charm] = true;
|
||||
Attributes[GameAttributes.using_Bossbar] = true;
|
||||
Attributes[GameAttributes.InBossEncounter] = true;
|
||||
Attributes[GameAttributes.Hitpoints_Max] *= GameServerConfig.Instance.BossHealthMultiplier;
|
||||
Attributes[GameAttributes.Damage_Weapon_Min, 0] *= GameServerConfig.Instance.BossDamageMultiplier;
|
||||
Attributes[GameAttributes.Damage_Weapon_Delta, 0] *= GameServerConfig.Instance.BossDamageMultiplier;
|
||||
Attributes[GameAttributes.Hitpoints_Max] *= GameModsConfig.Instance.Boss.HealthMultiplier;
|
||||
Attributes[GameAttributes.Damage_Weapon_Min, 0] *= GameModsConfig.Instance.Boss.DamageMultiplier;
|
||||
Attributes[GameAttributes.Damage_Weapon_Delta, 0] *= GameModsConfig.Instance.Boss.DamageMultiplier;
|
||||
Attributes[GameAttributes.Hitpoints_Cur] = Attributes[GameAttributes.Hitpoints_Max_Total];
|
||||
Attributes[GameAttributes.TeamID] = 10;
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@ using GameBalance = DiIiS_NA.Core.MPQ.FileFormats.GameBalance;
|
||||
using DiIiS_NA.GameServer.GSSystem.ObjectsSystem;
|
||||
using DiIiS_NA.Core.Logging;
|
||||
using DiIiS_NA.Core.MPQ.FileFormats;
|
||||
using DiIiS_NA.D3_GameServer;
|
||||
using DiIiS_NA.GameServer.GSSystem.TickerSystem;
|
||||
using DiIiS_NA.GameServer.MessageSystem;
|
||||
using DiIiS_NA.GameServer.Core.Types.SNO;
|
||||
@ -96,26 +97,26 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem
|
||||
|
||||
Attributes[GameAttributes.Hitpoints_Max] = (int)((int)monsterLevels.MonsterLevel[monsterLevel].HPMin + DiIiS_NA.Core.Helpers.Math.RandomHelper.Next(0, (int)monsterLevels.MonsterLevel[monsterLevel].HPDelta) * HpMultiplier * World.Game.HpModifier);
|
||||
Attributes[GameAttributes.Hitpoints_Max_Percent_Bonus_Multiplicative] = ((int)World.Game.ConnectedPlayers.Length + 1) * 1.5f;
|
||||
Attributes[GameAttributes.Hitpoints_Max_Percent_Bonus_Multiplicative] *= GameServerConfig.Instance.RateMonsterHP;
|
||||
Attributes[GameAttributes.Hitpoints_Max_Percent_Bonus_Multiplicative] *= GameModsConfig.Instance.Monster.HealthMultiplier;
|
||||
if (World.Game.ConnectedPlayers.Length > 1)
|
||||
Attributes[GameAttributes.Hitpoints_Max_Percent_Bonus_Multiplicative] = Attributes[GameAttributes.Hitpoints_Max_Percent_Bonus_Multiplicative];// / 2f;
|
||||
var hpMax = Attributes[GameAttributes.Hitpoints_Max];
|
||||
var hpTotal = Attributes[GameAttributes.Hitpoints_Max_Total];
|
||||
float damageMin = monsterLevels.MonsterLevel[World.Game.MonsterLevel].Dmg * DmgMultiplier;// * 0.5f;
|
||||
float damageDelta = damageMin;
|
||||
Attributes[GameAttributes.Damage_Weapon_Min, 0] = damageMin * World.Game.DmgModifier * GameServerConfig.Instance.RateMonsterDMG;
|
||||
Attributes[GameAttributes.Damage_Weapon_Min, 0] = damageMin * World.Game.DmgModifier * GameModsConfig.Instance.Monster.DamageMultiplier;
|
||||
Attributes[GameAttributes.Damage_Weapon_Delta, 0] = damageDelta;
|
||||
|
||||
if (monsterLevel > 30)
|
||||
{
|
||||
Attributes[GameAttributes.Hitpoints_Max_Percent_Bonus_Multiplicative] = Attributes[GameAttributes.Hitpoints_Max_Percent_Bonus_Multiplicative];// * 0.5f;
|
||||
Attributes[GameAttributes.Damage_Weapon_Min, 0] = damageMin * World.Game.DmgModifier * GameServerConfig.Instance.RateMonsterDMG;// * 0.2f;
|
||||
Attributes[GameAttributes.Damage_Weapon_Min, 0] = damageMin * World.Game.DmgModifier * GameModsConfig.Instance.Monster.DamageMultiplier;// * 0.2f;
|
||||
Attributes[GameAttributes.Damage_Weapon_Delta, 0] = damageDelta;
|
||||
}
|
||||
if (monsterLevel > 60)
|
||||
{
|
||||
Attributes[GameAttributes.Hitpoints_Max_Percent_Bonus_Multiplicative] = Attributes[GameAttributes.Hitpoints_Max_Percent_Bonus_Multiplicative];// * 0.7f;
|
||||
Attributes[GameAttributes.Damage_Weapon_Min, 0] = damageMin * World.Game.DmgModifier * GameServerConfig.Instance.RateMonsterDMG;// * 0.15f;
|
||||
Attributes[GameAttributes.Damage_Weapon_Min, 0] = damageMin * World.Game.DmgModifier * GameModsConfig.Instance.Monster.DamageMultiplier;// * 0.15f;
|
||||
//this.Attributes[GameAttribute.Damage_Weapon_Delta, 0] = DamageDelta * 0.5f;
|
||||
}
|
||||
|
||||
|
||||
@ -270,7 +270,7 @@ namespace DiIiS_NA.D3_GameServer.GSSystem.GameSystem
|
||||
if (!Game.Empty)
|
||||
{
|
||||
RevealQuestProgress();
|
||||
if ((Game.CurrentActEnum != ActEnum.OpenWorld && GameServerConfig.Instance.AutoSaveQuests) ||
|
||||
if ((Game.CurrentActEnum != ActEnum.OpenWorld && GameModsConfig.Instance.Quest.AutoSave) ||
|
||||
Quests[Game.CurrentQuest].Steps[Game.CurrentStep].Saveable)
|
||||
SaveQuestProgress(false);
|
||||
}
|
||||
|
||||
@ -18,6 +18,7 @@ using DiIiS_NA.GameServer.Core.Types.TagMap;
|
||||
using DiIiS_NA.GameServer.MessageSystem;
|
||||
using DiIiS_NA.LoginServer.Toons;
|
||||
using DiIiS_NA.Core.Helpers.Math;
|
||||
using DiIiS_NA.D3_GameServer;
|
||||
using DiIiS_NA.GameServer.GSSystem.PlayerSystem;
|
||||
|
||||
namespace DiIiS_NA.GameServer.GSSystem.ItemsSystem
|
||||
@ -1358,8 +1359,8 @@ namespace DiIiS_NA.GameServer.GSSystem.ItemsSystem
|
||||
private static void RandomSetUnidentified(Item item) => item.Unidentified =
|
||||
FastRandom.Instance.Chance(item.Name.Contains("unique", StringComparison.InvariantCultureIgnoreCase)
|
||||
|| item.ItemDefinition.Quality is ItemTable.ItemQuality.Legendary or ItemTable.ItemQuality.Special or ItemTable.ItemQuality.Set
|
||||
? GameServerConfig.Instance.ChanceHighQualityUnidentified
|
||||
: GameServerConfig.Instance.ChanceNormalUnidentified);
|
||||
? GameModsConfig.Instance.Items.UnidentifiedDropChances.HighQuality
|
||||
: GameModsConfig.Instance.Items.UnidentifiedDropChances.NormalQuality);
|
||||
|
||||
// Allows cooking a custom item.
|
||||
public static Item Cook(Player player, string name)
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DiIiS_NA.D3_GameServer;
|
||||
|
||||
namespace DiIiS_NA.GameServer.GSSystem.ItemsSystem
|
||||
{
|
||||
@ -613,16 +614,16 @@ namespace DiIiS_NA.GameServer.GSSystem.ItemsSystem
|
||||
switch (MonsterQuality)
|
||||
{
|
||||
case 0: //Normal
|
||||
return new List<float> { 0.18f * GameServerConfig.Instance.RateChangeDrop };
|
||||
return new List<float> { 0.18f * GameModsConfig.Instance.Rate.ChangeDrop };
|
||||
case 1: //Champion
|
||||
return new List<float> { 1f, 1f, 1f, 1f, 0.75f * GameServerConfig.Instance.RateChangeDrop };
|
||||
return new List<float> { 1f, 1f, 1f, 1f, 0.75f * GameModsConfig.Instance.Rate.ChangeDrop };
|
||||
case 2: //Rare (Elite)
|
||||
case 4: //Unique
|
||||
return new List<float> { 1f, 1f, 1f, 1f, 1f };
|
||||
case 7: //Boss
|
||||
return new List<float> { 1f, 1f, 1f, 1f, 1f, 0.75f * GameServerConfig.Instance.RateChangeDrop, 0.4f * GameServerConfig.Instance.RateChangeDrop };
|
||||
return new List<float> { 1f, 1f, 1f, 1f, 1f, 0.75f * GameModsConfig.Instance.Rate.ChangeDrop, 0.4f * GameModsConfig.Instance.Rate.ChangeDrop };
|
||||
default:
|
||||
return new List<float> { 0.12f * GameServerConfig.Instance.RateChangeDrop };
|
||||
return new List<float> { 0.12f * GameModsConfig.Instance.Rate.ChangeDrop };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -24,6 +24,7 @@ using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using DiIiS_NA.D3_GameServer;
|
||||
using Actor = DiIiS_NA.GameServer.GSSystem.ActorSystem.Actor;
|
||||
|
||||
namespace DiIiS_NA.GameServer.GSSystem.MapSystem
|
||||
@ -549,7 +550,7 @@ namespace DiIiS_NA.GameServer.GSSystem.MapSystem
|
||||
SceneSNO = SceneSNO.Id,
|
||||
Transform = Transform,
|
||||
WorldID = World.GlobalID,
|
||||
MiniMapVisibility = GameServerConfig.Instance.ForceMinimapVisibility
|
||||
MiniMapVisibility = GameModsConfig.Instance.Minimap.ForceVisibility
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -10,6 +10,7 @@ using DiIiS_NA.Core.Helpers.Math;
|
||||
using DiIiS_NA.Core.Logging;
|
||||
using DiIiS_NA.Core.MPQ;
|
||||
using DiIiS_NA.Core.MPQ.FileFormats;
|
||||
using DiIiS_NA.D3_GameServer;
|
||||
using DiIiS_NA.D3_GameServer.Core.Types.SNO;
|
||||
using DiIiS_NA.GameServer.Core.Types.Math;
|
||||
using DiIiS_NA.GameServer.Core.Types.QuadTrees;
|
||||
@ -930,7 +931,7 @@ namespace DiIiS_NA.GameServer.GSSystem.MapSystem
|
||||
/// <param name="position">The position for drop.</param>
|
||||
public void SpawnGold(Actor source, Player player, int Min = -1)
|
||||
{
|
||||
int amount = (int)(LootManager.GetGoldAmount(player.Attributes[GameAttributes.Level]) * Game.GoldModifier * GameServerConfig.Instance.RateMoney);
|
||||
int amount = (int)(LootManager.GetGoldAmount(player.Attributes[GameAttributes.Level]) * Game.GoldModifier * GameModsConfig.Instance.Rate.Money);
|
||||
if (Min != -1)
|
||||
amount += Min;
|
||||
var item = ItemGenerator.CreateGold(player, amount); // somehow the actual ammount is not shown on ground /raist.
|
||||
|
||||
@ -56,6 +56,7 @@ using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Pet;
|
||||
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Game;
|
||||
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Hireling;
|
||||
using DiIiS_NA.Core.Helpers.Hash;
|
||||
using DiIiS_NA.D3_GameServer;
|
||||
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Encounter;
|
||||
using DiIiS_NA.D3_GameServer.Core.Types.SNO;
|
||||
using DiIiS_NA.D3_GameServer.GSSystem.ActorSystem.Implementations.Artisans;
|
||||
@ -2481,6 +2482,21 @@ public class Player : Actor, IMessageConsumer, IUpdateable
|
||||
|
||||
public bool SpeedCheckDisabled = false;
|
||||
|
||||
public float StrengthMultiplier => ParagonLevel > 0
|
||||
? GameModsConfig.Instance.Player.Multipliers.Strength.Paragon
|
||||
: GameModsConfig.Instance.Player.Multipliers.Strength.Normal;
|
||||
public float DexterityMultiplier => ParagonLevel > 0
|
||||
? GameModsConfig.Instance.Player.Multipliers.Dexterity.Paragon
|
||||
: GameModsConfig.Instance.Player.Multipliers.Dexterity.Normal;
|
||||
|
||||
public float IntelligenceMultiplier => ParagonLevel > 0
|
||||
? GameModsConfig.Instance.Player.Multipliers.Intelligence.Paragon
|
||||
: GameModsConfig.Instance.Player.Multipliers.Intelligence.Normal;
|
||||
|
||||
public float VitalityMultiplier => ParagonLevel > 0
|
||||
? GameModsConfig.Instance.Player.Multipliers.Vitality.Paragon
|
||||
: GameModsConfig.Instance.Player.Multipliers.Intelligence.Normal;
|
||||
|
||||
public static byte[] StringToByteArray(string hex)
|
||||
{
|
||||
return Enumerable.Range(0, hex.Length)
|
||||
@ -2675,8 +2691,9 @@ public class Player : Actor, IMessageConsumer, IUpdateable
|
||||
Logger.WarnException(e, "questEvent()");
|
||||
}
|
||||
}
|
||||
// Reset resurrection charges on zone change - TODO: do not reset charges on reentering the same zone
|
||||
Attributes[GameAttributes.Corpse_Resurrection_Charges] = GameServerConfig.Instance.ResurrectionCharges;
|
||||
// Reset resurrection charges on zone change
|
||||
// TODO: do not reset charges on reentering the same zone
|
||||
Attributes[GameAttributes.Corpse_Resurrection_Charges] = GameModsConfig.Instance.Health.ResurrectionCharges;
|
||||
|
||||
#if DEBUG
|
||||
Logger.Warn($"Player Location {Toon.Name}, Scene: {CurrentScene.SceneSNO.Name} SNO: {CurrentScene.SceneSNO.Id} LevelArea: {CurrentScene.Specification.SNOLevelAreas[0]}");
|
||||
@ -3995,7 +4012,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable
|
||||
get
|
||||
{
|
||||
var baseStrength = 0.0f;
|
||||
var multiplier = ParagonLevel > 0 ? GameServerConfig.Instance.StrengthParagonMultiplier : GameServerConfig.Instance.StrengthMultiplier;
|
||||
var multiplier = StrengthMultiplier;
|
||||
baseStrength = Toon.HeroTable.CoreAttribute == GameBalance.PrimaryAttribute.Strength
|
||||
? Toon.HeroTable.Strength + (Level - 1) * 3
|
||||
: Toon.HeroTable.Strength + (Level - 1);
|
||||
@ -4011,8 +4028,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable
|
||||
{
|
||||
get
|
||||
{
|
||||
var multiplier = ParagonLevel > 0 ? GameServerConfig.Instance.DexterityParagonMultiplier : GameServerConfig.Instance.DexterityMultiplier;
|
||||
|
||||
var multiplier = DexterityMultiplier;
|
||||
return Toon.HeroTable.CoreAttribute == GameBalance.PrimaryAttribute.Dexterity
|
||||
? Toon.HeroTable.Dexterity + (Level - 1) * 3 * multiplier
|
||||
: Toon.HeroTable.Dexterity + (Level - 1) * multiplier;
|
||||
@ -4022,7 +4038,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable
|
||||
public float TotalDexterity =>
|
||||
Attributes[GameAttributes.Dexterity] + Inventory.GetItemBonus(GameAttributes.Dexterity_Item);
|
||||
|
||||
public float Vitality => Toon.HeroTable.Vitality + (Level - 1) * 2 * (ParagonLevel > 0 ? GameServerConfig.Instance.VitalityParagonMultiplier : GameServerConfig.Instance.VitalityMultiplier);
|
||||
public float Vitality => Toon.HeroTable.Vitality + (Level - 1) * 2 * (VitalityMultiplier);
|
||||
|
||||
public float TotalVitality =>
|
||||
Attributes[GameAttributes.Vitality] + Inventory.GetItemBonus(GameAttributes.Vitality_Item);
|
||||
@ -4031,7 +4047,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable
|
||||
{
|
||||
get
|
||||
{
|
||||
var multiplier = ParagonLevel > 0 ? GameServerConfig.Instance.IntelligenceParagonMultiplier : GameServerConfig.Instance.IntelligenceMultiplier;
|
||||
var multiplier = IntelligenceMultiplier;
|
||||
return Toon.HeroTable.CoreAttribute == GameBalance.PrimaryAttribute.Intelligence
|
||||
? Toon.HeroTable.Intelligence + (Level - 1) * 3 * multiplier
|
||||
: Toon.HeroTable.Intelligence + (Level - 1) * multiplier;
|
||||
@ -4090,7 +4106,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable
|
||||
},
|
||||
SkillSlotEverAssigned = 0x0F, //0xB4,
|
||||
PlaytimeTotal = Toon.TimePlayed,
|
||||
WaypointFlags = GameServerConfig.Instance.UnlockAllWaypoints ? 0x0000ffff : World.Game.WaypointFlags,
|
||||
WaypointFlags = GameModsConfig.Instance.Quest.UnlockAllWaypoints ? 0x0000ffff : World.Game.WaypointFlags,
|
||||
HirelingData = new HirelingSavedData()
|
||||
{
|
||||
HirelingInfos = HirelingInfo,
|
||||
@ -5499,7 +5515,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable
|
||||
{
|
||||
if (InGameClient.Game.ActiveNephalemTimer && InGameClient.Game.ActiveNephalemKilledMobs == false)
|
||||
{
|
||||
InGameClient.Game.ActiveNephalemProgress += 15f * GameServerConfig.Instance.NephalemRiftProgressMultiplier;
|
||||
InGameClient.Game.ActiveNephalemProgress += 15f * GameModsConfig.Instance.NephalemRift.ProgressMultiplier;
|
||||
foreach (var plr in InGameClient.Game.Players.Values)
|
||||
{
|
||||
plr.InGameClient.SendMessage(new FloatDataMessage(Opcodes.DunggeonFinderProgressGlyphPickUp)
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using DiIiS_NA.D3_GameServer;
|
||||
using DiIiS_NA.GameServer.GSSystem.PlayerSystem;
|
||||
using DiIiS_NA.GameServer.GSSystem.TickerSystem;
|
||||
using DiIiS_NA.LoginServer;
|
||||
@ -12,8 +13,8 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Implementations.General
|
||||
public override IEnumerable<TickTimer> Run()
|
||||
{
|
||||
if (User is not Player player) yield break;
|
||||
player.AddPercentageHP(GameServerConfig.Instance.HealthPotionRestorePercentage);
|
||||
AddBuff(player, player, new CooldownBuff(30211, TickTimer.WaitSeconds(player.World.Game, GameServerConfig.Instance.HealthPotionCooldown)));
|
||||
player.AddPercentageHP(GameModsConfig.Instance.Health.PotionRestorePercentage);
|
||||
AddBuff(player, player, new CooldownBuff(30211, TickTimer.WaitSeconds(player.World.Game, GameModsConfig.Instance.Health.PotionCooldown)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,6 +14,7 @@ using DiIiS_NA.GameServer.GSSystem.PowerSystem.Implementations;
|
||||
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Effect;
|
||||
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Combat;
|
||||
using DiIiS_NA.Core.Helpers.Math;
|
||||
using DiIiS_NA.D3_GameServer;
|
||||
using DiIiS_NA.LoginServer.Toons;
|
||||
using DiIiS_NA.GameServer.Core.Types.TagMap;
|
||||
using DiIiS_NA.GameServer.GSSystem.GeneratorsSystem;
|
||||
@ -425,7 +426,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Payloads
|
||||
{
|
||||
grantedExp = (int)(grantedExp * rangedPlayer.World.Game.XpModifier);
|
||||
|
||||
float tempExp = grantedExp * GameServerConfig.Instance.RateExp;
|
||||
float tempExp = grantedExp * GameModsConfig.Instance.Rate.Experience;
|
||||
|
||||
rangedPlayer.UpdateExp(Math.Max((int)tempExp, 1));
|
||||
var a = (int)rangedPlayer.Attributes[GameAttributes.Experience_Bonus];
|
||||
@ -636,13 +637,13 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Payloads
|
||||
Target.World.Game.ActiveNephalemTimer && Target.World.Game.ActiveNephalemKilledMobs == false)
|
||||
{
|
||||
Target.World.Game.ActiveNephalemProgress +=
|
||||
GameServerConfig.Instance.NephalemRiftProgressMultiplier * (Target.Quality + 1);
|
||||
GameModsConfig.Instance.NephalemRift.ProgressMultiplier * (Target.Quality + 1);
|
||||
Player master = null;
|
||||
foreach (var plr3 in Target.World.Game.Players.Values)
|
||||
{
|
||||
if (plr3.PlayerIndex == 0)
|
||||
master = plr3;
|
||||
if (GameServerConfig.Instance.NephalemRiftAutoFinish && Target.World.Monsters.Count(s => !s.Dead) <= GameServerConfig.Instance.NephalemRiftAutoFinishThreshold) Target.World.Game.ActiveNephalemProgress = 651;
|
||||
if (GameModsConfig.Instance.NephalemRift.AutoFinish && Target.World.Monsters.Count(s => !s.Dead) <= GameModsConfig.Instance.NephalemRift.AutoFinishThreshold) Target.World.Game.ActiveNephalemProgress = 651;
|
||||
plr3.InGameClient.SendMessage(new SimpleMessage(Opcodes.KillCounterRefresh));
|
||||
plr3.InGameClient.SendMessage(new FloatDataMessage(Opcodes.DungeonFinderProgressMessage)
|
||||
{
|
||||
@ -711,7 +712,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Payloads
|
||||
|
||||
}
|
||||
|
||||
if (Target.Quality > 1 || FastRandom.Instance.Chance(GameServerConfig.Instance.NephalemRiftOrbsChance))
|
||||
if (Target.Quality > 1 || FastRandom.Instance.Chance(GameModsConfig.Instance.NephalemRift.OrbsChance))
|
||||
{
|
||||
//spawn spheres for mining indicator
|
||||
for (int i = 0; i < Target.Quality + 1; i++)
|
||||
@ -938,7 +939,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Payloads
|
||||
// if seed is less than the drop rate, drop the item
|
||||
if (seed < rate * (1f
|
||||
+ lootSpawnPlayer.Attributes[GameAttributes.Magic_Find])
|
||||
* GameServerConfig.Instance.RateDrop)
|
||||
* GameModsConfig.Instance.Rate.Drop)
|
||||
{
|
||||
//Logger.Debug("rate: {0}", rate);
|
||||
var lootQuality = Target.World.Game.IsHardcore
|
||||
|
||||
257
src/DiIiS-NA/D3-GameServer/GameModsConfig.cs
Normal file
257
src/DiIiS-NA/D3-GameServer/GameModsConfig.cs
Normal file
@ -0,0 +1,257 @@
|
||||
using System;
|
||||
using System.Dynamic;
|
||||
using System.IO;
|
||||
using DiIiS_NA;
|
||||
using DiIiS_NA.Core.Logging;
|
||||
using DiIiS_NA.GameServer;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace DiIiS_NA.D3_GameServer;
|
||||
|
||||
public class RateConfig
|
||||
{
|
||||
public float Experience { get; set; } = 1;
|
||||
public float Money { get; set; } = 1;
|
||||
public float Drop { get; set; } = 1;
|
||||
public float ChangeDrop { get; set; } = 1;
|
||||
}
|
||||
|
||||
public class HealthConfig
|
||||
{
|
||||
public float PotionRestorePercentage { get; set; } = 60f;
|
||||
public float PotionCooldown { get; set; } = 30f;
|
||||
public int ResurrectionCharges { get; set; } = 3;
|
||||
}
|
||||
|
||||
public class HealthDamageMultiplier
|
||||
{
|
||||
public float HealthMultiplier { get; set; } = 1;
|
||||
public float DamageMultiplier { get; set; } = 1;
|
||||
}
|
||||
|
||||
public class QuestConfig
|
||||
{
|
||||
public bool AutoSave { get; set; } = false;
|
||||
public bool UnlockAllWaypoints { get; set; } = false;
|
||||
}
|
||||
|
||||
public class PlayerMultiplierConfig
|
||||
{
|
||||
public ParagonConfig<float> Strength { get; set; } = new(1f);
|
||||
public ParagonConfig<float> Dexterity { get; set; } = new(1f);
|
||||
public ParagonConfig<float> Intelligence { get; set; } = new(1f);
|
||||
public ParagonConfig<float> Vitality { get; set; } = new(1f);
|
||||
}
|
||||
public class PlayerConfig
|
||||
{
|
||||
public PlayerMultiplierConfig Multipliers = new();
|
||||
}
|
||||
|
||||
public class ItemsConfig
|
||||
{
|
||||
public UnidentifiedDrop UnidentifiedDropChances { get; set; } = new();
|
||||
}
|
||||
|
||||
public class UnidentifiedDrop
|
||||
{
|
||||
public float HighQuality { get; set; } = 30f;
|
||||
public float NormalQuality { get; set; } = 5f;
|
||||
}
|
||||
|
||||
public class MinimapConfig
|
||||
{
|
||||
public bool ForceVisibility { get; set; } = false;
|
||||
}
|
||||
|
||||
public class NephalemRiftConfig
|
||||
{
|
||||
public float ProgressMultiplier { get; set; } = 1f;
|
||||
public bool AutoFinish { get; set; } = false;
|
||||
public int AutoFinishThreshold { get; set; } = 2;
|
||||
public float OrbsChance { get; set; } = 0f;
|
||||
}
|
||||
|
||||
public class GameModsConfig
|
||||
{
|
||||
public RateConfig Rate { get; set; } = new();
|
||||
public HealthConfig Health { get; set; } = new();
|
||||
public HealthDamageMultiplier Monster { get; set; } = new();
|
||||
public HealthDamageMultiplier Boss { get; set; } = new();
|
||||
public QuestConfig Quest { get; set; } = new();
|
||||
public PlayerConfig Player { get; set; } = new();
|
||||
public ItemsConfig Items { get; set; } = new();
|
||||
public MinimapConfig Minimap { get; set; } = new();
|
||||
public NephalemRiftConfig NephalemRift { get; set; } = new();
|
||||
|
||||
private static readonly Logger Logger = LogManager.CreateLogger();
|
||||
|
||||
public GameModsConfig() {}
|
||||
|
||||
static GameModsConfig()
|
||||
{
|
||||
CreateInstance();
|
||||
}
|
||||
|
||||
public static void ReloadSettings()
|
||||
{
|
||||
CreateInstance(reload: true);
|
||||
}
|
||||
|
||||
private static readonly object InstanceCreationLock = new();
|
||||
public static GameModsConfig Instance { get; private set; }
|
||||
|
||||
private static void CreateInstance(bool reload = false)
|
||||
{
|
||||
lock (InstanceCreationLock)
|
||||
{
|
||||
if (reload && File.Exists("config.mods.json")) File.Delete("config.mods.json");
|
||||
if (reload || !File.Exists("config.mods.json"))
|
||||
{
|
||||
Instance = CreateDefaultFile();
|
||||
}
|
||||
else
|
||||
{
|
||||
var content = File.ReadAllText("config.mods.json");
|
||||
if (content.TryFromJson(out GameModsConfig config, out Exception ex))
|
||||
{
|
||||
Logger.Success("Game mods loaded successfully!");
|
||||
Instance = config;
|
||||
return;
|
||||
}
|
||||
|
||||
Logger.Fatal("An error occured whilst loading $[white on red]$config.mods.json$[/]$ file. Please verify if the file is correct. Delete the file and try again.");
|
||||
Program.Shutdown(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static GameModsConfig CreateDefaultFile()
|
||||
{
|
||||
var migration = GameServerConfig.Instance;
|
||||
Logger.Info("$[blue]$Migrating mods configuration file...$[/]$");
|
||||
GameModsConfig content = new()
|
||||
{
|
||||
#pragma warning disable CS0618
|
||||
Rate =
|
||||
{
|
||||
Experience = migration.RateExp,
|
||||
Money = migration.RateMoney,
|
||||
ChangeDrop = migration.RateChangeDrop,
|
||||
Drop = migration.RateDrop
|
||||
},
|
||||
Health =
|
||||
{
|
||||
ResurrectionCharges = migration.ResurrectionCharges,
|
||||
PotionCooldown = migration.HealthPotionCooldown,
|
||||
PotionRestorePercentage = migration.HealthPotionRestorePercentage
|
||||
},
|
||||
Monster =
|
||||
{
|
||||
HealthMultiplier = migration.RateMonsterHP,
|
||||
DamageMultiplier = migration.RateMonsterDMG
|
||||
},
|
||||
Boss =
|
||||
{
|
||||
HealthMultiplier = migration.BossHealthMultiplier,
|
||||
DamageMultiplier = migration.BossDamageMultiplier
|
||||
},
|
||||
Quest =
|
||||
{
|
||||
AutoSave = migration.AutoSaveQuests,
|
||||
UnlockAllWaypoints = migration.UnlockAllWaypoints
|
||||
},
|
||||
Player =
|
||||
{
|
||||
Multipliers =
|
||||
{
|
||||
Strength = new(migration.StrengthMultiplier, migration.StrengthParagonMultiplier),
|
||||
Dexterity = new(migration.DexterityMultiplier, migration.DexterityParagonMultiplier),
|
||||
Intelligence = new(migration.IntelligenceMultiplier, migration.IntelligenceParagonMultiplier),
|
||||
Vitality = new(migration.VitalityMultiplier, migration.VitalityParagonMultiplier)
|
||||
}
|
||||
},
|
||||
Items =
|
||||
{
|
||||
UnidentifiedDropChances =
|
||||
{
|
||||
HighQuality = migration.ChanceHighQualityUnidentified,
|
||||
NormalQuality = migration.ChanceNormalUnidentified
|
||||
}
|
||||
},
|
||||
Minimap =
|
||||
{
|
||||
ForceVisibility = migration.ForceMinimapVisibility
|
||||
},
|
||||
NephalemRift =
|
||||
{
|
||||
AutoFinish = migration.NephalemRiftAutoFinish,
|
||||
AutoFinishThreshold = migration.NephalemRiftAutoFinishThreshold,
|
||||
OrbsChance = migration.NephalemRiftAutoFinishThreshold,
|
||||
ProgressMultiplier = migration.NephalemRiftProgressMultiplier
|
||||
}
|
||||
#pragma warning restore CS0618
|
||||
};
|
||||
File.WriteAllText("config.mods.json", content.ToJson());
|
||||
|
||||
if (Program.Build == 30 && Program.Stage < 6)
|
||||
{
|
||||
Logger.Success(
|
||||
"$[underline]$Migration is complete!$[/]$ - All game mods migrated from $[white]$config.ini$[/]$ to $[white]$config.mods.json$[/]$.");
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
}
|
||||
|
||||
public static class JsonExtensions
|
||||
{
|
||||
private const bool Indented = true;
|
||||
|
||||
public static string ToJson(this object obj, Formatting? formatting = null)
|
||||
{
|
||||
return JsonConvert.SerializeObject(obj, formatting ?? (Indented ? Formatting.Indented : Formatting.None));
|
||||
}
|
||||
|
||||
public static bool TryFromJson<T>(this string obj, out T value)
|
||||
where T: class, new()
|
||||
{
|
||||
try
|
||||
{
|
||||
value = obj.FromJson<T>();
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool TryFromJson<T>(this string obj, out T value, out Exception exception)
|
||||
where T: class, new()
|
||||
{
|
||||
try
|
||||
{
|
||||
value = obj.FromJson<T>();
|
||||
exception = null;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
value = default;
|
||||
exception = ex;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static T FromJson<T>(this string obj)
|
||||
where T: class, new()
|
||||
{
|
||||
return JsonConvert.DeserializeObject<T>(obj);
|
||||
}
|
||||
|
||||
public static dynamic FromJsonDynamic(this string obj)
|
||||
{
|
||||
return obj.FromJson<ExpandoObject>();
|
||||
}
|
||||
}
|
||||
@ -71,6 +71,7 @@ namespace DiIiS_NA.GameServer
|
||||
/// <summary>
|
||||
/// Rate of experience gain.
|
||||
/// </summary>
|
||||
[Obsolete("Use GameModsConfig instead.")]
|
||||
public float RateExp
|
||||
{
|
||||
get => GetFloat(nameof(RateExp), 1);
|
||||
@ -80,6 +81,7 @@ namespace DiIiS_NA.GameServer
|
||||
/// <summary>
|
||||
/// Rate of gold gain.
|
||||
/// </summary>
|
||||
[Obsolete("Use GameModsConfig instead.")]
|
||||
public float RateMoney
|
||||
{
|
||||
get => GetFloat(nameof(RateMoney), 1);
|
||||
@ -89,12 +91,14 @@ namespace DiIiS_NA.GameServer
|
||||
/// <summary>
|
||||
/// Rate of item drop.
|
||||
/// </summary>
|
||||
[Obsolete("Use GameModsConfig instead.")]
|
||||
public float RateDrop
|
||||
{
|
||||
get => GetFloat(nameof(RateDrop), 1);
|
||||
set => Set(nameof(RateDrop), value);
|
||||
}
|
||||
|
||||
[Obsolete("Use GameModsConfig instead.")]
|
||||
public float RateChangeDrop
|
||||
{
|
||||
get => GetFloat(nameof(RateChangeDrop), 1);
|
||||
@ -104,6 +108,7 @@ namespace DiIiS_NA.GameServer
|
||||
/// <summary>
|
||||
/// Rate of monster's HP.
|
||||
/// </summary>
|
||||
[Obsolete("Use GameModsConfig instead.")]
|
||||
public float RateMonsterHP
|
||||
{
|
||||
get => GetFloat(nameof(RateMonsterHP), 1);
|
||||
@ -113,6 +118,7 @@ namespace DiIiS_NA.GameServer
|
||||
/// <summary>
|
||||
/// Rate of monster's damage.
|
||||
/// </summary>
|
||||
[Obsolete("Use GameModsConfig instead.")]
|
||||
public float RateMonsterDMG
|
||||
{
|
||||
get => GetFloat(nameof(RateMonsterDMG), 1);
|
||||
@ -122,6 +128,7 @@ namespace DiIiS_NA.GameServer
|
||||
/// <summary>
|
||||
/// Percentage that a unique, legendary, set or special item created is unidentified
|
||||
/// </summary>
|
||||
[Obsolete("Use GameModsConfig instead.")]
|
||||
public float ChanceHighQualityUnidentified
|
||||
{
|
||||
get => GetFloat(nameof(ChanceHighQualityUnidentified), 30f);
|
||||
@ -131,6 +138,7 @@ namespace DiIiS_NA.GameServer
|
||||
/// <summary>
|
||||
/// Percentage that a normal item created is unidentified
|
||||
/// </summary>
|
||||
[Obsolete("Use GameModsConfig instead.")]
|
||||
public float ChanceNormalUnidentified
|
||||
{
|
||||
get => GetFloat(nameof(ChanceNormalUnidentified), 5f);
|
||||
@ -140,6 +148,7 @@ namespace DiIiS_NA.GameServer
|
||||
/// <summary>
|
||||
/// Resurrection charges on changing worlds
|
||||
/// </summary>
|
||||
[Obsolete("Use GameModsConfig instead.")]
|
||||
public int ResurrectionCharges
|
||||
{
|
||||
get => GetInt(nameof(ResurrectionCharges), 3);
|
||||
@ -149,6 +158,7 @@ namespace DiIiS_NA.GameServer
|
||||
/// <summary>
|
||||
/// Boss Health Multiplier
|
||||
/// </summary>
|
||||
[Obsolete("Use GameModsConfig instead.")]
|
||||
public float BossHealthMultiplier
|
||||
{
|
||||
get => GetFloat(nameof(BossHealthMultiplier), 6f);
|
||||
@ -158,6 +168,7 @@ namespace DiIiS_NA.GameServer
|
||||
/// <summary>
|
||||
/// Boss Damage Multiplier
|
||||
/// </summary>
|
||||
[Obsolete("Use GameModsConfig instead.")]
|
||||
public float BossDamageMultiplier
|
||||
{
|
||||
get => GetFloat(nameof(BossDamageMultiplier), 3f);
|
||||
@ -167,6 +178,7 @@ namespace DiIiS_NA.GameServer
|
||||
/// <summary>
|
||||
/// Whether to bypass the quest's settings of "Saveable" to TRUE (unless in OpenWorld)
|
||||
/// </summary>
|
||||
[Obsolete("Use GameModsConfig instead.")]
|
||||
public bool AutoSaveQuests
|
||||
{
|
||||
get => GetBoolean(nameof(AutoSaveQuests), false);
|
||||
@ -176,6 +188,7 @@ namespace DiIiS_NA.GameServer
|
||||
/// <summary>
|
||||
/// Progress gained when killing a monster in Nephalem Rifts
|
||||
/// </summary>
|
||||
[Obsolete("Use GameModsConfig instead.")]
|
||||
public float NephalemRiftProgressMultiplier
|
||||
{
|
||||
get => GetFloat(nameof(NephalemRiftProgressMultiplier), 1f);
|
||||
@ -185,6 +198,7 @@ namespace DiIiS_NA.GameServer
|
||||
/// <summary>
|
||||
/// How much a health potion heals in percentage
|
||||
/// </summary>
|
||||
[Obsolete("Use GameModsConfig instead.")]
|
||||
public float HealthPotionRestorePercentage
|
||||
{
|
||||
get => GetFloat(nameof(HealthPotionRestorePercentage), 60f);
|
||||
@ -194,6 +208,7 @@ namespace DiIiS_NA.GameServer
|
||||
/// <summary>
|
||||
/// Cooldown (in seconds) to use a health potion again.
|
||||
/// </summary>
|
||||
[Obsolete("Use GameModsConfig instead.")]
|
||||
public float HealthPotionCooldown
|
||||
{
|
||||
get => GetFloat(nameof(HealthPotionCooldown), 30f);
|
||||
@ -203,6 +218,7 @@ namespace DiIiS_NA.GameServer
|
||||
/// <summary>
|
||||
/// Unlocks all waypoints in the campaign.
|
||||
/// </summary>
|
||||
[Obsolete("Use GameModsConfig instead.")]
|
||||
public bool UnlockAllWaypoints
|
||||
{
|
||||
get => GetBoolean(nameof(UnlockAllWaypoints), false);
|
||||
@ -212,6 +228,7 @@ namespace DiIiS_NA.GameServer
|
||||
/// <summary>
|
||||
/// Strength multiplier when you're not a paragon.
|
||||
/// </summary>
|
||||
[Obsolete("Use GameModsConfig instead.")]
|
||||
public float StrengthMultiplier
|
||||
{
|
||||
get => GetFloat(nameof(StrengthMultiplier), 1f);
|
||||
@ -221,6 +238,7 @@ namespace DiIiS_NA.GameServer
|
||||
/// <summary>
|
||||
/// Strength multiplier when you're a paragon.
|
||||
/// </summary>
|
||||
[Obsolete("Use GameModsConfig instead.")]
|
||||
public float StrengthParagonMultiplier
|
||||
{
|
||||
get => GetFloat(nameof(StrengthParagonMultiplier), 1f);
|
||||
@ -230,6 +248,7 @@ namespace DiIiS_NA.GameServer
|
||||
/// <summary>
|
||||
/// Dexterity multiplier when you're not a paragon.
|
||||
/// </summary>
|
||||
[Obsolete("Use GameModsConfig instead.")]
|
||||
public float DexterityMultiplier
|
||||
{
|
||||
get => GetFloat(nameof(DexterityMultiplier), 1f);
|
||||
@ -239,6 +258,7 @@ namespace DiIiS_NA.GameServer
|
||||
/// <summary>
|
||||
/// Dexterity multiplier when you're a paragon.
|
||||
/// </summary>
|
||||
[Obsolete("Use GameModsConfig instead.")]
|
||||
public float DexterityParagonMultiplier
|
||||
{
|
||||
get => GetFloat(nameof(DexterityParagonMultiplier), 1f);
|
||||
@ -248,6 +268,7 @@ namespace DiIiS_NA.GameServer
|
||||
/// <summary>
|
||||
/// Intelligence multiplier when you're not a paragon.
|
||||
/// </summary>
|
||||
[Obsolete("Use GameModsConfig instead.")]
|
||||
public float IntelligenceMultiplier
|
||||
{
|
||||
get => GetFloat(nameof(IntelligenceMultiplier), 1f);
|
||||
@ -257,6 +278,7 @@ namespace DiIiS_NA.GameServer
|
||||
/// <summary>
|
||||
/// Intelligence multiplier when you're a paragon.
|
||||
/// </summary>
|
||||
[Obsolete("Use GameModsConfig instead.")]
|
||||
public float IntelligenceParagonMultiplier
|
||||
{
|
||||
get => GetFloat(nameof(IntelligenceParagonMultiplier), 1f);
|
||||
@ -266,6 +288,7 @@ namespace DiIiS_NA.GameServer
|
||||
/// <summary>
|
||||
/// Vitality multiplier when you're not a paragon.
|
||||
/// </summary>
|
||||
[Obsolete("Use GameModsConfig instead.")]
|
||||
public float VitalityMultiplier
|
||||
{
|
||||
get => GetFloat(nameof(VitalityMultiplier), 1f);
|
||||
@ -275,6 +298,7 @@ namespace DiIiS_NA.GameServer
|
||||
/// <summary>
|
||||
/// Vitality multiplier when you're a paragon.
|
||||
/// </summary>
|
||||
[Obsolete("Use GameModsConfig instead.")]
|
||||
public float VitalityParagonMultiplier
|
||||
{
|
||||
get => GetFloat(nameof(VitalityParagonMultiplier), 1f);
|
||||
@ -284,6 +308,7 @@ namespace DiIiS_NA.GameServer
|
||||
/// <summary>
|
||||
/// Auto finishes nephalem rift when there's <see cref="NephalemRiftAutoFinishThreshold"></see> or less monsters left.
|
||||
/// </summary>
|
||||
[Obsolete("Use GameModsConfig instead.")]
|
||||
public bool NephalemRiftAutoFinish
|
||||
{
|
||||
get => GetBoolean(nameof(NephalemRiftAutoFinish), false);
|
||||
@ -293,6 +318,7 @@ namespace DiIiS_NA.GameServer
|
||||
/// <summary>
|
||||
/// If <see cref="NephalemRiftAutoFinish"></see> is enabled, this is the threshold.
|
||||
/// </summary>
|
||||
[Obsolete("Use GameModsConfig instead.")]
|
||||
public int NephalemRiftAutoFinishThreshold
|
||||
{
|
||||
get => GetInt(nameof(NephalemRiftAutoFinishThreshold), 2);
|
||||
@ -302,6 +328,7 @@ namespace DiIiS_NA.GameServer
|
||||
/// <summary>
|
||||
/// Nephalem Rifts chance of spawning a orb.
|
||||
/// </summary>
|
||||
[Obsolete("Use GameModsConfig instead.")]
|
||||
public float NephalemRiftOrbsChance
|
||||
{
|
||||
get => GetFloat(nameof(NephalemRiftOrbsChance), 0f);
|
||||
@ -311,6 +338,7 @@ namespace DiIiS_NA.GameServer
|
||||
/// <summary>
|
||||
/// Forces the game to reveal all the map.
|
||||
/// </summary>
|
||||
[Obsolete("Use GameModsConfig instead.")]
|
||||
public bool ForceMinimapVisibility
|
||||
{
|
||||
get => GetBoolean(nameof(ForceMinimapVisibility), false);
|
||||
|
||||
16
src/DiIiS-NA/D3-GameServer/ParagonMod.cs
Normal file
16
src/DiIiS-NA/D3-GameServer/ParagonMod.cs
Normal file
@ -0,0 +1,16 @@
|
||||
public class ParagonConfig<T>
|
||||
{
|
||||
public T Normal { get; set; }
|
||||
public T Paragon { get; set; }
|
||||
|
||||
public ParagonConfig() {}
|
||||
public ParagonConfig(T defaultValue) : this(defaultValue, defaultValue)
|
||||
{
|
||||
}
|
||||
|
||||
public ParagonConfig(T normal, T paragon)
|
||||
{
|
||||
Normal = normal;
|
||||
Paragon = paragon;
|
||||
}
|
||||
}
|
||||
@ -33,6 +33,7 @@ using System.Security.Permissions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using DiIiS_NA.Core.Extensions;
|
||||
using DiIiS_NA.D3_GameServer;
|
||||
using Spectre.Console;
|
||||
using Environment = System.Environment;
|
||||
|
||||
@ -65,11 +66,19 @@ namespace DiIiS_NA
|
||||
public static string RestServerIp = RestConfig.Instance.IP;
|
||||
public static string PublicGameServerIp = DiIiS_NA.GameServer.NATConfig.Instance.PublicIP;
|
||||
|
||||
public static int Build => 30;
|
||||
public static int Stage => 2;
|
||||
public const int Build = 30;
|
||||
public const int Stage = 3;
|
||||
public static TypeBuildEnum TypeBuild => TypeBuildEnum.Beta;
|
||||
private static bool DiabloCoreEnabled = DiIiS_NA.GameServer.GameServerConfig.Instance.CoreActive;
|
||||
|
||||
private static readonly CancellationTokenSource CancellationTokenSource = new();
|
||||
public static readonly CancellationToken Token = CancellationTokenSource.Token;
|
||||
public static void Cancel() => CancellationTokenSource.Cancel();
|
||||
public static void CancelAfter(TimeSpan span) => CancellationTokenSource.CancelAfter(span);
|
||||
public static bool IsCancellationRequested() => CancellationTokenSource.IsCancellationRequested;
|
||||
|
||||
public void MergeCancellationWith(params CancellationToken[] tokens) =>
|
||||
CancellationTokenSource.CreateLinkedTokenSource(tokens);
|
||||
static void WriteBanner()
|
||||
{
|
||||
void RightTextRule(string text, string ruleStyle) => AnsiConsole.Write(new Rule(text).RuleStyle(ruleStyle));
|
||||
@ -104,7 +113,7 @@ namespace DiIiS_NA
|
||||
if (!DiabloCoreEnabled)
|
||||
Logger.Warning("Diablo III Core is $[red]$disabled$[/]$.");
|
||||
#endif
|
||||
|
||||
var mod = GameModsConfig.Instance;
|
||||
#pragma warning disable CS4014
|
||||
Task.Run(async () =>
|
||||
#pragma warning restore CS4014
|
||||
@ -126,6 +135,9 @@ namespace DiIiS_NA
|
||||
$"Memory: {totalMemory:0.000} GB | " +
|
||||
$"CPU Time: {cpuTime.ToSmallText()} | " +
|
||||
$"Uptime: {uptime.ToSmallText()}";
|
||||
|
||||
if (IsCancellationRequested())
|
||||
text = "SHUTTING DOWN: " + text;
|
||||
if (SetTitle(text))
|
||||
await Task.Delay(1000);
|
||||
else
|
||||
@ -242,15 +254,15 @@ namespace DiIiS_NA
|
||||
|
||||
IChannel boundChannel = await serverBootstrap.BindAsync(loginConfig.Port);
|
||||
|
||||
Logger.Info(
|
||||
"$[bold red3_1]$Tip:$[/]$ graceful shutdown with $[red3_1]$CTRL+C$[/]$ or $[red3_1]$!q[uit]$[/]$ or $[red3_1]$!exit$[/]$.");
|
||||
Logger.Info("$[bold red3_1]$" +
|
||||
"Tip:$[/]$ SNO breakdown with $[red3_1]$!sno$[/]$ $[red3_1]$<fullSnoBreakdown(true:false)>$[/]$.");
|
||||
while (true)
|
||||
Logger.Info("$[bold deeppink4]$Gracefully$[/]$ shutdown with $[red3_1]$CTRL+C$[/]$ or $[deeppink4]$!q[uit]$[/]$.");
|
||||
while (!IsCancellationRequested())
|
||||
{
|
||||
var line = Console.ReadLine();
|
||||
if (line is null or "!q" or "!quit" or "!exit")
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (line is "!cls" or "!clear" or "cls" or "clear")
|
||||
{
|
||||
AnsiConsole.Clear();
|
||||
@ -272,9 +284,11 @@ namespace DiIiS_NA
|
||||
|
||||
if (PlayerManager.OnlinePlayers.Count > 0)
|
||||
{
|
||||
Logger.Success("Gracefully shutting down...");
|
||||
Logger.Info(
|
||||
$"Server is shutting down in 1 minute, $[blue]${PlayerManager.OnlinePlayers.Count} players$[/]$ are still online.");
|
||||
PlayerManager.SendWhisper("Server is shutting down in 1 minute.");
|
||||
|
||||
await Task.Delay(TimeSpan.FromMinutes(1));
|
||||
}
|
||||
|
||||
@ -292,16 +306,22 @@ namespace DiIiS_NA
|
||||
}
|
||||
}
|
||||
|
||||
private static void Shutdown(Exception exception = null)
|
||||
{
|
||||
// if (!IsTargetEnabled("ansi"))
|
||||
private static bool _shuttingDown = false;
|
||||
public static void Shutdown(Exception exception = null)
|
||||
{
|
||||
if (_shuttingDown) return;
|
||||
_shuttingDown = true;
|
||||
if (!IsCancellationRequested())
|
||||
Cancel();
|
||||
|
||||
AnsiTarget.StopIfRunning(IsTargetEnabled("ansi"));
|
||||
if (exception != null)
|
||||
{
|
||||
AnsiConsole.WriteLine("An unhandled exception occured at initialization. Please report this to the developers.");
|
||||
AnsiConsole.WriteLine(
|
||||
"An unhandled exception occured at initialization. Please report this to the developers.");
|
||||
AnsiConsole.WriteException(exception);
|
||||
}
|
||||
|
||||
AnsiConsole.Progress().Start(ctx =>
|
||||
{
|
||||
var task = ctx.AddTask("[darkred_1]Shutting down[/] [white]in[/] [red underline]10 seconds[/]");
|
||||
@ -312,15 +332,13 @@ namespace DiIiS_NA
|
||||
{
|
||||
task.Increment(1);
|
||||
Thread.Sleep(100);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
task.Description = $"[darkred_1]Shutting down[/]";
|
||||
|
||||
task.Description = $"[darkred_1]Shutting down now.[/]";
|
||||
task.StopTask();
|
||||
});
|
||||
}
|
||||
|
||||
Environment.Exit(exception is null ? 0 : -1);
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
user.block.title