Scut快速開發(3)
1 開發環境
Scut Lib版本:5.2.3.2
需要安裝的軟件
a) IIS和消息隊列(MSMQ)
b) 數據庫,Sql2005以上版本
c) VS2010開發工具(.Net Framework 4.0以上)
d) Python2.6(ScutGame官網下載IronPython2.6.1 RC1 for .NET 4.0插件)
工具
a) 協議工具(目錄Source\Tools\ContractTools)
2 代碼框架
項目划分三層:實體層,組件層,業務邏輯層(腳本層);模型層主要是數據實體映射,自定義緩存結構;組件層主要負責實現中層層擴展功能;業務邏輯層主要負責實現游戲功能;
2.1 數據庫創建
游戲划分成三個庫:DemoConfig庫(負責存儲游戲配置數據) 、DemoData庫(負責存儲游戲玩家數據)和DemoLog庫(游戲玩家日志記錄數據);如圖
這里只為每個庫建立一張表:
2.2 項目搭建
2.2.1 創建解決方案
打開VS2010 在菜單上選擇 文件 -> 新建 -> 項目;彈出“新建項目”對話窗口,在左則展開“其它項目類型”,選擇“Visual Studio解決方案”,選擇“.Net Framework 4.0”后,輸出項目名稱及位置,再點擊“確定”;如圖:
2.2.2 創建項目
在“資源管理器”中添加新的幾個項目Model、Lang、Com、Bll、HostServer;Model項目:負責從數據庫中導出表的數據實體類映射;
Lang項目:負責多語言包;
Com項目:負責中間層組件擴展處理,及中間層業務實體類;
Bll項目:負責業務邏輯處理;
HostServer項目:控制台啟動程序,及腳本(Python)業務邏輯處理;
如圖:
創建項目結果如下:
設置控制台程序“HostServer”屬性為“.Net Framework 4.0”
設置成“Release”編譯方式
2.2.3 Model項目
組件引用
項目 |
引用路徑 |
Model |
Lib\protobuf-net.dll
Lib\ZyGames.Framework.Common.dll
Lib\ZyGames.Framework.dll
Lib\ZyGames.Framework.Game.dll |
目錄划分
划分配置庫(ConfigModel)、玩家信息庫(DataModel)、玩家日志庫(LogModel)和自定義類型數據實體(Model)目錄存儲數據實體類; Enum目錄存儲自定枚舉;
DbConfig類
在生成實體類時,生成配置ConnectKey項中使用
public class DbConfig { public const string Config = "DemoConfig"; public const string Data = "DemoData"; public const string Log = "DemoLog"; public const int GlobalPeriodTime = 0; public const int PeriodTime = 0; public const string PersonalName = "UserId"; } //UserId:是玩家庫中表的主鍵字段名稱; 紅色部分是需要修改的
項目建立完成如圖:
實體靜態注入配置
用記事本打開Demo.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="Demo.Model.dll" /> </Target> ... ... </Project>
2.2.4 Lang項目
組件引用
項目 |
引用路徑 |
Lang |
Lib\ZyGames.Framework.Common.dll Lib\ZyGames.Framework.Game.Lang.dll |
負責處理多語言包配置,需要實現中層提供的語言包;以下是定義類
LanguageManager類
public class LanguageManager { private static object thisLock = new object(); private static Dictionary<LangEnum, IGameLanguage> _langTable = new Dictionary<LangEnum, IGameLanguage>(); private static LangEnum _langEnum; static LanguageManager() { _langEnum = (ConfigUtils.GetSetting("LanguageType", "0")).ToEnum<LangEnum>(); LanguageHelper.SetLang(_langEnum); } public static IGameLanguage GetLang() { return GetLang(_langEnum); } public static IGameLanguage GetLang(LangEnum langEnum) { IGameLanguage lang = null; if (!_langTable.ContainsKey(langEnum)) { lock (thisLock) { if (!_langTable.ContainsKey(langEnum)) { switch (langEnum) { case LangEnum.ZH_CN: _langTable.Add(langEnum, new GameZhLanguage()); break; default: throw new Exception("Language is error."); } } } } lang = _langTable[langEnum]; return lang; } }
IGameLanguage接口
public interface IGameLanguage : ILanguage { #region /// <summary> /// 君主帳號 /// </summary> int SystemUserId { get; } /// <summary> /// 玩家名稱 /// </summary> string KingName { get; } string Date_Yesterday { get; } string Date_BeforeYesterday { get; } string Date_Day { get; } string St1002_GetRegisterPassportIDError { get; } string St1005_NickNameOutRange { get; } string St1005_NickNameExistKeyword { get; } string St1005_NickNameExist { get; } string St1006_PasswordTooLong { get;} string St1006_ChangePasswordError { get;} string St1006_PasswordError { get;} string St1066_PayError { get; } #endregion }
GameZhLanguage類
class GameZhLanguage : BaseZHLanguage, IGameLanguage { public int SystemUserId { get { return 1000000; } } public string KingName { get { return "系統"; } } public string Date_Yesterday { get { return "昨天"; } } public string Date_BeforeYesterday { get { return "前天"; } } public string Date_Day { get { return "{0}天前"; } } public string St1002_GetRegisterPassportIDError { get { return "獲取注冊通行證ID失敗!"; } } public string St1005_NickNameOutRange { get { return "您的昵稱輸入有誤,請重新輸入!"; } } public string St1005_NickNameExistKeyword { get { return "您輸入的昵稱存在非法字符,請重新輸入!"; } } public string St1005_NickNameExist { get { return "您輸入的昵稱已存在,請重新輸入!"; } } public string St1006_PasswordTooLong { get { return "輸入錯誤,請輸入4-12位數字或字母!"; } } public string St1006_ChangePasswordError { get { return "修改密碼失敗!"; } } public string St1006_PasswordError { get { return "密碼格式錯誤!"; } } public string St1066_PayError { get { return "充值失敗"; } }
2.2.5 Com項目
組件引用
項目 |
引用路徑 |
Com |
Lib\protobuf-net.dll Lib\ZyGames.Framework.Common.dll Lib\ZyGames.Framework.dll Lib\ZyGames.Framework.Game.Lang.dll Lib\ZyGames.Framework.Game.dll Model Lang |
划分中間件業務實體(Model),聊天組件(Chat)與排行榜(Rank)等目錄,如圖:
需要使用中間層的功能,請參考《中間層使用文檔》
2.2.6 Bll項目
組件引用
項目 |
引用路徑 |
Bll |
LibNewtonsoft.Json.dll Lib\IronPython.dll Lib\ZyGames.Framework.Common.dll Lib\ZyGames.Framework.dll Lib\ZyGames.Framework.Plugin.dll Lib\ZyGames.Framework.RPC.dll Lib\ZyGames.Framework.Game.Lang.dll Lib\ZyGames.Framework.Game.dll Lib\ ZyGames.Framework.Game.Contract.dll Model Lang Com |
功能划分
創建Action目錄划分接口協議處理邏輯;主要提供中間層定義的固定協議接口,如:登錄(1004)與建角(1005)及充值中間層接口
ActionIDDefine類
public class ActionIDDefine { ///<summary> ///客戶端注冊Socket ///</summary> public const Int16 Cst_Action100 = 100; ///<summary> ///錯誤日志 ///</summary> public const Int16 Cst_Action404 = 404; ///<summary> ///注冊通行證ID獲取接口 ///</summary> public const Int16 Cst_Action1002 = 1002; ///<summary> ///用戶注冊 ///</summary> public const Int16 Cst_Action1003 = 1003; ///<summary> ///用戶登錄 ///</summary> public const Int16 Cst_Action1004 = 1004; ///<summary> ///創建角色 ///</summary> public const Int16 Cst_Action1005 = 1005; }
BaseAction類
public abstract class BaseAction : AuthorizeAction { protected BaseAction(short actionID, HttpGet httpGet) : base(actionID, httpGet) { } protected override bool IgnoreActionId { get { //排除不需要登錄授權的協議接口 return actionId == ActionIDDefine.Cst_Action404; } } }
2.2.7 HostServer項目
組件引用
項目 |
引用路徑 |
HostServer |
LibNewtonsoft.Json.dll LibNLog.dll Lib\protobuf-net.dll
Lib\IronPython.dll Lib\IronPython.Modules.dll Lib\Microsoft.Dynamic.dll Lib\Microsoft.Scripting.dll
Lib\ServiceStack.dll Lib\ ServiceStack.Common.dll Lib\ ServiceStack.Interfaces.dll Lib\ ServiceStack.Redis.dll Lib\ ServiceStack.Text.dll
Lib\ZyGames.Framework.Common.dll Lib\ZyGames.Framework.dll Lib\ZyGames.Framework.Plugin.dll Lib\ZyGames.Framework.RPC.dll Lib\ZyGames.Framework.Game.Lang.dll Lib\ZyGames.Framework.Game.dll Lib\ ZyGames.Framework.Game.Contract.dll Model Lang Com Bll |
功能划分
划分PyScript目錄,存放Python腳本文件;層次如圖:
Action目錄:處理請求與響應的腳本,可以協議生成器工具中Copy部分模板;
Lib目錄:Python中間層腳本,復制Scut開發包中的PythonLib目錄;
Remote:應用程序之間內通訊,訪問時有IP訪問限制;
Route.config.xml:是請求路由配置表,格式如下:
<?xml version="1.0" encoding="utf-8" ?> <config> <!--Python安裝類庫路徑--> <lib path="D:\Python\Lib" /> <route-list> <!--配置Action路由 action:映射的Action代碼 path:指定執行的腳本路徑 ignoreAuthorize:是否不需要登錄授權,true:不需要登錄授權 --> <route action="404" path="Action\action404.py"/> <route action="1009" path="Action\action1009.py"/> </route-list> </config>
GameHostApp類
class GameHostApp : GameSocketHost { private static GameHostApp instance; static GameHostApp() { instance = new GameHostApp(); } private GameHostApp() { } public static GameHostApp Current { get { return instance; } } protected override void OnConnectCompleted(object sender, ConnectionEventArgs e) { Console.WriteLine("Client:{0} connect to server.", e.Socket.RemoteEndPoint); } protected override void OnRequested(HttpGet httpGet, IGameResponse response) { try { ActionFactory.Request(httpGet, response, null); } catch (Exception ex) { Console.WriteLine("{0}", ex.Message); } } protected override void OnStartAffer() { try { //時º¡À間?間?隔?更¨¹新?庫a int cacheInterval = 600; GameEnvironment.Start(cacheInterval, () => true); Console.WriteLine("The server is staring..."); } catch (Exception ex) { TraceLog.WriteError("The server start error:{0}",ex); } } protected override void OnServiceStop() { GameEnvironment.Stop(); } }
Program類
static void Main(string[] args) { try { GameHostApp.Current.Start(); } catch (Exception ex) { Console.WriteLine(ex.Message); TraceLog.WriteError("HostServer error:{0}", ex); } finally { Console.WriteLine("Press any key to exit the listener!"); Console.ReadKey(); GameHostApp.Current.Stop(); } }
宿主程序Config配置
<?xml version="1.0"?> <configuration> <configSections> <section name="zyGameBaseBll" type="ZyGames.Framework.Game.Configuration.ZyGameBaseBllSection,ZyGames.Framework.Game"/> <section name="zyGameBase-GM" type="ZyGames.Framework.Game.Command.GmSection,ZyGames.Framework.Game"/> <section name="sdkChannel" type="ZyGames.Framework.Game.Sns.Section.SdkChannelSection,ZyGames.Framework.Game"/> </configSections> <appSettings> <!--必須配置 Port:監聽端口 Code:產品代碼 ServerId:產品游服代碼 --> <add key="Product.Code" value="1" /> <add key="Product.Name" value="" /> <add key="Product.ServerId" value="1" /> <add key="Game.Port" value="9701" /> <!--可選配置 MessageQueuePath:消息隊列中創建指定的專用名稱 Action.AssemblyName:Python開發不用設置, 當使用C#語言開發的Action接口必須設置 SignKey:請求簽名Key PublishType:發布版本類型,Debug:請求出錯會有信息通知客戶端(正式發布可刪除) EnableGM:開啟可使用GM命令(正式發布可刪除) Python_IsDebug:設置python可以調試(正式發布可刪除) PythonRootPath:修改Python執行的相對路徑(正式發布可刪除) --> <add key="Game.Action.AssemblyName" value="ZyGames.Demo.Bll"/> <add key="MessageQueuePath" value=".\private$\DemoCmdSql"></add> <add key="Product.SignKey" value="44CAC8ED53714BF18D60C5C7B6296000"/> <add key="PublishType" value="Debug"/> <add key="EnableGM" value="true"/> <add key="Python_IsDebug" value="true" /> <add key="PythonRootPath" value="..\..\PyScript" /> <!--通用組件配置開始 PayDB:充值模塊功能使用的數據庫配置(ConnectionString:連接串,Server:服務器,Acount:加密后的登錄帳號與密碼) Snscenter:用戶中心模塊使用的數據庫配置(ConnectionString:連接串,Server:服務器,Acount:加密后的登錄帳號與密碼) 注(Acount原串:"Uid=sa;Pwd=123" 密鑰:BF3856AD) --> <add key="PayDB_ConnectionString" value="Data Source={0};Database=PayDB;{1}; Pooling=true;" /> <add key="PayDB_Server" value="." /> <add key="PayDB_Acount" value="39B30ED8D3FA3A3E5B3B4CA4F9039D55" /> <add key="Snscenter_ConnectionString" value="Data Source={0};Database=snscenter;{1}; Pooling=true;" /> <add key="Snscenter_Server" value="." /> <add key="Snscenter_Acount" value="39B30ED8D3FA3A3E5B3B4CA4F9039D55" /> </appSettings> <connectionStrings> <add name="DemoConfig" providerName="" connectionString="Data Source=.;Database=DemoConfig;Uid=sa;Pwd=123; Pooling=true;"/> <add name="DemoData" providerName="" connectionString="Data Source=.;Database=Demo1Data;Uid=sa;Pwd=123; Pooling=true;"/> <add name="DemoLog" providerName="" connectionString="Data Source=.;Database=Demo1Log;Uid=sa;Pwd=123; Pooling=true;"/> </connectionStrings> <!--業務層自定義配置--> <zyGameBaseBll> <login defaultType="ZyGames.Framework.Game.Sns.Login36you,ZyGames.Framework.Game"> <retailList> <add id="0000" type="ZyGames.Framework.Game.Sns.Login36you,ZyGames.Framework.Game" args="Pid,Pwd,DeviceID"/> </retailList> </login> </zyGameBaseBll> <zyGameBase-GM> <command> <!--GM:cache--> </command> </zyGameBase-GM> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/> </startup> </configuration>
2.3 定義協議
打開協議生成器工具,增加一個“Demo”項目方案,接着在增加協議(或從現有項目中Copy相同的接口協議),接着定義客戶端提供的請求參數和服務器下發的參數(支持多行的格式,字段類型:Record與End組合);定義好客戶端與服務器之前通訊的接口后,使用自動生成的服務端Python代碼(客戶端使用Lua腳本代碼)復制到已創建的Python接口文件,如圖:
開源地址
GitHub地址:https://github.com/ScutGame