From 01be1f1eac4d0d234a096d0e38ce44beea860b1e Mon Sep 17 00:00:00 2001 From: caioavidal Date: Mon, 23 Dec 2024 17:42:18 -0300 Subject: [PATCH 1/8] Fix player location on login --- .../Player/PlayerLogInCommand.cs | 26 +++++++-- .../Services/PlayerLocationResolver.cs | 53 +++++++++++++++++++ .../Repositories/AccountRepository.cs | 2 +- .../Functions/TileFunctions.cs | 2 +- .../Contracts/World/Tiles/IDynamicTile.cs | 2 +- .../Contracts/World/Tiles/ITile.cs | 6 +++ .../Contracts/World/Tiles/ITileEnterRule.cs | 1 + .../NeoServer.Game.Common/InvalidOperation.cs | 4 +- .../CreatureEnterTileRule.cs | 23 ++++++++ .../NeoServer.Game.World/Map/Map.cs | 4 +- .../Models/Tiles/BaseTile.cs | 1 - .../Models/Tiles/DynamicTile.cs | 6 +-- .../Interfaces/IPlayerLoader.cs | 1 + .../NeoServer.Loaders/Players/PlayerLoader.cs | 32 ++++------- .../TileRule/TileRuleLoader.cs | 2 +- .../ClientVersion/ClientProtocolVersion.cs | 2 +- .../LogIn/AccountLoginHandler.cs | 7 ++- .../LogIn/PlayerLogInHandler.cs | 6 ++- .../Outgoing/TextMessageOutgoingParser.cs | 2 +- .../IoC/Modules/ServiceInjection.cs | 2 + 20 files changed, 142 insertions(+), 42 deletions(-) create mode 100644 src/ApplicationServer/NeoServer.Server/Services/PlayerLocationResolver.cs diff --git a/src/ApplicationServer/NeoServer.Server.Commands/Player/PlayerLogInCommand.cs b/src/ApplicationServer/NeoServer.Server.Commands/Player/PlayerLogInCommand.cs index e8bcdf446..43d4d73a7 100644 --- a/src/ApplicationServer/NeoServer.Server.Commands/Player/PlayerLogInCommand.cs +++ b/src/ApplicationServer/NeoServer.Server.Commands/Player/PlayerLogInCommand.cs @@ -1,11 +1,18 @@ using System.Collections.Generic; using System.Linq; using NeoServer.Data.Entities; +using NeoServer.Game.Common; +using NeoServer.Game.Common.Contracts.World.Tiles; +using NeoServer.Game.Common.Location.Structs; +using NeoServer.Game.Common.Results; +using NeoServer.Game.Creatures; +using NeoServer.Game.World; using NeoServer.Loaders.Guilds; using NeoServer.Loaders.Interfaces; using NeoServer.Server.Common.Contracts; using NeoServer.Server.Common.Contracts.Commands; using NeoServer.Server.Common.Contracts.Network; +using NeoServer.Server.Services; using Serilog; namespace NeoServer.Server.Commands.Player; @@ -15,29 +22,40 @@ public class PlayerLogInCommand : ICommand private readonly ILogger _logger; private readonly IGameServer game; private readonly GuildLoader guildLoader; + private readonly PlayerLocationResolver _playerLocationResolver; private readonly IEnumerable playerLoaders; public PlayerLogInCommand(IGameServer game, IEnumerable playerLoaders, GuildLoader guildLoader, + PlayerLocationResolver playerLocationResolver, ILogger logger) { this.game = game; this.playerLoaders = playerLoaders; this.guildLoader = guildLoader; + _playerLocationResolver = playerLocationResolver; _logger = logger; } - public void Execute(PlayerEntity playerRecord, IConnection connection) + public Result Execute(PlayerEntity playerRecord, IConnection connection) { if (playerRecord is null) //todo validations here - return; + return Result.Fail(InvalidOperation.PlayerNotFound); if (!game.CreatureManager.TryGetLoggedPlayer((uint)playerRecord.Id, out var player)) { if (playerLoaders.FirstOrDefault(x => x.IsApplicable(playerRecord)) is not { } playerLoader) - return; + return Result.Fail(InvalidOperation.InvalidPlayer); guildLoader.Load(playerRecord.GuildMember?.Guild); + + var playerLocation = _playerLocationResolver.GetPlayerLocation(playerRecord); + if (playerLocation == Location.Zero) return Result.Fail(InvalidOperation.PlayerLocationInvalid); + + playerRecord.PosX = playerLocation.X; + playerRecord.PosY = playerLocation.Y; + playerRecord.PosZ = playerLocation.Z; + player = playerLoader.Load(playerRecord); } @@ -46,5 +64,7 @@ public void Execute(PlayerEntity playerRecord, IConnection connection) player.Login(); player.Vip.LoadVipList(playerRecord.Account.VipList.Select(x => ((uint)x.PlayerId, x.Player?.Name))); _logger.Information("Player {PlayerName} logged in", player.Name); + + return Result.Success; } } \ No newline at end of file diff --git a/src/ApplicationServer/NeoServer.Server/Services/PlayerLocationResolver.cs b/src/ApplicationServer/NeoServer.Server/Services/PlayerLocationResolver.cs new file mode 100644 index 000000000..f5d904848 --- /dev/null +++ b/src/ApplicationServer/NeoServer.Server/Services/PlayerLocationResolver.cs @@ -0,0 +1,53 @@ +using NeoServer.Data.Entities; +using NeoServer.Game.Common.Contracts.World; +using NeoServer.Game.Common.Contracts.World.Tiles; +using NeoServer.Game.Common.Location.Structs; +using NeoServer.Game.Creatures; +using NeoServer.Game.World; +using Serilog; + +namespace NeoServer.Server.Services; + +//todo: this project is not the best place for this +public class PlayerLocationResolver(World world, ILogger logger) +{ + public Location GetPlayerLocation(PlayerEntity playerEntity) + { + var location = new Location((ushort)playerEntity.PosX, (ushort)playerEntity.PosY, (byte)playerEntity.PosZ); + + var playerTile = world.TryGetTile(ref location, out var tile) && + PlayerEnterTileRule.Rule.CanEnter(tile, location) + ? tile + : null; + + if (playerTile is not null) return location; + + foreach (var neighbour in location.Neighbours) + { + world.TryGetTile(ref location, out var neighbourTile); + if (neighbourTile is IDynamicTile && PlayerEnterTileRule.Rule.CanEnter(neighbourTile, neighbour)) + { + return location; + } + } + + var town = GetTown(playerEntity); + if (town is null) return Location.Zero; + + var townLocation = town.Coordinate.Location; + + playerTile = world.TryGetTile(ref townLocation, out var townTile) && townTile is IDynamicTile townDynamicTile && + PlayerEnterTileRule.Rule.CanEnter(townDynamicTile, townLocation) + ? townDynamicTile + : null; + + return playerTile?.Location ?? Location.Zero; + } + + protected ITown GetTown(PlayerEntity playerEntity) + { + if (!world.TryGetTown((ushort)playerEntity.TownId, out var town)) + logger.Error("player town not found: {PlayerModelTownId}", playerEntity.TownId); + return town; + } +} \ No newline at end of file diff --git a/src/Database/NeoServer.Data/Repositories/AccountRepository.cs b/src/Database/NeoServer.Data/Repositories/AccountRepository.cs index 4ef0afcb2..afb050f0c 100644 --- a/src/Database/NeoServer.Data/Repositories/AccountRepository.cs +++ b/src/Database/NeoServer.Data/Repositories/AccountRepository.cs @@ -48,7 +48,7 @@ public async Task GetPlayer(string accountName, string password, s .ThenInclude(x => x.VipList) .ThenInclude(x => x.Player) .Include(x => x.GuildMember) - .ThenInclude(x => x.Guild).SingleOrDefaultAsync(); + .ThenInclude(x => x.Guild).AsNoTracking().SingleOrDefaultAsync(); } public async Task GetOnlinePlayer(string accountName) diff --git a/src/Extensions/NeoServer.Scripts.Lua/Functions/TileFunctions.cs b/src/Extensions/NeoServer.Scripts.Lua/Functions/TileFunctions.cs index f3598f566..a76712601 100644 --- a/src/Extensions/NeoServer.Scripts.Lua/Functions/TileFunctions.cs +++ b/src/Extensions/NeoServer.Scripts.Lua/Functions/TileFunctions.cs @@ -28,7 +28,7 @@ private static void AddEnterRule(Location location, LuaFunction rule) var tile = map.GetTile(location); if (tile is not IDynamicTile dynamicTile) return; - dynamicTile.CanEnter = creature => (bool)(rule.Call(creature).FirstOrDefault() ?? false); + dynamicTile.CanEnterFunction = creature => (bool)(rule.Call(creature).FirstOrDefault() ?? false); } private static bool RemoveTopItem(Location location) diff --git a/src/GameWorldSimulator/NeoServer.Game.Common/Contracts/World/Tiles/IDynamicTile.cs b/src/GameWorldSimulator/NeoServer.Game.Common/Contracts/World/Tiles/IDynamicTile.cs index 74f0021b3..ef1ef616d 100644 --- a/src/GameWorldSimulator/NeoServer.Game.Common/Contracts/World/Tiles/IDynamicTile.cs +++ b/src/GameWorldSimulator/NeoServer.Game.Common/Contracts/World/Tiles/IDynamicTile.cs @@ -23,7 +23,7 @@ public interface IDynamicTile : ITile, IHasItem bool HasBlockPathFinding { get; } bool HasHole { get; } List Players { get; } - Func CanEnter { get; set; } + Func CanEnterFunction { get; set; } IItem[] AllItems { get; } bool HasTeleport(out ITeleport teleport); diff --git a/src/GameWorldSimulator/NeoServer.Game.Common/Contracts/World/Tiles/ITile.cs b/src/GameWorldSimulator/NeoServer.Game.Common/Contracts/World/Tiles/ITile.cs index 200bca21f..fb35be9b2 100644 --- a/src/GameWorldSimulator/NeoServer.Game.Common/Contracts/World/Tiles/ITile.cs +++ b/src/GameWorldSimulator/NeoServer.Game.Common/Contracts/World/Tiles/ITile.cs @@ -25,4 +25,10 @@ public bool IsNextTo(ITile dest) bool TryGetStackPositionOfThing(IPlayer player, IThing thing, out byte stackPosition); byte GetCreatureStackPositionIndex(IPlayer observer); bool HasFlag(TileFlags flag); + public bool CanEnter(ICreature creature) + { + if (creature is not IWalkableCreature walkableCreature) return false; + if (!walkableCreature.TileEnterRule.CanEnter(this, creature)) return false; + return true; + } } \ No newline at end of file diff --git a/src/GameWorldSimulator/NeoServer.Game.Common/Contracts/World/Tiles/ITileEnterRule.cs b/src/GameWorldSimulator/NeoServer.Game.Common/Contracts/World/Tiles/ITileEnterRule.cs index 1a356ba76..78f68768c 100644 --- a/src/GameWorldSimulator/NeoServer.Game.Common/Contracts/World/Tiles/ITileEnterRule.cs +++ b/src/GameWorldSimulator/NeoServer.Game.Common/Contracts/World/Tiles/ITileEnterRule.cs @@ -6,4 +6,5 @@ public interface ITileEnterRule { bool ShouldIgnore(ITile tile, ICreature creature); bool CanEnter(ITile tile, ICreature creature); + bool CanEnter(ITile tile, Location.Structs.Location location); } \ No newline at end of file diff --git a/src/GameWorldSimulator/NeoServer.Game.Common/InvalidOperation.cs b/src/GameWorldSimulator/NeoServer.Game.Common/InvalidOperation.cs index 01de28032..f88b69953 100644 --- a/src/GameWorldSimulator/NeoServer.Game.Common/InvalidOperation.cs +++ b/src/GameWorldSimulator/NeoServer.Game.Common/InvalidOperation.cs @@ -34,5 +34,7 @@ public enum InvalidOperation CannotUseWeapon, AggressorIsNotHostile, CannotMove, - AttackTargetIsInvisible + AttackTargetIsInvisible, + InvalidPlayer, + PlayerLocationInvalid } \ No newline at end of file diff --git a/src/GameWorldSimulator/NeoServer.Game.Creatures/CreatureEnterTileRule.cs b/src/GameWorldSimulator/NeoServer.Game.Creatures/CreatureEnterTileRule.cs index 835510187..880c2658b 100644 --- a/src/GameWorldSimulator/NeoServer.Game.Creatures/CreatureEnterTileRule.cs +++ b/src/GameWorldSimulator/NeoServer.Game.Creatures/CreatureEnterTileRule.cs @@ -4,6 +4,7 @@ using NeoServer.Game.Common.Creatures; using NeoServer.Game.Common.Helpers; using NeoServer.Game.Common.Location; +using NeoServer.Game.Common.Location.Structs; namespace NeoServer.Game.Creatures; @@ -28,6 +29,15 @@ public virtual bool CanEnter(ITile tile, ICreature creature) { if (tile is not IDynamicTile dynamicTile) return false; + return ConditionEvaluation.And( + !dynamicTile.HasCreature, + !dynamicTile.HasFlag(TileFlags.Unpassable), + dynamicTile.Ground is not null); + } + public virtual bool CanEnter(ITile tile, Location location) + { + if (tile is not IDynamicTile dynamicTile) return false; + return ConditionEvaluation.And( !dynamicTile.HasCreature, !dynamicTile.HasFlag(TileFlags.Unpassable), @@ -63,6 +73,19 @@ public override bool CanEnter(ITile tile, ICreature creature) !dynamicTile.HasFlag(TileFlags.Unpassable), dynamicTile.Ground is not null); } + public override bool CanEnter(ITile tile, Location location) + { + if (tile is not IDynamicTile dynamicTile) return false; + + var goingToDifferentFloor = !location.SameFloorAs(tile.Location); + var hasMonsterOrNpc = !goingToDifferentFloor && + (dynamicTile.HasCreatureOfType() || dynamicTile.HasCreatureOfType()); + + return ConditionEvaluation.And( + !hasMonsterOrNpc, + !dynamicTile.HasFlag(TileFlags.Unpassable), + dynamicTile.Ground is not null); + } } public class MonsterEnterTileRule : CreatureEnterTileRule diff --git a/src/GameWorldSimulator/NeoServer.Game.World/Map/Map.cs b/src/GameWorldSimulator/NeoServer.Game.World/Map/Map.cs index 1c0b6d319..b4ac1fdb4 100644 --- a/src/GameWorldSimulator/NeoServer.Game.World/Map/Map.cs +++ b/src/GameWorldSimulator/NeoServer.Game.World/Map/Map.cs @@ -358,6 +358,8 @@ public void PlaceCreature(ICreature creature) { if (this[creature.Location] is not IDynamicTile tile) return; + if(!tile.CanEnter(creature)) return; + if (tile.HasCreature) foreach (var location in tile.Location.Neighbours) if (this[location] is IDynamicTile { HasCreature: false } t @@ -459,7 +461,7 @@ public void MoveCreature(IWalkableCreature creature) nextTile = newDestinationTile; } - if (nextTile is IDynamicTile dynamicTile && !(dynamicTile.CanEnter?.Invoke(creature) ?? true)) + if (nextTile is IDynamicTile dynamicTile && !(dynamicTile.CanEnterFunction?.Invoke(creature) ?? true)) { creature.CancelWalk(); OperationFailService.Send(creature.CreatureId, TextConstants.NOT_POSSIBLE); diff --git a/src/GameWorldSimulator/NeoServer.Game.World/Models/Tiles/BaseTile.cs b/src/GameWorldSimulator/NeoServer.Game.World/Models/Tiles/BaseTile.cs index 7513f0b7c..f436a5790 100644 --- a/src/GameWorldSimulator/NeoServer.Game.World/Models/Tiles/BaseTile.cs +++ b/src/GameWorldSimulator/NeoServer.Game.World/Models/Tiles/BaseTile.cs @@ -30,7 +30,6 @@ public bool HasFlag(TileFlags flag) { return ((uint)flag & Flags) != 0; } - public bool BlockMissile => HasFlag(TileFlags.BlockMissile); public Location Location { get; private set; } diff --git a/src/GameWorldSimulator/NeoServer.Game.World/Models/Tiles/DynamicTile.cs b/src/GameWorldSimulator/NeoServer.Game.World/Models/Tiles/DynamicTile.cs index ce6351454..1903c24d6 100644 --- a/src/GameWorldSimulator/NeoServer.Game.World/Models/Tiles/DynamicTile.cs +++ b/src/GameWorldSimulator/NeoServer.Game.World/Models/Tiles/DynamicTile.cs @@ -526,7 +526,7 @@ public void ReplaceGround(IGround ground) AddItem(ground); } - public Func CanEnter { get; set; } + public Func CanEnterFunction { get; set; } public bool CanRemoveItem(IItem thing) { @@ -597,7 +597,7 @@ private void SetGround(IGround ground) TileOperationEvent.OnChanged(this, ground, operations); } - + public Result> AddCreature(ICreature creature) { if (creature is not IWalkableCreature walkableCreature) @@ -606,7 +606,7 @@ public Result> AddCreature(ICreature creature) if (!walkableCreature.TileEnterRule.CanEnter(this, creature)) return Result>.NotPossible; - if (!CanEnter?.Invoke(creature) ?? false) return Result>.NotPossible; + if (!CanEnterFunction?.Invoke(creature) ?? false) return Result>.NotPossible; Creatures ??= new List(); Creatures.Add(walkableCreature); diff --git a/src/Loaders/NeoServer.Loaders/Interfaces/IPlayerLoader.cs b/src/Loaders/NeoServer.Loaders/Interfaces/IPlayerLoader.cs index c3f6be40c..823031b2d 100644 --- a/src/Loaders/NeoServer.Loaders/Interfaces/IPlayerLoader.cs +++ b/src/Loaders/NeoServer.Loaders/Interfaces/IPlayerLoader.cs @@ -1,5 +1,6 @@ using NeoServer.Data.Entities; using NeoServer.Game.Common.Contracts.Creatures; +using NeoServer.Game.Common.Results; namespace NeoServer.Loaders.Interfaces; diff --git a/src/Loaders/NeoServer.Loaders/Players/PlayerLoader.cs b/src/Loaders/NeoServer.Loaders/Players/PlayerLoader.cs index cc5aae4ca..942e2392a 100644 --- a/src/Loaders/NeoServer.Loaders/Players/PlayerLoader.cs +++ b/src/Loaders/NeoServer.Loaders/Players/PlayerLoader.cs @@ -18,9 +18,11 @@ using NeoServer.Game.Common.Helpers; using NeoServer.Game.Common.Item; using NeoServer.Game.Common.Location.Structs; +using NeoServer.Game.Common.Results; using NeoServer.Game.Creatures.Player; using NeoServer.Game.Creatures.Player.Inventory; using NeoServer.Loaders.Interfaces; +using NeoServer.Server.Services; using Serilog; namespace NeoServer.Loaders.Players; @@ -72,7 +74,9 @@ public virtual IPlayer Load(PlayerEntity playerEntity) var playerLocation = new Location((ushort)playerEntity.PosX, (ushort)playerEntity.PosY, (byte)playerEntity.PosZ); - + + var currentTile = GetCurrentTile(playerLocation); + var player = new Player( (uint)playerEntity.Id, playerEntity.Name, @@ -110,7 +114,8 @@ public virtual IPlayer Load(PlayerEntity playerEntity) GuildLevel = (ushort)(playerEntity.GuildMember?.RankId ?? 0) }; - SetCurrentTile(player); + player.SetCurrentTile(currentTile); + AddRegenerationCondition(playerEntity, player); player.AddInventory(ConvertToInventory(player, playerEntity)); @@ -134,27 +139,10 @@ protected IVocation GetVocation(PlayerEntity playerEntity) return vocation; } - protected void SetCurrentTile(IPlayer player) + protected IDynamicTile GetCurrentTile(Location location) { - var location = player.Location; - - var playerTile = World.TryGetTile(ref location, out var tile) && tile is IDynamicTile dynamicTile - ? dynamicTile - : null; - - if (playerTile is not null) - { - player.SetCurrentTile(playerTile); - return; - } - - var townLocation = player.Town.Coordinate.Location; - - playerTile = World.TryGetTile(ref townLocation, out var townTile) && townTile is IDynamicTile townDynamicTile - ? townDynamicTile - : null; - - player.SetCurrentTile(playerTile); + World.TryGetTile(ref location, out var dynamicTile); + return dynamicTile as IDynamicTile; } private static void AddRegenerationCondition(PlayerEntity playerEntity, IPlayer player) diff --git a/src/Loaders/NeoServer.Loaders/TileRule/TileRuleLoader.cs b/src/Loaders/NeoServer.Loaders/TileRule/TileRuleLoader.cs index 53c42aef2..98adbb65a 100644 --- a/src/Loaders/NeoServer.Loaders/TileRule/TileRuleLoader.cs +++ b/src/Loaders/NeoServer.Loaders/TileRule/TileRuleLoader.cs @@ -62,7 +62,7 @@ private int LoadTileRules() if (_map[tileLocation] is not IDynamicTile dynamicTile) continue; - dynamicTile.CanEnter = creature => CanEnter(creature, tileRule); + dynamicTile.CanEnterFunction = creature => CanEnter(creature, tileRule); } return tilesData.Count; diff --git a/src/NetworkingServer/NeoServer.Networking.Handlers/ClientVersion/ClientProtocolVersion.cs b/src/NetworkingServer/NeoServer.Networking.Handlers/ClientVersion/ClientProtocolVersion.cs index c19ddfb94..4cbe93b6e 100644 --- a/src/NetworkingServer/NeoServer.Networking.Handlers/ClientVersion/ClientProtocolVersion.cs +++ b/src/NetworkingServer/NeoServer.Networking.Handlers/ClientVersion/ClientProtocolVersion.cs @@ -18,7 +18,7 @@ public bool IsSupported(uint version) { if (version == _serverConfiguration.Version) return true; - _logger.Warning($"Client protocol version {version} is not supported"); + _logger.Warning("Client protocol version {Version} is not supported", version); return false; } } \ No newline at end of file diff --git a/src/NetworkingServer/NeoServer.Networking.Handlers/LogIn/AccountLoginHandler.cs b/src/NetworkingServer/NeoServer.Networking.Handlers/LogIn/AccountLoginHandler.cs index 71b314398..48408e2c5 100644 --- a/src/NetworkingServer/NeoServer.Networking.Handlers/LogIn/AccountLoginHandler.cs +++ b/src/NetworkingServer/NeoServer.Networking.Handlers/LogIn/AccountLoginHandler.cs @@ -24,15 +24,14 @@ public AccountLoginHandler(IAccountRepository repositoryNeo, ServerConfiguration public override async void HandleMessage(IReadOnlyNetworkMessage message, IConnection connection) { var account = new AccountLoginPacket(message); - + connection.SetXtea(account.Xtea); + if (!_clientProtocolVersion.IsSupported(account.ProtocolVersion)) { - connection.Close(); + connection.Disconnect($"Client protocol version {account.ProtocolVersion} is not supported."); return; } - connection.SetXtea(account.Xtea); - if (account == null) { //todo: use option diff --git a/src/NetworkingServer/NeoServer.Networking.Handlers/LogIn/PlayerLogInHandler.cs b/src/NetworkingServer/NeoServer.Networking.Handlers/LogIn/PlayerLogInHandler.cs index abf95c05b..d810c263d 100644 --- a/src/NetworkingServer/NeoServer.Networking.Handlers/LogIn/PlayerLogInHandler.cs +++ b/src/NetworkingServer/NeoServer.Networking.Handlers/LogIn/PlayerLogInHandler.cs @@ -75,7 +75,11 @@ private async Task Connect(IConnection connection, PlayerLogInPacket packet) return; } - _game.Dispatcher.AddEvent(new Event(() => _playerLogInCommand.Execute(playerRecord, connection))); + _game.Dispatcher.AddEvent(new Event(() => + { + var result = _playerLogInCommand.Execute(playerRecord, connection); + if(result.Failed) Disconnect(connection, TextMessageOutgoingParser.Parse(result.Error)); + })); } private Result ValidateOnlineStatus(IConnection connection, PlayerEntity playerOnline, diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/TextMessageOutgoingParser.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/TextMessageOutgoingParser.cs index 4ddc70162..0ba415d8d 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/TextMessageOutgoingParser.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/TextMessageOutgoingParser.cs @@ -23,7 +23,7 @@ public static string Parse(InvalidOperation error) InvalidOperation.CreatureIsNotReachable => "Creature is not reachable.", InvalidOperation.CannotAttackThatFast => "You cannot attack that fast.", InvalidOperation.NotPermittedInProtectionZone => TextConstants.NOT_PERMITTED_IN_PROTECTION_ZONE, - + InvalidOperation.PlayerLocationInvalid => "Player location is invalid.", _ => string.Empty }; } diff --git a/src/Standalone/IoC/Modules/ServiceInjection.cs b/src/Standalone/IoC/Modules/ServiceInjection.cs index a77a3d4c0..4073052f9 100644 --- a/src/Standalone/IoC/Modules/ServiceInjection.cs +++ b/src/Standalone/IoC/Modules/ServiceInjection.cs @@ -11,6 +11,7 @@ using NeoServer.Game.Systems.Services; using NeoServer.Game.World.Services; using NeoServer.Server.Commands.Player.UseItem; +using NeoServer.Server.Services; namespace NeoServer.Server.Standalone.IoC.Modules; @@ -55,6 +56,7 @@ public static IServiceCollection AddServices(this IServiceCollection builder) //application services builder.AddSingleton(); + builder.AddSingleton(); return builder; } From 8d366d2b2d1c0e9e40935e30f4e62fa7dd15242f Mon Sep 17 00:00:00 2001 From: caioavidal Date: Mon, 23 Dec 2024 17:59:38 -0300 Subject: [PATCH 2/8] Fix unit test --- .../Events/CreatureTeleportedEventHandler.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/GameWorldSimulator/NeoServer.Game.Creatures/Events/CreatureTeleportedEventHandler.cs b/src/GameWorldSimulator/NeoServer.Game.Creatures/Events/CreatureTeleportedEventHandler.cs index 487a3f58f..baf2aeb31 100644 --- a/src/GameWorldSimulator/NeoServer.Game.Creatures/Events/CreatureTeleportedEventHandler.cs +++ b/src/GameWorldSimulator/NeoServer.Game.Creatures/Events/CreatureTeleportedEventHandler.cs @@ -29,8 +29,8 @@ public void Execute(IWalkableCreature creature, Location location) if (destination == Location.Zero) return; if (tile is null || !creature.TileEnterRule.CanEnter(tile, creature)) return; - - map.TryMoveCreature(creature, location); + + map.TryMoveCreature(creature, tile.Location); } private IDynamicTile FindNeighbourTile(IWalkableCreature creature, Location location) From 755fbe31354ed9877c72faa061bc652929214303 Mon Sep 17 00:00:00 2001 From: Caio Vidal Date: Tue, 24 Dec 2024 11:29:18 -0300 Subject: [PATCH 3/8] Implement ping packet (#627) * Implement ping packet * Undo changes on Connection.cs * Revert change to NetworkMessage.cs --- data/extensions/Players/Loaders/GodLoader.cs | 10 ++++--- .../extensions/Players/Loaders/TutorLoader.cs | 7 +++-- .../Player/PlayerLogInCommand.cs | 2 +- .../Network/Enums/GameIncomingPacketType.cs | 1 + .../Contracts/Network/IConnection.cs | 4 ++- .../Contracts/Network/INetworkMessage.cs | 1 + .../Enums/OperatingSystem.cs | 21 +++++++++++++++ .../AdlerChecksum.cs | 2 +- .../InputHandlerMap.cs | 4 ++- .../LogIn/PlayerLogInHandler.cs | 22 +++++++++++++++- .../Server/NetworkPingHandler.cs | 17 ++++++++++++ .../Connection/Connection.cs | 22 ++++++++++++---- .../Incoming/AccountLoginPacket.cs | 7 +++-- .../Incoming/PlayerLoginPacket.cs | 18 ++++++++++--- .../Incoming/Server/NetworkPingPacket.cs | 17 ++++++++++++ .../Messages/NetworkMessage.cs | 13 +++++++++- .../Messages/ReadOnlyNetworkMessage.cs | 14 +++++++++- .../Outgoing/Custom/FeaturesPacket.cs | 26 +++++++++++++++++++ .../Outgoing/Custom/NetworkPingPacket.cs | 13 ++++++++++ .../Outgoing/Custom/OpcodeMessagePacket.cs | 13 ++++++++++ .../Outgoing/GameOutgoingPacketType.cs | 3 ++- .../Outgoing/Login/FirstConnectionPacket.cs | 15 ++++++----- 22 files changed, 221 insertions(+), 31 deletions(-) create mode 100644 src/ApplicationServer/NeoServer.Server.Contracts/Enums/OperatingSystem.cs create mode 100644 src/NetworkingServer/NeoServer.Networking.Handlers/Server/NetworkPingHandler.cs create mode 100644 src/NetworkingServer/NeoServer.Networking.Packets/Incoming/Server/NetworkPingPacket.cs create mode 100644 src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Custom/FeaturesPacket.cs create mode 100644 src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Custom/NetworkPingPacket.cs create mode 100644 src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Custom/OpcodeMessagePacket.cs diff --git a/data/extensions/Players/Loaders/GodLoader.cs b/data/extensions/Players/Loaders/GodLoader.cs index e30df56d6..3b0db9d9c 100644 --- a/data/extensions/Players/Loaders/GodLoader.cs +++ b/data/extensions/Players/Loaders/GodLoader.cs @@ -35,6 +35,11 @@ public override IPlayer Load(PlayerEntity playerEntity) if (Guard.IsNull(playerEntity)) return null; var town = GetTown(playerEntity); + + var playerLocation = + new Location((ushort)playerEntity.PosX, (ushort)playerEntity.PosY, (byte)playerEntity.PosZ); + + var currentTile = GetCurrentTile(playerLocation); var newPlayer = new God( (uint)playerEntity.Id, @@ -61,9 +66,8 @@ public override IPlayer Load(PlayerEntity playerEntity) Guild = GuildStore.Get((ushort)(playerEntity.GuildMember?.GuildId ?? 0)), GuildLevel = (ushort)(playerEntity.GuildMember?.RankId ?? 0) }; - - SetCurrentTile(newPlayer); - + + newPlayer.SetCurrentTile(currentTile); newPlayer.AddInventory(ConvertToInventory(newPlayer, playerEntity)); var god = CreatureFactory.CreatePlayer(newPlayer); diff --git a/data/extensions/Players/Loaders/TutorLoader.cs b/data/extensions/Players/Loaders/TutorLoader.cs index 9841eba91..32065ef29 100644 --- a/data/extensions/Players/Loaders/TutorLoader.cs +++ b/data/extensions/Players/Loaders/TutorLoader.cs @@ -35,7 +35,10 @@ public override IPlayer Load(PlayerEntity playerEntity) if (Guard.IsNull(playerEntity)) return null; var town = GetTown(playerEntity); - + var playerLocation = + new Location((ushort)playerEntity.PosX, (ushort)playerEntity.PosY, (byte)playerEntity.PosZ); + + var currentTile = GetCurrentTile(playerLocation); var newPlayer = new Tutor( (uint)playerEntity.Id, playerEntity.Name, @@ -63,7 +66,7 @@ public override IPlayer Load(PlayerEntity playerEntity) }; newPlayer.AddInventory(ConvertToInventory(newPlayer, playerEntity)); - SetCurrentTile(newPlayer); + newPlayer.SetCurrentTile(currentTile); var tutor = CreatureFactory.CreatePlayer(newPlayer); return tutor; diff --git a/src/ApplicationServer/NeoServer.Server.Commands/Player/PlayerLogInCommand.cs b/src/ApplicationServer/NeoServer.Server.Commands/Player/PlayerLogInCommand.cs index 43d4d73a7..72a350762 100644 --- a/src/ApplicationServer/NeoServer.Server.Commands/Player/PlayerLogInCommand.cs +++ b/src/ApplicationServer/NeoServer.Server.Commands/Player/PlayerLogInCommand.cs @@ -41,7 +41,7 @@ public Result Execute(PlayerEntity playerRecord, IConnection connection) if (playerRecord is null) //todo validations here return Result.Fail(InvalidOperation.PlayerNotFound); - + if (!game.CreatureManager.TryGetLoggedPlayer((uint)playerRecord.Id, out var player)) { if (playerLoaders.FirstOrDefault(x => x.IsApplicable(playerRecord)) is not { } playerLoader) diff --git a/src/ApplicationServer/NeoServer.Server.Contracts/Contracts/Network/Enums/GameIncomingPacketType.cs b/src/ApplicationServer/NeoServer.Server.Contracts/Contracts/Network/Enums/GameIncomingPacketType.cs index 2e8eec878..081f1ac3c 100644 --- a/src/ApplicationServer/NeoServer.Server.Contracts/Contracts/Network/Enums/GameIncomingPacketType.cs +++ b/src/ApplicationServer/NeoServer.Server.Contracts/Contracts/Network/Enums/GameIncomingPacketType.cs @@ -73,5 +73,6 @@ public enum GameIncomingPacketType : byte ReportBug = 0xE6, ReportViolation = 0xE7, ReportDebugAssertion = 0xE8, + NewPing = 0x40, Any = 0xFF // Do not send } \ No newline at end of file diff --git a/src/ApplicationServer/NeoServer.Server.Contracts/Contracts/Network/IConnection.cs b/src/ApplicationServer/NeoServer.Server.Contracts/Contracts/Network/IConnection.cs index bd35d0387..2875a354b 100644 --- a/src/ApplicationServer/NeoServer.Server.Contracts/Contracts/Network/IConnection.cs +++ b/src/ApplicationServer/NeoServer.Server.Contracts/Contracts/Network/IConnection.cs @@ -15,6 +15,8 @@ public interface IConnection long LastPingRequest { get; set; } long LastPingResponse { get; set; } string Ip { get; } + long TimeStamp { get; } + byte RandomNumber { get; } event EventHandler OnProcessEvent; event EventHandler OnCloseEvent; @@ -23,7 +25,7 @@ public interface IConnection void BeginStreamRead(); void Close(bool force = false); void Disconnect(string text = null); - void Send(IOutgoingPacket packet); + public void Send(IOutgoingPacket packet); void SendFirstConnection(); void SetXtea(uint[] xtea); void SetAsAuthenticated(); diff --git a/src/ApplicationServer/NeoServer.Server.Contracts/Contracts/Network/INetworkMessage.cs b/src/ApplicationServer/NeoServer.Server.Contracts/Contracts/Network/INetworkMessage.cs index 7e4d49604..daa2ddf75 100644 --- a/src/ApplicationServer/NeoServer.Server.Contracts/Contracts/Network/INetworkMessage.cs +++ b/src/ApplicationServer/NeoServer.Server.Contracts/Contracts/Network/INetworkMessage.cs @@ -12,6 +12,7 @@ public interface INetworkMessage : IReadOnlyNetworkMessage void AddString(string value); void AddUInt16(ushort value); void AddUInt32(uint value); + void WriteUint32(uint value, int position); byte[] AddHeader(bool addChecksum = true); void AddItem(IItem item); void AddLocation(Location location); diff --git a/src/ApplicationServer/NeoServer.Server.Contracts/Enums/OperatingSystem.cs b/src/ApplicationServer/NeoServer.Server.Contracts/Enums/OperatingSystem.cs new file mode 100644 index 000000000..56bd27d8c --- /dev/null +++ b/src/ApplicationServer/NeoServer.Server.Contracts/Enums/OperatingSystem.cs @@ -0,0 +1,21 @@ +namespace NeoServer.Server.Common.Enums; + +public enum OperatingSystem +{ + None = 0, + Linux = 1, + Windows = 2, + Flash = 3, + OtcLinux = 10, + OtcWindows = 11, + OtcMac = 12, + + // by default OTCv8 uses CLIENTOS_WINDOWS for backward compatibility + // for correct value enable g_game.enableFeature(GameExtendedOpcode) + OtcV8Linux = 20, + OtcV8Windows = 21, + OtcV8Mac = 22, + OtcV8Android = 23, + OtcV8Ios = 24, + OtcV8Web = 25 +} \ No newline at end of file diff --git a/src/ApplicationServer/NeoServer.Server.Security/AdlerChecksum.cs b/src/ApplicationServer/NeoServer.Server.Security/AdlerChecksum.cs index 13b291c7d..cc0217c1a 100644 --- a/src/ApplicationServer/NeoServer.Server.Security/AdlerChecksum.cs +++ b/src/ApplicationServer/NeoServer.Server.Security/AdlerChecksum.cs @@ -1,6 +1,6 @@ namespace NeoServer.Server.Security; -public class AdlerChecksum +public static class AdlerChecksum { public static uint Checksum(byte[] data, int index, int length) { diff --git a/src/NetworkingServer/NeoServer.Networking.Handlers/InputHandlerMap.cs b/src/NetworkingServer/NeoServer.Networking.Handlers/InputHandlerMap.cs index 03a54d455..8307deda9 100644 --- a/src/NetworkingServer/NeoServer.Networking.Handlers/InputHandlerMap.cs +++ b/src/NetworkingServer/NeoServer.Networking.Handlers/InputHandlerMap.cs @@ -5,6 +5,7 @@ using NeoServer.Networking.Handlers.Player; using NeoServer.Networking.Handlers.Player.Movement; using NeoServer.Networking.Handlers.Player.Party; +using NeoServer.Networking.Handlers.Server; using NeoServer.Networking.Handlers.Shop; using NeoServer.Networking.Handlers.Trade; using NeoServer.Server.Common.Contracts.Network.Enums; @@ -66,6 +67,7 @@ public static class InputHandlerMap [GameIncomingPacketType.OutfitChangeCompleted] = typeof(PlayerChangeCompletedOutFitHandler), [GameIncomingPacketType.TradeRequest] = typeof(TradeRequestHandler), [GameIncomingPacketType.TradeCancel] = typeof(TradeCancelHandler), - [GameIncomingPacketType.TradeAccept] = typeof(TradeAcceptHandler) + [GameIncomingPacketType.TradeAccept] = typeof(TradeAcceptHandler), + [GameIncomingPacketType.NewPing] = typeof(NetworkPingHandler) }; } \ No newline at end of file diff --git a/src/NetworkingServer/NeoServer.Networking.Handlers/LogIn/PlayerLogInHandler.cs b/src/NetworkingServer/NeoServer.Networking.Handlers/LogIn/PlayerLogInHandler.cs index d810c263d..57c85c13e 100644 --- a/src/NetworkingServer/NeoServer.Networking.Handlers/LogIn/PlayerLogInHandler.cs +++ b/src/NetworkingServer/NeoServer.Networking.Handlers/LogIn/PlayerLogInHandler.cs @@ -4,6 +4,7 @@ using NeoServer.Game.Common.Results; using NeoServer.Networking.Packets.Incoming; using NeoServer.Networking.Packets.Outgoing; +using NeoServer.Networking.Packets.Outgoing.Custom; using NeoServer.Server.Commands.Player; using NeoServer.Server.Common.Contracts; using NeoServer.Server.Common.Contracts.Network; @@ -78,7 +79,20 @@ private async Task Connect(IConnection connection, PlayerLogInPacket packet) _game.Dispatcher.AddEvent(new Event(() => { var result = _playerLogInCommand.Execute(playerRecord, connection); - if(result.Failed) Disconnect(connection, TextMessageOutgoingParser.Parse(result.Error)); + if (result.Failed) + { + Disconnect(connection, TextMessageOutgoingParser.Parse(result.Error)); + return; + } + + if (packet.OtcV8Version > 0 || packet.OperatingSystem >= OperatingSystem.OtcLinux) + { + if (packet.OtcV8Version > 0) + { + connection.Send(new FeaturesPacket()); + } + connection.Send(new OpcodeMessagePacket()); + } })); } @@ -103,6 +117,12 @@ private Result ValidateOnlineStatus(IConnection connection, PlayerEntity playerO private bool Verify(IConnection connection, PlayerLogInPacket packet) { + if (packet.ChallengeTimeStamp != connection.TimeStamp || packet.ChallengeNumber != connection.RandomNumber) + { + Disconnect(connection, "Login challenge is not valid."); + return false; + } + if (string.IsNullOrWhiteSpace(packet.Account)) { Disconnect(connection, "You must enter your account name."); diff --git a/src/NetworkingServer/NeoServer.Networking.Handlers/Server/NetworkPingHandler.cs b/src/NetworkingServer/NeoServer.Networking.Handlers/Server/NetworkPingHandler.cs new file mode 100644 index 000000000..e7fd7b1cd --- /dev/null +++ b/src/NetworkingServer/NeoServer.Networking.Handlers/Server/NetworkPingHandler.cs @@ -0,0 +1,17 @@ +using NeoServer.Networking.Packets.Incoming.Server; +using NeoServer.Server.Common.Contracts.Network; + +namespace NeoServer.Networking.Handlers.Server; + +public class NetworkPingHandler: PacketHandler +{ + public override void HandleMessage(IReadOnlyNetworkMessage message, IConnection connection) + { + var packet = new NetworkPingPacket(message); + + connection.Send(new Packets.Outgoing.Custom.NetworkPingPacket() + { + PingId = packet.PingId + }); + } +} \ No newline at end of file diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Connection/Connection.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Connection/Connection.cs index 402bb7e2c..0c57532ec 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Connection/Connection.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Connection/Connection.cs @@ -36,6 +36,8 @@ public Connection(Socket socket, ILogger logger) _connectionLock = new object(); _logger = logger; LastPingResponse = DateTime.Now.Ticks; + RandomNumber = (byte)new Random().Next(byte.MinValue, byte.MaxValue); + TimeStamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); } private bool Closed @@ -58,7 +60,8 @@ private bool Closed public bool Disconnected { get; private set; } public long LastPingRequest { get; set; } public long LastPingResponse { get; set; } - + public long TimeStamp { get; private set; } + public byte RandomNumber { get; private set; } public event EventHandler OnProcessEvent; public event EventHandler OnCloseEvent; public event EventHandler OnPostProcessEvent; @@ -119,11 +122,18 @@ public void SendFirstConnection() { var message = new NetworkMessage(); - new FirstConnectionPacket().WriteToMessage(message); + new FirstConnectionPacket + { + RandomNumber = RandomNumber, + TimeStamp = TimeStamp + }.WriteToMessage(message); + + message.AddLength(); - SendMessage(message); + SendMessage(message, addHeader: false); } + public void Send(IOutgoingPacket packet) { var message = new NetworkMessage(); @@ -134,6 +144,7 @@ public void Send(IOutgoingPacket packet) var encryptedMessage = Xtea.Encrypt(message, XteaKey); + _logger.Debug("To {PlayerId}: {Name}", CreatureId, packet.GetType().Name); SendMessage(encryptedMessage); } @@ -285,14 +296,15 @@ private void CloseSocket() } } - private void SendMessage(INetworkMessage message) + private void SendMessage(INetworkMessage message, bool addHeader = true) { try { lock (_writeLock) { if (Closed || !_socket.Connected || Disconnected) return; - var streamMessage = message.AddHeader(); + + var streamMessage = addHeader ? message.AddHeader() : message.GetMessageInBytes().ToArray(); _stream.BeginWrite(streamMessage, 0, streamMessage.Length, null, null); } diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Incoming/AccountLoginPacket.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Incoming/AccountLoginPacket.cs index 5d2179ddc..c7a88232b 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Incoming/AccountLoginPacket.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Incoming/AccountLoginPacket.cs @@ -1,5 +1,6 @@ using NeoServer.Networking.Packets.Messages; using NeoServer.Server.Common.Contracts.Network; +using NeoServer.Server.Common.Enums; using NeoServer.Server.Security; namespace NeoServer.Networking.Packets.Incoming; @@ -10,8 +11,8 @@ public AccountLoginPacket(IReadOnlyNetworkMessage message) { var packetPayload = message.GetUInt16(); var tcpPayload = packetPayload + 2; - message.SkipBytes(7); - //var os = message.GetUInt16(); + message.SkipBytes(5); + OperatingSystem = (OperatingSystem) message.GetUInt16(); ProtocolVersion = message.GetUInt16(); message.SkipBytes(12); @@ -30,6 +31,8 @@ public AccountLoginPacket(IReadOnlyNetworkMessage message) Password = data.GetString(); } + public OperatingSystem OperatingSystem { get; set; } + public string Account { get; } public string Password { get; } public ushort ProtocolVersion { get; } diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Incoming/PlayerLoginPacket.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Incoming/PlayerLoginPacket.cs index edc720409..230595fb7 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Incoming/PlayerLoginPacket.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Incoming/PlayerLoginPacket.cs @@ -2,6 +2,7 @@ using NeoServer.Networking.Packets.Messages; using NeoServer.Server.Common.Contracts.Network; using NeoServer.Server.Security; +using OperatingSystem = NeoServer.Server.Common.Enums.OperatingSystem; namespace NeoServer.Networking.Packets.Incoming; @@ -13,7 +14,7 @@ public PlayerLogInPacket(IReadOnlyNetworkMessage message) var tcpPayload = packetLength + 2; message.SkipBytes(5); - OS = message.GetUInt16(); + OperatingSystem = (OperatingSystem) message.GetUInt16(); Version = message.GetUInt16(); //message.SkipBytes(9); @@ -34,14 +35,23 @@ public PlayerLogInPacket(IReadOnlyNetworkMessage message) Account = data.GetString(); CharacterName = data.GetString(); Password = data.GetString(); - GameServerNonce = data.GetBytes(5).ToArray(); + ChallengeTimeStamp = data.GetUInt32(); + ChallengeNumber = data.GetByte(); + var clientStringLength = data.GetUInt16(); + if (clientStringLength == 5 && data.GetString(5) == "OTCv8") + { + OtcV8Version = data.GetUInt16(); + } } + public ushort OtcV8Version { get; set; } + public string Account { get; set; } public string Password { get; set; } public string CharacterName { get; set; } public bool GameMaster { get; set; } - public byte[] GameServerNonce { get; set; } - public ushort OS { get; set; } + public uint ChallengeTimeStamp { get; set; } + public byte ChallengeNumber { get; set; } + public OperatingSystem OperatingSystem { get; set; } public ushort Version { get; set; } } \ No newline at end of file diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Incoming/Server/NetworkPingPacket.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Incoming/Server/NetworkPingPacket.cs new file mode 100644 index 000000000..b1ff2fd00 --- /dev/null +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Incoming/Server/NetworkPingPacket.cs @@ -0,0 +1,17 @@ +using NeoServer.Server.Common.Contracts.Network; + +namespace NeoServer.Networking.Packets.Incoming.Server; + +public class NetworkPingPacket: IncomingPacket +{ + public uint PingId { get; } + public ushort LocalPing { get; } + public ushort Fps { get; } + + public NetworkPingPacket(IReadOnlyNetworkMessage message) + { + PingId = message.GetUInt32(); + LocalPing = message.GetUInt16(); + Fps = message.GetUInt16(); + } +} \ No newline at end of file diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Messages/NetworkMessage.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Messages/NetworkMessage.cs index 8f9461530..2c07c1860 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Messages/NetworkMessage.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Messages/NetworkMessage.cs @@ -80,6 +80,17 @@ public void AddUInt32(uint value) WriteBytes(buffer); } + public void WriteUint32(uint value, int position) + { + Span buffer = stackalloc byte[4]; + BitConverter.TryWriteBytes(buffer, value); + + Buffer[position] = buffer[position++]; + Buffer[position] = buffer[position++]; + Buffer[position] = buffer[position++]; + Buffer[position] = buffer[position]; + } + /// /// Adds ushort (2 bytes) to buffer /// @@ -97,7 +108,7 @@ public void AddUInt16(ushort value) /// public void AddByte(byte b) { - WriteBytes(new[] { b }); + WriteByte(b); } /// diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Messages/ReadOnlyNetworkMessage.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Messages/ReadOnlyNetworkMessage.cs index 1ab80998b..6dd075372 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Messages/ReadOnlyNetworkMessage.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Messages/ReadOnlyNetworkMessage.cs @@ -43,7 +43,7 @@ public GameIncomingPacketType GetIncomingPacketType(bool isAuthenticated) { case true: if (Buffer.Length.IsLessThan(9)) return GameIncomingPacketType.None; - SkipBytes(6); + SkipBytes(6); //skip header GetUInt16(); var packetType = (GameIncomingPacketType)GetByte(); IncomingPacket = packetType; @@ -105,6 +105,18 @@ public string GetString() return Iso88591Encoding.GetString(span); } + /// + /// Get string value based on payload length + /// + /// + public string GetString(int length) + { + if (length == 0 || BytesRead + length > Buffer.Length) return null; + + var span = GetBytes(length); + return Iso88591Encoding.GetString(span); + } + public void Resize(int length) { if (length.IsLessThanZero()) return; diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Custom/FeaturesPacket.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Custom/FeaturesPacket.cs new file mode 100644 index 000000000..40a54046e --- /dev/null +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Custom/FeaturesPacket.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using NeoServer.Server.Common.Contracts.Network; + +namespace NeoServer.Networking.Packets.Outgoing.Custom; + +public class FeaturesPacket:OutgoingPacket +{ + public override void WriteToMessage(INetworkMessage message) + { + message.AddByte(0x43); + message.AddUInt16(4); + + var features = new Dictionary() + { + [80] = true, + [13] = false, + [25] = true, + [93] = true + }; + foreach (var feature in features) + { + message.AddByte(feature.Key); + message.AddByte((byte)(feature.Value ? 1 : 0)); + } + } +} \ No newline at end of file diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Custom/NetworkPingPacket.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Custom/NetworkPingPacket.cs new file mode 100644 index 000000000..ed46a1ad6 --- /dev/null +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Custom/NetworkPingPacket.cs @@ -0,0 +1,13 @@ +using NeoServer.Server.Common.Contracts.Network; + +namespace NeoServer.Networking.Packets.Outgoing.Custom; + +public class NetworkPingPacket : OutgoingPacket +{ + public required uint PingId { get; init; } + public override void WriteToMessage(INetworkMessage message) + { + message.AddByte((byte)GameOutgoingPacketType.NetworkPing); + message.AddUInt32(PingId); + } +} \ No newline at end of file diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Custom/OpcodeMessagePacket.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Custom/OpcodeMessagePacket.cs new file mode 100644 index 000000000..1dd3beb26 --- /dev/null +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Custom/OpcodeMessagePacket.cs @@ -0,0 +1,13 @@ +using NeoServer.Server.Common.Contracts.Network; + +namespace NeoServer.Networking.Packets.Outgoing.Custom; + +public class OpcodeMessagePacket:OutgoingPacket +{ + public override void WriteToMessage(INetworkMessage message) + { + message.AddByte(0x32); + message.AddByte(0x00); + message.AddUInt16(0x00); + } +} \ No newline at end of file diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/GameOutgoingPacketType.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/GameOutgoingPacketType.cs index 52de85047..36253a5a4 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/GameOutgoingPacketType.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/GameOutgoingPacketType.cs @@ -62,5 +62,6 @@ public enum GameOutgoingPacketType : byte AddVip = 0xD2, OnlineStatusVip = 0xD3, OfflineStatusVip = 0xD4, - TextWindow = 0x96 + TextWindow = 0x96, + NetworkPing = 0x40, } \ No newline at end of file diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Login/FirstConnectionPacket.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Login/FirstConnectionPacket.cs index 960e6ae2b..aa850a9b4 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Login/FirstConnectionPacket.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Login/FirstConnectionPacket.cs @@ -1,18 +1,19 @@ -using System; -using NeoServer.Server.Common.Contracts.Network; +using NeoServer.Server.Common.Contracts.Network; namespace NeoServer.Networking.Packets.Outgoing.Login; public class FirstConnectionPacket : OutgoingPacket { + public required long TimeStamp { get; set; } + public required byte RandomNumber { get; set; } + public override void WriteToMessage(INetworkMessage message) { + message.AddUInt32(0); message.AddUInt16(0x0006); message.AddByte(0x1F); - message.AddUInt32((uint)DateTimeOffset.UtcNow.ToUnixTimeSeconds()); - - var rnd = new Random(); - var randomByte = (byte)rnd.Next(byte.MinValue, byte.MaxValue); - message.AddByte(randomByte); + message.AddUInt32((uint)TimeStamp); + message.AddByte(RandomNumber); + message.WriteUint32(NeoServer.Server.Security.AdlerChecksum.Checksum(message.Buffer,4, message.Length - 4), 0); } } \ No newline at end of file From 7455930e710366165e94bfd804b7dea063d13c81 Mon Sep 17 00:00:00 2001 From: Caio Vidal Date: Tue, 24 Dec 2024 14:54:25 -0300 Subject: [PATCH 4/8] Code cleanup (#628) --- data/extensions/Players/Loaders/GodLoader.cs | 6 +- .../extensions/Players/Loaders/TutorLoader.cs | 2 +- .../Spells/Support/Knight/BloodRage.cs | 8 +-- .../Player/PlayerLogInCommand.cs | 13 ++-- .../PlayerConditionChangedEventHandler.cs | 5 +- .../Services/PlayerLocationResolver.cs | 8 +-- .../NeoServer.Server/Tasks/Dispatcher.cs | 2 +- .../NeoServer.Data/Entities/WorldEntity.cs | 2 +- .../NeoServer.Data/Seeds/WorldModelSeed.cs | 4 +- .../NeoServer.Game.Combat/Spells/Spell.cs | 8 +-- .../Contracts/World/Tiles/ITile.cs | 1 + .../Creatures/CooldownType.cs | 2 +- .../CreatureEnterTileRule.cs | 2 + .../Events/CreatureTeleportedEventHandler.cs | 8 +-- .../Models/Bases/CombatActor.cs | 37 ++++++---- .../NeoServer.Game.Creatures/Player/Player.cs | 3 +- .../NeoServer.Game.Creatures/Player/Skill.cs | 11 ++- .../NeoServer.Game.World/Map/Map.cs | 2 +- .../Models/Tiles/BaseTile.cs | 1 + .../Models/Tiles/DynamicTile.cs | 2 +- .../Interfaces/IPlayerLoader.cs | 1 - .../NeoServer.Loaders/Players/PlayerLoader.cs | 6 +- .../LogIn/AccountLoginHandler.cs | 2 +- .../LogIn/PlayerLogInHandler.cs | 9 +-- .../Server/NetworkPingHandler.cs | 6 +- .../Connection/Connection.cs | 8 +-- .../Incoming/AccountLoginPacket.cs | 2 +- .../Incoming/PlayerLoginPacket.cs | 9 +-- .../Incoming/Server/NetworkPingPacket.cs | 10 +-- .../Messages/NetworkMessage.cs | 2 +- .../Messages/ReadOnlyNetworkMessage.cs | 24 +++---- .../Outgoing/Custom/FeaturesPacket.cs | 12 ++-- .../Outgoing/Custom/NetworkPingPacket.cs | 1 + .../Outgoing/Custom/OpcodeMessagePacket.cs | 2 +- .../Outgoing/GameOutgoingPacketType.cs | 2 +- .../Outgoing/Login/CharacterListPacket.cs | 1 + .../Outgoing/Login/FirstConnectionPacket.cs | 3 +- .../Listeners/GameListener.cs | 3 +- .../Modules/DatabaseInjection.cs | 7 +- .../NeoServer.IoC/Modules/LoggerInjection.cs | 11 +-- .../NeoServer.IoC/NeoServer.Shared.IoC.csproj | 58 ++++++++-------- .../IoC/Modules/ConfigurationInjection.cs | 4 +- src/WebAPI/NeoServer.Web.API.csproj | 68 +++++++++---------- src/WebAPI/Program.cs | 8 ++- .../Combat/CombatTests.cs | 31 ++++----- .../SafeTrade/PreTradeValidationTests.cs | 3 +- .../SafeTrade/TradeCancellationTests.cs | 3 +- .../SafeTrade/TradeExchangeValidationTests.cs | 3 +- .../NeoServer.WebApi.Tests.csproj | 2 +- .../Tests/PlayerTests.cs | 1 - 50 files changed, 216 insertions(+), 213 deletions(-) diff --git a/data/extensions/Players/Loaders/GodLoader.cs b/data/extensions/Players/Loaders/GodLoader.cs index 3b0db9d9c..d69d4158f 100644 --- a/data/extensions/Players/Loaders/GodLoader.cs +++ b/data/extensions/Players/Loaders/GodLoader.cs @@ -35,10 +35,10 @@ public override IPlayer Load(PlayerEntity playerEntity) if (Guard.IsNull(playerEntity)) return null; var town = GetTown(playerEntity); - + var playerLocation = new Location((ushort)playerEntity.PosX, (ushort)playerEntity.PosY, (byte)playerEntity.PosZ); - + var currentTile = GetCurrentTile(playerLocation); var newPlayer = new God( @@ -66,7 +66,7 @@ public override IPlayer Load(PlayerEntity playerEntity) Guild = GuildStore.Get((ushort)(playerEntity.GuildMember?.GuildId ?? 0)), GuildLevel = (ushort)(playerEntity.GuildMember?.RankId ?? 0) }; - + newPlayer.SetCurrentTile(currentTile); newPlayer.AddInventory(ConvertToInventory(newPlayer, playerEntity)); var god = CreatureFactory.CreatePlayer(newPlayer); diff --git a/data/extensions/Players/Loaders/TutorLoader.cs b/data/extensions/Players/Loaders/TutorLoader.cs index 32065ef29..234dac98e 100644 --- a/data/extensions/Players/Loaders/TutorLoader.cs +++ b/data/extensions/Players/Loaders/TutorLoader.cs @@ -37,7 +37,7 @@ public override IPlayer Load(PlayerEntity playerEntity) var town = GetTown(playerEntity); var playerLocation = new Location((ushort)playerEntity.PosX, (ushort)playerEntity.PosY, (byte)playerEntity.PosZ); - + var currentTile = GetCurrentTile(playerLocation); var newPlayer = new Tutor( (uint)playerEntity.Id, diff --git a/data/extensions/Spells/Support/Knight/BloodRage.cs b/data/extensions/Spells/Support/Knight/BloodRage.cs index d6867a5ae..3fa752c49 100644 --- a/data/extensions/Spells/Support/Knight/BloodRage.cs +++ b/data/extensions/Spells/Support/Knight/BloodRage.cs @@ -17,12 +17,12 @@ public override bool OnCast(ICombatActor actor, string words, out InvalidOperati error = InvalidOperation.None; if (actor is not IPlayer player) return false; - + player.AddSkillBonus(SkillType.Axe, (sbyte)Math.Abs(player.Skills[SkillType.Axe].Level * 0.35)); player.AddSkillBonus(SkillType.Sword, (sbyte)Math.Abs(player.Skills[SkillType.Axe].Level * 0.35)); player.AddSkillBonus(SkillType.Club, (sbyte)Math.Abs(player.Skills[SkillType.Axe].Level * 0.35)); player.AddSkillBonus(SkillType.Fist, (sbyte)Math.Abs(player.Skills[SkillType.Axe].Level * 0.35)); - + actor.DisableShieldDefense(); actor.IncreaseDamageReceived(15); return true; @@ -31,12 +31,12 @@ public override bool OnCast(ICombatActor actor, string words, out InvalidOperati public override void OnEnd(ICombatActor actor) { if (actor is not IPlayer player) return; - + player.RemoveSkillBonus(SkillType.Axe, (sbyte)Math.Abs(player.Skills[SkillType.Axe].Level * 0.35)); player.RemoveSkillBonus(SkillType.Sword, (sbyte)Math.Abs(player.Skills[SkillType.Axe].Level * 0.35)); player.RemoveSkillBonus(SkillType.Club, (sbyte)Math.Abs(player.Skills[SkillType.Axe].Level * 0.35)); player.RemoveSkillBonus(SkillType.Fist, (sbyte)Math.Abs(player.Skills[SkillType.Axe].Level * 0.35)); - + actor.EnableShieldDefense(); actor.DecreaseDamageReceived(15); diff --git a/src/ApplicationServer/NeoServer.Server.Commands/Player/PlayerLogInCommand.cs b/src/ApplicationServer/NeoServer.Server.Commands/Player/PlayerLogInCommand.cs index 72a350762..466af8069 100644 --- a/src/ApplicationServer/NeoServer.Server.Commands/Player/PlayerLogInCommand.cs +++ b/src/ApplicationServer/NeoServer.Server.Commands/Player/PlayerLogInCommand.cs @@ -2,11 +2,8 @@ using System.Linq; using NeoServer.Data.Entities; using NeoServer.Game.Common; -using NeoServer.Game.Common.Contracts.World.Tiles; using NeoServer.Game.Common.Location.Structs; using NeoServer.Game.Common.Results; -using NeoServer.Game.Creatures; -using NeoServer.Game.World; using NeoServer.Loaders.Guilds; using NeoServer.Loaders.Interfaces; using NeoServer.Server.Common.Contracts; @@ -20,9 +17,9 @@ namespace NeoServer.Server.Commands.Player; public class PlayerLogInCommand : ICommand { private readonly ILogger _logger; + private readonly PlayerLocationResolver _playerLocationResolver; private readonly IGameServer game; private readonly GuildLoader guildLoader; - private readonly PlayerLocationResolver _playerLocationResolver; private readonly IEnumerable playerLoaders; public PlayerLogInCommand(IGameServer game, IEnumerable playerLoaders, GuildLoader guildLoader, @@ -41,7 +38,7 @@ public Result Execute(PlayerEntity playerRecord, IConnection connection) if (playerRecord is null) //todo validations here return Result.Fail(InvalidOperation.PlayerNotFound); - + if (!game.CreatureManager.TryGetLoggedPlayer((uint)playerRecord.Id, out var player)) { if (playerLoaders.FirstOrDefault(x => x.IsApplicable(playerRecord)) is not { } playerLoader) @@ -51,11 +48,11 @@ public Result Execute(PlayerEntity playerRecord, IConnection connection) var playerLocation = _playerLocationResolver.GetPlayerLocation(playerRecord); if (playerLocation == Location.Zero) return Result.Fail(InvalidOperation.PlayerLocationInvalid); - + playerRecord.PosX = playerLocation.X; playerRecord.PosY = playerLocation.Y; playerRecord.PosZ = playerLocation.Z; - + player = playerLoader.Load(playerRecord); } @@ -64,7 +61,7 @@ public Result Execute(PlayerEntity playerRecord, IConnection connection) player.Login(); player.Vip.LoadVipList(playerRecord.Account.VipList.Select(x => ((uint)x.PlayerId, x.Player?.Name))); _logger.Information("Player {PlayerName} logged in", player.Name); - + return Result.Success; } } \ No newline at end of file diff --git a/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerConditionChangedEventHandler.cs b/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerConditionChangedEventHandler.cs index ce0365193..1f93728e9 100644 --- a/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerConditionChangedEventHandler.cs +++ b/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerConditionChangedEventHandler.cs @@ -20,10 +20,7 @@ public void Execute(ICreature creature, ICondition c) if (!game.CreatureManager.GetPlayerConnection(creature.CreatureId, out var connection)) return; ushort icons = 0; - foreach (var condition in player.Conditions) - { - icons |= (ushort)ConditionIconParser.Parse(condition.Key); - } + foreach (var condition in player.Conditions) icons |= (ushort)ConditionIconParser.Parse(condition.Key); connection.OutgoingPackets.Enqueue(new ConditionIconPacket(icons)); connection.Send(); diff --git a/src/ApplicationServer/NeoServer.Server/Services/PlayerLocationResolver.cs b/src/ApplicationServer/NeoServer.Server/Services/PlayerLocationResolver.cs index f5d904848..8ca34bb2b 100644 --- a/src/ApplicationServer/NeoServer.Server/Services/PlayerLocationResolver.cs +++ b/src/ApplicationServer/NeoServer.Server/Services/PlayerLocationResolver.cs @@ -21,23 +21,21 @@ public Location GetPlayerLocation(PlayerEntity playerEntity) : null; if (playerTile is not null) return location; - + foreach (var neighbour in location.Neighbours) { world.TryGetTile(ref location, out var neighbourTile); if (neighbourTile is IDynamicTile && PlayerEnterTileRule.Rule.CanEnter(neighbourTile, neighbour)) - { return location; - } } var town = GetTown(playerEntity); if (town is null) return Location.Zero; - + var townLocation = town.Coordinate.Location; playerTile = world.TryGetTile(ref townLocation, out var townTile) && townTile is IDynamicTile townDynamicTile && - PlayerEnterTileRule.Rule.CanEnter(townDynamicTile, townLocation) + PlayerEnterTileRule.Rule.CanEnter(townDynamicTile, townLocation) ? townDynamicTile : null; diff --git a/src/ApplicationServer/NeoServer.Server/Tasks/Dispatcher.cs b/src/ApplicationServer/NeoServer.Server/Tasks/Dispatcher.cs index 86da8bc77..9a9d48fec 100644 --- a/src/ApplicationServer/NeoServer.Server/Tasks/Dispatcher.cs +++ b/src/ApplicationServer/NeoServer.Server/Tasks/Dispatcher.cs @@ -42,7 +42,7 @@ public void Start(CancellationToken token) Task.Run(async () => { while (await _reader.WaitToReadAsync(token)) - + { if (token.IsCancellationRequested) _writer.Complete(); // Fast loop around available jobs diff --git a/src/Database/NeoServer.Data/Entities/WorldEntity.cs b/src/Database/NeoServer.Data/Entities/WorldEntity.cs index 1734f8992..7365b631b 100644 --- a/src/Database/NeoServer.Data/Entities/WorldEntity.cs +++ b/src/Database/NeoServer.Data/Entities/WorldEntity.cs @@ -6,4 +6,4 @@ public class WorldEntity public string Name { get; set; } public string Ip { get; set; } public int Port { get; set; } -} +} \ No newline at end of file diff --git a/src/Database/NeoServer.Data/Seeds/WorldModelSeed.cs b/src/Database/NeoServer.Data/Seeds/WorldModelSeed.cs index 969b42881..b78aa521e 100644 --- a/src/Database/NeoServer.Data/Seeds/WorldModelSeed.cs +++ b/src/Database/NeoServer.Data/Seeds/WorldModelSeed.cs @@ -1,6 +1,6 @@ -using Microsoft.EntityFrameworkCore.Metadata.Builders; +using System; +using Microsoft.EntityFrameworkCore.Metadata.Builders; using NeoServer.Data.Entities; -using System; namespace NeoServer.Data.Seeds; diff --git a/src/GameWorldSimulator/NeoServer.Game.Combat/Spells/Spell.cs b/src/GameWorldSimulator/NeoServer.Game.Combat/Spells/Spell.cs index 03f9e56f8..5c7db65e7 100644 --- a/src/GameWorldSimulator/NeoServer.Game.Combat/Spells/Spell.cs +++ b/src/GameWorldSimulator/NeoServer.Game.Combat/Spells/Spell.cs @@ -23,7 +23,7 @@ public abstract class BaseSpell : ISpell public bool InvokeOn(ICombatActor actor, ICombatActor onCreature, string words, out InvalidOperation error) { if (!CanBeUsedBy(actor, out error)) return false; - + if (!onCreature.HasCondition(ConditionType)) if (!OnCast(onCreature, words, out error)) return false; @@ -31,17 +31,17 @@ public bool InvokeOn(ICombatActor actor, ICombatActor onCreature, string words, AddCondition(onCreature); if (actor is IPlayer) AddCooldown(actor); - + OnSpellInvoked?.Invoke(onCreature, this); if (actor is IPlayer player) player.ConsumeMana(Mana); - + return true; } public bool Invoke(ICombatActor actor, string words, out InvalidOperation error) { if (!CanBeUsedBy(actor, out error)) return false; - + if (!actor.HasCondition(ConditionType)) if (!OnCast(actor, words, out error)) return false; diff --git a/src/GameWorldSimulator/NeoServer.Game.Common/Contracts/World/Tiles/ITile.cs b/src/GameWorldSimulator/NeoServer.Game.Common/Contracts/World/Tiles/ITile.cs index fb35be9b2..c5db1cca8 100644 --- a/src/GameWorldSimulator/NeoServer.Game.Common/Contracts/World/Tiles/ITile.cs +++ b/src/GameWorldSimulator/NeoServer.Game.Common/Contracts/World/Tiles/ITile.cs @@ -25,6 +25,7 @@ public bool IsNextTo(ITile dest) bool TryGetStackPositionOfThing(IPlayer player, IThing thing, out byte stackPosition); byte GetCreatureStackPositionIndex(IPlayer observer); bool HasFlag(TileFlags flag); + public bool CanEnter(ICreature creature) { if (creature is not IWalkableCreature walkableCreature) return false; diff --git a/src/GameWorldSimulator/NeoServer.Game.Common/Creatures/CooldownType.cs b/src/GameWorldSimulator/NeoServer.Game.Common/Creatures/CooldownType.cs index f0c19b6f1..eecd132e2 100644 --- a/src/GameWorldSimulator/NeoServer.Game.Common/Creatures/CooldownType.cs +++ b/src/GameWorldSimulator/NeoServer.Game.Common/Creatures/CooldownType.cs @@ -25,5 +25,5 @@ public enum CooldownType Advertise, WalkAround, UseItem, - SupportSpell, + SupportSpell } \ No newline at end of file diff --git a/src/GameWorldSimulator/NeoServer.Game.Creatures/CreatureEnterTileRule.cs b/src/GameWorldSimulator/NeoServer.Game.Creatures/CreatureEnterTileRule.cs index 880c2658b..d85a9b00b 100644 --- a/src/GameWorldSimulator/NeoServer.Game.Creatures/CreatureEnterTileRule.cs +++ b/src/GameWorldSimulator/NeoServer.Game.Creatures/CreatureEnterTileRule.cs @@ -34,6 +34,7 @@ public virtual bool CanEnter(ITile tile, ICreature creature) !dynamicTile.HasFlag(TileFlags.Unpassable), dynamicTile.Ground is not null); } + public virtual bool CanEnter(ITile tile, Location location) { if (tile is not IDynamicTile dynamicTile) return false; @@ -73,6 +74,7 @@ public override bool CanEnter(ITile tile, ICreature creature) !dynamicTile.HasFlag(TileFlags.Unpassable), dynamicTile.Ground is not null); } + public override bool CanEnter(ITile tile, Location location) { if (tile is not IDynamicTile dynamicTile) return false; diff --git a/src/GameWorldSimulator/NeoServer.Game.Creatures/Events/CreatureTeleportedEventHandler.cs b/src/GameWorldSimulator/NeoServer.Game.Creatures/Events/CreatureTeleportedEventHandler.cs index baf2aeb31..36974bed1 100644 --- a/src/GameWorldSimulator/NeoServer.Game.Creatures/Events/CreatureTeleportedEventHandler.cs +++ b/src/GameWorldSimulator/NeoServer.Game.Creatures/Events/CreatureTeleportedEventHandler.cs @@ -21,11 +21,9 @@ public void Execute(IWalkableCreature creature, Location location) if (creature.Location == location) return; var destination = location; - + if (map[location] is not IDynamicTile { FloorDirection: FloorChangeDirection.None } tile) - { tile = FindNeighbourTile(creature, location); - } if (destination == Location.Zero) return; if (tile is null || !creature.TileEnterRule.CanEnter(tile, creature)) return; @@ -36,12 +34,8 @@ public void Execute(IWalkableCreature creature, Location location) private IDynamicTile FindNeighbourTile(IWalkableCreature creature, Location location) { foreach (var neighbour in location.Neighbours) - { if (map[neighbour] is IDynamicTile toTile) - { return toTile; - } - } return null; } diff --git a/src/GameWorldSimulator/NeoServer.Game.Creatures/Models/Bases/CombatActor.cs b/src/GameWorldSimulator/NeoServer.Game.Creatures/Models/Bases/CombatActor.cs index 3bc898bb4..6ade09db5 100644 --- a/src/GameWorldSimulator/NeoServer.Game.Creatures/Models/Bases/CombatActor.cs +++ b/src/GameWorldSimulator/NeoServer.Game.Creatures/Models/Bases/CombatActor.cs @@ -34,11 +34,12 @@ protected CombatActor(ICreatureType type, IMapTool mapTool, IOutfit outfit = nul { } - public abstract int DefendUsingShield(int attack); - public abstract int DefendUsingArmor(int attack); public bool IsShieldDefenseEnabled { get; private set; } = true; public byte DamageReceivedPercentage { get; private set; } + public abstract int DefendUsingShield(int attack); + public abstract int DefendUsingArmor(int attack); + public void AddCondition(ICondition condition) { var result = Conditions.TryAdd(condition.Type, condition); @@ -348,6 +349,26 @@ public Result Attack(ICombatActor enemy, ICombatAttack attack, CombatAttackValue return Result.Success; } + public void DisableShieldDefense() + { + IsShieldDefenseEnabled = false; + } + + public void EnableShieldDefense() + { + IsShieldDefenseEnabled = true; + } + + public void IncreaseDamageReceived(byte percentage) + { + DamageReceivedPercentage += percentage; + } + + public void DecreaseDamageReceived(byte percentage) + { + DamageReceivedPercentage -= percentage; + } + public abstract bool HasImmunity(Immunity immunity); public virtual bool CanBlock(DamageType damage) @@ -437,18 +458,6 @@ protected void InvokeAttackCanceled() { OnAttackCanceled?.Invoke(this); } - - public void DisableShieldDefense() => IsShieldDefenseEnabled = false; - public void EnableShieldDefense() => IsShieldDefenseEnabled = true; - public void IncreaseDamageReceived(byte percentage) - { - DamageReceivedPercentage += percentage; - } - - public void DecreaseDamageReceived(byte percentage) - { - DamageReceivedPercentage -= percentage; - } #region Events diff --git a/src/GameWorldSimulator/NeoServer.Game.Creatures/Player/Player.cs b/src/GameWorldSimulator/NeoServer.Game.Creatures/Player/Player.cs index 24081e576..766938910 100644 --- a/src/GameWorldSimulator/NeoServer.Game.Creatures/Player/Player.cs +++ b/src/GameWorldSimulator/NeoServer.Game.Creatures/Player/Player.cs @@ -253,6 +253,7 @@ public ushort GetRawSkillLevel(SkillType skillType) var skillLevel = hasSkill ? skill.Level : 1; return (ushort)Math.Max(0, skillLevel); } + public ushort GetSkillLevel(SkillType skillType) { var hasSkill = Skills.TryGetValue(skillType, out var skill); @@ -415,7 +416,7 @@ public void ChangeSecureMode(byte mode) public override int DefendUsingShield(int attack) { if (!IsShieldDefenseEnabled) return attack; - + var defense = Inventory.TotalDefense * Skills[SkillType.Shielding].Level * (DefenseFactor / 100d) - attack / 100d * ArmorRating * (Vocation.Formula?.Defense ?? 1f); diff --git a/src/GameWorldSimulator/NeoServer.Game.Creatures/Player/Skill.cs b/src/GameWorldSimulator/NeoServer.Game.Creatures/Player/Skill.cs index 19119a401..3f3ce6cb8 100644 --- a/src/GameWorldSimulator/NeoServer.Game.Creatures/Player/Skill.cs +++ b/src/GameWorldSimulator/NeoServer.Game.Creatures/Player/Skill.cs @@ -35,8 +35,15 @@ public Skill(SkillType type, ushort level = 0, double count = 0) public sbyte Bonus { get; private set; } - public void AddBonus(sbyte increase) => Bonus = (sbyte)(Bonus + increase); - public void RemoveBonus(sbyte decrease) => Bonus = (sbyte)(Bonus - decrease); + public void AddBonus(sbyte increase) + { + Bonus = (sbyte)(Bonus + increase); + } + + public void RemoveBonus(sbyte decrease) + { + Bonus = (sbyte)(Bonus - decrease); + } public SkillType Type { get; } public ushort Level { get; private set; } diff --git a/src/GameWorldSimulator/NeoServer.Game.World/Map/Map.cs b/src/GameWorldSimulator/NeoServer.Game.World/Map/Map.cs index b4ac1fdb4..e3c6f2ffd 100644 --- a/src/GameWorldSimulator/NeoServer.Game.World/Map/Map.cs +++ b/src/GameWorldSimulator/NeoServer.Game.World/Map/Map.cs @@ -358,7 +358,7 @@ public void PlaceCreature(ICreature creature) { if (this[creature.Location] is not IDynamicTile tile) return; - if(!tile.CanEnter(creature)) return; + if (!tile.CanEnter(creature)) return; if (tile.HasCreature) foreach (var location in tile.Location.Neighbours) diff --git a/src/GameWorldSimulator/NeoServer.Game.World/Models/Tiles/BaseTile.cs b/src/GameWorldSimulator/NeoServer.Game.World/Models/Tiles/BaseTile.cs index f436a5790..7513f0b7c 100644 --- a/src/GameWorldSimulator/NeoServer.Game.World/Models/Tiles/BaseTile.cs +++ b/src/GameWorldSimulator/NeoServer.Game.World/Models/Tiles/BaseTile.cs @@ -30,6 +30,7 @@ public bool HasFlag(TileFlags flag) { return ((uint)flag & Flags) != 0; } + public bool BlockMissile => HasFlag(TileFlags.BlockMissile); public Location Location { get; private set; } diff --git a/src/GameWorldSimulator/NeoServer.Game.World/Models/Tiles/DynamicTile.cs b/src/GameWorldSimulator/NeoServer.Game.World/Models/Tiles/DynamicTile.cs index 1903c24d6..efed57786 100644 --- a/src/GameWorldSimulator/NeoServer.Game.World/Models/Tiles/DynamicTile.cs +++ b/src/GameWorldSimulator/NeoServer.Game.World/Models/Tiles/DynamicTile.cs @@ -597,7 +597,7 @@ private void SetGround(IGround ground) TileOperationEvent.OnChanged(this, ground, operations); } - + public Result> AddCreature(ICreature creature) { if (creature is not IWalkableCreature walkableCreature) diff --git a/src/Loaders/NeoServer.Loaders/Interfaces/IPlayerLoader.cs b/src/Loaders/NeoServer.Loaders/Interfaces/IPlayerLoader.cs index 823031b2d..c3f6be40c 100644 --- a/src/Loaders/NeoServer.Loaders/Interfaces/IPlayerLoader.cs +++ b/src/Loaders/NeoServer.Loaders/Interfaces/IPlayerLoader.cs @@ -1,6 +1,5 @@ using NeoServer.Data.Entities; using NeoServer.Game.Common.Contracts.Creatures; -using NeoServer.Game.Common.Results; namespace NeoServer.Loaders.Interfaces; diff --git a/src/Loaders/NeoServer.Loaders/Players/PlayerLoader.cs b/src/Loaders/NeoServer.Loaders/Players/PlayerLoader.cs index 942e2392a..bb224b329 100644 --- a/src/Loaders/NeoServer.Loaders/Players/PlayerLoader.cs +++ b/src/Loaders/NeoServer.Loaders/Players/PlayerLoader.cs @@ -18,11 +18,9 @@ using NeoServer.Game.Common.Helpers; using NeoServer.Game.Common.Item; using NeoServer.Game.Common.Location.Structs; -using NeoServer.Game.Common.Results; using NeoServer.Game.Creatures.Player; using NeoServer.Game.Creatures.Player.Inventory; using NeoServer.Loaders.Interfaces; -using NeoServer.Server.Services; using Serilog; namespace NeoServer.Loaders.Players; @@ -74,9 +72,9 @@ public virtual IPlayer Load(PlayerEntity playerEntity) var playerLocation = new Location((ushort)playerEntity.PosX, (ushort)playerEntity.PosY, (byte)playerEntity.PosZ); - + var currentTile = GetCurrentTile(playerLocation); - + var player = new Player( (uint)playerEntity.Id, playerEntity.Name, diff --git a/src/NetworkingServer/NeoServer.Networking.Handlers/LogIn/AccountLoginHandler.cs b/src/NetworkingServer/NeoServer.Networking.Handlers/LogIn/AccountLoginHandler.cs index 48408e2c5..da64deef4 100644 --- a/src/NetworkingServer/NeoServer.Networking.Handlers/LogIn/AccountLoginHandler.cs +++ b/src/NetworkingServer/NeoServer.Networking.Handlers/LogIn/AccountLoginHandler.cs @@ -25,7 +25,7 @@ public override async void HandleMessage(IReadOnlyNetworkMessage message, IConne { var account = new AccountLoginPacket(message); connection.SetXtea(account.Xtea); - + if (!_clientProtocolVersion.IsSupported(account.ProtocolVersion)) { connection.Disconnect($"Client protocol version {account.ProtocolVersion} is not supported."); diff --git a/src/NetworkingServer/NeoServer.Networking.Handlers/LogIn/PlayerLogInHandler.cs b/src/NetworkingServer/NeoServer.Networking.Handlers/LogIn/PlayerLogInHandler.cs index 57c85c13e..f32f19a5b 100644 --- a/src/NetworkingServer/NeoServer.Networking.Handlers/LogIn/PlayerLogInHandler.cs +++ b/src/NetworkingServer/NeoServer.Networking.Handlers/LogIn/PlayerLogInHandler.cs @@ -84,13 +84,10 @@ private async Task Connect(IConnection connection, PlayerLogInPacket packet) Disconnect(connection, TextMessageOutgoingParser.Parse(result.Error)); return; } - + if (packet.OtcV8Version > 0 || packet.OperatingSystem >= OperatingSystem.OtcLinux) { - if (packet.OtcV8Version > 0) - { - connection.Send(new FeaturesPacket()); - } + if (packet.OtcV8Version > 0) connection.Send(new FeaturesPacket()); connection.Send(new OpcodeMessagePacket()); } })); @@ -122,7 +119,7 @@ private bool Verify(IConnection connection, PlayerLogInPacket packet) Disconnect(connection, "Login challenge is not valid."); return false; } - + if (string.IsNullOrWhiteSpace(packet.Account)) { Disconnect(connection, "You must enter your account name."); diff --git a/src/NetworkingServer/NeoServer.Networking.Handlers/Server/NetworkPingHandler.cs b/src/NetworkingServer/NeoServer.Networking.Handlers/Server/NetworkPingHandler.cs index e7fd7b1cd..0daaf09bb 100644 --- a/src/NetworkingServer/NeoServer.Networking.Handlers/Server/NetworkPingHandler.cs +++ b/src/NetworkingServer/NeoServer.Networking.Handlers/Server/NetworkPingHandler.cs @@ -3,13 +3,13 @@ namespace NeoServer.Networking.Handlers.Server; -public class NetworkPingHandler: PacketHandler +public class NetworkPingHandler : PacketHandler { public override void HandleMessage(IReadOnlyNetworkMessage message, IConnection connection) { var packet = new NetworkPingPacket(message); - - connection.Send(new Packets.Outgoing.Custom.NetworkPingPacket() + + connection.Send(new Packets.Outgoing.Custom.NetworkPingPacket { PingId = packet.PingId }); diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Connection/Connection.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Connection/Connection.cs index 0c57532ec..1bea74383 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Connection/Connection.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Connection/Connection.cs @@ -60,8 +60,8 @@ private bool Closed public bool Disconnected { get; private set; } public long LastPingRequest { get; set; } public long LastPingResponse { get; set; } - public long TimeStamp { get; private set; } - public byte RandomNumber { get; private set; } + public long TimeStamp { get; } + public byte RandomNumber { get; } public event EventHandler OnProcessEvent; public event EventHandler OnCloseEvent; public event EventHandler OnPostProcessEvent; @@ -127,10 +127,10 @@ public void SendFirstConnection() RandomNumber = RandomNumber, TimeStamp = TimeStamp }.WriteToMessage(message); - + message.AddLength(); - SendMessage(message, addHeader: false); + SendMessage(message, false); } diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Incoming/AccountLoginPacket.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Incoming/AccountLoginPacket.cs index c7a88232b..c6d0f4f27 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Incoming/AccountLoginPacket.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Incoming/AccountLoginPacket.cs @@ -12,7 +12,7 @@ public AccountLoginPacket(IReadOnlyNetworkMessage message) var packetPayload = message.GetUInt16(); var tcpPayload = packetPayload + 2; message.SkipBytes(5); - OperatingSystem = (OperatingSystem) message.GetUInt16(); + OperatingSystem = (OperatingSystem)message.GetUInt16(); ProtocolVersion = message.GetUInt16(); message.SkipBytes(12); diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Incoming/PlayerLoginPacket.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Incoming/PlayerLoginPacket.cs index 230595fb7..29e181ee8 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Incoming/PlayerLoginPacket.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Incoming/PlayerLoginPacket.cs @@ -14,7 +14,7 @@ public PlayerLogInPacket(IReadOnlyNetworkMessage message) var tcpPayload = packetLength + 2; message.SkipBytes(5); - OperatingSystem = (OperatingSystem) message.GetUInt16(); + OperatingSystem = (OperatingSystem)message.GetUInt16(); Version = message.GetUInt16(); //message.SkipBytes(9); @@ -38,14 +38,11 @@ public PlayerLogInPacket(IReadOnlyNetworkMessage message) ChallengeTimeStamp = data.GetUInt32(); ChallengeNumber = data.GetByte(); var clientStringLength = data.GetUInt16(); - if (clientStringLength == 5 && data.GetString(5) == "OTCv8") - { - OtcV8Version = data.GetUInt16(); - } + if (clientStringLength == 5 && data.GetString(5) == "OTCv8") OtcV8Version = data.GetUInt16(); } public ushort OtcV8Version { get; set; } - + public string Account { get; set; } public string Password { get; set; } public string CharacterName { get; set; } diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Incoming/Server/NetworkPingPacket.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Incoming/Server/NetworkPingPacket.cs index b1ff2fd00..f3aeebad6 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Incoming/Server/NetworkPingPacket.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Incoming/Server/NetworkPingPacket.cs @@ -2,16 +2,16 @@ namespace NeoServer.Networking.Packets.Incoming.Server; -public class NetworkPingPacket: IncomingPacket +public class NetworkPingPacket : IncomingPacket { - public uint PingId { get; } - public ushort LocalPing { get; } - public ushort Fps { get; } - public NetworkPingPacket(IReadOnlyNetworkMessage message) { PingId = message.GetUInt32(); LocalPing = message.GetUInt16(); Fps = message.GetUInt16(); } + + public uint PingId { get; } + public ushort LocalPing { get; } + public ushort Fps { get; } } \ No newline at end of file diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Messages/NetworkMessage.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Messages/NetworkMessage.cs index 2c07c1860..9d559efd9 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Messages/NetworkMessage.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Messages/NetworkMessage.cs @@ -84,7 +84,7 @@ public void WriteUint32(uint value, int position) { Span buffer = stackalloc byte[4]; BitConverter.TryWriteBytes(buffer, value); - + Buffer[position] = buffer[position++]; Buffer[position] = buffer[position++]; Buffer[position] = buffer[position++]; diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Messages/ReadOnlyNetworkMessage.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Messages/ReadOnlyNetworkMessage.cs index 6dd075372..55d59afaa 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Messages/ReadOnlyNetworkMessage.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Messages/ReadOnlyNetworkMessage.cs @@ -105,18 +105,6 @@ public string GetString() return Iso88591Encoding.GetString(span); } - /// - /// Get string value based on payload length - /// - /// - public string GetString(int length) - { - if (length == 0 || BytesRead + length > Buffer.Length) return null; - - var span = GetBytes(length); - return Iso88591Encoding.GetString(span); - } - public void Resize(int length) { if (length.IsLessThanZero()) return; @@ -137,6 +125,18 @@ public Location GetLocation() return new Location { X = GetUInt16(), Y = GetUInt16(), Z = GetByte() }; } + /// + /// Get string value based on payload length + /// + /// + public string GetString(int length) + { + if (length == 0 || BytesRead + length > Buffer.Length) return null; + + var span = GetBytes(length); + return Iso88591Encoding.GetString(span); + } + private void IncreaseByteRead(int length) { BytesRead += length; diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Custom/FeaturesPacket.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Custom/FeaturesPacket.cs index 40a54046e..f672c274a 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Custom/FeaturesPacket.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Custom/FeaturesPacket.cs @@ -3,19 +3,19 @@ namespace NeoServer.Networking.Packets.Outgoing.Custom; -public class FeaturesPacket:OutgoingPacket +public class FeaturesPacket : OutgoingPacket { public override void WriteToMessage(INetworkMessage message) { message.AddByte(0x43); message.AddUInt16(4); - var features = new Dictionary() + var features = new Dictionary { - [80] = true, - [13] = false, - [25] = true, - [93] = true + [80] = true, + [13] = false, + [25] = true, + [93] = true }; foreach (var feature in features) { diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Custom/NetworkPingPacket.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Custom/NetworkPingPacket.cs index ed46a1ad6..38ce1c2bd 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Custom/NetworkPingPacket.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Custom/NetworkPingPacket.cs @@ -5,6 +5,7 @@ namespace NeoServer.Networking.Packets.Outgoing.Custom; public class NetworkPingPacket : OutgoingPacket { public required uint PingId { get; init; } + public override void WriteToMessage(INetworkMessage message) { message.AddByte((byte)GameOutgoingPacketType.NetworkPing); diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Custom/OpcodeMessagePacket.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Custom/OpcodeMessagePacket.cs index 1dd3beb26..1f8510da6 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Custom/OpcodeMessagePacket.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Custom/OpcodeMessagePacket.cs @@ -2,7 +2,7 @@ namespace NeoServer.Networking.Packets.Outgoing.Custom; -public class OpcodeMessagePacket:OutgoingPacket +public class OpcodeMessagePacket : OutgoingPacket { public override void WriteToMessage(INetworkMessage message) { diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/GameOutgoingPacketType.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/GameOutgoingPacketType.cs index 36253a5a4..a70eb64d9 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/GameOutgoingPacketType.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/GameOutgoingPacketType.cs @@ -63,5 +63,5 @@ public enum GameOutgoingPacketType : byte OnlineStatusVip = 0xD3, OfflineStatusVip = 0xD4, TextWindow = 0x96, - NetworkPing = 0x40, + NetworkPing = 0x40 } \ No newline at end of file diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Login/CharacterListPacket.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Login/CharacterListPacket.cs index 1ba08f350..b80db7a58 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Login/CharacterListPacket.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Login/CharacterListPacket.cs @@ -9,6 +9,7 @@ public class CharacterListPacket : OutgoingPacket private readonly string _ipAddress; private readonly ushort _port; private readonly string _serverName; + public CharacterListPacket(AccountEntity account, string serverName, string ipAddress, ushort port) { _accountEntity = account; diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Login/FirstConnectionPacket.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Login/FirstConnectionPacket.cs index aa850a9b4..a67240ca6 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Login/FirstConnectionPacket.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Login/FirstConnectionPacket.cs @@ -1,4 +1,5 @@ using NeoServer.Server.Common.Contracts.Network; +using NeoServer.Server.Security; namespace NeoServer.Networking.Packets.Outgoing.Login; @@ -14,6 +15,6 @@ public override void WriteToMessage(INetworkMessage message) message.AddByte(0x1F); message.AddUInt32((uint)TimeStamp); message.AddByte(RandomNumber); - message.WriteUint32(NeoServer.Server.Security.AdlerChecksum.Checksum(message.Buffer,4, message.Length - 4), 0); + message.WriteUint32(AdlerChecksum.Checksum(message.Buffer, 4, message.Length - 4), 0); } } \ No newline at end of file diff --git a/src/NetworkingServer/NeoServer.Networking/Listeners/GameListener.cs b/src/NetworkingServer/NeoServer.Networking/Listeners/GameListener.cs index 650d0ffc0..917e52bd1 100644 --- a/src/NetworkingServer/NeoServer.Networking/Listeners/GameListener.cs +++ b/src/NetworkingServer/NeoServer.Networking/Listeners/GameListener.cs @@ -6,7 +6,8 @@ namespace NeoServer.Networking.Listeners; public class GameListener : Listener { - public GameListener(GameProtocol protocol, ILogger logger, ServerConfiguration serverConfiguration) : base(serverConfiguration.ServerGamePort, + public GameListener(GameProtocol protocol, ILogger logger, ServerConfiguration serverConfiguration) : base( + serverConfiguration.ServerGamePort, protocol, logger) { } diff --git a/src/Shared/NeoServer.IoC/Modules/DatabaseInjection.cs b/src/Shared/NeoServer.IoC/Modules/DatabaseInjection.cs index bf2724e8a..f6e2e2e38 100644 --- a/src/Shared/NeoServer.IoC/Modules/DatabaseInjection.cs +++ b/src/Shared/NeoServer.IoC/Modules/DatabaseInjection.cs @@ -73,16 +73,17 @@ private static void LoadEnvironmentVariables(ref DatabaseConfiguration databaseC var dbConnections = databaseConfiguration.Connections; - if(!string.IsNullOrEmpty(sqliteDatabase)) + if (!string.IsNullOrEmpty(sqliteDatabase)) dbConnections[DatabaseType.SQLITE] = $"Data Source={sqliteDatabase}"; if (!string.IsNullOrEmpty(postgresDatabase)) - dbConnections[DatabaseType.POSTGRESQL] = $"host={postgresHost};port={postgresPort};database={postgresDatabase};username={postgresUser};password={postgresPassword};"; + dbConnections[DatabaseType.POSTGRESQL] = + $"host={postgresHost};port={postgresPort};database={postgresDatabase};username={postgresUser};password={postgresPassword};"; var active = databaseConfiguration.Active; if (!string.IsNullOrEmpty(activeDatabase) && Enum.TryParse(activeDatabase, out DatabaseType databaseType)) active = databaseType; - databaseConfiguration = new(dbConnections, active); + databaseConfiguration = new DatabaseConfiguration(dbConnections, active); } } \ No newline at end of file diff --git a/src/Shared/NeoServer.IoC/Modules/LoggerInjection.cs b/src/Shared/NeoServer.IoC/Modules/LoggerInjection.cs index c5ef3b686..3cd8f0c7a 100644 --- a/src/Shared/NeoServer.IoC/Modules/LoggerInjection.cs +++ b/src/Shared/NeoServer.IoC/Modules/LoggerInjection.cs @@ -6,7 +6,6 @@ using Serilog.Sinks.Graylog; using Serilog.Sinks.Graylog.Core.Transport; using Serilog.Sinks.SystemConsole.Themes; -using static Org.BouncyCastle.Math.EC.ECCurve; public static class LoggerConfigurationExtensions { @@ -50,10 +49,14 @@ private static void LoadEnvironmentVariables(ref GrayLogConfiguration grayLogCon var graylogHostnameOverride = Environment.GetEnvironmentVariable("GRAYLOG_HOSTNAME_OVERRIDE"); var graylogFacility = Environment.GetEnvironmentVariable("GRAYLOG_FACILITY"); - grayLogConfiguration = new( - string.IsNullOrEmpty(graylogHostnameOrAddress) ? grayLogConfiguration.HostnameOrAddress : graylogHostnameOrAddress, + grayLogConfiguration = new GrayLogConfiguration( + string.IsNullOrEmpty(graylogHostnameOrAddress) + ? grayLogConfiguration.HostnameOrAddress + : graylogHostnameOrAddress, string.IsNullOrEmpty(graylogPort) ? grayLogConfiguration.Port : int.Parse(graylogPort), - string.IsNullOrEmpty(graylogHostnameOverride) ? grayLogConfiguration.HostnameOverride : graylogHostnameOverride, + string.IsNullOrEmpty(graylogHostnameOverride) + ? grayLogConfiguration.HostnameOverride + : graylogHostnameOverride, string.IsNullOrEmpty(graylogFacility) ? grayLogConfiguration.Facility : graylogFacility); } } \ No newline at end of file diff --git a/src/Shared/NeoServer.IoC/NeoServer.Shared.IoC.csproj b/src/Shared/NeoServer.IoC/NeoServer.Shared.IoC.csproj index bdb2c8518..e8552e381 100644 --- a/src/Shared/NeoServer.IoC/NeoServer.Shared.IoC.csproj +++ b/src/Shared/NeoServer.IoC/NeoServer.Shared.IoC.csproj @@ -6,36 +6,36 @@ false - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/src/Standalone/IoC/Modules/ConfigurationInjection.cs b/src/Standalone/IoC/Modules/ConfigurationInjection.cs index d591438e5..ca0eb1018 100644 --- a/src/Standalone/IoC/Modules/ConfigurationInjection.cs +++ b/src/Standalone/IoC/Modules/ConfigurationInjection.cs @@ -29,7 +29,7 @@ public static IServiceCollection AddConfigurations(this IServiceCollection build IConfigurationRoot configuration) { ServerConfiguration serverConfiguration = - new(0, null, null, null, string.Empty, string.Empty, string.Empty, 7171, 7172,new SaveConfiguration(3600)); + new(0, null, null, null, string.Empty, string.Empty, string.Empty, 7171, 7172, new SaveConfiguration(3600)); GameConfiguration gameConfiguration = new(); LogConfiguration logConfiguration = new(null); @@ -53,7 +53,7 @@ private static void LoadEnvironmentVariables(ref ServerConfiguration serverConfi var serverGameName = Environment.GetEnvironmentVariable("SERVER_GAME_NAME"); var serverGameIP = Environment.GetEnvironmentVariable("SERVER_GAME_IP"); - serverConfiguration = new( + serverConfiguration = new ServerConfiguration( serverConfiguration.Version, serverConfiguration.OTBM, serverConfiguration.OTB, diff --git a/src/WebAPI/NeoServer.Web.API.csproj b/src/WebAPI/NeoServer.Web.API.csproj index b91e19c6d..b1480edb5 100644 --- a/src/WebAPI/NeoServer.Web.API.csproj +++ b/src/WebAPI/NeoServer.Web.API.csproj @@ -1,41 +1,41 @@  - - net9.0 - enable - Linux - c71a823c-0b62-4db1-9942-ad2bf4c080b0 - + + net9.0 + enable + Linux + c71a823c-0b62-4db1-9942-ad2bf4c080b0 + - - - - - - - - - - - - - - + + + - - - .dockerignore - - + + + + + + + + + + - - - - + + + .dockerignore + + - - - Always - - + + + + + + + + Always + + diff --git a/src/WebAPI/Program.cs b/src/WebAPI/Program.cs index e007c0829..542c88c36 100644 --- a/src/WebAPI/Program.cs +++ b/src/WebAPI/Program.cs @@ -14,8 +14,8 @@ // Configure appsettings builder.Configuration .SetBasePath(environment.ContentRootPath) - .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) - .AddJsonFile($"appsettings.{environment.EnvironmentName}.json", optional: true) + .AddJsonFile("appsettings.json", true, true) + .AddJsonFile($"appsettings.{environment.EnvironmentName}.json", true) .AddEnvironmentVariables(); // Add services to the container @@ -101,4 +101,6 @@ app.Run(); -public partial class Program { } \ No newline at end of file +public partial class Program +{ +} \ No newline at end of file diff --git a/tests/NeoServer.Game.Creatures.Tests/Combat/CombatTests.cs b/tests/NeoServer.Game.Creatures.Tests/Combat/CombatTests.cs index caca1953d..b031f2684 100644 --- a/tests/NeoServer.Game.Creatures.Tests/Combat/CombatTests.cs +++ b/tests/NeoServer.Game.Creatures.Tests/Combat/CombatTests.cs @@ -2,7 +2,6 @@ using NeoServer.Game.Common.Combat.Structs; using NeoServer.Game.Common.Creatures.Players; using NeoServer.Game.Common.Item; -using NeoServer.Game.Creatures.Player.Inventory; using NeoServer.Game.Tests.Helpers; using NeoServer.Game.Tests.Helpers.Player; using Xunit; @@ -17,28 +16,28 @@ public void Player_Gets_More_Damage_When_Has_Damage_Percentage_Increased() //arrange var victim = PlayerTestDataBuilder.Build(hp: 1000); var attacker = PlayerTestDataBuilder.Build(); - + //act victim.ReceiveAttack(attacker, new CombatDamage(100, DamageType.Physical)); - + //assert victim.HealthPoints.Should().Be(900); - + //act victim.IncreaseDamageReceived(100); victim.ReceiveAttack(attacker, new CombatDamage(100, DamageType.Physical)); - + //assert victim.HealthPoints.Should().Be(700); - + //act victim.DecreaseDamageReceived(100); victim.ReceiveAttack(attacker, new CombatDamage(100, DamageType.Physical)); - + //assert victim.HealthPoints.Should().Be(600); } - + [Fact] public void Player_Does_Not_Block_Attack_When_Shield_Defense_Is_Disabled() { @@ -46,31 +45,31 @@ public void Player_Does_Not_Block_Attack_When_Shield_Defense_Is_Disabled() var inventory = InventoryTestDataBuilder.Build(); var shield = ItemTestData.CreateBodyEquipmentItem(7, "", "shield"); shield.Metadata.Attributes.SetAttribute(ItemAttribute.Defense, byte.MaxValue); - + inventory.AddItem(shield, Slot.Right); - - var victim = PlayerTestDataBuilder.Build(hp: 1000, capacity: uint.MaxValue ); + + var victim = PlayerTestDataBuilder.Build(hp: 1000, capacity: uint.MaxValue); victim.AddInventory(inventory); - + var attacker = PlayerTestDataBuilder.Build(); - + //act victim.ReceiveAttack(attacker, new CombatDamage(1, DamageType.Melee)); //assert victim.HealthPoints.Should().Be(1000); - + //act victim.DisableShieldDefense(); victim.ReceiveAttack(attacker, new CombatDamage(1, DamageType.Melee)); //assert victim.HealthPoints.Should().Be(999); - + //act victim.EnableShieldDefense(); victim.ReceiveAttack(attacker, new CombatDamage(1, DamageType.Melee)); - + //assert victim.HealthPoints.Should().Be(999); } diff --git a/tests/NeoServer.Game.Systems.Tests/SafeTrade/PreTradeValidationTests.cs b/tests/NeoServer.Game.Systems.Tests/SafeTrade/PreTradeValidationTests.cs index df18353ab..dfd1996d1 100644 --- a/tests/NeoServer.Game.Systems.Tests/SafeTrade/PreTradeValidationTests.cs +++ b/tests/NeoServer.Game.Systems.Tests/SafeTrade/PreTradeValidationTests.cs @@ -1,5 +1,4 @@ -using System.Linq; -using FluentAssertions; +using FluentAssertions; using NeoServer.Game.Common.Item; using NeoServer.Game.Common.Location.Structs; using NeoServer.Game.Common.Services; diff --git a/tests/NeoServer.Game.Systems.Tests/SafeTrade/TradeCancellationTests.cs b/tests/NeoServer.Game.Systems.Tests/SafeTrade/TradeCancellationTests.cs index c5b363a95..4090d1c55 100644 --- a/tests/NeoServer.Game.Systems.Tests/SafeTrade/TradeCancellationTests.cs +++ b/tests/NeoServer.Game.Systems.Tests/SafeTrade/TradeCancellationTests.cs @@ -1,5 +1,4 @@ -using System.Threading; -using FluentAssertions; +using FluentAssertions; using NeoServer.Data.InMemory.DataStores; using NeoServer.Game.Common.Combat.Structs; using NeoServer.Game.Common.Contracts.Creatures; diff --git a/tests/NeoServer.Game.Systems.Tests/SafeTrade/TradeExchangeValidationTests.cs b/tests/NeoServer.Game.Systems.Tests/SafeTrade/TradeExchangeValidationTests.cs index 69feae210..449c7315e 100644 --- a/tests/NeoServer.Game.Systems.Tests/SafeTrade/TradeExchangeValidationTests.cs +++ b/tests/NeoServer.Game.Systems.Tests/SafeTrade/TradeExchangeValidationTests.cs @@ -1,5 +1,4 @@ -using System.Linq; -using FluentAssertions; +using FluentAssertions; using NeoServer.Game.Common.Contracts.Creatures; using NeoServer.Game.Common.Contracts.World; using NeoServer.Game.Common.Creatures.Players; diff --git a/tests/NeoServer.WebApi.Tests/NeoServer.WebApi.Tests.csproj b/tests/NeoServer.WebApi.Tests/NeoServer.WebApi.Tests.csproj index c32651472..bfd88c3b2 100644 --- a/tests/NeoServer.WebApi.Tests/NeoServer.WebApi.Tests.csproj +++ b/tests/NeoServer.WebApi.Tests/NeoServer.WebApi.Tests.csproj @@ -4,7 +4,7 @@ net9.0 enable false - true + true diff --git a/tests/NeoServer.WebApi.Tests/Tests/PlayerTests.cs b/tests/NeoServer.WebApi.Tests/Tests/PlayerTests.cs index f16b404bb..1f350696a 100644 --- a/tests/NeoServer.WebApi.Tests/Tests/PlayerTests.cs +++ b/tests/NeoServer.WebApi.Tests/Tests/PlayerTests.cs @@ -38,6 +38,5 @@ public async Task Get_Player_By_Id() response.Name.Should().Be(player.Name); } - #endregion } \ No newline at end of file From 768e28c19f2761d4c9d15d7e90ee0cc8fbb764c3 Mon Sep 17 00:00:00 2001 From: Caio Vidal Date: Thu, 26 Dec 2024 16:08:43 -0300 Subject: [PATCH 5/8] Fix item packets when otcv8 is active. (#629) * Code cleanup * Fix item packets when OTCv8 --- .../Contracts/Network/IConnection.cs | 1 + .../Contracts/Network/INetworkMessage.cs | 2 +- .../ContentModifiedOnContainerEventHandler.cs | 10 ++++++++-- .../PlayerOpenedContainerEventHandler.cs | 5 ++++- .../Player/PlayerChangedInventoryEventHandler.cs | 5 ++++- .../Player/PlayerSelfAppearOnMapEventHandler.cs | 5 ++++- .../Player/Trade/TradeRequestedEventHandler.cs | 15 ++++++++++++--- .../LogIn/PlayerLogInHandler.cs | 4 +++- .../Connection/Connection.cs | 1 + .../Messages/NetworkMessage.cs | 6 +++++- .../Outgoing/Item/AddItemContainerPacket.cs | 4 +++- .../Outgoing/Item/UpdateItemContainerPacket.cs | 4 +++- .../Outgoing/Player/OpenContainerPacket.cs | 5 +++-- .../Outgoing/Player/PlayerInventoryItemPacket.cs | 3 ++- .../Outgoing/Player/PlayerInventoryPacket.cs | 3 ++- .../Outgoing/Trade/TradeRequestPacket.cs | 4 ++-- 16 files changed, 58 insertions(+), 19 deletions(-) diff --git a/src/ApplicationServer/NeoServer.Server.Contracts/Contracts/Network/IConnection.cs b/src/ApplicationServer/NeoServer.Server.Contracts/Contracts/Network/IConnection.cs index 2875a354b..9a4df2222 100644 --- a/src/ApplicationServer/NeoServer.Server.Contracts/Contracts/Network/IConnection.cs +++ b/src/ApplicationServer/NeoServer.Server.Contracts/Contracts/Network/IConnection.cs @@ -17,6 +17,7 @@ public interface IConnection string Ip { get; } long TimeStamp { get; } byte RandomNumber { get; } + ushort OtcV8Version { get; set; } event EventHandler OnProcessEvent; event EventHandler OnCloseEvent; diff --git a/src/ApplicationServer/NeoServer.Server.Contracts/Contracts/Network/INetworkMessage.cs b/src/ApplicationServer/NeoServer.Server.Contracts/Contracts/Network/INetworkMessage.cs index daa2ddf75..d320563dc 100644 --- a/src/ApplicationServer/NeoServer.Server.Contracts/Contracts/Network/INetworkMessage.cs +++ b/src/ApplicationServer/NeoServer.Server.Contracts/Contracts/Network/INetworkMessage.cs @@ -14,7 +14,7 @@ public interface INetworkMessage : IReadOnlyNetworkMessage void AddUInt32(uint value); void WriteUint32(uint value, int position); byte[] AddHeader(bool addChecksum = true); - void AddItem(IItem item); + void AddItem(IItem item, bool showItemDescription = false); void AddLocation(Location location); void AddLength(); } \ No newline at end of file diff --git a/src/ApplicationServer/NeoServer.Server.Events/Items/ContentModifiedOnContainerEventHandler.cs b/src/ApplicationServer/NeoServer.Server.Events/Items/ContentModifiedOnContainerEventHandler.cs index e71c35dae..363357419 100644 --- a/src/ApplicationServer/NeoServer.Server.Events/Items/ContentModifiedOnContainerEventHandler.cs +++ b/src/ApplicationServer/NeoServer.Server.Events/Items/ContentModifiedOnContainerEventHandler.cs @@ -30,10 +30,16 @@ public void Execute(IPlayer player, ContainerOperation operation, byte container connection.OutgoingPackets.Enqueue(new RemoveItemContainerPacket(containerId, slotIndex, item)); break; case ContainerOperation.ItemAdded: - connection.OutgoingPackets.Enqueue(new AddItemContainerPacket(containerId, item)); + connection.OutgoingPackets.Enqueue(new AddItemContainerPacket(containerId, item) + { + ShowItemDescription = connection.OtcV8Version > 0 + }); break; case ContainerOperation.ItemUpdated: - connection.OutgoingPackets.Enqueue(new UpdateItemContainerPacket(containerId, slotIndex, item)); + connection.OutgoingPackets.Enqueue(new UpdateItemContainerPacket(containerId, slotIndex, item) + { + ShowItemDescription = connection.OtcV8Version > 0 + }); break; } diff --git a/src/ApplicationServer/NeoServer.Server.Events/Player/Containers/PlayerOpenedContainerEventHandler.cs b/src/ApplicationServer/NeoServer.Server.Events/Player/Containers/PlayerOpenedContainerEventHandler.cs index a59bfcfe9..aed80a703 100644 --- a/src/ApplicationServer/NeoServer.Server.Events/Player/Containers/PlayerOpenedContainerEventHandler.cs +++ b/src/ApplicationServer/NeoServer.Server.Events/Player/Containers/PlayerOpenedContainerEventHandler.cs @@ -23,7 +23,10 @@ private void SendContainerPacket(IPlayer player, byte containerId, IContainer co { if (!game.CreatureManager.GetPlayerConnection(player.CreatureId, out var connection)) return; - connection.OutgoingPackets.Enqueue(new OpenContainerPacket(container, containerId)); + connection.OutgoingPackets.Enqueue(new OpenContainerPacket(container, containerId) + { + WithDescription = connection.OtcV8Version > 0 + }); connection.Send(); } } \ No newline at end of file diff --git a/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerChangedInventoryEventHandler.cs b/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerChangedInventoryEventHandler.cs index 15cb44398..c815ee32b 100644 --- a/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerChangedInventoryEventHandler.cs +++ b/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerChangedInventoryEventHandler.cs @@ -28,7 +28,10 @@ public void Execute(IInventory inventory, IItem item, Slot slot, byte amount = 1 if (!game.CreatureManager.GetPlayerConnection(player.CreatureId, out var connection)) return; - connection.OutgoingPackets.Enqueue(new PlayerInventoryItemPacket(player.Inventory, slot)); + connection.OutgoingPackets.Enqueue(new PlayerInventoryItemPacket(player.Inventory, slot) + { + ShowItemDescription = connection.OtcV8Version > 0 + }); if (player.Shopping) connection.OutgoingPackets.Enqueue(new SaleItemListPacket(player, diff --git a/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerSelfAppearOnMapEventHandler.cs b/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerSelfAppearOnMapEventHandler.cs index 38aa4fe24..672501764 100644 --- a/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerSelfAppearOnMapEventHandler.cs +++ b/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerSelfAppearOnMapEventHandler.cs @@ -39,7 +39,10 @@ private void SendPacketsToPlayer(IPlayer player, IConnection connection) connection.OutgoingPackets.Enqueue(new SelfAppearPacket(player)); connection.OutgoingPackets.Enqueue(new MapDescriptionPacket(player, map)); connection.OutgoingPackets.Enqueue(new MagicEffectPacket(player.Location, EffectT.BubbleBlue)); - connection.OutgoingPackets.Enqueue(new PlayerInventoryPacket(player.Inventory)); + connection.OutgoingPackets.Enqueue(new PlayerInventoryPacket(player.Inventory) + { + ShowItemDescription = connection.OtcV8Version > 0 + }); connection.OutgoingPackets.Enqueue(new PlayerStatusPacket(player)); connection.OutgoingPackets.Enqueue(new PlayerSkillsPacket(player)); diff --git a/src/ApplicationServer/NeoServer.Server.Events/Player/Trade/TradeRequestedEventHandler.cs b/src/ApplicationServer/NeoServer.Server.Events/Player/Trade/TradeRequestedEventHandler.cs index 79a767917..9a366c788 100644 --- a/src/ApplicationServer/NeoServer.Server.Events/Player/Trade/TradeRequestedEventHandler.cs +++ b/src/ApplicationServer/NeoServer.Server.Events/Player/Trade/TradeRequestedEventHandler.cs @@ -27,7 +27,10 @@ public void Execute(TradeRequest tradeRequest) out var playerRequestedConnection); playerRequestingConnection.OutgoingPackets.Enqueue(new TradeRequestPacket(tradeRequest.PlayerRequesting.Name, - tradeRequest.Items)); + tradeRequest.Items) + { + ShowItemDescription = playerRequestingConnection.OtcV8Version > 0 + }); SendTradeMessage(tradeRequest, playerRequestedConnection); @@ -55,9 +58,15 @@ private static void SendAcknowledgeTradeToBothPlayers(TradeRequest tradeRequest, var items = SafeTradeSystem.GetTradedItems(tradeRequest.PlayerRequested); playerRequestingConnection.OutgoingPackets.Enqueue(new TradeRequestPacket(tradeRequest.PlayerRequested.Name, - items, true)); + items, true) + { + ShowItemDescription = playerRequestingConnection.OtcV8Version > 0 + }); playerRequestedConnection.OutgoingPackets.Enqueue(new TradeRequestPacket(tradeRequest.PlayerRequesting.Name, - tradeRequest.Items, true)); + tradeRequest.Items, true) + { + ShowItemDescription = playerRequestedConnection.OtcV8Version > 0 + }); } } \ No newline at end of file diff --git a/src/NetworkingServer/NeoServer.Networking.Handlers/LogIn/PlayerLogInHandler.cs b/src/NetworkingServer/NeoServer.Networking.Handlers/LogIn/PlayerLogInHandler.cs index f32f19a5b..de2906a07 100644 --- a/src/NetworkingServer/NeoServer.Networking.Handlers/LogIn/PlayerLogInHandler.cs +++ b/src/NetworkingServer/NeoServer.Networking.Handlers/LogIn/PlayerLogInHandler.cs @@ -75,7 +75,9 @@ private async Task Connect(IConnection connection, PlayerLogInPacket packet) Disconnect(connection, "Your account is banned."); return; } - + + connection.OtcV8Version = packet.OtcV8Version; + _game.Dispatcher.AddEvent(new Event(() => { var result = _playerLogInCommand.Execute(playerRecord, connection); diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Connection/Connection.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Connection/Connection.cs index 1bea74383..6cc342190 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Connection/Connection.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Connection/Connection.cs @@ -62,6 +62,7 @@ private bool Closed public long LastPingResponse { get; set; } public long TimeStamp { get; } public byte RandomNumber { get; } + public ushort OtcV8Version { get; set; } public event EventHandler OnProcessEvent; public event EventHandler OnCloseEvent; public event EventHandler OnPostProcessEvent; diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Messages/NetworkMessage.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Messages/NetworkMessage.cs index 9d559efd9..53de79824 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Messages/NetworkMessage.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Messages/NetworkMessage.cs @@ -60,13 +60,17 @@ public void AddString(string value) /// Inserts item object into the buffer. /// /// - public void AddItem(IItem item) + public void AddItem(IItem item, bool showItemDescription = false) { if (item == null) //todo log return; AddBytes(item.GetRaw().ToArray()); + if (showItemDescription) + { + AddString(""); + } } /// diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Item/AddItemContainerPacket.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Item/AddItemContainerPacket.cs index 34e7ce3d5..9daa77cc1 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Item/AddItemContainerPacket.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Item/AddItemContainerPacket.cs @@ -7,6 +7,7 @@ public class AddItemContainerPacket : OutgoingPacket { private readonly byte containerId; private readonly IItem item; + public required bool ShowItemDescription { get; init; } public AddItemContainerPacket(byte containerId, IItem item) { @@ -14,11 +15,12 @@ public AddItemContainerPacket(byte containerId, IItem item) this.item = item; } + public override void WriteToMessage(INetworkMessage message) { message.AddByte((byte)GameOutgoingPacketType.ContainerAddItem); message.AddByte(containerId); - message.AddItem(item); + message.AddItem(item, ShowItemDescription); } } \ No newline at end of file diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Item/UpdateItemContainerPacket.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Item/UpdateItemContainerPacket.cs index f83745add..834b094bc 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Item/UpdateItemContainerPacket.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Item/UpdateItemContainerPacket.cs @@ -16,12 +16,14 @@ public UpdateItemContainerPacket(byte containerId, byte slot, IItem item) this.slot = slot; } + public required bool ShowItemDescription { get; init; } + public override void WriteToMessage(INetworkMessage message) { message.AddByte((byte)GameOutgoingPacketType.ContainerUpdateItem); message.AddByte(containerId); message.AddByte(slot); - message.AddItem(item); + message.AddItem(item, ShowItemDescription); } } \ No newline at end of file diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Player/OpenContainerPacket.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Player/OpenContainerPacket.cs index db211ef2b..877d5a0c4 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Player/OpenContainerPacket.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Player/OpenContainerPacket.cs @@ -8,6 +8,7 @@ public class OpenContainerPacket : OutgoingPacket { private readonly IContainer container; private readonly byte containerId; + public required bool WithDescription { get; init; } public OpenContainerPacket(IContainer container, byte containerId) { @@ -20,7 +21,7 @@ public override void WriteToMessage(INetworkMessage message) message.AddByte((byte)GameOutgoingPacketType.ContainerOpen); message.AddByte(containerId); - message.AddItem(container); + message.AddItem(container, WithDescription); message.AddString(container.Name); message.AddByte(container.Capacity); @@ -28,6 +29,6 @@ public override void WriteToMessage(INetworkMessage message) message.AddByte(Math.Min((byte)0xFF, container.SlotsUsed)); - for (byte i = 0; i < container.SlotsUsed; i++) message.AddItem(container.Items[i]); + for (byte i = 0; i < container.SlotsUsed; i++) message.AddItem(container.Items[i], WithDescription); } } \ No newline at end of file diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Player/PlayerInventoryItemPacket.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Player/PlayerInventoryItemPacket.cs index 2cce908d6..472eb176b 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Player/PlayerInventoryItemPacket.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Player/PlayerInventoryItemPacket.cs @@ -8,6 +8,7 @@ public class PlayerInventoryItemPacket : OutgoingPacket { private readonly IInventory inventory; private readonly Slot slot; + public required bool ShowItemDescription { get; init; } public PlayerInventoryItemPacket(IInventory inventory, Slot slot) { @@ -26,7 +27,7 @@ public override void WriteToMessage(INetworkMessage message) { message.AddByte((byte)GameOutgoingPacketType.InventoryItem); message.AddByte((byte)slot); - message.AddItem(inventory[slot]); + message.AddItem(inventory[slot], ShowItemDescription); } } } \ No newline at end of file diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Player/PlayerInventoryPacket.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Player/PlayerInventoryPacket.cs index 9cd2011df..21e1bc4a9 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Player/PlayerInventoryPacket.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Player/PlayerInventoryPacket.cs @@ -8,6 +8,7 @@ namespace NeoServer.Networking.Packets.Outgoing.Player; public class PlayerInventoryPacket : OutgoingPacket { private readonly IInventory inventory; + public required bool ShowItemDescription { get; init; } public PlayerInventoryPacket(IInventory inventory) { @@ -27,7 +28,7 @@ public override void WriteToMessage(INetworkMessage message) { message.AddByte((byte)GameOutgoingPacketType.InventoryItem); message.AddByte((byte)slot); - message.AddItem(inventory[slot]); + message.AddItem(inventory[slot], ShowItemDescription); } }); diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Trade/TradeRequestPacket.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Trade/TradeRequestPacket.cs index 15121ff8a..c42eef4c3 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Trade/TradeRequestPacket.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Trade/TradeRequestPacket.cs @@ -15,7 +15,7 @@ public TradeRequestPacket(string playerName, IItem[] items, bool acknowledged = private string PlayerName { get; } private IItem[] Items { get; } private bool Acknowledged { get; } - + public required bool ShowItemDescription { get; init; } public void WriteToMessage(INetworkMessage message) { message.AddByte(Acknowledged @@ -25,6 +25,6 @@ public void WriteToMessage(INetworkMessage message) message.AddString(PlayerName); message.AddByte((byte)Items.Length); - foreach (var item in Items) message.AddItem(item); + foreach (var item in Items) message.AddItem(item, ShowItemDescription); } } \ No newline at end of file From 55e4f5ff4d0c2e79089c1218a0e3d804f49dddd0 Mon Sep 17 00:00:00 2001 From: Caio Vidal Date: Thu, 26 Dec 2024 18:20:58 -0300 Subject: [PATCH 6/8] Add otcv8 features to appsettings.json (#630) * Add otcv8 features to appsettings.json * Fix trade issue --- .../ContentModifiedOnContainerEventHandler.cs | 9 +++++--- .../PlayerOpenedContainerEventHandler.cs | 7 +++++-- .../PlayerChangedInventoryEventHandler.cs | 7 +++++-- .../PlayerSelfAppearOnMapEventHandler.cs | 21 +++++++++++-------- .../Trade/TradeRequestedEventHandler.cs | 13 +++++++----- .../Configurations/ServerConfiguration.cs | 9 ++++++++ .../Operations/TradeSlotDestinationQuery.cs | 2 +- .../LogIn/PlayerLogInHandler.cs | 12 +++++++++-- .../Messages/NetworkMessage.cs | 1 + .../Outgoing/Custom/FeaturesPacket.cs | 21 +++++++++++++++---- .../IoC/Modules/ConfigurationInjection.cs | 3 +++ src/Standalone/appsettings.json | 8 +++++++ 12 files changed, 85 insertions(+), 28 deletions(-) diff --git a/src/ApplicationServer/NeoServer.Server.Events/Items/ContentModifiedOnContainerEventHandler.cs b/src/ApplicationServer/NeoServer.Server.Events/Items/ContentModifiedOnContainerEventHandler.cs index 363357419..e46461edf 100644 --- a/src/ApplicationServer/NeoServer.Server.Events/Items/ContentModifiedOnContainerEventHandler.cs +++ b/src/ApplicationServer/NeoServer.Server.Events/Items/ContentModifiedOnContainerEventHandler.cs @@ -5,18 +5,21 @@ using NeoServer.Networking.Packets.Outgoing.Item; using NeoServer.Networking.Packets.Outgoing.Npc; using NeoServer.Server.Common.Contracts; +using NeoServer.Server.Configurations; namespace NeoServer.Server.Events.Items; public class ContentModifiedOnContainerEventHandler { private readonly ICoinTypeStore _coinTypeStore; + private readonly ClientConfiguration _clientConfiguration; private readonly IGameServer game; - public ContentModifiedOnContainerEventHandler(IGameServer game, ICoinTypeStore coinTypeStore) + public ContentModifiedOnContainerEventHandler(IGameServer game, ICoinTypeStore coinTypeStore, ClientConfiguration clientConfiguration) { this.game = game; _coinTypeStore = coinTypeStore; + _clientConfiguration = clientConfiguration; } public void Execute(IPlayer player, ContainerOperation operation, byte containerId, byte slotIndex, IItem item) @@ -32,13 +35,13 @@ public void Execute(IPlayer player, ContainerOperation operation, byte container case ContainerOperation.ItemAdded: connection.OutgoingPackets.Enqueue(new AddItemContainerPacket(containerId, item) { - ShowItemDescription = connection.OtcV8Version > 0 + ShowItemDescription = connection.OtcV8Version > 0 && _clientConfiguration.OtcV8.GameItemTooltip }); break; case ContainerOperation.ItemUpdated: connection.OutgoingPackets.Enqueue(new UpdateItemContainerPacket(containerId, slotIndex, item) { - ShowItemDescription = connection.OtcV8Version > 0 + ShowItemDescription = connection.OtcV8Version > 0 && _clientConfiguration.OtcV8.GameItemTooltip }); break; } diff --git a/src/ApplicationServer/NeoServer.Server.Events/Player/Containers/PlayerOpenedContainerEventHandler.cs b/src/ApplicationServer/NeoServer.Server.Events/Player/Containers/PlayerOpenedContainerEventHandler.cs index aed80a703..4fae44b87 100644 --- a/src/ApplicationServer/NeoServer.Server.Events/Player/Containers/PlayerOpenedContainerEventHandler.cs +++ b/src/ApplicationServer/NeoServer.Server.Events/Player/Containers/PlayerOpenedContainerEventHandler.cs @@ -2,16 +2,19 @@ using NeoServer.Game.Common.Contracts.Items.Types.Containers; using NeoServer.Networking.Packets.Outgoing.Player; using NeoServer.Server.Common.Contracts; +using NeoServer.Server.Configurations; namespace NeoServer.Server.Events.Player.Containers; public class PlayerOpenedContainerEventHandler { private readonly IGameServer game; + private readonly ClientConfiguration _clientConfiguration; - public PlayerOpenedContainerEventHandler(IGameServer game) + public PlayerOpenedContainerEventHandler(IGameServer game, ClientConfiguration clientConfiguration) { this.game = game; + _clientConfiguration = clientConfiguration; } public void Execute(IPlayer player, byte containerId, IContainer container) @@ -25,7 +28,7 @@ private void SendContainerPacket(IPlayer player, byte containerId, IContainer co connection.OutgoingPackets.Enqueue(new OpenContainerPacket(container, containerId) { - WithDescription = connection.OtcV8Version > 0 + WithDescription = connection.OtcV8Version > 0 && _clientConfiguration.OtcV8.GameItemTooltip }); connection.Send(); } diff --git a/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerChangedInventoryEventHandler.cs b/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerChangedInventoryEventHandler.cs index c815ee32b..78460560a 100644 --- a/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerChangedInventoryEventHandler.cs +++ b/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerChangedInventoryEventHandler.cs @@ -6,18 +6,21 @@ using NeoServer.Networking.Packets.Outgoing.Npc; using NeoServer.Networking.Packets.Outgoing.Player; using NeoServer.Server.Common.Contracts; +using NeoServer.Server.Configurations; namespace NeoServer.Server.Events.Player; public class PlayerChangedInventoryEventHandler { private readonly ICoinTypeStore _coinTypeStore; + private readonly ClientConfiguration _clientConfiguration; private readonly IGameServer game; - public PlayerChangedInventoryEventHandler(IGameServer game, ICoinTypeStore coinTypeStore) + public PlayerChangedInventoryEventHandler(IGameServer game, ICoinTypeStore coinTypeStore, ClientConfiguration clientConfiguration) { this.game = game; _coinTypeStore = coinTypeStore; + _clientConfiguration = clientConfiguration; } public void Execute(IInventory inventory, IItem item, Slot slot, byte amount = 1) @@ -30,7 +33,7 @@ public void Execute(IInventory inventory, IItem item, Slot slot, byte amount = 1 connection.OutgoingPackets.Enqueue(new PlayerInventoryItemPacket(player.Inventory, slot) { - ShowItemDescription = connection.OtcV8Version > 0 + ShowItemDescription = connection.OtcV8Version > 0 && _clientConfiguration.OtcV8.GameItemTooltip }); if (player.Shopping) diff --git a/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerSelfAppearOnMapEventHandler.cs b/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerSelfAppearOnMapEventHandler.cs index 672501764..e58b69341 100644 --- a/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerSelfAppearOnMapEventHandler.cs +++ b/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerSelfAppearOnMapEventHandler.cs @@ -9,18 +9,21 @@ using NeoServer.Networking.Packets.Outgoing.Player; using NeoServer.Server.Common.Contracts; using NeoServer.Server.Common.Contracts.Network; +using NeoServer.Server.Configurations; namespace NeoServer.Server.Events.Player; public class PlayerSelfAppearOnMapEventHandler : IEventHandler { - private readonly IGameServer game; - private readonly IMap map; + private readonly IGameServer _game; + private readonly ClientConfiguration _clientConfiguration; + private readonly IMap _map; - public PlayerSelfAppearOnMapEventHandler(IMap map, IGameServer game) + public PlayerSelfAppearOnMapEventHandler(IMap map, IGameServer game, ClientConfiguration clientConfiguration) { - this.map = map; - this.game = game; + _map = map; + _game = game; + _clientConfiguration = clientConfiguration; } public void Execute(IWalkableCreature creature) @@ -29,7 +32,7 @@ public void Execute(IWalkableCreature creature) if (creature is not IPlayer player) return; - if (!game.CreatureManager.GetPlayerConnection(creature.CreatureId, out var connection)) return; + if (!_game.CreatureManager.GetPlayerConnection(creature.CreatureId, out var connection)) return; SendPacketsToPlayer(player, connection); } @@ -37,16 +40,16 @@ public void Execute(IWalkableCreature creature) private void SendPacketsToPlayer(IPlayer player, IConnection connection) { connection.OutgoingPackets.Enqueue(new SelfAppearPacket(player)); - connection.OutgoingPackets.Enqueue(new MapDescriptionPacket(player, map)); + connection.OutgoingPackets.Enqueue(new MapDescriptionPacket(player, _map)); connection.OutgoingPackets.Enqueue(new MagicEffectPacket(player.Location, EffectT.BubbleBlue)); connection.OutgoingPackets.Enqueue(new PlayerInventoryPacket(player.Inventory) { - ShowItemDescription = connection.OtcV8Version > 0 + ShowItemDescription = connection.OtcV8Version > 0 && _clientConfiguration.OtcV8.GameItemTooltip }); connection.OutgoingPackets.Enqueue(new PlayerStatusPacket(player)); connection.OutgoingPackets.Enqueue(new PlayerSkillsPacket(player)); - connection.OutgoingPackets.Enqueue(new WorldLightPacket(game.LightLevel, game.LightColor)); + connection.OutgoingPackets.Enqueue(new WorldLightPacket(_game.LightLevel, _game.LightColor)); connection.OutgoingPackets.Enqueue(new CreatureLightPacket(player)); diff --git a/src/ApplicationServer/NeoServer.Server.Events/Player/Trade/TradeRequestedEventHandler.cs b/src/ApplicationServer/NeoServer.Server.Events/Player/Trade/TradeRequestedEventHandler.cs index 9a366c788..17e6a1c9d 100644 --- a/src/ApplicationServer/NeoServer.Server.Events/Player/Trade/TradeRequestedEventHandler.cs +++ b/src/ApplicationServer/NeoServer.Server.Events/Player/Trade/TradeRequestedEventHandler.cs @@ -5,16 +5,19 @@ using NeoServer.Networking.Packets.Outgoing.Trade; using NeoServer.Server.Common.Contracts; using NeoServer.Server.Common.Contracts.Network; +using NeoServer.Server.Configurations; namespace NeoServer.Server.Events.Player.Trade; public class TradeRequestedEventHandler : IEventHandler { private readonly IGameServer _gameServer; + private readonly ClientConfiguration _clientConfiguration; - public TradeRequestedEventHandler(IGameServer gameServer) + public TradeRequestedEventHandler(IGameServer gameServer, ClientConfiguration clientConfiguration) { _gameServer = gameServer; + _clientConfiguration = clientConfiguration; } public void Execute(TradeRequest tradeRequest) @@ -29,7 +32,7 @@ public void Execute(TradeRequest tradeRequest) playerRequestingConnection.OutgoingPackets.Enqueue(new TradeRequestPacket(tradeRequest.PlayerRequesting.Name, tradeRequest.Items) { - ShowItemDescription = playerRequestingConnection.OtcV8Version > 0 + ShowItemDescription = playerRequestingConnection.OtcV8Version > 0 && _clientConfiguration.OtcV8.GameItemTooltip }); SendTradeMessage(tradeRequest, playerRequestedConnection); @@ -49,7 +52,7 @@ private static void SendTradeMessage(TradeRequest tradeRequest, IConnection play TextMessageOutgoingType.Small)); } - private static void SendAcknowledgeTradeToBothPlayers(TradeRequest tradeRequest, + private void SendAcknowledgeTradeToBothPlayers(TradeRequest tradeRequest, IConnection playerRequestingConnection, IConnection playerRequestedConnection) { @@ -60,13 +63,13 @@ private static void SendAcknowledgeTradeToBothPlayers(TradeRequest tradeRequest, playerRequestingConnection.OutgoingPackets.Enqueue(new TradeRequestPacket(tradeRequest.PlayerRequested.Name, items, true) { - ShowItemDescription = playerRequestingConnection.OtcV8Version > 0 + ShowItemDescription = playerRequestingConnection.OtcV8Version > 0 && _clientConfiguration.OtcV8.GameItemTooltip }); playerRequestedConnection.OutgoingPackets.Enqueue(new TradeRequestPacket(tradeRequest.PlayerRequesting.Name, tradeRequest.Items, true) { - ShowItemDescription = playerRequestedConnection.OtcV8Version > 0 + ShowItemDescription = playerRequestedConnection.OtcV8Version > 0 && _clientConfiguration.OtcV8.GameItemTooltip }); } } \ No newline at end of file diff --git a/src/ApplicationServer/NeoServer.Server/Configurations/ServerConfiguration.cs b/src/ApplicationServer/NeoServer.Server/Configurations/ServerConfiguration.cs index 8faf481d0..721c157c0 100644 --- a/src/ApplicationServer/NeoServer.Server/Configurations/ServerConfiguration.cs +++ b/src/ApplicationServer/NeoServer.Server/Configurations/ServerConfiguration.cs @@ -39,4 +39,13 @@ public record GrayLogConfiguration( string HostnameOverride, string Facility) { +} + +public record ClientConfiguration(ClientConfiguration.OtcV8Configuration OtcV8) +{ + public record OtcV8Configuration( + bool GameExtendedOpcode, + bool GameEnvironmentEffect, + bool GameExtendedClientPing, + bool GameItemTooltip); } \ No newline at end of file diff --git a/src/GameWorldSimulator/NeoServer.Game.Systems/SafeTrade/Operations/TradeSlotDestinationQuery.cs b/src/GameWorldSimulator/NeoServer.Game.Systems/SafeTrade/Operations/TradeSlotDestinationQuery.cs index 8039eea1a..7945ed312 100644 --- a/src/GameWorldSimulator/NeoServer.Game.Systems/SafeTrade/Operations/TradeSlotDestinationQuery.cs +++ b/src/GameWorldSimulator/NeoServer.Game.Systems/SafeTrade/Operations/TradeSlotDestinationQuery.cs @@ -12,7 +12,7 @@ public static Slot Get(IPlayer player, IItem itemToAdd, IItem itemToBeRemoved) var existingItemOnSlot = player.Inventory[itemToAdd.Metadata.BodyPosition]; if (itemToAdd.IsCumulative && - existingItemOnSlot.ServerId == itemToAdd.ServerId && + existingItemOnSlot?.ServerId == itemToAdd.ServerId && itemToAdd.Amount + existingItemOnSlot.Amount == 100) return itemToAdd.Metadata.BodyPosition; var slotDestination = GetTwoHandedWeaponSlotDestination(player, itemToAdd, itemToBeRemoved); diff --git a/src/NetworkingServer/NeoServer.Networking.Handlers/LogIn/PlayerLogInHandler.cs b/src/NetworkingServer/NeoServer.Networking.Handlers/LogIn/PlayerLogInHandler.cs index de2906a07..e30493502 100644 --- a/src/NetworkingServer/NeoServer.Networking.Handlers/LogIn/PlayerLogInHandler.cs +++ b/src/NetworkingServer/NeoServer.Networking.Handlers/LogIn/PlayerLogInHandler.cs @@ -20,17 +20,19 @@ public class PlayerLogInHandler : PacketHandler private readonly IGameServer _game; private readonly PlayerLogInCommand _playerLogInCommand; private readonly PlayerLogOutCommand _playerLogOutCommand; + private readonly ClientConfiguration _clientConfiguration; private readonly ServerConfiguration _serverConfiguration; public PlayerLogInHandler(IAccountRepository repositoryNeo, IGameServer game, ServerConfiguration serverConfiguration, PlayerLogInCommand playerLogInCommand, - PlayerLogOutCommand playerLogOutCommand) + PlayerLogOutCommand playerLogOutCommand, ClientConfiguration clientConfiguration) { _accountRepository = repositoryNeo; _game = game; _serverConfiguration = serverConfiguration; _playerLogInCommand = playerLogInCommand; _playerLogOutCommand = playerLogOutCommand; + _clientConfiguration = clientConfiguration; } public override void HandleMessage(IReadOnlyNetworkMessage message, IConnection connection) @@ -89,7 +91,13 @@ private async Task Connect(IConnection connection, PlayerLogInPacket packet) if (packet.OtcV8Version > 0 || packet.OperatingSystem >= OperatingSystem.OtcLinux) { - if (packet.OtcV8Version > 0) connection.Send(new FeaturesPacket()); + if (packet.OtcV8Version > 0) connection.Send(new FeaturesPacket + { + GameEnvironmentEffect = _clientConfiguration.OtcV8.GameEnvironmentEffect, + GameExtendedOpcode = _clientConfiguration.OtcV8.GameExtendedOpcode, + GameExtendedClientPing = _clientConfiguration.OtcV8.GameExtendedClientPing, + GameItemTooltip = _clientConfiguration.OtcV8.GameItemTooltip + }); connection.Send(new OpcodeMessagePacket()); } })); diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Messages/NetworkMessage.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Messages/NetworkMessage.cs index 53de79824..19f9e3b82 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Messages/NetworkMessage.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Messages/NetworkMessage.cs @@ -67,6 +67,7 @@ public void AddItem(IItem item, bool showItemDescription = false) return; AddBytes(item.GetRaw().ToArray()); + if (showItemDescription) { AddString(""); diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Custom/FeaturesPacket.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Custom/FeaturesPacket.cs index f672c274a..dc5188ca7 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Custom/FeaturesPacket.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Custom/FeaturesPacket.cs @@ -5,6 +5,10 @@ namespace NeoServer.Networking.Packets.Outgoing.Custom; public class FeaturesPacket : OutgoingPacket { + public required bool GameExtendedOpcode { get; init; } + public required bool GameEnvironmentEffect { get; init; } + public required bool GameExtendedClientPing { get; init; } + public required bool GameItemTooltip { get; init; } public override void WriteToMessage(INetworkMessage message) { message.AddByte(0x43); @@ -12,15 +16,24 @@ public override void WriteToMessage(INetworkMessage message) var features = new Dictionary { - [80] = true, - [13] = false, - [25] = true, - [93] = true + [(byte)Feature.GameExtendedOpcode] = GameExtendedOpcode, + [(byte)Feature.GameEnvironmentEffect] = GameEnvironmentEffect, + [(byte)Feature.GameExtendedClientPing] = GameExtendedClientPing, + [(byte)Feature.GameItemTooltip] = GameItemTooltip }; + foreach (var feature in features) { message.AddByte(feature.Key); message.AddByte((byte)(feature.Value ? 1 : 0)); } } + + private enum Feature : byte + { + GameExtendedOpcode = 80, + GameEnvironmentEffect = 13, + GameExtendedClientPing = 25, + GameItemTooltip = 93 + } } \ No newline at end of file diff --git a/src/Standalone/IoC/Modules/ConfigurationInjection.cs b/src/Standalone/IoC/Modules/ConfigurationInjection.cs index ca0eb1018..e5b040607 100644 --- a/src/Standalone/IoC/Modules/ConfigurationInjection.cs +++ b/src/Standalone/IoC/Modules/ConfigurationInjection.cs @@ -32,16 +32,19 @@ public static IServiceCollection AddConfigurations(this IServiceCollection build new(0, null, null, null, string.Empty, string.Empty, string.Empty, 7171, 7172, new SaveConfiguration(3600)); GameConfiguration gameConfiguration = new(); LogConfiguration logConfiguration = new(null); + ClientConfiguration clientConfiguration = new(null); configuration.GetSection("server").Bind(serverConfiguration); configuration.GetSection("game").Bind(gameConfiguration); configuration.GetSection("log").Bind(logConfiguration); + configuration.GetSection("client").Bind(clientConfiguration); LoadEnvironmentVariables(ref serverConfiguration); builder.AddSingleton(serverConfiguration); builder.AddSingleton(gameConfiguration); builder.AddSingleton(logConfiguration); + builder.AddSingleton(clientConfiguration); return builder; } diff --git a/src/Standalone/appsettings.json b/src/Standalone/appsettings.json index 649752b51..921f7f415 100644 --- a/src/Standalone/appsettings.json +++ b/src/Standalone/appsettings.json @@ -29,6 +29,14 @@ "fishing": 1.5 } }, + "client": { + "otcv8": { + "GameExtendedOpcode": false, + "GameEnvironmentEffect": false, + "GameExtendedClientPing": true, + "GameItemTooltip": false + } + }, "database": { "connections": { "INMEMORY": "neo", From 58b87a8e0bc407882151289c8f05b4f40c336d67 Mon Sep 17 00:00:00 2001 From: Caio Vidal Date: Thu, 26 Dec 2024 19:53:14 -0300 Subject: [PATCH 7/8] Add item tooltip to otcv8 (#631) * Add otcv8 features to appsettings.json * Fix trade issue * Add item tooltip to otcv8 * Remove IInspectionTextBuilder.cs * Fix build * Fix unit tests --- .../Events/Startup/VocationConverter.cs | 4 +- .../Player/PlayerLookedAtEventHandler.cs | 2 +- .../PlayerSelfAppearOnMapEventHandler.cs | 1 + .../Inspection/IInspectionTextBuilder.cs | 8 +- .../Contracts/Items/IThing.cs | 3 +- .../Item/ItemAttribute.cs | 3 +- .../Models/Bases/Creature.cs | 2 +- .../NeoServer.Game.Items/Bases/BaseItem.cs | 13 +-- .../Inspection/InspectionTextBuilder.cs | 26 ++---- .../RequirementInspectionTextBuilder.cs | 15 +-- .../NeoServer.Game.Items/Items/Sign.cs | 6 +- .../Models/Tiles/BaseTile.cs | 5 +- .../LogIn/PlayerLogInHandler.cs | 24 +++-- .../Messages/NetworkMessage.cs | 2 +- .../Outgoing/Player/PlayerInventoryPacket.cs | 24 ++--- src/Standalone/appsettings.json | 2 +- .../Inspection/InspectionTextBuilderTest.cs | 28 ++---- .../RequirementInspectionTextBuilderTests.cs | 91 ++++++------------- 18 files changed, 101 insertions(+), 158 deletions(-) diff --git a/data/extensions/Events/Startup/VocationConverter.cs b/data/extensions/Events/Startup/VocationConverter.cs index 0cbf6bd3e..9506b0a75 100644 --- a/data/extensions/Events/Startup/VocationConverter.cs +++ b/data/extensions/Events/Startup/VocationConverter.cs @@ -29,8 +29,10 @@ public void Run() foreach (var itemType in _itemTypeStore.All) { var vocationsAttr = itemType.Attributes.GetAttributeArray(ItemAttribute.Vocation); - if (vocationsAttr is not string[] vocations) continue; + if (vocationsAttr is not string[] vocations) continue; + + itemType.Attributes.SetAttribute(ItemAttribute.VocationNames, vocations); var vocationsType = new List(vocations.Length); foreach (var vocation in vocations) diff --git a/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerLookedAtEventHandler.cs b/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerLookedAtEventHandler.cs index c9b83eaa5..cea30c5ee 100644 --- a/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerLookedAtEventHandler.cs +++ b/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerLookedAtEventHandler.cs @@ -24,7 +24,7 @@ public void Execute(IPlayer player, IThing thing, bool isClose) var inspectionTextBuilder = GetInspectionTextBuilder(thing); - var text = thing.GetLookText(inspectionTextBuilder, player, isClose); + var text = thing.GetLookText( isClose, player.CanSeeInspectionDetails); connection.OutgoingPackets.Enqueue(new TextMessagePacket(text, TextMessageOutgoingType.Description)); connection.Send(); diff --git a/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerSelfAppearOnMapEventHandler.cs b/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerSelfAppearOnMapEventHandler.cs index e58b69341..1f0cec2be 100644 --- a/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerSelfAppearOnMapEventHandler.cs +++ b/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerSelfAppearOnMapEventHandler.cs @@ -46,6 +46,7 @@ private void SendPacketsToPlayer(IPlayer player, IConnection connection) { ShowItemDescription = connection.OtcV8Version > 0 && _clientConfiguration.OtcV8.GameItemTooltip }); + connection.OutgoingPackets.Enqueue(new PlayerStatusPacket(player)); connection.OutgoingPackets.Enqueue(new PlayerSkillsPacket(player)); diff --git a/src/GameWorldSimulator/NeoServer.Game.Common/Contracts/Inspection/IInspectionTextBuilder.cs b/src/GameWorldSimulator/NeoServer.Game.Common/Contracts/Inspection/IInspectionTextBuilder.cs index 4d1589394..eedba4b1d 100644 --- a/src/GameWorldSimulator/NeoServer.Game.Common/Contracts/Inspection/IInspectionTextBuilder.cs +++ b/src/GameWorldSimulator/NeoServer.Game.Common/Contracts/Inspection/IInspectionTextBuilder.cs @@ -1,19 +1,17 @@ -using System; -using NeoServer.Game.Common.Contracts.Creatures; +using System; using NeoServer.Game.Common.Contracts.Items; namespace NeoServer.Game.Common.Contracts.Inspection; public interface IInspectionTextBuilder -{ - string Build(IThing thing, IPlayer player, bool isClose = false); +{ bool IsApplicable(IThing thing); public static string GetArticle(string name) { if (string.IsNullOrWhiteSpace(name)) return "a"; - Span vowels = stackalloc char[5] { 'a', 'e', 'i', 'o', 'u' }; + Span vowels = ['a', 'e', 'i', 'o', 'u']; return vowels.Contains(name.ToLower()[0]) ? "an" : "a"; } } \ No newline at end of file diff --git a/src/GameWorldSimulator/NeoServer.Game.Common/Contracts/Items/IThing.cs b/src/GameWorldSimulator/NeoServer.Game.Common/Contracts/Items/IThing.cs index 0ddd2188e..92d83634f 100644 --- a/src/GameWorldSimulator/NeoServer.Game.Common/Contracts/Items/IThing.cs +++ b/src/GameWorldSimulator/NeoServer.Game.Common/Contracts/Items/IThing.cs @@ -13,8 +13,7 @@ public interface IThing : IUsable Location.Structs.Location Location { get; } - string GetLookText(IInspectionTextBuilder inspectionTextBuilder, IPlayer player, bool isClose = false); - + string GetLookText(bool isClose = false, bool showInternalDetails = false); public bool IsCloseTo(IThing thing) { if (Location.Type is not LocationType.Ground && diff --git a/src/GameWorldSimulator/NeoServer.Game.Common/Item/ItemAttribute.cs b/src/GameWorldSimulator/NeoServer.Game.Common/Item/ItemAttribute.cs index e7f0148fe..1af5eb0b5 100644 --- a/src/GameWorldSimulator/NeoServer.Game.Common/Item/ItemAttribute.cs +++ b/src/GameWorldSimulator/NeoServer.Game.Common/Item/ItemAttribute.cs @@ -207,5 +207,6 @@ public enum ItemAttribute : byte ManaUse, CooldownTime, UseOn, - DecayElapsed + DecayElapsed, + VocationNames } \ No newline at end of file diff --git a/src/GameWorldSimulator/NeoServer.Game.Creatures/Models/Bases/Creature.cs b/src/GameWorldSimulator/NeoServer.Game.Creatures/Models/Bases/Creature.cs index fb0e75cf5..46dbae080 100644 --- a/src/GameWorldSimulator/NeoServer.Game.Creatures/Models/Bases/Creature.cs +++ b/src/GameWorldSimulator/NeoServer.Game.Creatures/Models/Bases/Creature.cs @@ -60,7 +60,7 @@ protected set public uint MaxHealthPoints { get; protected set; } public string Name => CreatureType.Name; - public string GetLookText(IInspectionTextBuilder inspectionTextBuilder, IPlayer player, bool isClose = false) + public string GetLookText(bool isClose = false, bool showInternalDetails = false) { return $"You see {(isClose ? CloseInspectionText : InspectionText)}"; } diff --git a/src/GameWorldSimulator/NeoServer.Game.Items/Bases/BaseItem.cs b/src/GameWorldSimulator/NeoServer.Game.Items/Bases/BaseItem.cs index 736d1ea54..47db1db48 100644 --- a/src/GameWorldSimulator/NeoServer.Game.Items/Bases/BaseItem.cs +++ b/src/GameWorldSimulator/NeoServer.Game.Items/Bases/BaseItem.cs @@ -5,6 +5,7 @@ using NeoServer.Game.Common.Contracts.Items.Types.Containers; using NeoServer.Game.Common.Location.Structs; using NeoServer.Game.Items.Factories.AttributeFactory; +using NeoServer.Game.Items.Inspection; namespace NeoServer.Game.Items.Bases; @@ -63,14 +64,14 @@ public void SetNewLocation(Location location) Location = location; } - public virtual string GetLookText(IInspectionTextBuilder inspectionTextBuilder, IPlayer player, - bool isClose = false) + public virtual string GetLookText( + bool isClose = false, bool showInternalDetails = false) { - return inspectionTextBuilder is null - ? $"You see {Metadata.Article} {Metadata.Name}." - : inspectionTextBuilder.Build(this, player, isClose); + return InspectionTextBuilder.IsApplicable(this) + ? InspectionTextBuilder.Build(this, isClose, showInternalDetails) + : $"You see {Metadata.Article} {Metadata.Name}."; } - + public string FullName => Metadata.FullName; public byte Amount { get; set; } = 1; diff --git a/src/GameWorldSimulator/NeoServer.Game.Items/Inspection/InspectionTextBuilder.cs b/src/GameWorldSimulator/NeoServer.Game.Items/Inspection/InspectionTextBuilder.cs index 674ad6712..a0e24425a 100644 --- a/src/GameWorldSimulator/NeoServer.Game.Items/Inspection/InspectionTextBuilder.cs +++ b/src/GameWorldSimulator/NeoServer.Game.Items/Inspection/InspectionTextBuilder.cs @@ -1,30 +1,20 @@ using System.Globalization; using System.Text; -using NeoServer.Game.Common.Contracts.Creatures; -using NeoServer.Game.Common.Contracts.DataStores; -using NeoServer.Game.Common.Contracts.Inspection; using NeoServer.Game.Common.Contracts.Items; using NeoServer.Game.Common.Contracts.Items.Types; using NeoServer.Game.Common.Helpers; namespace NeoServer.Game.Items.Inspection; -public class InspectionTextBuilder : IInspectionTextBuilder +public class InspectionTextBuilder { - private readonly IVocationStore _vocationStore; - - public InspectionTextBuilder(IVocationStore vocationStore) - { - _vocationStore = vocationStore; - } - - public string Build(IThing thing, IPlayer player, bool isClose = false) + public static string Build(IThing thing, bool isClose = false, bool showInternalDetails = false) { if (thing is not IItem item) return string.Empty; var inspectionText = new StringBuilder(); - AddItemName(item, player, inspectionText); + AddItemName(item, showInternalDetails, inspectionText); AddEquipmentAttributes(item, inspectionText); inspectionText.AppendNewLine("."); AddRequirement(item, inspectionText); @@ -37,14 +27,14 @@ public string Build(IThing thing, IPlayer player, bool isClose = false) return $"{finalText}"; } - public bool IsApplicable(IThing thing) + public static bool IsApplicable(IThing thing) { return thing is IItem; } - private void AddRequirement(IItem item, StringBuilder inspectionText) + private static void AddRequirement(IItem item, StringBuilder inspectionText) { - var result = RequirementInspectionTextBuilder.Build(item, _vocationStore); + var result = RequirementInspectionTextBuilder.Build(item); if (string.IsNullOrWhiteSpace(result)) return; inspectionText.AppendNewLine(result); } @@ -62,9 +52,9 @@ private static void AddWeight(IItem item, bool isClose, StringBuilder inspection $"{(item is ICumulative ? "They weigh" : "It weighs")} {item.Weight.ToString("F", CultureInfo.InvariantCulture)} oz."); } - private static void AddItemName(IItem item, IPlayer player, StringBuilder inspectionText) + private static void AddItemName(IItem item, bool showInternalDetails, StringBuilder inspectionText) { - if (player.CanSeeInspectionDetails) + if (showInternalDetails) inspectionText.AppendNewLine($"Id: [{item.ServerId}] - Pos: {item.Location}"); inspectionText.Append("You see "); diff --git a/src/GameWorldSimulator/NeoServer.Game.Items/Inspection/RequirementInspectionTextBuilder.cs b/src/GameWorldSimulator/NeoServer.Game.Items/Inspection/RequirementInspectionTextBuilder.cs index e23794911..c666f81a1 100644 --- a/src/GameWorldSimulator/NeoServer.Game.Items/Inspection/RequirementInspectionTextBuilder.cs +++ b/src/GameWorldSimulator/NeoServer.Game.Items/Inspection/RequirementInspectionTextBuilder.cs @@ -1,21 +1,21 @@ using System.Text; -using NeoServer.Game.Common.Contracts.DataStores; using NeoServer.Game.Common.Contracts.Items; using NeoServer.Game.Common.Helpers; +using NeoServer.Game.Common.Item; namespace NeoServer.Game.Items.Inspection; public static class RequirementInspectionTextBuilder { - public static string Build(IItem item, IVocationStore vocationStore) + public static string Build(IItem item) { if (item is not IRequirement itemRequirement) return string.Empty; - var vocations = itemRequirement.Vocations; + var vocations = itemRequirement.Metadata.Attributes.GetAttributeArray(ItemAttribute.VocationNames); var minLevel = itemRequirement.MinLevel; if (Guard.IsNullOrEmpty(vocations) && minLevel == 0) return string.Empty; - var vocationsText = FormatVocations(vocations, vocationStore); + var vocationsText = FormatVocations(vocations); var verb = itemRequirement switch { @@ -29,14 +29,15 @@ public static string Build(IItem item, IVocationStore vocationStore) $"It can only be {verb} properly by {vocationsText}{(minLevel > 0 ? $" of level {minLevel} or higher" : string.Empty)}."; } - private static string FormatVocations(byte[] allVocations, IVocationStore vocationStore) + private static string FormatVocations(string[] allVocations) { if (Guard.IsNullOrEmpty(allVocations)) return "players"; var text = new StringBuilder(); for (var i = 0; i < allVocations.Length; i++) { - if (!vocationStore.TryGetValue(allVocations[i], out var vocation)) continue; - text.Append($"{vocation.Name.ToLower()}s"); + var vocation = allVocations[i]; + + text.Append($"{vocation.ToLower()}s"); var lastItem = i == allVocations.Length - 1; var penultimate = i == allVocations.Length - 2; if (lastItem) continue; diff --git a/src/GameWorldSimulator/NeoServer.Game.Items/Items/Sign.cs b/src/GameWorldSimulator/NeoServer.Game.Items/Items/Sign.cs index 5836eddfe..bb3bc5e02 100644 --- a/src/GameWorldSimulator/NeoServer.Game.Items/Items/Sign.cs +++ b/src/GameWorldSimulator/NeoServer.Game.Items/Items/Sign.cs @@ -22,10 +22,10 @@ public Sign(IItemType metadata, Location location, IDictionary string.Empty; public void Use(IPlayer usedBy) { diff --git a/src/NetworkingServer/NeoServer.Networking.Handlers/LogIn/PlayerLogInHandler.cs b/src/NetworkingServer/NeoServer.Networking.Handlers/LogIn/PlayerLogInHandler.cs index e30493502..bbc8cecbe 100644 --- a/src/NetworkingServer/NeoServer.Networking.Handlers/LogIn/PlayerLogInHandler.cs +++ b/src/NetworkingServer/NeoServer.Networking.Handlers/LogIn/PlayerLogInHandler.cs @@ -79,6 +79,17 @@ private async Task Connect(IConnection connection, PlayerLogInPacket packet) } connection.OtcV8Version = packet.OtcV8Version; + if (packet.OtcV8Version > 0 || packet.OperatingSystem >= OperatingSystem.OtcLinux) + { + if (packet.OtcV8Version > 0) connection.Send(new FeaturesPacket + { + GameEnvironmentEffect = _clientConfiguration.OtcV8.GameEnvironmentEffect, + GameExtendedOpcode = _clientConfiguration.OtcV8.GameExtendedOpcode, + GameExtendedClientPing = _clientConfiguration.OtcV8.GameExtendedClientPing, + GameItemTooltip = _clientConfiguration.OtcV8.GameItemTooltip + }); + connection.Send(new OpcodeMessagePacket()); + } _game.Dispatcher.AddEvent(new Event(() => { @@ -86,19 +97,6 @@ private async Task Connect(IConnection connection, PlayerLogInPacket packet) if (result.Failed) { Disconnect(connection, TextMessageOutgoingParser.Parse(result.Error)); - return; - } - - if (packet.OtcV8Version > 0 || packet.OperatingSystem >= OperatingSystem.OtcLinux) - { - if (packet.OtcV8Version > 0) connection.Send(new FeaturesPacket - { - GameEnvironmentEffect = _clientConfiguration.OtcV8.GameEnvironmentEffect, - GameExtendedOpcode = _clientConfiguration.OtcV8.GameExtendedOpcode, - GameExtendedClientPing = _clientConfiguration.OtcV8.GameExtendedClientPing, - GameItemTooltip = _clientConfiguration.OtcV8.GameItemTooltip - }); - connection.Send(new OpcodeMessagePacket()); } })); } diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Messages/NetworkMessage.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Messages/NetworkMessage.cs index 19f9e3b82..ac085ac9e 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Messages/NetworkMessage.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Messages/NetworkMessage.cs @@ -70,7 +70,7 @@ public void AddItem(IItem item, bool showItemDescription = false) if (showItemDescription) { - AddString(""); + AddString(item.GetLookText(true)); } } diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Player/PlayerInventoryPacket.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Player/PlayerInventoryPacket.cs index 21e1bc4a9..757067742 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Player/PlayerInventoryPacket.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Player/PlayerInventoryPacket.cs @@ -17,7 +17,7 @@ public PlayerInventoryPacket(IInventory inventory) public override void WriteToMessage(INetworkMessage message) { - var addInventoryItem = new Action(slot => + void SendInventoryItem(Slot slot) { if (inventory[slot] == null) { @@ -30,17 +30,17 @@ public override void WriteToMessage(INetworkMessage message) message.AddByte((byte)slot); message.AddItem(inventory[slot], ShowItemDescription); } - }); + }; - addInventoryItem(Slot.Head); - addInventoryItem(Slot.Necklace); - addInventoryItem(Slot.Backpack); - addInventoryItem(Slot.Body); - addInventoryItem(Slot.Right); - addInventoryItem(Slot.Left); - addInventoryItem(Slot.Legs); - addInventoryItem(Slot.Feet); - addInventoryItem(Slot.Ring); - addInventoryItem(Slot.Ammo); + SendInventoryItem(Slot.Head); + SendInventoryItem(Slot.Necklace); + SendInventoryItem(Slot.Backpack); + SendInventoryItem(Slot.Body); + SendInventoryItem(Slot.Right); + SendInventoryItem(Slot.Left); + SendInventoryItem(Slot.Legs); + SendInventoryItem(Slot.Feet); + SendInventoryItem(Slot.Ring); + SendInventoryItem(Slot.Ammo); } } \ No newline at end of file diff --git a/src/Standalone/appsettings.json b/src/Standalone/appsettings.json index 921f7f415..01f09e890 100644 --- a/src/Standalone/appsettings.json +++ b/src/Standalone/appsettings.json @@ -34,7 +34,7 @@ "GameExtendedOpcode": false, "GameEnvironmentEffect": false, "GameExtendedClientPing": true, - "GameItemTooltip": false + "GameItemTooltip": true } }, "database": { diff --git a/tests/NeoServer.Game.Items.Tests/Inspection/InspectionTextBuilderTest.cs b/tests/NeoServer.Game.Items.Tests/Inspection/InspectionTextBuilderTest.cs index 7006aa249..faca9cba8 100644 --- a/tests/NeoServer.Game.Items.Tests/Inspection/InspectionTextBuilderTest.cs +++ b/tests/NeoServer.Game.Items.Tests/Inspection/InspectionTextBuilderTest.cs @@ -14,29 +14,17 @@ public class InspectionTextBuilderTest { [Theory] [InlineData("You see item.")] - [InlineData("You see item.\nIt can only be wielded properly by knights and paladins.", 1, 2)] - [InlineData("You see item.\nIt can only be wielded properly by knights.", 1)] - [InlineData("You see item.\nIt can only be wielded properly by knights, paladins and sorcerers.", 1, 2, 3)] - [InlineData("You see item.\nIt can only be wielded properly by knights, paladins, sorcerers and druids.", 1, 2, 3, - 4)] - public void Add_HasVocations_ReturnText(string expected, params int[] vocations) + [InlineData("You see item.\nIt can only be wielded properly by knights and paladins.", "knight", "paladin")] + [InlineData("You see item.\nIt can only be wielded properly by knights.", "knight")] + [InlineData("You see item.\nIt can only be wielded properly by knights, paladins and sorcerers.", "knight", "paladin", "sorcerer")] + [InlineData("You see item.\nIt can only be wielded properly by knights, paladins, sorcerers and druids.", "knight", "paladin", "sorcerer", "druid")] + public void Add_HasVocations_ReturnText(string expected, params string[] vocations) { - var vocationStore = new VocationStore(); - vocationStore.Add(1, new Vocation { Name = "Knight" }); - vocationStore.Add(2, new Vocation { Name = "Paladin" }); - vocationStore.Add(3, new Vocation { Name = "Sorcerer" }); - vocationStore.Add(4, new Vocation { Name = "Druid" }); - - var input = vocations.Select(x => (byte)x).ToArray(); - var item = ItemTestData.CreateDefenseEquipmentItem(1); - item.Metadata.Attributes.SetAttribute(ItemAttribute.Vocation, input); - - var player = PlayerTestDataBuilder.Build(hp: 200); - var inspectionTextBuilder = new InspectionTextBuilder(vocationStore); - + item.Metadata.Attributes.SetAttribute(ItemAttribute.VocationNames, vocations); + //act - var actual = inspectionTextBuilder.Build(item, player); + var actual = InspectionTextBuilder.Build(item); //assert actual.Should().Be(expected); diff --git a/tests/NeoServer.Game.Items.Tests/Inspection/RequirementInspectionTextBuilderTests.cs b/tests/NeoServer.Game.Items.Tests/Inspection/RequirementInspectionTextBuilderTests.cs index 86990b829..de3cb6e10 100644 --- a/tests/NeoServer.Game.Items.Tests/Inspection/RequirementInspectionTextBuilderTests.cs +++ b/tests/NeoServer.Game.Items.Tests/Inspection/RequirementInspectionTextBuilderTests.cs @@ -13,25 +13,17 @@ public class RequirementInspectionTextBuilderTests { [Theory] [InlineData("")] - [InlineData("It can only be wielded properly by knights and paladins.", 1, 2)] - [InlineData("It can only be wielded properly by knights, paladins and sorcerers.", 1, 2, 3)] - [InlineData("It can only be wielded properly by knights, paladins, sorcerers and druids.", 1, 2, 3, 4)] - [InlineData("It can only be wielded properly by knights, sorcerers and druids.", 1, 10, 3, 4)] - public void Add_HasVocations_ReturnText(string expected, params int[] vocations) + [InlineData("It can only be wielded properly by knights and paladins.", "knight", "paladin")] + [InlineData("It can only be wielded properly by knights, paladins and sorcerers.", "knight", "paladin", "sorcerer")] + [InlineData("It can only be wielded properly by knights, paladins, sorcerers and druids.", "knight", "paladin", "sorcerer", "druid")] + [InlineData("It can only be wielded properly by knights, sorcerers and druids.", "knight", "sorcerer", "druid")] + public void Add_HasVocations_ReturnText(string expected, params string[] vocations) { - var vocationStore = new VocationStore(); - vocationStore.Add(1, new Vocation { Name = "Knight" }); - vocationStore.Add(2, new Vocation { Name = "Paladin" }); - vocationStore.Add(3, new Vocation { Name = "Sorcerer" }); - vocationStore.Add(4, new Vocation { Name = "Druid" }); - - var input = vocations.Select(x => (byte)x).ToArray(); - var item = ItemTestData.CreateDefenseEquipmentItem(1); - item.Metadata.Attributes.SetAttribute(ItemAttribute.Vocation, input); + item.Metadata.Attributes.SetAttribute(ItemAttribute.VocationNames, vocations); //act - var actual = RequirementInspectionTextBuilder.Build(item, vocationStore); + var actual = RequirementInspectionTextBuilder.Build(item); //assert actual.Should().Be(expected); @@ -48,34 +40,27 @@ public void Add_HasLevel_ReturnText(string expected, int level) item.Metadata.Attributes.SetAttribute(ItemAttribute.MinimumLevel, level); //act - var actual = RequirementInspectionTextBuilder.Build(item, null); + var actual = RequirementInspectionTextBuilder.Build(item); //assert actual.Should().Be(expected); } [Theory] - [InlineData("It can only be wielded properly by knights of level 10 or higher.", 10, 1)] - [InlineData("It can only be wielded properly by knights and paladins of level 1 or higher.", 1, 1, 2)] - [InlineData("It can only be wielded properly by knights, paladins and sorcerers of level 200 or higher.", 200, 1, 2, - 3)] + [InlineData("It can only be wielded properly by knights of level 10 or higher.", 10, "knight")] + [InlineData("It can only be wielded properly by knights and paladins of level 1 or higher.", 1, "knight", + "paladin")] + [InlineData("It can only be wielded properly by knights, paladins and sorcerers of level 200 or higher.", 200, + "knight", "paladin", "sorcerer")] [InlineData("", 0)] - public void Add_HasLevelAndVocations_ReturnText(string expected, int level, params int[] vocations) + public void Add_HasLevelAndVocations_ReturnText(string expected, int level, params string[] vocations) { - var vocationStore = new VocationStore(); - vocationStore.Add(1, new Vocation { Name = "Knight" }); - vocationStore.Add(2, new Vocation { Name = "Paladin" }); - vocationStore.Add(3, new Vocation { Name = "Sorcerer" }); - vocationStore.Add(4, new Vocation { Name = "Druid" }); - - var input = vocations.Select(x => (byte)x).ToArray(); - var item = ItemTestData.CreateDefenseEquipmentItem(1); item.Metadata.Attributes.SetAttribute(ItemAttribute.MinimumLevel, level); - item.Metadata.Attributes.SetAttribute(ItemAttribute.Vocation, input); + item.Metadata.Attributes.SetAttribute(ItemAttribute.VocationNames, vocations); //act - var actual = RequirementInspectionTextBuilder.Build(item, vocationStore); + var actual = RequirementInspectionTextBuilder.Build(item); //assert actual.Should().Be(expected); @@ -86,61 +71,43 @@ public void Add_HasNoRequirement_ReturnEmpty() { var item = ItemTestData.CreateCoin(1, 10, 1); //act - var actual = RequirementInspectionTextBuilder.Build(item, null); + var actual = RequirementInspectionTextBuilder.Build(item); //assert actual.Should().BeEmpty(); } [Theory] - [InlineData("It can only be used properly by knights of level 10 or higher.", 10, 1)] - [InlineData("It can only be used properly by knights and paladins of level 1 or higher.", 1, 1, 2)] - [InlineData("It can only be used properly by knights, paladins and sorcerers of level 200 or higher.", 200, 1, 2, - 3)] + [InlineData("It can only be used properly by knights of level 10 or higher.", 10, "knight")] + [InlineData("It can only be used properly by knights and paladins of level 1 or higher.", 1, "knight", "paladin")] + [InlineData("It can only be used properly by knights, paladins and sorcerers of level 200 or higher.", 200, "knight", "paladin", "sorcerer")] [InlineData("", 0)] - public void Build_UsableHasLevelAndVocations_ReturnText(string expected, int level, params int[] vocations) + public void Build_UsableHasLevelAndVocations_ReturnText(string expected, int level, params string[] vocations) { - var vocationStore = new VocationStore(); - vocationStore.Add(1, new Vocation { Name = "Knight" }); - vocationStore.Add(2, new Vocation { Name = "Paladin" }); - vocationStore.Add(3, new Vocation { Name = "Sorcerer" }); - vocationStore.Add(4, new Vocation { Name = "Druid" }); - - var input = vocations.Select(x => (byte)x).ToArray(); - var item = ItemTestData.CreateAttackRune(1); item.Metadata.Attributes.SetAttribute(ItemAttribute.MinimumLevel, level); - item.Metadata.Attributes.SetAttribute(ItemAttribute.Vocation, input); + item.Metadata.Attributes.SetAttribute(ItemAttribute.VocationNames, vocations); //act - var actual = RequirementInspectionTextBuilder.Build(item, vocationStore); + var actual = RequirementInspectionTextBuilder.Build(item); //assert actual.Should().Be(expected); } [Theory] - [InlineData("It can only be consumed properly by knights of level 10 or higher.", 10, 1)] - [InlineData("It can only be consumed properly by knights and paladins of level 1 or higher.", 1, 1, 2)] - [InlineData("It can only be consumed properly by knights, paladins and sorcerers of level 200 or higher.", 200, 1, - 2, 3)] + [InlineData("It can only be consumed properly by knights of level 10 or higher.", 10, "knight")] + [InlineData("It can only be consumed properly by knights and paladins of level 1 or higher.", 1, "knight", "paladin")] + [InlineData("It can only be consumed properly by knights, paladins and sorcerers of level 200 or higher.", 200, "knight", "paladin", "sorcerer")] [InlineData("", 0)] - public void Build_ConsumableHasLevelAndVocations_ReturnText(string expected, int level, params int[] vocations) + public void Build_ConsumableHasLevelAndVocations_ReturnText(string expected, int level, params string[] vocations) { - var vocationStore = new VocationStore(); - vocationStore.Add(1, new Vocation { Name = "Knight" }); - vocationStore.Add(2, new Vocation { Name = "Paladin" }); - vocationStore.Add(3, new Vocation { Name = "Sorcerer" }); - vocationStore.Add(4, new Vocation { Name = "Druid" }); - - var input = vocations.Select(x => (byte)x).ToArray(); - var item = ItemTestData.CreatePot(1); item.Metadata.Attributes.SetAttribute(ItemAttribute.MinimumLevel, level); - item.Metadata.Attributes.SetAttribute(ItemAttribute.Vocation, input); + item.Metadata.Attributes.SetAttribute(ItemAttribute.VocationNames, vocations); //act - var actual = RequirementInspectionTextBuilder.Build(item, vocationStore); + var actual = RequirementInspectionTextBuilder.Build(item); //assert actual.Should().Be(expected); From b619b7bc34300d63f8d894961c8a57cae0ce7a66 Mon Sep 17 00:00:00 2001 From: caioavidal Date: Fri, 27 Dec 2024 12:34:54 -0300 Subject: [PATCH 8/8] Fix scripts --- data/extensions/Items/Doors/LevelDoor.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/extensions/Items/Doors/LevelDoor.cs b/data/extensions/Items/Doors/LevelDoor.cs index ed43b11b4..0f55d5a84 100644 --- a/data/extensions/Items/Doors/LevelDoor.cs +++ b/data/extensions/Items/Doors/LevelDoor.cs @@ -62,8 +62,8 @@ private void TeleportNorthOrSouth(IPlayer player, Direction directionTo) player.TeleportTo(Location.X, (ushort)(Location.Y + 1), Location.Z); } - public override string GetLookText(IInspectionTextBuilder inspectionTextBuilder, IPlayer player, - bool isClose = false) + public override string GetLookText( + bool isClose = false, bool showInternalDetails = false) { Metadata.Attributes.TryGetAttribute(ItemAttribute.ActionId, out int actionId);