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;

项目地址

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/783790.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2.作业2

目录 1.作业题目 A图 B代码 2.css盒子模型 0.css盒子模型 1.外边距&#xff08;margin&#xff09; 2.边框&#xff08;border&#xff09; 3.内边距&#xff08;padding&#xff09; ​编辑 3.GET方法与POST方法的区别 学习产出&#xff1a; html的作业 1.作业题目 A图…

无向图中寻找指定路径:深度优先遍历算法

刷题记录 1. 节点依赖 背景: 类似于无向图中, 寻找从 起始节点 --> 目标节点 的 线路. 需求: 现在需要从 起始节点 A, 找到所有到 终点 H 的所有路径 A – B &#xff1a; 路径由一个对象构成 public class NodeAssociation {private String leftNodeName;private Stri…

文华财经盘立方期货通鳄鱼指标公式均线交易策略源码

文华财经盘立方期货通鳄鱼指标公式均线交易策略源码&#xff1a; 新建主图幅图类型指标都可以&#xff01; VAR1:(HL)/2; 唇:REF(SMA(VAR1,5,1),3),COLORGREEN; 齿:REF(SMA(VAR1,8,1),5),COLORRED; 颚:REF(SMA(VAR1,13,1),8),COLORBLUE;

离线查询+线段树,CF522D - Closest Equals

一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 522D - Closest Equals 二、解题报告 1、思路分析 考虑查询区间已经给出&#xff0c;我们可以离线查询 对于这类区间离线查询的问题我们通常可以通过左端点排序&#xff0c;然后遍历询问同时维护左区间信息…

数据泄露态势(2024年5月)

监控说明&#xff1a;以下数据由零零信安0.zone安全开源情报系统提供&#xff0c;该系统监控范围包括约10万个明网、深网、暗网、匿名社交社群威胁源。在进行抽样事件分析时&#xff0c;涉及到我国的数据不会选取任何政府、安全与公共事务的事件进行分析。如遇到影响较大的伪造…

《金山 WPS AI 2.0:重塑办公未来的智能引擎》

AITOP100平台获悉&#xff0c;在 2024 世界人工智能大会这一科技盛宴上&#xff0c;金山办公以其前瞻性的视野和创新的技术&#xff0c;正式发布了 WPS AI 2.0&#xff0c;犹如一颗璀璨的星辰&#xff0c;照亮了智能办公的新征程&#xff0c;同时首次公开的金山政务办公模型 1.…

支持图片识别语音输入的LobeChat保姆级本地部署流程

文章目录 前言1. LobeChat对我们有哪些帮助?2. 本地安装LobeChat3. 如何使用LobeChat工具4. 安装Cpolar内网穿透5. 实现公网访问LobeChat6. 固定LobeChat公网地址 前言 本文主要介绍如何在Windows系统电脑本地部署LobeChat&#xff0c;一款高颜值的开源AI大模型智能应用&…

5-google::protobuf命名空间下常用的C++ API----message.h

#include <google/protobuf/message.h> namespace google::protobuf 假设您有一个消息定义为: message Foo {optional string text 1;repeated int32 numbers 2; } 然后&#xff0c;如果你使用 protocol编译器从上面的定义生成一个类&#xff0c;你可以这样使用它: …

Studying-代码随想录训练营day31| 56.合并区间、738.单调递增的数字、968.监控二叉树、贪心算法总结

第31天&#xff0c;贪心最后一节(ง •_•)ง&#x1f4aa;&#xff0c;编程语言&#xff1a;C 目录 56.合并区间 738.单调递增的数字 968.监控二叉树 贪心算法总结 56.合并区间 文档讲解&#xff1a;代码随想录合并区间 视频讲解&#xff1a;手撕合并区间 题目&#xf…

C语言下结构体、共用体、枚举类型的讲解

主要内容 结构体结构体数组结构体指针包含结构体的结构链表链表相关操作共用体枚举类型 结构体 结构体的类型的概念 结构体实现步骤 结构体变量的声明 struct struct 结构体名{ 数据类型 成员名1; 数据类型 成员名2; ..…

绝地求生PUBG兰博基尼怎么兑换 兰博基尼怎么获得

绝地求生采用虚幻4引擎制作&#xff0c;玩家们会在一个偏远的岛屿上出生&#xff0c;然后展开一场赢家通吃的生存竞赛&#xff0c;最后只会有1个人存活。当然&#xff0c;和其他生存游戏一样&#xff0c;玩家需要在广袤复杂的地图中收集武器、车辆、物资&#xff0c;而且也会有…

解决win10报“无法加载文件……profile.ps1,因为在此系统上禁止运行脚本”的问题

打开命令行报错 解决方法 使用管理员权限打开PowerShell&#xff1a;WinX, 选择“Windows PowerShell&#xff08;管理员&#xff09;” 输入&#xff1a;Set-ExecutionPolicy -ExecutionPolicy RemoteSigned 输入&#xff1a;y确认修改安全策略 &#xff1a;y确认修改安全策略…

探讨大数据在视频汇聚平台LntonCVS国标GB28181协议中的应用

随着摄像头和视频监控系统的普及和数字化程度的提高&#xff0c;视频监控系统产生的数据量急剧增加。大数据技术因其优秀的数据管理、分析和利用能力&#xff0c;成为提升视频监控系统效能和价值的重要工具。 大数据技术可以将视频监控数据与其他数据源进行融合分析&#xff0c…

【elasticsearch】IK分词器添加自定义词库,然后更新现有的索引

进入elasticsearch中的plugins位置&#xff0c;找到ik分词器插件&#xff0c;进入ik插件的config文件夹&#xff0c;当中有一个IKAnalyzer.cfg.xml配置文件。使用vim编辑器修改配置文件&#xff1a; vim IKAnalyzer.cfg.xml 配置文件如下&#xff08;添加了自定义字典的位置&…

pygame 音乐粒子特效

代码 import pygame import numpy as np import pymunk from pymunk import Vec2d import random import librosa import pydub# 初始化pygame pygame.init()# 创建屏幕 screen pygame.display.set_mode((1920*2-10, 1080*2-10)) clock pygame.time.Clock()# 加载音乐文件 a…

人工智能的新时代:从模型到应用的转变

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

信息技术课堂上如何有效防止学生玩游戏?

防止学生在信息技术课堂上玩游戏需要综合运用教育策略和技术手段。以下是一些有效的措施&#xff0c;可以用来阻止或减少学生在课堂上玩游戏的行为&#xff1a; 1. 明确课堂规则 在课程开始之初&#xff0c;向学生清楚地说明课堂纪律&#xff0c;强调不得在上课时间玩游戏。 制…

使用tcpdump抓取本本机的所有icmp包

1、抓取本机所有icmp包 tcpdump -i any icmp -vv 图中上半部分&#xff0c;是源主机tmp179无法ping通目标主机192.168.10.79&#xff08;因为把该主机关机了&#xff09;的状态&#xff0c;注意看&#xff0c;其中有unreachable 图中下半部分&#xff0c;是源主机tmp179可以p…

Docker总结

准备环境&#xff1a; VMware17Ubuntu18.04(LTS)&#xff1a;https://releases.ubuntu.com/18.04/ubuntu-18.04.6-desktop-amd64.iso 1. Docker前瞻 docker相关文档&#xff1a; docker官网地址 : https://www.docker.com/docker文档地址 : https://docs.docker.com/docker镜像…