mirror of
https://github.com/MinecraftForge/MinecraftForge.git
synced 2026-11-14 09:05:17 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db4d8a4729 | ||
|
|
0ca1d0ebd0 | ||
|
|
4995902bc0 | ||
|
|
28e55b2843 | ||
|
|
decaace84a | ||
|
|
72f98dc4a3 | ||
|
|
2951c1dac8 | ||
|
|
40a0a16db0 | ||
|
|
520680b037 | ||
|
|
2844bead6e | ||
|
|
d498ec4a45 | ||
|
|
e2d1ca7d0e | ||
|
|
a547327c61 | ||
|
|
e9a7ce9544 | ||
|
|
511be6415c | ||
|
|
4d85053a4d | ||
|
|
4fcf1877c1 | ||
|
|
41fd15fc57 | ||
|
|
8e0845d032 | ||
|
|
c04e533a61 | ||
|
|
54f4997f71 | ||
|
|
3272e995ab | ||
|
|
8edb551571 | ||
|
|
4bf0de4763 | ||
|
|
f6a54436b9 | ||
|
|
7a497cdbd6 | ||
|
|
06336a40d8 | ||
|
|
842c95cfb9 | ||
|
|
aa2f471e87 | ||
|
|
4209d1fc12 | ||
|
|
583f363b6b | ||
|
|
1c633b4624 | ||
|
|
2677511da6 | ||
|
|
387441c045 |
No files matched your search
Vendored
+1
-1
@@ -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*)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
+11
-25
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+6
-1
@@ -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);
|
||||
|
||||
+8
-1
@@ -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());
|
||||
|
||||
+84
-66
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+8
-2
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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_);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -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_));
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -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;
|
||||
|
||||
+13
@@ -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
|
||||
|
||||
+2
-2
@@ -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));
|
||||
|
||||
+11
@@ -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_)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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();
|
||||
}
|
||||
+10
-8
@@ -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;
|
||||
}
|
||||
}
|
||||
+3
@@ -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);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user