ProjectDescription - ScutGame/Scut GitHub Wiki

此章节介绍如何搭建服务端项目工程

新建立项目

Scut的开发环境要在VS2013以上版本

  1. 首先打开VS2013,创建一个“类库”类型的项目;

    Project add

  2. 选择Scut最新的Lib类库,将Lib目录和Console目录下的所有文件复制到新创建的类库项目中;

  3. 添加dll引用,切换到VS解决方案管理器中,将所有dll引用到项目中;

  4. 在VS解决方案管理器中,选择项目点击“显示所有文件”,将Script目录与GameServer.exe.config和Nlog.config文件包含到项目中;

  5. 调试项目,右击项目选“属性”,打开“调试”栏选择“启动外部程序”设置为“GameServer.exe”路径,并将工作目录设置成与GameSession.exe文件同级目录(此设置会影响Log的输入目录);

    Project property

下面是Scut服务端项目的目录结构:

ScutProject

理解目录结构

  1. 第一部分: Script脚本目录

包括:Model、CsScript、PyScript和LuaScript子级目录;不能有含有其它自定义的目录或文件,自定义的目录或文件是不会被监听的。

  • Model目录: 所有脚本统一使用的数据实体类目录,它是单独编译的子项目;此目录下的脚本不能调试,因此不要在脚本内写业务处理代码;

  • CsScript目录: C#脚本的业务逻辑目录,C#开发者使用,包括以下子目录和文件:

    Action子目录: 与客户端对接的通讯协议处理接口类,包括:处理请求包,响应封包等方法;

    Locale子目录: 本地化的多语言化处理类,如:提示语;

    MainClass.cs文件: C#脚本启动入口,包括:程序启动,程序停止,接收请求,打开连接,关闭连接和心跳包接收等方法;

    扩展子目录: 可以根据需要在CsScript目录下划分子目录,如以功能划分:Chat(聊天)、Plot(副本)、Task(任务)等。

  • PyScript目录: Python脚本的业务逻辑目录,Python开发者使用,包括以下子目录和文件:

    Action子目录: 与客户端对接的通讯协议处理接口类,包括:处理请求包,响应封包等方法;

    Lib子目录: Python脚本开发者的类库

  • LuaScript目录: Lua脚本的业务逻辑目录,Lua开发者使用;

  1. 第二部分: Scut类库与第三方类库

包括所有的dll文件,ZyGames名称开头的是Scut的类库,其它的是第三方类库。

  1. 第三部分: GameServer宿主程序与ScutSMS工具

包括以下文件:

  • GameServer.exe文件: 以Console控制台方式运行的宿主程序;

  • GameServer.exe.config文件: 宿主程序的配置文件;

  • Nlog.Config文件: 第三方错误跟踪Log日志类库的配置文件,包括:输出的目录位置,错误级别输出控制和Log输出的类型控制(输出的类型:文件,控制台,Trace和Azure第三方存日志储等);

  • ScutSMS.exe文件: Scut提供的工具,可以方便配置游戏的参数和Redis数据的操作;

Config配置文件

  1. NLog.config文件: 游戏服日志文件配置,使用第三方的Nlog类库,结点"logDirectory" 是配置日志文件输出的路径,其它结点按默认配置。

    <variable name="logDirectory" value="d:\NLog\XXgame"/>
    
  2. GameServer.exe.config文件: 游戏服的主要配置,包括:数据库连接配置,Redis连接配置和其它游戏环境配置等;可以打开当前目录下的ScutSMS工具进行配置。

    <?xml version="1.0"?>
    <configuration>    
      <!--基本参数配置,其它详细参数通过ScutSMS工具查看参数-->
      <appSettings>
        <add key="Redis.Host" value="127.0.0.1:6379"/> <!--Redis服务的连接串,格式:password@host:port -->
    
        <add key="Script_IsDebug" value="True"/> <!--开启脚本调试模式-->
      </appSettings>
    
      <!--数据库连接串配置-->
      <connectionStrings>
        <!--
        @name: 连接串的标识Key,是Entity类配置的EntityTable属性的ConnKey参数值,两者要对应上
        @providerName: 连接的数据库驱动类型;SqlDataProvider是SQL数据库的连接,MySqlDataProvider是MySql数据库的连接
        @connectionString: 数据库连接串,与SQL或MySql数据库的连接串相同
        -->
        <add name="ConnData" providerName="SqlDataProvider" connectionString="Data Source={服务器地址};Database={数据库名};Uid={登录帐号};Pwd={登录密码};"/>
      </connectionStrings>
    </configuration>

Redis配置注意:

  • 一个Redis库只能被一个GameServer绑定,防止串库数据回档,否则启动时会有错误,这在新版本中有增加限制了;
  • 绑定的规则:机器名+GameServer路径,如果移动了项目位置,可以通过Redis-clie客户端连接到Redis服务器并直接删除"__redisinfo"的键;

开发者疑问

  1. 创建项目时为什么选择的是类库类型项目,而不是Console类型项目

    由于Scut已经提供了直接可运行的Consele(GameServer.exe)项目,开发者开发的脚本可以直接宿主在GameServer项目中运行。

  2. Model与CsScript之间的类交叉引用运行出错问题

    Scut运行时会分别为Model与CsScript两个dll在temp目录下(通过查看属性可以区分哪个是Model的dll),它们之间是有依赖层级关系的,CsScript的程序集引用Model的程序集,如果Model中有类使用了CsScript的类,就会发生编译出错,在Log的Exception目录下会有编译出错详细信息。

  3. 使用类库类型的项目如何调试框架内的代码

    .net项目调试是需要*.pdb类型的文件才可以调试,在Scut提供的Lib库中如果没有提供此类文件,需要自己编译源码生成*.dll*.pdb文件, 编译源码步骤如下:

    • 先Git下载Scut的源码,并打开源码中的Framework项目,使用Debug的编译方式生成代码;
    • 接着在Framework目录\bin\Debug\*.dll*.pdb所有文件Copy到你自己的项目目录下(如果使用Release编译,是在bin\Release目录);
    • 同上,打开源码中的Middleware项目,编译后,Copy GameServer\bin\debug\目录下的*.dll与`*.pdb和GameServer.exe;
    • 接下来,在脚本类中设置断点,VS项目中按F5,启动调试,如果断点显示的是实心红点说明断点设置成功,否则失败,检查以上步骤中是否遗漏;
  4. 创建项目默认是以脚本源码方式运行,如果想直接使用编译好的dll如何运行

    • Scut运行时,对Model会注入属性修改事件,在修改属性时才会保存数据,因此需要将Model所在的项目在编译时也要注入,用记事本打开项目中的.csproj文件,在结尾增加如下配置;
    <Project>
      ...
      <UsingTask TaskName="ZyGames.Framework.Common.Build.WeavingEntityTask" AssemblyFile="bin\$(Configuration)\ZyGames.Framework.Common.dll" />
      <Target Name="AfterBuild">
        <WeavingEntityTask SolutionDir=".\\bin\$(Configuration)" FilePattern="{项目程序集的名称}.dll" />
      </Target>
    </Project>
    

    配置好重新编译成功后,使用反射工具(ILSpy)打开生成的dll,可以看到属性中的代码有BindAndChangeProperty方法,它会触发保存的事件:

    [ProtoMember(8), EntityField]
    public ushort RoleLv
    {
    [CompilerGenerated]
    get
    {
    	return this.<RoleLv>k__BackingField;
    }
    [CompilerGenerated]
    set
    {
    	if (!object.Equals(this.<RoleLv>k__BackingField, value))
    	{
    		this.<RoleLv>k__BackingField = value;
    		base.BindAndChangeProperty(this.<RoleLv>k__BackingField, "RoleLv");
    	}
    }
    }
    
    • 接着需要在GameServer.exe.config文件中配置ScriptAsmReferences的键值,将你的项目dll配置进去,多个以';'分隔
    • CsScript目录上需要有MainClass文件,Model与CsScript目录下就不需要放其它脚本文件了
⚠️ **GitHub.com Fallback** ⚠️