Skip to content

Commit 55cb75e

Browse files
authored
Merge pull request #105 from byquanton/main
Add Support for 1.21.4
2 parents 765ad33 + 51f4777 commit 55cb75e

File tree

9 files changed

+293
-11
lines changed

9 files changed

+293
-11
lines changed

gradle/libs.versions.toml

+4-4
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ cloud-build-logic = "0.0.3"
33
ktlint = "0.50.0"
44
checkstyle = "10.12.5"
55
kotlin = "1.9.20"
6-
shadow = "9.0.0-beta4"
7-
paperweight = "1.7.7"
8-
run-paper = "2.3.0"
6+
shadow = "9.0.0-beta8"
7+
paperweight = "2.0.0-beta.14"
8+
run-paper = "2.3.1"
99
pluginyml = "0.6.0"
1010

1111
# Platforms
12-
minecraft = "1.17.1-R0.1-SNAPSHOT"
12+
minecraft = "1.20.6-R0.1-SNAPSHOT"
1313

1414
# Libraries
1515
cloud = "1.8.4"

gradle/wrapper/gradle-wrapper.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip
44
networkTimeout=10000
55
validateDistributionUrl=true
66
zipStoreBase=GRADLE_USER_HOME

hyperverse-core/build.gradle.kts

+6-1
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ dependencies {
6565
runtimeOnly(projects.hyperverseNms1213) {
6666
targetConfiguration = "reobf"
6767
}
68+
runtimeOnly(projects.hyperverseNms1214) {
69+
targetConfiguration = "reobf"
70+
}
6871
}
6972

7073
bukkit {
@@ -126,6 +129,8 @@ tasks {
126129
exclude(project(":hyperverse-nms-1-20"))
127130
exclude(project(":hyperverse-nms-1-20-6"))
128131
exclude(project(":hyperverse-nms-1-21"))
132+
exclude(project(":hyperverse-nms-1-21-3"))
133+
exclude(project(":hyperverse-nms-1-21-4"))
129134
}
130135
mergeServiceFiles()
131136

@@ -163,6 +168,6 @@ tasks {
163168

164169
runServer {
165170
java.toolchain.languageVersion.set(JavaLanguageVersion.of(21))
166-
minecraftVersion("1.21")
171+
minecraftVersion("1.21.4")
167172
}
168173
}

hyperverse-core/src/main/java/org/incendo/hyperverse/Hyperverse.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,8 @@ public final class Hyperverse extends JavaPlugin implements HyperverseAPI, Liste
9999
Version.parseMinecraft("1.20.4"),
100100
Version.parseMinecraft("1.20.6"),
101101
Version.parseMinecraft("1.21.1"),
102-
Version.parseMinecraft("1.21.3")
102+
Version.parseMinecraft("1.21.3"),
103+
Version.parseMinecraft("1.21.4")
103104
);
104105

105106
private WorldManager worldManager;

hyperverse-core/src/main/java/org/incendo/hyperverse/commands/HyperCloudCommandManager.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
import com.google.gson.JsonParser;
4545
import com.google.inject.Inject;
4646
import io.leangen.geantyref.TypeToken;
47-
import org.apache.commons.lang.StringUtils;
4847
import org.bukkit.ChatColor;
4948
import org.bukkit.GameRule;
5049
import org.bukkit.Location;
@@ -1277,7 +1276,7 @@ public void doPlugin(final CommandSender sender) {
12771276
final PluginDescriptionFile description = plugin.getDescription();
12781277
Stream.of(
12791278
"<gold>Plugin Version:</gold> <gray>" + description.getVersion() + "</gray>",
1280-
"<gold>Author(s):</gold> <gray>" + StringUtils.join(description.getAuthors(), ", ") + "</gray>",
1279+
"<gold>Author(s):</gold> <gray>" + String.join(", ", description.getAuthors()) + "</gray>",
12811280
"<gold>Website:</gold> <gray><hover:show_text:\"<gray>Click to open</gray>\"><click:open_url:https://hyperver.se>https://hyperver.se</click></hover></gray>"
12821281
).forEach(msg ->
12831282
MessageUtil.sendMessage(sender, new Message("plugin.internal", "<dark_gray>[</dark_gray><gold>Hyperverse</gold"

hyperverse-core/src/main/java/org/incendo/hyperverse/commands/HyperCommandManager.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
import com.google.gson.JsonObject;
3838
import com.google.gson.JsonParser;
3939
import com.google.inject.Inject;
40-
import org.apache.commons.lang.StringUtils;
4140
import org.bukkit.Bukkit;
4241
import org.bukkit.ChatColor;
4342
import org.bukkit.GameRule;
@@ -1179,7 +1178,7 @@ public void doPlugin(final CommandSender sender) {
11791178
final PluginDescriptionFile description = plugin.getDescription();
11801179
Stream.of(
11811180
"<gold>Plugin Version:</gold> <gray>" + description.getVersion() + "</gray>",
1182-
"<gold>Author(s):</gold> <gray>" + StringUtils.join(description.getAuthors(), ", ") + "</gray>",
1181+
"<gold>Author(s):</gold> <gray>" + String.join(", ", description.getAuthors()) + "</gray>",
11831182
"<gold>Website:</gold> <gray><hover:show_text:\"<gray>Click to open</gray>\"><click:open_url:https://hyperver.se>https://hyperver.se</click></hover></gray>"
11841183
).forEach(msg ->
11851184
MessageUtil.sendMessage(sender, new Message("plugin.internal", "<dark_gray>[</dark_gray><gold>Hyperverse</gold"
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
plugins {
2+
id("hyperverse.base-conventions")
3+
alias(libs.plugins.paperweight.userdev)
4+
}
5+
6+
indra {
7+
javaVersions {
8+
minimumToolchain(21)
9+
target(21)
10+
}
11+
}
12+
13+
dependencies {
14+
paperweight.paperDevBundle("1.21.4-R0.1-SNAPSHOT")
15+
compileOnly(projects.hyperverseNmsCommon)
16+
}
17+
18+
tasks {
19+
assemble {
20+
dependsOn(reobfJar)
21+
}
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
//
2+
// Hyperverse - A minecraft world management plugin
3+
//
4+
// This program is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU General Public License
15+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
//
17+
18+
package org.incendo.hyperverse.platform.v1_21_4;
19+
20+
import co.aikar.taskchain.TaskChainFactory;
21+
import com.google.inject.Inject;
22+
import io.papermc.lib.PaperLib;
23+
import java.io.InputStream;
24+
import java.io.OutputStream;
25+
import java.lang.reflect.Field;
26+
import java.nio.file.Files;
27+
import java.nio.file.Path;
28+
import java.util.Objects;
29+
import java.util.Optional;
30+
31+
import net.minecraft.BlockUtil;
32+
import net.minecraft.core.BlockPos;
33+
import net.minecraft.nbt.CompoundTag;
34+
import net.minecraft.nbt.DoubleTag;
35+
import net.minecraft.nbt.ListTag;
36+
import net.minecraft.nbt.NbtAccounter;
37+
import net.minecraft.nbt.NbtIo;
38+
import net.minecraft.server.level.ServerLevel;
39+
import net.minecraft.server.level.ServerPlayer;
40+
import net.minecraft.world.entity.Entity;
41+
import net.minecraft.world.level.border.WorldBorder;
42+
import net.minecraft.world.level.dimension.DimensionType;
43+
import net.minecraft.world.level.entity.EntityLookup;
44+
import net.minecraft.world.level.entity.PersistentEntitySectionManager;
45+
import net.minecraft.world.level.portal.PortalForcer;
46+
import net.minecraft.world.phys.Vec3;
47+
import org.apache.logging.log4j.core.Filter;
48+
import org.apache.logging.log4j.core.Logger;
49+
import org.apache.logging.log4j.core.filter.RegexFilter;
50+
import org.bukkit.Bukkit;
51+
import org.bukkit.Location;
52+
import org.bukkit.World;
53+
import org.bukkit.craftbukkit.CraftWorld;
54+
import org.bukkit.craftbukkit.entity.CraftEntity;
55+
import org.bukkit.craftbukkit.entity.CraftPlayer;
56+
import org.bukkit.entity.Player;
57+
import org.bukkit.event.player.PlayerRespawnEvent;
58+
import org.jetbrains.annotations.NotNull;
59+
import org.jetbrains.annotations.Nullable;
60+
import org.incendo.hyperverse.util.HyperConfigShouldGroupProfiles;
61+
import org.incendo.hyperverse.util.NMS;
62+
63+
@SuppressWarnings("unused")
64+
public class NMSImpl implements NMS {
65+
66+
private final TaskChainFactory taskFactory;
67+
private Field entitySectionManager;
68+
private Field entityLookup;
69+
private org.apache.logging.log4j.core.Logger worldServerLogger;
70+
71+
@Inject public NMSImpl(final TaskChainFactory taskFactory, final @HyperConfigShouldGroupProfiles boolean hyperConfiguration) {
72+
this.taskFactory = taskFactory;
73+
if (hyperConfiguration) {
74+
try {
75+
final Field field = ServerLevel.class.getDeclaredField("LOGGER");
76+
field.setAccessible(true);
77+
this.worldServerLogger = (Logger) field.get(null);
78+
} catch (final Exception e) {
79+
e.printStackTrace();
80+
}
81+
try {
82+
final RegexFilter regexFilter = RegexFilter
83+
.createFilter("[\\S\\s]*Force-added player with duplicate UUID[\\S\\s]*", null, false,
84+
Filter.Result.DENY, Filter.Result.ACCEPT);
85+
this.worldServerLogger.addFilter(regexFilter);
86+
} catch (IllegalAccessException e) {
87+
e.printStackTrace();
88+
}
89+
}
90+
}
91+
92+
@Override @Nullable public Location getOrCreateNetherPortal(@NotNull final org.bukkit.entity.Entity entity,
93+
@NotNull final Location origin) {
94+
final ServerLevel worldServer = Objects.requireNonNull(((CraftWorld) origin.getWorld()).getHandle());
95+
final PortalForcer portalTravelAgent = Objects.requireNonNull(worldServer.getPortalForcer());
96+
final Entity nmsEntity = Objects.requireNonNull(((CraftEntity) entity).getHandle());
97+
final BlockPos blockPosition = new BlockPos(origin.getBlockX(), origin.getBlockY(), origin.getBlockZ());
98+
final WorldBorder worldBorder = worldServer.getWorldBorder();
99+
Optional<BlockPos> existingPortalPosition = Objects.requireNonNull(portalTravelAgent, "travel agent")
100+
.findClosestPortalPosition(Objects.requireNonNull(blockPosition, "position"), worldBorder,128);
101+
if (existingPortalPosition.isPresent()) {
102+
BlockPos bottomLeft = existingPortalPosition.get();
103+
return new Location(origin.getWorld(), bottomLeft.getX(), bottomLeft.getY(), bottomLeft.getZ());
104+
}
105+
Optional<BlockUtil.FoundRectangle> createdPortal = portalTravelAgent.createPortal(blockPosition,
106+
nmsEntity.getDirection().getAxis(), nmsEntity,
107+
16);
108+
if (createdPortal.isEmpty()) {
109+
return null;
110+
}
111+
final BlockUtil.FoundRectangle rectangle = createdPortal.get();
112+
return new Location(origin.getWorld(), rectangle.minCorner.getX() + 1D, rectangle.minCorner.getY() - 1D,
113+
rectangle.minCorner.getZ() + 1D);
114+
}
115+
116+
@Override @Nullable public Location getDimensionSpawn(@NotNull final Location origin) {
117+
if (Objects.requireNonNull(origin.getWorld()).getEnvironment()
118+
== World.Environment.THE_END) {
119+
return new Location(origin.getWorld(), 100, 50, 0);
120+
}
121+
return origin.getWorld().getSpawnLocation();
122+
}
123+
124+
@Override public void writePlayerData(@NotNull final Player player, @NotNull final Path file) {
125+
final CompoundTag playerTag = new CompoundTag();
126+
final net.minecraft.world.entity.player.Player entityPlayer = ((CraftPlayer) player).getHandle();
127+
entityPlayer.save(playerTag);
128+
129+
if (!playerTag.contains("hyperverse")) {
130+
playerTag.put("hyperverse", new CompoundTag());
131+
}
132+
final CompoundTag hyperverse = playerTag.getCompound("hyperverse");
133+
hyperverse.putLong("writeTime", System.currentTimeMillis());
134+
hyperverse.putString("version", Bukkit.getPluginManager().getPlugin("Hyperverse").getDescription().getVersion());
135+
136+
taskFactory.newChain().async(() -> {
137+
try (final OutputStream outputStream = Files.newOutputStream(file)) {
138+
NbtIo.writeCompressed(playerTag, outputStream);
139+
} catch (final Exception e) {
140+
e.printStackTrace();
141+
}
142+
}).execute();
143+
}
144+
145+
@Override public void readPlayerData(@NotNull final Player player, @NotNull final Path file, @NotNull final Runnable whenDone) {
146+
final Location originLocation = player.getLocation().clone();
147+
taskFactory.newChain().asyncFirst(() -> {
148+
try (final InputStream inputStream = Files.newInputStream(file)) {
149+
return Optional.of(NbtIo.readCompressed(inputStream, NbtAccounter.unlimitedHeap()));
150+
} catch (final Exception e) {
151+
e.printStackTrace();
152+
}
153+
return Optional.empty();
154+
}).syncLast((optionalCompound) -> {
155+
if (!optionalCompound.isPresent()) {
156+
return;
157+
}
158+
final CompoundTag compound = (CompoundTag) optionalCompound.get();
159+
PaperLib.getChunkAtAsync(originLocation).thenAccept(chunk -> {
160+
// Health and hunger don't update properly, so we
161+
// give them a little help
162+
final float health = compound.getFloat("Health");
163+
final int foodLevel = compound.getInt("foodLevel");
164+
165+
// Restore bed spawn
166+
final String spawnWorld = compound.getString("SpawnWorld");
167+
final int spawnX = compound.getInt("SpawnX");
168+
final int spawnY = compound.getInt("SpawnY");
169+
final int spawnZ = compound.getInt("SpawnZ");
170+
final Location spawnLocation = new Location(Bukkit.getWorld(spawnWorld), spawnX,
171+
spawnY, spawnZ);
172+
173+
final ServerPlayer entityPlayer = ((CraftPlayer) player).getHandle();
174+
175+
// We re-write the extra Bukkit data as to not
176+
// mess up the profile
177+
((CraftPlayer) player).setExtraData(compound);
178+
// Set the position to the player's current position
179+
Vec3 pos = entityPlayer.position();
180+
compound.put("Pos", doubleList(pos.x, pos.y, pos.z));
181+
// Set the world to the player's current world
182+
compound.putString("world", player.getWorld().getName());
183+
// Store persistent values
184+
((CraftPlayer) player).storeBukkitValues(compound);
185+
186+
// We start by doing a total reset
187+
entityPlayer.reset();
188+
entityPlayer.load(compound);
189+
190+
entityPlayer.effectsDirty = true;
191+
entityPlayer.onUpdateAbilities();
192+
player.teleport(originLocation);
193+
194+
final ServerLevel worldServer = ((CraftWorld) originLocation.getWorld()).getHandle();
195+
final DimensionType dimensionManager = worldServer.dimensionType();
196+
197+
// Prevent annoying message
198+
// Spigot-obf = decouple()
199+
entityPlayer.unRide();
200+
worldServer.removePlayerImmediately(entityPlayer, Entity.RemovalReason.CHANGED_DIMENSION);
201+
// worldServer.removePlayer above should remove the player from the
202+
// map, but that doesn't always happen. This is a last effort
203+
// attempt to prevent the annoying "Force re-added" message
204+
// from appearing
205+
try {
206+
if (this.entitySectionManager == null) {
207+
this.entitySectionManager = worldServer.getClass().getDeclaredField("entityManager");
208+
this.entitySectionManager.setAccessible(true);
209+
}
210+
final PersistentEntitySectionManager<Entity> esm = (PersistentEntitySectionManager<Entity>) this.entitySectionManager.get(worldServer);
211+
if (this.entityLookup == null) {
212+
this.entityLookup = esm.getClass().getDeclaredField("visibleEntityStorage");
213+
}
214+
final EntityLookup<Entity> lookup = (EntityLookup<Entity>) this.entityLookup.get(esm);
215+
lookup.remove(entityPlayer);
216+
} catch (final NoSuchFieldException | IllegalAccessException e) {
217+
e.printStackTrace();
218+
}
219+
220+
// pre 1.18 code = PlayerList#moveToWorld
221+
entityPlayer.server.getPlayerList().remove(entityPlayer);
222+
worldServer.getServer().getPlayerList().respawn(entityPlayer, true,
223+
Entity.RemovalReason.CHANGED_DIMENSION, PlayerRespawnEvent.RespawnReason.PLUGIN, originLocation);
224+
225+
// Apply health and foodLevel
226+
player.setHealth(health);
227+
player.setFoodLevel(foodLevel);
228+
player.setPortalCooldown(40);
229+
player.setBedSpawnLocation(spawnLocation, true);
230+
});
231+
}).execute(whenDone);
232+
}
233+
234+
@Override @Nullable public Location findBedRespawn(@NotNull final Location spawnLocation) {
235+
final CraftWorld craftWorld = (CraftWorld) spawnLocation.getWorld();
236+
if (craftWorld == null) {
237+
return null;
238+
}
239+
240+
return ServerPlayer.findRespawnAndUseSpawnBlock(craftWorld.getHandle(), new BlockPos(spawnLocation.getBlockX(),
241+
spawnLocation.getBlockY(), spawnLocation.getBlockZ()), 0, true, false)
242+
.map(ServerPlayer.RespawnPosAngle::position)
243+
.map(pos -> new Location(spawnLocation.getWorld(), pos.x(), pos.y(), pos.z()))
244+
.orElse(null);
245+
}
246+
247+
private static ListTag doubleList(final double... values) {
248+
final ListTag tagList = new ListTag();
249+
for (final double d : values) {
250+
tagList.add(DoubleTag.valueOf(d));
251+
}
252+
return tagList;
253+
}
254+
255+
}

settings.gradle.kts

+1
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ include(":hyperverse-nms-1-20")
2020
include(":hyperverse-nms-1-20-6")
2121
include(":hyperverse-nms-1-21")
2222
include(":hyperverse-nms-1-21-3")
23+
include(":hyperverse-nms-1-21-4")

0 commit comments

Comments
 (0)