Compare commits

...
Sign in to create a new pull request.

22 commits

Author SHA1 Message Date
794d560363
refactor: delete todo file for the 198259th time 2025-06-30 22:03:18 +02:00
42f9476970
refactor: remove the print 2025-06-30 22:02:09 +02:00
c20df8bc48
fix(appearance): fix player destroy/create 2025-06-30 22:01:49 +02:00
b7ac5862eb
fix(favorite/item): i had forgor how to use library 2025-06-30 21:37:06 +02:00
9b6e7e0f8e
feat(favorite/item): bug notice 2025-06-30 21:29:09 +02:00
5f32720617
feat: update readme 2025-06-30 21:28:36 +02:00
18a533667e
feat: add click interaction with favorite item 2025-06-30 21:27:10 +02:00
d7663ab463
feat: update random skin item 2025-06-30 16:19:21 +02:00
ae9b8143aa
refactor: revert paper plugin drop 2025-06-30 11:44:00 +02:00
942c6e3609
refactor(packet): convert to record 2025-06-30 11:40:22 +02:00
1a499fe7cc
refactor(pe): move settings before load 2025-06-30 11:37:18 +02:00
a1e9684c08
feat: remove paper plugin requirement 2025-06-30 11:34:30 +02:00
3f697c3e23
remove TODO file 2025-06-29 14:07:29 +02:00
1613a85461
Merge branch 'packetevents' of https://git.ineanto.xyz/ineanto/nicko into packetevents 2025-06-29 14:06:27 +02:00
1a45ca186a
fix: reset 2025-06-29 14:04:44 +02:00
436fc91556
fix: reset 2025-06-29 14:04:20 +02:00
03a8eb9b7d
fix: return ok instead of error dumbass 2025-06-28 20:21:19 +02:00
deb76e0150
style: blank space 2025-06-28 20:16:52 +02:00
11b0f680bc
feat: and chat encryption is broken again 2025-06-27 18:51:17 +02:00
cc61a89ec1
feat(pe): add tab list packet 2025-06-27 18:30:45 +02:00
ab2ffcbd37
feat: init pe 2025-06-27 14:54:35 +02:00
073d96bf99
feat: switching to pe 2025-06-27 10:49:54 +02:00
21 changed files with 458 additions and 715 deletions

5
.gitignore vendored
View file

@ -26,4 +26,7 @@ bin/
!**/src/test/**/bin/
### Server ###
run/
run/
### Private ###
TODO

View file

@ -1,4 +1,7 @@
1.3.0-RC1: Update n°13 (XX/XX/25)
As of 1.3.0-RC1, Nicko will now run on every Minecraft version.
However, I will NOT provide support if the plugin breaks.
[FEATURES]
- Players are now able to mark disguises as favorites.

View file

@ -12,10 +12,7 @@ https://www.spigotmc.org/resources/nicko.113868/
## Known bugs:
- Players who have operator (OP) status lose access to the Operator Items tab in creative mode
after disguising **(1.20 and up)**.
- When disguising and only changing their display name, players will have the new default
skins **(1.20 and up)**.
N/A
---
@ -25,5 +22,5 @@ https://www.spigotmc.org/resources/nicko.113868/
|---------------|----------------------------------------------------------------------------|
| 1.7 and lower | Unsupported |
| 1.8 - 1.12.2 | Use [NickReloaded](https://www.spigotmc.org/resources/nickreloaded.46335/) |
| 1.13 to 1.19 | Unsupported |
| 1.20 - 1.21 | Use Nicko |
| 1.13 to 1.19 | Use Nicko (without support) |
| 1.20 - 1.21 | Use Nicko (with support) |

View file

@ -2,11 +2,10 @@ plugins {
id("java")
id("com.gradleup.shadow") version "8.3.2"
id("xyz.jpenilla.run-paper") version "2.3.0"
id("io.papermc.paperweight.userdev") version "2.0.0-beta.17"
}
group = "xyz.ineanto"
version = "1.2.0"
version = "1.3.0"
val invuiVersion: String = "1.44"
@ -26,17 +25,19 @@ repositories {
maven("https://repo.xenondevs.xyz/releases")
maven("https://repo.papermc.io/repository/maven-public/")
maven("https://repo.codemc.io/repository/maven-snapshots/")
maven("https://repo.codemc.io/repository/maven-releases/")
maven("https://repo.extendedclip.com/content/repositories/placeholderapi/")
}
dependencies {
paperweight.paperDevBundle("1.21.5-R0.1-SNAPSHOT")
compileOnly("io.papermc.paper:paper-api:1.21.6-R0.1-SNAPSHOT")
compileOnly("me.clip:placeholderapi:2.11.5")
compileOnly("net.kyori:adventure-api:4.21.0")
compileOnly("xyz.xenondevs.invui:invui-core:$invuiVersion")
compileOnly("net.wesjd:anvilgui:1.10.4-SNAPSHOT")
compileOnly("com.comphenix.protocol:ProtocolLib:5.4.0-SNAPSHOT")
implementation("com.github.retrooper:packetevents-spigot:2.8.0")
implementation("de.rapha149.signgui:signgui:2.5.0")
implementation("com.github.jsixface:yamlconfig:1.2")

View file

@ -1,6 +1,8 @@
package xyz.ineanto.nicko;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import io.github.retrooper.packetevents.factory.spigot.SpigotPacketEventsBuilder;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.plugin.java.JavaPlugin;
@ -38,20 +40,28 @@ public class Nicko extends JavaPlugin {
private PlayerNameStore nameStore;
private RandomNameFetcher nameFetcher;
@Override
public void onLoad() {
PacketEvents.setAPI(SpigotPacketEventsBuilder.build(this));
PacketEvents.getAPI().getSettings().checkForUpdates(false).kickOnPacketException(true);
PacketEvents.getAPI().load();
}
@Override
public void onEnable() {
plugin = this;
PacketEvents.getAPI().init();
configurationManager = new ConfigurationManager(getDataFolder());
configurationManager.saveDefaultConfig();
dataStore = new PlayerDataStore(mojangAPI, getNickoConfig());
if (!MinecraftVersion.v1_21_5.atOrAbove()) {
getLogger().severe("This version (" + MinecraftVersion.getCurrentVersion().getVersion() + ") is not supported by Nicko!");
getLogger().severe("As of version 1.2.0, Nicko only supports the latest Minecraft version. (Currently 1.21.5)");
dataStore.getStorage().setError(true);
Bukkit.getPluginManager().disablePlugin(this);
if (PacketEvents.getAPI().getServerManager().getVersion().isOlderThan(ServerVersion.V_1_20)) {
getLogger().severe("This version (" + PacketEvents.getAPI().getServerManager().getVersion() + ") is not officially supported by Nicko!");
getLogger().severe("As of version 1.3.0, Nicko only supports the two latest major Minecraft versions. (Currently 1.20 to 1.21.5)");
getLogger().severe("Do NOT complain about it not working, you've been warned!");
}
if (!Bukkit.getOnlineMode()) {

View file

@ -5,8 +5,8 @@ import org.bukkit.entity.Player;
import xyz.ineanto.nicko.Nicko;
import xyz.ineanto.nicko.event.custom.PlayerDisguiseEvent;
import xyz.ineanto.nicko.event.custom.PlayerResetDisguiseEvent;
import xyz.ineanto.nicko.packet.PacketEventsPacketSender;
import xyz.ineanto.nicko.packet.PacketSender;
import xyz.ineanto.nicko.packet.PaperPacketSender;
import xyz.ineanto.nicko.profile.NickoProfile;
import xyz.ineanto.nicko.storage.PlayerDataStore;
import xyz.ineanto.nicko.storage.name.PlayerNameStore;
@ -23,7 +23,7 @@ public class AppearanceManager {
public AppearanceManager(Player player) {
this.player = player;
this.packetSender = new PaperPacketSender(player, getNickoProfile());
this.packetSender = new PacketEventsPacketSender(player, getNickoProfile());
}
public ActionResult reset() {
@ -33,11 +33,16 @@ public class AppearanceManager {
final PlayerResetDisguiseEvent event = new PlayerResetDisguiseEvent(player);
Bukkit.getPluginManager().callEvent(event);
final String playerName = nameStore.getStoredName(player);
profile.setName(playerName);
profile.setSkin(playerName);
final ActionResult resetSkinUpdate = update(true);
profile.setName(null);
profile.setSkin(null);
dataStore.getCache().cache(player.getUniqueId(), profile);
return ActionResult.error();
return resetSkinUpdate;
}
public ActionResult update(boolean skinChange) {
@ -50,19 +55,38 @@ public class AppearanceManager {
final ActionResult propertiesUpdateResult = packetSender.updatePlayerProfileProperties();
if (propertiesUpdateResult.isError()) {
return reset();
return resetWithoutUpdate();
}
}
// Not needed, but still broken using PE.
//packetSender.sendPlayerRespawn();
// Call the event.
final PlayerDisguiseEvent event = new PlayerDisguiseEvent(player, profile.getSkin(), profile.getName());
Bukkit.getPluginManager().callEvent(event);
packetSender.sendEntityMetadataUpdate();
packetSender.sendTabListUpdate(displayName);
packetSender.sendEntityRespawn();
return result;
}
private ActionResult resetWithoutUpdate() {
final NickoProfile profile = getNickoProfile();
// Call the event.
final PlayerResetDisguiseEvent event = new PlayerResetDisguiseEvent(player);
Bukkit.getPluginManager().callEvent(event);
profile.setName(null);
profile.setSkin(null);
dataStore.getCache().cache(player.getUniqueId(), profile);
return ActionResult.ok();
}
private NickoProfile getNickoProfile() {
final Optional<NickoProfile> optionalProfile = dataStore.getData(player.getUniqueId());
return optionalProfile.orElse(NickoProfile.EMPTY_PROFILE.clone());

View file

@ -47,7 +47,7 @@ public class FavoritesGUI {
items = Collections.emptyList();
} else {
items = favorites.stream()
.map((appearance) -> new FavoriteAppearanceEntryItem(player, appearance).get())
.map((appearance) -> new FavoriteAppearanceEntryItem(playerLanguage, appearance))
.collect(Collectors.toList());
}

View file

@ -2,34 +2,34 @@ package xyz.ineanto.nicko.gui.items.favorites;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.jetbrains.annotations.NotNull;
import xyz.ineanto.nicko.Nicko;
import xyz.ineanto.nicko.appearance.ActionResult;
import xyz.ineanto.nicko.appearance.Appearance;
import xyz.ineanto.nicko.appearance.AppearanceManager;
import xyz.ineanto.nicko.gui.items.ItemDefaults;
import xyz.ineanto.nicko.language.LanguageKey;
import xyz.ineanto.nicko.language.PlayerLanguage;
import xyz.ineanto.nicko.profile.NickoProfile;
import xyz.ineanto.nicko.storage.PlayerDataStore;
import xyz.xenondevs.invui.item.builder.ItemBuilder;
import xyz.xenondevs.invui.item.builder.SkullBuilder;
import xyz.xenondevs.invui.item.impl.AsyncItem;
import xyz.xenondevs.invui.util.MojangApiUtils;
import xyz.xenondevs.invui.item.impl.SuppliedItem;
import java.io.IOException;
public class FavoriteAppearanceEntryItem extends AsyncItem {
private final PlayerDataStore dataStore = Nicko.getInstance().getDataStore();
public class FavoriteAppearanceEntryItem {
private final AppearanceManager appearanceManager;
private final PlayerLanguage playerLanguage;
private final Appearance appearance;
public FavoriteAppearanceEntryItem(Player player, Appearance appearance) {
this.appearanceManager = new AppearanceManager(player);
this.playerLanguage = new PlayerLanguage(player);
this.appearance = appearance;
}
public AsyncItem get() {
// TODO (Ineanto, 26/06/2025): handle click
final ItemBuilder temporaryItemBuilder = new ItemBuilder(Material.PAINTING);
return new AsyncItem(playerLanguage.translateItem(temporaryItemBuilder, LanguageKey.GUI.LOADING),
public FavoriteAppearanceEntryItem(PlayerLanguage playerLanguage, Appearance appearance) {
super(new SuppliedItem(() -> {
final ItemBuilder builder = new ItemBuilder(Material.PAINTING);
return playerLanguage.translateItem(builder, LanguageKey.GUI.LOADING);
}, (_ -> true)).getItemProvider(),
() -> {
try {
// TODO (Ineanto, 08/06/2025): set a default skin if the entry contains only a name
@ -37,10 +37,38 @@ public class FavoriteAppearanceEntryItem {
final String skin = (appearance.skin() == null ? "N/A" : appearance.skin());
final SkullBuilder skull = new SkullBuilder(skin);
return playerLanguage.translateItem(skull, LanguageKey.GUI.Favorites.ENTRY, name, skin);
} catch (MojangApiUtils.MojangApiException | IOException e) {
} catch (Exception e) {
Nicko.getInstance().getLogger().warning("Unable to get Head texture for specified UUID (" + appearance.skin() + ")! (GUI/Favorites/Entry)");
return ItemDefaults.getErrorSkullItem(playerLanguage, LanguageKey.GUI.Favorites.ENTRY, "N/A", "N/A");
}
});
this.playerLanguage = playerLanguage;
this.appearance = appearance;
}
@Override
public void handleClick(@NotNull ClickType clickType, @NotNull Player player, @NotNull InventoryClickEvent event) {
if (clickType.isLeftClick() || clickType.isRightClick()) {
event.getView().close();
final NickoProfile profile = dataStore.getData(player.getUniqueId()).orElse(NickoProfile.EMPTY_PROFILE);
final AppearanceManager appearanceManager = new AppearanceManager(player);
profile.setName(appearance.name());
profile.setSkin(appearance.skin());
dataStore.updateCache(player.getUniqueId(), profile);
final ActionResult result = appearanceManager.update(true);
if (!result.isError()) {
player.sendMessage(playerLanguage.translateWithWhoosh(LanguageKey.Event.Appearance.Set.OK));
} else {
player.sendMessage(playerLanguage.translateWithOops(
LanguageKey.Event.Appearance.Set.ERROR,
result.getErrorKey()
)
);
appearanceManager.reset();
}
}
}
}

View file

@ -25,7 +25,7 @@ public class RandomSkinItem {
public SuppliedItem get() {
return new SuppliedItem(() -> {
final ItemBuilder builder = new ItemBuilder(Material.WIND_CHARGE);
final ItemBuilder builder = new ItemBuilder(Material.COBWEB);
return playerLanguage.translateItem(builder, LanguageKey.GUI.Home.RANDOM_SKIN);
}, (event) -> {
final Player player = event.getPlayer();

View file

@ -4,6 +4,7 @@ import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import xyz.ineanto.nicko.appearance.ActionResult;
import xyz.ineanto.nicko.appearance.AppearanceManager;
import xyz.ineanto.nicko.language.PlayerLanguage;
import xyz.ineanto.nicko.language.LanguageKey;
@ -37,10 +38,11 @@ public class ResetItem {
}
final AppearanceManager appearanceManager = new AppearanceManager(player);
if (!appearanceManager.reset().isError()) {
final ActionResult reset = appearanceManager.reset();
if (!reset.isError()) {
player.sendMessage(playerLanguage.translateWithWhoosh(LanguageKey.Event.Appearance.Remove.OK));
} else {
player.sendMessage(playerLanguage.translateWithOops(LanguageKey.Event.Appearance.Remove.ERROR));
player.sendMessage(playerLanguage.translateWithOops(LanguageKey.Event.Appearance.Remove.ERROR, reset.getErrorKey()));
player.playSound(player.getLocation(), Sound.ENTITY_VILLAGER_NO, 1, 1f);
}
});

View file

@ -0,0 +1,176 @@
package xyz.ineanto.nicko.packet;
import com.destroystokyo.paper.profile.PlayerProfile;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
import com.github.retrooper.packetevents.protocol.player.TextureProperty;
import com.github.retrooper.packetevents.protocol.player.UserProfile;
import com.github.retrooper.packetevents.protocol.world.Difficulty;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import com.github.retrooper.packetevents.wrapper.play.server.*;
import io.github.retrooper.packetevents.util.SpigotConversionUtil;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.entity.Player;
import xyz.ineanto.nicko.Nicko;
import xyz.ineanto.nicko.appearance.ActionResult;
import xyz.ineanto.nicko.language.LanguageKey;
import xyz.ineanto.nicko.mojang.MojangAPI;
import xyz.ineanto.nicko.mojang.MojangSkin;
import xyz.ineanto.nicko.profile.NickoProfile;
import java.io.IOException;
import java.util.EnumSet;
import java.util.List;
import java.util.Optional;
import java.util.Random;
import java.util.concurrent.ExecutionException;
public record PacketEventsPacketSender(Player player, NickoProfile profile) implements PacketSender {
@Override
public void sendEntityRespawn() {
if (!profile.hasData()) return;
final WrapperPlayServerDestroyEntities destroy = new WrapperPlayServerDestroyEntities(player.getEntityId());
final WrapperPlayServerSpawnEntity spawn = new WrapperPlayServerSpawnEntity(
new Random().nextInt(9999),
Optional.of(player.getUniqueId()),
EntityTypes.PLAYER,
new Vector3d(player.getX(), player.getY(), player.getZ()),
player.getPitch(),
player.getYaw(),
player.getBodyYaw(),
0,
Optional.empty()
);
Bukkit.getOnlinePlayers().stream().filter(receiver -> receiver.getUniqueId() != player.getUniqueId()).forEach(receiver -> {
sendPacket(destroy, player);
sendPacket(spawn, player);
});
}
@Override
public ActionResult updatePlayerProfile(String name) {
final PlayerProfile previousProfile = player.getPlayerProfile();
final PlayerProfile newProfile = Bukkit.getServer().createProfile(player.getUniqueId(), name);
// Copy previous properties to preserve skin
newProfile.setProperties(previousProfile.getProperties());
player.setPlayerProfile(newProfile);
return ActionResult.ok();
}
@Override
public ActionResult updatePlayerProfileProperties() {
final PlayerProfile playerProfile = player.getPlayerProfile();
try {
final MojangAPI mojangAPI = Nicko.getInstance().getMojangAPI();
final Optional<String> uuid = mojangAPI.getUUID(profile.getSkin());
if (uuid.isEmpty()) {
return ActionResult.error(LanguageKey.Error.MOJANG);
}
final Optional<MojangSkin> skin = mojangAPI.getSkin(uuid.get());
if (skin.isEmpty()) {
return ActionResult.error(LanguageKey.Error.MOJANG);
}
final MojangSkin skinResult = skin.get();
playerProfile.setProperties(skinResult.asProfileProperties());
player.setPlayerProfile(playerProfile);
return ActionResult.ok();
} catch (ExecutionException | IOException e) {
return ActionResult.error(LanguageKey.Error.CACHE);
}
}
@Override
public void sendEntityMetadataUpdate() {
// This was surprisingly easy to write?
final EntityData<Byte> entityData = new EntityData<>(17, EntityDataTypes.BYTE, (byte) 0x7f);
final WrapperPlayServerEntityMetadata metadata = new WrapperPlayServerEntityMetadata(player.getEntityId(), List.of(entityData));
sendPacket(metadata, player);
}
@Override
public void sendPlayerRespawn() {
final World world = player.getWorld();
final WrapperPlayServerRespawn respawn = new WrapperPlayServerRespawn(
SpigotConversionUtil.typeFromBukkitWorld(world),
world.getName(),
Difficulty.getById(world.getDifficulty().ordinal()),
world.getSeed(),
SpigotConversionUtil.fromBukkitGameMode(player.getGameMode()),
SpigotConversionUtil.fromBukkitGameMode(player.getPreviousGameMode()),
false,
false,
true,
null,
null,
null
);
sendPacket(respawn, player);
}
@Override
public void sendTabListUpdate(String displayName) {
final EnumSet<WrapperPlayServerPlayerInfoUpdate.Action> actions = EnumSet.of(
WrapperPlayServerPlayerInfoUpdate.Action.ADD_PLAYER,
WrapperPlayServerPlayerInfoUpdate.Action.INITIALIZE_CHAT,
WrapperPlayServerPlayerInfoUpdate.Action.UPDATE_LISTED,
WrapperPlayServerPlayerInfoUpdate.Action.UPDATE_DISPLAY_NAME,
WrapperPlayServerPlayerInfoUpdate.Action.UPDATE_GAME_MODE,
WrapperPlayServerPlayerInfoUpdate.Action.UPDATE_LATENCY
);
final List<WrapperPlayServerPlayerInfoUpdate.PlayerInfo> entries = List.of(
new WrapperPlayServerPlayerInfoUpdate.PlayerInfo(
toUserProfile(player.getPlayerProfile()),
true,
player.getPing(),
SpigotConversionUtil.fromBukkitGameMode(player.getGameMode()),
Component.text(displayName),
null, // Welcome back fucked chat encryption
player.getPlayerListOrder(),
true
)
);
final WrapperPlayServerPlayerInfoRemove remove = new WrapperPlayServerPlayerInfoRemove(player.getUniqueId());
final WrapperPlayServerPlayerInfoUpdate update = new WrapperPlayServerPlayerInfoUpdate(actions, entries);
Bukkit.getOnlinePlayers().forEach(onlinePlayer -> {
sendPacket(remove, onlinePlayer);
sendPacket(update, onlinePlayer);
});
}
private UserProfile toUserProfile(PlayerProfile playerProfile) {
return new UserProfile(
playerProfile.getId(),
playerProfile.getName(),
playerProfile.getProperties()
.stream()
.map(profileProperty -> new TextureProperty(
profileProperty.getName(),
profileProperty.getValue(),
profileProperty.getSignature()
))
.toList()
);
}
private void sendPacket(PacketWrapper<?> packet, Player player) {
PacketEvents.getAPI().getPlayerManager().sendPacket(player, packet);
}
}

View file

@ -1,167 +1,167 @@
package xyz.ineanto.nicko.packet;
import com.destroystokyo.paper.profile.CraftPlayerProfile;
import com.destroystokyo.paper.profile.PlayerProfile;
import it.unimi.dsi.fastutil.ints.IntList;
import net.minecraft.Optionull;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.network.chat.RemoteChatSession;
import net.minecraft.network.chat.contents.PlainTextContents;
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.world.entity.EntityType;
import net.minecraft.world.phys.Vec3;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.entity.Player;
import xyz.ineanto.nicko.Nicko;
import xyz.ineanto.nicko.appearance.ActionResult;
import xyz.ineanto.nicko.language.LanguageKey;
import xyz.ineanto.nicko.mojang.MojangAPI;
import xyz.ineanto.nicko.mojang.MojangSkin;
import xyz.ineanto.nicko.profile.NickoProfile;
import java.io.IOException;
import java.util.EnumSet;
import java.util.List;
import java.util.Optional;
import java.util.Random;
import java.util.concurrent.ExecutionException;
/**
* Look at this Mojang.
* I want you to really stare at this code.
* You made me do this.
*/
public class PaperPacketSender implements PacketSender {
private final Player player;
private final NickoProfile profile;
public PaperPacketSender(Player player, NickoProfile profile) {
this.player = player;
this.profile = profile;
}
@Override
public void sendEntityRespawn() {
if (!profile.hasData()) return;
final ClientboundRemoveEntitiesPacket destroy = new ClientboundRemoveEntitiesPacket(IntList.of(player.getEntityId()));
final ClientboundAddEntityPacket add = new ClientboundAddEntityPacket(
new Random().nextInt(9999),
player.getUniqueId(),
player.getX(),
player.getY(),
player.getZ(),
player.getPitch(),
player.getYaw(),
EntityType.PLAYER,
0,
Vec3.ZERO,
player.getBodyYaw()
);
Bukkit.getOnlinePlayers().stream().filter(receiver -> receiver.getUniqueId() != player.getUniqueId()).forEach(receiver -> {
sendPacket(destroy, player);
sendPacket(add, player);
});
}
@Override
public ActionResult updatePlayerProfile(String name) {
final PlayerProfile playerProfile = new CraftPlayerProfile(player.getUniqueId(), name);
// Copy previous properties to preserve skin
playerProfile.setProperties(playerProfile.getProperties());
player.setPlayerProfile(playerProfile);
return ActionResult.ok();
}
@Override
public ActionResult updatePlayerProfileProperties() {
final PlayerProfile playerProfile = new CraftPlayerProfile(player.getUniqueId(), profile.getName() == null ? player.getName() : profile.getName());
try {
final MojangAPI mojangAPI = Nicko.getInstance().getMojangAPI();
final Optional<String> uuid = mojangAPI.getUUID(profile.getSkin());
if (uuid.isEmpty()) {
return ActionResult.error(LanguageKey.Error.MOJANG);
}
final Optional<MojangSkin> skin = mojangAPI.getSkin(uuid.get());
if (skin.isEmpty()) {
return ActionResult.error(LanguageKey.Error.MOJANG);
}
final MojangSkin skinResult = skin.get();
playerProfile.setProperties(skinResult.asProfileProperties());
player.setPlayerProfile(playerProfile);
return ActionResult.ok();
} catch (ExecutionException | IOException e) {
return ActionResult.error(LanguageKey.Error.CACHE);
}
}
@Override
public void sendEntityMetadataUpdate() {
final SynchedEntityData.DataValue<?> dataValueComponent =
new SynchedEntityData.DataItem<>(
new EntityDataAccessor<>(17, EntityDataSerializers.BYTE),
(byte) 0x7f
).value();
final ClientboundSetEntityDataPacket data = new ClientboundSetEntityDataPacket(player.getEntityId(), List.of(dataValueComponent));
sendPacket(data, player);
}
@Override
public void sendPlayerRespawn() {
final ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();
final ServerLevel level = serverPlayer.serverLevel();
final ClientboundRespawnPacket respawn = new ClientboundRespawnPacket(serverPlayer.createCommonSpawnInfo(level), (byte) 0x03);
sendPacket(respawn, player);
}
@Override
public void sendTabListUpdate(String displayName) {
final ServerPlayer serverPlayer = (((CraftPlayer) player)).getHandle();
final EnumSet<ClientboundPlayerInfoUpdatePacket.Action> actions = EnumSet.of(
ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER,
ClientboundPlayerInfoUpdatePacket.Action.INITIALIZE_CHAT,
ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED,
ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME,
ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE,
ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY);
final List<ClientboundPlayerInfoUpdatePacket.Entry> entries = List.of(new ClientboundPlayerInfoUpdatePacket.Entry(
serverPlayer.getUUID(),
serverPlayer.gameProfile,
true,
serverPlayer.connection.latency(),
serverPlayer.gameMode.getGameModeForPlayer(),
MutableComponent.create(new PlainTextContents.LiteralContents(displayName)),
true,
serverPlayer.getTabListOrder(),
Optionull.map(serverPlayer.getChatSession(), RemoteChatSession::asData)
));
final ClientboundPlayerInfoUpdatePacket update = new ClientboundPlayerInfoUpdatePacket(actions, entries);
final ClientboundPlayerInfoRemovePacket remove = new ClientboundPlayerInfoRemovePacket(List.of(player.getUniqueId()));
Bukkit.getOnlinePlayers().forEach(onlinePlayer -> {
sendPacket(remove, onlinePlayer);
sendPacket(update, onlinePlayer);
});
}
private void sendPacket(Packet<?> packet, Player player) {
(((CraftPlayer) player).getHandle()).connection.send(packet);
}
}
//package xyz.ineanto.nicko.packet;
//
//import com.destroystokyo.paper.profile.CraftPlayerProfile;
//import com.destroystokyo.paper.profile.PlayerProfile;
//import it.unimi.dsi.fastutil.ints.IntList;
//import net.minecraft.Optionull;
//import net.minecraft.network.chat.MutableComponent;
//import net.minecraft.network.chat.RemoteChatSession;
//import net.minecraft.network.chat.contents.PlainTextContents;
//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.world.entity.EntityType;
//import net.minecraft.world.phys.Vec3;
//import org.bukkit.Bukkit;
//import org.bukkit.craftbukkit.entity.CraftPlayer;
//import org.bukkit.entity.Player;
//import xyz.ineanto.nicko.Nicko;
//import xyz.ineanto.nicko.appearance.ActionResult;
//import xyz.ineanto.nicko.language.LanguageKey;
//import xyz.ineanto.nicko.mojang.MojangAPI;
//import xyz.ineanto.nicko.mojang.MojangSkin;
//import xyz.ineanto.nicko.profile.NickoProfile;
//
//import java.io.IOException;
//import java.util.EnumSet;
//import java.util.List;
//import java.util.Optional;
//import java.util.Random;
//import java.util.concurrent.ExecutionException;
//
///**
// * Look at this Mojang.
// * I want you to really stare at this code.
// * You made me do this.
// */
//public class PaperPacketSender implements PacketSender {
// private final Player player;
// private final NickoProfile profile;
//
// public PaperPacketSender(Player player, NickoProfile profile) {
// this.player = player;
// this.profile = profile;
// }
//
// @Override
// public void sendEntityRespawn() {
// if (!profile.hasData()) return;
//
// final ClientboundRemoveEntitiesPacket destroy = new ClientboundRemoveEntitiesPacket(IntList.of(player.getEntityId()));
// final ClientboundAddEntityPacket add = new ClientboundAddEntityPacket(
// new Random().nextInt(9999),
// player.getUniqueId(),
// player.getX(),
// player.getY(),
// player.getZ(),
// player.getPitch(),
// player.getYaw(),
// EntityType.PLAYER,
// 0,
// Vec3.ZERO,
// player.getBodyYaw()
// );
//
// Bukkit.getOnlinePlayers().stream().filter(receiver -> receiver.getUniqueId() != player.getUniqueId()).forEach(receiver -> {
// sendPacket(destroy, player);
// sendPacket(add, player);
// });
// }
//
// @Override
// public ActionResult updatePlayerProfile(String name) {
// final PlayerProfile playerProfile = new CraftPlayerProfile(player.getUniqueId(), name);
// // Copy previous properties to preserve skin
// playerProfile.setProperties(playerProfile.getProperties());
// player.setPlayerProfile(playerProfile);
// return ActionResult.ok();
// }
//
// @Override
// public ActionResult updatePlayerProfileProperties() {
// final PlayerProfile playerProfile = new CraftPlayerProfile(player.getUniqueId(), profile.getName() == null ? player.getName() : profile.getName());
//
// try {
// final MojangAPI mojangAPI = Nicko.getInstance().getMojangAPI();
//
// final Optional<String> uuid = mojangAPI.getUUID(profile.getSkin());
// if (uuid.isEmpty()) {
// return ActionResult.error(LanguageKey.Error.MOJANG);
// }
//
// final Optional<MojangSkin> skin = mojangAPI.getSkin(uuid.get());
// if (skin.isEmpty()) {
// return ActionResult.error(LanguageKey.Error.MOJANG);
// }
//
// final MojangSkin skinResult = skin.get();
// playerProfile.setProperties(skinResult.asProfileProperties());
// player.setPlayerProfile(playerProfile);
// return ActionResult.ok();
// } catch (ExecutionException | IOException e) {
// return ActionResult.error(LanguageKey.Error.CACHE);
// }
// }
//
// @Override
// public void sendEntityMetadataUpdate() {
// final SynchedEntityData.DataValue<?> dataValueComponent =
// new SynchedEntityData.DataItem<>(
// new EntityDataAccessor<>(17, EntityDataSerializers.BYTE),
// (byte) 0x7f
// ).value();
//
// final ClientboundSetEntityDataPacket data = new ClientboundSetEntityDataPacket(player.getEntityId(), List.of(dataValueComponent));
// sendPacket(data, player);
// }
//
// @Override
// public void sendPlayerRespawn() {
// final ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();
// final ServerLevel level = serverPlayer.serverLevel();
//
// final ClientboundRespawnPacket respawn = new ClientboundRespawnPacket(serverPlayer.createCommonSpawnInfo(level), (byte) 0x03);
// sendPacket(respawn, player);
// }
//
// @Override
// public void sendTabListUpdate(String displayName) {
// final ServerPlayer serverPlayer = (((CraftPlayer) player)).getHandle();
//
// final EnumSet<ClientboundPlayerInfoUpdatePacket.Action> actions = EnumSet.of(
// ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER,
// ClientboundPlayerInfoUpdatePacket.Action.INITIALIZE_CHAT,
// ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED,
// ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME,
// ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE,
// ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY);
//
// final List<ClientboundPlayerInfoUpdatePacket.Entry> entries = List.of(new ClientboundPlayerInfoUpdatePacket.Entry(
// serverPlayer.getUUID(),
// serverPlayer.gameProfile,
// true,
// serverPlayer.connection.latency(),
// serverPlayer.gameMode.getGameModeForPlayer(),
// MutableComponent.create(new PlainTextContents.LiteralContents(displayName)),
// true,
// serverPlayer.getTabListOrder(),
// Optionull.map(serverPlayer.getChatSession(), RemoteChatSession::asData)
// ));
//
// final ClientboundPlayerInfoUpdatePacket update = new ClientboundPlayerInfoUpdatePacket(actions, entries);
// final ClientboundPlayerInfoRemovePacket remove = new ClientboundPlayerInfoRemovePacket(List.of(player.getUniqueId()));
//
// Bukkit.getOnlinePlayers().forEach(onlinePlayer -> {
// sendPacket(remove, onlinePlayer);
// sendPacket(update, onlinePlayer);
// });
// }
//
// private void sendPacket(Packet<?> packet, Player player) {
// (((CraftPlayer) player).getHandle()).connection.send(packet);
// }
//}

View file

@ -1,82 +0,0 @@
package xyz.ineanto.nicko.packet.debug;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.ListeningWhitelist;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.events.PacketListener;
import com.comphenix.protocol.wrappers.MinecraftKey;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey;
import org.bukkit.World;
import org.bukkit.plugin.Plugin;
import xyz.ineanto.nicko.Nicko;
import java.util.Arrays;
import java.util.Optional;
public class RespawnPacketListener implements PacketListener {
@Override
public void onPacketSending(PacketEvent event) {
try {
final Optional<World> world = getWorld(event);
if (world.isEmpty()) {
Bukkit.broadcast(Component.text("did not find the world the player was in"));
return;
}
Bukkit.broadcast(Component.text("found " + world.get().getName() + "!"));
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
@Override
public void onPacketReceiving(PacketEvent event) {
}
@Override
public ListeningWhitelist getSendingWhitelist() {
return ListeningWhitelist.newBuilder().types(PacketType.Play.Server.RESPAWN).build();
}
@Override
public ListeningWhitelist getReceivingWhitelist() {
return ListeningWhitelist.EMPTY_WHITELIST;
}
@Override
public Plugin getPlugin() {
return Nicko.getInstance();
}
private boolean keysEquals(MinecraftKey wrappedKey, NamespacedKey bukkitKey) {
// compare bukkit minecraft key and NMS wrapped minecraft key
return wrappedKey.getPrefix().equals(bukkitKey.getNamespace()) && wrappedKey.getKey().equals(bukkitKey.getKey());
}
public Optional<World> getWorld(PacketEvent event) throws Throwable {
// access CommonPlayerSpawnInfo, first field of that type in the Respawn / Login packets
final Object packetHandle = event.getPacket().getHandle();
final Object commonSpawnData = packetHandle.getClass().getRecordComponents()[0].getAccessor().invoke(packetHandle);
Arrays.stream(commonSpawnData.getClass().getRecordComponents()).forEach(component -> {
component.getAccessor().setAccessible(true);
System.out.println("-=-=-=-=-=-=-=-=-=-=-=-=-=-");
System.out.println(component.getName());
System.out.println(component.getType().getSimpleName());
component.getAccessor().setAccessible(false);
}
);
// get the key of the level the player is joining. Second field in the object. First of type ResourceKey
final MinecraftKey key = MinecraftKey.fromHandle(commonSpawnData.getClass().getRecordComponents()[1]);
for (World world : Bukkit.getWorlds()) {
if (keysEquals(key, world.getKey())) {
return Optional.of(world);
}
}
return Optional.empty();
}
}

View file

@ -1,73 +0,0 @@
/**
* PacketWrapper - ProtocolLib wrappers for Minecraft packets
* Copyright (C) dmulloy2 <http://dmulloy2.net>
* Copyright (C) Kristian S. Strangeland
* <p>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* <p>
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* <p>
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package xyz.ineanto.nicko.packet.wrapper;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.PacketContainer;
import com.google.common.base.Objects;
import org.bukkit.entity.Player;
public abstract class AbstractPacket {
protected PacketContainer handle;
/**
* Constructs a new strongly typed wrapper for the given packet.
*
* @param handle - handle to the raw packet data.
* @param type - the packet type.
*/
protected AbstractPacket(PacketContainer handle, PacketType type) {
// Make sure we're given a valid packet
if (handle == null)
throw new IllegalArgumentException("Packet handle cannot be NULL.");
if (!Objects.equal(handle.getType(), type))
throw new IllegalArgumentException(handle.getHandle()
+ " is not a packet of type " + type);
this.handle = handle;
}
/**
* Retrieve a handle to the raw packet data.
*
* @return Raw packet data.
*/
public PacketContainer getHandle() {
return handle;
}
/**
* Send the current packet to the given receiver.
*
* @param receiver - the receiver.
* @throws RuntimeException If the packet cannot be sent.
*/
public void sendPacket(Player receiver) {
ProtocolLibrary.getProtocolManager().sendServerPacket(receiver,
getHandle());
}
/**
* Send the current packet to all online players.
*/
public void broadcastPacket() {
ProtocolLibrary.getProtocolManager().broadcastServerPacket(getHandle());
}
}

View file

@ -1,32 +0,0 @@
package xyz.ineanto.nicko.packet.wrapper;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.wrappers.Converters;
import it.unimi.dsi.fastutil.ints.IntList;
/**
* Sent by the server to the client to remove one or more entities.
*/
public class WrapperPlayServerEntityDestroy extends AbstractPacket {
/**
* The packet type that is wrapped by this wrapper.
*/
public static final PacketType TYPE = PacketType.Play.Server.ENTITY_DESTROY;
public WrapperPlayServerEntityDestroy() {
super(new PacketContainer(TYPE), TYPE);
handle.getModifier().writeDefaults();
}
/**
* Sets the list of entity ids to remove
*
* @param value New value for field 'entityIds'
*/
public void setEntityIds(IntList value) {
this.handle.getModifier().withType(IntList.class, Converters.passthrough(IntList.class)).writeSafely(0, value);
}
}

View file

@ -1,147 +0,0 @@
package xyz.ineanto.nicko.packet.wrapper;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.InternalStructure;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.StructureModifier;
import com.comphenix.protocol.reflect.accessors.Accessors;
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.comphenix.protocol.wrappers.BukkitConverters;
import com.comphenix.protocol.wrappers.EnumWrappers;
import com.comphenix.protocol.wrappers.MinecraftKey;
import com.google.common.hash.Hashing;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.World;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.RecordComponent;
import java.util.Arrays;
/**
* PacketPlayServerRespawn Wrapper class (1.20.X to 1.21.X)
* <p>
* In 1.20.2, all the fields were merged inside a
* single "CommonPlayerSpawnInfo" record.
*
* @author inenato (w/ additional help from lukalt), based on work from dmulloy2 and Kristian S. Strangeland
*/
public class WrapperPlayServerRespawn extends AbstractPacket {
public static final PacketType TYPE = PacketType.Play.Server.RESPAWN;
private InternalStructure spawnInfoStructure = null;
public WrapperPlayServerRespawn() {
super(new PacketContainer(TYPE), TYPE);
handle.getModifier().writeDefaults();
if (MinecraftVersion.CONFIG_PHASE_PROTOCOL_UPDATE.atOrAbove()) {
spawnInfoStructure = handle.getStructures().read(0);
}
}
public void setDimension(World value) {
final MinecraftVersion v1_20_5 = new MinecraftVersion(1, 20, 5);
if (!MinecraftVersion.getCurrentVersion().isAtLeast(v1_20_5)) {
// 1.20 - 1.20.4
final StructureModifier<InternalStructure> structureModifier = spawnInfoStructure == null ?
handle.getStructures() : spawnInfoStructure.getStructures();
final StructureModifier<World> worldStructureModifier = spawnInfoStructure == null ?
handle.getWorldKeys() : spawnInfoStructure.getWorldKeys();
final InternalStructure dimensionType = structureModifier.read(0);
dimensionType.getMinecraftKeys().writeSafely(0, new MinecraftKey("minecraft", "dimension_type"));
dimensionType.getMinecraftKeys().writeSafely(1, new MinecraftKey("minecraft", "overworld"));
structureModifier.writeSafely(0, dimensionType);
worldStructureModifier.writeSafely(0, value);
} else {
// 1.20.5 to 1.21.1
try {
final Class<?> spawnInfoClass = MinecraftReflection.getMinecraftClass("network.protocol.game.CommonPlayerSpawnInfo");
Class<?>[] componentTypes = Arrays.stream(spawnInfoClass.getRecordComponents())
.map(RecordComponent::getType)
.toArray(Class<?>[]::new);
final Constructor<?> spawnInfoConstructor = spawnInfoClass.getDeclaredConstructor(componentTypes);
/**
* Holder<DimensionType> dimensionType,
* ResourceKey<Level> dimension,
* long seed,
* GameType gameType,
* GameType previousGameType,
* boolean isDebug,
* boolean isFlat,
* Optional<GlobalPos> lastDeathLocation,
* int portalCooldown
*/
final World world = Bukkit.getWorld("world");
FuzzyReflection.fromClass(spawnInfoClass).getConstructor(
FuzzyMethodContract
.newBuilder()
.build()
);
final Object spawnInfo = spawnInfoConstructor.newInstance(
BukkitConverters.getDimensionConverter().getGeneric(world),
BukkitConverters.getWorldKeyConverter().getGeneric(world),
world.getSeed(),
EnumWrappers.getGameModeConverter().getGeneric(EnumWrappers.NativeGameMode.fromBukkit(GameMode.SURVIVAL)),
EnumWrappers.getGameModeConverter().getGeneric(EnumWrappers.NativeGameMode.fromBukkit(GameMode.SURVIVAL)),
false,
false,
BukkitConverters.getSectionPositionConverter()
);
final Field commonSpawnDataField = Accessors.getFieldAccessor(TYPE.getPacketClass(), spawnInfoClass, true).getField();
commonSpawnDataField.set(spawnInfoStructure.getHandle(), spawnInfo);
} catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException |
InstantiationException e) {
throw new RuntimeException();
}
}
}
public void setGameMode(GameMode value) {
if (!MinecraftVersion.CONFIG_PHASE_PROTOCOL_UPDATE.atOrAbove()) {
// 1.20 to 1.20.1
handle.getGameModes().writeSafely(0, EnumWrappers.NativeGameMode.fromBukkit(value));
return;
}
spawnInfoStructure.getGameModes().writeSafely(0, EnumWrappers.NativeGameMode.fromBukkit(value));
}
public void setPreviousGameMode(GameMode value) {
if (!MinecraftVersion.CONFIG_PHASE_PROTOCOL_UPDATE.atOrAbove()) {
// 1.20 to 1.20.1
handle.getGameModes().writeSafely(1, EnumWrappers.NativeGameMode.fromBukkit(value));
return;
}
spawnInfoStructure.getGameModes().writeSafely(1, EnumWrappers.NativeGameMode.fromBukkit(value));
}
public void setCopyMetadata(boolean value) {
if (!MinecraftVersion.CONFIG_PHASE_PROTOCOL_UPDATE.atOrAbove()) return;
// 1.20 to 1.20.1
handle.getBooleans().writeSafely(0, value);
}
public void setSeed(long value) {
if (!MinecraftVersion.CONFIG_PHASE_PROTOCOL_UPDATE.atOrAbove()) {
// 1.20 to 1.20.1
handle.getLongs().writeSafely(0, Hashing.sha256().hashLong(value).asLong());
}
}
}

View file

@ -1,103 +0,0 @@
package xyz.ineanto.nicko.packet.wrapper;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketContainer;
import org.bukkit.Location;
import org.bukkit.entity.EntityType;
import javax.annotation.Nonnull;
import java.util.UUID;
/**
* This packet is sent by the server when a player comes into visible range, not when a player joins.
*/
public class WrapperPlayServerSpawnEntity extends AbstractPacket {
/**
* The packet type that is wrapped by this wrapper.
*/
public static final PacketType TYPE = PacketType.Play.Server.SPAWN_ENTITY;
/**
* Constructors a new wrapper for the specified packet
*/
public WrapperPlayServerSpawnEntity() {
super(new PacketContainer(TYPE), TYPE);
handle.getModifier().writeDefaults();
}
/**
* Sets the entity id of the player
*
* @param value New value for field 'entityId'
*/
public void setEntityId(int value) {
this.handle.getIntegers().writeSafely(0, value);
this.handle.getEntityTypeModifier().writeSafely(0, EntityType.PLAYER);
}
/**
* Sets the unique id of the player
*
* @param value New value for field 'playerId'
*/
public void setPlayerId(UUID value) {
this.handle.getUUIDs().writeSafely(0, value);
}
/**
* Sets the value of field 'x'
*
* @param value New value for field 'x'
*/
public void setX(double value) {
this.handle.getDoubles().writeSafely(0, value);
}
/**
* Sets the value of field 'y'
*
* @param value New value for field 'y'
*/
public void setY(double value) {
this.handle.getDoubles().writeSafely(1, value);
}
/**
* Sets the value of field 'z'
*
* @param value New value for field 'z'
*/
public void setZ(double value) {
this.handle.getDoubles().write(2, value);
}
/**
* Sets the discrete rotation around the y-axis (yaw)
*
* @param value New value for field 'yRot'
*/
public void setYRotRaw(byte value) {
this.handle.getBytes().writeSafely(0, value);
}
/**
* Sets the discrete rotation around the x-axis (pitch)
*
* @param value New value for field 'xRot'
*/
public void setXRotRaw(byte value) {
this.handle.getBytes().writeSafely(1, value);
}
public void setLocation(@Nonnull Location location) {
setX(location.getX());
setY(location.getY());
setZ(location.getZ());
setYRotRaw(degreesToAngle(location.getYaw()));
setXRotRaw(degreesToAngle(location.getPitch()));
}
private byte degreesToAngle(float degree) {
return (byte)((int)(degree * 256.0F / 360.0F));
}
}

View file

@ -1,37 +0,0 @@
package xyz.ineanto.nicko.packet.wrapper;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.comphenix.protocol.wrappers.EnumWrappers;
import com.comphenix.protocol.wrappers.PlayerInfoData;
import java.util.List;
import java.util.Set;
/**
* Up-to-date version of the Wrapper class
* for the PlayerServerPlayerInfo.
*
* @author ineanto, based on work from dmulloy2 and Kristian S. Strangeland
*/
public class WrapperPlayerServerPlayerInfo extends AbstractPacket {
public static final PacketType TYPE = PacketType.Play.Server.PLAYER_INFO;
public WrapperPlayerServerPlayerInfo() {
super(new PacketContainer(TYPE), TYPE);
handle.getModifier().writeDefaults();
}
public void setActions(Set<EnumWrappers.PlayerInfoAction> value) {
if (MinecraftVersion.FEATURE_PREVIEW_UPDATE.atOrAbove()) {
handle.getPlayerInfoActions().writeSafely(0, value);
} else {
handle.getPlayerInfoAction().writeSafely(0, value.stream().iterator().next()); // Get the first Value.
}
}
public void setData(List<PlayerInfoData> value) {
handle.getPlayerInfoDataLists().writeSafely(1, value);
}
}

View file

@ -1,27 +0,0 @@
package xyz.ineanto.nicko.packet.wrapper;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketContainer;
import java.util.List;
import java.util.UUID;
/**
* Up-to-date version of the Wrapper class
* for the PlayerServerPlayerInfoRemove.
*
* @author ineanto, based on work from dmulloy2 and Kristian S. Strangeland
*/
public class WrapperPlayerServerPlayerInfoRemove extends AbstractPacket {
public static final PacketType TYPE = PacketType.Play.Server.PLAYER_INFO_REMOVE;
public WrapperPlayerServerPlayerInfoRemove() {
super(new PacketContainer(TYPE), TYPE);
handle.getModifier().writeDefaults();
}
public void setUUIDs(List<UUID> value) {
handle.getUUIDLists().writeSafely(0, value);
}
}

View file

@ -169,7 +169,7 @@ gui:
- "<grey>Clicking on any disguise as this mode is</grey>"
- "<grey>active will remove it from your favorites.</grey>"
entry:
name: "Favorite"
name: "<gold>Favorite</gold>"
lore:
- "<gray>Name:</gray> <green>{0}</green>"
- "<gray>Skin:</gray> <green>{1}</green>"
- "<gray>Name:</gray> <yellow>{0}</yellow>"
- "<gray>Skin:</gray> <yellow>{1}</yellow>"

View file

@ -26,7 +26,7 @@ event:
error: "<gray>Impossible d''appliquer le précédent déguisement ! ({0})</gray>"
ok: "<gray>Votre précédent déguisement a été appliqué.<gray>"
remove:
error: "<gray>Impossible de retirer votre déguisement.</gray>"
error: "<gray>Impossible de retirer votre déguisement ({0}).</gray>"
missing: "<gray>Vous n''avez pas de déguisement.</gray>"
ok: "<gray>Déguisement retiré.</gray>"
admin:
@ -171,7 +171,7 @@ gui:
- "<grey>Cliquer sur un déguisement lorsque le mode est</grey>"
- "<grey>actif le supprimera de vos favoris.</grey>"
entry:
name: "Favori"
name: "<gold>Favori</gold>"
lore:
- "<gray>Nom:</gray> <green>{0}</green>"
- "<gray>Skin:</gray> <green>{1}</green>"
- "<gray>Nom:</gray> <yellow>{0}</yellow>"
- "<gray>Skin:</gray> <yellow>{1}</yellow>"