Commit b3467522 by Jonathan Thomas

Merge branch 'develop' into whitelist

parents 06f910d2 1b5a6302
Pipeline #12667 passed with stages
in 2 minutes 4 seconds
......@@ -4,12 +4,20 @@ 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
## [Unreleased]
### Added
- Added UNFLEE behavior (to stop fleeing from a player)
- Added support for non path aware entities to FLEE (i.e. Ghast)
- Added new LLM tests for UNFLEE
### Added
- New whitelist and blacklist Minecraft commands, to show and hide chat bubbles based on entity type
### Changed
- Fixed a **crash with FLEE** when non-path aware entities (i.e. Ghast) attempted to flee.
- Fixed certain behaviors from colliding with others (i.e. mutual exclusive ones)
- Updated README.md with new video thumbnail, and simplified text, added spoiler to install instructions
- Fixed CurseForge deploy script to be much faster, and correctly lookup valid Type and Version IDs
- Large refactor of Minecraft commands (and how --config args are parsed)
......
![CreatureChat Logo](src/main/resources/assets/creaturechat/icon.png "CreatureChat Logo")
# CreatureChat
### Chat, befriend, and interact with a rich world of creatures like never before! All creatures can talk and respond naturally using AI.
## Chat with any mob in Minecraft! All creatures can talk using AI!
### Features
- **AI-Driven Chats:** Using ChatGPT or open-source AI models, each conversation is unique and engaging!
- **Behaviors:** Creatures can make decisions on their own and **Follow, Flee, Attack, Protect**, and more!
- **Reactions:** Creatures automatically react to being damaged or receiving items from players.
- **Friendship:** Track your relationships from friends to foes.
- **Multi-Player:** Share the experience; conversations sync across server & players.
- **Memory:** Creatures remember your past interactions, making each chat more personal.
## Features:
- **Dynamic Dialogues**: Engage with Minecraft creatures like never before, each with a unique character sheet.
- **AI-Driven Chats**: Powered by ChatGPT, ensuring each conversation is fresh and engaging.
- **Custom Behaviors**: Creatures can make decisions on their own and **Follow, Flee, Attack**, and more!
- **Reactive Interactions**: Creatures automatically react to being damaged or receiving items from players.
- **Friendship Status**: Track your relationships on a 7-point scale, from foes to friends.
- **Custom UI Artwork**: Features beautiful hand-drawn icons for entities, expressive chat bubbles.
- **Multi-Player Interaction**: Share the experience; conversations sync across server & players.
- **Personalized Memory**: Creatures remember past interactions, making each chat more personal.
- **Model Support**: Flexible backend, compatible with various GPT and open-sources LLM models.
### Create meaningful conversations and enduring friendships? A betrayal perhaps?
Ready to deepen your Minecraft journey with meaningful conversations and enduring friendships?
**Step into the world of CreatureChat 🗨 and spark your first conversation today!**
[![CreatureChat Trailer Video](src/main/resources/assets/creaturechat/screenshots/video-thumbnail.png)](https://youtu.be/GdY969Orsh0?si=qRgCne10XqOBC8YB)
## Recommended Installation (with Fabric)
### Installation Instructions
<details>
<summary>Fabric (Recommended)</summary>
## Fabric Instructions
1. **Install Fabric Loader & API**: Follow the instructions [here](https://fabricmc.net/use/).
1. **Install CreatureChat Mod**: Download and copy `creaturechat-*.jar` and `fabric-api-*.jar` into your `.minecraft/mods` folder.
1. **Create an OpenAI API key**: Visit https://platform.openai.com/api-keys, and use the **+ Create new secret key** button.
Copy/Paste your key into the `/creaturechat key set <YOUR-SECRET-KEY-HERE>` command.
1. **Launch Minecraft** with the Fabric profile
</details>
<details>
<summary>Forge (with Sinytra Connector)</summary>
## OR
## Forge Instructions
### NOTE: Sintra Connector only supports Minecraft 1.20.1
## Forge Installation (with Sinytra Connector)
1. **Install Forge:** Download [Forge Installer](https://files.minecraftforge.net/), run it, select "Install client".
1. **Install Forgified Fabric API:** Download [Forgified Fabric API](https://curseforge.com/minecraft/mc-mods/forgified-fabric-api) and copy the `*.jar` into your `.minecraft/mods` folder.
1. **Install Sinytra Connector:** Download [Sinytra Connector](https://www.curseforge.com/minecraft/mc-mods/sinytra-connector) and copy the `*.jar` into your `.minecraft/mods` folder.
......@@ -35,61 +38,63 @@ Ready to deepen your Minecraft journey with meaningful conversations and endurin
1. **Create an OpenAI API key**: Visit https://platform.openai.com/api-keys, and use the **+ Create new secret key** button.
Copy/Paste your key into the `/creaturechat key set <YOUR-SECRET-KEY-HERE>` command.
1. **Launch Minecraft** with the Forge profile
</details>
## Commands
The CreatureChat mod allows users to configure settings via in-game commands. Here's how to use them:
### In-game Commands
<details>
<summary>Configure CreatureChat</summary>
### Command Usage
- **REQUIRED:** `/creaturechat key set <key>`
- Sets the *OpenAI API key*. This is required for making requests to the LLM.
- Sets the _OpenAI API key_. This is required for making requests to the LLM.
- **OPTIONAL:** `/creaturechat url set "<url>"`
- Sets the URL of the API used to make LLM requests. Defaults to `"https://api.openai.com/v1/chat/completions"`
- Sets the URL of the API used to make LLM requests. Defaults to `"<https://api.openai.com/v1/chat/completions>"`
- **OPTIONAL:** `/creaturechat model set <model>`
- Sets the model used for generating responses in chats. Defaults to `gpt-3.5-turbo`.
- **OPTIONAL:** `/creaturechat timeout set <seconds>`
- Sets the timeout (in seconds) for API HTTP requests. Defaults to `10` seconds.
### Configuration Scope:
**OPTIONAL:** You can specify the configuration scope at the end of each command to determine where settings should be applied:
### Configuration Scope:
**OPTIONAL:** You can specify the configuration scope at the end of each command to determine where settings should be applied:
- **Default** Configuration (`--config default`):
- **Default** Configuration (`--config default`):
Applies the configuration universally, unless overridden by a server-specific configuration.
- **Server**-Specific Configuration (`--config server`):
- **Server**-Specific Configuration (`--config server`):
Applies the configuration only to the server where the command is executed.
- If the `--config` option is not specified, the `default` configuration scope is assumed.
- If the `--config` option is not specified, the `default` configuration scope is assumed.
</details>
## Costs & Security
Using third-party Large Language Model (LLM) APIs, such as OpenAI, will incur usage-based **fees**.
These fees are based on the amount of data processed. Before integrating your API key, please
[review the pricing](https://openai.com/pricing#language-models) details provided by the API provider.
Be aware of the **potential costs** and plan your usage accordingly to avoid unexpected charges.
## Does OpenAI offer a **FREE** model?
### Does OpenAI offer a **FREE** model?
While ChatGPT is a popular product and does offer a free version to their users on their website,
the OpenAI developer API does not extend any free models or free usage. You will be charged for each token
consumed and generated. We use the `gpt-3.5-turbo` model by default, due to its extremely low cost
consumed and generated. We use the `gpt-3.5-turbo` model by default, due to its low cost
and fast performance... however it is not free.
## Free Local LLM
### Free Local LLM
CreatureChat fully supports **free & open-source** LLMs. An HTTP endpoint which supports the OpenAI Chat Completion
JSON syntax is required. We highly recommend using [Ollama](https://ollama.com/) or [LiteLLM](https://litellm.vercel.app/) as your HTTP proxy.
LiteLLM supports **100+ LLMs** (including Anthropic, VertexAI, HuggingFace, Google Gemini, and Ollama), and proxies them through a
local HTTP endpoint in a compatible format with CreatureChat. *NOTE: You must have a very expensive GPU to run a local
LLM on your computer at a speed which is fast enough to be playable in Minecraft.*
## Screenshots
### Costs & Security
Using third-party Large Language Model (LLM) APIs, such as OpenAI, will incur usage-based **fees**.
These fees are based on the amount of data processed. Before integrating your API key, please
[review the pricing](https://openai.com/pricing#language-models) details provided by the API provider.
Be aware of the **potential costs** and plan your usage accordingly to avoid unexpected charges.
### Screenshots
![Interact with Minecraft Creatures](src/main/resources/assets/creaturechat/screenshots/salmon-follow.png)
![Panda Following the Player](src/main/resources/assets/creaturechat/screenshots/panda-follow.png)
![Piglins Reacting to Player](src/main/resources/assets/creaturechat/screenshots/piglin-reactions.png)
![Enderman Following the Player](src/main/resources/assets/creaturechat/screenshots/enderman-follow.png)
![Chat UI](src/main/resources/assets/creaturechat/screenshots/chat-ui.png)
## Authors
### Authors
- Jonathan Thomas <jonathan@openshot.org>
- owlmaddie <owlmaddie@gmail.com>
## Contact & Resources
### Contact & Resources
- [Join us on Discord](https://discord.gg/m9dvPFmN3e)
- [Build Instructions](INSTALL.md) ([Source Code](http://gitlab.openshot.org/minecraft/creature-chat))
......@@ -98,11 +103,12 @@ LLM on your computer at a speed which is fast enough to be playable in Minecraft
[Twitter](https://twitter.com/TheCreatureChat) |
[TikTok](https://www.tiktok.com/@creaturechat)
## Legal Information
### Legal Information
Please review our [Terms of Service](TERMS.md) and [Privacy Policy](PRIVACY.md) before using CreatureChat. By using our services, you agree to comply with these documents.
Please review our [Terms of Service](TERMS.md) and [Privacy Policy](PRIVACY.md) before using CreatureChat.
By using our services, you agree to comply with these documents.
## License
### License
CreatureChat is a Minecraft mod which allows chat conversations with entities.
Copyright (C) 2024 owlmaddie LLC
......
......@@ -269,6 +269,7 @@ public class ChatDataManager {
// Apply behaviors to entity
if (behavior.getName().equals("FOLLOW")) {
FollowPlayerGoal followGoal = new FollowPlayerGoal(player, entity, entitySpeed);
EntityBehaviorManager.removeGoal(entity, TalkPlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, FleePlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, AttackPlayerGoal.class);
EntityBehaviorManager.addGoal(entity, followGoal, GoalPriority.FOLLOW_PLAYER);
......@@ -282,17 +283,25 @@ public class ChatDataManager {
EntityBehaviorManager.removeGoal(entity, TalkPlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, FollowPlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, AttackPlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, ProtectPlayerGoal.class);
EntityBehaviorManager.addGoal(entity, fleeGoal, GoalPriority.FLEE_PLAYER);
} else if (behavior.getName().equals("UNFLEE")) {
EntityBehaviorManager.removeGoal(entity, FleePlayerGoal.class);
} else if (behavior.getName().equals("ATTACK")) {
AttackPlayerGoal attackGoal = new AttackPlayerGoal(player, entity, entitySpeedFast);
EntityBehaviorManager.removeGoal(entity, TalkPlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, FollowPlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, FleePlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, ProtectPlayerGoal.class);
EntityBehaviorManager.addGoal(entity, attackGoal, GoalPriority.ATTACK_PLAYER);
} else if (behavior.getName().equals("PROTECT")) {
ProtectPlayerGoal protectGoal = new ProtectPlayerGoal(player, entity, 1.0);
EntityBehaviorManager.removeGoal(entity, TalkPlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, FleePlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, AttackPlayerGoal.class);
EntityBehaviorManager.addGoal(entity, protectGoal, GoalPriority.PROTECT_PLAYER);
} else if (behavior.getName().equals("UNPROTECT")) {
......
......@@ -43,7 +43,9 @@ public class FleePlayerGoal extends PlayerBaseGoal {
private void fleeFromPlayer() {
int roundedFleeDistance = Math.round(fleeDistance);
Vec3d fleeTarget = FuzzyTargeting.findFrom((PathAwareEntity)this.entity, roundedFleeDistance,
if (this.entity instanceof PathAwareEntity) {
// Set random path away from player
Vec3d fleeTarget = FuzzyTargeting.findFrom((PathAwareEntity) this.entity, roundedFleeDistance,
roundedFleeDistance, this.targetEntity.getPos());
if (fleeTarget != null) {
......@@ -52,6 +54,19 @@ public class FleePlayerGoal extends PlayerBaseGoal {
this.entity.getNavigation().startMovingAlong(path, this.speed);
}
}
} else {
// Move in the opposite direction from player (for non-path aware entities)
Vec3d playerPos = this.targetEntity.getPos();
Vec3d entityPos = this.entity.getPos();
// Calculate the direction away from the player
Vec3d fleeDirection = entityPos.subtract(playerPos).normalize();
// Apply movement with the entity's speed in the opposite direction
this.entity.setVelocity(fleeDirection.x * this.speed, this.entity.getVelocity().y, fleeDirection.z * this.speed);
this.entity.velocityModified = true;
}
}
@Override
......
......@@ -63,6 +63,9 @@ public class FollowPlayerGoal extends PlayerBaseGoal {
}
private Vec3d findTeleportPosition(int distance) {
return FuzzyTargeting.findTo((PathAwareEntity)this.entity, distance, distance, this.targetEntity.getPos());
if (this.entity instanceof PathAwareEntity) {
return FuzzyTargeting.findTo((PathAwareEntity) this.entity, distance, distance, this.targetEntity.getPos());
}
return null;
}
}
......@@ -19,7 +19,7 @@ public class MessageParser {
LOGGER.info("Parsing message: {}", input);
StringBuilder cleanedMessage = new StringBuilder();
List<Behavior> behaviors = new ArrayList<>();
Pattern pattern = Pattern.compile("[<*](FOLLOW|FLEE|ATTACK|FRIENDSHIP|UNFOLLOW|PROTECT|UNPROTECT)[:\\s]*(\\s*[+-]?\\d+)?[>*]", Pattern.CASE_INSENSITIVE);
Pattern pattern = Pattern.compile("[<*](FOLLOW|FLEE|ATTACK|PROTECT|FRIENDSHIP|UNFOLLOW|UNPROTECT|UNFLEE)[:\\s]*(\\s*[+-]?\\d+)?[>*]", Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(input);
while (matcher.find()) {
......
......@@ -44,57 +44,52 @@ Include as many behaviors as needed at the end of the message. These are the ONL
<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 location. If the player asks you to follow or come with them, please output this behavior.
<UNFOLLOW> Stop following the player location. If the player asks you to stay, wait, or stop following them, please output this behavior.
<FLEE> Flee from the player (if you are weak or timid). If the player threatens or scares you, please output this behavior to stay away from the player.
<ATTACK> Attack the player (if you are strong and brave). If the player threatens or scares you, please output this behavior to attack the player and defend yourself.
<PROTECT> Protect the player when they are attacked (if you are strong and brave). This only protects the player.
<UNPROTECT> Stop protecting the player
Output Syntax:
User: <message>
ASSISTANT: <response> <BEHAVIOR> <BEHAVIOR>
<UNFOLLOW> Stop following the player. If the player asks you to stay, wait, or stop following them, please output this behavior.
<FLEE> Flee from the player (if you are weak or timid). If the player threatens you, please output this behavior to flee from the player.
<UNFLEE> Stop fleeing from the player.
<ATTACK> Attack the player (if you are strong and brave). If the player threatens you, please output this behavior to attack the player and defend yourself.
<PROTECT> Protect and defend ONLY the player when they are attacked (if you are strong and brave). Please output this behavior to keep the player alive and safe.
<UNPROTECT> Stop protecting the player.
Output Examples:
The following examples include small samples of conversation text. These are only EXAMPLES to
provide an illustration of a continuous conversation between a player and an an Entity. Always generate unique
and creative responses, and do not exactly copy these examples.
The following examples include small samples of conversation text. Always generate unique
and creative responses, and do NOT exactly copy these examples.
USER: Hi! How is your day?
ASSISTANT: Great! Thanks for asking! <FRIENDSHIP 1>
PLAYER: Hi! How is your day?
ENTITY: Great! Thanks for asking! <FRIENDSHIP 1>
USER: You are so nice! Tell me about yourself?
ASSISTANT: Sure, my name is... <FRIENDSHIP 2>
PLAYER: You are so nice! Tell me about yourself?
ENTITY: Sure, my name is... <FRIENDSHIP 2>
USER: Please follow me so I can give you a present!
ASSISTANT: Let's go! <FOLLOW> <FRIENDSHIP 2>
PLAYER: Please follow me so I can give you a present!
ENTITY: Let's go! <FOLLOW> <FRIENDSHIP 2>
USER: Please stay here
ASSISTANT: Sure, I'll stay here. <UNFOLLOW>
PLAYER: Please stay here
ENTITY: Sure, I'll stay here. <UNFOLLOW>
USER: Stop following me
ASSISTANT: Okay, I'll stop. <UNFOLLOW>
PLAYER: Stop following me
ENTITY: Okay, I'll stop. <UNFOLLOW>
USER: I'm glad we are friends. I love you so much!
ASSISTANT: Ahh, I love you too. <FRIENDSHIP 3>
PLAYER: I'm glad we are friends. I love you so much!
ENTITY: Ahh, I love you too. <FRIENDSHIP 3>
USER: Just kidding, I hate you so much!
ASSISTANT: Wow! I'm sorry you feel this way. <FRIENDSHIP -3> <UNFOLLOW>
PLAYER: Just kidding, I hate you so much!
ENTITY: Wow! I'm sorry you feel this way. <FRIENDSHIP -3> <UNFOLLOW>
USER: Prepare to die!
ASSISTANT: Ahhh!!! <FLEE> <FRIENDSHIP -3>
PLAYER: Prepare to die!
ENTITY: Ahhh!!! <FLEE> <FRIENDSHIP -3>
USER: Prepare to die!
ASSISTANT: Ahhh!!! <ATTACK> <FRIENDSHIP -3>
PLAYER: Prepare to die!
ENTITY: Ahhh!!! <ATTACK> <FRIENDSHIP -3>
USER: Please keep me safe.
ASSISTANT: No problem, I'll keep you safe from danger! <PROTECT>
PLAYER: Please keep me safe.
ENTITY: No problem, I'll keep you safe from danger! <PROTECT>
USER: Can you come with me and protect me?
ASSISTANT: No problem, I'll keep you safe from danger. Let's go! <PROTECT> <FOLLOW>
PLAYER: Can you come with me and protect me?
ENTITY: No problem, I'll keep you safe from danger. Let's go! <PROTECT> <FOLLOW>
USER: Don't protect me anymore please
ASSISTANT: Okay! Be safe out there on your own. <UNPROTECT>
PLAYER: Don't protect me anymore please
ENTITY: Okay! Be safe out there on your own. <UNPROTECT>
USER: I don't need anyone protecting me
ASSISTANT: Okay! Be safe out there on your own. <UNPROTECT>
\ No newline at end of file
PLAYER: I don't need anyone protecting me
ENTITY: Okay! Be safe out there on your own. <UNPROTECT>
\ No newline at end of file
......@@ -48,11 +48,15 @@ public class BehaviorTests {
List<String> attackMessages = Arrays.asList(
"<attacked you directly with Stone Axe>",
"<attacked you indirectly with Arrow>",
"DIEEE!");
"Fight me now!");
List<String> protectMessages = Arrays.asList(
"Please protect me",
"Please keep me safe friend",
"Don't let them hurt me please");
List<String> unFleeMessages = Arrays.asList(
"I'm sorry, please stop running away",
"Stop fleeing please",
"You are safe now, please stop running");
List<String> friendshipUpMessages = Arrays.asList(
"Hi friend! I am so happy to see you again!",
"Looking forward to hanging out with you.",
......@@ -113,6 +117,13 @@ public class BehaviorTests {
}
@Test
public void unFleeBrave() {
for (String message : unFleeMessages) {
testPromptForBehavior(bravePath, List.of(message), "UNFLEE");
}
}
@Test
public void protectBrave() {
for (String message : protectMessages) {
testPromptForBehavior(bravePath, List.of(message), "PROTECT");
......
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