0x00_Inital
省流:软件官网:https://cfg.laosepi.cool/
下载地址:https://mrdeng.lanzoue.com/b0133wrfc (密码:awrr)
作为一个CSGO官匹玩家,最难受的事情莫过于上网吧的时候调配置。尤其是准星,准星不对劲完全打不到人;好在各大对战平台都提供了便捷的配置文件上传下载功能,但是每次在网吧登录都需要等待平台更新,验证环境等等,而且手机上得有对战平台的APP才能异地登录,较为繁琐。
于是就想自己写一个简单的配置下载工具,它可以自动扫描Steam目录,下载解压配置文件后释放配置文件。由于直接在服务器保存配置文件不太安全,且我的小服务器也承受不了太多用户,所以采用了WebDav的方式下载配置文件,我的服务器仅储存用户的WebDav配置信息用于下载。后续可能支持一键更新上传
大概思路是这样的:
- 初始化程序,检测Steam进程是否存在,若无则提示用户启动Steam;
- ,扫描软件根目录下是否存在配置文件压缩包,若有则解压释放,从中获取用户好友ID,若无则弹出登录框联网获取WebDav信息;
- 用户登录从服务器获取信息,若有WebDav配置信息则进行显示,若无则提示添加配置;若查询不到该用户则引导注册并添加WebDav配置信息;
- 在添加或修改WebDav配置信息时,先进行测试下载,确认配置无误后才解锁上传按钮,避免储存错误配置;
本来想的是使用Python+PyQt的方式实现,但是考虑到Python项目打包后庞大的体积就放弃了。所幸在大二的时候学过一点点C#的皮毛,并且编译后的体积非常小巧,所以考虑使用C#制作桌面应用,使用Flask作为后端。
0x01_The Front End
首先是制作桌面应用,C#桌面应用可以在Visual Studio中直接拖拽设计并绑定按钮函数,非常方便。下面简单介绍一下各个页面的设计思路。
0x01-1 启动页面
启动页面就三个按钮,一个项目地址跳转链接和用于显示扫描到Steam地址的TextEdit。在初始化完成前,“替换CFG”和“替换视频设置”的按钮是禁用状态,避免程序找不到对应的配置文件而出错。当初始化完成后,在下方的TextEdit中显示扫描到的CSGO配置文件夹地址。
下面是伪代码思路:
public string[] UnzipFile()
if (根目录存在cfg.zip) 解压cfg.zip
else{
if(弹出提示框“当前目录不存在cfg.zip,点击是登录,点击否打开软件根目录”) 弹出登录框
else 打开软件根目录
}
return 解压后文件中的子文件夹名称或空值
public void CopyFile(string CFG_Path, string Local_Path, string Target)
if(软件根目录存在“cfg”文件夹) 删除原有cfg文件夹
释放下载的配置文件夹
移动配置文件夹中的 Target 文件到本地CSGO配置文件夹 Local_Path
private void Init_Btn_Click()
if(Steam进程是否存在)
{
if(调用UnzipFile) 从返回值拼接配置文件夹路径
else 弹出提示
}
private void CFG_Btn_Click()
if(存在config.cfg) 删除config.cfg
CopyFile(CFG_Path, Local_Path, "config.cfg")
private void Vid_Btn_Click()
if(存在video.txt) 删除video.txt
CopyFile(CFG_Path, Local_Path, "video.txt")
0x01-2 登录页面
在点击初始化按钮后,在根目录找不到配置文件压缩包后,弹出登录页面
这个页面就更加简洁了,就两个输入框,两个按钮。原本是打算使用网页进行注册的,但是我的前端水平实在有限,写出来的Demo我自己都看不下去,就放弃了,直接在软件内进行注册。然后在保持登录状态这一点,使用了Session的方式,在登录成功时将用户邮箱写入Session["email"]中,用于后续查询配置操作。同时在此窗口内新建一个HttpClient对象,并在调用注册和WebDav编辑页面时将它传入,用以保持登录信息。
private void SignUp_Btn_Click()
调起 注册页面(HttpClient)
public void DownLoad(string url, string username, string password)
WebClient client = new WebClient();
client.Credentials = new NetworkCredential(username, password);
client.DownloadFile(url, localPath);
private async void Login_Btn_Click()
if(验证账号和密码输入框不为空)
{
构造登录信息表单 UserData
res = await HttpClient.post(服务器, UserData)
if(res) 调起 WebDav配置页面(HttpClient)
else 账号不存在或密码错误
}
0x01-3注册页面
注册页面也较为简洁,在点击“验证”按钮前锁定注册按钮,同时对邮箱输入框进行了简单的判断,防止有用户输错邮箱。
private bool IsValidEmail(string input)
if(input符合邮箱地址的格式)return true
else return false
async private void Ver_Btn_Click()
禁用邮箱输入框,禁用验证按钮,启用注册按钮
//此处有Timer对验证按钮进行倒计时显示,代码略
if(IsValidEmail(邮件框))
{
构造注册邮箱数据表 EmailData
res = await post(服务器验证码接口, EmailData)
if(res == "success") 显示 注册成功
else if(res == "error") 显示 该邮箱已注册
else 显示 无法连接至邮件服务器
}else 提示邮箱格式错误
async private void SignUp_Btn_Click()
if(密码框文字长度<6) 提示密码过短
else if(验证码长度<6) 提示验证码不正确
else
{
构造注册信息表单 SignUpData
res = await HttpClient.post(服务器注册接口, SignUpData)
}
if(res == "success") 提示注册成功,调起配置页面(HttpClient)
else 提示注册失败或无法连接到服务器
0x01-4WebDav配置修改页面
配置修改页面主要为三个输入框和两个按钮。这里采用了一个防呆设计,“保存配置”的按钮是默认禁用的,得通过下载测试后,才使能该按钮。在该页面初始化时,会向服务器配置信息接口请求一次用户WebDav配置。
private void Test_Btn_Click()
if(三个输入框均不为空)
{
if(当前目录存在cfg.zip) 删除cfg.zip
try 根据输入框信息下载配置文件
catch WebException 提示配置信息有误,return
if(当前目录存在cfg.zip) 提示下载成功,禁用输入框,使能保存按钮
}else 提示配置栏不能留空
async private void Save_Btn_Click()
构造WebDav配置信息表 CFGData
res = HttpClient.post(服务器配置信息接口, CFGData)
if(res) 提示上传成功,关闭此窗口
else 提示上传失败
以上为桌面应用的设计,由于对于C#不是太熟悉,所以对于登录表单的校验等工作基本上都是交由后端完成的,并且注册页面有一个bug是验证按钮的倒计时Timer,在倒计时结束前如果关闭注册窗口会导致程序崩溃,是由于Timer更新UI的线程丢失,而引起的崩溃,暂时还没想到什么好的解决办法,也请评论区的大神们指点一二。
0x02_The Back End
再来简单介绍一下后端,这一部分使用了Flask框架进行构建,也比较简单,就全部放在了一个main.py中,使用了sqlite作为数据库,便于部署。以下为简化后的伪代码:
# 发邮件函数
def send_subscribe_mail(mail_data):
从 mail_data 中获取数据
发送邮件
@app.route('/', methods=['GET']) # 定义主页路由
def index():
在数据库查询总用户数和总下载数
return render_template('index.html', Users=len(Users)-1, Count=Count)
@app.route('/login', methods=['POST']) # 定义登录接口
def login():
从请求表单获取信息
if 在数据库中查询用户:
写入Session
在数据库中查询用户配置信息 CFG
return jsonify(CFG)
else:
return "None"
@app.route('/email', methods=['POST']) # 定义验证码邮件接口
def email():
if 请求邮箱地址 email == 系统邮箱地址:
return "error"
if 在数据库中查询email:
return "error"
code = 生成6位验证码
code,email 存入Session
发送验证码邮件
return "success"
@app.route('/register', methods=['POST']) # 定义 注册接口
def register():
if 请求表单中的验证码 == Session中的验证码:
将用户信息写入数据库
return "success"
else:
return "error"
@app.route('/cfg', methods=['GET', 'POST']) # 定义配置接口
def cfg():
if request.method == 'GET': # 请求下载配置
if session['email']: # 如果已经登录或从注册页面进入
try:
从数据库中查询email匹配的配置信息 CFG
return jsonify(CFG)
except IndexError: # 查询失败报错
return "" # 无配置返回空
elif request.method == 'POST':
try:
数据库写入请求表单数据
return "success"
except E:
return "error"
0x03_Usage
在设计的时候,软件的初始化操作有两步,第一步是检测Steam进程从而找到Steam.exe的路径,以此找到Steam安装文件夹中的Userdata文件夹;第二步是尝试解压软件根目录下的“cfg.zip”,因此本软件可以直接打包好配置文件压缩包一起移动,省去登录下载的时间,亦或者是上传到坚果云等支持WebDav的免费网盘中,将配置信息填写好联网下载。
限于篇幅这里不做过多赘述,详细使用信息见GitHub:Lord2333/CSGO_CFG
0x04_Another Thing
这个软件是我花了两天时间一边百度一边GPT写出来的,很粗糙,也不好看,勉强够用的水平。
由于V社的官方SDK要交100刀注册成为开发者才能使用,所以就用了一个笨办法在配置文件夹中获取用户的好友ID以定位本地的配置文件夹,后续尝试一下能不能像Steam++那样自动识别(但是好像它也是用的Steam的SDK实现的)。
此外由于打包配置文件夹的过程较为繁琐,且每次修改配置后都需要重新手动打包,不太方便,后续将尝试自动打包上传到WebDav服务器。
最后,欢迎各位留言,提Issue~