Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.loohp.limbo.network.protocol.packets;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;

public class ClientboundOpenBookPacket extends PacketOut {

private final int hand; // 0 = main hand, 1 = off hand

public ClientboundOpenBookPacket(int hand) {
this.hand = hand;
}

public int getHand() {
return hand;
}

@Override
public byte[] serializePacket() throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();

DataOutputStream output = new DataOutputStream(buffer);
output.writeByte(Packet.getPlayOut().get(getClass()));
output.writeByte(hand);

return buffer.toByteArray();
}
}
116 changes: 75 additions & 41 deletions src/main/java/com/loohp/limbo/player/Player.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,12 @@
import com.loohp.limbo.inventory.Inventory;
import com.loohp.limbo.inventory.InventoryHolder;
import com.loohp.limbo.inventory.InventoryView;
import com.loohp.limbo.inventory.ItemStack;
import com.loohp.limbo.inventory.TitledInventory;
import com.loohp.limbo.location.Location;
import com.loohp.limbo.network.ClientConnection;
import com.loohp.limbo.network.protocol.packets.ClientboundClearTitlesPacket;
import com.loohp.limbo.network.protocol.packets.ClientboundOpenBookPacket;
import com.loohp.limbo.network.protocol.packets.ClientboundSetActionBarTextPacket;
import com.loohp.limbo.network.protocol.packets.ClientboundSetSubtitleTextPacket;
import com.loohp.limbo.network.protocol.packets.ClientboundSetTitleTextPacket;
Expand All @@ -53,6 +55,7 @@
import com.loohp.limbo.network.protocol.packets.PacketPlayOutPositionAndLook;
import com.loohp.limbo.network.protocol.packets.PacketPlayOutResourcePackSend;
import com.loohp.limbo.network.protocol.packets.PacketPlayOutRespawn;
import com.loohp.limbo.network.protocol.packets.PacketPlayOutSetSlot;
import com.loohp.limbo.network.protocol.packets.PacketPlayOutStopSound;
import com.loohp.limbo.sounds.SoundEffect;
import com.loohp.limbo.utils.BungeecordAdventureConversionUtils;
Expand All @@ -68,11 +71,15 @@
import net.kyori.adventure.sound.SoundStop;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import net.kyori.adventure.title.Title;
import net.kyori.adventure.title.Title.Times;
import net.kyori.adventure.title.TitlePart;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.BaseComponent;
import net.querz.nbt.tag.CompoundTag;
import net.querz.nbt.tag.ListTag;
import net.querz.nbt.tag.StringTag;

import java.io.IOException;
import java.time.Duration;
Expand All @@ -82,7 +89,7 @@
import java.util.concurrent.atomic.AtomicInteger;

public class Player extends LivingEntity implements CommandSender, InventoryHolder {

public static final String CHAT_DEFAULT_FORMAT = "<%name%> %message%";

public final ClientConnection clientConnection;
Expand All @@ -95,20 +102,20 @@ public class Player extends LivingEntity implements CommandSender, InventoryHold
protected final PlayerInventory playerInventory;
protected final InventoryView inventoryView;
private final AtomicInteger containerIdCounter;
@WatchableField(MetadataIndex = 15, WatchableObjectType = WatchableObjectType.FLOAT)

@WatchableField(MetadataIndex = 15, WatchableObjectType = WatchableObjectType.FLOAT)
protected float additionalHearts = 0.0F;
@WatchableField(MetadataIndex = 16, WatchableObjectType = WatchableObjectType.VARINT)
@WatchableField(MetadataIndex = 16, WatchableObjectType = WatchableObjectType.VARINT)
protected int score = 0;
@WatchableField(MetadataIndex = 17, WatchableObjectType = WatchableObjectType.BYTE)
@WatchableField(MetadataIndex = 17, WatchableObjectType = WatchableObjectType.BYTE)
protected byte skinLayers = 0;
@WatchableField(MetadataIndex = 18, WatchableObjectType = WatchableObjectType.BYTE)
@WatchableField(MetadataIndex = 18, WatchableObjectType = WatchableObjectType.BYTE)
protected byte mainHand = 1;
//@WatchableField(MetadataIndex = 19, WatchableObjectType = WatchableObjectType.NBT)
//@WatchableField(MetadataIndex = 19, WatchableObjectType = WatchableObjectType.NBT)
//protected Entity leftShoulder = null;
//@WatchableField(MetadataIndex = 20, WatchableObjectType = WatchableObjectType.NBT)
//@WatchableField(MetadataIndex = 20, WatchableObjectType = WatchableObjectType.NBT)
//protected Entity rightShoulder = null;

public Player(ClientConnection clientConnection, String username, UUID uuid, int entityId, Location location, PlayerInteractManager playerInteractManager) throws IllegalArgumentException, IllegalAccessException {
super(EntityType.PLAYER, entityId, uuid, location.getWorld(), location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
this.clientConnection = clientConnection;
Expand Down Expand Up @@ -159,7 +166,7 @@ public void setGamemode(GameMode gamemode) {
}
this.gamemode = gamemode;
}

@Deprecated
protected void setEntityId(int entityId) {
this.entityId = entityId;
Expand Down Expand Up @@ -196,20 +203,20 @@ public byte getMainHand() {
public void setMainHand(byte mainHand) {
this.mainHand = mainHand;
}

@Override
public DataWatcher getDataWatcher() {
return watcher;
}

@Override
public boolean isValid() {
return Limbo.getInstance().getPlayers().contains(this);
}

@Override
public void remove() {

}

/*
Expand All @@ -234,7 +241,7 @@ public void setRightShoulder(Entity rightShoulder) {
public String getName() {
return username;
}

@Override
public boolean hasPermission(String permission) {
return Limbo.getInstance().getPermissionsManager().hasPermission(this, permission);
Expand All @@ -256,7 +263,7 @@ public void teleport(Location location) {
} catch (IOException e) {}
}
}

protected void setLocation(Location location) {
super.teleport(location);
}
Expand All @@ -269,7 +276,7 @@ public void sendPluginMessage(Key channel, byte[] data) throws IOException {
public void sendPluginMessage(String channel, byte[] data) throws IOException {
clientConnection.sendPluginMessage(channel, data);
}

public void sendMessage(String message, UUID uuid) {
sendMessage(Identity.identity(uuid), LegacyComponentSerializer.legacySection().deserialize(message));
}
Expand All @@ -284,7 +291,7 @@ public void sendMessage(BaseComponent component, UUID uuid) {
public void sendMessage(BaseComponent[] component, UUID uuid) {
sendMessage(Identity.identity(uuid), BungeecordAdventureConversionUtils.toComponent(component));
}

public void sendMessage(String message) {
sendMessage(LegacyComponentSerializer.legacySection().deserialize(message));
}
Expand All @@ -299,37 +306,37 @@ public void sendMessage(BaseComponent component) {
public void sendMessage(BaseComponent[] component) {
sendMessage(BungeecordAdventureConversionUtils.toComponent(component));
}

public void disconnect() {
disconnect(Component.translatable("multiplayer.disconnect.kicked"));
}

public void disconnect(String reason) {
disconnect(LegacyComponentSerializer.legacySection().deserialize(reason));
}

public void disconnect(Component reason) {
clientConnection.disconnect(reason);
}

@Deprecated
public void disconnect(BaseComponent reason) {
disconnect(new BaseComponent[] {reason});
}

@Deprecated
public void disconnect(BaseComponent[] reason) {
disconnect(BungeecordAdventureConversionUtils.toComponent(reason));
}

public void chat(String message) {
chat(message, false);
}

public void chat(String message, boolean verbose) {
chat(message, verbose, null, Instant.now());
}

public void chat(String message, boolean verbose, MessageSignature saltSignature, Instant time) {
if (Limbo.getInstance().getServerProperties().isAllowChat()) {
PlayerChatEvent event = Limbo.getInstance().getEventsManager().callEvent(new PlayerChatEvent(this, CHAT_DEFAULT_FORMAT, message, false));
Expand All @@ -352,11 +359,11 @@ public void chat(String message, boolean verbose, MessageSignature saltSignature
}
}
}

public void setResourcePack(String url, String hash, boolean forced) {
setResourcePack(url, hash, forced, (BaseComponent[]) null);
}

@Deprecated
public void setResourcePack(String url, String hash, boolean forced, BaseComponent promptmessage) {
setResourcePack(url, hash, forced, promptmessage == null ? null : new BaseComponent[] {promptmessage});
Expand All @@ -366,7 +373,7 @@ public void setResourcePack(String url, String hash, boolean forced, BaseCompone
public void setResourcePack(String url, String hash, boolean forced, BaseComponent[] promptmessage) {
setResourcePack(url, hash, forced, promptmessage == null ? null : BungeecordAdventureConversionUtils.toComponent(promptmessage));
}

public void setResourcePack(String url, String hash, boolean forced, Component promptmessage) {
try {
PacketPlayOutResourcePackSend packsend = new PacketPlayOutResourcePackSend(url, hash, forced, promptmessage != null, promptmessage);
Expand All @@ -375,7 +382,7 @@ public void setResourcePack(String url, String hash, boolean forced, Component p
e.printStackTrace();
}
}

@Deprecated
public void setPlayerListHeaderFooter(BaseComponent[] header, BaseComponent[] footer) {
sendPlayerListHeaderAndFooter(header == null ? Component.empty() : BungeecordAdventureConversionUtils.toComponent(header), footer == null ? Component.empty() : BungeecordAdventureConversionUtils.toComponent(footer));
Expand All @@ -385,55 +392,55 @@ public void setPlayerListHeaderFooter(BaseComponent[] header, BaseComponent[] fo
public void setPlayerListHeaderFooter(BaseComponent header, BaseComponent footer) {
sendPlayerListHeaderAndFooter(header == null ? Component.empty() : BungeecordAdventureConversionUtils.toComponent(header), footer == null ? Component.empty() : BungeecordAdventureConversionUtils.toComponent(footer));
}

public void setPlayerListHeaderFooter(String header, String footer) {
sendPlayerListHeaderAndFooter(header == null ? Component.empty() : LegacyComponentSerializer.legacySection().deserialize(header), footer == null ? Component.empty() : LegacyComponentSerializer.legacySection().deserialize(footer));
}

@Deprecated
public void setTitle(BaseComponent[] title) {
sendTitlePart(TitlePart.TITLE, BungeecordAdventureConversionUtils.toComponent(title));
}

@Deprecated
public void setTitle(BaseComponent title) {
sendTitlePart(TitlePart.TITLE, BungeecordAdventureConversionUtils.toComponent(title));
}

public void setTitle(String title) {
sendTitlePart(TitlePart.TITLE, LegacyComponentSerializer.legacySection().deserialize(title));
}

@Deprecated
public void setSubTitle(BaseComponent[] subTitle) {
sendTitlePart(TitlePart.SUBTITLE, BungeecordAdventureConversionUtils.toComponent(subTitle));
}

@Deprecated
public void setSubTitle(BaseComponent subTitle) {
sendTitlePart(TitlePart.SUBTITLE, BungeecordAdventureConversionUtils.toComponent(subTitle));
}

public void setSubTitle(String subTitle) {
sendTitlePart(TitlePart.SUBTITLE, LegacyComponentSerializer.legacySection().deserialize(subTitle));
}

public void setTitleTimer(int fadeIn, int stay, int fadeOut) {
sendTitlePart(TitlePart.TIMES, Title.Times.times(Duration.ofMillis(fadeIn * 50), Duration.ofMillis(stay * 50), Duration.ofMillis(fadeOut * 50)));
}

@Deprecated
public void setTitleSubTitle(BaseComponent[] title, BaseComponent[] subTitle, int fadeIn, int stay, int fadeOut) {
setTitleTimer(fadeIn, stay, fadeOut);
setTitle(title);
setSubTitle(subTitle);
}

@Deprecated
public void setTitleSubTitle(BaseComponent title, BaseComponent subTitle, int fadeIn, int stay, int fadeOut) {
setTitleSubTitle(new BaseComponent[] {title}, new BaseComponent[] {subTitle}, fadeIn, stay, fadeOut);
}

public void setTitleSubTitle(String title, String subTitle, int fadeIn, int stay, int fadeOut) {
sendTitlePart(TitlePart.TIMES, Title.Times.times(Duration.ofMillis(fadeIn * 50), Duration.ofMillis(stay * 50), Duration.ofMillis(fadeOut * 50)));
sendTitlePart(TitlePart.SUBTITLE, LegacyComponentSerializer.legacySection().deserialize(subTitle));
Expand Down Expand Up @@ -469,7 +476,34 @@ public void sendMessage(Identity source, Component message, MessageType type, Me

@Override
public void openBook(Book book) {
throw new UnsupportedOperationException("This function has not been implemented yet.");
ItemStack item = new ItemStack(Key.key("minecraft:written_book"));
CompoundTag nbt = new CompoundTag();
nbt.putString("title", PlainTextComponentSerializer.plainText().serialize(book.title()));
nbt.putString("author", PlainTextComponentSerializer.plainText().serialize(book.author()));
ListTag<StringTag> pages = new ListTag<>(StringTag.class);
for (Component page : book.pages()) {
pages.add(new StringTag(PlainTextComponentSerializer.plainText().serialize(page)));
}
nbt.put("pages", pages);
item.nbt(nbt);
PacketPlayOutSetSlot setSlot = new PacketPlayOutSetSlot(0, 0,0, item);
try {
clientConnection.sendPacket(setSlot);
} catch (IOException e) {
e.printStackTrace();
}
ClientboundOpenBookPacket openBook = new ClientboundOpenBookPacket(0);
try {
clientConnection.sendPacket(openBook);
} catch (IOException e) {
e.printStackTrace();
}
PacketPlayOutSetSlot resetSlot = new PacketPlayOutSetSlot(0, 0,0, getInventory().getItemInMainHand());
try {
clientConnection.sendPacket(resetSlot);
} catch (IOException e) {
e.printStackTrace();
}
}

@Override
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/mapping.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
"PacketPlayOutStopSound": "0x5F",
"PacketPlayOutWindowItems": "0x10",
"PacketPlayOutSetSlot": "0x12",
"ClientboundOpenBookPacket": "0x2B",
"PacketPlayOutOpenWindow": "0x2C",
"PacketPlayOutCloseWindow": "0x0F",
"PacketPlayOutWindowData": "0x11"
Expand Down