# -*- coding: utf-8 -*- from odoo import models, fields import random class YtWorld(models.Model): """玩家世界:每个用户一条。seed 再生基础地图,tile_ids 存被改地块。""" _name = 'yt.world' _description = '玩家世界' name = fields.Char(string='世界名称', translate=True) user_id = fields.Many2one('res.users', string='拥有者', required=True, ondelete='cascade', index=True) seed = fields.Integer(string='生成种子', required=True, index=True) world_version = fields.Integer(string='生成算法版本', default=1) settings = fields.Json(string='世界设置') # 相机位/缩放/UI 偏好 tile_ids = fields.One2many('yt.world.tile', 'world_id', string='地表地块') created_at = fields.Datetime(string='创建时间', default=fields.Datetime.now) last_active = fields.Datetime(string='最后活跃') # ---------- 接口方法(供 controller 调用) ---------- def get_or_create_for_user(self, user): """取当前用户的世界;没有则按随机 seed 新建。""" rec = self.search([('user_id', '=', user.id)], limit=1) if not rec: rec = self.create({ 'user_id': user.id, 'seed': random.randint(1, 2_000_000_000), 'name': '我的世界', }) rec.last_active = fields.Datetime.now() return rec def export_state(self): """导出前端需要的世界状态:seed + 地块覆盖列表。""" self.ensure_one() tiles = [] for t in self.tile_ids: tiles.append({ 'q': t.q, 'r': t.r, 'terrain': t.terrain or None, 'height': t.height or None, 'flags': t.flags or {}, 'micro_world_id': t.micro_world_id.id if t.micro_world_id else None, }) return { 'world_id': self.id, 'seed': self.seed, 'world_version': self.world_version, 'settings': self.settings or {}, 'tiles': tiles, } def import_tiles(self, tiles): """增量覆盖:upsert 地块。terrain/height/flags 全回退底图则删除覆盖行。""" self.ensure_one() tile_model = self.env['yt.world.tile'] for tv in (tiles or []): q, r = tv.get('q'), tv.get('r') if q is None or r is None: continue terrain = tv.get('terrain') height = tv.get('height') flags = tv.get('flags') # 全部回退底图 → 删覆盖行,保持最小集(种子+增量覆盖原则) if not terrain and height is None and not (flags or {}): existing = tile_model.search([ ('world_id', '=', self.id), ('q', '=', q), ('r', '=', r)]) if existing: existing.unlink() continue vals = {} if terrain is not None: vals['terrain'] = terrain if height is not None: vals['height'] = height if flags is not None: vals['flags'] = flags existing = tile_model.search([ ('world_id', '=', self.id), ('q', '=', q), ('r', '=', r)]) if existing: existing.write(vals) else: vals.update({'q': q, 'r': r, 'world_id': self.id}) tile_model.create(vals) # create 钩子自动建微观占位 self.last_active = fields.Datetime.now()