DNF90 服务端与启动器完整源码(含 GM 工具功能增强)
服务端(Go): - GM 塞背包/带属性装备发放:在线角色推送 op14 增量物品行,背包实时刷新,无需回角色选择界面 - GM 改金币/改等级:去掉在线拒绝,落库后推送 op14 钱包/op37 等级状态,在线实时刷新 - 等级端点统一切换到新版 GMSetCharacterLevel(自带在线刷新) - 无限/锁死疲劳模式 + 燃烧疲劳:每房间消耗 2 点、打怪与通关经验双倍 - 燃烧疲劳开关时给所有在线角色推送系统提示(op12 mode 0) - 深渊史诗掉率:GM 全局倍率 + 城镇增益药剂窗口倍率,真实接入掉落结算 启动器(Python/JS): - 标题栏自绘、窗口 1204x717、禁止拖拽改大小、仅最小化/关闭 - GM 工具:疲劳与燃烧、深渊史诗掉率、拍卖行上架(单一定价对齐) - 拍卖行上架前端对齐服务端单一价格语义,修复 400 报错
This commit is contained in:
commit
645b64fe21
4388 files changed
+1405457
No files matched your search
@@ -0,0 +1,135 @@
|
||||
// 本文件解析任务类 C2S 请求体。
|
||||
// C# QuestManager 会在 body 长度大于 2 时去掉前 2 字节 wire-type echo,再交给 QuestService。
|
||||
package quest
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
"longheng.io/server/internal/modules/dnf/dnfenum"
|
||||
)
|
||||
|
||||
const (
|
||||
CurrentFinishQuestRequestBodySize = 10
|
||||
CurrentFinishQuestObservedTailMarker = ^uint16(0)
|
||||
|
||||
// CurrentSetTriggerRequestBodySize is the scalar op33 shape:
|
||||
// echo | quest | add/remove | reserved-or-answer.
|
||||
CurrentSetTriggerRequestBodySize = 6
|
||||
// CurrentMaskedSetTriggerRequestBodySize is the current-client packed
|
||||
// objective shape used by multi-lane tasks such as the Hell Party
|
||||
// challenges: echo | quest | lane mask | add/remove | reserved.
|
||||
CurrentMaskedSetTriggerRequestBodySize = 7
|
||||
)
|
||||
|
||||
// QuestIDRequest 描述只携带 questId 的任务请求。
|
||||
type QuestIDRequest struct {
|
||||
QuestID uint16
|
||||
}
|
||||
|
||||
// SetTriggerRequest 描述任务触发进度请求。
|
||||
type SetTriggerRequest struct {
|
||||
QuestID uint16
|
||||
TriggerType byte
|
||||
TriggerArgument byte
|
||||
IsIncrement bool
|
||||
}
|
||||
|
||||
// FinishQuestRequest 描述完成任务请求。
|
||||
type FinishQuestRequest struct {
|
||||
QuestID uint16
|
||||
RewardSelectIndex uint16
|
||||
HasRewardSelect bool
|
||||
Multiplier uint16
|
||||
Reserved uint16
|
||||
}
|
||||
|
||||
// DecodeQuestIDRequest 解析接取/放弃任务请求。
|
||||
func DecodeQuestIDRequest(body []byte) (QuestIDRequest, error) {
|
||||
qBody := stripEcho(body)
|
||||
if len(qBody) < 2 {
|
||||
return QuestIDRequest{}, fmt.Errorf("body too short after echo strip: got %d want >= 2", len(qBody))
|
||||
}
|
||||
return QuestIDRequest{QuestID: binary.LittleEndian.Uint16(qBody)}, nil
|
||||
}
|
||||
|
||||
// DecodeSetTriggerRequest parses both proven current-client op33 forms. The
|
||||
// seven-byte form is not a transport trailer: its 0x10/0x20/0x40 mask selects
|
||||
// one 9-bit lane of the packed quest trigger. Older six-byte masked clones are
|
||||
// retained only as a compatibility input for an already-supported profile.
|
||||
func DecodeSetTriggerRequest(body []byte) (SetTriggerRequest, error) {
|
||||
if len(body) != CurrentSetTriggerRequestBodySize && len(body) != CurrentMaskedSetTriggerRequestBodySize {
|
||||
return SetTriggerRequest{}, fmt.Errorf("set quest trigger body size: got %d want %d or %d", len(body), CurrentSetTriggerRequestBodySize, CurrentMaskedSetTriggerRequestBodySize)
|
||||
}
|
||||
if echo := binary.LittleEndian.Uint16(body[:2]); echo != uint16(dnfenum.CmdPacketSetQuestTrigger) {
|
||||
return SetTriggerRequest{}, fmt.Errorf("set quest trigger echo: got %d want %d", echo, dnfenum.CmdPacketSetQuestTrigger)
|
||||
}
|
||||
request := SetTriggerRequest{QuestID: binary.LittleEndian.Uint16(body[2:4])}
|
||||
if request.QuestID == 0 {
|
||||
return SetTriggerRequest{}, fmt.Errorf("set quest trigger has zero quest ID")
|
||||
}
|
||||
|
||||
if len(body) == CurrentMaskedSetTriggerRequestBodySize {
|
||||
switch body[4] {
|
||||
case 0x10, 0x20, 0x40:
|
||||
request.TriggerType = body[4]
|
||||
default:
|
||||
return SetTriggerRequest{}, fmt.Errorf("set quest trigger mask: got %#x want 0x10, 0x20, or 0x40", body[4])
|
||||
}
|
||||
if body[5] > 1 {
|
||||
return SetTriggerRequest{}, fmt.Errorf("set quest trigger add/remove: got %d want boolean", body[5])
|
||||
}
|
||||
if body[6] != 0 {
|
||||
return SetTriggerRequest{}, fmt.Errorf("set quest trigger masked reserved: got %#x want 0", body[6])
|
||||
}
|
||||
request.IsIncrement = body[5] != 0
|
||||
return request, nil
|
||||
}
|
||||
|
||||
// Retain the established local six-byte clone unchanged. Its last two
|
||||
// bytes are trigger type and trigger argument; several existing quest
|
||||
// families (notably seeking) still use type 1 through that compatibility
|
||||
// route. The current masked Hell Party form above is unambiguous because it
|
||||
// is seven bytes.
|
||||
request.TriggerType = body[4]
|
||||
request.TriggerArgument = body[5]
|
||||
request.IsIncrement = body[5] != 0
|
||||
return request, nil
|
||||
}
|
||||
|
||||
// DecodeFinishQuestRequest 解析完成任务请求。
|
||||
func DecodeFinishQuestRequest(body []byte) (FinishQuestRequest, error) {
|
||||
if len(body) != CurrentFinishQuestRequestBodySize {
|
||||
return FinishQuestRequest{}, fmt.Errorf("current EXE finish-quest body size: got %d want %d", len(body), CurrentFinishQuestRequestBodySize)
|
||||
}
|
||||
if echo := binary.LittleEndian.Uint16(body[0:2]); echo != uint16(dnfenum.CmdPacketFinishQuest) {
|
||||
return FinishQuestRequest{}, fmt.Errorf("current EXE finish-quest echo: got %d want %d", echo, dnfenum.CmdPacketFinishQuest)
|
||||
}
|
||||
req := FinishQuestRequest{
|
||||
QuestID: binary.LittleEndian.Uint16(body[2:4]),
|
||||
RewardSelectIndex: binary.LittleEndian.Uint16(body[4:6]),
|
||||
Multiplier: binary.LittleEndian.Uint16(body[6:8]),
|
||||
Reserved: binary.LittleEndian.Uint16(body[8:10]),
|
||||
}
|
||||
req.HasRewardSelect = req.RewardSelectIndex != ^uint16(0)
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func stripEcho(body []byte) []byte {
|
||||
if body == nil || len(body) <= 2 {
|
||||
return body
|
||||
}
|
||||
return body[2:]
|
||||
}
|
||||
|
||||
func (r QuestIDRequest) String() string {
|
||||
return fmt.Sprintf("quest=%d", r.QuestID)
|
||||
}
|
||||
|
||||
func (r SetTriggerRequest) String() string {
|
||||
return fmt.Sprintf("quest=%d triggerType=%d argument=%d increment=%t", r.QuestID, r.TriggerType, r.TriggerArgument, r.IsIncrement)
|
||||
}
|
||||
|
||||
func (r FinishQuestRequest) String() string {
|
||||
return fmt.Sprintf("quest=%d rewardSelect=%d hasReward=%t multiplier=%d reserved=%d", r.QuestID, r.RewardSelectIndex, r.HasRewardSelect, r.Multiplier, r.Reserved)
|
||||
}
|
||||
Reference in new issue
Block a user