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

+99
View File
@@ -0,0 +1,99 @@
// Command pktbench 临时基准:量化「服务端回包二次加密」的每包开销,
// 与同一条路径上**已经在做**的 CRC 逐字节循环对比。用完即删。
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"fmt"
"time"
"golang.org/x/crypto/chacha20"
dnfproto "longheng.io/server/internal/modules/dnf/protocol"
)
const rounds = 2000000
func main() {
sizes := []int{43, 73, 233, 1024, 2048}
fmt.Printf("rounds per case = %d\n\n", rounds)
fmt.Printf("%6s | %-22s | %-22s | %-22s | %-22s | %-22s\n",
"bytes", "AES-128-CTR in-place", "AES-128-GCM (reuse dst)", "ChaCha20 XOR", "existing CRC32 loop", "GCM with alloc")
fmt.Println("-------|------------------------|------------------------|------------------------|------------------------|----------------------")
for _, size := range sizes {
src := make([]byte, size)
if _, err := rand.Read(src); err != nil {
panic(err)
}
buf := make([]byte, size)
dst := make([]byte, 0, size+32)
block, err := aes.NewCipher(make([]byte, 16))
if err != nil {
panic(err)
}
ctr := cipher.NewCTR(block, make([]byte, aes.BlockSize))
gcm, err := cipher.NewGCM(block)
if err != nil {
panic(err)
}
chacha, err := chacha20.NewUnauthenticatedCipher(make([]byte, 32), make([]byte, chacha20.NonceSize))
if err != nil {
panic(err)
}
ctrNS := timeIt(func() {
ctr.XORKeyStream(buf, src)
})
gcmReuseNS := timeIt(func() {
_ = gcm.Seal(dst[:0], buf[:12], src, nil)
})
gcmAllocNS := timeIt(func() {
out := gcm.Seal(nil, buf[:12], src, nil)
sink += len(out)
})
chachaNS := timeIt(func() {
chacha.XORKeyStream(buf, src)
})
crcNS := timeIt(func() {
sum, err := dnfproto.ChecksumRange(src, 0, len(src))
if err != nil {
panic(err)
}
sink ^= int(sum & 1)
})
fmt.Printf("%6d | %8.1f ns (%6.0f MB/s) | %8.1f ns (%6.0f MB/s) | %8.1f ns (%6.0f MB/s) | %8.1f ns (%6.0f MB/s) | %8.1f ns\n",
size,
ctrNS, mbps(size, ctrNS),
gcmReuseNS, mbps(size, gcmReuseNS),
chachaNS, mbps(size, chachaNS),
crcNS, mbps(size, crcNS),
gcmAllocNS)
}
fmt.Printf("\nsink=%d\n", sink&1)
}
var sink int
func timeIt(fn func()) float64 {
// 预热
for i := 0; i < 20000; i++ {
fn()
}
start := time.Now()
for i := 0; i < rounds; i++ {
fn()
}
return float64(time.Since(start).Nanoseconds()) / float64(rounds)
}
func mbps(size int, ns float64) float64 {
if ns <= 0 {
return 0
}
return float64(size) / ns * 1000 // bytes/ns → MB/s (10^6)
}