diff --git a/serverdata/vehicles/vehicles.sdb b/serverdata/vehicles/vehicles.sdb index 8d335049..0046da3f 100644 --- a/serverdata/vehicles/vehicles.sdb +++ b/serverdata/vehicles/vehicles.sdb @@ -58,4 +58,4 @@ walker_at_xt object/intangible/vehicle/walker_at_xt_pcd.iff object/mobile/vehicl x31 object/intangible/vehicle/landspeeder_x31_pcd.iff object/mobile/vehicle/landspeeder_x31.iff object/tangible/tcg/series7/garage_display_vehicles/landspeeder_x31.iff 15 4 FALSE 0 16 TRUE 154 77 2.9 7.9 7 2 3 4 2.5 45 0.5 0.25 vehicle_1 x34 object/intangible/vehicle/landspeeder_x34_pcd.iff object/mobile/vehicle/landspeeder_x34.iff object/tangible/tcg/series7/garage_display_vehicles/landspeeder_x34.iff 15 4 FALSE 0 17.9 TRUE 154 77 2.9 7.9 7 2 3 4 2.5 45 0.5 0.25 vehicle_2 xj6_air_speeder object/intangible/vehicle/xj6_air_speeder_pcd.iff object/mobile/vehicle/xj6_air_speeder.iff object/tangible/tcg/series7/garage_display_vehicles/xj6_air_speeder.iff 15 4 TRUE 0 22 TRUE 154 77 2.9 9.9 7 2 3 4 2.5 45 0.5 0.25 vehicle_3 -xp38 object/intangible/vehicle/landspeeder_xp38_pcd.iff object/mobile/vehicle/landspeeder_xp38.iff object/tangible/tcg/series7/garage_display_vehicles/landspeeder_xp38.iff 15 4 FALSE 0 17.9 TRUE 154 77 2.9 8.9 7 2 3 4 2.5 45 0.5 0.25 vehicle_1 \ No newline at end of file +xp38 object/intangible/vehicle/landspeeder_xp38_pcd.iff object/mobile/vehicle/landspeeder_xp38.iff object/tangible/tcg/series7/garage_display_vehicles/landspeeder_xp38.iff 15 4 FALSE 0 17.9 TRUE 154 77 2.9 8.9 7 2 3 4 2.5 45 0.5 0.25 vehicle_1 diff --git a/src/main/java/com/projectswg/holocore/resources/support/data/server_info/loader/CachedLoader.java b/src/main/java/com/projectswg/holocore/resources/support/data/server_info/loader/CachedLoader.java index 87a9bb0f..2419f669 100644 --- a/src/main/java/com/projectswg/holocore/resources/support/data/server_info/loader/CachedLoader.java +++ b/src/main/java/com/projectswg/holocore/resources/support/data/server_info/loader/CachedLoader.java @@ -19,7 +19,8 @@ enum CachedLoader { OBJECT_DATA (ObjectDataLoader::new), COMMANDS (CommandLoader::new), SLOT_DEFINITIONS (SlotDefinitionLoader::new), - ZONE_INSERTIONS (TerrainZoneInsertionLoader::new); + ZONE_INSERTIONS (TerrainZoneInsertionLoader::new), + VEHICLES (VehicleLoader::new); private final AtomicReference> cachedLoader; private final Supplier supplier; diff --git a/src/main/java/com/projectswg/holocore/resources/support/data/server_info/loader/DataLoader.java b/src/main/java/com/projectswg/holocore/resources/support/data/server_info/loader/DataLoader.java index 84534d69..3b86d2cb 100644 --- a/src/main/java/com/projectswg/holocore/resources/support/data/server_info/loader/DataLoader.java +++ b/src/main/java/com/projectswg/holocore/resources/support/data/server_info/loader/DataLoader.java @@ -78,4 +78,8 @@ public abstract class DataLoader { return (TerrainZoneInsertionLoader) CachedLoader.ZONE_INSERTIONS.load(); } + public static VehicleLoader vehicles() { + return (VehicleLoader) CachedLoader.VEHICLES.load(); + } + } diff --git a/src/main/java/com/projectswg/holocore/resources/support/data/server_info/loader/VehicleLoader.java b/src/main/java/com/projectswg/holocore/resources/support/data/server_info/loader/VehicleLoader.java new file mode 100644 index 00000000..9db67a0b --- /dev/null +++ b/src/main/java/com/projectswg/holocore/resources/support/data/server_info/loader/VehicleLoader.java @@ -0,0 +1,229 @@ +/*********************************************************************************** + * Copyright (c) 2018 /// Project SWG /// www.projectswg.com * + * * + * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on * + * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. * + * Our goal is to create an emulator which will provide a server for players to * + * continue playing a game similar to the one they used to play. We are basing * + * it on the final publish of the game prior to end-game events. * + * * + * This file is part of Holocore. * + * * + * --------------------------------------------------------------------------------* + * * + * Holocore is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * Holocore 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 Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with Holocore. If not, see . * + ***********************************************************************************/ +package com.projectswg.holocore.resources.support.data.server_info.loader; + +import com.projectswg.common.data.swgfile.ClientFactory; +import com.projectswg.holocore.resources.support.data.server_info.SdbLoader; +import com.projectswg.holocore.resources.support.data.server_info.SdbLoader.SdbResultSet; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +public final class VehicleLoader extends DataLoader { + + private final Map vehicleTemplates; + private final Map pcdTemplates; + + VehicleLoader() { + this.vehicleTemplates = new HashMap<>(); + this.pcdTemplates = new HashMap<>(); + } + + @Nullable + public VehicleInfo getVehicleFromIff(String vehicleIff) { + return vehicleTemplates.get(ClientFactory.formatToSharedFile(vehicleIff)); + } + + @Nullable + public VehicleInfo getVehicleFromPcdIff(String pcdIff) { + return pcdTemplates.get(ClientFactory.formatToSharedFile(pcdIff)); + } + + @Override + public final void load() throws IOException { + try (SdbResultSet set = SdbLoader.load(new File("serverdata/vehicles/vehicles.sdb"))) { + while (set.next()) { + VehicleInfo vehicle = new VehicleInfo(set); + assert !vehicleTemplates.containsKey(vehicle.getObjectTemplate()) : "vehicle template already exists in map"; + assert !pcdTemplates.containsKey(vehicle.getPcdTemplate()) : "vehicle template already exists in map"; + vehicleTemplates.put(ClientFactory.formatToSharedFile(vehicle.getObjectTemplate()), vehicle); + pcdTemplates.put(ClientFactory.formatToSharedFile(vehicle.getPcdTemplate()), vehicle); + } + } + } + + public static class VehicleInfo { + + private final String objectReference; + private final String pcdTemplate; + private final String objectTemplate; + private final String garageDisplayTemplate; + private final int decayRate; + private final double repairRate; + private final boolean canRepairDisabled; + private final double minSpeed; + private final double speed; + private final boolean strafe; + private final int turnRate; + private final int turnRateMax; + private final double accelMin; + private final double accelMax; + private final double decel; + private final double dampingRoll; + private final double dampingPitch; + private final double dampingHeight; + private final double glide; + private final double bankingAngle; + private final double hoverHeight; + private final double autoLevel; + private final String playerBuff; + private final String vehicleBuff; + private final String buffClientEffect; + + public VehicleInfo(SdbResultSet set) { + this.objectReference = set.getText("object_reference"); + this.pcdTemplate = set.getText("pcd_template"); + this.objectTemplate = set.getText("object_template"); + this.garageDisplayTemplate = set.getText("garage_display_template"); + this.decayRate = (int) set.getInt("decay_rate"); + this.repairRate = set.getReal("repair_rate"); + this.canRepairDisabled = set.getBoolean("can_repair_disabled"); + this.minSpeed = set.getReal("min_speed"); + this.speed = set.getReal("speed"); + this.strafe = set.getBoolean("strafe"); + this.turnRate = (int) set.getInt("turn_rate"); + this.turnRateMax = (int) set.getInt("turn_rate_max"); + this.accelMin = set.getReal("accel_min"); + this.accelMax = set.getReal("accel_max"); + this.decel = set.getReal("decel"); + this.dampingRoll = set.getReal("damping_roll"); + this.dampingPitch = set.getReal("damping_pitch"); + this.dampingHeight = set.getReal("damping_height"); + this.glide = set.getReal("glide"); + this.bankingAngle = set.getReal("banking_angle"); + this.hoverHeight = set.getReal("hover_height"); + this.autoLevel = set.getReal("auto_level"); + this.playerBuff = set.getText("player_buff"); + this.vehicleBuff = set.getText("vehicle_buff"); + this.buffClientEffect = set.getText("buff_client_effect"); + } + + public String getObjectReference() { + return objectReference; + } + + public String getPcdTemplate() { + return pcdTemplate; + } + + public String getObjectTemplate() { + return objectTemplate; + } + + public String getGarageDisplayTemplate() { + return garageDisplayTemplate; + } + + public int getDecayRate() { + return decayRate; + } + + public double getRepairRate() { + return repairRate; + } + + public boolean isCanRepairDisabled() { + return canRepairDisabled; + } + + public double getMinSpeed() { + return minSpeed; + } + + public double getSpeed() { + return speed; + } + + public boolean isStrafe() { + return strafe; + } + + public int getTurnRate() { + return turnRate; + } + + public int getTurnRateMax() { + return turnRateMax; + } + + public double getAccelMin() { + return accelMin; + } + + public double getAccelMax() { + return accelMax; + } + + public double getDecel() { + return decel; + } + + public double getDampingRoll() { + return dampingRoll; + } + + public double getDampingPitch() { + return dampingPitch; + } + + public double getDampingHeight() { + return dampingHeight; + } + + public double getGlide() { + return glide; + } + + public double getBankingAngle() { + return bankingAngle; + } + + public double getHoverHeight() { + return hoverHeight; + } + + public double getAutoLevel() { + return autoLevel; + } + + public String getPlayerBuff() { + return playerBuff; + } + + public String getVehicleBuff() { + return vehicleBuff; + } + + public String getBuffClientEffect() { + return buffClientEffect; + } + } + +} diff --git a/src/main/java/com/projectswg/holocore/services/gameplay/world/travel/PlayerMountService.java b/src/main/java/com/projectswg/holocore/services/gameplay/world/travel/PlayerMountService.java index 3276c297..53a46124 100644 --- a/src/main/java/com/projectswg/holocore/services/gameplay/world/travel/PlayerMountService.java +++ b/src/main/java/com/projectswg/holocore/services/gameplay/world/travel/PlayerMountService.java @@ -27,9 +27,10 @@ package com.projectswg.holocore.services.gameplay.world.travel; import com.projectswg.common.data.encodables.tangible.Posture; -import com.projectswg.common.data.location.Location; +import com.projectswg.common.network.packets.swg.zone.PlayClientEffectObjectMessage; import com.projectswg.holocore.intents.gameplay.combat.CreatureIncapacitatedIntent; import com.projectswg.holocore.intents.gameplay.combat.CreatureKilledIntent; +import com.projectswg.holocore.intents.gameplay.combat.buffs.BuffIntent; import com.projectswg.holocore.intents.gameplay.world.travel.pet.*; import com.projectswg.holocore.intents.support.global.chat.SystemMessageIntent; import com.projectswg.holocore.intents.support.global.command.ExecuteCommandIntent; @@ -41,6 +42,8 @@ import com.projectswg.holocore.intents.support.objects.swg.ObjectCreatedIntent; import com.projectswg.holocore.resources.support.data.config.ConfigFile; import com.projectswg.holocore.resources.support.data.server_info.DataManager; import com.projectswg.holocore.resources.support.data.server_info.StandardLog; +import com.projectswg.holocore.resources.support.data.server_info.loader.DataLoader; +import com.projectswg.holocore.resources.support.data.server_info.loader.VehicleLoader.VehicleInfo; import com.projectswg.holocore.resources.support.global.network.DisconnectReason; import com.projectswg.holocore.resources.support.objects.ObjectCreator; import com.projectswg.holocore.resources.support.objects.swg.SWGObject; @@ -51,6 +54,7 @@ import com.projectswg.holocore.resources.support.objects.swg.group.GroupObject; import com.projectswg.holocore.resources.support.objects.swg.intangible.IntangibleObject; import com.projectswg.holocore.resources.support.objects.swg.tangible.OptionFlag; import com.projectswg.holocore.services.support.objects.ObjectStorageService.ObjectLookup; +import me.joshlarson.jlcommon.concurrency.Delay; import me.joshlarson.jlcommon.control.IntentHandler; import me.joshlarson.jlcommon.control.Service; import org.jetbrains.annotations.NotNull; @@ -205,13 +209,17 @@ public class PlayerMountService extends Service { } private void generateVehicle(CreatureObject creator, SWGObject deed) { - String deedTemplate = deed.getTemplate(); - String pcdTemplate = pcdForVehicleDeed(deedTemplate); + String pcdTemplate = pcdForVehicleDeed(deed.getTemplate()); + VehicleInfo vehicleInfo = DataLoader.vehicles().getVehicleFromPcdIff(pcdTemplate); + if (vehicleInfo == null) { + StandardLog.onPlayerError(this, creator, "Unknown vehicle created from deed: %s", deed.getTemplate()); + return; + } IntangibleObject vehicleControlDevice = (IntangibleObject) ObjectCreator.createObjectFromTemplate(pcdTemplate); DestroyObjectIntent.broadcast(deed); - vehicleControlDevice.setServerAttribute(ServerAttribute.PCD_PET_TEMPLATE, mobileForVehicleDeed(deedTemplate)); + vehicleControlDevice.setServerAttribute(ServerAttribute.PCD_PET_TEMPLATE, vehicleInfo.getObjectTemplate()); vehicleControlDevice.setCount(IntangibleObject.COUNT_PCD_STORED); vehicleControlDevice.moveToContainer(creator.getDatapad()); ObjectCreatedIntent.broadcast(vehicleControlDevice); @@ -252,6 +260,13 @@ public class PlayerMountService extends Service { return; } mountControlDevice.setCount(IntangibleObject.COUNT_PCD_CALLED); + VehicleInfo vehicleInfo = DataLoader.vehicles().getVehicleFromIff(mount.getTemplate()); + if (vehicleInfo != null) { + mount.setWalkSpeed(vehicleInfo.getMinSpeed()); + mount.setRunSpeed(vehicleInfo.getSpeed()); + mount.setAccelScale(vehicleInfo.getAccelMax()); + mount.setTurnScale(vehicleInfo.getTurnRateMax()); + } ObjectCreatedIntent.broadcast(mount); StandardLog.onPlayerTrace(this, player, "called mount %s at %s %s", mount, mount.getTerrain(), mount.getLocation().getPosition()); @@ -267,9 +282,6 @@ public class PlayerMountService extends Service { if (player.getParent() != null || player.getPosture() != Posture.UPRIGHT) return; - player.setStatesBitmask(CreatureState.RIDING_MOUNT); - mount.setStatesBitmask(CreatureState.MOUNTED_CREATURE); - if (player.getObjectId() == mount.getOwnerId()) { player.moveToSlot(mount, "rider", mount.getArrangementId(player)); } else if (mount.getSlottedObject("rider") != null) { @@ -282,7 +294,6 @@ public class PlayerMountService extends Service { for (int i = 1; i <= 7; i++) { if (!mount.hasSlot("rider" + i)) { StandardLog.onPlayerTrace(this, player, "attempted to mount %s when no slots remain", mount); - player.clearStatesBitmask(CreatureState.RIDING_MOUNT); return; } if (mount.getSlottedObject("rider" + i) == null) { @@ -293,15 +304,26 @@ public class PlayerMountService extends Service { } if (!added) { StandardLog.onPlayerTrace(this, player, "attempted to mount %s when no slots remain", mount); - player.clearStatesBitmask(CreatureState.RIDING_MOUNT); return; } } else { - player.clearStatesBitmask(CreatureState.RIDING_MOUNT); - mount.clearStatesBitmask(CreatureState.MOUNTED_CREATURE); return; } + player.setStatesBitmask(CreatureState.RIDING_MOUNT); + mount.setStatesBitmask(CreatureState.MOUNTED_CREATURE); + mount.setPosture(Posture.DRIVING_VEHICLE); + + VehicleInfo vehicleInfo = DataLoader.vehicles().getVehicleFromIff(mount.getTemplate()); + if (vehicleInfo != null) { + if (!vehicleInfo.getPlayerBuff().isEmpty()) + BuffIntent.broadcast(vehicleInfo.getPlayerBuff(), player, player, false); + if (!vehicleInfo.getVehicleBuff().isEmpty()) + BuffIntent.broadcast(vehicleInfo.getVehicleBuff(), player, mount, false); + if (!vehicleInfo.getBuffClientEffect().isEmpty()) + player.sendObservers(new PlayClientEffectObjectMessage(vehicleInfo.getBuffClientEffect(), "", mount.getObjectId(), "")); + } + player.inheritMovement(mount); StandardLog.onPlayerEvent(this, player, "mounted %s", mount); } @@ -323,20 +345,22 @@ public class PlayerMountService extends Service { return; } - clearPlayerMountState(player); + + VehicleInfo vehicleInfo = DataLoader.vehicles().getVehicleFromIff(mount.getTemplate()); if (player.getParent() == mount) { - player.moveToContainer(null, mount.getLocation()); + dismount(player, mount, vehicleInfo); + if (mount.getSlottedObject("rider") == null) { for (SWGObject child : mount.getSlottedObjects()) { assert child instanceof CreatureObject; - clearPlayerMountState((CreatureObject) child); - child.moveToContainer(null, mount.getLocation()); + dismount((CreatureObject) child, mount, vehicleInfo); } + if (vehicleInfo != null && !vehicleInfo.getVehicleBuff().isEmpty()) + BuffIntent.broadcast(vehicleInfo.getVehicleBuff(), player, mount, true); mount.clearStatesBitmask(CreatureState.MOUNTED_CREATURE); + mount.setPosture(Posture.UPRIGHT); } } - - StandardLog.onPlayerEvent(this, player, "dismounted %s", mount); } private void storeMount(@NotNull CreatureObject player, @NotNull CreatureObject mount, @NotNull IntangibleObject mountControlDevice) { @@ -387,9 +411,14 @@ public class PlayerMountService extends Service { calledMounts.entrySet().removeIf(e -> e.getValue().isEmpty()); } - private static void clearPlayerMountState(CreatureObject player) { + private void dismount(CreatureObject player, CreatureObject mount, VehicleInfo vehicleInfo) { + assert player.getParent() == mount; player.clearStatesBitmask(CreatureState.RIDING_MOUNT); + player.moveToContainer(null, mount.getLocation()); player.resetMovement(); + if (vehicleInfo != null && !vehicleInfo.getPlayerBuff().isEmpty()) + BuffIntent.broadcast(vehicleInfo.getPlayerBuff(), player, mount, true); + StandardLog.onPlayerEvent(this, player, "dismounted %s", mount); } private static boolean isMountable(CreatureObject mount) {