当前位置:首页 > CN2资讯 > 正文内容

我的世界联机失败显示java

3天前CN2资讯


前往我的主页以阅读完整内容,并获取源码
DearXuan的主页

MOD介绍

使用漏斗链进行分类或传递物品时,常常会发现漏斗速度太慢,难以收集全部掉落物.或者漏斗太多,影响性能.而现有的漏斗加速mod则是引入新的快速漏斗,存在各种兼容问题.开服时发现paper服务器可以修改原版漏斗速度,而因此萌生想法,编写一个可以修改原版漏斗速度的mod.

截至发布本文时,mod已拥有物品过滤功能,未来将会添加投掷器自动发射功能.

支持版本

本mod支持Minecraft 1.19.4版本,需要Fabric及Fabric-api,以及前置mod: modmenu(≥6.2.1)

该mod仅限客户端使用.局域网联机时,仅房主需要安装,而其他成员无需安装,即使安装了也无法修改.

该MOD理论上适用于多个版本,可以在自己电脑上尝试修改版本号重新编译.

创建项目

本项目采用 IDEA 开发,在插件市场下载Minecraft Development,来快速初始化项目.

如果项目有大写字母,则创建完成后,需要前往src/main/resources/fabric.mod.json中修改id一项为小写,因为modid不支持大写字母.

创建项目需要下载大量文件,需耐心等待.创建完成后,先彻底关闭IDEA,再重写打开项目.

开发思路

本mod的功能是修改原版漏斗代码,因此需要用到fabric提供的Mixin功能,该功能可将自己的代码注入到游戏源码中,而无需对其进行修改.

此外modmenu模组提供了可视化菜单,可以方便菜单制作,因而列为前置mod.实际上即使没有该前置也可以正常运行,但是无法打开菜单.

引入依赖

在build.gradle中引入以下maven和依赖

repositories { // Add repositories to retrieve artifacts from in here. // You should only use this when depending on other mods because // Loom adds the essential maven repositories to download Minecraft and libraries from automatically. // See https://docs.gradle.org/current/userguide/declaring_repositories.html // for more information about repositories. /** * EasyHopper 依赖项 */ maven { url "https://maven.shedaniel.me/" } maven { url "https://maven.terraformersmc.com/releases/" } maven { url "https://maven.architectury.dev/" } /** * EasyHopper 依赖项结束 */ } dependencies { // To change the versions see the gradle.properties file minecraft "com.mojang:minecraft:${project.minecraft_version}" mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" // Fabric API. This is technically optional, but you probably want it anyway. modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" /** * EasyHopper 依赖项 */ modApi("me.shedaniel.cloth:cloth-config-fabric:10.0.96") { exclude(group: "net.fabricmc.fabric-api") } modApi "com.terraformersmc:modmenu:6.2.1" /** * EasyHopper 依赖项结束 */ }

此时右上角会提示重写构建,等待一段时间即可.

反编译源码

展开Gradle一栏,运行genSources,即可进行反编译.所需时间视电脑配置而定.

如果找不到这一栏,则可以在项目根目录下执行以下命令.

./gradlew genSources

如果失败则重启IDEA,多尝试几次.

Mixin配置文件

创建Mixin配置文件src/main/resources/modid.mixin.json,如图所示.注意要修改为你自己的modid

修改fabric.mod.json,天上你的Mixin配置文件名称

"mixins": [ "modid.mixins.json" ]

注册Mixin

以我的项目为例,modid为"EasyHopper",则在com.dearxuan.easyhopper下创建目录mixin,并在该目录下创建EasyHopperMixin.java

修改冷却时间

由于我们要修改漏斗函数,因此我们直接搜索漏斗的英文,简单查看后,可以发现控制漏斗事件的类为HopperBlockEntity.class,因此我们注入这个类.

在EasyHopperMixin.java中编写代码如下,注意修改为你的包名.

@Mixin(HopperBlockEntity.class) public abstract class EasyHopperMixin extends LootableContainerBlockEntity { }

其中@Mixin注释用于标识我们要注入的类.此时IDEA会将这段代码标红,因为缺少了构造函数,可以使用IDEA来自动创建.

现在这个类已经被成功注入,但我们还不知道漏斗的控制逻辑,因此无法进行编码.接下来查看HopperBlockEntity.class的源码(按住Ctrl+右键可以快速跳转),因为该游戏的事件都是基于刻(tick)来处理的,因此我们搜索"tick",仅有一个函数与此相符.为了便于分析,此处额外展示了两个用到的函数.

public static void serverTick(World world, BlockPos pos, BlockState state, HopperBlockEntity blockEntity) { --blockEntity.transferCooldown; blockEntity.lastTickTime = world.getTime(); if (!blockEntity.needsCooldown()) { blockEntity.setTransferCooldown(0); HopperBlockEntity.insertAndExtract(world, pos, state, blockEntity, () -> HopperBlockEntity.extract(world, blockEntity)); } } private boolean needsCooldown() { return this.transferCooldown > 0; } private void setTransferCooldown(int transferCooldown) { this.transferCooldown = transferCooldown; }

于是我们可以猜测,该函数控制这漏斗何时输送物品,其中blockEntity.transferCooldown是冷却时间,每个tick会减一,而needsCooldown()函数根据blockEntity.transferCooldown是否为正来判断漏斗是否处于冷却中,为零或负则是冷却完毕.

一旦冷却完毕,则执行blockEntity.setTransferCooldown(0),推测是用于防止出现负数的.而HopperBlockEntity.insertAndExtract()函数显然是用来输入输出物品的.

因此我们只需要修改setTransferCooldown()这个函数,即可实现修改冷却时间的功能.

@Mixin(HopperBlockEntity.class) public abstract class EasyHopperMixin extends LootableContainerBlockEntity { @Shadow private int transferCooldown; protected EasyHopperMixin(BlockEntityType<?> blockEntityType, BlockPos blockPos, BlockState blockState) { super(blockEntityType, blockPos, blockState); } @Inject( method = {"setTransferCooldown"}, at = {@At("HEAD")}, cancellable = true ) private void EasyCooldown_head(int cooldown, CallbackInfo info){ if(cooldown > 0){ this.transferCooldown = cooldown - 8 + ModConfig.INSTANCE.TRANSFER_COOLDOWN; info.cancel(); } } }

由于transferCooldown是私有变量,无法直接访问,因此使用@Shadow来映射.这将把原私有变量映射到你自己创建的类中,以便开发者进行修改.

你会发现我在函数参数里加了CallbackInfo info一项,这是用来控制返回值的,我们需要利用它来实现中途退出.

现在开始修改setTransferCooldown()函数,这里我们选择@Inject注释,它可以将你的代码插入到原函数中,methed指原函数名,at指插入位置,为了屏蔽掉原函数,我们应该把代码插入到原函数头部,然后直接返回,以使后面部分失效.cancellable指原函数能否中途退出,显然需要为true.

下面代码中的cooldown - 8是为了减去原有的冷却时间,从而改成我们需要的值,ModConfig.INSTANCE.TRANSFER_COOLDOWN是指我们自己规定的冷却时间,该部分在配置文件中定义,会在接下来介绍.

最后的info.cancel()指取消原函数执行,相当于在我们代码的尾部,原函数头部插入了return,即屏取消了原函数的执行.

修改传输数量

上面已分析出HopperBlockEntity.insertAndExtract()是用于执行输入输出操作,因此我们继续查看源码.

private static boolean insertAndExtract(World world, BlockPos pos, BlockState state, HopperBlockEntity blockEntity, BooleanSupplier booleanSupplier) { if (world.isClient) { return false; } if (!blockEntity.needsCooldown() && state.get(HopperBlock.ENABLED).booleanValue()) { boolean bl = false; if (!blockEntity.isEmpty()) { bl = HopperBlockEntity.insert(world, pos, state, blockEntity); } if (!blockEntity.isFull()) { bl |= booleanSupplier.getAsBoolean(); } if (bl) { blockEntity.setTransferCooldown(8); HopperBlockEntity.markDirty(world, pos, state); return true; } } return false; }

先猜测代码含义,显然第一步是判断自己是客户端还是服务端,该函数仅在服务端执行.然后检查漏斗是否在冷却中或不可用.

boolean bl = false则定义了一个布尔变量,用于判断该漏斗是否使用过,如果为true,则已经使用,那么就需要blockEntity.setTransferCooldown(8)来重新设置冷却时间.而blockEntity.isEmpty()和blockEntity.isFull()显然是用来检查容器中是否有物品的,即输入输出功能.因此我们只需要在这里加个循环即可实现任意数量物品的输入输出.

我们的思路仍然是在原函数头部插入自己的代码,注意到其中用到了四个private函数,因此我们需要先提取出这四个函数

@Mixin(HopperBlockEntity.class) interface IEasyHopperEntity { @Invoker("needsCooldown") public boolean Invoke_needsCooldown(); @Invoker("isFull") public boolean Invoke_isFull(); @Invoker("setTransferCooldown") public void Invoke_setTransferCooldown(int transferCooldown); @Invoker("insert") public static boolean Invoke_insert(World world, BlockPos pos, BlockState state, Inventory inventory){ return false; }; }

@Invoker允许你访问一个私有的方法,类似@Shadow,它可以将原本不可见的方法映射为你新定义的方法.其中静态函数必须要有函数体,不过它永远也不会执行.

编写的函数如下

@Inject( method = {"insertAndExtract"}, at = {@At("HEAD")}, cancellable = true ) private static void Insert( World world, BlockPos pos, BlockState state, HopperBlockEntity blockEntity, BooleanSupplier booleanSupplier, CallbackInfoReturnable<Boolean> info){ if (world.isClient) { info.setReturnValue(false); } if (!((IEasyHopperEntity) blockEntity).Invoke_needsCooldown() && state.get(HopperBlock.ENABLED).booleanValue()) { boolean bl = false; for(int i=0;i<ModConfig.INSTANCE.TRANSFER_OUTPUT_COUNT;i++){ if (!blockEntity.isEmpty()) { bl = IEasyHopperEntity.Invoke_insert(world, pos, state, blockEntity); } } for(int i=0;i<ModConfig.INSTANCE.TRANSFER_INPUT_COUNT;i++){ if (!((IEasyHopperEntity) blockEntity).Invoke_isFull()) { bl |= booleanSupplier.getAsBoolean(); } } if (bl) { ((IEasyHopperEntity) blockEntity).Invoke_setTransferCooldown(8); HopperBlockEntity.markDirty(world, pos, state); info.setReturnValue(true); } } info.setReturnValue(false); }

由于原函数有返回值,因此末尾需要改用CallbackInfoReturnable<Boolean> info,将原本的return true改为info.setReturnValue(true),即可实现中途退出的功能.其他代码直接复制下来即可,部分私有函数需要转换成自己刚刚定义的接口来调用.

最后,我们在easyhopper.mixin.json中注册上面的两个Mixin

{ "required": true, "minVersion": "0.8", "package": "com.dearxuan.easyhopper.mixin", "compatibilityLevel": "JAVA_17", "mixins": [ "EasyHopperMixin", "IEasyHopperEntity" ], "client": [ ], "injectors": { "defaultRequire": 1 } }

完整的EasyHopperMixin.java代码可在我的主页查看

保存配置

创建Config目录和其中的两个java文件,如下图所示

为ModConfig编写如下代码

@Config( name = "easyhopper" ) public class ModConfig implements ConfigData { @Excluded public static ModConfig INSTANCE; @Comment("控制漏斗输送物品冷却时间") public int TRANSFER_COOLDOWN = 8; @Comment("控制漏斗每次输入多少个物品") public int TRANSFER_INPUT_COUNT = 1; @Comment("控制漏斗每次输出多少个物品") public int TRANSFER_OUTPUT_COUNT = 1; public ModConfig(){ } public static void init(){ AutoConfig.register(ModConfig.class, GsonConfigSerializer::new); INSTANCE = (ModConfig) AutoConfig .getConfigHolder(ModConfig.class) .getConfig(); } }

@Config表面这个类是一个配置类,它将会被序列化后保存在游戏目录的config文件夹下.

@Excluded注释表面该字段不会被保存,@Comment则是注释,在设置界面,当鼠标悬浮于某一项上方时显示.init()函数用于注册和初始化这个类.在EasyHopper.java中执行这个函数

public class EasyHopper implements ModInitializer { @Override public void onInitialize() { ModConfig.init(); } }

在ModMenu.java中编写如下代码

package com.dearxuan.easyhopper.Config; import com.terraformersmc.modmenu.api.ConfigScreenFactory; import com.terraformersmc.modmenu.api.ModMenuApi; import me.shedaniel.autoconfig.AutoConfig; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; @Environment(EnvType.CLIENT) public class ModMenu implements ModMenuApi { @Override public ConfigScreenFactory<?> getModConfigScreenFactory(){ return parent -> AutoConfig .getConfigScreen(ModConfig.class, parent) .get(); } }

此代码将会为该配置类自动生成一个图形界面,便于用户可视化修改.只有安装了前置模组modmenu才会看到设置按钮,同时许多模组也使用了该前置mod.即使不安装,也可以正常运行,但是修改配置较为麻烦,因此列入到前置模组名单,来强制用户安装.同时还要添加modmenu的入口点.修改fabric.mod.json如下

{ //***// "entrypoints": { "client": [ "com.dearxuan.easyhopper.client.EasyHopperClient" ], "main": [ "com.dearxuan.easyhopper.EasyHopper" ], "modmenu": [ "com.dearxuan.easyhopper.Config.ModMenu" ] }, "mixins": [ "easyhopper.mixins.json" ], "depends": { "fabricloader": ">=${loader_version}", "fabric": "*", "fabric-api": "*", "minecraft": "${minecraft_version}", "modmenu": ">=6.2.1" } }

至此mod开发完毕.


    你可能想看:

    扫描二维码推送至手机访问。

    版权声明:本文由皇冠云发布,如需转载请注明出处。

    本文链接:https://www.idchg.com/info/22101.html

    分享给朋友:

    “我的世界联机失败显示java” 的相关文章

    美国远程游戏主机:如何选择最佳服务以提升游戏体验

    美国远程游戏主机市场近年来发展迅速,吸引了大量用户和企业的关注。这个市场不仅提供了多样化的产品和服务,还满足了从个人玩家到大型游戏开发公司的不同需求。无论是高性能计算、低延迟连接,还是全球覆盖和安全性,美国远程游戏主机市场都在不断优化和创新。 市场现状与发展趋势 美国远程游戏主机市场的现状可以用“多...

    2023年最佳VPS服务商排名与推荐

    在数字化时代,VPS(虚拟专用服务器)成为了很多企业和开发者青睐的主机解决方案。简单来说,VPS是将一台物理服务器划分成多个虚拟服务器,每个虚拟服务器都能够独立运行它自己的操作系统和应用。这样的设计不仅提升了资源利用率,还为用户提供了更高的灵活性与控制权,尤其适合需要稳定性能的中小型企业和开发者。...

    国外常用ping工具及其使用方法

    ping工具在国外的应用 什么是ping工具?其基本功能和重要性 ping工具是一种非常实用的网络诊断工具,通过向指定的IP地址发送数据包来检测网络连接的质量。当我们在互联网上进行访问时,ping工具能够帮助我们了解网络延迟、丢包率等关键指标。这些信息对于网站运营者和普通用户来说都是极其重要的,因为...

    宝塔面板PHP扩展新增指南:提升网站性能的实用技巧

    在日常网站管理和服务器配置中,宝塔面板的出现让这一切变得更为简单直观。作为一个流行的服务器控制面板,宝塔面板以其用户友好的界面和丰富的功能备受欢迎。对于没有技术背景的用户来说,它提供了极大的便利,而对于开发者来说,宝塔也能高效管理复杂的服务器配置。 宝塔面板不仅支持多种服务器环境,还能够轻松管理数据...

    选择香港机房的优势与服务:最理想的数据中心解决方案

    在当今数字化的时代,香港机房作为亚洲地区的数据中心枢纽,其重要性愈发凸显。随着全球对高效、安全、稳定数据处理需求的上升,香港凭借其优越的地理位置和完善的网络基础设施,已成为众多企业首选的托管与服务器服务地点。以高速网络连接、优质的BGP多线路接入以及高标准的设施著称,香港机房为客户提供了一系列的解决...

    VPS CN2:提升网络性能的最佳选择

    在了解VPS CN2之前,我觉得有必要先简单说说VPS究竟是什么。VPS即虚拟专用服务器,是一种利用虚拟化技术将物理服务器划分成多个独立的虚拟服务器。每个VPS都能独立运行操作系统和应用软件,用户可以通过远程方式管理和使用。这给了我们极大的灵活性和自由度,让我可以随时根据需求扩大或缩小资源。 说到V...