Files
GaCy-GO/internal/gameserver/currency_wars_dispatch.go
T
2026-10-28 18:54:43 +07:00

65 lines
2.2 KiB
Go

package gameserver
import (
"errors"
"fmt"
"io"
"net"
pb "gac-hkrpg-go/protocol/proto"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
)
type cwPacketSendError struct{ cause error }
func (e *cwPacketSendError) Error() string { return e.cause.Error() }
func (e *cwPacketSendError) Unwrap() error { return e.cause }
// Mark every explicit send failure, including serialization/projection errors,
// so the request wrapper never attempts a second response after such a failure.
func cwSend(s *Session, message proto.Message) error {
if err := s.Send(message); err != nil {
return &cwPacketSendError{cause: err}
}
return nil
}
// CW transactions report configuration/validation/save failures through their
// typed response. Returning these errors directly to the general dispatcher
// suppresses the response altogether and leaves the Client's wait block open.
// This does not manufacture success or retry a transaction after a failed save.
func cwHandle[ReqT any, RspT any](name string, fn func(*Session, *ReqT, *RspT) error) {
cwHandleNamed(name, name+"ScRsp", fn)
}
func cwHandleNamed[ReqT any, RspT any](name, responseName string, fn func(*Session, *ReqT, *RspT) error) {
handleNamed(name, responseName, func(s *Session, req *ReqT, rsp *RspT) error {
err := fn(s, req, rsp)
if err == nil || errors.Is(err, errResponseAlreadySent) {
return err
}
// An actual transport failure belongs to the connection, not a new CW
// result packet. Preserve it for the network caller to handle.
var networkError net.Error
var sendError *cwPacketSendError
if errors.As(err, &sendError) || errors.As(err, &networkError) || errors.Is(err, io.EOF) || errors.Is(err, net.ErrClosed) {
return err
}
message, ok := any(rsp).(proto.Message)
if !ok {
return err
}
view := message.ProtoReflect()
retcode := view.Descriptor().Fields().ByName("retcode")
if retcode == nil || retcode.Kind() != protoreflect.Uint32Kind {
return err
}
if view.Get(retcode).Uint() == 0 {
view.Set(retcode, protoreflect.ValueOfUint32(uint32(pb.Retcode_RET_GRID_FIGHT_CONF_MISS)))
}
PacketLog(fmt.Sprintf("CW_REQUEST failed request=%s response=%s retcode=%d error=%v", name, responseName, view.Get(retcode).Uint(), err))
return nil
})
}