diff --git a/Common/Database/Scene/SceneData.cs b/Common/Database/Scene/SceneData.cs index 7524abd6..c18b7204 100644 --- a/Common/Database/Scene/SceneData.cs +++ b/Common/Database/Scene/SceneData.cs @@ -1,4 +1,6 @@ using EggLink.DanhengServer.Enums.Scene; +using EggLink.DanhengServer.Proto; +using Google.Protobuf; using SqlSugar; namespace EggLink.DanhengServer.Database.Scene; @@ -20,10 +22,31 @@ public class SceneData : BaseDatabaseDataHelper [SugarColumn(IsJson = true)] public Dictionary> FloorSavedData { get; set; } = []; // Dictionary> + + [SugarColumn(IsJson = true)] + public Dictionary>> PropTimelineData { get; set; } = + []; // Dictionary> } public class ScenePropData { - public int PropId; - public PropStateEnum State; + public int PropId { get; set; } + public PropStateEnum State { get; set; } +} + +public class ScenePropTimelineData +{ + public uint UintValue { get; set; } + public bool BoolValue { get; set; } + public string ByteValue { get; set; } = ""; // Base64 + + public PropTimelineInfo ToProto() + { + return new PropTimelineInfo + { + TimelineIntValue = UintValue, + TimelineBoolValue = BoolValue, + TimelineByteValue = ByteString.FromBase64(ByteValue) + }; + } } \ No newline at end of file diff --git a/GameServer/Game/Mission/FinishType/Handler/MissionHandlerTimeLineSetState.cs b/GameServer/Game/Mission/FinishType/Handler/MissionHandlerTimeLineSetState.cs new file mode 100644 index 00000000..140a0bbd --- /dev/null +++ b/GameServer/Game/Mission/FinishType/Handler/MissionHandlerTimeLineSetState.cs @@ -0,0 +1,43 @@ +using EggLink.DanhengServer.Data.Config; +using EggLink.DanhengServer.Data.Excel; +using EggLink.DanhengServer.Enums.Mission; +using EggLink.DanhengServer.GameServer.Game.Player; +using System.Text; + +namespace EggLink.DanhengServer.GameServer.Game.Mission.FinishType.Handler; + +[MissionFinishType(MissionFinishTypeEnum.TimeLineSetState)] +public class MissionHandlerTimeLineSetState : MissionFinishTypeHandler +{ + public override async ValueTask HandleMissionFinishType(PlayerInstance player, SubMissionInfo info, object? arg) + { + var floorId = info.LevelFloorID; + var groupId = info.ParamInt1; + var propId = info.ParamInt2; + var value = info.ParamStr1; + + var data = player.GetScenePropTimelineData(floorId, groupId, propId); // get data + + if (data == null) return; + // compare + if (Encoding.UTF8.GetString(Convert.FromBase64String(data.ByteValue)) != value) return; + + await player.MissionManager!.FinishSubMission(info.ID); + } + + public override async ValueTask HandleQuestFinishType(PlayerInstance player, QuestDataExcel quest, FinishWayExcel excel, object? arg) + { + var floorId = excel.MazeFloorID; + var groupId = excel.ParamInt1; + var propId = excel.ParamInt2; + var value = excel.ParamStr1; + + var data = player.GetScenePropTimelineData(floorId, groupId, propId); // get data + + if (data == null) return; + // compare + if (Encoding.UTF8.GetString(Convert.FromBase64String(data.ByteValue)) != value) return; + + await player.MissionManager!.FinishSubMission(excel.ID); + } +} \ No newline at end of file diff --git a/GameServer/Game/Mission/FinishType/Handler/MissionHandlerTimeLineSetStateCnt.cs b/GameServer/Game/Mission/FinishType/Handler/MissionHandlerTimeLineSetStateCnt.cs new file mode 100644 index 00000000..acd2827f --- /dev/null +++ b/GameServer/Game/Mission/FinishType/Handler/MissionHandlerTimeLineSetStateCnt.cs @@ -0,0 +1,22 @@ +using EggLink.DanhengServer.Data.Config; +using EggLink.DanhengServer.Data.Excel; +using EggLink.DanhengServer.Enums.Mission; +using EggLink.DanhengServer.GameServer.Game.Player; + +namespace EggLink.DanhengServer.GameServer.Game.Mission.FinishType.Handler; + +[MissionFinishType(MissionFinishTypeEnum.TimeLineSetStateCnt)] +public class MissionHandlerTimeLineSetStateCnt : MissionFinishTypeHandler +{ + public override async ValueTask HandleMissionFinishType(PlayerInstance player, SubMissionInfo info, object? arg) + { + // TODO + await ValueTask.CompletedTask; + } + + public override async ValueTask HandleQuestFinishType(PlayerInstance player, QuestDataExcel quest, FinishWayExcel excel, object? arg) + { + // TODO + await ValueTask.CompletedTask; + } +} \ No newline at end of file diff --git a/GameServer/Game/Player/PlayerInstance.cs b/GameServer/Game/Player/PlayerInstance.cs index d0767f41..6dcff80a 100644 --- a/GameServer/Game/Player/PlayerInstance.cs +++ b/GameServer/Game/Player/PlayerInstance.cs @@ -550,6 +550,49 @@ public class PlayerInstance(PlayerData data) return prop; } + public async ValueTask SetPropTimeline(int propEntityId, PropTimelineInfo info) + { + if (SceneInstance == null) return; + SceneInstance.Entities.TryGetValue(propEntityId, out var entity); + if (entity is not EntityProp prop) return; + + var data = new ScenePropTimelineData + { + BoolValue = info.TimelineBoolValue, + ByteValue = info.TimelineByteValue.ToBase64(), + UintValue = info.TimelineIntValue + }; + + // save to db + SceneData!.PropTimelineData.TryGetValue(Data.FloorId, out var floorData); + if (floorData == null) + { + floorData = new Dictionary>(); + SceneData.PropTimelineData[Data.FloorId] = floorData; + } + + if (!floorData.ContainsKey(prop.GroupID)) + floorData[prop.GroupID] = new Dictionary(); + + floorData[prop.GroupID][prop.PropInfo.ID] = data; + + prop.PropTimelineData = data; + + // handle mission / quest + await MissionManager!.HandleFinishType(MissionFinishTypeEnum.TimeLineSetState); + await MissionManager!.HandleFinishType(MissionFinishTypeEnum.TimeLineSetStateCnt); + } + + public ScenePropTimelineData? GetScenePropTimelineData(int floorId, int groupId, int propId) + { + SceneData!.PropTimelineData.TryGetValue(floorId, out var floorData); + if (floorData == null) return null; + floorData.TryGetValue(groupId, out var groupData); + if (groupData == null) return null; + groupData.TryGetValue(propId, out var data); + return data; + } + public async ValueTask EnterScene(int entryId, int teleportId, bool sendPacket, int storyLineId = 0, bool mapTp = false) { diff --git a/GameServer/Game/Scene/Entity/EntityProp.cs b/GameServer/Game/Scene/Entity/EntityProp.cs index fb946ab4..9e291973 100644 --- a/GameServer/Game/Scene/Entity/EntityProp.cs +++ b/GameServer/Game/Scene/Entity/EntityProp.cs @@ -1,5 +1,6 @@ using EggLink.DanhengServer.Data.Config.Scene; using EggLink.DanhengServer.Data.Excel; +using EggLink.DanhengServer.Database.Scene; using EggLink.DanhengServer.Enums.Scene; using EggLink.DanhengServer.GameServer.Game.Battle; using EggLink.DanhengServer.GameServer.Server.Packet.Send.Scene; @@ -20,6 +21,7 @@ public class EntityProp(SceneInstance scene, MazePropExcel excel, GroupInfo grou public GroupInfo Group { get; set; } = group; public int EntityID { get; set; } public int GroupID { get; set; } = group.Id; + public ScenePropTimelineData? PropTimelineData { get; set; } public async ValueTask AddBuff(SceneBuff buff) { @@ -39,6 +41,11 @@ public class EntityProp(SceneInstance scene, MazePropExcel excel, GroupInfo grou PropState = (uint)State }; + if (PropTimelineData != null) + { + prop.TimelineInfo = PropTimelineData.ToProto(); + } + return new SceneEntityInfo { EntityId = (uint)EntityID, diff --git a/GameServer/Game/Scene/SceneEntityLoader.cs b/GameServer/Game/Scene/SceneEntityLoader.cs index 3f6097d4..0db30bb4 100644 --- a/GameServer/Game/Scene/SceneEntityLoader.cs +++ b/GameServer/Game/Scene/SceneEntityLoader.cs @@ -276,6 +276,9 @@ public class SceneEntityLoader(SceneInstance scene) prop.State = prop.Excel.PropType == PropTypeEnum.PROP_ELEVATOR ? PropStateEnum.Elevator1 : info.State; } + var timelineData = Scene.Player.GetScenePropTimelineData(Scene.FloorId, group.Id, info.ID); + prop.PropTimelineData = timelineData; + if (group.GroupName.Contains("Machine")) { await prop.SetState(PropStateEnum.Open); diff --git a/GameServer/Server/Packet/Recv/Scene/HandlerChangePropTimelineInfoCsReq.cs b/GameServer/Server/Packet/Recv/Scene/HandlerChangePropTimelineInfoCsReq.cs new file mode 100644 index 00000000..de6a2491 --- /dev/null +++ b/GameServer/Server/Packet/Recv/Scene/HandlerChangePropTimelineInfoCsReq.cs @@ -0,0 +1,17 @@ +using EggLink.DanhengServer.GameServer.Server.Packet.Send.Scene; +using EggLink.DanhengServer.Kcp; +using EggLink.DanhengServer.Proto; + +namespace EggLink.DanhengServer.GameServer.Server.Packet.Recv.Scene; + +[Opcode(CmdIds.ChangePropTimelineInfoCsReq)] +public class HandlerChangePropTimelineInfoCsReq : Handler +{ + public override async Task OnHandle(Connection connection, byte[] header, byte[] data) + { + var req = ChangePropTimelineInfoCsReq.Parser.ParseFrom(data); + + await connection.Player!.SetPropTimeline((int)req.PropEntityId, req.TimelineInfo); + await connection.SendPacket(new PacketChangePropTimelineInfoScRsp(req.PropEntityId)); + } +} \ No newline at end of file diff --git a/GameServer/Server/Packet/Send/Scene/PacketChangePropTimelineInfoScRsp.cs b/GameServer/Server/Packet/Send/Scene/PacketChangePropTimelineInfoScRsp.cs new file mode 100644 index 00000000..aa707d99 --- /dev/null +++ b/GameServer/Server/Packet/Send/Scene/PacketChangePropTimelineInfoScRsp.cs @@ -0,0 +1,17 @@ +using EggLink.DanhengServer.Kcp; +using EggLink.DanhengServer.Proto; + +namespace EggLink.DanhengServer.GameServer.Server.Packet.Send.Scene; + +public class PacketChangePropTimelineInfoScRsp : BasePacket +{ + public PacketChangePropTimelineInfoScRsp(uint entityId) : base(CmdIds.ChangePropTimelineInfoScRsp) + { + var proto = new ChangePropTimelineInfoScRsp + { + PropEntityId = entityId + }; + + SetData(proto); + } +} \ No newline at end of file