系列文章目录

python编写游戏测试机器人客户端(一)
python编写游戏测试机器人客户端(二)
python编写游戏测试机器人客户端(三)
python编写游戏测试机器人客户端(四)
python编写游戏测试机器人客户端(五)
python编写游戏测试机器人客户端(六)
python编写游戏测试机器人客户端(七)
python编写游戏测试机器人客户端(八)


游戏测试机器人搭建 - Player Actor

  • 系列文章目录
    • 前言:
    • 阅读前的基础知识
      • Actors做什么
      • Actor的组成
      • pykka框架的使用
    • 环境
    • 正文
      • 机器人架构图
      • 测试机器人要用的3个核心Actor(Player,Send,Recv)
      • Player Actor
      • Player对象初始化
      • 封装消息发送,用来给自己发送消息或者其它Actor调用
      • Player Actor 实例化之后第一个执行的地方
      • 接收消息及消息处理
      • 封装远程命令
      • 停止Player Actor
      • log收集

前言:

第一次写博客,文笔有限,加上半路出身的游测,大佬们别往死里喷,错的地方请指正,在正式介绍之前先简单说下框架:Python的 pykka(Actor模型),测试框架 pytest和测试报告 allure。粗略框架介绍

阅读前的基础知识

Python 的socket编程,多进程,多线程,队列

Actors做什么

当一个actor接收到消息后,它能做如下三件事中的一件:

  • Create more actors; 创建其他actors
  • Send messages to other actors; 向其他actors发送消息
  • Designates what to do with the next message. 指定下一条消息到来的行为

Actor的组成

Actor是由状态(state)、行为(behavior)、邮箱(mailbox)三者组成的。

  • 状态(state):状态是指actor对象的变量信息,状态由actor自身管理,避免并发环境下的锁和内存原子性等问题。
  • 行为(behavior):行为指定的是actor中计算逻辑,通过actor接收到的消息来改变actor的状态。
  • 邮箱(mailbox):邮箱是actor之间的通信桥梁,邮箱内部通过FIFO消息队列来存储发送发消息,而接收方则从邮箱中获取消息。

Actors一大重要特征在于 actors之间相互隔离,它们并不互相共享内存。这点区别于上述的对象。也就是说,一个actor能维持一个私有的状态,并且这个状态不可能被另一个actor所改变。
具体Actor介绍可参考:传送门 >> JunChow520的Actor模型介绍

pykka框架的使用

传送门 >> pykka使用说明
引用说明书的例子:

#!/usr/bin/env python3import pykkaGetMessages = object()class PlainActor(pykka.ThreadingActor):def __init__(self):super().__init__()self.stored_messages = []def on_receive(self, message):if message is GetMessages:return self.stored_messageselse:self.stored_messages.append(message)if __name__ == '__main__':actor = PlainActor.start()actor.tell({'no': 'Norway', 'se': 'Sweden'})actor.tell({'a': 3, 'b': 4, 'c': 5})print(actor.ask(GetMessages))actor.stop()

环境

  • Python:3.7
  • Windows/Linux

正文

机器人架构图

测试机器人要用的3个核心Actor(Player,Send,Recv)

Player Actor

Player对象初始化

  • 传递参数:用户名、服务器IP和Port、性别、职业,根据项目类型增减;
  • 其他Actor的调用:
    • Recv Actor:必要的,socket接收数据,后面章节介绍;
    • Send Actor:必要的,socket发送数据,后面章节介绍;
    • 可自由增加其他的Actor;
  • 初始化可设置角色的相关属性,后面根据服务端返回数据进行相关赋值,如:角色的ID,name,资产货币,攻击防御等 ;
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File    :   player.py
@Contact :   512759438@qq.com
@Author  :   Jian
'''import pykka
import websocket
import traceback as tb
from proto import ProtoHandler
from remote import RemoteHandler
from util import MsgSwitch, RecvActor, SendActorTEST_CASE_CALL = None
class Player(pykka.ThreadingActor):def __init__(self, user_name='', server='SERVER_1',sex=1, job=1):super(Player, self).__init__()self.host = SERVER_LIST[server]['GAME_HOST']self.port = SERVER_LIST[server]['GAME_PORT']self.web_host = "x.x.x.x"self.recv_actor = Noneself.send_actor = Noneself.socket = Noneself.proto_handler = ProtoHandler(self)self.remote_handler = RemoteHandler(self)'''测试用例执行时需要调用player'''global TEST_CASE_CALLTEST_CASE_CALL = selfself.player_id = Noneself.state_user_id = 0self.state_user_name = user_nameself.sys_count = 0

封装消息发送,用来给自己发送消息或者其它Actor调用

    def send_msg(self, msg_type=None, data=None):''':param msg_type:消息类型 :param data: 数据'''self.actor_ref.tell({'msg': msg_type,'data': data})

Player Actor 实例化之后第一个执行的地方

  • 不指定用户的话则随机账号登录
  • MSG_GUEST_LOGIN: 消息类型
  • 接下来就把消息告诉自己,on_receive会接收到这条消息
     def on_start(self):if self.state_user_name is '':self.send_msg(MSG_GUEST_LOGIN)else:self.send_msg(MSG_LOGIN_INFO)

接收消息及消息处理

  • 接收的消息会放进MsgSwitch进行参数检查,MsgSwitch参考C语言switch
  • 接下来是用户注册、创角、登录流程
  • MSG_LOGIN_INFO:获取玩家的信息
    • 获取用户信息后通知 MSG_LOGIN
  • MSG_LOGIN:玩家开始连接socket,有角色则开始登录,没有角色则通知 MSG_CREATE_PLAYER
    • 连接socket后开启 Send ActorRecv Actor
    • Send Actor 发送消息:角色登录需要的参数,Send Actor会进行打包和发给服务端
  • MSG_CREATE_PLAYER:
    • 把需要的创角参数传给Send Actor,打包后通知服务端要创角
  • MSG_PROTO:Recv Actor 从socket.recv接收的数据进行反序列化后会发送过来到这处理
    • 如果需要对服务端返回的协议数据进行自动处理,可以在proto模块写上对应处理方法,MSG_PROTO消息类型接收的每一条协议数据都会去proto模块查找有没有对应的处理方法(hasattr和getattr)
  • MSG_REMOTE_CMD:后续写到remote再进行结合一起写,不影响运行
    def on_receive(self, msg):for case in MsgSwitch(msg):# 获取用户信息if case(MSG_LOGIN_INFO):account_info = Account(self.state_user_name).login_info()if account_info['code_str'] == 'OK':user_into = account_info['user']self.create_player_params  = {'rd3_token': user_into['token'],'rd3_userId': user_into['userId'],'server_list_type': 0,'sid': 1,'token': user_into['token'],}self.create_player_params.update(Account(self.state_user_name).data)self.create_player_params.pop('password')self.create_player_params['cmd'] = 'game_login'self.send_msg(MSG_LOGIN)else:print(f'获取角色信息ERROR, 原因: {account_info["code_str"]},{account_info["code"]}')break# 用户登录if case(MSG_LOGIN):self.socket = websocket.create_connection(f'ws://{self.host}:{self.port}/')self.recv_actor = RecvActor.start(self, self.socket)self.send_actor = SendActor.start(self, self.socket)self.send_actor.tell({MSG_PROTO: self.create_player_params})break# 用户创角if case(MSG_CREATE_PLAYER):create_data = {'nickname': self.state_user_name,'rd3_token': self.create_player_params['rd3_token'],'rd3_userId': self.create_player_params['rd3_userId'],'sid': self.create_player_params['sid'],'token': self.create_player_params['token'],}self.send_actor.tell({MSG_PROTO: create_data})break# 服务端返回协议处理if case(MSG_PROTO):  method, data = msg['data']if hasattr(self.proto_handler, method):getattr(self.proto_handler, method)(data)else:print(f"没有为协议: {method} 定义处理方法, 请前往 proto.py 文件中定义!")break# 控制台调用命令if case(MSG_REMOTE_CMD):method = msg['method']method = (type(method) is int and "r" + str(method)) or (type(method) is str and method)if hasattr(self.remote_handler, method):getattr(self.remote_handler, method)(msg['data'])else:print(f"没有为远程命令: {method} 定义处理方法, 请前往 remote.py 文件中定义!")break

封装远程命令

  • 角色登录后可通过 pykka.ActorRegistry.get_by_class_name(‘Player’) 获取实例对象用远程命令遥控角色
    def remote_msg(self, method:str=None, data=None):'''调用remote里的方法:param method: 方法名:param data: 传入的参数 元组'''self.actor_ref.tell({'msg': MSG_REMOTE_CMD,'method': method,'data': data})

停止Player Actor

  • 先停止其他的Actor 再关闭socket,最后关掉自己
    def on_stop(self):self.recv_actor.stop()self.send_actor.stop()self.socket.close()self.socket.shutdown()self.stop()

log收集

    # 打印报错消息@GetLog(level='fatal')def on_failure(self, exception_type, exception_value, traceback):logging.fatal(f'Player: {self.state_user_name} is down.')logging.fatal(f"ErrorType  => {exception_type}")logging.fatal(f"ErrorValue => {exception_value}")logging.fatal(f"TraceBack  => {tb.print_tb(traceback)}")self.on_stop()

到这里Player Actor 已经写完了,目前是无法单独运行的,需要结合后面的Send Actor 和 Recv Actor 才能运行,写的不清晰的欢迎在评论留言,接下来的是python编写游戏测试机器人客户端(二)

最后的最后,各位的关注、点赞、收藏、碎银子打赏是对我最大的支持,谢谢大家!
需要脚本源码的小伙伴关注微信公众号ID:gameTesterGz
或扫描二维码关注回复机器人框架即可

python编写游戏测试机器人客户端(一)相关推荐

  1. python编写游戏测试机器人客户端(四)

    游戏测试机器人搭建 - 玩家登录 运行机器人 需要导入的模块 定义Main,检测账号参数 开始登录 登录成功 机器人下线 运行机器人 需要导入的模块 @File : main.py @Contact ...

  2. python调用微信客户端_用Python编写的简化版微信客户端

    原标题:用Python编写的简化版微信客户端 原文:A simple WeChat client written in Python supports session persistence. 翻译: ...

  3. Python编写游戏——拼图游戏

    Python编写游戏需要用到pgzrun模块.但不能用pip install pgzrun进行安装,正确的库名是pgzero,pip install pgzero. 一.开发工具 Python版本:P ...

  4. python编写游戏怎么打包——详解python+pygame游戏开发之使用Py2exe打包游戏为exe文件

    python编写游戏怎么打包 1.简介 2.软件准备 3.打包流程 最近在用python+pygame 开发游戏,写完以后在分享给朋友玩的时候遇到了很大的问题,只有搭建了环境才能运行python脚本. ...

  5. 【游戏测试】客户端性能 - drawcall 工具链

    原文由资深游戏测试开发工程师 陈子昂,发表于TesterHome社区,点击原文链接可与作者交流. 一般 drawCall 可以理解成是调用次数,到底是调用了什么,一般性能测试里面会关注哪些. 提交给程 ...

  6. python编写测试小工具-Python与游戏测试(小工具篇)

    import datetime import paramiko import time import os class ScanError(object): def __init__(self): s ...

  7. 用Python编写的简化版微信客户端

    原文:A simple WeChat client written in Python supports session persistence. 翻译:Peter pywxclient 基于Web ...

  8. python怎么制作游戏修改器_使用python编写游戏修改器

    最近比较怀旧,在玩一个比较老的PC游戏.由于游戏难度太高了,于是就打算自己写一个修改器. 通过查阅资料,在 Windows 下的修改器主要需要用到四个函数:OpenProcess, CloseHand ...

  9. python编写游戏加速器_Numba:用CUDA加速的高性能Python编译器

    [IT168 编译]Python是一种高效的动态编程语言,广泛应用于科学.工程和数据分析应用领域.使python如此受欢迎的因素有很多,包括其干净的.表达性的语法和标准的数据结构,综合的"内 ...

最新文章

  1. iOS自动签名打包(xcodebuild)----常用
  2. 关于bcg库记忆界面的问题及其解决办法
  3. jvm性能调优 - 05对象在JVM内存中的分配和流转
  4. redistemplate set方法_spring boot整合redis ---- RedisTemplate 三分钟快速入门
  5. day1-参数化关联函数响应断言
  6. 为什么要选择基于NAS存储方案
  7. jquery 图片切换插件(初版)
  8. 热烈庆贺博客等级V7
  9. [模板]线性筛素数(欧拉筛法)
  10. java编译及运行过程_简述JAVA程序的编辑编译和运行过程
  11. 【题解】Luogu P5294 [HNOI2019]序列
  12. 龙讯7号 国芯发布龙芯电脑引争议
  13. 如何设置word的默认输入法——搜狗输入法
  14. H5 架构和原生架构的区别
  15. 那些年,我们一起做过的 Java 课后练习题(26 - 30)
  16. Javaweb学习笔记——Javaweb概述
  17. 如何进行数据文件的传输(不简单)
  18. 谷歌账户二次验证_为您的Google帐户和Microsoft帐户设置双重身份验证
  19. 【艾兰岛建筑】系列1—五大实用绝招!教你场景建造又快又美!
  20. 国内期刊投稿用 CTeX(CTeX_2.9.2.164_Full)

热门文章

  1. BandiZip解压工具
  2. 7.8 Introduce Local Extension 引入本地扩展
  3. 相机标定实验过程注意问题及总结
  4. 为什么c语言排在第一位,c语言我排第几个
  5. 小木工 ____农民工纪事之一
  6. 录音m4a怎么转换成mp3
  7. 啊?你还在用vmware,快来试试免费好用的Hyper V吧!
  8. 大数据可视化分析以及预测性分析方法
  9. 人工智能python好学吗_人工智能“速成班”Python好学吗 小心别被忽悠了
  10. 瀑布模型、迭代模型和敏捷开发