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

+257
View File
@@ -0,0 +1,257 @@
package bus
import (
"bytes"
"encoding/binary"
"encoding/json"
"fmt"
"io"
"sort"
"sync"
"time"
)
const (
NATSWireBinary = "binary_v1"
NATSWireJSON = "json"
)
var (
natsWireMagic = []byte{'L', 'H', 'B', '1'}
natsWirePool = sync.Pool{New: func() any { return new(bytes.Buffer) }}
)
type natsWireMessage struct {
Topic string
Payload []byte
PublishedAt time.Time
Reply string
RequestID string
Trace map[string]string
}
type natsJSONWireMessage struct {
Topic string `json:"topic"`
Payload json.RawMessage `json:"payload"`
PublishedAt time.Time `json:"published_at"`
Reply string `json:"reply,omitempty"`
RequestID string `json:"request_id,omitempty"`
Trace map[string]string `json:"trace,omitempty"`
}
func isNATSWireEncoding(encoding string) bool {
switch encoding {
case NATSWireBinary, NATSWireJSON:
return true
default:
return false
}
}
func encodeNATSWire(msg natsWireMessage, encoding string) ([]byte, error) {
if encoding == NATSWireJSON {
return encodeNATSJSON(msg)
}
return encodeNATSBinary(msg)
}
func encodeNATSJSON(msg natsWireMessage) ([]byte, error) {
return json.Marshal(natsJSONWireMessage{
Topic: msg.Topic,
Payload: json.RawMessage(msg.Payload),
PublishedAt: msg.PublishedAt,
Reply: msg.Reply,
RequestID: msg.RequestID,
Trace: msg.Trace,
})
}
func decodeNATSWire(data []byte) (natsWireMessage, error) {
if bytes.HasPrefix(data, natsWireMagic) {
return decodeNATSBinary(data)
}
var wire natsJSONWireMessage
if err := json.Unmarshal(data, &wire); err != nil {
return natsWireMessage{}, err
}
return natsWireMessage{
Topic: wire.Topic,
Payload: append([]byte(nil), wire.Payload...),
PublishedAt: wire.PublishedAt,
Reply: wire.Reply,
RequestID: wire.RequestID,
Trace: wire.Trace,
}, nil
}
func encodeNATSBinary(msg natsWireMessage) ([]byte, error) {
buf := natsWirePool.Get().(*bytes.Buffer)
buf.Reset()
defer func() {
buf.Reset()
natsWirePool.Put(buf)
}()
buf.Write(natsWireMagic)
writeVarint(buf, msg.PublishedAt.UnixNano())
writeString(buf, msg.Topic)
writeString(buf, msg.Reply)
writeString(buf, msg.RequestID)
writeTrace(buf, msg.Trace)
writeBytes(buf, msg.Payload)
return append([]byte(nil), buf.Bytes()...), nil
}
func decodeNATSBinary(data []byte) (natsWireMessage, error) {
reader := bytes.NewReader(data)
magic := make([]byte, len(natsWireMagic))
if _, err := io.ReadFull(reader, magic); err != nil {
return natsWireMessage{}, err
}
if !bytes.Equal(magic, natsWireMagic) {
return natsWireMessage{}, fmt.Errorf("invalid nats wire magic")
}
unixNano, err := readVarint(reader)
if err != nil {
return natsWireMessage{}, err
}
topic, err := readString(reader)
if err != nil {
return natsWireMessage{}, err
}
reply, err := readString(reader)
if err != nil {
return natsWireMessage{}, err
}
requestID, err := readString(reader)
if err != nil {
return natsWireMessage{}, err
}
trace, err := readTrace(reader)
if err != nil {
return natsWireMessage{}, err
}
payload, err := readBytes(reader)
if err != nil {
return natsWireMessage{}, err
}
if reader.Len() != 0 {
return natsWireMessage{}, fmt.Errorf("nats wire has %d trailing bytes", reader.Len())
}
var publishedAt time.Time
if unixNano != 0 {
publishedAt = time.Unix(0, unixNano).UTC()
}
return natsWireMessage{
Topic: topic,
Payload: payload,
PublishedAt: publishedAt,
Reply: reply,
RequestID: requestID,
Trace: trace,
}, nil
}
func writeVarint(buf *bytes.Buffer, value int64) {
var scratch [binary.MaxVarintLen64]byte
n := binary.PutVarint(scratch[:], value)
buf.Write(scratch[:n])
}
func readVarint(reader *bytes.Reader) (int64, error) {
value, err := binary.ReadVarint(reader)
if err != nil {
return 0, fmt.Errorf("read varint: %w", err)
}
return value, nil
}
func writeUvarint(buf *bytes.Buffer, value uint64) {
var scratch [binary.MaxVarintLen64]byte
n := binary.PutUvarint(scratch[:], value)
buf.Write(scratch[:n])
}
func readUvarint(reader *bytes.Reader) (uint64, error) {
value, err := binary.ReadUvarint(reader)
if err != nil {
return 0, fmt.Errorf("read uvarint: %w", err)
}
return value, nil
}
func writeString(buf *bytes.Buffer, value string) {
writeBytes(buf, []byte(value))
}
func readString(reader *bytes.Reader) (string, error) {
value, err := readBytes(reader)
if err != nil {
return "", err
}
return string(value), nil
}
func writeBytes(buf *bytes.Buffer, value []byte) {
writeUvarint(buf, uint64(len(value)))
buf.Write(value)
}
func readBytes(reader *bytes.Reader) ([]byte, error) {
length, err := readUvarint(reader)
if err != nil {
return nil, err
}
if length > uint64(reader.Len()) { //nolint:gosec // G115:bytes.Reader.Len 永远非负,这里只用于剩余长度上界比较。
return nil, fmt.Errorf("nats wire length %d exceeds remaining %d", length, reader.Len())
}
value := make([]byte, int(length)) //nolint:gosec // G115:前面已确认 length 不超过 reader.Len。
if _, err := io.ReadFull(reader, value); err != nil {
return nil, err
}
return value, nil
}
func writeTrace(buf *bytes.Buffer, trace map[string]string) {
if len(trace) == 0 {
writeUvarint(buf, 0)
return
}
keys := make([]string, 0, len(trace))
for key := range trace {
keys = append(keys, key)
}
sort.Strings(keys)
writeUvarint(buf, uint64(len(keys)))
for _, key := range keys {
writeString(buf, key)
writeString(buf, trace[key])
}
}
func readTrace(reader *bytes.Reader) (map[string]string, error) {
count, err := readUvarint(reader)
if err != nil {
return nil, err
}
if count == 0 {
return nil, nil
}
maxEntries := uint64(reader.Len() / 2) //nolint:gosec // G115:bytes.Reader.Len 永远非负,这里估算剩余 trace 最多条目。
if count > maxEntries {
return nil, fmt.Errorf("nats wire trace count %d exceeds remaining %d", count, reader.Len())
}
trace := make(map[string]string, int(count)) //nolint:gosec // G115:前面已按剩余字节数约束 count。
for i := uint64(0); i < count; i++ {
key, err := readString(reader)
if err != nil {
return nil, err
}
value, err := readString(reader)
if err != nil {
return nil, err
}
trace[key] = value
}
return trace, nil
}