1package com.runehive.content.ai;
3import com.runehive.content.dialogue.Dialogue;
4import com.runehive.content.dialogue.DialogueFactory;
5import com.runehive.content.dialogue.Expression;
6import com.runehive.game.task.Task;
7import com.runehive.game.world.World;
8import com.runehive.game.world.entity.mob.npc.Npc;
9import com.runehive.game.world.entity.mob.player.Player;
10import com.runehive.game.world.object.CustomGameObject;
11import com.runehive.game.world.object.ObjectDirection;
12import com.runehive.game.world.position.Position;
13import com.runehive.net.packet.out.SendInputMessage;
14import org.slf4j.Logger;
15import org.slf4j.LoggerFactory;
34 player.dialogueCamNpc =
npc;
35 player.dialogueCamMode = com.runehive.game.world.entity.mob.player.camera.DialogueCameraDirector.Mode.OFF;
36 player.dialogueCamDelayTicks = 2;
37 com.runehive.game.world.entity.mob.player.camera.DialogueCameraDirector.boostSwap(player, 8);
40 "What would you like to ask?",
41 "Type in chat: ::gpt <your message>")
45 com.runehive.game.world.entity.mob.player.camera.DialogueCameraDirector.requestReset(player);
60 player.
message(
"You must be near the Wise Old Man to use AI chat.");
65 player.
message(
"AI services are not initialized. Click the Wise Old Man first.");
72 if (gandalf ==
null) {
73 player.
message(
"Could not find the Wise Old Man NPC. Please stand closer.");
81 player.
move(playerTarget);
86 player.dialogueCamNpc = gandalf;
87 player.dialogueCamMode = com.runehive.game.world.entity.mob.player.camera.DialogueCameraDirector.Mode.OFF;
88 player.dialogueCamDelayTicks = 2;
89 com.runehive.game.world.entity.mob.player.camera.DialogueCameraDirector.boostSwap(player, 8);
95 new AIDialogueHandler(gandalf).processGandalfAIMessage(player, gandalf, sanitizedInput);
104 int distX = Math.abs(
npc.getPosition().getX() - targetX);
105 int distY = Math.abs(
npc.getPosition().getY() - targetY);
106 if (distX <= maxDistance && distY <= maxDistance) {
118 String cleaned = input.trim().replaceAll(
"[<>]",
"");
119 return cleaned.substring(0, Math.min(cleaned.length(), 500));
130 player.dialogueCamMode = com.runehive.game.world.entity.mob.player.camera.DialogueCameraDirector.Mode.BEHIND_NPC;
131 com.runehive.game.world.entity.mob.player.camera.DialogueCameraDirector.boostSwap(player, 8);
132 npc.animate(
new com.runehive.game.Animation(4079));
135 logger.info(
"Processing Gandalf AI request from {} (length: {})",
140 .thenAccept(response -> {
143 public void execute() {
145 logger.warn(
"Player {} is no longer online, skipping response",
155 npc.animate(
new com.runehive.game.Animation(-1));
158 if (response !=
null && !response.isEmpty()) {
162 player.dialogueFactory
164 "The mystical connection faltered.",
165 "Perhaps try again with a different query.")
172 }
catch (Exception e) {
173 logger.error(
"Exception while processing AI response for {}", player.
getUsername(), e);
180 .exceptionally(throwable -> {
181 logger.error(
"Error in Gandalf AI processing", throwable);
184 public void execute() {
192 player.dialogueFactory
194 "The AI spirits are restless.",
195 "Please try again in a moment.")
200 }
catch (Exception e) {
212 logger.info(
"[TTS-SERVER] ========================================");
213 logger.info(
"[TTS-SERVER] Sending Gandalf response to player: {}", player.
getUsername());
214 logger.info(
"[TTS-SERVER] Full response: {}", response);
217 logger.info(
"[TTS-SERVER] Wrapped into {} lines", lines.length);
218 for (
int i = 0; i < lines.length; i++) {
219 logger.info(
"[TTS-SERVER] Line {}: {}", i+1, lines[i]);
225 player.dialogueCamMode = com.runehive.game.world.entity.mob.
player.camera.DialogueCameraDirector.Mode.BEHIND_NPC;
227 int linesPerPage = 3;
228 for (
int i = 0; i < lines.length; i += linesPerPage) {
229 int endIndex = Math.min(i + linesPerPage, lines.length);
230 String[] pageLines = java.util.Arrays.copyOfRange(lines, i, endIndex);
232 logger.info(
"[TTS-SERVER] Sending dialogue page {}: {} lines", (i/linesPerPage)+1, pageLines.length);
236 String combinedText = String.join(
" ", pageLines);
237 npc.speak(combinedText);
240 logger.info(
"[TTS-SERVER] ========================================");
243 "Ask another question", () -> {
245 com.runehive.game.world.entity.mob.player.camera.DialogueCameraDirector.requestReset(player);
249 "No further questions", () -> {
252 player.dialogueCamMode = com.runehive.game.world.entity.mob.player.camera.DialogueCameraDirector.Mode.BEHIND_PLAYER;
253 com.runehive.game.world.entity.mob.player.camera.DialogueCameraDirector.boostSwap(player, 6);
258 public void execute() {
260 player.
speak(
"No, that's all, thank you.");
265 public void execute() {
266 npc.speak(
"Come back again, anytime!");
272 public void execute() {
275 com.runehive.game.world.entity.mob.player.camera.DialogueCameraDirector.requestReset(player);
292 String[] words = text.split(
" ");
293 StringBuilder current =
new StringBuilder();
294 java.util.List<String> lines =
new java.util.ArrayList<>();
296 for (String word : words) {
297 if (current.length() + word.length() + 1 > maxCharsPerLine) {
298 if (current.length() > 0) {
299 lines.add(current.toString().trim());
300 current =
new StringBuilder(word);
305 if (current.length() > 0) {
308 current.append(word);
312 if (current.length() > 0) {
313 lines.add(current.toString().trim());
316 return lines.toArray(
new String[0]);
String sanitizeInput(String input)
AIDialogueHandler(Npc npc)
static Npc findNearbyNpc(Player player, int npcId, int targetX, int targetY, int maxDistance)
Find an NPC by ID near specific coordinates.
void sendDialogues(DialogueFactory factory)
Sends a player a dialogue.
static void handleAICommand(Player player, String message)
Process AI command input (called from command handler)
static final Logger logger
static final int GANDALF_AI_ID
void processGandalfAIMessage(Player player, Npc npc, String message)
String[] wrapTextToLines(String text, int maxCharsPerLine)
void streamGandalfResponse(Player player, Npc npc, String response)
static OpenAIService getOpenAIService()
static void clearPlayerConsent(String username)
static void markInstructionsReceived(String username)
static boolean isInitialized()
CompletableFuture< String > processPlayerMessage(String username, String message, int npcId)
Represents a factory class that contains important functions for building dialogues.
final DialogueFactory sendDialogue(Dialogue dialogue)
Sends a player a dialogue.
final DialogueFactory execute()
Retrieves the next dialogue in the chain and executes it.
final DialogueFactory onAction(Runnable action)
Sets an action so this action can be executed after dialogues are done.
final Player player
The player who owns this factory.
Player getPlayer()
The player that owns this factory.
final DialogueFactory sendNpcChat(int id, String... lines)
Appends an NpcDialogue to the current dialogue chain.
final DialogueFactory sendOption(String option1, Runnable action1, String option2, Runnable action2)
Appends the OptionDialogue onto the current dialogue chain.
Represents an abstract dialogue, in which extending classes will be able to construct and send dialog...
A game representing a cyclic unit of work.
Represents the game world.
static void schedule(Task task)
Submits a new event.
static MobList< Npc > getNpcs()
final boolean isRegistered()
void unlock()
Unlocks the mob.
void speak(String forceChat)
Sets the mob's forced chat.
void move(Position position)
Moves the mob to a set position.
void face(GameObject object)
Sets the client update flag to face a certain direction.
Represents a non-player character in the in-game world.
void close(int interfaceId)
This class represents a character controlled by a player.
void message(String message)
DialogueFactory dialogueFactory
final InterfaceManager interfaceManager
Represents a static game object loaded from the map fs.
void unregister()
Unregisters an entity from the World.
void register()
Registers an entity to the World.
Represents a single tile on the game world.
int getHeight()
Gets the height coordinate, or height.
int getY()
Gets the absolute y coordinate.
Position(int x, int y)
Creates a location with a default height of 0.
int getX()
Gets the absolute x coordinate.
Represents the expressions of entities for dialogue.
The enumerated type whose elements represent the directions for objects.
WEST
The west orientation.