Вопрос Как спаунить мобов в определенное время

Artemis_37

Единомышленник
Участник
Сообщения
78
Розыгрыши
0
Репутация
79
Реакции
106
Баллы
143
Я использую lucera2 interlude и пытаюсь сделать пользовательский код, в котором я могу спаунить много монстров в нескольких зонах в зависимости от дня с координатами x y z. Я хочу спросить, как правильно сделать этот скрипт.
Мои попытки на данный момент:
- Мобы спаунятся, но ходят бесконечно.
- Мобы появляются, но во всех зонах.
- Мобы появляются, но когда я бью их, они куда-то телепортируются.

*Я пытаюсь сделать следующее с TeleporterInstance
Используемый метод:
- с помощью xml-файла
- по списку массивов

Мне нужно знать следующее:
- Как спаунить/деспаунить монстров
- Как спавнить мобов в 00:00 каждый день, когда зона меняется.
- (Рекогносцировка для спавна через xml готова)
- Как добавить объявление в чат героев (%) о том, что зона меняется. (Время 00:01)



просто примечание: я новичок в программировании на java.
Если у кого-то есть свободное время, пожалуйста, объясните мне, как я могу решить эту задачу. Спасибо!
 

Посмотрите как реализован спавн босса из эпиков, там есть время в какое их спавнить и сделайте по примеру для своих мобов.
Деспавн можно посмотреть в квестах.
Еще как реализован спавн/деспавн мамона в катах.

Это все что могу сказать, на руках нет сборки.
 
ThreadPoolManager поможет удалить всех мобов, чтобы удалить нужно при спавне добавить всех мобов в список и через н-время удалять, также будет спавнить мобов по времени календаря
Announcements даст анонсы всем игрокам
Calendar поможет рассчитать время для следующего спавна и время можно хранить в кэше/бд и его передавать в Announcements
Список нужных Location + Rnd по локациям даст рандом локу, которую также можно записать и передать в анонс
 
Calendar поможет рассчитать время для следующего спавна и время можно хранить в кэше/бд и его передавать в Announcements
С Calendar будет слишком уж громоздкий и запутанный код расчетов такого времени, имхо.
Тут лучше и удобней будет использовать работу с временем в стиле Cron для получений времени спавна и т.д., например через класс SchedulingPattern, который можно стянуть из того же овера, если в люцере нет ничего похожего. Ну или можно прицепить какую нибудь либу для работы с этим, например , правда это как из пушки по воробьям будет в этом случае :)
Ну а в случае с SchedulingPattern получение нужного времени можно уложить чуть ли не в одну-две строки кода.

Вот как пример - начиная отсчет от текущего времени получит время наступления следующих 6:30 ночи или 18:30 вечера.
Java:
long time = new SchedulingPattern("30 6 * * *|30 18 * * *").next(System.currentTimeMillis());

Мобы появляются, но когда я бью их, они куда-то телепортируются.
Если у тебя мобы в процессе телепортируются в разные места по времени, то подозреваю что ты просто не обновляешь после телепортации им точку спавна на актуальную и в итоге при атаке срабатывает проверка "моб слишком далеко ушел от точки спавна - надо вернуть его туда".
 
Последнее редактирование:
С Calendar будет слишком уж громоздкий и запутанный код расчетов такого времени, имхо.
Тут лучше и удобней будет использовать работу с временем в стиле Cron для получений времени спавна и т.д., например через класс SchedulingPattern, который можно стянуть из того же овера, если в люцере нет ничего похожего. Ну или можно прицепить какую нибудь либу для работы с этим, например , правда это как из пушки по воробьям будет в этом случае :)
Ну а в случае с SchedulingPattern полчение нужного времени можно уложить чуть ли не в одну строчку кода.
Расчет будет не так часто происходить, с календарем 15 строк уходит на календарь. В календарь массив времени отправляем, он подбирает ближайший спавн
Если временные рамки раз в 3 часа, плюс рандом, то календарь вовсе не нужен.
Тут как кто хочет так юзает)
 
Ну я у себя для поддержки спавнов в конкретное время как раз в стандартные спавнеры овера впилил поддержку SchedulingPattern, что в целом удобно.
В итоге теперь могу в любом спавне вместо обычного респа через заданное время тупо задать время в виде строки для cron и оно будет работать как от него и ожидается.
Ну т.е. к примеру был респ в час +/- полчаса
XML:
    <spawn>
        <npc id="20001" count="1" respawn="3600" respawn_random="1800" />
        <point x="10000" y="10000" z="0" />
    </spawn>
просто задал вот так и будет респ при наступлении каждого нового четного часа
XML:
    <spawn>
        <npc id="20001" count="1" respawn_time="0 */2 * * *" />
        <point x="10000" y="10000" z="0" />
    </spawn>
 
Необоснованные (без доказательств) обвинения
ThreadPoolManager поможет удалить всех мобов, чтобы удалить нужно при спавне добавить всех мобов в список и через н-время удалять, также будет спавнить мобов по времени календаря
Announcements даст анонсы всем игрокам
Calendar поможет рассчитать время для следующего спавна и время можно хранить в кэше/бд и его передавать в Announcements
Список нужных Location + Rnd по локациям даст рандом локу, которую также можно записать и передать в анонс
малыш ты уже давно устарел и те на ком ты наварил бабок же давно поумнели
PS2 а твой совет это просто совет школьника а ты орая я протгер прогер
 
Ну я у себя для поддержки спавнов в конкретное время как раз в стандартные спавнеры овера впилил поддержку SchedulingPattern, что в целом удобно.
В итоге теперь могу в любом спавне вместо обычного респа через заданное время тупо задать время в виде строки для cron и оно будет работать как от него и ожидается.
Ну т.е. к примеру был респ в час +/- полчаса
XML:
    <spawn>
        <npc id="20001" count="1" respawn="3600" respawn_random="1800" />
        <point x="10000" y="10000" z="0" />
    </spawn>
просто задал вот так и будет респ при наступлении каждого нового четного часа
XML:
    <spawn>
        <npc id="20001" count="1" respawn_time="0 */2 * * *" />
        <point x="10000" y="10000" z="0" />
    </spawn>
Это хороший пример, но в моем случае все немного иначе.

Вот текущий код, как я загружаю монстров из xml-файла. Теперь у меня нет проблем, когда я бью монстра. (Он не телепортируется). Единственная проблема заключается в том, что код порождает монстров во всех зонах, а не только в активной зоне на текущий день.

Вот текущий код, как я загружаю монстров из xml-файла. Теперь у меня нет проблем, когда я бью монстра. (Он не телепортируется). Единственная проблема заключается в том, что код порождает монстров во всех зонах, а не только в активной зоне на текущий день.
В целом, мой код не хочет депаунить монстров в 00:00.
Кстати, у некоторых монстров время респауна 60 секунд, а у некоторых 800 секунд, так что я не могу использовать ваш пример с cron. Это будет хорошо для рейдовых боссов.

Java:
public class TeleporterInstance extends MerchantInstance {
    private static final String DATA_PATH = "data/spawn/";

    private static ScheduledFuture<?> zoneRotationTask;
    private static List<NpcInstance> activeNpcs = new ArrayList<>();

    // Constructor for TeleporterInstance
    public TeleporterInstance(int objectId, NpcTemplate template) {
        super(objectId, template);
        startAutoZoneRotation();  // Automatically start zone rotation when NPC is created
    }

    // Automatically schedules zone rotation every day at midnight
    public static void startAutoZoneRotation() {
        runZoneRotation(); // Perform an immediate rotation
        long timeUntilNextDay = calculateTimeUntilMidnight();

        // Schedule daily zone rotation at 00:00
        zoneRotationTask = ThreadPoolManager.getInstance().scheduleAtFixedRate(TeleporterInstance::runZoneRotation,
                timeUntilNextDay,
                86400000); // 24 hours
    }

    // Run the zone rotation logic (spawn/despawn NPCs)
    public static void runZoneRotation() {
        // Get the current day of the week to determine the active zone
        DayOfWeek currentDay = LocalDate.now().getDayOfWeek();
        String dayName = currentDay.name().toLowerCase(); // Get day in lowercase (e.g., "monday")

        // Load NPCs from XML based on the day of the week
        loadNpcsForDay(dayName);
    }

    // Load NPCs for the current day from XML files
    public static void loadNpcsForDay(String dayName) {
        // Define zone names for each day and load respective XML files
        String[] zones = {"devilsisle", "cruma_marshlands", "pagan_temple", "ruins_of_despair"};

        // Despawn current NPCs, if any
        despawnNpcs();

        // Load and spawn NPCs for each zone
        for (String zone : zones) {
            String filename = DATA_PATH + dayName + "_" + zone + ".xml";
            spawnNpcsFromXml(filename);
        }

        // Announce the new active zone to players
        Announcements.getInstance().announceByCustomMessage("CustomZonesEvent.ZoneActive." + dayName, null);
    }

    // Spawn NPCs from the given XML file
    private static void spawnNpcsFromXml(String filename) {
        try {
            // Initialize the XML parser
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document doc = builder.parse(new File(filename));

            NodeList spawnList = doc.getElementsByTagName("spawn");

            for (int i = 0; i < spawnList.getLength(); i++) {
                Node spawnNode = spawnList.item(i);
                if (spawnNode.getNodeType() == Node.ELEMENT_NODE) {
                    Element spawnElement = (Element) spawnNode;

                    // Get the <npc> element inside <spawn>
                    NodeList npcList = spawnElement.getElementsByTagName("npc");

                    for (int j = 0; j < npcList.getLength(); j++) {
                        Element npcElement = (Element) npcList.item(j);

                        // Extract npc attributes
                        int npcId = Integer.parseInt(npcElement.getAttribute("id"));
                        int respawnTime = Integer.parseInt(npcElement.getAttribute("respawn"));

                        // Extract the position from the 'pos' attribute
                        String pos = npcElement.getAttribute("pos");
                        String[] positionData = pos.split(" ");

                        int x = Integer.parseInt(positionData[0]);
                        int y = Integer.parseInt(positionData[1]);
                        int z = Integer.parseInt(positionData[2]);
                        int heading = Integer.parseInt(positionData[3]);  // Optional, for future use

                        // Spawn the NPC and set respawn timer
                        spawnAndRespawnNpc(npcId, x, y, z, respawnTime);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // Method to spawn and respawn an NPC after a certain delay
    private static void spawnAndRespawnNpc(int npcId, int x, int y, int z, int respawnTime) {
        Location spawnLocation = new Location(x, y, z);
        NpcInstance npc = NpcHolder.getInstance().getTemplate(npcId).getNewInstance();

        // Spawn the NPC at the specified location
        npc.spawnMe(spawnLocation);

        // Prevent the NPC from walking (set AI to idle)
        npc.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);

        // Add to the active NPC list
        activeNpcs.add(npc);

        // Schedule the NPC to respawn after the specified time
        ThreadPoolManager.getInstance().schedule(() -> {
            // Despawn the NPC and respawn it after the delay
            if (!npc.isDeleted()) {
                npc.deleteMe();
                activeNpcs.remove(npc);
            }
            spawnAndRespawnNpc(npcId, x, y, z, respawnTime);  // Recursively respawn the NPC
        }, respawnTime * 1000L);  // Convert respawn time to milliseconds
    }
 
Единственная проблема заключается в том, что код порождает монстров во всех зонах, а не только в активной зоне на текущий день.
мне кажется или ты вон в loadNpcsForDay как раз по всем зонам пробегаешься циклом и потому у тебя и везде спавн идет?
почему вместо этого просто одну не выбирать, случайным образмо там или последовательно.

З.Ы. в люцере поддержки групп спавнов нет кстати что ли? а то вместо подгрузки разных файлов спавнов можно было бы манипулировать посто спавном/деспавном по именам групп.
 
Последнее редактирование:
мне кажется или ты вон в loadNpcsForDay как раз по всем зонам пробегаешься циклом и потому у тебя и везде спавн идет?
почему вместо этого просто одну не выбирать, случайным образмо там или последовательно.

З.Ы. в люцере поддержки групп спавнов нет кстати что ли? а то вместо подгрузки разных файлов спавнов можно было бы манипулировать посто спавном/деспавном по именам групп.
Хорошая идея с названиями групп.

HTML:
<spawn name="[custom_spawn_group]">
        <npc id="40012" count="1" respawn="60" pos="83313 147901 -3430 52507" />
        <npc id="40040" count="1" respawn="60" pos="44807 188983 -3581 27931" />
        <npc id="40031" count="1" respawn="60" pos="44374 189418 -3581 44315" />
        <npc id="48000" count="1" respawn="60" pos="44054 189613 -3581 44315" />
        <npc id="48004" count="1" respawn="60" pos="44409 188725 -3512 40959" />
</spawn>
Также я могу использовать спаун с помощью cron, но он подходит только для рейдовых боссов.
<spawn name = "[queenant_room]">
<npc id = "29001" count = "1" respawn_cron = "0 19 * * *" pos = "- 21610 181594 -5720 0" />
</spawn>

В отношении loadNpcsForDay я сделал некоторые изменения.
Java:
// Load NPCs for the current day from XML files
    public static void loadNpcsForDay(String dayName) {
        // Define zone names for each day and load respective XML files
        String[] zones = {"devilsisle", "cruma_marshlands", "pagan_temple", "ruins_of_despair"};

        // Despawn NPCs for the previous days
        for (String zone : zones) {
            if (!zone.equals(dayName)) {
                despawnNpcsFromZone(zone);  // Despawn NPCs that are not for the current day
            }
        }

        // Now, spawn NPCs for the current day
        String filename = DATA_PATH + dayName + "_" + "zone" + ".xml";
        spawnNpcsFromXml(filename, dayName);

        // Announce the new active zone to players
        Announcements.getInstance().announceByCustomMessage("CustomZonesEvent.ZoneActive." + dayName, null);
    }

    // Spawn NPCs from the given XML file
    private static void spawnNpcsFromXml(String filename, String zoneName) {
        try {
            // Initialize the XML parser
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document doc = builder.parse(new File(filename));

            NodeList spawnList = doc.getElementsByTagName("spawn");

            List<NpcInstance> spawnedNpcs = new ArrayList<>();

            for (int i = 0; i < spawnList.getLength(); i++) {
                Node spawnNode = spawnList.item(i);
                if (spawnNode.getNodeType() == Node.ELEMENT_NODE) {
                    Element spawnElement = (Element) spawnNode;

                    // Get the <npc> element inside <spawn>
                    NodeList npcList = spawnElement.getElementsByTagName("npc");

                    for (int j = 0; j < npcList.getLength(); j++) {
                        Element npcElement = (Element) npcList.item(j);

                        // Extract npc attributes
                        int npcId = Integer.parseInt(npcElement.getAttribute("id"));
                        int respawnTime = Integer.parseInt(npcElement.getAttribute("respawn"));

                        // Extract the position from the 'pos' attribute
                        String pos = npcElement.getAttribute("pos");
                        String[] positionData = pos.split(" ");

                        int x = Integer.parseInt(positionData[0]);
                        int y = Integer.parseInt(positionData[1]);
                        int z = Integer.parseInt(positionData[2]);

                        // Spawn the NPC and set respawn timer
                        NpcInstance npc = spawnAndRespawnNpc(npcId, x, y, z, respawnTime);
                        spawnedNpcs.add(npc);  // Track the spawned NPC
                    }
                }
            }

            // Store the NPCs in the map, associating them with the zone
            zoneNpcMap.put(zoneName, spawnedNpcs);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // Method to spawn and respawn an NPC after a certain delay
    private static NpcInstance spawnAndRespawnNpc(int npcId, int x, int y, int z, int respawnTime) {
        Location spawnLocation = new Location(x, y, z);
        NpcInstance npc = NpcHolder.getInstance().getTemplate(npcId).getNewInstance();

        // Spawn the NPC at the specified location
        npc.spawnMe(spawnLocation);

        // Prevent the NPC from walking (set AI to idle)
        npc.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);

        // Schedule the NPC to respawn after the specified time
        ThreadPoolManager.getInstance().schedule(() -> {
            // Despawn the NPC and respawn it after the delay
            if (!npc.isDeleted()) {
                npc.deleteMe();
            }
            spawnAndRespawnNpc(npcId, x, y, z, respawnTime);  // Recursively respawn the NPC
        }, respawnTime * 1000L);  // Convert respawn time to milliseconds

        return npc;  // Return the spawned NPC
    }

Если хотите, я могу выслать вам полный код для ознакомления (если вам интересно).
 
Назад
Сверху Снизу