Support Boss Chest

This commit is contained in:
Akka
2022-05-20 13:46:00 +08:00
committed by Melledy
parent 5429469852
commit 717c2d1dd7
24 changed files with 324 additions and 94 deletions

View File

@@ -14,6 +14,7 @@ import emu.grasscutter.scripts.constants.EventType;
import emu.grasscutter.scripts.data.*;
import emu.grasscutter.scripts.service.ScriptMonsterSpawnService;
import emu.grasscutter.scripts.service.ScriptMonsterTideService;
import io.netty.util.concurrent.FastThreadLocalThread;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import org.luaj.vm2.LuaError;
@@ -21,6 +22,10 @@ import org.luaj.vm2.LuaValue;
import org.luaj.vm2.lib.jse.CoerceJavaToLua;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class SceneScriptManager {
private final Scene scene;
@@ -43,6 +48,12 @@ public class SceneScriptManager {
* blockid - loaded groupSet
*/
private Int2ObjectMap<Set<SceneGroup>> loadedGroupSetPerBlock;
public static final ExecutorService eventExecutor;
static {
eventExecutor = new ThreadPoolExecutor(4, 4,
60, TimeUnit.SECONDS, new LinkedBlockingDeque<>(100),
FastThreadLocalThread::new, new ThreadPoolExecutor.AbortPolicy());
}
public SceneScriptManager(Scene scene) {
this.scene = scene;
this.triggers = new HashMap<>();
@@ -211,7 +222,7 @@ public class SceneScriptManager {
}
var toCreate = gadgets.stream()
.map(g -> createGadget(g.groupId, group.block_id, g))
.map(g -> createGadget(g.group.id, group.block_id, g))
.filter(Objects::nonNull)
.toList();
this.addEntities(toCreate);
@@ -254,8 +265,17 @@ public class SceneScriptManager {
getScene().addEntity(createMonster(group.id, group.block_id, group.monsters.get(configId)));
}
// Events
public void callEvent(int eventType, ScriptArgs params) {
public void callEvent(int eventType, ScriptArgs params){
/**
* We use ThreadLocal to trans SceneScriptManager context to ScriptLib, to avoid eval script for every groups' trigger in every scene instances.
* But when callEvent is called in a ScriptLib func, it may cause NPE because the inner call cleans the ThreadLocal so that outer call could not get it.
* e.g. CallEvent -> set -> ScriptLib.xxx -> CallEvent -> set -> remove -> NPE -> (remove)
* So we use thread pool to clean the stack to avoid this new issue.
*/
eventExecutor.submit(() -> this.realCallEvent(eventType, params));
}
private void realCallEvent(int eventType, ScriptArgs params) {
try{
ScriptLoader.getScriptLib().setSceneScriptManager(this);
for (SceneTrigger trigger : this.getTriggersByEvent(eventType)) {
@@ -282,7 +302,7 @@ public class SceneScriptManager {
}
}
public LuaValue callScriptFunc(String funcName, SceneGroup group, ScriptArgs params){
private LuaValue callScriptFunc(String funcName, SceneGroup group, ScriptArgs params){
LuaValue funcLua = null;
if (funcName != null && !funcName.isEmpty()) {
funcLua = (LuaValue) group.getBindings().get(funcName);
@@ -332,10 +352,8 @@ public class SceneScriptManager {
entity.getRotation().set(g.rot);
entity.setState(g.state);
entity.setPointType(g.point_type);
entity.setMetaGadget(g);
entity.buildContent();
// Lua event
this.callEvent(EventType.EVENT_GADGET_CREATE, new ScriptArgs(entity.getConfigId()));
return entity;
}

View File

@@ -8,7 +8,6 @@ import emu.grasscutter.game.entity.gadget.GadgetWorktop;
import emu.grasscutter.scripts.data.SceneGroup;
import emu.grasscutter.scripts.data.SceneRegion;
import emu.grasscutter.server.packet.send.PacketCanUseSkillNotify;
import emu.grasscutter.server.packet.send.PacketGadgetStateNotify;
import emu.grasscutter.server.packet.send.PacketWorktopOptionNotify;
import io.netty.util.concurrent.FastThreadLocal;
import org.luaj.vm2.LuaTable;
@@ -16,7 +15,6 @@ import org.luaj.vm2.LuaValue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Optional;
public class ScriptLib {
@@ -68,34 +66,24 @@ public class ScriptLib {
if (entity.isEmpty()) {
return 1;
}
if (!(entity.get() instanceof EntityGadget)) {
return 1;
if (entity.get() instanceof EntityGadget entityGadget) {
entityGadget.updateState(gadgetState);
return 0;
}
EntityGadget gadget = (EntityGadget) entity.get();
gadget.setState(gadgetState);
getSceneScriptManager().getScene().broadcastPacket(new PacketGadgetStateNotify(gadget, gadgetState));
return 0;
return 1;
}
public int SetGroupGadgetStateByConfigId(int groupId, int configId, int gadgetState) {
logger.debug("[LUA] Call SetGroupGadgetStateByConfigId with {},{},{}",
groupId,configId,gadgetState);
List<GameEntity> list = getSceneScriptManager().getScene().getEntities().values().stream()
.filter(e -> e.getGroupId() == groupId).toList();
for (GameEntity entity : list) {
if (!(entity instanceof EntityGadget)) {
continue;
}
EntityGadget gadget = (EntityGadget) entity;
gadget.setState(gadgetState);
getSceneScriptManager().getScene().broadcastPacket(new PacketGadgetStateNotify(gadget, gadgetState));
}
getSceneScriptManager().getScene().getEntities().values().stream()
.filter(e -> e.getGroupId() == groupId)
.filter(e -> e instanceof EntityGadget)
.map(e -> (EntityGadget)e)
.forEach(e -> e.updateState(gadgetState));
return 0;
}
@@ -450,8 +438,9 @@ public class ScriptLib {
if (entity instanceof EntityGadget entityGadget) {
entityGadget.updateState(state);
return 0;
}
return 0;
return 1;
}
}

View File

@@ -0,0 +1,13 @@
package emu.grasscutter.scripts.data;
import lombok.Setter;
import lombok.ToString;
@Setter
@ToString
public class SceneBossChest {
public int life_time;
public int monster_config_id;
public int resin;
public int take_num;
}

View File

@@ -9,4 +9,5 @@ public class SceneGadget extends SceneObject{
public int gadget_id;
public int state;
public int point_type;
public SceneBossChest boss_chest;
}

View File

@@ -98,11 +98,11 @@ public class SceneGroup {
// Set
monsters = ScriptLoader.getSerializer().toList(SceneMonster.class, bindings.get("monsters")).stream()
.collect(Collectors.toMap(x -> x.config_id, y -> y));
monsters.values().forEach(m -> m.groupId = id);
monsters.values().forEach(m -> m.group = this);
gadgets = ScriptLoader.getSerializer().toList(SceneGadget.class, bindings.get("gadgets")).stream()
.collect(Collectors.toMap(x -> x.config_id, y -> y));
gadgets.values().forEach(m -> m.groupId = id);
gadgets.values().forEach(m -> m.group = this);
triggers = ScriptLoader.getSerializer().toList(SceneTrigger.class, bindings.get("triggers")).stream()
.collect(Collectors.toMap(x -> x.name, y -> y));

View File

@@ -16,5 +16,5 @@ public class SceneObject {
/**
* not set by lua
*/
public transient int groupId;
public transient SceneGroup group;
}