Commit d71248da by Jonathan Thomas

Refactor messages back to a single List<ChatMessage>, but now with a "name"…

Refactor messages back to a single List<ChatMessage>, but now with a "name" attribute based on Player's display name. This will more easily allow for filtering the list of messages by player name, and also allow for more role playing (i.e. changing nick on a server can change your friendship / message history).
parent 7717d5ac
Pipeline #12984 passed with stages
in 2 minutes 0 seconds
...@@ -102,6 +102,7 @@ public class ClientPackets { ...@@ -102,6 +102,7 @@ public class ClientPackets {
// Read the data from the server packet // Read the data from the server packet
UUID entityId = UUID.fromString(buffer.readString()); UUID entityId = UUID.fromString(buffer.readString());
UUID playerId = UUID.fromString(buffer.readString()); UUID playerId = UUID.fromString(buffer.readString());
String playerName =buffer.readString(32767);
String message = buffer.readString(32767); String message = buffer.readString(32767);
int line = buffer.readInt(); int line = buffer.readInt();
String status_name = buffer.readString(32767); String status_name = buffer.readString(32767);
...@@ -114,13 +115,13 @@ public class ClientPackets { ...@@ -114,13 +115,13 @@ public class ClientPackets {
if (entity != null) { if (entity != null) {
ChatDataManager chatDataManager = ChatDataManager.getClientInstance(); ChatDataManager chatDataManager = ChatDataManager.getClientInstance();
EntityChatData chatData = chatDataManager.getOrCreateChatData(entity.getUuidAsString(), playerId.toString()); EntityChatData chatData = chatDataManager.getOrCreateChatData(entity.getUuidAsString(), playerId.toString());
PlayerData playerData = chatData.getPlayerData(playerId.toString());
if (!message.isEmpty()) { if (!message.isEmpty()) {
chatData.currentMessage = message; chatData.currentMessage = message;
} }
chatData.currentLineNumber = line; chatData.currentLineNumber = line;
chatData.status = ChatDataManager.ChatStatus.valueOf(status_name); chatData.status = ChatDataManager.ChatStatus.valueOf(status_name);
chatData.sender = ChatDataManager.ChatSender.valueOf(sender_name); chatData.sender = ChatDataManager.ChatSender.valueOf(sender_name);
PlayerData playerData = chatData.getPlayerData(playerName);
playerData.friendship = friendship; playerData.friendship = friendship;
if (chatData.sender == ChatDataManager.ChatSender.USER) { if (chatData.sender == ChatDataManager.ChatSender.USER) {
......
...@@ -480,7 +480,7 @@ public class BubbleRenderer { ...@@ -480,7 +480,7 @@ public class BubbleRenderer {
PlayerData playerData = null; PlayerData playerData = null;
if (entity instanceof MobEntity) { if (entity instanceof MobEntity) {
chatData = ChatDataManager.getClientInstance().getOrCreateChatData(entity.getUuidAsString(), player.getUuidAsString()); chatData = ChatDataManager.getClientInstance().getOrCreateChatData(entity.getUuidAsString(), player.getUuidAsString());
playerData = chatData.getPlayerData(player.getUuidAsString()); playerData = chatData.getPlayerData(player.getDisplayName().getString());
} else if (entity instanceof PlayerEntity) { } else if (entity instanceof PlayerEntity) {
chatData = PlayerMessageManager.getMessage(entity.getUuid()); chatData = PlayerMessageManager.getMessage(entity.getUuid());
} }
......
...@@ -93,11 +93,11 @@ public class ChatDataManager { ...@@ -93,11 +93,11 @@ public class ChatDataManager {
} }
// Save chat data to file // Save chat data to file
public String GetLightChatData(UUID playerId) { public String GetLightChatData(String playerName) {
try { try {
// Create "light" version of entire chat data HashMap // Create "light" version of entire chat data HashMap
HashMap<String, EntityChatDataLight> lightVersionMap = new HashMap<>(); HashMap<String, EntityChatDataLight> lightVersionMap = new HashMap<>();
this.entityChatDataMap.forEach((id, entityChatData) -> lightVersionMap.put(id, entityChatData.toLightVersion(playerId))); this.entityChatDataMap.forEach((name, entityChatData) -> lightVersionMap.put(name, entityChatData.toLightVersion(playerName)));
return GSON.toJson(lightVersionMap); return GSON.toJson(lightVersionMap);
} catch (Exception e) { } catch (Exception e) {
// Handle exceptions // Handle exceptions
......
...@@ -5,12 +5,14 @@ package com.owlmaddie.chat; ...@@ -5,12 +5,14 @@ package com.owlmaddie.chat;
*/ */
public class ChatMessage { public class ChatMessage {
public String message; public String message;
public String name;
public ChatDataManager.ChatSender sender; public ChatDataManager.ChatSender sender;
public Long timestamp; public Long timestamp;
public ChatMessage(String message, ChatDataManager.ChatSender sender) { public ChatMessage(String message, ChatDataManager.ChatSender sender, String playerName) {
this.message = message; this.message = message;
this.sender = sender; this.sender = sender;
this.name = playerName;
this.timestamp = System.currentTimeMillis(); this.timestamp = System.currentTimeMillis();
} }
} }
\ No newline at end of file
...@@ -50,15 +50,12 @@ public class EntityChatData { ...@@ -50,15 +50,12 @@ public class EntityChatData {
public String characterSheet; public String characterSheet;
public ChatDataManager.ChatSender sender; public ChatDataManager.ChatSender sender;
public int auto_generated; public int auto_generated;
public List<ChatMessage> previousMessages;
@SerializedName("playerId") @SerializedName("playerId")
@Expose(serialize = false) @Expose(serialize = false)
private String legacyPlayerId; private String legacyPlayerId;
@SerializedName("previousMessages")
@Expose(serialize = false)
public List<ChatMessage> legacyMessages;
@SerializedName("friendship") @SerializedName("friendship")
@Expose(serialize = false) @Expose(serialize = false)
public Integer legacyFriendship; public Integer legacyFriendship;
...@@ -78,9 +75,10 @@ public class EntityChatData { ...@@ -78,9 +75,10 @@ public class EntityChatData {
this.status = ChatDataManager.ChatStatus.NONE; this.status = ChatDataManager.ChatStatus.NONE;
this.sender = ChatDataManager.ChatSender.USER; this.sender = ChatDataManager.ChatSender.USER;
this.auto_generated = 0; this.auto_generated = 0;
this.previousMessages = new ArrayList<>();
// Old, unused migrated properties
this.legacyPlayerId = null; this.legacyPlayerId = null;
this.legacyMessages = null;
this.legacyFriendship = null; this.legacyFriendship = null;
} }
...@@ -99,22 +97,23 @@ public class EntityChatData { ...@@ -99,22 +97,23 @@ public class EntityChatData {
// Ensure the blank player data entry exists // Ensure the blank player data entry exists
PlayerData blankPlayerData = this.players.computeIfAbsent("", k -> new PlayerData()); PlayerData blankPlayerData = this.players.computeIfAbsent("", k -> new PlayerData());
// Migrate the old data to the blank player and assign timestamps if missing // Update the previousMessages arraylist and add timestamps if missing
if (this.legacyMessages != null) { if (this.previousMessages != null) {
this.legacyMessages.forEach(message -> message.timestamp = for (ChatMessage message : this.previousMessages) {
message.timestamp != null ? message.timestamp : System.currentTimeMillis()); if (message.timestamp == null) {
blankPlayerData.messages.addAll(this.legacyMessages); message.timestamp = System.currentTimeMillis();
}
}
} }
blankPlayerData.friendship = this.legacyFriendship; blankPlayerData.friendship = this.legacyFriendship;
// Clean up old player data // Clean up old player data
this.legacyPlayerId = null; this.legacyPlayerId = null;
this.legacyMessages = null;
this.legacyFriendship = null; this.legacyFriendship = null;
} }
// Get the player data (or fallback to the blank player) // Get the player data (or fallback to the blank player)
public PlayerData getPlayerData(String playerId) { public PlayerData getPlayerData(String playerName) {
if (this.players == null) { if (this.players == null) {
return new PlayerData(); return new PlayerData();
} }
...@@ -124,21 +123,29 @@ public class EntityChatData { ...@@ -124,21 +123,29 @@ public class EntityChatData {
// If a blank migrated legacy entity is found, always return this // If a blank migrated legacy entity is found, always return this
return this.players.get(""); return this.players.get("");
} else if (this.players.containsKey(playerId)) { } else if (this.players.containsKey(playerName)) {
// Return a specific player's data // Return a specific player's data
return this.players.get(playerId); return this.players.get(playerName);
} else { } else {
// Return a blank player data // Return a blank player data
PlayerData newPlayerData = new PlayerData(); PlayerData newPlayerData = new PlayerData();
this.players.put(playerId, newPlayerData); this.players.put(playerName, newPlayerData);
return newPlayerData; return newPlayerData;
} }
} }
// Get a filtered list of ChatMessages by a particular name (plus any messages with null or empty names)
// For example, if chat data is migrated before 'name' was stored, we want those message to be visible by everyone.
public ArrayList<ChatMessage> getMessagesByName(String playerName) {
return this.previousMessages.stream()
.filter(message -> message.name == null || message.name.isEmpty() || message.name.equals(playerName))
.collect(Collectors.toCollection(ArrayList::new));
}
// Generate light version of chat data (no previous messages) // Generate light version of chat data (no previous messages)
public EntityChatDataLight toLightVersion(UUID playerId) { public EntityChatDataLight toLightVersion(String playerName) {
return new EntityChatDataLight(this, playerId); return new EntityChatDataLight(this, playerName);
} }
public String getCharacterProp(String propertyName) { public String getCharacterProp(String propertyName) {
...@@ -225,7 +232,7 @@ public class EntityChatData { ...@@ -225,7 +232,7 @@ public class EntityChatData {
contextData.put("entity_skills", getCharacterProp("Skills")); contextData.put("entity_skills", getCharacterProp("Skills"));
contextData.put("entity_background", getCharacterProp("Background")); contextData.put("entity_background", getCharacterProp("Background"));
PlayerData playerData = this.getPlayerData(player.getUuidAsString()); PlayerData playerData = this.getPlayerData(player.getDisplayName().getString());
if (playerData != null) { if (playerData != null) {
contextData.put("entity_friendship", String.valueOf(playerData.friendship)); contextData.put("entity_friendship", String.valueOf(playerData.friendship));
} else { } else {
...@@ -247,7 +254,7 @@ public class EntityChatData { ...@@ -247,7 +254,7 @@ public class EntityChatData {
} }
// Add message // Add message
this.addMessage(userMessage, ChatDataManager.ChatSender.USER, player.getUuid()); this.addMessage(userMessage, ChatDataManager.ChatSender.USER, player.getDisplayName().getString());
// Add PLAYER context information // Add PLAYER context information
Map<String, String> contextData = getPlayerContext(player, userLanguage); Map<String, String> contextData = getPlayerContext(player, userLanguage);
...@@ -256,24 +263,27 @@ public class EntityChatData { ...@@ -256,24 +263,27 @@ public class EntityChatData {
ConfigurationHandler.Config config = new ConfigurationHandler(ServerPackets.serverInstance).loadConfig(); ConfigurationHandler.Config config = new ConfigurationHandler(ServerPackets.serverInstance).loadConfig();
String promptText = ChatPrompt.loadPromptFromResource(ServerPackets.serverInstance.getResourceManager(), systemPrompt); String promptText = ChatPrompt.loadPromptFromResource(ServerPackets.serverInstance.getResourceManager(), systemPrompt);
// Get all message (filtered by player)
List<ChatMessage> playerMessages = getMessagesByName(player.getDisplayName().getString());
// Get messages for player // Get messages for player
PlayerData playerData = this.getPlayerData(player.getUuidAsString()); PlayerData playerData = this.getPlayerData(player.getDisplayName().getString());
if (playerData.messages.size() == 1 && systemPrompt.equals("system-chat")) { if (playerMessages.size() == 1 && systemPrompt.equals("system-chat")) {
// No messages exist yet for this player (start with normal greeting) // No messages exist yet for this player (start with normal greeting)
String shortGreeting = Optional.ofNullable(getCharacterProp("short greeting")).filter(s -> !s.isEmpty()).orElse(Randomizer.getRandomMessage(Randomizer.RandomType.NO_RESPONSE)).replace("\n", " "); String shortGreeting = Optional.ofNullable(getCharacterProp("short greeting")).filter(s -> !s.isEmpty()).orElse(Randomizer.getRandomMessage(Randomizer.RandomType.NO_RESPONSE)).replace("\n", " ");
playerData.messages.add(0, new ChatMessage(shortGreeting, ChatDataManager.ChatSender.ASSISTANT)); previousMessages.add(0, new ChatMessage(shortGreeting, ChatDataManager.ChatSender.ASSISTANT, player.getDisplayName().getString()));
} }
// fetch HTTP response from ChatGPT // fetch HTTP response from ChatGPT
ChatGPTRequest.fetchMessageFromChatGPT(config, promptText, contextData, playerData.messages, false).thenAccept(output_message -> { ChatGPTRequest.fetchMessageFromChatGPT(config, promptText, contextData, playerMessages, false).thenAccept(output_message -> {
if (output_message != null && systemPrompt.equals("system-character")) { if (output_message != null && systemPrompt.equals("system-character")) {
// Character Sheet: Remove system-character message from previous messages // Character Sheet: Remove system-character message from previous messages
playerData.messages.clear(); previousMessages.clear();
// Add NEW CHARACTER sheet & greeting // Add NEW CHARACTER sheet & greeting
this.characterSheet = output_message; this.characterSheet = output_message;
String shortGreeting = Optional.ofNullable(getCharacterProp("short greeting")).filter(s -> !s.isEmpty()).orElse(Randomizer.getRandomMessage(Randomizer.RandomType.NO_RESPONSE)).replace("\n", " "); 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.getUuid()); this.addMessage(shortGreeting, ChatDataManager.ChatSender.ASSISTANT, player.getDisplayName().getString());
} else if (output_message != null && systemPrompt.equals("system-chat")) { } else if (output_message != null && systemPrompt.equals("system-chat")) {
// Chat Message: Parse message for behaviors // Chat Message: Parse message for behaviors
...@@ -463,7 +473,7 @@ public class EntityChatData { ...@@ -463,7 +473,7 @@ public class EntityChatData {
} }
// Add ASSISTANT message to history // Add ASSISTANT message to history
this.addMessage(result.getOriginalMessage(), ChatDataManager.ChatSender.ASSISTANT, player.getUuid()); this.addMessage(result.getOriginalMessage(), ChatDataManager.ChatSender.ASSISTANT, player.getDisplayName().getString());
// Get cleaned message (i.e. no <BEHAVIOR> strings) // Get cleaned message (i.e. no <BEHAVIOR> strings)
String cleanedMessage = result.getCleanedMessage(); String cleanedMessage = result.getCleanedMessage();
...@@ -476,7 +486,7 @@ public class EntityChatData { ...@@ -476,7 +486,7 @@ public class EntityChatData {
} else { } 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.getUuid()); this.addMessage(randomErrorMessage, ChatDataManager.ChatSender.ASSISTANT, player.getDisplayName().getString());
// Determine error message to display // Determine error message to display
String errorMessage = "Help is available at discord.creaturechat.com"; String errorMessage = "Help is available at discord.creaturechat.com";
...@@ -490,7 +500,7 @@ public class EntityChatData { ...@@ -490,7 +500,7 @@ public class EntityChatData {
// Clear history (if no character sheet was generated) // Clear history (if no character sheet was generated)
if (characterSheet.isEmpty()) { if (characterSheet.isEmpty()) {
playerData.messages.clear(); previousMessages.clear();
} }
} }
...@@ -504,15 +514,12 @@ public class EntityChatData { ...@@ -504,15 +514,12 @@ public class EntityChatData {
} }
// Add a message to the history and update the current message // Add a message to the history and update the current message
public void addMessage(String message, ChatDataManager.ChatSender messageSender, UUID playerId) { public void addMessage(String message, ChatDataManager.ChatSender messageSender, String playerName) {
// Truncate message (prevent crazy long messages... just in case) // Truncate message (prevent crazy long messages... just in case)
String truncatedMessage = message.substring(0, Math.min(message.length(), ChatDataManager.MAX_CHAR_IN_USER_MESSAGE)); String truncatedMessage = message.substring(0, Math.min(message.length(), ChatDataManager.MAX_CHAR_IN_USER_MESSAGE));
// Get or create player data
PlayerData playerData = getPlayerData(playerId.toString());
// Add message to history // Add message to history
playerData.messages.add(new ChatMessage(truncatedMessage, messageSender)); previousMessages.add(new ChatMessage(truncatedMessage, messageSender, playerName));
// Set new message and reset line number of displayed text // Set new message and reset line number of displayed text
currentMessage = truncatedMessage; currentMessage = truncatedMessage;
......
...@@ -18,7 +18,7 @@ public class EntityChatDataLight { ...@@ -18,7 +18,7 @@ public class EntityChatDataLight {
public Map<String, PlayerData> players; public Map<String, PlayerData> players;
// Constructor to initialize the light version from the full version // Constructor to initialize the light version from the full version
public EntityChatDataLight(EntityChatData fullData, UUID playerId) { public EntityChatDataLight(EntityChatData fullData, String playerName) {
this.entityId = fullData.entityId; this.entityId = fullData.entityId;
this.currentMessage = fullData.currentMessage; this.currentMessage = fullData.currentMessage;
this.currentLineNumber = fullData.currentLineNumber; this.currentLineNumber = fullData.currentLineNumber;
...@@ -27,8 +27,7 @@ public class EntityChatDataLight { ...@@ -27,8 +27,7 @@ public class EntityChatDataLight {
// Initialize the players map and add only the current player's data // Initialize the players map and add only the current player's data
this.players = new HashMap<>(); this.players = new HashMap<>();
String playerIdStr = playerId.toString(); PlayerData playerData = fullData.getPlayerData(playerName);
PlayerData playerData = fullData.getPlayerData(playerId.toString()); this.players.put(playerName, playerData);
this.players.put(playerIdStr, playerData);
} }
} }
\ No newline at end of file
package com.owlmaddie.chat; package com.owlmaddie.chat;
import java.util.ArrayList;
import java.util.List;
public class PlayerData { public class PlayerData {
public List<ChatMessage> messages;
public int friendship; public int friendship;
public PlayerData() { public PlayerData() {
this.messages = new ArrayList<>();
this.friendship = 0; this.friendship = 0;
} }
} }
\ No newline at end of file
...@@ -33,7 +33,7 @@ public class MixinLivingEntity { ...@@ -33,7 +33,7 @@ public class MixinLivingEntity {
if (target instanceof PlayerEntity) { if (target instanceof PlayerEntity) {
LivingEntity thisEntity = (LivingEntity) (Object) this; LivingEntity thisEntity = (LivingEntity) (Object) this;
EntityChatData entityData = getChatData(thisEntity, (PlayerEntity) target); EntityChatData entityData = getChatData(thisEntity, (PlayerEntity) target);
PlayerData playerData = entityData.getPlayerData(target.getUuidAsString()); PlayerData playerData = entityData.getPlayerData(target.getDisplayName().getString());
if (playerData.friendship > 0) { if (playerData.friendship > 0) {
// Friendly creatures can't target a player // Friendly creatures can't target a player
cir.setReturnValue(false); cir.setReturnValue(false);
......
...@@ -55,7 +55,7 @@ public class MixinMobEntity { ...@@ -55,7 +55,7 @@ public class MixinMobEntity {
// Get chat data for entity // Get chat data for entity
ChatDataManager chatDataManager = ChatDataManager.getServerInstance(); ChatDataManager chatDataManager = ChatDataManager.getServerInstance();
EntityChatData entityData = chatDataManager.getOrCreateChatData(thisEntity.getUuidAsString(), player.getUuidAsString()); EntityChatData entityData = chatDataManager.getOrCreateChatData(thisEntity.getUuidAsString(), player.getUuidAsString());
PlayerData playerData = entityData.getPlayerData(player.getUuidAsString()); PlayerData playerData = entityData.getPlayerData(player.getDisplayName().getString());
// Check if the player successfully interacts with an item // Check if the player successfully interacts with an item
if (player instanceof ServerPlayerEntity) { if (player instanceof ServerPlayerEntity) {
......
...@@ -198,7 +198,7 @@ public class ServerPackets { ...@@ -198,7 +198,7 @@ public class ServerPackets {
LOGGER.info("Server send compressed, chunked login message packets to player: " + player.getName().getString()); LOGGER.info("Server send compressed, chunked login message packets to player: " + player.getName().getString());
// Get lite JSON data & compress to byte array // Get lite JSON data & compress to byte array
String chatDataJSON = ChatDataManager.getServerInstance().GetLightChatData(player.getUuid()); String chatDataJSON = ChatDataManager.getServerInstance().GetLightChatData(player.getDisplayName().getString());
byte[] compressedData = Compression.compressString(chatDataJSON); byte[] compressedData = Compression.compressString(chatDataJSON);
if (compressedData == null) { if (compressedData == null) {
LOGGER.error("Failed to compress chat data."); LOGGER.error("Failed to compress chat data.");
...@@ -346,12 +346,13 @@ public class ServerPackets { ...@@ -346,12 +346,13 @@ public class ServerPackets {
// Iterate over all players and send the packet // Iterate over all players and send the packet
for (ServerPlayerEntity player : serverInstance.getPlayerManager().getPlayerList()) { for (ServerPlayerEntity player : serverInstance.getPlayerManager().getPlayerList()) {
PlayerData playerData = chatData.getPlayerData(player.getUuidAsString()); PlayerData playerData = chatData.getPlayerData(player.getDisplayName().getString());
PacketByteBuf buffer = new PacketByteBuf(Unpooled.buffer()); PacketByteBuf buffer = new PacketByteBuf(Unpooled.buffer());
// Write the entity's chat updated data // Write the entity's chat updated data
buffer.writeString(chatData.entityId); buffer.writeString(chatData.entityId);
buffer.writeString(player.getUuidAsString()); buffer.writeString(player.getUuidAsString());
buffer.writeString(player.getDisplayName().getString());
buffer.writeString(chatData.currentMessage); buffer.writeString(chatData.currentMessage);
buffer.writeInt(chatData.currentLineNumber); buffer.writeInt(chatData.currentLineNumber);
buffer.writeString(chatData.status.toString()); buffer.writeString(chatData.status.toString());
......
...@@ -203,7 +203,7 @@ public class BehaviorTests { ...@@ -203,7 +203,7 @@ public class BehaviorTests {
// Add test message // Add test message
for (String message : messages) { for (String message : messages) {
entityTestData.addMessage(message, ChatDataManager.ChatSender.USER); entityTestData.addMessage(message, ChatDataManager.ChatSender.USER, "TestPlayer1");
} }
// Get prompt // Get prompt
......
...@@ -60,12 +60,12 @@ public class EntityTestData { ...@@ -60,12 +60,12 @@ public class EntityTestData {
} }
// Add a message to the history and update the current message // Add a message to the history and update the current message
public void addMessage(String message, ChatDataManager.ChatSender messageSender) { public void addMessage(String message, ChatDataManager.ChatSender messageSender, String playerName) {
// Truncate message (prevent crazy long messages... just in case) // Truncate message (prevent crazy long messages... just in case)
String truncatedMessage = message.substring(0, Math.min(message.length(), ChatDataManager.MAX_CHAR_IN_USER_MESSAGE)); String truncatedMessage = message.substring(0, Math.min(message.length(), ChatDataManager.MAX_CHAR_IN_USER_MESSAGE));
// Add message to history // Add message to history
previousMessages.add(new ChatMessage(truncatedMessage, messageSender)); previousMessages.add(new ChatMessage(truncatedMessage, messageSender, playerName));
// Set new message and reset line number of displayed text // Set new message and reset line number of displayed text
currentMessage = truncatedMessage; currentMessage = truncatedMessage;
......
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