mirror of
https://github.com/Grasscutters/Grasscutter.git
synced 2025-01-09 04:03:21 +08:00
Add events to support scene group substitution (#2413)
* Add events to support scene group substitution * make event members private with getter/setter * delete stray unused var
This commit is contained in:
parent
269f7b4fbf
commit
cf6fb275be
@ -252,12 +252,16 @@ public class EntityMonster extends GameEntity {
|
|||||||
if (scriptManager.isInit() && this.getGroupId() > 0) {
|
if (scriptManager.isInit() && this.getGroupId() > 0) {
|
||||||
Optional.ofNullable(scriptManager.getScriptMonsterSpawnService()).ifPresent(s -> s.onMonsterDead(this));
|
Optional.ofNullable(scriptManager.getScriptMonsterSpawnService()).ifPresent(s -> s.onMonsterDead(this));
|
||||||
|
|
||||||
// prevent spawn monster after success
|
// Ensure each EVENT_ANY_MONSTER_DIE runs to completion.
|
||||||
/*if (challenge.map(c -> c.inProgress()).orElse(true)) {
|
// Multiple such events firing at the same time may cause
|
||||||
scriptManager.callEvent(new ScriptArgs(EventType.EVENT_ANY_MONSTER_DIE, this.getConfigId()).setGroupId(this.getGroupId()));
|
// the same lua trigger to fire multiple times, when it
|
||||||
} else if (getScene().getChallenge() == null) {
|
// should happen only once.
|
||||||
}*/
|
var future = scriptManager.callEvent(new ScriptArgs(this.getGroupId(), EventType.EVENT_ANY_MONSTER_DIE, this.getConfigId()));
|
||||||
scriptManager.callEvent(new ScriptArgs(this.getGroupId(), EventType.EVENT_ANY_MONSTER_DIE, this.getConfigId()));
|
try {
|
||||||
|
future.get();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Battle Pass trigger
|
// Battle Pass trigger
|
||||||
scene.getPlayers().forEach(p -> p.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_MONSTER_DIE, this.getMonsterId(), 1));
|
scene.getPlayers().forEach(p -> p.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_MONSTER_DIE, this.getMonsterId(), 1));
|
||||||
|
@ -5,6 +5,13 @@ import lombok.Data;
|
|||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class GroupReplacementData {
|
public class GroupReplacementData {
|
||||||
int id;
|
public int id;
|
||||||
List<Integer> replace_groups;
|
public List<Integer> replace_groups;
|
||||||
|
|
||||||
|
public GroupReplacementData() {}
|
||||||
|
|
||||||
|
public GroupReplacementData(int id, List<Integer> replace_groups) {
|
||||||
|
this.id = id;
|
||||||
|
this.replace_groups = replace_groups;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1110,6 +1110,9 @@ public class Scene {
|
|||||||
if (group.regions != null) {
|
if (group.regions != null) {
|
||||||
group.regions.values().forEach(getScriptManager()::deregisterRegion);
|
group.regions.values().forEach(getScriptManager()::deregisterRegion);
|
||||||
}
|
}
|
||||||
|
if (challenge != null && group.id == challenge.getGroup().id) {
|
||||||
|
challenge.fail();
|
||||||
|
}
|
||||||
|
|
||||||
scriptManager.getLoadedGroupSetPerBlock().get(block.id).remove(group);
|
scriptManager.getLoadedGroupSetPerBlock().get(block.id).remove(group);
|
||||||
this.loadedGroups.remove(group);
|
this.loadedGroups.remove(group);
|
||||||
|
@ -17,6 +17,7 @@ import emu.grasscutter.net.proto.VisionTypeOuterClass;
|
|||||||
import emu.grasscutter.scripts.constants.EventType;
|
import emu.grasscutter.scripts.constants.EventType;
|
||||||
import emu.grasscutter.scripts.data.*;
|
import emu.grasscutter.scripts.data.*;
|
||||||
import emu.grasscutter.scripts.service.*;
|
import emu.grasscutter.scripts.service.*;
|
||||||
|
import emu.grasscutter.server.event.game.SceneMetaLoadEvent;
|
||||||
import emu.grasscutter.server.packet.send.PacketGroupSuiteNotify;
|
import emu.grasscutter.server.packet.send.PacketGroupSuiteNotify;
|
||||||
import emu.grasscutter.utils.*;
|
import emu.grasscutter.utils.*;
|
||||||
import io.netty.util.concurrent.FastThreadLocalThread;
|
import io.netty.util.concurrent.FastThreadLocalThread;
|
||||||
@ -38,6 +39,7 @@ public class SceneScriptManager {
|
|||||||
private final Map<String, Integer> variables;
|
private final Map<String, Integer> variables;
|
||||||
private SceneMeta meta;
|
private SceneMeta meta;
|
||||||
private boolean isInit;
|
private boolean isInit;
|
||||||
|
private boolean noCacheGroupGridsToDisk;
|
||||||
|
|
||||||
private final Map<String, SceneTimeAxis> timeAxis = new ConcurrentHashMap<>();
|
private final Map<String, SceneTimeAxis> timeAxis = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
@ -134,7 +136,7 @@ public class SceneScriptManager {
|
|||||||
public void registerTrigger(SceneTrigger trigger) {
|
public void registerTrigger(SceneTrigger trigger) {
|
||||||
this.triggerInvocations.put(trigger.getName(), new AtomicInteger(0));
|
this.triggerInvocations.put(trigger.getName(), new AtomicInteger(0));
|
||||||
this.getTriggersByEvent(trigger.getEvent()).add(trigger);
|
this.getTriggersByEvent(trigger.getEvent()).add(trigger);
|
||||||
Grasscutter.getLogger().trace("Registered trigger {}", trigger.getName());
|
Grasscutter.getLogger().trace("Registered trigger {} from group {}", trigger.getName(), trigger.getCurrentGroup().id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deregisterTrigger(List<SceneTrigger> triggers) {
|
public void deregisterTrigger(List<SceneTrigger> triggers) {
|
||||||
@ -143,7 +145,7 @@ public class SceneScriptManager {
|
|||||||
|
|
||||||
public void deregisterTrigger(SceneTrigger trigger) {
|
public void deregisterTrigger(SceneTrigger trigger) {
|
||||||
this.getTriggersByEvent(trigger.getEvent()).remove(trigger);
|
this.getTriggersByEvent(trigger.getEvent()).remove(trigger);
|
||||||
Grasscutter.getLogger().trace("deregistered trigger {}", trigger.getName());
|
Grasscutter.getLogger().trace("deregistered trigger {} from group {}", trigger.getName(), trigger.getCurrentGroup().id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resetTriggers(int eventId) {
|
public void resetTriggers(int eventId) {
|
||||||
@ -438,6 +440,17 @@ public class SceneScriptManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void init() {
|
private void init() {
|
||||||
|
var event = new SceneMetaLoadEvent(getScene());
|
||||||
|
event.call();
|
||||||
|
|
||||||
|
if (event.isOverride()) {
|
||||||
|
// Group grids should not be cached to disk when a scene
|
||||||
|
// group override is in effect. Otherwise, when the server
|
||||||
|
// next runs without that override, the cached content
|
||||||
|
// will not make sense.
|
||||||
|
noCacheGroupGridsToDisk = true;
|
||||||
|
}
|
||||||
|
|
||||||
var meta = ScriptLoader.getSceneMeta(getScene().getId());
|
var meta = ScriptLoader.getSceneMeta(getScene().getId());
|
||||||
if (meta == null) {
|
if (meta == null) {
|
||||||
return;
|
return;
|
||||||
@ -455,7 +468,7 @@ public class SceneScriptManager {
|
|||||||
return groupGridsCache.get(sceneId);
|
return groupGridsCache.get(sceneId);
|
||||||
} else {
|
} else {
|
||||||
var path = FileUtils.getCachePath("scene" + sceneId + "_grid.json");
|
var path = FileUtils.getCachePath("scene" + sceneId + "_grid.json");
|
||||||
if (path.toFile().isFile() && !Grasscutter.config.server.game.cacheSceneEntitiesEveryRun) {
|
if (path.toFile().isFile() && !Grasscutter.config.server.game.cacheSceneEntitiesEveryRun && !noCacheGroupGridsToDisk) {
|
||||||
try {
|
try {
|
||||||
var groupGrids = JsonUtils.loadToList(path, Grid.class);
|
var groupGrids = JsonUtils.loadToList(path, Grid.class);
|
||||||
groupGridsCache.put(sceneId, groupGrids);
|
groupGridsCache.put(sceneId, groupGrids);
|
||||||
@ -585,6 +598,7 @@ public class SceneScriptManager {
|
|||||||
}
|
}
|
||||||
groupGridsCache.put(scene.getId(), groupGrids);
|
groupGridsCache.put(scene.getId(), groupGrids);
|
||||||
|
|
||||||
|
if (!noCacheGroupGridsToDisk) {
|
||||||
try {
|
try {
|
||||||
Files.createDirectories(path.getParent());
|
Files.createDirectories(path.getParent());
|
||||||
} catch (IOException ignored) {
|
} catch (IOException ignored) {
|
||||||
@ -595,6 +609,7 @@ public class SceneScriptManager {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Grasscutter.getLogger().error("Scene {} unable to save grid file.", getScene().getId(), e);
|
Grasscutter.getLogger().error("Scene {} unable to save grid file.", getScene().getId(), e);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return groupGrids;
|
return groupGrids;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ import emu.grasscutter.scripts.serializer.*;
|
|||||||
import emu.grasscutter.utils.FileUtils;
|
import emu.grasscutter.utils.FileUtils;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.ref.SoftReference;
|
import java.lang.ref.SoftReference;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
@ -172,6 +172,17 @@ public class ScriptLoader {
|
|||||||
* @return The sources of the script.
|
* @return The sources of the script.
|
||||||
*/
|
*/
|
||||||
public static String readScript(String path) {
|
public static String readScript(String path) {
|
||||||
|
return readScript(path, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the sources of a script.
|
||||||
|
*
|
||||||
|
* @param path The path of the script.
|
||||||
|
* @param useAbsPath Use path as-is; don't look under Scripts resources.
|
||||||
|
* @return The sources of the script.
|
||||||
|
*/
|
||||||
|
public static String readScript(String path, boolean useAbsPath) {
|
||||||
// Check if the path is cached.
|
// Check if the path is cached.
|
||||||
var cached = ScriptLoader.tryGet(ScriptLoader.scriptSources.get(path));
|
var cached = ScriptLoader.tryGet(ScriptLoader.scriptSources.get(path));
|
||||||
if (cached.isPresent()) {
|
if (cached.isPresent()) {
|
||||||
@ -179,8 +190,11 @@ public class ScriptLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to load the script.
|
// Attempt to load the script.
|
||||||
var scriptPath = FileUtils.getScriptPath(path);
|
var scriptPath = useAbsPath ? Paths.get(path) : FileUtils.getScriptPath(path);
|
||||||
if (!Files.exists(scriptPath)) return null;
|
if (!Files.exists(scriptPath)) {
|
||||||
|
Grasscutter.getLogger().error("Could not find script at path {}", path);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var source = Files.readString(scriptPath);
|
var source = Files.readString(scriptPath);
|
||||||
@ -201,6 +215,17 @@ public class ScriptLoader {
|
|||||||
* @return The compiled script.
|
* @return The compiled script.
|
||||||
*/
|
*/
|
||||||
public static CompiledScript getScript(String path) {
|
public static CompiledScript getScript(String path) {
|
||||||
|
return getScript(path, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches a script and compiles it, or uses the cached varient.
|
||||||
|
*
|
||||||
|
* @param path The path of the script.
|
||||||
|
* @param useAbsPath Use path as-is; don't look under Scripts resources.
|
||||||
|
* @return The compiled script.
|
||||||
|
*/
|
||||||
|
public static CompiledScript getScript(String path, boolean useAbsPath) {
|
||||||
// Check if the script is cached.
|
// Check if the script is cached.
|
||||||
var sc = ScriptLoader.tryGet(ScriptLoader.scriptsCache.get(path));
|
var sc = ScriptLoader.tryGet(ScriptLoader.scriptsCache.get(path));
|
||||||
if (sc.isPresent()) {
|
if (sc.isPresent()) {
|
||||||
@ -211,15 +236,18 @@ public class ScriptLoader {
|
|||||||
CompiledScript script;
|
CompiledScript script;
|
||||||
if (Configuration.FAST_REQUIRE) {
|
if (Configuration.FAST_REQUIRE) {
|
||||||
// Attempt to load the script.
|
// Attempt to load the script.
|
||||||
var scriptPath = FileUtils.getScriptPath(path);
|
var scriptPath = useAbsPath ? Paths.get(path) : FileUtils.getScriptPath(path);
|
||||||
if (!Files.exists(scriptPath)) return null;
|
if (!Files.exists(scriptPath)) {
|
||||||
|
Grasscutter.getLogger().error("Could not find script at path {}", path);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// Compile the script from the file.
|
// Compile the script from the file.
|
||||||
var source = Files.newBufferedReader(scriptPath);
|
var source = Files.newBufferedReader(scriptPath);
|
||||||
script = ScriptLoader.getEngine().compile(source);
|
script = ScriptLoader.getEngine().compile(source);
|
||||||
} else {
|
} else {
|
||||||
// Load the script sources.
|
// Load the script sources.
|
||||||
var sources = ScriptLoader.readScript(path);
|
var sources = ScriptLoader.readScript(path, useAbsPath);
|
||||||
if (sources == null) return null;
|
if (sources == null) return null;
|
||||||
|
|
||||||
// Check to see if the script references other scripts.
|
// Check to see if the script references other scripts.
|
||||||
@ -237,7 +265,7 @@ public class ScriptLoader {
|
|||||||
var scriptName = line.substring(9, line.length() - 1);
|
var scriptName = line.substring(9, line.length() - 1);
|
||||||
// Resolve the script path.
|
// Resolve the script path.
|
||||||
var scriptPath = "Common/" + scriptName + ".lua";
|
var scriptPath = "Common/" + scriptName + ".lua";
|
||||||
var scriptSource = ScriptLoader.readScript(scriptPath);
|
var scriptSource = ScriptLoader.readScript(scriptPath, useAbsPath);
|
||||||
if (scriptSource == null) continue;
|
if (scriptSource == null) continue;
|
||||||
|
|
||||||
// Append the script source.
|
// Append the script source.
|
||||||
|
@ -5,6 +5,7 @@ import com.github.davidmoten.rtreemulti.geometry.*;
|
|||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.game.world.Position;
|
import emu.grasscutter.game.world.Position;
|
||||||
import emu.grasscutter.scripts.*;
|
import emu.grasscutter.scripts.*;
|
||||||
|
import emu.grasscutter.server.event.game.SceneBlockLoadedEvent;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import javax.script.*;
|
import javax.script.*;
|
||||||
@ -64,6 +65,10 @@ public class SceneBlock {
|
|||||||
.collect(Collectors.toMap(x -> x.id, y -> y, (a, b) -> a));
|
.collect(Collectors.toMap(x -> x.id, y -> y, (a, b) -> a));
|
||||||
|
|
||||||
this.groups.values().forEach(g -> g.block_id = this.id);
|
this.groups.values().forEach(g -> g.block_id = this.id);
|
||||||
|
|
||||||
|
var event = new SceneBlockLoadedEvent(this);
|
||||||
|
event.call();
|
||||||
|
|
||||||
this.sceneGroupIndex =
|
this.sceneGroupIndex =
|
||||||
SceneIndexManager.buildIndex(3, this.groups.values(), g -> g.pos.toPoint());
|
SceneIndexManager.buildIndex(3, this.groups.values(), g -> g.pos.toPoint());
|
||||||
} catch (ScriptException exception) {
|
} catch (ScriptException exception) {
|
||||||
|
@ -3,6 +3,7 @@ package emu.grasscutter.scripts.data;
|
|||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.game.world.Position;
|
import emu.grasscutter.game.world.Position;
|
||||||
import emu.grasscutter.scripts.ScriptLoader;
|
import emu.grasscutter.scripts.ScriptLoader;
|
||||||
|
import java.io.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import javax.script.*;
|
import javax.script.*;
|
||||||
@ -39,6 +40,7 @@ public final class SceneGroup {
|
|||||||
private transient boolean loaded;
|
private transient boolean loaded;
|
||||||
private transient CompiledScript script;
|
private transient CompiledScript script;
|
||||||
private transient Bindings bindings;
|
private transient Bindings bindings;
|
||||||
|
public String overrideScriptPath;
|
||||||
|
|
||||||
public static SceneGroup of(int groupId) {
|
public static SceneGroup of(int groupId) {
|
||||||
var group = new SceneGroup();
|
var group = new SceneGroup();
|
||||||
@ -86,8 +88,12 @@ public final class SceneGroup {
|
|||||||
// Create the bindings.
|
// Create the bindings.
|
||||||
this.bindings = ScriptLoader.getEngine().createBindings();
|
this.bindings = ScriptLoader.getEngine().createBindings();
|
||||||
|
|
||||||
var cs =
|
CompiledScript cs;
|
||||||
ScriptLoader.getScript("Scene/%s/scene%s_group%s.lua".formatted(sceneId, sceneId, this.id));
|
if (overrideScriptPath != null && !overrideScriptPath.equals("")) {
|
||||||
|
cs = ScriptLoader.getScript(overrideScriptPath, true);
|
||||||
|
} else {
|
||||||
|
cs = ScriptLoader.getScript("Scene/%s/scene%s_group%s.lua".formatted(sceneId, sceneId, this.id));
|
||||||
|
}
|
||||||
|
|
||||||
if (cs == null) {
|
if (cs == null) {
|
||||||
return this;
|
return this;
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
package emu.grasscutter.server.event.game;
|
||||||
|
|
||||||
|
import emu.grasscutter.server.event.types.ServerEvent;
|
||||||
|
import emu.grasscutter.scripts.data.SceneBlock;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public final class SceneBlockLoadedEvent extends ServerEvent {
|
||||||
|
private SceneBlock block;
|
||||||
|
|
||||||
|
public SceneBlockLoadedEvent(SceneBlock block) {
|
||||||
|
super(Type.GAME);
|
||||||
|
|
||||||
|
this.block = block;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package emu.grasscutter.server.event.game;
|
||||||
|
|
||||||
|
import emu.grasscutter.game.world.Scene;
|
||||||
|
import emu.grasscutter.server.event.types.ServerEvent;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public final class SceneMetaLoadEvent extends ServerEvent {
|
||||||
|
private Scene scene;
|
||||||
|
@Setter private boolean override;
|
||||||
|
|
||||||
|
public SceneMetaLoadEvent(Scene scene) {
|
||||||
|
super(Type.GAME);
|
||||||
|
|
||||||
|
this.scene = scene;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user