Files
90CNServer/server/internal/services/dnfbridge/pvp_total_rewards.go
T
hanfuit 645b64fe21 DNF90 服务端与启动器完整源码(含 GM 工具功能增强)
服务端(Go):
- GM 塞背包/带属性装备发放:在线角色推送 op14 增量物品行,背包实时刷新,无需回角色选择界面
- GM 改金币/改等级:去掉在线拒绝,落库后推送 op14 钱包/op37 等级状态,在线实时刷新
- 等级端点统一切换到新版 GMSetCharacterLevel(自带在线刷新)
- 无限/锁死疲劳模式 + 燃烧疲劳:每房间消耗 2 点、打怪与通关经验双倍
- 燃烧疲劳开关时给所有在线角色推送系统提示(op12 mode 0)
- 深渊史诗掉率:GM 全局倍率 + 城镇增益药剂窗口倍率,真实接入掉落结算

启动器(Python/JS):
- 标题栏自绘、窗口 1204x717、禁止拖拽改大小、仅最小化/关闭
- GM 工具:疲劳与燃烧、深渊史诗掉率、拍卖行上架(单一定价对齐)
- 拍卖行上架前端对齐服务端单一价格语义,修复 400 报错
2026-11-04 14:31:55 +08:00

61 lines
2.5 KiB
Go

package dnfbridge
import (
"context"
"errors"
"fmt"
"strconv"
"time"
"longheng.io/server/internal/modules/dnf/alignedcmd"
"longheng.io/server/internal/modules/dnf/inventory"
dnfpvp "longheng.io/server/internal/modules/dnf/pvp"
repo "longheng.io/server/internal/modules/dnf/repository"
)
func (s *Service) grantCurrentPVPTotalTargets(ctx context.Context, repos repo.Group, catalog *dnfpvp.Catalog, session *gameSession) (dnfpvp.TotalRewards, error) {
place := func(record repo.InventoryRecord, id, count int64, now time.Time) (repo.InventoryRecord, error) {
items, err := s.currentPVFItemCatalog()
if err != nil {
return repo.InventoryRecord{}, err
}
definition, err := items.ResolveItem(uint32(id))
if err != nil {
return repo.InventoryRecord{}, err
}
definition, err = currentPVFItemDefinitionForGrantAt(definition, now)
if err != nil {
return repo.InventoryRecord{}, err
}
if definition.Kind != dungeonDropItemStackable {
return repo.InventoryRecord{}, fmt.Errorf("total target item %d is not stackable", id)
}
result, err := inventory.PlaceStackableReward(record, alignedcmd.MagicBoxRewardItem{
ItemID: id, Kind: string(definition.Kind), StackLimit: definition.StackLimit,
SlotStart: definition.SlotStart, SlotEnd: definition.SlotEnd, PVFPath: definition.PVFPath,
ExpireAt: definition.ExpirationDate, UsablePeriodDays: definition.UsablePeriodDays,
}, count)
if errors.Is(err, inventory.ErrRandomRewardInventoryFull) {
return repo.InventoryRecord{}, dnfpvp.ErrTotalRewardInventoryFull
}
if err != nil {
return repo.InventoryRecord{}, fmt.Errorf("total target reward item=%d: %w", id, err)
}
return result, err
}
result, err := dnfpvp.GrantTotalTargets(ctx, repos, catalog, session.accountID, strconv.Itoa(int(session.selectedCharacterID)), s.gameplayNow(), place)
if err == nil && (len(result.Granted) > 0 || len(result.Pending) > 0) {
s.logGameEvent(session, "game-pvp-total-target-rewards", "granted", result.Granted, "pending_inventory_space", result.Pending)
}
return result, err
}
func (s *Service) sendCurrentPVPTotalRewards(session *gameSession, rewards dnfpvp.TotalRewards) error {
entries := []currentItemListEntry{currentPVPEmblemWalletEntry(statU32(rewards.Character, dnfpvp.EmblemsKey, 0))}
for slot, stack := range rewards.Items {
entries = append(entries, currentItemListEntryFromStack(0, slot, stack))
}
sortCurrentItemListEntries(entries)
return s.sendGameUpperRawClass(session, 14, buildCurrentItemUpdateBody(0, entries), 0)
}