服务端(Go): - GM 塞背包/带属性装备发放:在线角色推送 op14 增量物品行,背包实时刷新,无需回角色选择界面 - GM 改金币/改等级:去掉在线拒绝,落库后推送 op14 钱包/op37 等级状态,在线实时刷新 - 等级端点统一切换到新版 GMSetCharacterLevel(自带在线刷新) - 无限/锁死疲劳模式 + 燃烧疲劳:每房间消耗 2 点、打怪与通关经验双倍 - 燃烧疲劳开关时给所有在线角色推送系统提示(op12 mode 0) - 深渊史诗掉率:GM 全局倍率 + 城镇增益药剂窗口倍率,真实接入掉落结算 启动器(Python/JS): - 标题栏自绘、窗口 1204x717、禁止拖拽改大小、仅最小化/关闭 - GM 工具:疲劳与燃烧、深渊史诗掉率、拍卖行上架(单一定价对齐) - 拍卖行上架前端对齐服务端单一价格语义,修复 400 报错
100 lines
2.5 KiB
Go
100 lines
2.5 KiB
Go
// 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)
|
|
}
|