Commit 1e55dcba by Jonathan Thomas

Improved error handling to prevent broken "..." pending chat status. (HTTP and…

Improved error handling to prevent broken "..." pending chat status. (HTTP and message processing is more protected). Removed randomized error messages from chat history (so it doesn't break the chat history when an error is shown)
parent a5fb3933
Pipeline #13344 passed with stages
in 2 minutes 28 seconds
...@@ -11,11 +11,13 @@ All notable changes to **CreatureChat** are documented in this file. The format ...@@ -11,11 +11,13 @@ All notable changes to **CreatureChat** are documented in this file. The format
### Changed ### Changed
- Broadcasting and receiving chat messages now ignores if the UUID is valid (to keep data synced) - Broadcasting and receiving chat messages now ignores if the UUID is valid (to keep data synced)
- Improved error handling to prevent broken "..." pending chat status. (HTTP and message processing is more protected)
### Fixed ### Fixed
- Bees no longer forget their chat data when entering/leaving hives (writeNbt & readNbt modified) - Bees no longer forget their chat data when entering/leaving hives (writeNbt & readNbt modified)
- Vexes no longer take damage when chat data exists - Vexes no longer take damage when chat data exists
- Wandering Trader no longer despawns if it has chat data - Wandering Trader no longer despawns if it has chat data
- Removed randomized error messages from chat history (so it doesn't break the chat history when an error is shown)
## [1.3.0] - 2025-01-14 ## [1.3.0] - 2025-01-14
......
...@@ -196,6 +196,7 @@ public class ChatGPTRequest { ...@@ -196,6 +196,7 @@ public class ChatGPTRequest {
lastErrorMessage = cleanError; lastErrorMessage = cleanError;
} catch (Exception e) { } catch (Exception e) {
LOGGER.error("Failed to read error response", e); LOGGER.error("Failed to read error response", e);
lastErrorMessage = "Failed to read error response: " + e.getMessage();
} }
return null; return null;
} else { } else {
...@@ -214,12 +215,16 @@ public class ChatGPTRequest { ...@@ -214,12 +215,16 @@ public class ChatGPTRequest {
if (chatGPTResponse != null && chatGPTResponse.choices != null && !chatGPTResponse.choices.isEmpty()) { if (chatGPTResponse != null && chatGPTResponse.choices != null && !chatGPTResponse.choices.isEmpty()) {
String content = chatGPTResponse.choices.get(0).message.content; String content = chatGPTResponse.choices.get(0).message.content;
return content; return content;
} else {
lastErrorMessage = "Failed to parse response from LLM";
return null;
} }
} }
} catch (IOException e) { } catch (Exception e) {
LOGGER.error("Failed to fetch message from ChatGPT", e); LOGGER.error("Failed to request message from LLM", e);
lastErrorMessage = "Failed to request message from LLM: " + e.getMessage();
return null;
} }
return null; // If there was an error or no response, return null
}); });
} }
} }
......
...@@ -273,34 +273,41 @@ public class EntityChatData { ...@@ -273,34 +273,41 @@ public class EntityChatData {
// fetch HTTP response from ChatGPT // fetch HTTP response from ChatGPT
ChatGPTRequest.fetchMessageFromChatGPT(config, promptText, contextData, previousMessages, false).thenAccept(output_message -> { ChatGPTRequest.fetchMessageFromChatGPT(config, promptText, contextData, previousMessages, false).thenAccept(output_message -> {
if (output_message != null) { try {
// Character Sheet: Remove system-character message from previous messages if (output_message != null) {
previousMessages.clear(); // Character Sheet: Remove system-character message from previous messages
previousMessages.clear();
// Add NEW CHARACTER sheet & greeting
this.characterSheet = output_message;
String shortGreeting = Optional.ofNullable(getCharacterProp("short greeting")).filter(s -> !s.isEmpty()).orElse(Randomizer.getRandomMessage(Randomizer.RandomType.NO_RESPONSE)).replace("\n", " ");
this.addMessage(shortGreeting, ChatDataManager.ChatSender.ASSISTANT, player, systemPrompt);
} else {
// No valid LLM response
throw new RuntimeException(ChatGPTRequest.lastErrorMessage);
}
// Add NEW CHARACTER sheet & greeting } catch (Exception e) {
this.characterSheet = output_message; // Log the exception for debugging
String shortGreeting = Optional.ofNullable(getCharacterProp("short greeting")).filter(s -> !s.isEmpty()).orElse(Randomizer.getRandomMessage(Randomizer.RandomType.NO_RESPONSE)).replace("\n", " "); LOGGER.error("Error processing LLM response", e);
this.addMessage(shortGreeting, ChatDataManager.ChatSender.ASSISTANT, player, systemPrompt);
} else {
// Error / No Chat Message (Failure) // Error / No Chat Message (Failure)
String randomErrorMessage = Randomizer.getRandomMessage(Randomizer.RandomType.ERROR); String randomErrorMessage = Randomizer.getRandomMessage(Randomizer.RandomType.ERROR);
this.addMessage(randomErrorMessage, ChatDataManager.ChatSender.ASSISTANT, player, systemPrompt); this.addMessage(randomErrorMessage, ChatDataManager.ChatSender.ASSISTANT, player, systemPrompt);
// Determine error message to display // Remove the error message from history to prevent it from affecting future ChatGPT requests
String errorMessage = "Help is available at discord.creaturechat.com"; if (!previousMessages.isEmpty()) {
if (!ChatGPTRequest.lastErrorMessage.isEmpty()) { previousMessages.remove(previousMessages.size() - 1);
errorMessage = "Error: " + truncateString(ChatGPTRequest.lastErrorMessage, 55) + "\n" + errorMessage;
} }
// Send clickable error message // Send clickable error message
ServerPackets.SendClickableError(player, String errorMessage = "Error: ";
errorMessage, "http://discord.creaturechat.com"); if (e.getMessage() != null && !e.getMessage().isEmpty()) {
errorMessage += truncateString(e.getMessage(), 55) + "\n";
// Clear history (if no character sheet was generated)
if (characterSheet.isEmpty()) {
previousMessages.clear();
} }
errorMessage += "Help is available at discord.creaturechat.com";
ServerPackets.SendClickableError(player, errorMessage, "http://discord.creaturechat.com");
} }
}); });
} }
...@@ -336,236 +343,242 @@ public class EntityChatData { ...@@ -336,236 +343,242 @@ public class EntityChatData {
// fetch HTTP response from ChatGPT // fetch HTTP response from ChatGPT
ChatGPTRequest.fetchMessageFromChatGPT(config, promptText, contextData, previousMessages, false).thenAccept(output_message -> { ChatGPTRequest.fetchMessageFromChatGPT(config, promptText, contextData, previousMessages, false).thenAccept(output_message -> {
if (output_message != null) { try {
// Chat Message: Parse message for behaviors if (output_message != null) {
ParsedMessage result = MessageParser.parseMessage(output_message.replace("\n", " ")); // Chat Message: Parse message for behaviors
MobEntity entity = (MobEntity)ServerEntityFinder.getEntityByUUID(player.getServerWorld(), UUID.fromString(entityId)); ParsedMessage result = MessageParser.parseMessage(output_message.replace("\n", " "));
MobEntity entity = (MobEntity) ServerEntityFinder.getEntityByUUID(player.getServerWorld(), UUID.fromString(entityId));
// Determine entity's default speed
// Some Entities (i.e. Axolotl) set this incorrectly... so adjusting in the SpeedControls class // Determine entity's default speed
float entitySpeed = SpeedControls.getMaxSpeed(entity); // Some Entities (i.e. Axolotl) set this incorrectly... so adjusting in the SpeedControls class
float entitySpeedMedium = MathHelper.clamp(entitySpeed * 1.15F, 0.5f, 1.15f); float entitySpeed = SpeedControls.getMaxSpeed(entity);
float entitySpeedFast = MathHelper.clamp(entitySpeed * 1.3F, 0.5f, 1.3f); float entitySpeedMedium = MathHelper.clamp(entitySpeed * 1.15F, 0.5f, 1.15f);
float entitySpeedFast = MathHelper.clamp(entitySpeed * 1.3F, 0.5f, 1.3f);
// Apply behaviors (if any)
for (Behavior behavior : result.getBehaviors()) { // Apply behaviors (if any)
LOGGER.info("Behavior: " + behavior.getName() + (behavior.getArgument() != null ? for (Behavior behavior : result.getBehaviors()) {
", Argument: " + behavior.getArgument() : "")); LOGGER.info("Behavior: " + behavior.getName() + (behavior.getArgument() != null ?
", Argument: " + behavior.getArgument() : ""));
// Apply behaviors to entity
if (behavior.getName().equals("FOLLOW")) { // Apply behaviors to entity
FollowPlayerGoal followGoal = new FollowPlayerGoal(player, entity, entitySpeedMedium); if (behavior.getName().equals("FOLLOW")) {
EntityBehaviorManager.removeGoal(entity, TalkPlayerGoal.class); FollowPlayerGoal followGoal = new FollowPlayerGoal(player, entity, entitySpeedMedium);
EntityBehaviorManager.removeGoal(entity, FleePlayerGoal.class); EntityBehaviorManager.removeGoal(entity, TalkPlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, AttackPlayerGoal.class); EntityBehaviorManager.removeGoal(entity, FleePlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, LeadPlayerGoal.class); EntityBehaviorManager.removeGoal(entity, AttackPlayerGoal.class);
EntityBehaviorManager.addGoal(entity, followGoal, GoalPriority.FOLLOW_PLAYER); EntityBehaviorManager.removeGoal(entity, LeadPlayerGoal.class);
if (playerData.friendship >= 0) { EntityBehaviorManager.addGoal(entity, followGoal, GoalPriority.FOLLOW_PLAYER);
ParticleEmitter.emitCreatureParticle((ServerWorld) entity.getWorld(), entity, FOLLOW_FRIEND_PARTICLE, 0.5, 1); if (playerData.friendship >= 0) {
} else { ParticleEmitter.emitCreatureParticle((ServerWorld) entity.getWorld(), entity, FOLLOW_FRIEND_PARTICLE, 0.5, 1);
ParticleEmitter.emitCreatureParticle((ServerWorld) entity.getWorld(), entity, FOLLOW_ENEMY_PARTICLE, 0.5, 1); } else {
} ParticleEmitter.emitCreatureParticle((ServerWorld) entity.getWorld(), entity, FOLLOW_ENEMY_PARTICLE, 0.5, 1);
}
} else if (behavior.getName().equals("UNFOLLOW")) { } else if (behavior.getName().equals("UNFOLLOW")) {
EntityBehaviorManager.removeGoal(entity, FollowPlayerGoal.class); EntityBehaviorManager.removeGoal(entity, FollowPlayerGoal.class);
} else if (behavior.getName().equals("FLEE")) {
float fleeDistance = 40F;
FleePlayerGoal fleeGoal = new FleePlayerGoal(player, entity, entitySpeedFast, fleeDistance);
EntityBehaviorManager.removeGoal(entity, TalkPlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, FollowPlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, AttackPlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, ProtectPlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, LeadPlayerGoal.class);
EntityBehaviorManager.addGoal(entity, fleeGoal, GoalPriority.FLEE_PLAYER);
ParticleEmitter.emitCreatureParticle((ServerWorld) entity.getWorld(), entity, FLEE_PARTICLE, 0.5, 1);
} else if (behavior.getName().equals("UNFLEE")) {
EntityBehaviorManager.removeGoal(entity, FleePlayerGoal.class);
} else if (behavior.getName().equals("ATTACK")) {
AttackPlayerGoal attackGoal = new AttackPlayerGoal(player, entity, entitySpeedFast);
EntityBehaviorManager.removeGoal(entity, TalkPlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, FollowPlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, FleePlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, ProtectPlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, LeadPlayerGoal.class);
EntityBehaviorManager.addGoal(entity, attackGoal, GoalPriority.ATTACK_PLAYER);
ParticleEmitter.emitCreatureParticle((ServerWorld) entity.getWorld(), entity, FLEE_PARTICLE, 0.5, 1);
} else if (behavior.getName().equals("PROTECT")) {
if (playerData.friendship <= 0) {
// force friendship to prevent entity from attacking player when protecting
playerData.friendship = 1;
}
ProtectPlayerGoal protectGoal = new ProtectPlayerGoal(player, entity, 1.0);
EntityBehaviorManager.removeGoal(entity, TalkPlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, FleePlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, AttackPlayerGoal.class);
EntityBehaviorManager.addGoal(entity, protectGoal, GoalPriority.PROTECT_PLAYER);
ParticleEmitter.emitCreatureParticle((ServerWorld) entity.getWorld(), entity, PROTECT_PARTICLE, 0.5, 1);
} else if (behavior.getName().equals("UNPROTECT")) {
EntityBehaviorManager.removeGoal(entity, ProtectPlayerGoal.class);
} else if (behavior.getName().equals("LEAD")) {
LeadPlayerGoal leadGoal = new LeadPlayerGoal(player, entity, entitySpeedMedium);
EntityBehaviorManager.removeGoal(entity, FollowPlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, FleePlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, AttackPlayerGoal.class);
EntityBehaviorManager.addGoal(entity, leadGoal, GoalPriority.LEAD_PLAYER);
if (playerData.friendship >= 0) {
ParticleEmitter.emitCreatureParticle((ServerWorld) entity.getWorld(), entity, LEAD_FRIEND_PARTICLE, 0.5, 1);
} else {
ParticleEmitter.emitCreatureParticle((ServerWorld) entity.getWorld(), entity, LEAD_ENEMY_PARTICLE, 0.5, 1);
}
} else if (behavior.getName().equals("UNLEAD")) {
EntityBehaviorManager.removeGoal(entity, LeadPlayerGoal.class);
} else if (behavior.getName().equals("FRIENDSHIP")) { } else if (behavior.getName().equals("FLEE")) {
int new_friendship = Math.max(-3, Math.min(3, behavior.getArgument())); float fleeDistance = 40F;
FleePlayerGoal fleeGoal = new FleePlayerGoal(player, entity, entitySpeedFast, fleeDistance);
EntityBehaviorManager.removeGoal(entity, TalkPlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, FollowPlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, AttackPlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, ProtectPlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, LeadPlayerGoal.class);
EntityBehaviorManager.addGoal(entity, fleeGoal, GoalPriority.FLEE_PLAYER);
ParticleEmitter.emitCreatureParticle((ServerWorld) entity.getWorld(), entity, FLEE_PARTICLE, 0.5, 1);
// Does friendship improve? } else if (behavior.getName().equals("UNFLEE")) {
if (new_friendship > playerData.friendship) { EntityBehaviorManager.removeGoal(entity, FleePlayerGoal.class);
// Stop any attack/flee if friendship improves
} else if (behavior.getName().equals("ATTACK")) {
AttackPlayerGoal attackGoal = new AttackPlayerGoal(player, entity, entitySpeedFast);
EntityBehaviorManager.removeGoal(entity, TalkPlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, FollowPlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, FleePlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, ProtectPlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, LeadPlayerGoal.class);
EntityBehaviorManager.addGoal(entity, attackGoal, GoalPriority.ATTACK_PLAYER);
ParticleEmitter.emitCreatureParticle((ServerWorld) entity.getWorld(), entity, FLEE_PARTICLE, 0.5, 1);
} else if (behavior.getName().equals("PROTECT")) {
if (playerData.friendship <= 0) {
// force friendship to prevent entity from attacking player when protecting
playerData.friendship = 1;
}
ProtectPlayerGoal protectGoal = new ProtectPlayerGoal(player, entity, 1.0);
EntityBehaviorManager.removeGoal(entity, TalkPlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, FleePlayerGoal.class); EntityBehaviorManager.removeGoal(entity, FleePlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, AttackPlayerGoal.class); EntityBehaviorManager.removeGoal(entity, AttackPlayerGoal.class);
EntityBehaviorManager.addGoal(entity, protectGoal, GoalPriority.PROTECT_PLAYER);
ParticleEmitter.emitCreatureParticle((ServerWorld) entity.getWorld(), entity, PROTECT_PARTICLE, 0.5, 1);
} else if (behavior.getName().equals("UNPROTECT")) {
EntityBehaviorManager.removeGoal(entity, ProtectPlayerGoal.class);
if (entity instanceof WitherEntity && new_friendship == 3) { } else if (behavior.getName().equals("LEAD")) {
// Best friend a Nether and get a NETHER_STAR LeadPlayerGoal leadGoal = new LeadPlayerGoal(player, entity, entitySpeedMedium);
WitherEntity wither = (WitherEntity) entity; EntityBehaviorManager.removeGoal(entity, FollowPlayerGoal.class);
((WitherEntityAccessor) wither).callDropEquipment(entity.getWorld().getDamageSources().generic(), 1, true); EntityBehaviorManager.removeGoal(entity, FleePlayerGoal.class);
entity.getWorld().playSound(entity, entity.getBlockPos(), SoundEvents.ENTITY_WITHER_DEATH, SoundCategory.PLAYERS, 0.3F, 1.0F); EntityBehaviorManager.removeGoal(entity, AttackPlayerGoal.class);
EntityBehaviorManager.addGoal(entity, leadGoal, GoalPriority.LEAD_PLAYER);
if (playerData.friendship >= 0) {
ParticleEmitter.emitCreatureParticle((ServerWorld) entity.getWorld(), entity, LEAD_FRIEND_PARTICLE, 0.5, 1);
} else {
ParticleEmitter.emitCreatureParticle((ServerWorld) entity.getWorld(), entity, LEAD_ENEMY_PARTICLE, 0.5, 1);
} }
} else if (behavior.getName().equals("UNLEAD")) {
EntityBehaviorManager.removeGoal(entity, LeadPlayerGoal.class);
} else if (behavior.getName().equals("FRIENDSHIP")) {
int new_friendship = Math.max(-3, Math.min(3, behavior.getArgument()));
// Does friendship improve?
if (new_friendship > playerData.friendship) {
// Stop any attack/flee if friendship improves
EntityBehaviorManager.removeGoal(entity, FleePlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, AttackPlayerGoal.class);
if (entity instanceof WitherEntity && new_friendship == 3) {
// Best friend a Nether and get a NETHER_STAR
WitherEntity wither = (WitherEntity) entity;
((WitherEntityAccessor) wither).callDropEquipment(entity.getWorld().getDamageSources().generic(), 1, true);
entity.getWorld().playSound(entity, entity.getBlockPos(), SoundEvents.ENTITY_WITHER_DEATH, SoundCategory.PLAYERS, 0.3F, 1.0F);
}
if (entity instanceof EnderDragonEntity && new_friendship == 3) { if (entity instanceof EnderDragonEntity && new_friendship == 3) {
// Trigger end of game (friendship always wins!) // Trigger end of game (friendship always wins!)
EnderDragonEntity dragon = (EnderDragonEntity) entity; EnderDragonEntity dragon = (EnderDragonEntity) entity;
// Emit particles & sound // Emit particles & sound
ParticleEmitter.emitCreatureParticle((ServerWorld) entity.getWorld(), entity, HEART_BIG_PARTICLE, 3, 200); ParticleEmitter.emitCreatureParticle((ServerWorld) entity.getWorld(), entity, HEART_BIG_PARTICLE, 3, 200);
entity.getWorld().playSound(entity, entity.getBlockPos(), SoundEvents.ENTITY_ENDER_DRAGON_DEATH, SoundCategory.PLAYERS, 0.3F, 1.0F); entity.getWorld().playSound(entity, entity.getBlockPos(), SoundEvents.ENTITY_ENDER_DRAGON_DEATH, SoundCategory.PLAYERS, 0.3F, 1.0F);
entity.getWorld().playSound(entity, entity.getBlockPos(), SoundEvents.UI_TOAST_CHALLENGE_COMPLETE, SoundCategory.PLAYERS, 0.5F, 1.0F); entity.getWorld().playSound(entity, entity.getBlockPos(), SoundEvents.UI_TOAST_CHALLENGE_COMPLETE, SoundCategory.PLAYERS, 0.5F, 1.0F);
// Check if the game rule for mob loot is enabled // Check if the game rule for mob loot is enabled
boolean doMobLoot = entity.getWorld().getGameRules().getBoolean(GameRules.DO_MOB_LOOT); boolean doMobLoot = entity.getWorld().getGameRules().getBoolean(GameRules.DO_MOB_LOOT);
// If this is the first time the dragon is 'befriended', adjust the XP // If this is the first time the dragon is 'befriended', adjust the XP
int baseXP = 500; int baseXP = 500;
if (dragon.getFight() != null && !dragon.getFight().hasPreviouslyKilled()) { if (dragon.getFight() != null && !dragon.getFight().hasPreviouslyKilled()) {
baseXP = 12000; baseXP = 12000;
} }
// If the world is a server world and mob loot is enabled, spawn XP orbs // If the world is a server world and mob loot is enabled, spawn XP orbs
if (entity.getWorld() instanceof ServerWorld && doMobLoot) { if (entity.getWorld() instanceof ServerWorld && doMobLoot) {
// Loop to spawn XP orbs // Loop to spawn XP orbs
for (int j = 1; j <= 11; j++) { for (int j = 1; j <= 11; j++) {
float xpFraction = (j == 11) ? 0.2F : 0.08F; float xpFraction = (j == 11) ? 0.2F : 0.08F;
int xpAmount = MathHelper.floor((float)baseXP * xpFraction); int xpAmount = MathHelper.floor((float) baseXP * xpFraction);
ExperienceOrbEntity.spawn((ServerWorld)entity.getWorld(), entity.getPos(), xpAmount); ExperienceOrbEntity.spawn((ServerWorld) entity.getWorld(), entity.getPos(), xpAmount);
}
} }
}
// Mark fight as over // Mark fight as over
dragon.getFight().dragonKilled(dragon); dragon.getFight().dragonKilled(dragon);
}
} }
}
// Merchant deals (if friendship changes with a Villager // Merchant deals (if friendship changes with a Villager
if (entity instanceof VillagerEntity && playerData.friendship != new_friendship) { if (entity instanceof VillagerEntity && playerData.friendship != new_friendship) {
VillagerEntityAccessor villager = (VillagerEntityAccessor) entity; VillagerEntityAccessor villager = (VillagerEntityAccessor) entity;
switch (new_friendship) { switch (new_friendship) {
case 3: case 3:
villager.getGossip().startGossip(player.getUuid(), VillageGossipType.MAJOR_POSITIVE, 20); villager.getGossip().startGossip(player.getUuid(), VillageGossipType.MAJOR_POSITIVE, 20);
villager.getGossip().startGossip(player.getUuid(), VillageGossipType.MINOR_POSITIVE, 25); villager.getGossip().startGossip(player.getUuid(), VillageGossipType.MINOR_POSITIVE, 25);
break; break;
case 2: case 2:
villager.getGossip().startGossip(player.getUuid(), VillageGossipType.MINOR_POSITIVE, 25); villager.getGossip().startGossip(player.getUuid(), VillageGossipType.MINOR_POSITIVE, 25);
break; break;
case 1: case 1:
villager.getGossip().startGossip(player.getUuid(), VillageGossipType.MINOR_POSITIVE, 10); villager.getGossip().startGossip(player.getUuid(), VillageGossipType.MINOR_POSITIVE, 10);
break; break;
case -1: case -1:
villager.getGossip().startGossip(player.getUuid(), VillageGossipType.MINOR_NEGATIVE, 10); villager.getGossip().startGossip(player.getUuid(), VillageGossipType.MINOR_NEGATIVE, 10);
break; break;
case -2: case -2:
villager.getGossip().startGossip(player.getUuid(), VillageGossipType.MINOR_NEGATIVE, 25); villager.getGossip().startGossip(player.getUuid(), VillageGossipType.MINOR_NEGATIVE, 25);
break; break;
case -3: case -3:
villager.getGossip().startGossip(player.getUuid(), VillageGossipType.MAJOR_NEGATIVE, 20); villager.getGossip().startGossip(player.getUuid(), VillageGossipType.MAJOR_NEGATIVE, 20);
villager.getGossip().startGossip(player.getUuid(), VillageGossipType.MINOR_NEGATIVE, 25); villager.getGossip().startGossip(player.getUuid(), VillageGossipType.MINOR_NEGATIVE, 25);
break; break;
}
} }
}
// Tame best friends and un-tame worst enemies // Tame best friends and un-tame worst enemies
if (entity instanceof TameableEntity && playerData.friendship != new_friendship) { if (entity instanceof TameableEntity && playerData.friendship != new_friendship) {
TameableEntity tamableEntity = (TameableEntity) entity; TameableEntity tamableEntity = (TameableEntity) entity;
if (new_friendship == 3 && !tamableEntity.isTamed()) { if (new_friendship == 3 && !tamableEntity.isTamed()) {
tamableEntity.setOwner(player); tamableEntity.setOwner(player);
} else if (new_friendship == -3 && tamableEntity.isTamed()) { } else if (new_friendship == -3 && tamableEntity.isTamed()) {
tamableEntity.setTamed(false); tamableEntity.setTamed(false);
tamableEntity.setOwnerUuid(null); tamableEntity.setOwnerUuid(null);
}
} }
}
// Emit friendship particles // Emit friendship particles
if (playerData.friendship != new_friendship) { if (playerData.friendship != new_friendship) {
int friendDiff = new_friendship - playerData.friendship; int friendDiff = new_friendship - playerData.friendship;
if (friendDiff > 0) { if (friendDiff > 0) {
// Heart particles // Heart particles
if (new_friendship == 3) { if (new_friendship == 3) {
ParticleEmitter.emitCreatureParticle((ServerWorld) entity.getWorld(), entity, HEART_BIG_PARTICLE, 0.5, 10); ParticleEmitter.emitCreatureParticle((ServerWorld) entity.getWorld(), entity, HEART_BIG_PARTICLE, 0.5, 10);
} else { } else {
ParticleEmitter.emitCreatureParticle((ServerWorld) entity.getWorld(), entity, HEART_SMALL_PARTICLE, 0.1, 1); ParticleEmitter.emitCreatureParticle((ServerWorld) entity.getWorld(), entity, HEART_SMALL_PARTICLE, 0.1, 1);
} }
} else if (friendDiff < 0) { } else if (friendDiff < 0) {
// Fire particles // Fire particles
if (new_friendship == -3) { if (new_friendship == -3) {
ParticleEmitter.emitCreatureParticle((ServerWorld) entity.getWorld(), entity, FIRE_BIG_PARTICLE, 0.5, 10); ParticleEmitter.emitCreatureParticle((ServerWorld) entity.getWorld(), entity, FIRE_BIG_PARTICLE, 0.5, 10);
} else { } else {
ParticleEmitter.emitCreatureParticle((ServerWorld) entity.getWorld(), entity, FIRE_SMALL_PARTICLE, 0.1, 1); ParticleEmitter.emitCreatureParticle((ServerWorld) entity.getWorld(), entity, FIRE_SMALL_PARTICLE, 0.1, 1);
}
} }
} }
playerData.friendship = new_friendship;
} }
}
playerData.friendship = new_friendship; // Get cleaned message (i.e. no <BEHAVIOR> strings)
String cleanedMessage = result.getCleanedMessage();
if (cleanedMessage.isEmpty()) {
cleanedMessage = Randomizer.getRandomMessage(Randomizer.RandomType.NO_RESPONSE);
} }
}
// Get cleaned message (i.e. no <BEHAVIOR> strings) // Add ASSISTANT message to history
String cleanedMessage = result.getCleanedMessage(); this.addMessage(cleanedMessage, ChatDataManager.ChatSender.ASSISTANT, player, systemPrompt);
if (cleanedMessage.isEmpty()) {
cleanedMessage = Randomizer.getRandomMessage(Randomizer.RandomType.NO_RESPONSE);
}
// Add ASSISTANT message to history // Update the last entry in previousMessages to use the original message
this.addMessage(cleanedMessage, ChatDataManager.ChatSender.ASSISTANT, player, systemPrompt); this.previousMessages.set(this.previousMessages.size() - 1,
new ChatMessage(result.getOriginalMessage(), ChatDataManager.ChatSender.ASSISTANT, player.getDisplayName().getString()));
// Update the last entry in previousMessages to use the original message } else {
this.previousMessages.set(this.previousMessages.size() - 1, // No valid LLM response
new ChatMessage(result.getOriginalMessage(), ChatDataManager.ChatSender.ASSISTANT, player.getDisplayName().getString())); throw new RuntimeException(ChatGPTRequest.lastErrorMessage);
}
} catch (Exception e) {
// Log the exception for debugging
LOGGER.error("Error processing LLM response", e);
} else {
// Error / No Chat Message (Failure) // Error / No Chat Message (Failure)
String randomErrorMessage = Randomizer.getRandomMessage(Randomizer.RandomType.ERROR); String randomErrorMessage = Randomizer.getRandomMessage(Randomizer.RandomType.ERROR);
this.addMessage(randomErrorMessage, ChatDataManager.ChatSender.ASSISTANT, player, systemPrompt); this.addMessage(randomErrorMessage, ChatDataManager.ChatSender.ASSISTANT, player, systemPrompt);
// Determine error message to display // Remove the error message from history to prevent it from affecting future ChatGPT requests
String errorMessage = "Help is available at discord.creaturechat.com"; if (!previousMessages.isEmpty()) {
if (!ChatGPTRequest.lastErrorMessage.isEmpty()) { previousMessages.remove(previousMessages.size() - 1);
errorMessage = "Error: " + truncateString(ChatGPTRequest.lastErrorMessage, 55) + "\n" + errorMessage;
} }
// Send clickable error message // Send clickable error message
ServerPackets.SendClickableError(player, String errorMessage = "Error: ";
errorMessage, "http://discord.creaturechat.com"); if (e.getMessage() != null && !e.getMessage().isEmpty()) {
errorMessage += truncateString(e.getMessage(), 55) + "\n";
// Clear history (if no character sheet was generated)
if (characterSheet.isEmpty()) {
previousMessages.clear();
} }
errorMessage += "Help is available at discord.creaturechat.com";
ServerPackets.SendClickableError(player, errorMessage, "http://discord.creaturechat.com");
} }
}); });
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment