mirror of
https://github.com/Grasscutters/Grasscutter.git
synced 2026-06-04 07:23:34 +08:00
Compare commits
19 Commits
v1.7.4
..
e1469e152d
@@ -0,0 +1,51 @@
|
||||
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 }}
|
||||
@@ -64,6 +64,7 @@ tmp/
|
||||
|
||||
/*.jar
|
||||
/*.sh
|
||||
!entrypoint.sh
|
||||
|
||||
GM Handbook*.txt
|
||||
handbook.html
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
# Builder
|
||||
FROM gradle:jdk17-alpine as builder
|
||||
|
||||
RUN apk add --update nodejs npm
|
||||
|
||||
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
|
||||
ARG DATA_BRANCH=4.0
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN git clone --branch ${DATA_BRANCH} --depth 1 ${DATA_REPOSITORY}
|
||||
|
||||
# Result Container
|
||||
FROM amazoncorretto:17-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy built assets
|
||||
COPY --from=builder /app/grasscutter-*.jar /app/grasscutter.jar
|
||||
COPY --from=builder /app/keystore.p12 /app/keystore.p12
|
||||
|
||||
# Copy the resources
|
||||
COPY --from=data /app/GC-Resources/Resources /app/resources/
|
||||
|
||||
# Copy startup files
|
||||
COPY ./entrypoint.sh /app/
|
||||
|
||||
CMD [ "sh", "/app/entrypoint.sh" ]
|
||||
|
||||
EXPOSE 80 443 8888 22102
|
||||
@@ -24,9 +24,11 @@
|
||||
|
||||
### 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 (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
|
||||
- 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)
|
||||
|
||||
- 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.
|
||||
@@ -38,7 +40,7 @@
|
||||
|
||||
- Click the small button next to launch.
|
||||
- Click the launch button.
|
||||
- Log in with whatever username you want. Password doesn't matter.
|
||||
- Log in with whatever username you want. Password can be anything.
|
||||
|
||||
### Building
|
||||
|
||||
|
||||
@@ -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) | [简中](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)
|
||||
[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)
|
||||
|
||||
**ध्यान:** हम हमेशा परियोजना में योगदानकर्ताओं का स्वागत करते हैं।. अपना योगदान जोड़ने से पहले कृपया हमारा ध्यानपूर्वक पढ़ें [आचार संहिता](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) और सपोर्ट चैनल पर जाएं.
|
||||
|
||||
+19
-5
@@ -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) | [简中](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)
|
||||
[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)
|
||||
|
||||
|
||||
**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のクライアントを持っていない場合は右のリンクからダウンロード): https://github.com/MAnggiarMustofa/GI-Download-Library/blob/main/GenshinImpact/Client/4.0.0.md
|
||||
- ゲームバージョンが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)
|
||||
- [最新の Cultivation](https://github.com/Grasscutters/Cultivation/releases/latest)をダウンロードする。`.msi`インストーラを使ってください。
|
||||
- 管理者権限を付与して Cultivation を実行した後、右上端にあるダウンロードアイコンのボタンを押す。
|
||||
- `Download All-in-One` をクリックする
|
||||
@@ -35,10 +35,9 @@
|
||||
- `Game Install Path` にゲームファイルのパスを指定する。
|
||||
- `Custom Java Path` に、自分が用意したJavaのパスを指定する。 (例: `C:\Program Files\Java\jdk-17\bin\java.exe`)
|
||||
- その他の設定には手を付けず次の段階に進む。
|
||||
|
||||
- Launch の隣にある小さいボタンを押す。
|
||||
- Launchボタンを押す
|
||||
- 好きなユーザ名でログインする。パスワードは特段気にすることはない。
|
||||
- 好きなユーザ名でログインする。ログインに関する設定がデフォルトの場合、パスワードは何を入れてもいい。
|
||||
|
||||
|
||||
### ビルド
|
||||
@@ -79,7 +78,22 @@ chmod +x gradlew
|
||||
./gradlew jar # コンパイル
|
||||
```
|
||||
|
||||
生成されたjarファイルはプロジェクトフォルダのルートにあります。
|
||||
##### 手動によるハンドブックの生成
|
||||
|
||||
Gradleを使用する場合:
|
||||
```shell
|
||||
./gradlew generateHandbook
|
||||
```
|
||||
|
||||
NPMを使用する場合:
|
||||
```shell
|
||||
cd src/handbook
|
||||
npm install
|
||||
npm run build
|
||||
```
|
||||
|
||||
|
||||
生成されたjarファイルはプロジェクトのルートフォルダにあります。
|
||||
|
||||
### トラブルシューティング
|
||||
|
||||
|
||||
@@ -26,7 +26,9 @@
|
||||
|
||||
- 获取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的客户端,可以在这里找到):https://github.com/MAnggiarMustofa/GI-Download-Library/blob/main/GenshinImpact/Client/4.0.0.md)
|
||||
- 获取游戏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)
|
||||
|
||||
- 下载[最新的Cultivation版本](https://github.com/Grasscutters/Cultivation/releases/latest)(使用以“.msi”为后缀的安装包)。
|
||||
- 以管理员身份打开Cultivation,按右上角的下载按钮。
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
#/bin/sh
|
||||
|
||||
java -jar /app/grasscutter.jar
|
||||
@@ -3,8 +3,7 @@ package emu.grasscutter;
|
||||
import emu.grasscutter.game.world.Position;
|
||||
import emu.grasscutter.utils.Utils;
|
||||
import emu.grasscutter.utils.objects.SparseSet;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.*;
|
||||
|
||||
public final class GameConstants {
|
||||
public static String VERSION = "4.0.0";
|
||||
@@ -60,4 +59,23 @@ public final class GameConstants {
|
||||
public static final int[] DEFAULT_ABILITY_HASHES =
|
||||
Arrays.stream(DEFAULT_ABILITY_STRINGS).mapToInt(Utils::abilityHash).toArray();
|
||||
public static final int DEFAULT_ABILITY_NAME = Utils.abilityHash("Default");
|
||||
public static final Map<Integer, Integer> YAE_MIKO_ITEM_TO_REGION_COMBINE_BONUS = new HashMap<>() {{
|
||||
put(104304, 1);
|
||||
put(104307, 1);
|
||||
put(104310, 2);
|
||||
put(104313, 2);
|
||||
put(104316, 2);
|
||||
put(104320, 3);
|
||||
put(104323, 3);
|
||||
put(104326, 3);
|
||||
put(104329, 4);
|
||||
put(104332, 4);
|
||||
put(104335, 4);
|
||||
}};
|
||||
public static final Map<Integer, List<Integer>> YAE_MIKO_REGION_TO_ITEM_COMBINE_BONUS = new HashMap<>() {{
|
||||
put(1, List.of(104304, 104307));
|
||||
put(2, List.of(104310, 104313, 104316));
|
||||
put(3, List.of(104320, 104323, 104326));
|
||||
put(4, List.of(104329, 104332, 104335));
|
||||
}};
|
||||
}
|
||||
|
||||
@@ -17,8 +17,10 @@ public final class StopCommand implements CommandHandler {
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
CommandHandler.sendMessage(null, translate("commands.stop.success"));
|
||||
for (Player p : Grasscutter.getGameServer().getPlayers().values()) {
|
||||
CommandHandler.sendMessage(p, translate(p, "commands.stop.success"));
|
||||
if (Grasscutter.getGameServer() != null) {
|
||||
for (Player p : Grasscutter.getGameServer().getPlayers().values()) {
|
||||
CommandHandler.sendMessage(p, translate(p, "commands.stop.success"));
|
||||
}
|
||||
}
|
||||
|
||||
System.exit(1000);
|
||||
|
||||
@@ -140,6 +140,7 @@ public class ConfigContainer {
|
||||
public boolean autoCreate = false;
|
||||
public boolean EXPERIMENTAL_RealPassword = false;
|
||||
public String[] defaultPermissions = {};
|
||||
public String playerEmail = "grasscutter.io";
|
||||
public int maxPlayer = -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -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() + "@grasscutter.io";
|
||||
return this.getUsername() + "@" + ACCOUNT.playerEmail;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,7 +235,7 @@ public class Account {
|
||||
this.addPermission("*");
|
||||
}
|
||||
|
||||
// Set account default language as server default language
|
||||
// Set account default language to server default language
|
||||
if (!document.containsKey("locale")) {
|
||||
this.locale = LANGUAGE;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package emu.grasscutter.game.combine;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter @Setter
|
||||
public class CombineBonusData {
|
||||
private int avatarId;
|
||||
private int combineType;
|
||||
private BonusType bonusType;
|
||||
private List<Double> paramVec;
|
||||
|
||||
public enum BonusType {
|
||||
COMBINE_BONUS_DOUBLE,
|
||||
COMBINE_BONUS_REFUND,
|
||||
COMBINE_BONUS_REFUND_RANDOM,
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
package emu.grasscutter.game.combine;
|
||||
|
||||
import emu.grasscutter.GameConstants;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.*;
|
||||
import emu.grasscutter.data.common.ItemParamData;
|
||||
import emu.grasscutter.data.excels.CombineData;
|
||||
import emu.grasscutter.game.avatar.Avatar;
|
||||
import emu.grasscutter.game.inventory.GameItem;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.ActionReason;
|
||||
@@ -12,15 +14,26 @@ import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode;
|
||||
import emu.grasscutter.server.game.*;
|
||||
import emu.grasscutter.server.packet.send.*;
|
||||
import emu.grasscutter.utils.Utils;
|
||||
import io.netty.util.internal.ThreadLocalRandom;
|
||||
import it.unimi.dsi.fastutil.ints.*;
|
||||
import java.util.*;
|
||||
|
||||
public class CombineManger extends BaseGameSystem {
|
||||
private static final Int2ObjectMap<List<Integer>> reliquaryDecomposeData =
|
||||
new Int2ObjectOpenHashMap<>();
|
||||
private final Int2ObjectMap<CombineBonusData> combineBonusData = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
public CombineManger(GameServer server) {
|
||||
super(server);
|
||||
|
||||
// load combine bonus data
|
||||
try {
|
||||
DataLoader.loadList("CombineBonus.json", CombineBonusData.class)
|
||||
.forEach(entry -> combineBonusData.put(entry.getAvatarId(), entry));
|
||||
} catch (Exception ignored) {
|
||||
Grasscutter.getLogger()
|
||||
.error("Unable to load combine bonus data. Please place CombineBonus.json in the data folder.");
|
||||
}
|
||||
}
|
||||
|
||||
public static void initialize() {
|
||||
@@ -47,7 +60,7 @@ public class CombineManger extends BaseGameSystem {
|
||||
return true;
|
||||
}
|
||||
|
||||
public CombineResult combineItem(Player player, int cid, int count) {
|
||||
public CombineResult combineItem(Player player, int cid, int count, long avatarGuid) {
|
||||
// check config exist
|
||||
if (!GameData.getCombineDataMap().containsKey(cid)) {
|
||||
player.getWorld().getHost().sendPacket(new PacketCombineRsp());
|
||||
@@ -81,11 +94,104 @@ public class CombineManger extends BaseGameSystem {
|
||||
result.setMaterial(List.of());
|
||||
result.setResult(
|
||||
List.of(
|
||||
new ItemParamData(
|
||||
combineData.getResultItemId(), combineData.getResultItemCount() * count)));
|
||||
// TODO lucky characters
|
||||
result.setExtra(List.of());
|
||||
result.setBack(List.of());
|
||||
new ItemParamData(combineData.getResultItemId(), combineData.getResultItemCount())));
|
||||
// lucky characters
|
||||
int luckyCount = 0;
|
||||
Avatar avatar = player.getAvatars().getAvatarByGuid(avatarGuid);
|
||||
CombineBonusData combineBonusAvatar = combineBonusData.get(avatar.getAvatarId());
|
||||
if (combineBonusAvatar != null
|
||||
&& combineData.getCombineType() == combineBonusAvatar.getCombineType()) {
|
||||
double luckyChange = combineBonusAvatar.getParamVec().get(0);
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (ThreadLocalRandom.current().nextDouble() <= luckyChange) {
|
||||
luckyCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.setExtra(new ArrayList<ItemParamData>());
|
||||
result.setBack(new ArrayList<ItemParamData>());
|
||||
result.setRandom(new ArrayList<ItemParamData>());
|
||||
|
||||
// add lucky items
|
||||
if (luckyCount > 0) {
|
||||
switch (combineBonusAvatar.getBonusType()) {
|
||||
case COMBINE_BONUS_DOUBLE -> {
|
||||
var combineExtra = new ItemParamData(combineData.getResultItemId(), luckyCount);
|
||||
player.getInventory().addItem(combineExtra);
|
||||
result.getExtra().add(combineExtra);
|
||||
}
|
||||
case COMBINE_BONUS_REFUND -> {
|
||||
if (combineData.getMaterialItems().size() == 1) {
|
||||
var combineBack = new ItemParamData(combineData.getMaterialItems().get(0).getItemId(),
|
||||
luckyCount);
|
||||
player.getInventory().addItem(combineBack);
|
||||
result.getBack().add(combineBack);
|
||||
} else {
|
||||
Map<Integer, Integer> mapIdCount = new HashMap<>();
|
||||
for (int i = 0; i < luckyCount; i++) {
|
||||
var randomId = combineData
|
||||
.getMaterialItems()
|
||||
.get(
|
||||
ThreadLocalRandom.current()
|
||||
.nextInt(combineData.getMaterialItems().size()))
|
||||
.getItemId();
|
||||
mapIdCount.put(randomId, mapIdCount.getOrDefault(randomId, 0) + 1);
|
||||
}
|
||||
|
||||
for (var entry : mapIdCount.entrySet()) {
|
||||
var combineBack = new ItemParamData(entry.getKey(), entry.getValue());
|
||||
player.getInventory().addItem(combineBack);
|
||||
result.getBack().add(combineBack);
|
||||
}
|
||||
}
|
||||
}
|
||||
case COMBINE_BONUS_REFUND_RANDOM -> {
|
||||
// for yae miko, "Has a 25% chance to get 1 regional Character Talent Material
|
||||
// (base
|
||||
// material excluded) when crafting. The rarity is that of the base material."
|
||||
// from wiki
|
||||
// map of material id to region id
|
||||
Map<Integer, Integer> itemToRegion = GameConstants.YAE_MIKO_ITEM_TO_REGION_COMBINE_BONUS;
|
||||
|
||||
// get list of material id with every region
|
||||
Map<Integer, List<Integer>> regionToId = GameConstants.YAE_MIKO_REGION_TO_ITEM_COMBINE_BONUS;
|
||||
|
||||
// check material id in itemToRegion
|
||||
int itemId = combineData.getMaterialItems().get(0).getItemId();
|
||||
int rank = 0; // rank of material
|
||||
if (itemToRegion.get(itemId) != null)
|
||||
rank = 1;
|
||||
if (itemToRegion.get(itemId - 1) != null) {
|
||||
rank = 2;
|
||||
itemId -= 1;
|
||||
}
|
||||
|
||||
if (rank >= 1) { // if material is regional
|
||||
// get list of material id with same region
|
||||
List<Integer> listIdRandom = regionToId.get(itemToRegion.get(itemId));
|
||||
// remove material id from array
|
||||
listIdRandom.remove(Integer.valueOf(itemId));
|
||||
|
||||
HashMap<Integer, Integer> mapIdCount = new HashMap<>();
|
||||
// pick random material from list with luckyCount
|
||||
for (int i = 0; i < luckyCount; i++) {
|
||||
int randomId = listIdRandom.get(ThreadLocalRandom.current().nextInt(listIdRandom.size()));
|
||||
mapIdCount.put(randomId, mapIdCount.getOrDefault(randomId, 0) + 1);
|
||||
}
|
||||
|
||||
// add to random list
|
||||
for (var entry : mapIdCount.entrySet()) {
|
||||
// if rank 2, add 1 to material id
|
||||
var combineRandom = new ItemParamData(
|
||||
(rank == 2) ? entry.getKey() + 1 : entry.getKey(), entry.getValue());
|
||||
player.getInventory().addItem(combineRandom);
|
||||
result.getRandom().add(combineRandom);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -2,42 +2,14 @@ package emu.grasscutter.game.combine;
|
||||
|
||||
import emu.grasscutter.data.common.ItemParamData;
|
||||
import java.util.List;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Setter @Getter
|
||||
public class CombineResult {
|
||||
private List<ItemParamData> material;
|
||||
private List<ItemParamData> result;
|
||||
private List<ItemParamData> extra;
|
||||
private List<ItemParamData> back;
|
||||
|
||||
public List<ItemParamData> getMaterial() {
|
||||
return material;
|
||||
}
|
||||
|
||||
public void setMaterial(List<ItemParamData> material) {
|
||||
this.material = material;
|
||||
}
|
||||
|
||||
public List<ItemParamData> getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setResult(List<ItemParamData> result) {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public List<ItemParamData> getExtra() {
|
||||
return extra;
|
||||
}
|
||||
|
||||
public void setExtra(List<ItemParamData> extra) {
|
||||
this.extra = extra;
|
||||
}
|
||||
|
||||
public List<ItemParamData> getBack() {
|
||||
return back;
|
||||
}
|
||||
|
||||
public void setBack(List<ItemParamData> back) {
|
||||
this.back = back;
|
||||
}
|
||||
private List<ItemParamData> random;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ public class WorldChallenge {
|
||||
private final AtomicInteger score;
|
||||
private boolean progress;
|
||||
private boolean success;
|
||||
private long startedAt;
|
||||
private int startedAt;
|
||||
private int finishedTime;
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -36,6 +36,6 @@ public class KillMonsterCountInTimeIncChallengeFactoryHandler implements Challen
|
||||
List.of(
|
||||
new KillMonsterCountTrigger(),
|
||||
new InTimeTrigger(),
|
||||
new KillMonsterTimeIncTrigger(timeInc)));
|
||||
new KillMonsterTimeIncTrigger(timeLimit, timeInc)));
|
||||
}
|
||||
}
|
||||
|
||||
+13
-2
@@ -1,11 +1,12 @@
|
||||
package emu.grasscutter.game.dungeons.challenge.factory;
|
||||
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
||||
import emu.grasscutter.game.dungeons.challenge.enums.ChallengeType;
|
||||
import emu.grasscutter.game.dungeons.challenge.trigger.*;
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.scripts.data.SceneGroup;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import lombok.val;
|
||||
|
||||
public class KillMonsterTimeChallengeFactoryHandler implements ChallengeFactoryHandler {
|
||||
@@ -28,6 +29,16 @@ public class KillMonsterTimeChallengeFactoryHandler implements ChallengeFactoryH
|
||||
Scene scene,
|
||||
SceneGroup group) {
|
||||
val realGroup = scene.getScriptManager().getGroupById(groupId);
|
||||
val challengeTriggers = new ArrayList<ChallengeTrigger>();
|
||||
challengeTriggers.addAll(List.of(new KillMonsterCountTrigger(), new InTimeTrigger()));
|
||||
|
||||
val challengeData = GameData.getDungeonChallengeConfigDataMap().get(challengeId);
|
||||
val challengeType = challengeData.getChallengeType();
|
||||
if (challengeType == ChallengeType.CHALLENGE_KILL_COUNT_FAST) {
|
||||
challengeTriggers.add(
|
||||
new KillMonsterTimeIncTrigger(timeLimit, 0 /* refresh to original limit on kill */));
|
||||
}
|
||||
|
||||
return new WorldChallenge(
|
||||
scene,
|
||||
realGroup,
|
||||
@@ -36,6 +47,6 @@ public class KillMonsterTimeChallengeFactoryHandler implements ChallengeFactoryH
|
||||
List.of(targetCount, timeLimit),
|
||||
timeLimit, // Limit
|
||||
targetCount, // Goal
|
||||
List.of(new KillMonsterCountTrigger(), new InTimeTrigger()));
|
||||
challengeTriggers);
|
||||
}
|
||||
}
|
||||
|
||||
+19
-8
@@ -6,22 +6,33 @@ import emu.grasscutter.server.packet.send.PacketChallengeDataNotify;
|
||||
|
||||
public class KillMonsterTimeIncTrigger extends ChallengeTrigger {
|
||||
|
||||
private int increment;
|
||||
private final int maxTime;
|
||||
private final int increment;
|
||||
|
||||
public KillMonsterTimeIncTrigger(int increment) {
|
||||
public KillMonsterTimeIncTrigger(int maxTime, int increment) {
|
||||
this.maxTime = maxTime;
|
||||
this.increment = increment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBegin(WorldChallenge challenge) {
|
||||
// challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 0,
|
||||
// challenge.getScore().get()));
|
||||
}
|
||||
public void onBegin(WorldChallenge challenge) {}
|
||||
|
||||
@Override
|
||||
public void onMonsterDeath(WorldChallenge challenge, EntityMonster monster) {
|
||||
challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 0, increment));
|
||||
|
||||
var scene = challenge.getScene();
|
||||
var elapsed = scene.getSceneTimeSeconds() - challenge.getStartedAt();
|
||||
var timeLeft = challenge.getTimeLimit() - elapsed;
|
||||
var increment = this.increment;
|
||||
if (increment == 0) {
|
||||
// Refresh time limit back to max
|
||||
increment = maxTime - timeLeft;
|
||||
} else if (maxTime < timeLeft + increment) {
|
||||
// Don't add back more time than original limit
|
||||
increment -= timeLeft + increment - maxTime;
|
||||
}
|
||||
challenge.setTimeLimit(challenge.getTimeLimit() + increment);
|
||||
scene.broadcastPacket(
|
||||
new PacketChallengeDataNotify(
|
||||
challenge, 2, timeLeft + increment + scene.getSceneTimeSeconds()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,7 +222,9 @@ public class EntityMonster extends GameEntity {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
public void onTick(int sceneTime) {
|
||||
super.onTick(sceneTime);
|
||||
|
||||
// Lua event
|
||||
getScene()
|
||||
.getScriptManager()
|
||||
|
||||
@@ -218,6 +218,8 @@ 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>
|
||||
""");
|
||||
|
||||
@@ -20,7 +20,11 @@ public class HandlerCombineReq extends PacketHandler {
|
||||
session
|
||||
.getServer()
|
||||
.getCombineSystem()
|
||||
.combineItem(session.getPlayer(), req.getCombineId(), req.getCombineCount());
|
||||
.combineItem(
|
||||
session.getPlayer(),
|
||||
req.getCombineId(),
|
||||
req.getCombineCount(),
|
||||
req.getAvatarGuid());
|
||||
|
||||
if (result == null) {
|
||||
return;
|
||||
@@ -33,7 +37,7 @@ public class HandlerCombineReq extends PacketHandler {
|
||||
toItemParamList(result.getResult()),
|
||||
toItemParamList(result.getExtra()),
|
||||
toItemParamList(result.getBack()),
|
||||
toItemParamList(result.getBack())));
|
||||
toItemParamList(result.getRandom())));
|
||||
}
|
||||
|
||||
private List<ItemParamOuterClass.ItemParam> toItemParamList(List<ItemParamData> list) {
|
||||
|
||||
Reference in New Issue
Block a user