我目前正在制作一个插件插件,该插件会在加入时随机产生用户。总的来说,我有两种方法。 getLocationList
和getRandomStringFromList
。
public String getRandomStringFromList(List<String> list) {
ThreadLocalRandom random = ThreadLocalRandom.current();
int randomNumber = random.nextInt(list.size());
String randomString = list.get(randomNumber);
return randomString;
}
private List<String> locationList;
public List<String> getLocationList() {
if (this.locationList == null)
this.locationList = new ArrayList<>();
this.locationList = locationList.stream().distinct().collect(Collectors.toList());
return this.locationList;
}
然后,在我的活动课上,我有这个。
RandomSpawn plugin;
public RSEvent(RandomSpawn instance) {
plugin = instance;
}
@EventHandler
public void onPlayerJoinEvent(PlayerJoinEvent e) {
Player p = e.getPlayer();
String randomString = plugin.getRandomStringFromList(plugin.getLocationList());
p.teleport(new Location(Bukkit.getWorld(String.valueOf(plugin.getConfig().getString("locations." + randomString + ".world"))),
plugin.getConfig().getDouble("locations." + randomString + ".x"),
plugin.getConfig().getDouble("locations." + randomString + ".y"),
plugin.getConfig().getDouble("locations." + randomString + ".z"),
plugin.getConfig().getInt("locations." + randomString + ".yaw"),
plugin.getConfig().getInt("locations." + randomString + ".pitch")));
这很好用,但是,我添加了一个禁用命令。因此,在config中,每个名为disabled的位置都会生成一个新的默认值。这可以设置为true或false。我希望插件检查randomString.disabled
是否设置为true,如果是,请重新运行整个getRandomStringFromList
以获取新的randomString
,直到将disabled设置为false。
答案 0 :(得分:2)
我将您的问题解释为您要从列表中选择一个由字符串表示的随机位置。但是,永远不应该选择任何禁用的位置(存储在别处)。
您的方法是选择一个随机位置,检查是否已禁用,如果是,请重试。重复此操作,直到弹出一个未禁用的位置。这不是一个好主意
如果所有位置都被禁用怎么办?→无限循环
如果只启用了多个位置中的一个?→许多位置都会进行不必要的测试
更好的方法是获取您的位置列表,过滤它们以便只保留启用的位置,然后随机选择一个。当过滤后的列表为空时,您知道可能有问题(也许您可以选择一个默认位置,不知何故?)。
使用streams可以优雅地过滤列表。在我们的初始位置列表(字符串)creating stream之后,我们可以filter流,然后collect这些位置in a new List
。如果某个位置被禁用,过滤器功能可以查找。
这是一个过滤的小例子,它自己编译并演示了这个想法。
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
class Filtering {
public static void main(String[] args) {
// a list of strings
List<String> strings = new ArrayList<>();
strings.add("foo");
strings.add("bar");
strings.add("baz");
// a quick and dirty way of representing if a string is enabled
HashSet<String> disabled = new HashSet<>();
disabled.add("bar");
// filter strings to only enabled ones
strings.stream()
.filter(s -> !disabled.contains(s))
.forEach(System.out::println);
}
}
在您的代码中,更改应该类似于以下内容。
@EventHandler
public void onPlayerJoinEvent(PlayerJoinEvent e) {
Player p = e.getPlayer();
FileConfiguration cfg = plugin.getConfig();
// get all enabled locations
List<String> locations = plugin.getLocationList().stream().
filter(s -> !cfg.getBoolean("locations." + s + ".disabled")).
collect(Collectors.toList());
if (locations.size() === 0) {
// TODO: handle this special case
}
// teleport to random location
String randomString = plugin.getRandomStringFromList(locations);
String cfgPrefix = "locations." + randomString + ".";
p.teleport(new Location(
Bukkit.getWorld(cfg.getString(cfgPrefix + "world")),
cfg.getDouble(cfgPrefix + "x"),
cfg.getDouble(cfgPrefix + "y"),
cfg.getDouble(cfgPrefix + "z"),
cfg.getInt(cfgPrefix + "yaw"),
cfg.getInt(cfgPrefix + "pitch")));
}
我介绍了一些临时变量以提高可读性,摆脱了不必要的String.valueOf
调用并对格式进行了微小的更改。然而,主要的变化是// get all enabled locations
以下的区块。应该直观地清楚那里发生了什么,但是如果你需要我澄清任何事情,请告诉我。