mirror of
https://github.com/MinecraftForge/MinecraftForge.git
synced 2026-11-14 01:04:24 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
949984268d | ||
|
|
114acfca3b | ||
|
|
56e538e8a9 | ||
|
|
fa46f3dd49 | ||
|
|
6ec5a8f2c1 | ||
|
|
49b596dda3 | ||
|
|
0c5ced1bbf | ||
|
|
4a09a2420d | ||
|
|
0ff8a596fc | ||
|
|
bca20ace4e | ||
|
|
f3b53001c9 | ||
|
|
15bac0eeaa | ||
|
|
1782973a29 | ||
|
|
9a4a501a95 | ||
|
|
9bbfbd5479 | ||
|
|
8c68731838 | ||
|
|
0d7f507f4e | ||
|
|
f78b943bdf | ||
|
|
160f3f88f9 | ||
|
|
45e38859ed | ||
|
|
38a5400a8c | ||
|
|
acd18455c2 | ||
|
|
5a7facc20f |
No files matched your search
+4
-2
@@ -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,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));
|
||||
}
|
||||
}
|
||||
+28
-11
@@ -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;
|
||||
|
||||
+19
@@ -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;
|
||||
|
||||
+19
@@ -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;
|
||||
|
||||
+19
@@ -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;
|
||||
|
||||
+19
@@ -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;
|
||||
|
||||
+19
@@ -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;
|
||||
|
||||
+19
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
Reference in new issue
Block a user