更新功能
This commit is contained in:
@@ -25,8 +25,30 @@ type wsMessage struct {
|
||||
}
|
||||
|
||||
// push 向该客户端推送一条消息(满队列时丢弃,防止慢客户端拖垮全局)
|
||||
// 注意:data 若是 json.RawMessage([]byte),必须走 wsMessage 结构体嵌入,
|
||||
// 否则 encoding/json 会把 []byte 编成 base64 字符串,饥荒世界快照会损坏。
|
||||
func (c *Client) push(msgType string, data any) {
|
||||
payload, _ := json.Marshal(map[string]any{"type": msgType, "data": data})
|
||||
var dataRaw json.RawMessage
|
||||
switch v := data.(type) {
|
||||
case nil:
|
||||
dataRaw = json.RawMessage("null")
|
||||
case json.RawMessage:
|
||||
if len(v) == 0 {
|
||||
dataRaw = json.RawMessage("null")
|
||||
} else {
|
||||
dataRaw = v
|
||||
}
|
||||
default:
|
||||
b, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
dataRaw = b
|
||||
}
|
||||
payload, err := json.Marshal(wsMessage{Type: msgType, Data: dataRaw})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
select {
|
||||
case c.send <- payload:
|
||||
default:
|
||||
@@ -44,7 +66,7 @@ func (c *Client) readPump() {
|
||||
c.hub.onDisconnect(c)
|
||||
c.conn.Close()
|
||||
}()
|
||||
c.conn.SetReadLimit(8 * 1024)
|
||||
c.conn.SetReadLimit(4 * 1024 * 1024) // 4MB:饥荒全量世界快照(tiles+ents)远超默认 8KB
|
||||
// 心跳:60秒收不到任何数据判定断线(前端每30秒发 ping)
|
||||
c.conn.SetReadDeadline(time.Now().Add(60 * time.Second))
|
||||
c.conn.SetPongHandler(func(string) error {
|
||||
|
||||
@@ -463,7 +463,7 @@ func (r *Room) handleMessage(c *Client, msgType string, raw json.RawMessage) {
|
||||
seat.Skin = req.Skin
|
||||
r.broadcastStateLocked()
|
||||
case "starve_input":
|
||||
// 饥荒队友输入:不解析内容,附上座位号仅转发给房主连接(主机权威模拟)
|
||||
// 饥荒队友输入:解析后附上权威座位号转发给房主(主机权威模拟)
|
||||
if r.Game != "starve" || r.status != "playing" {
|
||||
return
|
||||
}
|
||||
@@ -471,14 +471,27 @@ func (r *Room) handleMessage(c *Client, msgType string, raw json.RawMessage) {
|
||||
if host == nil || host.client == nil || seat.UserID == r.hostUserID {
|
||||
return
|
||||
}
|
||||
host.client.push("starve_input", map[string]any{"seat": seat.Index, "data": raw})
|
||||
var payload map[string]any
|
||||
if err := json.Unmarshal(raw, &payload); err != nil || payload == nil {
|
||||
return
|
||||
}
|
||||
payload["seat"] = seat.Index // 以服务端座位为准,防伪造
|
||||
host.client.push("starve_input", payload)
|
||||
case "starve_state":
|
||||
// 饥荒主机快照:仅房主可发,原样广播给其余座位(间隔 <80ms 丢弃防刷)
|
||||
// 饥荒主机快照:仅房主可发,原样广播给其余座位
|
||||
// 全量世界(full:1)不限流;增量快照间隔 <80ms 丢弃防刷
|
||||
if r.Game != "starve" || r.status != "playing" || seat.UserID != r.hostUserID {
|
||||
return
|
||||
}
|
||||
isFull := false
|
||||
var peek struct {
|
||||
Full int `json:"full"`
|
||||
}
|
||||
if json.Unmarshal(raw, &peek) == nil && peek.Full != 0 {
|
||||
isFull = true
|
||||
}
|
||||
now := time.Now().UnixMilli()
|
||||
if now-r.starveMs < 80 {
|
||||
if !isFull && now-r.starveMs < 80 {
|
||||
return
|
||||
}
|
||||
r.starveMs = now
|
||||
@@ -495,6 +508,62 @@ func (r *Room) handleMessage(c *Client, msgType string, raw json.RawMessage) {
|
||||
r.broadcastChatLocked(-1, "系统", "", "全员阵亡,冒险结束", false)
|
||||
r.endStarveLocked("全员阵亡,冒险结束")
|
||||
r.broadcastStateLocked()
|
||||
case "invite":
|
||||
// 邀请好友进房:仅房主可发,目标必须是自己的已通过好友且不在房内
|
||||
// 好友在线则实时推弹窗邀请;离线落一条私聊兜底(上线可见)
|
||||
var req struct {
|
||||
UserID int `json:"user_id"`
|
||||
}
|
||||
json.Unmarshal(raw, &req)
|
||||
if r.status != "waiting" {
|
||||
c.pushError("对局进行中,无法邀请")
|
||||
return
|
||||
}
|
||||
if seat.UserID != r.hostUserID {
|
||||
c.pushError("只有房主可以邀请好友")
|
||||
return
|
||||
}
|
||||
if req.UserID <= 0 || req.UserID == c.userID {
|
||||
c.pushError("参数有误")
|
||||
return
|
||||
}
|
||||
// 必须是已通过的好友关系
|
||||
var cnt int64
|
||||
database.DB.Model(&model.Friend{}).
|
||||
Where("(user_id = ? AND friend_id = ? OR user_id = ? AND friend_id = ?) AND status = ?",
|
||||
c.userID, req.UserID, req.UserID, c.userID, model.FriendStatusAccepted).
|
||||
Count(&cnt)
|
||||
if cnt == 0 {
|
||||
c.pushError("只能邀请好友")
|
||||
return
|
||||
}
|
||||
// 不能已在房内
|
||||
for _, s := range r.seats {
|
||||
if s.UserID == req.UserID {
|
||||
c.pushError("对方已在房间内")
|
||||
return
|
||||
}
|
||||
}
|
||||
gameName := r.Game
|
||||
var g model.Game
|
||||
if err := database.DB.Where("code = ?", r.Game).First(&g).Error; err == nil && g.Name != "" {
|
||||
gameName = g.Name
|
||||
}
|
||||
inviteData := map[string]any{
|
||||
"code": r.Code, "game": r.Game, "game_name": gameName,
|
||||
"host_id": c.userID, "host_name": seat.Name, "host_avatar": seat.Avatar,
|
||||
}
|
||||
// 在线实时弹窗;离线降级为私聊消息兜底(下次上线可见)
|
||||
if !PushToUser(req.UserID, "room_invite", inviteData) {
|
||||
var peer model.User
|
||||
if err := database.DB.First(&peer, req.UserID).Error; err == nil {
|
||||
database.DB.Create(&model.ChatMessage{
|
||||
FromID: c.userID, ToID: req.UserID,
|
||||
Content: fmt.Sprintf("邀请你加入房间【%s】,邀请码 %s", gameName, r.Code),
|
||||
})
|
||||
}
|
||||
}
|
||||
c.push("invite_sent", map[string]any{"user_id": req.UserID})
|
||||
case "chat":
|
||||
var req struct {
|
||||
Text string `json:"text"`
|
||||
|
||||
Reference in New Issue
Block a user