Compare commits

..
48 Commits
Author SHA1 Message Date
LexManos 2fb2bbeed0 1.20.1 RB 2023-09-21 10:17:41 -07:00
Paint_Ninjaanddhyces 12d24df4f6 Keep order of sources in PackRepository (#9702)
Co-authored-by: dhyces <[email protected]>
2023-09-02 16:21:06 -07:00
Paint_Ninja e69f5e262a Fix DelegatingPackResources searching resource path twice (#9697) 2023-08-30 14:10:17 -07:00
Paint_Ninjaandmalte0811 23cee57d88 Fix Level leak in debug HUD (#9699)
Co-authored-by: malte0811 <[email protected]>
2023-08-30 14:09:51 -07:00
Paint_Ninja ab70bde1d6 Fix PlayerSpawnPhantomsEvent not being fired (#9689) 2023-08-11 10:42:31 -07:00
Meldexun f65381fbff Enhance LivingBreathEvent and LivingDrownEvent. Closes #9680
Also remove 3.5MB of useless data from the installer.
2023-07-24 14:42:24 -07:00
LexManos b680d09359 Partially revert LazyOptional changes, now no longer internally uses weak references. 2023-07-22 08:57:25 -07:00
LexManos 7969daf81a Make LazyOptional's internal references to invalidation listeners use WeakReference, and allow modders to unregister themselves. Closes #8805 2023-07-21 23:46:26 -07:00
LexManos f157567d2a Revert EntityEvent.Size changes to before #9018 was called. (#9679)
Kept newly added methods for binary compatibility but deprecated them all for removal.
The entire pose/eye/size system needs to be reevaluated and address some of Mojang's changes.
However this should fix any bugs that pulling that PR may of caused.
2023-07-21 23:44:01 -07:00
Kovak 93a615e900 Add a config option to restore the calculate all normals behavior in case some setups require old broken behavior. (#9670) 2023-07-19 14:46:05 -07:00
Kovak 7c84249996 Fix rounding errors on models with 45 degree normals by favoring one Direction (#9669)
Should fix flickering issues when breaking custom models and having our vanilla solution disabled.
2023-07-19 14:44:28 -07:00
RealMangoRage 881725c7d5 Moved ForgeHooksClient.onCreativeModeTabBuildContents to ForgeHooks to fix #9662 2023-07-19 11:18:45 -07:00
LexManos 2745531f08 Fix tag removal functionality that broke during the 1.19 update. Closes #9053 and #8949 2023-07-19 10:26:55 -07:00
LexManos bcdd44aece Replace string with forge tag in vanilla recipes. Closes #9062 2023-07-19 00:02:11 -07:00
LexManos bad5b1b5d4 Fix new brain hooks not persisting active activities. 2023-07-18 23:50:27 -07:00
Kovak 30f255d76c Fix breaking overlay flickering on campfires by using vanilla method to calculate block normals. (#9664) 2023-07-17 18:10:12 -07:00
LexManos ebb316a15c Cleanup usages of static imports and build script so that our build doesn't spam useless error like messages.
So that it is easier to see real errors.
Add compatibility checking to standard testing tasks.
2023-07-17 17:26:28 -07:00
LegoMaster3650 e6bb7eecbd Added Action value to PlayerInteractEvent.LeftClickEvent to expose what action fired the event. #9175 2023-07-17 10:57:10 -07:00
Jonathan Colmenares c66f70d6c2 Fix parameter names in IForgeDimensionSpecialEffects.adjustLightmapColors to better describe what they are. (#9656) 2023-07-17 09:38:05 -07:00
Jonathan Colmenares 26adf4da44 Re-add EntityEvent.Size methods to maintain bincompat 2023-07-17 07:50:18 -07:00
mgaray99 30d0a630d6 Added LivingMakeBrainEvent, to allow a consistent way for modders to manipulate entity Brains. #9292 2023-07-15 12:37:42 -07:00
JustRed23 00ad61b4ae Add LivingSwapHandItemsEvent 2023-07-15 11:15:57 -07:00
brandon3055 09bc73d5cd Fixed FluidUtil#tryFillContainer returning invalid result when simulating #9358 2023-07-15 10:51:17 -07:00
Jonathan Colmenares 1ee53c0464 Re-add in-game mod menu (#9652) 2023-07-15 10:45:34 -07:00
LexManos 16863c8d3b Fix Entity eye height for multipart entities. 2023-07-15 10:45:21 -07:00
Random832 150e8281ae Fix conflicting keybindings not having the correct click count set. #9360 2023-07-15 09:28:47 -07:00
Kovak 4385eb2155 Fix the Emissive Rendering for Experimental Light Pipeline (#9651) 2023-07-15 08:07:37 -07:00
RealMangoRage 5c40bef28e Fixed AdvancementsScreen.java.patch buttons not rendering (#9649) 2023-07-14 19:06:17 -07:00
ChampionAsh5357 55aa419100 Properly Handle Fluid Updates while in a Boat #9428 2023-07-14 19:05:27 -07:00
SilverDavid a4bef82836 New hook in IClientBlockExtensions to handle enabling tinting on breaking particles. #9446 2023-07-14 16:08:24 -07:00
LexManos b741df5f18 Fix invalid index when ticking itemstacks in a player nventory by adding a new onInventoryTick event. Closes #9453 2023-07-14 15:42:13 -07:00
LexManos 0c81a71308 Make the FireworkShapes enum extensible (Closes #9486) 2023-07-14 14:01:32 -07:00
Technici4n ea7f755a11 Add EmptyEnergyStorage (#9487) 2023-07-14 11:40:16 -07:00
Paint_Ninja d947d35eb1 Support IPv6 address compression for logged IPs 2023-07-14 11:14:56 -07:00
Sara Freimer 5271ef79fe Make item name rendering and status bar rendering respect additional gui overlays being rendered by mods (#9648) 2023-07-14 10:17:43 -07:00
Meldexun b7131824f0 Fix EyeHeight event being fired twice (#9647) 2023-07-14 10:09:48 -07:00
DBotThePony 3e624db4f8 Add PlayerSpawnPhantomsEvent, utilized to block or forcefully allow PhantomSpawner to spawn phantoms (#9644) 2023-07-14 07:20:21 -07:00
Nathan fc7af96bde Fix creative mode screen not correctly using CreativeModeTab::getTabsImage (#9627) 2023-07-14 07:10:49 -07:00
Paint_Ninja b1965db30b Add option to advertise dedicated servers to LAN. 2023-07-14 05:58:10 -07:00
LexManos 8df5a80725 Fix entity eye height loop. 2023-07-14 05:57:50 -07:00
ChampionAsh5357 d9043298d3 Particle Description Data Provider. 2023-07-13 19:34:53 -07:00
Meldexun e91ff9a5a6 Add LivingBreatheEvent and LivingDrownEvent (#9525) 2023-07-13 19:19:40 -07:00
Meldexun 77fb08713f Fix entity size event not being fired, changed it to split eye height and size calculations. (#9535) 2023-07-13 19:16:17 -07:00
bconlon 2c965fac90 AlterGroundEvent for modifying block placement performed by AlterGroundDecorator (#9637) 2023-07-13 17:29:03 -07:00
JustRed23 2f229c5bb1 Change ProjectileHitEvent to return a result instead of being cancelable. Closes #9642 2023-07-13 17:21:13 -07:00
noeppi_noeppi 54b08d2711 Replace static import with regular one to fix S2S and non-official mappings. (#9633) 2023-07-11 11:26:02 -07:00
Su5eD 46f641a502 Add missing null check for TagsProvider#existingFileHelper (#9638) 2023-07-11 11:25:39 -07:00
Sara Freimer 6304cb655b Add GuiGraphics helpers for blitNineSliced and blitRepeating that support specifying a custom texture size (#9641) 2023-07-10 22:03:47 +02:00
136 changed files with 3194 additions and 585 deletions

No files matched your search

+18 -9
View File
@@ -27,8 +27,8 @@ plugins {
id 'net.minecraftforge.gradleutils' version '2.+'
id 'eclipse'
id 'de.undercouch.download' version '5.4.0'
id 'net.minecraftforge.gradle.patcher' version '[6.0.6,6.2)' apply false
id 'net.minecraftforge.gradle.mcp' version '[6.0.6,6.2)' apply false
id 'net.minecraftforge.gradle.patcher' version '[6.0.11,6.2)' apply false
id 'net.minecraftforge.gradle.mcp' version '[6.0.11,6.2)' apply false
}
Util.init() //Init all our extension methods!
@@ -209,6 +209,11 @@ subprojects {
maven gradleutils.getPublishingForgeMaven()
}
}
tasks.withType(JavaCompile).configureEach {
options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation
options.warnings = false // Shutup deprecated for removal warnings
}
}
project(':mcp') {
@@ -887,9 +892,8 @@ project(':forge') {
apply plugin: 'org.cadixdev.licenser'
applyPatches {
verbose = true
//failOnError = false
}
level 'WARNING'
}
sourceSets {
main {
@@ -1775,10 +1779,10 @@ project(':forge') {
}
// Since we need the modules in the bootstrap, we need to make sure they are compiled before we do each run
afterEvaluate { prepareRuns.dependsOn(PACKED_DEPS) }
tasks.withType(JavaCompile).configureEach {
options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation
}
// Make sure we run bin compat checking during local testing.
if (!System.env.MAVEN_USER || !System.env.MAVEN_PASSWORD)
publish.dependsOn(':forge:checkJarCompatibility')
}
//evaluationDependsOnChildren()
@@ -1789,6 +1793,11 @@ task setup() { //These must be strings so that we can do lazy resolution. Else
dependsOn ':forge:extractMapped'
}
task doChecks {
dependsOn ':forge:checkJarCompatibility'
dependsOn ':forge:publish'
}
if (symlinkValid)
project.gradle.startParameter.excludedTaskNames.add(':fmlonly:genPatches')
project.gradle.startParameter.excludedTaskNames.add(':clean:genPatches')
+1 -1
View File
@@ -27,7 +27,7 @@ You can download the installer for the *Recommended Build* or the
*Latest build* there. Latest builds may have newer features but may be
more unstable as a result. The installer will attempt to install Forge
into your vanilla launcher environment, where you can then create a new
profile using that version and play the game!
profile using that version and play the game!
For support and questions, visit [the Support Forum][Support-Forum] or [the Forge Discord server][Discord].
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 MiB

@@ -0,0 +1,11 @@
--- a/com/mojang/blaze3d/vertex/SheetedDecalTextureGenerator.java
+++ b/com/mojang/blaze3d/vertex/SheetedDecalTextureGenerator.java
@@ -46,7 +_,7 @@
public void m_5752_() {
Vector3f vector3f = this.f_85869_.transform(new Vector3f(this.f_85876_, this.f_85877_, this.f_85878_));
- Direction direction = Direction.m_122372_(vector3f.x(), vector3f.y(), vector3f.z());
+ Direction direction = net.minecraftforge.client.ForgeHooksClient.getNearestStable(vector3f.x(), vector3f.y(), vector3f.z());
Vector4f vector4f = this.f_85868_.transform(new Vector4f(this.f_85870_, this.f_85871_, this.f_85872_, 1.0F));
vector4f.rotateY((float)Math.PI);
vector4f.rotateX((-(float)Math.PI / 2F));
@@ -12,6 +12,15 @@
private static final Set<String> f_90811_ = Sets.newHashSet();
public static final String f_167805_ = "key.categories.movement";
public static final String f_167806_ = "key.categories.misc";
@@ -41,7 +_,7 @@
private int f_90818_;
public static void m_90835_(InputConstants.Key p_90836_) {
- KeyMapping keymapping = f_90810_.get(p_90836_);
+ for (KeyMapping keymapping : f_90810_.getAll(p_90836_))
if (keymapping != null) {
++keymapping.f_90818_;
}
@@ -49,7 +_,7 @@
}
@@ -17,8 +17,14 @@
TextureAtlasSprite textureatlassprite = mobeffecttexturemanager.m_118732_(mobeffect);
int i1 = j;
float f1 = f;
@@ -574,12 +_,13 @@
@@ -572,16 +_,21 @@
}
public void m_280295_(GuiGraphics p_283501_) {
+ renderSelectedItemName(p_283501_, 0);
+ }
+
+ public void renderSelectedItemName(GuiGraphics p_283501_, int yShift) {
this.f_92986_.m_91307_().m_6180_("selectedItemName");
if (this.f_92993_ > 0 && !this.f_92994_.m_41619_()) {
- MutableComponent mutablecomponent = Component.m_237119_().m_7220_(this.f_92994_.m_41786_()).m_130940_(this.f_92994_.m_41791_().f_43022_);
@@ -31,8 +37,11 @@
+ Component highlightTip = this.f_92994_.getHighlightTip(mutablecomponent);
+ int i = this.m_93082_().m_92852_(highlightTip);
int j = (this.f_92977_ - i) / 2;
int k = this.f_92978_ - 59;
- int k = this.f_92978_ - 59;
+ int k = this.f_92978_ - Math.max(yShift, 59);
if (!this.f_92986_.f_91072_.m_105205_()) {
k += 14;
}
@@ -593,7 +_,13 @@
if (l > 0) {
@@ -33,6 +33,26 @@
int i = p_282636_.m_272191_(p_281596_, (float)p_281586_, (float)p_282816_, p_281743_, p_282394_, this.f_279612_.m_85850_().m_252922_(), this.f_279627_, Font.DisplayMode.NORMAL, 0, 15728880);
this.m_286081_();
return i;
@@ -405,6 +_,10 @@
}
public void m_280543_(ResourceLocation p_283059_, int p_283575_, int p_283192_, int p_281790_, int p_283642_, int p_282691_, int p_281912_, int p_281728_, int p_282324_) {
+ blitRepeating(p_283059_, p_283575_, p_283192_, p_281790_, p_283642_, p_282691_, p_281912_, p_281728_, p_282324_, 256, 256);
+ }
+
+ public void blitRepeating(ResourceLocation p_283059_, int p_283575_, int p_283192_, int p_281790_, int p_283642_, int p_282691_, int p_281912_, int p_281728_, int p_282324_, int textureWidth, int textureHeight) {
int i = p_283575_;
int j;
@@ -417,7 +_,7 @@
for(IntIterator intiterator1 = m_280358_(p_283642_, p_282324_); intiterator1.hasNext(); l += i1) {
i1 = intiterator1.nextInt();
int j1 = (p_282324_ - i1) / 2;
- this.m_280218_(p_283059_, i, l, p_282691_ + k, p_281912_ + j1, j, i1);
+ this.m_280163_(p_283059_, i, l, p_282691_ + k, p_281912_ + j1, j, i1, textureWidth, textureHeight);
}
}
@@ -477,6 +_,7 @@
crashreportcategory.m_128165_("Item Type", () -> {
return String.valueOf((Object)p_281675_.m_41720_());
@@ -0,0 +1,10 @@
--- a/net/minecraft/client/gui/screens/PauseScreen.java
+++ b/net/minecraft/client/gui/screens/PauseScreen.java
@@ -82,6 +_,7 @@
} else {
gridlayout$rowhelper.m_264139_(this.m_262456_(f_262254_, SocialInteractionsScreen::new));
}
+ gridlayout$rowhelper.m_264108_(Button.m_253074_(Component.m_237115_("fml.menu.mods"), button -> this.f_96541_.m_91152_(new net.minecraftforge.client.gui.ModListScreen(this))).m_252780_(f_262268_).m_253136_(), 2);
Component component = this.f_96541_.m_91090_() ? f_262217_ : f_262246_;
this.f_252482_ = gridlayout$rowhelper.m_264108_(Button.m_253074_(component, (p_280815_) -> {
@@ -34,7 +34,7 @@
this.f_97334_.m_104401_(advancementtab.m_97182_(), true);
break;
}
@@ -98,6 +_,11 @@
@@ -98,9 +_,15 @@
int i = (this.f_96543_ - 252) / 2;
int j = (this.f_96544_ - 140) / 2;
this.m_280273_(p_282589_);
@@ -46,6 +46,10 @@
this.m_97373_(p_282589_, p_282255_, p_283354_, i, j);
this.m_280088_(p_282589_, i, j);
this.m_280355_(p_282589_, p_282255_, p_283354_, i, j);
+ super.m_88315_(p_282589_, p_282255_, p_283354_, p_283123_);
}
public boolean m_7979_(double p_97347_, double p_97348_, int p_97349_, double p_97350_, double p_97351_) {
@@ -135,10 +_,12 @@
p_283395_.m_280218_(f_97329_, p_281890_, p_282532_, 0, 0, 252, 140);
if (this.f_97335_.size() > 1) {
@@ -187,7 +187,7 @@
list1.add(i++, creativemodetab.m_40786_().m_6881_().m_130940_(ChatFormatting.BLUE));
}
}
@@ -639,13 +_,13 @@
@@ -639,21 +_,22 @@
}
protected void m_7286_(GuiGraphics p_282663_, float p_282504_, int p_282089_, int p_282249_) {
@@ -203,8 +203,10 @@
this.f_98510_.m_88315_(p_282663_, p_282089_, p_282249_, p_282504_);
int j = this.f_97735_ + 175;
int k = this.f_97736_ + 18;
@@ -654,6 +_,7 @@
p_282663_.m_280218_(f_98504_, j, k + (int)((float)(i - k - 17) * this.f_98508_), 232 + (this.m_98631_() ? 0 : 12), 0, 12, 15);
int i = k + 112;
if (f_98507_.m_40791_()) {
- p_282663_.m_280218_(f_98504_, j, k + (int)((float)(i - k - 17) * this.f_98508_), 232 + (this.m_98631_() ? 0 : 12), 0, 12, 15);
+ p_282663_.m_280218_(f_98507_.getTabsImage(), j, k + (int)((float)(i - k - 17) * this.f_98508_), 232 + (this.m_98631_() ? 0 : 12), 0, 12, 15);
}
+ if (currentPage.getVisibleTabs().contains(f_98507_)) //Forge: only display tab selection when the selected tab is on the current page
@@ -240,14 +242,16 @@
int j = i * 26;
int k = 0;
int l = this.f_97735_ + this.m_258094_(p_283489_);
@@ -720,6 +_,7 @@
@@ -720,7 +_,8 @@
i1 += this.f_97727_ - 4;
}
- p_283590_.m_280218_(f_98504_, l, i1, j, k, 26, 32);
+ com.mojang.blaze3d.systems.RenderSystem.enableBlend(); //Forge: Make sure blend is enabled else tabs show a white border.
p_283590_.m_280218_(f_98504_, l, i1, j, k, 26, 32);
+ p_283590_.m_280218_(p_283489_.getTabsImage(), l, i1, j, k, 26, 32);
p_283590_.m_280168_().m_85836_();
p_283590_.m_280168_().m_252880_(0.0F, 0.0F, 100.0F);
l += 5;
@@ -763,6 +_,14 @@
}
@@ -23,7 +23,7 @@
BlockState blockstate = this.f_105189_.f_91073_.m_8055_(p_105270_);
this.f_105189_.m_91301_().m_120581_(this.f_105189_.f_91073_, p_105270_, blockstate, 1.0F);
this.m_233729_(this.f_105189_.f_91073_, (p_233757_) -> {
+ if (!net.minecraftforge.common.ForgeHooks.onLeftClickBlock(this.f_105189_.f_91074_, p_105270_, p_105271_).isCanceled())
+ if (!net.minecraftforge.common.ForgeHooks.onLeftClickBlock(this.f_105189_.f_91074_, p_105270_, p_105271_, ServerboundPlayerActionPacket.Action.START_DESTROY_BLOCK).isCanceled())
this.m_105267_(p_105270_);
return new ServerboundPlayerActionPacket(ServerboundPlayerActionPacket.Action.START_DESTROY_BLOCK, p_105270_, p_105271_, p_233757_);
});
@@ -31,7 +31,7 @@
if (this.f_105196_) {
this.f_105190_.m_104955_(new ServerboundPlayerActionPacket(ServerboundPlayerActionPacket.Action.ABORT_DESTROY_BLOCK, this.f_105191_, p_105271_));
}
+ net.minecraftforge.event.entity.player.PlayerInteractEvent.LeftClickBlock event = net.minecraftforge.common.ForgeHooks.onLeftClickBlock(this.f_105189_.f_91074_, p_105270_, p_105271_);
+ net.minecraftforge.event.entity.player.PlayerInteractEvent.LeftClickBlock event = net.minecraftforge.common.ForgeHooks.onLeftClickBlock(this.f_105189_.f_91074_, p_105270_, p_105271_, ServerboundPlayerActionPacket.Action.START_DESTROY_BLOCK);
BlockState blockstate1 = this.f_105189_.f_91073_.m_8055_(p_105270_);
this.f_105189_.m_91301_().m_120581_(this.f_105189_.f_91073_, p_105270_, blockstate1, 0.0F);
@@ -60,7 +60,7 @@
BlockState blockstate1 = this.f_105189_.f_91073_.m_8055_(p_105284_);
this.f_105189_.m_91301_().m_120581_(this.f_105189_.f_91073_, p_105284_, blockstate1, 1.0F);
this.m_233729_(this.f_105189_.f_91073_, (p_233753_) -> {
+ if (!net.minecraftforge.common.ForgeHooks.onLeftClickBlock(this.f_105189_.f_91074_, p_105284_, p_105285_).isCanceled())
+ if (!net.minecraftforge.common.ForgeHooks.onLeftClickBlock(this.f_105189_.f_91074_, p_105284_, p_105285_, ServerboundPlayerActionPacket.Action.START_DESTROY_BLOCK).isCanceled())
this.m_105267_(p_105284_);
return new ServerboundPlayerActionPacket(ServerboundPlayerActionPacket.Action.START_DESTROY_BLOCK, p_105284_, p_105285_, p_233753_);
});
@@ -75,7 +75,7 @@
++this.f_105194_;
this.f_105189_.m_91301_().m_120581_(this.f_105189_.f_91073_, p_105284_, blockstate, Mth.m_14036_(this.f_105193_, 0.0F, 1.0F));
+ if (net.minecraftforge.common.ForgeHooks.onLeftClickBlock(this.f_105189_.f_91074_, p_105284_, p_105285_).getUseItem() == net.minecraftforge.eventbus.api.Event.Result.DENY) return true;
+ if (net.minecraftforge.common.ForgeHooks.onClientMineHold(this.f_105189_.f_91074_, p_105284_, p_105285_).getUseItem() == net.minecraftforge.eventbus.api.Event.Result.DENY) return true;
if (this.f_105193_ >= 1.0F) {
this.f_105196_ = false;
this.m_233729_(this.f_105189_.f_91073_, (p_233739_) -> {
@@ -0,0 +1,31 @@
--- a/net/minecraft/client/particle/FireworkParticles.java
+++ b/net/minecraft/client/particle/FireworkParticles.java
@@ -172,7 +_,7 @@
} else {
for(int i = 0; i < this.f_106752_.size(); ++i) {
CompoundTag compoundtag = this.f_106752_.m_128728_(i);
- if (FireworkRocketItem.Shape.m_41237_(compoundtag.m_128445_("Type")) == FireworkRocketItem.Shape.LARGE_BALL) {
+ if (FireworkRocketItem.Shape.getShape(compoundtag) == FireworkRocketItem.Shape.LARGE_BALL) {
flag1 = true;
break;
}
@@ -192,7 +_,7 @@
if (this.f_106754_ % 2 == 0 && this.f_106752_ != null && this.f_106754_ / 2 < this.f_106752_.size()) {
int k = this.f_106754_ / 2;
CompoundTag compoundtag1 = this.f_106752_.m_128728_(k);
- FireworkRocketItem.Shape fireworkrocketitem$shape = FireworkRocketItem.Shape.m_41237_(compoundtag1.m_128445_("Type"));
+ FireworkRocketItem.Shape fireworkrocketitem$shape = FireworkRocketItem.Shape.getShape(compoundtag1);
boolean flag4 = compoundtag1.m_128471_("Trail");
boolean flag2 = compoundtag1.m_128471_("Flicker");
int[] aint = compoundtag1.m_128465_("Colors");
@@ -201,6 +_,10 @@
aint = new int[]{DyeColor.BLACK.m_41070_()};
}
+ var factory = net.minecraftforge.client.FireworkShapeFactoryRegistry.get(fireworkrocketitem$shape);
+ if (factory != null)
+ factory.build(this, flag4, flag2, aint, aint1);
+ else
switch (fireworkrocketitem$shape) {
case SMALL_BALL:
default:
@@ -1,6 +1,6 @@
--- a/net/minecraft/client/particle/Particle.java
+++ b/net/minecraft/client/particle/Particle.java
@@ -226,4 +_,12 @@
@@ -226,4 +_,16 @@
public Optional<ParticleGroup> m_142654_() {
return Optional.empty();
}
@@ -11,5 +11,9 @@
+ */
+ public boolean shouldCull() {
+ return true;
+ }
+
+ public net.minecraft.world.phys.Vec3 getPos() {
+ return new net.minecraft.world.phys.Vec3(this.f_107212_, this.f_107213_, this.f_107214_);
+ }
}
@@ -1,5 +1,14 @@
--- a/net/minecraft/client/particle/TerrainParticle.java
+++ b/net/minecraft/client/particle/TerrainParticle.java
@@ -28,7 +_,7 @@
this.f_107227_ = 0.6F;
this.f_107228_ = 0.6F;
this.f_107229_ = 0.6F;
- if (!p_172458_.m_60713_(Blocks.f_50440_)) {
+ if (net.minecraftforge.client.extensions.common.IClientBlockExtensions.of(p_172458_).areBreakingParticlesTinted(p_172458_, p_172451_, p_172459_)) {
int i = Minecraft.m_91087_().m_91298_().m_92577_(p_172458_, p_172451_, p_172459_, 0);
this.f_107227_ *= (float)(i >> 16 & 255) / 255.0F;
this.f_107228_ *= (float)(i >> 8 & 255) / 255.0F;
@@ -69,7 +_,13 @@
public static class Provider implements ParticleProvider<BlockParticleOption> {
public Particle m_6966_(BlockParticleOption p_108304_, ClientLevel p_108305_, double p_108306_, double p_108307_, double p_108308_, double p_108309_, double p_108310_, double p_108311_) {
@@ -5,7 +5,7 @@
}
- return new BakedQuad(aint, p_111603_.f_111355_, direction, p_111604_, p_111608_);
+ net.minecraftforge.client.ForgeHooksClient.fillNormal(aint, direction);
+ net.minecraftforge.client.ForgeHooksClient.fillNormal(aint, direction, p_111603_.getFaceData().calculateNormals());
+ var data = p_111603_.getFaceData();
+ var quad = new BakedQuad(aint, p_111603_.f_111355_, direction, p_111604_, p_111608_, data.ambientOcclusion());
+ if (!net.minecraftforge.client.model.ForgeFaceData.DEFAULT.equals(data)) {
@@ -9,21 +9,13 @@
this.f_120088_.setSoTimeout(5000);
this.f_120088_.joinGroup(this.f_120087_);
}
@@ -87,7 +_,19 @@
@@ -87,7 +_,11 @@
String s = LanServerPinger.m_120111_(p_120097_);
String s1 = LanServerPinger.m_120116_(p_120097_);
if (s1 != null) {
- s1 = p_120098_.getHostAddress() + ":" + s1;
+ if (net.minecraftforge.network.DualStackUtils.checkIPv6(p_120098_)) {
+ final String ip;
+
+ // compress to short form if enabled in config
+ if (net.minecraftforge.common.ForgeConfig.CLIENT.compressLanIPv6Addresses.get())
+ ip = com.google.common.net.InetAddresses.toAddrString(p_120098_);
+ else
+ ip = p_120098_.getHostAddress();
+
+ s1 = "[" + ip + "]:" + s1;
+ s1 = "[" + com.google.common.net.InetAddresses.toAddrString(p_120098_) + "]:" + s1;
+ } else {
+ s1 = p_120098_.getHostAddress() + ":" + s1;
+ }
@@ -1,6 +1,6 @@
--- a/net/minecraft/client/server/LanServerPinger.java
+++ b/net/minecraft/client/server/LanServerPinger.java
@@ -16,7 +_,7 @@
@@ -13,7 +_,7 @@
public class LanServerPinger extends Thread {
private static final AtomicInteger f_120101_ = new AtomicInteger(0);
private static final Logger f_120102_ = LogUtils.getLogger();
@@ -9,7 +9,7 @@
public static final int f_174975_ = 4445;
private static final long f_174976_ = 1500L;
private final String f_120103_;
@@ -39,7 +_,7 @@
@@ -36,7 +_,7 @@
while(!this.isInterrupted() && this.f_120105_) {
try {
@@ -24,7 +24,7 @@
public boolean m_207277_(HolderOwner<T> p_256542_) {
return this.f_254711_.m_254921_(p_256542_);
+ }
+ // FORGE: Keep a list of invalidation callbacks so they can be run when tags rebind
+ // 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);
@@ -66,9 +66,12 @@
Predicate<ResourceLocation> predicate = (p_255496_) -> {
return registrylookup.m_254902_(ResourceKey.m_135785_(this.f_254716_, p_255496_)).isPresent();
};
@@ -77,12 +_,13 @@
@@ -75,14 +_,16 @@
ResourceLocation resourcelocation = p_255499_.getKey();
TagBuilder tagbuilder = p_255499_.getValue();
List<TagEntry> list = tagbuilder.m_215904_();
List<TagEntry> list1 = list.stream().filter((p_274771_) -> {
- List<TagEntry> list1 = list.stream().filter((p_274771_) -> {
+ List<TagEntry> list1 = java.util.stream.Stream.concat(list.stream(), tagbuilder.getRemoveEntries()).filter((p_274771_) -> {
return !p_274771_.m_215940_(predicate, predicate1);
- }).toList();
+ }).filter(this::missing).toList(); // Forge: Add validation via existing resources
@@ -77,13 +80,14 @@
} else {
- JsonElement jsonelement = TagFile.f_215958_.encodeStart(JsonOps.INSTANCE, new TagFile(list, false)).getOrThrow(false, f_126541_::error);
- Path path = this.f_236439_.m_245731_(resourcelocation);
+ JsonElement jsonelement = TagFile.f_215958_.encodeStart(JsonOps.INSTANCE, new TagFile(list, tagbuilder.isReplace())).getOrThrow(false, f_126541_::error);
+ var removed = tagbuilder.getRemoveEntries().toList();
+ JsonElement jsonelement = TagFile.f_215958_.encodeStart(JsonOps.INSTANCE, new TagFile(list, tagbuilder.isReplace(), removed)).getOrThrow(false, f_126541_::error);
+ Path path = this.getPath(resourcelocation);
+ if (path == null) return CompletableFuture.completedFuture(null); // Forge: Allow running this data provider without writing it. Recipe provider needs valid tags.
return DataProvider.m_253162_(p_253684_, jsonelement, path);
}
}).toArray((p_253442_) -> {
@@ -91,13 +_,23 @@
@@ -91,13 +_,25 @@
});
}
@@ -104,7 +108,9 @@
protected TagBuilder m_236451_(TagKey<T> p_236452_) {
return this.f_126543_.computeIfAbsent(p_236452_.f_203868_(), (p_236442_) -> {
+ existingFileHelper.trackGenerated(p_236442_, resourceType);
+ if (existingFileHelper != null) {
+ existingFileHelper.trackGenerated(p_236442_, resourceType);
+ }
return TagBuilder.m_215899_();
});
}
@@ -1,5 +1,14 @@
--- a/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
@@ -68,6 +_,8 @@
private MinecraftServerGui f_139605_;
@Nullable
private final TextFilterClient f_139606_;
+ @Nullable
+ private net.minecraft.client.server.LanServerPinger dediLanPinger;
public DedicatedServer(Thread p_214789_, LevelStorageSource.LevelStorageAccess p_214790_, PackRepository p_214791_, WorldStem p_214792_, DedicatedServerSettings p_214793_, DataFixer p_214794_, Services p_214795_, ChunkProgressListenerFactory p_214796_) {
super(p_214789_, p_214790_, p_214791_, p_214792_, Proxy.NO_PROXY, p_214794_, p_214795_, p_214796_);
@@ -79,6 +_,7 @@
public boolean m_7038_() throws IOException {
Thread thread = new Thread("Server console handler") {
@@ -22,26 +31,41 @@
if (dedicatedserverproperties.f_139744_ != null) {
this.m_129900_().m_46170_(GameRules.f_46153_).m_46246_(dedicatedserverproperties.f_139744_, this);
}
@@ -183,12 +_,13 @@
thread1.start();
}
+ // <3 you Grum for this, saves us ~30 patch files! --^
if (dedicatedserverproperties.f_139721_) {
MinecraftServerStatistics.m_18328_(this);
@@ -188,7 +_,12 @@
f_139598_.info("JMX monitoring enabled");
}
- return true;
+ if (net.minecraftforge.common.ForgeConfig.SERVER.advertiseDedicatedServerToLan.get()) {
+ this.dediLanPinger = new net.minecraft.client.server.LanServerPinger(this.m_129916_(), String.valueOf(this.m_7448_()));
+ this.dediLanPinger.start();
+ }
+
+ return net.minecraftforge.server.ServerLifecycleHooks.handleServerStarting(this);
}
}
@@ -492,6 +_,7 @@
@@ -263,6 +_,10 @@
this.f_139601_.m_7530_();
}
+ if (this.dediLanPinger != null) {
+ this.dediLanPinger.interrupt();
+ this.dediLanPinger = null;
+ }
}
public void m_5703_(BooleanSupplier p_139661_) {
@@ -492,7 +_,12 @@
}
public void m_7041_() {
+ net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.GameShuttingDownEvent());
super.m_7041_();
+ if (this.dediLanPinger != null) {
+ this.dediLanPinger.interrupt();
+ this.dediLanPinger = null;
+ }
Util.m_137580_();
SkullBlockEntity.m_196704_();
}
@@ -5,7 +5,7 @@
public void m_214168_(BlockPos p_215120_, ServerboundPlayerActionPacket.Action p_215121_, Direction p_215122_, int p_215123_, int p_215124_) {
- if (this.f_9245_.m_146892_().m_82557_(Vec3.m_82512_(p_215120_)) > ServerGamePacketListenerImpl.f_215198_) {
+ net.minecraftforge.event.entity.player.PlayerInteractEvent.LeftClickBlock event = net.minecraftforge.common.ForgeHooks.onLeftClickBlock(f_9245_, p_215120_, p_215122_);
+ net.minecraftforge.event.entity.player.PlayerInteractEvent.LeftClickBlock event = net.minecraftforge.common.ForgeHooks.onLeftClickBlock(f_9245_, p_215120_, p_215122_, p_215121_);
+ if (event.isCanceled() || (!this.m_9295_() && event.getResult() == net.minecraftforge.eventbus.api.Event.Result.DENY)) {
+ return;
+ }
@@ -25,6 +25,19 @@
this.f_9742_.m_129512_(new ClientboundMoveVehiclePacket(entity));
return;
}
@@ -983,8 +_,10 @@
case SWAP_ITEM_WITH_OFFHAND:
if (!this.f_9743_.m_5833_()) {
ItemStack itemstack = this.f_9743_.m_21120_(InteractionHand.OFF_HAND);
- this.f_9743_.m_21008_(InteractionHand.OFF_HAND, this.f_9743_.m_21120_(InteractionHand.MAIN_HAND));
- this.f_9743_.m_21008_(InteractionHand.MAIN_HAND, itemstack);
+ var event = net.minecraftforge.common.ForgeHooks.onLivingSwapHandItems(this.f_9743_);
+ if (event.isCanceled()) return;
+ this.f_9743_.m_21008_(InteractionHand.OFF_HAND, event.getItemSwappedToOffHand());
+ this.f_9743_.m_21008_(InteractionHand.MAIN_HAND, event.getItemSwappedToMainHand());
this.f_9743_.m_5810_();
}
@@ -1035,7 +_,7 @@
Vec3 vec3 = blockhitresult.m_82450_();
BlockPos blockpos = blockhitresult.m_82425_();
@@ -15,6 +15,16 @@
this.m_10055_();
} else if (this.f_10019_ == ServerLoginPacketListenerImpl.State.DELAY_ACCEPT) {
ServerPlayer serverplayer = this.f_10018_.m_6846_().m_11259_(this.f_10021_.getId());
@@ -138,7 +_,8 @@
}
public String m_10056_() {
- return this.f_10021_ != null ? this.f_10021_ + " (" + this.f_10013_.m_129523_() + ")" : String.valueOf((Object)this.f_10013_.m_129523_());
+ final String addressString = net.minecraftforge.network.DualStackUtils.getAddressString(this.f_10013_.m_129523_());
+ return this.f_10021_ != null ? this.f_10021_ + " (" + addressString + ")" : addressString;
}
public void m_5990_(ServerboundHelloPacket p_10047_) {
@@ -147,14 +_,14 @@
GameProfile gameprofile = this.f_10018_.m_236731_();
if (gameprofile != null && p_10047_.f_238040_().equalsIgnoreCase(gameprofile.getName())) {
@@ -5,7 +5,7 @@
public PackRepository(RepositorySource... p_251886_) {
- this.f_10497_ = ImmutableSet.copyOf(p_251886_);
+ this.f_10497_ = new java.util.HashSet<>(List.of(p_251886_)); //Forge: This needs to be a mutable set, so that we can add to it later on.
+ this.f_10497_ = new java.util.LinkedHashSet<>(List.of(p_251886_)); //Forge: This needs to be a mutable set, so that we can add to it later on.
}
public void m_10506_() {
@@ -8,7 +8,15 @@
public PlayerList(MinecraftServer p_203842_, LayeredRegistryAccess<RegistryLayer> p_251844_, PlayerDataStorage p_203844_, int p_203845_) {
this.f_11195_ = p_203842_;
@@ -174,6 +_,7 @@
@@ -167,13 +_,14 @@
p_11263_.m_284127_(serverlevel1);
String s1 = "local";
if (p_11262_.m_129523_() != null) {
- s1 = p_11262_.m_129523_().toString();
+ s1 = net.minecraftforge.network.DualStackUtils.getAddressString(p_11262_.m_129523_());
}
f_11188_.info("{}[{}] logged in with entity id {} at ({}, {}, {})", p_11263_.m_7755_().getString(), s1, p_11263_.m_19879_(), p_11263_.m_20185_(), p_11263_.m_20186_(), p_11263_.m_20189_());
LevelData leveldata = serverlevel1.m_6106_();
p_11263_.m_143427_(compoundtag);
ServerGamePacketListenerImpl servergamepacketlistenerimpl = new ServerGamePacketListenerImpl(this.f_11195_, p_11262_, p_11263_);
@@ -0,0 +1,17 @@
--- a/net/minecraft/tags/TagFile.java
+++ b/net/minecraft/tags/TagFile.java
@@ -4,8 +_,12 @@
import com.mojang.serialization.codecs.RecordCodecBuilder;
import java.util.List;
-public record TagFile(List<TagEntry> f_215959_, boolean f_215960_) {
+public record TagFile(List<TagEntry> f_215959_, boolean f_215960_, List<TagEntry> remove) {
public static final Codec<TagFile> f_215958_ = RecordCodecBuilder.create((p_215967_) -> {
- return p_215967_.group(TagEntry.f_215911_.listOf().fieldOf("values").forGetter(TagFile::f_215959_), Codec.BOOL.optionalFieldOf("replace", Boolean.valueOf(false)).forGetter(TagFile::f_215960_)).apply(p_215967_, TagFile::new);
+ return p_215967_.group(TagEntry.f_215911_.listOf().fieldOf("values").forGetter(TagFile::f_215959_), Codec.BOOL.optionalFieldOf("replace", Boolean.valueOf(false)).forGetter(TagFile::f_215960_), TagEntry.f_215911_.listOf().optionalFieldOf("remove", List.of()).forGetter(TagFile::remove)).apply(p_215967_, TagFile::new);
});
+
+ public TagFile(List<TagEntry> f_215959_, boolean f_215960_) {
+ this(f_215959_, f_215960_, List.of());
+ }
}
@@ -1,5 +1,34 @@
--- a/net/minecraft/tags/TagLoader.java
+++ b/net/minecraft/tags/TagLoader.java
@@ -59,6 +_,7 @@
tagfile.f_215959_().forEach((p_215997_) -> {
list.add(new TagLoader.EntryWithSource(p_215997_, s));
});
+ tagfile.remove().forEach(e -> list.add(new TagLoader.EntryWithSource(e, s, true)));
} catch (Exception exception) {
f_13445_.error("Couldn't read tag list {} from {} in data pack {}", resourcelocation1, resourcelocation, resource.m_215506_(), exception);
}
@@ -69,16 +_,17 @@
}
private Either<Collection<TagLoader.EntryWithSource>, Collection<T>> m_215978_(TagEntry.Lookup<T> p_215979_, List<TagLoader.EntryWithSource> p_215980_) {
- ImmutableSet.Builder<T> builder = ImmutableSet.builder();
+ var builder = new java.util.HashSet<T>();
List<TagLoader.EntryWithSource> list = new ArrayList<>();
for(TagLoader.EntryWithSource tagloader$entrywithsource : p_215980_) {
- if (!tagloader$entrywithsource.f_216042_().m_215927_(p_215979_, builder::add)) {
+ if (!tagloader$entrywithsource.f_216042_().m_215927_(p_215979_, tagloader$entrywithsource.remove() ? builder::remove : builder::add)) {
+ if (!tagloader$entrywithsource.remove()) // Treat all removals as optional at runtime. If it was missing, then it could of never been added.
list.add(tagloader$entrywithsource);
}
}
- return list.isEmpty() ? Either.right(builder.build()) : Either.left(list);
+ return list.isEmpty() ? Either.right(List.copyOf(builder)) : Either.left(list);
}
public Map<ResourceLocation, Collection<T>> m_203898_(Map<ResourceLocation, List<TagLoader.EntryWithSource>> p_203899_) {
@@ -100,7 +_,7 @@
});
dependencysorter.m_284430_((p_284682_, p_284683_) -> {
@@ -9,3 +38,13 @@
}).ifRight((p_216001_) -> {
map.put(p_284682_, p_216001_);
});
@@ -112,7 +_,8 @@
return this.m_203898_(this.m_144495_(p_203901_));
}
- public static record EntryWithSource(TagEntry f_216042_, String f_216043_) {
+ public static record EntryWithSource(TagEntry f_216042_, String f_216043_, boolean remove) {
+ public EntryWithSource(TagEntry f_216042_, String f_216043_) { this(f_216042_, f_216043_, false); }
public String toString() {
return this.f_216042_ + " (from " + this.f_216043_ + ")";
}
@@ -41,7 +41,7 @@
this.m_8097_();
this.m_6034_(0.0D, 0.0D, 0.0D);
- this.f_19816_ = this.m_6380_(Pose.STANDING, this.f_19815_);
+ net.minecraftforge.event.entity.EntityEvent.Size sizeEvent = net.minecraftforge.event.ForgeEventFactory.getEntitySizeForge(this, Pose.STANDING, this.f_19815_, this.m_6380_(Pose.STANDING, this.f_19815_));
+ var sizeEvent = net.minecraftforge.event.ForgeEventFactory.getEntitySizeForge(this, Pose.STANDING, this.f_19815_, this.m_6380_(Pose.STANDING, this.f_19815_));
+ this.f_19815_ = sizeEvent.getNewSize();
+ this.f_19816_ = sizeEvent.getNewEyeHeight();
+ net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.entity.EntityEvent.EntityConstructing(this));
@@ -147,7 +147,7 @@
this.m_5496_(soundtype.m_56776_(), soundtype.m_56773_() * 0.15F, soundtype.m_56774_());
}
@@ -1176,19 +_,22 @@
@@ -1176,31 +_,38 @@
public void m_5844_() {
if (this.m_6069_()) {
@@ -175,6 +175,24 @@
}
void m_20074_() {
Entity entity = this.m_20202_();
+ java.util.function.BooleanSupplier updateFluidHeight = () -> this.m_204031_(FluidTags.f_13131_, 0.014D);
if (entity instanceof Boat boat) {
if (!boat.m_5842_()) {
this.f_19798_ = false;
- return;
+ updateFluidHeight = () -> {
+ this.updateFluidHeightAndDoFluidPushing(state -> this.shouldUpdateFluidWhileBoating(state, boat));
+ return false;
+ };
}
}
- if (this.m_204031_(FluidTags.f_13131_, 0.014D)) {
+ if (updateFluidHeight.getAsBoolean()) {
if (!this.f_19798_ && !this.f_19803_) {
this.m_5841_();
}
@@ -1217,6 +_,7 @@
private void m_20323_() {
this.f_19800_ = this.m_204029_(FluidTags.f_13131_);
@@ -385,7 +403,7 @@
EntityDimensions entitydimensions = this.f_19815_;
Pose pose = this.m_20089_();
EntityDimensions entitydimensions1 = this.m_6972_(pose);
+ net.minecraftforge.event.entity.EntityEvent.Size sizeEvent = net.minecraftforge.event.ForgeEventFactory.getEntitySizeForge(this, pose, entitydimensions, entitydimensions1, this.m_6380_(pose, entitydimensions1));
+ var sizeEvent = net.minecraftforge.event.ForgeEventFactory.getEntitySizeForge(this, pose, entitydimensions, entitydimensions1, this.m_6380_(pose, entitydimensions1));
+ entitydimensions1 = sizeEvent.getNewSize();
this.f_19815_ = entitydimensions1;
- this.f_19816_ = this.m_6380_(pose, entitydimensions1);
@@ -404,11 +422,11 @@
});
}
@@ -2980,9 +_,17 @@
@@ -2980,9 +_,22 @@
this.f_19859_ = this.m_146908_();
}
+ @Deprecated // Forge: Use no parameter version instead, only for vanilla Tags
+ @Deprecated // Forge: Use predicate version instead, only for vanilla Tags
public boolean m_204031_(TagKey<Fluid> p_204032_, double p_204033_) {
+ this.updateFluidHeightAndDoFluidPushing();
+ if(p_204032_ == FluidTags.f_13131_) return this.isInFluidType(net.minecraftforge.common.ForgeMod.WATER_TYPE.get());
@@ -416,7 +434,12 @@
+ else return false;
+ }
+
+ @Deprecated(forRemoval = true, since = "1.20.1")
+ public void updateFluidHeightAndDoFluidPushing() {
+ this.updateFluidHeightAndDoFluidPushing(com.google.common.base.Predicates.alwaysTrue());
+ }
+
+ public void updateFluidHeightAndDoFluidPushing(Predicate<FluidState> shouldUpdate) {
if (this.m_146899_()) {
- return false;
+ return;
@@ -436,7 +459,7 @@
FluidState fluidstate = this.m_9236_().m_6425_(blockpos$mutableblockpos);
- if (fluidstate.m_205070_(p_204032_)) {
+ net.minecraftforge.fluids.FluidType fluidType = fluidstate.getFluidType();
+ if (!fluidType.isAir()) {
+ if (!fluidType.isAir() && shouldUpdate.test(fluidstate)) {
double d1 = (double)((float)i2 + fluidstate.m_76155_(this.m_9236_(), blockpos$mutableblockpos));
if (d1 >= aabb.f_82289_) {
flag1 = true;
@@ -525,7 +548,7 @@
public float m_274421_() {
return this.f_19793_;
}
@@ -3319,6 +_,103 @@
@@ -3319,6 +_,109 @@
public boolean m_142265_(Level p_146843_, BlockPos p_146844_) {
return true;
}
@@ -593,6 +616,7 @@
+ /**
+ * Accessor method for {@link #getEyeHeight(Pose, EntityDimensions)}
+ */
+ @Deprecated(forRemoval = true, since = "1.20.1") // Remove Entity Eye/Size hooks, as they need to be redesigned
+ public float getEyeHeightAccess(Pose pose, EntityDimensions size) {
+ return this.m_6380_(pose, size);
+ }
@@ -624,6 +648,11 @@
+ return this.forgeFluidTypeHeight.object2DoubleEntrySet().stream().max(java.util.Comparator.comparingDouble(Object2DoubleMap.Entry::getDoubleValue)).map(Object2DoubleMap.Entry::getKey).orElseGet(net.minecraftforge.common.ForgeMod.EMPTY_TYPE);
+ }
+
+ @Deprecated(forRemoval = true, since = "1.20.1") // Remove Entity Eye/Size hooks, as they need to be redesigned
+ public EntityDimensions getDimensionsForge(Pose pose) {
+ return m_6972_(pose);
+ }
+
+ /* ================================== Forge End =====================================*/
+
@@ -16,6 +16,16 @@
public static final int f_147166_ = 2;
public static final int f_147167_ = 4;
public static final int f_147168_ = 98;
@@ -239,7 +_,8 @@
this.f_20885_ = this.m_146908_();
this.m_274367_(0.6F);
NbtOps nbtops = NbtOps.f_128958_;
- this.f_20939_ = this.m_8075_(new Dynamic<>(nbtops, nbtops.createMap(ImmutableMap.of(nbtops.createString("memories"), nbtops.emptyMap()))));
+ var dyn = new Dynamic<>(nbtops, nbtops.createMap(ImmutableMap.of(nbtops.createString("memories"), nbtops.emptyMap())));
+ this.f_20939_ = net.minecraftforge.common.ForgeHooks.onLivingMakeBrain(this, this.m_8075_(dyn), dyn);
}
public Brain<?> m_6274_() {
@@ -273,7 +_,7 @@
}
@@ -43,31 +53,16 @@
public boolean m_6040_() {
return this.m_6336_() == MobType.f_21641_;
}
@@ -352,8 +_,8 @@
@@ -352,6 +_,9 @@
}
}
- if (this.m_204029_(FluidTags.f_13131_) && !this.m_9236_().m_8055_(BlockPos.m_274561_(this.m_20185_(), this.m_20188_(), this.m_20189_())).m_60713_(Blocks.f_50628_)) {
- boolean flag1 = !this.m_6040_() && !MobEffectUtil.m_19588_(this) && (!flag || !((Player)this).m_150110_().f_35934_);
+ if (!this.getEyeInFluidType().isAir() && !this.m_9236_().m_8055_(BlockPos.m_274561_(this.m_20185_(), this.m_20188_(), this.m_20189_())).m_60713_(Blocks.f_50628_)) {
+ boolean flag1 = this.canDrownInFluidType(this.getEyeInFluidType()) && !MobEffectUtil.m_19588_(this) && (!flag || !((Player)this).m_150110_().f_35934_);
+ int airSupply = this.m_20146_();
+ net.minecraftforge.common.ForgeHooks.onLivingBreathe(this, airSupply - m_7302_(airSupply), m_7305_(airSupply) - airSupply);
+ if (false) // Forge: Handled in ForgeHooks#onLivingBreathe(LivingEntity, int, int)
if (this.m_204029_(FluidTags.f_13131_) && !this.m_9236_().m_8055_(BlockPos.m_274561_(this.m_20185_(), this.m_20188_(), this.m_20189_())).m_60713_(Blocks.f_50628_)) {
boolean flag1 = !this.m_6040_() && !MobEffectUtil.m_19588_(this) && (!flag || !((Player)this).m_150110_().f_35934_);
if (flag1) {
this.m_20301_(this.m_7302_(this.m_20146_()));
if (this.m_20146_() == -20) {
@@ -371,10 +_,11 @@
}
}
- if (!this.m_9236_().f_46443_ && this.m_20159_() && this.m_20202_() != null && this.m_20202_().m_275843_()) {
+ if (!this.m_9236_().f_46443_ && this.m_20159_() && this.m_20202_() != null && !this.m_20202_().canBeRiddenUnderFluidType(this.getEyeInFluidType(), this)) {
this.m_8127_();
}
- } else if (this.m_20146_() < this.m_6062_()) {
+ } // Forge: Move to if statement since we need to increase the air supply if in bubble column or can't drown
+ if (this.m_20146_() < this.m_6062_() && (!this.canDrownInFluidType(this.getEyeInFluidType()) || this.m_9236_().m_8055_(BlockPos.m_274561_(this.m_20185_(), this.m_20188_(), this.m_20189_())).m_60713_(Blocks.f_50628_))) {
this.m_20301_(this.m_7305_(this.m_20146_()));
}
@@ -387,7 +_,7 @@
}
}
@@ -77,6 +72,16 @@
this.m_252836_();
}
@@ -734,7 +_,8 @@
}
if (p_21096_.m_128425_("Brain", 10)) {
- this.f_20939_ = this.m_8075_(new Dynamic<>(NbtOps.f_128958_, p_21096_.m_128423_("Brain")));
+ var dyn = new Dynamic<>(NbtOps.f_128958_, p_21096_.m_128423_("Brain"));
+ this.f_20939_ = net.minecraftforge.common.ForgeHooks.onLivingMakeBrain(this, this.m_8075_(dyn), dyn);
}
}
@@ -749,7 +_,7 @@
if (!mobeffectinstance.m_19552_(this, () -> {
this.m_141973_(mobeffectinstance, true, (Entity)null);
@@ -386,6 +391,19 @@
if (!this.f_20911_ || this.f_20913_ >= this.m_21304_() / 2 || this.f_20913_ < 0) {
this.f_20913_ = -1;
this.f_20911_ = true;
@@ -1761,8 +_,10 @@
private void m_21312_() {
ItemStack itemstack = this.m_6844_(EquipmentSlot.OFFHAND);
- this.m_8061_(EquipmentSlot.OFFHAND, this.m_6844_(EquipmentSlot.MAINHAND));
- this.m_8061_(EquipmentSlot.MAINHAND, itemstack);
+ var event = net.minecraftforge.common.ForgeHooks.onLivingSwapHandItems(this);
+ if (event.isCanceled()) return;
+ this.m_8061_(EquipmentSlot.OFFHAND, event.getItemSwappedToOffHand());
+ this.m_8061_(EquipmentSlot.MAINHAND, event.getItemSwappedToMainHand());
}
protected void m_6088_() {
@@ -1955,14 +_,17 @@
}
@@ -0,0 +1,33 @@
--- a/net/minecraft/world/entity/ai/Brain.java
+++ b/net/minecraft/world/entity/ai/Brain.java
@@ -478,6 +_,30 @@
return builder.build();
}
+ public net.minecraftforge.common.util.BrainBuilder<E> createBuilder(){
+ var builder = new net.minecraftforge.common.util.BrainBuilder<>(this);
+ builder.getMemoryTypes().addAll(this.f_21843_.keySet());
+ builder.getSensorTypes().addAll(this.f_21844_.keySet());
+ builder.addAvailableBehaviorsByPriorityFrom(this.f_21845_);
+ builder.setSchedule(this.m_21932_());
+ builder.addActivityRequirementsFrom(this.f_21847_);
+ builder.addActivityMemoriesToEraseWhenStoppedFrom(this.f_21848_);
+ builder.getCoreActivities().addAll(this.f_21849_);
+ builder.setDefaultActivity(this.f_21851_);
+ builder.setActiveActivites(this.f_21850_);
+ return builder;
+ }
+
+ public void copyFromBuilder(net.minecraftforge.common.util.BrainBuilder<E> builder){
+ builder.addAvailableBehaviorsByPriorityTo(this.f_21845_);
+ this.m_21912_(builder.getSchedule());
+ builder.addActivityRequirementsTo(this.f_21847_);
+ builder.addActivityMemoriesToEraseWhenStoppedTo(this.f_21848_);
+ this.m_21930_(builder.getCoreActivities());
+ this.m_21944_(builder.getDefaultActivity());
+ this.f_21850_.addAll(builder.getActiveActivites());
+ }
+
static final class MemoryValue<U> {
private final MemoryModuleType<U> f_22030_;
private final Optional<? extends ExpirableValue<U>> f_22031_;
@@ -1,5 +1,14 @@
--- a/net/minecraft/world/entity/projectile/AbstractArrow.java
+++ b/net/minecraft/world/entity/projectile/AbstractArrow.java
@@ -66,6 +_,8 @@
@Nullable
private List<Entity> f_36702_;
+ private final IntOpenHashSet ignoredEntities = new IntOpenHashSet();
+
protected AbstractArrow(EntityType<? extends AbstractArrow> p_36721_, Level p_36722_) {
super(p_36721_, p_36722_);
}
@@ -150,7 +_,7 @@
--this.f_36706_;
}
@@ -9,14 +18,54 @@
this.m_20095_();
}
@@ -186,7 +_,9 @@
@@ -186,9 +_,28 @@
}
}
- if (hitresult != null && !flag) {
- this.m_6532_(hitresult);
- this.f_19812_ = true;
+ if (hitresult != null && hitresult.m_6662_() != HitResult.Type.MISS && !flag) {
+ if (net.minecraftforge.event.ForgeEventFactory.onProjectileImpact(this, hitresult))
+ break;
this.m_6532_(hitresult);
this.f_19812_ = true;
+ switch (net.minecraftforge.event.ForgeEventFactory.onProjectileImpactResult(this, hitresult)) {
+ case SKIP_ENTITY:
+ if (hitresult.m_6662_() != HitResult.Type.ENTITY) { // If there is no entity, we just return default behaviour
+ this.m_6532_(hitresult);
+ this.f_19812_ = true;
+ break;
+ }
+ ignoredEntities.add(entityhitresult.m_82443_().m_19879_());
+ entityhitresult = null; // Don't process any further
+ break;
+ case STOP_AT_CURRENT_NO_DAMAGE:
+ this.m_146870_();
+ entityhitresult = null; // Don't process any further
+ break;
+ case STOP_AT_CURRENT:
+ this.m_36767_((byte) 0);
+ case DEFAULT:
+ this.m_6532_(hitresult);
+ this.f_19812_ = true;
+ break;
+ }
}
if (entityhitresult == null || this.m_36796_() <= 0) {
@@ -198,6 +_,9 @@
hitresult = null;
}
+ if (this.m_213877_())
+ return;
+
vec3 = this.m_20184_();
double d5 = vec3.f_82479_;
double d6 = vec3.f_82480_;
@@ -422,7 +_,7 @@
}
protected boolean m_5603_(Entity p_36743_) {
- return super.m_5603_(p_36743_) && (this.f_36701_ == null || !this.f_36701_.contains(p_36743_.m_19879_()));
+ return super.m_5603_(p_36743_) && (this.f_36701_ == null || !this.f_36701_.contains(p_36743_.m_19879_())) && !this.ignoredEntities.contains(p_36743_.m_19879_());
}
public void m_7380_(CompoundTag p_36772_) {
@@ -60,7 +60,7 @@
return new IllegalStateException("Unregistered creative tab: " + this);
});
- this.f_256824_.m_257865_(p_270156_, creativemodetab$itemdisplaybuilder);
+ net.minecraftforge.client.ForgeHooksClient.onCreativeModeTabBuildContents(this, resourcekey, this.f_256824_, p_270156_, creativemodetab$itemdisplaybuilder);
+ net.minecraftforge.common.ForgeHooks.onCreativeModeTabBuildContents(this, resourcekey, this.f_256824_, p_270156_, creativemodetab$itemdisplaybuilder);
this.f_243839_ = creativemodetab$itemdisplaybuilder.f_244363_;
this.f_243841_ = creativemodetab$itemdisplaybuilder.f_244585_;
this.m_257466_();
@@ -0,0 +1,40 @@
--- a/net/minecraft/world/item/FireworkRocketItem.java
+++ b/net/minecraft/world/item/FireworkRocketItem.java
@@ -107,7 +_,7 @@
return itemstack;
}
- public static enum Shape {
+ public static enum Shape implements net.minecraftforge.common.IExtensibleEnum {
SMALL_BALL(0, "small_ball"),
LARGE_BALL(1, "large_ball"),
STAR(2, "star"),
@@ -131,8 +_,28 @@
return this.f_41228_;
}
+ public void save(net.minecraft.nbt.CompoundTag tag) {
+ tag.m_128344_("Type", (byte)m_41236_());
+ tag.m_128359_("forge:shape_type", name());
+ }
+
+ /** Use {getShape(ComoundTag)} */
+ @Deprecated
public static FireworkRocketItem.Shape m_41237_(int p_41238_) {
return f_41226_.apply(p_41238_);
+ }
+
+ public static FireworkRocketItem.Shape getShape(net.minecraft.nbt.CompoundTag tag) {
+ var name = tag.m_128425_("forge:shape_type", 8) ? tag.m_128461_("forge:shape_type") : null;
+ if (name == null) return m_41237_(tag.m_128445_("Type"));
+ for (var ret : values())
+ if (ret.name().equals(name))
+ return ret;
+ return SMALL_BALL;
+ }
+
+ public static Shape create(String registryName, int id, String shapeName) {
+ throw new IllegalStateException("Enum not extended");
}
}
}
@@ -0,0 +1,11 @@
--- a/net/minecraft/world/item/FireworkStarItem.java
+++ b/net/minecraft/world/item/FireworkStarItem.java
@@ -23,7 +_,7 @@
}
public static void m_41256_(CompoundTag p_41257_, List<Component> p_41258_) {
- FireworkRocketItem.Shape fireworkrocketitem$shape = FireworkRocketItem.Shape.m_41237_(p_41257_.m_128445_("Type"));
+ FireworkRocketItem.Shape fireworkrocketitem$shape = FireworkRocketItem.Shape.getShape(p_41257_);
p_41258_.add(Component.m_237115_("item.minecraft.firework_star.shape." + fireworkrocketitem$shape.m_41241_()).m_130940_(ChatFormatting.GRAY));
int[] aint = p_41257_.m_128465_("Colors");
if (aint.length > 0) {
@@ -0,0 +1,11 @@
--- a/net/minecraft/world/item/crafting/FireworkStarRecipe.java
+++ b/net/minecraft/world/item/crafting/FireworkStarRecipe.java
@@ -107,7 +_,7 @@
}
compoundtag.m_128408_("Colors", list);
- compoundtag.m_128344_("Type", (byte)fireworkrocketitem$shape.m_41236_());
+ fireworkrocketitem$shape.save(compoundtag);
return itemstack;
}
@@ -0,0 +1,29 @@
--- a/net/minecraft/world/level/levelgen/PhantomSpawner.java
+++ b/net/minecraft/world/level/levelgen/PhantomSpawner.java
@@ -42,19 +_,22 @@
for(ServerPlayer serverplayer : p_64576_.m_6907_()) {
if (!serverplayer.m_5833_()) {
BlockPos blockpos = serverplayer.m_20183_();
- if (!p_64576_.m_6042_().f_223549_() || blockpos.m_123342_() >= p_64576_.m_5736_() && p_64576_.m_45527_(blockpos)) {
- DifficultyInstance difficultyinstance = p_64576_.m_6436_(blockpos);
+ DifficultyInstance difficultyinstance = p_64576_.m_6436_(blockpos);
+ var event = new net.minecraftforge.event.entity.player.PlayerSpawnPhantomsEvent(serverplayer, 1 + randomsource.m_188503_(difficultyinstance.m_19048_().m_19028_() + 1));
+ net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(event);
+ if (event.getResult() == net.minecraftforge.eventbus.api.Event.Result.DENY) continue;
+ if (event.getResult() == net.minecraftforge.eventbus.api.Event.Result.ALLOW || !p_64576_.m_6042_().f_223549_() || blockpos.m_123342_() >= p_64576_.m_5736_() && p_64576_.m_45527_(blockpos)) {
if (difficultyinstance.m_19049_(randomsource.m_188501_() * 3.0F)) {
ServerStatsCounter serverstatscounter = serverplayer.m_8951_();
int j = Mth.m_14045_(serverstatscounter.m_13015_(Stats.f_12988_.m_12902_(Stats.f_12992_)), 1, Integer.MAX_VALUE);
int k = 24000;
- if (randomsource.m_188503_(j) >= 72000) {
+ if (event.getResult() == net.minecraftforge.eventbus.api.Event.Result.ALLOW || randomsource.m_188503_(j) >= 72000) {
BlockPos blockpos1 = blockpos.m_6630_(20 + randomsource.m_188503_(15)).m_122030_(-10 + randomsource.m_188503_(21)).m_122020_(-10 + randomsource.m_188503_(21));
BlockState blockstate = p_64576_.m_8055_(blockpos1);
FluidState fluidstate = p_64576_.m_6425_(blockpos1);
if (NaturalSpawner.m_47056_(p_64576_, blockpos1, blockstate, fluidstate, EntityType.f_20509_)) {
SpawnGroupData spawngroupdata = null;
- int l = 1 + randomsource.m_188503_(difficultyinstance.m_19048_().m_19028_() + 1);
+ int l = event.getPhantomsToSpawn();
for(int i1 = 0; i1 < l; ++i1) {
Phantom phantom = EntityType.f_20509_.m_20615_(p_64576_);
@@ -0,0 +1,11 @@
--- a/net/minecraft/world/level/levelgen/feature/treedecorators/AlterGroundDecorator.java
+++ b/net/minecraft/world/level/levelgen/feature/treedecorators/AlterGroundDecorator.java
@@ -72,7 +_,7 @@
for(int i = 2; i >= -3; --i) {
BlockPos blockpos = p_225975_.m_6630_(i);
if (Feature.m_65788_(p_225974_.m_226058_(), blockpos)) {
- p_225974_.m_226061_(blockpos, this.f_69303_.m_213972_(p_225974_.m_226067_(), p_225975_));
+ p_225974_.m_226061_(blockpos, net.minecraftforge.event.ForgeEventFactory.alterGround(p_225974_.m_226058_(), p_225974_.m_226067_(), blockpos, this.f_69303_.m_213972_(p_225974_.m_226067_(), p_225975_)));
break;
}
@@ -6,7 +6,7 @@
"tag": "forge:rods/wooden"
},
"X": {
"item": "minecraft:string"
"tag": "forge:string"
}
},
"pattern": [
@@ -0,0 +1,20 @@
{
"type": "minecraft:crafting_shaped",
"category": "misc",
"key": {
"H": {
"item": "minecraft:honeycomb"
},
"S": {
"tag": "forge:string"
}
},
"pattern": [
"S",
"H"
],
"result": {
"item": "minecraft:candle"
},
"show_notification": true
}
@@ -12,7 +12,7 @@
"tag": "forge:ingots/iron"
},
"~": {
"item": "minecraft:string"
"tag": "forge:string"
}
},
"pattern": [
@@ -6,7 +6,7 @@
"tag": "forge:rods/wooden"
},
"X": {
"item": "minecraft:string"
"tag": "forge:string"
}
},
"pattern": [
@@ -0,0 +1,22 @@
{
"type": "minecraft:crafting_shaped",
"category": "equipment",
"key": {
"O": {
"item": "minecraft:slime_ball"
},
"~": {
"tag": "forge:string"
}
},
"pattern": [
"~~ ",
"~O ",
" ~"
],
"result": {
"count": 2,
"item": "minecraft:lead"
},
"show_notification": true
}
@@ -0,0 +1,20 @@
{
"type": "minecraft:crafting_shaped",
"category": "misc",
"key": {
"#": {
"tag": "minecraft:planks"
},
"@": {
"tag": "forge:string"
}
},
"pattern": [
"@@",
"##"
],
"result": {
"item": "minecraft:loom"
},
"show_notification": true
}
@@ -0,0 +1,22 @@
{
"type": "minecraft:crafting_shaped",
"category": "misc",
"key": {
"I": {
"item": "minecraft:bamboo"
},
"~": {
"tag": "forge:string"
}
},
"pattern": [
"I~I",
"I I",
"I I"
],
"result": {
"count": 6,
"item": "minecraft:scaffolding"
},
"show_notification": true
}
@@ -0,0 +1,12 @@
{
"textures": [
"minecraft:generic_7",
"minecraft:generic_6",
"minecraft:generic_5",
"minecraft:generic_4",
"minecraft:generic_3",
"minecraft:generic_2",
"minecraft:generic_1",
"minecraft:generic_0"
]
}
@@ -0,0 +1,5 @@
{
"textures": [
"minecraft:drip_hang"
]
}
@@ -0,0 +1,30 @@
{
"textures": [
"minecraft:sga_a",
"minecraft:sga_b",
"minecraft:sga_c",
"minecraft:sga_d",
"minecraft:sga_e",
"minecraft:sga_f",
"minecraft:sga_g",
"minecraft:sga_h",
"minecraft:sga_i",
"minecraft:sga_j",
"minecraft:sga_k",
"minecraft:sga_l",
"minecraft:sga_m",
"minecraft:sga_n",
"minecraft:sga_o",
"minecraft:sga_p",
"minecraft:sga_q",
"minecraft:sga_r",
"minecraft:sga_s",
"minecraft:sga_t",
"minecraft:sga_u",
"minecraft:sga_v",
"minecraft:sga_w",
"minecraft:sga_x",
"minecraft:sga_y",
"minecraft:sga_z"
]
}
@@ -0,0 +1,8 @@
{
"textures": [
"minecraft:splash_0",
"minecraft:splash_1",
"minecraft:splash_2",
"minecraft:splash_3"
]
}
@@ -1,3 +1,14 @@
{
"remove": [
"minecraft:dirt",
"minecraft:oak_door",
"minecraft:dark_oak_door",
"minecraft:anvil",
"minecraft:basalt",
"minecraft:polished_andesite",
"#minecraft:beehives",
"#minecraft:banners",
"#minecraft:beds"
],
"values": []
}
@@ -0,0 +1,6 @@
{
"remove": [
"minecraft:music_disc_cat"
],
"values": []
}
@@ -0,0 +1,6 @@
{
"remove": [
"minecraft:spruce_planks"
],
"values": []
}
@@ -0,0 +1,35 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.client;
import java.util.HashMap;
import java.util.Map;
import org.jetbrains.annotations.Nullable;
import net.minecraft.client.particle.FireworkParticles;
import net.minecraft.world.item.FireworkRocketItem;
/**
* Keeps track of custom firework shape types, because Particle is client side only this can't be on the Shape itself.
* So sometime during your client initalization call register.
*/
public class FireworkShapeFactoryRegistry {
private static final Map<FireworkRocketItem.Shape, Factory> factories = new HashMap<>();
public static interface Factory {
void build(FireworkParticles.Starter starter, boolean trail, boolean flicker, int[] colors, int[] fadecolors);
}
public static void register(FireworkRocketItem.Shape shape, Factory factory) {
factories.put(shape, factory);
}
@Nullable
public static Factory get(FireworkRocketItem.Shape shape) {
return factories.get(shape);
}
}
@@ -12,8 +12,10 @@ import com.mojang.blaze3d.shaders.FogShape;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.SheetedDecalTextureGenerator;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.datafixers.util.Either;
import com.mojang.math.Constants;
import net.minecraft.FileUtil;
import net.minecraft.client.Camera;
import net.minecraft.client.KeyMapping;
@@ -146,6 +148,8 @@ import net.minecraftforge.client.gui.overlay.GuiOverlayManager;
import net.minecraftforge.client.model.data.ModelData;
import net.minecraftforge.client.textures.ForgeTextureMetadata;
import net.minecraftforge.client.textures.TextureAtlasSpriteLoaderManager;
import net.minecraftforge.common.ForgeConfig;
import net.minecraftforge.common.ForgeHooks;
import net.minecraftforge.common.ForgeI18n;
import net.minecraftforge.common.ForgeMod;
import net.minecraftforge.common.MinecraftForge;
@@ -496,21 +500,30 @@ public class ForgeHooksClient
return new Material(TextureAtlas.LOCATION_BLOCKS, loc);
}
public static void fillNormal(int[] faceData, Direction facing)
{
fillNormal(faceData, facing, false);
}
/**
* internal, relies on fixed format of FaceBakery
*/
// TODO Do we need this?
public static void fillNormal(int[] faceData, Direction facing)
public static void fillNormal(int[] faceData, Direction facing, boolean calculateNormals)
{
Vector3f v1 = getVertexPos(faceData, 3);
Vector3f t1 = getVertexPos(faceData, 1);
Vector3f v2 = getVertexPos(faceData, 2);
Vector3f t2 = getVertexPos(faceData, 0);
v1.sub(t1);
v2.sub(t2);
v2.cross(v1);
v2.normalize();
Vector3f v2;
if (calculateNormals || ForgeConfig.CLIENT.calculateAllNormals.get()) {
Vector3f v1 = getVertexPos(faceData, 3);
Vector3f t1 = getVertexPos(faceData, 1);
v2 = getVertexPos(faceData, 2);
Vector3f t2 = getVertexPos(faceData, 0);
v1.sub(t1);
v2.sub(t2);
v2.cross(v1);
v2.normalize();
} else {
v2 = new Vector3f(facing.getNormal().getX(), facing.getNormal().getY(), facing.getNormal().getZ());
}
int x = ((byte) Math.round(v2.x() * 127)) & 0xFF;
int y = ((byte) Math.round(v2.y() * 127)) & 0xFF;
int z = ((byte) Math.round(v2.z() * 127)) & 0xFF;
@@ -1192,27 +1205,46 @@ public class ForgeHooksClient
return new ResourceLocation(loc.getNamespace(), normalised);
}
// Use ForgeHooks.onCreativeModeTabBuildContents()
// since calling this will crash if called on server
@Deprecated(forRemoval = true, since = "1.20.1")
public static void onCreativeModeTabBuildContents(CreativeModeTab tab, ResourceKey<CreativeModeTab> tabKey, CreativeModeTab.DisplayItemsGenerator originalGenerator, CreativeModeTab.ItemDisplayParameters params, CreativeModeTab.Output output)
{
final var entries = new MutableHashedLinkedMap<ItemStack, CreativeModeTab.TabVisibility>(ItemStackLinkedSet.TYPE_AND_TAG,
(key, left, right) -> {
//throw new IllegalStateException("Accidentally adding the same item stack twice " + key.getDisplayName().getString() + " to a Creative Mode Tab: " + tab.getDisplayName().getString());
// Vanilla adds enchanting books twice in both visibilities.
// This is just code cleanliness for them. For us lets just increase the visibility and merge the entries.
return CreativeModeTab.TabVisibility.PARENT_AND_SEARCH_TABS;
}
);
// Bounce to ForgeHooks.onCreativeModeBuildContents(...)
ForgeHooks.onCreativeModeTabBuildContents(tab, tabKey, originalGenerator, params, output);
}
originalGenerator.accept(params, (stack, vis) -> {
if (stack.getCount() != 1)
throw new IllegalArgumentException("The stack count must be 1");
entries.put(stack, vis);
});
ModLoader.get().postEvent(new BuildCreativeModeTabContentsEvent(tab, tabKey, params, entries));
for (var entry : entries)
output.accept(entry.getKey(), entry.getValue());
/**
* This function is a clone of {@link Direction#getNearest(float, float, float)} designed to return a consistent
* direction when the normal is at an inflection point (ie 45 degrees) rounding errors
* from associated matrix multiplication (such as during {@link SheetedDecalTextureGenerator#endVertex()}
* can cause the direction chosen to be unstable.
*
* The function will only take effect if the Forge Client config option "stabilizeDirectionGetNearest" is enabled.
*
* This is a port of the downstream changes from https://github.com/neoforged/NeoForge PR #26
*
* @param nX X component of the normal
* @param nY Y component of the normal
* @param nZ Z component of the normal
* @return the nearest Direction to the passed in normal, biased slightly in favor of the order of declaration
*/
public static Direction getNearestStable(float nX, float nY, float nZ)
{
if (ForgeConfig.CLIENT.stabilizeDirectionGetNearest.get()) {
Direction ret = Direction.NORTH;
float sum = Float.MIN_VALUE;
for(Direction dir : Direction.values()) {
float newSum = nX * (float)dir.getNormal().getX() + nY * (float)dir.getNormal().getY() + nZ * (float)dir.getNormal().getZ();
if (newSum > sum + Constants.EPSILON) {
sum = newSum;
ret = dir;
}
}
return ret;
} else {
return Direction.getNearest(nX, nY, nZ);
}
}
// Make sure the below method is only ever called once (by forge).
@@ -22,8 +22,6 @@ import java.util.List;
import java.util.Map;
import java.util.function.Function;
import static net.minecraft.client.RecipeBookCategories.*;
/**
* Manager for {@link RecipeBookType recipe book types} and {@link RecipeBookCategories categories}.
* <p>
@@ -63,7 +61,13 @@ public final class RecipeBookManager
public static void init()
{
// The ImmutableMap is the patched out value of AGGREGATE_CATEGORIES
var aggregateCategories = new HashMap<>(ImmutableMap.of(CRAFTING_SEARCH, ImmutableList.of(CRAFTING_EQUIPMENT, CRAFTING_BUILDING_BLOCKS, CRAFTING_MISC, CRAFTING_REDSTONE), FURNACE_SEARCH, ImmutableList.of(FURNACE_FOOD, FURNACE_BLOCKS, FURNACE_MISC), BLAST_FURNACE_SEARCH, ImmutableList.of(BLAST_FURNACE_BLOCKS, BLAST_FURNACE_MISC), SMOKER_SEARCH, ImmutableList.of(SMOKER_FOOD)));
var aggregateCategories = new HashMap<>(ImmutableMap.of(
RecipeBookCategories.CRAFTING_SEARCH, ImmutableList.of(RecipeBookCategories.CRAFTING_EQUIPMENT, RecipeBookCategories.CRAFTING_BUILDING_BLOCKS, RecipeBookCategories.CRAFTING_MISC, RecipeBookCategories.CRAFTING_REDSTONE),
RecipeBookCategories.FURNACE_SEARCH, ImmutableList.of(RecipeBookCategories.FURNACE_FOOD, RecipeBookCategories.FURNACE_BLOCKS, RecipeBookCategories.FURNACE_MISC),
RecipeBookCategories.BLAST_FURNACE_SEARCH, ImmutableList.of(RecipeBookCategories.BLAST_FURNACE_BLOCKS, RecipeBookCategories.BLAST_FURNACE_MISC),
RecipeBookCategories.SMOKER_SEARCH, ImmutableList.of(RecipeBookCategories.SMOKER_FOOD)
));
var typeCategories = new HashMap<RecipeBookType, ImmutableList<RecipeBookCategories>>();
var recipeCategoryLookups = new HashMap<RecipeType<?>, Function<Recipe<?>, RecipeBookCategories>>();
var event = new RegisterRecipeBookCategoriesEvent(aggregateCategories, typeCategories, recipeCategoryLookups);
@@ -67,15 +67,15 @@ public interface IForgeDimensionSpecialEffects
* Allows for manipulating the coloring of the lightmap texture.
* Will be called for each 16*16 combination of sky/block light values.
*
* @param level The current level (client-side).
* @param partialTicks Progress between ticks.
* @param skyDarken Current darkness of the sky.
* @param skyLight Sky light brightness factor.
* @param blockLight Block light brightness factor.
* @param pixelX X-coordinate of the lightmap texture.
* @param pixelY Y-coordinate of the lightmap texture.
* @param colors The color values that will be used: [r, g, b].
* @param level The current level (client-side).
* @param partialTicks Progress between ticks.
* @param skyDarken Current darkness of the sky (can be used to calculate sky light).
* @param blockLightRedFlicker Block light flicker factor (red color) (can be used to calculate block light).
* @param skyLight Sky light brightness (accounting for sky darkness).
* @param pixelX X-coordinate of the lightmap texture (block).
* @param pixelY Y-coordinate of the lightmap texture (sky).
* @param colors The color values that will be used: [r, g, b].
* @see LightTexture#updateLightTexture(float)
*/
default void adjustLightmapColors(ClientLevel level, float partialTicks, float skyDarken, float skyLight, float blockLight, int pixelX, int pixelY, Vector3f colors) {}
default void adjustLightmapColors(ClientLevel level, float partialTicks, float skyDarken, float blockLightRedFlicker, float skyLight, int pixelX, int pixelY, Vector3f colors) {}
}
@@ -136,4 +136,63 @@ public interface IForgeGuiGraphics
self().blit(texture, x, y, boundsWidth, boundsHeight, 0.0f,0.0f, rectWidth, rectHeight, rectWidth, rectHeight);
}
/**
* Version of {@link GuiGraphics#blitNineSliced(ResourceLocation, int, int, int, int, int, int, int, int, int)} that supports specifying the texture's size.
*/
default void blitNineSlicedSized(ResourceLocation texture, int x, int y, int width, int height, int sliceSize, int uWidth, int vHeight, int uOffset, int vOffset,
int textureWidth, int textureHeight)
{
blitNineSlicedSized(texture, x, y, width, height, sliceSize, sliceSize, uWidth, vHeight, uOffset, vOffset, textureWidth, textureHeight);
}
/**
* Version of {@link GuiGraphics#blitNineSliced(ResourceLocation, int, int, int, int, int, int, int, int, int, int)} that supports specifying the texture's size.
*/
default void blitNineSlicedSized(ResourceLocation texture, int x, int y, int width, int height, int sliceWidth, int sliceHeight, int uWidth, int vHeight,
int uOffset, int vOffset, int textureWidth, int textureHeight)
{
blitNineSlicedSized(texture, x, y, width, height, sliceWidth, sliceHeight, sliceWidth, sliceHeight, uWidth, vHeight, uOffset, vOffset, textureWidth, textureHeight);
}
/**
* Version of {@link GuiGraphics#blitNineSliced(ResourceLocation, int, int, int, int, int, int, int, int, int, int, int, int)} that supports specifying the texture's size.
*/
default void blitNineSlicedSized(ResourceLocation texture, int x, int y, int width, int height, int cornerWidth, int cornerHeight, int edgeWidth, int edgeHeight,
int uWidth, int vHeight, int uOffset, int vOffset, int textureWidth, int textureHeight)
{
cornerWidth = Math.min(cornerWidth, width / 2);
edgeWidth = Math.min(edgeWidth, width / 2);
cornerHeight = Math.min(cornerHeight, height / 2);
edgeHeight = Math.min(edgeHeight, height / 2);
GuiGraphics self = self();
if (width == uWidth && height == vHeight)
{
self.blit(texture, x, y, uOffset, vOffset, width, height, textureWidth, textureHeight);
}
else if (height == vHeight)
{
self.blit(texture, x, y, uOffset, vOffset, cornerWidth, height, textureWidth, textureHeight);
self.blitRepeating(texture, x + cornerWidth, y, width - edgeWidth - cornerWidth, height, uOffset + cornerWidth, vOffset, uWidth - edgeWidth - cornerWidth, vHeight, textureWidth, textureHeight);
self.blit(texture, x + width - edgeWidth, y, uOffset + uWidth - edgeWidth, vOffset, edgeWidth, height, textureWidth, textureHeight);
}
else if (width == uWidth)
{
self.blit(texture, x, y, uOffset, vOffset, width, cornerHeight, textureWidth, textureHeight);
self.blitRepeating(texture, x, y + cornerHeight, width, height - edgeHeight - cornerHeight, uOffset, vOffset + cornerHeight, uWidth, vHeight - edgeHeight - cornerHeight, textureWidth, textureHeight);
self.blit(texture, x, y + height - edgeHeight, uOffset, vOffset + vHeight - edgeHeight, width, edgeHeight, textureWidth, textureHeight);
}
else
{
self.blit(texture, x, y, uOffset, vOffset, cornerWidth, cornerHeight, textureWidth, textureHeight);
self.blitRepeating(texture, x + cornerWidth, y, width - edgeWidth - cornerWidth, cornerHeight, uOffset + cornerWidth, vOffset, uWidth - edgeWidth - cornerWidth, cornerHeight, textureWidth, textureHeight);
self.blit(texture, x + width - edgeWidth, y, uOffset + uWidth - edgeWidth, vOffset, edgeWidth, cornerHeight, textureWidth, textureHeight);
self.blit(texture, x, y + height - edgeHeight, uOffset, vOffset + vHeight - edgeHeight, cornerWidth, edgeHeight, textureWidth, textureHeight);
self.blitRepeating(texture, x + cornerWidth, y + height - edgeHeight, width - edgeWidth - cornerWidth, edgeHeight, uOffset + cornerWidth, vOffset + vHeight - edgeHeight, uWidth - edgeWidth - cornerWidth, edgeHeight, textureWidth, textureHeight);
self.blit(texture, x + width - edgeWidth, y + height - edgeHeight, uOffset + uWidth - edgeWidth, vOffset + vHeight - edgeHeight, edgeWidth, edgeHeight, textureWidth, textureHeight);
self.blitRepeating(texture, x, y + cornerHeight, cornerWidth, height - edgeHeight - cornerHeight, uOffset, vOffset + cornerHeight, cornerWidth, vHeight - edgeHeight - cornerHeight, textureWidth, textureHeight);
self.blitRepeating(texture, x + cornerWidth, y + cornerHeight, width - edgeWidth - cornerWidth, height - edgeHeight - cornerHeight, uOffset + cornerWidth, vOffset + cornerHeight, uWidth - edgeWidth - cornerWidth, vHeight - edgeHeight - cornerHeight, textureWidth, textureHeight);
self.blitRepeating(texture, x + width - edgeWidth, y + cornerHeight, cornerWidth, height - edgeHeight - cornerHeight, uOffset + uWidth - edgeWidth, vOffset + cornerHeight, edgeWidth, vHeight - edgeHeight - cornerHeight, textureWidth, textureHeight);
}
}
}
@@ -5,6 +5,7 @@
package net.minecraftforge.client.extensions.common;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.particle.ParticleEngine;
import net.minecraft.core.BlockPos;
import net.minecraft.tags.FluidTags;
@@ -15,6 +16,7 @@ import net.minecraft.world.item.enchantment.EnchantmentHelper;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.phys.HitResult;
@@ -113,4 +115,17 @@ public interface IClientBlockExtensions
}
return originalColor;
}
/**
* Returns true if the breaking particles created from the {@link BlockState} passed should be tinted with biome colors.
*
* @param state The state of this block
* @param level The level the particles are spawning in
* @param pos The position of the block
* @return {@code true} if the particles should be tinted.
*/
default boolean areBreakingParticlesTinted(BlockState state, ClientLevel level, BlockPos pos)
{
return !state.is(Blocks.GRASS_BLOCK);
}
}
@@ -474,6 +474,13 @@ public class ForgeGui extends Gui
}
}
@Override
public void clearCache()
{
super.clearCache();
this.debugOverlay.clearChunkCache();
}
protected void renderRecordOverlay(int width, int height, float partialTick, GuiGraphics guiGraphics)
{
if (overlayMessageTime > 0)
@@ -485,8 +492,12 @@ public class ForgeGui extends Gui
if (opacity > 8)
{
//Include a shift based on the bar height plus the difference between the height that renderSelectedItemName
// renders at (59) and the height that the overlay/status bar renders at (68) by default
int yShift = Math.max(leftHeight, rightHeight) + (68 - 59);
guiGraphics.pose().pushPose();
guiGraphics.pose().translate(width / 2D, height - 68, 0.0D);
//If y shift is smaller less than the default y level, just render it at the base y level
guiGraphics.pose().translate(width / 2D, height - Math.max(yShift, 68), 0.0D);
RenderSystem.enableBlend();
RenderSystem.defaultBlendFunc();
int color = (animateOverlayMessageColor ? Mth.hsvToRgb(hue / 50.0F, 0.7F, 0.6F) & WHITE : WHITE);
@@ -144,7 +144,7 @@ public enum VanillaGuiOverlay
gui.setupOverlayRenderState(true, false);
if (gui.getMinecraft().gameMode.getPlayerMode() != GameType.SPECTATOR)
{
gui.renderSelectedItemName(guiGraphics);
gui.renderSelectedItemName(guiGraphics, Math.max(gui.leftHeight, gui.rightHeight));
}
else if (gui.getMinecraft().player.isSpectator())
{
@@ -5,11 +5,11 @@
package net.minecraftforge.client.loading;
import static net.minecraftforge.fml.Logging.CORE;
import static net.minecraftforge.fml.Logging.LOADING;
import java.io.File;
import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.*;
import java.util.function.Consumer;
@@ -34,11 +34,8 @@ import net.minecraftforge.resource.PathPackResources;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.SharedConstants;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.ClientPackSource;
import net.minecraft.util.profiling.ProfilerFiller;
import net.minecraft.server.packs.PackType;
import net.minecraft.server.packs.metadata.pack.PackMetadataSection;
@@ -121,7 +118,7 @@ public class ClientModLoader
public static boolean completeModLoading()
{
List<ModLoadingWarning> warnings = ModLoader.get().getWarnings();
var warnings = ModLoader.get().getWarnings();
boolean showWarnings = true;
try {
showWarnings = ForgeConfig.CLIENT.showLoadWarnings.get();
@@ -131,8 +128,8 @@ public class ClientModLoader
if (!showWarnings) {
//User disabled warning screen, as least log them
if (!warnings.isEmpty()) {
LOGGER.warn(LOADING, "Mods loaded with {} warning(s)", warnings.size());
warnings.forEach(warning -> LOGGER.warn(LOADING, warning.formatToString()));
LOGGER.warn(Logging.LOADING, "Mods loaded with {} warning(s)", warnings.size());
warnings.forEach(warning -> LOGGER.warn(Logging.LOADING, warning.formatToString()));
}
warnings = Collections.emptyList(); //Clear warnings, as the user does not want to see them
}
@@ -163,7 +160,7 @@ public class ClientModLoader
}
private static void clientPackFinder(Map<IModFile, ? extends PathPackResources> modResourcePacks, Consumer<Pack> packAcceptor) {
List<PathPackResources> hiddenPacks = new ArrayList<>();
var hiddenPacks = new ArrayList<PathPackResources>();
for (Entry<IModFile, ? extends PathPackResources> e : modResourcePacks.entrySet())
{
IModInfo mod = e.getKey().getModInfos().get(0);
@@ -174,7 +171,7 @@ public class ClientModLoader
ModLoader.get().addWarning(new ModLoadingWarning(mod, ModLoadingStage.ERROR, "fml.modloading.brokenresources", e.getKey()));
continue;
}
LOGGER.debug(CORE, "Generating PackInfo named {} for mod file {}", name, e.getKey().getFilePath());
LOGGER.debug(Logging.CORE, "Generating PackInfo named {} for mod file {}", name, e.getKey().getFilePath());
if (mod.getOwningFile().showAsResourcePack()) {
packAcceptor.accept(modPack);
} else {
@@ -5,6 +5,7 @@
package net.minecraftforge.client.loading;
import com.mojang.blaze3d.platform.GlConst;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.BufferBuilder;
@@ -21,22 +22,19 @@ import net.minecraft.client.gui.screens.LoadingOverlay;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.ReloadInstance;
import net.minecraft.util.Mth;
import net.minecraftforge.fml.StartupMessageManager;
import net.minecraftforge.fml.earlydisplay.ColourScheme;
import net.minecraftforge.fml.earlydisplay.DisplayWindow;
import net.minecraftforge.fml.loading.progress.ProgressMeter;
import org.jetbrains.annotations.NotNull;
import org.joml.Matrix4f;
import org.lwjgl.opengl.GL30C;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Supplier;
import static com.mojang.blaze3d.platform.GlConst.*;
import static net.minecraft.util.Mth.clamp;
import static org.lwjgl.opengl.GL30C.glViewport;
import static org.lwjgl.opengl.GL30C.glTexParameterIi;
/**
* This is an implementation of the LoadingOverlay that calls back into the early window rendering, as part of the
* game loading cycle. We completely replace the {@link #render(GuiGraphics, int, int, float)} call from the parent
@@ -71,8 +69,8 @@ public class ForgeLoadingOverlay extends LoadingOverlay {
public void render(final @NotNull GuiGraphics graphics, final int mouseX, final int mouseY, final float partialTick) {
long millis = Util.getMillis();
float fadeouttimer = this.fadeOutStart > -1L ? (float)(millis - this.fadeOutStart) / 1000.0F : -1.0F;
progress.setAbsolute(clamp((int)(this.reload.getActualProgress() * 100f), 0, 100));
var fade = 1.0F - clamp(fadeouttimer - 1.0F, 0.0F, 1.0F);
progress.setAbsolute(Mth.clamp((int)(this.reload.getActualProgress() * 100f), 0, 100));
var fade = 1.0F - Mth.clamp(fadeouttimer - 1.0F, 0.0F, 1.0F);
var colour = this.displayWindow.context().colourScheme().background();
RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, fade);
if (fadeouttimer >= 1.0F) {
@@ -82,24 +80,24 @@ public class ForgeLoadingOverlay extends LoadingOverlay {
displayWindow.render(0xff);
} else {
GlStateManager._clearColor(colour.redf(), colour.greenf(), colour.bluef(), 1f);
GlStateManager._clear(GL_COLOR_BUFFER_BIT, Minecraft.ON_OSX);
GlStateManager._clear(GlConst.GL_COLOR_BUFFER_BIT, Minecraft.ON_OSX);
displayWindow.render(0xFF);
}
RenderSystem.enableBlend();
RenderSystem.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
RenderSystem.blendFunc(GlConst.GL_SRC_ALPHA, GlConst.GL_ONE_MINUS_SRC_ALPHA);
var fbWidth = this.minecraft.getWindow().getWidth();
var fbHeight = this.minecraft.getWindow().getHeight();
glViewport(0, 0, fbWidth, fbHeight);
GL30C.glViewport(0, 0, fbWidth, fbHeight);
final var twidth = this.displayWindow.context().width();
final var theight = this.displayWindow.context().height();
var wscale = (float)fbWidth / twidth;
var hscale = (float)fbHeight / theight;
var scale = this.displayWindow.context().scale() * Math.min(wscale, hscale) / 2f;
var wleft = clamp(fbWidth * 0.5f - scale * twidth, 0, fbWidth);
var wtop = clamp(fbHeight * 0.5f - scale * theight, 0, fbHeight);
var wright = clamp(fbWidth * 0.5f + scale * twidth, 0, fbWidth);
var wbottom = clamp(fbHeight * 0.5f + scale * theight, 0, fbHeight);
GlStateManager.glActiveTexture(GL_TEXTURE0);
var wleft = Mth.clamp(fbWidth * 0.5f - scale * twidth, 0, fbWidth);
var wtop = Mth.clamp(fbHeight * 0.5f - scale * theight, 0, fbHeight);
var wright = Mth.clamp(fbWidth * 0.5f + scale * twidth, 0, fbWidth);
var wbottom = Mth.clamp(fbHeight * 0.5f + scale * theight, 0, fbHeight);
GlStateManager.glActiveTexture(GlConst.GL_TEXTURE0);
RenderSystem.disableCull();
BufferBuilder bufferbuilder = Tesselator.getInstance().getBuilder();
RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, fade);
@@ -120,7 +118,7 @@ public class ForgeLoadingOverlay extends LoadingOverlay {
// This is the actual screen data from the loading screen
RenderSystem.enableBlend();
RenderSystem.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
RenderSystem.blendFunc(GlConst.GL_SRC_ALPHA, GlConst.GL_ONE_MINUS_SRC_ALPHA);
RenderSystem.setShader(GameRenderer::getPositionTexColorShader);
RenderSystem.setShaderTexture(0, displayWindow.getFramebufferTextureId());
bufferbuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX_COLOR);
@@ -128,8 +126,8 @@ public class ForgeLoadingOverlay extends LoadingOverlay {
bufferbuilder.vertex(wright, wbottom, 0f).uv(1, 0).color(1f, 1f, 1f, fade).endVertex();
bufferbuilder.vertex(wright, wtop, 0f).uv(1, 1).color(1f, 1f, 1f, fade).endVertex();
bufferbuilder.vertex(wleft, wtop, 0f).uv(0, 1).color(1f, 1f, 1f, fade).endVertex();
glTexParameterIi(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterIi(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
GL30C.glTexParameterIi(GlConst.GL_TEXTURE_2D, GlConst.GL_TEXTURE_MIN_FILTER, GlConst.GL_NEAREST);
GL30C.glTexParameterIi(GlConst.GL_TEXTURE_2D, GlConst.GL_TEXTURE_MAG_FILTER, GlConst.GL_NEAREST);
BufferUploader.drawWithShader(bufferbuilder.end());
RenderSystem.defaultBlendFunc();
RenderSystem.disableBlend();
@@ -11,14 +11,18 @@ import net.minecraft.client.gui.screens.LoadingOverlay;
import net.minecraft.server.packs.resources.ReloadInstance;
import java.util.Optional;
import java.util.function.*;
import java.util.function.Consumer;
import java.util.function.IntConsumer;
import java.util.function.IntSupplier;
import java.util.function.LongSupplier;
import java.util.function.Supplier;
import static org.lwjgl.glfw.GLFW.*;
import org.lwjgl.glfw.GLFW;
public final class NoVizFallback {
private static long WINDOW;
public static LongSupplier windowHandoff(IntSupplier width, IntSupplier height, Supplier<String> title, LongSupplier monitor) {
return () -> WINDOW = glfwCreateWindow(width.getAsInt(), height.getAsInt(), title.get(), monitor.getAsLong(), 0L);
return () -> WINDOW = GLFW.glfwCreateWindow(width.getAsInt(), height.getAsInt(), title.get(), monitor.getAsLong(), 0L);
}
public static Supplier<LoadingOverlay> loadingOverlay(Supplier<Minecraft> mc, Supplier<ReloadInstance> ri, Consumer<Optional<Throwable>> ex, boolean fadein) {
@@ -31,8 +35,8 @@ public final class NoVizFallback {
public static String glVersion() {
if (WINDOW != 0) {
var maj = glfwGetWindowAttrib(WINDOW, GLFW_CONTEXT_VERSION_MAJOR);
var min = glfwGetWindowAttrib(WINDOW, GLFW_CONTEXT_VERSION_MINOR);
var maj = GLFW.glfwGetWindowAttrib(WINDOW, GLFW.GLFW_CONTEXT_VERSION_MAJOR);
var min = GLFW.glfwGetWindowAttrib(WINDOW, GLFW.GLFW_CONTEXT_VERSION_MINOR);
return maj+"."+min;
} else {
return "3.2";
@@ -28,11 +28,16 @@ import net.minecraft.util.ExtraCodecs;
* @param blockLight Block Light for this face from 0-15 (inclusive)
* @param skyLight Sky Light for this face from 0-15 (inclusive)
* @param ambientOcclusion If this face has AO
* @param calculateNormals If we should manually calculate the normals for this block or inherit facing normals like vanilla
*/
public record ForgeFaceData(int color, int blockLight, int skyLight, boolean ambientOcclusion)
public record ForgeFaceData(int color, int blockLight, int skyLight, boolean ambientOcclusion, boolean calculateNormals)
{
public ForgeFaceData(int color, int blockLight, int skyLight, boolean ambientOcclusion)
{
this(color, blockLight, skyLight, ambientOcclusion, false);
}
public static final ForgeFaceData DEFAULT = new ForgeFaceData(0xFFFFFFFF, 0, 0, true);
public static final ForgeFaceData DEFAULT = new ForgeFaceData(0xFFFFFFFF, 0, 0, true, false);
public static final Codec<Integer> COLOR = new ExtraCodecs.EitherCodec<>(Codec.INT, Codec.STRING).xmap(
either -> either.map(Function.identity(), str -> (int) Long.parseLong(str, 16)),
@@ -42,7 +47,8 @@ public record ForgeFaceData(int color, int blockLight, int skyLight, boolean amb
COLOR.optionalFieldOf("color", 0xFFFFFFFF).forGetter(ForgeFaceData::color),
Codec.intRange(0, 15).optionalFieldOf("block_light", 0).forGetter(ForgeFaceData::blockLight),
Codec.intRange(0, 15).optionalFieldOf("sky_light", 0).forGetter(ForgeFaceData::skyLight),
Codec.BOOL.optionalFieldOf("ambient_occlusion", true).forGetter(ForgeFaceData::ambientOcclusion))
Codec.BOOL.optionalFieldOf("ambient_occlusion", true).forGetter(ForgeFaceData::ambientOcclusion),
Codec.BOOL.optionalFieldOf("calculate_normals", false).forGetter(ForgeFaceData::calculateNormals))
.apply(builder, ForgeFaceData::new));
/**
@@ -388,6 +388,7 @@ public class ModelBuilder<T extends ModelBuilder<T>> extends ModelFile {
private int color = 0xFFFFFFFF;
private int blockLight = 0, skyLight = 0;
private boolean hasAmbientOcclusion = true;
private boolean calculateNormals = false;
private void validateCoordinate(float coord, char name) {
Preconditions.checkArgument(!(coord < -16.0F) && !(coord > 32.0F), "Position " + name + " out of range, must be within [-16, 32]. Found: %d", coord);
@@ -556,6 +557,17 @@ public class ModelBuilder<T extends ModelBuilder<T>> extends ModelFile {
return this;
}
/**
* Sets whether we should calculate actual normals for the faces of this model or inherit them from facing the
* way vanilla does
* @param calc whether to calculate normals
* @return this builder
*/
public ElementBuilder calculateNormals(boolean calc) {
this.calculateNormals = calc;
return this;
}
private BiConsumer<Direction, FaceBuilder> addTexture(String texture) {
return ($, f) -> f.texture(texture);
}
@@ -563,7 +575,7 @@ public class ModelBuilder<T extends ModelBuilder<T>> extends ModelFile {
BlockElement build() {
Map<Direction, BlockElementFace> faces = this.faces.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().build(), (k1, k2) -> { throw new IllegalArgumentException(); }, LinkedHashMap::new));
return new BlockElement(from, to, faces, rotation == null ? null : rotation.build(), shade, new ForgeFaceData(this.color, this.blockLight, this.skyLight, this.hasAmbientOcclusion));
return new BlockElement(from, to, faces, rotation == null ? null : rotation.build(), shade, new ForgeFaceData(this.color, this.blockLight, this.skyLight, this.hasAmbientOcclusion, this.calculateNormals));
}
public T end() { return self(); }
@@ -578,6 +590,7 @@ public class ModelBuilder<T extends ModelBuilder<T>> extends ModelFile {
private int color = 0xFFFFFFFF;
private int blockLight = 0, skyLight = 0;
private boolean hasAmbientOcclusion = true;
private boolean calculateNormals = false;
FaceBuilder(Direction dir) {
// param unused for functional match
@@ -660,11 +673,22 @@ public class ModelBuilder<T extends ModelBuilder<T>> extends ModelFile {
return this;
}
/**
* Sets whether we should calculate actual normals for this face or inherit them from facing the
* way vanilla does
* @param calc whether to calculate normals
* @return this builder
*/
public FaceBuilder calculateNormals(boolean calc) {
this.calculateNormals = calc;
return this;
}
BlockElementFace build() {
if (this.texture == null) {
throw new IllegalStateException("A model face must have a texture");
}
return new BlockElementFace(cullface, tintindex, texture, new BlockFaceUV(uvs, rotation.rotation), new ForgeFaceData(this.color, this.blockLight, this.skyLight, this.hasAmbientOcclusion));
return new BlockElementFace(cullface, tintindex, texture, new BlockFaceUV(uvs, rotation.rotation), new ForgeFaceData(this.color, this.blockLight, this.skyLight, this.hasAmbientOcclusion, this.calculateNormals));
}
public ElementBuilder end() { return ElementBuilder.this; }
@@ -60,7 +60,7 @@ public class ItemLayerModelBuilder<T extends ModelBuilder<T>> extends CustomLoad
{
faceData.compute(i, (key, value) -> {
ForgeFaceData fallback = value == null ? ForgeFaceData.DEFAULT : value;
return new ForgeFaceData(fallback.color(), blockLight, skyLight, fallback.ambientOcclusion());
return new ForgeFaceData(fallback.color(), blockLight, skyLight, fallback.ambientOcclusion(), fallback.calculateNormals());
});
}
return this;
@@ -85,7 +85,7 @@ public class ItemLayerModelBuilder<T extends ModelBuilder<T>> extends CustomLoad
{
faceData.compute(i, (key, value) -> {
ForgeFaceData fallback = value == null ? ForgeFaceData.DEFAULT : value;
return new ForgeFaceData(color, fallback.blockLight(), fallback.skyLight(), fallback.ambientOcclusion());
return new ForgeFaceData(color, fallback.blockLight(), fallback.skyLight(), fallback.ambientOcclusion(), fallback.calculateNormals());
});
}
return this;
@@ -38,7 +38,7 @@ public class FlatQuadLighter extends QuadLighter
isFullCube = Block.isShapeFullBlock(state.getCollisionShape(level, pos));
for (Direction side : SIDES)
{
packedLight[side.ordinal()] = getLightColor(level, pos.relative(side), state);
packedLight[side.ordinal()] = LevelRenderer.getLightColor(level, state, pos.relative(side));
}
//Note: We can just use the LevelRenderer method as we know the state is the state at the given position
packedLight[6] = LevelRenderer.getLightColor(level, state, pos);
@@ -14,12 +14,12 @@ import net.minecraft.core.BlockPos;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.LightLayer;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.client.model.IQuadTransformer;
import org.joml.Vector3f;
import java.util.Objects;
import static net.minecraftforge.client.model.IQuadTransformer.*;
/**
* Base class for all quad lighting providers.
* <p>
@@ -84,15 +84,15 @@ public abstract class QuadLighter
var vertices = quad.getVertices();
for (int i = 0; i < 4; i++)
{
int offset = i * STRIDE;
positions[i][0] = Float.intBitsToFloat(vertices[offset + POSITION]);
positions[i][1] = Float.intBitsToFloat(vertices[offset + POSITION + 1]);
positions[i][2] = Float.intBitsToFloat(vertices[offset + POSITION + 2]);
int packedNormal = vertices[offset + NORMAL];
int offset = i * IQuadTransformer.STRIDE;
positions[i][0] = Float.intBitsToFloat(vertices[offset + IQuadTransformer.POSITION]);
positions[i][1] = Float.intBitsToFloat(vertices[offset + IQuadTransformer.POSITION + 1]);
positions[i][2] = Float.intBitsToFloat(vertices[offset + IQuadTransformer.POSITION + 2]);
int packedNormal = vertices[offset + IQuadTransformer.NORMAL];
normals[i][0] = (byte) (packedNormal & 0xFF);
normals[i][1] = (byte) ((packedNormal >> 8) & 0xFF);
normals[i][2] = (byte) ((packedNormal >> 16) & 0xFF);
packedLightmaps[i] = vertices[offset + UV2];
packedLightmaps[i] = vertices[offset + IQuadTransformer.UV2];
}
if (normals[0][0] == 0 && normals[0][1] == 0 && normals[0][2] == 0)
{
@@ -158,6 +158,7 @@ public abstract class QuadLighter
* as it only uses the state for querying if the state has emissive rendering but instead looks up the state at the given position for checking the
* light emission.
*/
@Deprecated(since = "1.20.1")
protected static int getLightColor(BlockAndTintGetter level, BlockPos pos, BlockState state)
{
if (state.emissiveRendering(level, pos))
@@ -50,7 +50,7 @@ public class SmoothQuadLighter extends QuadLighter
pos.setWithOffset(origin, x - 1, y - 1, z - 1);
BlockState neighborState = level.getBlockState(pos);
t[x][y][z] = neighborState.getLightBlock(level, pos) < 15;
int brightness = getLightColor(level, pos, state);
int brightness = LevelRenderer.getLightColor(level, neighborState, pos);
s[x][y][z] = LightTexture.sky(brightness);
b[x][y][z] = LightTexture.block(brightness);
ao[x][y][z] = neighborState.getShadeBrightness(level, pos);
@@ -13,14 +13,13 @@ import net.minecraft.Util;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.core.Direction;
import net.minecraftforge.client.model.IQuadTransformer;
import net.minecraftforge.client.textures.UnitTextureAtlasSprite;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.function.Consumer;
import static net.minecraftforge.client.model.IQuadTransformer.*;
/**
* Vertex consumer that outputs {@linkplain BakedQuad baked quads}.
* <p>
@@ -34,7 +33,7 @@ public class QuadBakingVertexConsumer implements VertexConsumer
for (var element : DefaultVertexFormat.BLOCK.getElements())
map.put(element, DefaultVertexFormat.BLOCK.getOffset(i++) / 4); // Int offset
});
private static final int QUAD_DATA_SIZE = STRIDE * 4;
private static final int QUAD_DATA_SIZE = IQuadTransformer.STRIDE * 4;
private final Consumer<BakedQuad> quadConsumer;
@@ -55,7 +54,7 @@ public class QuadBakingVertexConsumer implements VertexConsumer
@Override
public VertexConsumer vertex(double x, double y, double z)
{
int offset = vertexIndex * STRIDE + POSITION;
int offset = vertexIndex * IQuadTransformer.STRIDE + IQuadTransformer.POSITION;
quadData[offset] = Float.floatToRawIntBits((float) x);
quadData[offset + 1] = Float.floatToRawIntBits((float) y);
quadData[offset + 2] = Float.floatToRawIntBits((float) z);
@@ -65,7 +64,7 @@ public class QuadBakingVertexConsumer implements VertexConsumer
@Override
public VertexConsumer normal(float x, float y, float z)
{
int offset = vertexIndex * STRIDE + NORMAL;
int offset = vertexIndex * IQuadTransformer.STRIDE + IQuadTransformer.NORMAL;
quadData[offset] = ((int) (x * 127.0f) & 0xFF) |
(((int) (y * 127.0f) & 0xFF) << 8) |
(((int) (z * 127.0f) & 0xFF) << 16);
@@ -75,7 +74,7 @@ public class QuadBakingVertexConsumer implements VertexConsumer
@Override
public VertexConsumer color(int r, int g, int b, int a)
{
int offset = vertexIndex * STRIDE + COLOR;
int offset = vertexIndex * IQuadTransformer.STRIDE + IQuadTransformer.COLOR;
quadData[offset] = ((a & 0xFF) << 24) |
((b & 0xFF) << 16) |
((g & 0xFF) << 8) |
@@ -86,7 +85,7 @@ public class QuadBakingVertexConsumer implements VertexConsumer
@Override
public VertexConsumer uv(float u, float v)
{
int offset = vertexIndex * STRIDE + UV0;
int offset = vertexIndex * IQuadTransformer.STRIDE + IQuadTransformer.UV0;
quadData[offset] = Float.floatToRawIntBits(u);
quadData[offset + 1] = Float.floatToRawIntBits(v);
return this;
@@ -95,9 +94,9 @@ public class QuadBakingVertexConsumer implements VertexConsumer
@Override
public VertexConsumer overlayCoords(int u, int v)
{
if (UV1 >= 0) // Vanilla doesn't support this, but it may be added by a 3rd party
if (IQuadTransformer.UV1 >= 0) // Vanilla doesn't support this, but it may be added by a 3rd party
{
int offset = vertexIndex * STRIDE + UV1;
int offset = vertexIndex * IQuadTransformer.STRIDE + IQuadTransformer.UV1;
quadData[offset] = (u & 0xFFFF) | ((v & 0xFFFF) << 16);
}
return this;
@@ -106,7 +105,7 @@ public class QuadBakingVertexConsumer implements VertexConsumer
@Override
public VertexConsumer uv2(int u, int v)
{
int offset = vertexIndex * STRIDE + UV2;
int offset = vertexIndex * IQuadTransformer.STRIDE + IQuadTransformer.UV2;
quadData[offset] = (u & 0xFFFF) | ((v & 0xFFFF) << 16);
return this;
}
@@ -117,7 +116,7 @@ public class QuadBakingVertexConsumer implements VertexConsumer
Integer baseOffset = ELEMENT_OFFSETS.get(element);
if (baseOffset != null)
{
int offset = vertexIndex * STRIDE + baseOffset;
int offset = vertexIndex * IQuadTransformer.STRIDE + baseOffset;
System.arraycopy(rawData, 0, quadData, offset, rawData.length);
}
return this;
@@ -27,6 +27,8 @@ public class KeyMappingLookup
}
}
/** Replaced by {@link #getAll(InputConstants.Key) getAll} */
@Deprecated(forRemoval = true, since = "1.20.1")
@Nullable
public KeyMapping get(InputConstants.Key keyCode)
{
@@ -43,6 +45,7 @@ public class KeyMappingLookup
}
@Nullable
@Deprecated(forRemoval = true, since = "1.20.1")
private KeyMapping get(InputConstants.Key keyCode, KeyModifier keyModifier)
{
Collection<KeyMapping> bindings = map.get(keyModifier).get(keyCode);
@@ -59,6 +62,13 @@ public class KeyMappingLookup
return null;
}
/**
* Returns all active keys associated with the given key code and the active
* modifiers and conflict context.
*
* @param keyCode the key being pressed
* @return the list of key mappings
*/
public List<KeyMapping> getAll(InputConstants.Key keyCode)
{
List<KeyMapping> matchingBindings = new ArrayList<KeyMapping>();
@@ -5,9 +5,8 @@
package net.minecraftforge.common;
import static net.minecraftforge.fml.Logging.FORGEMOD;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.Logging;
import net.minecraftforge.fml.event.config.ModConfigEvent;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.logging.log4j.LogManager;
@@ -16,7 +15,6 @@ import net.minecraftforge.common.ForgeConfigSpec.BooleanValue;
import net.minecraftforge.common.ForgeConfigSpec.DoubleValue;
import net.minecraftforge.common.ForgeConfigSpec.ConfigValue;
public class ForgeConfig {
public static class Server {
public final BooleanValue removeErroringBlockEntities;
@@ -30,6 +28,8 @@ public class ForgeConfig {
public final ConfigValue<String> permissionHandler;
public final BooleanValue advertiseDedicatedServerToLan;
Server(ForgeConfigSpec.Builder builder) {
builder.comment("Server configuration settings")
.push("server");
@@ -69,6 +69,11 @@ public class ForgeConfig {
.translation("forge.configgui.permissionHandler")
.define("permissionHandler", "forge:default_handler");
advertiseDedicatedServerToLan = builder
.comment("Set this to true to enable advertising the dedicated server to local LAN clients so that it shows up in the Multiplayer screen automatically.")
.translation("forge.configgui.advertiseDedicatedServerToLan")
.define("advertiseDedicatedServerToLan", true);
builder.pop();
}
}
@@ -98,8 +103,14 @@ public class ForgeConfig {
public final BooleanValue useCombinedDepthStencilAttachment;
@Deprecated(since = "1.20.1", forRemoval = true) // Config option ignored.
public final BooleanValue compressLanIPv6Addresses;
public final BooleanValue calculateAllNormals;
public final BooleanValue stabilizeDirectionGetNearest;
Client(ForgeConfigSpec.Builder builder) {
builder.comment("Client only settings, mostly things related to rendering")
.push("client");
@@ -127,10 +138,24 @@ public class ForgeConfig {
.define("useCombinedDepthStencilAttachment", false);
compressLanIPv6Addresses = builder
.comment("When enabled, Forge will convert discovered 'Open to LAN' IPv6 addresses to their more compact, compressed representation")
.comment("[DEPRECATED] Does nothing anymore, IPv6 addresses will be compressed always")
.translation("forge.configgui.compressLanIPv6Addresses")
.define("compressLanIPv6Addresses", true);
calculateAllNormals = builder
.comment("During block model baking, manually calculates the normal for all faces.",
"This was the default behavior of forge between versions 31.0 and 47.1.",
"May result in differences between vanilla rendering and forge rendering.",
"Will only produce differences for blocks that contain non-axis aligned faces.",
"You will need to reload your resources to see results.")
.translation("forge.configgui.calculateAllNormals")
.define("calculateAllNormals", false);
stabilizeDirectionGetNearest = builder
.comment("When enabled, a slightly biased Direction#getNearest calculation will be used to prevent normal fighting on 45 degree angle faces.")
.translation("forge.configgui.stabilizeDirectionGetNearest")
.define("stabilizeDirectionGetNearest", true);
builder.pop();
}
}
@@ -163,12 +188,12 @@ public class ForgeConfig {
@SubscribeEvent
public static void onLoad(final ModConfigEvent.Loading configEvent) {
LogManager.getLogger().debug(FORGEMOD, "Loaded forge config file {}", configEvent.getConfig().getFileName());
LogManager.getLogger().debug(Logging.FORGEMOD, "Loaded forge config file {}", configEvent.getConfig().getFileName());
}
@SubscribeEvent
public static void onFileChange(final ModConfigEvent.Reloading configEvent) {
LogManager.getLogger().debug(FORGEMOD, "Forge config just got changed on the file system!");
LogManager.getLogger().debug(Logging.FORGEMOD, "Forge config just got changed on the file system!");
}
//General
@@ -5,11 +5,6 @@
package net.minecraftforge.common;
import static com.electronwill.nightconfig.core.ConfigSpec.CorrectionAction.ADD;
import static com.electronwill.nightconfig.core.ConfigSpec.CorrectionAction.REMOVE;
import static com.electronwill.nightconfig.core.ConfigSpec.CorrectionAction.REPLACE;
import static net.minecraftforge.fml.Logging.CORE;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -26,6 +21,7 @@ import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import net.minecraftforge.fml.Logging;
import net.minecraftforge.fml.config.IConfigSpec;
import net.minecraftforge.fml.loading.FMLEnvironment;
import org.apache.commons.lang3.tuple.Pair;
@@ -82,12 +78,12 @@ public class ForgeConfigSpec extends UnmodifiableConfigWrapper<UnmodifiableConfi
this.childConfig = config;
if (config != null && !isCorrect(config)) {
String configName = config instanceof FileConfig ? ((FileConfig) config).getNioPath().toString() : config.toString();
LOGGER.warn(CORE, "Configuration file {} is not correct. Correcting", configName);
LOGGER.warn(Logging.CORE, "Configuration file {} is not correct. Correcting", configName);
correct(config,
(action, path, incorrectValue, correctedValue) ->
LOGGER.warn(CORE, "Incorrect key {} was corrected from {} to its default, {}. {}", DOT_JOINER.join( path ), incorrectValue, correctedValue, incorrectValue == correctedValue ? "This seems to be an error." : ""),
LOGGER.warn(Logging.CORE, "Incorrect key {} was corrected from {} to its default, {}. {}", DOT_JOINER.join( path ), incorrectValue, correctedValue, incorrectValue == correctedValue ? "This seems to be an error." : ""),
(action, path, incorrectValue, correctedValue) ->
LOGGER.debug(CORE, "The comment on key {} does not match the spec. This may create a backup.", DOT_JOINER.join( path )));
LOGGER.debug(Logging.CORE, "The comment on key {} does not match the spec. This may create a backup.", DOT_JOINER.join( path )));
if (config instanceof FileConfig) {
((FileConfig) config).save();
@@ -178,7 +174,7 @@ public class ForgeConfigSpec extends UnmodifiableConfigWrapper<UnmodifiableConfi
final String key = specEntry.getKey();
final Object specValue = specEntry.getValue();
final Object configValue = configMap.get(key);
final CorrectionAction action = configValue == null ? ADD : REPLACE;
final CorrectionAction action = configValue == null ? CorrectionAction.ADD : CorrectionAction.REPLACE;
parentPath.addLast(key);
@@ -256,7 +252,7 @@ public class ForgeConfigSpec extends UnmodifiableConfigWrapper<UnmodifiableConfi
ittr.remove();
parentPath.addLast(entry.getKey());
listener.onCorrect(REMOVE, parentPathUnmodifiable, entry.getValue(), null);
listener.onCorrect(CorrectionAction.REMOVE, parentPathUnmodifiable, entry.getValue(), null);
parentPath.removeLast();
count++;
}
@@ -367,13 +363,13 @@ public class ForgeConfigSpec extends UnmodifiableConfigWrapper<UnmodifiableConfi
@Override
public Object correct(Object value) {
if (value == null || !(value instanceof List) || ((List<?>)value).isEmpty()) {
LOGGER.debug(CORE, "List on key {} is deemed to need correction. It is null, not a list, or an empty list. Modders, consider defineListAllowEmpty?", path.get(path.size() - 1));
LOGGER.debug(Logging.CORE, "List on key {} is deemed to need correction. It is null, not a list, or an empty list. Modders, consider defineListAllowEmpty?", path.get(path.size() - 1));
return getDefault();
}
List<?> list = Lists.newArrayList((List<?>) value);
list.removeIf(elementValidator.negate());
if (list.isEmpty()) {
LOGGER.debug(CORE, "List on key {} is deemed to need correction. It failed validation.", path.get(path.size() - 1));
LOGGER.debug(Logging.CORE, "List on key {} is deemed to need correction. It failed validation.", path.get(path.size() - 1));
return getDefault();
}
return list;
@@ -395,13 +391,13 @@ public class ForgeConfigSpec extends UnmodifiableConfigWrapper<UnmodifiableConfi
@Override
public Object correct(Object value) {
if (value == null || !(value instanceof List)) {
LOGGER.debug(CORE, "List on key {} is deemed to need correction, as it is null or not a list.", path.get(path.size() - 1));
LOGGER.debug(Logging.CORE, "List on key {} is deemed to need correction, as it is null or not a list.", path.get(path.size() - 1));
return getDefault();
}
List<?> list = Lists.newArrayList((List<?>) value);
list.removeIf(elementValidator.negate());
if (list.isEmpty()) {
LOGGER.debug(CORE, "List on key {} is deemed to need correction. It failed validation.", path.get(path.size() - 1));
LOGGER.debug(Logging.CORE, "List on key {} is deemed to need correction. It failed validation.", path.get(path.size() - 1));
return getDefault();
}
return list;
@@ -654,7 +650,7 @@ public class ForgeConfigSpec extends UnmodifiableConfigWrapper<UnmodifiableConfi
if (comment.stream().allMatch(String::isBlank))
{
if (FMLEnvironment.production)
LOGGER.warn(CORE, "Detected a comment that is all whitespace for config option {}, which causes obscure bugs in Forge's config system and will cause a crash in the future. Please report this to the mod author.",
LOGGER.warn(Logging.CORE, "Detected a comment that is all whitespace for config option {}, which causes obscure bugs in Forge's config system and will cause a crash in the future. Please report this to the mod author.",
DOT_JOINER.join(path));
else
throw new IllegalStateException("Can not build comment for config option " + DOT_JOINER.join(path) + " as it comprises entirely of blank lines/whitespace. This is not allowed as it causes a \"constantly correcting config\" bug with NightConfig in Forge's config system.");
@@ -730,7 +726,7 @@ public class ForgeConfigSpec extends UnmodifiableConfigWrapper<UnmodifiableConfi
boolean result = ((Number)min).doubleValue() <= n.doubleValue() && n.doubleValue() <= ((Number)max).doubleValue();
if(!result)
{
LOGGER.debug(CORE, "Range value {} is not within its bounds {}-{}", n.doubleValue(), ((Number)min).doubleValue(), ((Number)max).doubleValue());
LOGGER.debug(Logging.CORE, "Range value {} is not within its bounds {}-{}", n.doubleValue(), ((Number)min).doubleValue(), ((Number)max).doubleValue());
}
return result;
}
@@ -740,7 +736,7 @@ public class ForgeConfigSpec extends UnmodifiableConfigWrapper<UnmodifiableConfi
boolean result = c.compareTo(min) >= 0 && c.compareTo(max) <= 0;
if(!result)
{
LOGGER.debug(CORE, "Range value {} is not within its bounds {}-{}", c, min, max);
LOGGER.debug(Logging.CORE, "Range value {} is not within its bounds {}-{}", c, min, max);
}
return result;
}
@@ -35,6 +35,7 @@ import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.mojang.serialization.Dynamic;
import com.mojang.serialization.Lifecycle;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
@@ -47,6 +48,7 @@ import net.minecraft.core.Direction;
import net.minecraft.core.Holder;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.HolderSet;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.chat.ChatDecorator;
import net.minecraft.network.chat.ClickEvent;
@@ -70,11 +72,13 @@ import net.minecraft.world.Difficulty;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.effect.MobEffect;
import net.minecraft.world.effect.MobEffectUtil;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.ExperienceOrb;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.Brain;
import net.minecraft.world.entity.ai.attributes.Attribute;
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
@@ -89,6 +93,7 @@ import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.RecipeType;
import net.minecraft.world.item.enchantment.Enchantments;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.level.material.Fluids;
import net.minecraft.world.level.storage.LevelStorageSource;
@@ -108,6 +113,7 @@ import net.minecraft.nbt.ListTag;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.syncher.EntityDataSerializer;
import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket;
import net.minecraft.network.protocol.game.ServerboundPlayerActionPacket;
import net.minecraft.world.item.alchemy.Potion;
import net.minecraft.world.item.alchemy.PotionUtils;
import net.minecraft.stats.Stats;
@@ -125,9 +131,12 @@ import net.minecraftforge.common.loot.IGlobalLootModifier;
import net.minecraftforge.common.loot.LootModifierManager;
import net.minecraftforge.common.loot.LootTableIdCondition;
import net.minecraftforge.common.util.BlockSnapshot;
import net.minecraftforge.common.util.BrainBuilder;
import net.minecraftforge.common.util.Lazy;
import net.minecraftforge.common.util.MavenVersionStringHelper;
import net.minecraftforge.common.util.MutableHashedLinkedMap;
import net.minecraftforge.event.AnvilUpdateEvent;
import net.minecraftforge.event.BuildCreativeModeTabContentsEvent;
import net.minecraftforge.event.DifficultyChangeEvent;
import net.minecraftforge.event.ForgeEventFactory;
import net.minecraftforge.event.GrindstoneEvent;
@@ -144,10 +153,12 @@ import net.minecraftforge.event.entity.EntityTravelToDimensionEvent;
import net.minecraftforge.event.entity.item.ItemTossEvent;
import net.minecraftforge.event.entity.living.EnderManAngerEvent;
import net.minecraftforge.event.entity.living.LivingAttackEvent;
import net.minecraftforge.event.entity.living.LivingBreatheEvent;
import net.minecraftforge.event.entity.living.LivingChangeTargetEvent;
import net.minecraftforge.event.entity.living.LivingDamageEvent;
import net.minecraftforge.event.entity.living.LivingDeathEvent;
import net.minecraftforge.event.entity.living.LivingDropsEvent;
import net.minecraftforge.event.entity.living.LivingDrownEvent;
import net.minecraftforge.event.entity.living.LivingEvent;
import net.minecraftforge.event.entity.living.LivingEvent.LivingJumpEvent;
import net.minecraftforge.event.entity.living.LivingEvent.LivingTickEvent;
@@ -155,6 +166,8 @@ import net.minecraftforge.event.entity.living.LivingChangeTargetEvent.ILivingTar
import net.minecraftforge.event.entity.living.LivingFallEvent;
import net.minecraftforge.event.entity.living.LivingHurtEvent;
import net.minecraftforge.event.entity.living.LivingKnockBackEvent;
import net.minecraftforge.event.entity.living.LivingMakeBrainEvent;
import net.minecraftforge.event.entity.living.LivingSwapItemsEvent;
import net.minecraftforge.event.entity.living.LivingUseTotemEvent;
import net.minecraftforge.event.entity.living.LootingLevelEvent;
import net.minecraftforge.event.entity.living.ShieldBlockEvent;
@@ -238,6 +251,14 @@ public class ForgeHooks
return event;
}
public static Brain<?> onLivingMakeBrain(LivingEntity entity, Brain<?> originalBrain, Dynamic<?> dynamic)
{
BrainBuilder<?> brainBuilder = originalBrain.createBuilder();
LivingMakeBrainEvent event = new LivingMakeBrainEvent(entity, brainBuilder);
MinecraftForge.EVENT_BUS.post(event);
return brainBuilder.makeBrain(dynamic);
}
public static boolean onLivingTick(LivingEntity entity)
{
return MinecraftForge.EVENT_BUS.post(new LivingTickEvent(entity));
@@ -751,9 +772,25 @@ public class ForgeHooks
return evt.isCanceled() ? evt.getCancellationResult() : null;
}
/**
* @deprecated Use {@link #onLeftClickBlock(Player, BlockPos, Direction, ServerboundPlayerActionPacket.Action)} instead
*/
@Deprecated(since = "1.20.1", forRemoval = true)
public static PlayerInteractEvent.LeftClickBlock onLeftClickBlock(Player player, BlockPos pos, Direction face)
{
PlayerInteractEvent.LeftClickBlock evt = new PlayerInteractEvent.LeftClickBlock(player, pos, face);
return onLeftClickBlock(player, pos, face, ServerboundPlayerActionPacket.Action.START_DESTROY_BLOCK);
}
public static PlayerInteractEvent.LeftClickBlock onLeftClickBlock(Player player, BlockPos pos, Direction face, ServerboundPlayerActionPacket.Action action)
{
PlayerInteractEvent.LeftClickBlock evt = new PlayerInteractEvent.LeftClickBlock(player, pos, face, PlayerInteractEvent.LeftClickBlock.Action.convert(action));
MinecraftForge.EVENT_BUS.post(evt);
return evt;
}
public static PlayerInteractEvent.LeftClickBlock onClientMineHold(Player player, BlockPos pos, Direction face)
{
PlayerInteractEvent.LeftClickBlock evt = new PlayerInteractEvent.LeftClickBlock(player, pos, face, PlayerInteractEvent.LeftClickBlock.Action.CLIENT_HOLD);
MinecraftForge.EVENT_BUS.post(evt);
return evt;
}
@@ -1046,22 +1083,8 @@ public class ForgeHooks
return false;
}
public static <T> void deserializeTagAdditions(List<TagEntry> list, JsonObject json, List<TagEntry> allList)
{
if (json.has("remove"))
{
for (JsonElement entry : GsonHelper.getAsJsonArray(json, "remove"))
{
String s = GsonHelper.convertToString(entry, "value");
TagEntry dummy;
if (!s.startsWith("#"))
dummy = TagEntry.optionalElement(new ResourceLocation(s));
else
dummy = TagEntry.tag(new ResourceLocation(s.substring(1)));
allList.removeIf(e -> e.equals(dummy));
}
}
}
@Deprecated(forRemoval = true, since = "1.20.1") // Tags use a codec now This was never used in 1.20
public static <T> void deserializeTagAdditions(List<TagEntry> list, JsonObject json, List<TagEntry> allList) {}
@Nullable
public static EntityDataSerializer<?> getSerializer(int id, CrudeIncrementalIntIdentityHashBiMap<EntityDataSerializer<?>> vanilla)
@@ -1221,6 +1244,13 @@ public class ForgeHooks
return e;
}
public static LivingSwapItemsEvent.Hands onLivingSwapHandItems(LivingEntity livingEntity)
{
LivingSwapItemsEvent.Hands event = new LivingSwapItemsEvent.Hands(livingEntity);
MinecraftForge.EVENT_BUS.post(event);
return event;
}
public static void writeAdditionalLevelSaveData(WorldData worldData, CompoundTag levelTag)
{
CompoundTag fmlData = new CompoundTag();
@@ -1526,4 +1556,83 @@ public class ForgeHooks
@Override public Optional<HolderSet.Named<T>> get(TagKey<T> key) { return Optional.of(HolderSet.emptyNamed(lookup, key)); }
};
}
/**
* Handles living entities being under water. This fires the {@link LivingBreatheEvent} and if the entity's air supply
* is less than or equal to zero also the {@link LivingDrownEvent}. Additionally when the entity is under water it will
* dismount if {@link IForgeEntity#canBeRiddenUnderFluidType(FluidType, Entity)} returns false.
*
* @param entity The living entity which is currently updated
* @param consumeAirAmount The amount of air to consume when the entity is unable to breathe
* @param refillAirAmount The amount of air to refill when the entity is able to breathe
* @implNote This method needs to closely replicate the logic found right after the call site in {@link LivingEntity#baseTick()} as it overrides it.
*/
public static void onLivingBreathe(LivingEntity entity, int consumeAirAmount, int refillAirAmount)
{
// Check things that vanilla considers to be air - these will cause the air supply to be increased.
boolean isAir = entity.getEyeInFluidType().isAir() || entity.level().getBlockState(BlockPos.containing(entity.getX(), entity.getEyeY(), entity.getZ())).is(Blocks.BUBBLE_COLUMN);
// The following effects cause the entity to not drown, but do not cause the air supply to be increased.
boolean canBreathe = !entity.canDrownInFluidType(entity.getEyeInFluidType()) || MobEffectUtil.hasWaterBreathing(entity) || (entity instanceof Player && ((Player) entity).getAbilities().invulnerable);
LivingBreatheEvent breatheEvent = new LivingBreatheEvent(entity, isAir || canBreathe, consumeAirAmount, refillAirAmount, isAir);
MinecraftForge.EVENT_BUS.post(breatheEvent);
if (breatheEvent.canBreathe())
{
if (breatheEvent.canRefillAir())
{
entity.setAirSupply(Math.min(entity.getAirSupply() + breatheEvent.getRefillAirAmount(), entity.getMaxAirSupply()));
}
}
else
{
entity.setAirSupply(entity.getAirSupply() - breatheEvent.getConsumeAirAmount());
}
if (entity.getAirSupply() <= 0)
{
LivingDrownEvent drownEvent = new LivingDrownEvent(entity, entity.getAirSupply() <= -20, 2.0F, 8);
if (!MinecraftForge.EVENT_BUS.post(drownEvent) && drownEvent.isDrowning())
{
entity.setAirSupply(0);
Vec3 vec3 = entity.getDeltaMovement();
for (int i = 0; i < drownEvent.getBubbleCount(); ++i)
{
double d2 = entity.getRandom().nextDouble() - entity.getRandom().nextDouble();
double d3 = entity.getRandom().nextDouble() - entity.getRandom().nextDouble();
double d4 = entity.getRandom().nextDouble() - entity.getRandom().nextDouble();
entity.level().addParticle(ParticleTypes.BUBBLE, entity.getX() + d2, entity.getY() + d3, entity.getZ() + d4, vec3.x, vec3.y, vec3.z);
}
if (drownEvent.getDamageAmount() > 0) entity.hurt(entity.damageSources().drown(), drownEvent.getDamageAmount());
}
}
if (!isAir && !entity.level().isClientSide && entity.isPassenger() && entity.getVehicle() != null && !entity.getVehicle().canBeRiddenUnderFluidType(entity.getEyeInFluidType(), entity))
{
entity.stopRiding();
}
}
public static void onCreativeModeTabBuildContents(CreativeModeTab tab, ResourceKey<CreativeModeTab> tabKey, CreativeModeTab.DisplayItemsGenerator originalGenerator, CreativeModeTab.ItemDisplayParameters params, CreativeModeTab.Output output)
{
final var entries = new MutableHashedLinkedMap<ItemStack, CreativeModeTab.TabVisibility>(ItemStackLinkedSet.TYPE_AND_TAG,
(key, left, right) -> {
//throw new IllegalStateException("Accidentally adding the same item stack twice " + key.getDisplayName().getString() + " to a Creative Mode Tab: " + tab.getDisplayName().getString());
// Vanilla adds enchanting books twice in both visibilities.
// This is just code cleanliness for them. For us lets just increase the visibility and merge the entries.
return CreativeModeTab.TabVisibility.PARENT_AND_SEARCH_TABS;
}
);
originalGenerator.accept(params, (stack, vis) -> {
if (stack.getCount() != 1)
throw new IllegalArgumentException("The stack count must be 1");
entries.put(stack, vis);
});
ModLoader.get().postEvent(new BuildCreativeModeTabContentsEvent(tab, tabKey, params, entries));
for (var entry : entries)
output.accept(entry.getKey(), entry.getValue());
}
}
@@ -7,6 +7,7 @@ package net.minecraftforge.common;
import com.google.common.base.CharMatcher;
import net.minecraftforge.common.util.MavenVersionStringHelper;
import net.minecraftforge.fml.Logging;
import net.minecraftforge.fml.loading.StringUtils;
import net.minecraftforge.forgespi.language.IModInfo;
import org.apache.commons.lang3.text.ExtendedMessageFormat;
@@ -23,8 +24,6 @@ import java.util.Objects;
import java.util.function.BiConsumer;
import java.util.regex.Pattern;
import static net.minecraftforge.fml.Logging.CORE;
//TODO, this should be re-evaluated now that ITextComponents are passed everywhere instaed of strings.
public class ForgeI18n {
private static final Logger LOGGER = LogManager.getLogger();
@@ -81,7 +80,7 @@ public class ForgeI18n {
}
public static void loadLanguageData(final Map<String, String> properties) {
LOGGER.debug(CORE,"Loading I18N data entries: {}", properties.size());
LOGGER.debug(Logging.CORE,"Loading I18N data entries: {}", properties.size());
i18n = properties;
}
@@ -90,7 +89,7 @@ public class ForgeI18n {
try {
return parseFormat(pattern, args);
} catch (IllegalArgumentException e) {
LOGGER.error(CORE,"Illegal format found `{}`", pattern);
LOGGER.error(Logging.CORE,"Illegal format found `{}`", pattern);
return pattern;
}
}
@@ -5,10 +5,8 @@
package net.minecraftforge.common;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.BiomeTags;
import net.minecraft.tags.BlockTags;
import net.minecraft.tags.FluidTags;
import net.minecraft.tags.ItemTags;
@@ -19,7 +17,6 @@ import net.minecraft.world.item.Item;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.material.Fluid;
import net.minecraftforge.registries.ForgeRegistries;
public class Tags
{
@@ -5,6 +5,7 @@
package net.minecraftforge.common.capabilities;
import net.minecraftforge.fml.Logging;
import net.minecraftforge.fml.ModLoader;
import net.minecraftforge.forgespi.language.ModFileScanData;
import org.apache.logging.log4j.LogManager;
@@ -15,8 +16,6 @@ import java.util.Comparator;
import java.util.IdentityHashMap;
import java.util.List;
import static net.minecraftforge.fml.Logging.CAPABILITIES;
public enum CapabilityManager
{
INSTANCE;
@@ -46,7 +45,7 @@ public enum CapabilityManager
{
if (cap.isRegistered())
{
LOGGER.error(CAPABILITIES, "Cannot register capability implementation multiple times : {}", realName);
LOGGER.error(Logging.CAPABILITIES, "Cannot register capability implementation multiple times : {}", realName);
throw new IllegalArgumentException("Cannot register a capability implementation multiple times : "+ realName);
}
else
@@ -74,7 +73,7 @@ public enum CapabilityManager
for (var auto : autos)
{
LOGGER.debug(CAPABILITIES, "Attempting to automatically register: " + auto);
LOGGER.debug(Logging.CAPABILITIES, "Attempting to automatically register: " + auto);
get(auto.getInternalName(), true);
}
@@ -10,8 +10,6 @@ import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandlerItem;
import net.minecraftforge.items.IItemHandler;
import static net.minecraftforge.common.capabilities.CapabilityManager.get;
/*
* References to Forge's built in capabilities.
* Modders are recommended to use their own CapabilityTokens for 3rd party caps to maintain soft dependencies.
@@ -19,8 +17,8 @@ import static net.minecraftforge.common.capabilities.CapabilityManager.get;
*/
public class ForgeCapabilities
{
public static final Capability<IEnergyStorage> ENERGY = get(new CapabilityToken<>(){});
public static final Capability<IFluidHandler> FLUID_HANDLER = get(new CapabilityToken<>(){});
public static final Capability<IFluidHandlerItem> FLUID_HANDLER_ITEM = get(new CapabilityToken<>(){});
public static final Capability<IItemHandler> ITEM_HANDLER = get(new CapabilityToken<>(){});
public static final Capability<IEnergyStorage> ENERGY = CapabilityManager.get(new CapabilityToken<>(){});
public static final Capability<IFluidHandler> FLUID_HANDLER = CapabilityManager.get(new CapabilityToken<>(){});
public static final Capability<IFluidHandlerItem> FLUID_HANDLER_ITEM = CapabilityManager.get(new CapabilityToken<>(){});
public static final Capability<IItemHandler> ITEM_HANDLER = CapabilityManager.get(new CapabilityToken<>(){});
}
@@ -6,9 +6,7 @@
package net.minecraftforge.common.data;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.registries.Registries;
import net.minecraft.data.PackOutput;
import net.minecraft.data.tags.IntrinsicHolderTagsProvider;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.BlockTags;
import net.minecraft.tags.TagKey;
@@ -23,6 +21,7 @@ import java.util.Locale;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
// We typically don't do static imports as S2S can't remap them {as they are not qualified}, however this conflicts with vanilla and our tag class names, and our tags don't get obfed so its one line of warning.
import static net.minecraftforge.common.Tags.Blocks.*;
public final class ForgeBlockTagsProvider extends BlockTagsProvider
@@ -9,11 +9,10 @@ import net.minecraft.core.HolderLookup;
import net.minecraft.data.PackOutput;
import net.minecraft.data.tags.FluidTagsProvider;
import net.minecraftforge.common.ForgeMod;
import net.minecraftforge.common.Tags.Fluids;
import java.util.concurrent.CompletableFuture;
import static net.minecraftforge.common.Tags.Fluids.MILK;
public final class ForgeFluidTagsProvider extends FluidTagsProvider
{
public ForgeFluidTagsProvider(PackOutput output, CompletableFuture<HolderLookup.Provider> lookupProvider, ExistingFileHelper existingFileHelper)
@@ -24,7 +23,7 @@ public final class ForgeFluidTagsProvider extends FluidTagsProvider
@Override
public void addTags(HolderLookup.Provider lookupProvider)
{
tag(MILK).addOptional(ForgeMod.MILK.getId()).addOptional(ForgeMod.FLOWING_MILK.getId());
tag(Fluids.MILK).addOptional(ForgeMod.MILK.getId()).addOptional(ForgeMod.FLOWING_MILK.getId());
}
@Override
@@ -29,34 +29,37 @@ import net.minecraftforge.registries.ForgeRegistries;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Field;
import java.nio.file.Path;
import java.util.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
public final class ForgeRecipeProvider extends VanillaRecipeProvider
{
public final class ForgeRecipeProvider extends VanillaRecipeProvider {
private final Map<Item, TagKey<Item>> replacements = new HashMap<>();
private final Set<ResourceLocation> excludes = new HashSet<>();
public ForgeRecipeProvider(PackOutput packOutput)
{
public ForgeRecipeProvider(PackOutput packOutput) {
super(packOutput);
}
private void exclude(ItemLike item)
{
private void exclude(ItemLike item) {
excludes.add(ForgeRegistries.ITEMS.getKey(item.asItem()));
}
private void replace(ItemLike item, TagKey<Item> tag)
{
private void exclude(String name) {
excludes.add(new ResourceLocation(name));
}
private void replace(ItemLike item, TagKey<Item> tag) {
replacements.put(item.asItem(), tag);
}
@Override
protected void buildRecipes(Consumer<FinishedRecipe> consumer)
{
protected void buildRecipes(Consumer<FinishedRecipe> consumer) {
replace(Items.STICK, Tags.Items.RODS_WOODEN);
replace(Items.GOLD_INGOT, Tags.Items.INGOTS_GOLD);
replace(Items.IRON_INGOT, Tags.Items.INGOTS_IRON);
@@ -69,6 +72,9 @@ public final class ForgeRecipeProvider extends VanillaRecipeProvider
replace(Blocks.COBBLESTONE, Tags.Items.COBBLESTONE_NORMAL);
replace(Blocks.COBBLED_DEEPSLATE, Tags.Items.COBBLESTONE_DEEPSLATE);
replace(Items.STRING, Tags.Items.STRING);
exclude(getConversionRecipeName(Blocks.WHITE_WOOL, Items.STRING));
exclude(Blocks.GOLD_BLOCK);
exclude(Items.GOLD_NUGGET);
exclude(Blocks.IRON_BLOCK);
@@ -94,8 +100,7 @@ public final class ForgeRecipeProvider extends VanillaRecipeProvider
}
@Nullable
private FinishedRecipe enhance(FinishedRecipe vanilla)
{
private FinishedRecipe enhance(FinishedRecipe vanilla) {
if (vanilla instanceof ShapelessRecipeBuilder.Result shapeless)
return enhance(shapeless);
if (vanilla instanceof ShapedRecipeBuilder.Result shaped)
@@ -104,15 +109,12 @@ public final class ForgeRecipeProvider extends VanillaRecipeProvider
}
@Nullable
private FinishedRecipe enhance(ShapelessRecipeBuilder.Result vanilla)
{
private FinishedRecipe enhance(ShapelessRecipeBuilder.Result vanilla) {
List<Ingredient> ingredients = getField(ShapelessRecipeBuilder.Result.class, vanilla, 4);
boolean modified = false;
for (int x = 0; x < ingredients.size(); x++)
{
for (int x = 0; x < ingredients.size(); x++) {
Ingredient ing = enhance(vanilla.getId(), ingredients.get(x));
if (ing != null)
{
if (ing != null) {
ingredients.set(x, ing);
modified = true;
}
@@ -122,29 +124,24 @@ public final class ForgeRecipeProvider extends VanillaRecipeProvider
@Nullable
@Override
protected CompletableFuture<?> saveAdvancement(CachedOutput output, FinishedRecipe finishedRecipe, JsonObject advancementJson)
{
protected CompletableFuture<?> saveAdvancement(CachedOutput output, FinishedRecipe recipe, JsonObject json) {
// NOOP - We don't replace any of the advancement things yet...
return null;
}
@Override
protected CompletableFuture<?> buildAdvancement(CachedOutput p_253674_, ResourceLocation p_254102_, Advancement.Builder p_253712_)
{
protected CompletableFuture<?> buildAdvancement(CachedOutput output, ResourceLocation name, Advancement.Builder builder) {
// NOOP - We don't replace any of the advancement things yet...
return CompletableFuture.allOf();
}
@Nullable
private FinishedRecipe enhance(ShapedRecipeBuilder.Result vanilla)
{
private FinishedRecipe enhance(ShapedRecipeBuilder.Result vanilla) {
Map<Character, Ingredient> ingredients = getField(ShapedRecipeBuilder.Result.class, vanilla, 5);
boolean modified = false;
for (Character x : ingredients.keySet())
{
for (Character x : ingredients.keySet()) {
Ingredient ing = enhance(vanilla.getId(), ingredients.get(x));
if (ing != null)
{
if (ing != null) {
ingredients.put(x, ing);
modified = true;
}
@@ -153,22 +150,18 @@ public final class ForgeRecipeProvider extends VanillaRecipeProvider
}
@Nullable
private Ingredient enhance(ResourceLocation name, Ingredient vanilla)
{
private Ingredient enhance(ResourceLocation name, Ingredient vanilla) {
if (excludes.contains(name))
return null;
boolean modified = false;
List<Value> items = new ArrayList<>();
Value[] vanillaItems = getField(Ingredient.class, vanilla, 2); //This will probably crash between versions, if null fix index
for (Value entry : vanillaItems)
{
if (entry instanceof ItemValue)
{
for (Value entry : vanillaItems) {
if (entry instanceof ItemValue) {
ItemStack stack = entry.getItems().stream().findFirst().orElse(ItemStack.EMPTY);
TagKey<Item> replacement = replacements.get(stack.getItem());
if (replacement != null)
{
if (replacement != null) {
items.add(new TagValue(replacement));
modified = true;
} else
@@ -180,15 +173,12 @@ public final class ForgeRecipeProvider extends VanillaRecipeProvider
}
@SuppressWarnings("unchecked")
private <T, R> R getField(Class<T> clz, T inst, int index)
{
private <T, R> R getField(Class<T> clz, T inst, int index) {
Field fld = clz.getDeclaredFields()[index];
fld.setAccessible(true);
try
{
try {
return (R) fld.get(inst);
} catch (IllegalArgumentException | IllegalAccessException e)
{
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
@@ -0,0 +1,238 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.common.data;
import com.google.common.base.Preconditions;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import net.minecraft.Util;
import net.minecraft.client.particle.ParticleEngine;
import net.minecraft.client.particle.ParticleProvider;
import net.minecraft.core.particles.ParticleType;
import net.minecraft.data.CachedOutput;
import net.minecraft.data.DataProvider;
import net.minecraft.data.PackOutput;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.PackType;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.registries.ForgeRegistries;
import org.jetbrains.annotations.VisibleForTesting;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Stream;
/**
* A data provider for {@link net.minecraft.client.particle.ParticleDescription}s.
*
* <p>To use this provider, extend this class and implement {@link #addDescriptions()}.
* Then, register an instance using {@link net.minecraft.data.DataGenerator#addProvider(boolean, Factory)}
* via the {@link net.minecraftforge.data.event.GatherDataEvent} on the {@linkplain FMLJavaModLoadingContext#getModEventBus() mod event bus}.
*
* <p>A description can be added to a {@link ParticleType} which uses a {@linkplain #sprite(ParticleType, ResourceLocation) sprite}
* or {@linkplain #spriteSet(ParticleType, Iterable) sprite set}.
*
* <pre>{@code
* @Override
* protected void addDescriptions() {
* // Single sprite
* this.sprite(ParticleTypes.DRIPPING_LAVA, new ResourceLocation("drip_hang"));
*
* // Multiple sprites
* this.spriteSet(ParticleTypes.CLOUD, new ResourceLocation("generic"), 8, true);
* }
* }</pre>
*
* <p>A particle description holds a list of textures used when rendering the
* particle to the screen. All registered particle descriptions are stitched
* together into a texture atlas called {@link net.minecraft.client.renderer.texture.TextureAtlas#LOCATION_PARTICLES}.
* A {@link ParticleType} whose particle uses the texture atlas, typically via
* the {@link net.minecraft.client.particle.ParticleRenderType}, can then reference
* the necessary texture during rendering.
*
* <p>Particles with a particle description must have their particle providers
* attached to a {@link ParticleType} as a {@linkplain net.minecraftforge.client.event.RegisterParticleProvidersEvent#registerSprite(ParticleType, ParticleProvider.Sprite) sprite}
* or {@linkplain net.minecraftforge.client.event.RegisterParticleProvidersEvent#registerSpriteSet(ParticleType, ParticleEngine.SpriteParticleRegistration) sprite set}
* consumer.
*
* @see DataProvider
* @see net.minecraft.client.particle.ParticleDescription
*/
public abstract class ParticleDescriptionProvider implements DataProvider {
private final PackOutput.PathProvider particlesPath;
@VisibleForTesting
protected final ExistingFileHelper fileHelper;
@VisibleForTesting
protected final Map<ResourceLocation, List<String>> descriptions;
/**
* Creates an instance of the data provider.
*
* @param output the expected root directory the data generator outputs to
* @param fileHelper the helper used to validate a texture's existence
*/
protected ParticleDescriptionProvider(PackOutput output, ExistingFileHelper fileHelper) {
this.particlesPath = output.createPathProvider(PackOutput.Target.RESOURCE_PACK, "particles");
this.fileHelper = fileHelper;
this.descriptions = new HashMap<>();
}
/**
* Registers the particle descriptions generated by {@link #sprite(ParticleType, ResourceLocation)}
* or one of the {@link #spriteSet(ParticleType, Iterable) sprite set methods}.
*/
protected abstract void addDescriptions();
/**
* Creates a new particle description that contains a single texture for the
* associated {@link ParticleType}.
*
* <p>Particle types with this description should be attached to a particle provider
* via {@link net.minecraftforge.client.event.RegisterParticleProvidersEvent#registerSprite(ParticleType, ParticleProvider.Sprite)}.
*
* @param type the particle type the textures are applied
* for
* @param texture the texture to render for the particle type
* @throws NullPointerException if the particle type is not registered
* @throws IllegalArgumentException if a texture does not have an associated PNG
* file, or the particle type has already been
* provided
*/
protected void sprite(ParticleType<?> type, ResourceLocation texture) {
this.spriteSet(type, texture);
}
/**
* Creates a new particle description that contains multiple textures for the
* associated {@link ParticleType}. The textures are generated from a common
* name and appended with a number representing the state of the animation.
*
* <pre>{@code
* minecraft:generic_0
* minecraft:generic_1
* minecraft:generic_2
* // ...
* }</pre>
*
* <p>Particle types with this description should be attached to a particle provider
* via {@link net.minecraftforge.client.event.RegisterParticleProvidersEvent#registerSpriteSet(ParticleType, ParticleEngine.SpriteParticleRegistration)}.
*
* @param type the particle type the textures are applied
* for
* @param baseName the common name of all the textures
* @param numOfTextures the number of textures within the set
* @param reverse when {@code true}, the textures will be
* listed in descending order
* @throws NullPointerException if the particle type is not registered
* @throws IllegalArgumentException if a texture does not have an associated PNG
* file, or the particle type has already been
* provided
*/
protected void spriteSet(ParticleType<?> type, ResourceLocation baseName, int numOfTextures, boolean reverse) {
Preconditions.checkArgument(numOfTextures > 0, "The number of textures to generate must be positive");
this.spriteSet(type, () -> new Iterator<>() {
private int counter = 0;
@Override
public boolean hasNext() {
return this.counter < numOfTextures;
}
@Override
public ResourceLocation next() {
var texture = baseName.withSuffix("_" + (reverse ? numOfTextures - this.counter - 1 : this.counter));
this.counter++;
return texture;
}
});
}
/**
* Creates a new particle description that contains multiple textures for the
* associated {@link ParticleType}. The textures are passed as varargs with
* at least one texture present.
*
* <p>Particle types with this description should be attached to a particle provider
* via {@link net.minecraftforge.client.event.RegisterParticleProvidersEvent#registerSpriteSet(ParticleType, ParticleEngine.SpriteParticleRegistration)}.
*
* @param type the particle type the textures are applied
* for
* @param texture the first texture in the description
* @param textures a list of subsequent textures to render for
* the particle type
* @throws NullPointerException if the particle type is not registered
* @throws IllegalArgumentException if a texture does not have an associated PNG
* file, or the particle type has already been
* provided
*/
protected void spriteSet(ParticleType<?> type, ResourceLocation texture, ResourceLocation... textures) {
this.spriteSet(type, Stream.concat(Stream.of(texture), Arrays.stream(textures))::iterator);
}
/**
* Creates a new particle description that contains multiple textures for the
* associated {@link ParticleType}. The textures are passed as an iterable.
*
* <p>Particle types with this description should be attached to a particle provider
* via {@link net.minecraftforge.client.event.RegisterParticleProvidersEvent#registerSpriteSet(ParticleType, ParticleEngine.SpriteParticleRegistration)}.
*
* @param type the particle type the textures are applied
* for
* @param textures a list of textures to render for the
* particle type
* @throws NullPointerException if the particle type is not registered
* @throws IllegalArgumentException if there are no textures provided, a texture
* does not have an associated PNG file, or
* the particle type has already been provided
*/
protected void spriteSet(ParticleType<?> type, Iterable<ResourceLocation> textures) {
// Make sure particle type is registered
var particle = Preconditions.checkNotNull(ForgeRegistries.PARTICLE_TYPES.getKey(type), "The particle type is not registered");
// Validate textures
List<String> desc = new ArrayList<>();
for (var texture : textures) {
Preconditions.checkArgument(this.fileHelper.exists(texture, PackType.CLIENT_RESOURCES, ".png", "textures/particle"),
"Texture '%s' does not exist in any known resource pack", texture);
desc.add(texture.toString());
}
Preconditions.checkArgument(desc.size() > 0, "The particle type '%s' must have one texture", particle);
// Insert into map
if (this.descriptions.putIfAbsent(particle, desc) != null) {
throw new IllegalArgumentException(String.format("The particle type '%s' already has a description associated with it", particle));
}
}
@Override
public CompletableFuture<?> run(CachedOutput cache) {
this.addDescriptions();
return CompletableFuture.allOf(
this.descriptions.entrySet().stream().map(entry -> {
// Map entries to the description format
var textures = new JsonArray();
entry.getValue().forEach(textures::add);
return DataProvider.saveStable(cache,
Util.make(new JsonObject(), obj -> obj.add("textures", textures)),
this.particlesPath.json(entry.getKey())
);
}).toArray(CompletableFuture[]::new)
);
}
@Override
public String getName() {
return "Particle Descriptions";
}
}
@@ -5,6 +5,7 @@
package net.minecraftforge.common.extensions;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.vehicle.Boat;
import net.minecraft.world.level.material.FluidState;
import net.minecraftforge.fluids.FluidType;
@@ -37,4 +38,17 @@ public interface IForgeBoat
{
return type.supportsBoating(self());
}
/**
* When {@code false}, the fluid will no longer update its height value while
* within a boat while it is not within a fluid ({@link Boat#isUnderWater()}.
*
* @param state the state of the fluid the rider is within
* @param rider the rider of the boat
* @return {@code true} if the fluid height should be updated, {@code false} otherwise
*/
default boolean shouldUpdateFluidWhileRiding(FluidState state, Entity rider)
{
return state.shouldUpdateWhileBoating(self(), rider);
}
}
@@ -13,10 +13,13 @@ 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.entity.vehicle.Boat;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityDimensions;
import net.minecraft.world.entity.MobCategory;
import net.minecraft.world.entity.Pose;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.item.SpawnEggItem;
import net.minecraft.world.item.ItemStack;
@@ -26,9 +29,11 @@ import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.phys.HitResult;
import net.minecraftforge.common.ForgeMod;
import net.minecraftforge.common.ForgeSpawnEggItem;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.SoundAction;
import net.minecraftforge.common.capabilities.ICapabilitySerializable;
import net.minecraftforge.entity.PartEntity;
import net.minecraftforge.event.entity.EntityEvent;
import net.minecraftforge.fluids.FluidType;
import org.jetbrains.annotations.Nullable;
@@ -424,4 +429,23 @@ public interface IForgeEntity extends ICapabilitySerializable<CompoundTag>
{
return false;
}
@Deprecated(forRemoval = true, since = "1.20.1") // Remove Entity Eye/Size hooks, as they need to be redesigned
default float getEyeHeightForge(Pose pose, EntityDimensions size)
{
return self().getEyeHeightAccess(pose, size);
}
/**
* When {@code false}, the fluid will no longer update its height value while
* within a boat while it is not within a fluid ({@link Boat#isUnderWater()}.
*
* @param state the state of the fluid the rider is within
* @param boat the boat the rider is within that is not inside a fluid
* @return {@code true} if the fluid height should be updated, {@code false} otherwise
*/
default boolean shouldUpdateFluidWhileBoating(FluidState state, Boat boat)
{
return boat.shouldUpdateFluidWhileRiding(state, self());
}
}
@@ -6,6 +6,7 @@
package net.minecraftforge.common.extensions;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.vehicle.Boat;
@@ -94,6 +95,20 @@ public interface IForgeFluid
return getFluidType().supportsBoating(state, boat);
}
/**
* When {@code false}, the fluid will no longer update its height value while
* within a boat while it is not within a fluid ({@link Boat#isUnderWater()}.
*
* @param state the state of the fluid the rider is within
* @param boat the boat the rider is within that is not inside a fluid
* @param rider the rider of the boat
* @return {@code true} if the fluid height should be updated, {@code false} otherwise
*/
default boolean shouldUpdateWhileBoating(FluidState state, Boat boat, Entity rider)
{
return getFluidType().shouldUpdateWhileBoating(state, boat, rider);
}
/**
* Gets the path type of this fluid when an entity is pathfinding. When
* {@code null}, uses vanilla behavior.
@@ -6,6 +6,7 @@
package net.minecraftforge.common.extensions;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.vehicle.Boat;
@@ -88,6 +89,19 @@ public interface IForgeFluidState
return self().getType().supportsBoating(self(), boat);
}
/**
* When {@code false}, the fluid will no longer update its height value while
* within a boat while it is not within a fluid ({@link Boat#isUnderWater()}.
*
* @param boat the boat the rider is within that is not inside a fluid
* @param rider the rider of the boat
* @return {@code true} if the fluid height should be updated, {@code false} otherwise
*/
default boolean shouldUpdateWhileBoating(Boat boat, Entity rider)
{
return self().getType().shouldUpdateWhileBoating(self(), boat, rider);
}
/**
* Gets the path type of this fluid when an entity is pathfinding. When
* {@code null}, uses vanilla behavior.
@@ -10,8 +10,7 @@ import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
public interface IForgeIntrinsicHolderTagAppender<T> extends IForgeTagAppender<T>
{
public interface IForgeIntrinsicHolderTagAppender<T> extends IForgeTagAppender<T> {
private IntrinsicHolderTagsProvider.IntrinsicTagAppender<T> self() {
return (IntrinsicHolderTagsProvider.IntrinsicTagAppender<T>) this;
}
@@ -24,8 +23,7 @@ public interface IForgeIntrinsicHolderTagAppender<T> extends IForgeTagAppender<T
* @param entry The entry to remove
* @return The builder for chaining
*/
default IntrinsicHolderTagsProvider.IntrinsicTagAppender<T> remove(final T entry)
{
default IntrinsicHolderTagsProvider.IntrinsicTagAppender<T> remove(final T entry) {
return remove(this.getKey(entry));
}
@@ -36,78 +34,66 @@ public interface IForgeIntrinsicHolderTagAppender<T> extends IForgeTagAppender<T
* @return The builder for chaining
*/
@SuppressWarnings("unchecked")
default IntrinsicHolderTagsProvider.IntrinsicTagAppender<T> remove(final T first, final T...entries)
{
default IntrinsicHolderTagsProvider.IntrinsicTagAppender<T> remove(final T first, final T...entries) {
this.remove(first);
for (T entry : entries)
{
this.remove(entry);
}
return self();
}
@Override
@SuppressWarnings("unchecked")
default IntrinsicHolderTagsProvider.IntrinsicTagAppender<T> addTags(TagKey<T>... values)
{
default IntrinsicHolderTagsProvider.IntrinsicTagAppender<T> addTags(TagKey<T>... values) {
IForgeTagAppender.super.addTags(values);
return self();
}
@Override
default IntrinsicHolderTagsProvider.IntrinsicTagAppender<T> replace()
{
default IntrinsicHolderTagsProvider.IntrinsicTagAppender<T> replace() {
IForgeTagAppender.super.replace();
return self();
}
@Override
default IntrinsicHolderTagsProvider.IntrinsicTagAppender<T> replace(boolean value)
{
default IntrinsicHolderTagsProvider.IntrinsicTagAppender<T> replace(boolean value) {
IForgeTagAppender.super.replace(value);
return self();
}
@Override
default IntrinsicHolderTagsProvider.IntrinsicTagAppender<T> remove(final ResourceLocation location)
{
default IntrinsicHolderTagsProvider.IntrinsicTagAppender<T> remove(final ResourceLocation location) {
IForgeTagAppender.super.remove(location);
return self();
}
@Override
default IntrinsicHolderTagsProvider.IntrinsicTagAppender<T> remove(final ResourceLocation first, final ResourceLocation... locations)
{
default IntrinsicHolderTagsProvider.IntrinsicTagAppender<T> remove(final ResourceLocation first, final ResourceLocation... locations) {
IForgeTagAppender.super.remove(first, locations);
return self();
}
@Override
default IntrinsicHolderTagsProvider.IntrinsicTagAppender<T> remove(final ResourceKey<T> resourceKey)
{
default IntrinsicHolderTagsProvider.IntrinsicTagAppender<T> remove(final ResourceKey<T> resourceKey) {
IForgeTagAppender.super.remove(resourceKey);
return self();
}
@Override
@SuppressWarnings("unchecked")
default IntrinsicHolderTagsProvider.IntrinsicTagAppender<T> remove(final ResourceKey<T> firstResourceKey, final ResourceKey<T>... resourceKeys)
{
default IntrinsicHolderTagsProvider.IntrinsicTagAppender<T> remove(final ResourceKey<T> firstResourceKey, final ResourceKey<T>... resourceKeys) {
IForgeTagAppender.super.remove(firstResourceKey, resourceKeys);
return self();
}
@Override
default IntrinsicHolderTagsProvider.IntrinsicTagAppender<T> remove(TagKey<T> tag)
{
default IntrinsicHolderTagsProvider.IntrinsicTagAppender<T> remove(TagKey<T> tag) {
IForgeTagAppender.super.remove(tag);
return self();
}
@Override
@SuppressWarnings("unchecked")
default IntrinsicHolderTagsProvider.IntrinsicTagAppender<T> remove(TagKey<T> first, TagKey<T>...tags)
{
default IntrinsicHolderTagsProvider.IntrinsicTagAppender<T> remove(TagKey<T> first, TagKey<T>...tags) {
IForgeTagAppender.super.remove(first, tags);
return self();
}
@@ -330,10 +330,28 @@ public interface IForgeItem
/**
* Called to tick armor in the armor slot. Override to do something
*/
@Deprecated(forRemoval = true, since = "1.20.1") // Use onInventoryTick
default void onArmorTick(ItemStack stack, Level level, Player player)
{
}
/**
* Called to tick this items in a players inventory, the indexes are the global slot index.
*/
default void onInventoryTick(ItemStack stack, Level level, Player player, int slotIndex, int selectedIndex)
{
// For compatibility reasons we have to use non-local index values, I think this is a vanilla bug but lets maintain compatibility
int vanillaIndex = slotIndex;
if (slotIndex >= 36) {
vanillaIndex -= 36;
if (vanillaIndex >= 4)
vanillaIndex -= 4;
else
onArmorTick(stack, level, player);
}
stack.inventoryTick(level, player, vanillaIndex, selectedIndex == vanillaIndex);
}
/**
* Determines if the specific ItemStack can be placed in the specified armor
* slot, for the entity.
@@ -292,11 +292,21 @@ public interface IForgeItemStack extends ICapabilitySerializable<CompoundTag>
/**
* Called to tick armor in the armor slot. Override to do something
*/
@Deprecated(forRemoval = true, since = "1.20.1") // Use onInventoryTick
default void onArmorTick(Level level, Player player)
{
self().getItem().onArmorTick(self(), level, player);
}
/**
* Called to tick this items in a players inventory, the indexes are the global slot index.
*/
default void onInventoryTick(Level level, Player player, int slotIndex, int selectedIndex)
{
self().getItem().onInventoryTick(self(), level, player, slotIndex, selectedIndex);
}
/**
* Called every tick from {@code Horse#playGallopSound(SoundEvent)} on the item in the
* armor slot.
@@ -5,37 +5,22 @@
package net.minecraftforge.common.extensions;
import java.util.stream.Stream;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagBuilder;
import net.minecraft.tags.TagEntry;
public interface IForgeRawTagBuilder
{
default TagBuilder getRawBuilder()
{
public interface IForgeRawTagBuilder {
default TagBuilder getRawBuilder() {
return (TagBuilder)this;
}
/**
* internal, called when a raw builder is written to json to add forge additions (e.g. the remove list)
* @deprecated Never used, tags use a Codec now, so remove this later.
*/
default void serializeTagAdditions(final JsonObject tagJson)
{
TagBuilder rawBuilder = this.getRawBuilder();
Stream<TagEntry> removeEntries = rawBuilder.getRemoveEntries();
JsonArray removeEntriesAsJsonArray = new JsonArray();
//removeEntries.forEach(proxy ->proxy.serializeTo(removeEntriesAsJsonArray)); // TODO: Figure out what the replacement for this is. -C
if (removeEntriesAsJsonArray.size() > 0)
{
tagJson.add("remove", removeEntriesAsJsonArray);
}
}
@Deprecated(forRemoval = true, since = "1.20.1")
default void serializeTagAdditions(final JsonObject tagJson) {}
/**
* Adds a tag entry to the remove list.
@@ -43,8 +28,7 @@ public interface IForgeRawTagBuilder
* @param source The source of the caller for logging purposes (generally a modid)
* @return The builder for chaining purposes
*/
default TagBuilder remove(final TagEntry tagEntry, final String source)
{
default TagBuilder remove(final TagEntry tagEntry, final String source) {
return this.getRawBuilder().remove(tagEntry);
}
@@ -54,20 +38,17 @@ public interface IForgeRawTagBuilder
* @param source The source of the caller for logging purposes (generally a modid)
* @return The builder for chaining purposes
*/
default TagBuilder removeElement(final ResourceLocation elementID, final String source)
{
default TagBuilder removeElement(final ResourceLocation elementID, final String source) {
return this.remove(TagEntry.element(elementID), source);
}
/**
* Adds a tag to the remove list.
* @param tagID The ID of the tag to add to the remove list
* @param source The source of the caller for logging purposes (generally a modid)
* @return The builder for chaining purposes
*/
default TagBuilder removeTag(final ResourceLocation tagID, final String source)
{
default TagBuilder removeTag(final ResourceLocation tagID, final String source) {
return this.remove(TagEntry.tag(tagID), source);
}
}
@@ -0,0 +1,172 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.common.util;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.Dynamic;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.Brain;
import net.minecraft.world.entity.ai.behavior.BehaviorControl;
import net.minecraft.world.entity.ai.memory.MemoryModuleType;
import net.minecraft.world.entity.ai.memory.MemoryStatus;
import net.minecraft.world.entity.ai.sensing.Sensor;
import net.minecraft.world.entity.ai.sensing.SensorType;
import net.minecraft.world.entity.schedule.Activity;
import net.minecraft.world.entity.schedule.Schedule;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.jetbrains.annotations.ApiStatus;
/**
* This object is used to encapsulate state found inside a {@link Brain} instance,
* to make it easily accessible for modders to manipulate during {@link net.minecraftforge.event.entity.living.LivingMakeBrainEvent}.<br>
* <br>
* Provided are a variety of getter/setter methods to access and manipulate the encapsulated state.<br>
* <br>
* Methods marked with "INTENDED FOR INTERNAL USE" are only meant to be used inside:
* <ul>
* <li>{@link net.minecraftforge.common.ForgeHooks#onLivingMakeBrain(LivingEntity, Brain, Dynamic)}
* <li>{@link Brain#createBuilder()}
* <li>{@link Brain#copyFromBuilder(BrainBuilder)}
* </ul>
* Of course, nothing egregious will happen should a modder choose to use them for their own purposes.<br>
*/
public class BrainBuilder<E extends LivingEntity> {
private final Collection<MemoryModuleType<?>> memoryTypes = new HashSet<>();
private final Collection<SensorType<? extends Sensor<? super E>>> sensorTypes = new HashSet<>();
private final Map<Integer, Map<Activity, Set<BehaviorControl<? super E>>>> availableBehaviorsByPriority = Maps.newTreeMap();
private Schedule schedule = Schedule.EMPTY;
private final Map<Activity, Set<Pair<MemoryModuleType<?>, MemoryStatus>>> activityRequirements = Maps.newHashMap();
private final Map<Activity, Set<MemoryModuleType<?>>> activityMemoriesToEraseWhenStopped = Maps.newHashMap();
private final Set<Activity> coreActivities = Sets.newHashSet();
private final Set<Activity> activeActivites = Sets.newHashSet();
private Activity defaultActivity = Activity.IDLE;
public BrainBuilder(Brain<E> ignoredBrain) {}
public Brain.Provider<E> provider() {
return Brain.provider(this.memoryTypes, this.sensorTypes);
}
public Collection<MemoryModuleType<?>> getMemoryTypes() {
return this.memoryTypes;
}
public Collection<SensorType<? extends Sensor<? super E>>> getSensorTypes() {
return this.sensorTypes;
}
public Map<Integer, Map<Activity, Set<BehaviorControl<? super E>>>> getAvailableBehaviorsByPriority() {
return this.availableBehaviorsByPriority;
}
public Schedule getSchedule() {
return this.schedule;
}
public void setSchedule(Schedule schedule) {
this.schedule = schedule;
}
public Map<Activity, Set<Pair<MemoryModuleType<?>, MemoryStatus>>> getActivityRequirements() {
return this.activityRequirements;
}
public Map<Activity, Set<MemoryModuleType<?>>> getActivityMemoriesToEraseWhenStopped() {
return this.activityMemoriesToEraseWhenStopped;
}
public Set<Activity> getCoreActivities() {
return this.coreActivities;
}
public Activity getDefaultActivity() {
return this.defaultActivity;
}
public void setDefaultActivity(Activity defaultActivity) {
this.defaultActivity = defaultActivity;
}
public Set<Activity> getActiveActivites() {
return this.activeActivites;
}
public void setActiveActivites(Set<Activity> value) {
this.activeActivites.clear();
this.activeActivites.addAll(value);
}
/** You may use this as a helper method for adding a behavior to an Activity by priority to an entity's brain. */
public void addBehaviorToActivityByPriority(Integer priority, Activity activity, BehaviorControl<? super E> behaviorControl) {
this.availableBehaviorsByPriority.computeIfAbsent(priority, (i) -> Maps.newHashMap()).computeIfAbsent(activity, (a) -> Sets.newLinkedHashSet()).add(behaviorControl);
}
/** You may use this as a helper method for adding memory requirements for an Activity to an entity's brain. */
public void addRequirementsToActivity(Activity activity, Collection<Pair<MemoryModuleType<?>, MemoryStatus>> requirements) {
addRequirementsToActivityInternal(this.activityRequirements, activity, requirements);
}
/** You may use this as a helper method for adding a collection of memories to erase when an Activity is stopped to entity's brain. */
public void addMemoriesToEraseWhenActivityStopped(Activity activity, Collection<MemoryModuleType<?>> memories) {
addMemoriesToEraseWhenActivityStoppedInternal(this.activityMemoriesToEraseWhenStopped, activity, memories);
}
//====================================================================================================================//
// Everything below this is just to implement Brain.createBuilder and Brain.copyFromBuilder, hence marked as internal //
//====================================================================================================================//
@ApiStatus.Internal
public void addAvailableBehaviorsByPriorityFrom(Map<Integer, Map<Activity, Set<BehaviorControl<? super E>>>> addFrom) {
addFrom.forEach(((priority, activitySetMap) -> activitySetMap.forEach(((activity, behaviorControls) -> this.availableBehaviorsByPriority.computeIfAbsent(priority, (p) -> Maps.newHashMap()).computeIfAbsent(activity, (a) -> Sets.newLinkedHashSet()).addAll(behaviorControls)))));
}
@ApiStatus.Internal
public void addAvailableBehaviorsByPriorityTo(Map<Integer, Map<Activity, Set<BehaviorControl<? super E>>>> addTo){
this.availableBehaviorsByPriority.forEach(((priority, activitySetMap) -> activitySetMap.forEach(((activity, behaviorControls) -> addTo.computeIfAbsent(priority, (p) -> Maps.newHashMap()).computeIfAbsent(activity, (a) -> Sets.newLinkedHashSet()).addAll(behaviorControls)))));
}
@ApiStatus.Internal
public void addActivityRequirementsFrom(Map<Activity, Set<Pair<MemoryModuleType<?>, MemoryStatus>>> addFrom) {
addFrom.forEach(this::addRequirementsToActivity);
}
@ApiStatus.Internal
public void addActivityRequirementsTo(Map<Activity, Set<Pair<MemoryModuleType<?>, MemoryStatus>>> addTo) {
this.activityRequirements.forEach(((activity, requirements) -> addRequirementsToActivityInternal(addTo, activity, requirements)));
}
@ApiStatus.Internal
public void addActivityMemoriesToEraseWhenStoppedFrom(Map<Activity, Set<MemoryModuleType<?>>> addFrom) {
addFrom.forEach(this::addMemoriesToEraseWhenActivityStopped);
}
@ApiStatus.Internal
public void addActivityMemoriesToEraseWhenStoppedTo(Map<Activity, Set<MemoryModuleType<?>>> addTo) {
this.activityMemoriesToEraseWhenStopped.forEach(((activity, memories) -> addMemoriesToEraseWhenActivityStoppedInternal(addTo, activity, memories)));
}
private static void addMemoriesToEraseWhenActivityStoppedInternal(Map<Activity, Set<MemoryModuleType<?>>> activityMemoriesToEraseWhenStopped, Activity activity, Collection<MemoryModuleType<?>> memories) {
activityMemoriesToEraseWhenStopped.computeIfAbsent(activity, (a) -> Sets.newHashSet()).addAll(memories);
}
private static void addRequirementsToActivityInternal(Map<Activity, Set<Pair<MemoryModuleType<?>, MemoryStatus>>> activityRequirements, Activity activity, Collection<Pair<MemoryModuleType<?>, MemoryStatus>> requirements) {
activityRequirements.computeIfAbsent(activity, (a) -> Sets.newHashSet()).addAll(requirements);
}
@ApiStatus.Internal
public Brain<E> makeBrain(Dynamic<?> dynamic) {
Brain<E> brain = Brain.provider(this.memoryTypes, this.sensorTypes).makeBrain(dynamic);
brain.copyFromBuilder(this);
return brain;
}
}
@@ -5,6 +5,7 @@
package net.minecraftforge.common.util;
import java.lang.ref.WeakReference;
import java.util.HashSet;
import java.util.Objects;
import java.util.Optional;
@@ -40,8 +41,7 @@ import org.jetbrains.annotations.Nullable;
*/
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
public class LazyOptional<T>
{
public class LazyOptional<T> {
private final NonNullSupplier<T> supplier;
private final Object lock = new Object();
// null -> not resolved yet
@@ -62,16 +62,14 @@ public class LazyOptional<T>
* null, but can be null itself. If null, this method
* returns {@link #empty()}.
*/
public static <T> LazyOptional<T> of(final @Nullable NonNullSupplier<T> instanceSupplier)
{
public static <T> LazyOptional<T> of(final @Nullable NonNullSupplier<T> instanceSupplier) {
return instanceSupplier == null ? empty() : new LazyOptional<>(instanceSupplier);
}
/**
* @return The singleton empty instance
*/
public static <T> LazyOptional<T> empty()
{
public static <T> LazyOptional<T> empty() {
return EMPTY.cast();
}
@@ -83,27 +81,21 @@ public class LazyOptional<T>
* @return This {@link LazyOptional}, cast to the inferred generic type
*/
@SuppressWarnings("unchecked")
public <X> LazyOptional<X> cast()
{
public <X> LazyOptional<X> cast() {
return (LazyOptional<X>)this;
}
private LazyOptional(@Nullable NonNullSupplier<T> instanceSupplier)
{
private LazyOptional(@Nullable NonNullSupplier<T> instanceSupplier) {
this.supplier = instanceSupplier;
}
private @Nullable T getValue()
{
private @Nullable T getValue() {
if (!isValid || supplier == null)
return null;
if (resolved == null)
{
synchronized (lock)
{
if (resolved == null) {
synchronized (lock) {
// resolved == null: Double checked locking to prevent two threads from resolving
if (resolved == null)
{
if (resolved == null) {
T temp = supplier.get();
if (temp == null)
LOGGER.catching(Level.WARN, new NullPointerException("Supplier should not return null value"));
@@ -114,13 +106,10 @@ public class LazyOptional<T>
return resolved.getValue();
}
private T getValueUnsafe()
{
private T getValueUnsafe() {
T ret = getValue();
if (ret == null)
{
throw new IllegalStateException("LazyOptional is empty or otherwise returned null from getValue() unexpectedly");
}
return ret;
}
@@ -130,8 +119,7 @@ public class LazyOptional<T>
* @return {@code true} if this {@link LazyOptional} is non-empty, i.e. holds a
* non-null supplier
*/
public boolean isPresent()
{
public boolean isPresent() {
return supplier != null && isValid;
}
@@ -142,8 +130,7 @@ public class LazyOptional<T>
* @param consumer The {@link NonNullConsumer} to run if this optional is non-empty.
* @throws NullPointerException if {@code consumer} is null and this {@link LazyOptional} is non-empty
*/
public void ifPresent(NonNullConsumer<? super T> consumer)
{
public void ifPresent(NonNullConsumer<? super T> consumer) {
Objects.requireNonNull(consumer);
T val = getValue();
if (isValid && val != null)
@@ -169,8 +156,7 @@ public class LazyOptional<T>
* present, otherwise an empty {@link LazyOptional}
* @throws NullPointerException if {@code mapper} is null.
*/
public <U> LazyOptional<U> lazyMap(NonNullFunction<? super T, ? extends U> mapper)
{
public <U> LazyOptional<U> lazyMap(NonNullFunction<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
return isPresent() ? of(() -> mapper.apply(getValueUnsafe())) : empty();
}
@@ -189,8 +175,7 @@ public class LazyOptional<T>
* present, otherwise an empty {@link Optional}
* @throws NullPointerException if {@code mapper} is null.
*/
public <U> Optional<U> map(NonNullFunction<? super T, ? extends U> mapper)
{
public <U> Optional<U> map(NonNullFunction<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
return isPresent() ? Optional.of(mapper.apply(getValueUnsafe())) : Optional.empty();
}
@@ -211,8 +196,7 @@ public class LazyOptional<T>
* @throws NullPointerException If {@code predicate} is null and this
* {@link Optional} is non-empty
*/
public Optional<T> filter(NonNullPredicate<? super T> predicate)
{
public Optional<T> filter(NonNullPredicate<? super T> predicate) {
Objects.requireNonNull(predicate);
final T value = getValue(); // To keep the non-null contract we have to evaluate right now. Should we allow this function at all?
return value != null && predicate.test(value) ? Optional.of(value) : Optional.empty();
@@ -222,8 +206,7 @@ public class LazyOptional<T>
* Resolves the value of this LazyOptional, turning it into a standard non-lazy {@link Optional<T>}
* @return The resolved optional.
*/
public Optional<T> resolve()
{
public Optional<T> resolve() {
return isPresent() ? Optional.of(getValueUnsafe()) : Optional.empty();
}
@@ -234,8 +217,7 @@ public class LazyOptional<T>
* @param other the value to be returned if this {@link LazyOptional} is empty
* @return the result of the supplier, if non-empty, otherwise {@code other}
*/
public T orElse(T other)
{
public T orElse(T other) {
T val = getValue();
return val != null ? val : other;
}
@@ -251,8 +233,7 @@ public class LazyOptional<T>
* @throws NullPointerException If {@code other} is null and this
* {@link LazyOptional} is non-empty
*/
public T orElseGet(NonNullSupplier<? extends T> other)
{
public T orElseGet(NonNullSupplier<? extends T> other) {
T val = getValue();
return val != null ? val : other.get();
}
@@ -273,8 +254,7 @@ public class LazyOptional<T>
* @throws NullPointerException If {@code exceptionSupplier} is null and this
* {@link LazyOptional} is empty
*/
public <X extends Throwable> T orElseThrow(NonNullSupplier<? extends X> exceptionSupplier) throws X
{
public <X extends Throwable> T orElseThrow(NonNullSupplier<? extends X> exceptionSupplier) throws X {
T val = getValue();
if (val != null)
return val;
@@ -286,16 +266,19 @@ public class LazyOptional<T>
* <p>
* If this {@link LazyOptional} is empty, the listener will be called immediately.
*/
public void addListener(NonNullConsumer<LazyOptional<T>> listener)
{
public void addListener(NonNullConsumer<LazyOptional<T>> listener) {
if (isPresent())
{
this.listeners.add(listener);
}
else
{
listener.accept(this);
}
}
/**
* Unregisters a {@link NonNullConsumer listener} from the list to be notified when this {@link LazyOptional} becomes invalid (via {@link #invalidate()}).<br>
* This allows modder who know they will not need to be notified, to remove the hard reference that this holds to their listener.
*/
public void removeListener(NonNullConsumer<LazyOptional<T>> listener) {
this.listeners.remove(listener);
}
/**
@@ -312,12 +295,11 @@ public class LazyOptional<T>
* etc... This allows modders to keep a cache of capability objects instead of
* re-checking them every tick.
*/
public void invalidate()
{
if (this.isValid)
{
public void invalidate() {
if (this.isValid) {
this.isValid = false;
this.listeners.forEach(e -> e.accept(this));
this.listeners.clear();
}
}
}
@@ -0,0 +1,58 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.energy;
/**
* Implementation of {@link IEnergyStorage} that cannot store, receive, or provide energy.
* Use the {@link #INSTANCE}, don't instantiate. Example:
* <pre>{@code
* ItemStack stack = ...;
* IEnergyStorage storage = stack.getCapability(ForgeCapabilities.ENERGY).orElse(EmptyEnergyStorage.INSTANCE);
* // Use storage without checking whether it's present.
* }</pre>
*/
public class EmptyEnergyStorage implements IEnergyStorage
{
public static final EmptyEnergyStorage INSTANCE = new EmptyEnergyStorage();
protected EmptyEnergyStorage() {}
@Override
public int receiveEnergy(int maxReceive, boolean simulate)
{
return 0;
}
@Override
public int extractEnergy(int maxExtract, boolean simulate)
{
return 0;
}
@Override
public int getEnergyStored()
{
return 0;
}
@Override
public int getMaxEnergyStored()
{
return 0;
}
@Override
public boolean canExtract()
{
return false;
}
@Override
public boolean canReceive()
{
return false;
}
}
@@ -30,6 +30,7 @@ import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.entity.MobCategory;
import net.minecraft.world.entity.projectile.Projectile;
import net.minecraft.world.entity.projectile.ThrownEnderpearl;
import net.minecraft.world.level.LevelSimulatedReader;
import net.minecraft.world.level.biome.MobSpawnSettings;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
@@ -39,13 +40,13 @@ import net.minecraft.world.item.TooltipFlag;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.Pose;
import net.minecraft.world.entity.EntityDimensions;
import net.minecraft.world.entity.SpawnGroupData;
import net.minecraft.world.entity.SpawnPlacements;
import net.minecraft.world.entity.EntityDimensions;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.MobSpawnType;
import net.minecraft.world.entity.Pose;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.LightningBolt;
import net.minecraft.world.entity.item.ItemEntity;
@@ -128,6 +129,7 @@ import net.minecraftforge.event.entity.player.PlayerWakeUpEvent;
import net.minecraftforge.event.entity.player.SleepingLocationCheckEvent;
import net.minecraftforge.event.entity.player.SleepingTimeCheckEvent;
import net.minecraftforge.event.furnace.FurnaceFuelBurnTimeEvent;
import net.minecraftforge.event.level.AlterGroundEvent;
import net.minecraftforge.event.level.BlockEvent;
import net.minecraftforge.event.level.BlockEvent.BlockToolModificationEvent;
import net.minecraftforge.event.level.BlockEvent.CreateFluidSourceEvent;
@@ -269,7 +271,7 @@ public class ForgeEventFactory
* @see MobSpawnEvent.FinalizeSpawn
* @see Mob#finalizeSpawn(ServerLevelAccessor, DifficultyInstance, MobSpawnType, SpawnGroupData, CompoundTag)
* @apiNote Callers do not need to check if the entity's spawn was cancelled, as the spawn will be blocked by Forge.
* @implNote Changes to the signature of this method must be reflected in the method redirector coremod.
* @implNote Changes to the signature of this method must be reflected in the method redirector coremod.
*/
@Nullable
@SuppressWarnings("deprecation") // Call to deprecated Mob#finalizeSpawn is expected.
@@ -667,9 +669,20 @@ public class ForgeEventFactory
return event.getCharge();
}
public static ProjectileImpactEvent.ImpactResult onProjectileImpactResult(Projectile projectile, HitResult ray)
{
ProjectileImpactEvent event = new ProjectileImpactEvent(projectile, ray);
// Remove this when the event is no longer cancelable
if (MinecraftForge.EVENT_BUS.post(event))
return ProjectileImpactEvent.ImpactResult.SKIP_ENTITY;
return event.getImpactResult();
}
public static boolean onProjectileImpact(Projectile projectile, HitResult ray)
{
return MinecraftForge.EVENT_BUS.post(new ProjectileImpactEvent(projectile, ray));
return onProjectileImpactResult(projectile, ray) != ProjectileImpactEvent.ImpactResult.DEFAULT;
}
public static LootTable loadLootTable(ResourceLocation name, LootTable table)
@@ -726,6 +739,13 @@ public class ForgeEventFactory
return event;
}
public static BlockState alterGround(LevelSimulatedReader level, RandomSource random, BlockPos pos, BlockState altered)
{
AlterGroundEvent event = new AlterGroundEvent(level, random, pos, altered);
MinecraftForge.EVENT_BUS.post(event);
return event.getNewAlteredState();
}
public static void fireChunkTicketLevelUpdated(ServerLevel level, long chunkPos, int oldTicketLevel, int newTicketLevel, @Nullable ChunkHolder chunkHolder)
{
if (oldTicketLevel != newTicketLevel)
@@ -772,16 +792,18 @@ public class ForgeEventFactory
MinecraftForge.EVENT_BUS.post(event);
}
@Deprecated(forRemoval = true, since = "1.20.1") // Remove Entity Eye/Size hooks, as they need to be redesigned
public static net.minecraftforge.event.entity.EntityEvent.Size getEntitySizeForge(Entity entity, Pose pose, EntityDimensions size, float eyeHeight)
{
EntityEvent.Size evt = new EntityEvent.Size(entity, pose, size, eyeHeight);
var evt = new EntityEvent.Size(entity, pose, size, eyeHeight);
MinecraftForge.EVENT_BUS.post(evt);
return evt;
}
@Deprecated(forRemoval = true, since = "1.20.1") // Remove Entity Eye/Size hooks, as they need to be redesigned
public static net.minecraftforge.event.entity.EntityEvent.Size getEntitySizeForge(Entity entity, Pose pose, EntityDimensions oldSize, EntityDimensions newSize, float newEyeHeight)
{
EntityEvent.Size evt = new EntityEvent.Size(entity, pose, oldSize, newSize, entity.getEyeHeight(), newEyeHeight);
var evt = new EntityEvent.Size(entity, pose, oldSize, newSize, entity.getEyeHeight(), newEyeHeight);
MinecraftForge.EVENT_BUS.post(evt);
return evt;
}
@@ -14,8 +14,7 @@ import net.minecraftforge.eventbus.api.Event;
import java.util.Locale;
import java.util.Map;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.Preconditions;
/**
* Fired for registering structure conversions for pre-1.18.2 worlds. This is used by {@link StructuresBecomeConfiguredFix}
@@ -92,11 +91,11 @@ public class RegisterStructureConversionsEvent extends Event
*/
public void register(String oldStructureID, StructuresBecomeConfiguredFix.Conversion conversion)
{
checkNotNull(oldStructureID, "Original structure ID must not be null");
checkArgument(oldStructureID.toLowerCase(Locale.ROOT).equals(oldStructureID),
Preconditions.checkNotNull(oldStructureID, "Original structure ID must not be null");
Preconditions.checkArgument(oldStructureID.toLowerCase(Locale.ROOT).equals(oldStructureID),
"Original structure ID should be in all lowercase");
checkNotNull(conversion, "Structure conversion must not be null");
checkNotNull(conversion.fallback(), "Fallback structure ID in structure conversion must not be null");
Preconditions.checkNotNull(conversion, "Structure conversion must not be null");
Preconditions.checkNotNull(conversion.fallback(), "Fallback structure ID in structure conversion must not be null");
if (map.putIfAbsent(oldStructureID.toLowerCase(Locale.ROOT), conversion) != null)
{
throw new IllegalArgumentException("Conversion has already been registered for structure " + oldStructureID);
@@ -10,6 +10,7 @@ import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityDimensions;
import net.minecraft.world.entity.Pose;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.extensions.IForgeEntity;
import net.minecraftforge.eventbus.api.Cancelable;
import net.minecraftforge.eventbus.api.Event;
@@ -127,8 +128,7 @@ public class EntityEvent extends Event
}
/**
* This event is fired whenever the {@link Pose} changes, and in a few other hardcoded scenarios.<br>
* CAREFUL: This is also fired in the Entity constructor. Therefore the entity(subclass) might not be fully initialized. Check Entity#isAddedToWorld() or !Entity#firstUpdate.<br>
* CAREFUL: This is also fired in the Entity constructor. Therefore, the entity (subclass) might not be fully initialized. Check {@link Entity#isAddedToWorld()} or {@code !Entity.firstUpdate}.<br>
* If you change the player's size, you probably want to set the eye height accordingly as well<br>
* <br>
* This event is not {@link Cancelable}.<br>
@@ -137,51 +137,70 @@ public class EntityEvent extends Event
* <br>
* This event is fired on the {@link MinecraftForge#EVENT_BUS}.<br>
**/
public static class Size extends EntityEvent
{
@Deprecated(forRemoval = true, since = "1.20.1") // Remove Entity Eye/Size hooks, as they need to be redesigned
public static class Size extends EntityEvent {
private final Pose pose;
private final EntityDimensions oldSize;
private final EntityDimensions originalSize;
private EntityDimensions newSize;
private final float oldEyeHeight;
private float newEyeHeight;
public Size(Entity entity, Pose pose, EntityDimensions size, float defaultEyeHeight)
{
public Size(Entity entity, Pose pose, EntityDimensions size) {
this(entity, pose, size, 1.0f); // Eye height doesn't matter this is just for binary compatibility.
}
public Size(Entity entity, Pose pose, EntityDimensions size, float defaultEyeHeight) {
this(entity, pose, size, size, defaultEyeHeight, defaultEyeHeight);
}
public Size(Entity entity, Pose pose, EntityDimensions oldSize, EntityDimensions newSize, float oldEyeHeight, float newEyeHeight)
{
public Size(Entity entity, Pose pose, EntityDimensions oldSize, EntityDimensions newSize, float oldEyeHeight, float newEyeHeight) {
super(entity);
this.pose = pose;
this.oldSize = oldSize;
this.originalSize = oldSize;
this.newSize = newSize;
this.oldEyeHeight = oldEyeHeight;
this.newEyeHeight = newEyeHeight;
}
public Pose getPose() { return pose; }
public EntityDimensions getOldSize() { return oldSize; }
public EntityDimensions getOldSize() { return this.getOriginalSize(); }
public EntityDimensions getOriginalSize() { return originalSize; }
public EntityDimensions getNewSize() { return newSize; }
public void setNewSize(EntityDimensions size)
{
setNewSize(size, false);
}
public void setNewSize(EntityDimensions size) { this.newSize = size; }
/**
* Set the new size of the entity. Set updateEyeHeight to true to also update the eye height according to the new size.
*/
public void setNewSize(EntityDimensions size, boolean updateEyeHeight)
{
this.newSize = size;
if (updateEyeHeight)
{
public void setNewSize(EntityDimensions size, boolean updateEyeHeight) {
this.setNewSize(size);
if (updateEyeHeight) {
this.newEyeHeight = this.getEntity().getEyeHeightAccess(this.getPose(), this.newSize);
}
}
public float getOldEyeHeight() { return oldEyeHeight; }
public float getNewEyeHeight() { return newEyeHeight; }
public void setNewEyeHeight(float newHeight) { this.newEyeHeight = newHeight; }
public void setNewEyeHeight(float eyeHeight) { this.newEyeHeight = eyeHeight; }
}
/**
*Remove Entity Eye/Size hooks, as they need to be redesigned, this is no longer fired in any forge/vanilla code.
**/
@Deprecated(forRemoval = true, since = "1.20.1")
public static class EyeHeight extends EntityEvent {
private final Pose pose;
private final EntityDimensions size;
private final float originalEyeHeight;
private float newEyeHeight;
public EyeHeight(Entity entity, Pose pose, EntityDimensions size, float eyeHeight) {
super(entity);
this.pose = pose;
this.size = size;
this.originalEyeHeight = eyeHeight;
this.newEyeHeight = eyeHeight;
}
public Pose getPose() { return pose; }
public EntityDimensions getSize() { return size; }
public float getOriginalEyeHeight() { return originalEyeHeight; }
public float getNewEyeHeight() { return newEyeHeight; }
public void setNewEyeHeight(float newEyeHeight) { this.newEyeHeight = newEyeHeight; }
}
}
@@ -10,6 +10,9 @@ import net.minecraft.world.phys.HitResult;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.ForgeEventFactory;
import net.minecraftforge.eventbus.api.Cancelable;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
/**
* This event is fired on the {@link MinecraftForge#EVENT_BUS}.<br>
@@ -19,6 +22,8 @@ import net.minecraftforge.eventbus.api.Cancelable;
* custom projectiles should fire this event and check the result in a similar fashion.
* This event is cancelable. When canceled, the impact will not be processed and the projectile will continue flying.
* Killing or other handling of the entity after event cancellation is up to the modder.
* You can also directly set the {@link ImpactResult} to change the impact behaviour.
* @see #setImpactResult(ImpactResult)
*/
@Cancelable
public class ProjectileImpactEvent extends EntityEvent
@@ -26,6 +31,8 @@ public class ProjectileImpactEvent extends EntityEvent
private final HitResult ray;
private final Projectile projectile;
private ImpactResult result = ImpactResult.DEFAULT;
public ProjectileImpactEvent(Projectile projectile, HitResult ray)
{
super(projectile);
@@ -33,6 +40,16 @@ public class ProjectileImpactEvent extends EntityEvent
this.projectile = projectile;
}
/**
* {@inheritDoc}
* @deprecated Use {@link #setImpactResult(ImpactResult)} instead.
*/
@Deprecated(forRemoval = true, since = "1.20.1")
public void setCanceled(boolean cancel)
{
super.setCanceled(cancel);
}
public HitResult getRayTraceResult()
{
return ray;
@@ -42,4 +59,34 @@ public class ProjectileImpactEvent extends EntityEvent
{
return projectile;
}
public void setImpactResult(@NotNull ImpactResult newResult)
{
this.result = Objects.requireNonNull(newResult, "ImpactResult cannot be null");
}
public ImpactResult getImpactResult()
{
return result;
}
public enum ImpactResult
{
/**
* The default behaviour, the projectile will be destroyed and the hit will be processed.
*/
DEFAULT,
/**
* The projectile will pass through the current entity as if it wasn't there. This will return default behaviour if there is no entity.
*/
SKIP_ENTITY,
/**
* Damage the entity and stop the projectile here, the projectile will not pierce.
*/
STOP_AT_CURRENT,
/**
* Cancel the piercing aspect of the projectile, and do not damage the entity.
*/
STOP_AT_CURRENT_NO_DAMAGE
}
}
@@ -0,0 +1,113 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.event.entity.living;
import org.jetbrains.annotations.ApiStatus;
import net.minecraft.world.entity.LivingEntity;
import net.minecraftforge.common.ForgeHooks;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.eventbus.api.Cancelable;
/**
* LivingBreatheEvent is fired whenever a living entity ticks.<br>
* <br>
* This event is fired via {@link ForgeHooks#onLivingBreathe(LivingEntity, int, int)}.<br>
* <br>
* This event is not {@link Cancelable}.<br>
* <br>
* This event does not have a result. {@link HasResult}
* <br>
* This event is fired on {@link MinecraftForge#EVENT_BUS}
*/
public class LivingBreatheEvent extends LivingEvent {
private boolean canBreathe;
private boolean canRefillAir;
private int consumeAirAmount;
private int refillAirAmount;
@ApiStatus.Internal
@Deprecated(forRemoval = true, since = "1.20.1")
public LivingBreatheEvent(LivingEntity entity, boolean canBreathe, int consumeAirAmount, int refillAirAmount) {
this(entity, canBreathe, consumeAirAmount, refillAirAmount, canBreathe);
}
@ApiStatus.Internal
public LivingBreatheEvent(LivingEntity entity, boolean canBreathe, int consumeAirAmount, int refillAirAmount, boolean canRefillAir) {
super(entity);
this.canBreathe = canBreathe;
this.canRefillAir = canRefillAir;
this.consumeAirAmount = Math.max(consumeAirAmount, 0);
this.refillAirAmount = Math.max(refillAirAmount, 0);
}
/**
* If the entity can breathe and {@link #canRefillAir()} returns true, their air value will be increased by {@link #getRefillAirAmount()}.<br>
* If the entity can breathe and {@link #canRefillAir()} returns false, their air value will stay the same.<br>
* If the entity cannot breathe, their air value will be reduced by {@link #getConsumeAirAmount()}.
* @return True if the entity can breathe
*/
public boolean canBreathe() {
return canBreathe;
}
/**
* Sets if the entity can breathe or not.
* @param canBreathe The new value.
*/
public void setCanBreathe(boolean canBreathe) {
this.canBreathe = canBreathe;
}
/**
* If the entity can breathe, {@link #canRefillAir()} will be checked to see if their air value should be refilled.
* @return True if the entity can refill its air value
*/
public boolean canRefillAir() {
return canRefillAir;
}
/**
* Sets if the entity can refill its air value or not.
* @param canRefillAir The new value.
*/
public void setCanRefillAir(boolean canRefillAir) {
this.canRefillAir = canRefillAir;
}
/**
* @return The amount the entity's {@linkplain LivingEntity#getAirSupply() air supply} will be reduced by if the entity {@linkplain #canBreathe() cannot breathe}.
*/
public int getConsumeAirAmount() {
return consumeAirAmount;
}
/**
* Sets the new consumed air amount.
* @param consumeAirAmount The new value.
* @see #getConsumeAirAmount()
*/
public void setConsumeAirAmount(int consumeAirAmount) {
this.consumeAirAmount = Math.max(consumeAirAmount, 0);
}
/**
* @return The amount the entity's {@linkplain LivingEntity#getAirSupply() air supply} will be increased by if the entity {@linkplain #canBreathe() can breathe}.
*/
public int getRefillAirAmount() {
return refillAirAmount;
}
/**
* Sets the new refilled air amount.
*
* @param refillAirAmount The new value.
* @see #getRefillAirAmount()
*/
public void setRefillAirAmount(int refillAirAmount) {
this.refillAirAmount = Math.max(refillAirAmount, 0);
}
}
@@ -0,0 +1,131 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.event.entity.living;
import org.jetbrains.annotations.ApiStatus;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.world.damagesource.DamageSources;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraftforge.common.ForgeHooks;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.eventbus.api.Cancelable;
/**
* LivingDrownEvent is fired whenever a living entity can't breathe and its air supply is less than or equal to zero.
* <p>
* This event is fired via {@link ForgeHooks#onLivingBreathe(LivingEntity, int, int)}.
* <p>
* This event is {@link Cancelable}. Effects of cancellation are noted in {@link #setCanceled(boolean)}.
* <p>
* This event does not {@linkplain HasResult have a result}.
* This event is fired on {@link MinecraftForge#EVENT_BUS}
**/
@Cancelable
public class LivingDrownEvent extends LivingEvent {
private boolean isDrowning;
private float damageAmount;
private int bubbleCount;
/**
* Constructs a new LivingDrownEvent.
*
* @param entity The entity that is drowning.
* @param isDrowning If the entity is "actively" drowning, and would take damage.
* @param damageAmount The amount of {@linkplain DamageSources#drown() drowning damage} the entity would take.
* @param bubbleCount The number of {@linkplain ParticleTypes#BUBBLE} particles that will be spawned when actively drowning.
*/
@ApiStatus.Internal
public LivingDrownEvent(LivingEntity entity, boolean isDrowning, float damageAmount, int bubbleCount) {
super(entity);
this.isDrowning = isDrowning;
this.damageAmount = damageAmount;
this.bubbleCount = bubbleCount;
}
@ApiStatus.Internal
@Deprecated(forRemoval = true, since = "1.20.1")
public LivingDrownEvent(LivingEntity entity, boolean isDrowning) {
this(entity, isDrowning, 2.0F, 8);
}
/**
* This method returns true if the entity is "actively" drowning.<br>
* For most entities, this happens when their air supply reaches -20.<br>
* When this is true, the entity will take damage, spawn particles, and reset their air supply to 0.
*
* @return If the entity is actively drowning.
*/
public boolean isDrowning() {
return isDrowning;
}
/**
* Sets if the entity is actively drowning.
*
* @param isDrowning The new value.
* @see #isDrowning()
*/
public void setDrowning(boolean isDrowning) {
this.isDrowning = isDrowning;
}
/**
* Gets the amount of {@linkplain DamageSources#drown() drowning damage} the entity would take.<br>
* Drowning damage is only inflicted if the entity is {@linkplain #isDrowning() actively drowning}.<br>
* For vanilla entities, the default amount of damage is 2 (1 heart).
* <p>
* If the damage amount is less than or equal to zero, {@link Entity#hurt} will not be called.
*
* @return The amount of damage that will be dealt to the entity when actively drowning.
*/
public float getDamageAmount() {
return damageAmount;
}
/**
* Sets the amount of drowning damage that may be inflicted.
*
* @param damageAmount The new value.
* @see #getDamageAmount()
*/
public void setDamageAmount(float damageAmount) {
this.damageAmount = damageAmount;
}
/**
* Gets the number of {@linkplain ParticleTypes#BUBBLE} particles that would be spawned.<br>
* Bubbles are only spawned if the entity is {@linkplain #isDrowning() actively drowning}.<br>
* For vanilla entities, the default value is 8 particles.
*
* @return The number of bubble particles that will spawn when actively drowning.
*/
public int getBubbleCount() {
return bubbleCount;
}
/**
* Sets the amount of bubbles that may be spawned.
*
* @param bubbleCount The new value.
* @see #getBubbleCount()
*/
public void setBubbleCount(int bubbleCount) {
this.bubbleCount = bubbleCount;
}
/**
* Cancels the drowning event.<br>
* Cancellation is mostly equivalent to {@link #setDrowning(boolean)} with a value of false.<br>
* However, this also incurs the usual side effects of cancellation.
*/
@Override
public void setCanceled(boolean cancel) {
super.setCanceled(cancel);
}
}
@@ -0,0 +1,48 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.event.entity.living;
import com.mojang.serialization.Dynamic;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.Brain;
import net.minecraftforge.common.ForgeHooks;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.util.BrainBuilder;
import net.minecraftforge.eventbus.api.Cancelable;
/**
* LivingMakeBrainEvent is fired whenever a new {@link net.minecraft.world.entity.ai.Brain} instance is created using {@link LivingEntity#makeBrain(Dynamic)}.<br>
* <br>
* To access the internal {@link BrainBuilder}, call {@link LivingMakeBrainEvent#getTypedBrainBuilder(LivingEntity)} using the downcasted {@link LivingEntity} obtained from {@link LivingEvent#getEntity()}.<br>
* <br>
* The BrainBuilder will initially contain all the state found in the original Brain instance.<br>
* <br>
* After this event is posted, a fresh Brain instance will be created using the encapsulated state found in the BrainBuilder
* and replace the previously created Brain instance for the entity.<br>
* <br>
* This event is fired via the {@link ForgeHooks#onLivingMakeBrain(LivingEntity, Brain, Dynamic)}.<br>
* <br>
* This event is not {@link Cancelable}.<br>
* <br>
* This event does not have a result. {@link HasResult}<br>
* <br>
* This event is fired on the {@link MinecraftForge#EVENT_BUS}.
**/
public class LivingMakeBrainEvent extends LivingEvent
{
private final BrainBuilder<?> brainBuilder;
public LivingMakeBrainEvent(LivingEntity entity, BrainBuilder<?> brainBuilder)
{
super(entity);
this.brainBuilder = brainBuilder;
}
public <E extends LivingEntity> BrainBuilder<E> getTypedBrainBuilder(E ignoredEntity)
{
return (BrainBuilder<E>) this.brainBuilder;
}
}
@@ -0,0 +1,79 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.event.entity.living;
import net.minecraft.server.network.ServerGamePacketListenerImpl;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.eventbus.api.Cancelable;
import org.jetbrains.annotations.ApiStatus;
public class LivingSwapItemsEvent extends LivingEvent
{
@ApiStatus.Internal
public LivingSwapItemsEvent(LivingEntity entity)
{
super(entity);
}
/**
* This event is fired when a living entity is about to swap the items in their main and offhand.
* This event is executed in {@link ServerGamePacketListenerImpl#handlePlayerAction}
*
* <p>This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.
*/
@Cancelable
public static class Hands extends LivingSwapItemsEvent
{
private ItemStack toMainHand;
private ItemStack toOffHand;
@ApiStatus.Internal
public Hands(LivingEntity entity)
{
super(entity);
this.toMainHand = entity.getOffhandItem(); //the main hand will be swapped with the offhand
this.toOffHand = entity.getMainHandItem(); //the offhand will be swapped with the main hand
}
/**
* Gets the item that will be swapped to the main hand of the entity.
* @return The item that will be swapped to the main hand.
*/
public ItemStack getItemSwappedToMainHand()
{
return toMainHand;
}
/**
* Gets the item that will be swapped to the offhand of the entity.
* @return The item that will be swapped to the offhand.
*/
public ItemStack getItemSwappedToOffHand()
{
return toOffHand;
}
/**
* Sets the item that will be swapped to the main hand of the entity.
* @param item The item to swap to the main hand.
*/
public void setItemSwappedToMainHand(ItemStack item)
{
this.toMainHand = item;
}
/**
* Sets the item that will be swapped to the offhand of the entity.
* @param item The item to swap to the offhand.
*/
public void setItemSwappedToOffHand(ItemStack item)
{
this.toOffHand = item;
}
}
}
Loaded 100 of 136 files, more files were not shown because too many files have changed in this diff. Show more