diff --git a/game-server/app/servers/role/handler/friendHandler.ts b/game-server/app/servers/role/handler/friendHandler.ts index a6ede464f..a9510aa93 100644 --- a/game-server/app/servers/role/handler/friendHandler.ts +++ b/game-server/app/servers/role/handler/friendHandler.ts @@ -1,13 +1,15 @@ import { Application, BackendSession } from "pinus"; -import { resResult, getRandEelm } from "../../../pubUtils/util"; -import { STATUS, ROLE } from "../../../consts"; -import Role, { RoleModel, RoleType } from "../../../db/Role"; +import { resResult, getRandEelm, getResStr } from "../../../pubUtils/util"; +import { STATUS, ROLE, FRIEND_DROP_TYPE, FRIEND_RELATION_TYPE } from "../../../consts"; +import { RoleModel, RoleType } from "../../../db/Role"; import { getBeforeDaySeconds } from "../../../pubUtils/timeUtil"; import { FriendApplyModel } from "../../../db/FriendApply"; -import { FriendApplyParams, FriendListParam } from "../../../domain/roleField/friend"; +import { FriendApplyParams, FriendListParam, FriendRecommendParams } from "../../../domain/roleField/friend"; import { FriendShipModel, FriendShipType } from "../../../db/FriendShip"; import { FriendRelationModel } from "../../../db/FriendRelation"; import { isRoleOnline } from "../../../services/redisService"; +import { increaseFrdCnt, getRecommendType } from "../../../services/friendService"; +import { FriendPointModel } from "../../../db/FriendPoint"; export default function (app: Application) { return new FriendHandler(app); @@ -25,9 +27,41 @@ export class FriendHandler { const day = getBeforeDaySeconds(1); const { lv } = await RoleModel.findByRoleId(roleId, ROLE.GET_LV); - const allList = await RoleModel.getRecommedList(roleId, lv - 5, lv + 5, day); - let list = getRandEelm(allList, 10); - if(!list.length) list = allList; + let allList = await RoleModel.getRecommedList(lv - 5, lv + 5, day); + + let myFriendRelation = await FriendRelationModel.findFriendByRole(roleId, false); + + let paramAllList = new Array(); + for(let role of allList) { + let type = getRecommendType(myFriendRelation, roleId, role.roleId); + if(type == FRIEND_RELATION_TYPE.NORMAL) { + let param = new FriendRecommendParams(role); + param.setType(type); + paramAllList.push(param); + } + } + + let list = getRandEelm(paramAllList, 6); + if(!list.length) list = paramAllList; + + return resResult(STATUS.SUCCESS, { list }); + } + + // 搜索好友 + public async searchUser(msg: { value: string }, session: BackendSession) { + let roleId: string = session.get('roleId'); + + let { value } = msg; + let allList = await RoleModel.searchByNameOrId(value); + let myFriendRelation = await FriendRelationModel.findFriendByRole(roleId, false); + + let list = new Array(); + for(let role of allList) { + let type = getRecommendType(myFriendRelation, roleId, role.roleId); + let param = new FriendRecommendParams(role); + param.setType(type); + list.push(param); + } return resResult(STATUS.SUCCESS, { list }); } @@ -39,18 +73,38 @@ export class FriendHandler { let roleIds = msg.roleIds; const role = await RoleModel.findByRoleId(roleId, ROLE.GET_ROLE_ID); + let myFriendRelation = await FriendRelationModel.findFriendByRole(roleId, false); + + let str = '', resultRoleIds = new Array(); for(let hisRoleId of roleIds) { + let type = getRecommendType(myFriendRelation, roleId, hisRoleId); + if(type == FRIEND_RELATION_TYPE.HAS_FRIEND) { + str = getResStr(STATUS.FRIEND_HAS_ADD); continue; + } else if(type == FRIEND_RELATION_TYPE.HAS_BLOCKED) { + str = getResStr(STATUS.FRIEND_HAS_BLOCKED); continue; + } else if (type == FRIEND_RELATION_TYPE.MYSELF) { + str = getResStr(STATUS.FRIEND_YOURSELF); continue; + } + + let incResult = await RoleModel.increaseFriendApplyCnt(hisRoleId, 1, 50); + if(!incResult) { + str = getResStr(STATUS.FRIEND_HIS_APPLY_MAX); continue; + } + await FriendApplyModel.createApply(hisRoleId, role); + resultRoleIds.push(hisRoleId); } return resResult(STATUS.SUCCESS, { - isSuccess: true + isSuccess: str == '', + msg: str, + roleIds: resultRoleIds }); } // 获取申请列表 - public async getApplyList(msg: { lastApplyCode: string }, session: BackendSession) { - // TODO 分页 + public async getApplyList(msg: { }, session: BackendSession) { + let roleId: string = session.get('roleId'); let list = await FriendApplyModel.getApplyList(roleId); @@ -72,28 +126,58 @@ export class FriendHandler { let { applyCodeList, isPass } = msg; let role = await RoleModel.findByRoleId(roleId); + let friendCnt = role.friendCnt; + + let myFriendRelation = await FriendRelationModel.findFriendByRole(roleId, false); let applyList = await FriendApplyModel.getApplyListByCode(applyCodeList); - let result = new Array(); + let list = new Array(); + + let str = '', resultApplyCodeList = new Array(); if(isPass) { for(let apply of applyList) { + let type = getRecommendType(myFriendRelation, roleId, apply.frdRoleId); + if(type == FRIEND_RELATION_TYPE.HAS_FRIEND) { + str = getResStr(STATUS.FRIEND_HAS_ADD); continue; + } else if(type == FRIEND_RELATION_TYPE.HAS_BLOCKED) { + str = getResStr(STATUS.FRIEND_HAS_BLOCKED); continue; + } else if (type == FRIEND_RELATION_TYPE.MYSELF) { + str = getResStr(STATUS.FRIEND_YOURSELF); continue; + } + + // 好友数量校验 let friend = apply.friend; - // TODO检查我的好友人数上限,检查加过好友没有 - // TODO检查对方的好友人数上限 + str = await increaseFrdCnt(role, friend, friendCnt); + if(str != '') continue; + // 创建friendShip let friendShip = await FriendShipModel.createFriendShip([roleId, friend.roleId]); - if(!friendShip) continue; - // 创建或push我的好友relation - let result1 = await FriendRelationModel.addFriend(roleId, friend, friendShip); - // 创建或push他的好友relation - let result2 = await FriendRelationModel.addFriend(friend.roleId, role, friendShip); + if(!friendShip) { + str = getResStr(STATUS.FRIEND_SHIP_CREATE_ERROR); continue; + } + + await FriendRelationModel.addFriend(roleId, friend, friendShip); + await FriendRelationModel.addFriend(friend.roleId, role, friendShip); + + let param = new FriendListParam(friend, friendShip); + let isOnline = await isRoleOnline(friend.roleId); + param.setOnline(isOnline); + + list.push(param); + resultApplyCodeList.push(apply.applyCode); } + } else { + resultApplyCodeList = applyCodeList; } - // await FriendApplyModel.deleteApply(applyCodeList); + await FriendApplyModel.deleteApply(resultApplyCodeList); return resResult(STATUS.SUCCESS, { - list: result + isSuccess: str == '', + msg: str, + applyCodeList: resultApplyCodeList, + list, + friendCnt }); } @@ -127,9 +211,12 @@ export class FriendHandler { } let { friendCnt = 0, blockCnt = 0 } = role; + let frdPointRec = await FriendPointModel.getFrdPointRecToday(roleId, FRIEND_DROP_TYPE.SEND_GIFT); + let { cnt: todayReceiveCnt = 0, sendCnt: todaySendCnt = 0 } = frdPointRec||{}; + return resResult(STATUS.SUCCESS, { - todayReceiveCnt: 0, - todaySendCnt: 0, + todayReceiveCnt, + todaySendCnt, list, friendCnt, blockCnt }); diff --git a/game-server/app/services/friendService.ts b/game-server/app/services/friendService.ts new file mode 100644 index 000000000..74350687d --- /dev/null +++ b/game-server/app/services/friendService.ts @@ -0,0 +1,51 @@ +import { gameData } from "../pubUtils/data"; +import { RoleType, RoleModel } from "../db/Role"; +import { FriendRelationType } from "../db/FriendRelation"; +import { getResStr } from "../pubUtils/util"; +import { STATUS, FRIEND_RELATION_TYPE } from "../consts"; + +/** + * 增加双方好友数 + * @param role1 我方 + * @param role2 对方 + * @returns 是否添加成功 + */ +export async function increaseFrdCnt(role1: RoleType, role2: RoleType, originalFriendCnt: number) { + + let { roleId, lv, friendCnt } = role1; + let dicFriend = gameData.roleFriend.get(lv); + + if(friendCnt >= dicFriend.frdCnt) return getResStr(STATUS.FRIEND_MY_CNT_MAX); + + let { roleId: _roleId, lv: _lv, friendCnt: _friendCnt } = role2; + let _dicFriend = gameData.roleFriend.get(_lv); + if(_friendCnt >= _dicFriend.frdCnt) return getResStr(STATUS.FRIEND_THEY_CNT_MAX); + + let incMyFrdCnt = await RoleModel.increaseFriendCnt(roleId, 1, dicFriend.frdCnt); + if(!incMyFrdCnt) return getResStr(STATUS.FRIEND_MY_CNT_MAX); + let incHisFrdCnt = await RoleModel.increaseFriendCnt(_roleId, 1, _dicFriend.frdCnt); + if(!incHisFrdCnt) { // 回滚 + await RoleModel.increaseFriendCnt(roleId, -1, dicFriend.frdCnt); + return getResStr(STATUS.FRIEND_THEY_CNT_MAX); + } + originalFriendCnt = incMyFrdCnt.friendCnt; + + return ''; +} + +export function getRecommendType(myFriendRelation: FriendRelationType, myRoleId: string, roleId: string) { + if(myRoleId == roleId) { + return FRIEND_RELATION_TYPE.MYSELF; + } + let friendList = myFriendRelation? myFriendRelation.friends: []; + let blackList = myFriendRelation? myFriendRelation.blacklist: []; + let hasFriend = friendList.find(cur => cur.roleId == roleId); + if(hasFriend) { + return FRIEND_RELATION_TYPE.HAS_FRIEND; + } + let hasBlcklist = blackList.find(cur => cur.roleId == roleId); + if(hasBlcklist) { + return FRIEND_RELATION_TYPE.HAS_BLOCKED; + } + return FRIEND_RELATION_TYPE.NORMAL; +} \ No newline at end of file diff --git a/shared/consts/constModules/selectConst.ts b/shared/consts/constModules/selectConst.ts index 09d1f54e8..10e25d687 100644 --- a/shared/consts/constModules/selectConst.ts +++ b/shared/consts/constModules/selectConst.ts @@ -2,6 +2,7 @@ export enum ROLE { // 玩家列表显示基础数据 SHOW_SIMPLE = 'roleId roleName ce headHid sHid lv title job quitTime vLv guildName', + SHOW_FRIEND_APPLY_LIST = 'roleId roleName ce headHid sHid lv title job quitTime vLv guildName friendCnt recFrdApplyCnt', HANDLE_APPLY = 'roleId friendCnt lv', GET_LV = 'lv', diff --git a/shared/consts/constModules/sysConst.ts b/shared/consts/constModules/sysConst.ts index c923bedae..6d0962ec7 100644 --- a/shared/consts/constModules/sysConst.ts +++ b/shared/consts/constModules/sysConst.ts @@ -243,7 +243,8 @@ export const FUNCS_ID = { } export const FRIEND_DROP_TYPE = { - COM_BATTLE: 1 + COM_BATTLE: 1, + SEND_GIFT: 2 } // 每日情谊点上限 @@ -362,3 +363,10 @@ export const MAIL_TYPE = { }; export const CHAT_SERVER = 'chat-server-1'; + +export enum FRIEND_RELATION_TYPE { + NORMAL = 1, + HAS_FRIEND = 2, + HAS_BLOCKED = 3, + MYSELF = 4 +} \ No newline at end of file diff --git a/shared/consts/statusCode.ts b/shared/consts/statusCode.ts index e567e4df2..7eeef5bb1 100644 --- a/shared/consts/statusCode.ts +++ b/shared/consts/statusCode.ts @@ -231,7 +231,7 @@ export const STATUS = { EQUIP_NOT_EQUIPED_HERO: { code: 30509, simStr: '装备不能被该武将穿戴' }, EQUIP_LEVEL_LIMIT: { code: 30510, simStr: '装备穿戴等级限制' }, EQUIP_NOT_MATCH_JEWEL: { code: 30511, simStr: '装备不能镶嵌该宝石' }, - //全局养成30600-30799 + //全局养成30600-30699 ROLE_REACH_MAX_TITLE_LEVEL: { code: 30600, simStr: '玩家已达到最高的爵位' }, ROLE_TERAPH_NOT_STRENGTHEN: { code: 30601, simStr: '玩家神像不能强化' }, ROLE_TERAPH_NOT_QUILITY: { code: 30602, simStr: '玩家神像不能进阶' }, @@ -241,6 +241,14 @@ export const STATUS = { ROLE_SCHOOL_POSITION_UNLOCK_NOT_NEED: { code: 30605, simStr: '该位置已解锁' }, ROLE_SCROLL_REACH_MAX: { code: 30606, simStr: '已经升到可以升的最高等级' }, + // 好友30700-30799 + FRIEND_MY_CNT_MAX: { code: 30700, simStr: '好友数量已达上限' }, + FRIEND_THEY_CNT_MAX: { code: 30701, simStr: '玩家好友已满' }, + FRIEND_HAS_ADD: { code: 30702, simStr: '该玩家已是您的好友' }, + FRIEND_HAS_BLOCKED: { code: 30703, simStr: '该玩家在您的黑名单' }, + FRIEND_YOURSELF: { code: 30704, simStr: '不能添加自己为好友' }, + FRIEND_HIS_APPLY_MAX: { code: 30705, simStr: '该玩家申请达上限' }, + FRIEND_SHIP_CREATE_ERROR: { code: 30706, simStr: '创建失败' }, // 社交相关状态 40000 - 49999 diff --git a/shared/db/FriendApply.ts b/shared/db/FriendApply.ts index 8e80a9c30..4144b0769 100644 --- a/shared/db/FriendApply.ts +++ b/shared/db/FriendApply.ts @@ -37,7 +37,7 @@ export default class FriendApply extends BaseModel { public static async getApplyList(roleId: string) { const list: FriendApplyType[] = await FriendApplyModel.find({ roleId }, { _id: 0 }) // .select(select) - .populate('friend', ROLE.SHOW_SIMPLE, 'Role') + .populate('friend', ROLE.SHOW_FRIEND_APPLY_LIST, 'Role') .lean({ getters: true }); return list; } @@ -46,7 +46,7 @@ export default class FriendApply extends BaseModel { public static async getApplyListByCode(applyCodeList: string[]) { const list: FriendApplyType[] = await FriendApplyModel.find({ applyCode: { $in: applyCodeList } }, { _id: 0 }) // .select(select) - .populate('friend', ROLE.SHOW_SIMPLE, 'Role') + .populate('friend', ROLE.SHOW_FRIEND_APPLY_LIST, 'Role') .lean({ getters: true }); return list; } diff --git a/shared/db/FriendPoint.ts b/shared/db/FriendPoint.ts index 5bef855da..b1d1b8de8 100644 --- a/shared/db/FriendPoint.ts +++ b/shared/db/FriendPoint.ts @@ -14,6 +14,8 @@ export default class FriendPoint extends BaseModel { @prop({ required: true, default: 0 }) cnt: number; // 当天获取的点数 @prop({ required: true, default: 0 }) + sendCnt: number; // 当天赠送的点数 + @prop({ required: true, default: 0 }) type: number; // 情谊点统计的类型,不同功能都可能有每日获取上限 /** diff --git a/shared/db/FriendRelation.ts b/shared/db/FriendRelation.ts index 273d9b39f..0f50506e3 100644 --- a/shared/db/FriendRelation.ts +++ b/shared/db/FriendRelation.ts @@ -41,12 +41,17 @@ export default class FriendRelation extends BaseModel { // 获取列表 - public static async findFriendByRole(roleId: string) { - const result: FriendRelationType = await FriendRelationModel.findOne({ roleId }) - .populate('friends.role', ROLE.SHOW_SIMPLE, 'Role') - .populate('friends.friendShip', null, 'FriendShip') + public static async findFriendByRole(roleId: string, populate = true) { + let document = FriendRelationModel.findOne({ roleId }) .lean({ getters: true, virtuals: true }); + if (populate) { + document + .populate('friends.role', ROLE.SHOW_SIMPLE, 'Role') + .populate('friends.friendShip', null, 'FriendShip'); + } + + let result: FriendRelationType = await document; return result; } diff --git a/shared/db/FriendShip.ts b/shared/db/FriendShip.ts index ce492ac55..763b3c2a7 100644 --- a/shared/db/FriendShip.ts +++ b/shared/db/FriendShip.ts @@ -79,6 +79,7 @@ export default class FriendShip extends BaseModel { return result; } + // 查询关系 public static async deleteAccount(roleId: string) { let result = await FriendShipModel.deleteMany({ $or: [{ roleIdA: roleId }, { roleIdB: roleId }] }); return result; diff --git a/shared/db/Role.ts b/shared/db/Role.ts index 3bef209b7..702bc9a40 100644 --- a/shared/db/Role.ts +++ b/shared/db/Role.ts @@ -222,6 +222,8 @@ export default class Role extends BaseModel { friendCnt: number; // 好友人数 @prop({ required: true, default: 0 }) blockCnt: number; // 黑名单人数 + @prop({ required: true, default: 0 }) + recFrdApplyCnt: number; // 玩家收取好友申请数量 public static async findAllByUid(uid: number, lean = true) { const role: RoleType[] = await RoleModel.find({ 'userInfo.uid': uid }).select('roleId roleName serverId').lean(lean); @@ -445,11 +447,25 @@ export default class Role extends BaseModel { } // 获取好友推荐列表 - public static async getRecommedList(roleId: string, minLv: number, maxLv: number, time: number) { - const result = await RoleModel.find({ loginTime: { $gt: time }, lv: { $gte: minLv, $lte: maxLv }, roleId: { $ne: roleId } }, { _id: 0 }) - .select(ROLE.SHOW_SIMPLE) + public static async getRecommedList(minLv: number, maxLv: number, time: number) { + const result = await RoleModel.find({ loginTime: { $gt: time }, lv: { $gte: minLv, $lte: maxLv } }, { _id: 0 }) + .select(ROLE.SHOW_FRIEND_APPLY_LIST) .sort({quitTime: -1, lv: -1, ce: -1}) - .limit(100).lean({ getters: true }); + .limit(200).lean({ getters: true }); + return result; + } + + // 查询玩家 + public static async searchByNameOrId(value: string) { + const result = await RoleModel.find({ + $or: [ + { roleName: { $regex: new RegExp(value.toString(), 'i') } }, + { roleId: value } + ] + }, { _id: 0 }) + .select(ROLE.SHOW_FRIEND_APPLY_LIST) + .sort({quitTime: -1, lv: -1, ce: -1}) + .limit(200).lean({ getters: true }); return result; } @@ -467,7 +483,13 @@ export default class Role extends BaseModel { // 增加好友数量 public static async increaseFriendCnt(roleId: string, inc: number, max: number) { - const result = await RoleModel.findOneAndUpdate({ roleId, friendCnt: {$lt: max}}, {$inc: { friendCnt: inc }}, {new: true}).lean(); + const result = await RoleModel.findOneAndUpdate({ roleId, friendCnt: {$lte: max - inc}}, {$inc: { friendCnt: inc }}, {new: true}).lean(); + return result; + } + + // 增加好友申请数量 + public static async increaseFriendApplyCnt(roleId: string, inc: number, max: number) { + const result = await RoleModel.findOneAndUpdate({ roleId, recFrdApplyCnt: {$lte: max - inc}}, {$inc: { recFrdApplyCnt: inc }}, {new: true}).lean(); return result; } } diff --git a/shared/domain/roleField/friend.ts b/shared/domain/roleField/friend.ts index 047558152..f22bb0156 100644 --- a/shared/domain/roleField/friend.ts +++ b/shared/domain/roleField/friend.ts @@ -21,11 +21,30 @@ export class FriendParams { } } +export class FriendRecommendParams extends FriendParams { + friendCnt: number = 0; + recFrdApplyCnt: number = 0; + type: number; + + constructor(role: RoleType) { + super(role); + if(role.friendCnt) this.friendCnt = role.friendCnt; + if(role.recFrdApplyCnt) this.recFrdApplyCnt = role.recFrdApplyCnt; + } + + setType(type: number) { + this.type = type; + } +} + export class FriendApplyParams extends FriendParams { applyCode: string; + friendCnt: number = 0; + constructor(applyCode: string, role: RoleType) { super(role); this.applyCode = applyCode; + if(role.friendCnt) this.friendCnt = role.friendCnt; } } @@ -35,8 +54,8 @@ export class FriendListParam extends FriendParams { quitTime: number = 0; friendValue: number = 0; friendLv: number = 1; - canReceive: boolean = false; - canSend: boolean = false; + canReceive: boolean = false; // 初始没人送肯定不能领取 + canSend: boolean = true; // 初始可以赠送 constructor(role: RoleType, friendship: FriendShipType) { super(role); diff --git a/shared/pubUtils/util.ts b/shared/pubUtils/util.ts index 46a600da5..256d99c4f 100644 --- a/shared/pubUtils/util.ts +++ b/shared/pubUtils/util.ts @@ -324,6 +324,10 @@ export function resResult(status: { code: number, simStr: string }, data = null, return { code, msg: customMsg || simStr, data }; } +export function getResStr(status: { code: number, simStr: string }) { + return status.simStr; +} + // 消除 js 浮点计算bug export const cal = {