MOD L2BuffRequiredZone (Development)

  • Автор темы Автор темы lBrazza
  • Дата начала Дата начала

lBrazza

Выдающийся
Местный
Сообщения
50
Розыгрыши
0
Репутация
0
Реакции
20
Баллы
1 313
Hey everyone, I'm developing a mod for an area that requires a "buff" to enter and stay inside. This mod checks if the player has the buff; if not, they will be teleported to a location set in the config. The buff is also configured in the XML. Below are the codes, but I'm having trouble adjusting the part where it checks if the player has the buff. When I enter the area, it says I don't have the buff (even though I do), and I'm teleported to a location I didn't set in the config.

Project L2JSunrise

L2BuffRequiredZone:
Java:
package l2r.gameserver.model.zone.type;

import l2r.gameserver.enums.ZoneIdType;
import l2r.gameserver.model.actor.L2Character;
import l2r.gameserver.model.actor.instance.L2PcInstance;
import l2r.gameserver.model.zone.L2ZoneType;

/**
 * A Zone that requires a specific buff to enter. If the player does not have the buff, they will be teleported to a configured location.
 */

public class L2BuffRequiredZone extends L2ZoneType
{
    private int _requiredBuffId; // Required buff ID
    private int _teleportX; // X coordinate to teleport the player
    private int _teleportY; // Y coordinate to teleport the player
    private int _teleportZ; // Z coordinate to teleport the player
    
    public L2BuffRequiredZone(int id)
    {
        super(id);
    }
    
    public void setConfig(int requiredBuffId, int teleportX, int teleportY, int teleportZ)
    {
        _requiredBuffId = requiredBuffId;
        _teleportX = teleportX;
        _teleportY = teleportY;
        _teleportZ = teleportZ;
    }
    
    @Override
    public void setParameter(String name, String value)
    {
        switch (name)
        {
            case "requiredBuffId":
                _requiredBuffId = Integer.parseInt(value);
                break;
            case "teleportX":
                _teleportX = Integer.parseInt(value);
                break;
            case "teleportY":
                _teleportY = Integer.parseInt(value);
                break;
            case "teleportZ":
                _teleportZ = Integer.parseInt(value);
                break;
            default:
                super.setParameter(name, value);
                break;
        }
    }
    
    @Override
    protected void onEnter(L2Character character)
    {
        if (character.isPlayer())
        {
            L2PcInstance player = character.getActingPlayer();
            
            // Check if the player has the required buff
            if (!hasRequiredBuff(player))
            {
                player.sendMessage("You do not have the required buff to enter this zone.");
                teleportOut(player); // Teleports the player out of the zone
            }
            else
            {
                player.sendMessage("You entered the zone with the required buff.");
                player.setInsideZone(ZoneIdType.FLAG, true);
            }
        }
    }
    
    @Override
    protected void onExit(L2Character character)
    {
        if (character.isPlayer())
        {
            L2PcInstance player = character.getActingPlayer();
            player.setInsideZone(ZoneIdType.FLAG, false);
            player.sendMessage("You left the zone.");
        }
    }
    
    /**
     * Checks if the player has the required buff.
     * @param player The player to be checked.
     * @return {@code true} if the player has the buff, {@code false} otherwise.
     */
    private boolean hasRequiredBuff(L2PcInstance player)
    {
        if (_requiredBuffId == 0)
        {
            return false; // If no buff is configured, returns false
        }
        
        // Checks if the player has the buff active
        return player.getEffectList().getFirstEffect(_requiredBuffId) != null;
    }
    
    /**
     * Teleports the player to the configured coordinates.
     * @param player The player to be teleported.
     */
    private void teleportOut(L2PcInstance player)
    {
        // Checks if the teleport coordinates are configured
        if ((_teleportX == 0) && (_teleportY == 0) && (_teleportZ == 0))
        {
            player.sendMessage("Teleport location not configured.");
            return;
        }
        
        // Teleports the player
        player.teleToLocation(_teleportX, _teleportY, _teleportZ);
        player.sendMessage("You have been teleported out of the zone.");
    }
    
    @Override
    public void onDieInside(L2Character character)
    {
        if (character.isPlayer())
        {
            L2PcInstance player = character.getActingPlayer();
            player.sendMessage("You died inside the zone.");
        }
    }
    
    @Override
    public void onReviveInside(L2Character character)
    {
        if (character.isPlayer())
        {
            L2PcInstance player = character.getActingPlayer();
            player.sendMessage("You revived inside the zone.");
        }
    }
}


BuffRequiredZoneLoader:

Java:
package l2r.gameserver.data.xml.impl;

import java.io.File;
import java.util.logging.Logger;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import l2r.gameserver.instancemanager.ZoneManager;
import l2r.gameserver.model.zone.L2ZoneForm;
import l2r.gameserver.model.zone.form.ZoneNPoly;
import l2r.gameserver.model.zone.type.L2BuffRequiredZone;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class BuffRequiredZoneLoader
{
    private static final Logger LOGGER = Logger.getLogger(BuffRequiredZoneLoader.class.getName());
    
    public BuffRequiredZoneLoader()
    {
        load();
    }
    
    public void load()
    {
        File xmlFile = new File("data/xml/zones/BuffRequiredZones.xml");
        if (!xmlFile.exists())
        {
            LOGGER.warning("XML file not found: " + xmlFile.getAbsolutePath());
            return;
        }
        
        try
        {
            DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
            Document doc = dBuilder.parse(xmlFile);
            doc.getDocumentElement().normalize();
            parseDocument(doc);
            LOGGER.info("Buff Required Zones loaded successfully!");
        }
        catch (Exception e)
        {
            LOGGER.severe("Error loading BuffRequiredZones: " + e.getMessage());
        }
    }
    
    private void parseDocument(Document doc)
    {
        NodeList zoneList = doc.getElementsByTagName("zone");
        for (int i = 0; i < zoneList.getLength(); i++)
        {
            Node zoneNode = zoneList.item(i);
            if (zoneNode.getNodeType() == Node.ELEMENT_NODE)
            {
                Element zoneElement = (Element) zoneNode;
                
                try
                {
                    // Read zone attributes
                    int id = Integer.parseInt(zoneElement.getAttribute("id"));
                    String name = zoneElement.getAttribute("name");
                    int minZ = Integer.parseInt(zoneElement.getAttribute("minZ"));
                    int maxZ = Integer.parseInt(zoneElement.getAttribute("maxZ"));
                    
                    int requiredBuffId = Integer.parseInt(zoneElement.getAttribute("requiredBuffId"));
                    int teleportX = Integer.parseInt(zoneElement.getAttribute("teleportX"));
                    int teleportY = Integer.parseInt(zoneElement.getAttribute("teleportY"));
                    int teleportZ = Integer.parseInt(zoneElement.getAttribute("teleportZ"));
                    
                    LOGGER.info("[DEBUG] BuffID loaded: " + requiredBuffId + ", Teleport: (" + teleportX + ", " + teleportY + ", " + teleportZ + ")");
                    
                    // Create the zone
                    L2BuffRequiredZone zone = new L2BuffRequiredZone(id);
                    zone.setConfig(requiredBuffId, teleportX, teleportY, teleportZ);
                    zone.setName(name);
                    
                    // Read the zone nodes (X and Y coordinates)
                    NodeList nodeNodes = zoneElement.getElementsByTagName("node");
                    int[] aX = new int[nodeNodes.getLength()];
                    int[] aY = new int[nodeNodes.getLength()];
                    
                    for (int j = 0; j < nodeNodes.getLength(); j++)
                    {
                        Element nodeElement = (Element) nodeNodes.item(j);
                        aX[j] = Integer.parseInt(nodeElement.getAttribute("X"));
                        aY[j] = Integer.parseInt(nodeElement.getAttribute("Y"));
                    }
                    
                    // Set the zone shape (polygon)
                    L2ZoneForm zoneForm = new ZoneNPoly(aX, aY, minZ, maxZ);
                    zone.setZone(zoneForm);
                    
                    // Add the zone to the ZoneManager
                    ZoneManager.getInstance().addZone(id, zone);
                    LOGGER.info("Zone loaded: ID=" + id + " Name=" + name + " BuffID=" + requiredBuffId);
                }
                catch (Exception e)
                {
                    LOGGER.warning("Error loading the zone: " + e.getMessage());
                }
            }
        }
    }
    
    public static void init()
    {
        new BuffRequiredZoneLoader();
    }
}



XML:
<?xml version="1.0" encoding="UTF-8"?>
<list enabled="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../xsd/zones.xsd">
    <zone id="1" name="buff_zone_example1" minZ="-4142" maxZ="-2142" shape="NPoly" type="BuffRequiredZone" requiredBuffId="23246" teleportX="82698" teleportY="148638" teleportZ="-3464">
        <node X="10536" Y="-109432" />
        <node X="11976" Y="-111640" />
        <node X="12728" Y="-109576" />
        <node X="12952" Y="-109352" />
        <node X="16184" Y="-108552" />
        <node X="16376" Y="-108264" />
        <node X="17688" Y="-107528" />
        <node X="17880" Y="-107240" />
        <node X="20920" Y="-106952" />
        <node X="24088" Y="-107976" />
        <node X="24392" Y="-109320" />
        <node X="24296" Y="-110296" />
        <node X="24200" Y="-113528" />
        <node X="24440" Y="-113720" />
        <node X="24056" Y="-117928" />
        <node X="23496" Y="-120408" />
        <node X="22504" Y="-120744" />
        <node X="22072" Y="-120696" />
        <node X="19752" Y="-120328" />
        <node X="18792" Y="-120696" />
        <node X="17000" Y="-120568" />
        <node X="16008" Y="-120008" />
        <node X="15637" Y="-118905" />
        <node X="15224" Y="-116872" />
        <node X="14984" Y="-116776" />
        <node X="14424" Y="-115976" />
        <node X="14392" Y="-115416" />
        <node X="11944" Y="-113320" />
        <node X="10552" Y="-116120" />
    </zone>
</list>
 

1. Where is setParameter is called? Place a breakpoint to start of this method to be sure that your are not overriding _requiredBuffId
2. Are you sure that your code is not create new instance of BuffRequiredZoneLoader before calling onEnter? I that case your config will be empty if you not call setConfig
3. An finally place a breakpoint to your getFirstEffect and check if your pick effect by id logic is fine
 
1. Where is setParameter is called? Place a breakpoint to start of this method to be sure that your are not overriding _requiredBuffId
2. Are you sure that your code is not create new instance of BuffRequiredZoneLoader before calling onEnter? I that case your config will be empty if you not call setConfig
3. An finally place a breakpoint to your getFirstEffect and check if your pick effect by id logic is fine
Okay, I'll make these adjustments and investigate further and come back with feedback.
 
Okay, I'll make these adjustments and investigate further and come back with feedback.
1. Where is setParameter is called? Place a breakpoint to start of this method to be sure that your are not overriding _requiredBuffId
2. Are you sure that your code is not create new instance of BuffRequiredZoneLoader before calling onEnter? I that case your config will be empty if you not call setConfig
3. An finally place a breakpoint to your getFirstEffect and check if your pick effect by id logic is fine


I keep having the same problem
 
Не код, а п**н*г**афия какая-то...
Зачем-то отдельный парсер только под такой тип зон, сама обработка этих зон...

Тут можно было бы обойтись банальнейшим и простым листенером зон, навешанным на нужные зоны. Или в этой сборке листенеров зон нет?

Чисто как пример, набросанная на коленке буквально за пару минут, простейшая реализация подобных зон через листенер, для серверов на базе овера.
Java:
package listeners.zones;

import l2p.gameserver.listener.zone.OnZoneEnterLeaveListener;
import l2p.gameserver.model.Creature;
import l2p.gameserver.model.Location;
import l2p.gameserver.model.Zone;
import l2p.gameserver.scripts.ScriptFile;
import l2p.gameserver.utils.ReflectionUtils;
import l2p.gameserver.utils.Strings;

public class BuffReqZone implements ScriptFile
{
    private static final String[] _zones = { "[zone_name1]", "[zone_name2]", "[zone_name3]" };
    private static final ZoneListener _listener = new ZoneListener();

    @Override
    public void onLoad()
    {
        for (String name : _zones)
        {
            Zone zone = ReflectionUtils.getZone(name);

            if (zone != null)
                zone.addListener(_listener);
        }
    }

    private static class ZoneListener implements OnZoneEnterLeaveListener
    {
        @Override
        public void onEnter(Zone zone, Creature cha)
        {
            if (!cha.isPlayer() || !zone.isActive())
                return;

            int skillId = zone.getParams().getInteger("skillId", 0);

            if (skillId > 0 && !cha.getEffectList().checkEffects(skillId))
            {
                Location loc = Location.parse(zone.getParams().getString("loc", Strings.EMPTY));

                if (loc != null)
                    cha.teleToLocation(loc);
            }
        }

        @Override
        public void onLeave(Zone zone, Creature cha)
        {}
    }
}
 
Последнее редактирование:
Please be consistent and go ahead to answer my questions step by step with results you've observed :)
Не код, а п**н*г**афия какая-то...
Зачем-то отдельный парсер только под такой тип зон, сама обработка этих зон...

Тут можно было бы обойтись банальнейшим и простым листенером зон, навешанным на нужные зоны. Или в этой сборке листенеров зон нет?

Чисто как пример, набросанная на коленке буквально за пару минут, простейшая реализация подобных зон через листенер, для серверов на базе овера.
Java:
package listeners.zones;

import l2p.gameserver.listener.zone.OnZoneEnterLeaveListener;
import l2p.gameserver.model.Creature;
import l2p.gameserver.model.Location;
import l2p.gameserver.model.Zone;
import l2p.gameserver.scripts.ScriptFile;
import l2p.gameserver.utils.ReflectionUtils;
import l2p.gameserver.utils.Strings;

public class BuffReqZone implements ScriptFile
{
    private static final String[] _zones = { "[zone_name1]", "[zone_name2]", "[zone_name3]" };
    private static final ZoneListener _listener = new ZoneListener();

    @Override
    public void onLoad()
    {
        for (String name : _zones)
        {
            Zone zone = ReflectionUtils.getZone(name);

            if (zone != null)
                zone.addListener(_listener);
        }
    }

    private static class ZoneListener implements OnZoneEnterLeaveListener
    {
        @Override
        public void onEnter(Zone zone, Creature cha)
        {
            if (!cha.isPlayer() || !zone.isActive())
                return;

            int skillId = zone.getParams().getInteger("skillId", 0);

            if (skillId > 0 && !cha.getEffectList().checkEffects(skillId))
            {
                Location loc = Location.parse(zone.getParams().getString("loc", Strings.EMPTY));

                if (loc != null)
                    cha.teleToLocation(loc);
            }
        }

        @Override
        public void onLeave(Zone zone, Creature cha)
        {}
    }
}


It's just that I'm new to this, so I don't know much about it.
 
Не код, а п**н*г**афия какая-то...
Зачем-то отдельный парсер только под такой тип зон, сама обработка этих зон...

Тут можно было бы обойтись банальнейшим и простым листенером зон, навешанным на нужные зоны. Или в этой сборке листенеров зон нет?

Чисто как пример, набросанная на коленке буквально за пару минут, простейшая реализация подобных зон через листенер, для серверов на базе овера.
Java:
package listeners.zones;

import l2p.gameserver.listener.zone.OnZoneEnterLeaveListener;
import l2p.gameserver.model.Creature;
import l2p.gameserver.model.Location;
import l2p.gameserver.model.Zone;
import l2p.gameserver.scripts.ScriptFile;
import l2p.gameserver.utils.ReflectionUtils;
import l2p.gameserver.utils.Strings;

public class BuffReqZone implements ScriptFile
{
    private static final String[] _zones = { "[zone_name1]", "[zone_name2]", "[zone_name3]" };
    private static final ZoneListener _listener = new ZoneListener();

    @Override
    public void onLoad()
    {
        for (String name : _zones)
        {
            Zone zone = ReflectionUtils.getZone(name);

            if (zone != null)
                zone.addListener(_listener);
        }
    }

    private static class ZoneListener implements OnZoneEnterLeaveListener
    {
        @Override
        public void onEnter(Zone zone, Creature cha)
        {
            if (!cha.isPlayer() || !zone.isActive())
                return;

            int skillId = zone.getParams().getInteger("skillId", 0);

            if (skillId > 0 && !cha.getEffectList().checkEffects(skillId))
            {
                Location loc = Location.parse(zone.getParams().getString("loc", Strings.EMPTY));

                if (loc != null)
                    cha.teleToLocation(loc);
            }
        }

        @Override
        public void onLeave(Zone zone, Creature cha)
        {}
    }
}

Friend, I managed to do it using your approach, much simpler and more practical, but I just have a doubt, I added some lines to my zonemanager, I wanted to know if I can really use it this way:

Java:
// Read specific attributes from BuffReqZone (only if it is of type BuffReqZone)
                      int requiredBuffId = 0;
                    int teleportX = 0;
                    int teleportY = 0;
                    int teleportZ = 0;
                    
                    if (zoneType.equalsIgnoreCase("BuffReqZone"))
                    {
                        requiredBuffId = parseInteger(attrs, "requiredBuffId");
                        teleportX = parseInteger(attrs, "teleportX");
                        teleportY = parseInteger(attrs, "teleportY");
                        teleportZ = parseInteger(attrs, "teleportZ");
                        
// Log for debugging
                        LOGGER.info("[ZoneManager] Carregando zona BuffReqZone: type=" + zoneType + ", id=" + zoneId + ", name=" + zoneName);
                        LOGGER.info("[ZoneManager] requiredBuffId=" + requiredBuffId + ", teleportX=" + teleportX + ", teleportY=" + teleportY + ", teleportZ=" + teleportZ);
                    }

// Pass specific parameters to BuffReqZone (only if it is of type BuffReqZone)

                     if (temp instanceof L2BuffReqZone)
                        {
                            ((L2BuffReqZone) temp).setParameter("requiredBuffId", String.valueOf(requiredBuffId));
                            ((L2BuffReqZone) temp).setParameter("teleportX", String.valueOf(teleportX));
                            ((L2BuffReqZone) temp).setParameter("teleportY", String.valueOf(teleportY));
                            ((L2BuffReqZone) temp).setParameter("teleportZ", String.valueOf(teleportZ));
                        }

Below is the complete code as I am using it:
Java:
package l2r.gameserver.model.zone.type;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
import java.util.logging.Logger;

import l2r.gameserver.ThreadPoolManager;
import l2r.gameserver.model.actor.L2Character;
import l2r.gameserver.model.actor.instance.L2PcInstance;
import l2r.gameserver.model.zone.L2ZoneType;

public class L2BuffReqZone extends L2ZoneType
{
    private static final Logger LOGGER = Logger.getLogger(L2BuffReqZone.class.getName());
    private static final Map<L2PcInstance, ScheduledFuture<?>> _tasks = new ConcurrentHashMap<>();
    
    private int _requiredBuffId = 0; // ID do buff requerido
    private int _teleportX = 0; // Coordenada X para teleportar o jogador
    private int _teleportY = 0; // Coordenada Y para teleportar o jogador
    private int _teleportZ = 0; // Coordenada Z para teleportar o jogador
    
    public L2BuffReqZone(int id)
    {
        super(id);
        LOGGER.info("[L2BuffReqZone] Zona criada com ID: " + id); // Log para depuração
    }
    
    @Override
    public void setParameter(String name, String value)
    {
        LOGGER.info("[L2BuffReqZone] setParameter: name=" + name + ", value=" + value); // Log para depuração
        switch (name)
        {
            case "requiredBuffId":
                _requiredBuffId = Integer.parseInt(value);
                break;
            case "teleportX":
                _teleportX = Integer.parseInt(value);
                break;
            case "teleportY":
                _teleportY = Integer.parseInt(value);
                break;
            case "teleportZ":
                _teleportZ = Integer.parseInt(value);
                break;
            default:
                super.setParameter(name, value);
                break;
        }
    }
    
    @Override
    protected void onEnter(L2Character character)
    {
        if (character.isPlayer())
        {
            L2PcInstance player = character.getActingPlayer();
            
            // Log para depuração
            LOGGER.info("[L2BuffReqZone] onEnter: requiredBuffId=" + _requiredBuffId + ", teleportX=" + _teleportX + ", teleportY=" + _teleportY + ", teleportZ=" + _teleportZ);
            
            // Verifica se os parâmetros são válidos
            if ((_requiredBuffId == 0) || ((_teleportX == 0) && (_teleportY == 0) && (_teleportZ == 0)))
            {
                LOGGER.warning("[L2BuffReqZone] Parâmetros inválidos na zona: " + getName());
                return;
            }
            
            // Lógica da zona
            if (!hasRequiredBuff(player, _requiredBuffId))
            {
                player.sendMessage("Você precisa do buff necessário para entrar nesta zona.");
                player.teleToLocation(_teleportX, _teleportY, _teleportZ);
            }
            else
            {
                player.sendMessage("Você entrou na Zona Especial. O buff necessário está ativo.");
                monitorBuff(player, _requiredBuffId, _teleportX, _teleportY, _teleportZ);
            }
        }
    }
    
    @Override
    protected void onExit(L2Character character)
    {
        if (character.isPlayer())
        {
            L2PcInstance player = character.getActingPlayer();
            player.sendMessage("Você saiu da Zona Especial.");
            
            ScheduledFuture<?> task = _tasks.remove(player);
            if (task != null)
            {
                task.cancel(true);
            }
        }
    }
    
    private boolean hasRequiredBuff(L2PcInstance player, int buffId)
    {
        return player.getEffectList().getFirstEffect(buffId) != null;
    }
    
    private void monitorBuff(L2PcInstance player, int buffId, int x, int y, int z)
    {
        ScheduledFuture<?> task = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(() ->
        {
            if (!hasRequiredBuff(player, buffId))
            {
                player.sendMessage("Você perdeu o buff necessário e será teleportado para fora da zona.");
                player.teleToLocation(x, y, z);
                ScheduledFuture<?> scheduledTask = _tasks.remove(player);
                if (scheduledTask != null)
                {
                    scheduledTask.cancel(true);
                }
            }
        } , 5000, 5000);
        
        _tasks.put(player, task);
    }
}
 
Назад
Сверху