Files
hanfuit 645b64fe21 DNF90 服务端与启动器完整源码(含 GM 工具功能增强)
服务端(Go):
- GM 塞背包/带属性装备发放:在线角色推送 op14 增量物品行,背包实时刷新,无需回角色选择界面
- GM 改金币/改等级:去掉在线拒绝,落库后推送 op14 钱包/op37 等级状态,在线实时刷新
- 等级端点统一切换到新版 GMSetCharacterLevel(自带在线刷新)
- 无限/锁死疲劳模式 + 燃烧疲劳:每房间消耗 2 点、打怪与通关经验双倍
- 燃烧疲劳开关时给所有在线角色推送系统提示(op12 mode 0)
- 深渊史诗掉率:GM 全局倍率 + 城镇增益药剂窗口倍率,真实接入掉落结算

启动器(Python/JS):
- 标题栏自绘、窗口 1204x717、禁止拖拽改大小、仅最小化/关闭
- GM 工具:疲劳与燃烧、深渊史诗掉率、拍卖行上架(单一定价对齐)
- 拍卖行上架前端对齐服务端单一价格语义,修复 400 报错
2026-11-04 14:31:55 +08:00

242 lines
8.3 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 本文件把已确认的攻坚队 C2S 命令纳入模块化分流。
package raid
import (
"context"
"fmt"
"longheng.io/server/internal/modules/dnf/alignedcmd"
"longheng.io/server/internal/modules/dnf/dnfenum"
)
type handler struct{}
// NewHandler 创建攻坚队协议处理器。
func NewHandler() alignedcmd.Handler {
return handler{}
}
// Domain 返回攻坚队业务域。
func (handler) Domain() dnfenum.AlignedDomain {
return dnfenum.AlignedDomainRaid
}
// Handle 解析已确认的攻坚队 C2S 命令,并禁止模块层伪造成攻坚成功;在线刷新由 dnfbridge/后续 raid owner 推 0x24F。
func (handler) Handle(_ context.Context, req alignedcmd.Request) (alignedcmd.Result, error) {
switch dnfenum.CmdPacket(req.Opcode) {
case dnfenum.CmdPacketCreateRaid:
return handleCreateRaid(req), nil
case dnfenum.CmdPacketLeaveRaid:
return handleLeaveRaid(req), nil
case dnfenum.CmdPacketStartRaid:
return handleStartRaid(req), nil
case dnfenum.CmdPacketRaidEntryCostInfo:
return handleEntryCostInfo(req), nil
case dnfenum.CmdPacketRaidSetSymbol:
return handleSetSymbol(req), nil
case dnfenum.CmdPacketSetRaidWaiting:
return handleSetWaiting(req), nil
case dnfenum.CmdPacketRejoinRaid:
return handleRejoinRaid(req), nil
case dnfenum.CmdPacketRaidManagerWork:
return handleManagerWork(req), nil
case dnfenum.CmdPacketModifyRaidInfo:
return handleModifyRaidInfo(req), nil
case dnfenum.CmdPacketRaidOtherChannelRequestJoin:
return handleOtherChannelRequestJoin(req), nil
case dnfenum.CmdPacketRaidMemberChangeState:
return handleMemberChangeState(req), nil
case dnfenum.CmdPacketRaidUserMoveChannelFail:
return handleUserMoveChannelFail(req), nil
case dnfenum.CmdPacketRaidOtherChannelList:
return handleOtherChannelList(req), nil
case dnfenum.CmdPacketRaidCheckRaidUser:
return handleCheckRaidUser(req), nil
default:
return alignedcmd.Result{
Handled: false,
ResponseAllowed: false,
Operation: "unregistered",
Reason: fmt.Sprintf("raid 模块未登记 opcode %d", req.Opcode),
}, nil
}
}
func handleCreateRaid(req alignedcmd.Request) alignedcmd.Result {
parsed, err := DecodeCreateRaidRequest(req.Body)
if err != nil {
return raidPendingParseError("raid_create", err)
}
return raidPending("raid_create", fmt.Sprintf(
"MCP 20260705:664 创建攻坚队 body=u8,dstr name,u8 tail;route=%d name_len=%d tail=%d;真实成功后应推 0x24F mode=3",
parsed.RouteOrRaidType,
len(parsed.NameBytes),
parsed.TailFlag,
))
}
func handleLeaveRaid(req alignedcmd.Request) alignedcmd.Result {
parsed, err := DecodeLeaveRaidRequest(req.Body)
if err != nil {
return raidPendingParseError("raid_leave", err)
}
return raidPending("raid_leave", fmt.Sprintf(
"MCP 20260705:665 离开攻坚队 body=u16 key=%d;真实成功后应推 0x24F mode=3 或清空攻坚 UI",
parsed.RaidOrMemberKey,
))
}
func handleStartRaid(req alignedcmd.Request) alignedcmd.Result {
if err := DecodeStartRaidRequest(req.Body); err != nil {
return raidPendingParseError("raid_start", err)
}
return raidPending("raid_start", "MCP 20260705:666 开始攻坚为空包;服务端开始后按 group_index/slot_order 自动创建普通 4 人小队")
}
func handleRejoinRaid(req alignedcmd.Request) alignedcmd.Result {
parsed, err := DecodeRejoinRaidRequest(req.Body)
if err != nil {
return raidPendingParseError("raid_rejoin", err)
}
return raidPending("raid_rejoin", fmt.Sprintf(
"MCP 20260705:668 重新加入攻坚 body=u32 raid_key=0x%08X;后续由服务端重推 0x24F mode=3",
parsed.RaidKey,
))
}
func handleSetWaiting(req alignedcmd.Request) alignedcmd.Result {
parsed, err := DecodeSetWaitingRequest(req.Body)
if err != nil {
return raidPendingParseError("raid_set_waiting", err)
}
return raidPending("raid_set_waiting", fmt.Sprintf(
"MCP 20260705:667 攻坚等待状态 body=u8 flag,u8 route;flag=%d route=%d;对象级刷新待 0x24F mode=2 继续确认",
parsed.Flag,
parsed.RouteRaidType,
))
}
func handleEntryCostInfo(req alignedcmd.Request) alignedcmd.Result {
parsed, err := DecodeEntryCostInfoRequest(req.Body)
if err != nil {
return raidPendingParseError("raid_entry_cost_info", err)
}
return raidPending("raid_entry_cost_info", fmt.Sprintf(
"MCP 20260705: 658 RaidEntryCostInfo body=u8 enabled=%d;这是入场消耗/材料信息请求,未确认 S2C 成功结构前不自动回包",
parsed.Enabled,
))
}
func handleSetSymbol(req alignedcmd.Request) alignedcmd.Result {
parsed, err := DecodeSetSymbolRequest(req.Body)
if err != nil {
return raidPendingParseError("raid_set_symbol", err)
}
return raidPending("raid_set_symbol", fmt.Sprintf(
"MCP 20260705: 662 RaidSetSymbol body=u32,u32,u8;source=0x%08X target=0x%08X symbol=%d;先登记,不伪造 raid 标记同步",
parsed.SourceValue,
parsed.TargetValue,
parsed.Symbol,
))
}
func handleManagerWork(req alignedcmd.Request) alignedcmd.Result {
parsed, err := DecodeManagerWorkRequest(req.Body)
if err != nil {
return raidPendingParseError("raid_manager_work", err)
}
return raidPending("raid_manager_work", fmt.Sprintf(
"MCP 20260705:669 仅是攻坚队长编辑请求,S2C 669 为 DoNothing;需更新成员 %d 到小组 %d 后推 0x24F mode=3",
parsed.MemberCharKey,
parsed.TargetGroup,
))
}
func handleOtherChannelRequestJoin(req alignedcmd.Request) alignedcmd.Result {
parsed, err := DecodeOtherChannelRequestJoinRequest(req.Body)
if err != nil {
return raidPendingParseError("raid_other_channel_request_join", err)
}
return raidPending("raid_other_channel_request_join", fmt.Sprintf(
"MCP 20260705:820 跨频道攻坚申请 body=u8,u16,u32,u16;mode=%d target=%d client=0x%08X route=%d;需要公共频道 owner 决定回包",
parsed.Mode,
parsed.TargetKey,
parsed.ClientValue,
parsed.RouteRaidType,
))
}
func handleMemberChangeState(req alignedcmd.Request) alignedcmd.Result {
parsed, err := DecodeMemberChangeStateRequest(req.Body)
if err != nil {
return raidPendingParseError("raid_member_change_state", err)
}
return raidPending("raid_member_change_state", fmt.Sprintf(
"MCP 20260705:823 成员状态变化 body=u8 state=%d;在线实现更新 member state 后推 0x24F mode=3",
parsed.State,
))
}
func handleUserMoveChannelFail(req alignedcmd.Request) alignedcmd.Result {
parsed, err := DecodeUserMoveChannelFailRequest(req.Body)
if err != nil {
return raidPendingParseError("raid_user_move_channel_fail", err)
}
return raidPending("raid_user_move_channel_fail", fmt.Sprintf(
"MCP 20260705:824 跨频道移动失败 body=u8,u16;mode=%d target=%d;只记录,不伪造成功",
parsed.Mode,
parsed.TargetKey,
))
}
func handleOtherChannelList(req alignedcmd.Request) alignedcmd.Result {
parsed, err := DecodeOtherChannelListRequest(req.Body)
if err != nil {
return raidPendingParseError("raid_other_channel_list", err)
}
return raidPending("raid_other_channel_list", fmt.Sprintf(
"MCP 20260705:831 公共频道攻坚列表 body=u8 或 u8,raw8,dstr;mode=%d has_ctx=%v name_len=%d;列表回包待公共频道 owner",
parsed.Mode,
parsed.HasContext,
len(parsed.NameBytes),
))
}
func handleCheckRaidUser(req alignedcmd.Request) alignedcmd.Result {
parsed, err := DecodeCheckRaidUserRequest(req.Body)
if err != nil {
return raidPendingParseError("raid_check_user", err)
}
return raidPending("raid_check_user", fmt.Sprintf(
"MCP 20260705:889 攻坚用户检查 body=u8,u16;mode=%d target=%d;S2C 889 是复杂列表,禁止最小假成功",
parsed.Mode,
parsed.TargetKey,
))
}
func handleModifyRaidInfo(req alignedcmd.Request) alignedcmd.Result {
parsed, err := DecodeModifyRaidInfoRequest(req.Body)
if err != nil {
return raidPendingParseError("raid_modify_info", err)
}
return raidPending("raid_modify_info", fmt.Sprintf(
"MCP 20260705:670 修改攻坚信息 body=u8,dstr name,u8 tail;route=%d name_len=%d tail=%d;真实成功后应推 0x24F mode=3",
parsed.RouteOrRaidType,
len(parsed.NameBytes),
parsed.TailFlag,
))
}
func raidPendingParseError(operation string, err error) alignedcmd.Result {
return raidPending(operation, fmt.Sprintf("%s 请求体解析失败:%v;禁止伪造成攻坚成功", operation, err))
}
func raidPending(operation string, reason string) alignedcmd.Result {
return alignedcmd.Result{
Handled: true,
ResponseAllowed: false,
Operation: operation,
Reason: reason,
}
}