Commit 9dbe4702 by Jonathan Thomas

- Render other player messages above their heads (skips own player)

- Added player face to player chat bubbles
- Added placeholder player text-top UI graphic (no friendship)
- Reduced ticks visible per page of player messages
- Changed PlayerMessage to extend EntityChatData, for simplicity
parent 53000c90
Pipeline #11993 passed with stage
in 20 seconds
...@@ -42,7 +42,7 @@ public class BubbleRenderer { ...@@ -42,7 +42,7 @@ public class BubbleRenderer {
public static int animationFrame = 0; public static int animationFrame = 0;
public static long lastTick = 0; public static long lastTick = 0;
public static void drawTextBubbleBackground(MatrixStack matrices, float x, float y, float width, float height, int friendship) { public static void drawTextBubbleBackground(String base_name, MatrixStack matrices, float x, float y, float width, float height, int friendship) {
RenderSystem.enableDepthTest(); RenderSystem.enableDepthTest();
RenderSystem.enableBlend(); RenderSystem.enableBlend();
RenderSystem.defaultBlendFunc(); RenderSystem.defaultBlendFunc();
...@@ -54,11 +54,11 @@ public class BubbleRenderer { ...@@ -54,11 +54,11 @@ public class BubbleRenderer {
// Draw UI text background (based on friendship) // Draw UI text background (based on friendship)
if (friendship == -3) { if (friendship == -3) {
RenderSystem.setShaderTexture(0, textures.GetUI("text-top-enemy")); RenderSystem.setShaderTexture(0, textures.GetUI(base_name + "-enemy"));
} else if (friendship == 3) { } else if (friendship == 3) {
RenderSystem.setShaderTexture(0, textures.GetUI("text-top-friend")); RenderSystem.setShaderTexture(0, textures.GetUI(base_name + "-friend"));
} else { } else {
RenderSystem.setShaderTexture(0, textures.GetUI("text-top")); RenderSystem.setShaderTexture(0, textures.GetUI(base_name));
} }
drawTexturePart(matrices, buffer, x - 50, y, z, 228, 40); drawTexturePart(matrices, buffer, x - 50, y, z, 228, 40);
...@@ -164,6 +164,40 @@ public class BubbleRenderer { ...@@ -164,6 +164,40 @@ public class BubbleRenderer {
RenderSystem.disableDepthTest(); RenderSystem.disableDepthTest();
} }
private static void drawPlayerIcon(MatrixStack matrices, Entity entity, float x, float y, float width, float height) {
// Get player skin texture
EntityRenderer renderer = EntityRendererAccessor.getEntityRenderer(entity);
Identifier playerTexture = renderer.getTexture(entity);
RenderSystem.setShaderTexture(0, playerTexture);
RenderSystem.enableDepthTest();
RenderSystem.enableBlend();
RenderSystem.defaultBlendFunc();
RenderSystem.setShader(GameRenderer::getPositionTexProgram);
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder bufferBuilder = tessellator.getBuffer();
bufferBuilder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE);
// Texture coordinates for the face region (8, 8) to (16, 16) in a 64x64 texture
float textureWidth = 64.0F;
float textureHeight = 64.0F;
float u1 = 8.0F / textureWidth;
float v1 = 8.0F / textureHeight;
float u2 = 16.0F / textureWidth;
float v2 = 16.0F / textureHeight;
float z = -0.01F;
bufferBuilder.vertex(matrices.peek().getPositionMatrix(), x, y + height, z).texture(u1, v2).next(); // bottom left
bufferBuilder.vertex(matrices.peek().getPositionMatrix(), x + width, y + height, z).texture(u2, v2).next(); // bottom right
bufferBuilder.vertex(matrices.peek().getPositionMatrix(), x + width, y, z).texture(u2, v1).next(); // top right
bufferBuilder.vertex(matrices.peek().getPositionMatrix(), x, y, z).texture(u1, v1).next(); // top left
tessellator.draw();
RenderSystem.disableBlend();
RenderSystem.disableDepthTest();
}
private static void drawMessageText(Matrix4f matrix, List<String> lines, int starting_line, int ending_line, private static void drawMessageText(Matrix4f matrix, List<String> lines, int starting_line, int ending_line,
VertexConsumerProvider immediate, float lineSpacing, int fullBright, float yOffset) { VertexConsumerProvider immediate, float lineSpacing, int fullBright, float yOffset) {
TextRenderer fontRenderer = MinecraftClient.getInstance().textRenderer; TextRenderer fontRenderer = MinecraftClient.getInstance().textRenderer;
...@@ -239,13 +273,21 @@ public class BubbleRenderer { ...@@ -239,13 +273,21 @@ public class BubbleRenderer {
.collect(Collectors.toList()); .collect(Collectors.toList());
for (Entity entity : relevantEntities) { for (Entity entity : relevantEntities) {
if (entity.hasPassengers()) {
// Look-up greeting (if any)
ChatDataManager.EntityChatData chatData = null;
if (entity instanceof MobEntity) {
chatData = ChatDataManager.getClientInstance().getOrCreateChatData(entity.getUuidAsString());
} else if (entity instanceof PlayerEntity) {
chatData = PlayerMessageManager.getMessage(entity.getUuid());
}
// Bail if no chatData found, or if they have passengers
if (chatData == null || entity.hasPassengers()) {
// Skip // Skip
continue; continue;
} }
// Look-up greeting (if any)
ChatDataManager.EntityChatData chatData = ChatDataManager.getClientInstance().getOrCreateChatData(entity.getUuidAsString());
List<String> lines = chatData.getWrappedLines(); List<String> lines = chatData.getWrappedLines();
// Set the range of lines to display // Set the range of lines to display
...@@ -375,7 +417,7 @@ public class BubbleRenderer { ...@@ -375,7 +417,7 @@ public class BubbleRenderer {
} else if (chatData.sender == ChatDataManager.ChatSender.ASSISTANT && chatData.status != ChatDataManager.ChatStatus.HIDDEN) { } else if (chatData.sender == ChatDataManager.ChatSender.ASSISTANT && chatData.status != ChatDataManager.ChatStatus.HIDDEN) {
// Draw text background (no smaller than 50F tall) // Draw text background (no smaller than 50F tall)
drawTextBubbleBackground(matrices, -64, 0, 128, scaledTextHeight, chatData.friendship); drawTextBubbleBackground("text-top", matrices, -64, 0, 128, scaledTextHeight, chatData.friendship);
// Draw face icon of entity // Draw face icon of entity
drawEntityIcon(matrices, entity, -82, 7, 32, 32); drawEntityIcon(matrices, entity, -82, 7, 32, 32);
...@@ -399,6 +441,16 @@ public class BubbleRenderer { ...@@ -399,6 +441,16 @@ public class BubbleRenderer {
} else if (chatData.sender == ChatDataManager.ChatSender.ASSISTANT && chatData.status == ChatDataManager.ChatStatus.HIDDEN) { } else if (chatData.sender == ChatDataManager.ChatSender.ASSISTANT && chatData.status == ChatDataManager.ChatStatus.HIDDEN) {
// Draw 'resume chat' button // Draw 'resume chat' button
drawIcon("button-chat", matrices, -16, textHeaderHeight, 32, 17); drawIcon("button-chat", matrices, -16, textHeaderHeight, 32, 17);
} else if (chatData.sender == ChatDataManager.ChatSender.USER && chatData.status == ChatDataManager.ChatStatus.DISPLAY) {
// Draw text background
drawTextBubbleBackground("text-top-player", matrices, -64, 0, 128, scaledTextHeight, chatData.friendship);
// Draw face icon of player
drawPlayerIcon(matrices, entity, -75, 14, 18, 18);
// Render each line of the player's text
drawMessageText(matrix, lines, starting_line, ending_line, immediate, lineSpacing, fullBright, 40.0F + DISPLAY_PADDING);
} }
// Pop the matrix to return to the original state. // Pop the matrix to return to the original state.
......
...@@ -57,7 +57,7 @@ public class ClickHandler { ...@@ -57,7 +57,7 @@ public class ClickHandler {
ClientPlayNetworking.registerGlobalReceiver(ModInit.PACKET_S2C_MESSAGE, (client, handler, buffer, responseSender) -> { ClientPlayNetworking.registerGlobalReceiver(ModInit.PACKET_S2C_MESSAGE, (client, handler, buffer, responseSender) -> {
// 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()); String playerId = buffer.readString();
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);
...@@ -70,7 +70,7 @@ public class ClickHandler { ...@@ -70,7 +70,7 @@ public class ClickHandler {
if (entity != null) { if (entity != null) {
ChatDataManager chatDataManager = ChatDataManager.getClientInstance(); ChatDataManager chatDataManager = ChatDataManager.getClientInstance();
ChatDataManager.EntityChatData chatData = chatDataManager.getOrCreateChatData(entity.getUuidAsString()); ChatDataManager.EntityChatData chatData = chatDataManager.getOrCreateChatData(entity.getUuidAsString());
chatData.playerId = playerId.toString(); chatData.playerId = playerId;
if (!message.isEmpty()) { if (!message.isEmpty()) {
chatData.currentMessage = message; chatData.currentMessage = message;
} }
...@@ -79,7 +79,7 @@ public class ClickHandler { ...@@ -79,7 +79,7 @@ public class ClickHandler {
chatData.sender = ChatDataManager.ChatSender.valueOf(sender_name); chatData.sender = ChatDataManager.ChatSender.valueOf(sender_name);
chatData.friendship = friendship; chatData.friendship = friendship;
if (chatData.sender == ChatDataManager.ChatSender.USER) { if (chatData.sender == ChatDataManager.ChatSender.USER && !playerId.isEmpty()) {
// Add player message to queue for rendering // Add player message to queue for rendering
PlayerMessageManager.addMessage(UUID.fromString(chatData.playerId), chatData.currentMessage, ChatDataManager.TICKS_TO_DISPLAY_USER_MESSAGE); PlayerMessageManager.addMessage(UUID.fromString(chatData.playerId), chatData.currentMessage, ChatDataManager.TICKS_TO_DISPLAY_USER_MESSAGE);
} }
......
package com.owlmaddie.ui; package com.owlmaddie.ui;
import com.owlmaddie.chat.ChatDataManager; import com.owlmaddie.chat.ChatDataManager;
import com.owlmaddie.chat.LineWrapper;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
/** /**
...@@ -11,24 +8,14 @@ import java.util.concurrent.atomic.AtomicInteger; ...@@ -11,24 +8,14 @@ import java.util.concurrent.atomic.AtomicInteger;
* many ticks to remain visible, and the message to display. Similar to an EntityChatData, but * many ticks to remain visible, and the message to display. Similar to an EntityChatData, but
* much simpler. * much simpler.
*/ */
public class PlayerMessage { public class PlayerMessage extends ChatDataManager.EntityChatData {
public String currentMessage;
public int currentLineNumber;
public AtomicInteger tickCountdown; public AtomicInteger tickCountdown;
public PlayerMessage(String messageText, int ticks) { public PlayerMessage(String playerId, String messageText, int ticks) {
super("", playerId);
this.currentMessage = messageText; this.currentMessage = messageText;
this.currentLineNumber = 0; this.currentLineNumber = 0;
this.tickCountdown = new AtomicInteger(ticks); this.tickCountdown = new AtomicInteger(ticks);
} this.status = ChatDataManager.ChatStatus.DISPLAY;
public List<String> getWrappedLines() {
return LineWrapper.wrapLines(this.currentMessage, ChatDataManager.MAX_CHAR_PER_LINE);
}
public boolean isEndOfMessage() {
int totalLines = this.getWrappedLines().size();
// Check if the current line number plus DISPLAY_NUM_LINES covers or exceeds the total number of lines
return currentLineNumber + ChatDataManager.DISPLAY_NUM_LINES >= totalLines;
} }
} }
\ No newline at end of file
...@@ -12,7 +12,11 @@ public class PlayerMessageManager { ...@@ -12,7 +12,11 @@ public class PlayerMessageManager {
private static final ConcurrentHashMap<UUID, PlayerMessage> messages = new ConcurrentHashMap<>(); private static final ConcurrentHashMap<UUID, PlayerMessage> messages = new ConcurrentHashMap<>();
public static void addMessage(UUID playerUUID, String messageText, int ticks) { public static void addMessage(UUID playerUUID, String messageText, int ticks) {
messages.put(playerUUID, new PlayerMessage(messageText, ticks)); messages.put(playerUUID, new PlayerMessage(playerUUID.toString(), messageText, ticks));
}
public static PlayerMessage getMessage(UUID playerId) {
return messages.get(playerId);
} }
public static void tickUpdate() { public static void tickUpdate() {
......
...@@ -42,7 +42,7 @@ public class ChatDataManager { ...@@ -42,7 +42,7 @@ public class ChatDataManager {
public static int MAX_CHAR_PER_LINE = 20; public static int MAX_CHAR_PER_LINE = 20;
public static int DISPLAY_NUM_LINES = 3; public static int DISPLAY_NUM_LINES = 3;
public static int MAX_CHAR_IN_USER_MESSAGE = 512; public static int MAX_CHAR_IN_USER_MESSAGE = 512;
public static int TICKS_TO_DISPLAY_USER_MESSAGE = 90; public static int TICKS_TO_DISPLAY_USER_MESSAGE = 60;
public QuestJson quest = null; public QuestJson quest = null;
private static final Gson GSON = new Gson(); private static final Gson GSON = new Gson();
...@@ -83,9 +83,9 @@ public class ChatDataManager { ...@@ -83,9 +83,9 @@ public class ChatDataManager {
public ChatSender sender; public ChatSender sender;
public int friendship; // -3 to 3 (0 = neutral) public int friendship; // -3 to 3 (0 = neutral)
public EntityChatData(String entityId) { public EntityChatData(String entityId, String playerId) {
this.entityId = entityId; this.entityId = entityId;
this.playerId = null; this.playerId = playerId;
this.currentMessage = ""; this.currentMessage = "";
this.currentLineNumber = 0; this.currentLineNumber = 0;
this.previousMessages = new ArrayList<>(); this.previousMessages = new ArrayList<>();
...@@ -200,7 +200,12 @@ public class ChatDataManager { ...@@ -200,7 +200,12 @@ public class ChatDataManager {
public void generateMessage(ServerPlayerEntity player, String systemPrompt, String userMessage) { public void generateMessage(ServerPlayerEntity player, String systemPrompt, String userMessage) {
this.status = ChatStatus.PENDING; this.status = ChatStatus.PENDING;
// Add USER Message // Add USER Message
if (systemPrompt == "system-character") {
// Add message without playerId (so it does not display)
this.addMessage(userMessage, ChatSender.USER, "");
} else if (systemPrompt == "system-chat") {
this.addMessage(userMessage, ChatSender.USER, player.getUuidAsString()); this.addMessage(userMessage, ChatSender.USER, player.getUuidAsString());
}
// Add PLAYER context information // Add PLAYER context information
Map<String, String> contextData = getPlayerContext(player); Map<String, String> contextData = getPlayerContext(player);
...@@ -383,7 +388,7 @@ public class ChatDataManager { ...@@ -383,7 +388,7 @@ public class ChatDataManager {
// Retrieve chat data for a specific entity, or create it if it doesn't exist // Retrieve chat data for a specific entity, or create it if it doesn't exist
public EntityChatData getOrCreateChatData(String entityId) { public EntityChatData getOrCreateChatData(String entityId) {
return entityChatDataMap.computeIfAbsent(entityId, k -> new EntityChatData(entityId)); return entityChatDataMap.computeIfAbsent(entityId, k -> new EntityChatData(entityId, ""));
} }
// Generate quest data for this server session // Generate quest data for this server session
......
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