game/addons/yt_world/models/yt_world.py

90 lines
3.6 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 -*-
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,
'name': self.name,
'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()