GachaBanner.java 8.88 KB
Newer Older
Melledy's avatar
Melledy committed
1
2
package emu.grasscutter.game.gacha;

3
4
import static emu.grasscutter.config.Configuration.*;

5
import emu.grasscutter.Grasscutter;
6
import emu.grasscutter.data.common.ItemParamData;
CamChua_VN's avatar
CamChua_VN committed
7
import emu.grasscutter.game.player.Player;
Melledy's avatar
Melledy committed
8
9
import emu.grasscutter.net.proto.GachaInfoOuterClass.GachaInfo;
import emu.grasscutter.net.proto.GachaUpInfoOuterClass.GachaUpInfo;
AnimeGitB's avatar
AnimeGitB committed
10
import emu.grasscutter.utils.Utils;
11
import lombok.Getter;
Melledy's avatar
Melledy committed
12
13

public class GachaBanner {
github-actions's avatar
github-actions committed
14
15
16
    @Getter private int gachaType;
    @Getter private int scheduleId;
    @Getter private String prefabPath;
17
    @Getter private String previewPrefabPath;
github-actions's avatar
github-actions committed
18
19
20
21
22
23
24
25
26
    @Getter private String titlePath;
    private int costItemId = 0;
    private int costItemAmount = 1;
    private int costItemId10 = 0;
    private int costItemAmount10 = 10;
    @Getter private int beginTime;
    @Getter private int endTime;
    @Getter private int sortId;
    @Getter private int gachaTimesLimit = Integer.MAX_VALUE;
27
28
    @Getter private int[] rateUpItems4 = {};
    @Getter private int[] rateUpItems5 = {};
github-actions's avatar
github-actions committed
29
    @Getter private int[] fallbackItems3 = {11301, 11302, 11306, 12301, 12302, 12305, 13303, 14301, 14302, 14304, 15301, 15302, 15304};
30
    @Getter private int[] fallbackItems4Pool1 = {1014, 1020, 1023, 1024, 1025, 1027, 1031, 1032, 1034, 1036, 1039, 1043, 1044, 1045, 1048, 1053, 1055, 1056, 1059, 1064, 1065, 1067, 1068, 1072};
github-actions's avatar
github-actions committed
31
    @Getter private int[] fallbackItems4Pool2 = {11401, 11402, 11403, 11405, 12401, 12402, 12403, 12405, 13401, 13407, 14401, 14402, 14403, 14409, 15401, 15402, 15403, 15405};
32
    @Getter private int[] fallbackItems5Pool1 = {1003, 1016, 1042, 1035, 1041, 1069};
github-actions's avatar
github-actions committed
33
34
35
36
37
38
39
40
41
42
43
44
    @Getter private int[] fallbackItems5Pool2 = {11501, 11502, 12501, 12502, 13502, 13505, 14501, 14502, 15501, 15502};
    @Getter private boolean removeC6FromPool = false;
    @Getter private boolean autoStripRateUpFromFallback = true;
    private int[][] weights4 = {{1,510}, {8,510}, {10,10000}};
    private int[][] weights5 = {{1,75}, {73,150}, {90,10000}};
    private int[][] poolBalanceWeights4 = {{1,255}, {17,255}, {21,10455}};
    private int[][] poolBalanceWeights5 = {{1,30}, {147,150}, {181,10230}};
    private int eventChance4 = 50; // Chance to win a featured event item
    private int eventChance5 = 50; // Chance to win a featured event item
    @Getter private BannerType bannerType = BannerType.STANDARD;
    @Getter private int wishMaxProgress = 2;

45
46
47
48
49
50
51
52
53
54
    // Deprecated fields that were tolerated in early May 2022 but have apparently still being circulating in new custom configs
    // For now, throw up big scary errors on load telling people that they will be banned outright in a future version
    @Deprecated private int[] rateUpItems1 = {};
    @Deprecated private int[] rateUpItems2 = {};
    @Deprecated private int eventChance = -1;
    @Deprecated private int costItem = 0;
    @Deprecated private int softPity = -1;
    @Deprecated private int hardPity = -1;
    @Deprecated private int minItemType = -1;
    @Deprecated private int maxItemType = -1;
55
    @Getter private boolean deprecated = false;
56

57
58
59
    private void warnDeprecated(String name, String replacement) {
        Grasscutter.getLogger().error("Deprecated field found in Banners config: "+name+" was replaced back in early May 2022, use "+replacement+" instead. You MUST remove this field from your config.");
        this.deprecated = true;
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
    }
    public void onLoad() {
        if (eventChance != -1)
            warnDeprecated("eventChance", "eventChance4 & eventChance5");
        if (costItem != 0)
            warnDeprecated("costItem", "costItemId");
        if (softPity != -1)
            warnDeprecated("softPity", "weights5");
        if (hardPity != -1)
            warnDeprecated("hardPity", "weights5");
        if (minItemType != -1)
            warnDeprecated("minItemType", "fallbackItems[4,5]Pool[1,2]");
        if (maxItemType != -1)
            warnDeprecated("maxItemType", "fallbackItems[4,5]Pool[1,2]");
        if (rateUpItems1.length > 0)
            warnDeprecated("rateUpItems1", "rateUpItems5");
        if (rateUpItems2.length > 0)
            warnDeprecated("rateUpItems2", "rateUpItems4");
78
79
80
81
82
83
        if (this.previewPrefabPath != null && this.previewPrefabPath.equals("UI_Tab_" + this.prefabPath))
            Grasscutter.getLogger().error("Redundant field found in Banners config: previewPrefabPath does not need to be specified if it is identical to prefabPath prefixed with \"UI_Tab_\".");
        if (this.previewPrefabPath == null || this.previewPrefabPath.isEmpty())
            this.previewPrefabPath = "UI_Tab_" + this.prefabPath;
        if (this.costItemId10 == 0)
            this.costItemId10 = this.costItemId;
AnimeGitB's avatar
AnimeGitB committed
84
85
    }

github-actions's avatar
github-actions committed
86
87
    public ItemParamData getCost(int numRolls) {
        return switch (numRolls) {
88
89
            case 10 -> new ItemParamData(costItemId10, costItemAmount10);
            default -> new ItemParamData(costItemId, costItemAmount * numRolls);
github-actions's avatar
github-actions committed
90
91
92
        };
    }

93
    @Deprecated
github-actions's avatar
github-actions committed
94
    public int getCostItem() {
95
        return costItemId;
github-actions's avatar
github-actions committed
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
    }

    public boolean hasEpitomized() {
        return bannerType.equals(BannerType.WEAPON);
    }

    public int getWeight(int rarity, int pity) {
        return switch (rarity) {
            case 4 -> Utils.lerp(pity, weights4);
            default -> Utils.lerp(pity, weights5);
        };
    }

    public int getPoolBalanceWeight(int rarity, int pity) {
        return switch (rarity) {
            case 4 -> Utils.lerp(pity, poolBalanceWeights4);
            default -> Utils.lerp(pity, poolBalanceWeights5);
        };
    }

    public int getEventChance(int rarity) {
        return switch (rarity) {
            case 4 -> eventChance4;
119
            default -> eventChance5;
github-actions's avatar
github-actions committed
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
        };
    }

    public GachaInfo toProto(Player player) {
        // TODO: use other Nonce/key insteadof session key to ensure the overall security for the player
        String sessionKey = player.getAccount().getSessionKey();

        String record = "http" + (HTTP_ENCRYPTION.useInRouting ? "s" : "") + "://"
                        + lr(HTTP_INFO.accessAddress, HTTP_INFO.bindAddress) + ":"
                        + lr(HTTP_INFO.accessPort, HTTP_INFO.bindPort)
                        + "/gacha?s=" + sessionKey + "&gachaType=" + gachaType;
        String details = "http" + (HTTP_ENCRYPTION.useInRouting ? "s" : "") + "://"
                        + lr(HTTP_INFO.accessAddress, HTTP_INFO.bindAddress) + ":"
                        + lr(HTTP_INFO.accessPort, HTTP_INFO.bindPort)
                        + "/gacha/details?s=" + sessionKey + "&scheduleId=" + scheduleId;

        // Grasscutter.getLogger().info("record = " + record);
        PlayerGachaBannerInfo gachaInfo = player.getGachaInfo().getBannerInfo(this);
        int leftGachaTimes = switch (gachaTimesLimit) {
            case Integer.MAX_VALUE -> Integer.MAX_VALUE;
            default -> Math.max(gachaTimesLimit - gachaInfo.getTotalPulls(), 0);
        };
        GachaInfo.Builder info = GachaInfo.newBuilder()
                .setGachaType(this.getGachaType())
                .setScheduleId(this.getScheduleId())
                .setBeginTime(this.getBeginTime())
                .setEndTime(this.getEndTime())
147
148
149
150
                .setCostItemId(this.costItemId)
                .setCostItemNum(this.costItemAmount)
                .setTenCostItemId(this.costItemId10)
                .setTenCostItemNum(this.costItemAmount10)
github-actions's avatar
github-actions committed
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
                .setGachaPrefabPath(this.getPrefabPath())
                .setGachaPreviewPrefabPath(this.getPreviewPrefabPath())
                .setGachaProbUrl(details)
                .setGachaProbUrlOversea(details)
                .setGachaRecordUrl(record)
                .setGachaRecordUrlOversea(record)
                .setLeftGachaTimes(leftGachaTimes)
                .setGachaTimesLimit(gachaTimesLimit)
                .setGachaSortId(this.getSortId());

        if (hasEpitomized()) {
            info.setWishItemId(gachaInfo.getWishItemId())
                .setWishProgress(gachaInfo.getFailedChosenItemPulls())
                .setWishMaxProgress(this.getWishMaxProgress());
        }

        if (this.getTitlePath() != null) {
            info.setTitleTextmap(this.getTitlePath());
        }

        if (this.getRateUpItems5().length > 0) {
            GachaUpInfo.Builder upInfo = GachaUpInfo.newBuilder().setItemParentType(1);

            for (int id : getRateUpItems5()) {
                upInfo.addItemIdList(id);
                info.addDisplayUp5ItemList(id);
            }

            info.addGachaUpInfoList(upInfo);
        }

        if (this.getRateUpItems4().length > 0) {
            GachaUpInfo.Builder upInfo = GachaUpInfo.newBuilder().setItemParentType(2);

            for (int id : getRateUpItems4()) {
                upInfo.addItemIdList(id);
                if (info.getDisplayUp4ItemListCount() == 0) {
                    info.addDisplayUp4ItemList(id);
                }
            }

            info.addGachaUpInfoList(upInfo);
        }

        return info.build();
    }

    public enum BannerType {
        STANDARD, EVENT, WEAPON;
    }
Melledy's avatar
Melledy committed
201
}