3 Commits

Author SHA1 Message Date
Codex
548a0d5b9c ci: restore Gitea build workflow
All checks were successful
Build / build (push) Successful in 5m46s
2026-04-28 00:18:40 +02:00
Codex
7da891b34b fix: address NeoForge GUI runtime issues
Avoid passing null narration text to GuiHintTextField, emit item components for custom item display/enchantment/attribute data, and update the player preview render call for the 1.21.1 InventoryScreen API.

Validated with ./gradlew.bat build --no-daemon.
2026-04-28 00:17:57 +02:00
Codex
193d93069e feat: add NeoForge 1.21.1 support
Port WorldHandler to Minecraft 1.21.1 on NeoForge 21.1.225.

This migrates the build from ForgeGradle to NeoForge ModDevGradle, updates mod metadata, replaces Forge API usage with NeoForge equivalents, updates registry access for 1.21.1, and avoids a client-startup advancement reload that can hang large modpacks.

Validated with compileJava and full Gradle build.
2026-04-26 20:54:01 +02:00
15 changed files with 150 additions and 20 deletions

View File

@@ -10,7 +10,7 @@ author = Exopandora
# NeoForge
neo_version = 21.1.225
loader_version_range = [4,)
neoforge_compatible_minecraft_versions = 1.21.1
neoforge_compatible_minecraft_versions = 1.21,1.21.1
# Publishing
curse_project_id = 228970

View File

@@ -4,7 +4,14 @@ import javax.annotation.Nullable;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import java.util.ArrayList;
import java.util.List;
import exopandora.worldhandler.builder.argument.tag.IItemComponentProvider;
import exopandora.worldhandler.util.ItemPredicateParser;
import exopandora.worldhandler.util.RegistryHelper;
import net.minecraft.commands.arguments.item.ItemInput;
import net.minecraft.core.component.DataComponentPatch;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.minecraft.core.registries.BuiltInRegistries;
@@ -12,6 +19,7 @@ import net.minecraft.core.registries.BuiltInRegistries;
public class ItemArgument extends TagArgument
{
private Item item;
private List<IItemComponentProvider> componentProviders;
protected ItemArgument()
{
@@ -39,6 +47,16 @@ public class ItemArgument extends TagArgument
{
return this.item;
}
public void addComponentProvider(IItemComponentProvider provider)
{
if(this.componentProviders == null)
{
this.componentProviders = new ArrayList<IItemComponentProvider>();
}
this.componentProviders.add(provider);
}
@Override
public void deserialize(@Nullable String string)
@@ -80,6 +98,23 @@ public class ItemArgument extends TagArgument
{
return null;
}
DataComponentPatch.Builder components = DataComponentPatch.builder();
if(this.componentProviders != null)
{
for(IItemComponentProvider provider : this.componentProviders)
{
provider.addItemComponents(components);
}
}
DataComponentPatch componentPatch = components.build();
if(!componentPatch.isEmpty())
{
return new ItemInput(BuiltInRegistries.ITEM.wrapAsHolder(this.item), componentPatch).serialize(RegistryHelper.registryAccess());
}
String tag = super.serialize();

View File

@@ -12,7 +12,7 @@ import net.minecraft.core.registries.BuiltInRegistries;
public abstract class AbstractAttributeTag implements ITagProvider
{
public static final List<Attribute> ATTRIBUTES = BuiltInRegistries.ATTRIBUTE.stream().toList().stream()
public static final List<Attribute> ATTRIBUTES = BuiltInRegistries.ATTRIBUTE.stream()
.filter(attribute -> !attribute.getDescriptionId().equals(I18n.get(attribute.getDescriptionId())))
.collect(Collectors.toList());

View File

@@ -5,13 +5,19 @@ import java.util.UUID;
import javax.annotation.Nullable;
import net.minecraft.core.component.DataComponentPatch;
import net.minecraft.core.component.DataComponents;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
import net.minecraft.world.entity.EquipmentSlotGroup;
import net.minecraft.world.entity.ai.attributes.Attribute;
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.world.item.component.ItemAttributeModifiers;
public class AttributeModifiersTag extends AbstractAttributeTag
public class AttributeModifiersTag extends AbstractAttributeTag implements IItemComponentProvider
{
@Override
@Nullable
@@ -48,4 +54,27 @@ public class AttributeModifiersTag extends AbstractAttributeTag
{
return "AttributeModifiers";
}
@Override
public void addItemComponents(DataComponentPatch.Builder components)
{
ItemAttributeModifiers.Builder modifiers = ItemAttributeModifiers.builder();
boolean hasModifiers = false;
for(Entry<Attribute, Double> entry : this.attributes.entrySet())
{
if(entry.getValue() != 0)
{
ResourceLocation id = BuiltInRegistries.ATTRIBUTE.getKey(entry.getKey());
modifiers.add(BuiltInRegistries.ATTRIBUTE.wrapAsHolder(entry.getKey()), new AttributeModifier(id, entry.getValue() / 100, AttributeModifier.Operation.ADD_MULTIPLIED_BASE), EquipmentSlotGroup.ANY);
hasModifiers = true;
}
}
if(hasModifiers)
{
components.set(DataComponents.ATTRIBUTE_MODIFIERS, modifiers.build());
}
}
}

View File

@@ -1,14 +1,20 @@
package exopandora.worldhandler.builder.argument.tag;
import java.util.ArrayList;
import java.util.List;
import exopandora.worldhandler.util.TextUtils;
import exopandora.worldhandler.util.UserStylableComponent;
import net.minecraft.core.component.DataComponentPatch;
import net.minecraft.core.component.DataComponents;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.StringTag;
import net.minecraft.nbt.Tag;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.component.ItemLore;
public class DisplayTag implements ITagProvider
public class DisplayTag implements ITagProvider, IItemComponentProvider
{
private UserStylableComponent name = new UserStylableComponent();
private Component[] lore = new Component[2];
@@ -91,4 +97,28 @@ public class DisplayTag implements ITagProvider
{
return "display";
}
@Override
public void addItemComponents(DataComponentPatch.Builder components)
{
if(this.name.getText() != null && !this.name.getText().isEmpty())
{
components.set(DataComponents.CUSTOM_NAME, this.name);
}
List<Component> lore = new ArrayList<Component>();
for(int x = 0; x < this.lore.length; x++)
{
if(this.lore[x] != null && !this.lore[x].getString().isEmpty())
{
lore.add(this.lore[x]);
}
}
if(!lore.isEmpty())
{
components.set(DataComponents.LORE, new ItemLore(lore));
}
}
}

View File

@@ -1,6 +1,7 @@
package exopandora.worldhandler.builder.argument.tag;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
@@ -8,12 +9,16 @@ import java.util.Set;
import javax.annotation.Nullable;
import exopandora.worldhandler.util.RegistryHelper;
import net.minecraft.core.Holder;
import net.minecraft.core.component.DataComponentPatch;
import net.minecraft.core.component.DataComponents;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
import net.minecraft.world.item.enchantment.Enchantment;
import net.minecraft.world.item.enchantment.ItemEnchantments;
public class EnchantmentsTag implements ITagProvider
public class EnchantmentsTag implements ITagProvider, IItemComponentProvider
{
private final Map<Enchantment, Short> enchantments = new HashMap<Enchantment, Short>();
@@ -71,4 +76,26 @@ public class EnchantmentsTag implements ITagProvider
{
return "Enchantments";
}
@Override
public void addItemComponents(DataComponentPatch.Builder components)
{
ItemEnchantments.Mutable enchantments = new ItemEnchantments.Mutable(ItemEnchantments.EMPTY);
for(Entry<Enchantment, Short> entry : this.enchantments.entrySet())
{
if(entry.getValue() > 0)
{
Holder<Enchantment> holder = RegistryHelper.enchantments().wrapAsHolder(entry.getKey());
enchantments.set(holder, entry.getValue());
}
}
ItemEnchantments itemEnchantments = enchantments.toImmutable();
if(!itemEnchantments.isEmpty())
{
components.set(DataComponents.ENCHANTMENTS, itemEnchantments);
}
}
}

View File

@@ -0,0 +1,8 @@
package exopandora.worldhandler.builder.argument.tag;
import net.minecraft.core.component.DataComponentPatch;
public interface IItemComponentProvider
{
void addItemComponents(DataComponentPatch.Builder components);
}

View File

@@ -42,22 +42,22 @@ public class ContentButcherPresets extends ContentChild
container.addRenderableWidget(new GuiButtonBase(x + 58, y, 114, 20, Component.translatable("gui.worldhandler.butcher.presets.passive_mobs"), () ->
{
ContentButcher.slaughter(container.getPlayer(), BuiltInRegistries.ENTITY_TYPE.stream().toList().stream().filter(entity -> !MobCategory.MONSTER.equals(entity.getCategory()) && !MobCategory.MISC.equals(entity.getCategory())).collect(Collectors.toList()), this.radius);
ContentButcher.slaughter(container.getPlayer(), BuiltInRegistries.ENTITY_TYPE.stream().filter(entity -> !MobCategory.MONSTER.equals(entity.getCategory()) && !MobCategory.MISC.equals(entity.getCategory())).collect(Collectors.toList()), this.radius);
ActionHelper.open(this.getParentContent());
}));
container.addRenderableWidget(new GuiButtonBase(x + 58, y + 24, 114, 20, Component.translatable("gui.worldhandler.butcher.presets.hostile_mobs"), () ->
{
ContentButcher.slaughter(container.getPlayer(), BuiltInRegistries.ENTITY_TYPE.stream().toList().stream().filter(entity -> MobCategory.MONSTER.equals(entity.getCategory())).collect(Collectors.toList()), this.radius);
ContentButcher.slaughter(container.getPlayer(), BuiltInRegistries.ENTITY_TYPE.stream().filter(entity -> MobCategory.MONSTER.equals(entity.getCategory())).collect(Collectors.toList()), this.radius);
ActionHelper.open(this.getParentContent());
}));
container.addRenderableWidget(new GuiButtonBase(x + 58, y + 48, 114, 20, Component.translatable("gui.worldhandler.butcher.presets.players"), () ->
{
ContentButcher.slaughter(container.getPlayer(), BuiltInRegistries.ENTITY_TYPE.stream().toList().stream().filter(entity -> EntityType.PLAYER.equals(entity)).collect(Collectors.toList()), this.radius);
ContentButcher.slaughter(container.getPlayer(), BuiltInRegistries.ENTITY_TYPE.stream().filter(entity -> EntityType.PLAYER.equals(entity)).collect(Collectors.toList()), this.radius);
ActionHelper.open(this.getParentContent());
}));
container.addRenderableWidget(new GuiButtonBase(x + 58, y + 72, 114, 20, Component.translatable("gui.worldhandler.butcher.presets.entities"), () ->
{
ContentButcher.slaughter(container.getPlayer(), BuiltInRegistries.ENTITY_TYPE.stream().toList().stream().filter(entity -> MobCategory.MISC.equals(entity.getCategory()) && !EntityType.PLAYER.equals(entity)).collect(Collectors.toList()), this.radius);
ContentButcher.slaughter(container.getPlayer(), BuiltInRegistries.ENTITY_TYPE.stream().filter(entity -> MobCategory.MISC.equals(entity.getCategory()) && !EntityType.PLAYER.equals(entity)).collect(Collectors.toList()), this.radius);
ActionHelper.open(this.getParentContent());
}));
}

View File

@@ -24,7 +24,7 @@ public class ContentButcherSettings extends ContentChild
@Override
public void initGui(Container container, int x, int y)
{
List<EntityType<?>> list = BuiltInRegistries.ENTITY_TYPE.stream().toList().stream().filter(EntityType::canSummon).collect(Collectors.toList());
List<EntityType<?>> list = BuiltInRegistries.ENTITY_TYPE.stream().filter(EntityType::canSummon).collect(Collectors.toList());
MenuPageList<EntityType<?>> entities = new MenuPageList<EntityType<?>>(x, y, list, 114, 20, 3, container, new ILogicPageList<EntityType<?>>()
{

View File

@@ -52,9 +52,9 @@ public class ContentCustomItem extends Content
public ContentCustomItem()
{
this.builderCutomItem.item().addTagProvider(this.attributes);
this.builderCutomItem.item().addTagProvider(this.display);
this.builderCutomItem.item().addTagProvider(this.enchantments);
this.builderCutomItem.item().addComponentProvider(this.attributes);
this.builderCutomItem.item().addComponentProvider(this.display);
this.builderCutomItem.item().addComponentProvider(this.enchantments);
}
@Override

View File

@@ -188,7 +188,7 @@ public class ContentPlayer extends Content
guiGraphics.drawString(minecraft.font, minecraft.player.getName(), container.width / 2 - playerNameWidth + 59, yPos - 73, 0xE0E0E0);
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
InventoryScreen.renderEntityInInventoryFollowsMouse(guiGraphics, xPos, yPos, 30, xPos - mouseX, yPos - mouseY - 44, 0.0625F, (float) mouseX, (float) mouseY, minecraft.player);
InventoryScreen.renderEntityInInventoryFollowsMouse(guiGraphics, xPos - 30, yPos - 70, xPos + 30, yPos, 30, 0.0625F, (float) mouseX, (float) mouseY, minecraft.player);
RenderSystem.defaultBlendFunc();
}
}

View File

@@ -17,7 +17,7 @@ public class GuiHintTextField extends EditBox
public GuiHintTextField(int x, int y, int width, int height, Component hint)
{
super(Minecraft.getInstance().font, x, y, width, height, null);
super(Minecraft.getInstance().font, x, y, width, height, Component.empty());
this.setMaxLength(Integer.MAX_VALUE);
this.hint = hint;
}
@@ -60,7 +60,7 @@ public class GuiHintTextField extends EditBox
}
else
{
this.setValue((String) null);
this.setValue("");
}
}
}

View File

@@ -22,7 +22,7 @@ public class BlockPredicateParser
private static final ResourceLocation AIR_RESOURCE_LOCATION = BuiltInRegistries.BLOCK.getKey(Blocks.AIR);
private final StringReader reader;
private final Map<String, String> vagueProperties = Maps.newHashMap();
private ResourceLocation block = null;
private ResourceLocation block = AIR_RESOURCE_LOCATION;
@Nullable
private CompoundTag nbt;
private boolean isTag;

View File

@@ -19,9 +19,10 @@ import net.minecraft.core.registries.BuiltInRegistries;
public class ItemPredicateParser
{
private static final ResourceLocation AIR_RESOURCE_LOCATION = BuiltInRegistries.ITEM.getKey(Items.AIR);
private static final SimpleCommandExceptionType ERROR_NO_TAGS_ALLOWED = new SimpleCommandExceptionType(Component.translatable("argument.item.tag.disallowed"));
private final StringReader reader;
private ResourceLocation item = null;
private ResourceLocation item = AIR_RESOURCE_LOCATION;
@Nullable
private CompoundTag nbt;
private boolean isTag;

View File

@@ -18,13 +18,13 @@ license="GPL v3.0"
[[dependencies.worldhandler]]
modId="minecraft"
type="required"
versionRange="[1.21.1,1.21.2)"
versionRange="[1.21,1.21.2)"
ordering="NONE"
side="BOTH"
[[dependencies.worldhandler]]
modId="neoforge"
type="required"
versionRange="[21.1.225,)"
versionRange="[21.0.167,)"
ordering="NONE"
side="BOTH"