Skip to content

Instantly share code, notes, and snippets.

@Williams0ff
Last active September 28, 2024 11:45
Show Gist options
  • Save Williams0ff/f044f95524c805a72fbef9bcad126e1c to your computer and use it in GitHub Desktop.
Save Williams0ff/f044f95524c805a72fbef9bcad126e1c to your computer and use it in GitHub Desktop.
L2jOne - Commands SpawnManeger
diff --git a/aCis_gameserver/java/net/sf/l2j/gameserver/handler/admincommandhandlers/AdminSpawn.java b/aCis_gameserver/java/net/sf/l2j/gameserver/handler/admincommandhandlers/AdminSpawn.java
index 0a20e4a..a367708 100644
--- a/aCis_gameserver/java/net/sf/l2j/gameserver/handler/admincommandhandlers/AdminSpawn.java
+++ b/aCis_gameserver/java/net/sf/l2j/gameserver/handler/admincommandhandlers/AdminSpawn.java
@@ -197,7 +197,7 @@
spawn.setRespawnDelay(respawnTime);
spawn.doSpawn(false);
- SpawnManager.getInstance().addSpawn(spawn);
+ SpawnManager.getInstance().addSpawn(spawn, true);
player.sendMessage("You spawned " + template.getName() + ". - Cmd: " + cmd);
}
@@ -223,7 +224,7 @@
// Npc ASpawn must be Spawn type.
final ASpawn spawn = targetNpc.getSpawn();
- if (!(spawn instanceof Spawn))
+ if (!(spawn instanceof Spawn) && !(spawn instanceof MultiSpawn))
{
player.sendPacket(SystemMessageId.INVALID_TARGET);
return;
@@ -231,9 +232,11 @@
// Delete the Npc.
targetNpc.deleteMe();
-
- // Delete the Spawn entry.
- SpawnManager.getInstance().deleteSpawn((Spawn) spawn);
+
+ if (spawn instanceof MultiSpawn multi)
+ SpawnManager.getInstance().deleteSpawn(multi.getNpcMaker().getName());
+ else if (spawn instanceof Spawn)
+ SpawnManager.getInstance().removeSpawn((Spawn) spawn);
// Send Player log.
player.sendMessage("You deleted " + targetNpc.getName() + ".");
diff --git a/aCis_gameserver/java/net/sf/l2j/gameserver/data/manager/SpawnManager.java b/aCis_gameserver/java/net/sf/l2j/gameserver/data/manager/SpawnManager.java
index 7e4bf6f..2ca0289 100644
--- a/aCis_gameserver/java/net/sf/l2j/gameserver/data/manager/SpawnManager.java
+++ b/aCis_gameserver/java/net/sf/l2j/gameserver/data/manager/SpawnManager.java
@@ -1,5 +1,10 @@
package net.sf.l2j.gameserver.data.manager;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
import java.nio.file.Path;
import java.sql.Connection;
import java.sql.PreparedStatement;
@@ -11,6 +16,13 @@
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
import net.sf.l2j.commons.data.StatSet;
import net.sf.l2j.commons.data.xml.IXmlReader;
import net.sf.l2j.commons.geometry.Triangle;
@@ -22,6 +34,7 @@
import net.sf.l2j.gameserver.data.xml.NpcData;
import net.sf.l2j.gameserver.enums.CabalType;
import net.sf.l2j.gameserver.enums.SealType;
+import net.sf.l2j.gameserver.model.World;
import net.sf.l2j.gameserver.model.actor.Npc;
import net.sf.l2j.gameserver.model.actor.template.NpcTemplate;
import net.sf.l2j.gameserver.model.location.Location;
@@ -37,7 +50,10 @@
import net.sf.l2j.gameserver.scripting.Quest;
import org.w3c.dom.Document;
+import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
/**
* Loads spawn list based on {@link Territory}s and {@link NpcMaker}s.<br>
@@ -58,6 +73,7 @@
private final Set<Spawn> _spawns = ConcurrentHashMap.newKeySet();
private int _dynamicGroupId = 0;
+ private int _index = 1;
public SpawnManager()
{
@@ -785,6 +802,272 @@
}
/**
+ * Adds a new spawn to the spawn table.
+ * @param spawn the spawn to add
+ * @param store if {@code true} it'll be saved in the spawn XML files
+ */
+ public void addSpawn(Spawn spawn, boolean store)
+ {
+ addSpawn(spawn);
+
+ if (store)
+ {
+ // Create output directory if it doesn't exist
+ final File outputDirectory = new File("./data/xml/spawnlist/custom/");
+ if (!outputDirectory.exists())
+ {
+ try
+ {
+ outputDirectory.mkdir();
+ }
+ catch (SecurityException se)
+ {
+ // empty
+ }
+ }
+
+ // index spawn
+ int index = _index++;
+
+ // XML file for spawn
+ final String name = spawn.getNpc().getName().replaceAll("(\\s|')+","").toLowerCase();
+
+ final int x = ((spawn.getLocX() - World.WORLD_X_MIN) >> 15) + World.TILE_X_MIN;
+ final int y = ((spawn.getLocY() - World.WORLD_Y_MIN) >> 15) + World.TILE_Y_MIN;
+ final File spawnFile = new File("./data/xml/spawnlist/custom/" + name + "_" + x + "_" + y + ".xml");
+
+ // Write info to XML
+ final String spawnLoc = String.valueOf(spawn.getLocX() + ";" + spawn.getLocY() + ";" + spawn.getLocZ() + ";" + spawn.getHeading());
+
+ final var respawnDelay = getSpawn(spawn.getNpc().getNpcId()).getRespawnDelay() + "sec";
+
+ if (spawnFile.exists()) // update
+ {
+ final File tempFile = new File("./data/xml/spawnlist/custom/" + name + "_" + x + "_" + y + ".tmp");
+ try (BufferedReader reader = new BufferedReader(new FileReader(spawnFile));
+ BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile)))
+ {
+ String currentLine;
+ while ((currentLine = reader.readLine()) != null)
+ {
+ if (currentLine.contains("</list>"))
+ {
+ writer.write(" <territory name=\"" + name + "_" + x + "_" + y +"_0"+ index + "\" minZ=\"" + (spawn.getLocZ()) + "\" maxZ=\"" + (spawn.getLocZ() + 16) + "\">\n");
+ writer.write(" <node x=\"" + (spawn.getLocX() + 50) + "\" y=\"" + (spawn.getLocY() + 50) + "\" />\n");
+ writer.write(" <node x=\"" + (spawn.getLocX() - 50) + "\" y=\"" + (spawn.getLocY() + 50) + "\" />\n");
+ writer.write(" <node x=\"" + (spawn.getLocX() - 50) + "\" y=\"" + (spawn.getLocY() - 50) + "\" />\n");
+ writer.write(" <node x=\"" + (spawn.getLocX() + 50) + "\" y=\"" + (spawn.getLocY() - 50) + "\" />\n");
+ writer.write(" </territory>\n");
+ writer.write(" <npcmaker name=\"" + name + "_" + x + "_" + y +"_0"+ index + "\" territory=\"" + name + "_" + x + "_" + y +"_0"+ index + "\" maximumNpcs=\"" + 1 + "\">\n");
+ writer.write(" <ai type=\"default_maker\"/>\n");
+ writer.write(" <npc id=\"" + spawn.getNpcId() + "\" pos=\"" + spawnLoc + "\" total=\"" + 1 + "\" respawn=\"" + respawnDelay + "\" /> <!-- " + spawn.getNpc().getName() + " -->\n");
+ writer.write(" </npcmaker>\n");
+ writer.write(currentLine + "\n");
+ continue;
+ }
+ writer.write(currentLine + "\n");
+ }
+ writer.close();
+ reader.close();
+ spawnFile.delete();
+ tempFile.renameTo(spawnFile);
+ }
+ catch (Exception e)
+ {
+ LOGGER.warn("Could not store spawn in the spawn XML files: " + e);
+ }
+ }
+ else // new file
+ {
+ try (BufferedWriter writer = new BufferedWriter(new FileWriter(spawnFile)))
+ {
+ writer.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
+ writer.write("<list>\n");
+ writer.write(" <territory name=\"" + name + "_" + x + "_" + y +"_0"+ index + "\" minZ=\"" + (spawn.getLocZ()) + "\" maxZ=\"" + (spawn.getLocZ() + 16) + "\">\n");
+ writer.write(" <node x=\"" + (spawn.getLocX() + 50) + "\" y=\"" + (spawn.getLocY() + 50) + "\" />\n");
+ writer.write(" <node x=\"" + (spawn.getLocX() - 50) + "\" y=\"" + (spawn.getLocY() + 50) + "\" />\n");
+ writer.write(" <node x=\"" + (spawn.getLocX() - 50) + "\" y=\"" + (spawn.getLocY() - 50) + "\" />\n");
+ writer.write(" <node x=\"" + (spawn.getLocX() + 50) + "\" y=\"" + (spawn.getLocY() - 50) + "\" />\n");
+ writer.write(" </territory>\n");
+ writer.write(" <npcmaker name=\"" + name + "_" + x + "_" + y + "\" territory=\"" + name + "_" + x + "_" + y +"_0"+ index + "\" maximumNpcs=\"" + 1 + "\">\n");
+ writer.write(" <ai type=\"default_maker\"/>\n");
+ writer.write(" <npc id=\"" + spawn.getNpcId() + "\" pos=\"" + spawnLoc + "\" total=\"" + 1 + "\" respawn=\"" + respawnDelay + "\" /> <!-- " + spawn.getNpc().getName() + " -->\n");
+ writer.write(" </npcmaker>\n");
+ writer.write("</list>\n");
+ writer.close();
+ }
+ catch (Exception e)
+ {
+ LOGGER.warn("Spawn " + spawn + " could not be added to the spawn XML files: " + e);
+ }
+ }
+ }
+ }
+
+ /**
+ * Removes the specific NPC from the spawn XML file.
+ * @param spawn the spawn to remove
+ */
+ public void removeSpawn(Spawn spawn)
+ {
+ final String name = spawn.getNpc().getName().replaceAll("(\\s|')+", "").toLowerCase();
+ final int x = ((spawn.getLocX() - World.WORLD_X_MIN) >> 15) + World.TILE_X_MIN;
+ final int y = ((spawn.getLocY() - World.WORLD_Y_MIN) >> 15) + World.TILE_Y_MIN;
+ final File spawnFile = new File("./data/xml/spawnlist/custom/" + name + "_" + x + "_" + y + ".xml");
+
+ if (!spawnFile.exists())
+ {
+ LOGGER.warn("File for spawn {} not found.", spawn);
+ return;
+ }
+
+ try
+ {
+ DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
+ Document doc = dBuilder.parse(spawnFile);
+ doc.getDocumentElement().normalize();
+
+ String territoryName = null;
+
+ NodeList npcMakers = doc.getElementsByTagName("npcmaker");
+ for (int i = 0; i < npcMakers.getLength(); i++)
+ {
+ Element npcMaker = (Element) npcMakers.item(i);
+ NodeList npcs = npcMaker.getElementsByTagName("npc");
+ boolean npcFound = false;
+
+ for (int j = 0; j < npcs.getLength(); j++)
+ {
+ Element npc = (Element) npcs.item(j);
+ if (npc.getAttribute("id").equals(String.valueOf(spawn.getNpcId())))
+ {
+ territoryName = npcMaker.getAttribute("territory");
+ npcFound = true;
+ break;
+ }
+ }
+
+ if (npcFound)
+ {
+ npcMaker.getParentNode().removeChild(npcMaker);
+ break;
+ }
+ }
+
+ if (territoryName != null)
+ {
+ NodeList territories = doc.getElementsByTagName("territory");
+ for (int i = 0; i < territories.getLength(); i++)
+ {
+ Element territory = (Element) territories.item(i);
+ if (territory.getAttribute("name").startsWith(name + "_" + x + "_" + y))
+ {
+ territory.getParentNode().removeChild(territory);
+ break;
+ }
+ }
+ }
+
+ TransformerFactory transformerFactory = TransformerFactory.newInstance();
+ Transformer transformer = transformerFactory.newTransformer();
+ DOMSource source = new DOMSource(doc);
+ StreamResult result = new StreamResult(spawnFile);
+ transformer.transform(source, result);
+
+ LOGGER.info("Successfully removed spawn {} and its territory from XML.", spawn);
+
+ }
+ catch (Exception e)
+ {
+ LOGGER.warn("Could not remove spawn {} from the spawn XML files: {}", spawn, e);
+ }
+ }
+
+ /**
+ * Deletes a spawn associated with a {@link MultiSpawn}, removing both the associated npcMaker and territory.
+ * If no elements remain in the XML file, the file is deleted.
+ * @param spawnName the name of the {@link MultiSpawn} to be deleted
+ */
+ public void deleteSpawn(String spawnName)
+ {
+ _spawns.removeIf(spawn -> spawn.getNpc().getName().equalsIgnoreCase(spawnName));
+
+ String xmlFileName = "./data/xml/spawnlist/custom/" + spawnName + ".xml";
+ File xmlFile = new File(xmlFileName);
+
+ if (xmlFile.exists() && xmlFile.isFile())
+ {
+ try
+ {
+ DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
+ Document doc = docBuilder.parse(xmlFile);
+
+ // Encontrar e remover os NPCs associados ao npcMaker e os territ�rios
+ NodeList npcMakerList = doc.getElementsByTagName("npcmaker");
+ NodeList territoryList = doc.getElementsByTagName("territory");
+
+ boolean nodeRemoved = false;
+
+ for (int i = npcMakerList.getLength() - 1; i >= 0; i--)
+ {
+ Element npcMakerElement = (Element) npcMakerList.item(i);
+ String npcMakerName = npcMakerElement.getAttribute("name");
+
+ if (npcMakerName.equalsIgnoreCase(spawnName))
+ {
+ Node parentNode = npcMakerElement.getParentNode();
+ parentNode.removeChild(npcMakerElement);
+ nodeRemoved = true;
+ }
+ }
+
+ for (int i = territoryList.getLength() - 1; i >= 0; i--)
+ {
+ Element territoryElement = (Element) territoryList.item(i);
+ String territoryName = territoryElement.getAttribute("name");
+
+ if (territoryName.startsWith(spawnName))
+ {
+ Node parentNode = territoryElement.getParentNode();
+ parentNode.removeChild(territoryElement);
+ nodeRemoved = true;
+ }
+ }
+
+ boolean isEmpty = doc.getDocumentElement().getChildNodes().getLength() == 0;
+
+ if (isEmpty)
+ {
+ if (xmlFile.delete())
+ LOGGER.info("Arquivo XML vazio deletado: {}", xmlFileName);
+ else
+ LOGGER.warn("Falha ao deletar o arquivo XML vazio: {}", xmlFileName);
+ }
+ else if (nodeRemoved)
+ {
+ TransformerFactory transformerFactory = TransformerFactory.newInstance();
+ Transformer transformer = transformerFactory.newTransformer();
+ DOMSource source = new DOMSource(doc);
+ StreamResult result = new StreamResult(xmlFile);
+ transformer.transform(source, result);
+ }
+ else
+ LOGGER.warn("Nenhum spawn encontrado para remover no arquivo XML: {}", xmlFileName);
+ }
+ catch (Exception e)
+ {
+ LOGGER.error("Erro ao modificar o arquivo XML de spawn: {}", xmlFileName, e);
+ }
+ }
+ else
+ {
+ LOGGER.warn("Arquivo XML n�o encontrado: {}", xmlFileName);
+ }
+ }
+
+ /**
* Remove an individual {@link Spawn}.
* @param spawn : {@link Spawn} to be removed.
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment