Skip to content

Commit f682040

Browse files
committed
v13.3.0
1 parent c117648 commit f682040

File tree

11 files changed

+104
-63
lines changed

11 files changed

+104
-63
lines changed

README.md

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
![XSeries Logo](https://github.com/user-attachments/assets/4b179b17-3f2b-4640-bc50-df2275300bcb)
2+
13
# XSeries
24

35
[![Minecraft](https://img.shields.io/badge/Minecraft-1.21.5-dark_green.svg)](https://shields.io/)
@@ -13,7 +15,7 @@ Some utilities are completely unrelated to cross-version support such as NoteBlo
1315
> [!IMPORTANT]
1416
> Don't forget to add `api-version: "1.13"` to your **plugin.yml**.
1517
> This will not prevent your plugin from working even if the server is not using Minecraft v1.13
16-
> This is only required if you want to use one of the XBase/XModule classes.
18+
> This is only required if you want to use one of the XBase/XModule classes.
1719
1820
> [!CAUTION]
1921
> Make sure to [shade](https://github.com/CryptoMorin/XSeries?tab=readme-ov-file#shading)
@@ -42,7 +44,8 @@ You can use some of these utilities individually or use the maven dependency.
4244
Most of the utilities are intended to be independent. However, some
4345
utilities such as [XParticle](core/src/main/java/com/cryptomorin/xseries/particles/XParticle.java) are intended to use
4446
another class ([ParticleDisplay](core/src/main/java/com/cryptomorin/xseries/particles/ParticleDisplay.java)).
45-
All XBase/XModule classes also depend on these base classes and also [XRegistry](core/src/main/java/com/cryptomorin/xseries/base).
47+
All XBase/XModule classes also depend on these base classes and
48+
also [XRegistry](core/src/main/java/com/cryptomorin/xseries/base).
4649

4750
#### Maven ![maven-central](https://img.shields.io/maven-central/v/com.github.cryptomorin/XSeries)
4851

@@ -53,21 +56,26 @@ All XBase/XModule classes also depend on these base classes and also [XRegistry]
5356
<artifactId>XSeries</artifactId>
5457
<version>version</version>
5558
</dependency>
56-
57-
<!-- If you want to use XSkull and you use 'spigot-api' dependency you need the following: -->
58-
<repository>
59-
<id>minecraft-libraries</id>
60-
<name>Minecraft Libraries</name>
61-
<url>https://libraries.minecraft.net/</url>
62-
</repository>
63-
<dependency>
64-
<groupId>com.mojang</groupId>
65-
<artifactId>authlib</artifactId>
66-
<version>6.0.54</version>
67-
<scope>provided</scope>
68-
</dependency>
6959
```
7060

61+
> [!NOTE]
62+
> If you want to use XSkull and you use `spigot-api` dependency you need the following:
63+
> ```xml
64+
> <repository>
65+
> <id>minecraft-libraries</id>
66+
> <name>Minecraft Libraries</name>
67+
> <url>https://libraries.minecraft.net/</url>
68+
> </repository>
69+
> ```
70+
> ```xml
71+
> <dependency>
72+
> <groupId>com.mojang</groupId>
73+
> <artifactId>authlib</artifactId>
74+
> <version>6.0.54</version>
75+
> <scope>provided</scope>
76+
> </dependency>
77+
> ```
78+
7179
Gradle
7280
7381
```kotlin

core/src/main/java/com/cryptomorin/xseries/messages/MessageComponents.java

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,12 @@
3131
import org.jetbrains.annotations.ApiStatus;
3232

3333
import java.lang.invoke.MethodHandle;
34-
import java.util.regex.Pattern;
3534

3635
import static com.cryptomorin.xseries.reflection.XReflection.ofMinecraft;
3736

3837
/**
3938
* Utility class for sharing methods relating to {@link BaseComponent}.
4039
*/
41-
@ApiStatus.Experimental
4240
public final class MessageComponents {
4341
private static final MethodHandle CraftChatMessage_fromJson;
4442

@@ -61,16 +59,36 @@ public final class MessageComponents {
6159
CraftChatMessage_fromJson = fromJson;
6260
}
6361

62+
// @formatter:off
63+
public interface MessageText {
64+
String asString();
65+
BaseComponent asComponent();
66+
}
67+
public static final class MessageTextString implements MessageText {
68+
private final String string;
69+
public MessageTextString(String string) {this.string = string;}
70+
71+
public String asString() {return string;}
72+
public BaseComponent asComponent() {return MessageComponents.fromLegacy(string);}
73+
}
74+
public static final class MessageTextComponent implements MessageText {
75+
private final BaseComponent component;
76+
public MessageTextComponent(BaseComponent component) {this.component = component;}
77+
78+
public String asString() {return component.toLegacyText();}
79+
public BaseComponent asComponent() {return component;}
80+
}
81+
// @formatter:on
82+
6483
/**
6584
* This method is only officially available on <a href="https://github.com/PaperMC/Paper/blob/c98cd65802fcecfd3db613819e6053e2b8cbdf4f/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java#L350-L352">Paper</a>.
6685
*/
86+
@ApiStatus.Experimental
6787
public static Object bungeeToVanilla(BaseComponent component) throws Throwable {
6888
String json = ComponentSerializer.toString(component);
6989
return CraftChatMessage_fromJson.invoke(json);
7090
}
7191

72-
private static final Pattern url = Pattern.compile("^(?:(https?)://)?([-\\w_.]{2,}\\.[a-z]{2,4})(/\\S*)?$");
73-
7492
@SuppressWarnings("deprecation")
7593
public static BaseComponent fromLegacy(String message) {
7694
return new TextComponent(TextComponent.fromLegacyText(message));

core/src/main/java/com/cryptomorin/xseries/messages/Titles.java

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import java.util.Objects;
4040
import java.util.function.Function;
4141

42+
import static com.cryptomorin.xseries.messages.MessageComponents.*;
4243
import static com.cryptomorin.xseries.reflection.XReflection.ofMinecraft;
4344
import static com.cryptomorin.xseries.reflection.minecraft.MinecraftConnection.sendPacket;
4445

@@ -55,6 +56,7 @@
5556
* @author Crypto Morin
5657
* @version 4.0.0
5758
* @see XReflection
59+
* @see ActionBar
5860
*/
5961
public final class Titles {
6062
/**
@@ -74,7 +76,7 @@ public final class Titles {
7476
ClientboundSetTitleTextPacket,
7577
ClientboundSetSubtitleTextPacket;
7678

77-
private BaseComponent title, subtitle;
79+
private MessageText title, subtitle;
7880
private final int fadeIn, stay, fadeOut;
7981

8082
/**
@@ -175,16 +177,20 @@ public final class Titles {
175177
ClientboundSetSubtitleTextPacket = subtitleCtor;
176178
}
177179

178-
public Titles(BaseComponent title, BaseComponent subtitle, int fadeIn, int stay, int fadeOut) {
180+
public Titles(MessageText title, MessageText subtitle, int fadeIn, int stay, int fadeOut) {
179181
this.title = title;
180182
this.subtitle = subtitle;
181183
this.fadeIn = fadeIn;
182184
this.stay = stay;
183185
this.fadeOut = fadeOut;
184186
}
185187

188+
public Titles(BaseComponent title, BaseComponent subtitle, int fadeIn, int stay, int fadeOut) {
189+
this(new MessageTextComponent(title), new MessageTextComponent(subtitle), fadeIn, stay, fadeOut);
190+
}
191+
186192
public Titles(String title, String subtitle, int fadeIn, int stay, int fadeOut) {
187-
this(MessageComponents.fromLegacy(title), MessageComponents.fromLegacy(subtitle), fadeIn, stay, fadeOut);
193+
this(new MessageTextString(title), new MessageTextString(subtitle), fadeIn, stay, fadeOut);
188194
}
189195

190196
public Titles copy() {
@@ -210,12 +216,12 @@ public void send(Player player) {
210216
public static void sendTitle(@NotNull Player player,
211217
int fadeIn, int stay, int fadeOut,
212218
@Nullable String title, @Nullable String subtitle) {
213-
sendTitle(player, fadeIn, stay, fadeOut, MessageComponents.fromLegacy(title), MessageComponents.fromLegacy(subtitle));
219+
sendTitle(player, fadeIn, stay, fadeOut, new MessageTextString(title), new MessageTextString(subtitle));
214220
}
215221

216222
public static void sendTitle(@NotNull Player player,
217223
int fadeIn, int stay, int fadeOut,
218-
@Nullable BaseComponent title, @Nullable BaseComponent subtitle) {
224+
@Nullable MessageText title, @Nullable MessageText subtitle) {
219225
Objects.requireNonNull(player, "Cannot send title to null player");
220226
if (title == null && subtitle == null) return;
221227

@@ -228,11 +234,11 @@ public static void sendTitle(@NotNull Player player,
228234
packets.add(ClientboundSetTitlesAnimationPacket.invoke(fadeIn, stay, fadeOut));
229235

230236
if (title != null) {
231-
packets.add(ClientboundSetTitleTextPacket.invoke(MessageComponents.bungeeToVanilla(title)));
237+
packets.add(ClientboundSetTitleTextPacket.invoke(MessageComponents.bungeeToVanilla(title.asComponent())));
232238
}
233239

234240
if (subtitle != null) {
235-
packets.add(ClientboundSetSubtitleTextPacket.invoke(MessageComponents.bungeeToVanilla(title)));
241+
packets.add(ClientboundSetSubtitleTextPacket.invoke(MessageComponents.bungeeToVanilla(subtitle.asComponent())));
236242
}
237243
} catch (Throwable e) {
238244
throw new RuntimeException(e);
@@ -243,7 +249,7 @@ public static void sendTitle(@NotNull Player player,
243249
}
244250

245251
if (SUPPORTS_TITLES) {
246-
player.sendTitle(title.toLegacyText(), subtitle.toLegacyText(), fadeIn, stay, fadeOut);
252+
player.sendTitle(title.asString(), subtitle.asString(), fadeIn, stay, fadeOut);
247253
return;
248254
}
249255

@@ -330,30 +336,28 @@ public static Titles parseTitle(@NotNull ConfigurationSection config, @Nullable
330336
return new Titles(title, subtitle, fadeIn, stay, fadeOut);
331337
}
332338

333-
public BaseComponent getTitle() {
339+
public MessageText getTitle() {
334340
return title;
335341
}
336342

337-
public BaseComponent getSubtitle() {
343+
public MessageText getSubtitle() {
338344
return subtitle;
339345
}
340346

341-
@Deprecated
342347
public void setTitle(String title) {
343-
this.title = MessageComponents.fromLegacy(title);
348+
this.title = new MessageTextString(title);
344349
}
345350

346-
@Deprecated
347351
public void setSubtitle(String subtitle) {
348-
this.subtitle = MessageComponents.fromLegacy(subtitle);
352+
this.subtitle = new MessageTextString(subtitle);
349353
}
350354

351355
public void setTitle(BaseComponent title) {
352-
this.title = title;
356+
this.title = new MessageTextComponent(title);
353357
}
354358

355359
public void setSubtitle(BaseComponent subtitle) {
356-
this.subtitle = subtitle;
360+
this.subtitle = new MessageTextComponent(subtitle);
357361
}
358362

359363
/**

core/src/main/java/com/cryptomorin/xseries/profiles/mojang/MojangAPI.java

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,9 @@ public static Map<UUID, String> usernamesToUUIDs(@NotNull Collection<String> use
216216

217217
try {
218218
for (String username : usernames) {
219-
finalUsernames.put(username, MojangRequestQueue.USERNAME_REQUESTS.lock(username));
219+
KeyedLock<String> lock = MojangRequestQueue.USERNAME_REQUESTS.lock(username);
220+
lock.lock();
221+
finalUsernames.put(username, lock);
220222
}
221223

222224
{
@@ -349,21 +351,27 @@ public static GameProfile getOrFetchProfile(@NotNull final GameProfile profile)
349351
}
350352
}
351353

352-
GameProfile cached = handleCache(profile, realUUID);
353-
if (cached != null) return cached;
354+
try (KeyedLock<UUID> lock = MojangRequestQueue.UUID_REQUESTS.lock(realUUID)) {
355+
lock.lock();
354356

355-
JsonElement request = requestProfile(profile, realUUID);
356-
JsonObject profileData = request.getAsJsonObject();
357-
List<String> profileActions = new ArrayList<>();
358-
GameProfile fetchedProfile = createGameProfile(profileData, profileActions);
357+
GameProfile cached = handleCache(profile, realUUID);
358+
if (cached != null) return cached;
359359

360-
fetchedProfile = PlayerProfiles.sanitizeProfile(fetchedProfile);
361-
cacheProfile(fetchedProfile);
360+
JsonElement request = requestProfile(profile, realUUID);
361+
JsonObject profileData = request.getAsJsonObject();
362+
List<String> profileActions = new ArrayList<>();
363+
GameProfile fetchedProfile = createGameProfile(profileData, profileActions);
362364

363-
INSECURE_PROFILES.put(realUUID, Optional.of(fetchedProfile));
364-
MOJANG_PROFILE_CACHE.cache(new PlayerProfile(realUUID, profile, fetchedProfile, profileActions));
365+
fetchedProfile = PlayerProfiles.sanitizeProfile(fetchedProfile);
366+
cacheProfile(fetchedProfile);
365367

366-
return fetchedProfile;
368+
INSECURE_PROFILES.put(realUUID, Optional.of(fetchedProfile));
369+
MOJANG_PROFILE_CACHE.cache(new PlayerProfile(realUUID, profile, fetchedProfile, profileActions));
370+
371+
return fetchedProfile;
372+
} catch (Throwable ex) {
373+
throw new IllegalStateException("Failed to fetch porfile for " + profile, ex);
374+
}
367375
}
368376

369377
@SuppressWarnings("OptionalAssignedToNull")
@@ -387,8 +395,7 @@ public static GameProfile getOrFetchProfile(@NotNull final GameProfile profile)
387395

388396
private static @NotNull JsonElement requestProfile(@NotNull GameProfile profile, UUID realUUID) {
389397
JsonElement request;
390-
try (KeyedLock<UUID> lock = MojangRequestQueue.UUID_REQUESTS.lock(realUUID)) {
391-
lock.lock();
398+
try {
392399
request = UUID_TO_PROFILE.session(null)
393400
.append(PlayerUUIDs.toUndashedUUID(realUUID) + "?unsigned=" + !REQUIRE_SECURE_PROFILES)
394401
.request();
@@ -401,6 +408,7 @@ public static GameProfile getOrFetchProfile(@NotNull final GameProfile profile)
401408
MOJANG_PROFILE_CACHE.cache(new PlayerProfile(realUUID, profile, null, null));
402409
throw new UnknownPlayerException(realUUID, "Player with the given properties not found: " + profile);
403410
}
411+
404412
return request;
405413
}
406414

core/src/main/java/com/cryptomorin/xseries/profiles/objects/DelegateProfileable.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ default GameProfile getProfile() {
6464
}
6565

6666
@Override
67-
default boolean isComplete() {return getDelegateProfile().isComplete();}
67+
default boolean isReady() {return getDelegateProfile().isReady();}
6868

6969
@Override
7070
@NotNull

core/src/main/java/com/cryptomorin/xseries/profiles/objects/ProfileContainer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public abstract class ProfileContainer<T> implements Profileable {
5252
public abstract T getObject();
5353

5454
@Override
55-
public boolean isComplete() {
55+
public boolean isReady() {
5656
return true;
5757
}
5858

core/src/main/java/com/cryptomorin/xseries/profiles/objects/Profileable.java

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -84,17 +84,18 @@ public interface Profileable {
8484
GameProfile getProfile();
8585

8686
/**
87-
* Whether this profile has all necessary information to construct its {@link #getProfile()} right away.
88-
* When this returns true, it means some kind of request has to be sent to Mojang servers
89-
* in order to retrieve information.
87+
* Whether this profile has all the necessary information to construct its {@link #getProfile()} right away.
88+
* When this method returns false, it means some kind of request has to be sent to Mojang servers
89+
* in order to retrieve some information.
9090
* <p>
91-
* This doesn't necessarily mean that this profile has all information (skin, username, UUID, etc.)
92-
* it merely means that it has all the information it needs in memory to compute {@link #getProfile()}
93-
* and doesn't need to a request using {@link com.cryptomorin.xseries.profiles.mojang.MinecraftClient MinecraftClient}.
91+
* Even if this method returns true, it doesn't necessarily mean that this profile has all information (textures, username, UUID, etc.)
92+
* it merely means that it has all the information it needs in memory to compute its {@link #getProfile()}
93+
* and doesn't need to a request any data using {@link com.cryptomorin.xseries.profiles.mojang.MinecraftClient MinecraftClient}.
9494
*
9595
* @see #prepare(Collection)
9696
*/
97-
boolean isComplete();
97+
@Contract(pure = true)
98+
boolean isReady();
9899

99100
/**
100101
* Tests whether this profile has any issues or throws any exception.
@@ -109,6 +110,7 @@ public interface Profileable {
109110
* Any other type of exception that might happen are still ignored.
110111
*/
111112
@Nullable
113+
@Contract("-> new")
112114
default ProfileException test() {
113115
try {
114116
getProfile();
@@ -129,6 +131,7 @@ default ProfileException test() {
129131
*/
130132
@Nullable
131133
@ApiStatus.Internal
134+
@Contract("-> new")
132135
default GameProfile getDisposableProfile() {
133136
GameProfile profile = getProfile();
134137
return profile == null ? null : PlayerProfiles.clone(profile);
@@ -429,7 +432,7 @@ final class RawGameProfileProfileable implements Profileable {
429432
public RawGameProfileProfileable(GameProfile profile) {this.profile = Objects.requireNonNull(profile);}
430433

431434
@Override
432-
public boolean isComplete() {
435+
public boolean isReady() {
433436
return true;
434437
}
435438

core/src/main/java/com/cryptomorin/xseries/profiles/objects/cache/CacheableProfileable.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public final boolean hasExpired() {
7777
}
7878

7979
@Override
80-
public final boolean isComplete() {
80+
public final boolean isReady() {
8181
return !hasExpired(false);
8282
}
8383

core/src/main/java/com/cryptomorin/xseries/profiles/objects/transformer/TransformableProfile.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ private void transform() {
9191
}
9292

9393
@Override
94-
public boolean isComplete() {
94+
public boolean isReady() {
9595
return true;
9696
}
9797

0 commit comments

Comments
 (0)