Commit 52db426e by Jonathan Thomas

Merge branch 'bug-fixes-death-messages' into 'develop'

1.2.1 Release

See merge request !22
parents 3c44ed5f a609de8c
Pipeline #13238 passed with stages
in 2 minutes 57 seconds
......@@ -4,11 +4,18 @@ All notable changes to **CreatureChat** are documented in this file. The format
[Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Unreleased
## [1.2.1] - 2025-01-01
### Changed
- Refactor of EntityChatData constructor (no need for playerName anymore)
- Improved LLM / AI Options in README.md (to more clearly separate free and paid options)
### Fixed
- Fixed a bug which broadcasts too many death messages (any mob with a custom name). Now it must also have a character sheet.
- Prevent crash due to missing texture when max friend/enemy + right click on entity
- Fixed bug which caused a max friend to interact with both off hand + main hand, causing both a message + riding (only check main hand now)
- Hide auto-generated messages from briefly appearing from the mob (i.e. interact, show, attack, arrival)
## [1.2.0] - 2024-12-28
### Added
......
......@@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx1G
org.gradle.parallel=true
# Mod Properties
mod_version=1.2.0
mod_version=1.2.1
maven_group=com.owlmaddie
archives_base_name=creaturechat
......
......@@ -143,9 +143,8 @@ public class ClientPackets {
}
// Get entity chat data for current entity & player
String currentPlayerName = client.player.getDisplayName().getString();
ChatDataManager chatDataManager = ChatDataManager.getClientInstance();
EntityChatData chatData = chatDataManager.getOrCreateChatData(entity.getUuidAsString(), currentPlayerName);
EntityChatData chatData = chatDataManager.getOrCreateChatData(entity.getUuidAsString());
if (senderPlayerId != null && sender == ChatDataManager.ChatSender.USER && status == ChatDataManager.ChatStatus.DISPLAY) {
// Add player message to queue for rendering
......@@ -160,7 +159,7 @@ public class ClientPackets {
chatData.currentLineNumber = line;
chatData.status = status;
chatData.sender = sender;
chatData.players = players; // friendships
chatData.players = players;
}
// Play sound with volume based on distance (from player or entity)
......
......@@ -70,9 +70,9 @@ public class BubbleRenderer {
// Draw UI text background (based on friendship)
// Draw TOP
if (friendship == -3) {
if (friendship == -3 && !base_name.endsWith("-player")) {
RenderSystem.setShaderTexture(0, textures.GetUI(base_name + "-enemy"));
} else if (friendship == 3) {
} else if (friendship == 3 && !base_name.endsWith("-player")) {
RenderSystem.setShaderTexture(0, textures.GetUI(base_name + "-friend"));
} else {
RenderSystem.setShaderTexture(0, textures.GetUI(base_name));
......@@ -479,7 +479,7 @@ public class BubbleRenderer {
EntityChatData chatData = null;
PlayerData playerData = null;
if (entity instanceof MobEntity) {
chatData = ChatDataManager.getClientInstance().getOrCreateChatData(entity.getUuidAsString(), player.getDisplayName().getString());
chatData = ChatDataManager.getClientInstance().getOrCreateChatData(entity.getUuidAsString());
if (chatData != null) {
playerData = chatData.getPlayerData(player.getDisplayName().getString());
}
......
......@@ -120,7 +120,7 @@ public class ClickHandler {
MobEntity closestEntity = ClientEntityFinder.getEntityByUUID(client.world, closestEntityUUID);
if (closestEntity != null) {
// Look-up conversation
EntityChatData chatData = ChatDataManager.getClientInstance().getOrCreateChatData(closestEntityUUID.toString(), player.getDisplayName().getString());
EntityChatData chatData = ChatDataManager.getClientInstance().getOrCreateChatData(closestEntityUUID.toString());
// Determine area clicked inside chat bubble (top, left, right)
String hitRegion = determineHitRegion(closestHitResult.get(), closestBubbleData.position, camera, closestBubbleData.height);
......
......@@ -13,8 +13,8 @@ import java.util.concurrent.atomic.AtomicInteger;
public class PlayerMessage extends EntityChatData {
public AtomicInteger tickCountdown;
public PlayerMessage(String playerId, String playerName, String messageText, int ticks) {
super(playerId, playerName);
public PlayerMessage(String playerId, String messageText, int ticks) {
super(playerId);
this.currentMessage = messageText;
this.currentLineNumber = 0;
this.tickCountdown = new AtomicInteger(ticks);
......
......@@ -13,7 +13,7 @@ public class PlayerMessageManager {
private static final ConcurrentHashMap<UUID, Boolean> openChatUIs = new ConcurrentHashMap<>();
public static void addMessage(UUID playerUUID, String messageText, String playerName, int ticks) {
messages.put(playerUUID, new PlayerMessage(playerUUID.toString(), playerName, messageText, ticks));
messages.put(playerUUID, new PlayerMessage(playerUUID.toString(), messageText, ticks));
}
public static PlayerMessage getMessage(UUID playerId) {
......
......@@ -72,8 +72,8 @@ public class ChatDataManager {
}
// Retrieve chat data for a specific entity, or create it if it doesn't exist
public EntityChatData getOrCreateChatData(String entityId, String playerName) {
return entityChatDataMap.computeIfAbsent(entityId, k -> new EntityChatData(entityId, playerName));
public EntityChatData getOrCreateChatData(String entityId) {
return entityChatDataMap.computeIfAbsent(entityId, k -> new EntityChatData(entityId));
}
// Update the UUID in the map (i.e. bucketed entity and then released, changes their UUID)
......
......@@ -65,12 +65,9 @@ public class EntityChatData {
// The map to store data for each player interacting with this entity
public Map<String, PlayerData> players;
public EntityChatData(String entityId, String playerName) {
public EntityChatData(String entityId) {
this.entityId = entityId;
this.players = new HashMap<>();
if (!playerName.isEmpty()) {
this.players.put(playerName, new PlayerData());
}
this.currentMessage = "";
this.currentLineNumber = 0;
this.characterSheet = "";
......
......@@ -71,7 +71,7 @@ public class LeadPlayerGoal extends PlayerBaseGoal {
String arrivedMessage = "<You have arrived at your destination>";
ChatDataManager chatDataManager = ChatDataManager.getServerInstance();
EntityChatData chatData = chatDataManager.getOrCreateChatData(this.entity.getUuidAsString(), this.targetEntity.getDisplayName().getString());
EntityChatData chatData = chatDataManager.getOrCreateChatData(this.entity.getUuidAsString());
if (!chatData.characterSheet.isEmpty() && chatData.auto_generated < chatDataManager.MAX_AUTOGENERATE_RESPONSES) {
ServerPackets.generate_chat("N/A", chatData, (ServerPlayerEntity) this.targetEntity, this.entity, arrivedMessage, true);
}
......
......@@ -28,16 +28,16 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(LivingEntity.class)
public class MixinLivingEntity {
private EntityChatData getChatData(LivingEntity entity, PlayerEntity player) {
private EntityChatData getChatData(LivingEntity entity) {
ChatDataManager chatDataManager = ChatDataManager.getServerInstance();
return chatDataManager.getOrCreateChatData(entity.getUuidAsString(), player.getDisplayName().getString());
return chatDataManager.getOrCreateChatData(entity.getUuidAsString());
}
@Inject(method = "canTarget(Lnet/minecraft/entity/LivingEntity;)Z", at = @At("HEAD"), cancellable = true)
private void modifyCanTarget(LivingEntity target, CallbackInfoReturnable<Boolean> cir) {
if (target instanceof PlayerEntity) {
LivingEntity thisEntity = (LivingEntity) (Object) this;
EntityChatData entityData = getChatData(thisEntity, (PlayerEntity) target);
EntityChatData entityData = getChatData(thisEntity);
PlayerData playerData = entityData.getPlayerData(target.getDisplayName().getString());
if (playerData.friendship > 0) {
// Friendly creatures can't target a player
......@@ -62,7 +62,7 @@ public class MixinLivingEntity {
// Generate attacked message (only if the previous user message was not an attacked message)
// We don't want to constantly generate messages during a prolonged, multi-damage event
ServerPlayerEntity player = (ServerPlayerEntity) attacker;
EntityChatData chatData = getChatData(thisEntity, player);
EntityChatData chatData = getChatData(thisEntity);
if (!chatData.characterSheet.isEmpty() && chatData.auto_generated < ChatDataManager.MAX_AUTOGENERATE_RESPONSES) {
// Only auto-generate a response to being attacked if chat data already exists
// and this is the first attack event.
......@@ -94,10 +94,14 @@ public class MixinLivingEntity {
return;
}
// Get the original death message
Text deathMessage = entity.getDamageTracker().getDeathMessage();
// Broadcast the death message to all players in the world
ServerPackets.BroadcastMessage(deathMessage);
// Get chatData for the entity
EntityChatData chatData = getChatData(entity);
if (chatData != null && !chatData.characterSheet.isEmpty()) {
// Get the original death message
Text deathMessage = entity.getDamageTracker().getDeathMessage();
// Broadcast the death message to all players in the world
ServerPackets.BroadcastMessage(deathMessage);
}
}
}
}
......@@ -27,6 +27,16 @@ public class MixinMobEntity {
@Inject(method = "interact", at = @At(value = "RETURN"))
private void onItemGiven(PlayerEntity player, Hand hand, CallbackInfoReturnable<ActionResult> cir) {
// Only process interactions on the server side
if (player.getWorld().isClient()) {
return;
}
// Only process interactions for the main hand
if (hand != Hand.MAIN_HAND) {
return;
}
ItemStack itemStack = player.getStackInHand(hand);
MobEntity thisEntity = (MobEntity) (Object) this;
......@@ -54,7 +64,7 @@ public class MixinMobEntity {
// Get chat data for entity
ChatDataManager chatDataManager = ChatDataManager.getServerInstance();
EntityChatData entityData = chatDataManager.getOrCreateChatData(thisEntity.getUuidAsString(), player.getDisplayName().getString());
EntityChatData entityData = chatDataManager.getOrCreateChatData(thisEntity.getUuidAsString());
PlayerData playerData = entityData.getPlayerData(player.getDisplayName().getString());
// Check if the player successfully interacts with an item
......
......@@ -98,7 +98,7 @@ public class ServerPackets {
server.execute(() -> {
MobEntity entity = (MobEntity)ServerEntityFinder.getEntityByUUID(player.getServerWorld(), entityId);
if (entity != null) {
EntityChatData chatData = ChatDataManager.getServerInstance().getOrCreateChatData(entity.getUuidAsString(), player.getDisplayName().getString());
EntityChatData chatData = ChatDataManager.getServerInstance().getOrCreateChatData(entity.getUuidAsString());
if (chatData.characterSheet.isEmpty()) {
generate_character(userLanguage, chatData, player, entity);
}
......@@ -119,7 +119,7 @@ public class ServerPackets {
TalkPlayerGoal talkGoal = new TalkPlayerGoal(player, entity, 3.5F);
EntityBehaviorManager.addGoal(entity, talkGoal, GoalPriority.TALK_PLAYER);
EntityChatData chatData = ChatDataManager.getServerInstance().getOrCreateChatData(entity.getUuidAsString(), player.getDisplayName().getString());
EntityChatData chatData = ChatDataManager.getServerInstance().getOrCreateChatData(entity.getUuidAsString());
LOGGER.debug("Update read lines to " + lineNumber + " for: " + entity.getType().toString());
chatData.setLineNumber(lineNumber);
}
......@@ -139,7 +139,7 @@ public class ServerPackets {
TalkPlayerGoal talkGoal = new TalkPlayerGoal(player, entity, 3.5F);
EntityBehaviorManager.addGoal(entity, talkGoal, GoalPriority.TALK_PLAYER);
EntityChatData chatData = ChatDataManager.getServerInstance().getOrCreateChatData(entity.getUuidAsString(), player.getDisplayName().getString());
EntityChatData chatData = ChatDataManager.getServerInstance().getOrCreateChatData(entity.getUuidAsString());
LOGGER.debug("Hiding chat bubble for: " + entity.getType().toString());
chatData.setStatus(ChatDataManager.ChatStatus.valueOf(status_name));
}
......@@ -183,7 +183,7 @@ public class ServerPackets {
server.execute(() -> {
MobEntity entity = (MobEntity)ServerEntityFinder.getEntityByUUID(player.getServerWorld(), entityId);
if (entity != null) {
EntityChatData chatData = ChatDataManager.getServerInstance().getOrCreateChatData(entity.getUuidAsString(), player.getDisplayName().getString());
EntityChatData chatData = ChatDataManager.getServerInstance().getOrCreateChatData(entity.getUuidAsString());
if (chatData.characterSheet.isEmpty()) {
generate_character(userLanguage, chatData, player, entity);
} else {
......@@ -365,6 +365,11 @@ public class ServerPackets {
entity.setPersistent();
}
// Make auto-generated message appear as a pending icon (attack, show/give, arrival)
if (chatData.sender == ChatDataManager.ChatSender.USER && chatData.auto_generated > 0) {
chatData.status = ChatDataManager.ChatStatus.PENDING;
}
// Iterate over all players and send the packet
for (ServerPlayerEntity player : serverInstance.getPlayerManager().getPlayerList()) {
PacketByteBuf buffer = new PacketByteBuf(Unpooled.buffer());
......
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