Skip to content
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
2 changes: 1 addition & 1 deletion Maple2.Database/Storage/Game/GameStorage.Nurturing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public partial class Request {
Exp = 0,
ClaimedGiftForStage = 1,
CreationTime = DateTime.Now,
LastFeedTime = DateTime.MinValue,
LastFeedTime = DateTime.Now,
PlayedBy = [],
};
Context.Nurturing.Add(nurturing);
Expand Down
6 changes: 6 additions & 0 deletions Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,12 @@ private void ProcessPackets() {
continue;
}
packet.handler.Handle(packet.session, packet.reader);
} catch (Exception ex) {
if (ex is IndexOutOfRangeException) {
logger.Error("Error processing packet {OpCode} for account ID {AccountId}. Packet: {Packet}", packet.handler.OpCode, packet.session.AccountId, packet.ToString());
} else {
logger.Error(ex, "Error processing handler {Handler} for account ID {AccountId}. Packet: {Packet}", packet.handler.OpCode, packet.session.AccountId, packet.ToString());
}
} finally {
ArrayPool<byte>.Shared.Return(packet.reader.Buffer);
}
Expand Down
3 changes: 2 additions & 1 deletion Maple2.Server.Game/Manager/HousingManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -714,7 +714,8 @@ public bool TryRemoveCube(Plot plot, in Vector3B position, [NotNullWhen(true)] o
}

if (!session.Item.Furnishing.RetrieveCube(cube.Id)) {
throw new InvalidOperationException($"Failed to deposit cube {cube.Id} back into storage.");
logger.Error("Failed to deposit cube {CubeId} back into storage.", cube.Id);
return false;
}

DeleteCube(cube);
Expand Down
8 changes: 4 additions & 4 deletions Maple2.Server.Game/Manager/Items/InventoryManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -460,8 +460,8 @@ public bool ConsumeItemComponents(IReadOnlyList<ItemComponent> components, int q
foreach (Item material in materialsByTag[ingredient.Tag]) {
int consume = Math.Min(remainingIngredients, material.Amount);
if (!session.Item.Inventory.Consume(material.Uid, consume)) {
Log.Fatal("Failed to consume item {ItemUid}", material.Uid);
throw new InvalidOperationException($"Fatal: Consuming item: {material.Uid}");
Log.Fatal("Failed to consume item uid: {ItemUid}, item id: {ItemId}", material.Uid, material.Id);
throw new InvalidOperationException($"Fatal: Consuming item uid: {material.Uid}, item id: {material.Id}");
}

remainingIngredients -= consume;
Expand All @@ -473,8 +473,8 @@ public bool ConsumeItemComponents(IReadOnlyList<ItemComponent> components, int q
foreach (Item material in materialsById[ingredient.ItemId]) {
int consume = Math.Min(remainingIngredients, material.Amount);
if (!session.Item.Inventory.Consume(material.Uid, consume)) {
Log.Fatal("Failed to consume item {ItemUid}", material.Uid);
throw new InvalidOperationException($"Fatal: Consuming item: {material.Uid}");
Log.Fatal("Failed to consume item uid: {ItemUid}, item id: {ItemId}", material.Uid, material.Id);
throw new InvalidOperationException($"Fatal: Consuming item uid: {material.Uid}, item id: {material.Id}");
}

remainingIngredients -= consume;
Expand Down
6 changes: 5 additions & 1 deletion Maple2.Server.Game/Manager/MailManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using Maple2.Server.Game.Packets;
using Maple2.Server.Game.Session;
using Maple2.Tools.Extensions;
using Serilog;

namespace Maple2.Server.Game.Manager;

Expand All @@ -20,6 +21,8 @@ public sealed class MailManager {

private readonly SortedList<long, Mail> inbox;

private readonly ILogger logger = Log.ForContext<MailManager>();

public MailManager(GameSession session) {
this.session = session;

Expand Down Expand Up @@ -205,7 +208,8 @@ private MailError CollectInternal(GameStorage.Request db, Mail mail) {
}

if (!session.Item.Inventory.Add(item, notifyNew: true, commit: true)) {
throw new InvalidOperationException($"Mail {mail.Id} was collected but items could not be added to inventory.");
logger.Error("Mail {MailId} was collected but items could not be added to inventory. Item: {Item}", mail.Id, item);
return MailError.s_mail_error_receiveitem_to_inven;
}

mail.Items.RemoveAt(i);
Expand Down
69 changes: 37 additions & 32 deletions Maple2.Server.World/Containers/ChannelClientLookup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,38 +26,14 @@ public class ChannelClientLookup : IEnumerable<(int, ChannelClient)> {
private enum ChannelStatus {
Active,
Inactive,
Pending,
}

public void InjectDependencies(WorldServer worldSv, PlayerInfoLookup playerInfo) {
worldServer = worldSv;
playerInfoLookup = playerInfo;
}

private class Channel {
public ChannelStatus Status { get; set; }

public readonly int Id;
public readonly bool InstancedContent;

public readonly IPEndPoint Endpoint;
public readonly ushort GamePort;
public readonly int GrpcPort;

public readonly ChannelClient Client;
public readonly Health.HealthClient Health;

public Channel(ChannelStatus status, int id, bool instancedContent, IPEndPoint endpoint, ChannelClient client, Health.HealthClient health, ushort gamePort, int grpcPort) {
Status = status;
Id = id;
InstancedContent = instancedContent;
Endpoint = endpoint;
Client = client;
Health = health;
GamePort = gamePort;
GrpcPort = grpcPort;
}
}

private readonly ConcurrentDictionary<int, Channel> channels = [];

private readonly ILogger logger = Log.ForContext<ChannelClientLookup>();
Expand All @@ -73,13 +49,15 @@ public IEnumerable<int> Keys {
}

public (ushort gamePort, int grpcPort, int channel) FindOrCreateChannelByIp(string gameIp, string grpcGameIp, bool instancedContent) {
// find the first channel that matches the ip, status and instanced content
// find the first channel that matches the ip, status and instanced content, but only if not Pending
Channel? activeChannel = channels.Values.FirstOrDefault(channel =>
channel.Endpoint.Address.ToString() == gameIp &&
channel.Status is ChannelStatus.Inactive &&
channel.InstancedContent == instancedContent);

if (activeChannel is not null) {
// Mark as pending before returning
activeChannel.Status = ChannelStatus.Pending;
return (activeChannel.GamePort, activeChannel.GrpcPort, activeChannel.Id);
Comment thread
AngeloTadeucci marked this conversation as resolved.
}

Expand All @@ -98,7 +76,7 @@ public int FirstChannel() {
return -1;
}

public bool TryGetInstancedChannelId([NotNullWhen(true)] out int channelId) {
public bool TryGetInstancedChannelId(out int channelId) {
foreach (Channel channel in channels.Values.Where(ch => ch.Status is ChannelStatus.Active && ch.InstancedContent)) {
channelId = channel.Id;
return true;
Expand Down Expand Up @@ -136,7 +114,7 @@ public bool TryGetActiveEndpoint(int channelId, [NotNullWhen(true)] out IPEndPoi
int channelId = 1;
if (!instancedContent) {
// Find the smallest positive integer not used as a channel ID (excluding 0)
var usedIds = channels.Keys.Where(id => id > 0).ToHashSet();
HashSet<int> usedIds = channels.Keys.Where(id => id > 0).ToHashSet();
while (usedIds.Contains(channelId)) {
channelId++;
}
Expand Down Expand Up @@ -165,7 +143,7 @@ public bool TryGetActiveEndpoint(int channelId, [NotNullWhen(true)] out IPEndPoi
GrpcChannel grpcChannel = GrpcChannel.ForAddress(grpcUri);
var client = new ChannelClient(grpcChannel);
var healthClient = new Health.HealthClient(grpcChannel);
var activeChannel = new Channel(ChannelStatus.Inactive, channelId, instancedContent, gameEndpoint, client, healthClient, (ushort) newGamePort, newGrpcChannelPort);
var activeChannel = new Channel(ChannelStatus.Pending, channelId, instancedContent, gameEndpoint, client, healthClient, (ushort) newGamePort, newGrpcChannelPort);
if (!channels.TryAdd(channelId, activeChannel)) {
logger.Error("Failed to add channel {Channel}", channelId);
return (0, 0, -1);
Expand All @@ -187,13 +165,13 @@ private async Task MonitorChannel(Channel channel, CancellationTokenSource cance
cancellationToken: cancellationToken);
switch (response.Status) {
case HealthCheckResponse.Types.ServingStatus.Serving:
if (channel.Status is ChannelStatus.Inactive) {
if (channel.Status is ChannelStatus.Inactive || channel.Status is ChannelStatus.Pending) {
logger.Information("Channel {Channel} has become active", channel.Id);
Active(channel);
}
break;
default:
if (channel.Status is ChannelStatus.Active) {
if (channel.Status is ChannelStatus.Active || channel.Status is ChannelStatus.Pending) {
Inactive(channel);
logger.Information("Channel {Channel} has become inactive due to {Status}", channel.Id, response.Status);
#if !DEBUG
Expand Down Expand Up @@ -284,8 +262,35 @@ private void UpdateChannels(int exclueChannelBroadcast = -1) {

List<int> channelList = channels.Values.Where(ch => ch.Status is ChannelStatus.Active && !ch.InstancedContent).Select(ch => ch.Id).ToList();
channelClient.UpdateChannels(new Maple2.Server.Channel.Service.ChannelsUpdateRequest {
Channels = { channelList },
Channels = {
channelList,
},
});
}
}

private class Channel {
public ChannelStatus Status { get; set; }

public readonly int Id;
public readonly bool InstancedContent;

public readonly IPEndPoint Endpoint;
public readonly ushort GamePort;
public readonly int GrpcPort;

public readonly ChannelClient Client;
public readonly Health.HealthClient Health;

public Channel(ChannelStatus status, int id, bool instancedContent, IPEndPoint endpoint, ChannelClient client, Health.HealthClient health, ushort gamePort, int grpcPort) {
Status = status;
Id = id;
InstancedContent = instancedContent;
Endpoint = endpoint;
Client = client;
Health = health;
GamePort = gamePort;
GrpcPort = grpcPort;
}
}
}
Loading