DNF90 服务端与启动器完整源码(含 GM 工具功能增强)

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

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

No files matched your search

+241
View File
@@ -0,0 +1,241 @@
// 本文件把已确认的攻坚队 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,
}
}