2 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
7 changed files with 174 additions and 47 deletions

124
.gitea/workflows/build.yml Normal file
View File

@@ -0,0 +1,124 @@
name: Build
on:
push:
branches-ignore:
- artifacts
tags:
- "v*"
pull_request:
workflow_dispatch:
permissions:
contents: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Java 21
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: "21"
- name: Make Gradle wrapper executable
run: chmod +x ./gradlew
- name: Build
run: ./gradlew build --no-daemon
- name: Create Gitea release
if: startsWith(github.ref, 'refs/tags/')
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
run: |
set -euo pipefail
tag="${GITHUB_REF_NAME}"
api="${GITHUB_SERVER_URL}/api/v1"
release_name="WorldHandler ${tag}"
jar="$(find build/libs -maxdepth 1 -name '*neoforge*.jar' -print -quit)"
token="${GITEA_TOKEN:-${GITHUB_TOKEN:-}}"
if [ -z "${jar}" ]; then
echo "No NeoForge jar found in build/libs" >&2
exit 1
fi
if [ -z "${token}" ]; then
echo "No Gitea token available" >&2
exit 1
fi
release_json="$(mktemp)"
if ! curl -fsS \
-H "Authorization: token ${token}" \
-H "Accept: application/json" \
"${api}/repos/${GITHUB_REPOSITORY}/releases/tags/${tag}" \
-o "${release_json}"; then
export tag release_name GITHUB_SHA
python3 -c 'import json, os; print(json.dumps({"tag_name": os.environ["tag"], "target_commitish": os.environ["GITHUB_SHA"], "name": os.environ["release_name"], "body": "NeoForge 21.1.225 build for Minecraft 1.21.1.", "draft": False, "prerelease": False}))' > "${release_json}"
curl -fsS \
-X POST \
-H "Authorization: token ${token}" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
--data-binary @"${release_json}" \
"${api}/repos/${GITHUB_REPOSITORY}/releases" \
-o "${release_json}"
fi
release_id="$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1]))["id"])' "${release_json}")"
asset_name="$(basename "${jar}")"
python3 -c 'import json, sys; release = json.load(open(sys.argv[1])); asset_name = sys.argv[2]; [print(asset["id"]) for asset in release.get("assets", []) if asset.get("name") == asset_name]' "${release_json}" "${asset_name}" > assets-to-delete.txt
while read -r asset_id; do
[ -z "${asset_id}" ] && continue
curl -fsS \
-X DELETE \
-H "Authorization: token ${token}" \
"${api}/repos/${GITHUB_REPOSITORY}/releases/${release_id}/assets/${asset_id}"
done < assets-to-delete.txt
curl -fsS \
-X POST \
-H "Authorization: token ${token}" \
-H "Accept: application/json" \
-F "attachment=@${jar};type=application/java-archive" \
"${api}/repos/${GITHUB_REPOSITORY}/releases/${release_id}/assets?name=${asset_name}"
- name: Publish jar to artifacts branch
if: github.event_name != 'pull_request'
shell: bash
run: |
set -euo pipefail
mkdir -p /tmp/worldhandler-artifacts
cp build/libs/*.jar /tmp/worldhandler-artifacts/
git config user.name "Gitea Actions"
git config user.email "actions@gitea.local"
git fetch origin artifacts || true
git switch --force-create artifacts
git rm -rf .
cp /tmp/worldhandler-artifacts/*.jar .
cat > README.md <<'EOF'
# WorldHandler build artifacts
This branch is maintained by the Gitea runner.
Download the jar file from this branch.
EOF
git add README.md *.jar
git commit --allow-empty -m "Publish WorldHandler jar from ${GITHUB_SHA}"
git push --force origin artifacts

5
.gitignore vendored
View File

@@ -130,3 +130,8 @@ bin/
### Changelog ###
changelog.txt
### Local Codex build runtime ###
.codex-jdk/
.gradle-home/
temurin-jdk21.zip

View File

@@ -9,6 +9,9 @@ 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;
@@ -96,19 +99,21 @@ public class ItemArgument extends TagArgument
return null;
}
List<String> components = new ArrayList<String>();
DataComponentPatch.Builder components = DataComponentPatch.builder();
if(this.componentProviders != null)
{
for(IItemComponentProvider provider : this.componentProviders)
{
provider.appendItemComponents(components);
provider.addItemComponents(components);
}
}
if(!components.isEmpty())
DataComponentPatch componentPatch = components.build();
if(!componentPatch.isEmpty())
{
return BuiltInRegistries.ITEM.getKey(this.item).toString() + "[" + String.join(",", components) + "]";
return new ItemInput(BuiltInRegistries.ITEM.wrapAsHolder(this.item), componentPatch).serialize(RegistryHelper.registryAccess());
}
String tag = super.serialize();

View File

@@ -1,16 +1,21 @@
package exopandora.worldhandler.builder.argument.tag;
import java.util.Map.Entry;
import java.util.List;
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 implements IItemComponentProvider
{
@@ -51,34 +56,25 @@ public class AttributeModifiersTag extends AbstractAttributeTag implements IItem
}
@Override
public void appendItemComponents(List<String> components)
public void addItemComponents(DataComponentPatch.Builder components)
{
StringBuilder modifiers = new StringBuilder();
ItemAttributeModifiers.Builder modifiers = ItemAttributeModifiers.builder();
boolean hasModifiers = false;
for(Entry<Attribute, Double> entry : this.attributes.entrySet())
{
if(entry.getValue() != 0)
{
String id = BuiltInRegistries.ATTRIBUTE.getKey(entry.getKey()).toString();
ResourceLocation id = BuiltInRegistries.ATTRIBUTE.getKey(entry.getKey());
if(modifiers.length() > 0)
{
modifiers.append(',');
}
modifiers.append("{type:\"")
.append(id)
.append("\",id:\"")
.append(id)
.append("\",amount:")
.append(entry.getValue() / 100)
.append(",operation:\"add_multiplied_base\"}");
modifiers.add(BuiltInRegistries.ATTRIBUTE.wrapAsHolder(entry.getKey()), new AttributeModifier(id, entry.getValue() / 100, AttributeModifier.Operation.ADD_MULTIPLIED_BASE), EquipmentSlotGroup.ANY);
hasModifiers = true;
}
}
if(modifiers.length() > 0)
if(hasModifiers)
{
components.add("minecraft:attribute_modifiers={modifiers:[" + modifiers + "]}");
components.set(DataComponents.ATTRIBUTE_MODIFIERS, modifiers.build());
}
}
}

View File

@@ -5,11 +5,14 @@ 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, IItemComponentProvider
{
@@ -96,31 +99,26 @@ public class DisplayTag implements ITagProvider, IItemComponentProvider
}
@Override
public void appendItemComponents(List<String> components)
public void addItemComponents(DataComponentPatch.Builder components)
{
if(this.name.getText() != null && !this.name.getText().isEmpty())
{
components.add("minecraft:custom_name=" + quote(TextUtils.toJson(this.name)));
components.set(DataComponents.CUSTOM_NAME, this.name);
}
List<String> lore = new ArrayList<String>();
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(quote(TextUtils.toJson(this.lore[x])));
lore.add(this.lore[x]);
}
}
if(!lore.isEmpty())
{
components.add("minecraft:lore=[" + String.join(",", lore) + "]");
components.set(DataComponents.LORE, new ItemLore(lore));
}
}
private static String quote(String value)
{
return "'" + value.replace("\\", "\\\\").replace("'", "\\'") + "'";
}
}

View File

@@ -9,10 +9,14 @@ 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, IItemComponentProvider
{
@@ -74,29 +78,24 @@ public class EnchantmentsTag implements ITagProvider, IItemComponentProvider
}
@Override
public void appendItemComponents(List<String> components)
public void addItemComponents(DataComponentPatch.Builder components)
{
StringBuilder levels = new StringBuilder();
ItemEnchantments.Mutable enchantments = new ItemEnchantments.Mutable(ItemEnchantments.EMPTY);
for(Entry<Enchantment, Short> entry : this.enchantments.entrySet())
{
if(entry.getValue() > 0)
{
if(levels.length() > 0)
{
levels.append(',');
}
levels.append('"')
.append(RegistryHelper.getEnchantmentKey(entry.getKey()))
.append("\":")
.append(entry.getValue());
Holder<Enchantment> holder = RegistryHelper.enchantments().wrapAsHolder(entry.getKey());
enchantments.set(holder, entry.getValue());
}
}
if(levels.length() > 0)
ItemEnchantments itemEnchantments = enchantments.toImmutable();
if(!itemEnchantments.isEmpty())
{
components.add("minecraft:enchantments={levels:{" + levels + "}}");
components.set(DataComponents.ENCHANTMENTS, itemEnchantments);
}
}
}

View File

@@ -1,8 +1,8 @@
package exopandora.worldhandler.builder.argument.tag;
import java.util.List;
import net.minecraft.core.component.DataComponentPatch;
public interface IItemComponentProvider
{
void appendItemComponents(List<String> components);
void addItemComponents(DataComponentPatch.Builder components);
}