feat(域模型v2+工作台): 聚合API game_create/game_workbench/scene_add/entity_add + 4个dspy端点
This commit is contained in:
parent
ade3b4be1e
commit
b9d4a650c5
140
scense_game/aggregation.py
Normal file
140
scense_game/aggregation.py
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""域模型 v2 聚合 API:game 为唯一聚合根。
|
||||||
|
|
||||||
|
- game_create:建游戏 → 自动建 1:1 空世界(world.game_id 回填)
|
||||||
|
- game_workbench:game 上下文全量查询(world/scenes/entities/scripts)
|
||||||
|
- scene_add / entity_add:强归属创建(scene 必属 game 的 world;entity 必属该 world 的 scene 或世界级)
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
|
||||||
|
from appPublic.uniqueID import getID
|
||||||
|
from appPublic.log import info, error, exception
|
||||||
|
from sqlor.dbpools import DBPools
|
||||||
|
|
||||||
|
|
||||||
|
def _get_dbname():
|
||||||
|
from ahserver.serverenv import ServerEnv
|
||||||
|
return ServerEnv().get_module_dbname('scense_game')
|
||||||
|
|
||||||
|
|
||||||
|
def _now():
|
||||||
|
import time
|
||||||
|
return time.strftime('%Y-%m-%d %H:%M:%S')
|
||||||
|
|
||||||
|
|
||||||
|
async def game_create(ns):
|
||||||
|
"""建游戏并自动创建 1:1 空世界。ns: {name, code?, description?, icon?}"""
|
||||||
|
name = (ns or {}).get('name') or ''
|
||||||
|
if not str(name).strip():
|
||||||
|
return {'code': 'PARAM_REQUIRED', 'message': '游戏名称必填', 'field': 'name'}
|
||||||
|
gid = getID()
|
||||||
|
wid = getID()
|
||||||
|
now = _now()
|
||||||
|
dbname = _get_dbname()
|
||||||
|
try:
|
||||||
|
async with DBPools().sqlorContext(dbname) as sor:
|
||||||
|
await sor.C('game', {
|
||||||
|
'id': gid, 'name': str(name).strip(),
|
||||||
|
'code': str((ns or {}).get('code') or ('G-' + gid[:8].upper())),
|
||||||
|
'description': str((ns or {}).get('description') or ''),
|
||||||
|
'icon': str((ns or {}).get('icon') or 'fa-gamepad'),
|
||||||
|
'status': 'draft', 'created_at': now, 'updated_at': now})
|
||||||
|
await sor.C('world', {
|
||||||
|
'id': wid, 'game_id': gid,
|
||||||
|
'name': str(name).strip() + ' 世界',
|
||||||
|
'code': 'W-' + gid[:8].upper(),
|
||||||
|
'description': '游戏「%s」的世界(1:1 自动创建)' % str(name).strip(),
|
||||||
|
'world_type': 'game', 'status': 'active',
|
||||||
|
'config_json': '{}', 'created_at': now, 'updated_at': now})
|
||||||
|
return {'success': True, 'data': {'game_id': gid, 'world_id': wid}}
|
||||||
|
except Exception as e:
|
||||||
|
exception('game_create: %s' % e)
|
||||||
|
return {'code': 'DB_ERROR', 'message': '创建游戏失败: %s' % e}
|
||||||
|
|
||||||
|
|
||||||
|
async def game_workbench(ns):
|
||||||
|
"""game 上下文全量:{game, world, scenes, entities, scripts}"""
|
||||||
|
gid = (ns or {}).get('game_id') or ''
|
||||||
|
if not gid:
|
||||||
|
return {'code': 'PARAM_REQUIRED', 'message': 'game_id 必填', 'field': 'game_id'}
|
||||||
|
dbname = _get_dbname()
|
||||||
|
try:
|
||||||
|
async with DBPools().sqlorContext(dbname) as sor:
|
||||||
|
g = await sor.R('game', {'id': gid})
|
||||||
|
if not g:
|
||||||
|
return {'code': 'NOT_FOUND', 'message': '游戏不存在'}
|
||||||
|
w = await sor.R('world', {'game_id': gid})
|
||||||
|
wid = w[0].id if w else None
|
||||||
|
scenes = await sor.R('scene', {'world_id': wid}) if wid else []
|
||||||
|
ents = await sor.R('entity', {'world_id': wid}) if wid else []
|
||||||
|
scripts = await sor.R('script_engine', {'game_id': gid}) if gid else []
|
||||||
|
return {'success': True, 'data': {
|
||||||
|
'game': dict(g[0]) if g else None,
|
||||||
|
'world': dict(w[0]) if w else None,
|
||||||
|
'scenes': [dict(s) for s in (scenes or [])],
|
||||||
|
'entities': [dict(e) for e in (ents or [])],
|
||||||
|
'scripts': [dict(s) for s in (scripts or [])]}}
|
||||||
|
except Exception as e:
|
||||||
|
exception('game_workbench: %s' % e)
|
||||||
|
return {'code': 'DB_ERROR', 'message': '查询失败: %s' % e}
|
||||||
|
|
||||||
|
|
||||||
|
async def scene_add(ns):
|
||||||
|
"""在游戏的世界下加场景。ns: {game_id, name, scene_type?}"""
|
||||||
|
gid = (ns or {}).get('game_id') or ''
|
||||||
|
name = (ns or {}).get('name') or ''
|
||||||
|
if not gid or not str(name).strip():
|
||||||
|
return {'code': 'PARAM_REQUIRED', 'message': 'game_id 与 name 必填'}
|
||||||
|
dbname = _get_dbname()
|
||||||
|
try:
|
||||||
|
async with DBPools().sqlorContext(dbname) as sor:
|
||||||
|
w = await sor.R('world', {'game_id': gid})
|
||||||
|
if not w:
|
||||||
|
return {'code': 'NOT_FOUND', 'message': '游戏无世界,先建游戏'}
|
||||||
|
sid = getID()
|
||||||
|
now = _now()
|
||||||
|
await sor.C('scene', {
|
||||||
|
'id': sid, 'world_id': w[0].id, 'name': str(name).strip(),
|
||||||
|
'code': 'S-' + sid[:8].upper(),
|
||||||
|
'description': str((ns or {}).get('description') or ''),
|
||||||
|
'scene_type': str((ns or {}).get('scene_type') or '0'),
|
||||||
|
'status': 'active', 'config_json': '{}',
|
||||||
|
'created_at': now, 'updated_at': now})
|
||||||
|
return {'success': True, 'data': {'scene_id': sid, 'world_id': w[0].id}}
|
||||||
|
except Exception as e:
|
||||||
|
exception('scene_add: %s' % e)
|
||||||
|
return {'code': 'DB_ERROR', 'message': '创建场景失败: %s' % e}
|
||||||
|
|
||||||
|
|
||||||
|
async def entity_add(ns):
|
||||||
|
"""在游戏世界内加实体。ns: {game_id, scene_id?(空=世界级实体), name, entity_type?, attributes_json?}"""
|
||||||
|
gid = (ns or {}).get('game_id') or ''
|
||||||
|
name = (ns or {}).get('name') or ''
|
||||||
|
if not gid or not str(name).strip():
|
||||||
|
return {'code': 'PARAM_REQUIRED', 'message': 'game_id 与 name 必填'}
|
||||||
|
dbname = _get_dbname()
|
||||||
|
try:
|
||||||
|
async with DBPools().sqlorContext(dbname) as sor:
|
||||||
|
w = await sor.R('world', {'game_id': gid})
|
||||||
|
if not w:
|
||||||
|
return {'code': 'NOT_FOUND', 'message': '游戏无世界'}
|
||||||
|
wid = w[0].id
|
||||||
|
scene_id = (ns or {}).get('scene_id') or ''
|
||||||
|
if scene_id:
|
||||||
|
sc = await sor.R('scene', {'id': scene_id})
|
||||||
|
if not sc or sc[0].world_id != wid:
|
||||||
|
return {'code': 'NOT_FOUND', 'message': '场景不属于该游戏的世界'}
|
||||||
|
eid = getID()
|
||||||
|
now = _now()
|
||||||
|
await sor.C('entity', {
|
||||||
|
'id': eid, 'world_id': wid, 'scene_id': scene_id or None,
|
||||||
|
'name': str(name).strip(), 'code': 'E-' + eid[:8].upper(),
|
||||||
|
'entity_type': str((ns or {}).get('entity_type') or '0'),
|
||||||
|
'status': 'active',
|
||||||
|
'attributes_json': (ns or {}).get('attributes_json') or '{}',
|
||||||
|
'created_at': now, 'updated_at': now})
|
||||||
|
return {'success': True, 'data': {'entity_id': eid, 'world_id': wid,
|
||||||
|
'scene_id': scene_id or None}}
|
||||||
|
except Exception as e:
|
||||||
|
exception('entity_add: %s' % e)
|
||||||
|
return {'code': 'DB_ERROR', 'message': '创建实体失败: %s' % e}
|
||||||
@ -1,5 +1,8 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""scense_game 游戏展示模块初始化:注册全部服务函数到 ServerEnv。"""
|
"""scense_game 游戏展示模块初始化:注册全部服务函数到 ServerEnv。"""
|
||||||
|
from scense_game.aggregation import (
|
||||||
|
game_create, game_workbench, scene_add, entity_add,
|
||||||
|
)
|
||||||
from scense_game.core import (
|
from scense_game.core import (
|
||||||
game_list_games, game_list_sessions, game_list_results,
|
game_list_games, game_list_sessions, game_list_results,
|
||||||
game_start_session, game_pause_session, game_resume_session,
|
game_start_session, game_pause_session, game_resume_session,
|
||||||
@ -14,6 +17,10 @@ def load_scense_game(env=None):
|
|||||||
from ahserver.serverenv import ServerEnv
|
from ahserver.serverenv import ServerEnv
|
||||||
if env is None:
|
if env is None:
|
||||||
env = ServerEnv()
|
env = ServerEnv()
|
||||||
|
env.game_create = game_create
|
||||||
|
env.game_workbench = game_workbench
|
||||||
|
env.scene_add = scene_add
|
||||||
|
env.entity_add = entity_add
|
||||||
env.game_list_games = game_list_games
|
env.game_list_games = game_list_games
|
||||||
env.game_list_sessions = game_list_sessions
|
env.game_list_sessions = game_list_sessions
|
||||||
env.game_list_results = game_list_results
|
env.game_list_results = game_list_results
|
||||||
|
|||||||
3
wwwroot/game/api/entity_add.dspy
Normal file
3
wwwroot/game/api/entity_add.dspy
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
result = await entity_add(dict(params_kw))
|
||||||
|
return json.dumps(result, ensure_ascii=False, default=str)
|
||||||
3
wwwroot/game/api/game_create.dspy
Normal file
3
wwwroot/game/api/game_create.dspy
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
result = await game_create(dict(params_kw))
|
||||||
|
return json.dumps(result, ensure_ascii=False, default=str)
|
||||||
3
wwwroot/game/api/game_workbench.dspy
Normal file
3
wwwroot/game/api/game_workbench.dspy
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
result = await game_workbench(dict(params_kw))
|
||||||
|
return json.dumps(result, ensure_ascii=False, default=str)
|
||||||
3
wwwroot/game/api/scene_add.dspy
Normal file
3
wwwroot/game/api/scene_add.dspy
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
result = await scene_add(dict(params_kw))
|
||||||
|
return json.dumps(result, ensure_ascii=False, default=str)
|
||||||
Loading…
x
Reference in New Issue
Block a user