Implement script support needed for dungeons

Only a few are supported right now
You will need certain script files in ./resources/Scripts
This commit is contained in:
Melledy
2022-04-28 22:19:14 -07:00
parent 53cc1822f6
commit d71b7abfc3
39 changed files with 1499 additions and 44 deletions

View File

@@ -7,6 +7,7 @@ import emu.grasscutter.data.def.DungeonData;
import emu.grasscutter.data.def.MonsterData;
import emu.grasscutter.data.def.SceneData;
import emu.grasscutter.data.def.WorldLevelData;
import emu.grasscutter.game.dungeons.DungeonChallenge;
import emu.grasscutter.game.entity.*;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.player.TeamInfo;
@@ -18,6 +19,10 @@ import emu.grasscutter.game.world.SpawnDataEntry.SpawnGroupEntry;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult;
import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType;
import emu.grasscutter.scripts.SceneScriptManager;
import emu.grasscutter.scripts.data.SceneBlock;
import emu.grasscutter.scripts.data.SceneGadget;
import emu.grasscutter.scripts.data.SceneGroup;
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
import emu.grasscutter.server.packet.send.PacketLifeStateChangeNotify;
import emu.grasscutter.server.packet.send.PacketSceneEntityAppearNotify;
@@ -37,15 +42,19 @@ public class Scene {
private final Set<SpawnDataEntry> spawnedEntities;
private final Set<SpawnDataEntry> deadSpawnedEntities;
private final Set<SceneBlock> loadedBlocks;
private boolean dontDestroyWhenEmpty;
private int time;
private ClimateType climate;
private int weather;
private SceneScriptManager scriptManager;
private DungeonChallenge challenge;
private DungeonData dungeonData;
private int prevScene; // Id of the previous scene
private int prevScenePoint;
public Scene(World world, SceneData sceneData) {
this.world = world;
this.sceneData = sceneData;
@@ -58,6 +67,8 @@ public class Scene {
this.spawnedEntities = new HashSet<>();
this.deadSpawnedEntities = new HashSet<>();
this.loadedBlocks = new HashSet<>();
this.scriptManager = new SceneScriptManager(this);
}
public int getId() {
@@ -124,6 +135,14 @@ public class Scene {
this.prevScene = prevScene;
}
public int getPrevScenePoint() {
return prevScenePoint;
}
public void setPrevScenePoint(int prevPoint) {
this.prevScenePoint = prevPoint;
}
public boolean dontDestroyWhenEmpty() {
return dontDestroyWhenEmpty;
}
@@ -132,6 +151,10 @@ public class Scene {
this.dontDestroyWhenEmpty = dontDestroyWhenEmpty;
}
public Set<SceneBlock> getLoadedBlocks() {
return loadedBlocks;
}
public Set<SpawnDataEntry> getSpawnedEntities() {
return spawnedEntities;
}
@@ -140,6 +163,10 @@ public class Scene {
return deadSpawnedEntities;
}
public SceneScriptManager getScriptManager() {
return scriptManager;
}
public DungeonData getDungeonData() {
return dungeonData;
}
@@ -151,6 +178,14 @@ public class Scene {
this.dungeonData = dungeonData;
}
public DungeonChallenge getChallenge() {
return challenge;
}
public void setChallenge(DungeonChallenge challenge) {
this.challenge = challenge;
}
public boolean isInScene(GameEntity entity) {
return this.entities.containsKey(entity.getId());
}
@@ -183,7 +218,7 @@ public class Scene {
this.removePlayerAvatars(player);
// Remove player gadgets
for (EntityGadget gadget : player.getTeamManager().getGadgets()) {
for (EntityBaseGadget gadget : player.getTeamManager().getGadgets()) {
this.removeEntity(gadget);
}
@@ -338,7 +373,15 @@ public class Scene {
}
public void onTick() {
this.checkSpawns();
if (this.getScriptManager().isInit()) {
this.checkBlocks();
} else {
// TEMPORARY
this.checkSpawns();
}
// Triggers
this.getScriptManager().onTick();
}
// TODO - Test
@@ -411,6 +454,75 @@ public class Scene {
}
}
public void checkBlocks() {
Set<SceneBlock> visible = new HashSet<>();
for (Player player : this.getPlayers()) {
for (SceneBlock block : getScriptManager().getBlocks()) {
if (!block.contains(player.getPos())) {
continue;
}
visible.add(block);
}
}
Iterator<SceneBlock> it = this.getLoadedBlocks().iterator();
while (it.hasNext()) {
SceneBlock block = it.next();
if (!visible.contains(block)) {
it.remove();
onUnloadBlock(block);
}
}
for (SceneBlock block : visible) {
if (!this.getLoadedBlocks().contains(block)) {
this.getLoadedBlocks().add(block);
this.onLoadBlock(block);
}
}
}
// TODO optimize
public void onLoadBlock(SceneBlock block) {
for (SceneGroup group : block.groups) {
group.triggers.forEach(getScriptManager()::registerTrigger);
}
for (SceneGroup group : block.groups) {
for (SceneGadget g : group.gadgets) {
EntityGadget entity = new EntityGadget(this, g.gadget_id, g.pos);
if (entity.getGadgetData() == null) continue;
entity.setBlockId(block.id);
entity.setConfigId(g.config_id);
entity.setGroupId(group.id);
entity.getRotation().set(g.rot);
entity.setState(g.state);
this.addEntity(entity);
this.getScriptManager().onGadgetCreate(entity);
}
}
}
public void onUnloadBlock(SceneBlock block) {
List<GameEntity> toRemove = this.getEntities().values().stream().filter(e -> e.getBlockId() == block.id).toList();
if (toRemove.size() > 0) {
toRemove.stream().forEach(this::removeEntityDirectly);
this.broadcastPacket(new PacketSceneEntityDisappearNotify(toRemove, VisionType.VISION_REMOVE));
}
for (SceneGroup group : block.groups) {
group.triggers.forEach(getScriptManager()::deregisterTrigger);
}
}
// Gadgets
public void onPlayerCreateGadget(EntityClientGadget gadget) {

View File

@@ -21,11 +21,12 @@ import emu.grasscutter.data.def.DungeonData;
import emu.grasscutter.data.def.SceneData;
import emu.grasscutter.game.entity.EntityAvatar;
import emu.grasscutter.game.entity.EntityClientGadget;
import emu.grasscutter.game.entity.EntityGadget;
import emu.grasscutter.game.entity.EntityBaseGadget;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult;
import emu.grasscutter.net.proto.EnterTypeOuterClass.EnterType;
import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType;
import emu.grasscutter.scripts.data.SceneConfig;
import emu.grasscutter.server.packet.send.PacketDelTeamEntityNotify;
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
import emu.grasscutter.server.packet.send.PacketLifeStateChangeNotify;
@@ -243,16 +244,22 @@ public class World implements Iterable<Player> {
newScene.addPlayer(player);
// Dungeon
if (dungeonData != null) {
// TODO set position
SceneConfig config = newScene.getScriptManager().getConfig();
if (pos == null && config != null) {
if (config.born_pos != null) {
pos = newScene.getScriptManager().getConfig().born_pos;
}
if (config.born_rot != null) {
player.getRotation().set(config.born_rot);
}
}
// Set player position
if (pos != null) {
player.getPos().set(pos);
} else {
if (pos == null) {
pos = player.getPos();
}
player.getPos().set(pos);
if (oldScene != null) {
newScene.setPrevScene(oldScene.getId());