Skip to content

Commit 0ce9484

Browse files
committed
v9.10.0
1 parent 7cfefb6 commit 0ce9484

File tree

10 files changed

+221
-65
lines changed

10 files changed

+221
-65
lines changed

pom.xml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>com.github.cryptomorin</groupId>
88
<artifactId>XSeries</artifactId>
9-
<version>9.9.0</version>
9+
<version>9.10.0</version>
1010

1111
<name>XSeries</name>
1212
<description>A set of utilities for Minecraft plugins</description>
@@ -78,6 +78,11 @@
7878
<!-- <artifactId>authlib</artifactId>-->
7979
<!-- <version>1.5.25</version>-->
8080
<!-- <scope>provided</scope>-->
81+
<!-- </dependency>-->
82+
<!-- <dependency>-->
83+
<!-- <groupId>org.jetbrains</groupId>-->
84+
<!-- <artifactId>annotations</artifactId>-->
85+
<!-- <version>24.1.0</version>-->
8186
<!-- </dependency>-->
8287
<dependency>
8388
<groupId>org.spigotmc</groupId>

src/main/java/com/cryptomorin/xseries/NoteBlockMusic.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -418,8 +418,7 @@ protected char checkup(char ch) {
418418

419419
@SuppressWarnings("StringBufferField")
420420
private static final class InstructionBuilder {
421-
@Nonnull
422-
final CharSequence script;
421+
@Nonnull final CharSequence script;
423422
final int len;
424423
final StringBuilder
425424
instrumentBuilder = new StringBuilder(10),
@@ -516,7 +515,7 @@ private Instruction buildInstruction() {
516515
int fermata = fermataBuilder.length() == 0 ? 0 : Integer.parseInt(fermataBuilder.toString());
517516
int restatement = restatementBuilder.length() == 0 ? 1 : Integer.parseInt(restatementBuilder.toString());
518517
int restatementFermata = restatementDelayBuilder.length() == 0 ? 0 : Integer.parseInt(restatementDelayBuilder.toString());
519-
//if (restatement > 1 && restatementFermata <= 0) throw new IllegalStateException("No restatement fermata found at " + i + " with restatement: " + restatement);
518+
// if (restatement > 1 && restatementFermata <= 0) throw new IllegalStateException("No restatement fermata found at " + i + " with restatement: " + restatement);
520519

521520
Instruction instruction;
522521
if (isSequence) {

src/main/java/com/cryptomorin/xseries/SkullUtils.java

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
* I don't know if this cache system works across other servers or is just specific to one server.
6868
*
6969
* @author Crypto Morin
70-
* @version 6.0.1
70+
* @version 7.0.0
7171
* @see XMaterial
7272
* @see ReflectionUtils
7373
*/
@@ -80,7 +80,7 @@ public final class SkullUtils {
8080
* Some people use this without quotes surrounding the keys, not sure what that'd work.
8181
*/
8282
private static final String VALUE_PROPERTY = "{\"textures\":{\"SKIN\":{\"url\":\"";
83-
private static final boolean SUPPORTS_UUID = ReflectionUtils.supports(12);
83+
public static final boolean SUPPORTS_UUID = ReflectionUtils.supports(12);
8484

8585
/**
8686
* We'll just return an x shaped hardcoded skull.
@@ -161,7 +161,7 @@ public final class SkullUtils {
161161

162162
if (!ReflectionUtils.supports(20, 2)) {
163163
try {
164-
//noinspection JavaLangInvokeHandleSignature
164+
// noinspection JavaLangInvokeHandleSignature
165165
propGetval = lookup.findVirtual(Property.class, "getValue", MethodType.methodType(String.class));
166166
} catch (Throwable ex) {
167167
ex.printStackTrace();
@@ -326,19 +326,28 @@ public static StringSkullCache detectSkullValueType(@Nonnull String identifier)
326326

327327
public static void setSkin(@Nonnull Block block, @Nonnull String value) {
328328
Objects.requireNonNull(block, "Can't set skin of null block");
329-
330329
BlockState state = block.getState();
331-
if (!(state instanceof Skull)) return;
330+
setSkin(state, value);
331+
state.update(true);
332+
}
333+
334+
public static void setSkin(@Nonnull BlockState state, @Nonnull String value) {
335+
setSkin(state, detectProfileFromString(value));
336+
}
337+
338+
public static void setSkin(@Nonnull BlockState state, @Nonnull GameProfile profile) {
339+
Objects.requireNonNull(state, "Can't set skin of null block state");
340+
Objects.requireNonNull(profile, "Can't set skin of block with null GameProfile");
341+
342+
if (!(state instanceof Skull))
343+
throw new IllegalArgumentException("Cannot set skin of a block that is not a skull: " + state);
332344
Skull skull = (Skull) state;
333345

334-
GameProfile profile = detectProfileFromString(value);
335346
try {
336347
CRAFT_META_SKULL_BLOCK_SETTER.invoke(skull, profile);
337348
} catch (Throwable e) {
338-
throw new RuntimeException("Error while setting block skin with value: " + value, e);
349+
throw new RuntimeException("Error while setting block skin with value: " + state + " with profiel " + profile, e);
339350
}
340-
341-
skull.update(true);
342351
}
343352

344353
public static String encodeTexturesURL(String url) {
@@ -362,7 +371,7 @@ private static String decodeBase64(@Nonnull String base64) {
362371
} catch (IllegalArgumentException ignored) {
363372
return null;
364373
}
365-
//return BASE64.matcher(base64).matches();
374+
// return BASE64.matcher(base64).matches();
366375
}
367376

368377
@Nullable
@@ -420,7 +429,7 @@ private static String extractMojangSHAFromBase64(String decodedBase64) {
420429
}
421430
}
422431

423-
private static final class StringSkullCache {
432+
public static final class StringSkullCache {
424433
private final ValueType valueType;
425434
private final Object object;
426435

src/main/java/com/cryptomorin/xseries/XBlock.java

Lines changed: 99 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@
2323

2424
import org.bukkit.DyeColor;
2525
import org.bukkit.Material;
26+
import org.bukkit.SkullType;
2627
import org.bukkit.TreeSpecies;
2728
import org.bukkit.block.Banner;
28-
import org.bukkit.block.Block;
29-
import org.bukkit.block.BlockFace;
30-
import org.bukkit.block.BlockState;
29+
import org.bukkit.block.Skull;
30+
import org.bukkit.block.*;
3131
import org.bukkit.block.data.BlockData;
3232
import org.bukkit.inventory.InventoryHolder;
3333
import org.bukkit.material.*;
@@ -46,7 +46,7 @@
4646
* This class doesn't and shouldn't support materials that are {@link Material#isLegacy()}.
4747
*
4848
* @author Crypto Morin
49-
* @version 2.2.1
49+
* @version 3.0.0
5050
* @see Block
5151
* @see BlockState
5252
* @see MaterialData
@@ -247,12 +247,19 @@ public static boolean setType(@Nonnull Block block, @Nullable XMaterial material
247247
if (material == null) material = XMaterial.AIR;
248248
XMaterial smartConversion = ITEM_TO_BLOCK.get(material);
249249
if (smartConversion != null) material = smartConversion;
250-
if (material.parseMaterial() == null) return false;
251250

252-
block.setType(material.parseMaterial(), applyPhysics);
251+
Material parsedMat = material.parseMaterial();
252+
if (parsedMat == null) return false;
253+
254+
String parsedName = parsedMat.name();
255+
256+
// SKULL_ITEM is for items and SKULL is for blocks.
257+
SkullType skullType = getSkullType(material);
258+
if (skullType != null) parsedMat = Material.valueOf("SKULL");
259+
260+
block.setType(parsedMat, applyPhysics);
253261
if (ISFLAT) return false;
254262

255-
String parsedName = material.parseMaterial().name();
256263
if (parsedName.endsWith("_ITEM")) {
257264
String blockName = parsedName.substring(0, parsedName.length() - "_ITEM".length());
258265
Material blockMaterial = Objects.requireNonNull(Material.getMaterial(blockName),
@@ -352,14 +359,53 @@ public static boolean setType(@Nonnull Block block, @Nullable XMaterial material
352359
throw new AssertionError("Unknown block type " + legacyMaterial + " for tree species: " + species);
353360
}
354361
} else if (material.getData() != 0) {
355-
state.setRawData(material.getData());
362+
if (skullType != null) {
363+
boolean isWallSkull = material.name().contains("WALL");
364+
state.setRawData((byte) (isWallSkull ? 0 : 1));
365+
} else {
366+
state.setRawData(material.getData());
367+
}
368+
update = true;
369+
}
370+
371+
if (skullType != null) {
372+
Skull skull = (Skull) state;
373+
skull.setSkullType(skullType);
356374
update = true;
357375
}
358376

359-
if (update) state.update(false, applyPhysics);
377+
if (update) state.update(true, applyPhysics);
360378
return update;
361379
}
362380

381+
public static SkullType getSkullType(XMaterial material) {
382+
switch (material) {
383+
case PLAYER_HEAD:
384+
case PLAYER_WALL_HEAD:
385+
return SkullType.PLAYER;
386+
case DRAGON_HEAD:
387+
case DRAGON_WALL_HEAD:
388+
return SkullType.DRAGON;
389+
case ZOMBIE_HEAD:
390+
case ZOMBIE_WALL_HEAD:
391+
return SkullType.ZOMBIE;
392+
case CREEPER_HEAD:
393+
case CREEPER_WALL_HEAD:
394+
return SkullType.CREEPER;
395+
case SKELETON_SKULL:
396+
case SKELETON_WALL_SKULL:
397+
return SkullType.SKELETON;
398+
case WITHER_SKELETON_SKULL:
399+
case WITHER_SKELETON_WALL_SKULL:
400+
return SkullType.WITHER;
401+
case PIGLIN_HEAD:
402+
case PIGLIN_WALL_HEAD:
403+
return SkullType.PIGLIN;
404+
default:
405+
return null;
406+
}
407+
}
408+
363409
public static boolean setType(@Nonnull Block block, @Nullable XMaterial material) {
364410
return setType(block, material, true);
365411
}
@@ -726,26 +772,61 @@ public static void setOpened(Block block, boolean opened) {
726772
Openable openable = (Openable) state.getData();
727773
openable.setOpen(opened);
728774
state.setData((MaterialData) openable);
729-
state.update();
775+
state.update(true, true);
730776
}
731777

732778
public static BlockFace getRotation(Block block) {
733779
if (ISFLAT) {
734-
if (!(block.getBlockData() instanceof org.bukkit.block.data.Rotatable)) return null;
735-
org.bukkit.block.data.Rotatable rotatable = (org.bukkit.block.data.Rotatable) block.getBlockData();
736-
return rotatable.getRotation();
780+
BlockData blockData = block.getBlockData();
781+
if (blockData instanceof org.bukkit.block.data.Rotatable) {
782+
return ((org.bukkit.block.data.Rotatable) blockData).getRotation();
783+
} else if (blockData instanceof org.bukkit.block.data.Directional) {
784+
return ((org.bukkit.block.data.Directional) blockData).getFacing();
785+
}
786+
} else {
787+
BlockState state = block.getState();
788+
if (state instanceof Skull) {
789+
return ((Skull) state).getRotation();
790+
} else {
791+
MaterialData data = state.getData();
792+
if (data instanceof Directional) {
793+
return ((Directional) data).getFacing();
794+
}
795+
}
737796
}
738797

739798
return null;
740799
}
741800

742801
public static void setRotation(Block block, BlockFace facing) {
743802
if (ISFLAT) {
744-
if (!(block.getBlockData() instanceof org.bukkit.block.data.Rotatable)) return;
745-
BlockData data = block.getBlockData();
746-
org.bukkit.block.data.Rotatable rotatable = (org.bukkit.block.data.Rotatable) data;
747-
rotatable.setRotation(facing);
748-
block.setBlockData(data, false);
803+
BlockData blockData = block.getBlockData();
804+
if (blockData instanceof org.bukkit.block.data.Rotatable) {
805+
((org.bukkit.block.data.Rotatable) blockData).setRotation(facing);
806+
} else if (blockData instanceof org.bukkit.block.data.Directional) {
807+
((org.bukkit.block.data.Directional) blockData).setFacing(facing);
808+
}
809+
block.setBlockData(blockData, false);
810+
} else {
811+
BlockState state = block.getState();
812+
if (state instanceof Skull) {
813+
// Special case because the raw data is used for both rotation and
814+
// whether the block should be considered a wall skull or a normal skull
815+
// on the ground. Some of the raw data values represent wall skulls with
816+
// various rotations, but only values that represent normal skull values
817+
// on the ground only has one rotation.
818+
// https://www.spigotmc.org/threads/getting-player-skull-to-spawn-on-top-of-fence.385083/
819+
// https://www.spigotmc.org/threads/placing-skull-in-world.212900/
820+
// https://www.spigotmc.org/threads/skull-position-above-block-1-13.343247/
821+
// https://www.spigotmc.org/threads/solved-update-skull-rotation.47795/
822+
((Skull) state).setRotation(facing);
823+
} else {
824+
MaterialData data = state.getData();
825+
if (!(data instanceof Directional)) return;
826+
Directional directional = (Directional) data;
827+
directional.setFacingDirection(facing);
828+
}
829+
state.update(true, true);
749830
}
750831
}
751832

src/main/java/com/cryptomorin/xseries/XItemStack.java

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,18 @@ public final class XItemStack {
9191
* Because item metas cannot be applied to AIR, apparently.
9292
*/
9393
private static final XMaterial DEFAULT_MATERIAL = XMaterial.NETHER_PORTAL;
94+
private static final boolean SUPPORTS_POTION_COLOR;
95+
96+
static {
97+
boolean supportsPotionColor = false;
98+
try {
99+
Class.forName("org.bukkit.inventory.meta.PotionMeta").getMethod("setColor", Color.class);
100+
supportsPotionColor = true;
101+
} catch (Throwable ignored) {
102+
}
103+
104+
SUPPORTS_POTION_COLOR = supportsPotionColor;
105+
}
94106

95107
private XItemStack() {
96108
}
@@ -100,18 +112,21 @@ public static boolean isDefaultItem(ItemStack item) {
100112
}
101113

102114
private static BlockState safeBlockState(BlockStateMeta meta) {
103-
// Due to a bug in the latest paper v1.9-1.10 (and some older v1.11) versions.
104-
// java.lang.IllegalStateException: Missing blockState for BREWING_STAND_ITEM
105-
// BREWING_STAND_ITEM, ENCHANTMENT_TABLE, REDSTONE_COMPARATOR
106-
// https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/diff/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java?until=b6ad714e853042def52620befe9bc85d0137cd71
107115
try {
108116
return meta.getBlockState();
109117
} catch (IllegalStateException ex) {
118+
// Due to a bug in the latest paper v1.9-1.10 (and some older v1.11) versions.
119+
// java.lang.IllegalStateException: Missing blockState for BREWING_STAND_ITEM
120+
// BREWING_STAND_ITEM, ENCHANTMENT_TABLE, REDSTONE_COMPARATOR
121+
// https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/diff/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java?until=b6ad714e853042def52620befe9bc85d0137cd71
110122
if (ex.getMessage().toLowerCase(Locale.ENGLISH).contains("missing blockstate")) {
111123
return null;
112124
} else {
113125
throw ex;
114126
}
127+
} catch (ClassCastException ex) {
128+
// java.lang.ClassCastException: net.minecraft.server.v1_9_R2.TileEntityDispenser cannot be cast to net.minecraft.server.v1_9_R2.TileEntityDropper
129+
return null;
115130
}
116131
}
117132

@@ -246,8 +261,7 @@ public static void serialize(@Nonnull ItemStack item, @Nonnull ConfigurationSect
246261
PotionData potionData = potion.getBasePotionData();
247262
config.set("base-effect", potionData.getType().name() + ", " + potionData.isExtended() + ", " + potionData.isUpgraded());
248263

249-
if (potion.hasColor()) config.set("color", potion.getColor().asRGB());
250-
264+
if (SUPPORTS_POTION_COLOR && potion.hasColor()) config.set("color", potion.getColor().asRGB());
251265
} else {
252266
// Check for water bottles in 1.8
253267
if (item.getDurability() != 0) {
@@ -670,7 +684,7 @@ public static ItemStack edit(@Nonnull ItemStack item,
670684
potion.setBasePotionData(potionData);
671685
}
672686

673-
if (config.contains("color")) {
687+
if (SUPPORTS_POTION_COLOR && config.contains("color")) {
674688
potion.setColor(Color.fromRGB(config.getInt("color")));
675689
}
676690
} else {

src/main/java/com/cryptomorin/xseries/XMaterial.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565
* @see Material
6666
* @see ItemStack
6767
*/
68-
public enum XMaterial {
68+
public enum XMaterial /* implements com.cryptomorin.xseries.abstractions.Material*/ {
6969
ACACIA_BOAT("BOAT_ACACIA"),
7070
ACACIA_BUTTON("WOOD_BUTTON"),
7171
ACACIA_CHEST_BOAT,

src/main/java/com/cryptomorin/xseries/XPotion.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ public enum XPotion {
116116

117117
static {
118118
for (XPotion pot : VALUES)
119-
if (pot.type != null) //noinspection deprecation
119+
if (pot.type != null)
120120
POTIONEFFECTTYPE_MAPPING[pot.type.getId()] = pot;
121121
}
122122

0 commit comments

Comments
 (0)