game/addons/game_ai_npc/controllers/npc_api.py

125 lines
5.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- coding: utf-8 -*-
import json
from odoo import http
from odoo.http import request
from datetime import datetime
def _json(data):
return request.make_response(
json.dumps(data, ensure_ascii=False, default=str),
headers=[('Content-Type', 'application/json; charset=utf-8')]
)
class GameNpcApi(http.Controller):
# ── NPC 列表 ──
@http.route('/game/api/npcs', type='http', auth='public', methods=['GET'], csrf=False)
def npc_list(self, **kw):
"""返回所有活跃 NPC含当前活动和关键状态"""
npcs = request.env['game.npc'].sudo().search_read(
[('active', '=', True)],
['id', 'name', 'title', 'code', 'archetype', 'personality',
'current_activity', 'energy', 'hunger', 'safety', 'mood',
'mood_label', 'activity_label', 'goal_progress', 'current_goal',
'current_area', 'relationship_count', 'recent_log', 'tick_count',
'affiliation'],
order='sequence, id'
)
for n in npcs:
n['archetype_label'] = dict(
request.env['game.npc']._fields['archetype'].selection
).get(n['archetype'], n['archetype'])
return _json({'npcs': npcs})
# ── NPC 详情 ──
@http.route('/game/api/npc/<int:npc_id>', type='http', auth='public', methods=['GET'], csrf=False)
def npc_detail(self, npc_id, **kw):
"""NPC 详情(含关系网 + 最近行为 + 知识)。"""
Npc = request.env['game.npc'].sudo()
npc = Npc.browse(npc_id)
if not npc.exists():
return _json({'error': 'NPC 不存在'})
data = npc.read([
'id', 'name', 'title', 'code', 'archetype', 'personality',
'origin', 'bio', 'current_activity', 'energy', 'hunger', 'safety',
'mood', 'mood_label', 'activity_label', 'goal_progress', 'current_goal',
'goal_detail', 'current_area', 'tick_count', 'last_tick',
'affiliation',
])
if not data:
return _json({'error': 'NPC 不存在'})
data = data[0]
# 关系网
rels = request.env['game.npc.relationship'].sudo().search_read(
[('npc_id', '=', npc_id)],
['target_npc_id', 'affinity', 'status', 'last_interaction'],
order='affinity desc'
)
data['relationships'] = [{
'target_id': r['target_npc_id'][0] if r['target_npc_id'] else None,
'target_name': r['target_npc_id'][1] if r['target_npc_id'] else '',
'affinity': r['affinity'],
'status': r['status'],
} for r in rels]
# 最近行为20 条)
logs = request.env['game.npc.behavior.log'].sudo().search_read(
[('npc_id', '=', npc_id)],
['tick_time', 'activity', 'activity_label', 'location', 'summary', 'target_npc_id'],
limit=20, order='tick_time desc'
)
data['recent_behaviors'] = [{
'time': str(l['tick_time']),
'activity': l['activity'],
'label': l['activity_label'],
'location': l['location'] or '',
'summary': l['summary'],
} for l in logs]
# 知识
knowledge = request.env['game.npc.knowledge'].sudo().search_read(
[('npc_id', '=', npc_id)],
['topic', 'content', 'accuracy', 'source'],
order='sequence, id'
)
data['knowledge'] = knowledge
return _json(data)
# ── NPC 关系网 ──
@http.route('/game/api/npc/<int:npc_id>/relationships', type='http', auth='public', methods=['GET'], csrf=False)
def npc_relationships(self, npc_id, **kw):
rels = request.env['game.npc.relationship'].sudo().search_read(
[('npc_id', '=', npc_id)],
['target_npc_id', 'affinity', 'status', 'last_interaction', 'interaction_count'],
order='affinity desc'
)
return _json({'relationships': [{
'target_id': r['target_npc_id'][0] if r['target_npc_id'] else None,
'target_name': r['target_npc_id'][1] if r['target_npc_id'] else '',
'affinity': r['affinity'],
'status': r['status'],
'last_interaction': str(r['last_interaction']),
'interaction_count': r['interaction_count'],
} for r in rels]})
# ── 主动触发单个 NPC Tick ──
@http.route('/game/api/npc/<int:npc_id>/tick', type='http', auth='user', methods=['POST'], csrf=False)
def npc_tick(self, npc_id, **kw):
npc = request.env['game.npc'].sudo().browse(npc_id)
if not npc.exists():
return _json({'error': 'NPC 不存在'})
npc.action_tick()
return _json({'ok': True, 'name': npc.name, 'tick_count': npc.tick_count,
'activity': npc.activity_label, 'mood': npc.mood_label})
# ── 批量 Tick ──
@http.route('/game/api/npc/tick-all', type='http', auth='user', methods=['POST'], csrf=False)
def npc_tick_all(self, **kw):
count = request.env['game.npc'].sudo().cron_batch_tick(batch_size=100)
return _json({'ok': True, 'ticked': count})