Skip to content

Commit

Permalink
Add ClientboundSetEntityDataPacket
Browse files Browse the repository at this point in the history
  • Loading branch information
OliverSchlueter committed Jun 13, 2024
1 parent 004d38e commit 04aba26
Show file tree
Hide file tree
Showing 7 changed files with 232 additions and 20 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package de.oliver.fancysitula.api.packets;

import java.util.List;

public abstract class FS_ClientboundSetEntityDataPacket implements FS_ClientboundPacket {

protected int entityId;
protected List<EntityData> entityData;

public FS_ClientboundSetEntityDataPacket(int entityId, List<EntityData> entityData) {
this.entityId = entityId;
this.entityData = entityData;
}

public int getEntityId() {
return entityId;
}

public void setEntityId(int entityId) {
this.entityId = entityId;
}

public List<EntityData> getEntityData() {
return entityData;
}

public void setEntityData(List<EntityData> entityData) {
this.entityData = entityData;
}

/**
* @param accessor can be found in {@link de.oliver.fancysitula.api.utils.entityData}
* @param value must be the correct type for the accessor (see accessor javadoc)
*/
public record EntityData(EntityDataAccessor accessor, Object value) {
}

/**
* @param entityClassName the class name of the entity (e.g. "net.minecraft.world.entity.Display$TextDisplay")
* @param accessorFieldName the field name of the accessor (typically starts with "DATA_" and ends with "_ID")
*/
public record EntityDataAccessor(String entityClassName, String accessorFieldName) {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package de.oliver.fancysitula.api.utils.entityData;

import de.oliver.fancysitula.api.packets.FS_ClientboundSetEntityDataPacket;

public enum TextDisplayData {
/**
* Use {@link net.kyori.adventure.text.Component} as value
*/
TEXT(new FS_ClientboundSetEntityDataPacket.EntityDataAccessor("net.minecraft.world.entity.Display$TextDisplay", "DATA_TEXT_ID")),

/**
* Use {@link Integer} as value
*/
LINE_WIDTH(new FS_ClientboundSetEntityDataPacket.EntityDataAccessor("net.minecraft.world.entity.Display$TextDisplay", "DATA_LINE_WIDTH_ID")),

/**
* Use {@link Integer} as value
*/
BACKGROUND(new FS_ClientboundSetEntityDataPacket.EntityDataAccessor("net.minecraft.world.entity.Display$TextDisplay", "DATA_BACKGROUND_COLOR_ID")),

/**
* Use {@link Byte} as value
*/
TEXT_OPACITY(new FS_ClientboundSetEntityDataPacket.EntityDataAccessor("net.minecraft.world.entity.Display$TextDisplay", "DATA_TEXT_OPACITY_ID")),

/**
* Use {@link Byte} as value
*/
STYLE_FLAGS(new FS_ClientboundSetEntityDataPacket.EntityDataAccessor("net.minecraft.world.entity.Display$TextDisplay", "DATA_STYLE_FLAGS_ID")),
;

private final FS_ClientboundSetEntityDataPacket.EntityDataAccessor accessor;

TextDisplayData(FS_ClientboundSetEntityDataPacket.EntityDataAccessor accessor) {
this.accessor = accessor;
}

public FS_ClientboundSetEntityDataPacket.EntityDataAccessor get() {
return accessor;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,10 @@ public static void setFinalField(Object target, String fieldName, Object value)
unsafe.putObject(target, offset, value);
}
}

public static <T> T getStaticField(Class<?> clazz, String fieldName) throws NoSuchFieldException, IllegalAccessException {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return (T) field.get(null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -236,4 +236,30 @@ public FS_ClientboundRotateHeadPacket createRotateHeadPacket(ServerVersion serve
public FS_ClientboundRotateHeadPacket createRotateHeadPacket(int entityId, float headYaw) {
return createRotateHeadPacket(ServerVersion.getCurrentVersion(), entityId, headYaw);
}

/**
* Creates a new FS_ClientboundSetEntityDataPacket instance based on the server version
*
* @param entityId ID of the entity to set the data of
* @param entityData List of {@link FS_ClientboundSetEntityDataPacket.EntityData} to set
*/
public FS_ClientboundSetEntityDataPacket createSetEntityDataPacket(
ServerVersion serverVersion, int entityId, List<FS_ClientboundSetEntityDataPacket.EntityData> entityData) {
switch (serverVersion) {
case v1_20_6 -> {
return new de.oliver.fancysitula.versions.v1_20_6.packets.ClientboundSetEntityDataPacketImpl(entityId, entityData);
}
default -> throw new IllegalArgumentException("Unsupported server version: " + serverVersion.getVersion());
}
}

/**
* Creates a new FS_ClientboundSetEntityDataPacket instance based on the current server version
*
* @param entityId ID of the entity to set the data of
* @param entityData List of {@link FS_ClientboundSetEntityDataPacket.EntityData} to set
*/
public FS_ClientboundSetEntityDataPacket createSetEntityDataPacket(int entityId, List<FS_ClientboundSetEntityDataPacket.EntityData> entityData) {
return createSetEntityDataPacket(ServerVersion.getCurrentVersion(), entityId, entityData);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package de.oliver.fancysitula.versions.v1_20_6.packets;

import de.oliver.fancysitula.api.entities.FS_RealPlayer;
import de.oliver.fancysitula.api.packets.FS_ClientboundSetEntityDataPacket;
import de.oliver.fancysitula.api.utils.reflections.ReflectionUtils;
import de.oliver.fancysitula.versions.v1_20_6.utils.VanillaPlayerAdapter;
import io.papermc.paper.adventure.PaperAdventure;
import net.kyori.adventure.text.Component;
import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.server.level.ServerPlayer;

import java.util.ArrayList;
import java.util.List;

public class ClientboundSetEntityDataPacketImpl extends FS_ClientboundSetEntityDataPacket {

public ClientboundSetEntityDataPacketImpl(int entityId, List<EntityData> entityData) {
super(entityId, entityData);
}

@Override
public Object createPacket() {
List<SynchedEntityData.DataValue<?>> dataValues = new ArrayList<>();
for (EntityData data : entityData) {
try {
Class<?> entityClass = Class.forName(data.accessor().entityClassName());
net.minecraft.network.syncher.EntityDataAccessor<Object> accessor = ReflectionUtils.getStaticField(entityClass, data.accessor().accessorFieldName());

Object vanillaValue = data.value();

if (data.value() instanceof Component c) {
vanillaValue = PaperAdventure.asVanilla(c);
}

dataValues.add(SynchedEntityData.DataValue.create(accessor, vanillaValue));
} catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}

return new ClientboundSetEntityDataPacket(entityId, dataValues);
}

@Override
public void send(FS_RealPlayer player) {
ClientboundSetEntityDataPacket packet = (ClientboundSetEntityDataPacket) createPacket();

ServerPlayer vanillaPlayer = VanillaPlayerAdapter.asVanilla(player.getBukkitPlayer());
vanillaPlayer.connection.send(packet);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package de.oliver.fancysitula.versions.v1_20_6.packets;

import de.oliver.fancysitula.api.packets.FS_ClientboundSetEntityDataPacket;
import de.oliver.fancysitula.api.utils.entityData.TextDisplayData;
import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket;

import java.util.List;

class ClientboundSetEntityDataPacketImplTest {

//TODO: Fix this test (using registry)
// @Test
void createPacket() {
int entityId = 712;
List<FS_ClientboundSetEntityDataPacket.EntityData> entityData = List.of(
new FS_ClientboundSetEntityDataPacket.EntityData(
TextDisplayData.TEXT.get(),
"Hello, World!"
)
);

ClientboundSetEntityDataPacketImpl packet = new ClientboundSetEntityDataPacketImpl(entityId, entityData);
ClientboundSetEntityDataPacket createdPacket = (ClientboundSetEntityDataPacket) packet.createPacket();

assert createdPacket.id() == entityId;
assert createdPacket.packedItems().size() == 1;
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package de.oliver.fancysitula.commands;

import de.oliver.fancysitula.api.entities.FS_RealPlayer;
import de.oliver.fancysitula.api.packets.FS_ClientboundPlayerInfoUpdatePacket;
import de.oliver.fancysitula.api.packets.FS_ClientboundSetEntityDataPacket;
import de.oliver.fancysitula.api.utils.FS_GameProfile;
import de.oliver.fancysitula.api.utils.FS_GameType;
import de.oliver.fancysitula.api.utils.entityData.TextDisplayData;
import de.oliver.fancysitula.factories.FancySitula;
import net.kyori.adventure.text.Component;
import org.bukkit.command.Command;
Expand All @@ -12,7 +12,6 @@
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;

import java.util.EnumSet;
import java.util.List;
import java.util.UUID;

Expand All @@ -36,29 +35,29 @@ public boolean execute(@NotNull CommandSender sender, @NotNull String s, @NotNul
FS_GameProfile fakeProfile = new FS_GameProfile(UUID.randomUUID(), "FakePlayer");

// PlayerInfoUpdatePacket
FS_ClientboundPlayerInfoUpdatePacket.Entry entry = new FS_ClientboundPlayerInfoUpdatePacket.Entry(
fakeProfile.getUUID(),
fakeProfile,
true,
42,
FS_GameType.SURVIVAL,
Component.text("FakePlayer1123")
);

EnumSet<FS_ClientboundPlayerInfoUpdatePacket.Action> actions = EnumSet.of(FS_ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER);
actions.add(FS_ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME);
actions.add(FS_ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED);

FancySitula.PACKET_FACTORY
.createPlayerInfoUpdatePacket(actions, List.of(entry))
.send(fsPlayer);
// FS_ClientboundPlayerInfoUpdatePacket.Entry entry = new FS_ClientboundPlayerInfoUpdatePacket.Entry(
// fakeProfile.getUUID(),
// fakeProfile,
// true,
// 42,
// FS_GameType.SURVIVAL,
// Component.text("FakePlayer1123")
// );
//
// EnumSet<FS_ClientboundPlayerInfoUpdatePacket.Action> actions = EnumSet.of(FS_ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER);
// actions.add(FS_ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME);
// actions.add(FS_ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED);
//
// FancySitula.PACKET_FACTORY
// .createPlayerInfoUpdatePacket(actions, List.of(entry))
// .send(fsPlayer);

// AddEntityPacket
FancySitula.PACKET_FACTORY
.createAddEntityPacket(
420,
fakeProfile.getUUID(),
EntityType.PLAYER,
EntityType.TEXT_DISPLAY,
p.getLocation().getX(),
p.getLocation().getY(),
p.getLocation().getZ(),
Expand All @@ -72,6 +71,22 @@ public boolean execute(@NotNull CommandSender sender, @NotNull String s, @NotNul
)
.send(fsPlayer);


FancySitula.PACKET_FACTORY
.createSetEntityDataPacket(
420,
List.of(
new FS_ClientboundSetEntityDataPacket.EntityData(
TextDisplayData.TEXT.get(),
Component.text("Hello world")
),
new FS_ClientboundSetEntityDataPacket.EntityData(
TextDisplayData.BACKGROUND.get(),
0xFF00FF00
)
)
)
.send(fsPlayer);
return true;
}
}

0 comments on commit 04aba26

Please sign in to comment.