Skip to content

Commit b421f9f

Browse files
committed
1.21.11 compatibility (compile ok, not tested.)
1 parent 98fd94d commit b421f9f

File tree

8 files changed

+271
-90
lines changed

8 files changed

+271
-90
lines changed

fall_effect/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
<module>v_1_21_8</module>
6363
<module>v_1_21_9</module>
6464
<module>v_1_21_10</module>
65+
<module>v_1_21_11</module>
6566
</modules>
6667

6768

fall_effect/v_1_21_11/pom.xml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
2+
<modelVersion>4.0.0</modelVersion>
3+
<parent>
4+
<groupId>fr.black_eyes.lootchest</groupId>
5+
<artifactId>fall_effect</artifactId>
6+
<version>${revision}</version>
7+
</parent>
8+
9+
10+
<artifactId>v_1_21_11</artifactId>
11+
<version>${revision}</version>
12+
13+
<properties>
14+
<MCVersionPacket>1.21.11</MCVersionPacket>
15+
<maven.compiler.release>14</maven.compiler.release>
16+
</properties>
17+
<build>
18+
<plugins>
19+
<plugin>
20+
<groupId>net.md-5</groupId>
21+
<artifactId>specialsource-maven-plugin</artifactId>
22+
</plugin>
23+
</plugins>
24+
</build>
25+
<dependencies>
26+
<dependency>
27+
<groupId>org.spigotmc</groupId>
28+
<artifactId>spigot</artifactId>
29+
<version>${MCVersionPacket}-R0.1-SNAPSHOT</version>
30+
<classifier>remapped-mojang</classifier>
31+
<scope>provided</scope>
32+
</dependency>
33+
</dependencies>
34+
</project>
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
package fr.black_eyes.lootchest.falleffect;
2+
3+
import net.minecraft.world.item.Item;
4+
import net.minecraft.world.item.Items;
5+
import org.bukkit.Location;
6+
import org.bukkit.Material;
7+
8+
import java.util.*;
9+
import java.util.stream.Stream;
10+
import java.util.stream.StreamSupport;
11+
12+
import org.bukkit.plugin.java.JavaPlugin;
13+
import org.bukkit.scheduler.BukkitRunnable;
14+
15+
import com.mojang.datafixers.util.Pair;
16+
17+
import net.minecraft.server.MinecraftServer;
18+
import net.minecraft.server.level.ServerLevel;
19+
import net.minecraft.server.level.ServerPlayer;
20+
import net.minecraft.world.entity.EquipmentSlot;
21+
import net.minecraft.world.entity.decoration.ArmorStand;
22+
import net.minecraft.world.phys.Vec3;
23+
import net.minecraft.network.protocol.game.ClientboundAddEntityPacket;
24+
import net.minecraft.network.protocol.game.ClientboundMoveEntityPacket;
25+
import net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket;
26+
import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket;
27+
import net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket;
28+
import net.minecraft.world.item.ItemStack;
29+
30+
/**
31+
* 1.17+ class to make an invisible armorstand fall from the sky with packets and a block on its head
32+
*/
33+
@SuppressWarnings("unused")
34+
public final class Fallv_1_21_11 implements IFallPacket {
35+
private final ClientboundAddEntityPacket spawnPacket;
36+
private final net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket dataPacket;
37+
private final ClientboundSetEquipmentPacket equipmentPacket;
38+
private final ClientboundMoveEntityPacket motionPacket;
39+
private final ArmorStand armorstand;
40+
private final Location startLocation;
41+
private final int height;
42+
private final double speed;
43+
private static ItemStack headItem;
44+
private long counter;
45+
private static final short SPEED_ONE_BLOCK_PER_SECOND = 410; // speed found after like 10 tests corresponding to one block fall per second
46+
private static final long COUNTER_ONE_BLOCK = 10; // after 10*2 ticks at speed 410, the armorstand falls one block
47+
private static final short SPEED_MULTIPLIER = 31;
48+
private final JavaPlugin instance;
49+
50+
/**
51+
* Get the actual location of the armorstand
52+
* Getting it with the entity class won't work because I move the armorstand, but only client sees it moving,
53+
* so I need to get the location from the start location and the counter
54+
* @return Location of the armorstand
55+
*/
56+
@Override
57+
public Location getLocation() {
58+
Location loc = startLocation.clone();
59+
loc.setY(loc.getY() - (height-((counter /(COUNTER_ONE_BLOCK/(this.speed*SPEED_MULTIPLIER)))-3)) );
60+
return loc;
61+
}
62+
63+
/**
64+
* Creates four packets to make an armorstand fall from the sky
65+
* The armorstand will have a head made of the headItem material
66+
* The armorstand will fall from its spawn location to {height} blocks below
67+
* One packet for the spawn of the armorstand
68+
* One packet for the equipment of the armorstand
69+
* One packet for the movement of the armorstand
70+
* One packet for its datas (invisible, etc.)
71+
* @param loc The location where the armorstand will spawn
72+
* @param headItem The material used for the head of the armorstand, the main reason for all of this
73+
* @param height The height of the fall, in blocks
74+
* @param speed The speed of the fall, does not have a clear meaning
75+
*/
76+
public Fallv_1_21_11(Location loc, Material headItem, int height, double speed, JavaPlugin plugin) {
77+
this.instance = plugin;
78+
this.speed = speed;
79+
this.height = height;
80+
this.startLocation = loc;
81+
@SuppressWarnings("deprecation")
82+
MinecraftServer server = MinecraftServer.getServer();
83+
84+
// stream all levels and filter the one that matches the world name
85+
org.bukkit.World world = loc.getWorld();
86+
String worldName = (world != null) ? world.getName() : null;
87+
ServerLevel s = StreamSupport.stream(server.getAllLevels().spliterator(), false).filter(level -> level.getWorld().getName().equals(worldName)).findFirst().orElse(null);
88+
ArmorStand stand = new ArmorStand(s, loc.getX(), loc.getY(), loc.getZ());
89+
stand.setInvisible(true);
90+
stand.setNoBasePlate(true);
91+
armorstand = stand;
92+
93+
List<Pair<EquipmentSlot, ItemStack>> equipmentList = Collections.singletonList(
94+
new Pair<>(EquipmentSlot.HEAD, getNmsItemStackFromMaterial(headItem)) // nmsHeadItem is your helmet ItemStack
95+
);
96+
97+
equipmentPacket = new ClientboundSetEquipmentPacket(stand.getId(), equipmentList);
98+
spawnPacket = new ClientboundAddEntityPacket(
99+
stand.getId(), // Entity ID
100+
UUID.randomUUID(), // Unique ID
101+
loc.getX(), loc.getY(), loc.getZ(), // Position (X, Y, Z)
102+
loc.getYaw(), loc.getPitch(), // Rotation (Yaw, Pitch)
103+
stand.getType(), // Entity type (ArmorStand)
104+
0, // No specific motion (use 0 for no velocity)
105+
new Vec3(0, 0, 0), // Velocity (none in this case)
106+
0.0);
107+
dataPacket = new ClientboundSetEntityDataPacket(stand.getId(), stand.getEntityData().getNonDefaultValues());
108+
short newSpeed = (short)(this.speed*SPEED_MULTIPLIER*SPEED_ONE_BLOCK_PER_SECOND); // the plugin had a default speed of 0.8 wich was quite fast, but it was never meaningful, 0.8 was like 5 blocks per seconds.
109+
// divide the counter by the speed multiplyer to get the number of ticks the armorstand will need to fall to get the fall ticks of one block for the new speed, then multiply it by the total height to fall
110+
counter = (int)((COUNTER_ONE_BLOCK/(this.speed*SPEED_MULTIPLIER))*(height+3));
111+
// I added 3 to height, else packet is removed too fast
112+
motionPacket = new ClientboundMoveEntityPacket.Pos(
113+
armorstand.getId(),
114+
(short) (0), // Multiply by 4096 for correct movement scaling
115+
(short) (-newSpeed), // Adjust Y for gravity/fall (lower Y for falling)
116+
(short) (0),
117+
true // Yaw
118+
);
119+
}
120+
121+
/**
122+
* Sends the four packets to all players that are in a 100 blocks radius of the armorstand
123+
* An entity can't have gravity with packets, so we will manually move it to the ground, ticks after ticks
124+
*/
125+
@Override
126+
public void sendPacketToAll() {
127+
@SuppressWarnings("deprecation")
128+
MinecraftServer server = MinecraftServer.getServer();
129+
Stream<ServerPlayer> players = server.getPlayerList().getPlayers().stream();
130+
players.forEach(p -> {
131+
// check if player is in the same world as the armorstand
132+
if (!p.getBukkitEntity().getWorld().getName().equals(Objects.requireNonNull(startLocation.getWorld()).getName())) {
133+
return;
134+
}
135+
// check distance between player and armorstand
136+
if (p.distanceTo(armorstand) > 100) {
137+
return;
138+
}
139+
p.connection.send(spawnPacket);
140+
p.connection.send(dataPacket);
141+
p.connection.send(equipmentPacket);
142+
new BukkitRunnable() {
143+
@Override
144+
public void run() {
145+
p.connection.send(motionPacket);
146+
counter--;
147+
if(counter <= 0){
148+
cancel();
149+
removePacketToAll();
150+
}
151+
}
152+
153+
}.runTaskTimer(instance, 0, 2L);
154+
});
155+
}
156+
157+
/**
158+
* Removes the armorstand from all players
159+
*/
160+
@Override
161+
public void removePacketToAll() {
162+
@SuppressWarnings("deprecation")
163+
MinecraftServer server = MinecraftServer.getServer();
164+
Stream<ServerPlayer> players = server.getPlayerList().getPlayers().stream();
165+
players.forEach(p -> p.connection.send(new ClientboundRemoveEntitiesPacket(armorstand.getId())));
166+
}
167+
168+
169+
/**
170+
* Get an NMS ItemStack from a Bukkit Material
171+
*/
172+
public ItemStack getNmsItemStackFromMaterial(Material material) {
173+
String itemKey = "item."+material.getKey().toString().replace(":",".");
174+
String blockKey = "block."+material.getKey().toString().replace(":",".");
175+
if(headItem != null && (Objects.requireNonNull(headItem.getItem().getDescriptionId()).equals(itemKey) || headItem.getItem().getDescriptionId().equals(blockKey))) {
176+
return headItem;
177+
}
178+
for(Item item : Arrays.stream(Items.class.getFields()).map(field -> {
179+
try {
180+
return (Item) field.get(null);
181+
} catch (IllegalArgumentException | IllegalAccessException ignored) {
182+
}
183+
return null;
184+
}).toArray(Item[]::new)) {
185+
if (item == null) {
186+
continue;
187+
}
188+
if (Objects.requireNonNull(item.getDescriptionId()).equals(itemKey) || item.getDescriptionId().equals(blockKey)) {
189+
headItem = new ItemStack(item);
190+
return headItem;
191+
}
192+
193+
}
194+
return ItemStack.EMPTY; // Return an empty item if reflection fails
195+
}
196+
}

lootchest/pom.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@
242242
<dependency>
243243
<groupId>com.github.Guarmanda</groupId>
244244
<artifactId>decentholograms</artifactId>
245-
<version>2.9.8</version>
245+
<version>2.9.9</version>
246246
</dependency>
247247
<dependency><groupId>fr.black_eyes.lootchest</groupId><artifactId>v_1_8_3</artifactId><version>${revision}</version></dependency>
248248
<dependency><groupId>fr.black_eyes.lootchest</groupId><artifactId>v_1_8_8</artifactId><version>${revision}</version></dependency>
@@ -288,6 +288,7 @@
288288
<dependency><groupId>fr.black_eyes.lootchest</groupId><artifactId>v_1_21_8</artifactId><version>${revision}</version></dependency>
289289
<dependency><groupId>fr.black_eyes.lootchest</groupId><artifactId>v_1_21_9</artifactId><version>${revision}</version></dependency>
290290
<dependency><groupId>fr.black_eyes.lootchest</groupId><artifactId>v_1_21_10</artifactId><version>${revision}</version></dependency>
291+
<dependency><groupId>fr.black_eyes.lootchest</groupId><artifactId>v_1_21_11</artifactId><version>${revision}</version></dependency>
291292

292293
<dependency>
293294
<groupId>fr.black_eyes.lootchest</groupId>

lootchest/src/main/java/fr/black_eyes/lootchest/Metrics.java

Lines changed: 8 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,6 @@
2525
import java.nio.charset.StandardCharsets;
2626
import java.util.Arrays;
2727
import java.util.Collection;
28-
import java.util.HashSet;
29-
import java.util.Objects;
30-
import java.util.Set;
3128
import java.util.UUID;
3229
import java.util.concurrent.ScheduledExecutorService;
3330
import java.util.concurrent.ScheduledThreadPoolExecutor;
@@ -70,12 +67,6 @@ public Metrics(Plugin plugin, int serviceId) {
7067
// Inform the server owners about bStats
7168
config
7269
.options()
73-
.header(
74-
"bStats (https://bStats.org) collects some basic information for plugin authors, like how\n"
75-
+ "many people use their plugin and their total player count. It's recommended to keep bStats\n"
76-
+ "enabled, but if you're not comfortable with this, you can turn this setting off. There is no\n"
77-
+ "performance penalty associated with having metrics enabled, and data sent to bStats is fully\n"
78-
+ "anonymous.")
7970
.copyDefaults(true);
8071
try {
8172
config.save(configFile);
@@ -191,8 +182,6 @@ public static class MetricsBase {
191182

192183
private final boolean logResponseStatusText;
193184

194-
private final Set<CustomChart> customCharts = new HashSet<>();
195-
196185
private final boolean enabled;
197186

198187
/**
@@ -201,21 +190,21 @@ public static class MetricsBase {
201190
* @param platform The platform of the service.
202191
* @param serviceId The id of the service.
203192
* @param serverUuid The server uuid.
204-
* @param enabled Whether or not data sending is enabled.
193+
* @param enabled Whether data sending is enabled.
205194
* @param appendPlatformDataConsumer A consumer that receives a {@code JsonObjectBuilder} and
206195
* appends all platform-specific data.
207196
* @param appendServiceDataConsumer A consumer that receives a {@code JsonObjectBuilder} and
208197
* appends all service-specific data.
209198
* @param submitTaskConsumer A consumer that takes a runnable with the submit task. This can be
210-
* used to delegate the data collection to a another thread to prevent errors caused by
199+
* used to delegate the data collection to a thread to prevent errors caused by
211200
* concurrency. Can be {@code null}.
212201
* @param checkServiceEnabledSupplier A supplier to check if the service is still enabled.
213202
* @param errorLogger A consumer that accepts log message and an error.
214203
* @param infoLogger A consumer that accepts info log messages.
215-
* @param logErrors Whether or not errors should be logged.
216-
* @param logSentData Whether or not the sent data should be logged.
217-
* @param logResponseStatusText Whether or not the response status text should be logged.
218-
* @param skipRelocateCheck Whether or not the relocate check should be skipped.
204+
* @param logErrors Whether errors should be logged.
205+
* @param logSentData Whether the sent data should be logged.
206+
* @param logResponseStatusText Whether the response status text should be logged.
207+
* @param skipRelocateCheck Whether the relocate check should be skipped.
219208
*/
220209
public MetricsBase(
221210
String platform,
@@ -303,11 +292,7 @@ private void submitData() {
303292
appendPlatformDataConsumer.accept(baseJsonBuilder);
304293
final JsonObjectBuilder serviceJsonBuilder = new JsonObjectBuilder();
305294
appendServiceDataConsumer.accept(serviceJsonBuilder);
306-
JsonObjectBuilder.JsonObject[] chartData =
307-
customCharts.stream()
308-
.map(customChart -> customChart.getRequestJsonObject(errorLogger, logErrors))
309-
.filter(Objects::nonNull)
310-
.toArray(JsonObjectBuilder.JsonObject[]::new);
295+
JsonObjectBuilder.JsonObject[] chartData = new JsonObjectBuilder.JsonObject[0];
311296
serviceJsonBuilder.appendField("id", serviceId);
312297
serviceJsonBuilder.appendField("customCharts", chartData);
313298
baseJsonBuilder.appendField("service", serviceJsonBuilder.build());
@@ -398,44 +383,10 @@ private static byte[] compress(final String str) throws IOException {
398383
}
399384
}
400385

401-
public abstract static class CustomChart {
402-
403-
private final String chartId;
404-
405-
protected CustomChart(String chartId) {
406-
if (chartId == null) {
407-
throw new IllegalArgumentException("chartId must not be null");
408-
}
409-
this.chartId = chartId;
410-
}
411-
412-
public JsonObjectBuilder.JsonObject getRequestJsonObject(
413-
BiConsumer<String, Throwable> errorLogger, boolean logErrors) {
414-
JsonObjectBuilder builder = new JsonObjectBuilder();
415-
builder.appendField("chartId", chartId);
416-
try {
417-
JsonObjectBuilder.JsonObject data = getChartData();
418-
if (data == null) {
419-
// If the data is null we don't send the chart.
420-
return null;
421-
}
422-
builder.appendField("data", data);
423-
} catch (Throwable t) {
424-
if (logErrors) {
425-
errorLogger.accept("Failed to get data for custom chart with id " + chartId, t);
426-
}
427-
return null;
428-
}
429-
return builder.build();
430-
}
431-
432-
protected abstract JsonObjectBuilder.JsonObject getChartData() throws Exception;
433-
}
434-
435386
/**
436387
* An extremely simple JSON builder.
437388
*
438-
* <p>While this class is neither feature-rich nor the most performant one, it's sufficient enough
389+
* <p>While this class is neither feature-rich nor the most performant one, it's sufficient
439390
* for its use-case.
440391
*/
441392
public static class JsonObjectBuilder {

0 commit comments

Comments
 (0)