CookingManager.java 5.93 KB
Newer Older
1
2
3
4
5
6
7
8
9
package emu.grasscutter.game.managers;

import java.util.ArrayList;
import java.util.Dictionary;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import emu.grasscutter.data.GameData;
10
11
12
import emu.grasscutter.data.common.ItemParamData;
import emu.grasscutter.data.excels.ItemData;
import emu.grasscutter.game.inventory.GameItem;
13
import emu.grasscutter.game.player.Player;
14
import emu.grasscutter.game.props.ActionReason;
15
import emu.grasscutter.net.proto.CookRecipeDataOuterClass;
16
17
18
import emu.grasscutter.net.proto.PlayerCookArgsReqOuterClass.PlayerCookArgsReq;
import emu.grasscutter.net.proto.PlayerCookReqOuterClass.PlayerCookReq;
import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode;
19
import emu.grasscutter.server.packet.send.PacketCookDataNotify;
20
21
22
import emu.grasscutter.server.packet.send.PacketCookRecipeDataNotify;
import emu.grasscutter.server.packet.send.PacketPlayerCookArgsRsp;
import emu.grasscutter.server.packet.send.PacketPlayerCookRsp;
23
24

public class CookingManager {
25
26
    private static final int MANUAL_PERFECT_COOK_QUALITY = 3;

27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
    private static Set<Integer> defaultUnlockedRecipies;
    private final Player player;

    public CookingManager(Player player) {
        this.player = player;
    }

    public static void initialize() {
        // Initialize the set of recipies that are unlocked by default.
        defaultUnlockedRecipies = new HashSet<>();

        for (var recipe : GameData.getCookRecipeDataMap().values()) {
            if (recipe.isDefaultUnlocked()) {
                defaultUnlockedRecipies.add(recipe.getId());
            }
        }
    }

45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
    /********************
     * Unlocking for recipies.
     ********************/
    public synchronized boolean unlockRecipe(GameItem recipeItem) {
		// Make sure this is actually a cooking recipe.
		if (!recipeItem.getItemData().getItemUse().get(0).getUseOp().equals("ITEM_USE_UNLOCK_COOK_RECIPE")) {
			return false;
		}

		// Determine the recipe we should unlock.
		int recipeId = Integer.parseInt(recipeItem.getItemData().getItemUse().get(0).getUseParam().get(0));

		// Remove the item from the player's inventory.
		// We need to do this here, before sending CookRecipeDataNotify, or the the UI won't correctly update.
		player.getInventory().removeItem(recipeItem, 1);

		// Tell the client that this blueprint is now unlocked and add the unlocked item to the player.
		this.player.getUnlockedRecipies().put(recipeId, 0);
		this.player.sendPacket(new PacketCookRecipeDataNotify(recipeId));

		return true;
	}

68
69
70
    /********************
     * Perform cooking.
     ********************/
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
    public void handlePlayerCookReq(PlayerCookReq req) {
        // Get info from the request.
        int recipeId = req.getRecipeId();
        int quality = req.getQteQuality();
        int count = req.getCookCount();

        // Get recipe data.
        var recipeData = GameData.getCookRecipeDataMap().get(recipeId);
        if (recipeData == null) {
            this.player.sendPacket(new PacketPlayerCookRsp(Retcode.RET_FAIL));
            return;
        }

        // Get proficiency for player.
        int proficiency = this.player.getUnlockedRecipies().getOrDefault(recipeId, 0);

        // Try consuming materials.
		boolean success = player.getInventory().payItems(recipeData.getInputVec().toArray(new ItemParamData[0]), count, ActionReason.Cook);
		if (!success) {
			this.player.sendPacket(new PacketPlayerCookRsp(Retcode.RET_FAIL)); //ToDo: Probably the wrong return code.
		}

        // Obtain results.
        int qualityIndex = 
            quality == 0 
            ? 2 
            : quality - 1;

        ItemParamData resultParam = recipeData.getQualityOutputVec().get(qualityIndex);
        ItemData resultItemData = GameData.getItemDataMap().get(resultParam.getItemId());

		GameItem cookResult = new GameItem(resultItemData, resultParam.getCount() * count);
		this.player.getInventory().addItem(cookResult);

        // Increase player proficiency, if this was a manual perfect cook.
        if (quality == MANUAL_PERFECT_COOK_QUALITY) {
            proficiency = Math.min(proficiency + 1, recipeData.getMaxProficiency());
            this.player.getUnlockedRecipies().put(recipeId, proficiency);
        }

        // Send response.
        this.player.sendPacket(new PacketPlayerCookRsp(cookResult, quality, count, recipeId, proficiency));
    }


    /********************
     * Cooking arguments.
     ********************/
    public void handleCookArgsReq(PlayerCookArgsReq req) {
        this.player.sendPacket(new PacketPlayerCookArgsRsp());
    }
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163

     /********************
     * Notify unlocked recipies.
     ********************/
    private void addDefaultUnlocked() {
        // Get recipies that are already unlocked.
        var unlockedRecipies = this.player.getUnlockedRecipies();

        // Get recipies that should be unlocked by default but aren't.
        var additionalRecipies = new HashSet<>(defaultUnlockedRecipies);
        additionalRecipies.removeAll(unlockedRecipies.keySet());

        // Add them to the player.
        for (int id : additionalRecipies) {
            unlockedRecipies.put(id, 0);
        }
    }

    public void sendCookDataNofity() {
        // Default unlocked recipies to player if they don't have them yet.
        this.addDefaultUnlocked();

        // Get unlocked recipies.
        var unlockedRecipies = this.player.getUnlockedRecipies();

        // Construct CookRecipeData protos.
        List<CookRecipeDataOuterClass.CookRecipeData> data = new ArrayList<>();
        for (var recipe : unlockedRecipies.entrySet()) {
            int recipeId = recipe.getKey();
            int proficiency = recipe.getValue();

            CookRecipeDataOuterClass.CookRecipeData proto = CookRecipeDataOuterClass.CookRecipeData.newBuilder()
                .setRecipeId(recipeId)
                .setProficiency(proficiency)
                .build();
            data.add(proto);
        }

        // Send packet.
        this.player.sendPacket(new PacketCookDataNotify(data));
    }
}