mirror of
https://github.com/Melledy/Grasscutter.git
synced 2024-11-26 15:39:37 +00:00
official shop support
This commit is contained in:
parent
027bd28afb
commit
0559cc4e0b
@ -72,6 +72,7 @@ public final class Config {
|
||||
public boolean WatchGacha = false;
|
||||
public int[] WelcomeEmotes = {2007, 1002, 4010};
|
||||
public String WelcomeMotd = "Welcome to Grasscutter emu";
|
||||
public boolean EnableOfficialShop = true;
|
||||
|
||||
public GameRates Game = new GameRates();
|
||||
|
||||
|
@ -61,9 +61,12 @@ public class GameData {
|
||||
private static final Int2ObjectMap<FetterCharacterCardData> fetterCharacterCardDataMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<RewardData> rewardDataMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<WorldLevelData> worldLevelDataMap = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
private static final Int2ObjectMap<ShopGoodsData> shopGoodsDataMap = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
// Cache
|
||||
private static Map<Integer, List<Integer>> fetters = new HashMap<>();
|
||||
private static Map<Integer, List<ShopGoodsData>> shopGoods = new HashMap<>();
|
||||
|
||||
public static Int2ObjectMap<?> getMapByResourceDef(Class<?> resourceDefinition) {
|
||||
Int2ObjectMap<?> map = null;
|
||||
@ -265,4 +268,16 @@ public class GameData {
|
||||
public static Int2ObjectMap<WorldLevelData> getWorldLevelDataMap() {
|
||||
return worldLevelDataMap;
|
||||
}
|
||||
|
||||
public static Map<Integer, List<ShopGoodsData>> getShopGoodsDataEntries() {
|
||||
if (shopGoods.isEmpty()) {
|
||||
shopGoodsDataMap.forEach((k, v) -> {
|
||||
if (!shopGoods.containsKey(v.getShopType()))
|
||||
shopGoods.put(v.getShopType(), new ArrayList<>());
|
||||
shopGoods.get(v.getShopType()).add(v);
|
||||
});
|
||||
}
|
||||
|
||||
return shopGoods;
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,12 @@ package emu.grasscutter.data.common;
|
||||
public class ItemParamData {
|
||||
private int Id;
|
||||
private int Count;
|
||||
|
||||
public ItemParamData() {}
|
||||
public ItemParamData(int id, int count) {
|
||||
this.Id = id;
|
||||
this.Count = count;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return Id;
|
||||
|
80
src/main/java/emu/grasscutter/data/def/ShopGoodsData.java
Normal file
80
src/main/java/emu/grasscutter/data/def/ShopGoodsData.java
Normal file
@ -0,0 +1,80 @@
|
||||
package emu.grasscutter.data.def;
|
||||
|
||||
import emu.grasscutter.data.GameResource;
|
||||
import emu.grasscutter.data.ResourceType;
|
||||
import emu.grasscutter.data.common.ItemParamData;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ResourceType(name = "ShopGoodsExcelConfigData.json")
|
||||
public class ShopGoodsData extends GameResource {
|
||||
private int GoodsId;
|
||||
private int ShopType;
|
||||
private int ItemId;
|
||||
|
||||
private int ItemCount;
|
||||
|
||||
private int CostScoin;
|
||||
private int CostHcoin;
|
||||
private int CostMcoin;
|
||||
|
||||
private List<ItemParamData> CostItems;
|
||||
private int MinPlayerLevel;
|
||||
private int MaxPlayerLevel;
|
||||
|
||||
private int BuyLimit;
|
||||
private int SubTabId;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return getGoodsId();
|
||||
}
|
||||
|
||||
public int getGoodsId() {
|
||||
return GoodsId;
|
||||
}
|
||||
|
||||
public int getShopType() {
|
||||
return ShopType;
|
||||
}
|
||||
|
||||
public int getItemId() {
|
||||
return ItemId;
|
||||
}
|
||||
|
||||
public int getItemCount() {
|
||||
return ItemCount;
|
||||
}
|
||||
|
||||
public int getCostScoin() {
|
||||
return CostScoin;
|
||||
}
|
||||
|
||||
public int getCostHcoin() {
|
||||
return CostHcoin;
|
||||
}
|
||||
|
||||
public int getCostMcoin() {
|
||||
return CostMcoin;
|
||||
}
|
||||
|
||||
public List<ItemParamData> getCostItems() {
|
||||
return CostItems;
|
||||
}
|
||||
|
||||
public int getMinPlayerLevel() {
|
||||
return MinPlayerLevel;
|
||||
}
|
||||
|
||||
public int getMaxPlayerLevel() {
|
||||
return MaxPlayerLevel;
|
||||
}
|
||||
|
||||
public int getBuyLimit() {
|
||||
return BuyLimit;
|
||||
}
|
||||
|
||||
public int getSubTabId() {
|
||||
return SubTabId;
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package emu.grasscutter.game.shop;
|
||||
|
||||
import emu.grasscutter.data.common.ItemParamData;
|
||||
import emu.grasscutter.data.def.ShopGoodsData;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -23,6 +24,20 @@ public class ShopInfo {
|
||||
private int disableType = 0;
|
||||
private int secondarySheetId = 0;
|
||||
|
||||
public ShopInfo(ShopGoodsData sgd) {
|
||||
this.goodsId = sgd.getGoodsId();
|
||||
this.goodsItem = new ItemParamData(sgd.getItemId(), sgd.getItemCount());
|
||||
this.scoin = sgd.getCostScoin();
|
||||
this.mcoin = sgd.getCostMcoin();
|
||||
this.hcoin = sgd.getCostHcoin();
|
||||
this.buyLimit = sgd.getBuyLimit();
|
||||
|
||||
this.minLevel = sgd.getMinPlayerLevel();
|
||||
this.maxLevel = sgd.getMaxPlayerLevel();
|
||||
this.costItemList = sgd.getCostItems().stream().filter(x -> x.getId() != 0).map(x -> new ItemParamData(x.getId(), x.getCount())).toList();
|
||||
this.secondarySheetId = sgd.getSubTabId();
|
||||
}
|
||||
|
||||
public int getHcoin() {
|
||||
return hcoin;
|
||||
}
|
||||
|
@ -2,12 +2,19 @@ package emu.grasscutter.game.shop;
|
||||
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.common.ItemParamData;
|
||||
import emu.grasscutter.data.def.ShopGoodsData;
|
||||
import emu.grasscutter.net.proto.ItemParamOuterClass;
|
||||
import emu.grasscutter.net.proto.ShopGoodsOuterClass;
|
||||
import emu.grasscutter.server.game.GameServer;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
|
||||
import java.io.FileReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public class ShopManager {
|
||||
@ -31,12 +38,39 @@ public class ShopManager {
|
||||
List<ShopTable> banners = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, ShopTable.class).getType());
|
||||
if(banners.size() > 0) {
|
||||
for (ShopTable shopTable : banners) {
|
||||
for (ShopInfo cost : shopTable.getItems()) {
|
||||
if (cost.getCostItemList() != null) {
|
||||
Iterator<ItemParamData> iterator = cost.getCostItemList().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
ItemParamData ipd = iterator.next();
|
||||
if (ipd.getId() == 201) {
|
||||
cost.setHcoin(cost.getHcoin() + ipd.getCount());
|
||||
iterator.remove();
|
||||
}
|
||||
if (ipd.getId() == 203) {
|
||||
cost.setMcoin(cost.getMcoin() + ipd.getCount());
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
getShopData().put(shopTable.getShopId(), shopTable.getItems());
|
||||
}
|
||||
Grasscutter.getLogger().info("Shop data successfully loaded.");
|
||||
} else {
|
||||
Grasscutter.getLogger().error("Unable to load shop data. Shop data size is 0.");
|
||||
}
|
||||
|
||||
if (Grasscutter.getConfig().getGameServerOptions().EnableOfficialShop) {
|
||||
GameData.getShopGoodsDataEntries().forEach((k, v) -> {
|
||||
if (!getShopData().containsKey(k.intValue()))
|
||||
getShopData().put(k.intValue(), new ArrayList<>());
|
||||
for (ShopGoodsData sgd : v) {
|
||||
var shopInfo = new ShopInfo(sgd);
|
||||
getShopData().get(k.intValue()).add(shopInfo);
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
|
@ -1,9 +1,11 @@
|
||||
package emu.grasscutter.server.packet.recv;
|
||||
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.common.ItemParamData;
|
||||
import emu.grasscutter.game.inventory.GameItem;
|
||||
import emu.grasscutter.game.props.ActionReason;
|
||||
import emu.grasscutter.game.props.PlayerProperty;
|
||||
import emu.grasscutter.game.shop.ShopInfo;
|
||||
import emu.grasscutter.net.packet.Opcodes;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
@ -16,6 +18,7 @@ import emu.grasscutter.server.packet.send.PacketStoreItemChangeNotify;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Opcodes(PacketOpcodes.BuyGoodsReq)
|
||||
@ -24,8 +27,18 @@ public class HandlerBuyGoodsReq extends PacketHandler {
|
||||
@Override
|
||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||
BuyGoodsReqOuterClass.BuyGoodsReq buyGoodsReq = BuyGoodsReqOuterClass.BuyGoodsReq.parseFrom(payload);
|
||||
List<ShopInfo> configShop = session.getServer().getShopManager().getShopData().get(buyGoodsReq.getShopType());
|
||||
if (configShop == null)
|
||||
return;
|
||||
|
||||
// Don't trust your users' input
|
||||
List<Integer> targetShopGoodsId = buyGoodsReq.getGoodsListList().stream().map(ShopGoodsOuterClass.ShopGoods::getGoodsId).toList();
|
||||
for (int goodsId : targetShopGoodsId) {
|
||||
Optional<ShopInfo> sg2 = configShop.stream().filter(x -> x.getGoodsId() == goodsId).findFirst();
|
||||
if (sg2.isEmpty())
|
||||
continue;
|
||||
ShopInfo sg = sg2.get();
|
||||
|
||||
for (ShopGoodsOuterClass.ShopGoods sg : buyGoodsReq.getGoodsListList()) {
|
||||
if (sg.getScoin() > 0 && session.getPlayer().getMora() < buyGoodsReq.getBoughtNum() * sg.getScoin()) {
|
||||
return;
|
||||
}
|
||||
@ -37,11 +50,13 @@ public class HandlerBuyGoodsReq extends PacketHandler {
|
||||
}
|
||||
|
||||
HashMap<GameItem, Integer> itemsCache = new HashMap<>();
|
||||
for (ItemParamOuterClass.ItemParam p : sg.getCostItemListList()) {
|
||||
Optional<GameItem> invItem = session.getPlayer().getInventory().getItems().values().stream().filter(x -> x.getItemId() == p.getItemId()).findFirst();
|
||||
if (invItem.isEmpty() || invItem.get().getCount() < p.getCount())
|
||||
return;
|
||||
itemsCache.put(invItem.get(), p.getCount() * buyGoodsReq.getBoughtNum());
|
||||
if (sg.getCostItemList() != null) {
|
||||
for (ItemParamData p : sg.getCostItemList()) {
|
||||
Optional<GameItem> invItem = session.getPlayer().getInventory().getItems().values().stream().filter(x -> x.getItemId() == p.getId()).findFirst();
|
||||
if (invItem.isEmpty() || invItem.get().getCount() < p.getCount())
|
||||
return;
|
||||
itemsCache.put(invItem.get(), p.getCount() * buyGoodsReq.getBoughtNum());
|
||||
}
|
||||
}
|
||||
|
||||
session.getPlayer().setMora(session.getPlayer().getMora() - buyGoodsReq.getBoughtNum() * sg.getScoin());
|
||||
@ -56,10 +71,10 @@ public class HandlerBuyGoodsReq extends PacketHandler {
|
||||
}
|
||||
|
||||
session.getPlayer().addShopLimit(sg.getGoodsId(), buyGoodsReq.getBoughtNum());
|
||||
GameItem item = new GameItem(GameData.getItemDataMap().get(sg.getGoodsItem().getItemId()));
|
||||
GameItem item = new GameItem(GameData.getItemDataMap().get(sg.getGoodsItem().getId()));
|
||||
item.setCount(buyGoodsReq.getBoughtNum() * sg.getGoodsItem().getCount());
|
||||
session.getPlayer().getInventory().addItem(item, ActionReason.Shop, true); // fix: not notify when got virtual item from shop
|
||||
session.send(new PacketBuyGoodsRsp(buyGoodsReq.getShopType(), session.getPlayer().getGoodsLimitNum(sg.getGoodsId()), sg));
|
||||
session.send(new PacketBuyGoodsRsp(buyGoodsReq.getShopType(), session.getPlayer().getGoodsLimitNum(sg.getGoodsId()), buyGoodsReq.getGoodsListList().stream().filter(x -> x.getGoodsId() == goodsId).findFirst().get()));
|
||||
}
|
||||
|
||||
session.getPlayer().save();
|
||||
|
@ -1,6 +1,8 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.def.ShopGoodsData;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.shop.ShopInfo;
|
||||
import emu.grasscutter.game.shop.ShopManager;
|
||||
@ -43,13 +45,15 @@ public class PacketGetShopRsp extends BasePacket {
|
||||
.setNextRefreshTime(info.getNextRefreshTime())
|
||||
.setMinLevel(info.getMinLevel())
|
||||
.setMaxLevel(info.getMaxLevel())
|
||||
.addAllPreGoodsIdList(info.getPreGoodsIdList())
|
||||
.setMcoin(info.getMcoin())
|
||||
.setDisableType(info.getDisableType())
|
||||
.setSecondarySheetId(info.getSecondarySheetId());
|
||||
if (info.getCostItemList() != null) {
|
||||
goods.addAllCostItemList(info.getCostItemList().stream().map(x -> ItemParamOuterClass.ItemParam.newBuilder().setItemId(x.getId()).setCount(x.getCount()).build()).collect(Collectors.toList()));
|
||||
}
|
||||
if (info.getPreGoodsIdList() != null) {
|
||||
goods.addAllPreGoodsIdList(info.getPreGoodsIdList());
|
||||
}
|
||||
goodsList.add(goods.build());
|
||||
}
|
||||
shop.addAllGoodsList(goodsList);
|
||||
|
Loading…
Reference in New Issue
Block a user