diff --git a/game-server/app/servers/battle/handler/pvpHandler.ts b/game-server/app/servers/battle/handler/pvpHandler.ts index add092be2..f271caf99 100644 --- a/game-server/app/servers/battle/handler/pvpHandler.ts +++ b/game-server/app/servers/battle/handler/pvpHandler.ts @@ -8,8 +8,8 @@ import { resResult, reduceCe, genCode } from '../../../pubUtils/util'; import { SystemConfigModel } from '../../../db/SystemConfig' import { PvpDefenseModel, PvpDefenseType, OppPlayers } from '../../../db/PvpDefense'; -import { oppHeroesDefenseInter, pvpEndParamInter } from '../../../pubUtils/interface'; -import { PVP_HERO_POS } from '../../../consts'; +import { oppHeroesDefenseInter, pvpEndParamInter, RankParam } from '../../../pubUtils/interface'; +import { PVP_HERO_POS, REDIS_KEY } from '../../../consts'; import { HeroType, HeroModel } from '../../../db/Hero'; import { CeAttrNumber } from '../../../db/generalField'; @@ -17,6 +17,8 @@ import { checkBattleHeroesByHid } from '../../../services/normalBattleService'; import { BattleRecordModel } from '../../../db/BattleRecord'; import { PvpRecordModel, HeroesRecord } from '../../../db/PvpRecord'; import { setPvpDefResult } from '../../../services/timeTaskService'; +import { existsRank, initRank, getRank, setRank, getMyRank } from '../../../services/redisService'; + export default function(app: Application) { return new PvpHandler(app); } @@ -25,17 +27,10 @@ export class PvpHandler { constructor(private app: Application) { } - async test(msg: {}, session: BackendSession) { - let roleId = session.get('roleId'); - let role = await RoleModel.findByRoleId(roleId); - const result = await initPvpInfo(role); - return resResult(STATUS.SUCCESS, {result}); - } - async getData (msg: {}, session: BackendSession) { let roleId = session.get('roleId'); let pvpDefense = await PvpDefenseModel.findByRoleIdIncludeAll(roleId); - let oppPlayers = getEnemies(pvpDefense.oppPlayers, pvpDefense.winStreakNum); + let oppPlayers = await getEnemies(pvpDefense.oppPlayers, pvpDefense.winStreakNum); let {warId, seasonNum, seasonEndTime} = await SystemConfigModel.findSystemConfig(); let {heroes, score, pLv, winStreakNum, refOppCnt, challengeCnt, challengeRefTime, receivedBox, hisScore, heroScores, isFirstEntry} = pvpDefense; if (pvpDefense.seasonNum !== seasonNum) { @@ -44,7 +39,7 @@ export class PvpHandler { if (isFirstEntry) { await PvpDefenseModel.updateInfo(roleId, {isFirstEntry:false}); } - let myRank = 999;//TODO去redis中获取 + let myRank = await getMyRank(REDIS_KEY.PVP_RANK, 0, roleId);//去redis中获取排名 let data = {warId, seasonNum, seasonEndTime, myRank, oppPlayers, heroes, score, pLv, winStreakNum, refOppCnt, challengeCnt, challengeRefTime, receivedBox, hisScore, heroScores, isFirstEntry} return resResult(STATUS.SUCCESS, data); } @@ -59,7 +54,9 @@ export class PvpHandler { let oppPlayers = await refreshEnemies(role, pvpDefense.score, pvpDefense.pLv); pvpDefense = await PvpDefenseModel.updateInfoAndInclude(roleId, { oppPlayers }); - let result = getEnemies(pvpDefense.oppPlayers, pvpDefense.winStreakNum); + let result = await getEnemies(pvpDefense.oppPlayers, pvpDefense.winStreakNum); + + // TODO 刷新次数及消耗 return resResult(STATUS.SUCCESS, { oppPlayers: result, refOppCnt: 0 }); } @@ -146,6 +143,8 @@ export class PvpHandler { let checkHeroes = await checkBattleHeroesByHid(roleId, heroes); if(!checkHeroes) return resResult(STATUS.BATTLE_HERO_NOT_FOUND); + // TODO 检查挑战次数 + const pvpDefense = await PvpDefenseModel.findByRoleId(roleId); if(!pvpDefense) return resResult(STATUS.PVP_NOT_OPEN); let { oppPlayers } = pvpDefense; @@ -256,15 +255,6 @@ export class PvpHandler { const role = await RoleModel.findByRoleId(roleId); let newOppPlayers: Array = await refreshEnemies(role, score, pLv); - pvpDefense = await PvpDefenseModel.updateInfoAndInclude(roleId, { oppPlayers: newOppPlayers, heroScores, score, pLv, winStreakNum }); - let result = getEnemies(pvpDefense.oppPlayers, pvpDefense.winStreakNum); - - - // 更新battleRecord - await BattleRecordModel.updateBattleRecordByCode(battleCode, { - $set: { status: isSuccess?1:2 } - }, true); - let oppRole; if(curOpp.isRobot) { oppRole = { ...curOpp.robot, title: 1, topFiveCe: curOpp.robot.defCe}; @@ -279,9 +269,23 @@ export class PvpHandler { roleId: oppRole.roleId, roleName: oppRole.roleName, lv: oppRole.lv, sHid: oppRole.sHid, headHid: oppRole.headHid, title: oppRole.title, ce: oppRole.topFiveCe, heroes: myHeroRecords, isSuccess: !isSuccess, score: 0 }}) + // 更新battleRecord + await BattleRecordModel.updateBattleRecordByCode(battleCode, { + $set: { status: isSuccess?1:2 } + }, true); + + // TODO 增加挑战次数 + + pvpDefense = await PvpDefenseModel.updateInfoAndInclude(roleId, { oppPlayers: newOppPlayers, heroScores, score, pLv, winStreakNum }); + let result = await getEnemies(pvpDefense.oppPlayers, pvpDefense.winStreakNum); + + // 加入排行榜 + let params = new RankParam(roleName, role.lv, role.vLv, role.headHid, role.sHid, role.title); + await setRank(REDIS_KEY.PVP_RANK, 0, roleId, pvpDefense.score, pvpDefense.updatedAt.getTime(), params); + let myRank = await getMyRank(REDIS_KEY.PVP_RANK, 0, roleId); return resResult(STATUS.SUCCESS, { battleCode, isSuccess, - score, pLv, myRank: 0, + score, pLv, myRank, heroScores: showHeroScores, oppPlayers: result }); @@ -333,5 +337,26 @@ export class PvpHandler { } } + async getRank(msg: {}, session: BackendSession) { + let roleId = session.get('roleId'); + let roleName = session.get('roleName'); + let serverId = session.get('serverId') + + const hasRank = await existsRank(REDIS_KEY.PVP_RANK, serverId); + if(!hasRank) await initRank(serverId); + + let {ranks, myRank} = await getRank(REDIS_KEY.PVP_RANK, 0, roleId); + if(!myRank) { + let pvpDefense = await PvpDefenseModel.findByRoleId(roleId); + let role = await RoleModel.findByRoleId(roleId); + let { lv, vLv, headHid, sHid, title} = role; + let rankRank = new RankParam(roleName, lv, vLv, headHid, sHid, title); + myRank = { + rank: 0, roleId, ...rankRank, num: pvpDefense.score, str: '' + } + } + + return resResult(STATUS.SUCCESS, { ranks: ranks.slice(0, 100), myRank }); + } } diff --git a/game-server/app/servers/battle/handler/towerBattleHandler.ts b/game-server/app/servers/battle/handler/towerBattleHandler.ts index 28e6b630f..9603734db 100644 --- a/game-server/app/servers/battle/handler/towerBattleHandler.ts +++ b/game-server/app/servers/battle/handler/towerBattleHandler.ts @@ -12,6 +12,7 @@ import { calcuHangUpReward, checkTaskConditions, checkHangUpSpdUpCnt, createCurT import { handleFixedReward, addItems, handleCost } from '../../../services/rewardService'; import { checkBattleHeroes } from '../../../services/normalBattleService'; import { getRank, setRank, initRank, existsRank } from '../../../services/redisService'; +import { RankParam } from '../../../pubUtils/interface'; export default function(app: Application) { return new TowerBattleHandler(app); @@ -33,8 +34,9 @@ export class TowerBattleHandler { towerLv = 1; let role = await RoleModel.towerLvUp(roleId); // 更新redis - let { roleName, towerUpTime, lv, vLv } = role; - await setRank(REDIS_KEY.TOWER_RANK, serverId, roleId, towerLv, towerUpTime.getTime(), {roleName, lv, vLv, guildName:"", head: "zhaoyun"}); + let { roleName, towerUpTime, lv, vLv, headHid, sHid, title } = role; + let rankRank = new RankParam(roleName, lv, vLv, headHid, sHid, title); + await setRank(REDIS_KEY.TOWER_RANK, serverId, roleId, towerLv, towerUpTime.getTime(), rankRank); } let towerRec = await TowerRecordModel.getRecordByLv(roleId, towerLv); diff --git a/game-server/app/servers/connector/handler/entryHandler.ts b/game-server/app/servers/connector/handler/entryHandler.ts index 13991b8dc..9e108b5b1 100644 --- a/game-server/app/servers/connector/handler/entryHandler.ts +++ b/game-server/app/servers/connector/handler/entryHandler.ts @@ -85,6 +85,7 @@ export class EntryHandler { let apJson = await getAp(Date.now(), role.roleId); role['apJson'] = apJson; role['ce'] = reduceCe(role.ce); + role['topFiveCe'] = reduceCe(role.topFiveCe); return resResult(STATUS.SUCCESS, { role }); } diff --git a/game-server/app/services/battleService.ts b/game-server/app/services/battleService.ts index 63cc6d66e..685a83827 100644 --- a/game-server/app/services/battleService.ts +++ b/game-server/app/services/battleService.ts @@ -11,6 +11,7 @@ import { STATUS } from '../consts/statusCode'; import { HangUpSpdUpRecModel } from '../db/HangUpSpdUpRec'; import { TowerTaskRecModel } from '../db/TowerTaskRec'; import { setRank } from './redisService'; +import { RankParam } from '../pubUtils/interface'; export async function checkTowerWar(roleId: string, battleId: number, heroes: Array) { const battleIdStr = `${battleId}`; @@ -71,8 +72,9 @@ export async function towerBattleEnd(sid: string, roleId: string, serverId: numb if (inc === 1) { let role = await RoleModel.towerLvUp(roleId); // 更新redis - let { roleName, towerLv, towerUpTime, lv, vLv } = role; - await setRank(REDIS_KEY.TOWER_RANK, serverId, roleId, towerLv, towerUpTime.getTime(), {roleName, lv, vLv, guildName:"", head: "zhaoyun"}); + let { roleName, towerLv, towerUpTime, lv, vLv, headHid, sHid, title } = role; + let rankRank = new RankParam(roleName, lv, vLv, headHid, sHid, title); + await setRank(REDIS_KEY.TOWER_RANK, serverId, roleId, towerLv, towerUpTime.getTime(), rankRank); const nextTowerInfo = getTowerDataByLv(towerLv + 1); if (nextTowerInfo) { diff --git a/game-server/app/services/pvpService.ts b/game-server/app/services/pvpService.ts index 62ca26e09..bb35b2454 100644 --- a/game-server/app/services/pvpService.ts +++ b/game-server/app/services/pvpService.ts @@ -3,14 +3,15 @@ */ import { PvpDefenseModel, Heroes, OppPlayers, Robot, PvpDefenseType, HeroScores } from '../db/PvpDefense'; import { RoleType } from '../db/Role'; -import { PVP_HERO_POS, ROBOT_NAME } from '../consts'; +import { PVP_HERO_POS, ROBOT_NAME, REDIS_KEY } from '../consts'; import { dicPvpOpponent, DicPvpOpponent } from "../pubUtils/dictionary/DicPvpOpponent"; import { getRandomIndexByLen, genCode, getRandomByLen } from '../pubUtils/util'; -import { oppPlayersInter } from '../pubUtils/interface'; +import { oppPlayersInter, RankParam } from '../pubUtils/interface'; import { gameData, getPLvByScore } from "../pubUtils/data"; import { PVP } from '../pubUtils/dicParam'; import { SystemConfigModel } from '../db/SystemConfig' +import { setRank, getMyRank } from './redisService'; const _ = require('underscore'); @@ -33,7 +34,12 @@ export async function initPvpInfo(role: RoleType) { let {warId, seasonNum } = await SystemConfigModel.findSystemConfig(); let challengeCnt = PVP.PVP_CHALLENGE_COUNTS; let result = await PvpDefenseModel.createPvpDefense({ roleId: role.roleId, roleName: role.roleName, role: role._id, heroes, oppPlayers, defCe: role.topFiveCe, seasonNum, warId, challengeCnt }); - //加入排行榜 TODO + + //加入排行榜 + let { roleId, roleName, lv, vLv, headHid, sHid, title } = role; + let params = new RankParam(roleName, lv, vLv, headHid, sHid, title); + await setRank(REDIS_KEY.PVP_RANK, 0, roleId, result.score, result.updatedAt.getTime(), params); + return result; } @@ -51,7 +57,7 @@ export async function checkPvp(role: RoleType) { * @param oppPlayers pvpDefense表中的oppPlayers字段,需要populate过的 * @param pLv 玩家本人的队伍等级 */ -export function getEnemies(oppPlayers: OppPlayers[], winStreakNum: number) { +export async function getEnemies(oppPlayers: OppPlayers[], winStreakNum: number) { let result = new Array(); for(let {pos, isRobot, oppDef, robot} of oppPlayers) { let dicOpponent = dicPvpOpponent.get(pos); @@ -68,10 +74,11 @@ export function getEnemies(oppPlayers: OppPlayers[], winStreakNum: number) { let role = opp.role; let { roleId, roleName, headHid, sHid } = role; let { pLv, defCe } = opp; + let rankLv = await getMyRank(REDIS_KEY.PVP_RANK, 0, roleId); result.push({ pos, roleId, roleName, headHid, sHid, pLv, defCe, addScore: dicOpponent.score, - rankLv: 0, // TODO读取排名 + rankLv, // 读取排名 plusScore: getPlusScore(winStreakNum) }); } @@ -108,7 +115,9 @@ async function matchPlayer(oppPlayers: OppPlayers[], roleId: string, pLv: number let result = range[index]; if(!result) return false; if(result.roleId == roleId) { + console.log(range.length) range.splice(index, 1); + console.log(JSON.stringify(range)) if(range.length <= 0) return false; index = getRandomIndexByLen(range.length); result = range[index]; diff --git a/game-server/app/services/redisService.ts b/game-server/app/services/redisService.ts index 936a12bce..208f23bd4 100644 --- a/game-server/app/services/redisService.ts +++ b/game-server/app/services/redisService.ts @@ -1,10 +1,12 @@ import { GOOD_QUALITY } from './../consts'; -import { RoleModel } from "../db/Role"; +import { RoleModel, RoleType } from "../db/Role"; import * as Redis from 'redis'; import {REDIS_KEY} from '../consts' import { GameModel } from "../db/Game"; import { promisifyAll } from 'bluebird'; import { pinus } from 'pinus'; +import { PvpDefenseModel } from '../db/PvpDefense'; +import { RankParam } from '../pubUtils/interface'; /** * 在服务重新启动时,将信息存入redis @@ -13,6 +15,7 @@ export async function initAllRank() { const client: Redis.RedisClient = pinus.app.get('redis'); const serverList = await GameModel.getAllServerList(); await client.delAsync(REDIS_KEY.USER_INFO); + await client.delAsync(REDIS_KEY.PVP_RANK); for(let {id} of serverList) { await client.delAsync(getKeyName(REDIS_KEY.TOWER_RANK, id)); await initRank(id); @@ -23,13 +26,27 @@ export async function initRank(serverId: number) { // console.log('*****', 'initRank') const client: Redis.RedisClient = pinus.app.get('redis'); await client.expireAsync(getKeyName(REDIS_KEY.TOWER_RANK, serverId), 30 * 24 * 60 * 60); + await client.expireAsync(REDIS_KEY.PVP_RANK, 30 * 24 * 60 * 60); await client.expireAsync(REDIS_KEY.USER_INFO, 30 * 24 * 60 * 60); - let ranks = await RoleModel.getRank('tower', serverId, ['roleId', 'roleName', 'towerLv', 'lv', 'vLv']); - for(let {towerLv, roleId, roleName, lv, vLv, towerUpTime} of ranks) { + let ranks = await RoleModel.getRank('tower', serverId, ['roleId', 'roleName', 'towerLv', 'lv', 'vLv', 'headHid', 'sHid', 'title', 'updatedAt']); + for(let {towerLv, roleId, roleName, lv, vLv, towerUpTime, headHid, sHid, title} of ranks) { // console.log(roleId); await client.zaddAsync(getKeyName(REDIS_KEY.TOWER_RANK, serverId), encodeScoreWithTime(towerLv, towerUpTime?towerUpTime.getTime():0), roleId); - await redisUserInfoAdd(roleId, {roleName, lv, vLv, guildName:"", head: "zhaoyun"}); + let rankPram = new RankParam(roleName, lv, vLv, headHid, sHid, title); + await redisUserInfoAdd(roleId, rankPram); + } + let pvpRank = await PvpDefenseModel.getRank(); + for(let {roleId, role: _role, score, updatedAt } of pvpRank) { + let role = _role; + let { roleName, headHid, sHid, title, lv, vLv } = role; + await client.zaddAsync(getKeyName(REDIS_KEY.PVP_RANK), encodeScoreWithTime(score, updatedAt?updatedAt.getTime():0), roleId); + + const hasCurUser = await client.hexistsAsync(REDIS_KEY.USER_INFO, roleId); + if(!hasCurUser) { + let rankPram = new RankParam(roleName, lv, vLv, headHid, sHid, title); + await redisUserInfoAdd(roleId, rankPram); + } } } @@ -40,8 +57,12 @@ export async function existsRank(key: string, serverId: number) { return result; } -export function getKeyName(key: string, serverId: number) { - return `${key}:${serverId}`; +export function getKeyName(key: string, serverId?: number) { + if(serverId) { + return `${key}:${serverId}`; + } else { + return key; + } } // 更新玩家信息 @@ -58,21 +79,21 @@ export async function redisUserInfoUpdate(roleId: string, arr: Array<{field: str } // 添加玩家信息缓存 -export async function redisUserInfoAdd(roleId: string, params: {roleName: string, lv: number, vLv: number, guildName: string, head: string}) { +export async function redisUserInfoAdd(roleId: string, params: RankParam) { const client: Redis.RedisClient = pinus.app.get('redis'); let value = JSON.stringify(params); return await client.hsetAsync(REDIS_KEY.USER_INFO, roleId, value); } -// 更新排行榜 -export async function setRank(key: string, serverId: number, roleId: string, score: number, timestamp: number, params: {roleName: string, lv: number, vLv: number, guildName: string, head: string}) { +// 更新排行榜, 如pvp这样跨服的,serverId传0 +export async function setRank(key: string, serverId: number, roleId: string, score: number, timestamp: number, params: RankParam, limit = 100) { const client: Redis.RedisClient = pinus.app.get('redis'); // 更新分数 const _score = encodeScoreWithTime(score, timestamp); await client.zaddAsync(getKeyName(key, serverId), _score, roleId); // 移除100名以外 - await client.zremrangebyrankAsync(getKeyName(key, serverId), 100, 10000); + await client.zremrangebyrankAsync(getKeyName(key, serverId), limit, 10000); // 如果没有信息,更新玩家信息 const hasCurUser = await client.hexistsAsync(REDIS_KEY.USER_INFO, roleId); if(!hasCurUser) { @@ -99,16 +120,23 @@ export async function getRank(key: string, serverId: number, roleId: string) { return {ranks, myRank} } +// 获取我的排名 +export async function getMyRank(key: string, serverId: number, roleId: string) { + const client: Redis.RedisClient = pinus.app.get('redis'); + let myRank = await client.zrevrankAsync(getKeyName(key, serverId), roleId); + return myRank + 1; +} + // 有序排行综合时间和得分排序 function encodeScoreWithTime(score: number, timestamp: number): number { // value = score * Math.power(10, 14) + max_time - timestamp - let timelen = 13; + let timelen = 10; let pow = Math.pow(10, timelen + 1); - return score * pow + pow - 1 - timestamp + return score * pow + pow - 1 - Math.floor(timestamp/1000) } function decodeScoreWithTime(num: string): number { - let timelen = 13; + let timelen = 10; let pow = Math.pow(10, timelen + 1); let _num = parseInt(num); return Math.floor(_num/pow); @@ -184,7 +212,7 @@ export async function checkRoleInQueue(roleId: string, sid: string, qualityArr: export async function clearComBtlQueue() { const client: Redis.RedisClient = pinus.app.get('redis'); for (let q of GOOD_QUALITY) { - client.delAsync(`${REDIS_KEY.COM_TEAM_SEARCH_PRE}${q}`); + await client.delAsync(`${REDIS_KEY.COM_TEAM_SEARCH_PRE}${q}`); } } diff --git a/game-server/config/redis.ts b/game-server/config/redis.ts index 234a16b14..74eef8e25 100644 --- a/game-server/config/redis.ts +++ b/game-server/config/redis.ts @@ -17,6 +17,8 @@ declare module 'redis' { hsetAsync(key: string, field: string, value: string): Promise; // 获取存储在哈希表中指定字段的值 hgetAsync(key: string, field: string): Promise; + // 获取存储在哈希表中指定字段的值。 + hexistsAsync(key: string, field: string): Promise; // 移除并返回集合中的一个随机元素 spopAsync(key: string, count?: number): Promise; @@ -35,8 +37,10 @@ declare module 'redis' { zcardAsync(key: string): Promise; // 移除有序集合中给定的排名区间的所有成员 zremrangebyrankAsync(key: string, start: number, stop: number): Promise; - // 获取存储在哈希表中指定字段的值。 - hexistsAsync(key: string, field: string): Promise; + // 返回有序集中指定成员的排名,从小到大 + zrankAsync(key: string, field: string): Promise; + // 返回有序集中指定成员的排名,从大到小 + zrevrankAsync(key: string, field: string): Promise; } export interface Multi extends Commands { execAsync(...args: any[]): Promise; diff --git a/shared/consts/constModules/sysConst.ts b/shared/consts/constModules/sysConst.ts index 90a43eeba..94d9c4b74 100644 --- a/shared/consts/constModules/sysConst.ts +++ b/shared/consts/constModules/sysConst.ts @@ -220,6 +220,7 @@ export const REDIS_KEY = { USER_INFO: "userInfo", // 玩家缓存信息 TOWER_RANK: "towerRank", // 天梯排行榜 COM_TEAM_SEARCH_PRE: 'comTeamSerQ', // 匹配中的玩家,按品质分 + PVP_RANK: "pvpRank", // pvp排行榜 } export const FUNC_OPT_TYPE = { diff --git a/shared/consts/consts.ts b/shared/consts/consts.ts index cd708c66d..996798a26 100644 --- a/shared/consts/consts.ts +++ b/shared/consts/consts.ts @@ -321,6 +321,7 @@ export const REDIS_KEY = { USER_INFO: "userInfo", // 玩家缓存信息 TOWER_RANK: "towerRank", // 天梯排行榜 COM_TEAM_SEARCH_PRE: 'comTeamSerQ', // 匹配中的玩家,按品质分 + PVP_RANK: 'pvpRank' } export const FUNC_OPT_TYPE = { diff --git a/shared/db/PvpDefense.ts b/shared/db/PvpDefense.ts index 8666274c2..a641a3f25 100644 --- a/shared/db/PvpDefense.ts +++ b/shared/db/PvpDefense.ts @@ -226,6 +226,14 @@ export default class PvpDefense extends BaseModel { let result: Array = await PvpDefenseModel.find().sort({ score: -1 }).limit(limitNum).lean(lean); return result; } + + public static async getRank(page = 1, limit = 1000, lean = true) { + let sortBy = { score: -1, updatedAt: 1 }; + const ranks: PvpDefenseType[] = await PvpDefenseModel.find().limit(limit).skip(page - 1).select('roleId role score updatedAt') + .populate('role', 'roleId roleName headHid sHid title lv vLv') + .sort(sortBy).limit(limit).skip((page - 1) * limit).lean(lean); + return ranks; + } } export const PvpDefenseModel = getModelForClass(PvpDefense); diff --git a/shared/pubUtils/interface.ts b/shared/pubUtils/interface.ts index 5bbcb0e3b..73183843d 100644 --- a/shared/pubUtils/interface.ts +++ b/shared/pubUtils/interface.ts @@ -95,4 +95,24 @@ export interface pvpEndParamInter { damage: number; heal: number; underDamage: number; +} + +export class RankParam { + roleName: string; + lv: number; + vLv: number; + guildName: string = ""; + head: string = 'zhaoyun'; + headHid: number = 19; + sHid: number = 19; + title: number; + + constructor(roleName: string, lv: number, vLv: number, headHid: number, sHid: number, title: number) { + this.roleName = roleName; + this.lv = lv; + this.vLv = vLv; + this.headHid = headHid; + this.sHid = sHid; + this.title = title; + } } \ No newline at end of file