Skip to content
This repository was archived by the owner on Jun 17, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion src/Prima.Core.Server/Data/Session/NetworkSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,32 @@ public class NetworkSession : INetworkSession

public delegate Task DisconnectDelegate(string id);


private readonly Dictionary<string, object> _properties = new();


public void SetProperty<T>(T value, string name = "default")
{
if (_properties.ContainsKey(name))
{
_properties[name] = value;
}
else
{
_properties.Add(name, value);
}
}

public T GetProperty<T>(string name = "default")
{
if (_properties.TryGetValue(name, out var value))
{
return (T)value;
}

return default;
}

public DateTime LastPing { get; set; }

public event SendPacketDelegate OnSendPacket;
Expand All @@ -30,7 +56,6 @@ public class NetworkSession : INetworkSession

public string AccountId { get; set; }


public ClientVersion ClientVersion { get; set; }


Expand Down
66 changes: 0 additions & 66 deletions src/Prima.Server/Handlers/CharacterCreationHandler.cs

This file was deleted.

134 changes: 134 additions & 0 deletions src/Prima.Server/Handlers/CharacterHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
using LiteDB;
using Orion.Core.Server.Interfaces.Services.System;
using Prima.Core.Server.Data.Session;
using Prima.Core.Server.Handlers.Base;
using Prima.Core.Server.Interfaces.Listeners;
using Prima.Core.Server.Interfaces.Services;
using Prima.Network.Packets;
using Prima.Server.Modules.Scripts;
using Prima.UOData.Data.EventData;
using Prima.UOData.Entities;
using Prima.UOData.Entities.Db;
using Prima.UOData.Id;
using Prima.UOData.Interfaces.Services;
using Prima.UOData.Packets;

namespace Prima.Server.Handlers;

public class CharacterHandler
: BasePacketListenerHandler, INetworkPacketListener<CharacterCreation>, INetworkPacketListener<CharacterLogin>,
INetworkPacketListener<CharacterDelete>
{
private readonly IScriptEngineService _scriptEngineService;

private readonly IWorldManagerService _worldManagerService;
private readonly IDatabaseService _databaseService;

private readonly IMapService _mapService;

public CharacterHandler(
ILogger<CharacterHandler> logger, INetworkService networkService, IServiceProvider serviceProvider,
IScriptEngineService scriptEngineService, IMapService mapService, IWorldManagerService worldManagerService,
IDatabaseService databaseService
) : base(logger, networkService, serviceProvider)
{
_scriptEngineService = scriptEngineService;
_mapService = mapService;
_worldManagerService = worldManagerService;
_databaseService = databaseService;
}

protected override void RegisterHandlers()
{
RegisterHandler<CharacterCreation>(this);
RegisterHandler<CharacterLogin>(this);
RegisterHandler<CharacterDelete>(this);
}

public async Task OnPacketReceived(NetworkSession session, CharacterCreation packet)
{
var characterEntity = new CharacterEntity
{
AccountId = new ObjectId(session.AccountId),
Slot = packet.Slot
};

var playerMobile = _worldManagerService.GenerateWorldEntity<MobileEntity>();

characterEntity.MobileId = playerMobile.Id;

playerMobile.Name = packet.Name;

_worldManagerService.AddWorldEntity(playerMobile);

await _databaseService.InsertAsync(characterEntity);

TriggerCharacterCreatedEvent(packet);

await session.SendPacketAsync(new ClientVersionReq());
}

private void TriggerCharacterCreatedEvent(CharacterCreation packet)
{
var eventArgs = new CharacterCreatedEventArgs(
packet.Name,
packet.IsFemale,
packet.Hue,
packet.Int,
packet.Str,
packet.Dex,
_mapService.GetAvailableStartingCities()[packet.StartingLocation],
packet.Skills,
packet.ShirtColor,
packet.PantsColor,
packet.HairStyle,
packet.HairColor,
packet.FacialHair,
packet.FacialHairColor,
packet.Profession,
packet.Race
);

_scriptEngineService.ExecuteCallback(nameof(EventScriptModule.OnCharacterCreated), eventArgs);
}

public async Task OnPacketReceived(NetworkSession session, CharacterLogin packet)
{
Logger.LogInformation("Character login request for {Name}", packet.Name);

var character = await _databaseService.FirstOrDefaultAsync<CharacterEntity>(x =>
x.AccountId == new ObjectId(session.AccountId) && x.Slot == packet.Slot
);

// TODO: Check if character exists

session.SetProperty(character.MobileId, "mobileId");

var mobile = _worldManagerService.GetEntityBySerial<MobileEntity>(character.MobileId);

await session.SendPacketAsync(new ClientVersionReq());
}

public async Task OnPacketReceived(NetworkSession session, CharacterDelete packet)
{
Logger.LogInformation("Character delete request for slot {Name}", packet.Slot);
var character = await _databaseService.FirstOrDefaultAsync<CharacterEntity>(x =>
x.AccountId == new ObjectId(session.AccountId) && x.Slot == packet.Slot
);

if (character == null)
{
Logger.LogWarning("Character not found for slot {Slot}", packet.Slot);
return;
}

var mobile = _worldManagerService.GetEntityBySerial<MobileEntity>(character.MobileId);

if (mobile != null)
{
_worldManagerService.RemoveWorldEntity(mobile);
}

await _databaseService.DeleteAsync(character);
}
}
25 changes: 23 additions & 2 deletions src/Prima.Server/Handlers/LoginHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@
using Prima.Network.Types;
using Prima.Server.Modules.Scripts;
using Prima.UOData.Context;
using Prima.UOData.Entities;
using Prima.UOData.Entities.Db;
using Prima.UOData.Interfaces.Services;
using Prima.UOData.Packets;
using Prima.UOData.Packets.Entries;


namespace Prima.Server.Handlers;
Expand All @@ -29,6 +32,10 @@ public class LoginHandler
private readonly INetworkService _networkService;
private readonly PrimaServerConfig _primaServerConfig;

private readonly IDatabaseService _databaseService;

private readonly IWorldManagerService _worldManagerService;

private readonly IScriptEngineService _scriptEngineService;
private readonly IProcessQueueService _processQueueService;
private readonly List<GameServerEntry> _gameServerEntries = new();
Expand All @@ -39,7 +46,8 @@ public class LoginHandler
public LoginHandler(
ILogger<LoginHandler> logger, INetworkService networkService, IServiceProvider serviceProvider,
IAccountManager accountManager, PrimaServerConfig primaServerConfig, IMapService mapService,
IScriptEngineService scriptEngineService, IProcessQueueService processQueueService
IScriptEngineService scriptEngineService, IProcessQueueService processQueueService, IDatabaseService databaseService,
IWorldManagerService worldManagerService
) :
base(logger, networkService, serviceProvider)
{
Expand All @@ -49,6 +57,8 @@ public LoginHandler(
_mapService = mapService;
_scriptEngineService = scriptEngineService;
_processQueueService = processQueueService;
_databaseService = databaseService;
_worldManagerService = worldManagerService;

CreateGameServerList();
}
Expand Down Expand Up @@ -180,13 +190,24 @@ public async Task OnPacketReceived(NetworkSession session, GameServerLogin packe

_networkService.MoveLoginSessionToGameSession(session.Id, packet.SessionKey);

// TODO: Check characeters on database

var charactersAndCities = new CharactersStartingLocations(session.ClientVersion.ProtocolChanges);

charactersAndCities.Cities.AddRange(_mapService.GetAvailableStartingCities());

charactersAndCities.FillCharacters();

var characters = await _databaseService.QueryAsync<CharacterEntity>(entity => entity.AccountId == account.Id);


for (var i = 0; i < characters.ToList().Count; i++)
{
var character = characters.ToList()[i];
var mobile = _worldManagerService.GetEntityBySerial<MobileEntity>(character.MobileId);

charactersAndCities.Characters[i] = new CharacterEntry(mobile.Name);
}


await session.SendPacketAsync(charactersAndCities);

Expand Down
2 changes: 1 addition & 1 deletion src/Prima.Server/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ static async Task Main(string[] args)
builder.Services
.AddService<ConnectionHandler>()
.AddService<PingPongHandler>()
.AddService<CharacterCreationHandler>()
.AddService<CharacterHandler>()
.AddService<LoginHandler>();

builder.Services.AddHostedService<PrimaHostedService>();
Expand Down
2 changes: 2 additions & 0 deletions src/Prima.Server/Services/NetworkService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,8 @@ private void RegisterPackets()
_packetManager.RegisterPacket<GameServerLogin>();
_packetManager.RegisterPacket<PingRequest>();
_packetManager.RegisterPacket<CharacterCreation>();
_packetManager.RegisterPacket<CharacterLogin>();
_packetManager.RegisterPacket<CharacterDelete>();
}

public void Dispose()
Expand Down
15 changes: 15 additions & 0 deletions src/Prima.UOData/Entities/Db/CharacterEntity.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using LiteDB;
using Prima.Core.Server.Entities.Base;
using Prima.UOData.Id;

namespace Prima.UOData.Entities.Db;

public class CharacterEntity : BaseDbEntity
{

public ObjectId AccountId { get; set; }

public int Slot { get; set; }

public Serial MobileId { get; set; }
}
3 changes: 0 additions & 3 deletions src/Prima.UOData/Entities/ItemEntity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,12 @@ namespace Prima.UOData.Entities;
public class ItemEntity : BaseWorldEntity
{
public string Name { get; set; }

public int Hue { get; set; }

public Point3D Position { get; set; }

public int Amount { get; set; }

public int ItemId { get; set; }

public ItemEntity()
{
}
Expand Down
3 changes: 3 additions & 0 deletions src/Prima.UOData/Events/World/WorldLoadedEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace Prima.UOData.Events.World;

public record WorldLoadedEvent(TimeSpan ElapsedTime, int EntityCount);
5 changes: 4 additions & 1 deletion src/Prima.UOData/Interfaces/Services/IWorldManagerService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Orion.Core.Server.Interfaces.Services.Base;
using Prima.UOData.Id;
using Prima.UOData.Interfaces.Entities;

namespace Prima.UOData.Interfaces.Services;
Expand All @@ -9,7 +10,9 @@ public interface IWorldManagerService : IOrionStartService, IOrionService

TEntity GenerateWorldEntity<TEntity>() where TEntity : IHaveSerial;

TEntity? GetEntityBySerial<TEntity>(Serial id) where TEntity : IHaveSerial;

Task SaveWorldAsync();
bool RemoveWorldEntity(IHaveSerial entity);

Task SaveWorldAsync();
}
Loading