合并本地领先源码:旧UI、GM疲劳燃烧、白金徽章孔、宠物修复、支援兵普攻开关

This commit is contained in:
hanfuit committed 2026-11-04 19:20:49 +08:00
1 parent f2debaf9bf
commit 70b3c5a6dc
57 files changed
+4256 -30

No files matched your search

@@ -0,0 +1,129 @@
package dnfbridge
import (
"bytes"
"encoding/binary"
"net"
"testing"
"time"
"longheng.io/server/internal/modules/dnf/channelcatalog"
)
type companionPartyTestConn struct {
net.Conn
write bytes.Buffer
}
func (c *companionPartyTestConn) Write(data []byte) (int, error) { return c.write.Write(data) }
func (c *companionPartyTestConn) SetWriteDeadline(time.Time) error {
return nil
}
func TestCompanionPresenceFriendRowRendersOnline(t *testing.T) {
service := &Service{}
virtual := &gameSession{
selectedCharacterID: 6,
characterGeneration: 7,
channel: channelcatalog.Channel{ID: 11},
companionVirtual: true,
companionOwnerID: 2,
}
service.companionSessions = map[uint16]*gameSession{6: virtual}
presence := service.currentUnitedFriendPresence(6)
if presence.Busy {
t.Fatal("volunteer friend row must not render busy/登录中")
}
if presence.ChannelID != 11 {
t.Fatalf("friend row channel=%d want 11", presence.ChannelID)
}
}
func TestBuildCompanionPartyStateUsesNativeFourSlotRoster(t *testing.T) {
service := &Service{}
owner := &gameSession{selectedCharacterID: 2}
run := &currentDungeonCompanionRun{
Ready: true,
Sources: []currentDungeonCompanionSourceRun{
{Ready: true, SourceCharacterID: 6},
{Ready: false, SourceCharacterID: 7},
{Ready: true, SourceCharacterID: 3},
},
}
state := service.buildCompanionPartyState(owner, run)
if state.PartyID <= 0 || state.PartyID >= 0xFFFF {
t.Fatalf("party id=%d is not a printable native party", state.PartyID)
}
if state.UserID != 2 || !state.IsLeader || state.MaxMembers != 4 {
t.Fatalf("party identity=%+v", state)
}
if len(state.Members) != 3 {
t.Fatalf("members=%v want owner + 2 ready volunteers", state.Members)
}
want := []struct {
id uint16
slot byte
}{{2, 0}, {6, 1}, {3, 2}}
for index, expected := range want {
member := state.Members[index]
if member.UserID != expected.id || member.Slot != expected.slot {
t.Fatalf("member %d=%+v want id=%d slot=%d", index, member, expected.id, expected.slot)
}
if member.HPPercent != 100 || member.MPPercent != 100 {
t.Fatalf("member %d hp/mp=%d/%d want 100/100", index, member.HPPercent, member.MPPercent)
}
}
}
func TestClearCompanionNativePartySendsOp9ThenOp153(t *testing.T) {
connection := &companionPartyTestConn{}
session := &gameSession{
conn: connection,
connID: "companion-party-clear",
selectedCharacterID: 2,
characterGeneration: 3,
channel: channelcatalog.Channel{ID: 11},
}
run := &currentDungeonCompanionRun{
Ready: true,
NativePartyID: 0xE002,
NativePartySent: true,
}
service := &Service{}
service.clearCurrentDungeonCompanionNativeParty(session, run)
if run.NativePartySent {
t.Fatal("native party flag was not cleared")
}
stream := connection.write.Bytes()
headerSize := service.gameUpperHeaderSize()
msgIDs := make([]uint16, 0, 2)
for len(stream) > 0 {
if len(stream) < headerSize {
t.Fatalf("truncated packet header: %d", len(stream))
}
total := int(binary.LittleEndian.Uint32(stream[3:7]))
if total < headerSize || total > len(stream) {
t.Fatalf("packet total=%d stream=%d", total, len(stream))
}
msgIDs = append(msgIDs, binary.LittleEndian.Uint16(stream[1:3]))
stream = stream[total:]
}
if len(msgIDs) != 2 || msgIDs[0] != 9 || msgIDs[1] != 0x0099 {
t.Fatalf("clear packets=%v want [9 153]", msgIDs)
}
}
func TestCompanionSessionIdentityIsCurrentOnlyWhileRegistered(t *testing.T) {
service := &Service{}
virtual := &gameSession{selectedCharacterID: 6, characterGeneration: 9, companionVirtual: true}
service.companionSessions = map[uint16]*gameSession{6: virtual}
identity, ok := service.companionSessionSnapshot(6)
if !ok || !identity.virtual || !service.boundGameSessionCharacterCurrent(identity) {
t.Fatalf("virtual identity=%+v ok=%v current=%v", identity, ok, service.boundGameSessionCharacterCurrent(identity))
}
delete(service.companionSessions, 6)
if service.boundGameSessionCharacterCurrent(identity) {
t.Fatal("removed volunteer session must fail the liveness check")
}
}