chore: novel auto-sync, codex data seeding, story page font slider UI, topbar reorder, codex/codex filter/search/sticky refinements

This commit is contained in:
李鹏宇
2026-07-28 21:42:34 +08:00
parent c267c0143b
commit b41d25a545
82 changed files with 4992 additions and 1277 deletions
+1
View File
@@ -8,6 +8,7 @@
'data': [
'security/ir.model.access.csv',
'data/game_base_data.xml',
'data/story_cron.xml',
'views/codex_views.xml',
'views/rule_category_views.xml',
'views/rule_views.xml',
+3 -239
View File
@@ -166,191 +166,6 @@
<field name="body_html"><![CDATA[<p>宇森官网第一阶段上线:介绍 / 规则 / 图鉴 / 论坛 / 公告 五块,单页切换呈现。欢迎园丁们入驻。</p>]]></field>
</record>
<!-- ============ 页面板块 ============ -->
<!-- 特色 -->
<record id="page_features" model="game.page">
<field name="key">features</field>
<field name="title">游戏特色</field>
<field name="subtitle">CORE FEATURES</field>
<field name="sequence">10</field>
</record>
<record id="page_features_item_1" model="game.page.item">
<field name="page_id" ref="page_features"/>
<field name="sequence">10</field>
<field name="icon">🌐</field>
<field name="title">垂直五层世界</field>
<field name="desc">从地心熔岩到陨石星空,文明在五个垂直切面中同时生长,每一层都有独立的生态、资源与事件池。</field>
</record>
<record id="page_features_item_2" model="game.page.item">
<field name="page_id" ref="page_features"/>
<field name="sequence">20</field>
<field name="icon">🌱</field>
<field name="title">自发演化</field>
<field name="desc">不是脚本,不是关卡。文明自己生长、分裂、兼并、飞升——每一次开局都是一部独一无二的编年史。</field>
</record>
<record id="page_features_item_3" model="game.page.item">
<field name="page_id" ref="page_features"/>
<field name="sequence">30</field>
<field name="icon">🧑‍🌾</field>
<field name="title">园丁视角</field>
<field name="desc">你不是英雄,也不是上帝。你是园丁——播种灵气、引导势力、守望文明,在关键节点轻推一把,让世界自洽前行。</field>
</record>
<record id="page_features_item_4" model="game.page.item">
<field name="page_id" ref="page_features"/>
<field name="sequence">40</field>
<field name="icon">⚖️</field>
<field name="title">三维等级联动</field>
<field name="desc">世界等级定舞台上限,势力等级定群体进度,角色等级定个体极限。三者交叉构成无限策略空间。</field>
</record>
<record id="page_features_item_5" model="game.page.item">
<field name="page_id" ref="page_features"/>
<field name="sequence">50</field>
<field name="icon">💰</field>
<field name="title">六档货币体系</field>
<field name="desc">从墟铢到元玺,百进制兑换贯穿五层世界。跨层贸易、资源调度、神器交易构成完整经济闭环。</field>
</record>
<record id="page_features_item_6" model="game.page.item">
<field name="page_id" ref="page_features"/>
<field name="sequence">60</field>
<field name="icon">🎭</field>
<field name="title">活的个体</field>
<field name="desc">每个 NPC 都有独立的天赋、性格与成长轨迹。英雄在历练中觉醒,传奇在时间中自发生成,无人是棋子。</field>
</record>
<!-- 介绍 -->
<record id="page_intro" model="game.page">
<field name="key">intro</field>
<field name="title">关于宇森</field>
<field name="subtitle">ABOUT YUSEN</field>
<field name="sequence">15</field>
<field name="body_html"><![CDATA[<p>宇森,是一颗会自己呼吸的种子。</p>
<p>你播种的不是一个角色,而是一个<b style="color:#fff">世界</b>——从地心熔岩到陨石星空,五层垂直切面层层相托,文明在其中自发地生长、分裂、兼并、飞升。没有脚本替你演绎剧情,没有关卡替你定义胜利,每一次开局都是一部独一无二的编年史。</p>
<p>我们相信,最好的模拟不在于你操控了多少,而在于你<b style="color:#fff">见证</b>了多少。所以宇森把「玩家」重新定义为<b style="color:var(--gold)">园丁</b>:你不能命令谁,却可以改变土壤、调节灵气、在关键节点轻轻推一把。世界的走向,由无数个体的选择汇聚而成,而你只是其中一股温柔的力。</p>
<p style="margin-top:22px;color:var(--gold);font-style:italic;">往下翻,看这颗种子如何长成一片森林。</p>]]></field>
</record>
<record id="page_intro_item_1" model="game.page.item">
<field name="page_id" ref="page_intro"/>
<field name="sequence">10</field>
<field name="icon">🌍</field>
<field name="title">一颗会呼吸的世界</field>
<field name="desc">五层垂直世界,文明自发演化,没有固定剧情与通关条件。</field>
</record>
<record id="page_intro_item_2" model="game.page.item">
<field name="page_id" ref="page_intro"/>
<field name="sequence">20</field>
<field name="icon">🧑‍🌾</field>
<field name="title">你是园丁,不是上帝</field>
<field name="desc">改变土壤与灵气,在关键节点轻推一把,而非发号施令。</field>
</record>
<!-- 背景 -->
<record id="page_background" model="game.page">
<field name="key">background</field>
<field name="title">世界起源</field>
<field name="subtitle">BACKGROUND</field>
<field name="sequence">20</field>
<field name="body_html"><![CDATA[<p>天地初开,混沌未分。一缕灵气自地心涌出,沿垂直切面向上攀爬——穿透岩层、跨越地表、掠过云海、直抵星空。五层世界自此苏醒。</p>
<p>地表层最先活过来。灵气稀薄,但足够点燃文明的火种。各族散居荒野,狩猎采集,以血缘结群,在蒙昧的凡土上挣扎求生。这是<b style="color:#fff">凡墟</b>。</p>
<p>而后灵气渐浓,天地共振。聚落涌现,分工萌芽,物物交换催生最早的势力。灵启的时代,文明开始有了形状。</p>
<p>再往后,是兼并、是征伐、是道统与造物的竞逐。<b style="color:#fff">玄界</b>的大地上,多元族群共治的完整疆域成形,传奇事件如潮涌来。</p>
<p>直到有一天,有人掘穿了地表之下的黑暗,有人驾着浮空石飞上了云海。地下深渊与浩瀚星空同时向文明敞开——<b style="color:#fff">穹冥</b>时代,天地上下尽数纳入管辖。</p>
<p>最终,顶尖文明勘破了这片天地的诞生本源。他们追溯灵气的源头,在地心深处找到了答案。飞升、轮回、更高维度的演化实验——<b style="color:#fff">溯元</b>,不是终点,而是新的起点。</p>
<p style="margin-top:22px;color:var(--gold);font-style:italic;">而你,是这一切的园丁。</p>]]></field>
</record>
<record id="page_bg_layer_1" model="game.page.item">
<field name="page_id" ref="page_background"/>
<field name="sequence">10</field>
<field name="icon">✦</field>
<field name="title">星空层</field>
<field name="desc">陨石科技带 · 穹鎏产地</field>
</record>
<record id="page_bg_layer_2" model="game.page.item">
<field name="page_id" ref="page_background"/>
<field name="sequence">20</field>
<field name="icon">✦</field>
<field name="title">天空层</field>
<field name="desc">云朵地基块 · 浮空城邦</field>
</record>
<record id="page_bg_layer_3" model="game.page.item">
<field name="page_id" ref="page_background"/>
<field name="sequence">30</field>
<field name="icon">✦</field>
<field name="title">地表层</field>
<field name="desc">文明发源地 · 主舞台</field>
</record>
<record id="page_bg_layer_4" model="game.page.item">
<field name="page_id" ref="page_background"/>
<field name="sequence">40</field>
<field name="icon">✦</field>
<field name="title">地下层</field>
<field name="desc">矿脉深渊 · 冥玉产地</field>
</record>
<record id="page_bg_layer_5" model="game.page.item">
<field name="page_id" ref="page_background"/>
<field name="sequence">50</field>
<field name="icon">✦</field>
<field name="title">地心层</field>
<field name="desc">本源之地 · 元玺凝聚</field>
</record>
<!-- 说明 -->
<record id="page_notes" model="game.page">
<field name="key">notes</field>
<field name="title">制度说明</field>
<field name="subtitle">HOW THE WORLD WORKS</field>
<field name="sequence">25</field>
<field name="body_html"><![CDATA[<p>宇森的世界由三套相互独立的等级体系共同驱动,它们彼此加成,又彼此制约:</p>
<p><b style="color:#fff">世界等级</b>是舞台的上限——它决定这片土地上「能发生什么」。从凡墟到溯元,每一级跃迁都会解锁更深的内容层(更深的地下、更远的星空)与更厚的事件池。</p>
<p><b style="color:#fff">势力等级</b>是群体的进度——它决定文明「能调动什么」。聚落、联盟到多维联合体,等级越高,可调度资源与外交权重越大。</p>
<p><b style="color:#fff">角色等级</b>是个体的成长——它决定一个生命「能做成什么」。从无名萌新到超越生死的永恒,英雄在历练中觉醒。</p>
<p>而贯穿三者的,是<b style="color:var(--gold)">六档货币</b>:从凡俗墟铢到本源元玺,百进制兑换构成完整经济闭环,决定文明「能交换什么」。</p>
<p>园丁的核心策略,便是在这四方之间分配有限的引导资源,让文明自洽地向上演化——每一级提升,世界都因此越活越厚。</p>]]></field>
</record>
<record id="page_notes_item_1" model="game.page.item">
<field name="page_id" ref="page_notes"/>
<field name="sequence">10</field>
<field name="icon">🌐</field>
<field name="title">世界等级</field>
<field name="desc">舞台上限:决定能发生什么。凡墟 → 灵启 → 玄界 → 穹冥 → 溯元。</field>
</record>
<record id="page_notes_item_2" model="game.page.item">
<field name="page_id" ref="page_notes"/>
<field name="sequence">20</field>
<field name="icon">🏛️</field>
<field name="title">势力等级</field>
<field name="desc">群体进度:决定能调动什么。墟族 → 灵聚 → 玄邑 → 冥朝 → 穹统 → 溯盟。</field>
</record>
<record id="page_notes_item_3" model="game.page.item">
<field name="page_id" ref="page_notes"/>
<field name="sequence">30</field>
<field name="icon">⚔️</field>
<field name="title">角色等级</field>
<field name="desc">个体成长:决定能做成什么。萌新 → …… → 永恒,十二阶序。</field>
</record>
<record id="page_notes_item_4" model="game.page.item">
<field name="page_id" ref="page_notes"/>
<field name="sequence">40</field>
<field name="icon">💰</field>
<field name="title">六档货币</field>
<field name="desc">经济闭环:决定能交换什么。墟铢 → 灵币 → 玄锭 → 冥玉 → 穹鎏 → 元玺。</field>
</record>
<!-- 致玩家 -->
<record id="page_letter" model="game.page">
<field name="key">letter</field>
<field name="title">致园丁</field>
<field name="subtitle">A LETTER TO GARDENERS</field>
<field name="sequence">30</field>
<field name="body_html"><![CDATA[<p>致每一位踏入宇森的园丁:</p>
<p>感谢你来到这里。</p>
<p>宇森不是一款传统的策略游戏。这里没有关卡,没有通关,没有固定的胜利条件。我们想做的,是一个<span class="hl">会自己呼吸的世界</span>——你播下一颗种子,它自己长成一片森林;你引导一个族群,它自己走出一段历史。</p>
<p>你是园丁,不是上帝。你不能命令谁去做什么,但你可以改变土壤、调节灵气、在关键节点轻轻推一把。文明的走向由无数个体的选择汇聚而成,而你只是其中一股温柔的力。</p>
<p>这个世界有五层。从地心到星空,每一层都有自己的生态和故事。文明会从地表的凡墟开始,一路向上向下生长,直到触及世界的本源。这个过程可能很慢,也可能充满意外——但那正是我们想要的。</p>
<p>我们还在生长。宇森目前处于早期阶段,很多系统仍在打磨。但你看到的每一个种族、每一件神器、每一段传奇事件,都是这个世界真实存在的一部分。它们会随着版本的推进越来越厚,越来越活。</p>
<p>如果你在这里找到了哪怕一刻的沉浸感,那就是我们最大的成功。</p>
<p>欢迎播种。</p>]]></field>
</record>
<!-- ============ 论坛种子(登录后可见) ============ -->
<record id="thread_welcome" model="game.forum.thread">
<field name="name">【公告】宇森官网第一阶段上线,欢迎园丁们入驻</field>
@@ -404,59 +219,8 @@
<field name="body_html"><![CDATA[<p>剧情站正式上线!首卷《园丁手记·凡墟篇》已开放阅读,记录灵气初醒、第一株苗与聚落第一缕光的蒙昧年代。前往导航「剧情」即可翻阅。</p>]]></field>
</record>
<!-- ============ 剧情(小说)种子 ============ -->
<record id="story_vol_fanxu" model="game.story.volume">
<field name="name">第一卷 · 园丁手记·凡墟篇</field>
<field name="sequence">10</field>
<field name="intro"><![CDATA[<p>凡墟篇·园丁手记。灵气初醒的蒙昧年代,文明的种子刚刚落进泥土。</p>]]></field>
</record>
<record id="story_ch_fx_1" model="game.story.chapter">
<field name="volume_id" ref="story_vol_fanxu"/>
<field name="sequence">10</field>
<field name="name">楔子 · 灵气初醒</field>
<field name="body_html"><![CDATA[<p>天地初开的时候,没有名字。</p>
<p>只有一团混沌的灵气,从地心最深处艰难地往上爬——它穿过滚烫的岩浆,穿过沉默的岩层,在某个谁也说不清的时刻,第一次触到了冰冷的地表。</p>
<p>那一刻,凡土醒了。</p>
<p>后来的人把它叫做「灵气初醒」。但在当时,没有谁记得这一刻。只有风,把第一缕微弱的生机,吹向了荒野里零散的族群。</p>]]></field>
</record>
<record id="story_ch_fx_2" model="game.story.chapter">
<field name="volume_id" ref="story_vol_fanxu"/>
<field name="sequence">20</field>
<field name="name">第一章 · 第一株苗</field>
<field name="body_html"><![CDATA[<p>园丁第一次伸手,是在一片荒芜的斜坡上。</p>
<p>他什么也没做,只是把掌心的灵气,轻轻按进了一粒埋在石缝里的种子。没有咒语,没有仪式——只是给予,然后等待。</p>
<p>三天后,一株嫩绿的苗破土而出。它不知道自己被谁照料,也不在乎。它只是生长,像这个世界本该有的样子。</p>
<p>园丁看着那点绿色,忽然明白了自己该做的事:不是统治,不是创造,而是——让生长发生。</p>]]></field>
</record>
<record id="story_ch_fx_3" model="game.story.chapter">
<field name="volume_id" ref="story_vol_fanxu"/>
<field name="sequence">30</field>
<field name="name">第二章 · 聚落的第一缕光</field>
<field name="body_html"><![CDATA[<p>苗活下来之后,荒野里有了第二个、第三个生命。</p>
<p>零散的族群循着灵气的痕迹聚拢。他们不再只是狩猎采集,开始用碎石垒出简陋的屋舍,用兽骨交换 surplus 的猎物。第一缕属于「文明」的光,在凡墟的夜色里亮起。</p>
<p>园丁没有现身。他只是把灵气的浓度,往聚落的方向,悄悄调浓了半分。</p>]]></field>
</record>
<record id="story_vol_lingqi" model="game.story.volume">
<field name="name">第二卷 · 园丁手记·灵启篇</field>
<field name="sequence">20</field>
<field name="intro"><![CDATA[<p>灵启篇·园丁手记。当聚落连成部族,争与和同时降临。</p>]]></field>
</record>
<record id="story_ch_lq_1" model="game.story.chapter">
<field name="volume_id" ref="story_vol_lingqi"/>
<field name="sequence">10</field>
<field name="name">第一章 · 部族初成</field>
<field name="body_html"><![CDATA[<p>灵气浓到一定程度,聚落开始兼并。</p>
<p>三个相邻的族群,在一场没有流血的议事之后,决定共用一口深井。这是凡墟历史上第一次「联盟」——没有王,只有约定。</p>
<p>园丁在云端记下了这一笔。他知道,从今往后,世界不再只是一群野生的人,而是一个会自己谈判、自己妥协的活物。</p>]]></field>
</record>
<record id="story_ch_lq_2" model="game.story.chapter">
<field name="volume_id" ref="story_vol_lingqi"/>
<field name="sequence">20</field>
<field name="name">第二章 · 交易与争端</field>
<field name="body_html"><![CDATA[<p>联盟带来了繁荣,也带来了第一场争端。</p>
<p>东边的墟族说井水该归他们,西边的人不肯。争执了七天,最后是园丁在不经意间,让井边多长出一片可食用的苔藓——谁都能采,谁都不必独占。</p>
<p>争端平息的方式,从来不在胜负,而在有没有第三种选择。这是园丁学到的第二课。</p>]]></field>
</record>
<!-- ============ 剧情(小说)种子 ============
注意:小说内容改为由 novel/ 源文件经 novel/sync_novel.py 同步进数据库,
不再在此 XML 硬编码。修改 novel/ 后运行该脚本即可更新剧情站。 -->
</odoo>
+18
View File
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- 定时把 novel/ 下的 Markdown 增量同步进数据库。
间隔 5 分钟:改完 md 无需手动跑命令,网站数分钟内自动更新;
Odoo 重启后调度器恢复,也会按时触发(即"重启带着一块更新")。
Odoo 18 的 ir.cron 改为委托 ir.actions.server(code 状态)执行,
故用 model_id + state="code" + code 的方式,旧的 model/function/args/numbercall 字段已废弃。 -->
<record id="ir_cron_sync_novel" model="ir.cron">
<field name="name">宇森·小说 Markdown 同步</field>
<field name="model_id" ref="game_base.model_game_story_volume"/>
<field name="state">code</field>
<field name="code">model.action_sync_novel()</field>
<field name="interval_number">5</field>
<field name="interval_type">minutes</field>
<field name="active" eval="True"/>
<field name="user_id" ref="base.user_root"/>
</record>
</odoo>
+31
View File
@@ -1,5 +1,12 @@
# -*- coding: utf-8 -*-
import os
import sys
import subprocess
import logging
from odoo import models, fields
from odoo.modules.module import get_module_path
_logger = logging.getLogger(__name__)
class GameStoryVolume(models.Model):
@@ -13,6 +20,30 @@ class GameStoryVolume(models.Model):
intro = fields.Html(string='卷首语')
chapter_ids = fields.One2many('game.story.chapter', 'volume_id', string='章节')
def action_sync_novel(self):
"""由定时任务(ir.cron)调用:把 novel/ 下的 Markdown 增量同步进数据库。
走独立同步脚本(novel/sync_novel.py),单一实现来源。
注意:脚本依赖 venv 的 psycopg2,而 Odoo 可能跑在系统 Python 上,
因此显式使用项目 venv 的 python 执行,而非 sys.executable。"""
base = get_module_path('game_base')
script = os.path.normpath(os.path.join(base, '..', '..', 'novel', 'sync_novel.py'))
if not os.path.exists(script):
_logger.warning('小说同步脚本不存在: %s', script)
return
# 优先用项目 venv 的 python(自带 psycopg2);否则退化为当前解释器
venv_py = os.path.normpath(os.path.join(base, '..', '..', '..', '.venv', 'Scripts', 'python.exe'))
python = venv_py if os.path.exists(venv_py) else sys.executable
try:
proc = subprocess.run([python, script],
capture_output=True, text=True, timeout=180)
if proc.returncode != 0:
_logger.error('小说同步失败(%s): %s', proc.returncode, (proc.stderr or '')[-2000:])
else:
last = (proc.stdout or '').strip().splitlines()
_logger.info('小说同步完成: %s', last[-1] if last else 'ok')
except Exception as e:
_logger.exception('小说同步异常: %s', e)
class GameStoryChapter(models.Model):
_name = 'game.story.chapter'
+4
View File
@@ -7,6 +7,10 @@
'depends': ['base', 'web'],
'data': [
'security/ir.model.access.csv',
'data/codex_resource.xml',
'data/codex_creature.xml',
'data/codex_monster.xml',
'data/codex_race.xml',
'views/yt_world_views.xml',
],
'assets': {
+59 -5
View File
@@ -9,11 +9,22 @@ _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',
)
"""返回 UTF-8 JSON 响应(与 game_base 一致),并附带 CORS 头以支持跨域(8080→8069)。"""
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 Response(json.dumps(data, ensure_ascii=False), headers=headers)
def _post_body():
@@ -86,3 +97,46 @@ class YtWorldApi(http.Controller):
world.name = name
_logger.info('yt.world rename uid=%s %r -> %r', user.id, old, name)
return _json({'ok': True, 'name': name})
# ========== 图鉴 API ==========
def _records_json(self, model, fields):
"""将 model 的全部记录转为 [{field: value}, ...] 格式(Json 字段解析为对象)。"""
recs = request.env[model].sudo().search([], order='sequence, id')
out = []
for r in recs:
item = {}
for f in fields:
val = getattr(r, f)
if isinstance(val, str):
try:
val = json.loads(val)
except (ValueError, TypeError):
pass
item[f] = val
out.append(item)
return _json(out)
@http.route('/yt_world/api/codex/resources', type='http', auth='public',
methods=['GET', 'OPTIONS'], csrf=False)
def codex_resources(self, **kw):
return self._records_json('yt.codex.resource',
['code','name','icon','category','quality','source','uses','recipe','description'])
@http.route('/yt_world/api/codex/creatures', type='http', auth='public',
methods=['GET', 'OPTIONS'], csrf=False)
def codex_creatures(self, **kw):
return self._records_json('yt.codex.creature',
['code','name','icon','habitat','tameable','diet','products','description'])
@http.route('/yt_world/api/codex/monsters', type='http', auth='public',
methods=['GET', 'OPTIONS'], csrf=False)
def codex_monsters(self, **kw):
return self._records_json('yt.codex.monster',
['code','name','icon','tier','level_min','level_max','habitat','drops','description'])
@http.route('/yt_world/api/codex/races', type='http', auth='public',
methods=['GET', 'OPTIONS'], csrf=False)
def codex_races(self, **kw):
return self._records_json('yt.codex.race',
['code','name','icon','layer','traits','description'])
+103
View File
@@ -0,0 +1,103 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="crea_cow" model="yt.codex.creature">
<field name="code">cow</field><field name="name">牛</field><field name="icon">🐄</field>
<field name="habitat">草原</field><field name="tameable">1</field><field name="diet">植食</field>
<field name="products">["肉","牛奶","皮革"]</field><field name="sequence">10</field>
</record>
<record id="crea_sheep" model="yt.codex.creature">
<field name="code">sheep</field><field name="name">羊</field><field name="icon">🐑</field>
<field name="habitat">草原</field><field name="tameable">1</field><field name="diet">植食</field>
<field name="products">["肉","羊毛"]</field><field name="sequence">20</field>
</record>
<record id="crea_horse" model="yt.codex.creature">
<field name="code">horse</field><field name="name">马</field><field name="icon">🐎</field>
<field name="habitat">草原</field><field name="tameable">1</field><field name="diet">植食</field>
<field name="products">["骑乘运输","骑兵"]</field><field name="sequence">30</field>
</record>
<record id="crea_pig" model="yt.codex.creature">
<field name="code">pig</field><field name="name">猪</field><field name="icon">🐖</field>
<field name="habitat">林地/村落</field><field name="tameable">1</field><field name="diet">杂食</field>
<field name="products">["肉","鬃毛"]</field><field name="sequence">40</field>
</record>
<record id="crea_chicken" model="yt.codex.creature">
<field name="code">chicken</field><field name="name">鸡</field><field name="icon">🐔</field>
<field name="habitat">村落/草地</field><field name="tameable">1</field><field name="diet">杂食</field>
<field name="products">["蛋","肉","羽毛"]</field><field name="sequence">50</field>
</record>
<record id="crea_duck" model="yt.codex.creature">
<field name="code">duck</field><field name="name">鸭</field><field name="icon">🦆</field>
<field name="habitat">湿地/河岸</field><field name="tameable">1</field><field name="diet">杂食</field>
<field name="products">["蛋","肉","羽绒"]</field><field name="sequence">60</field>
</record>
<record id="crea_dog" model="yt.codex.creature">
<field name="code">dog</field><field name="name">狗</field><field name="icon">🐕</field>
<field name="habitat">村落/营地</field><field name="tameable">1</field><field name="diet">杂食</field>
<field name="products">["护卫","狩猎协助"]</field><field name="sequence">70</field>
</record>
<record id="crea_cat" model="yt.codex.creature">
<field name="code">cat</field><field name="name">猫</field><field name="icon">🐈</field>
<field name="habitat">村落</field><field name="tameable">1</field><field name="diet">肉食</field>
<field name="products">["捕鼠","幸运"]</field><field name="sequence">80</field>
</record>
<record id="crea_rabbit" model="yt.codex.creature">
<field name="code">rabbit</field><field name="name">兔</field><field name="icon">🐇</field>
<field name="habitat">林地/草地</field><field name="tameable">1</field><field name="diet">植食</field>
<field name="products">["肉","毛皮"]</field><field name="sequence">90</field>
</record>
<record id="crea_squirrel" model="yt.codex.creature">
<field name="code">squirrel</field><field name="name">松鼠</field><field name="icon">🐿️</field>
<field name="habitat">森林</field><field name="diet">植食</field>
<field name="products">["坚果","藏宝指引"]</field><field name="sequence">100</field>
</record>
<record id="crea_hedgehog" model="yt.codex.creature">
<field name="code">hedgehog</field><field name="name">刺猬</field><field name="icon">🦔</field>
<field name="habitat">林地/村落</field><field name="tameable">1</field><field name="diet">杂食</field>
<field name="products">["虫害防治"]</field><field name="sequence">110</field>
</record>
<record id="crea_bee" model="yt.codex.creature">
<field name="code">bee</field><field name="name">蜂</field><field name="icon">🐝</field>
<field name="habitat">花海/林地</field><field name="tameable">1</field><field name="diet">植食</field>
<field name="products">["蜂蜜","授粉"]</field><field name="sequence">120</field>
</record>
<record id="crea_butterfly" model="yt.codex.creature">
<field name="code">butterfly</field><field name="name">蝶</field><field name="icon">🦋</field>
<field name="habitat">花海/草地</field><field name="diet">植食</field>
<field name="products">["灵粉","生态指示"]</field><field name="sequence">130</field>
</record>
<record id="crea_deer" model="yt.codex.creature">
<field name="code">deer</field><field name="name">鹿</field><field name="icon">🦌</field>
<field name="habitat">森林</field><field name="diet">植食</field>
<field name="products">["肉","鹿皮","鹿角"]</field><field name="sequence">140</field>
</record>
<record id="crea_fox" model="yt.codex.creature">
<field name="code">fox</field><field name="name">狐</field><field name="icon">🦊</field>
<field name="habitat">林地/丘陵</field><field name="diet">肉食</field>
<field name="products">["狐皮","灵性"]</field><field name="sequence">150</field>
</record>
<record id="crea_wolf" model="yt.codex.creature">
<field name="code">wolf</field><field name="name">狼</field><field name="icon">🐺</field>
<field name="habitat">森林/山地</field><field name="diet">肉食</field>
<field name="products">["狼皮","利齿"]</field><field name="sequence">160</field>
</record>
<record id="crea_snake" model="yt.codex.creature">
<field name="code">snake</field><field name="name">蛇</field><field name="icon">🐍</field>
<field name="habitat">丛林/岩洞</field><field name="diet">肉食</field>
<field name="products">["蛇毒","蛇皮","灵性"]</field><field name="sequence">170</field>
</record>
<record id="crea_eagle" model="yt.codex.creature">
<field name="code">eagle</field><field name="name">鹰</field><field name="icon">🦅</field>
<field name="habitat">高山/天空</field><field name="diet">肉食</field>
<field name="products">["巨羽","视野共享"]</field><field name="sequence">180</field>
</record>
<record id="crea_fish" model="yt.codex.creature">
<field name="code">fish</field><field name="name">鱼</field><field name="icon">🐟</field>
<field name="habitat">河流/湖泊</field><field name="diet">杂食</field>
<field name="products">["鱼肉","鱼骨","鱼苗"]</field><field name="sequence">190</field>
</record>
<record id="crea_turtle" model="yt.codex.creature">
<field name="code">turtle</field><field name="name">龟</field><field name="icon">🐢</field>
<field name="habitat">河岸/湖泊</field><field name="tameable">1</field><field name="diet">植食</field>
<field name="products">["龟甲盾","龟蛋","长寿"]</field><field name="sequence">200</field>
</record>
</odoo>
+266
View File
@@ -0,0 +1,266 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- ===== 普通野怪 ===== -->
<record id="mon_grasswolf" model="yt.codex.monster">
<field name="code">grasswolf</field><field name="name">草原狼</field><field name="icon">🐺</field>
<field name="tier">normal</field><field name="level_min">1</field><field name="level_max">3</field>
<field name="habitat">草原</field>
<field name="drops">["兽骨","毛皮"]</field><field name="sequence">10</field>
</record>
<record id="mon_deer" model="yt.codex.monster">
<field name="code">deer</field><field name="name">大角鹿</field><field name="icon">🦌</field>
<field name="tier">normal</field><field name="level_min">2</field><field name="level_max">4</field>
<field name="habitat">草原</field>
<field name="drops">["兽骨","毛皮","鹿角"]</field><field name="sequence">20</field>
</record>
<record id="mon_molerat" model="yt.codex.monster">
<field name="code">molerat</field><field name="name">地鼠群</field><field name="icon">🐭</field>
<field name="tier">normal</field><field name="level_min">1</field><field name="level_max">2</field>
<field name="habitat">草原</field>
<field name="drops">["兽骨","毛皮"]</field><field name="sequence">30</field>
</record>
<record id="mon_boar" model="yt.codex.monster">
<field name="code">boar</field><field name="name">野猪</field><field name="icon">🐗</field>
<field name="tier">normal</field><field name="level_min">3</field><field name="level_max">5</field>
<field name="habitat">草原</field>
<field name="drops">["肉","兽骨","鬃毛"]</field><field name="sequence">40</field>
</record>
<record id="mon_spider" model="yt.codex.monster">
<field name="code">spider</field><field name="name">林间蜘蛛</field><field name="icon">🕷️</field>
<field name="tier">normal</field><field name="level_min">3</field><field name="level_max">5</field>
<field name="habitat">森林</field>
<field name="drops">["蛛丝","毒囊"]</field><field name="sequence">50</field>
</record>
<record id="mon_mushroom" model="yt.codex.monster">
<field name="code">mushroom</field><field name="name">毒蘑菇精</field><field name="icon">🍄</field>
<field name="tier">normal</field><field name="level_min">4</field><field name="level_max">6</field>
<field name="habitat">森林</field>
<field name="drops">["菌丝","草本"]</field><field name="sequence">60</field>
</record>
<record id="mon_treant" model="yt.codex.monster">
<field name="code">treant</field><field name="name">树精</field><field name="icon">🌳</field>
<field name="tier">normal</field><field name="level_min">5</field><field name="level_max">8</field>
<field name="habitat">森林</field>
<field name="drops">["木材","树脂","露珠"]</field><field name="sequence">70</field>
</record>
<record id="mon_thornsnake" model="yt.codex.monster">
<field name="code">thornsnake</field><field name="name">荆棘蛇</field><field name="icon">🐍</field>
<field name="tier">normal</field><field name="level_min">4</field><field name="level_max">6</field>
<field name="habitat">森林</field>
<field name="drops">["蛇皮","蛇毒"]</field><field name="sequence">80</field>
</record>
<record id="mon_maddog" model="yt.codex.monster">
<field name="code">maddog</field><field name="name">疯狗</field><field name="icon">🐕‍🦺</field>
<field name="tier">normal</field><field name="level_min">3</field><field name="level_max">5</field>
<field name="habitat">森林</field>
<field name="drops">["兽骨","毛皮"]</field><field name="sequence">90</field>
</record>
<record id="mon_golem" model="yt.codex.monster">
<field name="code">golem</field><field name="name">石傀儡</field><field name="icon">🗿</field>
<field name="tier">normal</field><field name="level_min">7</field><field name="level_max">10</field>
<field name="habitat">山地</field>
<field name="drops">["石材","矿石"]</field><field name="sequence">100</field>
</record>
<record id="mon_scorpion" model="yt.codex.monster">
<field name="code">scorpion</field><field name="name">岩蝎</field><field name="icon">🦂</field>
<field name="tier">normal</field><field name="level_min">6</field><field name="level_max">9</field>
<field name="habitat">山地</field>
<field name="drops">["鳞片","毒囊"]</field><field name="sequence">110</field>
</record>
<record id="mon_mandrill" model="yt.codex.monster">
<field name="code">mandrill</field><field name="name">山魈</field><field name="icon">🐒</field>
<field name="tier">normal</field><field name="level_min">6</field><field name="level_max">8</field>
<field name="habitat">山地</field>
<field name="drops">["毛皮","兽骨"]</field><field name="sequence">120</field>
</record>
<record id="mon_sandworm" model="yt.codex.monster">
<field name="code">sandworm</field><field name="name">沙虫</field><field name="icon">🪱</field>
<field name="tier">normal</field><field name="level_min">7</field><field name="level_max">10</field>
<field name="habitat">沙漠</field>
<field name="drops">["鳞片","兽骨"]</field><field name="sequence">130</field>
</record>
<record id="mon_desertscorp" model="yt.codex.monster">
<field name="code">desertscorp</field><field name="name">荒漠蝎</field><field name="icon">🦂</field>
<field name="tier">normal</field><field name="level_min">6</field><field name="level_max">9</field>
<field name="habitat">沙漠</field>
<field name="drops">["毒囊","鳞片"]</field><field name="sequence">140</field>
</record>
<record id="mon_vulture" model="yt.codex.monster">
<field name="code">vulture</field><field name="name">秃鹫</field><field name="icon">🦅</field>
<field name="tier">normal</field><field name="level_min">5</field><field name="level_max">8</field>
<field name="habitat">沙漠</field>
<field name="drops">["羽毛","兽骨"]</field><field name="sequence">150</field>
</record>
<record id="mon_crocodile" model="yt.codex.monster">
<field name="code">crocodile</field><field name="name">河鳄</field><field name="icon">🐊</field>
<field name="tier">normal</field><field name="level_min">6</field><field name="level_max">9</field>
<field name="habitat">水域</field>
<field name="drops">["鳞片","皮革"]</field><field name="sequence">160</field>
</record>
<record id="mon_watersnake" model="yt.codex.monster">
<field name="code">watersnake</field><field name="name">水蛇</field><field name="icon">🐍</field>
<field name="tier">normal</field><field name="level_min">4</field><field name="level_max">6</field>
<field name="habitat">水域</field>
<field name="drops">["蛇皮","蛇毒"]</field><field name="sequence">170</field>
</record>
<record id="mon_frog" model="yt.codex.monster">
<field name="code">frog</field><field name="name">巨蛙</field><field name="icon">🐸</field>
<field name="tier">normal</field><field name="level_min">5</field><field name="level_max">8</field>
<field name="habitat">水域</field>
<field name="drops">["鳞片","露珠"]</field><field name="sequence">180</field>
</record>
<record id="mon_junglepython" model="yt.codex.monster">
<field name="code">junglepython</field><field name="name">丛林蟒</field><field name="icon">🐍</field>
<field name="tier">normal</field><field name="level_min">8</field><field name="level_max">12</field>
<field name="habitat">丛林</field>
<field name="drops">["蛇皮","兽骨","肉"]</field><field name="sequence">190</field>
</record>
<record id="mon_mosquito" model="yt.codex.monster">
<field name="code">mosquito</field><field name="name">吸血蚊群</field><field name="icon">🦟</field>
<field name="tier">normal</field><field name="level_min">7</field><field name="level_max">10</field>
<field name="habitat">丛林</field>
<field name="drops">["露珠","毛皮"]</field><field name="sequence">200</field>
</record>
<record id="mon_ape" model="yt.codex.monster">
<field name="code">ape</field><field name="name">丛林猿</field><field name="icon">🦧</field>
<field name="tier">normal</field><field name="level_min">7</field><field name="level_max">10</field>
<field name="habitat">丛林</field>
<field name="drops">["毛皮","木材"]</field><field name="sequence">210</field>
</record>
<record id="mon_cavespider" model="yt.codex.monster">
<field name="code">cavespider</field><field name="name">洞穴巨蛛</field><field name="icon">🕷️</field>
<field name="tier">normal</field><field name="level_min">10</field><field name="level_max">14</field>
<field name="habitat">洞穴</field>
<field name="drops">["蛛丝","毒囊","兽骨"]</field><field name="sequence">220</field>
</record>
<record id="mon_bat" model="yt.codex.monster">
<field name="code">bat</field><field name="name">蝙蝠群</field><field name="icon">🦇</field>
<field name="tier">normal</field><field name="level_min">8</field><field name="level_max">12</field>
<field name="habitat">洞穴</field>
<field name="drops">["羽毛","兽骨"]</field><field name="sequence">230</field>
</record>
<record id="mon_ghost" model="yt.codex.monster">
<field name="code">ghost</field><field name="name">幽魂</field><field name="icon">👻</field>
<field name="tier">normal</field><field name="level_min">12</field><field name="level_max">16</field>
<field name="habitat">洞穴</field>
<field name="drops">["灵气","露珠"]</field><field name="sequence">240</field>
</record>
<record id="mon_crystal" model="yt.codex.monster">
<field name="code">crystal</field><field name="name">晶石怪</field><field name="icon">💎</field>
<field name="tier">normal</field><field name="level_min">10</field><field name="level_max">15</field>
<field name="habitat">洞穴</field>
<field name="drops">["矿石","水晶"]</field><field name="sequence">250</field>
</record>
<record id="mon_nightmare" model="yt.codex.monster">
<field name="code">nightmare</field><field name="name">夜魇</field><field name="icon">🌑</field>
<field name="tier">normal</field><field name="level_min">12</field><field name="level_max">16</field>
<field name="habitat">特殊</field>
<field name="drops">["灵气","露珠"]</field><field name="sequence">260</field>
</record>
<record id="mon_fogwalker" model="yt.codex.monster">
<field name="code">fogwalker</field><field name="name">雾行者</field><field name="icon">🌫️</field>
<field name="tier">normal</field><field name="level_min">10</field><field name="level_max">14</field>
<field name="habitat">特殊</field>
<field name="drops">["露珠","羽毛"]</field><field name="sequence">270</field>
</record>
<record id="mon_zombie" model="yt.codex.monster">
<field name="code">zombie</field><field name="name">饥饿尸</field><field name="icon">💀</field>
<field name="tier">normal</field><field name="level_min">8</field><field name="level_max">12</field>
<field name="habitat">特殊</field>
<field name="drops">["兽骨","灵气"]</field><field name="sequence">280</field>
</record>
<record id="mon_thunderbird" model="yt.codex.monster">
<field name="code">thunderbird</field><field name="name">雷鸟</field><field name="icon">⚡</field>
<field name="tier">normal</field><field name="level_min">10</field><field name="level_max">14</field>
<field name="habitat">高山</field>
<field name="drops">["羽毛","水晶"]</field><field name="sequence">290</field>
</record>
<record id="mon_windspirit" model="yt.codex.monster">
<field name="code">windspirit</field><field name="name">风精</field><field name="icon">🌪️</field>
<field name="tier">normal</field><field name="level_min">8</field><field name="level_max">12</field>
<field name="habitat">高山</field>
<field name="drops">["露珠","羽毛"]</field><field name="sequence">300</field>
</record>
<!-- ===== 精英野怪 ===== -->
<record id="mon_elite_wolfking" model="yt.codex.monster">
<field name="code">wolfking</field><field name="name">狼王</field><field name="icon">🐺✨</field>
<field name="tier">elite</field><field name="level_min">15</field><field name="level_max">18</field>
<field name="habitat">草原</field>
<field name="drops">["毛皮","兽骨","狼王牙"]</field><field name="sequence">10</field>
</record>
<record id="mon_elite_ancienttreant" model="yt.codex.monster">
<field name="code">ancienttreant</field><field name="name">远古树精</field><field name="icon">🌳✨</field>
<field name="tier">elite</field><field name="level_min">18</field><field name="level_max">22</field>
<field name="habitat">森林</field>
<field name="drops">["木材","树脂","生命露珠"]</field><field name="sequence">20</field>
</record>
<record id="mon_elite_lavagiant" model="yt.codex.monster">
<field name="code">lavagiant</field><field name="name">熔岩巨人</field><field name="icon">🔥✨</field>
<field name="tier">elite</field><field name="level_min">20</field><field name="level_max">25</field>
<field name="habitat">山地</field>
<field name="drops">["石材","矿石","火焰水晶"]</field><field name="sequence">30</field>
</record>
<record id="mon_elite_shadow" model="yt.codex.monster">
<field name="code">shadow</field><field name="name">幽影刺客</field><field name="icon">👤✨</field>
<field name="tier">elite</field><field name="level_min">18</field><field name="level_max">22</field>
<field name="habitat">洞穴</field>
<field name="drops">["蛛丝","毒囊","暗影精华"]</field><field name="sequence">40</field>
</record>
<record id="mon_elite_scorpionking" model="yt.codex.monster">
<field name="code">scorpionking</field><field name="name">毒蝎王</field><field name="icon">🦂✨</field>
<field name="tier">elite</field><field name="level_min">16</field><field name="level_max">20</field>
<field name="habitat">沙漠</field>
<field name="drops">["鳞片","毒囊","蝎王毒针"]</field><field name="sequence">50</field>
</record>
<record id="mon_elite_frostlizard" model="yt.codex.monster">
<field name="code">frostlizard</field><field name="name">冰霜蜥蜴</field><field name="icon">🦎✨</field>
<field name="tier">elite</field><field name="level_min">20</field><field name="level_max">24</field>
<field name="habitat">特殊</field>
<field name="drops">["鳞片","水晶","寒冰核心"]</field><field name="sequence">60</field>
</record>
<record id="mon_elite_thundereagle" model="yt.codex.monster">
<field name="code">thundereagle</field><field name="name">雷霆鹰</field><field name="icon">🦅✨</field>
<field name="tier">elite</field><field name="level_min">18</field><field name="level_max">22</field>
<field name="habitat">高山</field>
<field name="drops">["羽毛","水晶","雷击木"]</field><field name="sequence">70</field>
</record>
<record id="mon_elite_spiderqueen" model="yt.codex.monster">
<field name="code">spiderqueen</field><field name="name">腐毒蛛后</field><field name="icon">🕷️✨</field>
<field name="tier">elite</field><field name="level_min">20</field><field name="level_max">26</field>
<field name="habitat">洞穴</field>
<field name="drops">["蛛丝","毒囊","蛛后腺体"]</field><field name="sequence">80</field>
</record>
<record id="mon_elite_waterlord" model="yt.codex.monster">
<field name="code">waterlord</field><field name="name">水元素之主</field><field name="icon">💧✨</field>
<field name="tier">elite</field><field name="level_min">16</field><field name="level_max">20</field>
<field name="habitat">水域</field>
<field name="drops">["露珠","鳞片","水灵珠"]</field><field name="sequence">90</field>
</record>
<record id="mon_elite_crystalguard" model="yt.codex.monster">
<field name="code">crystalguard</field><field name="name">水晶守卫</field><field name="icon">💎✨</field>
<field name="tier">elite</field><field name="level_min">22</field><field name="level_max">28</field>
<field name="habitat">洞穴</field>
<field name="drops">["水晶","矿石","纯净晶核"]</field><field name="sequence">100</field>
</record>
<!-- ===== Boss ===== -->
<record id="mon_boss_dragon" model="yt.codex.monster">
<field name="code">nidhogg</field><field name="name">远古巨龙·尼德霍格</field><field name="icon">🐉</field>
<field name="tier">boss</field><field name="level_min">50</field><field name="level_max">60</field>
<field name="habitat">世界之巅·龙巢</field>
<field name="drops">["龙鳞","龙牙","龙晶","灵气"]</field><field name="sequence">10</field>
</record>
<record id="mon_boss_kraken" model="yt.codex.monster">
<field name="code">kraken</field><field name="name">深渊之主·克拉肯</field><field name="icon">🦑</field>
<field name="tier">boss</field><field name="level_min">45</field><field name="level_max">55</field>
<field name="habitat">无尽深渊·地下海</field>
<field name="drops">["深渊触须","深渊之核","黑珍珠","灵气"]</field><field name="sequence">20</field>
</record>
<record id="mon_boss_creator" model="yt.codex.monster">
<field name="code">creator</field><field name="name">创世之灵·宇</field><field name="icon">✨</field>
<field name="tier">boss</field><field name="level_min">60</field><field name="level_max">60</field>
<field name="habitat">星空层·世界核心</field>
<field name="drops">["创世碎片","世界之种"]</field><field name="sequence">30</field>
</record>
</odoo>
+78
View File
@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="race_human" model="yt.codex.race">
<field name="code">human</field><field name="name">人族</field><field name="icon">👤</field>
<field name="layer">大地</field>
<field name="traits">["适应力","雄心"]</field><field name="sequence">10</field>
</record>
<record id="race_elf" model="yt.codex.race">
<field name="code">elf</field><field name="name">精灵</field><field name="icon">🧝</field>
<field name="layer">森林</field>
<field name="traits">["自然共鸣","长生"]</field><field name="sequence">20</field>
</record>
<record id="race_dwarf" model="yt.codex.race">
<field name="code">dwarf</field><field name="name">矮人</field><field name="icon">⛏️</field>
<field name="layer">山脉</field>
<field name="traits">["锻造专精","坚毅"]</field><field name="sequence">30</field>
</record>
<record id="race_orc" model="yt.codex.race">
<field name="code">orc</field><field name="name">兽人</field><field name="icon">🐗</field>
<field name="layer">荒原</field>
<field name="traits">["战意","蛮力"]</field><field name="sequence">40</field>
</record>
<record id="race_demon" model="yt.codex.race">
<field name="code">demon</field><field name="name">魔族</field><field name="icon">😈</field>
<field name="layer">深渊</field>
<field name="traits">["混沌之力","契约"]</field><field name="sequence">50</field>
</record>
<record id="race_yao" model="yt.codex.race">
<field name="code">yao</field><field name="name">妖族</field><field name="icon">🦊</field>
<field name="layer">全境</field>
<field name="traits">["化形","灵觉"]</field><field name="sequence">60</field>
</record>
<record id="race_angel" model="yt.codex.race">
<field name="code">angel</field><field name="name">天使</field><field name="icon">✨</field>
<field name="layer">天空</field>
<field name="traits">["圣光之翼","净化"]</field><field name="sequence">70</field>
</record>
<record id="race_undead" model="yt.codex.race">
<field name="code">undead</field><field name="name">亡灵</field><field name="icon">💀</field>
<field name="layer">地下</field>
<field name="traits">["不死","恐惧免疫"]</field><field name="sequence">80</field>
</record>
<record id="race_dragon" model="yt.codex.race">
<field name="code">dragon</field><field name="name">龙族</field><field name="icon">🐉</field>
<field name="layer">全境</field>
<field name="traits">["太古之力","龙息"]</field><field name="sequence">90</field>
</record>
<record id="race_goblin" model="yt.codex.race">
<field name="code">goblin</field><field name="name">地精</field><field name="icon">👹</field>
<field name="layer">地下</field>
<field name="traits">["巧手","商业嗅觉"]</field><field name="sequence">100</field>
</record>
<record id="race_giant" model="yt.codex.race">
<field name="code">giant</field><field name="name">巨人</field><field name="icon">🦶</field>
<field name="layer">高山</field>
<field name="traits">["巨力","坚韧"]</field><field name="sequence">110</field>
</record>
<record id="race_elemental" model="yt.codex.race">
<field name="code">elemental</field><field name="name">元素灵</field><field name="icon">🌪️</field>
<field name="layer">全境</field>
<field name="traits">["元素亲和","灵体"]</field><field name="sequence">120</field>
</record>
<record id="race_mechanical" model="yt.codex.race">
<field name="code">mechanical</field><field name="name">机械</field><field name="icon">⚙️</field>
<field name="layer">遗迹</field>
<field name="traits">["太古知识","机械之躯"]</field><field name="sequence">130</field>
</record>
<record id="race_halforc" model="yt.codex.race">
<field name="code">halforc</field><field name="name">半兽人</field><field name="icon">🐾</field>
<field name="layer">边境</field>
<field name="traits">["双重血统","体能"]</field><field name="sequence">140</field>
</record>
<record id="race_naga" model="yt.codex.race">
<field name="code">naga</field><field name="name">娜迦</field><field name="icon">🐍</field>
<field name="layer">水域</field>
<field name="traits">["两栖","水元素亲和"]</field><field name="sequence">150</field>
</record>
</odoo>
+356
View File
@@ -0,0 +1,356 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- ===== 材料 ===== -->
<record id="res_wood" model="yt.codex.resource">
<field name="code">wood</field><field name="name">木材</field><field name="icon">🪵</field>
<field name="category">material</field><field name="quality">common</field>
<field name="source">森林地块</field><field name="uses">建造建筑、加工木板、燃料</field>
<field name="sequence">10</field>
</record>
<record id="res_stone" model="yt.codex.resource">
<field name="code">stone</field><field name="name">石材</field><field name="icon">🪨</field>
<field name="category">material</field><field name="quality">common</field>
<field name="source">山地/岩层地块</field><field name="uses">建造石质建筑、加工石料、铺路</field>
<field name="sequence">20</field>
</record>
<record id="res_ore" model="yt.codex.resource">
<field name="code">ore</field><field name="name">矿石</field><field name="icon">⛏️</field>
<field name="category">material</field><field name="quality">uncommon</field>
<field name="source">深层矿脉/地下世界</field><field name="uses">冶炼金属、锻造工具、科技升级</field>
<field name="sequence">30</field>
</record>
<record id="res_herb" model="yt.codex.resource">
<field name="code">herb</field><field name="name">草本</field><field name="icon">🌿</field>
<field name="category">material</field><field name="quality">common</field>
<field name="source">绿地/林地地块</field><field name="uses">制药、烹饪、灵气转化</field>
<field name="sequence">40</field>
</record>
<record id="res_meat" model="yt.codex.resource">
<field name="code">meat</field><field name="name">肉</field><field name="icon">🍖</field>
<field name="category">material</field><field name="quality">common</field>
<field name="source">狩猎/畜牧</field><field name="uses">食物消耗、烹饪加工、人口维持</field>
<field name="sequence">50</field>
</record>
<record id="res_hide" model="yt.codex.resource">
<field name="code">hide</field><field name="name">毛皮</field><field name="icon">🧶</field>
<field name="category">material</field><field name="quality">common</field>
<field name="source">畜牧/狩猎</field><field name="uses">制衣、制作、贸易</field>
<field name="sequence">60</field>
</record>
<record id="res_honey" model="yt.codex.resource">
<field name="code">honey</field><field name="name">蜂蜜</field><field name="icon">🍯</field>
<field name="category">material</field><field name="quality">uncommon</field>
<field name="source">蜂群/花海地块</field><field name="uses">烹饪、制药、贸易</field>
<field name="sequence">70</field>
</record>
<record id="res_clay" model="yt.codex.resource">
<field name="code">clay</field><field name="name">粘土</field><field name="icon">🏺</field>
<field name="category">material</field><field name="quality">common</field>
<field name="source">河岸/湿地地块</field><field name="uses">制陶、砖瓦、雕塑</field>
<field name="sequence">80</field>
</record>
<record id="res_sand" model="yt.codex.resource">
<field name="code">sand</field><field name="name">沙子</field><field name="icon">⏳</field>
<field name="category">material</field><field name="quality">common</field>
<field name="source">沙漠/河岸地块</field><field name="uses">制玻璃、砂浆、滤水</field>
<field name="sequence">90</field>
</record>
<record id="res_vine" model="yt.codex.resource">
<field name="code">vine</field><field name="name">藤蔓</field><field name="icon">🌱</field>
<field name="category">material</field><field name="quality">common</field>
<field name="source">丛林地块</field><field name="uses">制绳索、简易桥梁、捆绑</field>
<field name="sequence">100</field>
</record>
<record id="res_fiber" model="yt.codex.resource">
<field name="code">fiber</field><field name="name">纤维</field><field name="icon">🧵</field>
<field name="category">material</field><field name="quality">common</field>
<field name="source">草甸/湿地地块</field><field name="uses">织布、造纸、绳索</field>
<field name="sequence">110</field>
</record>
<record id="res_resin" model="yt.codex.resource">
<field name="code">resin</field><field name="name">树脂</field><field name="icon">🫧</field>
<field name="category">material</field><field name="quality">uncommon</field>
<field name="source">针叶林地块</field><field name="uses">制胶、熏香、精炼油</field>
<field name="sequence">120</field>
</record>
<record id="res_bone" model="yt.codex.resource">
<field name="code">bone</field><field name="name">兽骨</field><field name="icon">🦴</field>
<field name="category">material</field><field name="quality">common</field>
<field name="source">狩猎/献祭</field><field name="uses">制骨器、装饰、肥料</field>
<field name="sequence">130</field>
</record>
<record id="res_feather" model="yt.codex.resource">
<field name="code">feather</field><field name="name">羽毛</field><field name="icon">🪶</field>
<field name="category">material</field><field name="quality">common</field>
<field name="source">鸟类/家禽养殖</field><field name="uses">制箭、书写、装饰</field>
<field name="sequence">140</field>
</record>
<record id="res_crystal" model="yt.codex.resource">
<field name="code">crystal</field><field name="name">水晶</field><field name="icon">💎</field>
<field name="category">material</field><field name="quality">rare</field>
<field name="source">岩洞深处/地下世界</field><field name="uses">能量引导、附魔、高级加工</field>
<field name="sequence">150</field>
</record>
<record id="res_mycelium" model="yt.codex.resource">
<field name="code">mycelium</field><field name="name">菌丝</field><field name="icon">🍄</field>
<field name="category">material</field><field name="quality">uncommon</field>
<field name="source">朽木/地下湿地</field><field name="uses">发酵、制药、生态转化</field>
<field name="sequence">160</field>
</record>
<record id="res_dew" model="yt.codex.resource">
<field name="code">dew</field><field name="name">露珠</field><field name="icon">💧</field>
<field name="category">material</field><field name="quality">uncommon</field>
<field name="source">清晨草地/特殊气候</field><field name="uses">制药、酿酒、灵气调和</field>
<field name="sequence">170</field>
</record>
<record id="res_scale" model="yt.codex.resource">
<field name="code">scale</field><field name="name">鳞片</field><field name="icon">🐟</field>
<field name="category">material</field><field name="quality">uncommon</field>
<field name="source">水域/水族狩猎</field><field name="uses">制甲、装饰、研磨入药</field>
<field name="sequence">180</field>
</record>
<record id="res_silk" model="yt.codex.resource">
<field name="code">silk</field><field name="name">蛛丝</field><field name="icon">🕸️</field>
<field name="category">material</field><field name="quality">rare</field>
<field name="source">洞穴深处/特殊生态</field><field name="uses">织极品布匹、弓弦、陷阱</field>
<field name="sequence">190</field>
</record>
<record id="res_horn" model="yt.codex.resource">
<field name="code">horn</field><field name="name">兽角</field><field name="icon">🦌</field>
<field name="category">material</field><field name="quality">uncommon</field>
<field name="source">狩猎大型野兽</field><field name="uses">制器、装饰、药材</field>
<field name="sequence">200</field>
</record>
<record id="res_aura" model="yt.codex.resource">
<field name="code">aura</field><field name="name">灵气</field><field name="icon">✨</field>
<field name="category">special</field><field name="quality">epic</field>
<field name="source">地心/星空层/文明事件</field><field name="uses">文明跃迁、特殊事件、世界规则改写</field>
<field name="sequence">210</field>
</record>
<!-- ===== 加工品 ===== -->
<record id="res_plank" model="yt.codex.resource">
<field name="code">plank</field><field name="name">木板</field><field name="icon">📦</field>
<field name="category">processed</field><field name="quality">uncommon</field>
<field name="source">加工台</field><field name="uses">精良建造、家具、机关</field>
<field name="recipe">[{"code":"wood","num":3}]</field>
<field name="sequence">10</field>
</record>
<record id="res_stoneblock" model="yt.codex.resource">
<field name="code">stoneBlock</field><field name="name">石料</field><field name="icon">🧱</field>
<field name="category">processed</field><field name="quality">uncommon</field>
<field name="source">加工台</field><field name="uses">石质建筑、城墙、纪念碑</field>
<field name="recipe">[{"code":"stone","num":2}]</field>
<field name="sequence">20</field>
</record>
<record id="res_brick" model="yt.codex.resource">
<field name="code">brick</field><field name="name">砖块</field><field name="icon">🧱</field>
<field name="category">processed</field><field name="quality">uncommon</field>
<field name="source">窑炉</field><field name="uses">建筑、道路、烟囱</field>
<field name="recipe">[{"code":"clay","num":1},{"code":"sand","num":1}]</field>
<field name="sequence">30</field>
</record>
<record id="res_metal" model="yt.codex.resource">
<field name="code">metal</field><field name="name">金属锭</field><field name="icon">🔩</field>
<field name="category">processed</field><field name="quality">rare</field>
<field name="source">冶炼炉</field><field name="uses">工具升级、武器、机械</field>
<field name="recipe">[{"code":"ore","num":3}]</field>
<field name="sequence">40</field>
</record>
<record id="res_cloth" model="yt.codex.resource">
<field name="code">cloth</field><field name="name">布匹</field><field name="icon">🧵</field>
<field name="category">processed</field><field name="quality">common</field>
<field name="source">纺织台</field><field name="uses">制衣、装饰、贸易</field>
<field name="recipe">[{"code":"fiber","num":2}]</field>
<field name="sequence">50</field>
</record>
<record id="res_driedmeat" model="yt.codex.resource">
<field name="code">driedMeat</field><field name="name">风干肉</field><field name="icon">🥩</field>
<field name="category">processed</field><field name="quality">common</field>
<field name="source">晒晾架</field><field name="uses">食物储备、远征、贸易</field>
<field name="recipe">[{"code":"meat","num":2}]</field>
<field name="sequence">60</field>
</record>
<record id="res_rope" model="yt.codex.resource">
<field name="code">rope</field><field name="name">绳索</field><field name="icon">🪢</field>
<field name="category">processed</field><field name="quality">common</field>
<field name="source">编织台</field><field name="uses">攀爬、捆绑、建筑</field>
<field name="recipe">[{"code":"vine","num":2},{"code":"fiber","num":1}]</field>
<field name="sequence">70</field>
</record>
<record id="res_paper" model="yt.codex.resource">
<field name="code">paper</field><field name="name">纸张</field><field name="icon">📄</field>
<field name="category">processed</field><field name="quality">common</field>
<field name="source">造纸坊</field><field name="uses">书写、记录、贸易</field>
<field name="recipe">[{"code":"fiber","num":2}]</field>
<field name="sequence">80</field>
</record>
<record id="res_charcoal" model="yt.codex.resource">
<field name="code">charcoal</field><field name="name">木炭</field><field name="icon">🔥</field>
<field name="category">processed</field><field name="quality">common</field>
<field name="source">炭窑</field><field name="uses">冶炼燃料、保温、滤材</field>
<field name="recipe">[{"code":"wood","num":2}]</field>
<field name="sequence">90</field>
</record>
<record id="res_glass" model="yt.codex.resource">
<field name="code">glass</field><field name="name">玻璃</field><field name="icon">🔮</field>
<field name="category">processed</field><field name="quality">uncommon</field>
<field name="source">熔炉</field><field name="uses">窗户、器皿、透镜</field>
<field name="recipe">[{"code":"sand","num":2},{"code":"charcoal","num":1}]</field>
<field name="sequence">100</field>
</record>
<record id="res_pottery" model="yt.codex.resource">
<field name="code">pottery</field><field name="name">陶器</field><field name="icon">🏺</field>
<field name="category">processed</field><field name="quality">common</field>
<field name="source">陶轮</field><field name="uses">储物、烹饪、盛水</field>
<field name="recipe">[{"code":"clay","num":2}]</field>
<field name="sequence">110</field>
</record>
<record id="res_leather" model="yt.codex.resource">
<field name="code">leather</field><field name="name">皮革</field><field name="icon">🟫</field>
<field name="category">processed</field><field name="quality">uncommon</field>
<field name="source">鞣制坊</field><field name="uses">制甲、行囊、马具</field>
<field name="recipe">[{"code":"hide","num":1},{"code":"herb","num":2}]</field>
<field name="sequence">120</field>
</record>
<record id="res_blanket" model="yt.codex.resource">
<field name="code">blanket</field><field name="name">毛毯</field><field name="icon">🧣</field>
<field name="category">processed</field><field name="quality">uncommon</field>
<field name="source">裁缝台</field><field name="uses">保暖、贸易、床品</field>
<field name="recipe">[{"code":"hide","num":2},{"code":"cloth","num":1}]</field>
<field name="sequence">130</field>
</record>
<record id="res_wine" model="yt.codex.resource">
<field name="code">wine</field><field name="name">果酒</field><field name="icon">🍷</field>
<field name="category">processed</field><field name="quality">uncommon</field>
<field name="source">酿酒坊</field><field name="uses">饮食、贸易、仪式</field>
<field name="recipe">[{"code":"honey","num":2},{"code":"dew","num":1}]</field>
<field name="sequence">140</field>
</record>
<record id="res_smokedmeat" model="yt.codex.resource">
<field name="code">smokedMeat</field><field name="name">熏肉</field><field name="icon">🍖</field>
<field name="category">processed</field><field name="quality">uncommon</field>
<field name="source">熏房</field><field name="uses">食物储备、贸易、远行</field>
<field name="recipe">[{"code":"meat","num":1},{"code":"wood","num":1}]</field>
<field name="sequence">150</field>
</record>
<record id="res_salve" model="yt.codex.resource">
<field name="code">salve</field><field name="name">草药膏</field><field name="icon">🩹</field>
<field name="category">processed</field><field name="quality">uncommon</field>
<field name="source">药臼</field><field name="uses">疗伤、解毒、护肤</field>
<field name="recipe">[{"code":"herb","num":2},{"code":"resin","num":1}]</field>
<field name="sequence">160</field>
</record>
<record id="res_oil" model="yt.codex.resource">
<field name="code">oil</field><field name="name">精炼油</field><field name="icon">🫒</field>
<field name="category">processed</field><field name="quality">rare</field>
<field name="source">蒸馏器</field><field name="uses">照明、润滑、制药</field>
<field name="recipe">[{"code":"resin","num":2},{"code":"charcoal","num":1}]</field>
<field name="sequence">170</field>
</record>
<record id="res_mortar" model="yt.codex.resource">
<field name="code">mortar</field><field name="name">砂浆</field><field name="icon">🪣</field>
<field name="category">processed</field><field name="quality">common</field>
<field name="source">搅拌池</field><field name="uses">砌墙、铺路、雕塑</field>
<field name="recipe">[{"code":"sand","num":1},{"code":"clay","num":1}]</field>
<field name="sequence">180</field>
</record>
<record id="res_steel" model="yt.codex.resource">
<field name="code">steel</field><field name="name">钢锭</field><field name="icon">⚙️</field>
<field name="category">processed</field><field name="quality">epic</field>
<field name="source">高炉</field><field name="uses">武器、装甲、高级机械</field>
<field name="recipe">[{"code":"metal","num":2},{"code":"ore","num":1}]</field>
<field name="sequence">190</field>
</record>
<record id="res_alloy" model="yt.codex.resource">
<field name="code">alloy</field><field name="name">灵晶合金</field><field name="icon">🔷</field>
<field name="category">processed</field><field name="quality">legendary</field>
<field name="source">灵炉</field><field name="uses">神器、图腾、终极装备</field>
<field name="recipe">[{"code":"steel","num":1},{"code":"crystal","num":1},{"code":"aura","num":1}]</field>
<field name="sequence">200</field>
</record>
<record id="res_potion" model="yt.codex.resource">
<field name="code">potion</field><field name="name">灵药剂</field><field name="icon">🧪</field>
<field name="category">processed</field><field name="quality">rare</field>
<field name="source">炼药台</field><field name="uses">疗伤、增益、事件触发</field>
<field name="recipe">[{"code":"herb","num":3},{"code":"aura","num":1}]</field>
<field name="sequence">210</field>
</record>
<record id="res_wallpanel" model="yt.codex.resource">
<field name="code">wallPanel</field><field name="name">木板墙</field><field name="icon">🚧</field>
<field name="category">processed</field><field name="quality">uncommon</field>
<field name="source">木工台</field><field name="uses">建筑墙体、围栏、哨塔</field>
<field name="recipe">[{"code":"plank","num":3}]</field>
<field name="sequence">220</field>
</record>
<record id="res_stonebrick" model="yt.codex.resource">
<field name="code">stoneBrick</field><field name="name">石砖</field><field name="icon">🗿</field>
<field name="category">processed</field><field name="quality">rare</field>
<field name="source">石工台</field><field name="uses">石质建筑、城堡、纪念碑</field>
<field name="recipe">[{"code":"stoneBlock","num":2}]</field>
<field name="sequence">230</field>
</record>
<record id="res_tile" model="yt.codex.resource">
<field name="code">tile</field><field name="name">瓷砖</field><field name="icon">■</field>
<field name="category">processed</field><field name="quality">common</field>
<field name="source">窑炉</field><field name="uses">屋面、地面、装饰</field>
<field name="recipe">[{"code":"clay","num":1}]</field>
<field name="sequence">240</field>
</record>
<record id="res_silkcloth" model="yt.codex.resource">
<field name="code">silkCloth</field><field name="name">丝绸</field><field name="icon">🎀</field>
<field name="category">processed</field><field name="quality">rare</field>
<field name="source">精纺机</field><field name="uses">极品衣饰、贸易、图腾</field>
<field name="recipe">[{"code":"silk","num":2}]</field>
<field name="sequence">250</field>
</record>
<record id="res_dye" model="yt.codex.resource">
<field name="code">dye</field><field name="name">染料</field><field name="icon">🎨</field>
<field name="category">processed</field><field name="quality">uncommon</field>
<field name="source">染缸</field><field name="uses">染色、装饰、贸易</field>
<field name="recipe">[{"code":"herb","num":2}]</field>
<field name="sequence">260</field>
</record>
<record id="res_spice" model="yt.codex.resource">
<field name="code">spice</field><field name="name">香料</field><field name="icon">🫘</field>
<field name="category">processed</field><field name="quality">uncommon</field>
<field name="source">研钵</field><field name="uses">烹饪、贸易、仪式</field>
<field name="recipe">[{"code":"herb","num":3}]</field>
<field name="sequence">270</field>
</record>
<record id="res_candle" model="yt.codex.resource">
<field name="code">candle</field><field name="name">蜡烛</field><field name="icon">🕯️</field>
<field name="category">processed</field><field name="quality">common</field>
<field name="source">制烛台</field><field name="uses">照明、仪式、温暖</field>
<field name="recipe">[{"code":"resin","num":1},{"code":"fiber","num":1}]</field>
<field name="sequence">280</field>
</record>
<record id="res_medicatedwine" model="yt.codex.resource">
<field name="code">medicatedWine</field><field name="name">药酒</field><field name="icon">⚗️</field>
<field name="category">processed</field><field name="quality">rare</field>
<field name="source">药酒窖</field><field name="uses">疗伤、增益、御寒</field>
<field name="recipe">[{"code":"wine","num":1},{"code":"salve","num":1}]</field>
<field name="sequence">290</field>
</record>
<record id="res_runestone" model="yt.codex.resource">
<field name="code">runeStone</field><field name="name">符文石</field><field name="icon">🪨</field>
<field name="category">processed</field><field name="quality">epic</field>
<field name="source">符文工坊</field><field name="uses">附魔、仪式、地脉节点</field>
<field name="recipe">[{"code":"stoneBlock","num":1},{"code":"aura","num":1}]</field>
<field name="sequence">300</field>
</record>
<record id="res_fertilizer" model="yt.codex.resource">
<field name="code">fertilizer</field><field name="name">堆肥</field><field name="icon">🌱</field>
<field name="category">processed</field><field name="quality">common</field>
<field name="source">堆肥池</field><field name="uses">农业增产、生态修复</field>
<field name="recipe">[{"code":"bone","num":1},{"code":"herb","num":2}]</field>
<field name="sequence">310</field>
</record>
<record id="res_gear" model="yt.codex.resource">
<field name="code">gear</field><field name="name">精密齿轮</field><field name="icon">⚙️</field>
<field name="category">processed</field><field name="quality">rare</field>
<field name="source">精密工坊</field><field name="uses">机械制造、机关、自动化</field>
<field name="recipe">[{"code":"metal","num":2}]</field>
<field name="sequence">320</field>
</record>
</odoo>
+1
View File
@@ -2,3 +2,4 @@ from . import yt_world
from . import yt_world_tile
from . import yt_world_tile_micro
from . import yt_resource
from . import yt_codex
+84
View File
@@ -0,0 +1,84 @@
# -*- coding: utf-8 -*-
from odoo import models, fields
class YtCodexResource(models.Model):
"""图鉴-资源(材料/加工品/特殊)"""
_name = 'yt.codex.resource'
_description = '图鉴-资源'
_order = 'category, sequence, id'
name = fields.Char(string='名称', required=True, translate=True)
code = fields.Char(string='编码', required=True, index=True)
icon = fields.Char(string='图标', default='📦')
category = fields.Selection([
('material', '材料'),
('processed', '加工品'),
('special', '特殊'),
], string='分类', required=True, default='material')
quality = fields.Selection([
('common', '普通'),
('uncommon', '优秀'),
('rare', '精良'),
('epic', '史诗'),
('legendary', '传说'),
], string='基准品质', default='common')
description = fields.Char(string='描述')
source = fields.Char(string='来源')
uses = fields.Char(string='用途')
recipe = fields.Json(string='配方') # [{"code":"wood","num":3}]
sequence = fields.Integer(string='排序', default=10)
class YtCodexCreature(models.Model):
"""图鉴-生物"""
_name = 'yt.codex.creature'
_description = '图鉴-生物'
_order = 'sequence, id'
name = fields.Char(string='名称', required=True, translate=True)
code = fields.Char(string='编码', required=True, index=True)
icon = fields.Char(string='图标', default='🐾')
habitat = fields.Char(string='栖息地')
tameable = fields.Boolean(string='可驯养', default=False)
diet = fields.Char(string='食性')
products = fields.Json(string='产物')
description = fields.Char(string='描述')
sequence = fields.Integer(string='排序', default=10)
class YtCodexMonster(models.Model):
"""图鉴-野怪/精英/Boss"""
_name = 'yt.codex.monster'
_description = '图鉴-野怪'
_order = 'tier, level_min, sequence'
name = fields.Char(string='名称', required=True, translate=True)
code = fields.Char(string='编码', required=True, index=True)
icon = fields.Char(string='图标', default='👹')
tier = fields.Selection([
('normal', '普通野怪'),
('elite', '精英野怪'),
('boss', 'Boss'),
], string='等级', required=True, default='normal')
level_min = fields.Integer(string='最小等级', default=1)
level_max = fields.Integer(string='最大等级', default=5)
habitat = fields.Char(string='栖息地')
description = fields.Char(string='描述')
drops = fields.Json(string='掉落')
sequence = fields.Integer(string='排序', default=10)
class YtCodexRace(models.Model):
"""图鉴-种族"""
_name = 'yt.codex.race'
_description = '图鉴-种族'
_order = 'sequence, id'
name = fields.Char(string='名称', required=True, translate=True)
code = fields.Char(string='编码', required=True, index=True)
icon = fields.Char(string='图标', default='🧑')
layer = fields.Char(string='所属层域')
description = fields.Char(string='描述')
traits = fields.Json(string='天赋/特性')
sequence = fields.Integer(string='排序', default=10)
@@ -11,3 +11,11 @@ access_yt_world_tile_micro_portal,yt.world.tile.micro portal,model_yt_world_tile
access_yt_resource_user,yt.resource user,model_yt_resource,base.group_user,1,1,1,1
access_yt_resource_public,yt.resource public,model_yt_resource,base.group_public,1,1,1,1
access_yt_resource_portal,yt.resource portal,model_yt_resource,base.group_portal,1,1,1,1
access_yt_codex_resource_user,yt.codex.resource user,model_yt_codex_resource,base.group_user,1,0,0,0
access_yt_codex_resource_public,yt.codex.resource public,model_yt_codex_resource,base.group_public,1,0,0,0
access_yt_codex_creature_user,yt.codex.creature user,model_yt_codex_creature,base.group_user,1,0,0,0
access_yt_codex_creature_public,yt.codex.creature public,model_yt_codex_creature,base.group_public,1,0,0,0
access_yt_codex_monster_user,yt.codex.monster user,model_yt_codex_monster,base.group_user,1,0,0,0
access_yt_codex_monster_public,yt.codex.monster public,model_yt_codex_monster,base.group_public,1,0,0,0
access_yt_codex_race_user,yt.codex.race user,model_yt_codex_race,base.group_user,1,0,0,0
access_yt_codex_race_public,yt.codex.race public,model_yt_codex_race,base.group_public,1,0,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
11 access_yt_resource_user yt.resource user model_yt_resource base.group_user 1 1 1 1
12 access_yt_resource_public yt.resource public model_yt_resource base.group_public 1 1 1 1
13 access_yt_resource_portal yt.resource portal model_yt_resource base.group_portal 1 1 1 1
14 access_yt_codex_resource_user yt.codex.resource user model_yt_codex_resource base.group_user 1 0 0 0
15 access_yt_codex_resource_public yt.codex.resource public model_yt_codex_resource base.group_public 1 0 0 0
16 access_yt_codex_creature_user yt.codex.creature user model_yt_codex_creature base.group_user 1 0 0 0
17 access_yt_codex_creature_public yt.codex.creature public model_yt_codex_creature base.group_public 1 0 0 0
18 access_yt_codex_monster_user yt.codex.monster user model_yt_codex_monster base.group_user 1 0 0 0
19 access_yt_codex_monster_public yt.codex.monster public model_yt_codex_monster base.group_public 1 0 0 0
20 access_yt_codex_race_user yt.codex.race user model_yt_codex_race base.group_user 1 0 0 0
21 access_yt_codex_race_public yt.codex.race public model_yt_codex_race base.group_public 1 0 0 0
+19 -27
View File
@@ -1,31 +1,23 @@
/* @odoo-module */
import { UserMenu } from "@web/web/user_menu/user_menu";
import { patch } from "@web/core/utils/patch";
import { useService } from "@web/core/utils/hooks";
/**
* 在 Odoo 18 后台用户下拉菜单插入"官网"入口。
* Odoo 18 用户菜单用 registry 注册制,UserMenu 在 web.assets_frontend_lazy 中。
*/
import { registry } from "@web/core/registry";
patch(UserMenu.prototype, "yt_world.UserMenu", {
setup() {
this._super(...arguments);
},
console.log("[yt_world] user_menu.js 开始执行");
get menuItems() {
const items = this._super(...arguments) || [];
const websiteItem = {
id: "website_link",
description: "官网",
href: "/",
callback: () => {
window.location.href = "/";
},
sequence: 5,
};
// Insert before "设置" (settings) and after separator-ish area
const insertIndex = items.findIndex(i => i.id === "settings");
if (insertIndex > -1) {
items.splice(insertIndex, 0, websiteItem);
} else {
items.unshift(websiteItem);
}
return items;
},
registry.category("user_menuitems").add("website", function (env) {
console.log("[yt_world] 官网菜单项被注册");
return {
type: "item",
id: "website_link",
description: "官网",
callback: () => {
window.location.href = "/";
},
sequence: 45,
};
});
console.log("[yt_world] user_menu.js 执行完毕");