Skip to content

Commit

Permalink
Merge branch '1.21.x' into feature/e2e-selftest
Browse files Browse the repository at this point in the history
  • Loading branch information
marchermans authored Nov 27, 2024
2 parents b461e32 + cc64d63 commit c84dff0
Show file tree
Hide file tree
Showing 10 changed files with 176 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
+ this.pages.clear();
+ int tabIndex = 0;
+ List<CreativeModeTab> currentPage = new java.util.ArrayList<>();
+ for (CreativeModeTab sortedCreativeModeTab : net.neoforged.neoforge.common.CreativeModeTabRegistry.getSortedCreativeModeTabs()) {
+ for (CreativeModeTab sortedCreativeModeTab : net.neoforged.neoforge.common.CreativeModeTabRegistry.getSortedCreativeModeTabs().stream().filter(CreativeModeTab::hasAnyItems).toList()) {
+ currentPage.add(sortedCreativeModeTab);
+ tabIndex++;
+ if (tabIndex == 10) {
Expand Down
23 changes: 16 additions & 7 deletions patches/net/minecraft/world/item/crafting/RecipeManager.java.patch
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
--- a/net/minecraft/world/item/crafting/RecipeManager.java
+++ b/net/minecraft/world/item/crafting/RecipeManager.java
@@ -260,6 +_,11 @@
@@ -69,7 +_,7 @@
protected RecipeMap prepare(ResourceManager p_379845_, ProfilerFiller p_380058_) {
SortedMap<ResourceLocation, Recipe<?>> sortedmap = new TreeMap<>();
SimpleJsonResourceReloadListener.scanDirectory(
- p_379845_, Registries.elementsDirPath(Registries.RECIPE), this.registries.createSerializationContext(JsonOps.INSTANCE), Recipe.CODEC, sortedmap
+ p_379845_, Registries.elementsDirPath(Registries.RECIPE), new net.neoforged.neoforge.common.conditions.ConditionalOps<>(this.registries.createSerializationContext(JsonOps.INSTANCE), getContext()), Recipe.CODEC, sortedmap // Neo: add condition context
);
List<RecipeHolder<?>> list = new ArrayList<>(sortedmap.size());
sortedmap.forEach((p_379232_, p_379233_) -> {
@@ -258,6 +_,11 @@
return p_380850_ -> p_380850_.getType() == p_381108_ && p_380850_ instanceof SingleItemRecipe singleitemrecipe
? Optional.of(singleitemrecipe.input())
: Optional.empty();
}
+ }
+
+ // Neo: expose recipe map
+ public RecipeMap recipeMap() {
+ return this.recipes;
+ }
+
public interface CachedCheck<I extends RecipeInput, T extends Recipe<I>> {
Optional<RecipeHolder<T>> getRecipeFor(I p_344938_, ServerLevel p_379487_);
}

public interface CachedCheck<I extends RecipeInput, T extends Recipe<I>> {
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@
p_78531_.get("Player").flatMap(CompoundTag.CODEC::parse).result().orElse(null),
p_78531_.get("WasModded").asBoolean(false),
new BlockPos(p_78531_.get("SpawnX").asInt(0), p_78531_.get("SpawnY").asInt(0), p_78531_.get("SpawnZ").asInt(0)),
@@ -192,7 +_,8 @@
.asStream()
.flatMap(p_338118_ -> p_338118_.asString().result().stream())
.collect(Collectors.toCollection(Sets::newLinkedHashSet)),
- p_78531_.get("removed_features").asStream().flatMap(p_338117_ -> p_338117_.asString().result().stream()).collect(Collectors.toSet()),
+ // Neo: Append removed modded feature flags
+ updateRemovedFeatureFlags(p_78531_.get("removed_features").asStream().flatMap(p_338117_ -> p_338117_.asString().result().stream()), p_78531_.get("enabled_features").asStream().flatMap(features -> features.asString().result().stream())).collect(Collectors.toSet()),
new TimerQueue<>(TimerCallbacks.SERVER_CALLBACKS, p_78531_.get("ScheduledEvents").asStream()),
(CompoundTag)p_78531_.get("CustomBossEvents").orElseEmptyMap().getValue(),
p_78531_.get("DragonFight").read(EndDragonFight.Data.CODEC).resultOrPartial(LOGGER::error).orElse(EndDragonFight.Data.DEFAULT),
@@ -200,7 +_,11 @@
p_251864_,
p_250651_,
Expand All @@ -42,7 +52,7 @@
}

private static ListTag stringCollectionToTag(Set<String> p_277880_) {
@@ -572,10 +_,44 @@
@@ -572,10 +_,58 @@
return this.settings.copy();
}

Expand Down Expand Up @@ -85,5 +95,19 @@
+ @Override
+ public void setDayTimePerTick(float dayTimePerTick) {
+ this.dayTimePerTick = dayTimePerTick;
+ }
+
+ private static java.util.stream.Stream<String> updateRemovedFeatureFlags(java.util.stream.Stream<String> removedFeatures, java.util.stream.Stream<String> enabledFeatures) {
+ var unknownFeatureFlags = new HashSet<net.minecraft.resources.ResourceLocation>();
+ // parses the incoming Stream<String> and spits out unknown flag names (ResourceLocation)
+ // we do not care about the returned FeatureFlagSet, only the flags which do not exist
+ net.minecraft.world.flag.FeatureFlags.REGISTRY.fromNames(enabledFeatures.map(net.minecraft.resources.ResourceLocation::parse).collect(Collectors.toSet()), unknownFeatureFlags::add);
+ // concat the received removed flags with our new additions
+ return java.util.stream.Stream.concat(removedFeatures, unknownFeatureFlags.stream()
+ // we only want modded flags, mojang has datafixers for vanilla flags
+ .filter(java.util.function.Predicate.not(name -> name.getNamespace().equals(net.minecraft.resources.ResourceLocation.DEFAULT_NAMESPACE)))
+ .map(net.minecraft.resources.ResourceLocation::toString))
+ // no duplicates should exist in this stream
+ .distinct();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,11 @@ public static class Server {
*/
public static class Common {
public final ModConfigSpec.EnumValue<TagConventionLogWarning.LogWarningMode> logUntranslatedItemTagWarnings;

public final ModConfigSpec.EnumValue<TagConventionLogWarning.LogWarningMode> logLegacyTagWarnings;

public final BooleanValue attributeAdvancedTooltipDebugInfo;

Common(ModConfigSpec.Builder builder) {
logUntranslatedItemTagWarnings = builder
.comment("A config option mainly for developers. Logs out modded item tags that do not have translations when running on integrated server. Format desired is tag.item.<namespace>.<path> for the translation key. Defaults to SILENCED.")
Expand All @@ -77,6 +80,11 @@ public static class Common {
.comment("A config option mainly for developers. Logs out modded tags that are using the 'forge' namespace when running on integrated server. Defaults to DEV_SHORT.")
.translation("neoforge.configgui.logLegacyTagWarnings")
.defineEnum("logLegacyTagWarnings", TagConventionLogWarning.LogWarningMode.DEV_SHORT);

attributeAdvancedTooltipDebugInfo = builder
.comment("Set this to true to enable showing debug information about attributes on an item when advanced tooltips is on.")
.translation("neoforge.configgui.attributeAdvancedTooltipDebugInfo")
.define("attributeAdvancedTooltipDebugInfo", true);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import net.minecraft.world.entity.ai.attributes.AttributeModifier.Operation;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.item.TooltipFlag;
import net.neoforged.neoforge.common.NeoForgeConfig;
import net.neoforged.neoforge.common.NeoForgeMod;
import net.neoforged.neoforge.common.util.AttributeUtil;
import org.jetbrains.annotations.Nullable;
Expand Down Expand Up @@ -83,7 +84,7 @@ default MutableComponent toComponent(AttributeModifier modif, TooltipFlag flag)
default Component getDebugInfo(AttributeModifier modif, TooltipFlag flag) {
Component debugInfo = CommonComponents.EMPTY;

if (flag.isAdvanced()) {
if (flag.isAdvanced() && NeoForgeConfig.COMMON.attributeAdvancedTooltipDebugInfo.get()) {
// Advanced Tooltips show the underlying operation and the "true" value. We offset MULTIPLY_TOTAL by 1 due to how the operation is calculated.
double advValue = (modif.operation() == Operation.ADD_MULTIPLIED_TOTAL ? 1 : 0) + modif.amount();
String valueStr = FORMAT.format(advValue);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,22 +87,24 @@ public static void sendToAllPlayers(CustomPacketPayload payload, CustomPacketPay
* Send the given payload(s) to all players tracking the given entity
*/
public static void sendToPlayersTrackingEntity(Entity entity, CustomPacketPayload payload, CustomPacketPayload... payloads) {
if (entity.level().getChunkSource() instanceof ServerChunkCache chunkCache) {
chunkCache.broadcast(entity, makeClientboundPacket(payload, payloads));
} else {
if (entity.level().isClientSide()) {
throw new IllegalStateException("Cannot send clientbound payloads on the client");
} else if (entity.level().getChunkSource() instanceof ServerChunkCache chunkCache) {
chunkCache.broadcast(entity, makeClientboundPacket(payload, payloads));
}
// Silently ignore custom Level implementations which may not return ServerChunkCache.
}

/**
* Send the given payload(s) to all players tracking the given entity and the entity itself if it is a player
*/
public static void sendToPlayersTrackingEntityAndSelf(Entity entity, CustomPacketPayload payload, CustomPacketPayload... payloads) {
if (entity.level().getChunkSource() instanceof ServerChunkCache chunkCache) {
chunkCache.broadcastAndSend(entity, makeClientboundPacket(payload, payloads));
} else {
if (entity.level().isClientSide()) {
throw new IllegalStateException("Cannot send clientbound payloads on the client");
} else if (entity.level().getChunkSource() instanceof ServerChunkCache chunkCache) {
chunkCache.broadcastAndSend(entity, makeClientboundPacket(payload, payloads));
}
// Silently ignore custom Level implementations which may not return ServerChunkCache.
}

/**
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/assets/neoforge/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,8 @@
"neoforge.configuration.section.neoforge.server.toml.title": "Server settings",
"neoforge.configgui.advertiseDedicatedServerToLan": "Advertise Dedicated Server To LAN",
"neoforge.configgui.advertiseDedicatedServerToLan.tooltip": "Set this to true to enable advertising the dedicated server to local LAN clients so that it shows up in the Multiplayer screen automatically.",
"neoforge.configgui.attributeAdvancedTooltipDebugInfo": "Additional Attribute Advanced Tooltips",
"neoforge.configgui.attributeAdvancedTooltipDebugInfo.tooltip": "Set this to true to enable additional information about attributes on an item when advanced tooltips is on.",
"neoforge.configgui.forgeLightPipelineEnabled": "NeoForge Light Pipeline",
"neoforge.configgui.forgeLightPipelineEnabled.tooltip": "Enable the NeoForge block rendering pipeline - fixes the lighting of custom models.",
"neoforge.configgui.fullBoundingBoxLadders": "Full Bounding Box Ladders",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"neoforge:conditions": [
{
"type": "neoforge:false"
}
],
"parent": "minecraft:recipes/root",
"criteria": {
"has_stone": {
"conditions": {
"items": [
{
"items": "minecraft:stone"
}
]
},
"trigger": "minecraft:inventory_changed"
},
"has_the_recipe": {
"conditions": {
"recipe": "neotests_test_conditional_recipe:always_disabled_recipe"
},
"trigger": "minecraft:recipe_unlocked"
}
},
"requirements": [
[
"has_the_recipe",
"has_stone"
]
],
"rewards": {
"recipes": [
"neotests_test_conditional_recipe:always_disabled_recipe"
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"neoforge:conditions": [
{
"type": "neoforge:false"
}
],
"type": "minecraft:crafting_shapeless",
"category": "misc",
"ingredients": [
"minecraft:stone"
],
"result": {
"count": 1,
"id": "minecraft:bedrock"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright (c) NeoForged and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/

package net.neoforged.neoforge.debug;

import net.minecraft.core.HolderLookup;
import net.minecraft.core.registries.Registries;
import net.minecraft.data.recipes.RecipeCategory;
import net.minecraft.data.recipes.RecipeOutput;
import net.minecraft.data.recipes.RecipeProvider;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Items;
import net.neoforged.neoforge.common.conditions.FalseCondition;
import net.neoforged.neoforge.event.server.ServerStartedEvent;
import net.neoforged.testframework.DynamicTest;
import net.neoforged.testframework.annotation.ForEachTest;
import net.neoforged.testframework.annotation.TestHolder;
import net.neoforged.testframework.registration.RegistrationHelper;

@ForEachTest(groups = "conditional_recipes")
public interface ConditionalRecipeTest {
@TestHolder(description = "Validates that recipes support conditionals by generating a new recipe disabled by the FALSE condition", enabledByDefault = true)
static void testConditionalRecipe(DynamicTest test, RegistrationHelper reg) {
// name pointing to recipe which should never be enabled
var recipeName = ResourceKey.create(Registries.RECIPE, ResourceLocation.fromNamespaceAndPath(reg.modId(), "always_disabled_recipe"));

reg.addProvider(event -> new RecipeProvider.Runner(event.getGenerator().getPackOutput(), event.getLookupProvider()) {
@Override
protected RecipeProvider createRecipeProvider(HolderLookup.Provider registries, RecipeOutput output) {
return new RecipeProvider(registries, output) {
@Override
protected void buildRecipes() {
// generic stone -> bedrock recipe
shapeless(RecipeCategory.MISC, Items.BEDROCK)
.requires(Items.STONE)
.unlockedBy("has_stone", has(Items.STONE))
// false condition to have this recipe always disabled
.save(output.withConditions(FalseCondition.INSTANCE), recipeName);
}
};
}

@Override
public String getName() {
return "always_disabled_recipe_provider";
}
});

test.eventListeners().forge().addListener((ServerStartedEvent event) -> {
var recipe = event.getServer().getRecipeManager().recipeMap().byKey(recipeName);

if (recipe == null)
test.pass();
else
test.fail("Found recipe: '" + recipeName.location() + "', This should always be disabled due to 'FALSE' condition!");
});
}
}

0 comments on commit c84dff0

Please sign in to comment.