diff --git a/src/main/java/emu/grasscutter/commands/PlayerCommands.java b/src/main/java/emu/grasscutter/commands/PlayerCommands.java index 4e8c2e57e..8c8433b4f 100644 --- a/src/main/java/emu/grasscutter/commands/PlayerCommands.java +++ b/src/main/java/emu/grasscutter/commands/PlayerCommands.java @@ -338,7 +338,11 @@ public class PlayerCommands { return; } - player.getWorld().transferPlayerToScene(player, sceneId, player.getPos()); + boolean result = player.getWorld().transferPlayerToScene(player, sceneId, player.getPos()); + + if (!result) { + player.dropMessage("Scene does not exist!"); + } } } } diff --git a/src/main/java/emu/grasscutter/data/GenshinData.java b/src/main/java/emu/grasscutter/data/GenshinData.java index 84614618a..bb2709108 100644 --- a/src/main/java/emu/grasscutter/data/GenshinData.java +++ b/src/main/java/emu/grasscutter/data/GenshinData.java @@ -51,6 +51,8 @@ public class GenshinData { private static final Int2ObjectMap avatarCostumeDataMap = new Int2ObjectLinkedOpenHashMap<>(); private static final Int2ObjectMap avatarCostumeDataItemIdMap = new Int2ObjectLinkedOpenHashMap<>(); + private static final Int2ObjectMap sceneDataMap = new Int2ObjectLinkedOpenHashMap<>(); + public static Int2ObjectMap getMapByResourceDef(Class resourceDefinition) { Int2ObjectMap map = null; @@ -209,4 +211,8 @@ public class GenshinData { public static Int2ObjectMap getAvatarCostumeDataItemIdMap() { return avatarCostumeDataItemIdMap; } + + public static Int2ObjectMap getSceneDataMap() { + return sceneDataMap; + } } diff --git a/src/main/java/emu/grasscutter/data/def/SceneData.java b/src/main/java/emu/grasscutter/data/def/SceneData.java new file mode 100644 index 000000000..d9c0bd0ab --- /dev/null +++ b/src/main/java/emu/grasscutter/data/def/SceneData.java @@ -0,0 +1,32 @@ +package emu.grasscutter.data.def; + +import emu.grasscutter.data.GenshinData; +import emu.grasscutter.data.GenshinResource; +import emu.grasscutter.data.ResourceType; + +import emu.grasscutter.game.props.SceneType; + +@ResourceType(name = "SceneExcelConfigData.json") +public class SceneData extends GenshinResource { + private int Id; + private SceneType SceneType; + private String ScriptData; + + @Override + public int getId() { + return this.Id; + } + + public SceneType getSceneType() { + return SceneType; + } + + public String getScriptData() { + return ScriptData; + } + + @Override + public void onLoad() { + + } +} diff --git a/src/main/java/emu/grasscutter/game/GenshinScene.java b/src/main/java/emu/grasscutter/game/GenshinScene.java index 98fe98c71..36de90ea0 100644 --- a/src/main/java/emu/grasscutter/game/GenshinScene.java +++ b/src/main/java/emu/grasscutter/game/GenshinScene.java @@ -7,6 +7,7 @@ import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import emu.grasscutter.data.def.SceneData; import emu.grasscutter.game.entity.EntityAvatar; import emu.grasscutter.game.entity.EntityClientGadget; import emu.grasscutter.game.entity.EntityGadget; @@ -14,6 +15,7 @@ import emu.grasscutter.game.entity.GenshinEntity; import emu.grasscutter.game.props.ClimateType; import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.game.props.LifeState; +import emu.grasscutter.game.props.SceneType; import emu.grasscutter.net.packet.GenshinPacket; import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult; import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType; @@ -26,30 +28,38 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; public class GenshinScene { private final World world; + private final SceneData sceneData; private final List players; private final Int2ObjectMap entities; - private final int id; private int time; private ClimateType climate; - public GenshinScene(World world, int sceneId) { + public GenshinScene(World world, SceneData sceneData) { this.world = world; + this.sceneData = sceneData; this.players = Collections.synchronizedList(new ArrayList<>()); this.entities = new Int2ObjectOpenHashMap<>(); - this.id = sceneId; - + this.time = 8 * 60; this.climate = ClimateType.CLIMATE_SUNNY; } public int getId() { - return id; + return sceneData.getId(); } public World getWorld() { return world; } + + public SceneData getSceneData() { + return this.sceneData; + } + + public SceneType getSceneType() { + return getSceneData().getSceneType(); + } public List getPlayers() { return players; diff --git a/src/main/java/emu/grasscutter/game/World.java b/src/main/java/emu/grasscutter/game/World.java index 31c4c9f2f..b3fb3e150 100644 --- a/src/main/java/emu/grasscutter/game/World.java +++ b/src/main/java/emu/grasscutter/game/World.java @@ -14,6 +14,8 @@ import emu.grasscutter.game.props.EnterReason; import emu.grasscutter.game.props.EntityIdType; import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.game.props.LifeState; +import emu.grasscutter.data.GenshinData; +import emu.grasscutter.data.def.SceneData; import emu.grasscutter.game.GenshinPlayer.SceneLoadState; import emu.grasscutter.game.entity.EntityAvatar; import emu.grasscutter.game.entity.EntityClientGadget; @@ -99,7 +101,21 @@ public class World implements Iterable { } public GenshinScene getSceneById(int sceneId) { - return getScenes().computeIfAbsent(sceneId, id -> new GenshinScene(this, id)); + // Get scene normally + GenshinScene scene = getScenes().get(sceneId); + if (scene != null) { + return scene; + } + + // Create scene from scene data if it doesnt exist + SceneData sceneData = GenshinData.getSceneDataMap().get(sceneId); + if (sceneData != null) { + scene = new GenshinScene(this, sceneData); + this.getScenes().put(sceneId, scene); + return scene; + } + + return null; } public int getPlayerCount() { @@ -182,9 +198,9 @@ public class World implements Iterable { } } - public void transferPlayerToScene(GenshinPlayer player, int sceneId, Position pos) { - if (player.getScene().getId() == sceneId) { - return; + public boolean transferPlayerToScene(GenshinPlayer player, int sceneId, Position pos) { + if (player.getScene().getId() == sceneId || GenshinData.getSceneDataMap().get(sceneId) == null) { + return false; } if (player.getScene() != null) { @@ -193,10 +209,11 @@ public class World implements Iterable { GenshinScene scene = this.getSceneById(sceneId); scene.addPlayer(player); - player.getPos().set(pos); - + + // Teleport packet player.sendPacket(new PacketPlayerEnterSceneNotify(player, EnterType.EnterSelf, EnterReason.TransPoint, sceneId, pos)); + return true; } private void updatePlayerInfos(GenshinPlayer paramPlayer) { diff --git a/src/main/java/emu/grasscutter/game/props/SceneType.java b/src/main/java/emu/grasscutter/game/props/SceneType.java new file mode 100644 index 000000000..d6fbaf40d --- /dev/null +++ b/src/main/java/emu/grasscutter/game/props/SceneType.java @@ -0,0 +1,45 @@ +package emu.grasscutter.game.props; + +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Stream; + +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; + +public enum SceneType { + SCENE_NONE (0), + SCENE_WORLD (1), + SCENE_DUNGEON (2), + SCENE_ROOM (3), + SCENE_HOME_WORLD (4), + SCENE_HOME_ROOM (5), + SCENE_ACTIVITY (6); + + private final int value; + private static final Int2ObjectMap map = new Int2ObjectOpenHashMap<>(); + private static final Map stringMap = new HashMap<>(); + + static { + Stream.of(values()).forEach(e -> { + map.put(e.getValue(), e); + stringMap.put(e.name(), e); + }); + } + + private SceneType(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + + public static SceneType getTypeByValue(int value) { + return map.getOrDefault(value, SCENE_NONE); + } + + public static SceneType getTypeByName(String name) { + return stringMap.getOrDefault(name, SCENE_NONE); + } +}