Commit 5b55df69 authored by Yazawazi's avatar Yazawazi Committed by GitHub
Browse files

Merge branch 'Grasscutters:development' into development

parents 897f529e f6db3992
package emu.grasscutter.server.game;
import java.net.InetSocketAddress;
import java.time.OffsetDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import emu.grasscutter.GameConstants;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.CommandMap;
import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.game.Account;
import emu.grasscutter.game.drop.DropManager;
import emu.grasscutter.game.dungeons.DungeonManager;
import emu.grasscutter.game.gacha.GachaManager;
import emu.grasscutter.game.managers.ChatManager;
......@@ -27,6 +23,11 @@ import emu.grasscutter.server.event.internal.ServerStartEvent;
import emu.grasscutter.server.event.internal.ServerStopEvent;
import emu.grasscutter.task.TaskMap;
import java.net.InetSocketAddress;
import java.time.OffsetDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public final class GameServer extends KcpServer {
private final InetSocketAddress address;
private final GameServerPacketHandler packetHandler;
......@@ -42,6 +43,7 @@ public final class GameServer extends KcpServer {
private final DungeonManager dungeonManager;
private final CommandMap commandMap;
private final TaskMap taskMap;
private final DropManager dropManager;
public GameServer(InetSocketAddress address) {
super(address);
......@@ -60,6 +62,7 @@ public final class GameServer extends KcpServer {
this.dungeonManager = new DungeonManager(this);
this.commandMap = new CommandMap(true);
this.taskMap = new TaskMap(true);
this.dropManager = new DropManager(this);
// Schedule game loop.
Timer gameLoop = new Timer();
......@@ -110,6 +113,10 @@ public final class GameServer extends KcpServer {
return multiplayerManager;
}
public DropManager getDropManager() {
return dropManager;
}
public DungeonManager getDungeonManager() {
return dungeonManager;
}
......@@ -196,6 +203,7 @@ public final class GameServer extends KcpServer {
@Override
public void onStartFinish() {
Grasscutter.getLogger().info("Grasscutter is FREE software. If you have paid for this, you may have been scammed. Homepage: https://github.com/Grasscutters/Grasscutter");
Grasscutter.getLogger().info("Game Server started on port " + address.getPort());
ServerStartEvent event = new ServerStartEvent(ServerEvent.Type.GAME, OffsetDateTime.now()); event.call();
}
......
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.data.GameData;
import emu.grasscutter.game.inventory.GameItem;
import emu.grasscutter.game.props.ActionReason;
import emu.grasscutter.game.props.PlayerProperty;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.BuyGoodsReqOuterClass;
import emu.grasscutter.net.proto.ItemParamOuterClass;
import emu.grasscutter.net.proto.ShopGoodsOuterClass;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketBuyGoodsRsp;
import emu.grasscutter.server.packet.send.PacketStoreItemChangeNotify;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Optional;
@Opcodes(PacketOpcodes.BuyGoodsReq)
public class HandlerBuyGoodsReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
BuyGoodsReqOuterClass.BuyGoodsReq buyGoodsReq = BuyGoodsReqOuterClass.BuyGoodsReq.parseFrom(payload);
for (ShopGoodsOuterClass.ShopGoods sg : buyGoodsReq.getGoodsListList()) {
if (sg.getScoin() > 0 && session.getPlayer().getMora() < buyGoodsReq.getBoughtNum() * sg.getScoin()) {
return;
}
if (sg.getHcoin() > 0 && session.getPlayer().getPrimogems() < buyGoodsReq.getBoughtNum() * sg.getHcoin()) {
return;
}
if (sg.getMcoin() > 0 && session.getPlayer().getCrystals() < buyGoodsReq.getBoughtNum() * sg.getMcoin()) {
return;
}
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());
}
session.getPlayer().setMora(session.getPlayer().getMora() - buyGoodsReq.getBoughtNum() * sg.getScoin());
session.getPlayer().setPrimogems(session.getPlayer().getPrimogems() - buyGoodsReq.getBoughtNum() * sg.getHcoin());
session.getPlayer().setCrystals(session.getPlayer().getCrystals() - buyGoodsReq.getBoughtNum() * sg.getMcoin());
if (!itemsCache.isEmpty()) {
for (GameItem gi : itemsCache.keySet()) {
session.getPlayer().getInventory().removeItem(gi, itemsCache.get(gi));
}
itemsCache.clear();
}
session.getPlayer().addShopLimit(sg.getGoodsId(), buyGoodsReq.getBoughtNum());
GameItem item = new GameItem(GameData.getItemDataMap().get(sg.getGoodsItem().getItemId()));
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.getPlayer().save();
}
}
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.GetShopReqOuterClass.GetShopReq;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketGetShopRsp;
......@@ -13,7 +13,6 @@ public class HandlerGetShopReq extends PacketHandler {
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
GetShopReq req = GetShopReq.parseFrom(payload);
// TODO
session.send(new PacketGetShopRsp(req.getShopType()));
session.send(new PacketGetShopRsp(session.getPlayer(), req.getShopType()));
}
}
package emu.grasscutter.server.packet.send;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.BuyGoodsRspOuterClass;
import emu.grasscutter.net.proto.ShopGoodsOuterClass;
public class PacketBuyGoodsRsp extends BasePacket {
public PacketBuyGoodsRsp(int shopType, int boughtNum, ShopGoodsOuterClass.ShopGoods sg) {
super(PacketOpcodes.BuyGoodsRsp);
BuyGoodsRspOuterClass.BuyGoodsRsp buyGoodsRsp = BuyGoodsRspOuterClass.BuyGoodsRsp.newBuilder()
.setShopType(shopType)
.setBoughtNum(boughtNum)
.addGoodsList(ShopGoodsOuterClass.ShopGoods.newBuilder()
.mergeFrom(sg)
.setBoughtNum(boughtNum)
).build();
this.setData(buyGoodsRsp);
}
}
......@@ -11,7 +11,7 @@ public class PacketChangeAvatarRsp extends BasePacket {
super(PacketOpcodes.ChangeAvatarRsp);
ChangeAvatarRsp p = ChangeAvatarRsp.newBuilder()
.setRetcode(RetcodeOuterClass.Retcode.RET_SVR_ERROR_VALUE)
.setRetcode(RetcodeOuterClass.Retcode.RET_SUCC_VALUE)
.setCurGuid(guid)
.build();
......
......@@ -14,32 +14,23 @@ import emu.grasscutter.net.proto.MailTextContentOuterClass.MailTextContent;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
public class PacketGetAllMailRsp extends BasePacket {
public PacketGetAllMailRsp(Player player, boolean isGiftMail) {
super(PacketOpcodes.GetAllMailRsp);
GetAllMailRsp.Builder proto = GetAllMailRsp.newBuilder();
if (isGiftMail) {
// TODO: Gift Mail
// Make sure to send the stupid empty packet
Base64.Decoder decoder = Base64.getDecoder();
byte[] rsp = decoder.decode("IAE=");
try {
GetAllMailRsp var = GetAllMailRsp.parseFrom(rsp);
this.setData(var.toBuilder().build());
} catch (Exception e) {
}
proto.setIsGiftMail(true);
} else {
proto.setIsGiftMail(false);
if (player.getAllMail().size() != 0) { // Make sure the player has mail
GetAllMailRsp.Builder proto = GetAllMailRsp.newBuilder();
List<MailData> mailDataList = new ArrayList<MailData>();
for (Mail message : player.getAllMail()) {
if(message.stateValue == 1) { // Make sure it isn't a gift
if (message.expireTime > (int) Instant.now().getEpochSecond()) { // Make sure the message isn't expired (The game won't show expired mail, but I don't want to send unnecessary information).
if(mailDataList.size() <= 1000) { // Make sure that there isn't over 1000 messages in the mailbox. (idk what will happen if there is but the game probably won't like it.)
......@@ -79,17 +70,8 @@ public class PacketGetAllMailRsp extends BasePacket {
proto.addAllMailList(mailDataList);
proto.setIsTruncated(mailDataList.size() <= 1000 ? false : true); // When enabled this will send a notification to the user telling them their inbox is full and they should delete old messages when opening the mailbox.
this.setData(proto.build());
} else {
// Make sure to send the stupid empty packet
Base64.Decoder decoder = Base64.getDecoder();
byte[] rsp = decoder.decode("IAE=");
try {
GetAllMailRsp var = GetAllMailRsp.parseFrom(rsp);
this.setData(var.toBuilder().build());
} catch (Exception e) {}
}
}
this.setData(proto.build());
}
}
......@@ -8,7 +8,7 @@ import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.FriendBriefOuterClass.FriendBrief;
import emu.grasscutter.net.proto.FriendOnlineStateOuterClass.FriendOnlineState;
import emu.grasscutter.net.proto.GetPlayerFriendListRspOuterClass.GetPlayerFriendListRsp;
import emu.grasscutter.net.proto.HeadImageOuterClass.HeadImage;
import emu.grasscutter.net.proto.ProfilePictureOuterClass.ProfilePicture;
import emu.grasscutter.net.proto.PlatformTypeOuterClass;
public class PacketGetPlayerFriendListRsp extends BasePacket {
......@@ -20,7 +20,7 @@ public class PacketGetPlayerFriendListRsp extends BasePacket {
.setUid(GameConstants.SERVER_CONSOLE_UID)
.setNickname("Server")
.setLevel(1)
.setAvatarId(HeadImage.newBuilder().setAvatarId(GameConstants.MAIN_CHARACTER_FEMALE).getAvatarId())
.setProfilePicture(ProfilePicture.newBuilder().setAvatarId(GameConstants.MAIN_CHARACTER_FEMALE))
.setWorldLevel(0)
.setSignature("")
.setLastActiveTime((int) (System.currentTimeMillis() / 1000f))
......
package emu.grasscutter.server.packet.send;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.shop.ShopInfo;
import emu.grasscutter.game.shop.ShopManager;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.GetShopRspOuterClass.GetShopRsp;
import emu.grasscutter.net.proto.GetShopRspOuterClass;
import emu.grasscutter.net.proto.ItemParamOuterClass;
import emu.grasscutter.net.proto.ShopGoodsOuterClass.ShopGoods;
import emu.grasscutter.net.proto.ShopOuterClass.Shop;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class PacketGetShopRsp extends BasePacket {
public PacketGetShopRsp(int shopType) {
public PacketGetShopRsp(Player inv, int shopType) {
super(PacketOpcodes.GetShopRsp);
GetShopRsp proto = GetShopRsp.newBuilder()
.setShop(Shop.newBuilder().setShopType(shopType))
.build();
// TODO: CityReputationLevel
Shop.Builder shop = Shop.newBuilder()
.setShopType(shopType)
.setCityId(1) //mock
.setCityReputationLevel(10); //mock
ShopManager manager = Grasscutter.getGameServer().getShopManager();
if (manager.getShopData().get(shopType) != null) {
List<ShopInfo> list = manager.getShopData().get(shopType);
List<ShopGoods> goodsList = new ArrayList<>();
for (ShopInfo info : list) {
ShopGoods.Builder goods = ShopGoods.newBuilder()
.setGoodsId(info.getGoodsId())
.setGoodsItem(ItemParamOuterClass.ItemParam.newBuilder().setItemId(info.getGoodsItem().getId()).setCount(info.getGoodsItem().getCount()).build())
.setScoin(info.getScoin())
.setHcoin(info.getHcoin())
.setBoughtNum(inv.getGoodsLimitNum(info.getGoodsId()))
.setBuyLimit(info.getBuyLimit())
.setBeginTime(info.getBeginTime())
.setEndTime(info.getEndTime())
.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()));
}
goodsList.add(goods.build());
}
shop.addAllGoodsList(goodsList);
}
this.setData(proto);
this.setData(GetShopRspOuterClass.GetShopRsp.newBuilder().setShop(shop).build());
}
}
......@@ -3,7 +3,7 @@ package emu.grasscutter.server.packet.send;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.HeadImageOuterClass.HeadImage;
import emu.grasscutter.net.proto.ProfilePictureOuterClass.ProfilePicture;
import emu.grasscutter.net.proto.SetPlayerHeadImageRspOuterClass.SetPlayerHeadImageRsp;
public class PacketSetPlayerHeadImageRsp extends BasePacket {
......@@ -12,7 +12,7 @@ public class PacketSetPlayerHeadImageRsp extends BasePacket {
super(PacketOpcodes.SetPlayerHeadImageRsp);
SetPlayerHeadImageRsp proto = SetPlayerHeadImageRsp.newBuilder()
.setAvatarId(HeadImage.newBuilder().setAvatarId(player.getHeadImage()).getAvatarId())
.setProfilePicture(ProfilePicture.newBuilder().setAvatarId(player.getHeadImage()))
.build();
this.setData(proto);
......
......@@ -33,7 +33,7 @@ if not "%JAVA_PATH%" == "DO_NOT_CHECK_PATH" (
goto :EXIT
)
) else set JAVA_PATH=
if not exist "%SERVER_PATH%grasscutter.jar" (
if not exist "%SERVER_PATH%%SERVER_JAR_NAME%" (
call :LOG [ERROR] Server jar not found.
goto :EXIT
)
......@@ -129,7 +129,7 @@ del /f /q "%temp%\db.vbs" >nul 2>nul
:GAME
call :LOG [INFO] Starting server...
"%JAVA_PATH%java.exe" -jar "%SERVER_PATH%grasscutter.jar"
"%JAVA_PATH%java.exe" -jar "%SERVER_PATH%%SERVER_JAR_NAME%"
call :LOG [INFO] Server stopped
:EXIT
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment