From af85b6071cc5b68dc41d2c3ded646324418166a7 Mon Sep 17 00:00:00 2001
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
Date: Sat, 12 Nov 2022 12:41:22 -0500
Subject: [PATCH] Cleanup reputation API + back with an EnumMap instead of
 array (#8258)

Resolves: #7142
---
 patches/api/Add-villager-reputation-API.patch | 35 ++++++-----
 .../server/Add-villager-reputation-API.patch  | 60 +++++++++----------
 2 files changed, 49 insertions(+), 46 deletions(-)

diff --git a/patches/api/Add-villager-reputation-API.patch b/patches/api/Add-villager-reputation-API.patch
index 6eb59f4313..70828a1a04 100644
--- a/patches/api/Add-villager-reputation-API.patch
+++ b/patches/api/Add-villager-reputation-API.patch
@@ -13,6 +13,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +package com.destroystokyo.paper.entity.villager;
 +
 +import com.google.common.base.Preconditions;
++
++import java.util.EnumMap;
 +import java.util.Map;
 +import org.jetbrains.annotations.NotNull;
 +
@@ -20,26 +22,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 + * A reputation score for a player on a villager.
 + */
 +public final class Reputation {
-+    private static final ReputationType[] REPUTATION_TYPES = ReputationType.values(); // Avoid allocation
++
 +    @NotNull
-+    private final int[] reputation;
++    private final Map<ReputationType, Integer> reputation;
 +
 +    public Reputation() {
-+        this(new int[REPUTATION_TYPES.length]);
++        this(new EnumMap<>(ReputationType.class));
 +    }
 +
-+    // Package level to avoid plugins creating reputations with "magic values".
-+    Reputation(@NotNull int[] reputation) {
-+        this.reputation = reputation;
-+    }
-+
-+    public Reputation(@NotNull final Map<ReputationType, Integer> reputation) {
-+        this();
++    public Reputation(@NotNull Map<ReputationType, Integer> reputation) {
 +        Preconditions.checkNotNull(reputation, "reputation cannot be null");
-+
-+        for (Map.Entry<ReputationType, Integer> entry : reputation.entrySet()) {
-+            setReputation(entry.getKey(), entry.getValue());
-+        }
++        this.reputation = reputation;
 +    }
 +
 +    /**
@@ -50,7 +43,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +     */
 +    public int getReputation(@NotNull ReputationType type) {
 +        Preconditions.checkNotNull(type, "the reputation type cannot be null");
-+        return reputation[type.ordinal()];
++        return this.reputation.getOrDefault(type, 0);
 +    }
 +
 +    /**
@@ -61,7 +54,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +     */
 +    public void setReputation(@NotNull ReputationType type, int value) {
 +        Preconditions.checkNotNull(type, "the reputation type cannot be null");
-+        reputation[type.ordinal()] = value;
++        this.reputation.put(type, value);
++    }
++
++    /**
++     * Gets if a reputation value is currently set for a specific {@link ReputationType}.
++     *
++     * @param type The {@link ReputationType type} to check
++     * @return If there is a value for this {@link ReputationType type} set.
++     */
++    public boolean hasReputationSet(@NotNull ReputationType type) {
++        return this.reputation.containsKey(type);
 +    }
 +}
 diff --git a/src/main/java/com/destroystokyo/paper/entity/villager/ReputationType.java b/src/main/java/com/destroystokyo/paper/entity/villager/ReputationType.java
diff --git a/patches/server/Add-villager-reputation-API.patch b/patches/server/Add-villager-reputation-API.patch
index 4e416025bb..3f28e0020d 100644
--- a/patches/server/Add-villager-reputation-API.patch
+++ b/patches/server/Add-villager-reputation-API.patch
@@ -4,21 +4,6 @@ Date: Wed, 22 Apr 2020 23:29:20 +0200
 Subject: [PATCH] Add villager reputation API
 
 
-diff --git a/src/main/java/com/destroystokyo/paper/entity/villager/ReputationConstructor.java b/src/main/java/com/destroystokyo/paper/entity/villager/ReputationConstructor.java
-new file mode 100644
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
---- /dev/null
-+++ b/src/main/java/com/destroystokyo/paper/entity/villager/ReputationConstructor.java
-@@ -0,0 +0,0 @@
-+package com.destroystokyo.paper.entity.villager;
-+// Must have own package due to package-level constructor.
-+
-+public final class ReputationConstructor {
-+    // Abuse the package-level constructor.
-+    public static Reputation construct(int[] values) {
-+        return new Reputation(values);
-+    }
-+}
 diff --git a/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java b/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java
@@ -38,24 +23,39 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
          }
 +
 +        // Paper start - Add villager reputation API
-+        private static final com.destroystokyo.paper.entity.villager.ReputationType[] REPUTATION_TYPES = com.destroystokyo.paper.entity.villager.ReputationType.values();
++        private static final GossipType[] TYPES = GossipType.values();
 +        public com.destroystokyo.paper.entity.villager.Reputation getPaperReputation() {
-+            int[] reputation = new int[REPUTATION_TYPES.length];
-+            reputation[com.destroystokyo.paper.entity.villager.ReputationType.MAJOR_NEGATIVE.ordinal()] = entries.getOrDefault(GossipType.MAJOR_NEGATIVE, 0);
-+            reputation[com.destroystokyo.paper.entity.villager.ReputationType.MAJOR_POSITIVE.ordinal()] = entries.getOrDefault(GossipType.MAJOR_POSITIVE, 0);
-+            reputation[com.destroystokyo.paper.entity.villager.ReputationType.MINOR_NEGATIVE.ordinal()] = entries.getOrDefault(GossipType.MINOR_NEGATIVE, 0);
-+            reputation[com.destroystokyo.paper.entity.villager.ReputationType.MINOR_POSITIVE.ordinal()] = entries.getOrDefault(GossipType.MINOR_POSITIVE, 0);
-+            reputation[com.destroystokyo.paper.entity.villager.ReputationType.TRADING.ordinal()] = entries.getOrDefault(GossipType.TRADING, 0);
-+            return com.destroystokyo.paper.entity.villager.ReputationConstructor.construct(reputation);
++            Map<com.destroystokyo.paper.entity.villager.ReputationType, Integer> map = new java.util.EnumMap<>(com.destroystokyo.paper.entity.villager.ReputationType.class);
++            for (Object2IntMap.Entry<GossipType> type : this.entries.object2IntEntrySet()) {
++                map.put(toApi(type.getKey()), type.getIntValue());
++            }
++
++            return new com.destroystokyo.paper.entity.villager.Reputation(map);
 +        }
 +
 +        public void assignFromPaperReputation(com.destroystokyo.paper.entity.villager.Reputation rep) {
-+            int val;
-+            if ((val = rep.getReputation(com.destroystokyo.paper.entity.villager.ReputationType.MAJOR_NEGATIVE)) != 0) this.entries.put(GossipType.MAJOR_NEGATIVE, val);
-+            if ((val = rep.getReputation(com.destroystokyo.paper.entity.villager.ReputationType.MAJOR_POSITIVE)) != 0) this.entries.put(GossipType.MAJOR_POSITIVE, val);
-+            if ((val = rep.getReputation(com.destroystokyo.paper.entity.villager.ReputationType.MINOR_NEGATIVE)) != 0) this.entries.put(GossipType.MINOR_NEGATIVE, val);
-+            if ((val = rep.getReputation(com.destroystokyo.paper.entity.villager.ReputationType.MINOR_POSITIVE)) != 0) this.entries.put(GossipType.MINOR_POSITIVE, val);
-+            if ((val = rep.getReputation(com.destroystokyo.paper.entity.villager.ReputationType.TRADING)) != 0) this.entries.put(GossipType.TRADING, val);
++            for (GossipType type : TYPES) {
++                com.destroystokyo.paper.entity.villager.ReputationType api = toApi(type);
++
++                if (rep.hasReputationSet(api)) {
++                    int reputation = rep.getReputation(api);
++                    if (reputation == 0) {
++                        this.entries.removeInt(type);
++                    } else {
++                        this.entries.put(type, reputation);
++                    }
++                }
++            }
++        }
++
++        private static com.destroystokyo.paper.entity.villager.ReputationType toApi(GossipType type) {
++            return switch (type) {
++                case MAJOR_NEGATIVE -> com.destroystokyo.paper.entity.villager.ReputationType.MAJOR_NEGATIVE;
++                case MINOR_NEGATIVE -> com.destroystokyo.paper.entity.villager.ReputationType.MINOR_NEGATIVE;
++                case MINOR_POSITIVE -> com.destroystokyo.paper.entity.villager.ReputationType.MINOR_POSITIVE;
++                case MAJOR_POSITIVE -> com.destroystokyo.paper.entity.villager.ReputationType.MAJOR_POSITIVE;
++                case TRADING -> com.destroystokyo.paper.entity.villager.ReputationType.TRADING;
++            };
 +        }
 +        // Paper end
      }
@@ -89,7 +89,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +    public Reputation getReputation(UUID uniqueId) {
 +        net.minecraft.world.entity.ai.gossip.GossipContainer.EntityGossips rep = getHandle().getGossips().getReputations().get(uniqueId);
 +        if (rep == null) {
-+            return new Reputation(Maps.newHashMap());
++            return new Reputation(new java.util.EnumMap<>(com.destroystokyo.paper.entity.villager.ReputationType.class));
 +        }
 +
 +        return rep.getPaperReputation();