Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
9d6a113
Setup unstable publishing to PaperMC snapshots repo (DO NOT MERGE TO …
jpenilla Aug 21, 2025
80659e1
Init ObjectComponent
jpenilla Aug 21, 2025
ca21ba8
Fix atlas nullability
jpenilla Aug 21, 2025
68c5e9a
override examinableProperties
jpenilla Aug 21, 2025
3025b4d
Add tests
jpenilla Aug 21, 2025
ff3b13f
Refactor ObjectComponent to have a Contents
jpenilla Aug 22, 2025
4004b7c
make SpriteContents#atlas non-null
jpenilla Aug 22, 2025
4869176
jd fix
jpenilla Aug 22, 2025
0ed2897
Add net.kyori capabilities when group is something else
jpenilla Aug 22, 2025
511f853
Add PlayerHeadContents
jpenilla Aug 26, 2025
cfccd17
dont clear props on properties(map)
jpenilla Aug 26, 2025
614ad73
allow using SkinSource with builder
jpenilla Aug 26, 2025
fd8a901
Add more property helpers & a test
jpenilla Aug 26, 2025
1c8aabe
Add import layout to editorconfig
jpenilla Aug 26, 2025
55924a6
Move ObjectComponent inner classes to top level
jpenilla Aug 26, 2025
e8f91a5
clear existing profile when setting from skin source
jpenilla Aug 26, 2025
a9ee9a2
make it build (add javadocs and etc.)
jpenilla Aug 26, 2025
43231d3
Assert PlayerHeadObjectContents is non-empty
jpenilla Aug 26, 2025
380fe42
Rename objectContents field back to contents
jpenilla Aug 26, 2025
1ebf401
Allow empty steve contents
jpenilla Aug 26, 2025
42188eb
De-emphasize hat param, default to true
jpenilla Aug 27, 2025
17a2304
Merge pull request #1294 from KyoriPowered/player-head-contents-exp-1
jpenilla Aug 27, 2025
1962e73
fix profile properties collection type
jpenilla Aug 30, 2025
f9fd048
Add texture field to PlayerHeadObjectContents
jpenilla Sep 16, 2025
d342f10
Add missing copy for toBuilder
jpenilla Sep 16, 2025
4b0b339
Clean texture when setting from a SkinSource
jpenilla Sep 16, 2025
4b1827f
feat(minimessage): add sprite tag
Strokkur424 Aug 22, 2025
6c3b642
feat(minimessage): add atlas argument to sprite tag
Strokkur424 Aug 22, 2025
4fe2652
chore: apply suggestions
Strokkur424 Aug 22, 2025
c00715d
chore: spotless apply
Strokkur424 Sep 17, 2025
8dfb187
chore: fix rebase compile time errors
Strokkur424 Sep 17, 2025
6db5673
fix: gradlew build compile time errors
Strokkur424 Sep 19, 2025
ae092f4
Merge pull request #1292 from Strokkur424/feat/sprite-tag
jpenilla Sep 19, 2025
beb052d
feat: start work on named arguments in tags
Strokkur424 Sep 17, 2025
f1e2234
feat: modify token parser to parse named arguments
Strokkur424 Sep 18, 2025
6e0c648
chore: introduce new TokenType to uniquely distinguish value-less tog…
Strokkur424 Sep 18, 2025
3aea640
feat: (WIP) abstracting away TagProvider into QueuedTagProvider and N…
Strokkur424 Sep 18, 2025
1172751
fix: (WIP) parser should now theoretically be able to distinguish nam…
Strokkur424 Sep 19, 2025
17d553a
feat: flesh out parsing logic further and fix a bunch of issues
Strokkur424 Sep 19, 2025
7ee25ea
feat: add test for basic named argument parsing
Strokkur424 Sep 19, 2025
74484c7
feat: start adding more tests
Strokkur424 Sep 19, 2025
bdca761
fix: <red > tag with space being recognized as valid tag
Strokkur424 Sep 19, 2025
fe2fe03
feat: add a bunch more tests
Strokkur424 Sep 19, 2025
c20b3b7
chore: fix all compile time issues
Strokkur424 Sep 19, 2025
e76be23
feat: add test
Strokkur424 Sep 19, 2025
51913b9
chore: cleanup diff and rename to sequential
Strokkur424 Sep 19, 2025
783b5cd
chore: add a bunch more tests
Strokkur424 Sep 20, 2025
8c3b14a
feat: add inverted flag arguments
Strokkur424 Sep 20, 2025
c2d8f65
feat: split the claiming resolvers into named and sequenced resolvers
Strokkur424 Sep 20, 2025
d4894ba
feat: add missing context newException method and try to parse tag wi…
Strokkur424 Sep 20, 2025
7c55a07
feat: add isFlagPresent
Strokkur424 Sep 20, 2025
07d0557
fix: invalid tag in test
Strokkur424 Sep 20, 2025
6f4ca44
feat: add named argument support to token emitter
Strokkur424 Sep 23, 2025
92a93c3
feat: add flag support to token emitter
Strokkur424 Sep 23, 2025
f758731
chore: remove unused import
Strokkur424 Sep 23, 2025
b9c9547
feat: add head tag
Strokkur424 Sep 18, 2025
0a89d05
chore: migrate head tag to named arguments
Strokkur424 Sep 23, 2025
7383cb1
chore: update tests for head tag
Strokkur424 Sep 23, 2025
1817525
chore: rename HAT_DEFAULT to be consistent with other static default …
Strokkur424 Sep 23, 2025
8c944e4
feat: add simple sequential head tag for basic arguments
Strokkur424 Sep 23, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Refactor ObjectComponent to have a Contents
  • Loading branch information
jpenilla committed Aug 22, 2025
commit ff3b13f71d8b65b150501e57f56569c4271e54bc
21 changes: 4 additions & 17 deletions api/src/main/java/net/kyori/adventure/text/Component.java
Original file line number Diff line number Diff line change
Expand Up @@ -601,28 +601,15 @@ public interface Component extends ComponentBuilderApplicable, ComponentLike, Ex
}

/**
* Creates an object component with an atlas and sprite.
* Creates an object component with the given contents.
*
* @param atlas the atlas
* @param sprite the sprite
* @return an object component
* @since 4.25.0
*/
@Contract(value = "_, _ -> new", pure = true)
static @NotNull ObjectComponent object(final @Nullable Key atlas, final @NotNull Key sprite) {
return ObjectComponentImpl.create(Collections.emptyList(), Style.empty(), atlas, requireNonNull(sprite, "sprite"));
}

/**
* Creates an object component a sprite and the default atlas.
*
* @param sprite the sprite
* @param contents the contents
* @return an object component
* @since 4.25.0
*/
@Contract(value = "_ -> new", pure = true)
static @NotNull ObjectComponent object(final @NotNull Key sprite) {
return ObjectComponentImpl.create(Collections.emptyList(), Style.empty(), null, requireNonNull(sprite, "sprite"));
static @NotNull ObjectComponent object(final ObjectComponent.@NotNull Contents contents) {
return ObjectComponentImpl.create(Collections.emptyList(), Style.empty(), contents);
}

/*
Expand Down
113 changes: 77 additions & 36 deletions api/src/main/java/net/kyori/adventure/text/ObjectComponent.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,62 +25,112 @@

import java.util.stream.Stream;
import net.kyori.adventure.key.Key;
import net.kyori.examination.Examinable;
import net.kyori.examination.ExaminableProperty;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import static java.util.Objects.requireNonNull;

/**
* Displays a sprite based on an atlas and sprite key.
* Displays a non-text object.
*
* @since 4.25.0
* @sinceMinecraft 1.21.9
*/
public interface ObjectComponent extends BuildableComponent<ObjectComponent, ObjectComponent.Builder>, ScopedComponent<ObjectComponent> {
/**
* Gets the atlas key.
*
* <p>When null, the default atlas key is used by the client, currently {@code minecraft:blocks}.</p>
* Gets the contents of this object component.
*
* @return the atlas key or null
* @return the contents
* @since 4.25.0
*/
@Nullable Key atlas();
@NotNull Contents contents();

/**
* Gets the sprite key.
* Creates a copy of this object component with the given contents.
*
* @return the sprite key
* @param contents the contents to set
* @return new object component
* @since 4.25.0
*/
@NotNull Key sprite();
@NotNull ObjectComponent contents(@NotNull Contents contents);

@Override
default @NotNull Stream<? extends ExaminableProperty> examinableProperties() {
return Stream.concat(
Stream.of(ExaminableProperty.of("contents", this.contents())),
BuildableComponent.super.examinableProperties()
);
}

/**
* Creates a copy of this object component with a new atlas key.
* An object component contents.
*
* @param atlas the atlas key, or null for the default
* @return a new object component
* @since 4.25.0
*/
@NotNull ObjectComponent atlas(@Nullable Key atlas);
/*sealed*/ interface Contents extends Examinable /*permits SpriteContents*/ {
/**
* Creates a sprite contents with the given atlas and sprite.
*
* @param atlas the atlas
* @param sprite the sprite
* @return a sprite contents
* @since 4.25.0
*/
@Contract(value = "_, _ -> new", pure = true)
static @NotNull SpriteContents sprite(final @Nullable Key atlas, final @NotNull Key sprite) {
return new ObjectComponentImpl.SpriteContentsImpl(atlas, requireNonNull(sprite, "sprite"));
}

/**
* Creates a sprite contents with the given sprite and the default atlas.
*
* @param sprite the sprite
* @return a sprite contents
* @since 4.25.0
*/
@Contract(value = "_ -> new", pure = true)
static @NotNull SpriteContents sprite(final @NotNull Key sprite) {
return new ObjectComponentImpl.SpriteContentsImpl(null, requireNonNull(sprite, "sprite"));
}
}

/**
* Creates a copy of this object component with a new sprite key.
* A sprite contents.
*
* <p>Represents a sprite in an atlas, such as a block texture.</p>
*
* @param sprite the sprite key
* @return a new object component
* @since 4.25.0
* @sinceMinecraft 1.21.9
*/
@NotNull ObjectComponent sprite(@NotNull Key sprite);
interface SpriteContents extends Contents {
/**
* Gets the atlas key.
*
* <p>When null, the default atlas key is used by the client, currently {@code minecraft:blocks}.</p>
*
* @return the atlas key or null
* @since 4.25.0
*/
@Nullable Key atlas();

@Override
default @NotNull Stream<? extends ExaminableProperty> examinableProperties() {
return Stream.concat(
Stream.of(
/**
* Gets the sprite key.
*
* @return the sprite key
* @since 4.25.0
*/
@NotNull Key sprite();

@Override
default @NotNull Stream<? extends ExaminableProperty> examinableProperties() {
return Stream.of(
ExaminableProperty.of("atlas", this.atlas()),
ExaminableProperty.of("sprite", this.sprite())
),
BuildableComponent.super.examinableProperties()
);
);
}
}

/**
Expand All @@ -90,21 +140,12 @@ public interface ObjectComponent extends BuildableComponent<ObjectComponent, Obj
*/
interface Builder extends ComponentBuilder<ObjectComponent, Builder> {
/**
* Sets the atlas key.
*
* @param atlas the atlas key
* @return this builder
* @since 4.25.0
*/
@NotNull Builder atlas(@Nullable Key atlas);

/**
* Sets the sprite key.
* Sets the contents of this object component builder.
*
* @param sprite the sprite key
* @param contents the contents to set
* @return this builder
* @since 4.25.0
*/
@NotNull Builder sprite(@NotNull Key sprite);
@NotNull Builder contents(@NotNull Contents contents);
}
}
104 changes: 61 additions & 43 deletions api/src/main/java/net/kyori/adventure/text/ObjectComponentImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,33 +34,21 @@
import static java.util.Objects.requireNonNull;

final class ObjectComponentImpl extends AbstractComponent implements ObjectComponent {
private final @Nullable Key atlas;
private final Key sprite;
private final Contents contents;

private ObjectComponentImpl(final @NotNull List<Component> children, final @NotNull Style style, final @Nullable Key atlas, final @NotNull Key sprite) {
private ObjectComponentImpl(final @NotNull List<Component> children, final @NotNull Style style, final @NotNull Contents contents) {
super(children, style);
this.atlas = atlas;
this.sprite = sprite;
this.contents = contents;
}

@Override
public @Nullable Key atlas() {
return this.atlas;
public @NotNull Contents contents() {
return this.contents;
}

@Override
public @NotNull Key sprite() {
return this.sprite;
}

@Override
public @NotNull ObjectComponent atlas(final @Nullable Key atlas) {
return create(this.children, this.style, atlas, this.sprite);
}

@Override
public @NotNull ObjectComponent sprite(final @NotNull Key sprite) {
return create(this.children, this.style, this.atlas, requireNonNull(sprite, "sprite"));
public @NotNull ObjectComponent contents(final @NotNull Contents contents) {
return create(this.children, this.style, contents);
}

@Override
Expand All @@ -69,15 +57,13 @@ public boolean equals(final @Nullable Object other) {
if (!(other instanceof ObjectComponent)) return false;
if (!super.equals(other)) return false;
final ObjectComponentImpl that = (ObjectComponentImpl) other;
return Objects.equals(this.atlas, that.atlas())
&& Objects.equals(this.sprite, that.sprite());
return Objects.equals(this.contents, that.contents());
}

@Override
public int hashCode() {
int result = super.hashCode();
result = (31 * result) + Objects.hashCode(this.atlas);
result = (31 * result) + this.sprite.hashCode();
result = (31 * result) + this.contents.hashCode();
return result;
}

Expand All @@ -91,54 +77,86 @@ public String toString() {
return new BuilderImpl(this);
}

static @NotNull ObjectComponentImpl create(final @NotNull List<? extends ComponentLike> children, final @NotNull Style style, final @Nullable Key atlas, final @NotNull Key sprite) {
static @NotNull ObjectComponentImpl create(final @NotNull List<? extends ComponentLike> children, final @NotNull Style style, final @NotNull Contents contents) {
return new ObjectComponentImpl(
ComponentLike.asComponents(children, IS_NOT_EMPTY),
requireNonNull(style, "style"),
atlas,
requireNonNull(sprite, "sprite")
requireNonNull(contents, "contents")
);
}

@Override
public @NotNull ObjectComponent children(final @NotNull List<? extends ComponentLike> children) {
return create(children, this.style, this.atlas, this.sprite);
return create(children, this.style, this.contents);
}

@Override
public @NotNull ObjectComponent style(final @NotNull Style style) {
return create(this.children, style, this.atlas, this.sprite);
return create(this.children, style, this.contents);
}

static class BuilderImpl extends AbstractComponentBuilder<ObjectComponent, ObjectComponent.Builder> implements ObjectComponent.Builder {
private Key atlas;
private Key sprite;
static final class SpriteContentsImpl implements SpriteContents {
private final @Nullable Key atlas;
private final Key sprite;

BuilderImpl() {
SpriteContentsImpl(final @Nullable Key atlas, final @NotNull Key sprite) {
this.atlas = atlas;
this.sprite = requireNonNull(sprite, "sprite");
}

BuilderImpl(final @NotNull ObjectComponent component) {
super(component);
this.atlas = component.atlas();
this.sprite = component.sprite();
@Override
public @Nullable Key atlas() {
return this.atlas;
}

@Override
public @NotNull Builder atlas(final @Nullable Key atlas) {
this.atlas = atlas;
return this;
public @NotNull Key sprite() {
return this.sprite;
}

@Override
public @NotNull Builder sprite(final @NotNull Key sprite) {
this.sprite = requireNonNull(sprite, "sprite");
public boolean equals(final @Nullable Object other) {
if (this == other) return true;
if (!(other instanceof SpriteContents)) return false;
final SpriteContentsImpl that = (SpriteContentsImpl) other;
return Objects.equals(this.atlas, that.atlas())
&& Objects.equals(this.sprite, that.sprite());
}

@Override
public int hashCode() {
int result = Objects.hashCode(this.atlas);
result = (31 * result) + this.sprite.hashCode();
return result;
}

@Override
public String toString() {
return Internals.toString(this);
}
}

static final class BuilderImpl extends AbstractComponentBuilder<ObjectComponent, ObjectComponent.Builder> implements ObjectComponent.Builder {
private Contents contents;

BuilderImpl() {
}

BuilderImpl(final @NotNull ObjectComponent component) {
super(component);
this.contents = component.contents();
}

@Override
public @NotNull Builder contents(final @NotNull Contents contents) {
this.contents = requireNonNull(contents, "contents");
return this;
}

@Override
public @NotNull ObjectComponent build() {
if (this.sprite == null) throw new IllegalStateException("sprite id must be set");
return create(this.children, this.buildStyle(), this.atlas, this.sprite);
if (this.contents == null) throw new IllegalStateException("contents must be set");
return create(this.children, this.buildStyle(), this.contents);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,24 +31,17 @@
class ObjectComponentTest extends AbstractComponentTest<ObjectComponent, ObjectComponent.Builder> {
@Override
ObjectComponent.Builder builder() {
return Component.object().sprite(Key.key("sprite"));
return Component.object().contents(ObjectComponent.Contents.sprite(Key.key("sprite")));
}

@Test
void testSprite() {
final ObjectComponent c0 = Component.object(Key.key("atlas"), Key.key("sprite"));
final ObjectComponent c1 = c0.sprite(Key.key("sprite1"));
assertEquals(Key.key("sprite"), c0.sprite());
assertEquals(Key.key("sprite1"), c1.sprite());
assertEquals(Key.key("atlas"), c1.atlas());
}
void testContents() {
final ObjectComponent.SpriteContents sprite = ObjectComponent.Contents.sprite(Key.key("atlas"), Key.key("sprite"));
final ObjectComponent c0 = Component.object(sprite);
assertEquals(sprite, c0.contents());

@Test
void testAtlas() {
final ObjectComponent c0 = Component.object(Key.key("atlas"), Key.key("sprite"));
final ObjectComponent c1 = c0.atlas(Key.key("atlas1"));
assertEquals(Key.key("atlas"), c0.atlas());
assertEquals(Key.key("atlas1"), c1.atlas());
assertEquals(Key.key("sprite"), c1.sprite());
final ObjectComponent.SpriteContents sprite1 = ObjectComponent.Contents.sprite(Key.key("atlas"), Key.key("sprite1"));
final ObjectComponent c1 = c0.contents(sprite1);
assertEquals(sprite1, c1.contents());
}
}
Loading