Dropped SQL spawnlist.

This commit is contained in:
MobiusDev 2018-04-06 01:12:11 +00:00
parent aa520ca56a
commit 3b22c6321f
24 changed files with 38456 additions and 43173 deletions

View File

@ -1,15 +0,0 @@
CREATE TABLE IF NOT EXISTS `custom_spawnlist` (
`location` varchar(40) NOT NULL DEFAULT '',
`count` tinyint(1) unsigned NOT NULL DEFAULT '0',
`npc_templateid` mediumint(7) unsigned NOT NULL DEFAULT '0',
`locx` mediumint(6) NOT NULL DEFAULT '0',
`locy` mediumint(6) NOT NULL DEFAULT '0',
`locz` mediumint(6) NOT NULL DEFAULT '0',
`randomx` mediumint(6) NOT NULL DEFAULT '0',
`randomy` mediumint(6) NOT NULL DEFAULT '0',
`heading` mediumint(6) NOT NULL DEFAULT '0',
`respawn_delay` mediumint(5) NOT NULL DEFAULT '0',
`respawn_random` mediumint(5) NOT NULL DEFAULT '0',
`loc_id` int(9) NOT NULL DEFAULT '0',
`periodOfDay` tinyint(1) unsigned NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

File diff suppressed because it is too large Load Diff

View File

@ -754,13 +754,6 @@ SafeEnchantCostMultipiler = 5
# Custom Components
# ---------------------------------------------------------------------------
# Default: False
CustomSpawnlistTable = True
# Option to save GM spawn only in the custom table.
# Default: False
SaveGmSpawnOnCustom = True
# Default: False
CustomNpcData = True

View File

@ -22,7 +22,8 @@
<tr><td><table width=270 border=0 bgcolor=131210><tr><td width=100><font color="LEVEL">Race</font></td><td align=right width=170>%race%</td></tr></table></td></tr>
<tr><td><table width=270 border=0><tr><td width=100><font color="LEVEL">Territory:</font></td><td align=right width=170>%territory%</td></tr></table></td></tr>
<tr><td><table width=270 border=0 bgcolor=131210><tr><td width=100><font color="LEVEL">Spawn type:</font></td><td align=right width=170>%spawntype%</td></tr></table></td></tr>
<tr><td><table width=270 border=0><tr><td width=100><font color="LEVEL">Spawn loc:</font></td><td align=right width=170>%spawn%</td></tr></table></td></tr>
<tr><td><table width=270 border=0><tr><td width=100><font color="LEVEL">Spawn file:</font></td><td align=right width=170>%spawnfile%</td></tr></table></td></tr>
<tr><td><table width=270 border=0 bgcolor=131210><tr><td width=100><font color="LEVEL">Spawn loc:</font></td><td align=right width=170>%spawn%</td></tr></table></td></tr>
<tr><td><table width=270 border=0><tr><td width=100><font color="LEVEL">Location:</font></td><td align=right width=170>%loc%</td></tr></table></td></tr>
<tr><td><table width=270 border=0 bgcolor=131210><tr><td width=100><font color="LEVEL">Heading:</font></td><td align=right width=170>%heading%</td></tr></table></td></tr>
<tr><td><table width=270 border=0><tr><td width=100><font color="LEVEL">Collision Radius:</font></td><td align=right width=170>%collision_radius%</td></tr></table></td></tr>

View File

@ -279,7 +279,7 @@ public final class NpcLocationInfo extends Quest
if (Util.contains(NPCRADAR, npcId))
{
int x = 0, y = 0, z = 0;
final L2Spawn spawn = SpawnTable.getInstance().findAny(npcId);
final L2Spawn spawn = SpawnTable.getInstance().getAnySpawn(npcId);
if (spawn != null)
{
x = spawn.getX();

View File

@ -79,7 +79,7 @@ public final class RaidbossInfo extends Quest
if (RAIDS.contains(bossId))
{
final L2Spawn spawn = SpawnTable.getInstance().findAny(bossId);
final L2Spawn spawn = SpawnTable.getInstance().getAnySpawn(bossId);
if (spawn != null)
{
final Location loc = spawn.getLocation();

View File

@ -93,9 +93,9 @@ public class Lindvior extends AbstractNpcAI
}
case "start":
{
_lindviorCamera = SpawnTable.getInstance().findAny(LINDVIOR_CAMERA).getLastSpawn();
_tomaris = SpawnTable.getInstance().findAny(TOMARIS).getLastSpawn();
_artius = SpawnTable.getInstance().findAny(ARTIUS).getLastSpawn();
_lindviorCamera = SpawnTable.getInstance().getAnySpawn(LINDVIOR_CAMERA).getLastSpawn();
_tomaris = SpawnTable.getInstance().getAnySpawn(TOMARIS).getLastSpawn();
_artius = SpawnTable.getInstance().getAnySpawn(ARTIUS).getLastSpawn();
startQuestTimer("tomaris_shout1", 1000, _tomaris, null);
startQuestTimer("artius_shout", 60000, _artius, null);
startQuestTimer("tomaris_shout2", 90000, _tomaris, null);

View File

@ -19,6 +19,7 @@ package handlers.actionshifthandlers;
import java.util.Set;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.datatables.SpawnTable;
import com.l2jmobius.gameserver.enums.InstanceType;
import com.l2jmobius.gameserver.handler.IActionShiftHandler;
import com.l2jmobius.gameserver.instancemanager.WalkingManager;
@ -134,15 +135,19 @@ public class L2NpcActionShift implements IActionShiftHandler
}
else if (((L2Npc) target).getSpawn().hasRespawnRandom())
{
html.replace("%resp%", ((L2Npc) target).getSpawn().getRespawnMinDelay() / 1000 + "-" + (((L2Npc) target).getSpawn().getRespawnMaxDelay() / 1000) + " sec");
html.replace("%resp%", (((L2Npc) target).getSpawn().getRespawnMinDelay() / 1000) + "-" + (((L2Npc) target).getSpawn().getRespawnMaxDelay() / 1000) + " sec");
}
else
{
html.replace("%resp%", ((L2Npc) target).getSpawn().getRespawnMinDelay() / 1000 + " sec");
html.replace("%resp%", (((L2Npc) target).getSpawn().getRespawnMinDelay() / 1000) + " sec");
}
final String spawnFile = SpawnTable.getInstance().getSpawnFile(((L2Npc) target).getSpawn().getNpcSpawnTemplateId());
html.replace("%spawnfile%", spawnFile.substring(spawnFile.lastIndexOf("\\") + 1));
}
else
{
html.replace("%spawnfile%", "<font color=FF0000>--</font>");
html.replace("%territory%", "<font color=FF0000>--</font>");
html.replace("%spawntype%", "<font color=FF0000>--</font>");
html.replace("%spawn%", "<font color=FF0000>null</font>");

View File

@ -23,7 +23,6 @@ import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.SevenSigns;
import com.l2jmobius.gameserver.data.xml.impl.AdminData;
import com.l2jmobius.gameserver.data.xml.impl.NpcData;
@ -417,10 +416,6 @@ public class AdminSpawn implements IAdminCommandHandler
try
{
final L2Spawn spawn = new L2Spawn(template);
if (Config.SAVE_GMSPAWN_ON_CUSTOM)
{
spawn.setCustom(true);
}
spawn.setX(target.getX());
spawn.setY(target.getY());
spawn.setZ(target.getZ());

View File

@ -23,7 +23,6 @@ import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.datatables.SpawnTable;
@ -545,10 +544,6 @@ public class AdminTeleport implements IAdminCommandHandler
try
{
spawn = new L2Spawn(target.getTemplate().getId());
if (Config.SAVE_GMSPAWN_ON_CUSTOM)
{
spawn.setCustom(true);
}
spawn.setX(activeChar.getX());
spawn.setY(activeChar.getY());
spawn.setZ(activeChar.getZ());
@ -590,10 +585,6 @@ public class AdminTeleport implements IAdminCommandHandler
try
{
final L2Spawn spawnDat = new L2Spawn(target.getId());
if (Config.SAVE_GMSPAWN_ON_CUSTOM)
{
spawn.setCustom(true);
}
spawnDat.setX(activeChar.getX());
spawnDat.setY(activeChar.getY());
spawnDat.setZ(activeChar.getZ());

View File

@ -286,7 +286,7 @@ public class DropSearchBoard implements IParseBoardHandler
case "_bbs_npc_trace":
{
int npcId = Integer.parseInt(params[1]);
L2Spawn spawn = SpawnTable.getInstance().findAny(npcId);
L2Spawn spawn = SpawnTable.getInstance().getAnySpawn(npcId);
if (spawn == null)
{
player.sendMessage("Cannot find any spawn. Maybe dropped by a boss or instance monster.");

View File

@ -267,6 +267,6 @@ public final class Q00604_DaimonTheWhiteEyedPart2 extends Quest
private static boolean isDaimonSpawned()
{
return SpawnTable.getInstance().findAny(DAIMON_THE_WHITE_EYED) != null;
return SpawnTable.getInstance().getAnySpawn(DAIMON_THE_WHITE_EYED) != null;
}
}

View File

@ -280,6 +280,6 @@ public final class Q00625_TheFinestIngredientsPart2 extends Quest
private static boolean isBumbalumpSpawned()
{
return SpawnTable.getInstance().findAny(ICICLE_EMPEROR_BUMBALUMP) != null;
return SpawnTable.getInstance().getAnySpawn(ICICLE_EMPEROR_BUMBALUMP) != null;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<list enabled="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../xsd/spawnlist.xsd">
<list enabled="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../xsd/spawns.xsd">
<spawn name="chapel_guard_spawns">
<AIData>
<disableRandomWalk>true</disableRandomWalk>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<list enabled="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../xsd/spawnlist.xsd">
<list enabled="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../xsd/spawns.xsd">
<spawn zone="aden03_tb2417_01">
<npc id="18283" respawnDelay="90" count="1" /> <!-- Treasure Chest -->
<npc id="21819" respawnDelay="90" count="1" /> <!-- Treasure Chest -->

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<list enabled="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../xsd/spawnlist.xsd">
<list enabled="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../xsd/spawns.xsd">
<!-- oren22_2219_a01 -->
<spawn name="smtg_drill_group_01">
<AIData>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<list enabled="false" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../xsd/spawnlist.xsd">
<list enabled="false" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../xsd/spawns.xsd">
<!-- gludio15_1621_01m1 -->
<spawn>
<AIData>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<list enabled="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../xsd/spawnlist.xsd">
<list enabled="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../xsd/spawns.xsd">
<!-- gludio15_1621_01m1 -->
<spawn zone="turek_orc_zone_01">
<AIData>

View File

@ -646,8 +646,6 @@ public final class Config
public static boolean JAIL_IS_PVP;
public static boolean JAIL_DISABLE_CHAT;
public static boolean JAIL_DISABLE_TRANSACTION;
public static boolean CUSTOM_SPAWNLIST_TABLE;
public static boolean SAVE_GMSPAWN_ON_CUSTOM;
public static boolean CUSTOM_NPC_DATA;
public static boolean CUSTOM_TELEPORT_TABLE;
public static boolean CUSTOM_NPCBUFFER_TABLES;
@ -2008,8 +2006,6 @@ public final class Config
JAIL_IS_PVP = General.getBoolean("JailIsPvp", false);
JAIL_DISABLE_CHAT = General.getBoolean("JailDisableChat", true);
JAIL_DISABLE_TRANSACTION = General.getBoolean("JailDisableTransaction", false);
CUSTOM_SPAWNLIST_TABLE = General.getBoolean("CustomSpawnlistTable", false);
SAVE_GMSPAWN_ON_CUSTOM = General.getBoolean("SaveGmSpawnOnCustom", false);
CUSTOM_NPC_DATA = General.getBoolean("CustomNpcData", false);
CUSTOM_TELEPORT_TABLE = General.getBoolean("CustomTeleportTable", false);
CUSTOM_NPCBUFFER_TABLES = General.getBoolean("CustomNpcBufferTables", false);

View File

@ -16,14 +16,15 @@
*/
package com.l2jmobius.gameserver.datatables;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
@ -35,50 +36,36 @@ import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import com.l2jmobius.Config;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.commons.util.IGameXmlReader;
import com.l2jmobius.gameserver.data.xml.impl.NpcData;
import com.l2jmobius.gameserver.instancemanager.DayNightSpawnManager;
import com.l2jmobius.gameserver.instancemanager.ZoneManager;
import com.l2jmobius.gameserver.model.L2Spawn;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.templates.L2NpcTemplate;
/**
* Spawn data retriever.
* @author Zoey76
* @author Zoey76, Mobius
*/
public final class SpawnTable implements IGameXmlReader
{
private static final Logger LOGGER = Logger.getLogger(SpawnTable.class.getName());
// SQL
private static final String SELECT_SPAWNS = "SELECT count, npc_templateid, locx, locy, locz, heading, respawn_delay, respawn_random, loc_id, periodOfDay FROM spawnlist";
private static final String SELECT_CUSTOM_SPAWNS = "SELECT count, npc_templateid, locx, locy, locz, heading, respawn_delay, respawn_random, loc_id, periodOfDay FROM custom_spawnlist";
private static final String OTHER_XML_FOLDER = "data/spawns/Others";
private static final Map<Integer, Set<L2Spawn>> _spawnTable = new ConcurrentHashMap<>();
private static final Map<Integer, String> _spawnTemplates = new HashMap<>();
private int _spanwCount = 0;
private int _xmlSpawnCount = 0;
/**
* Wrapper to load all spawns.
*/
@Override
public void load()
{
_spawnTemplates.put(0, "None");
if (!Config.ALT_DEV_NO_SPAWNS)
{
fillSpawnTable(false);
final int spawnCount = _spawnTable.size();
LOGGER.info(getClass().getSimpleName() + ": Loaded " + spawnCount + " npc spawns.");
if (Config.CUSTOM_SPAWNLIST_TABLE)
{
fillSpawnTable(true);
LOGGER.info(getClass().getSimpleName() + ": Loaded " + (_spawnTable.size() - spawnCount) + " custom npc spawns.");
}
// Load XML list
parseDatapackDirectory("data/spawns", false);
LOGGER.info(getClass().getSimpleName() + ": Loaded " + _xmlSpawnCount + " npc spawns from XML.");
LOGGER.info(getClass().getSimpleName() + ": Initializing spawns...");
parseDatapackDirectory("data/spawns", true);
LOGGER.info(getClass().getSimpleName() + ": " + _spanwCount + " spawns have been initialized!");
}
}
@ -179,6 +166,13 @@ public final class SpawnTable implements IGameXmlReader
{
// mandatory
final int templateId = parseInteger(attrs, "id");
// avoid spawning unwanted spawns
if (!checkTemplate(templateId))
{
continue;
}
// coordinates are optional, if territory is specified; mandatory otherwise
int x = 0;
int y = 0;
@ -239,7 +233,9 @@ public final class SpawnTable implements IGameXmlReader
}
}
_xmlSpawnCount += addSpawn(spawnInfo, map);
spawnInfo.set("fileName", f.getPath());
_spanwCount += addSpawn(spawnInfo, map);
}
}
}
@ -248,51 +244,6 @@ public final class SpawnTable implements IGameXmlReader
}
}
/**
* Retrieves spawn data from database.
* @param isCustom if {@code true} the spawns are loaded as custom from custom spawn table
* @return the spawn count
*/
private int fillSpawnTable(boolean isCustom)
{
int npcSpawnCount = 0;
try (Connection con = DatabaseFactory.getInstance().getConnection();
Statement s = con.createStatement();
ResultSet rs = s.executeQuery(isCustom ? SELECT_CUSTOM_SPAWNS : SELECT_SPAWNS))
{
while (rs.next())
{
final StatsSet spawnInfo = new StatsSet();
final int npcId = rs.getInt("npc_templateid");
// Check basic requirements first
if (!checkTemplate(npcId))
{
// Don't spawn
continue;
}
spawnInfo.set("npcTemplateid", npcId);
spawnInfo.set("count", rs.getInt("count"));
spawnInfo.set("x", rs.getInt("locx"));
spawnInfo.set("y", rs.getInt("locy"));
spawnInfo.set("z", rs.getInt("locz"));
spawnInfo.set("heading", rs.getInt("heading"));
spawnInfo.set("respawnDelay", rs.getInt("respawn_delay"));
spawnInfo.set("respawnRandom", rs.getInt("respawn_random"));
spawnInfo.set("locId", rs.getInt("loc_id"));
spawnInfo.set("periodOfDay", rs.getInt("periodOfDay"));
spawnInfo.set("isCustomSpawn", isCustom);
npcSpawnCount += addSpawn(spawnInfo);
}
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Spawn could not be initialized: " + e.getMessage(), e);
}
return npcSpawnCount;
}
/**
* Creates NPC spawn
* @param spawnInfo StatsSet of spawn parameters
@ -315,7 +266,6 @@ public final class SpawnTable implements IGameXmlReader
spawnDat.setLocationId(spawnInfo.getInt("locId", 0));
final String territoryName = spawnInfo.getString("territoryName", "");
final String spawnName = spawnInfo.getString("spawnName", "");
spawnDat.setCustom(spawnInfo.getBoolean("isCustomSpawn", false));
if (!spawnName.isEmpty())
{
spawnDat.setName(spawnName);
@ -347,6 +297,25 @@ public final class SpawnTable implements IGameXmlReader
}
}
final String fileName = spawnInfo.getString("fileName", "None");
if (_spawnTemplates.values().contains(fileName))
{
for (Entry<Integer, String> entry : _spawnTemplates.entrySet())
{
if (entry.getValue().equals(fileName))
{
spawnDat.setSpawnTemplateId(entry.getKey());
break;
}
}
}
else
{
final int newId = _spawnTemplates.size();
_spawnTemplates.put(newId, fileName);
spawnDat.setSpawnTemplateId(newId);
}
addSpawn(spawnDat);
}
catch (Exception e)
@ -358,16 +327,6 @@ public final class SpawnTable implements IGameXmlReader
return ret;
}
/**
* Wrapper for {@link #addSpawn(StatsSet, Map)}.
* @param spawnInfo StatsSet of spawn parameters
* @return count NPC instances, spawned by this spawn
*/
private int addSpawn(StatsSet spawnInfo)
{
return addSpawn(spawnInfo, null);
}
/**
* Gets the spawn data.
* @return the spawn data
@ -398,11 +357,11 @@ public final class SpawnTable implements IGameXmlReader
}
/**
* Finds a spawn for the given NPC ID.
* Gets a spawn for the given NPC ID.
* @param npcId the NPC Id
* @return a spawn for the given NPC ID or {@code null}
*/
public L2Spawn findAny(int npcId)
public L2Spawn getAnySpawn(int npcId)
{
return getSpawns(npcId).stream().findFirst().orElse(null);
}
@ -410,32 +369,93 @@ public final class SpawnTable implements IGameXmlReader
/**
* Adds a new spawn to the spawn table.
* @param spawn the spawn to add
* @param storeInDb if {@code true} it'll be saved in the database
* @param store if {@code true} it'll be saved in the spawn XML files
*/
public void addNewSpawn(L2Spawn spawn, boolean storeInDb)
public void addNewSpawn(L2Spawn spawn, boolean store)
{
addSpawn(spawn);
if (storeInDb)
if (store)
{
final String spawnTable = spawn.isCustom() && Config.CUSTOM_SPAWNLIST_TABLE ? "custom_spawnlist" : "spawnlist";
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement insert = con.prepareStatement("INSERT INTO " + spawnTable + "(count,npc_templateid,locx,locy,locz,heading,respawn_delay,respawn_random,loc_id) values(?,?,?,?,?,?,?,?,?)"))
// Create output directory if it doesn't exist
final File outputDirectory = new File(OTHER_XML_FOLDER);
if (!outputDirectory.exists())
{
insert.setInt(1, spawn.getAmount());
insert.setInt(2, spawn.getId());
insert.setInt(3, spawn.getX());
insert.setInt(4, spawn.getY());
insert.setInt(5, spawn.getZ());
insert.setInt(6, spawn.getHeading());
insert.setInt(7, spawn.getRespawnDelay() / 1000);
insert.setInt(8, spawn.getRespawnMaxDelay() - spawn.getRespawnMinDelay());
insert.setInt(9, spawn.getLocationId());
insert.execute();
boolean result = false;
try
{
outputDirectory.mkdir();
result = true;
}
catch (SecurityException se)
{
// empty
}
if (result)
{
LOGGER.info(getClass().getSimpleName() + ": Created directory: " + OTHER_XML_FOLDER);
}
}
catch (Exception e)
// XML file for spawn
final int x = ((spawn.getX() - L2World.MAP_MIN_X) >> 15) + L2World.TILE_X_MIN;
final int y = ((spawn.getY() - L2World.MAP_MIN_Y) >> 15) + L2World.TILE_Y_MIN;
final File spawnFile = new File(OTHER_XML_FOLDER + "/" + x + "_" + y + ".xml");
// Write info to XML
final String spawnId = String.valueOf(spawn.getId());
final String spawnCount = String.valueOf(spawn.getAmount());
final String spawnX = String.valueOf(spawn.getX());
final String spawnY = String.valueOf(spawn.getY());
final String spawnZ = String.valueOf(spawn.getZ());
final String spawnHeading = String.valueOf(spawn.getHeading());
final String spawnDelay = String.valueOf(spawn.getRespawnDelay() / 1000);
if (spawnFile.exists()) // update
{
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Could not store spawn in the DB:" + e.getMessage(), e);
final File tempFile = new File(spawnFile.getAbsolutePath().substring(Config.DATAPACK_ROOT.getAbsolutePath().length() + 1).replace('\\', '/') + ".tmp");
try
{
final BufferedReader reader = new BufferedReader(new FileReader(spawnFile));
final BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile));
String currentLine;
while ((currentLine = reader.readLine()) != null)
{
if (currentLine.contains("</spawn>"))
{
writer.write(" <npc id=\"" + spawnId + (spawn.getAmount() > 1 ? "\" count=\"" + spawnCount : "") + "\" x=\"" + spawnX + "\" y=\"" + spawnY + "\" z=\"" + spawnZ + (spawn.getHeading() > 0 ? "\" heading=\"" + spawnHeading : "") + "\" respawnDelay=\"" + spawnDelay + "\" /> <!-- " + NpcData.getInstance().getTemplate(spawn.getId()).getName() + " -->" + Config.EOL);
writer.write(currentLine + Config.EOL);
continue;
}
writer.write(currentLine + Config.EOL);
}
writer.close();
reader.close();
spawnFile.delete();
tempFile.renameTo(spawnFile);
}
catch (Exception e)
{
LOGGER.warning(getClass().getSimpleName() + ": Could not store spawn in the spawn XML files: " + e);
}
}
else // new file
{
try
{
final BufferedWriter writer = new BufferedWriter(new FileWriter(spawnFile));
writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + Config.EOL);
writer.write("<list enabled=\"true\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"../../xsd/spawns.xsd\">" + Config.EOL);
writer.write(" <spawn name=\"" + x + "_" + y + "\">" + Config.EOL);
writer.write(" <npc id=\"" + spawnId + (spawn.getAmount() > 1 ? "\" count=\"" + spawnCount : "") + "\" x=\"" + spawnX + "\" y=\"" + spawnY + "\" z=\"" + spawnZ + (spawn.getHeading() > 0 ? "\" heading=\"" + spawnHeading : "") + "\" respawnDelay=\"" + spawnDelay + "\" /> <!-- " + NpcData.getInstance().getTemplate(spawn.getId()).getName() + " -->" + Config.EOL);
writer.write(" </spawn>" + Config.EOL);
writer.write("</list>" + Config.EOL);
writer.close();
LOGGER.info(getClass().getSimpleName() + ": Created file: " + OTHER_XML_FOLDER + "/" + x + "_" + y + ".xml");
}
catch (Exception e)
{
LOGGER.warning(getClass().getSimpleName() + ": Spawn " + spawn + " could not be added to the spawn XML files: " + e);
}
}
}
}
@ -443,30 +463,84 @@ public final class SpawnTable implements IGameXmlReader
/**
* Delete an spawn from the spawn table.
* @param spawn the spawn to delete
* @param updateDb if {@code true} database will be updated
* @param update if {@code true} the spawn XML files will be updated
*/
public void deleteSpawn(L2Spawn spawn, boolean updateDb)
public void deleteSpawn(L2Spawn spawn, boolean update)
{
if (!removeSpawn(spawn))
{
return;
}
if (updateDb)
if (update)
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement delete = con.prepareStatement("DELETE FROM " + (spawn.isCustom() ? "custom_spawnlist" : "spawnlist") + " WHERE locx=? AND locy=? AND locz=? AND npc_templateid=? AND heading=?"))
final int x = ((spawn.getX() - L2World.MAP_MIN_X) >> 15) + L2World.TILE_X_MIN;
final int y = ((spawn.getY() - L2World.MAP_MIN_Y) >> 15) + L2World.TILE_Y_MIN;
final int npcSpawnTemplateId = spawn.getNpcSpawnTemplateId();
final File spawnFile = npcSpawnTemplateId != -1 ? new File(_spawnTemplates.get(npcSpawnTemplateId)) : new File(OTHER_XML_FOLDER + "/" + x + "_" + y + ".xml");
final File tempFile = new File(spawnFile.getAbsolutePath().substring(Config.DATAPACK_ROOT.getAbsolutePath().length() + 1).replace('\\', '/') + ".tmp");
try
{
delete.setInt(1, spawn.getX());
delete.setInt(2, spawn.getY());
delete.setInt(3, spawn.getZ());
delete.setInt(4, spawn.getId());
delete.setInt(5, spawn.getHeading());
delete.execute();
final BufferedReader reader = new BufferedReader(new FileReader(spawnFile));
final BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile));
final String spawnId = String.valueOf(spawn.getId());
final String spawnX = String.valueOf(spawn.getX());
final String spawnY = String.valueOf(spawn.getY());
final String spawnZ = String.valueOf(spawn.getZ());
boolean found = false; // in XML you can have more than one spawn with same coords
boolean isMultiLine = false; // in case spawn has more stats
boolean lastLineFound = false; // used to check for empty file
int lineCount = 0;
String currentLine;
while ((currentLine = reader.readLine()) != null)
{
if (!found)
{
if (isMultiLine)
{
if (currentLine.contains("</npc>"))
{
found = true;
}
continue;
}
if (currentLine.contains(spawnId) && currentLine.contains(spawnX) && currentLine.contains(spawnY) && currentLine.contains(spawnZ))
{
if (!currentLine.contains("/>") && !currentLine.contains("</npc>"))
{
isMultiLine = true;
}
else
{
found = true;
}
continue;
}
}
writer.write(currentLine + Config.EOL);
if (currentLine.contains("</list>"))
{
lastLineFound = true;
}
if (!lastLineFound)
{
lineCount++;
}
}
writer.close();
reader.close();
spawnFile.delete();
tempFile.renameTo(spawnFile);
// Delete empty file
if (lineCount < 7)
{
LOGGER.info(getClass().getSimpleName() + ": Deleted empty file: " + spawnFile.getAbsolutePath().substring(Config.DATAPACK_ROOT.getAbsolutePath().length() + 1).replace('\\', '/'));
spawnFile.delete();
}
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Spawn " + spawn + " could not be removed from DB: " + e.getMessage(), e);
LOGGER.warning(getClass().getSimpleName() + ": Spawn " + spawn + " could not be removed from the spawn XML files: " + e);
}
}
}
@ -521,6 +595,11 @@ public final class SpawnTable implements IGameXmlReader
return true;
}
public String getSpawnFile(int templateId)
{
return _spawnTemplates.get(templateId);
}
public static SpawnTable getInstance()
{
return SingletonHolder._instance;

View File

@ -78,12 +78,11 @@ public class L2Spawn implements IPositionable, IIdentifiable, INamable
private Constructor<? extends L2Npc> _constructor;
/** If True a L2NpcInstance is respawned each time that another is killed */
private boolean _doRespawn;
/** If true then spawn is custom */
private boolean _customSpawn;
private static List<SpawnListener> _spawnListeners = new CopyOnWriteArrayList<>();
private final Deque<L2Npc> _spawnedNpcs = new ConcurrentLinkedDeque<>();
private Map<Integer, Location> _lastSpawnPoints;
private boolean _isNoRndWalk = false; // Is no random walk
private int _spawnTemplateId = 0;
/** The task launching the function doSpawn() */
class SpawnTask implements Runnable
@ -389,23 +388,6 @@ public class L2Spawn implements IPositionable, IIdentifiable, INamable
_respawnMaxDelay = date;
}
/**
* Set the spawn as custom.<BR>
* @param custom
*/
public void setCustom(boolean custom)
{
_customSpawn = custom;
}
/**
* @return type of spawn.
*/
public boolean isCustom()
{
return _customSpawn;
}
/**
* Decrease the current number of L2NpcInstance of this L2Spawn and if necessary create a SpawnTask to launch after the respawn Delay. <B><U> Actions</U> :</B>
* <li>Decrease the current number of L2NpcInstance of this L2Spawn</li>
@ -556,10 +538,10 @@ public class L2Spawn implements IPositionable, IIdentifiable, INamable
}
/**
* @param mob
* @param npc
* @return
*/
private L2Npc initializeNpcInstance(L2Npc mob)
private L2Npc initializeNpcInstance(L2Npc npc)
{
int newlocx = 0;
int newlocy = 0;
@ -579,7 +561,7 @@ public class L2Spawn implements IPositionable, IIdentifiable, INamable
{
if (getLocationId() == 0)
{
return mob;
return npc;
}
// Calculate the random position in the location area
@ -607,8 +589,8 @@ public class L2Spawn implements IPositionable, IIdentifiable, INamable
final int randX = newlocx + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE);
final int randY = newlocy + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE);
final boolean isQuestMonster = (mob.getTitle() != null) && mob.getTitle().contains("Quest");
if (mob.isMonster() && !isQuestMonster && !mob.isWalker() && !mob.isInsideZone(ZoneId.NO_BOOKMARK) && (getInstanceId() == 0) && GeoEngine.getInstance().canMoveToTarget(newlocx, newlocy, newlocz, randX, randY, newlocz, getInstanceId()) && !getTemplate().isUndying() && !mob.isRaid() && !mob.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(mob.getId()))
final boolean isQuestMonster = (npc.getTitle() != null) && npc.getTitle().contains("Quest");
if (npc.isMonster() && !isQuestMonster && !npc.isWalker() && !npc.isInsideZone(ZoneId.NO_BOOKMARK) && (getInstanceId() == 0) && GeoEngine.getInstance().canMoveToTarget(newlocx, newlocy, newlocz, randX, randY, newlocz, getInstanceId()) && !getTemplate().isUndying() && !npc.isRaid() && !npc.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getId()))
{
newlocx = randX;
newlocy = randY;
@ -622,69 +604,69 @@ public class L2Spawn implements IPositionable, IIdentifiable, INamable
// newlocz = GeoEngine.getInstance().getHeight(newlocx, newlocy, newlocz);
// }
mob.stopAllEffects();
npc.stopAllEffects();
mob.setIsDead(false);
npc.setIsDead(false);
// Reset decay info
mob.setDecayed(false);
npc.setDecayed(false);
// Set the HP and MP of the L2NpcInstance to the max
mob.setCurrentHpMp(mob.getMaxHp(), mob.getMaxMp());
npc.setCurrentHpMp(npc.getMaxHp(), npc.getMaxMp());
// Clear script variables
if (mob.hasVariables())
if (npc.hasVariables())
{
mob.getVariables().getSet().clear();
npc.getVariables().getSet().clear();
}
// Set is not random walk default value
mob.setIsNoRndWalk(isNoRndWalk());
npc.setIsNoRndWalk(isNoRndWalk());
// Set the heading of the L2NpcInstance (random heading if not defined)
if (getHeading() == -1)
{
mob.setHeading(Rnd.nextInt(61794));
npc.setHeading(Rnd.nextInt(61794));
}
else
{
mob.setHeading(getHeading());
npc.setHeading(getHeading());
}
if (mob instanceof L2Attackable)
if (npc instanceof L2Attackable)
{
((L2Attackable) mob).setChampion(false);
((L2Attackable) npc).setChampion(false);
}
if (Config.L2JMOD_CHAMPION_ENABLE)
{
// Set champion on next spawn
if (mob.isMonster() && !getTemplate().isUndying() && !mob.isRaid() && !mob.isRaidMinion() && (Config.L2JMOD_CHAMPION_FREQUENCY > 0) && (mob.getLevel() >= Config.L2JMOD_CHAMP_MIN_LVL) && (mob.getLevel() <= Config.L2JMOD_CHAMP_MAX_LVL) && (Config.L2JMOD_CHAMPION_ENABLE_IN_INSTANCES || (getInstanceId() == 0)))
if (npc.isMonster() && !getTemplate().isUndying() && !npc.isRaid() && !npc.isRaidMinion() && (Config.L2JMOD_CHAMPION_FREQUENCY > 0) && (npc.getLevel() >= Config.L2JMOD_CHAMP_MIN_LVL) && (npc.getLevel() <= Config.L2JMOD_CHAMP_MAX_LVL) && (Config.L2JMOD_CHAMPION_ENABLE_IN_INSTANCES || (getInstanceId() == 0)))
{
if (Rnd.get(100) < Config.L2JMOD_CHAMPION_FREQUENCY)
{
((L2Attackable) mob).setChampion(true);
((L2Attackable) npc).setChampion(true);
}
}
}
// Reset summoner
mob.setSummoner(null);
npc.setSummoner(null);
// Reset summoned list
mob.resetSummonedNpcs();
npc.resetSummonedNpcs();
// Link the L2NpcInstance to this L2Spawn
mob.setSpawn(this);
npc.setSpawn(this);
// Spawn NPC
mob.spawnMe(newlocx, newlocy, newlocz);
npc.spawnMe(newlocx, newlocy, newlocz);
notifyNpcSpawned(mob);
notifyNpcSpawned(npc);
_spawnedNpcs.add(mob);
_spawnedNpcs.add(npc);
if (_lastSpawnPoints != null)
{
_lastSpawnPoints.put(mob.getObjectId(), new Location(newlocx, newlocy, newlocz));
_lastSpawnPoints.put(npc.getObjectId(), new Location(newlocx, newlocy, newlocz));
}
// Increase the current number of L2NpcInstance managed by this L2Spawn
_currentCount++;
return mob;
return npc;
}
public static void addSpawnListener(SpawnListener listener)
@ -801,6 +783,16 @@ public class L2Spawn implements IPositionable, IIdentifiable, INamable
_isNoRndWalk = value;
}
public void setSpawnTemplateId(int npcSpawnTemplateId)
{
_spawnTemplateId = npcSpawnTemplateId;
}
public int getNpcSpawnTemplateId()
{
return _spawnTemplateId;
}
@Override
public String toString()
{

View File

@ -30,3 +30,4 @@ What is done
-New ThreadPool
-New XML reader
-Replaced MMOCore with Netty
-Dropped SQL spawnlist