Система рифтов в Подземный Каталам Сопоставимые версии v4.8+ ЯДРО Добавляем в автозагрузку GameServer сервис Код: KatalamUnderRiftService.getInstance().spawn(); Сам сервис Код: /* * M.O.G. Devs Team * www.mmorpg-onlinegames.ru * Teg's {/aiononline, /eveonline} * * F5 Katalam Under rift Service */ package com.mog.gameserver.services.upheaval.f5Event; import java.util.Map.Entry; import java.util.concurrent.Future; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.mog.gameserver.model.gameobjects.VisibleObject; import com.mog.gameserver.model.gameobjects.player.Player; import com.mog.gameserver.model.rift.RiftList; import com.mog.gameserver.network.aion.AionServerPacket; import com.mog.gameserver.network.aion.serverpackets.SM_RIFT_ANNOUNCE; import com.mog.gameserver.spawnengine.SpawnEngine; import com.mog.gameserver.utils.PacketSendUtility; import com.mog.gameserver.utils.ThreadPoolManager; import com.mog.gameserver.world.World; import com.mog.gameserver.world.WorldMapInstance; import com.mog.gameserver.world.knownlist.Visitor; import javolution.util.FastMap; /** * @author Dision */ public class KatalamUnderRiftService { private static final Logger log = LoggerFactory.getLogger(KatalamUnderRiftService.class); private FastMap<Integer, Future<?>> tasks = FastMap.newInstance(); private FastMap<Integer, VisibleObject> objects = new FastMap<>(); private FastMap<Integer, RiftList> rifts = new FastMap<>(); private int RIFT_SPAWN_DELAY = 5; // 5 min. private int RIFT_RESPAWN_DELAY = 3600; // 1 hour private int RIFT_LIFETIME = 1800; // 30 min. private int key = 0; public void spawn() { tasks.put(key++, ThreadPoolManager.getInstance().scheduleAtFixedRate(new Runnable() { @Override public void run() { spawnRift(210070000, 731631, 777.01f, 1479.86f, 457.37f, (byte) 34); spawnRift(220080000, 731632, 233.35f, 1136.98f, 225.87f, (byte) 115); } }, RIFT_SPAWN_DELAY * 60000, RIFT_RESPAWN_DELAY * 1000)); } public FastMap<Integer, VisibleObject> getObjects() { return objects; } public FastMap<Integer, RiftList> getRifts() { return rifts; } public void loadRiftList(boolean isActive) { if (rifts != null) { for (Entry<Integer, RiftList> entry : rifts.entrySet()) { globalRiftPacket(entry.getValue(), isActive); } } } private void spawnRift(int worldId, int npcId, float x, float y, float z, byte h) { objects.put(npcId, SpawnEngine.spawnObject(SpawnEngine.addNewSingleTimeSpawn(worldId, npcId, x, y, z, h), 1)); rifts.put(objects.get(npcId).getObjectId(), new RiftList(objects.get(npcId).getObjectId(), worldId, x, y, z)); loadRiftList(true); sendAnnounce(objects.get(npcId)); scheduleDelete(npcId); log.info("KatalamUnderRiftService: spawnRift [npcId = " + npcId + "]"); } public void globalRiftPacket(final RiftList riftList, final boolean isActive) { World.getInstance().getWorldMap(riftList.getWorldId()).getMainWorldMapInstance().doOnAllPlayers(new Visitor<Player>() { @Override public void visit(Player player) { if (isActive) { PacketSendUtility.sendPacket(player, riftPacketInfo(riftList.getObjectId(), riftList.getX(), riftList.getY(), riftList.getZ(), true)); log.info("KatalamUnderRiftService: globalRiftPacket add [Id = " + riftList.getObjectId() + "] [x = " + riftList.getX() + "] [y = " + riftList.getY() + "] [z = " + riftList.getZ() + "]"); } else { PacketSendUtility.sendPacket(player, riftPacketInfoRemove(riftList.getObjectId())); log.info("KatalamUnderRiftService: globalRiftPacket remove [Id = " + riftList.getObjectId() + "]"); } } }); } private AionServerPacket riftPacketInfo(int objectId, float x, float y, float z, boolean isMaster) { return new SM_RIFT_ANNOUNCE(objectId, x, y, z, isMaster); } private AionServerPacket riftPacketInfoRemove(int objectId) { return new SM_RIFT_ANNOUNCE(4, objectId); } private void scheduleDelete(int npcId) { tasks.put(npcId, ThreadPoolManager.getInstance().schedule(new Runnable() { @Override public void run() { if (objects.containsKey(npcId)) { // Rift remove if (rifts.containsKey(objects.get(npcId).getObjectId())) { globalRiftPacket(rifts.get(objects.get(npcId).getObjectId()), false); rifts.remove(objects.get(npcId).getObjectId()); } objects.get(npcId).getController().onDelete(); objects.remove(npcId); } // Task remove if (tasks != null && tasks.containsKey(npcId)) { tasks.get(npcId).cancel(true); tasks.remove(npcId); } log.info("KatalamUnderRiftService: scheduleDelete [npcId = " + npcId + "]"); } }, RIFT_LIFETIME * 1000)); } public void sendAnnounce(VisibleObject object) { if (object.isSpawned()) { WorldMapInstance instance = object.getPosition().getMapRegion().getParent(); instance.doOnAllPlayers(new Visitor<Player>() { @Override public void visit(Player player) { if (player.isSpawned()) { PacketSendUtility.sendMessage(player, "Появился тоннель ведущий в Подземный Каталам."); } } }); } } public static KatalamUnderRiftService getInstance() { return KatalamUnderRiftService.SingletonHolder.instance; } private static class SingletonHolder { protected static final KatalamUnderRiftService instance = new KatalamUnderRiftService(); } } Код: /* * M.O.G. Devs Team * www.mmorpg-onlinegames.ru * Teg's {/aiononline, /eveonline} */ package com.mog.gameserver.model.rift; /** * @author Dision */ public class RiftList { private int objectId = 0; private int worldId = 0; private float x = 0; private float y = 0; private float z = 0; public RiftList(int objectId, int worldId, float x, float y, float z) { this.objectId = objectId; this.worldId = worldId; this.x = x; this.y = y; this.z = z; } public int getObjectId() { return objectId; } public void setObjectId(int objectId) { this.objectId = objectId; } public int getWorldId() { return worldId; } public void setWorldId(int worldId) { this.worldId = worldId; } public float getX() { return x; } public void setX(float x) { this.x = x; } public float getY() { return y; } public void setY(float y) { this.y = y; } public float getZ() { return z; } public void setZ(float z) { this.z = z; } } Код: /* * SM_RIFT_ANNOUNCE */ package com.mog.gameserver.network.aion.serverpackets; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.mog.gameserver.controllers.RVController; import com.mog.gameserver.network.aion.AionConnection; import com.mog.gameserver.network.aion.AionServerPacket; import javolution.util.FastMap; /** * @author Sweetkr, Dision */ public class SM_RIFT_ANNOUNCE extends AionServerPacket { private static final Logger log = LoggerFactory.getLogger(SM_RIFT_ANNOUNCE.class); private int actionId; private RVController rift; private FastMap<Integer, Integer> rifts; private int objectId; private float x, y, z; private boolean type; public SM_RIFT_ANNOUNCE(FastMap<Integer, Integer> rifts) { this.actionId = 0; this.rifts = rifts; } public SM_RIFT_ANNOUNCE(RVController rift, boolean isMaster) { this.rift = rift; this.actionId = isMaster ? 2 : 3; this.type = true; } public SM_RIFT_ANNOUNCE(int actionId) { this.actionId = actionId; } public SM_RIFT_ANNOUNCE(int actionId, int objectId) { this.actionId = actionId; this.objectId = objectId; } public SM_RIFT_ANNOUNCE(int objectId, float x, float y, float z, boolean isMaster) { this.objectId = objectId; this.x = x; this.y = y; this.z = z; this.actionId = isMaster ? 2 : 3; this.type = false; } /** * {@inheritDoc} */ @Override protected void writeImpl(AionConnection con) { switch (actionId) { case 0: // announce writeH(0x39); // 5.6 writeC(actionId); for (int value : rifts.values()) { writeD(value); } break; case 1: writeH(0x09); // 0x09 writeC(actionId); writeD(0x01); writeD(0x01); break; case 2: if (type) { writeH(0x23); // 0x23 writeC(actionId); writeD(rift.getOwner().getObjectId()); writeD(rift.getMaxEntries()); writeD(rift.getRemainTime()); writeD(rift.getMinLevel()); writeD(rift.getMaxLevel()); writeF(rift.getOwner().getX()); writeF(rift.getOwner().getY()); writeF(rift.getOwner().getZ()); writeC(rift.isVortex() ? 1 : 0); // red | blue writeC(rift.isMaster() ? 1 : 0); // display | hide } else { writeH(0x23); // 0x23 writeC(actionId); writeD(objectId); writeD(100); writeD(((int) (System.currentTimeMillis() / 1000) + 3600) - (int) (System.currentTimeMillis() / 1000)); writeD(65); writeD(75); writeF(x); writeF(y); writeF(z); writeC(1); // red | blue writeC(1); // display | hide } break; case 3: if (type) { writeH(0x0f); // 0x0f writeC(actionId); writeD(rift.getOwner().getObjectId()); writeD(rift.getUsedEntries()); writeD(rift.getRemainTime()); writeC(rift.isVortex() ? 1 : 0); writeC(0); // unk } else { writeH(0x0f); // 0x0f writeC(actionId); writeD(objectId); writeD(100); writeD(((int) (System.currentTimeMillis() / 1000) + 3600) - (int) (System.currentTimeMillis() / 1000)); writeC(1); writeC(0); // unk } break; case 4: writeH(0x05); writeC(actionId); writeD(objectId); break; case 5: writeH(0x05); writeC(actionId); writeC(0x00); writeC(0x00); writeC(0x00); writeC(0x00); break; } log.info("writeImpl RiftAnnounce packet count: 0x" + actionId); } } Аи для сервиса Код: /* * Direct portal katalam under */ package com.mog.gameserver.ai2.handlers.worlds.upheaval.f5Event; import com.mog.gameserver.ai2.AIName; import com.mog.gameserver.ai2.handlers.general.ActionItemNpcAI2; import com.mog.gameserver.dataholders.DataManager; import com.mog.gameserver.model.gameobjects.Creature; import com.mog.gameserver.model.gameobjects.player.Player; import com.mog.gameserver.model.gameobjects.player.RequestResponseHandler; import com.mog.gameserver.model.templates.portal.PortalPath; import com.mog.gameserver.model.templates.portal.PortalUse; import com.mog.gameserver.network.aion.serverpackets.SM_QUESTION_WINDOW; import com.mog.gameserver.services.teleport.PortalService; import com.mog.gameserver.utils.PacketSendUtility; /** * M.O.G. Devs Team * @author Dision */ @AIName("directportal_katalam_under") public class DirectPortalKatalamUnderAI2 extends ActionItemNpcAI2 { protected PortalUse portalUse; @Override protected void handleSpawned() { super.handleSpawned(); portalUse = DataManager.PORTAL2_DATA.getPortalUse(getNpcId()); } @Override protected void handleUseItemFinish(Player player) { RequestResponseHandler responseHandler = new RequestResponseHandler(getOwner()) { @Override public void acceptRequest(Creature requester, Player responder) { if (portalUse != null) { PortalPath portalPath = portalUse.getPortalPath(player.getRace()); if (portalPath != null) { PortalService.port(portalPath, player, getObjectId()); } } } @Override public void denyRequest(Creature requester, Player responder) { } @Override public void enterInstanceRequest(Creature requester, Player responder) { } }; boolean requested = player.getResponseRequester().putRequest(SM_QUESTION_WINDOW.STR_ASK_PASS_BY_DIRECT_PORTAL, responseHandler); if (requested) { PacketSendUtility.sendPacket(player, new SM_QUESTION_WINDOW(SM_QUESTION_WINDOW.STR_ASK_PASS_BY_DIRECT_PORTAL, 0, 0)); } } } ДАТА Добавляем в статик дату портал C:\Server_AioN\AioN_5.8_MASTER_TEST\Game\data\static_data\npcs\npc_templates HTML: <npc_template npc_id="731631" level="65" name="Тоннель в подземный Каталам" name_id="466433" desc="ldf5_under_l_entrance_in01" rank="VETERAN" rating="NORMAL" race="ELYOS" height="2.0" tribe="FIELD_OBJECT_LIGHT" type="GENERAL" ai="directportal_katalam_under" adelay="2000" hpgauge="3"> <stats maxHp="200000" maxXp="5000" main_hand_attack="1500" main_hand_accuracy="1500" pdef="4000" mresist="1500" power="1500" evasion="1500" accuracy="1500"/> <bound_radius front="0.5" side="0.7" upper="2.0"/> <talk_info distance="5" delay="3"/> </npc_template> <npc_template npc_id="731632" level="65" name="Тоннель в подземный Каталам" name_id="466434" desc="ldf5_under_d_entrance_in01" rank="VETERAN" rating="NORMAL" race="ASMODIANS" height="2.0" tribe="FIELD_OBJECT_DARK" type="GENERAL" ai="directportal_katalam_under" adelay="2000" hpgauge="3"> <stats maxHp="200000" maxXp="5000" main_hand_attack="1500" main_hand_accuracy="1500" pdef="4000" mresist="1500" power="1500" evasion="1500" accuracy="1500"/> <bound_radius front="0.5" side="0.7" upper="2.0"/> <talk_info distance="5" delay="3"/> </npc_template> C:\Server_AioN\AioN_5.8_MASTER_TEST\Game\data\static_data\portals HTML: portal_loc <!-- Подземный каталам --> <portal_loc world_id="210090000" loc_id="2100900" x="688.61" y="709.18" z="514.87" h="119"/> <!-- Вход L --> <portal_loc world_id="220100000" loc_id="2201000" x="688.61" y="709.18" z="514.87" h="119"/> <!-- Вход D --> <portal_loc world_id="210090000" loc_id="2100901" x="292.50" y="688.08" z="562.41" h="59"/> <!-- 1-й гарнизон Раты L --> <portal_loc world_id="220100000" loc_id="2201001" x="292.50" y="688.08" z="562.41" h="59"/> <!-- 1-й гарнизон Раты D --> <portal_loc world_id="110010000" loc_id="1100108" x="1317.04" y="1512.10" z="568.10" h="119"/> <!-- Выход L --> <portal_loc world_id="120010000" loc_id="1200110" x="1681.02" y="1400.54" z="195.37" h="59"/> <!-- Выход D --> portal_template2 <!-- 4.8 Подземный Каталам (Вход) L --> <portal_use npc_id="731631"> <portal_path loc_id="2100900"> <portal_req min_level="10"/> </portal_path> </portal_use> <!-- 4.8 Подземный Каталам (Вход) D --> <portal_use npc_id="731632"> <portal_path loc_id="2201000"> <portal_req min_level="10"/> </portal_path> </portal_use> <!-- 4.8 Подземный Каталам (Выход) L --> <portal_use npc_id="731633"> <portal_path loc_id="1100108"> <portal_req min_level="10"/> </portal_path> </portal_use> <!-- 4.8 Подземный Каталам (Выход) D --> <portal_use npc_id="731634"> <portal_path loc_id="1200110"> <portal_req min_level="10"/> </portal_path> </portal_use> <!-- 4.8 1-й гарнизон Раты L --> <portal_use npc_id="731635"> <portal_path loc_id="2100901"> <portal_req min_level="10"/> </portal_path> </portal_use> <!-- 4.8 1-й гарнизон Раты D --> <portal_use npc_id="731636"> <portal_path loc_id="2201001"> <portal_req min_level="10"/> </portal_path> </portal_use>