设为首页收藏本站
查看: 183|回复: 0

DELPHI版传奇引擎学习菜鸟篇(applem2)-01

[复制链接]

Rank: 9Rank: 9Rank: 9

管理员

UID
1
元宝
13
声望
6
贡献
579
帖子
116
主题
107
在线时间
38 小时
注册时间
2023-1-13
最后登录
2023-6-9
发表于 2023-2-27 20:40:49 | 显示全部楼层 |阅读模式
一点废话:因为非工科出身,又对编程有点兴趣,杂乱的学习了好多(C,C++,PYTHON…)等好多语言,最后发现DELPHI上手比较快,对于不知道线代和高数等是什么的我来说也许是较好的选择了,毕竟只是兴趣而已,对于DELPHI的资料不是没有,就是觉得没有自己可以渐进入门的.因为以前玩过一个叫传奇的游戏,所以知道最早的传奇是DELPHI开发的,感觉还好,这就找了不少服务端学习(呵呵,研究说不上,因为咱没到那层次),自己动手架设修改,有时还提供给网友玩公益.然后就找传奇的DELPHI源码,不算很多,毕竟现在大部分还是用C写的,也不会开源给大家看,后来听网友说APPLEM2引擎不知道因为什么开源了,就找到一个比较全的(当然还是少了很多东西,比如三方VLC),看着前辈们写的东西,在佩服的同时也觉得自己对照写一遍也许会得到点什么,于是就开始了这个过程,决心从头开始把代码都敲一遍,尽管时间很长,也有点"盗用"(虽说APPLEM2开源了,但是架构模式也还是有知识产权的)嫌疑,呵呵…,不管怎么说,我发现这样学习东西很快,至少对我来说是这样的,这样的过程让我知道了什么是记录,什么是类,什么是SOCKET,对于初学的我来说,收获还是颇丰的,当然也发现了早期代码有不少的不妥之处,函数和过程的繁杂让我一贯找不着北,在试着将一些繁杂的代码简化后,突然发现有的函数被我重新写过了,也许这也是一种提高的方式吧,希望我能坚持下去.正题开始.
后续所有内容都是我自己学习DELPHI过程中对程序设计的一点浅显的了解,有的也许会引发前辈门笑喷,但是这恰是我学习的成长过程,也是我提高的途径.
1.传奇服务端结构:
大部分名字都叫MirServer,基本结构包含八个文件夹和一个GAMECENTER.EXE文件和一个CONFIG.INI文件,以下按照启动顺序说明.
名称说明描述
GAMECENTER控制中心引导所有服务端程序启动,早期的端我没看到过
DBServer数据库服务器管理人物\怪物\物品\魔法数据
LoginSrv登录服务器控制账号登录
LogServer日志服务器记录玩家操作日志
Mir200游戏主引擎管理游戏庞大的脚本和设置
RunGate游戏网关呵呵,现在我还不知道什么是网关
SelGate角色网关好像进入游戏与角色选择有关吧
LoginGate登录网关好像是登录控制和玩家状态检测的
Mud2数据文件夹物品\魔法\怪物数据,应该是paradox的
applem2的还有个排行榜的,我想大部分端应该集成在M2里边了吧.
能够看到的就这些,既然从头开始,就先把目录硬记下来,虽然后边在"抄写"的过程中会改变一些设置.
2.源代码结构
源代码和上述结构一样,除了MUD2,每个都对应一个工程文件,用了好多插件,准备把不需要的都去掉,把所有的服务端程序集中到一个进程里边,暂时不考虑性能如何,尽量用不带插件的DELPHI完整编译,版本以2007为基准吧.先写完了一个GAMECENTER和DBServer,效果如下:
服务端只有一个Server.exe程序,其他服务都集成到一个父窗口中,然后根据主程序设置决定需要启动那些服务,毕竟传奇架设的时候有些服务可能不在一个服务器上,虽然是菜鸟,但是咱也得考虑远一点,学习前辈们的一些先进理念,也是拓展了自己的学习思路.

3.GAMECENTER
先说说启动中心,不说别的,光是主窗口4000多行的代码就让我眼花缭乱了,这对我来说太难了,有的过程或函数快300行了,阅读比较困难,还是先从自己的角度去理解吧.
GAMECENTER工程架构如下(名字都是从自己理解的角度起的):
//本身包含的单元ugamecenter.pas     // 主窗口单元
GShare.pas          // 全局常量单元
DataBackUp.pas      // 数据备份单元
//引用的单元
DBShare.pas         // 共享数据单元
HUtil32.pas         // 人物操作单元
MD5Unit.pas         // 数据校验单元
Common.pas          // 通用常量单元
3.1 GShare.pas单元
单元之间的引用很复杂,也许是因为早起代码的原因吧,先说说GShare.pas单元,这个单元包含了服务器的配置常量,如文件夹名字\服务状态\配置文件等全局常量和服务的启动\停止函数以及消息处理过程,先记录一点自己能够理解的.
unit GShare;
interface
uses
   Windows, Messages, Classes, SysUtils, INIFiles, DataBackUp, ComCtrls;
const
MAXRUNGATECOUNT = 8;  // 最大游戏网关数量  
{以下0-9是每个服务的消息编号常量}  
tDBServer = 0;  
tLoginSrv = 1;  
tLogServer = 2;  
tM2Server = 3;
tLoginGate = 4;  
tSelGate = 6;  
tRunGate = 8;  
tPlugTop = 9;  
{不言而喻,这里是服务配置INI文件的节名称常量}  
BasicSectionName = \'GameConfig\';  
DBServerSectionName = \'DBServer\';  
LoginSrvSectionName = \'LoginSrv\';  
M2ServerSectionName = \'M2Server\';  
LogServerSectionName = \'LogServer\';
RunGateSectionName = \'RunGate\';  
SelGateSectionName = \'SelGate\';  
LoginGateSectionName = \'LoginGate\';  
PlugTopSectionName=\'PlugTop\';  
{IP设置,APPLEM2自带一机双IP设置}  
sAllIPaddr = \'0.0.0.0\';  
sLocalIPaddr = \'127.0.0.1\';  
sLocalIPaddr2 = \'127.0.0.2\';  
nLimitOnlineUser = 2000;    //服务器最高上线人数(源码自带注释)
{以下是各个服务的配置路径和文件常量}  
SERVERCONFIGDIR = \'Config\\';  
SERVERCONFIGFILE = \'Config.ini\';  
SERVERGAMEDATADIR = \'GameData\\';  
SERVERLOGDIR = \'Log\\';  
DBSERVERSECTIONNAME2 = \'DBServer\';  
DBSERVERDBDIR = \'DB\\';  
DBSERVERALLOWADDR = \'AllowAddr.txt\';  
DBSERVERGATEINFO = \'GateInfo.txt\';  
LOGINSRVSECTIONNAME2 = \'LoginSrv\';  
LOGINSRVCHRLOGNAME = SERVERLOGDIR + \'ChrLog\\';  
LOGINSRVALLOWADDR = \'LoginSrv_AllowAddr.txt\';  
LOGINSRVGETINFO = \'LoginSrv_GateInfo.txt\';  
LOGINSRVUSERLIMIT = \'LoginSrv_UserLimit.txt\';  
M2SERVERCONFIGFILE = \'!Setup.txt\';  
M2SERVERSECTIONNAME1 = \'Server\';  
M2SERVERSECTIONNAME2 = \'Share\';  
M2SERVERSEGuildBase = SERVERGAMEDATADIR + \'GuildBase\\';  
M2SERVERSEGuildDir = M2SERVERSEGuildBase + \'Guilds\\';  
M2SERVERSEGuildFile = M2SERVERSEGuildBase + \'GuildList.txt\';  
M2SERVERSEConLogDir = SERVERLOGDIR + \'M2ConLog\\';  
M2SERVERSECastleDir = SERVERGAMEDATADIR + \'Castle\\';  
M2SERVERSECastleFile = SERVERGAMEDATADIR + \'Castle\List.txt\';  
M2SERVERSELogDir = SERVERLOGDIR + \'M2Log\\';  
M2SERVERSEEMailDir = SERVERLOGDIR + \'M2Log\\';  
M2SERVERSEnvirDir = \'Envir\\';  
M2SERVERSMapDir = \'Map\\';  
M2SERVERSALLOWADDR = \'M2Server_AllowAddr.txt\';  
M2SERVERSEmailDir = SERVERGAMEDATADIR + \'EMail\\';  
LOGSERVERSECTIONNAME2 = \'LogDataServer\';  
LOGSERVERBaseDir = SERVERGAMEDATADIR + \'GameLog\\';  
RunGateSectionName2 = \'RunGate\';  
SelGateSectionName2 = \'SelGate\';  
LoginGateSectionName2 = \'LoginGate\';  
PlugTopDIR=SERVERGAMEDATADIR +\'\mir200\\';
type  
{定义每个服务的应用程序状态结构指针}  
pTProgram = ^TProgram;  
TProgram = packed record   
boGetStart: Boolean; //DBServer启动标志 (源码自带注释)   
boReStart: Boolean; //程序异常停止,是否重新启动 (源码自带注释)   
btStartStatus: Byte;//0,1,2,3 未启动,正在启动,已启动,正在关闭 (源码自带注释)   
sProgramFile: string[50];   
sDirectory: string[100];   
ProcessInfo: TProcessInformation; //服务的进程信息(进程,线程,进程ID,线程ID)   
ProcessHandle: THandle;           //进程句柄   
MainFormHandle: THandle;          //主窗口句柄,后续改为每个服务对应的活动窗口句柄   
nMainFormX: Integer;  //服务端启动后窗口位置   
nMainFormY: Integer;  end;  {应该是加载地图文件的结构指针}  
pTDataListInfo = ^TDataListInfo;  
TDataListInfo = packed record   
sFileName: string[255];   
MapFileHandle: THandle;   
MapFileBuffer: PChar;   
DateTime: TDateTime;   
Data: PChar;   
DataSize: Integer;   
Item: TListItem;  
end;  
{检测服务运行状态}  
TCheckCode = packed record   
dwThread0: LongWord;   
sThread0: string;  
end;  
{下边的一堆CONFIG是对应的每个服务状态的结构}  
TDBServerConfig = packed record   
MainFormX: Integer;   
MainFormY: Integer;   
GatePort: Integer;   
ServerPort: Integer;   
GetStart: Boolean;   
ProgramFile: string[50];
end;  
TLoginSrvConfig = packed record   
MainFormX: Integer;   
MainFormY: Integer;   
GatePort: Integer;   
ServerPort: Integer;   
MonPort: Integer;   
GetStart: Boolean;   
ProgramFile: string[50];  
end;  
TM2ServerConfig = packed record   
MainFormX: Integer;   
MainFormY: Integer;   
GatePort: Integer;   
MsgSrvPort: Integer;   
GetStart: Boolean;   
ProgramFile: string[50];
end;  
TLogServerConfig = packed record   
MainFormX: Integer;   
MainFormY: Integer;   
Port: Integer;   
GetStart: Boolean;   
ProgramFile: string[50];
  end;   
TPlugTopConfig = packed record   
MainFormX: Integer;   
MainFormY: Integer;   
Port: Integer;   
GetStart: Boolean;   
ProgramFile: string[50];
end;
TRunGateConfig = packed record   
MainFormX: Integer;   
MainFormY: Integer;   
GetStart: array[0..MAXRUNGATECOUNT - 1] of Boolean;  
  GatePort: array[0..MAXRUNGATECOUNT - 1] of Integer;   
ProgramFile: string[50];  
end;
TSelGateConfig = packed record   
MainFormX: Integer;  
  MainFormY: Integer;   
GatePort: array[0..1] of Integer;
   GetStart1: Boolean;  
  GetStart2: Boolean;   
ProgramFile: string[50];  
end;  
TLoginGateConfig = packed record   
MainFormX: Integer;   
MainFormY: Integer;   
GatePort: Integer;   
GetStart: Boolean;   
ProgramFile: string[50];  
end;  
{将所有的服务状态声明为一个结构指针}
pTConfig = ^TConfig;  
TConfig = packed record   
DBServer: TDBServerConfig;  
  LoginSrv: TLoginSrvConfig;   
M2Server: TM2ServerConfig;
   LogServer: TLogServerConfig;  
  RunGate: TRunGateConfig;   
SelGate: TSelGateConfig;   
LoginGate: TLoginGateConfig;   
PlugTop: TPlugTopConfig;  
end;  
procedure LoadConfig();  //加载启动设置  
procedure SaveConfig();  //保存启动设置  
{下边2个是启动和停止每个服务的函数}
function RunProgram(var ProgramInfo: TProgram; sHandle: string; dwWaitTime: LongWord): LongWord;  
function StopProgram(var ProgramInfo: TProgram; dwWaitTime: LongWord): Integer;  
{发送每个服务当前状态的消息处理过程}  
procedure SendProgramMsg(DesForm: THandle; wIdent: Word; sSendMsg: string);




您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

精彩图片

    为你推荐

    DELPHI版传奇引擎学习菜鸟篇(applem2)-02
    2023-02-27 / 魔神归来
    接着学习GShare.pas的实现部分,其实这个应该叫做GAMECENTER共享 ...<详情>
    Delphi2007安装包+破解文件
    2023-01-18 / 魔神归来
    **** 本内容被作者隐藏 **** ...<详情>
    联系电话 ( 9:00—18:00 ) 000-123456789

    扫一扫关注我们,了解更多最新动态

    快速回复 返回顶部 返回列表