Compare commits

...
34 Commits
Author SHA1 Message Date
LexManos db4d8a4729 1.21.1 2024-08-08 13:40:50 -07:00
andan42 0ca1d0ebd0 Removed unneeded boat patch related to MC-119811 (#10061) 2024-08-07 21:49:40 -07:00
LexManos 4995902bc0 Fix network sync of custom datapack registries.
Add gametest to verify that it functions.
2024-08-05 13:30:14 -07:00
James Mitchell 28e55b2843 Add a way to render tooltips from Formatted text and TooltipComponents elements (#10056) 2024-08-04 19:25:23 +01:00
LexManos decaace84a Fix custom creative tabs with search listing all items instead of just their own. 2024-08-01 17:21:35 -07:00
Joseph T. McQuigg 72f98dc4a3 Patch CropBlock to use instanceOf FarmBlock check instead of hard coding to Blocks.FARMLAND (#10044)
Signed-off-by: Joseph T. McQuigg <[email protected]>
2024-07-26 13:06:07 -07:00
LexManos 2951c1dac8 Fix ItemStack sensitive getDefaultAttributeModifiers not being called. 2024-07-25 16:01:53 -07:00
LexManos 40a0a16db0 Add missed @user_jvm_args.txt to run.bat 2024-07-25 16:00:04 -07:00
Martijn van den Brand 520680b037 Fix onPlaceItemIntoWorld always resetting item stack when in creative mode (#10047) 2024-07-18 12:43:11 -07:00
Martijn van den Brand 2844bead6e Fix matrix stack translations for RenderHighlightEvent (#10050) 2024-07-17 20:17:33 -07:00
LexManos d498ec4a45 Fix Global Loot Modifier deserialization not having registry access. Closes #10042 and #10043 2024-07-10 11:46:23 -07:00
LexManos e2d1ca7d0e Bump Mixin to 0.8.7 and allocate more ram to java compile tasks. 2024-07-08 13:11:00 -07:00
Paint_Ninja a547327c61 Use the new fire() and Result#isAllowed/isDenied/isDefault methods from EventBus (#10028) 2024-07-06 11:35:37 -07:00
LexManos e9a7ce9544 Some build cleanup 2024-07-02 10:25:49 -07:00
LexManos 511be6415c Make HangingSignBlockEntity useable with custom BlockEntityTypes. #10038 2024-07-02 10:25:35 -07:00
LexManos 4d85053a4d Send last PoseStack pos to RenderLevelStageEvent AFTER_PARTICLES stage. Fixes #10031 2024-07-02 10:12:16 -07:00
Jonathing 4fcf1877c1 Fix compile errors in MDK (#10029) 2024-06-24 11:52:00 -07:00
LexManos 41fd15fc57 Fix converting dirt to mud consumes whole bottle (not just emptying) Closes #10027 2024-06-21 13:34:37 -07:00
LexManos 8e0845d032 Add support for named sub-caps 2024-06-19 15:30:46 -07:00
LexManos c04e533a61 Fix conditional checking swallowing decoding errors when loading registry entries from datapacks. Fixes #9995 2024-06-19 15:09:37 -07:00
LexManos 54f4997f71 Apply license headers 2024-06-19 12:54:22 -07:00
LexManos 3272e995ab Some code cleanup in ModInfo/ModFileInfo to use less streams and make things easier to debug. 2024-06-18 11:47:11 -07:00
LexManos 8edb551571 Bump NightConfig to 3.7.3, to fix toml sub-configs being completely broken. Fixes #10015 2024-06-18 11:46:34 -07:00
LexManos 4bf0de4763 Make ForgeSpawnEgg assume color is opaque if alpha is set to 0.
Fixes "invisible" spawn eggs by default, but still allows modders to specify partial transparency.
2024-06-18 11:45:13 -07:00
vicmatskiv f6a54436b9 Fixed perspective rendering in SeparateTransformsModel (#10014) 2024-06-17 15:55:22 -07:00
Gabriel Harris-Rouquette 7a497cdbd6 Fix missed PartEntity patch in Player.attack (#10011) 2024-06-16 19:05:01 -07:00
thedarkcolour 06336a40d8 Choose default JarJar mod file type based on parent JAR Closes #9939 2024-06-14 09:50:05 -07:00
Ven 842c95cfb9 Fixed falling block entities not rendering as moving blocks (#10006) 2024-06-14 09:03:14 -07:00
LexManos aa2f471e87 Bump Night Config, Should fix #9122 2024-06-14 08:37:07 -07:00
LexManos 4209d1fc12 Fix ClientTickEvent not firing properly. 2024-06-13 17:13:15 -07:00
LexManos 583f363b6b Change tick event to have pre/post classes (#9890) 2024-06-13 15:15:04 -07:00
LexManos 1c633b4624 Fix Bogged and Wolf armor not being shearable by custom shears. Closes #10005 2024-06-13 14:21:30 -07:00
LexManos 2677511da6 Set team city branch 2024-06-13 14:20:03 -07:00
LexManos 387441c045 Remove Non-HolderLookup methods from INBTSerializeable and mark it as deprecated in favor of using Vanilla's new Component system. Closes #9998 2024-06-13 13:17:03 -07:00
93 changed files with 1092 additions and 751 deletions

No files matched your search

+1 -1
View File
@@ -38,7 +38,7 @@ project {
params {
text("docker_jdk_version", "21", label = "Gradle version", description = "The version of the JDK to use during execution of tasks in a JDK.", display = ParameterDisplay.HIDDEN, allowEmpty = false)
text("docker_gradle_version", "8.7", label = "Gradle version", description = "The version of Gradle to use during execution of Gradle tasks.", display = ParameterDisplay.HIDDEN, allowEmpty = false)
text("git_main_branch", "1.20.x", label = "Git Main Branch", description = "The git main or default branch to use in VCS operations.", display = ParameterDisplay.HIDDEN, allowEmpty = false)
text("git_main_branch", "1.21.x", label = "Git Main Branch", description = "The git main or default branch to use in VCS operations.", display = ParameterDisplay.HIDDEN, allowEmpty = false)
text("git_branch_spec", """
+:refs/heads/(main*)
+:refs/heads/(master*)
-33
View File
@@ -404,16 +404,6 @@ tasks.register("downloadServerShim", DownloadMavenArtifact) {
artifact = libs.bootstrap.shim.get().toString()
changing = true
}
tasks.register("downloadMCPConfig", DownloadMavenArtifact) {
artifact = MCP_ARTIFACT
}
tasks.register('extractMCPConfigMappings', net.minecraftforge.gradle.common.tasks.JarExec) {
ext.output = file('build/mcp_mappings.tsrg')
tool = INSTALLER_TOOLS + ':fatjar'
args = ['--task', 'MCP_DATA', '--key', 'mappings', '--input', downloadMCPConfig.output.get().asFile.absolutePath, '--output', output.absolutePath]
outputs.file(output)
inputs.file(downloadMCPConfig.output)
}
tasks.register('downloadClientMappings', net.minecraftforge.gradle.common.tasks.JarExec) {
ext.output = file('build/client_mappings.tsrg')
tool = INSTALLER_TOOLS + ':fatjar'
@@ -620,9 +610,6 @@ tasks.register('installerJson', InstallerJson) {
dependsOn(launcherJson)
input.from(launcherJson.output)
// Extract MCP Mappings
dependsOn(extractMCPConfigMappings)
input.from(extractMCPConfigMappings.output)
// Download Official Mappings
dependsOn(downloadClientMappings, downloadServerMappings)
input.from(downloadClientMappings.output, downloadServerMappings.output)
@@ -649,14 +636,6 @@ tasks.register('installerJson', InstallerJson) {
minecraft: MC_VERSION,
serverJarPath: '{LIBRARY_DIR}/net/minecraft/server/{MINECRAFT_VERSION}/server-{MINECRAFT_VERSION}-bundled.jar',
data: [
MAPPINGS: [
client: "[${MCP_ARTIFACT.group}:${MCP_ARTIFACT.name}:${MCP_ARTIFACT.version}:mappings@tsrg]",
server: "[${MCP_ARTIFACT.group}:${MCP_ARTIFACT.name}:${MCP_ARTIFACT.version}:mappings@tsrg]"
],
MAPPINGS_SHA: [
client: "'${extractMCPConfigMappings.output.sha1}'",
server: "'${extractMCPConfigMappings.output.sha1}'"
],
MOJMAPS: [
client: "[net.minecraft:client:${MC_VERSION}:mappings@tsrg]",
server: "[net.minecraft:server:${MC_VERSION}:mappings@tsrg]"
@@ -746,18 +725,6 @@ tasks.register('installerJson', InstallerJson) {
outputs: [
'{MC_UNPACKED}': '{MC_UNPACKED_SHA}'
]
], [
jar: INSTALLER_TOOLS,
classpath: INSTALLER_TOOLS_CLASSPATH,
args: [
'--task', 'MCP_DATA',
'--input', "[${MCP_ARTIFACT.descriptor}]",
'--output', '{MAPPINGS}',
'--key', 'mappings'
],
outputs: [
'{MAPPINGS}': '{MAPPINGS_SHA}'
]
], [
jar: INSTALLER_TOOLS,
classpath: INSTALLER_TOOLS_CLASSPATH,
+1
View File
@@ -44,6 +44,7 @@ tasks.withType(JavaCompile).configureEach {
dependsOn 'processResources' // Needed because we merge the output of this with the output of the compile task. And gradle detects downstream tasks using the output without a hard dep
options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation
options.warnings = false // Shutup deprecated for removal warnings
options.forkOptions.jvmArgs += '-Xmx3G' // Needed to make compiling faster, and not run out of heap space in some cases.
}
// Merge the resources and classes into the same directory. We'll need to split them at runtime because
@@ -47,12 +47,8 @@ public class ConfigFileTypeHandler {
throw new ConfigLoadingException(c, ex);
}
LOGGER.debug(CONFIG, "Loaded TOML config file {}", configPath.toString());
try {
FileWatcher.defaultInstance().addWatch(configPath, new ConfigWatcher(c, configData, Thread.currentThread().getContextClassLoader()));
LOGGER.debug(CONFIG, "Watching TOML config file {} for changes", configPath.toString());
} catch (IOException e) {
throw new RuntimeException("Couldn't watch config file", e);
}
FileWatcher.defaultInstance().addWatch(configPath, new ConfigWatcher(c, configData, Thread.currentThread().getContextClassLoader()));
LOGGER.debug(CONFIG, "Watching TOML config file {} for changes", configPath.toString());
return configData;
};
}
@@ -49,49 +49,38 @@ public class CapabilityTokenSubclass implements ILaunchPluginService {
private static final EnumSet<Phase> NAY = EnumSet.noneOf(Phase.class);
@Override
public EnumSet<Phase> handlesClass(Type classType, boolean isEmpty)
{
public EnumSet<Phase> handlesClass(Type classType, boolean isEmpty) {
return isEmpty ? NAY : YAY;
}
@Override
public int processClassWithFlags(final Phase phase, final ClassNode classNode, final Type classType, final String reason)
{
if (CAP_INJECT.equals(classNode.name))
{
for (MethodNode mtd : classNode.methods)
{
if (FUNC_NAME.equals(mtd.name) && FUNC_DESC.equals(mtd.desc))
{
public int processClassWithFlags(final Phase phase, final ClassNode classNode, final Type classType, final String reason) {
if (CAP_INJECT.equals(classNode.name)) {
for (MethodNode mtd : classNode.methods) {
if (FUNC_NAME.equals(mtd.name) && FUNC_DESC.equals(mtd.desc)) {
mtd.access &= ~Opcodes.ACC_FINAL; // We have it final in code so people don't override it, cuz that'd be stupid, and make our transformer more complicated.
}
}
return ComputeFlags.SIMPLE_REWRITE;
}
else if (CAP_INJECT.equals(classNode.superName))
{
} else if (CAP_INJECT.equals(classNode.superName)) {
Holder cls = new Holder();
SignatureReader reader = new SignatureReader(classNode.signature); // Having a node version of this would probably be useful.
reader.accept(new SignatureVisitor(Opcodes.ASM9)
{
reader.accept(new SignatureVisitor(Opcodes.ASM9) {
Deque<String> stack = new ArrayDeque<>();
@Override
public void visitClassType(final String name)
{
public void visitClassType(final String name) {
stack.push(name);
}
@Override
public void visitInnerClassType(final String name)
{
public void visitInnerClassType(final String name) {
stack.push(stack.pop() + '$' + name);
}
@Override
public void visitEnd()
{
public void visitEnd() {
var val = stack.pop();
if (!stack.isEmpty() && CAP_INJECT.equals(stack.peek()))
cls.value = val;
@@ -106,9 +95,7 @@ public class CapabilityTokenSubclass implements ILaunchPluginService {
mtd.visitInsn(Opcodes.ARETURN);
mtd.visitEnd();
return ComputeFlags.COMPUTE_MAXS;
}
else
{
} else {
return ComputeFlags.NO_REWRITE;
}
}
@@ -116,5 +103,4 @@ public class CapabilityTokenSubclass implements ILaunchPluginService {
private static class Holder {
String value;
}
}
@@ -42,6 +42,11 @@ public abstract class AbstractModProvider implements IModProvider {
@Nullable
protected IModLocator.ModFileOrException createMod(Path path, boolean ignoreUnknown) {
return createMod(path, false, getDefaultJarModType());
}
@Nullable
protected IModLocator.ModFileOrException createMod(Path path, boolean ignoreUnknown, String defaultType) {
var mjm = new ModJarMetadata();
var sj = SecureJar.from(
jar -> jar.moduleDataProvider().findFile(MODS_TOML).isPresent() ? mjm : JarMetadata.from(jar, path),
@@ -51,7 +56,7 @@ public abstract class AbstractModProvider implements IModProvider {
IModFile mod;
var type = sj.moduleDataProvider().getManifest().getMainAttributes().getValue(ModFile.TYPE);
if (type == null)
type = getDefaultJarModType();
type = defaultType;
if (sj.moduleDataProvider().findFile(MODS_TOML).isPresent()) {
LOGGER.debug(LogMarkers.SCAN, "Found {} mod of type {}: {}", MODS_TOML, type, path);
@@ -83,7 +83,14 @@ public class JarInJarDependencyLocator extends AbstractModProvider implements ID
final Map<String, ?> outerFsArgs = ImmutableMap.of("packagePath", pathInModFile);
final FileSystem zipFS = FileSystems.newFileSystem(filePathUri, outerFsArgs);
final Path pathInFS = zipFS.getPath("/");
return Optional.of(createMod(pathInFS).file());
final IModFile.Type parentType = file.getType();
final String modType;
if (parentType == IModFile.Type.LIBRARY || parentType == IModFile.Type.LANGPROVIDER) {
modType = IModFile.Type.LIBRARY.name();
} else {
modType = IModFile.Type.GAMELIBRARY.name();
}
return Optional.of(createMod(pathInFS, false, modType).file());
} catch (Exception e) {
LOGGER.error("Failed to load mod file {} from {}", path, file.getFileName());
final RuntimeException exception = new ModFileLoadingException("Failed to load mod file " + file.getFileName());
@@ -7,7 +7,6 @@ package net.minecraftforge.fml.loading.moddiscovery;
import com.google.common.base.Strings;
import com.mojang.logging.LogUtils;
import cpw.mods.modlauncher.api.LamdbaExceptionUtils;
import net.minecraftforge.fml.loading.LogMarkers;
import net.minecraftforge.fml.loading.StringUtils;
import net.minecraftforge.forgespi.language.IConfigurable;
@@ -18,17 +17,15 @@ import org.jetbrains.annotations.ApiStatus;
import org.slf4j.Logger;
import javax.security.auth.x500.X500Principal;
import java.net.URL;
import java.security.CodeSigner;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SignatureException;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
@@ -37,10 +34,8 @@ import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class ModFileInfo implements IModFileInfo, IConfigurable
{
public class ModFileInfo implements IModFileInfo, IConfigurable {
private static final Logger LOGGER = LogUtils.getLogger();
private static final String MAYBE_NOT_JAVAFML_VER = "[2,)";
private static final String JAVAFML = "javafml";
@@ -60,8 +55,7 @@ public class ModFileInfo implements IModFileInfo, IConfigurable
private final String license;
private final List<String> usesServices;
ModFileInfo(final ModFile modFile, final IConfigurable config, Consumer<IModFileInfo> configFileConsumer)
{
ModFileInfo(final ModFile modFile, final IConfigurable config, Consumer<IModFileInfo> configFileConsumer) {
this.modFile = modFile;
this.config = config;
configFileConsumer.accept(this);
@@ -86,10 +80,6 @@ public class ModFileInfo implements IModFileInfo, IConfigurable
.orElse(false);
this.clientSideOnly = config.<Boolean>getConfigElement("clientSideOnly")
.orElse(false);
if (this.clientSideOnly) {
// if clientSideOnly, then this is definitely a Forge mod
maybeNotAForgeMod = false;
}
this.showAsDataPack = config.<Boolean>getConfigElement("showAsDataPack")
.orElse(false);
this.usesServices = config.<List<String>>getConfigElement("services")
@@ -98,6 +88,10 @@ public class ModFileInfo implements IModFileInfo, IConfigurable
.map(StringUtils::toURL)
.orElse(null);
// if clientSideOnly, then this is definitely a Forge mod
if (this.clientSideOnly)
maybeNotAForgeMod = false;
if (maybeNotAForgeMod) {
// mark this file as not a Forge mod. Note: this marker may be removed later based on the mod dependencies
this.properties = config.<Map<String, Object>>getConfigElement("properties")
@@ -111,14 +105,13 @@ public class ModFileInfo implements IModFileInfo, IConfigurable
final List<? extends IConfigurable> modConfigs = config.getConfigList("mods");
if (modConfigs.isEmpty())
{
throw new InvalidModFileException("Missing mods list", this);
}
this.mods = modConfigs.stream()
.map(mi-> (IModInfo)new ModInfo(this, mi))
.toList();
if (LOGGER.isDebugEnabled(LogMarkers.LOADING))
{
if (LOGGER.isDebugEnabled(LogMarkers.LOADING)) {
LOGGER.debug(LogMarkers.LOADING, "Found valid mod file {} with {} mods - versions {}",
this.modFile.getFileName(),
this.mods.stream().map(IModInfo::getModId).collect(Collectors.joining(",", "{", "}")),
@@ -132,13 +125,11 @@ public class ModFileInfo implements IModFileInfo, IConfigurable
}
@Override
public List<IModInfo> getMods()
{
public List<IModInfo> getMods() {
return mods;
}
public ModFile getFile()
{
public ModFile getFile() {
return this.modFile;
}
@@ -148,44 +139,37 @@ public class ModFileInfo implements IModFileInfo, IConfigurable
}
@Override
public Map<String, Object> getFileProperties()
{
public Map<String, Object> getFileProperties() {
return this.properties;
}
@Override
public boolean showAsResourcePack()
{
public boolean showAsResourcePack() {
return this.showAsResourcePack;
}
@Override
public boolean isClientSideOnly()
{
public boolean isClientSideOnly() {
return this.clientSideOnly;
}
@Override
public boolean showAsDataPack()
{
public boolean showAsDataPack() {
return this.showAsDataPack;
}
@Override
public <T> Optional<T> getConfigElement(final String... key)
{
public <T> Optional<T> getConfigElement(final String... key) {
return this.config.getConfigElement(key);
}
@Override
public List<? extends IConfigurable> getConfigList(final String... key)
{
public List<? extends IConfigurable> getConfigList(final String... key) {
return this.config.getConfigList(key);
}
@Override
public String getLicense()
{
public String getLicense() {
return license;
}
@@ -194,49 +178,78 @@ public class ModFileInfo implements IModFileInfo, IConfigurable
return this;
}
public URL getIssueURL()
{
public URL getIssueURL() {
return issueURL;
}
public boolean missingLicense()
{
public boolean missingLicense() {
return Strings.isNullOrEmpty(license);
}
private final char[] HEX = "0123456789ABCDEF".toCharArray();
public Optional<String> getCodeSigningFingerprint() {
var signers = this.modFile.getSecureJar().getManifestSigners();
return (signers == null ? Stream.<CodeSigner>of() : Arrays.stream(signers))
.flatMap(csa->csa.getSignerCertPath().getCertificates().stream())
.findFirst()
.map(LamdbaExceptionUtils.rethrowFunction(Certificate::getEncoded))
.map(bytes->LamdbaExceptionUtils.uncheck(()->MessageDigest.getInstance("SHA-256")).digest(bytes))
.map(StringUtils::binToHex)
.map(str-> String.join(":", str.split("(?<=\\G.{2})")));
if (signers == null)
return Optional.empty();
for (var signer : signers) {
for (var cert : signer.getSignerCertPath().getCertificates()) {
try {
var encoded = cert.getEncoded();
var sha256 = MessageDigest.getInstance("SHA-256");
var digest = sha256.digest(encoded);
var buf = new StringBuilder(digest.length * 3);
for (int x = 0; x < digest.length - 1; x++) {
buf.append(HEX[(digest[x] & 0xF0) >> 4]);
buf.append(HEX[(digest[x] & 0x0F) ]);
buf.append(':');
}
buf.append(HEX[(digest[digest.length - 1] & 0xF0) >> 4]);
buf.append(HEX[(digest[digest.length - 1] & 0x0F) ]);
// We only care about the first. Should we list them all?
return Optional.of(buf.toString());
} catch (CertificateEncodingException | NoSuchAlgorithmException e) {
sneak(e);
}
}
}
return Optional.empty();
}
public Optional<String> getTrustData() {
return Arrays.stream(this.modFile.getSecureJar().getManifestSigners())
.flatMap(csa->csa.getSignerCertPath().getCertificates().stream())
.findFirst()
.map(X509Certificate.class::cast)
.map(c->{
StringBuffer sb = new StringBuffer();
sb.append(c.getSubjectX500Principal().getName(X500Principal.RFC2253).split(",")[0]);
boolean selfSigned = false;
try {
c.verify(c.getPublicKey());
selfSigned = true;
} catch (CertificateException | NoSuchAlgorithmException | InvalidKeyException | SignatureException | NoSuchProviderException e) {
// not self signed
}
if (selfSigned) {
var signers = this.modFile.getSecureJar().getManifestSigners();
if (signers == null)
return Optional.empty();
for (var signer : signers) {
for (var cert : signer.getSignerCertPath().getCertificates()) {
if (!(cert instanceof X509Certificate x509))
continue;
var sb = new StringBuilder();
sb.append(x509.getSubjectX500Principal().getName(X500Principal.RFC2253).split(",")[0]);
var selfSigned = false;
try {
x509.verify(x509.getPublicKey());
selfSigned = true;
} catch (CertificateException | NoSuchAlgorithmException | InvalidKeyException | SignatureException | NoSuchProviderException e) {
// not self signed
}
if (selfSigned)
sb.append(" self-signed");
} else {
sb.append(" signed by ").append(c.getIssuerX500Principal().getName(X500Principal.RFC2253).split(",")[0]);
};
return sb.toString();
});
else
sb.append(" signed by ").append(x509.getIssuerX500Principal().getName(X500Principal.RFC2253).split(",")[0]);
return Optional.of(sb.toString());
}
}
return Optional.empty();
}
@Override
@@ -253,4 +266,9 @@ public class ModFileInfo implements IModFileInfo, IConfigurable
public List<String> usesServices() {
return usesServices;
}
@SuppressWarnings("unchecked")
private static <E extends Throwable, R> R sneak(Throwable e) throws E {
throw (E)e;
}
}
@@ -19,11 +19,11 @@ import org.jetbrains.annotations.ApiStatus;
import org.slf4j.Logger;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.regex.Pattern;
@ApiStatus.Internal
@@ -50,34 +50,39 @@ public class ModInfo implements IModInfo, IConfigurable {
private final IConfigurable config;
private final Optional<URL> modUrl;
public ModInfo(final ModFileInfo owningFile, final IConfigurable config)
{
public ModInfo(final ModFileInfo owningFile, final IConfigurable config) {
Optional<ModFileInfo> ownFile = Optional.ofNullable(owningFile);
this.owningFile = owningFile;
this.config = config;
// These are sourced from the mod specific [[mod]] entry
this.modId = config.<String>getConfigElement("modId")
.orElseThrow(() -> new InvalidModFileException("Missing modId", owningFile));
// verify we have a valid modid
if (!VALID_MODID.matcher(this.modId).matches()) {
LOGGER.error(LogUtils.FATAL_MARKER, "Invalid modId found in file {} - {} does not match the standard: {}", this.owningFile.getFile().getFilePath(), this.modId, VALID_MODID.pattern());
throw new InvalidModFileException("Invalid modId found : " + this.modId, owningFile);
}
this.namespace = config.<String>getConfigElement("namespace")
.orElse(this.modId);
// verify our namespace is valid
if (!VALID_NAMESPACE.matcher(this.namespace).matches()) {
LOGGER.error(LogUtils.FATAL_MARKER, "Invalid override namespace found in file {} - {} does not match the standard: {}", this.owningFile.getFile().getFilePath(), this.namespace, VALID_NAMESPACE.pattern());
throw new InvalidModFileException("Invalid override namespace found : " + this.namespace, owningFile);
}
this.version = config.<String>getConfigElement("version")
.map(s -> StringSubstitutor.replace(s, ownFile.map(ModFileInfo::getFile).orElse(null)))
.map(DefaultArtifactVersion::new)
.orElse(DEFAULT_VERSION);
// verify we have a valid mod version
if (!VALID_VERSION.matcher(this.version.toString()).matches()) {
throw new InvalidModFileException("Illegal version number specified "+this.version, this.getOwningFile());
}
if (!VALID_VERSION.matcher(this.version.toString()).matches())
throw new InvalidModFileException("Illegal version number specified " + this.version, this.getOwningFile());
// The remaining properties all default to sensible values and are not essential
this.displayName = config.<String>getConfigElement("displayName")
.orElse(this.modId);
@@ -88,25 +93,48 @@ public class ModInfo implements IModInfo, IConfigurable {
.orElseGet(() -> ownFile.flatMap(mf -> mf.<String>getConfigElement("logoFile"))
.orElse(null)));
this.logoBlur = config.<Boolean>getConfigElement("logoBlur")
.orElseGet(() -> ownFile.flatMap(f -> f.<Boolean>getConfigElement("logoBlur"))
.orElseGet(() -> ownFile.flatMap(mf -> mf.<Boolean>getConfigElement("logoBlur"))
.orElse(true));
this.updateJSONURL = config.<String>getConfigElement("updateJSONURL")
.map(StringUtils::toURL);
this.modUrl = config.<String>getConfigElement("modUrl")
.map(StringUtils::toURL);
// These are sourced from the file rather than the mod-specific block, but with a modid tag
this.dependencies = ownFile.map(mfi -> mfi.getConfigList("dependencies", this.modId))
.orElse(Collections.emptyList())
.stream()
.map(dep -> new ModVersion(this, dep))
.toList();
this.features = ownFile.flatMap(mfi -> mfi.<Map<String, Object>>getConfigElement("features", this.modId))
.stream()
.flatMap(m->m.entrySet().stream())
.map(this::makeBound)
.toList();
this.properties = ownFile.flatMap(mfi -> mfi.<Map<String, Object>>getConfigElement("modproperties", this.modId))
.orElse(Collections.emptyMap());
if (ownFile.isEmpty()) {
this.dependencies = Collections.emptyList();
this.features = Collections.emptyList();
this.properties = Collections.emptyMap();
} else {
var deps = this.owningFile.getConfigList("dependencies", this.modId);
if (deps == null || deps.isEmpty()) {
this.dependencies = Collections.emptyList();
} else {
var tmp = new ArrayList<ModVersion>();
for (var dep : deps)
tmp.add(new ModVersion(this, dep));
this.dependencies = Collections.unmodifiableList(tmp);
}
var feats = this.owningFile.<Map<String, Object>>getConfigElement("features", this.modId).orElse(null);
if (feats == null) {
this.features = Collections.emptyList();
} else {
var tmp = new ArrayList<ForgeFeature.Bound>();
for (var entry : feats.entrySet()) {
if (!(entry.getValue() instanceof String val))
throw new InvalidModFileException("Invalid feature bound {" + entry.getValue() + "} for key {" + entry.getKey() + "} only strings are accepted", this.owningFile);
tmp.add(new ForgeFeature.Bound(entry.getKey(), val, this));
}
this.features = Collections.unmodifiableList(tmp);
}
var props = this.owningFile.<Map<String, Object>>getConfigElement("modproperties", this.modId).orElse(null);
if (props == null)
this.properties = Collections.emptyMap();
else
this.properties = Collections.unmodifiableMap(props);
}
}
@Override
@@ -120,14 +148,12 @@ public class ModInfo implements IModInfo, IConfigurable {
}
@Override
public String getDisplayName()
{
public String getDisplayName() {
return this.displayName;
}
@Override
public String getDescription()
{
public String getDescription() {
return this.description;
}
@@ -157,14 +183,12 @@ public class ModInfo implements IModInfo, IConfigurable {
}
@Override
public Optional<String> getLogoFile()
{
public Optional<String> getLogoFile() {
return this.logoFile;
}
@Override
public boolean getLogoBlur()
{
public boolean getLogoBlur() {
return this.logoBlur;
}
@@ -193,14 +217,6 @@ public class ModInfo implements IModInfo, IConfigurable {
return modUrl;
}
private ForgeFeature.Bound makeBound(Map.Entry<String, Object> e) {
if (e.getValue() instanceof String val) {
return new ForgeFeature.Bound(e.getKey(), val, this);
} else {
throw new InvalidModFileException("Invalid feature bound {" + e.getValue() + "} for key {" + e.getKey() + "} only strings are accepted", this.owningFile);
}
}
class ModVersion implements net.minecraftforge.forgespi.language.IModInfo.ModVersion {
private IModInfo owner;
private final String modId;
@@ -214,6 +230,7 @@ public class ModInfo implements IModInfo, IConfigurable {
this.owner = owner;
this.modId = config.<String>getConfigElement("modId")
.orElseThrow(()->new InvalidModFileException("Missing required field modid in dependency", getOwningFile()));
if (this.modId.equals("forge")) {
var fileProps = owner.getOwningFile().getFileProperties();
// Checking containsKey to avoid a possible exception if the property is not present (due to Collections.emptyMap())
@@ -223,14 +240,15 @@ public class ModInfo implements IModInfo, IConfigurable {
fileProps.remove(ModFileInfo.NOT_A_FORGE_MOD_PROP);
}
}
var mandatory = config.<Boolean>getConfigElement("mandatory");
if (mandatory.isPresent()) {
if (mandatory.isPresent())
this.mandatory = mandatory.get();
} else if (owner.getOwningFile().getFileProperties().containsKey(ModFileInfo.NOT_A_FORGE_MOD_PROP)) {
else if (owner.getOwningFile().getFileProperties().containsKey(ModFileInfo.NOT_A_FORGE_MOD_PROP))
this.mandatory = true;
} else {
else
throw new InvalidModFileException("Missing required field mandatory in dependency", getOwningFile());
}
this.versionRange = config.<String>getConfigElement("versionRange")
.map(MavenVersionAdapter::createFromVersionSpec)
.orElse(UNBOUNDED);
@@ -244,46 +262,38 @@ public class ModInfo implements IModInfo, IConfigurable {
.map(StringUtils::toURL);
}
@Override
public String getModId()
{
public String getModId() {
return modId;
}
@Override
public VersionRange getVersionRange()
{
public VersionRange getVersionRange() {
return versionRange;
}
@Override
public boolean isMandatory()
{
public boolean isMandatory() {
return mandatory;
}
@Override
public Ordering getOrdering()
{
public Ordering getOrdering() {
return ordering;
}
@Override
public DependencySide getSide()
{
public DependencySide getSide() {
return side;
}
@Override
public void setOwner(final IModInfo owner)
{
public void setOwner(final IModInfo owner) {
this.owner = owner;
}
@Override
public IModInfo getOwner()
{
public IModInfo getOwner() {
return owner;
}
@@ -292,5 +302,4 @@ public class ModInfo implements IModInfo, IConfigurable {
return referralUrl;
}
}
}
@@ -6,6 +6,8 @@
package net.minecraftforge.fml.loading.moddiscovery;
import com.electronwill.nightconfig.core.UnmodifiableConfig;
import com.google.common.collect.ImmutableMap;
import net.minecraftforge.forgespi.language.IConfigurable;
import net.minecraftforge.forgespi.language.IModFileInfo;
@@ -38,8 +40,12 @@ class NightConfigWrapper implements IConfigurable {
public <T> Optional<T> getConfigElement(final String... key) {
var path = asList(key);
return this.config.getOptional(path).map(value -> {
if (value instanceof UnmodifiableConfig) {
return (T) ((UnmodifiableConfig) value).valueMap();
if (value instanceof UnmodifiableConfig cfg) {
// New Night config doesn't implement valueMap(), so do a copy.
var builder = ImmutableMap.builder();
for (var e: cfg.entrySet())
builder.put(e.getKey(), e.getValue());
return (T)builder.build();
} else if (value instanceof ArrayList<?> al && al.size() > 0 && al.get(0) instanceof UnmodifiableConfig) {
throw new InvalidModFileException("The configuration path " + path + " is invalid. I wasn't expecting a multi-object list - remove one of the [[ ]]", file);
}
+5 -5
View File
@@ -5,13 +5,13 @@ org.gradle.daemon=false
org.gradle.parallel=true
JAVA_VERSION=21
MC_VERSION=1.21
MC_NEXT_VERSION=1.21
MCP_VERSION=20240613.102039
MC_VERSION=1.21.1
MC_NEXT_VERSION=1.22
MCP_VERSION=20240808.132146
MAPPING_CHANNEL=official
MAPPING_VERSION=1.21
MAPPING_VERSION=1.21.1
// Set to true before the first build of a new MC version, so we don't do compatibility checks
CHECK_COMPATIBILITY=false
// Set to true to allow for fuzzy patching. Useful during updateing
UPDATING=false
UPDATING=true
@@ -46,7 +46,7 @@ public class Config
private static boolean validateItemName(final Object obj)
{
return obj instanceof final String itemName && ForgeRegistries.ITEMS.containsKey(new ResourceLocation(itemName));
return obj instanceof final String itemName && ForgeRegistries.ITEMS.containsKey(ResourceLocation.tryParse(itemName));
}
@SubscribeEvent
@@ -58,7 +58,7 @@ public class Config
// convert the list of strings into a set of items
items = ITEM_STRINGS.get().stream()
.map(itemName -> ForgeRegistries.ITEMS.getValue(new ResourceLocation(itemName)))
.map(itemName -> ForgeRegistries.ITEMS.getValue(ResourceLocation.tryParse(itemName)))
.collect(Collectors.toSet());
}
}
@@ -70,7 +70,7 @@
this.renderTooltipInternal(p_283128_, list, p_283678_, p_281696_, DefaultTooltipPositioner.INSTANCE);
}
@@ -922,7 +_,15 @@
@@ -922,7 +_,22 @@
}
public void renderComponentTooltip(Font p_282739_, List<Component> p_281832_, int p_282191_, int p_282446_) {
@@ -83,6 +83,13 @@
+ this.tooltipStack = stack;
+ List<ClientTooltipComponent> components = net.minecraftforge.client.ForgeHooksClient.gatherTooltipComponents(stack, tooltips, mouseX, guiWidth(), guiHeight(), font);
+ this.renderTooltipInternal(font, components, mouseX, mouseY, DefaultTooltipPositioner.INSTANCE);
+ this.tooltipStack = ItemStack.EMPTY;
+ }
+
+ public void renderComponentTooltipFromElements(Font font, List<com.mojang.datafixers.util.Either<FormattedText, TooltipComponent>> elements, int mouseX, int mouseY, ItemStack stack) {
+ this.tooltipStack = stack;
+ List<ClientTooltipComponent> components = net.minecraftforge.client.ForgeHooksClient.gatherTooltipComponentsFromElements(stack, elements, mouseX, guiWidth(), guiHeight(), font);
+ this.renderTooltipInternal(font, components, mouseX, mouseY, DefaultTooltipPositioner.INSTANCE);
+ this.tooltipStack = ItemStack.EMPTY;
}
@@ -176,7 +176,7 @@
boolean flag = this.hoveredSlot != null && this.hoveredSlot instanceof CreativeModeInventoryScreen.CustomCreativeSlot;
boolean flag1 = selectedTab.getType() == CreativeModeTab.Type.CATEGORY;
- boolean flag2 = selectedTab.getType() == CreativeModeTab.Type.SEARCH;
+ boolean flag2 =selectedTab.hasSearchBar();
+ boolean flag2 = selectedTab.hasSearchBar();
TooltipFlag.Default tooltipflag$default = this.minecraft.options.advancedItemTooltips ? TooltipFlag.Default.ADVANCED : TooltipFlag.Default.NORMAL;
TooltipFlag tooltipflag = flag ? tooltipflag$default.asCreative() : tooltipflag$default;
List<Component> list = p_281769_.getTooltipLines(Item.TooltipContext.of(this.minecraft.level), this.minecraft.player, tooltipflag);
@@ -11,21 +11,23 @@
private CompletableFuture<SearchTree<RecipeCollection>> recipeSearch = CompletableFuture.completedFuture(SearchTree.empty());
private final Map<SessionSearchTrees.Key, Runnable> reloaders = new IdentityHashMap<>();
@@ -82,44 +_,50 @@
@@ -82,44 +_,52 @@
}
public void updateCreativeTags(List<ItemStack> p_344581_) {
+ for (var name : net.minecraftforge.client.CreativeModeTabSearchRegistry.getTagSearchKeys().values())
+ for (var entry : net.minecraftforge.client.CreativeModeTabSearchRegistry.getTagSearchKeys().entrySet())
this.register(
- CREATIVE_TAGS,
+ name,
+ entry.getValue(),
() -> {
- CompletableFuture<?> completablefuture = this.creativeByTagSearch;
- this.creativeByTagSearch = CompletableFuture.supplyAsync(
+ CompletableFuture<?> completablefuture = this.creativeSearch.getOrDefault(name, EMPTY);
+ this.creativeSearch.put(name, CompletableFuture.supplyAsync(
() -> new IdSearchTree<>(p_342206_ -> p_342206_.getTags().map(TagKey::location), p_344581_), Util.backgroundExecutor()
- () -> new IdSearchTree<>(p_342206_ -> p_342206_.getTags().map(TagKey::location), p_344581_), Util.backgroundExecutor()
- );
+ var items = entry.getKey() == net.minecraft.world.item.CreativeModeTabs.searchTab() ? p_344581_ : List.copyOf(entry.getKey().getDisplayItems());
+ CompletableFuture<?> completablefuture = this.creativeSearch.getOrDefault(entry.getValue(), EMPTY);
+ this.creativeSearch.put(entry.getValue(), CompletableFuture.supplyAsync(
+ () -> new IdSearchTree<>(p_342206_ -> p_342206_.getTags().map(TagKey::location), items), Util.backgroundExecutor()
+ ));
completablefuture.cancel(true);
}
@@ -38,21 +40,23 @@
}
public void updateCreativeTooltips(HolderLookup.Provider p_343364_, List<ItemStack> p_342500_) {
+ for (var name : net.minecraftforge.client.CreativeModeTabSearchRegistry.getNameSearchKeys().values())
+ for (var entry : net.minecraftforge.client.CreativeModeTabSearchRegistry.getNameSearchKeys().entrySet())
this.register(
- CREATIVE_NAMES,
+ name,
+ entry.getValue(),
() -> {
+ var items = entry.getKey() == net.minecraft.world.item.CreativeModeTabs.searchTab() ? p_342500_ : List.copyOf(entry.getKey().getDisplayItems());
Item.TooltipContext item$tooltipcontext = Item.TooltipContext.of(p_343364_);
TooltipFlag tooltipflag = TooltipFlag.Default.NORMAL.asCreative();
- CompletableFuture<?> completablefuture = this.creativeByNameSearch;
- this.creativeByNameSearch = CompletableFuture.supplyAsync(
+ CompletableFuture<?> completablefuture = this.creativeSearch.getOrDefault(name, EMPTY);
+ this.creativeSearch.put(name, CompletableFuture.supplyAsync(
+ CompletableFuture<?> completablefuture = this.creativeSearch.getOrDefault(entry.getValue(), EMPTY);
+ this.creativeSearch.put(entry.getValue(), CompletableFuture.supplyAsync(
() -> new FullTextSearchTree<>(
p_345254_ -> getTooltipLines(Stream.of(p_345254_), item$tooltipcontext, tooltipflag),
p_344415_ -> p_344415_.getItemHolder().unwrapKey().map(ResourceKey::location).stream(),
p_342500_
- p_342500_
+ items
),
Util.backgroundExecutor()
- );
@@ -123,13 +123,13 @@
profilerfiller.popPush("outline");
BlockPos blockpos1 = ((BlockHitResult)hitresult).getBlockPos();
BlockState blockstate = this.level.getBlockState(blockpos1);
+ if (!net.minecraftforge.client.ForgeHooksClient.onDrawHighlight(this, p_109604_, hitresult, f, p_254120_, multibuffersource$buffersource))
+ if (!net.minecraftforge.client.ForgeHooksClient.onDrawHighlight(this, p_109604_, hitresult, f, posestack, multibuffersource$buffersource))
if (!blockstate.isAir() && this.level.getWorldBorder().isWithinBounds(blockpos1)) {
VertexConsumer vertexconsumer2 = multibuffersource$buffersource.getBuffer(RenderType.lines());
this.renderHitOutline(posestack, vertexconsumer2, p_109604_.getEntity(), d0, d1, d2, blockpos1, blockstate);
}
+ } else if (hitresult != null && hitresult.getType() == HitResult.Type.ENTITY) {
+ net.minecraftforge.client.ForgeHooksClient.onDrawHighlight(this, p_109604_, hitresult, f, p_254120_, multibuffersource$buffersource);
+ net.minecraftforge.client.ForgeHooksClient.onDrawHighlight(this, p_109604_, hitresult, f, posestack, multibuffersource$buffersource);
}
this.minecraft.debugRenderer.render(posestack, multibuffersource$buffersource, d0, d1, d2);
@@ -139,7 +139,7 @@
profilerfiller.popPush("particles");
- this.minecraft.particleEngine.render(p_109606_, p_109604_, f);
+ this.minecraft.particleEngine.render(p_109606_, p_109604_, f, frustum);
+ net.minecraftforge.client.event.RenderLevelStageEvent.Stage.AFTER_PARTICLES.dispatch(this, p_254120_, p_254120_, this.ticks, p_109604_, frustum);
+ net.minecraftforge.client.event.RenderLevelStageEvent.Stage.AFTER_PARTICLES.dispatch(this, posestack.last().pose(), p_254120_, this.ticks, p_109604_, frustum);
RenderStateShard.PARTICLES_TARGET.clearRenderState();
} else {
profilerfiller.popPush("translucent");
@@ -149,7 +149,7 @@
profilerfiller.popPush("particles");
- this.minecraft.particleEngine.render(p_109606_, p_109604_, f);
+ this.minecraft.particleEngine.render(p_109606_, p_109604_, f, frustum);
+ net.minecraftforge.client.event.RenderLevelStageEvent.Stage.AFTER_PARTICLES.dispatch(this, p_254120_, p_254120_, this.ticks, p_109604_, frustum);
+ net.minecraftforge.client.event.RenderLevelStageEvent.Stage.AFTER_PARTICLES.dispatch(this, posestack.last().pose(), p_254120_, this.ticks, p_109604_, frustum);
}
if (this.minecraft.options.getCloudsType() != CloudStatus.OFF) {
@@ -7,7 +7,7 @@
- if (this.shouldShowName(p_114485_)) {
- this.renderNameTag(p_114485_, p_114485_.getDisplayName(), p_114488_, p_114489_, p_114490_, p_114487_);
+ var event = net.minecraftforge.client.event.ForgeEventFactoryClient.fireRenderNameTagEvent(p_114485_, p_114485_.getDisplayName(), this, p_114488_, p_114489_, p_114490_, p_114487_);
+ if (event.getResult() != net.minecraftforge.eventbus.api.Event.Result.DENY && (event.getResult() == net.minecraftforge.eventbus.api.Event.Result.ALLOW || this.shouldShowName(p_114485_))) {
+ if (!event.getResult().isDenied() && (event.getResult().isAllowed() || this.shouldShowName(p_114485_))) {
+ this.renderNameTag(p_114485_, event.getContent(), p_114488_, p_114489_, p_114490_, p_114487_);
}
}
@@ -1,11 +1,12 @@
--- a/net/minecraft/client/renderer/entity/FallingBlockRenderer.java
+++ b/net/minecraft/client/renderer/entity/FallingBlockRenderer.java
@@ -34,20 +_,25 @@
@@ -34,20 +_,26 @@
p_114637_.pushPose();
BlockPos blockpos = BlockPos.containing(p_114634_.getX(), p_114634_.getBoundingBox().maxY, p_114634_.getZ());
p_114637_.translate(-0.5, 0.0, -0.5);
+ var model = this.dispatcher.getBlockModel(blockstate);
+ for (var renderType : model.getRenderTypes(blockstate, RandomSource.create(blockstate.getSeed(p_114634_.getStartPos())), net.minecraftforge.client.model.data.ModelData.EMPTY)) {
+ renderType = net.minecraftforge.client.RenderTypeHelper.getMovingBlockRenderType(renderType);
this.dispatcher
.getModelRenderer()
.tesselateBlock(
@@ -1,10 +1,10 @@
--- a/net/minecraft/commands/arguments/EntityArgument.java
+++ b/net/minecraft/commands/arguments/EntityArgument.java
@@ -115,7 +_,7 @@
@@ -123,7 +_,7 @@
if (p_91482_.getSource() instanceof SharedSuggestionProvider sharedsuggestionprovider) {
StringReader stringreader = new StringReader(p_91483_.getInput());
stringreader.setCursor(p_91483_.getStart());
- EntitySelectorParser entityselectorparser = new EntitySelectorParser(stringreader, sharedsuggestionprovider.hasPermission(2));
- EntitySelectorParser entityselectorparser = new EntitySelectorParser(stringreader, EntitySelectorParser.allowSelectors(sharedsuggestionprovider));
+ EntitySelectorParser entityselectorparser = new EntitySelectorParser(stringreader, net.minecraftforge.common.ForgeHooks.canUseEntitySelectors(sharedsuggestionprovider));
try {
@@ -1,10 +1,10 @@
--- a/net/minecraft/commands/arguments/MessageArgument.java
+++ b/net/minecraft/commands/arguments/MessageArgument.java
@@ -84,7 +_,7 @@
@@ -89,7 +_,7 @@
public static record Message(String text, MessageArgument.Part[] parts) {
Component resolveComponent(CommandSourceStack p_232197_) throws CommandSyntaxException {
- return this.toComponent(p_232197_, p_232197_.hasPermission(2));
- return this.toComponent(p_232197_, EntitySelectorParser.allowSelectors(p_232197_));
+ return this.toComponent(p_232197_, net.minecraftforge.common.ForgeHooks.canUseEntitySelectors(p_232197_));
}
@@ -1,6 +1,6 @@
--- a/net/minecraft/commands/arguments/selector/EntitySelectorParser.java
+++ b/net/minecraft/commands/arguments/selector/EntitySelectorParser.java
@@ -472,6 +_,11 @@
@@ -477,6 +_,11 @@
}
this.reader.skip();
@@ -12,7 +12,7 @@
this.parseSelector();
} else {
this.parseNameOrUUID();
@@ -488,6 +_,7 @@
@@ -493,6 +_,7 @@
p_121248_.suggest("@s", Component.translatable("argument.entity.selector.self"));
p_121248_.suggest("@e", Component.translatable("argument.entity.selector.allEntities"));
p_121248_.suggest("@n", Component.translatable("argument.entity.selector.nearestEntity"));
@@ -0,0 +1,16 @@
--- a/net/minecraft/core/RegistrySynchronization.java
+++ b/net/minecraft/core/RegistrySynchronization.java
@@ -19,10 +_,11 @@
import net.minecraft.server.packs.repository.KnownPack;
public class RegistrySynchronization {
- public static final Set<ResourceKey<? extends Registry<?>>> NETWORKABLE_REGISTRIES = RegistryDataLoader.SYNCHRONIZED_REGISTRIES
+ public static final Set<ResourceKey<? extends Registry<?>>> NETWORKABLE_REGISTRIES = net.minecraftforge.registries.DataPackRegistriesHooks.grabNetworkableRegistries(() -> RegistryDataLoader.SYNCHRONIZED_REGISTRIES
.stream()
.map(RegistryDataLoader.RegistryData::key)
- .collect(Collectors.toUnmodifiableSet());
+ .collect(Collectors.toUnmodifiableSet())
+ );
public static void packRegistries(
DynamicOps<Tag> p_330752_,
@@ -39,6 +39,15 @@
);
return dataresult.map(p_326149_ -> Pair.of((HolderSet<E>)p_326149_, (T)p_326147_.getSecond()));
}
@@ -90,7 +_,7 @@
}
private <T> DataResult<Pair<HolderSet<E>, T>> decodeWithoutRegistry(DynamicOps<T> p_206671_, T p_206672_) {
- return this.elementCodec.listOf().decode(p_206671_, p_206672_).flatMap(p_206666_ -> {
+ return this.homogenousListCodec.decode(p_206671_, p_206672_).flatMap(p_206666_ -> { // Forge: Match encodeWithoutRegistry's use of the homogenousListCodec
List<Holder.Direct<E>> list = new ArrayList<>();
for (Holder<E> holder : p_206666_.getFirst()) {
@@ -106,6 +_,9 @@
}
@@ -9,6 +9,15 @@
new RegistryDataLoader.RegistryData<>(Registries.DIMENSION_TYPE, DimensionType.DIRECT_CODEC),
new RegistryDataLoader.RegistryData<>(Registries.BIOME, Biome.DIRECT_CODEC),
new RegistryDataLoader.RegistryData<>(Registries.CHAT_TYPE, ChatType.DIRECT_CODEC),
@@ -100,7 +_,7 @@
public static final List<RegistryDataLoader.RegistryData<?>> DIMENSION_REGISTRIES = List.of(
new RegistryDataLoader.RegistryData<>(Registries.LEVEL_STEM, LevelStem.CODEC)
);
- public static final List<RegistryDataLoader.RegistryData<?>> SYNCHRONIZED_REGISTRIES = List.of(
+ public static final List<RegistryDataLoader.RegistryData<?>> SYNCHRONIZED_REGISTRIES = net.minecraftforge.registries.DataPackRegistriesHooks.grabSynchronizedRegistries(
new RegistryDataLoader.RegistryData<>(Registries.BIOME, Biome.NETWORK_CODEC),
new RegistryDataLoader.RegistryData<>(Registries.CHAT_TYPE, ChatType.DIRECT_CODEC),
new RegistryDataLoader.RegistryData<>(Registries.TRIM_PATTERN, TrimPattern.DIRECT_CODEC),
@@ -114,6 +_,10 @@
new RegistryDataLoader.RegistryData<>(Registries.JUKEBOX_SONG, JukeboxSong.DIRECT_CODEC)
);
@@ -40,17 +49,26 @@
RegistryOps<JsonElement> p_332135_,
ResourceKey<E> p_332850_,
Resource p_335244_,
@@ -208,7 +_,14 @@
@@ -208,7 +_,23 @@
) throws IOException {
try (Reader reader = p_335244_.openAsReader()) {
JsonElement jsonelement = JsonParser.parseReader(reader);
- DataResult<E> dataresult = p_333909_.parse(p_332135_, jsonelement);
+
+ var result = p_333909_.decode(p_332135_, jsonelement);
+ if (result.result().map(p -> p.getFirst()).isEmpty()) {
+ LOGGER.debug("Skipping {} conditions not met", p_332850_);
+ return;
+
+ if (result.isError()) {
+ LOGGER.error("Couldn't parse data file {}: {}", p_332850_, result.error().get().message());
+ throw new IllegalStateException("Couldn't parse data file " + p_332850_ + ": " + result.error().get().message());
+ }
+
+ var mappedResult = result.result().map(a -> a.getFirst());
+
+ if (mappedResult.get().isEmpty()) {
+ LOGGER.debug("Skipping {} conditions not met", p_332850_);
+ return;
+ }
+
+ DataResult<E> dataresult = result.map(p -> p.mapFirst(Optional::get)).map(p -> p.getFirst());
+
E e = dataresult.getOrThrow();
@@ -5,7 +5,7 @@
public void handleBlockBreakAction(BlockPos p_215120_, ServerboundPlayerActionPacket.Action p_215121_, Direction p_215122_, int p_215123_, int p_215124_) {
+ var event = net.minecraftforge.event.ForgeEventFactory.onLeftClickBlock(player, p_215120_, p_215122_, p_215121_);
+ if (event.isCanceled() || (!this.isCreative() && event.getResult() == net.minecraftforge.eventbus.api.Event.Result.DENY)) {
+ if (event.isCanceled() || (!this.isCreative() && event.getResult().isDenied())) {
+ return;
+ }
if (!this.player.canInteractWithBlock(p_215120_, 1.0)) {
@@ -228,7 +228,7 @@
}
+ p_20241_.putBoolean("CanUpdate", canUpdate);
+ CompoundTag caps = serializeCaps();
+ CompoundTag caps = serializeCaps(this.registryAccess());
+ if (caps != null) p_20241_.put("ForgeCaps", caps);
+ if (persistentData != null) p_20241_.put("ForgeData", persistentData.copy());
+
@@ -241,7 +241,7 @@
this.hasVisualFire = p_20259_.getBoolean("HasVisualFire");
+ if (p_20259_.contains("ForgeData", 10)) persistentData = p_20259_.getCompound("ForgeData");
+ if (p_20259_.contains("CanUpdate", 99)) this.canUpdate(p_20259_.getBoolean("CanUpdate"));
+ if (p_20259_.contains("ForgeCaps", 10)) deserializeCaps(p_20259_.getCompound("ForgeCaps"));
+ if (p_20259_.contains("ForgeCaps", 10)) deserializeCaps(this.registryAccess(), p_20259_.getCompound("ForgeCaps"));
if (p_20259_.contains("Tags", 9)) {
this.tags.clear();
ListTag listtag3 = p_20259_.getList("Tags", 8);
@@ -121,9 +121,9 @@
}
public boolean canBeAffected(MobEffectInstance p_21197_) {
+ var event = net.minecraftforge.event.ForgeEventFactory.onLivingEffectCanApply(this, p_21197_);
+ if (event.getResult() != net.minecraftforge.eventbus.api.Event.Result.DEFAULT) {
+ return event.getResult() == net.minecraftforge.eventbus.api.Event.Result.ALLOW;
+ var eventResult = net.minecraftforge.event.ForgeEventFactory.onLivingEffectCanApply(this, p_21197_).getResult();
+ if (!eventResult.isDefault()) {
+ return eventResult.isAllowed();
+ }
if (this.getType().is(EntityTypeTags.IMMUNE_TO_INFESTED)) {
return !p_21197_.is(MobEffects.INFESTED);
@@ -1,10 +1,18 @@
--- a/net/minecraft/world/entity/Shearable.java
+++ b/net/minecraft/world/entity/Shearable.java
@@ -2,6 +_,7 @@
@@ -2,8 +_,14 @@
import net.minecraft.sounds.SoundSource;
+/** @deprecated Use {@link net.minecraftforge.common.IForgeShearable} */
public interface Shearable {
-public interface Shearable {
+public interface Shearable extends net.minecraftforge.common.IForgeShearable {
+ /** @deprecated Use {@link net.minecraftforge.common.IForgeShearable#onSheared} */
void shear(SoundSource p_21749_);
+ /** @deprecated Use {@link net.minecraftforge.common.IForgeShearable#isShearable} */
boolean readyForShearing();
+
+ default boolean isShearable(net.minecraft.world.item.ItemStack item, net.minecraft.world.level.Level level, net.minecraft.core.BlockPos pos) {
+ return readyForShearing();
+ }
}
@@ -1,14 +1,5 @@
--- a/net/minecraft/world/entity/animal/MushroomCow.java
+++ b/net/minecraft/world/entity/animal/MushroomCow.java
@@ -42,7 +_,7 @@
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.gameevent.GameEvent;
-public class MushroomCow extends Cow implements Shearable, VariantHolder<MushroomCow.MushroomType> {
+public class MushroomCow extends Cow implements Shearable, VariantHolder<MushroomCow.MushroomType>, net.minecraftforge.common.IForgeShearable {
private static final EntityDataAccessor<String> DATA_TYPE = SynchedEntityData.defineId(MushroomCow.class, EntityDataSerializers.STRING);
private static final int MUTATE_CHANCE = 1024;
private static final String TAG_STEW_EFFECTS = "stew_effects";
@@ -108,7 +_,7 @@
this.playSound(soundevent, 1.0F, 1.0F);
@@ -55,7 +46,7 @@
}
@Override
@@ -255,6 +_,17 @@
@@ -255,6 +_,12 @@
}
return mushroomcow$mushroomtype2;
@@ -65,11 +56,6 @@
+ public java.util.List<ItemStack> onSheared(@org.jetbrains.annotations.Nullable Player player, @org.jetbrains.annotations.NotNull ItemStack item, Level world, BlockPos pos, int fortune) {
+ this.gameEvent(GameEvent.SHEAR, player);
+ return shearInternal(player == null ? SoundSource.BLOCKS : SoundSource.PLAYERS);
+ }
+
+ @Override
+ public boolean isShearable(ItemStack item, Level world, BlockPos pos) {
+ return readyForShearing();
}
public static enum MushroomType implements StringRepresentable {
@@ -1,14 +1,5 @@
--- a/net/minecraft/world/entity/animal/Sheep.java
+++ b/net/minecraft/world/entity/animal/Sheep.java
@@ -61,7 +_,7 @@
import net.minecraft.world.level.storage.loot.BuiltInLootTables;
import net.minecraft.world.level.storage.loot.LootTable;
-public class Sheep extends Animal implements Shearable {
+public class Sheep extends Animal implements Shearable, net.minecraftforge.common.IForgeShearable {
private static final int EAT_ANIMATION_TICKS = 40;
private static final EntityDataAccessor<Byte> DATA_WOOL_ID = SynchedEntityData.defineId(Sheep.class, EntityDataSerializers.BYTE);
private static final Map<DyeColor, ItemLike> ITEM_BY_DYE = Util.make(Maps.newEnumMap(DyeColor.class), p_29841_ -> {
@@ -212,7 +_,7 @@
@Override
public InteractionResult mobInteract(Player p_29853_, InteractionHand p_29854_) {
@@ -44,18 +35,13 @@
if (itementity != null) {
itementity.setDeltaMovement(
itementity.getDeltaMovement()
@@ -366,5 +_,15 @@
@@ -366,5 +_,10 @@
private static CraftingInput makeCraftInput(DyeColor p_344668_, DyeColor p_344678_) {
return CraftingInput.of(2, 1, List.of(new ItemStack(DyeItem.byColor(p_344668_)), new ItemStack(DyeItem.byColor(p_344678_))));
+ }
+
+ @Override
+ public boolean isShearable(@org.jetbrains.annotations.NotNull ItemStack item, Level world, BlockPos pos) {
+ return readyForShearing();
+ }
+
+ @Override
+ public java.util.List<ItemStack> onSheared(@Nullable Player player, ItemStack item, Level world, BlockPos pos, int fortune) {
+ return shearInternal(player == null ? SoundSource.BLOCKS : SoundSource.PLAYERS);
}
@@ -36,16 +36,11 @@
this.shear(SoundSource.PLAYERS);
this.gameEvent(GameEvent.SHEAR, p_29920_);
if (!this.level().isClientSide) {
@@ -189,4 +_,21 @@
@@ -189,4 +_,16 @@
public Vec3 getLeashOffset() {
return new Vec3(0.0, (double)(0.75F * this.getEyeHeight()), (double)(this.getBbWidth() * 0.4F));
}
+
+ @Override
+ public boolean isShearable(@org.jetbrains.annotations.NotNull ItemStack item, Level world, BlockPos pos) {
+ return readyForShearing();
+ }
+
+ @org.jetbrains.annotations.NotNull
+ @Override
+ public java.util.List<ItemStack> onSheared(@Nullable Player player, @org.jetbrains.annotations.NotNull ItemStack item, Level world, BlockPos pos, int fortune) {
@@ -1,5 +1,33 @@
--- a/net/minecraft/world/entity/animal/Wolf.java
+++ b/net/minecraft/world/entity/animal/Wolf.java
@@ -87,7 +_,7 @@
import net.minecraft.world.level.pathfinder.PathType;
import net.minecraft.world.phys.Vec3;
-public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder<Holder<WolfVariant>> {
+public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder<Holder<WolfVariant>>, net.minecraftforge.common.IForgeShearable {
private static final EntityDataAccessor<Boolean> DATA_INTERESTED_ID = SynchedEntityData.defineId(Wolf.class, EntityDataSerializers.BOOLEAN);
private static final EntityDataAccessor<Integer> DATA_COLLAR_COLOR = SynchedEntityData.defineId(Wolf.class, EntityDataSerializers.INT);
private static final EntityDataAccessor<Integer> DATA_REMAINING_ANGER_TIME = SynchedEntityData.defineId(Wolf.class, EntityDataSerializers.INT);
@@ -448,16 +_,11 @@
this.setBodyArmorItem(itemstack.copyWithCount(1));
itemstack.consume(1, p_30412_);
return InteractionResult.SUCCESS;
- } else if (itemstack.is(Items.SHEARS)
+ } else if (itemstack.canPerformAction(net.minecraftforge.common.ToolActions.SHEARS_HARVEST)
&& this.isOwnedBy(p_30412_)
&& this.hasArmor()
&& (!EnchantmentHelper.has(this.getBodyArmorItem(), EnchantmentEffectComponents.PREVENT_ARMOR_CHANGE) || p_30412_.isCreative())) {
- itemstack.hurtAndBreak(1, p_30412_, getSlotForHand(p_30413_));
- this.playSound(SoundEvents.ARMOR_UNEQUIP_WOLF);
- ItemStack itemstack1 = this.getBodyArmorItem();
- this.setBodyArmorItem(ItemStack.EMPTY);
- this.spawnAtLocation(itemstack1);
- return InteractionResult.SUCCESS;
+ return InteractionResult.PASS;
} else if (ArmorMaterials.ARMADILLO.value().repairIngredient().get().test(itemstack)
&& this.isInSittingPose()
&& this.hasArmor()
@@ -496,7 +_,7 @@
}
@@ -9,3 +37,28 @@
this.tame(p_336244_);
this.navigation.stop();
this.setTarget(null);
@@ -648,6 +_,24 @@
return true;
}
+ }
+
+ @Override
+ public boolean isShearable(ItemStack item, Level world, BlockPos pos) {
+ return this.hasArmor();
+ }
+
+ @Override
+ public java.util.List<ItemStack> onSheared(@org.jetbrains.annotations.Nullable Player player, @org.jetbrains.annotations.NotNull ItemStack item, Level world, BlockPos pos, int fortune) {
+ if (!this.hasArmor() || (player != null && !this.isOwnedBy(player)) ||
+ (EnchantmentHelper.has(this.getBodyArmorItem(), EnchantmentEffectComponents.PREVENT_ARMOR_CHANGE) && (player == null || !player.isCreative()))
+ )
+ return java.util.Collections.emptyList();
+
+ this.playSound(SoundEvents.ARMOR_UNEQUIP_WOLF);
+ var armor = this.getBodyArmorItem();
+ this.setBodyArmorItem(ItemStack.EMPTY);
+ return java.util.List.of(armor);
}
@Override
@@ -0,0 +1,49 @@
--- a/net/minecraft/world/entity/monster/Bogged.java
+++ b/net/minecraft/world/entity/monster/Bogged.java
@@ -74,7 +_,7 @@
@Override
protected InteractionResult mobInteract(Player p_335303_, InteractionHand p_335145_) {
ItemStack itemstack = p_335303_.getItemInHand(p_335145_);
- if (itemstack.is(Items.SHEARS) && this.readyForShearing()) {
+ if (false && itemstack.is(Items.SHEARS) && this.readyForShearing()) { // Forge: move to onSheared
this.shear(SoundSource.PLAYERS);
this.gameEvent(GameEvent.SHEAR, p_335303_);
if (!this.level().isClientSide) {
@@ -129,12 +_,20 @@
@Override
public void shear(SoundSource p_332421_) {
- this.level().playSound(null, this, SoundEvents.BOGGED_SHEAR, p_332421_, 1.0F, 1.0F);
- this.spawnShearedMushrooms();
+ shearInternal(p_332421_).stream().forEach(stack -> this.spawnAtLocation(stack, this.getBbHeight()));
+ }
+
+ @Override
+ public java.util.List<ItemStack> onSheared(@org.jetbrains.annotations.Nullable Player player, @org.jetbrains.annotations.NotNull ItemStack item, Level world, net.minecraft.core.BlockPos pos, int fortune) {
+ this.gameEvent(GameEvent.SHEAR, player);
+ return shearInternal(player == null ? SoundSource.BLOCKS : SoundSource.PLAYERS);
+ }
+
+ private java.util.List<ItemStack> shearInternal(SoundSource sound) {
+ this.level().playSound(null, this, SoundEvents.BOGGED_SHEAR, sound, 1.0F, 1.0F);
this.setSheared(true);
- }
- private void spawnShearedMushrooms() {
+ var ret = new java.util.ArrayList<ItemStack>();
if (this.level() instanceof ServerLevel serverlevel) {
LootTable loottable = serverlevel.getServer().reloadableRegistries().getLootTable(BuiltInLootTables.BOGGED_SHEAR);
LootParams lootparams = new LootParams.Builder(serverlevel)
@@ -143,9 +_,11 @@
.create(LootContextParamSets.SHEARING);
for (ItemStack itemstack : loottable.getRandomItems(lootparams)) {
- this.spawnAtLocation(itemstack, this.getBbHeight());
+ ret.add(itemstack);
}
}
+
+ return ret;
}
@Override
@@ -1,14 +1,12 @@
--- a/net/minecraft/world/entity/monster/Spider.java
+++ b/net/minecraft/world/entity/monster/Spider.java
@@ -121,7 +_,12 @@
@@ -121,7 +_,10 @@
@Override
public boolean canBeAffected(MobEffectInstance p_33809_) {
- return p_33809_.is(MobEffects.POISON) ? false : super.canBeAffected(p_33809_);
+ if (p_33809_.getEffect() == MobEffects.POISON) {
+ net.minecraftforge.event.entity.living.MobEffectEvent.Applicable event = new net.minecraftforge.event.entity.living.MobEffectEvent.Applicable(this, p_33809_);
+ net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(event);
+ return event.getResult() == net.minecraftforge.eventbus.api.Event.Result.ALLOW;
+ return net.minecraftforge.event.ForgeEventFactory.onLivingEffectCanApply(this, p_33809_).getResult().isAllowed();
+ }
+ return super.canBeAffected(p_33809_);
}
@@ -36,9 +36,9 @@
+ var event = net.minecraftforge.event.ForgeEventFactory.fireZombieSummonAid(this, level(), i, j, k, livingentity, this.getAttributeValue(Attributes.SPAWN_REINFORCEMENTS_CHANCE));
+
+ Zombie zombie = null;
+ if (event.getResult() == net.minecraftforge.eventbus.api.Event.Result.ALLOW) {
+ if (event.getResult().isAllowed()) {
+ zombie = event.getCustomSummonedAid() != null ? event.getCustomSummonedAid() : EntityType.ZOMBIE.create(this.level());
+ } else if (event.getResult() == net.minecraftforge.eventbus.api.Event.Result.DEFAULT && vanilla) {
+ } else if (vanilla && event.getResult().isDefault()) {
+ zombie = EntityType.ZOMBIE.create(this.level());
+ }
+
@@ -224,6 +224,17 @@
if (livingentity2 != this
&& livingentity2 != p_36347_
&& !this.isAlliedTo(livingentity2)
@@ -1262,8 +_,8 @@
this.setLastHurtMob(p_36347_);
Entity entity = p_36347_;
- if (p_36347_ instanceof EnderDragonPart) {
- entity = ((EnderDragonPart)p_36347_).parentMob;
+ if (p_36347_ instanceof net.minecraftforge.entity.PartEntity<?> pe) {
+ entity = pe.getParent();
}
boolean flag5 = false;
@@ -1304,6 +_,7 @@
this.level().playSound(null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_NODAMAGE, this.getSoundSource(), 1.0F, 1.0F);
}
@@ -63,20 +63,3 @@
}
protected int getMaxPassengers() {
@@ -904,6 +_,16 @@
@Override
public ItemStack getPickResult() {
return new ItemStack(this.getDropItem());
+ }
+
+ // Forge: Fix MC-119811 by instantly completing lerp on board
+ @Override
+ protected void addPassenger(Entity passenger) {
+ super.addPassenger(passenger);
+ if (this.isControlledByLocalInstance() && this.lerpSteps > 0) {
+ this.lerpSteps = 0;
+ this.absMoveTo(this.lerpX, this.lerpY, this.lerpZ, (float)this.lerpYRot, (float)this.lerpXRot);
+ }
}
public static enum Status {
@@ -118,8 +118,8 @@
+ */
+ public CreativeModeTab.Builder withSearchBar() {
+ this.hasSearchBar = true;
+ if (this.backgroundTexture == null)
+ return this.backgroundTexture(createTextureLocation("item_seach"));
+ if (this.backgroundTexture == CreativeModeTab.DEFAULT_BACKGROUND)
+ return this.backgroundTexture(createTextureLocation("item_search"));
+ return this;
+ }
+
@@ -68,10 +68,18 @@
return p_41436_.clip(new ClipContext(vec3, vec31, ClipContext.Block.OUTLINE, p_41438_, p_41437_));
}
+ @Deprecated // Use ItemStack sensitive version.
+ /** @deprecated in favor of {@link net.minecraftforge.common.extensions.IForgeItem#getEnchantmentValue(ItemStack)} */
public int getEnchantmentValue() {
return 0;
}
@@ -305,6 +_,7 @@
return false;
}
+ /** @deprecated in favor of {@link net.minecraftforge.common.extensions.IForgeItem#getDefaultAttributeModifiers(ItemStack)} */
@Deprecated
public ItemAttributeModifiers getDefaultAttributeModifiers() {
return ItemAttributeModifiers.EMPTY;
@@ -338,6 +_,30 @@
public FeatureFlagSet requiredFeatures() {
return this.requiredFeatures;
@@ -57,6 +57,24 @@
return list;
}
}
@@ -923,7 +_,7 @@
if (!itemattributemodifiers.modifiers().isEmpty()) {
itemattributemodifiers.forEach(p_344758_, p_342345_);
} else {
- this.getItem().getDefaultAttributeModifiers().forEach(p_344758_, p_342345_);
+ this.getDefaultAttributeModifiers().forEach(p_344758_, p_342345_);
}
EnchantmentHelper.forEachModifier(this, p_344758_, p_342345_);
@@ -934,7 +_,7 @@
if (!itemattributemodifiers.modifiers().isEmpty()) {
itemattributemodifiers.forEach(p_331036_, p_334430_);
} else {
- this.getItem().getDefaultAttributeModifiers().forEach(p_331036_, p_334430_);
+ this.getItem().getAttributeModifiers(p_331036_, this).forEach(p_331036_, p_334430_);
}
EnchantmentHelper.forEachModifier(this, p_331036_, p_334430_);
@@ -1011,6 +_,7 @@
this.getItem().onUseTick(p_41732_, p_41733_, this, p_41734_);
}
@@ -1,6 +1,6 @@
--- a/net/minecraft/world/item/ShearsItem.java
+++ b/net/minecraft/world/item/ShearsItem.java
@@ -79,4 +_,32 @@
@@ -79,4 +_,33 @@
return super.useOn(p_186371_);
}
@@ -21,7 +21,8 @@
+ var ent = entity.spawnAtLocation(d, 1.0F);
+ ent.setDeltaMovement(ent.getDeltaMovement().add((double)((rand.nextFloat() - rand.nextFloat()) * 0.1F), (double)(rand.nextFloat() * 0.05F), (double)((rand.nextFloat() - rand.nextFloat()) * 0.1F)));
+ });
+ stack.hurtAndBreak(1, playerIn, LivingEntity.getSlotForHand(hand));
+ if (!drops.isEmpty())
+ stack.hurtAndBreak(1, playerIn, LivingEntity.getSlotForHand(hand));
+ }
+ return InteractionResult.SUCCESS;
+ }
@@ -1,5 +1,14 @@
--- a/net/minecraft/world/level/block/CropBlock.java
+++ b/net/minecraft/world/level/block/CropBlock.java
@@ -54,7 +_,7 @@
@Override
protected boolean mayPlaceOn(BlockState p_52302_, BlockGetter p_52303_, BlockPos p_52304_) {
- return p_52302_.is(Blocks.FARMLAND);
+ return p_52302_.getBlock() instanceof net.minecraft.world.level.block.FarmBlock;
}
protected IntegerProperty getAgeProperty() {
@@ -88,8 +_,9 @@
int i = this.getAge(p_221050_);
if (i < this.getMaxAge()) {
@@ -7,7 +7,7 @@
- this.getFeature(p_221243_).ifPresent(p_256352_ -> p_256352_.value().place(p_221243_, p_221243_.getChunkSource().getGenerator(), p_221244_, p_221245_));
+ this.getFeature(p_221243_).ifPresent(p_256352_ -> {
+ var event = net.minecraftforge.event.ForgeEventFactory.blockGrowFeature(p_221243_, p_221244_, p_221245_, p_256352_);
+ if (event.getResult().equals(net.minecraftforge.eventbus.api.Event.Result.DENY)) return;
+ if (event.getResult().isDenied()) return;
+ event.getFeature().value().place(p_221243_, p_221243_.getChunkSource().getGenerator(), p_221244_, p_221245_);
+ });
}
@@ -14,7 +14,7 @@
return false;
} else {
+ var event = net.minecraftforge.event.ForgeEventFactory.blockGrowFeature(p_221774_, p_221777_, p_221775_, optional.get());
+ if (event.getResult().equals(net.minecraftforge.eventbus.api.Event.Result.DENY)) return false;
+ if (event.getResult().isDenied()) return false;
p_221774_.removeBlock(p_221775_, false);
- if (optional.get().value().place(p_221774_, p_221774_.getChunkSource().getGenerator(), p_221777_, p_221775_)) {
+ if (event.getFeature().value().place(p_221774_, p_221774_.getChunkSource().getGenerator(), p_221777_, p_221775_)) {
@@ -1,6 +1,6 @@
--- a/net/minecraft/world/level/block/SculkSensorBlock.java
+++ b/net/minecraft/world/level/block/SculkSensorBlock.java
@@ -294,8 +_,13 @@
@@ -293,8 +_,13 @@
@Override
protected void spawnAfterBreak(BlockState p_222142_, ServerLevel p_222143_, BlockPos p_222144_, ItemStack p_222145_, boolean p_222146_) {
super.spawnAfterBreak(p_222142_, p_222143_, p_222144_, p_222145_, p_222146_);
@@ -9,35 +9,36 @@
private static final Logger LOGGER = LogUtils.getLogger();
private final BlockEntityType<?> type;
@Nullable
@@ -38,9 +_,11 @@
@@ -38,10 +_,12 @@
private DataComponentMap components = DataComponentMap.EMPTY;
public BlockEntity(BlockEntityType<?> p_155228_, BlockPos p_155229_, BlockState p_155230_) {
+ super(BlockEntity.class);
this.type = p_155228_;
this.worldPosition = p_155229_.immutable();
this.validateBlockState(p_155230_);
this.blockState = p_155230_;
+ this.gatherCapabilities();
}
public static BlockPos getPosFromTag(CompoundTag p_187473_) {
@@ -61,6 +_,7 @@
private void validateBlockState(BlockState p_345558_) {
@@ -72,6 +_,7 @@
}
protected void loadAdditional(CompoundTag p_331149_, HolderLookup.Provider p_333170_) {
+ if (getCapabilities() != null && p_331149_.contains("ForgeCaps")) deserializeCaps(p_331149_.getCompound("ForgeCaps"));
+ if (getCapabilities() != null && p_331149_.contains("ForgeCaps")) deserializeCaps(p_333170_, p_331149_.getCompound("ForgeCaps"));
}
public final void loadWithComponents(CompoundTag p_331756_, HolderLookup.Provider p_335164_) {
@@ -76,6 +_,7 @@
@@ -87,6 +_,7 @@
}
protected void saveAdditional(CompoundTag p_187471_, HolderLookup.Provider p_327783_) {
+ if (getCapabilities() != null) p_187471_.put("ForgeCaps", serializeCaps());
+ if (getCapabilities() != null) p_187471_.put("ForgeCaps", serializeCaps(p_327783_));
}
public final CompoundTag saveWithFullMetadata(HolderLookup.Provider p_331193_) {
@@ -205,6 +_,13 @@
@@ -216,6 +_,13 @@
public void setRemoved() {
this.remove = true;
@@ -0,0 +1,13 @@
--- a/net/minecraft/world/level/block/entity/HangingSignBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/HangingSignBlockEntity.java
@@ -13,6 +_,10 @@
super(BlockEntityType.HANGING_SIGN, p_250603_, p_251674_);
}
+ public HangingSignBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
+ super(type, pos, state);
+ }
+
@Override
public int getTextLineHeight() {
return 9;
@@ -6,7 +6,7 @@
Holder<ConfiguredFeature<?, ?>> holder = p_309830_.registryAccess().registryOrThrow(Registries.CONFIGURED_FEATURE).getHolder(resourcekey).orElse(null);
+ var event = net.minecraftforge.event.ForgeEventFactory.blockGrowFeature(p_309830_, p_309951_, p_310327_, holder);
+ holder = event.getFeature();
+ if (event.getResult() == net.minecraftforge.eventbus.api.Event.Result.DENY) return false;
+ if (event.getResult().isDenied()) return false;
if (holder != null) {
for (int i = 0; i >= -1; i--) {
for (int j = 0; j >= -1; j--) {
@@ -34,7 +34,7 @@
p_62866_.onPlace(this.level, p_62865_, blockstate, p_62867_);
}
@@ -321,6 +_,12 @@
@@ -326,6 +_,12 @@
@Nullable
public BlockEntity getBlockEntity(BlockPos p_62868_, LevelChunk.EntityCreationType p_62869_) {
BlockEntity blockentity = this.blockEntities.get(p_62868_);
@@ -47,7 +47,7 @@
if (blockentity == null) {
CompoundTag compoundtag = this.pendingBlockEntities.remove(p_62868_);
if (compoundtag != null) {
@@ -338,9 +_,6 @@
@@ -343,9 +_,6 @@
this.addAndRegisterBlockEntity(blockentity);
}
}
@@ -57,7 +57,7 @@
}
return blockentity;
@@ -354,6 +_,7 @@
@@ -359,6 +_,7 @@
}
this.updateBlockEntityTicker(p_156391_);
@@ -65,7 +65,7 @@
}
}
@@ -406,9 +_,14 @@
@@ -411,9 +_,14 @@
public CompoundTag getBlockEntityNbtForSaving(BlockPos p_62932_, HolderLookup.Provider p_329605_) {
BlockEntity blockentity = this.getBlockEntity(p_62932_);
if (blockentity != null && !blockentity.isRemoved()) {
@@ -80,7 +80,7 @@
} else {
CompoundTag compoundtag = this.pendingBlockEntities.get(p_62932_);
if (compoundtag != null) {
@@ -488,7 +_,7 @@
@@ -493,7 +_,7 @@
p_187974_.accept((p_327409_, p_327410_, p_327411_) -> {
BlockEntity blockentity = this.getBlockEntity(p_327409_, LevelChunk.EntityCreationType.IMMEDIATE);
if (blockentity != null && p_327411_ != null && blockentity.getType() == p_327410_) {
@@ -89,7 +89,7 @@
}
});
}
@@ -596,6 +_,7 @@
@@ -601,6 +_,7 @@
}
public void clearAllBlockEntities() {
@@ -97,7 +97,7 @@
this.blockEntities.values().forEach(BlockEntity::setRemoved);
this.blockEntities.clear();
this.tickersInLevel.values().forEach(p_187966_ -> p_187966_.rebind(NULL_TICKER));
@@ -603,6 +_,7 @@
@@ -608,6 +_,7 @@
}
public void registerAllBlockEntitiesAfterLevelLoad() {
@@ -105,7 +105,7 @@
this.blockEntities.values().forEach(p_187988_ -> {
if (this.level instanceof ServerLevel serverlevel) {
this.addGameEventListener(p_187988_, serverlevel);
@@ -654,6 +_,34 @@
@@ -659,6 +_,24 @@
return new LevelChunk.BoundTickingBlockEntity<>(p_156376_, p_156377_);
}
@@ -118,16 +118,6 @@
+ }
+
+ @Override
+ public boolean areCapsCompatible(net.minecraftforge.common.capabilities.CapabilityProvider<LevelChunk> other) {
+ return capProvider.areCapsCompatible(other);
+ }
+
+ @Override
+ public boolean areCapsCompatible(@org.jetbrains.annotations.Nullable net.minecraftforge.common.capabilities.CapabilityDispatcher other) {
+ return capProvider.areCapsCompatible(other);
+ }
+
+ @Override
+ public void invalidateCaps() {
+ capProvider.invalidateCaps();
+ }
@@ -140,7 +130,7 @@
class BoundTickingBlockEntity<T extends BlockEntity> implements TickingBlockEntity {
private final T blockEntity;
private final BlockEntityTicker<T> ticker;
@@ -671,6 +_,7 @@
@@ -676,6 +_,7 @@
if (LevelChunk.this.isTicking(blockpos)) {
try {
ProfilerFiller profilerfiller = LevelChunk.this.level.getProfiler();
@@ -148,7 +138,7 @@
profilerfiller.push(this::getType);
BlockState blockstate = LevelChunk.this.getBlockState(blockpos);
if (this.blockEntity.getType().isValid(blockstate)) {
@@ -692,6 +_,11 @@
@@ -697,6 +_,11 @@
CrashReport crashreport = CrashReport.forThrowable(throwable, "Ticking block entity");
CrashReportCategory crashreportcategory = crashreport.addCategory("Block entity being ticked");
this.blockEntity.fillCrashReportCategory(crashreportcategory);
@@ -160,7 +150,7 @@
throw new ReportedException(crashreport);
}
}
@@ -765,5 +_,32 @@
@@ -770,5 +_,32 @@
public String toString() {
return this.ticker + " <wrapped>";
}
@@ -173,8 +163,8 @@
+ */
+ @java.lang.Deprecated
+ @org.jetbrains.annotations.Nullable
+ public final CompoundTag writeCapsToNBT() {
+ return capProvider.serializeInternal();
+ public final CompoundTag writeCapsToNBT(HolderLookup.Provider registryAccess) {
+ return capProvider.serializeInternal(registryAccess);
+ }
+
+ /**
@@ -184,8 +174,8 @@
+ *
+ */
+ @java.lang.Deprecated
+ public final void readCapsFromNBT(CompoundTag tag) {
+ capProvider.deserializeInternal(tag);
+ public final void readCapsFromNBT(HolderLookup.Provider registryAccess, CompoundTag tag) {
+ capProvider.deserializeInternal(registryAccess, tag);
+ }
+
+ @Override
@@ -5,7 +5,7 @@
blendingdata
);
+ if (p_188234_.contains("ForgeCaps")) {
+ ((LevelChunk)chunkaccess).readCapsFromNBT(p_188234_.getCompound("ForgeCaps"));
+ ((LevelChunk)chunkaccess).readCapsFromNBT(p_188231_.registryAccess(), p_188234_.getCompound("ForgeCaps"));
+ }
} else {
ProtoChunkTicks<Block> protochunkticks = ProtoChunkTicks.load(
@@ -33,7 +33,7 @@
+ }
+ else if (p_63456_ instanceof LevelChunk levelChunk){
+ try {
+ final CompoundTag capTag = levelChunk.writeCapsToNBT();
+ final CompoundTag capTag = levelChunk.writeCapsToNBT(p_63455_.registryAccess());
+ if (capTag != null) compoundtag.put("ForgeCaps", capTag);
+ } catch (Exception exception) {
+ LOGGER.error("A capability provider has thrown an exception trying to write state. It will not persist. Report this to the mod author", exception);
@@ -1,6 +1,6 @@
--- a/net/minecraft/world/level/levelgen/PhantomSpawner.java
+++ b/net/minecraft/world/level/levelgen/PhantomSpawner.java
@@ -42,13 +_,17 @@
@@ -42,13 +_,18 @@
for (ServerPlayer serverplayer : p_64576_.players()) {
if (!serverplayer.isSpectator()) {
BlockPos blockpos = serverplayer.blockPosition();
@@ -9,14 +9,15 @@
+ var vanillaPosition = (!p_64576_.dimensionType().hasSkyLight() || blockpos.getY() >= p_64576_.getSeaLevel() && p_64576_.canSeeSky(blockpos));
+ var count = 1 + randomsource.nextInt(difficultyinstance.getDifficulty().getId() + 1);
+ var event = net.minecraftforge.event.ForgeEventFactory.onPlayerSpawnPhantom(serverplayer, count);
+ if (event.getResult() == net.minecraftforge.eventbus.api.Event.Result.DENY) continue;
+ if (event.getResult() == net.minecraftforge.eventbus.api.Event.Result.ALLOW || vanillaPosition) {
+ var eventResult = event.getResult();
+ if (eventResult.isDenied()) continue;
+ if (vanillaPosition || eventResult.isAllowed()) {
if (difficultyinstance.isHarderThan(randomsource.nextFloat() * 3.0F)) {
ServerStatsCounter serverstatscounter = serverplayer.getStats();
int j = Mth.clamp(serverstatscounter.getValue(Stats.CUSTOM.get(Stats.TIME_SINCE_REST)), 1, Integer.MAX_VALUE);
int k = 24000;
- if (randomsource.nextInt(j) >= 72000) {
+ if (event.getResult() == net.minecraftforge.eventbus.api.Event.Result.ALLOW || randomsource.nextInt(j) >= 72000) {
+ if (eventResult.isAllowed() || randomsource.nextInt(j) >= 72000) {
BlockPos blockpos1 = blockpos.above(20 + randomsource.nextInt(15))
.east(-10 + randomsource.nextInt(21))
.south(-10 + randomsource.nextInt(21));
@@ -0,0 +1,11 @@
--- a/net/minecraft/world/level/storage/loot/functions/SetAttributesFunction.java
+++ b/net/minecraft/world/level/storage/loot/functions/SetAttributesFunction.java
@@ -66,7 +_,7 @@
p_80840_.update(
DataComponents.ATTRIBUTE_MODIFIERS,
ItemAttributeModifiers.EMPTY,
- p_327582_ -> p_327582_.modifiers().isEmpty() ? this.updateModifiers(p_80841_, p_80840_.getItem().getDefaultAttributeModifiers()) : this.updateModifiers(p_80841_, p_327582_)
+ p_327582_ -> p_327582_.modifiers().isEmpty() ? this.updateModifiers(p_80841_, p_80840_.getDefaultAttributeModifiers()) : this.updateModifiers(p_80841_, p_327582_)
);
}
+1 -1
View File
@@ -9,7 +9,7 @@ if %ERRORLEVEL% NEQ 0 (
)
REM Add custom program arguments (such as nogui) to the next line before the %* or pass them to this script directly
java @libraries/@MAVEN_PATH@/win_args.txt %*
java @user_jvm_args.txt @libraries/@MAVEN_PATH@/win_args.txt %*
:exit
pause
+3 -3
View File
@@ -30,11 +30,11 @@ dependencyResolutionManagement {
library('accesstransformers', 'net.minecraftforge:accesstransformers:8.2.0')
library('coremods', 'net.minecraftforge:coremods:5.1.6')
library('nashorn', 'org.openjdk.nashorn:nashorn-core:15.4') // Needed by coremods, because the JRE no longer ships JS
library('eventbus', 'net.minecraftforge:eventbus:6.2.6')
library('eventbus', 'net.minecraftforge:eventbus:6.2.8')
library('typetools', 'net.jodah:typetools:0.6.3') // Needed by EventBus because of lambdas
library('mergetool-api', 'net.minecraftforge:mergetool-api:1.0')
library('mixin', 'org.spongepowered:mixin:0.8.5')
library('mixin', 'org.spongepowered:mixin:0.8.7')
library('nulls', 'org.jetbrains:annotations:24.1.0') // Got to have our null annotations!
library('slf4j-api', 'org.slf4j:slf4j-api:2.0.7')
library('maven-artifact', 'org.apache.maven:maven-artifact:3.8.5')
@@ -67,7 +67,7 @@ dependencyResolutionManagement {
bundle('terminalconsoleappender', ['terminalconsoleappender', 'jline-reader', 'jline-terminal', 'jline-terminal-jna'])
// The core of our configuration system, it has many flaws, but it works for the most part
version('night-config', '3.6.7')
version('night-config', '3.7.3')
library('night-config-toml', 'com.electronwill.night-config', 'toml').versionRef('night-config')
library('night-config-core', 'com.electronwill.night-config', 'core').versionRef('night-config')
bundle('night-config', ['night-config-toml', 'night-config-core'])
@@ -251,9 +251,7 @@ public class ForgeHooksClient {
return result != null ? result : layer.texture(inner);
}
public static boolean onDrawHighlight(LevelRenderer context, Camera camera, HitResult target, float partialTick, Matrix4f ctxPos, MultiBufferSource bufferSource) {
var poseStack = new PoseStack();
poseStack.mulPose(ctxPos);
public static boolean onDrawHighlight(LevelRenderer context, Camera camera, HitResult target, float partialTick, PoseStack poseStack, MultiBufferSource bufferSource) {
switch (target.getType()) {
case BLOCK:
if (!(target instanceof BlockHitResult blockTarget)) return false;
@@ -816,11 +814,15 @@ public class ForgeHooksClient {
}
public static List<ClientTooltipComponent> gatherTooltipComponents(ItemStack stack, List<? extends FormattedText> textElements, Optional<TooltipComponent> itemComponent, int mouseX, int screenWidth, int screenHeight, Font fallbackFont) {
Font font = getTooltipFont(stack, fallbackFont);
List<Either<FormattedText, TooltipComponent>> elements = textElements.stream()
.map((Function<FormattedText, Either<FormattedText, TooltipComponent>>) Either::left)
.collect(Collectors.toCollection(ArrayList::new));
itemComponent.ifPresent(c -> elements.add(1, Either.right(c)));
return gatherTooltipComponentsFromElements(stack, elements, mouseX, screenWidth, screenHeight, fallbackFont);
}
public static List<ClientTooltipComponent> gatherTooltipComponentsFromElements(ItemStack stack, List<Either<FormattedText, TooltipComponent>> elements, int mouseX, int screenWidth, int screenHeight, Font fallbackFont) {
Font font = getTooltipFont(stack, fallbackFont);
var event = new RenderTooltipEvent.GatherComponents(stack, screenWidth, screenHeight, elements, -1);
MinecraftForge.EVENT_BUS.post(event);
@@ -258,10 +258,10 @@ public final class ForgeEventFactoryClient {
}
public static void onRenderTickStart(DeltaTracker timer) {
post(new TickEvent.RenderTickEvent.Start(timer));
post(new TickEvent.RenderTickEvent.Pre(timer));
}
public static void onRenderTickEnd(DeltaTracker timer) {
post(new TickEvent.RenderTickEvent.End(timer));
post(new TickEvent.RenderTickEvent.Post(timer));
}
}
@@ -77,8 +77,9 @@ public class RenderLevelStageEvent extends Event {
}
/**
* {@return the pose stack used for rendering}
* @deprecated Mojang has stopped passing around PosStacks. getProjectionMatrix should be enough.
*/
@Deprecated(forRemoval = true, since = "1.21")
public Matrix4f getPoseStack() {
return poseStack;
}
@@ -61,7 +61,7 @@ public class SeparateTransformsModel implements IUnbakedGeometry<SeparateTransfo
spriteGetter.apply(context.getMaterial("particle")), overrides,
baseModel.bake(baker, baseModel, spriteGetter, modelState, context.useBlockLight()),
ImmutableMap.copyOf(Maps.transformValues(perspectives, value -> {
return value.bake(baker, value, spriteGetter, modelState, context.useBlockLight(), context.getRenderType(context.getRenderTypeHint()));
return value.bake(baker, value, spriteGetter, modelState, context.useBlockLight());
}))
);
}
@@ -119,17 +119,16 @@ public class ForgeConfigSpec extends UnmodifiableConfigWrapper<UnmodifiableConfi
@Override
public void afterReload() {
this.resetCaches(getValues().valueMap().values());
this.resetCaches(getValues());
}
private void resetCaches(final Iterable<Object> configValues) {
configValues.forEach(value -> {
if (value instanceof ConfigValue<?> configValue) {
private void resetCaches(UnmodifiableConfig cfg) {
for (var entry : cfg.entrySet()) {
if (entry.getValue() instanceof ConfigValue<?> configValue)
configValue.clearCache();
} else if (value instanceof Config innerConfig) {
this.resetCaches(innerConfig.valueMap().values());
}
});
else if (entry.getValue() instanceof UnmodifiableConfig innerConfig)
resetCaches(innerConfig);
}
}
public void save() {
@@ -169,13 +168,10 @@ public class ForgeConfigSpec extends UnmodifiableConfigWrapper<UnmodifiableConfi
private int correct(UnmodifiableConfig spec, CommentedConfig config, LinkedList<String> parentPath, List<String> parentPathUnmodifiable, CorrectionListener listener, CorrectionListener commentListener, boolean dryRun) {
int count = 0;
Map<String, Object> specMap = spec.valueMap();
Map<String, Object> configMap = config.valueMap();
for (Map.Entry<String, Object> specEntry : specMap.entrySet()) {
for (var specEntry : spec.entrySet()) {
final String key = specEntry.getKey();
final Object specValue = specEntry.getValue();
final Object configValue = configMap.get(key);
final Object configValue = config.get(key);
final CorrectionAction action = configValue == null ? CorrectionAction.ADD : CorrectionAction.REPLACE;
parentPath.addLast(key);
@@ -189,7 +185,7 @@ public class ForgeConfigSpec extends UnmodifiableConfigWrapper<UnmodifiableConfi
return 1;
} else {
CommentedConfig newValue = config.createSubConfig();
configMap.put(key, newValue);
config.set(key, newValue);
listener.onCorrect(action, parentPathUnmodifiable, configValue, newValue);
count++;
count += correct((Config)specValue, newValue, parentPath, parentPathUnmodifiable, listener, commentListener, dryRun);
@@ -213,7 +209,7 @@ public class ForgeConfigSpec extends UnmodifiableConfigWrapper<UnmodifiableConfi
return 1;
Object newValue = valueSpec.correct(configValue);
configMap.put(key, newValue);
config.set(key, newValue);
listener.onCorrect(action, parentPathUnmodifiable, configValue, newValue);
count++;
}
@@ -232,16 +228,17 @@ public class ForgeConfigSpec extends UnmodifiableConfigWrapper<UnmodifiableConfi
parentPath.removeLast();
}
var keys = config.entrySet().stream().map(Entry::getKey).toList();
// Second step: removes the unspecified values
for (Iterator<Map.Entry<String, Object>> ittr = configMap.entrySet().iterator(); ittr.hasNext();) {
Map.Entry<String, Object> entry = ittr.next();
if (!specMap.containsKey(entry.getKey())) {
for (var key : keys) {
if (!spec.contains(key)) {
if (dryRun)
return 1;
ittr.remove();
parentPath.addLast(entry.getKey());
listener.onCorrect(CorrectionAction.REMOVE, parentPathUnmodifiable, entry.getValue(), null);
var value = config.get(key);
config.remove(key);
parentPath.addLast(key);
listener.onCorrect(CorrectionAction.REMOVE, parentPathUnmodifiable, value, null);
parentPath.removeLast();
count++;
}
@@ -42,6 +42,7 @@ import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.commands.SharedSuggestionProvider;
import net.minecraft.commands.arguments.selector.EntitySelectorParser;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Holder;
@@ -465,7 +466,7 @@ public final class ForgeHooks {
level.captureBlockSnapshots = false;
if (ret.consumesAction()) {
var postUse = itemstack.copy();
var postUse = player.getItemInHand(context.getHand());
var blockSnapshots = new ArrayList<>(level.capturedBlockSnapshots);
level.capturedBlockSnapshots.clear();
@@ -491,8 +492,7 @@ public final class ForgeHooks {
}
} else {
// Change the stack to its new content
if (!player.isCreative())
player.setItemInHand(context.getHand(), postUse);
player.setItemInHand(context.getHand(), postUse);
for (BlockSnapshot snap : blockSnapshots) {
int updateFlag = snap.getFlag();
@@ -639,9 +639,8 @@ public final class ForgeHooks {
}
public static boolean onCropsGrowPre(Level level, BlockPos pos, BlockState state, boolean def) {
BlockEvent ev = new BlockEvent.CropGrowEvent.Pre(level,pos,state);
MinecraftForge.EVENT_BUS.post(ev);
return (ev.getResult() == Event.Result.ALLOW || (ev.getResult() == Event.Result.DEFAULT && def));
var result = MinecraftForge.EVENT_BUS.fire(new BlockEvent.CropGrowEvent.Pre(level,pos,state)).getResult();
return (result.isAllowed() || (def && result.isDefault()));
}
public static void onCropsGrowPost(Level level, BlockPos pos, BlockState state) {
@@ -1005,7 +1004,7 @@ public final class ForgeHooks {
}
public static boolean canUseEntitySelectors(SharedSuggestionProvider provider) {
if (provider.hasPermission(Commands.LEVEL_GAMEMASTERS))
if (EntitySelectorParser.allowSelectors(provider))
return true;
else if (provider instanceof CommandSourceStack source && source.source instanceof ServerPlayer player)
return PermissionAPI.getPermission(player, ForgeMod.USE_SELECTORS_PERMISSION);
@@ -51,8 +51,13 @@ public class ForgeInternalHandler {
}
@SubscribeEvent
public void onServerTick(ServerTickEvent event) {
WorldWorkerManager.tick(event.phase == TickEvent.Phase.START);
public void onServerTick(ServerTickEvent.Pre event) {
WorldWorkerManager.tick(true);
}
@SubscribeEvent
public void onServerTick(ServerTickEvent.Post event) {
WorldWorkerManager.tick(false);
}
@SubscribeEvent
@@ -96,7 +101,7 @@ public class ForgeInternalHandler {
@SubscribeEvent
public void onResourceReload(AddReloadListenerEvent event) {
INSTANCE = new LootModifierManager();
INSTANCE = new LootModifierManager(event.getRegistryAccess());
event.addListener(INSTANCE);
}
@@ -538,7 +538,7 @@ public class ForgeMod {
/**
* TODO: Remove when {@link ForgeRegistry#addAlias(ResourceLocation, ResourceLocation)} is elevated to {@link IForgeRegistry}.
*/
@Deprecated(forRemoval = true, since = "1.20")
//@Deprecated(forRemoval = true, since = "1.20")
private static <T> void addAlias(IForgeRegistry<T> registry, ResourceLocation from, ResourceLocation to) {
ForgeRegistry<T> fReg = (ForgeRegistry<T>) registry;
fReg.addAlias(from, to);
@@ -7,6 +7,7 @@ package net.minecraftforge.common;
import net.minecraft.core.Direction;
import net.minecraft.core.dispenser.DispenseItemBehavior;
import net.minecraft.util.FastColor;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.MobSpawnType;
@@ -91,9 +92,14 @@ public class ForgeSpawnEggItem extends SpawnEggItem {
private static class ColorRegisterHandler {
@SubscribeEvent(priority = EventPriority.HIGHEST)
public static void registerSpawnEggColors(RegisterColorHandlersEvent.Item event) {
MOD_EGGS.forEach(egg ->
event.register((stack, layer) -> egg.getColor(layer), egg)
);
MOD_EGGS.forEach(egg -> {
event.register((stack, layer) -> {
int color = egg.getColor(layer);
if (FastColor.ARGB32.alpha(color) == 0)
color = FastColor.ARGB32.opaque(color);
return color;
}, egg);
});
}
}
}
@@ -16,19 +16,17 @@ import net.minecraftforge.registries.GameData;
import net.minecraftforge.registries.ObjectHolderRegistry;
import net.minecraftforge.registries.RegistryManager;
public class ForgeStatesProvider implements IModStateProvider
{
public class ForgeStatesProvider implements IModStateProvider {
final ModLoadingState CREATE_REGISTRIES = ModLoadingState.withInline("CREATE_REGISTRIES", "CONSTRUCT", ModLoadingPhase.GATHER, ml -> RegistryManager.postNewRegistryEvent());
final ModLoadingState OBJECT_HOLDERS = ModLoadingState.withInline("OBJECT_HOLDERS", "CREATE_REGISTRIES", ModLoadingPhase.GATHER, ml -> ObjectHolderRegistry.findObjectHolders());
final ModLoadingState INJECT_CAPABILITIES = ModLoadingState.withInline("INJECT_CAPABILITIES", "OBJECT_HOLDERS", ModLoadingPhase.GATHER, ml -> CapabilityManager.INSTANCE.injectCapabilities(ml.getAllScanData()));
final ModLoadingState INJECT_CAPABILITIES = ModLoadingState.withInline("INJECT_CAPABILITIES", "OBJECT_HOLDERS", ModLoadingPhase.GATHER, CapabilityManager::injectCapabilities);
final ModLoadingState UNFREEZE = ModLoadingState.withInline("UNFREEZE_DATA", "INJECT_CAPABILITIES", ModLoadingPhase.GATHER, ml -> GameData.unfreezeData());
final ModLoadingState LOAD_REGISTRIES = ModLoadingState.withInline("LOAD_REGISTRIES", "UNFREEZE_DATA", ModLoadingPhase.GATHER, ml -> GameData.postRegisterEvents());
final ModLoadingState FREEZE = ModLoadingState.withInline("FREEZE_DATA", "COMPLETE", ModLoadingPhase.COMPLETE, ml -> GameData.freezeData());
final ModLoadingState NETLOCK = ModLoadingState.withInline("NETWORK_LOCK", "FREEZE_DATA", ModLoadingPhase.COMPLETE, ml -> NetworkRegistry.lock());
@Override
public List<IModLoadingState> getAllStates()
{
public List<IModLoadingState> getAllStates() {
return List.of(CREATE_REGISTRIES, OBJECT_HOLDERS, INJECT_CAPABILITIES, UNFREEZE, LOAD_REGISTRIES, FREEZE, NETLOCK);
}
}
@@ -23,8 +23,7 @@ import org.jetbrains.annotations.Nullable;
* to support mod-shears as well.
*
*/
public interface IForgeShearable
{
public interface IForgeShearable {
/**
* Checks if the object is currently shearable
* Example: Sheep return false when they have no wool
@@ -34,8 +33,7 @@ public interface IForgeShearable
* @param pos Block's position in level.
* @return If this is shearable, and onSheared should be called.
*/
default boolean isShearable(@NotNull ItemStack item, Level level, BlockPos pos)
{
default boolean isShearable(@NotNull ItemStack item, Level level, BlockPos pos) {
return true;
}
@@ -58,8 +56,7 @@ public interface IForgeShearable
* @return A List containing all items from this shearing. May be empty.
*/
@NotNull
default List<ItemStack> onSheared(@Nullable Player player, @NotNull ItemStack item, Level level, BlockPos pos, int fortune)
{
default List<ItemStack> onSheared(@Nullable Player player, @NotNull ItemStack item, Level level, BlockPos pos, int fortune) {
return Collections.emptyList();
}
}
@@ -67,7 +67,7 @@ public class ToolActions
/**
* Used during player attack to figure out if a sweep attack should be performed
*
*
* @see IForgeItem#getSweepHitBox
*/
public static final ToolAction SWORD_SWEEP = ToolAction.get("sword_sweep");
@@ -19,16 +19,16 @@ import java.util.function.Consumer;
*
* The CapabilityManager is in charge of creating this class.
*/
public class Capability<T>
{
public final class Capability<T> {
/**
* @return The unique name of this capability, typically this is
* the fully qualified class name for the target interface.
*/
public String getName() { return name; }
public String getName() {
return name;
}
public @NotNull <R> LazyOptional<R> orEmpty(Capability<R> toCheck, LazyOptional<T> inst)
{
public @NotNull <R> LazyOptional<R> orEmpty(Capability<R> toCheck, LazyOptional<T> inst) {
return this == toCheck ? inst.cast() : LazyOptional.empty();
}
@@ -36,8 +36,7 @@ public class Capability<T>
* @return true if something has registered this capability to the Manager.
* This is a marker that the class for this capability exists, and can be used.
*/
public boolean isRegistered()
{
public boolean isRegistered() {
return this.listeners == null;
}
@@ -48,8 +47,7 @@ public class Capability<T>
* @param listener Function to fire when capability is registered.
* @return self, in case people want to use builder pattern.
*/
public synchronized Capability<T> addListener(Consumer<Capability<T>> listener)
{
public synchronized Capability<T> addListener(Consumer<Capability<T>> listener) {
if (this.isRegistered())
listener.accept(this);
else
@@ -61,13 +59,11 @@ public class Capability<T>
private final String name;
List<Consumer<Capability<T>>> listeners = new ArrayList<>();
Capability(String name)
{
Capability(String name) {
this.name = name;
}
void onRegister()
{
void onRegister() {
var listeners = this.listeners;
this.listeners = null;
listeners.forEach(l -> l.accept(this));
@@ -16,6 +16,7 @@ import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.nbt.Tag;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.core.Direction;
import net.minecraft.core.HolderLookup;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.common.util.INBTSerializable;
import net.minecraftforge.common.util.LazyOptional;
@@ -33,42 +34,36 @@ import org.jetbrains.annotations.Nullable;
*/
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
public final class CapabilityDispatcher implements INBTSerializable<CompoundTag>, ICapabilityProvider
{
@SuppressWarnings("deprecation")
public final class CapabilityDispatcher implements INBTSerializable<CompoundTag>, ICapabilityProvider {
private final ICapabilityProvider[] caps;
private final INBTSerializable<Tag>[] writers;
private final String[] names;
private final List<Runnable> listeners;
public CapabilityDispatcher(Map<ResourceLocation, ICapabilityProvider> list, List<Runnable> listeners)
{
public CapabilityDispatcher(Map<ResourceLocation, ICapabilityProvider> list, List<Runnable> listeners) {
this(list, listeners, null);
}
@SuppressWarnings("unchecked")
public CapabilityDispatcher(Map<ResourceLocation, ICapabilityProvider> list, List<Runnable> listeners, @Nullable ICapabilityProvider parent)
{
public CapabilityDispatcher(Map<ResourceLocation, ICapabilityProvider> list, List<Runnable> listeners, @Nullable ICapabilityProvider parent) {
List<ICapabilityProvider> lstCaps = new ArrayList<>();
List<INBTSerializable<Tag>> lstWriters = new ArrayList<>();
List<String> lstNames = new ArrayList<>();
this.listeners = listeners;
if (parent != null) // Parents go first!
{
if (parent != null) { // Parents go first!
lstCaps.add(parent);
if (parent instanceof INBTSerializable)
{
if (parent instanceof INBTSerializable) {
lstWriters.add((INBTSerializable<Tag>)parent);
lstNames.add("Parent");
}
}
for (Map.Entry<ResourceLocation, ICapabilityProvider> entry : list.entrySet())
{
for (var entry : list.entrySet()) {
ICapabilityProvider prov = entry.getValue();
lstCaps.add(prov);
if (prov instanceof INBTSerializable)
{
if (prov instanceof INBTSerializable) {
lstWriters.add((INBTSerializable<Tag>)prov);
lstNames.add(entry.getKey().toString());
}
@@ -81,14 +76,11 @@ public final class CapabilityDispatcher implements INBTSerializable<CompoundTag>
@Override
public <T> LazyOptional<T> getCapability(Capability<T> cap, @Nullable Direction side)
{
for (ICapabilityProvider c : caps)
{
public <T> LazyOptional<T> getCapability(Capability<T> cap, @Nullable Direction side) {
for (ICapabilityProvider c : caps) {
LazyOptional<T> ret = c.getCapability(cap, side);
//noinspection ConstantConditions
if (ret == null)
{
if (ret == null) {
throw new RuntimeException(
String.format(
Locale.ENGLISH,
@@ -97,46 +89,31 @@ public final class CapabilityDispatcher implements INBTSerializable<CompoundTag>
)
);
}
if (ret.isPresent())
{
return ret;
}
}
return LazyOptional.empty();
}
@Override
public CompoundTag serializeNBT()
{
public CompoundTag serializeNBT(HolderLookup.Provider registryAccess) {
CompoundTag nbt = new CompoundTag();
for (int x = 0; x < writers.length; x++)
{
nbt.put(names[x], writers[x].serializeNBT());
}
nbt.put(names[x], writers[x].serializeNBT(registryAccess));
return nbt;
}
@Override
public void deserializeNBT(CompoundTag nbt)
{
for (int x = 0; x < writers.length; x++)
{
public void deserializeNBT(HolderLookup.Provider registryAccess, CompoundTag nbt) {
for (int x = 0; x < writers.length; x++) {
if (nbt.contains(names[x]))
{
writers[x].deserializeNBT(nbt.get(names[x]));
}
writers[x].deserializeNBT(registryAccess, nbt.get(names[x]));
}
}
public boolean areCompatible(@Nullable CapabilityDispatcher other) //Called from ItemStack to compare equality.
{ // Only compares serializeable caps.
if (other == null) return this.writers.length == 0; // Done this way so we can do some pre-checks before doing the costly NBT serialization and compare
if (this.writers.length == 0) return other.writers.length == 0;
return this.serializeNBT().equals(other.serializeNBT());
}
public void invalidate()
{
public void invalidate() {
this.listeners.forEach(Runnable::run);
}
}
@@ -5,65 +5,90 @@
package net.minecraftforge.common.capabilities;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.fml.Logging;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.ModLoader;
import net.minecraftforge.forgespi.language.ModFileScanData;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.ApiStatus;
import org.objectweb.asm.Type;
import java.util.Comparator;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
public enum CapabilityManager
{
INSTANCE;
static final Logger LOGGER = LogManager.getLogger();
public final class CapabilityManager {
@Deprecated(forRemoval = true, since = "1.21")
public static final CapabilityManager INSTANCE = new CapabilityManager();
private static final Logger LOGGER = LogManager.getLogger();
public static <T> Capability<T> get(CapabilityToken<T> type)
{
return INSTANCE.get(type.getType(), false);
/**
* Retrieves the 'root' capability for the specified type. This is the generic one that is used when the API
* registers the specified type. It is also safe to assume that if your child token is a valid return when
* this Capability is requested.
*/
public static <T> Capability<T> get(CapabilityToken<T> type) {
return get(type.getType(), null, false);
}
/**
* Retrieves a named capability of the specified type. This is useful when providers supply multiple instances of the same interface and want to
* distinguish between them. It is generally not safe to return your generic implementation for the root type when this is requested.
*/
public static <T> Capability<T> get(CapabilityToken<T> type, String modid, String name) {
return get(type, ResourceLocation.fromNamespaceAndPath(modid, name));
}
/**
* Retrieves a named capability of the specified type. This is useful when providers supply multiple instances of the same interface and want to
* distinguish between them. It is generally not safe to return your generic implementation for the root type when this is requested.
*/
public static <T> Capability<T> get(CapabilityToken<T> type, ResourceLocation name) {
return get(type.getType(), name, false);
}
@SuppressWarnings("unchecked")
<T> Capability<T> get(String realName, boolean registering)
{
static <T> Capability<T> get(String type, ResourceLocation name, boolean registering) {
Capability<T> cap;
synchronized (providers)
{
realName = realName.intern();
cap = (Capability<T>)providers.computeIfAbsent(realName, Capability::new);
synchronized (providers) {
final var parent = (Capability<T>)providers.computeIfAbsent(new Key(type, null), k -> new Capability<>(type.intern()));
if (name == null) {
cap = parent;
} else { // A Named child
cap = (Capability<T>)providers.computeIfAbsent(new Key(type, name), k -> {
var ret = new Capability<>((parent.getName() + '#' + name.toString()).intern());
parent.addListener(p -> ret.onRegister());
return ret;
});
}
}
if (registering) {
if (name != null)
error("Cannot register capability type " + type + " + with a name: " + name);
if (registering)
{
synchronized (cap)
{
synchronized (cap) {
if (cap.isRegistered())
{
LOGGER.error(Logging.CAPABILITIES, "Cannot register capability implementation multiple times : {}", realName);
throw new IllegalArgumentException("Cannot register a capability implementation multiple times : "+ realName);
}
else
{
cap.onRegister();
}
error("Cannot register capability type " + type + " multiple times");
cap.onRegister();
}
}
return cap;
}
// INTERNAL
private static final Type AUTO_REGISTER = Type.getType(AutoRegisterCapability.class);
private final IdentityHashMap<String, Capability<?>> providers = new IdentityHashMap<>();
public void injectCapabilities(List<ModFileScanData> data)
{
var autos = data.stream()
private record Key(String type, ResourceLocation name) {};
private static final Map<Key, Capability<?>> providers = new HashMap<>();
@ApiStatus.Internal
public static void injectCapabilities(ModList modlist) {
var autos = modlist.getAllScanData().stream()
.flatMap(e -> e.getAnnotations().stream())
.filter(a -> AUTO_REGISTER.equals(a.annotationType()))
.map(a -> a.clazz())
@@ -71,13 +96,18 @@ public enum CapabilityManager
.sorted(Comparator.comparing(Type::toString))
.toList();
for (var auto : autos)
{
for (var auto : autos) {
LOGGER.debug(Logging.CAPABILITIES, "Attempting to automatically register: " + auto);
get(auto.getInternalName(), true);
get(auto.getInternalName(), null, true);
}
@SuppressWarnings("removal")
var event = new RegisterCapabilitiesEvent();
ModLoader.get().postEvent(event);
}
private static void error(String message) {
LOGGER.error(Logging.CAPABILITIES, message);
throw new IllegalStateException(message);
}
}
@@ -10,6 +10,7 @@ import javax.annotation.ParametersAreNonnullByDefault;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.core.Direction;
import net.minecraft.core.HolderLookup;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.event.ForgeEventFactory;
@@ -21,8 +22,7 @@ import java.util.function.Supplier;
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public abstract class CapabilityProvider<B extends ICapabilityProviderImpl<B>> implements ICapabilityProviderImpl<B>
{
public abstract class CapabilityProvider<B extends ICapabilityProviderImpl<B>> implements ICapabilityProviderImpl<B> {
@VisibleForTesting
static boolean SUPPORTS_LAZY_CAPABILITIES = true;
@@ -33,33 +33,28 @@ public abstract class CapabilityProvider<B extends ICapabilityProviderImpl<B>> i
private boolean isLazy = false;
private Supplier<ICapabilityProvider> lazyParentSupplier = null;
private CompoundTag lazyData = null;
private HolderLookup.Provider registryAccess = null;
private boolean initialized = false;
protected CapabilityProvider(Class<B> baseClass)
{
protected CapabilityProvider(Class<B> baseClass) {
this(baseClass, false);
}
protected CapabilityProvider(final Class<B> baseClass, final boolean isLazy)
{
protected CapabilityProvider(final Class<B> baseClass, final boolean isLazy) {
this.baseClass = baseClass;
this.isLazy = SUPPORTS_LAZY_CAPABILITIES && isLazy;
}
protected final void gatherCapabilities()
{
protected final void gatherCapabilities() {
gatherCapabilities(() -> null);
}
protected final void gatherCapabilities(@Nullable ICapabilityProvider parent)
{
protected final void gatherCapabilities(@Nullable ICapabilityProvider parent) {
gatherCapabilities(() -> parent);
}
protected final void gatherCapabilities(@Nullable Supplier<ICapabilityProvider> parent)
{
if (isLazy && !initialized)
{
protected final void gatherCapabilities(@Nullable Supplier<ICapabilityProvider> parent) {
if (isLazy && !initialized) {
lazyParentSupplier = parent == null ? () -> null : parent;
return;
}
@@ -67,86 +62,51 @@ public abstract class CapabilityProvider<B extends ICapabilityProviderImpl<B>> i
doGatherCapabilities(parent == null ? null : parent.get());
}
private void doGatherCapabilities(@Nullable ICapabilityProvider parent)
{
private void doGatherCapabilities(@Nullable ICapabilityProvider parent) {
this.capabilities = ForgeEventFactory.gatherCapabilities(baseClass, getProvider(), parent);
this.initialized = true;
}
@SuppressWarnings("unchecked")
@NotNull
B getProvider()
{
B getProvider() {
return (B)this;
}
protected final @Nullable CapabilityDispatcher getCapabilities()
{
if (isLazy && !initialized)
{
protected final @Nullable CapabilityDispatcher getCapabilities() {
if (isLazy && !initialized) {
doGatherCapabilities(lazyParentSupplier == null ? null : lazyParentSupplier.get());
if (lazyData != null)
{
deserializeCaps(lazyData);
}
deserializeCaps(registryAccess, lazyData);
}
return capabilities;
}
public final boolean areCapsCompatible(CapabilityProvider<B> other)
{
return areCapsCompatible(other.getCapabilities());
}
public final boolean areCapsCompatible(@Nullable CapabilityDispatcher other)
{
final CapabilityDispatcher disp = getCapabilities();
if (disp == null)
{
if (other == null)
{
return true;
}
else
{
return other.areCompatible(null);
}
}
else
{
return disp.areCompatible(other);
}
}
protected final @Nullable CompoundTag serializeCaps()
{
protected final @Nullable CompoundTag serializeCaps(HolderLookup.Provider registryAccess) {
if (isLazy && !initialized)
{
return lazyData;
}
final CapabilityDispatcher disp = getCapabilities();
var disp = getCapabilities();
if (disp != null)
{
return disp.serializeNBT();
}
return disp.serializeNBT(registryAccess);
return null;
}
protected final void deserializeCaps(CompoundTag tag)
{
if (isLazy && !initialized)
{
lazyData = tag;
protected final void deserializeCaps(HolderLookup.Provider registryAccess, CompoundTag tag) {
if (isLazy && !initialized) {
this.lazyData = tag;
this.registryAccess = registryAccess;
return;
}
final CapabilityDispatcher disp = getCapabilities();
var disp = getCapabilities();
if (disp != null)
{
disp.deserializeNBT(tag);
}
disp.deserializeNBT(registryAccess, tag);
this.lazyData = null;
this.registryAccess = null;
}
/*
@@ -157,8 +117,7 @@ public abstract class CapabilityProvider<B extends ICapabilityProviderImpl<B>> i
* when they are finished.
* Be sure to make your invalidate callbaks recursion safe.
*/
public void invalidateCaps()
{
public void invalidateCaps() {
this.valid = false;
final CapabilityDispatcher disp = getCapabilities();
if (disp != null)
@@ -170,15 +129,13 @@ public abstract class CapabilityProvider<B extends ICapabilityProviderImpl<B>> i
* Modders can use this if they need to copy caps from one removed provider to a new one.
* It is expected the modders who call this function, then call invalidateCaps() to invalidate the provider again.
*/
public void reviveCaps()
{
public void reviveCaps() {
this.valid = true; //Stupid players don't copy the entity when transporting across worlds.
}
@Override
@NotNull
public <T> LazyOptional<T> getCapability(@NotNull Capability<T> cap, @Nullable Direction side)
{
public <T> LazyOptional<T> getCapability(@NotNull Capability<T> cap, @Nullable Direction side) {
final CapabilityDispatcher disp = getCapabilities();
return !valid || disp == null ? LazyOptional.empty() : disp.getCapability(cap, side);
}
@@ -187,42 +144,35 @@ public abstract class CapabilityProvider<B extends ICapabilityProviderImpl<B>> i
* Special implementation for cases which have a superclass and can't extend CapabilityProvider directly.
* See {@link LevelChunk}
*/
public static class AsField<B extends ICapabilityProviderImpl<B>> extends CapabilityProvider<B>
{
public static class AsField<B extends ICapabilityProviderImpl<B>> extends CapabilityProvider<B> {
private final B owner;
public AsField(Class<B> baseClass, B owner)
{
public AsField(Class<B> baseClass, B owner) {
super(baseClass);
this.owner = owner;
}
public AsField(Class<B> baseClass, B owner, boolean isLazy)
{
public AsField(Class<B> baseClass, B owner, boolean isLazy) {
super(baseClass, isLazy);
this.owner = owner;
}
public void initInternal()
{
public void initInternal() {
gatherCapabilities();
}
@Nullable
public CompoundTag serializeInternal()
{
return serializeCaps();
public CompoundTag serializeInternal(HolderLookup.Provider registryAccess) {
return serializeCaps(registryAccess);
}
public void deserializeInternal(CompoundTag tag)
{
deserializeCaps(tag);
public void deserializeInternal(HolderLookup.Provider registryAccess, CompoundTag tag) {
deserializeCaps(registryAccess, tag);
}
@Override
@NotNull
B getProvider()
{
B getProvider() {
return owner;
}
};
@@ -21,16 +21,13 @@ import net.minecraftforge.fml.common.asm.CapabilityTokenSubclass;
* }</pre>
*
*/
public abstract class CapabilityToken<T>
{
protected final String getType()
{
public abstract class CapabilityToken<T> {
protected final String getType() {
throw new RuntimeException("This will be implemented by a transformer");
}
@Override
public String toString()
{
public String toString() {
return "CapabilityToken[" + getType() + "]";
}
}
@@ -6,13 +6,9 @@
package net.minecraftforge.common.capabilities;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
@ApiStatus.Internal // Modders should use ICapabilityProvider, this is for Forge
public interface ICapabilityProviderImpl<B extends ICapabilityProviderImpl<B>> extends ICapabilityProvider
{
boolean areCapsCompatible(CapabilityProvider<B> other);
boolean areCapsCompatible(@Nullable CapabilityDispatcher other);
public interface ICapabilityProviderImpl<B extends ICapabilityProviderImpl<B>> extends ICapabilityProvider {
void invalidateCaps();
void reviveCaps();
}
@@ -15,19 +15,21 @@ import net.minecraftforge.fml.event.IModBusEvent;
/**
* This event fires when it is time to register your capabilities.
* @see Capability
*
* @deprecated Use {@link AutoRegisterCapability} annotation on your class.
*/
public final class RegisterCapabilitiesEvent extends Event implements IModBusEvent
{
@Deprecated(forRemoval = true, since = "1.21")
public final class RegisterCapabilitiesEvent extends Event implements IModBusEvent {
/**
* Registers a capability to be consumed by others.
* APIs who define the capability should call this.
* To retrieve the Capability instance, use the @CapabilityInject annotation.
* This is meant to allow Capability consumers to have soft dependencies on the Capability type.
* But be automatically notified when the Class actually exists. Meaning it's safe to create their implementations.
*
* @param type The type to be registered
* To retrieve the Capability instance, use the {@link CapabilityManager} gets functions.
*/
public <T> void register(Class<T> type)
{
Objects.requireNonNull(type,"Attempted to register a capability with invalid type");
CapabilityManager.INSTANCE.get(Type.getInternalName(type), true);
public <T> void register(Class<T> type) {
Objects.requireNonNull(type, "Attempted to register a capability with invalid type");
CapabilityManager.get(Type.getInternalName(type), null, true);
}
}
@@ -20,6 +20,7 @@ import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.core.BlockPos;
import net.minecraft.core.HolderLookup;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.phys.HitResult;
import net.minecraftforge.common.ForgeSpawnEggItem;
@@ -34,11 +35,13 @@ public interface IForgeEntity extends ICapabilitySerializable<CompoundTag> {
return (Entity)this;
}
default void deserializeNBT(CompoundTag nbt) {
@Override
default void deserializeNBT(HolderLookup.Provider registryAccess, CompoundTag nbt) {
self().load(nbt);
}
default CompoundTag serializeNBT() {
@Override
default CompoundTag serializeNBT(HolderLookup.Provider registryAccess) {
var ret = new CompoundTag();
var id = self().getEncodeId();
if (id != null)
@@ -12,7 +12,6 @@ import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.item.*;
import net.minecraft.world.item.component.ItemAttributeModifiers;
import net.minecraft.world.item.enchantment.Enchantment;
import net.minecraft.world.item.enchantment.EnchantmentHelper;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.entity.Entity;
@@ -23,11 +22,11 @@ import net.minecraft.world.entity.monster.EnderMan;
import net.minecraft.world.entity.monster.piglin.PiglinAi;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.EquipmentSlotGroup;
import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.item.crafting.RecipeType;
import net.minecraft.world.InteractionResult;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.Level;
@@ -45,10 +44,17 @@ public interface IForgeItem {
}
/**
* ItemStack sensitive version of getItemAttributeModifiers
* @deprecated In favor of {@link #getDefaultAttributeModifiers(ItemStack)} as it matches vanilla name, and not all cases that call this has the EquipmentSlot argument
*/
@SuppressWarnings("deprecation")
@Deprecated(forRemoval = true, since = "1.21")
default ItemAttributeModifiers getAttributeModifiers(EquipmentSlot slot, ItemStack stack) {
return getDefaultAttributeModifiers(stack);
}
/**
* ItemStack sensitive version of {@link Item#getDefaultAttributeModifiers}
*/
default ItemAttributeModifiers getDefaultAttributeModifiers(ItemStack stack) {
return self().getDefaultAttributeModifiers();
}
@@ -18,8 +18,10 @@ import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.EquipmentSlotGroup;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.component.ItemAttributeModifiers;
import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.stats.Stats;
import net.minecraft.world.InteractionResult;
@@ -403,4 +405,11 @@ public interface IForgeItemStack {
default boolean canGrindstoneRepair() {
return self().getItem().canGrindstoneRepair(self());
}
/**
* ItemStack and Slot sensitive version of {@link Item#getItemAttributeModifiers}
*/
default ItemAttributeModifiers getDefaultAttributeModifiers() {
return self().getItem().getDefaultAttributeModifiers(self());
}
}
@@ -23,6 +23,7 @@ import net.minecraft.server.packs.resources.SimpleJsonResourceReloadListener;
import net.minecraft.util.profiling.ProfilerFiller;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.util.GsonHelper;
import net.minecraft.core.RegistryAccess;
import net.minecraft.resources.ResourceLocation;
public class LootModifierManager extends SimpleJsonResourceReloadListener {
@@ -30,10 +31,12 @@ public class LootModifierManager extends SimpleJsonResourceReloadListener {
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();
private static final String FOLDER = "loot_modifiers";
private final RegistryAccess registries;
private Map<ResourceLocation, IGlobalLootModifier> modifiers = ImmutableMap.of();
public LootModifierManager() {
public LootModifierManager(RegistryAccess registries) {
super(GSON, FOLDER);
this.registries = registries;
}
@Override
@@ -68,12 +71,13 @@ public class LootModifierManager extends SimpleJsonResourceReloadListener {
@Override
protected void apply(Map<ResourceLocation, JsonElement> resources, ResourceManager resourceManagerIn, ProfilerFiller profilerIn) {
Builder<ResourceLocation, IGlobalLootModifier> builder = ImmutableMap.builder();
var ops = registries.createSerializationContext(JsonOps.INSTANCE);
resources.forEach((location, json) -> {
IGlobalLootModifier.DIRECT_CODEC.parse(JsonOps.INSTANCE, json)
IGlobalLootModifier.DIRECT_CODEC.parse(ops, json)
// log error if parse fails
.resultOrPartial(errorMsg -> LOGGER.warn("Could not decode GlobalLootModifier with json id {} - error: {}", location, errorMsg))
.ifError(error -> LOGGER.warn("Could not decode GlobalLootModifier with json id {} - error: {}", location, error.message()))
// add loot modifier if parse succeeds
.ifPresent(modifier -> builder.put(location, modifier));
.ifSuccess(modifier -> builder.put(location, modifier));
});
this.modifiers = builder.build();
}
@@ -1,3 +1,8 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.common.util;
@@ -13,14 +13,10 @@ import net.minecraft.nbt.Tag;
* code base that can be serialized to and from a NBT tag.
*
* @deprecated // Mojang has switched most things to Codecs and registry context, probably worth deleting this.
*
* Most cases this is used for Capabilities, and should use Components attached to the object that the cap is attached to.
*/
public interface INBTSerializable<T extends Tag> {
default T serializeNBT() { return null; }
default T serializeNBT(HolderLookup.Provider registryAccess) {
return serializeNBT();
}
default void deserializeNBT(T nbt) { }
default void deserializeNBT(HolderLookup.Provider registryAccess, T nbt) {
deserializeNBT(nbt);
}
T serializeNBT(HolderLookup.Provider registryAccess);
void deserializeNBT(HolderLookup.Provider registryAccess, T nbt);
}
@@ -6,7 +6,6 @@
package net.minecraftforge.common.util;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.HolderLookup.Provider;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.saveddata.SavedData;
import net.minecraft.world.level.storage.DimensionDataStorage;
@@ -23,18 +22,10 @@ public class LevelCapabilityData extends SavedData {
this.serializable = serializable;
}
public void read(CompoundTag nbt) {
this.capNBT = nbt;
if (serializable != null) {
serializable.deserializeNBT(this.capNBT);
this.capNBT = null;
}
}
@Override
public CompoundTag save(CompoundTag nbt, HolderLookup.Provider provider) {
if (serializable != null)
nbt = serializable.serializeNBT();
nbt = serializable.serializeNBT(provider);
return nbt;
}
@@ -43,27 +34,18 @@ public class LevelCapabilityData extends SavedData {
return true;
}
public void setCapabilities(INBTSerializable<CompoundTag> capabilities) {
this.serializable = capabilities;
if (this.capNBT != null && serializable != null) {
serializable.deserializeNBT(this.capNBT);
this.capNBT = null;
}
}
public static LevelCapabilityData compute(DimensionDataStorage data, @Nullable INBTSerializable<CompoundTag> caps) {
var factory = new Factory<>(
() -> new LevelCapabilityData(caps),
(tag, lookup) -> {
var ret = new LevelCapabilityData(caps);
ret.read(tag);
if (caps != null)
caps.deserializeNBT(lookup, tag);
return ret;
},
null
);
var ret = data.computeIfAbsent(factory, ID);
ret.setCapabilities(caps);
return ret;
return data.computeIfAbsent(factory, ID);
}
}
@@ -5,6 +5,7 @@
package net.minecraftforge.energy;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.IntTag;
import net.minecraft.nbt.Tag;
import net.minecraftforge.common.util.INBTSerializable;
@@ -15,30 +16,25 @@ import net.minecraftforge.common.util.INBTSerializable;
* Derived from the Redstone Flux power system designed by King Lemming and originally utilized in Thermal Expansion and related mods.
* Created with consent and permission of King Lemming and Team CoFH. Released with permission under LGPL 2.1 when bundled with Forge.
*/
public class EnergyStorage implements IEnergyStorage, INBTSerializable<Tag>
{
public class EnergyStorage implements IEnergyStorage, INBTSerializable<Tag> {
protected int energy;
protected int capacity;
protected int maxReceive;
protected int maxExtract;
public EnergyStorage(int capacity)
{
public EnergyStorage(int capacity) {
this(capacity, capacity, capacity, 0);
}
public EnergyStorage(int capacity, int maxTransfer)
{
public EnergyStorage(int capacity, int maxTransfer) {
this(capacity, maxTransfer, maxTransfer, 0);
}
public EnergyStorage(int capacity, int maxReceive, int maxExtract)
{
public EnergyStorage(int capacity, int maxReceive, int maxExtract) {
this(capacity, maxReceive, maxExtract, 0);
}
public EnergyStorage(int capacity, int maxReceive, int maxExtract, int energy)
{
public EnergyStorage(int capacity, int maxReceive, int maxExtract, int energy) {
this.capacity = capacity;
this.maxReceive = maxReceive;
this.maxExtract = maxExtract;
@@ -46,8 +42,7 @@ public class EnergyStorage implements IEnergyStorage, INBTSerializable<Tag>
}
@Override
public int receiveEnergy(int maxReceive, boolean simulate)
{
public int receiveEnergy(int maxReceive, boolean simulate) {
if (!canReceive())
return 0;
@@ -58,8 +53,7 @@ public class EnergyStorage implements IEnergyStorage, INBTSerializable<Tag>
}
@Override
public int extractEnergy(int maxExtract, boolean simulate)
{
public int extractEnergy(int maxExtract, boolean simulate) {
if (!canExtract())
return 0;
@@ -70,20 +64,17 @@ public class EnergyStorage implements IEnergyStorage, INBTSerializable<Tag>
}
@Override
public int getEnergyStored()
{
public int getEnergyStored() {
return energy;
}
@Override
public int getMaxEnergyStored()
{
public int getMaxEnergyStored() {
return capacity;
}
@Override
public boolean canExtract()
{
public boolean canExtract() {
return this.maxExtract > 0;
}
@@ -94,14 +85,12 @@ public class EnergyStorage implements IEnergyStorage, INBTSerializable<Tag>
}
@Override
public Tag serializeNBT()
{
public Tag serializeNBT(HolderLookup.Provider registryAccess) {
return IntTag.valueOf(this.getEnergyStored());
}
@Override
public void deserializeNBT(Tag nbt)
{
public void deserializeNBT(HolderLookup.Provider registryAccess, Tag nbt) {
if (!(nbt instanceof IntTag intNbt))
throw new IllegalArgumentException("Can not deserialize to an instance that isn't the default implementation");
this.energy = intNbt.getAsInt();
@@ -800,35 +800,35 @@ public final class ForgeEventFactory {
}
public static void onPlayerPreTick(Player player) {
post(new TickEvent.PlayerTickEvent(TickEvent.Phase.START, player));
post(new TickEvent.PlayerTickEvent.Pre(player));
}
public static void onPlayerPostTick(Player player) {
post(new TickEvent.PlayerTickEvent(TickEvent.Phase.END, player));
post(new TickEvent.PlayerTickEvent.Post(player));
}
public static void onPreLevelTick(Level level, BooleanSupplier haveTime) {
post(new TickEvent.LevelTickEvent(level.isClientSide ? LogicalSide.CLIENT : LogicalSide.SERVER, TickEvent.Phase.START, level, haveTime));
post(new TickEvent.LevelTickEvent.Pre(level.isClientSide ? LogicalSide.CLIENT : LogicalSide.SERVER, level, haveTime));
}
public static void onPostLevelTick(Level level, BooleanSupplier haveTime) {
post(new TickEvent.LevelTickEvent(level.isClientSide ? LogicalSide.CLIENT : LogicalSide.SERVER, TickEvent.Phase.END, level, haveTime));
post(new TickEvent.LevelTickEvent.Post(level.isClientSide ? LogicalSide.CLIENT : LogicalSide.SERVER, level, haveTime));
}
public static void onPreClientTick() {
post(new TickEvent.ClientTickEvent(TickEvent.Phase.START));
post(new TickEvent.ClientTickEvent.Pre());
}
public static void onPostClientTick() {
post(new TickEvent.ClientTickEvent(TickEvent.Phase.END));
post(new TickEvent.ClientTickEvent.Post());
}
public static void onPreServerTick(BooleanSupplier haveTime, MinecraftServer server) {
post(new TickEvent.ServerTickEvent(TickEvent.Phase.START, haveTime, server));
post(new TickEvent.ServerTickEvent.Pre(haveTime, server));
}
public static void onPostServerTick(BooleanSupplier haveTime, MinecraftServer server) {
post(new TickEvent.ServerTickEvent(TickEvent.Phase.END, haveTime, server));
post(new TickEvent.ServerTickEvent.Post(haveTime, server));
}
public static WeightedRandomList<MobSpawnSettings.SpawnerData> getPotentialSpawns(LevelAccessor level, MobCategory category, BlockPos pos, WeightedRandomList<MobSpawnSettings.SpawnerData> oldList) {
@@ -1,3 +1,8 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.event;
import net.minecraft.core.component.DataComponentMap;
@@ -16,8 +16,7 @@ import net.minecraft.world.level.Level;
import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.fml.LogicalSide;
public class TickEvent extends Event
{
public class TickEvent extends Event {
public enum Type {
LEVEL, PLAYER, CLIENT, SERVER, RENDER;
}
@@ -25,11 +24,12 @@ public class TickEvent extends Event
public enum Phase {
START, END;
}
public final Type type;
public final LogicalSide side;
public final Phase phase;
public TickEvent(Type type, LogicalSide side, Phase phase)
{
public TickEvent(Type type, LogicalSide side, Phase phase) {
this.type = type;
this.side = side;
this.phase = phase;
@@ -39,8 +39,7 @@ public class TickEvent extends Event
private final BooleanSupplier haveTime;
private final MinecraftServer server;
public ServerTickEvent(Phase phase, BooleanSupplier haveTime, MinecraftServer server)
{
protected ServerTickEvent(BooleanSupplier haveTime, MinecraftServer server, Phase phase) {
super(Type.SERVER, LogicalSide.SERVER, phase);
this.haveTime = haveTime;
this.server = server;
@@ -48,36 +47,56 @@ public class TickEvent extends Event
/**
* @return {@code true} whether the server has enough time to perform any
* additional tasks (usually IO related) during the current tick,
* otherwise {@code false}
* additional tasks (usually IO related) during the current tick,
* otherwise {@code false}
*/
public boolean haveTime()
{
public boolean haveTime() {
return this.haveTime.getAsBoolean();
}
/**
* {@return the server instance}
*/
public MinecraftServer getServer()
{
public MinecraftServer getServer() {
return server;
}
public static class Pre extends ServerTickEvent {
public Pre(BooleanSupplier haveTime, MinecraftServer server) {
super(haveTime, server, Phase.START);
}
}
public static class Post extends ServerTickEvent {
public Post(BooleanSupplier haveTime, MinecraftServer server) {
super(haveTime, server, Phase.END);
}
}
}
public static class ClientTickEvent extends TickEvent {
public ClientTickEvent(Phase phase)
{
protected ClientTickEvent(Phase phase) {
super(Type.CLIENT, LogicalSide.CLIENT, phase);
}
public static class Pre extends ClientTickEvent {
public Pre() {
super(Phase.START);
}
}
public static class Post extends ClientTickEvent {
public Post() {
super(Phase.END);
}
}
}
public static class LevelTickEvent extends TickEvent {
public final Level level;
private final BooleanSupplier haveTime;
public LevelTickEvent(LogicalSide side, Phase phase, Level level, BooleanSupplier haveTime)
{
protected LevelTickEvent(LogicalSide side, Level level, BooleanSupplier haveTime, Phase phase) {
super(Type.LEVEL, side, phase);
this.level = level;
this.haveTime = haveTime;
@@ -85,24 +104,46 @@ public class TickEvent extends Event
/**
* @return {@code true} whether the server has enough time to perform any
* additional tasks (usually IO related) during the current tick,
* otherwise {@code false}
*
* additional tasks (usually IO related) during the current tick,
* otherwise {@code false}
* @see ServerTickEvent#haveTime()
*/
public boolean haveTime()
{
public boolean haveTime() {
return this.haveTime.getAsBoolean();
}
public static class Pre extends LevelTickEvent {
public Pre(LogicalSide side, Level level, BooleanSupplier haveTime) {
super(side, level, haveTime, Phase.START);
}
}
public static class Post extends LevelTickEvent {
public Post(LogicalSide side, Level level, BooleanSupplier haveTime) {
super(side, level, haveTime, Phase.END);
}
}
}
public static class PlayerTickEvent extends TickEvent {
public final Player player;
public PlayerTickEvent(Phase phase, Player player)
{
protected PlayerTickEvent(Player player, Phase phase) {
super(Type.PLAYER, player instanceof ServerPlayer ? LogicalSide.SERVER : LogicalSide.CLIENT, phase);
this.player = player;
}
public static class Pre extends PlayerTickEvent {
public Pre(Player player) {
super(player, Phase.START);
}
}
public static class Post extends PlayerTickEvent {
public Post(Player player) {
super(player, Phase.END);
}
}
}
public static class RenderTickEvent extends TickEvent {
@@ -117,16 +158,17 @@ public class TickEvent extends Event
return this.timer;
}
public static class Start extends RenderTickEvent {
public Start(DeltaTracker timer) {
public static class Pre extends RenderTickEvent {
public Pre(DeltaTracker timer) {
super(Phase.START, timer);
}
}
public static class End extends RenderTickEvent {
public End(DeltaTracker timer) {
public static class Post extends RenderTickEvent {
public Post(DeltaTracker timer) {
super(Phase.END, timer);
}
}
}
}
@@ -5,33 +5,40 @@
package net.minecraftforge.registries;
import com.google.common.collect.ImmutableMap;
import net.minecraft.core.Registry;
import net.minecraft.core.RegistrySynchronization;
import net.minecraft.resources.RegistryDataLoader;
import net.minecraft.resources.ResourceKey;
import org.jetbrains.annotations.ApiStatus;
import java.util.*;
import java.util.stream.Stream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Supplier;
@ApiStatus.Internal
public final class DataPackRegistriesHooks {
private DataPackRegistriesHooks() {} // utility class
private static final Map<ResourceKey<? extends Registry<?>>, RegistryDataLoader.RegistryData<?>> NETWORKABLE_REGISTRIES = new LinkedHashMap<>();
// Mutable views of vanilla registries
private static final List<RegistryDataLoader.RegistryData<?>> SYNCHRONIZED_REGISTRIES = new ArrayList<>();
private static final List<RegistryDataLoader.RegistryData<?>> WORLDGEN_REGISTRIES = new ArrayList<>();
private static final Set<ResourceKey<? extends Registry<?>>> SYNCED_CUSTOM_REGISTRIES = new HashSet<>();
private static final Set<ResourceKey<? extends Registry<?>>> SYNCED_CUSTOM_REGISTRIES_VIEW = Collections.unmodifiableSet(SYNCED_CUSTOM_REGISTRIES);
private static final Set<ResourceKey<? extends Registry<?>>> NETWORKABLE_REGISTRIES = new HashSet<>();
// Out custom registries, things we need to make sure the client has
private static final Set<ResourceKey<? extends Registry<?>>> SYNCHRONIZED_REGISTRIES_CUSTOM = new HashSet<>();
private static final Set<ResourceKey<? extends Registry<?>>> SYNCHRONIZED_REGISTRIESD_CUSTOM_VIEW = Collections.unmodifiableSet(SYNCHRONIZED_REGISTRIES_CUSTOM);
/* Internal forge hook for retaining mutable access to RegistryAccess's codec registry when it bootstraps. */
public static Map<ResourceKey<? extends Registry<?>>, RegistryDataLoader.RegistryData<?>> grabNetworkableRegistries(ImmutableMap.Builder<ResourceKey<? extends Registry<?>>, RegistryDataLoader.RegistryData<?>> builder) {
if (!StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE).getCallerClass().equals(RegistrySynchronization.class))
throw new IllegalCallerException("Attempted to call DataPackRegistriesHooks#grabNetworkableRegistries!");
NETWORKABLE_REGISTRIES.forEach(builder::put);
NETWORKABLE_REGISTRIES.clear();
NETWORKABLE_REGISTRIES.putAll(builder.build());
return Collections.unmodifiableMap(NETWORKABLE_REGISTRIES);
public static List<RegistryDataLoader.RegistryData<?>> grabSynchronizedRegistries(RegistryDataLoader.RegistryData<?>... vanilla) {
if (!StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE).getCallerClass().equals(RegistryDataLoader.class))
throw new IllegalCallerException("Attempted to call DataPackRegistriesHooks#grabSynchronizedRegistries!");
for (var reg : vanilla)
SYNCHRONIZED_REGISTRIES.add(reg);
return Collections.unmodifiableList(SYNCHRONIZED_REGISTRIES);
}
/* Internal forge method, registers a datapack registry codec and folder. */
@@ -39,25 +46,12 @@ public final class DataPackRegistriesHooks {
RegistryDataLoader.RegistryData<T> loaderData = data.loaderData();
WORLDGEN_REGISTRIES.add(loaderData);
if (data.networkCodec() != null) {
SYNCED_CUSTOM_REGISTRIES.add(loaderData.key());
NETWORKABLE_REGISTRIES.put(loaderData.key(), new RegistryDataLoader.RegistryData<>(loaderData.key(), data.networkCodec(), false));
NETWORKABLE_REGISTRIES.add(loaderData.key());
SYNCHRONIZED_REGISTRIES_CUSTOM.add(loaderData.key());
SYNCHRONIZED_REGISTRIES.add(new RegistryDataLoader.RegistryData<>(loaderData.key(), data.networkCodec(), false));
}
}
/**
* {@return An unmodifiable view of the list of datapack registries}.
* These registries are loaded from per-world datapacks on server startup.
*/
@Deprecated // Use RegistryDataLoader#WORLDGEN_REGISTRIES instead
public static List<RegistryDataLoader.RegistryData<?>> getDataPackRegistries() {
return Collections.unmodifiableList(WORLDGEN_REGISTRIES);
}
@Deprecated // Use RegistryDataLoader#WORLDGEN_REGISTRIES instead
public static Stream<RegistryDataLoader.RegistryData<?>> getDataPackRegistriesWithDimensions() {
return WORLDGEN_REGISTRIES.stream();
}
/**
* Captures a mutable view of {@link RegistryDataLoader#WORLDGEN_REGISTRIES} so that we can register modded entries during the registry event.
* All uses should use that field instead of this class.
@@ -71,12 +65,27 @@ public final class DataPackRegistriesHooks {
return Collections.unmodifiableList(WORLDGEN_REGISTRIES);
}
/**
* Captures a mutable view of {@link RegistrySynchronization#NETWORKABLE_REGISTRIES} so that we can register modded entries during the registry event.
* All users should use that field instead of this class.
*
* @param vanilla Supplier for the default vanilla values
* @return An unmodifiable set of networksable registry names
*/
public static Set<ResourceKey<? extends Registry<?>>> grabNetworkableRegistries(Supplier<Set<ResourceKey<? extends Registry<?>>>> vanilla) {
if (!StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE).getCallerClass().equals(RegistrySynchronization.class))
throw new IllegalCallerException("Attempted to call DataPackRegistriesHooks#grabNetworkableRegistries!");
NETWORKABLE_REGISTRIES.addAll(vanilla.get());
return Collections.unmodifiableSet(NETWORKABLE_REGISTRIES);
}
/**
* {@return An unmodifiable view of the set of synced non-vanilla datapack registry IDs}
* Clients must have each of a server's synced datapack registries to be able to connect to that server;
* vanilla clients therefore cannot connect if this list is non-empty on the server.
*/
public static Set<ResourceKey<? extends Registry<?>>> getSyncedCustomRegistries() {
return SYNCED_CUSTOM_REGISTRIES_VIEW;
return SYNCHRONIZED_REGISTRIESD_CUSTOM_VIEW;
}
}
@@ -0,0 +1,3 @@
{
"value": "network_data_registry:test_value"
}
@@ -1,3 +1,8 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.debug.client;
import net.minecraftforge.client.event.CustomizeGuiOverlayEvent;
@@ -16,6 +16,7 @@ import net.minecraft.world.item.CreativeModeTabs;
import net.minecraft.world.item.DyeColor;
import net.minecraft.world.item.DyeItem;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
@@ -32,6 +33,8 @@ public class CreativeModeTabTest {
private static final ResourceKey<CreativeModeTab> LOGS = ResourceKey.create(Registries.CREATIVE_MODE_TAB, ResourceLocation.fromNamespaceAndPath(MOD_ID, "logs"));
private static final ResourceKey<CreativeModeTab> STONE = ResourceKey.create(Registries.CREATIVE_MODE_TAB, ResourceLocation.fromNamespaceAndPath(MOD_ID, "stone"));
private static final ResourceKey<CreativeModeTab> COLORS = ResourceKey.create(Registries.CREATIVE_MODE_TAB, ResourceLocation.fromNamespaceAndPath(MOD_ID, "colors"));
private static final ResourceKey<CreativeModeTab> SEARCH = ResourceKey.create(Registries.CREATIVE_MODE_TAB, ResourceLocation.fromNamespaceAndPath(MOD_ID, "search"));
public CreativeModeTabTest() {
if (!ENABLED)
@@ -58,7 +61,8 @@ public class CreativeModeTabTest {
})
.build());
helper.register(STONE, CreativeModeTab.builder().icon(() -> new ItemStack(Blocks.STONE))
helper.register(STONE, CreativeModeTab.builder()
.icon(() -> new ItemStack(Blocks.STONE))
.title(Component.literal("Stone"))
.withLabelColor(0x0000FF)
.displayItems((params, output) -> {
@@ -67,16 +71,29 @@ public class CreativeModeTabTest {
output.accept(new ItemStack(Blocks.DIORITE));
output.accept(new ItemStack(Blocks.ANDESITE));
})
.withTabsAfter(CreativeModeTabs.BUILDING_BLOCKS)
.withTabsBefore(LOGS)
.build());
helper.register(ResourceLocation.fromNamespaceAndPath(MOD_ID, "colors"), CreativeModeTab.builder().title(Component.literal("Colors"))
helper.register(COLORS, CreativeModeTab.builder()
.title(Component.literal("Colors"))
.displayItems((params, output) -> {
for (DyeColor color : DyeColor.values())
output.accept(DyeItem.byColor(color));
})
.withTabFactory(CreativeModeColorTab::new)
.withTabsBefore(CreativeModeTabs.COLORED_BLOCKS)
.withTabsBefore(STONE)
.build()
);
helper.register(SEARCH, CreativeModeTab.builder()
.title(Component.literal("Search"))
.icon(() -> new ItemStack(Items.BOOKSHELF))
.displayItems((params, output) -> {
for (DyeColor color : DyeColor.values())
output.accept(DyeItem.byColor(color));
})
.withTabsBefore(COLORS)
.withSearchBar()
.build()
);
@@ -1,3 +1,8 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.debug.gameplay.biome;
import net.minecraft.core.HolderLookup;
@@ -1,3 +1,8 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.debug.gameplay.item;
import net.minecraft.core.component.DataComponents;
@@ -106,15 +106,18 @@ public class GlobalLootModifiersTest extends BaseTestMod {
private static final RegistryObject<Item> TEST_ITEM = ITEMS.register("test", () -> new BlockItem(TEST_BLOCK.get(), new Item.Properties()));
public GlobalLootModifiersTest() {
testItem(lookup -> getTestItem(lookup.lookup(Registries.ENCHANTMENT).get()));
testItem(lookup -> getSmelterAxe(lookup.lookup(Registries.ENCHANTMENT).get(), true));
}
private static ItemStack getTestItem(HolderLookup<Enchantment> lookup) {
var smelt = new ItemStack(Items.IRON_AXE);
var enchants = new ItemEnchantments.Mutable(EnchantmentHelper.getEnchantmentsForCrafting(smelt));
private static ItemStack getSmelterAxe(HolderLookup<Enchantment> lookup, boolean enchanted) {
var item = new ItemStack(Items.IRON_AXE);
if (!enchanted)
return item;
var enchants = new ItemEnchantments.Mutable(EnchantmentHelper.getEnchantmentsForCrafting(item));
enchants.set(lookup.getOrThrow(SMELT), 1);
smelt.set(DataComponents.ENCHANTMENTS, enchants.toImmutable());
return smelt;
item.set(DataComponents.ENCHANTMENTS, enchants.toImmutable());
return item;
}
@SubscribeEvent
@@ -128,24 +131,36 @@ public class GlobalLootModifiersTest extends BaseTestMod {
event.getGenerator().addProvider(event.includeServer(), new LootProvider(out, lookup));
}
// Tests the Enchantment condition, as well as the ability to completely override the returned values.
@GameTest(template = "forge:empty3x3x3")
public static void test_smelting_modifier(GameTestHelper helper) {
var center = new BlockPos(1, 1, 1);
helper.setBlock(center, Blocks.OAK_LOG);
var smelt = getTestItem(helper.getLevel().holderLookup(Registries.ENCHANTMENT));
public static void smellting(GameTestHelper helper) {
var player = helper.makeMockServerPlayer();
player.setItemSlot(EquipmentSlot.MAINHAND, smelt);
player.gameMode.destroyBlock(helper.absolutePos(center));
var center = new BlockPos(1, 1, 1);
var enchants = helper.getLevel().holderLookup(Registries.ENCHANTMENT);
var smelt = getSmelterAxe(enchants, true);
var normal = getSmelterAxe(enchants, false);
// Harvesting with normal axe should just dorp log
player.setItemSlot(EquipmentSlot.MAINHAND, normal);
helper.setBlock(center, Blocks.OAK_LOG);
player.gameMode.destroyBlock(helper.absolutePos(center));
helper.assertItemEntityPresent(Items.OAK_LOG, center, 1.0);
//Reset
helper.killAllEntities();
// Test smelting enchantment, should result in charcoal
player.setItemSlot(EquipmentSlot.MAINHAND, smelt);
helper.setBlock(center, Blocks.OAK_LOG);
player.gameMode.destroyBlock(helper.absolutePos(center));
helper.assertItemEntityPresent(Items.CHARCOAL, center, 1.0);
helper.succeed();
}
// Tests the table name condition by duplicating the drops for our test block, but not for anything else.
@GameTest(template = "forge:empty3x3x3")
public static void table_name_condition(GameTestHelper helper) {
public static void condition_table_name(GameTestHelper helper) {
var center = new BlockPos(1, 1, 1);
var player = helper.makeMockServerPlayer();
@@ -162,6 +177,29 @@ public class GlobalLootModifiersTest extends BaseTestMod {
helper.succeed();
}
@GameTest(template = "forge:empty3x3x3")
public static void silk_reentrant(GameTestHelper helper) {
var center = new BlockPos(1, 1, 1);
var player = helper.makeMockServerPlayer();
var bamboo = new ItemStack(Items.BAMBOO);
var normal = new ItemStack(Items.IRON_AXE);
// Should drop nothing
helper.setBlock(center, Blocks.GLASS);
player.setItemSlot(EquipmentSlot.MAINHAND, normal);
player.gameMode.destroyBlock(helper.absolutePos(center));
helper.assertItemEntityNotPresent(Items.GLASS, center, 1.0);
// Should drop the glass
helper.setBlock(center, Blocks.GLASS);
player.setItemSlot(EquipmentSlot.MAINHAND, bamboo);
player.gameMode.destroyBlock(helper.absolutePos(center));
helper.assertItemEntityPresent(Items.GLASS, center, 1.0);
helper.succeed();
}
private static class ModifierProvider extends GlobalLootModifierProvider {
public ModifierProvider(PackOutput output, String modid, CompletableFuture<HolderLookup.Provider> registries) {
super(output, modid, registries);
@@ -171,6 +209,7 @@ public class GlobalLootModifiersTest extends BaseTestMod {
protected void start(HolderLookup.Provider registries) {
var smelt = registries.lookupOrThrow(Registries.ENCHANTMENT).getOrThrow(SMELT);
// Tested vis breaking a log and checking if we get charcoal
add("smelting", new SmeltingEnchantmentModifier(
new LootItemCondition[]{
MatchTool.toolMatches(
@@ -185,6 +224,8 @@ public class GlobalLootModifiersTest extends BaseTestMod {
})
);
// This has no game test because it relies on random number generation and I can't be bothered to try and force that right now.
add("wheat_harvest", new WheatSeedsConverterModifier(
new LootItemCondition[] {
MatchTool.toolMatches(ItemPredicate.Builder.item().of(Items.SHEARS)).build(),
@@ -193,13 +234,14 @@ public class GlobalLootModifiersTest extends BaseTestMod {
3, Items.WHEAT_SEEDS, Items.WHEAT)
);
// Tested by verifying that we drop 2 test blocks when broken instead of the default 1
add("multiply_loot", new MultiplyDropsModifier(
new LootItemCondition[] {
LootTableIdCondition.builder(TEST_BLOCK.get().getLootTable().location()).build()
}, 2)
);
// Bamboo silk harvests everything
// Bamboo silk harvests everything, Tested by breaking glass and seeing if we get glass back.
add("bamboo_silk", new SilkTouchTestModifier(
new LootItemCondition[] {
MatchTool.toolMatches(ItemPredicate.Builder.item().of(Items.BAMBOO)).build()
@@ -275,7 +317,6 @@ public class GlobalLootModifiersTest extends BaseTestMod {
/**
* When harvesting blocks with bamboo, this modifier is invoked, via the silk_touch_bamboo loot_modifier json
*
*/
private static class SilkTouchTestModifier extends LootModifier {
public static final Supplier<MapCodec<SilkTouchTestModifier>> CODEC = Suppliers.memoize(() ->
@@ -317,7 +358,6 @@ public class GlobalLootModifiersTest extends BaseTestMod {
/**
* When harvesting wheat with shears, this modifier is invoked via the wheat_harvest loot_modifier json<br/>
* This modifier checks how many seeds were harvested and turns X seeds into Y wheat (3:1)
*
*/
private static class WheatSeedsConverterModifier extends LootModifier {
public static final Supplier<MapCodec<WheatSeedsConverterModifier>> CODEC = Suppliers.memoize(() -> RecordCodecBuilder.mapCodec(inst -> codecStart(inst).and(
@@ -0,0 +1,87 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.debug.registries;
import java.util.Set;
import org.slf4j.Logger;
import com.mojang.logging.LogUtils;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.client.Minecraft;
import net.minecraft.core.Registry;
import net.minecraft.core.RegistrySetBuilder;
import net.minecraft.gametest.framework.GameTest;
import net.minecraft.gametest.framework.GameTestHelper;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.common.data.DatapackBuiltinEntriesProvider;
import net.minecraftforge.data.event.GatherDataEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.loading.FMLLoader;
import net.minecraftforge.gametest.GameTestHolder;
import net.minecraftforge.registries.DataPackRegistryEvent;
import net.minecraftforge.test.BaseTestMod;
@GameTestHolder("forge.network_data_registry")
@Mod(NetworkDatapackRegistryTest.MODID)
public class NetworkDatapackRegistryTest extends BaseTestMod {
private static final Logger LOGGER = LogUtils.getLogger();
public static final String MODID = "network_data_registry";
private static final ResourceKey<Registry<DataObject>> REGISTRY_KEY = ResourceKey.createRegistryKey(rl(MODID, "registry"));
private static final ResourceKey<DataObject> TEST_ENTRY = ResourceKey.create(REGISTRY_KEY, rl(MODID, "test_entry"));
private static final ResourceLocation TEST_VALUE = rl(MODID, "test_value");
@SubscribeEvent
public void onNewDatapackRegistry(DataPackRegistryEvent.NewRegistry event) {
event.dataPackRegistry(REGISTRY_KEY, DataObject.DIRECT_CODEC, DataObject.DIRECT_CODEC);
}
@SubscribeEvent
public void onDataGen(GatherDataEvent event) {
var gen = event.getGenerator();
var packOutput = gen.getPackOutput();
gen.addProvider(event.includeServer(), new DatapackBuiltinEntriesProvider(packOutput, event.getLookupProvider(),
new RegistrySetBuilder()
.add(REGISTRY_KEY,
ctx -> {
ctx.register(TEST_ENTRY, new DataObject(TEST_VALUE));
}
),
Set.of(MODID))
);
}
@GameTest(template = "forge:empty3x3x3")
public static void client_has_registry(GameTestHelper helper) {
if (FMLLoader.getDist().isDedicatedServer())
LOGGER.info("client_has_registry test skipped as we're on dedicated server");
else
client_has_registry_client_code(helper);
helper.succeed();
}
// Separate function to not resolve classes until it's called, as it references client only classes.
private static void client_has_registry_client_code(GameTestHelper helper) {
var mc = Minecraft.getInstance();
var level = mc.level;
var reg = level.registryAccess().registry(REGISTRY_KEY);
helper.assertTrue(reg.isPresent(), "Failed to find " + REGISTRY_KEY.location());
var entry = reg.get().get(TEST_ENTRY);
if (entry == null)
helper.fail("Failed to find " + TEST_ENTRY);
helper.assertValueEqual(entry.value, TEST_VALUE, "Loaded entry does not contain expected value");
}
public static record DataObject(ResourceLocation value) {
public static final Codec<DataObject> DIRECT_CODEC = RecordCodecBuilder.create(instance -> instance.group(
ResourceLocation.CODEC.fieldOf("value").forGetter(DataObject::value)
).apply(instance, DataObject::new));
}
}
@@ -12,6 +12,7 @@ import java.util.List;
import java.util.function.Function;
import net.minecraft.world.item.ItemStack;
import net.minecraft.core.HolderLookup;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.CreativeModeTab.TabVisibility;
import net.minecraftforge.event.BuildCreativeModeTabContentsEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
@@ -41,6 +42,10 @@ public abstract class BaseTestMod {
}
}
protected static ResourceLocation rl(String namespace, String path) {
return ResourceLocation.fromNamespaceAndPath(namespace, path);
}
protected void testItem(Function<HolderLookup.Provider, ItemStack> supplier) {
this.testItems.add(supplier);
}