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,122 @@
|
||||
package inventory
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
"longheng.io/server/internal/modules/dnf/alignedcmd"
|
||||
dnfguardianshield "longheng.io/server/internal/modules/dnf/guardianshield"
|
||||
)
|
||||
|
||||
const currentGuardianShieldDeckNotificationMsgID uint16 = 580
|
||||
|
||||
func decodeCurrentGuardianShieldDeckRequest(body []byte) (dnfguardianshield.Deck, error) {
|
||||
var deck dnfguardianshield.Deck
|
||||
if len(body) != dnfguardianshield.DeckSlotCount*4 {
|
||||
return deck, fmt.Errorf("current op657 guardian shield deck body length=%d want=%d", len(body), dnfguardianshield.DeckSlotCount*4)
|
||||
}
|
||||
for index := range deck {
|
||||
deck[index] = binary.LittleEndian.Uint32(body[index*4 : index*4+4])
|
||||
}
|
||||
return deck, nil
|
||||
}
|
||||
|
||||
func buildCurrentGuardianShieldDeckBody(deck dnfguardianshield.Deck) []byte {
|
||||
body := make([]byte, dnfguardianshield.DeckSlotCount*4)
|
||||
for index, itemID := range deck {
|
||||
binary.LittleEndian.PutUint32(body[index*4:index*4+4], itemID)
|
||||
}
|
||||
return body
|
||||
}
|
||||
|
||||
func buildCurrentGuardianShieldDeckSuccessBody(deck dnfguardianshield.Deck) []byte {
|
||||
body := make([]byte, 2+dnfguardianshield.DeckSlotCount*4)
|
||||
body[0] = 1
|
||||
copy(body[2:], buildCurrentGuardianShieldDeckBody(deck))
|
||||
return body
|
||||
}
|
||||
|
||||
func ownerAppliedGuardianShieldMoveResult(opcode uint16, cmd Command, result dnfguardianshield.Result) alignedcmd.Result {
|
||||
postActions := []alignedcmd.PostAction(nil)
|
||||
if result.MainChanged {
|
||||
// The Guardian's visible main shield is persisted in actor equipment
|
||||
// slot 24. That slot is outside the ordinary fourteen-row mode0
|
||||
// appearance table, so the town actor must be reconciled through the
|
||||
// current client's native complete op342 equipment group followed by its
|
||||
// op357 same-state redraw. Backup-only deck edits use op657 and do not
|
||||
// touch the visible actor.
|
||||
postActions = append(postActions, alignedcmd.PostActionRefreshSelectedActorExpandedEquipment)
|
||||
// While the main deck slot stays occupied, additionally republish the
|
||||
// selected actor's mode0 scene-object appearance rows exactly like an
|
||||
// ordinary equipment change. The mode0 appearance summary carries the
|
||||
// actor-slot-24 deck projection as an extra row, so the client redraws
|
||||
// the shield immediately without a scene reselect. Equipping a shield
|
||||
// while the deck[0] slot was empty still reaches this branch (empty ->
|
||||
// item); only an unequip (deck[0] emptied) skips it and converges on
|
||||
// the next scene bootstrap, mirroring the 90server deck-move sequence
|
||||
// (op19 ACK -> op580 deck -> op342 expanded equipment -> mode0
|
||||
// appearance + op357 user-state redraw).
|
||||
if result.Deck[dnfguardianshield.MainDeckSlot] > 0 {
|
||||
postActions = append(postActions, alignedcmd.PostActionRefreshSelectedActorAppearance)
|
||||
}
|
||||
}
|
||||
return alignedcmd.Result{
|
||||
Handled: true,
|
||||
ResponseAllowed: true,
|
||||
Operation: cmd.Operation,
|
||||
Reason: fmt.Sprintf(
|
||||
"guardian shield owner applied current op19 endpoints source=(%d,%d) destination=(%d,%d) changed=%t main_changed=%t; emitted native ACK then authoritative class0/op580 five-slot deck and, when the visible main changed, native op342/op357 town appearance refresh",
|
||||
cmd.SourceListType,
|
||||
cmd.SourceSlotIndex,
|
||||
cmd.DestinationListType,
|
||||
cmd.DestinationSlotIndex,
|
||||
result.Changed,
|
||||
result.MainChanged,
|
||||
),
|
||||
UpperResponses: []alignedcmd.UpperResponse{
|
||||
class1Response(opcode, buildMoveItemspaceSuccessAck(cmd, cmd.MoveCount)),
|
||||
class0Response(currentGuardianShieldDeckNotificationMsgID, buildCurrentGuardianShieldDeckBody(result.Deck)),
|
||||
},
|
||||
PostActions: postActions,
|
||||
}
|
||||
}
|
||||
|
||||
func ownerRejectedGuardianShieldMoveResult(opcode uint16, cmd Command, err error) alignedcmd.Result {
|
||||
return alignedcmd.Result{
|
||||
Handled: true,
|
||||
ResponseAllowed: true,
|
||||
Operation: cmd.Operation,
|
||||
Reason: fmt.Sprintf("guardian shield move rejected without mutation: %s: %v", cmd.String(), err),
|
||||
UpperResponses: []alignedcmd.UpperResponse{
|
||||
class1Response(opcode, buildMoveItemspaceFailureAck(cmd, moveItemspaceRejectedErrorCode)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func appliedGuardianShieldDeckResult(opcode uint16, result dnfguardianshield.Result) alignedcmd.Result {
|
||||
return alignedcmd.Result{
|
||||
Handled: true,
|
||||
ResponseAllowed: true,
|
||||
Operation: "change_guardian_shield_deck",
|
||||
Reason: fmt.Sprintf(
|
||||
"guardian shield owner atomically saved current op657 five-slot deck changed=%t main_changed=%t",
|
||||
result.Changed,
|
||||
result.MainChanged,
|
||||
),
|
||||
UpperResponses: []alignedcmd.UpperResponse{
|
||||
class0Response(opcode, buildCurrentGuardianShieldDeckSuccessBody(result.Deck)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func rejectedGuardianShieldDeckResult(opcode uint16, err error) alignedcmd.Result {
|
||||
return alignedcmd.Result{
|
||||
Handled: true,
|
||||
ResponseAllowed: true,
|
||||
Operation: "change_guardian_shield_deck",
|
||||
Reason: fmt.Sprintf("guardian shield op657 rejected without mutation: %v", err),
|
||||
// Current handler reads the remaining reserved/deck fields only when
|
||||
// status is nonzero. A one-byte zero is therefore the closed failure body.
|
||||
UpperResponses: []alignedcmd.UpperResponse{class0Response(opcode, []byte{0})},
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user