From 38b532d27b9c2f1a24b7bd4a3d2ee49d19255622 Mon Sep 17 00:00:00 2001 From: Waverunner Date: Mon, 11 Aug 2014 21:13:28 -0400 Subject: [PATCH] Added Quest Service, Added /activateQuest command for admins --- scripts/commands/activatequest.py | 11 +++ scripts/commands/setgodmode.py | 13 ++- src/main/NGECore.java | 19 ++-- ...wnAbilityPacket.java => GrantCommand.java} | 12 +-- src/resources/datatables/DisplayType.java | 2 +- .../objects/player/PlayerObject.java | 14 ++- src/resources/quest/Quest.java | 81 ++++++++++++++++- src/services/quest/QuestService.java | 88 +++++++++++++++++++ 8 files changed, 215 insertions(+), 25 deletions(-) create mode 100644 scripts/commands/activatequest.py rename src/protocol/swg/{UnknownAbilityPacket.java => GrantCommand.java} (82%) create mode 100644 src/services/quest/QuestService.java diff --git a/scripts/commands/activatequest.py b/scripts/commands/activatequest.py new file mode 100644 index 00000000..9c784fdb --- /dev/null +++ b/scripts/commands/activatequest.py @@ -0,0 +1,11 @@ +import sys + +def setup(): + return + +def run(core, actor, target, commandString): + + # WARNING: Quest may not show up if you haven't completed a prior quest if it's a chain - this is clientside, no way to circumvent atm + core.questService.adminActivateQuest(actor, commandString) + actor.sendSystemMessage(' \\#FE2EF7 [GM] \\#FFFFFF ActivateQuest: Command completed successfully.', 0) + return \ No newline at end of file diff --git a/scripts/commands/setgodmode.py b/scripts/commands/setgodmode.py index f3a9c4f1..aeff3947 100644 --- a/scripts/commands/setgodmode.py +++ b/scripts/commands/setgodmode.py @@ -1 +1,12 @@ -# This file will be updated at a later date with a new command. \ No newline at end of file +# This file will be updated at a later date with a new command. + +import sys +from resources.common import ProsePackage +from resources.common import OutOfBand +from protocol.swg import CreateClientPathMessage +def setup(): + return + +def run(core, actor, target, commandString): + core.questService.giveBasicQuest(actor) + return \ No newline at end of file diff --git a/src/main/NGECore.java b/src/main/NGECore.java index ccd918d8..d68e1493 100644 --- a/src/main/NGECore.java +++ b/src/main/NGECore.java @@ -23,20 +23,15 @@ package main; import java.io.BufferedReader; import java.io.File; -import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Vector; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -44,19 +39,13 @@ import java.util.concurrent.TimeUnit; import org.apache.mina.core.service.IoHandler; import org.apache.mina.core.session.IoSession; -import com.sleepycat.je.Transaction; -import com.sleepycat.persist.EntityCursor; - -import protocol.swg.chat.ChatSystemMessage; import net.engio.mbassy.bus.config.BusConfiguration; import resources.common.BountyListItem; -import resources.common.RadialOptions; import resources.common.ThreadMonitor; import resources.datatables.GalaxyStatus; import resources.objects.creature.CreatureObject; import resources.objects.guild.GuildObject; import resources.objects.resource.GalacticResource; -import resources.objects.resource.ResourceRoot; import services.AttributeService; import services.BuffService; import services.CharacterService; @@ -105,6 +94,7 @@ import services.pet.MountService; import services.pet.PetService; import services.playercities.PlayerCity; import services.playercities.PlayerCityService; +import services.quest.QuestService; import services.resources.HarvesterService; import services.resources.ResourceService; import services.retro.RetroService; @@ -144,11 +134,11 @@ import engine.servers.InteractiveJythonServer; import engine.servers.MINAServer; import engine.servers.PingServer; -@SuppressWarnings("unused") +@SuppressWarnings("unused") public class NGECore { - private static boolean logUnhandledExceptions = false; + private static boolean logUnhandledExceptions = true; public static boolean didServerCrash = false; @@ -202,6 +192,7 @@ public class NGECore { public SpawnService spawnService; public AIService aiService; public MissionService missionService; + public QuestService questService; public InstanceService instanceService; public SurveyService surveyService; public ResourceService resourceService; @@ -391,6 +382,7 @@ public class NGECore { spawnService = new SpawnService(this); aiService = new AIService(this); missionService = new MissionService(this); + questService = new QuestService(this); invasionService = new InvasionService(this); // Ping Server @@ -438,6 +430,7 @@ public class NGECore { zoneDispatch.addService(buffService); zoneDispatch.addService(entertainmentService); zoneDispatch.addService(missionService); + zoneDispatch.addService(questService); zoneDispatch.addService(bazaarService); zoneDispatch.addService(lootService); zoneDispatch.addService(mountService); diff --git a/src/protocol/swg/UnknownAbilityPacket.java b/src/protocol/swg/GrantCommand.java similarity index 82% rename from src/protocol/swg/UnknownAbilityPacket.java rename to src/protocol/swg/GrantCommand.java index 6c8047a8..1011f162 100644 --- a/src/protocol/swg/UnknownAbilityPacket.java +++ b/src/protocol/swg/GrantCommand.java @@ -25,12 +25,12 @@ import java.nio.ByteOrder; import org.apache.mina.core.buffer.IoBuffer; -public class UnknownAbilityPacket extends SWGMessage { +public class GrantCommand extends SWGMessage { - private String ability; + private String command; - public UnknownAbilityPacket(String ability) { - this.ability = ability; + public GrantCommand(String command) { + this.command = command; } @Override @@ -40,10 +40,10 @@ public class UnknownAbilityPacket extends SWGMessage { @Override public IoBuffer serialize() { - IoBuffer buffer = IoBuffer.allocate(8 + ability.length()).order(ByteOrder.LITTLE_ENDIAN); + IoBuffer buffer = IoBuffer.allocate(8 + command.length()).order(ByteOrder.LITTLE_ENDIAN); buffer.putShort((short) 2); buffer.putInt(0xE67E3875); - buffer.put(getAsciiString(ability)); + buffer.put(getAsciiString(command)); return buffer.flip(); } diff --git a/src/resources/datatables/DisplayType.java b/src/resources/datatables/DisplayType.java index 437a0df4..8003e36c 100644 --- a/src/resources/datatables/DisplayType.java +++ b/src/resources/datatables/DisplayType.java @@ -28,7 +28,7 @@ public class DisplayType { public static byte Screen = 1; // Screen? XP gain public static byte Chat = 2; //public static byte Overhead = 3; // Flytext? Seen on ent duration - //public static byte Combat = 4; // CombatSpam? + public static byte Quest = 4; //public static byte Combat = 5; // Seen in combat flytext //public static byte Combat = 11; // Seen when blocking diff --git a/src/resources/objects/player/PlayerObject.java b/src/resources/objects/player/PlayerObject.java index a10046c4..6ac855d1 100644 --- a/src/resources/objects/player/PlayerObject.java +++ b/src/resources/objects/player/PlayerObject.java @@ -46,6 +46,8 @@ import resources.objects.resource.ResourceContainerObject; import resources.objects.waypoint.WaypointObject; import resources.quest.Quest; import engine.clients.Client; +import engine.resources.common.CRC; +import engine.resources.common.StringUtilities; import engine.resources.objects.Baseline; import engine.resources.scene.Planet; import engine.resources.scene.Point3D; @@ -158,8 +160,8 @@ public class PlayerObject extends IntangibleObject implements Serializable { baseline.put("maxForcePower", 100); baseline.put("currentFSQuestList", new SWGList(this, 8, 4, false)); baseline.put("completedFSQuestList", new SWGList(this, 8, 5, false)); - baseline.put("questJournal", new SWGList(this, 8, 6, false)); - baseline.put("7", 0); + baseline.put("activeQuest", 0); + baseline.put("questJournal", new SWGList(this, 8, 7, false)); baseline.put("professionWheelPosition", ""); return baseline; } @@ -593,6 +595,13 @@ public class PlayerObject extends IntangibleObject implements Serializable { return (SWGList) getBaseline(8).get("questJournal"); } + public int getActiveQuest() { + return (int) getBaseline(8).get("activeQuest"); + } + + public void setActiveQuest(String quest) { + getBaseline(8).set("activeQuest", CRC.StringtoCRC("quest/"+quest)); + } public String getProfessionWheelPosition() { return (String) getBaseline(8).get("professionWheelPosition"); } @@ -1020,6 +1029,7 @@ public class PlayerObject extends IntangibleObject implements Serializable { @Override public void sendListDelta(byte viewType, short updateType, IoBuffer buffer) { + switch (viewType) { case 3: case 6: diff --git a/src/resources/quest/Quest.java b/src/resources/quest/Quest.java index 80348605..f2f205ea 100644 --- a/src/resources/quest/Quest.java +++ b/src/resources/quest/Quest.java @@ -23,18 +23,95 @@ package resources.quest; import java.io.Serializable; +import org.apache.mina.core.buffer.IoBuffer; + +import engine.resources.common.CRC; import engine.resources.objects.Delta; public class Quest extends Delta implements Serializable { private static final long serialVersionUID = 1L; - public Quest() { + private long ownerId; + private short activeStep = 1; + private short completedStep; + private boolean isCompleted = false; + private String name; + private int crc; + + public Quest() {} + + public Quest(String name, long ownerId) { + this.ownerId = ownerId; + this.name = name; + this.crc = CRC.StringtoCRC("quest/"+name); } + public long getOwnerId() { + return ownerId; + } + + public void setOwnerId(long ownerId) { + this.ownerId = ownerId; + } + + public short getActiveStep() { + return activeStep; + } + + public void setActiveStep(short activeStep) { + this.activeStep = activeStep; + } + + public short getCompletedStep() { + return completedStep; + } + + public void setCompletedStep(short completedStep) { + this.completedStep = completedStep; + } + + public boolean isCompleted() { + return isCompleted; + } + + public void setCompleted(boolean isCompleted) { + this.isCompleted = isCompleted; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + this.crc = CRC.StringtoCRC(name); + } + + public int getCrc() { + return crc; + } + public byte[] getBytes() { - return new byte[] { }; + IoBuffer buffer = createBuffer(23); + + buffer.put((byte) 0); + + buffer.putInt(crc); + + buffer.putLong(ownerId); + + buffer.putShort(activeStep); + buffer.putShort(completedStep); + + buffer.put((byte) ((isCompleted) ? 1 : 0)); // isCompleted + buffer.putInt(21); // questCounter + //buffer.put((byte) 0); // ? + + buffer.flip(); + + return buffer.array(); } } diff --git a/src/services/quest/QuestService.java b/src/services/quest/QuestService.java new file mode 100644 index 00000000..018b2105 --- /dev/null +++ b/src/services/quest/QuestService.java @@ -0,0 +1,88 @@ +/******************************************************************************* + * 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.quest; + +import java.util.Map; + +import protocol.swg.PlayMusicMessage; +import resources.common.OutOfBand; +import resources.common.ProsePackage; +import resources.datatables.DisplayType; +import resources.objects.creature.CreatureObject; +import resources.objects.player.PlayerObject; +import resources.quest.Quest; +import main.NGECore; +import engine.resources.service.INetworkDispatch; +import engine.resources.service.INetworkRemoteEvent; + +public class QuestService implements INetworkDispatch { + + @SuppressWarnings("unused") + private NGECore core; + + public QuestService(NGECore core) { + this.core = core; + } + + @Override + public void insertOpcodes(Map swgOpcodes, Map objControllerOpcodes) { + + } + + @Override + public void shutdown() { } + + public void beginQuest(String questName, CreatureObject questReciever) { + + } + + public void adminActivateQuest(CreatureObject creo, String questName) { + + PlayerObject ghost = creo.getPlayerObject(); + + if (ghost == null) + return; + + if (questName.endsWith(".qst")) + questName = questName.split(".qst")[0]; + + Quest quest = new Quest(questName, creo.getObjectID()); + + ProsePackage prose = new ProsePackage("@quest/ground/system_message:quest_received"); + + // Format for stf string if quest resides in multiple folders beyond base one + if (questName.contains("/")) { + String[] split = questName.split("/"); + questName = split[split.length - 1]; + } + + prose.setToCustomString("@quest/ground/" + questName + ":journal_entry_title"); + creo.sendSystemMessage(new OutOfBand(prose), DisplayType.Quest); + + PlayMusicMessage music = new PlayMusicMessage("sound/ui_npe2_quest_received.snd", creo.getObjectID(), 0, true); + creo.getClient().getSession().write(music.serialize()); + + ghost.getQuestJournal().add(quest); + ghost.setActiveQuest(quest.getName()); + + } +}