我的世界Bukkit服务器插件开发教程(十三)资源包与玩家资料

news2024/11/15 13:56:38

十三、资源包与玩家资料


1.资源包(Resource Pack)

早期的 Minecraft 并没有资源包一说,而是被叫做材质包。有些服务器为了让玩家拥有更好的游戏体验,一般会在自己特制的客户端中存放一些资源包供玩家加载。

显然,使用资源包的主动权在玩家手中,而且服务器无法检测到玩家是否开启了资源包(在某些场合下,资源包必须开启)。

服务器觉得非常没有面子,于是开始了复仇之路……

复仇个屁啊,server.properties写一行require-resource-pack=true,玩家要是不乖乖下载资源包直接断开连接(小声)


1.1.通通安排

如果你是一名插件制作者,且你的插件需要指定的资源包,必须提供资源包的uri,客户端将会通过该地址下载指定的资源包。

如果你是一名腐竹(插件教程还有腐竹看,ε=(´ο`*))) 唉),你可以打开server.properties文件,找到resource-pack=这一行,填上资源包的uri,建议找到resource-pack-sha1=这一行把它填上(是资源包的SHA-1值),会提高资源包的可靠性缓存的有效性


额外的:

你可以调用Bukkit类中的getResourcePack方法来获取服务器资源包的uri,也可以调用getResourcePackHash获取资源包的SHA-1值。

你也可以获取自定义提示下载资源包时的消息,调用getResourcePackPrompt来实现此功能。

但是,你不可以在插件中更改以上获取到的值,只有通过更改server.properties文件才是有效的。


1.2.获取主动

于是,在之后的版本中,服务器可以请求玩家下载并使用指定的资源包,但是是否下载并使用资源包的主动权依然在玩家手中,在开始下载之前会弹出窗口提示是否下载资源包,如果玩家选择“否”那么也就无能为力了。

Player player = (Player) sender;
player.setResourcePack("<uri>");

如上,填上资源包的uri,这样客户端会弹出窗口请求下载。


1.3.你在干什么?

真是这样吗?

不!当玩家对弹出的窗口采取行动时会触发PlayerResourcePackStatusEvent事件,插件可以获取资源包的状态,必定会是以下四种状态之一:

状态解释
ACCEPTED客户端接受了资源包, 并开始下载
DECLINED客户端拒绝接受资源包
FAILED_DOWNLOAD客户端接受了资源包, 但下载失败
SUCCESSFULLY_LOADED资源包成功地下载并应用到了客户端

如果服务器要求比较苛刻,可以通过这个事件获取资源包状态,要是被拒绝了直接踢出玩家(嘿嘿)。

至于如何监听事件,在上一章已经提到过,这里就不再赘述了。


附:关于插件包资源

插件包中的资源应该位于resource这个文件夹当中,具体如图示:

在这里插入图片描述

可以调用插件主类中getResource方法获取相应的资源:

@Nullable
@Override
public InputStream getResource(@NotNull String filename);
//获取插件相应资源

获取名为filename的资源,返回类型为InputStream


也可以保存内置于插件的.jar文件的某个资源的原始内容。

@Override
public void saveResource(@NotNull String resourcePath, boolean replace);

当参数replacetrue时表示覆盖内置资源的所有内容。第一个参数表示插件.jar文件中查找的内置资源路径。

更多关于资源包的方法或其他请参阅 API文档。


2.玩家资料(PlayerProfile)

注:玩家资料在较新版本被引入,旧版本(已知是1.17及以前)没有PlayerProfile

玩家资料,顾名思义,关于某一位玩家的相关资料。想象一下,一摞资料文件放在你的桌前,你尽情翻阅着每位玩家的相关信息,是不是有一种________的感觉。

一份玩家资料(PlayerProfile接口)至少包含玩家唯一ID非空名字,完整的玩家资料除两者外还要有玩家的纹理

PlayerProfile是一个接口,所以你可以放心地使用。


2.1.「打印文件」

我们可以创建一份新的资料,至于是哪个玩家的资料取决于玩家名:

@NotNull
PlayerProfile createPlayerProfile(@Nullable UUID uniqueId, @Nullable String name);

createPlayerProfile方法在Server接口中,可以使用getServer方法来获取:

Bukkit.getServer().createPlayerProfile(UUID.randomUUID(), "<玩家名>");

返回类型是PlayerProfile接口,这就是一份玩家资料。


2.2.「审阅文件」&「核验文件」

我们拿到了一份玩家资料,首先要检查资料是否齐全,即是否是一份完整的玩家资料,我们可以使用isComplete方法来检查资料是否完整。如果不完整,我们还可以调用update方法来更新玩家资料:

@NotNull
CompletableFuture<PlayerProfile> update();

必须注意,返回的类型是CompletableFuture类。因为玩家的相关资料都在官方网站中,所以update方法需要在另外一个线程中发起一个对外连接, 以拉取官方最新资料属性

可以使用如下代码来操作更新完成的玩家资料:

profile.update().thenAcceptAsync(updatedProfile -> {
	//这里操作更新完成的玩家资料
	//...
}, runnable -> Bukkit.getScheduler().runTask(this, runnable));

thenAcceptAsync是指异步对单个处理完的结果进行操作(消费),但它不和父线程使用同一个线程,而是使用自定义的线程池,而在最后一个参数为该方法提供了Executor框架。

关于CompletableFuture<T>,有兴趣可以自行了解,本章不做详细讲解。


玩家的唯一ID及玩家名对我们来说没有一丁点价值,有价值的是玩家的纹理,纹理包括玩家的皮肤(Skin)披风(Cape),我们可以用getSkingetCape分别获取皮肤和披风,注意二者的返回类型均为URL类。

可以用setSkinsetCape方法分别设置玩家的皮肤和披风为指定的URL。但是必须指向 Minecraft 纹理服务器,比如下面的URL就是一个栗子:

http://textures.minecraft.net/texture/b3fbd454b599df593f57101bfca34e67d292a8861213d2202bb575da7fd091ac

PlayerProfile profile = Bukkit.getServer().createPlayerProfile(UUID.randomUUID(), "<玩家名>");
PlayerTextures textures = profile.getTextures();
try {
	textures.setSkin(new URL("http://textures.minecraft.net/texture/b3fbd454b599df593f57101bfca34e67d292a8861213d2202bb575da7fd091ac"));
} catch(Exception e) {
	e.printStackTrace();
	sender.sendMessage("发生异常:" + e.getMessage());
}

这样我们就设置了玩家的皮肤(其实本人没有试过行不行qwq)。

最后,为辨别真假,我们使用isSigned方法来判断这份「文件」是否有效地签名,至此一份资料就审阅完了。


感觉这是自我发布教程以来为数不多的文章了啊,虽然是“简简单单”两个方面但是唠叨了四千多字,实感不容易,也希望读者能够消化消化。

附:Bukkit 和 Spigot 之间的关系

有很多人不明白 Bukkit 和 Spigot 之间有何关系:教程写的是 Bukkit,给的文档确是 Spigot API 文档,让很多人一头雾水。

如果你在翻阅文档时,大致浏览一下 文档 所列出的所有程序包的话,你会发现几乎所有程序包都是以org.开头,只有三个程序包以net.md_5.bungee.开头。这三个程序包在万众之上,所以非常显眼。

在这里插入图片描述

之前提过,Bukkit 是一款开源、免费的项目,但由于种种原因而极其短命。Spigot 项目则继承了 Bukkit,一直存活到现在。它的地位与 Forge 和 Fabric 不相上下。

某种意义上,你可以理解为 Bukkit = Spigot。除此之外还有以org.spigotmc.开头的程序包,这是 Spigot 所特有的。

不难看出 Spigot 是一个大熔炉,用面向对象语言的特性形容 Spigot 就是两个字——继承


上一篇:我的世界Bukkit服务器插件开发教程(十二)物品与监听事件
下一篇:我的世界Bukkit服务器插件开发教程(十四)消息和命令补全器

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

自动梯度计算

神经网络的参数主要通过梯度下降来进行优化&#xff0e; 当确定了风险函数以及网络结构后&#xff0c; 我们就可以手动用链式法则来计算风险函数对每个参数的梯度&#xff0c; 并用代码进行实现&#xff0e; 但是手动求导并转换为计算机程序的过程非常琐碎并容易出错&#xff0…

二叉树的基础oj题(单值二叉树、相同的树、对称二叉树、二叉树的前序、中序、后序遍历、另一棵树的子树、二叉树的构建和遍历、翻转二叉树)

今天&#xff0c;我带来二叉树的基础oj题 目录单值二叉树&#xff1a;[链接](https://leetcode.cn/problems/univalued-binary-tree/)相同的树&#xff1a;[链接](https://leetcode.cn/problems/same-tree/)对称二叉树&#xff1a;[链接](https://leetcode.cn/problems/symmetr…

syzkaller 黑盒测试1:环境搭建

syzkaller 黑盒测试1&#xff1a;环境搭建 近期需要使用syzkaller对某Linux发行版系统内核进行测试&#xff0c;但是未提供内核源码&#xff0c;只能在黑盒条件下测试。这是笔者第一次接触syzkaller&#xff0c;对测试流程不太熟悉。另外&#xff0c;网上很少有syzkaller黑盒测…

C语言版扫雷——从0到1实现扫雷小游戏

&#x1f412;博客名&#xff1a;平凡的小苏 &#x1f4da;学习格言&#xff1a;有志者&#xff0c;事竟成&#xff0c;破釜沉舟&#xff0c;百二秦关终属楚&#xff1b;苦心人&#xff0c;天不负&#xff0c;卧薪尝胆&#xff0c;三千越甲可吞吴。 扫雷思维导图 目录 扫雷思维…

9_2、Java基本语法之常用类日期、时间类的使用

一、JDK 8之前时间日期API jdk8之前的日期时间类 1.System的currentTimeMillis() 2.java.util.Date以及子类java.sql.Date 3.SimpleDateFormat 4.Calender类&#xff1a;日历类 1、获取系统当前时间&#xff1a;System类下的currentTimeMillis(); //返回的是当前时间与1970年…

MySQL--整合Keepalived进行双机热备自动切换(升级版)

原文网址&#xff1a;MySQL--整合Keepalived进行双机热备自动切换&#xff08;升级版&#xff09;_IT利刃出鞘的博客-CSDN博客 简介 本文介绍MySQL整合Keepalived进行双机热备自动切换&#xff08;升级版&#xff09;。 服务器要考虑高可用问题。nginx、tomcat、缓存、队列、数…

Java开发的古董拍卖系统竞标系统拍卖网

简介 古董展品拍卖网站 用户可以注册成为买家也可以申请开店成为卖家&#xff0c;发布古董展品&#xff0c;设置拍卖起止时间进行展品的拍卖。如果早于拍卖开始时间或者晚于拍卖结束时间&#xff0c;则不可以竞拍。多人竞拍&#xff0c;买家可以根据最高价设置谁中标&#xff…

系分 - 结构化方法【概念】

个人总结&#xff0c;仅供参考&#xff0c;欢迎加好友一起讨论 系分 - &#xff08;概念&#xff09;结构化方法 结构化方法贯穿整个软件工程全部&#xff0c;可以单独细分出来作为某个软件工程环节的技术指引 结构化方法&#xff0c;由结构化分析&#xff08;SA&#xff0c;St…

【C语言进阶】速学,不会用数据库可不能再错过文本与二进制文件操作

目录 ✨前言✨&#xff1a; &#x1f388;一、文本文件与二进制文件&#x1f388;&#xff1a; &#x1f381;二、文件读取结束的判定&#x1f381;&#xff1a; 1.错误使用 feof 函数&#xff1a; 2.判断文件读取结束&#xff1a; &#x1f38a;三、文件缓冲区&#x1f38…

Ubuntu虚拟机图文安装详细教程

Hello, 小伙伴们&#xff0c;大家好&#xff01;今天教大家一步一步进行ubuntu虚拟机的安装。俗话说的好&#xff1a;“工欲善其事必先利其器”&#xff0c;作为一名嵌入式软件开发人员&#xff0c;我们必须熟悉Linux系统的操作及使用&#xff0c;熟练掌握Linux系统下的开发&am…

java 接口的私有方法

其实java8就已经做下伏笔了 在拥有静态和默认 两种拥有方法体的方法之后 接口出现私有方法也是一种必然 然后我们来创建一个包 包下创建一个接口 subInterface 参考代码如下 public interface subInterface {private void show2() {System.out.println("我是一个私有方…

头条权重在线查询,头条号增加权重的4个妙招

头条号权重可以简单理解为头条号指数&#xff0c;刚开通头条号的时候&#xff0c;会根据头条号的领域、介绍等等给予相应的权重。后期会根据账号使用情况进行调整权重&#xff0c;提高或者降低。 头条权重在线查询方法 打开“站长工具”之后&#xff0c;输入网站网址。…

LeetCodeday04

24. 两两交换链表中的节点 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交换&#xff09;。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3…

JavaScript篇.day08-DOM,节点,事件,定时器,位置及坐标

目录 1.DOM 2.DOM相关操作 (1)获取元素 (2)操作元素 (3)操作元素属性 (4)操作元素类名 (5)操作元素样式 3.节点操作 4.事件 5.事件传播 6.定时器 7.位置及坐标 1.DOM Document Object Model 文档对象模型一整套操作文档流相关内容的属性和方法可以做的操作: 修改样…

前端框架搭建(六)搭建页面框架【vite】

1.安装所需依赖 需要安装 vue-routernaive视图框架 npm npm install vue-router4 yarn yarn add vue-router4npm i -D naive-ui2.搭建naive适配框架 创建文件夹——存放通用组件 在components下创建文件夹common 全局配置常用组件 在之前创建的global.d.ts中添加Window…

枚举的应用

枚举&#xff1a; 在数学和计算机科学理论中&#xff0c;一个集的枚举是列出某些有穷序列集的所有成员的程序&#xff0c;或者是一种特定类型对象的计数。这两种类型经常&#xff08;但不总是&#xff09;重叠。 [1] 是一个被命名的整型常数的集合&#xff0c;枚举在日常生活…

基于CAS操作的atomic原子类型

原子操作 C A S (compare And Swap&#xff09;也叫比较交换&#xff0c;是一种无锁原子算法&#xff0c;映射到操作系统就是一条cmpxchg硬件汇编指令&#xff08;保证原子性)&#xff0c;其作用是让CPU将内存值更新为新值&#xff0c;但是有个条件&#xff0c;内存值必须与期望…

站长权重在线查询,怎么查询网站权重是多少?

什么是网站权重 当站长们辛辛苦苦建立起来一个网站&#xff0c;怎么才能知道自己的网站在搜索引擎中的权重情况呢&#xff1f; 对于很多人而言&#xff0c;权重这个词可能听到最多的场景就是淘宝京东店铺权重。淘宝或京东会根据商家网店的浏览量、好评率、转化率、是否…

4A(统一安全管控平台)解析

4A是指帐号&#xff08;Account&#xff09;、认证&#xff08;Authentication&#xff09;、授权&#xff08;Authorization&#xff09;和审计&#xff08;Audit&#xff09;&#xff0c;4A统一安全管控平台是以身份为中心&#xff0c;实现帐号、认证、授权和审计统一管控的安…

Spark注意事项

一、Spark理解 数据的操作只有两种 大数据领域中对数据的操作只有两种:聚合 & 处理 无论是多华丽算法,最终都是这两个平平无奇的操作组合而成的 action理解 在spark中,一个action操作为一个jobId(在源码中可以看到runjob 是只有在action操作后才会调用) , 所以一个…