room.go 9.68 KB
package roomrank

import (
	"apigame/configs/confroomrank"
	"apigame/service-common/svcommon"
	"apigame/service-common/svmysql"
	"apigame/util/util-lx/lxalilog"
	"apigame/util/util-lx/lxtime"
	"math"
	"math/rand"
	"sort"
)

func tryInitRoom(gameId string, room *Room) {
	svmysql.InitTable(room, gameId, false)
}

// SaveRoom 存储数据
func SaveRoom(gameId string, room *Room) {
	tryInitRoom(gameId, room)

	room.UpdateTime = lxtime.NowUninx()
	room.Encode()

	err := svmysql.Save(room, gameId)
	if err != nil {
		lxalilog.Errors(err, "roomrank.SaveRoom error", gameId, room.Id, room.ActivityId)
		return
	}
}

// LoadRoom 获取数据
func LoadRoom(gameId string, topType int, activityId int64, roomUid int64) (room *Room, has bool) {
	room = &Room{Id: roomUid, TopType: topType, ActivityId: activityId}
	if roomUid == 0 {
		has = false
		return
	}
	tryInitRoom(gameId, room)

	var err error
	has, err = svmysql.First(room, gameId)
	if err != nil {
		lxalilog.Errors(err, "roomrank.LoadRoom error", gameId, roomUid, activityId)
		return
	}
	room.Decode()

	return
}

func CreateRoom(gameId string, topType int, config *confroomrank.ActivityConfig, roomConfigId int, activityTime int64) (room *Room, has bool) {
	room = new(Room)
	room.TopType = topType
	room.ActivityId = config.Id
	room.ConfigId = roomConfigId
	room.Closed = false
	room.HasSettle = false
	room.CreateTime = lxtime.NowUninx()
	room.ActivityTime = activityTime
	details := new(RoomDetails)
	details.Players = make([]*RoomPlayer, 0)
	details.IndexNames = make([]int, 0)
	room.Details = details

	err := svmysql.Save(room, gameId)
	if err != nil {
		has = false
	} else {
		has = true
	}
	return
}

// FindRoom 查找
func FindRoom(gameId string, topType int, activityId int64, roomConfigId int, activityTime int64) (rooms []*Room, has bool) {
	roomDemo := &Room{TopType: topType, ActivityId: activityId, ActivityTime: activityTime}
	tryInitRoom(gameId, roomDemo)
	info := roomDemo.MysqlInfo(gameId)

	info.DbMysql = info.DbMysql.Where("config_id = ?  AND activity_time = ? AND closed = false", roomConfigId, activityTime)
	has, _ = svmysql.Find(&rooms, info)
	for _, room := range rooms {
		room.Decode()
	}

	return
}

// TryGetRoom 尝试获取房间
func TryGetRoom(gameId string, topType int, player *Player, config *confroomrank.ActivityConfig) (room *Room, hasRoom bool) {
	hasRoom = false
	// 查找玩家所在的房间
	room, hasRoom = LoadRoom(gameId, topType, config.Id, player.RoomUid)
	if hasRoom {
		if confRoom, hasConfRoom := config.Room[room.ConfigId]; hasConfRoom {
			TryCloseRoom(gameId, room, config, confRoom)
		}
		return
	}

	return
}

// TryFindRoom 尝试获取房间
func TryFindRoom(gameId string, topType int, player *Player, config *confroomrank.ActivityConfig, playerLevel int, activityTime int64) (room *Room, hasRoom bool, firstJoin bool) {
	// 根据等级和分数范围查找合适的房间配置ID
	roomConfigId := 0
	roomConfig := confroomrank.RoomConfig{}
	for _, i2 := range config.Room {
		if playerLevel >= i2.Levels[0] &&
			playerLevel <= i2.Levels[1] &&
			player.UserClass == i2.UserClass {
			roomConfigId = i2.Id
			roomConfig = i2
		}
	}
	if roomConfigId == 0 {
		lxalilog.Errors("TryGetRoom find roomConfigId error", playerLevel, player.UserClass)
		return
	}
	// 数据库查找合适条件的房间列表
	rooms, has := FindRoom(gameId, topType, config.Id, roomConfigId, activityTime)
	if has {
		for i := 0; i < len(rooms); i++ {
			roomTemp := rooms[i]
			TryCloseRoom(gameId, roomTemp, config, roomConfig)
			if roomTemp.Closed {
				continue
			}
			// 可容纳玩家类型数量
			canJoinCount := GetTypeCanJoinCount(roomTemp, roomConfig, player.UserType)
			if canJoinCount > 0 {
				room = roomTemp
				hasRoom = true
				break
			}
		}
	}
	if hasRoom {
		// 如果有 就加入
		PlayerJoinRoom(room, player)
		firstJoin = true
	} else {
		// 如果没有合适条件的房间 创建一个
		roomCreate, hasCreate := CreateRoom(gameId, topType, config, roomConfigId, activityTime)
		if hasCreate {
			room = roomCreate

			room.Details.IndexNames = svcommon.GetIndexNames(gameId, roomConfig.TotalPlayer)

			// 配置原生机器人
			JoinInitRobot(gameId, room, roomConfig)

			PlayerJoinRoom(room, player)
			firstJoin = true
			hasRoom = hasCreate
		}
	}

	return
}

func PlayerJoinRoom(room *Room, player *Player) {
	roomPlayer := NewRoomPlayer(player)
	room.Details.Players = append(room.Details.Players, roomPlayer)
	player.RoomUid = room.Id
}

// TryCloseRoom 尝试关闭房间
func TryCloseRoom(gameId string, room *Room, config *confroomrank.ActivityConfig, roomConfig confroomrank.RoomConfig) {
	if room.Closed {
		return
	}
	secNow := lxtime.NowUninx()
	if secNow > room.CreateTime+RoomCloseSecond {
		room.Closed = true
		// 根据缺口自动填充机器人
		for i := 0; i < len(roomConfig.PlayerTypeCount); i++ {
			pair := roomConfig.PlayerTypeCount[i]
			userType := pair[0]
			canJoinCount := pair[1] - room.GetPlayerTypeCount(userType)
			robotConfigId := roomConfig.AutoRobot[i]
			for i := 0; i < canJoinCount; i++ {
				roomPlayer := NewRoomRobot(gameId, room, robotConfigId, userType)
				room.Details.Players = append(room.Details.Players, roomPlayer)
			}
		}
		// 如果总数还不足 用默认的第一类来填充
		{
			canJoinCount := roomConfig.TotalPlayer - len(room.Details.Players)
			if canJoinCount > 0 && len(roomConfig.AutoRobot) > 0 {
				userType := roomConfig.PlayerTypeCount[0][0]
				robotConfigId := roomConfig.AutoRobot[0]
				for i := 0; i < canJoinCount; i++ {
					roomPlayer := NewRoomRobot(gameId, room, robotConfigId, userType)
					room.Details.Players = append(room.Details.Players, roomPlayer)
				}
			}
		}
		// 填充完之后要排序计算
		TryReSort(room, config)

		SaveRoom(gameId, room)
	}
}

// GetTypeCanJoinCount 房间获取某种类型玩家可加入数量
func GetTypeCanJoinCount(room *Room, roomConfig confroomrank.RoomConfig, userType int) int {
	maxCount := 0
	for i := 0; i < len(roomConfig.PlayerTypeCount); i++ {
		pair := roomConfig.PlayerTypeCount[i]
		if pair[0] == userType {
			maxCount = pair[1]
			break
		}
	}
	return maxCount - room.GetPlayerTypeCount(userType)
}

// JoinInitRobot 配置原生机器人
func JoinInitRobot(gameId string, room *Room, roomConfig confroomrank.RoomConfig) {
	for i := 0; i < len(roomConfig.InitRobot); i++ {
		pair := roomConfig.InitRobot[i]
		robotConfigId := pair[0]
		robotCount := pair[1]
		for i := 0; i < robotCount; i++ {
			roomPlayer := NewRoomRobot(gameId, room, robotConfigId, -1)
			room.Details.Players = append(room.Details.Players, roomPlayer)
		}
	}
}

// TrySettleRoom 尝试结算房间
func TrySettleRoom(gameId string, room *Room, config *confroomrank.ActivityConfig) {
	// 已经结算过的不结算
	if room.HasSettle {
		return
	}
	// 活动切换或者时间到 触发结算
	needSettle := false
	if room.ActivityId != config.Id {
		needSettle = true
	} else {
		dateEnd := GetTimeEnd(room.ActivityTime, config.ReleaseTime)
		dtNow := lxtime.NowUninx()
		if dtNow >= dateEnd.Unix() {
			needSettle = true
		}
	}

	if !needSettle {
		return
	}

	percent := float64(0)
	dateEnd := GetTimeEnd(room.ActivityTime, config.ReleaseTime)
	secTotal := 24 * 60 * 60
	dtEnd := dateEnd.Unix()
	if dtEnd > config.EndTime {
		dtEnd = config.EndTime
	}
	dtCreate := room.CreateTime
	if dtEnd <= dtCreate {
		percent = 0
	} else {
		percent = float64(dtEnd-dtCreate) * 100 / float64(secTotal)
	}
	// 机器人最终算分
	for i := 0; i < len(room.Details.Players); i++ {
		roomPlayer := room.Details.Players[i]
		if roomPlayer.RobotConfigId == 0 {
			continue
		}
		confRobot, hasConfRobot := config.Robot[roomPlayer.RobotConfigId]
		if hasConfRobot {
			roomPlayer.Score = GetRobotScoreCurrent(&confRobot, percent)
		}
	}

	sort.Sort(room.Details)
	room.HasSettle = true
	SaveRoom(gameId, room)
}

// TryResetRobot 尝试改变机器人分数并重新排序
func TryResetRobot(room *Room, config *confroomrank.ActivityConfig) {
	secNow := lxtime.NowUninx()
	if secNow < room.ResetRobotTime+RoomResetRobotSecond {
		return
	}
	room.ResetRobotTime = secNow

	percent := float64(0)
	dateEnd := GetTimeEnd(room.ActivityTime, config.ReleaseTime)
	secTotal := 24 * 60 * 60
	dtEnd := dateEnd.Unix()
	if dtEnd > config.EndTime {
		dtEnd = config.EndTime
	}
	dtCreate := room.CreateTime
	if dtEnd <= dtCreate {
		percent = 0
	} else if secNow <= dtCreate {
		percent = 0
	} else if secNow >= dtEnd {
		percent = 100
	} else {
		percent = float64(secNow-dtCreate) * 100 / float64(secTotal)
	}

	// 机器人即时算分
	for i := 0; i < len(room.Details.Players); i++ {
		roomPlayer := room.Details.Players[i]
		if roomPlayer.RobotConfigId == 0 {
			continue
		}
		confRobot, hasConfRobot := config.Robot[roomPlayer.RobotConfigId]
		if hasConfRobot {
			roomPlayer.Score = GetRobotScoreCurrent(&confRobot, percent)
		}
	}
}

// TryReSort 尝试重新排序
func TryReSort(room *Room, config *confroomrank.ActivityConfig) {
	TryResetRobot(room, config)
	sort.Sort(room.Details)
}

// GetRobotScoreCurrent 从机器人配置里得到实时得分
func GetRobotScoreCurrent(confRobot *confroomrank.RobotConfig, percent float64) int64 {
	score := (float64(confRobot.TotalScore-confRobot.MinScore) *
		float64(100-confRobot.Range+rand.Intn(confRobot.Range*2)) / 100) * percent / 100
	result := int64(confRobot.MinScore) + int64(math.Ceil(score))
	if result < int64(confRobot.MinScore) {
		result = int64(confRobot.MinScore)
	}
	return result
}

// GetRobotScoreMax 从机器人配置里得到最高分
func GetRobotScoreMax(confRobot *confroomrank.RobotConfig) int64 {
	score := float64(confRobot.TotalScore-confRobot.MinScore) *
		float64(100-confRobot.Range+rand.Intn(confRobot.Range*2)) / float64(100)
	result := int64(confRobot.MinScore) + int64(math.Ceil(score))
	if result < int64(confRobot.MinScore) {
		result = int64(confRobot.MinScore)
	}
	return result
}