CarbonPaper99
主要就是Player JoinEvent 然后计时器开启,当计数值大于100 ticks时调动插件运行传送指令
但计时器不会写,是一次性的那种,用完就注销。

吕易天
本帖最后由 吕易天 于 2019-8-17 14:38 编辑

Player p=e.getPlayer();
new Thread(()->{
for(int i=0;i<100;i++)
{
for(int i2=0;i2<50;i++)
{
if(!p.isOnline())
  return;
try{
Thread.sleep(1);
}catch(Throwable e2){}
}
}
if(!p.isOnline())
  return;
Bukkit.getScheduler().runTask(this,()->{
Bukkit.dispatchCommand(p,"命令(不带/)");
});
}).start();




Dante_7
吕易天 发表于 2019-8-17 14:26
Player p=e.getPlayer();
new Thread(()->{
for(int i=0;i{

就这种答案也好意思往上摆? 误人子弟吗?

有两种方式: 使用 Bukkit 自带的计时器(BukkitRunnable) 或是 Java 提供的线程池: ScheduledExecutorService

我个人推荐你用第二种(因为我比较熟悉).

具体的代码怎么写, 还需要你自己去翻阅文档, 因为这两种方式都没什么技术含量, 百度一下这两个词就有大把多的教程

BukkitRunnable

ScheduledExecutorService

另外别用楼上提供的方法, 这种代码放服务器上简直就是害人

另外要是我的答案对你有点用不给金粒也给个人气呗~


吕易天
凋灵兔子 发表于 2019-8-17 14:38
就这种答案也好意思往上摆? 误人子弟吗?

有两种方式: 使用 Bukkit 自带的计时器(BukkitRunnable) 或是 J ...

我要是用Bukkit内置的那玩意玩家离线了也会继续等

Dante_7
吕易天 发表于 2019-8-17 14:39
我要是用Bukkit内置的那玩意玩家离线了也会继续等

不好意思, Bukkit 内置的计时器也不是你这种用法

吕易天
凋灵兔子 发表于 2019-8-17 14:40
不好意思, Bukkit 内置的计时器也不是你这种用法

你的意思就是runTaskLater嘛,如果用runTaskLater会导致等待这100tick的时间内如果玩家离线又重进就会出现两个重复的task

吕易天
本帖最后由 吕易天 于 2019-8-17 14:55 编辑
凋灵兔子 发表于 2019-8-17 14:40
不好意思, Bukkit 内置的计时器也不是你这种用法

你的意思:
Bukkit.getScheduler().runTaskLater(this,()->Bukkit.dispatchCommand(e.getPlayer(),"命令"),100);
这种方法有问题,所以我才没用

Dante_7
吕易天 发表于 2019-8-17 14:49
你的意思:
Bukkit.getScheduler().runTaskLater(this,()->{Bukkit.dispatchCommand(e.getPlayer(),"命令" ...

我已经说过了, 我个人习惯用第二种. 第一种是否存在问题我不知道, 但是第二种一定是安全的.

插件属于服务端程序, 再写服务端程序的时候我都是慎之又慎, 特别是涉及到一些敏感资源比如数据库, IO, 线程 等. 因为这些资源如果使用不当, 在服务端这种同时为很多人工作的场景下, 一个很小的问题乘以一百个用户就是一个很大的问题, 而你的解决方式就是用 new Thread 的方式新建一个线程来计时吗? 如果有一百个玩家使用这个功能, 我就要创建一百个线程吗? 有一万个玩家在线我要为这么小的一个功能而耗尽所有服务器资源创建一万个线程吗?

吕易天
本帖最后由 吕易天 于 2019-8-17 22:37 编辑
凋灵兔子 发表于 2019-8-17 14:57
我已经说过了, 我个人习惯用第二种. 第一种是否存在问题我不知道, 但是第二种一定是安全的.

插件属于服 ...

那么我还有一个方法:
类开头加:
public ConcurrentHashMap<String.Long> waitList=new ConcurrentHashMap<String,Long>();
public boolean terminate=false;
onEnable写:
Bukkit.getPluginManager().registerEvents(this,this);
Thread a=new Thread(()->{
while(!terminate)
{
Player[] temp=new Player[Bukkit.getOnlinePlayers().size()];
Bukkit.getOnlinePlayers().toArray(temp);
for(Player i : temp)
{
if(waitList.containsKey(i.getUniqueID().toString()))
{
if(waitList.get(i.getUniqueID().toString())<=0)
{
waitList.remove(i.getUniqueID().toString());
Bukkit.getScheduler().runTask(this,()->Bukkit.dispatchCommand(i,"命令"));
}else{
waitList.replace(i.getUniqueID().toString(),waitList.get(i.getUniqueID().toString())-1);
}
}try{
Thread.sleep(0,1);
}catch(Throwable e){}
}
try{
Thread.sleep(1);
}catch(Throwable e){}
}
});
a.setDaemon(true);
terminate=false;
a.start();
onDisable写:
waitList.clear();
terminate=true;
然后:
@EventHandler(priority=EventPriority.MONITOR,ignoreCancelled=false)
public void onPlayerJoin(PlayerJoinEvent e)
{
waitList.put(e.getPlayer().getUniqueID().toString(),5000);
}
@EventHandler(priority=EventPriority.MONITOR,ignoreCancelled=false)
public void onPlayerLeave(PlayerQuitEvent e)
{
waitList.remove(e.getPlayer().getUniqueID().toString());
}


Dante_7
吕易天 发表于 2019-8-17 15:12
那么我还有一个方法:
类开头加:
public ConcurrentHashMap waitList=new ConcurrentHashMap();

如果这就是你的真实技术的话, 我建议你还是下架你所有的插件吧.

1139365029
本帖最后由 1139365029 于 2019-8-17 15:49 编辑

看了一下回复,
考虑到假人压测和玩家有加入后立即退出的可能,
至少需要这些要求:线程不能开太多,也不能不需要时一直开着,玩家退出后不需要继续执行,
此外还需要额外满足:对玩家/服务器/指令等的操作必须在主线程,但其它操作不需要,

简单的说一下思路,
首先需要一个List或者类似的东西,
玩家加入时,将玩家和时间记录进去,
玩家退出时,或者执行操作之后,将记录移除,
其次还需要一个线程,用于遍历记录,并进行操作,
全部操作完毕之后,线程可以退出,
最后,玩家加入时,除了记录之外,
若线程未启动,则启动,反之不用管。

代码(未测试,大佬勿喷):
忘记线程安全了,重新改了一下,把操作List的代码放到了主线程,感谢@吕易天 的提醒


吕易天
1139365029 发表于 2019-8-17 15:32
看了一下回复,
考虑到假人压测和玩家有加入后立即退出的可能,
至少需要这些要求:线程不能开太多,也不能 ...

由于ArrayList是非线程安全的,所以我用了ConcurrentHashMap

下一页 最后一页