当前位置: 首页 > news >正文

Rust入门实战 编写Minecraft启动器#3解析资源配置

首发于Enaium的个人博客


在上一篇文章中,我们已经建立了资源模型,接下来我们需要解析游戏的配置文件。

首先我们添加serde_json依赖和model依赖。

model = { path = "../model" }
serde_json = "1.0"

之后我们在lib.rs中添加解析的trait

pub trait Parse<T>: Sized {type Error;fn parse(value: T) -> Result<Self, Self::Error>;
}

之后将所有的model都实现这个trait,并测试它们。这里其实只用将需要手动解析的实现这个trait,其他的会在我们用reqwest下载的时候自动解析。

asset.rs

use model::asset::*;use crate::Parse;impl Parse<&str> for AssetIndex {type Error = serde_json::Error;fn parse(value: &str) -> Result<Self, Self::Error> {serde_json::from_str::<AssetIndex>(value)}
}impl Parse<&str> for Index {type Error = serde_json::Error;fn parse(value: &str) -> Result<Self, Self::Error> {serde_json::from_str::<Index>(value)}
}impl Parse<&str> for Object {type Error = serde_json::Error;fn parse(value: &str) -> Result<Self, Self::Error> {serde_json::from_str::<Object>(value)}
}#[cfg(test)]
mod tests {use super::*;#[test]fn test_asset_index() {let asset_index = AssetIndex::parse(r#"{"id": "17", "sha1": "fab15439bdef669e389e25e815eee8f1b2aa915e", "size": 447033, "totalSize": 799252591, "url": "https://piston-meta.mojang.com/v1/packages/fab15439bdef669e389e25e815eee8f1b2aa915e/17.json"}"#).unwrap_or_else(|err| panic!("{:?}",err));assert_eq!("17", asset_index.id);assert_eq!("fab15439bdef669e389e25e815eee8f1b2aa915e", asset_index.sha1);assert_eq!(447033, asset_index.size);assert_eq!(799252591, asset_index.total_size);assert_eq!("https://piston-meta.mojang.com/v1/packages/fab15439bdef669e389e25e815eee8f1b2aa915e/17.json", asset_index.url);}#[test]fn test_index() {let index = Index::parse(r#"{"objects": {"icons/icon_128x128.png": {"hash": "b62ca8ec10d07e6bf5ac8dae0c8c1d2e6a1e3356", "size": 9101}}}"#).unwrap_or_else(|err| panic!("{:?}",err));assert_eq!(1, index.objects.len());assert_eq!("b62ca8ec10d07e6bf5ac8dae0c8c1d2e6a1e3356",index.objects.get("icons/icon_128x128.png").unwrap().hash);assert_eq!(9101,index.objects.get("icons/icon_128x128.png").unwrap().size);}
}

library.rs

use model::library::*;use crate::Parse;impl Parse<&str> for Library {type Error = serde_json::Error;fn parse(value: &str) -> Result<Self, Self::Error> {serde_json::from_str::<Library>(value)}
}impl Parse<&str> for Rule {type Error = serde_json::Error;fn parse(value: &str) -> Result<Self, Self::Error> {serde_json::from_str::<Rule>(value)}
}impl Parse<&str> for Os {type Error = serde_json::Error;fn parse(value: &str) -> Result<Self, Self::Error> {serde_json::from_str::<Os>(value)}
}impl Parse<&str> for Download {type Error = serde_json::Error;fn parse(value: &str) -> Result<Self, Self::Error> {serde_json::from_str::<Download>(value)}
}impl Parse<&str> for Artifact {type Error = serde_json::Error;fn parse(value: &str) -> Result<Self, Self::Error> {serde_json::from_str::<Artifact>(value)}
}#[cfg(test)]
mod tests {use super::*;#[test]fn test_library() {let library = Library::parse(r#"{"downloads": {"artifact": {"path": "ca/weblite/java-objc-bridge/1.1/java-objc-bridge-1.1.jar", "sha1": "1227f9e0666314f9de41477e3ec277e542ed7f7b", "size": 1330045, "url": "https://libraries.minecraft.net/ca/weblite/java-objc-bridge/1.1/java-objc-bridge-1.1.jar"}}, "name": "ca.weblite:java-objc-bridge:1.1", "rules": [{"action": "allow", "os": {"name": "osx"}}]}"#,).unwrap_or_else(|err| panic!("{:?}",err));assert_eq!("ca.weblite:java-objc-bridge:1.1", library.name);assert_eq!("ca/weblite/java-objc-bridge/1.1/java-objc-bridge-1.1.jar",library.downloads.artifact.path);assert_eq!("1227f9e0666314f9de41477e3ec277e542ed7f7b",library.downloads.artifact.sha1);assert_eq!(1330045, library.downloads.artifact.size);assert_eq!("https://libraries.minecraft.net/ca/weblite/java-objc-bridge/1.1/java-objc-bridge-1.1.jar",library.downloads.artifact.url);let rules = &library.rules.unwrap();assert_eq!("allow", rules[0].action);assert_eq!("osx", rules[0].os.name);}
}

version_manifest.rs

use model::version_manifest::*;use crate::Parse;impl Parse<&str> for VersionManifest {type Error = serde_json::Error;fn parse(value: &str) -> Result<Self, Self::Error> {serde_json::from_str::<VersionManifest>(value)}
}impl Parse<&str> for Latest {type Error = serde_json::Error;fn parse(value: &str) -> Result<Self, Self::Error> {serde_json::from_str::<Latest>(value)}
}impl Parse<&str> for Version {type Error = serde_json::Error;fn parse(value: &str) -> Result<Self, Self::Error> {serde_json::from_str::<Version>(value)}
}#[cfg(test)]
mod tests {use super::*;#[test]fn test_version() {let version = Version::parse(r#"{"id": "1.21", "type": "release", "url": "https://piston-meta.mojang.com/v1/packages/177e49d3233cb6eac42f0495c0a48e719870c2ae/1.21.json", "time": "2024-06-13T08:32:38+00:00", "releaseTime": "2024-06-13T08:24:03+00:00"}"#,).unwrap_or_else(|err| panic!("{:?}",err));assert_eq!("1.21", version.id);assert_eq!("release", version.type_);assert_eq!("https://piston-meta.mojang.com/v1/packages/177e49d3233cb6eac42f0495c0a48e719870c2ae/1.21.json", version.url);assert_eq!("2024-06-13T08:32:38+00:00", version.time);assert_eq!("2024-06-13T08:24:03+00:00", version.release_time);}#[test]fn test_latest() {let latest = Latest::parse(r#"{"release": "1.21", "snapshot": "1.21"}"#).unwrap_or_else(|err| panic!("{:?}", err));assert_eq!("1.21", latest.release);assert_eq!("1.21", latest.snapshot);}#[test]fn test_version_manifest() {let version_manifest =VersionManifest::parse(r#"{"latest": {"release": "1.21", "snapshot": "1.21"}, "versions": [{"id": "1.21", "type": "release", "url": "https://piston-meta.mojang.com/v1/packages/177e49d3233cb6eac42f0495c0a48e719870c2ae/1.21.json", "time": "2024-06-13T08:32:38+00:00", "releaseTime": "2024-06-13T08:24:03+00:00"}]}"#).unwrap_or_else(|err| panic!("{:?}", err));assert_eq!("1.21", version_manifest.latest.release);assert_eq!("1.21", version_manifest.latest.snapshot);assert_eq!("1.21", version_manifest.versions[0].id);assert_eq!("release", version_manifest.versions[0].type_);assert_eq!("https://piston-meta.mojang.com/v1/packages/177e49d3233cb6eac42f0495c0a48e719870c2ae/1.21.json", version_manifest.versions[0].url);assert_eq!("2024-06-13T08:32:38+00:00",version_manifest.versions[0].time);assert_eq!("2024-06-13T08:24:03+00:00",version_manifest.versions[0].release_time);}
}

version.rs

use crate::Parse;
use model::version::*;impl Parse<&str> for Version {type Error = serde_json::Error;fn parse(value: &str) -> Result<Self, Self::Error> {serde_json::from_str::<Version>(value)}
}impl Parse<&str> for Download {type Error = serde_json::Error;fn parse(value: &str) -> Result<Self, Self::Error> {serde_json::from_str::<Download>(value)}
}impl Parse<&str> for Client {type Error = serde_json::Error;fn parse(value: &str) -> Result<Self, Self::Error> {serde_json::from_str::<Client>(value)}
}#[cfg(test)]
mod tests {use super::*;#[test]fn test_version() {let game = Version::parse(r#"{"downloads": {"client": {"sha1": "0e9a07b9bb3390602f977073aa12884a4ce12431", "size": 26836080, "url": "https://piston-data.mojang.com/v1/objects/0e9a07b9bb3390602f977073aa12884a4ce12431/client.jar"}}, "id": "1.21", "libraries": [], "mainClass": "net.minecraft.client.main.Main", "releaseTime": "2024-06-13T08:24:03+00:00", "time": "2024-06-13T08:32:38+00:00", "type": "release"}"#,).unwrap_or_else(|err| panic!("{:?}",err));let client = &game.downloads.client;assert_eq!("0e9a07b9bb3390602f977073aa12884a4ce12431", client.sha1);assert_eq!(26836080, client.size);assert_eq!("https://piston-data.mojang.com/v1/objects/0e9a07b9bb3390602f977073aa12884a4ce12431/client.jar", client.url);assert_eq!("1.21", game.id);assert_eq!("net.minecraft.client.main.Main", game.main_class);assert_eq!("2024-06-13T08:24:03+00:00", game.release_time);assert_eq!("2024-06-13T08:32:38+00:00", game.time);assert_eq!("release", game.type_);}
}

最后我们将这些tait导出。

pub mod asset;
pub mod library;
pub mod version;
pub mod version_manifest;

项目地址

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 冯诺依曼体系结构与操作系统(Linux)
  • (1)Jupyter Notebook 下载及安装
  • OpenCV教程02:图像处理系统1.0(翻转+形态学+滤波+缩放+旋转)
  • 华为机试HJ37统计每个月兔子的总数
  • 进程输入输出及终端属性学习
  • 30 - 最新2024版SpringCloud学习记录 - 项目版本选型
  • 如何在 PostgreSQL 中实现数据的增量备份和恢复?
  • 线性代数中的“过定系统”和“欠定系统”
  • 微软正在放弃React
  • 推荐算法学习笔记2.1:基于深度学习的推荐算法-基于共线矩阵的深度推荐算法-AutoRec模型
  • 2.5 C#视觉程序开发实例1----IO_Manager实现脉冲输出控制
  • 浔川官方宣布官方账号将在CSDN进行无人管理——浔川官方
  • 【Python基础篇】你了解python中运算符吗
  • ESP32——物联网小项目汇总
  • 安卓面试题系列--【1】
  • 《深入 React 技术栈》
  • 【Leetcode】104. 二叉树的最大深度
  • 345-反转字符串中的元音字母
  • angular组件开发
  • Javascript弹出层-初探
  • Linux链接文件
  • Meteor的表单提交:Form
  • Mysql5.6主从复制
  • PHP那些事儿
  • Shadow DOM 内部构造及如何构建独立组件
  • TCP拥塞控制
  • weex踩坑之旅第一弹 ~ 搭建具有入口文件的weex脚手架
  • windows下如何用phpstorm同步测试服务器
  • 阿里云容器服务区块链解决方案全新升级 支持Hyperledger Fabric v1.1
  • 闭包--闭包作用之保存(一)
  • 基于Volley网络库实现加载多种网络图片(包括GIF动态图片、圆形图片、普通图片)...
  • 京东美团研发面经
  • 使用common-codec进行md5加密
  • 试着探索高并发下的系统架构面貌
  • 详解NodeJs流之一
  • 【运维趟坑回忆录 开篇】初入初创, 一脸懵
  • 【运维趟坑回忆录】vpc迁移 - 吃螃蟹之路
  • 机器人开始自主学习,是人类福祉,还是定时炸弹? ...
  • 交换综合实验一
  • $ is not function   和JQUERY 命名 冲突的解说 Jquer问题 (
  • (09)Hive——CTE 公共表达式
  • (1)(1.13) SiK无线电高级配置(五)
  • (7)svelte 教程: Props(属性)
  • (a /b)*c的值
  • (C语言)二分查找 超详细
  • (二)丶RabbitMQ的六大核心
  • (转)关于多人操作数据的处理策略
  • .babyk勒索病毒解析:恶意更新如何威胁您的数据安全
  • .Net Attribute详解(上)-Attribute本质以及一个简单示例
  • .NET Core实战项目之CMS 第一章 入门篇-开篇及总体规划
  • .net mvc 获取url中controller和action
  • .NET 编写一个可以异步等待循环中任何一个部分的 Awaiter
  • .net 使用ajax控件后如何调用前端脚本
  • .Net6 Api Swagger配置
  • .Net7 环境安装配置