# -*- coding: utf-8 -*- import json from odoo import http from odoo.http import request, Response def _json(data): """返回 UTF-8 JSON 响应(与 game_base 一致)。""" return Response( json.dumps(data, ensure_ascii=False), content_type='application/json; charset=utf-8', ) def _post_body(): try: raw = request.httprequest.get_data(as_text=True) or '{}' return json.loads(raw) except Exception: return {} class YtWorldApi(http.Controller): """前端沙盘记忆接口(JSON over HTTP)。auth=user:需已登录 Odoo。 前端统一带 ?db=game 且 credentials:'same-origin',故路由须为 type='http' 并以 _json 返回原始 JSON(与 game-api.js 的 fetch().json() 对齐)。""" @http.route('/yt_world/api/world', type='http', auth='user', methods=['GET', 'OPTIONS'], csrf=False) def world(self, **kw): """取或建当前用户世界,导出 seed + 地块覆盖。""" user = request.env.user rec = request.env['yt.world'].sudo().get_or_create_for_user(user) return _json(rec.export_state()) @http.route('/yt_world/api/tiles/save', type='http', auth='user', methods=['POST', 'OPTIONS'], csrf=False) def save_tiles(self, **kw): """增量覆盖保存地块。body: {"tiles": [...]}""" user = request.env.user world = request.env['yt.world'].sudo().search( [('user_id', '=', user.id)], limit=1) if not world: return _json({'ok': False, 'error': 'no_world'}) body = _post_body() tiles = body.get('tiles') or [] world.import_tiles(tiles) return _json({'ok': True, 'saved': len(tiles)}) @http.route('/yt_world/api/settings', type='http', auth='user', methods=['POST', 'OPTIONS'], csrf=False) def save_settings(self, **kw): """保存相机/UI 偏好。body: {"settings": {...}}""" user = request.env.user world = request.env['yt.world'].sudo().search( [('user_id', '=', user.id)], limit=1) body = _post_body() settings = body.get('settings') if world and settings is not None: world.settings = settings return _json({'ok': True})