diff --git a/Maple2.Database/Storage/Game/GameStorage.Mail.cs b/Maple2.Database/Storage/Game/GameStorage.Mail.cs index 4299d68b0..3dc77ca97 100644 --- a/Maple2.Database/Storage/Game/GameStorage.Mail.cs +++ b/Maple2.Database/Storage/Game/GameStorage.Mail.cs @@ -110,7 +110,7 @@ public ICollection GetAllMail(long characterId, long minId = 0) { Context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.TrackAll; Model.Mail? mail = Context.Mail.Find(characterId, mailId); - if (mail == null || mail.ReadTime > DateTime.UnixEpoch) { + if (mail == null || mail.ReadTime > DateTime.Now) { return null; } diff --git a/Maple2.Database/Storage/Game/GameStorage.Map.cs b/Maple2.Database/Storage/Game/GameStorage.Map.cs index 4429ae040..c208943c8 100644 --- a/Maple2.Database/Storage/Game/GameStorage.Map.cs +++ b/Maple2.Database/Storage/Game/GameStorage.Map.cs @@ -293,6 +293,7 @@ public bool InitUgcMap(IEnumerable maps) { Position = new Vector3B(model.X, model.Y, model.Z), Rotation = model.Rotation, Interact = ToInteractCube(model.Interact), + Type = PlotCube.CubeType.Construction, }; } @@ -309,6 +310,7 @@ public bool InitUgcMap(IEnumerable maps) { Position = new Vector3B(model.X, model.Y, model.Z), Rotation = model.Rotation, Interact = ToInteractCube(model.Interact), + Type = PlotCube.CubeType.Construction, }; } } diff --git a/Maple2.File.Ingest/Mapper/MapEntityMapper.cs b/Maple2.File.Ingest/Mapper/MapEntityMapper.cs index 8ecdd8d57..e75cd60c3 100644 --- a/Maple2.File.Ingest/Mapper/MapEntityMapper.cs +++ b/Maple2.File.Ingest/Mapper/MapEntityMapper.cs @@ -189,7 +189,7 @@ private IEnumerable ParseMap(string xblock, IEnumerable e switch (physXProp) { case IMS2Liftable liftable: yield return new MapEntity(xblock, new Guid(entity.EntityId), entity.EntityName) { - Block = new Liftable((int) liftable.ItemID, liftable.ItemStackCount, liftable.ItemLifeTime, liftable.LiftableRegenCheckTime, liftable.LiftableFinishTime, liftable.MaskQuestID, liftable.MaskQuestState, liftable.EffectQuestID, liftable.EffectQuestState, liftable.Position, liftable.Rotation) + Block = new Liftable((int) liftable.ItemID, liftable.ItemStackCount, liftable.ItemLifeTime, liftable.LiftableRegenCheckTime, liftable.LiftableFinishTime, liftable.MaskQuestID, liftable.MaskQuestState, liftable.EffectQuestID, liftable.EffectQuestState, liftable.IsReactEffect, liftable.Position, liftable.Rotation) }; continue; case IMS2TaxiStation taxiStation: diff --git a/Maple2.Model/Game/Cube/PlotCube.cs b/Maple2.Model/Game/Cube/PlotCube.cs index 5bfe92a27..2a9bfe305 100644 --- a/Maple2.Model/Game/Cube/PlotCube.cs +++ b/Maple2.Model/Game/Cube/PlotCube.cs @@ -10,7 +10,7 @@ public enum CubeType { Default, Construction, Liftable }; public Vector3B Position { get; set; } public float Rotation { get; set; } - public CubeType Type { get; set; } + public required CubeType Type { get; set; } public int PlotId { get; set; } diff --git a/Maple2.Model/Game/User/Character.cs b/Maple2.Model/Game/User/Character.cs index c65493fac..6080c8b34 100644 --- a/Maple2.Model/Game/User/Character.cs +++ b/Maple2.Model/Game/User/Character.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Numerics; +using System.Numerics; using Maple2.Model.Common; using Maple2.Model.Enum; diff --git a/Maple2.Model/Game/User/IPlayerInfo.cs b/Maple2.Model/Game/User/IPlayerInfo.cs index 687dea35d..127fea04f 100644 --- a/Maple2.Model/Game/User/IPlayerInfo.cs +++ b/Maple2.Model/Game/User/IPlayerInfo.cs @@ -1,6 +1,4 @@ -using System.Collections.Concurrent; -using System.Collections.Generic; -using Maple2.Model.Enum; +using Maple2.Model.Enum; namespace Maple2.Model.Game; diff --git a/Maple2.Model/Game/User/PlayerInfo.cs b/Maple2.Model/Game/User/PlayerInfo.cs index 56ee035c8..308a8c39c 100644 --- a/Maple2.Model/Game/User/PlayerInfo.cs +++ b/Maple2.Model/Game/User/PlayerInfo.cs @@ -30,7 +30,7 @@ public static implicit operator PlayerInfo(Player player) { AchievementInfo = player.Character.AchievementInfo, PremiumTime = player.Character.PremiumTime, LastOnlineTime = player.Character.LastOnlineTime, - DungeonEnterLimits = [], + DungeonEnterLimits = player.Character.DungeonEnterLimits, GuildId = player.Character.GuildId, GuildName = player.Character.GuildName, }; diff --git a/Maple2.Model/Game/User/PlotInfo.cs b/Maple2.Model/Game/User/PlotInfo.cs index fdda880b6..fa9db5aa8 100644 --- a/Maple2.Model/Game/User/PlotInfo.cs +++ b/Maple2.Model/Game/User/PlotInfo.cs @@ -51,6 +51,12 @@ public PlotState State { public class Plot(UgcMapGroup metadata) : PlotInfo(metadata) { public readonly Dictionary Cubes = new(); + public static readonly Plot Default = new(new UgcMapGroup(0, + 0, + 0, + new UgcMapGroup.Cost(0, 0, 0), + new UgcMapGroup.Cost(0, 0, 0), + new UgcMapGroup.Limits(0, 0, 0, 0, 0, 0))); public void SetPlannerMode(PlotMode mode) { PlotMode = mode; diff --git a/Maple2.Model/Metadata/MapEntity/Liftable.cs b/Maple2.Model/Metadata/MapEntity/Liftable.cs index 8e10c0868..031ca24b5 100644 --- a/Maple2.Model/Metadata/MapEntity/Liftable.cs +++ b/Maple2.Model/Metadata/MapEntity/Liftable.cs @@ -12,6 +12,7 @@ public record Liftable( string MaskQuestState, string EffectQuestId, string EffectQuestState, + bool ReactEffect, Vector3 Position, Vector3 Rotation) : MapBlock; diff --git a/Maple2.Server.Core/Sync/PlayerInfoUpdateExtensions.cs b/Maple2.Server.Core/Sync/PlayerInfoUpdateExtensions.cs index 7fc9136ae..221a374e2 100644 --- a/Maple2.Server.Core/Sync/PlayerInfoUpdateExtensions.cs +++ b/Maple2.Server.Core/Sync/PlayerInfoUpdateExtensions.cs @@ -118,7 +118,6 @@ public static void Update(this IPlayerInfo self, UpdateField type, IPlayerInfo o if (type.HasFlag(UpdateField.Clubs)) { self.ClubIds = other.ClubIds; } - if (type.HasFlag(UpdateField.Dungeon)) { self.DungeonEnterLimits = other.DungeonEnterLimits; } diff --git a/Maple2.Server.Game/Manager/DungeonManager.cs b/Maple2.Server.Game/Manager/DungeonManager.cs index 74ccd78f8..1cbdf3554 100644 --- a/Maple2.Server.Game/Manager/DungeonManager.cs +++ b/Maple2.Server.Game/Manager/DungeonManager.cs @@ -81,6 +81,15 @@ public void UpdateDungeonEnterLimit() { } if (updated) { + session.PlayerInfo.SendUpdate(new PlayerUpdateRequest { + AccountId = session.AccountId, + CharacterId = session.CharacterId, + DungeonEnterLimits = { EnterLimits.Select(dungeon => new DungeonEnterLimitUpdate { + DungeonId = dungeon.Key, + Limit = (int) dungeon.Value, + })}, + Async = true, + }); session.Send(FieldEntrancePacket.Load(EnterLimits)); } } @@ -209,13 +218,6 @@ public void CreateDungeonRoom(int dungeonId, bool withParty) { session.Send(DungeonRoomPacket.Error(DungeonRoomError.s_room_party_err_not_chief)); return; } - - foreach (PartyMember member in Party.Members.Values) { - if (!member.Info.DungeonEnterLimits.TryGetValue(dungeonId, out DungeonEnterLimit enterLimit) || enterLimit != DungeonEnterLimit.None) { - //session.Send(DungeonRoomPacket.Error(DungeonRoomError)); - return; - } - } } diff --git a/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs b/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs index 5322f05fc..51bcb38ac 100644 --- a/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs +++ b/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs @@ -656,7 +656,10 @@ public bool RemoveLiftable(string entityId) { return false; } - Broadcast(CubePacket.RemoveCube(fieldLiftable.ObjectId, fieldLiftable.Position)); + if (Plots[0].Cubes.Remove(fieldLiftable.Position)) { + Broadcast(CubePacket.RemoveCube(fieldLiftable.ObjectId, fieldLiftable.Position)); + } + Broadcast(LiftablePacket.Remove(entityId)); return true; } @@ -735,7 +738,10 @@ public bool RemoveInstrument(int objectId) { public void OnAddPlayer(FieldPlayer added) { Players[added.ObjectId] = added; // LOAD: - added.Session.Send(LiftablePacket.Update(fieldLiftables.Values)); + foreach (FieldLiftable liftable in fieldLiftables.Values.Where(liftable => liftable.FinishTick > 0)) { + added.Session.Send(LiftablePacket.Add(liftable)); + } + added.Session.Send(LiftablePacket.Update(fieldLiftables.Values.Where(liftable => liftable.FinishTick == 0).ToList())); added.Session.Send(BreakablePacket.Update(fieldBreakables.Values)); added.Session.Send(InteractObjectPacket.Load(fieldInteracts.Values)); foreach (FieldInteract fieldInteract in fieldAdBalloons.Values) { diff --git a/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.Ugc.cs b/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.Ugc.cs index 354fab312..6f81fd43b 100644 --- a/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.Ugc.cs +++ b/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.Ugc.cs @@ -1,8 +1,12 @@ using System.Collections.Concurrent; +using System.Numerics; using Maple2.Database.Storage; +using Maple2.Model.Common; +using Maple2.Model.Enum; using Maple2.Model.Game; using Maple2.Model.Game.Ugc; -using Maple2.Server.Core.Packets; +using Maple2.Model.Metadata; +using Maple2.Server.Game.Model; using Maple2.Server.Game.Model.Field; using Maple2.Server.Game.Packets; using Maple2.Server.Game.Session; @@ -84,4 +88,78 @@ void SavePlot(Plot plot) { } } } + + public void PlaceCube(GameSession session, HeldCube cubeItem, in Vector3B position, float rotation) { + Plot? plot = session.Field.Plots[0]; + if (!session.ItemMetadata.TryGet(cubeItem.ItemId, out ItemMetadata? itemMetadata)) { + logger.Error("Failed to get item metadata for cube {cubeId}.", cubeItem.ItemId); + return; + } + switch (session.HeldCube) { + case PlotCube _: + if (itemMetadata.Install is null || itemMetadata.Housing is null) { + logger.Error($"Item {cubeItem.ItemId} is not a housing item."); + return; + } + plot = session.Housing.GetFieldPlot(); + if (plot == null) { + return; + } + + if (!session.Housing.TryPlaceCube(cubeItem, plot, itemMetadata, position, rotation, out PlotCube? plotCube)) { + return; + } + + session.Field.Broadcast(CubePacket.PlaceCube(session.Player.ObjectId, plot, plotCube)); + + if (plotCube.Interact is not null) { + if (plotCube.Interact.Nurturing is not null && plotCube.Interact.Metadata.Nurturing is not null) { + using GameStorage.Request db = session.GameStorage.Context(); + Nurturing? nurturing = db.GetNurturing(session.AccountId, plotCube.ItemId, plotCube.Interact.Metadata.Nurturing); + if (nurturing is null) { + nurturing = db.CreateNurturing(session.AccountId, plotCube.Interact.Metadata.Nurturing, plotCube.Interact.Metadata.Id); + if (nurturing is null) { + lock (Plots) { + logger.Error("Failed to create Nurturing for {AccountId}, ItemId {ItemId}", session.AccountId, plotCube.ItemId); + } + return; + } + } + plotCube.Interact.Nurturing = nurturing; + } + session.Field.Broadcast(FunctionCubePacket.AddFunctionCube(plotCube.Interact)); + } + + if (plot.IsPlanner) { + return; + } + break; + case LiftableCube liftable: + FieldLiftable? fieldLiftable = session.Field.AddLiftable($"4_{position.ConvertToInt()}", liftable.Liftable); + if (fieldLiftable == null) { + return; + } + + session.HeldCube = null; + fieldLiftable.Count = 1; + fieldLiftable.State = LiftableState.Default; + fieldLiftable.Position = position; + fieldLiftable.Rotation = new Vector3(0, 0, rotation); + fieldLiftable.FinishTick = session.Field.FieldTick + fieldLiftable.Value.ItemLifetime; + + if (session.Field.Entities.LiftableTargetBoxes.TryGetValue(position, out LiftableTargetBox? liftableTarget)) { + session.ConditionUpdate(ConditionType.item_move, codeLong: cubeItem.ItemId, targetLong: liftableTarget.LiftableTarget); + } + + Broadcast(LiftablePacket.Add(fieldLiftable)); + if (plot.Cubes.TryAdd(position, new PlotCube(itemMetadata, liftable.Id) { Type = PlotCube.CubeType.Liftable, Position = position, Rotation = rotation })) { + Broadcast(CubePacket.PlaceLiftable(session.Player.ObjectId, liftable, position, rotation)); + } + Broadcast(SetCraftModePacket.Stop(session.Player.ObjectId)); + Broadcast(LiftablePacket.Update(fieldLiftable)); + break; + } + + session.ConditionUpdate(ConditionType.install_item, codeLong: cubeItem.ItemId); + } } diff --git a/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs b/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs index 663153375..ac737c3ed 100644 --- a/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs +++ b/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs @@ -125,6 +125,9 @@ public virtual void Init() { } } + // Create default to place liftable cubes + Plots[0] = Plot.Default; + foreach (TriggerModel trigger in Entities.TriggerModels.Values) { AddTrigger(trigger); } diff --git a/Maple2.Server.Game/Manager/HousingManager.cs b/Maple2.Server.Game/Manager/HousingManager.cs index be5de4eea..1f4dd3112 100644 --- a/Maple2.Server.Game/Manager/HousingManager.cs +++ b/Maple2.Server.Game/Manager/HousingManager.cs @@ -450,15 +450,10 @@ public void InteriorReward(byte rewardId) { } #region Helpers - public bool TryPlaceCube(HeldCube cube, Plot plot, in Vector3B position, float rotation, + public bool TryPlaceCube(HeldCube cube, Plot plot, ItemMetadata itemMetadata, in Vector3B position, float rotation, [NotNullWhen(true)] out PlotCube? result, bool isReplace = false) { result = null; - if (!session.ItemMetadata.TryGet(cube.ItemId, out ItemMetadata? itemMetadata) || itemMetadata.Install is null || itemMetadata.Housing is null) { - logger.Error("Failed to get item metadata for cube {cubeId}.", cube.ItemId); - return false; - } - - if (plot.PlotMode is PlotMode.BlueprintPlanner && itemMetadata.Housing.IsNotAllowedInBlueprint) { + if (plot.PlotMode is PlotMode.BlueprintPlanner && itemMetadata.Housing!.IsNotAllowedInBlueprint) { if (itemMetadata.Housing.HousingCategory is HousingCategory.Farming or HousingCategory.Ranching) { session.Send(CubePacket.Error(UgcMapError.s_err_cannot_install_nurturing_in_design_home)); } else if (cube.ItemId is Constant.InteriorPortalCubeId) { @@ -480,7 +475,7 @@ public bool TryPlaceCube(HeldCube cube, Plot plot, in Vector3B position, float r groundHeight = groundTile.Position.Z / Constant.BlockSize; } - bool isSolidCube = itemMetadata.Install.IsSolidCube; + bool isSolidCube = itemMetadata.Install!.IsSolidCube; bool isOnGround = Math.Abs(position.Z - groundHeight) < 0.1; bool allowWaterOnGround = itemMetadata.Install.MapAttribute is MapAttribute.water && Constant.AllowWaterOnGround; @@ -517,6 +512,7 @@ public bool TryPlaceCube(HeldCube cube, Plot plot, in Vector3B position, float r result = new PlotCube(itemMetadata, FurnishingManager.NextCubeId(), cube.Template) { Position = position, Rotation = rotation, + Type = cube is LiftableCube ? PlotCube.CubeType.Liftable : PlotCube.CubeType.Construction, }; if (functionCubeMetadata is not null) { @@ -679,7 +675,7 @@ public void ApplyLayout(Plot plot, HomeLayout layout, bool isBlueprint = false) foreach (PlotCube cube in layout.Cubes) { Item? item = session.Item.Furnishing.GetItem(cube.ItemId); cube.Id = item?.Uid ?? 0; - if (!TryPlaceCube(cube, plot, cube.Position, cube.Rotation, out PlotCube? plotCube)) { + if (!TryPlaceCube(cube, plot, item!.Metadata, cube.Position, cube.Rotation, out PlotCube? plotCube)) { return; } diff --git a/Maple2.Server.Game/Manager/Items/FurnishingManager.cs b/Maple2.Server.Game/Manager/Items/FurnishingManager.cs index 2a0f62c4a..e0612affd 100644 --- a/Maple2.Server.Game/Manager/Items/FurnishingManager.cs +++ b/Maple2.Server.Game/Manager/Items/FurnishingManager.cs @@ -104,7 +104,9 @@ public bool TryPlaceCube(long uid, [NotNullWhen(true)] out PlotCube? cube) { ? FurnishingStoragePacket.Update(item.Uid, item.Amount) : FurnishingStoragePacket.Remove(item.Uid)); - cube = new PlotCube(item.Metadata, NextCubeId(), item.Template); + cube = new PlotCube(item.Metadata, NextCubeId(), item.Template) { + Type = PlotCube.CubeType.Construction, + }; if (!AddInventory(cube)) { logger.Fatal("Failed to add cube: {CubeId} to inventory", cube.Id); throw new InvalidOperationException($"Failed to add cube: {cube.Id} to inventory"); diff --git a/Maple2.Server.Game/Model/Field/Entity/FieldLiftable.cs b/Maple2.Server.Game/Model/Field/Entity/FieldLiftable.cs index 1dfe2a98e..51a4a03fe 100644 --- a/Maple2.Server.Game/Model/Field/Entity/FieldLiftable.cs +++ b/Maple2.Server.Game/Model/Field/Entity/FieldLiftable.cs @@ -28,14 +28,18 @@ public FieldLiftable(FieldManager field, int objectId, string entityId, Liftable Count--; // Only respawn if we have a regen time if (RespawnTick == 0 && Value.RegenCheckTime > 0) { - RespawnTick = Environment.TickCount64 + Value.RegenCheckTime; + RespawnTick = Field.FieldTick + Value.RegenCheckTime; } if (Count > 0) { Field.Broadcast(LiftablePacket.Update(this)); + } else if (FinishTick > 0) { + // This is a temp liftable, so we need to remove it + Field.RemoveLiftable(EntityId); } else { - State = Value.RegenCheckTime > 0 ? LiftableState.Respawning : LiftableState.Removed; - Field.Broadcast(LiftablePacket.Remove(EntityId)); + State = LiftableState.Removed; + Field.Broadcast(LiftablePacket.Update(this)); + Field.Broadcast(CubePacket.RemoveCube(ObjectId, Position)); } @@ -43,29 +47,28 @@ public FieldLiftable(FieldManager field, int objectId, string entityId, Liftable } public override void Update(long tickCount) { - // Handles despawning after being placed - if (FinishTick != 0 && tickCount > FinishTick) { - Field.RemoveLiftable(EntityId); - return; - } - - if (RespawnTick == 0 || tickCount < RespawnTick) { - return; - } - - Count++; - // Only respawn if we have a regen time - if (Count < Value.ItemStackCount && Value.RegenCheckTime > 0) { - RespawnTick = tickCount + Value.RegenCheckTime; - } else { - RespawnTick = 0; - } - - if (Count == 1) { - State = LiftableState.Default; - Field.Broadcast(LiftablePacket.Add(this)); - Field.Broadcast(CubePacket.PlaceLiftable(ObjectId, new LiftableCube(Value), Position, Rotation.Z)); + switch (State) { + case LiftableState.Removed: + if (RespawnTick > tickCount) { + State = LiftableState.Respawning; + } + break; + case LiftableState.Respawning: + if (tickCount >= RespawnTick) { + State = LiftableState.Default; + Count = Value.ItemStackCount; + RespawnTick = 0; + Field.Broadcast(LiftablePacket.Update(this)); + } + break; + case LiftableState.Default: + if (FinishTick != 0 && tickCount > FinishTick) { + Field.RemoveLiftable(EntityId); + return; + } + break; + case LiftableState.Disabled: + return; } - Field.Broadcast(LiftablePacket.Update(this)); } } diff --git a/Maple2.Server.Game/PacketHandlers/RequestCubeHandler.cs b/Maple2.Server.Game/PacketHandlers/RequestCubeHandler.cs index 7401bb53d..dea94c1d4 100644 --- a/Maple2.Server.Game/PacketHandlers/RequestCubeHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/RequestCubeHandler.cs @@ -219,64 +219,7 @@ private void HandlePlaceCube(GameSession session, IByteReader packet) { return; } - switch (session.HeldCube) { - case PlotCube _: - Plot? plot = session.Housing.GetFieldPlot(); - if (plot == null) { - return; - } - - if (!session.Housing.TryPlaceCube(cubeItem, plot, position, rotation, out PlotCube? plotCube)) { - return; - } - - session.Field.Broadcast(CubePacket.PlaceCube(session.Player.ObjectId, plot, plotCube)); - - if (plotCube.Interact is not null) { - if (plotCube.Interact.Nurturing is not null && plotCube.Interact.Metadata.Nurturing is not null) { - using GameStorage.Request db = session.GameStorage.Context(); - Nurturing? nurturing = db.GetNurturing(session.AccountId, plotCube.ItemId, plotCube.Interact.Metadata.Nurturing); - if (nurturing is null) { - nurturing = db.CreateNurturing(session.AccountId, plotCube.Interact.Metadata.Nurturing, plotCube.Interact.Metadata.Id); - if (nurturing is null) { - Logger.Error("Failed to create Nurturing for {AccountId}, ItemId {ItemId}", session.AccountId, plotCube.ItemId); - return; - } - } - plotCube.Interact.Nurturing = nurturing; - } - session.Field.Broadcast(FunctionCubePacket.AddFunctionCube(plotCube.Interact)); - } - - if (plot.IsPlanner) { - return; - } - break; - case LiftableCube liftable: - FieldLiftable? fieldLiftable = session.Field.AddLiftable(position.ToString(), liftable.Liftable); - if (fieldLiftable == null) { - return; - } - - session.HeldCube = null; - fieldLiftable.Count = 1; - fieldLiftable.State = LiftableState.Disabled; - fieldLiftable.Position = position; - fieldLiftable.Rotation = new Vector3(0, 0, rotation); - fieldLiftable.FinishTick = session.Field.FieldTick + fieldLiftable.Value.FinishTime + fieldLiftable.Value.ItemLifetime; - - if (session.Field.Entities.LiftableTargetBoxes.TryGetValue(position, out LiftableTargetBox? liftableTarget)) { - session.ConditionUpdate(ConditionType.item_move, codeLong: cubeItem.ItemId, targetLong: liftableTarget.LiftableTarget); - } - - session.Field.Broadcast(LiftablePacket.Add(fieldLiftable)); - session.Field.Broadcast(CubePacket.PlaceLiftable(session.Player.ObjectId, liftable, position, rotation)); - session.Field.Broadcast(SetCraftModePacket.Stop(session.Player.ObjectId)); - session.Field.Broadcast(LiftablePacket.Update(fieldLiftable)); - break; - } - - session.ConditionUpdate(ConditionType.install_item, codeLong: cubeItem.ItemId); + session.Field.PlaceCube(session, cubeItem, position, rotation); } private void HandleRemoveCube(GameSession session, IByteReader packet) { @@ -337,7 +280,10 @@ private void HandleReplaceCube(GameSession session, IByteReader packet) { return; } - if (session.Housing.TryPlaceCube(cubeItem, plot, position, rotation, out PlotCube? placedCube, isReplace: true)) { + if (!session.ItemMetadata.TryGet(cubeItem.ItemId, out ItemMetadata? metdata)) { + return; + } + if (session.Housing.TryPlaceCube(cubeItem, plot, metdata, position, rotation, out PlotCube? placedCube, isReplace: true)) { session.Field?.Broadcast(CubePacket.ReplaceCube(session.Player.ObjectId, placedCube)); } } diff --git a/Maple2.Server.Game/PacketHandlers/UserChatHandler.cs b/Maple2.Server.Game/PacketHandlers/UserChatHandler.cs index 8a0137b75..7dc363156 100644 --- a/Maple2.Server.Game/PacketHandlers/UserChatHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/UserChatHandler.cs @@ -299,7 +299,7 @@ private void HandleWedding(GameSession session, string message, ICollection LinkedItemUids(GameSession session, string message) { + private static ICollection LinkedItemUids(GameSession session, string message) { List itemUids = []; MatchCollection matches = Regex.Matches(message, "[^<]+"); diff --git a/Maple2.Server.Game/Packets/LiftablePacket.cs b/Maple2.Server.Game/Packets/LiftablePacket.cs index 7f2ba97c5..d8cc36774 100644 --- a/Maple2.Server.Game/Packets/LiftablePacket.cs +++ b/Maple2.Server.Game/Packets/LiftablePacket.cs @@ -20,14 +20,14 @@ public static ByteWriter Update(ICollection liftables) { pWriter.WriteInt(liftables.Count); foreach (FieldLiftable liftable in liftables) { pWriter.WriteString(liftable.EntityId); - pWriter.WriteByte(); + pWriter.WriteByte(1); pWriter.WriteInt(liftable.Count); pWriter.Write(liftable.State); pWriter.WriteUnicodeString(liftable.Value.MaskQuestId); pWriter.WriteUnicodeString(liftable.Value.MaskQuestState); pWriter.WriteUnicodeString(liftable.Value.EffectQuestId); pWriter.WriteUnicodeString(liftable.Value.EffectQuestState); - pWriter.WriteBool(true); + pWriter.WriteBool(liftable.Value.ReactEffect); } return pWriter; @@ -37,7 +37,7 @@ public static ByteWriter Update(FieldLiftable liftable) { var pWriter = Packet.Of(SendOp.Liftable); pWriter.Write(Command.Update); pWriter.WriteString(liftable.EntityId); - pWriter.WriteByte(); + pWriter.WriteByte(1); pWriter.WriteInt(liftable.Count); pWriter.Write(liftable.State); @@ -53,7 +53,7 @@ public static ByteWriter Add(FieldLiftable liftable) { pWriter.WriteUnicodeString(liftable.Value.MaskQuestState); pWriter.WriteUnicodeString(liftable.Value.EffectQuestId); pWriter.WriteUnicodeString(liftable.Value.EffectQuestState); - pWriter.WriteBool(true); // UseEffect + pWriter.WriteBool(liftable.Value.ReactEffect); return pWriter; } diff --git a/Maple2.Server.Game/Packets/LoadCubesPacket.cs b/Maple2.Server.Game/Packets/LoadCubesPacket.cs index 81088cca5..48079a2de 100644 --- a/Maple2.Server.Game/Packets/LoadCubesPacket.cs +++ b/Maple2.Server.Game/Packets/LoadCubesPacket.cs @@ -27,7 +27,7 @@ public static ByteWriter Load(List plotCubes) { pWriter.WriteClass(cube); pWriter.WriteInt(cube.PlotId); pWriter.WriteInt(); - pWriter.WriteBool(false); + pWriter.WriteBool(cube.Type == PlotCube.CubeType.Liftable); pWriter.WriteFloat(cube.Rotation); pWriter.WriteInt(); pWriter.WriteBool(false); // Binding? diff --git a/Maple2.Server.Game/Packets/TriggerPacket.cs b/Maple2.Server.Game/Packets/TriggerPacket.cs index 5af53c77d..76849023d 100644 --- a/Maple2.Server.Game/Packets/TriggerPacket.cs +++ b/Maple2.Server.Game/Packets/TriggerPacket.cs @@ -280,7 +280,7 @@ public static ByteWriter UiFaceEmotion(int objectId, string emotionName) { pWriter.Write(Command.Ui); pWriter.Write(UiCommand.FaceEmotion); pWriter.WriteInt(objectId); - pWriter.WriteUnicodeString(emotionName); + pWriter.WriteString(emotionName); return pWriter; } diff --git a/Maple2.Server.Game/Session/GameSession.cs b/Maple2.Server.Game/Session/GameSession.cs index 4155cafdf..e3bfe57ca 100644 --- a/Maple2.Server.Game/Session/GameSession.cs +++ b/Maple2.Server.Game/Session/GameSession.cs @@ -351,9 +351,13 @@ private bool PrepareFieldInternal(int mapId, out FieldManager? newField, int por ownerId = AccountId; } - newField = FieldFactory.Get(mapId, ownerId: ownerId, roomId: roomId); - if (newField == null) { - return false; + if (Field is DungeonFieldManager dungeonField && dungeonField.RoomFields.TryGetValue(mapId, out DungeonFieldManager? nextDungeonField)) { + newField = nextDungeonField; + } else { + newField = FieldFactory.Get(mapId, ownerId: ownerId, roomId: roomId); + if (newField == null) { + return false; + } } State = SessionState.ChangeMap; diff --git a/Maple2.Server.Game/Util/Sync/PlayerInfoStorage.cs b/Maple2.Server.Game/Util/Sync/PlayerInfoStorage.cs index 82088617f..6cc77a3a6 100644 --- a/Maple2.Server.Game/Util/Sync/PlayerInfoStorage.cs +++ b/Maple2.Server.Game/Util/Sync/PlayerInfoStorage.cs @@ -57,6 +57,7 @@ public bool GetOrFetch(long characterId, [NotNullWhen(true)] out PlayerInfo? inf PlotExpiryTime = response.Home.ExpiryTime.Seconds, PremiumTime = response.PremiumTime, LastOnlineTime = response.LastOnlineTime, + DungeonEnterLimits = response.DungeonEnterLimits.ToDictionary(limit => limit.DungeonId, limit => (DungeonEnterLimit) limit.Limit), }; cache[characterId] = info;