Started on catalogue, added the index and pages packets

main
Tiger 2023-10-06 18:12:35 +02:00
parent 66744ead65
commit 59d90aeeb2
16 changed files with 349 additions and 5 deletions

View File

@ -0,0 +1,34 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Outgoing.Catalog;
using Tiger.Communication.Messages.Types;
using Tiger.Game.Catalogue;
using Tiger.Networking.Game.Sessions;
namespace Tiger.Communication.Messages.Incoming.Catalog;
public class GetCatalogIndexEvent : IMessageEvent
{
private readonly ICatalogueManager _catalogueManager;
private readonly IGameSessionManager _gameSessionManager;
public GetCatalogIndexEvent(ICatalogueManager catalogueManager, IGameSessionManager gameSessionManager)
{
_catalogueManager = catalogueManager;
_gameSessionManager = gameSessionManager;
}
public IncomingHeaders Header => IncomingHeaders.GetCatalogIndexEvent;
public async Task HandleAsync(GameSession gameSession, ClientMessage request)
{
if (gameSession.Habbo == null)
{
await _gameSessionManager.CloseAsync("Not logged in", gameSession);
return;
}
var categories = _catalogueManager.Pages.Values.Where(p => p.Parent is null);
await gameSession.SendComposerAsync(new CatalogIndexMessageComposer(categories,
request.ReadString() ?? "normal"));
}
}

View File

@ -0,0 +1,40 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Outgoing.Catalog;
using Tiger.Communication.Messages.Types;
using Tiger.Game.Catalogue;
using Tiger.Networking.Game.Sessions;
namespace Tiger.Communication.Messages.Incoming.Catalog;
public class GetCatalogPageEvent : IMessageEvent
{
private readonly ICatalogueManager _catalogueManager;
private readonly IGameSessionManager _gameSessionManager;
public GetCatalogPageEvent(ICatalogueManager catalogueManager, IGameSessionManager gameSessionManager)
{
_catalogueManager = catalogueManager;
_gameSessionManager = gameSessionManager;
}
public IncomingHeaders Header => IncomingHeaders.GetCatalogPageEvent;
public async Task HandleAsync(GameSession gameSession, ClientMessage request)
{
if (gameSession.Habbo == null)
{
await _gameSessionManager.CloseAsync("Not logged in", gameSession);
return;
}
var pageId = request.ReadInt32() ?? -1;
var offerId = request.ReadInt32() ?? 0;
var mode = request.ReadString() ?? "normal";
if (!_catalogueManager.Pages.TryGetValue(pageId, out var page))
{
return;
}
await gameSession.SendComposerAsync(new CatalogPageMessageComposer(page, offerId, mode));
}
}

View File

@ -32,7 +32,8 @@ public class SetActivatedBadgesEvent : IMessageEvent
return;
var wearingBadges = new Collection<Badge>();
foreach (var currentBadge in gameSession.Habbo.Badges)
var current = gameSession.Habbo.Badges.Where(b => b.Slot != 0);
foreach (var currentBadge in current)
{
currentBadge.Slot = 0;
}

View File

@ -0,0 +1,53 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Types;
using Tiger.Game.Catalogue;
namespace Tiger.Communication.Messages.Outgoing.Catalog;
public class CatalogIndexMessageComposer : IMessageComposer
{
private readonly IEnumerable<CataloguePage> _pages;
private readonly string _mode;
public CatalogIndexMessageComposer(IEnumerable<CataloguePage> pages, string mode)
{
_pages = pages;
_mode = mode;
}
public OutgoingHeaders Header => OutgoingHeaders.CatalogIndexMessageComposer;
public void Compose(ServerMessage message)
{
message.AppendBoolean(true);
message.AppendInt32(0);
message.AppendInt32(-1);
message.AppendString(string.Empty);
message.AppendString(string.Empty);
message.AppendInt32(0);
message.AppendInt32(_pages.Count());
foreach (var page in _pages)
{
SerializeNode(page, message);
}
message.AppendBoolean(false);
message.AppendString(_mode);
}
private void SerializeNode(CataloguePage page, ServerMessage message)
{
message.AppendBoolean(page.Visible);
message.AppendInt32(page.Icon);
message.AppendInt32(page.Id);
message.AppendString(page.InternalName);
message.AppendString(page.Name);
message.AppendInt32(0);
message.AppendInt32(page.Children.Count);
foreach (var child in page.Children)
{
SerializeNode(child, message);
}
}
}

View File

@ -0,0 +1,44 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Types;
using Tiger.Game.Catalogue;
namespace Tiger.Communication.Messages.Outgoing.Catalog;
public class CatalogPageMessageComposer : IMessageComposer
{
private readonly CataloguePage _page;
private readonly int _offerId;
private readonly string _mode;
public CatalogPageMessageComposer(CataloguePage page, int offerId, string mode)
{
_page = page;
_offerId = offerId;
_mode = mode;
}
public OutgoingHeaders Header => OutgoingHeaders.CatalogPageMessageComposer;
public void Compose(ServerMessage message)
{
message.AppendInt32(_page.Id);
message.AppendString(_mode);
message.AppendString(_page.Layout);
message.AppendInt32(_page.Images.Count);
foreach (var image in _page.Images)
{
message.AppendString(image);
}
message.AppendInt32(_page.Texts.Count);
foreach (var text in _page.Texts)
{
message.AppendString(text);
}
message.AppendInt32(0);
message.AppendInt32(_offerId);
message.AppendBoolean(_page.SeasonalCurrency);
}
}

View File

@ -55,7 +55,7 @@ public enum OutgoingHeaders
CarryObjectMessageComposer = 1474,
CatalogPageExpirationComposer = 2668,
CatalogPageMessageComposer = 804,
CatalogPagesListComposer = 1032,
CatalogIndexMessageComposer = 1032,
CatalogPageWithEarliestExpiryMessageComposer = 2515,
CatalogPublishedMessageComposer = 1866,
CategoriesWithVisitorCountComposer = 1455,

View File

@ -0,0 +1,26 @@
using Microsoft.Extensions.Logging;
using Tiger.Storage;
namespace Tiger.Game.Catalogue;
public class CatalogueManager : ICatalogueManager
{
private readonly IRepository<CataloguePage> _pagesRepository;
private readonly ILogger<ICatalogueManager> _logger;
public IDictionary<int, CataloguePage> Pages { get; private set; }
public CatalogueManager(IRepository<CataloguePage> pagesRepository, ILogger<ICatalogueManager> logger)
{
_pagesRepository = pagesRepository;
_logger = logger;
Pages = new Dictionary<int, CataloguePage>();
}
public async Task LoadPagesAsync()
{
Pages = (await _pagesRepository.FindByAsync()).ToDictionary(p => p.Id, p => p);
_logger.LogInformation("Loaded {Count} catalogue pages", Pages.Count);
}
}

View File

@ -0,0 +1,19 @@
namespace Tiger.Game.Catalogue;
public class CataloguePage
{
public virtual int Id { get; set; }
public virtual string Name { get; set; } = null!;
public virtual string InternalName { get; set; } = null!;
public virtual string Layout { get; set; } = null!;
public virtual bool Visible { get; set; }
public virtual bool Enabled { get; set; }
public virtual int Icon { get; set; }
public virtual int MinRank { get; set; }
public virtual CataloguePage? Parent { get; set; }
public virtual IList<CataloguePage> Children { get; set; } = new List<CataloguePage>();
public virtual IList<string> Images { get; set; } = new List<string>();
public virtual IList<string> Texts { get; set; } = new List<string>();
public virtual bool SeasonalCurrency { get; set; }
public virtual IList<string> Modes { get; set; } = new List<string>();
}

View File

@ -0,0 +1,27 @@
using FluentNHibernate.Mapping;
using Tiger.Storage;
namespace Tiger.Game.Catalogue;
public class CataloguePageMap : ClassMap<CataloguePage>
{
public CataloguePageMap()
{
Table("catalogue_pages");
LazyLoad();
Id(c => c.Id).Column("id").GeneratedBy.Identity();
Map(c => c.Name).Column("name").Not.Nullable();
Map(c => c.InternalName).Column("internal_name").Not.Nullable();
Map(c => c.Layout).Column("layout").Not.Nullable();
Map(c => c.Visible).Column("visible").Not.Nullable();
Map(c => c.Enabled).Column("enabled").Not.Nullable();
Map(c => c.Icon).Column("icon").Not.Nullable();
Map(c => c.MinRank).Column("min_rank").Not.Nullable();
References(x => x.Parent).Column("parent_id").Nullable();
HasMany(x => x.Children).KeyColumn("parent_id").Inverse().Cascade.AllDeleteOrphan();
Map(c => c.Images).CustomType<StringListTypeConverter>();
Map(c => c.Texts).CustomType<StringListTypeConverter>();
Map(c => c.SeasonalCurrency).Column("seasonal_currency").Not.Nullable();
Map(c => c.Modes).CustomType<StringListTypeConverter>();
}
}

View File

@ -0,0 +1,7 @@
namespace Tiger.Game.Catalogue;
public interface ICatalogueManager
{
public IDictionary<int, CataloguePage> Pages { get; }
Task LoadPagesAsync();
}

View File

@ -3,6 +3,7 @@ using Microsoft.Extensions.Configuration.Yaml;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Tiger.Communication.Messages;
using Tiger.Game.Catalogue;
using Tiger.Game.Habbos;
using Tiger.Game.Settings;
using Tiger.Networking.Game;
@ -33,11 +34,13 @@ collection.AddSingleton<INhSessionFactory, NhSessionFactory>();
collection.AddScoped(serviceProvider => serviceProvider.GetRequiredService<INhSessionFactory>().OpenSession());
collection.AddScoped(typeof(IRepository<>), typeof(Repository<>));
collection.AddSingleton<ISettingManager, SettingManager>();
collection.AddSingleton<ICatalogueManager, CatalogueManager>();
collection.RegisterMessageEvents();
var provider = collection.BuildServiceProvider();
await provider.GetRequiredService<ISettingManager>().ReloadSettingsAsync();
await provider.GetRequiredService<ICatalogueManager>().LoadPagesAsync();
provider.GetRequiredService<IWebSocketServer>().Start($"http://{configuration["Network:Game:Ip"]}:{configuration["Network:Game:Port"]}/");

View File

@ -6,6 +6,9 @@ public interface IRepository<T>
{
Task<T?> FindAsync(object id);
Task SaveAsync(T entity);
Task SaveManyAsync(params T[] entities);
Task SaveManyAsync(IEnumerable<T> entities);
// Task FlushAsync();
Task<IEnumerable<T>> FindByAsync(Expression<Func<T, bool>>? expression = null);
Task<T?> FindOneByAsync(Expression<Func<T, bool>> expression);
}

View File

@ -24,6 +24,26 @@ public class Repository<T> : IRepository<T> where T : class
await _session.FlushAsync();
}
public async Task SaveManyAsync(params T[] entities)
{
foreach (var entity in entities)
{
await _session.SaveOrUpdateAsync(entity);
}
await _session.FlushAsync();
}
public async Task SaveManyAsync(IEnumerable<T> entities)
{
foreach (var entity in entities)
{
await _session.SaveOrUpdateAsync(entity);
}
await _session.FlushAsync();
}
public async Task<IEnumerable<T>> FindByAsync(Expression<Func<T, bool>>? expression)
{
var query = _session.Query<T>();

View File

@ -0,0 +1,67 @@
using System.Data;
using System.Data.Common;
using System.Text.Json;
using NHibernate.Engine;
using NHibernate.SqlTypes;
using NHibernate.UserTypes;
namespace Tiger.Storage;
public class StringListTypeConverter : IUserType
{
public new bool Equals(object x, object y)
{
return object.Equals(x, y);
}
public int GetHashCode(object x)
{
return x.GetHashCode();
}
public object NullSafeGet(DbDataReader rs, string[] names, ISessionImplementor session, object owner)
{
var r = rs[names[0]];
if (r == DBNull.Value) return null!;
var strList = JsonSerializer.Deserialize<List<string>>(r.ToString() ?? "") ?? new List<string>();
return strList;
}
public void NullSafeSet(DbCommand cmd, object value, int index, ISessionImplementor session)
{
if (value == null!)
{
((IDataParameter)cmd.Parameters[index]).Value = DBNull.Value;
}
else
{
var strList = (List<string>)value;
var strValue = JsonSerializer.Serialize(strList);
((IDataParameter)cmd.Parameters[index]).Value = strValue;
}
}
public object DeepCopy(object value)
{
return value;
}
public object Replace(object original, object target, object owner)
{
return original;
}
public object Assemble(object cached, object owner)
{
return cached;
}
public object Disassemble(object value)
{
return value;
}
public SqlType[] SqlTypes => new SqlType[] { SqlTypeFactory.GetString(8000) };
public Type ReturnedType => typeof(List<string>);
public bool IsMutable => true;
}

View File

@ -23,7 +23,7 @@
</ItemGroup>
<ItemGroup>
<None Update="appsettings.yaml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@ -1,7 +1,7 @@
Database:
Host: 127.0.0.1
Host: localhost
Port: 3306
Username: root
Username: tiger
Password: 123
Database: tiger_db
MinPool: 5