server-master/srcs/_plugins/WingsEmu.Plugins.PacketHandling/CharScreen/CreateCharacterPacketHandler.cs
2026-02-10 18:21:30 +01:00

239 lines
No EOL
9.2 KiB
C#

// WingsEmu
//
// Developed by NosWings Team
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using CloneExtensions;
using Mapster;
using PhoenixLib.Logging;
using WingsAPI.Communication;
using WingsAPI.Communication.DbServer.CharacterService;
using WingsAPI.Data.Character;
using WingsEmu.Customization.NewCharCustomisation;
using WingsEmu.DTOs.Account;
using WingsEmu.DTOs.Inventory;
using WingsEmu.Game;
using WingsEmu.Game._enum;
using WingsEmu.Game._i18n;
using WingsEmu.Game.Configurations;
using WingsEmu.Game.Extensions;
using WingsEmu.Game.Inventory;
using WingsEmu.Game.Items;
using WingsEmu.Game.Managers;
using WingsEmu.Game.Maps;
using WingsEmu.Game.Networking;
using WingsEmu.Packets.ClientPackets;
using WingsEmu.Packets.Enums;
using WingsEmu.Plugins.PacketHandling.Customization;
namespace WingsEmu.Plugins.PacketHandling.CharScreen;
public class CreateCharacterPacketHandler : GenericCharScreenPacketHandlerBase<CharacterCreatePacket>
{
private readonly BaseCharacter _baseCharacter;
private readonly BaseInventory _baseInventory;
private readonly BaseQuicklist _baseQuicklist;
private readonly BaseSkill _baseSkill;
private readonly ICharacterService _characterService;
private readonly EntryPointPacketHandler _entrypoint;
private readonly IForbiddenNamesManager _forbiddenNamesManager;
private readonly IGameItemInstanceFactory _gameItemInstanceFactory;
private readonly IGameLanguageService _gameLanguage;
private readonly IGameItemInstanceFactory _itemInstanceFactory;
private readonly IMapManager _mapManager;
private readonly IRandomGenerator _randomGenerator;
private readonly IRespawnDefaultConfiguration _respawnDefaultConfiguration;
public CreateCharacterPacketHandler(EntryPointPacketHandler entrypoint, IGameLanguageService gameLanguage, BaseCharacter baseCharacter, BaseSkill baseSkill, BaseQuicklist baseQuicklist,
BaseInventory baseInventory, IGameItemInstanceFactory gameItemInstanceFactory, ICharacterService characterService, IMapManager mapManager,
IRespawnDefaultConfiguration respawnDefaultConfiguration, IRandomGenerator randomGenerator, IGameItemInstanceFactory itemInstanceFactory, IForbiddenNamesManager forbiddenNamesManager)
{
_entrypoint = entrypoint;
_gameLanguage = gameLanguage;
_baseCharacter = baseCharacter;
_baseSkill = baseSkill;
_baseQuicklist = baseQuicklist;
_baseInventory = baseInventory;
_gameItemInstanceFactory = gameItemInstanceFactory;
_characterService = characterService;
_mapManager = mapManager;
_respawnDefaultConfiguration = respawnDefaultConfiguration;
_randomGenerator = randomGenerator;
_itemInstanceFactory = itemInstanceFactory;
_forbiddenNamesManager = forbiddenNamesManager;
}
protected override async Task HandlePacketAsync(IClientSession session, CharacterCreatePacket packet)
{
if (session.HasCurrentMapInstance)
{
Log.Warn("HAS_CURRENTMAP_INSTANCE");
return;
}
// TODO: Hold Account Information in Authorized object
long accountId = session.Account.Id;
byte slot = packet.Slot;
string characterName = packet.Name;
DbServerGetCharacterResponse response = await _characterService.GetCharacterBySlot(new DbServerGetCharacterFromSlotRequest
{
AccountId = accountId,
Slot = slot
});
if (response.RpcResponseType == RpcResponseType.SUCCESS)
{
Log.Warn($"[CREATE_CHARACTER_PACKET_HANDLER] Character slot is already busy. Slot: '{slot.ToString()}'");
return;
}
if (slot > 3)
{
Log.Info("SLOTS > 3");
return;
}
if (characterName.Length is < 3 or >= 15 && session.Account.Authority < AuthorityType.GameMaster)
{
session.SendInfo(_gameLanguage.GetLanguage(GameDialogKey.CHARACTER_CREATION_INFO_INVALID_CHARNAME, session.UserLanguage));
return;
}
if ((byte)packet.HairColor > 9)
{
Log.Info("COLOR NOT VALID FOR A NEW CHARACTER");
return;
}
if (packet.HairStyle != HairStyleType.A && packet.HairStyle != HairStyleType.B)
{
Log.Info("HAIRSTYLE NOT VALID FOR A NEW CHARACTER");
return;
}
var rg = new Regex(@"^[a-zA-Z0-9_\-\*]*$");
if (rg.Matches(characterName).Count != 1)
{
session.SendInfo(_gameLanguage.GetLanguage(GameDialogKey.CHARACTER_CREATION_INFO_INVALID_CHARNAME, session.UserLanguage));
return;
}
if (session.Account.Authority <= AuthorityType.GameMaster)
{
string lowerCharName = characterName.ToLower();
if (_forbiddenNamesManager.IsBanned(lowerCharName, out string bannedName))
{
session.SendInfo(_gameLanguage.GetLanguageFormat(GameDialogKey.CHARACTER_CREATION_INFO_BANNED_CHARNAME, session.UserLanguage, bannedName));
return;
}
}
DbServerGetCharacterResponse response2 = await _characterService.GetCharacterByName(new DbServerGetCharacterRequestByName
{
CharacterName = characterName
});
if (response2.RpcResponseType == RpcResponseType.SUCCESS)
{
session.SendInfo(_gameLanguage.GetLanguage(GameDialogKey.CHARACTER_CREATION_INFO_ALREADY_TAKEN, session.UserLanguage));
return;
}
CharacterDTO newCharacter = _baseCharacter.GetCharacter();
newCharacter.AccountId = accountId;
newCharacter.Gender = packet.Gender;
newCharacter.HairColor = packet.HairColor;
newCharacter.HairStyle = packet.HairStyle;
newCharacter.Name = characterName;
newCharacter.Slot = slot;
newCharacter.QuickGetUp = true;
newCharacter.UiBlocked = true;
newCharacter.IsPartnerAutoRelive = true;
newCharacter.IsPetAutoRelive = true;
newCharacter.Dignity = 100;
newCharacter.MinilandPoint = 2000;
RespawnDefault getRespawn = _respawnDefaultConfiguration.GetReturn(RespawnType.NOSVILLE_SPAWN);
if (getRespawn != null)
{
IMapInstance mapInstance = _mapManager.GetBaseMapInstanceByMapId(getRespawn.MapId);
if (mapInstance != null)
{
int randomX = getRespawn.MapX + _randomGenerator.RandomNumber(getRespawn.Radius, -getRespawn.Radius);
int randomY = getRespawn.MapY + _randomGenerator.RandomNumber(getRespawn.Radius, -getRespawn.Radius);
if (mapInstance.IsBlockedZone(randomX, randomY))
{
randomX = getRespawn.MapX;
randomY = getRespawn.MapY;
}
newCharacter.MapX = (short)randomX;
newCharacter.MapY = (short)randomY;
}
}
BaseSkill skills = _baseSkill.GetClone();
if (skills != null)
{
newCharacter.LearnedSkills.AddRange(skills.Skills);
}
BaseQuicklist quicklist = _baseQuicklist.GetClone();
if (quicklist != null)
{
newCharacter.Quicklist.AddRange(quicklist.Quicklist);
}
BaseInventory startupInventory = _baseInventory.GetClone();
var listOfItems = new List<InventoryItem>();
if (startupInventory != null)
{
foreach (BaseInventory.StartupInventoryItem item in startupInventory.Items)
{
GameItemInstance newItem = _gameItemInstanceFactory.CreateItem(item.Vnum, item.Quantity);
var inventoryItem = new InventoryItem
{
InventoryType = item.InventoryType,
IsEquipped = false,
ItemInstance = newItem,
CharacterId = newCharacter.Id,
Slot = item.Slot
};
listOfItems.Add(inventoryItem);
}
}
newCharacter.EquippedStuffs = listOfItems.Where(s => s is { IsEquipped: true }).Select(s =>
{
CharacterInventoryItemDto tmp = s.Adapt<CharacterInventoryItemDto>();
tmp.ItemInstance = _itemInstanceFactory.CreateDto(s.ItemInstance);
return tmp;
}).ToList();
newCharacter.Inventory = listOfItems.Where(s => s is { IsEquipped: false }).Select(s =>
{
CharacterInventoryItemDto tmp = s.Adapt<CharacterInventoryItemDto>();
tmp.ItemInstance = _itemInstanceFactory.CreateDto(s.ItemInstance);
return tmp;
}).ToList();
newCharacter.LifetimeStats = new CharacterLifetimeStatsDto();
DbServerSaveCharacterResponse response3 = await _characterService.CreateCharacter(new DbServerSaveCharacterRequest
{
Character = newCharacter
});
if (response3.RpcResponseType != RpcResponseType.SUCCESS)
{
session.SendInfo(_gameLanguage.GetLanguage(GameDialogKey.CHARACTER_CREATION_INFO_ALREADY_TAKEN, session.UserLanguage));
return;
}
await _entrypoint.EntryPointAsync(session, null);
}
}