From 7789df6d4d45cb941586802276597a390146b440 Mon Sep 17 00:00:00 2001 From: Yazawazi <47273265+Yazawazi@users.noreply.github.com> Date: Wed, 27 Apr 2022 13:10:50 +0800 Subject: [PATCH 01/31] Task Improvement --- src/main/java/emu/grasscutter/task/Task.java | 4 + .../emu/grasscutter/task/TaskHandler.java | 19 +++-- .../java/emu/grasscutter/task/TaskMap.java | 73 +++++++++++++++---- .../emu/grasscutter/task/tasks/MoonCard.java | 13 ++-- 4 files changed, 80 insertions(+), 29 deletions(-) diff --git a/src/main/java/emu/grasscutter/task/Task.java b/src/main/java/emu/grasscutter/task/Task.java index 34638a777..1f35d16ce 100644 --- a/src/main/java/emu/grasscutter/task/Task.java +++ b/src/main/java/emu/grasscutter/task/Task.java @@ -1,5 +1,7 @@ package emu.grasscutter.task; +import org.quartz.JobDataMap; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -27,4 +29,6 @@ public @interface Task { String taskName() default "NO_NAME"; String taskCronExpression() default "0 0 0 0 0 ?"; String triggerName() default "NO_NAME"; + boolean executeImmediatelyAfterReset() default false; + boolean executeImmediately() default false; } diff --git a/src/main/java/emu/grasscutter/task/TaskHandler.java b/src/main/java/emu/grasscutter/task/TaskHandler.java index e1a160a07..c61f45534 100644 --- a/src/main/java/emu/grasscutter/task/TaskHandler.java +++ b/src/main/java/emu/grasscutter/task/TaskHandler.java @@ -1,11 +1,18 @@ package emu.grasscutter.task; -import org.quartz.Job; -import org.quartz.JobExecutionContext; -import org.quartz.JobExecutionException; +import org.quartz.*; -public interface TaskHandler extends Job { - default void execute(JobExecutionContext context) throws JobExecutionException { - +@PersistJobDataAfterExecution +public class TaskHandler implements Job { + + public void restartExecute() throws JobExecutionException { + execute(null); } + + @Override + public void execute(JobExecutionContext context) throws JobExecutionException { + // TODO Auto-generated method stub + + } + } diff --git a/src/main/java/emu/grasscutter/task/TaskMap.java b/src/main/java/emu/grasscutter/task/TaskMap.java index 077ff1f59..9e6c1efca 100644 --- a/src/main/java/emu/grasscutter/task/TaskMap.java +++ b/src/main/java/emu/grasscutter/task/TaskMap.java @@ -1,20 +1,9 @@ package emu.grasscutter.task; import emu.grasscutter.Grasscutter; -import emu.grasscutter.game.Account; -import emu.grasscutter.game.player.Player; -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.*; import org.quartz.impl.StdSchedulerFactory; -import org.quartz.spi.MutableTrigger; import org.reflections.Reflections; import java.util.*; @@ -23,6 +12,7 @@ import java.util.*; public final class TaskMap { private final Map tasks = new HashMap<>(); private final Map annotations = new HashMap<>(); + private final Map afterReset = new HashMap<>(); private final SchedulerFactory schedulerFactory = new StdSchedulerFactory(); public TaskMap() { @@ -37,6 +27,44 @@ public final class TaskMap { return Grasscutter.getGameServer().getTaskMap(); } + public void resetNow() { + // Unregister all tasks + for (TaskHandler task : this.tasks.values()) { + unregisterTask(task.getClass().getAnnotation(Task.class).taskName()); + } + + // 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(String taskName) { + this.tasks.remove(taskName); + this.annotations.remove(taskName); + + try { + Scheduler scheduler = schedulerFactory.getScheduler(); + scheduler.deleteJob(new JobKey(taskName)); + } catch (SchedulerException e) { + e.printStackTrace(); + } + + return this; + } + public TaskMap registerTask(String taskName, TaskHandler task) { Task annotation = task.getClass().getAnnotation(Task.class); this.annotations.put(taskName, annotation); @@ -56,7 +84,10 @@ public final class TaskMap { .build(); scheduler.scheduleJob(job, convTrigger); - scheduler.start(); + + if (annotation.executeImmediately()) { + task.execute(null); + } } catch (SchedulerException e) { e.printStackTrace(); } @@ -83,12 +114,24 @@ public final class TaskMap { try { Task taskData = annotated.getAnnotation(Task.class); Object object = annotated.newInstance(); - if (object instanceof TaskHandler) + if (object instanceof TaskHandler) { 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) { Grasscutter.getLogger().error("Failed to register task handler for " + annotated.getSimpleName(), exception); } }); + try { + Scheduler scheduler = schedulerFactory.getScheduler(); + scheduler.start(); + } catch (SchedulerException e) { + e.printStackTrace(); + } + } } diff --git a/src/main/java/emu/grasscutter/task/tasks/MoonCard.java b/src/main/java/emu/grasscutter/task/tasks/MoonCard.java index 45c04586e..21ac60c97 100644 --- a/src/main/java/emu/grasscutter/task/tasks/MoonCard.java +++ b/src/main/java/emu/grasscutter/task/tasks/MoonCard.java @@ -1,27 +1,24 @@ package emu.grasscutter.task.tasks; -import emu.grasscutter.database.DatabaseManager; -import emu.grasscutter.game.player.Player; +import emu.grasscutter.Grasscutter; import emu.grasscutter.task.Task; import emu.grasscutter.task.TaskHandler; -import java.util.List; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; @Task(taskName = "MoonCard", taskCronExpression = "0 0 0 * * ?", triggerName = "MoonCardTrigger") // 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 execute(JobExecutionContext context) throws JobExecutionException { - List players = DatabaseManager.getDatastore().find(Player.class).stream().toList(); - for (Player player : players) { + public synchronized void execute(JobExecutionContext context) throws JobExecutionException { + Grasscutter.getGameServer().getPlayers().forEach((uid, player) -> { if (player.isOnline()) { if (player.inMoonCard()) { player.getTodayMoonCard(); } } - } + }); } } From 2374c53ec313654ae7625a26520aee64f0552f04 Mon Sep 17 00:00:00 2001 From: Yazawazi <47273265+Yazawazi@users.noreply.github.com> Date: Wed, 27 Apr 2022 17:30:16 +0800 Subject: [PATCH 02/31] onEnable & onDisable --- src/main/java/emu/grasscutter/task/TaskHandler.java | 8 ++++++++ src/main/java/emu/grasscutter/task/TaskMap.java | 13 ++++++++----- .../java/emu/grasscutter/task/tasks/MoonCard.java | 11 +++++++++++ 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/main/java/emu/grasscutter/task/TaskHandler.java b/src/main/java/emu/grasscutter/task/TaskHandler.java index c61f45534..ea6fe22cd 100644 --- a/src/main/java/emu/grasscutter/task/TaskHandler.java +++ b/src/main/java/emu/grasscutter/task/TaskHandler.java @@ -9,6 +9,14 @@ public class TaskHandler implements Job { execute(null); } + public void onEnable() { + + } + + public void onDisable() { + + } + @Override public void execute(JobExecutionContext context) throws JobExecutionException { // TODO Auto-generated method stub diff --git a/src/main/java/emu/grasscutter/task/TaskMap.java b/src/main/java/emu/grasscutter/task/TaskMap.java index 9e6c1efca..fe067e795 100644 --- a/src/main/java/emu/grasscutter/task/TaskMap.java +++ b/src/main/java/emu/grasscutter/task/TaskMap.java @@ -30,7 +30,7 @@ public final class TaskMap { public void resetNow() { // Unregister all tasks for (TaskHandler task : this.tasks.values()) { - unregisterTask(task.getClass().getAnnotation(Task.class).taskName()); + unregisterTask(task); } // Run all afterReset tasks @@ -51,17 +51,19 @@ public final class TaskMap { } } - public TaskMap unregisterTask(String taskName) { - this.tasks.remove(taskName); - this.annotations.remove(taskName); + 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(taskName)); + scheduler.deleteJob(new JobKey(task.getClass().getAnnotation(Task.class).taskName())); } catch (SchedulerException e) { e.printStackTrace(); } + task.onDisable(); + return this; } @@ -88,6 +90,7 @@ public final class TaskMap { if (annotation.executeImmediately()) { task.execute(null); } + task.onEnable(); } catch (SchedulerException e) { e.printStackTrace(); } diff --git a/src/main/java/emu/grasscutter/task/tasks/MoonCard.java b/src/main/java/emu/grasscutter/task/tasks/MoonCard.java index 21ac60c97..51088f46d 100644 --- a/src/main/java/emu/grasscutter/task/tasks/MoonCard.java +++ b/src/main/java/emu/grasscutter/task/tasks/MoonCard.java @@ -11,6 +11,17 @@ import org.quartz.JobExecutionException; @Task(taskName = "MoonCard", taskCronExpression = "0 0 0 * * ?", triggerName = "MoonCardTrigger") // taskCronExpression: Fixed time period: 0:0:0 every day (twenty-four hour system) 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 public synchronized void execute(JobExecutionContext context) throws JobExecutionException { Grasscutter.getGameServer().getPlayers().forEach((uid, player) -> { From 8b614d8df84dce58bbfe71f29b06b0644aa8ca09 Mon Sep 17 00:00:00 2001 From: Kengxxiao <11478651+Kengxxiao@users.noreply.github.com> Date: Wed, 27 Apr 2022 17:42:02 +0800 Subject: [PATCH 03/31] implement simple drop system --- data/Drop.json | 14 +++ .../emu/grasscutter/game/drop/DropData.java | 57 +++++++++++ .../emu/grasscutter/game/drop/DropInfo.java | 16 +++ .../grasscutter/game/drop/DropManager.java | 99 +++++++++++++++++++ .../grasscutter/game/entity/EntityItem.java | 25 ++++- .../emu/grasscutter/game/player/Player.java | 31 +++--- .../emu/grasscutter/game/world/Scene.java | 33 +++---- .../grasscutter/server/game/GameServer.java | 17 +++- 8 files changed, 254 insertions(+), 38 deletions(-) create mode 100644 data/Drop.json create mode 100644 src/main/java/emu/grasscutter/game/drop/DropData.java create mode 100644 src/main/java/emu/grasscutter/game/drop/DropInfo.java create mode 100644 src/main/java/emu/grasscutter/game/drop/DropManager.java diff --git a/data/Drop.json b/data/Drop.json new file mode 100644 index 000000000..dfa37e8c8 --- /dev/null +++ b/data/Drop.json @@ -0,0 +1,14 @@ +[ + { + "monsterId": 20010201, + "dropDataList": [ + { + "itemId": 223, + "minCount": 1, + "maxCount": 100, + "minWeight": 0, + "maxWeight": 10000 + } + ] + } +] \ No newline at end of file diff --git a/src/main/java/emu/grasscutter/game/drop/DropData.java b/src/main/java/emu/grasscutter/game/drop/DropData.java new file mode 100644 index 000000000..dd4d07b40 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/drop/DropData.java @@ -0,0 +1,57 @@ +package emu.grasscutter.game.drop; + +public class DropData { + private int minWeight; + private int maxWeight; + private int itemId; + private int minCount; + private int maxCount; + private boolean share = false; + + public int getItemId() { + return itemId; + } + + public void setItemId(int itemId) { + this.itemId = itemId; + } + + public int getMinCount() { + return minCount; + } + + + public int getMaxCount() { + return maxCount; + } + + + public int getMinWeight() { + return minWeight; + } + + public int getMaxWeight() { + return maxWeight; + } + + + public boolean isShare() { + return share; + } + + public void setIsShare(boolean share) { + this.share = share; + } + + public boolean isGive() { + return give; + } + + private boolean give = false; + + public boolean isExp() { + return exp; + } + + private boolean exp = false; +} diff --git a/src/main/java/emu/grasscutter/game/drop/DropInfo.java b/src/main/java/emu/grasscutter/game/drop/DropInfo.java new file mode 100644 index 000000000..d9ccfc4c5 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/drop/DropInfo.java @@ -0,0 +1,16 @@ +package emu.grasscutter.game.drop; + +import java.util.List; + +public class DropInfo { + public int getMonsterId() { + return monsterId; + } + + public List getDropDataList() { + return dropDataList; + } + + private int monsterId; + private List dropDataList; +} diff --git a/src/main/java/emu/grasscutter/game/drop/DropManager.java b/src/main/java/emu/grasscutter/game/drop/DropManager.java new file mode 100644 index 000000000..3bea18c71 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/drop/DropManager.java @@ -0,0 +1,99 @@ +package emu.grasscutter.game.drop; + +import com.google.gson.reflect.TypeToken; +import emu.grasscutter.Grasscutter; +import emu.grasscutter.data.GameData; +import emu.grasscutter.data.def.ItemData; +import emu.grasscutter.game.entity.EntityItem; +import emu.grasscutter.game.entity.EntityMonster; +import emu.grasscutter.game.player.Player; +import emu.grasscutter.server.game.GameServer; +import emu.grasscutter.utils.Position; +import emu.grasscutter.utils.Utils; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; + +import java.io.FileReader; +import java.util.Collection; +import java.util.List; + +public class DropManager { + public GameServer getGameServer() { + return gameServer; + } + + private final GameServer gameServer; + + public Int2ObjectMap> getDropData() { + return dropData; + } + + private final Int2ObjectMap> dropData; + + public DropManager(GameServer gameServer) { + this.gameServer = gameServer; + this.dropData = new Int2ObjectOpenHashMap<>(); + this.load(); + } + + public synchronized void load() { + try (FileReader fileReader = new FileReader(Grasscutter.getConfig().DATA_FOLDER + "Drop.json")) { + getDropData().clear(); + List banners = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, DropInfo.class).getType()); + if(banners.size() > 0) { + for (DropInfo di : banners) { + getDropData().put(di.getMonsterId(), di.getDropDataList()); + } + Grasscutter.getLogger().info("Drop data successfully loaded."); + } else { + Grasscutter.getLogger().error("Unable to load drop data. Drop data size is 0."); + } + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + private void processDrop(DropData dd, EntityMonster em, Player gp) { + int target = Utils.randomRange(1, 10000); + if (target >= dd.getMinWeight() && target < dd.getMaxWeight()) { + ItemData itemData = GameData.getItemDataMap().get(dd.getItemId()); + int num = Utils.randomRange(dd.getMinCount(), dd.getMaxCount()); + if (!dd.isGive()) { + if (itemData.isEquip()) { + for (int i = 0; i < num; i++) { + float range = (5f + (.1f * num)); + Position pos = em.getPosition().clone().addX((float) (Math.random() * range) - (range / 2)).addY(3f).addZ((float) (Math.random() * range) - (range / 2)); + EntityItem entity = new EntityItem(em.getScene(), gp, itemData, pos, num, dd.isShare()); + if (!dd.isShare()) + em.getScene().addEntityToSingleClient(gp, entity); + else + em.getScene().addEntity(entity); + } + } else { + Position pos = em.getPosition().clone().addY(3f); + EntityItem entity = new EntityItem(em.getScene(), gp, itemData, pos, num, dd.isShare()); + if (!dd.isShare()) + em.getScene().addEntityToSingleClient(gp, entity); + else + em.getScene().addEntity(entity); + } + } + } + } + + public void callDrop(EntityMonster em) { + int id = em.getMonsterData().getId(); + if (getDropData().containsKey(id)) { + for (DropData dd : getDropData().get(id)) { + if (dd.isShare()) + processDrop(dd, em, null); + else { + for (Player gp : em.getScene().getPlayers()) { + processDrop(dd, em, gp); + } + } + } + } + } +} diff --git a/src/main/java/emu/grasscutter/game/entity/EntityItem.java b/src/main/java/emu/grasscutter/game/entity/EntityItem.java index 5b1e05fc7..e23c1cb33 100644 --- a/src/main/java/emu/grasscutter/game/entity/EntityItem.java +++ b/src/main/java/emu/grasscutter/game/entity/EntityItem.java @@ -6,7 +6,6 @@ import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.EntityIdType; import emu.grasscutter.game.props.PlayerProperty; import emu.grasscutter.game.world.Scene; -import emu.grasscutter.game.world.World; import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo; import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair; import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo; @@ -30,14 +29,30 @@ public class EntityItem extends EntityGadget { private final GameItem item; private final long guid; - + + private final boolean share; + public EntityItem(Scene scene, Player player, ItemData itemData, Position pos, int count) { super(scene); this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET); this.pos = new Position(pos); this.rot = new Position(); - this.guid = player.getNextGameGuid(); + this.guid = player == null ? scene.getWorld().getHost().getNextGameGuid() : player.getNextGameGuid(); this.item = new GameItem(itemData, count); + this.share = true; + } + + // In official game, some drop items are shared to all players, and some other items are independent to all players + // For example, if you killed a monster in MP mode, all players could get drops but rarity and number of them are different + // but if you broke regional mine, when someone picked up the drop then it disappeared + public EntityItem(Scene scene, Player player, ItemData itemData, Position pos, int count, boolean share) { + super(scene); + this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET); + this.pos = new Position(pos); + this.rot = new Position(); + this.guid = player == null ? scene.getWorld().getHost().getNextGameGuid() : player.getNextGameGuid(); + this.item = new GameItem(itemData, count); + this.share = share; } @Override @@ -81,6 +96,10 @@ public class EntityItem extends EntityGadget { return null; } + public boolean isShare() { + return share; + } + @Override public SceneEntityInfo toProto() { EntityAuthorityInfo authority = EntityAuthorityInfo.newBuilder() diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index 5970c3f13..2c18ce0ec 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -1,20 +1,16 @@ package emu.grasscutter.game.player; -import java.time.Instant; -import java.util.*; - import dev.morphia.annotations.*; import emu.grasscutter.GameConstants; import emu.grasscutter.Grasscutter; -import emu.grasscutter.command.CommandHandler; import emu.grasscutter.data.GameData; import emu.grasscutter.data.def.PlayerLevelData; import emu.grasscutter.database.DatabaseHelper; -import emu.grasscutter.game.avatar.AvatarProfileData; -import emu.grasscutter.game.avatar.AvatarStorage; import emu.grasscutter.game.Account; import emu.grasscutter.game.CoopRequest; import emu.grasscutter.game.avatar.Avatar; +import emu.grasscutter.game.avatar.AvatarProfileData; +import emu.grasscutter.game.avatar.AvatarStorage; import emu.grasscutter.game.entity.EntityItem; import emu.grasscutter.game.entity.GameEntity; import emu.grasscutter.game.friends.FriendsList; @@ -34,7 +30,6 @@ import emu.grasscutter.net.proto.HeadImageOuterClass.HeadImage; import emu.grasscutter.net.proto.InteractTypeOuterClass.InteractType; import emu.grasscutter.net.proto.MpSettingTypeOuterClass.MpSettingType; import emu.grasscutter.net.proto.OnlinePlayerInfoOuterClass.OnlinePlayerInfo; -import emu.grasscutter.net.proto.PlayerApplyEnterMpReasonOuterClass.PlayerApplyEnterMpReason; import emu.grasscutter.net.proto.PlayerApplyEnterMpResultNotifyOuterClass; import emu.grasscutter.net.proto.PlayerLocationInfoOuterClass.PlayerLocationInfo; import emu.grasscutter.net.proto.PlayerWorldLocationInfoOuterClass; @@ -42,11 +37,12 @@ import emu.grasscutter.net.proto.SocialDetailOuterClass.SocialDetail; import emu.grasscutter.server.game.GameServer; import emu.grasscutter.server.game.GameSession; import emu.grasscutter.server.packet.send.*; -import emu.grasscutter.utils.Position; import emu.grasscutter.utils.DateHelper; +import emu.grasscutter.utils.Position; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import java.time.Instant; import java.util.*; @Entity(value = "players", useDiscriminator = false) @@ -714,19 +710,30 @@ public class Player { return; } - // Delete - entity.getScene().removeEntity(entity); - // Handle if (entity instanceof EntityItem) { // Pick item EntityItem drop = (EntityItem) entity; + if (!drop.isShare()) // check drop owner to avoid someone picked up item in others' world + { + int dropOwner = (int)(drop.getGuid() >> 32); + if (dropOwner != getUid()) + return; + } + entity.getScene().removeEntity(entity); GameItem item = new GameItem(drop.getItemData(), drop.getCount()); // Add to inventory boolean success = getInventory().addItem(item, ActionReason.SubfieldDrop); if (success) { - this.sendPacket(new PacketGadgetInteractRsp(drop, InteractType.INTERACT_PICK_ITEM)); + + if (!drop.isShare()) // not shared drop + this.sendPacket(new PacketGadgetInteractRsp(drop, InteractType.INTERACT_PICK_ITEM)); + else + this.getScene().broadcastPacket(new PacketGadgetInteractRsp(drop, InteractType.INTERACT_PICK_ITEM)); } + } else { + // Delete directly + entity.getScene().removeEntity(entity); } return; diff --git a/src/main/java/emu/grasscutter/game/world/Scene.java b/src/main/java/emu/grasscutter/game/world/Scene.java index d9b01e0ef..543079153 100644 --- a/src/main/java/emu/grasscutter/game/world/Scene.java +++ b/src/main/java/emu/grasscutter/game/world/Scene.java @@ -1,28 +1,12 @@ 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.data.GameData; import emu.grasscutter.data.GameDepot; -import emu.grasscutter.data.GameResource; import emu.grasscutter.data.def.MonsterData; import emu.grasscutter.data.def.SceneData; import emu.grasscutter.data.def.WorldLevelData; -import emu.grasscutter.game.entity.EntityAvatar; -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.entity.*; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.TeamInfo; import emu.grasscutter.game.props.ClimateType; @@ -37,10 +21,12 @@ import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify; import emu.grasscutter.server.packet.send.PacketLifeStateChangeNotify; import emu.grasscutter.server.packet.send.PacketSceneEntityAppearNotify; 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.Int2ObjectMaps; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import org.danilopianini.util.SpatialIndex; + +import java.util.*; public class Scene { private final World world; @@ -228,6 +214,11 @@ public class Scene { this.addEntityDirectly(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 entities) { for (GameEntity entity : entities) { @@ -310,6 +301,12 @@ public class Scene { public void killEntity(GameEntity target, int attackerId) { // Packet this.broadcastPacket(new PacketLifeStateChangeNotify(attackerId, target, LifeState.LIFE_DEAD)); + + // Reward drop + if (target instanceof EntityMonster) { + Grasscutter.getGameServer().getDropManager().callDrop((EntityMonster) target); + } + this.removeEntity(target); // Death event diff --git a/src/main/java/emu/grasscutter/server/game/GameServer.java b/src/main/java/emu/grasscutter/server/game/GameServer.java index 50889fd56..257ac9fef 100644 --- a/src/main/java/emu/grasscutter/server/game/GameServer.java +++ b/src/main/java/emu/grasscutter/server/game/GameServer.java @@ -1,15 +1,11 @@ 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(); @@ -109,6 +112,10 @@ public final class GameServer extends KcpServer { public MultiplayerManager getMultiplayerManager() { return multiplayerManager; } + + public DropManager getDropManager() { + return dropManager; + } public DungeonManager getDungeonManager() { return dungeonManager; From 57e408012b03875196124f9e42681bc233e4eed6 Mon Sep 17 00:00:00 2001 From: Kengxxiao <11478651+Kengxxiao@users.noreply.github.com> Date: Wed, 27 Apr 2022 17:44:12 +0800 Subject: [PATCH 04/31] reset drop table in reload command --- .../java/emu/grasscutter/command/commands/ReloadCommand.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/emu/grasscutter/command/commands/ReloadCommand.java b/src/main/java/emu/grasscutter/command/commands/ReloadCommand.java index 26dbb903b..6a3697acb 100644 --- a/src/main/java/emu/grasscutter/command/commands/ReloadCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/ReloadCommand.java @@ -16,6 +16,7 @@ public final class ReloadCommand implements CommandHandler { CommandHandler.sendMessage(sender, "Reloading config."); Grasscutter.loadConfig(); Grasscutter.getGameServer().getGachaManager().load(); + Grasscutter.getGameServer().getDropManager().load(); Grasscutter.getDispatchServer().loadQueries(); CommandHandler.sendMessage(sender, "Reload complete."); } From 897f529e6242ada99cc1786872f63be42b0463bf Mon Sep 17 00:00:00 2001 From: Yazawazi <47273265+Yazawazi@users.noreply.github.com> Date: Wed, 27 Apr 2022 17:52:04 +0800 Subject: [PATCH 05/31] comment & mooncard --- src/main/java/emu/grasscutter/game/player/Player.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index 5970c3f13..e226b0eaf 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -901,6 +901,8 @@ public class Player { session.send(new PacketPlayerStoreNotify(this)); session.send(new PacketAvatarDataNotify(this)); + getTodayMoonCard(); // The timer works at 0:0, some users log in after that, use this method to check if they have received a reward today or not. If not, send the reward. + session.send(new PacketPlayerEnterSceneNotify(this)); // Enter game world session.send(new PacketPlayerLevelRewardUpdateNotify(rewardedLevels)); session.send(new PacketOpenStateUpdateNotify()); From 3c543e5c671dd8827d793e25426a64210634b828 Mon Sep 17 00:00:00 2001 From: memetrollsXD Date: Wed, 27 Apr 2022 14:44:36 +0200 Subject: [PATCH 06/31] Update Drop.json data/ will appear in everyones files, so better change it to something more sane --- data/Drop.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/data/Drop.json b/data/Drop.json index dfa37e8c8..1fd5dd69e 100644 --- a/data/Drop.json +++ b/data/Drop.json @@ -1,14 +1,14 @@ [ { - "monsterId": 20010201, + "monsterId": 21010101, "dropDataList": [ { - "itemId": 223, + "itemId": 112005, "minCount": 1, - "maxCount": 100, + "maxCount": 3, "minWeight": 0, "maxWeight": 10000 } ] } -] \ No newline at end of file +] From 0e3a80407ef24dbcf9b0fe6e5ca5f61eef800e3f Mon Sep 17 00:00:00 2001 From: ayy lmao Date: Wed, 27 Apr 2022 14:39:20 +0300 Subject: [PATCH 07/31] Added missing isGiftMail section to GetAllMailRsp --- .../packet/send/PacketGetAllMailRsp.java | 28 ++++--------------- 1 file changed, 5 insertions(+), 23 deletions(-) diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketGetAllMailRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketGetAllMailRsp.java index 8c8fb4b07..59af30f42 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketGetAllMailRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketGetAllMailRsp.java @@ -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 mailDataList = new ArrayList(); 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()); } } From 3e0ccbbbdea49e086b9116d7fba5433fcacc5a8c Mon Sep 17 00:00:00 2001 From: Kengxxiao <11478651+Kengxxiao@users.noreply.github.com> Date: Wed, 27 Apr 2022 18:51:48 +0800 Subject: [PATCH 08/31] implement npc shop --- data/Shop.json | 86 ++++++++++ .../command/commands/ReloadCommand.java | 1 + .../grasscutter/game/inventory/Inventory.java | 10 ++ .../emu/grasscutter/game/player/Player.java | 33 ++++ .../emu/grasscutter/game/shop/ShopInfo.java | 159 +++++++++++++++++- .../emu/grasscutter/game/shop/ShopLimit.java | 25 +++ .../grasscutter/game/shop/ShopManager.java | 38 +++++ .../packet/recv/HandlerBuyGoodsReq.java | 67 ++++++++ .../server/packet/recv/HandlerGetShopReq.java | 7 +- .../server/packet/send/PacketBuyGoodsRsp.java | 22 +++ .../server/packet/send/PacketGetShopRsp.java | 57 ++++++- 11 files changed, 492 insertions(+), 13 deletions(-) create mode 100644 data/Shop.json create mode 100644 src/main/java/emu/grasscutter/game/shop/ShopLimit.java create mode 100644 src/main/java/emu/grasscutter/server/packet/recv/HandlerBuyGoodsReq.java create mode 100644 src/main/java/emu/grasscutter/server/packet/send/PacketBuyGoodsRsp.java diff --git a/data/Shop.json b/data/Shop.json new file mode 100644 index 000000000..85d6ad9e8 --- /dev/null +++ b/data/Shop.json @@ -0,0 +1,86 @@ +[ + { + "shopId": 1004, + "goodsId": 1004202, + "goodsItem": { + "Id": 202, + "Count": 1000000 + }, + "scoin": 1, + "buyLimit": 500, + "beginTime": 1575129600, + "endTime": 2051193600, + "minLevel": 1, + "maxLevel": 99 + }, + { + "shopId": 1004, + "goodsId": 10048006, + "goodsItem": { + "Id": 108006, + "Count": 20 + }, + "scoin": 1, + "buyLimit": 50000, + "beginTime": 1575129600, + "endTime": 2051193600, + "minLevel": 1, + "maxLevel": 99 + }, + { + "shopId": 1004, + "goodsId": 10048033, + "goodsItem": { + "Id": 108033, + "Count": 20 + }, + "scoin": 1, + "buyLimit": 50000, + "beginTime": 1575129600, + "endTime": 2051193600, + "minLevel": 1, + "maxLevel": 99 + }, + { + "shopId": 1004, + "goodsId": 10040008, + "goodsItem": { + "Id": 220008, + "Count": 1 + }, + "scoin": 1, + "buyLimit": 1, + "beginTime": 1575129600, + "endTime": 2051193600, + "minLevel": 1, + "maxLevel": 99 + }, + { + "shopId": 1004, + "goodsId": 10044003, + "goodsItem": { + "Id": 104003, + "Count": 200 + }, + "scoin": 1, + "buyLimit": 50000, + "beginTime": 1575129600, + "endTime": 2051193600, + "minLevel": 1, + "maxLevel": 99 + }, + { + "shopId": 1004, + "goodsId": 10044013, + "goodsItem": { + "Id": 104013, + "Count": 200 + }, + "scoin": 1, + "buyLimit": 50000, + "beginTime": 1575129600, + "endTime": 2051193600, + "minLevel": 1, + "maxLevel": 99 + } +] \ No newline at end of file diff --git a/src/main/java/emu/grasscutter/command/commands/ReloadCommand.java b/src/main/java/emu/grasscutter/command/commands/ReloadCommand.java index 26dbb903b..bad97a20a 100644 --- a/src/main/java/emu/grasscutter/command/commands/ReloadCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/ReloadCommand.java @@ -16,6 +16,7 @@ public final class ReloadCommand implements CommandHandler { CommandHandler.sendMessage(sender, "Reloading config."); Grasscutter.loadConfig(); Grasscutter.getGameServer().getGachaManager().load(); + Grasscutter.getGameServer().getShopManager().load(); Grasscutter.getDispatchServer().loadQueries(); CommandHandler.sendMessage(sender, "Reload complete."); } diff --git a/src/main/java/emu/grasscutter/game/inventory/Inventory.java b/src/main/java/emu/grasscutter/game/inventory/Inventory.java index bb8dfad46..d407e077b 100644 --- a/src/main/java/emu/grasscutter/game/inventory/Inventory.java +++ b/src/main/java/emu/grasscutter/game/inventory/Inventory.java @@ -109,6 +109,16 @@ public class Inventory implements Iterable { return result; } + + public boolean addItem(GameItem item, ActionReason reason, boolean forceNotify) { + boolean result = addItem(item); + + if (reason != null && (forceNotify || result)) { + getPlayer().sendPacket(new PacketItemAddHintNotify(item, reason)); + } + + return result; + } public void addItems(Collection items) { this.addItems(items, null); diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index 5970c3f13..059292497 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -25,6 +25,7 @@ import emu.grasscutter.game.inventory.Inventory; import emu.grasscutter.game.mail.Mail; import emu.grasscutter.game.props.ActionReason; import emu.grasscutter.game.props.PlayerProperty; +import emu.grasscutter.game.shop.ShopLimit; import emu.grasscutter.game.world.Scene; import emu.grasscutter.game.world.World; import emu.grasscutter.net.packet.BasePacket; @@ -84,6 +85,7 @@ public class Player { private ArrayList shownAvatars; private Set rewardedLevels; private ArrayList mail; + private ArrayList shopLimit; private int sceneId; private int regionId; @@ -141,6 +143,8 @@ public class Player { this.birthday = new PlayerBirthday(); this.rewardedLevels = new HashSet<>(); this.moonCardGetTimes = new HashSet<>(); + + this.shopLimit = new ArrayList<>(); } // On player creation @@ -592,6 +596,35 @@ public class Player { session.send(new PacketCardProductRewardNotify(getMoonCardRemainDays())); } + public List getShopLimit() { + return shopLimit; + } + + public int getGoodsLimitNum(int goodsId) { + for (ShopLimit sl : getShopLimit()) { + if (sl.getShopGoodId() == goodsId) + return sl.getHasBought(); + } + return 0; + } + + public void addShopLimit(int goodsId, int boughtCount) { + boolean found = false; + for (ShopLimit sl : getShopLimit()) { + if (sl.getShopGoodId() == goodsId){ + sl.setHasBought(sl.getHasBought() + boughtCount); + found = true; + } + } + if (!found) { + ShopLimit sl = new ShopLimit(); + sl.setShopGoodId(goodsId); + sl.setHasBought(boughtCount); + shopLimit.add(sl); + } + this.save(); + } + public boolean inGodmode() { return godmode; } diff --git a/src/main/java/emu/grasscutter/game/shop/ShopInfo.java b/src/main/java/emu/grasscutter/game/shop/ShopInfo.java index 768a3a7ca..510f0d479 100644 --- a/src/main/java/emu/grasscutter/game/shop/ShopInfo.java +++ b/src/main/java/emu/grasscutter/game/shop/ShopInfo.java @@ -1,5 +1,162 @@ package emu.grasscutter.game.shop; -public class ShopInfo { +import emu.grasscutter.data.common.ItemParamData; +import java.util.ArrayList; +import java.util.List; + +public class ShopInfo { + public int shopId = 1004; + public int goodsId = 0; + public ItemParamData goodsItem; + public int scoin = 0; + public List costItemList; + public int boughtNum = 0; + public int buyLimit = 0; + public int beginTime = 0; + public int endTime = 1924992000; + public int nextRefreshTime = 1924992000; + public int minLevel = 0; + public int maxLevel = 61; + public List preGoodsIdList = new ArrayList<>(); + public int mcoin = 0; + public int hcoin = 0; + public int disableType = 0; + public int secondarySheetId = 0; + + public int getHcoin() { + return hcoin; + } + + public void setHcoin(int hcoin) { + this.hcoin = hcoin; + } + + public List getPreGoodsIdList() { + return preGoodsIdList; + } + + public void setPreGoodsIdList(List preGoodsIdList) { + this.preGoodsIdList = preGoodsIdList; + } + + public int getMcoin() { + return mcoin; + } + + public void setMcoin(int mcoin) { + this.mcoin = mcoin; + } + + public int getDisableType() { + return disableType; + } + + public void setDisableType(int disableType) { + this.disableType = disableType; + } + + public int getSecondarySheetId() { + return secondarySheetId; + } + + public void setSecondarySheetId(int secondarySheetId) { + this.secondarySheetId = secondarySheetId; + } + + public int getShopId() { + return shopId; + } + + public void setShopId(int shopId) { + this.shopId = shopId; + } + + public int getGoodsId() { + return goodsId; + } + + public void setGoodsId(int goodsId) { + this.goodsId = goodsId; + } + + public ItemParamData getGoodsItem() { + return goodsItem; + } + + public void setGoodsItem(ItemParamData goodsItem) { + this.goodsItem = goodsItem; + } + + public int getScoin() { + return scoin; + } + + public void setScoin(int scoin) { + this.scoin = scoin; + } + + public List getCostItemList() { + return costItemList; + } + + public void setCostItemList(List costItemList) { + this.costItemList = costItemList; + } + + public int getBoughtNum() { + return boughtNum; + } + + public void setBoughtNum(int boughtNum) { + this.boughtNum = boughtNum; + } + + public int getBuyLimit() { + return buyLimit; + } + + public void setBuyLimit(int buyLimit) { + this.buyLimit = buyLimit; + } + + public int getBeginTime() { + return beginTime; + } + + public void setBeginTime(int beginTime) { + this.beginTime = beginTime; + } + + public int getEndTime() { + return endTime; + } + + public void setEndTime(int endTime) { + this.endTime = endTime; + } + + public int getNextRefreshTime() { + return nextRefreshTime; + } + + public void setNextRefreshTime(int nextRefreshTime) { + this.nextRefreshTime = nextRefreshTime; + } + + public int getMinLevel() { + return minLevel; + } + + public void setMinLevel(int minLevel) { + this.minLevel = minLevel; + } + + public int getMaxLevel() { + return maxLevel; + } + + public void setMaxLevel(int maxLevel) { + this.maxLevel = maxLevel; + } } diff --git a/src/main/java/emu/grasscutter/game/shop/ShopLimit.java b/src/main/java/emu/grasscutter/game/shop/ShopLimit.java new file mode 100644 index 000000000..ded87102e --- /dev/null +++ b/src/main/java/emu/grasscutter/game/shop/ShopLimit.java @@ -0,0 +1,25 @@ +package emu.grasscutter.game.shop; + +import dev.morphia.annotations.Entity; + +@Entity +public class ShopLimit { + public int getShopGoodId() { + return shopGoodId; + } + + public void setShopGoodId(int shopGoodId) { + this.shopGoodId = shopGoodId; + } + + public int getHasBought() { + return hasBought; + } + + public void setHasBought(int hasBought) { + this.hasBought = hasBought; + } + + private int shopGoodId; + private int hasBought; +} diff --git a/src/main/java/emu/grasscutter/game/shop/ShopManager.java b/src/main/java/emu/grasscutter/game/shop/ShopManager.java index a21888f25..e591aa65e 100644 --- a/src/main/java/emu/grasscutter/game/shop/ShopManager.java +++ b/src/main/java/emu/grasscutter/game/shop/ShopManager.java @@ -1,12 +1,50 @@ package emu.grasscutter.game.shop; +import com.google.gson.reflect.TypeToken; +import emu.grasscutter.Grasscutter; 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.List; public class ShopManager { private final GameServer server; + + public Int2ObjectMap> getShopData() { + return shopData; + } + + private final Int2ObjectMap> shopData; public ShopManager(GameServer server) { this.server = server; + this.shopData = new Int2ObjectOpenHashMap<>(); + this.load(); + } + + public synchronized void load() { + try (FileReader fileReader = new FileReader(Grasscutter.getConfig().DATA_FOLDER + "Shop.json")) { + getShopData().clear(); + List banners = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, ShopInfo.class).getType()); + if(banners.size() > 0) { + for (ShopInfo shopInfo : banners) { + if (!getShopData().containsKey(shopInfo.getShopId())) + getShopData().put(shopInfo.getShopId(), new ArrayList<>()); + getShopData().get(shopInfo.getShopId()).add(shopInfo); + Grasscutter.getLogger().info(String.format("Shop add: id [%d], data [%d*%d]", shopInfo.getShopId(), shopInfo.getGoodsItem().getId(), shopInfo.getGoodsItem().getCount())); + } + Grasscutter.getLogger().info("Shop data successfully loaded."); + } else { + Grasscutter.getLogger().error("Unable to load shop data. Shop data size is 0."); + } + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } public GameServer getServer() { diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerBuyGoodsReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerBuyGoodsReq.java new file mode 100644 index 000000000..c83808ada --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerBuyGoodsReq.java @@ -0,0 +1,67 @@ +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().getProperty(PlayerProperty.PROP_PLAYER_MCOIN) < buyGoodsReq.getBoughtNum() * sg.getMcoin()) { + return; + } + + HashMap itemsCache = new HashMap<>(); + for (ItemParamOuterClass.ItemParam p : sg.getCostItemListList()) { + Optional 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().setProperty(PlayerProperty.PROP_PLAYER_MCOIN, session.getPlayer().getProperty(PlayerProperty.PROP_PLAYER_MCOIN) - 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(); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetShopReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetShopReq.java index 9b7c6e96d..1dbe1c3ff 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetShopReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetShopReq.java @@ -1,9 +1,9 @@ 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; @@ -12,8 +12,7 @@ public class HandlerGetShopReq extends PacketHandler { @Override 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())); } } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketBuyGoodsRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketBuyGoodsRsp.java new file mode 100644 index 000000000..07371440d --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketBuyGoodsRsp.java @@ -0,0 +1,22 @@ +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); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketGetShopRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketGetShopRsp.java index 64d415763..4f57c72e6 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketGetShopRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketGetShopRsp.java @@ -1,19 +1,60 @@ 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(); - - this.setData(proto); + // 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 list = manager.getShopData().get(shopType); + List 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()); } } From ee3a0c32fc89413d34433a661e8f4584d9102e9e Mon Sep 17 00:00:00 2001 From: Kengxxiao <11478651+Kengxxiao@users.noreply.github.com> Date: Wed, 27 Apr 2022 19:56:53 +0800 Subject: [PATCH 09/31] use better shop config structure --- data/Shop.json | 130 +++++++----------- .../emu/grasscutter/game/shop/ShopInfo.java | 41 +++--- .../grasscutter/game/shop/ShopManager.java | 12 +- .../emu/grasscutter/game/shop/ShopTable.java | 25 ++++ 4 files changed, 94 insertions(+), 114 deletions(-) create mode 100644 src/main/java/emu/grasscutter/game/shop/ShopTable.java diff --git a/data/Shop.json b/data/Shop.json index 85d6ad9e8..9670b0bfc 100644 --- a/data/Shop.json +++ b/data/Shop.json @@ -1,86 +1,54 @@ [ { "shopId": 1004, - "goodsId": 1004202, - "goodsItem": { - "Id": 202, - "Count": 1000000 - }, - "scoin": 1, - "buyLimit": 500, - "beginTime": 1575129600, - "endTime": 2051193600, - "minLevel": 1, - "maxLevel": 99 - }, - { - "shopId": 1004, - "goodsId": 10048006, - "goodsItem": { - "Id": 108006, - "Count": 20 - }, - "scoin": 1, - "buyLimit": 50000, - "beginTime": 1575129600, - "endTime": 2051193600, - "minLevel": 1, - "maxLevel": 99 - }, - { - "shopId": 1004, - "goodsId": 10048033, - "goodsItem": { - "Id": 108033, - "Count": 20 - }, - "scoin": 1, - "buyLimit": 50000, - "beginTime": 1575129600, - "endTime": 2051193600, - "minLevel": 1, - "maxLevel": 99 - }, - { - "shopId": 1004, - "goodsId": 10040008, - "goodsItem": { - "Id": 220008, - "Count": 1 - }, - "scoin": 1, - "buyLimit": 1, - "beginTime": 1575129600, - "endTime": 2051193600, - "minLevel": 1, - "maxLevel": 99 - }, - { - "shopId": 1004, - "goodsId": 10044003, - "goodsItem": { - "Id": 104003, - "Count": 200 - }, - "scoin": 1, - "buyLimit": 50000, - "beginTime": 1575129600, - "endTime": 2051193600, - "minLevel": 1, - "maxLevel": 99 - }, - { - "shopId": 1004, - "goodsId": 10044013, - "goodsItem": { - "Id": 104013, - "Count": 200 - }, - "scoin": 1, - "buyLimit": 50000, - "beginTime": 1575129600, - "endTime": 2051193600, - "minLevel": 1, - "maxLevel": 99 + "items": [ + { + "goodsId": 1004202, + "goodsItem": { + "Id": 202, + "Count": 1000000 + }, + "scoin": 1, + "buyLimit": 500, + "beginTime": 1575129600, + "endTime": 2051193600, + "minLevel": 1, + "maxLevel": 99, + "costItemList": [ + { + "Id": 223, + "Count": 100 + } + ] + }, + { + "goodsId": 10048006, + "goodsItem": { + "Id": 108006, + "Count": 20 + }, + "scoin": 100, + "hcoin": 100, + "mcoin": 100, + "buyLimit": 50000, + "beginTime": 1575129600, + "endTime": 2051193600, + "minLevel": 1, + "maxLevel": 99 + }, + { + "goodsId": 10048033, + "goodsItem": { + "Id": 108033, + "Count": 20 + }, + "scoin": 1, + "buyLimit": 50000, + "beginTime": 1575129600, + "endTime": 2051193600, + "minLevel": 1, + "maxLevel": 99 + } + ] } ] \ No newline at end of file diff --git a/src/main/java/emu/grasscutter/game/shop/ShopInfo.java b/src/main/java/emu/grasscutter/game/shop/ShopInfo.java index 510f0d479..b0e3b819b 100644 --- a/src/main/java/emu/grasscutter/game/shop/ShopInfo.java +++ b/src/main/java/emu/grasscutter/game/shop/ShopInfo.java @@ -6,23 +6,22 @@ import java.util.ArrayList; import java.util.List; public class ShopInfo { - public int shopId = 1004; - public int goodsId = 0; - public ItemParamData goodsItem; - public int scoin = 0; - public List costItemList; - public int boughtNum = 0; - public int buyLimit = 0; - public int beginTime = 0; - public int endTime = 1924992000; - public int nextRefreshTime = 1924992000; - public int minLevel = 0; - public int maxLevel = 61; - public List preGoodsIdList = new ArrayList<>(); - public int mcoin = 0; - public int hcoin = 0; - public int disableType = 0; - public int secondarySheetId = 0; + private int goodsId = 0; + private ItemParamData goodsItem; + private int scoin = 0; + private List costItemList; + private int boughtNum = 0; + private int buyLimit = 0; + private int beginTime = 0; + private int endTime = 1924992000; + private int nextRefreshTime = 1924992000; + private int minLevel = 0; + private int maxLevel = 61; + private List preGoodsIdList = new ArrayList<>(); + private int mcoin = 0; + private int hcoin = 0; + private int disableType = 0; + private int secondarySheetId = 0; public int getHcoin() { return hcoin; @@ -64,14 +63,6 @@ public class ShopInfo { this.secondarySheetId = secondarySheetId; } - public int getShopId() { - return shopId; - } - - public void setShopId(int shopId) { - this.shopId = shopId; - } - public int getGoodsId() { return goodsId; } diff --git a/src/main/java/emu/grasscutter/game/shop/ShopManager.java b/src/main/java/emu/grasscutter/game/shop/ShopManager.java index e591aa65e..63436e517 100644 --- a/src/main/java/emu/grasscutter/game/shop/ShopManager.java +++ b/src/main/java/emu/grasscutter/game/shop/ShopManager.java @@ -7,7 +7,6 @@ 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.List; @@ -19,7 +18,7 @@ public class ShopManager { } private final Int2ObjectMap> shopData; - + public ShopManager(GameServer server) { this.server = server; this.shopData = new Int2ObjectOpenHashMap<>(); @@ -29,13 +28,10 @@ public class ShopManager { public synchronized void load() { try (FileReader fileReader = new FileReader(Grasscutter.getConfig().DATA_FOLDER + "Shop.json")) { getShopData().clear(); - List banners = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, ShopInfo.class).getType()); + List banners = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, ShopTable.class).getType()); if(banners.size() > 0) { - for (ShopInfo shopInfo : banners) { - if (!getShopData().containsKey(shopInfo.getShopId())) - getShopData().put(shopInfo.getShopId(), new ArrayList<>()); - getShopData().get(shopInfo.getShopId()).add(shopInfo); - Grasscutter.getLogger().info(String.format("Shop add: id [%d], data [%d*%d]", shopInfo.getShopId(), shopInfo.getGoodsItem().getId(), shopInfo.getGoodsItem().getCount())); + for (ShopTable shopTable : banners) { + getShopData().put(shopTable.getShopId(), shopTable.getItems()); } Grasscutter.getLogger().info("Shop data successfully loaded."); } else { diff --git a/src/main/java/emu/grasscutter/game/shop/ShopTable.java b/src/main/java/emu/grasscutter/game/shop/ShopTable.java new file mode 100644 index 000000000..7396cd028 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/shop/ShopTable.java @@ -0,0 +1,25 @@ +package emu.grasscutter.game.shop; + +import java.util.ArrayList; +import java.util.List; + +public class ShopTable { + private int shopId; + private List items = new ArrayList<>(); + + public int getShopId() { + return shopId; + } + + public void setShopId(int shopId) { + this.shopId = shopId; + } + + public List getItems() { + return items; + } + + public void setItems(List items) { + this.items = items; + } +} From e1b6cbc87e9a3bb643495b3c60bf0e27495e2e9d Mon Sep 17 00:00:00 2001 From: xmplay <81370285+xmplay@users.noreply.github.com> Date: Wed, 27 Apr 2022 15:58:47 +0100 Subject: [PATCH 10/31] fix readme again (bruh moment) --- README.md | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index d32e1ca9e..de9e8e7e2 100644 --- a/README.md +++ b/README.md @@ -14,19 +14,19 @@ EN | [中文](README_zh-CN.md) * Friends list * Teleportation * Gacha system -* Co-op *partially* work +* Co-op *partially* works * Spawning monsters via console * Inventory features (recieving items/characters, upgrading items/characters, etc) ## Quick setup guide -**Note:** for support please join our [Discord](https://discord.gg/T5vZU6UyeG) +**Note:** For support please join our [Discord](https://discord.gg/T5vZU6UyeG). ### Requirements -* Java SE - 17 ([mirror link](https://github.com/adoptium/temurin17-binaries/releases/tag/jdk-17.0.3+7) since Oracle required an account to download old builds) +* Java SE - 17 ([link](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html)) - **Note:** If you just want to **run it**, then **jre** is fine + **Note:** If you just want to **run it**, then **jre** only is fine. * MongoDB (recommended 4.0+) @@ -34,12 +34,12 @@ EN | [中文](README_zh-CN.md) ### Running -**Note:** If you update from an older version, delete `config.json` for regeneration +**Note:** If you updated from an older version, delete `config.json` to regenerate it. 1. Get `grasscutter.jar` - Download from [actions](https://nightly.link/Grasscutters/Grasscutter/workflows/build/stable/Grasscutter.zip) - [Build by yourself](#Building) -2. Create a `resources` folder in the directory where grasscutter.jar is located and bring your `BinOutput` and `ExcelBinOutput` folders into it *(Check the [wiki](https://github.com/Grasscutters/Grasscutter/wiki) for more details how to get those.)* +2. Create a `resources` folder in the directory where grasscutter.jar is located and move your `BinOutput` and `ExcelBinOutput` folders there *(Check the [wiki](https://github.com/Grasscutters/Grasscutter/wiki) for more details how to get those.)* 3. Run Grasscutter with `java -jar grasscutter.jar`. **Make sure mongodb service is running as well.** ### Connecting with the client @@ -96,7 +96,7 @@ chmod +x gradlew ./gradlew jar # Compile ``` -You can find the output jar in the root of the project folder +You can find the output jar in the root of the project folder. ## Commands @@ -106,32 +106,32 @@ There is a dummy user named "Server" in every player's friends list that you can | Commands | Usage | Permission node | Availability | description | Alias | | -------------- | ------------------------------------------------- | ------------------------- | ------------ | ------------------------------------------------------------ | ----------------------------------------------- | -| account | account [uid] | | Server only | Creates an account with the specified username and the in-game uid for that account. The uid will be auto generated if not set. | | +| account | account [UID] | | Server only | Creates an account with the specified username and the in-game UID for that account. The UID will be auto generated if not set. | | | broadcast | broadcast | server.broadcast | Both side | Sends a message to all the players. | b | | changescene | changescene | player.changescene | Client only | Switch scenes by scene ID. | scene | -| clearartifacts | clearartifacts | player.clearartifacts | Client only | Deletes all unequipped and unlocked level 0 artifacts, including yellow rarity ones from your inventory. | clearart | -| clearweapons | clearweapons | player.clearweapons | Client only | Deletes all unequipped and unlocked weapons, including yellow rarity ones from your inventory. | clearwpns | +| clearartifacts | clearartifacts | player.clearartifacts | Client only | Deletes all unequipped and unlocked level 0 artifacts, including 5-star rarity ones from your inventory. | clearart | +| clearweapons | clearweapons | player.clearweapons | Client only | Deletes all unequipped and unlocked weapons, including 5-star rarity ones from your inventory. | clearwpns | | drop | drop [amount] | server.drop | Client only | Drops an item around you. | `d` `dropitem` | | give | give [player] [amount] [level] | player.give | Both side | Gives item(s) to you or the specified player. | `g` `item` `giveitem` | | givechar | givechar [level] | player.givechar | Both side | Gives the player a specified character. | givec | | godmode | godmode [uid] | player.godmode | Client only | Prevents you from taking damage. | | -| heal | heal | player.heal | Client only | Heal all characters in your current team. | h | +| heal | heal | player.heal | Client only | Heals all characters in your current team. | h | | help | help [command] | | Both side | Sends the help message or shows information about a specified command. | | | kick | kick | server.kick | Both side | Kicks the specified player from the server. (WIP) | k | -| killall | killall [playerUid] [sceneId] | server.killall | Both side | Kill all entities in the current scene or specified scene of the corresponding player. | | -| list | list | | Both side | List online players. | | +| killall | killall [playerUid] [sceneId] | server.killall | Both side | Kills all entities in the current scene or specified scene of the corresponding player. | | +| list | list | | Both side | Lists online players. | | | permission | permission | * | Both side | Grants or removes a permission for a user. | | -| position | position | | Client only | Get coordinates. | pos | -| reload | reload | server.reload | Both side | Reload server config | | -| resetconst | resetconst [all] | player.resetconstellation | Client only | Resets the constellation level on your current active character, will need to relog after using the command to see any changes. | resetconstellation | +| position | position | | Client only | Sends your current coordinates. | pos | +| reload | reload | server.reload | Both side | Reloads the server config | | +| resetconst | resetconst [all] | player.resetconstellation | Client only | Resets the constellation level on your currently selected character, will need to relog after using the command to see any changes. | resetconstellation | | restart | | | Both side | Restarts the current session | | | say | say | server.sendmessage | Both side | Sends a message to a player as the server | `sendservmsg` `sendservermessage` `sendmessage` | -| setfetterlevel | setfetterlevel | player.setfetterlevel | Client only | Sets your fetter level for your current active character | setfetterlvl | -| setstats | setstats | player.setstats | Client only | Set fight property for your current active character | stats | +| setfetterlevel | setfetterlevel | player.setfetterlevel | Client only | Sets the friendship level for your currently selected character | setfetterlvl | +| setstats | setstats | player.setstats | Client only | Sets a stat for your currently selected character | stats | | setworldlevel | setworldlevel | player.setworldlevel | Client only | Sets your world level (Relog to see proper effects) | setworldlvl | | spawn | spanw [level] [amount] | server.spawn | Client only | Spawns an entity near you | | | stop | stop | server.stop | Both side | Stops the server | | -| talent | talent | player.settalent | Client only | Set talent level for your current active character | | +| talent | talent | player.settalent | Client only | Sets talent level for your currently selected character | | | teleport | teleport | player.teleport | Client only | Change the player's position. | tp | | weather | weather | player.weather | Client only | Changes the weather | w | @@ -145,4 +145,4 @@ character falling from a very high destination, exact location that you marked. * If compiling wasn't successful, please check your JDK installation (JDK 17 and validated JDK's bin PATH variable) * My client doesn't connect, doesn't login, 4206, etc... - Mostly your proxy daemon setup is *the issue*, if using Fiddler make sure it running on another port except 8888 -* Startup sequence: Mongodb > Grasscutter > Proxy daemon (mitmdump, fiddler, etc.) > Client +* Startup sequence: Mongodb -> Grasscutter -> Proxy daemon (mitmdump, fiddler, etc.) -> Client From 5b6ecc721958d877744bb952bdda09291ae593ad Mon Sep 17 00:00:00 2001 From: Yazawazi <47273265+Yazawazi@users.noreply.github.com> Date: Wed, 27 Apr 2022 13:10:50 +0800 Subject: [PATCH 11/31] Task Improvement --- src/main/java/emu/grasscutter/task/Task.java | 4 + .../emu/grasscutter/task/TaskHandler.java | 19 +++-- .../java/emu/grasscutter/task/TaskMap.java | 73 +++++++++++++++---- .../emu/grasscutter/task/tasks/MoonCard.java | 13 ++-- 4 files changed, 80 insertions(+), 29 deletions(-) diff --git a/src/main/java/emu/grasscutter/task/Task.java b/src/main/java/emu/grasscutter/task/Task.java index 34638a777..1f35d16ce 100644 --- a/src/main/java/emu/grasscutter/task/Task.java +++ b/src/main/java/emu/grasscutter/task/Task.java @@ -1,5 +1,7 @@ package emu.grasscutter.task; +import org.quartz.JobDataMap; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -27,4 +29,6 @@ public @interface Task { String taskName() default "NO_NAME"; String taskCronExpression() default "0 0 0 0 0 ?"; String triggerName() default "NO_NAME"; + boolean executeImmediatelyAfterReset() default false; + boolean executeImmediately() default false; } diff --git a/src/main/java/emu/grasscutter/task/TaskHandler.java b/src/main/java/emu/grasscutter/task/TaskHandler.java index e1a160a07..c61f45534 100644 --- a/src/main/java/emu/grasscutter/task/TaskHandler.java +++ b/src/main/java/emu/grasscutter/task/TaskHandler.java @@ -1,11 +1,18 @@ package emu.grasscutter.task; -import org.quartz.Job; -import org.quartz.JobExecutionContext; -import org.quartz.JobExecutionException; +import org.quartz.*; -public interface TaskHandler extends Job { - default void execute(JobExecutionContext context) throws JobExecutionException { - +@PersistJobDataAfterExecution +public class TaskHandler implements Job { + + public void restartExecute() throws JobExecutionException { + execute(null); } + + @Override + public void execute(JobExecutionContext context) throws JobExecutionException { + // TODO Auto-generated method stub + + } + } diff --git a/src/main/java/emu/grasscutter/task/TaskMap.java b/src/main/java/emu/grasscutter/task/TaskMap.java index 077ff1f59..9e6c1efca 100644 --- a/src/main/java/emu/grasscutter/task/TaskMap.java +++ b/src/main/java/emu/grasscutter/task/TaskMap.java @@ -1,20 +1,9 @@ package emu.grasscutter.task; import emu.grasscutter.Grasscutter; -import emu.grasscutter.game.Account; -import emu.grasscutter.game.player.Player; -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.*; import org.quartz.impl.StdSchedulerFactory; -import org.quartz.spi.MutableTrigger; import org.reflections.Reflections; import java.util.*; @@ -23,6 +12,7 @@ import java.util.*; public final class TaskMap { private final Map tasks = new HashMap<>(); private final Map annotations = new HashMap<>(); + private final Map afterReset = new HashMap<>(); private final SchedulerFactory schedulerFactory = new StdSchedulerFactory(); public TaskMap() { @@ -37,6 +27,44 @@ public final class TaskMap { return Grasscutter.getGameServer().getTaskMap(); } + public void resetNow() { + // Unregister all tasks + for (TaskHandler task : this.tasks.values()) { + unregisterTask(task.getClass().getAnnotation(Task.class).taskName()); + } + + // 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(String taskName) { + this.tasks.remove(taskName); + this.annotations.remove(taskName); + + try { + Scheduler scheduler = schedulerFactory.getScheduler(); + scheduler.deleteJob(new JobKey(taskName)); + } catch (SchedulerException e) { + e.printStackTrace(); + } + + return this; + } + public TaskMap registerTask(String taskName, TaskHandler task) { Task annotation = task.getClass().getAnnotation(Task.class); this.annotations.put(taskName, annotation); @@ -56,7 +84,10 @@ public final class TaskMap { .build(); scheduler.scheduleJob(job, convTrigger); - scheduler.start(); + + if (annotation.executeImmediately()) { + task.execute(null); + } } catch (SchedulerException e) { e.printStackTrace(); } @@ -83,12 +114,24 @@ public final class TaskMap { try { Task taskData = annotated.getAnnotation(Task.class); Object object = annotated.newInstance(); - if (object instanceof TaskHandler) + if (object instanceof TaskHandler) { 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) { Grasscutter.getLogger().error("Failed to register task handler for " + annotated.getSimpleName(), exception); } }); + try { + Scheduler scheduler = schedulerFactory.getScheduler(); + scheduler.start(); + } catch (SchedulerException e) { + e.printStackTrace(); + } + } } diff --git a/src/main/java/emu/grasscutter/task/tasks/MoonCard.java b/src/main/java/emu/grasscutter/task/tasks/MoonCard.java index 45c04586e..21ac60c97 100644 --- a/src/main/java/emu/grasscutter/task/tasks/MoonCard.java +++ b/src/main/java/emu/grasscutter/task/tasks/MoonCard.java @@ -1,27 +1,24 @@ package emu.grasscutter.task.tasks; -import emu.grasscutter.database.DatabaseManager; -import emu.grasscutter.game.player.Player; +import emu.grasscutter.Grasscutter; import emu.grasscutter.task.Task; import emu.grasscutter.task.TaskHandler; -import java.util.List; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; @Task(taskName = "MoonCard", taskCronExpression = "0 0 0 * * ?", triggerName = "MoonCardTrigger") // 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 execute(JobExecutionContext context) throws JobExecutionException { - List players = DatabaseManager.getDatastore().find(Player.class).stream().toList(); - for (Player player : players) { + public synchronized void execute(JobExecutionContext context) throws JobExecutionException { + Grasscutter.getGameServer().getPlayers().forEach((uid, player) -> { if (player.isOnline()) { if (player.inMoonCard()) { player.getTodayMoonCard(); } } - } + }); } } From 32d322b0be43b2e075806ee16698cd7a2512615e Mon Sep 17 00:00:00 2001 From: Yazawazi <47273265+Yazawazi@users.noreply.github.com> Date: Wed, 27 Apr 2022 17:30:16 +0800 Subject: [PATCH 12/31] onEnable & onDisable --- src/main/java/emu/grasscutter/task/TaskHandler.java | 8 ++++++++ src/main/java/emu/grasscutter/task/TaskMap.java | 13 ++++++++----- .../java/emu/grasscutter/task/tasks/MoonCard.java | 11 +++++++++++ 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/main/java/emu/grasscutter/task/TaskHandler.java b/src/main/java/emu/grasscutter/task/TaskHandler.java index c61f45534..ea6fe22cd 100644 --- a/src/main/java/emu/grasscutter/task/TaskHandler.java +++ b/src/main/java/emu/grasscutter/task/TaskHandler.java @@ -9,6 +9,14 @@ public class TaskHandler implements Job { execute(null); } + public void onEnable() { + + } + + public void onDisable() { + + } + @Override public void execute(JobExecutionContext context) throws JobExecutionException { // TODO Auto-generated method stub diff --git a/src/main/java/emu/grasscutter/task/TaskMap.java b/src/main/java/emu/grasscutter/task/TaskMap.java index 9e6c1efca..fe067e795 100644 --- a/src/main/java/emu/grasscutter/task/TaskMap.java +++ b/src/main/java/emu/grasscutter/task/TaskMap.java @@ -30,7 +30,7 @@ public final class TaskMap { public void resetNow() { // Unregister all tasks for (TaskHandler task : this.tasks.values()) { - unregisterTask(task.getClass().getAnnotation(Task.class).taskName()); + unregisterTask(task); } // Run all afterReset tasks @@ -51,17 +51,19 @@ public final class TaskMap { } } - public TaskMap unregisterTask(String taskName) { - this.tasks.remove(taskName); - this.annotations.remove(taskName); + 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(taskName)); + scheduler.deleteJob(new JobKey(task.getClass().getAnnotation(Task.class).taskName())); } catch (SchedulerException e) { e.printStackTrace(); } + task.onDisable(); + return this; } @@ -88,6 +90,7 @@ public final class TaskMap { if (annotation.executeImmediately()) { task.execute(null); } + task.onEnable(); } catch (SchedulerException e) { e.printStackTrace(); } diff --git a/src/main/java/emu/grasscutter/task/tasks/MoonCard.java b/src/main/java/emu/grasscutter/task/tasks/MoonCard.java index 21ac60c97..51088f46d 100644 --- a/src/main/java/emu/grasscutter/task/tasks/MoonCard.java +++ b/src/main/java/emu/grasscutter/task/tasks/MoonCard.java @@ -11,6 +11,17 @@ import org.quartz.JobExecutionException; @Task(taskName = "MoonCard", taskCronExpression = "0 0 0 * * ?", triggerName = "MoonCardTrigger") // taskCronExpression: Fixed time period: 0:0:0 every day (twenty-four hour system) 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 public synchronized void execute(JobExecutionContext context) throws JobExecutionException { Grasscutter.getGameServer().getPlayers().forEach((uid, player) -> { From 2ba16cf8b284e3c61e413998cf8e77003b9fd4bc Mon Sep 17 00:00:00 2001 From: Yazawazi <47273265+Yazawazi@users.noreply.github.com> Date: Wed, 27 Apr 2022 17:52:04 +0800 Subject: [PATCH 13/31] comment & mooncard --- src/main/java/emu/grasscutter/game/player/Player.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index a0654f2c7..826f65563 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -941,6 +941,8 @@ public class Player { session.send(new PacketPlayerStoreNotify(this)); session.send(new PacketAvatarDataNotify(this)); + getTodayMoonCard(); // The timer works at 0:0, some users log in after that, use this method to check if they have received a reward today or not. If not, send the reward. + session.send(new PacketPlayerEnterSceneNotify(this)); // Enter game world session.send(new PacketPlayerLevelRewardUpdateNotify(rewardedLevels)); session.send(new PacketOpenStateUpdateNotify()); From f0d728b4e3a894e7d14e3462c430483a4c1bf951 Mon Sep 17 00:00:00 2001 From: iTruth Date: Wed, 27 Apr 2022 21:48:57 +0800 Subject: [PATCH 14/31] Fix start.cmd can't find grasscutter when modify SERVER_JAR_NAME in start_config.cmd --- start.cmd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/start.cmd b/start.cmd index f44a5f00d..9cee1a999 100644 --- a/start.cmd +++ b/start.cmd @@ -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 From 1130138a4f179383bbd8537af8060af659f3a4a1 Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Wed, 27 Apr 2022 10:25:25 -0700 Subject: [PATCH 15/31] Fix internal server error when changing characters --- .../grasscutter/server/packet/send/PacketChangeAvatarRsp.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketChangeAvatarRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketChangeAvatarRsp.java index f5efe6808..0fd69fe26 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketChangeAvatarRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketChangeAvatarRsp.java @@ -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(); From 1586bab5d797fd42f5483f70e26e9185e92b1235 Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Wed, 27 Apr 2022 10:26:27 -0700 Subject: [PATCH 16/31] Gacha banner tweaks Removed min/maxItemType Added configurable base weight values for banners --- .../grasscutter/game/gacha/GachaBanner.java | 20 +++++++++---------- .../grasscutter/game/gacha/GachaManager.java | 9 +++++---- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/main/java/emu/grasscutter/game/gacha/GachaBanner.java b/src/main/java/emu/grasscutter/game/gacha/GachaBanner.java index ed5492b62..9b54c924f 100644 --- a/src/main/java/emu/grasscutter/game/gacha/GachaBanner.java +++ b/src/main/java/emu/grasscutter/game/gacha/GachaBanner.java @@ -16,8 +16,8 @@ public class GachaBanner { private int sortId; private int[] rateUpItems1; private int[] rateUpItems2; - private int minItemType = 1; - private int maxItemType = 2; + private int baseYellowWeight = 60; // Max 10000 + private int basePurpleWeight = 510; // Max 10000 private int eventChance = 50; // Chance to win a featured event item private int softPity = 75; private int hardPity = 90; @@ -63,6 +63,14 @@ public class GachaBanner { return sortId; } + public int getBaseYellowWeight() { + return baseYellowWeight; + } + + public int getBasePurpleWeight() { + return basePurpleWeight; + } + public int[] getRateUpItems1() { return rateUpItems1; } @@ -70,14 +78,6 @@ public class GachaBanner { public int[] getRateUpItems2() { return rateUpItems2; } - - public int getMinItemType() { - return minItemType; - } - - public int getMaxItemType() { - return maxItemType; - } public int getSoftPity() { return softPity - 1; diff --git a/src/main/java/emu/grasscutter/game/gacha/GachaManager.java b/src/main/java/emu/grasscutter/game/gacha/GachaManager.java index fa26569e4..5cd484e9a 100644 --- a/src/main/java/emu/grasscutter/game/gacha/GachaManager.java +++ b/src/main/java/emu/grasscutter/game/gacha/GachaManager.java @@ -15,6 +15,7 @@ import emu.grasscutter.Grasscutter; import emu.grasscutter.data.GameData; import emu.grasscutter.data.def.ItemData; import emu.grasscutter.game.avatar.Avatar; +import emu.grasscutter.game.gacha.GachaBanner.BannerType; import emu.grasscutter.game.inventory.GameItem; import emu.grasscutter.game.inventory.ItemType; import emu.grasscutter.game.inventory.MaterialType; @@ -125,8 +126,8 @@ public class GachaManager { int itemId = 0; int bonusYellowChance = gachaInfo.getPity5() >= banner.getSoftPity() ? 100 * (gachaInfo.getPity5() - banner.getSoftPity() - 1): 0; - int yellowChance = 60 + (int) Math.floor(100f * (gachaInfo.getPity5() / (banner.getSoftPity() - 1D))) + bonusYellowChance; - int purpleChance = 10000 - (510 + (int) Math.floor(790f * (gachaInfo.getPity4() / 8f))); + int yellowChance = banner.getBaseYellowWeight() + (int) Math.floor(100f * (gachaInfo.getPity5() / (banner.getSoftPity() - 1D))) + bonusYellowChance; + int purpleChance = 10000 - (banner.getBasePurpleWeight() + (int) Math.floor(790f * (gachaInfo.getPity4() / 8f))); if (random <= yellowChance || gachaInfo.getPity5() >= banner.getHardPity()) { if (banner.getRateUpItems1().length > 0) { @@ -142,7 +143,7 @@ public class GachaManager { } if (itemId == 0) { - int typeChance = this.randomRange(banner.getMinItemType(), banner.getMaxItemType()); + int typeChance = this.randomRange(banner.getBannerType() == BannerType.WEAPON ? 2 : 1, banner.getBannerType() == BannerType.EVENT ? 1 : 2); if (typeChance == 1) { itemId = getRandom(this.yellowAvatars); } else { @@ -163,7 +164,7 @@ public class GachaManager { } if (itemId == 0) { - int typeChance = this.randomRange(banner.getMinItemType(), banner.getMaxItemType()); + int typeChance = this.randomRange(banner.getBannerType() == BannerType.WEAPON ? 2 : 1, banner.getBannerType() == BannerType.EVENT ? 1 : 2); if (typeChance == 1) { itemId = getRandom(this.purpleAvatars); } else { From 8bf17a8bdce1ab61ab373753ec1a0ae014ee4e0d Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Wed, 27 Apr 2022 10:42:50 -0700 Subject: [PATCH 17/31] Fixed genesis crystals not being given to player --- .../emu/grasscutter/game/inventory/Inventory.java | 3 +++ .../game/managers/InventoryManager.java | 1 + .../java/emu/grasscutter/game/player/Player.java | 15 ++++++++++----- .../server/packet/recv/HandlerBuyGoodsReq.java | 4 ++-- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/main/java/emu/grasscutter/game/inventory/Inventory.java b/src/main/java/emu/grasscutter/game/inventory/Inventory.java index d407e077b..5ca0d022f 100644 --- a/src/main/java/emu/grasscutter/game/inventory/Inventory.java +++ b/src/main/java/emu/grasscutter/game/inventory/Inventory.java @@ -249,6 +249,9 @@ public class Inventory implements Iterable { case 202: // Mora getPlayer().setMora(player.getMora() + count); break; + case 203: // Genesis Crystals + getPlayer().setCrystals(player.getCrystals() + count); + break; } } diff --git a/src/main/java/emu/grasscutter/game/managers/InventoryManager.java b/src/main/java/emu/grasscutter/game/managers/InventoryManager.java index 904d2cbdd..055d3da6d 100644 --- a/src/main/java/emu/grasscutter/game/managers/InventoryManager.java +++ b/src/main/java/emu/grasscutter/game/managers/InventoryManager.java @@ -923,6 +923,7 @@ public class InventoryManager { break; } + // Welkin if (useItem.getItemId() == 1202) { player.rechargeMoonCard(); used = 1; diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index 826f65563..b4a22328d 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -294,6 +294,15 @@ public class Player { this.setProperty(PlayerProperty.PROP_PLAYER_SCOIN, mora); this.sendPacket(new PacketPlayerPropNotify(this, PlayerProperty.PROP_PLAYER_SCOIN)); } + + public int getCrystals() { + return this.getProperty(PlayerProperty.PROP_PLAYER_MCOIN); + } + + public void setCrystals(int crystals) { + this.setProperty(PlayerProperty.PROP_PLAYER_MCOIN, crystals); + this.sendPacket(new PacketPlayerPropNotify(this, PlayerProperty.PROP_PLAYER_MCOIN)); + } private int getExpRequired(int level) { PlayerLevelData levelData = GameData.getPlayerLevelDataMap().get(level); @@ -550,11 +559,7 @@ public class Player { } public void rechargeMoonCard() { - LinkedList items = new LinkedList(); - for (int i = 0; i < 300; i++) { - items.add(new GameItem(203)); - } - inventory.addItems(items); + inventory.addItem(new GameItem(203, 300)); if (!moonCard) { moonCard = true; Date now = new Date(); diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerBuyGoodsReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerBuyGoodsReq.java index c83808ada..1df08de43 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerBuyGoodsReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerBuyGoodsReq.java @@ -32,7 +32,7 @@ public class HandlerBuyGoodsReq extends PacketHandler { if (sg.getHcoin() > 0 && session.getPlayer().getPrimogems() < buyGoodsReq.getBoughtNum() * sg.getHcoin()) { return; } - if (sg.getMcoin() > 0 && session.getPlayer().getProperty(PlayerProperty.PROP_PLAYER_MCOIN) < buyGoodsReq.getBoughtNum() * sg.getMcoin()) { + if (sg.getMcoin() > 0 && session.getPlayer().getCrystals() < buyGoodsReq.getBoughtNum() * sg.getMcoin()) { return; } @@ -46,7 +46,7 @@ public class HandlerBuyGoodsReq extends PacketHandler { session.getPlayer().setMora(session.getPlayer().getMora() - buyGoodsReq.getBoughtNum() * sg.getScoin()); session.getPlayer().setPrimogems(session.getPlayer().getPrimogems() - buyGoodsReq.getBoughtNum() * sg.getHcoin()); - session.getPlayer().setProperty(PlayerProperty.PROP_PLAYER_MCOIN, session.getPlayer().getProperty(PlayerProperty.PROP_PLAYER_MCOIN) - buyGoodsReq.getBoughtNum() * sg.getMcoin()); + session.getPlayer().setCrystals(session.getPlayer().getCrystals() - buyGoodsReq.getBoughtNum() * sg.getMcoin()); if (!itemsCache.isEmpty()) { for (GameItem gi : itemsCache.keySet()) { From 555937d2aac6ed648a96e2971071e9fdc0bd292e Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Wed, 27 Apr 2022 10:42:59 -0700 Subject: [PATCH 18/31] Fixed concurrency issue in killall --- .../emu/grasscutter/command/commands/KillAllCommand.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/emu/grasscutter/command/commands/KillAllCommand.java b/src/main/java/emu/grasscutter/command/commands/KillAllCommand.java index 3e2466686..9636fd845 100644 --- a/src/main/java/emu/grasscutter/command/commands/KillAllCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/KillAllCommand.java @@ -4,6 +4,7 @@ import emu.grasscutter.Grasscutter; import emu.grasscutter.command.Command; import emu.grasscutter.command.CommandHandler; import emu.grasscutter.game.entity.EntityMonster; +import emu.grasscutter.game.entity.GameEntity; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.world.Scene; @@ -53,10 +54,12 @@ public final class KillAllCommand implements CommandHandler { return; } - mainScene.getEntities().values().stream() + // Separate into list to avoid concurrency issue + List toKill = mainScene.getEntities().values().stream() .filter(entity -> entity instanceof EntityMonster) - .forEach(entity -> mainScene.killEntity(entity, 0)); - CommandHandler.sendMessage(sender, "Killing all monsters in scene " + mainScene.getId()); + .toList(); + toKill.stream().forEach(entity -> mainScene.killEntity(entity, 0)); + CommandHandler.sendMessage(sender, "Killing " + toKill.size() + " monsters in scene " + mainScene.getId()); } catch (NumberFormatException ignored) { CommandHandler.sendMessage(sender, "Invalid arguments."); } From 10e5851a592e045a068f2e6b739fc85e3ad3039d Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Wed, 27 Apr 2022 11:16:14 -0700 Subject: [PATCH 19/31] Add message about the server being free --- src/main/java/emu/grasscutter/server/game/GameServer.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/emu/grasscutter/server/game/GameServer.java b/src/main/java/emu/grasscutter/server/game/GameServer.java index 257ac9fef..2b22b6a95 100644 --- a/src/main/java/emu/grasscutter/server/game/GameServer.java +++ b/src/main/java/emu/grasscutter/server/game/GameServer.java @@ -203,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(); } From f6db39926d1be7c177f5f1e553548b3c619aba89 Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Wed, 27 Apr 2022 11:21:26 -0700 Subject: [PATCH 20/31] Fix co-op requests not showing up --- src/main/java/emu/grasscutter/game/friends/Friendship.java | 4 ++-- src/main/java/emu/grasscutter/game/player/Player.java | 6 +++--- .../server/packet/send/PacketGetPlayerFriendListRsp.java | 4 ++-- .../server/packet/send/PacketSetPlayerHeadImageRsp.java | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/emu/grasscutter/game/friends/Friendship.java b/src/main/java/emu/grasscutter/game/friends/Friendship.java index ef0bed109..79439bb3a 100644 --- a/src/main/java/emu/grasscutter/game/friends/Friendship.java +++ b/src/main/java/emu/grasscutter/game/friends/Friendship.java @@ -8,7 +8,7 @@ import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.game.player.Player; import emu.grasscutter.net.proto.FriendBriefOuterClass.FriendBrief; import emu.grasscutter.net.proto.FriendOnlineStateOuterClass.FriendOnlineState; -import emu.grasscutter.net.proto.HeadImageOuterClass.HeadImage; +import emu.grasscutter.net.proto.ProfilePictureOuterClass.ProfilePicture; @Entity(value = "friendships", useDiscriminator = false) public class Friendship { @@ -92,7 +92,7 @@ public class Friendship { .setUid(getFriendProfile().getUid()) .setNickname(getFriendProfile().getName()) .setLevel(getFriendProfile().getPlayerLevel()) - .setAvatarId(HeadImage.newBuilder().setAvatarId(getFriendProfile().getAvatarId()).getAvatarId()) + .setProfilePicture(ProfilePicture.newBuilder().setAvatarId(getFriendProfile().getAvatarId())) .setWorldLevel(getFriendProfile().getWorldLevel()) .setSignature(getFriendProfile().getSignature()) .setOnlineState(getFriendProfile().isOnline() ? FriendOnlineState.FRIEND_ONLINE : FriendOnlineState.FREIEND_DISCONNECT) diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index b4a22328d..2715ba6e6 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -27,13 +27,13 @@ import emu.grasscutter.game.world.World; import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry; import emu.grasscutter.net.proto.CombatInvokeEntryOuterClass.CombatInvokeEntry; -import emu.grasscutter.net.proto.HeadImageOuterClass.HeadImage; import emu.grasscutter.net.proto.InteractTypeOuterClass.InteractType; import emu.grasscutter.net.proto.MpSettingTypeOuterClass.MpSettingType; import emu.grasscutter.net.proto.OnlinePlayerInfoOuterClass.OnlinePlayerInfo; import emu.grasscutter.net.proto.PlayerApplyEnterMpResultNotifyOuterClass; import emu.grasscutter.net.proto.PlayerLocationInfoOuterClass.PlayerLocationInfo; import emu.grasscutter.net.proto.PlayerWorldLocationInfoOuterClass; +import emu.grasscutter.net.proto.ProfilePictureOuterClass.ProfilePicture; import emu.grasscutter.net.proto.SocialDetailOuterClass.SocialDetail; import emu.grasscutter.server.game.GameServer; import emu.grasscutter.server.game.GameSession; @@ -799,7 +799,7 @@ public class Player { .setMpSettingType(this.getMpSetting()) .setNameCardId(this.getNameCardId()) .setSignature(this.getSignature()) - .setAvatarId(HeadImage.newBuilder().setAvatarId(this.getHeadImage()).getAvatarId()); + .setProfilePicture(ProfilePicture.newBuilder().setAvatarId(this.getHeadImage())); if (this.getWorld() != null) { onlineInfo.setCurPlayerNumInWorld(this.getWorld().getPlayers().indexOf(this) + 1); @@ -834,7 +834,7 @@ public class Player { public SocialDetail.Builder getSocialDetail() { SocialDetail.Builder social = SocialDetail.newBuilder() .setUid(this.getUid()) - .setAvatarId(HeadImage.newBuilder().setAvatarId(this.getHeadImage()).getAvatarId()) + .setProfilePicture(ProfilePicture.newBuilder().setAvatarId(this.getHeadImage())) .setNickname(this.getNickname()) .setSignature(this.getSignature()) .setLevel(this.getLevel()) diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketGetPlayerFriendListRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketGetPlayerFriendListRsp.java index b2628e36d..dbaa4b316 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketGetPlayerFriendListRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketGetPlayerFriendListRsp.java @@ -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)) diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketSetPlayerHeadImageRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketSetPlayerHeadImageRsp.java index 9b736dc3e..4cbfd4b46 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketSetPlayerHeadImageRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketSetPlayerHeadImageRsp.java @@ -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); From f16d33b41399cfa31af8b3378002274ac4533cf6 Mon Sep 17 00:00:00 2001 From: Yazawazi <47273265+Yazawazi@users.noreply.github.com> Date: Thu, 28 Apr 2022 03:21:51 +0800 Subject: [PATCH 21/31] Player show avatar list --- .../emu/grasscutter/game/player/Player.java | 35 ++++++++++++++++++- .../HandlerUpdatePlayerShowAvatarListReq.java | 22 ++++++++++++ .../PacketUpdatePlayerShowAvatarListRsp.java | 22 ++++++++++++ 3 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 src/main/java/emu/grasscutter/server/packet/recv/HandlerUpdatePlayerShowAvatarListReq.java create mode 100644 src/main/java/emu/grasscutter/server/packet/send/PacketUpdatePlayerShowAvatarListRsp.java diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index 2715ba6e6..198992766 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -93,6 +93,9 @@ public class Player { private int moonCardDuration; private Set moonCardGetTimes; + private List showAvatarList; + private boolean showAvatars; + @Transient private boolean paused; @Transient private int enterSceneToken; @Transient private SceneLoadState sceneState; @@ -513,6 +516,22 @@ public class Player { this.regionId = regionId; } + public void setShowAvatars(boolean showAvatars) { + this.showAvatars = showAvatars; + } + + public boolean isShowAvatars() { + return showAvatars; + } + + public void setShowAvatarList(List showAvatarList) { + this.showAvatarList = showAvatarList; + } + + public List getShowAvatarList() { + return showAvatarList; + } + public boolean inMoonCard() { return moonCard; } @@ -832,15 +851,29 @@ public class Player { } public SocialDetail.Builder getSocialDetail() { + List socialShowAvatarInfoList = new ArrayList<>(); + for (int avatarId : this.getShowAvatarList()) { + socialShowAvatarInfoList.add( + socialShowAvatarInfoList.size(), + SocialShowAvatarInfoOuterClass.SocialShowAvatarInfo.newBuilder() + .setAvatarId(avatarId) + .setLevel(getAvatars().getAvatarById(avatarId).getLevel()) + .setCostumeId(getAvatars().getAvatarById(avatarId).getCostume()) + .build() + ); + } + SocialDetail.Builder social = SocialDetail.newBuilder() .setUid(this.getUid()) - .setProfilePicture(ProfilePicture.newBuilder().setAvatarId(this.getHeadImage())) + .setAvatarId(HeadImage.newBuilder().setAvatarId(this.getHeadImage()).getAvatarId()) .setNickname(this.getNickname()) .setSignature(this.getSignature()) .setLevel(this.getLevel()) .setBirthday(this.getBirthday().getFilledProtoWhenNotEmpty()) .setWorldLevel(this.getWorldLevel()) .setNameCardId(this.getNameCardId()) + .setIsShowAvatar(this.isShowAvatars()) + .addAllShowAvatarInfoList(socialShowAvatarInfoList) .setFinishAchievementNum(0); return social; } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerUpdatePlayerShowAvatarListReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerUpdatePlayerShowAvatarListReq.java new file mode 100644 index 000000000..d04fb7308 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerUpdatePlayerShowAvatarListReq.java @@ -0,0 +1,22 @@ +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())); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketUpdatePlayerShowAvatarListRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketUpdatePlayerShowAvatarListRsp.java new file mode 100644 index 000000000..d04fb7308 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketUpdatePlayerShowAvatarListRsp.java @@ -0,0 +1,22 @@ +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())); + } +} From 9092c9b3f91ce0ba527b5fbba4963ac712aaab27 Mon Sep 17 00:00:00 2001 From: Yazawazi <47273265+Yazawazi@users.noreply.github.com> Date: Thu, 28 Apr 2022 03:31:36 +0800 Subject: [PATCH 22/31] import --- src/main/java/emu/grasscutter/game/player/Player.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index 198992766..573dd830e 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -35,6 +35,7 @@ import emu.grasscutter.net.proto.PlayerLocationInfoOuterClass.PlayerLocationInfo import emu.grasscutter.net.proto.PlayerWorldLocationInfoOuterClass; import emu.grasscutter.net.proto.ProfilePictureOuterClass.ProfilePicture; import emu.grasscutter.net.proto.SocialDetailOuterClass.SocialDetail; +import emu.grasscutter.net.proto.SocialShowAvatarInfoOuterClass; import emu.grasscutter.server.game.GameServer; import emu.grasscutter.server.game.GameSession; import emu.grasscutter.server.packet.send.*; From 363dae9fa62d9aaaed4f9f4c61e7be0da9d2f964 Mon Sep 17 00:00:00 2001 From: Yazawazi <47273265+Yazawazi@users.noreply.github.com> Date: Thu, 28 Apr 2022 03:37:09 +0800 Subject: [PATCH 23/31] Next time I'll never use github.dev again --- .../PacketUpdatePlayerShowAvatarListRsp.java | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketUpdatePlayerShowAvatarListRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketUpdatePlayerShowAvatarListRsp.java index d04fb7308..1785c9f45 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketUpdatePlayerShowAvatarListRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketUpdatePlayerShowAvatarListRsp.java @@ -1,22 +1,22 @@ -package emu.grasscutter.server.packet.recv; +package emu.grasscutter.server.packet.send; -import emu.grasscutter.Grasscutter; -import emu.grasscutter.net.packet.Opcodes; -import emu.grasscutter.net.packet.PacketHandler; +import emu.grasscutter.net.packet.BasePacket; 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; +import emu.grasscutter.net.proto.UpdatePlayerShowAvatarListRspOuterClass.UpdatePlayerShowAvatarListRsp; -@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); +import java.util.List; - session.getPlayer().setShowAvatars(req.getIsShowAvatar()); - session.getPlayer().setShowAvatarList(req.getShowAvatarIdListList()); +public class PacketUpdatePlayerShowAvatarListRsp extends BasePacket { - session.send(new PacketUpdatePlayerShowAvatarListRsp(req.getIsShowAvatar(), req.getShowAvatarIdListList())); + public PacketUpdatePlayerShowAvatarListRsp(boolean isShowAvatar, List avatarIds) { + super(PacketOpcodes.UpdatePlayerShowAvatarListRsp); + + UpdatePlayerShowAvatarListRsp proto = UpdatePlayerShowAvatarListRsp.newBuilder() + .setIsShowAvatar(isShowAvatar) + .addAllShowAvatarIdList(avatarIds) + .setRetcode(0) + .build(); + + this.setData(proto); } } From e55160dad69df51a852d94da8c0186b42685d4e7 Mon Sep 17 00:00:00 2001 From: Yazawazi <47273265+Yazawazi@users.noreply.github.com> Date: Thu, 28 Apr 2022 03:40:32 +0800 Subject: [PATCH 24/31] Headimage --- src/main/java/emu/grasscutter/game/player/Player.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index 573dd830e..3677d3801 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -27,6 +27,7 @@ import emu.grasscutter.game.world.World; import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry; import emu.grasscutter.net.proto.CombatInvokeEntryOuterClass.CombatInvokeEntry; +import emu.grasscutter.net.proto.HeadImageOuterClass.HeadImage; import emu.grasscutter.net.proto.InteractTypeOuterClass.InteractType; import emu.grasscutter.net.proto.MpSettingTypeOuterClass.MpSettingType; import emu.grasscutter.net.proto.OnlinePlayerInfoOuterClass.OnlinePlayerInfo; From 982cbbe5d25b5909d751d742a21fffadc4b32128 Mon Sep 17 00:00:00 2001 From: Yazawazi <47273265+Yazawazi@users.noreply.github.com> Date: Thu, 28 Apr 2022 03:45:17 +0800 Subject: [PATCH 25/31] no headimage okay --- src/main/java/emu/grasscutter/game/player/Player.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index 3677d3801..79696093b 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -867,7 +867,7 @@ public class Player { SocialDetail.Builder social = SocialDetail.newBuilder() .setUid(this.getUid()) - .setAvatarId(HeadImage.newBuilder().setAvatarId(this.getHeadImage()).getAvatarId()) + .setProfilePicture(ProfilePicture.newBuilder().setAvatarId(this.getHeadImage())) .setNickname(this.getNickname()) .setSignature(this.getSignature()) .setLevel(this.getLevel()) From 02ce62422fa6ae6a5dfe8261fcd0542e57b9a1e7 Mon Sep 17 00:00:00 2001 From: Yazawazi <47273265+Yazawazi@users.noreply.github.com> Date: Thu, 28 Apr 2022 03:46:24 +0800 Subject: [PATCH 26/31] kill me plz --- src/main/java/emu/grasscutter/game/player/Player.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index 79696093b..d550e5914 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -27,7 +27,6 @@ import emu.grasscutter.game.world.World; import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry; import emu.grasscutter.net.proto.CombatInvokeEntryOuterClass.CombatInvokeEntry; -import emu.grasscutter.net.proto.HeadImageOuterClass.HeadImage; import emu.grasscutter.net.proto.InteractTypeOuterClass.InteractType; import emu.grasscutter.net.proto.MpSettingTypeOuterClass.MpSettingType; import emu.grasscutter.net.proto.OnlinePlayerInfoOuterClass.OnlinePlayerInfo; From 0cbfcddae4f23866bfcb96202337267711f359d1 Mon Sep 17 00:00:00 2001 From: Yazawazi <47273265+Yazawazi@users.noreply.github.com> Date: Thu, 28 Apr 2022 06:40:25 +0800 Subject: [PATCH 27/31] Should be OK --- .../emu/grasscutter/game/player/Player.java | 38 ++++++++++++++----- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index d550e5914..75c9c21ad 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -853,15 +853,35 @@ public class Player { public SocialDetail.Builder getSocialDetail() { List socialShowAvatarInfoList = new ArrayList<>(); - for (int avatarId : this.getShowAvatarList()) { - socialShowAvatarInfoList.add( - socialShowAvatarInfoList.size(), - SocialShowAvatarInfoOuterClass.SocialShowAvatarInfo.newBuilder() - .setAvatarId(avatarId) - .setLevel(getAvatars().getAvatarById(avatarId).getLevel()) - .setCostumeId(getAvatars().getAvatarById(avatarId).getCostume()) - .build() - ); + if (this.isOnline()) { + if (this.getShowAvatarList() != null) { + for (int avatarId : this.getShowAvatarList()) { + socialShowAvatarInfoList.add( + socialShowAvatarInfoList.size(), + SocialShowAvatarInfoOuterClass.SocialShowAvatarInfo.newBuilder() + .setAvatarId(avatarId) + .setLevel(getAvatars().getAvatarById(avatarId).getLevel()) + .setCostumeId(getAvatars().getAvatarById(avatarId).getCostume()) + .build() + ); + } + } + } else { + List showAvatarList = DatabaseHelper.getPlayerById(id).getShowAvatarList(); + AvatarStorage avatars = DatabaseHelper.getPlayerById(id).getAvatars(); + avatars.loadFromDatabase(); + if (showAvatarList != null) { + for (int avatarId : showAvatarList) { + socialShowAvatarInfoList.add( + socialShowAvatarInfoList.size(), + SocialShowAvatarInfoOuterClass.SocialShowAvatarInfo.newBuilder() + .setAvatarId(avatarId) + .setLevel(avatars.getAvatarById(avatarId).getLevel()) + .setCostumeId(avatars.getAvatarById(avatarId).getCostume()) + .build() + ); + } + } } SocialDetail.Builder social = SocialDetail.newBuilder() From 0c665d940ee25c4af4a5dd443087b1e987ee8574 Mon Sep 17 00:00:00 2001 From: memetrollsXD Date: Thu, 28 Apr 2022 00:10:46 +0200 Subject: [PATCH 28/31] Add default permissions --- src/main/java/emu/grasscutter/Config.java | 1 + .../java/emu/grasscutter/server/dispatch/DispatchServer.java | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/src/main/java/emu/grasscutter/Config.java b/src/main/java/emu/grasscutter/Config.java index ee5fe65c8..3e6e16d20 100644 --- a/src/main/java/emu/grasscutter/Config.java +++ b/src/main/java/emu/grasscutter/Config.java @@ -33,6 +33,7 @@ public final class Config { public Boolean FrontHTTPS = true; public boolean AutomaticallyCreateAccounts = false; + public String[] defaultPermissions = new String[] { "" }; public RegionInfo[] GameServers = {}; diff --git a/src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java b/src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java index 1ac721ce2..99c5e4f8d 100644 --- a/src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java +++ b/src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java @@ -339,6 +339,10 @@ public final class DispatchServer { // added. account = DatabaseHelper.createAccountWithId(requestData.account, 0); + for (String permission : Grasscutter.getConfig().getDispatchOptions().defaultPermissions) { + account.addPermission(permission); + } + if (account != null) { responseData.message = "OK"; responseData.data.account.uid = account.getId(); From eaf2982ebc86b93529760bcd2108d812d5bb45f2 Mon Sep 17 00:00:00 2001 From: memetrollsXD Date: Thu, 28 Apr 2022 00:18:59 +0200 Subject: [PATCH 29/31] Apply to account command --- .../grasscutter/command/commands/AccountCommand.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/java/emu/grasscutter/command/commands/AccountCommand.java b/src/main/java/emu/grasscutter/command/commands/AccountCommand.java index 68da1569a..52848e56c 100644 --- a/src/main/java/emu/grasscutter/command/commands/AccountCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/AccountCommand.java @@ -1,5 +1,6 @@ package emu.grasscutter.command.commands; +import emu.grasscutter.Grasscutter; import emu.grasscutter.command.Command; import emu.grasscutter.command.CommandHandler; import emu.grasscutter.database.DatabaseHelper; @@ -7,8 +8,7 @@ import emu.grasscutter.game.player.Player; import java.util.List; -@Command(label = "account", usage = "account [uid]", - description = "Modify user accounts") +@Command(label = "account", usage = "account [uid]", description = "Modify user accounts") public final class AccountCommand implements CommandHandler { @Override @@ -47,7 +47,13 @@ public final class AccountCommand implements CommandHandler { return; } else { CommandHandler.sendMessage(null, "Account created with UID " + account.getPlayerUid() + "."); - account.addPermission("*"); // Grant the player superuser permissions. + + for (String permission : Grasscutter.getConfig().getDispatchOptions().defaultPermissions) { + if (!permission.isBlank()) { + account.addPermission(permission); + } + } + account.save(); // Save account to database. } return; From b80b8aedd989d84c4376146e58ab6cdfccb3a3eb Mon Sep 17 00:00:00 2001 From: memetrollsXD Date: Thu, 28 Apr 2022 00:28:16 +0200 Subject: [PATCH 30/31] Remove default permissions from account command --- .../grasscutter/command/commands/AccountCommand.java | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/main/java/emu/grasscutter/command/commands/AccountCommand.java b/src/main/java/emu/grasscutter/command/commands/AccountCommand.java index 52848e56c..fc169c3de 100644 --- a/src/main/java/emu/grasscutter/command/commands/AccountCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/AccountCommand.java @@ -46,15 +46,10 @@ public final class AccountCommand implements CommandHandler { CommandHandler.sendMessage(null, "Account already exists."); return; } else { - CommandHandler.sendMessage(null, "Account created with UID " + account.getPlayerUid() + "."); - - for (String permission : Grasscutter.getConfig().getDispatchOptions().defaultPermissions) { - if (!permission.isBlank()) { - account.addPermission(permission); - } - } - + account.addPermission('*'); account.save(); // Save account to database. + + CommandHandler.sendMessage(null, "Account created with UID " + account.getPlayerUid() + "."); } return; case "delete": From 96dbc2fbfda180bde1db505d33b3478c53faa14c Mon Sep 17 00:00:00 2001 From: memetrollsXD Date: Thu, 28 Apr 2022 00:30:04 +0200 Subject: [PATCH 31/31] God damn forgot I was in java for a sec --- .../java/emu/grasscutter/command/commands/AccountCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/emu/grasscutter/command/commands/AccountCommand.java b/src/main/java/emu/grasscutter/command/commands/AccountCommand.java index fc169c3de..ab09b3afa 100644 --- a/src/main/java/emu/grasscutter/command/commands/AccountCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/AccountCommand.java @@ -46,7 +46,7 @@ public final class AccountCommand implements CommandHandler { CommandHandler.sendMessage(null, "Account already exists."); return; } else { - account.addPermission('*'); + account.addPermission("*"); account.save(); // Save account to database. CommandHandler.sendMessage(null, "Account created with UID " + account.getPlayerUid() + ".");