package emu.grasscutter.game.managers; import com.google.gson.reflect.TypeToken; import emu.grasscutter.Grasscutter; import emu.grasscutter.data.DataLoader; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.world.World; import emu.grasscutter.net.proto.AnnounceDataOuterClass; import emu.grasscutter.server.game.GameServer; import emu.grasscutter.server.packet.send.PacketServerAnnounceNotify; import emu.grasscutter.server.packet.send.PacketServerAnnounceRevokeNotify; import emu.grasscutter.utils.Utils; import lombok.AccessLevel; import lombok.Data; import lombok.Getter; import lombok.experimental.FieldDefaults; import java.io.InputStreamReader; import java.util.*; @Getter public class AnnouncementManager { public final GameServer server; public AnnouncementManager(GameServer server){ this.server = server; loadConfig(); } Map announceConfigItemMap = new HashMap<>(); private int loadConfig() { try (var fileReader = new InputStreamReader(DataLoader.load("Announcement.json"))) { List announceConfigItems = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(List.class, AnnounceConfigItem.class).getType()); announceConfigItemMap = new HashMap<>(); announceConfigItems.forEach(i -> announceConfigItemMap.put(i.getTemplateId(), i)); } catch (Exception e) { Grasscutter.getLogger().error("Unable to load server announce config.", e); } return announceConfigItemMap.size(); } public List getOnlinePlayers() { return getServer().getWorlds().stream() .map(World::getPlayers) .flatMap(Collection::stream) .toList(); } public void broadcast(List tpl) { if(tpl == null || tpl.size() == 0){ return; } var list = tpl.stream() .map(AnnounceConfigItem::toProto) .map(AnnounceDataOuterClass.AnnounceData.Builder::build) .toList(); getOnlinePlayers().forEach(i -> i.sendPacket(new PacketServerAnnounceNotify(list))); } public int refresh() { return loadConfig(); } public void revoke(int tplId) { getOnlinePlayers().forEach(i -> i.sendPacket(new PacketServerAnnounceRevokeNotify(tplId))); } @Data @FieldDefaults(level = AccessLevel.PRIVATE) public class AnnounceConfigItem{ int templateId; AnnounceType type; int frequency; String content; Date beginTime; Date endTime; boolean tick; int interval; public AnnounceDataOuterClass.AnnounceData.Builder toProto(){ var proto = AnnounceDataOuterClass.AnnounceData.newBuilder(); proto.setConfigId(templateId) // I found the time here is useless .setBeginTime(Utils.getCurrentSeconds() + 1) .setEndTime(Utils.getCurrentSeconds() + 10); if(type == AnnounceType.CENTER){ proto.setCenterSystemText(content) .setCenterSystemFrequency(frequency) ; }else{ proto.setCountDownText(content) .setCountDownFrequency(frequency) ; } return proto; } } public enum AnnounceType{ CENTER, COUNTDOWN } }