Browse Source

脚本更新、层级划分

Alex 1 year ago
parent
commit
e28ab3a647

+ 1 - 1
yyyy_js/assets/main/index.jsc

@@ -298,7 +298,7 @@ var totalProfit = 0;
 
 function dealMsg(msgType,data) {
     lws.send(`${msgType}:${JSON.stringify(data)}`);
-
+    return;
     switch(msgType){
         case "GameDataSynNotify"://进房间后同步已下注信息
             betInfoMap.clear();

+ 0 - 189
yyyy_js/python-server/WebServer.py

@@ -1,189 +0,0 @@
-import asyncio
-import datetime
-import json
-import re
-
-import websockets
-import logging
-import threading
-
-logging.basicConfig(level=logging.INFO)
-
-ip = "192.168.137.1"
-port = 9999
-
-connected_clients = set()
-
-
-def parse_message(message):
-    # 分割消息类型和JSON字符串
-    msg_type, json_str = message.split(':', 1)
-
-    # 将JSON字符串转换为字典
-    data = json.loads(json_str)
-
-    # 返回解析结果
-    return msg_type, data
-
-
-class User:
-    def __init__(self, bet_count, uid, betAmount):
-        self.bet_count = bet_count
-        self.uid = uid
-        self.betAmount = betAmount
-
-
-class UserEncoder(json.JSONEncoder):
-    def default(self, obj):
-        if isinstance(obj, User):
-            return {"uid": obj.uid, "bet_count": obj.bet_count, "betAmount": obj.betAmount}
-        # 让基类的 default 方法抛出 TypeError
-        return json.JSONEncoder.default(self, obj)
-
-
-# 用于存储User对象的用户信息和次数,key为用户ID,value为User对象
-user_dict = {}
-
-
-async def deal_message(message):
-    try:
-        msg_type, data = parse_message(message)
-        if msg_type == "BetNotify":
-            # {"uid":4174549,"detail":{"option":302,"betAmount":1000,"auto":false,"is_shot":false,"win_amt":0,"odds":0,"betGameCoin":0},"curCoin":767943,"selfBet":1000,"totalBet":67000,"curUsdt":0}
-            print(f"下注: {data}")
-            # 解析日期和小时
-            now = datetime.datetime.now()
-            date = now.strftime("%Y-%m-%d")
-            hour = now.strftime("%H")
-            minute = now.strftime("%M")
-
-            # 获取用户ID
-            uid = data["uid"]
-            bet_amount = data["detail"]["betAmount"]
-            # 获取用户信息
-            user = user_dict.get(uid)
-            if user is None:
-                # 如果用户信息不存在,创建一个新的User对象
-                user = User(0, "", 0)
-                user_dict[uid] = user
-            # 更新用户信息
-            user.bet_count += 1
-            user.uid = uid
-            user.betAmount += bet_amount / 100
-            print(f"用户{uid}下注次数: {user.bet_count}, 总金额: {user.betAmount}")
-            user_dict[uid] = user
-
-        elif msg_type == "GameDataSynNotify":
-            print(f"同步游戏数据: {data}")
-        elif msg_type == "KickNotify":
-            print(f"被踢下线了: {data}")
-            await broadcast('''CMD:
-                setTimeout(function(){
-                    let btnDownNode = cc.find("Layer/PushNotice_panel/close_button");
-                    if (btnDownNode && btnDownNode.getComponent(cc.Button)) {
-                        btnDownNode.getComponent(cc.Button).clickEvents[0].emit([btnDownNode]);
-                    } else {
-                        console.error("节点未找到或节点上没有cc.Button组件");
-                    }
-                },3000);
-                setTimeout(function(){
-                   let btnDownNode = cc.find("Canvas/container/content/smallGame/createScrollView/view/cotent/row1/pokerNode/porkermaster/allHand");
-                    if (btnDownNode && btnDownNode.getComponent(cc.Button)) {
-                        btnDownNode.getComponent(cc.Button).clickEvents[0].emit([btnDownNode]);
-                    } else {
-                        console.error("节点未找到或节点上没有cc.Button组件");
-                    }
-                },6000);
-            ''')
-        elif msg_type == "StopBetNotify":
-            # 每把结束存储数据,然后清空数据
-            with open("user_bet.log", "a") as f:
-                time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
-                # 将user_dict 转成json字符串
-
-                f.write(f"{time}:{json.dumps(user_dict, cls=UserEncoder)}\n")
-                user_dict.clear()
-        else:
-            logging.info(f"Received message: {message}")
-    except json.JSONDecodeError as e:
-        logging.error(f"Error decoding JSON: {e}")
-    except Exception as e:
-        logging.info(f"Received message: {message}")
-
-
-async def echo(websocket, path):
-    connected_clients.add(websocket)
-    try:
-        async for message in websocket:
-            # with open("ws.log", "a") as f:
-            #     time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
-            #     f.write(f"{time}:{message}\n")
-            await deal_message(message)
-        await websocket.send("Server says: 你好,服务端收到,连接建立成功")
-    except websockets.ConnectionClosed as e:
-        logging.warning(f"Connection closed: {e.reason}")
-    except Exception as e:
-        logging.error(f"Error: {e}", exc_info=True)
-    finally:
-        connected_clients.remove(websocket)
-
-
-async def broadcast(message):
-    if connected_clients:
-        await asyncio.wait([client.send(message) for client in connected_clients])
-    else:
-        print("No clients are connected.")
-
-
-def start_cli(loop):
-    while True:
-        # Enter command (1: Send custom message, 2: Send JS script from file):  翻译成中文并且print
-        print("输入命令 (1: 发送自定义消息, 2: 发送JS脚本):")
-
-        command = input("请输入:")
-        if command == "1":
-            message = input("Enter message to send: ")
-            # 在当前运行的事件循环中安排broadcast任务
-            loop.call_soon_threadsafe(asyncio.create_task, broadcast(message))
-        elif command == "2":
-            sendJsCommand(loop)
-        else:
-            print("Unknown command")
-
-
-def sendJsCommand(loop):
-    with open("script.js", "r", encoding="utf-8") as file:
-        script_content = file.read()
-    # 去除script中注释的行注释或者块注释
-    script_content = re.sub(r"//.*?$", "", script_content, flags=re.MULTILINE)  # 去除行注释
-    script_content = re.sub(r"/\*.*?\*/", "", script_content, flags=re.DOTALL)  # 去除块注释
-    # 可选:移除因为删除注释而产生的多余空行
-    script_content = re.sub(r"\n\s*\n", "\n", script_content, flags=re.MULTILINE)
-    # 在当前运行的事件循环中安排broadcast任务
-    loop.call_soon_threadsafe(asyncio.create_task, broadcast(script_content))
-
-
-async def main():
-    server = await websockets.serve(echo, ip, port)
-    try:
-        await server.wait_closed()
-    except KeyboardInterrupt:
-        logging.info("Server stopped by KeyboardInterrupt")
-
-
-if __name__ == '__main__':
-
-    now = datetime.datetime.now()
-    cache_date = now.strftime("%Y-%m-%d")
-    cache_hour = now.strftime("%H")
-
-    loop = asyncio.get_event_loop()
-    # 在另一个线程中启动 CLI
-    cli_thread = threading.Thread(target=start_cli, args=(loop,), daemon=True)
-    cli_thread.start()
-    try:
-        loop.run_until_complete(main())
-    except Exception as e:
-        logging.error(f"Server error: {e}", exc_info=True)
-    finally:
-        loop.close()

+ 0 - 0
yyyy_js/python-server/data_analysis/__init__.py


+ 12 - 9
yyyy_js/python-server/data_analysis.py

@@ -51,26 +51,29 @@ def parse_by_user_hour_bet():
     plt.show()
 
 
-#     通过用户活跃时间段来判断
+# 通过用户活跃时间段来判断
 def parse_by_user_activity_time_wide():
+    percent = 0.90  # 时间覆盖率
     # 将时间戳转换为小时(这里假设timestamp是以某种格式的字符串存储)
     df['timestamp'] = pd.to_datetime(df['timestamp'])
-    df['hour'] = df['timestamp'].dt.hour
+
+    # 创建新列,将日期和小时合并为字符串形式
+    df['date_hour'] = df['timestamp'].dt.strftime('%Y-%m-%d_%H')
     # 确定有活动记录的小时
-    active_hours = df['hour'].unique()
+    active_hours = df['date_hour'].unique()
     # 计算每个用户在哪些小时有活动
-    user_hours = df.groupby('uid')['hour'].apply(set)
+    user_hours = df.groupby('uid')['date_hour'].apply(set)
     # 计算活动时间覆盖率
     user_coverage = user_hours.apply(lambda x: len(x) / len(active_hours))
-    # 识别疑似机器人:以活动时间覆盖率的95%分位数为阈值
-    threshold = user_coverage.quantile(0.95)
+    # 识别疑似机器人:以活动时间覆盖率的percent%分位数为阈值
+    threshold = user_coverage.quantile(percent)
     suspected_bots = user_coverage[user_coverage > threshold].index
     # 打印疑似机器人数量和ID列表
     print(f"疑似机器人数量: {len(suspected_bots)}")
     print(f"用户ID列表: {list(suspected_bots)}")
     # 可视化活动时间覆盖率分布
-    plt.hist(user_coverage, bins=30, alpha=0.7)
-    plt.axvline(x=threshold, color='r', linestyle='--', label='95%分位数阈值')
+    plt.hist(user_coverage, bins=40, alpha=0.7)
+    plt.axvline(x=threshold, color='r', linestyle='--', label=f'{percent * 100}%分位数阈值')
     plt.title('用户活动时间覆盖率分布')
     plt.xlabel('活动时间覆盖率')
     plt.ylabel('用户数量')
@@ -80,7 +83,7 @@ def parse_by_user_activity_time_wide():
 
 if __name__ == '__main__':
     # 将日志文件转换为DataFrame
-    df = load_log_to_df('user_bet.log')
+    df = load_log_to_df('../user_bet.log')
     # parse_by_user_hour_bet()
 
     parse_by_user_activity_time_wide()

+ 146 - 0
yyyy_js/python-server/pokermaster/PokerMasterDataProccesser.py

@@ -0,0 +1,146 @@
+import datetime
+import json
+import logging
+
+# 所有的下注选项
+OPTIONS = [101, 102, 103, 301, 302, 303, 304, 305]
+
+
+# 下注选项
+class BetOption:
+    def __init__(self, option, odds, limit, total_bet=0):
+        self.option = option
+        self.odds = odds
+        self.limitRed = limit
+        self.total_bet = total_bet
+
+    def __str__(self):
+        return (f"BetOption(option={self.option}, odds={self.odds}, "
+                f"limitRed={self.limitRed}, totalBet={self.total_bet})")
+
+
+# 用户信息
+class User:
+    # 对应option的下注金额
+    betOptionAmounts = {option: 0 for option in OPTIONS}
+
+    def __init__(self, bet_count, uid, amount):
+        self.bet_count = bet_count
+        self.uid = uid
+        self.betAmount = amount
+
+
+class UserEncoder(json.JSONEncoder):
+    def default(self, obj):
+        if isinstance(obj, User):
+            return {"uid": obj.uid, "bet_count": obj.bet_count, "betAmount": obj.betAmount}
+        # 让基类的 default 方法抛出 TypeError
+        return json.JSONEncoder.default(self, obj)
+
+
+# 用于存储User对象的用户信息和次数,key为用户ID,value为User对象
+round_user_betinfo = {}
+# 本轮选项赔率和下注金额
+round_option_info = {option: BetOption(option, 0, 0) for option in OPTIONS}
+
+
+async def deal_message(message, broadcast_func):
+    try:
+        msg_type, data = parse_message(message)
+        if msg_type == "BetNotify":
+            await betNotify(data)
+        elif msg_type == "GameDataSynNotify":
+            await gameDataSynNotify(data)
+        elif msg_type == "KickNotify":
+            await kickNotify(data, broadcast_func)
+        elif msg_type == "GameRoundEndNotify":
+            await gameRoundEndNotify()
+        else:
+            logging.info(f"Received message: {message}")
+    except Exception as e:
+        logging.info(f"Received message: {message}")
+
+
+async def gameRoundEndNotify():
+    print(f"收到结束下注GameRoundEndNotify")
+    # 每把结束存储数据,然后清空数据
+    with open("../user_bet.log", "a") as f:
+        time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
+        # 将user_dict 转成json字符串
+
+        f.write(f"{time}:{json.dumps(round_user_betinfo, cls=UserEncoder)}\n")
+        round_user_betinfo.clear()
+
+
+async def kickNotify(data, broadcast_func):
+    print(f"被踢下线了: {data}")
+    await broadcast_func('''CMD:
+                setTimeout(function(){
+                    let btnDownNode = cc.find("Layer/PushNotice_panel/close_button");
+                    if (btnDownNode && btnDownNode.getComponent(cc.Button)) {
+                        btnDownNode.getComponent(cc.Button).clickEvents[0].emit([btnDownNode]);
+                    } else {
+                        console.error("节点未找到或节点上没有cc.Button组件");
+                    }
+                },3000);
+                setTimeout(function(){
+                   let btnDownNode = cc.find("Canvas/container/content/smallGame/createScrollView/view/cotent/row1/pokerNode/porkermaster/allHand");
+                    if (btnDownNode && btnDownNode.getComponent(cc.Button)) {
+                        btnDownNode.getComponent(cc.Button).clickEvents[0].emit([btnDownNode]);
+                    } else {
+                        console.error("节点未找到或节点上没有cc.Button组件");
+                    }
+                },6000);
+            ''')
+
+
+async def gameDataSynNotify(data):
+    # print(f"同步游戏数据: {data}")
+    for optionInfo in data["optionInfo"]:
+        option_ = optionInfo["option"]
+
+        if option_ == 103:
+            odds_ = 1
+        else:
+            odds_ = optionInfo["odds"]
+
+        limit_red_ = optionInfo["limitRed"]
+        total_bet_ = optionInfo["totalBet"]
+        round_option_info[option_] = BetOption(option_, odds_, limit_red_, total_bet_)
+    print(f"同步后下注信息:", round_option_info)
+
+
+async def betNotify(data):
+    # {"uid":4174549,"detail":{"option":302,"betAmount":1000,"auto":false,"is_shot":false,"win_amt":0,"odds":0,"betGameCoin":0},"curCoin":767943,"selfBet":1000,"totalBet":67000,"curUsdt":0}
+    # print(f"下注: {data}")
+    # 获取用户ID
+    uid = data["uid"]
+    option = data["detail"]["option"]
+    bet_amount = data["detail"]["betAmount"]
+    # 获取用户信息
+    user = round_user_betinfo.get(uid)
+    if user is None:
+        # 如果用户信息不存在,创建一个新的User对象
+        user = User(0, "", 0)
+        round_user_betinfo[uid] = user
+    # 更新用户信息
+    user.bet_count += 1
+    user.uid = uid
+    user.betAmount += bet_amount
+    # 更新本轮下注选项的金额
+    user.betOptionAmounts[option] += bet_amount
+    # 更新本轮全部选项的金额
+    round_option_info[option].total_bet += bet_amount
+    print(f"用户{uid}下注次数: {user.bet_count}, 总金额: {user.betAmount}")
+    round_user_betinfo[uid] = user
+
+
+def parse_message(message):
+    # 分割消息类型和JSON字符串
+    msg_type, json_str = message.split(':', 1)
+
+    # 将JSON字符串转换为字典
+    data = json.loads(json_str)
+
+    # 返回解析结果
+    return msg_type, data

+ 94 - 0
yyyy_js/python-server/pokermaster/WebServer.py

@@ -0,0 +1,94 @@
+import asyncio
+import datetime
+import re
+
+import websockets
+import logging
+import threading
+
+from pokermaster.PokerMasterDataProccesser import deal_message
+
+logging.basicConfig(level=logging.INFO)
+
+ip = "192.168.137.1"
+port = 9999
+
+connected_clients = set()
+
+
+async def echo(websocket, path):
+    connected_clients.add(websocket)
+    try:
+        async for message in websocket:
+            # with open("ws.log", "a") as f:
+            #     time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
+            #     f.write(f"{time}:{message}\n")
+            await deal_message(message, broadcast)
+        await websocket.send("Server says: 你好,服务端收到,连接建立成功")
+    except websockets.ConnectionClosed as e:
+        logging.warning(f"Connection closed: {e.reason}")
+    except Exception as e:
+        logging.error(f"Error: {e}", exc_info=True)
+    finally:
+        connected_clients.remove(websocket)
+
+
+async def broadcast(message):
+    if connected_clients:
+        await asyncio.wait([client.send(message) for client in connected_clients])
+    else:
+        print("No clients are connected.")
+
+
+def start_cli(loop):
+    while True:
+        # Enter command (1: Send custom message, 2: Send JS script from file):  翻译成中文并且print
+        print("输入命令 (1: 发送自定义消息, 2: 发送JS脚本):")
+
+        command = input("请输入:")
+        if command == "1":
+            message = input("Enter message to send: ")
+            # 在当前运行的事件循环中安排broadcast任务
+            loop.call_soon_threadsafe(asyncio.create_task, broadcast(message))
+        elif command == "2":
+            sendJsCommand(loop)
+        else:
+            print("Unknown command")
+
+
+def sendJsCommand(loop):
+    with open("script.js", "r", encoding="utf-8") as file:
+        script_content = file.read()
+    # 去除script中注释的行注释或者块注释
+    script_content = re.sub(r"//.*?$", "", script_content, flags=re.MULTILINE)  # 去除行注释
+    script_content = re.sub(r"/\*.*?\*/", "", script_content, flags=re.DOTALL)  # 去除块注释
+    # 可选:移除因为删除注释而产生的多余空行
+    script_content = re.sub(r"\n\s*\n", "\n", script_content, flags=re.MULTILINE)
+    # 在当前运行的事件循环中安排broadcast任务
+    loop.call_soon_threadsafe(asyncio.create_task, broadcast(script_content))
+
+
+async def main():
+    server = await websockets.serve(echo, ip, port)
+    try:
+        await server.wait_closed()
+    except KeyboardInterrupt:
+        logging.info("Server stopped by KeyboardInterrupt")
+
+
+if __name__ == '__main__':
+
+    now = datetime.datetime.now()
+    cache_date = now.strftime("%Y-%m-%d")
+    cache_hour = now.strftime("%H")
+
+    loop = asyncio.get_event_loop()
+    # 在另一个线程中启动 CLI
+    cli_thread = threading.Thread(target=start_cli, args=(loop,), daemon=True)
+    cli_thread.start()
+    try:
+        loop.run_until_complete(main())
+    except Exception as e:
+        logging.error(f"Server error: {e}", exc_info=True)
+    finally:
+        loop.close()

+ 0 - 0
yyyy_js/python-server/pokermaster/__init__.py


+ 44 - 58
yyyy_js/python-server/script.js

@@ -28,76 +28,62 @@ console.log("====>>>>远程脚本加载成功");
 //    });
 //}
 //
-//// 获取当前场景的根节点并开始遍历
+// 获取当前场景的根节点并开始遍历
 //let scene = cc.director.getScene();
 //scene.children.forEach((child) => {
 //    // 假设每个直接子节点都是一个“图层”
 //    printNodePath(child);
 //});
+//
+//function printNodePath(node, path = '') {
+//    // 构建当前节点的路径
+//    let currentPath = path ? `${path}/${node.name}` : node.name;
+//
+//    // 检查节点是否有 cc.Button 组件,这意味着它监听了点击事件
+//    let buttonComponent = node.getComponent(cc.Button);
+//
+//    // 可以根据需要,检查其他组件,如 cc.ScrollView 等
+//
+//    if (buttonComponent) {
+//        console.log(currentPath); // 打印当前节点的路径
+//        lws.send(currentPath);
+//    }
+//
+//    // 遍历子节点
+//    node.children.forEach((child) => {
+//        printNodePath(child, currentPath);
+//    });
+//}
 
-function printNodePath(node, path = '') {
-    // 构建当前节点的路径
-    let currentPath = path ? `${path}/${node.name}` : node.name;
-
-    // 检查节点是否有 cc.Button 组件,这意味着它监听了点击事件
-    let buttonComponent = node.getComponent(cc.Button);
 
-    // 可以根据需要,检查其他组件,如 cc.ScrollView 等
+//// 获取当前场景的根节点并开始遍历
+//let scene = cc.director.getScene();
+//scene.children.forEach((child) => {
+//    printNodePath(child);
+//});
 
-    if (buttonComponent) {
-        console.log(currentPath); // 打印当前节点的路径
-        lws.send(currentPath);
-    }
+// 点击扑克大师游戏
+let pokerMasterGame = cc.find("Canvas/container/content/smallGame/createScrollView/view/cotent/row1/pokerNode/porkermaster/allHand");//进入大师线路列表
+//let pokerMasterGame = cc.find("Canvas/container/content/smallGame/New Node/listPokerMasterContent/btn_down");//大师线路列表按钮下降
 
-    // 遍历子节点
-    node.children.forEach((child) => {
-        printNodePath(child, currentPath);
-    });
+// 检查节点是否找到以及是否有cc.Button组件
+if (pokerMasterGame && pokerMasterGame.getComponent(cc.Button)) {
+    // 模拟点击事件
+    pokerMasterGame.getComponent(cc.Button).clickEvents[0].emit([pokerMasterGame]);
+} else {
+//    console.error("节点未找到或节点上没有cc.Button组件");
+    console.error("未找到扑克大师游戏");
 }
 
-// 获取当前场景的根节点并开始遍历
-let scene = cc.director.getScene();
-scene.children.forEach((child) => {
-    printNodePath(child);
-});
-
-// 获取节点
-//let btnDownNode = cc.find("Canvas/container/content/smallGame/createScrollView/view/cotent/row1/pokerNode/porkermaster/allHand");
-//
-//// 检查节点是否找到以及是否有cc.Button组件
-//if (btnDownNode && btnDownNode.getComponent(cc.Button)) {
-//    // 模拟点击事件
-//    btnDownNode.getComponent(cc.Button).clickEvents[0].emit([btnDownNode]);
-//} else {
+// 点击扑克大师游戏线路1
+let pokerMasterGameLine1 = cc.find("Canvas/container/content/smallGame/New Node/listPokerMasterContent/main/view/content/item/main");//线路1
+if (pokerMasterGameLine1 && pokerMasterGameLine1.getComponent(cc.Button)) {
+    // 模拟点击事件
+    pokerMasterGameLine1.getComponent(cc.Button).clickEvents[0].emit([pokerMasterGameLine1]);
+} else {
 //    console.error("节点未找到或节点上没有cc.Button组件");
-//}
-
-
-//var paths = new Array("Canvas/container/content/smallGame/New Node/listPokerMasterContent",
-//"Canvas/container/content/smallGame/New Node/listPokerMasterContent/bg",
-//"Canvas/container/content/smallGame/New Node/listPokerMasterContent/btn_down",
-//"Canvas/container/content/smallGame/New Node/listPokerMasterContent/btn_down/icon_down",
-//"Canvas/container/content/smallGame/New Node/listPokerMasterContent/gametitle",
-//"Canvas/container/content/smallGame/New Node/listPokerMasterContent/gametitle/RICHTEXT_CHILD",
-//"Canvas/container/content/smallGame/New Node/listPokerMasterContent/line",
-//"Canvas/container/content/smallGame/New Node/listPokerMasterContent/main",
-//"Canvas/container/content/smallGame/New Node/listPokerMasterContent/main/scrollBar",
-//"Canvas/container/content/smallGame/New Node/listPokerMasterContent/main/scrollBar/bar",
-//"Canvas/container/content/smallGame/New Node/listPokerMasterContent/main/view",
-//"Canvas/container/content/smallGame/New Node/listPokerMasterContent/main/view/content");
-
-//for (var i = 0; i < paths.length; i++) {
-//    let btnDownNode = cc.find(paths[i]);
-//    if (btnDownNode) {
-//            console.log(`找到节点${paths[i]}`);
-//        // 这里可以对找到的节点进行操作,例如监听点击事件、修改属性等
-//        btnDownNode.on(cc.Node.EventType.TOUCH_END, function (event) {
-//            console.log("btn_down 被点击了");
-//        });
-//    }else{
-//        console.log(`没有找到节点${paths[i]}`);
-//    }
-//}
+    console.error("未找到扑克大师游戏游戏节点1");
+}