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,209 @@
|
||||
// 本文件验证已对齐 DNF 协议号的模块化注册表。
|
||||
package dnfenum
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestLookupAlignedCommandDirectDomains(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
opcode CmdPacket
|
||||
domain AlignedDomain
|
||||
support AlignedSupport
|
||||
}{
|
||||
{name: "inventory delete", opcode: CmdPacketDeleteItem, domain: AlignedDomainInventory, support: AlignedSupportDirect},
|
||||
{name: "inventory event level up", opcode: CmdPacketRequestEventServerLevelUp, domain: AlignedDomainInventory, support: AlignedSupportDirect},
|
||||
{name: "inventory shared effect item", opcode: CmdPacketUseSharedEffectItem, domain: AlignedDomainInventory, support: AlignedSupportDirect},
|
||||
{name: "inventory weapon forging", opcode: CmdPacketUpgradeItemSeparate, domain: AlignedDomainInventory, support: AlignedSupportDirect},
|
||||
// 扩容券:现场 2026-10-03 客户端发了 op430/op408,服务端当时没有路由所以
|
||||
// 一条回包都没发("使用后没效果")。
|
||||
{name: "inventory container upgrade (bag voucher)", opcode: CmdPacketUpgradeInventory, domain: AlignedDomainInventory, support: AlignedSupportDirect},
|
||||
{name: "inventory container upgrade (cargo voucher)", opcode: CmdPacketUpgradeCargo, domain: AlignedDomainInventory, support: AlignedSupportDirect},
|
||||
{name: "pet rename", opcode: CmdPacketRenameCreature, domain: AlignedDomainPet, support: AlignedSupportDirect},
|
||||
{name: "pet hatch egg", opcode: CmdPacketHatchCreatureEgg, domain: AlignedDomainPet, support: AlignedSupportDirect},
|
||||
{name: "skill slot", opcode: CmdPacketChangeSkillslot, domain: AlignedDomainSkill, support: AlignedSupportDirect},
|
||||
{name: "skill init", opcode: CmdPacketSkillInit, domain: AlignedDomainSkill, support: AlignedSupportDirect},
|
||||
{name: "account cargo", opcode: CmdPacketCreateAccountCargo, domain: AlignedDomainCargo, support: AlignedSupportDirect},
|
||||
{name: "mailbox open", opcode: CmdPacketMailboxOpen, domain: AlignedDomainMail, support: AlignedSupportDirect},
|
||||
{name: "mailbox send", opcode: CmdPacketMailboxSend, domain: AlignedDomainMail, support: AlignedSupportDirect},
|
||||
{name: "mailbox extract", opcode: CmdPacketMailboxExtractItem, domain: AlignedDomainMail, support: AlignedSupportDirect},
|
||||
{name: "mailbox state", opcode: CmdPacketChangeLetterStat, domain: AlignedDomainMail, support: AlignedSupportDirect},
|
||||
{name: "mailbox account roles", opcode: CmdPacketRequestServerCharacterList, domain: AlignedDomainMail, support: AlignedSupportDirect},
|
||||
{name: "party set info", opcode: CmdPacketSetPartyInfo, domain: AlignedDomainParty, support: AlignedSupportDirect},
|
||||
{name: "dungeon pick item", opcode: CmdPacketGetItem, domain: AlignedDomainDungeon, support: AlignedSupportDirect},
|
||||
{name: "clone title animation", opcode: CmdPacketSetCloneTitle, domain: AlignedDomainAvatarTitle, support: AlignedSupportDirect},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, ok := LookupAlignedCommand(uint16(tt.opcode))
|
||||
if !ok {
|
||||
t.Fatalf("LookupAlignedCommand(%d) not found", tt.opcode)
|
||||
}
|
||||
if got.Domain != tt.domain || got.Support != tt.support {
|
||||
t.Fatalf("LookupAlignedCommand(%d) = domain %q support %q, want domain %q support %q",
|
||||
tt.opcode, got.Domain, got.Support, tt.domain, tt.support)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestConclusionACommandsAreDirect(t *testing.T) {
|
||||
directA := []CmdPacket{
|
||||
CmdPacketSelectCharacter,
|
||||
CmdPacketCreateCharacter,
|
||||
CmdPacketDeleteCharacter,
|
||||
CmdPacketReturnSelectCharacter,
|
||||
CmdPacketGetUserinfo,
|
||||
CmdPacketCheckDoubleCharacterName,
|
||||
CmdPacketSetPartyInfo,
|
||||
CmdPacketLeaveParty,
|
||||
CmdPacketCallPartyMemberRealtimeInfo,
|
||||
CmdPacketDeleteItem,
|
||||
CmdPacketMoveItemspace,
|
||||
CmdPacketSortItem,
|
||||
CmdPacketBuyItem,
|
||||
CmdPacketSellItem,
|
||||
CmdPacketRepairEquipment,
|
||||
CmdPacketDisjointItem,
|
||||
CmdPacketUseStackable,
|
||||
CmdPacketRequestEventServerLevelUp,
|
||||
CmdPacketUseSharedEffectItem,
|
||||
CmdPacketUpgradeItem,
|
||||
CmdPacketUpgradeItemSeparate,
|
||||
CmdPacketEnchantByBead,
|
||||
CmdPacketRenameCreature,
|
||||
CmdPacketHatchCreature,
|
||||
CmdPacketHatchCreatureEgg,
|
||||
CmdPacketRequestHatchedCreature,
|
||||
CmdPacketUseBoosterItem,
|
||||
CmdPacketUseRandomboxItem,
|
||||
CmdPacketCompoundAvatar,
|
||||
CmdPacketUseEmblem,
|
||||
CmdPacketAddAvatarSocket,
|
||||
CmdPacketTitleBookPut,
|
||||
CmdPacketTitleBookGet,
|
||||
CmdPacketSetCloneTitle,
|
||||
CmdPacketChangeSkillslot,
|
||||
CmdPacketBuySkill,
|
||||
CmdPacketSkillInit,
|
||||
CmdPacketChangeAnotherSkillTree,
|
||||
CmdPacketSkillCommandCustomizing,
|
||||
CmdPacketSkillCommandAllDefault,
|
||||
CmdPacketCreateAccountCargo,
|
||||
CmdPacketUpgradeAccountCargo,
|
||||
CmdPacketDepositMoney,
|
||||
CmdPacketWithdrawMoney,
|
||||
CmdPacketRequestItemLock,
|
||||
CmdPacketRequestItemUnlock,
|
||||
CmdPacketRequestItemUnlockCancel,
|
||||
CmdPacketEnterSelectDungeon,
|
||||
CmdPacketSelectDungeon,
|
||||
CmdPacketGetItem,
|
||||
CmdPacketMoveMap,
|
||||
CmdPacketAcceptQuest,
|
||||
CmdPacketGiveupQuest,
|
||||
CmdPacketSetQuestTrigger,
|
||||
CmdPacketFinishQuest,
|
||||
CmdPacketMailboxSend,
|
||||
CmdPacketMailboxExtractItem,
|
||||
CmdPacketMailboxOpen,
|
||||
CmdPacketChangeLetterStat,
|
||||
CmdPacketMultiMailboxSend,
|
||||
CmdPacketQueryCharacInfoMailbox,
|
||||
CmdPacketRequestServerCharacterList,
|
||||
}
|
||||
for _, opcode := range directA {
|
||||
got, ok := LookupAlignedCommand(uint16(opcode))
|
||||
if !ok {
|
||||
t.Fatalf("A command %d missing from aligned commands", opcode)
|
||||
}
|
||||
if got.Support != AlignedSupportDirect {
|
||||
t.Fatalf("A command %d support = %q, want %q", opcode, got.Support, AlignedSupportDirect)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPartyMCPPartialCommands(t *testing.T) {
|
||||
partial := []CmdPacket{
|
||||
CmdPacketRegisterQuickParty,
|
||||
CmdPacketDirectEntranceDungeonQuickParty,
|
||||
CmdPacketReserveLeaveParty,
|
||||
CmdPacketChangePartyMemberPosition,
|
||||
CmdPacketEntryIntoParty,
|
||||
CmdPacketEntryIntoPartyFinish,
|
||||
}
|
||||
for _, opcode := range partial {
|
||||
got, ok := LookupAlignedCommand(uint16(opcode))
|
||||
if !ok {
|
||||
t.Fatalf("party partial command %d missing from aligned commands", opcode)
|
||||
}
|
||||
if got.Domain != AlignedDomainParty || got.Support != AlignedSupportPartial {
|
||||
t.Fatalf("party partial command %d = domain %q support %q", opcode, got.Domain, got.Support)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRaidMCPPartialCommands(t *testing.T) {
|
||||
partial := []CmdPacket{
|
||||
CmdPacketCreateRaid,
|
||||
CmdPacketLeaveRaid,
|
||||
CmdPacketStartRaid,
|
||||
CmdPacketSetRaidWaiting,
|
||||
CmdPacketRejoinRaid,
|
||||
CmdPacketRaidManagerWork,
|
||||
CmdPacketModifyRaidInfo,
|
||||
CmdPacketRaidOtherChannelRequestJoin,
|
||||
CmdPacketRaidMemberChangeState,
|
||||
CmdPacketRaidUserMoveChannelFail,
|
||||
CmdPacketRaidOtherChannelList,
|
||||
CmdPacketRaidCheckRaidUser,
|
||||
}
|
||||
for _, opcode := range partial {
|
||||
got, ok := LookupAlignedCommand(uint16(opcode))
|
||||
if !ok {
|
||||
t.Fatalf("raid partial command %d missing from aligned commands", opcode)
|
||||
}
|
||||
if got.Domain != AlignedDomainRaid || got.Support != AlignedSupportPartial {
|
||||
t.Fatalf("raid partial command %d = domain %q support %q", opcode, got.Domain, got.Support)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLookupBlockedMigration(t *testing.T) {
|
||||
if _, ok := LookupAlignedCommand(uint16(CmdPacketGetItembox)); ok {
|
||||
t.Fatalf("519 must not be treated as a reusable package command")
|
||||
}
|
||||
blocked, ok := LookupBlockedMigration(uint16(CmdPacketGetItembox))
|
||||
if !ok {
|
||||
t.Fatalf("LookupBlockedMigration(519) not found")
|
||||
}
|
||||
if blocked.Domain != AlignedDomainPackage {
|
||||
t.Fatalf("blocked 519 domain = %q, want %q", blocked.Domain, AlignedDomainPackage)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCurrentEXEBlocksOldCharacterSkillInfoMapping(t *testing.T) {
|
||||
if _, ok := LookupAlignedCommand(uint16(CmdPacketRequestCharacSkillInfo)); ok {
|
||||
t.Fatalf("484 must not be treated as a current EXE skill command")
|
||||
}
|
||||
blocked, ok := LookupBlockedMigration(uint16(CmdPacketRequestCharacSkillInfo))
|
||||
if !ok || blocked.Domain != AlignedDomainSkill {
|
||||
t.Fatalf("blocked 484 = %+v, found=%t", blocked, ok)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAlignedCommandsSortedCopy(t *testing.T) {
|
||||
commands := AlignedCommands()
|
||||
if len(commands) == 0 {
|
||||
t.Fatalf("AlignedCommands is empty")
|
||||
}
|
||||
for i := 1; i < len(commands); i++ {
|
||||
if commands[i-1].Opcode > commands[i].Opcode {
|
||||
t.Fatalf("AlignedCommands not sorted at %d: %d > %d", i, commands[i-1].Opcode, commands[i].Opcode)
|
||||
}
|
||||
}
|
||||
commands[0].Note = "changed by test"
|
||||
again := AlignedCommands()
|
||||
if again[0].Note == "changed by test" {
|
||||
t.Fatalf("AlignedCommands returned mutable backing data")
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user