diff --git a/src/main/java/emu/grasscutter/game/avatar/AvatarStorage.java b/src/main/java/emu/grasscutter/game/avatar/AvatarStorage.java index 3fb8fa5b5..6343fc30d 100644 --- a/src/main/java/emu/grasscutter/game/avatar/AvatarStorage.java +++ b/src/main/java/emu/grasscutter/game/avatar/AvatarStorage.java @@ -8,6 +8,7 @@ import emu.grasscutter.game.entity.EntityAvatar; import emu.grasscutter.game.inventory.GameItem; import emu.grasscutter.game.player.BasePlayerManager; import emu.grasscutter.game.player.Player; +import emu.grasscutter.server.event.entity.EntityCreationEvent; import emu.grasscutter.server.packet.send.PacketAvatarChangeCostumeNotify; import emu.grasscutter.server.packet.send.PacketAvatarFlycloakChangeNotify; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; @@ -115,7 +116,8 @@ public class AvatarStorage extends BasePlayerManager implements Iterable // Update entity EntityAvatar entity = avatar.getAsEntity(); if (entity == null) { - entity = new EntityAvatar(avatar); + entity = EntityCreationEvent.call(EntityAvatar.class, + new Class[] {Avatar.class}, new Object[] {avatar}); getPlayer().sendPacket(new PacketAvatarChangeCostumeNotify(entity)); } else { getPlayer().getScene().broadcastPacket(new PacketAvatarChangeCostumeNotify(entity)); diff --git a/src/main/java/emu/grasscutter/game/player/PlayerProgressManager.java b/src/main/java/emu/grasscutter/game/player/PlayerProgressManager.java index 9f570db9b..66c49d1f9 100644 --- a/src/main/java/emu/grasscutter/game/player/PlayerProgressManager.java +++ b/src/main/java/emu/grasscutter/game/player/PlayerProgressManager.java @@ -1,8 +1,5 @@ package emu.grasscutter.game.player; -import static emu.grasscutter.config.Configuration.GAME_OPTIONS; -import static emu.grasscutter.scripts.constants.EventType.EVENT_UNLOCK_TRANS_POINT; - import emu.grasscutter.data.GameData; import emu.grasscutter.data.binout.ScenePointEntry; import emu.grasscutter.data.excels.OpenStateData; @@ -15,9 +12,13 @@ import emu.grasscutter.game.quest.enums.QuestState; import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode; import emu.grasscutter.scripts.data.ScriptArgs; import emu.grasscutter.server.packet.send.*; + import java.util.Set; import java.util.stream.Collectors; +import static emu.grasscutter.config.Configuration.GAME_OPTIONS; +import static emu.grasscutter.scripts.constants.EventType.EVENT_UNLOCK_TRANS_POINT; + // @Entity public final class PlayerProgressManager extends BasePlayerDataManager { /****************************************************************************************************************** @@ -81,6 +82,8 @@ public final class PlayerProgressManager extends BasePlayerDataManager { // Auto-unlock the first statue and map area. this.player.getUnlockedScenePoints(3).add(7); this.player.getUnlockedSceneAreas(3).add(1); + // Allow the player to visit all areas. + this.setOpenState(47, 1, true); } } diff --git a/src/main/java/emu/grasscutter/game/player/TeamManager.java b/src/main/java/emu/grasscutter/game/player/TeamManager.java index b2c756576..e34147f00 100644 --- a/src/main/java/emu/grasscutter/game/player/TeamManager.java +++ b/src/main/java/emu/grasscutter/game/player/TeamManager.java @@ -1,7 +1,5 @@ package emu.grasscutter.game.player; -import static emu.grasscutter.config.Configuration.GAME_OPTIONS; - import dev.morphia.annotations.Entity; import dev.morphia.annotations.Transient; import emu.grasscutter.GameConstants; @@ -25,6 +23,7 @@ import emu.grasscutter.net.proto.PlayerDieTypeOuterClass.PlayerDieType; import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode; import emu.grasscutter.net.proto.TrialAvatarGrantRecordOuterClass.TrialAvatarGrantRecord.GrantReason; import emu.grasscutter.net.proto.VisionTypeOuterClass; +import emu.grasscutter.server.event.entity.EntityCreationEvent; import emu.grasscutter.server.event.player.PlayerTeamDeathEvent; import emu.grasscutter.server.packet.send.*; import emu.grasscutter.utils.Utils; @@ -32,12 +31,15 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; -import java.util.*; -import java.util.stream.Stream; import lombok.Getter; import lombok.Setter; import lombok.val; +import java.util.*; +import java.util.stream.Stream; + +import static emu.grasscutter.config.Configuration.GAME_OPTIONS; + @Entity public final class TeamManager extends BasePlayerDataManager { @Transient private final List avatars; @@ -353,9 +355,11 @@ public final class TeamManager extends BasePlayerDataManager { prevSelectedAvatarIndex = i; } } else { - entity = - new EntityAvatar( - this.getPlayer().getScene(), this.getPlayer().getAvatars().getAvatarById(avatarId)); + var player = this.getPlayer(); + entity = EntityCreationEvent.call(EntityAvatar.class, + new Class[] {Scene.class, Avatar.class}, new Object[] { + player.getScene(), player.getAvatars().getAvatarById(avatarId) + }); } this.getActiveTeam().add(entity); @@ -494,7 +498,10 @@ public final class TeamManager extends BasePlayerDataManager { this.getActiveTeam().removeIf(x -> x.getAvatar().getAvatarId() == trialAvatar.getAvatarId()); this.getCurrentTeamInfo().getAvatars().removeIf(x -> x == trialAvatar.getAvatarId()); // Add the avatar to the teams. - this.getActiveTeam().add(new EntityAvatar(this.getPlayer().getScene(), trialAvatar)); + this.getActiveTeam().add(EntityCreationEvent.call(EntityAvatar.class, + new Class[] {Scene.class, Avatar.class}, new Object[] { + player.getScene(), trialAvatar + })); this.getCurrentTeamInfo().addAvatar(trialAvatar); this.getTrialAvatars().put(trialAvatar.getAvatarId(), trialAvatar); } @@ -581,7 +588,10 @@ public final class TeamManager extends BasePlayerDataManager { .forEach( avatarId -> this.getActiveTeam() - .add(new EntityAvatar(scene, player.getAvatars().getAvatarById(avatarId)))); + .add(EntityCreationEvent.call(EntityAvatar.class, + new Class[] {Scene.class, Avatar.class}, new Object[] { + scene, player.getAvatars().getAvatarById(avatarId) + }))); } else { // Restores all avatars from the player's avatar storage. // If the avatar is already in the team, it will not be added. @@ -597,7 +607,10 @@ public final class TeamManager extends BasePlayerDataManager { var avatarData = player.getAvatars().getAvatarById(avatar); if (avatarData == null) continue; - this.getActiveTeam().add(index, new EntityAvatar(scene, avatarData)); + this.getActiveTeam().add(index, EntityCreationEvent.call(EntityAvatar.class, + new Class[] {Scene.class, Avatar.class}, new Object[] { + scene, avatarData + })); } } @@ -963,7 +976,9 @@ public final class TeamManager extends BasePlayerDataManager { var avatar = avatars.getAvatarById(id); if (avatar == null) continue; - specifiedAvatarList.add(new EntityAvatar(scene, avatar)); + specifiedAvatarList.add(EntityCreationEvent.call(EntityAvatar.class, + new Class[] {Scene.class, Avatar.class}, + new Object[] {scene, avatar})); } } diff --git a/src/main/java/emu/grasscutter/game/quest/GameMainQuest.java b/src/main/java/emu/grasscutter/game/quest/GameMainQuest.java index ce7355f32..0af5359f9 100644 --- a/src/main/java/emu/grasscutter/game/quest/GameMainQuest.java +++ b/src/main/java/emu/grasscutter/game/quest/GameMainQuest.java @@ -24,12 +24,13 @@ import emu.grasscutter.server.packet.send.PacketFinishedParentQuestUpdateNotify; import emu.grasscutter.server.packet.send.PacketQuestProgressUpdateNotify; import emu.grasscutter.server.packet.send.PacketQuestUpdateQuestVarNotify; import emu.grasscutter.utils.ConversionUtils; -import java.util.*; -import java.util.stream.Collectors; import lombok.Getter; import lombok.val; import org.bson.types.ObjectId; +import java.util.*; +import java.util.stream.Collectors; + @Entity(value = "quests", useDiscriminator = false) public class GameMainQuest { @Id private ObjectId id; diff --git a/src/main/java/emu/grasscutter/game/world/Position.java b/src/main/java/emu/grasscutter/game/world/Position.java index 1a0d5bd8c..c508cf476 100644 --- a/src/main/java/emu/grasscutter/game/world/Position.java +++ b/src/main/java/emu/grasscutter/game/world/Position.java @@ -5,12 +5,15 @@ import com.google.gson.annotations.SerializedName; import dev.morphia.annotations.Entity; import emu.grasscutter.net.proto.VectorOuterClass.Vector; import emu.grasscutter.utils.Utils; -import java.io.Serializable; -import java.util.List; import lombok.Getter; import lombok.Setter; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.List; @Entity +@Accessors(chain = true) public class Position implements Serializable { private static final long serialVersionUID = -2001232313615923575L; @@ -104,6 +107,13 @@ public class Position implements Serializable { return this; } + public Position multiply(float value) { + this.x *= value; + this.y *= value; + this.z *= value; + return this; + } + public Position add(Position add) { this.x += add.getX(); this.y += add.getY(); diff --git a/src/main/java/emu/grasscutter/game/world/Scene.java b/src/main/java/emu/grasscutter/game/world/Scene.java index b8744e53f..661e281d2 100644 --- a/src/main/java/emu/grasscutter/game/world/Scene.java +++ b/src/main/java/emu/grasscutter/game/world/Scene.java @@ -36,18 +36,20 @@ import emu.grasscutter.scripts.constants.EventType; import emu.grasscutter.scripts.data.SceneBlock; import emu.grasscutter.scripts.data.SceneGroup; import emu.grasscutter.scripts.data.ScriptArgs; +import emu.grasscutter.server.event.entity.EntityCreationEvent; import emu.grasscutter.server.event.player.PlayerTeleportEvent; import emu.grasscutter.server.packet.send.*; import emu.grasscutter.utils.objects.KahnsSort; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import lombok.Getter; +import lombok.Setter; +import lombok.val; + +import javax.annotation.Nullable; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.stream.Collectors; -import javax.annotation.Nullable; -import lombok.Getter; -import lombok.Setter; -import lombok.val; public final class Scene { @Getter private final World world; @@ -246,7 +248,11 @@ public final class Scene { } if (avatar == null) continue; } - player.getTeamManager().getActiveTeam().add(new EntityAvatar(player.getScene(), avatar)); + player.getTeamManager().getActiveTeam().add( + EntityCreationEvent.call(EntityAvatar.class, + new Class[] {Scene.class, Avatar.class}, + new Object[] {player.getScene(), avatar}) + ); } // Limit character index in case its out of bounds diff --git a/src/main/java/emu/grasscutter/server/event/entity/EntityCreationEvent.java b/src/main/java/emu/grasscutter/server/event/entity/EntityCreationEvent.java new file mode 100644 index 000000000..8693153ba --- /dev/null +++ b/src/main/java/emu/grasscutter/server/event/entity/EntityCreationEvent.java @@ -0,0 +1,48 @@ +package emu.grasscutter.server.event.entity; + +import emu.grasscutter.game.entity.GameEntity; +import emu.grasscutter.server.event.Event; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +import javax.annotation.Nullable; + +/** Invoked when an entity is created. */ +@AllArgsConstructor +public final class EntityCreationEvent extends Event { + /** + * Helper method to call EntityCreationEvent. + * Returns the result of the event call. + * + * @param type The type of entity to create. + * @return The result of the event call. + * @param The type of entity to create. + */ + public static T call( + Class type, Class[] argTypes, Object[] args + ) { + var event = new EntityCreationEvent(type, argTypes, args); + event.call(); return type.cast(event.getEntity()); + } + + @Getter @Setter private Class entityType; + @Getter @Setter private Class[] constructorArgTypes; + @Getter @Setter private Object[] constructorArgs; + + /** + * Creates a new entity. + * Returns null if the entity could not be created. + * + * @return The created entity. + */ + @Nullable + public GameEntity getEntity() { + try { + return this.entityType.getConstructor(this.constructorArgTypes) + .newInstance(this.constructorArgs); + } catch (ReflectiveOperationException ignored) { + return null; + } + } +} diff --git a/src/main/java/emu/grasscutter/server/event/types/EntityEvent.java b/src/main/java/emu/grasscutter/server/event/types/EntityEvent.java index 3530ebd57..e009612ad 100644 --- a/src/main/java/emu/grasscutter/server/event/types/EntityEvent.java +++ b/src/main/java/emu/grasscutter/server/event/types/EntityEvent.java @@ -7,8 +7,8 @@ import emu.grasscutter.server.event.Event; public abstract class EntityEvent extends Event { protected final GameEntity entity; - public EntityEvent(GameEntity player) { - this.entity = player; + public EntityEvent(GameEntity entity) { + this.entity = entity; } public GameEntity getEntity() {