diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/lang/el/NpcNameLocalisation.xml b/L2J_Mobius_1.0_Ertheia/dist/game/data/lang/el/NpcNameLocalisation.xml new file mode 100644 index 0000000000..e260fd7156 --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/lang/el/NpcNameLocalisation.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java index 505e6d91db..9939d6ddcf 100644 --- a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java @@ -37,6 +37,7 @@ import org.l2jmobius.gameserver.data.xml.impl.FishingData; import org.l2jmobius.gameserver.data.xml.impl.ItemCrystallizationData; import org.l2jmobius.gameserver.data.xml.impl.MultisellData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.OptionData; import org.l2jmobius.gameserver.data.xml.impl.PrimeShopData; import org.l2jmobius.gameserver.data.xml.impl.SayuneData; @@ -333,6 +334,7 @@ public class AdminReload implements IAdminCommandHandler SystemMessageId.loadLocalisations(); NpcStringId.loadLocalisations(); SendMessageLocalisationData.getInstance().load(); + NpcNameLocalisationData.getInstance().load(); AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Localisation data."); break; } diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java index 559eaaea12..26f24c4e52 100644 --- a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java @@ -19,9 +19,16 @@ package handlers.voicedcommandhandlers; import java.util.StringTokenizer; import org.l2jmobius.Config; +import org.l2jmobius.commons.concurrent.ThreadPool; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.handler.IVoicedCommandHandler; +import org.l2jmobius.gameserver.model.World; +import org.l2jmobius.gameserver.model.WorldObject; +import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; +import org.l2jmobius.gameserver.network.serverpackets.DeleteObject; import org.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage; +import org.l2jmobius.gameserver.network.serverpackets.NpcInfo; public class Lang implements IVoicedCommandHandler { @@ -61,6 +68,18 @@ public class Lang implements IVoicedCommandHandler { msg.setFile(activeChar, "data/html/mods/Lang/Ok.htm"); activeChar.sendPacket(msg); + for (WorldObject obj : World.getInstance().getVisibleObjects()) + { + if (obj.isNpc() && NpcNameLocalisationData.getInstance().hasLocalisation(obj.getId())) + { + activeChar.sendPacket(new DeleteObject(obj)); + ThreadPool.schedule(() -> + { + activeChar.sendPacket(new NpcInfo((Npc) obj)); + }, 1000); + } + } + activeChar.setTarget(null); return true; } msg.setFile(activeChar, "data/html/mods/Lang/Error.htm"); diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/xsd/NpcNameLocalisation.xsd b/L2J_Mobius_1.0_Ertheia/dist/game/data/xsd/NpcNameLocalisation.xsd new file mode 100644 index 0000000000..b8b185243e --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/xsd/NpcNameLocalisation.xsd @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/java/org/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_1.0_Ertheia/java/org/l2jmobius/gameserver/GameServer.java index 090f88c0ec..37693c723a 100644 --- a/L2J_Mobius_1.0_Ertheia/java/org/l2jmobius/gameserver/GameServer.java +++ b/L2J_Mobius_1.0_Ertheia/java/org/l2jmobius/gameserver/GameServer.java @@ -75,6 +75,7 @@ import org.l2jmobius.gameserver.data.xml.impl.KarmaData; import org.l2jmobius.gameserver.data.xml.impl.LuckyGameData; import org.l2jmobius.gameserver.data.xml.impl.MultisellData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.OptionData; import org.l2jmobius.gameserver.data.xml.impl.PetDataTable; import org.l2jmobius.gameserver.data.xml.impl.PetSkillData; @@ -341,6 +342,7 @@ public class GameServer if (Config.MULTILANG_ENABLE) { SendMessageLocalisationData.getInstance(); + NpcNameLocalisationData.getInstance(); } printSection("Scripts"); diff --git a/L2J_Mobius_1.0_Ertheia/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java b/L2J_Mobius_1.0_Ertheia/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java new file mode 100644 index 0000000000..e374cd78a5 --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java @@ -0,0 +1,126 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.l2jmobius.gameserver.data.xml.impl; + +import java.io.File; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Logger; + +import org.w3c.dom.Document; + +import org.l2jmobius.Config; +import org.l2jmobius.commons.util.IXmlReader; +import org.l2jmobius.gameserver.model.StatsSet; + +/** + * @author Mobius + */ +public class NpcNameLocalisationData implements IXmlReader +{ + private final static Logger LOGGER = Logger.getLogger(NpcNameLocalisationData.class.getName()); + + private final static Map> NPC_NAME_LOCALISATIONS = new ConcurrentHashMap<>(); + private static String _lang; + + protected NpcNameLocalisationData() + { + load(); + } + + @Override + public void load() + { + NPC_NAME_LOCALISATIONS.clear(); + + if (Config.MULTILANG_ENABLE) + { + for (String lang : Config.MULTILANG_ALLOWED) + { + final File file = new File("data/lang/" + lang + "/NpcNameLocalisation.xml"); + if (!file.isFile()) + { + continue; + } + + NPC_NAME_LOCALISATIONS.put(lang, new ConcurrentHashMap()); + _lang = lang; + parseDatapackFile("data/lang/" + lang + "/NpcNameLocalisation.xml"); + final int count = NPC_NAME_LOCALISATIONS.get(lang).values().size(); + if (count == 0) + { + NPC_NAME_LOCALISATIONS.remove(lang); + } + else + { + LOGGER.info(getClass().getSimpleName() + ": Loaded localisations for '" + lang + "'"); + } + } + } + } + + @Override + public void parseDocument(Document doc, File f) + { + forEach(doc, "list", listNode -> forEach(listNode, "localisation", localisationNode -> + { + final StatsSet set = new StatsSet(parseAttributes(localisationNode)); + NPC_NAME_LOCALISATIONS.get(_lang).put(set.getInt("id"), new String[] + { + set.getString("name"), + set.getString("title") + }); + })); + } + + /** + * @param lang + * @param id + * @return a String Array[] that contains NPC name and title or Null if is does not exist. + */ + public String[] getLocalisation(String lang, int id) + { + final Map localisations = NPC_NAME_LOCALISATIONS.get(lang); + if (localisations != null) + { + return localisations.get(id); + } + return null; + } + + public boolean hasLocalisation(int id) + { + for (Map data : NPC_NAME_LOCALISATIONS.values()) + { + if (data.containsKey(id)) + { + return true; + } + } + return false; + } + + public static NpcNameLocalisationData getInstance() + { + return SingletonHolder.INSTANCE; + } + + private static class SingletonHolder + { + protected static final NpcNameLocalisationData INSTANCE = new NpcNameLocalisationData(); + } +} diff --git a/L2J_Mobius_1.0_Ertheia/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java b/L2J_Mobius_1.0_Ertheia/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java index cbe6566430..4fce9f5617 100644 --- a/L2J_Mobius_1.0_Ertheia/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java +++ b/L2J_Mobius_1.0_Ertheia/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java @@ -67,6 +67,7 @@ import org.l2jmobius.gameserver.data.xml.impl.ClassListData; import org.l2jmobius.gameserver.data.xml.impl.ExperienceData; import org.l2jmobius.gameserver.data.xml.impl.HennaData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.PetDataTable; import org.l2jmobius.gameserver.data.xml.impl.PlayerTemplateData; import org.l2jmobius.gameserver.data.xml.impl.PlayerXpPercentLostData; @@ -11658,7 +11659,19 @@ public final class PlayerInstance extends Playable { sm = new SystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2); sm.addPcName(this); - sm.addString(target.getName()); + + // Localisation related. + String targetName = target.getName(); + if (Config.MULTILANG_ENABLE && target.isNpc()) + { + final String[] localisation = NpcNameLocalisationData.getInstance().getLocalisation(_lang, target.getId()); + if (localisation != null) + { + targetName = localisation[0]; + } + } + + sm.addString(targetName); sm.addInt(damage); sm.addPopup(target.getObjectId(), getObjectId(), -damage); } diff --git a/L2J_Mobius_1.0_Ertheia/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java b/L2J_Mobius_1.0_Ertheia/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java index 64d1bdbd1c..df33eb168e 100644 --- a/L2J_Mobius_1.0_Ertheia/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java +++ b/L2J_Mobius_1.0_Ertheia/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java @@ -18,6 +18,7 @@ package org.l2jmobius.gameserver.model.actor.status; import org.l2jmobius.Config; import org.l2jmobius.gameserver.ai.CtrlIntention; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.enums.PrivateStoreType; import org.l2jmobius.gameserver.instancemanager.DuelManager; import org.l2jmobius.gameserver.model.actor.Creature; @@ -253,7 +254,19 @@ public class PlayerStatus extends PlayableStatus // Send a System Message to the PlayerInstance SystemMessage smsg = new SystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2); smsg.addString(getActiveChar().getName()); - smsg.addString(attacker.getName()); + + // Localisation related. + String targetName = attacker.getName(); + if (Config.MULTILANG_ENABLE && attacker.isNpc()) + { + final String[] localisation = NpcNameLocalisationData.getInstance().getLocalisation(getActiveChar().getLang(), attacker.getId()); + if (localisation != null) + { + targetName = localisation[0]; + } + } + + smsg.addString(targetName); smsg.addInt(fullValue); smsg.addPopup(getActiveChar().getObjectId(), attacker.getObjectId(), -fullValue); getActiveChar().sendPacket(smsg); diff --git a/L2J_Mobius_1.0_Ertheia/java/org/l2jmobius/gameserver/network/GameClient.java b/L2J_Mobius_1.0_Ertheia/java/org/l2jmobius/gameserver/network/GameClient.java index 4ed506b02a..ed0f223551 100644 --- a/L2J_Mobius_1.0_Ertheia/java/org/l2jmobius/gameserver/network/GameClient.java +++ b/L2J_Mobius_1.0_Ertheia/java/org/l2jmobius/gameserver/network/GameClient.java @@ -49,6 +49,7 @@ import org.l2jmobius.gameserver.network.serverpackets.ActionFailed; import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; import org.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket; import org.l2jmobius.gameserver.network.serverpackets.LeaveWorld; +import org.l2jmobius.gameserver.network.serverpackets.NpcInfo; import org.l2jmobius.gameserver.network.serverpackets.NpcSay; import org.l2jmobius.gameserver.network.serverpackets.ServerClose; import org.l2jmobius.gameserver.network.serverpackets.SystemMessage; @@ -268,6 +269,10 @@ public final class GameClient extends ChannelInboundHandler { ((ExShowScreenMessage) packet).setLang(lang); } + else if (packet instanceof NpcInfo) + { + ((NpcInfo) packet).setLang(lang); + } } } diff --git a/L2J_Mobius_1.0_Ertheia/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java b/L2J_Mobius_1.0_Ertheia/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java index b9aed30eb3..eb77b0fd17 100644 --- a/L2J_Mobius_1.0_Ertheia/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java +++ b/L2J_Mobius_1.0_Ertheia/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java @@ -21,6 +21,8 @@ import java.util.Set; import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketWriter; import org.l2jmobius.gameserver.data.sql.impl.ClanTable; +import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.enums.NpcInfoType; import org.l2jmobius.gameserver.enums.Team; import org.l2jmobius.gameserver.model.actor.Npc; @@ -57,6 +59,40 @@ public class NpcInfo extends AbstractMaskPacket private int _statusMask = 0; private final Set _abnormalVisualEffects; + private String[] _localisation; + + public void setLang(String lang) + { + _localisation = NpcNameLocalisationData.getInstance().getLocalisation(lang, _npc.getId()); + if (_localisation != null) + { + if (!containsMask(NpcInfoType.NAME)) + { + addComponentType(NpcInfoType.NAME); + } + _blockSize -= _npc.getName().length() * 2; + _blockSize += _localisation[0].length() * 2; + + if (!_localisation[1].equals("")) + { + if (!containsMask(NpcInfoType.TITLE)) + { + addComponentType(NpcInfoType.TITLE); + } + final String title = _npc.getTitle(); + _initSize -= title.length() * 2; + if (title.equals("")) + { + _initSize += _localisation[1].length() * 2; + } + else + { + _initSize += title.replace(NpcData.getInstance().getTemplate(_npc.getId()).getTitle(), _localisation[1]).length() * 2; + } + } + } + } + public NpcInfo(Npc npc) { _npc = npc; @@ -283,7 +319,22 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.TITLE)) { - packet.writeS(_npc.getTitle()); + String title = _npc.getTitle(); + + // Localisation related. + if ((_localisation != null) && !_localisation[1].equals("")) + { + if (title.equals("")) + { + title = _localisation[1]; + } + else + { + title = title.replace(NpcData.getInstance().getTemplate(_npc.getId()).getTitle(), _localisation[1]); + } + } + + packet.writeS(title); } // Block 2 @@ -344,7 +395,7 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.FLYING)) { - packet.writeD(_npc.isFlying() ? 0x01 : 00); + packet.writeD(_npc.isFlying() ? 0x01 : 0x00); } if (containsMask(NpcInfoType.CLONE)) { @@ -389,7 +440,7 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.NAME)) { - packet.writeS(_npc.getName()); + packet.writeS(_localisation != null ? _localisation[0] : _npc.getName()); } if (containsMask(NpcInfoType.NAME_NPCSTRINGID)) { diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/lang/el/NpcNameLocalisation.xml b/L2J_Mobius_2.5_Underground/dist/game/data/lang/el/NpcNameLocalisation.xml new file mode 100644 index 0000000000..e260fd7156 --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/data/lang/el/NpcNameLocalisation.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java index 445212da84..54988607c0 100644 --- a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java +++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java @@ -38,6 +38,7 @@ import org.l2jmobius.gameserver.data.xml.impl.FishingData; import org.l2jmobius.gameserver.data.xml.impl.ItemCrystallizationData; import org.l2jmobius.gameserver.data.xml.impl.MultisellData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.OptionData; import org.l2jmobius.gameserver.data.xml.impl.PrimeShopData; import org.l2jmobius.gameserver.data.xml.impl.SayuneData; @@ -340,6 +341,7 @@ public class AdminReload implements IAdminCommandHandler SystemMessageId.loadLocalisations(); NpcStringId.loadLocalisations(); SendMessageLocalisationData.getInstance().load(); + NpcNameLocalisationData.getInstance().load(); AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Localisation data."); break; } diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java index 559eaaea12..26f24c4e52 100644 --- a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java +++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java @@ -19,9 +19,16 @@ package handlers.voicedcommandhandlers; import java.util.StringTokenizer; import org.l2jmobius.Config; +import org.l2jmobius.commons.concurrent.ThreadPool; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.handler.IVoicedCommandHandler; +import org.l2jmobius.gameserver.model.World; +import org.l2jmobius.gameserver.model.WorldObject; +import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; +import org.l2jmobius.gameserver.network.serverpackets.DeleteObject; import org.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage; +import org.l2jmobius.gameserver.network.serverpackets.NpcInfo; public class Lang implements IVoicedCommandHandler { @@ -61,6 +68,18 @@ public class Lang implements IVoicedCommandHandler { msg.setFile(activeChar, "data/html/mods/Lang/Ok.htm"); activeChar.sendPacket(msg); + for (WorldObject obj : World.getInstance().getVisibleObjects()) + { + if (obj.isNpc() && NpcNameLocalisationData.getInstance().hasLocalisation(obj.getId())) + { + activeChar.sendPacket(new DeleteObject(obj)); + ThreadPool.schedule(() -> + { + activeChar.sendPacket(new NpcInfo((Npc) obj)); + }, 1000); + } + } + activeChar.setTarget(null); return true; } msg.setFile(activeChar, "data/html/mods/Lang/Error.htm"); diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/xsd/NpcNameLocalisation.xsd b/L2J_Mobius_2.5_Underground/dist/game/data/xsd/NpcNameLocalisation.xsd new file mode 100644 index 0000000000..b8b185243e --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/data/xsd/NpcNameLocalisation.xsd @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/java/org/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_2.5_Underground/java/org/l2jmobius/gameserver/GameServer.java index bdb634c8e0..717772e98d 100644 --- a/L2J_Mobius_2.5_Underground/java/org/l2jmobius/gameserver/GameServer.java +++ b/L2J_Mobius_2.5_Underground/java/org/l2jmobius/gameserver/GameServer.java @@ -78,6 +78,7 @@ import org.l2jmobius.gameserver.data.xml.impl.KarmaData; import org.l2jmobius.gameserver.data.xml.impl.LuckyGameData; import org.l2jmobius.gameserver.data.xml.impl.MultisellData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.OptionData; import org.l2jmobius.gameserver.data.xml.impl.PetDataTable; import org.l2jmobius.gameserver.data.xml.impl.PetSkillData; @@ -349,6 +350,7 @@ public class GameServer if (Config.MULTILANG_ENABLE) { SendMessageLocalisationData.getInstance(); + NpcNameLocalisationData.getInstance(); } printSection("Scripts"); diff --git a/L2J_Mobius_2.5_Underground/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java b/L2J_Mobius_2.5_Underground/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java new file mode 100644 index 0000000000..e374cd78a5 --- /dev/null +++ b/L2J_Mobius_2.5_Underground/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java @@ -0,0 +1,126 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.l2jmobius.gameserver.data.xml.impl; + +import java.io.File; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Logger; + +import org.w3c.dom.Document; + +import org.l2jmobius.Config; +import org.l2jmobius.commons.util.IXmlReader; +import org.l2jmobius.gameserver.model.StatsSet; + +/** + * @author Mobius + */ +public class NpcNameLocalisationData implements IXmlReader +{ + private final static Logger LOGGER = Logger.getLogger(NpcNameLocalisationData.class.getName()); + + private final static Map> NPC_NAME_LOCALISATIONS = new ConcurrentHashMap<>(); + private static String _lang; + + protected NpcNameLocalisationData() + { + load(); + } + + @Override + public void load() + { + NPC_NAME_LOCALISATIONS.clear(); + + if (Config.MULTILANG_ENABLE) + { + for (String lang : Config.MULTILANG_ALLOWED) + { + final File file = new File("data/lang/" + lang + "/NpcNameLocalisation.xml"); + if (!file.isFile()) + { + continue; + } + + NPC_NAME_LOCALISATIONS.put(lang, new ConcurrentHashMap()); + _lang = lang; + parseDatapackFile("data/lang/" + lang + "/NpcNameLocalisation.xml"); + final int count = NPC_NAME_LOCALISATIONS.get(lang).values().size(); + if (count == 0) + { + NPC_NAME_LOCALISATIONS.remove(lang); + } + else + { + LOGGER.info(getClass().getSimpleName() + ": Loaded localisations for '" + lang + "'"); + } + } + } + } + + @Override + public void parseDocument(Document doc, File f) + { + forEach(doc, "list", listNode -> forEach(listNode, "localisation", localisationNode -> + { + final StatsSet set = new StatsSet(parseAttributes(localisationNode)); + NPC_NAME_LOCALISATIONS.get(_lang).put(set.getInt("id"), new String[] + { + set.getString("name"), + set.getString("title") + }); + })); + } + + /** + * @param lang + * @param id + * @return a String Array[] that contains NPC name and title or Null if is does not exist. + */ + public String[] getLocalisation(String lang, int id) + { + final Map localisations = NPC_NAME_LOCALISATIONS.get(lang); + if (localisations != null) + { + return localisations.get(id); + } + return null; + } + + public boolean hasLocalisation(int id) + { + for (Map data : NPC_NAME_LOCALISATIONS.values()) + { + if (data.containsKey(id)) + { + return true; + } + } + return false; + } + + public static NpcNameLocalisationData getInstance() + { + return SingletonHolder.INSTANCE; + } + + private static class SingletonHolder + { + protected static final NpcNameLocalisationData INSTANCE = new NpcNameLocalisationData(); + } +} diff --git a/L2J_Mobius_2.5_Underground/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java b/L2J_Mobius_2.5_Underground/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java index 3748450659..bf4090be70 100644 --- a/L2J_Mobius_2.5_Underground/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java +++ b/L2J_Mobius_2.5_Underground/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java @@ -68,6 +68,7 @@ import org.l2jmobius.gameserver.data.xml.impl.ClassListData; import org.l2jmobius.gameserver.data.xml.impl.ExperienceData; import org.l2jmobius.gameserver.data.xml.impl.HennaData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.PetDataTable; import org.l2jmobius.gameserver.data.xml.impl.PlayerTemplateData; import org.l2jmobius.gameserver.data.xml.impl.PlayerXpPercentLostData; @@ -11665,7 +11666,19 @@ public final class PlayerInstance extends Playable { sm = new SystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2); sm.addPcName(this); - sm.addString(target.getName()); + + // Localisation related. + String targetName = target.getName(); + if (Config.MULTILANG_ENABLE && target.isNpc()) + { + final String[] localisation = NpcNameLocalisationData.getInstance().getLocalisation(_lang, target.getId()); + if (localisation != null) + { + targetName = localisation[0]; + } + } + + sm.addString(targetName); sm.addInt(damage); sm.addPopup(target.getObjectId(), getObjectId(), -damage); } diff --git a/L2J_Mobius_2.5_Underground/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java b/L2J_Mobius_2.5_Underground/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java index 64d1bdbd1c..df33eb168e 100644 --- a/L2J_Mobius_2.5_Underground/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java +++ b/L2J_Mobius_2.5_Underground/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java @@ -18,6 +18,7 @@ package org.l2jmobius.gameserver.model.actor.status; import org.l2jmobius.Config; import org.l2jmobius.gameserver.ai.CtrlIntention; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.enums.PrivateStoreType; import org.l2jmobius.gameserver.instancemanager.DuelManager; import org.l2jmobius.gameserver.model.actor.Creature; @@ -253,7 +254,19 @@ public class PlayerStatus extends PlayableStatus // Send a System Message to the PlayerInstance SystemMessage smsg = new SystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2); smsg.addString(getActiveChar().getName()); - smsg.addString(attacker.getName()); + + // Localisation related. + String targetName = attacker.getName(); + if (Config.MULTILANG_ENABLE && attacker.isNpc()) + { + final String[] localisation = NpcNameLocalisationData.getInstance().getLocalisation(getActiveChar().getLang(), attacker.getId()); + if (localisation != null) + { + targetName = localisation[0]; + } + } + + smsg.addString(targetName); smsg.addInt(fullValue); smsg.addPopup(getActiveChar().getObjectId(), attacker.getObjectId(), -fullValue); getActiveChar().sendPacket(smsg); diff --git a/L2J_Mobius_2.5_Underground/java/org/l2jmobius/gameserver/network/GameClient.java b/L2J_Mobius_2.5_Underground/java/org/l2jmobius/gameserver/network/GameClient.java index 4ed506b02a..ed0f223551 100644 --- a/L2J_Mobius_2.5_Underground/java/org/l2jmobius/gameserver/network/GameClient.java +++ b/L2J_Mobius_2.5_Underground/java/org/l2jmobius/gameserver/network/GameClient.java @@ -49,6 +49,7 @@ import org.l2jmobius.gameserver.network.serverpackets.ActionFailed; import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; import org.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket; import org.l2jmobius.gameserver.network.serverpackets.LeaveWorld; +import org.l2jmobius.gameserver.network.serverpackets.NpcInfo; import org.l2jmobius.gameserver.network.serverpackets.NpcSay; import org.l2jmobius.gameserver.network.serverpackets.ServerClose; import org.l2jmobius.gameserver.network.serverpackets.SystemMessage; @@ -268,6 +269,10 @@ public final class GameClient extends ChannelInboundHandler { ((ExShowScreenMessage) packet).setLang(lang); } + else if (packet instanceof NpcInfo) + { + ((NpcInfo) packet).setLang(lang); + } } } diff --git a/L2J_Mobius_2.5_Underground/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java b/L2J_Mobius_2.5_Underground/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java index b9aed30eb3..eb77b0fd17 100644 --- a/L2J_Mobius_2.5_Underground/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java +++ b/L2J_Mobius_2.5_Underground/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java @@ -21,6 +21,8 @@ import java.util.Set; import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketWriter; import org.l2jmobius.gameserver.data.sql.impl.ClanTable; +import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.enums.NpcInfoType; import org.l2jmobius.gameserver.enums.Team; import org.l2jmobius.gameserver.model.actor.Npc; @@ -57,6 +59,40 @@ public class NpcInfo extends AbstractMaskPacket private int _statusMask = 0; private final Set _abnormalVisualEffects; + private String[] _localisation; + + public void setLang(String lang) + { + _localisation = NpcNameLocalisationData.getInstance().getLocalisation(lang, _npc.getId()); + if (_localisation != null) + { + if (!containsMask(NpcInfoType.NAME)) + { + addComponentType(NpcInfoType.NAME); + } + _blockSize -= _npc.getName().length() * 2; + _blockSize += _localisation[0].length() * 2; + + if (!_localisation[1].equals("")) + { + if (!containsMask(NpcInfoType.TITLE)) + { + addComponentType(NpcInfoType.TITLE); + } + final String title = _npc.getTitle(); + _initSize -= title.length() * 2; + if (title.equals("")) + { + _initSize += _localisation[1].length() * 2; + } + else + { + _initSize += title.replace(NpcData.getInstance().getTemplate(_npc.getId()).getTitle(), _localisation[1]).length() * 2; + } + } + } + } + public NpcInfo(Npc npc) { _npc = npc; @@ -283,7 +319,22 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.TITLE)) { - packet.writeS(_npc.getTitle()); + String title = _npc.getTitle(); + + // Localisation related. + if ((_localisation != null) && !_localisation[1].equals("")) + { + if (title.equals("")) + { + title = _localisation[1]; + } + else + { + title = title.replace(NpcData.getInstance().getTemplate(_npc.getId()).getTitle(), _localisation[1]); + } + } + + packet.writeS(title); } // Block 2 @@ -344,7 +395,7 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.FLYING)) { - packet.writeD(_npc.isFlying() ? 0x01 : 00); + packet.writeD(_npc.isFlying() ? 0x01 : 0x00); } if (containsMask(NpcInfoType.CLONE)) { @@ -389,7 +440,7 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.NAME)) { - packet.writeS(_npc.getName()); + packet.writeS(_localisation != null ? _localisation[0] : _npc.getName()); } if (containsMask(NpcInfoType.NAME_NPCSTRINGID)) { diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/lang/el/NpcNameLocalisation.xml b/L2J_Mobius_3.0_Helios/dist/game/data/lang/el/NpcNameLocalisation.xml new file mode 100644 index 0000000000..e260fd7156 --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/data/lang/el/NpcNameLocalisation.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java index 445212da84..54988607c0 100644 --- a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java +++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java @@ -38,6 +38,7 @@ import org.l2jmobius.gameserver.data.xml.impl.FishingData; import org.l2jmobius.gameserver.data.xml.impl.ItemCrystallizationData; import org.l2jmobius.gameserver.data.xml.impl.MultisellData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.OptionData; import org.l2jmobius.gameserver.data.xml.impl.PrimeShopData; import org.l2jmobius.gameserver.data.xml.impl.SayuneData; @@ -340,6 +341,7 @@ public class AdminReload implements IAdminCommandHandler SystemMessageId.loadLocalisations(); NpcStringId.loadLocalisations(); SendMessageLocalisationData.getInstance().load(); + NpcNameLocalisationData.getInstance().load(); AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Localisation data."); break; } diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java index 559eaaea12..26f24c4e52 100644 --- a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java +++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java @@ -19,9 +19,16 @@ package handlers.voicedcommandhandlers; import java.util.StringTokenizer; import org.l2jmobius.Config; +import org.l2jmobius.commons.concurrent.ThreadPool; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.handler.IVoicedCommandHandler; +import org.l2jmobius.gameserver.model.World; +import org.l2jmobius.gameserver.model.WorldObject; +import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; +import org.l2jmobius.gameserver.network.serverpackets.DeleteObject; import org.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage; +import org.l2jmobius.gameserver.network.serverpackets.NpcInfo; public class Lang implements IVoicedCommandHandler { @@ -61,6 +68,18 @@ public class Lang implements IVoicedCommandHandler { msg.setFile(activeChar, "data/html/mods/Lang/Ok.htm"); activeChar.sendPacket(msg); + for (WorldObject obj : World.getInstance().getVisibleObjects()) + { + if (obj.isNpc() && NpcNameLocalisationData.getInstance().hasLocalisation(obj.getId())) + { + activeChar.sendPacket(new DeleteObject(obj)); + ThreadPool.schedule(() -> + { + activeChar.sendPacket(new NpcInfo((Npc) obj)); + }, 1000); + } + } + activeChar.setTarget(null); return true; } msg.setFile(activeChar, "data/html/mods/Lang/Error.htm"); diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/xsd/NpcNameLocalisation.xsd b/L2J_Mobius_3.0_Helios/dist/game/data/xsd/NpcNameLocalisation.xsd new file mode 100644 index 0000000000..b8b185243e --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/data/xsd/NpcNameLocalisation.xsd @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_3.0_Helios/java/org/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_3.0_Helios/java/org/l2jmobius/gameserver/GameServer.java index bdb634c8e0..717772e98d 100644 --- a/L2J_Mobius_3.0_Helios/java/org/l2jmobius/gameserver/GameServer.java +++ b/L2J_Mobius_3.0_Helios/java/org/l2jmobius/gameserver/GameServer.java @@ -78,6 +78,7 @@ import org.l2jmobius.gameserver.data.xml.impl.KarmaData; import org.l2jmobius.gameserver.data.xml.impl.LuckyGameData; import org.l2jmobius.gameserver.data.xml.impl.MultisellData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.OptionData; import org.l2jmobius.gameserver.data.xml.impl.PetDataTable; import org.l2jmobius.gameserver.data.xml.impl.PetSkillData; @@ -349,6 +350,7 @@ public class GameServer if (Config.MULTILANG_ENABLE) { SendMessageLocalisationData.getInstance(); + NpcNameLocalisationData.getInstance(); } printSection("Scripts"); diff --git a/L2J_Mobius_3.0_Helios/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java b/L2J_Mobius_3.0_Helios/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java new file mode 100644 index 0000000000..e374cd78a5 --- /dev/null +++ b/L2J_Mobius_3.0_Helios/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java @@ -0,0 +1,126 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.l2jmobius.gameserver.data.xml.impl; + +import java.io.File; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Logger; + +import org.w3c.dom.Document; + +import org.l2jmobius.Config; +import org.l2jmobius.commons.util.IXmlReader; +import org.l2jmobius.gameserver.model.StatsSet; + +/** + * @author Mobius + */ +public class NpcNameLocalisationData implements IXmlReader +{ + private final static Logger LOGGER = Logger.getLogger(NpcNameLocalisationData.class.getName()); + + private final static Map> NPC_NAME_LOCALISATIONS = new ConcurrentHashMap<>(); + private static String _lang; + + protected NpcNameLocalisationData() + { + load(); + } + + @Override + public void load() + { + NPC_NAME_LOCALISATIONS.clear(); + + if (Config.MULTILANG_ENABLE) + { + for (String lang : Config.MULTILANG_ALLOWED) + { + final File file = new File("data/lang/" + lang + "/NpcNameLocalisation.xml"); + if (!file.isFile()) + { + continue; + } + + NPC_NAME_LOCALISATIONS.put(lang, new ConcurrentHashMap()); + _lang = lang; + parseDatapackFile("data/lang/" + lang + "/NpcNameLocalisation.xml"); + final int count = NPC_NAME_LOCALISATIONS.get(lang).values().size(); + if (count == 0) + { + NPC_NAME_LOCALISATIONS.remove(lang); + } + else + { + LOGGER.info(getClass().getSimpleName() + ": Loaded localisations for '" + lang + "'"); + } + } + } + } + + @Override + public void parseDocument(Document doc, File f) + { + forEach(doc, "list", listNode -> forEach(listNode, "localisation", localisationNode -> + { + final StatsSet set = new StatsSet(parseAttributes(localisationNode)); + NPC_NAME_LOCALISATIONS.get(_lang).put(set.getInt("id"), new String[] + { + set.getString("name"), + set.getString("title") + }); + })); + } + + /** + * @param lang + * @param id + * @return a String Array[] that contains NPC name and title or Null if is does not exist. + */ + public String[] getLocalisation(String lang, int id) + { + final Map localisations = NPC_NAME_LOCALISATIONS.get(lang); + if (localisations != null) + { + return localisations.get(id); + } + return null; + } + + public boolean hasLocalisation(int id) + { + for (Map data : NPC_NAME_LOCALISATIONS.values()) + { + if (data.containsKey(id)) + { + return true; + } + } + return false; + } + + public static NpcNameLocalisationData getInstance() + { + return SingletonHolder.INSTANCE; + } + + private static class SingletonHolder + { + protected static final NpcNameLocalisationData INSTANCE = new NpcNameLocalisationData(); + } +} diff --git a/L2J_Mobius_3.0_Helios/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java b/L2J_Mobius_3.0_Helios/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java index edb5e800af..1e73eb707c 100644 --- a/L2J_Mobius_3.0_Helios/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java +++ b/L2J_Mobius_3.0_Helios/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java @@ -68,6 +68,7 @@ import org.l2jmobius.gameserver.data.xml.impl.ClassListData; import org.l2jmobius.gameserver.data.xml.impl.ExperienceData; import org.l2jmobius.gameserver.data.xml.impl.HennaData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.PetDataTable; import org.l2jmobius.gameserver.data.xml.impl.PlayerTemplateData; import org.l2jmobius.gameserver.data.xml.impl.PlayerXpPercentLostData; @@ -11667,7 +11668,19 @@ public final class PlayerInstance extends Playable { sm = new SystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2); sm.addPcName(this); - sm.addString(target.getName()); + + // Localisation related. + String targetName = target.getName(); + if (Config.MULTILANG_ENABLE && target.isNpc()) + { + final String[] localisation = NpcNameLocalisationData.getInstance().getLocalisation(_lang, target.getId()); + if (localisation != null) + { + targetName = localisation[0]; + } + } + + sm.addString(targetName); sm.addInt(damage); sm.addPopup(target.getObjectId(), getObjectId(), -damage); } diff --git a/L2J_Mobius_3.0_Helios/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java b/L2J_Mobius_3.0_Helios/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java index 64d1bdbd1c..df33eb168e 100644 --- a/L2J_Mobius_3.0_Helios/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java +++ b/L2J_Mobius_3.0_Helios/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java @@ -18,6 +18,7 @@ package org.l2jmobius.gameserver.model.actor.status; import org.l2jmobius.Config; import org.l2jmobius.gameserver.ai.CtrlIntention; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.enums.PrivateStoreType; import org.l2jmobius.gameserver.instancemanager.DuelManager; import org.l2jmobius.gameserver.model.actor.Creature; @@ -253,7 +254,19 @@ public class PlayerStatus extends PlayableStatus // Send a System Message to the PlayerInstance SystemMessage smsg = new SystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2); smsg.addString(getActiveChar().getName()); - smsg.addString(attacker.getName()); + + // Localisation related. + String targetName = attacker.getName(); + if (Config.MULTILANG_ENABLE && attacker.isNpc()) + { + final String[] localisation = NpcNameLocalisationData.getInstance().getLocalisation(getActiveChar().getLang(), attacker.getId()); + if (localisation != null) + { + targetName = localisation[0]; + } + } + + smsg.addString(targetName); smsg.addInt(fullValue); smsg.addPopup(getActiveChar().getObjectId(), attacker.getObjectId(), -fullValue); getActiveChar().sendPacket(smsg); diff --git a/L2J_Mobius_3.0_Helios/java/org/l2jmobius/gameserver/network/GameClient.java b/L2J_Mobius_3.0_Helios/java/org/l2jmobius/gameserver/network/GameClient.java index 4ed506b02a..ed0f223551 100644 --- a/L2J_Mobius_3.0_Helios/java/org/l2jmobius/gameserver/network/GameClient.java +++ b/L2J_Mobius_3.0_Helios/java/org/l2jmobius/gameserver/network/GameClient.java @@ -49,6 +49,7 @@ import org.l2jmobius.gameserver.network.serverpackets.ActionFailed; import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; import org.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket; import org.l2jmobius.gameserver.network.serverpackets.LeaveWorld; +import org.l2jmobius.gameserver.network.serverpackets.NpcInfo; import org.l2jmobius.gameserver.network.serverpackets.NpcSay; import org.l2jmobius.gameserver.network.serverpackets.ServerClose; import org.l2jmobius.gameserver.network.serverpackets.SystemMessage; @@ -268,6 +269,10 @@ public final class GameClient extends ChannelInboundHandler { ((ExShowScreenMessage) packet).setLang(lang); } + else if (packet instanceof NpcInfo) + { + ((NpcInfo) packet).setLang(lang); + } } } diff --git a/L2J_Mobius_3.0_Helios/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java b/L2J_Mobius_3.0_Helios/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java index b9aed30eb3..eb77b0fd17 100644 --- a/L2J_Mobius_3.0_Helios/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java +++ b/L2J_Mobius_3.0_Helios/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java @@ -21,6 +21,8 @@ import java.util.Set; import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketWriter; import org.l2jmobius.gameserver.data.sql.impl.ClanTable; +import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.enums.NpcInfoType; import org.l2jmobius.gameserver.enums.Team; import org.l2jmobius.gameserver.model.actor.Npc; @@ -57,6 +59,40 @@ public class NpcInfo extends AbstractMaskPacket private int _statusMask = 0; private final Set _abnormalVisualEffects; + private String[] _localisation; + + public void setLang(String lang) + { + _localisation = NpcNameLocalisationData.getInstance().getLocalisation(lang, _npc.getId()); + if (_localisation != null) + { + if (!containsMask(NpcInfoType.NAME)) + { + addComponentType(NpcInfoType.NAME); + } + _blockSize -= _npc.getName().length() * 2; + _blockSize += _localisation[0].length() * 2; + + if (!_localisation[1].equals("")) + { + if (!containsMask(NpcInfoType.TITLE)) + { + addComponentType(NpcInfoType.TITLE); + } + final String title = _npc.getTitle(); + _initSize -= title.length() * 2; + if (title.equals("")) + { + _initSize += _localisation[1].length() * 2; + } + else + { + _initSize += title.replace(NpcData.getInstance().getTemplate(_npc.getId()).getTitle(), _localisation[1]).length() * 2; + } + } + } + } + public NpcInfo(Npc npc) { _npc = npc; @@ -283,7 +319,22 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.TITLE)) { - packet.writeS(_npc.getTitle()); + String title = _npc.getTitle(); + + // Localisation related. + if ((_localisation != null) && !_localisation[1].equals("")) + { + if (title.equals("")) + { + title = _localisation[1]; + } + else + { + title = title.replace(NpcData.getInstance().getTemplate(_npc.getId()).getTitle(), _localisation[1]); + } + } + + packet.writeS(title); } // Block 2 @@ -344,7 +395,7 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.FLYING)) { - packet.writeD(_npc.isFlying() ? 0x01 : 00); + packet.writeD(_npc.isFlying() ? 0x01 : 0x00); } if (containsMask(NpcInfoType.CLONE)) { @@ -389,7 +440,7 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.NAME)) { - packet.writeS(_npc.getName()); + packet.writeS(_localisation != null ? _localisation[0] : _npc.getName()); } if (containsMask(NpcInfoType.NAME_NPCSTRINGID)) { diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/lang/el/NpcNameLocalisation.xml b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/lang/el/NpcNameLocalisation.xml new file mode 100644 index 0000000000..e260fd7156 --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/lang/el/NpcNameLocalisation.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java index 7bee2f3d02..3c26c6f57b 100644 --- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java @@ -37,6 +37,7 @@ import org.l2jmobius.gameserver.data.xml.impl.FishingData; import org.l2jmobius.gameserver.data.xml.impl.ItemCrystallizationData; import org.l2jmobius.gameserver.data.xml.impl.MultisellData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.OptionData; import org.l2jmobius.gameserver.data.xml.impl.PrimeShopData; import org.l2jmobius.gameserver.data.xml.impl.SayuneData; @@ -333,6 +334,7 @@ public class AdminReload implements IAdminCommandHandler SystemMessageId.loadLocalisations(); NpcStringId.loadLocalisations(); SendMessageLocalisationData.getInstance().load(); + NpcNameLocalisationData.getInstance().load(); AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Localisation data."); break; } diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java index 559eaaea12..26f24c4e52 100644 --- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java @@ -19,9 +19,16 @@ package handlers.voicedcommandhandlers; import java.util.StringTokenizer; import org.l2jmobius.Config; +import org.l2jmobius.commons.concurrent.ThreadPool; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.handler.IVoicedCommandHandler; +import org.l2jmobius.gameserver.model.World; +import org.l2jmobius.gameserver.model.WorldObject; +import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; +import org.l2jmobius.gameserver.network.serverpackets.DeleteObject; import org.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage; +import org.l2jmobius.gameserver.network.serverpackets.NpcInfo; public class Lang implements IVoicedCommandHandler { @@ -61,6 +68,18 @@ public class Lang implements IVoicedCommandHandler { msg.setFile(activeChar, "data/html/mods/Lang/Ok.htm"); activeChar.sendPacket(msg); + for (WorldObject obj : World.getInstance().getVisibleObjects()) + { + if (obj.isNpc() && NpcNameLocalisationData.getInstance().hasLocalisation(obj.getId())) + { + activeChar.sendPacket(new DeleteObject(obj)); + ThreadPool.schedule(() -> + { + activeChar.sendPacket(new NpcInfo((Npc) obj)); + }, 1000); + } + } + activeChar.setTarget(null); return true; } msg.setFile(activeChar, "data/html/mods/Lang/Error.htm"); diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/xsd/NpcNameLocalisation.xsd b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/xsd/NpcNameLocalisation.xsd new file mode 100644 index 0000000000..b8b185243e --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/xsd/NpcNameLocalisation.xsd @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_4.0_GrandCrusade/java/org/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_4.0_GrandCrusade/java/org/l2jmobius/gameserver/GameServer.java index aa09c9be7c..9e7d7cec03 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/org/l2jmobius/gameserver/GameServer.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/org/l2jmobius/gameserver/GameServer.java @@ -78,6 +78,7 @@ import org.l2jmobius.gameserver.data.xml.impl.LuckyGameData; import org.l2jmobius.gameserver.data.xml.impl.MonsterBookData; import org.l2jmobius.gameserver.data.xml.impl.MultisellData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.OptionData; import org.l2jmobius.gameserver.data.xml.impl.PetDataTable; import org.l2jmobius.gameserver.data.xml.impl.PetSkillData; @@ -349,6 +350,7 @@ public class GameServer if (Config.MULTILANG_ENABLE) { SendMessageLocalisationData.getInstance(); + NpcNameLocalisationData.getInstance(); } printSection("Scripts"); diff --git a/L2J_Mobius_4.0_GrandCrusade/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java b/L2J_Mobius_4.0_GrandCrusade/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java new file mode 100644 index 0000000000..e374cd78a5 --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java @@ -0,0 +1,126 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.l2jmobius.gameserver.data.xml.impl; + +import java.io.File; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Logger; + +import org.w3c.dom.Document; + +import org.l2jmobius.Config; +import org.l2jmobius.commons.util.IXmlReader; +import org.l2jmobius.gameserver.model.StatsSet; + +/** + * @author Mobius + */ +public class NpcNameLocalisationData implements IXmlReader +{ + private final static Logger LOGGER = Logger.getLogger(NpcNameLocalisationData.class.getName()); + + private final static Map> NPC_NAME_LOCALISATIONS = new ConcurrentHashMap<>(); + private static String _lang; + + protected NpcNameLocalisationData() + { + load(); + } + + @Override + public void load() + { + NPC_NAME_LOCALISATIONS.clear(); + + if (Config.MULTILANG_ENABLE) + { + for (String lang : Config.MULTILANG_ALLOWED) + { + final File file = new File("data/lang/" + lang + "/NpcNameLocalisation.xml"); + if (!file.isFile()) + { + continue; + } + + NPC_NAME_LOCALISATIONS.put(lang, new ConcurrentHashMap()); + _lang = lang; + parseDatapackFile("data/lang/" + lang + "/NpcNameLocalisation.xml"); + final int count = NPC_NAME_LOCALISATIONS.get(lang).values().size(); + if (count == 0) + { + NPC_NAME_LOCALISATIONS.remove(lang); + } + else + { + LOGGER.info(getClass().getSimpleName() + ": Loaded localisations for '" + lang + "'"); + } + } + } + } + + @Override + public void parseDocument(Document doc, File f) + { + forEach(doc, "list", listNode -> forEach(listNode, "localisation", localisationNode -> + { + final StatsSet set = new StatsSet(parseAttributes(localisationNode)); + NPC_NAME_LOCALISATIONS.get(_lang).put(set.getInt("id"), new String[] + { + set.getString("name"), + set.getString("title") + }); + })); + } + + /** + * @param lang + * @param id + * @return a String Array[] that contains NPC name and title or Null if is does not exist. + */ + public String[] getLocalisation(String lang, int id) + { + final Map localisations = NPC_NAME_LOCALISATIONS.get(lang); + if (localisations != null) + { + return localisations.get(id); + } + return null; + } + + public boolean hasLocalisation(int id) + { + for (Map data : NPC_NAME_LOCALISATIONS.values()) + { + if (data.containsKey(id)) + { + return true; + } + } + return false; + } + + public static NpcNameLocalisationData getInstance() + { + return SingletonHolder.INSTANCE; + } + + private static class SingletonHolder + { + protected static final NpcNameLocalisationData INSTANCE = new NpcNameLocalisationData(); + } +} diff --git a/L2J_Mobius_4.0_GrandCrusade/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java b/L2J_Mobius_4.0_GrandCrusade/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java index 5313606b55..a3485ff31f 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java @@ -69,6 +69,7 @@ import org.l2jmobius.gameserver.data.xml.impl.ExperienceData; import org.l2jmobius.gameserver.data.xml.impl.HennaData; import org.l2jmobius.gameserver.data.xml.impl.MonsterBookData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.PetDataTable; import org.l2jmobius.gameserver.data.xml.impl.PlayerTemplateData; import org.l2jmobius.gameserver.data.xml.impl.PlayerXpPercentLostData; @@ -11647,7 +11648,19 @@ public final class PlayerInstance extends Playable { sm = new SystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2); sm.addPcName(this); - sm.addString(target.getName()); + + // Localisation related. + String targetName = target.getName(); + if (Config.MULTILANG_ENABLE && target.isNpc()) + { + final String[] localisation = NpcNameLocalisationData.getInstance().getLocalisation(_lang, target.getId()); + if (localisation != null) + { + targetName = localisation[0]; + } + } + + sm.addString(targetName); sm.addInt(damage); sm.addPopup(target.getObjectId(), getObjectId(), -damage); } diff --git a/L2J_Mobius_4.0_GrandCrusade/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java b/L2J_Mobius_4.0_GrandCrusade/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java index 64d1bdbd1c..df33eb168e 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java @@ -18,6 +18,7 @@ package org.l2jmobius.gameserver.model.actor.status; import org.l2jmobius.Config; import org.l2jmobius.gameserver.ai.CtrlIntention; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.enums.PrivateStoreType; import org.l2jmobius.gameserver.instancemanager.DuelManager; import org.l2jmobius.gameserver.model.actor.Creature; @@ -253,7 +254,19 @@ public class PlayerStatus extends PlayableStatus // Send a System Message to the PlayerInstance SystemMessage smsg = new SystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2); smsg.addString(getActiveChar().getName()); - smsg.addString(attacker.getName()); + + // Localisation related. + String targetName = attacker.getName(); + if (Config.MULTILANG_ENABLE && attacker.isNpc()) + { + final String[] localisation = NpcNameLocalisationData.getInstance().getLocalisation(getActiveChar().getLang(), attacker.getId()); + if (localisation != null) + { + targetName = localisation[0]; + } + } + + smsg.addString(targetName); smsg.addInt(fullValue); smsg.addPopup(getActiveChar().getObjectId(), attacker.getObjectId(), -fullValue); getActiveChar().sendPacket(smsg); diff --git a/L2J_Mobius_4.0_GrandCrusade/java/org/l2jmobius/gameserver/network/GameClient.java b/L2J_Mobius_4.0_GrandCrusade/java/org/l2jmobius/gameserver/network/GameClient.java index 4ed506b02a..ed0f223551 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/org/l2jmobius/gameserver/network/GameClient.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/org/l2jmobius/gameserver/network/GameClient.java @@ -49,6 +49,7 @@ import org.l2jmobius.gameserver.network.serverpackets.ActionFailed; import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; import org.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket; import org.l2jmobius.gameserver.network.serverpackets.LeaveWorld; +import org.l2jmobius.gameserver.network.serverpackets.NpcInfo; import org.l2jmobius.gameserver.network.serverpackets.NpcSay; import org.l2jmobius.gameserver.network.serverpackets.ServerClose; import org.l2jmobius.gameserver.network.serverpackets.SystemMessage; @@ -268,6 +269,10 @@ public final class GameClient extends ChannelInboundHandler { ((ExShowScreenMessage) packet).setLang(lang); } + else if (packet instanceof NpcInfo) + { + ((NpcInfo) packet).setLang(lang); + } } } diff --git a/L2J_Mobius_4.0_GrandCrusade/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java b/L2J_Mobius_4.0_GrandCrusade/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java index b9aed30eb3..eb77b0fd17 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java @@ -21,6 +21,8 @@ import java.util.Set; import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketWriter; import org.l2jmobius.gameserver.data.sql.impl.ClanTable; +import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.enums.NpcInfoType; import org.l2jmobius.gameserver.enums.Team; import org.l2jmobius.gameserver.model.actor.Npc; @@ -57,6 +59,40 @@ public class NpcInfo extends AbstractMaskPacket private int _statusMask = 0; private final Set _abnormalVisualEffects; + private String[] _localisation; + + public void setLang(String lang) + { + _localisation = NpcNameLocalisationData.getInstance().getLocalisation(lang, _npc.getId()); + if (_localisation != null) + { + if (!containsMask(NpcInfoType.NAME)) + { + addComponentType(NpcInfoType.NAME); + } + _blockSize -= _npc.getName().length() * 2; + _blockSize += _localisation[0].length() * 2; + + if (!_localisation[1].equals("")) + { + if (!containsMask(NpcInfoType.TITLE)) + { + addComponentType(NpcInfoType.TITLE); + } + final String title = _npc.getTitle(); + _initSize -= title.length() * 2; + if (title.equals("")) + { + _initSize += _localisation[1].length() * 2; + } + else + { + _initSize += title.replace(NpcData.getInstance().getTemplate(_npc.getId()).getTitle(), _localisation[1]).length() * 2; + } + } + } + } + public NpcInfo(Npc npc) { _npc = npc; @@ -283,7 +319,22 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.TITLE)) { - packet.writeS(_npc.getTitle()); + String title = _npc.getTitle(); + + // Localisation related. + if ((_localisation != null) && !_localisation[1].equals("")) + { + if (title.equals("")) + { + title = _localisation[1]; + } + else + { + title = title.replace(NpcData.getInstance().getTemplate(_npc.getId()).getTitle(), _localisation[1]); + } + } + + packet.writeS(title); } // Block 2 @@ -344,7 +395,7 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.FLYING)) { - packet.writeD(_npc.isFlying() ? 0x01 : 00); + packet.writeD(_npc.isFlying() ? 0x01 : 0x00); } if (containsMask(NpcInfoType.CLONE)) { @@ -389,7 +440,7 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.NAME)) { - packet.writeS(_npc.getName()); + packet.writeS(_localisation != null ? _localisation[0] : _npc.getName()); } if (containsMask(NpcInfoType.NAME_NPCSTRINGID)) { diff --git a/L2J_Mobius_5.0_Salvation/dist/game/data/lang/el/NpcNameLocalisation.xml b/L2J_Mobius_5.0_Salvation/dist/game/data/lang/el/NpcNameLocalisation.xml new file mode 100644 index 0000000000..e260fd7156 --- /dev/null +++ b/L2J_Mobius_5.0_Salvation/dist/game/data/lang/el/NpcNameLocalisation.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/L2J_Mobius_5.0_Salvation/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java b/L2J_Mobius_5.0_Salvation/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java index fc8f01eb2b..328d863377 100644 --- a/L2J_Mobius_5.0_Salvation/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java +++ b/L2J_Mobius_5.0_Salvation/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java @@ -38,6 +38,7 @@ import org.l2jmobius.gameserver.data.xml.impl.FishingData; import org.l2jmobius.gameserver.data.xml.impl.ItemCrystallizationData; import org.l2jmobius.gameserver.data.xml.impl.MultisellData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.OptionData; import org.l2jmobius.gameserver.data.xml.impl.PrimeShopData; import org.l2jmobius.gameserver.data.xml.impl.SayuneData; @@ -340,6 +341,7 @@ public class AdminReload implements IAdminCommandHandler SystemMessageId.loadLocalisations(); NpcStringId.loadLocalisations(); SendMessageLocalisationData.getInstance().load(); + NpcNameLocalisationData.getInstance().load(); AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Localisation data."); break; } diff --git a/L2J_Mobius_5.0_Salvation/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java b/L2J_Mobius_5.0_Salvation/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java index 559eaaea12..26f24c4e52 100644 --- a/L2J_Mobius_5.0_Salvation/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java +++ b/L2J_Mobius_5.0_Salvation/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java @@ -19,9 +19,16 @@ package handlers.voicedcommandhandlers; import java.util.StringTokenizer; import org.l2jmobius.Config; +import org.l2jmobius.commons.concurrent.ThreadPool; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.handler.IVoicedCommandHandler; +import org.l2jmobius.gameserver.model.World; +import org.l2jmobius.gameserver.model.WorldObject; +import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; +import org.l2jmobius.gameserver.network.serverpackets.DeleteObject; import org.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage; +import org.l2jmobius.gameserver.network.serverpackets.NpcInfo; public class Lang implements IVoicedCommandHandler { @@ -61,6 +68,18 @@ public class Lang implements IVoicedCommandHandler { msg.setFile(activeChar, "data/html/mods/Lang/Ok.htm"); activeChar.sendPacket(msg); + for (WorldObject obj : World.getInstance().getVisibleObjects()) + { + if (obj.isNpc() && NpcNameLocalisationData.getInstance().hasLocalisation(obj.getId())) + { + activeChar.sendPacket(new DeleteObject(obj)); + ThreadPool.schedule(() -> + { + activeChar.sendPacket(new NpcInfo((Npc) obj)); + }, 1000); + } + } + activeChar.setTarget(null); return true; } msg.setFile(activeChar, "data/html/mods/Lang/Error.htm"); diff --git a/L2J_Mobius_5.0_Salvation/dist/game/data/xsd/NpcNameLocalisation.xsd b/L2J_Mobius_5.0_Salvation/dist/game/data/xsd/NpcNameLocalisation.xsd new file mode 100644 index 0000000000..b8b185243e --- /dev/null +++ b/L2J_Mobius_5.0_Salvation/dist/game/data/xsd/NpcNameLocalisation.xsd @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_5.0_Salvation/java/org/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_5.0_Salvation/java/org/l2jmobius/gameserver/GameServer.java index 206cd7ee61..eb71b8ff1e 100644 --- a/L2J_Mobius_5.0_Salvation/java/org/l2jmobius/gameserver/GameServer.java +++ b/L2J_Mobius_5.0_Salvation/java/org/l2jmobius/gameserver/GameServer.java @@ -80,6 +80,7 @@ import org.l2jmobius.gameserver.data.xml.impl.LuckyGameData; import org.l2jmobius.gameserver.data.xml.impl.MonsterBookData; import org.l2jmobius.gameserver.data.xml.impl.MultisellData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.OptionData; import org.l2jmobius.gameserver.data.xml.impl.PetDataTable; import org.l2jmobius.gameserver.data.xml.impl.PetSkillData; @@ -353,6 +354,7 @@ public class GameServer if (Config.MULTILANG_ENABLE) { SendMessageLocalisationData.getInstance(); + NpcNameLocalisationData.getInstance(); } printSection("Scripts"); diff --git a/L2J_Mobius_5.0_Salvation/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java b/L2J_Mobius_5.0_Salvation/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java new file mode 100644 index 0000000000..e374cd78a5 --- /dev/null +++ b/L2J_Mobius_5.0_Salvation/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java @@ -0,0 +1,126 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.l2jmobius.gameserver.data.xml.impl; + +import java.io.File; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Logger; + +import org.w3c.dom.Document; + +import org.l2jmobius.Config; +import org.l2jmobius.commons.util.IXmlReader; +import org.l2jmobius.gameserver.model.StatsSet; + +/** + * @author Mobius + */ +public class NpcNameLocalisationData implements IXmlReader +{ + private final static Logger LOGGER = Logger.getLogger(NpcNameLocalisationData.class.getName()); + + private final static Map> NPC_NAME_LOCALISATIONS = new ConcurrentHashMap<>(); + private static String _lang; + + protected NpcNameLocalisationData() + { + load(); + } + + @Override + public void load() + { + NPC_NAME_LOCALISATIONS.clear(); + + if (Config.MULTILANG_ENABLE) + { + for (String lang : Config.MULTILANG_ALLOWED) + { + final File file = new File("data/lang/" + lang + "/NpcNameLocalisation.xml"); + if (!file.isFile()) + { + continue; + } + + NPC_NAME_LOCALISATIONS.put(lang, new ConcurrentHashMap()); + _lang = lang; + parseDatapackFile("data/lang/" + lang + "/NpcNameLocalisation.xml"); + final int count = NPC_NAME_LOCALISATIONS.get(lang).values().size(); + if (count == 0) + { + NPC_NAME_LOCALISATIONS.remove(lang); + } + else + { + LOGGER.info(getClass().getSimpleName() + ": Loaded localisations for '" + lang + "'"); + } + } + } + } + + @Override + public void parseDocument(Document doc, File f) + { + forEach(doc, "list", listNode -> forEach(listNode, "localisation", localisationNode -> + { + final StatsSet set = new StatsSet(parseAttributes(localisationNode)); + NPC_NAME_LOCALISATIONS.get(_lang).put(set.getInt("id"), new String[] + { + set.getString("name"), + set.getString("title") + }); + })); + } + + /** + * @param lang + * @param id + * @return a String Array[] that contains NPC name and title or Null if is does not exist. + */ + public String[] getLocalisation(String lang, int id) + { + final Map localisations = NPC_NAME_LOCALISATIONS.get(lang); + if (localisations != null) + { + return localisations.get(id); + } + return null; + } + + public boolean hasLocalisation(int id) + { + for (Map data : NPC_NAME_LOCALISATIONS.values()) + { + if (data.containsKey(id)) + { + return true; + } + } + return false; + } + + public static NpcNameLocalisationData getInstance() + { + return SingletonHolder.INSTANCE; + } + + private static class SingletonHolder + { + protected static final NpcNameLocalisationData INSTANCE = new NpcNameLocalisationData(); + } +} diff --git a/L2J_Mobius_5.0_Salvation/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java b/L2J_Mobius_5.0_Salvation/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java index 3280b75116..ddda92dff2 100644 --- a/L2J_Mobius_5.0_Salvation/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java +++ b/L2J_Mobius_5.0_Salvation/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java @@ -69,6 +69,7 @@ import org.l2jmobius.gameserver.data.xml.impl.ExperienceData; import org.l2jmobius.gameserver.data.xml.impl.HennaData; import org.l2jmobius.gameserver.data.xml.impl.MonsterBookData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.PetDataTable; import org.l2jmobius.gameserver.data.xml.impl.PlayerTemplateData; import org.l2jmobius.gameserver.data.xml.impl.PlayerXpPercentLostData; @@ -11637,7 +11638,19 @@ public final class PlayerInstance extends Playable { sm = new SystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2); sm.addPcName(this); - sm.addString(target.getName()); + + // Localisation related. + String targetName = target.getName(); + if (Config.MULTILANG_ENABLE && target.isNpc()) + { + final String[] localisation = NpcNameLocalisationData.getInstance().getLocalisation(_lang, target.getId()); + if (localisation != null) + { + targetName = localisation[0]; + } + } + + sm.addString(targetName); sm.addInt(damage); sm.addPopup(target.getObjectId(), getObjectId(), -damage); } diff --git a/L2J_Mobius_5.0_Salvation/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java b/L2J_Mobius_5.0_Salvation/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java index 64d1bdbd1c..df33eb168e 100644 --- a/L2J_Mobius_5.0_Salvation/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java +++ b/L2J_Mobius_5.0_Salvation/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java @@ -18,6 +18,7 @@ package org.l2jmobius.gameserver.model.actor.status; import org.l2jmobius.Config; import org.l2jmobius.gameserver.ai.CtrlIntention; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.enums.PrivateStoreType; import org.l2jmobius.gameserver.instancemanager.DuelManager; import org.l2jmobius.gameserver.model.actor.Creature; @@ -253,7 +254,19 @@ public class PlayerStatus extends PlayableStatus // Send a System Message to the PlayerInstance SystemMessage smsg = new SystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2); smsg.addString(getActiveChar().getName()); - smsg.addString(attacker.getName()); + + // Localisation related. + String targetName = attacker.getName(); + if (Config.MULTILANG_ENABLE && attacker.isNpc()) + { + final String[] localisation = NpcNameLocalisationData.getInstance().getLocalisation(getActiveChar().getLang(), attacker.getId()); + if (localisation != null) + { + targetName = localisation[0]; + } + } + + smsg.addString(targetName); smsg.addInt(fullValue); smsg.addPopup(getActiveChar().getObjectId(), attacker.getObjectId(), -fullValue); getActiveChar().sendPacket(smsg); diff --git a/L2J_Mobius_5.0_Salvation/java/org/l2jmobius/gameserver/network/GameClient.java b/L2J_Mobius_5.0_Salvation/java/org/l2jmobius/gameserver/network/GameClient.java index 4ed506b02a..ed0f223551 100644 --- a/L2J_Mobius_5.0_Salvation/java/org/l2jmobius/gameserver/network/GameClient.java +++ b/L2J_Mobius_5.0_Salvation/java/org/l2jmobius/gameserver/network/GameClient.java @@ -49,6 +49,7 @@ import org.l2jmobius.gameserver.network.serverpackets.ActionFailed; import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; import org.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket; import org.l2jmobius.gameserver.network.serverpackets.LeaveWorld; +import org.l2jmobius.gameserver.network.serverpackets.NpcInfo; import org.l2jmobius.gameserver.network.serverpackets.NpcSay; import org.l2jmobius.gameserver.network.serverpackets.ServerClose; import org.l2jmobius.gameserver.network.serverpackets.SystemMessage; @@ -268,6 +269,10 @@ public final class GameClient extends ChannelInboundHandler { ((ExShowScreenMessage) packet).setLang(lang); } + else if (packet instanceof NpcInfo) + { + ((NpcInfo) packet).setLang(lang); + } } } diff --git a/L2J_Mobius_5.0_Salvation/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java b/L2J_Mobius_5.0_Salvation/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java index b9aed30eb3..eb77b0fd17 100644 --- a/L2J_Mobius_5.0_Salvation/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java +++ b/L2J_Mobius_5.0_Salvation/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java @@ -21,6 +21,8 @@ import java.util.Set; import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketWriter; import org.l2jmobius.gameserver.data.sql.impl.ClanTable; +import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.enums.NpcInfoType; import org.l2jmobius.gameserver.enums.Team; import org.l2jmobius.gameserver.model.actor.Npc; @@ -57,6 +59,40 @@ public class NpcInfo extends AbstractMaskPacket private int _statusMask = 0; private final Set _abnormalVisualEffects; + private String[] _localisation; + + public void setLang(String lang) + { + _localisation = NpcNameLocalisationData.getInstance().getLocalisation(lang, _npc.getId()); + if (_localisation != null) + { + if (!containsMask(NpcInfoType.NAME)) + { + addComponentType(NpcInfoType.NAME); + } + _blockSize -= _npc.getName().length() * 2; + _blockSize += _localisation[0].length() * 2; + + if (!_localisation[1].equals("")) + { + if (!containsMask(NpcInfoType.TITLE)) + { + addComponentType(NpcInfoType.TITLE); + } + final String title = _npc.getTitle(); + _initSize -= title.length() * 2; + if (title.equals("")) + { + _initSize += _localisation[1].length() * 2; + } + else + { + _initSize += title.replace(NpcData.getInstance().getTemplate(_npc.getId()).getTitle(), _localisation[1]).length() * 2; + } + } + } + } + public NpcInfo(Npc npc) { _npc = npc; @@ -283,7 +319,22 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.TITLE)) { - packet.writeS(_npc.getTitle()); + String title = _npc.getTitle(); + + // Localisation related. + if ((_localisation != null) && !_localisation[1].equals("")) + { + if (title.equals("")) + { + title = _localisation[1]; + } + else + { + title = title.replace(NpcData.getInstance().getTemplate(_npc.getId()).getTitle(), _localisation[1]); + } + } + + packet.writeS(title); } // Block 2 @@ -344,7 +395,7 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.FLYING)) { - packet.writeD(_npc.isFlying() ? 0x01 : 00); + packet.writeD(_npc.isFlying() ? 0x01 : 0x00); } if (containsMask(NpcInfoType.CLONE)) { @@ -389,7 +440,7 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.NAME)) { - packet.writeS(_npc.getName()); + packet.writeS(_localisation != null ? _localisation[0] : _npc.getName()); } if (containsMask(NpcInfoType.NAME_NPCSTRINGID)) { diff --git a/L2J_Mobius_5.5_EtinasFate/dist/game/data/lang/el/NpcNameLocalisation.xml b/L2J_Mobius_5.5_EtinasFate/dist/game/data/lang/el/NpcNameLocalisation.xml new file mode 100644 index 0000000000..e260fd7156 --- /dev/null +++ b/L2J_Mobius_5.5_EtinasFate/dist/game/data/lang/el/NpcNameLocalisation.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/L2J_Mobius_5.5_EtinasFate/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java b/L2J_Mobius_5.5_EtinasFate/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java index fc8f01eb2b..328d863377 100644 --- a/L2J_Mobius_5.5_EtinasFate/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java +++ b/L2J_Mobius_5.5_EtinasFate/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java @@ -38,6 +38,7 @@ import org.l2jmobius.gameserver.data.xml.impl.FishingData; import org.l2jmobius.gameserver.data.xml.impl.ItemCrystallizationData; import org.l2jmobius.gameserver.data.xml.impl.MultisellData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.OptionData; import org.l2jmobius.gameserver.data.xml.impl.PrimeShopData; import org.l2jmobius.gameserver.data.xml.impl.SayuneData; @@ -340,6 +341,7 @@ public class AdminReload implements IAdminCommandHandler SystemMessageId.loadLocalisations(); NpcStringId.loadLocalisations(); SendMessageLocalisationData.getInstance().load(); + NpcNameLocalisationData.getInstance().load(); AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Localisation data."); break; } diff --git a/L2J_Mobius_5.5_EtinasFate/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java b/L2J_Mobius_5.5_EtinasFate/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java index 559eaaea12..26f24c4e52 100644 --- a/L2J_Mobius_5.5_EtinasFate/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java +++ b/L2J_Mobius_5.5_EtinasFate/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java @@ -19,9 +19,16 @@ package handlers.voicedcommandhandlers; import java.util.StringTokenizer; import org.l2jmobius.Config; +import org.l2jmobius.commons.concurrent.ThreadPool; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.handler.IVoicedCommandHandler; +import org.l2jmobius.gameserver.model.World; +import org.l2jmobius.gameserver.model.WorldObject; +import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; +import org.l2jmobius.gameserver.network.serverpackets.DeleteObject; import org.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage; +import org.l2jmobius.gameserver.network.serverpackets.NpcInfo; public class Lang implements IVoicedCommandHandler { @@ -61,6 +68,18 @@ public class Lang implements IVoicedCommandHandler { msg.setFile(activeChar, "data/html/mods/Lang/Ok.htm"); activeChar.sendPacket(msg); + for (WorldObject obj : World.getInstance().getVisibleObjects()) + { + if (obj.isNpc() && NpcNameLocalisationData.getInstance().hasLocalisation(obj.getId())) + { + activeChar.sendPacket(new DeleteObject(obj)); + ThreadPool.schedule(() -> + { + activeChar.sendPacket(new NpcInfo((Npc) obj)); + }, 1000); + } + } + activeChar.setTarget(null); return true; } msg.setFile(activeChar, "data/html/mods/Lang/Error.htm"); diff --git a/L2J_Mobius_5.5_EtinasFate/dist/game/data/xsd/NpcNameLocalisation.xsd b/L2J_Mobius_5.5_EtinasFate/dist/game/data/xsd/NpcNameLocalisation.xsd new file mode 100644 index 0000000000..b8b185243e --- /dev/null +++ b/L2J_Mobius_5.5_EtinasFate/dist/game/data/xsd/NpcNameLocalisation.xsd @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_5.5_EtinasFate/java/org/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_5.5_EtinasFate/java/org/l2jmobius/gameserver/GameServer.java index 206cd7ee61..eb71b8ff1e 100644 --- a/L2J_Mobius_5.5_EtinasFate/java/org/l2jmobius/gameserver/GameServer.java +++ b/L2J_Mobius_5.5_EtinasFate/java/org/l2jmobius/gameserver/GameServer.java @@ -80,6 +80,7 @@ import org.l2jmobius.gameserver.data.xml.impl.LuckyGameData; import org.l2jmobius.gameserver.data.xml.impl.MonsterBookData; import org.l2jmobius.gameserver.data.xml.impl.MultisellData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.OptionData; import org.l2jmobius.gameserver.data.xml.impl.PetDataTable; import org.l2jmobius.gameserver.data.xml.impl.PetSkillData; @@ -353,6 +354,7 @@ public class GameServer if (Config.MULTILANG_ENABLE) { SendMessageLocalisationData.getInstance(); + NpcNameLocalisationData.getInstance(); } printSection("Scripts"); diff --git a/L2J_Mobius_5.5_EtinasFate/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java b/L2J_Mobius_5.5_EtinasFate/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java new file mode 100644 index 0000000000..e374cd78a5 --- /dev/null +++ b/L2J_Mobius_5.5_EtinasFate/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java @@ -0,0 +1,126 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.l2jmobius.gameserver.data.xml.impl; + +import java.io.File; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Logger; + +import org.w3c.dom.Document; + +import org.l2jmobius.Config; +import org.l2jmobius.commons.util.IXmlReader; +import org.l2jmobius.gameserver.model.StatsSet; + +/** + * @author Mobius + */ +public class NpcNameLocalisationData implements IXmlReader +{ + private final static Logger LOGGER = Logger.getLogger(NpcNameLocalisationData.class.getName()); + + private final static Map> NPC_NAME_LOCALISATIONS = new ConcurrentHashMap<>(); + private static String _lang; + + protected NpcNameLocalisationData() + { + load(); + } + + @Override + public void load() + { + NPC_NAME_LOCALISATIONS.clear(); + + if (Config.MULTILANG_ENABLE) + { + for (String lang : Config.MULTILANG_ALLOWED) + { + final File file = new File("data/lang/" + lang + "/NpcNameLocalisation.xml"); + if (!file.isFile()) + { + continue; + } + + NPC_NAME_LOCALISATIONS.put(lang, new ConcurrentHashMap()); + _lang = lang; + parseDatapackFile("data/lang/" + lang + "/NpcNameLocalisation.xml"); + final int count = NPC_NAME_LOCALISATIONS.get(lang).values().size(); + if (count == 0) + { + NPC_NAME_LOCALISATIONS.remove(lang); + } + else + { + LOGGER.info(getClass().getSimpleName() + ": Loaded localisations for '" + lang + "'"); + } + } + } + } + + @Override + public void parseDocument(Document doc, File f) + { + forEach(doc, "list", listNode -> forEach(listNode, "localisation", localisationNode -> + { + final StatsSet set = new StatsSet(parseAttributes(localisationNode)); + NPC_NAME_LOCALISATIONS.get(_lang).put(set.getInt("id"), new String[] + { + set.getString("name"), + set.getString("title") + }); + })); + } + + /** + * @param lang + * @param id + * @return a String Array[] that contains NPC name and title or Null if is does not exist. + */ + public String[] getLocalisation(String lang, int id) + { + final Map localisations = NPC_NAME_LOCALISATIONS.get(lang); + if (localisations != null) + { + return localisations.get(id); + } + return null; + } + + public boolean hasLocalisation(int id) + { + for (Map data : NPC_NAME_LOCALISATIONS.values()) + { + if (data.containsKey(id)) + { + return true; + } + } + return false; + } + + public static NpcNameLocalisationData getInstance() + { + return SingletonHolder.INSTANCE; + } + + private static class SingletonHolder + { + protected static final NpcNameLocalisationData INSTANCE = new NpcNameLocalisationData(); + } +} diff --git a/L2J_Mobius_5.5_EtinasFate/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java b/L2J_Mobius_5.5_EtinasFate/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java index a2c7b7f649..5f1676d987 100644 --- a/L2J_Mobius_5.5_EtinasFate/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java +++ b/L2J_Mobius_5.5_EtinasFate/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java @@ -69,6 +69,7 @@ import org.l2jmobius.gameserver.data.xml.impl.ExperienceData; import org.l2jmobius.gameserver.data.xml.impl.HennaData; import org.l2jmobius.gameserver.data.xml.impl.MonsterBookData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.PetDataTable; import org.l2jmobius.gameserver.data.xml.impl.PlayerTemplateData; import org.l2jmobius.gameserver.data.xml.impl.PlayerXpPercentLostData; @@ -11643,7 +11644,19 @@ public final class PlayerInstance extends Playable { sm = new SystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2); sm.addPcName(this); - sm.addString(target.getName()); + + // Localisation related. + String targetName = target.getName(); + if (Config.MULTILANG_ENABLE && target.isNpc()) + { + final String[] localisation = NpcNameLocalisationData.getInstance().getLocalisation(_lang, target.getId()); + if (localisation != null) + { + targetName = localisation[0]; + } + } + + sm.addString(targetName); sm.addInt(damage); sm.addPopup(target.getObjectId(), getObjectId(), -damage); } diff --git a/L2J_Mobius_5.5_EtinasFate/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java b/L2J_Mobius_5.5_EtinasFate/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java index 0e9db17a8c..f521339fb1 100644 --- a/L2J_Mobius_5.5_EtinasFate/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java +++ b/L2J_Mobius_5.5_EtinasFate/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java @@ -18,6 +18,7 @@ package org.l2jmobius.gameserver.model.actor.status; import org.l2jmobius.Config; import org.l2jmobius.gameserver.ai.CtrlIntention; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.enums.PrivateStoreType; import org.l2jmobius.gameserver.instancemanager.DuelManager; import org.l2jmobius.gameserver.model.actor.Creature; @@ -253,7 +254,19 @@ public class PlayerStatus extends PlayableStatus // Send a System Message to the PlayerInstance SystemMessage smsg = new SystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2); smsg.addString(getActiveChar().getName()); - smsg.addString(attacker.getName()); + + // Localisation related. + String targetName = attacker.getName(); + if (Config.MULTILANG_ENABLE && attacker.isNpc()) + { + final String[] localisation = NpcNameLocalisationData.getInstance().getLocalisation(getActiveChar().getLang(), attacker.getId()); + if (localisation != null) + { + targetName = localisation[0]; + } + } + + smsg.addString(targetName); smsg.addInt(fullValue); smsg.addPopup(getActiveChar().getObjectId(), attacker.getObjectId(), -fullValue); getActiveChar().sendPacket(smsg); diff --git a/L2J_Mobius_5.5_EtinasFate/java/org/l2jmobius/gameserver/network/GameClient.java b/L2J_Mobius_5.5_EtinasFate/java/org/l2jmobius/gameserver/network/GameClient.java index 4ed506b02a..ed0f223551 100644 --- a/L2J_Mobius_5.5_EtinasFate/java/org/l2jmobius/gameserver/network/GameClient.java +++ b/L2J_Mobius_5.5_EtinasFate/java/org/l2jmobius/gameserver/network/GameClient.java @@ -49,6 +49,7 @@ import org.l2jmobius.gameserver.network.serverpackets.ActionFailed; import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; import org.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket; import org.l2jmobius.gameserver.network.serverpackets.LeaveWorld; +import org.l2jmobius.gameserver.network.serverpackets.NpcInfo; import org.l2jmobius.gameserver.network.serverpackets.NpcSay; import org.l2jmobius.gameserver.network.serverpackets.ServerClose; import org.l2jmobius.gameserver.network.serverpackets.SystemMessage; @@ -268,6 +269,10 @@ public final class GameClient extends ChannelInboundHandler { ((ExShowScreenMessage) packet).setLang(lang); } + else if (packet instanceof NpcInfo) + { + ((NpcInfo) packet).setLang(lang); + } } } diff --git a/L2J_Mobius_5.5_EtinasFate/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java b/L2J_Mobius_5.5_EtinasFate/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java index b9aed30eb3..eb77b0fd17 100644 --- a/L2J_Mobius_5.5_EtinasFate/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java +++ b/L2J_Mobius_5.5_EtinasFate/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java @@ -21,6 +21,8 @@ import java.util.Set; import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketWriter; import org.l2jmobius.gameserver.data.sql.impl.ClanTable; +import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.enums.NpcInfoType; import org.l2jmobius.gameserver.enums.Team; import org.l2jmobius.gameserver.model.actor.Npc; @@ -57,6 +59,40 @@ public class NpcInfo extends AbstractMaskPacket private int _statusMask = 0; private final Set _abnormalVisualEffects; + private String[] _localisation; + + public void setLang(String lang) + { + _localisation = NpcNameLocalisationData.getInstance().getLocalisation(lang, _npc.getId()); + if (_localisation != null) + { + if (!containsMask(NpcInfoType.NAME)) + { + addComponentType(NpcInfoType.NAME); + } + _blockSize -= _npc.getName().length() * 2; + _blockSize += _localisation[0].length() * 2; + + if (!_localisation[1].equals("")) + { + if (!containsMask(NpcInfoType.TITLE)) + { + addComponentType(NpcInfoType.TITLE); + } + final String title = _npc.getTitle(); + _initSize -= title.length() * 2; + if (title.equals("")) + { + _initSize += _localisation[1].length() * 2; + } + else + { + _initSize += title.replace(NpcData.getInstance().getTemplate(_npc.getId()).getTitle(), _localisation[1]).length() * 2; + } + } + } + } + public NpcInfo(Npc npc) { _npc = npc; @@ -283,7 +319,22 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.TITLE)) { - packet.writeS(_npc.getTitle()); + String title = _npc.getTitle(); + + // Localisation related. + if ((_localisation != null) && !_localisation[1].equals("")) + { + if (title.equals("")) + { + title = _localisation[1]; + } + else + { + title = title.replace(NpcData.getInstance().getTemplate(_npc.getId()).getTitle(), _localisation[1]); + } + } + + packet.writeS(title); } // Block 2 @@ -344,7 +395,7 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.FLYING)) { - packet.writeD(_npc.isFlying() ? 0x01 : 00); + packet.writeD(_npc.isFlying() ? 0x01 : 0x00); } if (containsMask(NpcInfoType.CLONE)) { @@ -389,7 +440,7 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.NAME)) { - packet.writeS(_npc.getName()); + packet.writeS(_localisation != null ? _localisation[0] : _npc.getName()); } if (containsMask(NpcInfoType.NAME_NPCSTRINGID)) { diff --git a/L2J_Mobius_6.0_Fafurion/dist/game/data/lang/el/NpcNameLocalisation.xml b/L2J_Mobius_6.0_Fafurion/dist/game/data/lang/el/NpcNameLocalisation.xml new file mode 100644 index 0000000000..e260fd7156 --- /dev/null +++ b/L2J_Mobius_6.0_Fafurion/dist/game/data/lang/el/NpcNameLocalisation.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java b/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java index fc8f01eb2b..328d863377 100644 --- a/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java +++ b/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java @@ -38,6 +38,7 @@ import org.l2jmobius.gameserver.data.xml.impl.FishingData; import org.l2jmobius.gameserver.data.xml.impl.ItemCrystallizationData; import org.l2jmobius.gameserver.data.xml.impl.MultisellData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.OptionData; import org.l2jmobius.gameserver.data.xml.impl.PrimeShopData; import org.l2jmobius.gameserver.data.xml.impl.SayuneData; @@ -340,6 +341,7 @@ public class AdminReload implements IAdminCommandHandler SystemMessageId.loadLocalisations(); NpcStringId.loadLocalisations(); SendMessageLocalisationData.getInstance().load(); + NpcNameLocalisationData.getInstance().load(); AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Localisation data."); break; } diff --git a/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java b/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java index 559eaaea12..26f24c4e52 100644 --- a/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java +++ b/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java @@ -19,9 +19,16 @@ package handlers.voicedcommandhandlers; import java.util.StringTokenizer; import org.l2jmobius.Config; +import org.l2jmobius.commons.concurrent.ThreadPool; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.handler.IVoicedCommandHandler; +import org.l2jmobius.gameserver.model.World; +import org.l2jmobius.gameserver.model.WorldObject; +import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; +import org.l2jmobius.gameserver.network.serverpackets.DeleteObject; import org.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage; +import org.l2jmobius.gameserver.network.serverpackets.NpcInfo; public class Lang implements IVoicedCommandHandler { @@ -61,6 +68,18 @@ public class Lang implements IVoicedCommandHandler { msg.setFile(activeChar, "data/html/mods/Lang/Ok.htm"); activeChar.sendPacket(msg); + for (WorldObject obj : World.getInstance().getVisibleObjects()) + { + if (obj.isNpc() && NpcNameLocalisationData.getInstance().hasLocalisation(obj.getId())) + { + activeChar.sendPacket(new DeleteObject(obj)); + ThreadPool.schedule(() -> + { + activeChar.sendPacket(new NpcInfo((Npc) obj)); + }, 1000); + } + } + activeChar.setTarget(null); return true; } msg.setFile(activeChar, "data/html/mods/Lang/Error.htm"); diff --git a/L2J_Mobius_6.0_Fafurion/dist/game/data/xsd/NpcNameLocalisation.xsd b/L2J_Mobius_6.0_Fafurion/dist/game/data/xsd/NpcNameLocalisation.xsd new file mode 100644 index 0000000000..b8b185243e --- /dev/null +++ b/L2J_Mobius_6.0_Fafurion/dist/game/data/xsd/NpcNameLocalisation.xsd @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/GameServer.java index e43ea524d5..b5c635c4c8 100644 --- a/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/GameServer.java +++ b/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/GameServer.java @@ -81,6 +81,7 @@ import org.l2jmobius.gameserver.data.xml.impl.LuckyGameData; import org.l2jmobius.gameserver.data.xml.impl.MonsterBookData; import org.l2jmobius.gameserver.data.xml.impl.MultisellData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.OptionData; import org.l2jmobius.gameserver.data.xml.impl.PetDataTable; import org.l2jmobius.gameserver.data.xml.impl.PetSkillData; @@ -355,6 +356,7 @@ public class GameServer if (Config.MULTILANG_ENABLE) { SendMessageLocalisationData.getInstance(); + NpcNameLocalisationData.getInstance(); } printSection("Scripts"); diff --git a/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java b/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java new file mode 100644 index 0000000000..e374cd78a5 --- /dev/null +++ b/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java @@ -0,0 +1,126 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.l2jmobius.gameserver.data.xml.impl; + +import java.io.File; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Logger; + +import org.w3c.dom.Document; + +import org.l2jmobius.Config; +import org.l2jmobius.commons.util.IXmlReader; +import org.l2jmobius.gameserver.model.StatsSet; + +/** + * @author Mobius + */ +public class NpcNameLocalisationData implements IXmlReader +{ + private final static Logger LOGGER = Logger.getLogger(NpcNameLocalisationData.class.getName()); + + private final static Map> NPC_NAME_LOCALISATIONS = new ConcurrentHashMap<>(); + private static String _lang; + + protected NpcNameLocalisationData() + { + load(); + } + + @Override + public void load() + { + NPC_NAME_LOCALISATIONS.clear(); + + if (Config.MULTILANG_ENABLE) + { + for (String lang : Config.MULTILANG_ALLOWED) + { + final File file = new File("data/lang/" + lang + "/NpcNameLocalisation.xml"); + if (!file.isFile()) + { + continue; + } + + NPC_NAME_LOCALISATIONS.put(lang, new ConcurrentHashMap()); + _lang = lang; + parseDatapackFile("data/lang/" + lang + "/NpcNameLocalisation.xml"); + final int count = NPC_NAME_LOCALISATIONS.get(lang).values().size(); + if (count == 0) + { + NPC_NAME_LOCALISATIONS.remove(lang); + } + else + { + LOGGER.info(getClass().getSimpleName() + ": Loaded localisations for '" + lang + "'"); + } + } + } + } + + @Override + public void parseDocument(Document doc, File f) + { + forEach(doc, "list", listNode -> forEach(listNode, "localisation", localisationNode -> + { + final StatsSet set = new StatsSet(parseAttributes(localisationNode)); + NPC_NAME_LOCALISATIONS.get(_lang).put(set.getInt("id"), new String[] + { + set.getString("name"), + set.getString("title") + }); + })); + } + + /** + * @param lang + * @param id + * @return a String Array[] that contains NPC name and title or Null if is does not exist. + */ + public String[] getLocalisation(String lang, int id) + { + final Map localisations = NPC_NAME_LOCALISATIONS.get(lang); + if (localisations != null) + { + return localisations.get(id); + } + return null; + } + + public boolean hasLocalisation(int id) + { + for (Map data : NPC_NAME_LOCALISATIONS.values()) + { + if (data.containsKey(id)) + { + return true; + } + } + return false; + } + + public static NpcNameLocalisationData getInstance() + { + return SingletonHolder.INSTANCE; + } + + private static class SingletonHolder + { + protected static final NpcNameLocalisationData INSTANCE = new NpcNameLocalisationData(); + } +} diff --git a/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java b/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java index 75d4ebebc1..5d0158ed21 100644 --- a/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java +++ b/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java @@ -69,6 +69,7 @@ import org.l2jmobius.gameserver.data.xml.impl.ExperienceData; import org.l2jmobius.gameserver.data.xml.impl.HennaData; import org.l2jmobius.gameserver.data.xml.impl.MonsterBookData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.PetDataTable; import org.l2jmobius.gameserver.data.xml.impl.PlayerTemplateData; import org.l2jmobius.gameserver.data.xml.impl.PlayerXpPercentLostData; @@ -11649,7 +11650,19 @@ public final class PlayerInstance extends Playable { sm = new SystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2); sm.addPcName(this); - sm.addString(target.getName()); + + // Localisation related. + String targetName = target.getName(); + if (Config.MULTILANG_ENABLE && target.isNpc()) + { + final String[] localisation = NpcNameLocalisationData.getInstance().getLocalisation(_lang, target.getId()); + if (localisation != null) + { + targetName = localisation[0]; + } + } + + sm.addString(targetName); sm.addInt(damage); sm.addPopup(target.getObjectId(), getObjectId(), -damage); } diff --git a/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java b/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java index 0e9db17a8c..f521339fb1 100644 --- a/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java +++ b/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java @@ -18,6 +18,7 @@ package org.l2jmobius.gameserver.model.actor.status; import org.l2jmobius.Config; import org.l2jmobius.gameserver.ai.CtrlIntention; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.enums.PrivateStoreType; import org.l2jmobius.gameserver.instancemanager.DuelManager; import org.l2jmobius.gameserver.model.actor.Creature; @@ -253,7 +254,19 @@ public class PlayerStatus extends PlayableStatus // Send a System Message to the PlayerInstance SystemMessage smsg = new SystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2); smsg.addString(getActiveChar().getName()); - smsg.addString(attacker.getName()); + + // Localisation related. + String targetName = attacker.getName(); + if (Config.MULTILANG_ENABLE && attacker.isNpc()) + { + final String[] localisation = NpcNameLocalisationData.getInstance().getLocalisation(getActiveChar().getLang(), attacker.getId()); + if (localisation != null) + { + targetName = localisation[0]; + } + } + + smsg.addString(targetName); smsg.addInt(fullValue); smsg.addPopup(getActiveChar().getObjectId(), attacker.getObjectId(), -fullValue); getActiveChar().sendPacket(smsg); diff --git a/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/network/GameClient.java b/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/network/GameClient.java index 4ed506b02a..ed0f223551 100644 --- a/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/network/GameClient.java +++ b/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/network/GameClient.java @@ -49,6 +49,7 @@ import org.l2jmobius.gameserver.network.serverpackets.ActionFailed; import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; import org.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket; import org.l2jmobius.gameserver.network.serverpackets.LeaveWorld; +import org.l2jmobius.gameserver.network.serverpackets.NpcInfo; import org.l2jmobius.gameserver.network.serverpackets.NpcSay; import org.l2jmobius.gameserver.network.serverpackets.ServerClose; import org.l2jmobius.gameserver.network.serverpackets.SystemMessage; @@ -268,6 +269,10 @@ public final class GameClient extends ChannelInboundHandler { ((ExShowScreenMessage) packet).setLang(lang); } + else if (packet instanceof NpcInfo) + { + ((NpcInfo) packet).setLang(lang); + } } } diff --git a/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java b/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java index b9aed30eb3..eb77b0fd17 100644 --- a/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java +++ b/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java @@ -21,6 +21,8 @@ import java.util.Set; import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketWriter; import org.l2jmobius.gameserver.data.sql.impl.ClanTable; +import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.enums.NpcInfoType; import org.l2jmobius.gameserver.enums.Team; import org.l2jmobius.gameserver.model.actor.Npc; @@ -57,6 +59,40 @@ public class NpcInfo extends AbstractMaskPacket private int _statusMask = 0; private final Set _abnormalVisualEffects; + private String[] _localisation; + + public void setLang(String lang) + { + _localisation = NpcNameLocalisationData.getInstance().getLocalisation(lang, _npc.getId()); + if (_localisation != null) + { + if (!containsMask(NpcInfoType.NAME)) + { + addComponentType(NpcInfoType.NAME); + } + _blockSize -= _npc.getName().length() * 2; + _blockSize += _localisation[0].length() * 2; + + if (!_localisation[1].equals("")) + { + if (!containsMask(NpcInfoType.TITLE)) + { + addComponentType(NpcInfoType.TITLE); + } + final String title = _npc.getTitle(); + _initSize -= title.length() * 2; + if (title.equals("")) + { + _initSize += _localisation[1].length() * 2; + } + else + { + _initSize += title.replace(NpcData.getInstance().getTemplate(_npc.getId()).getTitle(), _localisation[1]).length() * 2; + } + } + } + } + public NpcInfo(Npc npc) { _npc = npc; @@ -283,7 +319,22 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.TITLE)) { - packet.writeS(_npc.getTitle()); + String title = _npc.getTitle(); + + // Localisation related. + if ((_localisation != null) && !_localisation[1].equals("")) + { + if (title.equals("")) + { + title = _localisation[1]; + } + else + { + title = title.replace(NpcData.getInstance().getTemplate(_npc.getId()).getTitle(), _localisation[1]); + } + } + + packet.writeS(title); } // Block 2 @@ -344,7 +395,7 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.FLYING)) { - packet.writeD(_npc.isFlying() ? 0x01 : 00); + packet.writeD(_npc.isFlying() ? 0x01 : 0x00); } if (containsMask(NpcInfoType.CLONE)) { @@ -389,7 +440,7 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.NAME)) { - packet.writeS(_npc.getName()); + packet.writeS(_localisation != null ? _localisation[0] : _npc.getName()); } if (containsMask(NpcInfoType.NAME_NPCSTRINGID)) { diff --git a/L2J_Mobius_CT_2.6_HighFive/dist/game/data/lang/el/NpcNameLocalisation.xml b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/lang/el/NpcNameLocalisation.xml new file mode 100644 index 0000000000..e260fd7156 --- /dev/null +++ b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/lang/el/NpcNameLocalisation.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java index 4bb4693b02..823bf3e16b 100644 --- a/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java +++ b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java @@ -33,6 +33,7 @@ import org.l2jmobius.gameserver.data.xml.impl.EnchantItemGroupsData; import org.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import org.l2jmobius.gameserver.data.xml.impl.MultisellData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.PrimeShopData; import org.l2jmobius.gameserver.data.xml.impl.SendMessageLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.SkillData; @@ -285,6 +286,7 @@ public class AdminReload implements IAdminCommandHandler SystemMessageId.loadLocalisations(); NpcStringId.loadLocalisations(); SendMessageLocalisationData.getInstance().load(); + NpcNameLocalisationData.getInstance().load(); AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Localisation data."); break; } diff --git a/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java index 4aca2e64c7..2367fbe022 100644 --- a/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java +++ b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java @@ -19,8 +19,15 @@ package handlers.voicedcommandhandlers; import java.util.StringTokenizer; import org.l2jmobius.Config; +import org.l2jmobius.commons.concurrent.ThreadPool; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.handler.IVoicedCommandHandler; +import org.l2jmobius.gameserver.model.World; +import org.l2jmobius.gameserver.model.WorldObject; +import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; +import org.l2jmobius.gameserver.network.serverpackets.AbstractNpcInfo.NpcInfo; +import org.l2jmobius.gameserver.network.serverpackets.DeleteObject; import org.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage; public class Lang implements IVoicedCommandHandler @@ -61,6 +68,18 @@ public class Lang implements IVoicedCommandHandler { msg.setFile(activeChar, "data/html/mods/Lang/Ok.htm"); activeChar.sendPacket(msg); + for (WorldObject obj : World.getInstance().getVisibleObjects()) + { + if (obj.isNpc() && NpcNameLocalisationData.getInstance().hasLocalisation(obj.getId())) + { + activeChar.sendPacket(new DeleteObject(obj)); + ThreadPool.schedule(() -> + { + activeChar.sendPacket(new NpcInfo((Npc) obj, activeChar)); + }, 1000); + } + } + activeChar.setTarget(null); return true; } msg.setFile(activeChar, "data/html/mods/Lang/Error.htm"); diff --git a/L2J_Mobius_CT_2.6_HighFive/dist/game/data/xsd/NpcNameLocalisation.xsd b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/xsd/NpcNameLocalisation.xsd new file mode 100644 index 0000000000..b8b185243e --- /dev/null +++ b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/xsd/NpcNameLocalisation.xsd @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/GameServer.java index 00c3f41784..92c2cd1b4e 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/GameServer.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/GameServer.java @@ -65,6 +65,7 @@ import org.l2jmobius.gameserver.data.xml.impl.InitialShortcutData; import org.l2jmobius.gameserver.data.xml.impl.KarmaData; import org.l2jmobius.gameserver.data.xml.impl.MultisellData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.OptionData; import org.l2jmobius.gameserver.data.xml.impl.PetDataTable; import org.l2jmobius.gameserver.data.xml.impl.PetSkillData; @@ -331,6 +332,7 @@ public class GameServer if (Config.MULTILANG_ENABLE) { SendMessageLocalisationData.getInstance(); + NpcNameLocalisationData.getInstance(); } printSection("Scripts"); diff --git a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java new file mode 100644 index 0000000000..e374cd78a5 --- /dev/null +++ b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java @@ -0,0 +1,126 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.l2jmobius.gameserver.data.xml.impl; + +import java.io.File; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Logger; + +import org.w3c.dom.Document; + +import org.l2jmobius.Config; +import org.l2jmobius.commons.util.IXmlReader; +import org.l2jmobius.gameserver.model.StatsSet; + +/** + * @author Mobius + */ +public class NpcNameLocalisationData implements IXmlReader +{ + private final static Logger LOGGER = Logger.getLogger(NpcNameLocalisationData.class.getName()); + + private final static Map> NPC_NAME_LOCALISATIONS = new ConcurrentHashMap<>(); + private static String _lang; + + protected NpcNameLocalisationData() + { + load(); + } + + @Override + public void load() + { + NPC_NAME_LOCALISATIONS.clear(); + + if (Config.MULTILANG_ENABLE) + { + for (String lang : Config.MULTILANG_ALLOWED) + { + final File file = new File("data/lang/" + lang + "/NpcNameLocalisation.xml"); + if (!file.isFile()) + { + continue; + } + + NPC_NAME_LOCALISATIONS.put(lang, new ConcurrentHashMap()); + _lang = lang; + parseDatapackFile("data/lang/" + lang + "/NpcNameLocalisation.xml"); + final int count = NPC_NAME_LOCALISATIONS.get(lang).values().size(); + if (count == 0) + { + NPC_NAME_LOCALISATIONS.remove(lang); + } + else + { + LOGGER.info(getClass().getSimpleName() + ": Loaded localisations for '" + lang + "'"); + } + } + } + } + + @Override + public void parseDocument(Document doc, File f) + { + forEach(doc, "list", listNode -> forEach(listNode, "localisation", localisationNode -> + { + final StatsSet set = new StatsSet(parseAttributes(localisationNode)); + NPC_NAME_LOCALISATIONS.get(_lang).put(set.getInt("id"), new String[] + { + set.getString("name"), + set.getString("title") + }); + })); + } + + /** + * @param lang + * @param id + * @return a String Array[] that contains NPC name and title or Null if is does not exist. + */ + public String[] getLocalisation(String lang, int id) + { + final Map localisations = NPC_NAME_LOCALISATIONS.get(lang); + if (localisations != null) + { + return localisations.get(id); + } + return null; + } + + public boolean hasLocalisation(int id) + { + for (Map data : NPC_NAME_LOCALISATIONS.values()) + { + if (data.containsKey(id)) + { + return true; + } + } + return false; + } + + public static NpcNameLocalisationData getInstance() + { + return SingletonHolder.INSTANCE; + } + + private static class SingletonHolder + { + protected static final NpcNameLocalisationData INSTANCE = new NpcNameLocalisationData(); + } +} diff --git a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java index 7b95c15b88..5da180d3f5 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java @@ -71,6 +71,7 @@ import org.l2jmobius.gameserver.data.xml.impl.ExperienceData; import org.l2jmobius.gameserver.data.xml.impl.FishData; import org.l2jmobius.gameserver.data.xml.impl.HennaData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.PetDataTable; import org.l2jmobius.gameserver.data.xml.impl.PlayerTemplateData; import org.l2jmobius.gameserver.data.xml.impl.PlayerXpPercentLostData; @@ -12592,7 +12593,19 @@ public final class PlayerInstance extends Playable { sm = new SystemMessage(SystemMessageId.C1_HAS_DONE_S3_POINTS_OF_DAMAGE_TO_C2); sm.addPcName(this); - sm.addString(target.getName()); + + // Localisation related. + String targetName = target.getName(); + if (Config.MULTILANG_ENABLE && target.isNpc()) + { + final String[] localisation = NpcNameLocalisationData.getInstance().getLocalisation(_lang, target.getId()); + if (localisation != null) + { + targetName = localisation[0]; + } + } + + sm.addString(targetName); sm.addInt(damage); } diff --git a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java index 4aff039a8f..5d18236814 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java @@ -19,6 +19,7 @@ package org.l2jmobius.gameserver.model.actor.status; import org.l2jmobius.Config; import org.l2jmobius.commons.util.Rnd; import org.l2jmobius.gameserver.ai.CtrlIntention; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.enums.PrivateStoreType; import org.l2jmobius.gameserver.instancemanager.DuelManager; import org.l2jmobius.gameserver.model.actor.Creature; @@ -226,11 +227,22 @@ public class PlayerStatus extends PlayableStatus if ((fullValue > 0) && !isDOT) { - SystemMessage smsg; // Send a System Message to the PlayerInstance - smsg = new SystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2); + SystemMessage smsg = new SystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2); smsg.addString(getActiveChar().getName()); - smsg.addString(attacker.getName()); + + // Localisation related. + String targetName = attacker.getName(); + if (Config.MULTILANG_ENABLE && attacker.isNpc()) + { + final String[] localisation = NpcNameLocalisationData.getInstance().getLocalisation(getActiveChar().getLang(), attacker.getId()); + if (localisation != null) + { + targetName = localisation[0]; + } + } + + smsg.addString(targetName); smsg.addInt(fullValue); getActiveChar().sendPacket(smsg); diff --git a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/network/GameClient.java b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/network/GameClient.java index f2b0d40f22..c5bf66e8b0 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/network/GameClient.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/network/GameClient.java @@ -40,6 +40,7 @@ import org.l2jmobius.gameserver.model.CharSelectInfoPackage; import org.l2jmobius.gameserver.model.World; import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; import org.l2jmobius.gameserver.model.clan.Clan; +import org.l2jmobius.gameserver.network.serverpackets.AbstractNpcInfo.NpcInfo; import org.l2jmobius.gameserver.network.serverpackets.ActionFailed; import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; import org.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket; @@ -263,6 +264,10 @@ public final class GameClient extends ChannelInboundHandler { ((ExShowScreenMessage) packet).setLang(lang); } + else if (packet instanceof NpcInfo) + { + ((NpcInfo) packet).setLang(lang); + } } } diff --git a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/network/serverpackets/AbstractNpcInfo.java b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/network/serverpackets/AbstractNpcInfo.java index 31d27bc273..d13c40effe 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/network/serverpackets/AbstractNpcInfo.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/network/serverpackets/AbstractNpcInfo.java @@ -19,6 +19,7 @@ package org.l2jmobius.gameserver.network.serverpackets; import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketWriter; import org.l2jmobius.gameserver.data.sql.impl.ClanTable; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.instancemanager.TownManager; import org.l2jmobius.gameserver.model.PlayerCondOverride; import org.l2jmobius.gameserver.model.actor.Creature; @@ -90,6 +91,17 @@ public abstract class AbstractNpcInfo implements IClientOutgoingPacket private int _allyId = 0; private int _clanId = 0; private int _displayEffect = 0; + private String[] _localisation; + + public void setLang(String lang) + { + _localisation = NpcNameLocalisationData.getInstance().getLocalisation(lang, _npc.getId()); + if (_localisation != null) + { + _name = _localisation[0]; + _title = _localisation[1]; + } + } public NpcInfo(Npc cha, Creature attacker) { @@ -102,9 +114,10 @@ public abstract class AbstractNpcInfo implements IClientOutgoingPacket _collisionHeight = cha.getCollisionHeight();// On every subclass _collisionRadius = cha.getCollisionRadius();// On every subclass _isAttackable = cha.isAutoAttackable(attacker); - if (cha.getTemplate().isUsingServerSideName()) + + if (_name.equals("") && cha.getTemplate().isUsingServerSideName()) { - _name = cha.getName();// On every subclass + _name = cha.getName(); // On every subclass } if (_npc.isInvisible()) @@ -115,13 +128,16 @@ public abstract class AbstractNpcInfo implements IClientOutgoingPacket { _title = (Config.CHAMP_TITLE); // On every subclass } - else if (cha.getTemplate().isUsingServerSideTitle()) + else if (_title.equals("")) { - _title = cha.getTemplate().getTitle(); // On every subclass - } - else - { - _title = cha.getTitle(); // On every subclass + if (cha.getTemplate().isUsingServerSideTitle()) + { + _title = cha.getTemplate().getTitle(); // On every subclass + } + else + { + _title = cha.getTitle(); // On every subclass + } } if (Config.SHOW_NPC_LVL && _npc.isMonster()) diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/lang/el/NpcNameLocalisation.xml b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/lang/el/NpcNameLocalisation.xml new file mode 100644 index 0000000000..e260fd7156 --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/lang/el/NpcNameLocalisation.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java index 7bee2f3d02..3c26c6f57b 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java +++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java @@ -37,6 +37,7 @@ import org.l2jmobius.gameserver.data.xml.impl.FishingData; import org.l2jmobius.gameserver.data.xml.impl.ItemCrystallizationData; import org.l2jmobius.gameserver.data.xml.impl.MultisellData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.OptionData; import org.l2jmobius.gameserver.data.xml.impl.PrimeShopData; import org.l2jmobius.gameserver.data.xml.impl.SayuneData; @@ -333,6 +334,7 @@ public class AdminReload implements IAdminCommandHandler SystemMessageId.loadLocalisations(); NpcStringId.loadLocalisations(); SendMessageLocalisationData.getInstance().load(); + NpcNameLocalisationData.getInstance().load(); AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Localisation data."); break; } diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java index 559eaaea12..26f24c4e52 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java +++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java @@ -19,9 +19,16 @@ package handlers.voicedcommandhandlers; import java.util.StringTokenizer; import org.l2jmobius.Config; +import org.l2jmobius.commons.concurrent.ThreadPool; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.handler.IVoicedCommandHandler; +import org.l2jmobius.gameserver.model.World; +import org.l2jmobius.gameserver.model.WorldObject; +import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; +import org.l2jmobius.gameserver.network.serverpackets.DeleteObject; import org.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage; +import org.l2jmobius.gameserver.network.serverpackets.NpcInfo; public class Lang implements IVoicedCommandHandler { @@ -61,6 +68,18 @@ public class Lang implements IVoicedCommandHandler { msg.setFile(activeChar, "data/html/mods/Lang/Ok.htm"); activeChar.sendPacket(msg); + for (WorldObject obj : World.getInstance().getVisibleObjects()) + { + if (obj.isNpc() && NpcNameLocalisationData.getInstance().hasLocalisation(obj.getId())) + { + activeChar.sendPacket(new DeleteObject(obj)); + ThreadPool.schedule(() -> + { + activeChar.sendPacket(new NpcInfo((Npc) obj)); + }, 1000); + } + } + activeChar.setTarget(null); return true; } msg.setFile(activeChar, "data/html/mods/Lang/Error.htm"); diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/xsd/NpcNameLocalisation.xsd b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/xsd/NpcNameLocalisation.xsd new file mode 100644 index 0000000000..b8b185243e --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/xsd/NpcNameLocalisation.xsd @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/GameServer.java index ccb8c7d068..b0ed8693fe 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/GameServer.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/GameServer.java @@ -76,6 +76,7 @@ import org.l2jmobius.gameserver.data.xml.impl.KarmaData; import org.l2jmobius.gameserver.data.xml.impl.LuckyGameData; import org.l2jmobius.gameserver.data.xml.impl.MultisellData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.OptionData; import org.l2jmobius.gameserver.data.xml.impl.PetDataTable; import org.l2jmobius.gameserver.data.xml.impl.PetSkillData; @@ -345,6 +346,7 @@ public class GameServer if (Config.MULTILANG_ENABLE) { SendMessageLocalisationData.getInstance(); + NpcNameLocalisationData.getInstance(); } printSection("Scripts"); diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java new file mode 100644 index 0000000000..e374cd78a5 --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java @@ -0,0 +1,126 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.l2jmobius.gameserver.data.xml.impl; + +import java.io.File; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Logger; + +import org.w3c.dom.Document; + +import org.l2jmobius.Config; +import org.l2jmobius.commons.util.IXmlReader; +import org.l2jmobius.gameserver.model.StatsSet; + +/** + * @author Mobius + */ +public class NpcNameLocalisationData implements IXmlReader +{ + private final static Logger LOGGER = Logger.getLogger(NpcNameLocalisationData.class.getName()); + + private final static Map> NPC_NAME_LOCALISATIONS = new ConcurrentHashMap<>(); + private static String _lang; + + protected NpcNameLocalisationData() + { + load(); + } + + @Override + public void load() + { + NPC_NAME_LOCALISATIONS.clear(); + + if (Config.MULTILANG_ENABLE) + { + for (String lang : Config.MULTILANG_ALLOWED) + { + final File file = new File("data/lang/" + lang + "/NpcNameLocalisation.xml"); + if (!file.isFile()) + { + continue; + } + + NPC_NAME_LOCALISATIONS.put(lang, new ConcurrentHashMap()); + _lang = lang; + parseDatapackFile("data/lang/" + lang + "/NpcNameLocalisation.xml"); + final int count = NPC_NAME_LOCALISATIONS.get(lang).values().size(); + if (count == 0) + { + NPC_NAME_LOCALISATIONS.remove(lang); + } + else + { + LOGGER.info(getClass().getSimpleName() + ": Loaded localisations for '" + lang + "'"); + } + } + } + } + + @Override + public void parseDocument(Document doc, File f) + { + forEach(doc, "list", listNode -> forEach(listNode, "localisation", localisationNode -> + { + final StatsSet set = new StatsSet(parseAttributes(localisationNode)); + NPC_NAME_LOCALISATIONS.get(_lang).put(set.getInt("id"), new String[] + { + set.getString("name"), + set.getString("title") + }); + })); + } + + /** + * @param lang + * @param id + * @return a String Array[] that contains NPC name and title or Null if is does not exist. + */ + public String[] getLocalisation(String lang, int id) + { + final Map localisations = NPC_NAME_LOCALISATIONS.get(lang); + if (localisations != null) + { + return localisations.get(id); + } + return null; + } + + public boolean hasLocalisation(int id) + { + for (Map data : NPC_NAME_LOCALISATIONS.values()) + { + if (data.containsKey(id)) + { + return true; + } + } + return false; + } + + public static NpcNameLocalisationData getInstance() + { + return SingletonHolder.INSTANCE; + } + + private static class SingletonHolder + { + protected static final NpcNameLocalisationData INSTANCE = new NpcNameLocalisationData(); + } +} diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java index b8901a4db0..220f355070 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java @@ -68,6 +68,7 @@ import org.l2jmobius.gameserver.data.xml.impl.ClassListData; import org.l2jmobius.gameserver.data.xml.impl.ExperienceData; import org.l2jmobius.gameserver.data.xml.impl.HennaData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.PetDataTable; import org.l2jmobius.gameserver.data.xml.impl.PlayerTemplateData; import org.l2jmobius.gameserver.data.xml.impl.PlayerXpPercentLostData; @@ -11500,7 +11501,19 @@ public final class PlayerInstance extends Playable { sm = new SystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2); sm.addPcName(this); - sm.addString(target.getName()); + + // Localisation related. + String targetName = target.getName(); + if (Config.MULTILANG_ENABLE && target.isNpc()) + { + final String[] localisation = NpcNameLocalisationData.getInstance().getLocalisation(_lang, target.getId()); + if (localisation != null) + { + targetName = localisation[0]; + } + } + + sm.addString(targetName); sm.addInt(damage); sm.addPopup(target.getObjectId(), getObjectId(), -damage); } diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java index 64d1bdbd1c..df33eb168e 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java @@ -18,6 +18,7 @@ package org.l2jmobius.gameserver.model.actor.status; import org.l2jmobius.Config; import org.l2jmobius.gameserver.ai.CtrlIntention; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.enums.PrivateStoreType; import org.l2jmobius.gameserver.instancemanager.DuelManager; import org.l2jmobius.gameserver.model.actor.Creature; @@ -253,7 +254,19 @@ public class PlayerStatus extends PlayableStatus // Send a System Message to the PlayerInstance SystemMessage smsg = new SystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2); smsg.addString(getActiveChar().getName()); - smsg.addString(attacker.getName()); + + // Localisation related. + String targetName = attacker.getName(); + if (Config.MULTILANG_ENABLE && attacker.isNpc()) + { + final String[] localisation = NpcNameLocalisationData.getInstance().getLocalisation(getActiveChar().getLang(), attacker.getId()); + if (localisation != null) + { + targetName = localisation[0]; + } + } + + smsg.addString(targetName); smsg.addInt(fullValue); smsg.addPopup(getActiveChar().getObjectId(), attacker.getObjectId(), -fullValue); getActiveChar().sendPacket(smsg); diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/network/GameClient.java b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/network/GameClient.java index 4ed506b02a..ed0f223551 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/network/GameClient.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/network/GameClient.java @@ -49,6 +49,7 @@ import org.l2jmobius.gameserver.network.serverpackets.ActionFailed; import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; import org.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket; import org.l2jmobius.gameserver.network.serverpackets.LeaveWorld; +import org.l2jmobius.gameserver.network.serverpackets.NpcInfo; import org.l2jmobius.gameserver.network.serverpackets.NpcSay; import org.l2jmobius.gameserver.network.serverpackets.ServerClose; import org.l2jmobius.gameserver.network.serverpackets.SystemMessage; @@ -268,6 +269,10 @@ public final class GameClient extends ChannelInboundHandler { ((ExShowScreenMessage) packet).setLang(lang); } + else if (packet instanceof NpcInfo) + { + ((NpcInfo) packet).setLang(lang); + } } } diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java index b9aed30eb3..eb77b0fd17 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java @@ -21,6 +21,8 @@ import java.util.Set; import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketWriter; import org.l2jmobius.gameserver.data.sql.impl.ClanTable; +import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.enums.NpcInfoType; import org.l2jmobius.gameserver.enums.Team; import org.l2jmobius.gameserver.model.actor.Npc; @@ -57,6 +59,40 @@ public class NpcInfo extends AbstractMaskPacket private int _statusMask = 0; private final Set _abnormalVisualEffects; + private String[] _localisation; + + public void setLang(String lang) + { + _localisation = NpcNameLocalisationData.getInstance().getLocalisation(lang, _npc.getId()); + if (_localisation != null) + { + if (!containsMask(NpcInfoType.NAME)) + { + addComponentType(NpcInfoType.NAME); + } + _blockSize -= _npc.getName().length() * 2; + _blockSize += _localisation[0].length() * 2; + + if (!_localisation[1].equals("")) + { + if (!containsMask(NpcInfoType.TITLE)) + { + addComponentType(NpcInfoType.TITLE); + } + final String title = _npc.getTitle(); + _initSize -= title.length() * 2; + if (title.equals("")) + { + _initSize += _localisation[1].length() * 2; + } + else + { + _initSize += title.replace(NpcData.getInstance().getTemplate(_npc.getId()).getTitle(), _localisation[1]).length() * 2; + } + } + } + } + public NpcInfo(Npc npc) { _npc = npc; @@ -283,7 +319,22 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.TITLE)) { - packet.writeS(_npc.getTitle()); + String title = _npc.getTitle(); + + // Localisation related. + if ((_localisation != null) && !_localisation[1].equals("")) + { + if (title.equals("")) + { + title = _localisation[1]; + } + else + { + title = title.replace(NpcData.getInstance().getTemplate(_npc.getId()).getTitle(), _localisation[1]); + } + } + + packet.writeS(title); } // Block 2 @@ -344,7 +395,7 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.FLYING)) { - packet.writeD(_npc.isFlying() ? 0x01 : 00); + packet.writeD(_npc.isFlying() ? 0x01 : 0x00); } if (containsMask(NpcInfoType.CLONE)) { @@ -389,7 +440,7 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.NAME)) { - packet.writeS(_npc.getName()); + packet.writeS(_localisation != null ? _localisation[0] : _npc.getName()); } if (containsMask(NpcInfoType.NAME_NPCSTRINGID)) { diff --git a/L2J_Mobius_Classic_2.1_Zaken/dist/game/data/lang/el/NpcNameLocalisation.xml b/L2J_Mobius_Classic_2.1_Zaken/dist/game/data/lang/el/NpcNameLocalisation.xml new file mode 100644 index 0000000000..e260fd7156 --- /dev/null +++ b/L2J_Mobius_Classic_2.1_Zaken/dist/game/data/lang/el/NpcNameLocalisation.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.1_Zaken/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java b/L2J_Mobius_Classic_2.1_Zaken/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java index 7bee2f3d02..3c26c6f57b 100644 --- a/L2J_Mobius_Classic_2.1_Zaken/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java +++ b/L2J_Mobius_Classic_2.1_Zaken/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java @@ -37,6 +37,7 @@ import org.l2jmobius.gameserver.data.xml.impl.FishingData; import org.l2jmobius.gameserver.data.xml.impl.ItemCrystallizationData; import org.l2jmobius.gameserver.data.xml.impl.MultisellData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.OptionData; import org.l2jmobius.gameserver.data.xml.impl.PrimeShopData; import org.l2jmobius.gameserver.data.xml.impl.SayuneData; @@ -333,6 +334,7 @@ public class AdminReload implements IAdminCommandHandler SystemMessageId.loadLocalisations(); NpcStringId.loadLocalisations(); SendMessageLocalisationData.getInstance().load(); + NpcNameLocalisationData.getInstance().load(); AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Localisation data."); break; } diff --git a/L2J_Mobius_Classic_2.1_Zaken/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java b/L2J_Mobius_Classic_2.1_Zaken/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java index 559eaaea12..26f24c4e52 100644 --- a/L2J_Mobius_Classic_2.1_Zaken/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java +++ b/L2J_Mobius_Classic_2.1_Zaken/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java @@ -19,9 +19,16 @@ package handlers.voicedcommandhandlers; import java.util.StringTokenizer; import org.l2jmobius.Config; +import org.l2jmobius.commons.concurrent.ThreadPool; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.handler.IVoicedCommandHandler; +import org.l2jmobius.gameserver.model.World; +import org.l2jmobius.gameserver.model.WorldObject; +import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; +import org.l2jmobius.gameserver.network.serverpackets.DeleteObject; import org.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage; +import org.l2jmobius.gameserver.network.serverpackets.NpcInfo; public class Lang implements IVoicedCommandHandler { @@ -61,6 +68,18 @@ public class Lang implements IVoicedCommandHandler { msg.setFile(activeChar, "data/html/mods/Lang/Ok.htm"); activeChar.sendPacket(msg); + for (WorldObject obj : World.getInstance().getVisibleObjects()) + { + if (obj.isNpc() && NpcNameLocalisationData.getInstance().hasLocalisation(obj.getId())) + { + activeChar.sendPacket(new DeleteObject(obj)); + ThreadPool.schedule(() -> + { + activeChar.sendPacket(new NpcInfo((Npc) obj)); + }, 1000); + } + } + activeChar.setTarget(null); return true; } msg.setFile(activeChar, "data/html/mods/Lang/Error.htm"); diff --git a/L2J_Mobius_Classic_2.1_Zaken/dist/game/data/xsd/NpcNameLocalisation.xsd b/L2J_Mobius_Classic_2.1_Zaken/dist/game/data/xsd/NpcNameLocalisation.xsd new file mode 100644 index 0000000000..b8b185243e --- /dev/null +++ b/L2J_Mobius_Classic_2.1_Zaken/dist/game/data/xsd/NpcNameLocalisation.xsd @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/GameServer.java index ccb8c7d068..b0ed8693fe 100644 --- a/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/GameServer.java +++ b/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/GameServer.java @@ -76,6 +76,7 @@ import org.l2jmobius.gameserver.data.xml.impl.KarmaData; import org.l2jmobius.gameserver.data.xml.impl.LuckyGameData; import org.l2jmobius.gameserver.data.xml.impl.MultisellData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.OptionData; import org.l2jmobius.gameserver.data.xml.impl.PetDataTable; import org.l2jmobius.gameserver.data.xml.impl.PetSkillData; @@ -345,6 +346,7 @@ public class GameServer if (Config.MULTILANG_ENABLE) { SendMessageLocalisationData.getInstance(); + NpcNameLocalisationData.getInstance(); } printSection("Scripts"); diff --git a/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java b/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java new file mode 100644 index 0000000000..e374cd78a5 --- /dev/null +++ b/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java @@ -0,0 +1,126 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.l2jmobius.gameserver.data.xml.impl; + +import java.io.File; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Logger; + +import org.w3c.dom.Document; + +import org.l2jmobius.Config; +import org.l2jmobius.commons.util.IXmlReader; +import org.l2jmobius.gameserver.model.StatsSet; + +/** + * @author Mobius + */ +public class NpcNameLocalisationData implements IXmlReader +{ + private final static Logger LOGGER = Logger.getLogger(NpcNameLocalisationData.class.getName()); + + private final static Map> NPC_NAME_LOCALISATIONS = new ConcurrentHashMap<>(); + private static String _lang; + + protected NpcNameLocalisationData() + { + load(); + } + + @Override + public void load() + { + NPC_NAME_LOCALISATIONS.clear(); + + if (Config.MULTILANG_ENABLE) + { + for (String lang : Config.MULTILANG_ALLOWED) + { + final File file = new File("data/lang/" + lang + "/NpcNameLocalisation.xml"); + if (!file.isFile()) + { + continue; + } + + NPC_NAME_LOCALISATIONS.put(lang, new ConcurrentHashMap()); + _lang = lang; + parseDatapackFile("data/lang/" + lang + "/NpcNameLocalisation.xml"); + final int count = NPC_NAME_LOCALISATIONS.get(lang).values().size(); + if (count == 0) + { + NPC_NAME_LOCALISATIONS.remove(lang); + } + else + { + LOGGER.info(getClass().getSimpleName() + ": Loaded localisations for '" + lang + "'"); + } + } + } + } + + @Override + public void parseDocument(Document doc, File f) + { + forEach(doc, "list", listNode -> forEach(listNode, "localisation", localisationNode -> + { + final StatsSet set = new StatsSet(parseAttributes(localisationNode)); + NPC_NAME_LOCALISATIONS.get(_lang).put(set.getInt("id"), new String[] + { + set.getString("name"), + set.getString("title") + }); + })); + } + + /** + * @param lang + * @param id + * @return a String Array[] that contains NPC name and title or Null if is does not exist. + */ + public String[] getLocalisation(String lang, int id) + { + final Map localisations = NPC_NAME_LOCALISATIONS.get(lang); + if (localisations != null) + { + return localisations.get(id); + } + return null; + } + + public boolean hasLocalisation(int id) + { + for (Map data : NPC_NAME_LOCALISATIONS.values()) + { + if (data.containsKey(id)) + { + return true; + } + } + return false; + } + + public static NpcNameLocalisationData getInstance() + { + return SingletonHolder.INSTANCE; + } + + private static class SingletonHolder + { + protected static final NpcNameLocalisationData INSTANCE = new NpcNameLocalisationData(); + } +} diff --git a/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java b/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java index 0bbe86ec44..b44610d91c 100644 --- a/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java +++ b/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java @@ -68,6 +68,7 @@ import org.l2jmobius.gameserver.data.xml.impl.ClassListData; import org.l2jmobius.gameserver.data.xml.impl.ExperienceData; import org.l2jmobius.gameserver.data.xml.impl.HennaData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.PetDataTable; import org.l2jmobius.gameserver.data.xml.impl.PlayerTemplateData; import org.l2jmobius.gameserver.data.xml.impl.PlayerXpPercentLostData; @@ -11507,7 +11508,19 @@ public final class PlayerInstance extends Playable { sm = new SystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2); sm.addPcName(this); - sm.addString(target.getName()); + + // Localisation related. + String targetName = target.getName(); + if (Config.MULTILANG_ENABLE && target.isNpc()) + { + final String[] localisation = NpcNameLocalisationData.getInstance().getLocalisation(_lang, target.getId()); + if (localisation != null) + { + targetName = localisation[0]; + } + } + + sm.addString(targetName); sm.addInt(damage); sm.addPopup(target.getObjectId(), getObjectId(), -damage); } diff --git a/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java b/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java index 64d1bdbd1c..df33eb168e 100644 --- a/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java +++ b/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java @@ -18,6 +18,7 @@ package org.l2jmobius.gameserver.model.actor.status; import org.l2jmobius.Config; import org.l2jmobius.gameserver.ai.CtrlIntention; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.enums.PrivateStoreType; import org.l2jmobius.gameserver.instancemanager.DuelManager; import org.l2jmobius.gameserver.model.actor.Creature; @@ -253,7 +254,19 @@ public class PlayerStatus extends PlayableStatus // Send a System Message to the PlayerInstance SystemMessage smsg = new SystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2); smsg.addString(getActiveChar().getName()); - smsg.addString(attacker.getName()); + + // Localisation related. + String targetName = attacker.getName(); + if (Config.MULTILANG_ENABLE && attacker.isNpc()) + { + final String[] localisation = NpcNameLocalisationData.getInstance().getLocalisation(getActiveChar().getLang(), attacker.getId()); + if (localisation != null) + { + targetName = localisation[0]; + } + } + + smsg.addString(targetName); smsg.addInt(fullValue); smsg.addPopup(getActiveChar().getObjectId(), attacker.getObjectId(), -fullValue); getActiveChar().sendPacket(smsg); diff --git a/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/network/GameClient.java b/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/network/GameClient.java index 4ed506b02a..ed0f223551 100644 --- a/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/network/GameClient.java +++ b/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/network/GameClient.java @@ -49,6 +49,7 @@ import org.l2jmobius.gameserver.network.serverpackets.ActionFailed; import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; import org.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket; import org.l2jmobius.gameserver.network.serverpackets.LeaveWorld; +import org.l2jmobius.gameserver.network.serverpackets.NpcInfo; import org.l2jmobius.gameserver.network.serverpackets.NpcSay; import org.l2jmobius.gameserver.network.serverpackets.ServerClose; import org.l2jmobius.gameserver.network.serverpackets.SystemMessage; @@ -268,6 +269,10 @@ public final class GameClient extends ChannelInboundHandler { ((ExShowScreenMessage) packet).setLang(lang); } + else if (packet instanceof NpcInfo) + { + ((NpcInfo) packet).setLang(lang); + } } } diff --git a/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java b/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java index b9aed30eb3..eb77b0fd17 100644 --- a/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java +++ b/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java @@ -21,6 +21,8 @@ import java.util.Set; import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketWriter; import org.l2jmobius.gameserver.data.sql.impl.ClanTable; +import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.enums.NpcInfoType; import org.l2jmobius.gameserver.enums.Team; import org.l2jmobius.gameserver.model.actor.Npc; @@ -57,6 +59,40 @@ public class NpcInfo extends AbstractMaskPacket private int _statusMask = 0; private final Set _abnormalVisualEffects; + private String[] _localisation; + + public void setLang(String lang) + { + _localisation = NpcNameLocalisationData.getInstance().getLocalisation(lang, _npc.getId()); + if (_localisation != null) + { + if (!containsMask(NpcInfoType.NAME)) + { + addComponentType(NpcInfoType.NAME); + } + _blockSize -= _npc.getName().length() * 2; + _blockSize += _localisation[0].length() * 2; + + if (!_localisation[1].equals("")) + { + if (!containsMask(NpcInfoType.TITLE)) + { + addComponentType(NpcInfoType.TITLE); + } + final String title = _npc.getTitle(); + _initSize -= title.length() * 2; + if (title.equals("")) + { + _initSize += _localisation[1].length() * 2; + } + else + { + _initSize += title.replace(NpcData.getInstance().getTemplate(_npc.getId()).getTitle(), _localisation[1]).length() * 2; + } + } + } + } + public NpcInfo(Npc npc) { _npc = npc; @@ -283,7 +319,22 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.TITLE)) { - packet.writeS(_npc.getTitle()); + String title = _npc.getTitle(); + + // Localisation related. + if ((_localisation != null) && !_localisation[1].equals("")) + { + if (title.equals("")) + { + title = _localisation[1]; + } + else + { + title = title.replace(NpcData.getInstance().getTemplate(_npc.getId()).getTitle(), _localisation[1]); + } + } + + packet.writeS(title); } // Block 2 @@ -344,7 +395,7 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.FLYING)) { - packet.writeD(_npc.isFlying() ? 0x01 : 00); + packet.writeD(_npc.isFlying() ? 0x01 : 0x00); } if (containsMask(NpcInfoType.CLONE)) { @@ -389,7 +440,7 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.NAME)) { - packet.writeS(_npc.getName()); + packet.writeS(_localisation != null ? _localisation[0] : _npc.getName()); } if (containsMask(NpcInfoType.NAME_NPCSTRINGID)) { diff --git a/L2J_Mobius_Classic_2.2_Antharas/dist/game/data/lang/el/NpcNameLocalisation.xml b/L2J_Mobius_Classic_2.2_Antharas/dist/game/data/lang/el/NpcNameLocalisation.xml new file mode 100644 index 0000000000..e260fd7156 --- /dev/null +++ b/L2J_Mobius_Classic_2.2_Antharas/dist/game/data/lang/el/NpcNameLocalisation.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.2_Antharas/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java b/L2J_Mobius_Classic_2.2_Antharas/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java index 7bee2f3d02..3c26c6f57b 100644 --- a/L2J_Mobius_Classic_2.2_Antharas/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java +++ b/L2J_Mobius_Classic_2.2_Antharas/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java @@ -37,6 +37,7 @@ import org.l2jmobius.gameserver.data.xml.impl.FishingData; import org.l2jmobius.gameserver.data.xml.impl.ItemCrystallizationData; import org.l2jmobius.gameserver.data.xml.impl.MultisellData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.OptionData; import org.l2jmobius.gameserver.data.xml.impl.PrimeShopData; import org.l2jmobius.gameserver.data.xml.impl.SayuneData; @@ -333,6 +334,7 @@ public class AdminReload implements IAdminCommandHandler SystemMessageId.loadLocalisations(); NpcStringId.loadLocalisations(); SendMessageLocalisationData.getInstance().load(); + NpcNameLocalisationData.getInstance().load(); AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Localisation data."); break; } diff --git a/L2J_Mobius_Classic_2.2_Antharas/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java b/L2J_Mobius_Classic_2.2_Antharas/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java index 559eaaea12..26f24c4e52 100644 --- a/L2J_Mobius_Classic_2.2_Antharas/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java +++ b/L2J_Mobius_Classic_2.2_Antharas/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java @@ -19,9 +19,16 @@ package handlers.voicedcommandhandlers; import java.util.StringTokenizer; import org.l2jmobius.Config; +import org.l2jmobius.commons.concurrent.ThreadPool; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.handler.IVoicedCommandHandler; +import org.l2jmobius.gameserver.model.World; +import org.l2jmobius.gameserver.model.WorldObject; +import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; +import org.l2jmobius.gameserver.network.serverpackets.DeleteObject; import org.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage; +import org.l2jmobius.gameserver.network.serverpackets.NpcInfo; public class Lang implements IVoicedCommandHandler { @@ -61,6 +68,18 @@ public class Lang implements IVoicedCommandHandler { msg.setFile(activeChar, "data/html/mods/Lang/Ok.htm"); activeChar.sendPacket(msg); + for (WorldObject obj : World.getInstance().getVisibleObjects()) + { + if (obj.isNpc() && NpcNameLocalisationData.getInstance().hasLocalisation(obj.getId())) + { + activeChar.sendPacket(new DeleteObject(obj)); + ThreadPool.schedule(() -> + { + activeChar.sendPacket(new NpcInfo((Npc) obj)); + }, 1000); + } + } + activeChar.setTarget(null); return true; } msg.setFile(activeChar, "data/html/mods/Lang/Error.htm"); diff --git a/L2J_Mobius_Classic_2.2_Antharas/dist/game/data/xsd/NpcNameLocalisation.xsd b/L2J_Mobius_Classic_2.2_Antharas/dist/game/data/xsd/NpcNameLocalisation.xsd new file mode 100644 index 0000000000..b8b185243e --- /dev/null +++ b/L2J_Mobius_Classic_2.2_Antharas/dist/game/data/xsd/NpcNameLocalisation.xsd @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/GameServer.java index ccb8c7d068..b0ed8693fe 100644 --- a/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/GameServer.java +++ b/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/GameServer.java @@ -76,6 +76,7 @@ import org.l2jmobius.gameserver.data.xml.impl.KarmaData; import org.l2jmobius.gameserver.data.xml.impl.LuckyGameData; import org.l2jmobius.gameserver.data.xml.impl.MultisellData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.OptionData; import org.l2jmobius.gameserver.data.xml.impl.PetDataTable; import org.l2jmobius.gameserver.data.xml.impl.PetSkillData; @@ -345,6 +346,7 @@ public class GameServer if (Config.MULTILANG_ENABLE) { SendMessageLocalisationData.getInstance(); + NpcNameLocalisationData.getInstance(); } printSection("Scripts"); diff --git a/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java b/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java new file mode 100644 index 0000000000..e374cd78a5 --- /dev/null +++ b/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java @@ -0,0 +1,126 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.l2jmobius.gameserver.data.xml.impl; + +import java.io.File; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Logger; + +import org.w3c.dom.Document; + +import org.l2jmobius.Config; +import org.l2jmobius.commons.util.IXmlReader; +import org.l2jmobius.gameserver.model.StatsSet; + +/** + * @author Mobius + */ +public class NpcNameLocalisationData implements IXmlReader +{ + private final static Logger LOGGER = Logger.getLogger(NpcNameLocalisationData.class.getName()); + + private final static Map> NPC_NAME_LOCALISATIONS = new ConcurrentHashMap<>(); + private static String _lang; + + protected NpcNameLocalisationData() + { + load(); + } + + @Override + public void load() + { + NPC_NAME_LOCALISATIONS.clear(); + + if (Config.MULTILANG_ENABLE) + { + for (String lang : Config.MULTILANG_ALLOWED) + { + final File file = new File("data/lang/" + lang + "/NpcNameLocalisation.xml"); + if (!file.isFile()) + { + continue; + } + + NPC_NAME_LOCALISATIONS.put(lang, new ConcurrentHashMap()); + _lang = lang; + parseDatapackFile("data/lang/" + lang + "/NpcNameLocalisation.xml"); + final int count = NPC_NAME_LOCALISATIONS.get(lang).values().size(); + if (count == 0) + { + NPC_NAME_LOCALISATIONS.remove(lang); + } + else + { + LOGGER.info(getClass().getSimpleName() + ": Loaded localisations for '" + lang + "'"); + } + } + } + } + + @Override + public void parseDocument(Document doc, File f) + { + forEach(doc, "list", listNode -> forEach(listNode, "localisation", localisationNode -> + { + final StatsSet set = new StatsSet(parseAttributes(localisationNode)); + NPC_NAME_LOCALISATIONS.get(_lang).put(set.getInt("id"), new String[] + { + set.getString("name"), + set.getString("title") + }); + })); + } + + /** + * @param lang + * @param id + * @return a String Array[] that contains NPC name and title or Null if is does not exist. + */ + public String[] getLocalisation(String lang, int id) + { + final Map localisations = NPC_NAME_LOCALISATIONS.get(lang); + if (localisations != null) + { + return localisations.get(id); + } + return null; + } + + public boolean hasLocalisation(int id) + { + for (Map data : NPC_NAME_LOCALISATIONS.values()) + { + if (data.containsKey(id)) + { + return true; + } + } + return false; + } + + public static NpcNameLocalisationData getInstance() + { + return SingletonHolder.INSTANCE; + } + + private static class SingletonHolder + { + protected static final NpcNameLocalisationData INSTANCE = new NpcNameLocalisationData(); + } +} diff --git a/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java b/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java index 89a3c6e729..a3ed51b30f 100644 --- a/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java +++ b/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java @@ -68,6 +68,7 @@ import org.l2jmobius.gameserver.data.xml.impl.ClassListData; import org.l2jmobius.gameserver.data.xml.impl.ExperienceData; import org.l2jmobius.gameserver.data.xml.impl.HennaData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.PetDataTable; import org.l2jmobius.gameserver.data.xml.impl.PlayerTemplateData; import org.l2jmobius.gameserver.data.xml.impl.PlayerXpPercentLostData; @@ -11492,7 +11493,19 @@ public final class PlayerInstance extends Playable { sm = new SystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2); sm.addPcName(this); - sm.addString(target.getName()); + + // Localisation related. + String targetName = target.getName(); + if (Config.MULTILANG_ENABLE && target.isNpc()) + { + final String[] localisation = NpcNameLocalisationData.getInstance().getLocalisation(_lang, target.getId()); + if (localisation != null) + { + targetName = localisation[0]; + } + } + + sm.addString(targetName); sm.addInt(damage); sm.addPopup(target.getObjectId(), getObjectId(), -damage); } diff --git a/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java b/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java index 64d1bdbd1c..df33eb168e 100644 --- a/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java +++ b/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java @@ -18,6 +18,7 @@ package org.l2jmobius.gameserver.model.actor.status; import org.l2jmobius.Config; import org.l2jmobius.gameserver.ai.CtrlIntention; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.enums.PrivateStoreType; import org.l2jmobius.gameserver.instancemanager.DuelManager; import org.l2jmobius.gameserver.model.actor.Creature; @@ -253,7 +254,19 @@ public class PlayerStatus extends PlayableStatus // Send a System Message to the PlayerInstance SystemMessage smsg = new SystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2); smsg.addString(getActiveChar().getName()); - smsg.addString(attacker.getName()); + + // Localisation related. + String targetName = attacker.getName(); + if (Config.MULTILANG_ENABLE && attacker.isNpc()) + { + final String[] localisation = NpcNameLocalisationData.getInstance().getLocalisation(getActiveChar().getLang(), attacker.getId()); + if (localisation != null) + { + targetName = localisation[0]; + } + } + + smsg.addString(targetName); smsg.addInt(fullValue); smsg.addPopup(getActiveChar().getObjectId(), attacker.getObjectId(), -fullValue); getActiveChar().sendPacket(smsg); diff --git a/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/network/GameClient.java b/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/network/GameClient.java index 4ed506b02a..ed0f223551 100644 --- a/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/network/GameClient.java +++ b/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/network/GameClient.java @@ -49,6 +49,7 @@ import org.l2jmobius.gameserver.network.serverpackets.ActionFailed; import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; import org.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket; import org.l2jmobius.gameserver.network.serverpackets.LeaveWorld; +import org.l2jmobius.gameserver.network.serverpackets.NpcInfo; import org.l2jmobius.gameserver.network.serverpackets.NpcSay; import org.l2jmobius.gameserver.network.serverpackets.ServerClose; import org.l2jmobius.gameserver.network.serverpackets.SystemMessage; @@ -268,6 +269,10 @@ public final class GameClient extends ChannelInboundHandler { ((ExShowScreenMessage) packet).setLang(lang); } + else if (packet instanceof NpcInfo) + { + ((NpcInfo) packet).setLang(lang); + } } } diff --git a/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java b/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java index b9aed30eb3..eb77b0fd17 100644 --- a/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java +++ b/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java @@ -21,6 +21,8 @@ import java.util.Set; import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketWriter; import org.l2jmobius.gameserver.data.sql.impl.ClanTable; +import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.enums.NpcInfoType; import org.l2jmobius.gameserver.enums.Team; import org.l2jmobius.gameserver.model.actor.Npc; @@ -57,6 +59,40 @@ public class NpcInfo extends AbstractMaskPacket private int _statusMask = 0; private final Set _abnormalVisualEffects; + private String[] _localisation; + + public void setLang(String lang) + { + _localisation = NpcNameLocalisationData.getInstance().getLocalisation(lang, _npc.getId()); + if (_localisation != null) + { + if (!containsMask(NpcInfoType.NAME)) + { + addComponentType(NpcInfoType.NAME); + } + _blockSize -= _npc.getName().length() * 2; + _blockSize += _localisation[0].length() * 2; + + if (!_localisation[1].equals("")) + { + if (!containsMask(NpcInfoType.TITLE)) + { + addComponentType(NpcInfoType.TITLE); + } + final String title = _npc.getTitle(); + _initSize -= title.length() * 2; + if (title.equals("")) + { + _initSize += _localisation[1].length() * 2; + } + else + { + _initSize += title.replace(NpcData.getInstance().getTemplate(_npc.getId()).getTitle(), _localisation[1]).length() * 2; + } + } + } + } + public NpcInfo(Npc npc) { _npc = npc; @@ -283,7 +319,22 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.TITLE)) { - packet.writeS(_npc.getTitle()); + String title = _npc.getTitle(); + + // Localisation related. + if ((_localisation != null) && !_localisation[1].equals("")) + { + if (title.equals("")) + { + title = _localisation[1]; + } + else + { + title = title.replace(NpcData.getInstance().getTemplate(_npc.getId()).getTitle(), _localisation[1]); + } + } + + packet.writeS(title); } // Block 2 @@ -344,7 +395,7 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.FLYING)) { - packet.writeD(_npc.isFlying() ? 0x01 : 00); + packet.writeD(_npc.isFlying() ? 0x01 : 0x00); } if (containsMask(NpcInfoType.CLONE)) { @@ -389,7 +440,7 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.NAME)) { - packet.writeS(_npc.getName()); + packet.writeS(_localisation != null ? _localisation[0] : _npc.getName()); } if (containsMask(NpcInfoType.NAME_NPCSTRINGID)) { diff --git a/L2J_Mobius_Classic_2.3_SevenSigns/dist/game/data/lang/el/NpcNameLocalisation.xml b/L2J_Mobius_Classic_2.3_SevenSigns/dist/game/data/lang/el/NpcNameLocalisation.xml new file mode 100644 index 0000000000..e260fd7156 --- /dev/null +++ b/L2J_Mobius_Classic_2.3_SevenSigns/dist/game/data/lang/el/NpcNameLocalisation.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.3_SevenSigns/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java b/L2J_Mobius_Classic_2.3_SevenSigns/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java index 7bee2f3d02..3c26c6f57b 100644 --- a/L2J_Mobius_Classic_2.3_SevenSigns/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java +++ b/L2J_Mobius_Classic_2.3_SevenSigns/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java @@ -37,6 +37,7 @@ import org.l2jmobius.gameserver.data.xml.impl.FishingData; import org.l2jmobius.gameserver.data.xml.impl.ItemCrystallizationData; import org.l2jmobius.gameserver.data.xml.impl.MultisellData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.OptionData; import org.l2jmobius.gameserver.data.xml.impl.PrimeShopData; import org.l2jmobius.gameserver.data.xml.impl.SayuneData; @@ -333,6 +334,7 @@ public class AdminReload implements IAdminCommandHandler SystemMessageId.loadLocalisations(); NpcStringId.loadLocalisations(); SendMessageLocalisationData.getInstance().load(); + NpcNameLocalisationData.getInstance().load(); AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Localisation data."); break; } diff --git a/L2J_Mobius_Classic_2.3_SevenSigns/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java b/L2J_Mobius_Classic_2.3_SevenSigns/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java index 559eaaea12..26f24c4e52 100644 --- a/L2J_Mobius_Classic_2.3_SevenSigns/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java +++ b/L2J_Mobius_Classic_2.3_SevenSigns/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java @@ -19,9 +19,16 @@ package handlers.voicedcommandhandlers; import java.util.StringTokenizer; import org.l2jmobius.Config; +import org.l2jmobius.commons.concurrent.ThreadPool; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.handler.IVoicedCommandHandler; +import org.l2jmobius.gameserver.model.World; +import org.l2jmobius.gameserver.model.WorldObject; +import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; +import org.l2jmobius.gameserver.network.serverpackets.DeleteObject; import org.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage; +import org.l2jmobius.gameserver.network.serverpackets.NpcInfo; public class Lang implements IVoicedCommandHandler { @@ -61,6 +68,18 @@ public class Lang implements IVoicedCommandHandler { msg.setFile(activeChar, "data/html/mods/Lang/Ok.htm"); activeChar.sendPacket(msg); + for (WorldObject obj : World.getInstance().getVisibleObjects()) + { + if (obj.isNpc() && NpcNameLocalisationData.getInstance().hasLocalisation(obj.getId())) + { + activeChar.sendPacket(new DeleteObject(obj)); + ThreadPool.schedule(() -> + { + activeChar.sendPacket(new NpcInfo((Npc) obj)); + }, 1000); + } + } + activeChar.setTarget(null); return true; } msg.setFile(activeChar, "data/html/mods/Lang/Error.htm"); diff --git a/L2J_Mobius_Classic_2.3_SevenSigns/dist/game/data/xsd/NpcNameLocalisation.xsd b/L2J_Mobius_Classic_2.3_SevenSigns/dist/game/data/xsd/NpcNameLocalisation.xsd new file mode 100644 index 0000000000..b8b185243e --- /dev/null +++ b/L2J_Mobius_Classic_2.3_SevenSigns/dist/game/data/xsd/NpcNameLocalisation.xsd @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/GameServer.java index ccb8c7d068..b0ed8693fe 100644 --- a/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/GameServer.java +++ b/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/GameServer.java @@ -76,6 +76,7 @@ import org.l2jmobius.gameserver.data.xml.impl.KarmaData; import org.l2jmobius.gameserver.data.xml.impl.LuckyGameData; import org.l2jmobius.gameserver.data.xml.impl.MultisellData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.OptionData; import org.l2jmobius.gameserver.data.xml.impl.PetDataTable; import org.l2jmobius.gameserver.data.xml.impl.PetSkillData; @@ -345,6 +346,7 @@ public class GameServer if (Config.MULTILANG_ENABLE) { SendMessageLocalisationData.getInstance(); + NpcNameLocalisationData.getInstance(); } printSection("Scripts"); diff --git a/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java b/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java new file mode 100644 index 0000000000..e374cd78a5 --- /dev/null +++ b/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java @@ -0,0 +1,126 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.l2jmobius.gameserver.data.xml.impl; + +import java.io.File; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Logger; + +import org.w3c.dom.Document; + +import org.l2jmobius.Config; +import org.l2jmobius.commons.util.IXmlReader; +import org.l2jmobius.gameserver.model.StatsSet; + +/** + * @author Mobius + */ +public class NpcNameLocalisationData implements IXmlReader +{ + private final static Logger LOGGER = Logger.getLogger(NpcNameLocalisationData.class.getName()); + + private final static Map> NPC_NAME_LOCALISATIONS = new ConcurrentHashMap<>(); + private static String _lang; + + protected NpcNameLocalisationData() + { + load(); + } + + @Override + public void load() + { + NPC_NAME_LOCALISATIONS.clear(); + + if (Config.MULTILANG_ENABLE) + { + for (String lang : Config.MULTILANG_ALLOWED) + { + final File file = new File("data/lang/" + lang + "/NpcNameLocalisation.xml"); + if (!file.isFile()) + { + continue; + } + + NPC_NAME_LOCALISATIONS.put(lang, new ConcurrentHashMap()); + _lang = lang; + parseDatapackFile("data/lang/" + lang + "/NpcNameLocalisation.xml"); + final int count = NPC_NAME_LOCALISATIONS.get(lang).values().size(); + if (count == 0) + { + NPC_NAME_LOCALISATIONS.remove(lang); + } + else + { + LOGGER.info(getClass().getSimpleName() + ": Loaded localisations for '" + lang + "'"); + } + } + } + } + + @Override + public void parseDocument(Document doc, File f) + { + forEach(doc, "list", listNode -> forEach(listNode, "localisation", localisationNode -> + { + final StatsSet set = new StatsSet(parseAttributes(localisationNode)); + NPC_NAME_LOCALISATIONS.get(_lang).put(set.getInt("id"), new String[] + { + set.getString("name"), + set.getString("title") + }); + })); + } + + /** + * @param lang + * @param id + * @return a String Array[] that contains NPC name and title or Null if is does not exist. + */ + public String[] getLocalisation(String lang, int id) + { + final Map localisations = NPC_NAME_LOCALISATIONS.get(lang); + if (localisations != null) + { + return localisations.get(id); + } + return null; + } + + public boolean hasLocalisation(int id) + { + for (Map data : NPC_NAME_LOCALISATIONS.values()) + { + if (data.containsKey(id)) + { + return true; + } + } + return false; + } + + public static NpcNameLocalisationData getInstance() + { + return SingletonHolder.INSTANCE; + } + + private static class SingletonHolder + { + protected static final NpcNameLocalisationData INSTANCE = new NpcNameLocalisationData(); + } +} diff --git a/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java b/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java index f481a56160..8275a59c00 100644 --- a/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java +++ b/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java @@ -68,6 +68,7 @@ import org.l2jmobius.gameserver.data.xml.impl.ClassListData; import org.l2jmobius.gameserver.data.xml.impl.ExperienceData; import org.l2jmobius.gameserver.data.xml.impl.HennaData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.PetDataTable; import org.l2jmobius.gameserver.data.xml.impl.PlayerTemplateData; import org.l2jmobius.gameserver.data.xml.impl.PlayerXpPercentLostData; @@ -11498,7 +11499,19 @@ public final class PlayerInstance extends Playable { sm = new SystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2); sm.addPcName(this); - sm.addString(target.getName()); + + // Localisation related. + String targetName = target.getName(); + if (Config.MULTILANG_ENABLE && target.isNpc()) + { + final String[] localisation = NpcNameLocalisationData.getInstance().getLocalisation(_lang, target.getId()); + if (localisation != null) + { + targetName = localisation[0]; + } + } + + sm.addString(targetName); sm.addInt(damage); sm.addPopup(target.getObjectId(), getObjectId(), -damage); } diff --git a/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java b/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java index 64d1bdbd1c..df33eb168e 100644 --- a/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java +++ b/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java @@ -18,6 +18,7 @@ package org.l2jmobius.gameserver.model.actor.status; import org.l2jmobius.Config; import org.l2jmobius.gameserver.ai.CtrlIntention; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.enums.PrivateStoreType; import org.l2jmobius.gameserver.instancemanager.DuelManager; import org.l2jmobius.gameserver.model.actor.Creature; @@ -253,7 +254,19 @@ public class PlayerStatus extends PlayableStatus // Send a System Message to the PlayerInstance SystemMessage smsg = new SystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2); smsg.addString(getActiveChar().getName()); - smsg.addString(attacker.getName()); + + // Localisation related. + String targetName = attacker.getName(); + if (Config.MULTILANG_ENABLE && attacker.isNpc()) + { + final String[] localisation = NpcNameLocalisationData.getInstance().getLocalisation(getActiveChar().getLang(), attacker.getId()); + if (localisation != null) + { + targetName = localisation[0]; + } + } + + smsg.addString(targetName); smsg.addInt(fullValue); smsg.addPopup(getActiveChar().getObjectId(), attacker.getObjectId(), -fullValue); getActiveChar().sendPacket(smsg); diff --git a/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/network/GameClient.java b/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/network/GameClient.java index 4ed506b02a..ed0f223551 100644 --- a/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/network/GameClient.java +++ b/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/network/GameClient.java @@ -49,6 +49,7 @@ import org.l2jmobius.gameserver.network.serverpackets.ActionFailed; import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; import org.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket; import org.l2jmobius.gameserver.network.serverpackets.LeaveWorld; +import org.l2jmobius.gameserver.network.serverpackets.NpcInfo; import org.l2jmobius.gameserver.network.serverpackets.NpcSay; import org.l2jmobius.gameserver.network.serverpackets.ServerClose; import org.l2jmobius.gameserver.network.serverpackets.SystemMessage; @@ -268,6 +269,10 @@ public final class GameClient extends ChannelInboundHandler { ((ExShowScreenMessage) packet).setLang(lang); } + else if (packet instanceof NpcInfo) + { + ((NpcInfo) packet).setLang(lang); + } } } diff --git a/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java b/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java index b9aed30eb3..eb77b0fd17 100644 --- a/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java +++ b/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java @@ -21,6 +21,8 @@ import java.util.Set; import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketWriter; import org.l2jmobius.gameserver.data.sql.impl.ClanTable; +import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.enums.NpcInfoType; import org.l2jmobius.gameserver.enums.Team; import org.l2jmobius.gameserver.model.actor.Npc; @@ -57,6 +59,40 @@ public class NpcInfo extends AbstractMaskPacket private int _statusMask = 0; private final Set _abnormalVisualEffects; + private String[] _localisation; + + public void setLang(String lang) + { + _localisation = NpcNameLocalisationData.getInstance().getLocalisation(lang, _npc.getId()); + if (_localisation != null) + { + if (!containsMask(NpcInfoType.NAME)) + { + addComponentType(NpcInfoType.NAME); + } + _blockSize -= _npc.getName().length() * 2; + _blockSize += _localisation[0].length() * 2; + + if (!_localisation[1].equals("")) + { + if (!containsMask(NpcInfoType.TITLE)) + { + addComponentType(NpcInfoType.TITLE); + } + final String title = _npc.getTitle(); + _initSize -= title.length() * 2; + if (title.equals("")) + { + _initSize += _localisation[1].length() * 2; + } + else + { + _initSize += title.replace(NpcData.getInstance().getTemplate(_npc.getId()).getTitle(), _localisation[1]).length() * 2; + } + } + } + } + public NpcInfo(Npc npc) { _npc = npc; @@ -283,7 +319,22 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.TITLE)) { - packet.writeS(_npc.getTitle()); + String title = _npc.getTitle(); + + // Localisation related. + if ((_localisation != null) && !_localisation[1].equals("")) + { + if (title.equals("")) + { + title = _localisation[1]; + } + else + { + title = title.replace(NpcData.getInstance().getTemplate(_npc.getId()).getTitle(), _localisation[1]); + } + } + + packet.writeS(title); } // Block 2 @@ -344,7 +395,7 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.FLYING)) { - packet.writeD(_npc.isFlying() ? 0x01 : 00); + packet.writeD(_npc.isFlying() ? 0x01 : 0x00); } if (containsMask(NpcInfoType.CLONE)) { @@ -389,7 +440,7 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.NAME)) { - packet.writeS(_npc.getName()); + packet.writeS(_localisation != null ? _localisation[0] : _npc.getName()); } if (containsMask(NpcInfoType.NAME_NPCSTRINGID)) { diff --git a/L2J_Mobius_Classic_2.4_SecretOfEmpire/dist/game/data/lang/el/NpcNameLocalisation.xml b/L2J_Mobius_Classic_2.4_SecretOfEmpire/dist/game/data/lang/el/NpcNameLocalisation.xml new file mode 100644 index 0000000000..e260fd7156 --- /dev/null +++ b/L2J_Mobius_Classic_2.4_SecretOfEmpire/dist/game/data/lang/el/NpcNameLocalisation.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.4_SecretOfEmpire/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java b/L2J_Mobius_Classic_2.4_SecretOfEmpire/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java index 7bee2f3d02..3c26c6f57b 100644 --- a/L2J_Mobius_Classic_2.4_SecretOfEmpire/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java +++ b/L2J_Mobius_Classic_2.4_SecretOfEmpire/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java @@ -37,6 +37,7 @@ import org.l2jmobius.gameserver.data.xml.impl.FishingData; import org.l2jmobius.gameserver.data.xml.impl.ItemCrystallizationData; import org.l2jmobius.gameserver.data.xml.impl.MultisellData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.OptionData; import org.l2jmobius.gameserver.data.xml.impl.PrimeShopData; import org.l2jmobius.gameserver.data.xml.impl.SayuneData; @@ -333,6 +334,7 @@ public class AdminReload implements IAdminCommandHandler SystemMessageId.loadLocalisations(); NpcStringId.loadLocalisations(); SendMessageLocalisationData.getInstance().load(); + NpcNameLocalisationData.getInstance().load(); AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Localisation data."); break; } diff --git a/L2J_Mobius_Classic_2.4_SecretOfEmpire/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java b/L2J_Mobius_Classic_2.4_SecretOfEmpire/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java index 559eaaea12..26f24c4e52 100644 --- a/L2J_Mobius_Classic_2.4_SecretOfEmpire/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java +++ b/L2J_Mobius_Classic_2.4_SecretOfEmpire/dist/game/data/scripts/handlers/voicedcommandhandlers/Lang.java @@ -19,9 +19,16 @@ package handlers.voicedcommandhandlers; import java.util.StringTokenizer; import org.l2jmobius.Config; +import org.l2jmobius.commons.concurrent.ThreadPool; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.handler.IVoicedCommandHandler; +import org.l2jmobius.gameserver.model.World; +import org.l2jmobius.gameserver.model.WorldObject; +import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; +import org.l2jmobius.gameserver.network.serverpackets.DeleteObject; import org.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage; +import org.l2jmobius.gameserver.network.serverpackets.NpcInfo; public class Lang implements IVoicedCommandHandler { @@ -61,6 +68,18 @@ public class Lang implements IVoicedCommandHandler { msg.setFile(activeChar, "data/html/mods/Lang/Ok.htm"); activeChar.sendPacket(msg); + for (WorldObject obj : World.getInstance().getVisibleObjects()) + { + if (obj.isNpc() && NpcNameLocalisationData.getInstance().hasLocalisation(obj.getId())) + { + activeChar.sendPacket(new DeleteObject(obj)); + ThreadPool.schedule(() -> + { + activeChar.sendPacket(new NpcInfo((Npc) obj)); + }, 1000); + } + } + activeChar.setTarget(null); return true; } msg.setFile(activeChar, "data/html/mods/Lang/Error.htm"); diff --git a/L2J_Mobius_Classic_2.4_SecretOfEmpire/dist/game/data/xsd/NpcNameLocalisation.xsd b/L2J_Mobius_Classic_2.4_SecretOfEmpire/dist/game/data/xsd/NpcNameLocalisation.xsd new file mode 100644 index 0000000000..b8b185243e --- /dev/null +++ b/L2J_Mobius_Classic_2.4_SecretOfEmpire/dist/game/data/xsd/NpcNameLocalisation.xsd @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/GameServer.java index ee8bca4041..960a31fcb3 100644 --- a/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/GameServer.java +++ b/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/GameServer.java @@ -77,6 +77,7 @@ import org.l2jmobius.gameserver.data.xml.impl.KarmaData; import org.l2jmobius.gameserver.data.xml.impl.LuckyGameData; import org.l2jmobius.gameserver.data.xml.impl.MultisellData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.OptionData; import org.l2jmobius.gameserver.data.xml.impl.PetDataTable; import org.l2jmobius.gameserver.data.xml.impl.PetSkillData; @@ -347,6 +348,7 @@ public class GameServer if (Config.MULTILANG_ENABLE) { SendMessageLocalisationData.getInstance(); + NpcNameLocalisationData.getInstance(); } printSection("Scripts"); diff --git a/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java b/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java new file mode 100644 index 0000000000..e374cd78a5 --- /dev/null +++ b/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/data/xml/impl/NpcNameLocalisationData.java @@ -0,0 +1,126 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.l2jmobius.gameserver.data.xml.impl; + +import java.io.File; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Logger; + +import org.w3c.dom.Document; + +import org.l2jmobius.Config; +import org.l2jmobius.commons.util.IXmlReader; +import org.l2jmobius.gameserver.model.StatsSet; + +/** + * @author Mobius + */ +public class NpcNameLocalisationData implements IXmlReader +{ + private final static Logger LOGGER = Logger.getLogger(NpcNameLocalisationData.class.getName()); + + private final static Map> NPC_NAME_LOCALISATIONS = new ConcurrentHashMap<>(); + private static String _lang; + + protected NpcNameLocalisationData() + { + load(); + } + + @Override + public void load() + { + NPC_NAME_LOCALISATIONS.clear(); + + if (Config.MULTILANG_ENABLE) + { + for (String lang : Config.MULTILANG_ALLOWED) + { + final File file = new File("data/lang/" + lang + "/NpcNameLocalisation.xml"); + if (!file.isFile()) + { + continue; + } + + NPC_NAME_LOCALISATIONS.put(lang, new ConcurrentHashMap()); + _lang = lang; + parseDatapackFile("data/lang/" + lang + "/NpcNameLocalisation.xml"); + final int count = NPC_NAME_LOCALISATIONS.get(lang).values().size(); + if (count == 0) + { + NPC_NAME_LOCALISATIONS.remove(lang); + } + else + { + LOGGER.info(getClass().getSimpleName() + ": Loaded localisations for '" + lang + "'"); + } + } + } + } + + @Override + public void parseDocument(Document doc, File f) + { + forEach(doc, "list", listNode -> forEach(listNode, "localisation", localisationNode -> + { + final StatsSet set = new StatsSet(parseAttributes(localisationNode)); + NPC_NAME_LOCALISATIONS.get(_lang).put(set.getInt("id"), new String[] + { + set.getString("name"), + set.getString("title") + }); + })); + } + + /** + * @param lang + * @param id + * @return a String Array[] that contains NPC name and title or Null if is does not exist. + */ + public String[] getLocalisation(String lang, int id) + { + final Map localisations = NPC_NAME_LOCALISATIONS.get(lang); + if (localisations != null) + { + return localisations.get(id); + } + return null; + } + + public boolean hasLocalisation(int id) + { + for (Map data : NPC_NAME_LOCALISATIONS.values()) + { + if (data.containsKey(id)) + { + return true; + } + } + return false; + } + + public static NpcNameLocalisationData getInstance() + { + return SingletonHolder.INSTANCE; + } + + private static class SingletonHolder + { + protected static final NpcNameLocalisationData INSTANCE = new NpcNameLocalisationData(); + } +} diff --git a/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java b/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java index 09d06b698d..9372c85feb 100644 --- a/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java +++ b/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/model/actor/instance/PlayerInstance.java @@ -68,6 +68,7 @@ import org.l2jmobius.gameserver.data.xml.impl.ClassListData; import org.l2jmobius.gameserver.data.xml.impl.ExperienceData; import org.l2jmobius.gameserver.data.xml.impl.HennaData; import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.data.xml.impl.PetDataTable; import org.l2jmobius.gameserver.data.xml.impl.PlayerTemplateData; import org.l2jmobius.gameserver.data.xml.impl.PlayerXpPercentLostData; @@ -11498,7 +11499,19 @@ public final class PlayerInstance extends Playable { sm = new SystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2); sm.addPcName(this); - sm.addString(target.getName()); + + // Localisation related. + String targetName = target.getName(); + if (Config.MULTILANG_ENABLE && target.isNpc()) + { + final String[] localisation = NpcNameLocalisationData.getInstance().getLocalisation(_lang, target.getId()); + if (localisation != null) + { + targetName = localisation[0]; + } + } + + sm.addString(targetName); sm.addInt(damage); sm.addPopup(target.getObjectId(), getObjectId(), -damage); } diff --git a/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java b/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java index 64d1bdbd1c..df33eb168e 100644 --- a/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java +++ b/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/model/actor/status/PlayerStatus.java @@ -18,6 +18,7 @@ package org.l2jmobius.gameserver.model.actor.status; import org.l2jmobius.Config; import org.l2jmobius.gameserver.ai.CtrlIntention; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.enums.PrivateStoreType; import org.l2jmobius.gameserver.instancemanager.DuelManager; import org.l2jmobius.gameserver.model.actor.Creature; @@ -253,7 +254,19 @@ public class PlayerStatus extends PlayableStatus // Send a System Message to the PlayerInstance SystemMessage smsg = new SystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2); smsg.addString(getActiveChar().getName()); - smsg.addString(attacker.getName()); + + // Localisation related. + String targetName = attacker.getName(); + if (Config.MULTILANG_ENABLE && attacker.isNpc()) + { + final String[] localisation = NpcNameLocalisationData.getInstance().getLocalisation(getActiveChar().getLang(), attacker.getId()); + if (localisation != null) + { + targetName = localisation[0]; + } + } + + smsg.addString(targetName); smsg.addInt(fullValue); smsg.addPopup(getActiveChar().getObjectId(), attacker.getObjectId(), -fullValue); getActiveChar().sendPacket(smsg); diff --git a/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/network/GameClient.java b/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/network/GameClient.java index 4ed506b02a..ed0f223551 100644 --- a/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/network/GameClient.java +++ b/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/network/GameClient.java @@ -49,6 +49,7 @@ import org.l2jmobius.gameserver.network.serverpackets.ActionFailed; import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; import org.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket; import org.l2jmobius.gameserver.network.serverpackets.LeaveWorld; +import org.l2jmobius.gameserver.network.serverpackets.NpcInfo; import org.l2jmobius.gameserver.network.serverpackets.NpcSay; import org.l2jmobius.gameserver.network.serverpackets.ServerClose; import org.l2jmobius.gameserver.network.serverpackets.SystemMessage; @@ -268,6 +269,10 @@ public final class GameClient extends ChannelInboundHandler { ((ExShowScreenMessage) packet).setLang(lang); } + else if (packet instanceof NpcInfo) + { + ((NpcInfo) packet).setLang(lang); + } } } diff --git a/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java b/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java index b9aed30eb3..eb77b0fd17 100644 --- a/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java +++ b/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/network/serverpackets/NpcInfo.java @@ -21,6 +21,8 @@ import java.util.Set; import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketWriter; import org.l2jmobius.gameserver.data.sql.impl.ClanTable; +import org.l2jmobius.gameserver.data.xml.impl.NpcData; +import org.l2jmobius.gameserver.data.xml.impl.NpcNameLocalisationData; import org.l2jmobius.gameserver.enums.NpcInfoType; import org.l2jmobius.gameserver.enums.Team; import org.l2jmobius.gameserver.model.actor.Npc; @@ -57,6 +59,40 @@ public class NpcInfo extends AbstractMaskPacket private int _statusMask = 0; private final Set _abnormalVisualEffects; + private String[] _localisation; + + public void setLang(String lang) + { + _localisation = NpcNameLocalisationData.getInstance().getLocalisation(lang, _npc.getId()); + if (_localisation != null) + { + if (!containsMask(NpcInfoType.NAME)) + { + addComponentType(NpcInfoType.NAME); + } + _blockSize -= _npc.getName().length() * 2; + _blockSize += _localisation[0].length() * 2; + + if (!_localisation[1].equals("")) + { + if (!containsMask(NpcInfoType.TITLE)) + { + addComponentType(NpcInfoType.TITLE); + } + final String title = _npc.getTitle(); + _initSize -= title.length() * 2; + if (title.equals("")) + { + _initSize += _localisation[1].length() * 2; + } + else + { + _initSize += title.replace(NpcData.getInstance().getTemplate(_npc.getId()).getTitle(), _localisation[1]).length() * 2; + } + } + } + } + public NpcInfo(Npc npc) { _npc = npc; @@ -283,7 +319,22 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.TITLE)) { - packet.writeS(_npc.getTitle()); + String title = _npc.getTitle(); + + // Localisation related. + if ((_localisation != null) && !_localisation[1].equals("")) + { + if (title.equals("")) + { + title = _localisation[1]; + } + else + { + title = title.replace(NpcData.getInstance().getTemplate(_npc.getId()).getTitle(), _localisation[1]); + } + } + + packet.writeS(title); } // Block 2 @@ -344,7 +395,7 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.FLYING)) { - packet.writeD(_npc.isFlying() ? 0x01 : 00); + packet.writeD(_npc.isFlying() ? 0x01 : 0x00); } if (containsMask(NpcInfoType.CLONE)) { @@ -389,7 +440,7 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.NAME)) { - packet.writeS(_npc.getName()); + packet.writeS(_localisation != null ? _localisation[0] : _npc.getName()); } if (containsMask(NpcInfoType.NAME_NPCSTRINGID)) {