Commit df2a7a6a by Jonathan Thomas

Added goals for "FOLLOW" and "UNFOLLOW", so Mob Entity types will follow the…

Added goals for "FOLLOW" and "UNFOLLOW", so Mob Entity types will follow the player. Refactored some code, to make this cleaner. GPT 3.5 still struggles to output the behaviors correctly, so I updated to GPT 4 Turbo.
parent 4846a19f
Pipeline #11888 passed with stage
in 25 seconds
......@@ -2,8 +2,13 @@ package com.owlmaddie;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.owlmaddie.goals.EntityBehaviorManager;
import com.owlmaddie.json.QuestJson;
import com.owlmaddie.message.Behavior;
import com.owlmaddie.message.MessageParser;
import com.owlmaddie.message.ParsedMessage;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerPlayerEntity;
......@@ -200,11 +205,19 @@ public class ChatDataManager {
ParsedMessage result = MessageParser.parseMessage(output_message.replace("\n", " "));
// Apply behaviors (if any)
MobEntity entity = (MobEntity) ServerEntityFinder.getEntityByUUID(player.getServerWorld(), UUID.fromString(entityId));
for (Behavior behavior : result.getBehaviors()) {
LOGGER.info("Behavior: " + behavior.getName());
if (behavior.getArgument() != null) {
LOGGER.info("Argument: " + behavior.getArgument());
}
// Apply goal to entity
if (behavior.getName().equals("FOLLOW")) {
EntityBehaviorManager.addFollowPlayerGoal(player, entity, 1.0);
} else if (behavior.getName().equals("UNFOLLOW")) {
EntityBehaviorManager.removeFollowPlayerGoal(entity);
}
}
// Add ASSISTANT message
......
......@@ -116,7 +116,7 @@ public class ChatGPTRequest {
}
// Convert JSON to String
ChatGPTRequestPayload payload = new ChatGPTRequestPayload("gpt-3.5-turbo", messages, jsonMode, 1.0f);
ChatGPTRequestPayload payload = new ChatGPTRequestPayload("gpt-4-turbo-preview", messages, jsonMode, 1.0f);
Gson gsonInput = new Gson();
String jsonInputString = gsonInput.toJson(payload);
......
package com.owlmaddie.goals;
import net.minecraft.entity.ai.goal.GoalSelector;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* The {@code EntityBehaviorManager} class keeps track of all Mob Entities which have
* custom goals attached to them, and prevents the same goal from being added to an
* entity more than once.
*/
public class EntityBehaviorManager {
private static final Map<UUID, FollowPlayerGoal> followGoals = new HashMap<>();
public static void addFollowPlayerGoal(ServerPlayerEntity player, MobEntity entity, double speed) {
if (!(entity.getWorld() instanceof ServerWorld)) return;
UUID entityId = entity.getUuid();
if (!followGoals.containsKey(entityId)) {
FollowPlayerGoal goal = new FollowPlayerGoal(player, entity, speed);
GoalSelector goalSelector = GoalUtils.getGoalSelector(entity);
goalSelector.add(1, goal); // Priority 1
followGoals.put(entityId, goal);
}
}
public static void removeFollowPlayerGoal(MobEntity entity) {
UUID entityId = entity.getUuid();
FollowPlayerGoal goal = followGoals.remove(entityId);
if (goal != null) {
GoalSelector goalSelector = GoalUtils.getGoalSelector(entity);
goalSelector.remove(goal);
}
}
}
package com.owlmaddie.goals;
import net.minecraft.entity.ai.goal.Goal;
import net.minecraft.entity.ai.pathing.EntityNavigation;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.server.network.ServerPlayerEntity;
import java.util.EnumSet;
/**
* The {@code FollowPlayerGoal} class instructs a Mob Entity to follow the current player.
*/
public class FollowPlayerGoal extends Goal {
private final MobEntity entity;
private ServerPlayerEntity targetPlayer;
private final EntityNavigation navigation;
private final double speed;
public FollowPlayerGoal(ServerPlayerEntity player, MobEntity entity, double speed) {
this.targetPlayer = player;
this.entity = entity;
this.speed = speed;
this.navigation = entity.getNavigation();
this.setControls(EnumSet.of(Control.MOVE));
}
@Override
public boolean canStart() {
return this.targetPlayer != null;
}
@Override
public boolean shouldContinue() {
return this.targetPlayer != null && this.targetPlayer.isAlive();
}
@Override
public void stop() {
this.targetPlayer = null;
this.navigation.stop();
}
@Override
public void tick() {
this.entity.getLookControl().lookAt(this.targetPlayer, 10.0F, (float) this.entity.getMaxLookPitchChange());
if (this.entity.squaredDistanceTo(this.targetPlayer) > 2.25) {
this.navigation.startMovingTo(this.targetPlayer, this.speed);
}
}
}
package com.owlmaddie.goals;
import net.minecraft.entity.ai.goal.GoalSelector;
import net.minecraft.entity.mob.MobEntity;
import java.lang.reflect.Field;
/**
* The {@code GoalUtils} class uses reflection to extend the MobEntity class
* and add a public GoalSelector method.
*/
public class GoalUtils {
private static Field goalSelectorField;
static {
try {
goalSelectorField = MobEntity.class.getDeclaredField("goalSelector");
goalSelectorField.setAccessible(true);
} catch (NoSuchFieldException e) {
// Handle the exception, perhaps the field name has changed
}
}
public static GoalSelector getGoalSelector(MobEntity mobEntity) {
try {
return (GoalSelector) goalSelectorField.get(mobEntity);
} catch (IllegalAccessException e) {
// Handle the exception
return null;
}
}
}
package com.owlmaddie;
package com.owlmaddie.message;
/**
* The {@code Behavior} class represents a single behavior with an optional integer argument.
......
package com.owlmaddie;
package com.owlmaddie.message;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
......
Please respond directly to the player, as if the response was written by the following Minecraft entity.
Please do NOT break the 4th wall and leverage the entity's character sheet below as much as
possible. Try and keep response to 1 to 2 sentences (very brief).
possible. Try and keep response to 1 to 2 sentences (very brief). Include behaviors at the end of the message
when relevant.
Entity Character Sheet:
{{entity_character_sheet}}
......@@ -25,11 +26,12 @@ World Info:
Behaviors:
If needed, include one or more of these behaviors at the end of the message. These behaviors allow
the entity to interact with the player and world, so it's important to include them if they are requested. For example, if
a player asks the entity to follow them, output <FOLLOW> at the end of the message. If the player improves the friendship
with an entity, output the new friendship value: <FRIENDSHIP value>. Include as many as needed (one per line).
IMPORTANT: Output one or more of these behaviors at the end of the message to instruct
the entity how to interact with the player and world, so it's important to include them if they are needed. For example, if
a player asks the entity to follow them, you MUST output <FOLLOW> at the end of the message. If the player improves the friendship
with an entity, you MUST output the new friendship value: <FRIENDSHIP value>. If the player wants the entity to stop following
them, you MUST output <UNFOLLOW>. Include as many behaviors as needed (one per line).
- <FRIENDSHIP 0> Friendship starts as neutral (0 value). The range of friendship values is -3 to 3. If the player gains (or loses) your trust & friendship, output a new friendship value with this behavior. Make the player work hard for a perfect friendship value.
- <FOLLOW> Follow the player's movements as they navigate the world.
- <UNFOLLOW> Stop following the player's movements.
\ No newline at end of file
- <FRIENDSHIP 0> Friendship starts as neutral (0 value). The range of friendship values is -3 to 3. If the player gains (or loses) your trust & friendship, output a new friendship value with this behavior.
- <FOLLOW> Follow the player. If the player asks you to follow them or come with them, please output this behavior.
- <UNFOLLOW> Stop following the player. If the player asks you to stay where you are or stop following them, please output this behavior.
\ 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