game/addons/yt_world/controllers/world_api.py
李鹏宇 e405eb7a07 feat: 网站布局统一化+公告卡片重做+地形素材归类+加载动画升级+底部栏拆分
- 网站 7 个页签统一内边距/宽度/滚动方式,去掉重复页头
- 公告卡片改为图文大卡(支持后台 image/title/pinned 字段)
- assets/terrain/ 拆 6 个子目录并同步 manifest + TERRAIN_ASSETS
- 删除 assets/art/(transition 图片已清空)
- 加载界面增加随机过渡背景图 + 深色压暗层
- 底部栏建造按钮拆为地形/移动/高度/管理 4 个独立按钮
- 侧面板改为从底部向上展开(WorldBox 风格)
- 删除视频背景文件(已回滚为静态 JPG)
- 新增 wc1.js(六边形地图渲染)、wc2.js(导航控件)
2026-07-24 23:39:49 +08:00

89 lines
3.3 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
import logging
import re
from odoo import http
from odoo.http import request, Response
_logger = logging.getLogger(__name__)
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})
@http.route('/yt_world/api/world/rename', type='http', auth='user',
methods=['POST', 'OPTIONS'], csrf=False)
def rename_world(self, **kw):
"""修改当前用户世界名称。body: {"name": "..."}
校验:trim 后 1-24 字符,禁控制字符,空白正常允许。"""
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()
name = (body.get('name') or '').strip()
if not name:
return _json({'ok': False, 'error': 'empty'})
if len(name) > 24:
return _json({'ok': False, 'error': 'too_long'})
if re.search(r'[\x00-\x1f\x7f]', name):
return _json({'ok': False, 'error': 'invalid_char'})
old = world.name
world.name = name
_logger.info('yt.world rename uid=%s %r -> %r', user.id, old, name)
return _json({'ok': True, 'name': name})