SPIGOT-5784, SPIGOT-6858, #1089: Add villager reputation API

This commit is contained in:
Mikołaj Nowak 2024-12-31 11:30:43 +11:00 committed by md_5
parent 23029a34a0
commit ab74003f43
No known key found for this signature in database
GPG key ID: E8E901AC7C617C11
3 changed files with 417 additions and 0 deletions

View file

@ -10,6 +10,7 @@ import org.bukkit.damage.DamageEffect;
import org.bukkit.damage.DamageSource;
import org.bukkit.damage.DamageType;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Villager;
import org.bukkit.inventory.CreativeCategory;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
@ -137,4 +138,10 @@ public interface UnsafeValues {
@ApiStatus.Internal
Biome getCustomBiome();
@ApiStatus.Internal
Villager.ReputationType createReputationType(String key);
@ApiStatus.Internal
Villager.ReputationEvent createReputationEvent(String key);
}

View file

@ -3,6 +3,8 @@ package org.bukkit.entity;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import java.util.Locale;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.Keyed;
import org.bukkit.Location;
import org.bukkit.NamespacedKey;
@ -118,6 +120,169 @@ public interface Villager extends AbstractVillager {
@Nullable
public ZombieVillager zombify();
/**
* Gets the reputation of an entity for a given type.
*
* @param uuid the UUID of the entity whose reputation is being checked
* @param reputationType reputation type to be retrieved
* @return current reputation for the given reputation type
*/
public int getReputation(@NotNull UUID uuid, @NotNull ReputationType reputationType);
/**
* Gets the weighted reputation of an entity for a given type.
*
* <p>The total reputation of an entity is a sum of its weighted
* reputations of each type, where the reputation is multiplied by weight
* assigned to its type.
*
* @param uuid the UUID of the entity whose reputation is being checked
* @param reputationType reputation type to be retrieved
* @return current reputation for the given reputation type
* @see ReputationType#getWeight()
*/
public int getWeightedReputation(@NotNull UUID uuid, @NotNull ReputationType reputationType);
/**
* Gets the reputation of an entity.
*
* @param uuid the UUID of the entity whose reputation is being checked
* @return current reputation for the given reputation type
*/
public int getReputation(@NotNull UUID uuid);
/**
* Add reputation of a given type towards a given entity.
*
* <p>The final value will be clamped to the maximum value supported by the
* provided reputation type. If the final value is below the reputation
* discard threshold, gossip associated with this reputation type will be
* removed.
*
* <p>Note: this will fire a
* {@link org.bukkit.event.entity.VillagerReputationChangeEvent}.
*
* @param uuid the UUID of the entity for whom the reputation is being
* added
* @param reputationType reputation type to be modified
* @param amount amount of reputation to add
*/
public void addReputation(@NotNull UUID uuid, @NotNull ReputationType reputationType, int amount);
/**
* Add reputation of a given type towards a given entity, with a specific
* change reason.
*
* <p>The final value will be clamped to the maximum value supported by the
* provided reputation type. If the final value is below the reputation
* discard threshold, gossip associated with this reputation type will be
* removed.
*
* <p>Note: this will fire a
* {@link org.bukkit.event.entity.VillagerReputationChangeEvent}.
*
* @param uuid the UUID of the entity for whom the reputation is being
* added
* @param reputationType reputation type to be modified
* @param amount amount of reputation to add
* @param changeReason reputation change reason
*/
public void addReputation(@NotNull UUID uuid, @NotNull ReputationType reputationType, int amount, @NotNull ReputationEvent changeReason);
/**
* Remove reputation of a given type towards a given entity.
*
* <p>The final value will be clamped to the maximum value supported by the
* provided reputation type. If the final value is below the reputation
* discard threshold, gossip associated with this reputation type will be
* removed.
*
* <p>Note: this will fire a
* {@link org.bukkit.event.entity.VillagerReputationChangeEvent}.
*
* @param uuid the UUID of the entity for whom the reputation is being
* removed
* @param reputationType reputation type to be modified
* @param amount amount of reputation to remove
*/
public void removeReputation(@NotNull UUID uuid, @NotNull ReputationType reputationType, int amount);
/**
* Remove reputation of a given type towards a given entity, with a
* specific change reason.
*
* <p>The final value will be clamped to the maximum value supported by the
* provided reputation type. If the final value is below the reputation
* discard threshold, gossip associated with this reputation type will be
* removed.
*
* <p>Note: this will fire a
* {@link org.bukkit.event.entity.VillagerReputationChangeEvent}.
*
* @param uuid the UUID of the entity for whom the reputation is being
* removed
* @param reputationType reputation type to be modified
* @param amount amount of reputation to remove
* @param changeReason reputation change reason
*/
public void removeReputation(@NotNull UUID uuid, @NotNull ReputationType reputationType, int amount, @NotNull ReputationEvent changeReason);
/**
* Set reputation of a given type towards a given entity.
*
* <p>The final value will be clamped to the maximum value supported by the
* provided reputation type. If the final value is below the reputation
* discard threshold, gossip associated with this reputation type will be
* removed.
*
* <p>Note: this will fire a
* {@link org.bukkit.event.entity.VillagerReputationChangeEvent}.
*
* @param uuid the UUID of the entity for whom the reputation is being
* added
* @param reputationType reputation type to be modified
* @param amount amount of reputation to add
*/
public void setReputation(@NotNull UUID uuid, @NotNull ReputationType reputationType, int amount);
/**
* Set reputation of a given type towards a given entity, with a specific
* change reason.
*
* <p>The final value will be clamped to the maximum value supported by the
* provided reputation type. If the final value is below the reputation
* discard threshold, gossip associated with this reputation type will be
* removed.
*
* <p>Note: this will fire a
* {@link org.bukkit.event.entity.VillagerReputationChangeEvent}.
*
* @param uuid the UUID of the entity for whom the reputation is being
* added
* @param reputationType reputation type to be modified
* @param amount amount of reputation to add
* @param changeReason reputation change reason
*/
public void setReputation(@NotNull UUID uuid, @NotNull ReputationType reputationType, int amount, @NotNull ReputationEvent changeReason);
/**
* Sets the reputation decay time for this villager.
*
* <p>Defaults to <b>24000</b> (1 daylight cycle).
*
* @param ticks amount of ticks until the villager's reputation decays
*/
public void setGossipDecayTime(long ticks);
/**
* Gets the reputation decay time for this villager.
*
* <p>Defaults to <b>24000</b> (1 daylight cycle).
*
* @return amount of ticks until the villager's reputation decays
*/
public long getGossipDecayTime();
/**
* Represents Villager type, usually corresponding to what biome they spawn
* in.
@ -267,4 +432,97 @@ public interface Villager extends AbstractVillager {
return Lists.newArrayList(Registry.VILLAGER_PROFESSION).toArray(new Profession[0]);
}
}
/**
* Reputation type used in gossips.
*/
interface ReputationType {
/**
* Major negative reputation. It is caused by killing a villager.
*/
ReputationType MAJOR_NEGATIVE = getReputationType("major_negative");
/**
* Minor negative reputation. It is caused by attacking a villager.
*/
ReputationType MINOR_NEGATIVE = getReputationType("minor_negative");
/**
* Minor positive reputation. It is caused by curing a villager.
*/
ReputationType MINOR_POSITIVE = getReputationType("minor_positive");
/**
* Major positive reputation. It is caused by curing a villager, it is
* never shared in gossip and never decays.
*/
ReputationType MAJOR_POSITIVE = getReputationType("major_positive");
/**
* Trading reputation. It has the same weight as minor positive
* reputation and is caused by trading with a villager.
*/
ReputationType TRADING = getReputationType("trading");
/**
* Get maximum reputation value of this type.
* @return maximum value of this reputation type
*/
int getMaxValue();
/**
* Get weight of this reputation type.
*
* <p>When calculating total reputation of an entity, reputation of
* each type is multiplied by its weight.
*
* @return weight assigned to this reputation type
*/
int getWeight();
private static ReputationType getReputationType(String key) {
return Bukkit.getUnsafe().createReputationType(key);
}
}
/**
* Reputation change reason.
*/
interface ReputationEvent {
/**
* A villager was cured by a player.
*/
ReputationEvent ZOMBIE_VILLAGER_CURED = getReputationEvent("zombie_villager_cured");
/**
* A player traded with a villager.
*/
ReputationEvent TRADE = getReputationEvent("trade");
/**
* A villager was hurt by an entity.
*/
ReputationEvent VILLAGER_HURT = getReputationEvent("villager_hurt");
/**
* A villager was killed by an entity.
*/
ReputationEvent VILLAGER_KILLED = getReputationEvent("villager_killed");
/**
* A villager gossiped with another villager.
*/
ReputationEvent GOSSIP = getReputationEvent("bukkit_gossip");
/**
* Reputation decayed over time.
*/
ReputationEvent DECAY = getReputationEvent("bukkit_decay");
/**
* Village's iron golem was killed by an entity.
*/
ReputationEvent GOLEM_KILLED = getReputationEvent("golem_killed");
/**
* Unspecified reason. Available only by setting the reputation
* programmatically.
*/
ReputationEvent UNSPECIFIED = getReputationEvent("bukkit_unspecified");
private static ReputationEvent getReputationEvent(String key) {
return Bukkit.getUnsafe().createReputationEvent(key);
}
}
}

View file

@ -0,0 +1,152 @@
package org.bukkit.event.entity;
import com.google.common.base.Preconditions;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Villager;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Called whenever an entity's reputation with a villager changes.
*/
public class VillagerReputationChangeEvent extends EntityEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean cancelled;
private final UUID targetUUID;
private final Villager.ReputationEvent reason;
private final Villager.ReputationType reputationType;
private final int oldValue;
private int newValue;
private final int maxValue;
public VillagerReputationChangeEvent(@NotNull Villager villager, @NotNull UUID targetUUID, @NotNull Villager.ReputationEvent reason, @NotNull Villager.ReputationType reputationType, int oldValue, int newValue, int maxValue) {
super(villager);
this.targetUUID = targetUUID;
this.reason = reason;
this.reputationType = reputationType;
this.oldValue = oldValue;
this.newValue = newValue;
this.maxValue = maxValue;
}
/**
* Get UUID of the entity for whom the reputation with a villager changes.
*
* @return UUID of the entity for whom the reputation with a villager
* changes
*/
@NotNull
public UUID getTargetUUID() {
return targetUUID;
}
/**
* Get the Entity for whom the reputation with a villager changes.
*
* @return the Entity for whom the reputation with a villager changes,
* or {@code null} if it isn't found
*/
@Nullable
public Entity getTarget() {
return Bukkit.getEntity(targetUUID);
}
/**
* Get the reason of this reputation change.
*
* @return the reason of this reputation change
*/
@NotNull
public Villager.ReputationEvent getReason() {
return reason;
}
/**
* Get the type of changed reputation.
*
* @return the type of changed reputation
*/
@NotNull
public Villager.ReputationType getReputationType() {
return reputationType;
}
/**
* Get the reputation value before the change.
*
* @return the reputation value before the change
*/
public int getOldValue() {
return oldValue;
}
/**
* Get new reputation value after the change.
*
* @return the reputation value after the change
*/
public int getNewValue() {
return newValue;
}
/**
* Set new reputation value for this event.
*
* <p>If the final value is below the reputation discard threshold, gossip
* associated with this reputation type will be removed.
*
* <p>The provided value must be between 0 and
* {@link VillagerReputationChangeEvent#getMaxValue()}, otherwise an
* {@link IllegalArgumentException} will be thrown. Each reputation type
* may have a different maximum value.
*
* @param newValue the reputation value after the change
* @see Villager.ReputationType#getMaxValue()
*/
public void setNewValue(int newValue) {
Preconditions.checkArgument(0 <= newValue && newValue <= maxValue, "new value (%s) must be between [0, %s]", newValue, maxValue);
this.newValue = newValue;
}
/**
* Get maximum value for the reputation type affected by this event.
*
* @return the maximum value for the reputation type affected by this event
* @see Villager.ReputationType#getMaxValue()
*/
public int getMaxValue() {
return maxValue;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
cancelled = cancel;
}
@NotNull
@Override
public Villager getEntity() {
return (Villager) super.getEntity();
}
@NotNull
@Override
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
}