Compare commits

...
23 Commits
Author SHA1 Message Date
LexManos 4f2f5c02a0 1.19.2 RB 2022-08-17 14:58:14 -07:00
agnor99 7a6843fa4a Added ItemDecorator API (#8794) 2022-08-17 23:39:56 +02:00
한현빈 f0ecf16c6b [1.19.x] Custom usage animations for items (#8932) 2022-08-17 23:08:13 +02:00
Take Weiland 8998fa71b2 Allow registering custom ColorResolvers (#8880) 2022-08-17 22:51:05 +02:00
Dennis C 4e677a7558 [1.19] Allow custom outline rendering on EntityRenderers and BlockEntityRenderers (#8938) 2022-08-17 00:01:33 +02:00
sciwhiz12 07254b36d7 Redirect checks for entity selector use to a permission (#8947)
This allows greater flexibility for configuring servers with
operator-like permissions to user groups through the permissions API and
their permissions handler of choice without needing to grant the
vanilla operator permission to any player.

The new permission is "forge:use_entity_selectors", which is granted by
default to players with permission level 2 (GAMEMASTERS) and above.

The hook falls back to checking the permission level if the source of
the command is not a ServerPlayer, such as for command blocks and
functions.
2022-08-16 14:11:54 -07:00
Brennan Ward a51b8d256d Allow FakePlayer to report its position (#8963) 2022-08-16 14:09:09 -07:00
Sara Freimer 75fcd9448e Add alternate version of renderEntityInInventory to allow for directly specifying the angles (#8961) 2022-08-16 13:57:30 -07:00
eerussianguy 6b45999702 Add cancellable ToastAddEvent (#8952) 2022-08-16 13:48:55 -07:00
eerussianguy a4f52f4057 Modify ScreenEvent.RenderInventoryMobEffects to allow moving the effect stack left or right (#8951) 2022-08-16 13:47:57 -07:00
Brennan Ward b8b3201372 Fix Enchantment#doPostHurt and Enchantment#doPostAttack being called twice for players. Fixes MC-248272 (#8948) 2022-08-16 13:40:10 -07:00
LexManos 41deadc1e2 Remove reflective implementation of ICustomPacket. (#8973)
Make vanilla custom packets able to be sent multiple times. Closes #8969
2022-08-16 13:17:25 -07:00
LexManos 82e8d06e54 Filter name spaces to directories only. Closes #8413 2022-08-14 12:22:38 -07:00
Marc Hermans 51db5f2ff7 Fix a corner case where the UMLB can not extract a version from a library. (#8967) 2022-08-14 12:18:22 -07:00
Alex O'Neill 2ec9e515ff Fix worlds with removed dimension types unable to load. (#8959) Closes #8800 2022-08-14 12:17:22 -07:00
Alex O'Neill 0579572148 Fix issue where unknown chunk generators would cause DFU to fail. (#8957) 2022-08-10 23:13:44 -07:00
TheMuso 83f4e6353c Fix comments and documentation that were missed during the review of #8712 (#8945) 2022-08-09 12:49:00 -07:00
Luis 130953e519 Make AnvilUpdateEvent fire even if the second input is empty, which means it fires even if only changing the item name. (#8905) 2022-08-09 12:48:46 -07:00
Sirttas 7981093591 Fix LivingEntity#isBlocking to use ToolActions#SHIELD_BLOCK instead of UseAnim#BLOCK (#8933) 2022-08-09 12:27:26 -07:00
Joseph B 79112d6208 Add Custom HolderSet Types allowing for logical combining of sets. (#8928) 2022-08-09 12:25:12 -07:00
Sara Freimer a3eb6263f4 Add values to VersionSupportMatrix to support loading mods that restrict versions to 1.19.1 on 1.19.2 (#8946) 2022-08-09 12:15:58 -07:00
Redstone_Dubstep d91bc9c73d Fix certain particles not updating their bounding box when their position changes (#8925) 2022-08-08 15:09:13 +02:00
LexManos c807665ab9 Update EventBus to address concurrency issue in ModLauncher Factory. Closes #8924 2022-08-07 17:35:15 -07:00
82 changed files with 1927 additions and 124 deletions

No files matched your search

+1 -1
View File
@@ -43,7 +43,7 @@ ext {
SPI_VERSION = '6.0.0'
ACCESSTRANSFORMERS_VERSION = '8.0.4'
COREMODS_VERSION = '5.0.1'
EVENTBUS_VERSION = '6.0.0'
EVENTBUS_VERSION = '6.0.3'
MODLAUNCHER_VERSION = '10.0.8'
SECUREJARHANDLER_VERSION = '2.1.4'
BOOTSTRAPLAUNCHER_VERSION = '1.1.2'
+1 -1
View File
@@ -2,7 +2,7 @@
MinecraftForge
=============
[![Stable Release](https://img.shields.io/badge/dynamic/json?url=https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json&label=Stable&prefix=1.19-&query=$.promos["1.19-recommended"]&color=brightgreen&logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBjbGFzcz0ic3ZnLWlubGluZS0tZmEgZmEtc3RhciBmYS13LTE4IiBhcmlhLWhpZGRlbj0idHJ1ZSIgZGF0YS1pY29uPSJzdGFyIiBkYXRhLXByZWZpeD0iZmFzIiBmb2N1c2FibGU9ImZhbHNlIiByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCA1NzYgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBkPSJNMjU5LjMgMTcuOEwxOTQgMTUwLjIgNDcuOSAxNzEuNWMtMjYuMiAzLjgtMzYuNyAzNi4xLTE3LjcgNTQuNmwxMDUuNyAxMDMtMjUgMTQ1LjVjLTQuNSAyNi4zIDIzLjIgNDYgNDYuNCAzMy43TDI4OCA0MzkuNmwxMzAuNyA2OC43YzIzLjIgMTIuMiA1MC45LTcuNCA0Ni40LTMzLjdsLTI1LTE0NS41IDEwNS43LTEwM2MxOS0xOC41IDguNS01MC44LTE3LjctNTQuNkwzODIgMTUwLjIgMzE2LjcgMTcuOGMtMTEuNy0yMy42LTQ1LjYtMjMuOS01Ny40IDB6IiBmaWxsPSJ3aGl0ZSIvPgo8L3N2Zz4K)](https://files.minecraftforge.net)
[![Stable Release](https://img.shields.io/badge/dynamic/json?url=https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json&label=Stable&prefix=1.19-&query=$.promos["1.19.2-recommended"]&color=brightgreen&logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBjbGFzcz0ic3ZnLWlubGluZS0tZmEgZmEtc3RhciBmYS13LTE4IiBhcmlhLWhpZGRlbj0idHJ1ZSIgZGF0YS1pY29uPSJzdGFyIiBkYXRhLXByZWZpeD0iZmFzIiBmb2N1c2FibGU9ImZhbHNlIiByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCA1NzYgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBkPSJNMjU5LjMgMTcuOEwxOTQgMTUwLjIgNDcuOSAxNzEuNWMtMjYuMiAzLjgtMzYuNyAzNi4xLTE3LjcgNTQuNmwxMDUuNyAxMDMtMjUgMTQ1LjVjLTQuNSAyNi4zIDIzLjIgNDYgNDYuNCAzMy43TDI4OCA0MzkuNmwxMzAuNyA2OC43YzIzLjIgMTIuMiA1MC45LTcuNCA0Ni40LTMzLjdsLTI1LTE0NS41IDEwNS43LTEwM2MxOS0xOC41IDguNS01MC44LTE3LjctNTQuNkwzODIgMTUwLjIgMzE2LjcgMTcuOGMtMTEuNy0yMy42LTQ1LjYtMjMuOS01Ny40IDB6IiBmaWxsPSJ3aGl0ZSIvPgo8L3N2Zz4K)](https://files.minecraftforge.net)
[![Latest Release](https://img.shields.io/badge/dynamic/json?url=https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json&label=Latest&prefix=1.19.2-&query=$.promos["1.19.2-latest"]&color=blue&logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBjbGFzcz0ic3ZnLWlubGluZS0tZmEgZmEtYnVnIGZhLXctMTYiIGFyaWEtaGlkZGVuPSJ0cnVlIiBkYXRhLWljb249ImJ1ZyIgZGF0YS1wcmVmaXg9ImZhcyIgZm9jdXNhYmxlPSJmYWxzZSIgcm9sZT0iaW1nIiB2aWV3Qm94PSIwIDAgNTEyIDUxMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTUxMS45ODggMjg4LjljLS40NzggMTcuNDMtMTUuMjE3IDMxLjEtMzIuNjUzIDMxLjFINDI0djE2YzAgMjEuODY0LTQuODgyIDQyLjU4NC0xMy42IDYxLjE0NWw2MC4yMjggNjAuMjI4YzEyLjQ5NiAxMi40OTcgMTIuNDk2IDMyLjc1OCAwIDQ1LjI1NS0xMi40OTggMTIuNDk3LTMyLjc1OSAxMi40OTYtNDUuMjU2IDBsLTU0LjczNi01NC43MzZDMzQ1Ljg4NiA0NjcuOTY1IDMxNC4zNTEgNDgwIDI4MCA0ODBWMjM2YzAtNi42MjctNS4zNzMtMTItMTItMTJoLTI0Yy02LjYyNyAwLTEyIDUuMzczLTEyIDEydjI0NGMtMzQuMzUxIDAtNjUuODg2LTEyLjAzNS05MC42MzYtMzIuMTA4bC01NC43MzYgNTQuNzM2Yy0xMi40OTggMTIuNDk3LTMyLjc1OSAxMi40OTYtNDUuMjU2IDAtMTIuNDk2LTEyLjQ5Ny0xMi40OTYtMzIuNzU4IDAtNDUuMjU1bDYwLjIyOC02MC4yMjhDOTIuODgyIDM3OC41ODQgODggMzU3Ljg2NCA4OCAzMzZ2LTE2SDMyLjY2NkMxNS4yMyAzMjAgLjQ5MSAzMDYuMzMuMDEzIDI4OC45LS40ODQgMjcwLjgxNiAxNC4wMjggMjU2IDMyIDI1Nmg1NnYtNTguNzQ1bC00Ni42MjgtNDYuNjI4Yy0xMi40OTYtMTIuNDk3LTEyLjQ5Ni0zMi43NTggMC00NS4yNTUgMTIuNDk4LTEyLjQ5NyAzMi43NTgtMTIuNDk3IDQ1LjI1NiAwTDE0MS4yNTUgMTYwaDIyOS40ODlsNTQuNjI3LTU0LjYyN2MxMi40OTgtMTIuNDk3IDMyLjc1OC0xMi40OTcgNDUuMjU2IDAgMTIuNDk2IDEyLjQ5NyAxMi40OTYgMzIuNzU4IDAgNDUuMjU1TDQyNCAxOTcuMjU1VjI1Nmg1NmMxNy45NzIgMCAzMi40ODQgMTQuODE2IDMxLjk4OCAzMi45ek0yNTcgMGMtNjEuODU2IDAtMTEyIDUwLjE0NC0xMTIgMTEyaDIyNEMzNjkgNTAuMTQ0IDMxOC44NTYgMCAyNTcgMHoiIGZpbGw9IndoaXRlIi8+Cjwvc3ZnPgo=
)](https://files.minecraftforge.net) [![Discord](https://img.shields.io/discord/313125603924639766.svg?color=%237289da&label=Discord&logo=discord&logoColor=%237289da)](https://discord.gg/UvedJ9m) [![Support](https://img.shields.io/badge/Patreon-Support-orange.svg?logo=Patreon)](https://www.patreon.com/LexManos)
@@ -106,16 +106,17 @@ public class UniqueModListBuilder
if (modInfoList.size() > 1) {
LOGGER.debug("Found {} mods for first modid {}, selecting most recent based on version data", modInfoList.size(), fullList.getKey());
modInfoList.sort(Comparator.comparing(this::getVersion).reversed());
LOGGER.debug("Selected file {} for modid {} with version {}", modInfoList.get(0).getFileName(), fullList.getKey(), modInfoList.get(0).getModInfos().get(0).getVersion());
LOGGER.debug("Selected file {} for modid {} with version {}", modInfoList.get(0).getFileName(), fullList.getKey(), this.getVersion(modInfoList.get(0)));
}
return modInfoList.get(0);
}
private ArtifactVersion getVersion(final ModFile mf)
{
if (mf.getModFileInfo() == null) {
if (mf.getModFileInfo() == null || mf.getModInfos() == null || mf.getModInfos().isEmpty()) {
return mf.getJarVersion();
}
return mf.getModInfos().get(0).getVersion();
}
@@ -5,6 +5,7 @@
package net.minecraftforge.fml.loading;
import net.minecraftforge.forgespi.language.MavenVersionAdapter;
import org.apache.maven.artifact.versioning.ArtifactVersion;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.apache.maven.artifact.versioning.VersionRange;
@@ -18,16 +19,12 @@ public class VersionSupportMatrix {
private static final HashMap<String, List<ArtifactVersion>> overrideVersions = new HashMap<>();
static {
final ArtifactVersion version = new DefaultArtifactVersion(FMLLoader.versionInfo().mcVersion());
// if (MavenVersionAdapter.createFromVersionSpec("[1.16.4,1.16.5]").containsVersion(version)) {
// // 1.16.4 is Compatible with 1.16.3
// add("languageloader.javafml", "34");
// add("mod.minecraft", "1.16.3");
// add("mod.forge", "34.1.42");
// // 1.16.5 is Compatible with 1.16.4, and thus 1.16.3
// add("languageloader.javafml", "35");
// add("mod.minecraft", "1.16.4");
// add("mod.forge", "35.1.37");
// }
if (MavenVersionAdapter.createFromVersionSpec("[1.19.2]").containsVersion(version)) {
// 1.19.2 is Compatible with 1.19.1
add("languageloader.javafml", "42");
add("mod.minecraft", "1.19.1");
add("mod.forge", "42.0.9");
}
}
private static void add(String key, String value) {
overrideVersions.computeIfAbsent(key, k -> new ArrayList<>()).add(new DefaultArtifactVersion(value));
@@ -38,7 +38,7 @@ public class FMLModContainer extends ModContainer
LOGGER.debug(LOADING,"Creating FMLModContainer instance for {}", className);
this.scanResults = modFileScanResults;
activityMap.put(ModLoadingStage.CONSTRUCT, this::constructMod);
this.eventBus = BusBuilder.builder().setExceptionHandler(this::onEventFailed).setTrackPhases(false).markerType(IModBusEvent.class).build();
this.eventBus = BusBuilder.builder().setExceptionHandler(this::onEventFailed).setTrackPhases(false).markerType(IModBusEvent.class).useModLauncher().build();
this.configHandler = Optional.of(ce->this.eventBus.post(ce.self()));
final FMLJavaModLoadingContext contextExtension = new FMLJavaModLoadingContext(this);
this.contextExtension = () -> contextExtension;
@@ -67,7 +67,7 @@
this.f_91064_ = new DebugRenderer(this);
this.f_238717_ = new RealmsDataFetcher(RealmsClient.m_239151_(this));
RenderSystem.m_69900_(this::m_91113_);
@@ -541,6 +_,19 @@
@@ -541,6 +_,21 @@
TinyFileDialogs.tinyfd_messageBox("Minecraft", stringbuilder.toString(), "ok", "error", false);
}
@@ -83,6 +83,8 @@
+ net.minecraftforge.client.gui.overlay.GuiOverlayManager.init();
+ net.minecraftforge.client.DimensionSpecialEffectsManager.init();
+ net.minecraftforge.client.NamedRenderTypeManager.init();
+ net.minecraftforge.client.ColorResolverManager.init();
+ net.minecraftforge.client.ItemDecoratorHandler.init();
+
this.f_90990_.m_85409_(this.f_91066_.m_231817_().m_231551_());
this.f_90990_.m_85424_(this.f_91066_.m_232123_().m_231551_());
@@ -0,0 +1,10 @@
--- a/net/minecraft/client/gui/components/toasts/ToastComponent.java
+++ b/net/minecraft/client/gui/components/toasts/ToastComponent.java
@@ -103,6 +_,7 @@
}
public void m_94922_(Toast p_94923_) {
+ if (net.minecraftforge.client.ForgeHooksClient.onToastAdd(p_94923_)) return;
this.f_94916_.add(p_94923_);
}
@@ -1,12 +1,13 @@
--- a/net/minecraft/client/gui/screens/inventory/EffectRenderingInventoryScreen.java
+++ b/net/minecraft/client/gui/screens/inventory/EffectRenderingInventoryScreen.java
@@ -42,12 +_,16 @@
@@ -42,12 +_,17 @@
if (!collection.isEmpty() && j >= 32) {
RenderSystem.m_157429_(1.0F, 1.0F, 1.0F, 1.0F);
boolean flag = j >= 120;
+ var event = net.minecraftforge.client.ForgeHooksClient.onScreenPotionSize(this, j, !flag);
+ if (event == 0) return; // 0 = cancel rendering
+ flag = event == 2; // 2 = full-size / 1 = compact
+ var event = net.minecraftforge.client.ForgeHooksClient.onScreenPotionSize(this, j, !flag, i);
+ if (event.isCanceled()) return;
+ flag = !event.isCompact();
+ i = event.getHorizontalOffset();
int k = 33;
if (collection.size() > 5) {
k = 132 / (collection.size() - 1);
@@ -0,0 +1,14 @@
--- a/net/minecraft/client/gui/screens/inventory/InventoryScreen.java
+++ b/net/minecraft/client/gui/screens/inventory/InventoryScreen.java
@@ -100,6 +_,11 @@
public static void m_98850_(int p_98851_, int p_98852_, int p_98853_, float p_98854_, float p_98855_, LivingEntity p_98856_) {
float f = (float)Math.atan((double)(p_98854_ / 40.0F));
float f1 = (float)Math.atan((double)(p_98855_ / 40.0F));
+ renderEntityInInventoryRaw(p_98851_, p_98852_, p_98853_, f, f1, p_98856_);
+ }
+ public static void renderEntityInInventoryRaw(int p_98851_, int p_98852_, int p_98853_, float angleXComponent, float angleYComponent, LivingEntity p_98856_) {
+ float f = angleXComponent;
+ float f1 = angleYComponent;
PoseStack posestack = RenderSystem.m_157191_();
posestack.m_85836_();
posestack.m_85837_((double)p_98851_, (double)p_98852_, 1050.0D);
@@ -0,0 +1,60 @@
--- a/net/minecraft/client/model/HumanoidModel.java
+++ b/net/minecraft/client/model/HumanoidModel.java
@@ -264,6 +_,8 @@
case TOOT_HORN:
this.f_102811_.f_104203_ = Mth.m_14036_(this.f_102808_.f_104203_, -1.2F, 1.2F) - 1.4835298F;
this.f_102811_.f_104204_ = this.f_102808_.f_104204_ - ((float)Math.PI / 6F);
+ default:
+ this.f_102816_.applyTransform(this, p_102876_, net.minecraft.world.entity.HumanoidArm.RIGHT);
}
}
@@ -304,6 +_,8 @@
case TOOT_HORN:
this.f_102812_.f_104203_ = Mth.m_14036_(this.f_102808_.f_104203_, -1.2F, 1.2F) - 1.4835298F;
this.f_102812_.f_104204_ = this.f_102808_.f_104204_ + ((float)Math.PI / 6F);
+ default:
+ this.f_102815_.applyTransform(this, p_102879_, net.minecraft.world.entity.HumanoidArm.LEFT);
}
}
@@ -396,7 +_,7 @@
}
@OnlyIn(Dist.CLIENT)
- public static enum ArmPose {
+ public static enum ArmPose implements net.minecraftforge.common.IExtensibleEnum {
EMPTY(false),
ITEM(false),
BLOCK(false),
@@ -411,10 +_,30 @@
private ArmPose(boolean p_102896_) {
this.f_102890_ = p_102896_;
+ this.forgeArmPose = null;
}
public boolean m_102897_() {
return this.f_102890_;
}
+ // FORGE START
+ @javax.annotation.Nullable
+ private final net.minecraftforge.client.IArmPoseTransformer forgeArmPose;
+
+ private ArmPose(boolean twoHanded, @javax.annotation.Nonnull net.minecraftforge.client.IArmPoseTransformer forgeArmPose) {
+ this.f_102890_ = twoHanded;
+ com.google.common.base.Preconditions.checkNotNull(forgeArmPose, "Cannot create new ArmPose with null transformer!");
+ this.forgeArmPose = forgeArmPose;
+ }
+
+ public static ArmPose create(String name, boolean twoHanded, @javax.annotation.Nonnull net.minecraftforge.client.IArmPoseTransformer forgeArmPose) {
+ throw new IllegalStateException("Enum not extended");
+ }
+
+ public <T extends LivingEntity> void applyTransform(HumanoidModel<T> model, T entity, net.minecraft.world.entity.HumanoidArm arm) {
+ com.google.common.base.Preconditions.checkNotNull(this.forgeArmPose, "applyTransform() must not be called on a vanilla ArmPose!");
+ this.forgeArmPose.applyTransform(model, entity, arm);
+ }
+ // FORGE END
}
}
@@ -1,6 +1,13 @@
--- a/net/minecraft/client/multiplayer/ClientLevel.java
+++ b/net/minecraft/client/multiplayer/ClientLevel.java
@@ -121,6 +_,8 @@
@@ -115,12 +_,15 @@
p_194170_.put(BiomeColors.f_108791_, new BlockTintCache((p_194168_) -> {
return this.m_104762_(p_194168_, BiomeColors.f_108791_);
}));
+ net.minecraftforge.client.ColorResolverManager.registerBlockTintCaches(ClientLevel.this, p_194170_);
});
private final ClientChunkCache f_104559_;
private final Deque<Runnable> f_194122_ = Queues.newArrayDeque();
private int f_194123_;
private final BlockStatePredictionHandler f_233599_ = new BlockStatePredictionHandler();
private static final Set<Item> f_194124_ = Set.of(Items.f_42127_, Items.f_151033_);
@@ -0,0 +1,10 @@
--- a/net/minecraft/client/particle/EnchantmentTableParticle.java
+++ b/net/minecraft/client/particle/EnchantmentTableParticle.java
@@ -73,6 +_,7 @@
this.f_107212_ = this.f_106461_ + this.f_107215_ * (double)f;
this.f_107213_ = this.f_106462_ + this.f_107216_ * (double)f - (double)(f1 * 1.2F);
this.f_107214_ = this.f_106460_ + this.f_107217_ * (double)f;
+ this.m_107264_(this.f_107212_, this.f_107213_, this.f_107214_); // FORGE: update the particle's bounding box
}
}
@@ -0,0 +1,10 @@
--- a/net/minecraft/client/particle/PortalParticle.java
+++ b/net/minecraft/client/particle/PortalParticle.java
@@ -75,6 +_,7 @@
this.f_107212_ = this.f_107548_ + this.f_107215_ * (double)f2;
this.f_107213_ = this.f_107549_ + this.f_107216_ * (double)f2 + (double)(1.0F - f);
this.f_107214_ = this.f_107547_ + this.f_107217_ * (double)f2;
+ this.m_107264_(this.f_107212_, this.f_107213_, this.f_107214_); // FORGE: update the particle's bounding box
}
}
@@ -0,0 +1,10 @@
--- a/net/minecraft/client/particle/ReversePortalParticle.java
+++ b/net/minecraft/client/particle/ReversePortalParticle.java
@@ -29,6 +_,7 @@
this.f_107212_ += this.f_107215_ * (double)f;
this.f_107213_ += this.f_107216_ * (double)f;
this.f_107214_ += this.f_107217_ * (double)f;
+ this.m_107264_(this.f_107212_, this.f_107213_, this.f_107214_); // FORGE: update the particle's bounding box
}
}
@@ -0,0 +1,10 @@
--- a/net/minecraft/client/particle/VibrationSignalParticle.java
+++ b/net/minecraft/client/particle/VibrationSignalParticle.java
@@ -100,6 +_,7 @@
this.f_107212_ = Mth.m_14139_(d0, this.f_107212_, vec3.m_7096_());
this.f_107213_ = Mth.m_14139_(d0, this.f_107213_, vec3.m_7098_());
this.f_107214_ = Mth.m_14139_(d0, this.f_107214_, vec3.m_7094_());
+ this.m_107264_(this.f_107212_, this.f_107213_, this.f_107214_); // FORGE: update the particle's bounding box
this.f_172460_ = this.f_172462_;
this.f_172462_ = (float)Mth.m_14136_(this.f_107212_ - vec3.m_7096_(), this.f_107214_ - vec3.m_7094_());
}
@@ -24,6 +24,14 @@
boolean flag1 = CrossbowItem.m_40932_(p_109377_);
boolean flag2 = humanoidarm == HumanoidArm.RIGHT;
int i = flag2 ? 1 : -1;
@@ -384,6 +_,7 @@
this.m_109322_(p_109372_, p_109377_, flag2 ? ItemTransforms.TransformType.FIRST_PERSON_RIGHT_HAND : ItemTransforms.TransformType.FIRST_PERSON_LEFT_HAND, !flag2, p_109379_, p_109380_, p_109381_);
} else {
boolean flag3 = humanoidarm == HumanoidArm.RIGHT;
+ if (!net.minecraftforge.client.extensions.common.IClientItemExtensions.of(p_109377_).applyForgeHandTransform(p_109379_, f_109299_.f_91074_, humanoidarm, p_109377_, p_109373_, p_109378_, p_109376_)) // FORGE: Allow items to define custom arm animation
if (p_109372_.m_6117_() && p_109372_.m_21212_() > 0 && p_109372_.m_7655_() == p_109375_) {
int k = flag3 ? 1 : -1;
switch (p_109377_.m_41780_()) {
@@ -487,8 +_,16 @@
this.f_109304_ = Mth.m_14036_(this.f_109304_ - 0.4F, 0.0F, 1.0F);
} else {
@@ -51,6 +51,16 @@
++this.f_109439_;
if (entity.f_19797_ == 0) {
entity.f_19790_ = entity.m_20185_();
@@ -1206,6 +_,9 @@
int i1 = i & 255;
outlinebuffersource.m_109929_(k, l, i1, 255);
} else {
+ if (this.m_109817_() && entity.hasCustomOutlineRendering(this.f_109461_.f_91074_)) { // FORGE: allow custom outline rendering
+ flag3 = true;
+ }
multibuffersource = multibuffersource$buffersource;
}
@@ -1226,6 +_,7 @@
List<BlockEntity> list = levelrenderer$renderchunkinfo.f_109839_.m_112835_().m_112773_();
if (!list.isEmpty()) {
@@ -59,7 +69,17 @@
BlockPos blockpos4 = blockentity1.m_58899_();
MultiBufferSource multibuffersource1 = multibuffersource$buffersource;
p_109600_.m_85836_();
@@ -1251,6 +_,7 @@
@@ -1242,6 +_,9 @@
};
}
}
+ if (this.m_109817_() && blockentity1.hasCustomOutlineRendering(this.f_109461_.f_91074_)) { // FORGE: allow custom outline rendering
+ flag3 = true;
+ }
this.f_172946_.m_112267_(blockentity1, p_109601_, p_109600_, multibuffersource1);
p_109600_.m_85849_();
@@ -1251,9 +_,13 @@
synchronized(this.f_109468_) {
for(BlockEntity blockentity : this.f_109468_) {
@@ -67,6 +87,12 @@
BlockPos blockpos3 = blockentity.m_58899_();
p_109600_.m_85836_();
p_109600_.m_85837_((double)blockpos3.m_123341_() - d0, (double)blockpos3.m_123342_() - d1, (double)blockpos3.m_123343_() - d2);
+ if (this.m_109817_() && blockentity.hasCustomOutlineRendering(this.f_109461_.f_91074_)) { // FORGE: allow custom outline rendering
+ flag3 = true;
+ }
this.f_172946_.m_112267_(blockentity, p_109601_, p_109600_, multibuffersource$buffersource);
p_109600_.m_85849_();
}
@@ -1290,7 +_,8 @@
p_109600_.m_85837_((double)blockpos2.m_123341_() - d0, (double)blockpos2.m_123342_() - d1, (double)blockpos2.m_123343_() - d2);
PoseStack.Pose posestack$pose = p_109600_.m_85850_();
@@ -60,6 +60,14 @@
crashreportcategory.m_128165_("Item Damage", () -> {
return String.valueOf(p_174237_.m_41773_());
});
@@ -362,6 +_,7 @@
RenderSystem.m_69482_();
}
+ net.minecraftforge.client.ItemDecoratorHandler.of(p_115176_).render(p_115175_, p_115176_, p_115177_, p_115178_, f_115093_);
}
}
@@ -377,5 +_,9 @@
public void m_6213_(ResourceManager p_115105_) {
@@ -10,7 +10,7 @@
}
public Vec3 m_7860_(AbstractClientPlayer p_117785_, float p_117786_) {
@@ -126,7 +_,7 @@
@@ -126,10 +_,13 @@
if (useanim == UseAnim.TOOT_HORN) {
return HumanoidModel.ArmPose.TOOT_HORN;
}
@@ -19,6 +19,12 @@
return HumanoidModel.ArmPose.CROSSBOW_HOLD;
}
+ HumanoidModel.ArmPose forgeArmPose = net.minecraftforge.client.extensions.common.IClientItemExtensions.of(itemstack).getArmPose(p_117795_, p_117796_, itemstack);
+ if (forgeArmPose != null) return forgeArmPose;
+
return HumanoidModel.ArmPose.ITEM;
}
}
@@ -161,10 +_,12 @@
}
@@ -0,0 +1,11 @@
--- a/net/minecraft/commands/arguments/EntityArgument.java
+++ b/net/minecraft/commands/arguments/EntityArgument.java
@@ -115,7 +_,7 @@
if (s instanceof SharedSuggestionProvider sharedsuggestionprovider) {
StringReader stringreader = new StringReader(p_91483_.getInput());
stringreader.setCursor(p_91483_.getStart());
- EntitySelectorParser entityselectorparser = new EntitySelectorParser(stringreader, sharedsuggestionprovider.m_6761_(2));
+ EntitySelectorParser entityselectorparser = new EntitySelectorParser(stringreader, net.minecraftforge.common.ForgeHooks.canUseEntitySelectors(sharedsuggestionprovider));
try {
entityselectorparser.m_121377_();
@@ -0,0 +1,11 @@
--- a/net/minecraft/commands/arguments/MessageArgument.java
+++ b/net/minecraft/commands/arguments/MessageArgument.java
@@ -134,7 +_,7 @@
}
Component m_232196_(CommandSourceStack p_232197_) throws CommandSyntaxException {
- return this.m_96849_(p_232197_, p_232197_.m_6761_(2));
+ return this.m_96849_(p_232197_, net.minecraftforge.common.ForgeHooks.canUseEntitySelectors(p_232197_));
}
public Component m_96849_(CommandSourceStack p_96850_, boolean p_96851_) throws CommandSyntaxException {
@@ -0,0 +1,11 @@
--- a/net/minecraft/commands/arguments/selector/EntitySelector.java
+++ b/net/minecraft/commands/arguments/selector/EntitySelector.java
@@ -87,7 +_,7 @@
}
private void m_121168_(CommandSourceStack p_121169_) throws CommandSyntaxException {
- if (this.f_121123_ && !p_121169_.m_6761_(2)) {
+ if (this.f_121123_ && !net.minecraftforge.common.ForgeHooks.canUseEntitySelectors(p_121169_)) {
throw EntityArgument.f_91441_.create();
}
}
@@ -0,0 +1,33 @@
--- a/net/minecraft/core/HolderSet.java
+++ b/net/minecraft/core/HolderSet.java
@@ -14,7 +_,7 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-public interface HolderSet<T> extends Iterable<Holder<T>> {
+public interface HolderSet<T> extends Iterable<Holder<T>>, net.minecraftforge.common.extensions.IForgeHolderSet<T> {
Stream<Holder<T>> m_203614_();
int m_203632_();
@@ -120,6 +_,9 @@
public void m_205835_(List<Holder<T>> p_205836_) {
this.f_205830_ = List.copyOf(p_205836_);
+ for (Runnable runnable : this.invalidationCallbacks) {
+ runnable.run(); // FORGE: invalidate listeners when tags rebind
+ }
}
public TagKey<T> m_205839_() {
@@ -144,6 +_,11 @@
public boolean m_207277_(Registry<T> p_211049_) {
return this.f_211044_ == p_211049_;
+ }
+ // FORGE: Keep a list of invalidation callbacks so they can be run when tags rebind
+ private List<Runnable> invalidationCallbacks = new java.util.ArrayList<>();
+ public void addInvalidationListener(Runnable runnable) {
+ invalidationCallbacks.add(runnable);
}
}
}
@@ -25,7 +25,7 @@
}
public ClientboundCustomPayloadPacket(FriendlyByteBuf p_178836_) {
@@ -43,6 +_,7 @@
@@ -43,15 +_,17 @@
} else {
throw new IllegalArgumentException("Payload may not be larger than 1048576 bytes");
}
@@ -33,7 +33,10 @@
}
public void m_5779_(FriendlyByteBuf p_132044_) {
@@ -52,6 +_,7 @@
p_132044_.m_130085_(this.f_132029_);
- p_132044_.writeBytes(this.f_132030_.copy());
+ p_132044_.writeBytes(this.f_132030_.slice()); // Use Slice instead of copy, to not update the read index, allowing packet to be sent multiple times.
}
public void m_5797_(ClientGamePacketListener p_132041_) {
p_132041_.m_7413_(this);
@@ -41,3 +44,12 @@
}
public ResourceLocation m_132042_() {
@@ -61,4 +_,8 @@
public FriendlyByteBuf m_132045_() {
return new FriendlyByteBuf(this.f_132030_.copy());
}
+
+ @Override public int getIndex() { return Integer.MAX_VALUE; }
+ @Override public ResourceLocation getName() { return m_132042_(); }
+ @org.jetbrains.annotations.Nullable @Override public FriendlyByteBuf getInternalData() { return this.f_132030_; }
}
@@ -14,7 +14,16 @@
public void m_5779_(FriendlyByteBuf p_133994_) {
p_133994_.m_130085_(this.f_133980_);
- p_133994_.writeBytes((ByteBuf)this.f_133981_);
+ p_133994_.writeBytes((ByteBuf)this.f_133981_.copy()); //This may be access multiple times, from multiple threads, lets be safe like the S->C packet
+ p_133994_.writeBytes((ByteBuf)this.f_133981_.slice()); // Use Slice instead of copy, to not update the read index, allowing packet to be sent multiple times.
}
public void m_5797_(ServerGamePacketListener p_133992_) {
@@ -43,4 +_,8 @@
public FriendlyByteBuf m_179590_() {
return this.f_133981_;
}
+
+ @Override public int getIndex() { return Integer.MAX_VALUE; }
+ @Override public ResourceLocation getName() { return m_179589_(); }
+ @org.jetbrains.annotations.Nullable @Override public FriendlyByteBuf getInternalData() { return m_179590_(); }
}
@@ -9,3 +9,21 @@
private static final int f_179804_ = 1048576;
private final int f_134745_;
private final ResourceLocation f_134746_;
@@ -30,7 +_,7 @@
public void m_5779_(FriendlyByteBuf p_134757_) {
p_134757_.m_130130_(this.f_134745_);
p_134757_.m_130085_(this.f_134746_);
- p_134757_.writeBytes(this.f_134747_.copy());
+ p_134757_.writeBytes(this.f_134747_.slice()); // Use Slice instead of copy, to not update the read index, allowing packet to be sent multiple times.
}
public void m_5797_(ClientLoginPacketListener p_134754_) {
@@ -48,4 +_,8 @@
public FriendlyByteBuf m_179812_() {
return this.f_134747_;
}
+
+ @Override public int getIndex() { return m_134755_(); }
+ @Override public ResourceLocation getName() { return m_179811_(); }
+ @org.jetbrains.annotations.Nullable @Override public FriendlyByteBuf getInternalData() { return m_179812_(); }
}
@@ -10,3 +10,12 @@
private static final int f_179821_ = 1048576;
private final int f_134825_;
@Nullable
@@ -46,4 +_,8 @@
public FriendlyByteBuf m_179825_() {
return this.f_134826_;
}
+
+ @Override public int getIndex() { return m_179824_(); }
+ @Override public net.minecraft.resources.ResourceLocation getName() { return net.minecraftforge.network.LoginWrapper.WRAPPER; }
+ @org.jetbrains.annotations.Nullable @Override public FriendlyByteBuf getInternalData() { return m_179825_(); }
}
@@ -0,0 +1,45 @@
--- a/net/minecraft/resources/HolderSetCodec.java
+++ b/net/minecraft/resources/HolderSetCodec.java
@@ -20,6 +_,8 @@
private final Codec<Holder<E>> f_206656_;
private final Codec<List<Holder<E>>> f_206657_;
private final Codec<Either<TagKey<E>, List<Holder<E>>>> f_206658_;
+ private final Codec<net.minecraftforge.registries.holdersets.ICustomHolderSet<E>> forgeDispatchCodec;
+ private final Codec<Either<net.minecraftforge.registries.holdersets.ICustomHolderSet<E>, Either<TagKey<E>, List<Holder<E>>>>> combinedCodec;
private static <E> Codec<List<Holder<E>>> m_206667_(Codec<Holder<E>> p_206668_, boolean p_206669_) {
Function<List<Holder<E>>, DataResult<List<Holder<E>>>> function = ExtraCodecs.m_203984_(Holder::m_203376_);
@@ -42,6 +_,10 @@
this.f_206656_ = p_206661_;
this.f_206657_ = m_206667_(p_206661_, p_206662_);
this.f_206658_ = Codec.either(TagKey.m_203886_(p_206660_), this.f_206657_);
+ // FORGE: make registry-specific dispatch codec and make forge-or-vanilla either codec
+ this.forgeDispatchCodec = ExtraCodecs.m_184415_(() -> net.minecraftforge.registries.ForgeRegistries.HOLDER_SET_TYPES.get().getCodec())
+ .dispatch(net.minecraftforge.registries.holdersets.ICustomHolderSet::type, type -> type.makeCodec(p_206660_, p_206661_, p_206662_));
+ this.combinedCodec = new ExtraCodecs.EitherCodec<>(this.forgeDispatchCodec, this.f_206658_);
}
public <T> DataResult<Pair<HolderSet<E>, T>> decode(DynamicOps<T> p_206696_, T p_206697_) {
@@ -49,9 +_,10 @@
Optional<? extends Registry<E>> optional = registryops.m_206826_(this.f_206655_);
if (optional.isPresent()) {
Registry<E> registry = optional.get();
- return this.f_206658_.decode(p_206696_, p_206697_).map((p_206682_) -> {
+ // FORGE: use the wrapped codec to decode custom/tag/list instead of just tag/list
+ return this.combinedCodec.decode(p_206696_, p_206697_).map((p_206682_) -> {
return p_206682_.mapFirst((p_206679_) -> {
- return p_206679_.map(registry::m_203561_, HolderSet::m_205800_);
+ return p_206679_.map(java.util.function.Function.identity(), tagOrList -> tagOrList.map(registry::m_203561_, HolderSet::m_205800_));
});
});
}
@@ -68,6 +_,9 @@
return DataResult.error("HolderSet " + p_206674_ + " is not valid in current registry set");
}
+ // FORGE: use the dispatch codec to encode custom holdersets, otherwise fall back to vanilla tag/list
+ if (p_206674_ instanceof net.minecraftforge.registries.holdersets.ICustomHolderSet<E> customHolderSet)
+ return this.forgeDispatchCodec.encode(customHolderSet, p_206675_, p_206676_);
return this.f_206658_.encode(p_206674_.m_203440_().mapRight(List::copyOf), p_206675_, p_206676_);
}
}
@@ -0,0 +1,16 @@
--- a/net/minecraft/resources/RegistryLoader.java
+++ b/net/minecraft/resources/RegistryLoader.java
@@ -48,7 +_,12 @@
if (dataresult != null) {
return dataresult;
} else {
- Holder<E> holder = p_214229_.m_214121_(p_214232_);
+ // Prevents an exception from disrupting codec decoding when calling this with prematurely frozen registries - see comment in LevelStorageSource
+ DataResult<Holder<E>> maybeHolder = p_214229_.m_214185_(p_214232_);
+ if (maybeHolder.error().isPresent()) {
+ return maybeHolder;
+ }
+ Holder<E> holder = maybeHolder.result().get();
readcache.f_206803_.put(p_214232_, DataResult.success(holder));
DataResult<Holder<E>> dataresult1;
if (p_214233_.isEmpty()) {
@@ -0,0 +1,20 @@
--- a/net/minecraft/util/datafix/schemas/V2832.java
+++ b/net/minecraft/util/datafix/schemas/V2832.java
@@ -19,7 +_,7 @@
return DSL.fields("Level", DSL.optionalFields("Entities", DSL.list(References.f_16785_.in(p_185234_)), "TileEntities", DSL.list(DSL.or(References.f_16781_.in(p_185234_), DSL.remainder())), "TileTicks", DSL.list(DSL.fields("i", References.f_16787_.in(p_185234_))), "Sections", DSL.list(DSL.optionalFields("biomes", DSL.optionalFields("palette", DSL.list(References.f_16794_.in(p_185234_))), "block_states", DSL.optionalFields("palette", DSL.list(References.f_16783_.in(p_185234_))))), "Structures", DSL.optionalFields("Starts", DSL.compoundList(References.f_16790_.in(p_185234_)))));
});
p_185234_.registerType(false, References.f_16795_, () -> {
- return DSL.fields("dimensions", DSL.compoundList(DSL.constType(m_17310_()), DSL.fields("generator", DSL.taggedChoiceLazy("type", DSL.string(), ImmutableMap.of("minecraft:debug", DSL::remainder, "minecraft:flat", () -> {
+ return DSL.fields("dimensions", DSL.compoundList(DSL.constType(m_17310_()), DSL.fields("generator", DSL.or(DSL.taggedChoiceLazy("type", DSL.string(), ImmutableMap.of("minecraft:debug", DSL::remainder, "minecraft:flat", () -> {
return DSL.optionalFields("settings", DSL.optionalFields("biome", References.f_16794_.in(p_185234_), "layers", DSL.list(DSL.optionalFields("block", References.f_16787_.in(p_185234_)))));
}, "minecraft:noise", () -> {
return DSL.optionalFields("biome_source", DSL.taggedChoiceLazy("type", DSL.string(), ImmutableMap.of("minecraft:fixed", () -> {
@@ -29,7 +_,7 @@
}, "minecraft:checkerboard", () -> {
return DSL.fields("biomes", DSL.list(References.f_16794_.in(p_185234_)));
}, "minecraft:the_end", DSL::remainder)), "settings", DSL.or(DSL.constType(DSL.string()), DSL.optionalFields("default_block", References.f_16787_.in(p_185234_), "default_fluid", References.f_16787_.in(p_185234_))));
- })))));
+ })), DSL.remainder()))));
});
}
}
@@ -590,6 +590,15 @@
if (this.f_20935_.m_41781_()) {
this.m_21329_();
}
@@ -2989,7 +_,7 @@
public boolean m_21254_() {
if (this.m_6117_() && !this.f_20935_.m_41619_()) {
Item item = this.f_20935_.m_41720_();
- if (item.m_6164_(this.f_20935_) != UseAnim.BLOCK) {
+ if (item.m_6164_(this.f_20935_) != UseAnim.BLOCK && !this.f_20935_.canPerformAction(net.minecraftforge.common.ToolActions.SHIELD_BLOCK)) { // TODO 1.20 only use the tool action
return false;
} else {
return item.m_8105_(this.f_20935_) - this.f_20936_ >= 5;
@@ -3115,8 +_,8 @@
}
@@ -24,9 +24,9 @@
this.f_39000_ = 0;
+ boolean flag = false;
+
+ if (!net.minecraftforge.common.ForgeHooks.onAnvilChange(this, itemstack, itemstack2, f_39768_, f_39001_, j, this.f_39771_)) return;
if (!itemstack2.m_41619_()) {
- boolean flag = itemstack2.m_150930_(Items.f_42690_) && !EnchantedBookItem.m_41163_(itemstack2).isEmpty();
+ if (!net.minecraftforge.common.ForgeHooks.onAnvilChange(this, itemstack, itemstack2, f_39768_, f_39001_, j, this.f_39771_)) return;
+ flag = itemstack2.m_41720_() == Items.f_42690_ && !EnchantedBookItem.m_41163_(itemstack2).isEmpty();
if (itemstack1.m_41763_() && itemstack1.m_41720_().m_6832_(itemstack, itemstack2)) {
int l2 = Math.min(itemstack1.m_41773_(), itemstack1.m_41776_() / 4);
@@ -0,0 +1,14 @@
--- a/net/minecraft/world/item/UseAnim.java
+++ b/net/minecraft/world/item/UseAnim.java
@@ -9,5 +_,10 @@
SPEAR,
CROSSBOW,
SPYGLASS,
- TOOT_HORN;
+ TOOT_HORN,
+ /**
+ * Items with custom arm animation should return this in `Item#getUseAnimation`
+ * to prevent vanilla from also trying to animate same item
+ */
+ CUSTOM
}
@@ -38,6 +38,22 @@
}, p_44834_);
return mutablefloat.floatValue();
}
@@ -168,6 +_,7 @@
m_44853_(enchantmenthelper$enchantmentvisitor, p_44824_.m_20158_());
}
+ if(false) // Forge: Fix MC-248272
if (p_44825_ instanceof Player) {
m_44850_(enchantmenthelper$enchantmentvisitor, p_44824_.m_21205_());
}
@@ -182,6 +_,7 @@
m_44853_(enchantmenthelper$enchantmentvisitor, p_44897_.m_20158_());
}
+ if(false) // Forge: Fix MC-248272
if (p_44897_ instanceof Player) {
m_44850_(enchantmenthelper$enchantmentvisitor, p_44897_.m_21205_());
}
@@ -302,7 +_,7 @@
public static int m_220287_(RandomSource p_220288_, int p_220289_, int p_220290_, ItemStack p_220291_) {
@@ -1,5 +1,19 @@
--- a/net/minecraft/world/level/storage/LevelStorageSource.java
+++ b/net/minecraft/world/level/storage/LevelStorageSource.java
@@ -96,6 +_,13 @@
}
Dynamic<T> dynamic1 = p_78206_.update(References.f_16795_, dynamic, p_78207_, SharedConstants.m_183709_().getWorldVersion());
+ // The above line is modified (via the patch in V2832), such that the data fixer upper will retain dimensions that don't exist in the schema, in the dynamic.
+ // When we parse the WorldGenSettings below, in vanilla, this uses the same call paths that can cause things to register (such as dimension types).
+ // However, since at this point all resource data will have been loaded, anything that *would* register now is going to error later, because it'll create a Holder<> reference, that is not bound to anything. This unbound reference will then throw an error when the registries are frozen.
+ // So, we freeze the registries before this call to parse(). This prevents them from leaking any new unbound holders into the registry.
+ // Attempting to register to a frozen registry throws an exception, which we resolve via a patch in RegistryLoader, causing it to return DataResult.error() instead, and prevent the faulty dimension from registering without aborting the parsing of the WorldGenSettings
+ // Finally, the resultOrPartial() promotes only the dimensions which successfully parsed, and the LenientUnboundedMapCodec which is patched into the WorldGenSettings codec ensures that *only* the invalid dimensions will fail to parse (see MC-197860), and not discard other dimensions as well.
+ if (p_78205_.getOps() instanceof net.minecraft.resources.RegistryOps<T> ops) ops.f_206806_.m_203610_().forEach(e -> e.f_206234_().m_203521_());
DataResult<WorldGenSettings> dataresult = WorldGenSettings.f_64600_.parse(dynamic1);
return Pair.of(dataresult.resultOrPartial(Util.m_137489_("WorldGenSettings: ", f_78191_::error)).orElseGet(() -> {
RegistryAccess registryaccess = RegistryAccess.m_206154_(dynamic1);
@@ -372,6 +_,19 @@
return LevelStorageSource.this.m_230817_(this.f_230867_, LevelStorageSource.m_211737_(p_211748_, p_211749_, p_211750_));
}
@@ -0,0 +1,51 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.client;
import com.google.common.collect.ImmutableList;
import net.minecraft.client.color.block.BlockTintCache;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.world.level.ColorResolver;
import net.minecraftforge.client.event.RegisterColorHandlersEvent;
import net.minecraftforge.fml.ModLoader;
import org.jetbrains.annotations.ApiStatus;
import java.util.Map;
/**
* Manager for custom {@link ColorResolver} instances, collected via {@link RegisterColorHandlersEvent.ColorResolvers}.
*/
public final class ColorResolverManager
{
private static ImmutableList<ColorResolver> colorResolvers;
@ApiStatus.Internal
public static void init()
{
ImmutableList.Builder<ColorResolver> builder = ImmutableList.builder();
ModLoader.get().postEvent(new RegisterColorHandlersEvent.ColorResolvers(builder));
colorResolvers = builder.build();
}
/**
* Register a {@link BlockTintCache} for every registered {@link ColorResolver} into the given target map.
*
* @param level the level to use
* @param target the map to populate
*/
public static void registerBlockTintCaches(ClientLevel level, Map<ColorResolver, BlockTintCache> target)
{
for (var resolver : colorResolvers)
{
target.put(resolver, new BlockTintCache(pos -> level.calculateBlockTint(pos, resolver)));
}
}
private ColorResolverManager()
{
}
}
+11 -3
View File
@@ -27,6 +27,7 @@ import net.minecraft.client.color.item.ItemColors;
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.GuiComponent;
import net.minecraft.client.gui.components.LerpingBossEvent;
import net.minecraft.client.gui.components.toasts.Toast;
import net.minecraft.client.gui.screens.ConfirmScreen;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.gui.screens.TitleScreen;
@@ -128,6 +129,7 @@ import net.minecraftforge.client.event.RenderTooltipEvent;
import net.minecraftforge.client.event.ScreenEvent;
import net.minecraftforge.client.event.ScreenshotEvent;
import net.minecraftforge.client.event.TextureStitchEvent;
import net.minecraftforge.client.event.ToastAddEvent;
import net.minecraftforge.client.event.ViewportEvent;
import net.minecraftforge.client.event.sound.PlaySoundEvent;
import net.minecraftforge.client.extensions.common.IClientFluidTypeExtensions;
@@ -1091,10 +1093,16 @@ public class ForgeHooksClient
};
}
public static int onScreenPotionSize(Screen screen, int availableSpace, boolean compact)
public static ScreenEvent.RenderInventoryMobEffects onScreenPotionSize(Screen screen, int availableSpace, boolean compact, int horizontalOffset)
{
final ScreenEvent.RenderInventoryMobEffects event = new ScreenEvent.RenderInventoryMobEffects(screen, availableSpace, compact);
return MinecraftForge.EVENT_BUS.post(event) ? 0 : (event.isCompact() ? 1 : 2);
final ScreenEvent.RenderInventoryMobEffects event = new ScreenEvent.RenderInventoryMobEffects(screen, availableSpace, compact, horizontalOffset);
MinecraftForge.EVENT_BUS.post(event);
return event;
}
public static boolean onToastAdd(Toast toast)
{
return MinecraftForge.EVENT_BUS.post(new ToastAddEvent(toast));
}
public static boolean isBlockInSolidLayer(BlockState state)
@@ -0,0 +1,34 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.client;
import net.minecraft.client.model.HumanoidModel;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.HumanoidArm;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.client.extensions.common.IClientItemExtensions;
/**
* An ArmPose that can be defined by the user.
* Register one by creating a custom {@link net.minecraft.client.model.HumanoidModel.ArmPose}
* and returning it in {@link IClientItemExtensions#getArmPose(LivingEntity, InteractionHand, ItemStack)}.
*/
@FunctionalInterface
public interface IArmPoseTransformer
{
/**
* This method should be used to apply all wanted transformations to the player when the ArmPose is active.
* You can use {@link LivingEntity#getTicksUsingItem()} and {@link LivingEntity#getUseItemRemainingTicks()} for moving animations.
*
* @param model The humanoid model
* @param entity The humanoid entity
* @param arm Arm to pose
*/
void applyTransform(HumanoidModel<?> model, LivingEntity entity, HumanoidArm arm);
}
@@ -0,0 +1,29 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.client;
import net.minecraft.client.gui.Font;
import net.minecraft.client.renderer.entity.ItemRenderer;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.ItemLike;
import net.minecraftforge.client.event.RegisterItemDecorationsEvent;
/**
* An ItemDecorator that is used to render something on specific items, when the DurabilityBar and StackCount is rendered.
* Add it to an item using {@linkplain RegisterItemDecorationsEvent#register(ItemLike, IItemDecorator)}.
*/
public interface IItemDecorator
{
/**
* Is called after {@linkplain ItemRenderer#renderGuiItemDecorations(Font, ItemStack, int, int, String)} is done rendering.
* The StackCount is rendered at blitOffset+200 so use the blitOffset with caution.
* <p>
* The RenderState during this call will be: enableTexture, enableDepthTest, enableBlend and defaultBlendFunc
* @return true if you have modified the RenderState and it has to be reset for other ItemDecorators
*/
boolean render(Font font, ItemStack stack, int xOffset, int yOffset, float blitOffset);
}
@@ -0,0 +1,73 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.client;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.mojang.blaze3d.systems.RenderSystem;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import net.minecraft.client.gui.Font;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.client.event.RegisterItemDecorationsEvent;
import net.minecraftforge.fml.ModLoader;
import net.minecraftforge.fml.ModLoadingContext;
import org.jetbrains.annotations.ApiStatus;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ApiStatus.Internal
public final class ItemDecoratorHandler
{
private final List<IItemDecorator> itemDecorators;
private static Map<Item, ItemDecoratorHandler> DECORATOR_LOOKUP = ImmutableMap.of();
private static final ItemDecoratorHandler EMPTY = new ItemDecoratorHandler();
private ItemDecoratorHandler()
{
this.itemDecorators = ImmutableList.of();
}
private ItemDecoratorHandler(List<IItemDecorator> itemDecorators)
{
this.itemDecorators = ImmutableList.copyOf(itemDecorators);
}
public static void init()
{
var decorators = new HashMap<Item, List<IItemDecorator>>();
var event = new RegisterItemDecorationsEvent(decorators);
ModLoader.get().postEventWithWrapInModOrder(event, (mc, e) -> ModLoadingContext.get().setActiveContainer(mc), (mc, e) -> ModLoadingContext.get().setActiveContainer(null));
var builder = new ImmutableMap.Builder<Item, ItemDecoratorHandler>();
decorators.forEach((item, itemDecorators) -> builder.put(item, new ItemDecoratorHandler(itemDecorators)));
DECORATOR_LOOKUP = builder.build();
}
public static ItemDecoratorHandler of(ItemStack stack)
{
return DECORATOR_LOOKUP.getOrDefault(stack.getItem(), EMPTY);
}
public void render(Font font, ItemStack stack, int xOffset, int yOffset, float blitOffset)
{
resetRenderState();
for (IItemDecorator itemDecorator : itemDecorators)
{
if (itemDecorator.render(font, stack, xOffset, yOffset, blitOffset))
resetRenderState();
}
}
private void resetRenderState()
{
RenderSystem.enableTexture();
RenderSystem.enableDepthTest();
RenderSystem.enableBlend();
RenderSystem.defaultBlendFunc();
}
}
@@ -5,10 +5,13 @@
package net.minecraftforge.client.event;
import com.google.common.collect.ImmutableList;
import net.minecraft.client.color.block.BlockColor;
import net.minecraft.client.color.block.BlockColors;
import net.minecraft.client.color.item.ItemColor;
import net.minecraft.client.color.item.ItemColors;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.ColorResolver;
import net.minecraft.world.level.ItemLike;
import net.minecraftforge.eventbus.api.Cancelable;
import net.minecraftforge.eventbus.api.Event;
@@ -127,4 +130,26 @@ public abstract class RegisterColorHandlersEvent extends Event implements IModBu
itemColors.register(itemColor, items);
}
}
/**
* Allows registration of custom {@link ColorResolver} implementations to be used with
* {@link net.minecraft.world.level.BlockAndTintGetter#getBlockTint(BlockPos, ColorResolver)}.
*/
public static class ColorResolvers extends RegisterColorHandlersEvent
{
private final ImmutableList.Builder<ColorResolver> builder;
@ApiStatus.Internal
public ColorResolvers(ImmutableList.Builder<ColorResolver> builder)
{
this.builder = builder;
}
public void register(ColorResolver resolver)
{
this.builder.add(resolver);
}
}
}
@@ -0,0 +1,49 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.client.event;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.ItemLike;
import net.minecraftforge.client.IItemDecorator;
import net.minecraftforge.eventbus.api.Cancelable;
import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.fml.LogicalSide;
import net.minecraftforge.fml.event.IModBusEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import org.jetbrains.annotations.ApiStatus;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Allows users to register custom {@linkplain IItemDecorator IItemDecorator} to Items.
*
* <p>This event is not {@linkplain Cancelable cancelable}, and does not {@linkplain HasResult have a result}.
*
* <p>This event is fired on the {@linkplain FMLJavaModLoadingContext#getModEventBus() mod-specific event bus},
* only on the {@linkplain LogicalSide#CLIENT logical client}.</p>
*/
public class RegisterItemDecorationsEvent extends Event implements IModBusEvent
{
private final Map<Item, List<IItemDecorator>> decorators;
@ApiStatus.Internal
public RegisterItemDecorationsEvent(Map<Item, List<IItemDecorator>> decorators)
{
this.decorators = decorators;
}
/**
* Register an ItemDecorator to an Item
*/
public void register(ItemLike itemLike, IItemDecorator decorator)
{
List<IItemDecorator> itemDecoratorList = decorators.computeIfAbsent(itemLike.asItem(), item -> new ArrayList<>());
itemDecoratorList.add(decorator);
}
}
@@ -275,6 +275,7 @@ public abstract class ScreenEvent extends Event
/**
* Fired ahead of rendering any active mob effects in the {@link EffectRenderingInventoryScreen inventory screen}.
* Can be used to select the size of the effects display (full or compact) or even hide or replace vanilla's rendering entirely.
* This event can also be used to modify the horizontal position of the stack of effects being rendered.
*
* <p>This event is {@linkplain Cancelable cancellable} and does not {@linkplain HasResult have a result}.
* Cancelling this event will prevent vanilla rendering.</p>
@@ -287,13 +288,15 @@ public abstract class ScreenEvent extends Event
{
private final int availableSpace;
private boolean compact;
private int horizontalOffset;
@ApiStatus.Internal
public RenderInventoryMobEffects(Screen screen, int availableSpace, boolean compact)
public RenderInventoryMobEffects(Screen screen, int availableSpace, boolean compact, int horizontalOffset)
{
super(screen);
this.availableSpace = availableSpace;
this.compact = compact;
this.horizontalOffset = horizontalOffset;
}
/**
@@ -312,6 +315,30 @@ public abstract class ScreenEvent extends Event
return compact;
}
/**
* The distance from the left side of the screen that the effect stack is rendered. Positive values shift this more to the right.
*/
public int getHorizontalOffset()
{
return horizontalOffset;
}
/**
* Replaces the horizontal offset of the effect stack
*/
public void setHorizontalOffset(int offset)
{
horizontalOffset = offset;
}
/**
* Adds to the horizontal offset of the effect stack. Negative values are acceptable.
*/
public void addHorizontalOffset(int offset)
{
horizontalOffset += offset;
}
/**
* Sets whether the effects should be rendered in compact mode (only icons, no text), or the default full size.
*/
@@ -0,0 +1,38 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.client.event;
import net.minecraft.client.gui.components.toasts.Toast;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.eventbus.api.Cancelable;
import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.fml.LogicalSide;
/**
* Fired when the client queues a {@link Toast} message to be shown onscreen.
* Toasts are small popups that appear on the top right of the screen, for certain actions such as unlocking Advancements and Recipes.
*
* <p>This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.
* Cancelling the event stops the toast from being queued, which means it never renders.</p>
*
* <p>This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus},
* only on the {@linkplain LogicalSide#CLIENT logical client}.</p>
*/
@Cancelable
public class ToastAddEvent extends Event
{
private final Toast toast;
public ToastAddEvent(Toast toast)
{
this.toast = toast;
}
public Toast getToast()
{
return toast;
}
}
@@ -5,19 +5,24 @@
package net.minecraftforge.client.extensions.common;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraft.client.model.HumanoidModel;
import net.minecraft.client.model.Model;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.HumanoidArm;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.client.ForgeHooksClient;
import net.minecraftforge.client.IArmPoseTransformer;
import net.minecraftforge.fml.LogicalSide;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -57,6 +62,37 @@ public interface IClientItemExtensions
return null;
}
/**
* This method returns an ArmPose that can be defined using the {@link net.minecraft.client.model.HumanoidModel.ArmPose#create(String, boolean, IArmPoseTransformer)} method.
* This allows for creating custom item use animations.
*
* @param entityLiving The entity holding the item
* @param hand The hand the ArmPose will be applied to
* @param itemStack The stack being held
* @return A custom ArmPose that can be used to define movement of the arm
*/
@Nullable
default HumanoidModel.ArmPose getArmPose(LivingEntity entityLiving, InteractionHand hand, ItemStack itemStack)
{
return null;
}
/**
* Called right before when client applies transformations to item in hand and render it.
*
* @param poseStack The pose stack
* @param player The player holding the item, it's always main client player
* @param arm The arm holding the item
* @param itemInHand The held item
* @param partialTick Partial tick time, useful for interpolation
* @param equipProcess Equip process time, Ranging from 0.0 to 1.0. 0.0 when it's done equipping
* @param swingProcess Swing process time, Ranging from 0.0 to 1.0. 0.0 when it's done swinging
* @return true if it should skip applying other transforms and go straight to rendering
*/
default boolean applyForgeHandTransform(PoseStack poseStack, LocalPlayer player, HumanoidArm arm, ItemStack itemInHand, float partialTick, float equipProcess, float swingProcess) {
return false;
}
/**
* Queries the humanoid armor model for this item when it's equipped.
*
@@ -25,12 +25,16 @@ import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.mojang.datafixers.util.Either;
import com.mojang.serialization.Codec;
import com.mojang.serialization.Lifecycle;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import net.minecraft.ResourceLocationException;
import net.minecraft.advancements.Advancement;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.commands.SharedSuggestionProvider;
import net.minecraft.core.*;
import net.minecraft.network.chat.*;
import net.minecraft.network.chat.contents.LiteralContents;
@@ -145,6 +149,8 @@ import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.registries.ForgeRegistry;
import net.minecraftforge.registries.GameData;
import net.minecraftforge.registries.RegistryManager;
import net.minecraftforge.registries.holdersets.ICustomHolderSet;
import net.minecraftforge.server.permission.PermissionAPI;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -152,6 +158,7 @@ import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;
import net.minecraft.ChatFormatting;
import net.minecraft.resources.HolderSetCodec;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.damagesource.DamageSource;
@@ -1488,4 +1495,13 @@ public class ForgeHooks
{
return registryKey.getNamespace().equals("minecraft") ? registryKey.getPath() : registryKey.getNamespace() + "/" + registryKey.getPath();
}
public static boolean canUseEntitySelectors(SharedSuggestionProvider provider)
{
if (provider instanceof CommandSourceStack source && source.getEntity() instanceof ServerPlayer player)
{
return PermissionAPI.getPermission(player, ForgeMod.USE_SELECTORS_PERMISSION);
}
return provider.hasPermission(Commands.LEVEL_GAMEMASTERS);
}
}
@@ -14,6 +14,7 @@ import net.minecraft.core.BlockPos;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.Mob;
import net.minecraft.commands.Commands;
import net.minecraft.world.entity.ai.attributes.Attribute;
import net.minecraft.world.entity.ai.attributes.RangedAttribute;
import net.minecraft.world.entity.item.ItemEntity;
@@ -61,6 +62,11 @@ import net.minecraftforge.fml.*;
import net.minecraftforge.fml.config.ModConfig;
import net.minecraftforge.fml.event.lifecycle.*;
import net.minecraftforge.registries.*;
import net.minecraftforge.registries.holdersets.AndHolderSet;
import net.minecraftforge.registries.holdersets.AnyHolderSet;
import net.minecraftforge.registries.holdersets.HolderSetType;
import net.minecraftforge.registries.holdersets.NotHolderSet;
import net.minecraftforge.registries.holdersets.OrHolderSet;
import net.minecraftforge.network.NetworkConstants;
import net.minecraftforge.event.server.ServerStoppingEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
@@ -68,6 +74,9 @@ import net.minecraftforge.data.event.GatherDataEvent;
import net.minecraftforge.network.filters.VanillaPacketSplitter;
import net.minecraftforge.server.command.EnumArgument;
import net.minecraftforge.server.command.ModIdArgument;
import net.minecraftforge.server.permission.events.PermissionGatherEvent;
import net.minecraftforge.server.permission.nodes.PermissionNode;
import net.minecraftforge.server.permission.nodes.PermissionTypes;
import net.minecraftforge.versions.forge.ForgeVersion;
import net.minecraftforge.versions.mcp.MCPVersion;
@@ -120,6 +129,7 @@ public class ForgeMod
private static final DeferredRegister<ArgumentTypeInfo<?, ?>> COMMAND_ARGUMENT_TYPES = DeferredRegister.create(Registry.COMMAND_ARGUMENT_TYPE_REGISTRY, "forge");
private static final DeferredRegister<Codec<? extends BiomeModifier>> BIOME_MODIFIER_SERIALIZERS = DeferredRegister.create(ForgeRegistries.Keys.BIOME_MODIFIER_SERIALIZERS, "forge");
private static final DeferredRegister<Codec<? extends StructureModifier>> STRUCTURE_MODIFIER_SERIALIZERS = DeferredRegister.create(ForgeRegistries.Keys.STRUCTURE_MODIFIER_SERIALIZERS, "forge");
private static final DeferredRegister<HolderSetType> HOLDER_SET_TYPES = DeferredRegister.create(ForgeRegistries.Keys.HOLDER_SET_TYPES, "forge");
@SuppressWarnings({ "unchecked", "rawtypes" })
private static final RegistryObject<EnumArgument.Info> ENUM_COMMAND_ARGUMENT_TYPE = COMMAND_ARGUMENT_TYPES.register("enum", () ->
@@ -212,6 +222,27 @@ public class ForgeMod
*/
public static final RegistryObject<Codec<NoneStructureModifier>> NONE_STRUCTURE_MODIFIER_TYPE = STRUCTURE_MODIFIER_SERIALIZERS.register("none", () -> Codec.unit(NoneStructureModifier.INSTANCE));
/**
* Stock holder set type that represents any/all values in a registry. Can be used in a holderset object with {@code { "type": "forge:any" }}
*/
public static final RegistryObject<HolderSetType> ANY_HOLDER_SET = HOLDER_SET_TYPES.register("any", () -> AnyHolderSet::codec);
/**
* Stock holder set type that represents an intersection of other holdersets. Can be used in a holderset object with {@code { "type": "forge:and", "values": [list of holdersets] }}
*/
public static final RegistryObject<HolderSetType> AND_HOLDER_SET = HOLDER_SET_TYPES.register("and", () -> AndHolderSet::codec);
/**
* Stock holder set type that represents a union of other holdersets. Can be used in a holderset object with {@code { "type": "forge:or", "values": [list of holdersets] }}
*/
public static final RegistryObject<HolderSetType> OR_HOLDER_SET = HOLDER_SET_TYPES.register("or", () -> OrHolderSet::codec);
/**
* <p>Stock holder set type that represents all values in a registry except those in another given set.
* Can be used in a holderset object with {@code { "type": "forge:not", "value": holderset }}</p>
*/
public static final RegistryObject<HolderSetType> NOT_HOLDER_SET = HOLDER_SET_TYPES.register("not", () -> NotHolderSet::codec);
private static final DeferredRegister<FluidType> VANILLA_FLUID_TYPES = DeferredRegister.create(ForgeRegistries.Keys.FLUID_TYPES, "minecraft");
public static final RegistryObject<FluidType> EMPTY_TYPE = VANILLA_FLUID_TYPES.register("empty", () ->
@@ -418,6 +449,7 @@ public class ForgeMod
COMMAND_ARGUMENT_TYPES.register(modEventBus);
BIOME_MODIFIER_SERIALIZERS.register(modEventBus);
STRUCTURE_MODIFIER_SERIALIZERS.register(modEventBus);
HOLDER_SET_TYPES.register(modEventBus);
VANILLA_FLUID_TYPES.register(modEventBus);
MinecraftForge.EVENT_BUS.addListener(this::serverStopping);
MinecraftForge.EVENT_BUS.addListener(this::missingSoundMapping);
@@ -433,6 +465,7 @@ public class ForgeMod
MinecraftForge.EVENT_BUS.addListener(VillagerTradingManager::loadTrades);
MinecraftForge.EVENT_BUS.register(MinecraftForge.INTERNAL_HANDLER);
MinecraftForge.EVENT_BUS.addListener(this::mappingChanged);
MinecraftForge.EVENT_BUS.addListener(this::registerPermissionNodes);
ForgeRegistries.ITEMS.tags().addOptionalTagDefaults(Tags.Items.ENCHANTING_FUELS, Set.of(ForgeRegistries.ITEMS.getDelegateOrThrow(Items.LAPIS_LAZULI)));
}
@@ -574,4 +607,12 @@ public class ForgeMod
event.register(Registry.LOOT_ITEM_REGISTRY, new ResourceLocation("forge:loot_table_id"), () -> LootTableIdCondition.LOOT_TABLE_ID);
event.register(Registry.LOOT_ITEM_REGISTRY, new ResourceLocation("forge:can_tool_perform_action"), () -> CanToolPerformAction.LOOT_CONDITION_TYPE);
}
public static final PermissionNode<Boolean> USE_SELECTORS_PERMISSION = new PermissionNode<>("forge", "use_entity_selectors",
PermissionTypes.BOOLEAN, (player, uuid, contexts) -> player != null && player.hasPermissions(Commands.LEVEL_GAMEMASTERS));
public void registerPermissionNodes(PermissionGatherEvent.Nodes event)
{
event.addNodes(USE_SELECTORS_PERMISSION);
}
}
@@ -26,7 +26,7 @@ public class MinecraftForge
* ORE_GEN_BUS for ore gen events
* EVENT_BUS for everything else
*/
public static final IEventBus EVENT_BUS = BusBuilder.builder().startShutdown().build();
public static final IEventBus EVENT_BUS = BusBuilder.builder().startShutdown().useModLauncher().build();
static final ForgeInternalHandler INTERNAL_HANDLER = new ForgeInternalHandler();
private static final Logger LOGGER = LogManager.getLogger();
@@ -9,6 +9,7 @@ import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.network.Connection;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
@@ -174,4 +175,15 @@ public interface IForgeBlockEntity extends ICapabilitySerializable<CompoundTag>
{
return ModelData.EMPTY;
}
/**
* Returns whether this {@link BlockEntity} has custom outline rendering behavior.
*
* @param player the local player currently viewing this {@code BlockEntity}
* @return {@code true} to enable outline processing
*/
default boolean hasCustomOutlineRendering(Player player)
{
return false;
}
}
@@ -12,6 +12,7 @@ import net.minecraft.sounds.SoundEvent;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.attributes.AttributeInstance;
import net.minecraft.world.entity.boss.enderdragon.EnderDragon;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.entity.Entity;
@@ -410,4 +411,17 @@ public interface IForgeEntity extends ICapabilitySerializable<CompoundTag>
{
return type.getSound(self(), action);
}
/**
* Returns whether this {@link Entity} has custom outline rendering behavior which does
* not use the existing automatic outline rendering based on {@link Entity#isCurrentlyGlowing()}
* and the entity's team color.
*
* @param player the local player currently viewing this {@code Entity}
* @return {@code true} to enable outline processing
*/
default boolean hasCustomOutlineRendering(Player player)
{
return false;
}
}
@@ -0,0 +1,26 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.common.extensions;
public interface IForgeHolderSet<T>
{
/**
* <p>Adds a callback to run when this holderset's contents invalidate (i.e. because tags were rebound).</p>
*
* <p>The intended usage and use case is with composite holdersets that need to cache sets/list based on other
* holdersets, which may be mutable (because they are tag-based or themselves composite holdersets).
* Composite holdersets should use this to add callbacks to each of their component holdersets when constructed.</p>
*
* @param runnable Runnable to invoke when this component holderset's contents are no longer valid.
* This runnable should only clear caches and allow them to be lazily reevaluated later,
* as not all tag holdersets may have been rebound when this is called.
* This runnable should also invalidate all of the caller's listeners.
*/
default public void addInvalidationListener(Runnable runnable)
{
// noop by default, mutable/composite holdersets must override
}
}
@@ -81,8 +81,6 @@ public class FakePlayer extends ServerPlayer
this.connection = new FakePlayerNetHandler(level.getServer(), this);
}
@Override public Vec3 position() { return new Vec3(0, 0, 0); }
@Override public BlockPos blockPosition() { return BlockPos.ZERO; }
@Override public void displayClientMessage(Component chatComponent, boolean actionBar) { }
@Override public void awardStat(Stat stat, int amount) { }
@Override public boolean isInvulnerableTo(DamageSource source) { return true; }
@@ -1,3 +1,8 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.common.world;
import net.minecraft.world.level.levelgen.structure.BoundingBox;
@@ -14,7 +14,7 @@ import org.jetbrains.annotations.Nullable;
/**
*
* AnvilUpdateEvent is fired when the inputs (either input stack, or the name) to an anvil are changed. <br>
* AnvilUpdateEvent is fired whenever the input stacks (left or right) or the name in an anvil changed. <br>
* It is called from {@link AnvilMenu#createResult()}. <br>
* If the event is canceled, vanilla behavior will not run, and the output will be set to {@link ItemStack#EMPTY}. <br>
* If the event is not canceled, but the output is not empty, it will set the output and not run vanilla behavior. <br>
@@ -131,7 +131,7 @@ public class LevelEvent extends Event
*
* <p>If an entry is added to the list, it needs to be a globally unique instance.</p>
*
* The event is called in {@link net.minecraft.world.level.NaturalSpawner#getRandomSpawnMobAt(ServerLevel,
* The event is called in {@link net.minecraft.world.level.NaturalSpawner#mobsAt(ServerLevel,
* StructureManager, ChunkGenerator, MobCategory, RandomSource, BlockPos)}.</p>
*
* <p>This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.
@@ -5,83 +5,24 @@
package net.minecraftforge.network;
import it.unimi.dsi.fastutil.objects.Reference2ReferenceArrayMap;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.protocol.login.ServerboundCustomQueryPacket;
import net.minecraft.network.protocol.login.ClientboundCustomQueryPacket;
import net.minecraft.network.protocol.game.ServerboundCustomPayloadPacket;
import net.minecraft.network.protocol.game.ClientboundCustomPayloadPacket;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.fml.unsafe.UnsafeHacks;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.jetbrains.annotations.Nullable;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
public interface ICustomPacket<T extends Packet<?>> {
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
enum Fields {
CPACKETCUSTOMPAYLOAD(ServerboundCustomPayloadPacket.class),
SPACKETCUSTOMPAYLOAD(ClientboundCustomPayloadPacket.class),
CPACKETCUSTOMLOGIN(ServerboundCustomQueryPacket.class),
SPACKETCUSTOMLOGIN(ClientboundCustomQueryPacket.class),
;
/**
* Returns a unsafe reference to this packet's internal data.
* Any modifications to this buffer will be reflected in the main buffer.
*/
@Nullable
FriendlyByteBuf getInternalData();
static final Reference2ReferenceArrayMap<Class<?>, Fields> lookup;
static {
lookup = Stream.of(values()).
collect(Collectors.toMap(Fields::getClazz, Function.identity(), (m1, m2)->m1, Reference2ReferenceArrayMap::new));
}
ResourceLocation getName();
private final Class<?> clazz;
final Optional<Field> data;
final Optional<Field> channel;
final Optional<Field> index;
Fields(Class<?> customPacketClass)
{
this.clazz = customPacketClass;
Field[] fields = customPacketClass.getDeclaredFields();
data = Arrays.stream(fields).filter(f-> !Modifier.isStatic(f.getModifiers()) && f.getType() == FriendlyByteBuf.class).findFirst();
channel = Arrays.stream(fields).filter(f->!Modifier.isStatic(f.getModifiers()) && f.getType() == ResourceLocation.class).findFirst();
index = Arrays.stream(fields).filter(f->!Modifier.isStatic(f.getModifiers()) && f.getType() == int.class).findFirst();
}
private Class<?> getClazz()
{
return clazz;
}
}
default FriendlyByteBuf getInternalData() {
return Fields.lookup.get(this.getClass()).data.map(f->UnsafeHacks.<FriendlyByteBuf>getField(f, this)).orElse(null);
}
default ResourceLocation getName() {
return Fields.lookup.get(this.getClass()).channel.map(f->UnsafeHacks.<ResourceLocation>getField(f, this)).orElse(LoginWrapper.WRAPPER);
}
default int getIndex() {
return Fields.lookup.get(this.getClass()).index.map(f->UnsafeHacks.getIntField(f, this)).orElse(Integer.MIN_VALUE);
}
default void setData(FriendlyByteBuf buffer) {
Fields.lookup.get(this.getClass()).data.ifPresent(f->UnsafeHacks.setField(f, this, buffer));
}
default void setName(ResourceLocation channelName) {
Fields.lookup.get(this.getClass()).channel.ifPresent(f->UnsafeHacks.setField(f, this, channelName));
}
default void setIndex(int index) {
Fields.lookup.get(this.getClass()).index.ifPresent(f->UnsafeHacks.setIntField(f, this, index));
}
int getIndex();
default NetworkDirection getDirection() {
return NetworkDirection.directionFor(this.getClass());
@@ -13,6 +13,7 @@ import net.minecraftforge.network.event.EventNetworkChannel;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.ApiStatus;
/**
* Wrapper for custom login packets. Transforms unnamed login channel messages into channels dispatched the same
@@ -21,7 +22,8 @@ import org.apache.logging.log4j.Logger;
public class LoginWrapper
{
private static final Logger LOGGER = LogManager.getLogger();
static final ResourceLocation WRAPPER = new ResourceLocation("fml:loginwrapper");
@ApiStatus.Internal
public static final ResourceLocation WRAPPER = new ResourceLocation("fml:loginwrapper");
private EventNetworkChannel wrapperChannel;
LoginWrapper() {
@@ -14,7 +14,6 @@ import net.minecraft.network.protocol.game.ServerboundCustomPayloadPacket;
import net.minecraft.network.protocol.game.ClientboundCustomPayloadPacket;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.fml.LogicalSide;
import net.minecraftforge.fml.unsafe.UnsafeHacks;
import org.apache.commons.lang3.tuple.Pair;
import java.util.function.BiFunction;
@@ -25,15 +24,16 @@ import java.util.stream.Stream;
public enum NetworkDirection
{
PLAY_TO_SERVER(NetworkEvent.ClientCustomPayloadEvent::new, LogicalSide.CLIENT, ServerboundCustomPayloadPacket.class, 1),
PLAY_TO_CLIENT(NetworkEvent.ServerCustomPayloadEvent::new, LogicalSide.SERVER, ClientboundCustomPayloadPacket.class, 0),
LOGIN_TO_SERVER(NetworkEvent.ClientCustomPayloadLoginEvent::new, LogicalSide.CLIENT, ServerboundCustomQueryPacket.class, 3),
LOGIN_TO_CLIENT(NetworkEvent.ServerCustomPayloadLoginEvent::new, LogicalSide.SERVER, ClientboundCustomQueryPacket.class, 2);
PLAY_TO_SERVER(NetworkEvent.ClientCustomPayloadEvent::new, LogicalSide.CLIENT, ServerboundCustomPayloadPacket.class, 1, (d, i, n) -> new ServerboundCustomPayloadPacket(n, d)),
PLAY_TO_CLIENT(NetworkEvent.ServerCustomPayloadEvent::new, LogicalSide.SERVER, ClientboundCustomPayloadPacket.class, 0, (d, i, n) -> new ClientboundCustomPayloadPacket(n, d)),
LOGIN_TO_SERVER(NetworkEvent.ClientCustomPayloadLoginEvent::new, LogicalSide.CLIENT, ServerboundCustomQueryPacket.class, 3, (d, i, n) -> new ServerboundCustomQueryPacket(i, d)),
LOGIN_TO_CLIENT(NetworkEvent.ServerCustomPayloadLoginEvent::new, LogicalSide.SERVER, ClientboundCustomQueryPacket.class, 2, (d, i, n) -> new ClientboundCustomQueryPacket(i, n, d));
private final BiFunction<ICustomPacket<?>, Supplier<NetworkEvent.Context>, NetworkEvent> eventSupplier;
private final LogicalSide logicalSide;
private final Class<? extends Packet> packetClass;
private final int otherWay;
private final Factory factory;
private static final Reference2ReferenceArrayMap<Class<? extends Packet>, NetworkDirection> packetLookup;
@@ -42,12 +42,13 @@ public enum NetworkDirection
collect(Collectors.toMap(NetworkDirection::getPacketClass, Function.identity(), (m1,m2)->m1, Reference2ReferenceArrayMap::new));
}
NetworkDirection(BiFunction<ICustomPacket<?>, Supplier<NetworkEvent.Context>, NetworkEvent> eventSupplier, LogicalSide logicalSide, Class<? extends Packet> clazz, int i)
private NetworkDirection(BiFunction<ICustomPacket<?>, Supplier<NetworkEvent.Context>, NetworkEvent> eventSupplier, LogicalSide logicalSide, Class<? extends Packet> clazz, int i, Factory factory)
{
this.eventSupplier = eventSupplier;
this.logicalSide = logicalSide;
this.packetClass = clazz;
this.otherWay = i;
this.factory = factory;
}
private Class<? extends Packet> getPacketClass() {
@@ -75,10 +76,10 @@ public enum NetworkDirection
@SuppressWarnings("unchecked")
public <T extends Packet<?>> ICustomPacket<T> buildPacket(Pair<FriendlyByteBuf,Integer> packetData, ResourceLocation channelName)
{
ICustomPacket<T> packet = (ICustomPacket<T>)UnsafeHacks.newInstance(getPacketClass());
packet.setName(channelName);
packet.setData(packetData.getLeft());
packet.setIndex(packetData.getRight());
return packet;
return this.factory.create(packetData.getLeft(), packetData.getRight(), channelName);
}
private interface Factory<T extends Packet<?>> {
ICustomPacket<T> create(FriendlyByteBuf data, Integer index, ResourceLocation channelName);
}
}
@@ -36,7 +36,7 @@ public class NetworkInstance
this.networkProtocolVersion = networkProtocolVersion.get();
this.clientAcceptedVersions = clientAcceptedVersions;
this.serverAcceptedVersions = serverAcceptedVersions;
this.networkEventBus = BusBuilder.builder().setExceptionHandler(this::handleError).build();
this.networkEventBus = BusBuilder.builder().setExceptionHandler(this::handleError).useModLauncher().build();
}
private void handleError(IEventBus iEventBus, Event event, IEventListener[] iEventListeners, int i, Throwable throwable)
@@ -135,7 +135,7 @@ public class IndexedMessageCodec
}
void consume(FriendlyByteBuf payload, int payloadIndex, Supplier<NetworkEvent.Context> context) {
if (payload == null) {
if (payload == null || !payload.isReadable()) {
LOGGER.error(SIMPLENET, "Received empty payload on channel {}", Optional.ofNullable(networkInstance).map(NetworkInstance::getChannelName).map(Objects::toString).orElse("MISSING CHANNEL"));
if (!HandshakeHandler.packetNeedsResponse(context.get().getNetworkManager(), payloadIndex))
{
@@ -26,6 +26,7 @@ public class ForgeDeferredRegistriesSetup
ForgeRegistries.DEFERRED_BIOME_MODIFIERS.register(modEventBus);
ForgeRegistries.DEFERRED_STRUCTURE_MODIFIER_SERIALIZERS.register(modEventBus);
ForgeRegistries.DEFERRED_STRUCTURE_MODIFIERS.register(modEventBus);
ForgeRegistries.DEFERRED_HOLDER_SET_TYPES.register(modEventBus);
setup = true;
}
@@ -45,6 +45,7 @@ import net.minecraftforge.common.Tags;
import net.minecraftforge.common.loot.IGlobalLootModifier;
import net.minecraftforge.common.world.BiomeModifier;
import net.minecraftforge.fluids.FluidType;
import net.minecraftforge.registries.holdersets.HolderSetType;
import java.util.function.Supplier;
import net.minecraftforge.common.world.StructureModifier;
@@ -127,6 +128,12 @@ public class ForgeRegistries
* Use {@link Keys#FLUID_TYPES} to create a {@link DeferredRegister}.
*/
public static final Supplier<IForgeRegistry<FluidType>> FLUID_TYPES = DEFERRED_FLUID_TYPES.makeRegistry(GameData::getFluidTypeRegistryBuilder);
static final DeferredRegister<HolderSetType> DEFERRED_HOLDER_SET_TYPES = DeferredRegister.create(Keys.HOLDER_SET_TYPES, "forge");
/**
* Calling {@link Supplier#get()} before {@link NewRegistryEvent} is fired will result in a null registry returned.
* Use {@link Keys#HOLDER_SET_TYPES} to create a {@link DeferredRegister}.
*/
public static final Supplier<IForgeRegistry<HolderSetType>> HOLDER_SET_TYPES = DEFERRED_HOLDER_SET_TYPES.makeRegistry(GameData::getHolderSetTypeRegistryBuilder);
// Custom forge datapack registries
static final DeferredRegister<BiomeModifier> DEFERRED_BIOME_MODIFIERS = DeferredRegister.create(Keys.BIOME_MODIFIERS, "forge");
@@ -175,6 +182,7 @@ public class ForgeRegistries
public static final ResourceKey<Registry<Codec<? extends BiomeModifier>>> BIOME_MODIFIER_SERIALIZERS = key("forge:biome_modifier_serializers");
public static final ResourceKey<Registry<Codec<? extends StructureModifier>>> STRUCTURE_MODIFIER_SERIALIZERS = key("forge:structure_modifier_serializers");
public static final ResourceKey<Registry<FluidType>> FLUID_TYPES = key("forge:fluid_type");
public static final ResourceKey<Registry<HolderSetType>> HOLDER_SET_TYPES = key("forge:holder_set_type");
// Forge Dynamic
public static final ResourceKey<Registry<BiomeModifier>> BIOME_MODIFIERS = key("forge:biome_modifier");
@@ -48,6 +48,8 @@ import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.StartupMessageManager;
import net.minecraftforge.fml.util.EnhancedRuntimeException;
import net.minecraftforge.fml.util.thread.EffectiveSide;
import net.minecraftforge.registries.holdersets.HolderSetType;
import org.apache.commons.lang3.Validate;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -164,6 +166,11 @@ public class GameData
{
return makeRegistry(FLUID_TYPES).disableSaving();
}
static RegistryBuilder<HolderSetType> getHolderSetTypeRegistryBuilder()
{
return new RegistryBuilder<HolderSetType>().disableSaving().disableSync();
}
private static <T> RegistryBuilder<T> makeRegistry(ResourceKey<? extends Registry<T>> key)
{
@@ -0,0 +1,80 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.registries.holdersets;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import com.mojang.serialization.Codec;
import net.minecraft.core.Holder;
import net.minecraft.core.HolderSet;
import net.minecraft.core.Registry;
import net.minecraft.resources.HolderSetCodec;
import net.minecraft.resources.ResourceKey;
import net.minecraftforge.common.ForgeMod;
/**
* <p>Holderset that represents an intersection of other holdersets. Json format:</p>
* <pre>
* {
* "type": "forge:and",
* "values":
* [
* // list of sub-holdersets (strings, lists, or objects)
* ]
* }
* </pre>
*/
public class AndHolderSet<T> extends CompositeHolderSet<T>
{
public static <T> Codec<? extends ICustomHolderSet<T>> codec(ResourceKey<? extends Registry<T>> registryKey, Codec<Holder<T>> holderCodec, boolean forceList)
{
return HolderSetCodec.create(registryKey, holderCodec, forceList)
.listOf()
.xmap(AndHolderSet::new, AndHolderSet::getComponents)
.fieldOf("values")
.codec();
}
public AndHolderSet(List<HolderSet<T>> values)
{
super(values);
}
@Override
public HolderSetType type()
{
return ForgeMod.AND_HOLDER_SET.get();
}
@Override
protected Set<Holder<T>> createSet()
{
List<HolderSet<T>> components = this.getComponents();
if (components.size() < 1)
{
return Set.of();
}
if (components.size() == 1)
{
return components.get(0).stream().collect(Collectors.toSet());
}
List<HolderSet<T>> remainingComponents = components.subList(1, components.size());
return components.get(0)
.stream()
.filter(holder -> remainingComponents.stream().allMatch(holderset -> holderset.contains(holder)))
.collect(Collectors.toSet());
}
@Override
public String toString()
{
return "AndSet[" + this.getComponents() + "]";
}
}
@@ -0,0 +1,102 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.registries.holdersets;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Stream;
import com.mojang.datafixers.util.Either;
import com.mojang.serialization.Codec;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.resources.RegistryOps;
import net.minecraft.resources.ResourceKey;
import net.minecraft.tags.TagKey;
import net.minecraft.util.RandomSource;
import net.minecraftforge.common.ForgeMod;
/**
* <p>Holderset that represents all elements of a registry. Json format:</p>
* <pre>
* {
* "type": "forge:any"
* }
* </pre>
*/
public record AnyHolderSet<T>(Registry<T> registry) implements ICustomHolderSet<T>
{
public static <T> Codec<? extends ICustomHolderSet<T>> codec(ResourceKey<? extends Registry<T>> registryKey, Codec<Holder<T>> holderCodec, boolean forceList)
{
return RegistryOps.retrieveRegistry(registryKey)
.xmap(AnyHolderSet::new, AnyHolderSet::registry)
.codec();
}
@Override
public HolderSetType type()
{
return ForgeMod.ANY_HOLDER_SET.get();
}
@Override
public Iterator<Holder<T>> iterator()
{
return this.stream().iterator();
}
@Override
public Stream<Holder<T>> stream()
{
return registry.holders().map(Function.identity());
}
@Override
public int size()
{
return this.registry.size();
}
@Override
public Either<TagKey<T>, List<Holder<T>>> unwrap()
{
return Either.right(this.stream().toList());
}
@Override
public Optional<Holder<T>> getRandomElement(RandomSource random)
{
return this.registry.getRandom(random);
}
@Override
public Holder<T> get(int i)
{
return this.registry.getHolder(i).orElseThrow(() -> new NoSuchElementException("No element " + i + " in registry " + this.registry.key()));
}
@Override
public boolean contains(Holder<T> holder)
{
return holder.unwrapKey().map(this.registry::containsKey).orElse(false);
}
@Override
public boolean isValidInRegistry(Registry<T> registry)
{
return this.registry == registry;
}
@Override
public String toString()
{
return "AnySet(" + this.registry.key() + ")";
}
}
@@ -0,0 +1,164 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.registries.holdersets;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;
import org.jetbrains.annotations.Nullable;
import com.mojang.datafixers.util.Either;
import net.minecraft.core.Holder;
import net.minecraft.core.HolderSet;
import net.minecraft.core.Registry;
import net.minecraft.tags.TagKey;
import net.minecraft.util.RandomSource;
/**
* Composite holdersets have component holdersets and possibly owner holdersets
* (which have this holderset as a component).
* When their component holderset(s) invalidate, they clear any cached data and then
* invalidate their owner holdersets.
*/
public abstract class CompositeHolderSet<T> implements ICustomHolderSet<T>
{
private final List<Runnable> owners = new ArrayList<>();
private final List<HolderSet<T>> components;
@Nullable
private Set<Holder<T>> set = null;
@Nullable
private List<Holder<T>> list = null;
public CompositeHolderSet(List<HolderSet<T>> components)
{
this.components = components;
for (HolderSet<T> holderset : components)
{
holderset.addInvalidationListener(this::invalidate);
}
}
/**
* {@return immutable Set of Holders given this composite holderset's component holdersets}
*/
protected abstract Set<Holder<T>> createSet();
public List<HolderSet<T>> getComponents()
{
return this.components;
}
public Set<Holder<T>> getSet()
{
Set<Holder<T>> thisSet = this.set;
if (thisSet == null)
{
Set<Holder<T>> set = this.createSet();
this.set = set;
return set;
}
else
{
return thisSet;
}
}
public List<Holder<T>> getList()
{
List<Holder<T>> thisList = this.list;
if (thisList == null)
{
List<Holder<T>> list = List.copyOf(this.getSet());
this.list = list;
return list;
}
else
{
return thisList;
}
}
@Override
public void addInvalidationListener(Runnable runnable)
{
this.owners.add(runnable);
}
private void invalidate()
{
this.set = null;
this.list = null;
for (Runnable runnable : this.owners)
{
runnable.run();
}
}
@Override
public Stream<Holder<T>> stream()
{
return this.getList().stream();
}
@Override
public int size()
{
return this.getList().size();
}
@Override
public Either<TagKey<T>, List<Holder<T>>> unwrap()
{
return Either.right(this.getList());
}
@Override
public Optional<Holder<T>> getRandomElement(RandomSource rand)
{
List<Holder<T>> list = this.getList();
int size = list.size();
return size > 0
? Optional.of(list.get(rand.nextInt(size)))
: Optional.empty();
}
@Override
public Holder<T> get(int i)
{
return this.getList().get(i);
}
@Override
public boolean contains(Holder<T> holder)
{
return this.getSet().contains(holder);
}
@Override
public boolean isValidInRegistry(Registry<T> registry)
{
for (HolderSet<T> component : this.components)
{
if (!component.isValidInRegistry(registry))
{
return false;
}
}
return true;
}
@Override
public Iterator<Holder<T>> iterator()
{
return this.getList().iterator();
}
}
@@ -0,0 +1,18 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.registries.holdersets;
import com.mojang.serialization.Codec;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
@FunctionalInterface
public interface HolderSetType
{
<T> Codec<? extends ICustomHolderSet<T>> makeCodec(ResourceKey<? extends Registry<T>> registryKey, Codec<Holder<T>> holderCodec, boolean forceList);
}
@@ -0,0 +1,19 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.registries.holdersets;
import net.minecraft.core.HolderSet;
/**
* Interface for mods' custom holderset types
*/
public interface ICustomHolderSet<T> extends HolderSet<T>
{
/**
* {@return HolderSetType registered to {@link ForgeRegistries.HOLDER_SET_TYPES}}
*/
HolderSetType type();
}
@@ -0,0 +1,164 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.registries.holdersets;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import org.jetbrains.annotations.Nullable;
import com.mojang.datafixers.util.Either;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.core.Holder;
import net.minecraft.core.HolderSet;
import net.minecraft.core.Registry;
import net.minecraft.resources.HolderSetCodec;
import net.minecraft.resources.RegistryOps;
import net.minecraft.resources.ResourceKey;
import net.minecraft.tags.TagKey;
import net.minecraft.util.RandomSource;
import net.minecraftforge.common.ForgeMod;
/**
* <p>Holderset that represents all elements of a registry not present in another holderset.
* forge:exclusion is preferable when the number of allowed elements is small relative to the size of the registry.
* Json format:</p>
* <pre>
* {
* "type": "forge:not",
* "value": "not_this_holderset" // string, list, or object
* }
* </pre>
*/
// this doesn't extend CompositeHolderSet because it doesn't need to cache a set
public class NotHolderSet<T> implements ICustomHolderSet<T>
{
public static <T> Codec<? extends ICustomHolderSet<T>> codec(ResourceKey<? extends Registry<T>> registryKey, Codec<Holder<T>> holderCodec, boolean forceList)
{
return RecordCodecBuilder.<NotHolderSet<T>>create(builder -> builder.group(
RegistryOps.retrieveRegistry(registryKey).forGetter(NotHolderSet::registry),
HolderSetCodec.create(registryKey, holderCodec, forceList).fieldOf("value").forGetter(NotHolderSet::value)
).apply(builder, NotHolderSet::new));
}
private final List<Runnable> owners = new ArrayList<>();
private final Registry<T> registry;
private final HolderSet<T> value;
@Nullable
private List<Holder<T>> list = null;
public Registry<T> registry() { return this.registry; }
public HolderSet<T> value() { return this.value; }
public NotHolderSet(Registry<T> registry, HolderSet<T> value)
{
this.registry = registry;
this.value = value;
this.value.addInvalidationListener(this::invalidate);
}
@Override
public HolderSetType type()
{
return ForgeMod.NOT_HOLDER_SET.get();
}
@Override
public void addInvalidationListener(Runnable runnable)
{
this.owners.add(runnable);
}
@Override
public Iterator<Holder<T>> iterator()
{
return this.getList().iterator();
}
@Override
public Stream<Holder<T>> stream()
{
return this.getList().stream();
}
@Override
public int size()
{
return this.getList().size();
}
@Override
public Either<TagKey<T>, List<Holder<T>>> unwrap()
{
return Either.right(this.getList());
}
@Override
public Optional<Holder<T>> getRandomElement(RandomSource random)
{
List<Holder<T>> list = this.getList();
int size = list.size();
return size > 0
? Optional.of(list.get(random.nextInt(size)))
: Optional.empty();
}
@Override
public Holder<T> get(int i)
{
return this.getList().get(i);
}
@Override
public boolean contains(Holder<T> holder)
{
return !this.value.contains(holder);
}
@Override
public boolean isValidInRegistry(Registry<T> registry)
{
return this.registry == registry;
}
@Override
public String toString()
{
return "NotSet(" + this.value + ")";
}
private List<Holder<T>> getList()
{
List<Holder<T>> thisList = this.list;
if (thisList == null)
{
List<Holder<T>> list = this.registry.holders()
.filter(holder -> !this.value.contains(holder))
.map(holder -> (Holder<T>)holder)
.toList();
this.list = list;
return list;
}
else
{
return thisList;
}
}
private void invalidate()
{
this.list = null;
for (Runnable runnable : this.owners)
{
runnable.run();
}
}
}
@@ -0,0 +1,66 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.registries.holdersets;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import com.mojang.serialization.Codec;
import net.minecraft.core.Holder;
import net.minecraft.core.HolderSet;
import net.minecraft.core.Registry;
import net.minecraft.resources.HolderSetCodec;
import net.minecraft.resources.ResourceKey;
import net.minecraftforge.common.ForgeMod;
/**
* <p>Holderset that represents a union of other holdersets. Json format:</p>
* <pre>
* {
* "type": "forge:or",
* "values":
* [
* // list of sub-holdersets (strings, lists, or objects)
* ]
* }
* </pre>
*/
public class OrHolderSet<T> extends CompositeHolderSet<T>
{
public static <T> Codec<? extends ICustomHolderSet<T>> codec(ResourceKey<? extends Registry<T>> registryKey, Codec<Holder<T>> holderCodec, boolean forceList)
{
return HolderSetCodec.create(registryKey, holderCodec, forceList)
.listOf()
.xmap(OrHolderSet::new, OrHolderSet::getComponents)
.fieldOf("values")
.codec();
}
public OrHolderSet(List<HolderSet<T>> values)
{
super(values);
}
@Override
public HolderSetType type()
{
return ForgeMod.OR_HOLDER_SET.get();
}
@Override
protected Set<Holder<T>> createSet()
{
return this.getComponents().stream().flatMap(HolderSet::stream).collect(Collectors.toSet());
}
@Override
public String toString()
{
return "OrSet[" + this.getComponents() + "]";
}
}
@@ -167,6 +167,7 @@ public class PathPackResources extends AbstractPackResources
{
Path root = resolve(type.getDirectory());
return Files.walk(root, 1)
.filter(Files::isDirectory)
.map(path -> root.relativize(path))
.filter(path -> path.getNameCount() > 0) // skip the root entry
.map(p -> p.toString().replaceAll("/$", "")) // remove the trailing slash, if present
@@ -77,6 +77,7 @@ public net.minecraft.client.particle.ParticleEngine m_107381_(Lnet/minecraft/cor
public net.minecraft.client.particle.ParticleEngine$SpriteParticleRegistration
public net.minecraft.client.player.LocalPlayer m_8088_()I # getPermissionLevel
public net.minecraft.client.renderer.GameRenderer m_109128_(Lnet/minecraft/resources/ResourceLocation;)V # loadEffect
public net.minecraft.client.renderer.LevelRenderer m_109817_()Z # shouldShowEntityOutlines
protected-f net.minecraft.client.renderer.RenderStateShard f_110131_ # setupState
public net.minecraft.client.renderer.RenderStateShard$BooleanStateShard
public net.minecraft.client.renderer.RenderStateShard$CullStateShard
@@ -268,6 +269,7 @@ public-f net.minecraft.data.tags.TagsProvider m_6055_()Ljava/lang/String; # getN
public net.minecraft.data.tags.TagsProvider$TagAppender f_126569_ # registry
public net.minecraft.gametest.framework.GameTestServer <init>(Ljava/lang/Thread;Lnet/minecraft/world/level/storage/LevelStorageSource$LevelStorageAccess;Lnet/minecraft/server/packs/repository/PackRepository;Lnet/minecraft/server/WorldStem;Ljava/util/Collection;Lnet/minecraft/core/BlockPos;)V # constructor
public net.minecraft.network.protocol.status.ClientboundStatusResponsePacket f_134885_ # GSON
public net.minecraft.resources.RegistryOps f_206806_ # registryAccess
public net.minecraft.resources.ResourceLocation m_135835_(C)Z # validNamespaceChar
public net.minecraft.resources.ResourceLocation m_135841_(Ljava/lang/String;)Z # isValidPath
public net.minecraft.resources.ResourceLocation m_135843_(Ljava/lang/String;)Z # isValidNamespace
+2 -1
View File
@@ -2,6 +2,7 @@ com/mojang/blaze3d/vertex/VertexConsumer.putBulkData(Lcom/mojang/blaze3d/vertex/
net/minecraft/advancements/Advancement$Builder.fromJson(Lcom/google/gson/JsonObject;Lnet/minecraft/advancements/critereon/DeserializationContext;Lnet/minecraftforge/common/crafting/conditions/ICondition$IContext;)Lnet/minecraft/advancements/Advancement$Builder;=|p_138381_,p_138382_,context
net/minecraft/client/Options.processOptionsForge(Lnet/minecraft/client/Options$FieldAccess;)V=|p_168428_
net/minecraft/client/gui/screens/MenuScreens.getScreenFactory(Lnet/minecraft/world/inventory/MenuType;Lnet/minecraft/client/Minecraft;ILnet/minecraft/network/chat/Component;)Ljava/util/Optional;=|p_96202_,p_96203_,p_96204_,p_96205_
net/minecraft/client/gui/screens/inventory/InventoryScreen.renderEntityInInventoryRaw(IIIFFLnet/minecraft/world/entity/LivingEntity;)V=|p_98851_,p_98852_,p_98853_,angleXComponent,angleYComponent,p_98856_
net/minecraft/client/gui/screens/worldselection/WorldOpenFlows.doLoadLevel(Lnet/minecraft/client/gui/screens/Screen;Ljava/lang/String;ZZZ)V=|p_233146_,p_233147_,p_233148_,p_233149_,confirmExperimentalWarning
net/minecraft/client/renderer/ScreenEffectRenderer.getOverlayBlock(Lnet/minecraft/world/entity/player/Player;)Lorg/apache/commons/lang3/tuple/Pair;=|p_110717_
net/minecraft/client/renderer/ScreenEffectRenderer.renderFluid(Lnet/minecraft/client/Minecraft;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/resources/ResourceLocation;)V=|p_110726_,p_110727_,texture
@@ -14,7 +15,7 @@ net/minecraft/client/renderer/block/ModelBlockRenderer.renderModel(Lcom/mojang/b
net/minecraft/client/renderer/block/ModelBlockRenderer.tesselateBlock(Lnet/minecraft/world/level/BlockAndTintGetter;Lnet/minecraft/client/resources/model/BakedModel;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/core/BlockPos;Lcom/mojang/blaze3d/vertex/PoseStack;Lcom/mojang/blaze3d/vertex/VertexConsumer;ZLnet/minecraft/util/RandomSource;JILnet/minecraftforge/client/model/data/ModelData;Lnet/minecraft/client/renderer/RenderType;)V=|p_111048_,p_111049_,p_111050_,p_111051_,p_111052_,p_111053_,p_111054_,p_111055_,p_111056_,p_111057_,modelData,renderType
net/minecraft/client/renderer/block/ModelBlockRenderer.tesselateWithAO(Lnet/minecraft/world/level/BlockAndTintGetter;Lnet/minecraft/client/resources/model/BakedModel;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/core/BlockPos;Lcom/mojang/blaze3d/vertex/PoseStack;Lcom/mojang/blaze3d/vertex/VertexConsumer;ZLnet/minecraft/util/RandomSource;JILnet/minecraftforge/client/model/data/ModelData;Lnet/minecraft/client/renderer/RenderType;)V=|p_111079_,p_111080_,p_111081_,p_111082_,p_111083_,p_111084_,p_111085_,p_111086_,p_111087_,p_111088_,modelData,renderType
net/minecraft/client/renderer/block/ModelBlockRenderer.tesselateWithoutAO(Lnet/minecraft/world/level/BlockAndTintGetter;Lnet/minecraft/client/resources/model/BakedModel;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/core/BlockPos;Lcom/mojang/blaze3d/vertex/PoseStack;Lcom/mojang/blaze3d/vertex/VertexConsumer;ZLnet/minecraft/util/RandomSource;JILnet/minecraftforge/client/model/data/ModelData;Lnet/minecraft/client/renderer/RenderType;)V=|p_111091_,p_111092_,p_111093_,p_111094_,p_111095_,p_111096_,p_111097_,p_111098_,p_111099_,p_111100_,modelData,renderType
net/minecraft/client/renderer/block/model/BlockElementFace.<init>(Lnet/minecraft/core/Direction;ILjava/lang/String;Lnet/minecraft/client/renderer/block/model/BlockFaceUV;Z)V=|p_111359_,p_111360_,p_111361_,p_111362_,emissive
net/minecraft/client/renderer/block/model/BlockElementFace.<init>(Lnet/minecraft/core/Direction;ILjava/lang/String;Lnet/minecraft/client/renderer/block/model/BlockFaceUV;I)V=|p_111359_,p_111360_,p_111361_,p_111362_,emissivity
net/minecraft/client/renderer/block/model/BlockModel.bakeVanilla(Lnet/minecraft/client/resources/model/ModelBakery;Lnet/minecraft/client/renderer/block/model/BlockModel;Ljava/util/function/Function;Lnet/minecraft/client/resources/model/ModelState;Lnet/minecraft/resources/ResourceLocation;ZLnet/minecraftforge/client/RenderTypeGroup;)Lnet/minecraft/client/resources/model/BakedModel;=|p_111450_,p_111451_,p_111452_,p_111453_,p_111454_,p_111455_,renderTypes
net/minecraft/client/renderer/block/model/ItemTransform.<init>(Lcom/mojang/math/Vector3f;Lcom/mojang/math/Vector3f;Lcom/mojang/math/Vector3f;Lcom/mojang/math/Vector3f;)V=|p_111760_,p_111761_,p_111762_,rightRotation
net/minecraft/client/renderer/block/model/ItemTransforms.<init>(Lnet/minecraft/client/renderer/block/model/ItemTransform;Lnet/minecraft/client/renderer/block/model/ItemTransform;Lnet/minecraft/client/renderer/block/model/ItemTransform;Lnet/minecraft/client/renderer/block/model/ItemTransform;Lnet/minecraft/client/renderer/block/model/ItemTransform;Lnet/minecraft/client/renderer/block/model/ItemTransform;Lnet/minecraft/client/renderer/block/model/ItemTransform;Lnet/minecraft/client/renderer/block/model/ItemTransform;Lcom/google/common/collect/ImmutableMap;)V=|p_111798_,p_111799_,p_111800_,p_111801_,p_111802_,p_111803_,p_111804_,p_111805_,moddedTransforms
@@ -0,0 +1,66 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.debug.client;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.ColorResolver;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.material.Material;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.RegisterColorHandlersEvent;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.registries.RegistryObject;
/**
* This mod tests custom {@link ColorResolver ColorResolvers} using {@link RegisterColorHandlersEvent.ColorResolvers}.
* To test, place the registered test block, it should be tinted blue in biomes with precipitation and red in others.
* The color should blend according to the biome blend setting.
*/
@Mod(CustomColorResolverTest.MOD_ID)
public class CustomColorResolverTest
{
static final String MOD_ID = "custom_color_resolver_test";
private static final DeferredRegister<Item> ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, MOD_ID);
private static final DeferredRegister<Block> BLOCKS = DeferredRegister.create(ForgeRegistries.BLOCKS, MOD_ID);
private static final RegistryObject<Block> BLOCK = BLOCKS.register("test_block", () -> new Block(BlockBehaviour.Properties.of(Material.STONE)));
public CustomColorResolverTest()
{
final IEventBus modBus = FMLJavaModLoadingContext.get().getModEventBus();
ITEMS.register(modBus);
BLOCKS.register(modBus);
ITEMS.register("test_block", () -> new BlockItem(BLOCK.get(), new Item.Properties()));
}
@Mod.EventBusSubscriber(value = Dist.CLIENT, modid=MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD)
private static class ClientHandler
{
private static final ColorResolver COLOR_RESOLVER = (biome, x, z) -> biome.getPrecipitation() == Biome.Precipitation.NONE ? 0xFF0000 : 0x0000FF;
@SubscribeEvent
static void registerColorResolver(RegisterColorHandlersEvent.ColorResolvers event)
{
event.register(COLOR_RESOLVER);
}
@SubscribeEvent
static void registerBlockColor(RegisterColorHandlersEvent.Block event)
{
event.register(((state, btGetter, pos, tintIndex) -> btGetter == null || pos == null ? 0 : btGetter.getBlockTint(pos, COLOR_RESOLVER)), BLOCK.get());
}
}
}
@@ -7,6 +7,7 @@ package net.minecraftforge.debug.client;
import net.minecraft.client.Minecraft;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.world.effect.MobEffects;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.ScreenEvent;
import net.minecraftforge.common.MinecraftForge;
@@ -49,10 +50,15 @@ public class PotionSizeEventTest
if (player.getActiveEffects().size() <= 3)
{
event.setCompact(true); // Force compact mode for 3 or less active effects
} else
}
else
{
event.setCompact(false); // Force classic mode for 4 or more active effects
}
if (player.hasEffect(MobEffects.MOVEMENT_SLOWDOWN))
{
event.addHorizontalOffset(20); // Move the effect rendering to the right when slowness is enabled
}
}
}
}
@@ -0,0 +1,79 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.debug.client.rendering;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.BufferBuilder;
import com.mojang.blaze3d.vertex.BufferUploader;
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.blaze3d.vertex.Tesselator;
import com.mojang.blaze3d.vertex.VertexFormat;
import net.minecraft.client.gui.Font;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.util.Mth;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.IItemDecorator;
import net.minecraftforge.client.ItemDecoratorHandler;
import net.minecraftforge.client.event.RegisterItemDecorationsEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import net.minecraftforge.registries.ForgeRegistries;
@Mod(CustomItemDecorationsTest.MOD_ID)
public class CustomItemDecorationsTest
{
public static final String MOD_ID = "custom_item_decorations_test";
private static final boolean ENABLED = true;
public CustomItemDecorationsTest() { }
@Mod.EventBusSubscriber(modid = CustomItemDecorationsTest.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT)
public static class ClientEvents
{
@SubscribeEvent
public static void onRegisterItemDecorations(final RegisterItemDecorationsEvent event)
{
if (ENABLED)
event.register(Items.EGG, new StackSizeDurabilityBar());
}
}
private static class StackSizeDurabilityBar implements IItemDecorator
{
@Override
public boolean render(Font font, ItemStack stack, int xOffset, int yOffset, float blitOffset)
{
RenderSystem.disableTexture();
RenderSystem.disableBlend();
Tesselator tesselator = Tesselator.getInstance();
BufferBuilder bufferbuilder = tesselator.getBuilder();
float f = Math.max(0.0F, (stack.getMaxStackSize() - (float)stack.getCount()) / stack.getMaxStackSize());
int i = Math.round(13.0F - (float)stack.getCount() * 13.0F / stack.getMaxStackSize());
int j = Mth.hsvToRgb(f / 3.0F,1f,1f);
fillRect(bufferbuilder, xOffset + 2, yOffset, blitOffset + 189, 13, 2, 0, 0, 0);
fillRect(bufferbuilder, xOffset + 2, yOffset, blitOffset + 190, i, 1, j >> 16 & 255, j >> 8 & 255, j & 255);
RenderSystem.enableBlend();
RenderSystem.enableTexture();
return true;
}
private static void fillRect(BufferBuilder pRenderer, int pX, int pY, float pZ, int pWidth, int pHeight, int pRed, int pGreen, int pBlue)
{
RenderSystem.setShader(GameRenderer::getPositionColorShader);
pRenderer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR);
pRenderer.vertex(pX, pY, pZ).color(pRed, pGreen, pBlue, 255).endVertex();
pRenderer.vertex(pX, pY + pHeight, pZ).color(pRed, pGreen, pBlue, 255).endVertex();
pRenderer.vertex(pX + pWidth, pY + pHeight, pZ).color(pRed, pGreen, pBlue, 255).endVertex();
pRenderer.vertex(pX + pWidth, pY, pZ).color(pRed, pGreen, pBlue, 255).endVertex();
BufferUploader.drawWithShader(pRenderer.end());
}
}
}
@@ -0,0 +1,109 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.debug.entity.player;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.model.HumanoidModel;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.HumanoidArm;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.food.FoodProperties;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.UseAnim;
import net.minecraftforge.client.extensions.common.IClientItemExtensions;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.registries.RegistryObject;
import java.util.function.Consumer;
/**
* Tests if item usage animation system works as intended. `item_use_animation_test:thing` is edible item with custom usage animation made with this system.
* In game, use `/give @s item_use_animation_test:thing 1` to obtain test item
* When you try to eat it, your arm in 3d person should start swinging really fast.
* And item in your hand will go down little.
*/
@Mod(ItemUseAnimationTest.MOD_ID)
public class ItemUseAnimationTest
{
public static final String MOD_ID = "item_use_animation_test";
private static final DeferredRegister<Item> ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, MOD_ID);
private static final RegistryObject<Item> THING = ITEMS.register("thing", () -> new ThingItem(new Item.Properties().tab(CreativeModeTab.TAB_TOOLS).food(new FoodProperties.Builder().nutrition(4).alwaysEat().build())));
public ItemUseAnimationTest()
{
ITEMS.register(FMLJavaModLoadingContext.get().getModEventBus());
}
private static class ThingItem extends Item
{
public ThingItem(Item.Properties props)
{
super(props);
}
@Override
public UseAnim getUseAnimation(ItemStack stack)
{
return UseAnim.CUSTOM;
}
@Override
public void initializeClient(Consumer<IClientItemExtensions> consumer)
{
consumer.accept(new IClientItemExtensions()
{
private static final HumanoidModel.ArmPose SWING_POSE = HumanoidModel.ArmPose.create("SWING", false, (model, entity, arm) -> {
if (arm == HumanoidArm.RIGHT)
{
model.rightArm.xRot = (float) (Math.random() * Math.PI * 2);
} else
{
model.leftArm.xRot = (float) (Math.random() * Math.PI * 2);
}
});
@Override
public HumanoidModel.ArmPose getArmPose(LivingEntity entityLiving, InteractionHand hand, ItemStack itemStack)
{
if (!itemStack.isEmpty())
{
if (entityLiving.getUsedItemHand() == hand && entityLiving.getUseItemRemainingTicks() > 0)
{
return SWING_POSE;
}
}
return HumanoidModel.ArmPose.EMPTY;
}
@Override
public boolean applyForgeHandTransform(PoseStack poseStack, LocalPlayer player, HumanoidArm arm, ItemStack itemInHand, float partialTick, float equipProcess, float swingProcess) {
applyItemArmTransform(poseStack, arm);
if (player.isUsingItem()) {
poseStack.translate(0.0, -0.05, 0.0);
}
return true;
}
private void applyItemArmTransform(PoseStack poseStack, HumanoidArm arm) {
int i = arm == HumanoidArm.RIGHT ? 1 : -1;
poseStack.translate(i * 0.56F, -0.52F, -0.72F);
}
});
}
}
}
@@ -0,0 +1,40 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.debug.misc;
import org.slf4j.Logger;
import com.mojang.logging.LogUtils;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.AnvilUpdateEvent;
import net.minecraftforge.fml.common.Mod;
/**
* This class provides a way to test the AnvilUpdateEvent. <br>
* The event is now fired as described in the javadoc (of AnvilUpdateEvent). <br>
* "AnvilUpdateEvent is fired whenever the input stacks (left or right) or the name in an anvil changed."
*/
@Mod(AnvilUpdateEventTest.MOD_ID)
public class AnvilUpdateEventTest
{
private static final boolean ENABLED = false;
private static final Logger LOGGER = LogUtils.getLogger();
static final String MOD_ID = "anvil_update_event_fix";
public AnvilUpdateEventTest()
{
if (ENABLED)
{
MinecraftForge.EVENT_BUS.addListener(this::anvilUpdate);
}
}
private void anvilUpdate(AnvilUpdateEvent event)
{
LOGGER.info("Anvil input or name changed!");
}
}
@@ -14,7 +14,7 @@ import net.minecraftforge.event.level.LevelEvent;
import net.minecraftforge.fml.common.Mod;
/**
* <p>This tests net.minecraftforge.event.world.World.WorldEvent.PotentialSpawns. If ENABLED is set to true,
* <p>This tests net.minecraftforge.event.world.World.LevelEvent.PotentialSpawns. If ENABLED is set to true,
* this test mod uses the PotentialSpawns event to prevent mobs in the MONSTER mob category from spawning if the
* game difficulty is set to anything other than hard.</p>
*/
+6
View File
@@ -242,6 +242,12 @@ modId="custom_transformtype_test"
modId="mega_model_test"
[[mods]]
modId="emissive_elements_test"
[[mods]]
modId="anvil_update_event_fix"
[[mods]]
modId="item_use_animation_test"
[[mods]]
modId="custom_color_resolver_test"
@@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "custom_color_resolver_test:block/block"
}
}
}
@@ -0,0 +1,3 @@
{
"parent": "minecraft:block/grass_block"
}