# GumYum NPC Game Client for Godot Bring NPCs to life in your Godot games with AI-powered dialogue and personality systems. ## Features - **API Key Authentication**: Simple setup with public/secret key pairs - **Character Spawning**: Create NPCs from any GumYum universe - **Natural Dialogue**: Chat with NPCs that remember context and have personalities - **Streaming Support**: Real-time typewriter effect for dialogue - **Auto-Retry**: Built-in error handling and request retry - **Lightweight**: Minimal footprint, perfect for production builds ## Installation ### Method 1: Clone from GitLab (Recommended) Since the client is stable & shouldn't be change, we recommend cloning & copying: 1. Clone the public repository: ```bash git clone https://git.unturf.com/engineering/gumyum/npc-clients.git ``` 2. Copy the addon to your project: ```bash cp -r npc-clients/godot/gumyum_npc_game_client /path/to/your/project/addons/ ``` 3. Enable the plugin in Project Settings → Plugins → GumYum NPC Game Client 4. The `GumyumClient` singleton will be available globally If you ever need to you can `git pull` the latest clients and patch game files as needed. ### Method 2: Direct Download Zip 1. Download the zip of all the client SDKs * https://git.unturf.com/engineering/gumyum/npc-clients/-/archive/main/npc-clients-main.zip 2. Decompress & copy the `godot/gumyum_npc_game_client` directory into your project's `addons/` directory 3. Enable the plugin in Project Settings → Plugins → GumYum NPC Game Client ### Method 3: Asset Library (Coming Soon) The GumYum NPC addon will be available in the Godot Asset Library. ## Quickstart Create a working chat UI with NPCs in under 5 minutes: ```gdscript # Quickstart: Chat UI with NPCs # Save as ChatDemo.gd and attach to a Control node extends Control @onready var chat_display = RichTextLabel.new() @onready var input_field = LineEdit.new() @onready var send_button = Button.new() var current_npc: GumYumNPC func _ready(): # Setup UI setup_ui() # Configure API GumyumClient.api_key = "gumyum-pk-your-public-key" GumyumClient.api_secret = "gumyum-sk-your-secret-key" GumyumClient.base_url = "https://npc.gumyum.com" # Spawn a random NPC add_system_message("Connecting to GumYum API...") GumyumClient.npcs.spawn( "kingdom", # universe 42, # seed null, # npc_id (null = random) _on_npc_spawned ) func _on_npc_spawned(npc: GumYumNPC): if npc == null: add_system_message("[color=red]Failed to spawn NPC![/color]") return current_npc = npc add_system_message( "[color=green]Connected to " + npc.name + " the " + npc.profession + "[/color]" ) func send_message(text: String): if text.is_empty() or current_npc == null: return add_player_message(text) # Use chat_with_history for easy conversation tracking current_npc.chat_with_history( text, 0.8, 1500, false, _on_chat_response ) func _on_chat_response(response): if response.has("error"): add_system_message("[color=red]Error: " + response.error + "[/color]") else: var content = response.choices[0].message.content add_npc_message(content) ``` ## API Reference ### Configuration ```gdscript # Set your API credentials GumyumClient.api_key = "gumyum-pk-your-public-key" GumyumClient.api_secret = "gumyum-sk-your-secret-key" # Optional: Set custom API endpoint GumyumClient.base_url = "https://npc.gumyum.com" # Optional: Enable debug mode GumyumClient.debug_mode = true ``` ### Spawning NPCs #### Method 1: Spawn by ID (Specific or Random) ```gdscript # Spawn a specific NPC GumyumClient.npcs.spawn( "kingdom", # universe_id 42, # world_seed 123456789, # npc_id (specific) _on_npc_spawned ) # Spawn a random NPC (API generates from seed) GumyumClient.npcs.spawn( "kingdom", # universe_id 42, # world_seed null, # npc_id (null/omit for random) _on_npc_spawned ) ``` #### Method 2: Spawn with Filters ```gdscript # Find NPCs by profession and location GumyumClient.npcs.spawn_filtered( "kingdom", 42, { "profession": ["warrior", "knight", "guard"], "sex": ["female"], "location": ["castle", "barracks"] }, _on_npc_spawned ) # Filter by personality type and mood GumyumClient.npcs.spawn_filtered( "blade-runner", 42, { "personality_type": [8, 3, 5], "mood": ["paranoid", "vigilant"], "location": ["police_station"] }, _on_npc_spawned ) ``` ### Chatting with NPCs #### Simple Chat with History ```gdscript # chat_with_history automatically tracks the conversation current_npc.chat_with_history( "Hello there!", # message 0.8, # temperature (0.0-1.0) 1500, # max_tokens false, # streaming _on_chat_response # callback ) ``` #### Advanced Chat API ```gdscript # Full control over messages current_npc.chat.completions( [ {"role": "system", "content": "You are in a tavern"}, {"role": "user", "content": "What's on the menu?"} ], 0.8, # temperature 2000, # max_tokens false, # streaming _on_chat_response ) ``` ### Streaming Responses Enable real-time streaming for a typewriter effect: ```gdscript func setup_streaming(): # Connect streaming signals npc.dialogue_chunk_received.connect(_on_chunk_received) npc.dialogue_stream_started.connect(_on_stream_started) npc.dialogue_stream_ended.connect(_on_stream_ended) # Enable streaming in chat npc.chat_with_history( "Tell me a story", 0.8, 1500, true, # streaming enabled! _on_final_response ) func _on_chunk_received(chunk: String): dialogue_box.text += chunk ``` ## Mood Transitions The GumYum API tracks NPC moods and can detect mood changes during conversations. Both streaming and non-streaming responses include mood transition data: ```gdscript func _on_dialogue_received(response): if response.has("choices") and response.choices.size() > 0: var content = response.choices[0]["message"]["content"] # Display the dialogue # Check for mood changes if response.has("mood_transition"): var mood_data = response.mood_transition var new_mood = mood_data.get("new_mood", "") var old_mood = mood_data.get("old_mood", "") var confidence = mood_data.get("confidence", 0.0) var reasoning = mood_data.get("reasoning", "") if new_mood and new_mood != old_mood: print("NPC mood changed from %s to %s (confidence: %.1f)" % [old_mood, new_mood, confidence]) print("Reason: %s" % reasoning) ``` Mood transition data includes: - `new_mood`: The NPC's current mood after this response - `old_mood`: The NPC's previous mood - `confidence`: How confident the AI is about this mood change (0.0-1.0) - `reasoning`: AI's explanation for why the mood changed - `stress_level`: Current stress level (1-9) ## NPC Properties Each `GumYumNPC` object has these properties: ```gdscript # Basic info npc.name # "Aldric" npc.profession # "blacksmith" npc.personality_type # 8 (Enneagram type) # Identity npc.npc_id # 123456789 npc.universe_id # "kingdom" npc.seed # 42 # Current state npc.get_location() # "forge" npc.get_mood() # "content" npc.get_stress_level() # 3 # Conversation history npc.chat_history # Array of messages ``` ## Universe Management (Limited) With API keys, universe management is limited: ```gdscript # List public universes (works with API keys) GumyumClient.universes.list_public( func(universes): for u in universes: print(u.name, " - ", u.description) ) # These methods require user authentication and will NOT work: # - universes.list() # List user's universes # - universes.list_user() # Same as list() # - universes.copy() # Copy a universe to user vault # - universes.get_universe() # Get universe details ``` **Note**: Games using API keys should hardcode their universe ID when spawning NPCs. ## Error Handling All callbacks receive either a valid response or an error dictionary: ```gdscript func _on_response(response): if response.has("error"): print("Error: ", response.error) # Handle error else: # Process successful response pass ``` ## Signals The client emits these signals: - `character_spawned(character: GumYumNPC)` - When an NPC is successfully spawned - `dialogue_received(response: String, context: Dictionary, mood_transition: Dictionary)` - Regular chat response with mood data - `dialogue_chunk_received(chunk: String)` - For streaming responses - `dialogue_stream_started` - When streaming begins - `dialogue_stream_ended(full_response: String, context: Dictionary, mood_transition: Dictionary)` - Streaming complete with mood data - `request_completed(endpoint: String, data: Dictionary)` - `request_failed(endpoint: String, error: String)` ## Examples Check the `examples/` folder for: - `QuickstartChat.gd` - Simple programmatic UI example (matches the docs quickstart) - `NpcChatExample.gd` + `.tscn` - Full scene-based example with streaming support ## Requirements - Godot 4.0 or later - GumYum API keys (get one at [npc.gumyum.com](https://npc.gumyum.com)) - Internet connection for API requests ## Support - [Discord Community](https://discord.com/invite/TZPmQdPj8a) - [GitLab Repository](https://git.unturf.com/engineering/gumyum/npc-clients)