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

90 lines
3.0 KiB
Go

package contracts
import (
"fmt"
"reflect"
"longheng.io/server/pkg/serializer"
)
var topicPayloadMakers = map[string]func() any{
TopicServiceStarted: func() any { return &ServiceStarted{} },
TopicClusterServiceStarted: func() any { return &ClusterServiceEvent{} },
TopicClusterServiceState: func() any { return &ClusterServiceEvent{} },
TopicClusterServiceBeat: func() any { return &ClusterServiceEvent{} },
TopicClusterServiceStopped: func() any { return &ClusterServiceEvent{} },
TopicGatewayClientPacket: func() any { return &GatewayClientPacket{} },
TopicGatewayPush: func() any { return &GatewayPush{} },
TopicLogicPlayerResponse: func() any { return &LogicPlayerResponse{} },
TopicSessionConnected: func() any { return &SessionConnected{} },
TopicSessionDisconnected: func() any { return &SessionDisconnected{} },
TopicPlayerStateChange: func() any { return &PlayerStateChanged{} },
TopicChatBroadcast: func() any { return &ChatBroadcast{} },
TopicNoticePublished: func() any { return &NoticePublished{} },
TopicRoomAllocated: func() any { return &RoomAllocated{} },
}
// MarshalTopicPayload 使用框架默认 JSON 编码器序列化 topic 负载。
func MarshalTopicPayload(payload any) ([]byte, error) {
codec, err := serializer.DefaultRegistry.MustGet("json")
if err != nil {
return nil, err
}
return codec.Marshal(payload)
}
// UnmarshalTopicPayload 按 topic 反序列化为已知契约结构,未知 topic 返回 map。
func UnmarshalTopicPayload(topic string, data []byte) (any, error) {
factory := topicPayloadFactory(topic)
if factory == nil {
var payload map[string]any
if err := unmarshalJSON(data, &payload); err != nil {
return nil, fmt.Errorf("decode topic %q: %w", topic, err)
}
return payload, nil
}
target := factory()
if err := unmarshalJSON(data, target); err != nil {
return nil, fmt.Errorf("decode topic %q: %w", topic, err)
}
value := reflect.ValueOf(target)
if value.Kind() == reflect.Pointer && !value.IsNil() {
return value.Elem().Interface(), nil
}
return target, nil
}
func topicPayloadFactory(topic string) func() any {
if factory, ok := topicPayloadMakers[topic]; ok {
return factory
}
switch {
case IsLogicNodePacketTopic(topic):
return func() any { return &GatewayClientPacket{} }
case IsLogicSessConnTopic(topic):
return func() any { return &SessionConnected{} }
case IsLogicSessDiscTopic(topic):
return func() any { return &SessionDisconnected{} }
case IsGatewayNodePushTopic(topic):
return func() any { return &GatewayPush{} }
case IsGatewayNodeRespTopic(topic):
return func() any { return &LogicPlayerResponse{} }
case IsRPCNodeRequestTopic(topic):
return func() any { return &RPCRequest{} }
case IsRPCResponseTopic(topic):
return func() any { return &RPCResponse{} }
default:
return nil
}
}
func unmarshalJSON(data []byte, target any) error {
codec, err := serializer.DefaultRegistry.MustGet("json")
if err != nil {
return err
}
return codec.Unmarshal(data, target)
}