Compare commits

...
24 Commits
Author SHA1 Message Date
LexManos bc2d0d1b25 1.19.2 RB 3 2023-09-21 11:59:41 -07:00
Paint_Ninja e2c1da98be Fix Level leak in debug HUD (#9701) 2023-09-03 11:03:37 -07:00
Paint_Ninjaanddhyces 0f6d11b1ee Keep order of sources in PackRepository (#9704)
Co-authored-by: dhyces <[email protected]>
2023-09-02 16:21:33 -07:00
Jonathan Colmenares 340d332e19 Fix parameter names in IForgeDimensionSpecialEffects.adjustLightmapColors to better describe what they are. (#9658) 2023-07-17 09:45:45 -07:00
Jonathan Colmenares 56f19dd53d Re-add in-game mod menu (#9655) 2023-07-17 08:51:03 -07:00
brandon3055 1fe420e4ab Fixed FluidUtil#tryFillContainer returning invalid result when simulating (#9358) 2023-07-15 10:52:57 -07:00
bconlon 945209c283 AlterGroundEvent for modifying block placement performed by AlterGroundDecorator (#9635) 2023-07-13 17:32:31 -07:00
embeddedt 3e5c3cabd5 Bump ASM to 9.5 (#9516) 2023-07-11 09:26:12 -07:00
Paint_Ninja b0f5a13f52 Improve logging for server connections (#9623) 2023-07-11 09:25:56 -07:00
Paint_Ninja 15fe8441f0 Log a proper duplicate mod(s) error message (#9625) 2023-07-11 09:25:42 -07:00
Brennan Ward babef71616 Fix erroneous getLevel call when firing SpecialSpawn (#9520) 2023-06-07 13:22:00 +00:00
Brennan Ward 1dd18ca27c [1.19.2] Fix the rest of the spawn event calls (#9482) 2023-05-31 11:52:38 +00:00
TelepathicGrunt 65c7390874 Loosen access for BucketItem's canBlockContainFluid (#9429) 2023-05-29 19:16:05 +00:00
Brennan WardandBrennan Ward fe3ad3b8f2 Fix event result being ignored (#9484)
Co-authored-by: Brennan Ward <[email protected]>
2023-05-08 22:52:15 +01:00
Brennan WardandBrennan Ward d05e76f7c4 Fix incorrect SpecialSpawn fire location (#9480)
Co-authored-by: Brennan Ward <[email protected]>
2023-05-03 07:08:07 +01:00
SizableShrimp bfa97bf097 [1.19.2] Fix forge grindstone hooks allowing stacks of non-stackable items (#9466) 2023-05-01 18:39:56 -05:00
Dennis C 469e9a6c1a Fix JSON model root transforms (#9411) 2023-03-22 11:09:58 +01:00
ferriarnus 58456c85af Fix StemBlock not checking canSustainPlant for the correct block
It now checks for Melons/Pumpkins instead of the stem itself.
2023-03-15 11:50:31 -07:00
cech12 7fe5b02ef3 Fix of inconsistent vaporization in BucketItem & FluidType (#9340) 2023-02-24 13:18:43 -08:00
SizableShrimp 184392e02e Backport ClientChatReceivedEvent.System for 1.19.2. Fixes #9352 (#9355) 2023-02-24 10:47:07 -08:00
Jonathan Colmenares d25a5466db Fire TickEvent.LevelTickEvent on ClientLevel tick (#9302) 2023-01-25 13:41:46 -08:00
Dennis C b5073c10ef Disable guiLight3d for generated item models (#9231) 2022-12-30 17:59:43 +01:00
sciwhiz12 16bc7cf783 Fix config key used by resource cache (#9253)
This bring it in line with the config key defined in the spec and
default config file in ResourceManagerBootCacheConfigurationHandler.

Fixes #9252
2022-12-26 13:20:27 -08:00
sciwhiz12 2d714f034f [1.19.2] Fix compatibility checker task configuration (#9233)
* Fix compatibility checker task configuration

The setupCheckJarCompatibility task exists to configure the main
compatibility checker task, checkJarCompatibility, because certain
configuration steps for that task could not be done until after the
configuration phase of Gradle.

However, that setup task previously held all the configuration for the
main check task in its task action. This caused problems because the
main check task's inputs are linked to other tasks, and the previous
situation made it so its configuration (by the setup task) happened
_after_ Gradle built the task dependency model/tree.

This meant that certain tasks which the main check task depended on did
not run before that task, because Gradle was unaware of this inter-task
dependency until it was too late (when it was already executing tasks).

This fixes the issue by moving the bulk of the configuration for the
main check task from the action of the setup task to the main
buildscript, therefore allowing Gradle to know about those task
dependencies and factor them in to its process of determining what tasks
to run and in what order.

The remaining configuration step in the setup task for the main check
task is linked to the setup task, and does not affect the task's
dependencies (because it uses a configuration which it resolves
immediately), so it stays in the setup task.

* Force checker setup task to never be up-to-date

The setup task configures the main check task, so it should always run
before that task. However, because it has an input and output, the setup
task is affected by Gradle's incremental build feature, which leads to
the possibility that Gradle considers the setup task as up-to-date,
therefore not executing its action and causing errors with the main
check task down the line.
2022-12-17 18:50:26 +01:00
57 changed files with 774 additions and 112 deletions

No files matched your search

+9 -1
View File
@@ -47,7 +47,7 @@ ext {
MODLAUNCHER_VERSION = '10.0.8'
SECUREJARHANDLER_VERSION = '2.1.4'
BOOTSTRAPLAUNCHER_VERSION = '1.1.2'
ASM_VERSION = '9.3'
ASM_VERSION = '9.5'
INSTALLER_VERSION = '2.1.+'
MIXIN_VERSION = '0.8.5'
TERMINALCONSOLEAPPENDER_VERSION = '1.2.0'
@@ -1241,6 +1241,14 @@ project(':forge') {
dependsOn 'setupCheckJarCompatibility'
baseJar = project.tasks.named('mergeBaseForgeJar').flatMap { it.output }
baseLibraries.from(project.tasks.named('createJoinedSRG').flatMap { it.output })
inputJar = project.tasks.named('reobfJar').flatMap { it.output }
concreteLibraries.from(project.PACKED_DEPS.collect { project.rootProject.tasks.getByPath(it).archiveFile })
commonLibraries.from(project.configurations.minecraftImplementation)
commonLibraries.from(project.configurations.installer)
commonLibraries.from(project.configurations.moduleonly)
}
task checkAll(dependsOn: [checkATs, checkSAS, checkExcs, findFieldInstanceChecks, checkPatches, checkLicenses]){}
+3 -3
View File
@@ -4,8 +4,8 @@ repositories {
}
dependencies {
implementation 'org.ow2.asm:asm:9.3'
implementation 'org.ow2.asm:asm-tree:9.3'
implementation 'net.minecraftforge:srgutils:0.4.+'
implementation 'org.ow2.asm:asm:9.5'
implementation 'org.ow2.asm:asm-tree:9.5'
implementation 'net.minecraftforge:srgutils:0.5.+'
implementation 'commons-io:commons-io:2.8.0'
}
@@ -18,6 +18,7 @@ abstract class SetupCheckJarCompatibility extends DefaultTask {
onlyIf {
inputVersion.getOrNull() != null
}
outputs.upToDateWhen { false } // Never up to date, because this setup task should always run
baseBinPatchesOutput.convention(project.layout.buildDirectory.dir(name).map { it.file('joined.lzma') })
}
@@ -31,17 +32,9 @@ abstract class SetupCheckJarCompatibility extends DefaultTask {
}.toArray(Dependency[]::new))
project.tasks.named('checkJarCompatibility') {
baseLibraries.from(project.tasks.createJoinedSRG.output)
baseLibraries.from(project.provider {
fmlLibs.resolvedConfiguration.lenientConfiguration.files
})
inputJar = project.tasks.reobfJar.output
concreteLibraries.from(project.PACKED_DEPS.collect { project.rootProject.tasks.getByPath(it).archiveFile })
commonLibraries.from(project.configurations.minecraftImplementation)
commonLibraries.from(project.configurations.installer)
commonLibraries.from(project.configurations.moduleonly)
}
def baseForgeUserdev = project.layout.buildDirectory.dir(name).map { it.file("forge-${inputVersion}-userdev.jar") }.get().asFile
+3 -2
View File
@@ -10,8 +10,9 @@ Forge is a free, open-source modding API all of your favourite mods use!
| Version | Support |
|---------| ------------- |
| 1.19.x | Active |
| 1.18.x | LTS |
| 1.20.x | Active |
| 1.19.4 | Legacy |
| 1.19.2 | Legacy |
* [Download]
* [Forum]
@@ -11,11 +11,17 @@ import net.minecraftforge.forgespi.language.IModInfo;
import org.apache.maven.artifact.versioning.ArtifactVersion;
import org.slf4j.Logger;
import java.util.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import static java.util.stream.Collectors.*;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.joining;
import static net.minecraftforge.fml.loading.LogMarkers.LOADING;
public class UniqueModListBuilder
{
@@ -66,28 +72,34 @@ public class UniqueModListBuilder
// Its theoretically possible that some mod has somehow moved an id to a secondary place, thus causing a dupe.
// We can't handle this
final List<IModInfo> dupedMods = modIds.values().stream()
final List<String> dupedModErrors = modIds.values().stream()
.filter(modInfos -> modInfos.size() > 1)
.map(modInfos -> modInfos.get(0))
.toList();
.map(mods -> String.format("\tMod ID: '%s' from mod files: %s",
mods.get(0).getModId(),
mods.stream()
.map(modInfo -> modInfo.getOwningFile().getFile().getFileName()).collect(joining(", "))
)).toList();
if (!dupedMods.isEmpty()) {
final List<EarlyLoadingException.ExceptionData> duplicateModErrors = dupedMods.stream()
.map(dm -> new EarlyLoadingException.ExceptionData("fml.modloading.dupedmod", dm, Objects.toString(dm)))
.toList();
throw new EarlyLoadingException("Duplicate mods found", null, duplicateModErrors);
if (!dupedModErrors.isEmpty()) {
LOGGER.error(LOADING, "Found duplicate mods:\n{}", dupedModErrors.stream().collect(joining("\n")));
throw new EarlyLoadingException("Duplicate mods found", null, dupedModErrors.stream()
.map(s -> new EarlyLoadingException.ExceptionData(s))
.toList());
}
final List<ModFile> dupedLibs = versionedLibIds.values().stream()
final List<String> dupedLibErrors = versionedLibIds.values().stream()
.filter(modFiles -> modFiles.size() > 1)
.map(modFiles -> modFiles.get(0))
.toList();
.map(mods -> String.format("\tLibrary: '%s' from files: %s",
getModId(mods.get(0)),
mods.stream()
.map(modFile -> modFile.getFileName()).collect(joining(", "))
)).toList();
if (!dupedLibs.isEmpty()) {
final List<EarlyLoadingException.ExceptionData> duplicateLibErrors = dupedLibs.stream()
.map(dm -> new EarlyLoadingException.ExceptionData("fml.modloading.dupedlib.versioned", dm, Objects.toString(dm)))
.toList();
throw new EarlyLoadingException("Duplicate plugins or libraries found", null, duplicateLibErrors);
if (!dupedLibErrors.isEmpty()) {
LOGGER.error(LOADING, "Found duplicate plugins or libraries:\n{}", dupedLibErrors.stream().collect(joining("\n")));
throw new EarlyLoadingException("Duplicate plugins or libraries found", null, dupedLibErrors.stream()
.map(s -> new EarlyLoadingException.ExceptionData(s))
.toList());
}
// Collect unique mod files by module name. This will be used for deduping purposes
@@ -342,6 +342,22 @@
this.f_91026_.m_6180_("gui");
this.f_240378_.m_240688_();
this.f_91065_.m_193832_(this.f_91012_);
@@ -1749,6 +_,7 @@
this.f_91005_.m_120596_();
+ net.minecraftforge.event.ForgeEventFactory.onPreLevelTick(this.f_91073_, () -> true);
try {
this.f_91073_.m_104726_(() -> {
return true;
@@ -1764,6 +_,7 @@
throw new ReportedException(crashreport);
}
+ net.minecraftforge.event.ForgeEventFactory.onPostLevelTick(this.f_91073_, () -> true);
}
this.f_91026_.m_6182_("animateTick");
@@ -1783,6 +_,8 @@
this.f_91026_.m_6182_("keyboard");
this.f_91068_.m_90931_();
@@ -0,0 +1,11 @@
--- a/net/minecraft/client/gui/screens/ConnectScreen.java
+++ b/net/minecraft/client/gui/screens/ConnectScreen.java
@@ -73,6 +_,8 @@
}
if (!optional.isPresent()) {
+ ConnectScreen.f_95683_.error("Couldn't connect to server: Unknown host \"{}\"", p_169266_.m_171863_());
+ net.minecraftforge.network.DualStackUtils.logInitialPreferences();
p_169265_.execute(() -> {
p_169265_.m_91152_(new DisconnectedScreen(ConnectScreen.this.f_95686_, CommonComponents.f_130661_, ConnectScreen.f_169260_));
});
@@ -0,0 +1,14 @@
--- a/net/minecraft/client/gui/screens/PauseScreen.java
+++ b/net/minecraft/client/gui/screens/PauseScreen.java
@@ -77,9 +_,10 @@
this.f_96541_.m_91152_(new SocialInteractionsScreen());
}));
}
+ this.m_142416_(new Button(this.f_96543_ / 2 - 102, this.f_96544_ / 4 + 120 - 16, 204, 20, Component.m_237115_("fml.menu.mods"), modButton -> this.f_96541_.m_91152_(new net.minecraftforge.client.gui.ModListScreen(this))));
Component component = this.f_96541_.m_91090_() ? Component.m_237115_("menu.returnToMenu") : Component.m_237115_("menu.disconnect");
- this.m_142416_(new Button(this.f_96543_ / 2 - 102, this.f_96544_ / 4 + 120 + -16, 204, 20, component, (p_96315_) -> {
+ this.m_142416_(new Button(this.f_96543_ / 2 - 102, this.f_96544_ / 4 + 144 + -16, 204, 20, component, (p_96315_) -> {
boolean flag = this.f_96541_.m_91090_();
boolean flag1 = this.f_96541_.m_91294_();
p_96315_.f_93623_ = false;
@@ -30,3 +30,12 @@
this.m_241119_(p_241518_, p_241542_.m_237220_());
this.m_240498_(p_241510_, p_241542_.m_241109_());
this.f_240659_ = Util.m_137550_();
@@ -263,6 +_,8 @@
public void m_240494_(Component p_240522_, boolean p_240642_) {
if (!this.f_240348_.f_91066_.m_231833_().m_231551_() || !this.f_240348_.m_91246_(this.m_240473_(p_240522_))) {
+ p_240522_ = net.minecraftforge.client.ForgeHooksClient.onClientSystemChat(p_240522_, p_240642_);
+ if (p_240522_ == null) return;
if (p_240642_) {
this.f_240348_.f_91065_.m_93063_(p_240522_, false);
} else {
@@ -1,10 +1,11 @@
--- a/net/minecraft/client/renderer/block/model/ItemModelGenerator.java
+++ b/net/minecraft/client/renderer/block/model/ItemModelGenerator.java
@@ -39,6 +_,7 @@
@@ -39,6 +_,8 @@
map.put("particle", p_111672_.m_111477_("particle") ? Either.left(p_111672_.m_111480_("particle")) : map.get("layer0"));
BlockModel blockmodel = new BlockModel((ResourceLocation)null, list, map, false, p_111672_.m_111479_(), p_111672_.m_111491_(), p_111672_.m_111484_());
blockmodel.f_111416_ = p_111672_.f_111416_;
+ blockmodel.customData.copyFrom(p_111672_.customData);
+ blockmodel.customData.setGui3d(false);
return blockmodel;
}
@@ -1,5 +1,14 @@
--- a/net/minecraft/core/dispenser/DispenseItemBehavior.java
+++ b/net/minecraft/core/dispenser/DispenseItemBehavior.java
@@ -343,7 +_,7 @@
DispensibleContainerItem dispensiblecontaineritem = (DispensibleContainerItem)p_123562_.m_41720_();
BlockPos blockpos = p_123561_.m_7961_().m_121945_(p_123561_.m_6414_().m_61143_(DispenserBlock.f_52659_));
Level level = p_123561_.m_7727_();
- if (dispensiblecontaineritem.m_142073_((Player)null, level, blockpos, (BlockHitResult)null)) {
+ if (dispensiblecontaineritem.emptyContents((Player)null, level, blockpos, (BlockHitResult)null, p_123562_)) {
dispensiblecontaineritem.m_142131_((Player)null, level, p_123562_, blockpos);
return new ItemStack(Items.f_42446_);
} else {
@@ -402,9 +_,10 @@
level.m_46597_(blockpos, BaseFireBlock.m_49245_(level, blockpos));
level.m_142346_((Entity)null, GameEvent.f_157797_, blockpos);
@@ -0,0 +1,10 @@
--- a/net/minecraft/server/commands/SummonCommand.java
+++ b/net/minecraft/server/commands/SummonCommand.java
@@ -55,6 +_,7 @@
throw f_138810_.create();
} else {
if (p_138825_ && entity instanceof Mob) {
+ if (!net.minecraftforge.event.ForgeEventFactory.doSpecialSpawn((Mob)entity, p_138821_.m_81372_(), (float)entity.m_20185_(), (float)entity.m_20186_(), (float)entity.m_20189_(), null, MobSpawnType.COMMAND))
((Mob)entity).m_6518_(p_138821_.m_81372_(), p_138821_.m_81372_().m_6436_(entity.m_20183_()), MobSpawnType.COMMAND, (SpawnGroupData)null, (CompoundTag)null);
}
@@ -5,7 +5,7 @@
public PackRepository(Pack.PackConstructor p_10502_, RepositorySource... p_10503_) {
this.f_10500_ = p_10502_;
- this.f_10497_ = ImmutableSet.copyOf(p_10503_);
+ this.f_10497_ = new java.util.HashSet<>(java.util.Arrays.asList(p_10503_));
+ this.f_10497_ = new java.util.LinkedHashSet<>(List.of(p_10503_)); //Forge: This needs to be a mutable set, so that we can add to it later on.
}
public PackRepository(PackType p_143890_, RepositorySource... p_143891_) {
@@ -0,0 +1,12 @@
--- a/net/minecraft/util/SpawnUtil.java
+++ b/net/minecraft/util/SpawnUtil.java
@@ -24,7 +_,8 @@
if (p_216406_.m_6857_().m_61937_(blockpos$mutableblockpos) && m_216398_(p_216406_, p_216410_, blockpos$mutableblockpos, p_216411_)) {
T t = p_216404_.m_20655_(p_216406_, (CompoundTag)null, (Component)null, (Player)null, blockpos$mutableblockpos, p_216405_, false, false);
if (t != null) {
- if (t.m_5545_(p_216406_, p_216405_) && t.m_6914_(p_216406_)) {
+ int res = net.minecraftforge.common.ForgeHooks.canEntitySpawn(t, p_216406_, t.m_20185_(), t.m_20186_(), t.m_20189_(), null, p_216405_);
+ if (res == 1 || (res == 0 && t.m_5545_(p_216406_, p_216405_) && t.m_6914_(p_216406_))) {
p_216406_.m_47205_(t);
return Optional.of(t);
}
@@ -33,14 +33,14 @@
}
@Nullable
@@ -326,6 +_,7 @@
public T m_20600_(ServerLevel p_20601_, @Nullable CompoundTag p_20602_, @Nullable Component p_20603_, @Nullable Player p_20604_, BlockPos p_20605_, MobSpawnType p_20606_, boolean p_20607_, boolean p_20608_) {
T t = this.m_20655_(p_20601_, p_20602_, p_20603_, p_20604_, p_20605_, p_20606_, p_20607_, p_20608_);
if (t != null) {
+ if (t instanceof net.minecraft.world.entity.Mob && net.minecraftforge.event.ForgeEventFactory.doSpecialSpawn((net.minecraft.world.entity.Mob) t, p_20601_, p_20605_.m_123341_(), p_20605_.m_123342_(), p_20605_.m_123343_(), null, p_20606_)) return null;
p_20601_.m_47205_(t);
}
@@ -351,6 +_,7 @@
Mob mob = (Mob)t;
mob.f_20885_ = mob.m_146908_();
mob.f_20883_ = mob.m_146908_();
+ if (!net.minecraftforge.event.ForgeEventFactory.doSpecialSpawn(mob, p_20656_, (float) mob.m_20185_(), (float) mob.m_20186_(), (float) mob.m_20189_(), null, p_20661_))
mob.m_6518_(p_20656_, p_20656_.m_6436_(mob.m_20183_()), p_20661_, (SpawnGroupData)null, p_20657_);
mob.m_8032_();
}
@@ -543,14 +_,23 @@
}
@@ -1,5 +1,14 @@
--- a/net/minecraft/world/entity/Mob.java
+++ b/net/minecraft/world/entity/Mob.java
@@ -116,6 +_,8 @@
private CompoundTag f_21359_;
private BlockPos f_21360_ = BlockPos.f_121853_;
private float f_21341_ = -1.0F;
+ @Nullable
+ private MobSpawnType spawnType;
protected Mob(EntityType<? extends Mob> p_21368_, Level p_21369_) {
super(p_21368_, p_21369_);
@@ -210,7 +_,11 @@
}
@@ -13,6 +22,31 @@
}
public boolean m_6549_(EntityType<?> p_21399_) {
@@ -408,6 +_,9 @@
p_21484_.m_128379_("NoAI", this.m_21525_());
}
+ if (this.spawnType != null) {
+ p_21484_.m_128359_("forge:spawn_type", this.spawnType.name());
+ }
}
public void m_7378_(CompoundTag p_21450_) {
@@ -460,6 +_,14 @@
}
this.m_21557_(p_21450_.m_128471_("NoAI"));
+
+ if (p_21450_.m_128441_("forge:spawn_type")) {
+ try {
+ this.spawnType = MobSpawnType.valueOf(p_21450_.m_128461_("forge:spawn_type"));
+ } catch (Exception ex) {
+ p_21450_.m_128473_("forge:spawn_type");
+ }
+ }
}
protected void m_7625_(DamageSource p_21389_, boolean p_21390_) {
@@ -499,9 +_,9 @@
public void m_8107_() {
super.m_8107_();
@@ -39,7 +73,26 @@
if (entity != null) {
double d0 = entity.m_20280_(this);
int i = this.m_6095_().m_20674_().m_21611_();
@@ -1374,13 +_,23 @@
@@ -990,6 +_,10 @@
}
+ /**
+ * <p>Calls to this method should be accompanied by firing the {@link net.minecraftforge.event.entity.living.LivingSpawnEvent.SpecialSpawn SpecialSpawn} event via {@link net.minecraftforge.event.ForgeEventFactory#doSpecialSpawn}.</p>
+ * Additionally, if you override this method, you should ensure you either call super, or manually set {@link #spawnType} from your override.
+ */
@Nullable
public SpawnGroupData m_6518_(ServerLevelAccessor p_21434_, DifficultyInstance p_21435_, MobSpawnType p_21436_, @Nullable SpawnGroupData p_21437_, @Nullable CompoundTag p_21438_) {
RandomSource randomsource = p_21434_.m_213780_();
@@ -1000,6 +_,7 @@
this.m_21559_(false);
}
+ this.spawnType = p_21436_;
return p_21437_;
}
@@ -1374,15 +_,25 @@
return false;
}
@@ -56,11 +109,30 @@
this.m_20256_(this.m_20184_().m_82520_(0.0D, 0.3D, 0.0D));
}
+ }
+
}
+ @Override
+ public void jumpInFluid(net.minecraftforge.fluids.FluidType type) {
+ this.jumpInLiquidInternal(() -> super.jumpInFluid(type));
}
+ }
+
public void m_147272_() {
this.f_21345_.m_148096_();
this.m_6274_().m_147343_();
@@ -1404,5 +_,16 @@
public Iterable<BlockPos> m_238383_() {
return ImmutableSet.of(new BlockPos(this.m_20191_().f_82288_, (double)this.m_146904_(), this.m_20191_().f_82290_), new BlockPos(this.m_20191_().f_82288_, (double)this.m_146904_(), this.m_20191_().f_82293_), new BlockPos(this.m_20191_().f_82291_, (double)this.m_146904_(), this.m_20191_().f_82290_), new BlockPos(this.m_20191_().f_82291_, (double)this.m_146904_(), this.m_20191_().f_82293_));
+ }
+
+ /**
+ * {@return the type of spawn that created this mob, if applicable}
+ * If it could not be determined, this will return null.
+ * <p>
+ * This is set via {@link Mob#finalizeSpawn}, so you should not call this from within that method, and instead use the parameter.
+ */
+ @Nullable
+ public final MobSpawnType getSpawnType() {
+ return this.spawnType;
}
}
@@ -0,0 +1,10 @@
--- a/net/minecraft/world/entity/monster/Strider.java
+++ b/net/minecraft/world/entity/monster/Strider.java
@@ -418,6 +_,7 @@
private SpawnGroupData m_33881_(ServerLevelAccessor p_33882_, DifficultyInstance p_33883_, Mob p_33884_, @Nullable SpawnGroupData p_33885_) {
p_33884_.m_7678_(this.m_20185_(), this.m_20186_(), this.m_20189_(), this.m_146908_(), 0.0F);
+ if (!net.minecraftforge.event.ForgeEventFactory.doSpecialSpawn(p_33884_, p_33882_, (float)p_33884_.m_20185_(), (float)p_33884_.m_20186_(), (float)p_33884_.m_20189_(), null, MobSpawnType.JOCKEY))
p_33884_.m_6518_(p_33882_, p_33883_, MobSpawnType.JOCKEY, p_33885_, (CompoundTag)null);
p_33884_.m_7998_(this, true);
return new AgeableMob.AgeableMobGroupData(0.0F);
@@ -1,11 +1,13 @@
--- a/net/minecraft/world/entity/npc/CatSpawner.java
+++ b/net/minecraft/world/entity/npc/CatSpawner.java
@@ -86,8 +_,9 @@
@@ -86,8 +_,11 @@
if (cat == null) {
return 0;
} else {
+ cat.m_20035_(p_35334_, 0.0F, 0.0F); // Fix MC-147659: Some witch huts spawn the incorrect cat
+ if(net.minecraftforge.common.ForgeHooks.canEntitySpawn(cat, p_35335_, p_35334_.m_123341_(), p_35334_.m_123342_(), p_35334_.m_123343_(), null, MobSpawnType.NATURAL) == -1) return 0;
+ // Note: This call to canEntitySpawn is erroneous, it is only provided for backwards compatibility.
+ if (net.minecraftforge.common.ForgeHooks.canEntitySpawn(cat, p_35335_, p_35334_.m_123341_(), p_35334_.m_123342_(), p_35334_.m_123343_(), null, MobSpawnType.NATURAL) == -1) return 0;
+ if (!net.minecraftforge.event.ForgeEventFactory.doSpecialSpawn(cat, p_35335_, p_35334_.m_123341_(), p_35334_.m_123342_(), p_35334_.m_123343_(), null, MobSpawnType.NATURAL))
cat.m_6518_(p_35335_, p_35335_.m_6436_(p_35334_), MobSpawnType.NATURAL, (SpawnGroupData)null, (CompoundTag)null);
- cat.m_20035_(p_35334_, 0.0F, 0.0F);
p_35335_.m_47205_(cat);
@@ -67,6 +67,17 @@
if (!ItemStack.m_41728_(itemstack, itemstack1)) {
this.f_39559_.m_6836_(0, ItemStack.f_41583_);
this.m_38946_();
@@ -163,6 +_,10 @@
itemstack2 = flag3 ? itemstack : itemstack1;
}
+ // Forge: Skip the repair if the result would give an item stack with a count not normally obtainable
+ if (j > itemstack2.m_41741_())
+ this.f_39559_.m_6836_(0, ItemStack.f_41583_);
+ else
this.f_39559_.m_6836_(0, this.m_39579_(itemstack2, i, j));
}
@@ -175,7 +_,7 @@
for(Map.Entry<Enchantment, Integer> entry : map.entrySet()) {
@@ -38,15 +38,44 @@
p_40704_.m_5496_(p_150709_, 1.0F, 1.0F);
});
p_40703_.m_142346_(p_40704_, GameEvent.f_157816_, blockpos);
@@ -72,7 +_,7 @@
@@ -72,8 +_,8 @@
return InteractionResultHolder.m_19100_(itemstack);
} else {
BlockState blockstate = p_40703_.m_8055_(blockpos);
- BlockPos blockpos2 = blockstate.m_60734_() instanceof LiquidBlockContainer && this.f_40687_ == Fluids.f_76193_ ? blockpos : blockpos1;
- if (this.m_142073_(p_40704_, p_40703_, blockpos2, blockhitresult)) {
+ BlockPos blockpos2 = canBlockContainFluid(p_40703_, blockpos, blockstate) ? blockpos : blockpos1;
if (this.m_142073_(p_40704_, p_40703_, blockpos2, blockhitresult)) {
+ if (this.emptyContents(p_40704_, p_40703_, blockpos2, blockhitresult, itemstack)) {
this.m_142131_(p_40704_, p_40703_, itemstack, blockpos2);
if (p_40704_ instanceof ServerPlayer) {
CriteriaTriggers.f_10591_.m_59469_((ServerPlayer)p_40704_, blockpos2, itemstack);
@@ -98,7 +_,12 @@
public void m_142131_(@Nullable Player p_150711_, Level p_150712_, ItemStack p_150713_, BlockPos p_150714_) {
}
+ @Deprecated //Forge: use the ItemStack sensitive version
public boolean m_142073_(@Nullable Player p_150716_, Level p_150717_, BlockPos p_150718_, @Nullable BlockHitResult p_150719_) {
+ return this.emptyContents(p_150716_, p_150717_, p_150718_, p_150719_, null);
+ }
+
+ public boolean emptyContents(@Nullable Player p_150716_, Level p_150717_, BlockPos p_150718_, @Nullable BlockHitResult p_150719_, @Nullable ItemStack container) {
if (!(this.f_40687_ instanceof FlowingFluid)) {
return false;
} else {
@@ -107,8 +_,12 @@
Material material = blockstate.m_60767_();
boolean flag = blockstate.m_60722_(this.f_40687_);
boolean flag1 = blockstate.m_60795_() || flag || block instanceof LiquidBlockContainer && ((LiquidBlockContainer)block).m_6044_(p_150717_, p_150718_, blockstate, this.f_40687_);
+ java.util.Optional<net.minecraftforge.fluids.FluidStack> containedFluidStack = java.util.Optional.ofNullable(container).flatMap(net.minecraftforge.fluids.FluidUtil::getFluidContained);
if (!flag1) {
- return p_150719_ != null && this.m_142073_(p_150716_, p_150717_, p_150719_.m_82425_().m_121945_(p_150719_.m_82434_()), (BlockHitResult)null);
+ return p_150719_ != null && this.emptyContents(p_150716_, p_150717_, p_150719_.m_82425_().m_121945_(p_150719_.m_82434_()), (BlockHitResult)null, container);
+ } else if (containedFluidStack.isPresent() && this.f_40687_.getFluidType().isVaporizedOnPlacement(p_150717_, p_150718_, containedFluidStack.get())) {
+ this.f_40687_.getFluidType().onVaporize(p_150716_, p_150717_, p_150718_, containedFluidStack.get());
+ return true;
} else if (p_150717_.m_6042_().f_63857_() && this.f_40687_.m_205067_(FluidTags.f_13131_)) {
int i = p_150718_.m_123341_();
int j = p_150718_.m_123342_();
@@ -120,7 +_,7 @@
}
@@ -78,7 +107,7 @@
+ private final java.util.function.Supplier<? extends Fluid> fluidSupplier;
+ public Fluid getFluid() { return fluidSupplier.get(); }
+
+ private boolean canBlockContainFluid(Level worldIn, BlockPos posIn, BlockState blockstate)
+ protected boolean canBlockContainFluid(Level worldIn, BlockPos posIn, BlockState blockstate)
+ {
+ return blockstate.m_60734_() instanceof LiquidBlockContainer && ((LiquidBlockContainer)blockstate.m_60734_()).m_6044_(worldIn, posIn, blockstate, this.f_40687_);
}
@@ -0,0 +1,19 @@
--- a/net/minecraft/world/item/BundleItem.java
+++ b/net/minecraft/world/item/BundleItem.java
@@ -40,7 +_,7 @@
}
public boolean m_142207_(ItemStack p_150733_, Slot p_150734_, ClickAction p_150735_, Player p_150736_) {
- if (p_150735_ != ClickAction.SECONDARY) {
+ if (p_150733_.m_41613_() != 1 || p_150735_ != ClickAction.SECONDARY) {
return false;
} else {
ItemStack itemstack = p_150734_.m_7993_();
@@ -62,6 +_,7 @@
}
public boolean m_142305_(ItemStack p_150742_, ItemStack p_150743_, Slot p_150744_, ClickAction p_150745_, Player p_150746_, SlotAccess p_150747_) {
+ if (p_150742_.m_41613_() != 1) return false;
if (p_150745_ == ClickAction.SECONDARY && p_150744_.m_150651_(p_150746_)) {
if (p_150743_.m_41619_()) {
m_150780_(p_150742_).ifPresent((p_186347_) -> {
@@ -0,0 +1,14 @@
--- a/net/minecraft/world/item/DispensibleContainerItem.java
+++ b/net/minecraft/world/item/DispensibleContainerItem.java
@@ -6,9 +_,10 @@
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.BlockHitResult;
-public interface DispensibleContainerItem {
+public interface DispensibleContainerItem extends net.minecraftforge.common.extensions.IForgeDispensibleContainerItem {
default void m_142131_(@Nullable Player p_150817_, Level p_150818_, ItemStack p_150819_, BlockPos p_150820_) {
}
+ @Deprecated //Forge: use the ItemStack sensitive version
boolean m_142073_(@Nullable Player p_150821_, Level p_150822_, BlockPos p_150823_, @Nullable BlockHitResult p_150824_);
}
@@ -1,6 +1,6 @@
--- a/net/minecraft/world/level/BaseSpawner.java
+++ b/net/minecraft/world/level/BaseSpawner.java
@@ -127,11 +_,15 @@
@@ -127,10 +_,15 @@
entity.m_7678_(entity.m_20185_(), entity.m_20186_(), entity.m_20189_(), randomsource.m_188501_() * 360.0F, 0.0F);
if (entity instanceof Mob) {
Mob mob = (Mob)entity;
@@ -11,11 +11,11 @@
continue;
}
+ // Fire this early so mods can react to mobs that vanilla normally ignores.
+ if (!net.minecraftforge.event.ForgeEventFactory.doSpecialSpawn(mob, p_151312_, (float)entity.m_20185_(), (float)entity.m_20186_(), (float)entity.m_20189_(), this, MobSpawnType.SPAWNER))
if (this.f_45444_.m_186567_().m_128440_() == 1 && this.f_45444_.m_186567_().m_128425_("id", 8)) {
+ if (!net.minecraftforge.event.ForgeEventFactory.doSpecialSpawn(mob, (LevelAccessor)p_151312_, (float)entity.m_20185_(), (float)entity.m_20186_(), (float)entity.m_20189_(), this, MobSpawnType.SPAWNER))
((Mob)entity).m_6518_(p_151312_, p_151312_.m_6436_(entity.m_20183_()), MobSpawnType.SPAWNER, (SpawnGroupData)null, (CompoundTag)null);
}
}
@@ -275,4 +_,12 @@
public double m_45474_() {
return this.f_45446_;
@@ -23,8 +23,8 @@
mob.m_7678_(d0, (double)i, d1, p_47040_.f_46441_.m_188501_() * 360.0F, 0.0F);
- if (m_46991_(p_47040_, mob, d2)) {
+ int canSpawn = net.minecraftforge.common.ForgeHooks.canEntitySpawn(mob, p_47040_, d0, i, d1, null, MobSpawnType.NATURAL);
+ if (canSpawn != -1 && (canSpawn == 1 || m_46991_(p_47040_, mob, d2))) {
+ if (!net.minecraftforge.event.ForgeEventFactory.doSpecialSpawn(mob, (LevelAccessor) p_47040_, (float)d0, (float)i, (float)d1, null, MobSpawnType.NATURAL))
+ if (canSpawn == 1 || (canSpawn == 0 && m_46991_(p_47040_, mob, d2))) {
+ if (!net.minecraftforge.event.ForgeEventFactory.doSpecialSpawn(mob, p_47040_, (float)d0, (float)i, (float)d1, null, MobSpawnType.NATURAL))
spawngroupdata = mob.m_6518_(p_47040_, p_47040_.m_6436_(mob.m_20183_()), MobSpawnType.NATURAL, spawngroupdata, (CompoundTag)null);
++j;
++l1;
@@ -75,11 +75,14 @@
}
}
@@ -370,6 +_,7 @@
@@ -370,7 +_,9 @@
entity.m_7678_(d0, (double)blockpos.m_123342_(), d1, p_220454_.m_188501_() * 360.0F, 0.0F);
if (entity instanceof Mob) {
Mob mob = (Mob)entity;
+ if (net.minecraftforge.common.ForgeHooks.canEntitySpawn(mob, p_220451_, d0, blockpos.m_123342_(), d1, null, MobSpawnType.CHUNK_GENERATION) == -1) continue;
if (mob.m_5545_(p_220451_, MobSpawnType.CHUNK_GENERATION) && mob.m_6914_(p_220451_)) {
- if (mob.m_5545_(p_220451_, MobSpawnType.CHUNK_GENERATION) && mob.m_6914_(p_220451_)) {
+ int res = net.minecraftforge.common.ForgeHooks.canEntitySpawn(mob, p_220451_, d0, blockpos.m_123342_(), d1, null, MobSpawnType.CHUNK_GENERATION);
+ if (res == 1 || (res == 0 && mob.m_5545_(p_220451_, MobSpawnType.CHUNK_GENERATION) && mob.m_6914_(p_220451_))) {
+ if (!net.minecraftforge.event.ForgeEventFactory.doSpecialSpawn(mob, p_220451_, (float) d0, blockpos.m_123342_(), (float) d1, null, MobSpawnType.CHUNK_GENERATION))
spawngroupdata = mob.m_6518_(p_220451_, p_220451_.m_6436_(mob.m_20183_()), MobSpawnType.CHUNK_GENERATION, spawngroupdata, (CompoundTag)null);
p_220451_.m_47205_(mob);
flag = true;
@@ -4,8 +4,9 @@
}
public void m_214148_(ServerLevel p_221243_, RandomSource p_221244_, BlockPos p_221245_, BlockState p_221246_) {
- this.f_53597_.get().m_203334_().m_224953_(p_221243_, p_221243_.m_7726_().m_8481_(), p_221244_, p_221245_);
+ net.minecraftforge.event.level.SaplingGrowTreeEvent event = net.minecraftforge.event.ForgeEventFactory.blockGrowFeature(p_221243_, p_221244_, p_221245_, this.f_53597_.get());
+ if (event.getResult().equals(net.minecraftforge.eventbus.api.Event.Result.DENY)) return;
this.f_53597_.get().m_203334_().m_224953_(p_221243_, p_221243_.m_7726_().m_8481_(), p_221244_, p_221245_);
+ event.getFeature().m_203334_().m_224953_(p_221243_, p_221243_.m_7726_().m_8481_(), p_221244_, p_221245_);
}
}
@@ -1,6 +1,6 @@
--- a/net/minecraft/world/level/block/StemBlock.java
+++ b/net/minecraft/world/level/block/StemBlock.java
@@ -43,22 +_,24 @@
@@ -43,22 +_,23 @@
}
public void m_213898_(BlockState p_222538_, ServerLevel p_222539_, BlockPos p_222540_, RandomSource p_222541_) {
@@ -19,8 +19,7 @@
BlockPos blockpos = p_222540_.m_121945_(direction);
BlockState blockstate = p_222539_.m_8055_(blockpos.m_7495_());
- if (p_222539_.m_8055_(blockpos).m_60795_() && (blockstate.m_60713_(Blocks.f_50093_) || blockstate.m_204336_(BlockTags.f_144274_))) {
+ Block block = blockstate.m_60734_();
+ if (p_222539_.m_46859_(blockpos) && (blockstate.canSustainPlant(p_222539_, blockpos.m_7495_(), Direction.UP, this) || block == Blocks.f_50093_ || block == Blocks.f_50493_ || block == Blocks.f_50546_ || block == Blocks.f_50599_ || block == Blocks.f_50440_)) {
+ if (p_222539_.m_46859_(blockpos) && (blockstate.canSustainPlant(p_222539_, blockpos.m_7495_(), Direction.UP, this.f_57015_) || blockstate.m_60713_(Blocks.f_50093_) || blockstate.m_204336_(BlockTags.f_144274_))) {
p_222539_.m_46597_(blockpos, this.f_57015_.m_49966_());
p_222539_.m_46597_(p_222540_, this.f_57015_.m_7810_().m_49966_().m_61124_(HorizontalDirectionalBlock.f_54117_, direction));
}
@@ -0,0 +1,23 @@
--- a/net/minecraft/world/level/block/StemGrownBlock.java
+++ b/net/minecraft/world/level/block/StemGrownBlock.java
@@ -2,7 +_,7 @@
import net.minecraft.world.level.block.state.BlockBehaviour;
-public abstract class StemGrownBlock extends Block {
+public abstract class StemGrownBlock extends Block implements net.minecraftforge.common.IPlantable {
public StemGrownBlock(BlockBehaviour.Properties p_57058_) {
super(p_57058_);
}
@@ -10,4 +_,11 @@
public abstract StemBlock m_7161_();
public abstract AttachedStemBlock m_7810_();
+
+ @Override
+ public net.minecraft.world.level.block.state.BlockState getPlant(net.minecraft.world.level.BlockGetter world, net.minecraft.core.BlockPos pos) {
+ net.minecraft.world.level.block.state.BlockState state = world.m_8055_(pos);
+ if (state.m_60734_() != this) return m_49966_();
+ return state;
+ }
}
@@ -1,10 +1,12 @@
--- a/net/minecraft/world/level/levelgen/PatrolSpawner.java
+++ b/net/minecraft/world/level/levelgen/PatrolSpawner.java
@@ -104,6 +_,7 @@
@@ -104,6 +_,9 @@
}
patrollingmonster.m_6034_((double)p_224534_.m_123341_(), (double)p_224534_.m_123342_(), (double)p_224534_.m_123343_());
+ if(net.minecraftforge.common.ForgeHooks.canEntitySpawn(patrollingmonster, p_224533_, p_224534_.m_123341_(), p_224534_.m_123342_(), p_224534_.m_123343_(), null, MobSpawnType.PATROL) == -1) return false;
+ // Note: This call to canEntitySpawn is erroneous, it is only provided for backwards compatibility.
+ if (net.minecraftforge.common.ForgeHooks.canEntitySpawn(patrollingmonster, p_224533_, p_224534_.m_123341_(), p_224534_.m_123342_(), p_224534_.m_123343_(), null, MobSpawnType.PATROL) == -1) return false;
+ if (!net.minecraftforge.event.ForgeEventFactory.doSpecialSpawn(patrollingmonster, p_224533_, p_224534_.m_123341_(), p_224534_.m_123342_(), p_224534_.m_123343_(), null, MobSpawnType.PATROL))
patrollingmonster.m_6518_(p_224533_, p_224533_.m_6436_(p_224534_), MobSpawnType.PATROL, (SpawnGroupData)null, (CompoundTag)null);
p_224533_.m_47205_(patrollingmonster);
return true;
@@ -1,10 +1,12 @@
--- a/net/minecraft/world/level/levelgen/PhantomSpawner.java
+++ b/net/minecraft/world/level/levelgen/PhantomSpawner.java
@@ -60,6 +_,7 @@
@@ -60,6 +_,9 @@
for(int i1 = 0; i1 < l; ++i1) {
Phantom phantom = EntityType.f_20509_.m_20615_(p_64576_);
phantom.m_20035_(blockpos1, 0.0F, 0.0F);
+ if(net.minecraftforge.common.ForgeHooks.canEntitySpawn(phantom, p_64576_, blockpos1.m_123341_(), blockpos1.m_123342_(), blockpos1.m_123343_(), null, MobSpawnType.NATURAL) == -1) { i--; continue; }
+ // Note: This call to canEntitySpawn is erroneous, it is only provided for backwards compatibility.
+ if (net.minecraftforge.common.ForgeHooks.canEntitySpawn(phantom, p_64576_, blockpos1.m_123341_(), blockpos1.m_123342_(), blockpos1.m_123343_(), null, MobSpawnType.NATURAL) == -1) { i--; continue; }
+ if (!net.minecraftforge.event.ForgeEventFactory.doSpecialSpawn(phantom, p_64576_, blockpos1.m_123341_(), blockpos1.m_123342_(), blockpos1.m_123343_(), null, MobSpawnType.NATURAL))
spawngroupdata = phantom.m_6518_(p_64576_, difficultyinstance, MobSpawnType.NATURAL, spawngroupdata, (CompoundTag)null);
p_64576_.m_47205_(phantom);
}
@@ -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;
}
@@ -0,0 +1,10 @@
--- a/net/minecraft/world/level/levelgen/structure/structures/OceanMonumentPieces.java
+++ b/net/minecraft/world/level/levelgen/structure/structures/OceanMonumentPieces.java
@@ -1442,6 +_,7 @@
ElderGuardian elderguardian = EntityType.f_20563_.m_20615_(p_228844_.m_6018_());
elderguardian.m_5634_(elderguardian.m_21233_());
elderguardian.m_7678_((double)blockpos.m_123341_() + 0.5D, (double)blockpos.m_123342_(), (double)blockpos.m_123343_() + 0.5D, 0.0F, 0.0F);
+ if (!net.minecraftforge.event.ForgeEventFactory.doSpecialSpawn(elderguardian, p_228844_, (float)elderguardian.m_20185_(), (float)elderguardian.m_20186_(), (float)elderguardian.m_20189_(), null, MobSpawnType.STRUCTURE))
elderguardian.m_6518_(p_228844_, p_228844_.m_6436_(elderguardian.m_20183_()), MobSpawnType.STRUCTURE, (SpawnGroupData)null, (CompoundTag)null);
p_228844_.m_47205_(elderguardian);
return true;
@@ -0,0 +1,10 @@
--- a/net/minecraft/world/level/levelgen/structure/structures/WoodlandMansionPieces.java
+++ b/net/minecraft/world/level/levelgen/structure/structures/WoodlandMansionPieces.java
@@ -1052,6 +_,7 @@
for(Mob mob : list) {
mob.m_21530_();
mob.m_20035_(p_230214_, 0.0F, 0.0F);
+ if (!net.minecraftforge.event.ForgeEventFactory.doSpecialSpawn(mob, p_230215_, (float)mob.m_20185_(), (float)mob.m_20186_(), (float)mob.m_20189_(), null, MobSpawnType.STRUCTURE))
mob.m_6518_(p_230215_, p_230215_.m_6436_(mob.m_20183_()), MobSpawnType.STRUCTURE, (SpawnGroupData)null, (CompoundTag)null);
p_230215_.m_47205_(mob);
p_230215_.m_7731_(p_230214_, Blocks.f_50016_.m_49966_(), 2);
@@ -86,7 +86,7 @@
ListTag listtag = new ListTag();
listtag.add(DoubleTag.m_128500_(vec31.f_82479_));
listtag.add(DoubleTag.m_128500_(vec31.f_82480_));
@@ -391,10 +_,10 @@
@@ -391,10 +_,11 @@
compoundtag.m_128365_("Pos", listtag);
compoundtag.m_128473_("UUID");
m_74543_(p_74524_, compoundtag).ifPresent((p_205061_) -> {
@@ -97,6 +97,7 @@
p_205061_.m_7678_(vec31.f_82479_, vec31.f_82480_, vec31.f_82481_, f, p_205061_.m_146909_());
- if (p_74530_ && p_205061_ instanceof Mob) {
+ if (placementIn.m_74414_() && p_205061_ instanceof Mob) {
+ if (!net.minecraftforge.event.ForgeEventFactory.doSpecialSpawn((Mob)p_205061_, p_74524_, (float)p_205061_.m_20185_(), (float)p_205061_.m_20186_(), (float)p_205061_.m_20189_(), null, MobSpawnType.STRUCTURE))
((Mob)p_205061_).m_6518_(p_74524_, p_74524_.m_6436_(new BlockPos(vec31)), MobSpawnType.STRUCTURE, (SpawnGroupData)null, compoundtag);
}
@@ -71,13 +71,14 @@ import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.locale.Language;
import net.minecraft.network.Connection;
import net.minecraft.network.chat.ChatSender;
import net.minecraft.network.chat.ChatType;
import net.minecraft.network.chat.ChatTypeDecoration;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.FormattedText;
import net.minecraft.network.chat.MessageSigner;
import net.minecraft.network.chat.PlayerChatMessage;
import net.minecraft.network.chat.Style;
import net.minecraft.network.protocol.status.ServerStatus;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.Resource;
@@ -963,6 +964,17 @@ public class ForgeHooksClient
return MinecraftForge.EVENT_BUS.post(event) ? null : event.getMessage();
}
private static final ChatTypeDecoration SYSTEM_CHAT_TYPE_DECORATION = new ChatTypeDecoration("forge.chatType.system", List.of(ChatTypeDecoration.Parameter.CONTENT), Style.EMPTY);
private static final ChatType SYSTEM_CHAT_TYPE = new ChatType(SYSTEM_CHAT_TYPE_DECORATION, SYSTEM_CHAT_TYPE_DECORATION);
private static final ChatType.Bound SYSTEM_CHAT_TYPE_BOUND = SYSTEM_CHAT_TYPE.bind(Component.literal("System"));
@Nullable
public static Component onClientSystemChat(Component message, boolean overlay)
{
ClientChatReceivedEvent.System event = new ClientChatReceivedEvent.System(SYSTEM_CHAT_TYPE_BOUND, message, overlay);
return MinecraftForge.EVENT_BUS.post(event) ? null : event.getMessage();
}
@NotNull
public static String onClientSendMessage(String message)
{
@@ -6,6 +6,7 @@
package net.minecraftforge.client.event;
import net.minecraft.Util;
import net.minecraft.network.chat.ChatMessageContent;
import net.minecraft.network.chat.ChatType;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MessageSigner;
@@ -45,6 +46,11 @@ public class ClientChatReceivedEvent extends Event
this.messageSigner = messageSigner;
}
private ClientChatReceivedEvent(ChatType.Bound boundChatType, Component message, PlayerChatMessage playerChatMessage)
{
this(boundChatType, message, playerChatMessage, playerChatMessage.signer());
}
/**
* {@return the message that will be displayed in the chat message window, if the event is not cancelled}
*/
@@ -98,4 +104,33 @@ public class ClientChatReceivedEvent extends Event
{
return this.messageSigner.isSystem();
}
/**
* Fired when a system chat message is received on the client.
*
* <p>This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.
* If the event is cancelled, the message is not displayed in the chat message window or in the overlay.</p>
*
* <p>This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus},
* only on the {@linkplain LogicalSide#CLIENT logical client}.</p>
*/
public static class System extends ClientChatReceivedEvent
{
private final boolean overlay;
@ApiStatus.Internal
public System(ChatType.Bound boundChatType, Component message, boolean overlay)
{
super(boundChatType, message, PlayerChatMessage.system(new ChatMessageContent(message.getString(), message)));
this.overlay = overlay;
}
/**
* {@return whether the message goes to the overlay}
*/
public boolean isOverlay()
{
return this.overlay;
}
}
}
@@ -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) {}
}
@@ -499,6 +499,13 @@ public class ForgeGui extends Gui
}
}
@Override
public void clearCache()
{
super.clearCache();
this.debugOverlay.clearChunkCache();
}
protected void renderRecordOverlay(int width, int height, float partialTick, PoseStack pStack)
{
if (overlayMessageTime > 0)
@@ -37,6 +37,7 @@ import net.minecraftforge.client.model.data.ModelProperty;
import net.minecraftforge.client.model.geometry.IGeometryBakingContext;
import net.minecraftforge.client.model.geometry.IGeometryLoader;
import net.minecraftforge.client.model.geometry.IUnbakedGeometry;
import net.minecraftforge.client.model.geometry.UnbakedGeometryHelper;
import net.minecraftforge.common.util.ConcatenatedListView;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -91,7 +92,7 @@ public class CompositeModel implements IUnbakedGeometry<CompositeModel>
var rootTransform = context.getRootTransform();
if (!rootTransform.isIdentity())
modelState = new SimpleModelState(modelState.getRotation().compose(rootTransform), modelState.isUvLocked());
modelState = UnbakedGeometryHelper.composeRootTransformIntoModelState(modelState, rootTransform);
var bakedPartsBuilder = ImmutableMap.<String, BakedModel>builder();
for (var entry : children.entrySet())
@@ -26,6 +26,7 @@ import net.minecraft.util.GsonHelper;
import net.minecraftforge.client.model.geometry.IGeometryBakingContext;
import net.minecraftforge.client.model.geometry.IGeometryLoader;
import net.minecraftforge.client.model.geometry.SimpleUnbakedGeometry;
import net.minecraftforge.client.model.geometry.UnbakedGeometryHelper;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -65,8 +66,10 @@ public class ElementsModel extends SimpleUnbakedGeometry<ElementsModel>
// If there is a root transform, undo the ModelState transform, apply it, then re-apply the ModelState transform.
// This is necessary because of things like UV locking, which should only respond to the ModelState, and as such
// that is the only transform that should be applied during face bake.
var postTransform = context.getRootTransform().isIdentity() ? QuadTransformers.empty() :
QuadTransformers.applying(modelState.getRotation().compose(context.getRootTransform()).compose(modelState.getRotation().inverse()));
var postTransform = QuadTransformers.empty();
var rootTransform = context.getRootTransform();
if (!rootTransform.isIdentity())
postTransform = UnbakedGeometryHelper.applyRootTransform(modelState, rootTransform);
for (BlockElement element : elements)
{
@@ -86,7 +86,7 @@ public class ItemLayerModel implements IUnbakedGeometry<ItemLayerModel>
);
var rootTransform = context.getRootTransform();
if (!rootTransform.isIdentity())
modelState = new SimpleModelState(modelState.getRotation().compose(rootTransform), modelState.isUvLocked());
modelState = UnbakedGeometryHelper.composeRootTransformIntoModelState(modelState, rootTransform);
var normalRenderTypes = new RenderTypeGroup(RenderType.translucent(), ForgeRenderTypes.ITEM_UNSORTED_TRANSLUCENT.get());
CompositeModel.Baked.Builder builder = CompositeModel.Baked.builder(context, particle, overrides, context.getTransforms());
@@ -42,6 +42,7 @@ public class BlockGeometryBakingContext implements IGeometryBakingContext
private Transformation rootTransform;
@Nullable
private ResourceLocation renderTypeHint;
private boolean gui3d = true;
@ApiStatus.Internal
public BlockGeometryBakingContext(BlockModel owner)
@@ -94,7 +95,7 @@ public class BlockGeometryBakingContext implements IGeometryBakingContext
@Override
public boolean isGui3d()
{
return true;
return gui3d;
}
@Override
@@ -142,12 +143,18 @@ public class BlockGeometryBakingContext implements IGeometryBakingContext
this.renderTypeHint = renderTypeHint;
}
public void setGui3d(boolean gui3d)
{
this.gui3d = gui3d;
}
public void copyFrom(BlockGeometryBakingContext other)
{
this.customGeometry = other.customGeometry;
this.rootTransform = other.rootTransform;
this.visibilityData.copyFrom(other.visibilityData);
this.renderTypeHint = other.renderTypeHint;
this.gui3d = other.gui3d;
}
public Collection<Material> getTextureDependencies(Function<ResourceLocation, UnbakedModel> modelGetter, Set<Pair<String, String>> missingTextureErrors)
@@ -27,6 +27,8 @@ import net.minecraft.core.Direction;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.client.model.ElementsModel;
import net.minecraftforge.client.model.IModelBuilder;
import net.minecraftforge.client.model.IQuadTransformer;
import net.minecraftforge.client.model.QuadTransformers;
import net.minecraftforge.client.model.SimpleModelState;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
@@ -244,4 +246,32 @@ public class UnbakedGeometryHelper
{
return FACE_BAKERY.bakeQuad(element.from, element.to, face, sprite, direction, state, element.rotation, element.shade, modelLocation);
}
/**
* Create an {@link IQuadTransformer} to apply a {@link Transformation} that undoes the {@link ModelState}
* transform (blockstate transform), applies the given root transform and then re-applies the
* blockstate transform.
*
* @return an {@code IQuadTransformer} that applies the root transform to a baked quad that already has the
* transformation of the given {@code ModelState} applied to it
*/
public static IQuadTransformer applyRootTransform(ModelState modelState, Transformation rootTransform)
{
// Move the origin of the ModelState transform and its inverse from the negative corner to the block center
// to replicate the way the ModelState transform is applied in the FaceBakery by moving the vertices such that
// the negative corner acts as the block center
Transformation transform = modelState.getRotation().applyOrigin(new Vector3f(.5F, .5F, .5F));
return QuadTransformers.applying(transform.compose(rootTransform).compose(transform.inverse()));
}
/**
* {@return a {@link ModelState} that combines the existing model state and the {@linkplain Transformation root transform}}
*/
public static ModelState composeRootTransformIntoModelState(ModelState modelState, Transformation rootTransform)
{
// Move the origin of the root transform as if the negative corner were the block center to match the way the
// ModelState transform is applied in the FaceBakery by moving the vertices to be centered on that corner
rootTransform = rootTransform.applyOrigin(new Vector3f(-.5F, -.5F, -.5F));
return new SimpleModelState(modelState.getRotation().compose(rootTransform), modelState.isUvLocked());
}
}
@@ -10,6 +10,7 @@ import net.minecraftforge.client.ClientCommandHandler;
import net.minecraftforge.eventbus.api.BusBuilder;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.loading.FMLEnvironment;
import net.minecraftforge.network.DualStackUtils;
import net.minecraftforge.versions.forge.ForgeVersion;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -42,6 +43,7 @@ public class MinecraftForge
UsernameCache.load();
TierSortingRegistry.init();
if (FMLEnvironment.dist == Dist.CLIENT) ClientCommandHandler.init();
DualStackUtils.initialise();
}
/*
@@ -0,0 +1,37 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.common.extensions;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.DispensibleContainerItem;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.BlockHitResult;
import org.jetbrains.annotations.Nullable;
public interface IForgeDispensibleContainerItem
{
private DispensibleContainerItem self()
{
return (DispensibleContainerItem)this;
}
/**
* Empties the contents of the container and returns whether it was successful.
*
* @param player Player who empties the container. May be null for blocks like dispensers.
* @param level Level to place the content in
* @param pos The position in the level to empty the content
* @param hitResult Hit result of the interaction. May be null for blocks like dispensers.
* @param container ItemStack of the container. May be null for backwards compatibility.
* @return true if emptying the contents of the container was successful, false otherwise
*/
default boolean emptyContents(@Nullable Player player, Level level, BlockPos pos, @Nullable BlockHitResult hitResult, @Nullable ItemStack container)
{
return self().emptyContents(player, level, pos, hitResult);
}
}
@@ -201,16 +201,9 @@ public final class TransformationHelper
elements.remove("origin");
}
if (!elements.isEmpty()) throw new JsonParseException("TRSR: can either have single 'matrix' key, or a combination of 'translation', 'rotation' OR 'left_rotation', 'scale', 'post-rotation' (legacy) OR 'right_rotation', 'origin'. Found: " + String.join(", ", elements));
Transformation matrix = new Transformation(translation, leftRot, scale, rightRot);
// Use a different origin if needed.
if (!TransformOrigin.CENTER.getVector().equals(origin))
{
Vector3f originFromCenter = origin.copy();
originFromCenter.sub(TransformOrigin.CENTER.getVector());
matrix = matrix.applyOrigin(originFromCenter);
}
return matrix;
Transformation matrix = new Transformation(translation, leftRot, scale, rightRot);
return matrix.applyOrigin(origin.copy());
}
private static Vector3f parseOrigin(JsonObject obj) {
@@ -28,6 +28,7 @@ import net.minecraft.world.Container;
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;
@@ -121,6 +122,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;
@@ -185,7 +187,7 @@ public class ForgeEventFactory
MinecraftForge.EVENT_BUS.post(new PlayerDestroyItemEvent(player, stack, hand));
}
public static Result canEntitySpawn(Mob entity, LevelAccessor level, double x, double y, double z, BaseSpawner spawner, MobSpawnType spawnReason)
public static Result canEntitySpawn(Mob entity, LevelAccessor level, double x, double y, double z, @Nullable BaseSpawner spawner, MobSpawnType spawnReason)
{
if (entity == null)
return Result.DEFAULT;
@@ -194,7 +196,7 @@ public class ForgeEventFactory
return event.getResult();
}
public static boolean doSpecialSpawn(Mob entity, LevelAccessor level, float x, float y, float z, BaseSpawner spawner, MobSpawnType spawnReason)
public static boolean doSpecialSpawn(Mob entity, LevelAccessor level, float x, float y, float z, @Nullable BaseSpawner spawner, MobSpawnType spawnReason)
{
return MinecraftForge.EVENT_BUS.post(new LivingSpawnEvent.SpecialSpawn(entity, level, x, y, z, spawner, spawnReason));
}
@@ -628,6 +630,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)
@@ -812,12 +821,12 @@ public class ForgeEventFactory
public static void onPreLevelTick(Level level, BooleanSupplier haveTime)
{
MinecraftForge.EVENT_BUS.post(new TickEvent.LevelTickEvent(LogicalSide.SERVER, TickEvent.Phase.START, level, haveTime));
MinecraftForge.EVENT_BUS.post(new TickEvent.LevelTickEvent(level.isClientSide ? LogicalSide.CLIENT : LogicalSide.SERVER, TickEvent.Phase.START, level, haveTime));
}
public static void onPostLevelTick(Level level, BooleanSupplier haveTime)
{
MinecraftForge.EVENT_BUS.post(new TickEvent.LevelTickEvent(LogicalSide.SERVER, TickEvent.Phase.END, level, haveTime));
MinecraftForge.EVENT_BUS.post(new TickEvent.LevelTickEvent(level.isClientSide ? LogicalSide.CLIENT : LogicalSide.SERVER, TickEvent.Phase.END, level, haveTime));
}
public static void onPreClientTick()
@@ -6,6 +6,7 @@
package net.minecraftforge.event.entity;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.LevelChunk;
@@ -26,6 +27,7 @@ import net.minecraftforge.fml.LogicalSide;
* <p>
* This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}
* on both logical sides.
* @apiNote If the spawned entity is a mob, and {@linkplain Mob#finalizeSpawn the spawn was finalized}, the spawn type is available via {@link Mob#getSpawnType()}
**/
@Cancelable
public class EntityJoinLevelEvent extends EntityEvent
@@ -5,23 +5,24 @@
package net.minecraftforge.event.entity.living;
import org.jetbrains.annotations.Nullable;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.MobSpawnType;
import net.minecraft.world.level.BaseSpawner;
import net.minecraft.world.level.LevelAccessor;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.entity.EntityJoinLevelEvent;
import net.minecraftforge.eventbus.api.Cancelable;
import net.minecraftforge.fml.LogicalSide;
import org.jetbrains.annotations.Nullable;
/**
* This event is fired whenever a {@link Mob} should do something spawn-related.
* <p>
* This event is not {@linkplain Cancelable cancellable} and does not {@linkplain HasResult have a result}.
* <p>
* This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}
* only on the {@linkplain LogicalSide#SERVER logical server}.
* Base class for mob spawn events.
* Will not be fired directly.
* @see CheckSpawn
* @see SpecialSpawn
* @see AllowDespawn
*/
public class LivingSpawnEvent extends LivingEvent
{
@@ -83,7 +84,7 @@ public class LivingSpawnEvent extends LivingEvent
}
/**
* This event is fired before a {@link Mob} spawns.
* This event is fired when {@link Mob#checkSpawnRules} would be called.
* <p>
* This event is not {@linkplain Cancelable cancellable}, but does {@linkplain HasResult have a result}.
* {@linkplain Result#DEFAULT DEFAULT} indicates that default spawn rules should be used.
@@ -125,13 +126,14 @@ public class LivingSpawnEvent extends LivingEvent
}
/**
* This event is fired whenever a {@link Mob} is set to be spawned, to allow for mod-specific initializers.
* This event is fired whenever {@link Mob#finalizeSpawn} would be called.
* <p>
* This event is {@linkplain Cancelable cancellable} and does not {@linkplain HasResult have a result}.
* If the event is canceled, the mob will not spawn.
* If the event is canceled, then {@link Mob#finalizeSpawn} will not be called.<br>
* The mob will still be spawned. Preventing the spawn requires usage of {@link EntityJoinLevelEvent}.
* <p>
* This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus},
* only on the {@linkplain LogicalSide#SERVER logical server}.
* and only on the {@linkplain LogicalSide#SERVER logical server}.
*/
@Cancelable
public static class SpecialSpawn extends LivingSpawnEvent
@@ -0,0 +1,79 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.event.level;
import net.minecraft.core.BlockPos;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.LevelSimulatedReader;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.feature.treedecorators.TreeDecorator;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.eventbus.api.Cancelable;
import net.minecraftforge.eventbus.api.Event;
import org.jetbrains.annotations.ApiStatus;
/**
* This event is fired when {@link net.minecraft.world.level.levelgen.feature.treedecorators.AlterGroundDecorator#placeBlockAt(TreeDecorator.Context, BlockPos)}
* attempts to alter a ground block when generating a feature. An example of this would be large spruce trees converting grass blocks into podzol.
* <p>
* This event is not {@linkplain Cancelable cancellable}.
* <p>
* This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}
* only on the {@linkplain net.minecraftforge.fml.LogicalSide#SERVER logical server}.
*/
public class AlterGroundEvent extends Event {
private final LevelSimulatedReader level;
private final RandomSource random;
private final BlockPos pos;
private final BlockState originalAltered;
private BlockState newAltered;
@ApiStatus.Internal
public AlterGroundEvent(LevelSimulatedReader level, RandomSource random, BlockPos pos, BlockState altered) {
super();
this.level = level;
this.random = random;
this.pos = pos;
this.originalAltered = altered;
this.newAltered = altered;
}
public LevelSimulatedReader getLevel() {
return this.level;
}
public RandomSource getRandom() {
return this.random;
}
/**
* {@return the position of the block that will be altered}
*/
public BlockPos getPos() {
return this.pos;
}
/**
* {@return the original block state that would be placed by the ground decorator}
*/
public BlockState getOriginalAlteredState() {
return this.originalAltered;
}
/**
* {@return the new block state to be placed by the ground decorator}
*/
public BlockState getNewAlteredState() {
return this.newAltered;
}
/**
* @param newAltered the new block state to be placed by the ground decorator
*/
public void setNewAlteredState(BlockState newAltered) {
this.newAltered = newAltered;
}
}
@@ -143,7 +143,9 @@ public class FluidUtil
}
else
{
containerFluidHandler.fill(simulatedTransfer, IFluidHandler.FluidAction.SIMULATE);
// We are acting on a COPY of the stack, so performing changes on the source is acceptable even if we are simulating.
// We need to perform the change otherwise the call to getContainer() will be incorrect.
containerFluidHandler.fill(simulatedTransfer, IFluidHandler.FluidAction.EXECUTE);
}
ItemStack resultContainer = containerFluidHandler.getContainer();
@@ -5,12 +5,16 @@
package net.minecraftforge.network;
import com.mojang.logging.LogUtils;
import net.minecraft.client.multiplayer.resolver.ResolvedServerAddress;
import net.minecraft.client.multiplayer.resolver.ServerAddress;
import net.minecraft.client.multiplayer.resolver.ServerNameResolver;
import net.minecraft.util.HttpUtil;
import org.jetbrains.annotations.ApiStatus;
import org.slf4j.Logger;
import javax.annotation.Nullable;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
@@ -19,6 +23,19 @@ import java.util.Optional;
public class DualStackUtils
{
private static final String INITIAL_PREFER_IPv4_STACK = System.getProperty("java.net.preferIPv4Stack") == null ? "false" : System.getProperty("java.net.preferIPv4Stack");
private static final String INITIAL_PREFER_IPv6_ADDRESSES = System.getProperty("java.net.preferIPv6Addresses") == null ? "false" : System.getProperty("java.net.preferIPv6Addresses");
private static final Logger LOGGER = LogUtils.getLogger();
/**
* Called by {@link net.minecraftforge.common.MinecraftForge} to load this class so that the initial network
* property constants are set before any of the other methods in this class are called. This is so we can
* distinguish what Java's read once on JVM start vs what we've set for Netty.
*/
@ApiStatus.Internal
public static void initialise() {}
/**
* Resolve the address and see if Java and the OS return an IPv6 or IPv4 one, then let Netty know
* accordingly (it doesn't understand the {@code java.net.preferIPv6Addresses=system} property).
@@ -45,14 +62,49 @@ public class DualStackUtils
*/
public static boolean checkIPv6(final InetAddress inetAddress)
{
if (inetAddress instanceof Inet6Address)
// only log debug messages if we're not in the server pinger thread, as otherwise it's unclear which IP
// corresponds to which server as soon as you have more than one server in the multiplayer server list
final String currentThreadName = Thread.currentThread().getName();
final boolean shouldLogDebug = !currentThreadName.contains("Server Pinger #");
if (inetAddress instanceof Inet6Address addr)
{
if (shouldLogDebug)
LOGGER.debug("Detected IPv6 address: \"" + addr.getHostAddress() + "\"");
System.setProperty("java.net.preferIPv4Stack", "false");
System.setProperty("java.net.preferIPv6Addresses", "true");
return true;
}
else if (inetAddress instanceof Inet4Address addr)
{
if (shouldLogDebug)
LOGGER.debug("Detected IPv4 address: \"" + addr.getHostAddress() + "\"");
System.setProperty("java.net.preferIPv4Stack", "true");
System.setProperty("java.net.preferIPv6Addresses", "false");
return false;
}
else
{
if (shouldLogDebug) {
final String addr = inetAddress == null ? "null" : "\"" + inetAddress.getHostAddress() + "\"";
LOGGER.debug("Unable to determine IP version of address: " + addr);
}
if (INITIAL_PREFER_IPv4_STACK.equalsIgnoreCase("false") && INITIAL_PREFER_IPv6_ADDRESSES.equalsIgnoreCase("true"))
{
if (shouldLogDebug)
LOGGER.debug("Assuming IPv6 as Java was explicitly told to prefer it...");
System.setProperty("java.net.preferIPv4Stack", "false");
System.setProperty("java.net.preferIPv6Addresses", "true");
return true;
}
if (shouldLogDebug)
LOGGER.debug("Assuming IPv4...");
System.setProperty("java.net.preferIPv4Stack", "true");
System.setProperty("java.net.preferIPv6Addresses", "false");
return false;
@@ -81,8 +133,21 @@ public class DualStackUtils
}
}
/**
* Used for the "Open to LAN" feature.
* @return The multicast group to use for LAN discovery - IPv6 if available, IPv4 otherwise.
*/
public static String getMulticastGroup() {
if (checkIPv6(getLocalAddress())) return "FF75:230::60";
else return "224.0.2.60";
}
/**
* Logs the initial values of the {@code java.net.preferIPv4Stack} and {@code java.net.preferIPv6Addresses} system
* properties that Java has read on JVM start. Useful for debugging hostname lookup failures.
*/
public static void logInitialPreferences() {
LOGGER.debug("Initial IPv4 stack preference: " + INITIAL_PREFER_IPv4_STACK);
LOGGER.debug("Initial IPv6 addresses preference: " + INITIAL_PREFER_IPv6_ADDRESSES);
}
}
@@ -108,7 +108,7 @@ public class ResourceCacheManager
*/
public static boolean shouldUseCache()
{
return ResourceManagerBootCacheConfigurationHandler.getInstance().getConfigValue("cachePackAccess", true);
return ResourceManagerBootCacheConfigurationHandler.getInstance().getConfigValue("cacheResources", true);
}
/**
@@ -217,6 +217,8 @@
"fluid_type.minecraft.milk": "Milk",
"fluid_type.minecraft.flowing_milk": "Milk",
"forge.chatType.system": "{0}",
"forge.experimentalsettings.tooltip": "This world uses experimental settings, which could stop working at any time.",
"forge.selectWorld.backupWarning.experimental.additional" : "This message will not show again for this world."
}
+1
View File
@@ -65,6 +65,7 @@ net/minecraft/world/entity/player/Player.getDigSpeed(Lnet/minecraft/world/level/
net/minecraft/world/entity/projectile/ThrownEnderpearl.changeDimension(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraftforge/common/util/ITeleporter;)Lnet/minecraft/world/entity/Entity;=|p_37506_,teleporter
net/minecraft/world/food/FoodData.eat(Lnet/minecraft/world/item/Item;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/entity/LivingEntity;)V=|p_38713_,p_38714_,entity
net/minecraft/world/item/BoneMealItem.applyBonemeal(Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/entity/player/Player;)Z=|p_40628_,p_40629_,p_40630_,player
net/minecraft/world/item/BucketItem.emptyContents(Lnet/minecraft/world/entity/player/Player;Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/phys/BlockHitResult;Lnet/minecraft/world/item/ItemStack;)Z=|p_150716_,p_150717_,p_150718_,p_150719_,container
net/minecraft/world/item/DyeableHorseArmorItem.<init>(ILnet/minecraft/resources/ResourceLocation;Lnet/minecraft/world/item/Item$Properties;)V=|p_41110_,p_41111_,p_41112_
net/minecraft/world/item/HorseArmorItem.<init>(ILnet/minecraft/resources/ResourceLocation;Lnet/minecraft/world/item/Item$Properties;)V=|p_41364_,p_41365_,p_41366_
net/minecraft/world/item/ItemStack.<init>(Lnet/minecraft/world/level/ItemLike;ILnet/minecraft/nbt/CompoundTag;)V=|p_41604_,p_41605_,p_41606_
@@ -0,0 +1,27 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.debug;
import net.minecraft.world.level.block.Blocks;
import net.minecraftforge.event.level.AlterGroundEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
@Mod("alter_ground_event_test")
@Mod.EventBusSubscriber
public class AlterGroundEventTest {
public static final boolean ENABLE = true;
@SubscribeEvent
public static void onAlterGround(AlterGroundEvent event)
{
if (ENABLE) {
if (event.getOriginalAlteredState().is(Blocks.PODZOL)) {
event.setNewAlteredState(Blocks.REDSTONE_BLOCK.defaultBlockState());
}
}
}
}
@@ -38,6 +38,7 @@ public class FluidUtilTest
private static void runTests(FMLCommonSetupEvent commonSetupEvent)
{
test_tryEmptyContainer();
test_tryFillContainer();
test_tryEmptyContainerAndStow_stackable();
LogManager.getLogger().info("FluidUtilTest ok!");
@@ -70,6 +71,35 @@ public class FluidUtilTest
checkItemStack(sourceStack, Items.WATER_BUCKET, 2); // Apparently the stack is not supposed to be modified
}
/**
* Ensures that tryFillContainer doesn't change the target fluid handler when simulating.
* Ant that the result of the simulated transfver is valid.
* Regression test for the root cause of <a href="https://github.com/MinecraftForge/MinecraftForge/issues/6796">issue #6796</a>.
*/
private static void test_tryFillContainer()
{
var targetStack = new ItemStack(Items.BUCKET, 2);
var sourceTank = new FluidTank(10000);
sourceTank.setFluid(new FluidStack(Fluids.WATER, 5000));
// Simulate is not supposed to modify anything
var simulateResult = FluidUtil.tryFillContainer(targetStack, sourceTank, 1000, null, false);
if (!simulateResult.isSuccess())
throw new AssertionError("Failed to transfer.");
checkItemStack(simulateResult.getResult(), Items.WATER_BUCKET, 1);
// Tank and stack shouldn't be modified
checkItemStack(targetStack, Items.BUCKET, 2);
checkFluidStack(sourceTank.getFluid(), Fluids.WATER, 5000);
// Execute should modify
var executeResult = FluidUtil.tryFillContainer(targetStack, sourceTank, 1000, null, true);
if (!executeResult.isSuccess())
throw new AssertionError("Failed to transfer.");
checkItemStack(executeResult.getResult(), Items.WATER_BUCKET, 1);
checkFluidStack(sourceTank.getFluid(), Fluids.WATER, 4000);
checkItemStack(targetStack, Items.BUCKET, 2);
}
/**
* Ensures that tryEmptyContainerAndStow doesn't duplicate fluids in the target when the container is stackable.
* Regression test for <a href="https://github.com/MinecraftForge/MinecraftForge/issues/6796">issue #6796</a>.
+2 -1
View File
@@ -270,6 +270,7 @@ modId="item_stacked_on_other_test"
modId="ambient_occlusion_elements_test"
[[mods]]
modId="grindstone_event_test"
[[mods]]
modId="alter_ground_event_test"
# ADD ABOVE THIS LINE