diff --git a/scripts/commands/eject.py b/scripts/commands/eject.py new file mode 100644 index 00000000..eafbd1f0 --- /dev/null +++ b/scripts/commands/eject.py @@ -0,0 +1,8 @@ +import sys + +def run(core, actor, target, commandString): + instSvc = core.instanceService + + if instSvc.isInInstance(actor): + instSvc.remove(instSvc.getActiveInstance(actor), actor) + diff --git a/scripts/instances/heroic_exar_kun.py b/scripts/instances/heroic_exar_kun.py new file mode 100644 index 00000000..d961fee0 --- /dev/null +++ b/scripts/instances/heroic_exar_kun.py @@ -0,0 +1,53 @@ +import sys +import services.InstanceService.Instance + +def getTerrain(): + return 'terrain/dungeon1.trn' + +def getBuilding(): + return 'object/building/heroic/shared_exar_kun_tomb.iff' + +def getCellId(): + return 1 + +def getSpawnPosition(position): + position.x = float(-11.918457) + position.y = float(0.601063) + position.z = float(-125.692871) + return + +def getDuration(): + return 120 + +# NK lockout time was 30 minutes. Most instances were 0 and got reset at 12AM PTC. +def getLockoutTime(): + return 0 + +def getExitTerrain(): + return 'terrain/yavin4.trn' + +def getExitPosition(position): + position.x = float(5097) + position.y = float(0) + position.z = float(5537) + return + +# Called on instance creation to spawn npcs and objects. +def setup(core, instance): + return + +# Called when there is a new participant added to the instance. +def add(core, instance, actor): + return + +# Called when a participant is removed from the instance. +def remove(core, instance, actor): + return + +# Any operations that need to be carried out regularly +def run(core, instance): + return + +# Called on instance destruction to destroy the instance. +def destroy(core, instance): + return \ No newline at end of file diff --git a/scripts/instances/heroic_star_destroyer.py b/scripts/instances/heroic_star_destroyer.py new file mode 100644 index 00000000..2109ea39 --- /dev/null +++ b/scripts/instances/heroic_star_destroyer.py @@ -0,0 +1,53 @@ +import sys +import services.InstanceService.Instance + +def getTerrain(): + return 'terrain/dungeon1.trn' + +def getBuilding(): + return 'object/building/general/shared_space_dungeon_star_destroyer.iff' + +def getCellId(): + return 36 + +def getSpawnPosition(position): + position.x = float(0) + position.y = float(173.834625) + position.z = float(30) + return + +def getDuration(): + return 120 + +# NK lockout time was 30 minutes. Most instances were 0 and got reset at 12AM PTC. +def getLockoutTime(): + return 0 + +def getExitTerrain(): + return 'terrain/corellia.trn' + +def getExitPosition(position): + position.x = float(-131) + position.y = float(0) + position.z = float(-4723) + return + +# Called on instance creation to spawn npcs and objects. +def setup(core, instance): + return + +# Called when there is a new participant added to the instance. +def add(core, instance, actor): + return + +# Called when a participant is removed from the instance. +def remove(core, instance, actor): + return + +# Any operations that need to be carried out regularly +def run(core, instance): + return + +# Called on instance destruction to destroy the instance. +def destroy(core, instance): + return \ No newline at end of file diff --git a/scripts/object/tangible/quest/heroic/heroic_exar_kun_entrance.py b/scripts/object/tangible/quest/heroic/heroic_exar_kun_entrance.py index ccad8904..79b40d1f 100644 --- a/scripts/object/tangible/quest/heroic/heroic_exar_kun_entrance.py +++ b/scripts/object/tangible/quest/heroic/heroic_exar_kun_entrance.py @@ -1,4 +1,9 @@ import sys def setup(core, object): - return \ No newline at end of file + object.setAttachment('radial_filename', 'exar_kun_brazier') + return + +def use(core, actor, object): + if actor: + core.instanceService.queue('heroic_exar_kun', actor) \ No newline at end of file diff --git a/scripts/radial/exar_kun_brazier.py b/scripts/radial/exar_kun_brazier.py new file mode 100644 index 00000000..d78e1915 --- /dev/null +++ b/scripts/radial/exar_kun_brazier.py @@ -0,0 +1,14 @@ +from resources.common import RadialOptions +import sys + +def createRadial(core, owner, target, radials): + radials.add(RadialOptions(0, 21, 1, '')) + radials.add(RadialOptions(0, 7, 1, '')) + radials.add(RadialOptions(0, 21, 3, '@building_name:heroic_exar_enter')) + return + +def handleSelection(core, owner, target, option): + if option == 21 and target: + core.objectService.useObject(owner, target) + return + \ No newline at end of file diff --git a/src/main/NGECore.java b/src/main/NGECore.java index 2d491e9d..dbb6cf0a 100644 --- a/src/main/NGECore.java +++ b/src/main/NGECore.java @@ -55,6 +55,7 @@ import services.ConnectionService; import services.EntertainmentService; import services.EquipmentService; import services.GroupService; +import services.InstanceService; import services.LoginService; import services.MissionService; import services.PlayerService; @@ -163,6 +164,7 @@ public class NGECore { public SpawnService spawnService; public AIService aiService; //public MissionService missionService; + public InstanceService instanceService; // Login Server public NetworkDispatch loginDispatch; @@ -391,6 +393,9 @@ public class NGECore { zoneDispatch.addService(skillService); + instanceService = new InstanceService(this); + zoneDispatch.addService(instanceService); + //travelService.startShuttleSchedule(); weatherService = new WeatherService(this); diff --git a/src/resources/objects/guild/GuildObject.java b/src/resources/objects/guild/GuildObject.java index a1fe7edb..5890756b 100644 --- a/src/resources/objects/guild/GuildObject.java +++ b/src/resources/objects/guild/GuildObject.java @@ -46,12 +46,11 @@ import com.sleepycat.persist.model.NotPersistent; import engine.clients.Client; import engine.resources.objects.IPersistent; -import engine.resources.objects.SWGObject; import engine.resources.scene.Planet; import engine.resources.scene.Point3D; import engine.resources.scene.Quaternion; -@Entity(version=0) +@Entity(version=1) public class GuildObject extends UniverseObject implements IPersistent { protected NGECore core; @@ -63,6 +62,8 @@ public class GuildObject extends UniverseObject implements IPersistent { @NotPersistent private Transaction txn; + private long nextInstanceId = 0; + // GILD 3 private float complexity = 0x803F0F00; private String STFFile = "string_id_table"; @@ -281,6 +282,12 @@ public class GuildObject extends UniverseObject implements IPersistent { } } + public synchronized long getNextInstanceId() { + long ret = nextInstanceId; + nextInstanceId++; + return ret; + } + @Override public void sendBaselines(Client destination) { destination.getSession().write(messageBuilder.buildBaseline3()); diff --git a/src/services/ConnectionService.java b/src/services/ConnectionService.java index 1d18bf53..c0d5405e 100644 --- a/src/services/ConnectionService.java +++ b/src/services/ConnectionService.java @@ -203,6 +203,10 @@ public class ConnectionService implements INetworkDispatch { } } + if (core.instanceService.isInInstance(object)) { + core.instanceService.remove(core.instanceService.getActiveInstance(object), object); + } + object.setClient(null); PlayerObject ghost = (PlayerObject) object.getSlottedObject("ghost"); @@ -210,8 +214,6 @@ public class ConnectionService implements INetworkDispatch { if(ghost == null) return; - if () - Point3D objectPos = object.getWorldPosition(); List collidables = core.simulationService.getCollidables(object.getPlanet(), objectPos.x, objectPos.z, 512); diff --git a/src/services/InstanceService.java b/src/services/InstanceService.java new file mode 100644 index 00000000..8747fd2f --- /dev/null +++ b/src/services/InstanceService.java @@ -0,0 +1,778 @@ +/******************************************************************************* + * Copyright (c) 2013 + * + * This File is part of NGECore2. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Using NGEngine to work with NGECore2 is making a combined work based on NGEngine. + * Therefore all terms and conditions of the GNU Lesser General Public License cover the combination. + ******************************************************************************/ +package services; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import resources.objects.building.BuildingObject; +import resources.objects.creature.CreatureObject; +import resources.objects.group.GroupObject; + +import main.NGECore; + +import engine.clientdata.ClientFileManager; +import engine.clientdata.visitors.DatatableVisitor; +import engine.resources.common.CRC; +import engine.resources.objects.SWGObject; +import engine.resources.scene.Planet; +import engine.resources.scene.Point3D; +import engine.resources.service.INetworkDispatch; +import engine.resources.service.INetworkRemoteEvent; + +public class InstanceService implements INetworkDispatch { + + private NGECore core; + + private Map> instanceMap = new HashMap>(); + + private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); + + public class Instance { + + private long instanceId = 0; + private String name = ""; + private long startTime = System.currentTimeMillis(); + private Point3D instancePosition; + private Point3D spawnPosition; + private int duration = 0; + private int lockoutTime = 0; + private CreatureObject owner; + private List participants = new ArrayList(); + private List activeParticipants = new ArrayList(); + protected final Object objectMutex = new Object(); + private ScheduledFuture task; + private boolean faulty = false; + private boolean closed = false; + + public Instance(long instanceId, String name, Point3D instancePosition, Point3D spawnPosition, int duration, int lockoutTime, CreatureObject owner) { + this.instanceId = instanceId; + this.name = name; + this.instancePosition = instancePosition; + this.spawnPosition = spawnPosition; + this.duration = (duration * 1000); + this.lockoutTime = lockoutTime; + this.owner = owner; + participants.add(owner); + } + + public Instance() { + + } + + public long getInstanceId() { + synchronized(objectMutex) { + return instanceId; + } + } + + public String getName() { + synchronized(objectMutex) { + return name; + } + } + + public long getStartTime() { + synchronized(objectMutex) { + return startTime; + } + } + + public long getTimeRemaining() { + synchronized(objectMutex) { + return ((closed) ? 0 : (((long) duration) - (System.currentTimeMillis() - startTime))); + } + } + + public boolean isOpen() { + synchronized(objectMutex) { + if (closed || getTimeRemaining() <= 0) { + return false; + } + + return true; + } + } + + public Point3D getInstancePosition() { + synchronized(objectMutex) { + return instancePosition; + } + } + + public Point3D getSpawnPosition() { + synchronized(objectMutex) { + return spawnPosition; + } + } + + public int getDuration() { + synchronized(objectMutex) { + return duration; + } + } + + public int getLockoutTime() { + synchronized(objectMutex) { + return lockoutTime; + } + } + + public CreatureObject getOwner() { + synchronized(objectMutex) { + return owner; + } + } + + public List getParticipants() { + return participants; + } + + public List getActiveParticipants() { + return participants; + } + + public boolean addParticipant(CreatureObject participant) { + synchronized(objectMutex) { + if (activeParticipants.contains(participant)) { + return true; + } + + if (activeParticipants.size() >= 8) { + return false; + } + + activeParticipants.add(participant); + participants.add(participant); + + return true; + } + } + + public boolean isActiveParticipant(CreatureObject participant) { + synchronized(objectMutex) { + return activeParticipants.contains(participant); + } + } + + public boolean isFormerParticipant(CreatureObject participant) { + synchronized(objectMutex) { + return participants.contains(participant); + } + } + + public boolean removeParticipant(CreatureObject participant) { + synchronized(objectMutex) { + return activeParticipants.remove(participant); + } + } + + public ScheduledFuture getTask() { + synchronized(objectMutex) { + return task; + } + } + + public void setTask(ScheduledFuture task) { + synchronized(objectMutex) { + this.task = task; + } + } + + public boolean isFaulty() { + synchronized(objectMutex) { + return faulty; + } + } + + public void setFaulty(boolean faulty) { + synchronized(objectMutex) { + this.faulty = faulty; + } + } + + public boolean isClosed() { + synchronized(objectMutex) { + return closed; + } + } + + public void close() { + synchronized(objectMutex) { + closed = true; + } + } + + } + + public InstanceService(NGECore core) { + this.core = core; + } + + /* + * @author Treeku + * + * @description Create a brand new instance. + * + * @param instanceName Buildout name of the instance to build. + * @param owner Creator's creature object. + */ + public synchronized Instance create(String instanceName, CreatureObject owner) { + Instance instance = null; + + try { + String planetName = core.scriptService.callScript("scripts/instances/", instanceName, "getTerrain").asString(); + Planet planet = core.terrainService.getPlanetByPath(planetName); + Point3D spawnPosition = new Point3D(); + int duration = (core.scriptService.callScript("scripts/instances/", instanceName, "getDuration").asInt() * 60); + int lockoutTime = core.scriptService.callScript("scripts/instances/", instanceName, "getLockoutTime").asInt();; + + core.scriptService.callScript("scripts/instances/", instanceName, "getSpawnPosition", spawnPosition); + + DatatableVisitor buildoutTable = ClientFileManager.loadFile("datatables/buildout/areas_" + planet.getName() + ".iff", DatatableVisitor.class); + + for (int i = 0; i < buildoutTable.getRowCount(); i++) { + if (((String) buildoutTable.getObject(i, 0)).equals(instanceName)) { + Point3D instancePosition = new Point3D((Float) buildoutTable.getObject(i, 1), 0, (Float) buildoutTable.getObject(i, 2)); + + if (!instanceInUse(instanceName, instancePosition)) { + instance = new Instance(core.guildService.getGuildObject().getNextInstanceId(), instanceName, instancePosition, spawnPosition, duration, lockoutTime, owner); + } + } + } + + if (instance == null) { + return null; + } + + core.scriptService.callScript("scripts/instances/", instanceName, "setup", core, instance); + + final Instance reference = instance; + + instance.setTask(scheduler.scheduleAtFixedRate(new Runnable() { + + private final Instance instance = reference; + private boolean sentCloseWarning = false; + + public void run() { + if (instance.getDuration() > 300 && instance.getTimeRemaining() <= 300 && !sentCloseWarning) { + for (CreatureObject player : instance.getActiveParticipants()) { + player.sendSystemMessage("@instance:five_minute_warning", (byte) 0); + } + + sentCloseWarning = true; + } + + if (!instance.isOpen()) { + for (CreatureObject player : instance.getActiveParticipants()) { + player.sendSystemMessage("@instance:instance_time_out", (byte) 0); + } + + close(instance); + } + + core.scriptService.callScript("scripts/instances/", instance.getName(), "run", core, instance); + } + + }, 1, 1, TimeUnit.MINUTES)); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + + if (!instanceMap.containsKey(instance.getName())) { + instanceMap.put(instance.getName(), new ArrayList()); + } + + instanceMap.get(instance.getName()).add(instance); + + return instance; + } + + + /* + * @author Treeku + * + * @description Queue them for an instance for 19 seconds, remove if none available. + * + * @param instanceName Name of the instance .py script. + * @param creature Player's creature object to queue for the instance. + * + * @return None. + */ + public void queue(String instanceName, CreatureObject creature) { + Instance instance = null; + + if (creature.getBuffByName("instance_launching") != null) { + creature.sendSystemMessage("@instance:instance_request_pending", (byte) 0); + return; + } + + core.buffService.addBuffToCreature(creature, "instance_launching"); + + if (isLockedOut(instanceName, creature)) { + creature.sendSystemMessage("@instance:lockout_notification", (byte) 0); + core.buffService.removeBuffFromCreature(creature, creature.getBuffByName("instance_launching")); + return; + } + + instance = getActiveInstance(instanceName, creature); + + if (creature.getGroupId() > 0) { + if (instance == null) { + GroupObject group = (GroupObject) core.objectService.getObject(creature.getGroupId()); + + if (group != null) { + for (SWGObject member : group.getMemberList()) { + instance = getActiveInstance(instanceName, (CreatureObject) member); + + if (instance != null) { + break; + } + } + } + } else { + GroupObject group = (GroupObject) core.objectService.getObject(creature.getGroupId()); + + if (group != null) { + for (SWGObject member : group.getMemberList()) { + Instance instance2 = getActiveInstance(instanceName, (CreatureObject) member); + + if (!instance2.equals(instance)) { + creature.sendSystemMessage("@instance:fail_invalid_lockout", (byte) 0); + core.buffService.removeBuffFromCreature(creature, creature.getBuffByName("instance_launching")); + return; + } + } + } + } + } + + if (instance == null) { + instance = create(instanceName, creature); + + if (instance == null) { + creature.sendSystemMessage("@instance:all_full", (byte) 0); + core.buffService.removeBuffFromCreature(creature, creature.getBuffByName("instance_launching")); + return; + } + } + + if (instance.getActiveParticipants().size() >= 8) { + creature.sendSystemMessage("@instance:fail_instance_full", (byte) 0); + core.buffService.removeBuffFromCreature(creature, creature.getBuffByName("instance_launching")); + return; + } + + if (instance != null) { + add(instance, creature); + } + + core.buffService.removeBuffFromCreature(creature, creature.getBuffByName("instance_launching")); + } + + /* + * @author Treeku + * + * @description Adds a player to an instance. Can be used directly to avoid queue. + * + * @param instance Instance object. + * @param creature Player's creature object to add to the instance. + * + * @return None. + */ + public synchronized void add(Instance instance, CreatureObject creature) { + try { + String terrain = core.scriptService.callScript("scripts/instances/", instance.getName(), "getTerrain").asString(); + Planet planet = core.terrainService.getPlanetByPath(terrain); + int cellId = core.scriptService.callScript("scripts/instances/", instance.getName(), "getCellId").asInt(); + + if (cellId == -1) { + Point3D position = new Point3D(); + position.x = instance.getInstancePosition().x + instance.getSpawnPosition().x; + position.y = instance.getInstancePosition().y + instance.getSpawnPosition().y; + position.z = instance.getInstancePosition().z + instance.getSpawnPosition().z; + + core.simulationService.transferToPlanet(creature, planet, position, creature.getOrientation(), null); + } else { + String buildingName = core.scriptService.callScript("scripts/instances/", instance.getName(), "getBuilding").asString(); + BuildingObject building = null; + + Point3D buildingPosition = instance.getInstancePosition().clone(); + + DatatableVisitor buildoutTable = ClientFileManager.loadFile("datatables/buildout/" + planet.getName() + "/" + instance.getName() + ".iff", DatatableVisitor.class); + + for (int i = 0; i < buildoutTable.getRowCount(); i++) { + if (((Integer) buildoutTable.getObject(i, 3)) == CRC.StringtoCRC(buildingName)) { + buildingPosition.x += ((Float) buildoutTable.getObject(i, 5)); + buildingPosition.y += ((Float) buildoutTable.getObject(i, 6)); + buildingPosition.z += ((Float) buildoutTable.getObject(i, 7)); + } + } + + for (SWGObject object : core.objectService.getObjectList().values()) { + if (object instanceof BuildingObject && + object.getTemplate().equals(buildingName) && + object.getPosition().x == buildingPosition.x && + object.getPosition().y == buildingPosition.y && + object.getPosition().z == buildingPosition.z) { + building = (BuildingObject) object; + break; + } + } + + if (building == null) { + throw new Exception(); + } + + core.simulationService.transferToPlanet(creature, planet, instance.getSpawnPosition(), creature.getOrientation(), building.getCellByCellNumber(cellId)); + } + + instance.addParticipant(creature); + + core.scriptService.callScript("scripts/instances/", instance.getName(), "add", core, instance, creature); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /* + * @author Treeku + * + * @description Removes a player from an instance. Can be used directly. + * + * @param instance Instance object. + * @param creature Player's creature object to add to the instance. + * + * @return None. + */ + public void remove(Instance instance, CreatureObject creature) { + try { + if (creature.getBuffByName("instance_exiting") != null) { + creature.sendSystemMessage("@instance:instance_request_pending", (byte) 0); + return; + } + + core.buffService.addBuffToCreature(creature, "instance_exiting"); + + String exitTerrain = core.scriptService.callScript("scripts/instances/", instance.getName(), "getExitTerrain").asString(); + Point3D exitPosition = new Point3D(); + Planet exitPlanet = core.terrainService.getPlanetByPath(exitTerrain); + + core.scriptService.callScript("scripts/instances/", instance.getName(), "getExitPosition", exitPosition); + + core.scriptService.callScript("scripts/instances/", instance.getName(), "remove", core, instance, creature); + + instance.removeParticipant(creature); + + core.simulationService.transferToPlanet(creature, exitPlanet, exitPosition, creature.getOrientation(), null); + } catch (Exception e) { + e.printStackTrace(); + } + + core.buffService.removeBuffFromCreature(creature, creature.getBuffByName("instance_exiting")); + } + + /* + * @author Treeku + * + * @description Closes an instance. + * + * @param instance Instance object. + * + * @return None. + */ + public synchronized void close(Instance instance) { + try { + if (instance.isClosed()) { + return; + } + + String exitTerrain = core.scriptService.callScript("scripts/instances/", instance.getName(), "getExitTerrain").asString(); + Point3D exitPosition = new Point3D(); + Planet exitPlanet = core.terrainService.getPlanetByPath(exitTerrain); + + core.scriptService.callScript("scripts/instances/", instance.getName(), "getExitPosition", exitPosition); + + for (CreatureObject participant : instance.getActiveParticipants()) { + instance.removeParticipant(participant); + core.simulationService.transferToPlanet(participant, exitPlanet, exitPosition, participant.getOrientation(), null); + } + + if (!instance.getTask().isCancelled()) { + instance.getTask().cancel(true); + } + + core.scriptService.callScript("scripts/instances/", instance.getName(), "destroy", core, instance); + + instance.close(); + } catch (Exception e) { + e.printStackTrace(); + instance.setFaulty(true); + } + } + + /* + * @author Treeku + * + * @description Checks if an instance area is in use. + * + * @param instanceName Buildout name of the instance. + * @param instancePosition Position of the instance in the game world. + * + * @return True if instance is in use. + */ + public boolean instanceInUse(String instanceName, Point3D instancePosition) { + if (instanceMap.containsKey(instanceName)) { + for (Instance instance : instanceMap.get(instanceName)) { + if (instance.isFaulty() || (instance.isOpen() && + instance.getInstancePosition().x == instancePosition.x && + instance.getInstancePosition().z == instancePosition.z)) { + return true; + } + } + } + + return false; + } + + /* + * @author Treeku + * + * @description Gets an instance object from an instanceId. + * + * @param instanceId Id of an instance you want an object for. + * + * @return Instance object, or null if none found. + */ + public Instance getInstance(long instanceId) { + for (List instanceList : instanceMap.values()) { + for (Instance instance : instanceList) { + if (instance.getInstanceId() == instanceId) { + return instance; + } + } + } + + return null; + } + + /* + * @author Treeku + * + * @description Checks if player is in an instance. + * + * @param creature Player's creature object. + * + * @return True if player is in an instance. + */ + public boolean isInInstance(CreatureObject creature) { + for (List instanceList : instanceMap.values()) { + for (Instance instance : instanceList) { + if (instance.isActiveParticipant(creature)) { + return true; + } + } + } + + return false; + } + + /* + * @author Treeku + * + * @description Checks if player is in a specific instance. + * + * @param instanceName Buildout name of the instance. + * @param creature Player's creature object. + * + * @return True if player is in the specified instance. + */ + public boolean isInInstance(String instanceName, CreatureObject creature) { + if (instanceMap.containsKey(instanceName)) { + for (Instance instance : instanceMap.get(instanceName)) { + if (instance.isActiveParticipant(creature)) { + return true; + } + } + } + + return false; + } + + /* + * @author Treeku + * + * @description Checks if player is in a specific instance. + * + * @param instance Instance object. + * @param creature Player's creature object. + * + * @return True if player is in the specified instance. + */ + public boolean isInInstance(Instance instance, CreatureObject creature) { + return instance.getActiveParticipants().contains(creature); + } + + /* + * @author Treeku + * + * @description Finds the instance object a player is currently in. + * + * @param creature Player's creature object. + * + * @return Instance object of the player, or null if they aren't in one. + */ + public Instance getActiveInstance(CreatureObject creature) { + for (List instanceList : instanceMap.values()) { + for (Instance instance : instanceList) { + if (instance.isActiveParticipant(creature)) { + return instance; + } + } + } + + return null; + } + + /* + * @author Treeku + * + * @description Finds the instance object of an instance a player is/has been in. + * + * @param instanceName Buildout name of the instance. + * @param creature Player's creature object. + * + * @return Instance object of the specified instance the specified player has entered since reset, or null if not found. + */ + public Instance getActiveInstance(String instanceName, CreatureObject creature) { + if (instanceMap.containsKey(instanceName)) { + for (Instance instance : instanceMap.get(instanceName)) { + if (instance.isFormerParticipant(creature) && instance.getTimeRemaining() > 0) { + return instance; + } + } + } + + return null; + } + + /* + * @author Treeku + * + * @description Checks if player has any instance lockouts. + * + * @param creature Player's creature object. + * + * @return True if player is locked out from any instances. + */ + public boolean hasInstanceLockout(CreatureObject creature) { + for (List instanceList : instanceMap.values()) { + for (Instance instance : instanceList) { + if (instance.isFormerParticipant(creature)) { + return true; + } + } + } + + return false; + } + + /* + * @author Treeku + * + * @description Finds the instance object of an instance a player is/has been in. + * + * @param instanceName Buildout name of the instance. + * @param creature Player's creature object. + * + * @return Instance object of the specified instance the specified player has entered since reset, or null if not found. + */ + public List getLockoutList(CreatureObject creature) { + List lockoutList = new ArrayList(); + + for (List instanceList : instanceMap.values()) { + for (Instance instance : instanceList) { + if (instance.isFormerParticipant(creature)) { + lockoutList.add(instance); + } + } + } + + return lockoutList; + } + + /* + * @author Treeku + * + * @description Checks if player is locked out of an instance. + * + * @param instanceName Buildout name of the instance. + * @param creature Player's creature object. + * + * @return True if player is locked out from the specified instance. + */ + public boolean isLockedOut(String instanceName, CreatureObject creature) { + if (instanceMap.containsKey(instanceName)) { + for (Instance instance : instanceMap.get(instanceName)) { + if (instance.isFormerParticipant(creature) && instance.getTimeRemaining() <= 0) { + return true; + } + } + } + + return false; + } + + /* + * @author Treeku + * + * @description Shows the instance UI. + * + * @param creature Player's creature object. + * + * @return None. + */ + public void showInstances(CreatureObject creature) { + // Stub for the /showi UI + } + + @Override + public void insertOpcodes(Map swgOpcodes, + Map objControllerOpcodes) { + // TODO Auto-generated method stub + + } + + @Override + public void shutdown() { + // TODO Auto-generated method stub + + } + +} diff --git a/src/services/SimulationService.java b/src/services/SimulationService.java index a71cb9c3..5c9c06b7 100644 --- a/src/services/SimulationService.java +++ b/src/services/SimulationService.java @@ -162,6 +162,7 @@ public class SimulationService implements INetworkDispatch { core.commandService.registerCommand("editbiography"); core.commandService.registerCommand("setbiography"); core.commandService.registerCommand("requestbiography"); + core.commandService.registerCommand("eject"); }