mirror of
https://github.com/Grasscutters/Grasscutter.git
synced 2025-08-03 20:21:50 +00:00
Compare commits
4 Commits
developmen
...
72f0c15108
Author | SHA1 | Date | |
---|---|---|---|
72f0c15108 | |||
d5b5e93522 | |||
60e713f4ff | |||
e1e0bb6928 |
51
.github/workflows/build_container.yml
vendored
51
.github/workflows/build_container.yml
vendored
@ -1,51 +0,0 @@
|
||||
name: Build Docker Container
|
||||
on:
|
||||
push:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch: ~
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- name: Checkout Project
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Generate Docker Meta
|
||||
uses: docker/metadata-action@v5
|
||||
id: meta
|
||||
with:
|
||||
images: ghcr.io/${{ github.repository }}
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
type=sha
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Setup Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3.1.0
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v3.0.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build and Push Docker image
|
||||
uses: docker/build-push-action@v5.2.0
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
platforms: linux/amd64
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -64,7 +64,6 @@ tmp/
|
||||
|
||||
/*.jar
|
||||
/*.sh
|
||||
!entrypoint.sh
|
||||
|
||||
GM Handbook*.txt
|
||||
handbook.html
|
||||
|
14
Dockerfile
14
Dockerfile
@ -1,14 +1,11 @@
|
||||
# Builder
|
||||
FROM gradle:jdk17-alpine as builder
|
||||
|
||||
RUN apk add --update nodejs npm
|
||||
FROM gradle:8.5.0-jdk17-alpine as builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY ./ /app/
|
||||
|
||||
RUN gradle jar --no-daemon
|
||||
|
||||
# Fetch Data
|
||||
FROM bitnami/git:2.43.0-debian-11-r1 as data
|
||||
|
||||
ARG DATA_REPOSITORY=https://gitlab.com/YuukiPS/GC-Resources.git
|
||||
@ -18,13 +15,14 @@ WORKDIR /app
|
||||
|
||||
RUN git clone --branch ${DATA_BRANCH} --depth 1 ${DATA_REPOSITORY}
|
||||
|
||||
# Result Container
|
||||
FROM amazoncorretto:17-alpine
|
||||
FROM bitnami/java:21.0.1-12
|
||||
|
||||
RUN apt-get update && apt-get install unzip
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy built assets
|
||||
COPY --from=builder /app/grasscutter-*.jar /app/grasscutter.jar
|
||||
COPY --from=builder /app/grasscutter-1.7.4.jar /app/grasscutter.jar
|
||||
COPY --from=builder /app/keystore.p12 /app/keystore.p12
|
||||
|
||||
# Copy the resources
|
||||
|
15
README.md
15
README.md
@ -18,24 +18,15 @@
|
||||
* Spawning monsters via console
|
||||
* Inventory features (receiving items/characters, upgrading items/characters, etc)
|
||||
|
||||
## Foreward
|
||||
|
||||
### **Grasscutter beyond the latest release will have no handholding in terms of instructions.**
|
||||
|
||||
Grasscutter has not been actively maintained and currently (as of January 12th, 2025) only works up to version REL4.0.1 (introduction to Fontaine). If you have a beta version/unofficial version of Grasscutter, this guide should theoretically still work, however, we will not provide official support these versions. You can still try your luck in the Discord if you are stuck, but please don't act entitled.
|
||||
|
||||
## Quick setup guide
|
||||
|
||||
**Note**: For support please join our [Discord](https://discord.gg/T5vZU6UyeG).
|
||||
|
||||
### Quick Start (automatic)
|
||||
|
||||
- Get [Java 17](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html)
|
||||
- Get Java 17: https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html
|
||||
- Get [MongoDB Community Server](https://www.mongodb.com/try/download/community)
|
||||
- Get game version REL4.0.x (If you don't have a 4.0.x client, you can find it here and open any of the links to download it):
|
||||
[4.0.x Client-github](https://github.com/JRSKelvin/GenshinRepository/blob/main/Version%204.0.0.md)
|
||||
[4.0.x Client-cloud drive](https://www.123pan.com/s/HoqUVv-U7SBA.html)
|
||||
- ***UPDATE JAN 12, 2025: YOU CANNOT MIX AND MATCH GAME VERSIONS AND SERVER VERSIONS, PLEASE DOWNLOAD THE CORRECT VERSION OF GRASSCUTTER FOR YOUR VERSION OF THE GAME.***
|
||||
- Get game version REL4.0.x (4.0.x client can be found here if you don't have it): https://github.com/MAnggiarMustofa/GI-Download-Library/blob/main/GenshinImpact/Client/4.0.0.md
|
||||
|
||||
- Download the [latest Cultivation version](https://github.com/Grasscutters/Cultivation/releases/latest). Use the `.msi` installer.
|
||||
- After opening Cultivation (as admin), press the download button in the upper right corner.
|
||||
@ -47,7 +38,7 @@ Grasscutter has not been actively maintained and currently (as of January 12th,
|
||||
|
||||
- Click the small button next to launch.
|
||||
- Click the launch button.
|
||||
- Log in with whatever username you want. Password can be anything.
|
||||
- Log in with whatever username you want. Password doesn't matter.
|
||||
|
||||
### Building
|
||||
|
||||
|
30
docker-compose.yml
Normal file
30
docker-compose.yml
Normal file
@ -0,0 +1,30 @@
|
||||
version: "3.8"
|
||||
services:
|
||||
grasscutter:
|
||||
image: grasscutter:latest
|
||||
build: .
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
- "8080:8080"
|
||||
- "8888:8888"
|
||||
- "22102:22102"
|
||||
environment:
|
||||
DATABASE_INFO_SERVER_CONNECTION_URI: "mongodb://lawnmower:grasscutter@database:27017"
|
||||
DATABASE_INFO_SERVER_COLLECTION: grasscutter
|
||||
DATABASE_INFO_GAME_CONNECTION_URI: "mongodb://lawnmower:grasscutter@database:27017"
|
||||
DATABASE_INFO_GAME_COLLECTION: grasscutter
|
||||
|
||||
stdin_open: true
|
||||
|
||||
database:
|
||||
image: mongo:7.0.4
|
||||
environment:
|
||||
MONGO_INITDB_ROOT_USERNAME: lawnmower
|
||||
MONGO_INITDB_ROOT_PASSWORD: grasscutter
|
||||
MONGO_INITDB_DATABASE: grasscutter
|
||||
volumes:
|
||||
- mongodata:/data/db
|
||||
|
||||
volumes:
|
||||
mongodata:
|
@ -5,7 +5,7 @@
|
||||
|
||||
[EN](../README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) | [IT](README_it-IT.md) | [VI](README_vi-VN.md) | [हिंदी](README_hn-IN.md)
|
||||
|
||||
**Aantekening:** We verwelkomen altijd bijdragers aan het project. Lees onze [Gedragscode](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md) zorgvuldig door voordat u uw bijdrage toevoegt.
|
||||
**Aantekening:** We verwelkomen altijd bijdragers aan het project. Lees onze [Gedragscode](https://github.com/Grasscutters/Grasscutter/blob/development/README_NL.md#bijdragen-aan-het-project) zorgvuldig door voordat u uw bijdrage toevoegt.
|
||||
|
||||
## Huidige functies
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
<div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div>
|
||||
|
||||
[EN](../README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) | [IT](README_it-IT.md) | [VI](README_vi-VN.md) | [हिंदी](README_hn-IN.md)
|
||||
[EN](README.md) | [简中](docs/README_zh-CN.md) | [繁中](docs/README_zh-TW.md) | [FR](docs/README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) | [IT](README_it-IT.md) | [VI](README_vi-VN.md) | [हिंदी](README_hn-IN.md)
|
||||
|
||||
**ध्यान:** हम हमेशा परियोजना में योगदानकर्ताओं का स्वागत करते हैं।. अपना योगदान जोड़ने से पहले कृपया हमारा ध्यानपूर्वक पढ़ें [आचार संहिता](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md).
|
||||
|
||||
@ -75,4 +75,4 @@ chmod +x gradlew
|
||||
|
||||
### समस्या निवारण
|
||||
|
||||
सामान्य मुद्दों और समाधानों की सूची और सहायता मांगने के लिए कृपया शामिल हों [our Discord server](https://discord.gg/T5vZU6UyeG) और सपोर्ट चैनल पर जाएं.
|
||||
सामान्य मुद्दों और समाधानों की सूची और सहायता मांगने के लिए कृपया शामिल हों [our Discord server](https://discord.gg/T5vZU6UyeG) और सपोर्ट चैनल पर जाएं.
|
@ -3,7 +3,7 @@
|
||||
|
||||
<div align="center"><a href="https://discord.gg/T5vZU6UyeG"><img alt="Discord - Grasscutter" src="https://img.shields.io/discord/965284035985305680?label=Discord&logo=discord&style=for-the-badge"></a></div>
|
||||
|
||||
[EN](../README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [FR](README_fr-FR.md) | [ES](README_es-ES.md) | [HE](README_HE.md) | [RU](README_ru-RU.md) | [PL](README_pl-PL.md) | [ID](README_id-ID.md) | [KR](README_ko-KR.md) | [FIL/PH](README_fil-PH.md) | [NL](README_NL.md) | [JP](README_ja-JP.md) | [IT](README_it-IT.md) | [VI](README_vi-VN.md) | [HI](README_hn-IN.md)
|
||||
[EN](README.md) | [简中](docs/README_zh-CN.md) | [繁中](docs/README_zh-TW.md) | [FR](docs/README_fr-FR.md) | [ES](docs/README_es-ES.md) | [HE](docs/README_HE.md) | [RU](docs/README_ru-RU.md) | [PL](docs/README_pl-PL.md) | [ID](docs/README_id-ID.md) | [KR](docs/README_ko-KR.md) | [FIL/PH](docs/README_fil-PH.md) | [NL](docs/README_NL.md) | [JP](docs/README_ja-JP.md) | [IT](docs/README_it-IT.md) | [VI](docs/README_vi-VN.md)
|
||||
|
||||
|
||||
**Attention:** 私たちはプロジェクトへのコントリビュータをいつでも歓迎します。コントリビュートする前に、私たちの [行動規範](https://github.com/Grasscutters/Grasscutter/blob/stable/CONTRIBUTING.md)をよくお読みください。
|
||||
@ -27,7 +27,7 @@
|
||||
|
||||
- [Java (バージョン17以降)](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html) を用意する
|
||||
- [MongoDB Community Server](https://www.mongodb.com/try/download/community) を用意する
|
||||
- ゲームバージョンがREL4.0.Xのクライアントを用意する (4.0.Xのクライアントを持っていない場合は右のリンクからダウンロード): [Github](https://github.com/JRSKelvin/GenshinRepository/blob/main/Version%204.0.0.md), [クラウド(123云盘)](https://www.123pan.com/s/HoqUVv-U7SBA.html)
|
||||
- ゲームバージョンがREL4.0.Xのものを用意する (4.0.Xのクライアントを持っていない場合は右のリンクからダウンロード): https://github.com/MAnggiarMustofa/GI-Download-Library/blob/main/GenshinImpact/Client/4.0.0.md
|
||||
- [最新の Cultivation](https://github.com/Grasscutters/Cultivation/releases/latest)をダウンロードする。`.msi`インストーラを使ってください。
|
||||
- 管理者権限を付与して Cultivation を実行した後、右上端にあるダウンロードアイコンのボタンを押す。
|
||||
- `Download All-in-One` をクリックする
|
||||
@ -35,9 +35,10 @@
|
||||
- `Game Install Path` にゲームファイルのパスを指定する。
|
||||
- `Custom Java Path` に、自分が用意したJavaのパスを指定する。 (例: `C:\Program Files\Java\jdk-17\bin\java.exe`)
|
||||
- その他の設定には手を付けず次の段階に進む。
|
||||
|
||||
- Launch の隣にある小さいボタンを押す。
|
||||
- Launchボタンを押す
|
||||
- 好きなユーザ名でログインする。ログインに関する設定がデフォルトの場合、パスワードは何を入れてもいい。
|
||||
- 好きなユーザ名でログインする。パスワードは特段気にすることはない。
|
||||
|
||||
|
||||
### ビルド
|
||||
@ -78,22 +79,7 @@ chmod +x gradlew
|
||||
./gradlew jar # コンパイル
|
||||
```
|
||||
|
||||
##### 手動によるハンドブックの生成
|
||||
|
||||
Gradleを使用する場合:
|
||||
```shell
|
||||
./gradlew generateHandbook
|
||||
```
|
||||
|
||||
NPMを使用する場合:
|
||||
```shell
|
||||
cd src/handbook
|
||||
npm install
|
||||
npm run build
|
||||
```
|
||||
|
||||
|
||||
生成されたjarファイルはプロジェクトのルートフォルダにあります。
|
||||
生成されたjarファイルはプロジェクトフォルダのルートにあります。
|
||||
|
||||
### トラブルシューティング
|
||||
|
||||
|
@ -22,25 +22,52 @@
|
||||
|
||||
**각주 :** 도움이 필요할 경우 [Discord](https://discord.gg/T5vZU6UyeG)에 가입하세요.
|
||||
|
||||
### 빠른 설치 (자동)
|
||||
### 설치에 필요한 것들
|
||||
|
||||
- [Java 17](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html) 설치
|
||||
- [MongoDB Community Server](https://www.mongodb.com/try/download/community) 설치
|
||||
- 게임 버전 REL4.0.x 다운로드 (만약 4.0.x 클라이언트를 가지고 있지 않다면, 여기서 찾을 수 있습니다.):
|
||||
[4.0.x 클라이언트 - GitHub](https://github.com/JRSKelvin/GenshinRepository/blob/main/Version%204.0.0.md)
|
||||
[4.0.x 클라이언트 - 구글 드라이브브](https://www.123pan.com/s/HoqUVv-U7SBA.html)
|
||||
* Java SE - 17 ([링크](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html))
|
||||
|
||||
- [최신 Cultivation](https://github.com/Grasscutters/Cultivation/releases/latest) 다운로드하세요. `.msi` 설치파일을 사용하면 됩니다.
|
||||
- (관리자 권한으로) Cultivation을 실행한 후, 우측 상단에 위치한 다운로드 버튼을 클릭하세요.
|
||||
- `올인원 다운로드`를 클릭하세요.
|
||||
- 우측 상단에 위치한 톱니바퀴 버튼을 누르세요.
|
||||
- 게임 설치 경로를 게임이 위치한 경로로 설정하세요.
|
||||
- 사용자 지정 Java 경로 설정을 `C:\Program Files\Java\jdk-17\bin\java.exe`로 설정하세요.
|
||||
- 다른 모든 설정은 기본값으로 두세요.
|
||||
**각주 :** **실행**만을 원한다면, **jre**만 있어도 괜찮습니다.
|
||||
|
||||
- 게임 시작 버튼 옆에 위치한 작은 버튼을 누르세요.
|
||||
- 게임 시작 버튼을 누르세요.
|
||||
- 원하는 사용자 이름으로 로그인하세요. 비밀번호는 무엇이든 가능합니다.
|
||||
* [MongoDB](https://www.mongodb.com/try/download/community) (4.0 이상의 버전 추천)
|
||||
|
||||
* 프록시 데몬 : mitmproxy (mitmdump 추천), Fiddler Classic 등.
|
||||
|
||||
### 실행
|
||||
|
||||
**각주 :** 구버전에서 업데이트 했을 경우, `config.json` 파일을 재생성하기 위해 파일을 삭제하세요.
|
||||
|
||||
1. `grasscutter.jar` 얻기
|
||||
- [Actions](https://github.com/Grasscutters/Grasscutter/suites/6895963598/artifacts/267483297) 탭에서 다운로드
|
||||
- [직접 빌드하기](#빌드하기)
|
||||
2. grasscutter.jar 파일이 위치한 폴더에 `resources` 폴더를 생성하고, `BinOutput` 과 `ExcelBinOutput` 폴더를 생성한 폴더 내로 옮기세요. *(이 파일들을 얻는 더 자세한 방법에 대해서는 [위키](https://github.com/Grasscutters/Grasscutter/wiki)를 참조하세요.)*
|
||||
3. Grasscutter를 `java -jar grasscutter.jar` 명령어로 실행합니다. **MongoDB 서비스가 정상적으로 실행되고 있는지 확인하세요.**
|
||||
|
||||
### 클라이언트와의 연결
|
||||
|
||||
½. [서버 콘솔 명령어](https://github.com/Grasscutters/Grasscutter/wiki/Commands#targeting)를 이용해서 계정을 생성합니다.
|
||||
|
||||
1. 리다이렉트 트래픽 : (1가지 선택)
|
||||
- mitmdump: `mitmdump -s proxy.py -k`
|
||||
|
||||
신뢰하는 인증 기관 인증서 (CA Cert) :
|
||||
|
||||
**각주 :** CA 인증서는 보통 `%USERPROFILE%\ .mitmproxy` 경로에 저장되며, `http://mitm.it`에서 다운로드 받을 수도 있습니다.
|
||||
|
||||
더블 클릭하여 [설치](https://docs.microsoft.com/en-us/skype-sdk/sdn/articles/installing-the-trusted-root-certificate#installing-a-trusted-root-certificate) 또는 ...
|
||||
|
||||
- 명령어를 통해서
|
||||
|
||||
```shell
|
||||
certutil -addstore root %USERPROFILE%\.mitmproxy\mitmproxy-ca-cert.cer
|
||||
```
|
||||
|
||||
- Fiddler Classic : Fiddler Classic을 실행한 후, Setting에서 `Decrypt https traffic` 옵션을 켜고, Tools -> Options -> Connections에 있는 기본 포트를 `8888`을 제외한 다른 포트로 지정합니다. 그리고 [이 스크립트](https://github.lunatic.moe/fiddlerscript)를 불러옵니다.
|
||||
|
||||
- [호스트 파일](https://github.com/Grasscutters/Grasscutter/wiki/Running#traffic-route-map)
|
||||
|
||||
2. 네트워크 프록시를 `127.0.0.1:8080` 로 설정하거나 지정한 프록시 포트로 설정합니다.
|
||||
|
||||
**또한 `start.cmd`를 실행함으로써, 서버와 프록시 데몬을 자동으로 실행되게 할 수 있습니다. 이를 이용하기 위해서는 JAVA_HOME 환경 변수를 등록해야 합니다.**
|
||||
|
||||
### 빌드하기
|
||||
|
||||
@ -50,50 +77,39 @@ Grasscutter는 종속성 및 컴파일 처리를 위해 Gradle을 이용합니
|
||||
|
||||
- [Java SE 개발 키트 - 17](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html)
|
||||
- [Git](https://git-scm.com/downloads)
|
||||
- [NodeJS](https://nodejs.org/en/download) (선택, 핸드북을 빌드하기 위해 필요함.)
|
||||
|
||||
##### 클론
|
||||
##### 윈도우 (온라인)
|
||||
|
||||
```shell
|
||||
git clone --recurse-submodules https://github.com/Grasscutters/Grasscutter.git
|
||||
git clone https://github.com/Grasscutters/Grasscutter.git
|
||||
cd Grasscutter
|
||||
.\gradlew.bat # 개발 환경 설정
|
||||
.\gradlew jar # 컴파일
|
||||
```
|
||||
|
||||
##### 컴파일
|
||||
|
||||
**각주**: 핸드북 생성은 일부 시스템에서 실패할 수도 있습니다. 핸드북 생성을 비활성화하려면, `gradlew jar`명령에 `-PskipHandbook=1`명령줄 스위치를 추가하세요.
|
||||
|
||||
|
||||
윈도우:
|
||||
##### 윈도우 (로컬)
|
||||
|
||||
```shell
|
||||
.\gradlew.bat # 환경 준비
|
||||
.\gradlew jar
|
||||
cd <로컬 주소>/Grasscutter
|
||||
.\gradlew.bat # 개발 환경 설정
|
||||
.\gradlew jar # 컴파일
|
||||
```
|
||||
|
||||
리눅스 (GNU):
|
||||
##### 리눅스
|
||||
|
||||
```bash
|
||||
git clone https://github.com/Grasscutters/Grasscutter.git
|
||||
cd Grasscutter
|
||||
chmod +x gradlew
|
||||
./gradlew jar
|
||||
```
|
||||
|
||||
##### 핸드북 컴파일 (수동동)
|
||||
|
||||
Gradle 사용:
|
||||
|
||||
```shell
|
||||
./gradlew generateHandbook
|
||||
```
|
||||
|
||||
NPM 사용:
|
||||
|
||||
```shell
|
||||
cd src/handbook
|
||||
npm install
|
||||
npm run build
|
||||
./gradlew jar # 컴파일
|
||||
```
|
||||
|
||||
프로젝트 폴더의 최상단에서 jar 파일을 찾을 수 있습니다.
|
||||
|
||||
### 문제 해결
|
||||
흔한 문제들의 해결방법과 도움을 요청하려면, [우리의 디스코드 서버](https://discord.gg/T5vZU6UyeG)에 참가하고 support 채널에 가보세요.
|
||||
### 명령어들은 [위키](https://github.com/Grasscutters/Grasscutter/wiki/Commands)에서 확인할 수 있습니다.
|
||||
|
||||
# 빠른 문제 해결
|
||||
|
||||
* 만약 컴파일링이 정상적으로 완료되지 않을 경우, JDK 설치를 확인하세요. (JDK 버전 17 및 JDK의 bin 경로 변수 등록을 확인)
|
||||
* 클라이언트가 연결되지 않거나, 로그인이 안 되거나, 4206 오류가 뜨는 등의 경우 - 대부분 프록시 데몬의 설치에 문제가 있을 것입니다. Fiddler를 사용하고 있다면, 8888을 제외한 다른 포트에서 구동되고 있는지 확인하세요.
|
||||
* 구동 순서 : MongoDB > Grasscutter > 프록시 데몬 (mitmdump, fiddler 등) > 게임
|
||||
|
@ -26,9 +26,7 @@
|
||||
|
||||
- 获取Java 17:https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html
|
||||
- 获取[MongoDB社区版](https://www.mongodb.com/try/download/community)
|
||||
- 获取游戏4.0正式版 (如果你没有4.0的客户端,可以在这里找到):
|
||||
[123pan share](https://www.123pan.com/s/HoqUVv-U7SBA.html)
|
||||
[github](https://github.com/JRSKelvin/GenshinRepository/blob/main/Version%204.0.0.md)
|
||||
- 获取游戏4.0正式版 (如果你没有4.0的客户端,可以在这里找到):https://github.com/MAnggiarMustofa/GI-Download-Library/blob/main/GenshinImpact/Client/4.0.0.md)
|
||||
|
||||
- 下载[最新的Cultivation版本](https://github.com/Grasscutters/Cultivation/releases/latest)(使用以“.msi”为后缀的安装包)。
|
||||
- 以管理员身份打开Cultivation,按右上角的下载按钮。
|
||||
|
0
entrypoint.sh
Normal file → Executable file
0
entrypoint.sh
Normal file → Executable file
@ -77,8 +77,6 @@ public final class Grasscutter {
|
||||
|
||||
// Load server configuration.
|
||||
Grasscutter.loadConfig();
|
||||
// Attempt to update configuration.
|
||||
ConfigContainer.updateConfig();
|
||||
|
||||
Grasscutter.getLogger().info("Loading Grasscutter...");
|
||||
|
||||
@ -238,22 +236,7 @@ public final class Grasscutter {
|
||||
/** Attempts to load the configuration from a file. */
|
||||
public static void loadConfig() {
|
||||
// Check if config.json exists. If not, we generate a new config.
|
||||
if (!configFile.exists()) {
|
||||
getLogger().info("config.json could not be found. Generating a default configuration ...");
|
||||
config = new ConfigContainer();
|
||||
Grasscutter.saveConfig(config);
|
||||
return;
|
||||
}
|
||||
|
||||
// If the file already exists, we attempt to load it.
|
||||
try {
|
||||
config = JsonUtils.loadToClass(configFile.toPath(), ConfigContainer.class);
|
||||
} catch (Exception exception) {
|
||||
getLogger()
|
||||
.error(
|
||||
"There was an error while trying to load the configuration from config.json. Please make sure that there are no syntax errors. If you want to start with a default configuration, delete your existing config.json.");
|
||||
System.exit(1);
|
||||
}
|
||||
config = new ConfigContainer();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -17,10 +17,8 @@ public final class StopCommand implements CommandHandler {
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
CommandHandler.sendMessage(null, translate("commands.stop.success"));
|
||||
if (Grasscutter.getGameServer() != null) {
|
||||
for (Player p : Grasscutter.getGameServer().getPlayers().values()) {
|
||||
CommandHandler.sendMessage(p, translate(p, "commands.stop.success"));
|
||||
}
|
||||
for (Player p : Grasscutter.getGameServer().getPlayers().values()) {
|
||||
CommandHandler.sendMessage(p, translate(p, "commands.stop.success"));
|
||||
}
|
||||
|
||||
System.exit(1000);
|
||||
|
@ -1,81 +1,257 @@
|
||||
package emu.grasscutter.config;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.utils.*;
|
||||
import emu.grasscutter.utils.Crypto;
|
||||
import emu.grasscutter.utils.Utils;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static emu.grasscutter.Grasscutter.*;
|
||||
import static emu.grasscutter.Grasscutter.ServerDebugMode;
|
||||
import static emu.grasscutter.Grasscutter.ServerRunMode;
|
||||
|
||||
/**
|
||||
* *when your JVM fails*
|
||||
*/
|
||||
public class ConfigContainer {
|
||||
/*
|
||||
* Configuration changes:
|
||||
* Version 5 - 'questing' has been changed from a boolean
|
||||
* to a container of options ('questOptions').
|
||||
* This field will be removed in future versions.
|
||||
* Version 6 - 'questing' has been fully replaced with 'questOptions'.
|
||||
* The field for 'legacyResources' has been removed.
|
||||
* Version 7 - 'regionKey' is being added for authentication
|
||||
* with the new dispatch server.
|
||||
* Version 8 - 'server' is being added for enforcing handbook server
|
||||
* addresses.
|
||||
* Version 9 - 'limits' was added for handbook requests.
|
||||
* Version 10 - 'trialCostumes' was added for enabling costumes
|
||||
* on trial avatars.
|
||||
* Version 11 - 'server.fastRequire' was added for disabling the new
|
||||
* Lua script require system if performance is a concern.
|
||||
* Version 12 - 'http.startImmediately' was added to control whether the
|
||||
* HTTP server should start immediately.
|
||||
* Version 13 - 'game.useUniquePacketKey' was added to control whether the
|
||||
* encryption key used for packets is a constant or randomly generated.
|
||||
/**
|
||||
* Retrieves the given key from the environment variables.
|
||||
* <p>
|
||||
* When the key is not set it will return the given default value.
|
||||
*
|
||||
* @param key The name of the environment variable
|
||||
* @param defaultValue The default value when the key is not set
|
||||
* @return The value from the environment variable or the default value
|
||||
*/
|
||||
private static int version() {
|
||||
return 13;
|
||||
static String getStringFromEnv(String key, String defaultValue) {
|
||||
var currentValue = System.getenv(key);
|
||||
|
||||
if (currentValue == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
return currentValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to update the server's existing configuration.
|
||||
* Retrieves the given key from the environment variables and tries to parse it as integer.
|
||||
* <p>
|
||||
* If the environment variable is not present or the parsing fails then the default value will be returned.
|
||||
*
|
||||
* @param key The name of the environment variable to parse
|
||||
* @param defaultValue The default value when the environment variable does not exists or is not a valid integer
|
||||
* @return The parsed integer or the default value
|
||||
*/
|
||||
public static void updateConfig() {
|
||||
try { // Check if the server is using a legacy config.
|
||||
var configObject = JsonUtils.loadToClass(Grasscutter.configFile.toPath(), JsonObject.class);
|
||||
if (!configObject.has("version")) {
|
||||
Grasscutter.getLogger().info("Updating legacy config...");
|
||||
Grasscutter.saveConfig(null);
|
||||
}
|
||||
} catch (Exception ignored) { }
|
||||
static int getIntFromEnv(String key, int defaultValue) {
|
||||
var currentValue = System.getenv(key);
|
||||
|
||||
var existing = config.version;
|
||||
var latest = version();
|
||||
|
||||
if (existing == latest)
|
||||
return;
|
||||
|
||||
// Create a new configuration instance.
|
||||
var updated = new ConfigContainer();
|
||||
// Update all configuration fields.
|
||||
var fields = ConfigContainer.class.getDeclaredFields();
|
||||
Arrays.stream(fields).forEach(field -> {
|
||||
try {
|
||||
field.set(updated, field.get(config));
|
||||
} catch (Exception exception) {
|
||||
Grasscutter.getLogger().error("Failed to update a configuration field.", exception);
|
||||
}
|
||||
}); updated.version = version();
|
||||
|
||||
try { // Save configuration and reload.
|
||||
Grasscutter.saveConfig(updated);
|
||||
Grasscutter.loadConfig();
|
||||
} catch (Exception exception) {
|
||||
Grasscutter.getLogger().warn("Failed to save the updated configuration.", exception);
|
||||
if (currentValue == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
try {
|
||||
return Integer.parseInt(currentValue, 10);
|
||||
} catch (Exception e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the given key from the environment variables and tries to parse it as float.
|
||||
* <p>
|
||||
* If the environment variable is not present or the parsing fails then the default value will be returned.
|
||||
*
|
||||
* @param key The name of the environment variable to parse
|
||||
* @param defaultValue The default value when the environment variable does not exist or is not a valid float
|
||||
* @return The parsed float or the default value
|
||||
*/
|
||||
static float getFloatFromEnv(String key, float defaultValue) {
|
||||
var currentValue = System.getenv(key);
|
||||
|
||||
if (currentValue == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
try {
|
||||
return Float.parseFloat(currentValue);
|
||||
} catch (Exception e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the given key from the environment variables and tries to parse it as float.
|
||||
* <p>
|
||||
* If the environment variable is not present or the parsing fails then the default value will be returned.
|
||||
*
|
||||
* @param key The name of the environment variable to parse
|
||||
* @param defaultValue The default value when the environment variable does not exists or is not a valid bool
|
||||
* @return The parsed boolean or the default value
|
||||
*/
|
||||
static boolean getBoolFromEnv(String key, boolean defaultValue) {
|
||||
var currentValue = System.getenv(key);
|
||||
|
||||
if (currentValue == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
return switch (currentValue.trim()) {
|
||||
case "true", "on", "1" -> true;
|
||||
case "false", "off", "0" -> false;
|
||||
default -> defaultValue;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the given from the environment variables and tries to parse it as a Set<String>.
|
||||
* <p>
|
||||
* If the environment variable is not present or the parsing fails then the default value will be returned.
|
||||
*
|
||||
* @param key The name of the environment variable to parse
|
||||
* @param defaultValue The default value when the environment variable does not exist or is not a valid set
|
||||
* @param separator The separator which will be used for splitting up the string
|
||||
* @return The parsed set or the default value
|
||||
*/
|
||||
static Set<String> getStringSetFromEnv(String key, Set<String> defaultValue, String separator) {
|
||||
var currentValue = System.getenv(key);
|
||||
|
||||
if (currentValue == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
var parts = currentValue.split(separator);
|
||||
|
||||
return Set.of(parts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the given key from the environment variables and tries to parse it as a string array.
|
||||
* <p>
|
||||
* If the environment variable is not present or the parsing fails then the default value will be returned.
|
||||
*
|
||||
* @param key The name of the environment variable
|
||||
* @param defaultValue The default value when the environment variable does not exist
|
||||
* @param separator The separator which will be used for splitting up the environment variable
|
||||
* @return The parsed integer set or the default value
|
||||
*/
|
||||
static Set<Integer> getIntSetFromEnv(String key, Set<Integer> defaultValue, String separator) {
|
||||
var defaultValues = defaultValue.stream().map(Object::toString).collect(Collectors.toSet());
|
||||
var currentValue = getStringSetFromEnv(key, defaultValues, separator);
|
||||
|
||||
return currentValue.stream().map(entry -> Integer.parseInt(entry, 10)).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the given key from the environment variables and tries to parse it as an enum member.
|
||||
* <p>
|
||||
* If the environment variable is not present or the parsing fails then the default value will be returned.
|
||||
*
|
||||
* @param key The name of the environment variable to parse
|
||||
* @param enumClass The enum class which contains all members
|
||||
* @param defaultValue The default value when the environment variable does not exists or is not a valid enum member
|
||||
* @param <T> The type of the enum member
|
||||
* @return The parsed enum member or the default value
|
||||
*/
|
||||
static <T extends Enum<T>> T getEnumFromEnv(String key, Class<T> enumClass, T defaultValue) {
|
||||
var currentValue = System.getenv(key);
|
||||
|
||||
if (currentValue == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
try {
|
||||
return Enum.valueOf(enumClass, currentValue);
|
||||
} catch (Exception e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the given key from the environment variables and tries to parse it as string array.
|
||||
* <p>
|
||||
* If the environment variable is not present or the parsing fails then the default value will be returned.
|
||||
*
|
||||
* @param key The name of the environment variable to parse
|
||||
* @param defaultValue The default value when the environment variable does not exist
|
||||
* @param separator The separator which will be used for splitting up the string
|
||||
* @return The parsed string array or the default value
|
||||
*/
|
||||
static String[] getStringArrayFromEnv(String key, String[] defaultValue, String separator) {
|
||||
var currentValue = System.getenv(key);
|
||||
|
||||
if (currentValue == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
return currentValue.split(separator);
|
||||
}
|
||||
|
||||
static int[] getIntArrayFromEnv(String key, int[] defaultValue, String separator) {
|
||||
var currentValue = System.getenv(key);
|
||||
|
||||
if (currentValue == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
return Arrays.stream(currentValue.split(separator)).mapToInt(Integer::parseInt).toArray();
|
||||
}
|
||||
|
||||
static emu.grasscutter.game.mail.Mail.MailItem[] getMailItemsFromEnv(String key, emu.grasscutter.game.mail.Mail.MailItem[] defaultValue, String partsSeparator, String valuesSeparator) {
|
||||
var currentValue = System.getenv(key);
|
||||
|
||||
if (currentValue == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
var parts = Arrays.stream(currentValue.split(partsSeparator)).map(part -> part.split(valuesSeparator));
|
||||
|
||||
return (emu.grasscutter.game.mail.Mail.MailItem[]) parts.filter(part -> part.length != 3).map(part -> {
|
||||
var itemId = Integer.parseInt(part[0], 10);
|
||||
var itemCount = Integer.parseInt(part[1], 10);
|
||||
var itemLevel = Integer.parseInt(part[2], 10);
|
||||
|
||||
return new emu.grasscutter.game.mail.Mail.MailItem(itemId, itemCount, itemLevel);
|
||||
}).toArray();
|
||||
}
|
||||
|
||||
static VisionOptions[] getVisionOptionsFromEnv(String key, VisionOptions[] defaultValue, String partsSeparator, String valuesSeparator) {
|
||||
var currentValue = System.getenv(key);
|
||||
|
||||
if (currentValue == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
var parts = currentValue.split(partsSeparator);
|
||||
return (VisionOptions[]) Arrays.stream(parts).map(part -> part.split(valuesSeparator)).filter(values -> values.length == 3).map(values -> {
|
||||
var name = values[0];
|
||||
var visionRange = Integer.parseInt(values[1]);
|
||||
var gridWidth = Integer.parseInt(values[2]);
|
||||
|
||||
return new VisionOptions(name, visionRange, gridWidth);
|
||||
}).toArray();
|
||||
}
|
||||
|
||||
static List<Region> getRegionsFromEnv(String key, List<Region> defaultValue, String partsSeparator, String valuesSeparator) {
|
||||
var currentValue = System.getenv(key);
|
||||
|
||||
if (currentValue == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
var parts = currentValue.split(partsSeparator);
|
||||
return Arrays.stream(parts).map(part -> part.split(valuesSeparator)).filter(values -> values.length == 4).map(values -> {
|
||||
var name = values[0];
|
||||
var title = values[1];
|
||||
var address = values[2];
|
||||
var port = Integer.parseInt(values[3]);
|
||||
|
||||
return new Region(name, title, address, port);
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public Structure folderStructure = new Structure();
|
||||
@ -84,9 +260,6 @@ public class ConfigContainer {
|
||||
public Account account = new Account();
|
||||
public Server server = new Server();
|
||||
|
||||
// DO NOT. TOUCH. THE VERSION NUMBER.
|
||||
public int version = version();
|
||||
|
||||
/* Option containers. */
|
||||
|
||||
public static class Database {
|
||||
@ -100,28 +273,29 @@ public class ConfigContainer {
|
||||
}
|
||||
|
||||
public static class Structure {
|
||||
public String resources = "./resources/";
|
||||
public String data = "./data/";
|
||||
public String packets = "./packets/";
|
||||
public String scripts = "resources:Scripts/";
|
||||
public String plugins = "./plugins/";
|
||||
public String cache = "./cache/";
|
||||
public String resources = getStringFromEnv("FOLDER_STRUCTURE_RESOURCES", "./resources/");
|
||||
public String data = getStringFromEnv("FOLDER_STRUCTURE_DATA", "./data/");
|
||||
public String packets = getStringFromEnv("FOLDER_STRUCTURE_PACKETS", "./packets/");
|
||||
public String scripts = getStringFromEnv("FOLDER_STRUCTURE_SCRIPTS", "resources:Scripts/");
|
||||
public String plugins = getStringFromEnv("FOLDER_STRUCTURE_PLUGINS", "./plugins/");
|
||||
public String cache = getStringFromEnv("FOLDER_STRUCTURE_CACHE", "./cache/");
|
||||
|
||||
// UNUSED (potentially added later?)
|
||||
// public String dumps = "./dumps/";
|
||||
}
|
||||
|
||||
public static class Server {
|
||||
public Set<Integer> debugWhitelist = Set.of();
|
||||
public Set<Integer> debugBlacklist = Set.of();
|
||||
public ServerRunMode runMode = ServerRunMode.HYBRID;
|
||||
public boolean logCommands = false;
|
||||
public Set<Integer> debugWhitelist = getIntSetFromEnv("SERVER_DEBUG_WHITELIST", Set.of(), ",");
|
||||
public Set<Integer> debugBlacklist = getIntSetFromEnv("SERVER_DEBUG_BLACKLIST", Set.of(), ",");
|
||||
public ServerRunMode runMode = getEnumFromEnv("SERVER_RUN_MODE", ServerRunMode.class, ServerRunMode.HYBRID);
|
||||
|
||||
public boolean logCommands = getBoolFromEnv("SERVER_LOG_COMMANDS", false);
|
||||
|
||||
/**
|
||||
* If enabled, the 'require' Lua function will load the script's compiled varient into the context. (faster; doesn't work as well)
|
||||
* If disabled, all 'require' calls will be replaced with the referenced script's source. (slower; works better)
|
||||
*/
|
||||
public boolean fastRequire = true;
|
||||
public boolean fastRequire = getBoolFromEnv("SERVER_FAST_REQUIRE", true);
|
||||
|
||||
public HTTP http = new HTTP();
|
||||
public Game game = new Game();
|
||||
@ -133,30 +307,29 @@ public class ConfigContainer {
|
||||
public static class Language {
|
||||
public Locale language = Locale.getDefault();
|
||||
public Locale fallback = Locale.US;
|
||||
public String document = "EN";
|
||||
public String document = getStringFromEnv("LANGUAGE_DOCUMENT", "EN");
|
||||
}
|
||||
|
||||
public static class Account {
|
||||
public boolean autoCreate = false;
|
||||
public boolean EXPERIMENTAL_RealPassword = false;
|
||||
public String[] defaultPermissions = {};
|
||||
public String playerEmail = "grasscutter.io";
|
||||
public int maxPlayer = -1;
|
||||
public boolean autoCreate = getBoolFromEnv("ACCOUNT_AUTO_CREATE", false);
|
||||
public boolean EXPERIMENTAL_RealPassword = getBoolFromEnv("ACCOUNT_EXPERIMENTAL_REAL_PASSWORD", false);
|
||||
public String[] defaultPermissions = getStringArrayFromEnv("ACCOUNT_DEFAULT_PERMISSIONS", new String[]{}, ",");
|
||||
public int maxPlayer = getIntFromEnv("ACCOUNT_MAX_PLAYER", -1);
|
||||
}
|
||||
|
||||
/* Server options. */
|
||||
|
||||
public static class HTTP {
|
||||
/* This starts the HTTP server before the game server. */
|
||||
public boolean startImmediately = false;
|
||||
public boolean startImmediately = getBoolFromEnv("SERVER_HTTP_START_IMMEDIATELY", false);
|
||||
|
||||
public String bindAddress = "0.0.0.0";
|
||||
public int bindPort = 443;
|
||||
public String bindAddress = getStringFromEnv("SERVER_HTTP_BIND_ADDRESS", "0.0.0.0");
|
||||
public int bindPort = getIntFromEnv("SERVER_HTTP_BIND_PORT", 443);
|
||||
|
||||
/* This is the address used in URLs. */
|
||||
public String accessAddress = "127.0.0.1";
|
||||
public String accessAddress = getStringFromEnv("SERVER_HTTP_ACCESS_ADDRESS", "127.0.0.1");
|
||||
/* This is the port used in URLs. */
|
||||
public int accessPort = 0;
|
||||
public int accessPort = getIntFromEnv("SERVER_HTTP_ACCESS_PORT", 0);
|
||||
|
||||
public Encryption encryption = new Encryption();
|
||||
public Policies policies = new Policies();
|
||||
@ -164,66 +337,65 @@ public class ConfigContainer {
|
||||
}
|
||||
|
||||
public static class Game {
|
||||
public String bindAddress = "0.0.0.0";
|
||||
public int bindPort = 22102;
|
||||
public String bindAddress = getStringFromEnv("SERVER_GAME_BIND_ADDRESS", "0.0.0.0");
|
||||
public int bindPort = getIntFromEnv("SERVER_GAME_BIND_PORT", 22102);
|
||||
|
||||
/* This is the address used in the default region. */
|
||||
public String accessAddress = "127.0.0.1";
|
||||
public String accessAddress = getStringFromEnv("SERVER_GAME_ACCESS_ADDRESS", "127.0.0.1");
|
||||
/* This is the port used in the default region. */
|
||||
public int accessPort = 0;
|
||||
public int accessPort = getIntFromEnv("SERVER_GAME_ACCESS_PORT", 0);
|
||||
|
||||
/* Enabling this will generate a unique packet encryption key for each player. */
|
||||
public boolean useUniquePacketKey = true;
|
||||
public boolean useUniquePacketKey = getBoolFromEnv("SERVER_GAME_USE_UNIQUE_PACKET_KEY", true);
|
||||
|
||||
/* Entities within a certain range will be loaded for the player */
|
||||
public int loadEntitiesForPlayerRange = 300;
|
||||
public int loadEntitiesForPlayerRange = getIntFromEnv("SERVER_GAME_LOAD_ENTITIES_FOR_PLAYER_RANGE", 300);
|
||||
/* Start in 'unstable-quests', Lua scripts will be enabled by default. */
|
||||
public boolean enableScriptInBigWorld = true;
|
||||
public boolean enableConsole = true;
|
||||
public boolean enableScriptInBigWorld = getBoolFromEnv("SERVER_GAME_ENABLE_SCRIPT_IN_BIG_WORLD", true);
|
||||
public boolean enableConsole = getBoolFromEnv("SERVER_GAME_ENABLE_CONSOLE", true);
|
||||
|
||||
/* Kcp internal work interval (milliseconds) */
|
||||
public int kcpInterval = 20;
|
||||
public int kcpInterval = getIntFromEnv("SERVER_GAME_KCP_INTERVAL", 20);
|
||||
/* Controls whether packets should be logged in console or not */
|
||||
public ServerDebugMode logPackets = ServerDebugMode.NONE;
|
||||
public ServerDebugMode logPackets = getEnumFromEnv("SERVER_GAME_LOG_PACKETS", ServerDebugMode.class, ServerDebugMode.NONE);
|
||||
/* Show packet payload in console or no (in any case the payload is shown in encrypted view) */
|
||||
public boolean isShowPacketPayload = false;
|
||||
public boolean isShowPacketPayload = getBoolFromEnv("SERVER_GAME_IS_SHOW_PACKET_PAYLOAD", false);
|
||||
/* Show annoying loop packets or no */
|
||||
public boolean isShowLoopPackets = false;
|
||||
public boolean isShowLoopPackets = getBoolFromEnv("SERVER_GAME_IS_SHOW_LOOP_PACKETS", false);
|
||||
|
||||
public boolean cacheSceneEntitiesEveryRun = false;
|
||||
public boolean cacheSceneEntitiesEveryRun = getBoolFromEnv("SERVER_GAME_CACHE_SCENE_ENTITIES_EVERY_RUN", false);
|
||||
|
||||
public GameOptions gameOptions = new GameOptions();
|
||||
public JoinOptions joinOptions = new JoinOptions();
|
||||
public ConsoleAccount serverAccount = new ConsoleAccount();
|
||||
|
||||
public VisionOptions[] visionOptions = new VisionOptions[] {
|
||||
new VisionOptions("VISION_LEVEL_NORMAL" , 80 , 20),
|
||||
new VisionOptions("VISION_LEVEL_LITTLE_REMOTE" , 16 , 40),
|
||||
new VisionOptions("VISION_LEVEL_REMOTE" , 1000 , 250),
|
||||
new VisionOptions("VISION_LEVEL_SUPER" , 4000 , 1000),
|
||||
new VisionOptions("VISION_LEVEL_NEARBY" , 40 , 20),
|
||||
new VisionOptions("VISION_LEVEL_SUPER_NEARBY" , 20 , 20)
|
||||
};
|
||||
public VisionOptions[] visionOptions = getVisionOptionsFromEnv("SERVER_GAME_VISION_OPTIONS", new VisionOptions[]{
|
||||
new VisionOptions("VISION_LEVEL_NORMAL", 80, 20),
|
||||
new VisionOptions("VISION_LEVEL_LITTLE_REMOTE", 16, 40),
|
||||
new VisionOptions("VISION_LEVEL_REMOTE", 1000, 250),
|
||||
new VisionOptions("VISION_LEVEL_SUPER", 4000, 1000),
|
||||
new VisionOptions("VISION_LEVEL_NEARBY", 40, 20),
|
||||
new VisionOptions("VISION_LEVEL_SUPER_NEARBY", 20, 20)
|
||||
}, "|", ",");
|
||||
}
|
||||
|
||||
/* Data containers. */
|
||||
|
||||
public static class Dispatch {
|
||||
/* An array of servers. */
|
||||
public List<Region> regions = List.of();
|
||||
public List<Region> regions = getRegionsFromEnv("SERVER_DISPATCH_REGIONS", List.of(), "|", ",");
|
||||
|
||||
/* The URL used to make HTTP requests to the dispatch server. */
|
||||
public String dispatchUrl = "ws://127.0.0.1:1111";
|
||||
public String dispatchUrl = getStringFromEnv("SERVER_DISPATCH_DISPATCH_URL", "ws://127.0.0.1:1111");
|
||||
/* A unique key used for encryption. */
|
||||
public byte[] encryptionKey = Crypto.createSessionKey(32);
|
||||
public byte[] encryptionKey = Utils.base64Decode(getStringFromEnv("SERVER_DISPATCH_ENCRYPTION_KEY", Utils.base64Encode(Crypto.createSessionKey(32))));
|
||||
/* A unique key used for authentication. */
|
||||
public String dispatchKey = Utils.base64Encode(
|
||||
Crypto.createSessionKey(32));
|
||||
public String dispatchKey = getStringFromEnv("SERVER_DISPATCH_DISPATCH_KEY", Utils.base64Encode(Crypto.createSessionKey(32)));
|
||||
|
||||
public String defaultName = "Grasscutter";
|
||||
public String defaultName = getStringFromEnv("SERVER_DISPATCH_DEFAULT_NAME", "Grasscutter");
|
||||
|
||||
/* Controls whether http requests should be logged in console or not */
|
||||
public ServerDebugMode logRequests = ServerDebugMode.NONE;
|
||||
public ServerDebugMode logRequests = getEnumFromEnv("SERVER_DISPATCH_SERVER_DEBUG_MODE", ServerDebugMode.class, ServerDebugMode.NONE);
|
||||
}
|
||||
|
||||
/* Debug options container, used when jar launch argument is -debug | -debugall and override default values
|
||||
@ -237,46 +409,46 @@ public class ConfigContainer {
|
||||
public Level servicesLoggersLevel = Level.INFO;
|
||||
|
||||
/* Controls whether packets should be logged in console or not */
|
||||
public ServerDebugMode logPackets = ServerDebugMode.ALL;
|
||||
public ServerDebugMode logPackets = getEnumFromEnv("SERVER_DEBUG_MODE_LOG_PACKETS", ServerDebugMode.class, ServerDebugMode.ALL);
|
||||
|
||||
/* Show packet payload in console or no (in any case the payload is shown in encrypted view) */
|
||||
public boolean isShowPacketPayload = false;
|
||||
public boolean isShowPacketPayload = getBoolFromEnv("SERVER_DEBUG_MODE_IS_SHOW_PACKET_PAYLOAD", false);
|
||||
|
||||
/* Show annoying loop packets or no */
|
||||
public boolean isShowLoopPackets = false;
|
||||
public boolean isShowLoopPackets = getBoolFromEnv("SERVER_DEBUG_MODE_IS_SHOW_LOOP_PACKETS", false);
|
||||
|
||||
/* Controls whether http requests should be logged in console or not */
|
||||
public ServerDebugMode logRequests = ServerDebugMode.ALL;
|
||||
public ServerDebugMode logRequests = getEnumFromEnv("SERVER_DEBUG_MODE_LOG_REQUESTS", ServerDebugMode.class, ServerDebugMode.ALL);
|
||||
}
|
||||
|
||||
public static class Encryption {
|
||||
public boolean useEncryption = true;
|
||||
public boolean useEncryption = getBoolFromEnv("SERVER_HTTP_ENCRYPTION_USE_ENCRYPTION", true);
|
||||
/* Should 'https' be appended to URLs? */
|
||||
public boolean useInRouting = true;
|
||||
public String keystore = "./keystore.p12";
|
||||
public String keystorePassword = "123456";
|
||||
public boolean useInRouting = getBoolFromEnv("SERVER_HTTP_ENCRYPTION_USE_IN_ROUTING", true);
|
||||
public String keystore = getStringFromEnv("SERVER_HTTP_ENCRYPTION_KEYSTORE", "./keystore.p12");
|
||||
public String keystorePassword = getStringFromEnv("SERVER_HTTP_ENCRYPTION_KEYSTORE_PASSWORD", "123456");
|
||||
}
|
||||
|
||||
public static class Policies {
|
||||
public Policies.CORS cors = new Policies.CORS();
|
||||
|
||||
public static class CORS {
|
||||
public boolean enabled = true;
|
||||
public String[] allowedOrigins = new String[]{"*"};
|
||||
public boolean enabled = getBoolFromEnv("SERVER_HTTP_POLICIES_CORS_ENABLED", true);
|
||||
public String[] allowedOrigins = getStringArrayFromEnv("SERVER_HTTP_POLICIES_ALLOWED_ORIGINS", new String[]{"*"}, ",");
|
||||
}
|
||||
}
|
||||
|
||||
public static class GameOptions {
|
||||
public InventoryLimits inventoryLimits = new InventoryLimits();
|
||||
public AvatarLimits avatarLimits = new AvatarLimits();
|
||||
public int sceneEntityLimit = 1000; // Unenforced. TODO: Implement.
|
||||
public int sceneEntityLimit = getIntFromEnv("SERVER_GAME_GAME_OPTIONS_SCENE_ENTITY_LIMIT", 1000); // Unenforced. TODO: Implement.
|
||||
|
||||
public boolean watchGachaConfig = false;
|
||||
public boolean enableShopItems = true;
|
||||
public boolean staminaUsage = true;
|
||||
public boolean energyUsage = true;
|
||||
public boolean fishhookTeleport = true;
|
||||
public boolean trialCostumes = false;
|
||||
public boolean watchGachaConfig = getBoolFromEnv("SERVER_GAME_GAME_OPTIONS_WATCH_GACHA_CONFIG", false);
|
||||
public boolean enableShopItems = getBoolFromEnv("SERVER_GAME_GAME_OPTIONS_ENABLE_SHOP_ITEMS", true);
|
||||
public boolean staminaUsage = getBoolFromEnv("SERVER_GAME_GAME_OPTIONS_STAMINA_USAGE", true);
|
||||
public boolean energyUsage = getBoolFromEnv("SERVER_GAME_GAME_OPTIONS_ENERGY_USAGE", true);
|
||||
public boolean fishhookTeleport = getBoolFromEnv("SERVER_GAME_GAME_OPTIONS_FISHHOOK_TELEPORT", true);
|
||||
public boolean trialCostumes = getBoolFromEnv("SERVER_GAME_GAME_OPTIONS_TRIAL_COSTUMES", false);
|
||||
|
||||
@SerializedName(value = "questing", alternate = "questOptions")
|
||||
public Questing questing = new Questing();
|
||||
@ -286,63 +458,63 @@ public class ConfigContainer {
|
||||
public HandbookOptions handbook = new HandbookOptions();
|
||||
|
||||
public static class InventoryLimits {
|
||||
public int weapons = 2000;
|
||||
public int relics = 2000;
|
||||
public int materials = 2000;
|
||||
public int furniture = 2000;
|
||||
public int all = 30000;
|
||||
public int weapons = getIntFromEnv("SERVER_GAME_GAME_OPTIONS_INVENTORY_LIMITS_WEAPONS", 2000);
|
||||
public int relics = getIntFromEnv("SERVER_GAME_GAME_OPTIONS_INVENTORY_LIMITS_RELICS", 2000);
|
||||
public int materials = getIntFromEnv("SERVER_GAME_GAME_OPTIONS_INVENTORY_LIMITS_MATERIALS", 2000);
|
||||
public int furniture = getIntFromEnv("SERVER_GAME_GAME_OPTIONS_INVENTORY_LIMITS_FURNITURE", 2000);
|
||||
public int all = getIntFromEnv("SERVER_GAME_GAME_OPTIONS_INVENTORY_LIMITS_ALL", 30000);
|
||||
}
|
||||
|
||||
public static class AvatarLimits {
|
||||
public int singlePlayerTeam = 4;
|
||||
public int multiplayerTeam = 4;
|
||||
public int singlePlayerTeam = getIntFromEnv("SERVER_GAME_GAME_OPTIONS_AVATAR_LIMITS_SINGLE_PLAYER_TEAM", 4);
|
||||
public int multiplayerTeam = getIntFromEnv("SERVER_GAME_GAME_OPTIONS_AVATAR_LIMITS_MULTIPLAYER_TEAM", 4);
|
||||
}
|
||||
|
||||
public static class Rates {
|
||||
public float adventureExp = 1.0f;
|
||||
public float mora = 1.0f;
|
||||
public float leyLines = 1.0f;
|
||||
public float adventureExp = getFloatFromEnv("SERVER_GAME_GAME_OPTIONS_RATES_ADVENTURE_EXP", 1.0f);
|
||||
public float mora = getFloatFromEnv("SERVER_GAME_GAME_OPTIONS_RATES_MORA", 1.0f);
|
||||
public float leyLines = getFloatFromEnv("SERVER_GAME_GAME_OPTIONS_RATES_LEY_LINES", 1.0f);
|
||||
}
|
||||
|
||||
public static class ResinOptions {
|
||||
public boolean resinUsage = false;
|
||||
public int cap = 160;
|
||||
public int rechargeTime = 480;
|
||||
public boolean resinUsage = getBoolFromEnv("SERVER_GAME_GAME_OPTIONS_RESIN_OPTIONS_RESIN_USAGE", false);
|
||||
public int cap = getIntFromEnv("SERVER_GAME_GAME_OPTIONS_RESIN_OPTIONS_CAP", 160);
|
||||
public int rechargeTime = getIntFromEnv("SERVER_GAME_GAME_OPTIONS_RESIN_OPTIONS_RECHARGE_TIME", 480);
|
||||
}
|
||||
|
||||
public static class Questing {
|
||||
/* Should questing behavior be used? */
|
||||
public boolean enabled = true;
|
||||
public boolean enabled = getBoolFromEnv("SERVER_GAME_GAME_OPTIONS_QUESTING_ENABLED", true);
|
||||
}
|
||||
|
||||
public static class HandbookOptions {
|
||||
public boolean enable = false;
|
||||
public boolean allowCommands = true;
|
||||
public boolean enable = getBoolFromEnv("SERVER_GAME_GAME_OPTIONS_HANDBOOK_OPTIONS_ENABLE", false);
|
||||
public boolean allowCommands = getBoolFromEnv("SERVER_GAME_GAME_OPTIONS_HANDBOOK_OPTIONS_ALLOW_COMMANDS", true);
|
||||
|
||||
public Limits limits = new Limits();
|
||||
public Server server = new Server();
|
||||
|
||||
public static class Limits {
|
||||
/* Are rate limits checked? */
|
||||
public boolean enabled = false;
|
||||
public boolean enabled = getBoolFromEnv("SERVER_GAME_GAME_OPTIONS_HANDBOOK_OPTIONS_LIMITS_ENABLED", false);
|
||||
/* The time for limits to expire. */
|
||||
public int interval = 3;
|
||||
public int interval = getIntFromEnv("SERVER_GAME_GAME_OPTIONS_HANDBOOK_OPTIONS_LIMITS_INTERVAL", 3);
|
||||
|
||||
/* The maximum amount of normal requests. */
|
||||
public int maxRequests = 10;
|
||||
public int maxRequests = getIntFromEnv("SERVER_GAME_GAME_OPTIONS_HANDBOOK_OPTIONS_LIMITS_MAX_REQUESTS", 10);
|
||||
/* The maximum amount of entities to be spawned in one request. */
|
||||
public int maxEntities = 25;
|
||||
public int maxEntities = getIntFromEnv("SERVER_GAME_GAME_OPTIONS_HANDBOOK_OPTIONS_LIMITS_MAX_ENTITIES", 25);
|
||||
}
|
||||
|
||||
public static class Server {
|
||||
/* Are the server settings sent to the handbook? */
|
||||
public boolean enforced = false;
|
||||
public boolean enforced = getBoolFromEnv("SERVER_GAME_GAME_OPTIONS_HANDBOOK_CONFIG_SERVER_ENFORCED", false);
|
||||
/* The default server address for the handbook's authentication. */
|
||||
public String address = "127.0.0.1";
|
||||
public String address = getStringFromEnv("SERVER_GAME_GAME_OPTIONS_HANDBOOK_CONFIG_SERVER_ADDRESS", "127.0.0.1");
|
||||
/* The default server port for the handbook's authentication. */
|
||||
public int port = 443;
|
||||
public int port = getIntFromEnv("SERVER_GAME_GAME_OPTIONS_HANDBOOK_CONFIG_SERVER_PORT", 443);
|
||||
/* Should the defaults be enforced? */
|
||||
public boolean canChange = true;
|
||||
public boolean canChange = getBoolFromEnv("SERVER_GAME_GAME_OPTIONS_HANDBOOK_CONFIG_SERVER_CAN_CHANGE", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -360,40 +532,37 @@ public class ConfigContainer {
|
||||
}
|
||||
|
||||
public static class JoinOptions {
|
||||
public int[] welcomeEmotes = {2007, 1002, 4010};
|
||||
public String welcomeMessage = "Welcome to a Grasscutter server.";
|
||||
public int[] welcomeEmotes = getIntArrayFromEnv("SERVER_GAME_JOIN_OPTIONS_WELCOME_EMOTES", new int[]{2007, 1002, 4010}, ",");
|
||||
public String welcomeMessage = getStringFromEnv("SERVER_GAME_JOIN_OPTIONS_WELCOME_MESSAGE", "Welcome to a Grasscutter server.");
|
||||
public JoinOptions.Mail welcomeMail = new JoinOptions.Mail();
|
||||
|
||||
public static class Mail {
|
||||
public String title = "Welcome to Grasscutter!";
|
||||
public String content = """
|
||||
Hi there!\r
|
||||
First of all, welcome to Grasscutter. If you have any issues, please let us know so that Lawnmower can help you! \r
|
||||
\r
|
||||
Check out our:\r
|
||||
<type="browser" text="Discord" href="https://discord.gg/T5vZU6UyeG"/>
|
||||
""";
|
||||
public String sender = "Lawnmower";
|
||||
public emu.grasscutter.game.mail.Mail.MailItem[] items = {
|
||||
new emu.grasscutter.game.mail.Mail.MailItem(13509, 1, 1),
|
||||
new emu.grasscutter.game.mail.Mail.MailItem(201, 99999, 1)
|
||||
};
|
||||
public String title = getStringFromEnv("SERVER_GAME_JOIN_OPTIONS_WELCOME_MAIL_TITLE", "Welcome to Grasscutter!");
|
||||
public String content = getStringFromEnv("SERVER_GAME_JOIN_OPTIONS_WELCOME_MAIL_CONTENT", """
|
||||
Hi there!\r
|
||||
First of all, welcome to Grasscutter. If you have any issues, please let us know so that Lawnmower can help you! \r
|
||||
\r
|
||||
Check out our:\r
|
||||
<type="browser" text="Discord" href="https://discord.gg/T5vZU6UyeG"/>
|
||||
""");
|
||||
public String sender = getStringFromEnv("SERVER_GAME_JOIN_OPTIONS_WELCOME_MAIL_SENDER", "Lawnmower");
|
||||
public emu.grasscutter.game.mail.Mail.MailItem[] items = getMailItemsFromEnv("SERVER_GAME_JOIN_OPTIONS_WELCOME_MAIL_ITEMS", new emu.grasscutter.game.mail.Mail.MailItem[]{new emu.grasscutter.game.mail.Mail.MailItem(13509, 1, 1), new emu.grasscutter.game.mail.Mail.MailItem(201, 99999, 1)}, "|", ",");
|
||||
}
|
||||
}
|
||||
|
||||
public static class ConsoleAccount {
|
||||
public int avatarId = 10000007;
|
||||
public int nameCardId = 210001;
|
||||
public int adventureRank = 1;
|
||||
public int worldLevel = 0;
|
||||
public int avatarId = getIntFromEnv("SERVER_GAME_CONSOLE_ACCOUNT_AVATAR_ID", 10000007);
|
||||
public int nameCardId = getIntFromEnv("SERVER_GAME_CONSOLE_ACCOUNT_NAME_CARD_ID", 210001);
|
||||
public int adventureRank = getIntFromEnv("SERVER_GAME_CONSOLE_ACCOUNT_ADVENTURE_RANK", 1);
|
||||
public int worldLevel = getIntFromEnv("SERVER_GAME_CONSOLE_ACCOUNT_WORLD_LEVEL", 0);
|
||||
|
||||
public String nickName = "Server";
|
||||
public String signature = "Welcome to Grasscutter!";
|
||||
public String nickName = getStringFromEnv("SERVER_GAME_CONSOLE_ACCOUNT_NICK_NAME", "Server");
|
||||
public String signature = getStringFromEnv("SERVER_GAME_CONSOLE_ACCOUNT_SIGNATURE", "Welcome to Grasscutter!");
|
||||
}
|
||||
|
||||
public static class Files {
|
||||
public String indexFile = "./index.html";
|
||||
public String errorFile = "./404.html";
|
||||
public String indexFile = getStringFromEnv("SERVER_HTTP_FILES_INDEX_FILE", "./index.html");
|
||||
public String errorFile = getStringFromEnv("SERVER_HTTP_FILES_ERROR_FILE", "./404.html");
|
||||
}
|
||||
|
||||
/* Objects. */
|
||||
@ -405,14 +574,11 @@ public class ConfigContainer {
|
||||
public String Ip = "127.0.0.1";
|
||||
public int Port = 22102;
|
||||
|
||||
public Region(
|
||||
String name, String title,
|
||||
String address, int port
|
||||
) {
|
||||
public Region(String name, String title, String address, int port) {
|
||||
this.Name = name;
|
||||
this.Title = title;
|
||||
this.Ip = address;
|
||||
this.Port = port;
|
||||
this.Port = port;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -109,7 +109,7 @@ public class Account {
|
||||
return email;
|
||||
} else {
|
||||
// As of game version 3.5+, only the email is displayed to a user.
|
||||
return this.getUsername() + "@" + ACCOUNT.playerEmail;
|
||||
return this.getUsername() + "@grasscutter.io";
|
||||
}
|
||||
}
|
||||
|
||||
@ -235,7 +235,7 @@ public class Account {
|
||||
this.addPermission("*");
|
||||
}
|
||||
|
||||
// Set account default language to server default language
|
||||
// Set account default language as server default language
|
||||
if (!document.containsKey("locale")) {
|
||||
this.locale = LANGUAGE;
|
||||
}
|
||||
|
@ -218,8 +218,6 @@ public final class HttpServer {
|
||||
|
||||
<body>
|
||||
<img src="https://http.cat/404" />
|
||||
<h1>Grasscutter cannot find the route you're trying to access.</h1>
|
||||
<p>Your proxy is active, so if you're trying to download something close the game/stop the proxy.</p>
|
||||
</body>
|
||||
</html>
|
||||
""");
|
||||
|
Reference in New Issue
Block a user