Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ versioned release tag yet, so entries are organized as pre-alpha snapshots.
- State of Mind and behavior-tendency backend expansion for issue #134: NPC
heartbeats now track fear, confidence, and current goal, personality-derived
tendencies now include social initiative, risk tolerance, idle radius, and
approach style, and model decision context receives a compact runtime state
card for more varied NPC behavior.
approach style, model decision context receives a compact runtime state card,
and Unity debug HUD DTOs can display the expanded runtime state.
- Linux headless dedicated server build path for issue #36: Unity now has a
`BuildLinuxDedicatedServer` editor build method, `tools/build-unity-linux-server.ps1`
runs batchmode/nographics/server builds, and setup docs define prerequisites,
Expand Down
3 changes: 3 additions & 0 deletions Unity/Assets/_SecondSpawn/Scripts/AI/AgentContextDto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,10 @@ public sealed class FrameHeartbeatDto
public string fallback_state;
public string mood;
public int stress;
public int fear;
public int confidence;
public string dominant_need;
public string current_goal;
public string last_trigger;
public string last_plan_summary;
}
Expand Down
7 changes: 5 additions & 2 deletions Unity/Assets/_SecondSpawn/Scripts/UI/HUDController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -721,8 +721,9 @@ private string BuildAgentActivityText(AgentContextDto context)
builder.AppendLine($"Offline {FormatSeconds(runtime.offline_seconds)} | Last {FormatTimestamp(runtime.last_activity_at)}");
if (body.heartbeat != null)
{
builder.AppendLine($"Mind {Fallback(body.heartbeat.mood, "steady")} | Stress {body.heartbeat.stress}/10");
builder.AppendLine($"Mind {Fallback(body.heartbeat.mood, "steady")} | Stress {body.heartbeat.stress}/10 | Fear {body.heartbeat.fear}/10 | Conf {body.heartbeat.confidence}/10");
builder.AppendLine($"Need {TrimForHud(Fallback(body.heartbeat.dominant_need, "preserve BodyTime"), 58)}");
builder.AppendLine($"Goal {TrimForHud(Fallback(body.heartbeat.current_goal, "stay alive"), 58)}");
}

return builder.ToString();
Expand Down Expand Up @@ -1358,7 +1359,9 @@ private void DrawStateOfMind(FrameHeartbeatDto heartbeat)
return;
}

GUILayout.Label($"Mind {Fallback(heartbeat.mood, "steady")} | Stress {heartbeat.stress}/10 | Need {TrimForHud(Fallback(heartbeat.dominant_need, "preserve BodyTime"), 56)}", _labelStyle);
GUILayout.Label($"Mind {Fallback(heartbeat.mood, "steady")} | Stress {heartbeat.stress}/10 | Fear {heartbeat.fear}/10 | Conf {heartbeat.confidence}/10", _labelStyle);
GUILayout.Label($"Need: {TrimForHud(Fallback(heartbeat.dominant_need, "preserve BodyTime"), 76)}", _wrapStyle);
GUILayout.Label($"Goal: {TrimForHud(Fallback(heartbeat.current_goal, "stay alive and preserve context"), 76)}", _wrapStyle);
GUILayout.Label($"Plan: {TrimForHud(Fallback(heartbeat.last_plan_summary, heartbeat.last_action_summary, "No plan yet."), 92)}", _wrapStyle);
}

Expand Down
53 changes: 53 additions & 0 deletions backend/nakama/tests/supabase_custom_auth.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,59 @@ assert.equal(seededNpcs.npcs[7].body.visual_variant, 17);
assert.equal(seededNpcs.npcs[8].body.visual_variant, 15);
assert.ok(harness.storage.get(storageKey("user-1", "secondspawn_actor", "world_profile:npc-synthetic-sentinel-0101")));

const cautiousTendencyProfile = JSON.parse(harness.registeredRpcs.get("secondspawn_actor_profile_get")(
{ userId: "user-1", env: {} },
harness.logger,
harness.nk,
JSON.stringify({
actor_id: "npc-tendency-cautious",
display_name: "Cautious Tendency",
story: { role: "relay yard drifter" },
characteristics: { courage: 2, discipline: 8, empathy: 7, curiosity: 1, aggression: 1, sociability: 1 }
})
));
const socialTendencyProfile = JSON.parse(harness.registeredRpcs.get("secondspawn_actor_profile_get")(
{ userId: "user-1", env: {} },
harness.logger,
harness.nk,
JSON.stringify({
actor_id: "npc-tendency-social",
display_name: "Social Tendency",
story: { role: "relay yard drifter" },
characteristics: { courage: 6, discipline: 3, empathy: 7, curiosity: 9, aggression: 1, sociability: 9 }
})
));
assert.ok(socialTendencyProfile.body.behavior_tendencies.talk_frequency > cautiousTendencyProfile.body.behavior_tendencies.talk_frequency);
assert.ok(socialTendencyProfile.body.behavior_tendencies.social_initiative > cautiousTendencyProfile.body.behavior_tendencies.social_initiative);
assert.ok(socialTendencyProfile.body.behavior_tendencies.idle_radius_meters > cautiousTendencyProfile.body.behavior_tendencies.idle_radius_meters);
assert.ok(cautiousTendencyProfile.body.behavior_tendencies.approach_style.length > 0);

const malformedHeartbeatProfile = JSON.parse(harness.registeredRpcs.get("secondspawn_actor_profile_get")(
{ userId: "user-1", env: {} },
harness.logger,
harness.nk,
JSON.stringify({
actor_id: "npc-malformed-heartbeat",
display_name: "Malformed Heartbeat",
heartbeat: {
mood: "",
stress: -5,
fear: 99,
confidence: -8,
dominant_need: "",
current_goal: "",
last_trigger: "",
last_plan_summary: ""
}
})
));
assert.equal(malformedHeartbeatProfile.body.heartbeat.mood, "steady");
assert.equal(malformedHeartbeatProfile.body.heartbeat.stress, 0);
assert.equal(malformedHeartbeatProfile.body.heartbeat.fear, 10);
assert.equal(malformedHeartbeatProfile.body.heartbeat.confidence, 0);
assert.equal(malformedHeartbeatProfile.body.heartbeat.dominant_need, "preserve BodyTime");
assert.equal(malformedHeartbeatProfile.body.heartbeat.current_goal, "stay alive and preserve useful context");

const playerChatEvent = JSON.parse(harness.registeredRpcs.get("secondspawn_npc_player_chat_event")(
{ userId: "user-1", env: {} },
harness.logger,
Expand Down
Loading