Improvement world bosses;

Command to open all doors;
Do not show logs of colors
This commit is contained in:
Lucca Faria Ferri 2023-01-31 09:09:37 -08:00
parent b95ab45e62
commit 8c9dc3c9d5
10 changed files with 287 additions and 142 deletions

View File

@ -2,6 +2,7 @@
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading;
namespace DiIiS_NA.Core.Logging
@ -24,48 +25,55 @@ namespace DiIiS_NA.Core.Logging
/// <param name="reset">Reset log file on application startup?</param>
public FileTarget(string fileName, Logger.Level minLevel, Logger.Level maxLevel, bool includeTimeStamps, bool reset = false)
{
this.MinimumLevel = minLevel;
this.MaximumLevel = maxLevel;
this.IncludeTimeStamps = includeTimeStamps;
this._fileName = fileName;
this._fileTimestamp = DateTime.Now.ToString("yyyyMMdd_HHmm");
this._filePath = string.Format("{0}/{1}/{2}", LogConfig.Instance.LoggingRoot, this._fileTimestamp, _fileName);
this._fileIndex = 0;
MinimumLevel = minLevel;
MaximumLevel = maxLevel;
IncludeTimeStamps = includeTimeStamps;
_fileName = fileName;
_fileTimestamp = DateTime.Now.ToString("yyyy-MM-dd_HH-mm");
_filePath = $"{LogConfig.Instance.LoggingRoot}/{_fileTimestamp}/{_fileName}";
_fileIndex = 0;
if (!Directory.Exists(LogConfig.Instance.LoggingRoot)) // create logging directory if it does not exist yet.
Directory.CreateDirectory(LogConfig.Instance.LoggingRoot);
if (!Directory.Exists(string.Format("{0}/{1}", LogConfig.Instance.LoggingRoot, this._fileTimestamp))) // create logging directory if it does not exist yet.
Directory.CreateDirectory(string.Format("{0}/{1}", LogConfig.Instance.LoggingRoot, this._fileTimestamp));
if (!Directory.Exists($"{LogConfig.Instance.LoggingRoot}/{_fileTimestamp}")) // create logging directory if it does not exist yet.
Directory.CreateDirectory($"{LogConfig.Instance.LoggingRoot}/{_fileTimestamp}");
this._fileStream = new FileStream(_filePath, reset ? FileMode.Create : FileMode.Append, FileAccess.Write, FileShare.Read); // init the file stream.
this._logStream = new StreamWriter(this._fileStream) { AutoFlush = true }; // init the stream writer.
this.TaskQueue = new ConcurrentQueue<Action>();
this.LoggerThread = new Thread(this.CheckQueue) { Name = "Logger", IsBackground = true };
this.LoggerThread.Start();
_fileStream = new FileStream(_filePath, reset ? FileMode.Create : FileMode.Append, FileAccess.Write, FileShare.Read); // init the file stream.
_logStream = new StreamWriter(_fileStream) { AutoFlush = true }; // init the stream writer.
TaskQueue = new ConcurrentQueue<Action>();
LoggerThread = new Thread(CheckQueue) { Name = "Logger", IsBackground = true };
LoggerThread.Start();
}
public void CheckQueue()
{
while (true)
{
Action action = null;
if (this.TaskQueue.TryDequeue(out action))
if (TaskQueue.TryDequeue(out var action))
action.Invoke();
Thread.Sleep(1);
}
}
/// <summary>
/// Replace the colors from AnsiColor so they do not appear in the log file.
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
private string NoColors(string message) => Regex.Replace(message, @"\$\[[\w\W\d\s_\-\/]+\]\$", "");
/// <param name="level">Log level.</param>
/// <param name="logger">Source of the log message.</param>
/// <param name="message">Log message.</param>
public override void LogMessage(Logger.Level level, string logger, string message)
{
this.TaskQueue.Enqueue(() =>
TaskQueue.Enqueue(() =>
{
var timeStamp = this.IncludeTimeStamps ? "[" + DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss.fff") + "] " : "";
if (!this._disposed) // make sure we're not disposed.
message = NoColors(message);
var timeStamp = IncludeTimeStamps ? "[" + DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss.fff") + "] " : "";
if (!_disposed) // make sure we're not disposed.
{
/*
if (this._fileStream.Length >= 20971520) //20 MB limit
@ -77,9 +85,9 @@ namespace DiIiS_NA.Core.Logging
}
//*/
if (level > Logger.Level.ChatMessage)
this._logStream.WriteLine(string.Format("{0}[{1}] [{2}]: {3}", timeStamp, level.ToString().PadLeft(5), logger, message));
_logStream.WriteLine($"{timeStamp}[{level.ToString(),5}] [{logger}]: {message}");
else
this._logStream.WriteLine(string.Format("{0}{1}", timeStamp, message));
_logStream.WriteLine($"{timeStamp}{message}");
}
});
}
@ -90,12 +98,13 @@ namespace DiIiS_NA.Core.Logging
/// <param name="exception">Exception to be included with log message.</param>
public override void LogException(Logger.Level level, string logger, string message, Exception exception)
{
this.TaskQueue.Enqueue(() =>
TaskQueue.Enqueue(() =>
{
var timeStamp = this.IncludeTimeStamps ? "[" + DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss.fff") + "] " : "";
if (!this._disposed) // make sure we're not disposed.
message = NoColors(message);
var timeStamp = IncludeTimeStamps ? "[" + DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss.fff") + "] " : "";
if (!_disposed) // make sure we're not disposed.
{
this._logStream.WriteLine(
_logStream.WriteLine(
$"{timeStamp}[{level.ToString(),5}] [{logger}]: {message} - [Exception] {exception}");
}
});
@ -109,23 +118,23 @@ namespace DiIiS_NA.Core.Logging
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this); // Take object out the finalization queue to prevent finalization code for it from executing a second time.
GC.SuppressFinalize(this); // Take object out the finalization queue to prevent finalization code for it from executing (~FileTarget).
}
private void Dispose(bool disposing)
{
if (this._disposed) return; // if already disposed, just return
if (_disposed) return; // if already disposed, just return
if (disposing) // only dispose managed resources if we're called from directly or in-directly from user code.
{
this._logStream.Close();
this._logStream.Dispose();
this._fileStream.Close();
this._fileStream.Dispose();
_logStream.Close();
_logStream.Dispose();
_fileStream.Close();
_fileStream.Dispose();
}
this._logStream = null;
this._fileStream = null;
_logStream = null;
_fileStream = null;
_disposed = true;
}

View File

@ -16,6 +16,7 @@ using DiIiS_NA.LoginServer.Battle;
using System;
using System.Collections.Generic;
using System.Linq;
using DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations;
using DiIiS_NA.GameServer.GSSystem.GameSystem;
using DiIiS_NA.GameServer.GSSystem.ObjectsSystem;
using DiIiS_NA.GameServer.GSSystem.PlayerSystem;
@ -25,6 +26,74 @@ using Actor = DiIiS_NA.Core.MPQ.FileFormats.Actor;
namespace DiIiS_NA.GameServer.CommandManager;
[CommandGroup("doors", "Information about all doors in the vicinity. This is useful for testing purposes.. Useful for testing.", Account.UserLevels.Tester)]
public class OpenDoorCommand : CommandGroup
{
[Command("all", "Activate all doors. This is useful for testing purposes.\nUsage: !open all", Account.UserLevels.Tester)]
public string OpenAllDoors(string[] @params, BattleClient invokerClient)
{
if (invokerClient?.InGameClient?.Player is not { } player)
return "You are not in game.";
var world = player.World;
var openedDoors = world.OpenAllDoors();
if (openedDoors.Length == 0)
return "No doors found.";
return $"Opened {openedDoors.Length} doors: {string.Join(", ", openedDoors.Select(d => (int)d.SNO + " - " + d.SNO))}";
}
[Command("near", "Activate all nearby doors in the vicinity. This is useful for testing purposes.\nUsage: !open near [distance:50]", Account.UserLevels.Tester)]
public string OpenAllDoorsNear(string[] @params, BattleClient invokerClient)
{
if (invokerClient?.InGameClient?.Player is not { } player)
return "You are not in game.";
var world = player.World;
var distance = 50f;
if (@params.Length > 0)
{
if (!float.TryParse(@params[0], out distance) || distance < 1)
return "Invalid distance. Distance must be greater than 1.";
}
var openedDoors = player.OpenNearDoors(distance);
if (openedDoors.Length == 0)
return "No doors found.";
return $"Opened {openedDoors.Count()} in a distance of {distance:0.0000} doors: {string.Join(", ", openedDoors)}";
}
[Command("info", "Retrieve all world doors in proximity, sorted in descending order.\nUsage: !open info [distance:50]", Account.UserLevels.Tester)]
public string InfoDoorsNear(string[] @params, BattleClient invokerClient)
{
if (invokerClient?.InGameClient?.Player is not { } player)
return "You are not in game.";
var world = player.World;
var distance = 50f;
if (@params.Length > 0)
{
if (!float.TryParse(@params[0], out distance) || distance < 1)
return "Invalid distance. Distance must be greater than 1.";
}
var doors = player.GetNearDoors(distance);
if (doors.Length == 0)
return "No doors found.";
return $"{doors.Length} doors in a distance of {distance:0.0000} doors: \n{string.Join("\n", doors.Select(s=>
{
var position = player.Position;
return s.Position.DistanceSquared(ref position) + " distance - [" + (int)s.SNO + "] " + s.SNO;;
}))}";
}
[DefaultCommand()]
public string DefaultCommand(string[] @params, BattleClient invokerClient)
{
return "!doors all - Activate all doors. This is useful for testing purposes.\n" +
"!doors near [distance:50] - Activate all nearby doors in the vicinity. This is useful for testing purposes.\n" +
"!doors info [distance:50] - Retrieve all world doors in proximity, sorted in descending order.";
}
}
[CommandGroup("powerful", "Makes your character with absurd amount of damage. Useful for testing.",
Account.UserLevels.Tester)]
public class PowerfulCommand : CommandGroup

View File

@ -134,6 +134,24 @@ namespace DiIiS_NA.GameServer
set => Set(nameof(ResurrectionCharges), value);
}
/// <summary>
/// Boss Health Multiplier
/// </summary>
public float BossHealthMultiplier
{
get => GetFloat(nameof(BossHealthMultiplier), 6f);
set => Set(nameof(BossHealthMultiplier), value);
}
/// <summary>
/// Boss Damage Multiplier
/// </summary>
public float BossDamageMultiplier
{
get => GetFloat(nameof(BossDamageMultiplier), 3f);
set => Set(nameof(BossDamageMultiplier), value);
}
public static Config Instance { get; } = new();
private Config() : base("Game-Server")

View File

@ -104,7 +104,7 @@ namespace DiIiS_NA.GameServer.Core.Types.Math
/// </summary>
/// <param name="point">the second <see cref="Vector3" /></param>
/// <returns>the distance squared between the vectors</returns>
public float DistanceSquared(ref Vector3D point)
public float DistanceSquared(ref Vector3D point) // todo: remove ref
{
float x = point.X - X,
y = point.Y - Y,
@ -183,8 +183,6 @@ namespace DiIiS_NA.GameServer.Core.Types.Math
public override string ToString() => $"X:{X:F4}, Y:{Y:F4} Z:{Z:F4}";
public bool IsNear(Vector3D other, float distance) => DistanceSquared(ref other) < distance * distance;
public bool IsNearSquared(Vector3D other, float distanceSquared) => DistanceSquared(ref other) < distanceSquared;
public bool IsNear(Vector3D other, float distance) => DistanceSquared(ref other) < distance;
}
}

View File

@ -69,6 +69,7 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations
public sealed class Boss : Monster
{
private static readonly Logger Logger = LogManager.CreateLogger(nameof(Boss));
public Boss(MapSystem.World world, ActorSno sno, TagMap tags)
: base(world, sno, tags)
{
@ -77,14 +78,15 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations
//this.Attributes[GameAttribute.Immune_To_Charm] = true;
Attributes[GameAttribute.using_Bossbar] = true;
Attributes[GameAttribute.InBossEncounter] = true;
Attributes[GameAttribute.Hitpoints_Max] *= 4f;
Attributes[GameAttribute.Damage_Weapon_Min, 0] *= 3f;
Attributes[GameAttribute.Damage_Weapon_Delta, 0] *= 3f;
Attributes[GameAttribute.Hitpoints_Max] *= Config.Instance.BossHealthMultiplier;
Attributes[GameAttribute.Damage_Weapon_Min, 0] *= Config.Instance.BossDamageMultiplier;
Attributes[GameAttribute.Damage_Weapon_Delta, 0] *= Config.Instance.BossDamageMultiplier;
Attributes[GameAttribute.Hitpoints_Cur] = Attributes[GameAttribute.Hitpoints_Max_Total];
Attributes[GameAttribute.TeamID] = 10;
WalkSpeed *= 0.5f;
MonsterBrain monsterBrain = (Brain as MonsterBrain);
if (Brain is MonsterBrain monsterBrain)
{
switch (sno)
{
case ActorSno._diablo: //Diablo
@ -150,35 +152,41 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations
*/
break;
case ActorSno._skeletonking://Leoric King
case ActorSno._skeletonking: //Leoric King
monsterBrain.RemovePresetPower(30592);
monsterBrain.AddPresetPower(30496);
monsterBrain.AddPresetPower(30504);
monsterBrain.AddPresetPower(73824);
monsterBrain.AddPresetPower(79334);
break;
case ActorSno._butcher://Butcher
case ActorSno._butcher: //Butcher
monsterBrain.AddPresetPower(83008);
break;
case ActorSno._belial_trueform://Belial (small)
case ActorSno._belial_trueform: //Belial (small)
HasLoot = false;
break;
case ActorSno._belial://Belial (big)
case ActorSno._belial: //Belial (big)
monsterBrain.AddPresetPower(152540);
break;
case ActorSno._maghda://Maghda
case ActorSno._maghda: //Maghda
monsterBrain.AddPresetPower(131744); //summon berserker
//(Brain as MonsterBrain).AddPresetPower(131745); //mothDust
monsterBrain.AddPresetPower(131749); //teleport
break;
case ActorSno._gluttony://Gluttony
case ActorSno._gluttony: //Gluttony
monsterBrain.AddPresetPower(93676); //gas cloud
monsterBrain.AddPresetPower(211292); //slime spawn
break;
default:
Logger.Warn($"Unhandled boss type {sno}");
break;
}
}
else
{
Logger.Error($"Boss $[underline red]${GetType().Name}$[/]$ ({sno}) has no monster brain!");
}
}
public int AntiCCTriggerCount = 0;

View File

@ -16,7 +16,7 @@ using System.Threading.Tasks;
namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations
{
[HandledSNO(ActorSno._caout_stingingwinds_khamsin_gate)]
class Door : Gizmo
public class Door : Gizmo
{
public bool isOpened = false;
public Portal NearestPortal = null;
@ -75,12 +75,13 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations
public void Open()
{
Logger.MethodTrace($"Opening door $[underline green]${SNO}$[/]$ in world $[underline green]{World.SNO}$[/]$");
World.BroadcastIfRevealed(plr => new PlayAnimationMessage
{
ActorID = DynamicID(plr),
AnimReason = 5,
UnitAniimStartTime = 0,
tAnim = new PlayAnimationMessageSpec[]
tAnim = new[]
{
new PlayAnimationMessageSpec()
{
@ -115,8 +116,8 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations
TickerSystem.TickTimer Timeout = new TickerSystem.SecondsTickTimer(World.Game, 1.8f);
if (NearestPortal != null)
{
var Boom = Task<bool>.Factory.StartNew(() => WaitToSpawn(Timeout));
Boom.ContinueWith(delegate
var nearestPortalOpen = Task<bool>.Factory.StartNew(() => WaitToSpawn(Timeout));
nearestPortalOpen.ContinueWith(delegate
{
NearestPortal.SetVisible(true);
foreach (var plr in World.Players.Values)

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Drawing;
using System.Linq;
using System.Reflection;
@ -1495,5 +1496,21 @@ namespace DiIiS_NA.GameServer.GSSystem.MapSystem
{
return $"[World] SNOId: {WorldSNO.Id} GlobalId: {GlobalID} Name: {WorldSNO.Name}";
}
public ImmutableArray<Door> GetAllDoors() =>
Actors.Select(a => a.Value).Where(a => a is Door).Cast<Door>().ToImmutableArray();
public ImmutableArray<Door> OpenAllDoors()
{
List<Door> openedDoors = new();
var doors = GetAllDoors();
foreach (var door in doors)
{
openedDoors.Add(door);
door.Open();
}
return openedDoors.ToImmutableArray();
}
}
}

View File

@ -3,6 +3,7 @@
using System;
//Blizzless Project 2022
using System.Collections.Generic;
using System.Collections.Immutable;
//Blizzless Project 2022
using System.Linq;
//Blizzless Project 2022
@ -6181,4 +6182,23 @@ public class Player : Actor, IMessageConsumer, IUpdateable
Attributes[GameAttribute.Hitpoints_Total_From_Level] = Attributes[GameAttribute.Hitpoints_Max_Total];
Attributes.BroadcastChangedIfRevealed();
}
public ImmutableArray<Door> GetNearDoors(float distance = 50f)
{
var doors = World.GetAllDoors();
List<Door> doorList = doors.Where(door => door.Position.IsNear(Position, distance)).ToList();
return doorList.ToImmutableArray();
}
public ImmutableArray<Door> OpenNearDoors(float distance = 50f)
{
List<Door> openedDoors = new();
foreach (var door in GetNearDoors(distance))
{
openedDoors.Add(door);
door.Open();
}
return openedDoors.ToImmutableArray();
}
}

View File

@ -1070,7 +1070,7 @@ namespace DiIiS_NA.GameServer.GSSystem.QuestSystem
});
ListenKill(ActorSno._skeletonking_shield_skeleton, 4, new Advance());
ListenKill(ActorSno._skeletonking_shield_skeleton, 1, new Advance());
}
});
@ -1082,11 +1082,8 @@ namespace DiIiS_NA.GameServer.GSSystem.QuestSystem
Objectives = new List<Objective> { Objective.Default() },
OnAdvance = () =>
{ //take crown on Leoric's head
Game.AddOnLoadWorldAction(WorldSno.a1trdun_king_level08, () =>
{
Open(Game.GetWorld(WorldSno.a1trdun_king_level08), ActorSno._trdun_cath_gate_b_skeletonking);
});
//Open(this.Game.GetWorld(73261), 172645);
OpenAll(this.Game.GetWorld(WorldSno.a1trdun_king_level08));
ListenInteract(ActorSno._skeletonkinggizmo, 1, new Advance());
}
});
@ -1111,6 +1108,7 @@ namespace DiIiS_NA.GameServer.GSSystem.QuestSystem
Objectives = new List<Objective> { Objective.Default() },
OnAdvance = () =>
{ //go to fallen star room
Open(Game.GetWorld(WorldSno.a1trdun_king_level08), ActorSno._trdun_cath_gate_b_skeletonking);
Game.CurrentEncounter.Activated = false;
ListenTeleport(117411, new Advance());
Game.AddOnLoadWorldAction(WorldSno.a1trdun_king_level08, () =>

View File

@ -182,6 +182,13 @@ namespace DiIiS_NA.GameServer.GSSystem.QuestSystem
return true;
}
//opening all doors
protected void OpenAll(World world)
{
foreach (var actor in world.Actors.Select(s=>s.Value).Where(t=>t is Door).Cast<Door>())
(actor).Open();
}
protected bool OpenAll(World world, ActorSno sno)
{
foreach (var actor in world.GetActorsBySNO(sno).Where(d => d.Visible).ToList())