Commit b4a9c8a8 authored by BaiSugar's avatar BaiSugar Committed by GitHub
Browse files

Merge branch 'Grasscutters:development' into development

parents fa9d703d d3925e8c
package emu.grasscutter.game.shop;
import java.util.ArrayList;
import java.util.List;
public class ShopTable {
private int shopId;
private List<ShopInfo> items = new ArrayList<>();
public int getShopId() {
return shopId;
}
public void setShopId(int shopId) {
this.shopId = shopId;
}
public List<ShopInfo> getItems() {
return items;
}
public void setItems(List<ShopInfo> items) {
this.items = items;
}
}
package emu.grasscutter.game.world; package emu.grasscutter.game.world;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.danilopianini.util.SpatialIndex;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.GameData; import emu.grasscutter.data.GameData;
import emu.grasscutter.data.GameDepot; import emu.grasscutter.data.GameDepot;
import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.def.MonsterData; import emu.grasscutter.data.def.MonsterData;
import emu.grasscutter.data.def.SceneData; import emu.grasscutter.data.def.SceneData;
import emu.grasscutter.data.def.WorldLevelData; import emu.grasscutter.data.def.WorldLevelData;
import emu.grasscutter.game.entity.EntityAvatar; import emu.grasscutter.game.entity.*;
import emu.grasscutter.game.entity.EntityClientGadget;
import emu.grasscutter.game.entity.EntityGadget;
import emu.grasscutter.game.entity.EntityMonster;
import emu.grasscutter.game.entity.GameEntity;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.player.TeamInfo; import emu.grasscutter.game.player.TeamInfo;
import emu.grasscutter.game.props.ClimateType; import emu.grasscutter.game.props.ClimateType;
...@@ -37,10 +21,12 @@ import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify; ...@@ -37,10 +21,12 @@ import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
import emu.grasscutter.server.packet.send.PacketLifeStateChangeNotify; import emu.grasscutter.server.packet.send.PacketLifeStateChangeNotify;
import emu.grasscutter.server.packet.send.PacketSceneEntityAppearNotify; import emu.grasscutter.server.packet.send.PacketSceneEntityAppearNotify;
import emu.grasscutter.server.packet.send.PacketSceneEntityDisappearNotify; import emu.grasscutter.server.packet.send.PacketSceneEntityDisappearNotify;
import emu.grasscutter.utils.Utils;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import org.danilopianini.util.SpatialIndex;
import java.util.*;
public class Scene { public class Scene {
private final World world; private final World world;
...@@ -228,6 +214,11 @@ public class Scene { ...@@ -228,6 +214,11 @@ public class Scene {
this.addEntityDirectly(entity); this.addEntityDirectly(entity);
this.broadcastPacket(new PacketSceneEntityAppearNotify(entity)); this.broadcastPacket(new PacketSceneEntityAppearNotify(entity));
} }
public synchronized void addEntityToSingleClient(Player player, GameEntity entity) {
this.addEntityDirectly(entity);
player.sendPacket(new PacketSceneEntityAppearNotify(entity));
}
public synchronized void addEntities(Collection<GameEntity> entities) { public synchronized void addEntities(Collection<GameEntity> entities) {
for (GameEntity entity : entities) { for (GameEntity entity : entities) {
...@@ -310,6 +301,12 @@ public class Scene { ...@@ -310,6 +301,12 @@ public class Scene {
public void killEntity(GameEntity target, int attackerId) { public void killEntity(GameEntity target, int attackerId) {
// Packet // Packet
this.broadcastPacket(new PacketLifeStateChangeNotify(attackerId, target, LifeState.LIFE_DEAD)); this.broadcastPacket(new PacketLifeStateChangeNotify(attackerId, target, LifeState.LIFE_DEAD));
// Reward drop
if (target instanceof EntityMonster) {
Grasscutter.getGameServer().getDropManager().callDrop((EntityMonster) target);
}
this.removeEntity(target); this.removeEntity(target);
// Death event // Death event
......
...@@ -339,6 +339,10 @@ public final class DispatchServer { ...@@ -339,6 +339,10 @@ public final class DispatchServer {
// added. // added.
account = DatabaseHelper.createAccountWithId(requestData.account, 0); account = DatabaseHelper.createAccountWithId(requestData.account, 0);
for (String permission : Grasscutter.getConfig().getDispatchOptions().defaultPermissions) {
account.addPermission(permission);
}
if (account != null) { if (account != null) {
responseData.message = "OK"; responseData.message = "OK";
responseData.data.account.uid = account.getId(); responseData.data.account.uid = account.getId();
......
package emu.grasscutter.server.game; 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.GameConstants;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.CommandMap; import emu.grasscutter.command.CommandMap;
import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.game.Account; import emu.grasscutter.game.Account;
import emu.grasscutter.game.drop.DropManager;
import emu.grasscutter.game.dungeons.DungeonManager; import emu.grasscutter.game.dungeons.DungeonManager;
import emu.grasscutter.game.gacha.GachaManager; import emu.grasscutter.game.gacha.GachaManager;
import emu.grasscutter.game.managers.ChatManager; import emu.grasscutter.game.managers.ChatManager;
...@@ -27,6 +23,11 @@ import emu.grasscutter.server.event.internal.ServerStartEvent; ...@@ -27,6 +23,11 @@ import emu.grasscutter.server.event.internal.ServerStartEvent;
import emu.grasscutter.server.event.internal.ServerStopEvent; import emu.grasscutter.server.event.internal.ServerStopEvent;
import emu.grasscutter.task.TaskMap; 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 { public final class GameServer extends KcpServer {
private final InetSocketAddress address; private final InetSocketAddress address;
private final GameServerPacketHandler packetHandler; private final GameServerPacketHandler packetHandler;
...@@ -42,6 +43,7 @@ public final class GameServer extends KcpServer { ...@@ -42,6 +43,7 @@ public final class GameServer extends KcpServer {
private final DungeonManager dungeonManager; private final DungeonManager dungeonManager;
private final CommandMap commandMap; private final CommandMap commandMap;
private final TaskMap taskMap; private final TaskMap taskMap;
private final DropManager dropManager;
public GameServer(InetSocketAddress address) { public GameServer(InetSocketAddress address) {
super(address); super(address);
...@@ -60,6 +62,7 @@ public final class GameServer extends KcpServer { ...@@ -60,6 +62,7 @@ public final class GameServer extends KcpServer {
this.dungeonManager = new DungeonManager(this); this.dungeonManager = new DungeonManager(this);
this.commandMap = new CommandMap(true); this.commandMap = new CommandMap(true);
this.taskMap = new TaskMap(true); this.taskMap = new TaskMap(true);
this.dropManager = new DropManager(this);
// Schedule game loop. // Schedule game loop.
Timer gameLoop = new Timer(); Timer gameLoop = new Timer();
...@@ -109,6 +112,10 @@ public final class GameServer extends KcpServer { ...@@ -109,6 +112,10 @@ public final class GameServer extends KcpServer {
public MultiplayerManager getMultiplayerManager() { public MultiplayerManager getMultiplayerManager() {
return multiplayerManager; return multiplayerManager;
} }
public DropManager getDropManager() {
return dropManager;
}
public DungeonManager getDungeonManager() { public DungeonManager getDungeonManager() {
return dungeonManager; return dungeonManager;
...@@ -196,6 +203,7 @@ public final class GameServer extends KcpServer { ...@@ -196,6 +203,7 @@ public final class GameServer extends KcpServer {
@Override @Override
public void onStartFinish() { 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()); Grasscutter.getLogger().info("Game Server started on port " + address.getPort());
ServerStartEvent event = new ServerStartEvent(ServerEvent.Type.GAME, OffsetDateTime.now()); event.call(); 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; package emu.grasscutter.server.packet.recv;
import emu.grasscutter.net.packet.Opcodes; import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.GetShopReqOuterClass.GetShopReq; import emu.grasscutter.net.proto.GetShopReqOuterClass.GetShopReq;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.server.game.GameSession; import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketGetShopRsp; import emu.grasscutter.server.packet.send.PacketGetShopRsp;
...@@ -12,8 +12,7 @@ public class HandlerGetShopReq extends PacketHandler { ...@@ -12,8 +12,7 @@ public class HandlerGetShopReq extends PacketHandler {
@Override @Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
GetShopReq req = GetShopReq.parseFrom(payload); GetShopReq req = GetShopReq.parseFrom(payload);
// TODO session.send(new PacketGetShopRsp(session.getPlayer(), req.getShopType()));
session.send(new PacketGetShopRsp(req.getShopType()));
} }
} }
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.UpdatePlayerShowAvatarListReqOuterClass;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketUpdatePlayerShowAvatarListRsp;
@Opcodes(PacketOpcodes.UpdatePlayerShowAvatarListReq)
public class HandlerUpdatePlayerShowAvatarListReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
UpdatePlayerShowAvatarListReqOuterClass.UpdatePlayerShowAvatarListReq req = UpdatePlayerShowAvatarListReqOuterClass.UpdatePlayerShowAvatarListReq.parseFrom(payload);
session.getPlayer().setShowAvatars(req.getIsShowAvatar());
session.getPlayer().setShowAvatarList(req.getShowAvatarIdListList());
session.send(new PacketUpdatePlayerShowAvatarListRsp(req.getIsShowAvatar(), req.getShowAvatarIdListList()));
}
}
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 { ...@@ -11,7 +11,7 @@ public class PacketChangeAvatarRsp extends BasePacket {
super(PacketOpcodes.ChangeAvatarRsp); super(PacketOpcodes.ChangeAvatarRsp);
ChangeAvatarRsp p = ChangeAvatarRsp.newBuilder() ChangeAvatarRsp p = ChangeAvatarRsp.newBuilder()
.setRetcode(RetcodeOuterClass.Retcode.RET_SVR_ERROR_VALUE) .setRetcode(RetcodeOuterClass.Retcode.RET_SUCC_VALUE)
.setCurGuid(guid) .setCurGuid(guid)
.build(); .build();
......
...@@ -14,32 +14,23 @@ import emu.grasscutter.net.proto.MailTextContentOuterClass.MailTextContent; ...@@ -14,32 +14,23 @@ import emu.grasscutter.net.proto.MailTextContentOuterClass.MailTextContent;
import java.time.Instant; import java.time.Instant;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Base64;
import java.util.List; import java.util.List;
public class PacketGetAllMailRsp extends BasePacket { public class PacketGetAllMailRsp extends BasePacket {
public PacketGetAllMailRsp(Player player, boolean isGiftMail) { public PacketGetAllMailRsp(Player player, boolean isGiftMail) {
super(PacketOpcodes.GetAllMailRsp); super(PacketOpcodes.GetAllMailRsp);
GetAllMailRsp.Builder proto = GetAllMailRsp.newBuilder();
if (isGiftMail) { if (isGiftMail) {
// TODO: Gift Mail proto.setIsGiftMail(true);
// 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) {
}
} else { } else {
proto.setIsGiftMail(false);
if (player.getAllMail().size() != 0) { // Make sure the player has mail if (player.getAllMail().size() != 0) { // Make sure the player has mail
GetAllMailRsp.Builder proto = GetAllMailRsp.newBuilder();
List<MailData> mailDataList = new ArrayList<MailData>(); List<MailData> mailDataList = new ArrayList<MailData>();
for (Mail message : player.getAllMail()) { for (Mail message : player.getAllMail()) {
if(message.stateValue == 1) { // Make sure it isn't a gift 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 (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.) 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 { ...@@ -79,17 +70,8 @@ public class PacketGetAllMailRsp extends BasePacket {
proto.addAllMailList(mailDataList); 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. 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; ...@@ -8,7 +8,7 @@ import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.FriendBriefOuterClass.FriendBrief; import emu.grasscutter.net.proto.FriendBriefOuterClass.FriendBrief;
import emu.grasscutter.net.proto.FriendOnlineStateOuterClass.FriendOnlineState; import emu.grasscutter.net.proto.FriendOnlineStateOuterClass.FriendOnlineState;
import emu.grasscutter.net.proto.GetPlayerFriendListRspOuterClass.GetPlayerFriendListRsp; 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; import emu.grasscutter.net.proto.PlatformTypeOuterClass;
public class PacketGetPlayerFriendListRsp extends BasePacket { public class PacketGetPlayerFriendListRsp extends BasePacket {
...@@ -20,7 +20,7 @@ public class PacketGetPlayerFriendListRsp extends BasePacket { ...@@ -20,7 +20,7 @@ public class PacketGetPlayerFriendListRsp extends BasePacket {
.setUid(GameConstants.SERVER_CONSOLE_UID) .setUid(GameConstants.SERVER_CONSOLE_UID)
.setNickname("Server") .setNickname("Server")
.setLevel(1) .setLevel(1)
.setAvatarId(HeadImage.newBuilder().setAvatarId(GameConstants.MAIN_CHARACTER_FEMALE).getAvatarId()) .setProfilePicture(ProfilePicture.newBuilder().setAvatarId(GameConstants.MAIN_CHARACTER_FEMALE))
.setWorldLevel(0) .setWorldLevel(0)
.setSignature("") .setSignature("")
.setLastActiveTime((int) (System.currentTimeMillis() / 1000f)) .setLastActiveTime((int) (System.currentTimeMillis() / 1000f))
......
package emu.grasscutter.server.packet.send; 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.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes; 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 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 class PacketGetShopRsp extends BasePacket {
public PacketGetShopRsp(int shopType) { public PacketGetShopRsp(Player inv, int shopType) {
super(PacketOpcodes.GetShopRsp); super(PacketOpcodes.GetShopRsp);
GetShopRsp proto = GetShopRsp.newBuilder() // TODO: CityReputationLevel
.setShop(Shop.newBuilder().setShopType(shopType)) Shop.Builder shop = Shop.newBuilder()
.build(); .setShopType(shopType)
.setCityId(1) //mock
this.setData(proto); .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(GetShopRspOuterClass.GetShopRsp.newBuilder().setShop(shop).build());
} }
} }
...@@ -3,7 +3,7 @@ package emu.grasscutter.server.packet.send; ...@@ -3,7 +3,7 @@ package emu.grasscutter.server.packet.send;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes; 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; import emu.grasscutter.net.proto.SetPlayerHeadImageRspOuterClass.SetPlayerHeadImageRsp;
public class PacketSetPlayerHeadImageRsp extends BasePacket { public class PacketSetPlayerHeadImageRsp extends BasePacket {
...@@ -12,7 +12,7 @@ public class PacketSetPlayerHeadImageRsp extends BasePacket { ...@@ -12,7 +12,7 @@ public class PacketSetPlayerHeadImageRsp extends BasePacket {
super(PacketOpcodes.SetPlayerHeadImageRsp); super(PacketOpcodes.SetPlayerHeadImageRsp);
SetPlayerHeadImageRsp proto = SetPlayerHeadImageRsp.newBuilder() SetPlayerHeadImageRsp proto = SetPlayerHeadImageRsp.newBuilder()
.setAvatarId(HeadImage.newBuilder().setAvatarId(player.getHeadImage()).getAvatarId()) .setProfilePicture(ProfilePicture.newBuilder().setAvatarId(player.getHeadImage()))
.build(); .build();
this.setData(proto); this.setData(proto);
......
package emu.grasscutter.server.packet.send;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.UpdatePlayerShowAvatarListRspOuterClass.UpdatePlayerShowAvatarListRsp;
import java.util.List;
public class PacketUpdatePlayerShowAvatarListRsp extends BasePacket {
public PacketUpdatePlayerShowAvatarListRsp(boolean isShowAvatar, List<Integer> avatarIds) {
super(PacketOpcodes.UpdatePlayerShowAvatarListRsp);
UpdatePlayerShowAvatarListRsp proto = UpdatePlayerShowAvatarListRsp.newBuilder()
.setIsShowAvatar(isShowAvatar)
.addAllShowAvatarIdList(avatarIds)
.setRetcode(0)
.build();
this.setData(proto);
}
}
package emu.grasscutter.task; package emu.grasscutter.task;
import org.quartz.JobDataMap;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
...@@ -27,4 +29,6 @@ public @interface Task { ...@@ -27,4 +29,6 @@ public @interface Task {
String taskName() default "NO_NAME"; String taskName() default "NO_NAME";
String taskCronExpression() default "0 0 0 0 0 ?"; String taskCronExpression() default "0 0 0 0 0 ?";
String triggerName() default "NO_NAME"; String triggerName() default "NO_NAME";
boolean executeImmediatelyAfterReset() default false;
boolean executeImmediately() default false;
} }
package emu.grasscutter.task; package emu.grasscutter.task;
import org.quartz.Job; import org.quartz.*;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException; @PersistJobDataAfterExecution
public class TaskHandler implements Job {
public void restartExecute() throws JobExecutionException {
execute(null);
}
public void onEnable() {
public interface TaskHandler extends Job {
default void execute(JobExecutionContext context) throws JobExecutionException {
} }
public void onDisable() {
}
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
// TODO Auto-generated method stub
}
} }
package emu.grasscutter.task; package emu.grasscutter.task;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.game.Account;
import emu.grasscutter.game.player.Player; import org.quartz.*;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory; import org.quartz.impl.StdSchedulerFactory;
import org.quartz.spi.MutableTrigger;
import org.reflections.Reflections; import org.reflections.Reflections;
import java.util.*; import java.util.*;
...@@ -23,6 +12,7 @@ import java.util.*; ...@@ -23,6 +12,7 @@ import java.util.*;
public final class TaskMap { public final class TaskMap {
private final Map<String, TaskHandler> tasks = new HashMap<>(); private final Map<String, TaskHandler> tasks = new HashMap<>();
private final Map<String, Task> annotations = new HashMap<>(); private final Map<String, Task> annotations = new HashMap<>();
private final Map<String, TaskHandler> afterReset = new HashMap<>();
private final SchedulerFactory schedulerFactory = new StdSchedulerFactory(); private final SchedulerFactory schedulerFactory = new StdSchedulerFactory();
public TaskMap() { public TaskMap() {
...@@ -37,6 +27,46 @@ public final class TaskMap { ...@@ -37,6 +27,46 @@ public final class TaskMap {
return Grasscutter.getGameServer().getTaskMap(); return Grasscutter.getGameServer().getTaskMap();
} }
public void resetNow() {
// Unregister all tasks
for (TaskHandler task : this.tasks.values()) {
unregisterTask(task);
}
// Run all afterReset tasks
for (TaskHandler task : this.afterReset.values()) {
try {
task.restartExecute();
} catch (Exception e) {
e.printStackTrace();
}
}
// Remove all afterReset tasks
this.afterReset.clear();
// Register all tasks
for (TaskHandler task : this.tasks.values()) {
registerTask(task.getClass().getAnnotation(Task.class).taskName(), task);
}
}
public TaskMap unregisterTask(TaskHandler task) {
this.tasks.remove(task.getClass().getAnnotation(Task.class).taskName());
this.annotations.remove(task.getClass().getAnnotation(Task.class).taskName());
try {
Scheduler scheduler = schedulerFactory.getScheduler();
scheduler.deleteJob(new JobKey(task.getClass().getAnnotation(Task.class).taskName()));
} catch (SchedulerException e) {
e.printStackTrace();
}
task.onDisable();
return this;
}
public TaskMap registerTask(String taskName, TaskHandler task) { public TaskMap registerTask(String taskName, TaskHandler task) {
Task annotation = task.getClass().getAnnotation(Task.class); Task annotation = task.getClass().getAnnotation(Task.class);
this.annotations.put(taskName, annotation); this.annotations.put(taskName, annotation);
...@@ -56,7 +86,11 @@ public final class TaskMap { ...@@ -56,7 +86,11 @@ public final class TaskMap {
.build(); .build();
scheduler.scheduleJob(job, convTrigger); scheduler.scheduleJob(job, convTrigger);
scheduler.start();
if (annotation.executeImmediately()) {
task.execute(null);
}
task.onEnable();
} catch (SchedulerException e) { } catch (SchedulerException e) {
e.printStackTrace(); e.printStackTrace();
} }
...@@ -83,12 +117,24 @@ public final class TaskMap { ...@@ -83,12 +117,24 @@ public final class TaskMap {
try { try {
Task taskData = annotated.getAnnotation(Task.class); Task taskData = annotated.getAnnotation(Task.class);
Object object = annotated.newInstance(); Object object = annotated.newInstance();
if (object instanceof TaskHandler) if (object instanceof TaskHandler) {
this.registerTask(taskData.taskName(), (TaskHandler) object); this.registerTask(taskData.taskName(), (TaskHandler) object);
else Grasscutter.getLogger().error("Class " + annotated.getName() + " is not a TaskHandler!"); if (taskData.executeImmediatelyAfterReset()) {
this.afterReset.put(taskData.taskName(), (TaskHandler) object);
}
} else {
Grasscutter.getLogger().error("Class " + annotated.getName() + " is not a TaskHandler!");
}
} catch (Exception exception) { } catch (Exception exception) {
Grasscutter.getLogger().error("Failed to register task handler for " + annotated.getSimpleName(), exception); Grasscutter.getLogger().error("Failed to register task handler for " + annotated.getSimpleName(), exception);
} }
}); });
try {
Scheduler scheduler = schedulerFactory.getScheduler();
scheduler.start();
} catch (SchedulerException e) {
e.printStackTrace();
}
} }
} }
package emu.grasscutter.task.tasks; package emu.grasscutter.task.tasks;
import emu.grasscutter.database.DatabaseManager; import emu.grasscutter.Grasscutter;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.task.Task; import emu.grasscutter.task.Task;
import emu.grasscutter.task.TaskHandler; import emu.grasscutter.task.TaskHandler;
import java.util.List;
import org.quartz.JobExecutionContext; import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException; import org.quartz.JobExecutionException;
@Task(taskName = "MoonCard", taskCronExpression = "0 0 0 * * ?", triggerName = "MoonCardTrigger") @Task(taskName = "MoonCard", taskCronExpression = "0 0 0 * * ?", triggerName = "MoonCardTrigger")
// taskCronExpression: Fixed time period: 0:0:0 every day (twenty-four hour system) // taskCronExpression: Fixed time period: 0:0:0 every day (twenty-four hour system)
public final class MoonCard implements TaskHandler { public class MoonCard extends TaskHandler {
@Override
public void onEnable() {
Grasscutter.getLogger().info("[Task] MoonCard task enabled.");
}
@Override
public void onDisable() {
Grasscutter.getLogger().info("[Task] MoonCard task disabled.");
}
@Override @Override
public void execute(JobExecutionContext context) throws JobExecutionException { public synchronized void execute(JobExecutionContext context) throws JobExecutionException {
List<Player> players = DatabaseManager.getDatastore().find(Player.class).stream().toList(); Grasscutter.getGameServer().getPlayers().forEach((uid, player) -> {
for (Player player : players) {
if (player.isOnline()) { if (player.isOnline()) {
if (player.inMoonCard()) { if (player.inMoonCard()) {
player.getTodayMoonCard(); player.getTodayMoonCard();
} }
} }
} });
} }
} }
...@@ -33,7 +33,7 @@ if not "%JAVA_PATH%" == "DO_NOT_CHECK_PATH" ( ...@@ -33,7 +33,7 @@ if not "%JAVA_PATH%" == "DO_NOT_CHECK_PATH" (
goto :EXIT goto :EXIT
) )
) else set JAVA_PATH= ) 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. call :LOG [ERROR] Server jar not found.
goto :EXIT goto :EXIT
) )
...@@ -129,7 +129,7 @@ del /f /q "%temp%\db.vbs" >nul 2>nul ...@@ -129,7 +129,7 @@ del /f /q "%temp%\db.vbs" >nul 2>nul
:GAME :GAME
call :LOG [INFO] Starting server... 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 call :LOG [INFO] Server stopped
:EXIT :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