diff --git a/src/network/packets/swg/zone/PlanetTravelPointListResponse.java b/src/network/packets/swg/zone/PlanetTravelPointListResponse.java index 2bcf5857a..3d74ee2a7 100644 --- a/src/network/packets/swg/zone/PlanetTravelPointListResponse.java +++ b/src/network/packets/swg/zone/PlanetTravelPointListResponse.java @@ -98,7 +98,7 @@ public class PlanetTravelPointListResponse extends SWGPacket { List pointNames = data.getList(StringType.ASCII); List points = data.getList(Point3D.class); int[] additionalCosts = data.getIntArray(); - boolean[] pointsReachable = data.getBooleanArray(); + data.getBooleanArray(); // reachable for (int additionalCost : additionalCosts) { this.additionalCosts.add(additionalCost * 2); @@ -107,9 +107,8 @@ public class PlanetTravelPointListResponse extends SWGPacket { for (int i = 0; i < pointNames.size(); i++) { String pointName = pointNames.get(i); Point3D point = points.get(i); - boolean reachable = pointsReachable[i]; - travelPoints.add(new TravelPoint(pointName, new Location(point.getX(), point.getY(), point.getZ(), Terrain.getTerrainFromName(planetName)), isStarport(pointName), reachable)); + travelPoints.add(new TravelPoint(pointName, new Location(point.getX(), point.getY(), point.getZ(), Terrain.getTerrainFromName(planetName)), null, isStarport(pointName))); } } diff --git a/src/resources/objects/SWGObject.java b/src/resources/objects/SWGObject.java index 7fbdd6b4f..cd22a8b33 100644 --- a/src/resources/objects/SWGObject.java +++ b/src/resources/objects/SWGObject.java @@ -133,6 +133,7 @@ public abstract class SWGObject extends BaselineObject implements Comparable> routeCosts; diff --git a/src/services/galaxy/travel/TravelPoint.java b/src/services/galaxy/travel/TravelPoint.java index c4e82a7be..419a74d3a 100644 --- a/src/services/galaxy/travel/TravelPoint.java +++ b/src/services/galaxy/travel/TravelPoint.java @@ -41,16 +41,17 @@ public final class TravelPoint implements Comparable { private final Location location; private final boolean reachable; private final boolean starport; - private TravelGroup group; + private final TravelGroup group; + private CreatureObject shuttle; private SWGObject collector; - public TravelPoint(String name, Location location, boolean starport, boolean reachable) { + public TravelPoint(String name, Location location, TravelGroup group, boolean starport) { this.name = name; this.location = location; - this.reachable = reachable; // Not sure which effect this has on the client. + this.reachable = true; // Not sure which effect this has on the client. this.starport = starport; - this.group = null; + this.group = group; } public String getName() { @@ -97,10 +98,6 @@ public final class TravelPoint implements Comparable { this.collector = collector; } - public void setGroup(TravelGroup group) { - this.group = group; - } - public String getSuiFormat() { return String.format("@planet_n:%s -- %s", location.getTerrain().getName(), name); } diff --git a/src/services/galaxy/travel/TravelService.java b/src/services/galaxy/travel/TravelService.java index 954bb04e5..8d87e956b 100644 --- a/src/services/galaxy/travel/TravelService.java +++ b/src/services/galaxy/travel/TravelService.java @@ -27,15 +27,12 @@ t* Copyright (c) 2015 /// Project SWG /// www.projectswg.com ***********************************************************************************/ package services.galaxy.travel; -import java.io.File; -import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import com.projectswg.common.control.Service; -import com.projectswg.common.data.location.Location; import com.projectswg.common.data.location.Terrain; import com.projectswg.common.debug.Log; @@ -60,8 +57,6 @@ import resources.objects.staticobject.StaticObject; import resources.objects.tangible.OptionFlag; import resources.player.Player; import resources.server_info.DataManager; -import resources.server_info.SdbLoader; -import resources.server_info.SdbLoader.SdbResultSet; import resources.sui.SuiButtons; import resources.sui.SuiListBox; import resources.sui.SuiMessageBox; @@ -75,8 +70,6 @@ public class TravelService extends Service { this.travel = new TravelHelper(); this.ticketPriceFactor = DataManager.getConfig(ConfigFile.FEATURES).getDouble("TICKET-PRICE-FACTOR", 1); - loadTravelPoints(); - registerForIntent(TravelPointSelectionIntent.class, tpsi -> handlePointSelection(tpsi)); registerForIntent(GalacticPacketIntent.class, gpi -> handleTravelPointRequest(gpi)); registerForIntent(TicketPurchaseIntent.class, tpi -> handleTicketPurchase(tpi)); @@ -96,56 +89,6 @@ public class TravelService extends Service { return super.stop(); } - /** - * Travel points are loaded from serverdata/static/travel.sdb - * A travel point represents a travel destination. - * - * @return true if all points were loaded succesfully and false if not. - */ - private void loadTravelPoints() { - SdbLoader loader = new SdbLoader(); - try (SdbResultSet set = loader.load(new File("serverdata/travel/travel.sdb"))) { - while (set.next()) { - loadTravelPoint(set); - } - } catch (IOException e) { - Log.e("Failed to load a travel point"); - Log.e(e); - } - } - - private void loadTravelPoint(SdbResultSet set) { - String pointName = set.getText("name"); - double x = set.getReal("x"); - double z = set.getReal("z"); - String type = set.getText("type"); - Terrain travelPlanet = Terrain.getTerrainFromName(set.getText("planet")); - if (travelPlanet == null) { - Log.e("Invalid planet in travel.sdb: %s", set.getText("planet")); - return; - } - - TravelPoint point = new TravelPoint(pointName, new Location(x, 0, z, travelPlanet), type.endsWith("starport"), true); - TravelGroup group; - switch (type) { - case "shuttleport": - group = travel.getTravelGroup(SpecificObject.SO_TRANSPORT_SHUTTLE.getTemplate()); - break; - case "starport": - group = travel.getTravelGroup(SpecificObject.SO_TRANSPORT_STARPORT.getTemplate()); - break; - case "theed_starport": - group = travel.getTravelGroup(SpecificObject.SO_TRANSPORT_STARPORT_THEED.getTemplate()); - break; - default: - Log.w("Invalid travel point type: %s", type); - return; - } - group.addTravelPoint(point); - point.setGroup(group); - travel.addTravelPoint(point); - } - private List getAdditionalCosts(Terrain objectTerrain, Collection points) { List additionalCosts = new ArrayList<>(); @@ -213,7 +156,9 @@ public class TravelService extends Service { return; } - travel.grantTickets(purchaser, nearestPoint, destinationPoint, roundTrip); + travel.grantTicket(nearestPoint, destinationPoint, purchaser); + if (roundTrip) + travel.grantTicket(destinationPoint, nearestPoint, purchaser); showMessageBox(purchaserOwner, "ticket_purchase_complete"); } @@ -278,8 +223,10 @@ public class TravelService extends Service { totalPrice += travel.getTravelFee(departurePlanet, arrivalPlanet); // The base price totalPrice += getAdditionalCost(departurePlanet, arrivalPlanet); // The extra amount to pay. - if (roundTrip) - totalPrice += travel.getTravelFee(arrivalPlanet, departurePlanet); + if (roundTrip) { + totalPrice += travel.getTravelFee(arrivalPlanet, departurePlanet); // The base price + totalPrice += getAdditionalCost(arrivalPlanet, departurePlanet); // The extra amount to pay. + } return totalPrice; } diff --git a/src/services/objects/ObjectAwareness.java b/src/services/objects/ObjectAwareness.java index 758ce73e0..e0177dce7 100644 --- a/src/services/objects/ObjectAwareness.java +++ b/src/services/objects/ObjectAwareness.java @@ -156,8 +156,8 @@ public class ObjectAwareness extends Service implements TerrainMapCallback { private void handleDestroyObjectIntent(DestroyObjectIntent doi) { SWGObject obj = doi.getObject(); disappearObject(obj, true, true); - obj.setPosition(Terrain.GONE, 0, 0, 0); obj.moveToContainer(null); + obj.setPosition(Terrain.GONE, 0, 0, 0); } private void processObjectTeleportIntent(ObjectTeleportIntent oti) { diff --git a/test/resources/objects/TestSWGObject.java b/test/resources/objects/TestSWGObject.java index 0e044cd84..4c780b4fd 100644 --- a/test/resources/objects/TestSWGObject.java +++ b/test/resources/objects/TestSWGObject.java @@ -34,6 +34,7 @@ import org.junit.runners.JUnit4; import com.projectswg.common.data.location.Location; import com.projectswg.common.data.location.Terrain; +import com.projectswg.common.debug.Assert.AssertionException; import test_resources.GenericCreatureObject; @@ -53,11 +54,59 @@ public class TestSWGObject { Assert.assertEquals(worldLocation, parent.getWorldLocation()); Assert.assertEquals(worldLocation, parent.getLocation()); Assert.assertEquals(worldLocation, child.getWorldLocation()); - Assert.assertEquals(new Location(0, 0, 0, null), child.getLocation()); + Assert.assertEquals(new Location(0, 0, 0, Terrain.NABOO), child.getLocation()); child.setPosition(5, 5, 5); Assert.assertEquals(new Location(20, 22, 24, Terrain.NABOO), child.getWorldLocation()); - Assert.assertEquals(new Location(5, 5, 5, null), child.getLocation()); + Assert.assertEquals(new Location(5, 5, 5, Terrain.NABOO), child.getLocation()); + } + + @Test + public void testChildTerrainUpdates() { + SWGObject parent = new GenericCreatureObject(1); + SWGObject child = new GenericCreatureObject(2); + parent.setTerrain(Terrain.ADVENTURE1); + + Assert.assertEquals(Terrain.ADVENTURE1, parent.getTerrain()); + Assert.assertEquals(null, child.getTerrain()); + + child.moveToContainer(parent); + Assert.assertEquals(Terrain.ADVENTURE1, parent.getTerrain()); + Assert.assertEquals(Terrain.ADVENTURE1, child.getTerrain()); + + parent.setTerrain(Terrain.TATOOINE); + Assert.assertEquals(Terrain.TATOOINE, parent.getTerrain()); + Assert.assertEquals(Terrain.TATOOINE, child.getTerrain()); + } + + @Test(expected=AssertionException.class) + public void testChildTerrainInvalidParent1() { + SWGObject parent = new GenericCreatureObject(1); + SWGObject child = new GenericCreatureObject(2); + parent.setTerrain(Terrain.ADVENTURE1); + child.moveToContainer(parent); + + child.setTerrain(Terrain.TATOOINE); + } + + @Test(expected=AssertionException.class) + public void testChildTerrainInvalidParent2() { + SWGObject parent = new GenericCreatureObject(1); + SWGObject child = new GenericCreatureObject(2); + parent.setTerrain(Terrain.ADVENTURE1); + child.moveToContainer(parent); + + child.setPosition(Terrain.CORELLIA, 0, 0, 0); + } + + @Test(expected=AssertionException.class) + public void testChildTerrainInvalidParent3() { + SWGObject parent = new GenericCreatureObject(1); + SWGObject child = new GenericCreatureObject(2); + parent.setTerrain(Terrain.ADVENTURE1); + child.moveToContainer(parent); + + child.setLocation(new Location(0, 0, 0, Terrain.NABOO)); } } diff --git a/test/services/galaxy/travel/TestTravelHelper.java b/test/services/galaxy/travel/TestTravelHelper.java index 7851ba915..07b9c3db1 100644 --- a/test/services/galaxy/travel/TestTravelHelper.java +++ b/test/services/galaxy/travel/TestTravelHelper.java @@ -27,6 +27,8 @@ ***********************************************************************************/ package services.galaxy.travel; +import java.util.List; + import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; @@ -35,6 +37,7 @@ import org.junit.runners.JUnit4; import com.projectswg.common.data.location.Location; import com.projectswg.common.data.location.Terrain; +import resources.objects.SWGObject; import resources.objects.SpecificObject; import test_resources.GenericCreatureObject; @@ -65,14 +68,17 @@ public class TestTravelHelper { Assert.assertEquals(2000, helper.getTravelFee(Terrain.CORELLIA, Terrain.DATHOMIR)); Assert.assertEquals(4000, helper.getTravelFee(Terrain.NABOO, Terrain.ENDOR)); Assert.assertEquals(500, helper.getTravelFee(Terrain.TATOOINE, Terrain.NABOO)); + Assert.assertFalse(helper.isValidRoute(Terrain.TATOOINE, Terrain.YAVIN4)); + Assert.assertTrue(helper.isValidRoute(Terrain.TATOOINE, Terrain.LOK)); + Assert.assertTrue(helper.isValidRoute(Terrain.TATOOINE, Terrain.NABOO)); } @Test public void testNearestTravelPoint() { TravelHelper helper = new TravelHelper(); - TravelPoint starport = new TravelPoint("starport", new Location(50, 0, 50, Terrain.TATOOINE), true, true); - TravelPoint shuttleport = new TravelPoint("shuttleport", new Location(-50, 0, -50, Terrain.TATOOINE), false, true); - TravelPoint outOfRange = new TravelPoint("outOfRange", new Location(1000, 0, 1000, Terrain.TATOOINE), true, true); + TravelPoint starport = new TravelPoint("starport", new Location(50, 0, 50, Terrain.TATOOINE), null, true); + TravelPoint shuttleport = new TravelPoint("shuttleport", new Location(-50, 0, -50, Terrain.TATOOINE), null, false); + TravelPoint outOfRange = new TravelPoint("outOfRange", new Location(1000, 0, 1000, Terrain.TATOOINE), null, true); helper.addTravelPoint(starport); helper.addTravelPoint(shuttleport); helper.addTravelPoint(outOfRange); @@ -89,4 +95,47 @@ public class TestTravelHelper { Assert.assertEquals(shuttleport, helper.getNearestTravelPoint(creature)); } + @Test + public void testNoInvalidRoutesTatooine() { + TravelHelper helper = new TravelHelper(); + GenericCreatureObject creature = new GenericCreatureObject(1); + creature.setPosition(Terrain.TATOOINE, 3500, 5, -4800); + List destinations = helper.getAvailableTravelPoints(creature, Terrain.YAVIN4); + Assert.assertEquals(0, destinations.size()); + destinations = helper.getAvailableTravelPoints(creature, Terrain.LOK); + Assert.assertEquals(1, destinations.size()); + Assert.assertEquals("Nym's Stronghold" , destinations.get(0).getName()); + } + + @Test + public void testNoInvalidRoutesCorellia() { + TravelHelper helper = new TravelHelper(); + GenericCreatureObject creature = new GenericCreatureObject(1); + creature.setPosition(Terrain.CORELLIA, -75, 0, -4723); + List destinations = helper.getAvailableTravelPoints(creature, Terrain.YAVIN4); + Assert.assertEquals(3, destinations.size()); + Assert.assertEquals("Imperial Base", destinations.get(0).getName()); + Assert.assertEquals("Labor Outpost", destinations.get(1).getName()); + Assert.assertEquals("Mining Outpost", destinations.get(2).getName()); + destinations = helper.getAvailableTravelPoints(creature, Terrain.LOK); + Assert.assertEquals(0, destinations.size()); + } + + @Test + public void testValidTicketCreated() { + TravelHelper helper = new TravelHelper(); + GenericCreatureObject creature = new GenericCreatureObject(1); + creature.setupAsCharacter(); + creature.setPosition(Terrain.YAVIN4, 4054, 0, -6216); + TravelPoint imperialBase = helper.getDestinationPoint(Terrain.YAVIN4, "Imperial Base"); + TravelPoint coronet = helper.getDestinationPoint(Terrain.CORELLIA, "Coronet Starport"); + helper.grantTicket(imperialBase, coronet, creature); + Assert.assertEquals(imperialBase, helper.getNearestTravelPoint(creature)); + Assert.assertEquals(1, creature.getSlottedObject("inventory").getContainedObjects().size()); + System.out.println(creature.getSlottedObject("inventory").getContainedObjects()); + List tickets = helper.getTickets(creature); + Assert.assertEquals(1, tickets.size()); + + } + } diff --git a/test/test_resources/GenericCreatureObject.java b/test/test_resources/GenericCreatureObject.java index 20109851b..a1fd8e33e 100644 --- a/test/test_resources/GenericCreatureObject.java +++ b/test/test_resources/GenericCreatureObject.java @@ -27,11 +27,27 @@ ***********************************************************************************/ package test_resources; +import java.util.Map.Entry; + +import com.projectswg.common.data.swgfile.ClientFactory; +import com.projectswg.common.data.swgfile.visitors.ObjectData; +import com.projectswg.common.data.swgfile.visitors.ObjectData.ObjectDataAttribute; +import com.projectswg.common.data.swgfile.visitors.SlotArrangementData; +import com.projectswg.common.data.swgfile.visitors.SlotDescriptorData; +import com.projectswg.common.debug.Assert; + +import intents.object.ObjectCreatedIntent; import network.packets.Packet; +import resources.Race; +import resources.containers.ContainerPermissionsType; +import resources.objects.GameObjectType; +import resources.objects.SWGObject; import resources.objects.creature.CreatureObject; import resources.objects.player.PlayerObject; +import resources.objects.tangible.TangibleObject; import resources.player.Player; import resources.player.PlayerState; +import services.objects.ObjectCreator; public class GenericCreatureObject extends CreatureObject { @@ -47,7 +63,7 @@ public class GenericCreatureObject extends CreatureObject { }; player.setPlayerState(PlayerState.ZONED_IN); setHasOwner(true); - setSlot("ghost", new PlayerObject(-objectId)); + setSlot("ghost", new PlayerObject(-getObjectId())); } public void setHasOwner(boolean hasOwner) { @@ -58,4 +74,77 @@ public class GenericCreatureObject extends CreatureObject { } } + public void setupAsCharacter() { + handlePostCreation(); + createInventoryObject("object/tangible/inventory/shared_character_inventory.iff"); + createInventoryObject("object/tangible/datapad/shared_character_datapad.iff"); + createInventoryObject("object/tangible/inventory/shared_appearance_inventory.iff"); + createInventoryObject("object/tangible/bank/shared_character_bank.iff"); + createInventoryObject("object/tangible/mission_bag/shared_mission_bag.iff"); + } + + private TangibleObject createTangible(ContainerPermissionsType type, String template) { + SWGObject obj = ObjectCreator.createObjectFromTemplate(template); + Assert.test(obj instanceof TangibleObject); + obj.setContainerPermissions(type); + obj.moveToContainer(this); + new ObjectCreatedIntent(obj).broadcast(); + return (TangibleObject) obj; + } + + /** Creates an object with inventory-level world visibility (only the owner) */ + private TangibleObject createInventoryObject(String template) { + return createTangible(ContainerPermissionsType.INVENTORY, template); + } + + private void handlePostCreation() { + ObjectData attributes = (ObjectData) ClientFactory.getInfoFromFile(Race.HUMAN_MALE.getFilename(), true); + addObjectAttributes(attributes); + createObjectSlots(); + Object got = getDataAttribute(ObjectDataAttribute.GAME_OBJECT_TYPE); + if (got != null) + setGameObjectType(GameObjectType.getTypeFromId((Integer) got)); + } + + private void addObjectAttributes(ObjectData attributes) { + if (attributes == null) + return; + + for (Entry e : attributes.getAttributes().entrySet()) { + setObjectAttribute(e.getKey(), e.getValue()); + } + } + + private void setObjectAttribute(ObjectDataAttribute key, Object value) { + setDataAttribute(key, value); + switch (key) { + case OBJECT_NAME: setStringId(value.toString()); break; + case DETAILED_DESCRIPTION: setDetailStringId(value.toString()); break; + case CONTAINER_TYPE: setContainerType((Integer) value); break; + default: break; + } + } + + private void createObjectSlots() { + if (getDataAttribute(ObjectDataAttribute.SLOT_DESCRIPTOR_FILENAME) != null) { + // These are the slots that the object *HAS* + SlotDescriptorData descriptor = (SlotDescriptorData) ClientFactory.getInfoFromFile((String) getDataAttribute(ObjectDataAttribute.SLOT_DESCRIPTOR_FILENAME), true); + if (descriptor == null) + return; + + for (String slotName : descriptor.getSlots()) { + setSlot(slotName, null); + } + } + + if (getDataAttribute(ObjectDataAttribute.ARRANGEMENT_DESCRIPTOR_FILENAME) != null) { + // This is what slots the created object is able to go into/use + SlotArrangementData arrangementData = (SlotArrangementData) ClientFactory.getInfoFromFile((String) getDataAttribute(ObjectDataAttribute.ARRANGEMENT_DESCRIPTOR_FILENAME), true); + if (arrangementData == null) + return; + + setArrangement(arrangementData.getArrangement()); + } + } + }