Commit 01b190bc authored by Magix's avatar Magix Committed by GitHub
Browse files

UPGRADE TO 1.1.0 POG

Merge `development` into `stable`
parents 6b81b888 1beddf16
package emu.grasscutter.scripts;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import javax.script.Bindings;
import javax.script.CompiledScript;
import javax.script.ScriptException;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.lib.jse.CoerceJavaToLua;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.def.MonsterData;
import emu.grasscutter.data.def.WorldLevelData;
import emu.grasscutter.game.entity.EntityGadget;
import emu.grasscutter.game.entity.EntityMonster;
import emu.grasscutter.game.entity.GameEntity;
import emu.grasscutter.game.props.EntityType;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.scripts.constants.EventType;
import emu.grasscutter.scripts.constants.ScriptGadgetState;
import emu.grasscutter.scripts.constants.ScriptRegionShape;
import emu.grasscutter.scripts.data.SceneBlock;
import emu.grasscutter.scripts.data.SceneConfig;
import emu.grasscutter.scripts.data.SceneGadget;
import emu.grasscutter.scripts.data.SceneGroup;
import emu.grasscutter.scripts.data.SceneInitConfig;
import emu.grasscutter.scripts.data.SceneMonster;
import emu.grasscutter.scripts.data.SceneRegion;
import emu.grasscutter.scripts.data.SceneSuite;
import emu.grasscutter.scripts.data.SceneTrigger;
import emu.grasscutter.scripts.data.SceneVar;
import emu.grasscutter.scripts.data.ScriptArgs;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
public class SceneScriptManager {
private final Scene scene;
private final ScriptLib scriptLib;
private final LuaValue scriptLibLua;
private final Map<String, Integer> variables;
private Bindings bindings;
private SceneConfig config;
private List<SceneBlock> blocks;
private boolean isInit;
private final Int2ObjectOpenHashMap<Set<SceneTrigger>> triggers;
private final Int2ObjectOpenHashMap<SceneRegion> regions;
public SceneScriptManager(Scene scene) {
this.scene = scene;
this.scriptLib = new ScriptLib(this);
this.scriptLibLua = CoerceJavaToLua.coerce(this.scriptLib);
this.triggers = new Int2ObjectOpenHashMap<>();
this.regions = new Int2ObjectOpenHashMap<>();
this.variables = new HashMap<>();
// TEMPORARY
if (this.getScene().getId() < 10) {
return;
}
// Create
this.init();
}
public Scene getScene() {
return scene;
}
public ScriptLib getScriptLib() {
return scriptLib;
}
public LuaValue getScriptLibLua() {
return scriptLibLua;
}
public Bindings getBindings() {
return bindings;
}
public SceneConfig getConfig() {
return config;
}
public List<SceneBlock> getBlocks() {
return blocks;
}
public Map<String, Integer> getVariables() {
return variables;
}
public Set<SceneTrigger> getTriggersByEvent(int eventId) {
return triggers.computeIfAbsent(eventId, e -> new HashSet<>());
}
public void registerTrigger(SceneTrigger trigger) {
getTriggersByEvent(trigger.event).add(trigger);
}
public void deregisterTrigger(SceneTrigger trigger) {
getTriggersByEvent(trigger.event).remove(trigger);
}
public SceneRegion getRegionById(int id) {
return regions.get(id);
}
public void registerRegion(SceneRegion region) {
regions.put(region.config_id, region);
}
public void deregisterRegion(SceneRegion region) {
regions.remove(region.config_id);
}
// TODO optimize
public SceneGroup getGroupById(int groupId) {
for (SceneBlock block : this.getScene().getLoadedBlocks()) {
for (SceneGroup group : block.groups) {
if (group.id == groupId) {
return group;
}
}
}
return null;
}
private void init() {
// Get compiled script if cached
CompiledScript cs = ScriptLoader.getScriptByPath(
Grasscutter.getConfig().SCRIPTS_FOLDER + "Scene/" + getScene().getId() + "/scene" + getScene().getId() + "." + ScriptLoader.getScriptType());
if (cs == null) {
Grasscutter.getLogger().warn("No script found for scene " + getScene().getId());
return;
}
// Create bindings
bindings = ScriptLoader.getEngine().createBindings();
// Set variables
bindings.put("ScriptLib", getScriptLib());
// Eval script
try {
cs.eval(getBindings());
this.config = ScriptLoader.getSerializer().toObject(SceneConfig.class, bindings.get("scene_config"));
// TODO optimize later
// Create blocks
List<Integer> blockIds = ScriptLoader.getSerializer().toList(Integer.class, bindings.get("blocks"));
List<SceneBlock> blocks = ScriptLoader.getSerializer().toList(SceneBlock.class, bindings.get("block_rects"));
for (int i = 0; i < blocks.size(); i++) {
SceneBlock block = blocks.get(i);
block.id = blockIds.get(i);
loadBlockFromScript(block);
}
this.blocks = blocks;
} catch (ScriptException e) {
Grasscutter.getLogger().error("Error running script", e);
return;
}
// TEMP
this.isInit = true;
}
public boolean isInit() {
return isInit;
}
private void loadBlockFromScript(SceneBlock block) {
CompiledScript cs = ScriptLoader.getScriptByPath(
Grasscutter.getConfig().SCRIPTS_FOLDER + "Scene/" + getScene().getId() + "/scene" + getScene().getId() + "_block" + block.id + "." + ScriptLoader.getScriptType());
if (cs == null) {
return;
}
// Eval script
try {
cs.eval(getBindings());
// Set groups
block.groups = ScriptLoader.getSerializer().toList(SceneGroup.class, bindings.get("groups"));
block.groups.forEach(g -> g.block_id = block.id);
} catch (ScriptException e) {
Grasscutter.getLogger().error("Error loading block " + block.id + " in scene " + getScene().getId(), e);
}
}
public void loadGroupFromScript(SceneGroup group) {
// Set flag here so if there is no script, we dont call this function over and over again.
group.setLoaded(true);
CompiledScript cs = ScriptLoader.getScriptByPath(
Grasscutter.getConfig().SCRIPTS_FOLDER + "Scene/" + getScene().getId() + "/scene" + getScene().getId() + "_group" + group.id + "." + ScriptLoader.getScriptType());
if (cs == null) {
return;
}
// Eval script
try {
cs.eval(getBindings());
// Set
group.monsters = ScriptLoader.getSerializer().toList(SceneMonster.class, bindings.get("monsters"));
group.gadgets = ScriptLoader.getSerializer().toList(SceneGadget.class, bindings.get("gadgets"));
group.triggers = ScriptLoader.getSerializer().toList(SceneTrigger.class, bindings.get("triggers"));
group.suites = ScriptLoader.getSerializer().toList(SceneSuite.class, bindings.get("suites"));
group.regions = ScriptLoader.getSerializer().toList(SceneRegion.class, bindings.get("regions"));
group.init_config = ScriptLoader.getSerializer().toObject(SceneInitConfig.class, bindings.get("init_config"));
// Add variables to suite
List<SceneVar> variables = ScriptLoader.getSerializer().toList(SceneVar.class, bindings.get("variables"));
variables.forEach(var -> this.getVariables().put(var.name, var.value));
// Add monsters to suite TODO optimize
Int2ObjectMap<Object> map = new Int2ObjectOpenHashMap<>();
group.monsters.forEach(m -> map.put(m.config_id, m));
group.gadgets.forEach(m -> map.put(m.config_id, m));
for (SceneSuite suite : group.suites) {
suite.sceneMonsters = new ArrayList<>(suite.monsters.size());
for (int id : suite.monsters) {
try {
SceneMonster monster = (SceneMonster) map.get(id);
if (monster != null) {
suite.sceneMonsters.add(monster);
}
} catch (Exception e) {
continue;
}
}
suite.sceneGadgets = new ArrayList<>(suite.gadgets.size());
for (int id : suite.gadgets) {
try {
SceneGadget gadget = (SceneGadget) map.get(id);
if (gadget != null) {
suite.sceneGadgets.add(gadget);
}
} catch (Exception e) {
continue;
}
}
}
} catch (ScriptException e) {
Grasscutter.getLogger().error("Error loading group " + group.id + " in scene " + getScene().getId(), e);
}
}
public void onTick() {
checkRegions();
}
public void checkRegions() {
if (this.regions.size() == 0) {
return;
}
for (SceneRegion region : this.regions.values()) {
getScene().getEntities().values()
.stream()
.filter(e -> e.getEntityType() <= 2 && region.contains(e.getPosition()))
.forEach(region::addEntity);
if (region.hasNewEntities()) {
// This is not how it works, source_eid should be region entity id, but we dont have an entity for regions yet
callEvent(EventType.EVENT_ENTER_REGION, new ScriptArgs(region.config_id).setSourceEntityId(region.config_id));
region.resetNewEntities();
}
}
}
public void spawnGadgetsInGroup(SceneGroup group, int suiteIndex) {
spawnGadgetsInGroup(group, group.getSuiteByIndex(suiteIndex));
}
public void spawnGadgetsInGroup(SceneGroup group) {
spawnGadgetsInGroup(group, null);
}
public void spawnGadgetsInGroup(SceneGroup group, SceneSuite suite) {
List<SceneGadget> gadgets = group.gadgets;
if (suite != null) {
gadgets = suite.sceneGadgets;
}
for (SceneGadget g : gadgets) {
EntityGadget entity = new EntityGadget(getScene(), g.gadget_id, g.pos);
if (entity.getGadgetData() == null) continue;
entity.setBlockId(group.block_id);
entity.setConfigId(g.config_id);
entity.setGroupId(group.id);
entity.getRotation().set(g.rot);
entity.setState(g.state);
getScene().addEntity(entity);
this.callEvent(EventType.EVENT_GADGET_CREATE, new ScriptArgs(entity.getConfigId()));
}
}
public void spawnMonstersInGroup(SceneGroup group, int suiteIndex) {
spawnMonstersInGroup(group, group.getSuiteByIndex(suiteIndex));
}
public void spawnMonstersInGroup(SceneGroup group) {
spawnMonstersInGroup(group, null);
}
public void spawnMonstersInGroup(SceneGroup group, SceneSuite suite) {
List<SceneMonster> monsters = group.monsters;
if (suite != null) {
monsters = suite.sceneMonsters;
}
List<GameEntity> toAdd = new ArrayList<>();
for (SceneMonster monster : monsters) {
MonsterData data = GameData.getMonsterDataMap().get(monster.monster_id);
if (data == null) {
continue;
}
// Calculate level
int level = monster.level;
if (getScene().getDungeonData() != null) {
level = getScene().getDungeonData().getShowLevel();
} else if (getScene().getWorld().getWorldLevel() > 0) {
WorldLevelData worldLevelData = GameData.getWorldLevelDataMap().get(getScene().getWorld().getWorldLevel());
if (worldLevelData != null) {
level = worldLevelData.getMonsterLevel();
}
}
// Spawn mob
EntityMonster entity = new EntityMonster(getScene(), data, monster.pos, level);
entity.getRotation().set(monster.rot);
entity.setGroupId(group.id);
entity.setConfigId(monster.config_id);
toAdd.add(entity);
}
if (toAdd.size() > 0) {
getScene().addEntities(toAdd);
for (GameEntity entity : toAdd) {
callEvent(EventType.EVENT_ANY_MONSTER_LIVE, new ScriptArgs(entity.getConfigId()));
}
}
}
// Events
public void callEvent(int eventType, ScriptArgs params) {
for (SceneTrigger trigger : this.getTriggersByEvent(eventType)) {
LuaValue condition = null;
if (trigger.condition != null && !trigger.condition.isEmpty()) {
condition = (LuaValue) this.getBindings().get(trigger.condition);
}
LuaValue ret = LuaValue.TRUE;
if (condition != null) {
LuaValue args = LuaValue.NIL;
if (params != null) {
args = CoerceJavaToLua.coerce(params);
}
ret = condition.call(this.getScriptLibLua(), args);
}
if (ret.checkboolean() == true) {
LuaValue action = (LuaValue) this.getBindings().get(trigger.action);
action.call(this.getScriptLibLua(), LuaValue.NIL);
}
}
}
}
package emu.grasscutter.scripts;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.def.MonsterData;
import emu.grasscutter.game.dungeons.DungeonChallenge;
import emu.grasscutter.game.entity.EntityGadget;
import emu.grasscutter.game.entity.EntityMonster;
import emu.grasscutter.game.entity.GameEntity;
import emu.grasscutter.scripts.constants.EventType;
import emu.grasscutter.scripts.data.SceneGroup;
import emu.grasscutter.scripts.data.SceneMonster;
import emu.grasscutter.scripts.data.SceneRegion;
import emu.grasscutter.scripts.data.ScriptArgs;
import emu.grasscutter.server.packet.send.PacketGadgetStateNotify;
import emu.grasscutter.server.packet.send.PacketWorktopOptionNotify;
public class ScriptLib {
private final SceneScriptManager sceneScriptManager;
public ScriptLib(SceneScriptManager sceneScriptManager) {
this.sceneScriptManager = sceneScriptManager;
}
public SceneScriptManager getSceneScriptManager() {
return sceneScriptManager;
}
public int SetGadgetStateByConfigId(int configId, int gadgetState) {
Optional<GameEntity> entity = getSceneScriptManager().getScene().getEntities().values().stream()
.filter(e -> e.getConfigId() == configId).findFirst();
if (entity.isEmpty()) {
return 1;
}
if (!(entity.get() instanceof EntityGadget)) {
return 1;
}
EntityGadget gadget = (EntityGadget) entity.get();
gadget.setState(gadgetState);
getSceneScriptManager().getScene().broadcastPacket(new PacketGadgetStateNotify(gadget, gadgetState));
return 0;
}
public int SetGroupGadgetStateByConfigId(int groupId, int configId, int 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));
}
return 0;
}
public int SetWorktopOptionsByGroupId(int groupId, int configId, int[] options) {
Optional<GameEntity> entity = getSceneScriptManager().getScene().getEntities().values().stream()
.filter(e -> e.getConfigId() == configId && e.getGroupId() == groupId).findFirst();
if (entity.isEmpty()) {
return 1;
}
if (!(entity.get() instanceof EntityGadget)) {
return 1;
}
EntityGadget gadget = (EntityGadget) entity.get();
gadget.addWorktopOptions(options);
getSceneScriptManager().getScene().broadcastPacket(new PacketWorktopOptionNotify(gadget));
return 0;
}
public int DelWorktopOptionByGroupId(int groupId, int configId, int option) {
Optional<GameEntity> entity = getSceneScriptManager().getScene().getEntities().values().stream()
.filter(e -> e.getConfigId() == configId && e.getGroupId() == groupId).findFirst();
if (entity.isEmpty()) {
return 1;
}
if (!(entity.get() instanceof EntityGadget)) {
return 1;
}
EntityGadget gadget = (EntityGadget) entity.get();
gadget.removeWorktopOption(option);
getSceneScriptManager().getScene().broadcastPacket(new PacketWorktopOptionNotify(gadget));
return 0;
}
// Some fields are guessed
public int AutoMonsterTide(int challengeIndex, int groupId, int[] config_ids, int param4, int param5, int param6) {
SceneGroup group = getSceneScriptManager().getGroupById(groupId);
if (group == null || group.monsters == null) {
return 1;
}
// TODO just spawn all from group for now
this.getSceneScriptManager().spawnMonstersInGroup(group);
return 0;
}
public int AddExtraGroupSuite(int groupId, int suite) {
SceneGroup group = getSceneScriptManager().getGroupById(groupId);
if (group == null || group.monsters == null) {
return 1;
}
// TODO just spawn all from group for now
this.getSceneScriptManager().spawnMonstersInGroup(group, suite);
return 0;
}
// param3 (probably time limit for timed dungeons)
public int ActiveChallenge(int challengeId, int challengeIndex, int param3, int groupId, int objectiveKills, int param5) {
SceneGroup group = getSceneScriptManager().getGroupById(groupId);
if (group == null || group.monsters == null) {
return 1;
}
DungeonChallenge challenge = new DungeonChallenge(getSceneScriptManager().getScene(), group);
challenge.setChallengeId(challengeId);
challenge.setChallengeIndex(challengeIndex);
challenge.setObjective(objectiveKills);
getSceneScriptManager().getScene().setChallenge(challenge);
challenge.start();
return 0;
}
public int GetGroupMonsterCountByGroupId(int groupId) {
return (int) getSceneScriptManager().getScene().getEntities().values().stream()
.filter(e -> e instanceof EntityMonster && e.getGroupId() == groupId)
.count();
}
public int GetGroupVariableValue(String var) {
return getSceneScriptManager().getVariables().getOrDefault(var, 0);
}
public int SetGroupVariableValue(String var, int value) {
getSceneScriptManager().getVariables().put(var, value);
return 0;
}
public LuaValue ChangeGroupVariableValue(String var, int value) {
getSceneScriptManager().getVariables().put(var, getSceneScriptManager().getVariables().get(var) + value);
return LuaValue.ZERO;
}
public int RefreshGroup(LuaTable table) {
// Kill and Respawn?
int groupId = table.get("group_id").toint();
int suite = table.get("suite").toint();
SceneGroup group = getSceneScriptManager().getGroupById(groupId);
if (group == null || group.monsters == null) {
return 1;
}
this.getSceneScriptManager().spawnMonstersInGroup(group, suite);
this.getSceneScriptManager().spawnGadgetsInGroup(group, suite);
return 0;
}
public int GetRegionEntityCount(LuaTable table) {
int regionId = table.get("region_eid").toint();
int entityType = table.get("entity_type").toint();
SceneRegion region = this.getSceneScriptManager().getRegionById(regionId);
if (region == null) {
return 0;
}
return (int) region.getEntities().intStream().filter(e -> e >> 24 == entityType).count();
}
public void PrintContextLog(String msg) {
Grasscutter.getLogger().info("[LUA] " + msg);
}
public int TowerCountTimeStatus(int var1, int var2){
return 0;
}
public int GetGroupMonsterCount(int var1){
// Maybe...
return GetGroupMonsterCountByGroupId(var1);
}
public int SetMonsterBattleByGroup(int var1, int var2, int var3){
return 0;
}
public int CauseDungeonFail(int var1){
return 0;
}
}
package emu.grasscutter.scripts;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.lib.OneArgFunction;
import org.luaj.vm2.lib.jse.CoerceJavaToLua;
import org.luaj.vm2.script.LuajContext;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.game.props.EntityType;
import emu.grasscutter.scripts.constants.EventType;
import emu.grasscutter.scripts.constants.ScriptGadgetState;
import emu.grasscutter.scripts.constants.ScriptRegionShape;
import emu.grasscutter.scripts.serializer.LuaSerializer;
import emu.grasscutter.scripts.serializer.Serializer;
public class ScriptLoader {
private static ScriptEngineManager sm;
private static ScriptEngine engine;
private static ScriptEngineFactory factory;
private static String fileType;
private static Serializer serializer;
private static Map<String, CompiledScript> scripts = new HashMap<>();
public synchronized static void init() throws Exception {
if (sm != null) {
throw new Exception("Script loader already initialized");
}
// Create script engine
sm = new ScriptEngineManager();
engine = sm.getEngineByName("luaj");
factory = getEngine().getFactory();
// Lua stuff
fileType = "lua";
serializer = new LuaSerializer();
// Set engine to replace require as a temporary fix to missing scripts
LuajContext ctx = (LuajContext) engine.getContext();
ctx.globals.set("require", new OneArgFunction() {
@Override
public LuaValue call(LuaValue arg0) {
return LuaValue.ZERO;
}
});
LuaTable table = new LuaTable();
Arrays.stream(EntityType.values()).forEach(e -> table.set(e.name().toUpperCase(), e.getValue()));
ctx.globals.set("EntityType", table);
ctx.globals.set("EventType", CoerceJavaToLua.coerce(new EventType())); // TODO - make static class to avoid instantiating a new class every scene
ctx.globals.set("GadgetState", CoerceJavaToLua.coerce(new ScriptGadgetState()));
ctx.globals.set("RegionShape", CoerceJavaToLua.coerce(new ScriptRegionShape()));
}
public static ScriptEngine getEngine() {
return engine;
}
public static String getScriptType() {
return fileType;
}
public static Serializer getSerializer() {
return serializer;
}
public static CompiledScript getScriptByPath(String path) {
CompiledScript sc = scripts.get(path);
Grasscutter.getLogger().info("Loaded " + path);
if (sc == null) {
File file = new File(path);
if (!file.exists()) return null;
try (FileReader fr = new FileReader(file)) {
sc = ((Compilable) getEngine()).compile(fr);
scripts.put(path, sc);
} catch (Exception e) {
//e.printStackTrace();
return null;
}
}
return sc;
}
}
package emu.grasscutter.scripts.constants;
public class EventType {
public static final int EVENT_NONE = 0;
public static final int EVENT_ANY_MONSTER_DIE = 1;
public static final int EVENT_ANY_GADGET_DIE = 2;
public static final int EVENT_VARIABLE_CHANGE = 3;
public static final int EVENT_ENTER_REGION = 4;
public static final int EVENT_LEAVE_REGION = 5;
public static final int EVENT_GADGET_CREATE = 6;
public static final int EVENT_GADGET_STATE_CHANGE = 7;
public static final int EVENT_DUNGEON_SETTLE = 8;
public static final int EVENT_SELECT_OPTION = 9;
public static final int EVENT_CLIENT_EXECUTE = 10;
public static final int EVENT_ANY_MONSTER_LIVE = 11;
public static final int EVENT_SPECIFIC_MONSTER_HP_CHANGE = 12;
public static final int EVENT_CITY_LEVELUP_UNLOCK_DUNGEON_ENTRY = 13;
public static final int EVENT_DUNGEON_BROADCAST_ONTIMER = 14;
public static final int EVENT_TIMER_EVENT = 15;
public static final int EVENT_CHALLENGE_SUCCESS = 16;
public static final int EVENT_CHALLENGE_FAIL = 17;
public static final int EVENT_SEAL_BATTLE_BEGIN = 18;
public static final int EVENT_SEAL_BATTLE_END = 19;
public static final int EVENT_GATHER = 20;
public static final int EVENT_QUEST_FINISH = 21;
public static final int EVENT_MONSTER_BATTLE = 22;
public static final int EVENT_CITY_LEVELUP = 23;
public static final int EVENT_CUTSCENE_END = 24;
public static final int EVENT_AVATAR_NEAR_PLATFORM = 25;
public static final int EVENT_PLATFORM_REACH_POINT = 26;
public static final int EVENT_UNLOCK_TRANS_POINT = 27;
public static final int EVENT_QUEST_START = 28;
public static final int EVENT_GROUP_LOAD = 29;
public static final int EVENT_GROUP_WILL_UNLOAD = 30;
public static final int EVENT_GROUP_WILL_REFRESH = 31;
public static final int EVENT_GROUP_REFRESH = 32;
public static final int EVENT_DUNGEON_REWARD_GET = 33;
public static final int EVENT_SPECIFIC_GADGET_HP_CHANGE = 34;
public static final int EVENT_MONSTER_TIDE_OVER = 35;
public static final int EVENT_MONSTER_TIDE_CREATE = 36;
public static final int EVENT_MONSTER_TIDE_DIE = 37;
public static final int EVENT_SEALAMP_PHASE_CHANGE = 38;
public static final int EVENT_BLOSSOM_PROGRESS_FINISH = 39;
public static final int EVENT_BLOSSOM_CHEST_DIE = 40;
public static final int EVENT_GADGET_PLAY_START = 41;
public static final int EVENT_GADGET_PLAY_START_CD = 42;
public static final int EVENT_GADGET_PLAY_STOP = 43;
public static final int EVENT_GADGET_LUA_NOTIFY = 44;
public static final int EVENT_MP_PLAY_PREPARE = 45;
public static final int EVENT_MP_PLAY_BATTLE = 46;
public static final int EVENT_MP_PLAY_PREPARE_INTERRUPT = 47;
public static final int EVENT_SELECT_DIFFICULTY = 48;
public static final int EVENT_SCENE_MP_PLAY_BATTLE_STATE = 49;
public static final int EVENT_SCENE_MP_PLAY_BATTLE_STAGE_CHANGE = 50;
public static final int EVENT_SCENE_MP_PLAY_BATTLE_RESULT = 51;
public static final int EVENT_SEAL_BATTLE_PROGRESS_DECREASE = 52;
public static final int EVENT_GENERAL_REWARD_DIE = 53;
public static final int EVENT_SCENE_MP_PLAY_BATTLE_INTERRUPT = 54;
public static final int EVENT_MONSTER_DIE_BEFORE_LEAVE_SCENE = 55;
public static final int EVENT_SCENE_MP_PLAY_OPEN = 56;
public static final int EVENT_OFFERING_LEVELUP = 57;
public static final int EVENT_DUNGEON_REVIVE = 58;
public static final int EVENT_SCENE_MP_PLAY_ALL_AVATAR_DIE = 59;
public static final int EVENT_DUNGEON_ALL_AVATAR_DIE = 60;
public static final int EVENT_GENERAL_REWARD_TAKEN = 61;
public static final int EVENT_PLATFORM_REACH_ARRAYPOINT = 62;
public static final int EVENT_SCENE_MULTISTAGE_PLAY_STAGE_END = 63;
public static final int EVENT_SCENE_MULTISTAGE_PLAY_END_STAGE_REQ = 64;
public static final int EVENT_MECHANICUS_PICKED_CARD = 65;
public static final int EVENT_POOL_MONSTER_TIDE_OVER = 66;
public static final int EVENT_POOL_MONSTER_TIDE_CREATE = 67;
public static final int EVENT_POOL_MONSTER_TIDE_DIE = 68;
public static final int EVENT_DUNGEON_AVATAR_SLIP_DIE = 69;
public static final int EVENT_GALLERY_START = 70;
public static final int EVENT_GALLERY_STOP = 71;
public static final int EVENT_TIME_AXIS_PASS = 72;
public static final int EVENT_FLEUR_FAIR_DUNGEON_ALL_PLAYER_ENTER = 73;
public static final int EVENT_GADGETTALK_DONE = 74;
public static final int EVENT_SET_GAME_TIME = 75;
public static final int EVENT_HIDE_AND_SEEK_PLAYER_QUIT = 76;
public static final int EVENT_AVATAR_DIE = 77;
}
package emu.grasscutter.scripts.constants;
public class ScriptGadgetState {
public static final int Default = 0;
public static final int GatherDrop = 1;
public static final int ChestLocked = 101;
public static final int ChestOpened = 102;
public static final int ChestTrap = 103;
public static final int ChestBramble = 104;
public static final int ChestFrozen = 105;
public static final int ChestRock = 106;
public static final int GearStart = 201;
public static final int GearStop = 202;
public static final int GearAction1 = 203;
public static final int GearAction2 = 204;
public static final int CrystalResonate1 = 301;
public static final int CrystalResonate2 = 302;
public static final int CrystalExplode = 303;
public static final int CrystalDrain = 304;
public static final int StatueActive = 401;
public static final int Action01 = 901;
public static final int Action02 = 902;
public static final int Action03 = 903;
}
package emu.grasscutter.scripts.constants;
public class ScriptRegionShape {
public static final int NONE = 0;
public static final int SPHERE = 1;
public static final int CUBIC = 2;
}
package emu.grasscutter.scripts.data;
import java.util.List;
import emu.grasscutter.utils.Position;
public class SceneBlock {
public int id;
public Position max;
public Position min;
public List<SceneGroup> groups;
public boolean contains(Position pos) {
return pos.getX() <= max.getX() && pos.getX() >= min.getX() &&
pos.getZ() <= max.getZ() && pos.getZ() >= min.getZ();
}
}
package emu.grasscutter.scripts.data;
import emu.grasscutter.utils.Position;
public class SceneConfig {
public Position vision_anchor;
public Position born_pos;
public Position born_rot;
public Position begin_pos;
public Position size;
}
package emu.grasscutter.scripts.data;
import emu.grasscutter.utils.Position;
public class SceneGadget {
public int level;
public int config_id;
public int gadget_id;
public int state;
public Position pos;
public Position rot;
}
package emu.grasscutter.scripts.data;
import java.util.List;
import emu.grasscutter.utils.Position;
public class SceneGroup {
public transient int block_id; // Not an actual variable in the scripts but we will keep it here for reference
public int id;
public int refresh_id;
public Position pos;
public List<SceneMonster> monsters;
public List<SceneGadget> gadgets;
public List<SceneTrigger> triggers;
public List<SceneRegion> regions;
public List<SceneSuite> suites;
public SceneInitConfig init_config;
private transient boolean isLoaded; // Not an actual variable in the scripts either
public boolean isLoaded() {
return isLoaded;
}
public boolean setLoaded(boolean loaded) {
return loaded;
}
public SceneSuite getSuiteByIndex(int index) {
return suites.get(index - 1);
}
}
package emu.grasscutter.scripts.data;
import emu.grasscutter.utils.Position;
public class SceneInitConfig {
public int suite;
public int end_suite;
public int rand_suite;
}
package emu.grasscutter.scripts.data;
import emu.grasscutter.utils.Position;
public class SceneMonster {
public int level;
public int config_id;
public int monster_id;
public Position pos;
public Position rot;
}
package emu.grasscutter.scripts.data;
import emu.grasscutter.game.entity.GameEntity;
import emu.grasscutter.scripts.constants.ScriptRegionShape;
import emu.grasscutter.utils.Position;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
public class SceneRegion {
public int config_id;
public int shape;
public Position pos;
public Position size;
private boolean hasNewEntities;
private final IntSet entities; // Ids of entities inside this region
public SceneRegion() {
this.entities = new IntOpenHashSet();
}
public IntSet getEntities() {
return entities;
}
public void addEntity(GameEntity entity) {
if (this.getEntities().contains(entity.getId())) {
return;
}
this.getEntities().add(entity.getId());
this.hasNewEntities = true;
}
public void removeEntity(GameEntity entity) {
this.getEntities().remove(entity.getId());
}
public boolean contains(Position p) {
switch (shape) {
case ScriptRegionShape.CUBIC:
return (Math.abs(pos.getX() - p.getX()) <= size.getX()) &&
(Math.abs(pos.getZ() - p.getZ()) <= size.getZ());
case ScriptRegionShape.SPHERE:
return false;
}
return false;
}
public boolean hasNewEntities() {
return hasNewEntities;
}
public void resetNewEntities() {
hasNewEntities = false;
}
}
package emu.grasscutter.scripts.data;
import java.util.List;
import emu.grasscutter.utils.Position;
public class SceneSuite {
public List<Integer> monsters;
public List<Integer> gadgets;
public List<String> triggers;
public int rand_weight;
public transient List<SceneMonster> sceneMonsters;
public transient List<SceneGadget> sceneGadgets;
}
package emu.grasscutter.scripts.data;
public class SceneTrigger {
public String name;
public int config_id;
public int event;
public String source;
public String condition;
public String action;
}
package emu.grasscutter.scripts.data;
public class SceneVar {
public String name;
public int value;
public boolean no_refresh;
}
package emu.grasscutter.scripts.data;
public class ScriptArgs {
public int param1;
public int param2;
public int param3;
public int source_eid; // Source entity
public ScriptArgs() {
}
public ScriptArgs(int param1) {
this.param1 = param1;
}
public ScriptArgs(int param1, int param2) {
this.param1 = param1;
this.param2 = param2;
}
public int getParam1() {
return param1;
}
public ScriptArgs setParam1(int param1) {
this.param1 = param1;
return this;
}
public int getParam2() {
return param2;
}
public ScriptArgs setParam2(int param2) {
this.param2 = param2;
return this;
}
public int getParam3() {
return param3;
}
public ScriptArgs setParam3(int param3) {
this.param3 = param3;
return this;
}
public int getSourceEntityId() {
return source_eid;
}
public ScriptArgs setSourceEntityId(int source_eid) {
this.source_eid = source_eid;
return this;
}
}
package emu.grasscutter.scripts.serializer;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
public class LuaSerializer implements Serializer {
@Override
public <T> List<T> toList(Class<T> type, Object obj) {
return serializeList(type, (LuaTable) obj);
}
@Override
public <T> T toObject(Class<T> type, Object obj) {
return serialize(type, (LuaTable) obj);
}
public <T> List<T> serializeList(Class<T> type, LuaTable table) {
List<T> list = new ArrayList();
try {
LuaValue[] keys = table.keys();
for (LuaValue k : keys) {
try {
LuaValue keyValue = table.get(k);
T object = null;
if (keyValue.istable()) {
object = serialize(type, keyValue.checktable());
} else if (keyValue.isint()) {
object = (T) (Integer) keyValue.toint();
} else if (keyValue.isnumber()) {
object = (T) (Float) keyValue.tofloat(); // terrible...
} else if (keyValue.isstring()) {
object = (T) keyValue.tojstring();
} else {
object = (T) keyValue;
}
if (object != null) {
list.add(object);
}
} catch (Exception ex) {
}
}
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
public <T> T serialize(Class<T> type, LuaTable table) {
T object = null;
if (type == List.class) {
try {
Class<T> listType = (Class<T>) type.getTypeParameters()[0].getClass();
return (T) serializeList(listType, table);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
try {
object = type.getDeclaredConstructor().newInstance(null);
LuaValue[] keys = table.keys();
for (LuaValue k : keys) {
try {
Field field = object.getClass().getDeclaredField(k.checkjstring());
if (field == null) {
continue;
}
field.setAccessible(true);
LuaValue keyValue = table.get(k);
if (keyValue.istable()) {
field.set(object, serialize(field.getType(), keyValue.checktable()));
} else if (field.getType().equals(float.class)) {
field.setFloat(object, keyValue.tofloat());
} else if (field.getType().equals(int.class)) {
field.setInt(object, keyValue.toint());
} else if (field.getType().equals(String.class)) {
field.set(object, keyValue.tojstring());
} else {
field.set(object, keyValue);
}
} catch (Exception ex) {
//ex.printStackTrace();
continue;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return object;
}
}
package emu.grasscutter.scripts.serializer;
import java.util.List;
import org.luaj.vm2.LuaTable;
public interface Serializer {
public <T> List<T> toList(Class<T> type, Object obj);
public <T> T toObject(Class<T> type, Object obj);
}
package emu.grasscutter.server.dispatch;
import emu.grasscutter.Grasscutter;
import express.http.HttpContextHandler;
import express.http.Request;
import express.http.Response;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Objects;
public final class AnnouncementHandler implements HttpContextHandler {
@Override
public void handle(Request request, Response response) throws IOException {//event
if (Objects.equals(request.baseUrl(), "/common/hk4e_global/announcement/api/getAnnContent")) {
response.send("{\"retcode\":0,\"message\":\"OK\",\"data\":" + readToString(new File(Grasscutter.getConfig().DATA_FOLDER + "GameAnnouncement.json")) +"}");
} else if (Objects.equals(request.baseUrl(), "/common/hk4e_global/announcement/api/getAnnList")) {
String data = readToString(new File(Grasscutter.getConfig().DATA_FOLDER + "GameAnnouncementList.json")).replace("System.currentTimeMillis()",String.valueOf(System.currentTimeMillis()));
response.send("{\"retcode\":0,\"message\":\"OK\",\"data\": "+data +"}");
}
}
private static String readToString(File file) {
Long filelength = file.length();
byte[] filecontent = new byte[filelength.intValue()];
try {
FileInputStream in = new FileInputStream(file);
in.read(filecontent);
in.close();
} catch (IOException fileNotFoundException) {
fileNotFoundException.printStackTrace();
}
return new String(filecontent);
}
}
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment