Move from trove to fastutil to match Minecraft. Add /npc text speech bubbles duration. Fix old Java back compatibility.

This commit is contained in:
fullwall 2024-08-31 00:15:54 +08:00
parent a1d208fe1e
commit ceb8d10cd2
11 changed files with 57 additions and 23 deletions

View File

@ -55,9 +55,9 @@
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.sf.trove4j</groupId>
<artifactId>trove4j</artifactId>
<version>3.0.3</version>
<groupId>it.unimi.dsi</groupId>
<artifactId>fastutil</artifactId>
<version>8.5.14</version>
<scope>provided</scope>
</dependency>
<dependency>
@ -202,8 +202,8 @@
</filters>
<relocations>
<relocation>
<pattern>gnu.trove</pattern>
<shadedPattern>clib.trove</shadedPattern>
<pattern>it.unimi.dsi</pattern>
<shadedPattern>clib.fastutil</shadedPattern>
</relocation>
<relocation>
<pattern>net.kyori</pattern>

View File

@ -291,8 +291,8 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
// Unfortunately, transitive dependency management is not supported in this library.
lib.loadLibrary(
Library.builder().groupId("ch{}ethz{}globis{}phtree").artifactId("phtree").version("2.8.0").build());
lib.loadLibrary(Library.builder().groupId("net{}sf{}trove4j").artifactId("trove4j").version("3.0.3")
.relocate("gnu{}trove", "clib{}trove").build());
lib.loadLibrary(Library.builder().groupId("it{}unimi{}dsi").artifactId("fastutil").version("8.5.14")
.relocate("it{}unimi{}dsi", "clib{}fastutil").build());
lib.loadLibrary(Library.builder().groupId("net{}kyori").artifactId("adventure-text-minimessage")
.version("4.17.0").relocate("net{}kyori", "clib{}net{}kyori").build());
lib.loadLibrary(Library.builder().groupId("net{}kyori").artifactId("adventure-api").version("4.17.0")

View File

@ -2,6 +2,7 @@ package net.citizensnpcs;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;
import org.bukkit.Bukkit;
import org.bukkit.Location;
@ -65,7 +66,6 @@ import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.util.Vector;
import com.google.common.base.Joiner;
import com.google.common.base.Predicates;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
@ -222,7 +222,7 @@ public class EventListen implements Listener {
}
private Iterable<NPC> getAllNPCs() {
return Iterables.filter(Iterables.concat(CitizensAPI.getNPCRegistries()), Predicates.notNull());
return Iterables.filter(Iterables.concat(CitizensAPI.getNPCRegistries()), Objects::nonNull);
}
void loadNPCs(ChunkEvent event) {

View File

@ -14,6 +14,7 @@ import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;
@ -55,7 +56,6 @@ import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import com.google.common.base.Joiner;
import com.google.common.base.Predicates;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.collect.Iterables;
@ -2811,7 +2811,7 @@ public class NPCCommands {
}
}
List<NPC> search = location.getWorld().getNearbyEntities(location, range, range, range).stream()
.map(registry::getNPC).filter(Predicates.notNull()).collect(Collectors.toList());
.map(registry::getNPC).filter(Objects::nonNull).collect(Collectors.toList());
search.sort((o1, o2) -> Double.compare(o1.getEntity().getLocation().distanceSquared(location),
o2.getEntity().getLocation().distanceSquared(location)));
for (NPC test : search) {

View File

@ -17,7 +17,7 @@ import org.bukkit.inventory.ItemStack;
import com.google.common.collect.Maps;
import gnu.trove.map.hash.TIntObjectHashMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import net.citizensnpcs.Settings.Setting;
import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.event.DespawnReason;
@ -36,7 +36,7 @@ import net.citizensnpcs.util.NMS;
public class CitizensNPCRegistry implements NPCRegistry {
private final String name;
private final TIntObjectHashMap<NPC> npcs = new TIntObjectHashMap<>();
private final Int2ObjectOpenHashMap<NPC> npcs = new Int2ObjectOpenHashMap<>();
private final NPCDataStore saves;
private final Map<UUID, NPC> uniqueNPCs = Maps.newHashMap();
@ -130,7 +130,7 @@ public class CitizensNPCRegistry implements NPCRegistry {
try {
npc.despawn(reason);
} catch (Throwable e) {
e.printStackTrace(); // ensure that all entities are despawned
e.printStackTrace();
}
itr.remove();
}
@ -200,7 +200,7 @@ public class CitizensNPCRegistry implements NPCRegistry {
@Override
public Iterator<NPC> iterator() {
return new Iterator<NPC>() {
Iterator<NPC> itr = npcs.valueCollection().iterator();
Iterator<NPC> itr = npcs.values().iterator();
UUID lastUUID;
@Override
@ -236,7 +236,7 @@ public class CitizensNPCRegistry implements NPCRegistry {
@Override
public Iterable<NPC> sorted() {
List<NPC> vals = new ArrayList<>(npcs.valueCollection());
List<NPC> vals = new ArrayList<>(npcs.values());
vals.sort(Comparator.comparing(NPC::getId));
return vals;
}

View File

@ -21,7 +21,6 @@ import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
@ -91,7 +90,7 @@ public class SkinUpdateTracker {
}
private Iterable<NPC> getAllNPCs() {
return Iterables.filter(Iterables.concat(CitizensAPI.getNPCRegistries()), Predicates.notNull());
return Iterables.filter(Iterables.concat(CitizensAPI.getNPCRegistries()), Objects::nonNull);
}
private List<SkinnableEntity> getNearbyNPCs(Player player, boolean reset, boolean checkFov) {

View File

@ -3,6 +3,7 @@ package net.citizensnpcs.trait;
import java.util.Objects;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import com.google.common.base.Charsets;
import com.google.common.io.BaseEncoding;
@ -16,6 +17,8 @@ import net.citizensnpcs.api.util.Messaging;
import net.citizensnpcs.api.util.Placeholders;
import net.citizensnpcs.npc.skin.Skin;
import net.citizensnpcs.npc.skin.SkinnableEntity;
import net.citizensnpcs.util.NMS;
import net.citizensnpcs.util.SkinProperty;
@TraitName("skintrait")
public class SkinTrait extends Trait {
@ -150,6 +153,17 @@ public class SkinTrait extends Trait {
skinName = ChatColor.stripColor(name);
}
/**
* Set skin data copying from a {@link Player}. Not subject to rate limiting from Mojang.
*
* @param player
* The player to copy
*/
public void setSkinPersistent(Player player) {
SkinProperty sp = SkinProperty.fromMojangProfile(NMS.getProfile(player));
setSkinPersistent(sp.name, sp.signature, sp.value);
}
/**
* Sets the skin data directly, respawning the NPC if spawned.
*

View File

@ -1,5 +1,7 @@
package net.citizensnpcs.trait.text;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@ -47,6 +49,8 @@ public class Text extends Trait implements Runnable, Listener {
private double range = Setting.DEFAULT_TALK_CLOSE_RANGE.asDouble();
@Persist(value = "realistic-looking")
private boolean realisticLooker = Setting.DEFAULT_REALISTIC_LOOKING.asBoolean();
@Persist(value = "speech-bubble-duration")
private int speechBubbleDuration = Setting.DEFAULT_TEXT_SPEECH_BUBBLE_DURATION.asTicks();
@Persist(value = "speech-bubbles")
private boolean speechBubbles;
@Persist(value = "talk-close")
@ -205,11 +209,9 @@ public class Text extends Trait implements Runnable, Listener {
}
if (speechBubbles) {
HologramTrait trait = npc.getOrAddTrait(HologramTrait.class);
trait.addTemporaryLine(Placeholders.replace(text.get(index), player, npc),
Setting.DEFAULT_TEXT_SPEECH_BUBBLE_DURATION.asTicks());
} else {
npc.getDefaultSpeechController().speak(new SpeechContext(text.get(index), player));
trait.addTemporaryLine(Placeholders.replace(text.get(index), player, npc), speechBubbleDuration);
}
npc.getDefaultSpeechController().speak(new SpeechContext(text.get(index), player));
return true;
}
@ -242,6 +244,10 @@ public class Text extends Trait implements Runnable, Listener {
this.range = range;
}
public void setSpeechBubbleDuration(Duration duration) {
this.speechBubbleDuration = (int) (duration.get(ChronoUnit.MILLIS) / 50);
}
/**
* @return Whether talking close is enabled.
*/

View File

@ -1,5 +1,6 @@
package net.citizensnpcs.trait.text;
import java.time.Duration;
import java.util.Arrays;
import org.bukkit.ChatColor;
@ -13,6 +14,7 @@ import com.google.common.base.Joiner;
import net.citizensnpcs.Settings.Setting;
import net.citizensnpcs.api.util.Messaging;
import net.citizensnpcs.api.util.SpigotUtil;
import net.citizensnpcs.util.Messages;
public class TextBasePrompt extends StringPrompt {
@ -76,6 +78,15 @@ public class TextBasePrompt extends StringPrompt {
text.toggleRealisticLooking();
} else if (original.trim().equalsIgnoreCase("speech bubbles")) {
text.toggleSpeechBubbles();
} else if (original.trim().startsWith("speech bubbles duration")) {
try {
Duration duration = SpigotUtil.parseDuration(original.replace("speech bubbles duration", "").trim(),
null);
text.setSpeechBubbleDuration(duration);
Messaging.sendErrorTr(sender, Messages.SPEECH_BUBBLES_DURATION_SET, duration);
} catch (Exception exception) {
Messaging.sendErrorTr(sender, Messages.INVALID_SPEECH_BUBBLES_DURATION);
}
} else if (input.equalsIgnoreCase("close") || original.trim().equalsIgnoreCase("talk close")) {
text.toggleTalkClose();
} else if (input.equalsIgnoreCase("range")) {

View File

@ -214,6 +214,7 @@ public class Messages {
public static final String INVALID_SKIN_FILE = "citizens.commands.npc.skin.invalid-file";
public static final String INVALID_SOUND = "citizens.commands.npc.sound.invalid-sound";
public static final String INVALID_SPAWN_LOCATION = "citizens.commands.npc.create.invalid-location";
public static final String INVALID_SPEECH_BUBBLES_DURATION = "citizens.commands.npc.text.invalid-speech-bubbles-duration";
public static final String INVALID_TRIGGER_TELEPORT_FORMAT = "citizens.editors.waypoints.triggers.teleport.invalid-format";
public static final String INVALID_TROPICALFISH_COLOR = "citizens.commands.npc.tropicalfish.invalid-color";
public static final String INVALID_TROPICALFISH_PATTERN = "citizens.commands.npc.tropicalfish.invalid-pattern";
@ -399,6 +400,7 @@ public class Messages {
public static final String SNOWMAN_FORM_SNOW_STOPPED = "citizens.commands.npc.snowman.form-snow-stopped";
public static final String SOUND_INFO = "citizens.commands.npc.sound.info";
public static final String SOUND_SET = "citizens.commands.npc.sound.set";
public static final String SPEECH_BUBBLES_DURATION_SET = "citizens.commands.npc.text.speech-bubbles-duration-set";
public static final String SPEED_MODIFIER_SET = "citizens.commands.npc.speed.set";
public static final String SPEED_TRIGGER_PROMPT = "citizens.editors.waypoints.triggers.speed.prompt";
public static final String SPELL_SET = "citizens.commands.npc.spellcaster.spell-set";

View File

@ -642,6 +642,8 @@
"citizens.commands.template.conflict" : "A template by that name already exists.",
"citizens.commands.template.list.description" : "Lists available templates",
"citizens.commands.template.list.header" : "]]Available templates:",
"citizens.commands.npc.text.invalid-speech-bubbles-duration" : "Invalid speech bubble duration.",
"citizens.commands.npc.text.speech-bubbles-duration-set" : "Speech bubble duration set to [[{0}]].",
"citizens.commands.template.list.help" : "",
"citizens.commands.template.missing" : "Template not found.",
"citizens.commands.template.namespace-already-exists" : "Namespace [[{0}]] already exists",
@ -707,7 +709,7 @@
"citizens.editors.text.range-set" : "[[Range]] set to [[{0}]].",
"citizens.editors.text.realistic-looking-set" : "[[Realistic looking]] set to [[{0}]].",
"citizens.editors.text.speech-bubbles-set" : "[[Speech bubbles]] set to [[{0}]].",
"citizens.editors.text.start-prompt" : "<click:suggest_command:add ><yellow><u>Add text</u></click> | <click:suggest_command:item ><hover:show_text:\"Set the talk item in hand pattern (set to <yellow>default</yellow> to clear)\"><yellow><u>item</hover></click> | <click:suggest_command:range ><hover:show_text:Set the talking range in blocks><yellow><u>range</hover></click> | <click:suggest_command:delay ><hover:show_text:Set the talking delay in ticks><yellow><u>delay</u></yellow></hover></click><br><click:run_command:/npc text close><hover:show_text:Toggle sending messages when players get close>{0}<u>talk close</hover></click> | <click:run_command:/npc text random><hover:show_text:Toggle random talking>{1}<u>random</hover></click> | <click:run_command:/npc text speech bubbles><hover:show_text:Toggle showing text as holograms instead of chat messages>{2}<u>speech bubbles</hover></click> | <click:run_command:/npc text realistic looking><hover:show_text:Toggle requiring line of sight before speaking>{3}<u>realistic</hover></click>",
"citizens.editors.text.start-prompt" : "<click:suggest_command:add ><yellow><u>Add text</u></click> | <click:suggest_command:item ><hover:show_text:\"Set the talk item in hand pattern (set to <yellow>default</yellow> to clear)\"><yellow><u>item</hover></click> | <click:suggest_command:range ><hover:show_text:Set the talking range in blocks><yellow><u>range</hover></click> | <click:suggest_command:delay ><hover:show_text:Set the talking delay in ticks><yellow><u>delay</u></yellow></hover></click><br><click:run_command:/npc text close><hover:show_text:Toggle sending messages when players get close>{0}<u>talk close</hover></click> | <click:run_command:/npc text random><hover:show_text:Toggle random talking>{1}<u>random</hover></click> | <click:suggest_command:/npc text speech bubbles duration ><hover:show_text:Set speech bubble duration>{2}<u>speech bubble duration</hover></click> | <click:run_command:/npc text speech bubbles><hover:show_text:Toggle showing text as holograms instead of chat messages>{2}<u>speech bubbles</hover></click> | <click:run_command:/npc text realistic looking><hover:show_text:Toggle requiring line of sight before speaking>{3}<u>realistic</hover></click>",
"citizens.editors.text.talk-item-set" : "[[Talk item pattern]] set to [[{0}]].",
"citizens.editors.text.text-list-header" : "Current text:",
"citizens.editors.waypoints.guided.added-available" : "Added a [[destination]] waypoint which the NPC will randomly pathfind between.",