Compare commits

..
23 Commits
Author SHA1 Message Date
LexManos 949984268d Bump version for RB. 2020-11-20 12:53:44 -08:00
Take Weiland 114acfca3b Fix food bar not rendering when non-living entities are mounted (#7446) 2020-11-20 10:24:43 -08:00
Alex O'Neill 56e538e8a9 Fix MC-194811 - Removing structures causes chunk save errors. 2020-11-20 10:23:50 -08:00
Take Weiland fa46f3dd49 Fix concurrency issue in StartupMessageManager (#7483) 2020-11-20 10:17:00 -08:00
Alex O'Neill 6ec5a8f2c1 Fix forge registry types that have private constructors (BlockStateProviderType, BlockPlacerType, FoliagePlacerType, TreeDecoratorType) (#7482) 2020-11-20 10:11:15 -08:00
cpw 49b596dda3 Fix problem where the absence of forge and MC in later loading triggered a weird crash.
Signed-off-by: cpw <[email protected]>
2020-11-15 11:08:34 -05:00
cpw 0c5ced1bbf Fix NPE problem when modid is mismatched.
Signed-off-by: cpw <[email protected]>
2020-11-13 20:41:20 -05:00
cpw 4a09a2420d Return the processed modlist data to the upstream system, not the raw unprocessed data. Should resolve the problem
that mixin complains about missing info when it's in a "crashed" situation.

Signed-off-by: cpw <[email protected]>
2020-11-13 19:12:43 -05:00
Cyborgmas 0ff8a596fc Fix dims on servers not loading the first run (#7445) 2020-11-11 01:09:35 -08:00
Take Weiland bca20ace4e Allow for custom argument types by filtering them on vanilla connections (#7463) 2020-11-10 12:24:25 -08:00
Brennan Ward f3b53001c9 Add Player context to AnvilUpdateEvent (#7442) 2020-11-10 12:05:47 -08:00
Jonathan Coates 15bac0eeaa Don't overwrite PlayerAdvancement's player with a fake one (#7454)
If a FakePlayer is constructed with the same UUID/GameProfile as a
currently active player, the player object within PlayerAdvancement is
set to the fake player.

As fake players cannot receive advancements (see grantCriterion), this
prevents the actual player from receiving any advancements until they
change dimension/relog.
2020-11-10 11:55:42 -08:00
Curle 1782973a29 Add BannerBlock.forColor to SAS to fix banner.toItem() on servers. 2020-11-10 11:38:20 -08:00
Boy132 9a4a501a95 Call Harvest check event even if the block doesn't require any tool (#7414) 2020-11-10 11:36:32 -08:00
LexManos 9bbfbd5479 Use linked collections to stabilize order when adding new registry entries. 2020-11-10 11:24:57 -08:00
Dennis C 8c68731838 Render local player when the renderViewEntity is not the local player (#7216) 2020-11-10 11:13:49 -08:00
cpw 0d7f507f4e Some help in ExtensionPoint regarding DISPLAYTEST. Let's improve those tick rates!
Signed-off-by: cpw <[email protected]>
2020-11-07 23:11:45 -05:00
cpw f78b943bdf Handle erroring during early mod construction phases, and actually report that into the error UI
by doing armslength exception handling and propagation.

Signed-off-by: cpw <[email protected]>
2020-11-07 22:30:19 -05:00
cpw 160f3f88f9 Support backwards loading 1.16.3 mods in 1.16.4, because we are able to do that. Tweak loading a bit to be smarter about dependency errors of various kinds.
Signed-off-by: cpw <[email protected]>
2020-11-07 20:48:02 -05:00
David Quintana 45e38859ed Add FluidStack codec, and a test mod that verifies its behaviour matches the existing write/read logic.
Add missing license headers.
2020-11-07 21:10:18 +01:00
cpw 38a5400a8c Update event bus version (should be 3.0.5)
Tweak MDK to automatically populate recommended values for things like forge version, loader version and minecraft version.

Signed-off-by: cpw <[email protected]>
2020-11-06 21:11:26 -05:00
diesieben07 acd18455c2 Workaround for modded attributes on vanilla entities logging warnings on vanilla clients
Switch to a handler-based approach per packet class, simplify patch, add some docs

Add license header and docs

Switch to a network handler based approach

Switch to a network handler based approach

revert build gradle change

Simplify Packet patch

Add license header to IForgePacket

Revert ForgeHooks changes

Less hacky and more generic way to filter packets for vanilla connections

_Actually_ Order SAS.
It's early

Order SAS

simplify vanilla connection check

Remove unneeded import change
2020-11-03 18:47:04 -05:00
cpw 5a7facc20f Fix early sorting bug that meant the file deduping was causing an error, to, well, not cause it, so we can get to an error screen.
Signed-off-by: cpw <[email protected]>
2020-11-02 14:57:23 -05:00
44 changed files with 978 additions and 122 deletions

No files matched your search

+4 -2
View File
@@ -197,7 +197,7 @@ project(':forge') {
}
ext {
SPEC_VERSION = '35.0' // This is overwritten by git tag, but here so dev time doesnt explode
SPEC_VERSION = '35.1' // This is overwritten by git tag, but here so dev time doesnt explode
// The new versioning sceme is <MCVersion>-<ForgeMC>.<RB>.<CommitsSinceRB>
// ForgeMC is a unique identifier for every MC version we have supported.
// Essentially, the same as the old, except dropping the first number, and the builds are no longer unique.
@@ -879,7 +879,9 @@ project(':forge') {
FORGE_NAME: project.name,
MC_VERSION: MC_VERSION,
MAPPING_CHANNEL: MAPPING_CHANNEL,
MAPPING_VERSION: MAPPING_VERSION
MAPPING_VERSION: MAPPING_VERSION,
FORGE_SPEC_VERSION: SPEC_VERSION.split("\\.")[0],
MC_NEXT_VERSION: "1."+((MC_VERSION.split("\\.")[1] as int)+1)
])
rename 'gitignore\\.txt', '.gitignore'
rename 'gitattributes\\.txt', '.gitattributes'
+6 -3
View File
@@ -6,7 +6,7 @@
# The name of the mod loader type to load - for regular FML @Mod mods it should be javafml
modLoader="javafml" #mandatory
# A version range to match for said mod loader - for regular FML @Mod it will be the forge version
loaderVersion="[34,)" #mandatory This is typically bumped every Minecraft version by Forge. See our download page for lists of versions.
loaderVersion="[@FORGE_SPEC_VERSION@,)" #mandatory This is typically bumped every Minecraft version by Forge. See our download page for lists of versions.
# The license for you mod. This is mandatory metadata and allows for easier comprehension of your redistributive properties.
# Review your options at https://choosealicense.com/. All rights reserved is the default copyright stance, and is thus the default here.
license="All rights reserved"
@@ -17,6 +17,8 @@ issueTrackerURL="http://my.issue.tracker/" #optional
# The modid of the mod
modId="examplemod" #mandatory
# The version number of the mod - there's a few well known ${} variables useable here or just hardcode it
# ${file.jarVersion} will substitute the value of the Implementation-Version as read from the mod's JAR file metadata
# see the associated build.gradle script for how to populate this completely automatically during a build
version="${file.jarVersion}" #mandatory
# A display name for the mod
displayName="Example Mod" #mandatory
@@ -45,7 +47,7 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed mollis lacinia magn
# Does this dependency have to exist - if not, ordering below must be specified
mandatory=true #mandatory
# The version range of the dependency
versionRange="[34,)" #mandatory
versionRange="[@FORGE_SPEC_VERSION@,)" #mandatory
# An ordering relationship for the dependency - BEFORE or AFTER required if the relationship is not mandatory
ordering="NONE"
# Side this dependency is applied on - BOTH, CLIENT or SERVER
@@ -54,6 +56,7 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed mollis lacinia magn
[[dependencies.examplemod]]
modId="minecraft"
mandatory=true
versionRange="[1.16.3]"
# This version range declares a minimum of the current minecraft version up to but not including the next major version
versionRange="[@MC_VERSION@,@MC_NEXT_VERSION@)"
ordering="NONE"
side="BOTH"
@@ -47,6 +47,15 @@
this.func_228441_a_(RenderType.func_228643_e_(), p_228426_1_, d0, d1, d2);
if (this.field_72769_h.func_239132_a_().func_239217_c_()) {
RenderHelper.func_237533_a_(p_228426_1_.func_227866_c_().func_227870_a_());
@@ -972,7 +979,7 @@
IRenderTypeBuffer.Impl irendertypebuffer$impl = this.field_228415_m_.func_228487_b_();
for(Entity entity : this.field_72769_h.func_217416_b()) {
- if ((this.field_175010_j.func_229086_a_(entity, clippinghelper, d0, d1, d2) || entity.func_184215_y(this.field_72777_q.field_71439_g)) && (entity != p_228426_6_.func_216773_g() || p_228426_6_.func_216770_i() || p_228426_6_.func_216773_g() instanceof LivingEntity && ((LivingEntity)p_228426_6_.func_216773_g()).func_70608_bn()) && (!(entity instanceof ClientPlayerEntity) || p_228426_6_.func_216773_g() == entity)) {
+ if ((this.field_175010_j.func_229086_a_(entity, clippinghelper, d0, d1, d2) || entity.func_184215_y(this.field_72777_q.field_71439_g)) && (entity != p_228426_6_.func_216773_g() || p_228426_6_.func_216770_i() || p_228426_6_.func_216773_g() instanceof LivingEntity && ((LivingEntity)p_228426_6_.func_216773_g()).func_70608_bn()) && (!(entity instanceof ClientPlayerEntity) || p_228426_6_.func_216773_g() == entity || (entity == field_72777_q.field_71439_g && !field_72777_q.field_71439_g.func_175149_v()))) { //FORGE: render local player entity when it is not the renderViewEntity
++this.field_72749_I;
if (entity.field_70173_aa == 0) {
entity.field_70142_S = entity.func_226277_ct_();
@@ -1010,6 +1017,7 @@
List<TileEntity> list = worldrenderer$localrenderinformationcontainer.field_178036_a.func_178571_g().func_178485_b();
if (!list.isEmpty()) {
@@ -0,0 +1,11 @@
--- a/net/minecraft/command/arguments/ArgumentTypes.java
+++ b/net/minecraft/command/arguments/ArgumentTypes.java
@@ -220,4 +220,8 @@
this.field_197481_c = p_i48088_3_;
}
}
+ @javax.annotation.Nullable public static ResourceLocation getId(ArgumentType<?> type) {
+ Entry<?> entry = func_201040_a(type);
+ return entry == null ? null : entry.field_197481_c;
+ }
}
@@ -26,7 +26,7 @@
+
if (!itemstack2.func_190926_b()) {
- boolean flag = itemstack2.func_77973_b() == Items.field_151134_bR && !EnchantedBookItem.func_92110_g(itemstack2).isEmpty();
+ if (!net.minecraftforge.common.ForgeHooks.onAnvilChange(this, itemstack, itemstack2, field_234642_c_, field_82857_m, j)) return;
+ if (!net.minecraftforge.common.ForgeHooks.onAnvilChange(this, itemstack, itemstack2, field_234642_c_, field_82857_m, j, this.field_234645_f_)) return;
+ flag = itemstack2.func_77973_b() == Items.field_151134_bR && !EnchantedBookItem.func_92110_g(itemstack2).isEmpty();
if (itemstack1.func_77984_f() && itemstack1.func_77973_b().func_82789_a(itemstack, itemstack2)) {
int l2 = Math.min(itemstack1.func_77952_i(), itemstack1.func_77958_k() / 4);
@@ -1,12 +0,0 @@
--- a/net/minecraft/network/play/server/SCommandListPacket.java
+++ b/net/minecraft/network/play/server/SCommandListPacket.java
@@ -119,6 +119,9 @@
String s = p_197695_0_.func_150789_c(32767);
ArgumentType<?> argumenttype = ArgumentTypes.func_197486_a(p_197695_0_);
if (argumenttype == null) {
+ if ((i & 16) != 0) { // FORGE: Flush unused suggestion data
+ p_197695_0_.func_192575_l();
+ }
return null;
} else {
RequiredArgumentBuilder<ISuggestionProvider, ?> requiredargumentbuilder = RequiredArgumentBuilder.argument(s, argumenttype);
@@ -55,7 +55,16 @@
SaveFormat saveformat = SaveFormat.func_237269_a_(file1.toPath());
SaveFormat.LevelSave saveformat$levelsave = saveformat.func_237274_c_(s);
MinecraftServer.func_240777_a_(saveformat$levelsave);
@@ -169,6 +176,7 @@
@@ -142,6 +149,8 @@
dimensiongeneratorsettings = optionset.has(optionspec3) ? serverproperties.field_241082_U_.func_236230_k_() : serverproperties.field_241082_U_;
}
+ // Forge: Deserialize the DimensionGeneratorSettings to ensure modded dims are loaded on first server load (see SimpleRegistryCodec#decode). Vanilla behaviour only loads from the server.properties and deserializes only after the 2nd server load.
+ dimensiongeneratorsettings = DimensionGeneratorSettings.field_236201_a_.encodeStart(worldsettingsimport, dimensiongeneratorsettings).flatMap(nbt -> DimensionGeneratorSettings.field_236201_a_.parse(worldsettingsimport, nbt)).getOrThrow(false, errorMsg->{});
iserverconfiguration = new ServerWorldInfo(worldsettings, dimensiongeneratorsettings, Lifecycle.stable());
}
@@ -169,6 +178,7 @@
Thread thread = new Thread("Server Shutdown Thread") {
public void run() {
dedicatedserver.func_71263_m(true);
@@ -106,7 +106,16 @@
if (flag2) {
serverplayerentity.field_71135_a.func_147359_a(new SPlaySoundEffectPacket(SoundEvents.field_232818_ms_, SoundCategory.BLOCKS, (double)blockpos.func_177958_n(), (double)blockpos.func_177956_o(), (double)blockpos.func_177952_p(), 1.0F, 1.0F));
}
@@ -786,7 +795,7 @@
@@ -769,6 +778,8 @@
this.field_192055_p.put(uuid, playeradvancements);
}
+ // Forge: don't overwrite active player with a fake one.
+ if (!(p_192054_1_ instanceof net.minecraftforge.common.util.FakePlayer))
playeradvancements.func_192739_a(p_192054_1_);
return playeradvancements;
}
@@ -786,7 +797,7 @@
}
public List<ServerPlayerEntity> func_181057_v() {
@@ -115,7 +124,7 @@
}
@Nullable
@@ -804,6 +813,7 @@
@@ -804,6 +815,7 @@
}
this.func_148540_a(new STagsListPacket(this.field_72400_f.func_244266_aF()));
@@ -123,7 +132,7 @@
SUpdateRecipesPacket supdaterecipespacket = new SUpdateRecipesPacket(this.field_72400_f.func_199529_aN().func_199510_b());
for(ServerPlayerEntity serverplayerentity : this.field_72404_b) {
@@ -816,4 +826,12 @@
@@ -816,4 +828,12 @@
public boolean func_206257_x() {
return this.field_72407_n;
}
@@ -17,6 +17,15 @@
chunkprimer.func_201637_h(blockpos);
}
}
@@ -167,7 +168,7 @@
Heightmap.func_222690_a(ichunk, enumset);
CompoundNBT compoundnbt4 = compoundnbt.func_74775_l("Structures");
ichunk.func_201612_a(func_235967_a_(p_222656_1_, compoundnbt4, p_222656_0_.func_72905_C()));
- ichunk.func_201606_b(func_227075_a_(p_222656_3_, compoundnbt4));
+ net.minecraftforge.common.ForgeHooks.fixNullStructureReferences(ichunk, func_227075_a_(p_222656_3_, compoundnbt4));
if (compoundnbt.func_74767_n("shouldSave")) {
ichunk.func_177427_f(true);
}
@@ -183,6 +184,7 @@
}
@@ -29,8 +29,6 @@ import java.util.List;
*/
public class EarlyLoadingException extends RuntimeException {
public static class ExceptionData {
private final IModInfo modInfo;
private final String i18message;
private final Object[] args;
@@ -34,6 +34,7 @@ import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.fml.loading.moddiscovery.BackgroundScanHandler;
import net.minecraftforge.fml.loading.moddiscovery.ModDiscoverer;
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo;
import net.minecraftforge.fml.loading.progress.EarlyProgressVisualization;
import net.minecraftforge.fml.loading.progress.StartupMessageManager;
import net.minecraftforge.forgespi.Environment;
@@ -53,6 +54,7 @@ import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@@ -214,7 +216,7 @@ public class FMLLoader
loadingModList = backgroundScanHandler.getLoadingModList();
commonLaunchHandler.addLibraries(backgroundScanHandler.getModFiles().getOrDefault(IModFile.Type.LIBRARY, Collections.emptyList()));
progressWindowTick.run();
return backgroundScanHandler.getModFiles();
return loadingModList.getModFiles().stream().map(ModFileInfo::getFile).collect(Collectors.groupingBy(ModFile::getType));
}
public static ICoreModProvider getCoreModProvider() {
@@ -170,7 +170,7 @@ public class LanguageLoadingProvider
LOGGER.error("Missing language {} version {} wanted by {}", modLoader, modLoaderVersion, languageFileName);
throw new EarlyLoadingException("Missing language "+modLoader, null, Collections.singletonList(new EarlyLoadingException.ExceptionData("fml.language.missingversion", modLoader, modLoaderVersion, languageFileName, "null")));
}
if (!modLoaderVersion.containsVersion(mlw.getVersion())) {
if (!VersionSupportMatrix.testVersionSupportMatrix(modLoaderVersion, modLoader, "languageloader", (llid, range) -> range.containsVersion(mlw.getVersion()))) {
LOGGER.error("Missing language {} version {} wanted by {}, found {}", modLoader, modLoaderVersion, languageFileName, mlw.getVersion());
throw new EarlyLoadingException("Missing language "+ modLoader + " matching range "+modLoaderVersion + " found "+mlw.getVersion(), null, Collections.singletonList(new EarlyLoadingException.ExceptionData("fml.language.missingversion", modLoader, modLoaderVersion, languageFileName, mlw.getVersion())));
}
@@ -36,17 +36,11 @@ import org.apache.logging.log4j.util.StringBuilderFormattable;
import org.apache.maven.artifact.versioning.ArtifactVersion;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import java.util.AbstractMap;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static net.minecraftforge.fml.loading.LogMarkers.LOADING;
@@ -56,6 +50,7 @@ public class ModSorter
private List<ModFile> modFiles;
private List<ModInfo> sortedList;
private Map<String, ModInfo> modIdNameLookup;
private List<ModFile> forgeAndMC;
private ModSorter(final List<ModFile> modFiles)
{
@@ -65,21 +60,41 @@ public class ModSorter
public static LoadingModList sort(List<ModFile> mods)
{
final ModSorter ms = new ModSorter(mods);
EarlyLoadingException earlyLoadingException = null;
try {
ms.findLanguages();
ms.buildUniqueList();
ms.verifyDependencyVersions();
ms.sort();
} catch (EarlyLoadingException ele) {
earlyLoadingException = ele;
ms.sortedList = Collections.emptyList();
} catch (EarlyLoadingException e) {
// We cannot build any list with duped mods. We have to abort immediately and report it
return LoadingModList.of(ms.forgeAndMC, ms.forgeAndMC.stream().map(mf->(ModInfo)mf.getModInfos().get(0)).collect(Collectors.toList()), e);
}
// try and locate languages and validate dependencies
List<EarlyLoadingException.ExceptionData> missingLangs = ms.findLanguages();
List<EarlyLoadingException.ExceptionData> missingDeps = ms.verifyDependencyVersions();
final List<ExceptionData> failedList = Stream.concat(missingLangs.stream(), missingDeps.stream()).collect(Collectors.toList());
// if we miss one or the other, we abort now
if (!failedList.isEmpty()) {
return LoadingModList.of(ms.forgeAndMC, ms.forgeAndMC.stream().map(mf->(ModInfo)mf.getModInfos().get(0)).collect(Collectors.toList()), new EarlyLoadingException("failure to validate mod list", null, failedList));
} else {
// Otherwise, lets try and sort the modlist and proceed
EarlyLoadingException earlyLoadingException = null;
try {
ms.sort();
} catch (EarlyLoadingException e) {
earlyLoadingException = e;
}
return LoadingModList.of(ms.modFiles, ms.sortedList, earlyLoadingException);
}
return LoadingModList.of(ms.modFiles, ms.sortedList, earlyLoadingException);
}
private void findLanguages() {
modFiles.forEach(ModFile::identifyLanguage);
private List<EarlyLoadingException.ExceptionData> findLanguages() {
List<EarlyLoadingException.ExceptionData> errorData = new ArrayList<>();
modFiles.forEach(modFile -> {
try {
modFile.identifyLanguage();
} catch (EarlyLoadingException e) {
errorData.addAll(e.getAllData());
}
});
return errorData;
}
@SuppressWarnings("UnstableApiUsage")
@@ -167,6 +182,11 @@ public class ModSorter
.stream()
.collect(Collectors.groupingBy(mf -> mf.getModInfos().get(0).getModId()));
// Capture forge and MC here, so we can keep them for later
forgeAndMC = new ArrayList<>();
forgeAndMC.add((ModFile)modFilesByFirstId.get("minecraft").get(0));
forgeAndMC.add((ModFile)modFilesByFirstId.get("forge").get(0));
// Select the newest by artifact version sorting of non-unique files thus identified
this.modFiles = modFilesByFirstId.entrySet().stream()
.map(this::selectNewestModInfo)
@@ -213,7 +233,7 @@ public class ModSorter
return new AbstractMap.SimpleImmutableEntry<>(fullList.getKey(), modInfoList.get(0));
}
private void verifyDependencyVersions()
private List<EarlyLoadingException.ExceptionData> verifyDependencyVersions()
{
final Map<String, ArtifactVersion> modVersions = modFiles
.stream()
@@ -237,24 +257,24 @@ public class ModSorter
LOGGER.debug(LOADING, "Found {} mandatory requirements", mandatoryModVersions.size());
final Set<IModInfo.ModVersion> missingVersions = mandatoryModVersions
.stream()
.filter(mv->this.modVersionMatches(mv, modVersions))
.filter(mv->this.modVersionNotContained(mv, modVersions))
.collect(Collectors.toSet());
LOGGER.debug(LOADING, "Found {} mandatory mod requirements missing", missingVersions.size());
if (!missingVersions.isEmpty()) {
final List<EarlyLoadingException.ExceptionData> exceptionData = missingVersions
return missingVersions
.stream()
.map(mv -> new EarlyLoadingException.ExceptionData("fml.modloading.missingdependency", mv.getOwner(),
.map(mv -> new ExceptionData("fml.modloading.missingdependency", mv.getOwner(),
mv.getModId(), mv.getOwner().getModId(), mv.getVersionRange(),
modVersions.getOrDefault(mv.getModId(), new DefaultArtifactVersion("null"))))
.collect(Collectors.toList());
throw new EarlyLoadingException("Missing mods", null, exceptionData);
}
return Collections.emptyList();
}
private boolean modVersionMatches(final IModInfo.ModVersion mv, final Map<String, ArtifactVersion> modVersions)
private boolean modVersionNotContained(final IModInfo.ModVersion mv, final Map<String, ArtifactVersion> modVersions)
{
return !(modVersions.containsKey(mv.getModId()) &&
(mv.getVersionRange().containsVersion(modVersions.get(mv.getModId())) || modVersions.get(mv.getModId()).toString().equals("NONE")));
return !(VersionSupportMatrix.testVersionSupportMatrix(mv.getVersionRange(), mv.getModId(), "mod", (modId, range) -> modVersions.containsKey(modId) &&
(range.containsVersion(modVersions.get(modId)) || modVersions.get(modId).toString().equals("NONE"))));
}
}
@@ -0,0 +1,24 @@
package net.minecraftforge.fml.loading;
import net.minecraftforge.forgespi.language.MavenVersionAdapter;
import org.apache.maven.artifact.versioning.ArtifactVersion;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.apache.maven.artifact.versioning.VersionRange;
import java.util.HashMap;
import java.util.function.BiPredicate;
public class VersionSupportMatrix {
private static final HashMap<String, ArtifactVersion> overrideVersions = new HashMap<>();
static {
final ArtifactVersion version = new DefaultArtifactVersion(FMLLoader.mcVersion);
if (MavenVersionAdapter.createFromVersionSpec("[1.16.4]").containsVersion(version)) {
overrideVersions.put("languageloader.javafml", new DefaultArtifactVersion("34")); // we also work with javafml 34
overrideVersions.put("mod.minecraft", new DefaultArtifactVersion("1.16.3")); // we work with anything declaring 1.16.3
overrideVersions.put("mod.forge", new DefaultArtifactVersion("34.1.42")); // we work with anything that supports forge 34.1.42
}
}
public static <T> boolean testVersionSupportMatrix(VersionRange declaredRange, String lookupId, String type, BiPredicate<String, VersionRange> standardLookup) {
return standardLookup.test(lookupId, declaredRange) || overrideVersions.containsKey(type +"." +lookupId) && declaredRange.containsVersion(overrideVersions.get(type +"." +lookupId));
}
}
@@ -24,15 +24,12 @@ import com.google.common.base.CharMatcher;
import org.apache.commons.lang3.tuple.Pair;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;
import java.util.stream.Collectors;
public class StartupMessageManager {
private static final EnumMap<MessageType, List<Message>> messages = new EnumMap<>(MessageType.class);
static {
Arrays.stream(MessageType.values()).forEach(mt->messages.computeIfAbsent(mt, k->new CopyOnWriteArrayList<>()));
}
private static volatile EnumMap<MessageType, List<Message>> messages = new EnumMap<>(MessageType.class);
public static List<Pair<Integer,Message>> getMessages() {
final long ts = System.nanoTime();
@@ -88,22 +85,42 @@ public class StartupMessageManager {
}
}
private synchronized static void addMessage(MessageType type, String message, int maxSize)
{
EnumMap<MessageType, List<Message>> newMessages = new EnumMap<>(messages);
newMessages.compute(type, (key, existingList) -> {
List<Message> newList = new ArrayList<>();
if (existingList != null)
{
if (maxSize < 0)
{
newList.addAll(existingList);
}
else
{
newList.addAll(existingList.subList(0, Math.min(existingList.size(), maxSize)));
}
}
newList.add(new Message(message, type));
return newList;
});
messages = newMessages;
}
public static void addModMessage(final String message) {
final String safeMessage = Ascii.truncate(CharMatcher.ascii().retainFrom(message),80,"~");
final List<Message> messages = StartupMessageManager.messages.get(MessageType.MOD);
messages.subList(0, Math.max(0, messages.size() - 20)).clear();
messages.add(new Message(safeMessage, MessageType.MOD));
addMessage(MessageType.MOD, safeMessage, 20);
}
public static Optional<Consumer<String>> modLoaderConsumer() {
return Optional.of(s-> messages.get(MessageType.ML).add(new Message(s, MessageType.ML)));
return Optional.of(s-> addMessage(MessageType.ML, s, -1));
}
public static Optional<Consumer<String>> locatorConsumer() {
return Optional.of(s -> messages.get(MessageType.LOC).add(new Message(s, MessageType.LOC)));
return Optional.of(s -> addMessage(MessageType.LOC, s, -1));
}
public static Optional<Consumer<String>> mcLoaderConsumer() {
return Optional.of(s-> messages.get(MessageType.MC).add(new Message(s, MessageType.MC)));
return Optional.of(s-> addMessage(MessageType.MC, s, -1));
}
}
@@ -1,3 +1,22 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.client.event;
import net.minecraft.client.network.play.NetworkPlayerInfo;
@@ -112,7 +112,7 @@ public class ForgeIngameGui extends IngameGui
this.scaledHeight = this.mc.getMainWindow().getScaledHeight();
eventParent = new RenderGameOverlayEvent(mStack, partialTicks, this.mc.getMainWindow());
renderHealthMount = mc.player.getRidingEntity() instanceof LivingEntity;
renderFood = mc.player.getRidingEntity() == null;
renderFood = !renderHealthMount;
renderJumpBar = mc.player.isRidingHorse();
right_height = 39;
@@ -1,3 +1,22 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.client.model.generators;
import com.google.common.base.Preconditions;
@@ -1,3 +1,22 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.client.model.generators.loaders;
import com.google.common.base.Preconditions;
@@ -1,3 +1,22 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.client.model.generators.loaders;
import com.google.common.base.Preconditions;
@@ -1,3 +1,22 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.client.model.generators.loaders;
import com.google.common.base.Preconditions;
@@ -1,3 +1,22 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.client.model.generators.loaders;
import com.google.common.base.Preconditions;
@@ -1,3 +1,22 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.client.model.generators.loaders;
import com.google.common.base.Preconditions;
@@ -1,3 +1,22 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.client.model.generators.loaders;
import com.google.common.base.Preconditions;
@@ -43,6 +43,8 @@ import com.mojang.serialization.codecs.RecordCodecBuilder;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import it.unimi.dsi.fastutil.longs.LongSet;
import net.minecraft.advancements.Advancement;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
@@ -91,6 +93,8 @@ import net.minecraft.potion.PotionUtils;
import net.minecraft.stats.Stats;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.util.text.*;
import net.minecraft.world.chunk.IChunk;
import net.minecraft.world.gen.feature.structure.Structure;
import net.minecraft.world.spawner.AbstractSpawner;
import net.minecraft.tileentity.FurnaceTileEntity;
import net.minecraft.tileentity.TileEntity;
@@ -177,7 +181,7 @@ public class ForgeHooks
{
//state = state.getActualState(world, pos);
if (!state.getRequiresTool())
return true;
return ForgeEventFactory.doPlayerHarvestCheck(player, state, true);
ItemStack stack = player.getHeldItemMainhand();
ToolType tool = state.getHarvestTool();
@@ -672,9 +676,15 @@ public class ForgeHooks
return ret;
}
@Deprecated // TODO: Remove 1.17 - Use player-contextual version below.
public static boolean onAnvilChange(RepairContainer container, @Nonnull ItemStack left, @Nonnull ItemStack right, IInventory outputSlot, String name, int baseCost)
{
AnvilUpdateEvent e = new AnvilUpdateEvent(left, right, name, baseCost);
return onAnvilChange(container, left, right, outputSlot, name, baseCost, null);
}
public static boolean onAnvilChange(RepairContainer container, @Nonnull ItemStack left, @Nonnull ItemStack right, IInventory outputSlot, String name, int baseCost, PlayerEntity player)
{
AnvilUpdateEvent e = new AnvilUpdateEvent(left, right, name, baseCost, player);
if (MinecraftForge.EVENT_BUS.post(e)) return false;
if (e.getOutput().isEmpty()) return true;
@@ -1226,4 +1236,18 @@ public class ForgeHooks
modpacks.add("vanilla");
return modpacks;
}
/**
* Fixes MC-194811
* When a structure mod is removed, this map may contain null keys. This will make the world unable to save if this persists.
* If we remove a structure from the save data in this way, we then mark the chunk for saving
*/
public static void fixNullStructureReferences(IChunk chunk, Map<Structure<?>, LongSet> structureReferences)
{
if (structureReferences.remove(null) != null)
{
chunk.setModified(true);
}
chunk.setStructureReferences(structureReferences);
}
}
@@ -19,6 +19,9 @@
package net.minecraftforge.common;
import net.minecraft.command.arguments.ArgumentSerializer;
import net.minecraft.command.arguments.ArgumentTypes;
import net.minecraft.command.arguments.IArgumentSerializer;
import net.minecraft.entity.ai.attributes.Attribute;
import net.minecraft.entity.ai.attributes.RangedAttribute;
import net.minecraft.util.SoundEvent;
@@ -34,6 +37,8 @@ import net.minecraftforge.fml.event.server.FMLServerStoppingEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.fml.loading.progress.StartupMessageManager;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.server.command.EnumArgument;
import net.minecraftforge.server.command.ModIdArgument;
import net.minecraftforge.versions.forge.ForgeVersion;
import net.minecraftforge.versions.mcp.MCPVersion;
@@ -139,13 +144,14 @@ public class ForgeMod implements WorldPersistenceHooks.WorldPersistenceHook
VersionChecker.startVersionCheck();
/*
* We can't actually add any of these, because vanilla clients will choke on unknown argument types
* So our custom arguments will not validate client-side, but they do still work
ArgumentTypes.register("forge:enum", EnumArgument.class, new EnumArgument.Serializer());
registerArgumentTypes();
}
@SuppressWarnings({"unchecked", "rawtypes"})
private void registerArgumentTypes()
{
ArgumentTypes.register("forge:enum", EnumArgument.class, (IArgumentSerializer) new EnumArgument.Serializer());
ArgumentTypes.register("forge:modid", ModIdArgument.class, new ArgumentSerializer<>(ModIdArgument::modIdArgument));
ArgumentTypes.register("forge:structure_type", StructureArgument.class, new ArgumentSerializer<>(StructureArgument::structure));
*/
}
public void serverStopping(FMLServerStoppingEvent evt)
@@ -19,52 +19,150 @@
package net.minecraftforge.event;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.container.RepairContainer;
import net.minecraft.item.ItemStack;
import net.minecraftforge.eventbus.api.Cancelable;
import net.minecraftforge.eventbus.api.Event;
import net.minecraft.item.ItemStack;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
*
* AnvilUpdateEvent is fired when a player places items in both the left and right slots of a anvil.
* If the event is canceled, vanilla behavior will not run, and the output will be set to null.
* If the event is not canceled, but the output is not null, it will set the output and not run vanilla behavior.
* if the output is null, and the event is not canceled, vanilla behavior will execute.
* AnvilUpdateEvent is fired when the inputs (either input stack, or the name) to an anvil are changed. <br>
* It is called from {@link RepairContainer#updateRepairOutput}. <br>
* If the event is canceled, vanilla behavior will not run, and the output will be set to {@link ItemStack#EMPTY}. <br>
* If the event is not canceled, but the output is not empty, it will set the output and not run vanilla behavior. <br>
* if the output is empty, and the event is not canceled, vanilla behavior will execute. <br>
*/
@Cancelable
public class AnvilUpdateEvent extends Event
{
@Nonnull
private final ItemStack left; // The left side of the input
@Nonnull
private final ItemStack right; // The right side of the input
private final String name; // The name to set the item, if the user specified one.
@Nonnull
private ItemStack output; // Set this to set the output stack
private int cost; // The base cost, set this to change it if output != null
private int materialCost; // The number of items from the right slot to be consumed during the repair. Leave as 0 to consume the entire stack.
public AnvilUpdateEvent(@Nonnull ItemStack left, @Nonnull ItemStack right, String name, int cost)
private final ItemStack left;
private final ItemStack right;
private final String name;
private ItemStack output;
private int cost;
private int materialCost;
@Nullable // TODO: Remove 1.17 - Nullable only in the instance that a mod uses the deprecated ctor.
private final PlayerEntity player;
@Deprecated //TODO: Remove 1.17 - Use Player-contextual constructor below.
public AnvilUpdateEvent(ItemStack left, ItemStack right, String name, int cost)
{
this(left, right, name, cost, null);
}
public AnvilUpdateEvent(ItemStack left, ItemStack right, String name, int cost, PlayerEntity player)
{
this.left = left;
this.right = right;
this.output = ItemStack.EMPTY;
this.name = name;
this.player = player;
this.setCost(cost);
this.setMaterialCost(0);
}
@Nonnull
public ItemStack getLeft() { return left; }
@Nonnull
public ItemStack getRight() { return right; }
public String getName() { return name; }
@Nonnull
public ItemStack getOutput() { return output; }
public void setOutput(@Nonnull ItemStack output) { this.output = output; }
public int getCost() { return cost; }
public void setCost(int cost) { this.cost = cost; }
public int getMaterialCost() { return materialCost; }
public void setMaterialCost(int materialCost) { this.materialCost = materialCost; }
/**
* @return The item in the left input (leftmost) anvil slot.
*/
public ItemStack getLeft()
{
return left;
}
/**
* @return The item in the right input (center) anvil slot.
*/
public ItemStack getRight()
{
return right;
}
/**
* This is the name as sent by the client. It may be null if none has been sent. <br>
* If empty, it indicates the user wishes to clear the custom name from the item.
* @return The name that the output item will be set to, if applicable.
*/
@Nullable
public String getName()
{
return name;
}
/**
* This is the output as determined by the event, not by the vanilla behavior between these two items. <br>
* If you are the first receiver of this event, it is guaranteed to be empty. <br>
* It will only be non-empty if changed by an event handler. <br>
* If this event is cancelled, this output stack is discarded.
* @return The item to set in the output (rightmost) anvil slot.
*/
public ItemStack getOutput()
{
return output;
}
/**
* Sets the output slot to a specific itemstack.
* @param output The stack to change the output to.
*/
public void setOutput(ItemStack output)
{
this.output = output;
}
/**
* This is the level cost of this anvil operation. <br>
* When unchanged, it is guaranteed to be left.getRepairCost() + right.getRepairCost().
* @return The level cost of this anvil operation.
*/
public int getCost()
{
return cost;
}
/**
* Changes the level cost of this operation. <br>
* The level cost does prevent the output from being available. <br>
* That is, a player without enough experience may not take the output.
* @param cost The new level cost.
*/
public void setCost(int cost)
{
this.cost = cost;
}
/**
* The material cost is how many units of the right input stack are consumed.
* @return The material cost of this anvil operation.
*/
public int getMaterialCost()
{
return materialCost;
}
/**
* Sets how many right inputs are consumed. <br>
* A material cost of zero consumes the entire stack. <br>
* A material cost higher than the count of the right stack
* consumes the entire stack. <br>
* The material cost does not prevent the output from being available.
* @param materialCost The new material cost.
*/
public void setMaterialCost(int materialCost)
{
this.materialCost = materialCost;
}
/**
* Nullable in the case someone is using the deprecated constructor.
* @return The player using this anvil container.
*/
@Nullable // TODO: Remove 1.17
public PlayerEntity getPlayer()
{
return this.player;
}
}
@@ -19,12 +19,15 @@
package net.minecraftforge.fluids;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.Fluids;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.text.ITextComponent;
import net.minecraftforge.common.util.Constants;
import net.minecraftforge.registries.ForgeRegistries;
@@ -36,6 +39,8 @@ import javax.annotation.Nullable;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.Optional;
/**
* ItemStack substitute for Fluids.
*
@@ -50,6 +55,18 @@ public class FluidStack
public static final FluidStack EMPTY = new FluidStack(Fluids.EMPTY, 0);
public static final Codec<FluidStack> CODEC = RecordCodecBuilder.create(
instance -> instance.group(
Registry.FLUID.fieldOf("FluidName").forGetter(FluidStack::getFluid),
Codec.INT.fieldOf("Amount").forGetter(FluidStack::getAmount),
CompoundNBT.CODEC.optionalFieldOf("Tag").forGetter(stack -> Optional.ofNullable(stack.getTag()))
).apply(instance, (fluid, amount, tag) -> {
FluidStack stack = new FluidStack(fluid, amount);
tag.ifPresent(stack::setTag);
return stack;
})
);
private boolean isEmpty;
private int amount;
private CompoundNBT tag;
@@ -40,6 +40,33 @@ public class ExtensionPoint<T>
*
* The supplier provides my "local" version for sending across the network or writing to disk
* The predicate tests the version from a remote instance or save for acceptability (Boolean is true for network, false for local save)
* and returns true if the version is compatible.
*
* <p>Return {@link net.minecraftforge.fml.network.FMLNetworkConstants#IGNORESERVERONLY} in the supplier, if you wish to be ignored
* as a server side only mod.</p>
* <p>Return true in the predicate for all values of the input string (when network boolean is true) if you are client side,
* and don't care about matching any potential server version.</p>
*
* <p>
* Examples: A server only mod
*
* <code><pre>
* registerExtensionPoint(DISPLAYTEST, ()->Pair.of(
* ()->FMLNetworkConstants.IGNORESERVERONLY, // ignore me, I'm a server only mod
* (s,b)->true // i accept anything from the server or the save, if I'm asked
* )
* </pre></code>
* </p>
* <p>
* Examples: A client only mod
* <code><pre>
* registerExtensionPoint(DISPLAYTEST, ()->Pair.of(
* ()->"anything. i don't care", // if i'm actually on the server, this string is sent but i'm a client only mod, so it won't be
* (remoteversionstring,networkbool)->networkbool // i accept anything from the server, by returning true if it's asking about the server
* )
* </pre></code>
* </p>
*
*/
public static final ExtensionPoint<Pair<Supplier<String>, BiPredicate<String, Boolean>>> DISPLAYTEST = new ExtensionPoint<>();
@@ -75,6 +75,16 @@ public abstract class ModContainer
(incoming, isNetwork)->Objects.equals(incoming, this.modInfo.getVersion().toString())));
}
/**
* Errored container state, used for filtering. Does nothing.
*/
ModContainer()
{
this.modLoadingStage = ModLoadingStage.ERROR;
modId = "BROKEN";
namespace = "BROKEN";
modInfo = null;
}
/**
* @return the modid for this mod
*/
@@ -33,6 +33,7 @@ import net.minecraftforge.fml.loading.LoadingModList;
import net.minecraftforge.fml.loading.moddiscovery.InvalidModIdentifier;
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo;
import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
import net.minecraftforge.fml.loading.progress.StartupMessageManager;
import net.minecraftforge.fml.network.FMLNetworkConstants;
import net.minecraftforge.fml.network.NetworkRegistry;
@@ -268,8 +269,10 @@ public class ModLoader
final Map<String, IModInfo> modInfoMap = modFile.getModFileInfo().getMods().stream().collect(Collectors.toMap(IModInfo::getModId, Function.identity()));
LOGGER.debug(LOADING, "ModContainer is {}", ModContainer.class.getClassLoader());
final List<ModContainer> containers = modFile.getScanResult().getTargets().entrySet().stream().
map(e -> buildModContainerFromTOML(modFile, modClassLoader, modInfoMap, e))
final List<ModContainer> containers = modFile.getScanResult().getTargets()
.entrySet()
.stream()
.map(e -> buildModContainerFromTOML(modFile, modClassLoader, modInfoMap, e))
.filter(Objects::nonNull)
.collect(Collectors.toList());
if (containers.size() != modInfoMap.size()) {
@@ -279,7 +282,8 @@ public class ModLoader
modInfoMap.size(), modInfoMap.values().stream().map(IModInfo::getModId).sorted().collect(Collectors.toList()));
loadingExceptions.add(new ModLoadingException(null, ModLoadingStage.CONSTRUCT, "fml.modloading.missingclasses", null, modFile.getFilePath()));
}
return containers;
// remove errored mod containers
return containers.stream().filter(mc -> mc.modLoadingStage != ModLoadingStage.ERROR).collect(Collectors.toList());
}
private ModContainer buildModContainerFromTOML(final ModFile modFile, final TransformingClassLoader modClassLoader, final Map<String, IModInfo> modInfoMap, final Map.Entry<String, ? extends IModLanguageProvider.IModLanguageLoader> idToProviderEntry) {
@@ -291,9 +295,10 @@ public class ModLoader
orElseThrow(()->new ModLoadingException(null, ModLoadingStage.CONSTRUCT, "fml.modloading.missingmetadata", null, modId));
return languageLoader.loadMod(info, modClassLoader, modFile.getScanResult());
} catch (ModLoadingException mle) {
// exceptions are caught and added to the error list for later handling. Null is returned here.
// exceptions are caught and added to the error list for later handling
loadingExceptions.add(mle);
return null;
// return an errored container instance here, because we tried and failed building a container.
return new ErroredModContainer();
}
}
@@ -336,4 +341,20 @@ public class ModLoader
public static boolean isDataGenRunning () {
return runningDataGen;
}
private static class ErroredModContainer extends ModContainer {
public ErroredModContainer() {
super();
}
@Override
public boolean matches(final Object mod) {
return false;
}
@Override
public Object getMod() {
return null;
}
}
}
@@ -19,6 +19,10 @@
package net.minecraftforge.fml.javafmlmod;
import cpw.mods.modlauncher.api.LamdbaExceptionUtils;
import net.minecraftforge.fml.ModLoadingException;
import net.minecraftforge.fml.ModLoadingStage;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.forgespi.language.ILifecycleEvent;
import net.minecraftforge.forgespi.language.IModLanguageProvider;
import net.minecraftforge.forgespi.language.IModInfo;
@@ -39,7 +43,6 @@ import static net.minecraftforge.fml.Logging.*;
public class FMLJavaModLanguageProvider implements IModLanguageProvider
{
private static final Logger LOGGER = LogManager.getLogger();
private static class FMLModTarget implements IModLanguageProvider.IModLanguageLoader {
@@ -72,10 +75,24 @@ public class FMLJavaModLanguageProvider implements IModLanguageProvider
final Constructor<?> constructor = fmlContainer.getConstructor(IModInfo.class, String.class, ClassLoader.class, ModFileScanData.class);
return (T)constructor.newInstance(info, className, modClassLoader, modFileScanResults);
}
catch (NoSuchMethodException | ClassNotFoundException | InstantiationException | IllegalAccessException | InvocationTargetException e)
// ALL exception handling has to be done through the classloader, because we're loaded in the wrong context, so any classes we just blind load will be in the wrong
// class loading context. Funky but works.
catch (InvocationTargetException e) {
LOGGER.fatal(LOADING, "Failed to build mod", e);
final Class<RuntimeException> mle = (Class<RuntimeException>)LamdbaExceptionUtils.uncheck(()->Class.forName("net.minecraftforge.fml.ModLoadingException", true, Thread.currentThread().getContextClassLoader()));
if (mle.isInstance(e.getTargetException())) {
throw mle.cast(e.getTargetException());
} else {
final Class<ModLoadingStage> mls = (Class<ModLoadingStage>) LamdbaExceptionUtils.uncheck(()->Class.forName("net.minecraftforge.fml.ModLoadingStage", true, Thread.currentThread().getContextClassLoader()));
throw LamdbaExceptionUtils.uncheck(()->LamdbaExceptionUtils.uncheck(()->mle.getConstructor(IModInfo.class, mls, String.class, Throwable.class)).newInstance(info, Enum.valueOf(mls, "CONSTRUCT"), "fml.modloading.failedtoloadmodclass", e));
}
}
catch (NoSuchMethodException | ClassNotFoundException | InstantiationException | IllegalAccessException e)
{
LOGGER.fatal(LOADING,"Unable to load FMLModContainer, wut?", e);
throw new RuntimeException(e);
final Class<RuntimeException> mle = (Class<RuntimeException>)LamdbaExceptionUtils.uncheck(()->Class.forName("net.minecraftforge.fml.ModLoadingException", true, Thread.currentThread().getContextClassLoader()));
final Class<ModLoadingStage> mls = (Class<ModLoadingStage>) LamdbaExceptionUtils.uncheck(()->Class.forName("net.minecraftforge.fml.ModLoadingStage", true, Thread.currentThread().getContextClassLoader()));
throw LamdbaExceptionUtils.uncheck(()->LamdbaExceptionUtils.uncheck(()->mle.getConstructor(IModInfo.class, mls, String.class, Throwable.class)).newInstance(info, Enum.valueOf(mls, "CONSTRUCT"), "fml.modloading.failedtoloadmodclass", e));
}
}
}
@@ -27,7 +27,8 @@ public enum ConnectionType
private final Function<String, Integer> versionExtractor;
ConnectionType(Function<String, Integer> versionExtractor) {
ConnectionType(Function<String, Integer> versionExtractor)
{
this.versionExtractor = versionExtractor;
}
@@ -36,7 +37,14 @@ public enum ConnectionType
return vers.startsWith(FMLNetworkConstants.FMLNETMARKER) ? MODDED : VANILLA;
}
public int getFMLVersionNumber(final String fmlVersion) {
public int getFMLVersionNumber(final String fmlVersion)
{
return versionExtractor.apply(fmlVersion);
}
public boolean isVanilla()
{
return this == VANILLA;
}
}
@@ -27,6 +27,8 @@ import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import net.minecraft.tags.ITagCollection;
import net.minecraft.tags.ITagCollectionSupplier;
import net.minecraft.util.text.StringTextComponent;
@@ -62,7 +64,17 @@ public class NetworkHooks
public static ConnectionType getConnectionType(final Supplier<NetworkManager> connection)
{
return ConnectionType.forVersionFlag(connection.get().channel().attr(FMLNetworkConstants.FML_NETVERSION).get());
return getConnectionType(connection.get().channel());
}
public static ConnectionType getConnectionType(ChannelHandlerContext context)
{
return getConnectionType(context.channel());
}
private static ConnectionType getConnectionType(Channel channel)
{
return ConnectionType.forVersionFlag(channel.attr(FMLNetworkConstants.FML_NETVERSION).get());
}
public static IPacket<?> getEntitySpawningPacket(Entity entity)
@@ -68,6 +68,7 @@ import net.minecraftforge.fml.loading.moddiscovery.ModFile;
import net.minecraftforge.fml.packs.ModFileResourcePack;
import net.minecraftforge.fml.packs.ResourcePackLoader;
import net.minecraftforge.forgespi.language.IModInfo;
import net.minecraftforge.network.VanillaConnectionNetworkFilter;
import net.minecraftforge.registries.GameData;
public class ServerLifecycleHooks
@@ -168,6 +169,7 @@ public class ServerLifecycleHooks
if (packet.getRequestedState() == ProtocolType.STATUS) return true;
NetworkHooks.registerServerLoginChannel(manager, packet);
VanillaConnectionNetworkFilter.injectIfNecessary(manager);
return true;
}
@@ -0,0 +1,89 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.network;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Predicate;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.builder.ArgumentBuilder;
import com.mojang.brigadier.tree.ArgumentCommandNode;
import com.mojang.brigadier.tree.CommandNode;
import com.mojang.brigadier.tree.RootCommandNode;
class CommandTreeCleaner
{
/**
* Cleans the command tree starting at the given root node from any argument types that do not match the given predicate.
* Any {@code ArgumentCommandNode}s that have an unmatched argument type will be stripped from the tree.
* @return A new command tree, stripped of any unmatched argument types
*/
public static <S> RootCommandNode<S> cleanArgumentTypes(RootCommandNode<S> root, Predicate<ArgumentType<?>> argumentTypeFilter)
{
Predicate<CommandNode<?>> nodeFilter = node -> !(node instanceof ArgumentCommandNode<?, ?>) || argumentTypeFilter.test(((ArgumentCommandNode<?, ?>)node).getType());
return (RootCommandNode<S>)processCommandNode(root, nodeFilter, new HashMap<>());
}
private static <S> CommandNode<S> processCommandNode(CommandNode<S> node, Predicate<CommandNode<?>> nodeFilter, Map<CommandNode<S>, CommandNode<S>> newNodes)
{
CommandNode<S> existingNode = newNodes.get(node);
if (existingNode == null)
{
CommandNode<S> newNode = cloneNode(node, nodeFilter, newNodes);
newNodes.put(node, newNode);
node.getChildren().stream()
.filter(nodeFilter)
.map(child -> processCommandNode(child, nodeFilter, newNodes))
.forEach(newNode::addChild);
return newNode;
}
else
{
return existingNode;
}
}
private static <S> CommandNode<S> cloneNode(CommandNode<S> node, Predicate<CommandNode<?>> nodeFilter, Map<CommandNode<S>, CommandNode<S>> newNodes)
{
if (node instanceof RootCommandNode<?>)
{
return new RootCommandNode<>();
}
else
{
ArgumentBuilder<S, ?> builder = node.createBuilder();
if (node.getRedirect() != null)
{
if (nodeFilter.test(node.getRedirect()))
{
builder.forward(processCommandNode(node.getRedirect(), nodeFilter, newNodes), node.getRedirectModifier(), node.isFork());
}
else
{
builder.redirect(null);
}
}
return builder.build();
}
}
}
@@ -0,0 +1,118 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.network;
import java.util.AbstractMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import javax.annotation.Nonnull;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageEncoder;
import net.minecraft.command.ISuggestionProvider;
import net.minecraft.command.arguments.ArgumentTypes;
import net.minecraft.network.IPacket;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.play.server.SCommandListPacket;
import net.minecraft.network.play.server.SEntityPropertiesPacket;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.network.NetworkHooks;
import net.minecraftforge.registries.ForgeRegistries;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.google.common.collect.ImmutableMap;
import com.mojang.brigadier.tree.RootCommandNode;
/**
* A filter for network packets, used to filter/modify parts of vanilla network messages that
* will cause errors or warnings on vanilla clients, for example entity attributes that are added by Forge or mods.
*/
public class VanillaConnectionNetworkFilter extends MessageToMessageEncoder<IPacket<?>>
{
private static final Logger LOGGER = LogManager.getLogger();
private static final Map<Class<? extends IPacket<?>>, Function<IPacket<?>, ? extends IPacket<?>>> handlers = ImmutableMap.<Class<? extends IPacket<?>>, Function<IPacket<?>, ? extends IPacket<?>>>builder()
.put(handler(SEntityPropertiesPacket.class, VanillaConnectionNetworkFilter::filterEntityProperties))
.put(handler(SCommandListPacket.class, VanillaConnectionNetworkFilter::filterCommandList))
.build();
public static void injectIfNecessary(NetworkManager manager)
{
if (NetworkHooks.isVanillaConnection(manager))
{
manager.channel().pipeline().addBefore("packet_handler", "forge:vanilla_filter", new VanillaConnectionNetworkFilter());
LOGGER.debug("Injected into {}", manager);
}
}
/**
* Helper function for building the handler map.
*/
@Nonnull
private static <T extends IPacket<?>> Map.Entry<Class<? extends IPacket<?>>, Function<IPacket<?>, ? extends IPacket<?>>> handler(Class<T> cls, Function<T, ? extends IPacket<?>> function)
{
return new AbstractMap.SimpleEntry<>(cls, function.compose(cls::cast));
}
/**
* Filter for SEntityPropertiesPacket. Filters out any entity attributes that are not in the "minecraft" namespace.
* A vanilla client would ignore these with an error log.
*/
@Nonnull
private static SEntityPropertiesPacket filterEntityProperties(SEntityPropertiesPacket msg)
{
SEntityPropertiesPacket newPacket = new SEntityPropertiesPacket();
msg.getSnapshots().stream()
.filter(snapshot -> {
ResourceLocation key = ForgeRegistries.ATTRIBUTES.getKey(snapshot.func_240834_a_());
return key != null && key.getNamespace().equals("minecraft");
})
.forEach(snapshot -> newPacket.getSnapshots().add(snapshot));
return newPacket;
}
/**
* Filter for SCommandListPacket. Uses {@link CommandTreeCleaner} to filter out any ArgumentTypes that are not in the "minecraft" or "brigadier" namespace.
* A vanilla client would fail to deserialize the packet and disconnect with an error message if these were sent.
*/
@Nonnull
private static SCommandListPacket filterCommandList(SCommandListPacket packet)
{
RootCommandNode<ISuggestionProvider> root = packet.getRoot();
RootCommandNode<ISuggestionProvider> newRoot = CommandTreeCleaner.cleanArgumentTypes(root, argType -> {
ResourceLocation id = ArgumentTypes.getId(argType);
return id != null && (id.getNamespace().equals("minecraft") || id.getNamespace().equals("brigadier"));
});
return new SCommandListPacket(newRoot);
}
@Override
protected void encode(ChannelHandlerContext ctx, IPacket<?> msg, List<Object> out)
{
Function<IPacket<?>, ? extends IPacket<?>> function = handlers.getOrDefault(msg.getClass(), Function.identity());
out.add(function.apply(msg));
}
}
@@ -680,6 +680,9 @@ public class GameData
for (ResourceLocation s : missingRegs)
text.append(s).append("\n");
LOGGER.warn(REGISTRIES, header);
LOGGER.warn(REGISTRIES, text.toString());
}
}
@@ -692,7 +695,7 @@ public class GameData
{
final Class<? extends IForgeRegistryEntry> clazz = RegistryManager.ACTIVE.getSuperType(key);
remaps.put(key, Maps.newLinkedHashMap());
missing.put(key, Maps.newHashMap());
missing.put(key, Maps.newLinkedHashMap());
loadPersistentDataToStagingRegistry(RegistryManager.ACTIVE, STAGING, remaps.get(key), missing.get(key), key, value, clazz);
});
@@ -769,6 +772,9 @@ public class GameData
entries.stream().sorted((o1, o2) -> o1.compareNamespaced(o2)).forEach(rl -> buf.append(" ").append(rl).append("\n"));
buf.append("\n");
});
LOGGER.warn(REGISTRIES, header);
LOGGER.warn(REGISTRIES, buf.toString());
}
if (!defaulted.isEmpty())
@@ -861,7 +867,7 @@ public class GameData
{
ForgeRegistry<T> frozen = RegistryManager.FROZEN.getRegistry(name);
ForgeRegistry<T> newRegistry = STAGING.getRegistry(name, RegistryManager.FROZEN);
Map<ResourceLocation, Integer> _new = Maps.newHashMap();
Map<ResourceLocation, Integer> _new = Maps.newLinkedHashMap();
frozen.getKeys().stream().filter(key -> !newRegistry.containsKey(key)).forEach(key -> _new.put(key, frozen.getID(key)));
newRegistry.loadIds(_new, frozen.getOverrideOwners(), Maps.newLinkedHashMap(), remaps, frozen, name);
}
@@ -19,6 +19,7 @@
package net.minecraftforge.server.command;
import com.google.gson.JsonObject;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.context.CommandContext;
@@ -26,6 +27,9 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import net.minecraft.command.ISuggestionProvider;
import net.minecraft.command.arguments.IArgumentSerializer;
import net.minecraft.network.PacketBuffer;
import java.util.Collection;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
@@ -56,28 +60,33 @@ public class EnumArgument<T extends Enum<T>> implements ArgumentType<T> {
return Stream.of(enumClass.getEnumConstants()).map(Object::toString).collect(Collectors.toList());
}
/* JAVAC HATES RAW TYPES!
@SuppressWarnings({"rawtypes", "unchecked"})
public static class Serialzier implements IArgumentSerializer<EnumArgument> {
public static class Serializer implements IArgumentSerializer<EnumArgument<?>>
{
@Override
public void write(EnumArgument argument, PacketBuffer buffer) {
public void write(EnumArgument<?> argument, PacketBuffer buffer)
{
buffer.writeString(argument.enumClass.getName());
}
@SuppressWarnings({"unchecked", "rawtypes"})
@Override
public EnumArgument<?> read(PacketBuffer buffer) {
try {
public EnumArgument<?> read(PacketBuffer buffer)
{
try
{
String name = buffer.readString();
return new EnumArgument(Class.forName(name));
} catch (ClassNotFoundException e) {
}
catch (ClassNotFoundException e)
{
return null;
}
}
@Override
public void write(EnumArgument argument, JsonObject json) {
public void write(EnumArgument<?> argument, JsonObject json)
{
json.addProperty("enum", argument.enumClass.getName());
}
}
*/
}
@@ -318,7 +318,11 @@ public net.minecraft.world.chunk.ChunkStatus <init>(Ljava/lang/String;Lnet/minec
private-f net.minecraft.world.gen.DebugChunkGenerator field_177462_b #GRID_WIDTH
private-f net.minecraft.world.gen.DebugChunkGenerator field_177464_a #ALL_VALID_STATES
private-f net.minecraft.world.gen.DebugChunkGenerator field_181039_c #GRID_HEIGHT
public net.minecraft.world.gen.blockplacer.BlockPlacerType <init>(Lcom/mojang/serialization/Codec;)V # constructor
public net.minecraft.world.gen.blockstateprovider.BlockStateProviderType <init>(Lcom/mojang/serialization/Codec;)V # constructor
public net.minecraft.world.gen.foliageplacer.FoliagePlacerType <init>(Lcom/mojang/serialization/Codec;)V # constructor
public net.minecraft.world.gen.layer.LayerUtil func_202829_a(JLnet/minecraft/world/gen/layer/traits/IAreaTransformer1;Lnet/minecraft/world/gen/area/IAreaFactory;ILjava/util/function/LongFunction;)Lnet/minecraft/world/gen/area/IAreaFactory; # repeat
public net.minecraft.world.gen.treedecorator.TreeDecoratorType <init>(Lcom/mojang/serialization/Codec;)V # constructor
private-f net.minecraft.world.raid.Raid$WaveMember field_221284_f # VALUES
public net.minecraft.world.server.ServerChunkProvider field_186029_c # chunkGenerator
public net.minecraft.world.server.ServerChunkProvider field_73251_h # worldObj
+3
View File
@@ -27,6 +27,7 @@ net/minecraft/block/Block func_185473_a(Lnet/minecraft/world/IBlockReader;Lnet/m
net/minecraft/block/TallSeaGrassBlock func_185473_a(Lnet/minecraft/world/IBlockReader;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;)Lnet/minecraft/item/ItemStack;
# Vanilla blocks calling these sided methods in getItem
net/minecraft/tileentity/BannerTileEntity func_190615_l(Lnet/minecraft/block/BlockState;)Lnet/minecraft/item/ItemStack;
net/minecraft/block/BannerBlock func_196287_a(Lnet/minecraft/item/DyeColor;)Lnet/minecraft/block/Block;
net/minecraft/block/AttachedStemBlock func_196279_O_()Lnet/minecraft/item/Item;
net/minecraft/block/StemBlock func_176481_j()Lnet/minecraft/item/Item;
#=====================================
@@ -74,6 +75,8 @@ net/minecraft/item/crafting/IRecipe func_193358_e()Ljava/lang/String; # getGroup
net/minecraft/item/crafting/SingleItemRecipe func_193358_e()Ljava/lang/String;
net/minecraft/nbt/CompressedStreamTools func_74797_a(Ljava/io/File;)Lnet/minecraft/nbt/CompoundNBT; # read
net/minecraft/nbt/CompressedStreamTools func_74795_b(Lnet/minecraft/nbt/CompoundNBT;Ljava/io/File;)V # write
net/minecraft/network/play/server/SCommandListPacket func_197693_a()Lcom/mojang/brigadier/tree/RootCommandNode; # getRoot
net/minecraft/network/play/server/SEntityPropertiesPacket func_149441_d()Ljava/util/List; # getSnapshots
net/minecraft/potion/Effect func_220303_e()Lnet/minecraft/potion/EffectType; # getEffectType
net/minecraft/potion/Effect func_111186_k()Ljava/util/Map; # getAttributeModifierMap
net/minecraft/potion/Effect func_188408_i()Z # isBeneficial
@@ -0,0 +1,79 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.debug;
import net.minecraft.fluid.Fluids;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.NBTDynamicOps;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fml.common.Mod;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* Created to host any custom codecs forge may be adding.
*/
@Mod("forge_codecs_test")
public class CodecsTest
{
private static final Logger LOGGER = LogManager.getLogger();
public CodecsTest()
{
testFluidStackCodec();
}
/**
* Makes sure FluidStack.CODEC produces the same data as FluidStack.write
*/
private void testFluidStackCodec()
{
FluidStack noTag = new FluidStack(Fluids.WATER, 10);
FluidStack withTag = new FluidStack(Fluids.LAVA, 10);
withTag.getOrCreateChildTag("test").putString("value", "This is a test");
CompoundNBT noTag_write = noTag.writeToNBT(new CompoundNBT());
CompoundNBT withTag_write = withTag.writeToNBT(new CompoundNBT());
CompoundNBT noTag_encode = (CompoundNBT)FluidStack.CODEC.encodeStart(NBTDynamicOps.INSTANCE, noTag).getOrThrow(false, error -> {
LOGGER.error("Error encoding noTag: {}", error);
});
CompoundNBT withTag_encode = (CompoundNBT)FluidStack.CODEC.encodeStart(NBTDynamicOps.INSTANCE, withTag).getOrThrow(false, error -> {
LOGGER.error("Error encoding withTag: {}", error);
});
if (!noTag_write.equals(noTag_encode))
throw new IllegalStateException("Encoded noTag does not match");
if (!withTag_write.equals(withTag_encode))
throw new IllegalStateException("Encoded withTag does not match");
FluidStack noTag_decode = FluidStack.CODEC.decode(NBTDynamicOps.INSTANCE, noTag_encode).getOrThrow(false, error -> {
LOGGER.error("Error decoding noTag: {}", error);
}).getFirst();
FluidStack withTag_decode = FluidStack.CODEC.decode(NBTDynamicOps.INSTANCE, withTag_encode).getOrThrow(false, error -> {
LOGGER.error("Error decoding withTag: {}", error);
}).getFirst();
if (!noTag.equals(noTag_decode))
throw new IllegalStateException("Decoded noTag does not match");
if (!withTag.equals(withTag_decode))
throw new IllegalStateException("Decoded withTag does not match");
}
}
@@ -0,0 +1,49 @@
package net.minecraftforge.debug.client.rendering;
import net.minecraft.client.Minecraft;
import net.minecraft.item.Items;
import net.minecraft.util.ActionResultType;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
@Mod(RenderLocalPlayerTest.MODID)
@Mod.EventBusSubscriber(value = Dist.CLIENT)
public class RenderLocalPlayerTest
{
public static final String MODID = "render_local_player_test";
static final boolean ENABLED = false;
@SubscribeEvent
public static void onItemRightClickEntity(final PlayerInteractEvent.EntityInteract event)
{
if (ENABLED && event.getItemStack().getItem() == Items.STICK)
{
Minecraft mc = Minecraft.getInstance();
if (mc.getRenderViewEntity() == mc.player)
{
mc.setRenderViewEntity(event.getTarget());
event.setCancellationResult(ActionResultType.SUCCESS);
event.setCanceled(true);
}
}
}
@SubscribeEvent
public static void onItemRightClick(final PlayerInteractEvent.RightClickItem event)
{
if (ENABLED && event.getItemStack().getItem() == Items.STICK)
{
Minecraft mc = Minecraft.getInstance();
if (mc.getRenderViewEntity() != mc.player)
{
mc.setRenderViewEntity(mc.player);
event.setCancellationResult(ActionResultType.SUCCESS);
event.setCanceled(true);
}
}
}
}
+4
View File
@@ -92,3 +92,7 @@ license="LGPL v2.1"
modId="player_game_mode_event_test"
[[mods]]
modId="structure_spawn_list_event_test"
[[mods]]
modId="forge_codecs_test"
[[mods]]
modId="render_local_player_test"