Benutzerdefinierte Schilde 26.2
Lerne, wie du deine eigenen Schilde erstellst und deren Eigenschaften konfigurierst.
VORAUSSETZUNGEN
Du musst zuerst versehen, wie man ein Werkzerug erstellt. Dieser Leitfaden referenziert auch die Datengenerierung von Rezepten, Itemmodellen und Item Tags.
Schilde können dazu verwendet werden, sich vor Angriffen zu schützen. Um dem Spiel einen neuen Schild hinzuzufügen, benötigst du ein Item, zwei Itemmodelle, ein Client Item, Rezepte, Item Tags und einen speziellen Renderer.
Das Item erstellen
VORAUSSETZUNGEN
Weitere Informationen findest du in der Dokumentation zur Erstellung von Items.
Für dieses Beispiel verwenden wir dasselbe Reperatur Item Tag, das wir bereits auf den Seiten Benutzerdefinierte Rüstungen und Benutzerdefinierte Werkzeuge verwendet haben. Wir definieren die Tag-Referenz wie folgt:
java
public static final TagKey<Item> REPAIRS_GUIDITE_ARMOR = TagKey.create(BuiltInRegistries.ITEM.key(), ExampleMod.id("repairs_guidite_armor"));1
Dann, erstellen wir eine Item ID und registrieren ein Item mit den folgenden Komponenten.
- Bannervorlagen: Erstellt ein Item mit einem leeren Set an Bannervorlagen.
- Reparierbar: Erstellt ein Item, dass mit einem gegebenen Item Tag repariert werden kann.
- Ausrüstbar/Nicht austauschbar: Ein Shift-Klick auf das Item im GUI, wird es in der zweiten Hand ausrüsten. In der Spielwelt wird das Item durch einen Rechtsklick nicht ausgerüstet.
- Blockiert Angriffe: Erstellt ein Item, dass Angriffs blockiert. Dieses Beispiel verwendet Werte von dem Vanilla Schild.
- Dies ist eine verzögerte Komponente, das heißt, sie wird erst geladen, nachdem die Welt geladen wurde, sodass sie auf Datapack-Objekte wie Tags verweisen kann.
- Zerstörungssound: Wenn das Item zerstört wird, wird der angegebene Ton abgespielt.
java
public static final ResourceKey<Item> GUIDITE_SHIELD = create("guidite_shield");1
java
public static final Item GUIDITE_SHIELD = register(
ModItemIds.GUIDITE_SHIELD,
ShieldItem::new,
new Item.Properties().durability(336)
.component(DataComponents.BANNER_PATTERNS, BannerPatternLayers.EMPTY)
.repairable(GuiditeArmorMaterial.REPAIRS_GUIDITE_ARMOR)
.equippableUnswappable(EquipmentSlot.OFFHAND)
.delayedComponent(DataComponents.BLOCKS_ATTACKS, (context) -> new BlocksAttacks(0.25F, 1.0F, List.of(new BlocksAttacks.DamageReduction(90.0F, Optional.empty(), 0.0F, 1.0F)), new BlocksAttacks.ItemDamageFunction(3.0F, 1.0F, 1.0F), Optional.of(context.getOrThrow(DamageTypeTags.BYPASSES_SHIELD)), Optional.of(SoundEvents.SHIELD_BLOCK), Optional.of(SoundEvents.SHIELD_BREAK)))
.component(DataComponents.BREAK_SOUND, SoundEvents.SHIELD_BREAK)
);1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
Vergiss nicht, ihn zu einem Kreativtab hinzuzufügen, wenn du vom Kreativinventar aus auf ihn zugreifen willst!
java
CreativeModeTabEvents.modifyOutputEvent(CreativeModeTabs.COMBAT)
.register((creativeTab) -> creativeTab.accept(ModItems.GUIDITE_SHIELD));1
2
2
Den speziellen Renderer erstellen
Wir werden einen speziellen Renderer verwenden, um den Schild zu rendern, anstatt das normale Itemmodell zu verwenden.
Zuerst erstellen wir einen Ort für die Modell-Ebenen, der anzeigt, wo das Schildmodell ist:
java
public static final ModelLayerLocation GUIDITE_SHIELD =
new ModelLayerLocation(ExampleMod.id("guidite_shield"), "main");1
2
2
Registriere dann die Ebene in deinem Client Initialisierer:
java
SpecialModelRenderers.ID_MAPPER.put(ExampleMod.id("guidite_shield"), GuiditeShieldSpecialRenderer.Unbaked.MAP_CODEC);
ModelLayerRegistry.registerModelLayer(GuiditeShieldLayers.GUIDITE_SHIELD, ShieldModel::createLayer);1
2
2
Dann werden wir einen speziellen Renderer für das Item erstellen. Dieser basiert auf dem Vanilla ShieldSpecialRenderer, wobei Änderungen vorgenommen wurden, damit er benutzerdefinierte Sprites vom Client Item übernehmen kann. Im nächsten Abschnitt werden wir diese Sprites dem Renderer zur Verfügung stellen.
Der Renderer ist kompliziert, daher werden wir ihn Schritt für Schritt erklären.
Konstruktor
Der Konstruktor des Renderer akzeptiert vier Parameter:
- Ein Interface
SpriteGetter, das Sprites anhand vonIdentifierbereitstellen kann. - Das Modell, das wir verwenden werden, ist in diesem Fall ein
ShieldModel. - Die weiße Grundtextur (im Client Item enthalten), die als
SpriteIdbereitgestellt wird. - Die Textur, die verwendet wird, wenn keine Färbung oder Bannermuster vorhanden sind, wird als
SpriteIdbereitgestellt.
Der Konstruktor speichert alle vier Parameter als Felder, damit wir sie später verwenden können.
java
public class GuiditeShieldSpecialRenderer implements SpecialModelRenderer<DataComponentMap> {
// The offset applied to the model by default
public static final Transformation DEFAULT_TRANSFORMATION = new Transformation(null, null, new Vector3f(1.0F, -1.0F, -1.0F), null);
// Maps Identifiers to their Sprites
private final SpriteGetter sprites;
// What model should be used.
private final ShieldModel model;
// The base white texture (provided in the client item)
private final SpriteId baseSprite;
// The texture used when no dye or banner patterns are present (based on the path provided in the client item).
private final SpriteId baseSpriteNoPattern;
public GuiditeShieldSpecialRenderer(final SpriteGetter sprites, final ShieldModel model, final SpriteId baseSprite, final SpriteId baseSpriteNoPattern) {
this.sprites = sprites;
this.model = model;
this.baseSprite = baseSprite;
this.baseSpriteNoPattern = baseSpriteNoPattern;
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Extraktion
Beim Extrahieren der zu rendernenden Daten benötigen wir eine unveränderliche Kopie der Daten, die ausschließlich die für die Darstellung des Items erforderlichen Informationen enthält. Wir können dies aus dem ItemStack abrufen, indem wir dessen DataComponentMap in extractArgument in eine unveränderliche Version umwandeln:
java
public @Nullable DataComponentMap extractArgument(final ItemStack stack) {
return stack.immutableComponents();
}1
2
3
2
3
Ausmaß
Außerdem werden wir die Ausmaße des Modells, die dessen Begrenzungsrahmen definieren, die für das Rendering und Animationen im Modell verwendet werden:
java
public void getExtents(final Consumer<Vector3fc> output) {
PoseStack poseStack = new PoseStack();
this.model.root().getExtentsForGui(poseStack, output);
}1
2
3
4
2
3
4
Übermittlung
Der Übermittlungsprozess behandelt die Logik, was gerendert werden soll. Die Logik des Schild Render macht folgendes:
- Rufe die Bannervorlagen des Schildes ab und speichere sie in
patterns. Wenn der Schild keine Bannervorlagen hat, wird es aufBannerPatternLayers.EMPTYgesetzt. - Rufe die Färbung des Schildes ab und speichere sie in
baseColor. Wenn Der Schild keine Färbung hat, wird diese Variable aufnullgesetzt. - Wenn das Schild Bannervorlagen or eine Färbung hat, verwende die Textur
base. Wenn nicht, verwende die Texturbase_nopattern. - Übermittle das zu rendernde Schildmodell unter Verwendung der angegebenen Parameter und der Textur.
- Wenn der Schild Bannervorlagen hat, übermittle auch diese.
- Wenn der Schild verzaubert ist, übermittle den Verzauberungsglanz.
java
public void submit(final @Nullable DataComponentMap components, final PoseStack poseStack, final SubmitNodeCollector submitNodeCollector, final int lightCoords, final int overlayCoords, final boolean hasFoil, final int outlineColor) {
BannerPatternLayers patterns = components != null ? components.getOrDefault(DataComponents.BANNER_PATTERNS, BannerPatternLayers.EMPTY) : BannerPatternLayers.EMPTY;
DyeColor baseColor = components != null ? components.get(DataComponents.BASE_COLOR) : null;
boolean hasPatterns = !patterns.layers().isEmpty() || baseColor != null;
SpriteId sprite = hasPatterns ? this.baseSprite : this.baseSpriteNoPattern;
submitNodeCollector.submitModel(this.model, Unit.INSTANCE, poseStack, lightCoords, overlayCoords, -1, sprite, this.sprites, outlineColor, null);
if (hasPatterns) {
BannerRenderer.submitPatterns(this.sprites, poseStack, submitNodeCollector, lightCoords, overlayCoords, this.model, Unit.INSTANCE, false, Objects.requireNonNullElse(baseColor, DyeColor.WHITE), patterns, null);
}
if (hasFoil) {
submitNodeCollector.submitModel(this.model, Unit.INSTANCE, poseStack, RenderTypes.entityGlint(), lightCoords, overlayCoords, -1, this.sprites.get(sprite), 0, null);
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Unverarbeitetes Modell
Außerdem benötigst du ein unverarbeitetes Modell, das dazu dient, auf den Modell-Renderer zu verweisen und dem Modell die Sprites bereitzustellen.
java
public record Unbaked(Identifier base, Identifier noPattern) implements SpecialModelRenderer.Unbaked<DataComponentMap> {
public static final MapCodec<Unbaked> MAP_CODEC = RecordCodecBuilder.mapCodec((i) -> i.group(
Identifier.CODEC.fieldOf("texture").forGetter(Unbaked::base),
Identifier.CODEC.fieldOf("no_pattern_texture").forGetter(Unbaked::noPattern)
).apply(i, Unbaked::new));
public MapCodec<Unbaked> type() {
return MAP_CODEC;
}
public GuiditeShieldSpecialRenderer bake(final SpecialModelRenderer.BakingContext context) {
return new GuiditeShieldSpecialRenderer(context.sprites(), new ShieldModel(context.entityModelSet()
.bakeLayer(GuiditeShieldLayers.GUIDITE_SHIELD)), Sheets.SHIELD_MAPPER.apply(this.base), Sheets.SHIELD_MAPPER.apply(this.noPattern));
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Das Modell erstellen
VORAUSSETZUNGEN
Weitere Informationen findest du in der Dokumentation zur Erstellung von Itemmodellen.
Wir werden zwei Itemmodelle erstellen - eines für den Normalzustand und eines für den Fall, dass der Schild blockt - sowie ein bedingtes Client Item für den Schild mit unseren benutzerdefinierten Texturen:
INFO
Diese Modelle sind datengeneriert. Weitere Informationen findest du in der Dokumentation zur Erstellung von Itemmodellen.
java
// Paths to the vanilla shield and modded shield
Identifier vanillaShieldModelLocation = ModelLocationUtils.getModelLocation(Items.SHIELD);
Identifier modelLocation = ModelLocationUtils.getModelLocation(ModItems.GUIDITE_SHIELD);
// Item models
ModelTemplate shieldTemplate = new ModelTemplate(Optional.of(vanillaShieldModelLocation), Optional.empty(), TextureSlot.PARTICLE);
shieldTemplate.create(modelLocation, TextureMapping.singleSlot(TextureSlot.PARTICLE, new Material(ModelLocationUtils.getModelLocation(Blocks.ACACIA_PLANKS))), itemModelGenerator.modelOutput);
ModelTemplate blockingShieldTemplate = new ModelTemplate(Optional.of(vanillaShieldModelLocation.withSuffix("_blocking")), Optional.empty(), TextureSlot.PARTICLE);
blockingShieldTemplate.create(modelLocation.withSuffix("_blocking"), TextureMapping.singleSlot(TextureSlot.PARTICLE, new Material(ModelLocationUtils.getModelLocation(Blocks.ACACIA_PLANKS))), itemModelGenerator.modelOutput);
// Client Item
GuiditeShieldSpecialRenderer.Unbaked specialRenderer = new GuiditeShieldSpecialRenderer.Unbaked(
ExampleMod.id("guidite_shield_base"),
ExampleMod.id("guidite_shield_base_nopattern")
);
itemModelGenerator.itemModelOutput.accept(ModItems.GUIDITE_SHIELD, ItemModelUtils.conditional(GuiditeShieldSpecialRenderer.DEFAULT_TRANSFORMATION, ItemModelUtils.isUsingItem(),
ItemModelUtils.specialModel(modelLocation.withSuffix("_blocking"), specialRenderer),
ItemModelUtils.specialModel(modelLocation, specialRenderer)
));1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Das Rezept für das dekorierte Schild erstellen
VORAUSSETZUNGEN
Weitere Informationen findest du in der Dokumentation zur Generierung von Rezepten.
Es gibt zwei Möglichkeiten, im Überlebensmodus an unseren Schild zu kommen: Entweder man stellt einen normalen Schild her oder man verziert einen mit Bannermustern.
Das Handwerks-Rezept für den Basisschild kann beliebig sein. Andererseits lässt sich das Rezept für den dekorierten Schild im Rezept-Provider wie folgt erstellen:
java
SpecialRecipeBuilder.special(
() -> new ShieldDecorationRecipe(
this.tag(ItemTags.BANNERS),
Ingredient.of(ModItems.GUIDITE_SHIELD),
new ItemStackTemplate(ModItems.GUIDITE_SHIELD))
)
.save(this.output, "shield_decoration");1
2
3
4
5
6
7
2
3
4
5
6
7
Nachdem dieses Rezept definiert ist, kannst du nun Bannervorlagen auf deinem Schild anbringen:

Schild Items taggen
VORAUSSETZUNGEN
Weitere Informationen findest du in der Dokumentation zur Generierung von Item Tags.
Außerdem solltest du dein Schild in eine passende Item Tags einordnen:
ItemTags.DURABILITY_ENCHANTABLE, damit es mit den Verzauberungen Reparatur und Haltbarkeit verzaubert werden kann,ConventionalItemTags.SHIELD_TOOLS, das von Moddern für schildspezifisches Verhalten genutzt werden kann, wie beispielsweise benutzerdefinierte Schildverzauberungen.
Füge in deinem Item Tag Provider die folgenden Zeilen zu addTags hinzu:
java
builder(ConventionalItemTags.SHIELD_TOOLS)
.add(ModItemIds.GUIDITE_SHIELD);
builder(ItemTags.DURABILITY_ENCHANTABLE)
.add(ModItemIds.GUIDITE_SHIELD);1
2
3
4
2
3
4
Das war's dann auch schon! Wenn du das Spiel startest, solltest du deinen Schild im Reiter "Combat" (Kampf) des Kreativ-Inventarmenüs sehen.



