hxp
2021-11-17 ffa8a645ed6a92a3c723bbf5c7f1eb4d5425c826
9341 【BT5】【主干】【后端】情缘系统(优化情缘系统)

# Conflicts:
# ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py
# ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldProcess.py
# ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py
# ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
# ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
29个文件已修改
2个文件已删除
4个文件已添加
2874 ■■■■ 已修改文件
PySysDB/PySysDBG.h 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
PySysDB/PySysDBPY.h 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/PyNetPack.ini 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py 88 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/BillboardData.py 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/Charm.py 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/Couple.py 128 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/Friend.py 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/GameWorld.py 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/Player/ChPlayer.py 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerBillboard.py 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerCharm.py 299 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerControl.py 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerEventCounter.py 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFriend.py 30 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerLove.py 756 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerSocial.py 338 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerTalk.py 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/PyDataManager.py 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/PyGameDataStruct.py 279 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py 88 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Event/EventSrc/FunctionNPCCommon.py 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Love.py 100 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/LoveRing.py 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py 33 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py 26 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerLove.py 253 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerTalk.py 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerViewCacheTube.py 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
PySysDB/PySysDBG.h
@@ -862,11 +862,24 @@
    dict        Award;    //奖励 {"职业":[[物品ID,个数,是否绑定],...], ...}
};
//情缘礼物表
struct tagLoveGift
{
    BYTE        _GiftNum;    //聘礼ID
    DWORD        AddCharmSelf;    //单个增加自身魅力
    DWORD        AddCharmTag;    //单个增加对方魅力
    DWORD        AddIntimacy;    //单个增加双方亲密度
    char        WorldNotifyKey;    //广播key
};
//情缘提亲表
struct tagMarry
{
    BYTE        _BridePriceID;    //聘礼ID
    BYTE        CanBuyCount;    //可购买次数
    BYTE        IsDayReset;    //是否每日重置
    DWORD        Prosperity;    //初始繁荣度
    WORD        CandyTimes;    //喜糖持续时间秒
    list        CandyItemInfo;    //喜糖物品列表[[物品ID,个数,是否拍品], ...]
PySysDB/PySysDBPY.h
@@ -2423,14 +2423,21 @@
    BYTE        _QualityLV;    //品级
};
//情缘礼物表
struct tagLoveGift
{
    BYTE        _GiftNum;    //聘礼ID
    DWORD        GiftItemID;    //物品ID
    BYTE        AllowBatch;    //是否允许批量赠送
};
//情缘提亲表
struct tagMarry
{
    BYTE        _BridePriceID;    //聘礼ID
    list        CostMoneyInfo;    //消耗货币类型|数值
    BYTE        CanBuyCount;    //可购买次数
    BYTE        IsDayReset;    //是否每日重置
};
//情缘情戒表
ServerPython/CoreServerGroup/GameServer/PyNetPack.ini
@@ -458,6 +458,17 @@
PacketSubCMD_2=0x16
PacketCallFunc_2=OnMarryBreakResponse
[PlayerCharm]
ScriptName = GameWorldLogic\PlayerCharm.py
Writer = hxp
Releaser = hxp
RegType = 0
RegisterPackCount = 1
PacketCMD_1=0xB3
PacketSubCMD_1=0x09
PacketCallFunc_1=OnCharmOfferBillboardQuery
[PlayerTalk]
ScriptName = Player\PlayerTalk.py
Writer = alee
ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py
@@ -592,7 +592,8 @@
            
            ShareDefine.Def_BT_Arena                    : 1000,          #竞技场榜
            ShareDefine.Def_BT_Environment              : 20,            #环保榜 (垃圾分类活动)
            ShareDefine.Def_BT_Charm                    : 100,           #魅力总榜
            ShareDefine.Def_BT_CharmTotal               : 100,           #魅力总榜
            ShareDefine.Def_BT_CharmWeek                : 100,           #魅力周榜
            ShareDefine.Def_BT_CharmDay                 : 100,           #魅力日榜
            }
@@ -754,13 +755,14 @@
Def_Online = 1
Def_OnlineNoClient = 2
# 分组 1 最近联系人 2 好友 3 仇人 4 黑名单
# 分组 1 最近联系人 2 好友 3 仇人 4 黑名单 5 亲密
(
Def_SocialGroup_Contacts,
Def_SocialGroup_Friend,
Def_SocialGroup_Enemy,
Def_SocialGroup_Black,
) = range(1, 5)
Def_SocialGroup_Intimacy,
) = range(1, 6)
Def_CDBPlayerRefresh_Online = "OnlineType"
ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py
@@ -2330,6 +2330,66 @@
#------------------------------------------------------
# B3 09 魅力贡献榜查看 #tagCGCharmOfferBillboardQuery
class  tagCGCharmOfferBillboardQuery(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("PlayerID", c_int),    # 魅力玩家ID
                  ("QueryType", c_ubyte),    # 查看类型: 1-总榜,2-周榜,3-日榜
                  ("QueryCount", c_ubyte),    # 查看名次数量,最大255
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0xB3
        self.SubCmd = 0x09
        return
    def ReadData(self, stringData, _pos=0, _len=0):
        self.Clear()
        memmove(addressof(self), stringData[_pos:], self.GetLength())
        return _pos + self.GetLength()
    def Clear(self):
        self.Cmd = 0xB3
        self.SubCmd = 0x09
        self.PlayerID = 0
        self.QueryType = 0
        self.QueryCount = 0
        return
    def GetLength(self):
        return sizeof(tagCGCharmOfferBillboardQuery)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// B3 09 魅力贡献榜查看 //tagCGCharmOfferBillboardQuery:
                                Cmd:%s,
                                SubCmd:%s,
                                PlayerID:%d,
                                QueryType:%d,
                                QueryCount:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.PlayerID,
                                self.QueryType,
                                self.QueryCount
                                )
        return DumpString
m_NAtagCGCharmOfferBillboardQuery=tagCGCharmOfferBillboardQuery()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCGCharmOfferBillboardQuery.Cmd,m_NAtagCGCharmOfferBillboardQuery.SubCmd))] = m_NAtagCGCharmOfferBillboardQuery
#------------------------------------------------------
# B3 16 和平离婚回应 #tagGCMarryBreakResponse
class  tagGCMarryBreakResponse(Structure):
@@ -4419,15 +4479,17 @@
#------------------------------------------------------
# B3 10 送花 #tagCMSendFlowers
# B3 10 送礼物 #tagCMSendGifts
class  tagCMSendFlowers(Structure):
class  tagCMSendGifts(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("TagPlayerID", c_int),    # 目标玩家ID
                  ("FlowerCount", c_int),    # 赠送花数量
                  ("GiftNum", c_ushort),    # 赠送礼物编号
                  ("GiftCount", c_int),    # 赠送礼物数量
                  ("IsAutoBuy", c_ubyte),    # 是否自动购买
                  ]
    def __init__(self):
@@ -4445,33 +4507,39 @@
        self.Cmd = 0xB3
        self.SubCmd = 0x10
        self.TagPlayerID = 0
        self.FlowerCount = 0
        self.GiftNum = 0
        self.GiftCount = 0
        self.IsAutoBuy = 0
        return
    def GetLength(self):
        return sizeof(tagCMSendFlowers)
        return sizeof(tagCMSendGifts)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// B3 10 送花 //tagCMSendFlowers:
        DumpString = '''// B3 10 送礼物 //tagCMSendGifts:
                                Cmd:%s,
                                SubCmd:%s,
                                TagPlayerID:%d,
                                FlowerCount:%d
                                GiftNum:%d,
                                GiftCount:%d,
                                IsAutoBuy:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.TagPlayerID,
                                self.FlowerCount
                                self.GiftNum,
                                self.GiftCount,
                                self.IsAutoBuy
                                )
        return DumpString
m_NAtagCMSendFlowers=tagCMSendFlowers()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMSendFlowers.Cmd,m_NAtagCMSendFlowers.SubCmd))] = m_NAtagCMSendFlowers
m_NAtagCMSendGifts=tagCMSendGifts()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMSendGifts.Cmd,m_NAtagCMSendGifts.SubCmd))] = m_NAtagCMSendGifts
#------------------------------------------------------
ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/BillboardData.py
@@ -28,6 +28,7 @@
    GameWorld.DebugAnswer(curPlayer, "榜单类型:0-战力,1-龙魂,2-灵瑶,4-等级,5-坐骑,6-灵宠,7-符印,8-脱机,9-境界,19-助战")
    GameWorld.DebugAnswer(curPlayer, "开服活动榜类型:11-强化,12-坐骑,13-宝石,14-冲级,15-境界,16-战力,18-符印,20-神兵,21-充值,22-灵宠,24-灵根,25-升星")
    GameWorld.DebugAnswer(curPlayer, "运营活动榜类型:17-仙界盛典,23-仙界盛典2")
    GameWorld.DebugAnswer(curPlayer, "魅力榜单类型:30-总榜,31-周榜,31-日榜")
    return
## 执行逻辑
ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/Charm.py
New file
@@ -0,0 +1,74 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package GM.Commands.Charm
#
# @todo:魅力
# @author hxp
# @date 2021-11-17
# @version 1.0
#
# 详细描述: 魅力
#
#-------------------------------------------------------------------------------
#"""Version = 2021-11-17 15:00"""
#-------------------------------------------------------------------------------
import GameWorld
import PlayerCharm
def __Help(curPlayer):
    GameWorld.DebugAnswer(curPlayer, "---------- %s" % GameWorld.GetCurrentDataTimeStr())
    GameWorld.DebugAnswer(curPlayer, "清空魅力: Charm 0")
    GameWorld.DebugAnswer(curPlayer, "随机魅力: Charm 1 人数  贡献人数 [选填 随机范围值A B]")
    GameWorld.DebugAnswer(curPlayer, "随机范围值不填的话默认10~1000")
    GameWorld.DebugAnswer(curPlayer, "增加魅力: Charm 2 数值 [选填 贡献玩家ID 获得玩家ID]")
    GameWorld.DebugAnswer(curPlayer, "玩家ID不填的话均默认自己")
    return
#逻辑实现
## 执行逻辑
#  @param curPlayer 当前玩家
#  @param gmList [cmdIndex gmAccID msg]
#  @return None
#  @remarks 函数详细说明.
def OnExec(curPlayer, gmList):
    if not gmList:
        __Help(curPlayer)
        return
    value1 = gmList[0]
    # 清空魅力
    if value1 == 0:
        PlayerCharm.GMClearCharm()
    # 随机魅力
    elif value1 == 1 and len(gmList) >= 3:
        playerCount = gmList[1]
        offerCount = gmList[2]
        randA = gmList[3] if len(gmList) > 3 else 10
        randB = gmList[4] if len(gmList) > 4 else 1000
        PlayerCharm.GMRandCharm(curPlayer, playerCount, offerCount, randA, randB)
    # 增加魅力
    elif value1 == 2 and len(gmList) >= 2:
        addValue = gmList[1]
        offerPlayerID = gmList[2] if len(gmList) > 2 else curPlayer.GetPlayerID()
        addPlayerID = gmList[3] if len(gmList) > 3 else curPlayer.GetPlayerID()
        addPlayer = None
        if addPlayerID == curPlayer.GetPlayerID():
            addPlayer = curPlayer
        elif addPlayerID >= 10000:
            addPlayer = GameWorld.GetPlayerManager().FindPlayerByID(addPlayerID)
        PlayerCharm.AddCharm(addPlayer, addPlayerID, offerPlayerID, addValue)
        GameWorld.DebugAnswer(curPlayer, "增加玩家[ %s ]魅力:%s, 贡献者[ %s ]" % (addPlayerID, addValue, offerPlayerID))
    else:
        __Help(curPlayer)
        return
    return
ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/Couple.py
New file
@@ -0,0 +1,128 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package GM.Commands.Couple
#
# @todo:伴侣
# @author hxp
# @date 2021-11-17
# @version 1.0
#
# 详细描述: 伴侣
#
#-------------------------------------------------------------------------------
#"""Version = 2021-11-17 15:00"""
#-------------------------------------------------------------------------------
import GameWorld
import PyDataManager
import PlayerLove
import PyGameData
import time
def __Help(curPlayer):
    GameWorld.DebugAnswer(curPlayer, "---------- %s" % GameWorld.GetCurrentDataTimeStr())
    GameWorld.DebugAnswer(curPlayer, "清除伴侣: Couple 0")
    GameWorld.DebugAnswer(curPlayer, "重置聘礼: Couple 0 1")
    GameWorld.DebugAnswer(curPlayer, "设置伴侣: Couple 1 目标ID [可选聘礼ID]")
    GameWorld.DebugAnswer(curPlayer, "设亲密度: Couple 2 目标ID 亲密度")
    GameWorld.DebugAnswer(curPlayer, "增加密度: Couple 3 目标ID 亲密度")
    return
#逻辑实现
## 执行逻辑
#  @param curPlayer 当前玩家
#  @param gmList [cmdIndex gmAccID msg]
#  @return None
#  @remarks 函数详细说明.
def OnExec(curPlayer, gmList):
    if not gmList:
        __Help(curPlayer)
        return
    playerID = curPlayer.GetPlayerID()
    coupleMgr = PyDataManager.GetDBPyCoupleManager()
    couple = coupleMgr.GetCouple(playerID)
    value1 = gmList[0]
    if value1 == 0:
        # 离婚
        if len(gmList) == 1:
            PlayerLove.__DoMarryBreakLogic(couple, playerID)
            GameWorld.DebugAnswer(curPlayer, "清除伴侣OK!")
            return
        value2 = gmList[1]
        # 重置聘礼
        if value2 == 1:
            if not couple:
                GameWorld.DebugAnswer(curPlayer, "没有伴侣!")
                return
            couple.coupleData.BridePriceState = 0
            PlayerLove.Sync_CoupleInfo(curPlayer)
            GameWorld.DebugAnswer(curPlayer, "重置聘礼OK!")
        return
    # 设置伴侣
    elif value1 == 1:
        if couple:
            GameWorld.DebugAnswer(curPlayer, "已有伴侣! coupleID=%s" % couple.GetCoupleID(playerID))
            return
        tagPlayerID = gmList[1] if len(gmList) > 1 else 0
        if not tagPlayerID or tagPlayerID == playerID:
            GameWorld.DebugAnswer(curPlayer, "非法伴侣玩家ID:%s,playerID=%s" % (tagPlayerID, playerID))
            return
        tagCouple = coupleMgr.GetCouple(tagPlayerID)
        if tagCouple:
            GameWorld.DebugAnswer(curPlayer, "对方已有伴侣! tagCoupleID=%s" % tagCouple.GetCoupleID(tagPlayerID))
            return
        bridePriceID = gmList[2] if len(gmList) > 2 else 1
        reqData = PlayerLove.MarryReq()
        reqData.playerIDA = tagPlayerID
        reqData.playerIDB = playerID
        reqData.bridePriceID = bridePriceID
        reqData.reqTime = int(time.time())
        PyGameData.g_marryReqInfo[tagPlayerID] = reqData
        reqPlayer = GameWorld.GetPlayerManager().FindPlayerByID(tagPlayerID)
        isOK = PlayerLove.__DoMarryResponse(curPlayer, reqPlayer, tagPlayerID, 1)
        GameWorld.DebugAnswer(curPlayer, "设置伴侣【%s】 %s" % (tagPlayerID, isOK))
        return
    # 设置亲密度
    elif value1 == 2 and len(gmList) >= 3:
        tagPlayerID = gmList[1]
        setValue = gmList[2]
        if not tagPlayerID or tagPlayerID == playerID:
            GameWorld.DebugAnswer(curPlayer, "玩家ID不能设置亲密度:%s,playerID=%s" % (tagPlayerID, playerID))
            return
        intimacys = PyDataManager.GetIntimacyManager().GetIntimacys(playerID)
        updIntimacy = intimacys.SetIntimacy(curPlayer, tagPlayerID, setValue)
        GameWorld.DebugAnswer(curPlayer, "设置目标【%s】亲密度: %s" % (tagPlayerID, updIntimacy))
    # 增加亲密度
    elif value1 == 3 and len(gmList) >= 3:
        tagPlayerID = gmList[1]
        addValue = gmList[2]
        if not tagPlayerID or tagPlayerID == playerID:
            GameWorld.DebugAnswer(curPlayer, "玩家ID不能增加亲密度:%s,playerID=%s" % (tagPlayerID, playerID))
            return
        PyDataManager.GetIntimacyManager().AddIntimacyBoth(playerID, tagPlayerID, addValue)
        intimacys = PyDataManager.GetIntimacyManager().GetIntimacys(playerID)
        if intimacys:
            GameWorld.DebugAnswer(curPlayer, "更新目标【%s】亲密度: %s" % (tagPlayerID, intimacys.GetTagIntimacy(tagPlayerID)))
    else:
        __Help(curPlayer)
        return
    return
ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/Friend.py
File was deleted
ServerPython/CoreServerGroup/GameServer/Script/GameWorld.py
@@ -996,6 +996,49 @@
    rate = random.randint(1, randList[-1][0])
    return GetResultByRiseList(randList, rate)
## 获得对应数位的值
#  @param numValue 数值
#  @param dataIndex 数位索引
#  @return 获得的值
def GetDataByDigitPlace(numValue, dataIndex):
    return (numValue/pow(10, dataIndex))%10
## 设置对应数位的值
#  @param numValue 数值
#  @param dataIndex 数位索引
#  @param dataValue 当前修改数值
#  @return 获得的值
def ChangeDataByDigitPlace(numValue, dataIndex, dataValue):
    if dataValue < 0 or dataValue > 9 or dataIndex > ShareDefine.Def_PDictDigitCnt:
        return numValue
    # 获得对应数位的值
    lastTagLV = GetDataByDigitPlace(numValue, dataIndex)
    numValue += pow(10, dataIndex)*(dataValue - lastTagLV)
    return numValue
def GetBitValue(dataValue, index):
    """ 得到某个字节值中某一位(Bit)的值
    @param dataValue: 待取值的字节值
    @param index: 待读取位的序号,从右向左0开始,0-7为一个完整字节的8个位
    @return: 返回读取该位的值,0或1
    """
    return 1 if dataValue & (1 << index) else 0
def SetBitValue(dataValue, index, val):
    """ 更改某个字节值中某一位(Bit)的值
    @param dataValue: 准备更改的字节原值
    @param index: 待更改位的序号,从右向左0开始,0-7为一个完整字节的8个位
    @param val: 目标位预更改的值,0或1
    @return: 返回更改后字节的值
    """
    if val:
        return dataValue | (1 << index)
    return dataValue & ~(1 << index)
## 根据字典key获取value值
#  @return 
def GetDictValueByKey(attrDict, findKey, defaultValue=None):
ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py
@@ -708,8 +708,18 @@
                        ("dict", "Award", 0),
                        ),
                "LoveGift":(
                        ("BYTE", "GiftNum", 1),
                        ("DWORD", "AddCharmSelf", 0),
                        ("DWORD", "AddCharmTag", 0),
                        ("DWORD", "AddIntimacy", 0),
                        ("char", "WorldNotifyKey", 0),
                        ),
                "Marry":(
                        ("BYTE", "BridePriceID", 1),
                        ("BYTE", "CanBuyCount", 0),
                        ("BYTE", "IsDayReset", 0),
                        ("DWORD", "Prosperity", 0),
                        ("WORD", "CandyTimes", 0),
                        ("list", "CandyItemInfo", 0),
@@ -2195,11 +2205,30 @@
    def GetRank(self): return self.Rank # 排名
    def GetAward(self): return self.Award # 奖励 {"职业":[[物品ID,个数,是否绑定],...], ...}
# 情缘礼物表
class IPY_LoveGift():
    def __init__(self):
        self.GiftNum = 0
        self.AddCharmSelf = 0
        self.AddCharmTag = 0
        self.AddIntimacy = 0
        self.WorldNotifyKey = ""
        return
    def GetGiftNum(self): return self.GiftNum # 聘礼ID
    def GetAddCharmSelf(self): return self.AddCharmSelf # 单个增加自身魅力
    def GetAddCharmTag(self): return self.AddCharmTag # 单个增加对方魅力
    def GetAddIntimacy(self): return self.AddIntimacy # 单个增加双方亲密度
    def GetWorldNotifyKey(self): return self.WorldNotifyKey # 广播key
# 情缘提亲表
class IPY_Marry():
    
    def __init__(self):
        self.BridePriceID = 0
        self.CanBuyCount = 0
        self.IsDayReset = 0
        self.Prosperity = 0
        self.CandyTimes = 0
        self.CandyItemInfo = []
@@ -2208,6 +2237,8 @@
        return
        
    def GetBridePriceID(self): return self.BridePriceID # 聘礼ID
    def GetCanBuyCount(self): return self.CanBuyCount # 可购买次数
    def GetIsDayReset(self): return self.IsDayReset # 是否每日重置
    def GetProsperity(self): return self.Prosperity # 初始繁荣度
    def GetCandyTimes(self): return self.CandyTimes # 喜糖持续时间秒
    def GetCandyItemInfo(self): return self.CandyItemInfo # 喜糖物品列表[[物品ID,个数,是否拍品], ...]
@@ -2493,6 +2524,8 @@
        self.ipyActNewFairyCeremonyLen = len(self.ipyActNewFairyCeremonyCache)
        self.ipyNewUniquenessArriveCache = self.__LoadFileData("NewUniquenessArrive", IPY_NewUniquenessArrive)
        self.ipyNewUniquenessArriveLen = len(self.ipyNewUniquenessArriveCache)
        self.ipyLoveGiftCache = self.__LoadFileData("LoveGift", IPY_LoveGift)
        self.ipyLoveGiftLen = len(self.ipyLoveGiftCache)
        self.ipyMarryCache = self.__LoadFileData("Marry", IPY_Marry)
        self.ipyMarryLen = len(self.ipyMarryCache)
        self.ipyActLuckyTreasureCache = self.__LoadFileData("ActLuckyTreasure", IPY_ActLuckyTreasure)
@@ -2799,6 +2832,8 @@
    def GetActNewFairyCeremonyByIndex(self, index): return self.ipyActNewFairyCeremonyCache[index]
    def GetNewUniquenessArriveCount(self): return self.ipyNewUniquenessArriveLen
    def GetNewUniquenessArriveByIndex(self, index): return self.ipyNewUniquenessArriveCache[index]
    def GetLoveGiftCount(self): return self.ipyLoveGiftLen
    def GetLoveGiftByIndex(self, index): return self.ipyLoveGiftCache[index]
    def GetMarryCount(self): return self.ipyMarryLen
    def GetMarryByIndex(self, index): return self.ipyMarryCache[index]
    def GetActLuckyTreasureCount(self): return self.ipyActLuckyTreasureLen
ServerPython/CoreServerGroup/GameServer/Script/Player/ChPlayer.py
@@ -67,6 +67,7 @@
import PlayerAssist
import PlayerFB
import PlayerLove
import PlayerCharm
#---------------------------------------------------------------------
#---------------------------------------------------------------------
@@ -212,6 +213,8 @@
    if not PlayerControl.GetIsTJG(curPlayer):
        #家族副本boss状态通知
        PlayerFamilyBoss.OnLogin(curPlayer)
        #魅力
        PlayerCharm.OnPlayerLogin(curPlayer)
        #情缘
        PlayerLove.OnPlayerLogin(curPlayer)
        
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerBillboard.py
@@ -26,8 +26,11 @@
import NetPackCommon
import DataRecordPack
import PlayerFamily
import PyDataManager
import PlayerViewCache
import time
import random
Def_Key_BillboardSortTick = "BillboardSortTick_%s" # 排行榜是否排序tick,参数(排行榜类型)
Def_Key_BillboardNeedSort = "BillboardNeedSort_%s" # 排行榜是否需要排序,参数(排行榜类型)
@@ -522,6 +525,53 @@
    #GameWorld.DebugLog("__UpdateBillboardSortState:bType=%s,autoSort=%s,isUpd=%s,needSort=%s" % (bType, autoSort, isUpd, gameWorld.GetDictByKey(key)))
    return
def GetBillboardOperateInfo(curPlayer):
    # 排行榜中所保存的运营商相关信息
    platform = curPlayer.GetAccID()
    if platform in ["tencent"]:
        return curPlayer.GetOperateInfo()
    return platform
def UpdatePlayerBillboardEx(curPlayer, playerID, bType, cmpValue, cmpValue2=0, cmpValue3=0, value1=0, value2=0, autoSort=False):
    ## 更新玩家排行榜
    # @param curPlayer: 可能为None
    playerOpInfo = ""
    playerJob = 0
    playerName = ""
    playerRealmLV = 0
    if curPlayer:
        playerID = curPlayer.GetID()
        playerJob = curPlayer.GetJob()
        playerName = curPlayer.GetName()
        playerRealmLV = curPlayer.GetOfficialRank()
        playerOpInfo = GetBillboardOperateInfo(curPlayer)
    else:
        socialPlayer = PyDataManager.GetPersonalSocialManager().GetSocialPlayer(playerID)
        if socialPlayer:
            playerJob = socialPlayer.playerInfo.Job
            playerName = socialPlayer.playerInfo.PlayerName
            playerRealmLV = socialPlayer.playerInfo.RealmLV
        else:
            curCache = PlayerViewCache.FindViewCache(playerID)
            if curCache:
                cacheDict = PlayerViewCache.GetCachePropDataDict(curCache)
                playerJob = cacheDict["Job"]
                playerName = cacheDict["Name"]
                playerRealmLV = cacheDict["RealmLV"]
    if not playerName and playerID < 10000:
        playerJob = random.choice([1, 2])
        playerName = "testName%s" % playerID
        playerRealmLV = random.randint(1, 10)
    if bType in ShareDefine.BTValue1_OfficialRankList:
        value1 = playerRealmLV
    UpdatePlayerBillboard(playerID, playerName, playerOpInfo, bType, playerJob, value1, value2, cmpValue, autoSort, cmpValue2, cmpValue3)
    return
#---------------------------------------------------------------------
#===============================================================================
#    void        SetType(int inputType);    //_I_KEY_INDEX_排行榜类型
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerCharm.py
New file
@@ -0,0 +1,299 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package PlayerCharm
#
# @todo:魅力系统
# @author hxp
# @date 2021-11-17
# @version 1.0
#
# 详细描述: 魅力系统
#
#-------------------------------------------------------------------------------
#"""Version = 2021-11-17 15:00"""
#-------------------------------------------------------------------------------
import CommFunc
import ShareDefine
import PlayerControl
import ChPyNetSendPack
import PyGameDataStruct
import PlayerBillboard
import NetPackCommon
import PyDataManager
import PlayerSocial
import GameWorld
import operator
import random
import time
CharmValueRecTypeList = (
CharmValueRecType_Total, # 总 - 1
CharmValueRecType_Week, # 周 - 2
CharmValueRecType_Day, # 日 - 3
) = range(1, 1 + 3)
class DBPyCharmValueRecManager(object):
    ## 魅力贡献记录管理
    def __init__(self):
        self.charmValueRecDict = {} # 魅力贡献记录字典 {playerID:{recType:{offerPlayerID:PyGameDataStruct.tagDBPyCharmValueRec, ...}, ...}}
        self.charmTotalDict = {} # 总魅力  {playerID:{recType:totalCharm, ...}, ...}
        self.charmSortListDict = {} # 排序后的贡献记录 {playerID:{recType:[PyGameDataStruct.tagDBPyCharmValueRec, ...], ...}}
        return
    def ClearCharmByType(self, recType):
        for recTypeDict in self.charmValueRecDict.values():
            recTypeDict.pop(recType, None)
        for recTypeDict in self.charmTotalDict.values():
            recTypeDict.pop(recType, None)
        for recTypeDict in self.charmSortListDict.values():
            recTypeDict.pop(recType, None)
        return
    # 保存数据 存数据库和realtimebackup
    def GetSaveData(self):
        savaData = ""
        cntData = ""
        cnt = 0
        for recTypeDict in self.charmValueRecDict.values():
            for offerPlayerDict in recTypeDict.values():
                for recData in offerPlayerDict.values():
                    cnt += 1
                    savaData += recData.getBuffer()
        GameWorld.Log("Save DBPyCharmValueRec count :%s len=%s" % (cnt, len(savaData)))
        return CommFunc.WriteDWORD(cntData, cnt) + savaData
    # 从数据库载入数据
    def LoadPyGameData(self, datas, pos, dataslen):
        cnt, pos = CommFunc.ReadDWORD(datas, pos)
        GameWorld.Log("Load DBPyCharmValueRec count :%s" % cnt)
        for _ in xrange(cnt):
            recData = PyGameDataStruct.tagDBPyCharmValueRec()
            recData.clear()
            pos += recData.readData(datas, pos, dataslen)
            playerID = recData.PlayerID
            recType = recData.Type
            offerPlayerID = recData.OfferPlayerID
            if playerID not in self.charmValueRecDict:
                self.charmValueRecDict[playerID] = {}
            recTypeDataDict = self.charmValueRecDict[playerID]
            if recType not in recTypeDataDict:
                recTypeDataDict[recType] = {}
            offerPlayerDict = recTypeDataDict[recType]
            offerPlayerDict[offerPlayerID] = recData
            if playerID not in self.charmTotalDict:
                self.charmTotalDict[playerID] = {}
            recTypeValueDict = self.charmTotalDict[playerID]
            recTypeValueDict[recType] = recTypeValueDict.get(recType, 0) + recData.CharmValue
        return pos
def DoOnWeek():
    PlayerBillboard.ClearBillboardByIndex(ShareDefine.Def_BT_CharmWeek)
    PyDataManager.GetDBPyCharmValueRecManager().ClearCharmByType(CharmValueRecType_Week)
    playerManager = GameWorld.GetPlayerManager()
    for i in xrange(playerManager.GetActivePlayerCount()):
        curPlayer = playerManager.GetActivePlayerAt(i)
        if not curPlayer or PlayerControl.GetIsTJG(curPlayer):
            continue
        Sync_PlayerCharmInfo(curPlayer)
    return
def DoOnDay():
    PlayerBillboard.ClearBillboardByIndex(ShareDefine.Def_BT_CharmDay)
    PyDataManager.GetDBPyCharmValueRecManager().ClearCharmByType(CharmValueRecType_Day)
    playerManager = GameWorld.GetPlayerManager()
    for i in xrange(playerManager.GetActivePlayerCount()):
        curPlayer = playerManager.GetActivePlayerAt(i)
        if not curPlayer or PlayerControl.GetIsTJG(curPlayer):
            continue
        Sync_PlayerCharmInfo(curPlayer)
    return
def OnPlayerLogin(curPlayer):
    Sync_PlayerCharmInfo(curPlayer)
    return
def GetPlayerCharmOfferSortList(playerID, recType):
    ## 获取排序后的玩家魅力贡献榜
    charmValueRecMgr = PyDataManager.GetDBPyCharmValueRecManager()
    if playerID not in charmValueRecMgr.charmValueRecDict:
        return []
    recTypeDataDict = charmValueRecMgr.charmValueRecDict[playerID]
    if recType not in recTypeDataDict:
        return []
    offerPlayerDict = recTypeDataDict[recType]
    if playerID not in charmValueRecMgr.charmSortListDict:
        charmValueRecMgr.charmSortListDict[playerID] = {}
    recTypeSortListDict = charmValueRecMgr.charmSortListDict[playerID]
    if recType not in recTypeSortListDict:
        # 排序
        recDataList = offerPlayerDict.values()
        recDataList.sort(key=operator.attrgetter("CharmValue", "UpdTime"), reverse=True)
        recTypeSortListDict[recType] = recDataList
    return recTypeSortListDict[recType]
def AddCharm(curPlayer, playerID, offerPlayerID, addValue, isNotify=True):
    ''' 添加魅力
    @param curPlayer: 增加魅力的玩家实例,可能为None
    @param offerPlayerID: 魅力贡献玩家ID
    @param addValue: 增加魅力值
    '''
    charmValueRecMgr = PyDataManager.GetDBPyCharmValueRecManager()
    if playerID not in charmValueRecMgr.charmValueRecDict:
        charmValueRecMgr.charmValueRecDict[playerID] = {}
    recTypeDataDict = charmValueRecMgr.charmValueRecDict[playerID]
    if playerID not in charmValueRecMgr.charmTotalDict:
        charmValueRecMgr.charmTotalDict[playerID] = {}
    recTypeValueDict = charmValueRecMgr.charmTotalDict[playerID]
    updTime = max(0, GameWorld.ChangeTimeStrToNum("2090-01-01 00:00:00") - int(time.time())) # 用于倒序排序
    for recType in CharmValueRecTypeList:
        if recType not in recTypeDataDict:
            recTypeDataDict[recType] = {}
        offerPlayerDict = recTypeDataDict[recType]
        if offerPlayerID not in offerPlayerDict:
            offerPlayerDict[offerPlayerID] = PyGameDataStruct.tagDBPyCharmValueRec()
        recData = offerPlayerDict[offerPlayerID]
        curValue = recData.CharmValue
        recData.PlayerID = playerID
        recData.Type = recType
        recData.OfferPlayerID = offerPlayerID
        recData.CharmValue += addValue
        recData.UpdTime = updTime
        typeTotalValue = recTypeValueDict.get(recType, 0)
        recTypeValueDict[recType] = typeTotalValue + addValue
        GameWorld.DebugLog("增加魅力记录: playerID=%s,recType=%s,offerPlayerID=%s,addValue=%s,updValue=(%s-%s),updTime=%s,typeTotalValue=(%s-%s)"
                           % (playerID, recType, offerPlayerID, addValue, curValue, recData.CharmValue, updTime, typeTotalValue, recTypeValueDict[recType]), playerID)
    # 榜单
    charmTotal = recTypeValueDict.get(CharmValueRecType_Total, 0)
    charmWeek = recTypeValueDict.get(CharmValueRecType_Week, 0)
    charmDay = recTypeValueDict.get(CharmValueRecType_Day, 0)
    PlayerBillboard.UpdatePlayerBillboardEx(curPlayer, playerID, ShareDefine.Def_BT_CharmTotal, charmTotal)
    PlayerBillboard.UpdatePlayerBillboardEx(curPlayer, playerID, ShareDefine.Def_BT_CharmWeek, charmWeek)
    PlayerBillboard.UpdatePlayerBillboardEx(curPlayer, playerID, ShareDefine.Def_BT_CharmDay, charmDay)
    charmValueRecMgr.charmSortListDict.pop(playerID, None) # 数据变更时移除,下次用到时再重新排序生成
    if not curPlayer:
        return
    if not isNotify:
        return
    PlayerControl.NotifyCode(curPlayer, "AddCharm", [addValue])
    Sync_PlayerCharmInfo(curPlayer)
    return
def Sync_PlayerCharmInfo(curPlayer, isForce=False):
    ## 同步魅力信息
    playerID = curPlayer.GetPlayerID()
    charmValueRecMgr = PyDataManager.GetDBPyCharmValueRecManager()
    if playerID not in charmValueRecMgr.charmTotalDict and not isForce:
        return
    recTypeValueDict = charmValueRecMgr.charmTotalDict.get(playerID, {})
    clientPack = ChPyNetSendPack.tagGCPlayerCharmValueInfo()
    clientPack.CharmValueTotal = recTypeValueDict.get(CharmValueRecType_Total, 0)
    clientPack.CharmValueWeek = recTypeValueDict.get(CharmValueRecType_Week, 0)
    clientPack.CharmValueDay = recTypeValueDict.get(CharmValueRecType_Day, 0)
    NetPackCommon.SendFakePack(curPlayer, clientPack)
    return
#// B3 09 魅力贡献榜查看 #tagCGCharmOfferBillboardQuery
#
#struct    tagCGCharmOfferBillboardQuery
#{
#    tagHead        Head;
#    DWORD        PlayerID;        // 魅力玩家ID
#    BYTE        QueryType;    // 查看类型: 1-总榜,2-周榜,3-日榜
#    BYTE        QueryCount;    // 查看名次数量,最大255
#};
def OnCharmOfferBillboardQuery(index, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    tagPlayerID = clientData.PlayerID
    queryType = clientData.QueryType
    queryCount = min(clientData.QueryCount, 255)
    sortList = GetPlayerCharmOfferSortList(tagPlayerID, queryType)
    clientPack = ChPyNetSendPack.tagGCCharmOfferBillboardDataList()
    clientPack.PlayerID = tagPlayerID
    clientPack.QueryType = queryType
    clientPack.OfferBillboardDataList = []
    for i, recData in enumerate(sortList[:queryCount]):
        billboardData = ChPyNetSendPack.tagGCCharmOfferBillboardData()
        billboardData.OrderIndex = i
        billboardData.PlayerID = recData.OfferPlayerID
        billboardData.PlayerName = PlayerSocial.GetSocialPlayerName(billboardData.PlayerID)
        billboardData.NameLen = len(billboardData.PlayerName)
        billboardData.CharmValue = recData.CharmValue
        clientPack.OfferBillboardDataList.append(billboardData)
    clientPack.DataCount = len(clientPack.OfferBillboardDataList)
    NetPackCommon.SendFakePack(curPlayer, clientPack)
    return
def GMClearCharm():
    ## GM清空魅力
    GameWorld.Log("GM清空魅力")
    charmValueRecMgr = PyDataManager.GetDBPyCharmValueRecManager()
    charmValueRecMgr.charmValueRecDict = {}
    charmValueRecMgr.charmTotalDict = {}
    charmValueRecMgr.charmSortListDict = {}
    playerManager = GameWorld.GetPlayerManager()
    for i in xrange(playerManager.GetActivePlayerCount()):
        curPlayer = playerManager.GetActivePlayerAt(i)
        if not curPlayer or PlayerControl.GetIsTJG(curPlayer):
            continue
        Sync_PlayerCharmInfo(curPlayer, True)
    GameWorld.DebugAnswer(curPlayer, "GM清空魅力OK")
    return
def GMRandCharm(curPlayer, playerCount, offerCount, randA, randB):
    ## GM随机增加魅力数据
    GameWorld.Log("GM随机增加魅力数据: playerCount=%s,offerCount=%s,randA=%s,randB=%s" % (playerCount, offerCount, randA, randB))
    playerDict = {}
    playerManager = GameWorld.GetPlayerManager()
    for i in xrange(playerManager.GetActivePlayerCount()):
        player = playerManager.GetActivePlayerAt(i)
        if not player or PlayerControl.GetIsTJG(player):
            continue
        playerDict[player.GetPlayerID()] = player
    playerCount = min(1000, playerCount)
    if len(playerDict) < playerCount:
        lackCount = playerCount - len(playerDict)
        for testPlayerID in xrange(1000, 1000 + lackCount):
            playerDict[testPlayerID] = None
    for playerID, player in playerDict.items():
        for offerPlayerID in xrange(2000, 2000 + offerCount):
            addValue = random.randint(randA, randB)
            AddCharm(player, playerID, offerPlayerID, addValue, False)
        if player:
            Sync_PlayerCharmInfo(player)
    GameWorld.DebugAnswer(curPlayer, "GM随机增加魅力数据OK")
    return
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerControl.py
@@ -247,10 +247,6 @@
def GetChatBubbleBox(curPlayer): return curPlayer.GetExAttr10()
def SetChatBubbleBox(curPlayer, value): return curPlayer.SetExAttr10(value)
##伴侣ID
def GetCoupleID(curPlayer): return curPlayer.GetExAttr11()
def SetCoupleID(curPlayer, coupleID): return curPlayer.SetExAttr11(coupleID)
##玩家主动退出仙盟时间(<100代表退出次数)
def SetLeaveFamilyTime(curPlayer, value, isSyncMap=True):
    curPlayer.SetExAttr12(value)
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerEventCounter.py
@@ -31,6 +31,7 @@
import GameWorldArena
import NetPackCommon
import PlayerDuJie
import PlayerCharm
#---------------------------------------------------------------------
#---------------------------------------------------------------------
@@ -57,6 +58,8 @@
    if isMixServer:
        PlayerDBGSEvent.SetDBGSTrig_ServerTime(PlayerDBGSEvent.Def_MixServerDay)
    
    #魅力
    PlayerCharm.DoOnDay()
    #家族更新
    PlayerFamily.FamilyOnDay(tick)
    
@@ -103,6 +106,8 @@
    #设定服务器当前周事件
    PlayerDBGSEvent.SetDBGSTrig_ServerTime(PlayerDBGSEvent.Def_ServerWeek)
    
    #魅力
    PlayerCharm.DoOnWeek()
    #家族更新
    PlayerFamily.FamilyOnWeek(tick)
    
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFriend.py
@@ -214,9 +214,9 @@
        GameWorld.Log('DeleteFriend -> 封包异常 ->没有这个玩家', playerID)
        return
    
    coupleID = PlayerControl.GetCoupleID(curPlayer)
    if coupleID == friendID:
        GameWorld.Log('DeleteFriend -> 封包异常 ->伴侣不能删除好友,coupleID=%s' % coupleID, playerID)
    couple = PyDataManager.GetDBPyCoupleManager().GetCouple(playerID)
    if couple and couple.GetCoupleID(playerID) == friendID:
        GameWorld.Log('DeleteFriend -> 封包异常 ->伴侣不能删除好友.friendID=%s' % friendID, playerID)
        return
    
    #离线好友同时删除记录
@@ -229,6 +229,12 @@
    if tagPlayer != None:
        PlayerControl.NotifyCode(tagPlayer, 'Friend_DeleteFriend2', [curPlayer.GetName()])
    PlayerTeam.OnTeamMemFriendChange(curPlayer, friendID, False)
    # 亲密度减少
    decIntimacyPer = IpyGameDataPY.GetFuncCfg("IntimacyReduce", 1)
    if decIntimacyPer:
        PyDataManager.GetIntimacyManager().DelIntimacyBothPer(playerID, friendID, decIntimacyPer)
    return
@@ -394,7 +400,8 @@
    #    return
    #===========================================================================
    
    if tagID == PlayerControl.GetCoupleID(curPlayer):
    couple = PyDataManager.GetDBPyCoupleManager().GetCouple(curPlayer.GetID())
    if couple and couple.GetCoupleID(curPlayer.GetID()) == tagID:
        GameWorld.DebugLog("伴侣不能加入黑名单! tagID=%s" % tagID, curPlayer.GetID())
        return
    
@@ -419,6 +426,11 @@
    
    PlayerControl.NotifyCode(curPlayer, 'AddBlackList', [playerName])
    
    # 亲密度减少
    decIntimacyPer = IpyGameDataPY.GetFuncCfg("IntimacyReduce", 2)
    if decIntimacyPer:
        PyDataManager.GetIntimacyManager().DelIntimacyBothPer(curPlayer.GetPlayerID(), tagID, decIntimacyPer)
    return
@@ -482,6 +494,15 @@
    players.Sync_SocialsInfo(curPlayer)
    return
#亲密
def __OnPlayerLoginIntimacylist(curPlayer, tick):
    intimacys = PyDataManager.GetIntimacyManager().GetIntimacys(curPlayer.GetID())
    if intimacys == None:
        return
    intimacys.Sync_SocialsInfo(curPlayer)
    return
## 玩家登陆
#  @param curPlayer 当前玩家
#  @param tick 当前时间
@@ -495,6 +516,7 @@
    __OnPlayerLoginEnemy(curPlayer, tick)
    __OnPlayerLoginContacts(curPlayer, tick)
    __OnPlayerLoginBlacklist(curPlayer, tick)
    __OnPlayerLoginIntimacylist(curPlayer, tick)
    
    # 向当前玩家通知相关联的所有玩家信息
    PlayerSocial.Sync_AllSocialsInfo(curPlayer)
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerLove.py
@@ -21,12 +21,14 @@
import ChPyNetSendPack
import PlayerCompensation
import PlayerFamilyRedPacket
import PlayerBillboard
import PyGameDataStruct
import NetPackCommon
import IpyGameDataPY
import PlayerSocial
import PlayerCharm
import ShareDefine
import PyGameData
import CommFunc
import operator
import time
@@ -58,6 +60,227 @@
        self.playerFreeEatCountDict = {} # 玩家免费吃喜糖次数 {playerID:次数, ...}
        self.fireworksCountDict = {} # 烟花次数信息 {playerID:次数, ...}
        return
class PlayerCouple():
    def __init__(self, coupleData):
        self.coupleData = coupleData # PyGameDataStruct.tagDBPyCouple()
        # 更新最大聘礼ID
        self.BridePriceMaxID = 0
        maxCount = IpyGameDataPY.IPY_Data().GetMarryCount()
        for index in range(maxCount)[::-1]:
            ipyData = IpyGameDataPY.IPY_Data().GetMarryByIndex(index)
            priceID = ipyData.GetBridePriceID()
            if self.GetBridePriceBuyCount(priceID):
                self.BridePriceMaxID = priceID
                break
        return
    def GetCoupleID(self, playerID):
        return self.coupleData.PlayerIDA if (playerID == self.coupleData.PlayerIDB) else self.coupleData.PlayerIDB
    def GetCoupleName(self, playerID): return PlayerSocial.GetSocialPlayerName(self.GetCoupleID(playerID))
    def GetCoupleJob(self, playerID): return PlayerSocial.GetSocialPlayerJob(self.GetCoupleID(playerID))
    def GetNewMarryTime(self): return self.coupleData.NewMarryTime
    def GetMarryTime(self): return self.coupleData.MarryTime
    def GetBridePriceState(self): return self.coupleData.BridePriceState
    def GetBridePriceBuyCount(self, priceID): return GameWorld.GetDataByDigitPlace(self.coupleData.BridePriceState, priceID - 1)
    def SetBridePriceBuyCount(self, priceID, buyCount):
        self.coupleData.BridePriceState = GameWorld.ChangeDataByDigitPlace(self.coupleData.BridePriceState, priceID - 1, min(buyCount, 9))
        return self.coupleData.BridePriceState
    def GetBreakRequestID(self): return self.coupleData.BreakRequestID
    def GetBreakRequestTime(self): return self.coupleData.BreakRequestTime
    def SetBreakRequestID(self, reqID):
        self.coupleData.BreakRequestID = reqID
        self.coupleData.BreakRequestTime = 0
        if reqID > 0:
            curTime = int(time.time())
            self.coupleData.BreakRequestTime = curTime
            if reqID == self.coupleData.PlayerIDA:
                self.coupleData.BreakRequestTimeA = curTime
            else:
                self.coupleData.BreakRequestTimeB = curTime
        return
    def GetPlayerBreakRequestTime(self, playerID):
        return self.coupleData.BreakRequestTimeA if (playerID == self.coupleData.PlayerIDA) else self.coupleData.BreakRequestTimeB
    def GetSendMapServerCoupleInfo(self, playerID):
        coupleID = self.GetCoupleID(playerID)
        coupleName = self.GetCoupleName(playerID)
        coupleJob = self.GetCoupleJob(playerID)
        bridePriceMaxID = self.BridePriceMaxID
        return coupleID, coupleName, coupleJob, bridePriceMaxID
class DBPyCoupleManager(object):
    ## 伴侣数据管理
    def __init__(self):
        self.coupleDict = {} # {(playerIDA, playerIDB):PlayerCouple, ...}
        self.coupleIDDict = {} # {playerID:(playerIDA, playerIDB), ...} # 伴侣对应关系
        return
    def DelCouple(self, playerIDA, playerIDB):
        ## 删除伴侣数据,如果已离婚且均已通知,则可直接删除
        key = (playerIDA, playerIDB)
        if key in self.coupleDict:
            self.coupleDict.pop(key)
        if playerIDA in self.coupleIDDict and self.coupleIDDict[playerIDA] == key:
            self.coupleIDDict.pop(playerIDA)
        if playerIDB in self.coupleIDDict and self.coupleIDDict[playerIDB] == key:
            self.coupleIDDict.pop(playerIDB)
        return
    def AddCouple(self, playerIDA, playerIDB, coupleData):
        ## 添加新伴侣
        coupleKey = (playerIDA, playerIDB)
        couple = PlayerCouple(coupleData)
        self.coupleDict[coupleKey] = couple
        self.coupleIDDict[playerIDA] = coupleKey
        self.coupleIDDict[playerIDB] = coupleKey
        return couple
    def GetCouple(self, playerID):
        ## 获取伴侣
        coupleData = None
        # 不可能成立的条件,只是为了. 能出代码提示指向 PlayerCouple 类
        if False:
            coupleData = PlayerCouple(None)
        if playerID not in self.coupleIDDict:
            return coupleData
        coupleKey = self.coupleIDDict[playerID]
        if coupleKey not in self.coupleDict:
            return coupleData
        coupleData = self.coupleDict[coupleKey]
        return coupleData
    def SendMapServerCoupleInfo(self, syncPlayerIDList=None):
        ## 同步地图伴侣信息
        syncCoupleInfo = {}
        if syncPlayerIDList == None:
            syncPlayerIDList = self.coupleIDDict.keys()
        for playerID in syncPlayerIDList:
            couple = self.GetCouple(playerID)
            if not couple:
                syncCoupleInfo[playerID] = []
            else:
                syncCoupleInfo[playerID] = couple.GetSendMapServerCoupleInfo(playerID)
        GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_CoupleInfo, syncCoupleInfo)
        return
    # 保存数据 存数据库和realtimebackup
    def GetSaveData(self):
        savaData = ""
        cntData = ""
        cnt = 0
        for couple in self.coupleDict.values():
            cnt += 1
            savaData += couple.coupleData.getBuffer()
        GameWorld.Log("Save DBPyMarry count :%s len=%s" % (cnt, len(savaData)))
        return CommFunc.WriteDWORD(cntData, cnt) + savaData
    # 从数据库载入数据
    def LoadPyGameData(self, datas, pos, dataslen):
        cnt, pos = CommFunc.ReadDWORD(datas, pos)
        GameWorld.Log("Load DBPyMarry count :%s" % cnt)
        for _ in xrange(cnt):
            coupleData = PyGameDataStruct.tagDBPyCouple()
            coupleData.clear()
            pos += coupleData.readData(datas, pos, dataslen)
            playerIDA = coupleData.PlayerIDA
            playerIDB = coupleData.PlayerIDB
            couple = self.AddCouple(playerIDA, playerIDB, coupleData)
            if couple.GetBreakRequestTime() > 0:
                PyGameData.g_marryBreakInfo[(playerIDA, playerIDB)] = couple
        SortMarryBreak()
        return pos
class DBPyUnNotifyLoveGiftRecManager(object):
    ## 未通知的赠送礼物记录管理
    def __init__(self):
        self.unNotifyLoveGiftDict = {} # {playerID:[PyGameDataStruct.tagDBPyUnNotifyLoveGiftRec, ...], ...}
        return
    def AddUnNotifyGiftRec(self, receivePlayerID, givePlayerID, giftNum, giftCount, sendTime):
        ''' 添加未通知的赠送礼物记录
        @param receivePlayerID: 未通知的受赠方玩家ID
        @param givePlayerID: 赠送方玩家ID
        '''
        recData = PyGameDataStruct.tagDBPyUnNotifyLoveGiftRec()
        recData.PlayerID = receivePlayerID
        recData.GivePlayerID = givePlayerID
        recData.GiftNum = giftNum
        recData.GiftCount = giftCount
        recData.SendTime = sendTime
        if receivePlayerID not in self.unNotifyLoveGiftDict:
            self.unNotifyLoveGiftDict[receivePlayerID] = []
        giftList = self.unNotifyLoveGiftDict[receivePlayerID]
        giftList.append(recData)
        return
    def LoginNotify(self, curPlayer):
        receivePlayerID = curPlayer.GetPlayerID()
        if receivePlayerID not in self.unNotifyLoveGiftDict:
            return
        giftList = self.unNotifyLoveGiftDict.pop(receivePlayerID, [])
        sendGiftList = []
        for recData in giftList:
            giftOK = ChPyNetSendPack.tagGCSendGiftsOK()
            giftOK.PlayerID = recData.GivePlayerID
            giftOK.Name = PlayerSocial.GetSocialPlayerName(recData.GivePlayerID)
            giftOK.NameLen = len(giftOK.Name)
            giftOK.GiftNum = recData.GiftNum
            giftOK.GiftCount = recData.GiftCount
            giftOK.SendTime = recData.SendTime
            sendGiftList.append(giftOK)
        clientPack = ChPyNetSendPack.tagGCSendGiftsOKList()
        clientPack.SendGiftsOKList = sendGiftList
        clientPack.Count = len(clientPack.SendGiftsOKList)
        NetPackCommon.SendFakePack(curPlayer, clientPack)
        return
    # 保存数据 存数据库和realtimebackup
    def GetSaveData(self):
        savaData = ""
        cntData = ""
        cnt = 0
        for recDataList in self.unNotifyLoveGiftDict.values():
            for recData in recDataList:
                cnt += 1
                savaData += recData.getBuffer()
        GameWorld.Log("Save DBPyUnNotifyLoveGiftRec count :%s len=%s" % (cnt, len(savaData)))
        return CommFunc.WriteDWORD(cntData, cnt) + savaData
    # 从数据库载入数据
    def LoadPyGameData(self, datas, pos, dataslen):
        cnt, pos = CommFunc.ReadDWORD(datas, pos)
        GameWorld.Log("Load DBPyUnNotifyLoveGiftRec count :%s" % cnt)
        for _ in xrange(cnt):
            recData = PyGameDataStruct.tagDBPyUnNotifyLoveGiftRec()
            recData.clear()
            pos += recData.readData(datas, pos, dataslen)
            playerID = recData.PlayerID
            if playerID not in self.unNotifyLoveGiftDict:
                self.unNotifyLoveGiftDict[playerID] = []
            recDataList = self.unNotifyLoveGiftDict[playerID]
            recDataList.append(recData)
        return pos
    
def AddProsperity(candyObj, addValue):
    candyObj.prosperity += addValue
@@ -100,11 +323,42 @@
    return
def DoOnDay():
    PlayerBillboard.ClearBillboardByIndex(ShareDefine.Def_BT_CharmDay)
    # 重置每日聘礼状态
    syncPlayerIDList = []
    coupleMgr = PyDataManager.GetDBPyCoupleManager()
    ipyDataMgr = IpyGameDataPY.IPY_Data()
    for index in range(ipyDataMgr.GetMarryCount()):
        ipyData = ipyDataMgr.GetMarryByIndex(index)
        if not ipyData.GetIsDayReset():
            continue
        bridePriceID = ipyData.GetBridePriceID()
        for couple in coupleMgr.coupleDict.values():
            bridePriceState = couple.GetBridePriceState()
            buyCount = couple.GetBridePriceBuyCount(bridePriceID)
            if not buyCount:
                continue
            coupleIDInfo = [couple.coupleData.PlayerIDA, couple.coupleData.PlayerIDB]
            updBridePriceState = couple.SetBridePriceBuyCount(bridePriceID, 0)
            GameWorld.DebugLog("重置每日聘礼次数: coupleIDInfo=%s,bridePriceState=%s,bridePriceID=%s,updBridePriceState=%s"
                               % (coupleIDInfo, bridePriceState, bridePriceID, updBridePriceState))
            syncPlayerIDList.extend(coupleIDInfo)
    if syncPlayerIDList:
        playerMgr = GameWorld.GetPlayerManager()
        syncPlayerIDList = list(set(syncPlayerIDList))
        for playerID in syncPlayerIDList:
            curPlayer = playerMgr.FindPlayerByID(playerID)
            if not curPlayer or PlayerControl.GetIsTJG(curPlayer):
                continue
            Sync_CoupleInfo(curPlayer)
    return
def OnPlayerLogin(curPlayer):
    __LoginCheckCouple(curPlayer)
    PyDataManager.GetDBPyUnNotifyLoveGiftRecManager().LoginNotify(curPlayer)
    Sync_CoupleInfo(curPlayer)
    Sync_CandyList(curPlayer)
    return
@@ -123,6 +377,22 @@
        PyGameData.g_marryCandyInfo.pop((candyObj.playerIDA, candyObj.playerIDB), None)
        
        __DoMarryCandyOver(candyObj)
    # 检查和离
    breakWaitTimes = IpyGameDataPY.GetFuncCfg("LoveMarryBreak", 5)
    doCount = len(PyGameData.g_marryBreakSortList)
    while doCount > 0 and PyGameData.g_marryBreakSortList:
        doCount -= 1
        couple = PyGameData.g_marryBreakSortList[0]
        if curTime <= (couple.GetBreakRequestTime() + breakWaitTimes):
            break
        playerIDA, playerIDB = couple.coupleData.PlayerIDA, couple.coupleData.PlayerIDB
        PyGameData.g_marryBreakSortList.pop(0)
        PyGameData.g_marryBreakInfo.pop((playerIDA, playerIDB), None)
        GameWorld.Log("和离提交请求到期,系统自动和离! playerIDA=%s,playerIDB=%s, len(g_marryBreakSortList)=%s"
                      % (playerIDA, playerIDB, len(PyGameData.g_marryBreakSortList)))
        __DoMarryBreakLogic(couple, 0)
        
    return
@@ -167,7 +437,6 @@
        return
    
    playerID = curPlayer.GetPlayerID()
    curTime = int(time.time())
    if reqPlayerID not in PyGameData.g_marryReqInfo:
        GameWorld.DebugLog("提亲请求不存在! reqPlayerID=%s" % reqPlayerID, playerID)
        PlayerControl.NotifyCode(curPlayer, "MarryReqInvalid")
@@ -180,21 +449,31 @@
        PlayerControl.NotifyCode(curPlayer, "MarryReqInvalid")
        return
    
    reqData = PyGameData.g_marryReqInfo.pop(reqPlayerID)
    bridePriceID = reqData.bridePriceID
    passSeconds = curTime - reqData.reqTime
    reqSecondCD = IpyGameDataPY.GetFuncCfg("LoveMarry", 1)
    if passSeconds > reqSecondCD:
    if __CheckMarryReqTimeout(reqData):
        GameWorld.DebugLog("提亲请求已超时! reqPlayerID=%s" % reqPlayerID, playerID)
        PlayerControl.NotifyCode(curPlayer, "MarryReqInvalid")
        PyGameData.g_marryReqInfo.pop(reqPlayerID, None)
        return
    
    __DoMarryResponse(curPlayer, reqPlayer, reqPlayerID, isOK)
    return
def __DoMarryResponse(curPlayer, reqPlayer, reqPlayerID, isOK):
    ''' 提亲回应
    @param curPlayer: 回应玩家
    @param reqPlayer: 提亲玩家
    @param isOK: 是否统一
    '''
    reqData = PyGameData.g_marryReqInfo.pop(reqPlayerID, None)
    if not reqData:
        return
    bridePriceID = reqData.bridePriceID
    ipyData = IpyGameDataPY.GetIpyGameData("Marry", bridePriceID)
    if not ipyData:
        return
    
    reqPlayerName = reqPlayer.GetName()
    playerID = curPlayer.GetPlayerID()
    reqPlayerName = reqPlayer.GetName() if reqPlayer else PlayerSocial.GetSocialPlayerName(reqPlayerID)
    playerName = curPlayer.GetName()
    
    responsePack = ChPyNetSendPack.tagGCMarryResponseRet()
@@ -205,13 +484,17 @@
    responsePack.PlayerNameB = playerName
    responsePack.NameBLen = len(responsePack.PlayerNameB)
    responsePack.IsOK = isOK
    NetPackCommon.SendFakePack(reqPlayer, responsePack) # 必回复提亲方
    if reqPlayer:
        NetPackCommon.SendFakePack(reqPlayer, responsePack) # 必回复提亲方
    # 拒绝
    if not isOK:
        return
    NetPackCommon.SendFakePack(curPlayer, responsePack) # 回应方仅同意时同步
    
    # ===================== 以下执行成亲逻辑 ===================== 
    GameWorld.Log("执行成亲: reqPlayerID=%s,playerID=%s,bridePriceID=%s" % (reqPlayerID, playerID, bridePriceID), playerID)
    curTime = int(time.time())
    prosperity = ipyData.GetProsperity()
    candyTimes = ipyData.GetCandyTimes()
    brideGiftItemInfo = ipyData.GetBrideGiftItemInfo()
@@ -222,26 +505,49 @@
            paramList.extend([itemID, itemCount])
        PlayerControl.WorldNotify(0, worldNotifyKey, paramList)
        
    for player, coupleID, coupleName in [[reqPlayer, playerID, playerName], [curPlayer, reqPlayerID, reqPlayerName]]:
        PlayerControl.SetCoupleID(player, coupleID)
    coupleMgr = PyDataManager.GetDBPyCoupleManager()
    couple = coupleMgr.GetCouple(playerID)
    if not couple:
        GameWorld.Log("    新婚: reqPlayerID=%s,playerID=%s,bridePriceID=%s" % (reqPlayerID, playerID, bridePriceID), playerID)
        coupleData = PyGameDataStruct.tagDBPyCouple()
        coupleData.PlayerIDA = reqPlayerID
        coupleData.PlayerNameA = reqPlayerName
        coupleData.PlayerIDB = playerID
        coupleData.PlayerNameB = playerName
        coupleData.NewMarryTime = curTime
        couple = coupleMgr.AddCouple(reqPlayerID, playerID, coupleData)
        
        # 更新社交关系
        socialPlayer = PyDataManager.GetPersonalSocialManager().GetSocialPlayer(player.GetPlayerID())
        if socialPlayer:
            socialPlayer.SetCoupleInfo(coupleID, coupleName)
            socialPlayer.CheckUpdCouplePriceMaxID(bridePriceID)
        # 通知地图玩家
        dataMsg = [reqPlayerID, coupleID, curTime, bridePriceID]
        # 通知给相关社交人员
        PlayerSocial.NotifySocialCoupleChange(reqPlayerID, playerID)
        PlayerSocial.NotifySocialCoupleChange(playerID, reqPlayerID)
        # 通知地图全局伴侣信息
        PyDataManager.GetDBPyCoupleManager().SendMapServerCoupleInfo([playerID, reqPlayerID])
    else:
        GameWorld.Log("    已婚,再次提亲: PlayerIDA=%s,PlayerIDB=%s, cur reqPlayerID=%s,playerID=%s,bridePriceID=%s"
                      % (couple.coupleData.PlayerIDA, couple.coupleData.PlayerIDB, reqPlayerID, playerID, bridePriceID), playerID)
    couple.coupleData.MarryTime = curTime
    updBuyCountValue = couple.SetBridePriceBuyCount(bridePriceID, couple.GetBridePriceBuyCount(bridePriceID) + 1)
    GameWorld.Log("    updBuyCountValue=%s" % updBuyCountValue, playerID)
    if bridePriceID > couple.BridePriceMaxID:
        couple.BridePriceMaxID = bridePriceID
        GameWorld.Log("    update BridePriceMaxID=%s" % couple.BridePriceMaxID, playerID)
    # 通知玩家
    for player in [reqPlayer, curPlayer]:
        if not player:
            continue
        mapServerCoupleInfo = couple.GetSendMapServerCoupleInfo(player.GetPlayerID())
        dataMsg = [reqPlayerID, bridePriceID, mapServerCoupleInfo]
        MapServer_QueryPlayer_DoLogic_Love(player, "MarrySuccess", dataMsg, playerID)
        Sync_CoupleInfo(player)
        
    # 聘礼奖励发邮件
    playerIDList = [reqPlayerID, playerID]
    paramList = [reqPlayerName, playerName]
    PlayerCompensation.SendMailByKey("MarrySuccess", playerIDList, brideGiftItemInfo, paramList)
    # 通知地图全局伴侣信息
    PlayerSocial.SendMapServerCoupleInfo([playerID, reqPlayerID])
    
    # 新增喜糖
    candyObj = MarryCandy()
@@ -255,11 +561,27 @@
    AddProsperity(candyObj, prosperity)
    
    PyGameData.g_marryCandyInfo[(reqPlayerID, playerID)] = candyObj
    __SortCandy()
    Sync_CandyList(None, [candyObj])
    return True
def __SortCandy():
    PyGameData.g_marryCandySortList = PyGameData.g_marryCandyInfo.values()
    PyGameData.g_marryCandySortList.sort(key=operator.attrgetter("endTime"))
    Sync_CandyList(None, [candyObj])
    return
def SortMarryBreak():
    PyGameData.g_marryBreakSortList = PyGameData.g_marryBreakInfo.values()
    PyGameData.g_marryBreakSortList.sort(key=operator.attrgetter("coupleData.BreakRequestTime"))
    #GameWorld.DebugLog("SortMarryBreak count=%s" % len(PyGameData.g_marryBreakSortList))
    return
def __CheckMarryReqTimeout(reqData):
    ## 检查提亲是否超时
    curTime = int(time.time())
    passSeconds = curTime - reqData.reqTime
    reqSecondCD = IpyGameDataPY.GetFuncCfg("LoveMarry", 1)
    return passSeconds > reqSecondCD
#// B3 16 和平离婚回应 #tagGCMarryBreakResponse
#
@@ -273,103 +595,89 @@
    isOK = clientData.IsOK
    
    playerID = curPlayer.GetPlayerID()
    coupleID = PlayerControl.GetCoupleID(curPlayer)
    if not coupleID:
    couple = PyDataManager.GetDBPyCoupleManager().GetCouple(playerID)
    if not couple:
        GameWorld.Log("没有伴侣,无法回应和离! ", playerID)
        return
    coupleID = couple.GetCoupleID(playerID)
    breakRequestID = couple.GetBreakRequestID()
    if not breakRequestID or coupleID != breakRequestID:
        GameWorld.Log("伴侣没有提出和离,无法回应和离! coupleID=%s,breakRequestID=%s"
                      % (coupleID, breakRequestID), playerID)
        return
    
    if coupleID not in PyGameData.g_marryBreakReqInfo:
        GameWorld.DebugLog("对方没有请求和离,回应无效! coupleID=%s" % coupleID, playerID)
        return
    playerIDA, playerIDB = couple.coupleData.PlayerIDA, couple.coupleData.PlayerIDB
    if (playerIDA, playerIDB) in PyGameData.g_marryBreakInfo:
        PyGameData.g_marryBreakInfo.pop((playerIDA, playerIDB), None)
        SortMarryBreak()
        
    if playerID != PyGameData.g_marryBreakReqInfo[coupleID]:
        GameWorld.DebugLog("非对方没有请求和离对象,回应无效! reqPlayerID=%s,tagPlayerID=%s"
                           % (coupleID, PyGameData.g_marryBreakReqInfo[coupleID]), playerID)
        return
    PyGameData.g_marryBreakReqInfo.pop(coupleID, None)
    if not isOK:
        GameWorld.Log("拒绝和离! coupleID=%s" % coupleID, playerID)
        couple.SetBreakRequestID(0) # 清除和离请求ID
        Sync_CoupleInfo(curPlayer)
        tagPlayer = GameWorld.GetPlayerManager().FindPlayerByID(coupleID)
        if tagPlayer and not PlayerControl.GetIsTJG(tagPlayer):
            Sync_CoupleInfo(tagPlayer)
        PlayerCompensation.SendMailByKey("MarryBreakRefuse", [coupleID], [], [curPlayer.GetName()])
        return
    
    GameWorld.Log("同意和离: coupleID=%s" % coupleID, playerID)
    
    __DoMarryBreak(curPlayer, coupleID)
    __DoMarryBreakLogic(couple, playerID)
    return
def __DoMarryBreak(curPlayer, coupleID):
def __DoMarryBreakLogic(couple, playerID=0):
    ## 执行离婚 
    
    playerID = curPlayer.GetPlayerID()
    __ClearCoupleSocial(curPlayer)
    tagPlayer = GameWorld.GetPlayerManager().FindPlayerByID(coupleID)
    if tagPlayer:
        __ClearCoupleSocial(tagPlayer)
    # 未在线,标记离婚状态,等下次玩家上线处理
    else:
        socialPlayer = PyDataManager.GetPersonalSocialManager().GetSocialPlayer(coupleID)
        if socialPlayer:
            socialPlayer.SetCoupleBreakOffline()
            GameWorld.Log("离婚时伴侣不在线,标记伴侣社交关系已离婚!等下次上线处理! coupleID=%s" % coupleID, playerID)
    # 通知地图全局伴侣信息
    PlayerSocial.SendMapServerCoupleInfo([playerID, coupleID])
    return
def __LoginCheckCouple(curPlayer):
    ## 登录检查是否已被离婚
    playerID = curPlayer.GetPlayerID()
    coupleID = PlayerControl.GetCoupleID(curPlayer)
    if not coupleID:
    if not couple:
        return
    
    socialPlayer = PyDataManager.GetPersonalSocialManager().GetSocialPlayer(playerID)
    if socialPlayer == None or socialPlayer.GetCoupleBreakOffline():
        GameWorld.Log("玩家上线检测到已被离婚,执行解除伴侣关系!coupleID=%s" % coupleID, playerID)
        __ClearCoupleSocial(curPlayer)
    # 上线未同步过地图全局伴侣信息的则同步
    if socialPlayer and not socialPlayer.syncMapCouple and socialPlayer.GetCoupleID():
        PlayerSocial.SendMapServerCoupleInfo([playerID])
    return
def __ClearCoupleSocial(curPlayer):
    ## 清除伴侣社交关系
    playerIDA = couple.coupleData.PlayerIDA
    playerIDB = couple.coupleData.PlayerIDB
    
    coupleID = PlayerControl.GetCoupleID(curPlayer)
    coupleName = ""
    coupleMgr = PyDataManager.GetDBPyCoupleManager()
    
    playerID = curPlayer.GetPlayerID()
    GameWorld.Log("玩家执行解除伴侣关系! coupleID=%s" % coupleID, playerID)
    if coupleID:
        # 亲密度减少
        curFriends = PyDataManager.GetFriendManager().GetFriends(playerID)
        if curFriends != None:
            decIntimacyPer = IpyGameDataPY.GetFuncCfg("LoveMarryBreak", 3)
            updIntimacy = curFriends.AddIntimacyByPer(curPlayer, coupleID, -decIntimacyPer)
            GameWorld.Log("    更新自身与对方亲密度: tagPlayerID=%s,decIntimacyPer=%s,updIntimacy=%s" % (coupleID, decIntimacyPer, updIntimacy), playerID)
    # 通知地图
    dataMsg = []
    MapServer_QueryPlayer_DoLogic_Love(curPlayer, "ClearCoupleSocial", dataMsg, playerID)
    # 清社交关系 - 由地图清除后同步更新
    PlayerControl.SetCoupleID(curPlayer, 0)
    socialPlayer = PyDataManager.GetPersonalSocialManager().GetSocialPlayer(playerID)
    if socialPlayer:
        coupleName = socialPlayer.playerInfo.CoupleName
        socialPlayer.SetCoupleInfo(0, "")
        socialPlayer.CheckUpdCouplePriceMaxID(0)
    # 亲密度减少
    decIntimacyPer = IpyGameDataPY.GetFuncCfg("LoveMarryBreak", 4)
    if decIntimacyPer:
        PyDataManager.GetIntimacyManager().DelIntimacyBothPer(playerIDA, playerIDB, decIntimacyPer)
        
    # 邮件通知离婚
    playerIDList = [playerID]
    paramList = [coupleName]
    PlayerCompensation.SendMailByKey("MarryBreakOK", playerIDList, [], paramList)
    return
    for pid in [playerIDA, playerIDB]:
        coupleName = couple.GetCoupleName(pid)
        playerIDList = [pid]
        paramList = [coupleName]
        PlayerCompensation.SendMailByKey("MarryBreakOK", playerIDList, [], paramList)
    coupleMgr.DelCouple(playerIDA, playerIDB)
    # 通知地图全局伴侣信息
    PyDataManager.GetDBPyCoupleManager().SendMapServerCoupleInfo([playerIDA, playerIDB])
    # 通知玩家
    dataMsg = []
    for pid in [playerIDA, playerIDB]:
        tagPlayer = GameWorld.GetPlayerManager().FindPlayerByID(pid)
        if tagPlayer and not PlayerControl.GetIsTJG(tagPlayer):
            MapServer_QueryPlayer_DoLogic_Love(tagPlayer, "ClearCoupleSocial", dataMsg, playerID)
            Sync_CoupleInfo(tagPlayer)
    # 通知给相关社交人员
    PlayerSocial.NotifySocialCoupleChange(playerIDA, 0)
    PlayerSocial.NotifySocialCoupleChange(playerIDB, 0)
    if (playerIDA, playerIDB) in PyGameData.g_marryCandyInfo:
        GameWorld.Log("离婚时同步清除喜糖宴会: playerIDA=%s, playerIDB=%s" % (playerIDA, playerIDB), playerID)
        PyGameData.g_marryCandyInfo.pop((playerIDA, playerIDB))
        __SortCandy()
        Sync_CandyList(None)
    if (playerIDA, playerIDB) in PyGameData.g_marryBreakInfo:
        GameWorld.Log("离婚时同步清除和离请求: playerIDA=%s, playerIDB=%s" % (playerIDA, playerIDB), playerID)
        PyGameData.g_marryBreakInfo.pop((playerIDA, playerIDB), None)
        SortMarryBreak()
    return True
def MapServer_Love(curPlayer, msgList):
    mapID = curPlayer.GetRealMapID()
@@ -379,13 +687,13 @@
    
    msgType, dataMsg = msgList
    
    # 送花请求
    if msgType == "SendFlowersReq":
        ret = __CheckSendFlowers(curPlayer, dataMsg)
    # 送礼物请求
    if msgType == "SendGiftsReq":
        ret = __SendGiftsReq(curPlayer, dataMsg)
        
    # 送花OK
    elif msgType == "SendFlowersOK":
        __DoSendFlowersOK(curPlayer, dataMsg)
    # 送礼物
    elif msgType == "SendGiftsOK":
        __DoSendGiftsOK(curPlayer, dataMsg)
        return
    
    # 提亲
@@ -409,63 +717,70 @@
        return
    return msgList + [ret]
def __CheckSendFlowers(curPlayer, dataMsg):
    ## 在线好友可赠送
def __SendGiftsReq(curPlayer, dataMsg):
    ## 送礼物请求
    tagPlayerID = dataMsg[0]
    playerID = curPlayer.GetPlayerID()
    curFriends = PyDataManager.GetFriendManager().GetFriends(playerID)
    if curFriends == None:
        return
    curFriend = curFriends.Find(tagPlayerID)
    if curFriend == None:
        PlayerControl.NotifyCode(curPlayer, "NotFriend")
        return
    
    tagPlayer = GameWorld.GetPlayerManager().FindPlayerByID(tagPlayerID)
    if not tagPlayer or PlayerControl.GetIsTJG(tagPlayer):
        PlayerControl.NotifyCode(curPlayer, "LoveOffline")
    # 黑名单检查
    if PyDataManager.GetBlacklistManager().CheckBlacklistBoth(playerID, tagPlayerID, curPlayer):
        return
    
    return True
def __DoSendFlowersOK(curPlayer, dataMsg):
    ## 送花OK
def __DoSendGiftsOK(curPlayer, dataMsg):
    ## 送礼物
    
    playerID = curPlayer.GetPlayerID()
    playerName = curPlayer.GetName()
    
    tagPlayerID, flowerID, flowerCount, addCharm, addCharmTag, addIntimacy, isWorldNotify = dataMsg
    tagPlayerID, giftNum, giftItemID, giftCount, isAutoBuy = dataMsg
    
    GameWorld.Log("赠送鲜花OK: tagPlayerID=%s,flowerCount=%s,addCharm=%s,addCharmTag=%s,addIntimacy=%s"
                  % (tagPlayerID, flowerCount, addCharm, addCharmTag, addIntimacy), playerID)
    curFriends = PyDataManager.GetFriendManager().GetFriends(playerID)
    if curFriends != None:
        updIntimacy = curFriends.AddIntimacy(curPlayer, tagPlayerID, addIntimacy)
        GameWorld.Log("    增加自身与对方亲密度: tagPlayerID=%s,updIntimacy=%s" % (tagPlayerID, updIntimacy), playerID)
    tagPlayer = GameWorld.GetPlayerManager().FindPlayerByID(tagPlayerID)
    if not tagPlayer or PlayerControl.GetIsTJG(tagPlayer):
    ipyData = IpyGameDataPY.GetIpyGameData("LoveGift", giftNum)
    if not ipyData:
        return
    tagPlayerName = tagPlayer.GetName()
    
    tagFriends = PyDataManager.GetFriendManager().GetFriends(tagPlayerID)
    if tagFriends != None:
        updIntimacy = tagFriends.AddIntimacy(tagPlayer, playerID, addIntimacy)
        GameWorld.Log("    增加对方与自身亲密度: tagPlayerID=%s,updIntimacy=%s" % (tagPlayerID, updIntimacy), playerID)
    addCharmSelf = ipyData.GetAddCharmSelf() * giftCount
    addCharmTag = ipyData.GetAddCharmTag() * giftCount
    addIntimacy = ipyData.GetAddIntimacy() * giftCount
    worldNotifyKey = ipyData.GetWorldNotifyKey()
    GameWorld.Log("赠送礼物: tagPlayerID=%s,giftNum=%s,giftItemID=%s,giftCount=%s,addCharmSelf=%s,addCharmTag=%s,addIntimacy=%s,isAutoBuy=%s"
                  % (tagPlayerID, giftNum, giftItemID, giftCount, addCharmSelf, addCharmTag, addIntimacy, isAutoBuy), playerID)
    tagPlayer = GameWorld.GetPlayerManager().FindPlayerByID(tagPlayerID)
    PyDataManager.GetIntimacyManager().AddIntimacyBoth(playerID, tagPlayerID, addIntimacy)
    PlayerCharm.AddCharm(curPlayer, playerID, playerID, addCharmSelf)
    PlayerCharm.AddCharm(tagPlayer, tagPlayerID, playerID, addCharmTag)
    tagPlayerName = ""
    isOnline = tagPlayer and not PlayerControl.GetIsTJG(tagPlayer)
    if isOnline:
        tagPlayerName = tagPlayer.GetName()
    else:
        tagPlayerName = PlayerSocial.GetSocialPlayerName(tagPlayerID)
        
    if isWorldNotify:
        PlayerControl.WorldNotify(0, "SendFlowers%s" % flowerCount, [playerName, tagPlayerName, flowerCount, flowerID])
    if worldNotifyKey:
        PlayerControl.WorldNotify(0, worldNotifyKey, [playerName, tagPlayerName, giftItemID, giftCount])
        
    dataMsg = [addCharmTag]
    MapServer_QueryPlayer_DoLogic_Love(tagPlayer, "AddCharm", dataMsg, playerID)
    sendTime = int(time.time())
    if not isOnline:
        PyDataManager.GetDBPyUnNotifyLoveGiftRecManager().AddUnNotifyGiftRec(tagPlayerID, playerID, giftNum, giftCount, sendTime)
        return
    # 通知目标前端送花成功
    clientPack = ChPyNetSendPack.tagGCSendFlowersOK()
    clientPack.PlayerID = playerID
    clientPack.Name = playerName
    clientPack.NameLen = len(clientPack.Name)
    clientPack.FlowerCount = flowerCount
    giftOK = ChPyNetSendPack.tagGCSendGiftsOK()
    giftOK.PlayerID = playerID
    giftOK.Name = playerName
    giftOK.NameLen = len(giftOK.Name)
    giftOK.GiftNum = giftNum
    giftOK.GiftCount = giftCount
    giftOK.SendTime = sendTime
    clientPack = ChPyNetSendPack.tagGCSendGiftsOKList()
    clientPack.SendGiftsOKList = [giftOK]
    clientPack.Count = len(clientPack.SendGiftsOKList)
    NetPackCommon.SendFakePack(tagPlayer, clientPack)
    return
@@ -485,33 +800,30 @@
    ## 成亲通用检查
    
    playerID = curPlayer.GetPlayerID()
    curFriends = PyDataManager.GetFriendManager().GetFriends(playerID)
    if curFriends == None:
        PlayerControl.NotifyCode(curPlayer, "NotFriend") # 非好友
        return
    curFriend = curFriends.Find(tagPlayerID)
    if curFriend == None:
        PlayerControl.NotifyCode(curPlayer, "NotFriend") # 非好友
    # 黑名单检查
    if PyDataManager.GetBlacklistManager().CheckBlacklistBoth(playerID, tagPlayerID, curPlayer):
        return
    
    if not tagPlayer or PlayerControl.GetIsTJG(tagPlayer):
        PlayerControl.NotifyCode(curPlayer, "LoveOffline") # 离线
        return
    
    coupleID = PlayerControl.GetCoupleID(curPlayer)
    if coupleID and coupleID != tagPlayerID:
        PlayerControl.NotifyCode(curPlayer, "TagHaveCouple") # 已经有其他伴侣了
    curCouple = PyDataManager.GetDBPyCoupleManager().GetCouple(playerID)
    if curCouple and curCouple.GetCoupleID(playerID) != tagPlayerID:
        PlayerControl.NotifyCode(curPlayer, "HaveCouple") # 已经有其他伴侣了
        return
    
    tagCoupleID = PlayerControl.GetCoupleID(tagPlayer)
    if tagCoupleID and tagCoupleID != playerID:
        PlayerControl.NotifyCode(curPlayer, "TagHaveCouple") # 已经有其他伴侣了
    tagCouple = PyDataManager.GetDBPyCoupleManager().GetCouple(tagPlayerID)
    if tagCouple and tagCouple.GetCoupleID(tagPlayerID) != playerID:
        PlayerControl.NotifyCode(curPlayer, "TagHaveCouple") # 对方已经有其他伴侣了
        return
    
    # 回应方可不检查亲密度
    if checkIntimacy:
        needIntimacy = IpyGameDataPY.GetFuncCfg("LoveMarry", 2)
        if curFriend.Intimacy < needIntimacy:
        curIntimacys = PyDataManager.GetIntimacyManager().GetIntimacys(playerID)
        if not curIntimacys or curIntimacys.GetTagIntimacy(tagPlayerID) < needIntimacy:
            PlayerControl.NotifyCode(curPlayer, "IntimacyLack", [needIntimacy]) # 亲密度不足
            return
        
@@ -519,7 +831,7 @@
def __DoMarryReq(curPlayer, dataMsg):
    ## 提亲
    tagPlayerID, bridePriceID = dataMsg
    
    tagPlayer = GameWorld.GetPlayerManager().FindPlayerByID(tagPlayerID)
@@ -533,6 +845,34 @@
        PlayerControl.NotifyCode(curPlayer, "MarryReqLimitByCandy") # 喜宴中无法操作
        return
    
    couple = PyDataManager.GetDBPyCoupleManager().GetCouple(playerID)
    if couple:
        coupleID = couple.GetCoupleID(playerID)
        if coupleID != tagPlayerID:
            GameWorld.Log("已成亲伴侣ID不一致,无法提亲! tagPlayerID(%s) != coupleID(%s)" % (tagPlayerID, coupleID), playerID)
            return
        ipyData = IpyGameDataPY.GetIpyGameData("Marry", bridePriceID)
        if not ipyData:
            return
        canBuyMax = ipyData.GetCanBuyCount()
        buyCount = couple.GetBridePriceBuyCount(bridePriceID)
        GameWorld.DebugLog("bridePriceID=%s,buyCount=%s,canBuyMax=%s %s" % (bridePriceID, buyCount, canBuyMax, couple.coupleData.BridePriceState))
        if canBuyMax and buyCount >= canBuyMax:
            GameWorld.Log("聘礼提亲次数不足,无法提亲! bridePriceID=%s,buyCount(%s) >= canBuyMax(%s)"
                          % (bridePriceID, buyCount, canBuyMax), playerID)
            return
    if tagPlayerID in PyGameData.g_marryReqInfo:
        tagReqData = PyGameData.g_marryReqInfo[tagPlayerID]
        if playerID == tagReqData.playerIDB and not __CheckMarryReqTimeout(tagReqData):
            GameWorld.Log("玩家提亲时,目标刚好已经先提过亲,且在有效期内,直接成亲!tagPlayerID=%s" % tagPlayerID, playerID)
            if __DoMarryResponse(curPlayer, tagPlayer, tagPlayerID, 1):
                return
        else:
            GameWorld.DebugLog("对方有提亲,但是对象不一样或已超时! tagPlayerID=%s, timeout=%s" % (tagReqData.playerIDB, __CheckMarryReqTimeout(tagReqData)), playerID)
    curTime = int(time.time())
    if playerID not in PyGameData.g_marryReqInfo:
        reqData = MarryReq()
@@ -631,44 +971,82 @@
def __DoMarryBreakReq(curPlayer, dataMsg):
    ## 离婚请求
    playerID, coupleID, breakType, moneyType, moneyValue = dataMsg
    playerID, breakType, moneyType, moneyValue = dataMsg
    
    gameServerCoupleID = PlayerControl.GetCoupleID(curPlayer)
    socialPlayer = PyDataManager.GetPersonalSocialManager().GetSocialPlayer(playerID)
    socialCoupleID = 0 if not socialPlayer else socialPlayer.GetCoupleID()
    couple = PyDataManager.GetDBPyCoupleManager().GetCouple(playerID)
    if not couple:
        GameWorld.Log("没有伴侣,不需要离婚! ", playerID)
        return
    coupleID = couple.GetCoupleID(playerID)
    
    if not gameServerCoupleID or coupleID != gameServerCoupleID or not socialCoupleID or coupleID != socialCoupleID:
        GameWorld.ErrLog("地图玩家伴侣数据与GameServer不一致,离婚请求时直接通过! gameServerCoupleID=%s,socialCoupleID=%s,mapCoupleID=%s"
                         % (gameServerCoupleID, socialCoupleID, coupleID), playerID)
        __ClearCoupleSocial(curPlayer)
        PlayerSocial.SendMapServerCoupleInfo([playerID])
    curTime = int(time.time())
    # 公共CD
    marryTime = couple.GetMarryTime()
    passTime = curTime - marryTime
    marryBreakCD = IpyGameDataPY.GetFuncCfg("LoveMarryBreak", 1)
    if marryBreakCD and passTime < marryBreakCD:
        GameWorld.Log("距离最近一次成亲离婚等待时间未到,无法请求离婚! marryTime=%s,passTime(%s) < %s"
                      % (GameWorld.ChangeTimeNumToStr(marryTime), passTime, marryBreakCD), playerID)
        return
    
    if (playerID, coupleID) in PyGameData.g_marryCandyInfo or (coupleID, playerID) in PyGameData.g_marryCandyInfo:
        PlayerControl.NotifyCode(curPlayer, "MarryReqLimitByCandy") # 喜宴中无法操作
    # 和离额外限制个人CD
    playerBreakRequestTime = couple.GetPlayerBreakRequestTime(playerID)
    if breakType == 0 and playerBreakRequestTime:
        passTime = curTime - playerBreakRequestTime
        breakReqCD = IpyGameDataPY.GetFuncCfg("LoveMarryBreak", 2)
        if breakReqCD and passTime < breakReqCD:
            GameWorld.Log("距离最近一次请求和离等待时间未到,无法请求离婚! playerBreakRequestTime=%s,passTime(%s) < %s"
                          % (GameWorld.ChangeTimeNumToStr(playerBreakRequestTime), passTime, breakReqCD), playerID)
            return
    if couple.GetBreakRequestID() == coupleID:
        GameWorld.Log("请求离婚时对方已经提出和离了,直接离婚! coupleID=%s,breakRequestID=%s"
                      % (coupleID, couple.GetBreakRequestID()), playerID)
        __DoMarryBreakLogic(couple, playerID)
        return
    
    # 0-和平离婚;1-强制离婚
    if breakType == 0:
        if couple.GetBreakRequestID() != playerID:
            playerIDA, playerIDB = couple.coupleData.PlayerIDA, couple.coupleData.PlayerIDB
            GameWorld.Log("新增提交和离! coupleID=%s" % coupleID, playerID)
            couple.SetBreakRequestID(playerID)
            PyGameData.g_marryBreakInfo[(playerIDA, playerIDB)] = couple
            SortMarryBreak()
            playerBreakRequestTime = couple.GetPlayerBreakRequestTime(playerID)
        else:
            GameWorld.Log("重复提交和离! coupleID=%s" % coupleID, playerID)
        Sync_CoupleInfo(curPlayer)
        tagPlayer = GameWorld.GetPlayerManager().FindPlayerByID(coupleID)
        if not tagPlayer or PlayerControl.GetIsTJG(tagPlayer):
            PlayerControl.NotifyCode(curPlayer, "LoveOffline") # 离线
            return
        clientPack = ChPyNetSendPack.tagGCMarryBreakInfo()
        clientPack.PlayerID = playerID
        clientPack.PlayerName = curPlayer.GetName()
        clientPack.NameLen = len(clientPack.PlayerName)
        NetPackCommon.SendFakePack(tagPlayer, clientPack)
        PyGameData.g_marryBreakReqInfo[playerID] = coupleID
        if tagPlayer and not PlayerControl.GetIsTJG(tagPlayer):
            Sync_CoupleInfo(tagPlayer)
        return
    
    GameWorld.Log("强制离婚: coupleID=%s" % coupleID, playerID)
    __DoMarryBreak(curPlayer, coupleID)
    __DoMarryBreakLogic(couple, playerID)
    
    return moneyType, moneyValue
def Sync_CoupleInfo(curPlayer):
    ## 同步伴侣信息
    playerID = curPlayer.GetPlayerID()
    clientPack = ChPyNetSendPack.tagGCCoupleInfo()
    curCouple = PyDataManager.GetDBPyCoupleManager().GetCouple(playerID)
    if curCouple:
        clientPack.CoupleID = curCouple.GetCoupleID(playerID)
        clientPack.CoupleName = curCouple.GetCoupleName(playerID)
        clientPack.NameLen = len(clientPack.CoupleName)
        clientPack.NewMarryTime = curCouple.GetNewMarryTime()
        clientPack.MarryTime = curCouple.GetMarryTime()
        clientPack.BridePriceState = curCouple.GetBridePriceState()
        clientPack.BreakRequestID = curCouple.GetBreakRequestID()
        clientPack.BreakRequestTime = curCouple.GetBreakRequestTime()
        clientPack.PlayerBreakRequestTime = curCouple.GetPlayerBreakRequestTime(playerID)
    NetPackCommon.SendFakePack(curPlayer, clientPack)
    return
def Sync_CandyList(curPlayer, syncCandyList=None):
    if syncCandyList == None:
        syncCandyList = PyGameData.g_marryCandySortList
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerSocial.py
@@ -139,8 +139,10 @@
            inPack = ChPyNetSendPack.tagGCGroupPlayer()
            inPack.PlayerID = player.TagID
            
            inPack.SortValue = player.Timestamp if hasattr(player, 'Timestamp') else 0
            inPack.Intimacy = player.Intimacy if hasattr(player, 'Intimacy') else 0
            if hasattr(player, 'Intimacy'):
                inPack.SortValue = player.Intimacy
            else:
                inPack.SortValue = player.Timestamp if hasattr(player, 'Timestamp') else 0
            pack.Players.append(inPack)
            
        pack.Count = len(pack.Players)
@@ -196,48 +198,7 @@
        self.Delete(delFriendID)
        curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(self.PlayerID)
        self.MapServer_SyncFriendInfo(curPlayer)
    def AddIntimacy(self, curPlayer, friendID, addValue):
        ## 增加亲密度 - 支持正负
        if friendID not in self.SocialDict:
            return 0
        friendObj = self.SocialDict[friendID]
        friendObj.Intimacy += addValue
        friendObj.Intimacy = max(0, min(friendObj.Intimacy, ShareDefine.Def_UpperLimit_DWord))
        
        if not curPlayer:
            return friendObj.Intimacy
        friendName = ""
        socialPlayer = PyDataManager.GetPersonalSocialManager().GetSocialPlayer(friendID)
        if socialPlayer:
            friendName = socialPlayer.playerInfo.PlayerName
        if addValue > 0:
            PlayerControl.NotifyCode(curPlayer, "AddIntimacy", [friendName, addValue])
        self.Sync_SocialsInfo(curPlayer, [friendID])
        return friendObj.Intimacy
    def AddIntimacyByPer(self, curPlayer, friendID, addPer):
        ## 增加亲密度 - 根据百分比,支持正负
        if friendID not in self.SocialDict:
            return 0
        friendObj = self.SocialDict[friendID]
        addValue = int(friendObj.Intimacy * addPer / 100.0)
        return self.AddIntimacy(curPlayer, friendID, addValue)
    def SetIntimacy(self, curPlayer, friendID, setValue):
        ## 直接设置亲密度 - 一般GM测试使用
        if friendID not in self.SocialDict:
            return
        friendObj = self.SocialDict[friendID]
        friendObj.Intimacy = setValue
        if curPlayer:
            self.Sync_SocialsInfo(curPlayer, [friendID])
        return friendObj.Intimacy
    # 通知地图好友信息
    def MapServer_SyncFriendInfo(self, curPlayer):
        return
@@ -334,6 +295,144 @@
            self.PlayerFriends[playerFriend.PlayerID].SocialDict[playerFriend.TagID] = playerFriend
            
            AddBeSocial(playerFriend.TagID, playerFriend.PlayerID)
        return pos
#-------------------亲密------------------------------
# 某个玩家的亲密组管理
class Intimacys(SocialPlayers):
    def __init__(self, PlayerID):
        super(Intimacys, self).__init__(PlayerID, PyGameDataStruct.tagDBPyPlayerIntimacy,
                                        ChConfig.Def_SocialGroup_Intimacy)
    def GetIntimacyObj(self, tagID):
        if tagID not in self.SocialDict:
            self.Add(tagID)
        return self.SocialDict.get(tagID)
    def GetTagIntimacy(self, tagID):
        intimacyObj = self.Find(tagID)
        return intimacyObj.Intimacy if intimacyObj else 0
    def AddIntimacy(self, curPlayer, tagID, addValue):
        ## 增加亲密度 - 支持正负、支持离线, curPlayer 可能为None
        intimacyObj = self.GetIntimacyObj(tagID)
        if not intimacyObj:
            return 0
        if not intimacyObj.Intimacy and addValue < 0:
            return 0
        intimacyObj.Intimacy = min(max(0, intimacyObj.Intimacy + addValue), ShareDefine.Def_UpperLimit_DWord)
        nowIntimacy = intimacyObj.Intimacy
        if nowIntimacy <= 0:
            self.Delete(tagID)
        if not curPlayer:
            return nowIntimacy
        tagName = ""
        socialPlayer = PyDataManager.GetPersonalSocialManager().GetSocialPlayer(tagID)
        if socialPlayer:
            tagName = socialPlayer.playerInfo.PlayerName
        if addValue > 0:
            PlayerControl.NotifyCode(curPlayer, "AddIntimacy", [tagName, addValue])
        elif addValue < 0:
            PlayerControl.NotifyCode(curPlayer, "DelIntimacy", [tagName, abs(addValue)])
        self.Sync_SocialsInfo(curPlayer, [tagID])
        return nowIntimacy
    def SetIntimacy(self, curPlayer, tagID, setValue):
        ## 直接设置亲密度 - 一般GM测试使用
        intimacyObj = self.GetIntimacyObj(tagID)
        if not intimacyObj:
            return 0
        intimacyObj.Intimacy = setValue
        if curPlayer:
            self.Sync_SocialsInfo(curPlayer, [tagID])
        return intimacyObj.Intimacy
# 整个游戏的亲密管理
class IntimacyManager(object):
    def __init__(self):
        self.PlayerIntimacys = {}     # PyGameDataStruct.tagDBPyPlayerIntimacy
        return
    # 增加双方亲密度
    def AddIntimacyBoth(self, aID, bID, addValue):
        for playerID, tagPlayerID in {aID:bID, bID:aID}.items():
            intimacys = self.GetIntimacys(playerID)
            if not intimacys:
                continue
            intimacyObj = intimacys.GetIntimacyObj(tagPlayerID)
            if not intimacyObj:
                continue
            curIntimacy = intimacyObj.Intimacy
            curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
            updIntimacy = intimacys.AddIntimacy(curPlayer, tagPlayerID, addValue)
            GameWorld.DebugLog("增加亲密度: playerID=%s,tagPlayerID=%s,curIntimacy=%s,addValue=%s,updIntimacy=%s"
                               % (playerID, tagPlayerID, curIntimacy, addValue, updIntimacy), playerID)
        return
    # 扣除双方亲密度 - 按百分比
    def DelIntimacyBothPer(self, aID, bID, delPer):
        for playerID, tagPlayerID in {aID:bID, bID:aID}.items():
            intimacys = self.GetIntimacys(playerID)
            if not intimacys:
                continue
            intimacyObj = intimacys.GetIntimacyObj(tagPlayerID)
            if not intimacyObj:
                continue
            curIntimacy = intimacyObj.Intimacy
            delValue = -max(1, int(curIntimacy * delPer / 100.0))
            curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
            updIntimacy = intimacys.AddIntimacy(curPlayer, tagPlayerID, delValue)
            GameWorld.DebugLog("扣除亲密度: playerID=%s,tagPlayerID=%s,curIntimacy=%s,delPer=%s,delValue=%s,updIntimacy=%s"
                               % (playerID, tagPlayerID, curIntimacy, delPer, delValue, updIntimacy), playerID)
        return
    # 获取亲密组
    def GetIntimacys(self, playerID):
        if playerID not in self.PlayerIntimacys:
            self.PlayerIntimacys[playerID] = Intimacys(playerID)
        return self.PlayerIntimacys[playerID]
    # 保存亲密数据 存数据库和realtimebackup
    def GetSaveData(self):
        savaData = ""
        cntData = ""
        cnt = 0
        for intimacys in self.PlayerIntimacys.values():
            for playerIntimacy in intimacys.SocialDict.values():
                cnt += 1
                savaData += playerIntimacy.getBuffer()
        GameWorld.Log("Save DBPyPlayerIntimacy cnt :%s len=%s" % (cnt, len(savaData)))
        return CommFunc.WriteDWORD(cntData, cnt) + savaData
    # 从数据库载入亲密数据
    def LoadPyGameData(self, datas, pos, dataslen):
        cnt, pos = CommFunc.ReadDWORD(datas, pos)
        GameWorld.Log("Load DBPyPlayerIntimacy cnt :%s"%cnt)
        self.PlayerIntimacys = {}
        for i in xrange(cnt):
            playerIntimacy = PyGameDataStruct.tagDBPyPlayerIntimacy()
            playerIntimacy.clear()
            pos += playerIntimacy.readData(datas, pos, dataslen)
            playerID = playerIntimacy.PlayerID
            if playerID not in self.PlayerIntimacys:
                self.PlayerIntimacys[playerID] = Intimacys(playerID)
            self.PlayerIntimacys[playerID].SocialDict[playerIntimacy.TagID] = playerIntimacy
            AddBeSocial(playerIntimacy.TagID, playerIntimacy.PlayerID)
        return pos
    
#-------------------仇人------------------------------
@@ -696,7 +795,6 @@
class SocialPlayerData(object):
    def __init__(self, playerSocial = None, player = None):
        self.playerInfo = PyGameDataStruct.tagPersonalSocial()
        self.syncMapCouple = 0 # 是否已经同步过地图全局伴侣信息
        
        if playerSocial:
            self.playerInfo = playerSocial
@@ -712,7 +810,6 @@
        self.playerInfo.LV = curPlayer.GetLV()
        self.playerInfo.RealmLV = curPlayer.GetOfficialRank()
        self.playerInfo.OnlineType = 1      # 0 不在线  1 在线 2 脱机在线  
        self.playerInfo.CoupleID = PlayerControl.GetCoupleID(curPlayer)
        if not self.playerInfo.RefCount:
            self.playerInfo.RefCount = 1
        return
@@ -725,38 +822,7 @@
        packStruct.LV = self.playerInfo.LV
        packStruct.RealmLV = self.playerInfo.RealmLV
        packStruct.OnlineType = self.playerInfo.OnlineType
        packStruct.CoupleID = self.GetCoupleID()
        return packStruct
    def GetCoupleID(self): return 0 if self.GetCoupleBreakOffline() else self.playerInfo.CoupleID
    def GetCoupleName(self): return "" if not self.GetCoupleID() else self.playerInfo.CoupleName
    def SetCoupleInfo(self, coupleID, coupleName):
        self.playerInfo.CoupleBreakOffline = 0
        self.playerInfo.CoupleID = coupleID
        self.playerInfo.CoupleName = coupleName
        Notify_All(self.playerInfo.PlayerID, IPY_PlayerDefine.CDBPlayerRefresh_ExAttr11, coupleID)
        return
    def GetBridePriceMaxID(self): return self.playerInfo.CouplePriceMaxID
    def CheckUpdCouplePriceMaxID(self, bridePriceID):
        if bridePriceID > 0 and bridePriceID <= self.playerInfo.CouplePriceMaxID:
            GameWorld.Log("不更新社交最高聘礼ID: bridePriceID=%s,self.playerInfo.CouplePriceMaxID=%s"
                          % (bridePriceID, self.playerInfo.CouplePriceMaxID), self.playerInfo.PlayerID)
            return
        self.playerInfo.CouplePriceMaxID = bridePriceID
        GameWorld.Log("更新社交最高聘礼ID: bridePriceID=%s" % (bridePriceID), self.playerInfo.PlayerID)
        return
    def GetCoupleBreakOffline(self):
        ## 是否离线状态下被离婚,等待下次上线处理
        return self.playerInfo.CoupleBreakOffline == 1
    def SetCoupleBreakOffline(self):
        ## 设置离线状态下被离婚,是的话将在玩家下次上线后处理解除相关伴侣关系,因为离线状态下无法处理,故做个标记等待上线处理
        self.playerInfo.CoupleBreakOffline = 1
        GameWorld.Log("离线状态下被离婚,标记伴侣社交关系已离婚!等下次上线处理! coupleID=%s" % self.playerInfo.CoupleID, self.playerInfo.PlayerID)
        return
    
    # 更新玩家数据引用, 根据需求是否更新玩家数据
    def AddSocialRef(self, curPlayer = None):
@@ -803,7 +869,6 @@
            playerSocial.LV = 1
            playerSocial.RealmLV = 1
            playerSocial.OnlineType = ChConfig.Def_Offline
            playerSocial.CoupleID = 0
        else:
            cacheDict = PlayerViewCache.GetCachePropDataDict(curCache)
    
@@ -814,7 +879,6 @@
            playerSocial.LV = cacheDict["LV"]
            playerSocial.RealmLV = cacheDict["RealmLV"]
            playerSocial.OnlineType = ChConfig.Def_Offline
            playerSocial.CoupleID = cacheDict.get("CoupleID", 0)
            
        self.SocialInfo[playerID] = SocialPlayerData(playerSocial)
        socialPlayer = self.SocialInfo[playerID]
@@ -831,11 +895,30 @@
        socialPlayer.SubSocialRef()
        if socialPlayer.GetRefCount() <= 0:
            self.SocialInfo.pop(delPlayerID)
    
    def GetSocialPlayer(self, playerID):
        return self.SocialInfo.get(playerID, None)
    
    def SyncSocialCoupleInfo(self, curPlayer):
        coupleMgr = PyDataManager.GetDBPyCoupleManager()
        coupleList = []
        for playerID in self.SocialInfo.keys():
            couple = coupleMgr.GetCouple(playerID)
            if not couple:
                continue
            socialCouple = ChPyNetSendPack.tagGCSocialCouple()
            socialCouple.PlayerID = playerID
            socialCouple.CoupleID = couple.GetCoupleID(playerID)
            coupleList.append(socialCouple)
        if not coupleList:
            return
        clientPack = ChPyNetSendPack.tagGCSocialCouples()
        clientPack.Player = coupleList
        clientPack.Count = len(clientPack.Player)
        NetPackCommon.SendFakePack(curPlayer, clientPack)
        return
    
    # 保存有社交的玩家信息
    def GetSaveData(self):
@@ -864,6 +947,38 @@
                
        return pos
def GetSocialPlayerName(playerID):
    ## 获取玩家社交昵称
    socialPlayer = PyDataManager.GetPersonalSocialManager().GetSocialPlayer(playerID)
    if socialPlayer:
        return socialPlayer.playerInfo.PlayerName
    curCache = PlayerViewCache.FindViewCache(playerID)
    if curCache:
        cacheDict = PlayerViewCache.GetCachePropDataDict(curCache)
        return cacheDict["Name"]
    if playerID < 10000:
        return "testName%s" % playerID
    return ""
def GetSocialPlayerJob(playerID):
    ## 获取玩家社交职业
    socialPlayer = PyDataManager.GetPersonalSocialManager().GetSocialPlayer(playerID)
    if socialPlayer:
        return socialPlayer.playerInfo.Job
    curCache = PlayerViewCache.FindViewCache(playerID)
    if curCache:
        cacheDict = PlayerViewCache.GetCachePropDataDict(curCache)
        return cacheDict["Job"]
    if playerID < 10000:
        job = 2 if playerID % 2 == 0 else 1
        return job
    return 1
# 向相关联的社交对象通知当前玩家信息
# 最近联系人、仇人和黑名单存在单向情况, 向对方通知信息
@@ -893,8 +1008,32 @@
        if PlayerControl.GetIsTJG(player):
            continue
        NetPackCommon.SendFakePack(player, pack)
    return
def NotifySocialCoupleChange(playerID, coupleID):
    ## 通知伴侣变更给相关社交人员
    if playerID not in PyGameData.g_BeSocialList:
        return
    couple = ChPyNetSendPack.tagGCSocialCouple()
    couple.PlayerID = playerID
    couple.CoupleID = coupleID
    clientPack = ChPyNetSendPack.tagGCSocialCouples()
    clientPack.Player.append(couple)
    clientPack.Count = len(clientPack.Player)
    for tagID in PyGameData.g_BeSocialList[playerID]:
        player = GameWorld.GetPlayerManager().FindPlayerByID(tagID)
        if not player:
            continue
        if PlayerControl.GetIsTJG(player):
            continue
        NetPackCommon.SendFakePack(player, clientPack)
    return
#更新玩家社交信息
def UpdateSocialInfo(playerID, notifyType, value):
@@ -908,39 +1047,8 @@
        socialPlayer.playerInfo.RealmLV = value
    elif notifyType == IPY_PlayerDefine.CDBPlayerRefresh_PlayerName:
        socialPlayer.playerInfo.PlayerName = value
        coupleID = socialPlayer.playerInfo.CoupleID
        if coupleID:
            coupleSocialPlayer = PyDataManager.GetPersonalSocialManager().GetSocialPlayer(coupleID)
            if coupleSocialPlayer:
                coupleSocialPlayer.playerInfo.CoupleName = value
                SendMapServerCoupleInfo([coupleID])
    Notify_All(playerID, notifyType, value)
    return
def SendMapServerCoupleInfo(syncPlayerIDList=None):
    checkState = False
    syncCoupleInfo = {}
    socialMgr = PyDataManager.GetPersonalSocialManager()
    if syncPlayerIDList == None:
        syncPlayerIDList = socialMgr.SocialInfo.keys()
        checkState = True # 未指定时才检查,防止启动地图时同步过多(启动地图时,只同步本次已经同步过的)
    for playerID in syncPlayerIDList:
        socialPlayer = socialMgr.GetSocialPlayer(playerID)
        if not socialPlayer:
            continue
        coupleID = socialPlayer.GetCoupleID()
        if checkState:
            if not socialPlayer.syncMapCouple:
                continue
            if not coupleID:
                continue
        socialPlayer.syncMapCouple = 1
        coupleName = socialPlayer.GetCoupleName()
        syncCoupleInfo[playerID] = [coupleID, coupleName] if coupleID else []
    GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_CoupleInfo, syncCoupleInfo)
    return
# 向当前玩家通知相关联的所有玩家信息
@@ -954,9 +1062,11 @@
    list3 = contacts.SocialDict.keys() if contacts else []
    blacklists = PyDataManager.GetBlacklistManager().GetBlacklist(playerID)
    list4 = blacklists.SocialDict.keys() if blacklists else []
    intimacys = PyDataManager.GetIntimacyManager().GetIntimacys(playerID)
    list5 = intimacys.SocialDict.keys() if intimacys else []
    #信息并集后发送, 玩家ID
    resultSet = set(list1)|set(list2)|set(list3)|set(list4)
    resultSet = set(list1)|set(list2)|set(list3)|set(list4)|set(list5)
    
    sendPack = ChPyNetSendPack.tagGCSocialPlayers()
    sendPack.Clear()
@@ -971,6 +1081,8 @@
        
    sendPack.Count = len(sendPack.Player)
    NetPackCommon.SendFakePack(curPlayer, sendPack)
    socialManager.SyncSocialCoupleInfo(curPlayer)
    return
    
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerTalk.py
@@ -453,12 +453,13 @@
    # 等级
    extraValueStr += GetTalkExtraValueStar(ShareDefine.Def_TalkExtraValue_Bit_LV) % player.GetLV()
    # 伴侣信息
    coupleName, bridePriceMaxID = "", 0
    socialPlayer = PyDataManager.GetPersonalSocialManager().GetSocialPlayer(playerID)
    if socialPlayer and socialPlayer.GetCoupleID():
        coupleName = socialPlayer.GetCoupleName()
        bridePriceMaxID = socialPlayer.GetBridePriceMaxID()
    extraValueStr = "%s|%s|%s" % (extraValueStr, coupleName, bridePriceMaxID)
    coupleName, coupleJob, bridePriceMaxID = "", 1, 0
    couple = PyDataManager.GetDBPyCoupleManager().GetCouple(playerID)
    if couple:
        coupleName = couple.GetCoupleName(playerID)
        coupleJob = couple.GetCoupleJob(playerID)
        bridePriceMaxID = couple.BridePriceMaxID
    extraValueStr = "%s|%s|%s|%s" % (extraValueStr, coupleName, coupleJob, bridePriceMaxID)
    return extraValueStr
ServerPython/CoreServerGroup/GameServer/Script/PyDataManager.py
@@ -28,6 +28,8 @@
import PlayerAssist
import PyGameDataStruct
import IpyGameDataPY
import PlayerCharm
import PlayerLove
import CommFunc
import time
@@ -307,6 +309,10 @@
class PyGameDataManager(object):
    def __init__(self):
        self.DBPyCoupleManager = PlayerLove.DBPyCoupleManager()
        self.DBPyUnNotifyLoveGiftRecManager = PlayerLove.DBPyUnNotifyLoveGiftRecManager()
        self.DBPyCharmValueRecManager = PlayerCharm.DBPyCharmValueRecManager()
        self.IntimacyManager = PlayerSocial.IntimacyManager()
        self.CrossPersonalCompensationManager = PlayerCompensation.CrossPersonalCompensationManager()
        self.CrossBillboardManager = CrossBillboard.CrossBillboardManager()
        self.PlayerAssistThanksPyManager = PlayerAssistThanksPyManager()
@@ -332,6 +338,10 @@
    def GetSaveData(self):
        buff = ""
        buff += self.DBPyCoupleManager.GetSaveData()
        buff += self.DBPyUnNotifyLoveGiftRecManager.GetSaveData()
        buff += self.DBPyCharmValueRecManager.GetSaveData()
        buff += self.IntimacyManager.GetSaveData()
        buff += self.CrossPersonalCompensationManager.GetSaveData()
        buff += self.CrossBillboardManager.GetSaveData()
        buff += self.PlayerAssistThanksPyManager.GetSaveData()
@@ -356,6 +366,10 @@
        return buff
    
    def LoadGameData(self, gameBuffer, pos):
        pos = self.DBPyCoupleManager.LoadPyGameData(gameBuffer, pos, len(gameBuffer))
        pos = self.DBPyUnNotifyLoveGiftRecManager.LoadPyGameData(gameBuffer, pos, len(gameBuffer))
        pos = self.DBPyCharmValueRecManager.LoadPyGameData(gameBuffer, pos, len(gameBuffer))
        pos = self.IntimacyManager.LoadPyGameData(gameBuffer, pos, len(gameBuffer))
        pos = self.CrossPersonalCompensationManager.LoadPyGameData(gameBuffer, pos, len(gameBuffer))
        pos = self.CrossBillboardManager.LoadPyGameData(gameBuffer, pos, len(gameBuffer))
        pos = self.PlayerAssistThanksPyManager.LoadPyGameData(gameBuffer, pos, len(gameBuffer))
@@ -467,6 +481,26 @@
    pyGameDataMgr = GetPyGameDataManager()
    return pyGameDataMgr.familyStoreItemManager
def GetDBPyCoupleManager():
    # 伴侣管理
    pyGameDataMgr = GetPyGameDataManager()
    return pyGameDataMgr.DBPyCoupleManager
def GetDBPyUnNotifyLoveGiftRecManager():
    # 未通知的赠送礼物记录
    pyGameDataMgr = GetPyGameDataManager()
    return pyGameDataMgr.DBPyUnNotifyLoveGiftRecManager
def GetDBPyCharmValueRecManager():
    # 魅力管理
    pyGameDataMgr = GetPyGameDataManager()
    return pyGameDataMgr.DBPyCharmValueRecManager
def GetIntimacyManager():
    # 亲密管理
    pyGameDataMgr = GetPyGameDataManager()
    return pyGameDataMgr.IntimacyManager
# 好友系统
def GetFriendManager():
    pyGameDataMgr = GetPyGameDataManager()
ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py
@@ -89,8 +89,9 @@
g_marryReqInfo = {} # 当前进行中的求亲信息 {请求玩家ID:MarryReq, ...}
g_marryCandyInfo = {} # 进行中的喜糖信息 {(playerIDA, playerIDB):MarryCandy, ...}
g_marryCandySortList = [] # 按结算时间排序后的喜糖列表
g_marryBreakReqInfo = {} # 请求离婚信息 {reqPlayerID:tagPlayerID, ...}
g_marryCandySortList = [] # 按结算时间排序后的喜糖列表,升序
g_marryBreakInfo = {} # 进行中的离婚信息{(playerIDA, playerIDB):MarryCandy, ...}
g_marryBreakSortList = [] # 按提交时间排序后的喜糖列表,升序
g_arenaPlayerBattleRecDict = {} # 本服竞技场玩家挑战记录缓存 {playerID:[ArenaBattleRec, ...], ...}
g_arenaPlayerMatchDict = {} # 本服竞技场玩家匹配记录缓存 {playerID:[ArenaMatchPlayer, ...], ...}
ServerPython/CoreServerGroup/GameServer/Script/PyGameDataStruct.py
@@ -2121,7 +2121,6 @@
    _fields_ = [
        ('PlayerID', ctypes.c_ulong),
        ('TagID', ctypes.c_ulong),
        ('Intimacy', ctypes.c_ulong),
        ('ADOResult', ctypes.c_ulong),
    ]
@@ -2141,7 +2140,6 @@
        self.clear()
        self.PlayerID, pos = CommFunc.ReadDWORD(buf, pos)
        self.TagID, pos = CommFunc.ReadDWORD(buf, pos)
        self.Intimacy, pos = CommFunc.ReadDWORD(buf, pos)
        return self.getLength()
@@ -2157,12 +2155,10 @@
        output = '''//玩家好友表#tagDBPyPlayerFriend:
            PlayerID = %s,
            TagID = %s,
            Intimacy = %s,
            ADOResult = %s,
            '''%(
                self.PlayerID,
                self.TagID,
                self.Intimacy,
                self.ADOResult,
            )
        return output
@@ -2232,10 +2228,6 @@
        ('RealmLV', ctypes.c_ushort),
        ('OnlineType', ctypes.c_ubyte),
        ('RefCount', ctypes.c_ulong),
        ('CoupleID', ctypes.c_ulong),
        ('CoupleName', ctypes.c_char * 33),
        ('CouplePriceMaxID', ctypes.c_ubyte),
        ('CoupleBreakOffline', ctypes.c_ubyte),
        ('ADOResult', ctypes.c_ulong),
    ]
@@ -2260,10 +2252,6 @@
        self.RealmLV, pos = CommFunc.ReadWORD(buf, pos)
        self.OnlineType, pos = CommFunc.ReadBYTE(buf, pos)
        self.RefCount, pos = CommFunc.ReadDWORD(buf, pos)
        self.CoupleID, pos = CommFunc.ReadDWORD(buf, pos)
        self.CoupleName, pos = CommFunc.ReadString(buf, pos, 33)
        self.CouplePriceMaxID, pos = CommFunc.ReadBYTE(buf, pos)
        self.CoupleBreakOffline, pos = CommFunc.ReadBYTE(buf, pos)
        return self.getLength()
@@ -2284,10 +2272,6 @@
            RealmLV = %s,
            OnlineType = %s,
            RefCount = %s,
            CoupleID = %s,
            CoupleName = %s,
            CouplePriceMaxID = %s,
            CoupleBreakOffline = %s,
            ADOResult = %s,
            '''%(
                self.PlayerID,
@@ -2297,10 +2281,6 @@
                self.RealmLV,
                self.OnlineType,
                self.RefCount,
                self.CoupleID,
                self.CoupleName,
                self.CouplePriceMaxID,
                self.CoupleBreakOffline,
                self.ADOResult,
            )
        return output
@@ -2311,11 +2291,256 @@
            self.PlayerName = Str
        else:
            self.PlayerName = Str[:33]
    def SetCoupleName(self,Str):
        if len(Str)<=33:
            self.CoupleName = Str
        else:
            self.CoupleName = Str[:33]
# 玩家亲密表 #tagDBPyPlayerIntimacy
class tagDBPyPlayerIntimacy(Structure):
    _pack_ = 1
    _fields_ = [
        ('PlayerID', ctypes.c_ulong),
        ('TagID', ctypes.c_ulong),
        ('Intimacy', ctypes.c_ulong),
        ('ADOResult', ctypes.c_ulong),
    ]
    def __init__(self):
        Structure.__init__(self)
        self.clear()
    def clear(self):
        memset(addressof(self), 0, self.getLength())
    def readData(self, buf, pos = 0, length = 0):
        if not pos <= length:
            return -1
        if len(buf) < pos + self.getLength():
            return -1
        self.clear()
        self.PlayerID, pos = CommFunc.ReadDWORD(buf, pos)
        self.TagID, pos = CommFunc.ReadDWORD(buf, pos)
        self.Intimacy, pos = CommFunc.ReadDWORD(buf, pos)
        return self.getLength()
    def getBuffer(self):
        buf = create_string_buffer(self.getLength())
        memmove(addressof(buf), addressof(self), self.getLength())
        return string_at(addressof(buf), self.getLength())
    def getLength(self):
        return sizeof(tagDBPyPlayerIntimacy)
    def outputString(self):
        output = '''// 玩家亲密表 #tagDBPyPlayerIntimacy:
            PlayerID = %s,
            TagID = %s,
            Intimacy = %s,
            ADOResult = %s,
            '''%(
                self.PlayerID,
                self.TagID,
                self.Intimacy,
                self.ADOResult,
            )
        return output
# 魅力贡献值记录表 #tagDBPyCharmValueRec
class tagDBPyCharmValueRec(Structure):
    _pack_ = 1
    _fields_ = [
        ('PlayerID', ctypes.c_ulong),
        ('Type', ctypes.c_ubyte),
        ('OfferPlayerID', ctypes.c_ulong),
        ('CharmValue', ctypes.c_ulong),
        ('UpdTime', ctypes.c_ulong),
        ('ADOResult', ctypes.c_ulong),
    ]
    def __init__(self):
        Structure.__init__(self)
        self.clear()
    def clear(self):
        memset(addressof(self), 0, self.getLength())
    def readData(self, buf, pos = 0, length = 0):
        if not pos <= length:
            return -1
        if len(buf) < pos + self.getLength():
            return -1
        self.clear()
        self.PlayerID, pos = CommFunc.ReadDWORD(buf, pos)
        self.Type, pos = CommFunc.ReadBYTE(buf, pos)
        self.OfferPlayerID, pos = CommFunc.ReadDWORD(buf, pos)
        self.CharmValue, pos = CommFunc.ReadDWORD(buf, pos)
        self.UpdTime, pos = CommFunc.ReadDWORD(buf, pos)
        return self.getLength()
    def getBuffer(self):
        buf = create_string_buffer(self.getLength())
        memmove(addressof(buf), addressof(self), self.getLength())
        return string_at(addressof(buf), self.getLength())
    def getLength(self):
        return sizeof(tagDBPyCharmValueRec)
    def outputString(self):
        output = '''// 魅力贡献值记录表 #tagDBPyCharmValueRec:
            PlayerID = %s,
            Type = %s,
            OfferPlayerID = %s,
            CharmValue = %s,
            UpdTime = %s,
            ADOResult = %s,
            '''%(
                self.PlayerID,
                self.Type,
                self.OfferPlayerID,
                self.CharmValue,
                self.UpdTime,
                self.ADOResult,
            )
        return output
# 未通知的情缘送礼记录 #tagDBPyUnNotifyLoveGiftRec
class tagDBPyUnNotifyLoveGiftRec(Structure):
    _pack_ = 1
    _fields_ = [
        ('PlayerID', ctypes.c_ulong),
        ('GivePlayerID', ctypes.c_ulong),
        ('GiftNum', ctypes.c_ushort),
        ('GiftCount', ctypes.c_ulong),
        ('SendTime', ctypes.c_ulong),
        ('ADOResult', ctypes.c_ulong),
    ]
    def __init__(self):
        Structure.__init__(self)
        self.clear()
    def clear(self):
        memset(addressof(self), 0, self.getLength())
    def readData(self, buf, pos = 0, length = 0):
        if not pos <= length:
            return -1
        if len(buf) < pos + self.getLength():
            return -1
        self.clear()
        self.PlayerID, pos = CommFunc.ReadDWORD(buf, pos)
        self.GivePlayerID, pos = CommFunc.ReadDWORD(buf, pos)
        self.GiftNum, pos = CommFunc.ReadWORD(buf, pos)
        self.GiftCount, pos = CommFunc.ReadDWORD(buf, pos)
        self.SendTime, pos = CommFunc.ReadDWORD(buf, pos)
        return self.getLength()
    def getBuffer(self):
        buf = create_string_buffer(self.getLength())
        memmove(addressof(buf), addressof(self), self.getLength())
        return string_at(addressof(buf), self.getLength())
    def getLength(self):
        return sizeof(tagDBPyUnNotifyLoveGiftRec)
    def outputString(self):
        output = '''// 未通知的情缘送礼记录 #tagDBPyUnNotifyLoveGiftRec:
            PlayerID = %s,
            GivePlayerID = %s,
            GiftNum = %s,
            GiftCount = %s,
            SendTime = %s,
            ADOResult = %s,
            '''%(
                self.PlayerID,
                self.GivePlayerID,
                self.GiftNum,
                self.GiftCount,
                self.SendTime,
                self.ADOResult,
            )
        return output
# 伴侣表 #tagDBPyCouple
class tagDBPyCouple(Structure):
    _pack_ = 1
    _fields_ = [
        ('PlayerIDA', ctypes.c_ulong),
        ('PlayerIDB', ctypes.c_ulong),
        ('NewMarryTime', ctypes.c_ulong),
        ('MarryTime', ctypes.c_ulong),
        ('BridePriceState', ctypes.c_ulong),
        ('BreakRequestID', ctypes.c_ulong),
        ('BreakRequestTime', ctypes.c_ulong),
        ('BreakRequestTimeA', ctypes.c_ulong),
        ('BreakRequestTimeB', ctypes.c_ulong),
        ('ADOResult', ctypes.c_ulong),
    ]
    def __init__(self):
        Structure.__init__(self)
        self.clear()
    def clear(self):
        memset(addressof(self), 0, self.getLength())
    def readData(self, buf, pos = 0, length = 0):
        if not pos <= length:
            return -1
        if len(buf) < pos + self.getLength():
            return -1
        self.clear()
        self.PlayerIDA, pos = CommFunc.ReadDWORD(buf, pos)
        self.PlayerIDB, pos = CommFunc.ReadDWORD(buf, pos)
        self.NewMarryTime, pos = CommFunc.ReadDWORD(buf, pos)
        self.MarryTime, pos = CommFunc.ReadDWORD(buf, pos)
        self.BridePriceState, pos = CommFunc.ReadDWORD(buf, pos)
        self.BreakRequestID, pos = CommFunc.ReadDWORD(buf, pos)
        self.BreakRequestTime, pos = CommFunc.ReadDWORD(buf, pos)
        self.BreakRequestTimeA, pos = CommFunc.ReadDWORD(buf, pos)
        self.BreakRequestTimeB, pos = CommFunc.ReadDWORD(buf, pos)
        return self.getLength()
    def getBuffer(self):
        buf = create_string_buffer(self.getLength())
        memmove(addressof(buf), addressof(self), self.getLength())
        return string_at(addressof(buf), self.getLength())
    def getLength(self):
        return sizeof(tagDBPyCouple)
    def outputString(self):
        output = '''// 伴侣表 #tagDBPyCouple:
            PlayerIDA = %s,
            PlayerIDB = %s,
            NewMarryTime = %s,
            MarryTime = %s,
            BridePriceState = %s,
            BreakRequestID = %s,
            BreakRequestTime = %s,
            BreakRequestTimeA = %s,
            BreakRequestTimeB = %s,
            ADOResult = %s,
            '''%(
                self.PlayerIDA,
                self.PlayerIDB,
                self.NewMarryTime,
                self.MarryTime,
                self.BridePriceState,
                self.BreakRequestID,
                self.BreakRequestTime,
                self.BreakRequestTimeA,
                self.BreakRequestTimeB,
                self.ADOResult,
            )
        return output
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
@@ -1615,7 +1615,7 @@
PacketCMD_1=0xB3
PacketSubCMD_1=0x10
PacketCallFunc_1=OnSendFlowers
PacketCallFunc_1=OnSendGifts
PacketCMD_2=0xB3
PacketSubCMD_2=0x11
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
@@ -4170,12 +4170,6 @@
Def_PDict_FuncSysPrivilegeAward = "FuncSysPrivilegeAward_%s" # 系统功能特权领奖记录,参数(系统功能ID)
#情缘
Def_PDict_LoveCharmTotal = "LoveCharmTotal" # 魅力值 - 总
Def_PDict_LoveCharmToday = "LoveCharmToday" # 魅力值 - 今日
Def_PDict_LoveNewMarryTime = "LoveNewMarryTime" # 成亲时间 - 新婚时间
Def_PDict_LoveMarryTime = "LoveMarryTime" # 成亲时间  - 最近一次提亲成功时间
Def_PDict_LoveBridePriceState = "LoveBridePriceState" # 聘礼状态,按聘礼ID位存储每种聘礼已购买次数
Def_PDict_LoveBridePriceMaxID = "LoveBridePriceMaxID" # 提亲最大聘礼ID,用于决定伴侣昵称颜色等
Def_PDict_LoveRingClassLV = "LoveRingClassLV" # 情戒 - 阶级
Def_PDict_LoveRingStarLV = "LoveRingStarLV" # 情戒 - 星级
Def_PDict_LoveRingEatCount = "LoveRingEatCount" # 情戒 - 本星已淬炼道具数
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
@@ -2330,6 +2330,66 @@
#------------------------------------------------------
# B3 09 魅力贡献榜查看 #tagCGCharmOfferBillboardQuery
class  tagCGCharmOfferBillboardQuery(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("PlayerID", c_int),    # 魅力玩家ID
                  ("QueryType", c_ubyte),    # 查看类型: 1-总榜,2-周榜,3-日榜
                  ("QueryCount", c_ubyte),    # 查看名次数量,最大255
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0xB3
        self.SubCmd = 0x09
        return
    def ReadData(self, stringData, _pos=0, _len=0):
        self.Clear()
        memmove(addressof(self), stringData[_pos:], self.GetLength())
        return _pos + self.GetLength()
    def Clear(self):
        self.Cmd = 0xB3
        self.SubCmd = 0x09
        self.PlayerID = 0
        self.QueryType = 0
        self.QueryCount = 0
        return
    def GetLength(self):
        return sizeof(tagCGCharmOfferBillboardQuery)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// B3 09 魅力贡献榜查看 //tagCGCharmOfferBillboardQuery:
                                Cmd:%s,
                                SubCmd:%s,
                                PlayerID:%d,
                                QueryType:%d,
                                QueryCount:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.PlayerID,
                                self.QueryType,
                                self.QueryCount
                                )
        return DumpString
m_NAtagCGCharmOfferBillboardQuery=tagCGCharmOfferBillboardQuery()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCGCharmOfferBillboardQuery.Cmd,m_NAtagCGCharmOfferBillboardQuery.SubCmd))] = m_NAtagCGCharmOfferBillboardQuery
#------------------------------------------------------
# B3 16 和平离婚回应 #tagGCMarryBreakResponse
class  tagGCMarryBreakResponse(Structure):
@@ -4419,15 +4479,17 @@
#------------------------------------------------------
# B3 10 送花 #tagCMSendFlowers
# B3 10 送礼物 #tagCMSendGifts
class  tagCMSendFlowers(Structure):
class  tagCMSendGifts(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("TagPlayerID", c_int),    # 目标玩家ID
                  ("FlowerCount", c_int),    # 赠送花数量
                  ("GiftNum", c_ushort),    # 赠送礼物编号
                  ("GiftCount", c_int),    # 赠送礼物数量
                  ("IsAutoBuy", c_ubyte),    # 是否自动购买
                  ]
    def __init__(self):
@@ -4445,33 +4507,39 @@
        self.Cmd = 0xB3
        self.SubCmd = 0x10
        self.TagPlayerID = 0
        self.FlowerCount = 0
        self.GiftNum = 0
        self.GiftCount = 0
        self.IsAutoBuy = 0
        return
    def GetLength(self):
        return sizeof(tagCMSendFlowers)
        return sizeof(tagCMSendGifts)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// B3 10 送花 //tagCMSendFlowers:
        DumpString = '''// B3 10 送礼物 //tagCMSendGifts:
                                Cmd:%s,
                                SubCmd:%s,
                                TagPlayerID:%d,
                                FlowerCount:%d
                                GiftNum:%d,
                                GiftCount:%d,
                                IsAutoBuy:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.TagPlayerID,
                                self.FlowerCount
                                self.GiftNum,
                                self.GiftCount,
                                self.IsAutoBuy
                                )
        return DumpString
m_NAtagCMSendFlowers=tagCMSendFlowers()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMSendFlowers.Cmd,m_NAtagCMSendFlowers.SubCmd))] = m_NAtagCMSendFlowers
m_NAtagCMSendGifts=tagCMSendGifts()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMSendGifts.Cmd,m_NAtagCMSendGifts.SubCmd))] = m_NAtagCMSendGifts
#------------------------------------------------------
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Event/EventSrc/FunctionNPCCommon.py
@@ -531,7 +531,7 @@
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_DelPackIndex, int(itemIndexs))
    return
def PayAutoBuyItem(curPlayer, lackItemDict, priceType, costType=ChConfig.Def_Cost_Unknown, infoDict={}):
def PayAutoBuyItem(curPlayer, lackItemDict, priceType, costType=ChConfig.Def_Cost_Unknown, infoDict={}, isCheck=False):
    ''' 支付自动购买物品消耗,从商城中购买,直接扣钱,不产生物品
            一般用于基础商店自动购买物品,不考虑复杂的限购逻辑
    '''
@@ -570,6 +570,9 @@
    if totalMoney <= 0:
        return
    
    if isCheck:
        return PlayerControl.HaveMoney(curPlayer, priceType, totalMoney)
    GameWorld.DebugLog("扣除自动购买消耗: lackItemDict=%s,priceType=%s,totalMoney=%s,costType=%s,addLimitCountInfo=%s" 
                       % (lackItemDict, priceType, totalMoney, costType, addLimitCountInfo), curPlayer.GetPlayerID())
    
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Love.py
File was deleted
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/LoveRing.py
New file
@@ -0,0 +1,49 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package GM.Commands.LoveRing
#
# @todo:情戒
# @author hxp
# @date 2021-11-09
# @version 1.0
#
# 详细描述: 情戒
#
#-------------------------------------------------------------------------------
#"""Version = 2021-11-09 20:00"""
#-------------------------------------------------------------------------------
import GameWorld
import PlayerControl
import PlayerLove
import ChConfig
## GM命令执行入口
#  @param curPlayer 当前玩家
#  @param msgList 参数列表 [addSkillID]
#  @return None
#  @remarks 函数详细说明.
def OnExec(curPlayer, msgList):
    if not msgList:
        GameWorld.DebugAnswer(curPlayer, "重置情戒: LoveRing 0")
        GameWorld.DebugAnswer(curPlayer, "设置情戒: LoveRing 阶  [可选星  已吃个数]")
        return
    classLV = msgList[0] if len(msgList) > 0 else 1
    if classLV == 0:
        starLV, eatCount = 0, 0
    else:
        starLV = msgList[1] if len(msgList) > 1 else 1
        eatCount = msgList[2] if len(msgList) > 2 else 0
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveRingClassLV, classLV)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveRingStarLV, starLV)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveRingEatCount, eatCount)
    PlayerLove.Sync_LoveRingInfo(curPlayer)
    PlayerLove.RefreshLoveAttr(curPlayer)
    GameWorld.DebugAnswer(curPlayer, "设置情戒: 阶:%s 星:%s 颗:%s" % (classLV, starLV, eatCount))
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
@@ -1876,11 +1876,15 @@
                        ("BYTE", "QualityLV", 1),
                        ),
                "LoveGift":(
                        ("BYTE", "GiftNum", 1),
                        ("DWORD", "GiftItemID", 0),
                        ("BYTE", "AllowBatch", 0),
                        ),
                "Marry":(
                        ("BYTE", "BridePriceID", 1),
                        ("list", "CostMoneyInfo", 0),
                        ("BYTE", "CanBuyCount", 0),
                        ("BYTE", "IsDayReset", 0),
                        ),
                "LoveRing":(
@@ -5802,20 +5806,29 @@
    def GetPointID(self): return self.PointID # 灵根ID
    def GetQualityLV(self): return self.QualityLV # 品级
# 情缘礼物表
class IPY_LoveGift():
    def __init__(self):
        self.GiftNum = 0
        self.GiftItemID = 0
        self.AllowBatch = 0
        return
    def GetGiftNum(self): return self.GiftNum # 聘礼ID
    def GetGiftItemID(self): return self.GiftItemID # 物品ID
    def GetAllowBatch(self): return self.AllowBatch # 是否允许批量赠送
# 情缘提亲表
class IPY_Marry():
    
    def __init__(self):
        self.BridePriceID = 0
        self.CostMoneyInfo = []
        self.CanBuyCount = 0
        self.IsDayReset = 0
        self.CostMoneyInfo = []
        return
        
    def GetBridePriceID(self): return self.BridePriceID # 聘礼ID
    def GetCostMoneyInfo(self): return self.CostMoneyInfo # 消耗货币类型|数值
    def GetCanBuyCount(self): return self.CanBuyCount # 可购买次数
    def GetIsDayReset(self): return self.IsDayReset # 是否每日重置
    def GetCostMoneyInfo(self): return self.CostMoneyInfo # 消耗货币类型|数值
# 情缘情戒表
class IPY_LoveRing():
@@ -6304,6 +6317,8 @@
        self.ipySkyTowerServerChallengeLen = len(self.ipySkyTowerServerChallengeCache)
        self.ipyLingGenEffectCache = self.__LoadFileData("LingGenEffect", IPY_LingGenEffect)
        self.ipyLingGenEffectLen = len(self.ipyLingGenEffectCache)
        self.ipyLoveGiftCache = self.__LoadFileData("LoveGift", IPY_LoveGift)
        self.ipyLoveGiftLen = len(self.ipyLoveGiftCache)
        self.ipyMarryCache = self.__LoadFileData("Marry", IPY_Marry)
        self.ipyMarryLen = len(self.ipyMarryCache)
        self.ipyLoveRingCache = self.__LoadFileData("LoveRing", IPY_LoveRing)
@@ -6860,6 +6875,8 @@
    def GetSkyTowerServerChallengeByIndex(self, index): return self.ipySkyTowerServerChallengeCache[index]
    def GetLingGenEffectCount(self): return self.ipyLingGenEffectLen
    def GetLingGenEffectByIndex(self, index): return self.ipyLingGenEffectCache[index]
    def GetLoveGiftCount(self): return self.ipyLoveGiftLen
    def GetLoveGiftByIndex(self, index): return self.ipyLoveGiftCache[index]
    def GetMarryCount(self): return self.ipyMarryLen
    def GetMarryByIndex(self, index): return self.ipyMarryCache[index]
    def GetLoveRingCount(self): return self.ipyLoveRingLen
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py
@@ -6200,9 +6200,29 @@
def GetChatBubbleBox(curPlayer): return curPlayer.GetExAttr10()
def SetChatBubbleBox(curPlayer, value): return curPlayer.SetExAttr10(value, False, True)
##伴侣ID
def GetCoupleID(curPlayer): return curPlayer.GetExAttr11()
def SetCoupleID(curPlayer, coupleID): return curPlayer.SetExAttr11(coupleID, False, False)
##伴侣
def GetCoupleID(curPlayer):
    coupleInfo = GetCoupleInfo(curPlayer.GetPlayerID())
    return coupleInfo[0] if coupleInfo else 0
def GetCoupleName(curPlayer):
    coupleInfo = GetCoupleInfo(curPlayer.GetPlayerID())
    return coupleInfo[1] if coupleInfo else ""
def GetCoupleJob(curPlayer):
    coupleInfo = GetCoupleInfo(curPlayer.GetPlayerID())
    return coupleInfo[2] if coupleInfo else 1
def GetBridePriceMaxID(curPlayer):
    coupleInfo = GetCoupleInfo(curPlayer.GetPlayerID())
    return coupleInfo[3] if coupleInfo else 0
def GetCoupleInfo(playerID):
    if playerID not in PyGameData.g_coupleInfo:
        return
    return PyGameData.g_coupleInfo[playerID]
def SetCoupleInfo(playerID, coupleInfo):
    if not coupleInfo:
        PyGameData.g_coupleInfo.pop(playerID, None)
    else:
        PyGameData.g_coupleInfo[playerID] = coupleInfo
    return
## 玩家所属服务器组ID
def GetPlayerServerGroupID(curPlayer): return curPlayer.GetExAttr13()
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py
@@ -1350,10 +1350,7 @@
        if key == ShareDefine.Def_Notify_WorldKey_CoupleInfo:
            syncCoupleInfo = eval(msgValue)
            for playerID, coupleInfo in syncCoupleInfo.items():
                if not coupleInfo:
                    PyGameData.g_coupleInfo.pop(playerID, None)
                else:
                    PyGameData.g_coupleInfo[playerID] = coupleInfo
                PlayerControl.SetCoupleInfo(playerID, coupleInfo)
            return
        
        if key.startswith(ShareDefine.Def_Notify_WorldKey_OperationActionInfo[:-2]): 
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerLove.py
@@ -20,88 +20,66 @@
import PlayerControl
import IpyGameDataPY
import ChPyNetSendPack
import PlayerBillboard
import FunctionNPCCommon
import IPY_GameWorld
import ItemControler
import NetPackCommon
import ShareDefine
import ChConfig
import time
def DoPlayerOnDay(curPlayer):
    # 重置每日魅力
    if curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveCharmToday):
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveCharmToday, 0)
        Sync_CharmInfo(curPlayer)
    # 重置每日聘礼
    bridePriceState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveBridePriceState)
    if bridePriceState:
        updBridePriceState = bridePriceState
        ipyDataMgr = IpyGameDataPY.IPY_Data()
        for index in range(ipyDataMgr.GetMarryCount()):
            ipyData = ipyDataMgr.GetMarryByIndex(index)
            if not ipyData.GetIsDayReset():
                continue
            bridePriceID = ipyData.GetBridePriceID()
            dataIndex = bridePriceID - 1
            buyCount = GameWorld.GetDataByDigitPlace(updBridePriceState, dataIndex)
            if not buyCount:
                continue
            updBridePriceState = GameWorld.ChangeDataByDigitPlace(updBridePriceState, dataIndex, 0)
            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveBridePriceState, updBridePriceState)
            GameWorld.DebugLog("重置每日聘礼次数: bridePriceState=%s,bridePriceID=%s,updBridePriceState=%s"
                               % (bridePriceState, bridePriceID, updBridePriceState), curPlayer.GetPlayerID())
        if bridePriceState != updBridePriceState:
            Sync_CoupleInfo(curPlayer)
def DoPlayerOnDay(curPlayer):
    return
def DoPlayerLogin(curPlayer):
    Sync_CharmInfo(curPlayer)
    Sync_CoupleInfo(curPlayer)
    Sync_LoveRingInfo(curPlayer)
    return
#// B3 10 送花 #tagCMSendFlowers
#// B3 10 送礼物 #tagCMSendGifts
#
#struct    tagCMSendFlowers
#struct    tagCMSendGifts
#{
#    tagHead        Head;
#    DWORD        TagPlayerID;    // 目标玩家ID
#    DWORD        FlowerCount;    // 赠送花数量
#    WORD        GiftNum;        // 赠送礼物编号
#    DWORD        GiftCount;    // 赠送礼物数量
#    BYTE        IsAutoBuy;    // 是否自动购买
#};
def OnSendFlowers(index, clientData, tick):
def OnSendGifts(index, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    tagPlayerID = clientData.TagPlayerID
    flowerCount = clientData.FlowerCount
    giftNum = clientData.GiftNum
    giftCount = clientData.GiftCount
    isAutoBuy = clientData.IsAutoBuy
    
    if flowerCount <= 0:
    if giftNum <= 0 or giftCount <= 0:
        return
    
    flowerCountInfoDict = IpyGameDataPY.GetFuncEvalCfg("LoveFlower", 2, {})
    if str(flowerCount) not in flowerCountInfoDict:
    ipyData = IpyGameDataPY.GetIpyGameData("LoveGift", giftNum)
    if not ipyData:
        return
    addCharm, addCharmTag, addIntimacy = flowerCountInfoDict[str(flowerCount)]
    flowerID = IpyGameDataPY.GetFuncCfg("LoveFlower", 1)
    
    _, bindCnt, unBindCnt = ItemCommon.GetPackItemBindStateIndexInfo(curPlayer, flowerID, flowerCount)
    lackCnt = flowerCount - bindCnt - unBindCnt
    giftItemID = ipyData.GetGiftItemID()
    if not ipyData.GetAllowBatch():
        giftCount = 1 # 不允许批量赠送的默认赠送1个
    _, bindCnt, unBindCnt = ItemCommon.GetPackItemBindStateIndexInfo(curPlayer, giftItemID, giftCount)
    lackCnt = giftCount - bindCnt - unBindCnt
    if lackCnt > 0:
        GameWorld.DebugLog("鲜花道具不足,无法赠送! flowerID=%s,flowerCount=%s,bindCnt=%s,unBindCnt=%s,lackCnt=%s"
                           % (flowerID, flowerCount, bindCnt, unBindCnt, lackCnt))
        return
        if not isAutoBuy:
            GameWorld.DebugLog("礼物道具不足,无法赠送! giftItemID=%s,giftCount=%s,bindCnt=%s,unBindCnt=%s,lackCnt=%s"
                               % (giftItemID, giftCount, bindCnt, unBindCnt, lackCnt))
            return
        moneyType = IpyGameDataPY.GetFuncCfg("LoveGift", 1)
        infoDict = {ChConfig.Def_Cost_Reason_SonKey:giftItemID}
        if not FunctionNPCCommon.PayAutoBuyItem(curPlayer, {giftItemID:lackCnt}, moneyType, ChConfig.Def_Cost_Love, infoDict, isCheck=True):
            return
    if not GameWorld.SetPlayerTickTime(curPlayer, ChConfig.TYPE_Player_Tick_Love, tick):
        PlayerControl.NotifyCode(curPlayer, "RequestLater")
        return
    
    isWorldNotify = (flowerCount in IpyGameDataPY.GetFuncEvalCfg("LoveFlower", 3))
    dataMsg = [tagPlayerID, flowerID, flowerCount, addCharm, addCharmTag, addIntimacy, isWorldNotify]
    SendToGameServer_Love(curPlayer, "SendFlowersReq", dataMsg)
    dataMsg = [tagPlayerID, giftNum, giftItemID, giftCount, isAutoBuy]
    SendToGameServer_Love(curPlayer, "SendGiftsReq", dataMsg)
    return
#// B3 11 提亲 #tagCMMarryReq
@@ -117,26 +95,9 @@
    tagPlayerID = clientData.TagPlayerID
    bridePriceID = clientData.BridePriceID
    
    playerID = curPlayer.GetPlayerID()
    coupleID = PlayerControl.GetCoupleID(curPlayer)
    if coupleID and coupleID != tagPlayerID:
        GameWorld.DebugLog("已成亲伴侣ID不一致,无法提亲! tagPlayerID(%s) != coupleID(%s)" % (tagPlayerID, coupleID), playerID)
        return
    ipyData = IpyGameDataPY.GetIpyGameData("Marry", bridePriceID)
    if not ipyData:
        return
    canBuyMax = ipyData.GetCanBuyCount()
    dataIndex = bridePriceID - 1
    bridePriceState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveBridePriceState)
    buyCount = GameWorld.GetDataByDigitPlace(bridePriceState, dataIndex)
    if canBuyMax and buyCount >= canBuyMax:
        GameWorld.DebugLog("聘礼提亲次数不足,无法提亲! bridePriceID=%s,buyCount(%s) >= canBuyMax(%s)"
                           % (bridePriceID, buyCount, canBuyMax), playerID)
        return
    costMoneyInfo = ipyData.GetCostMoneyInfo()
    if len(costMoneyInfo) != 2:
        return
@@ -222,23 +183,9 @@
    breakType = clientData.BreakType
    playerID = curPlayer.GetPlayerID()
    
    coupleID = PlayerControl.GetCoupleID(curPlayer)
    if not coupleID:
        GameWorld.DebugLog("没有伴侣,不需要离婚!", playerID)
        return
    curTime = int(time.time())
    marryTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveMarryTime)
    passTime = curTime - marryTime
    breakCD = IpyGameDataPY.GetFuncCfg("LoveMarryBreak", 1)
    if breakCD and passTime < breakCD:
        GameWorld.Log("离婚等待时间未到,无法离婚! marryTime=%s,passTime(%s) < %s"
                      % (GameWorld.ChangeTimeNumToStr(marryTime), passTime, breakCD), playerID)
        return
    moneyType, moneyValue = 0, 0
    if breakType == 1:
        costMoneyInfo = IpyGameDataPY.GetFuncEvalCfg("LoveMarryBreak", 2)
        costMoneyInfo = IpyGameDataPY.GetFuncEvalCfg("LoveMarryBreak", 3)
        if len(costMoneyInfo) != 2:
            return
        moneyType, moneyValue = costMoneyInfo
@@ -250,7 +197,7 @@
        PlayerControl.NotifyCode(curPlayer, "RequestLater")
        return
    
    dataMsg = [playerID, coupleID, breakType, moneyType, moneyValue]
    dataMsg = [playerID, breakType, moneyType, moneyValue]
    SendToGameServer_Love(curPlayer, "MarryBreakReq", dataMsg)
    return
@@ -265,14 +212,8 @@
    
    msgType, dataMsg = msgData[:2]
    
    ## 增加魅力值
    if msgType == "AddCharm":
        addCharmTag = dataMsg[0]
        __DoAddCharm(curPlayer, addCharmTag)
        return
    ## 结婚成功
    elif msgType == "MarrySuccess":
    if msgType == "MarrySuccess":
        __DoMarrySuccess(curPlayer, dataMsg)
    
    ## 离婚成功
@@ -285,11 +226,11 @@
    
    msgType, dataMsg, ret = msgData
    
    ## 送花请求返回
    if msgType == "SendFlowersReq":
    ## 送礼物请求返回
    if msgType == "SendGiftsReq":
        if not ret:
            return
        __DoSendFlowers(curPlayer, dataMsg)
        __DoSendGiftsReq(curPlayer, dataMsg)
        
    ## 吃喜糖返回
    elif msgType == "MarryEatCandy":
@@ -311,27 +252,35 @@
        
    return
def __DoSendFlowers(curPlayer, dataMsg):
    ## 送花方处理
def __DoSendGiftsReq(curPlayer, dataMsg):
    ## 送礼物方处理
    
    playerID = curPlayer.GetPlayerID()
    tagPlayerID, flowerID, flowerCount, addCharm = dataMsg[:4]
    tagPlayerID, giftNum, giftItemID, giftCount, isAutoBuy = dataMsg
    
    costItemIndexList, bindCnt, unBindCnt = ItemCommon.GetPackItemBindStateIndexInfo(curPlayer, flowerID, flowerCount)
    lackCnt = flowerCount - bindCnt - unBindCnt
    costItemIndexList, bindCnt, unBindCnt = ItemCommon.GetPackItemBindStateIndexInfo(curPlayer, giftItemID, giftCount)
    lackCnt = giftCount - bindCnt - unBindCnt
    delCnt = giftCount
    if lackCnt > 0:
        GameWorld.ErrLog("地图鲜花道具不足,无法赠送! tagPlayerID=%s,flowerID=%s,flowerCount=%s,lackCnt=%s"
                         % (tagPlayerID, flowerID, flowerCount, lackCnt), playerID)
        return
        if not isAutoBuy:
            GameWorld.ErrLog("礼物道具不足,无法赠送! giftItemID=%s,giftCount=%s,bindCnt=%s,unBindCnt=%s,lackCnt=%s"
                             % (giftItemID, giftCount, bindCnt, unBindCnt, lackCnt))
            return
        moneyType = IpyGameDataPY.GetFuncCfg("LoveGift", 1)
        infoDict = {ChConfig.Def_Cost_Reason_SonKey:giftItemID}
        if not FunctionNPCCommon.PayAutoBuyItem(curPlayer, {giftItemID:lackCnt}, moneyType, ChConfig.Def_Cost_Love, infoDict):
            return
        delCnt -= lackCnt
    GameWorld.Log("赠送礼物: tagPlayerID=%s,giftNum=%s,giftItemID=%s,giftCount=%s,isAutoBuy=%s"
                  % (tagPlayerID, giftNum, giftItemID, giftCount, isAutoBuy), playerID)
    
    GameWorld.Log("赠送鲜花: tagPlayerID=%s,flowerID=%s,flowerCount=%s,addCharm=%s" % (tagPlayerID, flowerID, flowerCount, addCharm), playerID)
    saveDataDict = {"tagPlayerID":tagPlayerID}
    ItemCommon.DelCostItemByBind(curPlayer, costItemIndexList, bindCnt, unBindCnt, flowerCount, "Love", saveDataDict)
    __DoAddCharm(curPlayer, addCharm)
    SendToGameServer_Love(curPlayer, "SendFlowersOK", dataMsg)
    # 扣除消耗
    if delCnt > 0:
        ItemCommon.DelCostItemByBind(curPlayer, costItemIndexList, bindCnt, unBindCnt, delCnt, "Love")
    SendToGameServer_Love(curPlayer, "SendGiftsOK", dataMsg)
    return
def __DoMarryEatCandy(curPlayer, retInfo):
@@ -369,57 +318,19 @@
    ## 离婚请求结果返回
    
    costMoneyType, costMoneyValue = retInfo
    GameWorld.Log("执行离婚请求结果: costMoneyType=%s, costMoneyValue=%s" % (costMoneyType, costMoneyValue), curPlayer.GetPlayerID())
    GameWorld.Log("执行强制离婚请求结果: costMoneyType=%s, costMoneyValue=%s" % (costMoneyType, costMoneyValue), curPlayer.GetPlayerID())
    
    infoDict = {ChConfig.Def_Cost_Reason_SonKey:"MarryBreak"}
    PlayerControl.PayMoney(curPlayer, costMoneyType, costMoneyValue, ChConfig.Def_Cost_Love, infoDict, isMinus=True)
    return
def __DoAddCharm(curPlayer, addValue):
    ## 增加魅力值
    charmTotal = min(curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveCharmTotal) + addValue, ShareDefine.Def_UpperLimit_DWord)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveCharmTotal, charmTotal)
    charmToday = min(curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveCharmToday) + addValue, ShareDefine.Def_UpperLimit_DWord)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveCharmToday, charmToday)
    GameWorld.Log("增加魅力: addValue=%s,charmTotal=%s,charmToday=%s" % (addValue, charmTotal, charmToday), curPlayer.GetPlayerID())
    PlayerControl.NotifyCode(curPlayer, "AddCharm", [addValue])
    PlayerBillboard.UpdatePlayerBillboard(curPlayer, ShareDefine.Def_BT_Charm, charmTotal)
    PlayerBillboard.UpdatePlayerBillboard(curPlayer, ShareDefine.Def_BT_CharmDay, charmToday)
    Sync_CharmInfo(curPlayer)
    return
def __DoMarrySuccess(curPlayer, dataMsg):
    ## 执行成亲成功
    reqPlayerID, coupleID, curTime, bridePriceID = dataMsg
    isNewlyMarried = (PlayerControl.GetCoupleID(curPlayer) != coupleID) # 是否新婚
    reqPlayerID, bridePriceID, mapServerCoupleInfo = dataMsg
    playerID = curPlayer.GetPlayerID()
    PlayerControl.SetCoupleInfo(playerID, mapServerCoupleInfo)
    
    if isNewlyMarried:
        PlayerControl.SetCoupleID(curPlayer, coupleID)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveNewMarryTime, curTime)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveBridePriceState, 0)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveBridePriceMaxID, 0)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveMarryTime, curTime)
    dataIndex = bridePriceID - 1
    bridePriceState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveBridePriceState)
    buyCount = GameWorld.GetDataByDigitPlace(bridePriceState, dataIndex)
    updBuyCount = min(9, buyCount + 1)
    updBridePriceState = GameWorld.ChangeDataByDigitPlace(bridePriceState, dataIndex, updBuyCount)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveBridePriceState, updBridePriceState)
    bridePriceMaxID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveBridePriceMaxID)
    if bridePriceID > bridePriceMaxID:
        bridePriceMaxID = bridePriceID
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveBridePriceMaxID, bridePriceMaxID)
    Sync_CoupleInfo(curPlayer)
    GameWorld.Log("执行成亲成功! reqPlayerID=%s,bridePriceID=%s" % (reqPlayerID, bridePriceID), playerID)
    
    if curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveRingClassLV) == 0:
        GameWorld.DebugLog("激活情戒!")
@@ -428,9 +339,6 @@
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveRingEatCount, 0)
        Sync_LoveRingInfo(curPlayer)
        
    GameWorld.Log("执行成亲成功! coupleID=%s,curTime=%s,bridePriceID=%s,isNewlyMarried=%s,bridePriceState=%s,buyCount=%s,updBuyCount=%s,updBridePriceState=%s,bridePriceMaxID=%s"
                  % (coupleID, curTime, bridePriceID, isNewlyMarried, bridePriceState, buyCount, updBuyCount, updBridePriceState, bridePriceMaxID), playerID)
    # 提亲的玩家扣除消耗
    if playerID == reqPlayerID:
        ipyData = IpyGameDataPY.GetIpyGameData("Marry", bridePriceID)
@@ -442,20 +350,13 @@
    RefreshLoveAttr(curPlayer)
    return
def GetBridePriceMaxID(curPlayer):
    ## 获取结婚聘礼的最高ID
    return curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveBridePriceMaxID)
def __ClearCoupleSocial(curPlayer, dataMsg):
    ## 离婚 - 清除伴侣关系
    
    playerID = curPlayer.GetPlayerID()
    
    coupleID = PlayerControl.GetCoupleID(curPlayer)
    PlayerControl.SetCoupleID(curPlayer, 0)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveBridePriceState, 0)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveBridePriceMaxID, 0)
    Sync_CoupleInfo(curPlayer)
    PlayerControl.SetCoupleInfo(playerID, None)
    
    GameWorld.Log("清除伴侣关系成功! coupleID=%s" % (coupleID), playerID)
    RefreshLoveAttr(curPlayer)
@@ -555,7 +456,7 @@
        
    # 扣除消耗
    if delCnt:
        ItemCommon.DelCostItemByBind(curPlayer, costItemIndexList, bindCnt, unBindCnt, delCnt, "LoveRing")
        ItemCommon.DelCostItemByBind(curPlayer, costItemIndexList, bindCnt, unBindCnt, delCnt, "Love")
        
    # 升星
    if ringUpType == "starUp":
@@ -631,24 +532,6 @@
    # 保存计算值
    PlayerControl.SetCalcAttrListValue(curPlayer, ChConfig.Def_CalcAttrFunc_LoveRing, allAttrList)
    PlayerControl.SetCalcAttrListValue(curPlayer, ChConfig.Def_CalcAttrFunc_LoveRingCouple, allAttrListCouple)
    return
def Sync_CharmInfo(curPlayer):
    ## 同步魅力信息
    clientPack = ChPyNetSendPack.tagMCCharmInfo()
    clientPack.CharmTotal = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveCharmTotal)
    clientPack.CharmToday = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveCharmToday)
    NetPackCommon.SendFakePack(curPlayer, clientPack)
    return
def Sync_CoupleInfo(curPlayer):
    ## 同步伴侣信息
    clientPack = ChPyNetSendPack.tagMCCoupleInfo()
    clientPack.CoupleID = PlayerControl.GetCoupleID(curPlayer)
    clientPack.NewMarryTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveNewMarryTime)
    clientPack.MarryTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveMarryTime)
    clientPack.BridePriceState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveBridePriceState)
    NetPackCommon.SendFakePack(curPlayer, clientPack)
    return
def Sync_LoveRingInfo(curPlayer):
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerTalk.py
@@ -381,12 +381,10 @@
    # 等级
    extraValueStr += GetTalkExtraValueStar(ShareDefine.Def_TalkExtraValue_Bit_LV) % objTalk.GetLV()
    # 伴侣信息
    coupleName, bridePriceMaxID = "", 0
    coupleInfo = PyGameData.g_coupleInfo.get(playerID)
    if coupleInfo and len(coupleInfo) >= 2 and coupleInfo[0] == PlayerControl.GetCoupleID(objTalk):
        coupleName = coupleInfo[1]
        bridePriceMaxID = PlayerLove.GetBridePriceMaxID(objTalk)
    extraValueStr = "%s|%s|%s" % (extraValueStr, coupleName, bridePriceMaxID)
    coupleName = PlayerControl.GetCoupleName(objTalk)
    coupleJob = PlayerControl.GetCoupleJob(objTalk)
    bridePriceMaxID = PlayerControl.GetBridePriceMaxID(objTalk)
    extraValueStr = "%s|%s|%s|%s" % (extraValueStr, coupleName, coupleJob, bridePriceMaxID)
    return extraValueStr
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerViewCacheTube.py
@@ -177,7 +177,6 @@
    curPlayerPropDict["ServerGroupID"] = PlayerControl.GetPlayerServerGroupID(curPlayer)
    curPlayerPropDict["LingGenPoint"] = [PlayerControl.GetMetal(curPlayer), PlayerControl.GetWood(curPlayer), PlayerControl.GetWater(curPlayer), 
                                         PlayerControl.GetFire(curPlayer), PlayerControl.GetEarth(curPlayer)]
    curPlayerPropDict["CoupleID"] = PlayerControl.GetCoupleID(curPlayer)
    
    #战斗属性
    curPlayerPropDict["MinAtk"] = curPlayer.GetMinAtk()