项目地址:https://github.com/Grasscutters/Grasscutter
官方 Wiki 文档:https://github.com/Grasscutters/Grasscutter/wiki

Grasscutter-资源统计(一个很有用的资源整合项目):https://github.com/Yuer-QAQ/Awesome-Grasscutter


「一」用Docker容器搭建服务端

本文介绍通过 Docker 容器技术较为简单地搭建原神私服。

Docker 是一种如字面意思的 “容器” 技术,可以理解为更加小型的虚拟机(当然本质并不是)。

本流程适用基于 Linux 系统的服务器搭建,当然,如果想在本地搭建,可以选择直接安装环境所需软件。

1.1 所需环境
官方文档如官方文档所示,需要 MongoDB 和 JDK 17 两个环境,我们使用两个 Docker 容器分别实现。

1.2 安装环境

・1.2.1・首先,安装 Docker(社区版)

yum install -y docker-ce  # 安装docker
systemctl start docker    # 启动docker服务

CentOS、Debian 和 Ubuntu 的安装命令有些许差异,可自行搜索。

另外现新版本宝塔面板侧边栏自带docker,使用宝塔面板的用户可跳过此步。

・1.2.2・创建 Docker network(可选)

使用 docker network 对 Docker 容器进行统一管理,MongoDB 数据库不对外提供端口,各容器之间通过 hostname 进行内部通信,保护系统安全。

docker network create genshin  # 创建Docker network
docker network ls              # 查看已创建的网络

使用docker network rm 网络名 可删除网络

・1.2.3・【第一个 Docker 容器 “mongodb”】:MongoDB

搭建 Docker-MongoDB 环境,在同一个 docker network 里,在内部通过 hostname 进行通信。
退出容器内部的命令是 exit

docker pull mongo:latest                # 拉取MongoDB基础镜像
mkdir -p /mydocker/mongodb/data         # 在物理机创建目录
# 创建容器,容器名mongodb;网络为创建的genshin;
# -v表示宿主机路径:容器路径;-h表示hostname;
# 最后指定镜像mongo
docker run -itd --name mongodb --network genshin -v /mydocker/mongodb/data:/data/db -h genshin_mongo mongo
docker update mongodb --restart=always  # 重启Docker时,自动启动容器

若没有创建 Docker network,可以将第三句命令改为:

docker run -itd --name mongodb -v /mydocker/mongodb/data:/data/db mongo

・1.2.4・【第二个 Docker 容器 “grasscutter”】:JDK 17

搭建 Docker-JDK17 环境,同时这也是割草机服务端的运行容器:
①「创建容器」

docker pull python                                # 拉取Python基础镜像
# 创建容器,容器名grasscutter;网络为创建的genshin;
# -p表示端口映射,这里将默认的443端口改为444或其他,避免占用;
# -h表示hostname;最后指定镜像python
docker run -itd --name grasscutter --network genshin -p 22102:22102/udp -p 444:444/tcp -h genshin_grasscutter python
iptables -I INPUT -p udp --dport 22102 -j ACCEPT  # 放行22102端口的udp协议
iptables -I INPUT -p tcp --dport 444 -j ACCEPT    # 放行444端口的tcp协议
docker update grasscutter --restart=always        # 设置开机自启docker exec -it grasscutter /bin/bash                             # 进入容器内部
cat /etc/issue                                    # 查看系统版本(Debian GNU/Linux11)

若没有创建 Docker network,可以将第二句命令改为:

docker run -itd --name grasscutter -p 22102:22102/udp -p 444:444/tcp python


②「在容器内安装常用软件包」

apt-get update# 更新apt-get
apt-getinstall sudo -y             # 安装sudo
apt-getinstall wget -y             # 安装wget
apt-getinstall curl -y             # 安装curl
apt-getinstall vim -y              # 安装vim

③「在容器内安装 jdk-17」

sudo apt install openjdk-17-jdk -y  # 安装jdk17
sudo apt install openjdk-17-jre -y  # 安装jre17
java -version# 查看版本
javac -version

此处创建容器时映射的 22102 和 444 端口,是为了后续搭建 Grasscutter 私服保留的。
22102(UDP)是游戏服务器(GameServer)端口,用来处理一些传送、伤害数值计算等信息,如果是在服务器部署的话记得在安全组放开这个端口的 UDP 协议,防止出现 4206 错误无法进入游戏。
444 (TCP) 是用来处理登录、游戏更新的端口 (DispatchServer),默认的 443 大概率被占用,可以更换成自己喜欢的,本文使用 444。


「二」拷贝服务端资源到docker

2.1 下载仓库文件

下载割草机 Grasscutter 仓库文件(Code -> Download ZIP):https://github.com/Grasscutters/Grasscutter
这里建议将左上角 stable 分支改为 development 分支再下载,此分支更新频率高,包含更多大世界新特性

将文件放至服务器任意目录(如根目录 / Grasscutter)解压,进行下一步处理

2.2 下载 resources 资源文件

从另一个仓库下载资源:https://github.com/Koko-boya/Grasscutter_Resources
将文件夹改名为 resources,放入上个步骤的目录 / Grasscutter / 中。注意,原版割草机仓库中并不包含 resources 文件夹。

2.3 下载 jar 启动文件

①从自动构建下载 development 版本:
https://nightly.link/Grasscutters/Grasscutter/workflows/build/development/Grasscutter.zip

②从 releases 下载:https://github.com/Melledy/Grasscutter/releases

③stable 版本自动构建下载:
https://nightly.link/Grasscutters/Grasscutter/workflows/build/stable/Grasscutter.zip

④也可以自己尝试构建:https://github.com/Grasscutters/Grasscutter#Building

下载完成后放入根目录,可以删掉其他多余的文件。此时,必需的目录结构应为:

Grasscutter
 ├── keystore.p12
 ├── grasscutter.jar
 └── resources
     ├── BinOutput
     ├── ExcelBinOutput
     ├── Readable
     ├── Subtitle
     └── TextMap

都懒得弄可下载别人处理好的整合包

整合包1(2.8.5含客户端):https://a.angelbeats.xyz/s/X3hE——提示:密码就在该链接地址中
整合包2(3.1.5仅服务端):https://github.com/snoobi-seggs/nahida_seggs

2.4 复制到 Docker 容器

之后会经常使用到的两个命令:
①在容器与宿主机之间相互复制文件:
docker cp [路径] [容器名]:[路径]
(注:表示从前者复制到后者,可以互换顺序)

②进入指定容器:
docker exec -it [容器名] /bin/bash


2.5 第一次启动

docker cp /Grasscutter grasscutter:/Grasscutter  # 将文件夹复制到容器里
docker exec -it grasscutter /bin/bash            # 进入grasscutter容器
cd /Grasscutter                                  # 进入刚刚复制进去的文件夹java -jar grasscutter-1.1.2-dev.jar              # 启动

第一次启动会失败,初次启动的目的是让 jar 包执行时自动生成logs、plugins、data、config.json(如果有的就不会重新生成),下面我们需要修改里面的配置:

vim config.json

配置含义说明:

・如果是本地运行的话里面的两个 PublicIp 不用动,如果是放在服务器上的话需要把两个 PublicIp 改为服务器的公网 IP。

・上面的 “bindPort”: 444 是用来处理登录、游戏更新的端口 (DispatchServer),默认的 443 端口服务器可能不太好搞,可能被 Nginx 等服务占用了。而 Windows 也可能会被 VMWare 的 Share 共享服务或者 Steam 占用,所以可以改为别的端口。改好之后如果是服务器的话记得在安全组放行该端口的 TCP 协议。除了安全组外,还要检查一下防火墙有没有开放。

・下面的 “bindPort”: 22102 是游戏服务器(GameServer)的端口,用来处理一些传送、伤害数值计算等信息,如果是在服务器部署的话记得在安全组放开这个端口的 UDP 协议,防止出现 4206 错误无法进入游戏。除了安全组外,还要检查一下防火墙有没有开放。

・“welcomeMessage”: “Welcome to Grasscutter”, 这个是进服务器之后 Server 发给你的欢迎语句,可以改成 “欢迎来到 XXX 私服 “之类的。

・“KeystorePassword”: “123456”,证书文件的密码,不需要修改。

・“autoCreate”: true, 这个是控制自动创建账号的,改为 true 之后,如果登录私服的时候没有那个账号的话会自动创建一个并登录进去,然后分配默认的 uid,从 10001 开始往后顺延。

・“singlePlayerTeam”: 5 “multiplayerTeam”: 10, 联机队伍中最多角色数,更改之后可以切换联机数量。

可能用到的命令:
①查看容器的内部 IP:docker inspect 容器名 | grep IPAddress
②查询运行的 Java 程序:ps -ef|grep java
③停止运行的 Java 程序:kill [进程 ID]

我的配置文件供参考

{
  "folderStructure": {
    "resources": "./resources/",
    "data": "./data/",
    "packets": "./packets/",
    "scripts": "./resources/Scripts/",
    "plugins": "./plugins/"
  },
  "databaseInfo": {
    "server": {
      "connectionUri": "mongodb://localhost:27017",   //【localhost替换为mongodb容器内部IP】
      "collection": "grasscutter"
    },
    "game": {
      "connectionUri": "mongodb://localhost:27017",    //【localhost替换为mongodb容器内部IP】
      "collection": "grasscutter"
    }
  },
  "language": {
    "language": "zh_CN",
    "fallback": "en_US",
    "document": "EN"
  },
  "account": {
    "autoCreate": true,
    "defaultPermissions": [],
    "maxPlayer": -1
  },
  "server": {
    "debugLevel": "NONE",
    "runMode": "HYBRID",
    "http": {
      "bindAddress": "0.0.0.0",
      "accessAddress": "服务器公网IP",
      "bindPort": 444,
      "accessPort": 0,
      "encryption": {
        "useEncryption": true,
        "useInRouting": true,
        "keystore": "./keystore.p12",
        "keystorePassword": "123456"
      },
      "policies": {
        "cors": {
          "enabled": false,
          "allowedOrigins": [
            "*"
          ]
        }
      },
      "files": {
        "indexFile": "./index.html",
        "errorFile": "./404.html"
      }
    },
    "game": {
      "bindAddress": "0.0.0.0",
      "accessAddress": "服务器公网IP",
      "bindPort": 22102,
      "accessPort": 0,
      "loadEntitiesForPlayerRange": 100,
      "enableScriptInBigWorld": false,
      "enableConsole": true,
      "gameOptions": {
        "inventoryLimits": {
          "weapons": 2000,
          "relics": 2000,
          "materials": 2000,
          "furniture": 2000,
          "all": 30000
        },
        "avatarLimits": {
          "singlePlayerTeam": 5,
          "multiplayerTeam": 6
        },
        "sceneEntityLimit": 1000,
        "watchGachaConfig": false,
        "enableShopItems": true,
        "staminaUsage": true,
        "energyUsage": false,
        "resinOptions": {
          "resinUsage": false,
          "cap": 160,
          "rechargeTime": 480
        },
        "rates": {
          "adventureExp": 1.0,
          "mora": 1.0,
          "leyLines": 1.0
        }
      },
      "joinOptions": {
        "welcomeEmotes": [
          2007,
          1002,
          4010
        ],
        "welcomeMessage": "Welcome to \u003ccolor\u003dred\u003eGenshin!",
        "welcomeMail": {
          "title": "Welcome to Genshin",
          "content": "Hi there!\r\nFirst of all, welcome to Ghenshin!",
          "sender": "aila",
          "items": [
            {
              "itemId": 13509,
              "itemCount": 1,
              "itemLevel": 1
            },
            {
              "itemId": 201,
              "itemCount": 99999,
              "itemLevel": 1
            }
          ]
        }
      },
      "serverAccount": {
        "avatarId": 10000029,
        "nameCardId": 210001,
        "adventureRank": 60,
        "worldLevel": 8,
        "nickName": "Server-aila",
        "signature": "Welcome to Genshin"
      }
    },
    "dispatch": {
      "regions": [],
      "defaultName": "Genshin"
    }
  },
  "version": 3
}

出现类似下方的提示,既为启动成功:
启动成功启动成功-中文

此时如果想创建自定义 UID 账号,可输入 account create [用户名] [想要的 UID]

启动成功后直接关闭就行。


「三」客户端配置,安装代理转发软件

至此,服务端的搭建已经完成!

3.1替换补丁文件(2.8版本以前不用替换)

2.8.5x补丁链接(含2.8.5x客户端):https://a.angelbeats.xyz/s/X3hE

全版本客户端的下载链接:https://github.com/kyou-nase/GI-Download-Library

3.2使用 Fiddler 转发流量

Fiddler 官网下载:https://www.telerik.com/fiddler/fiddler-classic

配置说明:

第一步:选择左上角 Tools-Options,在 HTTPS 里面选择 Decrypt HTTPS traffic,三个勾可以都打上。
第一步勾上

第二步:选择 Connections,然后选择一个端口,输入54321,点击 OK。

第三步:在 Fiddler 右侧找到 FiddlerScript,把原来的代码全部删掉,然后把下面的这一段代码放进去(把 oS.host 改成自己的即可),然后点击左上角的 Save Script 保存脚本使其生效。
第三步

/* Original script by NicknameGG, modified for Grasscutter by contributors. */
import System;
import System.Windows.Forms;
import Fiddler;
import System.Text.RegularExpressions;
 
class Handlers
{
    static function OnBeforeRequest(oS: Session) {
        if(oS.host.EndsWith(".yuanshen.com") || oS.host.EndsWith(".hoyoverse.com") || oS.host.EndsWith(".mihoyo.com")) {
            oS.host = "IP:444"; // This can also be replaced with another IP address.(输入域名也可)
        }
        if(oS.uriContains("http://uspider.yuanshen.com:8888/log")){
            oS.oRequest.FailSession(200, "Blocked", "haha");
        }
    }
};

恭喜!至此,理论的搭建已经全部完成。
当登陆界面的 logo 变成 hoyoverse,意味着代理已经成功运行了,输入事先创建的用户名,密码随便写。

如使用我给出的配置文件,可直接输入一个名称会自动创建,但输入指令时可能会没有权限,在服务端给予权限即可。

permission add @10001 * #给予10001用户全部权限(服务器管理员使用)

permission add @10001 player.* #给予10001用户普通权限(一般玩家使用)


「四」游戏内指令的使用

传统方式的命令执行,是在进入游戏后进入会话列表,添加会话用户找到 Server 用户并添加,就可以发送 “/ 命令” 的方式来执行指令。

当然,这种方法效率有些低,我们可以使用 @jie65535 制作的命令生成器
https://github.com/jie65535/GrasscutterCommandGenerator
可以方便地生成命令供粘贴使用。

进一步,这个工具还可以通过插件的方式远程执行指令,更加快捷:
服务端插件:https://github.com/jie65535/gc-opencommand-plugin

「五」常见问题

更新服务端:

以后更新的时候,除data中的Banners.json和主目录下的config.json、keystore.p12备份外其余文件全部删除(因为账号数据是保存在mongo数据库里的),然后替换为更新包中的 grasscutter.jarresources

服务端插件使用方法:


・在 Release 下载 jar
・放入服务器目录中的 / Grasscutter/plugins 文件夹
・重启割草机服务端:
①查询运行的 Java 程序:ps -ef|grep java
②停止运行的 Java 程序:kill [进程 ID]
③java -jar grasscutter-1.1.0.jar

・先进入游戏,再打开命令生成器,在 “远程” 页面中查询、发送验证码到你的 UID,再将游戏中左下角消息中的验证码填入即可使用一键执行命令。

环境备份方法:

一、Docker 镜像备份法
生成本地镜像:

docker save -o [导出的镜像名.tar] [本地镜像名]:[镜像标签]
如:docker save -o /home/grasscutter-image.tar grasscutter:latest

使用本地镜像:

dockerload-i[本地tar包文件]

二、手动备份法
复制 Docker 内指定目录到宿主机:

docker cp grasscutter:/Grasscutter /Grasscutter

输出 MongoDB 数据库备份:

mongodump -o /home/mongodb/

恢复所有数据到数据库:

mongorestore /home/mongodb/

如防火墙关闭,则需要重启docker服务

service docker restart

查看Docker中mongodb的内容

单击终端,输入mongo连接数据库,另外配置文件中的mongo容器IP也是填如图所示的IP

> show dbs                 -- 列出数据库
admin        0.000GB
config       0.000GB
grasscutter  0.001GB
local        0.000GB
> use grasscutter          -- 使用grasscutter
switched to db grasscutter
> show tables              -- 列出集合(表)
accounts
activities
avatars
battlepass
counters
friendships
gachas
homes
items
mail
players
quests
> db.accounts.find().pretty()-- 查询集合 accounts 的所有内容 
{
        "_id" : "10001",
        "username" : "aila",
        …………………………………………………………………………
}

使用3Dmigo更改角色模型

项目地址:https://github.com/SilentNightSound/GI-Model-Importer

模型下载:https://gamebanana.com/games/8552