Skip to content

Commit

Permalink
Per-NPC Visibility Distance (#217)
Browse files Browse the repository at this point in the history
  • Loading branch information
Grabsky authored Jan 2, 2025
1 parent 78712e8 commit 63d7cb1
Show file tree
Hide file tree
Showing 9 changed files with 125 additions and 3 deletions.
9 changes: 6 additions & 3 deletions api/src/main/java/de/oliver/fancynpcs/api/Npc.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,11 @@ public void removeForAll() {
* @return True if the NPC should be visible for the player, otherwise false.
*/
protected boolean shouldBeVisible(Player player) {
int visibilityDistance = FancyNpcsPlugin.get().getFancyNpcConfig().getVisibilityDistance();
int visibilityDistance = (data.getVisibilityDistance() > -1) ? data.getVisibilityDistance() : FancyNpcsPlugin.get().getFancyNpcConfig().getVisibilityDistance();

if (visibilityDistance == 0) {
return false;
}

if (!data.isSpawnEntity()) {
return false;
Expand All @@ -88,8 +92,7 @@ protected boolean shouldBeVisible(Player player) {
return false;
}

double distanceSquared = data.getLocation().distanceSquared(player.getLocation());
if (distanceSquared > visibilityDistance * visibilityDistance) {
if (visibilityDistance != Integer.MAX_VALUE && data.getLocation().distanceSquared(player.getLocation()) > visibilityDistance * visibilityDistance) {
return false;
}

Expand Down
14 changes: 14 additions & 0 deletions api/src/main/java/de/oliver/fancynpcs/api/NpcData.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public class NpcData {
private boolean turnToPlayer;
private float interactionCooldown;
private float scale;
private int visibilityDistance;
private Map<NpcAttribute, String> attributes;
private boolean isDirty;

Expand All @@ -60,6 +61,7 @@ public NpcData(
Map<ActionTrigger, List<NpcAction.NpcActionData>> actions,
float interactionCooldown,
float scale,
int visibilityDistance,
Map<NpcAttribute, String> attributes,
boolean mirrorSkin
) {
Expand All @@ -81,6 +83,7 @@ public NpcData(
this.turnToPlayer = turnToPlayer;
this.interactionCooldown = interactionCooldown;
this.scale = scale;
this.visibilityDistance = visibilityDistance;
this.attributes = attributes;
this.mirrorSkin = mirrorSkin;
this.isDirty = true;
Expand All @@ -107,6 +110,7 @@ public NpcData(String name, UUID creator, Location location) {
this.turnToPlayer = false;
this.interactionCooldown = 0;
this.scale = 1;
this.visibilityDistance = -1;
this.equipment = new ConcurrentHashMap<>();
this.attributes = new ConcurrentHashMap<>();
this.mirrorSkin = false;
Expand Down Expand Up @@ -317,6 +321,16 @@ public NpcData setScale(float scale) {
return this;
}

public int getVisibilityDistance() {
return visibilityDistance;
}

public NpcData setVisibilityDistance(int visibilityDistance) {
this.visibilityDistance = visibilityDistance;
isDirty = true;
return this;
}

public Map<NpcAttribute, String> getAttributes() {
return attributes;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ public enum NpcModification {
GLOWING_COLOR,
INTERACTION_COOLDOWN,
SCALE,
VISIBILITY_DISTANCE,
LOCATION,
MIRROR_SKIN,
PLAYER_COMMAND,
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/de/oliver/fancynpcs/NpcManagerImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,7 @@ public void loadNpcs() {

float interactionCooldown = (float) npcConfig.getDouble("npcs." + id + ".interactionCooldown", 0);
float scale = (float) npcConfig.getDouble("npcs." + id + ".scale", 1);
int visibilityDistance = npcConfig.getInt("npcs." + id + ".visibility_distance", -1);

Map<NpcAttribute, String> attributes = new HashMap<>();
if (npcConfig.isConfigurationSection("npcs." + id + ".attributes")) {
Expand Down Expand Up @@ -403,6 +404,7 @@ public void loadNpcs() {
actions,
interactionCooldown,
scale,
visibilityDistance,
attributes,
mirrorSkin
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ else if (exceptionContext.exception().enumClass() == GlowingColor.class)
annotationParser.parse(TurnToPlayerCMD.INSTANCE);
annotationParser.parse(TypeCMD.INSTANCE);
annotationParser.parse(ActionCMD.INSTANCE);
annotationParser.parse(VisibilityDistanceCMD.INSTANCE);


String mcVersion = Bukkit.getMinecraftVersion();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ public void onCopy(
new ConcurrentHashMap<>(npc.getData().getActions()),
npc.getData().getInteractionCooldown(),
npc.getData().getScale(),
npc.getData().getVisibilityDistance(),
new ConcurrentHashMap<>(npc.getData().getAttributes()),
npc.getData().isMirrorSkin()
));
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ public void onInfo(
final String glowingStateTranslated = (npc.getData().isGlowing() && npc.getData().getGlowingColor() != null)
? ((SimpleMessage) translator.translate(GlowingColor.fromAdventure(npc.getData().getGlowingColor()).getTranslationKey())).getMessage()
: ((SimpleMessage) translator.translate("disabled")).getMessage();
final String visibilityDistanceTranslated = (npc.getData().getVisibilityDistance() == -1)
? ((SimpleMessage) translator.translate("default").replace("value", String.valueOf(FancyNpcs.getInstance().getFancyNpcConfig().getVisibilityDistance()))).getMessage()
: (npc.getData().getVisibilityDistance() == 0)
? ((SimpleMessage) translator.translate("not_visible")).getMessage()
: (npc.getData().getVisibilityDistance() == Integer.MAX_VALUE)
? ((SimpleMessage) translator.translate("always_visible")).getMessage()
: String.valueOf(npc.getData().getVisibilityDistance());
// Getting the creator player profile, this will be completed from cache in order to get name of the player.
final PlayerProfile creatorProfile = Bukkit.createProfile(npc.getData().getCreator());
translator.translate("npc_info_general")
Expand All @@ -60,6 +67,7 @@ public void onInfo(
.replace("is_skin_mirror", getTranslatedBoolean(npc.getData().isMirrorSkin()))
.replace("interaction_cooldown", npc.getData().getInteractionCooldown() <= 0 ? getTranslatedState(false) : interactionCooldown.toString())
.replace("scale", String.valueOf(npc.getData().getScale()))
.replace("visibility_distance", visibilityDistanceTranslated)
.replace("actions_total", String.valueOf(actionsTotal))
.send(sender);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package de.oliver.fancynpcs.commands.npc;

import de.oliver.fancylib.translations.Translator;
import de.oliver.fancynpcs.FancyNpcs;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.events.NpcModifyEvent;
import org.bukkit.command.CommandSender;
import org.incendo.cloud.annotations.Argument;
import org.incendo.cloud.annotations.Command;
import org.incendo.cloud.annotations.Permission;
import org.incendo.cloud.annotations.parser.Parser;
import org.incendo.cloud.annotations.suggestion.Suggestions;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.context.CommandInput;

import java.util.List;

import org.jetbrains.annotations.NotNull;

public enum VisibilityDistanceCMD {
INSTANCE;

private final Translator translator = FancyNpcs.getInstance().getTranslator();

// Storing in a static variable to avoid re-creating the array each time suggestion is requested.
private final List<String> DISTANCE_SUGGESTIONS = List.of("always_visible", "default", "not_visible");

@Command("npc visibility_distance <npc> <distance>")
@Permission("fancynpcs.command.npc.visibility_distance")
public void onVisibilityDistance(
final @NotNull CommandSender sender,
final @NotNull Npc npc,
final @Argument(parserName = "VisibilityDistanceCMD/distance") int distance
) {
final int finalDistance = Math.clamp(distance, -1, Integer.MAX_VALUE);
if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.VISIBILITY_DISTANCE, distance, sender).callEvent()) {
npc.getData().setVisibilityDistance(finalDistance);
npc.updateForAll();
translator.translate(finalDistance == -1 ? "npc_visibility_distance_set_default" : finalDistance == 0 ? "npc_visibility_distance_set_not_visible" : finalDistance == Integer.MAX_VALUE ? "npc_visibility_distance_set_always_visible" : "npc_visibility_distance_set_value")
.replace("npc", npc.getData().getName())
.replace("distance", (finalDistance > -1) ? String.valueOf(finalDistance) : String.valueOf(FancyNpcs.getInstance().getFancyNpcConfig().getVisibilityDistance()))
.send(sender);
} else {
translator.translate("command_npc_modification_cancelled").send(sender);
}
}

/* PARSERS AND SUGGESTIONS */

@Parser(name = "VisibilityDistanceCMD/distance", suggestions = "VisibilityDistanceCMD/distance")
public @NotNull Integer parse(final CommandContext<CommandSender> context, final CommandInput input) {
// If 'default' string is provided, it is being handled as -1.
if (input.peekString().equalsIgnoreCase("default")) {
input.readString();
return -1;
}
// If 'not_visible' string is provided, it is being handled as 0.
if (input.peekString().equalsIgnoreCase("not_visible")) {
input.readString();
return 0;
}
// If 'always_visible' string is provided, it is being handled as Integer.MAX_VALUE.
if (input.peekString().equalsIgnoreCase("always_visible")) {
input.readString();
return Integer.MAX_VALUE;
}
// Otherwise, reading next argument as int.
return input.readInteger();
}

@Suggestions("VisibilityDistanceCMD/distance")
public @NotNull List<String> suggest(final CommandContext<CommandSender> context, final CommandInput input) {
return DISTANCE_SUGGESTIONS;
}

}
16 changes: 16 additions & 0 deletions src/main/resources/languages/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ messages:
unknown: "Unknown"
not_available: "N/A"

# Common (Visibility)
always_visible: "Always Visible"
not_visible: "Not Visible"

# Common (Default Values)
default: "Default ({value})"

# Common (Colors)
color_black: "<dark_gray>Black"
color_dark_blue: "<dark_blue>Dark Blue"
Expand Down Expand Up @@ -119,6 +126,7 @@ messages:
npc_teleport: "<dark_gray>› <gray>Syntax: {primaryColor}/npc teleport {secondaryColor}(npc)"
npc_turn_to_player: "<dark_gray>› <gray>Syntax: {primaryColor}/npc turn_to_player {secondaryColor}(npc) (state)"
npc_type: "<dark_gray>› <gray>Syntax: {primaryColor}/npc type {secondaryColor}(npc) (type)"
npc_visibility_distance: "<dark_gray>› <gray>Syntax: {primaryColor}/npc visibility_distance {secondaryColor}(npc) (always_visible | default | not_visible | distance)"

# Commands (fancynpcs)
fancynpcs_reload_success: "<dark_gray>› {successColor}Plugin has been reloaded."
Expand Down Expand Up @@ -165,6 +173,7 @@ messages:
- "<dark_gray>› <hover:show_text:'<gray>Teleports you to the specified NPC.'>{primaryColor}/npc teleport {secondaryColor}(npc)"
- "<dark_gray>› <hover:show_text:'<gray>Changes whether the NPC should turn to the player when in range.'>{primaryColor}/npc turn_to_player {secondaryColor}(npc) (state)"
- "<dark_gray>› <hover:show_text:'<gray>Changes the type of the NPC.'>{primaryColor}/npc type {secondaryColor}(npc) (type)"
- "<dark_gray>› <hover:show_text:'<gray>Changes the visibility distance of the NPC.'>{primaryColor}/npc visibility_distance {secondaryColor}(npc) (default | distance | ...)"

# Commands (npc action)
npc_action_add_success: "<dark_gray>› <gray>Action has been added. There are {warningColor}{total}<gray> actions in total."
Expand Down Expand Up @@ -245,6 +254,7 @@ messages:
- "<dark_gray>› <hover:show_text:'<gray>Skin mirroring state of the NPC. Can be {successColor}true<gray> or {errorColor}false<gray>.'><#848484>Skin Mirroring</hover><dark_gray>: {warningColor}{is_skin_mirror}"
- "<dark_gray>› <hover:show_text:'<gray>Cooldown between interactions.'><gray>Interaction Cooldown</hover><dark_gray>: {warningColor}{interaction_cooldown}"
- "<dark_gray>› <hover:show_text:'<gray>Scale factor for the NPC size.'><#848484>Scale</hover><dark_gray>: {warningColor}x{scale}"
- "<dark_gray>› <hover:show_text:'<gray>Visibility distance of the NPC.'><gray>Visibility Distance</hover><dark_gray>: {warningColor}{visibility_distance}"
- ""
- "<dark_gray>› <hover:show_text:'<gray>Equipment of the NPC.<newline>Click the {warningColor}[Click Here]<gray> button to browse.'><gray>Equipment</hover><dark_gray>: <click:RUN_COMMAND:'/npc equipment {name} list'>{warningColor}[Click Here]</click>"
- "<dark_gray>› <hover:show_text:'<gray>Modified attributes of the NPC.<newline>Click the {warningColor}[Click Here]<gray> button to browse.'><#848484>Attributes</hover><dark_gray>: <click:RUN_COMMAND:'/npc attribute {name} list'>{warningColor}[Click Here]</click>"
Expand Down Expand Up @@ -284,6 +294,12 @@ messages:
# Commands (scale)
npc_scale_set_success: "<dark_gray>› <gray>NPC {warningColor}{npc}<gray> has been scaled to {warningColor}{scale}<gray>."

# Commands (npc visibility_distance)
npc_visibility_distance_set_value: "<dark_gray>› <gray>NPC {warningColor}{npc}<gray> is now visible from {warningColor}{distance}<gray> blocks."
npc_visibility_distance_set_default: "<dark_gray>› <gray>NPC {warningColor}{npc}<gray> is now using default visibility distance of {warningColor}{distance}<gray>."
npc_visibility_distance_set_not_visible: "<dark_gray>› <gray>NPC {warningColor}{npc}<gray> is no longer visible."
npc_visibility_distance_set_always_visible: "<dark_gray>› <gray>NPC {warningColor}{npc}<gray> is now always visible."

# Commands (npc show_in_tab)
npc_show_in_tab_set_true: "<dark_gray>› <gray>NPC {warningColor}{npc}<gray> is now shown in player-list."
npc_show_in_tab_set_false: "<dark_gray>› <gray>NPC {warningColor}{npc}<gray> is no longer shown in player-list."
Expand Down

0 comments on commit 63d7cb1

Please sign in to comment.