Skip to content

Commit

Permalink
feat: Add support for FoliaMC server software in SkinHandler for Mine…
Browse files Browse the repository at this point in the history
…craft 1.19.4
  • Loading branch information
GeorgeV220 committed Jun 12, 2023
1 parent 18d8c83 commit 4d1a6b1
Show file tree
Hide file tree
Showing 7 changed files with 223 additions and 4 deletions.
Expand Up @@ -13,6 +13,8 @@
import com.georgev22.skinoverlay.listeners.bukkit.PaperPlayerListeners;
import com.georgev22.skinoverlay.listeners.bukkit.PlayerListeners;
import com.georgev22.skinoverlay.utilities.BukkitPluginMessageUtils;
import com.georgev22.skinoverlay.utilities.bukkit.SkinOverlayBukkitScheduler;
import com.georgev22.skinoverlay.utilities.bukkit.SkinOverlayFoliaScheduler;
import com.georgev22.skinoverlay.utilities.config.OptionsUtil;
import com.georgev22.skinoverlay.utilities.interfaces.SkinOverlayImpl;
import com.georgev22.skinoverlay.utilities.player.PlayerObject;
Expand Down Expand Up @@ -52,6 +54,8 @@ public class SkinOverlayBukkit extends JavaPlugin implements SkinOverlayImpl {
private BukkitAudiences adventure;
private SkinOverlay skinOverlay;

private SkinOverlayBukkitScheduler scheduler;

@Override
public void onLoad() {
try {
Expand All @@ -70,17 +74,28 @@ public void onLoad() {
public void onEnable() {
if (BukkitMinecraftUtils.MinecraftVersion.getCurrentVersion().isBelow(V1_16_R1))
this.adventure = BukkitAudiences.create(this);
Bukkit.getScheduler().runTaskTimer(this, () -> {
if (isFolia()) {
this.scheduler = new SkinOverlayFoliaScheduler();
} else {
this.scheduler = new SkinOverlayBukkitScheduler();
}
scheduler.createRepeatingTask(this, () -> {
tick++;
SchedulerManager.getScheduler().mainThreadHeartbeat(tick);
}, 0, 1L);
}, 1L, 1L);
switch (getCurrentVersion()) {
case V1_17_R1 -> skinOverlay.setSkinHandler(new SkinHandler_1_17());
case V1_18_R1 -> skinOverlay.setSkinHandler(new SkinHandler_1_18());
case V1_18_R2 -> skinOverlay.setSkinHandler(new SkinHandler_1_18_R2());
case V1_19_R1 -> skinOverlay.setSkinHandler(new SkinHandler_1_19());
case V1_19_R2 -> skinOverlay.setSkinHandler(new SkinHandler_1_19_R2());
case V1_19_R3 -> skinOverlay.setSkinHandler(new SkinHandler_1_19_R3());
case V1_19_R3 -> {
if (isFolia()) {
skinOverlay.setSkinHandler(new SkinHandler_Folia_1_19_R3());
} else {
skinOverlay.setSkinHandler(new SkinHandler_1_19_R3());
}
}
case UNKNOWN -> skinOverlay.setSkinHandler(new SkinHandler_Unsupported());
default -> skinOverlay.setSkinHandler(new SkinHandler_Legacy());
}
Expand All @@ -105,7 +120,7 @@ public void onDisable() {
Bukkit.getServer().getMessenger().unregisterIncomingPluginChannel(this);
Bukkit.getServer().getMessenger().unregisterOutgoingPluginChannel(this);
skinOverlay.onDisable();
Bukkit.getScheduler().cancelTasks(this);
scheduler.cancelTasks(this);
if (this.adventure != null) {
this.adventure.close();
this.adventure = null;
Expand Down Expand Up @@ -200,4 +215,13 @@ public String serverVersion() {
}
return this.adventure;
}

private boolean isFolia() {
try {
Class.forName("io.papermc.paper.threadedregions.RegionizedServer");
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
}
@@ -0,0 +1,20 @@
package com.georgev22.skinoverlay.utilities.bukkit;

import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;

public class SkinOverlayBukkitScheduler {

public void createDelayedTask(Plugin plugin, Runnable task, long delay) {
Bukkit.getScheduler().runTaskLater(plugin, task, delay);
}

public void createRepeatingTask(Plugin plugin, Runnable task, long delay, long period) {
Bukkit.getScheduler().runTaskTimer(plugin, task, delay, period);
}

public void cancelTasks(Plugin plugin) {
Bukkit.getScheduler().cancelTasks(plugin);
}

}
@@ -0,0 +1,22 @@
package com.georgev22.skinoverlay.utilities.bukkit;

import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;

public class SkinOverlayFoliaScheduler extends SkinOverlayBukkitScheduler {

@Override
public void createDelayedTask(Plugin plugin, Runnable task, long delay) {
Bukkit.getGlobalRegionScheduler().runDelayed(plugin, (scheduledTask) -> task.run(), delay);
}

@Override
public void createRepeatingTask(Plugin plugin, Runnable task, long delay, long period) {
Bukkit.getGlobalRegionScheduler().runAtFixedRate(plugin, (scheduledTask) -> task.run(), delay, period);
}

@Override
public void cancelTasks(Plugin plugin) {
Bukkit.getGlobalRegionScheduler().cancelTasks(plugin);
}
}
Empty file added folia/build.gradle
Empty file.
16 changes: 16 additions & 0 deletions folia/folia-1-19-4/build.gradle
@@ -0,0 +1,16 @@
plugins {
id "io.papermc.paperweight.userdev" version "1.5.5"
}

repositories {
mavenLocal()
mavenCentral()
}

dependencies {
paperweight.foliaDevBundle("1.19.4-R0.1-SNAPSHOT")

implementation project(path: ':core')

compileOnly "io.papermc:paperlib:1.0.8"
}
@@ -0,0 +1,134 @@

package com.georgev22.skinoverlay.handler.handlers;

import com.georgev22.library.scheduler.SchedulerManager;
import com.georgev22.skinoverlay.handler.SGameProfile;
import com.georgev22.skinoverlay.handler.Skin;
import com.georgev22.skinoverlay.handler.SkinHandler;
import com.georgev22.skinoverlay.utilities.player.PlayerObject;
import com.mojang.authlib.GameProfile;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.*;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.level.ServerPlayerGameMode;
import net.minecraft.world.level.biome.BiomeManager;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_19_R3.entity.CraftPlayer;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;

import java.util.HashSet;
import java.util.List;
import java.util.concurrent.CompletableFuture;

import static com.georgev22.skinoverlay.handler.handlers.SkinHandler_Unsupported.wrapper;

public final class SkinHandler_Folia_1_19_R3 extends SkinHandler {

@Override
public CompletableFuture<Boolean> updateSkin(@NotNull PlayerObject playerObject, @NotNull Skin skin) {
return CompletableFuture.supplyAsync(() -> {
try {
Player player = (Player) playerObject.player();
final CraftPlayer craftPlayer = (CraftPlayer) player;
final ServerPlayer entityPlayer = craftPlayer.getHandle();

ClientboundPlayerInfoRemovePacket removePlayer = new ClientboundPlayerInfoRemovePacket(List.of(entityPlayer.getUUID()));
ClientboundPlayerInfoUpdatePacket addPlayer = ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(entityPlayer));
ServerLevel world = entityPlayer.getLevel();
ServerPlayerGameMode gamemode = entityPlayer.gameMode;

ClientboundRespawnPacket respawn = new ClientboundRespawnPacket(
world.dimensionTypeId(),
world.dimension(),
BiomeManager.obfuscateSeed(world.getSeed()),
gamemode.getGameModeForPlayer(),
gamemode.getPreviousGameModeForPlayer(),
world.isDebug(),
world.isFlat(),
(byte) 3,
entityPlayer.getLastDeathLocation()
);

Location l = player.getLocation();
ClientboundPlayerPositionPacket pos = new ClientboundPlayerPositionPacket(l.getX(), l.getY(), l.getZ(), l.getYaw(), l.getPitch(), new HashSet<>(), 0);
ClientboundSetCarriedItemPacket slot = new ClientboundSetCarriedItemPacket(player.getInventory().getHeldItemSlot());

sendPacket(entityPlayer, removePlayer);
sendPacket(entityPlayer, addPlayer);

sendPacket(entityPlayer, respawn);

SynchedEntityData synchedEntityData = entityPlayer.getEntityData();

EntityDataAccessor<Byte> entityDataAccessor;

synchedEntityData.set(entityDataAccessor = new EntityDataAccessor<>(17, EntityDataSerializers.BYTE), skin.skinOptions().getFlags());

synchedEntityData.markDirty(entityDataAccessor);

synchedEntityData.refresh(entityPlayer);

entityPlayer.onUpdateAbilities();

sendPacket(entityPlayer, pos);
sendPacket(entityPlayer, slot);
craftPlayer.updateScaledHealth();
player.updateInventory();
entityPlayer.resetSentInfo();
return true;
} catch (Exception exception) {
throw new RuntimeException(exception);
}
});
}

@Override
public void applySkin(@NotNull PlayerObject playerObject, @NotNull Skin skin) {
SchedulerManager.getScheduler().runTaskLater(skinOverlay.getClass(), () -> {
Player player = (Player) playerObject.player();
player.hidePlayer((Plugin) skinOverlay.getSkinOverlay().plugin(), player);
player.showPlayer((Plugin) skinOverlay.getSkinOverlay().plugin(), player);
skinOverlay.getSkinHandler().updateSkin(playerObject, skin).handleAsync((aBoolean, throwable) -> {
if (throwable != null) {
throwable.printStackTrace();
return false;
}
return aBoolean;
}).thenAccept(aBoolean -> SchedulerManager.getScheduler().runTask(skinOverlay.getClass(), () -> {
if (aBoolean)
skinOverlay.onlinePlayers().stream().filter(playerObjects -> playerObjects != playerObject).forEach(playerObjects -> {
Player p = (Player) playerObjects.player();
p.hidePlayer((Plugin) skinOverlay.getSkinOverlay().plugin(), player);
p.showPlayer((Plugin) skinOverlay.getSkinOverlay().plugin(), player);
});
}));
}, 20L);
}

@Override
public GameProfile getInternalGameProfile(@NotNull PlayerObject playerObject) {
Player player = (Player) playerObject.player();
final CraftPlayer craftPlayer = (CraftPlayer) player;
final ServerPlayer entityPlayer = craftPlayer.getHandle();
return entityPlayer.getGameProfile();
}

@Override
public SGameProfile getGameProfile(@NotNull PlayerObject playerObject) {
if (sGameProfiles.containsKey(playerObject)) {
return sGameProfiles.get(playerObject);
}
return sGameProfiles.append(playerObject, wrapper(this.getInternalGameProfile(playerObject))).get(playerObject);
}

private void sendPacket(@NotNull ServerPlayer player, Packet<?> packet) {
player.connection.send(packet);
}
}

3 changes: 3 additions & 0 deletions settings.gradle
Expand Up @@ -19,4 +19,7 @@ include 'mc-1-17'
include 'bungee'
include 'velocity'
include 'mc-1-19-4'
include 'folia'
include 'folia:folia-1-19-4'
findProject(':folia:folia-1-19-4')?.name = 'folia-1-19-4'

0 comments on commit 4d1a6b1

Please sign in to comment.