术系统

by admin on 2018年12月16日

本篇是

广义的的说,和战结算相关的情还算是技能系统,包括技术音讯保管、技能调用接口、技能目标搜索、技能表现、技能结算、技能创生体(buff/法术场/弹道)管理,其它还关乎的模块包括:AI模块(技能调用者)、动作模块、寻路/移动模块和人物属性和重伤数值结算等。

PDF.NET数据开发框架实体类操作实例(MySQL)

的姐妹篇,两者拔取了跟一个测试程序,不同之只是下的类库和数据库不同,上边说说具体的以过程。

1,首先以App.config文件中配置数据库连接字符串:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <connectionStrings>
    <!--<add name ="default" connectionString ="server=192.168.50.XX;User Id=root;password=XXXX;database=test" providerName="PWMIS.DataProvider.Data.MySQL,PWMIS.MySqlClient"/>-->
    <add name ="default" connectionString ="server=127.0.0.1;User Id=postgres;password=XXXX;database=Test" providerName="PWMIS.DataProvider.Data.PostgreSQL,PWMIS.PostgreSQLClient"/>
  </connectionStrings>
</configuration>

2,定义一个用户实体类:

/*
 * PDF.NET 数据开发框架
 * http://www.pwmis.com/sqlmap
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PWMIS.DataMap.Entity;

namespace TestMySqlEntity
{
    class User:EntityBase 
    {
        public User()
        {
            TableName = “tb_user”;
            PrimaryKeys.Add(“ID”);//主键
            IdentityName = “ID”;//标识,自增
            PropertyNames = new string[] {“ID”,”Name”,”Age” };
            PropertyValues = new object[PropertyNames.Length];

        }

        public int ID
        {
            get { return getProperty<int>(“ID”); }
            set { setProperty(“ID”, value); }
        }

        public int Age
        {
            get { return getProperty<int>(“Age”); }
            set { setProperty(“Age”, value); }
        }

        public string Name
        {
            get { return getProperty<string>(“Name”); }
            set { setProperty(“Name”, value,50); }
        }
    }
}

跟MySQL中定义之用户实体类不同,下面就一行代码被诠释掉了:

 //IdentityName = “ID”;//标识,自增
虽说PostgreSQL有“自增”列,但无能为力直接获取到正插入的斯自增值,所以待注释它。

注:在PDF.NET SOD框架 5.6.0.1121
之后,框架撤除了即一个范围,你依然可以像以其他数据库中那么采取PostgreSQL的自增列,实体类无需开其余改变。

3,依照那一个实体类,我们去PostgreSQL定义一个用户表:tb_user,具体过程简单,注意字段“ID”如故以自增列(在PostgreSQL中凡是
serial
类型,但编制表类型的下,发现字段是整数类型,可是有了默认值:nextval(‘”User_ID_seq”‘::regclass))。

双重定义一个囤积过程查询指定条件的用户记录:

 

CREATE OR REPLACE FUNCTION “fn_queryUser2″(“Age” integer)
  RETURNS SETOF tb_user AS
‘select * from tb_user where “Age”>$1’
  LANGUAGE sql VOLATILE
  COST 100
  ROWS 1000;
ALTER FUNCTION “fn_queryUser2″(integer) OWNER TO postgres;

 

 

4,编写ORM实体类操作的测试代码:

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PWMIS.DataMap.Entity;
using System.Data;

namespace TestMySqlEntity
{
哲学原理,    class Program
    {
        static void Main(string[] args)
        {
            PWMIS.DataProvider.Data.AdoHelper db = PWMIS.DataProvider.Adapter.MyDB.GetDBHelperByConnectionName(“default”);
            //PWMIS.DataProvider.Data.AdoHelper db = PWMIS.DataProvider.Adapter.MyDB.Instance ;
            //MySQL 存储过程测试;
            //参数名字能够加 @符号,例如 @pAge1
            //DataSet ds1 = db.ExecuteDataSet(“proc_user1”,
            //    CommandType.StoredProcedure,
            //    new System.Data.IDataParameter[] { db.GetParameter(“@pAge1”, 18) });

            //PostgreSQL 的蕴藏过程就管参数顺序,不管参数名,假如存储过程名称来酷写字母,需要利用对引号
            //fn_queryUser2 定义之参数名字是 Age
            DataSet ds1 = db.ExecuteDataSet(“[fn_queryUser2]”,
              CommandType.StoredProcedure,
              new System.Data.IDataParameter[] { db.GetParameter(“@pAge1”, 18) });
            
            //
            User u = new User();

            //*************构建 OQL 查询表明式 ******* begin ************
            //查询实体集合
            //使用 OQLCompare 对象作为基准
            //OQL q = OQL.From(u).Select().Where(new OQLCompare(u).Comparer(u.Age, OQLCompare.CompareType.NoSmaller, 15)).END ;

            OQL q = new OQL(u);
            //使用OQL2 作为条件对象
            q.Select().Where(q.Condition.AND(u.Age, “>=”, 15)).OrderBy (u.Age ,”asc”);
            //使用 QueryParameter 数组作为基准,适合吃多独并列的And条件
            //q.Select().Where(new QueryParameter[] { new QueryParameter(“Age”, PWMIS.Common.enumCompare.NoSmaller, 15) }).OrderBy(u.Age, “asc”); 
            Console.WriteLine(“–OQL to SQL:\r\n”+q.ToString ());

            
            //*************构建 OQL 查询表达式 ******* end ************

            //查询实体列表
            var result = EntityQuery<User>.QueryList(q);
            Console.WriteLine(“–查询实体集合成功,数量:”+result .Count );

            Console.WriteLine(“\r\n–Executed SQL Text:\r\n{0}\r\n”, PWMIS.DataProvider.Data.CommandLog.Instance.CommandText);

            //查询单个实体
            u.Name = “zhang san”;
            q.Select().Where(u.Name);
            Console.WriteLine(“–OQL to SQL:\r\n” + q.ToString());
            User u1 = EntityQuery<User>.QueryObject(q);
            if (u1 != null)
                Console.WriteLine(“–查询单个实体成功!”);

            Console.WriteLine(“\r\n–Executed SQL Text:\r\n{0}\r\n”, PWMIS.DataProvider.Data.CommandLog.Instance.CommandText);

            //直接动用EntityQuery<T>.Instance 属性的插、修改、删除方法
            u.Name = “li si5”;
            u.Age = 28;
            //PostgreSQL 没有 @@IDENTITY 变量,所以无法将到刚刚的打增值
            //但可以行使 select currval(‘User_ID_seq’);
            //所以必须设置当前实体对应的注脚的自增字段体系名称
            //db.InsertKey = “User_ID_seq”;

            // Ver 5.6.0.1121 之后,框架撤废了这多少个限量

            if (EntityQuery<User>.Instance.Insert(u,db) > 0)
                Console.WriteLine(“–插入实体成功!”); //将自动吗ID属性赋值

            Console.WriteLine(“\r\n–Executed SQL Text:\r\n{0}\r\n”, PWMIS.DataProvider.Data.CommandLog.Instance.CommandText);

            
            u.Age = 29;
            if (EntityQuery<User>.Instance.Update(u,db) > 0)
                Console.WriteLine(“修改实体成功!”);

            Console.WriteLine(“\r\nExecuted SQL Text:\r\n{0}\r\n”, PWMIS.DataProvider.Data.CommandLog.Instance.CommandText);

            User u2 = new User();
            u2.Name = “wang wu”;
            u2.Age = 20;

            //使用EntityQuery<T> 的实例对象方法改进实体
            //只谋面更新赋值过的属性值
            EntityQuery<User> eq = new EntityQuery<User>(u2);
            eq.DefaultDataBase = db;//必须设置当前数据库访问对象
            if (eq.SaveAllChanges() > 0)
                Console.WriteLine(“–更新实体成功!”);

            Console.WriteLine(“\r\n–Executed SQL Text:\r\n{0}\r\n”, PWMIS.DataProvider.Data.CommandLog.Instance.CommandText);

            Console.Read();
        }
    }
}

 

只顾点代码中的当下同有的:

//PostgreSQL 没有 @@IDENTITY 变量,所以不能以到刚刚的打增值
            //但可以接纳 select currval(‘User_ID_seq’);
            //所以必须设置当前实体对应的表的自增字段序列名称
            db.InsertKey = “User_ID_seq”;

在PostgreSQL中,不同之发明得装不同的
InsertKey ,而当SQLSERVER等数据库被,始终以 InsertKey=“select @@IDENTITY ”;

注:在PDF.NET SOD框架 5.6.0.1121
之后,框架撤消了立刻一个限。可是原理上同原先是同一的,只然而框架自动处理了这些题材,前提是公要利用SOD自带的拍卖自增的方,自动创制表。

 

5,编译运行,得到下边的结果:

 

–OQL to SQL:
SELECT [ID],[Name],[Age]
 FROM [tb_user]
   Where  [Age] >= @Age0
        Order by [Age] asc
–查询实体集合成功,数量:18

–Executed SQL Text:
SELECT “ID”,”Name”,”Age”
 FROM “tb_user”
   Where  “Age” >= @Age0
        Order by “Age” asc

–OQL to SQL:
SELECT [ID],[Name],[Age]
 FROM [tb_user]
   Where [Name]=@Name

–查询单个实体成功!

–Executed SQL Text:
SELECT “ID”,”Name”,”Age”
 FROM “tb_user”
   Where “Name”=@Name

–插入实体成功!

–Executed SQL Text:
INSERT INTO “tb_user”(“Name”,”Age”) VALUES (@P0,@P1)

改实体成功!

Executed SQL Text:
UPDATE “tb_user” SET “Age”=@P0 WHERE “ID”=@P1

–更新实体成功!

–Executed SQL Text:
INSERT INTO “tb_user”(“Name”,”Age”) VALUES (@P0,@P1)

 

 

只顾:在PostgreSQL中,SQL语句被的字段名要使用对引号,PDF.NET数据开发框架为您活动就就所有,使得你的SQL语句可以挺易之移植到PostgreSQL。

最后,附带一个PostgreSQL中选取触发器模拟自增与无行使自增,还有跟MySQL自增下,CRUD数据的一个效用比测试数据,测试程序要看源码的
SampleOrmTest示例:

====**************** PDF.NET SOD ORM 控制台测试程序 **************====
框架核心程序集 PWMIS.Core Version:5.6.0.1111

====应用程序配置文件默认的数据库配置信息:===========================
-------测试1---使用触发器做自增测试------------------------------

当前使用的数据库类型是:PostgreSQL
连接字符串为:server=127.0.0.1;User Id=root;password=;DataBase=mydb
请确保数据库服务器和数据库是否有效(SqlServer,Access 会自动创建数据库),
继续请回车,退出请输入字母 Q .
=====Power by Bluedoctor,2015.3.1 http://www.pwmis.com/sqlmap =======


-------PDF.NET SOD ORM 测试 开始 ---------
测试:用户zhang san 的密码和注册日期已经更新
--删除 1002条数据--
--插入 1001条数据--
--修改 3次数据,User ID:1048--
SOD ORM的 6种 查询方式,开始----
Login0:True
Login1:True
Login2:True
Login3:True
Login4:True
Login5:True
Login6:False
模糊查询姓 张 的用户,数量:10
-------PDF.NET SOD ORM 测试 全部结束-----
耗时:(ms)1050

-------测试2---不使用触发器做自增测试------------------------------

当前使用的数据库类型是:PostgreSQL
连接字符串为:server=127.0.0.1;User Id=root;password=;DataBase=mydb
请确保数据库服务器和数据库是否有效(SqlServer,Access 会自动创建数据库),
继续请回车,退出请输入字母 Q .
=====Power by Bluedoctor,2015.3.1 http://www.pwmis.com/sqlmap =======


-------PDF.NET SOD ORM 测试 开始 ---------
测试:用户zhang san 的密码和注册日期已经更新
--删除 1001条数据--
--插入 1001条数据--
--修改 0次数据,User ID:0--
SOD ORM的 6种 查询方式,开始----
Login0:True
Login1:True
Login2:True
Login3:True
Login4:True
Login5:True
Login6:False
模糊查询姓 张 的用户,数量:10
-------PDF.NET SOD ORM 测试 全部结束-----
耗时:(ms)779

======================================================
-------测试3---MySQL对比测试(使用自增)------------------------------

当前使用的数据库类型是:MySql
连接字符串为:server=127.0.0.1;User Id=root;password=;DataBase=test
请确保数据库服务器和数据库是否有效(SqlServer,Access 会自动创建数据库),
继续请回车,退出请输入字母 Q .
=====Power by Bluedoctor,2015.3.1 http://www.pwmis.com/sqlmap =======


-------PDF.NET SOD ORM 测试 开始 ---------
测试:用户zhang san 的密码和注册日期已经更新
--删除 1002条数据--
--插入 1001条数据--
--修改 3次数据,User ID:11103--
SOD ORM的 6种 查询方式,开始----
Login0:True
Login1:True
Login2:True
Login3:True
Login4:True
Login5:True
Login6:False
模糊查询姓 张 的用户,数量:10
-------PDF.NET SOD ORM 测试 全部结束-----
耗时:(ms)604

 

 

 

 

预先说下技术模块每个片的天职以及原理:

  • 技巧音信保管:管理unit所享有的技艺以及技巧的等级、cd等。在我们娱乐被,这里尚需负责管理符文,符文会对技术音讯举办修改。
  • 艺调用接口:AI或者UI操作触发技能,触发技能时或许选取了一个对象(AI),也说不定并没有目的。
  • 技术流程管理:一个技能或鉴于五只子技能因运动的履情势组合而成,而诸一个最后实施之艺执行进程吧是一个流水线,一般包括:前摇过程-结算点-后摇过程。技能在前摇截止时入技能真正的结算流程,结算流程或创建子弹,也说不定触发buf或者成立法术场。
  • 技巧目的搜索:若技能触发时已经安装了技能目的unit(如大物AI释放技能),则直拿其当做靶子unit,否则需依照早晚之方针拔取一个目标。另外,技能释放的早晚还待自由方向与刑释解教地方等音信,也透过这多少个模块获取。
  • 技巧表现:技能释放过程中,需要创建相应的特效及实践相应的动作。
  • 艺创生体(buf/弹道/法术场)管理:buf挂在unit身上,可能影响unit的片段行为以及状态;法术场一般由气象管理,影响场景中某范围外之unit;弹道就是技巧创制的一个子弹,这一个子弹或以不同之途径走(直线/抛物线/直接命中等)

0技能表

率先说生促成技术的基本思路。实现技术的基本思路就是通过策划填写表格,来配制成某些技术,在实施某技能的时,分别去因这一个报表中之情,确定技能如何展现。基本的逻辑是:

if skillTable.get("技能动作"):
     paly 动作
if skillTable.get("特效"):
     播放特效
if skillTable.get("法术场"):
    创建法术场
....

1 技能音讯保管

unit成立时,此模块管理unit可下什么技术,比如游戏受玩家可选下什么技能。

娱乐中技术的升级、技能加点、技能池管理都当这一个模块。

此模块还用管住技术等级/符文/装备等标模块对技术参数的修改。

2 技能调用接口

提供技术调用的接口供AI或玩家操作调用,调用时得供一个对象unit,也堪无提供给技艺自己找寻。

提供三单接口:

  • 艺先导skill_enter:发轫履行技术,若技能不循环举办,则技能可活动终止。
  • 技能了skill_exit:有的技术不可能和谐了,比如一些循环技能,对于循环技能玩家可以停按钮一贯释放。当玩家松手按钮,调用技能了接口,告诉当前技术使该得了,此时技能到后摇点时,技能不再继续执行。
  • 艺截至skill_stop:当技术被胁持打断时,如给口诛笔伐、晕眩、蓝不足等,技能会受威迫截至。

此外,当前一个技正在尽时新的艺调用启动,此时新的技能调用信息会让保存。一般的话,并无会面把富有新的技术调用消息保存下去,这样就成了一个技术执行的行列。我们耍就保留一个新的技术调用信息。

如上所述,技能模块提供尽可能少之接口供AI/UI等上层逻辑下,这样好中之与AI和UI举行解耦。

3 技能流程管理

技巧流程这里分点儿接触探究:

  1. 一个技艺或由于四只子技能因为自然的形式做起来。
    一个技巧通常由多单子技能因为自然的格局组合而成,比如三段相撞、比如冲锋斩(先冲锋、后斩)等,甚至还存在因不同之条件拔取执行不同的子技能。分析图需求发现,技能可分为一个树形结构,这一个树形结构极度相近表现培训,同样好将节点分为控制节点和实施节点,甚至可以包括condition节点。为之,我们种引入一个术作育概念来讲述这种数据结构。

  2. 一个切实的技能(技能培训执行节点)也闹一个定位的尽流程。那一个流程一般也:前摇过程、前摇过程截至=技能结算时间点、后摇时间点。

3.1 技能树

技巧作育参考传统行为树的统筹,使用树形结构决定技能的施行流程。

技术作育和作为培训在结构上相比较相近,但是于运行逻辑上起良可怜的两样。

首先,技能培训之要并无是基于上下文选拔一个适度的节点执行,而是以一定之方针将技艺作育从头到尾遍历执行同样全副。

副,技能培养没tick的概念,而是基于回调的,比如一个依次节点,顺序节点受到一个子节点执行了后,立时通告顺序节点,顺序节点执行下一个子节点,直至顺序节点的末梢一个子节点执行了,顺序节点就会晤通告父节点(假诺起)它已施行了。

其它,为了完成技术的片需求,控制节点往往蕴藏更多的主宰音讯来控制子节点的履行流程。具体的信息按照策划需求设置,比如顺序结点包括原子属性与循环属性。假若一个各样节点有所原子属性,则这顺树节点在履的经过中并无会晤受end,唯有满子节点执行完毕才可以end。

坐我们打中战士普攻三截相撞为条例:

Paste_Image.png

老三截相撞本身是一个挨家挨户节点,当技术先河时,此节点顺序执行三独子节点。对于第一个子节点,它如故是一个依次节点,首先冲锋至目的单位身前,然后对目的单位举办挥砍。不过冲锋节点还包了一个condition,若与目的的偏离挺守,则超过了冲锋节点,直接挥砍。

普攻是一个巡回技能,这多少个技能只要玩家点正在按钮无放,技能便会见一向施行,因而根本节点(普攻)是一个独具循环属性的依次节点。而对子技能1(控制节点),他是一个有所原子属性的相继技能,即当单位在冲刺时,玩家放手按钮,单位吗会师履行完挥砍后才会出技能。


!关于技能作育的使用和思索

技术培训起来的计划性思路是,有些技能的履流程以及表现培训类,比如因为自然的次第执行同一序列子技能,比如按照不同的上下文确定技能的进行流程。简单的讲,技能培养的引入有以下好处:1.一旦技能模块可拿走有AI的能力,从而以与技巧赛相关的AI逻辑在技术模块使技能模块和AI模块降低耦合,2.可以清楚的叙说技能流程,3.下树多拓展性,策划好计划来各式各类复杂的艺。

关于好处1,举个例子:屠夫boss的勾子技能可用玩家拉过来,若成功的拖累过来,boss会执行一个攻击子技能,否则不履行。通过如此可以勾人和攻击作为少数单子技能成技能培训,攻击子技能有一个condition过程,即判断上一个子技巧是否中标。

术作育于使后渐渐发现部分题材,首先,技能培育的齐要求每个树节点都开展协同,增加并负担,其次,技能本身并无会面来无比复杂的控制结构。

啊之,后来大家对技术培育举办了优化:
1.简化同步音信,不再并所有节点的enter/exit消息(具体参考著作《技能模块的协同》)。
2.撤并行节点,通过拓展表头实现一个技术同时进行多件工作。

最后之技艺培训多是只有顺序/随机二种控制项目节点,节点有所较轻度的condition功用。


3.2 执行节点的技巧流程

诚如的话,技能的行流程包括:

  • 前摇工夫:技能起初,但是技术真正的结算流程还无开。技能起首下,机能相关的特效和动作就是最先广播。
  • 前摇时截至:技能前摇了时技术开头真正的获释以及结算,等技巧前摇了将来,技能真正的自由并结算。释放包括创设相应的弹道/法术场和buff。
  • 技能后摇点:技能播放到后摇点时间时不时,技能真正的截止。这时,技能对应的特效及人物动作可能还会继续播放,不过技术流程已经正式终止了。也就是说,下一个技可执行。

4 技能目的搜索

技术释放时,目标可能早已由AI传给了技能模块,也暴发或无一个靶,如玩家控制单位。

技能在放法术场、弹道的时刻,首要的凡技巧的取向而未是技术目标一般的话,技能拿到一个靶靶下,技能的趋势就是是释法者到对象的趋向。

此外,技能方向或需要部分布置,如前方摇锁定(前摇过程被目标运动,技能方向不移),UI可决定(技能释放过程遭到,玩家可透过控制UI控制技能的释放方向)。

5技能表现

技术的显示包括动作、特效、shader、音效等。其中,特效相比较复杂,需要安排的内容吧较多。比如,有些特效挂于范上,有的特效挂在场合里。对于法术场的特效,分别可分为法术场起始、结算、为止特效,分别在法术场起先日常、结算时、截止时显得。对于buff也仿佛。

6 弹道、法术场和buff等技能创生体

狭义的吧,技能只是当技术的实施流程(技能培育管理与技术流程管理),而技真正的结算首如果由于其创造生体结算的。当技术前摇了起生效时,技能创立相应的弹道和法术场,法术场弹道击中冤家时还要发生或来相应的buff。

诚如的话,法术场是一个情景的某块检测区域,每隔一段时间法术场检测这区域之仇人,并对准这攻击结算。
弹道是相同类子弹移动路径的虚幻,创造一个弹道就代表一个子弹特效沿这弹道移动并检测路径上之仇。
buff就是挂于单位身上的一个具备持续时间的状态,状态对单位爆发有尊重或负面的影响,并且于那多少个段猪时间内,每隔一段时间举办同样不行重伤结算

对于技术、法术场、buff之间的效益界定并无是卓殊稳定,比如技能是否直接针对单位导致损伤,法术场能否对单位招损伤,甚至技能只可以创设法术场,法术场只好检测对象不能招致伤害,只可以挂buff,而有所的祸害如故经buff来结算。当然,这样并不一定好,一般的话,技能和法术场都可以针对单位招伤害。

总的说来,创生体效率的限制需要遵照策划需求、功效考虑当元素调整。

6.1 Buff状态

Buff就是挂于单位身上连一定时间的利如故危害的状态,这里状态=buff。

Buff模块出只待留意的是Buff之间的相互关系,如排斥(A状态在,B状态挂不上来),清除(A状态挂上去同时招致B状态没有)等。

为了落实上述功用,最简易的格局是在状态A中一向填状态关系状态字段,如状态A排斥状态B/C/D/E…,A状态清除状态X/Y/Z…。

如上之兑现情势暴发只问题,等游戏做到先前时期,我们有诸六个buff状态,那么一个魔法免疫状态,策划要填表的排斥状态恐怕过多。

为了化解那题目,可以以分类的构思解决。定义某类状态和此外一样好像状态里的平整。
依照以上思想,引入一个叫buff原子状态的概念,原子状态表示无异接近状态,如减速、禁魔、魔免、悬空、晕眩、变羊等等等。

于为单位挂一个初的buff的前面,查询此buff持有的原子状态及单位身上就局部原子状态中的涉,依据单位身上既有些原子状态判定新的原子状态应当用何种行为处理。

此地的何种行为,代表的饶是原子状态里的平整,如排斥等。这么些规则可被策划填一个名字为“原子状态关系”的阐发,此表是一个n*n的二维数组,n为游戏中负有的原子状态的多寡。

原子状态的数量远小于buff的数量,所以可以挺易之概念这个规则。

6.2 法术场

法术场描述对同一片区域之震慑,这块区域可以各隔一段时间举办相同蹩脚检测,检测这块区域外之单位还要对单位开展结算。

法术场需要小心一个问题,就是一个法术场每一遍结算可能以不同的参数举行结算,比如一个术,第一次结算对每个单位展开晕眩,第二软结算对单位举办摧残。

缓解那种题材较间接的格局是技巧直接开立六只法术场,每个法术场结算一不行,第二独法术场创制有延迟时间。不过这种措施发出个问题,有或策划需求做一个结算十次并且每趟结算的参数都不比之法术场。那么,一个艺以得的时光间隔成立是个法术场,同时法术场的保管有自然的基金,从而造成效用的退。

否釜底抽薪是题材,我们优化了法术场结算的贯彻机制,增添了扳平栽新的法术场:体系法术场。这仿佛法术场策划好安排法术场每便结算中间的时刻间隔和历次结算所动的法术场参数。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图