Skip to content

Converts ExprColorOf into a Type Property - #8852

Open
ItsTheSky wants to merge 22 commits into
SkriptLang:dev/featurefrom
ItsTheSky:feat/new-type-properties
Open

Converts ExprColorOf into a Type Property#8852
ItsTheSky wants to merge 22 commits into
SkriptLang:dev/featurefrom
ItsTheSky:feat/new-type-properties

Conversation

@ItsTheSky

Copy link
Copy Markdown

Problem

ExprColorOf is still a classic PropertyExpression with a seven branch instanceof chain over Block, ItemType, Entity, FireworkEffect, PotionEffectType, Display and BossBar.
The logic for each type lives in the expression instead of with the type, and addons cannot hook their own types into color of without making tricky things or conflicts.

While converting it, i've faced two bugs in the property framework; Both block this
property from working at all, and both affect every existing type property. I tried to fix them on my own, please tell me what you think of it:

  1. PropertyBaseExpression#acceptChange returns new Class[0] from inside its loop on RESET/DELETE. Handlers after the first accepting one never get their types stored in changeDetails, so change() silently skips them. With seven types in an unordered HashMap, reset color of {_display} would fail depending on iteration order.
  2. PropertyBaseSyntax#getPossiblePropertyInfos passes the source expression to PropertyHandler#init, although the javadoc says "the expression that is using this handler". Source expressions (Variable, ConvertedExpression) do not implement RuntimeErrorProducer, so a handler can never emit a runtime error. That breaks the bossbar "Could not round to a color that is similar to ..." error asserted by ExprSecCreateBossBar.sk (when I ran the tests after my changes)

ExprColorOf also has some "bugs" of its own: an &&/|| precedence mistake that makes acceptChange accept every change mode for bossbars while change handles only SET/RESET, delta[0] dereferenced without a null or length guard, and a firework read path that only fires when the expression is statically typed as a firework effect (not sur eit that was intentional tho).

Solution

Follows the ExprName / PropExprName (and other new type properties') pattern:

New system: I added Property.COLOR and PropExprColor (+ its registration), and registered properties of that type property in the related class info (BlockClassInfo, ItemTypeClassInfo, ...)

Old system: ExprColorOf gets @Deprecated(forRemoval = true) and an early return in register(SyntaxRegistry) when SkriptConfig.useTypeProperties is on. No other line of it changes, so the two latent bugs stay put there and are fixed in the new handlers only.

Note

Display extends Entity and PropertyMap resolves handlers from the declared types of an expression. The old code did a runtime instanceof Display check regardless of the declared type, so color of event-entity worked on a text display. Without delegation that silently regresses, so EntityColorHandler forwards to DisplayColorHandler when the entity is a display. This is why DisplayColorHandler is a top level class instead of nested in DisplayModule. Maybe there's another/better way to do this?

Testing Completed

src/test/skript/tests/syntaxes/expressions/ExprColorOf.sk extended. It previously only covered displays, with the rest commented out as TODO:

  • color of entities: sheep read and set, covers the Colorable entity path.
  • color of firework effects: read of a multi valued property. The equality assertion is against presence and difference rather than red/blue, because firework colors come back as raw rgb (rgb 179, 49, 44) which does not match the dye color they were built from.
  • color of displays through an entity expression: locks in the Entity to Display delegation.

Supporting Information

Behaviour differences (which are all improvements):

  • Firework effect reads now work on untyped expressions. The old code tested source instanceof FireworkEffect[], which only matches a statically typed expression, so color of {_effect} on a variable returned nothing.
  • Bossbars no longer accept change modes they never applied (instead of throwing an error)

Questions to sharpen this PR

  1. I added an overload rather than changing getPossiblePropertyInfos(Property, Expression), to avoid breaking PropCondContains and PropertyBaseCondition, which have no parent expression. Would you rather widen PropertyHandler#init to take a SyntaxElement so conditions get the same capability?
  2. Is bukkit.entity.displays the right home for DisplayColorHandler, or should shared handlers live somewhere more central?
  3. Is preserving color of event-entity on displays worth the Entity to Display coupling, or would you rather accept the narrowing and require a display typed expression?
  4. I copied ExprColorOf's values, so it reads {"1.2", "2.10 (displays)", "2.16 (boss bars)"}, on the grounds that the property documents a capability that has existed since 1.2. The alternative is a single concrete version such as 2.17, since the property itself is new. Which convention do you want for converted syntaxes?
  5. @Deprecated(since = ...) on ExprColorOf is left as "INSERT VERSION". Should it be the next release number, or is the placeholder the expected convention?

Completes: none
Related: none
AI assistance: Inline GitHub Copilot + NES (Next Edit Suggestion) from IntelliJ IDEA ; Claude Code for helping structure the PR description.

It's my first Skript PR, I hope I respected everything :)

@ItsTheSky
ItsTheSky requested review from a team as code owners August 22, 2026 17:56
@ItsTheSky
ItsTheSky requested review from Absolutionism, UnderscoreTud and erenkarakal and removed request for a team August 22, 2026 17:56
@skriptlang-automation skriptlang-automation Bot added needs reviews A PR that needs additional reviews needs triage An issue that hasn't been classified or verified yet labels Aug 22, 2026
@skriptlang-automation

This comment has been minimized.

@skriptlang-automation skriptlang-automation Bot moved this to In Review in 2.17 Releases Aug 22, 2026
@ItsTheSky ItsTheSky closed this Aug 22, 2026
@skriptlang-automation skriptlang-automation Bot removed the needs reviews A PR that needs additional reviews label Aug 22, 2026
@ItsTheSky ItsTheSky reopened this Aug 22, 2026
@skriptlang-automation skriptlang-automation Bot added the needs reviews A PR that needs additional reviews label Aug 22, 2026
@ItsTheSky
ItsTheSky changed the base branch from master to dev/feature August 22, 2026 18:06
@TheMug06

TheMug06 commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Please target dev/patch or dev/feature, instead of master. Thank you :)

@sovdeeth
sovdeeth self-requested a review August 22, 2026 18:08
@skriptlang-automation skriptlang-automation Bot added enhancement Feature request, an issue about something that could be improved, or a PR improving something. and removed needs triage An issue that hasn't been classified or verified yet labels Aug 22, 2026
Comment thread src/main/java/ch/njol/skript/classes/data/BukkitClasses.java Outdated
Comment thread src/main/java/org/skriptlang/skript/bukkit/entity/displays/DisplayModule.java Outdated
Comment thread src/main/java/org/skriptlang/skript/bukkit/potion/PotionModule.java Outdated
Comment thread src/main/java/org/skriptlang/skript/lang/properties/Property.java Outdated
@ItsTheSky
ItsTheSky requested a review from Efnilite August 22, 2026 19:26
Comment thread src/main/java/ch/njol/skript/classes/data/BukkitClasses.java Outdated
@skriptlang-automation skriptlang-automation Bot removed the needs reviews A PR that needs additional reviews label Aug 22, 2026
ItsTheSky and others added 2 commits August 23, 2026 12:48
…/expressions/PropExprColor.java

Co-authored-by: SirSmurfy2 <82696841+Absolutionism@users.noreply.github.com>

@Absolutionism Absolutionism left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good

Comment thread src/main/java/ch/njol/skript/classes/data/BukkitClasses.java Outdated
Comment thread src/main/java/org/skriptlang/skript/bukkit/types/FireworkEffectClassInfo.java Outdated
…tClassInfo.java

Co-authored-by: SirSmurfy2 <82696841+Absolutionism@users.noreply.github.com>
@skriptlang-automation skriptlang-automation Bot added the needs reviews A PR that needs additional reviews label Aug 23, 2026
@ItsTheSky

Copy link
Copy Markdown
Author

If you have some time I can also work on passing some other properties with the new system; those includes: ExprEntityOwner, ExprLocationOf, ExprBookAuthor, ExprBookPages (for content) and the plural version of PropExprColor.

(those may appear a bit random but I'm facing several conflicts with their pattenrs while working on an addon)

Comment thread src/main/java/org/skriptlang/skript/lang/properties/PropertyBaseExpression.java Outdated
Comment thread src/main/java/org/skriptlang/skript/lang/properties/PropertyBaseSyntax.java Outdated
Comment on lines +18 to +25
test "color of firework effects":
set {_effect} to ball firework effect coloured red and blue
set {_colors::*} to colours of {_effect}
# firework colours are reported as raw rgb, which does not match the dye colour they were built from
assert amount of {_colors::*} is 2 with "firework effect should have 2 colours"
assert {_colors::1} is set with "first firework effect colour failed"
assert {_colors::2} is set with "second firework effect colour failed"
assert {_colors::1} is not {_colors::2} with "firework effect colours should differ"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs to test changers too

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't write a passing changer test here: FireworkEffect is immutable. getColors() returns this.colors, declared private final ImmutableList, so the add/remove/clear calls this handler inherits from ExprColorOf all throw UnsupportedOperationException at runtime. That's pre-existing, ExprColorOf has always been broken here, and I kept the logic as-is for parity. I can't change the value of the changing expression itself either, what should I do?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So why does it still accept changes? remove that

Comment thread src/main/java/org/skriptlang/skript/bukkit/types/EntityClassInfo.java Outdated
Comment on lines +94 to +102
if (state instanceof Colorable colorable) {
try {
colorable.setColor(dyeColor);
} catch (UnsupportedOperationException ex) {
// https://github.com/SkriptLang/Skript/issues/2931
Skript.error("Tried setting the color of a bed, but this isn't possible in your Minecraft version, " +
"since different colored beds are different materials. " +
"Instead, set the block to right material, such as a blue bed.");
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

likewise I don't think this functions anymore either.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kinda; On 26.2, Bed is deprecated (since = "26.2", forRemoval = true) with "bed block entity no longer exists", so getState() never returns one and the catch is unreachable there. But it still implements Colorable and its setColor is @contract("_ -> fail"), and Skript still supports 1.21.x where the bed block entity does exist, so I'd keep the catch until the minimum version rises. What do you think?

Also the Colorable branch itself is definitely still live though: Sign implements it, and that's the sign text dye colour. While checking I found the ported code never called state.update(), so setting a sign's colour silently did nothing. Fixed, and I replaced the # test "color of blocks" TODO with a real sign test covering read and write. Is it good?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok but does changing the color of a bed actually work on 1.21.x

@skriptlang-automation skriptlang-automation Bot removed the needs reviews A PR that needs additional reviews label Aug 24, 2026
ItsTheSky and others added 9 commits August 25, 2026 22:06
…seSyntax.java

Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com>
Returning an empty class array does not accept any type, it accepts no types
while still allowing the change, as opposed to returning null. Name the flag
after that rather than after 'any type'.
Callers should use the three-argument variant so the owning syntax can pass
itself as the parent expression, which handlers need to emit runtime errors.
…pertype

getPossiblePropertyInfos only put the nearest class info at or above each of
the expression's declared return types into the property map, so a value whose
runtime type had a more specific handler never reached it. Collect the class
infos below the declared type as well; PropertyMap already picks the most
specific assignable key at runtime.

This lets 'color of event-entity' find the display handler on its own, so the
delegation the entity handler used as a workaround is no longer needed.
The block color handler mutated the block state but never called update(), so
setting the color of a colorable block, a sign for instance, silently did
nothing. Replace the block color test TODO with a sign test covering both
reading and writing.
Adds the OWNER, LOCATION, AUTHOR and CONTENT properties, each with a PropExpr
syntax gated behind 'use type properties', and keeps the expression it replaces
registered and deprecated when the option is off.

- owner: handled by the entity type, ExprEntityOwner gated
- location: handled by the location type as an identity, so anything with a
  converter to a location keeps working; ExprLocationOf gated
- author: handled by the item type, ExprBookAuthor gated
- content: handled by the item type, only the "pages of" patterns of
  ExprBookPages are gated since the property cannot express a page index

PropExprContent overrides isSingle because PropertyBaseExpression only looks at
the source expression, while the pages of a book are multi valued.

getPages, setPages and the sign-if-needed logic move out of ExprBookPages into
BookUtils so the item type handler does not depend on a deprecated expression.
@skriptlang-automation skriptlang-automation Bot added the needs reviews A PR that needs additional reviews label Sep 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement Feature request, an issue about something that could be improved, or a PR improving something. needs reviews A PR that needs additional reviews

Projects

Status: In Review

Development

Successfully merging this pull request may close these issues.

5 participants