我的世界Java版1.21.4的Fabric模組開發教程(十四)方塊實體

這是適用于Minecraft Java版1.21.4的Fabric模組開發系列教程專欄第十四章——方塊實體。想要閱讀其他內容,請查看或訂閱上面的專欄。

方塊實體(Block Entity) 指的是一種用于存儲方塊額外數據的方法。但這種數據和為了控制方塊狀態而在自定義方塊類中創建的屬性不太相同,通常方塊實體中的數據可能需要進行邏輯處理和計算,且一般不會直接體現在方塊上。

不過,本章中創建的帶有方塊實體的自定義方塊始終使用了方塊實體中的數據來控制方塊外觀——光源方塊(light_block),玩家通過使用(右鍵點擊)“光源方塊”來動態切換其光照強度,每點擊一下,方塊的光照強度將+1;如果光照強度已經為15,則重置光照強度為0。

要創建“光源方塊”,需要按照以下步驟推進:

  • 創建方塊實體類;
  • 創建方塊實體注冊類;
  • 注冊方塊實體;
  • 創建帶有方塊實體功能的方塊類;
  • 注冊方塊并將其添加到物品組中;
  • 完成創建方塊的其他工作;
  • 在方塊實體類中添加數據;
  • 在方塊類中使用方塊實體;

創建方塊實體類

要創建方塊對應的實體,需要創建一個方塊實體類,并使其繼承BlockEntity類。


方塊實體類BlockEntity

BlockEntity類一般作為方塊實體類的父類,用于保存一個世界中方塊的額外數據。通常,方塊的數據由預定義的、有限的方塊狀態數據集合保存。但是,方塊需要存儲一些不能被預定義的數據,例如箱子里的物品、告示牌上的文字等,方塊實體可以存儲這些數據。

通常,繼承了BlockEntity類的自定義方塊實體類需要調用其構造方法;

public BlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {this.type = type;this.pos = pos.toImmutable();this.validateSupports(state);this.cachedState = state;
}

其中需要傳遞方塊實體類型BlockEntityType對象、方塊位置BlockPos對象和方塊狀態BlockState對象。

方塊實體類型類BlockEntityType

BlockEntityType類用于定義和管理方塊實體類型。在創建完實體類后,還需要在游戲注冊表中注冊實體類,此時將返回一個BlockEntityType對象,需要在實體類的構造方法中使用。


1.創建com/example/test/block/entity/custom目錄,然后在其中創建LightBlockEntity并繼承BlockEntity類;

public class LightBlockEntity extends BlockEntity {}

2.聲明構造方法,在方法體中調用其父類的構造方法;

public LightBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {super(type, pos, state);
}

稍后我們將修改此處的BlockEntityType對象。

創建方塊實體注冊類

方塊實體注冊類用于將所有方塊實體注冊到游戲注冊表中。一般,其中有三部分內容:

  • 封裝的register()方法:用于注冊方塊實體,并返回一個BlockEntityType對象;
  • 類型為BlockEntityType<T>的靜態常量:代表已經注冊的方塊實體。稍后將被對應的方塊實體類的構造方法所使用;
  • initialize():用于初始化方塊實體注冊類。需要在入口點類的onInitialize()方法中調用;

1.在com/example/test/block/entity目錄中創建ModBlockEntities.java

public class ModBlockEntities {}

2.聲明靜態私有方法register()。根據官方文檔,register()的寫法應該如下:

private static <T extends BlockEntity> BlockEntityType<T> register(String name,FabricBlockEntityTypeBuilder.Factory<? extends T> entityFactory,Block... blocks
) {Identifier id = Identifier.of(FabricDocsReference.MOD_ID, name);return Registry.register(Registries.BLOCK_ENTITY_TYPE, id, FabricBlockEntityTypeBuilder.<T>create(entityFactory, blocks).build());
}

方法提供三個參數,分別為注冊的方塊實體名name、Fabric方塊實體類型構造器工廠內部類FabricBlockEntityTypeBuilder.Factory對象的表達式和方塊對象block。方法首先調用了Identifier.of`()方法創建方塊實體的標識符對象,其中使用了模組Id和參數中的方塊實體名name,最后返回BlockEntityType對象,同時也是Registry.register()方法的返回值,其中傳遞了注冊鍵類型為方塊實體類型Registries.BLOCK_ENTITY_TYPE、標識符對象以及build()方法返回的BlockEntityType對象;

3.聲明initialize()方法,用于初始化方塊實體注冊類;

public static void initialize() {Test.LOGGER.info("Registering ModBlockEntities !!!");
}

其中可以輸出日志信息;

4.在入口點類的onInitialize()方法中調用ModBlockEntities.initialize()方法;

public void onInitialize() {//...ModBlockEntities.initialize();//...
}

完成方塊實體注冊類的初始化。

注冊方塊實體

現在,我們可以直接在方塊實體注冊類中將方塊實體注冊到游戲注冊表中。

1.在ModBlockEntities類中聲明靜態常量LIGHT_BLOCK_ENTITY,調用register()方法對其初始化;

public static final BlockEntityType<LightBlockEntity> LIGHT_BLOCK_ENTITY =register("light", LightBlockEntity::new, ModBlocks.LIGHT_BLOCK);

方法中分別傳遞了方塊實體路徑名“light”、Fabric方塊實體類型構造器工廠內部類FabricBlockEntityTypeBuilder.Factory對象的表達式LightBlockEntity::new,這里使用了方塊實體類構造方法的表達式,以及方塊對象ModBlocks.LIGHT_BLOCK

這里的ModBlocks.LIGHT_BLOCK指的是方塊對象,稍后我們將在方塊注冊類中聲明并對其初始化;

2.完成后,回到方塊實體類LightBlockEntity,修改構造方法;

public LightBlockEntity(BlockPos pos, BlockState state) {super(ModBlockEntities.LIGHT_BLOCK_ENTITY,pos, state);
}

首先刪除BlockEntityType<?> type參數,然后將super()方法中第一個參數改為剛剛注冊完畢的方塊實體對象ModBlockEntities.LIGHT_BLOCK_ENTITY

創建帶有方塊實體功能的方塊類

與普通方塊創建的過程有所不同,創建帶有方塊實體功能的方塊類時,方塊類需要繼承BlockWithEntity類并重寫相關方法。

1.創建com/example/test/block/custom目錄,在其中創建LightBlock.java并繼承BlockWithEntity類;

public class LightBlock extends BlockWithEntity {}

2.聲明構造方法;

public LightBlock(Settings settings) {super(settings);
}

3.重寫getCodec()方法,處理方塊實體中數據的序列化與反序列化;

@Override
protected MapCodec<? extends BlockWithEntity> getCodec() {return createCodec(LightBlock::new);
}

其中調用createCodec()方法,其中傳遞抽象方塊設置內部類和自定義方塊類的函數表達式,此處使用了方塊類的構造方法;

4.重寫createBlockEntity()方法,在方法體中調用方塊實體類的構造方法,用于在創建方塊時完成方塊實體的初始化。

@Nullable
@Override
public BlockEntity createBlockEntity(BlockPos pos, BlockState state) {return new LightBlockEntity(pos, state);
}

注冊方塊并將其添加到物品組中

現在,我們在方塊注冊類中使用自定義方塊類注冊方塊,這與其他方塊的注冊方式相同。

1.在方塊注冊類ModBlocks中聲明靜態常量LIGHT_BLOCK,調用register()方法對其進行初始化;

public static final Block LIGHT_BLOCK = register("light_block",LightBlock::new,AbstractBlock.Settings.create(),true
);

按順序依次設置了方塊名為“light_block”、抽象方塊設置內部類對象和方塊對象的函數式LightBlock::new、抽象方塊設置內部類對象并要求注冊方塊對應的方塊物品;

2.在入口點類的onInitialize()方法中,將方塊添加到指定物品組中。

ItemGroupEvents.modifyEntriesEvent(CUSTOM_ITEM_GROUP_KEY).register((itemGroup) -> {...itemGroup.add(ModBlocks.LIGHT_BLOCK.asItem());...});

完成創建方塊的其他工作

與創建普通方塊相同,我們還要為方塊:

  • 創建模型文件;
  • 創建模型描述文件;
  • 創建方塊紋理;
  • 創建方塊狀態文件;
  • 在語言文件中為其添加翻譯鍵值對;

1.在assets/test/models/block目錄中創建light_block.json作為方塊的模型文件;

{"parent": "minecraft:block/cube_all","textures": {"all": "test:block/light_block"}
}

2.在assets/test/items目錄中創建light_block.json作為方塊的模型描述文件;

{"model": {"type": "minecraft:model","model": "test:block/ice_wood"}
}

3.在assets/test/textures/block目錄中創建方塊的紋理圖light_block.png

在這里插入圖片描述
4.在assets/test/blockstates目錄中創建light_block.json作為方塊狀態文件;

{"variants": {"": {"model": "test:block/light_block"}}
}

5.在zh-cn.json中添加一條翻譯鍵值對;

{..."item.test.light_block": "光源方塊",...
}

啟動游戲測試

現在,方塊的基礎內容以及創建完畢,游戲中應當可以正常顯示方塊。

1.打開游戲,在創造模式物品欄中找到“光源方塊”;
在這里插入圖片描述
名稱、紋理等可以正常顯示;

2.將其放置在地面上,可以看到方塊模型顯示正常;
在這里插入圖片描述
但是方塊現在沒有任何功能,我們要通過方塊實體為其添加數據。

在方塊實體類中添加數據

下面,我們將方塊發光時的光照等級數值存儲在方塊實體中并編寫數據變化的邏輯。

1.聲明私有變量level,使其初始值為0,用于存儲光照等級;

private int level = 0;

2.為level變量聲明一個getLevels()方法,用于獲取光照等級;

public int getLevels() {return level;
}

3.聲明calculateLevels()方法,用于為光照等級數值添加計算邏輯;

public void calculateLevels() {if(level >= 15){level = 0;}else {level++;}
}

一般方塊的最高光照等級為15。因此,右鍵使用方塊時,當光照等級小于15時,光照等級將+1;否則,將光照等級重置為0。

在方塊類中使用方塊實體

現在,我們可以使用方塊實體中的數據來控制“光源方塊”的光照強度。

不過,想要控制方塊的光照等級,依然需要在方塊類中創建用于修改方塊狀態的屬性,然后通過方塊實體將已經計算完畢,或者說已經執行完邏輯處理的數據傳遞給方塊屬性,從而修改方塊的光照強度;

實際上,方塊實體中的數據是可以直接使用的。只是在這個例子中,修改方塊光源的方法luminance()由內部類AbstractBlock.Settings提供,而其中傳遞的是泛型為BlockState的函數式接口ToIntFunction的函數表達式,這使得方塊的光照強度只能通過方塊狀態修改;

所以,我們要先為方塊類添加用于修改方塊狀態的屬性,然后再使用方塊實體。


整型屬性類IntProperty

IntProperty用于為方塊提供控制方塊狀態的整型屬性。其構造方法已經私有化,所以想要創建一個IntProperty對象,通常調用其靜態方法of()

public static IntProperty of(String name, int min, int max) {return new IntProperty(name, min, max);
}

可以看到方法體中直接調用了構造方法,其中需要傳遞三個參數:

  • String name:指定屬性名;
  • int min:指定屬性的最小值;
  • int max:指定屬性的最大值;

通過minmax變量限制整型數據值的范圍。


1.聲明靜態常量LIGHT_LEVEL,類型為IntProperty,調用靜態方法IntProperty.of()對其初始化;

public static final IntProperty LIGHT_LEVEL = IntProperty.of("light_level", 0, 15);

方法中分別設置了屬性名為"light_level"以及數值的范圍在0~15;

2.重寫appendProperties()方法,將屬性LIGHT_LEVEL添加到方塊中;

@Override
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {builder.add(LIGHT_LEVEL);
}

調用StateManager.Builder對象的add()方法,將屬性附加到方塊中;

3.修改構造方法,在super()方法中調用AbstractBlock.Settings對象的luminance()方法,在構造方塊對象時直接修改方塊的光照強度;

public LightBlock(Settings settings) {super(settings.luminance(state -> state.get(LIGHT_LEVEL)));
}

luminance()方法中傳遞通過當前方塊狀態對象的get()方法返回的光照強度的LIGHT_LEVEL的值;

4.重寫onUse()方法,在方法體中使用方塊實體中的數據來修改當前方塊的光照強度LIGHT_LEVEL

@Override
protected ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, BlockHitResult hit) {LightBlockEntity lightBlockEntity = (LightBlockEntity) world.getBlockEntity(pos);if(!world.isClient && lightBlockEntity != null) {lightBlockEntity.calculateLevels();world.setBlockState(pos, state.with(LIGHT_LEVEL, lightBlockEntity.getLevels()));}return ActionResult.SUCCESS;
}

首先調用world.getBlockEntity()方法獲取指定方塊坐標的方塊實體對象,方法中傳遞一個BlockPos對象,即當前方塊的坐標對象,將返回的方塊實體對象存儲在lightBlockEntity中;

接著,在確保當前世界對象為服務器世界對象且方塊實體對象不為null的基礎上,調用方塊實體對象的calculateLevels()方法,處理光照強度的變化邏輯;

然后調用world.setBlockState()方法修改當前方塊的方塊狀態,方法中傳遞要修改的方塊坐標對象pos,以及修改后的方塊狀態對象,這里調用了state.with()方法,將當前光照等級修改為方塊實體中光照等級lightBlockEntity.getLevels()的值;

最后返回ActionResult.SUCCESS,代表操作成功;

5.現在,方塊所有功能已經通過方塊實體實現,可以再次啟動游戲進行測試;

打開游戲,修改世界時間為13000,將“光源方塊”放置在地面上,持續右鍵點擊方塊,可以發現方塊光照強度越來越高。
請添加圖片描述

本章小結

本章詳細闡述了方塊實體的作用與創建的過程。如果沒有方塊創建和方塊狀態等前置知識的支撐,閱讀本文的難度較高,還請參考專欄的其他文章。感謝各位的閱讀,有興趣可以訂閱此專欄!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/88799.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/88799.shtml
英文地址,請注明出處:http://en.pswp.cn/web/88799.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【UE教程/進階】UE中的指針與引用

目錄直接屬性引用共享指針 TSharedPtr實現原理共享引用 TSharedRef弱引用指針 TWeakPtrObject弱指針 FWeakPtr實現原理Object軟指針 FSoftObjectPtr原理直接屬性引用 在c通過UPROPERTY()宏將屬性公開&#xff0c;藍圖中屬性類型中的Object Reference。 對一個類型及其子類型的…

早期 CNN 的經典模型—卷積神經網絡(LeNet)

目錄 LeNet 的設計背景與目標 LeNet 的網絡結構&#xff08;經典 LeNet-5&#xff09; 局部感受野詳解 一、局部感受野和全連接網絡的區別 1. 傳統全連接網絡的問題 2. 局部感受野的解決方案 二、局部感受野的優勢 1. 參數大幅減少 2. 提取局部特征 3. 平移不變性 參數…

RabbitMQ 高級特性之延遲隊列

1. 簡介 在某些場景下&#xff0c;當生產者發送消息后&#xff0c;可能不需要讓消費者立即接收到&#xff0c;而是讓消息延遲一段時間后再發送給消費者。 2. 實現方式 2.1 TTL 死信隊列 給消息設置過期時間后&#xff0c;若消息在這段時間內沒有被消費&#xff0c;就會將消…

uniapp app安卓下載文件 圖片 doc xls 數據流文件 app安卓本地路徑下載保存

//下載圖片 downloadToLocal() {plus.android.requestPermissions([android.permission.WRITE_EXTERNAL_STORAGE],(success) > {uni.saveImageToPhotosAlbum({filePath: /static/x.png,//本地地址success: () > {this.$refs.uToast.show({message: "模版下載成功&am…

Context Engineering:從Prompt Engineering到上下文工程的演進

最近在做Deepresearch以及刷到一個不錯的文章&#xff1a;context-engineering-guide &#xff0c;這篇文章揭示了提示工程以及上下文過程在智能體應用開源流程中&#xff0c;包括Deepresearch&#xff0c;MCP在內的一些概念&#xff0c;起到了非常重要的作用&#xff01; Cont…

jenkins部署vue前端項目

文章目錄前言一、安裝nginx二、jenkins構建項目總結前言 前面已經使用jenkins部署了后端springboot項目&#xff0c;現在開始學習jenkins部署前端Vue項目。 一、安裝nginx 訪問nginx官網&#xff0c;https://nginx.org/en/download.html下載tar包 上傳到服務器目錄中 然后到…

設計總監年中復盤:用Adobe XD內容識別布局,告別“手動調距”

時至年中&#xff0c;這不僅是檢視上半年項目成果的節點&#xff0c;更是優化團隊工作流、為下半年挑戰儲備動能的關鍵時期。在海外設計界工作的十余年間&#xff0c;我發現&#xff0c;一個高效的設計團隊與一個疲于奔命的團隊之間&#xff0c;最大的差別往往就在于是否建立了…

Unity 在Rider中通過Lingma插件使用MCP

環境&#xff1a; Unity 2022.3.12f1 JetBrains Rider 2025.1.4 Lingma 2.5.14 Python 3.13.4 下載包 首先在unity package manager 加入unity-mcp包 https://github.com/justinpbarnett/unity-mcp.git 然后下載uv包&#xff08;要先先下載python&#xff09;,網上很多…

pycharm+SSH 深度學習項目 遠程后臺運行命令

pycharmSSH 深度學習項目 遠程后臺運行命令碎碎念&#xff0c;都是實驗室里那說關機就關機&#xff0c;說重啟就重啟的臺式機逼得。。學吧記錄 運行&#xff1a;nohup /root/miniconda3/bin/python -u "run.py" > /root/log/nohup.log 2>&1 &實時查看日…

【Linux | 網絡】應用層(HTTP)

目錄一、認識URL二、urlencode和urldecode三、HTTP協議格式&#xff08;使用Fiddler抓包&#xff09;3.1 安裝并使用Fiddler抓包3.2 HTTP協議格式3.2.1 HTTP請求3.2.1.1 資源URL路徑3.2.1.2 請求方法&#xff08;Method&#xff09;3.2.1.3 Location頭字段&#xff08;重定向相…

編程實踐:單例模式(懶漢模式+餓漢模式)

說明:本專欄文章有兩種解鎖方案 1:付費訂閱,暢享所有文章 2:免費獲取,點擊下方鏈接,關注,自動獲取免費鏈接 https://free-img.400040.xyz/4/2025/04/29/6810a50b7ac8b.jpg 主題:C++ 單例模式 什么是單例模式

破局電機制造四大痛點:MES與AI視覺的協同智造實踐

萬界星空科技電機行業MES系統解決方案是針對電機制造過程中多工序協同難、質量追溯復雜、設備管理要求高等痛點設計的數字化管理系統。一、電機行業的核心痛點1. 多工序協同困難 電機制造涉及繞線、裝配、測試等多道工序&#xff0c;工藝銜接復雜&#xff0c;傳統人工調度效率…

HTML 初體驗

HTML&#xff08;超文本標記語言&#xff09;全稱&#xff1a;HyperText Markup Language。超文本是什么&#xff1f;答&#xff1a;超文本就是網頁中的鏈接。標記是什么&#xff1f;答&#xff1a;標記也叫標簽&#xff0c;是帶尖括號的文本。需求1&#xff1a;將“我愛中國”…

網絡層TCP機制

1.確認應答機制由于發送信息的距離可能較遠,可能出現后發的信息先到的情況,怎么辦?TCP將每個字節的數據都進行了編號,即為序列號如何分辨一個數據包是普通數據還是應答數據呢2.超時重傳由于丟包是一個隨機的事件,因此在上述tcp傳輸的過程中,丟包就存在兩種情況但是在發送方的角…

【一起來學AI大模型】微調技術:LoRA(Low-Rank Adaptation) 的實戰應用

LoRA&#xff08;Low-Rank Adaptation&#xff09; 的實戰應用&#xff0c;使用 Hugging Face 的 peft (Parameter-Efficient Fine-Tuning) 庫對大型語言模型進行高效微調。LoRA 因其顯著降低資源消耗&#xff08;顯存和計算&#xff09;同時保持接近全量微調性能的特點&#x…

RedisJSON 內存占用剖析與調優

一、基礎內存模型指針包裝 所有 JSON 值&#xff08;標量、對象、數組、字符串等&#xff09;至少占用 8 字節&#xff0c;用于存儲一個帶類型標記的指針。標量與空容器 null、true、false、小整數&#xff08;靜態緩存&#xff09;、空字符串、空數組、空對象 均不分配額外內存…

【LeetCode 熱題 100】23. 合并 K 個升序鏈表——(解法一)逐一合并

Problem: 23. 合并 K 個升序鏈表 題目&#xff1a;給你一個鏈表數組&#xff0c;每個鏈表都已經按升序排列。 請你將所有鏈表合并到一個升序鏈表中&#xff0c;返回合并后的鏈表。 文章目錄整體思路完整代碼時空復雜度時間復雜度&#xff1a;O(K * N)空間復雜度&#xff1a;O(1…

垃圾收集器-Serial Old

第一章 引言1.1 JVM 中垃圾收集的簡要概述JVM&#xff08;Java Virtual Machine&#xff09;作為 Java 程序的運行時環境&#xff0c;負責將字節碼加載至內存并執行&#xff0c;同時也承擔著內存管理的重任。垃圾收集&#xff08;Garbage Collection&#xff0c;簡稱 GC&#x…

Docker(02) Docker-Compose、Dockerfile鏡像構建、Portainer

Docker-Compose 1、Docker Desktop 在Windows上安裝Docker服務&#xff0c;可以使用Docker Desktop這個應用程序。 下載并安裝這樣的一個安裝包 安裝好后&#xff1a;執行命令 docker --version 從Docker Hub提取hello-world映像并運行一個容器&#xff1a; docker run h…

大數據時代UI前端的用戶體驗設計新思維:以數據為驅動的情感化設計

hello寶子們...我們是艾斯視覺擅長ui設計和前端數字孿生、大數據、三維建模、三維動畫10年經驗!希望我的分享能幫助到您!如需幫助可以評論關注私信我們一起探討!致敬感謝感恩!一、引言&#xff1a;從 “經驗設計” 到 “數據共情” 的體驗革命傳統 UI 設計常陷入 “設計師主觀經…