Files
game/addons/yt_world/controllers/chest_api.py
T
2026-09-10 19:23:18 +08:00

130 lines
4.9 KiB
Python

# -*- coding: utf-8 -*-
import logging
from odoo import http
from odoo.http import request
_logger = logging.getLogger(__name__)
def _json(data):
headers = {
'Content-Type': 'application/json; charset=utf-8',
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type',
}
try:
origin = request.httprequest.headers.get('Origin')
if origin:
headers['Access-Control-Allow-Origin'] = origin
headers['Access-Control-Allow-Credentials'] = 'true'
else:
headers['Access-Control-Allow-Origin'] = '*'
except Exception:
headers['Access-Control-Allow-Origin'] = '*'
return request.make_response(
__import__('json').dumps(data, ensure_ascii=False), headers=headers)
def _post_body():
try:
raw = request.httprequest.get_data(as_text=True) or '{}'
return __import__('json').loads(raw)
except Exception:
return {}
def _require_user():
uid = request.session.uid
if not uid:
return {'ok': False, 'error': 'auth'}
user = request.env['res.users'].sudo().browse(uid)
if not user.exists() or not user.active:
return {'ok': False, 'error': 'auth'}
return None
def _get_world():
user = request.env['res.users'].sudo().browse(request.session.uid) \
if request.session.uid else request.env['res.users']
if not user.exists():
return None
return request.env['yt.world'].sudo().get_or_create_for_user(user)
class YtWorldChestApi(http.Controller):
# ── 列表:当前世界某地块的活跃宝箱 ──
@http.route('/yt_world/api/chests', type='http', auth='public',
methods=['GET', 'OPTIONS'], csrf=False)
def list_chests(self, **kw):
auth_err = _require_user()
if auth_err:
return _json(auth_err)
world = _get_world()
if not world:
return _json({'ok': False, 'error': 'no_world'})
domain = [('world_id', '=', world.id), ('state', '=', 'active')]
q = kw.get('q'); r = kw.get('r')
if q is not None and r is not None:
# tile_ref 是 Json,按字典值过滤:保留该地块的宝箱
recs = request.env['yt.world.chest'].sudo().search(domain)
recs = recs.filtered(lambda c: (c.tile_ref or {}).get('q') == int(q)
and (c.tile_ref or {}).get('r') == int(r))
else:
recs = request.env['yt.world.chest'].sudo().search(domain)
out = [{
'id': c.id,
'cell_i': c.cell_i, 'cell_j': c.cell_j,
'tier': c.tier, 'reward_type': c.reward_type,
'reward_amount': c.reward_amount, 'state': c.state,
'tile_ref': c.tile_ref or {},
} for c in recs]
return _json({'ok': True, 'chests': out})
# ── 生成:测试期前端每 10s 调一次;生产可挂 ir.cron ──
@http.route('/yt_world/api/chest/generate', type='http', auth='public',
methods=['POST', 'OPTIONS'], csrf=False)
def generate_chest(self, **kw):
auth_err = _require_user()
if auth_err:
return _json(auth_err)
world = _get_world()
if not world:
return _json({'ok': False, 'error': 'no_world'})
body = _post_body()
q = body.get('q'); r = body.get('r')
grid_n = int(body.get('grid_n') or 20)
q = int(q) if q is not None else None
r = int(r) if r is not None else None
chest = request.env['yt.world.chest'].sudo().generate_for_world(
world, q=q, r=r, grid_n=grid_n)
if not chest:
return _json({'ok': False, 'error': 'no_slot'})
return _json({'ok': True, 'chest': {
'id': chest.id, 'cell_i': chest.cell_i, 'cell_j': chest.cell_j,
'tier': chest.tier, 'reward_type': chest.reward_type,
'reward_amount': chest.reward_amount, 'state': chest.state,
'tile_ref': chest.tile_ref or {},
}})
# ── 开启:前端生物到达宝箱后调用 ──
@http.route('/yt_world/api/chest/claim', type='http', auth='public',
methods=['POST', 'OPTIONS'], csrf=False)
def claim_chest(self, **kw):
auth_err = _require_user()
if auth_err:
return _json(auth_err)
world = _get_world()
if not world:
return _json({'ok': False, 'error': 'no_world'})
body = _post_body()
cid = body.get('chest_id')
creature_cid = body.get('cid') or body.get('creature_cid')
chest = request.env['yt.world.chest'].sudo().browse(int(cid) if cid else 0)
if not chest.exists():
return _json({'ok': False, 'error': 'no_chest'})
if chest.world_id.id != world.id:
return _json({'ok': False, 'error': 'forbidden'})
res = chest.claim(creature_cid or '')
return _json(res)