GoldenPotato137 / OxygenSystem

Introduce oxygen to Minecraft!
Apache License 2.0
4 stars 4 forks source link

玩家氧气值存储的问题 #2

Closed heartalborada-del closed 2 years ago

heartalborada-del commented 2 years ago

其实玩家的氧气值可以存在他们的nbt里面,这样就可以数据持久化,但是不知道性能如何

PersistentDataContainer p = event.getPlayer().getPersistentDataContainer();
//设置
p.set(NamespacedKey, PersistentDataType, DATA);
//获取
p.get(NamespacedKey, PersistentDataType)
heartalborada-del commented 2 years ago

想了一下,其实可以在关闭插件的时候保存

heartalborada-del commented 2 years ago

稍微写了下,应该没啥大的毛病

GoldenPotato137 commented 2 years ago

好家伙,效率拉满了属于是。 看代码应该没啥问题,如果方便的话开个pr我merge进来吧( 肥肠感谢您的贡献

heartalborada-del commented 2 years ago

好家伙,效率拉满了属于是。 看代码应该没啥问题,如果方便的话开个pr我merge进来吧( 肥肠感谢您的贡献

我现在在整洞穴检测 (bbs上面的矿洞里面缺氧的功能我服玩家提出来的)

GoldenPotato137 commented 2 years ago

那个可能得稍微改下框架,现在用enableworld可能不太够,可能得每个世界记录个type,type 用来表示世界是完全有氧(原版)/ 洞穴无氧,其余有氧 / 完全无氧,这三种类型。

关于探测洞穴,我目前没有什么特别好的idea,可能还是得检测高度,高度低于海平面一定程度的直接钦定为洞穴环境。(mabye?)但这样没法区分天然结构和人工结构

heartalborada-del commented 2 years ago

那个可能得稍微改下框架,现在用enableworld可能不太够,可能得每个世界记录个type,type 用来表示世界是完全有氧(原版)/ 洞穴无氧,其余有氧 / 完全无氧,这三种类型。

关于探测洞穴,我目前没有什么特别好的idea,可能还是得检测高度,高度低于海平面一定程度的直接钦定为洞穴环境。(mabye?)但这样没法区分天然结构和人工结构

我现在的想法是,遍历玩家周围11*11*11的范围,判断是否是“洞穴方块”并且方块离最高方块相差一定距离,然后大于某个数值就判定为洞穴,也确实无法区分天然和人工结构

GoldenPotato137 commented 2 years ago

11*11*11的空间其实也不算小了,如果检查频率高的话我感觉可能会占用太多算力。但是我思来想去,总感觉地下结构都算做洞穴也没啥毛病。就算是人工结构一样会有缺氧的现象存在,需要长期使用的人工地下结构本来就应该补充氧气(在这里对应氧气室)。在这种基础上,直接检测高度也许是个好主意

heartalborada-del commented 2 years ago

11*11*11的空间其实也不算小了,如果检查频率高的话我感觉可能会占用太多算力。但是我思来想去,总感觉地下结构都算做洞穴也没啥毛病。就算是人工结构一样会有缺氧的现象存在,需要长期使用的人工地下结构本来就应该补充氧气(在这里对应氧气室)。在这种基础上,直接检测高度也许是个好主意

这个是我目前写的检测,监听的是PlayerMoveEvent

    public static boolean checkIsOnCave(Location center) {
        int count = 0;
        World w = center.getWorld();
        float version = Util.GetServerVersion();
        int min = version < 1.18 ? 0 : -64; //1.14的api没看到World.getMinHeight的实现
        int cx = center.getBlockX(), cy = center.getBlockY(), cz = center.getBlockZ();
        for(int i = 0;i <= 1331;i++) {
            int x = i%11 + cx - 5, y = i/11%11 + cy -5, z = i/11/11%11 +cz -5;
            if(y > w.getMaxHeight() || y < -64 || y < min) continue;
            Location lo = new Location(w,x,y,z);
            Block ch = lo.getBlock();
            int hy = w.getHighestBlockAt(lo).getY();
            if(ch.isEmpty()) continue;
            if(ch.getLightFromSky() == 15) continue;
            if(lo.getBlock().getType() == Material.STONE && hy - y > 20) count++;
            if(count >= 333) return true;
        }
        return false;
    }
heartalborada-del commented 2 years ago

11*11*11的空间其实也不算小了,如果检查频率高的话我感觉可能会占用太多算力。但是我思来想去,总感觉地下结构都算做洞穴也没啥毛病。就算是人工结构一样会有缺氧的现象存在,需要长期使用的人工地下结构本来就应该补充氧气(在这里对应氧气室)。在这种基础上,直接检测高度也许是个好主意

这个是我目前写的检测,监听的是PlayerMoveEvent

    public static boolean checkIsOnCave(Location center) {
        int count = 0;
        World w = center.getWorld();
        float version = Util.GetServerVersion();
        int min = version < 1.18 ? 0 : -64; //1.14的api没看到World.getMinHeight的实现
        int cx = center.getBlockX(), cy = center.getBlockY(), cz = center.getBlockZ();
        for(int i = 0;i <= 1331;i++) {
            int x = i%11 + cx - 5, y = i/11%11 + cy -5, z = i/11/11%11 +cz -5;
            if(y > w.getMaxHeight() || y < -64 || y < min) continue;
            Location lo = new Location(w,x,y,z);
            Block ch = lo.getBlock();
            int hy = w.getHighestBlockAt(lo).getY();
            if(ch.isEmpty()) continue;
            if(ch.getLightFromSky() == 15) continue;
            if(lo.getBlock().getType() == Material.STONE && hy - y > 20) count++;
            if(count >= 333) return true;
        }
        return false;
    }

跑了下图,感觉性能影响不大 Timings

GoldenPotato137 commented 2 years ago

如果是在moveevent的话,加个基于玩家的时间戳吧,最多两秒一次检测什么的,要不玩家多起来可能还真会卡。 P.S. 这个枚举写法我真是第一次见,我还是too young too simple,如果给我写的话我就三层循环了(

GoldenPotato137 commented 2 years ago

诶,不对,这个不应该在OnTickEnd那里调用吗?

heartalborada-del commented 2 years ago

诶,不对,这个不应该在OnTickEnd那里调用吗?

如果写在tickend好像就会跟气密室冲突

GoldenPotato137 commented 2 years ago

诶,不对,这个不应该在OnTickEnd那里调用吗?

如果写在tickend好像就会跟气密室冲突

不会呀,

    public void OnTickEnd(ServerTickEndEvent e)
    {
        if (e.getTickNumber() % 20 != 0) return;
        for (Player player : Bukkit.getOnlinePlayers())
        {
            if(!Config.EnableWorlds.contains(player.getWorld().getName())) continue; //这里得改成判断是不是全氧世界
            if(player.getGameMode()!= GameMode.SURVIVAL) continue;
            if(!OxygenSystem.playerOxygen.containsKey(player.getUniqueId()))
                OxygenSystem.playerOxygen.put(player.getUniqueId(), (double) OxygenCalculator.GetMaxOxygen(player));
            if(SealedRoomCalculator.GetBelong(player.getLocation())==0) //不在气密室里
            {
                //如果是山洞无氧世界且不在山洞里,return
                boolean result = OxygenCalculator.SetOxygen(player, -1);
                if(!result)
                {
                    ItemStack oxygenTank = OxygenCalculator.GetOxygenTank(player);
                    if(oxygenTank==null)
                        player.damage(2);
                    else
                    {
                        oxygenTank.add(-1);
                        OxygenCalculator.ConsumeOxygenTank(player);
                        player.getInventory().addItem(OxygenTankProembryo.GetItem());
                    }
                }
            }
            else
                OxygenCalculator.SetOxygen(player,Config.RoomOxygenAdd);

            OxygenUtil.ShowOxygen(player);
        }
    }
heartalborada-del commented 2 years ago

草,我是sb

heartalborada-del commented 2 years ago

写的有点烂,脑子是晕的

    public void OnTickEnd(ServerTickEndEvent e)
    {
        if (e.getTickNumber() % 20 != 0) return;
        for (Player player : Bukkit.getOnlinePlayers())
        {
            if(!Config.EnableWorlds.contains(player.getWorld().getName())) continue;
            if(player.getGameMode()!= GameMode.SURVIVAL) continue;
            if(!OxygenSystem.playerOxygen.containsKey(player.getUniqueId()))
                OxygenSystem.playerOxygen.put(player.getUniqueId(), (double) OxygenCalculator.GetMaxOxygen(player));
            if(SealedRoomCalculator.GetBelong(player.getLocation())==0 && !Config.EnableCaveNonOxygenWorlds.contains(player.getWorld().getName()))
            {
                boolean result = OxygenCalculator.SetOxygen(player, -1);
                if(!result)
                {
                    ItemStack oxygenTank = OxygenCalculator.GetOxygenTank(player);
                    if(oxygenTank==null)
                        player.damage(2);
                    else
                    {
                        oxygenTank.add(-1);
                        OxygenCalculator.ConsumeOxygenTank(player);
                        player.getInventory().addItem(OxygenTankProembryo.GetItem());
                    }
                }
            } else if (Config.EnableCaveNonOxygenWorlds.contains(player.getWorld().getName())) {
                if(SealedCaveCalculator.checkIsOnCave(player.getLocation())) {
                    boolean result = OxygenCalculator.SetOxygen(player, -1);
                    if(!result)
                    {
                        ItemStack oxygenTank = OxygenCalculator.GetOxygenTank(player);
                        if(oxygenTank==null)
                            player.damage(2);
                        else
                        {
                            oxygenTank.add(-1);
                            OxygenCalculator.ConsumeOxygenTank(player);
                            player.getInventory().addItem(OxygenTankProembryo.GetItem());
                        }
                    }
                }
            } else OxygenCalculator.SetOxygen(player,Config.RoomOxygenAdd);
            OxygenUtil.ShowOxygen(player);
        }
    }
heartalborada-del commented 2 years ago

我去找找地下会生成的方块(

heartalborada-del commented 2 years ago

我在想咋兼容1.19的新方块

GoldenPotato137 commented 2 years ago

写的有点烂,脑子是晕的

    public void OnTickEnd(ServerTickEndEvent e)
    {
        if (e.getTickNumber() % 20 != 0) return;
        for (Player player : Bukkit.getOnlinePlayers())
        {
            if(!Config.EnableWorlds.contains(player.getWorld().getName())) continue;
            if(player.getGameMode()!= GameMode.SURVIVAL) continue;
            if(!OxygenSystem.playerOxygen.containsKey(player.getUniqueId()))
                OxygenSystem.playerOxygen.put(player.getUniqueId(), (double) OxygenCalculator.GetMaxOxygen(player));
            if(SealedRoomCalculator.GetBelong(player.getLocation())==0 && !Config.EnableCaveNonOxygenWorlds.contains(player.getWorld().getName()))
            {
                boolean result = OxygenCalculator.SetOxygen(player, -1);
                if(!result)
                {
                    ItemStack oxygenTank = OxygenCalculator.GetOxygenTank(player);
                    if(oxygenTank==null)
                        player.damage(2);
                    else
                    {
                        oxygenTank.add(-1);
                        OxygenCalculator.ConsumeOxygenTank(player);
                        player.getInventory().addItem(OxygenTankProembryo.GetItem());
                    }
                }
            } else if (Config.EnableCaveNonOxygenWorlds.contains(player.getWorld().getName())) {
                if(SealedCaveCalculator.checkIsOnCave(player.getLocation())) {
                    boolean result = OxygenCalculator.SetOxygen(player, -1);
                    if(!result)
                    {
                        ItemStack oxygenTank = OxygenCalculator.GetOxygenTank(player);
                        if(oxygenTank==null)
                            player.damage(2);
                        else
                        {
                            oxygenTank.add(-1);
                            OxygenCalculator.ConsumeOxygenTank(player);
                            player.getInventory().addItem(OxygenTankProembryo.GetItem());
                        }
                    }
                }
            } else OxygenCalculator.SetOxygen(player,Config.RoomOxygenAdd);
            OxygenUtil.ShowOxygen(player);
        }
    }

写得有点麻烦,但是问题不大,merge之后我再改就行

GoldenPotato137 commented 2 years ago

我在想咋兼容1.19的新方块

可以考虑使用现有API(旧版本的),然后看看getblock.getType返回的是啥Material,如果能返回新方块的Material的话问题就不大,大不了用getString检测名字(暴论)。

u1s1,我也不知道怎么去获取新方块

heartalborada-del commented 2 years ago

我在想咋兼容1.19的新方块

可以考虑使用现有API(旧版本的),然后看看getblock.getType返回的是啥Material,如果能返回新方块的Material的话问题就不大,大不了用getString检测名字(暴论)。

u1s1,我也不知道怎么去获取新方块

测试之后这样写没问题

for(String s : Config.CaveBlockList) CaveBlockList.add(Material.matchMaterial(s));