<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh-Hans-CN">
	<id>https://mcbbs.wiki/index.php?action=history&amp;feed=atom&amp;title=%E7%94%A8%E6%88%B7%3AMashKJo%2F1.12.2%E6%A8%A1%E7%BB%84%E5%BC%80%E5%8F%91%E6%95%99%E7%A8%8B%2F2.%E5%9F%BA%E7%A1%80%E6%A6%82%E5%BF%B5</id>
	<title>用户:MashKJo/1.12.2模组开发教程/2.基础概念 - 版本历史</title>
	<link rel="self" type="application/atom+xml" href="https://mcbbs.wiki/index.php?action=history&amp;feed=atom&amp;title=%E7%94%A8%E6%88%B7%3AMashKJo%2F1.12.2%E6%A8%A1%E7%BB%84%E5%BC%80%E5%8F%91%E6%95%99%E7%A8%8B%2F2.%E5%9F%BA%E7%A1%80%E6%A6%82%E5%BF%B5"/>
	<link rel="alternate" type="text/html" href="https://mcbbs.wiki/index.php?title=%E7%94%A8%E6%88%B7:MashKJo/1.12.2%E6%A8%A1%E7%BB%84%E5%BC%80%E5%8F%91%E6%95%99%E7%A8%8B/2.%E5%9F%BA%E7%A1%80%E6%A6%82%E5%BF%B5&amp;action=history"/>
	<updated>2026-05-06T09:33:14Z</updated>
	<subtitle>本wiki上该页面的版本历史</subtitle>
	<generator>MediaWiki 1.40.3</generator>
	<entry>
		<id>https://mcbbs.wiki/index.php?title=%E7%94%A8%E6%88%B7:MashKJo/1.12.2%E6%A8%A1%E7%BB%84%E5%BC%80%E5%8F%91%E6%95%99%E7%A8%8B/2.%E5%9F%BA%E7%A1%80%E6%A6%82%E5%BF%B5&amp;diff=55362&amp;oldid=prev</id>
		<title>MashKJo：​/* 注册表 */</title>
		<link rel="alternate" type="text/html" href="https://mcbbs.wiki/index.php?title=%E7%94%A8%E6%88%B7:MashKJo/1.12.2%E6%A8%A1%E7%BB%84%E5%BC%80%E5%8F%91%E6%95%99%E7%A8%8B/2.%E5%9F%BA%E7%A1%80%E6%A6%82%E5%BF%B5&amp;diff=55362&amp;oldid=prev"/>
		<updated>2026-04-23T08:22:42Z</updated>

		<summary type="html">&lt;p&gt;&lt;span dir=&quot;auto&quot;&gt;&lt;span class=&quot;autocomment&quot;&gt;注册表&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;zh-Hans-CN&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;←上一版本&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;2026年4月23日 (四) 16:22的版本&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l60&quot;&gt;第60行：&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;第60行：&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;注册表是什么？那要先从“注册项”这个概念说起。&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;注册表是什么？那要先从“注册项”这个概念说起。&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;Minecraft原版中有着各种游戏元素，如物品、方块、状态效果、实体等等，这些游戏要素的很多行为（包括方块的“长按左键挖掘”这种通用行为，以及实体的“靠近玩家会尝试爆炸”这种仅在苦力怕这种生物上会体现的特殊行为），显然，是必须要在游戏初始化时完成设置的——不然游戏初始化有什么意义？干脆就在遇到某个游戏要素的时候读取相关逻辑不就好了？——显然，这种设计是很不好的。&lt;/del&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;Minecraft原版中有着各种游戏元素，如物品、方块、状态效果、实体等等，游戏需要以某种方式知道总共都有什么游戏元素，以方便管理。&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;所以在这种情况下，显然就需要一种东西来统筹这些游戏元素的逻辑的初始化，被统筹的游戏元素都是&#039;&#039;&#039;注册项&#039;&#039;&#039;，而统筹者则是&#039;&#039;&#039;注册表&#039;&#039;&lt;/del&gt;&#039;。一般而言，注册项会在FMLPreInitialization阶段被注册。想想看：如果没有注册表，就拿物品（Item）这一注册项举例，MC如何能获取到你想要添加到游戏中的所有物品呢？难不成还要用黑科技读取你的项目中的所有继承了Item类的类，再用&amp;lt;code&amp;gt;Class#newInstance&amp;lt;/code&amp;gt;手动构造实例？或者自动检索所有Item的实例？这根本不可行。所以注册表应运而生。&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;所以在这种情况下，注册表应运而生&lt;/ins&gt;&#039;。一般而言，注册项会在FMLPreInitialization阶段被注册。想想看：如果没有注册表，就拿物品（Item）这一注册项举例，MC如何能获取到你想要添加到游戏中的所有物品呢？难不成还要用黑科技读取你的项目中的所有继承了Item类的类，再用&amp;lt;code&amp;gt;Class#newInstance&amp;lt;/code&amp;gt;手动构造实例？或者自动检索所有Item的实例？这根本不可行。所以注册表应运而生。&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;Minecraft原版就有一套注册表系统，不过它的实现太过于丑陋，也根本就存在很多问题——如，你会发现使用它注册注册项时，你还需要显式指定每个实例的数字ID。那么请问你如何保证你的模组的注册项的数字ID不会和其他模组的发生冲突呢？实际上Minecraft在1.13也弃用了这种注册模式。&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;Minecraft原版就有一套注册表系统，不过它的实现太过于丑陋，也根本就存在很多问题——如，你会发现使用它注册注册项时，你还需要显式指定每个实例的数字ID。那么请问你如何保证你的模组的注册项的数字ID不会和其他模组的发生冲突呢？实际上Minecraft在1.13也弃用了这种注册模式。&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l70&quot;&gt;第70行：&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;第70行：&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;所有注册项的类都实现了IForgeRegistryEntry&amp;lt;V&amp;gt;这一接口，这个接口主要规定了关于注册名的一些规范，实际上这个接口有个静态内部类：Impl&amp;lt;T&amp;gt; implements IForgeRegistryEntry&amp;lt;T&amp;gt;，所以实际上所有注册项的类是继承了这个类，这个类提供了IForgeRegistryEntry&amp;lt;V&amp;gt;的默认实现。也就是说，理论上你可以通过T extends IForgeRegistryEntry.Impl&amp;lt;T&amp;gt;来设定：可以用Forge的注册表系统给你的某个自定义的游戏元素进行注册，不过一般没必要这么做。&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;所有注册项的类都实现了IForgeRegistryEntry&amp;lt;V&amp;gt;这一接口，这个接口主要规定了关于注册名的一些规范，实际上这个接口有个静态内部类：Impl&amp;lt;T&amp;gt; implements IForgeRegistryEntry&amp;lt;T&amp;gt;，所以实际上所有注册项的类是继承了这个类，这个类提供了IForgeRegistryEntry&amp;lt;V&amp;gt;的默认实现。也就是说，理论上你可以通过T extends IForgeRegistryEntry.Impl&amp;lt;T&amp;gt;来设定：可以用Forge的注册表系统给你的某个自定义的游戏元素进行注册，不过一般没必要这么做。&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;使用原版的注册表时，没有“注册名”这一说——但是我们用的是Forge的注册表，所以必须在注册对象前，设定该对象的注册名：通过setRegistryName这个方法设定。这个方法可以接受一个ResourceLocation，但也可以接受这样两种形参列表：&amp;lt;code&amp;gt;(String name)&amp;lt;/code&amp;gt;和&amp;lt;code&amp;gt;(String modid, String name)&amp;lt;/code&amp;gt;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;，用法可以类比ResourceLocation的那两个构造方法，笔者这里就不细说了。如果你尝试注册未设定注册名的注册项对象（即注册名为null），则肯定会崩游戏，抛NullPointerException。&lt;/del&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;使用原版的注册表时，没有“注册名”这一说——但是我们用的是Forge的注册表，所以必须在注册对象前，设定该对象的注册名：通过setRegistryName这个方法设定。这个方法可以接受一个ResourceLocation，但也可以接受这样两种形参列表：&amp;lt;code&amp;gt;(String name)&amp;lt;/code&amp;gt;和&amp;lt;code&amp;gt;(String modid, String name)&amp;lt;/code&amp;gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;，用法可以类比ResourceLocation的那两个构造方法，作者这里就不细说了。如果你尝试注册未设定注册名的注册项对象（即注册名为null），则肯定会崩游戏，抛NullPointerException。&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;=== @ObjectHolder ===&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;=== @ObjectHolder ===&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;利用&amp;lt;code&amp;gt;@GameRegistry.ObjectHolder&amp;lt;/code&amp;gt;这个注解，我们可以自动给某个类型为&amp;lt;T extends IForgeRegistryEntry&amp;lt;T&amp;gt;&amp;gt;的变量赋值。&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;利用&amp;lt;code&amp;gt;@GameRegistry.ObjectHolder&amp;lt;/code&amp;gt;这个注解，我们可以自动给某个类型为&amp;lt;T extends IForgeRegistryEntry&amp;lt;T&amp;gt;&amp;gt;的变量赋值。&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;

&lt;!-- diff cache key mcbbs_wiki:diff::1.12:old-55361:rev-55362 --&gt;
&lt;/table&gt;</summary>
		<author><name>MashKJo</name></author>
	</entry>
	<entry>
		<id>https://mcbbs.wiki/index.php?title=%E7%94%A8%E6%88%B7:MashKJo/1.12.2%E6%A8%A1%E7%BB%84%E5%BC%80%E5%8F%91%E6%95%99%E7%A8%8B/2.%E5%9F%BA%E7%A1%80%E6%A6%82%E5%BF%B5&amp;diff=55361&amp;oldid=prev</id>
		<title>MashKJo：​/* @SideOnly */</title>
		<link rel="alternate" type="text/html" href="https://mcbbs.wiki/index.php?title=%E7%94%A8%E6%88%B7:MashKJo/1.12.2%E6%A8%A1%E7%BB%84%E5%BC%80%E5%8F%91%E6%95%99%E7%A8%8B/2.%E5%9F%BA%E7%A1%80%E6%A6%82%E5%BF%B5&amp;diff=55361&amp;oldid=prev"/>
		<updated>2026-04-23T08:21:34Z</updated>

		<summary type="html">&lt;p&gt;&lt;span dir=&quot;auto&quot;&gt;&lt;span class=&quot;autocomment&quot;&gt;@SideOnly&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;zh-Hans-CN&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;←上一版本&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;2026年4月23日 (四) 16:21的版本&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l54&quot;&gt;第54行：&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;第54行：&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;那么&amp;lt;code&amp;gt;@SideOnly(Side.SERVER)&amp;lt;/code&amp;gt;呢？和你想的是一样的，但是——在正常情况下，不要用这个修饰任何东西。前文说了，&amp;lt;code&amp;gt;@SideOnly(Side.CLIENT)&amp;lt;/code&amp;gt;用于修饰那些负责渲染、播放音效的类、方法，而又说了，“逻辑客户端（Render Thread）主要用于处理和视觉、听觉有关的效果，还负责处理玩家的键鼠输入等”。因为&amp;#039;&amp;#039;&amp;#039;物理服务端没有逻辑客户端线程&amp;#039;&amp;#039;&amp;#039;，所以&amp;lt;code&amp;gt;@SideOnly(Side.CLIENT)&amp;lt;/code&amp;gt;实际上也起到了“把代码的执行限定在逻辑客户端”的作用。可问题是，物理客户端也会有逻辑服务端，比如有个萌新Modder觉得“逻辑服务端掌管的是游戏逻辑的进行”，给某个负责游戏逻辑进行的方法打了&amp;lt;code&amp;gt;@SideOnly(Side.SERVER)&amp;lt;/code&amp;gt;，那糟了，装了你的模组就没法进行单人游戏了——因为两个物理端都有逻辑服务端。&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;那么&amp;lt;code&amp;gt;@SideOnly(Side.SERVER)&amp;lt;/code&amp;gt;呢？和你想的是一样的，但是——在正常情况下，不要用这个修饰任何东西。前文说了，&amp;lt;code&amp;gt;@SideOnly(Side.CLIENT)&amp;lt;/code&amp;gt;用于修饰那些负责渲染、播放音效的类、方法，而又说了，“逻辑客户端（Render Thread）主要用于处理和视觉、听觉有关的效果，还负责处理玩家的键鼠输入等”。因为&amp;#039;&amp;#039;&amp;#039;物理服务端没有逻辑客户端线程&amp;#039;&amp;#039;&amp;#039;，所以&amp;lt;code&amp;gt;@SideOnly(Side.CLIENT)&amp;lt;/code&amp;gt;实际上也起到了“把代码的执行限定在逻辑客户端”的作用。可问题是，物理客户端也会有逻辑服务端，比如有个萌新Modder觉得“逻辑服务端掌管的是游戏逻辑的进行”，给某个负责游戏逻辑进行的方法打了&amp;lt;code&amp;gt;@SideOnly(Side.SERVER)&amp;lt;/code&amp;gt;，那糟了，装了你的模组就没法进行单人游戏了——因为两个物理端都有逻辑服务端。&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&lt;/del&gt;&lt;/div&gt;&lt;/td&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-added&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;可能会有读者觉得，笔者讲的太抽象了。没事，等读者有了一定的开发经验，就懂了。反正记住：什么情况下，都别用&amp;lt;code&gt;@SideOnly(Side.SERVER)&amp;lt;/code&gt;。我们是在写模组，不是在写服务器插件。&lt;/del&gt;&lt;/div&gt;&lt;/td&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-added&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;那么这个注解，意义何在呢？答案是减少性能开销，比如，你在物理服务端调用渲染代码也没卵用，毕竟物理服务端是以命令行的形式体现的，你渲染给谁看呢？可能又有人问了：要减少性能开销，那么针对两个物理端分别写不同的代码不就好了？这也太麻烦了。所以，这就是@SideOnly的存在的意义——让同一个模组在不同的物理端上运行时，共享同一套代码。&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;那么这个注解，意义何在呢？答案是减少性能开销，比如，你在物理服务端调用渲染代码也没卵用，毕竟物理服务端是以命令行的形式体现的，你渲染给谁看呢？可能又有人问了：要减少性能开销，那么针对两个物理端分别写不同的代码不就好了？这也太麻烦了。所以，这就是@SideOnly的存在的意义——让同一个模组在不同的物理端上运行时，共享同一套代码。&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;

&lt;!-- diff cache key mcbbs_wiki:diff::1.12:old-55360:rev-55361 --&gt;
&lt;/table&gt;</summary>
		<author><name>MashKJo</name></author>
	</entry>
	<entry>
		<id>https://mcbbs.wiki/index.php?title=%E7%94%A8%E6%88%B7:MashKJo/1.12.2%E6%A8%A1%E7%BB%84%E5%BC%80%E5%8F%91%E6%95%99%E7%A8%8B/2.%E5%9F%BA%E7%A1%80%E6%A6%82%E5%BF%B5&amp;diff=55360&amp;oldid=prev</id>
		<title>MashKJo：​/* ResourceLocation */</title>
		<link rel="alternate" type="text/html" href="https://mcbbs.wiki/index.php?title=%E7%94%A8%E6%88%B7:MashKJo/1.12.2%E6%A8%A1%E7%BB%84%E5%BC%80%E5%8F%91%E6%95%99%E7%A8%8B/2.%E5%9F%BA%E7%A1%80%E6%A6%82%E5%BF%B5&amp;diff=55360&amp;oldid=prev"/>
		<updated>2026-04-23T08:20:45Z</updated>

		<summary type="html">&lt;p&gt;&lt;span dir=&quot;auto&quot;&gt;&lt;span class=&quot;autocomment&quot;&gt;ResourceLocation&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;zh-Hans-CN&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;←上一版本&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;2026年4月23日 (四) 16:20的版本&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l12&quot;&gt;第12行：&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;第12行：&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;  Minecraft.getMinecraft().getTextureManager().bindTexture(location);&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;  Minecraft.getMinecraft().getTextureManager().bindTexture(location);&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;Minecraft就会尝试去原版和各个模组的.jar包中找路径为&amp;lt;code&amp;gt;assets/minecraft/textures/items/apple.png&amp;lt;/code&amp;gt;的文件，代码中的&amp;lt;code&amp;gt;TextureManager#bindTexture&amp;lt;/code&amp;gt;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;的作用是把图片绑定到当前渲染器，那么，苹果的材质文件就会被绑定。当然，这段代码看不懂没关系。笔者只是想说明ResourceLocation对象的使用机制：一般情况下，它实际上能指代一个位于某个&lt;/del&gt;.jar包中路径为&amp;lt;code&amp;gt;&quot;assets/&quot; + resourceDomain + &quot;/&quot; + resourcePath&amp;lt;/code&amp;gt;的文件。&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;Minecraft就会尝试去原版和各个模组的.jar包中找路径为&amp;lt;code&amp;gt;assets/minecraft/textures/items/apple.png&amp;lt;/code&amp;gt;的文件，代码中的&amp;lt;code&amp;gt;TextureManager#bindTexture&amp;lt;/code&amp;gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;的作用是把图片绑定到当前渲染器，那么，苹果的材质文件就会被绑定。当然，这段代码看不懂没关系。作者只是想说明ResourceLocation对象的使用机制：一般情况下，它实际上能指代一个位于某个&lt;/ins&gt;.jar包中路径为&amp;lt;code&amp;gt;&quot;assets/&quot; + resourceDomain + &quot;/&quot; + resourcePath&amp;lt;/code&amp;gt;的文件。&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;但是也不是所有时候都是如此，比如在设定物品的模型文件的时候，resourcePath就不需要打那么多了，只需要&amp;lt;code&amp;gt;new ResourceLocation(modid, itemid)&amp;lt;/code&amp;gt;就可以了，比如&amp;lt;code&amp;gt;new ResourceLocation(&quot;minecraft&quot;, &quot;apple&quot;)&amp;lt;/code&amp;gt;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;。所以，笔者的建议是，如果是你自定义的渲染操作，你按照“路径为&lt;/del&gt;&amp;lt;code&amp;gt;&quot;assets/&quot; + resourceDomain + &quot;/&quot; + resourcePath&amp;lt;/code&amp;gt;”的规则，是没问题的；但是如果你要用Minecraft或Forge内置的某些方法，其中要传入一个ResourceLocation对象，那你就要小心了，还是点进去看看Minecraft或Forge的代码到底是怎么处理这个ResourceLocation的吧。&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;但是也不是所有时候都是如此，比如在设定物品的模型文件的时候，resourcePath就不需要打那么多了，只需要&amp;lt;code&amp;gt;new ResourceLocation(modid, itemid)&amp;lt;/code&amp;gt;就可以了，比如&amp;lt;code&amp;gt;new ResourceLocation(&quot;minecraft&quot;, &quot;apple&quot;)&amp;lt;/code&amp;gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;。所以，作者的建议是，如果是你自定义的渲染操作，你按照“路径为&lt;/ins&gt;&amp;lt;code&amp;gt;&quot;assets/&quot; + resourceDomain + &quot;/&quot; + resourcePath&amp;lt;/code&amp;gt;”的规则，是没问题的；但是如果你要用Minecraft或Forge内置的某些方法，其中要传入一个ResourceLocation对象，那你就要小心了，还是点进去看看Minecraft或Forge的代码到底是怎么处理这个ResourceLocation的吧。&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;那么，那个只有一个resourceName的构造方法是怎么回事呢？再举个例子，我可以这样：&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;那么，那个只有一个resourceName的构造方法是怎么回事呢？再举个例子，我可以这样：&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;

&lt;!-- diff cache key mcbbs_wiki:diff::1.12:old-54973:rev-55360 --&gt;
&lt;/table&gt;</summary>
		<author><name>MashKJo</name></author>
	</entry>
	<entry>
		<id>https://mcbbs.wiki/index.php?title=%E7%94%A8%E6%88%B7:MashKJo/1.12.2%E6%A8%A1%E7%BB%84%E5%BC%80%E5%8F%91%E6%95%99%E7%A8%8B/2.%E5%9F%BA%E7%A1%80%E6%A6%82%E5%BF%B5&amp;diff=54973&amp;oldid=prev</id>
		<title>MashKJo：​/* 享元设计模式 */ // Edit via Wikiplus</title>
		<link rel="alternate" type="text/html" href="https://mcbbs.wiki/index.php?title=%E7%94%A8%E6%88%B7:MashKJo/1.12.2%E6%A8%A1%E7%BB%84%E5%BC%80%E5%8F%91%E6%95%99%E7%A8%8B/2.%E5%9F%BA%E7%A1%80%E6%A6%82%E5%BF%B5&amp;diff=54973&amp;oldid=prev"/>
		<updated>2024-12-16T07:47:23Z</updated>

		<summary type="html">&lt;p&gt;&lt;span dir=&quot;auto&quot;&gt;&lt;span class=&quot;autocomment&quot;&gt;享元设计模式：​&lt;/span&gt; // Edit via Wikiplus&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;zh-Hans-CN&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;←上一版本&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;2024年12月16日 (一) 15:47的版本&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l89&quot;&gt;第89行：&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;第89行：&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;意义就是：节省内存开销啊。如果不重复利用实例，你确定你的电脑有那么大内存去分配给数量爆炸的对象吗？&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;意义就是：节省内存开销啊。如果不重复利用实例，你确定你的电脑有那么大内存去分配给数量爆炸的对象吗？&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;提一句，既然要重复利用实例，那么显然我们需要缓存这些注册项的对象。你可以在&amp;lt;code&amp;gt;net.minecraft.init&amp;lt;/code&amp;gt;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;包下找到一些类：Items、Blocks、PotionTypes等等，这些类中有许多的静态字段，都是对这些需要重复利用的对象的引用，需要的时候直接拿来用即可。不过也有例外——比如，没有Potions这个类，实际上Potion的注册是在Potion类本身中完成的，它注册的时候根本就没有保有对对象的引用，而是直接new的。&lt;/del&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;提一句，既然要重复利用实例，那么显然我们需要缓存这些注册项的对象。你可以在&amp;lt;code&amp;gt;net.minecraft.init&amp;lt;/code&amp;gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;包下找到一些类：Items、Blocks、PotionTypes等等，这些类中有许多的静态字段，都是对这些需要重复利用的对象的引用，需要的时候直接拿来用即可。不过也有例外——比如，没有Potions这个类，实际上我们如果想要获取原版中的Potion实例，应该用MobEffects这个类。&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;那又有人要问了：那么Minecraft在处理性质不同、但是代表的对象相同的事物的逻辑的时候，如何区分呢？对于这个问题，不同种类的注册项的处理都不同。对于Item来说，Minecraft会随建随用一个ItemStack对象；对于Block来说，有BlockPos这个类可以用。这些在后面会具体讲到。&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;那又有人要问了：那么Minecraft在处理性质不同、但是代表的对象相同的事物的逻辑的时候，如何区分呢？对于这个问题，不同种类的注册项的处理都不同。对于Item来说，Minecraft会随建随用一个ItemStack对象；对于Block来说，有BlockPos这个类可以用。这些在后面会具体讲到。&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;

&lt;!-- diff cache key mcbbs_wiki:diff::1.12:old-54939:rev-54973 --&gt;
&lt;/table&gt;</summary>
		<author><name>MashKJo</name></author>
	</entry>
	<entry>
		<id>https://mcbbs.wiki/index.php?title=%E7%94%A8%E6%88%B7:MashKJo/1.12.2%E6%A8%A1%E7%BB%84%E5%BC%80%E5%8F%91%E6%95%99%E7%A8%8B/2.%E5%9F%BA%E7%A1%80%E6%A6%82%E5%BF%B5&amp;diff=54939&amp;oldid=prev</id>
		<title>MashKJo：​/* 注册表 */ // Edit via Wikiplus</title>
		<link rel="alternate" type="text/html" href="https://mcbbs.wiki/index.php?title=%E7%94%A8%E6%88%B7:MashKJo/1.12.2%E6%A8%A1%E7%BB%84%E5%BC%80%E5%8F%91%E6%95%99%E7%A8%8B/2.%E5%9F%BA%E7%A1%80%E6%A6%82%E5%BF%B5&amp;diff=54939&amp;oldid=prev"/>
		<updated>2024-12-05T08:17:11Z</updated>

		<summary type="html">&lt;p&gt;&lt;span dir=&quot;auto&quot;&gt;&lt;span class=&quot;autocomment&quot;&gt;注册表：​&lt;/span&gt; // Edit via Wikiplus&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;zh-Hans-CN&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;←上一版本&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;2024年12月5日 (四) 16:17的版本&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l70&quot;&gt;第70行：&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;第70行：&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;所以我们需要用Forge提供的注册表，我们不需要显式指定数字ID。另外它接管了原版的注册表，且是基于Forge的事件系统的，事件系统会在后面讲到。&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;所以我们需要用Forge提供的注册表，我们不需要显式指定数字ID。另外它接管了原版的注册表，且是基于Forge的事件系统的，事件系统会在后面讲到。&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;所有注册项的类都实现了IForgeRegistry&lt;/del&gt;&amp;lt;V&amp;gt;这一接口，这个接口主要规定了关于注册名的一些规范，实际上这个接口有个静态内部类：Impl&amp;lt;T&amp;gt; implements &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;IForgeRegistry&lt;/del&gt;&amp;lt;T&amp;gt;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;，所以实际上所有注册项的类是继承了这个类，这个类提供了IForgeRegistry&lt;/del&gt;&amp;lt;V&amp;gt;的默认实现。也就是说，理论上你可以通过T extends &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;IForgeRegistry&lt;/del&gt;.Impl&amp;lt;T&amp;gt;来设定：可以用Forge的注册表系统给你的某个自定义的游戏元素进行注册，不过一般没必要这么做。&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;所有注册项的类都实现了IForgeRegistryEntry&lt;/ins&gt;&amp;lt;V&amp;gt;这一接口，这个接口主要规定了关于注册名的一些规范，实际上这个接口有个静态内部类：Impl&amp;lt;T&amp;gt; implements &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;IForgeRegistryEntry&lt;/ins&gt;&amp;lt;T&amp;gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;，所以实际上所有注册项的类是继承了这个类，这个类提供了IForgeRegistryEntry&lt;/ins&gt;&amp;lt;V&amp;gt;的默认实现。也就是说，理论上你可以通过T extends &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;IForgeRegistryEntry&lt;/ins&gt;.Impl&amp;lt;T&amp;gt;来设定：可以用Forge的注册表系统给你的某个自定义的游戏元素进行注册，不过一般没必要这么做。&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;使用原版的注册表时，没有“注册名”这一说——但是我们用的是Forge的注册表，所以必须在注册对象前，设定该对象的注册名：通过setRegistryName这个方法设定。这个方法可以接受一个ResourceLocation，但也可以接受这样两种形参列表：&amp;lt;code&amp;gt;(String name)&amp;lt;/code&amp;gt;和&amp;lt;code&amp;gt;(String modid, String name)&amp;lt;/code&amp;gt;，用法可以类比ResourceLocation的那两个构造方法，笔者这里就不细说了。如果你尝试注册未设定注册名的注册项对象（即注册名为null），则肯定会崩游戏，抛NullPointerException。&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;使用原版的注册表时，没有“注册名”这一说——但是我们用的是Forge的注册表，所以必须在注册对象前，设定该对象的注册名：通过setRegistryName这个方法设定。这个方法可以接受一个ResourceLocation，但也可以接受这样两种形参列表：&amp;lt;code&amp;gt;(String name)&amp;lt;/code&amp;gt;和&amp;lt;code&amp;gt;(String modid, String name)&amp;lt;/code&amp;gt;，用法可以类比ResourceLocation的那两个构造方法，笔者这里就不细说了。如果你尝试注册未设定注册名的注册项对象（即注册名为null），则肯定会崩游戏，抛NullPointerException。&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;=== @ObjectHolder ===&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;=== @ObjectHolder ===&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;利用&amp;lt;code&amp;gt;@GameRegistry.ObjectHolder&amp;lt;/code&amp;gt;这个注解，我们可以自动给某个类型为&amp;lt;T extends &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;IForgeRegistry&lt;/del&gt;&amp;lt;T&amp;gt;&amp;gt;的变量赋值。&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;利用&amp;lt;code&amp;gt;@GameRegistry.ObjectHolder&amp;lt;/code&amp;gt;这个注解，我们可以自动给某个类型为&amp;lt;T extends &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;IForgeRegistryEntry&lt;/ins&gt;&amp;lt;T&amp;gt;&amp;gt;的变量赋值。&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;那么具体怎么用呢？看个例子就知道了：&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;那么具体怎么用呢？看个例子就知道了：&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;

&lt;!-- diff cache key mcbbs_wiki:diff::1.12:old-54922:rev-54939 --&gt;
&lt;/table&gt;</summary>
		<author><name>MashKJo</name></author>
	</entry>
	<entry>
		<id>https://mcbbs.wiki/index.php?title=%E7%94%A8%E6%88%B7:MashKJo/1.12.2%E6%A8%A1%E7%BB%84%E5%BC%80%E5%8F%91%E6%95%99%E7%A8%8B/2.%E5%9F%BA%E7%A1%80%E6%A6%82%E5%BF%B5&amp;diff=54922&amp;oldid=prev</id>
		<title>MashKJo：​创建页面，内容为“这一节，会讲述一些非常重要的前置概念。  == ResourceLocation == 这是一个位于&lt;code&gt;net.minecraft.util&lt;/code&gt;包下的一个类。这个类的用途的其中之一，顾名思义，就是用来表示文件在assets文件夹中的路径。在开发环境中，assets文件夹在&lt;code&gt;src/main/resources&lt;/code&gt;路径下；而在打包好的.jar文件的中，assets文件夹点进去就能看到。  ResourceLocation总共有3个构造器，我…”</title>
		<link rel="alternate" type="text/html" href="https://mcbbs.wiki/index.php?title=%E7%94%A8%E6%88%B7:MashKJo/1.12.2%E6%A8%A1%E7%BB%84%E5%BC%80%E5%8F%91%E6%95%99%E7%A8%8B/2.%E5%9F%BA%E7%A1%80%E6%A6%82%E5%BF%B5&amp;diff=54922&amp;oldid=prev"/>
		<updated>2024-12-03T07:33:40Z</updated>

		<summary type="html">&lt;p&gt;创建页面，内容为“这一节，会讲述一些非常重要的前置概念。  == ResourceLocation == 这是一个位于&amp;lt;code&amp;gt;net.minecraft.util&amp;lt;/code&amp;gt;包下的一个类。这个类的用途的其中之一，顾名思义，就是用来表示文件在assets文件夹中的路径。在开发环境中，assets文件夹在&amp;lt;code&amp;gt;src/main/resources&amp;lt;/code&amp;gt;路径下；而在打包好的.jar文件的中，assets文件夹点进去就能看到。  ResourceLocation总共有3个构造器，我…”&lt;/p&gt;
&lt;p&gt;&lt;b&gt;新页面&lt;/b&gt;&lt;/p&gt;&lt;div&gt;这一节，会讲述一些非常重要的前置概念。&lt;br /&gt;
&lt;br /&gt;
== ResourceLocation ==&lt;br /&gt;
这是一个位于&amp;lt;code&amp;gt;net.minecraft.util&amp;lt;/code&amp;gt;包下的一个类。这个类的用途的其中之一，顾名思义，就是用来表示文件在assets文件夹中的路径。在开发环境中，assets文件夹在&amp;lt;code&amp;gt;src/main/resources&amp;lt;/code&amp;gt;路径下；而在打包好的.jar文件的中，assets文件夹点进去就能看到。&lt;br /&gt;
&lt;br /&gt;
ResourceLocation总共有3个构造器，我们用到的有2个：&amp;lt;code&amp;gt;public ResourceLocation(String resourceName)&amp;lt;/code&amp;gt;和&amp;lt;code&amp;gt;public ResourceLocation(String resourceDomain, String resourcePath)&amp;lt;/code&amp;gt;。通常推荐使用后者。&lt;br /&gt;
&lt;br /&gt;
resourceDomain是什么意思？举个例子，&amp;lt;code&amp;gt;&amp;quot;minecraft&amp;quot;&amp;lt;/code&amp;gt;就是一个resourceDomain，&amp;lt;code&amp;gt;&amp;quot;buildcraft&amp;quot;&amp;lt;/code&amp;gt;同样也是。所以明白了吗？resourceDomain实质上就是某个模组的modid。我们当然一般是要用自己的Mod的modid。&lt;br /&gt;
&lt;br /&gt;
resourcePath又是什么意思呢？再举个例子，假如我这样new了一个ResourceLocation：&lt;br /&gt;
 ResourceLocation location = new ResourceLocation(&amp;quot;minecraft&amp;quot;, &amp;quot;textures/items/apple.png&amp;quot;);&lt;br /&gt;
 Minecraft.getMinecraft().getTextureManager().bindTexture(location);&lt;br /&gt;
&lt;br /&gt;
Minecraft就会尝试去原版和各个模组的.jar包中找路径为&amp;lt;code&amp;gt;assets/minecraft/textures/items/apple.png&amp;lt;/code&amp;gt;的文件，代码中的&amp;lt;code&amp;gt;TextureManager#bindTexture&amp;lt;/code&amp;gt;的作用是把图片绑定到当前渲染器，那么，苹果的材质文件就会被绑定。当然，这段代码看不懂没关系。笔者只是想说明ResourceLocation对象的使用机制：一般情况下，它实际上能指代一个位于某个.jar包中路径为&amp;lt;code&amp;gt;&amp;quot;assets/&amp;quot; + resourceDomain + &amp;quot;/&amp;quot; + resourcePath&amp;lt;/code&amp;gt;的文件。&lt;br /&gt;
&lt;br /&gt;
但是也不是所有时候都是如此，比如在设定物品的模型文件的时候，resourcePath就不需要打那么多了，只需要&amp;lt;code&amp;gt;new ResourceLocation(modid, itemid)&amp;lt;/code&amp;gt;就可以了，比如&amp;lt;code&amp;gt;new ResourceLocation(&amp;quot;minecraft&amp;quot;, &amp;quot;apple&amp;quot;)&amp;lt;/code&amp;gt;。所以，笔者的建议是，如果是你自定义的渲染操作，你按照“路径为&amp;lt;code&amp;gt;&amp;quot;assets/&amp;quot; + resourceDomain + &amp;quot;/&amp;quot; + resourcePath&amp;lt;/code&amp;gt;”的规则，是没问题的；但是如果你要用Minecraft或Forge内置的某些方法，其中要传入一个ResourceLocation对象，那你就要小心了，还是点进去看看Minecraft或Forge的代码到底是怎么处理这个ResourceLocation的吧。&lt;br /&gt;
&lt;br /&gt;
那么，那个只有一个resourceName的构造方法是怎么回事呢？再举个例子，我可以这样：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;ResourceLocation location = new ResourceLocation(&amp;quot;minecraft:apple&amp;quot;);&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
所以实质上，Minecraft会根据传入的resourceName中的英文冒号，自动分离出resourceDomain和resourcePath的。&lt;br /&gt;
&lt;br /&gt;
另外，ResourceLocation对象还经常被用来当作某个游戏元素的唯一标识符。这个时候，它实际上就没有指代一个具体文件的作用了。&lt;br /&gt;
&lt;br /&gt;
== 客户端与服务端 ==&lt;br /&gt;
看到这个二级标题，想必有的读者觉得自己没必要看这部分内容了——这也要特意强调？&lt;br /&gt;
&lt;br /&gt;
然而这部分确实很重要。&lt;br /&gt;
&lt;br /&gt;
如果我随便问一个MC玩家：Minecraft的客户端是什么，服务端又是什么？&lt;br /&gt;
&lt;br /&gt;
他/她的回答可能是这样：拿启动器启动的是客户端，拿开服工具的start.bat启动的是服务端。&lt;br /&gt;
&lt;br /&gt;
唔，这样的回答不能算错，但不够全面——至少比认为单人模式 = 客户端， 多人模式 = 服务端的理解要好到不知道哪里去了。&lt;br /&gt;
&lt;br /&gt;
=== 物理端和逻辑端 ===&lt;br /&gt;
实际上，上面那个回答，只是粗略地说出了物理客户端和物理服务端之间的区别。&lt;br /&gt;
&lt;br /&gt;
而实际上，除了物理端，还有个概念，名为“逻辑端”。&lt;br /&gt;
&lt;br /&gt;
逻辑端，实际上是线程层面的概念。逻辑客户端和逻辑服务端各分属两个线程组，其中逻辑客户端（Render Thread）主要用于处理和视觉、听觉有关的效果，还负责处理玩家的键鼠输入等；而逻辑服务端（Server Thread）则主要用于处理游戏逻辑的进行和游戏数据的更新。&lt;br /&gt;
&lt;br /&gt;
在你游玩服务器的时候，实际上是在用你启动的物理客户端的逻辑客户端线程，连接物理服务器的逻辑服务端线程。而你处于单人模式时呢？请回忆一下，你玩模组的时候，肯定有崩游戏的时候，崩游戏的那一刹那前，是不是会有一行字：“正在关闭内置服务端”？没错，处于单机存档时，逻辑服务端也存在。也就是说，你的单人游戏，实际上相当于一个IP地址为localhost的本地服务器。&lt;br /&gt;
&lt;br /&gt;
那么，逻辑客户端和逻辑服务端需不需要进行交互呢？当然是需要的。它们之间需要进行网络通信，以同步数据——否则，如果是单人模式还好，在你玩服务器的时候，你的电脑和运行服务器的设备可能距离十万八千里这么远，请问你的电脑凭什么什么都不做就能获取十万八千里外，另一台设备的服务端中的数据？所幸，Minecraft已经包办了绝大多数需要双端通信的地方。不过还有一些地方，需要我们自己完成通信。&lt;br /&gt;
&lt;br /&gt;
=== @SideOnly ===&lt;br /&gt;
这个注解，可以用于修饰类、字段、方法、构造器。它的唯一一个参数类型是枚举类：Side。Side类有三个实例：CLIENT、SERVER和BUKKIT。这里我们主要把目光放在前两个身上。&lt;br /&gt;
&lt;br /&gt;
举个例子，如果你给某个方法加上了&amp;lt;code&amp;gt;@SideOnly(Side.CLIENT)&amp;lt;/code&amp;gt;，那么这个方法只能在物理客户端被调用，如果尝试在物理服务端调用，会直接抛NoSuchMethodException。通常，这用来修饰那些负责渲染、播放音效的类、方法。&lt;br /&gt;
&lt;br /&gt;
所以，这个注解是针对物理端的。&lt;br /&gt;
&lt;br /&gt;
那么&amp;lt;code&amp;gt;@SideOnly(Side.SERVER)&amp;lt;/code&amp;gt;呢？和你想的是一样的，但是——在正常情况下，不要用这个修饰任何东西。前文说了，&amp;lt;code&amp;gt;@SideOnly(Side.CLIENT)&amp;lt;/code&amp;gt;用于修饰那些负责渲染、播放音效的类、方法，而又说了，“逻辑客户端（Render Thread）主要用于处理和视觉、听觉有关的效果，还负责处理玩家的键鼠输入等”。因为&amp;#039;&amp;#039;&amp;#039;物理服务端没有逻辑客户端线程&amp;#039;&amp;#039;&amp;#039;，所以&amp;lt;code&amp;gt;@SideOnly(Side.CLIENT)&amp;lt;/code&amp;gt;实际上也起到了“把代码的执行限定在逻辑客户端”的作用。可问题是，物理客户端也会有逻辑服务端，比如有个萌新Modder觉得“逻辑服务端掌管的是游戏逻辑的进行”，给某个负责游戏逻辑进行的方法打了&amp;lt;code&amp;gt;@SideOnly(Side.SERVER)&amp;lt;/code&amp;gt;，那糟了，装了你的模组就没法进行单人游戏了——因为两个物理端都有逻辑服务端。&lt;br /&gt;
&lt;br /&gt;
可能会有读者觉得，笔者讲的太抽象了。没事，等读者有了一定的开发经验，就懂了。反正记住：什么情况下，都别用&amp;lt;code&amp;gt;@SideOnly(Side.SERVER)&amp;lt;/code&amp;gt;。我们是在写模组，不是在写服务器插件。&lt;br /&gt;
&lt;br /&gt;
那么这个注解，意义何在呢？答案是减少性能开销，比如，你在物理服务端调用渲染代码也没卵用，毕竟物理服务端是以命令行的形式体现的，你渲染给谁看呢？可能又有人问了：要减少性能开销，那么针对两个物理端分别写不同的代码不就好了？这也太麻烦了。所以，这就是@SideOnly的存在的意义——让同一个模组在不同的物理端上运行时，共享同一套代码。&lt;br /&gt;
&lt;br /&gt;
== 注册表 ==&lt;br /&gt;
注册表是什么？那要先从“注册项”这个概念说起。&lt;br /&gt;
&lt;br /&gt;
Minecraft原版中有着各种游戏元素，如物品、方块、状态效果、实体等等，这些游戏要素的很多行为（包括方块的“长按左键挖掘”这种通用行为，以及实体的“靠近玩家会尝试爆炸”这种仅在苦力怕这种生物上会体现的特殊行为），显然，是必须要在游戏初始化时完成设置的——不然游戏初始化有什么意义？干脆就在遇到某个游戏要素的时候读取相关逻辑不就好了？——显然，这种设计是很不好的。&lt;br /&gt;
&lt;br /&gt;
所以在这种情况下，显然就需要一种东西来统筹这些游戏元素的逻辑的初始化，被统筹的游戏元素都是&amp;#039;&amp;#039;&amp;#039;注册项&amp;#039;&amp;#039;&amp;#039;，而统筹者则是&amp;#039;&amp;#039;&amp;#039;注册表&amp;#039;&amp;#039;&amp;#039;。一般而言，注册项会在FMLPreInitialization阶段被注册。想想看：如果没有注册表，就拿物品（Item）这一注册项举例，MC如何能获取到你想要添加到游戏中的所有物品呢？难不成还要用黑科技读取你的项目中的所有继承了Item类的类，再用&amp;lt;code&amp;gt;Class#newInstance&amp;lt;/code&amp;gt;手动构造实例？或者自动检索所有Item的实例？这根本不可行。所以注册表应运而生。&lt;br /&gt;
&lt;br /&gt;
Minecraft原版就有一套注册表系统，不过它的实现太过于丑陋，也根本就存在很多问题——如，你会发现使用它注册注册项时，你还需要显式指定每个实例的数字ID。那么请问你如何保证你的模组的注册项的数字ID不会和其他模组的发生冲突呢？实际上Minecraft在1.13也弃用了这种注册模式。&lt;br /&gt;
&lt;br /&gt;
所以我们需要用Forge提供的注册表，我们不需要显式指定数字ID。另外它接管了原版的注册表，且是基于Forge的事件系统的，事件系统会在后面讲到。&lt;br /&gt;
&lt;br /&gt;
所有注册项的类都实现了IForgeRegistry&amp;lt;V&amp;gt;这一接口，这个接口主要规定了关于注册名的一些规范，实际上这个接口有个静态内部类：Impl&amp;lt;T&amp;gt; implements IForgeRegistry&amp;lt;T&amp;gt;，所以实际上所有注册项的类是继承了这个类，这个类提供了IForgeRegistry&amp;lt;V&amp;gt;的默认实现。也就是说，理论上你可以通过T extends IForgeRegistry.Impl&amp;lt;T&amp;gt;来设定：可以用Forge的注册表系统给你的某个自定义的游戏元素进行注册，不过一般没必要这么做。&lt;br /&gt;
&lt;br /&gt;
使用原版的注册表时，没有“注册名”这一说——但是我们用的是Forge的注册表，所以必须在注册对象前，设定该对象的注册名：通过setRegistryName这个方法设定。这个方法可以接受一个ResourceLocation，但也可以接受这样两种形参列表：&amp;lt;code&amp;gt;(String name)&amp;lt;/code&amp;gt;和&amp;lt;code&amp;gt;(String modid, String name)&amp;lt;/code&amp;gt;，用法可以类比ResourceLocation的那两个构造方法，笔者这里就不细说了。如果你尝试注册未设定注册名的注册项对象（即注册名为null），则肯定会崩游戏，抛NullPointerException。&lt;br /&gt;
=== @ObjectHolder ===&lt;br /&gt;
利用&amp;lt;code&amp;gt;@GameRegistry.ObjectHolder&amp;lt;/code&amp;gt;这个注解，我们可以自动给某个类型为&amp;lt;T extends IForgeRegistry&amp;lt;T&amp;gt;&amp;gt;的变量赋值。&lt;br /&gt;
&lt;br /&gt;
那么具体怎么用呢？看个例子就知道了：&lt;br /&gt;
 @ObjectHolder(&amp;quot;minecraft:grass&amp;quot;)&lt;br /&gt;
 public static final Block GRASS;&lt;br /&gt;
&lt;br /&gt;
这样的话，这个静态字段就会自动被赋值Blocks.GRASS所对应的对象，相当于操作了&amp;lt;code&amp;gt;GRASS = Blocks.GRASS&amp;lt;/code&amp;gt;。&lt;br /&gt;
&lt;br /&gt;
另外，你还可以在这个字段所在的类上打这个注解，作用是指定默认的作用域（Domain），如，打上&amp;lt;code&amp;gt;@ObjectHolder(&amp;quot;minecraft&amp;quot;)&amp;lt;/code&amp;gt;，那么下面的只需写成&amp;lt;code&amp;gt;@ObjectHolder(&amp;quot;grass&amp;quot;)&amp;lt;/code&amp;gt;即可。&lt;br /&gt;
&lt;br /&gt;
=== 享元设计模式 ===&lt;br /&gt;
注册项基本上都有一个特点：遵循了“享元”的设计模式。简而言之，这个设计模式的核心思想是：重复利用实例。拿Item这一注册项举例：所有玩家背包里的苹果，无论其数量有多少，在物品栏的哪一格，其对应的Item对象都是同一个：&amp;lt;code&amp;gt;Items.APPLE&amp;lt;/code&amp;gt;；再拿Block举例：每个Minecraft存档中都有数不清的方块，所有草方块，不管它们的坐标是什么，对应的Block对象都是同一个：&amp;lt;code&amp;gt;Blocks.GRASS&amp;lt;/code&amp;gt;。那么，这样做有什么意义呢？&lt;br /&gt;
&lt;br /&gt;
意义就是：节省内存开销啊。如果不重复利用实例，你确定你的电脑有那么大内存去分配给数量爆炸的对象吗？&lt;br /&gt;
&lt;br /&gt;
提一句，既然要重复利用实例，那么显然我们需要缓存这些注册项的对象。你可以在&amp;lt;code&amp;gt;net.minecraft.init&amp;lt;/code&amp;gt;包下找到一些类：Items、Blocks、PotionTypes等等，这些类中有许多的静态字段，都是对这些需要重复利用的对象的引用，需要的时候直接拿来用即可。不过也有例外——比如，没有Potions这个类，实际上Potion的注册是在Potion类本身中完成的，它注册的时候根本就没有保有对对象的引用，而是直接new的。&lt;br /&gt;
&lt;br /&gt;
那又有人要问了：那么Minecraft在处理性质不同、但是代表的对象相同的事物的逻辑的时候，如何区分呢？对于这个问题，不同种类的注册项的处理都不同。对于Item来说，Minecraft会随建随用一个ItemStack对象；对于Block来说，有BlockPos这个类可以用。这些在后面会具体讲到。&lt;br /&gt;
&lt;br /&gt;
根据Forge的官方文档，Minecraft和Forge内建的注册项的种类有如下这些：&lt;br /&gt;
* 物品（Item）&lt;br /&gt;
* 方块（Block）&lt;br /&gt;
* 状态效果（Potion）&lt;br /&gt;
* 药水类型（PotionType）&lt;br /&gt;
* 声音（SoundEvent）&lt;br /&gt;
* 附魔（Enchantment）&lt;br /&gt;
* 合成配方（IRecipe）&lt;br /&gt;
* 村民职业（VillagerProfession）&lt;br /&gt;
* 实体类型（EntityEntry）&amp;lt;ref&amp;gt;注意：实体（Entity）并不遵循享元模式，实际上世界中一个实体就代表了一个独特的Entity对象。只是Forge提供了一个工具类：EntityEntry，用来代表实体的种类，因此我们可以通过注册表注册实体。&amp;lt;/ref&amp;gt;&lt;br /&gt;
* 生物群系（Biome）&lt;br /&gt;
&lt;br /&gt;
最后，注意：能使用注册表注册的游戏元素一定遵循享元设计模式，但是遵循享元设计模式的游戏元素，不一定是通过注册表注册。&lt;br /&gt;
&lt;br /&gt;
== 注释与外部链接 ==&lt;/div&gt;</summary>
		<author><name>MashKJo</name></author>
	</entry>
</feed>