Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[1.21.1] Allow mods to add custom FeatureFlags #1538

Merged
merged 10 commits into from
Nov 15, 2024
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
--- a/net/minecraft/client/gui/screens/worldselection/ExperimentsScreen.java
+++ b/net/minecraft/client/gui/screens/worldselection/ExperimentsScreen.java
@@ -50,6 +_,11 @@

@Override
protected void init() {
+ if (net.minecraft.world.flag.FeatureFlags.REGISTRY.hasAnyModdedFlags()) {
+ this.minecraft.setScreen(new net.neoforged.neoforge.client.gui.ScrollableExperimentsScreen(this.parent, this.packRepository, this.output));
+ return;
+ }
+
this.layout.addTitleHeader(TITLE, this.font);
LinearLayout linearlayout = this.layout.addToContents(LinearLayout.vertical());
linearlayout.addChild(new MultiLineTextWidget(INFO, this.font).setMaxWidth(310), p_293611_ -> p_293611_.paddingBottom(15));
28 changes: 28 additions & 0 deletions patches/net/minecraft/world/flag/FeatureFlag.java.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
--- a/net/minecraft/world/flag/FeatureFlag.java
+++ b/net/minecraft/world/flag/FeatureFlag.java
@@ -3,9 +_,25 @@
public class FeatureFlag {
final FeatureFlagUniverse universe;
final long mask;
+ final int offset;
+ final boolean modded;

+ /**
+ * @deprecated Neo: use {@link #FeatureFlag(FeatureFlagUniverse, int, int, boolean)} instead
+ */
+ @Deprecated
FeatureFlag(FeatureFlagUniverse p_249115_, int p_251067_) {
+ this(p_249115_, p_251067_, 0, false);
+ }
+
+ FeatureFlag(FeatureFlagUniverse p_249115_, int p_251067_, int offset, boolean modded) {
this.universe = p_249115_;
this.mask = 1L << p_251067_;
+ this.offset = offset;
+ this.modded = modded;
+ }
+
+ public boolean isModded() {
+ return modded;
}
}
44 changes: 44 additions & 0 deletions patches/net/minecraft/world/flag/FeatureFlagRegistry.java.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
--- a/net/minecraft/world/flag/FeatureFlagRegistry.java
+++ b/net/minecraft/world/flag/FeatureFlagRegistry.java
@@ -75,6 +_,18 @@
}, p_249796_ -> List.copyOf(this.toNames(p_249796_)));
}

+ public FeatureFlag getFlag(ResourceLocation name) {
XFactHD marked this conversation as resolved.
Show resolved Hide resolved
+ return com.google.common.base.Preconditions.checkNotNull(this.names.get(name), "Flag %s was not registered", name);
+ }
+
+ public Map<ResourceLocation, FeatureFlag> getAllFlags() {
+ return this.names;
+ }
+
+ public boolean hasAnyModdedFlags() {
+ return this.names.values().stream().anyMatch(FeatureFlag::isModded);
+ }
+
public static class Builder {
private final FeatureFlagUniverse universe;
private int id;
@@ -88,11 +_,20 @@
return this.create(ResourceLocation.withDefaultNamespace(p_251782_));
}

+ /**
+ * @deprecated Neo: use {@link #create(ResourceLocation, boolean)} instead
+ */
+ @Deprecated
public FeatureFlag create(ResourceLocation p_250098_) {
- if (this.id >= 64) {
+ return create(p_250098_, false);
+ }
+
+ public FeatureFlag create(ResourceLocation p_250098_, boolean modded) {
+ if (this.id >= 64 && false) {
throw new IllegalStateException("Too many feature flags");
} else {
- FeatureFlag featureflag = new FeatureFlag(this.universe, this.id++);
+ FeatureFlag featureflag = new FeatureFlag(this.universe, this.id % FeatureFlagSet.MAX_CONTAINER_SIZE, this.id / FeatureFlagSet.MAX_CONTAINER_SIZE, modded);
+ this.id++;
FeatureFlag featureflag1 = this.flags.put(p_250098_, featureflag);
if (featureflag1 != null) {
throw new IllegalStateException("Duplicate feature flag " + p_250098_);
188 changes: 188 additions & 0 deletions patches/net/minecraft/world/flag/FeatureFlagSet.java.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
--- a/net/minecraft/world/flag/FeatureFlagSet.java
+++ b/net/minecraft/world/flag/FeatureFlagSet.java
@@ -7,14 +_,21 @@

public final class FeatureFlagSet {
private static final FeatureFlagSet EMPTY = new FeatureFlagSet(null, 0L);
+ private static final long[] EMPTY_EXT_MASK = new long[0];
public static final int MAX_CONTAINER_SIZE = 64;
@Nullable
private final FeatureFlagUniverse universe;
private final long mask;
+ private final long[] extendedMask;

private FeatureFlagSet(@Nullable FeatureFlagUniverse p_250433_, long p_251523_) {
+ this(p_250433_, p_251523_, EMPTY_EXT_MASK);
+ }
+
+ private FeatureFlagSet(@Nullable FeatureFlagUniverse p_250433_, long p_251523_, long[] extendedMask) {
this.universe = p_250433_;
this.mask = p_251523_;
+ this.extendedMask = extendedMask;
}

static FeatureFlagSet create(FeatureFlagUniverse p_251573_, Collection<FeatureFlag> p_251037_) {
@@ -22,7 +_,8 @@
return EMPTY;
} else {
long i = computeMask(p_251573_, 0L, p_251037_);
- return new FeatureFlagSet(p_251573_, i);
+ long[] extMask = computeExtendedMask(p_251573_, 0, 0L, p_251037_);
+ return new FeatureFlagSet(p_251573_, i, extMask);
}
}

@@ -31,16 +_,19 @@
}

public static FeatureFlagSet of(FeatureFlag p_252331_) {
- return new FeatureFlagSet(p_252331_.universe, p_252331_.mask);
+ long[] extMask = computeExtendedMask(p_252331_.universe, p_252331_.offset, p_252331_.mask, java.util.List.of());
+ return new FeatureFlagSet(p_252331_.universe, p_252331_.offset > 0 ? 0L : p_252331_.mask, extMask);
}

public static FeatureFlagSet of(FeatureFlag p_251008_, FeatureFlag... p_249805_) {
- long i = p_249805_.length == 0 ? p_251008_.mask : computeMask(p_251008_.universe, p_251008_.mask, Arrays.asList(p_249805_));
- return new FeatureFlagSet(p_251008_.universe, i);
+ long i = p_249805_.length == 0 ? (p_251008_.offset > 0 ? 0L : p_251008_.mask) : computeMask(p_251008_.universe, p_251008_.offset > 0 ? 0L : p_251008_.mask, Arrays.asList(p_249805_));
+ long[] extMask = computeExtendedMask(p_251008_.universe, p_251008_.offset, p_251008_.mask, p_249805_.length == 0 ? java.util.List.of() : Arrays.asList(p_249805_));
+ return new FeatureFlagSet(p_251008_.universe, i, extMask);
}

private static long computeMask(FeatureFlagUniverse p_249684_, long p_250982_, Iterable<FeatureFlag> p_251734_) {
for (FeatureFlag featureflag : p_251734_) {
+ if (featureflag.offset > 0) continue;
if (p_249684_ != featureflag.universe) {
throw new IllegalStateException("Mismatched feature universe, expected '" + p_249684_ + "', but got '" + featureflag.universe + "'");
}
@@ -51,8 +_,36 @@
return p_250982_;
}

+ private static long[] computeExtendedMask(FeatureFlagUniverse universe, int firstOffset, long firstMask, Iterable<FeatureFlag> otherFlags) {
+ long[] extMask = EMPTY_EXT_MASK;
+ if (firstOffset > 0) {
+ extMask = new long[firstOffset + 1];
+ extMask[firstOffset] |= firstMask;
+ }
+ for (FeatureFlag flag : otherFlags) {
+ if (flag.offset == 0) continue;
+ if (universe != flag.universe) {
+ throw new IllegalStateException("Mismatched feature universe, expected '" + universe + "', but got '" + flag.universe + "'");
+ }
+ if (flag.offset >= extMask.length) {
+ extMask = Arrays.copyOfRange(extMask, 0, flag.offset + 1);
+ }
+ extMask[flag.offset] |= flag.mask;
+ }
+ return extMask;
+ }
+
public boolean contains(FeatureFlag p_249521_) {
- return this.universe != p_249521_.universe ? false : (this.mask & p_249521_.mask) != 0L;
+ if (this.universe != p_249521_.universe) {
+ return false;
+ }
+ if (p_249521_.offset == 0) {
+ return (this.mask & p_249521_.mask) != 0L;
+ }
+ if (this.extendedMask.length > p_249521_.offset) {
+ return (this.extendedMask[p_249521_.offset] & p_249521_.mask) != 0L;
+ }
+ return false;
}

public boolean isEmpty() {
@@ -62,13 +_,33 @@
public boolean isSubsetOf(FeatureFlagSet p_249164_) {
if (this.universe == null) {
return true;
- } else {
- return this.universe != p_249164_.universe ? false : (this.mask & ~p_249164_.mask) == 0L;
+ } else if (this.universe == p_249164_.universe) {
+ int len = Math.max(this.extendedMask.length, p_249164_.extendedMask.length);
+ for (int i = 0; i < len; i++) {
+ long thisMask = i < this.extendedMask.length ? this.extendedMask[i] : 0L;
+ long otherMask = i < p_249164_.extendedMask.length ? p_249164_.extendedMask[i] : 0L;
+ if ((thisMask & ~otherMask) != 0L) {
+ return false;
+ }
+ }
+ return (this.mask & ~p_249164_.mask) == 0L;
}
+ return false;
}

public boolean intersects(FeatureFlagSet p_341635_) {
- return this.universe != null && p_341635_.universe != null && this.universe == p_341635_.universe ? (this.mask & p_341635_.mask) != 0L : false;
+ if (this.universe == null || p_341635_.universe == null || this.universe != p_341635_.universe) {
+ return false;
+ }
+ int len = Math.min(this.extendedMask.length, p_341635_.extendedMask.length);
+ for (int i = 0; i < len; i++) {
+ long thisMask = this.extendedMask[i];
+ long otherMask = p_341635_.extendedMask[i];
+ if ((thisMask & otherMask) != 0L) {
+ return true;
+ }
+ }
+ return (this.mask & p_341635_.mask) != 0L;
}

public FeatureFlagSet join(FeatureFlagSet p_251527_) {
@@ -79,7 +_,16 @@
} else if (this.universe != p_251527_.universe) {
throw new IllegalArgumentException("Mismatched set elements: '" + this.universe + "' != '" + p_251527_.universe + "'");
} else {
- return new FeatureFlagSet(this.universe, this.mask | p_251527_.mask);
+ long[] extMask = EMPTY_EXT_MASK;
+ if (this.extendedMask.length > 0 || p_251527_.extendedMask.length > 0) {
+ extMask = new long[Math.max(this.extendedMask.length, p_251527_.extendedMask.length)];
+ for (int i = 0; i < extMask.length; i++) {
+ long thisMask = i < this.extendedMask.length ? this.extendedMask[i] : 0L;
+ long otherMask = i < p_251527_.extendedMask.length ? p_251527_.extendedMask[i] : 0L;
+ extMask[i] = thisMask | otherMask;
+ }
+ }
+ return new FeatureFlagSet(this.universe, this.mask | p_251527_.mask, extMask);
}
}

@@ -90,7 +_,15 @@
throw new IllegalArgumentException("Mismatched set elements: '" + this.universe + "' != '" + p_341688_.universe + "'");
} else {
long i = this.mask & ~p_341688_.mask;
- return i == 0L ? EMPTY : new FeatureFlagSet(this.universe, i);
+ long[] extMask = EMPTY_EXT_MASK;
+ if (this.extendedMask.length > 0 || p_341688_.extendedMask.length > 0) {
+ extMask = new long[this.extendedMask.length];
+ for (int idx = 0; idx < extMask.length; idx++) {
+ long otherMask = idx < p_341688_.extendedMask.length ? p_341688_.extendedMask[idx] : 0L;
+ extMask[idx] = this.extendedMask[idx] & ~otherMask;
+ }
+ }
+ return i == 0L && extMask.length == 0 ? EMPTY : new FeatureFlagSet(this.universe, i, extMask);
}
}

@@ -99,7 +_,7 @@
if (this == p_248691_) {
return true;
} else {
- if (p_248691_ instanceof FeatureFlagSet featureflagset && this.universe == featureflagset.universe && this.mask == featureflagset.mask) {
+ if (p_248691_ instanceof FeatureFlagSet featureflagset && this.universe == featureflagset.universe && this.mask == featureflagset.mask && Arrays.equals(this.extendedMask, featureflagset.extendedMask)) {
return true;
}

@@ -109,6 +_,10 @@

@Override
public int hashCode() {
- return (int)HashCommon.mix(this.mask);
+ int hash = (int)HashCommon.mix(this.mask);
+ for (long extMask : this.extendedMask) {
+ hash = 13 * hash + (int) HashCommon.mix(extMask);
+ }
+ return hash;
}
}
10 changes: 10 additions & 0 deletions patches/net/minecraft/world/flag/FeatureFlags.java.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
--- a/net/minecraft/world/flag/FeatureFlags.java
+++ b/net/minecraft/world/flag/FeatureFlags.java
@@ -33,6 +_,7 @@
VANILLA = featureflagregistry$builder.createVanilla("vanilla");
BUNDLE = featureflagregistry$builder.createVanilla("bundle");
TRADE_REBALANCE = featureflagregistry$builder.createVanilla("trade_rebalance");
+ net.neoforged.neoforge.common.util.flag.FeatureFlagLoader.loadModdedFlags(featureflagregistry$builder);
REGISTRY = featureflagregistry$builder.build();
CODEC = REGISTRY.codec();
VANILLA_SET = FeatureFlagSet.of(VANILLA);
Loading