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,114 @@
|
||||
package dnfbridge
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/text/encoding/simplifiedchinese"
|
||||
)
|
||||
|
||||
const currentActivityCalendarMsgID uint16 = 0x006c
|
||||
|
||||
type activityCalendarRecord struct {
|
||||
eventID uint16
|
||||
field0 uint32
|
||||
baseText0 []byte
|
||||
baseText1 []byte
|
||||
extension bool
|
||||
text3 string
|
||||
}
|
||||
|
||||
func currentActivityCalendarRecords() []activityCalendarRecord {
|
||||
return []activityCalendarRecord{
|
||||
{eventID: 181, field0: 0xff6e00ff, extension: true, text3: "ui/event/calendar/2awakeninglevel.xui/2/107&1"},
|
||||
{eventID: 192},
|
||||
{eventID: 200},
|
||||
{eventID: 145},
|
||||
{eventID: 143},
|
||||
{eventID: 202},
|
||||
{eventID: 457},
|
||||
}
|
||||
}
|
||||
|
||||
func writeCurrentActivityCalendarRecord(writer *packetWriter, record activityCalendarRecord) error {
|
||||
if writer == nil {
|
||||
return fmt.Errorf("activity calendar writer is nil")
|
||||
}
|
||||
writer.writeUint16(record.eventID)
|
||||
writer.writeUint32(record.field0)
|
||||
writer.writeRawDstr(record.baseText0)
|
||||
writer.writeRawDstr(record.baseText1)
|
||||
if !record.extension {
|
||||
writer.writeByte(0)
|
||||
return nil
|
||||
}
|
||||
text3, err := encodeCurrentActivityCalendarText(record.text3)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
writer.writeByte(1)
|
||||
writer.writeByte(0)
|
||||
writer.writeByte(0)
|
||||
writer.writeRawDstr(nil)
|
||||
writer.writeRawDstr(nil)
|
||||
writer.writeRawDstr(nil)
|
||||
writer.writeUint32(0)
|
||||
writer.writeUint32(0)
|
||||
writer.writeRawDstr(text3)
|
||||
writer.writeRawDstr(nil)
|
||||
writer.writeByte(0)
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeCurrentActivityCalendarText(value string) ([]byte, error) {
|
||||
if value == "" {
|
||||
return nil, nil
|
||||
}
|
||||
encoded, err := simplifiedchinese.GB18030.NewEncoder().Bytes([]byte(value))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("encode activity calendar text %q as GB18030: %w", value, err)
|
||||
}
|
||||
return encoded, nil
|
||||
}
|
||||
|
||||
func buildCurrentActivityCalendarBody() ([]byte, error) {
|
||||
records := currentActivityCalendarRecords()
|
||||
var writer packetWriter
|
||||
writer.writeUint16(uint16(len(records)))
|
||||
for _, record := range records {
|
||||
if err := writeCurrentActivityCalendarRecord(&writer, record); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
writer.writeByte(0)
|
||||
return writer.bytes(), nil
|
||||
}
|
||||
|
||||
func (s *Service) sendCurrentActivityCalendar(session *gameSession, source string) error {
|
||||
if s == nil || s.options.pvfPath == "" {
|
||||
// Unit/test-only services without a PVF source do not own the client
|
||||
// event table. Production always supplies env.PVF or a configured path.
|
||||
return nil
|
||||
}
|
||||
body, err := buildCurrentActivityCalendarBody()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(body) != 184 {
|
||||
return fmt.Errorf("activity calendar body length=%d want=184", len(body))
|
||||
}
|
||||
// The calendar has its own class-0/op0x006C owner. Keep it separate from
|
||||
// compressed op108, whose parser installs cumulative-online event state.
|
||||
s.logGameEvent(session, "game-activity-calendar-standalone-send",
|
||||
"source", source,
|
||||
"msg_id", currentActivityCalendarMsgID,
|
||||
"record_count", len(currentActivityCalendarRecords()),
|
||||
"body_len", len(body),
|
||||
"transport", "class0_protected_marker1_plaintext")
|
||||
return s.sendCurrentProtectedClass0Packet(
|
||||
session,
|
||||
currentActivityCalendarMsgID,
|
||||
body,
|
||||
"current_activity_calendar_plaintext",
|
||||
"activity_calendar",
|
||||
)
|
||||
}
|
||||
Reference in new issue
Block a user