用Docker一键构建你的魔兽世界游戏客户端
前言
作为魔兽世界的大龄玩家,我的骨子里忘记不了它。艾泽拉斯,深入我的灵魂。
成为一名程序员后,尝试着从技术上继续魔兽世界的热情。
目标
实现对魔兽世界从源码编译成实际可用的docker镜像,并成功局域网部署、运行。
这里源码主要是1.12.1版本的魔兽,最高等级 60级。
源码地址: https://github.com/cmangos/mangos-classic
名词介绍
mangos
开源的游戏服务端框架,魔兽世界是其具体的应用。
cmangos
基于mangos进行了开发,整合了其他一些框架的特性。
由于 mangos尝试编译时,遇到很多问题,因此我选择了cmangos进行编译。
过程
- 创建文件夹
mkdir cmangos
- 拉取源码。
mkdir cmangos
由于墙的原因,直接拉取代码非常缓慢。因此这里选择国内站点拉取代码。
国内地址: https://gitee.com/hi_php/mangos-classic
git clone https://gitee.com/hi_php/mangos-classic
拉取数据库
国内地址: https://gitee.com/hi_php/classic-db
git clone https://gitee.com/hi_php/classic-db
感谢开源中国,解决了速度问题。之前因为速度问题,多次泪崩。
- 客户端
下载客户端,这里提供的是百度网盘
链接:https://pan.baidu.com/s/1dGFYy7B 密码:4tdd
- 魔兽世界docker镜像的dockerfile文件
构建镜像依赖的2个文件:
debian国内源配置 :sources.list
编译魔兽需要资源包:data-map.tar.gz
下载地址:
链接:https://pan.baidu.com/s/14mH3rNs_A4TyTOMhIlv6nQ 密码:nugo
dockerfile文件内容如下
FROM debian:9
# 个人信息
MAINTAINER hijava <hi_php@163.com>
#使用网易源
ADD sources.list /etc/apt/sources.list
#安装依赖的文件
RUN apt-get update && apt-get -y install grep build-essential gcc g++ automake git-core autoconf make patch cmake libmysql++-dev \
mysql-server libtool libssl-dev binutils zlibc libc6 libbz2-dev subversion libboost-all-dev vim
#增加mangos用户
RUN useradd -m -d /home/mangos -c "MaNGOS" -U mangos
WORKDIR /home/mangos
#拉取源码
RUN git clone https://gitee.com/hi_php/mangos-classic
RUN mv /home/mangos/mangos-classic /home/mangos/mangos
#创建编译目录和运行目录
RUN mkdir -p /home/mangos/mangos/build
RUN mkdir -p /home/mangos/mangos/run
#切换工作目录
WORKDIR /home/mangos/mangos/build
# Want compile CMaNGOS & the map extraction tools & playerbots
RUN cmake /home/mangos/mangos -DCMAKE_INSTALL_PREFIX=/home/mangos/mangos/run -DBUILD_EXTRACTORS=ON -DPCH=1 -DDEBUG=0 -DBUILD_PLAYERBOT=ON
RUN make && make install
#修改配置文件
RUN cp /home/mangos/mangos/run/etc/mangosd.conf.dist /home/mangos/mangos/run/etc/mangosd.conf \
&& cp /home/mangos/mangos/run/etc/playerbot.conf.dist /home/mangos/mangos/run/etc/playerbot.conf \
&& cp /home/mangos/mangos/run/etc/realmd.conf.dist /home/mangos/mangos/run/etc/realmd.conf
#替换数据库参数
RUN sed -i "s/127.0.0.1;3306;mangos;mangos;/wow60-database;3306;root;123456;/g" /home/mangos/mangos/run/etc/*.conf
#关闭高清地图
RUN sed -i "s/mmap.enabled = 1/mmap.enabled = 0/g" /home/mangos/mangos/run/etc/mangosd.conf
#拷贝客户端资源包
ADD data-map.tar.gz /home/mangos/mangos/run/
RUN mv /home/mangos/mangos/run/data-map/* /home/mangos/mangos/run/bin/
#修改进入容器的工作空间。
WORKDIR /home/mangos/mangos/run/bin
#运行指令,避免容器退出
CMD ["/bin/bash","-c", "while true; do echo hello world; sleep 1; done"]
将三个文件放同一个目录下, 运行构建命令
docker build --tag=cmangos .
构建完成后,即可使用该镜像了。
魔兽世界数据库
需要3个数据库
classicrealmd
classicmangos
classiccharacters
源码的sql目录下 是 基本数据。
下载的classic-db是填充的数据,填充 classicmangos 例如大量的物品、角色、任务等。
此时的数据库还是英文的,这里提供一份我汉化后的数据库。
链接:https://pan.baidu.com/s/14mH3rNs_A4TyTOMhIlv6nQ 密码:nugo
构建魔兽世界应用
需要创建4个容器,分别是
Mysql容器
phpmyadmin容器
账号认证容器
魔兽世界容器
注意: 下面使用的镜像是我上传阿里云后的镜像。你可以直接使用。如果需要使用刚刚编译的镜像,请执行修改image参数
version: "2"
services:
wow60-database:
image: mysql:5.7
volumes:
- ./db_data:/var/lib/mysql
ports:
- 3306:3306/tcp
environment:
#mysql的root密码
MYSQL_ROOT_PASSWORD: 123456
wow60-realmd:
image: registry.cn-hangzhou.aliyuncs.com/hijava/centos7-mangos:latest
command: bash -c "/home/mangos/mangos/run/bin/realmd -c /home/mangos/mangos/run/etc/realmd.conf"
ports:
- 3724:3724/tcp
depends_on:
- wow60-database
wow60-world:
image: registry.cn-hangzhou.aliyuncs.com/hijava/centos7-mangos:latest
ports:
- 8085:8085/tcp
depends_on:
- wow60-realmd
phpmyadmin:
image: phpmyadmin/phpmyadmin
environment:
- PMA_ARBITRARY=1
restart: always
depends_on:
- wow60-database
ports:
- "3999:80"
构建应用
docker-compose -f docker-compose.yml up -d
访问 127.0.0.1:3999 即可打开phpmyadmin进行数据库管理。
phpmyadmin登录填写的内容依次是
地址 wow60-database
账号root
密码 123456
127.0.0.1是你本地电脑,如果是服务器,则使用服务器ip地址。
依次创建3个数据库,然后导入数据
设置服务端ip地址
这里的ip地址决定你的魔兽世界谁可以玩。
127.0.0.1 表示是本机玩魔兽
如果需要局域网一起玩,需要设置局域网的ip。例如 192.168.1.2
如果需要远方的朋友,则需要使用具有公网ip的电脑。
启动服务端
容器启动时,世界服务器无法自动启动,需要手动启动。
进入魔兽世界的容器
docker exec -it 容器id或者容器名 /bin/bash
启动服务
nohup /home/mangos/mangos/run/bin/mangosd > /home/mangos/mangos/run/bin/mangod.log 2>&1 &
退出容器
exit
设置客户端
realmlist.wtf 文件修改。
用记事本打开,设置内容如下
set realmlist 电脑ip地址
这里的ip和服务器要保持一致。
创建账号
默认提供的账号有4个。
最高权限账号 ADMINISTRATOR
较低权限账号 GAMEMASTER
较低权限账号 MODERATOR
普通玩家账号 PLAYER
上面账号的 密码就是 账号本身。
如果需要注册新账号,可以直接执行下面的sql语句。
INSERT INTO account
(username, sha_pass_hash, email)
VALUES
('wwf',SHA1(CONCAT(UPPER('123456'),':',UPPER('123456'))), 'wwf@163.com')
以上就表示创建账号wwf 密码123456
gm命令
非普通玩家,拥有一些gm命令。这里可以使用最高权限账号进行测试。
直接百度:mangos gm命令
使用方法:复制命令到魔兽世界的聊天框,回车即可。
例如:送到暴风城
.go -9065 434 94 0
最后
致敬我的魔兽岁月
群名称:
魔兽世界基佬群
群 号:227827768
上一篇: GM如何在魔兽世界中重置副本?
推荐阅读
-
用Docker一键构建你的魔兽世界游戏客户端
-
go语言Socket编程-Socket编程 什么是Socket Socket,英文含义是插座、插孔,一般称之为套接字,用于描述IP地址和端口。可以实现不同程序间的数据通信。 Socket起源于Unix,而Unix基本哲学之一就是“一切皆文件”,都可以用“打开open –> 读写write/read –> 关闭close”模式来操作。Socket就是该模式的一个实现,网络的Socket数据传输是一种特殊的I/O,Socket也是一种文件描述符。Socket也具有一个类似于打开文件的函数调用:Socket,该函数返回一个整型的Socket描述符,随后的连接建立、数据传输等操作都是通过该Socket实现的。 套接字的内核实现较为复杂,不宜在学习初期深入学习,了解到如下结构足矣。 套接字通讯原理示意 在TCP/IP协议中,“IP地址+TCP或UDP端口号”唯一标识网络通讯中的一个进程。“IP地址+端口号”就对应一个socket。欲建立连接的两个进程各自有一个socket来标识,那么这两个socket组成的socket pair就唯一标识一个连接。因此可以用Socket来描述网络连接的一对一关系。 常用的Socket类型有两种:流式Socket(SOCK_STREAM)和数据报式Socket(SOCK_DGRAM)。流式是一种面向连接的Socket,针对于面向连接的TCP服务应用;数据报式Socket是一种无连接的Socket,对应于无连接的UDP服务应用。 网络应用程序设计模式 C/S模式 传统的网络应用设计模式,客户机(client)/服务器(server)模式。需要在通讯两端各自部署客户机和服务器来完成数据通信。 B/S模式 浏览器(Browser)/服务器(Server)模式。只需在一端部署服务器,而另外一端使用每台PC都默认配置的浏览器即可完成数据的传输。 优缺点 对于C/S模式来说,其优点明显。客户端位于目标主机上可以保证性能,将数据缓存至客户端本地,从而提高数据传输效率。且,一般来说客户端和服务器程序由一个开发团队创作,所以他们之间所采用的协议相对灵活。可以在标准协议的基础上根据需求裁剪及定制。例如,腾讯所采用的通信协议,即为ftp协议的修改剪裁版。 因此,传统的网络应用程序及较大型的网络应用程序都首选C/S模式进行开发。如,知名的网络游戏魔兽世界。3D画面,数据量庞大,使用C/S模式可以提前在本地进行大量数据的缓存处理,从而提高观感。 C/S模式的缺点也较突出。由于客户端和服务器都需要有一个开发团队来完成开发。工作量将成倍提升,开发周期较长。另外,从用户角度出发,需要将客户端安插至用户主机上,对用户主机的安全性构成威胁。这也是很多用户不愿使用C/S模式应用程序的重要原因。 B/S模式相比C/S模式而言,由于它没有独立的客户端,使用标准浏览器作为客户端,其工作开发量较小。只需开发服务器端即可。另外由于其采用浏览器显示数据,因此移植性非常好,不受平台限制。如早期的偷菜游戏,在各个平台上都可以完美运行。 B/S模式的缺点也较明显。由于使用第三方浏览器,因此网络应用支持受限。另外,没有客户端放到对方主机上,缓存数据不尽如人意,从而传输数据量受到限制。应用的观感大打折扣。第三,必须与浏览器一样,采用标准http协议进行通信,协议选择不灵活。 因此在开发过程中,模式的选择由上述各自的特点决定。根据实际需求选择应用程序设计模式。 简单的C/S模型通信 Server端:Listen函数 func Listen(network, address string) (Listener, error) network:选用的协议:TCP、UDP, 如:“tcp”或 “udp” address:IP地址+端口号, 如:“127.0.0.1:8000”或 “:8000” Listener 接口: type Listener interface { Accept (Conn, error) Close error Addr Addr } Conn 接口: type Conn interface { Read(b byte) (n int, err error) Write(b byte) (n int, err error) Close error LocalAddr Addr RemoteAddr Addr SetDeadline(t time.Time) error SetReadDeadline(t time.Time) error SetWriteDeadline(t time.Time) error } 参看 [<u>https://studygolang.com/pkgdoc</u>](https://studygolang.com/pkgdoc) 中文帮助文档中的demo: 示例代码:TCP服务器.go package main import ( "net" "fmt" ) func main { // 创建监听 listener, err:= net.Listen("tcp", ":8000") if err != nil { fmt.Println("listen err:", err) return } defer listener.Close // 主协程结束时,关闭listener fmt.Println("服务器等待客户端建立连接...") // 等待客户端连接请求 conn, err := listener.Accept if err != nil { fmt.Println("accept err:", err) return } defer conn.Close // 使用结束,断开与客户端链接 fmt.Println("客户端与服务器连接建立成功...") // 接收客户端数据 buf := make(byte, 1024) // 创建1024大小的缓冲区,用于read n, err := conn.Read(buf) if err != nil { fmt.Println("read err:", err) return } fmt.Println("服务器读到:", string(buf[:n])) // 读多少,打印多少。 }