From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: MiniDigger | Martin <admin@minidigger.dev>
Date: Mon, 20 Jan 2020 21:38:15 +0100
Subject: [PATCH] Implement Player Client Options API


diff --git a/src/main/java/com/destroystokyo/paper/PaperSkinParts.java b/src/main/java/com/destroystokyo/paper/PaperSkinParts.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/PaperSkinParts.java
@@ -0,0 +0,0 @@
+package com.destroystokyo.paper;
+
+import com.google.common.base.Objects;
+
+import java.util.StringJoiner;
+
+public class PaperSkinParts implements SkinParts {
+
+    private final int raw;
+
+    public PaperSkinParts(int raw) {
+        this.raw = raw;
+    }
+
+    public boolean hasCapeEnabled() {
+        return (raw & 1) == 1;
+    }
+
+    public boolean hasJacketEnabled() {
+        return (raw >> 1 & 1) == 1;
+    }
+
+    public boolean hasLeftSleeveEnabled() {
+        return (raw >> 2 & 1) == 1;
+    }
+
+    public boolean hasRightSleeveEnabled() {
+        return (raw >> 3 & 1) == 1;
+    }
+
+    public boolean hasLeftPantsEnabled() {
+        return (raw >> 4 & 1) == 1;
+    }
+
+    public boolean hasRightPantsEnabled() {
+        return (raw >> 5 & 1) == 1;
+    }
+
+    public boolean hasHatsEnabled() {
+        return (raw >> 6 & 1) == 1;
+    }
+
+    @Override
+    public int getRaw() {
+        return raw;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        PaperSkinParts that = (PaperSkinParts) o;
+        return raw == that.raw;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(raw);
+    }
+
+    @Override
+    public String toString() {
+        return new StringJoiner(", ", PaperSkinParts.class.getSimpleName() + "[", "]")
+            .add("raw=" + raw)
+            .add("cape=" + hasCapeEnabled())
+            .add("jacket=" + hasJacketEnabled())
+            .add("leftSleeve=" + hasLeftSleeveEnabled())
+            .add("rightSleeve=" + hasRightSleeveEnabled())
+            .add("leftPants=" + hasLeftPantsEnabled())
+            .add("rightPants=" + hasRightPantsEnabled())
+            .add("hats=" + hasHatsEnabled())
+            .toString();
+    }
+}
diff --git a/src/main/java/net/minecraft/server/EntityHuman.java b/src/main/java/net/minecraft/server/EntityHuman.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/EntityHuman.java
+++ b/src/main/java/net/minecraft/server/EntityHuman.java
@@ -0,0 +0,0 @@ public abstract class EntityHuman extends EntityLiving {
     private static final Map<EntityPose, EntitySize> b = ImmutableMap.<EntityPose, EntitySize>builder().put(EntityPose.STANDING, EntityHuman.bo).put(EntityPose.SLEEPING, EntityHuman.ao).put(EntityPose.FALL_FLYING, EntitySize.b(0.6F, 0.6F)).put(EntityPose.SWIMMING, EntitySize.b(0.6F, 0.6F)).put(EntityPose.SPIN_ATTACK, EntitySize.b(0.6F, 0.6F)).put(EntityPose.CROUCHING, EntitySize.b(0.6F, 1.5F)).put(EntityPose.DYING, EntitySize.c(0.2F, 0.2F)).build();
     private static final DataWatcherObject<Float> c = DataWatcher.a(EntityHuman.class, DataWatcherRegistry.c);
     private static final DataWatcherObject<Integer> d = DataWatcher.a(EntityHuman.class, DataWatcherRegistry.b);
-    protected static final DataWatcherObject<Byte> bp = DataWatcher.a(EntityHuman.class, DataWatcherRegistry.a);
+    protected static final DataWatcherObject<Byte> bp = DataWatcher.a(EntityHuman.class, DataWatcherRegistry.a); public static DataWatcherObject<Byte> getSkinPartsWatcher() { return bp; } // Paper - OBFHELPER
     protected static final DataWatcherObject<Byte> bq = DataWatcher.a(EntityHuman.class, DataWatcherRegistry.a);
     protected static final DataWatcherObject<NBTTagCompound> br = DataWatcher.a(EntityHuman.class, DataWatcherRegistry.p);
     protected static final DataWatcherObject<NBTTagCompound> bs = DataWatcher.a(EntityHuman.class, DataWatcherRegistry.p);
diff --git a/src/main/java/net/minecraft/server/EntityPlayer.java b/src/main/java/net/minecraft/server/EntityPlayer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/EntityPlayer.java
+++ b/src/main/java/net/minecraft/server/EntityPlayer.java
@@ -0,0 +0,0 @@ package net.minecraft.server;
 
 import com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent;
 import com.google.common.collect.Lists;
+import com.destroystokyo.paper.event.player.PlayerClientOptionsChangeEvent; // Paper
 import com.mojang.authlib.GameProfile;
 import com.mojang.datafixers.util.Either;
 import com.mojang.serialization.DataResult;
@@ -0,0 +0,0 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
     public int lastSentExp = -99999999;
     public int invulnerableTicks = 60;
     private EnumChatVisibility cf;
-    private boolean cg = true;
+    private boolean cg = true; public boolean hasChatColorsEnabled() { return this.cg; } // Paper - OBFHELPER
     private long ch = SystemUtils.getMonotonicMillis();
     private Entity spectatedEntity;
     public boolean worldChangeInvuln;
@@ -0,0 +0,0 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
 
     public String locale = null; // CraftBukkit - lowercase // Paper - default to null
     public void a(PacketPlayInSettings packetplayinsettings) {
+        new PlayerClientOptionsChangeEvent(getBukkitEntity(), packetplayinsettings.getLocale(), packetplayinsettings.viewDistance, com.destroystokyo.paper.ClientOption.ChatVisibility.valueOf(packetplayinsettings.getChatVisibility().name()), packetplayinsettings.hasChatColorsEnabled(), new com.destroystokyo.paper.PaperSkinParts(packetplayinsettings.getSkinParts()), packetplayinsettings.getMainHand() == EnumMainHand.LEFT ? MainHand.LEFT : MainHand.RIGHT).callEvent(); // Paper - settings event
         // CraftBukkit start
         if (getMainHand() != packetplayinsettings.getMainHand()) {
             PlayerChangedMainHandEvent event = new PlayerChangedMainHandEvent(getBukkitEntity(), getMainHand() == EnumMainHand.LEFT ? MainHand.LEFT : MainHand.RIGHT);
diff --git a/src/main/java/net/minecraft/server/PacketPlayInSettings.java b/src/main/java/net/minecraft/server/PacketPlayInSettings.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/PacketPlayInSettings.java
+++ b/src/main/java/net/minecraft/server/PacketPlayInSettings.java
@@ -0,0 +0,0 @@ import java.io.IOException;
 
 public class PacketPlayInSettings implements Packet<PacketListenerPlayIn> {
 
-    public String locale;
+    public String locale; public String getLocale() { return this.locale; } // Paper - OBFHELPER
     public int viewDistance;
     private EnumChatVisibility c;
     private boolean d;
@@ -0,0 +0,0 @@ public class PacketPlayInSettings implements Packet<PacketListenerPlayIn> {
         packetlistenerplayin.a(this);
     }
 
+    public EnumChatVisibility getChatVisibility() { return d(); } // Paper - OBFHELPER
     public EnumChatVisibility d() {
         return this.c;
     }
 
+    public boolean hasChatColorsEnabled() { return e(); } // Paper - OBFHELPER
     public boolean e() {
         return this.d;
     }
 
+    public int getSkinParts() { return f(); } // Paper - OBFHELPER
     public int f() {
         return this.e;
     }
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -0,0 +0,0 @@
 package org.bukkit.craftbukkit.entity;
 
+import com.destroystokyo.paper.ClientOption.ChatVisibility;
+import com.destroystokyo.paper.PaperSkinParts;
+import com.destroystokyo.paper.ClientOption;
 import com.destroystokyo.paper.Title;
 import com.destroystokyo.paper.profile.CraftPlayerProfile;
 import com.destroystokyo.paper.profile.PlayerProfile;
@@ -0,0 +0,0 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
     public void setViewDistance(int viewDistance) {
         throw new NotImplementedException("Per-Player View Distance APIs need further understanding to properly implement (There are per world view distances though!)"); // TODO
     }
+
+    @Override
+    public <T> T getClientOption(ClientOption<T> type) {
+        if(ClientOption.SKIN_PARTS.equals(type)) {
+            return type.getType().cast(new PaperSkinParts(getHandle().getDataWatcher().get(EntityHuman.getSkinPartsWatcher())));
+        } else if(ClientOption.CHAT_COLORS_ENABLED.equals(type)) {
+            return type.getType().cast(getHandle().hasChatColorsEnabled());
+        } else if(ClientOption.CHAT_VISIBILITY.equals(type)) {
+            return type.getType().cast(getHandle().getChatFlags() == null ? ChatVisibility.UNKNOWN : ChatVisibility.valueOf(getHandle().getChatFlags().name()));
+        } else if(ClientOption.LOCALE.equals(type)) {
+            return type.getType().cast(getLocale());
+        } else if(ClientOption.MAIN_HAND.equals(type)) {
+            return type.getType().cast(getMainHand());
+        } else if(ClientOption.VIEW_DISTANCE.equals(type)) {
+            return type.getType().cast(getClientViewDistance());
+        }
+        throw new RuntimeException("Unknown settings type");
+    }
     // Paper end
 
     // Spigot start
