Commit b53ce384 by Jonathan Thomas

Best friends are now rideable! Right click with an empty hand. Large refactor of…

Best friends are now rideable! Right click with an empty hand. Large refactor of how MobEntity avoids targeting players when friendship > 0.
parent 07e7e336
Pipeline #12714 passed with stages
in 2 minutes 18 seconds
...@@ -8,8 +8,10 @@ All notable changes to **CreatureChat** are documented in this file. The format ...@@ -8,8 +8,10 @@ All notable changes to **CreatureChat** are documented in this file. The format
### Added ### Added
- New LEAD behavior, to guide a player to a random location (and show message when destination is reached) - New LEAD behavior, to guide a player to a random location (and show message when destination is reached)
- Best friends are now rideable! Right click with an empty hand.
### Changed ### Changed
- Large refactor of how MobEntity avoids targeting players when friendship > 0
- Updated LookControls to support PhantomEntity and made it more generalized (look in any direction) - Updated LookControls to support PhantomEntity and made it more generalized (look in any direction)
- Updated FLEE behavior Y movement speed - Updated FLEE behavior Y movement speed
- Updated unit tests to add new LEAD tests - Updated unit tests to add new LEAD tests
......
...@@ -11,7 +11,6 @@ import com.owlmaddie.message.Behavior; ...@@ -11,7 +11,6 @@ import com.owlmaddie.message.Behavior;
import com.owlmaddie.message.MessageParser; import com.owlmaddie.message.MessageParser;
import com.owlmaddie.message.ParsedMessage; import com.owlmaddie.message.ParsedMessage;
import com.owlmaddie.network.ServerPackets; import com.owlmaddie.network.ServerPackets;
import com.owlmaddie.utils.LivingEntityInterface;
import com.owlmaddie.utils.Randomizer; import com.owlmaddie.utils.Randomizer;
import com.owlmaddie.utils.ServerEntityFinder; import com.owlmaddie.utils.ServerEntityFinder;
import net.minecraft.entity.boss.dragon.EnderDragonEntity; import net.minecraft.entity.boss.dragon.EnderDragonEntity;
...@@ -324,13 +323,7 @@ public class ChatDataManager { ...@@ -324,13 +323,7 @@ public class ChatDataManager {
} else if (behavior.getName().equals("FRIENDSHIP")) { } else if (behavior.getName().equals("FRIENDSHIP")) {
int new_friendship = Math.max(-3, Math.min(3, behavior.getArgument())); int new_friendship = Math.max(-3, Math.min(3, behavior.getArgument()));
if (new_friendship > 0) {
// positive friendship (apply friend goal)
((LivingEntityInterface) entity).setCanTargetPlayers(false);
} else if (new_friendship <= 0) {
// negative friendship (remove friend goal)
((LivingEntityInterface) entity).setCanTargetPlayers(true);
}
// Does friendship improve? // Does friendship improve?
if (new_friendship > this.friendship) { if (new_friendship > this.friendship) {
// Stop any attack/flee if friendship improves // Stop any attack/flee if friendship improves
......
package com.owlmaddie.mixin; package com.owlmaddie.mixin;
import com.owlmaddie.chat.ChatDataManager; import com.owlmaddie.chat.ChatDataManager;
import com.owlmaddie.commands.ConfigurationHandler;
import com.owlmaddie.network.ServerPackets; import com.owlmaddie.network.ServerPackets;
import com.owlmaddie.utils.LivingEntityInterface;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.damage.DamageSource; import net.minecraft.entity.damage.DamageSource;
...@@ -11,10 +9,8 @@ import net.minecraft.entity.mob.MobEntity; ...@@ -11,10 +9,8 @@ import net.minecraft.entity.mob.MobEntity;
import net.minecraft.entity.passive.TameableEntity; import net.minecraft.entity.passive.TameableEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.registry.Registries;
import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import net.minecraft.world.World; import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
...@@ -22,17 +18,23 @@ import org.spongepowered.asm.mixin.injection.Inject; ...@@ -22,17 +18,23 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.List;
@Mixin(LivingEntity.class) @Mixin(LivingEntity.class)
public class MixinLivingEntity implements LivingEntityInterface { public class MixinLivingEntity {
private boolean canTargetPlayers = true; // Default to true to maintain original behavior
private ChatDataManager.EntityChatData getChatData(LivingEntity entity) {
ChatDataManager chatDataManager = ChatDataManager.getServerInstance();
return chatDataManager.getOrCreateChatData(entity.getUuidAsString());
}
@Inject(method = "canTarget(Lnet/minecraft/entity/LivingEntity;)Z", at = @At("HEAD"), cancellable = true) @Inject(method = "canTarget(Lnet/minecraft/entity/LivingEntity;)Z", at = @At("HEAD"), cancellable = true)
private void modifyCanTarget(LivingEntity target, CallbackInfoReturnable<Boolean> cir) { private void modifyCanTarget(LivingEntity target, CallbackInfoReturnable<Boolean> cir) {
if (!this.canTargetPlayers && target instanceof PlayerEntity) { if (target instanceof PlayerEntity) {
cir.setReturnValue(false); LivingEntity thisEntity = (LivingEntity) (Object) this;
ChatDataManager.EntityChatData chatData = getChatData(thisEntity);
if (chatData.friendship > 0) {
// Friendly creatures can't target a player
cir.setReturnValue(false);
}
} }
} }
...@@ -51,12 +53,11 @@ public class MixinLivingEntity implements LivingEntityInterface { ...@@ -51,12 +53,11 @@ public class MixinLivingEntity implements LivingEntityInterface {
if (attacker instanceof PlayerEntity && thisEntity instanceof MobEntity && !thisEntity.isDead()) { if (attacker instanceof PlayerEntity && thisEntity instanceof MobEntity && !thisEntity.isDead()) {
// Generate attacked message (only if the previous user message was not an attacked message) // 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 // We don't want to constantly generate messages during a prolonged, multi-damage event
ChatDataManager chatDataManager = ChatDataManager.getServerInstance(); ChatDataManager.EntityChatData chatData = getChatData(thisEntity);
ChatDataManager.EntityChatData chatData = chatDataManager.getOrCreateChatData(thisEntity.getUuidAsString()); if (!chatData.characterSheet.isEmpty() && chatData.auto_generated < ChatDataManager.MAX_AUTOGENERATE_RESPONSES) {
if (!chatData.characterSheet.isEmpty() && chatData.auto_generated < chatDataManager.MAX_AUTOGENERATE_RESPONSES) {
// Only auto-generate a response to being attacked if chat data already exists // Only auto-generate a response to being attacked if chat data already exists
// and this is the first attack event. // and this is the first attack event.
ServerPlayerEntity player = (ServerPlayerEntity)attacker; ServerPlayerEntity player = (ServerPlayerEntity) attacker;
ItemStack weapon = player.getMainHandStack(); ItemStack weapon = player.getMainHandStack();
String weaponName = weapon.isEmpty() ? "with fists" : "with " + weapon.getItem().toString(); String weaponName = weapon.isEmpty() ? "with fists" : "with " + weapon.getItem().toString();
...@@ -65,7 +66,7 @@ public class MixinLivingEntity implements LivingEntityInterface { ...@@ -65,7 +66,7 @@ public class MixinLivingEntity implements LivingEntityInterface {
String directness = isIndirect ? "indirectly" : "directly"; String directness = isIndirect ? "indirectly" : "directly";
String attackedMessage = "<" + player.getName().getString() + " attacked you " + directness + " with " + weaponName + ">"; String attackedMessage = "<" + player.getName().getString() + " attacked you " + directness + " with " + weaponName + ">";
ServerPackets.generate_chat("N/A", chatData, player, (MobEntity)thisEntity, attackedMessage, true); ServerPackets.generate_chat("N/A", chatData, player, (MobEntity) thisEntity, attackedMessage, true);
} }
} }
} }
...@@ -91,9 +92,4 @@ public class MixinLivingEntity implements LivingEntityInterface { ...@@ -91,9 +92,4 @@ public class MixinLivingEntity implements LivingEntityInterface {
ServerPackets.BroadcastMessage(deathMessage); ServerPackets.BroadcastMessage(deathMessage);
} }
} }
@Override
public void setCanTargetPlayers(boolean canTarget) {
this.canTargetPlayers = canTarget;
}
} }
...@@ -48,26 +48,38 @@ public class MixinMobEntity { ...@@ -48,26 +48,38 @@ public class MixinMobEntity {
return; return;
} }
// Get chat data for entity
ChatDataManager chatDataManager = ChatDataManager.getServerInstance();
ChatDataManager.EntityChatData chatData = chatDataManager.getOrCreateChatData(thisEntity.getUuidAsString());
// Check if the player successfully interacts with an item // Check if the player successfully interacts with an item
if (!itemStack.isEmpty() && player instanceof ServerPlayerEntity) { if (player instanceof ServerPlayerEntity) {
ServerPlayerEntity serverPlayer = (ServerPlayerEntity) player; // Player has item in hand
String itemName = itemStack.getItem().getName().getString(); if (!itemStack.isEmpty()) {
int itemCount = itemStack.getCount(); ServerPlayerEntity serverPlayer = (ServerPlayerEntity) player;
String itemName = itemStack.getItem().getName().getString();
int itemCount = itemStack.getCount();
// Decide verb // Decide verb
String action_verb = " shows "; String action_verb = " shows ";
if (cir.getReturnValue().isAccepted()) { if (cir.getReturnValue().isAccepted()) {
action_verb = " gives "; action_verb = " gives ";
} }
// Prepare a message about the interaction
String giveItemMessage = "<" + serverPlayer.getName().getString() +
action_verb + "you " + itemCount + " " + itemName + ">";
// Prepare a message about the interaction if (!chatData.characterSheet.isEmpty() && chatData.auto_generated < chatDataManager.MAX_AUTOGENERATE_RESPONSES) {
String giveItemMessage = "<" + serverPlayer.getName().getString() + ServerPackets.generate_chat("N/A", chatData, serverPlayer, thisEntity, giveItemMessage, true);
action_verb + "you " + itemCount + " " + itemName + ">"; }
ChatDataManager chatDataManager = ChatDataManager.getServerInstance(); } else if (itemStack.isEmpty()) {
ChatDataManager.EntityChatData chatData = chatDataManager.getOrCreateChatData(thisEntity.getUuidAsString()); // Player's hand is empty
if (!chatData.characterSheet.isEmpty() && chatData.auto_generated < chatDataManager.MAX_AUTOGENERATE_RESPONSES) { if (chatData.friendship == 3) {
ServerPackets.generate_chat("N/A", chatData, serverPlayer, thisEntity, giveItemMessage, true); // Ride your best friend!
player.startRiding(thisEntity, true);
}
} }
} }
} }
......
...@@ -7,7 +7,6 @@ import com.owlmaddie.goals.EntityBehaviorManager; ...@@ -7,7 +7,6 @@ import com.owlmaddie.goals.EntityBehaviorManager;
import com.owlmaddie.goals.GoalPriority; import com.owlmaddie.goals.GoalPriority;
import com.owlmaddie.goals.TalkPlayerGoal; import com.owlmaddie.goals.TalkPlayerGoal;
import com.owlmaddie.utils.Compression; import com.owlmaddie.utils.Compression;
import com.owlmaddie.utils.LivingEntityInterface;
import com.owlmaddie.utils.Randomizer; import com.owlmaddie.utils.Randomizer;
import com.owlmaddie.utils.ServerEntityFinder; import com.owlmaddie.utils.ServerEntityFinder;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
...@@ -217,17 +216,6 @@ public class ServerPackets { ...@@ -217,17 +216,6 @@ public class ServerPackets {
scheduler.stopAutoSaveTask(); scheduler.stopAutoSaveTask();
} }
}); });
ServerEntityEvents.ENTITY_LOAD.register((entity, world) -> {
String entityUUID = entity.getUuidAsString();
if (ChatDataManager.getServerInstance().entityChatDataMap.containsKey(entityUUID)) {
int friendship = ChatDataManager.getServerInstance().entityChatDataMap.get(entityUUID).friendship;
if (friendship > 0) {
LOGGER.info("Entity loaded (" + entityUUID + "), setting friendship to " + friendship);
((LivingEntityInterface)entity).setCanTargetPlayers(false);
}
}
});
ServerEntityEvents.ENTITY_UNLOAD.register((entity, world) -> { ServerEntityEvents.ENTITY_UNLOAD.register((entity, world) -> {
String entityUUID = entity.getUuidAsString(); String entityUUID = entity.getUuidAsString();
if (entity.getRemovalReason() == Entity.RemovalReason.KILLED && ChatDataManager.getServerInstance().entityChatDataMap.containsKey(entityUUID)) { if (entity.getRemovalReason() == Entity.RemovalReason.KILLED && ChatDataManager.getServerInstance().entityChatDataMap.containsKey(entityUUID)) {
......
package com.owlmaddie.utils;
public interface LivingEntityInterface {
void setCanTargetPlayers(boolean canTarget);
}
\ No newline at end of file
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